socketioMEANseed/www/node_modules/union/lib/response-stream.js
www/node_modules/union/lib/response-stream.jsRaw
1/*
2 * response-stream.js: A Stream focused on writing any relevant information to
3 * a raw http.ServerResponse object.
4 *
5 * (C) 2011, Charlie Robbins & the Contributors
6 * MIT LICENSE
7 *
8 */
9
10var util = require('util'),
11 HttpStream = require('./http-stream');
12
13var STATUS_CODES = require('http').STATUS_CODES;
14
15//
16// ### function ResponseStream (options)
17//
18//
19var ResponseStream = module.exports = function (options) {
20 var self = this,
21 key;
22
23 options = options || {};
24 HttpStream.call(this, options);
25
26 this.writeable = true;
27 this.response = options.response;
28
29 if (options.headers) {
30 for (key in options.headers) {
31 this.response.setHeader(key, options.headers[key]);
32 }
33 }
34
35 //
36 // Proxy `statusCode` changes to the actual `response.statusCode`.
37 //
38 Object.defineProperty(this, 'statusCode', {
39 get: function () {
40 return self.response.statusCode;
41 },
42 set: function (value) {
43 self.response.statusCode = value;
44 },
45 enumerable: true,
46 configurable: true
47 });
48
49 if (this.response) {
50 this._headers = this.response._headers = this.response._headers || {};
51
52 // Patch to node core
53 this.response._headerNames = this.response._headerNames || {};
54
55 //
56 // Proxy to emit "header" event
57 //
58 this._renderHeaders = this.response._renderHeaders;
59 this.response._renderHeaders = function () {
60 if (!self._emittedHeader) {
61 self._emittedHeader = true;
62 self.headerSent = true;
63 self._header = true;
64 self.emit('header');
65 }
66
67 return self._renderHeaders.call(self.response);
68 };
69 }
70};
71
72util.inherits(ResponseStream, HttpStream);
73
74ResponseStream.prototype.writeHead = function (statusCode, statusMessage, headers) {
75 if (typeof statusMessage === 'string') {
76 this.response.statusMessage = statusMessage;
77 } else {
78 this.response.statusMessage = this.response.statusMessage
79 || STATUS_CODES[statusCode] || 'unknown';
80 headers = statusMessage;
81 }
82
83 this.response.statusCode = statusCode;
84
85 if (headers) {
86 var keys = Object.keys(headers);
87 for (var i = 0; i < keys.length; i++) {
88 var k = keys[i];
89 if (k) this.response.setHeader(k, headers[k]);
90 }
91 }
92};
93
94//
95// Create pass-thru for the necessary
96// `http.ServerResponse` methods.
97//
98['setHeader', 'getHeader', 'removeHeader', '_implicitHeader', 'addTrailers'].forEach(function (method) {
99 ResponseStream.prototype[method] = function () {
100 return this.response[method].apply(this.response, arguments);
101 };
102});
103
104ResponseStream.prototype.json = function (obj) {
105 if (!this.response.writable) {
106 return;
107 }
108
109 if (typeof obj === 'number') {
110 this.response.statusCode = obj;
111 obj = arguments[1];
112 }
113
114 this.modified = true;
115
116 if (!this.response._header && this.response.getHeader('content-type') !== 'application/json') {
117 this.response.setHeader('content-type', 'application/json');
118 }
119
120 this.end(obj ? JSON.stringify(obj) : '');
121};
122
123ResponseStream.prototype.html = function (str) {
124 if (!this.response.writable) {
125 return;
126 }
127
128 if (typeof str === 'number') {
129 this.response.statusCode = str;
130 str = arguments[1];
131 }
132
133 this.modified = true;
134
135 if (!this.response._header && this.response.getHeader('content-type') !== 'text/html') {
136 this.response.setHeader('content-type', 'text/html');
137 }
138
139 this.end(str ? str: '');
140};
141
142ResponseStream.prototype.text = function (str) {
143 if (!this.response.writable) {
144 return;
145 }
146
147 if (typeof str === 'number') {
148 this.response.statusCode = str;
149 str = arguments[1];
150 }
151
152 this.modified = true;
153
154 if (!this.response._header && this.response.getHeader('content-type') !== 'text/plain') {
155 this.response.setHeader('content-type', 'text/plain');
156 }
157
158 this.end(str ? str: '');
159};
160
161ResponseStream.prototype.end = function (data) {
162 if (data && this.writable) {
163 this.emit('data', data);
164 }
165
166 this.modified = true;
167 this.emit('end');
168};
169
170ResponseStream.prototype.pipe = function () {
171 var self = this,
172 dest;
173
174 self.dest = dest = HttpStream.prototype.pipe.apply(self, arguments);
175
176 dest.on('drain', function() {
177 self.emit('drain')
178 })
179 return dest;
180};
181
182ResponseStream.prototype.write = function (data) {
183 this.modified = true;
184
185 if (this.writable) {
186 return this.dest.write(data);
187 }
188};
189
190ResponseStream.prototype.redirect = function (path, status) {
191 var url = '';
192
193 if (~path.indexOf('://')) {
194 url = path;
195 } else {
196 url += this.req.connection.encrypted ? 'https://' : 'http://';
197 url += this.req.headers.host;
198 url += (path[0] === '/') ? path : '/' + path;
199 }
200
201 this.res.writeHead(status || 302, { 'Location': url });
202 this.end();
203};