• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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'use strict';
23
24const {
25  ArrayIsArray,
26  Boolean,
27  Error,
28  FunctionPrototypeCall,
29  NumberIsFinite,
30  ObjectAssign,
31  ObjectKeys,
32  ObjectSetPrototypeOf,
33  ReflectApply,
34  RegExpPrototypeExec,
35  String,
36  StringPrototypeCharCodeAt,
37  StringPrototypeIncludes,
38  StringPrototypeIndexOf,
39  StringPrototypeToUpperCase,
40  Symbol,
41  TypedArrayPrototypeSlice,
42} = primordials;
43
44const net = require('net');
45const assert = require('internal/assert');
46const {
47  kEmptyObject,
48  once,
49} = require('internal/util');
50const {
51  _checkIsHttpToken: checkIsHttpToken,
52  freeParser,
53  parsers,
54  HTTPParser,
55  isLenient,
56  prepareError,
57} = require('_http_common');
58const {
59  kUniqueHeaders,
60  parseUniqueHeadersOption,
61  OutgoingMessage,
62} = require('_http_outgoing');
63const Agent = require('_http_agent');
64const { Buffer } = require('buffer');
65const { defaultTriggerAsyncIdScope } = require('internal/async_hooks');
66const { URL, urlToHttpOptions, isURL } = require('internal/url');
67const {
68  kOutHeaders,
69  kNeedDrain,
70  isTraceHTTPEnabled,
71  traceBegin,
72  traceEnd,
73  getNextTraceEventId,
74} = require('internal/http');
75const { connResetException, codes } = require('internal/errors');
76const {
77  ERR_HTTP_HEADERS_SENT,
78  ERR_INVALID_ARG_TYPE,
79  ERR_INVALID_HTTP_TOKEN,
80  ERR_INVALID_PROTOCOL,
81  ERR_UNESCAPED_CHARACTERS,
82} = codes;
83const {
84  validateInteger,
85  validateBoolean,
86} = require('internal/validators');
87const { getTimerDuration } = require('internal/timers');
88const {
89  DTRACE_HTTP_CLIENT_REQUEST,
90  DTRACE_HTTP_CLIENT_RESPONSE,
91} = require('internal/dtrace');
92
93const {
94  hasObserver,
95  startPerf,
96  stopPerf,
97} = require('internal/perf/observe');
98
99const kClientRequestStatistics = Symbol('ClientRequestStatistics');
100
101const dc = require('diagnostics_channel');
102const onClientRequestStartChannel = dc.channel('http.client.request.start');
103const onClientResponseFinishChannel = dc.channel('http.client.response.finish');
104
105const { addAbortSignal, finished } = require('stream');
106
107let debug = require('internal/util/debuglog').debuglog('http', (fn) => {
108  debug = fn;
109});
110
111const INVALID_PATH_REGEX = /[^\u0021-\u00ff]/;
112const kError = Symbol('kError');
113
114const kLenientAll = HTTPParser.kLenientAll | 0;
115const kLenientNone = HTTPParser.kLenientNone | 0;
116
117const HTTP_CLIENT_TRACE_EVENT_NAME = 'http.client.request';
118
119function validateHost(host, name) {
120  if (host !== null && host !== undefined && typeof host !== 'string') {
121    throw new ERR_INVALID_ARG_TYPE(`options.${name}`,
122                                   ['string', 'undefined', 'null'],
123                                   host);
124  }
125  return host;
126}
127
128class HTTPClientAsyncResource {
129  constructor(type, req) {
130    this.type = type;
131    this.req = req;
132  }
133}
134
135function ClientRequest(input, options, cb) {
136  FunctionPrototypeCall(OutgoingMessage, this);
137
138  if (typeof input === 'string') {
139    const urlStr = input;
140    input = urlToHttpOptions(new URL(urlStr));
141  } else if (isURL(input)) {
142    // url.URL instance
143    input = urlToHttpOptions(input);
144  } else {
145    cb = options;
146    options = input;
147    input = null;
148  }
149
150  if (typeof options === 'function') {
151    cb = options;
152    options = input || kEmptyObject;
153  } else {
154    options = ObjectAssign(input || {}, options);
155  }
156
157  let agent = options.agent;
158  const defaultAgent = options._defaultAgent || Agent.globalAgent;
159  if (agent === false) {
160    agent = new defaultAgent.constructor();
161  } else if (agent === null || agent === undefined) {
162    if (typeof options.createConnection !== 'function') {
163      agent = defaultAgent;
164    }
165    // Explicitly pass through this statement as agent will not be used
166    // when createConnection is provided.
167  } else if (typeof agent.addRequest !== 'function') {
168    throw new ERR_INVALID_ARG_TYPE('options.agent',
169                                   ['Agent-like Object', 'undefined', 'false'],
170                                   agent);
171  }
172  this.agent = agent;
173
174  const protocol = options.protocol || defaultAgent.protocol;
175  let expectedProtocol = defaultAgent.protocol;
176  if (this.agent && this.agent.protocol)
177    expectedProtocol = this.agent.protocol;
178
179  if (options.path) {
180    const path = String(options.path);
181    if (RegExpPrototypeExec(INVALID_PATH_REGEX, path) !== null) {
182      debug('Path contains unescaped characters: "%s"', path);
183      throw new ERR_UNESCAPED_CHARACTERS('Request path');
184    }
185  }
186
187  if (protocol !== expectedProtocol) {
188    throw new ERR_INVALID_PROTOCOL(protocol, expectedProtocol);
189  }
190
191  const defaultPort = options.defaultPort ||
192                    (this.agent && this.agent.defaultPort);
193
194  const port = options.port = options.port || defaultPort || 80;
195  const host = options.host = validateHost(options.hostname, 'hostname') ||
196                            validateHost(options.host, 'host') || 'localhost';
197
198  const setHost = (options.setHost === undefined || Boolean(options.setHost));
199
200  this.socketPath = options.socketPath;
201
202  if (options.timeout !== undefined)
203    this.timeout = getTimerDuration(options.timeout, 'timeout');
204
205  const signal = options.signal;
206  if (signal) {
207    addAbortSignal(signal, this);
208  }
209  let method = options.method;
210  const methodIsString = (typeof method === 'string');
211  if (method !== null && method !== undefined && !methodIsString) {
212    throw new ERR_INVALID_ARG_TYPE('options.method', 'string', method);
213  }
214
215  if (methodIsString && method) {
216    if (!checkIsHttpToken(method)) {
217      throw new ERR_INVALID_HTTP_TOKEN('Method', method);
218    }
219    method = this.method = StringPrototypeToUpperCase(method);
220  } else {
221    method = this.method = 'GET';
222  }
223
224  const maxHeaderSize = options.maxHeaderSize;
225  if (maxHeaderSize !== undefined)
226    validateInteger(maxHeaderSize, 'maxHeaderSize', 0);
227  this.maxHeaderSize = maxHeaderSize;
228
229  const insecureHTTPParser = options.insecureHTTPParser;
230  if (insecureHTTPParser !== undefined) {
231    validateBoolean(insecureHTTPParser, 'options.insecureHTTPParser');
232  }
233
234  this.insecureHTTPParser = insecureHTTPParser;
235
236  if (options.joinDuplicateHeaders !== undefined) {
237    validateBoolean(options.joinDuplicateHeaders, 'options.joinDuplicateHeaders');
238  }
239
240  this.joinDuplicateHeaders = options.joinDuplicateHeaders;
241
242  this.path = options.path || '/';
243  if (cb) {
244    this.once('response', cb);
245  }
246
247  if (method === 'GET' ||
248      method === 'HEAD' ||
249      method === 'DELETE' ||
250      method === 'OPTIONS' ||
251      method === 'TRACE' ||
252      method === 'CONNECT') {
253    this.useChunkedEncodingByDefault = false;
254  } else {
255    this.useChunkedEncodingByDefault = true;
256  }
257
258  this._ended = false;
259  this.res = null;
260  this.aborted = false;
261  this.timeoutCb = null;
262  this.upgradeOrConnect = false;
263  this.parser = null;
264  this.maxHeadersCount = null;
265  this.reusedSocket = false;
266  this.host = host;
267  this.protocol = protocol;
268
269  if (this.agent) {
270    // If there is an agent we should default to Connection:keep-alive,
271    // but only if the Agent will actually reuse the connection!
272    // If it's not a keepAlive agent, and the maxSockets==Infinity, then
273    // there's never a case where this socket will actually be reused
274    if (!this.agent.keepAlive && !NumberIsFinite(this.agent.maxSockets)) {
275      this._last = true;
276      this.shouldKeepAlive = false;
277    } else {
278      this._last = false;
279      this.shouldKeepAlive = true;
280    }
281  }
282
283  const headersArray = ArrayIsArray(options.headers);
284  if (!headersArray) {
285    if (options.headers) {
286      const keys = ObjectKeys(options.headers);
287      // Retain for(;;) loop for performance reasons
288      // Refs: https://github.com/nodejs/node/pull/30958
289      for (let i = 0; i < keys.length; i++) {
290        const key = keys[i];
291        this.setHeader(key, options.headers[key]);
292      }
293    }
294
295    if (host && !this.getHeader('host') && setHost) {
296      let hostHeader = host;
297
298      // For the Host header, ensure that IPv6 addresses are enclosed
299      // in square brackets, as defined by URI formatting
300      // https://tools.ietf.org/html/rfc3986#section-3.2.2
301      const posColon = StringPrototypeIndexOf(hostHeader, ':');
302      if (posColon !== -1 &&
303          StringPrototypeIncludes(hostHeader, ':', posColon + 1) &&
304          StringPrototypeCharCodeAt(hostHeader, 0) !== 91/* '[' */) {
305        hostHeader = `[${hostHeader}]`;
306      }
307
308      if (port && +port !== defaultPort) {
309        hostHeader += ':' + port;
310      }
311      this.setHeader('Host', hostHeader);
312    }
313
314    if (options.auth && !this.getHeader('Authorization')) {
315      this.setHeader('Authorization', 'Basic ' +
316                     Buffer.from(options.auth).toString('base64'));
317    }
318
319    if (this.getHeader('expect')) {
320      if (this._header) {
321        throw new ERR_HTTP_HEADERS_SENT('render');
322      }
323
324      this._storeHeader(this.method + ' ' + this.path + ' HTTP/1.1\r\n',
325                        this[kOutHeaders]);
326    }
327  } else {
328    this._storeHeader(this.method + ' ' + this.path + ' HTTP/1.1\r\n',
329                      options.headers);
330  }
331
332  this[kUniqueHeaders] = parseUniqueHeadersOption(options.uniqueHeaders);
333
334  let optsWithoutSignal = options;
335  if (optsWithoutSignal.signal) {
336    optsWithoutSignal = ObjectAssign({}, options);
337    delete optsWithoutSignal.signal;
338  }
339
340  // initiate connection
341  if (this.agent) {
342    this.agent.addRequest(this, optsWithoutSignal);
343  } else {
344    // No agent, default to Connection:close.
345    this._last = true;
346    this.shouldKeepAlive = false;
347    if (typeof optsWithoutSignal.createConnection === 'function') {
348      const oncreate = once((err, socket) => {
349        if (err) {
350          process.nextTick(() => this.emit('error', err));
351        } else {
352          this.onSocket(socket);
353        }
354      });
355
356      try {
357        const newSocket = optsWithoutSignal.createConnection(optsWithoutSignal,
358                                                             oncreate);
359        if (newSocket) {
360          oncreate(null, newSocket);
361        }
362      } catch (err) {
363        oncreate(err);
364      }
365    } else {
366      debug('CLIENT use net.createConnection', optsWithoutSignal);
367      this.onSocket(net.createConnection(optsWithoutSignal));
368    }
369  }
370}
371ObjectSetPrototypeOf(ClientRequest.prototype, OutgoingMessage.prototype);
372ObjectSetPrototypeOf(ClientRequest, OutgoingMessage);
373
374ClientRequest.prototype._finish = function _finish() {
375  DTRACE_HTTP_CLIENT_REQUEST(this, this.socket);
376  FunctionPrototypeCall(OutgoingMessage.prototype._finish, this);
377  if (hasObserver('http')) {
378    startPerf(this, kClientRequestStatistics, {
379      type: 'http',
380      name: 'HttpClient',
381      detail: {
382        req: {
383          method: this.method,
384          url: `${this.protocol}//${this.host}${this.path}`,
385          headers: typeof this.getHeaders === 'function' ? this.getHeaders() : {},
386        },
387      },
388    });
389  }
390  if (onClientRequestStartChannel.hasSubscribers) {
391    onClientRequestStartChannel.publish({
392      request: this,
393    });
394  }
395  if (isTraceHTTPEnabled()) {
396    this._traceEventId = getNextTraceEventId();
397    traceBegin(HTTP_CLIENT_TRACE_EVENT_NAME, this._traceEventId);
398  }
399};
400
401ClientRequest.prototype._implicitHeader = function _implicitHeader() {
402  if (this._header) {
403    throw new ERR_HTTP_HEADERS_SENT('render');
404  }
405  this._storeHeader(this.method + ' ' + this.path + ' HTTP/1.1\r\n',
406                    this[kOutHeaders]);
407};
408
409ClientRequest.prototype.abort = function abort() {
410  if (this.aborted) {
411    return;
412  }
413  this.aborted = true;
414  process.nextTick(emitAbortNT, this);
415  this.destroy();
416};
417
418ClientRequest.prototype.destroy = function destroy(err) {
419  if (this.destroyed) {
420    return this;
421  }
422  this.destroyed = true;
423
424  // If we're aborting, we don't care about any more response data.
425  if (this.res) {
426    this.res._dump();
427  }
428
429  this[kError] = err;
430  this.socket?.destroy(err);
431
432  return this;
433};
434
435function emitAbortNT(req) {
436  req.emit('abort');
437}
438
439function ondrain() {
440  const msg = this._httpMessage;
441  if (msg && !msg.finished && msg[kNeedDrain]) {
442    msg[kNeedDrain] = false;
443    msg.emit('drain');
444  }
445}
446
447function socketCloseListener() {
448  const socket = this;
449  const req = socket._httpMessage;
450  debug('HTTP socket close');
451
452  // NOTE: It's important to get parser here, because it could be freed by
453  // the `socketOnData`.
454  const parser = socket.parser;
455  const res = req.res;
456
457  req.destroyed = true;
458  if (res) {
459    // Socket closed before we emitted 'end' below.
460    if (!res.complete) {
461      res.destroy(connResetException('aborted'));
462    }
463    req._closed = true;
464    req.emit('close');
465    if (!res.aborted && res.readable) {
466      res.push(null);
467    }
468  } else {
469    if (!req.socket._hadError) {
470      // This socket error fired before we started to
471      // receive a response. The error needs to
472      // fire on the request.
473      req.socket._hadError = true;
474      req.emit('error', connResetException('socket hang up'));
475    }
476    req._closed = true;
477    req.emit('close');
478  }
479
480  // Too bad.  That output wasn't getting written.
481  // This is pretty terrible that it doesn't raise an error.
482  // Fixed better in v0.10
483  if (req.outputData)
484    req.outputData.length = 0;
485
486  if (parser) {
487    parser.finish();
488    freeParser(parser, req, socket);
489  }
490}
491
492function socketErrorListener(err) {
493  const socket = this;
494  const req = socket._httpMessage;
495  debug('SOCKET ERROR:', err.message, err.stack);
496
497  if (req) {
498    // For Safety. Some additional errors might fire later on
499    // and we need to make sure we don't double-fire the error event.
500    req.socket._hadError = true;
501    req.emit('error', err);
502  }
503
504  const parser = socket.parser;
505  if (parser) {
506    parser.finish();
507    freeParser(parser, req, socket);
508  }
509
510  // Ensure that no further data will come out of the socket
511  socket.removeListener('data', socketOnData);
512  socket.removeListener('end', socketOnEnd);
513  socket.destroy();
514}
515
516function socketOnEnd() {
517  const socket = this;
518  const req = this._httpMessage;
519  const parser = this.parser;
520
521  if (!req.res && !req.socket._hadError) {
522    // If we don't have a response then we know that the socket
523    // ended prematurely and we need to emit an error on the request.
524    req.socket._hadError = true;
525    req.emit('error', connResetException('socket hang up'));
526  }
527  if (parser) {
528    parser.finish();
529    freeParser(parser, req, socket);
530  }
531  socket.destroy();
532}
533
534function socketOnData(d) {
535  const socket = this;
536  const req = this._httpMessage;
537  const parser = this.parser;
538
539  assert(parser && parser.socket === socket);
540
541  const ret = parser.execute(d);
542  if (ret instanceof Error) {
543    prepareError(ret, parser, d);
544    debug('parse error', ret);
545    freeParser(parser, req, socket);
546    socket.removeListener('data', socketOnData);
547    socket.removeListener('end', socketOnEnd);
548    socket.destroy();
549    req.socket._hadError = true;
550    req.emit('error', ret);
551  } else if (parser.incoming && parser.incoming.upgrade) {
552    // Upgrade (if status code 101) or CONNECT
553    const bytesParsed = ret;
554    const res = parser.incoming;
555    req.res = res;
556
557    socket.removeListener('data', socketOnData);
558    socket.removeListener('end', socketOnEnd);
559    socket.removeListener('drain', ondrain);
560
561    if (req.timeoutCb) socket.removeListener('timeout', req.timeoutCb);
562    socket.removeListener('timeout', responseOnTimeout);
563
564    parser.finish();
565    freeParser(parser, req, socket);
566
567    const bodyHead = TypedArrayPrototypeSlice(d, bytesParsed, d.length);
568
569    const eventName = req.method === 'CONNECT' ? 'connect' : 'upgrade';
570    if (req.listenerCount(eventName) > 0) {
571      req.upgradeOrConnect = true;
572
573      // detach the socket
574      socket.emit('agentRemove');
575      socket.removeListener('close', socketCloseListener);
576      socket.removeListener('error', socketErrorListener);
577
578      socket._httpMessage = null;
579      socket.readableFlowing = null;
580
581      req.emit(eventName, res, socket, bodyHead);
582      req.destroyed = true;
583      req._closed = true;
584      req.emit('close');
585    } else {
586      // Requested Upgrade or used CONNECT method, but have no handler.
587      socket.destroy();
588    }
589  } else if (parser.incoming && parser.incoming.complete &&
590             // When the status code is informational (100, 102-199),
591             // the server will send a final response after this client
592             // sends a request body, so we must not free the parser.
593             // 101 (Switching Protocols) and all other status codes
594             // should be processed normally.
595             !statusIsInformational(parser.incoming.statusCode)) {
596    socket.removeListener('data', socketOnData);
597    socket.removeListener('end', socketOnEnd);
598    socket.removeListener('drain', ondrain);
599    freeParser(parser, req, socket);
600  }
601}
602
603function statusIsInformational(status) {
604  // 100 (Continue)    RFC7231 Section 6.2.1
605  // 102 (Processing)  RFC2518
606  // 103 (Early Hints) RFC8297
607  // 104-199 (Unassigned)
608  return (status < 200 && status >= 100 && status !== 101);
609}
610
611// client
612function parserOnIncomingClient(res, shouldKeepAlive) {
613  const socket = this.socket;
614  const req = socket._httpMessage;
615
616  debug('AGENT incoming response!');
617
618  if (req.res) {
619    // We already have a response object, this means the server
620    // sent a double response.
621    socket.destroy();
622    return 0;  // No special treatment.
623  }
624  req.res = res;
625
626  // Skip body and treat as Upgrade.
627  if (res.upgrade)
628    return 2;
629
630  // Responses to CONNECT request is handled as Upgrade.
631  const method = req.method;
632  if (method === 'CONNECT') {
633    res.upgrade = true;
634    return 2;  // Skip body and treat as Upgrade.
635  }
636
637  if (statusIsInformational(res.statusCode)) {
638    // Restart the parser, as this is a 1xx informational message.
639    req.res = null; // Clear res so that we don't hit double-responses.
640    // Maintain compatibility by sending 100-specific events
641    if (res.statusCode === 100) {
642      req.emit('continue');
643    }
644    // Send information events to all 1xx responses except 101 Upgrade.
645    req.emit('information', {
646      statusCode: res.statusCode,
647      statusMessage: res.statusMessage,
648      httpVersion: res.httpVersion,
649      httpVersionMajor: res.httpVersionMajor,
650      httpVersionMinor: res.httpVersionMinor,
651      headers: res.headers,
652      rawHeaders: res.rawHeaders,
653    });
654
655    return 1;  // Skip body but don't treat as Upgrade.
656  }
657
658  if (req.shouldKeepAlive && !shouldKeepAlive && !req.upgradeOrConnect) {
659    // Server MUST respond with Connection:keep-alive for us to enable it.
660    // If we've been upgraded (via WebSockets) we also shouldn't try to
661    // keep the connection open.
662    req.shouldKeepAlive = false;
663  }
664
665  DTRACE_HTTP_CLIENT_RESPONSE(socket, req);
666  if (req[kClientRequestStatistics] && hasObserver('http')) {
667    stopPerf(req, kClientRequestStatistics, {
668      detail: {
669        res: {
670          statusCode: res.statusCode,
671          statusMessage: res.statusMessage,
672          headers: res.headers,
673        },
674      },
675    });
676  }
677  if (onClientResponseFinishChannel.hasSubscribers) {
678    onClientResponseFinishChannel.publish({
679      request: req,
680      response: res,
681    });
682  }
683  if (isTraceHTTPEnabled() && typeof req._traceEventId === 'number') {
684    traceEnd(HTTP_CLIENT_TRACE_EVENT_NAME, req._traceEventId, {
685      path: req.path,
686      statusCode: res.statusCode,
687    });
688  }
689  req.res = res;
690  res.req = req;
691
692  // Add our listener first, so that we guarantee socket cleanup
693  res.on('end', responseOnEnd);
694  req.on('finish', requestOnFinish);
695  socket.on('timeout', responseOnTimeout);
696
697  // If the user did not listen for the 'response' event, then they
698  // can't possibly read the data, so we ._dump() it into the void
699  // so that the socket doesn't hang there in a paused state.
700  if (req.aborted || !req.emit('response', res))
701    res._dump();
702
703  if (method === 'HEAD')
704    return 1;  // Skip body but don't treat as Upgrade.
705
706  if (res.statusCode === 304) {
707    res.complete = true;
708    return 1; // Skip body as there won't be any
709  }
710
711  return 0;  // No special treatment.
712}
713
714// client
715function responseKeepAlive(req) {
716  const socket = req.socket;
717
718  debug('AGENT socket keep-alive');
719  if (req.timeoutCb) {
720    socket.setTimeout(0, req.timeoutCb);
721    req.timeoutCb = null;
722  }
723  socket.removeListener('close', socketCloseListener);
724  socket.removeListener('error', socketErrorListener);
725  socket.removeListener('data', socketOnData);
726  socket.removeListener('end', socketOnEnd);
727
728  // TODO(ronag): Between here and emitFreeNT the socket
729  // has no 'error' handler.
730
731  // There are cases where _handle === null. Avoid those. Passing undefined to
732  // nextTick() will call getDefaultTriggerAsyncId() to retrieve the id.
733  const asyncId = socket._handle ? socket._handle.getAsyncId() : undefined;
734  // Mark this socket as available, AFTER user-added end
735  // handlers have a chance to run.
736  defaultTriggerAsyncIdScope(asyncId, process.nextTick, emitFreeNT, req);
737
738  req.destroyed = true;
739  if (req.res) {
740    // Detach socket from IncomingMessage to avoid destroying the freed
741    // socket in IncomingMessage.destroy().
742    req.res.socket = null;
743  }
744}
745
746function responseOnEnd() {
747  const req = this.req;
748  const socket = req.socket;
749
750  if (socket) {
751    if (req.timeoutCb) socket.removeListener('timeout', emitRequestTimeout);
752    socket.removeListener('timeout', responseOnTimeout);
753  }
754
755  req._ended = true;
756
757  if (!req.shouldKeepAlive) {
758    if (socket.writable) {
759      debug('AGENT socket.destroySoon()');
760      if (typeof socket.destroySoon === 'function')
761        socket.destroySoon();
762      else
763        socket.end();
764    }
765    assert(!socket.writable);
766  } else if (req.writableFinished && !this.aborted) {
767    assert(req.finished);
768    // We can assume `req.finished` means all data has been written since:
769    // - `'responseOnEnd'` means we have been assigned a socket.
770    // - when we have a socket we write directly to it without buffering.
771    // - `req.finished` means `end()` has been called and no further data.
772    //   can be written
773    // In addition, `req.writableFinished` means all data written has been
774    // accepted by the kernel. (i.e. the `req.socket` is drained).Without
775    // this constraint, we may assign a non drained socket to a request.
776    responseKeepAlive(req);
777  }
778}
779
780function responseOnTimeout() {
781  const req = this._httpMessage;
782  if (!req) return;
783  const res = req.res;
784  if (!res) return;
785  res.emit('timeout');
786}
787
788// This function is necessary in the case where we receive the entire response
789// from the server before we finish sending out the request.
790function requestOnFinish() {
791  const req = this;
792
793  if (req.shouldKeepAlive && req._ended)
794    responseKeepAlive(req);
795}
796
797function emitFreeNT(req) {
798  req._closed = true;
799  req.emit('close');
800  if (req.socket) {
801    req.socket.emit('free');
802  }
803}
804
805function tickOnSocket(req, socket) {
806  const parser = parsers.alloc();
807  req.socket = socket;
808  const lenient = req.insecureHTTPParser === undefined ?
809    isLenient() : req.insecureHTTPParser;
810  parser.initialize(HTTPParser.RESPONSE,
811                    new HTTPClientAsyncResource('HTTPINCOMINGMESSAGE', req),
812                    req.maxHeaderSize || 0,
813                    lenient ? kLenientAll : kLenientNone);
814  parser.socket = socket;
815  parser.outgoing = req;
816  req.parser = parser;
817
818  socket.parser = parser;
819  socket._httpMessage = req;
820
821  // Propagate headers limit from request object to parser
822  if (typeof req.maxHeadersCount === 'number') {
823    parser.maxHeaderPairs = req.maxHeadersCount << 1;
824  }
825
826  parser.joinDuplicateHeaders = req.joinDuplicateHeaders;
827
828  parser.onIncoming = parserOnIncomingClient;
829  socket.on('error', socketErrorListener);
830  socket.on('data', socketOnData);
831  socket.on('end', socketOnEnd);
832  socket.on('close', socketCloseListener);
833  socket.on('drain', ondrain);
834
835  if (
836    req.timeout !== undefined ||
837    (req.agent && req.agent.options && req.agent.options.timeout)
838  ) {
839    listenSocketTimeout(req);
840  }
841  req.emit('socket', socket);
842}
843
844function emitRequestTimeout() {
845  const req = this._httpMessage;
846  if (req) {
847    req.emit('timeout');
848  }
849}
850
851function listenSocketTimeout(req) {
852  if (req.timeoutCb) {
853    return;
854  }
855  // Set timeoutCb so it will get cleaned up on request end.
856  req.timeoutCb = emitRequestTimeout;
857  // Delegate socket timeout event.
858  if (req.socket) {
859    req.socket.once('timeout', emitRequestTimeout);
860  } else {
861    req.on('socket', (socket) => {
862      socket.once('timeout', emitRequestTimeout);
863    });
864  }
865}
866
867ClientRequest.prototype.onSocket = function onSocket(socket, err) {
868  // TODO(ronag): Between here and onSocketNT the socket
869  // has no 'error' handler.
870  process.nextTick(onSocketNT, this, socket, err);
871};
872
873function onSocketNT(req, socket, err) {
874  if (req.destroyed || err) {
875    req.destroyed = true;
876
877    function _destroy(req, err) {
878      if (!req.aborted && !err) {
879        err = connResetException('socket hang up');
880      }
881      if (err) {
882        req.emit('error', err);
883      }
884      req._closed = true;
885      req.emit('close');
886    }
887
888    if (socket) {
889      if (!err && req.agent && !socket.destroyed) {
890        socket.emit('free');
891      } else {
892        finished(socket.destroy(err || req[kError]), (er) => {
893          if (er?.code === 'ERR_STREAM_PREMATURE_CLOSE') {
894            er = null;
895          }
896          _destroy(req, er || err);
897        });
898        return;
899      }
900    }
901
902    _destroy(req, err || req[kError]);
903  } else {
904    tickOnSocket(req, socket);
905    req._flush();
906  }
907}
908
909ClientRequest.prototype._deferToConnect = _deferToConnect;
910function _deferToConnect(method, arguments_) {
911  // This function is for calls that need to happen once the socket is
912  // assigned to this request and writable. It's an important promisy
913  // thing for all the socket calls that happen either now
914  // (when a socket is assigned) or in the future (when a socket gets
915  // assigned out of the pool and is eventually writable).
916
917  const callSocketMethod = () => {
918    if (method)
919      ReflectApply(this.socket[method], this.socket, arguments_);
920  };
921
922  const onSocket = () => {
923    if (this.socket.writable) {
924      callSocketMethod();
925    } else {
926      this.socket.once('connect', callSocketMethod);
927    }
928  };
929
930  if (!this.socket) {
931    this.once('socket', onSocket);
932  } else {
933    onSocket();
934  }
935}
936
937ClientRequest.prototype.setTimeout = function setTimeout(msecs, callback) {
938  if (this._ended) {
939    return this;
940  }
941
942  listenSocketTimeout(this);
943  msecs = getTimerDuration(msecs, 'msecs');
944  if (callback) this.once('timeout', callback);
945
946  if (this.socket) {
947    setSocketTimeout(this.socket, msecs);
948  } else {
949    this.once('socket', (sock) => setSocketTimeout(sock, msecs));
950  }
951
952  return this;
953};
954
955function setSocketTimeout(sock, msecs) {
956  if (sock.connecting) {
957    sock.once('connect', function() {
958      sock.setTimeout(msecs);
959    });
960  } else {
961    sock.setTimeout(msecs);
962  }
963}
964
965ClientRequest.prototype.setNoDelay = function setNoDelay(noDelay) {
966  this._deferToConnect('setNoDelay', [noDelay]);
967};
968
969ClientRequest.prototype.setSocketKeepAlive =
970    function setSocketKeepAlive(enable, initialDelay) {
971      this._deferToConnect('setKeepAlive', [enable, initialDelay]);
972    };
973
974ClientRequest.prototype.clearTimeout = function clearTimeout(cb) {
975  this.setTimeout(0, cb);
976};
977
978module.exports = {
979  ClientRequest,
980};
981