You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

203 lines
4.6 KiB

/*
* 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();
};