Spaces:
Running
Running
/* | |
* response-stream.js: A Stream focused on writing any relevant information to | |
* a raw http.ServerResponse object. | |
* | |
* (C) 2011, Charlie Robbins & the Contributors | |
* MIT LICENSE | |
* | |
*/ | |
var util = require('util'), | |
HttpStream = require('./http-stream'); | |
var STATUS_CODES = require('http').STATUS_CODES; | |
// | |
// ### function ResponseStream (options) | |
// | |
// | |
var ResponseStream = module.exports = function (options) { | |
var self = this, | |
key; | |
options = options || {}; | |
HttpStream.call(this, options); | |
this.writeable = true; | |
this.response = options.response; | |
if (options.headers) { | |
for (key in options.headers) { | |
this.response.setHeader(key, options.headers[key]); | |
} | |
} | |
// | |
// Proxy `statusCode` changes to the actual `response.statusCode`. | |
// | |
Object.defineProperty(this, 'statusCode', { | |
get: function () { | |
return self.response.statusCode; | |
}, | |
set: function (value) { | |
self.response.statusCode = value; | |
}, | |
enumerable: true, | |
configurable: true | |
}); | |
if (this.response) { | |
this._headers = this.response._headers = this.response._headers || {}; | |
// Patch to node core | |
this.response._headerNames = this.response._headerNames || {}; | |
// | |
// Proxy to emit "header" event | |
// | |
this._renderHeaders = this.response._renderHeaders; | |
this.response._renderHeaders = function () { | |
if (!self._emittedHeader) { | |
self._emittedHeader = true; | |
self.headerSent = true; | |
self._header = true; | |
self.emit('header'); | |
} | |
return self._renderHeaders.call(self.response); | |
}; | |
} | |
}; | |
util.inherits(ResponseStream, HttpStream); | |
ResponseStream.prototype.writeHead = function (statusCode, statusMessage, headers) { | |
if (typeof statusMessage === 'string') { | |
this.response.statusMessage = statusMessage; | |
} else { | |
this.response.statusMessage = this.response.statusMessage | |
|| STATUS_CODES[statusCode] || 'unknown'; | |
headers = statusMessage; | |
} | |
this.response.statusCode = statusCode; | |
if (headers) { | |
var keys = Object.keys(headers); | |
for (var i = 0; i < keys.length; i++) { | |
var k = keys[i]; | |
if (k) this.response.setHeader(k, headers[k]); | |
} | |
} | |
}; | |
// | |
// Create pass-thru for the necessary | |
// `http.ServerResponse` methods. | |
// | |
['setHeader', 'getHeader', 'removeHeader', '_implicitHeader', 'addTrailers'].forEach(function (method) { | |
ResponseStream.prototype[method] = function () { | |
return this.response[method].apply(this.response, arguments); | |
}; | |
}); | |
ResponseStream.prototype.json = function (obj) { | |
if (!this.response.writable) { | |
return; | |
} | |
if (typeof obj === 'number') { | |
this.response.statusCode = obj; | |
obj = arguments[1]; | |
} | |
this.modified = true; | |
if (!this.response._header && this.response.getHeader('content-type') !== 'application/json') { | |
this.response.setHeader('content-type', 'application/json'); | |
} | |
this.end(obj ? JSON.stringify(obj) : ''); | |
}; | |
ResponseStream.prototype.html = function (str) { | |
if (!this.response.writable) { | |
return; | |
} | |
if (typeof str === 'number') { | |
this.response.statusCode = str; | |
str = arguments[1]; | |
} | |
this.modified = true; | |
if (!this.response._header && this.response.getHeader('content-type') !== 'text/html') { | |
this.response.setHeader('content-type', 'text/html'); | |
} | |
this.end(str ? str: ''); | |
}; | |
ResponseStream.prototype.text = function (str) { | |
if (!this.response.writable) { | |
return; | |
} | |
if (typeof str === 'number') { | |
this.response.statusCode = str; | |
str = arguments[1]; | |
} | |
this.modified = true; | |
if (!this.response._header && this.response.getHeader('content-type') !== 'text/plain') { | |
this.response.setHeader('content-type', 'text/plain'); | |
} | |
this.end(str ? str: ''); | |
}; | |
ResponseStream.prototype.end = function (data) { | |
if (data && this.writable) { | |
this.emit('data', data); | |
} | |
this.modified = true; | |
this.emit('end'); | |
}; | |
ResponseStream.prototype.pipe = function () { | |
var self = this, | |
dest; | |
self.dest = dest = HttpStream.prototype.pipe.apply(self, arguments); | |
dest.on('drain', function() { | |
self.emit('drain') | |
}) | |
return dest; | |
}; | |
ResponseStream.prototype.write = function (data) { | |
this.modified = true; | |
if (this.writable) { | |
return this.dest.write(data); | |
} | |
}; | |
ResponseStream.prototype.redirect = function (path, status) { | |
var url = ''; | |
if (~path.indexOf('://')) { | |
url = path; | |
} else { | |
url += this.req.connection.encrypted ? 'https://' : 'http://'; | |
url += this.req.headers.host; | |
url += (path[0] === '/') ? path : '/' + path; | |
} | |
this.res.writeHead(status || 302, { 'Location': url }); | |
this.end(); | |
}; | |