787fc27bbf149410d9e5b748bea6cc0e877215ff
[platform/upstream/nodejs.git] / lib / _http_server.js
1 // Copyright Joyent, Inc. and other Node contributors.
2 //
3 // Permission is hereby granted, free of charge, to any person obtaining a
4 // copy of this software and associated documentation files (the
5 // "Software"), to deal in the Software without restriction, including
6 // without limitation the rights to use, copy, modify, merge, publish,
7 // distribute, sublicense, and/or sell copies of the Software, and to permit
8 // persons to whom the Software is furnished to do so, subject to the
9 // following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included
12 // in all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17 // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18 // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19 // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20 // USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22 var util = require('util');
23 var net = require('net');
24 var EventEmitter = require('events').EventEmitter;
25 var HTTPParser = process.binding('http_parser').HTTPParser;
26 var assert = require('assert').ok;
27
28 var common = require('_http_common');
29 var parsers = common.parsers;
30 var freeParser = common.freeParser;
31 var debug = common.debug;
32 var CRLF = common.CRLF;
33 var continueExpression = common.continueExpression;
34 var chunkExpression = common.chunkExpression;
35 var httpSocketSetup = common.httpSocketSetup;
36
37 var OutgoingMessage = require('_http_outgoing').OutgoingMessage;
38
39
40 var STATUS_CODES = exports.STATUS_CODES = {
41   100 : 'Continue',
42   101 : 'Switching Protocols',
43   102 : 'Processing',                 // RFC 2518, obsoleted by RFC 4918
44   200 : 'OK',
45   201 : 'Created',
46   202 : 'Accepted',
47   203 : 'Non-Authoritative Information',
48   204 : 'No Content',
49   205 : 'Reset Content',
50   206 : 'Partial Content',
51   207 : 'Multi-Status',               // RFC 4918
52   300 : 'Multiple Choices',
53   301 : 'Moved Permanently',
54   302 : 'Moved Temporarily',
55   303 : 'See Other',
56   304 : 'Not Modified',
57   305 : 'Use Proxy',
58   307 : 'Temporary Redirect',
59   308 : 'Permanent Redirect',         // RFC 7238
60   400 : 'Bad Request',
61   401 : 'Unauthorized',
62   402 : 'Payment Required',
63   403 : 'Forbidden',
64   404 : 'Not Found',
65   405 : 'Method Not Allowed',
66   406 : 'Not Acceptable',
67   407 : 'Proxy Authentication Required',
68   408 : 'Request Time-out',
69   409 : 'Conflict',
70   410 : 'Gone',
71   411 : 'Length Required',
72   412 : 'Precondition Failed',
73   413 : 'Request Entity Too Large',
74   414 : 'Request-URI Too Large',
75   415 : 'Unsupported Media Type',
76   416 : 'Requested Range Not Satisfiable',
77   417 : 'Expectation Failed',
78   418 : 'I\'m a teapot',              // RFC 2324
79   422 : 'Unprocessable Entity',       // RFC 4918
80   423 : 'Locked',                     // RFC 4918
81   424 : 'Failed Dependency',          // RFC 4918
82   425 : 'Unordered Collection',       // RFC 4918
83   426 : 'Upgrade Required',           // RFC 2817
84   428 : 'Precondition Required',      // RFC 6585
85   429 : 'Too Many Requests',          // RFC 6585
86   431 : 'Request Header Fields Too Large',// RFC 6585
87   500 : 'Internal Server Error',
88   501 : 'Not Implemented',
89   502 : 'Bad Gateway',
90   503 : 'Service Unavailable',
91   504 : 'Gateway Time-out',
92   505 : 'HTTP Version Not Supported',
93   506 : 'Variant Also Negotiates',    // RFC 2295
94   507 : 'Insufficient Storage',       // RFC 4918
95   509 : 'Bandwidth Limit Exceeded',
96   510 : 'Not Extended',               // RFC 2774
97   511 : 'Network Authentication Required' // RFC 6585
98 };
99
100
101 function ServerResponse(req) {
102   OutgoingMessage.call(this);
103
104   if (req.method === 'HEAD') this._hasBody = false;
105
106   this.sendDate = true;
107
108   if (req.httpVersionMajor < 1 || req.httpVersionMinor < 1) {
109     this.useChunkedEncodingByDefault = chunkExpression.test(req.headers.te);
110     this.shouldKeepAlive = false;
111   }
112 }
113 util.inherits(ServerResponse, OutgoingMessage);
114
115 ServerResponse.prototype._finish = function() {
116   DTRACE_HTTP_SERVER_RESPONSE(this.connection);
117   COUNTER_HTTP_SERVER_RESPONSE();
118   OutgoingMessage.prototype._finish.call(this);
119 };
120
121
122
123 exports.ServerResponse = ServerResponse;
124
125 ServerResponse.prototype.statusCode = 200;
126 ServerResponse.prototype.statusMessage = undefined;
127
128 function onServerResponseClose() {
129   // EventEmitter.emit makes a copy of the 'close' listeners array before
130   // calling the listeners. detachSocket() unregisters onServerResponseClose
131   // but if detachSocket() is called, directly or indirectly, by a 'close'
132   // listener, onServerResponseClose is still in that copy of the listeners
133   // array. That is, in the example below, b still gets called even though
134   // it's been removed by a:
135   //
136   //   var obj = new events.EventEmitter;
137   //   obj.on('event', a);
138   //   obj.on('event', b);
139   //   function a() { obj.removeListener('event', b) }
140   //   function b() { throw "BAM!" }
141   //   obj.emit('event');  // throws
142   //
143   // Ergo, we need to deal with stale 'close' events and handle the case
144   // where the ServerResponse object has already been deconstructed.
145   // Fortunately, that requires only a single if check. :-)
146   if (this._httpMessage) this._httpMessage.emit('close');
147 }
148
149 ServerResponse.prototype.assignSocket = function(socket) {
150   assert(!socket._httpMessage);
151   socket._httpMessage = this;
152   socket.on('close', onServerResponseClose);
153   this.socket = socket;
154   this.connection = socket;
155   this.emit('socket', socket);
156   this._flush();
157 };
158
159 ServerResponse.prototype.detachSocket = function(socket) {
160   assert(socket._httpMessage === this);
161   socket.removeListener('close', onServerResponseClose);
162   socket._httpMessage = null;
163   this.socket = this.connection = null;
164 };
165
166 ServerResponse.prototype.writeContinue = function(cb) {
167   this._writeRaw('HTTP/1.1 100 Continue' + CRLF + CRLF, 'ascii', cb);
168   this._sent100 = true;
169 };
170
171 ServerResponse.prototype._implicitHeader = function() {
172   this.writeHead(this.statusCode);
173 };
174
175 ServerResponse.prototype.writeHead = function(statusCode, reason, obj) {
176   var headers;
177
178   if (util.isString(reason)) {
179     // writeHead(statusCode, reasonPhrase[, headers])
180     this.statusMessage = reason;
181   } else {
182     // writeHead(statusCode[, headers])
183     this.statusMessage =
184         this.statusMessage || STATUS_CODES[statusCode] || 'unknown';
185     obj = reason;
186   }
187   this.statusCode = statusCode;
188
189   if (this._headers) {
190     // Slow-case: when progressive API and header fields are passed.
191     if (obj) {
192       var keys = Object.keys(obj);
193       for (var i = 0; i < keys.length; i++) {
194         var k = keys[i];
195         if (k) this.setHeader(k, obj[k]);
196       }
197     }
198     // only progressive api is used
199     headers = this._renderHeaders();
200   } else {
201     // only writeHead() called
202     headers = obj;
203   }
204
205   var statusLine = 'HTTP/1.1 ' + statusCode.toString() + ' ' +
206                    this.statusMessage + CRLF;
207
208   if (statusCode === 204 || statusCode === 304 ||
209       (100 <= statusCode && statusCode <= 199)) {
210     // RFC 2616, 10.2.5:
211     // The 204 response MUST NOT include a message-body, and thus is always
212     // terminated by the first empty line after the header fields.
213     // RFC 2616, 10.3.5:
214     // The 304 response MUST NOT contain a message-body, and thus is always
215     // terminated by the first empty line after the header fields.
216     // RFC 2616, 10.1 Informational 1xx:
217     // This class of status code indicates a provisional response,
218     // consisting only of the Status-Line and optional headers, and is
219     // terminated by an empty line.
220     this._hasBody = false;
221   }
222
223   // don't keep alive connections where the client expects 100 Continue
224   // but we sent a final status; they may put extra bytes on the wire.
225   if (this._expect_continue && !this._sent100) {
226     this.shouldKeepAlive = false;
227   }
228
229   this._storeHeader(statusLine, headers);
230 };
231
232 ServerResponse.prototype.writeHeader = function() {
233   this.writeHead.apply(this, arguments);
234 };
235
236
237 function Server(requestListener) {
238   if (!(this instanceof Server)) return new Server(requestListener);
239   net.Server.call(this, { allowHalfOpen: true });
240
241   if (requestListener) {
242     this.addListener('request', requestListener);
243   }
244
245   // Similar option to this. Too lazy to write my own docs.
246   // http://www.squid-cache.org/Doc/config/half_closed_clients/
247   // http://wiki.squid-cache.org/SquidFaq/InnerWorkings#What_is_a_half-closed_filedescriptor.3F
248   this.httpAllowHalfOpen = false;
249
250   this.addListener('connection', connectionListener);
251
252   this.addListener('clientError', function(err, conn) {
253     conn.destroy(err);
254   });
255
256   this.timeout = 2 * 60 * 1000;
257 }
258 util.inherits(Server, net.Server);
259
260
261 Server.prototype.setTimeout = function(msecs, callback) {
262   this.timeout = msecs;
263   if (callback)
264     this.on('timeout', callback);
265 };
266
267
268 exports.Server = Server;
269
270
271 function connectionListener(socket) {
272   var self = this;
273   var outgoing = [];
274   var incoming = [];
275
276   function abortIncoming() {
277     while (incoming.length) {
278       var req = incoming.shift();
279       req.emit('aborted');
280       req.emit('close');
281     }
282     // abort socket._httpMessage ?
283   }
284
285   function serverSocketCloseListener() {
286     debug('server socket close');
287     // mark this parser as reusable
288     if (this.parser) {
289       freeParser(this.parser, null, this);
290     }
291
292     abortIncoming();
293   }
294
295   debug('SERVER new http connection');
296
297   httpSocketSetup(socket);
298
299   // If the user has added a listener to the server,
300   // request, or response, then it's their responsibility.
301   // otherwise, destroy on timeout by default
302   if (self.timeout)
303     socket.setTimeout(self.timeout);
304   socket.on('timeout', function() {
305     var req = socket.parser && socket.parser.incoming;
306     var reqTimeout = req && !req.complete && req.emit('timeout', socket);
307     var res = socket._httpMessage;
308     var resTimeout = res && res.emit('timeout', socket);
309     var serverTimeout = self.emit('timeout', socket);
310
311     if (!reqTimeout && !resTimeout && !serverTimeout)
312       socket.destroy();
313   });
314
315   var parser = parsers.alloc();
316   parser.reinitialize(HTTPParser.REQUEST);
317   parser.socket = socket;
318   socket.parser = parser;
319   parser.incoming = null;
320
321   // Propagate headers limit from server instance to parser
322   if (util.isNumber(this.maxHeadersCount)) {
323     parser.maxHeaderPairs = this.maxHeadersCount << 1;
324   } else {
325     // Set default value because parser may be reused from FreeList
326     parser.maxHeaderPairs = 2000;
327   }
328
329   socket.addListener('error', socketOnError);
330   socket.addListener('close', serverSocketCloseListener);
331   parser.onIncoming = parserOnIncoming;
332   socket.on('end', socketOnEnd);
333   socket.on('data', socketOnData);
334
335   // TODO(isaacs): Move all these functions out of here
336   function socketOnError(e) {
337     self.emit('clientError', e, this);
338   }
339
340   function socketOnData(d) {
341     assert(!socket._paused);
342     debug('SERVER socketOnData %d', d.length);
343     var ret = parser.execute(d);
344     if (ret instanceof Error) {
345       debug('parse error');
346       socket.destroy(ret);
347     } else if (parser.incoming && parser.incoming.upgrade) {
348       // Upgrade or CONNECT
349       var bytesParsed = ret;
350       var req = parser.incoming;
351       debug('SERVER upgrade or connect', req.method);
352
353       socket.removeListener('data', socketOnData);
354       socket.removeListener('end', socketOnEnd);
355       socket.removeListener('close', serverSocketCloseListener);
356       parser.finish();
357       freeParser(parser, req, null);
358       parser = null;
359
360       var eventName = req.method === 'CONNECT' ? 'connect' : 'upgrade';
361       if (EventEmitter.listenerCount(self, eventName) > 0) {
362         debug('SERVER have listener for %s', eventName);
363         var bodyHead = d.slice(bytesParsed, d.length);
364
365         // TODO(isaacs): Need a way to reset a stream to fresh state
366         // IE, not flowing, and not explicitly paused.
367         socket._readableState.flowing = null;
368         self.emit(eventName, req, socket, bodyHead);
369       } else {
370         // Got upgrade header or CONNECT method, but have no handler.
371         socket.destroy();
372       }
373     }
374
375     if (socket._paused) {
376       // onIncoming paused the socket, we should pause the parser as well
377       debug('pause parser');
378       socket.parser.pause();
379     }
380   }
381
382   function socketOnEnd() {
383     var socket = this;
384     var ret = parser.finish();
385
386     if (ret instanceof Error) {
387       debug('parse error');
388       socket.destroy(ret);
389       return;
390     }
391
392     if (!self.httpAllowHalfOpen) {
393       abortIncoming();
394       if (socket.writable) socket.end();
395     } else if (outgoing.length) {
396       outgoing[outgoing.length - 1]._last = true;
397     } else if (socket._httpMessage) {
398       socket._httpMessage._last = true;
399     } else {
400       if (socket.writable) socket.end();
401     }
402   }
403
404
405   // The following callback is issued after the headers have been read on a
406   // new message. In this callback we setup the response object and pass it
407   // to the user.
408
409   socket._paused = false;
410   function socketOnDrain() {
411     // If we previously paused, then start reading again.
412     if (socket._paused) {
413       socket._paused = false;
414       socket.parser.resume();
415       socket.resume();
416     }
417   }
418   socket.on('drain', socketOnDrain);
419
420   function parserOnIncoming(req, shouldKeepAlive) {
421     incoming.push(req);
422
423     // If the writable end isn't consuming, then stop reading
424     // so that we don't become overwhelmed by a flood of
425     // pipelined requests that may never be resolved.
426     if (!socket._paused) {
427       var needPause = socket._writableState.needDrain;
428       if (needPause) {
429         socket._paused = true;
430         // We also need to pause the parser, but don't do that until after
431         // the call to execute, because we may still be processing the last
432         // chunk.
433         socket.pause();
434       }
435     }
436
437     var res = new ServerResponse(req);
438
439     res.shouldKeepAlive = shouldKeepAlive;
440     DTRACE_HTTP_SERVER_REQUEST(req, socket);
441     COUNTER_HTTP_SERVER_REQUEST();
442
443     if (socket._httpMessage) {
444       // There are already pending outgoing res, append.
445       outgoing.push(res);
446     } else {
447       res.assignSocket(socket);
448     }
449
450     // When we're finished writing the response, check if this is the last
451     // respose, if so destroy the socket.
452     res.on('prefinish', resOnFinish);
453     function resOnFinish() {
454       // Usually the first incoming element should be our request.  it may
455       // be that in the case abortIncoming() was called that the incoming
456       // array will be empty.
457       assert(incoming.length === 0 || incoming[0] === req);
458
459       incoming.shift();
460
461       // if the user never called req.read(), and didn't pipe() or
462       // .resume() or .on('data'), then we call req._dump() so that the
463       // bytes will be pulled off the wire.
464       if (!req._consuming && !req._readableState.resumeScheduled)
465         req._dump();
466
467       res.detachSocket(socket);
468
469       if (res._last) {
470         socket.destroySoon();
471       } else {
472         // start sending the next message
473         var m = outgoing.shift();
474         if (m) {
475           m.assignSocket(socket);
476         }
477       }
478     }
479
480     if (!util.isUndefined(req.headers.expect) &&
481         (req.httpVersionMajor == 1 && req.httpVersionMinor == 1) &&
482         continueExpression.test(req.headers['expect'])) {
483       res._expect_continue = true;
484       if (EventEmitter.listenerCount(self, 'checkContinue') > 0) {
485         self.emit('checkContinue', req, res);
486       } else {
487         res.writeContinue();
488         self.emit('request', req, res);
489       }
490     } else {
491       self.emit('request', req, res);
492     }
493     return false; // Not a HEAD response. (Not even a response!)
494   }
495 }
496 exports._connectionListener = connectionListener;