PageRenderTime 59ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/_http_common.js

https://gitlab.com/GeekSir/node
JavaScript | 228 lines | 132 code | 39 blank | 57 comment | 22 complexity | c29ffc025b7bb6e1ff005b8872f8b22b 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 FreeList = require('freelist').FreeList;
  23. var HTTPParser = process.binding('http_parser').HTTPParser;
  24. var incoming = require('_http_incoming');
  25. var IncomingMessage = incoming.IncomingMessage;
  26. var readStart = incoming.readStart;
  27. var readStop = incoming.readStop;
  28. var isNumber = require('util').isNumber;
  29. var debug = require('util').debuglog('http');
  30. exports.debug = debug;
  31. exports.CRLF = '\r\n';
  32. exports.chunkExpression = /chunk/i;
  33. exports.continueExpression = /100-continue/i;
  34. exports.methods = HTTPParser.methods;
  35. var kOnHeaders = HTTPParser.kOnHeaders | 0;
  36. var kOnHeadersComplete = HTTPParser.kOnHeadersComplete | 0;
  37. var kOnBody = HTTPParser.kOnBody | 0;
  38. var kOnMessageComplete = HTTPParser.kOnMessageComplete | 0;
  39. // Only called in the slow case where slow means
  40. // that the request headers were either fragmented
  41. // across multiple TCP packets or too large to be
  42. // processed in a single run. This method is also
  43. // called to process trailing HTTP headers.
  44. function parserOnHeaders(headers, url) {
  45. // Once we exceeded headers limit - stop collecting them
  46. if (this.maxHeaderPairs <= 0 ||
  47. this._headers.length < this.maxHeaderPairs) {
  48. this._headers = this._headers.concat(headers);
  49. }
  50. this._url += url;
  51. }
  52. // info.headers and info.url are set only if .onHeaders()
  53. // has not been called for this request.
  54. //
  55. // info.url is not set for response parsers but that's not
  56. // applicable here since all our parsers are request parsers.
  57. function parserOnHeadersComplete(info) {
  58. debug('parserOnHeadersComplete', info);
  59. var parser = this;
  60. var headers = info.headers;
  61. var url = info.url;
  62. if (!headers) {
  63. headers = parser._headers;
  64. parser._headers = [];
  65. }
  66. if (!url) {
  67. url = parser._url;
  68. parser._url = '';
  69. }
  70. parser.incoming = new IncomingMessage(parser.socket);
  71. parser.incoming.httpVersionMajor = info.versionMajor;
  72. parser.incoming.httpVersionMinor = info.versionMinor;
  73. parser.incoming.httpVersion = info.versionMajor + '.' + info.versionMinor;
  74. parser.incoming.url = url;
  75. var n = headers.length;
  76. // If parser.maxHeaderPairs <= 0 - assume that there're no limit
  77. if (parser.maxHeaderPairs > 0) {
  78. n = Math.min(n, parser.maxHeaderPairs);
  79. }
  80. parser.incoming._addHeaderLines(headers, n);
  81. if (isNumber(info.method)) {
  82. // server only
  83. parser.incoming.method = HTTPParser.methods[info.method];
  84. } else {
  85. // client only
  86. parser.incoming.statusCode = info.statusCode;
  87. parser.incoming.statusMessage = info.statusMessage;
  88. }
  89. parser.incoming.upgrade = info.upgrade;
  90. var skipBody = false; // response to HEAD or CONNECT
  91. if (!info.upgrade) {
  92. // For upgraded connections and CONNECT method request,
  93. // we'll emit this after parser.execute
  94. // so that we can capture the first part of the new protocol
  95. skipBody = parser.onIncoming(parser.incoming, info.shouldKeepAlive);
  96. }
  97. return skipBody;
  98. }
  99. // XXX This is a mess.
  100. // TODO: http.Parser should be a Writable emits request/response events.
  101. function parserOnBody(b, start, len) {
  102. var parser = this;
  103. var stream = parser.incoming;
  104. // if the stream has already been removed, then drop it.
  105. if (!stream)
  106. return;
  107. var socket = stream.socket;
  108. // pretend this was the result of a stream._read call.
  109. if (len > 0 && !stream._dumped) {
  110. var slice = b.slice(start, start + len);
  111. var ret = stream.push(slice);
  112. if (!ret)
  113. readStop(socket);
  114. }
  115. }
  116. function parserOnMessageComplete() {
  117. var parser = this;
  118. var stream = parser.incoming;
  119. if (stream) {
  120. stream.complete = true;
  121. // Emit any trailing headers.
  122. var headers = parser._headers;
  123. if (headers) {
  124. parser.incoming._addHeaderLines(headers, headers.length);
  125. parser._headers = [];
  126. parser._url = '';
  127. }
  128. if (!stream.upgrade)
  129. // For upgraded connections, also emit this after parser.execute
  130. stream.push(null);
  131. }
  132. if (stream && !parser.incoming._pendings.length) {
  133. // For emit end event
  134. stream.push(null);
  135. }
  136. // force to read the next incoming message
  137. readStart(parser.socket);
  138. }
  139. var parsers = new FreeList('parsers', 1000, function() {
  140. var parser = new HTTPParser(HTTPParser.REQUEST);
  141. parser._headers = [];
  142. parser._url = '';
  143. // Only called in the slow case where slow means
  144. // that the request headers were either fragmented
  145. // across multiple TCP packets or too large to be
  146. // processed in a single run. This method is also
  147. // called to process trailing HTTP headers.
  148. parser[kOnHeaders] = parserOnHeaders;
  149. parser[kOnHeadersComplete] = parserOnHeadersComplete;
  150. parser[kOnBody] = parserOnBody;
  151. parser[kOnMessageComplete] = parserOnMessageComplete;
  152. return parser;
  153. });
  154. exports.parsers = parsers;
  155. // Free the parser and also break any links that it
  156. // might have to any other things.
  157. // TODO: All parser data should be attached to a
  158. // single object, so that it can be easily cleaned
  159. // up by doing `parser.data = {}`, which should
  160. // be done in FreeList.free. `parsers.free(parser)`
  161. // should be all that is needed.
  162. function freeParser(parser, req, socket) {
  163. if (parser) {
  164. parser._headers = [];
  165. parser.onIncoming = null;
  166. if (parser.socket)
  167. parser.socket.parser = null;
  168. parser.socket = null;
  169. parser.incoming = null;
  170. if (parsers.free(parser) === false)
  171. parser.close();
  172. parser = null;
  173. }
  174. if (req) {
  175. req.parser = null;
  176. }
  177. if (socket) {
  178. socket.parser = null;
  179. }
  180. }
  181. exports.freeParser = freeParser;
  182. function ondrain() {
  183. if (this._httpMessage) this._httpMessage.emit('drain');
  184. }
  185. function httpSocketSetup(socket) {
  186. socket.removeListener('drain', ondrain);
  187. socket.on('drain', ondrain);
  188. }
  189. exports.httpSocketSetup = httpSocketSetup;