11cb0ef41Sopenharmony_ci// Copyright Joyent, Inc. and other Node contributors. 21cb0ef41Sopenharmony_ci// 31cb0ef41Sopenharmony_ci// Permission is hereby granted, free of charge, to any person obtaining a 41cb0ef41Sopenharmony_ci// copy of this software and associated documentation files (the 51cb0ef41Sopenharmony_ci// "Software"), to deal in the Software without restriction, including 61cb0ef41Sopenharmony_ci// without limitation the rights to use, copy, modify, merge, publish, 71cb0ef41Sopenharmony_ci// distribute, sublicense, and/or sell copies of the Software, and to permit 81cb0ef41Sopenharmony_ci// persons to whom the Software is furnished to do so, subject to the 91cb0ef41Sopenharmony_ci// following conditions: 101cb0ef41Sopenharmony_ci// 111cb0ef41Sopenharmony_ci// The above copyright notice and this permission notice shall be included 121cb0ef41Sopenharmony_ci// in all copies or substantial portions of the Software. 131cb0ef41Sopenharmony_ci// 141cb0ef41Sopenharmony_ci// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 151cb0ef41Sopenharmony_ci// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 161cb0ef41Sopenharmony_ci// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 171cb0ef41Sopenharmony_ci// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 181cb0ef41Sopenharmony_ci// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 191cb0ef41Sopenharmony_ci// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 201cb0ef41Sopenharmony_ci// USE OR OTHER DEALINGS IN THE SOFTWARE. 211cb0ef41Sopenharmony_ci 221cb0ef41Sopenharmony_ci'use strict'; 231cb0ef41Sopenharmony_ci 241cb0ef41Sopenharmony_ciconst { 251cb0ef41Sopenharmony_ci ArrayIsArray, 261cb0ef41Sopenharmony_ci Boolean, 271cb0ef41Sopenharmony_ci Error, 281cb0ef41Sopenharmony_ci FunctionPrototypeCall, 291cb0ef41Sopenharmony_ci NumberIsFinite, 301cb0ef41Sopenharmony_ci ObjectAssign, 311cb0ef41Sopenharmony_ci ObjectKeys, 321cb0ef41Sopenharmony_ci ObjectSetPrototypeOf, 331cb0ef41Sopenharmony_ci ReflectApply, 341cb0ef41Sopenharmony_ci RegExpPrototypeExec, 351cb0ef41Sopenharmony_ci String, 361cb0ef41Sopenharmony_ci StringPrototypeCharCodeAt, 371cb0ef41Sopenharmony_ci StringPrototypeIncludes, 381cb0ef41Sopenharmony_ci StringPrototypeIndexOf, 391cb0ef41Sopenharmony_ci StringPrototypeToUpperCase, 401cb0ef41Sopenharmony_ci Symbol, 411cb0ef41Sopenharmony_ci TypedArrayPrototypeSlice, 421cb0ef41Sopenharmony_ci} = primordials; 431cb0ef41Sopenharmony_ci 441cb0ef41Sopenharmony_ciconst net = require('net'); 451cb0ef41Sopenharmony_ciconst assert = require('internal/assert'); 461cb0ef41Sopenharmony_ciconst { 471cb0ef41Sopenharmony_ci kEmptyObject, 481cb0ef41Sopenharmony_ci once, 491cb0ef41Sopenharmony_ci} = require('internal/util'); 501cb0ef41Sopenharmony_ciconst { 511cb0ef41Sopenharmony_ci _checkIsHttpToken: checkIsHttpToken, 521cb0ef41Sopenharmony_ci freeParser, 531cb0ef41Sopenharmony_ci parsers, 541cb0ef41Sopenharmony_ci HTTPParser, 551cb0ef41Sopenharmony_ci isLenient, 561cb0ef41Sopenharmony_ci prepareError, 571cb0ef41Sopenharmony_ci} = require('_http_common'); 581cb0ef41Sopenharmony_ciconst { 591cb0ef41Sopenharmony_ci kUniqueHeaders, 601cb0ef41Sopenharmony_ci parseUniqueHeadersOption, 611cb0ef41Sopenharmony_ci OutgoingMessage, 621cb0ef41Sopenharmony_ci} = require('_http_outgoing'); 631cb0ef41Sopenharmony_ciconst Agent = require('_http_agent'); 641cb0ef41Sopenharmony_ciconst { Buffer } = require('buffer'); 651cb0ef41Sopenharmony_ciconst { defaultTriggerAsyncIdScope } = require('internal/async_hooks'); 661cb0ef41Sopenharmony_ciconst { URL, urlToHttpOptions, isURL } = require('internal/url'); 671cb0ef41Sopenharmony_ciconst { 681cb0ef41Sopenharmony_ci kOutHeaders, 691cb0ef41Sopenharmony_ci kNeedDrain, 701cb0ef41Sopenharmony_ci isTraceHTTPEnabled, 711cb0ef41Sopenharmony_ci traceBegin, 721cb0ef41Sopenharmony_ci traceEnd, 731cb0ef41Sopenharmony_ci getNextTraceEventId, 741cb0ef41Sopenharmony_ci} = require('internal/http'); 751cb0ef41Sopenharmony_ciconst { connResetException, codes } = require('internal/errors'); 761cb0ef41Sopenharmony_ciconst { 771cb0ef41Sopenharmony_ci ERR_HTTP_HEADERS_SENT, 781cb0ef41Sopenharmony_ci ERR_INVALID_ARG_TYPE, 791cb0ef41Sopenharmony_ci ERR_INVALID_HTTP_TOKEN, 801cb0ef41Sopenharmony_ci ERR_INVALID_PROTOCOL, 811cb0ef41Sopenharmony_ci ERR_UNESCAPED_CHARACTERS, 821cb0ef41Sopenharmony_ci} = codes; 831cb0ef41Sopenharmony_ciconst { 841cb0ef41Sopenharmony_ci validateInteger, 851cb0ef41Sopenharmony_ci validateBoolean, 861cb0ef41Sopenharmony_ci} = require('internal/validators'); 871cb0ef41Sopenharmony_ciconst { getTimerDuration } = require('internal/timers'); 881cb0ef41Sopenharmony_ciconst { 891cb0ef41Sopenharmony_ci DTRACE_HTTP_CLIENT_REQUEST, 901cb0ef41Sopenharmony_ci DTRACE_HTTP_CLIENT_RESPONSE, 911cb0ef41Sopenharmony_ci} = require('internal/dtrace'); 921cb0ef41Sopenharmony_ci 931cb0ef41Sopenharmony_ciconst { 941cb0ef41Sopenharmony_ci hasObserver, 951cb0ef41Sopenharmony_ci startPerf, 961cb0ef41Sopenharmony_ci stopPerf, 971cb0ef41Sopenharmony_ci} = require('internal/perf/observe'); 981cb0ef41Sopenharmony_ci 991cb0ef41Sopenharmony_ciconst kClientRequestStatistics = Symbol('ClientRequestStatistics'); 1001cb0ef41Sopenharmony_ci 1011cb0ef41Sopenharmony_ciconst dc = require('diagnostics_channel'); 1021cb0ef41Sopenharmony_ciconst onClientRequestStartChannel = dc.channel('http.client.request.start'); 1031cb0ef41Sopenharmony_ciconst onClientResponseFinishChannel = dc.channel('http.client.response.finish'); 1041cb0ef41Sopenharmony_ci 1051cb0ef41Sopenharmony_ciconst { addAbortSignal, finished } = require('stream'); 1061cb0ef41Sopenharmony_ci 1071cb0ef41Sopenharmony_cilet debug = require('internal/util/debuglog').debuglog('http', (fn) => { 1081cb0ef41Sopenharmony_ci debug = fn; 1091cb0ef41Sopenharmony_ci}); 1101cb0ef41Sopenharmony_ci 1111cb0ef41Sopenharmony_ciconst INVALID_PATH_REGEX = /[^\u0021-\u00ff]/; 1121cb0ef41Sopenharmony_ciconst kError = Symbol('kError'); 1131cb0ef41Sopenharmony_ci 1141cb0ef41Sopenharmony_ciconst kLenientAll = HTTPParser.kLenientAll | 0; 1151cb0ef41Sopenharmony_ciconst kLenientNone = HTTPParser.kLenientNone | 0; 1161cb0ef41Sopenharmony_ci 1171cb0ef41Sopenharmony_ciconst HTTP_CLIENT_TRACE_EVENT_NAME = 'http.client.request'; 1181cb0ef41Sopenharmony_ci 1191cb0ef41Sopenharmony_cifunction validateHost(host, name) { 1201cb0ef41Sopenharmony_ci if (host !== null && host !== undefined && typeof host !== 'string') { 1211cb0ef41Sopenharmony_ci throw new ERR_INVALID_ARG_TYPE(`options.${name}`, 1221cb0ef41Sopenharmony_ci ['string', 'undefined', 'null'], 1231cb0ef41Sopenharmony_ci host); 1241cb0ef41Sopenharmony_ci } 1251cb0ef41Sopenharmony_ci return host; 1261cb0ef41Sopenharmony_ci} 1271cb0ef41Sopenharmony_ci 1281cb0ef41Sopenharmony_ciclass HTTPClientAsyncResource { 1291cb0ef41Sopenharmony_ci constructor(type, req) { 1301cb0ef41Sopenharmony_ci this.type = type; 1311cb0ef41Sopenharmony_ci this.req = req; 1321cb0ef41Sopenharmony_ci } 1331cb0ef41Sopenharmony_ci} 1341cb0ef41Sopenharmony_ci 1351cb0ef41Sopenharmony_cifunction ClientRequest(input, options, cb) { 1361cb0ef41Sopenharmony_ci FunctionPrototypeCall(OutgoingMessage, this); 1371cb0ef41Sopenharmony_ci 1381cb0ef41Sopenharmony_ci if (typeof input === 'string') { 1391cb0ef41Sopenharmony_ci const urlStr = input; 1401cb0ef41Sopenharmony_ci input = urlToHttpOptions(new URL(urlStr)); 1411cb0ef41Sopenharmony_ci } else if (isURL(input)) { 1421cb0ef41Sopenharmony_ci // url.URL instance 1431cb0ef41Sopenharmony_ci input = urlToHttpOptions(input); 1441cb0ef41Sopenharmony_ci } else { 1451cb0ef41Sopenharmony_ci cb = options; 1461cb0ef41Sopenharmony_ci options = input; 1471cb0ef41Sopenharmony_ci input = null; 1481cb0ef41Sopenharmony_ci } 1491cb0ef41Sopenharmony_ci 1501cb0ef41Sopenharmony_ci if (typeof options === 'function') { 1511cb0ef41Sopenharmony_ci cb = options; 1521cb0ef41Sopenharmony_ci options = input || kEmptyObject; 1531cb0ef41Sopenharmony_ci } else { 1541cb0ef41Sopenharmony_ci options = ObjectAssign(input || {}, options); 1551cb0ef41Sopenharmony_ci } 1561cb0ef41Sopenharmony_ci 1571cb0ef41Sopenharmony_ci let agent = options.agent; 1581cb0ef41Sopenharmony_ci const defaultAgent = options._defaultAgent || Agent.globalAgent; 1591cb0ef41Sopenharmony_ci if (agent === false) { 1601cb0ef41Sopenharmony_ci agent = new defaultAgent.constructor(); 1611cb0ef41Sopenharmony_ci } else if (agent === null || agent === undefined) { 1621cb0ef41Sopenharmony_ci if (typeof options.createConnection !== 'function') { 1631cb0ef41Sopenharmony_ci agent = defaultAgent; 1641cb0ef41Sopenharmony_ci } 1651cb0ef41Sopenharmony_ci // Explicitly pass through this statement as agent will not be used 1661cb0ef41Sopenharmony_ci // when createConnection is provided. 1671cb0ef41Sopenharmony_ci } else if (typeof agent.addRequest !== 'function') { 1681cb0ef41Sopenharmony_ci throw new ERR_INVALID_ARG_TYPE('options.agent', 1691cb0ef41Sopenharmony_ci ['Agent-like Object', 'undefined', 'false'], 1701cb0ef41Sopenharmony_ci agent); 1711cb0ef41Sopenharmony_ci } 1721cb0ef41Sopenharmony_ci this.agent = agent; 1731cb0ef41Sopenharmony_ci 1741cb0ef41Sopenharmony_ci const protocol = options.protocol || defaultAgent.protocol; 1751cb0ef41Sopenharmony_ci let expectedProtocol = defaultAgent.protocol; 1761cb0ef41Sopenharmony_ci if (this.agent && this.agent.protocol) 1771cb0ef41Sopenharmony_ci expectedProtocol = this.agent.protocol; 1781cb0ef41Sopenharmony_ci 1791cb0ef41Sopenharmony_ci if (options.path) { 1801cb0ef41Sopenharmony_ci const path = String(options.path); 1811cb0ef41Sopenharmony_ci if (RegExpPrototypeExec(INVALID_PATH_REGEX, path) !== null) { 1821cb0ef41Sopenharmony_ci debug('Path contains unescaped characters: "%s"', path); 1831cb0ef41Sopenharmony_ci throw new ERR_UNESCAPED_CHARACTERS('Request path'); 1841cb0ef41Sopenharmony_ci } 1851cb0ef41Sopenharmony_ci } 1861cb0ef41Sopenharmony_ci 1871cb0ef41Sopenharmony_ci if (protocol !== expectedProtocol) { 1881cb0ef41Sopenharmony_ci throw new ERR_INVALID_PROTOCOL(protocol, expectedProtocol); 1891cb0ef41Sopenharmony_ci } 1901cb0ef41Sopenharmony_ci 1911cb0ef41Sopenharmony_ci const defaultPort = options.defaultPort || 1921cb0ef41Sopenharmony_ci (this.agent && this.agent.defaultPort); 1931cb0ef41Sopenharmony_ci 1941cb0ef41Sopenharmony_ci const port = options.port = options.port || defaultPort || 80; 1951cb0ef41Sopenharmony_ci const host = options.host = validateHost(options.hostname, 'hostname') || 1961cb0ef41Sopenharmony_ci validateHost(options.host, 'host') || 'localhost'; 1971cb0ef41Sopenharmony_ci 1981cb0ef41Sopenharmony_ci const setHost = (options.setHost === undefined || Boolean(options.setHost)); 1991cb0ef41Sopenharmony_ci 2001cb0ef41Sopenharmony_ci this.socketPath = options.socketPath; 2011cb0ef41Sopenharmony_ci 2021cb0ef41Sopenharmony_ci if (options.timeout !== undefined) 2031cb0ef41Sopenharmony_ci this.timeout = getTimerDuration(options.timeout, 'timeout'); 2041cb0ef41Sopenharmony_ci 2051cb0ef41Sopenharmony_ci const signal = options.signal; 2061cb0ef41Sopenharmony_ci if (signal) { 2071cb0ef41Sopenharmony_ci addAbortSignal(signal, this); 2081cb0ef41Sopenharmony_ci } 2091cb0ef41Sopenharmony_ci let method = options.method; 2101cb0ef41Sopenharmony_ci const methodIsString = (typeof method === 'string'); 2111cb0ef41Sopenharmony_ci if (method !== null && method !== undefined && !methodIsString) { 2121cb0ef41Sopenharmony_ci throw new ERR_INVALID_ARG_TYPE('options.method', 'string', method); 2131cb0ef41Sopenharmony_ci } 2141cb0ef41Sopenharmony_ci 2151cb0ef41Sopenharmony_ci if (methodIsString && method) { 2161cb0ef41Sopenharmony_ci if (!checkIsHttpToken(method)) { 2171cb0ef41Sopenharmony_ci throw new ERR_INVALID_HTTP_TOKEN('Method', method); 2181cb0ef41Sopenharmony_ci } 2191cb0ef41Sopenharmony_ci method = this.method = StringPrototypeToUpperCase(method); 2201cb0ef41Sopenharmony_ci } else { 2211cb0ef41Sopenharmony_ci method = this.method = 'GET'; 2221cb0ef41Sopenharmony_ci } 2231cb0ef41Sopenharmony_ci 2241cb0ef41Sopenharmony_ci const maxHeaderSize = options.maxHeaderSize; 2251cb0ef41Sopenharmony_ci if (maxHeaderSize !== undefined) 2261cb0ef41Sopenharmony_ci validateInteger(maxHeaderSize, 'maxHeaderSize', 0); 2271cb0ef41Sopenharmony_ci this.maxHeaderSize = maxHeaderSize; 2281cb0ef41Sopenharmony_ci 2291cb0ef41Sopenharmony_ci const insecureHTTPParser = options.insecureHTTPParser; 2301cb0ef41Sopenharmony_ci if (insecureHTTPParser !== undefined) { 2311cb0ef41Sopenharmony_ci validateBoolean(insecureHTTPParser, 'options.insecureHTTPParser'); 2321cb0ef41Sopenharmony_ci } 2331cb0ef41Sopenharmony_ci 2341cb0ef41Sopenharmony_ci this.insecureHTTPParser = insecureHTTPParser; 2351cb0ef41Sopenharmony_ci 2361cb0ef41Sopenharmony_ci if (options.joinDuplicateHeaders !== undefined) { 2371cb0ef41Sopenharmony_ci validateBoolean(options.joinDuplicateHeaders, 'options.joinDuplicateHeaders'); 2381cb0ef41Sopenharmony_ci } 2391cb0ef41Sopenharmony_ci 2401cb0ef41Sopenharmony_ci this.joinDuplicateHeaders = options.joinDuplicateHeaders; 2411cb0ef41Sopenharmony_ci 2421cb0ef41Sopenharmony_ci this.path = options.path || '/'; 2431cb0ef41Sopenharmony_ci if (cb) { 2441cb0ef41Sopenharmony_ci this.once('response', cb); 2451cb0ef41Sopenharmony_ci } 2461cb0ef41Sopenharmony_ci 2471cb0ef41Sopenharmony_ci if (method === 'GET' || 2481cb0ef41Sopenharmony_ci method === 'HEAD' || 2491cb0ef41Sopenharmony_ci method === 'DELETE' || 2501cb0ef41Sopenharmony_ci method === 'OPTIONS' || 2511cb0ef41Sopenharmony_ci method === 'TRACE' || 2521cb0ef41Sopenharmony_ci method === 'CONNECT') { 2531cb0ef41Sopenharmony_ci this.useChunkedEncodingByDefault = false; 2541cb0ef41Sopenharmony_ci } else { 2551cb0ef41Sopenharmony_ci this.useChunkedEncodingByDefault = true; 2561cb0ef41Sopenharmony_ci } 2571cb0ef41Sopenharmony_ci 2581cb0ef41Sopenharmony_ci this._ended = false; 2591cb0ef41Sopenharmony_ci this.res = null; 2601cb0ef41Sopenharmony_ci this.aborted = false; 2611cb0ef41Sopenharmony_ci this.timeoutCb = null; 2621cb0ef41Sopenharmony_ci this.upgradeOrConnect = false; 2631cb0ef41Sopenharmony_ci this.parser = null; 2641cb0ef41Sopenharmony_ci this.maxHeadersCount = null; 2651cb0ef41Sopenharmony_ci this.reusedSocket = false; 2661cb0ef41Sopenharmony_ci this.host = host; 2671cb0ef41Sopenharmony_ci this.protocol = protocol; 2681cb0ef41Sopenharmony_ci 2691cb0ef41Sopenharmony_ci if (this.agent) { 2701cb0ef41Sopenharmony_ci // If there is an agent we should default to Connection:keep-alive, 2711cb0ef41Sopenharmony_ci // but only if the Agent will actually reuse the connection! 2721cb0ef41Sopenharmony_ci // If it's not a keepAlive agent, and the maxSockets==Infinity, then 2731cb0ef41Sopenharmony_ci // there's never a case where this socket will actually be reused 2741cb0ef41Sopenharmony_ci if (!this.agent.keepAlive && !NumberIsFinite(this.agent.maxSockets)) { 2751cb0ef41Sopenharmony_ci this._last = true; 2761cb0ef41Sopenharmony_ci this.shouldKeepAlive = false; 2771cb0ef41Sopenharmony_ci } else { 2781cb0ef41Sopenharmony_ci this._last = false; 2791cb0ef41Sopenharmony_ci this.shouldKeepAlive = true; 2801cb0ef41Sopenharmony_ci } 2811cb0ef41Sopenharmony_ci } 2821cb0ef41Sopenharmony_ci 2831cb0ef41Sopenharmony_ci const headersArray = ArrayIsArray(options.headers); 2841cb0ef41Sopenharmony_ci if (!headersArray) { 2851cb0ef41Sopenharmony_ci if (options.headers) { 2861cb0ef41Sopenharmony_ci const keys = ObjectKeys(options.headers); 2871cb0ef41Sopenharmony_ci // Retain for(;;) loop for performance reasons 2881cb0ef41Sopenharmony_ci // Refs: https://github.com/nodejs/node/pull/30958 2891cb0ef41Sopenharmony_ci for (let i = 0; i < keys.length; i++) { 2901cb0ef41Sopenharmony_ci const key = keys[i]; 2911cb0ef41Sopenharmony_ci this.setHeader(key, options.headers[key]); 2921cb0ef41Sopenharmony_ci } 2931cb0ef41Sopenharmony_ci } 2941cb0ef41Sopenharmony_ci 2951cb0ef41Sopenharmony_ci if (host && !this.getHeader('host') && setHost) { 2961cb0ef41Sopenharmony_ci let hostHeader = host; 2971cb0ef41Sopenharmony_ci 2981cb0ef41Sopenharmony_ci // For the Host header, ensure that IPv6 addresses are enclosed 2991cb0ef41Sopenharmony_ci // in square brackets, as defined by URI formatting 3001cb0ef41Sopenharmony_ci // https://tools.ietf.org/html/rfc3986#section-3.2.2 3011cb0ef41Sopenharmony_ci const posColon = StringPrototypeIndexOf(hostHeader, ':'); 3021cb0ef41Sopenharmony_ci if (posColon !== -1 && 3031cb0ef41Sopenharmony_ci StringPrototypeIncludes(hostHeader, ':', posColon + 1) && 3041cb0ef41Sopenharmony_ci StringPrototypeCharCodeAt(hostHeader, 0) !== 91/* '[' */) { 3051cb0ef41Sopenharmony_ci hostHeader = `[${hostHeader}]`; 3061cb0ef41Sopenharmony_ci } 3071cb0ef41Sopenharmony_ci 3081cb0ef41Sopenharmony_ci if (port && +port !== defaultPort) { 3091cb0ef41Sopenharmony_ci hostHeader += ':' + port; 3101cb0ef41Sopenharmony_ci } 3111cb0ef41Sopenharmony_ci this.setHeader('Host', hostHeader); 3121cb0ef41Sopenharmony_ci } 3131cb0ef41Sopenharmony_ci 3141cb0ef41Sopenharmony_ci if (options.auth && !this.getHeader('Authorization')) { 3151cb0ef41Sopenharmony_ci this.setHeader('Authorization', 'Basic ' + 3161cb0ef41Sopenharmony_ci Buffer.from(options.auth).toString('base64')); 3171cb0ef41Sopenharmony_ci } 3181cb0ef41Sopenharmony_ci 3191cb0ef41Sopenharmony_ci if (this.getHeader('expect')) { 3201cb0ef41Sopenharmony_ci if (this._header) { 3211cb0ef41Sopenharmony_ci throw new ERR_HTTP_HEADERS_SENT('render'); 3221cb0ef41Sopenharmony_ci } 3231cb0ef41Sopenharmony_ci 3241cb0ef41Sopenharmony_ci this._storeHeader(this.method + ' ' + this.path + ' HTTP/1.1\r\n', 3251cb0ef41Sopenharmony_ci this[kOutHeaders]); 3261cb0ef41Sopenharmony_ci } 3271cb0ef41Sopenharmony_ci } else { 3281cb0ef41Sopenharmony_ci this._storeHeader(this.method + ' ' + this.path + ' HTTP/1.1\r\n', 3291cb0ef41Sopenharmony_ci options.headers); 3301cb0ef41Sopenharmony_ci } 3311cb0ef41Sopenharmony_ci 3321cb0ef41Sopenharmony_ci this[kUniqueHeaders] = parseUniqueHeadersOption(options.uniqueHeaders); 3331cb0ef41Sopenharmony_ci 3341cb0ef41Sopenharmony_ci let optsWithoutSignal = options; 3351cb0ef41Sopenharmony_ci if (optsWithoutSignal.signal) { 3361cb0ef41Sopenharmony_ci optsWithoutSignal = ObjectAssign({}, options); 3371cb0ef41Sopenharmony_ci delete optsWithoutSignal.signal; 3381cb0ef41Sopenharmony_ci } 3391cb0ef41Sopenharmony_ci 3401cb0ef41Sopenharmony_ci // initiate connection 3411cb0ef41Sopenharmony_ci if (this.agent) { 3421cb0ef41Sopenharmony_ci this.agent.addRequest(this, optsWithoutSignal); 3431cb0ef41Sopenharmony_ci } else { 3441cb0ef41Sopenharmony_ci // No agent, default to Connection:close. 3451cb0ef41Sopenharmony_ci this._last = true; 3461cb0ef41Sopenharmony_ci this.shouldKeepAlive = false; 3471cb0ef41Sopenharmony_ci if (typeof optsWithoutSignal.createConnection === 'function') { 3481cb0ef41Sopenharmony_ci const oncreate = once((err, socket) => { 3491cb0ef41Sopenharmony_ci if (err) { 3501cb0ef41Sopenharmony_ci process.nextTick(() => this.emit('error', err)); 3511cb0ef41Sopenharmony_ci } else { 3521cb0ef41Sopenharmony_ci this.onSocket(socket); 3531cb0ef41Sopenharmony_ci } 3541cb0ef41Sopenharmony_ci }); 3551cb0ef41Sopenharmony_ci 3561cb0ef41Sopenharmony_ci try { 3571cb0ef41Sopenharmony_ci const newSocket = optsWithoutSignal.createConnection(optsWithoutSignal, 3581cb0ef41Sopenharmony_ci oncreate); 3591cb0ef41Sopenharmony_ci if (newSocket) { 3601cb0ef41Sopenharmony_ci oncreate(null, newSocket); 3611cb0ef41Sopenharmony_ci } 3621cb0ef41Sopenharmony_ci } catch (err) { 3631cb0ef41Sopenharmony_ci oncreate(err); 3641cb0ef41Sopenharmony_ci } 3651cb0ef41Sopenharmony_ci } else { 3661cb0ef41Sopenharmony_ci debug('CLIENT use net.createConnection', optsWithoutSignal); 3671cb0ef41Sopenharmony_ci this.onSocket(net.createConnection(optsWithoutSignal)); 3681cb0ef41Sopenharmony_ci } 3691cb0ef41Sopenharmony_ci } 3701cb0ef41Sopenharmony_ci} 3711cb0ef41Sopenharmony_ciObjectSetPrototypeOf(ClientRequest.prototype, OutgoingMessage.prototype); 3721cb0ef41Sopenharmony_ciObjectSetPrototypeOf(ClientRequest, OutgoingMessage); 3731cb0ef41Sopenharmony_ci 3741cb0ef41Sopenharmony_ciClientRequest.prototype._finish = function _finish() { 3751cb0ef41Sopenharmony_ci DTRACE_HTTP_CLIENT_REQUEST(this, this.socket); 3761cb0ef41Sopenharmony_ci FunctionPrototypeCall(OutgoingMessage.prototype._finish, this); 3771cb0ef41Sopenharmony_ci if (hasObserver('http')) { 3781cb0ef41Sopenharmony_ci startPerf(this, kClientRequestStatistics, { 3791cb0ef41Sopenharmony_ci type: 'http', 3801cb0ef41Sopenharmony_ci name: 'HttpClient', 3811cb0ef41Sopenharmony_ci detail: { 3821cb0ef41Sopenharmony_ci req: { 3831cb0ef41Sopenharmony_ci method: this.method, 3841cb0ef41Sopenharmony_ci url: `${this.protocol}//${this.host}${this.path}`, 3851cb0ef41Sopenharmony_ci headers: typeof this.getHeaders === 'function' ? this.getHeaders() : {}, 3861cb0ef41Sopenharmony_ci }, 3871cb0ef41Sopenharmony_ci }, 3881cb0ef41Sopenharmony_ci }); 3891cb0ef41Sopenharmony_ci } 3901cb0ef41Sopenharmony_ci if (onClientRequestStartChannel.hasSubscribers) { 3911cb0ef41Sopenharmony_ci onClientRequestStartChannel.publish({ 3921cb0ef41Sopenharmony_ci request: this, 3931cb0ef41Sopenharmony_ci }); 3941cb0ef41Sopenharmony_ci } 3951cb0ef41Sopenharmony_ci if (isTraceHTTPEnabled()) { 3961cb0ef41Sopenharmony_ci this._traceEventId = getNextTraceEventId(); 3971cb0ef41Sopenharmony_ci traceBegin(HTTP_CLIENT_TRACE_EVENT_NAME, this._traceEventId); 3981cb0ef41Sopenharmony_ci } 3991cb0ef41Sopenharmony_ci}; 4001cb0ef41Sopenharmony_ci 4011cb0ef41Sopenharmony_ciClientRequest.prototype._implicitHeader = function _implicitHeader() { 4021cb0ef41Sopenharmony_ci if (this._header) { 4031cb0ef41Sopenharmony_ci throw new ERR_HTTP_HEADERS_SENT('render'); 4041cb0ef41Sopenharmony_ci } 4051cb0ef41Sopenharmony_ci this._storeHeader(this.method + ' ' + this.path + ' HTTP/1.1\r\n', 4061cb0ef41Sopenharmony_ci this[kOutHeaders]); 4071cb0ef41Sopenharmony_ci}; 4081cb0ef41Sopenharmony_ci 4091cb0ef41Sopenharmony_ciClientRequest.prototype.abort = function abort() { 4101cb0ef41Sopenharmony_ci if (this.aborted) { 4111cb0ef41Sopenharmony_ci return; 4121cb0ef41Sopenharmony_ci } 4131cb0ef41Sopenharmony_ci this.aborted = true; 4141cb0ef41Sopenharmony_ci process.nextTick(emitAbortNT, this); 4151cb0ef41Sopenharmony_ci this.destroy(); 4161cb0ef41Sopenharmony_ci}; 4171cb0ef41Sopenharmony_ci 4181cb0ef41Sopenharmony_ciClientRequest.prototype.destroy = function destroy(err) { 4191cb0ef41Sopenharmony_ci if (this.destroyed) { 4201cb0ef41Sopenharmony_ci return this; 4211cb0ef41Sopenharmony_ci } 4221cb0ef41Sopenharmony_ci this.destroyed = true; 4231cb0ef41Sopenharmony_ci 4241cb0ef41Sopenharmony_ci // If we're aborting, we don't care about any more response data. 4251cb0ef41Sopenharmony_ci if (this.res) { 4261cb0ef41Sopenharmony_ci this.res._dump(); 4271cb0ef41Sopenharmony_ci } 4281cb0ef41Sopenharmony_ci 4291cb0ef41Sopenharmony_ci this[kError] = err; 4301cb0ef41Sopenharmony_ci this.socket?.destroy(err); 4311cb0ef41Sopenharmony_ci 4321cb0ef41Sopenharmony_ci return this; 4331cb0ef41Sopenharmony_ci}; 4341cb0ef41Sopenharmony_ci 4351cb0ef41Sopenharmony_cifunction emitAbortNT(req) { 4361cb0ef41Sopenharmony_ci req.emit('abort'); 4371cb0ef41Sopenharmony_ci} 4381cb0ef41Sopenharmony_ci 4391cb0ef41Sopenharmony_cifunction ondrain() { 4401cb0ef41Sopenharmony_ci const msg = this._httpMessage; 4411cb0ef41Sopenharmony_ci if (msg && !msg.finished && msg[kNeedDrain]) { 4421cb0ef41Sopenharmony_ci msg[kNeedDrain] = false; 4431cb0ef41Sopenharmony_ci msg.emit('drain'); 4441cb0ef41Sopenharmony_ci } 4451cb0ef41Sopenharmony_ci} 4461cb0ef41Sopenharmony_ci 4471cb0ef41Sopenharmony_cifunction socketCloseListener() { 4481cb0ef41Sopenharmony_ci const socket = this; 4491cb0ef41Sopenharmony_ci const req = socket._httpMessage; 4501cb0ef41Sopenharmony_ci debug('HTTP socket close'); 4511cb0ef41Sopenharmony_ci 4521cb0ef41Sopenharmony_ci // NOTE: It's important to get parser here, because it could be freed by 4531cb0ef41Sopenharmony_ci // the `socketOnData`. 4541cb0ef41Sopenharmony_ci const parser = socket.parser; 4551cb0ef41Sopenharmony_ci const res = req.res; 4561cb0ef41Sopenharmony_ci 4571cb0ef41Sopenharmony_ci req.destroyed = true; 4581cb0ef41Sopenharmony_ci if (res) { 4591cb0ef41Sopenharmony_ci // Socket closed before we emitted 'end' below. 4601cb0ef41Sopenharmony_ci if (!res.complete) { 4611cb0ef41Sopenharmony_ci res.destroy(connResetException('aborted')); 4621cb0ef41Sopenharmony_ci } 4631cb0ef41Sopenharmony_ci req._closed = true; 4641cb0ef41Sopenharmony_ci req.emit('close'); 4651cb0ef41Sopenharmony_ci if (!res.aborted && res.readable) { 4661cb0ef41Sopenharmony_ci res.push(null); 4671cb0ef41Sopenharmony_ci } 4681cb0ef41Sopenharmony_ci } else { 4691cb0ef41Sopenharmony_ci if (!req.socket._hadError) { 4701cb0ef41Sopenharmony_ci // This socket error fired before we started to 4711cb0ef41Sopenharmony_ci // receive a response. The error needs to 4721cb0ef41Sopenharmony_ci // fire on the request. 4731cb0ef41Sopenharmony_ci req.socket._hadError = true; 4741cb0ef41Sopenharmony_ci req.emit('error', connResetException('socket hang up')); 4751cb0ef41Sopenharmony_ci } 4761cb0ef41Sopenharmony_ci req._closed = true; 4771cb0ef41Sopenharmony_ci req.emit('close'); 4781cb0ef41Sopenharmony_ci } 4791cb0ef41Sopenharmony_ci 4801cb0ef41Sopenharmony_ci // Too bad. That output wasn't getting written. 4811cb0ef41Sopenharmony_ci // This is pretty terrible that it doesn't raise an error. 4821cb0ef41Sopenharmony_ci // Fixed better in v0.10 4831cb0ef41Sopenharmony_ci if (req.outputData) 4841cb0ef41Sopenharmony_ci req.outputData.length = 0; 4851cb0ef41Sopenharmony_ci 4861cb0ef41Sopenharmony_ci if (parser) { 4871cb0ef41Sopenharmony_ci parser.finish(); 4881cb0ef41Sopenharmony_ci freeParser(parser, req, socket); 4891cb0ef41Sopenharmony_ci } 4901cb0ef41Sopenharmony_ci} 4911cb0ef41Sopenharmony_ci 4921cb0ef41Sopenharmony_cifunction socketErrorListener(err) { 4931cb0ef41Sopenharmony_ci const socket = this; 4941cb0ef41Sopenharmony_ci const req = socket._httpMessage; 4951cb0ef41Sopenharmony_ci debug('SOCKET ERROR:', err.message, err.stack); 4961cb0ef41Sopenharmony_ci 4971cb0ef41Sopenharmony_ci if (req) { 4981cb0ef41Sopenharmony_ci // For Safety. Some additional errors might fire later on 4991cb0ef41Sopenharmony_ci // and we need to make sure we don't double-fire the error event. 5001cb0ef41Sopenharmony_ci req.socket._hadError = true; 5011cb0ef41Sopenharmony_ci req.emit('error', err); 5021cb0ef41Sopenharmony_ci } 5031cb0ef41Sopenharmony_ci 5041cb0ef41Sopenharmony_ci const parser = socket.parser; 5051cb0ef41Sopenharmony_ci if (parser) { 5061cb0ef41Sopenharmony_ci parser.finish(); 5071cb0ef41Sopenharmony_ci freeParser(parser, req, socket); 5081cb0ef41Sopenharmony_ci } 5091cb0ef41Sopenharmony_ci 5101cb0ef41Sopenharmony_ci // Ensure that no further data will come out of the socket 5111cb0ef41Sopenharmony_ci socket.removeListener('data', socketOnData); 5121cb0ef41Sopenharmony_ci socket.removeListener('end', socketOnEnd); 5131cb0ef41Sopenharmony_ci socket.destroy(); 5141cb0ef41Sopenharmony_ci} 5151cb0ef41Sopenharmony_ci 5161cb0ef41Sopenharmony_cifunction socketOnEnd() { 5171cb0ef41Sopenharmony_ci const socket = this; 5181cb0ef41Sopenharmony_ci const req = this._httpMessage; 5191cb0ef41Sopenharmony_ci const parser = this.parser; 5201cb0ef41Sopenharmony_ci 5211cb0ef41Sopenharmony_ci if (!req.res && !req.socket._hadError) { 5221cb0ef41Sopenharmony_ci // If we don't have a response then we know that the socket 5231cb0ef41Sopenharmony_ci // ended prematurely and we need to emit an error on the request. 5241cb0ef41Sopenharmony_ci req.socket._hadError = true; 5251cb0ef41Sopenharmony_ci req.emit('error', connResetException('socket hang up')); 5261cb0ef41Sopenharmony_ci } 5271cb0ef41Sopenharmony_ci if (parser) { 5281cb0ef41Sopenharmony_ci parser.finish(); 5291cb0ef41Sopenharmony_ci freeParser(parser, req, socket); 5301cb0ef41Sopenharmony_ci } 5311cb0ef41Sopenharmony_ci socket.destroy(); 5321cb0ef41Sopenharmony_ci} 5331cb0ef41Sopenharmony_ci 5341cb0ef41Sopenharmony_cifunction socketOnData(d) { 5351cb0ef41Sopenharmony_ci const socket = this; 5361cb0ef41Sopenharmony_ci const req = this._httpMessage; 5371cb0ef41Sopenharmony_ci const parser = this.parser; 5381cb0ef41Sopenharmony_ci 5391cb0ef41Sopenharmony_ci assert(parser && parser.socket === socket); 5401cb0ef41Sopenharmony_ci 5411cb0ef41Sopenharmony_ci const ret = parser.execute(d); 5421cb0ef41Sopenharmony_ci if (ret instanceof Error) { 5431cb0ef41Sopenharmony_ci prepareError(ret, parser, d); 5441cb0ef41Sopenharmony_ci debug('parse error', ret); 5451cb0ef41Sopenharmony_ci freeParser(parser, req, socket); 5461cb0ef41Sopenharmony_ci socket.removeListener('data', socketOnData); 5471cb0ef41Sopenharmony_ci socket.removeListener('end', socketOnEnd); 5481cb0ef41Sopenharmony_ci socket.destroy(); 5491cb0ef41Sopenharmony_ci req.socket._hadError = true; 5501cb0ef41Sopenharmony_ci req.emit('error', ret); 5511cb0ef41Sopenharmony_ci } else if (parser.incoming && parser.incoming.upgrade) { 5521cb0ef41Sopenharmony_ci // Upgrade (if status code 101) or CONNECT 5531cb0ef41Sopenharmony_ci const bytesParsed = ret; 5541cb0ef41Sopenharmony_ci const res = parser.incoming; 5551cb0ef41Sopenharmony_ci req.res = res; 5561cb0ef41Sopenharmony_ci 5571cb0ef41Sopenharmony_ci socket.removeListener('data', socketOnData); 5581cb0ef41Sopenharmony_ci socket.removeListener('end', socketOnEnd); 5591cb0ef41Sopenharmony_ci socket.removeListener('drain', ondrain); 5601cb0ef41Sopenharmony_ci 5611cb0ef41Sopenharmony_ci if (req.timeoutCb) socket.removeListener('timeout', req.timeoutCb); 5621cb0ef41Sopenharmony_ci socket.removeListener('timeout', responseOnTimeout); 5631cb0ef41Sopenharmony_ci 5641cb0ef41Sopenharmony_ci parser.finish(); 5651cb0ef41Sopenharmony_ci freeParser(parser, req, socket); 5661cb0ef41Sopenharmony_ci 5671cb0ef41Sopenharmony_ci const bodyHead = TypedArrayPrototypeSlice(d, bytesParsed, d.length); 5681cb0ef41Sopenharmony_ci 5691cb0ef41Sopenharmony_ci const eventName = req.method === 'CONNECT' ? 'connect' : 'upgrade'; 5701cb0ef41Sopenharmony_ci if (req.listenerCount(eventName) > 0) { 5711cb0ef41Sopenharmony_ci req.upgradeOrConnect = true; 5721cb0ef41Sopenharmony_ci 5731cb0ef41Sopenharmony_ci // detach the socket 5741cb0ef41Sopenharmony_ci socket.emit('agentRemove'); 5751cb0ef41Sopenharmony_ci socket.removeListener('close', socketCloseListener); 5761cb0ef41Sopenharmony_ci socket.removeListener('error', socketErrorListener); 5771cb0ef41Sopenharmony_ci 5781cb0ef41Sopenharmony_ci socket._httpMessage = null; 5791cb0ef41Sopenharmony_ci socket.readableFlowing = null; 5801cb0ef41Sopenharmony_ci 5811cb0ef41Sopenharmony_ci req.emit(eventName, res, socket, bodyHead); 5821cb0ef41Sopenharmony_ci req.destroyed = true; 5831cb0ef41Sopenharmony_ci req._closed = true; 5841cb0ef41Sopenharmony_ci req.emit('close'); 5851cb0ef41Sopenharmony_ci } else { 5861cb0ef41Sopenharmony_ci // Requested Upgrade or used CONNECT method, but have no handler. 5871cb0ef41Sopenharmony_ci socket.destroy(); 5881cb0ef41Sopenharmony_ci } 5891cb0ef41Sopenharmony_ci } else if (parser.incoming && parser.incoming.complete && 5901cb0ef41Sopenharmony_ci // When the status code is informational (100, 102-199), 5911cb0ef41Sopenharmony_ci // the server will send a final response after this client 5921cb0ef41Sopenharmony_ci // sends a request body, so we must not free the parser. 5931cb0ef41Sopenharmony_ci // 101 (Switching Protocols) and all other status codes 5941cb0ef41Sopenharmony_ci // should be processed normally. 5951cb0ef41Sopenharmony_ci !statusIsInformational(parser.incoming.statusCode)) { 5961cb0ef41Sopenharmony_ci socket.removeListener('data', socketOnData); 5971cb0ef41Sopenharmony_ci socket.removeListener('end', socketOnEnd); 5981cb0ef41Sopenharmony_ci socket.removeListener('drain', ondrain); 5991cb0ef41Sopenharmony_ci freeParser(parser, req, socket); 6001cb0ef41Sopenharmony_ci } 6011cb0ef41Sopenharmony_ci} 6021cb0ef41Sopenharmony_ci 6031cb0ef41Sopenharmony_cifunction statusIsInformational(status) { 6041cb0ef41Sopenharmony_ci // 100 (Continue) RFC7231 Section 6.2.1 6051cb0ef41Sopenharmony_ci // 102 (Processing) RFC2518 6061cb0ef41Sopenharmony_ci // 103 (Early Hints) RFC8297 6071cb0ef41Sopenharmony_ci // 104-199 (Unassigned) 6081cb0ef41Sopenharmony_ci return (status < 200 && status >= 100 && status !== 101); 6091cb0ef41Sopenharmony_ci} 6101cb0ef41Sopenharmony_ci 6111cb0ef41Sopenharmony_ci// client 6121cb0ef41Sopenharmony_cifunction parserOnIncomingClient(res, shouldKeepAlive) { 6131cb0ef41Sopenharmony_ci const socket = this.socket; 6141cb0ef41Sopenharmony_ci const req = socket._httpMessage; 6151cb0ef41Sopenharmony_ci 6161cb0ef41Sopenharmony_ci debug('AGENT incoming response!'); 6171cb0ef41Sopenharmony_ci 6181cb0ef41Sopenharmony_ci if (req.res) { 6191cb0ef41Sopenharmony_ci // We already have a response object, this means the server 6201cb0ef41Sopenharmony_ci // sent a double response. 6211cb0ef41Sopenharmony_ci socket.destroy(); 6221cb0ef41Sopenharmony_ci return 0; // No special treatment. 6231cb0ef41Sopenharmony_ci } 6241cb0ef41Sopenharmony_ci req.res = res; 6251cb0ef41Sopenharmony_ci 6261cb0ef41Sopenharmony_ci // Skip body and treat as Upgrade. 6271cb0ef41Sopenharmony_ci if (res.upgrade) 6281cb0ef41Sopenharmony_ci return 2; 6291cb0ef41Sopenharmony_ci 6301cb0ef41Sopenharmony_ci // Responses to CONNECT request is handled as Upgrade. 6311cb0ef41Sopenharmony_ci const method = req.method; 6321cb0ef41Sopenharmony_ci if (method === 'CONNECT') { 6331cb0ef41Sopenharmony_ci res.upgrade = true; 6341cb0ef41Sopenharmony_ci return 2; // Skip body and treat as Upgrade. 6351cb0ef41Sopenharmony_ci } 6361cb0ef41Sopenharmony_ci 6371cb0ef41Sopenharmony_ci if (statusIsInformational(res.statusCode)) { 6381cb0ef41Sopenharmony_ci // Restart the parser, as this is a 1xx informational message. 6391cb0ef41Sopenharmony_ci req.res = null; // Clear res so that we don't hit double-responses. 6401cb0ef41Sopenharmony_ci // Maintain compatibility by sending 100-specific events 6411cb0ef41Sopenharmony_ci if (res.statusCode === 100) { 6421cb0ef41Sopenharmony_ci req.emit('continue'); 6431cb0ef41Sopenharmony_ci } 6441cb0ef41Sopenharmony_ci // Send information events to all 1xx responses except 101 Upgrade. 6451cb0ef41Sopenharmony_ci req.emit('information', { 6461cb0ef41Sopenharmony_ci statusCode: res.statusCode, 6471cb0ef41Sopenharmony_ci statusMessage: res.statusMessage, 6481cb0ef41Sopenharmony_ci httpVersion: res.httpVersion, 6491cb0ef41Sopenharmony_ci httpVersionMajor: res.httpVersionMajor, 6501cb0ef41Sopenharmony_ci httpVersionMinor: res.httpVersionMinor, 6511cb0ef41Sopenharmony_ci headers: res.headers, 6521cb0ef41Sopenharmony_ci rawHeaders: res.rawHeaders, 6531cb0ef41Sopenharmony_ci }); 6541cb0ef41Sopenharmony_ci 6551cb0ef41Sopenharmony_ci return 1; // Skip body but don't treat as Upgrade. 6561cb0ef41Sopenharmony_ci } 6571cb0ef41Sopenharmony_ci 6581cb0ef41Sopenharmony_ci if (req.shouldKeepAlive && !shouldKeepAlive && !req.upgradeOrConnect) { 6591cb0ef41Sopenharmony_ci // Server MUST respond with Connection:keep-alive for us to enable it. 6601cb0ef41Sopenharmony_ci // If we've been upgraded (via WebSockets) we also shouldn't try to 6611cb0ef41Sopenharmony_ci // keep the connection open. 6621cb0ef41Sopenharmony_ci req.shouldKeepAlive = false; 6631cb0ef41Sopenharmony_ci } 6641cb0ef41Sopenharmony_ci 6651cb0ef41Sopenharmony_ci DTRACE_HTTP_CLIENT_RESPONSE(socket, req); 6661cb0ef41Sopenharmony_ci if (req[kClientRequestStatistics] && hasObserver('http')) { 6671cb0ef41Sopenharmony_ci stopPerf(req, kClientRequestStatistics, { 6681cb0ef41Sopenharmony_ci detail: { 6691cb0ef41Sopenharmony_ci res: { 6701cb0ef41Sopenharmony_ci statusCode: res.statusCode, 6711cb0ef41Sopenharmony_ci statusMessage: res.statusMessage, 6721cb0ef41Sopenharmony_ci headers: res.headers, 6731cb0ef41Sopenharmony_ci }, 6741cb0ef41Sopenharmony_ci }, 6751cb0ef41Sopenharmony_ci }); 6761cb0ef41Sopenharmony_ci } 6771cb0ef41Sopenharmony_ci if (onClientResponseFinishChannel.hasSubscribers) { 6781cb0ef41Sopenharmony_ci onClientResponseFinishChannel.publish({ 6791cb0ef41Sopenharmony_ci request: req, 6801cb0ef41Sopenharmony_ci response: res, 6811cb0ef41Sopenharmony_ci }); 6821cb0ef41Sopenharmony_ci } 6831cb0ef41Sopenharmony_ci if (isTraceHTTPEnabled() && typeof req._traceEventId === 'number') { 6841cb0ef41Sopenharmony_ci traceEnd(HTTP_CLIENT_TRACE_EVENT_NAME, req._traceEventId, { 6851cb0ef41Sopenharmony_ci path: req.path, 6861cb0ef41Sopenharmony_ci statusCode: res.statusCode, 6871cb0ef41Sopenharmony_ci }); 6881cb0ef41Sopenharmony_ci } 6891cb0ef41Sopenharmony_ci req.res = res; 6901cb0ef41Sopenharmony_ci res.req = req; 6911cb0ef41Sopenharmony_ci 6921cb0ef41Sopenharmony_ci // Add our listener first, so that we guarantee socket cleanup 6931cb0ef41Sopenharmony_ci res.on('end', responseOnEnd); 6941cb0ef41Sopenharmony_ci req.on('finish', requestOnFinish); 6951cb0ef41Sopenharmony_ci socket.on('timeout', responseOnTimeout); 6961cb0ef41Sopenharmony_ci 6971cb0ef41Sopenharmony_ci // If the user did not listen for the 'response' event, then they 6981cb0ef41Sopenharmony_ci // can't possibly read the data, so we ._dump() it into the void 6991cb0ef41Sopenharmony_ci // so that the socket doesn't hang there in a paused state. 7001cb0ef41Sopenharmony_ci if (req.aborted || !req.emit('response', res)) 7011cb0ef41Sopenharmony_ci res._dump(); 7021cb0ef41Sopenharmony_ci 7031cb0ef41Sopenharmony_ci if (method === 'HEAD') 7041cb0ef41Sopenharmony_ci return 1; // Skip body but don't treat as Upgrade. 7051cb0ef41Sopenharmony_ci 7061cb0ef41Sopenharmony_ci if (res.statusCode === 304) { 7071cb0ef41Sopenharmony_ci res.complete = true; 7081cb0ef41Sopenharmony_ci return 1; // Skip body as there won't be any 7091cb0ef41Sopenharmony_ci } 7101cb0ef41Sopenharmony_ci 7111cb0ef41Sopenharmony_ci return 0; // No special treatment. 7121cb0ef41Sopenharmony_ci} 7131cb0ef41Sopenharmony_ci 7141cb0ef41Sopenharmony_ci// client 7151cb0ef41Sopenharmony_cifunction responseKeepAlive(req) { 7161cb0ef41Sopenharmony_ci const socket = req.socket; 7171cb0ef41Sopenharmony_ci 7181cb0ef41Sopenharmony_ci debug('AGENT socket keep-alive'); 7191cb0ef41Sopenharmony_ci if (req.timeoutCb) { 7201cb0ef41Sopenharmony_ci socket.setTimeout(0, req.timeoutCb); 7211cb0ef41Sopenharmony_ci req.timeoutCb = null; 7221cb0ef41Sopenharmony_ci } 7231cb0ef41Sopenharmony_ci socket.removeListener('close', socketCloseListener); 7241cb0ef41Sopenharmony_ci socket.removeListener('error', socketErrorListener); 7251cb0ef41Sopenharmony_ci socket.removeListener('data', socketOnData); 7261cb0ef41Sopenharmony_ci socket.removeListener('end', socketOnEnd); 7271cb0ef41Sopenharmony_ci 7281cb0ef41Sopenharmony_ci // TODO(ronag): Between here and emitFreeNT the socket 7291cb0ef41Sopenharmony_ci // has no 'error' handler. 7301cb0ef41Sopenharmony_ci 7311cb0ef41Sopenharmony_ci // There are cases where _handle === null. Avoid those. Passing undefined to 7321cb0ef41Sopenharmony_ci // nextTick() will call getDefaultTriggerAsyncId() to retrieve the id. 7331cb0ef41Sopenharmony_ci const asyncId = socket._handle ? socket._handle.getAsyncId() : undefined; 7341cb0ef41Sopenharmony_ci // Mark this socket as available, AFTER user-added end 7351cb0ef41Sopenharmony_ci // handlers have a chance to run. 7361cb0ef41Sopenharmony_ci defaultTriggerAsyncIdScope(asyncId, process.nextTick, emitFreeNT, req); 7371cb0ef41Sopenharmony_ci 7381cb0ef41Sopenharmony_ci req.destroyed = true; 7391cb0ef41Sopenharmony_ci if (req.res) { 7401cb0ef41Sopenharmony_ci // Detach socket from IncomingMessage to avoid destroying the freed 7411cb0ef41Sopenharmony_ci // socket in IncomingMessage.destroy(). 7421cb0ef41Sopenharmony_ci req.res.socket = null; 7431cb0ef41Sopenharmony_ci } 7441cb0ef41Sopenharmony_ci} 7451cb0ef41Sopenharmony_ci 7461cb0ef41Sopenharmony_cifunction responseOnEnd() { 7471cb0ef41Sopenharmony_ci const req = this.req; 7481cb0ef41Sopenharmony_ci const socket = req.socket; 7491cb0ef41Sopenharmony_ci 7501cb0ef41Sopenharmony_ci if (socket) { 7511cb0ef41Sopenharmony_ci if (req.timeoutCb) socket.removeListener('timeout', emitRequestTimeout); 7521cb0ef41Sopenharmony_ci socket.removeListener('timeout', responseOnTimeout); 7531cb0ef41Sopenharmony_ci } 7541cb0ef41Sopenharmony_ci 7551cb0ef41Sopenharmony_ci req._ended = true; 7561cb0ef41Sopenharmony_ci 7571cb0ef41Sopenharmony_ci if (!req.shouldKeepAlive) { 7581cb0ef41Sopenharmony_ci if (socket.writable) { 7591cb0ef41Sopenharmony_ci debug('AGENT socket.destroySoon()'); 7601cb0ef41Sopenharmony_ci if (typeof socket.destroySoon === 'function') 7611cb0ef41Sopenharmony_ci socket.destroySoon(); 7621cb0ef41Sopenharmony_ci else 7631cb0ef41Sopenharmony_ci socket.end(); 7641cb0ef41Sopenharmony_ci } 7651cb0ef41Sopenharmony_ci assert(!socket.writable); 7661cb0ef41Sopenharmony_ci } else if (req.writableFinished && !this.aborted) { 7671cb0ef41Sopenharmony_ci assert(req.finished); 7681cb0ef41Sopenharmony_ci // We can assume `req.finished` means all data has been written since: 7691cb0ef41Sopenharmony_ci // - `'responseOnEnd'` means we have been assigned a socket. 7701cb0ef41Sopenharmony_ci // - when we have a socket we write directly to it without buffering. 7711cb0ef41Sopenharmony_ci // - `req.finished` means `end()` has been called and no further data. 7721cb0ef41Sopenharmony_ci // can be written 7731cb0ef41Sopenharmony_ci // In addition, `req.writableFinished` means all data written has been 7741cb0ef41Sopenharmony_ci // accepted by the kernel. (i.e. the `req.socket` is drained).Without 7751cb0ef41Sopenharmony_ci // this constraint, we may assign a non drained socket to a request. 7761cb0ef41Sopenharmony_ci responseKeepAlive(req); 7771cb0ef41Sopenharmony_ci } 7781cb0ef41Sopenharmony_ci} 7791cb0ef41Sopenharmony_ci 7801cb0ef41Sopenharmony_cifunction responseOnTimeout() { 7811cb0ef41Sopenharmony_ci const req = this._httpMessage; 7821cb0ef41Sopenharmony_ci if (!req) return; 7831cb0ef41Sopenharmony_ci const res = req.res; 7841cb0ef41Sopenharmony_ci if (!res) return; 7851cb0ef41Sopenharmony_ci res.emit('timeout'); 7861cb0ef41Sopenharmony_ci} 7871cb0ef41Sopenharmony_ci 7881cb0ef41Sopenharmony_ci// This function is necessary in the case where we receive the entire response 7891cb0ef41Sopenharmony_ci// from the server before we finish sending out the request. 7901cb0ef41Sopenharmony_cifunction requestOnFinish() { 7911cb0ef41Sopenharmony_ci const req = this; 7921cb0ef41Sopenharmony_ci 7931cb0ef41Sopenharmony_ci if (req.shouldKeepAlive && req._ended) 7941cb0ef41Sopenharmony_ci responseKeepAlive(req); 7951cb0ef41Sopenharmony_ci} 7961cb0ef41Sopenharmony_ci 7971cb0ef41Sopenharmony_cifunction emitFreeNT(req) { 7981cb0ef41Sopenharmony_ci req._closed = true; 7991cb0ef41Sopenharmony_ci req.emit('close'); 8001cb0ef41Sopenharmony_ci if (req.socket) { 8011cb0ef41Sopenharmony_ci req.socket.emit('free'); 8021cb0ef41Sopenharmony_ci } 8031cb0ef41Sopenharmony_ci} 8041cb0ef41Sopenharmony_ci 8051cb0ef41Sopenharmony_cifunction tickOnSocket(req, socket) { 8061cb0ef41Sopenharmony_ci const parser = parsers.alloc(); 8071cb0ef41Sopenharmony_ci req.socket = socket; 8081cb0ef41Sopenharmony_ci const lenient = req.insecureHTTPParser === undefined ? 8091cb0ef41Sopenharmony_ci isLenient() : req.insecureHTTPParser; 8101cb0ef41Sopenharmony_ci parser.initialize(HTTPParser.RESPONSE, 8111cb0ef41Sopenharmony_ci new HTTPClientAsyncResource('HTTPINCOMINGMESSAGE', req), 8121cb0ef41Sopenharmony_ci req.maxHeaderSize || 0, 8131cb0ef41Sopenharmony_ci lenient ? kLenientAll : kLenientNone); 8141cb0ef41Sopenharmony_ci parser.socket = socket; 8151cb0ef41Sopenharmony_ci parser.outgoing = req; 8161cb0ef41Sopenharmony_ci req.parser = parser; 8171cb0ef41Sopenharmony_ci 8181cb0ef41Sopenharmony_ci socket.parser = parser; 8191cb0ef41Sopenharmony_ci socket._httpMessage = req; 8201cb0ef41Sopenharmony_ci 8211cb0ef41Sopenharmony_ci // Propagate headers limit from request object to parser 8221cb0ef41Sopenharmony_ci if (typeof req.maxHeadersCount === 'number') { 8231cb0ef41Sopenharmony_ci parser.maxHeaderPairs = req.maxHeadersCount << 1; 8241cb0ef41Sopenharmony_ci } 8251cb0ef41Sopenharmony_ci 8261cb0ef41Sopenharmony_ci parser.joinDuplicateHeaders = req.joinDuplicateHeaders; 8271cb0ef41Sopenharmony_ci 8281cb0ef41Sopenharmony_ci parser.onIncoming = parserOnIncomingClient; 8291cb0ef41Sopenharmony_ci socket.on('error', socketErrorListener); 8301cb0ef41Sopenharmony_ci socket.on('data', socketOnData); 8311cb0ef41Sopenharmony_ci socket.on('end', socketOnEnd); 8321cb0ef41Sopenharmony_ci socket.on('close', socketCloseListener); 8331cb0ef41Sopenharmony_ci socket.on('drain', ondrain); 8341cb0ef41Sopenharmony_ci 8351cb0ef41Sopenharmony_ci if ( 8361cb0ef41Sopenharmony_ci req.timeout !== undefined || 8371cb0ef41Sopenharmony_ci (req.agent && req.agent.options && req.agent.options.timeout) 8381cb0ef41Sopenharmony_ci ) { 8391cb0ef41Sopenharmony_ci listenSocketTimeout(req); 8401cb0ef41Sopenharmony_ci } 8411cb0ef41Sopenharmony_ci req.emit('socket', socket); 8421cb0ef41Sopenharmony_ci} 8431cb0ef41Sopenharmony_ci 8441cb0ef41Sopenharmony_cifunction emitRequestTimeout() { 8451cb0ef41Sopenharmony_ci const req = this._httpMessage; 8461cb0ef41Sopenharmony_ci if (req) { 8471cb0ef41Sopenharmony_ci req.emit('timeout'); 8481cb0ef41Sopenharmony_ci } 8491cb0ef41Sopenharmony_ci} 8501cb0ef41Sopenharmony_ci 8511cb0ef41Sopenharmony_cifunction listenSocketTimeout(req) { 8521cb0ef41Sopenharmony_ci if (req.timeoutCb) { 8531cb0ef41Sopenharmony_ci return; 8541cb0ef41Sopenharmony_ci } 8551cb0ef41Sopenharmony_ci // Set timeoutCb so it will get cleaned up on request end. 8561cb0ef41Sopenharmony_ci req.timeoutCb = emitRequestTimeout; 8571cb0ef41Sopenharmony_ci // Delegate socket timeout event. 8581cb0ef41Sopenharmony_ci if (req.socket) { 8591cb0ef41Sopenharmony_ci req.socket.once('timeout', emitRequestTimeout); 8601cb0ef41Sopenharmony_ci } else { 8611cb0ef41Sopenharmony_ci req.on('socket', (socket) => { 8621cb0ef41Sopenharmony_ci socket.once('timeout', emitRequestTimeout); 8631cb0ef41Sopenharmony_ci }); 8641cb0ef41Sopenharmony_ci } 8651cb0ef41Sopenharmony_ci} 8661cb0ef41Sopenharmony_ci 8671cb0ef41Sopenharmony_ciClientRequest.prototype.onSocket = function onSocket(socket, err) { 8681cb0ef41Sopenharmony_ci // TODO(ronag): Between here and onSocketNT the socket 8691cb0ef41Sopenharmony_ci // has no 'error' handler. 8701cb0ef41Sopenharmony_ci process.nextTick(onSocketNT, this, socket, err); 8711cb0ef41Sopenharmony_ci}; 8721cb0ef41Sopenharmony_ci 8731cb0ef41Sopenharmony_cifunction onSocketNT(req, socket, err) { 8741cb0ef41Sopenharmony_ci if (req.destroyed || err) { 8751cb0ef41Sopenharmony_ci req.destroyed = true; 8761cb0ef41Sopenharmony_ci 8771cb0ef41Sopenharmony_ci function _destroy(req, err) { 8781cb0ef41Sopenharmony_ci if (!req.aborted && !err) { 8791cb0ef41Sopenharmony_ci err = connResetException('socket hang up'); 8801cb0ef41Sopenharmony_ci } 8811cb0ef41Sopenharmony_ci if (err) { 8821cb0ef41Sopenharmony_ci req.emit('error', err); 8831cb0ef41Sopenharmony_ci } 8841cb0ef41Sopenharmony_ci req._closed = true; 8851cb0ef41Sopenharmony_ci req.emit('close'); 8861cb0ef41Sopenharmony_ci } 8871cb0ef41Sopenharmony_ci 8881cb0ef41Sopenharmony_ci if (socket) { 8891cb0ef41Sopenharmony_ci if (!err && req.agent && !socket.destroyed) { 8901cb0ef41Sopenharmony_ci socket.emit('free'); 8911cb0ef41Sopenharmony_ci } else { 8921cb0ef41Sopenharmony_ci finished(socket.destroy(err || req[kError]), (er) => { 8931cb0ef41Sopenharmony_ci if (er?.code === 'ERR_STREAM_PREMATURE_CLOSE') { 8941cb0ef41Sopenharmony_ci er = null; 8951cb0ef41Sopenharmony_ci } 8961cb0ef41Sopenharmony_ci _destroy(req, er || err); 8971cb0ef41Sopenharmony_ci }); 8981cb0ef41Sopenharmony_ci return; 8991cb0ef41Sopenharmony_ci } 9001cb0ef41Sopenharmony_ci } 9011cb0ef41Sopenharmony_ci 9021cb0ef41Sopenharmony_ci _destroy(req, err || req[kError]); 9031cb0ef41Sopenharmony_ci } else { 9041cb0ef41Sopenharmony_ci tickOnSocket(req, socket); 9051cb0ef41Sopenharmony_ci req._flush(); 9061cb0ef41Sopenharmony_ci } 9071cb0ef41Sopenharmony_ci} 9081cb0ef41Sopenharmony_ci 9091cb0ef41Sopenharmony_ciClientRequest.prototype._deferToConnect = _deferToConnect; 9101cb0ef41Sopenharmony_cifunction _deferToConnect(method, arguments_) { 9111cb0ef41Sopenharmony_ci // This function is for calls that need to happen once the socket is 9121cb0ef41Sopenharmony_ci // assigned to this request and writable. It's an important promisy 9131cb0ef41Sopenharmony_ci // thing for all the socket calls that happen either now 9141cb0ef41Sopenharmony_ci // (when a socket is assigned) or in the future (when a socket gets 9151cb0ef41Sopenharmony_ci // assigned out of the pool and is eventually writable). 9161cb0ef41Sopenharmony_ci 9171cb0ef41Sopenharmony_ci const callSocketMethod = () => { 9181cb0ef41Sopenharmony_ci if (method) 9191cb0ef41Sopenharmony_ci ReflectApply(this.socket[method], this.socket, arguments_); 9201cb0ef41Sopenharmony_ci }; 9211cb0ef41Sopenharmony_ci 9221cb0ef41Sopenharmony_ci const onSocket = () => { 9231cb0ef41Sopenharmony_ci if (this.socket.writable) { 9241cb0ef41Sopenharmony_ci callSocketMethod(); 9251cb0ef41Sopenharmony_ci } else { 9261cb0ef41Sopenharmony_ci this.socket.once('connect', callSocketMethod); 9271cb0ef41Sopenharmony_ci } 9281cb0ef41Sopenharmony_ci }; 9291cb0ef41Sopenharmony_ci 9301cb0ef41Sopenharmony_ci if (!this.socket) { 9311cb0ef41Sopenharmony_ci this.once('socket', onSocket); 9321cb0ef41Sopenharmony_ci } else { 9331cb0ef41Sopenharmony_ci onSocket(); 9341cb0ef41Sopenharmony_ci } 9351cb0ef41Sopenharmony_ci} 9361cb0ef41Sopenharmony_ci 9371cb0ef41Sopenharmony_ciClientRequest.prototype.setTimeout = function setTimeout(msecs, callback) { 9381cb0ef41Sopenharmony_ci if (this._ended) { 9391cb0ef41Sopenharmony_ci return this; 9401cb0ef41Sopenharmony_ci } 9411cb0ef41Sopenharmony_ci 9421cb0ef41Sopenharmony_ci listenSocketTimeout(this); 9431cb0ef41Sopenharmony_ci msecs = getTimerDuration(msecs, 'msecs'); 9441cb0ef41Sopenharmony_ci if (callback) this.once('timeout', callback); 9451cb0ef41Sopenharmony_ci 9461cb0ef41Sopenharmony_ci if (this.socket) { 9471cb0ef41Sopenharmony_ci setSocketTimeout(this.socket, msecs); 9481cb0ef41Sopenharmony_ci } else { 9491cb0ef41Sopenharmony_ci this.once('socket', (sock) => setSocketTimeout(sock, msecs)); 9501cb0ef41Sopenharmony_ci } 9511cb0ef41Sopenharmony_ci 9521cb0ef41Sopenharmony_ci return this; 9531cb0ef41Sopenharmony_ci}; 9541cb0ef41Sopenharmony_ci 9551cb0ef41Sopenharmony_cifunction setSocketTimeout(sock, msecs) { 9561cb0ef41Sopenharmony_ci if (sock.connecting) { 9571cb0ef41Sopenharmony_ci sock.once('connect', function() { 9581cb0ef41Sopenharmony_ci sock.setTimeout(msecs); 9591cb0ef41Sopenharmony_ci }); 9601cb0ef41Sopenharmony_ci } else { 9611cb0ef41Sopenharmony_ci sock.setTimeout(msecs); 9621cb0ef41Sopenharmony_ci } 9631cb0ef41Sopenharmony_ci} 9641cb0ef41Sopenharmony_ci 9651cb0ef41Sopenharmony_ciClientRequest.prototype.setNoDelay = function setNoDelay(noDelay) { 9661cb0ef41Sopenharmony_ci this._deferToConnect('setNoDelay', [noDelay]); 9671cb0ef41Sopenharmony_ci}; 9681cb0ef41Sopenharmony_ci 9691cb0ef41Sopenharmony_ciClientRequest.prototype.setSocketKeepAlive = 9701cb0ef41Sopenharmony_ci function setSocketKeepAlive(enable, initialDelay) { 9711cb0ef41Sopenharmony_ci this._deferToConnect('setKeepAlive', [enable, initialDelay]); 9721cb0ef41Sopenharmony_ci }; 9731cb0ef41Sopenharmony_ci 9741cb0ef41Sopenharmony_ciClientRequest.prototype.clearTimeout = function clearTimeout(cb) { 9751cb0ef41Sopenharmony_ci this.setTimeout(0, cb); 9761cb0ef41Sopenharmony_ci}; 9771cb0ef41Sopenharmony_ci 9781cb0ef41Sopenharmony_cimodule.exports = { 9791cb0ef41Sopenharmony_ci ClientRequest, 9801cb0ef41Sopenharmony_ci}; 981