PageRenderTime 56ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/_http_server.js

https://gitlab.com/GeekSir/node
JavaScript | 498 lines | 333 code | 75 blank | 90 comment | 68 complexity | 7e863076851c5cefb9199932160662fd MD5 | raw file
Possible License(s): 0BSD, Apache-2.0, MPL-2.0-no-copyleft-exception, JSON, WTFPL, CC-BY-SA-3.0, Unlicense, ISC, BSD-3-Clause, MIT, AGPL-3.0
  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. 'use strict';
  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. var common = require('_http_common');
  28. var parsers = common.parsers;
  29. var freeParser = common.freeParser;
  30. var debug = common.debug;
  31. var CRLF = common.CRLF;
  32. var continueExpression = common.continueExpression;
  33. var chunkExpression = common.chunkExpression;
  34. var httpSocketSetup = common.httpSocketSetup;
  35. var OutgoingMessage = require('_http_outgoing').OutgoingMessage;
  36. var STATUS_CODES = exports.STATUS_CODES = {
  37. 100 : 'Continue',
  38. 101 : 'Switching Protocols',
  39. 102 : 'Processing', // RFC 2518, obsoleted by RFC 4918
  40. 200 : 'OK',
  41. 201 : 'Created',
  42. 202 : 'Accepted',
  43. 203 : 'Non-Authoritative Information',
  44. 204 : 'No Content',
  45. 205 : 'Reset Content',
  46. 206 : 'Partial Content',
  47. 207 : 'Multi-Status', // RFC 4918
  48. 300 : 'Multiple Choices',
  49. 301 : 'Moved Permanently',
  50. 302 : 'Moved Temporarily',
  51. 303 : 'See Other',
  52. 304 : 'Not Modified',
  53. 305 : 'Use Proxy',
  54. 307 : 'Temporary Redirect',
  55. 308 : 'Permanent Redirect', // RFC 7238
  56. 400 : 'Bad Request',
  57. 401 : 'Unauthorized',
  58. 402 : 'Payment Required',
  59. 403 : 'Forbidden',
  60. 404 : 'Not Found',
  61. 405 : 'Method Not Allowed',
  62. 406 : 'Not Acceptable',
  63. 407 : 'Proxy Authentication Required',
  64. 408 : 'Request Time-out',
  65. 409 : 'Conflict',
  66. 410 : 'Gone',
  67. 411 : 'Length Required',
  68. 412 : 'Precondition Failed',
  69. 413 : 'Request Entity Too Large',
  70. 414 : 'Request-URI Too Large',
  71. 415 : 'Unsupported Media Type',
  72. 416 : 'Requested Range Not Satisfiable',
  73. 417 : 'Expectation Failed',
  74. 418 : 'I\'m a teapot', // RFC 2324
  75. 422 : 'Unprocessable Entity', // RFC 4918
  76. 423 : 'Locked', // RFC 4918
  77. 424 : 'Failed Dependency', // RFC 4918
  78. 425 : 'Unordered Collection', // RFC 4918
  79. 426 : 'Upgrade Required', // RFC 2817
  80. 428 : 'Precondition Required', // RFC 6585
  81. 429 : 'Too Many Requests', // RFC 6585
  82. 431 : 'Request Header Fields Too Large',// RFC 6585
  83. 500 : 'Internal Server Error',
  84. 501 : 'Not Implemented',
  85. 502 : 'Bad Gateway',
  86. 503 : 'Service Unavailable',
  87. 504 : 'Gateway Time-out',
  88. 505 : 'HTTP Version Not Supported',
  89. 506 : 'Variant Also Negotiates', // RFC 2295
  90. 507 : 'Insufficient Storage', // RFC 4918
  91. 509 : 'Bandwidth Limit Exceeded',
  92. 510 : 'Not Extended', // RFC 2774
  93. 511 : 'Network Authentication Required' // RFC 6585
  94. };
  95. function ServerResponse(req) {
  96. OutgoingMessage.call(this);
  97. if (req.method === 'HEAD') this._hasBody = false;
  98. this.sendDate = true;
  99. if (req.httpVersionMajor < 1 || req.httpVersionMinor < 1) {
  100. this.useChunkedEncodingByDefault = chunkExpression.test(req.headers.te);
  101. this.shouldKeepAlive = false;
  102. }
  103. }
  104. util.inherits(ServerResponse, OutgoingMessage);
  105. ServerResponse.prototype._finish = function() {
  106. DTRACE_HTTP_SERVER_RESPONSE(this.connection);
  107. COUNTER_HTTP_SERVER_RESPONSE();
  108. OutgoingMessage.prototype._finish.call(this);
  109. };
  110. exports.ServerResponse = ServerResponse;
  111. ServerResponse.prototype.statusCode = 200;
  112. ServerResponse.prototype.statusMessage = undefined;
  113. function onServerResponseClose() {
  114. // EventEmitter.emit makes a copy of the 'close' listeners array before
  115. // calling the listeners. detachSocket() unregisters onServerResponseClose
  116. // but if detachSocket() is called, directly or indirectly, by a 'close'
  117. // listener, onServerResponseClose is still in that copy of the listeners
  118. // array. That is, in the example below, b still gets called even though
  119. // it's been removed by a:
  120. //
  121. // var obj = new events.EventEmitter;
  122. // obj.on('event', a);
  123. // obj.on('event', b);
  124. // function a() { obj.removeListener('event', b) }
  125. // function b() { throw "BAM!" }
  126. // obj.emit('event'); // throws
  127. //
  128. // Ergo, we need to deal with stale 'close' events and handle the case
  129. // where the ServerResponse object has already been deconstructed.
  130. // Fortunately, that requires only a single if check. :-)
  131. if (this._httpMessage) this._httpMessage.emit('close');
  132. }
  133. ServerResponse.prototype.assignSocket = function(socket) {
  134. assert(!socket._httpMessage);
  135. socket._httpMessage = this;
  136. socket.on('close', onServerResponseClose);
  137. this.socket = socket;
  138. this.connection = socket;
  139. this.emit('socket', socket);
  140. this._flush();
  141. };
  142. ServerResponse.prototype.detachSocket = function(socket) {
  143. assert(socket._httpMessage === this);
  144. socket.removeListener('close', onServerResponseClose);
  145. socket._httpMessage = null;
  146. this.socket = this.connection = null;
  147. };
  148. ServerResponse.prototype.writeContinue = function(cb) {
  149. this._writeRaw('HTTP/1.1 100 Continue' + CRLF + CRLF, 'ascii', cb);
  150. this._sent100 = true;
  151. };
  152. ServerResponse.prototype._implicitHeader = function() {
  153. this.writeHead(this.statusCode);
  154. };
  155. ServerResponse.prototype.writeHead = function(statusCode, reason, obj) {
  156. var headers;
  157. if (util.isString(reason)) {
  158. // writeHead(statusCode, reasonPhrase[, headers])
  159. this.statusMessage = reason;
  160. } else {
  161. // writeHead(statusCode[, headers])
  162. this.statusMessage =
  163. this.statusMessage || STATUS_CODES[statusCode] || 'unknown';
  164. obj = reason;
  165. }
  166. this.statusCode = statusCode;
  167. if (this._headers) {
  168. // Slow-case: when progressive API and header fields are passed.
  169. if (obj) {
  170. var keys = Object.keys(obj);
  171. for (var i = 0; i < keys.length; i++) {
  172. var k = keys[i];
  173. if (k) this.setHeader(k, obj[k]);
  174. }
  175. }
  176. // only progressive api is used
  177. headers = this._renderHeaders();
  178. } else {
  179. // only writeHead() called
  180. headers = obj;
  181. }
  182. var statusLine = 'HTTP/1.1 ' + statusCode.toString() + ' ' +
  183. this.statusMessage + CRLF;
  184. if (statusCode === 204 || statusCode === 304 ||
  185. (100 <= statusCode && statusCode <= 199)) {
  186. // RFC 2616, 10.2.5:
  187. // The 204 response MUST NOT include a message-body, and thus is always
  188. // terminated by the first empty line after the header fields.
  189. // RFC 2616, 10.3.5:
  190. // The 304 response MUST NOT contain a message-body, and thus is always
  191. // terminated by the first empty line after the header fields.
  192. // RFC 2616, 10.1 Informational 1xx:
  193. // This class of status code indicates a provisional response,
  194. // consisting only of the Status-Line and optional headers, and is
  195. // terminated by an empty line.
  196. this._hasBody = false;
  197. }
  198. // don't keep alive connections where the client expects 100 Continue
  199. // but we sent a final status; they may put extra bytes on the wire.
  200. if (this._expect_continue && !this._sent100) {
  201. this.shouldKeepAlive = false;
  202. }
  203. this._storeHeader(statusLine, headers);
  204. };
  205. ServerResponse.prototype.writeHeader = function() {
  206. this.writeHead.apply(this, arguments);
  207. };
  208. function Server(requestListener) {
  209. if (!(this instanceof Server)) return new Server(requestListener);
  210. net.Server.call(this, { allowHalfOpen: true });
  211. if (requestListener) {
  212. this.addListener('request', requestListener);
  213. }
  214. // Similar option to this. Too lazy to write my own docs.
  215. // http://www.squid-cache.org/Doc/config/half_closed_clients/
  216. // http://wiki.squid-cache.org/SquidFaq/InnerWorkings#What_is_a_half-closed_filedescriptor.3F
  217. this.httpAllowHalfOpen = false;
  218. this.addListener('connection', connectionListener);
  219. this.addListener('clientError', function(err, conn) {
  220. conn.destroy(err);
  221. });
  222. this.timeout = 2 * 60 * 1000;
  223. }
  224. util.inherits(Server, net.Server);
  225. Server.prototype.setTimeout = function(msecs, callback) {
  226. this.timeout = msecs;
  227. if (callback)
  228. this.on('timeout', callback);
  229. };
  230. exports.Server = Server;
  231. function connectionListener(socket) {
  232. var self = this;
  233. var outgoing = [];
  234. var incoming = [];
  235. function abortIncoming() {
  236. while (incoming.length) {
  237. var req = incoming.shift();
  238. req.emit('aborted');
  239. req.emit('close');
  240. }
  241. // abort socket._httpMessage ?
  242. }
  243. function serverSocketCloseListener() {
  244. debug('server socket close');
  245. // mark this parser as reusable
  246. if (this.parser) {
  247. freeParser(this.parser, null, this);
  248. }
  249. abortIncoming();
  250. }
  251. debug('SERVER new http connection');
  252. httpSocketSetup(socket);
  253. // If the user has added a listener to the server,
  254. // request, or response, then it's their responsibility.
  255. // otherwise, destroy on timeout by default
  256. if (self.timeout)
  257. socket.setTimeout(self.timeout);
  258. socket.on('timeout', function() {
  259. var req = socket.parser && socket.parser.incoming;
  260. var reqTimeout = req && !req.complete && req.emit('timeout', socket);
  261. var res = socket._httpMessage;
  262. var resTimeout = res && res.emit('timeout', socket);
  263. var serverTimeout = self.emit('timeout', socket);
  264. if (!reqTimeout && !resTimeout && !serverTimeout)
  265. socket.destroy();
  266. });
  267. var parser = parsers.alloc();
  268. parser.reinitialize(HTTPParser.REQUEST);
  269. parser.socket = socket;
  270. socket.parser = parser;
  271. parser.incoming = null;
  272. // Propagate headers limit from server instance to parser
  273. if (util.isNumber(this.maxHeadersCount)) {
  274. parser.maxHeaderPairs = this.maxHeadersCount << 1;
  275. } else {
  276. // Set default value because parser may be reused from FreeList
  277. parser.maxHeaderPairs = 2000;
  278. }
  279. socket.addListener('error', socketOnError);
  280. socket.addListener('close', serverSocketCloseListener);
  281. parser.onIncoming = parserOnIncoming;
  282. socket.on('end', socketOnEnd);
  283. socket.on('data', socketOnData);
  284. // TODO(isaacs): Move all these functions out of here
  285. function socketOnError(e) {
  286. self.emit('clientError', e, this);
  287. }
  288. function socketOnData(d) {
  289. assert(!socket._paused);
  290. debug('SERVER socketOnData %d', d.length);
  291. var ret = parser.execute(d);
  292. if (ret instanceof Error) {
  293. debug('parse error');
  294. socket.destroy(ret);
  295. } else if (parser.incoming && parser.incoming.upgrade) {
  296. // Upgrade or CONNECT
  297. var bytesParsed = ret;
  298. var req = parser.incoming;
  299. debug('SERVER upgrade or connect', req.method);
  300. socket.removeListener('data', socketOnData);
  301. socket.removeListener('end', socketOnEnd);
  302. socket.removeListener('close', serverSocketCloseListener);
  303. parser.finish();
  304. freeParser(parser, req, null);
  305. parser = null;
  306. var eventName = req.method === 'CONNECT' ? 'connect' : 'upgrade';
  307. if (EventEmitter.listenerCount(self, eventName) > 0) {
  308. debug('SERVER have listener for %s', eventName);
  309. var bodyHead = d.slice(bytesParsed, d.length);
  310. // TODO(isaacs): Need a way to reset a stream to fresh state
  311. // IE, not flowing, and not explicitly paused.
  312. socket._readableState.flowing = null;
  313. self.emit(eventName, req, socket, bodyHead);
  314. } else {
  315. // Got upgrade header or CONNECT method, but have no handler.
  316. socket.destroy();
  317. }
  318. }
  319. if (socket._paused) {
  320. // onIncoming paused the socket, we should pause the parser as well
  321. debug('pause parser');
  322. socket.parser.pause();
  323. }
  324. }
  325. function socketOnEnd() {
  326. var socket = this;
  327. var ret = parser.finish();
  328. if (ret instanceof Error) {
  329. debug('parse error');
  330. socket.destroy(ret);
  331. return;
  332. }
  333. if (!self.httpAllowHalfOpen) {
  334. abortIncoming();
  335. if (socket.writable) socket.end();
  336. } else if (outgoing.length) {
  337. outgoing[outgoing.length - 1]._last = true;
  338. } else if (socket._httpMessage) {
  339. socket._httpMessage._last = true;
  340. } else {
  341. if (socket.writable) socket.end();
  342. }
  343. }
  344. // The following callback is issued after the headers have been read on a
  345. // new message. In this callback we setup the response object and pass it
  346. // to the user.
  347. socket._paused = false;
  348. function socketOnDrain() {
  349. // If we previously paused, then start reading again.
  350. if (socket._paused) {
  351. socket._paused = false;
  352. socket.parser.resume();
  353. socket.resume();
  354. }
  355. }
  356. socket.on('drain', socketOnDrain);
  357. function parserOnIncoming(req, shouldKeepAlive) {
  358. incoming.push(req);
  359. // If the writable end isn't consuming, then stop reading
  360. // so that we don't become overwhelmed by a flood of
  361. // pipelined requests that may never be resolved.
  362. if (!socket._paused) {
  363. var needPause = socket._writableState.needDrain;
  364. if (needPause) {
  365. socket._paused = true;
  366. // We also need to pause the parser, but don't do that until after
  367. // the call to execute, because we may still be processing the last
  368. // chunk.
  369. socket.pause();
  370. }
  371. }
  372. var res = new ServerResponse(req);
  373. res.shouldKeepAlive = shouldKeepAlive;
  374. DTRACE_HTTP_SERVER_REQUEST(req, socket);
  375. COUNTER_HTTP_SERVER_REQUEST();
  376. if (socket._httpMessage) {
  377. // There are already pending outgoing res, append.
  378. outgoing.push(res);
  379. } else {
  380. res.assignSocket(socket);
  381. }
  382. // When we're finished writing the response, check if this is the last
  383. // response, if so destroy the socket.
  384. res.on('prefinish', resOnFinish);
  385. function resOnFinish() {
  386. // Usually the first incoming element should be our request. it may
  387. // be that in the case abortIncoming() was called that the incoming
  388. // array will be empty.
  389. assert(incoming.length === 0 || incoming[0] === req);
  390. incoming.shift();
  391. // if the user never called req.read(), and didn't pipe() or
  392. // .resume() or .on('data'), then we call req._dump() so that the
  393. // bytes will be pulled off the wire.
  394. if (!req._consuming && !req._readableState.resumeScheduled)
  395. req._dump();
  396. res.detachSocket(socket);
  397. if (res._last) {
  398. socket.destroySoon();
  399. } else {
  400. // start sending the next message
  401. var m = outgoing.shift();
  402. if (m) {
  403. m.assignSocket(socket);
  404. }
  405. }
  406. }
  407. if (!util.isUndefined(req.headers.expect) &&
  408. (req.httpVersionMajor == 1 && req.httpVersionMinor == 1) &&
  409. continueExpression.test(req.headers['expect'])) {
  410. res._expect_continue = true;
  411. if (EventEmitter.listenerCount(self, 'checkContinue') > 0) {
  412. self.emit('checkContinue', req, res);
  413. } else {
  414. res.writeContinue();
  415. self.emit('request', req, res);
  416. }
  417. } else {
  418. self.emit('request', req, res);
  419. }
  420. return false; // Not a HEAD response. (Not even a response!)
  421. }
  422. }
  423. exports._connectionListener = connectionListener;