http.js 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263
  1. // Public API
  2. // ==========
  3. // The main governing power behind the http2 API design is that it should look very similar to the
  4. // existing node.js [HTTPS API][1] (which is, in turn, almost identical to the [HTTP API][2]). The
  5. // additional features of HTTP/2 are exposed as extensions to this API. Furthermore, node-http2
  6. // should fall back to using HTTP/1.1 if needed. Compatibility with undocumented or deprecated
  7. // elements of the node.js HTTP/HTTPS API is a non-goal.
  8. //
  9. // Additional and modified API elements
  10. // ------------------------------------
  11. //
  12. // - **Class: http2.Endpoint**: an API for using the raw HTTP/2 framing layer. For documentation
  13. // see [protocol/endpoint.js](protocol/endpoint.html).
  14. //
  15. // - **Class: http2.Server**
  16. // - **Event: 'connection' (socket, [endpoint])**: there's a second argument if the negotiation of
  17. // HTTP/2 was successful: the reference to the [Endpoint](protocol/endpoint.html) object tied to the
  18. // socket.
  19. //
  20. // - **http2.createServer(options, [requestListener])**: additional option:
  21. // - **log**: an optional [bunyan](https://github.com/trentm/node-bunyan) logger object
  22. //
  23. // - **Class: http2.ServerResponse**
  24. // - **response.push(options)**: initiates a server push. `options` describes the 'imaginary'
  25. // request to which the push stream is a response; the possible options are identical to the
  26. // ones accepted by `http2.request`. Returns a ServerResponse object that can be used to send
  27. // the response headers and content.
  28. //
  29. // - **Class: http2.Agent**
  30. // - **new Agent(options)**: additional option:
  31. // - **log**: an optional [bunyan](https://github.com/trentm/node-bunyan) logger object
  32. // - **agent.sockets**: only contains TCP sockets that corresponds to HTTP/1 requests.
  33. // - **agent.endpoints**: contains [Endpoint](protocol/endpoint.html) objects for HTTP/2 connections.
  34. //
  35. // - **http2.request(options, [callback])**:
  36. // - similar to http.request
  37. //
  38. // - **http2.get(options, [callback])**:
  39. // - similar to http.get
  40. //
  41. // - **Class: http2.ClientRequest**
  42. // - **Event: 'socket' (socket)**: in case of an HTTP/2 incoming message, `socket` is a reference
  43. // to the associated [HTTP/2 Stream](protocol/stream.html) object (and not to the TCP socket).
  44. // - **Event: 'push' (promise)**: signals the intention of a server push associated to this
  45. // request. `promise` is an IncomingPromise. If there's no listener for this event, the server
  46. // push is cancelled.
  47. // - **request.setPriority(priority)**: assign a priority to this request. `priority` is a number
  48. // between 0 (highest priority) and 2^31-1 (lowest priority). Default value is 2^30.
  49. //
  50. // - **Class: http2.IncomingMessage**
  51. // - has two subclasses for easier interface description: **IncomingRequest** and
  52. // **IncomingResponse**
  53. // - **message.socket**: in case of an HTTP/2 incoming message, it's a reference to the associated
  54. // [HTTP/2 Stream](protocol/stream.html) object (and not to the TCP socket).
  55. //
  56. // - **Class: http2.IncomingRequest (IncomingMessage)**
  57. // - **message.url**: in case of an HTTP/2 incoming request, the `url` field always contains the
  58. // path, and never a full url (it contains the path in most cases in the HTTPS api as well).
  59. // - **message.scheme**: additional field. Mandatory HTTP/2 request metadata.
  60. // - **message.host**: additional field. Mandatory HTTP/2 request metadata. Note that this
  61. // replaces the old Host header field, but node-http2 will add Host to the `message.headers` for
  62. // backwards compatibility.
  63. //
  64. // - **Class: http2.IncomingPromise (IncomingRequest)**
  65. // - contains the metadata of the 'imaginary' request to which the server push is an answer.
  66. // - **Event: 'response' (response)**: signals the arrival of the actual push stream. `response`
  67. // is an IncomingResponse.
  68. // - **Event: 'push' (promise)**: signals the intention of a server push associated to this
  69. // request. `promise` is an IncomingPromise. If there's no listener for this event, the server
  70. // push is cancelled.
  71. // - **promise.cancel()**: cancels the promised server push.
  72. // - **promise.setPriority(priority)**: assign a priority to this push stream. `priority` is a
  73. // number between 0 (highest priority) and 2^31-1 (lowest priority). Default value is 2^30.
  74. //
  75. // API elements not yet implemented
  76. // --------------------------------
  77. //
  78. // - **Class: http2.Server**
  79. // - **server.maxHeadersCount**
  80. //
  81. // API elements that are not applicable to HTTP/2
  82. // ----------------------------------------------
  83. //
  84. // The reason may be deprecation of certain HTTP/1.1 features, or that some API elements simply
  85. // don't make sense when using HTTP/2. These will not be present when a request is done with HTTP/2,
  86. // but will function normally when falling back to using HTTP/1.1.
  87. //
  88. // - **Class: http2.Server**
  89. // - **Event: 'checkContinue'**: not in the spec
  90. // - **Event: 'upgrade'**: upgrade is deprecated in HTTP/2
  91. // - **Event: 'timeout'**: HTTP/2 sockets won't timeout because of application level keepalive
  92. // (PING frames)
  93. // - **Event: 'connect'**: not yet supported
  94. // - **server.setTimeout(msecs, [callback])**
  95. // - **server.timeout**
  96. //
  97. // - **Class: http2.ServerResponse**
  98. // - **Event: 'close'**
  99. // - **Event: 'timeout'**
  100. // - **response.writeContinue()**
  101. // - **response.writeHead(statusCode, [reasonPhrase], [headers])**: reasonPhrase will always be
  102. // ignored since [it's not supported in HTTP/2][3]
  103. // - **response.setTimeout(timeout, [callback])**
  104. //
  105. // - **Class: http2.Agent**
  106. // - **agent.maxSockets**: only affects HTTP/1 connection pool. When using HTTP/2, there's always
  107. // one connection per host.
  108. //
  109. // - **Class: http2.ClientRequest**
  110. // - **Event: 'upgrade'**
  111. // - **Event: 'connect'**
  112. // - **Event: 'continue'**
  113. // - **request.setTimeout(timeout, [callback])**
  114. // - **request.setNoDelay([noDelay])**
  115. // - **request.setSocketKeepAlive([enable], [initialDelay])**
  116. //
  117. // - **Class: http2.IncomingMessage**
  118. // - **Event: 'close'**
  119. // - **message.setTimeout(timeout, [callback])**
  120. //
  121. // [1]: https://nodejs.org/api/https.html
  122. // [2]: https://nodejs.org/api/http.html
  123. // [3]: https://tools.ietf.org/html/rfc7540#section-8.1.2.4
  124. // Common server and client side code
  125. // ==================================
  126. var net = require('net');
  127. var url = require('url');
  128. var util = require('util');
  129. var EventEmitter = require('events').EventEmitter;
  130. var PassThrough = require('stream').PassThrough;
  131. var Readable = require('stream').Readable;
  132. var Writable = require('stream').Writable;
  133. var protocol = require('./protocol');
  134. var Endpoint = protocol.Endpoint;
  135. var http = require('http');
  136. var https = require('https');
  137. exports.STATUS_CODES = http.STATUS_CODES;
  138. exports.IncomingMessage = IncomingMessage;
  139. exports.OutgoingMessage = OutgoingMessage;
  140. exports.protocol = protocol;
  141. var deprecatedHeaders = [
  142. 'connection',
  143. 'host',
  144. 'keep-alive',
  145. 'proxy-connection',
  146. 'transfer-encoding',
  147. 'upgrade'
  148. ];
  149. // When doing NPN/ALPN negotiation, HTTP/1.1 is used as fallback
  150. var supportedProtocols = [protocol.VERSION, 'http/1.1', 'http/1.0'];
  151. // Ciphersuite list based on the recommendations of https://wiki.mozilla.org/Security/Server_Side_TLS
  152. // The only modification is that kEDH+AESGCM were placed after DHE and ECDHE suites
  153. var cipherSuites = [
  154. 'ECDHE-RSA-AES128-GCM-SHA256',
  155. 'ECDHE-ECDSA-AES128-GCM-SHA256',
  156. 'ECDHE-RSA-AES256-GCM-SHA384',
  157. 'ECDHE-ECDSA-AES256-GCM-SHA384',
  158. 'DHE-RSA-AES128-GCM-SHA256',
  159. 'DHE-DSS-AES128-GCM-SHA256',
  160. 'ECDHE-RSA-AES128-SHA256',
  161. 'ECDHE-ECDSA-AES128-SHA256',
  162. 'ECDHE-RSA-AES128-SHA',
  163. 'ECDHE-ECDSA-AES128-SHA',
  164. 'ECDHE-RSA-AES256-SHA384',
  165. 'ECDHE-ECDSA-AES256-SHA384',
  166. 'ECDHE-RSA-AES256-SHA',
  167. 'ECDHE-ECDSA-AES256-SHA',
  168. 'DHE-RSA-AES128-SHA256',
  169. 'DHE-RSA-AES128-SHA',
  170. 'DHE-DSS-AES128-SHA256',
  171. 'DHE-RSA-AES256-SHA256',
  172. 'DHE-DSS-AES256-SHA',
  173. 'DHE-RSA-AES256-SHA',
  174. 'kEDH+AESGCM',
  175. 'AES128-GCM-SHA256',
  176. 'AES256-GCM-SHA384',
  177. 'ECDHE-RSA-RC4-SHA',
  178. 'ECDHE-ECDSA-RC4-SHA',
  179. 'AES128',
  180. 'AES256',
  181. 'RC4-SHA',
  182. 'HIGH',
  183. '!aNULL',
  184. '!eNULL',
  185. '!EXPORT',
  186. '!DES',
  187. '!3DES',
  188. '!MD5',
  189. '!PSK'
  190. ].join(':');
  191. // Logging
  192. // -------
  193. // Logger shim, used when no logger is provided by the user.
  194. function noop() {}
  195. var defaultLogger = {
  196. fatal: noop,
  197. error: noop,
  198. warn : noop,
  199. info : noop,
  200. debug: noop,
  201. trace: noop,
  202. child: function() { return this; }
  203. };
  204. // Bunyan serializers exported by submodules that are worth adding when creating a logger.
  205. exports.serializers = protocol.serializers;
  206. // IncomingMessage class
  207. // ---------------------
  208. function IncomingMessage(stream) {
  209. // * This is basically a read-only wrapper for the [Stream](protocol/stream.html) class.
  210. PassThrough.call(this);
  211. stream.pipe(this);
  212. this.socket = this.stream = stream;
  213. this._log = stream._log.child({ component: 'http' });
  214. // * HTTP/2.0 does not define a way to carry the version identifier that is included in the
  215. // HTTP/1.1 request/status line. Version is always 2.0.
  216. this.httpVersion = '2.0';
  217. this.httpVersionMajor = 2;
  218. this.httpVersionMinor = 0;
  219. // * `this.headers` will store the regular headers (and none of the special colon headers)
  220. this.headers = {};
  221. this.trailers = undefined;
  222. this._lastHeadersSeen = undefined;
  223. // * Other metadata is filled in when the headers arrive.
  224. stream.once('headers', this._onHeaders.bind(this));
  225. stream.once('end', this._onEnd.bind(this));
  226. }
  227. IncomingMessage.prototype = Object.create(PassThrough.prototype, { constructor: { value: IncomingMessage } });
  228. // [Request Header Fields](https://tools.ietf.org/html/rfc7540#section-8.1.2.3)
  229. // * `headers` argument: HTTP/2.0 request and response header fields carry information as a series
  230. // of key-value pairs. This includes the target URI for the request, the status code for the
  231. // response, as well as HTTP header fields.
  232. IncomingMessage.prototype._onHeaders = function _onHeaders(headers) {
  233. // * Detects malformed headers
  234. this._validateHeaders(headers);
  235. // * Store the _regular_ headers in `this.headers`
  236. for (var name in headers) {
  237. if (name[0] !== ':') {
  238. if (name === 'set-cookie' && !Array.isArray(headers[name])) {
  239. this.headers[name] = [headers[name]];
  240. } else {
  241. this.headers[name] = headers[name];
  242. }
  243. }
  244. }
  245. // * The last header block, if it's not the first, will represent the trailers
  246. var self = this;
  247. this.stream.on('headers', function(headers) {
  248. self._lastHeadersSeen = headers;
  249. });
  250. };
  251. IncomingMessage.prototype._onEnd = function _onEnd() {
  252. this.trailers = this._lastHeadersSeen;
  253. };
  254. IncomingMessage.prototype.setTimeout = noop;
  255. IncomingMessage.prototype._checkSpecialHeader = function _checkSpecialHeader(key, value) {
  256. if ((typeof value !== 'string') || (value.length === 0)) {
  257. this._log.error({ key: key, value: value }, 'Invalid or missing special header field');
  258. this.stream.reset('PROTOCOL_ERROR');
  259. }
  260. return value;
  261. };
  262. IncomingMessage.prototype._validateHeaders = function _validateHeaders(headers) {
  263. // * An HTTP/2.0 request or response MUST NOT include any of the following header fields:
  264. // Connection, Host, Keep-Alive, Proxy-Connection, Transfer-Encoding, and Upgrade. A server
  265. // MUST treat the presence of any of these header fields as a stream error of type
  266. // PROTOCOL_ERROR.
  267. // If the TE header is present, it's only valid value is 'trailers'
  268. for (var i = 0; i < deprecatedHeaders.length; i++) {
  269. var key = deprecatedHeaders[i];
  270. if (key in headers || (key === 'te' && headers[key] !== 'trailers')) {
  271. this._log.error({ key: key, value: headers[key] }, 'Deprecated header found');
  272. this.stream.reset('PROTOCOL_ERROR');
  273. return;
  274. }
  275. }
  276. for (var headerName in headers) {
  277. // * Empty header name field is malformed
  278. if (headerName.length <= 1) {
  279. this.stream.reset('PROTOCOL_ERROR');
  280. return;
  281. }
  282. // * A request or response containing uppercase header name field names MUST be
  283. // treated as malformed (Section 8.1.3.5). Implementations that detect malformed
  284. // requests or responses need to ensure that the stream ends.
  285. if(/[A-Z]/.test(headerName)) {
  286. this.stream.reset('PROTOCOL_ERROR');
  287. return;
  288. }
  289. }
  290. };
  291. // OutgoingMessage class
  292. // ---------------------
  293. function OutgoingMessage() {
  294. // * This is basically a read-only wrapper for the [Stream](protocol/stream.html) class.
  295. Writable.call(this);
  296. this._headers = {};
  297. this._trailers = undefined;
  298. this.headersSent = false;
  299. this.finished = false;
  300. this.on('finish', this._finish);
  301. }
  302. OutgoingMessage.prototype = Object.create(Writable.prototype, { constructor: { value: OutgoingMessage } });
  303. OutgoingMessage.prototype._write = function _write(chunk, encoding, callback) {
  304. if (this.stream) {
  305. this.stream.write(chunk, encoding, callback);
  306. } else {
  307. this.once('socket', this._write.bind(this, chunk, encoding, callback));
  308. }
  309. };
  310. OutgoingMessage.prototype._finish = function _finish() {
  311. if (this.stream) {
  312. if (this._trailers) {
  313. if (this.request) {
  314. this.request.addTrailers(this._trailers);
  315. } else {
  316. this.stream.headers(this._trailers);
  317. }
  318. }
  319. this.finished = true;
  320. this.stream.end();
  321. } else {
  322. this.once('socket', this._finish.bind(this));
  323. }
  324. };
  325. OutgoingMessage.prototype.setHeader = function setHeader(name, value) {
  326. if (this.headersSent) {
  327. return this.emit('error', new Error('Can\'t set headers after they are sent.'));
  328. } else {
  329. name = name.toLowerCase();
  330. if (deprecatedHeaders.indexOf(name) !== -1) {
  331. return this.emit('error', new Error('Cannot set deprecated header: ' + name));
  332. }
  333. this._headers[name] = value;
  334. }
  335. };
  336. OutgoingMessage.prototype.removeHeader = function removeHeader(name) {
  337. if (this.headersSent) {
  338. return this.emit('error', new Error('Can\'t remove headers after they are sent.'));
  339. } else {
  340. delete this._headers[name.toLowerCase()];
  341. }
  342. };
  343. OutgoingMessage.prototype.getHeader = function getHeader(name) {
  344. return this._headers[name.toLowerCase()];
  345. };
  346. OutgoingMessage.prototype.addTrailers = function addTrailers(trailers) {
  347. this._trailers = trailers;
  348. };
  349. OutgoingMessage.prototype.setTimeout = noop;
  350. OutgoingMessage.prototype._checkSpecialHeader = IncomingMessage.prototype._checkSpecialHeader;
  351. // Server side
  352. // ===========
  353. exports.Server = Server;
  354. exports.IncomingRequest = IncomingRequest;
  355. exports.OutgoingResponse = OutgoingResponse;
  356. exports.ServerResponse = OutgoingResponse; // for API compatibility
  357. // Forward events `event` on `source` to all listeners on `target`.
  358. //
  359. // Note: The calling context is `source`.
  360. function forwardEvent(event, source, target) {
  361. function forward() {
  362. var listeners = target.listeners(event);
  363. var n = listeners.length;
  364. // Special case for `error` event with no listeners.
  365. if (n === 0 && event === 'error') {
  366. var args = [event];
  367. args.push.apply(args, arguments);
  368. target.emit.apply(target, args);
  369. return;
  370. }
  371. for (var i = 0; i < n; ++i) {
  372. listeners[i].apply(source, arguments);
  373. }
  374. }
  375. source.on(event, forward);
  376. // A reference to the function is necessary to be able to stop
  377. // forwarding.
  378. return forward;
  379. }
  380. // Server class
  381. // ------------
  382. function Server(options) {
  383. options = util._extend({}, options);
  384. this._log = (options.log || defaultLogger).child({ component: 'http' });
  385. this._settings = options.settings;
  386. var start = this._start.bind(this);
  387. var fallback = this._fallback.bind(this);
  388. // HTTP2 over TLS (using NPN or ALPN)
  389. if ((options.key && options.cert) || options.pfx) {
  390. this._log.info('Creating HTTP/2 server over TLS');
  391. this._mode = 'tls';
  392. options.ALPNProtocols = supportedProtocols;
  393. options.NPNProtocols = supportedProtocols;
  394. options.ciphers = options.ciphers || cipherSuites;
  395. options.honorCipherOrder = (options.honorCipherOrder != false);
  396. this._server = https.createServer(options);
  397. this._originalSocketListeners = this._server.listeners('secureConnection');
  398. this._server.removeAllListeners('secureConnection');
  399. this._server.on('secureConnection', function(socket) {
  400. var negotiatedProtocol = socket.alpnProtocol || socket.npnProtocol;
  401. // It's true that the client MUST use SNI, but if it doesn't, we don't care, don't fall back to HTTP/1,
  402. // since if the ALPN negotiation is otherwise successful, the client thinks we speak HTTP/2 but we don't.
  403. if (negotiatedProtocol === protocol.VERSION) {
  404. start(socket);
  405. } else {
  406. fallback(socket);
  407. }
  408. });
  409. this._server.on('request', this.emit.bind(this, 'request'));
  410. forwardEvent('error', this._server, this);
  411. forwardEvent('listening', this._server, this);
  412. }
  413. // HTTP2 over plain TCP
  414. else if (options.plain) {
  415. this._log.info('Creating HTTP/2 server over plain TCP');
  416. this._mode = 'plain';
  417. this._server = net.createServer(start);
  418. }
  419. // HTTP/2 with HTTP/1.1 upgrade
  420. else {
  421. this._log.error('Trying to create HTTP/2 server with Upgrade from HTTP/1.1');
  422. throw new Error('HTTP1.1 -> HTTP2 upgrade is not yet supported. Please provide TLS keys.');
  423. }
  424. this._server.on('close', this.emit.bind(this, 'close'));
  425. }
  426. Server.prototype = Object.create(EventEmitter.prototype, { constructor: { value: Server } });
  427. // Starting HTTP/2
  428. Server.prototype._start = function _start(socket) {
  429. var endpoint = new Endpoint(this._log, 'SERVER', this._settings);
  430. this._log.info({ e: endpoint,
  431. client: socket.remoteAddress + ':' + socket.remotePort,
  432. SNI: socket.servername
  433. }, 'New incoming HTTP/2 connection');
  434. endpoint.pipe(socket).pipe(endpoint);
  435. var self = this;
  436. endpoint.on('stream', function _onStream(stream) {
  437. var response = new OutgoingResponse(stream);
  438. var request = new IncomingRequest(stream);
  439. // Some conformance to Node.js Https specs allows to distinguish clients:
  440. request.remoteAddress = socket.remoteAddress;
  441. request.remotePort = socket.remotePort;
  442. request.connection = request.socket = response.socket = socket;
  443. request.once('ready', self.emit.bind(self, 'request', request, response));
  444. });
  445. endpoint.on('error', this.emit.bind(this, 'clientError'));
  446. socket.on('error', this.emit.bind(this, 'clientError'));
  447. this.emit('connection', socket, endpoint);
  448. };
  449. Server.prototype._fallback = function _fallback(socket) {
  450. var negotiatedProtocol = socket.alpnProtocol || socket.npnProtocol;
  451. this._log.info({ client: socket.remoteAddress + ':' + socket.remotePort,
  452. protocol: negotiatedProtocol,
  453. SNI: socket.servername
  454. }, 'Falling back to simple HTTPS');
  455. for (var i = 0; i < this._originalSocketListeners.length; i++) {
  456. this._originalSocketListeners[i].call(this._server, socket);
  457. }
  458. this.emit('connection', socket);
  459. };
  460. // There are [3 possible signatures][1] of the `listen` function. Every arguments is forwarded to
  461. // the backing TCP or HTTPS server.
  462. // [1]: https://nodejs.org/api/http.html#http_server_listen_port_hostname_backlog_callback
  463. Server.prototype.listen = function listen(port, hostname) {
  464. this._log.info({ on: ((typeof hostname === 'string') ? (hostname + ':' + port) : port) },
  465. 'Listening for incoming connections');
  466. this._server.listen.apply(this._server, arguments);
  467. return this._server;
  468. };
  469. Server.prototype.close = function close(callback) {
  470. this._log.info('Closing server');
  471. this._server.close(callback);
  472. };
  473. Server.prototype.setTimeout = function setTimeout(timeout, callback) {
  474. if (this._mode === 'tls') {
  475. this._server.setTimeout(timeout, callback);
  476. }
  477. };
  478. Object.defineProperty(Server.prototype, 'timeout', {
  479. get: function getTimeout() {
  480. if (this._mode === 'tls') {
  481. return this._server.timeout;
  482. } else {
  483. return undefined;
  484. }
  485. },
  486. set: function setTimeout(timeout) {
  487. if (this._mode === 'tls') {
  488. this._server.timeout = timeout;
  489. }
  490. }
  491. });
  492. // Overriding `EventEmitter`'s `on(event, listener)` method to forward certain subscriptions to
  493. // `server`.There are events on the `http.Server` class where it makes difference whether someone is
  494. // listening on the event or not. In these cases, we can not simply forward the events from the
  495. // `server` to `this` since that means a listener. Instead, we forward the subscriptions.
  496. Server.prototype.on = function on(event, listener) {
  497. if ((event === 'upgrade') || (event === 'timeout')) {
  498. return this._server.on(event, listener && listener.bind(this));
  499. } else {
  500. return EventEmitter.prototype.on.call(this, event, listener);
  501. }
  502. };
  503. // `addContext` is used to add Server Name Indication contexts
  504. Server.prototype.addContext = function addContext(hostname, credentials) {
  505. if (this._mode === 'tls') {
  506. this._server.addContext(hostname, credentials);
  507. }
  508. };
  509. Server.prototype.address = function address() {
  510. return this._server.address()
  511. };
  512. function createServerRaw(options, requestListener) {
  513. if (typeof options === 'function') {
  514. requestListener = options;
  515. options = {};
  516. }
  517. if (options.pfx || (options.key && options.cert)) {
  518. throw new Error('options.pfx, options.key, and options.cert are nonsensical!');
  519. }
  520. options.plain = true;
  521. var server = new Server(options);
  522. if (requestListener) {
  523. server.on('request', requestListener);
  524. }
  525. return server;
  526. }
  527. function createServerTLS(options, requestListener) {
  528. if (typeof options === 'function') {
  529. throw new Error('options are required!');
  530. }
  531. if (!options.pfx && !(options.key && options.cert)) {
  532. throw new Error('options.pfx or options.key and options.cert are required!');
  533. }
  534. options.plain = false;
  535. var server = new Server(options);
  536. if (requestListener) {
  537. server.on('request', requestListener);
  538. }
  539. return server;
  540. }
  541. // Exposed main interfaces for HTTPS connections (the default)
  542. exports.https = {};
  543. exports.createServer = exports.https.createServer = createServerTLS;
  544. exports.request = exports.https.request = requestTLS;
  545. exports.get = exports.https.get = getTLS;
  546. // Exposed main interfaces for raw TCP connections (not recommended)
  547. exports.raw = {};
  548. exports.raw.createServer = createServerRaw;
  549. exports.raw.request = requestRaw;
  550. exports.raw.get = getRaw;
  551. // Exposed main interfaces for HTTP plaintext upgrade connections (not implemented)
  552. function notImplemented() {
  553. throw new Error('HTTP UPGRADE is not implemented!');
  554. }
  555. exports.http = {};
  556. exports.http.createServer = exports.http.request = exports.http.get = notImplemented;
  557. // IncomingRequest class
  558. // ---------------------
  559. function IncomingRequest(stream) {
  560. IncomingMessage.call(this, stream);
  561. }
  562. IncomingRequest.prototype = Object.create(IncomingMessage.prototype, { constructor: { value: IncomingRequest } });
  563. // [Request Header Fields](https://tools.ietf.org/html/rfc7540#section-8.1.2.3)
  564. // * `headers` argument: HTTP/2.0 request and response header fields carry information as a series
  565. // of key-value pairs. This includes the target URI for the request, the status code for the
  566. // response, as well as HTTP header fields.
  567. IncomingRequest.prototype._onHeaders = function _onHeaders(headers) {
  568. // * The ":method" header field includes the HTTP method
  569. // * The ":scheme" header field includes the scheme portion of the target URI
  570. // * The ":authority" header field includes the authority portion of the target URI
  571. // * The ":path" header field includes the path and query parts of the target URI.
  572. // This field MUST NOT be empty; URIs that do not contain a path component MUST include a value
  573. // of '/', unless the request is an OPTIONS request for '*', in which case the ":path" header
  574. // field MUST include '*'.
  575. // * All HTTP/2.0 requests MUST include exactly one valid value for all of these header fields. A
  576. // server MUST treat the absence of any of these header fields, presence of multiple values, or
  577. // an invalid value as a stream error of type PROTOCOL_ERROR.
  578. this.method = this._checkSpecialHeader(':method' , headers[':method']);
  579. this.scheme = this._checkSpecialHeader(':scheme' , headers[':scheme']);
  580. this.host = this._checkSpecialHeader(':authority', headers[':authority'] );
  581. this.url = this._checkSpecialHeader(':path' , headers[':path'] );
  582. if (!this.method || !this.scheme || !this.host || !this.url) {
  583. // This is invalid, and we've sent a RST_STREAM, so don't continue processing
  584. return;
  585. }
  586. // * Host header is included in the headers object for backwards compatibility.
  587. this.headers.host = this.host;
  588. // * Handling regular headers.
  589. IncomingMessage.prototype._onHeaders.call(this, headers);
  590. // * Signaling that the headers arrived.
  591. this._log.info({ method: this.method, scheme: this.scheme, host: this.host,
  592. path: this.url, headers: this.headers }, 'Incoming request');
  593. this.emit('ready');
  594. };
  595. // OutgoingResponse class
  596. // ----------------------
  597. function OutgoingResponse(stream) {
  598. OutgoingMessage.call(this);
  599. this._log = stream._log.child({ component: 'http' });
  600. this.stream = stream;
  601. this.statusCode = 200;
  602. this.sendDate = true;
  603. this.stream.once('headers', this._onRequestHeaders.bind(this));
  604. }
  605. OutgoingResponse.prototype = Object.create(OutgoingMessage.prototype, { constructor: { value: OutgoingResponse } });
  606. OutgoingResponse.prototype.writeHead = function writeHead(statusCode, reasonPhrase, headers) {
  607. if (this.headersSent) {
  608. return;
  609. }
  610. if (typeof reasonPhrase === 'string') {
  611. this._log.warn('Reason phrase argument was present but ignored by the writeHead method');
  612. } else {
  613. headers = reasonPhrase;
  614. }
  615. for (var name in headers) {
  616. this.setHeader(name, headers[name]);
  617. }
  618. headers = this._headers;
  619. if (this.sendDate && !('date' in this._headers)) {
  620. headers.date = (new Date()).toUTCString();
  621. }
  622. this._log.info({ status: statusCode, headers: this._headers }, 'Sending server response');
  623. headers[':status'] = this.statusCode = statusCode;
  624. this.stream.headers(headers);
  625. this.headersSent = true;
  626. };
  627. OutgoingResponse.prototype._implicitHeaders = function _implicitHeaders() {
  628. if (!this.headersSent) {
  629. this.writeHead(this.statusCode);
  630. }
  631. };
  632. OutgoingResponse.prototype._implicitHeader = function() {
  633. this._implicitHeaders();
  634. };
  635. OutgoingResponse.prototype.write = function write() {
  636. this._implicitHeaders();
  637. return OutgoingMessage.prototype.write.apply(this, arguments);
  638. };
  639. OutgoingResponse.prototype.end = function end() {
  640. this.finshed = true;
  641. this._implicitHeaders();
  642. return OutgoingMessage.prototype.end.apply(this, arguments);
  643. };
  644. OutgoingResponse.prototype._onRequestHeaders = function _onRequestHeaders(headers) {
  645. this._requestHeaders = headers;
  646. };
  647. OutgoingResponse.prototype.push = function push(options) {
  648. if (typeof options === 'string') {
  649. options = url.parse(options);
  650. }
  651. if (!options.path) {
  652. throw new Error('`path` option is mandatory.');
  653. }
  654. var promise = util._extend({
  655. ':method': (options.method || 'GET').toUpperCase(),
  656. ':scheme': (options.protocol && options.protocol.slice(0, -1)) || this._requestHeaders[':scheme'],
  657. ':authority': options.hostname || options.host || this._requestHeaders[':authority'],
  658. ':path': options.path
  659. }, options.headers);
  660. this._log.info({ method: promise[':method'], scheme: promise[':scheme'],
  661. authority: promise[':authority'], path: promise[':path'],
  662. headers: options.headers }, 'Promising push stream');
  663. var pushStream = this.stream.promise(promise);
  664. return new OutgoingResponse(pushStream);
  665. };
  666. OutgoingResponse.prototype.altsvc = function altsvc(host, port, protocolID, maxAge, origin) {
  667. if (origin === undefined) {
  668. origin = "";
  669. }
  670. this.stream.altsvc(host, port, protocolID, maxAge, origin);
  671. };
  672. // Overriding `EventEmitter`'s `on(event, listener)` method to forward certain subscriptions to
  673. // `request`. See `Server.prototype.on` for explanation.
  674. OutgoingResponse.prototype.on = function on(event, listener) {
  675. if (this.request && (event === 'timeout')) {
  676. this.request.on(event, listener && listener.bind(this));
  677. } else {
  678. OutgoingMessage.prototype.on.call(this, event, listener);
  679. }
  680. };
  681. // Client side
  682. // ===========
  683. exports.ClientRequest = OutgoingRequest; // for API compatibility
  684. exports.OutgoingRequest = OutgoingRequest;
  685. exports.IncomingResponse = IncomingResponse;
  686. exports.Agent = Agent;
  687. exports.globalAgent = undefined;
  688. function requestRaw(options, callback) {
  689. if (typeof options === "string") {
  690. options = url.parse(options);
  691. }
  692. options.plain = true;
  693. if (options.protocol && options.protocol !== "http:") {
  694. throw new Error('This interface only supports http-schemed URLs');
  695. }
  696. if (options.agent && typeof(options.agent.request) === 'function') {
  697. var agentOptions = util._extend({}, options);
  698. delete agentOptions.agent;
  699. return options.agent.request(agentOptions, callback);
  700. }
  701. return exports.globalAgent.request(options, callback);
  702. }
  703. function requestTLS(options, callback) {
  704. if (typeof options === "string") {
  705. options = url.parse(options);
  706. }
  707. options.plain = false;
  708. if (options.protocol && options.protocol !== "https:") {
  709. throw new Error('This interface only supports https-schemed URLs');
  710. }
  711. if (options.agent && typeof(options.agent.request) === 'function') {
  712. var agentOptions = util._extend({}, options);
  713. delete agentOptions.agent;
  714. return options.agent.request(agentOptions, callback);
  715. }
  716. return exports.globalAgent.request(options, callback);
  717. }
  718. function getRaw(options, callback) {
  719. if (typeof options === "string") {
  720. options = url.parse(options);
  721. }
  722. options.plain = true;
  723. if (options.protocol && options.protocol !== "http:") {
  724. throw new Error('This interface only supports http-schemed URLs');
  725. }
  726. if (options.agent && typeof(options.agent.get) === 'function') {
  727. var agentOptions = util._extend({}, options);
  728. delete agentOptions.agent;
  729. return options.agent.get(agentOptions, callback);
  730. }
  731. return exports.globalAgent.get(options, callback);
  732. }
  733. function getTLS(options, callback) {
  734. if (typeof options === "string") {
  735. options = url.parse(options);
  736. }
  737. options.plain = false;
  738. if (options.protocol && options.protocol !== "https:") {
  739. throw new Error('This interface only supports https-schemed URLs');
  740. }
  741. if (options.agent && typeof(options.agent.get) === 'function') {
  742. var agentOptions = util._extend({}, options);
  743. delete agentOptions.agent;
  744. return options.agent.get(agentOptions, callback);
  745. }
  746. return exports.globalAgent.get(options, callback);
  747. }
  748. // Agent class
  749. // -----------
  750. function Agent(options) {
  751. EventEmitter.call(this);
  752. this.setMaxListeners(0);
  753. options = util._extend({}, options);
  754. this._settings = options.settings;
  755. this._log = (options.log || defaultLogger).child({ component: 'http' });
  756. this.endpoints = {};
  757. // * Using an own HTTPS agent, because the global agent does not look at `NPN/ALPNProtocols` when
  758. // generating the key identifying the connection, so we may get useless non-negotiated TLS
  759. // channels even if we ask for a negotiated one. This agent will contain only negotiated
  760. // channels.
  761. options.ALPNProtocols = supportedProtocols;
  762. options.NPNProtocols = supportedProtocols;
  763. this._httpsAgent = new https.Agent(options);
  764. this.sockets = this._httpsAgent.sockets;
  765. this.requests = this._httpsAgent.requests;
  766. }
  767. Agent.prototype = Object.create(EventEmitter.prototype, { constructor: { value: Agent } });
  768. Agent.prototype.request = function request(options, callback) {
  769. if (typeof options === 'string') {
  770. options = url.parse(options);
  771. } else {
  772. options = util._extend({}, options);
  773. }
  774. options.method = (options.method || 'GET').toUpperCase();
  775. options.protocol = options.protocol || 'https:';
  776. options.host = options.hostname || options.host || 'localhost';
  777. options.port = options.port || 443;
  778. options.path = options.path || '/';
  779. if (!options.plain && options.protocol === 'http:') {
  780. this._log.error('Trying to negotiate client request with Upgrade from HTTP/1.1');
  781. this.emit('error', new Error('HTTP1.1 -> HTTP2 upgrade is not yet supported.'));
  782. }
  783. var request = new OutgoingRequest(this._log);
  784. if (callback) {
  785. request.on('response', callback);
  786. }
  787. var key = [
  788. !!options.plain,
  789. options.host,
  790. options.port
  791. ].join(':');
  792. var self = this;
  793. // * There's an existing HTTP/2 connection to this host
  794. if (key in this.endpoints) {
  795. var endpoint = this.endpoints[key];
  796. request._start(endpoint.createStream(), options);
  797. }
  798. // * HTTP/2 over plain TCP
  799. else if (options.plain) {
  800. endpoint = new Endpoint(this._log, 'CLIENT', this._settings);
  801. endpoint.socket = net.connect({
  802. host: options.host,
  803. port: options.port,
  804. localAddress: options.localAddress
  805. });
  806. endpoint.socket.on('error', function (error) {
  807. self._log.error('Socket error: ' + error.toString());
  808. request.emit('error', error);
  809. });
  810. endpoint.on('error', function(error){
  811. self._log.error('Connection error: ' + error.toString());
  812. request.emit('error', error);
  813. });
  814. this.endpoints[key] = endpoint;
  815. endpoint.pipe(endpoint.socket).pipe(endpoint);
  816. request._start(endpoint.createStream(), options);
  817. }
  818. // * HTTP/2 over TLS negotiated using NPN or ALPN, or fallback to HTTPS1
  819. else {
  820. var started = false;
  821. var createAgent = hasAgentOptions(options);
  822. options.ALPNProtocols = supportedProtocols;
  823. options.NPNProtocols = supportedProtocols;
  824. options.servername = options.host; // Server Name Indication
  825. options.ciphers = options.ciphers || cipherSuites;
  826. if (createAgent) {
  827. options.agent = new https.Agent(options);
  828. } else if (options.agent == null) {
  829. options.agent = this._httpsAgent;
  830. }
  831. var httpsRequest = https.request(options);
  832. httpsRequest.on('error', function (error) {
  833. self._log.error('Socket error: ' + error.toString());
  834. self.removeAllListeners(key);
  835. request.emit('error', error);
  836. });
  837. httpsRequest.on('socket', function(socket) {
  838. var negotiatedProtocol = socket.alpnProtocol || socket.npnProtocol;
  839. if (negotiatedProtocol != null) { // null in >=0.11.0, undefined in <0.11.0
  840. negotiated();
  841. } else {
  842. socket.on('secureConnect', negotiated);
  843. }
  844. });
  845. function negotiated() {
  846. var endpoint;
  847. var negotiatedProtocol = httpsRequest.socket.alpnProtocol || httpsRequest.socket.npnProtocol;
  848. if (negotiatedProtocol === protocol.VERSION) {
  849. httpsRequest.socket.emit('agentRemove');
  850. unbundleSocket(httpsRequest.socket);
  851. endpoint = new Endpoint(self._log, 'CLIENT', self._settings);
  852. endpoint.socket = httpsRequest.socket;
  853. endpoint.pipe(endpoint.socket).pipe(endpoint);
  854. }
  855. if (started) {
  856. // ** In the meantime, an other connection was made to the same host...
  857. if (endpoint) {
  858. // *** and it turned out to be HTTP2 and the request was multiplexed on that one, so we should close this one
  859. endpoint.close();
  860. }
  861. // *** otherwise, the fallback to HTTPS1 is already done.
  862. } else {
  863. if (endpoint) {
  864. self._log.info({ e: endpoint, server: options.host + ':' + options.port },
  865. 'New outgoing HTTP/2 connection');
  866. self.endpoints[key] = endpoint;
  867. self.emit(key, endpoint);
  868. } else {
  869. self.emit(key, undefined);
  870. }
  871. }
  872. }
  873. this.once(key, function(endpoint) {
  874. started = true;
  875. if (endpoint) {
  876. request._start(endpoint.createStream(), options);
  877. } else {
  878. request._fallback(httpsRequest);
  879. }
  880. });
  881. }
  882. return request;
  883. };
  884. Agent.prototype.get = function get(options, callback) {
  885. var request = this.request(options, callback);
  886. request.end();
  887. return request;
  888. };
  889. Agent.prototype.destroy = function(error) {
  890. if (this._httpsAgent) {
  891. this._httpsAgent.destroy();
  892. }
  893. for (var key in this.endpoints) {
  894. this.endpoints[key].close(error);
  895. }
  896. };
  897. function unbundleSocket(socket) {
  898. socket.removeAllListeners('data');
  899. socket.removeAllListeners('end');
  900. socket.removeAllListeners('readable');
  901. socket.removeAllListeners('close');
  902. socket.removeAllListeners('error');
  903. socket.unpipe();
  904. delete socket.ondata;
  905. delete socket.onend;
  906. }
  907. function hasAgentOptions(options) {
  908. return options.pfx != null ||
  909. options.key != null ||
  910. options.passphrase != null ||
  911. options.cert != null ||
  912. options.ca != null ||
  913. options.ciphers != null ||
  914. options.rejectUnauthorized != null ||
  915. options.secureProtocol != null;
  916. }
  917. Object.defineProperty(Agent.prototype, 'maxSockets', {
  918. get: function getMaxSockets() {
  919. return this._httpsAgent.maxSockets;
  920. },
  921. set: function setMaxSockets(value) {
  922. this._httpsAgent.maxSockets = value;
  923. }
  924. });
  925. exports.globalAgent = new Agent();
  926. // OutgoingRequest class
  927. // ---------------------
  928. function OutgoingRequest() {
  929. OutgoingMessage.call(this);
  930. this._log = undefined;
  931. this.stream = undefined;
  932. }
  933. OutgoingRequest.prototype = Object.create(OutgoingMessage.prototype, { constructor: { value: OutgoingRequest } });
  934. OutgoingRequest.prototype._start = function _start(stream, options) {
  935. this.stream = stream;
  936. this.options = options;
  937. this._log = stream._log.child({ component: 'http' });
  938. for (var key in options.headers) {
  939. this.setHeader(key, options.headers[key]);
  940. }
  941. var headers = this._headers;
  942. delete headers.host;
  943. if (options.auth) {
  944. headers.authorization = 'Basic ' + new Buffer(options.auth).toString('base64');
  945. }
  946. headers[':scheme'] = options.protocol.slice(0, -1);
  947. headers[':method'] = options.method;
  948. headers[':authority'] = options.host;
  949. headers[':path'] = options.path;
  950. this._log.info({ scheme: headers[':scheme'], method: headers[':method'],
  951. authority: headers[':authority'], path: headers[':path'],
  952. headers: (options.headers || {}) }, 'Sending request');
  953. this.stream.headers(headers);
  954. this.headersSent = true;
  955. this.emit('socket', this.stream);
  956. var response = new IncomingResponse(this.stream);
  957. response.req = this;
  958. response.once('ready', this.emit.bind(this, 'response', response));
  959. this.stream.on('promise', this._onPromise.bind(this));
  960. };
  961. OutgoingRequest.prototype._fallback = function _fallback(request) {
  962. request.on('response', this.emit.bind(this, 'response'));
  963. this.stream = this.request = request;
  964. this.emit('socket', this.socket);
  965. };
  966. OutgoingRequest.prototype.setPriority = function setPriority(priority) {
  967. if (this.stream) {
  968. this.stream.priority(priority);
  969. } else {
  970. this.once('socket', this.setPriority.bind(this, priority));
  971. }
  972. };
  973. // Overriding `EventEmitter`'s `on(event, listener)` method to forward certain subscriptions to
  974. // `request`. See `Server.prototype.on` for explanation.
  975. OutgoingRequest.prototype.on = function on(event, listener) {
  976. if (this.request && (event === 'upgrade')) {
  977. this.request.on(event, listener && listener.bind(this));
  978. } else {
  979. OutgoingMessage.prototype.on.call(this, event, listener);
  980. }
  981. };
  982. // Methods only in fallback mode
  983. OutgoingRequest.prototype.setNoDelay = function setNoDelay(noDelay) {
  984. if (this.request) {
  985. this.request.setNoDelay(noDelay);
  986. } else if (!this.stream) {
  987. this.on('socket', this.setNoDelay.bind(this, noDelay));
  988. }
  989. };
  990. OutgoingRequest.prototype.setSocketKeepAlive = function setSocketKeepAlive(enable, initialDelay) {
  991. if (this.request) {
  992. this.request.setSocketKeepAlive(enable, initialDelay);
  993. } else if (!this.stream) {
  994. this.on('socket', this.setSocketKeepAlive.bind(this, enable, initialDelay));
  995. }
  996. };
  997. OutgoingRequest.prototype.setTimeout = function setTimeout(timeout, callback) {
  998. if (this.request) {
  999. this.request.setTimeout(timeout, callback);
  1000. } else if (!this.stream) {
  1001. this.on('socket', this.setTimeout.bind(this, timeout, callback));
  1002. }
  1003. };
  1004. // Aborting the request
  1005. OutgoingRequest.prototype.abort = function abort() {
  1006. if (this.request) {
  1007. this.request.abort();
  1008. } else if (this.stream) {
  1009. this.stream.reset('CANCEL');
  1010. } else {
  1011. this.on('socket', this.abort.bind(this));
  1012. }
  1013. };
  1014. // Receiving push promises
  1015. OutgoingRequest.prototype._onPromise = function _onPromise(stream, headers) {
  1016. this._log.info({ push_stream: stream.id }, 'Receiving push promise');
  1017. var promise = new IncomingPromise(stream, headers);
  1018. if (this.listeners('push').length > 0) {
  1019. this.emit('push', promise);
  1020. } else {
  1021. promise.cancel();
  1022. }
  1023. };
  1024. // IncomingResponse class
  1025. // ----------------------
  1026. function IncomingResponse(stream) {
  1027. IncomingMessage.call(this, stream);
  1028. }
  1029. IncomingResponse.prototype = Object.create(IncomingMessage.prototype, { constructor: { value: IncomingResponse } });
  1030. // [Response Header Fields](https://tools.ietf.org/html/rfc7540#section-8.1.2.4)
  1031. // * `headers` argument: HTTP/2.0 request and response header fields carry information as a series
  1032. // of key-value pairs. This includes the target URI for the request, the status code for the
  1033. // response, as well as HTTP header fields.
  1034. IncomingResponse.prototype._onHeaders = function _onHeaders(headers) {
  1035. // * A single ":status" header field is defined that carries the HTTP status code field. This
  1036. // header field MUST be included in all responses.
  1037. // * A client MUST treat the absence of the ":status" header field, the presence of multiple
  1038. // values, or an invalid value as a stream error of type PROTOCOL_ERROR.
  1039. // Note: currently, we do not enforce it strictly: we accept any format, and parse it as int
  1040. // * HTTP/2.0 does not define a way to carry the reason phrase that is included in an HTTP/1.1
  1041. // status line.
  1042. this.statusCode = parseInt(this._checkSpecialHeader(':status', headers[':status']));
  1043. // * Handling regular headers.
  1044. IncomingMessage.prototype._onHeaders.call(this, headers);
  1045. // * Signaling that the headers arrived.
  1046. this._log.info({ status: this.statusCode, headers: this.headers}, 'Incoming response');
  1047. this.emit('ready');
  1048. };
  1049. // IncomingPromise class
  1050. // -------------------------
  1051. function IncomingPromise(responseStream, promiseHeaders) {
  1052. var stream = new Readable();
  1053. stream._read = noop;
  1054. stream.push(null);
  1055. stream._log = responseStream._log;
  1056. IncomingRequest.call(this, stream);
  1057. this._onHeaders(promiseHeaders);
  1058. this._responseStream = responseStream;
  1059. var response = new IncomingResponse(this._responseStream);
  1060. response.once('ready', this.emit.bind(this, 'response', response));
  1061. this.stream.on('promise', this._onPromise.bind(this));
  1062. }
  1063. IncomingPromise.prototype = Object.create(IncomingRequest.prototype, { constructor: { value: IncomingPromise } });
  1064. IncomingPromise.prototype.cancel = function cancel() {
  1065. this._responseStream.reset('CANCEL');
  1066. };
  1067. IncomingPromise.prototype.setPriority = function setPriority(priority) {
  1068. this._responseStream.priority(priority);
  1069. };
  1070. IncomingPromise.prototype._onPromise = OutgoingRequest.prototype._onPromise;