11cb0ef41Sopenharmony_ci'use strict';
21cb0ef41Sopenharmony_ci
31cb0ef41Sopenharmony_ciconst {
41cb0ef41Sopenharmony_ci  ArrayFrom,
51cb0ef41Sopenharmony_ci  ArrayIsArray,
61cb0ef41Sopenharmony_ci  ArrayPrototypeForEach,
71cb0ef41Sopenharmony_ci  ArrayPrototypePush,
81cb0ef41Sopenharmony_ci  ArrayPrototypeUnshift,
91cb0ef41Sopenharmony_ci  FunctionPrototypeBind,
101cb0ef41Sopenharmony_ci  FunctionPrototypeCall,
111cb0ef41Sopenharmony_ci  MathMin,
121cb0ef41Sopenharmony_ci  ObjectAssign,
131cb0ef41Sopenharmony_ci  ObjectCreate,
141cb0ef41Sopenharmony_ci  ObjectKeys,
151cb0ef41Sopenharmony_ci  ObjectDefineProperty,
161cb0ef41Sopenharmony_ci  ObjectPrototypeHasOwnProperty,
171cb0ef41Sopenharmony_ci  Promise,
181cb0ef41Sopenharmony_ci  PromisePrototypeThen,
191cb0ef41Sopenharmony_ci  Proxy,
201cb0ef41Sopenharmony_ci  ReflectApply,
211cb0ef41Sopenharmony_ci  ReflectGet,
221cb0ef41Sopenharmony_ci  ReflectGetPrototypeOf,
231cb0ef41Sopenharmony_ci  ReflectSet,
241cb0ef41Sopenharmony_ci  RegExpPrototypeExec,
251cb0ef41Sopenharmony_ci  SafeArrayIterator,
261cb0ef41Sopenharmony_ci  SafeMap,
271cb0ef41Sopenharmony_ci  SafeSet,
281cb0ef41Sopenharmony_ci  StringPrototypeSlice,
291cb0ef41Sopenharmony_ci  Symbol,
301cb0ef41Sopenharmony_ci  SymbolDispose,
311cb0ef41Sopenharmony_ci  TypedArrayPrototypeGetLength,
321cb0ef41Sopenharmony_ci  Uint32Array,
331cb0ef41Sopenharmony_ci  Uint8Array,
341cb0ef41Sopenharmony_ci} = primordials;
351cb0ef41Sopenharmony_ci
361cb0ef41Sopenharmony_ciconst {
371cb0ef41Sopenharmony_ci  assertCrypto,
381cb0ef41Sopenharmony_ci  customInspectSymbol: kInspect,
391cb0ef41Sopenharmony_ci  kEmptyObject,
401cb0ef41Sopenharmony_ci  promisify,
411cb0ef41Sopenharmony_ci} = require('internal/util');
421cb0ef41Sopenharmony_ci
431cb0ef41Sopenharmony_ciassertCrypto();
441cb0ef41Sopenharmony_ci
451cb0ef41Sopenharmony_ciconst assert = require('assert');
461cb0ef41Sopenharmony_ciconst EventEmitter = require('events');
471cb0ef41Sopenharmony_ciconst fs = require('fs');
481cb0ef41Sopenharmony_ciconst http = require('http');
491cb0ef41Sopenharmony_ciconst { readUInt16BE, readUInt32BE } = require('internal/buffer');
501cb0ef41Sopenharmony_ciconst { URL } = require('internal/url');
511cb0ef41Sopenharmony_ciconst net = require('net');
521cb0ef41Sopenharmony_ciconst { Duplex } = require('stream');
531cb0ef41Sopenharmony_ciconst tls = require('tls');
541cb0ef41Sopenharmony_ciconst { setImmediate, setTimeout, clearTimeout } = require('timers');
551cb0ef41Sopenharmony_ci
561cb0ef41Sopenharmony_ciconst {
571cb0ef41Sopenharmony_ci  kIncomingMessage,
581cb0ef41Sopenharmony_ci  _checkIsHttpToken: checkIsHttpToken,
591cb0ef41Sopenharmony_ci} = require('_http_common');
601cb0ef41Sopenharmony_ciconst { kServerResponse } = require('_http_server');
611cb0ef41Sopenharmony_ciconst JSStreamSocket = require('internal/js_stream_socket');
621cb0ef41Sopenharmony_ci
631cb0ef41Sopenharmony_ciconst {
641cb0ef41Sopenharmony_ci  defaultTriggerAsyncIdScope,
651cb0ef41Sopenharmony_ci  symbols: {
661cb0ef41Sopenharmony_ci    async_id_symbol,
671cb0ef41Sopenharmony_ci    owner_symbol,
681cb0ef41Sopenharmony_ci  },
691cb0ef41Sopenharmony_ci} = require('internal/async_hooks');
701cb0ef41Sopenharmony_ciconst {
711cb0ef41Sopenharmony_ci  aggregateTwoErrors,
721cb0ef41Sopenharmony_ci  codes: {
731cb0ef41Sopenharmony_ci    ERR_HTTP2_ALTSVC_INVALID_ORIGIN,
741cb0ef41Sopenharmony_ci    ERR_HTTP2_ALTSVC_LENGTH,
751cb0ef41Sopenharmony_ci    ERR_HTTP2_CONNECT_AUTHORITY,
761cb0ef41Sopenharmony_ci    ERR_HTTP2_CONNECT_PATH,
771cb0ef41Sopenharmony_ci    ERR_HTTP2_CONNECT_SCHEME,
781cb0ef41Sopenharmony_ci    ERR_HTTP2_GOAWAY_SESSION,
791cb0ef41Sopenharmony_ci    ERR_HTTP2_HEADERS_AFTER_RESPOND,
801cb0ef41Sopenharmony_ci    ERR_HTTP2_HEADERS_SENT,
811cb0ef41Sopenharmony_ci    ERR_HTTP2_INVALID_INFO_STATUS,
821cb0ef41Sopenharmony_ci    ERR_HTTP2_INVALID_ORIGIN,
831cb0ef41Sopenharmony_ci    ERR_HTTP2_INVALID_PACKED_SETTINGS_LENGTH,
841cb0ef41Sopenharmony_ci    ERR_HTTP2_INVALID_SESSION,
851cb0ef41Sopenharmony_ci    ERR_HTTP2_INVALID_SETTING_VALUE,
861cb0ef41Sopenharmony_ci    ERR_HTTP2_INVALID_STREAM,
871cb0ef41Sopenharmony_ci    ERR_HTTP2_MAX_PENDING_SETTINGS_ACK,
881cb0ef41Sopenharmony_ci    ERR_HTTP2_NESTED_PUSH,
891cb0ef41Sopenharmony_ci    ERR_HTTP2_NO_MEM,
901cb0ef41Sopenharmony_ci    ERR_HTTP2_NO_SOCKET_MANIPULATION,
911cb0ef41Sopenharmony_ci    ERR_HTTP2_ORIGIN_LENGTH,
921cb0ef41Sopenharmony_ci    ERR_HTTP2_OUT_OF_STREAMS,
931cb0ef41Sopenharmony_ci    ERR_HTTP2_PAYLOAD_FORBIDDEN,
941cb0ef41Sopenharmony_ci    ERR_HTTP2_PING_CANCEL,
951cb0ef41Sopenharmony_ci    ERR_HTTP2_PING_LENGTH,
961cb0ef41Sopenharmony_ci    ERR_HTTP2_PUSH_DISABLED,
971cb0ef41Sopenharmony_ci    ERR_HTTP2_SEND_FILE,
981cb0ef41Sopenharmony_ci    ERR_HTTP2_SEND_FILE_NOSEEK,
991cb0ef41Sopenharmony_ci    ERR_HTTP2_SESSION_ERROR,
1001cb0ef41Sopenharmony_ci    ERR_HTTP2_SETTINGS_CANCEL,
1011cb0ef41Sopenharmony_ci    ERR_HTTP2_SOCKET_BOUND,
1021cb0ef41Sopenharmony_ci    ERR_HTTP2_SOCKET_UNBOUND,
1031cb0ef41Sopenharmony_ci    ERR_HTTP2_STATUS_101,
1041cb0ef41Sopenharmony_ci    ERR_HTTP2_STATUS_INVALID,
1051cb0ef41Sopenharmony_ci    ERR_HTTP2_STREAM_CANCEL,
1061cb0ef41Sopenharmony_ci    ERR_HTTP2_STREAM_ERROR,
1071cb0ef41Sopenharmony_ci    ERR_HTTP2_STREAM_SELF_DEPENDENCY,
1081cb0ef41Sopenharmony_ci    ERR_HTTP2_TRAILERS_ALREADY_SENT,
1091cb0ef41Sopenharmony_ci    ERR_HTTP2_TRAILERS_NOT_READY,
1101cb0ef41Sopenharmony_ci    ERR_HTTP2_UNSUPPORTED_PROTOCOL,
1111cb0ef41Sopenharmony_ci    ERR_INVALID_ARG_TYPE,
1121cb0ef41Sopenharmony_ci    ERR_INVALID_ARG_VALUE,
1131cb0ef41Sopenharmony_ci    ERR_INVALID_CHAR,
1141cb0ef41Sopenharmony_ci    ERR_INVALID_HTTP_TOKEN,
1151cb0ef41Sopenharmony_ci    ERR_OUT_OF_RANGE,
1161cb0ef41Sopenharmony_ci    ERR_SOCKET_CLOSED,
1171cb0ef41Sopenharmony_ci  },
1181cb0ef41Sopenharmony_ci  hideStackFrames,
1191cb0ef41Sopenharmony_ci  AbortError,
1201cb0ef41Sopenharmony_ci} = require('internal/errors');
1211cb0ef41Sopenharmony_ciconst {
1221cb0ef41Sopenharmony_ci  isUint32,
1231cb0ef41Sopenharmony_ci  validateAbortSignal,
1241cb0ef41Sopenharmony_ci  validateBuffer,
1251cb0ef41Sopenharmony_ci  validateFunction,
1261cb0ef41Sopenharmony_ci  validateInt32,
1271cb0ef41Sopenharmony_ci  validateInteger,
1281cb0ef41Sopenharmony_ci  validateNumber,
1291cb0ef41Sopenharmony_ci  validateString,
1301cb0ef41Sopenharmony_ci  validateUint32,
1311cb0ef41Sopenharmony_ci} = require('internal/validators');
1321cb0ef41Sopenharmony_ciconst fsPromisesInternal = require('internal/fs/promises');
1331cb0ef41Sopenharmony_ciconst { utcDate } = require('internal/http');
1341cb0ef41Sopenharmony_ciconst {
1351cb0ef41Sopenharmony_ci  Http2ServerRequest,
1361cb0ef41Sopenharmony_ci  Http2ServerResponse,
1371cb0ef41Sopenharmony_ci  onServerStream,
1381cb0ef41Sopenharmony_ci} = require('internal/http2/compat');
1391cb0ef41Sopenharmony_ci
1401cb0ef41Sopenharmony_ciconst {
1411cb0ef41Sopenharmony_ci  assertIsObject,
1421cb0ef41Sopenharmony_ci  assertValidPseudoHeader,
1431cb0ef41Sopenharmony_ci  assertValidPseudoHeaderResponse,
1441cb0ef41Sopenharmony_ci  assertValidPseudoHeaderTrailer,
1451cb0ef41Sopenharmony_ci  assertWithinRange,
1461cb0ef41Sopenharmony_ci  getAuthority,
1471cb0ef41Sopenharmony_ci  getDefaultSettings,
1481cb0ef41Sopenharmony_ci  getSessionState,
1491cb0ef41Sopenharmony_ci  getSettings,
1501cb0ef41Sopenharmony_ci  getStreamState,
1511cb0ef41Sopenharmony_ci  isPayloadMeaningless,
1521cb0ef41Sopenharmony_ci  kSensitiveHeaders,
1531cb0ef41Sopenharmony_ci  kSocket,
1541cb0ef41Sopenharmony_ci  kRequest,
1551cb0ef41Sopenharmony_ci  kProxySocket,
1561cb0ef41Sopenharmony_ci  mapToHeaders,
1571cb0ef41Sopenharmony_ci  NghttpError,
1581cb0ef41Sopenharmony_ci  sessionName,
1591cb0ef41Sopenharmony_ci  toHeaderObject,
1601cb0ef41Sopenharmony_ci  updateOptionsBuffer,
1611cb0ef41Sopenharmony_ci  updateSettingsBuffer,
1621cb0ef41Sopenharmony_ci} = require('internal/http2/util');
1631cb0ef41Sopenharmony_ciconst {
1641cb0ef41Sopenharmony_ci  writeGeneric,
1651cb0ef41Sopenharmony_ci  writevGeneric,
1661cb0ef41Sopenharmony_ci  onStreamRead,
1671cb0ef41Sopenharmony_ci  kAfterAsyncWrite,
1681cb0ef41Sopenharmony_ci  kMaybeDestroy,
1691cb0ef41Sopenharmony_ci  kUpdateTimer,
1701cb0ef41Sopenharmony_ci  kHandle,
1711cb0ef41Sopenharmony_ci  kSession,
1721cb0ef41Sopenharmony_ci  setStreamTimeout,
1731cb0ef41Sopenharmony_ci} = require('internal/stream_base_commons');
1741cb0ef41Sopenharmony_ciconst { kTimeout } = require('internal/timers');
1751cb0ef41Sopenharmony_ciconst { isArrayBufferView } = require('internal/util/types');
1761cb0ef41Sopenharmony_ciconst { format } = require('internal/util/inspect');
1771cb0ef41Sopenharmony_ci
1781cb0ef41Sopenharmony_ciconst { FileHandle } = internalBinding('fs');
1791cb0ef41Sopenharmony_ciconst binding = internalBinding('http2');
1801cb0ef41Sopenharmony_ciconst {
1811cb0ef41Sopenharmony_ci  ShutdownWrap,
1821cb0ef41Sopenharmony_ci  kReadBytesOrError,
1831cb0ef41Sopenharmony_ci  streamBaseState,
1841cb0ef41Sopenharmony_ci} = internalBinding('stream_wrap');
1851cb0ef41Sopenharmony_ciconst { UV_EOF } = internalBinding('uv');
1861cb0ef41Sopenharmony_ci
1871cb0ef41Sopenharmony_ciconst { StreamPipe } = internalBinding('stream_pipe');
1881cb0ef41Sopenharmony_ciconst { _connectionListener: httpConnectionListener } = http;
1891cb0ef41Sopenharmony_cilet debug = require('internal/util/debuglog').debuglog('http2', (fn) => {
1901cb0ef41Sopenharmony_ci  debug = fn;
1911cb0ef41Sopenharmony_ci});
1921cb0ef41Sopenharmony_ciconst debugEnabled = debug.enabled;
1931cb0ef41Sopenharmony_ci
1941cb0ef41Sopenharmony_cifunction debugStream(id, sessionType, message, ...args) {
1951cb0ef41Sopenharmony_ci  if (!debugEnabled) {
1961cb0ef41Sopenharmony_ci    return;
1971cb0ef41Sopenharmony_ci  }
1981cb0ef41Sopenharmony_ci  debug('Http2Stream %s [Http2Session %s]: ' + message,
1991cb0ef41Sopenharmony_ci        id, sessionName(sessionType), ...new SafeArrayIterator(args));
2001cb0ef41Sopenharmony_ci}
2011cb0ef41Sopenharmony_ci
2021cb0ef41Sopenharmony_cifunction debugStreamObj(stream, message, ...args) {
2031cb0ef41Sopenharmony_ci  const session = stream[kSession];
2041cb0ef41Sopenharmony_ci  const type = session ? session[kType] : undefined;
2051cb0ef41Sopenharmony_ci  debugStream(stream[kID], type, message, ...new SafeArrayIterator(args));
2061cb0ef41Sopenharmony_ci}
2071cb0ef41Sopenharmony_ci
2081cb0ef41Sopenharmony_cifunction debugSession(sessionType, message, ...args) {
2091cb0ef41Sopenharmony_ci  debug('Http2Session %s: ' + message, sessionName(sessionType),
2101cb0ef41Sopenharmony_ci        ...new SafeArrayIterator(args));
2111cb0ef41Sopenharmony_ci}
2121cb0ef41Sopenharmony_ci
2131cb0ef41Sopenharmony_cifunction debugSessionObj(session, message, ...args) {
2141cb0ef41Sopenharmony_ci  debugSession(session[kType], message, ...new SafeArrayIterator(args));
2151cb0ef41Sopenharmony_ci}
2161cb0ef41Sopenharmony_ci
2171cb0ef41Sopenharmony_ciconst kMaxFrameSize = (2 ** 24) - 1;
2181cb0ef41Sopenharmony_ciconst kMaxInt = (2 ** 32) - 1;
2191cb0ef41Sopenharmony_ciconst kMaxStreams = (2 ** 32) - 1;
2201cb0ef41Sopenharmony_ciconst kMaxALTSVC = (2 ** 14) - 2;
2211cb0ef41Sopenharmony_ci
2221cb0ef41Sopenharmony_ci// eslint-disable-next-line no-control-regex
2231cb0ef41Sopenharmony_ciconst kQuotedString = /^[\x09\x20-\x5b\x5d-\x7e\x80-\xff]*$/;
2241cb0ef41Sopenharmony_ci
2251cb0ef41Sopenharmony_ciconst { constants, nameForErrorCode } = binding;
2261cb0ef41Sopenharmony_ci
2271cb0ef41Sopenharmony_ciconst NETServer = net.Server;
2281cb0ef41Sopenharmony_ciconst TLSServer = tls.Server;
2291cb0ef41Sopenharmony_ci
2301cb0ef41Sopenharmony_ciconst kAlpnProtocol = Symbol('alpnProtocol');
2311cb0ef41Sopenharmony_ciconst kAuthority = Symbol('authority');
2321cb0ef41Sopenharmony_ciconst kEncrypted = Symbol('encrypted');
2331cb0ef41Sopenharmony_ciconst kID = Symbol('id');
2341cb0ef41Sopenharmony_ciconst kInit = Symbol('init');
2351cb0ef41Sopenharmony_ciconst kInfoHeaders = Symbol('sent-info-headers');
2361cb0ef41Sopenharmony_ciconst kLocalSettings = Symbol('local-settings');
2371cb0ef41Sopenharmony_ciconst kNativeFields = Symbol('kNativeFields');
2381cb0ef41Sopenharmony_ciconst kOptions = Symbol('options');
2391cb0ef41Sopenharmony_ciconst kOwner = owner_symbol;
2401cb0ef41Sopenharmony_ciconst kOrigin = Symbol('origin');
2411cb0ef41Sopenharmony_ciconst kPendingRequestCalls = Symbol('kPendingRequestCalls');
2421cb0ef41Sopenharmony_ciconst kProceed = Symbol('proceed');
2431cb0ef41Sopenharmony_ciconst kProtocol = Symbol('protocol');
2441cb0ef41Sopenharmony_ciconst kRemoteSettings = Symbol('remote-settings');
2451cb0ef41Sopenharmony_ciconst kSelectPadding = Symbol('select-padding');
2461cb0ef41Sopenharmony_ciconst kSentHeaders = Symbol('sent-headers');
2471cb0ef41Sopenharmony_ciconst kSentTrailers = Symbol('sent-trailers');
2481cb0ef41Sopenharmony_ciconst kServer = Symbol('server');
2491cb0ef41Sopenharmony_ciconst kState = Symbol('state');
2501cb0ef41Sopenharmony_ciconst kType = Symbol('type');
2511cb0ef41Sopenharmony_ciconst kWriteGeneric = Symbol('write-generic');
2521cb0ef41Sopenharmony_ci
2531cb0ef41Sopenharmony_ciconst {
2541cb0ef41Sopenharmony_ci  kBitfield,
2551cb0ef41Sopenharmony_ci  kSessionPriorityListenerCount,
2561cb0ef41Sopenharmony_ci  kSessionFrameErrorListenerCount,
2571cb0ef41Sopenharmony_ci  kSessionMaxInvalidFrames,
2581cb0ef41Sopenharmony_ci  kSessionMaxRejectedStreams,
2591cb0ef41Sopenharmony_ci  kSessionUint8FieldCount,
2601cb0ef41Sopenharmony_ci  kSessionHasRemoteSettingsListeners,
2611cb0ef41Sopenharmony_ci  kSessionRemoteSettingsIsUpToDate,
2621cb0ef41Sopenharmony_ci  kSessionHasPingListeners,
2631cb0ef41Sopenharmony_ci  kSessionHasAltsvcListeners,
2641cb0ef41Sopenharmony_ci} = binding;
2651cb0ef41Sopenharmony_ci
2661cb0ef41Sopenharmony_ciconst {
2671cb0ef41Sopenharmony_ci  NGHTTP2_CANCEL,
2681cb0ef41Sopenharmony_ci  NGHTTP2_REFUSED_STREAM,
2691cb0ef41Sopenharmony_ci  NGHTTP2_DEFAULT_WEIGHT,
2701cb0ef41Sopenharmony_ci  NGHTTP2_FLAG_END_STREAM,
2711cb0ef41Sopenharmony_ci  NGHTTP2_HCAT_PUSH_RESPONSE,
2721cb0ef41Sopenharmony_ci  NGHTTP2_HCAT_RESPONSE,
2731cb0ef41Sopenharmony_ci  NGHTTP2_INTERNAL_ERROR,
2741cb0ef41Sopenharmony_ci  NGHTTP2_NO_ERROR,
2751cb0ef41Sopenharmony_ci  NGHTTP2_SESSION_CLIENT,
2761cb0ef41Sopenharmony_ci  NGHTTP2_SESSION_SERVER,
2771cb0ef41Sopenharmony_ci  NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE,
2781cb0ef41Sopenharmony_ci  NGHTTP2_ERR_INVALID_ARGUMENT,
2791cb0ef41Sopenharmony_ci  NGHTTP2_ERR_STREAM_CLOSED,
2801cb0ef41Sopenharmony_ci  NGHTTP2_ERR_NOMEM,
2811cb0ef41Sopenharmony_ci
2821cb0ef41Sopenharmony_ci  HTTP2_HEADER_AUTHORITY,
2831cb0ef41Sopenharmony_ci  HTTP2_HEADER_DATE,
2841cb0ef41Sopenharmony_ci  HTTP2_HEADER_METHOD,
2851cb0ef41Sopenharmony_ci  HTTP2_HEADER_PATH,
2861cb0ef41Sopenharmony_ci  HTTP2_HEADER_PROTOCOL,
2871cb0ef41Sopenharmony_ci  HTTP2_HEADER_SCHEME,
2881cb0ef41Sopenharmony_ci  HTTP2_HEADER_STATUS,
2891cb0ef41Sopenharmony_ci  HTTP2_HEADER_CONTENT_LENGTH,
2901cb0ef41Sopenharmony_ci
2911cb0ef41Sopenharmony_ci  NGHTTP2_SETTINGS_HEADER_TABLE_SIZE,
2921cb0ef41Sopenharmony_ci  NGHTTP2_SETTINGS_ENABLE_PUSH,
2931cb0ef41Sopenharmony_ci  NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS,
2941cb0ef41Sopenharmony_ci  NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE,
2951cb0ef41Sopenharmony_ci  NGHTTP2_SETTINGS_MAX_FRAME_SIZE,
2961cb0ef41Sopenharmony_ci  NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE,
2971cb0ef41Sopenharmony_ci  NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL,
2981cb0ef41Sopenharmony_ci
2991cb0ef41Sopenharmony_ci  HTTP2_METHOD_GET,
3001cb0ef41Sopenharmony_ci  HTTP2_METHOD_HEAD,
3011cb0ef41Sopenharmony_ci  HTTP2_METHOD_CONNECT,
3021cb0ef41Sopenharmony_ci
3031cb0ef41Sopenharmony_ci  HTTP_STATUS_CONTINUE,
3041cb0ef41Sopenharmony_ci  HTTP_STATUS_RESET_CONTENT,
3051cb0ef41Sopenharmony_ci  HTTP_STATUS_OK,
3061cb0ef41Sopenharmony_ci  HTTP_STATUS_NO_CONTENT,
3071cb0ef41Sopenharmony_ci  HTTP_STATUS_NOT_MODIFIED,
3081cb0ef41Sopenharmony_ci  HTTP_STATUS_SWITCHING_PROTOCOLS,
3091cb0ef41Sopenharmony_ci  HTTP_STATUS_MISDIRECTED_REQUEST,
3101cb0ef41Sopenharmony_ci
3111cb0ef41Sopenharmony_ci  STREAM_OPTION_EMPTY_PAYLOAD,
3121cb0ef41Sopenharmony_ci  STREAM_OPTION_GET_TRAILERS,
3131cb0ef41Sopenharmony_ci} = constants;
3141cb0ef41Sopenharmony_ci
3151cb0ef41Sopenharmony_ciconst STREAM_FLAGS_PENDING = 0x0;
3161cb0ef41Sopenharmony_ciconst STREAM_FLAGS_READY = 0x1;
3171cb0ef41Sopenharmony_ciconst STREAM_FLAGS_CLOSED = 0x2;
3181cb0ef41Sopenharmony_ciconst STREAM_FLAGS_HEADERS_SENT = 0x4;
3191cb0ef41Sopenharmony_ciconst STREAM_FLAGS_HEAD_REQUEST = 0x8;
3201cb0ef41Sopenharmony_ciconst STREAM_FLAGS_ABORTED = 0x10;
3211cb0ef41Sopenharmony_ciconst STREAM_FLAGS_HAS_TRAILERS = 0x20;
3221cb0ef41Sopenharmony_ci
3231cb0ef41Sopenharmony_ciconst SESSION_FLAGS_PENDING = 0x0;
3241cb0ef41Sopenharmony_ciconst SESSION_FLAGS_READY = 0x1;
3251cb0ef41Sopenharmony_ciconst SESSION_FLAGS_CLOSED = 0x2;
3261cb0ef41Sopenharmony_ciconst SESSION_FLAGS_DESTROYED = 0x4;
3271cb0ef41Sopenharmony_ci
3281cb0ef41Sopenharmony_ci// Top level to avoid creating a closure
3291cb0ef41Sopenharmony_cifunction emit(self, ...args) {
3301cb0ef41Sopenharmony_ci  ReflectApply(self.emit, self, args);
3311cb0ef41Sopenharmony_ci}
3321cb0ef41Sopenharmony_ci
3331cb0ef41Sopenharmony_ci// Called when a new block of headers has been received for a given
3341cb0ef41Sopenharmony_ci// stream. The stream may or may not be new. If the stream is new,
3351cb0ef41Sopenharmony_ci// create the associated Http2Stream instance and emit the 'stream'
3361cb0ef41Sopenharmony_ci// event. If the stream is not new, emit the 'headers' event to pass
3371cb0ef41Sopenharmony_ci// the block of headers on.
3381cb0ef41Sopenharmony_cifunction onSessionHeaders(handle, id, cat, flags, headers, sensitiveHeaders) {
3391cb0ef41Sopenharmony_ci  const session = this[kOwner];
3401cb0ef41Sopenharmony_ci  if (session.destroyed)
3411cb0ef41Sopenharmony_ci    return;
3421cb0ef41Sopenharmony_ci
3431cb0ef41Sopenharmony_ci  const type = session[kType];
3441cb0ef41Sopenharmony_ci  session[kUpdateTimer]();
3451cb0ef41Sopenharmony_ci  debugStream(id, type, 'headers received');
3461cb0ef41Sopenharmony_ci  const streams = session[kState].streams;
3471cb0ef41Sopenharmony_ci
3481cb0ef41Sopenharmony_ci  const endOfStream = !!(flags & NGHTTP2_FLAG_END_STREAM);
3491cb0ef41Sopenharmony_ci  let stream = streams.get(id);
3501cb0ef41Sopenharmony_ci
3511cb0ef41Sopenharmony_ci  // Convert the array of header name value pairs into an object
3521cb0ef41Sopenharmony_ci  const obj = toHeaderObject(headers, sensitiveHeaders);
3531cb0ef41Sopenharmony_ci
3541cb0ef41Sopenharmony_ci  if (stream === undefined) {
3551cb0ef41Sopenharmony_ci    if (session.closed) {
3561cb0ef41Sopenharmony_ci      // We are not accepting any new streams at this point. This callback
3571cb0ef41Sopenharmony_ci      // should not be invoked at this point in time, but just in case it is,
3581cb0ef41Sopenharmony_ci      // refuse the stream using an RST_STREAM and destroy the handle.
3591cb0ef41Sopenharmony_ci      handle.rstStream(NGHTTP2_REFUSED_STREAM);
3601cb0ef41Sopenharmony_ci      handle.destroy();
3611cb0ef41Sopenharmony_ci      return;
3621cb0ef41Sopenharmony_ci    }
3631cb0ef41Sopenharmony_ci    // session[kType] can be only one of two possible values
3641cb0ef41Sopenharmony_ci    if (type === NGHTTP2_SESSION_SERVER) {
3651cb0ef41Sopenharmony_ci      // eslint-disable-next-line no-use-before-define
3661cb0ef41Sopenharmony_ci      stream = new ServerHttp2Stream(session, handle, id, {}, obj);
3671cb0ef41Sopenharmony_ci      if (endOfStream) {
3681cb0ef41Sopenharmony_ci        stream.push(null);
3691cb0ef41Sopenharmony_ci      }
3701cb0ef41Sopenharmony_ci      if (obj[HTTP2_HEADER_METHOD] === HTTP2_METHOD_HEAD) {
3711cb0ef41Sopenharmony_ci        // For head requests, there must not be a body...
3721cb0ef41Sopenharmony_ci        // end the writable side immediately.
3731cb0ef41Sopenharmony_ci        stream.end();
3741cb0ef41Sopenharmony_ci        stream[kState].flags |= STREAM_FLAGS_HEAD_REQUEST;
3751cb0ef41Sopenharmony_ci      }
3761cb0ef41Sopenharmony_ci    } else {
3771cb0ef41Sopenharmony_ci      // eslint-disable-next-line no-use-before-define
3781cb0ef41Sopenharmony_ci      stream = new ClientHttp2Stream(session, handle, id, {});
3791cb0ef41Sopenharmony_ci      if (endOfStream) {
3801cb0ef41Sopenharmony_ci        stream.push(null);
3811cb0ef41Sopenharmony_ci      }
3821cb0ef41Sopenharmony_ci      stream.end();
3831cb0ef41Sopenharmony_ci    }
3841cb0ef41Sopenharmony_ci    if (endOfStream)
3851cb0ef41Sopenharmony_ci      stream[kState].endAfterHeaders = true;
3861cb0ef41Sopenharmony_ci    process.nextTick(emit, session, 'stream', stream, obj, flags, headers);
3871cb0ef41Sopenharmony_ci  } else {
3881cb0ef41Sopenharmony_ci    let event;
3891cb0ef41Sopenharmony_ci    const status = obj[HTTP2_HEADER_STATUS];
3901cb0ef41Sopenharmony_ci    if (cat === NGHTTP2_HCAT_RESPONSE) {
3911cb0ef41Sopenharmony_ci      if (!endOfStream &&
3921cb0ef41Sopenharmony_ci          status !== undefined &&
3931cb0ef41Sopenharmony_ci          status >= 100 &&
3941cb0ef41Sopenharmony_ci          status < 200) {
3951cb0ef41Sopenharmony_ci        event = 'headers';
3961cb0ef41Sopenharmony_ci      } else {
3971cb0ef41Sopenharmony_ci        event = 'response';
3981cb0ef41Sopenharmony_ci      }
3991cb0ef41Sopenharmony_ci    } else if (cat === NGHTTP2_HCAT_PUSH_RESPONSE) {
4001cb0ef41Sopenharmony_ci      event = 'push';
4011cb0ef41Sopenharmony_ci    } else if (status !== undefined && status >= 200) {
4021cb0ef41Sopenharmony_ci      event = 'response';
4031cb0ef41Sopenharmony_ci    } else {
4041cb0ef41Sopenharmony_ci      event = endOfStream ? 'trailers' : 'headers';
4051cb0ef41Sopenharmony_ci    }
4061cb0ef41Sopenharmony_ci    const session = stream.session;
4071cb0ef41Sopenharmony_ci    if (status === HTTP_STATUS_MISDIRECTED_REQUEST) {
4081cb0ef41Sopenharmony_ci      const originSet = session[kState].originSet = initOriginSet(session);
4091cb0ef41Sopenharmony_ci      originSet.delete(stream[kOrigin]);
4101cb0ef41Sopenharmony_ci    }
4111cb0ef41Sopenharmony_ci    debugStream(id, type, "emitting stream '%s' event", event);
4121cb0ef41Sopenharmony_ci    process.nextTick(emit, stream, event, obj, flags, headers);
4131cb0ef41Sopenharmony_ci  }
4141cb0ef41Sopenharmony_ci  if (endOfStream) {
4151cb0ef41Sopenharmony_ci    stream.push(null);
4161cb0ef41Sopenharmony_ci  }
4171cb0ef41Sopenharmony_ci}
4181cb0ef41Sopenharmony_ci
4191cb0ef41Sopenharmony_cifunction tryClose(fd) {
4201cb0ef41Sopenharmony_ci  // Try to close the file descriptor. If closing fails, assert because
4211cb0ef41Sopenharmony_ci  // an error really should not happen at this point.
4221cb0ef41Sopenharmony_ci  fs.close(fd, assert.ifError);
4231cb0ef41Sopenharmony_ci}
4241cb0ef41Sopenharmony_ci
4251cb0ef41Sopenharmony_ci// Called when the Http2Stream has finished sending data and is ready for
4261cb0ef41Sopenharmony_ci// trailers to be sent. This will only be called if the { hasOptions: true }
4271cb0ef41Sopenharmony_ci// option is set.
4281cb0ef41Sopenharmony_cifunction onStreamTrailers() {
4291cb0ef41Sopenharmony_ci  const stream = this[kOwner];
4301cb0ef41Sopenharmony_ci  stream[kState].trailersReady = true;
4311cb0ef41Sopenharmony_ci  if (stream.destroyed || stream.closed)
4321cb0ef41Sopenharmony_ci    return;
4331cb0ef41Sopenharmony_ci  if (!stream.emit('wantTrailers')) {
4341cb0ef41Sopenharmony_ci    // There are no listeners, send empty trailing HEADERS frame and close.
4351cb0ef41Sopenharmony_ci    stream.sendTrailers({});
4361cb0ef41Sopenharmony_ci  }
4371cb0ef41Sopenharmony_ci}
4381cb0ef41Sopenharmony_ci
4391cb0ef41Sopenharmony_ci// Submit an RST-STREAM frame to be sent to the remote peer.
4401cb0ef41Sopenharmony_ci// This will cause the Http2Stream to be closed.
4411cb0ef41Sopenharmony_cifunction submitRstStream(code) {
4421cb0ef41Sopenharmony_ci  if (this[kHandle] !== undefined) {
4431cb0ef41Sopenharmony_ci    this[kHandle].rstStream(code);
4441cb0ef41Sopenharmony_ci  }
4451cb0ef41Sopenharmony_ci}
4461cb0ef41Sopenharmony_ci
4471cb0ef41Sopenharmony_ci// Keep track of the number/presence of JS event listeners. Knowing that there
4481cb0ef41Sopenharmony_ci// are no listeners allows the C++ code to skip calling into JS for an event.
4491cb0ef41Sopenharmony_cifunction sessionListenerAdded(name) {
4501cb0ef41Sopenharmony_ci  switch (name) {
4511cb0ef41Sopenharmony_ci    case 'ping':
4521cb0ef41Sopenharmony_ci      this[kNativeFields][kBitfield] |= 1 << kSessionHasPingListeners;
4531cb0ef41Sopenharmony_ci      break;
4541cb0ef41Sopenharmony_ci    case 'altsvc':
4551cb0ef41Sopenharmony_ci      this[kNativeFields][kBitfield] |= 1 << kSessionHasAltsvcListeners;
4561cb0ef41Sopenharmony_ci      break;
4571cb0ef41Sopenharmony_ci    case 'remoteSettings':
4581cb0ef41Sopenharmony_ci      this[kNativeFields][kBitfield] |= 1 << kSessionHasRemoteSettingsListeners;
4591cb0ef41Sopenharmony_ci      break;
4601cb0ef41Sopenharmony_ci    case 'priority':
4611cb0ef41Sopenharmony_ci      this[kNativeFields][kSessionPriorityListenerCount]++;
4621cb0ef41Sopenharmony_ci      break;
4631cb0ef41Sopenharmony_ci    case 'frameError':
4641cb0ef41Sopenharmony_ci      this[kNativeFields][kSessionFrameErrorListenerCount]++;
4651cb0ef41Sopenharmony_ci      break;
4661cb0ef41Sopenharmony_ci  }
4671cb0ef41Sopenharmony_ci}
4681cb0ef41Sopenharmony_ci
4691cb0ef41Sopenharmony_cifunction sessionListenerRemoved(name) {
4701cb0ef41Sopenharmony_ci  switch (name) {
4711cb0ef41Sopenharmony_ci    case 'ping':
4721cb0ef41Sopenharmony_ci      if (this.listenerCount(name) > 0) return;
4731cb0ef41Sopenharmony_ci      this[kNativeFields][kBitfield] &= ~(1 << kSessionHasPingListeners);
4741cb0ef41Sopenharmony_ci      break;
4751cb0ef41Sopenharmony_ci    case 'altsvc':
4761cb0ef41Sopenharmony_ci      if (this.listenerCount(name) > 0) return;
4771cb0ef41Sopenharmony_ci      this[kNativeFields][kBitfield] &= ~(1 << kSessionHasAltsvcListeners);
4781cb0ef41Sopenharmony_ci      break;
4791cb0ef41Sopenharmony_ci    case 'remoteSettings':
4801cb0ef41Sopenharmony_ci      if (this.listenerCount(name) > 0) return;
4811cb0ef41Sopenharmony_ci      this[kNativeFields][kBitfield] &=
4821cb0ef41Sopenharmony_ci          ~(1 << kSessionHasRemoteSettingsListeners);
4831cb0ef41Sopenharmony_ci      break;
4841cb0ef41Sopenharmony_ci    case 'priority':
4851cb0ef41Sopenharmony_ci      this[kNativeFields][kSessionPriorityListenerCount]--;
4861cb0ef41Sopenharmony_ci      break;
4871cb0ef41Sopenharmony_ci    case 'frameError':
4881cb0ef41Sopenharmony_ci      this[kNativeFields][kSessionFrameErrorListenerCount]--;
4891cb0ef41Sopenharmony_ci      break;
4901cb0ef41Sopenharmony_ci  }
4911cb0ef41Sopenharmony_ci}
4921cb0ef41Sopenharmony_ci
4931cb0ef41Sopenharmony_ci// Also keep track of listeners for the Http2Stream instances, as some events
4941cb0ef41Sopenharmony_ci// are emitted on those objects.
4951cb0ef41Sopenharmony_cifunction streamListenerAdded(name) {
4961cb0ef41Sopenharmony_ci  const session = this[kSession];
4971cb0ef41Sopenharmony_ci  if (!session) return;
4981cb0ef41Sopenharmony_ci  switch (name) {
4991cb0ef41Sopenharmony_ci    case 'priority':
5001cb0ef41Sopenharmony_ci      session[kNativeFields][kSessionPriorityListenerCount]++;
5011cb0ef41Sopenharmony_ci      break;
5021cb0ef41Sopenharmony_ci    case 'frameError':
5031cb0ef41Sopenharmony_ci      session[kNativeFields][kSessionFrameErrorListenerCount]++;
5041cb0ef41Sopenharmony_ci      break;
5051cb0ef41Sopenharmony_ci  }
5061cb0ef41Sopenharmony_ci}
5071cb0ef41Sopenharmony_ci
5081cb0ef41Sopenharmony_cifunction streamListenerRemoved(name) {
5091cb0ef41Sopenharmony_ci  const session = this[kSession];
5101cb0ef41Sopenharmony_ci  if (!session) return;
5111cb0ef41Sopenharmony_ci  switch (name) {
5121cb0ef41Sopenharmony_ci    case 'priority':
5131cb0ef41Sopenharmony_ci      session[kNativeFields][kSessionPriorityListenerCount]--;
5141cb0ef41Sopenharmony_ci      break;
5151cb0ef41Sopenharmony_ci    case 'frameError':
5161cb0ef41Sopenharmony_ci      session[kNativeFields][kSessionFrameErrorListenerCount]--;
5171cb0ef41Sopenharmony_ci      break;
5181cb0ef41Sopenharmony_ci  }
5191cb0ef41Sopenharmony_ci}
5201cb0ef41Sopenharmony_ci
5211cb0ef41Sopenharmony_cifunction onPing(payload) {
5221cb0ef41Sopenharmony_ci  const session = this[kOwner];
5231cb0ef41Sopenharmony_ci  if (session.destroyed)
5241cb0ef41Sopenharmony_ci    return;
5251cb0ef41Sopenharmony_ci  session[kUpdateTimer]();
5261cb0ef41Sopenharmony_ci  debugSessionObj(session, 'new ping received');
5271cb0ef41Sopenharmony_ci  session.emit('ping', payload);
5281cb0ef41Sopenharmony_ci}
5291cb0ef41Sopenharmony_ci
5301cb0ef41Sopenharmony_ci// Called when the stream is closed either by sending or receiving an
5311cb0ef41Sopenharmony_ci// RST_STREAM frame, or through a natural end-of-stream.
5321cb0ef41Sopenharmony_ci// If the writable and readable sides of the stream are still open at this
5331cb0ef41Sopenharmony_ci// point, close them. If there is an open fd for file send, close that also.
5341cb0ef41Sopenharmony_ci// At this point the underlying node::http2:Http2Stream handle is no
5351cb0ef41Sopenharmony_ci// longer usable so destroy it also.
5361cb0ef41Sopenharmony_cifunction onStreamClose(code) {
5371cb0ef41Sopenharmony_ci  const stream = this[kOwner];
5381cb0ef41Sopenharmony_ci  if (!stream || stream.destroyed)
5391cb0ef41Sopenharmony_ci    return false;
5401cb0ef41Sopenharmony_ci
5411cb0ef41Sopenharmony_ci  debugStreamObj(
5421cb0ef41Sopenharmony_ci    stream, 'closed with code %d, closed %s, readable %s',
5431cb0ef41Sopenharmony_ci    code, stream.closed, stream.readable,
5441cb0ef41Sopenharmony_ci  );
5451cb0ef41Sopenharmony_ci
5461cb0ef41Sopenharmony_ci  if (!stream.closed)
5471cb0ef41Sopenharmony_ci    closeStream(stream, code, kNoRstStream);
5481cb0ef41Sopenharmony_ci
5491cb0ef41Sopenharmony_ci  stream[kState].fd = -1;
5501cb0ef41Sopenharmony_ci  // Defer destroy we actually emit end.
5511cb0ef41Sopenharmony_ci  if (!stream.readable || code !== NGHTTP2_NO_ERROR) {
5521cb0ef41Sopenharmony_ci    // If errored or ended, we can destroy immediately.
5531cb0ef41Sopenharmony_ci    stream.destroy();
5541cb0ef41Sopenharmony_ci  } else {
5551cb0ef41Sopenharmony_ci    // Wait for end to destroy.
5561cb0ef41Sopenharmony_ci    stream.on('end', stream[kMaybeDestroy]);
5571cb0ef41Sopenharmony_ci    // Push a null so the stream can end whenever the client consumes
5581cb0ef41Sopenharmony_ci    // it completely.
5591cb0ef41Sopenharmony_ci    stream.push(null);
5601cb0ef41Sopenharmony_ci
5611cb0ef41Sopenharmony_ci    // If the user hasn't tried to consume the stream (and this is a server
5621cb0ef41Sopenharmony_ci    // session) then just dump the incoming data so that the stream can
5631cb0ef41Sopenharmony_ci    // be destroyed.
5641cb0ef41Sopenharmony_ci    if (stream[kSession][kType] === NGHTTP2_SESSION_SERVER &&
5651cb0ef41Sopenharmony_ci        !stream[kState].didRead &&
5661cb0ef41Sopenharmony_ci        stream.readableFlowing === null)
5671cb0ef41Sopenharmony_ci      stream.resume();
5681cb0ef41Sopenharmony_ci    else
5691cb0ef41Sopenharmony_ci      stream.read(0);
5701cb0ef41Sopenharmony_ci  }
5711cb0ef41Sopenharmony_ci  return true;
5721cb0ef41Sopenharmony_ci}
5731cb0ef41Sopenharmony_ci
5741cb0ef41Sopenharmony_ci// Called when the remote peer settings have been updated.
5751cb0ef41Sopenharmony_ci// Resets the cached settings.
5761cb0ef41Sopenharmony_cifunction onSettings() {
5771cb0ef41Sopenharmony_ci  const session = this[kOwner];
5781cb0ef41Sopenharmony_ci  if (session.destroyed)
5791cb0ef41Sopenharmony_ci    return;
5801cb0ef41Sopenharmony_ci  session[kUpdateTimer]();
5811cb0ef41Sopenharmony_ci  debugSessionObj(session, 'new settings received');
5821cb0ef41Sopenharmony_ci  session[kRemoteSettings] = undefined;
5831cb0ef41Sopenharmony_ci  session.emit('remoteSettings', session.remoteSettings);
5841cb0ef41Sopenharmony_ci}
5851cb0ef41Sopenharmony_ci
5861cb0ef41Sopenharmony_ci// If the stream exists, an attempt will be made to emit an event
5871cb0ef41Sopenharmony_ci// on the stream object itself. Otherwise, forward it on to the
5881cb0ef41Sopenharmony_ci// session (which may, in turn, forward it on to the server)
5891cb0ef41Sopenharmony_cifunction onPriority(id, parent, weight, exclusive) {
5901cb0ef41Sopenharmony_ci  const session = this[kOwner];
5911cb0ef41Sopenharmony_ci  if (session.destroyed)
5921cb0ef41Sopenharmony_ci    return;
5931cb0ef41Sopenharmony_ci  debugStream(id, session[kType],
5941cb0ef41Sopenharmony_ci              'priority [parent: %d, weight: %d, exclusive: %s]',
5951cb0ef41Sopenharmony_ci              parent, weight, exclusive);
5961cb0ef41Sopenharmony_ci  const emitter = session[kState].streams.get(id) || session;
5971cb0ef41Sopenharmony_ci  if (!emitter.destroyed) {
5981cb0ef41Sopenharmony_ci    emitter[kUpdateTimer]();
5991cb0ef41Sopenharmony_ci    emitter.emit('priority', id, parent, weight, exclusive);
6001cb0ef41Sopenharmony_ci  }
6011cb0ef41Sopenharmony_ci}
6021cb0ef41Sopenharmony_ci
6031cb0ef41Sopenharmony_ci// Called by the native layer when an error has occurred sending a
6041cb0ef41Sopenharmony_ci// frame. This should be exceedingly rare.
6051cb0ef41Sopenharmony_cifunction onFrameError(id, type, code) {
6061cb0ef41Sopenharmony_ci  const session = this[kOwner];
6071cb0ef41Sopenharmony_ci  if (session.destroyed)
6081cb0ef41Sopenharmony_ci    return;
6091cb0ef41Sopenharmony_ci  debugSessionObj(session, 'error sending frame type %d on stream %d, code: %d',
6101cb0ef41Sopenharmony_ci                  type, id, code);
6111cb0ef41Sopenharmony_ci  const emitter = session[kState].streams.get(id) || session;
6121cb0ef41Sopenharmony_ci  emitter[kUpdateTimer]();
6131cb0ef41Sopenharmony_ci  emitter.emit('frameError', type, code, id);
6141cb0ef41Sopenharmony_ci  session[kState].streams.get(id).close(code);
6151cb0ef41Sopenharmony_ci  session.close();
6161cb0ef41Sopenharmony_ci}
6171cb0ef41Sopenharmony_ci
6181cb0ef41Sopenharmony_cifunction onAltSvc(stream, origin, alt) {
6191cb0ef41Sopenharmony_ci  const session = this[kOwner];
6201cb0ef41Sopenharmony_ci  if (session.destroyed)
6211cb0ef41Sopenharmony_ci    return;
6221cb0ef41Sopenharmony_ci  debugSessionObj(session, 'altsvc received: stream: %d, origin: %s, alt: %s',
6231cb0ef41Sopenharmony_ci                  stream, origin, alt);
6241cb0ef41Sopenharmony_ci  session[kUpdateTimer]();
6251cb0ef41Sopenharmony_ci  session.emit('altsvc', alt, origin, stream);
6261cb0ef41Sopenharmony_ci}
6271cb0ef41Sopenharmony_ci
6281cb0ef41Sopenharmony_cifunction initOriginSet(session) {
6291cb0ef41Sopenharmony_ci  let originSet = session[kState].originSet;
6301cb0ef41Sopenharmony_ci  if (originSet === undefined) {
6311cb0ef41Sopenharmony_ci    const socket = session[kSocket];
6321cb0ef41Sopenharmony_ci    session[kState].originSet = originSet = new SafeSet();
6331cb0ef41Sopenharmony_ci    if (socket.servername != null) {
6341cb0ef41Sopenharmony_ci      let originString = `https://${socket.servername}`;
6351cb0ef41Sopenharmony_ci      if (socket.remotePort != null)
6361cb0ef41Sopenharmony_ci        originString += `:${socket.remotePort}`;
6371cb0ef41Sopenharmony_ci      // We have to ensure that it is a properly serialized
6381cb0ef41Sopenharmony_ci      // ASCII origin string. The socket.servername might not
6391cb0ef41Sopenharmony_ci      // be properly ASCII encoded.
6401cb0ef41Sopenharmony_ci      originSet.add((new URL(originString)).origin);
6411cb0ef41Sopenharmony_ci    }
6421cb0ef41Sopenharmony_ci  }
6431cb0ef41Sopenharmony_ci  return originSet;
6441cb0ef41Sopenharmony_ci}
6451cb0ef41Sopenharmony_ci
6461cb0ef41Sopenharmony_cifunction onOrigin(origins) {
6471cb0ef41Sopenharmony_ci  const session = this[kOwner];
6481cb0ef41Sopenharmony_ci  if (session.destroyed)
6491cb0ef41Sopenharmony_ci    return;
6501cb0ef41Sopenharmony_ci  debugSessionObj(session, 'origin received: %j', origins);
6511cb0ef41Sopenharmony_ci  session[kUpdateTimer]();
6521cb0ef41Sopenharmony_ci  if (!session.encrypted || session.destroyed)
6531cb0ef41Sopenharmony_ci    return undefined;
6541cb0ef41Sopenharmony_ci  const originSet = initOriginSet(session);
6551cb0ef41Sopenharmony_ci  for (let n = 0; n < origins.length; n++)
6561cb0ef41Sopenharmony_ci    originSet.add(origins[n]);
6571cb0ef41Sopenharmony_ci  session.emit('origin', origins);
6581cb0ef41Sopenharmony_ci}
6591cb0ef41Sopenharmony_ci
6601cb0ef41Sopenharmony_ci// Receiving a GOAWAY frame from the connected peer is a signal that no
6611cb0ef41Sopenharmony_ci// new streams should be created. If the code === NGHTTP2_NO_ERROR, we
6621cb0ef41Sopenharmony_ci// are going to send our close, but allow existing frames to close
6631cb0ef41Sopenharmony_ci// normally. If code !== NGHTTP2_NO_ERROR, we are going to send our own
6641cb0ef41Sopenharmony_ci// close using the same code then destroy the session with an error.
6651cb0ef41Sopenharmony_ci// The goaway event will be emitted on next tick.
6661cb0ef41Sopenharmony_cifunction onGoawayData(code, lastStreamID, buf) {
6671cb0ef41Sopenharmony_ci  const session = this[kOwner];
6681cb0ef41Sopenharmony_ci  if (session.destroyed)
6691cb0ef41Sopenharmony_ci    return;
6701cb0ef41Sopenharmony_ci  debugSessionObj(session, 'goaway %d received [last stream id: %d]',
6711cb0ef41Sopenharmony_ci                  code, lastStreamID);
6721cb0ef41Sopenharmony_ci
6731cb0ef41Sopenharmony_ci  const state = session[kState];
6741cb0ef41Sopenharmony_ci  state.goawayCode = code;
6751cb0ef41Sopenharmony_ci  state.goawayLastStreamID = lastStreamID;
6761cb0ef41Sopenharmony_ci
6771cb0ef41Sopenharmony_ci  session.emit('goaway', code, lastStreamID, buf);
6781cb0ef41Sopenharmony_ci  if (code === NGHTTP2_NO_ERROR) {
6791cb0ef41Sopenharmony_ci    // If this is a no error goaway, begin shutting down.
6801cb0ef41Sopenharmony_ci    // No new streams permitted, but existing streams may
6811cb0ef41Sopenharmony_ci    // close naturally on their own.
6821cb0ef41Sopenharmony_ci    session.close();
6831cb0ef41Sopenharmony_ci  } else {
6841cb0ef41Sopenharmony_ci    // However, if the code is not NGHTTP_NO_ERROR, destroy the
6851cb0ef41Sopenharmony_ci    // session immediately. We destroy with an error but send a
6861cb0ef41Sopenharmony_ci    // goaway using NGHTTP2_NO_ERROR because there was no error
6871cb0ef41Sopenharmony_ci    // condition on this side of the session that caused the
6881cb0ef41Sopenharmony_ci    // shutdown.
6891cb0ef41Sopenharmony_ci    session.destroy(new ERR_HTTP2_SESSION_ERROR(code), NGHTTP2_NO_ERROR);
6901cb0ef41Sopenharmony_ci  }
6911cb0ef41Sopenharmony_ci}
6921cb0ef41Sopenharmony_ci
6931cb0ef41Sopenharmony_ci// When a ClientHttp2Session is first created, the socket may not yet be
6941cb0ef41Sopenharmony_ci// connected. If request() is called during this time, the actual request
6951cb0ef41Sopenharmony_ci// will be deferred until the socket is ready to go.
6961cb0ef41Sopenharmony_cifunction requestOnConnect(headers, options) {
6971cb0ef41Sopenharmony_ci  const session = this[kSession];
6981cb0ef41Sopenharmony_ci
6991cb0ef41Sopenharmony_ci  // At this point, the stream should have already been destroyed during
7001cb0ef41Sopenharmony_ci  // the session.destroy() method. Do nothing else.
7011cb0ef41Sopenharmony_ci  if (session === undefined || session.destroyed)
7021cb0ef41Sopenharmony_ci    return;
7031cb0ef41Sopenharmony_ci
7041cb0ef41Sopenharmony_ci  // If the session was closed while waiting for the connect, destroy
7051cb0ef41Sopenharmony_ci  // the stream and do not continue with the request.
7061cb0ef41Sopenharmony_ci  if (session.closed) {
7071cb0ef41Sopenharmony_ci    const err = new ERR_HTTP2_GOAWAY_SESSION();
7081cb0ef41Sopenharmony_ci    this.destroy(err);
7091cb0ef41Sopenharmony_ci    return;
7101cb0ef41Sopenharmony_ci  }
7111cb0ef41Sopenharmony_ci
7121cb0ef41Sopenharmony_ci  debugSessionObj(session, 'connected, initializing request');
7131cb0ef41Sopenharmony_ci
7141cb0ef41Sopenharmony_ci  let streamOptions = 0;
7151cb0ef41Sopenharmony_ci  if (options.endStream)
7161cb0ef41Sopenharmony_ci    streamOptions |= STREAM_OPTION_EMPTY_PAYLOAD;
7171cb0ef41Sopenharmony_ci
7181cb0ef41Sopenharmony_ci  if (options.waitForTrailers)
7191cb0ef41Sopenharmony_ci    streamOptions |= STREAM_OPTION_GET_TRAILERS;
7201cb0ef41Sopenharmony_ci
7211cb0ef41Sopenharmony_ci  // `ret` will be either the reserved stream ID (if positive)
7221cb0ef41Sopenharmony_ci  // or an error code (if negative)
7231cb0ef41Sopenharmony_ci  const ret = session[kHandle].request(headers,
7241cb0ef41Sopenharmony_ci                                       streamOptions,
7251cb0ef41Sopenharmony_ci                                       options.parent | 0,
7261cb0ef41Sopenharmony_ci                                       options.weight | 0,
7271cb0ef41Sopenharmony_ci                                       !!options.exclusive);
7281cb0ef41Sopenharmony_ci
7291cb0ef41Sopenharmony_ci  // In an error condition, one of three possible response codes will be
7301cb0ef41Sopenharmony_ci  // possible:
7311cb0ef41Sopenharmony_ci  // * NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE - Maximum stream ID is reached, this
7321cb0ef41Sopenharmony_ci  //   is fatal for the session
7331cb0ef41Sopenharmony_ci  // * NGHTTP2_ERR_INVALID_ARGUMENT - Stream was made dependent on itself, this
7341cb0ef41Sopenharmony_ci  //   impacts on this stream.
7351cb0ef41Sopenharmony_ci  // For the first two, emit the error on the session,
7361cb0ef41Sopenharmony_ci  // For the third, emit the error on the stream, it will bubble up to the
7371cb0ef41Sopenharmony_ci  // session if not handled.
7381cb0ef41Sopenharmony_ci  if (typeof ret === 'number') {
7391cb0ef41Sopenharmony_ci    let err;
7401cb0ef41Sopenharmony_ci    switch (ret) {
7411cb0ef41Sopenharmony_ci      case NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE:
7421cb0ef41Sopenharmony_ci        err = new ERR_HTTP2_OUT_OF_STREAMS();
7431cb0ef41Sopenharmony_ci        this.destroy(err);
7441cb0ef41Sopenharmony_ci        break;
7451cb0ef41Sopenharmony_ci      case NGHTTP2_ERR_INVALID_ARGUMENT:
7461cb0ef41Sopenharmony_ci        err = new ERR_HTTP2_STREAM_SELF_DEPENDENCY();
7471cb0ef41Sopenharmony_ci        this.destroy(err);
7481cb0ef41Sopenharmony_ci        break;
7491cb0ef41Sopenharmony_ci      default:
7501cb0ef41Sopenharmony_ci        session.destroy(new NghttpError(ret));
7511cb0ef41Sopenharmony_ci    }
7521cb0ef41Sopenharmony_ci    return;
7531cb0ef41Sopenharmony_ci  }
7541cb0ef41Sopenharmony_ci  this[kInit](ret.id(), ret);
7551cb0ef41Sopenharmony_ci}
7561cb0ef41Sopenharmony_ci
7571cb0ef41Sopenharmony_ci// Validates that priority options are correct, specifically:
7581cb0ef41Sopenharmony_ci// 1. options.weight must be a number
7591cb0ef41Sopenharmony_ci// 2. options.parent must be a positive number
7601cb0ef41Sopenharmony_ci// 3. options.exclusive must be a boolean
7611cb0ef41Sopenharmony_ci// 4. if specified, options.silent must be a boolean
7621cb0ef41Sopenharmony_ci//
7631cb0ef41Sopenharmony_ci// Also sets the default priority options if they are not set.
7641cb0ef41Sopenharmony_ciconst setAndValidatePriorityOptions = hideStackFrames((options) => {
7651cb0ef41Sopenharmony_ci  if (options.weight === undefined) {
7661cb0ef41Sopenharmony_ci    options.weight = NGHTTP2_DEFAULT_WEIGHT;
7671cb0ef41Sopenharmony_ci  } else if (typeof options.weight !== 'number') {
7681cb0ef41Sopenharmony_ci    throw new ERR_INVALID_ARG_VALUE('options.weight', options.weight);
7691cb0ef41Sopenharmony_ci  }
7701cb0ef41Sopenharmony_ci
7711cb0ef41Sopenharmony_ci  if (options.parent === undefined) {
7721cb0ef41Sopenharmony_ci    options.parent = 0;
7731cb0ef41Sopenharmony_ci  } else if (typeof options.parent !== 'number' || options.parent < 0) {
7741cb0ef41Sopenharmony_ci    throw new ERR_INVALID_ARG_VALUE('options.parent', options.parent);
7751cb0ef41Sopenharmony_ci  }
7761cb0ef41Sopenharmony_ci
7771cb0ef41Sopenharmony_ci  if (options.exclusive === undefined) {
7781cb0ef41Sopenharmony_ci    options.exclusive = false;
7791cb0ef41Sopenharmony_ci  } else if (typeof options.exclusive !== 'boolean') {
7801cb0ef41Sopenharmony_ci    throw new ERR_INVALID_ARG_VALUE('options.exclusive', options.exclusive);
7811cb0ef41Sopenharmony_ci  }
7821cb0ef41Sopenharmony_ci
7831cb0ef41Sopenharmony_ci  if (options.silent === undefined) {
7841cb0ef41Sopenharmony_ci    options.silent = false;
7851cb0ef41Sopenharmony_ci  } else if (typeof options.silent !== 'boolean') {
7861cb0ef41Sopenharmony_ci    throw new ERR_INVALID_ARG_VALUE('options.silent', options.silent);
7871cb0ef41Sopenharmony_ci  }
7881cb0ef41Sopenharmony_ci});
7891cb0ef41Sopenharmony_ci
7901cb0ef41Sopenharmony_ci// When an error occurs internally at the binding level, immediately
7911cb0ef41Sopenharmony_ci// destroy the session.
7921cb0ef41Sopenharmony_cifunction onSessionInternalError(integerCode, customErrorCode) {
7931cb0ef41Sopenharmony_ci  if (this[kOwner] !== undefined)
7941cb0ef41Sopenharmony_ci    this[kOwner].destroy(new NghttpError(integerCode, customErrorCode));
7951cb0ef41Sopenharmony_ci}
7961cb0ef41Sopenharmony_ci
7971cb0ef41Sopenharmony_cifunction settingsCallback(cb, ack, duration) {
7981cb0ef41Sopenharmony_ci  this[kState].pendingAck--;
7991cb0ef41Sopenharmony_ci  this[kLocalSettings] = undefined;
8001cb0ef41Sopenharmony_ci  if (ack) {
8011cb0ef41Sopenharmony_ci    debugSessionObj(this, 'settings received');
8021cb0ef41Sopenharmony_ci    const settings = this.localSettings;
8031cb0ef41Sopenharmony_ci    if (typeof cb === 'function')
8041cb0ef41Sopenharmony_ci      cb(null, settings, duration);
8051cb0ef41Sopenharmony_ci    this.emit('localSettings', settings);
8061cb0ef41Sopenharmony_ci  } else {
8071cb0ef41Sopenharmony_ci    debugSessionObj(this, 'settings canceled');
8081cb0ef41Sopenharmony_ci    if (typeof cb === 'function')
8091cb0ef41Sopenharmony_ci      cb(new ERR_HTTP2_SETTINGS_CANCEL());
8101cb0ef41Sopenharmony_ci  }
8111cb0ef41Sopenharmony_ci}
8121cb0ef41Sopenharmony_ci
8131cb0ef41Sopenharmony_ci// Submits a SETTINGS frame to be sent to the remote peer.
8141cb0ef41Sopenharmony_cifunction submitSettings(settings, callback) {
8151cb0ef41Sopenharmony_ci  if (this.destroyed)
8161cb0ef41Sopenharmony_ci    return;
8171cb0ef41Sopenharmony_ci  debugSessionObj(this, 'submitting settings');
8181cb0ef41Sopenharmony_ci  this[kUpdateTimer]();
8191cb0ef41Sopenharmony_ci  updateSettingsBuffer(settings);
8201cb0ef41Sopenharmony_ci  if (!this[kHandle].settings(FunctionPrototypeBind(settingsCallback,
8211cb0ef41Sopenharmony_ci                                                    this, callback))) {
8221cb0ef41Sopenharmony_ci    this.destroy(new ERR_HTTP2_MAX_PENDING_SETTINGS_ACK());
8231cb0ef41Sopenharmony_ci  }
8241cb0ef41Sopenharmony_ci}
8251cb0ef41Sopenharmony_ci
8261cb0ef41Sopenharmony_ci// Submits a PRIORITY frame to be sent to the remote peer
8271cb0ef41Sopenharmony_ci// Note: If the silent option is true, the change will be made
8281cb0ef41Sopenharmony_ci// locally with no PRIORITY frame sent.
8291cb0ef41Sopenharmony_cifunction submitPriority(options) {
8301cb0ef41Sopenharmony_ci  if (this.destroyed)
8311cb0ef41Sopenharmony_ci    return;
8321cb0ef41Sopenharmony_ci  this[kUpdateTimer]();
8331cb0ef41Sopenharmony_ci
8341cb0ef41Sopenharmony_ci  // If the parent is the id, do nothing because a
8351cb0ef41Sopenharmony_ci  // stream cannot be made to depend on itself.
8361cb0ef41Sopenharmony_ci  if (options.parent === this[kID])
8371cb0ef41Sopenharmony_ci    return;
8381cb0ef41Sopenharmony_ci
8391cb0ef41Sopenharmony_ci  this[kHandle].priority(options.parent | 0,
8401cb0ef41Sopenharmony_ci                         options.weight | 0,
8411cb0ef41Sopenharmony_ci                         !!options.exclusive,
8421cb0ef41Sopenharmony_ci                         !!options.silent);
8431cb0ef41Sopenharmony_ci}
8441cb0ef41Sopenharmony_ci
8451cb0ef41Sopenharmony_ci// Submit a GOAWAY frame to be sent to the remote peer.
8461cb0ef41Sopenharmony_ci// If the lastStreamID is set to <= 0, then the lastProcStreamID will
8471cb0ef41Sopenharmony_ci// be used. The opaqueData must either be a typed array or undefined
8481cb0ef41Sopenharmony_ci// (which will be checked elsewhere).
8491cb0ef41Sopenharmony_cifunction submitGoaway(code, lastStreamID, opaqueData) {
8501cb0ef41Sopenharmony_ci  if (this.destroyed)
8511cb0ef41Sopenharmony_ci    return;
8521cb0ef41Sopenharmony_ci  debugSessionObj(this, 'submitting goaway');
8531cb0ef41Sopenharmony_ci  this[kUpdateTimer]();
8541cb0ef41Sopenharmony_ci  this[kHandle].goaway(code, lastStreamID, opaqueData);
8551cb0ef41Sopenharmony_ci}
8561cb0ef41Sopenharmony_ci
8571cb0ef41Sopenharmony_ciconst proxySocketHandler = {
8581cb0ef41Sopenharmony_ci  get(session, prop) {
8591cb0ef41Sopenharmony_ci    switch (prop) {
8601cb0ef41Sopenharmony_ci      case 'setTimeout':
8611cb0ef41Sopenharmony_ci      case 'ref':
8621cb0ef41Sopenharmony_ci      case 'unref':
8631cb0ef41Sopenharmony_ci        return FunctionPrototypeBind(session[prop], session);
8641cb0ef41Sopenharmony_ci      case 'destroy':
8651cb0ef41Sopenharmony_ci      case 'emit':
8661cb0ef41Sopenharmony_ci      case 'end':
8671cb0ef41Sopenharmony_ci      case 'pause':
8681cb0ef41Sopenharmony_ci      case 'read':
8691cb0ef41Sopenharmony_ci      case 'resume':
8701cb0ef41Sopenharmony_ci      case 'write':
8711cb0ef41Sopenharmony_ci      case 'setEncoding':
8721cb0ef41Sopenharmony_ci      case 'setKeepAlive':
8731cb0ef41Sopenharmony_ci      case 'setNoDelay':
8741cb0ef41Sopenharmony_ci        throw new ERR_HTTP2_NO_SOCKET_MANIPULATION();
8751cb0ef41Sopenharmony_ci      default: {
8761cb0ef41Sopenharmony_ci        const socket = session[kSocket];
8771cb0ef41Sopenharmony_ci        if (socket === undefined)
8781cb0ef41Sopenharmony_ci          throw new ERR_HTTP2_SOCKET_UNBOUND();
8791cb0ef41Sopenharmony_ci        const value = socket[prop];
8801cb0ef41Sopenharmony_ci        return typeof value === 'function' ?
8811cb0ef41Sopenharmony_ci          FunctionPrototypeBind(value, socket) :
8821cb0ef41Sopenharmony_ci          value;
8831cb0ef41Sopenharmony_ci      }
8841cb0ef41Sopenharmony_ci    }
8851cb0ef41Sopenharmony_ci  },
8861cb0ef41Sopenharmony_ci  getPrototypeOf(session) {
8871cb0ef41Sopenharmony_ci    const socket = session[kSocket];
8881cb0ef41Sopenharmony_ci    if (socket === undefined)
8891cb0ef41Sopenharmony_ci      throw new ERR_HTTP2_SOCKET_UNBOUND();
8901cb0ef41Sopenharmony_ci    return ReflectGetPrototypeOf(socket);
8911cb0ef41Sopenharmony_ci  },
8921cb0ef41Sopenharmony_ci  set(session, prop, value) {
8931cb0ef41Sopenharmony_ci    switch (prop) {
8941cb0ef41Sopenharmony_ci      case 'setTimeout':
8951cb0ef41Sopenharmony_ci      case 'ref':
8961cb0ef41Sopenharmony_ci      case 'unref':
8971cb0ef41Sopenharmony_ci        session[prop] = value;
8981cb0ef41Sopenharmony_ci        return true;
8991cb0ef41Sopenharmony_ci      case 'destroy':
9001cb0ef41Sopenharmony_ci      case 'emit':
9011cb0ef41Sopenharmony_ci      case 'end':
9021cb0ef41Sopenharmony_ci      case 'pause':
9031cb0ef41Sopenharmony_ci      case 'read':
9041cb0ef41Sopenharmony_ci      case 'resume':
9051cb0ef41Sopenharmony_ci      case 'write':
9061cb0ef41Sopenharmony_ci      case 'setEncoding':
9071cb0ef41Sopenharmony_ci      case 'setKeepAlive':
9081cb0ef41Sopenharmony_ci      case 'setNoDelay':
9091cb0ef41Sopenharmony_ci        throw new ERR_HTTP2_NO_SOCKET_MANIPULATION();
9101cb0ef41Sopenharmony_ci      default: {
9111cb0ef41Sopenharmony_ci        const socket = session[kSocket];
9121cb0ef41Sopenharmony_ci        if (socket === undefined)
9131cb0ef41Sopenharmony_ci          throw new ERR_HTTP2_SOCKET_UNBOUND();
9141cb0ef41Sopenharmony_ci        socket[prop] = value;
9151cb0ef41Sopenharmony_ci        return true;
9161cb0ef41Sopenharmony_ci      }
9171cb0ef41Sopenharmony_ci    }
9181cb0ef41Sopenharmony_ci  },
9191cb0ef41Sopenharmony_ci};
9201cb0ef41Sopenharmony_ci
9211cb0ef41Sopenharmony_ci// pingCallback() returns a function that is invoked when an HTTP2 PING
9221cb0ef41Sopenharmony_ci// frame acknowledgement is received. The ack is either true or false to
9231cb0ef41Sopenharmony_ci// indicate if the ping was successful or not. The duration indicates the
9241cb0ef41Sopenharmony_ci// number of milliseconds elapsed since the ping was sent and the ack
9251cb0ef41Sopenharmony_ci// received. The payload is a Buffer containing the 8 bytes of payload
9261cb0ef41Sopenharmony_ci// data received on the PING acknowledgement.
9271cb0ef41Sopenharmony_cifunction pingCallback(cb) {
9281cb0ef41Sopenharmony_ci  return function pingCallback(ack, duration, payload) {
9291cb0ef41Sopenharmony_ci    if (ack) {
9301cb0ef41Sopenharmony_ci      cb(null, duration, payload);
9311cb0ef41Sopenharmony_ci    } else {
9321cb0ef41Sopenharmony_ci      cb(new ERR_HTTP2_PING_CANCEL());
9331cb0ef41Sopenharmony_ci    }
9341cb0ef41Sopenharmony_ci  };
9351cb0ef41Sopenharmony_ci}
9361cb0ef41Sopenharmony_ci
9371cb0ef41Sopenharmony_ci// Validates the values in a settings object. Specifically:
9381cb0ef41Sopenharmony_ci// 1. headerTableSize must be a number in the range 0 <= n <= kMaxInt
9391cb0ef41Sopenharmony_ci// 2. initialWindowSize must be a number in the range 0 <= n <= kMaxInt
9401cb0ef41Sopenharmony_ci// 3. maxFrameSize must be a number in the range 16384 <= n <= kMaxFrameSize
9411cb0ef41Sopenharmony_ci// 4. maxConcurrentStreams must be a number in the range 0 <= n <= kMaxStreams
9421cb0ef41Sopenharmony_ci// 5. maxHeaderListSize must be a number in the range 0 <= n <= kMaxInt
9431cb0ef41Sopenharmony_ci// 6. enablePush must be a boolean
9441cb0ef41Sopenharmony_ci// 7. enableConnectProtocol must be a boolean
9451cb0ef41Sopenharmony_ci// All settings are optional and may be left undefined
9461cb0ef41Sopenharmony_ciconst validateSettings = hideStackFrames((settings) => {
9471cb0ef41Sopenharmony_ci  if (settings === undefined) return;
9481cb0ef41Sopenharmony_ci  assertWithinRange('headerTableSize',
9491cb0ef41Sopenharmony_ci                    settings.headerTableSize,
9501cb0ef41Sopenharmony_ci                    0, kMaxInt);
9511cb0ef41Sopenharmony_ci  assertWithinRange('initialWindowSize',
9521cb0ef41Sopenharmony_ci                    settings.initialWindowSize,
9531cb0ef41Sopenharmony_ci                    0, kMaxInt);
9541cb0ef41Sopenharmony_ci  assertWithinRange('maxFrameSize',
9551cb0ef41Sopenharmony_ci                    settings.maxFrameSize,
9561cb0ef41Sopenharmony_ci                    16384, kMaxFrameSize);
9571cb0ef41Sopenharmony_ci  assertWithinRange('maxConcurrentStreams',
9581cb0ef41Sopenharmony_ci                    settings.maxConcurrentStreams,
9591cb0ef41Sopenharmony_ci                    0, kMaxStreams);
9601cb0ef41Sopenharmony_ci  assertWithinRange('maxHeaderListSize',
9611cb0ef41Sopenharmony_ci                    settings.maxHeaderListSize,
9621cb0ef41Sopenharmony_ci                    0, kMaxInt);
9631cb0ef41Sopenharmony_ci  assertWithinRange('maxHeaderSize',
9641cb0ef41Sopenharmony_ci                    settings.maxHeaderSize,
9651cb0ef41Sopenharmony_ci                    0, kMaxInt);
9661cb0ef41Sopenharmony_ci  if (settings.enablePush !== undefined &&
9671cb0ef41Sopenharmony_ci      typeof settings.enablePush !== 'boolean') {
9681cb0ef41Sopenharmony_ci    throw new ERR_HTTP2_INVALID_SETTING_VALUE('enablePush',
9691cb0ef41Sopenharmony_ci                                              settings.enablePush);
9701cb0ef41Sopenharmony_ci  }
9711cb0ef41Sopenharmony_ci  if (settings.enableConnectProtocol !== undefined &&
9721cb0ef41Sopenharmony_ci      typeof settings.enableConnectProtocol !== 'boolean') {
9731cb0ef41Sopenharmony_ci    throw new ERR_HTTP2_INVALID_SETTING_VALUE('enableConnectProtocol',
9741cb0ef41Sopenharmony_ci                                              settings.enableConnectProtocol);
9751cb0ef41Sopenharmony_ci  }
9761cb0ef41Sopenharmony_ci});
9771cb0ef41Sopenharmony_ci
9781cb0ef41Sopenharmony_ci// Wrap a typed array in a proxy, and allow selectively copying the entries
9791cb0ef41Sopenharmony_ci// that have explicitly been set to another typed array.
9801cb0ef41Sopenharmony_cifunction trackAssignmentsTypedArray(typedArray) {
9811cb0ef41Sopenharmony_ci  const typedArrayLength = TypedArrayPrototypeGetLength(typedArray);
9821cb0ef41Sopenharmony_ci  const modifiedEntries = new Uint8Array(typedArrayLength);
9831cb0ef41Sopenharmony_ci
9841cb0ef41Sopenharmony_ci  function copyAssigned(target) {
9851cb0ef41Sopenharmony_ci    for (let i = 0; i < typedArrayLength; i++) {
9861cb0ef41Sopenharmony_ci      if (modifiedEntries[i]) {
9871cb0ef41Sopenharmony_ci        target[i] = typedArray[i];
9881cb0ef41Sopenharmony_ci      }
9891cb0ef41Sopenharmony_ci    }
9901cb0ef41Sopenharmony_ci  }
9911cb0ef41Sopenharmony_ci
9921cb0ef41Sopenharmony_ci  return new Proxy(typedArray, {
9931cb0ef41Sopenharmony_ci    __proto__: null,
9941cb0ef41Sopenharmony_ci    get(obj, prop, receiver) {
9951cb0ef41Sopenharmony_ci      if (prop === 'copyAssigned') {
9961cb0ef41Sopenharmony_ci        return copyAssigned;
9971cb0ef41Sopenharmony_ci      }
9981cb0ef41Sopenharmony_ci      return ReflectGet(obj, prop, receiver);
9991cb0ef41Sopenharmony_ci    },
10001cb0ef41Sopenharmony_ci    set(obj, prop, value) {
10011cb0ef41Sopenharmony_ci      if (`${+prop}` === prop) {
10021cb0ef41Sopenharmony_ci        modifiedEntries[prop] = 1;
10031cb0ef41Sopenharmony_ci      }
10041cb0ef41Sopenharmony_ci      return ReflectSet(obj, prop, value);
10051cb0ef41Sopenharmony_ci    },
10061cb0ef41Sopenharmony_ci  });
10071cb0ef41Sopenharmony_ci}
10081cb0ef41Sopenharmony_ci
10091cb0ef41Sopenharmony_ci// Creates the internal binding.Http2Session handle for an Http2Session
10101cb0ef41Sopenharmony_ci// instance. This occurs only after the socket connection has been
10111cb0ef41Sopenharmony_ci// established. Note: the binding.Http2Session will take over ownership
10121cb0ef41Sopenharmony_ci// of the socket. No other code should read from or write to the socket.
10131cb0ef41Sopenharmony_cifunction setupHandle(socket, type, options) {
10141cb0ef41Sopenharmony_ci  // If the session has been destroyed, go ahead and emit 'connect',
10151cb0ef41Sopenharmony_ci  // but do nothing else. The various on('connect') handlers set by
10161cb0ef41Sopenharmony_ci  // core will check for session.destroyed before progressing, this
10171cb0ef41Sopenharmony_ci  // ensures that those at l`east get cleared out.
10181cb0ef41Sopenharmony_ci  if (this.destroyed) {
10191cb0ef41Sopenharmony_ci    process.nextTick(emit, this, 'connect', this, socket);
10201cb0ef41Sopenharmony_ci    return;
10211cb0ef41Sopenharmony_ci  }
10221cb0ef41Sopenharmony_ci
10231cb0ef41Sopenharmony_ci  assert(socket._handle !== undefined,
10241cb0ef41Sopenharmony_ci         'Internal HTTP/2 Failure. The socket is not connected. Please ' +
10251cb0ef41Sopenharmony_ci         'report this as a bug in Node.js');
10261cb0ef41Sopenharmony_ci
10271cb0ef41Sopenharmony_ci  debugSession(type, 'setting up session handle');
10281cb0ef41Sopenharmony_ci  this[kState].flags |= SESSION_FLAGS_READY;
10291cb0ef41Sopenharmony_ci
10301cb0ef41Sopenharmony_ci  updateOptionsBuffer(options);
10311cb0ef41Sopenharmony_ci  const handle = new binding.Http2Session(type);
10321cb0ef41Sopenharmony_ci  handle[kOwner] = this;
10331cb0ef41Sopenharmony_ci
10341cb0ef41Sopenharmony_ci  if (typeof options.selectPadding === 'function')
10351cb0ef41Sopenharmony_ci    this[kSelectPadding] = options.selectPadding;
10361cb0ef41Sopenharmony_ci  handle.consume(socket._handle);
10371cb0ef41Sopenharmony_ci
10381cb0ef41Sopenharmony_ci  this[kHandle] = handle;
10391cb0ef41Sopenharmony_ci  if (this[kNativeFields]) {
10401cb0ef41Sopenharmony_ci    // If some options have already been set before the handle existed, copy
10411cb0ef41Sopenharmony_ci    // those (and only those) that have manually been set over.
10421cb0ef41Sopenharmony_ci    this[kNativeFields].copyAssigned(handle.fields);
10431cb0ef41Sopenharmony_ci  }
10441cb0ef41Sopenharmony_ci
10451cb0ef41Sopenharmony_ci  this[kNativeFields] = handle.fields;
10461cb0ef41Sopenharmony_ci
10471cb0ef41Sopenharmony_ci  if (socket.encrypted) {
10481cb0ef41Sopenharmony_ci    this[kAlpnProtocol] = socket.alpnProtocol;
10491cb0ef41Sopenharmony_ci    this[kEncrypted] = true;
10501cb0ef41Sopenharmony_ci  } else {
10511cb0ef41Sopenharmony_ci    // 'h2c' is the protocol identifier for HTTP/2 over plain-text. We use
10521cb0ef41Sopenharmony_ci    // it here to identify any session that is not explicitly using an
10531cb0ef41Sopenharmony_ci    // encrypted socket.
10541cb0ef41Sopenharmony_ci    this[kAlpnProtocol] = 'h2c';
10551cb0ef41Sopenharmony_ci    this[kEncrypted] = false;
10561cb0ef41Sopenharmony_ci  }
10571cb0ef41Sopenharmony_ci
10581cb0ef41Sopenharmony_ci  if (isUint32(options.maxSessionInvalidFrames)) {
10591cb0ef41Sopenharmony_ci    const uint32 = new Uint32Array(
10601cb0ef41Sopenharmony_ci      this[kNativeFields].buffer, kSessionMaxInvalidFrames, 1);
10611cb0ef41Sopenharmony_ci    uint32[0] = options.maxSessionInvalidFrames;
10621cb0ef41Sopenharmony_ci  }
10631cb0ef41Sopenharmony_ci
10641cb0ef41Sopenharmony_ci  if (isUint32(options.maxSessionRejectedStreams)) {
10651cb0ef41Sopenharmony_ci    const uint32 = new Uint32Array(
10661cb0ef41Sopenharmony_ci      this[kNativeFields].buffer, kSessionMaxRejectedStreams, 1);
10671cb0ef41Sopenharmony_ci    uint32[0] = options.maxSessionRejectedStreams;
10681cb0ef41Sopenharmony_ci  }
10691cb0ef41Sopenharmony_ci
10701cb0ef41Sopenharmony_ci  const settings = typeof options.settings === 'object' ?
10711cb0ef41Sopenharmony_ci    options.settings : {};
10721cb0ef41Sopenharmony_ci
10731cb0ef41Sopenharmony_ci  this.settings(settings);
10741cb0ef41Sopenharmony_ci
10751cb0ef41Sopenharmony_ci  if (type === NGHTTP2_SESSION_SERVER &&
10761cb0ef41Sopenharmony_ci      ArrayIsArray(options.origins)) {
10771cb0ef41Sopenharmony_ci    ReflectApply(this.origin, this, options.origins);
10781cb0ef41Sopenharmony_ci  }
10791cb0ef41Sopenharmony_ci
10801cb0ef41Sopenharmony_ci  process.nextTick(emit, this, 'connect', this, socket);
10811cb0ef41Sopenharmony_ci}
10821cb0ef41Sopenharmony_ci
10831cb0ef41Sopenharmony_ci// Emits a close event followed by an error event if err is truthy. Used
10841cb0ef41Sopenharmony_ci// by Http2Session.prototype.destroy()
10851cb0ef41Sopenharmony_cifunction emitClose(self, error) {
10861cb0ef41Sopenharmony_ci  if (error)
10871cb0ef41Sopenharmony_ci    self.emit('error', error);
10881cb0ef41Sopenharmony_ci  self.emit('close');
10891cb0ef41Sopenharmony_ci}
10901cb0ef41Sopenharmony_ci
10911cb0ef41Sopenharmony_cifunction cleanupSession(session) {
10921cb0ef41Sopenharmony_ci  const socket = session[kSocket];
10931cb0ef41Sopenharmony_ci  const handle = session[kHandle];
10941cb0ef41Sopenharmony_ci  session[kProxySocket] = undefined;
10951cb0ef41Sopenharmony_ci  session[kSocket] = undefined;
10961cb0ef41Sopenharmony_ci  session[kHandle] = undefined;
10971cb0ef41Sopenharmony_ci  session[kNativeFields] = trackAssignmentsTypedArray(
10981cb0ef41Sopenharmony_ci    new Uint8Array(kSessionUint8FieldCount));
10991cb0ef41Sopenharmony_ci  if (handle)
11001cb0ef41Sopenharmony_ci    handle.ondone = null;
11011cb0ef41Sopenharmony_ci  if (socket) {
11021cb0ef41Sopenharmony_ci    socket[kSession] = undefined;
11031cb0ef41Sopenharmony_ci    socket[kServer] = undefined;
11041cb0ef41Sopenharmony_ci  }
11051cb0ef41Sopenharmony_ci}
11061cb0ef41Sopenharmony_ci
11071cb0ef41Sopenharmony_cifunction finishSessionClose(session, error) {
11081cb0ef41Sopenharmony_ci  debugSessionObj(session, 'finishSessionClose');
11091cb0ef41Sopenharmony_ci
11101cb0ef41Sopenharmony_ci  const socket = session[kSocket];
11111cb0ef41Sopenharmony_ci  cleanupSession(session);
11121cb0ef41Sopenharmony_ci
11131cb0ef41Sopenharmony_ci  if (socket && !socket.destroyed) {
11141cb0ef41Sopenharmony_ci    socket.on('close', () => {
11151cb0ef41Sopenharmony_ci      emitClose(session, error);
11161cb0ef41Sopenharmony_ci    });
11171cb0ef41Sopenharmony_ci    if (session.closed) {
11181cb0ef41Sopenharmony_ci      // If we're gracefully closing the socket, call resume() so we can detect
11191cb0ef41Sopenharmony_ci      // the peer closing in case binding.Http2Session is already gone.
11201cb0ef41Sopenharmony_ci      socket.resume();
11211cb0ef41Sopenharmony_ci    }
11221cb0ef41Sopenharmony_ci
11231cb0ef41Sopenharmony_ci    // Always wait for writable side to finish.
11241cb0ef41Sopenharmony_ci    socket.end((err) => {
11251cb0ef41Sopenharmony_ci      debugSessionObj(session, 'finishSessionClose socket end', err, error);
11261cb0ef41Sopenharmony_ci      // If session.destroy() was called, destroy the underlying socket. Delay
11271cb0ef41Sopenharmony_ci      // it a bit to try to avoid ECONNRESET on Windows.
11281cb0ef41Sopenharmony_ci      if (!session.closed) {
11291cb0ef41Sopenharmony_ci        setImmediate(() => {
11301cb0ef41Sopenharmony_ci          socket.destroy(error);
11311cb0ef41Sopenharmony_ci        });
11321cb0ef41Sopenharmony_ci      }
11331cb0ef41Sopenharmony_ci    });
11341cb0ef41Sopenharmony_ci  } else {
11351cb0ef41Sopenharmony_ci    process.nextTick(emitClose, session, error);
11361cb0ef41Sopenharmony_ci  }
11371cb0ef41Sopenharmony_ci}
11381cb0ef41Sopenharmony_ci
11391cb0ef41Sopenharmony_cifunction closeSession(session, code, error) {
11401cb0ef41Sopenharmony_ci  debugSessionObj(session, 'start closing/destroying', error);
11411cb0ef41Sopenharmony_ci
11421cb0ef41Sopenharmony_ci  const state = session[kState];
11431cb0ef41Sopenharmony_ci  state.flags |= SESSION_FLAGS_DESTROYED;
11441cb0ef41Sopenharmony_ci  state.destroyCode = code;
11451cb0ef41Sopenharmony_ci
11461cb0ef41Sopenharmony_ci  // Clear timeout and remove timeout listeners.
11471cb0ef41Sopenharmony_ci  session.setTimeout(0);
11481cb0ef41Sopenharmony_ci  session.removeAllListeners('timeout');
11491cb0ef41Sopenharmony_ci
11501cb0ef41Sopenharmony_ci  // Destroy any pending and open streams
11511cb0ef41Sopenharmony_ci  if (state.pendingStreams.size > 0 || state.streams.size > 0) {
11521cb0ef41Sopenharmony_ci    const cancel = new ERR_HTTP2_STREAM_CANCEL(error);
11531cb0ef41Sopenharmony_ci    state.pendingStreams.forEach((stream) => stream.destroy(cancel));
11541cb0ef41Sopenharmony_ci    state.streams.forEach((stream) => stream.destroy(error));
11551cb0ef41Sopenharmony_ci  }
11561cb0ef41Sopenharmony_ci
11571cb0ef41Sopenharmony_ci  // Disassociate from the socket and server.
11581cb0ef41Sopenharmony_ci  const socket = session[kSocket];
11591cb0ef41Sopenharmony_ci  const handle = session[kHandle];
11601cb0ef41Sopenharmony_ci
11611cb0ef41Sopenharmony_ci  // Destroy the handle if it exists at this point.
11621cb0ef41Sopenharmony_ci  if (handle !== undefined) {
11631cb0ef41Sopenharmony_ci    handle.ondone = FunctionPrototypeBind(finishSessionClose,
11641cb0ef41Sopenharmony_ci                                          null, session, error);
11651cb0ef41Sopenharmony_ci    handle.destroy(code, socket.destroyed);
11661cb0ef41Sopenharmony_ci  } else {
11671cb0ef41Sopenharmony_ci    finishSessionClose(session, error);
11681cb0ef41Sopenharmony_ci  }
11691cb0ef41Sopenharmony_ci}
11701cb0ef41Sopenharmony_ci
11711cb0ef41Sopenharmony_ci// Upon creation, the Http2Session takes ownership of the socket. The session
11721cb0ef41Sopenharmony_ci// may not be ready to use immediately if the socket is not yet fully connected.
11731cb0ef41Sopenharmony_ci// In that case, the Http2Session will wait for the socket to connect. Once
11741cb0ef41Sopenharmony_ci// the Http2Session is ready, it will emit its own 'connect' event.
11751cb0ef41Sopenharmony_ci//
11761cb0ef41Sopenharmony_ci// The Http2Session.goaway() method will send a GOAWAY frame, signalling
11771cb0ef41Sopenharmony_ci// to the connected peer that a shutdown is in progress. Sending a goaway
11781cb0ef41Sopenharmony_ci// frame has no other effect, however.
11791cb0ef41Sopenharmony_ci//
11801cb0ef41Sopenharmony_ci// Receiving a GOAWAY frame will cause the Http2Session to first emit a 'goaway'
11811cb0ef41Sopenharmony_ci// event notifying the user that a shutdown is in progress. If the goaway
11821cb0ef41Sopenharmony_ci// error code equals 0 (NGHTTP2_NO_ERROR), session.close() will be called,
11831cb0ef41Sopenharmony_ci// causing the Http2Session to send its own GOAWAY frame and switch itself
11841cb0ef41Sopenharmony_ci// into a graceful closing state. In this state, new inbound or outbound
11851cb0ef41Sopenharmony_ci// Http2Streams will be rejected. Existing *pending* streams (those created
11861cb0ef41Sopenharmony_ci// but without an assigned stream ID or handle) will be destroyed with a
11871cb0ef41Sopenharmony_ci// cancel error. Existing open streams will be permitted to complete on their
11881cb0ef41Sopenharmony_ci// own. Once all existing streams close, session.destroy() will be called
11891cb0ef41Sopenharmony_ci// automatically.
11901cb0ef41Sopenharmony_ci//
11911cb0ef41Sopenharmony_ci// Calling session.destroy() will tear down the Http2Session immediately,
11921cb0ef41Sopenharmony_ci// making it no longer usable. Pending and existing streams will be destroyed.
11931cb0ef41Sopenharmony_ci// The bound socket will be destroyed. Once all resources have been freed up,
11941cb0ef41Sopenharmony_ci// the 'close' event will be emitted. Note that pending streams will be
11951cb0ef41Sopenharmony_ci// destroyed using a specific "ERR_HTTP2_STREAM_CANCEL" error. Existing open
11961cb0ef41Sopenharmony_ci// streams will be destroyed using the same error passed to session.destroy()
11971cb0ef41Sopenharmony_ci//
11981cb0ef41Sopenharmony_ci// If destroy is called with an error, an 'error' event will be emitted
11991cb0ef41Sopenharmony_ci// immediately following the 'close' event.
12001cb0ef41Sopenharmony_ci//
12011cb0ef41Sopenharmony_ci// The socket and Http2Session lifecycles are tightly bound. Once one is
12021cb0ef41Sopenharmony_ci// destroyed, the other should also be destroyed. When the socket is destroyed
12031cb0ef41Sopenharmony_ci// with an error, session.destroy() will be called with that same error.
12041cb0ef41Sopenharmony_ci// Likewise, when session.destroy() is called with an error, the same error
12051cb0ef41Sopenharmony_ci// will be sent to the socket.
12061cb0ef41Sopenharmony_ciclass Http2Session extends EventEmitter {
12071cb0ef41Sopenharmony_ci  constructor(type, options, socket) {
12081cb0ef41Sopenharmony_ci    super();
12091cb0ef41Sopenharmony_ci
12101cb0ef41Sopenharmony_ci    if (!socket._handle || !socket._handle.isStreamBase) {
12111cb0ef41Sopenharmony_ci      socket = new JSStreamSocket(socket);
12121cb0ef41Sopenharmony_ci    }
12131cb0ef41Sopenharmony_ci    socket.on('error', socketOnError);
12141cb0ef41Sopenharmony_ci    socket.on('close', socketOnClose);
12151cb0ef41Sopenharmony_ci
12161cb0ef41Sopenharmony_ci    // No validation is performed on the input parameters because this
12171cb0ef41Sopenharmony_ci    // constructor is not exported directly for users.
12181cb0ef41Sopenharmony_ci
12191cb0ef41Sopenharmony_ci    // If the session property already exists on the socket,
12201cb0ef41Sopenharmony_ci    // then it has already been bound to an Http2Session instance
12211cb0ef41Sopenharmony_ci    // and cannot be attached again.
12221cb0ef41Sopenharmony_ci    if (socket[kSession] !== undefined)
12231cb0ef41Sopenharmony_ci      throw new ERR_HTTP2_SOCKET_BOUND();
12241cb0ef41Sopenharmony_ci
12251cb0ef41Sopenharmony_ci    socket[kSession] = this;
12261cb0ef41Sopenharmony_ci
12271cb0ef41Sopenharmony_ci    this[kState] = {
12281cb0ef41Sopenharmony_ci      destroyCode: NGHTTP2_NO_ERROR,
12291cb0ef41Sopenharmony_ci      flags: SESSION_FLAGS_PENDING,
12301cb0ef41Sopenharmony_ci      goawayCode: null,
12311cb0ef41Sopenharmony_ci      goawayLastStreamID: null,
12321cb0ef41Sopenharmony_ci      streams: new SafeMap(),
12331cb0ef41Sopenharmony_ci      pendingStreams: new SafeSet(),
12341cb0ef41Sopenharmony_ci      pendingAck: 0,
12351cb0ef41Sopenharmony_ci      shutdownWritableCalled: false,
12361cb0ef41Sopenharmony_ci      writeQueueSize: 0,
12371cb0ef41Sopenharmony_ci      originSet: undefined,
12381cb0ef41Sopenharmony_ci    };
12391cb0ef41Sopenharmony_ci
12401cb0ef41Sopenharmony_ci    this[kEncrypted] = undefined;
12411cb0ef41Sopenharmony_ci    this[kAlpnProtocol] = undefined;
12421cb0ef41Sopenharmony_ci    this[kType] = type;
12431cb0ef41Sopenharmony_ci    this[kProxySocket] = null;
12441cb0ef41Sopenharmony_ci    this[kSocket] = socket;
12451cb0ef41Sopenharmony_ci    this[kTimeout] = null;
12461cb0ef41Sopenharmony_ci    this[kHandle] = undefined;
12471cb0ef41Sopenharmony_ci
12481cb0ef41Sopenharmony_ci    // Do not use nagle's algorithm
12491cb0ef41Sopenharmony_ci    if (typeof socket.setNoDelay === 'function')
12501cb0ef41Sopenharmony_ci      socket.setNoDelay();
12511cb0ef41Sopenharmony_ci
12521cb0ef41Sopenharmony_ci    // Disable TLS renegotiation on the socket
12531cb0ef41Sopenharmony_ci    if (typeof socket.disableRenegotiation === 'function')
12541cb0ef41Sopenharmony_ci      socket.disableRenegotiation();
12551cb0ef41Sopenharmony_ci
12561cb0ef41Sopenharmony_ci    const setupFn = FunctionPrototypeBind(setupHandle, this,
12571cb0ef41Sopenharmony_ci                                          socket, type, options);
12581cb0ef41Sopenharmony_ci    if (socket.connecting || socket.secureConnecting) {
12591cb0ef41Sopenharmony_ci      const connectEvent =
12601cb0ef41Sopenharmony_ci        socket instanceof tls.TLSSocket ? 'secureConnect' : 'connect';
12611cb0ef41Sopenharmony_ci      socket.once(connectEvent, () => {
12621cb0ef41Sopenharmony_ci        try {
12631cb0ef41Sopenharmony_ci          setupFn();
12641cb0ef41Sopenharmony_ci        } catch (error) {
12651cb0ef41Sopenharmony_ci          socket.destroy(error);
12661cb0ef41Sopenharmony_ci        }
12671cb0ef41Sopenharmony_ci      });
12681cb0ef41Sopenharmony_ci    } else {
12691cb0ef41Sopenharmony_ci      setupFn();
12701cb0ef41Sopenharmony_ci    }
12711cb0ef41Sopenharmony_ci
12721cb0ef41Sopenharmony_ci    if (!this[kNativeFields]) {
12731cb0ef41Sopenharmony_ci      this[kNativeFields] = trackAssignmentsTypedArray(
12741cb0ef41Sopenharmony_ci        new Uint8Array(kSessionUint8FieldCount));
12751cb0ef41Sopenharmony_ci    }
12761cb0ef41Sopenharmony_ci    this.on('newListener', sessionListenerAdded);
12771cb0ef41Sopenharmony_ci    this.on('removeListener', sessionListenerRemoved);
12781cb0ef41Sopenharmony_ci
12791cb0ef41Sopenharmony_ci    // Process data on the next tick - a remoteSettings handler may be attached.
12801cb0ef41Sopenharmony_ci    // https://github.com/nodejs/node/issues/35981
12811cb0ef41Sopenharmony_ci    process.nextTick(() => {
12821cb0ef41Sopenharmony_ci      // Socket already has some buffered data - emulate receiving it
12831cb0ef41Sopenharmony_ci      // https://github.com/nodejs/node/issues/35475
12841cb0ef41Sopenharmony_ci      // https://github.com/nodejs/node/issues/34532
12851cb0ef41Sopenharmony_ci      if (socket.readableLength) {
12861cb0ef41Sopenharmony_ci        let buf;
12871cb0ef41Sopenharmony_ci        while ((buf = socket.read()) !== null) {
12881cb0ef41Sopenharmony_ci          debugSession(type, `${buf.length} bytes already in buffer`);
12891cb0ef41Sopenharmony_ci          this[kHandle].receive(buf);
12901cb0ef41Sopenharmony_ci        }
12911cb0ef41Sopenharmony_ci      }
12921cb0ef41Sopenharmony_ci    });
12931cb0ef41Sopenharmony_ci
12941cb0ef41Sopenharmony_ci    debugSession(type, 'created');
12951cb0ef41Sopenharmony_ci  }
12961cb0ef41Sopenharmony_ci
12971cb0ef41Sopenharmony_ci  // Returns undefined if the socket is not yet connected, true if the
12981cb0ef41Sopenharmony_ci  // socket is a TLSSocket, and false if it is not.
12991cb0ef41Sopenharmony_ci  get encrypted() {
13001cb0ef41Sopenharmony_ci    return this[kEncrypted];
13011cb0ef41Sopenharmony_ci  }
13021cb0ef41Sopenharmony_ci
13031cb0ef41Sopenharmony_ci  // Returns undefined if the socket is not yet connected, `h2` if the
13041cb0ef41Sopenharmony_ci  // socket is a TLSSocket and the alpnProtocol is `h2`, or `h2c` if the
13051cb0ef41Sopenharmony_ci  // socket is not a TLSSocket.
13061cb0ef41Sopenharmony_ci  get alpnProtocol() {
13071cb0ef41Sopenharmony_ci    return this[kAlpnProtocol];
13081cb0ef41Sopenharmony_ci  }
13091cb0ef41Sopenharmony_ci
13101cb0ef41Sopenharmony_ci  // TODO(jasnell): originSet is being added in preparation for ORIGIN frame
13111cb0ef41Sopenharmony_ci  // support. At the current time, the ORIGIN frame specification is awaiting
13121cb0ef41Sopenharmony_ci  // publication as an RFC and is awaiting implementation in nghttp2. Once
13131cb0ef41Sopenharmony_ci  // added, an ORIGIN frame will add to the origins included in the origin
13141cb0ef41Sopenharmony_ci  // set. 421 responses will remove origins from the set.
13151cb0ef41Sopenharmony_ci  get originSet() {
13161cb0ef41Sopenharmony_ci    if (!this.encrypted || this.destroyed)
13171cb0ef41Sopenharmony_ci      return undefined;
13181cb0ef41Sopenharmony_ci    return ArrayFrom(initOriginSet(this));
13191cb0ef41Sopenharmony_ci  }
13201cb0ef41Sopenharmony_ci
13211cb0ef41Sopenharmony_ci  // True if the Http2Session is still waiting for the socket to connect
13221cb0ef41Sopenharmony_ci  get connecting() {
13231cb0ef41Sopenharmony_ci    return (this[kState].flags & SESSION_FLAGS_READY) === 0;
13241cb0ef41Sopenharmony_ci  }
13251cb0ef41Sopenharmony_ci
13261cb0ef41Sopenharmony_ci  // True if Http2Session.prototype.close() has been called
13271cb0ef41Sopenharmony_ci  get closed() {
13281cb0ef41Sopenharmony_ci    return !!(this[kState].flags & SESSION_FLAGS_CLOSED);
13291cb0ef41Sopenharmony_ci  }
13301cb0ef41Sopenharmony_ci
13311cb0ef41Sopenharmony_ci  // True if Http2Session.prototype.destroy() has been called
13321cb0ef41Sopenharmony_ci  get destroyed() {
13331cb0ef41Sopenharmony_ci    return !!(this[kState].flags & SESSION_FLAGS_DESTROYED);
13341cb0ef41Sopenharmony_ci  }
13351cb0ef41Sopenharmony_ci
13361cb0ef41Sopenharmony_ci  // Resets the timeout counter
13371cb0ef41Sopenharmony_ci  [kUpdateTimer]() {
13381cb0ef41Sopenharmony_ci    if (this.destroyed)
13391cb0ef41Sopenharmony_ci      return;
13401cb0ef41Sopenharmony_ci    if (this[kTimeout]) this[kTimeout].refresh();
13411cb0ef41Sopenharmony_ci  }
13421cb0ef41Sopenharmony_ci
13431cb0ef41Sopenharmony_ci  // Sets the id of the next stream to be created by this Http2Session.
13441cb0ef41Sopenharmony_ci  // The value must be a number in the range 0 <= n <= kMaxStreams. The
13451cb0ef41Sopenharmony_ci  // value also needs to be larger than the current next stream ID.
13461cb0ef41Sopenharmony_ci  setNextStreamID(id) {
13471cb0ef41Sopenharmony_ci    if (this.destroyed)
13481cb0ef41Sopenharmony_ci      throw new ERR_HTTP2_INVALID_SESSION();
13491cb0ef41Sopenharmony_ci
13501cb0ef41Sopenharmony_ci    validateNumber(id, 'id');
13511cb0ef41Sopenharmony_ci    if (id <= 0 || id > kMaxStreams)
13521cb0ef41Sopenharmony_ci      throw new ERR_OUT_OF_RANGE('id', `> 0 and <= ${kMaxStreams}`, id);
13531cb0ef41Sopenharmony_ci    this[kHandle].setNextStreamID(id);
13541cb0ef41Sopenharmony_ci  }
13551cb0ef41Sopenharmony_ci
13561cb0ef41Sopenharmony_ci  // Sets the local window size (local endpoints's window size)
13571cb0ef41Sopenharmony_ci  // Returns 0 if success or throw an exception if NGHTTP2_ERR_NOMEM
13581cb0ef41Sopenharmony_ci  // if the window allocation fails
13591cb0ef41Sopenharmony_ci  setLocalWindowSize(windowSize) {
13601cb0ef41Sopenharmony_ci    if (this.destroyed)
13611cb0ef41Sopenharmony_ci      throw new ERR_HTTP2_INVALID_SESSION();
13621cb0ef41Sopenharmony_ci
13631cb0ef41Sopenharmony_ci    validateInt32(windowSize, 'windowSize', 0);
13641cb0ef41Sopenharmony_ci    const ret = this[kHandle].setLocalWindowSize(windowSize);
13651cb0ef41Sopenharmony_ci
13661cb0ef41Sopenharmony_ci    if (ret === NGHTTP2_ERR_NOMEM) {
13671cb0ef41Sopenharmony_ci      this.destroy(new ERR_HTTP2_NO_MEM());
13681cb0ef41Sopenharmony_ci    }
13691cb0ef41Sopenharmony_ci  }
13701cb0ef41Sopenharmony_ci
13711cb0ef41Sopenharmony_ci  // If ping is called while we are still connecting, or after close() has
13721cb0ef41Sopenharmony_ci  // been called, the ping callback will be invoked immediately with a ping
13731cb0ef41Sopenharmony_ci  // cancelled error and a duration of 0.0.
13741cb0ef41Sopenharmony_ci  ping(payload, callback) {
13751cb0ef41Sopenharmony_ci    if (this.destroyed)
13761cb0ef41Sopenharmony_ci      throw new ERR_HTTP2_INVALID_SESSION();
13771cb0ef41Sopenharmony_ci
13781cb0ef41Sopenharmony_ci    if (typeof payload === 'function') {
13791cb0ef41Sopenharmony_ci      callback = payload;
13801cb0ef41Sopenharmony_ci      payload = undefined;
13811cb0ef41Sopenharmony_ci    }
13821cb0ef41Sopenharmony_ci    if (payload) {
13831cb0ef41Sopenharmony_ci      validateBuffer(payload, 'payload');
13841cb0ef41Sopenharmony_ci    }
13851cb0ef41Sopenharmony_ci    if (payload && payload.length !== 8) {
13861cb0ef41Sopenharmony_ci      throw new ERR_HTTP2_PING_LENGTH();
13871cb0ef41Sopenharmony_ci    }
13881cb0ef41Sopenharmony_ci    validateFunction(callback, 'callback');
13891cb0ef41Sopenharmony_ci
13901cb0ef41Sopenharmony_ci    const cb = pingCallback(callback);
13911cb0ef41Sopenharmony_ci    if (this.connecting || this.closed) {
13921cb0ef41Sopenharmony_ci      process.nextTick(cb, false, 0.0, payload);
13931cb0ef41Sopenharmony_ci      return;
13941cb0ef41Sopenharmony_ci    }
13951cb0ef41Sopenharmony_ci
13961cb0ef41Sopenharmony_ci    return this[kHandle].ping(payload, cb);
13971cb0ef41Sopenharmony_ci  }
13981cb0ef41Sopenharmony_ci
13991cb0ef41Sopenharmony_ci  [kInspect](depth, opts) {
14001cb0ef41Sopenharmony_ci    if (typeof depth === 'number' && depth < 0)
14011cb0ef41Sopenharmony_ci      return this;
14021cb0ef41Sopenharmony_ci
14031cb0ef41Sopenharmony_ci    const obj = {
14041cb0ef41Sopenharmony_ci      type: this[kType],
14051cb0ef41Sopenharmony_ci      closed: this.closed,
14061cb0ef41Sopenharmony_ci      destroyed: this.destroyed,
14071cb0ef41Sopenharmony_ci      state: this.state,
14081cb0ef41Sopenharmony_ci      localSettings: this.localSettings,
14091cb0ef41Sopenharmony_ci      remoteSettings: this.remoteSettings,
14101cb0ef41Sopenharmony_ci    };
14111cb0ef41Sopenharmony_ci    return `Http2Session ${format(obj)}`;
14121cb0ef41Sopenharmony_ci  }
14131cb0ef41Sopenharmony_ci
14141cb0ef41Sopenharmony_ci  // The socket owned by this session
14151cb0ef41Sopenharmony_ci  get socket() {
14161cb0ef41Sopenharmony_ci    const proxySocket = this[kProxySocket];
14171cb0ef41Sopenharmony_ci    if (proxySocket === null)
14181cb0ef41Sopenharmony_ci      return this[kProxySocket] = new Proxy(this, proxySocketHandler);
14191cb0ef41Sopenharmony_ci    return proxySocket;
14201cb0ef41Sopenharmony_ci  }
14211cb0ef41Sopenharmony_ci
14221cb0ef41Sopenharmony_ci  // The session type
14231cb0ef41Sopenharmony_ci  get type() {
14241cb0ef41Sopenharmony_ci    return this[kType];
14251cb0ef41Sopenharmony_ci  }
14261cb0ef41Sopenharmony_ci
14271cb0ef41Sopenharmony_ci  // If a GOAWAY frame has been received, gives the error code specified
14281cb0ef41Sopenharmony_ci  get goawayCode() {
14291cb0ef41Sopenharmony_ci    return this[kState].goawayCode || NGHTTP2_NO_ERROR;
14301cb0ef41Sopenharmony_ci  }
14311cb0ef41Sopenharmony_ci
14321cb0ef41Sopenharmony_ci  // If a GOAWAY frame has been received, gives the last stream ID reported
14331cb0ef41Sopenharmony_ci  get goawayLastStreamID() {
14341cb0ef41Sopenharmony_ci    return this[kState].goawayLastStreamID || 0;
14351cb0ef41Sopenharmony_ci  }
14361cb0ef41Sopenharmony_ci
14371cb0ef41Sopenharmony_ci  // True if the Http2Session is waiting for a settings acknowledgement
14381cb0ef41Sopenharmony_ci  get pendingSettingsAck() {
14391cb0ef41Sopenharmony_ci    return this[kState].pendingAck > 0;
14401cb0ef41Sopenharmony_ci  }
14411cb0ef41Sopenharmony_ci
14421cb0ef41Sopenharmony_ci  // Retrieves state information for the Http2Session
14431cb0ef41Sopenharmony_ci  get state() {
14441cb0ef41Sopenharmony_ci    return this.connecting || this.destroyed ?
14451cb0ef41Sopenharmony_ci      {} : getSessionState(this[kHandle]);
14461cb0ef41Sopenharmony_ci  }
14471cb0ef41Sopenharmony_ci
14481cb0ef41Sopenharmony_ci  // The settings currently in effect for the local peer. These will
14491cb0ef41Sopenharmony_ci  // be updated only when a settings acknowledgement has been received.
14501cb0ef41Sopenharmony_ci  get localSettings() {
14511cb0ef41Sopenharmony_ci    const settings = this[kLocalSettings];
14521cb0ef41Sopenharmony_ci    if (settings !== undefined)
14531cb0ef41Sopenharmony_ci      return settings;
14541cb0ef41Sopenharmony_ci
14551cb0ef41Sopenharmony_ci    if (this.destroyed || this.connecting)
14561cb0ef41Sopenharmony_ci      return {};
14571cb0ef41Sopenharmony_ci
14581cb0ef41Sopenharmony_ci    return this[kLocalSettings] = getSettings(this[kHandle], false); // Local
14591cb0ef41Sopenharmony_ci  }
14601cb0ef41Sopenharmony_ci
14611cb0ef41Sopenharmony_ci  // The settings currently in effect for the remote peer.
14621cb0ef41Sopenharmony_ci  get remoteSettings() {
14631cb0ef41Sopenharmony_ci    if (this[kNativeFields][kBitfield] &
14641cb0ef41Sopenharmony_ci        (1 << kSessionRemoteSettingsIsUpToDate)) {
14651cb0ef41Sopenharmony_ci      const settings = this[kRemoteSettings];
14661cb0ef41Sopenharmony_ci      if (settings !== undefined) {
14671cb0ef41Sopenharmony_ci        return settings;
14681cb0ef41Sopenharmony_ci      }
14691cb0ef41Sopenharmony_ci    }
14701cb0ef41Sopenharmony_ci
14711cb0ef41Sopenharmony_ci    if (this.destroyed || this.connecting)
14721cb0ef41Sopenharmony_ci      return {};
14731cb0ef41Sopenharmony_ci
14741cb0ef41Sopenharmony_ci    this[kNativeFields][kBitfield] |= (1 << kSessionRemoteSettingsIsUpToDate);
14751cb0ef41Sopenharmony_ci    return this[kRemoteSettings] = getSettings(this[kHandle], true); // Remote
14761cb0ef41Sopenharmony_ci  }
14771cb0ef41Sopenharmony_ci
14781cb0ef41Sopenharmony_ci  // Submits a SETTINGS frame to be sent to the remote peer.
14791cb0ef41Sopenharmony_ci  settings(settings, callback) {
14801cb0ef41Sopenharmony_ci    if (this.destroyed)
14811cb0ef41Sopenharmony_ci      throw new ERR_HTTP2_INVALID_SESSION();
14821cb0ef41Sopenharmony_ci    assertIsObject(settings, 'settings');
14831cb0ef41Sopenharmony_ci    validateSettings(settings);
14841cb0ef41Sopenharmony_ci
14851cb0ef41Sopenharmony_ci    if (callback) {
14861cb0ef41Sopenharmony_ci      validateFunction(callback, 'callback');
14871cb0ef41Sopenharmony_ci    }
14881cb0ef41Sopenharmony_ci    debugSessionObj(this, 'sending settings');
14891cb0ef41Sopenharmony_ci
14901cb0ef41Sopenharmony_ci    this[kState].pendingAck++;
14911cb0ef41Sopenharmony_ci
14921cb0ef41Sopenharmony_ci    const settingsFn = FunctionPrototypeBind(submitSettings, this,
14931cb0ef41Sopenharmony_ci                                             { ...settings }, callback);
14941cb0ef41Sopenharmony_ci    if (this.connecting) {
14951cb0ef41Sopenharmony_ci      this.once('connect', settingsFn);
14961cb0ef41Sopenharmony_ci      return;
14971cb0ef41Sopenharmony_ci    }
14981cb0ef41Sopenharmony_ci    settingsFn();
14991cb0ef41Sopenharmony_ci  }
15001cb0ef41Sopenharmony_ci
15011cb0ef41Sopenharmony_ci  // Submits a GOAWAY frame to be sent to the remote peer. Note that this
15021cb0ef41Sopenharmony_ci  // is only a notification, and does not affect the usable state of the
15031cb0ef41Sopenharmony_ci  // session with the notable exception that new incoming streams will
15041cb0ef41Sopenharmony_ci  // be rejected automatically.
15051cb0ef41Sopenharmony_ci  goaway(code = NGHTTP2_NO_ERROR, lastStreamID = 0, opaqueData) {
15061cb0ef41Sopenharmony_ci    if (this.destroyed)
15071cb0ef41Sopenharmony_ci      throw new ERR_HTTP2_INVALID_SESSION();
15081cb0ef41Sopenharmony_ci
15091cb0ef41Sopenharmony_ci    if (opaqueData !== undefined) {
15101cb0ef41Sopenharmony_ci      validateBuffer(opaqueData, 'opaqueData');
15111cb0ef41Sopenharmony_ci    }
15121cb0ef41Sopenharmony_ci    validateNumber(code, 'code');
15131cb0ef41Sopenharmony_ci    validateNumber(lastStreamID, 'lastStreamID');
15141cb0ef41Sopenharmony_ci
15151cb0ef41Sopenharmony_ci    const goawayFn = FunctionPrototypeBind(submitGoaway,
15161cb0ef41Sopenharmony_ci                                           this,
15171cb0ef41Sopenharmony_ci                                           code, lastStreamID, opaqueData);
15181cb0ef41Sopenharmony_ci    if (this.connecting) {
15191cb0ef41Sopenharmony_ci      this.once('connect', goawayFn);
15201cb0ef41Sopenharmony_ci      return;
15211cb0ef41Sopenharmony_ci    }
15221cb0ef41Sopenharmony_ci    goawayFn();
15231cb0ef41Sopenharmony_ci  }
15241cb0ef41Sopenharmony_ci
15251cb0ef41Sopenharmony_ci  // Destroy the Http2Session, making it no longer usable and cancelling
15261cb0ef41Sopenharmony_ci  // any pending activity.
15271cb0ef41Sopenharmony_ci  destroy(error = NGHTTP2_NO_ERROR, code) {
15281cb0ef41Sopenharmony_ci    if (this.destroyed)
15291cb0ef41Sopenharmony_ci      return;
15301cb0ef41Sopenharmony_ci
15311cb0ef41Sopenharmony_ci    debugSessionObj(this, 'destroying');
15321cb0ef41Sopenharmony_ci
15331cb0ef41Sopenharmony_ci    if (typeof error === 'number') {
15341cb0ef41Sopenharmony_ci      code = error;
15351cb0ef41Sopenharmony_ci      error =
15361cb0ef41Sopenharmony_ci        code !== NGHTTP2_NO_ERROR ?
15371cb0ef41Sopenharmony_ci          new ERR_HTTP2_SESSION_ERROR(code) : undefined;
15381cb0ef41Sopenharmony_ci    }
15391cb0ef41Sopenharmony_ci    if (code === undefined && error != null)
15401cb0ef41Sopenharmony_ci      code = NGHTTP2_INTERNAL_ERROR;
15411cb0ef41Sopenharmony_ci
15421cb0ef41Sopenharmony_ci    closeSession(this, code, error);
15431cb0ef41Sopenharmony_ci  }
15441cb0ef41Sopenharmony_ci
15451cb0ef41Sopenharmony_ci  // Closing the session will:
15461cb0ef41Sopenharmony_ci  // 1. Send a goaway frame
15471cb0ef41Sopenharmony_ci  // 2. Mark the session as closed
15481cb0ef41Sopenharmony_ci  // 3. Prevent new inbound or outbound streams from being opened
15491cb0ef41Sopenharmony_ci  // 4. Optionally register a 'close' event handler
15501cb0ef41Sopenharmony_ci  // 5. Will cause the session to automatically destroy after the
15511cb0ef41Sopenharmony_ci  //    last currently open Http2Stream closes.
15521cb0ef41Sopenharmony_ci  //
15531cb0ef41Sopenharmony_ci  // Close always assumes a good, non-error shutdown (NGHTTP_NO_ERROR)
15541cb0ef41Sopenharmony_ci  //
15551cb0ef41Sopenharmony_ci  // If the session has not connected yet, the closed flag will still be
15561cb0ef41Sopenharmony_ci  // set but the goaway will not be sent until after the connect event
15571cb0ef41Sopenharmony_ci  // is emitted.
15581cb0ef41Sopenharmony_ci  close(callback) {
15591cb0ef41Sopenharmony_ci    if (this.closed || this.destroyed)
15601cb0ef41Sopenharmony_ci      return;
15611cb0ef41Sopenharmony_ci    debugSessionObj(this, 'marking session closed');
15621cb0ef41Sopenharmony_ci    this[kState].flags |= SESSION_FLAGS_CLOSED;
15631cb0ef41Sopenharmony_ci    if (typeof callback === 'function')
15641cb0ef41Sopenharmony_ci      this.once('close', callback);
15651cb0ef41Sopenharmony_ci    this.goaway();
15661cb0ef41Sopenharmony_ci    this[kMaybeDestroy]();
15671cb0ef41Sopenharmony_ci  }
15681cb0ef41Sopenharmony_ci
15691cb0ef41Sopenharmony_ci  [EventEmitter.captureRejectionSymbol](err, event, ...args) {
15701cb0ef41Sopenharmony_ci    switch (event) {
15711cb0ef41Sopenharmony_ci      case 'stream': {
15721cb0ef41Sopenharmony_ci        const stream = args[0];
15731cb0ef41Sopenharmony_ci        stream.destroy(err);
15741cb0ef41Sopenharmony_ci        break;
15751cb0ef41Sopenharmony_ci      }
15761cb0ef41Sopenharmony_ci      default:
15771cb0ef41Sopenharmony_ci        this.destroy(err);
15781cb0ef41Sopenharmony_ci    }
15791cb0ef41Sopenharmony_ci  }
15801cb0ef41Sopenharmony_ci
15811cb0ef41Sopenharmony_ci  // Destroy the session if:
15821cb0ef41Sopenharmony_ci  // * error is not undefined/null
15831cb0ef41Sopenharmony_ci  // * session is closed and there are no more pending or open streams
15841cb0ef41Sopenharmony_ci  [kMaybeDestroy](error) {
15851cb0ef41Sopenharmony_ci    if (error == null) {
15861cb0ef41Sopenharmony_ci      const state = this[kState];
15871cb0ef41Sopenharmony_ci      // Do not destroy if we're not closed and there are pending/open streams
15881cb0ef41Sopenharmony_ci      if (!this.closed ||
15891cb0ef41Sopenharmony_ci          state.streams.size > 0 ||
15901cb0ef41Sopenharmony_ci          state.pendingStreams.size > 0) {
15911cb0ef41Sopenharmony_ci        return;
15921cb0ef41Sopenharmony_ci      }
15931cb0ef41Sopenharmony_ci    }
15941cb0ef41Sopenharmony_ci    this.destroy(error);
15951cb0ef41Sopenharmony_ci  }
15961cb0ef41Sopenharmony_ci
15971cb0ef41Sopenharmony_ci  _onTimeout() {
15981cb0ef41Sopenharmony_ci    callTimeout(this);
15991cb0ef41Sopenharmony_ci  }
16001cb0ef41Sopenharmony_ci
16011cb0ef41Sopenharmony_ci  ref() {
16021cb0ef41Sopenharmony_ci    if (this[kSocket]) {
16031cb0ef41Sopenharmony_ci      this[kSocket].ref();
16041cb0ef41Sopenharmony_ci    }
16051cb0ef41Sopenharmony_ci  }
16061cb0ef41Sopenharmony_ci
16071cb0ef41Sopenharmony_ci  unref() {
16081cb0ef41Sopenharmony_ci    if (this[kSocket]) {
16091cb0ef41Sopenharmony_ci      this[kSocket].unref();
16101cb0ef41Sopenharmony_ci    }
16111cb0ef41Sopenharmony_ci  }
16121cb0ef41Sopenharmony_ci}
16131cb0ef41Sopenharmony_ci
16141cb0ef41Sopenharmony_ci// ServerHttp2Session instances should never have to wait for the socket
16151cb0ef41Sopenharmony_ci// to connect as they are always created after the socket has already been
16161cb0ef41Sopenharmony_ci// established.
16171cb0ef41Sopenharmony_ciclass ServerHttp2Session extends Http2Session {
16181cb0ef41Sopenharmony_ci  constructor(options, socket, server) {
16191cb0ef41Sopenharmony_ci    super(NGHTTP2_SESSION_SERVER, options, socket);
16201cb0ef41Sopenharmony_ci    this[kServer] = server;
16211cb0ef41Sopenharmony_ci    // This is a bit inaccurate because it does not reflect changes to
16221cb0ef41Sopenharmony_ci    // number of listeners made after the session was created. This should
16231cb0ef41Sopenharmony_ci    // not be an issue in practice. Additionally, the 'priority' event on
16241cb0ef41Sopenharmony_ci    // server instances (or any other object) is fully undocumented.
16251cb0ef41Sopenharmony_ci    this[kNativeFields][kSessionPriorityListenerCount] =
16261cb0ef41Sopenharmony_ci      server.listenerCount('priority');
16271cb0ef41Sopenharmony_ci  }
16281cb0ef41Sopenharmony_ci
16291cb0ef41Sopenharmony_ci  get server() {
16301cb0ef41Sopenharmony_ci    return this[kServer];
16311cb0ef41Sopenharmony_ci  }
16321cb0ef41Sopenharmony_ci
16331cb0ef41Sopenharmony_ci  // Submits an altsvc frame to be sent to the client. `stream` is a
16341cb0ef41Sopenharmony_ci  // numeric Stream ID. origin is a URL string that will be used to get
16351cb0ef41Sopenharmony_ci  // the origin. alt is a string containing the altsvc details. No fancy
16361cb0ef41Sopenharmony_ci  // API is provided for that.
16371cb0ef41Sopenharmony_ci  altsvc(alt, originOrStream) {
16381cb0ef41Sopenharmony_ci    if (this.destroyed)
16391cb0ef41Sopenharmony_ci      throw new ERR_HTTP2_INVALID_SESSION();
16401cb0ef41Sopenharmony_ci
16411cb0ef41Sopenharmony_ci    let stream = 0;
16421cb0ef41Sopenharmony_ci    let origin;
16431cb0ef41Sopenharmony_ci
16441cb0ef41Sopenharmony_ci    if (typeof originOrStream === 'string') {
16451cb0ef41Sopenharmony_ci      origin = (new URL(originOrStream)).origin;
16461cb0ef41Sopenharmony_ci      if (origin === 'null')
16471cb0ef41Sopenharmony_ci        throw new ERR_HTTP2_ALTSVC_INVALID_ORIGIN();
16481cb0ef41Sopenharmony_ci    } else if (typeof originOrStream === 'number') {
16491cb0ef41Sopenharmony_ci      if (originOrStream >>> 0 !== originOrStream || originOrStream === 0) {
16501cb0ef41Sopenharmony_ci        throw new ERR_OUT_OF_RANGE('originOrStream',
16511cb0ef41Sopenharmony_ci                                   `> 0 && < ${2 ** 32}`, originOrStream);
16521cb0ef41Sopenharmony_ci      }
16531cb0ef41Sopenharmony_ci      stream = originOrStream;
16541cb0ef41Sopenharmony_ci    } else if (originOrStream !== undefined) {
16551cb0ef41Sopenharmony_ci      // Allow origin to be passed a URL or object with origin property
16561cb0ef41Sopenharmony_ci      if (originOrStream !== null && typeof originOrStream === 'object')
16571cb0ef41Sopenharmony_ci        origin = originOrStream.origin;
16581cb0ef41Sopenharmony_ci      // Note: if originOrStream is an object with an origin property other
16591cb0ef41Sopenharmony_ci      // than a URL, then it is possible that origin will be malformed.
16601cb0ef41Sopenharmony_ci      // We do not verify that here. Users who go that route need to
16611cb0ef41Sopenharmony_ci      // ensure they are doing the right thing or the payload data will
16621cb0ef41Sopenharmony_ci      // be invalid.
16631cb0ef41Sopenharmony_ci      if (typeof origin !== 'string') {
16641cb0ef41Sopenharmony_ci        throw new ERR_INVALID_ARG_TYPE('originOrStream',
16651cb0ef41Sopenharmony_ci                                       ['string', 'number', 'URL', 'object'],
16661cb0ef41Sopenharmony_ci                                       originOrStream);
16671cb0ef41Sopenharmony_ci      } else if (origin === 'null' || origin.length === 0) {
16681cb0ef41Sopenharmony_ci        throw new ERR_HTTP2_ALTSVC_INVALID_ORIGIN();
16691cb0ef41Sopenharmony_ci      }
16701cb0ef41Sopenharmony_ci    }
16711cb0ef41Sopenharmony_ci
16721cb0ef41Sopenharmony_ci    validateString(alt, 'alt');
16731cb0ef41Sopenharmony_ci    if (RegExpPrototypeExec(kQuotedString, alt) === null)
16741cb0ef41Sopenharmony_ci      throw new ERR_INVALID_CHAR('alt');
16751cb0ef41Sopenharmony_ci
16761cb0ef41Sopenharmony_ci    // Max length permitted for ALTSVC
16771cb0ef41Sopenharmony_ci    if ((alt.length + (origin !== undefined ? origin.length : 0)) > kMaxALTSVC)
16781cb0ef41Sopenharmony_ci      throw new ERR_HTTP2_ALTSVC_LENGTH();
16791cb0ef41Sopenharmony_ci
16801cb0ef41Sopenharmony_ci    this[kHandle].altsvc(stream, origin || '', alt);
16811cb0ef41Sopenharmony_ci  }
16821cb0ef41Sopenharmony_ci
16831cb0ef41Sopenharmony_ci  // Submits an origin frame to be sent.
16841cb0ef41Sopenharmony_ci  origin(...origins) {
16851cb0ef41Sopenharmony_ci    if (this.destroyed)
16861cb0ef41Sopenharmony_ci      throw new ERR_HTTP2_INVALID_SESSION();
16871cb0ef41Sopenharmony_ci
16881cb0ef41Sopenharmony_ci    if (origins.length === 0)
16891cb0ef41Sopenharmony_ci      return;
16901cb0ef41Sopenharmony_ci
16911cb0ef41Sopenharmony_ci    let arr = '';
16921cb0ef41Sopenharmony_ci    let len = 0;
16931cb0ef41Sopenharmony_ci    const count = origins.length;
16941cb0ef41Sopenharmony_ci    for (let i = 0; i < count; i++) {
16951cb0ef41Sopenharmony_ci      let origin = origins[i];
16961cb0ef41Sopenharmony_ci      if (typeof origin === 'string') {
16971cb0ef41Sopenharmony_ci        origin = (new URL(origin)).origin;
16981cb0ef41Sopenharmony_ci      } else if (origin != null && typeof origin === 'object') {
16991cb0ef41Sopenharmony_ci        origin = origin.origin;
17001cb0ef41Sopenharmony_ci      }
17011cb0ef41Sopenharmony_ci      validateString(origin, 'origin');
17021cb0ef41Sopenharmony_ci      if (origin === 'null')
17031cb0ef41Sopenharmony_ci        throw new ERR_HTTP2_INVALID_ORIGIN();
17041cb0ef41Sopenharmony_ci
17051cb0ef41Sopenharmony_ci      arr += `${origin}\0`;
17061cb0ef41Sopenharmony_ci      len += origin.length;
17071cb0ef41Sopenharmony_ci    }
17081cb0ef41Sopenharmony_ci
17091cb0ef41Sopenharmony_ci    if (len > kMaxALTSVC)
17101cb0ef41Sopenharmony_ci      throw new ERR_HTTP2_ORIGIN_LENGTH();
17111cb0ef41Sopenharmony_ci
17121cb0ef41Sopenharmony_ci    this[kHandle].origin(arr, count);
17131cb0ef41Sopenharmony_ci  }
17141cb0ef41Sopenharmony_ci
17151cb0ef41Sopenharmony_ci}
17161cb0ef41Sopenharmony_ci
17171cb0ef41Sopenharmony_ci// ClientHttp2Session instances have to wait for the socket to connect after
17181cb0ef41Sopenharmony_ci// they have been created. Various operations such as request() may be used,
17191cb0ef41Sopenharmony_ci// but the actual protocol communication will only occur after the socket
17201cb0ef41Sopenharmony_ci// has been connected.
17211cb0ef41Sopenharmony_ciclass ClientHttp2Session extends Http2Session {
17221cb0ef41Sopenharmony_ci  constructor(options, socket) {
17231cb0ef41Sopenharmony_ci    super(NGHTTP2_SESSION_CLIENT, options, socket);
17241cb0ef41Sopenharmony_ci    this[kPendingRequestCalls] = null;
17251cb0ef41Sopenharmony_ci  }
17261cb0ef41Sopenharmony_ci
17271cb0ef41Sopenharmony_ci  // Submits a new HTTP2 request to the connected peer. Returns the
17281cb0ef41Sopenharmony_ci  // associated Http2Stream instance.
17291cb0ef41Sopenharmony_ci  request(headers, options) {
17301cb0ef41Sopenharmony_ci    debugSessionObj(this, 'initiating request');
17311cb0ef41Sopenharmony_ci
17321cb0ef41Sopenharmony_ci    if (this.destroyed)
17331cb0ef41Sopenharmony_ci      throw new ERR_HTTP2_INVALID_SESSION();
17341cb0ef41Sopenharmony_ci
17351cb0ef41Sopenharmony_ci    if (this.closed)
17361cb0ef41Sopenharmony_ci      throw new ERR_HTTP2_GOAWAY_SESSION();
17371cb0ef41Sopenharmony_ci
17381cb0ef41Sopenharmony_ci    this[kUpdateTimer]();
17391cb0ef41Sopenharmony_ci
17401cb0ef41Sopenharmony_ci    if (headers !== null && headers !== undefined) {
17411cb0ef41Sopenharmony_ci      const keys = ObjectKeys(headers);
17421cb0ef41Sopenharmony_ci      for (let i = 0; i < keys.length; i++) {
17431cb0ef41Sopenharmony_ci        const header = keys[i];
17441cb0ef41Sopenharmony_ci        if (header[0] === ':') {
17451cb0ef41Sopenharmony_ci          assertValidPseudoHeader(header);
17461cb0ef41Sopenharmony_ci        } else if (header && !checkIsHttpToken(header))
17471cb0ef41Sopenharmony_ci          this.destroy(new ERR_INVALID_HTTP_TOKEN('Header name', header));
17481cb0ef41Sopenharmony_ci      }
17491cb0ef41Sopenharmony_ci    }
17501cb0ef41Sopenharmony_ci
17511cb0ef41Sopenharmony_ci    assertIsObject(headers, 'headers');
17521cb0ef41Sopenharmony_ci    assertIsObject(options, 'options');
17531cb0ef41Sopenharmony_ci
17541cb0ef41Sopenharmony_ci    headers = ObjectAssign(ObjectCreate(null), headers);
17551cb0ef41Sopenharmony_ci    options = { ...options };
17561cb0ef41Sopenharmony_ci
17571cb0ef41Sopenharmony_ci    if (headers[HTTP2_HEADER_METHOD] === undefined)
17581cb0ef41Sopenharmony_ci      headers[HTTP2_HEADER_METHOD] = HTTP2_METHOD_GET;
17591cb0ef41Sopenharmony_ci
17601cb0ef41Sopenharmony_ci    const connect = headers[HTTP2_HEADER_METHOD] === HTTP2_METHOD_CONNECT;
17611cb0ef41Sopenharmony_ci
17621cb0ef41Sopenharmony_ci    if (!connect || headers[HTTP2_HEADER_PROTOCOL] !== undefined) {
17631cb0ef41Sopenharmony_ci      if (getAuthority(headers) === undefined)
17641cb0ef41Sopenharmony_ci        headers[HTTP2_HEADER_AUTHORITY] = this[kAuthority];
17651cb0ef41Sopenharmony_ci      if (headers[HTTP2_HEADER_SCHEME] === undefined)
17661cb0ef41Sopenharmony_ci        headers[HTTP2_HEADER_SCHEME] = StringPrototypeSlice(this[kProtocol],
17671cb0ef41Sopenharmony_ci                                                            0, -1);
17681cb0ef41Sopenharmony_ci      if (headers[HTTP2_HEADER_PATH] === undefined)
17691cb0ef41Sopenharmony_ci        headers[HTTP2_HEADER_PATH] = '/';
17701cb0ef41Sopenharmony_ci    } else {
17711cb0ef41Sopenharmony_ci      if (headers[HTTP2_HEADER_AUTHORITY] === undefined)
17721cb0ef41Sopenharmony_ci        throw new ERR_HTTP2_CONNECT_AUTHORITY();
17731cb0ef41Sopenharmony_ci      if (headers[HTTP2_HEADER_SCHEME] !== undefined)
17741cb0ef41Sopenharmony_ci        throw new ERR_HTTP2_CONNECT_SCHEME();
17751cb0ef41Sopenharmony_ci      if (headers[HTTP2_HEADER_PATH] !== undefined)
17761cb0ef41Sopenharmony_ci        throw new ERR_HTTP2_CONNECT_PATH();
17771cb0ef41Sopenharmony_ci    }
17781cb0ef41Sopenharmony_ci
17791cb0ef41Sopenharmony_ci    setAndValidatePriorityOptions(options);
17801cb0ef41Sopenharmony_ci
17811cb0ef41Sopenharmony_ci    if (options.endStream === undefined) {
17821cb0ef41Sopenharmony_ci      // For some methods, we know that a payload is meaningless, so end the
17831cb0ef41Sopenharmony_ci      // stream by default if the user has not specifically indicated a
17841cb0ef41Sopenharmony_ci      // preference.
17851cb0ef41Sopenharmony_ci      options.endStream = isPayloadMeaningless(headers[HTTP2_HEADER_METHOD]);
17861cb0ef41Sopenharmony_ci    } else if (typeof options.endStream !== 'boolean') {
17871cb0ef41Sopenharmony_ci      throw new ERR_INVALID_ARG_VALUE('options.endStream', options.endStream);
17881cb0ef41Sopenharmony_ci    }
17891cb0ef41Sopenharmony_ci
17901cb0ef41Sopenharmony_ci    const headersList = mapToHeaders(headers);
17911cb0ef41Sopenharmony_ci
17921cb0ef41Sopenharmony_ci    // eslint-disable-next-line no-use-before-define
17931cb0ef41Sopenharmony_ci    const stream = new ClientHttp2Stream(this, undefined, undefined, {});
17941cb0ef41Sopenharmony_ci    stream[kSentHeaders] = headers;
17951cb0ef41Sopenharmony_ci    stream[kOrigin] = `${headers[HTTP2_HEADER_SCHEME]}://` +
17961cb0ef41Sopenharmony_ci                      `${getAuthority(headers)}`;
17971cb0ef41Sopenharmony_ci
17981cb0ef41Sopenharmony_ci    // Close the writable side of the stream if options.endStream is set.
17991cb0ef41Sopenharmony_ci    if (options.endStream)
18001cb0ef41Sopenharmony_ci      stream.end();
18011cb0ef41Sopenharmony_ci
18021cb0ef41Sopenharmony_ci    if (options.waitForTrailers)
18031cb0ef41Sopenharmony_ci      stream[kState].flags |= STREAM_FLAGS_HAS_TRAILERS;
18041cb0ef41Sopenharmony_ci
18051cb0ef41Sopenharmony_ci    const { signal } = options;
18061cb0ef41Sopenharmony_ci    if (signal) {
18071cb0ef41Sopenharmony_ci      validateAbortSignal(signal, 'options.signal');
18081cb0ef41Sopenharmony_ci      const aborter = () => {
18091cb0ef41Sopenharmony_ci        stream.destroy(new AbortError(undefined, { cause: signal.reason }));
18101cb0ef41Sopenharmony_ci      };
18111cb0ef41Sopenharmony_ci      if (signal.aborted) {
18121cb0ef41Sopenharmony_ci        aborter();
18131cb0ef41Sopenharmony_ci      } else {
18141cb0ef41Sopenharmony_ci        const disposable = EventEmitter.addAbortListener(signal, aborter);
18151cb0ef41Sopenharmony_ci        stream.once('close', disposable[SymbolDispose]);
18161cb0ef41Sopenharmony_ci      }
18171cb0ef41Sopenharmony_ci    }
18181cb0ef41Sopenharmony_ci
18191cb0ef41Sopenharmony_ci    const onConnect = FunctionPrototypeBind(requestOnConnect,
18201cb0ef41Sopenharmony_ci                                            stream, headersList, options);
18211cb0ef41Sopenharmony_ci    if (this.connecting) {
18221cb0ef41Sopenharmony_ci      if (this[kPendingRequestCalls] !== null) {
18231cb0ef41Sopenharmony_ci        ArrayPrototypePush(this[kPendingRequestCalls], onConnect);
18241cb0ef41Sopenharmony_ci      } else {
18251cb0ef41Sopenharmony_ci        this[kPendingRequestCalls] = [onConnect];
18261cb0ef41Sopenharmony_ci        this.once('connect', () => {
18271cb0ef41Sopenharmony_ci          ArrayPrototypeForEach(this[kPendingRequestCalls], (f) => f());
18281cb0ef41Sopenharmony_ci          this[kPendingRequestCalls] = null;
18291cb0ef41Sopenharmony_ci        });
18301cb0ef41Sopenharmony_ci      }
18311cb0ef41Sopenharmony_ci    } else {
18321cb0ef41Sopenharmony_ci      onConnect();
18331cb0ef41Sopenharmony_ci    }
18341cb0ef41Sopenharmony_ci    return stream;
18351cb0ef41Sopenharmony_ci  }
18361cb0ef41Sopenharmony_ci}
18371cb0ef41Sopenharmony_ci
18381cb0ef41Sopenharmony_cifunction trackWriteState(stream, bytes) {
18391cb0ef41Sopenharmony_ci  const session = stream[kSession];
18401cb0ef41Sopenharmony_ci  stream[kState].writeQueueSize += bytes;
18411cb0ef41Sopenharmony_ci  session[kState].writeQueueSize += bytes;
18421cb0ef41Sopenharmony_ci  session[kHandle].chunksSentSinceLastWrite = 0;
18431cb0ef41Sopenharmony_ci}
18441cb0ef41Sopenharmony_ci
18451cb0ef41Sopenharmony_cifunction streamOnResume() {
18461cb0ef41Sopenharmony_ci  if (!this.destroyed)
18471cb0ef41Sopenharmony_ci    this[kHandle].readStart();
18481cb0ef41Sopenharmony_ci}
18491cb0ef41Sopenharmony_ci
18501cb0ef41Sopenharmony_cifunction streamOnPause() {
18511cb0ef41Sopenharmony_ci  if (!this.destroyed && !this.pending)
18521cb0ef41Sopenharmony_ci    this[kHandle].readStop();
18531cb0ef41Sopenharmony_ci}
18541cb0ef41Sopenharmony_ci
18551cb0ef41Sopenharmony_cifunction afterShutdown(status) {
18561cb0ef41Sopenharmony_ci  const stream = this.handle[kOwner];
18571cb0ef41Sopenharmony_ci  if (stream) {
18581cb0ef41Sopenharmony_ci    stream.on('finish', () => {
18591cb0ef41Sopenharmony_ci      stream[kMaybeDestroy]();
18601cb0ef41Sopenharmony_ci    });
18611cb0ef41Sopenharmony_ci  }
18621cb0ef41Sopenharmony_ci  // Currently this status value is unused
18631cb0ef41Sopenharmony_ci  this.callback();
18641cb0ef41Sopenharmony_ci}
18651cb0ef41Sopenharmony_ci
18661cb0ef41Sopenharmony_cifunction shutdownWritable(callback) {
18671cb0ef41Sopenharmony_ci  const handle = this[kHandle];
18681cb0ef41Sopenharmony_ci  if (!handle) return callback();
18691cb0ef41Sopenharmony_ci  const state = this[kState];
18701cb0ef41Sopenharmony_ci  if (state.shutdownWritableCalled) {
18711cb0ef41Sopenharmony_ci    debugStreamObj(this, 'shutdownWritable() already called');
18721cb0ef41Sopenharmony_ci    return callback();
18731cb0ef41Sopenharmony_ci  }
18741cb0ef41Sopenharmony_ci  state.shutdownWritableCalled = true;
18751cb0ef41Sopenharmony_ci
18761cb0ef41Sopenharmony_ci  const req = new ShutdownWrap();
18771cb0ef41Sopenharmony_ci  req.oncomplete = afterShutdown;
18781cb0ef41Sopenharmony_ci  req.callback = callback;
18791cb0ef41Sopenharmony_ci  req.handle = handle;
18801cb0ef41Sopenharmony_ci  const err = handle.shutdown(req);
18811cb0ef41Sopenharmony_ci  if (err === 1)  // synchronous finish
18821cb0ef41Sopenharmony_ci    return ReflectApply(afterShutdown, req, [0]);
18831cb0ef41Sopenharmony_ci}
18841cb0ef41Sopenharmony_ci
18851cb0ef41Sopenharmony_cifunction finishSendTrailers(stream, headersList) {
18861cb0ef41Sopenharmony_ci  // The stream might be destroyed and in that case
18871cb0ef41Sopenharmony_ci  // there is nothing to do.
18881cb0ef41Sopenharmony_ci  // This can happen because finishSendTrailers is
18891cb0ef41Sopenharmony_ci  // scheduled via setImmediate.
18901cb0ef41Sopenharmony_ci  if (stream.destroyed) {
18911cb0ef41Sopenharmony_ci    return;
18921cb0ef41Sopenharmony_ci  }
18931cb0ef41Sopenharmony_ci
18941cb0ef41Sopenharmony_ci  stream[kState].flags &= ~STREAM_FLAGS_HAS_TRAILERS;
18951cb0ef41Sopenharmony_ci
18961cb0ef41Sopenharmony_ci  const ret = stream[kHandle].trailers(headersList);
18971cb0ef41Sopenharmony_ci  if (ret < 0)
18981cb0ef41Sopenharmony_ci    stream.destroy(new NghttpError(ret));
18991cb0ef41Sopenharmony_ci  else
19001cb0ef41Sopenharmony_ci    stream[kMaybeDestroy]();
19011cb0ef41Sopenharmony_ci}
19021cb0ef41Sopenharmony_ci
19031cb0ef41Sopenharmony_ciconst kNoRstStream = 0;
19041cb0ef41Sopenharmony_ciconst kSubmitRstStream = 1;
19051cb0ef41Sopenharmony_ciconst kForceRstStream = 2;
19061cb0ef41Sopenharmony_ci
19071cb0ef41Sopenharmony_cifunction closeStream(stream, code, rstStreamStatus = kSubmitRstStream) {
19081cb0ef41Sopenharmony_ci  const state = stream[kState];
19091cb0ef41Sopenharmony_ci  state.flags |= STREAM_FLAGS_CLOSED;
19101cb0ef41Sopenharmony_ci  state.rstCode = code;
19111cb0ef41Sopenharmony_ci
19121cb0ef41Sopenharmony_ci  // Clear timeout and remove timeout listeners
19131cb0ef41Sopenharmony_ci  stream.setTimeout(0);
19141cb0ef41Sopenharmony_ci  stream.removeAllListeners('timeout');
19151cb0ef41Sopenharmony_ci
19161cb0ef41Sopenharmony_ci  const { ending } = stream._writableState;
19171cb0ef41Sopenharmony_ci
19181cb0ef41Sopenharmony_ci  if (!ending) {
19191cb0ef41Sopenharmony_ci    // If the writable side of the Http2Stream is still open, emit the
19201cb0ef41Sopenharmony_ci    // 'aborted' event and set the aborted flag.
19211cb0ef41Sopenharmony_ci    if (!stream.aborted) {
19221cb0ef41Sopenharmony_ci      state.flags |= STREAM_FLAGS_ABORTED;
19231cb0ef41Sopenharmony_ci      stream.emit('aborted');
19241cb0ef41Sopenharmony_ci    }
19251cb0ef41Sopenharmony_ci
19261cb0ef41Sopenharmony_ci    // Close the writable side.
19271cb0ef41Sopenharmony_ci    stream.end();
19281cb0ef41Sopenharmony_ci  }
19291cb0ef41Sopenharmony_ci
19301cb0ef41Sopenharmony_ci  if (rstStreamStatus !== kNoRstStream) {
19311cb0ef41Sopenharmony_ci    const finishFn = FunctionPrototypeBind(finishCloseStream, stream, code);
19321cb0ef41Sopenharmony_ci    if (!ending || stream.writableFinished || code !== NGHTTP2_NO_ERROR ||
19331cb0ef41Sopenharmony_ci        rstStreamStatus === kForceRstStream)
19341cb0ef41Sopenharmony_ci      finishFn();
19351cb0ef41Sopenharmony_ci    else
19361cb0ef41Sopenharmony_ci      stream.once('finish', finishFn);
19371cb0ef41Sopenharmony_ci  }
19381cb0ef41Sopenharmony_ci}
19391cb0ef41Sopenharmony_ci
19401cb0ef41Sopenharmony_cifunction finishCloseStream(code) {
19411cb0ef41Sopenharmony_ci  const rstStreamFn = FunctionPrototypeBind(submitRstStream, this, code);
19421cb0ef41Sopenharmony_ci  // If the handle has not yet been assigned, queue up the request to
19431cb0ef41Sopenharmony_ci  // ensure that the RST_STREAM frame is sent after the stream ID has
19441cb0ef41Sopenharmony_ci  // been determined.
19451cb0ef41Sopenharmony_ci  if (this.pending) {
19461cb0ef41Sopenharmony_ci    this.push(null);
19471cb0ef41Sopenharmony_ci    this.once('ready', rstStreamFn);
19481cb0ef41Sopenharmony_ci    return;
19491cb0ef41Sopenharmony_ci  }
19501cb0ef41Sopenharmony_ci  rstStreamFn();
19511cb0ef41Sopenharmony_ci}
19521cb0ef41Sopenharmony_ci
19531cb0ef41Sopenharmony_ci// An Http2Stream is a Duplex stream that is backed by a
19541cb0ef41Sopenharmony_ci// node::http2::Http2Stream handle implementing StreamBase.
19551cb0ef41Sopenharmony_ciclass Http2Stream extends Duplex {
19561cb0ef41Sopenharmony_ci  constructor(session, options) {
19571cb0ef41Sopenharmony_ci    options.allowHalfOpen = true;
19581cb0ef41Sopenharmony_ci    options.decodeStrings = false;
19591cb0ef41Sopenharmony_ci    options.autoDestroy = false;
19601cb0ef41Sopenharmony_ci    super(options);
19611cb0ef41Sopenharmony_ci    this[async_id_symbol] = -1;
19621cb0ef41Sopenharmony_ci
19631cb0ef41Sopenharmony_ci    // Corking the stream automatically allows writes to happen
19641cb0ef41Sopenharmony_ci    // but ensures that those are buffered until the handle has
19651cb0ef41Sopenharmony_ci    // been assigned.
19661cb0ef41Sopenharmony_ci    this.cork();
19671cb0ef41Sopenharmony_ci    this[kSession] = session;
19681cb0ef41Sopenharmony_ci    session[kState].pendingStreams.add(this);
19691cb0ef41Sopenharmony_ci
19701cb0ef41Sopenharmony_ci    // Allow our logic for determining whether any reads have happened to
19711cb0ef41Sopenharmony_ci    // work in all situations. This is similar to what we do in _http_incoming.
19721cb0ef41Sopenharmony_ci    this._readableState.readingMore = true;
19731cb0ef41Sopenharmony_ci
19741cb0ef41Sopenharmony_ci    this[kTimeout] = null;
19751cb0ef41Sopenharmony_ci
19761cb0ef41Sopenharmony_ci    this[kState] = {
19771cb0ef41Sopenharmony_ci      didRead: false,
19781cb0ef41Sopenharmony_ci      flags: STREAM_FLAGS_PENDING,
19791cb0ef41Sopenharmony_ci      rstCode: NGHTTP2_NO_ERROR,
19801cb0ef41Sopenharmony_ci      writeQueueSize: 0,
19811cb0ef41Sopenharmony_ci      trailersReady: false,
19821cb0ef41Sopenharmony_ci      endAfterHeaders: false,
19831cb0ef41Sopenharmony_ci    };
19841cb0ef41Sopenharmony_ci
19851cb0ef41Sopenharmony_ci    // Fields used by the compat API to avoid megamorphisms.
19861cb0ef41Sopenharmony_ci    this[kRequest] = null;
19871cb0ef41Sopenharmony_ci    this[kProxySocket] = null;
19881cb0ef41Sopenharmony_ci
19891cb0ef41Sopenharmony_ci    this.on('pause', streamOnPause);
19901cb0ef41Sopenharmony_ci
19911cb0ef41Sopenharmony_ci    this.on('newListener', streamListenerAdded);
19921cb0ef41Sopenharmony_ci    this.on('removeListener', streamListenerRemoved);
19931cb0ef41Sopenharmony_ci  }
19941cb0ef41Sopenharmony_ci
19951cb0ef41Sopenharmony_ci  [kUpdateTimer]() {
19961cb0ef41Sopenharmony_ci    if (this.destroyed)
19971cb0ef41Sopenharmony_ci      return;
19981cb0ef41Sopenharmony_ci    if (this[kTimeout])
19991cb0ef41Sopenharmony_ci      this[kTimeout].refresh();
20001cb0ef41Sopenharmony_ci    if (this[kSession])
20011cb0ef41Sopenharmony_ci      this[kSession][kUpdateTimer]();
20021cb0ef41Sopenharmony_ci  }
20031cb0ef41Sopenharmony_ci
20041cb0ef41Sopenharmony_ci  [kInit](id, handle) {
20051cb0ef41Sopenharmony_ci    const state = this[kState];
20061cb0ef41Sopenharmony_ci    state.flags |= STREAM_FLAGS_READY;
20071cb0ef41Sopenharmony_ci
20081cb0ef41Sopenharmony_ci    const session = this[kSession];
20091cb0ef41Sopenharmony_ci    session[kState].pendingStreams.delete(this);
20101cb0ef41Sopenharmony_ci    session[kState].streams.set(id, this);
20111cb0ef41Sopenharmony_ci
20121cb0ef41Sopenharmony_ci    this[kID] = id;
20131cb0ef41Sopenharmony_ci    this[async_id_symbol] = handle.getAsyncId();
20141cb0ef41Sopenharmony_ci    handle[kOwner] = this;
20151cb0ef41Sopenharmony_ci    this[kHandle] = handle;
20161cb0ef41Sopenharmony_ci    handle.onread = onStreamRead;
20171cb0ef41Sopenharmony_ci    this.uncork();
20181cb0ef41Sopenharmony_ci    this.emit('ready');
20191cb0ef41Sopenharmony_ci  }
20201cb0ef41Sopenharmony_ci
20211cb0ef41Sopenharmony_ci  [kInspect](depth, opts) {
20221cb0ef41Sopenharmony_ci    if (typeof depth === 'number' && depth < 0)
20231cb0ef41Sopenharmony_ci      return this;
20241cb0ef41Sopenharmony_ci
20251cb0ef41Sopenharmony_ci    const obj = {
20261cb0ef41Sopenharmony_ci      id: this[kID] || '<pending>',
20271cb0ef41Sopenharmony_ci      closed: this.closed,
20281cb0ef41Sopenharmony_ci      destroyed: this.destroyed,
20291cb0ef41Sopenharmony_ci      state: this.state,
20301cb0ef41Sopenharmony_ci      readableState: this._readableState,
20311cb0ef41Sopenharmony_ci      writableState: this._writableState,
20321cb0ef41Sopenharmony_ci    };
20331cb0ef41Sopenharmony_ci    return `Http2Stream ${format(obj)}`;
20341cb0ef41Sopenharmony_ci  }
20351cb0ef41Sopenharmony_ci
20361cb0ef41Sopenharmony_ci  get bufferSize() {
20371cb0ef41Sopenharmony_ci    // `bufferSize` properties of `net.Socket` are `undefined` when
20381cb0ef41Sopenharmony_ci    // their `_handle` are falsy. Here we avoid the behavior.
20391cb0ef41Sopenharmony_ci    return this[kState].writeQueueSize + this.writableLength;
20401cb0ef41Sopenharmony_ci  }
20411cb0ef41Sopenharmony_ci
20421cb0ef41Sopenharmony_ci  get endAfterHeaders() {
20431cb0ef41Sopenharmony_ci    return this[kState].endAfterHeaders;
20441cb0ef41Sopenharmony_ci  }
20451cb0ef41Sopenharmony_ci
20461cb0ef41Sopenharmony_ci  get sentHeaders() {
20471cb0ef41Sopenharmony_ci    return this[kSentHeaders];
20481cb0ef41Sopenharmony_ci  }
20491cb0ef41Sopenharmony_ci
20501cb0ef41Sopenharmony_ci  get sentTrailers() {
20511cb0ef41Sopenharmony_ci    return this[kSentTrailers];
20521cb0ef41Sopenharmony_ci  }
20531cb0ef41Sopenharmony_ci
20541cb0ef41Sopenharmony_ci  get sentInfoHeaders() {
20551cb0ef41Sopenharmony_ci    return this[kInfoHeaders];
20561cb0ef41Sopenharmony_ci  }
20571cb0ef41Sopenharmony_ci
20581cb0ef41Sopenharmony_ci  get pending() {
20591cb0ef41Sopenharmony_ci    return this[kID] === undefined;
20601cb0ef41Sopenharmony_ci  }
20611cb0ef41Sopenharmony_ci
20621cb0ef41Sopenharmony_ci  // The id of the Http2Stream, will be undefined if the socket is not
20631cb0ef41Sopenharmony_ci  // yet connected.
20641cb0ef41Sopenharmony_ci  get id() {
20651cb0ef41Sopenharmony_ci    return this[kID];
20661cb0ef41Sopenharmony_ci  }
20671cb0ef41Sopenharmony_ci
20681cb0ef41Sopenharmony_ci  // The Http2Session that owns this Http2Stream.
20691cb0ef41Sopenharmony_ci  get session() {
20701cb0ef41Sopenharmony_ci    return this[kSession];
20711cb0ef41Sopenharmony_ci  }
20721cb0ef41Sopenharmony_ci
20731cb0ef41Sopenharmony_ci  _onTimeout() {
20741cb0ef41Sopenharmony_ci    callTimeout(this, kSession);
20751cb0ef41Sopenharmony_ci  }
20761cb0ef41Sopenharmony_ci
20771cb0ef41Sopenharmony_ci  // True if the HEADERS frame has been sent
20781cb0ef41Sopenharmony_ci  get headersSent() {
20791cb0ef41Sopenharmony_ci    return !!(this[kState].flags & STREAM_FLAGS_HEADERS_SENT);
20801cb0ef41Sopenharmony_ci  }
20811cb0ef41Sopenharmony_ci
20821cb0ef41Sopenharmony_ci  // True if the Http2Stream was aborted abnormally.
20831cb0ef41Sopenharmony_ci  get aborted() {
20841cb0ef41Sopenharmony_ci    return !!(this[kState].flags & STREAM_FLAGS_ABORTED);
20851cb0ef41Sopenharmony_ci  }
20861cb0ef41Sopenharmony_ci
20871cb0ef41Sopenharmony_ci  // True if dealing with a HEAD request
20881cb0ef41Sopenharmony_ci  get headRequest() {
20891cb0ef41Sopenharmony_ci    return !!(this[kState].flags & STREAM_FLAGS_HEAD_REQUEST);
20901cb0ef41Sopenharmony_ci  }
20911cb0ef41Sopenharmony_ci
20921cb0ef41Sopenharmony_ci  // The error code reported when this Http2Stream was closed.
20931cb0ef41Sopenharmony_ci  get rstCode() {
20941cb0ef41Sopenharmony_ci    return this[kState].rstCode;
20951cb0ef41Sopenharmony_ci  }
20961cb0ef41Sopenharmony_ci
20971cb0ef41Sopenharmony_ci  // State information for the Http2Stream
20981cb0ef41Sopenharmony_ci  get state() {
20991cb0ef41Sopenharmony_ci    const id = this[kID];
21001cb0ef41Sopenharmony_ci    if (this.destroyed || id === undefined)
21011cb0ef41Sopenharmony_ci      return {};
21021cb0ef41Sopenharmony_ci    return getStreamState(this[kHandle], id);
21031cb0ef41Sopenharmony_ci  }
21041cb0ef41Sopenharmony_ci
21051cb0ef41Sopenharmony_ci  [kProceed]() {
21061cb0ef41Sopenharmony_ci    assert.fail('Implementors MUST implement this. Please report this as a ' +
21071cb0ef41Sopenharmony_ci                'bug in Node.js');
21081cb0ef41Sopenharmony_ci  }
21091cb0ef41Sopenharmony_ci
21101cb0ef41Sopenharmony_ci  [kAfterAsyncWrite]({ bytes }) {
21111cb0ef41Sopenharmony_ci    this[kState].writeQueueSize -= bytes;
21121cb0ef41Sopenharmony_ci
21131cb0ef41Sopenharmony_ci    if (this.session !== undefined)
21141cb0ef41Sopenharmony_ci      this.session[kState].writeQueueSize -= bytes;
21151cb0ef41Sopenharmony_ci  }
21161cb0ef41Sopenharmony_ci
21171cb0ef41Sopenharmony_ci  [kWriteGeneric](writev, data, encoding, cb) {
21181cb0ef41Sopenharmony_ci    // When the Http2Stream is first created, it is corked until the
21191cb0ef41Sopenharmony_ci    // handle and the stream ID is assigned. However, if the user calls
21201cb0ef41Sopenharmony_ci    // uncork() before that happens, the Duplex will attempt to pass
21211cb0ef41Sopenharmony_ci    // writes through. Those need to be queued up here.
21221cb0ef41Sopenharmony_ci    if (this.pending) {
21231cb0ef41Sopenharmony_ci      this.once(
21241cb0ef41Sopenharmony_ci        'ready',
21251cb0ef41Sopenharmony_ci        FunctionPrototypeBind(this[kWriteGeneric],
21261cb0ef41Sopenharmony_ci                              this, writev, data, encoding, cb),
21271cb0ef41Sopenharmony_ci      );
21281cb0ef41Sopenharmony_ci      return;
21291cb0ef41Sopenharmony_ci    }
21301cb0ef41Sopenharmony_ci
21311cb0ef41Sopenharmony_ci    // If the stream has been destroyed, there's nothing else we can do
21321cb0ef41Sopenharmony_ci    // because the handle has been destroyed. This should only be an
21331cb0ef41Sopenharmony_ci    // issue if a write occurs before the 'ready' event in the case where
21341cb0ef41Sopenharmony_ci    // the duplex is uncorked before the stream is ready to go. In that
21351cb0ef41Sopenharmony_ci    // case, drop the data on the floor. An error should have already been
21361cb0ef41Sopenharmony_ci    // emitted.
21371cb0ef41Sopenharmony_ci    if (this.destroyed)
21381cb0ef41Sopenharmony_ci      return;
21391cb0ef41Sopenharmony_ci
21401cb0ef41Sopenharmony_ci    this[kUpdateTimer]();
21411cb0ef41Sopenharmony_ci    if (!this.headersSent)
21421cb0ef41Sopenharmony_ci      this[kProceed]();
21431cb0ef41Sopenharmony_ci
21441cb0ef41Sopenharmony_ci    let req;
21451cb0ef41Sopenharmony_ci
21461cb0ef41Sopenharmony_ci    let waitingForWriteCallback = true;
21471cb0ef41Sopenharmony_ci    let waitingForEndCheck = true;
21481cb0ef41Sopenharmony_ci    let writeCallbackErr;
21491cb0ef41Sopenharmony_ci    let endCheckCallbackErr;
21501cb0ef41Sopenharmony_ci    const done = () => {
21511cb0ef41Sopenharmony_ci      if (waitingForEndCheck || waitingForWriteCallback) return;
21521cb0ef41Sopenharmony_ci      const err = aggregateTwoErrors(endCheckCallbackErr, writeCallbackErr);
21531cb0ef41Sopenharmony_ci      // writeGeneric does not destroy on error and
21541cb0ef41Sopenharmony_ci      // we cannot enable autoDestroy,
21551cb0ef41Sopenharmony_ci      // so make sure to destroy on error.
21561cb0ef41Sopenharmony_ci      if (err) {
21571cb0ef41Sopenharmony_ci        this.destroy(err);
21581cb0ef41Sopenharmony_ci      }
21591cb0ef41Sopenharmony_ci      cb(err);
21601cb0ef41Sopenharmony_ci    };
21611cb0ef41Sopenharmony_ci    const writeCallback = (err) => {
21621cb0ef41Sopenharmony_ci      waitingForWriteCallback = false;
21631cb0ef41Sopenharmony_ci      writeCallbackErr = err;
21641cb0ef41Sopenharmony_ci      done();
21651cb0ef41Sopenharmony_ci    };
21661cb0ef41Sopenharmony_ci    const endCheckCallback = (err) => {
21671cb0ef41Sopenharmony_ci      waitingForEndCheck = false;
21681cb0ef41Sopenharmony_ci      endCheckCallbackErr = err;
21691cb0ef41Sopenharmony_ci      done();
21701cb0ef41Sopenharmony_ci    };
21711cb0ef41Sopenharmony_ci    // Shutdown write stream right after last chunk is sent
21721cb0ef41Sopenharmony_ci    // so final DATA frame can include END_STREAM flag
21731cb0ef41Sopenharmony_ci    process.nextTick(() => {
21741cb0ef41Sopenharmony_ci      if (writeCallbackErr ||
21751cb0ef41Sopenharmony_ci        !this._writableState.ending ||
21761cb0ef41Sopenharmony_ci        this._writableState.buffered.length ||
21771cb0ef41Sopenharmony_ci        (this[kState].flags & STREAM_FLAGS_HAS_TRAILERS))
21781cb0ef41Sopenharmony_ci        return endCheckCallback();
21791cb0ef41Sopenharmony_ci      debugStreamObj(this, 'shutting down writable on last write');
21801cb0ef41Sopenharmony_ci      shutdownWritable.call(this, endCheckCallback);
21811cb0ef41Sopenharmony_ci    });
21821cb0ef41Sopenharmony_ci
21831cb0ef41Sopenharmony_ci    if (writev)
21841cb0ef41Sopenharmony_ci      req = writevGeneric(this, data, writeCallback);
21851cb0ef41Sopenharmony_ci    else
21861cb0ef41Sopenharmony_ci      req = writeGeneric(this, data, encoding, writeCallback);
21871cb0ef41Sopenharmony_ci
21881cb0ef41Sopenharmony_ci    trackWriteState(this, req.bytes);
21891cb0ef41Sopenharmony_ci  }
21901cb0ef41Sopenharmony_ci
21911cb0ef41Sopenharmony_ci  _write(data, encoding, cb) {
21921cb0ef41Sopenharmony_ci    this[kWriteGeneric](false, data, encoding, cb);
21931cb0ef41Sopenharmony_ci  }
21941cb0ef41Sopenharmony_ci
21951cb0ef41Sopenharmony_ci  _writev(data, cb) {
21961cb0ef41Sopenharmony_ci    this[kWriteGeneric](true, data, '', cb);
21971cb0ef41Sopenharmony_ci  }
21981cb0ef41Sopenharmony_ci
21991cb0ef41Sopenharmony_ci  _final(cb) {
22001cb0ef41Sopenharmony_ci    if (this.pending) {
22011cb0ef41Sopenharmony_ci      this.once('ready', () => this._final(cb));
22021cb0ef41Sopenharmony_ci      return;
22031cb0ef41Sopenharmony_ci    }
22041cb0ef41Sopenharmony_ci    debugStreamObj(this, 'shutting down writable on _final');
22051cb0ef41Sopenharmony_ci    ReflectApply(shutdownWritable, this, [cb]);
22061cb0ef41Sopenharmony_ci  }
22071cb0ef41Sopenharmony_ci
22081cb0ef41Sopenharmony_ci  _read(nread) {
22091cb0ef41Sopenharmony_ci    if (this.destroyed) {
22101cb0ef41Sopenharmony_ci      this.push(null);
22111cb0ef41Sopenharmony_ci      return;
22121cb0ef41Sopenharmony_ci    }
22131cb0ef41Sopenharmony_ci    if (!this[kState].didRead) {
22141cb0ef41Sopenharmony_ci      this._readableState.readingMore = false;
22151cb0ef41Sopenharmony_ci      this[kState].didRead = true;
22161cb0ef41Sopenharmony_ci    }
22171cb0ef41Sopenharmony_ci    if (!this.pending) {
22181cb0ef41Sopenharmony_ci      FunctionPrototypeCall(streamOnResume, this);
22191cb0ef41Sopenharmony_ci    } else {
22201cb0ef41Sopenharmony_ci      this.once('ready', streamOnResume);
22211cb0ef41Sopenharmony_ci    }
22221cb0ef41Sopenharmony_ci  }
22231cb0ef41Sopenharmony_ci
22241cb0ef41Sopenharmony_ci  priority(options) {
22251cb0ef41Sopenharmony_ci    if (this.destroyed)
22261cb0ef41Sopenharmony_ci      throw new ERR_HTTP2_INVALID_STREAM();
22271cb0ef41Sopenharmony_ci
22281cb0ef41Sopenharmony_ci    assertIsObject(options, 'options');
22291cb0ef41Sopenharmony_ci    options = { ...options };
22301cb0ef41Sopenharmony_ci    setAndValidatePriorityOptions(options);
22311cb0ef41Sopenharmony_ci
22321cb0ef41Sopenharmony_ci    const priorityFn = FunctionPrototypeBind(submitPriority, this, options);
22331cb0ef41Sopenharmony_ci
22341cb0ef41Sopenharmony_ci    // If the handle has not yet been assigned, queue up the priority
22351cb0ef41Sopenharmony_ci    // frame to be sent as soon as the ready event is emitted.
22361cb0ef41Sopenharmony_ci    if (this.pending) {
22371cb0ef41Sopenharmony_ci      this.once('ready', priorityFn);
22381cb0ef41Sopenharmony_ci      return;
22391cb0ef41Sopenharmony_ci    }
22401cb0ef41Sopenharmony_ci    priorityFn();
22411cb0ef41Sopenharmony_ci  }
22421cb0ef41Sopenharmony_ci
22431cb0ef41Sopenharmony_ci  sendTrailers(headers) {
22441cb0ef41Sopenharmony_ci    if (this.destroyed || this.closed)
22451cb0ef41Sopenharmony_ci      throw new ERR_HTTP2_INVALID_STREAM();
22461cb0ef41Sopenharmony_ci    if (this[kSentTrailers])
22471cb0ef41Sopenharmony_ci      throw new ERR_HTTP2_TRAILERS_ALREADY_SENT();
22481cb0ef41Sopenharmony_ci    if (!this[kState].trailersReady)
22491cb0ef41Sopenharmony_ci      throw new ERR_HTTP2_TRAILERS_NOT_READY();
22501cb0ef41Sopenharmony_ci
22511cb0ef41Sopenharmony_ci    assertIsObject(headers, 'headers');
22521cb0ef41Sopenharmony_ci    headers = ObjectAssign(ObjectCreate(null), headers);
22531cb0ef41Sopenharmony_ci
22541cb0ef41Sopenharmony_ci    debugStreamObj(this, 'sending trailers');
22551cb0ef41Sopenharmony_ci
22561cb0ef41Sopenharmony_ci    this[kUpdateTimer]();
22571cb0ef41Sopenharmony_ci
22581cb0ef41Sopenharmony_ci    const headersList = mapToHeaders(headers, assertValidPseudoHeaderTrailer);
22591cb0ef41Sopenharmony_ci    this[kSentTrailers] = headers;
22601cb0ef41Sopenharmony_ci
22611cb0ef41Sopenharmony_ci    // Send the trailers in setImmediate so we don't do it on nghttp2 stack.
22621cb0ef41Sopenharmony_ci    setImmediate(finishSendTrailers, this, headersList);
22631cb0ef41Sopenharmony_ci  }
22641cb0ef41Sopenharmony_ci
22651cb0ef41Sopenharmony_ci  get closed() {
22661cb0ef41Sopenharmony_ci    return !!(this[kState].flags & STREAM_FLAGS_CLOSED);
22671cb0ef41Sopenharmony_ci  }
22681cb0ef41Sopenharmony_ci
22691cb0ef41Sopenharmony_ci  // Close initiates closing the Http2Stream instance by sending an RST_STREAM
22701cb0ef41Sopenharmony_ci  // frame to the connected peer. The readable and writable sides of the
22711cb0ef41Sopenharmony_ci  // Http2Stream duplex are closed and the timeout timer is cleared. If
22721cb0ef41Sopenharmony_ci  // a callback is passed, it is registered to listen for the 'close' event.
22731cb0ef41Sopenharmony_ci  //
22741cb0ef41Sopenharmony_ci  // If the handle and stream ID have not been assigned yet, the close
22751cb0ef41Sopenharmony_ci  // will be queued up to wait for the ready event. As soon as the stream ID
22761cb0ef41Sopenharmony_ci  // is determined, the close will proceed.
22771cb0ef41Sopenharmony_ci  //
22781cb0ef41Sopenharmony_ci  // Submitting the RST_STREAM frame to the underlying handle will cause
22791cb0ef41Sopenharmony_ci  // the Http2Stream to be closed and ultimately destroyed. After calling
22801cb0ef41Sopenharmony_ci  // close, it is still possible to queue up PRIORITY and RST_STREAM frames,
22811cb0ef41Sopenharmony_ci  // but no DATA and HEADERS frames may be sent.
22821cb0ef41Sopenharmony_ci  close(code = NGHTTP2_NO_ERROR, callback) {
22831cb0ef41Sopenharmony_ci    validateInteger(code, 'code', 0, kMaxInt);
22841cb0ef41Sopenharmony_ci
22851cb0ef41Sopenharmony_ci    if (callback !== undefined) {
22861cb0ef41Sopenharmony_ci      validateFunction(callback, 'callback');
22871cb0ef41Sopenharmony_ci    }
22881cb0ef41Sopenharmony_ci
22891cb0ef41Sopenharmony_ci    if (this.closed)
22901cb0ef41Sopenharmony_ci      return;
22911cb0ef41Sopenharmony_ci
22921cb0ef41Sopenharmony_ci    if (callback !== undefined)
22931cb0ef41Sopenharmony_ci      this.once('close', callback);
22941cb0ef41Sopenharmony_ci
22951cb0ef41Sopenharmony_ci    closeStream(this, code);
22961cb0ef41Sopenharmony_ci  }
22971cb0ef41Sopenharmony_ci
22981cb0ef41Sopenharmony_ci  // Called by this.destroy().
22991cb0ef41Sopenharmony_ci  // * Will submit an RST stream to shutdown the stream if necessary.
23001cb0ef41Sopenharmony_ci  //   This will cause the internal resources to be released.
23011cb0ef41Sopenharmony_ci  // * Then cleans up the resources on the js side
23021cb0ef41Sopenharmony_ci  _destroy(err, callback) {
23031cb0ef41Sopenharmony_ci    const session = this[kSession];
23041cb0ef41Sopenharmony_ci    const handle = this[kHandle];
23051cb0ef41Sopenharmony_ci    const id = this[kID];
23061cb0ef41Sopenharmony_ci
23071cb0ef41Sopenharmony_ci    debugStream(this[kID] || 'pending', session[kType], 'destroying stream');
23081cb0ef41Sopenharmony_ci
23091cb0ef41Sopenharmony_ci    const state = this[kState];
23101cb0ef41Sopenharmony_ci    const sessionState = session[kState];
23111cb0ef41Sopenharmony_ci    const sessionCode = sessionState.goawayCode || sessionState.destroyCode;
23121cb0ef41Sopenharmony_ci
23131cb0ef41Sopenharmony_ci    // If a stream has already closed successfully, there is no error
23141cb0ef41Sopenharmony_ci    // to report from this stream, even if the session has errored.
23151cb0ef41Sopenharmony_ci    // This can happen if the stream was already in process of destroying
23161cb0ef41Sopenharmony_ci    // after a successful close, but the session had a error between
23171cb0ef41Sopenharmony_ci    // this stream's close and destroy operations.
23181cb0ef41Sopenharmony_ci    // Previously, this always overrode a successful close operation code
23191cb0ef41Sopenharmony_ci    // NGHTTP2_NO_ERROR (0) with sessionCode because the use of the || operator.
23201cb0ef41Sopenharmony_ci    let code = this.closed ? this.rstCode : sessionCode;
23211cb0ef41Sopenharmony_ci    if (err != null) {
23221cb0ef41Sopenharmony_ci      if (sessionCode) {
23231cb0ef41Sopenharmony_ci        code = sessionCode;
23241cb0ef41Sopenharmony_ci      } else if (err instanceof AbortError) {
23251cb0ef41Sopenharmony_ci        // Enables using AbortController to cancel requests with RST code 8.
23261cb0ef41Sopenharmony_ci        code = NGHTTP2_CANCEL;
23271cb0ef41Sopenharmony_ci      } else {
23281cb0ef41Sopenharmony_ci        code = NGHTTP2_INTERNAL_ERROR;
23291cb0ef41Sopenharmony_ci      }
23301cb0ef41Sopenharmony_ci    }
23311cb0ef41Sopenharmony_ci    const hasHandle = handle !== undefined;
23321cb0ef41Sopenharmony_ci
23331cb0ef41Sopenharmony_ci    if (!this.closed)
23341cb0ef41Sopenharmony_ci      closeStream(this, code, hasHandle ? kForceRstStream : kNoRstStream);
23351cb0ef41Sopenharmony_ci    this.push(null);
23361cb0ef41Sopenharmony_ci
23371cb0ef41Sopenharmony_ci    if (hasHandle) {
23381cb0ef41Sopenharmony_ci      handle.destroy();
23391cb0ef41Sopenharmony_ci      sessionState.streams.delete(id);
23401cb0ef41Sopenharmony_ci    } else {
23411cb0ef41Sopenharmony_ci      sessionState.pendingStreams.delete(this);
23421cb0ef41Sopenharmony_ci    }
23431cb0ef41Sopenharmony_ci
23441cb0ef41Sopenharmony_ci    // Adjust the write queue size for accounting
23451cb0ef41Sopenharmony_ci    sessionState.writeQueueSize -= state.writeQueueSize;
23461cb0ef41Sopenharmony_ci    state.writeQueueSize = 0;
23471cb0ef41Sopenharmony_ci
23481cb0ef41Sopenharmony_ci    // RST code 8 not emitted as an error as its used by clients to signify
23491cb0ef41Sopenharmony_ci    // abort and is already covered by aborted event, also allows more
23501cb0ef41Sopenharmony_ci    // seamless compatibility with http1
23511cb0ef41Sopenharmony_ci    if (err == null && code !== NGHTTP2_NO_ERROR && code !== NGHTTP2_CANCEL)
23521cb0ef41Sopenharmony_ci      err = new ERR_HTTP2_STREAM_ERROR(nameForErrorCode[code] || code);
23531cb0ef41Sopenharmony_ci
23541cb0ef41Sopenharmony_ci    this[kSession] = undefined;
23551cb0ef41Sopenharmony_ci    this[kHandle] = undefined;
23561cb0ef41Sopenharmony_ci
23571cb0ef41Sopenharmony_ci    // This notifies the session that this stream has been destroyed and
23581cb0ef41Sopenharmony_ci    // gives the session the opportunity to clean itself up. The session
23591cb0ef41Sopenharmony_ci    // will destroy if it has been closed and there are no other open or
23601cb0ef41Sopenharmony_ci    // pending streams.
23611cb0ef41Sopenharmony_ci    session[kMaybeDestroy]();
23621cb0ef41Sopenharmony_ci    callback(err);
23631cb0ef41Sopenharmony_ci  }
23641cb0ef41Sopenharmony_ci  // The Http2Stream can be destroyed if it has closed and if the readable
23651cb0ef41Sopenharmony_ci  // side has received the final chunk.
23661cb0ef41Sopenharmony_ci  [kMaybeDestroy](code = NGHTTP2_NO_ERROR) {
23671cb0ef41Sopenharmony_ci    if (code !== NGHTTP2_NO_ERROR) {
23681cb0ef41Sopenharmony_ci      this.destroy();
23691cb0ef41Sopenharmony_ci      return;
23701cb0ef41Sopenharmony_ci    }
23711cb0ef41Sopenharmony_ci
23721cb0ef41Sopenharmony_ci    if (this.writableFinished) {
23731cb0ef41Sopenharmony_ci      if (!this.readable && this.closed) {
23741cb0ef41Sopenharmony_ci        this.destroy();
23751cb0ef41Sopenharmony_ci        return;
23761cb0ef41Sopenharmony_ci      }
23771cb0ef41Sopenharmony_ci
23781cb0ef41Sopenharmony_ci      // We've submitted a response from our server session, have not attempted
23791cb0ef41Sopenharmony_ci      // to process any incoming data, and have no trailers. This means we can
23801cb0ef41Sopenharmony_ci      // attempt to gracefully close the session.
23811cb0ef41Sopenharmony_ci      const state = this[kState];
23821cb0ef41Sopenharmony_ci      if (this.headersSent &&
23831cb0ef41Sopenharmony_ci          this[kSession] &&
23841cb0ef41Sopenharmony_ci          this[kSession][kType] === NGHTTP2_SESSION_SERVER &&
23851cb0ef41Sopenharmony_ci          !(state.flags & STREAM_FLAGS_HAS_TRAILERS) &&
23861cb0ef41Sopenharmony_ci          !state.didRead &&
23871cb0ef41Sopenharmony_ci          this.readableFlowing === null) {
23881cb0ef41Sopenharmony_ci        // By using setImmediate we allow pushStreams to make it through
23891cb0ef41Sopenharmony_ci        // before the stream is officially closed. This prevents a bug
23901cb0ef41Sopenharmony_ci        // in most browsers where those pushStreams would be rejected.
23911cb0ef41Sopenharmony_ci        setImmediate(callStreamClose, this);
23921cb0ef41Sopenharmony_ci      }
23931cb0ef41Sopenharmony_ci    }
23941cb0ef41Sopenharmony_ci  }
23951cb0ef41Sopenharmony_ci}
23961cb0ef41Sopenharmony_ci
23971cb0ef41Sopenharmony_cifunction callTimeout(self, kSession) {
23981cb0ef41Sopenharmony_ci  // If the session is destroyed, this should never actually be invoked,
23991cb0ef41Sopenharmony_ci  // but just in case...
24001cb0ef41Sopenharmony_ci  if (self.destroyed)
24011cb0ef41Sopenharmony_ci    return;
24021cb0ef41Sopenharmony_ci  // This checks whether a write is currently in progress and also whether
24031cb0ef41Sopenharmony_ci  // that write is actually sending data across the write. The kHandle
24041cb0ef41Sopenharmony_ci  // stored `chunksSentSinceLastWrite` is only updated when a timeout event
24051cb0ef41Sopenharmony_ci  // happens, meaning that if a write is ongoing it should never equal the
24061cb0ef41Sopenharmony_ci  // newly fetched, updated value.
24071cb0ef41Sopenharmony_ci  if (self[kState].writeQueueSize > 0) {
24081cb0ef41Sopenharmony_ci    const handle = kSession ? self[kSession][kHandle] : self[kHandle];
24091cb0ef41Sopenharmony_ci    const chunksSentSinceLastWrite = handle !== undefined ?
24101cb0ef41Sopenharmony_ci      handle.chunksSentSinceLastWrite : null;
24111cb0ef41Sopenharmony_ci    if (chunksSentSinceLastWrite !== null &&
24121cb0ef41Sopenharmony_ci      chunksSentSinceLastWrite !== handle.updateChunksSent()) {
24131cb0ef41Sopenharmony_ci      self[kUpdateTimer]();
24141cb0ef41Sopenharmony_ci      return;
24151cb0ef41Sopenharmony_ci    }
24161cb0ef41Sopenharmony_ci  }
24171cb0ef41Sopenharmony_ci
24181cb0ef41Sopenharmony_ci  self.emit('timeout');
24191cb0ef41Sopenharmony_ci}
24201cb0ef41Sopenharmony_ci
24211cb0ef41Sopenharmony_cifunction callStreamClose(stream) {
24221cb0ef41Sopenharmony_ci  stream.close();
24231cb0ef41Sopenharmony_ci}
24241cb0ef41Sopenharmony_ci
24251cb0ef41Sopenharmony_cifunction processHeaders(oldHeaders, options) {
24261cb0ef41Sopenharmony_ci  assertIsObject(oldHeaders, 'headers');
24271cb0ef41Sopenharmony_ci  const headers = ObjectCreate(null);
24281cb0ef41Sopenharmony_ci
24291cb0ef41Sopenharmony_ci  if (oldHeaders !== null && oldHeaders !== undefined) {
24301cb0ef41Sopenharmony_ci    // This loop is here for performance reason. Do not change.
24311cb0ef41Sopenharmony_ci    for (const key in oldHeaders) {
24321cb0ef41Sopenharmony_ci      if (ObjectPrototypeHasOwnProperty(oldHeaders, key)) {
24331cb0ef41Sopenharmony_ci        headers[key] = oldHeaders[key];
24341cb0ef41Sopenharmony_ci      }
24351cb0ef41Sopenharmony_ci    }
24361cb0ef41Sopenharmony_ci    headers[kSensitiveHeaders] = oldHeaders[kSensitiveHeaders];
24371cb0ef41Sopenharmony_ci  }
24381cb0ef41Sopenharmony_ci
24391cb0ef41Sopenharmony_ci  const statusCode =
24401cb0ef41Sopenharmony_ci    headers[HTTP2_HEADER_STATUS] =
24411cb0ef41Sopenharmony_ci      headers[HTTP2_HEADER_STATUS] | 0 || HTTP_STATUS_OK;
24421cb0ef41Sopenharmony_ci
24431cb0ef41Sopenharmony_ci  if (options.sendDate == null || options.sendDate) {
24441cb0ef41Sopenharmony_ci    if (headers[HTTP2_HEADER_DATE] === null ||
24451cb0ef41Sopenharmony_ci        headers[HTTP2_HEADER_DATE] === undefined) {
24461cb0ef41Sopenharmony_ci      headers[HTTP2_HEADER_DATE] = utcDate();
24471cb0ef41Sopenharmony_ci    }
24481cb0ef41Sopenharmony_ci  }
24491cb0ef41Sopenharmony_ci
24501cb0ef41Sopenharmony_ci  // This is intentionally stricter than the HTTP/1 implementation, which
24511cb0ef41Sopenharmony_ci  // allows values between 100 and 999 (inclusive) in order to allow for
24521cb0ef41Sopenharmony_ci  // backwards compatibility with non-spec compliant code. With HTTP/2,
24531cb0ef41Sopenharmony_ci  // we have the opportunity to start fresh with stricter spec compliance.
24541cb0ef41Sopenharmony_ci  // This will have an impact on the compatibility layer for anyone using
24551cb0ef41Sopenharmony_ci  // non-standard, non-compliant status codes.
24561cb0ef41Sopenharmony_ci  if (statusCode < 200 || statusCode > 599)
24571cb0ef41Sopenharmony_ci    throw new ERR_HTTP2_STATUS_INVALID(headers[HTTP2_HEADER_STATUS]);
24581cb0ef41Sopenharmony_ci
24591cb0ef41Sopenharmony_ci  const neverIndex = headers[kSensitiveHeaders];
24601cb0ef41Sopenharmony_ci  if (neverIndex !== undefined && !ArrayIsArray(neverIndex))
24611cb0ef41Sopenharmony_ci    throw new ERR_INVALID_ARG_VALUE('headers[http2.neverIndex]', neverIndex);
24621cb0ef41Sopenharmony_ci
24631cb0ef41Sopenharmony_ci  return headers;
24641cb0ef41Sopenharmony_ci}
24651cb0ef41Sopenharmony_ci
24661cb0ef41Sopenharmony_ci
24671cb0ef41Sopenharmony_cifunction onFileUnpipe() {
24681cb0ef41Sopenharmony_ci  const stream = this.sink[kOwner];
24691cb0ef41Sopenharmony_ci  if (stream.ownsFd)
24701cb0ef41Sopenharmony_ci    PromisePrototypeThen(this.source.close(), undefined,
24711cb0ef41Sopenharmony_ci                         FunctionPrototypeBind(stream.destroy, stream));
24721cb0ef41Sopenharmony_ci  else
24731cb0ef41Sopenharmony_ci    this.source.releaseFD();
24741cb0ef41Sopenharmony_ci}
24751cb0ef41Sopenharmony_ci
24761cb0ef41Sopenharmony_ci// This is only called once the pipe has returned back control, so
24771cb0ef41Sopenharmony_ci// it only has to handle errors and End-of-File.
24781cb0ef41Sopenharmony_cifunction onPipedFileHandleRead() {
24791cb0ef41Sopenharmony_ci  const err = streamBaseState[kReadBytesOrError];
24801cb0ef41Sopenharmony_ci  if (err < 0 && err !== UV_EOF) {
24811cb0ef41Sopenharmony_ci    this.stream.close(NGHTTP2_INTERNAL_ERROR);
24821cb0ef41Sopenharmony_ci  }
24831cb0ef41Sopenharmony_ci}
24841cb0ef41Sopenharmony_ci
24851cb0ef41Sopenharmony_cifunction processRespondWithFD(self, fd, headers, offset = 0, length = -1,
24861cb0ef41Sopenharmony_ci                              streamOptions = 0) {
24871cb0ef41Sopenharmony_ci  const state = self[kState];
24881cb0ef41Sopenharmony_ci  state.flags |= STREAM_FLAGS_HEADERS_SENT;
24891cb0ef41Sopenharmony_ci
24901cb0ef41Sopenharmony_ci  let headersList;
24911cb0ef41Sopenharmony_ci  try {
24921cb0ef41Sopenharmony_ci    headersList = mapToHeaders(headers, assertValidPseudoHeaderResponse);
24931cb0ef41Sopenharmony_ci  } catch (err) {
24941cb0ef41Sopenharmony_ci    self.destroy(err);
24951cb0ef41Sopenharmony_ci    return;
24961cb0ef41Sopenharmony_ci  }
24971cb0ef41Sopenharmony_ci  self[kSentHeaders] = headers;
24981cb0ef41Sopenharmony_ci
24991cb0ef41Sopenharmony_ci  // Close the writable side of the stream, but only as far as the writable
25001cb0ef41Sopenharmony_ci  // stream implementation is concerned.
25011cb0ef41Sopenharmony_ci  self._final = null;
25021cb0ef41Sopenharmony_ci  self.end();
25031cb0ef41Sopenharmony_ci
25041cb0ef41Sopenharmony_ci  const ret = self[kHandle].respond(headersList, streamOptions);
25051cb0ef41Sopenharmony_ci
25061cb0ef41Sopenharmony_ci  if (ret < 0) {
25071cb0ef41Sopenharmony_ci    self.destroy(new NghttpError(ret));
25081cb0ef41Sopenharmony_ci    return;
25091cb0ef41Sopenharmony_ci  }
25101cb0ef41Sopenharmony_ci
25111cb0ef41Sopenharmony_ci  defaultTriggerAsyncIdScope(self[async_id_symbol], startFilePipe,
25121cb0ef41Sopenharmony_ci                             self, fd, offset, length);
25131cb0ef41Sopenharmony_ci}
25141cb0ef41Sopenharmony_ci
25151cb0ef41Sopenharmony_cifunction startFilePipe(self, fd, offset, length) {
25161cb0ef41Sopenharmony_ci  const handle = new FileHandle(fd, offset, length);
25171cb0ef41Sopenharmony_ci  handle.onread = onPipedFileHandleRead;
25181cb0ef41Sopenharmony_ci  handle.stream = self;
25191cb0ef41Sopenharmony_ci
25201cb0ef41Sopenharmony_ci  const pipe = new StreamPipe(handle, self[kHandle]);
25211cb0ef41Sopenharmony_ci  pipe.onunpipe = onFileUnpipe;
25221cb0ef41Sopenharmony_ci  pipe.start();
25231cb0ef41Sopenharmony_ci
25241cb0ef41Sopenharmony_ci  // Exact length of the file doesn't matter here, since the
25251cb0ef41Sopenharmony_ci  // stream is closing anyway - just use 1 to signify that
25261cb0ef41Sopenharmony_ci  // a write does exist
25271cb0ef41Sopenharmony_ci  trackWriteState(self, 1);
25281cb0ef41Sopenharmony_ci}
25291cb0ef41Sopenharmony_ci
25301cb0ef41Sopenharmony_cifunction doSendFD(session, options, fd, headers, streamOptions, err, stat) {
25311cb0ef41Sopenharmony_ci  if (err) {
25321cb0ef41Sopenharmony_ci    this.destroy(err);
25331cb0ef41Sopenharmony_ci    return;
25341cb0ef41Sopenharmony_ci  }
25351cb0ef41Sopenharmony_ci
25361cb0ef41Sopenharmony_ci  // This can happen if the stream is destroyed or closed while we are waiting
25371cb0ef41Sopenharmony_ci  // for the file descriptor to be opened or the stat call to be completed.
25381cb0ef41Sopenharmony_ci  // In either case, we do not want to continue because the we are shutting
25391cb0ef41Sopenharmony_ci  // down and should not attempt to send any data.
25401cb0ef41Sopenharmony_ci  if (this.destroyed || this.closed) {
25411cb0ef41Sopenharmony_ci    this.destroy(new ERR_HTTP2_INVALID_STREAM());
25421cb0ef41Sopenharmony_ci    return;
25431cb0ef41Sopenharmony_ci  }
25441cb0ef41Sopenharmony_ci
25451cb0ef41Sopenharmony_ci  const statOptions = {
25461cb0ef41Sopenharmony_ci    offset: options.offset !== undefined ? options.offset : 0,
25471cb0ef41Sopenharmony_ci    length: options.length !== undefined ? options.length : -1,
25481cb0ef41Sopenharmony_ci  };
25491cb0ef41Sopenharmony_ci
25501cb0ef41Sopenharmony_ci  // options.statCheck is a user-provided function that can be used to
25511cb0ef41Sopenharmony_ci  // verify stat values, override or set headers, or even cancel the
25521cb0ef41Sopenharmony_ci  // response operation. If statCheck explicitly returns false, the
25531cb0ef41Sopenharmony_ci  // response is canceled. The user code may also send a separate type
25541cb0ef41Sopenharmony_ci  // of response so check again for the HEADERS_SENT flag
25551cb0ef41Sopenharmony_ci  if ((typeof options.statCheck === 'function' &&
25561cb0ef41Sopenharmony_ci       ReflectApply(options.statCheck, this,
25571cb0ef41Sopenharmony_ci                    [stat, headers, statOptions]) === false) ||
25581cb0ef41Sopenharmony_ci       (this[kState].flags & STREAM_FLAGS_HEADERS_SENT)) {
25591cb0ef41Sopenharmony_ci    return;
25601cb0ef41Sopenharmony_ci  }
25611cb0ef41Sopenharmony_ci
25621cb0ef41Sopenharmony_ci  processRespondWithFD(this, fd, headers,
25631cb0ef41Sopenharmony_ci                       statOptions.offset | 0,
25641cb0ef41Sopenharmony_ci                       statOptions.length | 0,
25651cb0ef41Sopenharmony_ci                       streamOptions);
25661cb0ef41Sopenharmony_ci}
25671cb0ef41Sopenharmony_ci
25681cb0ef41Sopenharmony_cifunction doSendFileFD(session, options, fd, headers, streamOptions, err, stat) {
25691cb0ef41Sopenharmony_ci  const onError = options.onError;
25701cb0ef41Sopenharmony_ci
25711cb0ef41Sopenharmony_ci  if (err) {
25721cb0ef41Sopenharmony_ci    tryClose(fd);
25731cb0ef41Sopenharmony_ci    if (onError)
25741cb0ef41Sopenharmony_ci      onError(err);
25751cb0ef41Sopenharmony_ci    else
25761cb0ef41Sopenharmony_ci      this.destroy(err);
25771cb0ef41Sopenharmony_ci    return;
25781cb0ef41Sopenharmony_ci  }
25791cb0ef41Sopenharmony_ci
25801cb0ef41Sopenharmony_ci  if (!stat.isFile()) {
25811cb0ef41Sopenharmony_ci    const isDirectory = stat.isDirectory();
25821cb0ef41Sopenharmony_ci    if (options.offset !== undefined || options.offset > 0 ||
25831cb0ef41Sopenharmony_ci        options.length !== undefined || options.length >= 0 ||
25841cb0ef41Sopenharmony_ci        isDirectory) {
25851cb0ef41Sopenharmony_ci      const err = isDirectory ?
25861cb0ef41Sopenharmony_ci        new ERR_HTTP2_SEND_FILE() : new ERR_HTTP2_SEND_FILE_NOSEEK();
25871cb0ef41Sopenharmony_ci      tryClose(fd);
25881cb0ef41Sopenharmony_ci      if (onError)
25891cb0ef41Sopenharmony_ci        onError(err);
25901cb0ef41Sopenharmony_ci      else
25911cb0ef41Sopenharmony_ci        this.destroy(err);
25921cb0ef41Sopenharmony_ci      return;
25931cb0ef41Sopenharmony_ci    }
25941cb0ef41Sopenharmony_ci
25951cb0ef41Sopenharmony_ci    options.offset = -1;
25961cb0ef41Sopenharmony_ci    options.length = -1;
25971cb0ef41Sopenharmony_ci  }
25981cb0ef41Sopenharmony_ci
25991cb0ef41Sopenharmony_ci  if (this.destroyed || this.closed) {
26001cb0ef41Sopenharmony_ci    tryClose(fd);
26011cb0ef41Sopenharmony_ci    this.destroy(new ERR_HTTP2_INVALID_STREAM());
26021cb0ef41Sopenharmony_ci    return;
26031cb0ef41Sopenharmony_ci  }
26041cb0ef41Sopenharmony_ci
26051cb0ef41Sopenharmony_ci  const statOptions = {
26061cb0ef41Sopenharmony_ci    offset: options.offset !== undefined ? options.offset : 0,
26071cb0ef41Sopenharmony_ci    length: options.length !== undefined ? options.length : -1,
26081cb0ef41Sopenharmony_ci  };
26091cb0ef41Sopenharmony_ci
26101cb0ef41Sopenharmony_ci  // options.statCheck is a user-provided function that can be used to
26111cb0ef41Sopenharmony_ci  // verify stat values, override or set headers, or even cancel the
26121cb0ef41Sopenharmony_ci  // response operation. If statCheck explicitly returns false, the
26131cb0ef41Sopenharmony_ci  // response is canceled. The user code may also send a separate type
26141cb0ef41Sopenharmony_ci  // of response so check again for the HEADERS_SENT flag
26151cb0ef41Sopenharmony_ci  if ((typeof options.statCheck === 'function' &&
26161cb0ef41Sopenharmony_ci       ReflectApply(options.statCheck, this, [stat, headers]) === false) ||
26171cb0ef41Sopenharmony_ci       (this[kState].flags & STREAM_FLAGS_HEADERS_SENT)) {
26181cb0ef41Sopenharmony_ci    tryClose(fd);
26191cb0ef41Sopenharmony_ci    return;
26201cb0ef41Sopenharmony_ci  }
26211cb0ef41Sopenharmony_ci
26221cb0ef41Sopenharmony_ci  if (stat.isFile()) {
26231cb0ef41Sopenharmony_ci    statOptions.length =
26241cb0ef41Sopenharmony_ci      statOptions.length < 0 ? stat.size - (+statOptions.offset) :
26251cb0ef41Sopenharmony_ci        MathMin(stat.size - (+statOptions.offset),
26261cb0ef41Sopenharmony_ci                statOptions.length);
26271cb0ef41Sopenharmony_ci
26281cb0ef41Sopenharmony_ci    headers[HTTP2_HEADER_CONTENT_LENGTH] = statOptions.length;
26291cb0ef41Sopenharmony_ci  }
26301cb0ef41Sopenharmony_ci
26311cb0ef41Sopenharmony_ci  processRespondWithFD(this, fd, headers,
26321cb0ef41Sopenharmony_ci                       options.offset | 0,
26331cb0ef41Sopenharmony_ci                       statOptions.length | 0,
26341cb0ef41Sopenharmony_ci                       streamOptions);
26351cb0ef41Sopenharmony_ci}
26361cb0ef41Sopenharmony_ci
26371cb0ef41Sopenharmony_cifunction afterOpen(session, options, headers, streamOptions, err, fd) {
26381cb0ef41Sopenharmony_ci  const state = this[kState];
26391cb0ef41Sopenharmony_ci  const onError = options.onError;
26401cb0ef41Sopenharmony_ci  if (err) {
26411cb0ef41Sopenharmony_ci    if (onError)
26421cb0ef41Sopenharmony_ci      onError(err);
26431cb0ef41Sopenharmony_ci    else
26441cb0ef41Sopenharmony_ci      this.destroy(err);
26451cb0ef41Sopenharmony_ci    return;
26461cb0ef41Sopenharmony_ci  }
26471cb0ef41Sopenharmony_ci  if (this.destroyed || this.closed) {
26481cb0ef41Sopenharmony_ci    tryClose(fd);
26491cb0ef41Sopenharmony_ci    return;
26501cb0ef41Sopenharmony_ci  }
26511cb0ef41Sopenharmony_ci  state.fd = fd;
26521cb0ef41Sopenharmony_ci
26531cb0ef41Sopenharmony_ci  fs.fstat(fd,
26541cb0ef41Sopenharmony_ci           FunctionPrototypeBind(doSendFileFD, this,
26551cb0ef41Sopenharmony_ci                                 session, options, fd,
26561cb0ef41Sopenharmony_ci                                 headers, streamOptions));
26571cb0ef41Sopenharmony_ci}
26581cb0ef41Sopenharmony_ci
26591cb0ef41Sopenharmony_ciclass ServerHttp2Stream extends Http2Stream {
26601cb0ef41Sopenharmony_ci  constructor(session, handle, id, options, headers) {
26611cb0ef41Sopenharmony_ci    super(session, options);
26621cb0ef41Sopenharmony_ci    handle.owner = this;
26631cb0ef41Sopenharmony_ci    this[kInit](id, handle);
26641cb0ef41Sopenharmony_ci    this[kProtocol] = headers[HTTP2_HEADER_SCHEME];
26651cb0ef41Sopenharmony_ci    this[kAuthority] = getAuthority(headers);
26661cb0ef41Sopenharmony_ci  }
26671cb0ef41Sopenharmony_ci
26681cb0ef41Sopenharmony_ci  // True if the remote peer accepts push streams
26691cb0ef41Sopenharmony_ci  get pushAllowed() {
26701cb0ef41Sopenharmony_ci    return !this.destroyed &&
26711cb0ef41Sopenharmony_ci           !this.closed &&
26721cb0ef41Sopenharmony_ci           !this.session.closed &&
26731cb0ef41Sopenharmony_ci           !this.session.destroyed &&
26741cb0ef41Sopenharmony_ci           this[kSession].remoteSettings.enablePush;
26751cb0ef41Sopenharmony_ci  }
26761cb0ef41Sopenharmony_ci
26771cb0ef41Sopenharmony_ci  // Create a push stream, call the given callback with the created
26781cb0ef41Sopenharmony_ci  // Http2Stream for the push stream.
26791cb0ef41Sopenharmony_ci  pushStream(headers, options, callback) {
26801cb0ef41Sopenharmony_ci    if (!this.pushAllowed)
26811cb0ef41Sopenharmony_ci      throw new ERR_HTTP2_PUSH_DISABLED();
26821cb0ef41Sopenharmony_ci    if (this[kID] % 2 === 0)
26831cb0ef41Sopenharmony_ci      throw new ERR_HTTP2_NESTED_PUSH();
26841cb0ef41Sopenharmony_ci
26851cb0ef41Sopenharmony_ci    const session = this[kSession];
26861cb0ef41Sopenharmony_ci
26871cb0ef41Sopenharmony_ci    debugStreamObj(this, 'initiating push stream');
26881cb0ef41Sopenharmony_ci
26891cb0ef41Sopenharmony_ci    this[kUpdateTimer]();
26901cb0ef41Sopenharmony_ci
26911cb0ef41Sopenharmony_ci    if (typeof options === 'function') {
26921cb0ef41Sopenharmony_ci      callback = options;
26931cb0ef41Sopenharmony_ci      options = undefined;
26941cb0ef41Sopenharmony_ci    }
26951cb0ef41Sopenharmony_ci
26961cb0ef41Sopenharmony_ci    validateFunction(callback, 'callback');
26971cb0ef41Sopenharmony_ci
26981cb0ef41Sopenharmony_ci    assertIsObject(options, 'options');
26991cb0ef41Sopenharmony_ci    options = { ...options };
27001cb0ef41Sopenharmony_ci    options.endStream = !!options.endStream;
27011cb0ef41Sopenharmony_ci
27021cb0ef41Sopenharmony_ci    assertIsObject(headers, 'headers');
27031cb0ef41Sopenharmony_ci    headers = ObjectAssign(ObjectCreate(null), headers);
27041cb0ef41Sopenharmony_ci
27051cb0ef41Sopenharmony_ci    if (headers[HTTP2_HEADER_METHOD] === undefined)
27061cb0ef41Sopenharmony_ci      headers[HTTP2_HEADER_METHOD] = HTTP2_METHOD_GET;
27071cb0ef41Sopenharmony_ci    if (getAuthority(headers) === undefined)
27081cb0ef41Sopenharmony_ci      headers[HTTP2_HEADER_AUTHORITY] = this[kAuthority];
27091cb0ef41Sopenharmony_ci    if (headers[HTTP2_HEADER_SCHEME] === undefined)
27101cb0ef41Sopenharmony_ci      headers[HTTP2_HEADER_SCHEME] = this[kProtocol];
27111cb0ef41Sopenharmony_ci    if (headers[HTTP2_HEADER_PATH] === undefined)
27121cb0ef41Sopenharmony_ci      headers[HTTP2_HEADER_PATH] = '/';
27131cb0ef41Sopenharmony_ci
27141cb0ef41Sopenharmony_ci    let headRequest = false;
27151cb0ef41Sopenharmony_ci    if (headers[HTTP2_HEADER_METHOD] === HTTP2_METHOD_HEAD)
27161cb0ef41Sopenharmony_ci      headRequest = options.endStream = true;
27171cb0ef41Sopenharmony_ci
27181cb0ef41Sopenharmony_ci    const headersList = mapToHeaders(headers);
27191cb0ef41Sopenharmony_ci
27201cb0ef41Sopenharmony_ci    const streamOptions = options.endStream ? STREAM_OPTION_EMPTY_PAYLOAD : 0;
27211cb0ef41Sopenharmony_ci
27221cb0ef41Sopenharmony_ci    const ret = this[kHandle].pushPromise(headersList, streamOptions);
27231cb0ef41Sopenharmony_ci    let err;
27241cb0ef41Sopenharmony_ci    if (typeof ret === 'number') {
27251cb0ef41Sopenharmony_ci      switch (ret) {
27261cb0ef41Sopenharmony_ci        case NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE:
27271cb0ef41Sopenharmony_ci          err = new ERR_HTTP2_OUT_OF_STREAMS();
27281cb0ef41Sopenharmony_ci          break;
27291cb0ef41Sopenharmony_ci        case NGHTTP2_ERR_STREAM_CLOSED:
27301cb0ef41Sopenharmony_ci          err = new ERR_HTTP2_INVALID_STREAM();
27311cb0ef41Sopenharmony_ci          break;
27321cb0ef41Sopenharmony_ci        default:
27331cb0ef41Sopenharmony_ci          err = new NghttpError(ret);
27341cb0ef41Sopenharmony_ci          break;
27351cb0ef41Sopenharmony_ci      }
27361cb0ef41Sopenharmony_ci      process.nextTick(callback, err);
27371cb0ef41Sopenharmony_ci      return;
27381cb0ef41Sopenharmony_ci    }
27391cb0ef41Sopenharmony_ci
27401cb0ef41Sopenharmony_ci    const id = ret.id();
27411cb0ef41Sopenharmony_ci    const stream = new ServerHttp2Stream(session, ret, id, options, headers);
27421cb0ef41Sopenharmony_ci    stream[kSentHeaders] = headers;
27431cb0ef41Sopenharmony_ci
27441cb0ef41Sopenharmony_ci    stream.push(null);
27451cb0ef41Sopenharmony_ci
27461cb0ef41Sopenharmony_ci    if (options.endStream)
27471cb0ef41Sopenharmony_ci      stream.end();
27481cb0ef41Sopenharmony_ci
27491cb0ef41Sopenharmony_ci    if (headRequest)
27501cb0ef41Sopenharmony_ci      stream[kState].flags |= STREAM_FLAGS_HEAD_REQUEST;
27511cb0ef41Sopenharmony_ci
27521cb0ef41Sopenharmony_ci    process.nextTick(callback, null, stream, headers, 0);
27531cb0ef41Sopenharmony_ci  }
27541cb0ef41Sopenharmony_ci
27551cb0ef41Sopenharmony_ci  // Initiate a response on this Http2Stream
27561cb0ef41Sopenharmony_ci  respond(headers, options) {
27571cb0ef41Sopenharmony_ci    if (this.destroyed || this.closed)
27581cb0ef41Sopenharmony_ci      throw new ERR_HTTP2_INVALID_STREAM();
27591cb0ef41Sopenharmony_ci    if (this.headersSent)
27601cb0ef41Sopenharmony_ci      throw new ERR_HTTP2_HEADERS_SENT();
27611cb0ef41Sopenharmony_ci
27621cb0ef41Sopenharmony_ci    const state = this[kState];
27631cb0ef41Sopenharmony_ci
27641cb0ef41Sopenharmony_ci    assertIsObject(options, 'options');
27651cb0ef41Sopenharmony_ci    options = { ...options };
27661cb0ef41Sopenharmony_ci
27671cb0ef41Sopenharmony_ci    debugStreamObj(this, 'initiating response');
27681cb0ef41Sopenharmony_ci    this[kUpdateTimer]();
27691cb0ef41Sopenharmony_ci
27701cb0ef41Sopenharmony_ci    options.endStream = !!options.endStream;
27711cb0ef41Sopenharmony_ci
27721cb0ef41Sopenharmony_ci    let streamOptions = 0;
27731cb0ef41Sopenharmony_ci    if (options.endStream)
27741cb0ef41Sopenharmony_ci      streamOptions |= STREAM_OPTION_EMPTY_PAYLOAD;
27751cb0ef41Sopenharmony_ci
27761cb0ef41Sopenharmony_ci    if (options.waitForTrailers) {
27771cb0ef41Sopenharmony_ci      streamOptions |= STREAM_OPTION_GET_TRAILERS;
27781cb0ef41Sopenharmony_ci      state.flags |= STREAM_FLAGS_HAS_TRAILERS;
27791cb0ef41Sopenharmony_ci    }
27801cb0ef41Sopenharmony_ci
27811cb0ef41Sopenharmony_ci    headers = processHeaders(headers, options);
27821cb0ef41Sopenharmony_ci    const headersList = mapToHeaders(headers, assertValidPseudoHeaderResponse);
27831cb0ef41Sopenharmony_ci    this[kSentHeaders] = headers;
27841cb0ef41Sopenharmony_ci
27851cb0ef41Sopenharmony_ci    state.flags |= STREAM_FLAGS_HEADERS_SENT;
27861cb0ef41Sopenharmony_ci
27871cb0ef41Sopenharmony_ci    // Close the writable side if the endStream option is set or status
27881cb0ef41Sopenharmony_ci    // is one of known codes with no payload, or it's a head request
27891cb0ef41Sopenharmony_ci    const statusCode = headers[HTTP2_HEADER_STATUS] | 0;
27901cb0ef41Sopenharmony_ci    if (!!options.endStream ||
27911cb0ef41Sopenharmony_ci        statusCode === HTTP_STATUS_NO_CONTENT ||
27921cb0ef41Sopenharmony_ci        statusCode === HTTP_STATUS_RESET_CONTENT ||
27931cb0ef41Sopenharmony_ci        statusCode === HTTP_STATUS_NOT_MODIFIED ||
27941cb0ef41Sopenharmony_ci        this.headRequest === true) {
27951cb0ef41Sopenharmony_ci      options.endStream = true;
27961cb0ef41Sopenharmony_ci      this.end();
27971cb0ef41Sopenharmony_ci    }
27981cb0ef41Sopenharmony_ci
27991cb0ef41Sopenharmony_ci    const ret = this[kHandle].respond(headersList, streamOptions);
28001cb0ef41Sopenharmony_ci    if (ret < 0)
28011cb0ef41Sopenharmony_ci      this.destroy(new NghttpError(ret));
28021cb0ef41Sopenharmony_ci  }
28031cb0ef41Sopenharmony_ci
28041cb0ef41Sopenharmony_ci  // Initiate a response using an open FD. Note that there are fewer
28051cb0ef41Sopenharmony_ci  // protections with this approach. For one, the fd is not validated by
28061cb0ef41Sopenharmony_ci  // default. In respondWithFile, the file is checked to make sure it is a
28071cb0ef41Sopenharmony_ci  // regular file, here the fd is passed directly. If the underlying
28081cb0ef41Sopenharmony_ci  // mechanism is not able to read from the fd, then the stream will be
28091cb0ef41Sopenharmony_ci  // reset with an error code.
28101cb0ef41Sopenharmony_ci  respondWithFD(fd, headers, options) {
28111cb0ef41Sopenharmony_ci    if (this.destroyed || this.closed)
28121cb0ef41Sopenharmony_ci      throw new ERR_HTTP2_INVALID_STREAM();
28131cb0ef41Sopenharmony_ci    if (this.headersSent)
28141cb0ef41Sopenharmony_ci      throw new ERR_HTTP2_HEADERS_SENT();
28151cb0ef41Sopenharmony_ci
28161cb0ef41Sopenharmony_ci    const session = this[kSession];
28171cb0ef41Sopenharmony_ci
28181cb0ef41Sopenharmony_ci    assertIsObject(options, 'options');
28191cb0ef41Sopenharmony_ci    options = { ...options };
28201cb0ef41Sopenharmony_ci
28211cb0ef41Sopenharmony_ci    if (options.offset !== undefined && typeof options.offset !== 'number')
28221cb0ef41Sopenharmony_ci      throw new ERR_INVALID_ARG_VALUE('options.offset', options.offset);
28231cb0ef41Sopenharmony_ci
28241cb0ef41Sopenharmony_ci    if (options.length !== undefined && typeof options.length !== 'number')
28251cb0ef41Sopenharmony_ci      throw new ERR_INVALID_ARG_VALUE('options.length', options.length);
28261cb0ef41Sopenharmony_ci
28271cb0ef41Sopenharmony_ci    if (options.statCheck !== undefined &&
28281cb0ef41Sopenharmony_ci        typeof options.statCheck !== 'function') {
28291cb0ef41Sopenharmony_ci      throw new ERR_INVALID_ARG_VALUE('options.statCheck', options.statCheck);
28301cb0ef41Sopenharmony_ci    }
28311cb0ef41Sopenharmony_ci
28321cb0ef41Sopenharmony_ci    let streamOptions = 0;
28331cb0ef41Sopenharmony_ci    if (options.waitForTrailers) {
28341cb0ef41Sopenharmony_ci      streamOptions |= STREAM_OPTION_GET_TRAILERS;
28351cb0ef41Sopenharmony_ci      this[kState].flags |= STREAM_FLAGS_HAS_TRAILERS;
28361cb0ef41Sopenharmony_ci    }
28371cb0ef41Sopenharmony_ci
28381cb0ef41Sopenharmony_ci    if (fd instanceof fsPromisesInternal.FileHandle)
28391cb0ef41Sopenharmony_ci      fd = fd.fd;
28401cb0ef41Sopenharmony_ci    else if (typeof fd !== 'number')
28411cb0ef41Sopenharmony_ci      throw new ERR_INVALID_ARG_TYPE('fd', ['number', 'FileHandle'], fd);
28421cb0ef41Sopenharmony_ci
28431cb0ef41Sopenharmony_ci    debugStreamObj(this, 'initiating response from fd');
28441cb0ef41Sopenharmony_ci    this[kUpdateTimer]();
28451cb0ef41Sopenharmony_ci    this.ownsFd = false;
28461cb0ef41Sopenharmony_ci
28471cb0ef41Sopenharmony_ci    headers = processHeaders(headers, options);
28481cb0ef41Sopenharmony_ci    const statusCode = headers[HTTP2_HEADER_STATUS] |= 0;
28491cb0ef41Sopenharmony_ci    // Payload/DATA frames are not permitted in these cases
28501cb0ef41Sopenharmony_ci    if (statusCode === HTTP_STATUS_NO_CONTENT ||
28511cb0ef41Sopenharmony_ci        statusCode === HTTP_STATUS_RESET_CONTENT ||
28521cb0ef41Sopenharmony_ci        statusCode === HTTP_STATUS_NOT_MODIFIED ||
28531cb0ef41Sopenharmony_ci        this.headRequest) {
28541cb0ef41Sopenharmony_ci      throw new ERR_HTTP2_PAYLOAD_FORBIDDEN(statusCode);
28551cb0ef41Sopenharmony_ci    }
28561cb0ef41Sopenharmony_ci
28571cb0ef41Sopenharmony_ci    if (options.statCheck !== undefined) {
28581cb0ef41Sopenharmony_ci      fs.fstat(fd,
28591cb0ef41Sopenharmony_ci               FunctionPrototypeBind(doSendFD, this,
28601cb0ef41Sopenharmony_ci                                     session, options, fd,
28611cb0ef41Sopenharmony_ci                                     headers, streamOptions));
28621cb0ef41Sopenharmony_ci      return;
28631cb0ef41Sopenharmony_ci    }
28641cb0ef41Sopenharmony_ci
28651cb0ef41Sopenharmony_ci    processRespondWithFD(this, fd, headers,
28661cb0ef41Sopenharmony_ci                         options.offset,
28671cb0ef41Sopenharmony_ci                         options.length,
28681cb0ef41Sopenharmony_ci                         streamOptions);
28691cb0ef41Sopenharmony_ci  }
28701cb0ef41Sopenharmony_ci
28711cb0ef41Sopenharmony_ci  // Initiate a file response on this Http2Stream. The path is passed to
28721cb0ef41Sopenharmony_ci  // fs.open() to acquire the fd with mode 'r', then the fd is passed to
28731cb0ef41Sopenharmony_ci  // fs.fstat(). Assuming fstat is successful, a check is made to ensure
28741cb0ef41Sopenharmony_ci  // that the file is a regular file, then options.statCheck is called,
28751cb0ef41Sopenharmony_ci  // giving the user an opportunity to verify the details and set additional
28761cb0ef41Sopenharmony_ci  // headers. If statCheck returns false, the operation is aborted and no
28771cb0ef41Sopenharmony_ci  // file details are sent.
28781cb0ef41Sopenharmony_ci  respondWithFile(path, headers, options) {
28791cb0ef41Sopenharmony_ci    if (this.destroyed || this.closed)
28801cb0ef41Sopenharmony_ci      throw new ERR_HTTP2_INVALID_STREAM();
28811cb0ef41Sopenharmony_ci    if (this.headersSent)
28821cb0ef41Sopenharmony_ci      throw new ERR_HTTP2_HEADERS_SENT();
28831cb0ef41Sopenharmony_ci
28841cb0ef41Sopenharmony_ci    assertIsObject(options, 'options');
28851cb0ef41Sopenharmony_ci    options = { ...options };
28861cb0ef41Sopenharmony_ci
28871cb0ef41Sopenharmony_ci    if (options.offset !== undefined && typeof options.offset !== 'number')
28881cb0ef41Sopenharmony_ci      throw new ERR_INVALID_ARG_VALUE('options.offset', options.offset);
28891cb0ef41Sopenharmony_ci
28901cb0ef41Sopenharmony_ci    if (options.length !== undefined && typeof options.length !== 'number')
28911cb0ef41Sopenharmony_ci      throw new ERR_INVALID_ARG_VALUE('options.length', options.length);
28921cb0ef41Sopenharmony_ci
28931cb0ef41Sopenharmony_ci    if (options.statCheck !== undefined &&
28941cb0ef41Sopenharmony_ci        typeof options.statCheck !== 'function') {
28951cb0ef41Sopenharmony_ci      throw new ERR_INVALID_ARG_VALUE('options.statCheck', options.statCheck);
28961cb0ef41Sopenharmony_ci    }
28971cb0ef41Sopenharmony_ci
28981cb0ef41Sopenharmony_ci    let streamOptions = 0;
28991cb0ef41Sopenharmony_ci    if (options.waitForTrailers) {
29001cb0ef41Sopenharmony_ci      streamOptions |= STREAM_OPTION_GET_TRAILERS;
29011cb0ef41Sopenharmony_ci      this[kState].flags |= STREAM_FLAGS_HAS_TRAILERS;
29021cb0ef41Sopenharmony_ci    }
29031cb0ef41Sopenharmony_ci
29041cb0ef41Sopenharmony_ci    const session = this[kSession];
29051cb0ef41Sopenharmony_ci    debugStreamObj(this, 'initiating response from file');
29061cb0ef41Sopenharmony_ci    this[kUpdateTimer]();
29071cb0ef41Sopenharmony_ci    this.ownsFd = true;
29081cb0ef41Sopenharmony_ci
29091cb0ef41Sopenharmony_ci    headers = processHeaders(headers, options);
29101cb0ef41Sopenharmony_ci    const statusCode = headers[HTTP2_HEADER_STATUS] |= 0;
29111cb0ef41Sopenharmony_ci    // Payload/DATA frames are not permitted in these cases
29121cb0ef41Sopenharmony_ci    if (statusCode === HTTP_STATUS_NO_CONTENT ||
29131cb0ef41Sopenharmony_ci        statusCode === HTTP_STATUS_RESET_CONTENT ||
29141cb0ef41Sopenharmony_ci        statusCode === HTTP_STATUS_NOT_MODIFIED ||
29151cb0ef41Sopenharmony_ci        this.headRequest) {
29161cb0ef41Sopenharmony_ci      throw new ERR_HTTP2_PAYLOAD_FORBIDDEN(statusCode);
29171cb0ef41Sopenharmony_ci    }
29181cb0ef41Sopenharmony_ci
29191cb0ef41Sopenharmony_ci    fs.open(path, 'r',
29201cb0ef41Sopenharmony_ci            FunctionPrototypeBind(afterOpen, this,
29211cb0ef41Sopenharmony_ci                                  session, options, headers, streamOptions));
29221cb0ef41Sopenharmony_ci  }
29231cb0ef41Sopenharmony_ci
29241cb0ef41Sopenharmony_ci  // Sends a block of informational headers. In theory, the HTTP/2 spec
29251cb0ef41Sopenharmony_ci  // allows sending a HEADER block at any time during a streams lifecycle,
29261cb0ef41Sopenharmony_ci  // but the HTTP request/response semantics defined in HTTP/2 places limits
29271cb0ef41Sopenharmony_ci  // such that HEADERS may only be sent *before* or *after* DATA frames.
29281cb0ef41Sopenharmony_ci  // If the block of headers being sent includes a status code, it MUST be
29291cb0ef41Sopenharmony_ci  // a 1xx informational code and it MUST be sent before the request/response
29301cb0ef41Sopenharmony_ci  // headers are sent, or an error will be thrown.
29311cb0ef41Sopenharmony_ci  additionalHeaders(headers) {
29321cb0ef41Sopenharmony_ci    if (this.destroyed || this.closed)
29331cb0ef41Sopenharmony_ci      throw new ERR_HTTP2_INVALID_STREAM();
29341cb0ef41Sopenharmony_ci    if (this.headersSent)
29351cb0ef41Sopenharmony_ci      throw new ERR_HTTP2_HEADERS_AFTER_RESPOND();
29361cb0ef41Sopenharmony_ci
29371cb0ef41Sopenharmony_ci    assertIsObject(headers, 'headers');
29381cb0ef41Sopenharmony_ci    headers = ObjectAssign(ObjectCreate(null), headers);
29391cb0ef41Sopenharmony_ci
29401cb0ef41Sopenharmony_ci    debugStreamObj(this, 'sending additional headers');
29411cb0ef41Sopenharmony_ci
29421cb0ef41Sopenharmony_ci    if (headers[HTTP2_HEADER_STATUS] != null) {
29431cb0ef41Sopenharmony_ci      const statusCode = headers[HTTP2_HEADER_STATUS] |= 0;
29441cb0ef41Sopenharmony_ci      if (statusCode === HTTP_STATUS_SWITCHING_PROTOCOLS)
29451cb0ef41Sopenharmony_ci        throw new ERR_HTTP2_STATUS_101();
29461cb0ef41Sopenharmony_ci      if (statusCode < 100 || statusCode >= 200) {
29471cb0ef41Sopenharmony_ci        throw new ERR_HTTP2_INVALID_INFO_STATUS(headers[HTTP2_HEADER_STATUS]);
29481cb0ef41Sopenharmony_ci      }
29491cb0ef41Sopenharmony_ci    }
29501cb0ef41Sopenharmony_ci
29511cb0ef41Sopenharmony_ci    this[kUpdateTimer]();
29521cb0ef41Sopenharmony_ci
29531cb0ef41Sopenharmony_ci    const headersList = mapToHeaders(headers, assertValidPseudoHeaderResponse);
29541cb0ef41Sopenharmony_ci    if (!this[kInfoHeaders])
29551cb0ef41Sopenharmony_ci      this[kInfoHeaders] = [headers];
29561cb0ef41Sopenharmony_ci    else
29571cb0ef41Sopenharmony_ci      ArrayPrototypePush(this[kInfoHeaders], headers);
29581cb0ef41Sopenharmony_ci
29591cb0ef41Sopenharmony_ci    const ret = this[kHandle].info(headersList);
29601cb0ef41Sopenharmony_ci    if (ret < 0)
29611cb0ef41Sopenharmony_ci      this.destroy(new NghttpError(ret));
29621cb0ef41Sopenharmony_ci  }
29631cb0ef41Sopenharmony_ci}
29641cb0ef41Sopenharmony_ci
29651cb0ef41Sopenharmony_ciServerHttp2Stream.prototype[kProceed] = ServerHttp2Stream.prototype.respond;
29661cb0ef41Sopenharmony_ci
29671cb0ef41Sopenharmony_ciclass ClientHttp2Stream extends Http2Stream {
29681cb0ef41Sopenharmony_ci  constructor(session, handle, id, options) {
29691cb0ef41Sopenharmony_ci    super(session, options);
29701cb0ef41Sopenharmony_ci    this[kState].flags |= STREAM_FLAGS_HEADERS_SENT;
29711cb0ef41Sopenharmony_ci    if (id !== undefined)
29721cb0ef41Sopenharmony_ci      this[kInit](id, handle);
29731cb0ef41Sopenharmony_ci    this.on('headers', handleHeaderContinue);
29741cb0ef41Sopenharmony_ci  }
29751cb0ef41Sopenharmony_ci}
29761cb0ef41Sopenharmony_ci
29771cb0ef41Sopenharmony_cifunction handleHeaderContinue(headers) {
29781cb0ef41Sopenharmony_ci  if (headers[HTTP2_HEADER_STATUS] === HTTP_STATUS_CONTINUE)
29791cb0ef41Sopenharmony_ci    this.emit('continue');
29801cb0ef41Sopenharmony_ci}
29811cb0ef41Sopenharmony_ci
29821cb0ef41Sopenharmony_ciconst setTimeoutValue = {
29831cb0ef41Sopenharmony_ci  configurable: true,
29841cb0ef41Sopenharmony_ci  enumerable: true,
29851cb0ef41Sopenharmony_ci  writable: true,
29861cb0ef41Sopenharmony_ci  value: setStreamTimeout,
29871cb0ef41Sopenharmony_ci};
29881cb0ef41Sopenharmony_ciObjectDefineProperty(Http2Stream.prototype, 'setTimeout', setTimeoutValue);
29891cb0ef41Sopenharmony_ciObjectDefineProperty(Http2Session.prototype, 'setTimeout', setTimeoutValue);
29901cb0ef41Sopenharmony_ci
29911cb0ef41Sopenharmony_ci
29921cb0ef41Sopenharmony_ci// When the socket emits an error, destroy the associated Http2Session and
29931cb0ef41Sopenharmony_ci// forward it the same error.
29941cb0ef41Sopenharmony_cifunction socketOnError(error) {
29951cb0ef41Sopenharmony_ci  const session = this[kSession];
29961cb0ef41Sopenharmony_ci  if (session !== undefined) {
29971cb0ef41Sopenharmony_ci    // We can ignore ECONNRESET after GOAWAY was received as there's nothing
29981cb0ef41Sopenharmony_ci    // we can do and the other side is fully within its rights to do so.
29991cb0ef41Sopenharmony_ci    if (error.code === 'ECONNRESET' && session[kState].goawayCode !== null)
30001cb0ef41Sopenharmony_ci      return session.destroy();
30011cb0ef41Sopenharmony_ci    debugSessionObj(this, 'socket error [%s]', error.message);
30021cb0ef41Sopenharmony_ci    session.destroy(error);
30031cb0ef41Sopenharmony_ci  }
30041cb0ef41Sopenharmony_ci}
30051cb0ef41Sopenharmony_ci
30061cb0ef41Sopenharmony_ci// Handles the on('stream') event for a session and forwards
30071cb0ef41Sopenharmony_ci// it on to the server object.
30081cb0ef41Sopenharmony_cifunction sessionOnStream(stream, headers, flags, rawHeaders) {
30091cb0ef41Sopenharmony_ci  if (this[kServer] !== undefined)
30101cb0ef41Sopenharmony_ci    this[kServer].emit('stream', stream, headers, flags, rawHeaders);
30111cb0ef41Sopenharmony_ci}
30121cb0ef41Sopenharmony_ci
30131cb0ef41Sopenharmony_cifunction sessionOnPriority(stream, parent, weight, exclusive) {
30141cb0ef41Sopenharmony_ci  if (this[kServer] !== undefined)
30151cb0ef41Sopenharmony_ci    this[kServer].emit('priority', stream, parent, weight, exclusive);
30161cb0ef41Sopenharmony_ci}
30171cb0ef41Sopenharmony_ci
30181cb0ef41Sopenharmony_cifunction sessionOnError(error) {
30191cb0ef41Sopenharmony_ci  if (this[kServer] !== undefined)
30201cb0ef41Sopenharmony_ci    this[kServer].emit('sessionError', error, this);
30211cb0ef41Sopenharmony_ci}
30221cb0ef41Sopenharmony_ci
30231cb0ef41Sopenharmony_ci// When the session times out on the server, try emitting a timeout event.
30241cb0ef41Sopenharmony_ci// If no handler is registered, destroy the session.
30251cb0ef41Sopenharmony_cifunction sessionOnTimeout() {
30261cb0ef41Sopenharmony_ci  // If destroyed or closed already, do nothing
30271cb0ef41Sopenharmony_ci  if (this.destroyed || this.closed)
30281cb0ef41Sopenharmony_ci    return;
30291cb0ef41Sopenharmony_ci  const server = this[kServer];
30301cb0ef41Sopenharmony_ci  if (!server.emit('timeout', this))
30311cb0ef41Sopenharmony_ci    this.destroy();  // No error code, just things down.
30321cb0ef41Sopenharmony_ci}
30331cb0ef41Sopenharmony_ci
30341cb0ef41Sopenharmony_cifunction connectionListener(socket) {
30351cb0ef41Sopenharmony_ci  debug('Http2Session server: received a connection');
30361cb0ef41Sopenharmony_ci  const options = this[kOptions] || {};
30371cb0ef41Sopenharmony_ci
30381cb0ef41Sopenharmony_ci  if (socket.alpnProtocol === false || socket.alpnProtocol === 'http/1.1') {
30391cb0ef41Sopenharmony_ci    // Fallback to HTTP/1.1
30401cb0ef41Sopenharmony_ci    if (options.allowHTTP1 === true) {
30411cb0ef41Sopenharmony_ci      socket.server[kIncomingMessage] = options.Http1IncomingMessage;
30421cb0ef41Sopenharmony_ci      socket.server[kServerResponse] = options.Http1ServerResponse;
30431cb0ef41Sopenharmony_ci      return FunctionPrototypeCall(httpConnectionListener, this, socket);
30441cb0ef41Sopenharmony_ci    }
30451cb0ef41Sopenharmony_ci    // Let event handler deal with the socket
30461cb0ef41Sopenharmony_ci    debug('Unknown protocol from %s:%s',
30471cb0ef41Sopenharmony_ci          socket.remoteAddress, socket.remotePort);
30481cb0ef41Sopenharmony_ci    if (!this.emit('unknownProtocol', socket)) {
30491cb0ef41Sopenharmony_ci      debug('Unknown protocol timeout:  %s', options.unknownProtocolTimeout);
30501cb0ef41Sopenharmony_ci      // Install a timeout if the socket was not successfully closed, then
30511cb0ef41Sopenharmony_ci      // destroy the socket to ensure that the underlying resources are
30521cb0ef41Sopenharmony_ci      // released.
30531cb0ef41Sopenharmony_ci      const timer = setTimeout(() => {
30541cb0ef41Sopenharmony_ci        if (!socket.destroyed) {
30551cb0ef41Sopenharmony_ci          debug('UnknownProtocol socket timeout, destroy socket');
30561cb0ef41Sopenharmony_ci          socket.destroy();
30571cb0ef41Sopenharmony_ci        }
30581cb0ef41Sopenharmony_ci      }, options.unknownProtocolTimeout);
30591cb0ef41Sopenharmony_ci      // Un-reference the timer to avoid blocking of application shutdown and
30601cb0ef41Sopenharmony_ci      // clear the timeout if the socket was successfully closed.
30611cb0ef41Sopenharmony_ci      timer.unref();
30621cb0ef41Sopenharmony_ci
30631cb0ef41Sopenharmony_ci      socket.once('close', () => clearTimeout(timer));
30641cb0ef41Sopenharmony_ci
30651cb0ef41Sopenharmony_ci      // We don't know what to do, so let's just tell the other side what's
30661cb0ef41Sopenharmony_ci      // going on in a format that they *might* understand.
30671cb0ef41Sopenharmony_ci      socket.end('HTTP/1.0 403 Forbidden\r\n' +
30681cb0ef41Sopenharmony_ci                 'Content-Type: text/plain\r\n\r\n' +
30691cb0ef41Sopenharmony_ci                 'Unknown ALPN Protocol, expected `h2` to be available.\n' +
30701cb0ef41Sopenharmony_ci                 'If this is a HTTP request: The server was not ' +
30711cb0ef41Sopenharmony_ci                 'configured with the `allowHTTP1` option or a ' +
30721cb0ef41Sopenharmony_ci                 'listener for the `unknownProtocol` event.\n');
30731cb0ef41Sopenharmony_ci    }
30741cb0ef41Sopenharmony_ci    return;
30751cb0ef41Sopenharmony_ci  }
30761cb0ef41Sopenharmony_ci
30771cb0ef41Sopenharmony_ci  // Set up the Session
30781cb0ef41Sopenharmony_ci  const session = new ServerHttp2Session(options, socket, this);
30791cb0ef41Sopenharmony_ci
30801cb0ef41Sopenharmony_ci  session.on('stream', sessionOnStream);
30811cb0ef41Sopenharmony_ci  session.on('error', sessionOnError);
30821cb0ef41Sopenharmony_ci  // Don't count our own internal listener.
30831cb0ef41Sopenharmony_ci  session.on('priority', sessionOnPriority);
30841cb0ef41Sopenharmony_ci  session[kNativeFields][kSessionPriorityListenerCount]--;
30851cb0ef41Sopenharmony_ci
30861cb0ef41Sopenharmony_ci  if (this.timeout)
30871cb0ef41Sopenharmony_ci    session.setTimeout(this.timeout, sessionOnTimeout);
30881cb0ef41Sopenharmony_ci
30891cb0ef41Sopenharmony_ci  socket[kServer] = this;
30901cb0ef41Sopenharmony_ci
30911cb0ef41Sopenharmony_ci  this.emit('session', session);
30921cb0ef41Sopenharmony_ci}
30931cb0ef41Sopenharmony_ci
30941cb0ef41Sopenharmony_cifunction initializeOptions(options) {
30951cb0ef41Sopenharmony_ci  assertIsObject(options, 'options');
30961cb0ef41Sopenharmony_ci  options = { ...options };
30971cb0ef41Sopenharmony_ci  assertIsObject(options.settings, 'options.settings');
30981cb0ef41Sopenharmony_ci  options.settings = { ...options.settings };
30991cb0ef41Sopenharmony_ci
31001cb0ef41Sopenharmony_ci  if (options.maxSessionInvalidFrames !== undefined)
31011cb0ef41Sopenharmony_ci    validateUint32(options.maxSessionInvalidFrames, 'maxSessionInvalidFrames');
31021cb0ef41Sopenharmony_ci
31031cb0ef41Sopenharmony_ci  if (options.maxSessionRejectedStreams !== undefined) {
31041cb0ef41Sopenharmony_ci    validateUint32(
31051cb0ef41Sopenharmony_ci      options.maxSessionRejectedStreams,
31061cb0ef41Sopenharmony_ci      'maxSessionRejectedStreams',
31071cb0ef41Sopenharmony_ci    );
31081cb0ef41Sopenharmony_ci  }
31091cb0ef41Sopenharmony_ci
31101cb0ef41Sopenharmony_ci  if (options.unknownProtocolTimeout !== undefined)
31111cb0ef41Sopenharmony_ci    validateUint32(options.unknownProtocolTimeout, 'unknownProtocolTimeout');
31121cb0ef41Sopenharmony_ci  else
31131cb0ef41Sopenharmony_ci    // TODO(danbev): is this a good default value?
31141cb0ef41Sopenharmony_ci    options.unknownProtocolTimeout = 10000;
31151cb0ef41Sopenharmony_ci
31161cb0ef41Sopenharmony_ci
31171cb0ef41Sopenharmony_ci  // Used only with allowHTTP1
31181cb0ef41Sopenharmony_ci  options.Http1IncomingMessage = options.Http1IncomingMessage ||
31191cb0ef41Sopenharmony_ci    http.IncomingMessage;
31201cb0ef41Sopenharmony_ci  options.Http1ServerResponse = options.Http1ServerResponse ||
31211cb0ef41Sopenharmony_ci    http.ServerResponse;
31221cb0ef41Sopenharmony_ci
31231cb0ef41Sopenharmony_ci  options.Http2ServerRequest = options.Http2ServerRequest ||
31241cb0ef41Sopenharmony_ci                                       Http2ServerRequest;
31251cb0ef41Sopenharmony_ci  options.Http2ServerResponse = options.Http2ServerResponse ||
31261cb0ef41Sopenharmony_ci                                        Http2ServerResponse;
31271cb0ef41Sopenharmony_ci  return options;
31281cb0ef41Sopenharmony_ci}
31291cb0ef41Sopenharmony_ci
31301cb0ef41Sopenharmony_cifunction initializeTLSOptions(options, servername) {
31311cb0ef41Sopenharmony_ci  options = initializeOptions(options);
31321cb0ef41Sopenharmony_ci  options.ALPNProtocols = ['h2'];
31331cb0ef41Sopenharmony_ci  if (options.allowHTTP1 === true)
31341cb0ef41Sopenharmony_ci    ArrayPrototypePush(options.ALPNProtocols, 'http/1.1');
31351cb0ef41Sopenharmony_ci  if (servername !== undefined && !options.servername)
31361cb0ef41Sopenharmony_ci    options.servername = servername;
31371cb0ef41Sopenharmony_ci  return options;
31381cb0ef41Sopenharmony_ci}
31391cb0ef41Sopenharmony_ci
31401cb0ef41Sopenharmony_cifunction onErrorSecureServerSession(err, socket) {
31411cb0ef41Sopenharmony_ci  if (!this.emit('clientError', err, socket))
31421cb0ef41Sopenharmony_ci    socket.destroy(err);
31431cb0ef41Sopenharmony_ci}
31441cb0ef41Sopenharmony_ci
31451cb0ef41Sopenharmony_ciclass Http2SecureServer extends TLSServer {
31461cb0ef41Sopenharmony_ci  constructor(options, requestListener) {
31471cb0ef41Sopenharmony_ci    options = initializeTLSOptions(options);
31481cb0ef41Sopenharmony_ci    super(options, connectionListener);
31491cb0ef41Sopenharmony_ci    this[kOptions] = options;
31501cb0ef41Sopenharmony_ci    this.timeout = 0;
31511cb0ef41Sopenharmony_ci    this.on('newListener', setupCompat);
31521cb0ef41Sopenharmony_ci    if (typeof requestListener === 'function')
31531cb0ef41Sopenharmony_ci      this.on('request', requestListener);
31541cb0ef41Sopenharmony_ci    this.on('tlsClientError', onErrorSecureServerSession);
31551cb0ef41Sopenharmony_ci  }
31561cb0ef41Sopenharmony_ci
31571cb0ef41Sopenharmony_ci  setTimeout(msecs, callback) {
31581cb0ef41Sopenharmony_ci    this.timeout = msecs;
31591cb0ef41Sopenharmony_ci    if (callback !== undefined) {
31601cb0ef41Sopenharmony_ci      validateFunction(callback, 'callback');
31611cb0ef41Sopenharmony_ci      this.on('timeout', callback);
31621cb0ef41Sopenharmony_ci    }
31631cb0ef41Sopenharmony_ci    return this;
31641cb0ef41Sopenharmony_ci  }
31651cb0ef41Sopenharmony_ci
31661cb0ef41Sopenharmony_ci  updateSettings(settings) {
31671cb0ef41Sopenharmony_ci    assertIsObject(settings, 'settings');
31681cb0ef41Sopenharmony_ci    validateSettings(settings);
31691cb0ef41Sopenharmony_ci    this[kOptions].settings = { ...this[kOptions].settings, ...settings };
31701cb0ef41Sopenharmony_ci  }
31711cb0ef41Sopenharmony_ci}
31721cb0ef41Sopenharmony_ci
31731cb0ef41Sopenharmony_ciclass Http2Server extends NETServer {
31741cb0ef41Sopenharmony_ci  constructor(options, requestListener) {
31751cb0ef41Sopenharmony_ci    options = initializeOptions(options);
31761cb0ef41Sopenharmony_ci    super(options, connectionListener);
31771cb0ef41Sopenharmony_ci    this[kOptions] = options;
31781cb0ef41Sopenharmony_ci    this.timeout = 0;
31791cb0ef41Sopenharmony_ci    this.on('newListener', setupCompat);
31801cb0ef41Sopenharmony_ci    if (typeof requestListener === 'function')
31811cb0ef41Sopenharmony_ci      this.on('request', requestListener);
31821cb0ef41Sopenharmony_ci  }
31831cb0ef41Sopenharmony_ci
31841cb0ef41Sopenharmony_ci  setTimeout(msecs, callback) {
31851cb0ef41Sopenharmony_ci    this.timeout = msecs;
31861cb0ef41Sopenharmony_ci    if (callback !== undefined) {
31871cb0ef41Sopenharmony_ci      validateFunction(callback, 'callback');
31881cb0ef41Sopenharmony_ci      this.on('timeout', callback);
31891cb0ef41Sopenharmony_ci    }
31901cb0ef41Sopenharmony_ci    return this;
31911cb0ef41Sopenharmony_ci  }
31921cb0ef41Sopenharmony_ci
31931cb0ef41Sopenharmony_ci  updateSettings(settings) {
31941cb0ef41Sopenharmony_ci    assertIsObject(settings, 'settings');
31951cb0ef41Sopenharmony_ci    validateSettings(settings);
31961cb0ef41Sopenharmony_ci    this[kOptions].settings = { ...this[kOptions].settings, ...settings };
31971cb0ef41Sopenharmony_ci  }
31981cb0ef41Sopenharmony_ci}
31991cb0ef41Sopenharmony_ci
32001cb0ef41Sopenharmony_ciHttp2Server.prototype[EventEmitter.captureRejectionSymbol] = function(
32011cb0ef41Sopenharmony_ci  err, event, ...args) {
32021cb0ef41Sopenharmony_ci
32031cb0ef41Sopenharmony_ci  switch (event) {
32041cb0ef41Sopenharmony_ci    case 'stream': {
32051cb0ef41Sopenharmony_ci      // TODO(mcollina): we might want to match this with what we do on
32061cb0ef41Sopenharmony_ci      // the compat side.
32071cb0ef41Sopenharmony_ci      const { 0: stream } = args;
32081cb0ef41Sopenharmony_ci      if (stream.sentHeaders) {
32091cb0ef41Sopenharmony_ci        stream.destroy(err);
32101cb0ef41Sopenharmony_ci      } else {
32111cb0ef41Sopenharmony_ci        stream.respond({ [HTTP2_HEADER_STATUS]: 500 });
32121cb0ef41Sopenharmony_ci        stream.end();
32131cb0ef41Sopenharmony_ci      }
32141cb0ef41Sopenharmony_ci      break;
32151cb0ef41Sopenharmony_ci    }
32161cb0ef41Sopenharmony_ci    case 'request': {
32171cb0ef41Sopenharmony_ci      const { 1: res } = args;
32181cb0ef41Sopenharmony_ci      if (!res.headersSent && !res.finished) {
32191cb0ef41Sopenharmony_ci        // Don't leak headers.
32201cb0ef41Sopenharmony_ci        for (const name of res.getHeaderNames()) {
32211cb0ef41Sopenharmony_ci          res.removeHeader(name);
32221cb0ef41Sopenharmony_ci        }
32231cb0ef41Sopenharmony_ci        res.statusCode = 500;
32241cb0ef41Sopenharmony_ci        res.end(http.STATUS_CODES[500]);
32251cb0ef41Sopenharmony_ci      } else {
32261cb0ef41Sopenharmony_ci        res.destroy();
32271cb0ef41Sopenharmony_ci      }
32281cb0ef41Sopenharmony_ci      break;
32291cb0ef41Sopenharmony_ci    }
32301cb0ef41Sopenharmony_ci    default:
32311cb0ef41Sopenharmony_ci      ArrayPrototypeUnshift(args, err, event);
32321cb0ef41Sopenharmony_ci      ReflectApply(net.Server.prototype[EventEmitter.captureRejectionSymbol],
32331cb0ef41Sopenharmony_ci                   this, args);
32341cb0ef41Sopenharmony_ci  }
32351cb0ef41Sopenharmony_ci};
32361cb0ef41Sopenharmony_ci
32371cb0ef41Sopenharmony_cifunction setupCompat(ev) {
32381cb0ef41Sopenharmony_ci  if (ev === 'request') {
32391cb0ef41Sopenharmony_ci    this.removeListener('newListener', setupCompat);
32401cb0ef41Sopenharmony_ci    this.on('stream', FunctionPrototypeBind(onServerStream,
32411cb0ef41Sopenharmony_ci                                            this,
32421cb0ef41Sopenharmony_ci                                            this[kOptions].Http2ServerRequest,
32431cb0ef41Sopenharmony_ci                                            this[kOptions].Http2ServerResponse),
32441cb0ef41Sopenharmony_ci    );
32451cb0ef41Sopenharmony_ci  }
32461cb0ef41Sopenharmony_ci}
32471cb0ef41Sopenharmony_ci
32481cb0ef41Sopenharmony_cifunction socketOnClose() {
32491cb0ef41Sopenharmony_ci  const session = this[kSession];
32501cb0ef41Sopenharmony_ci  if (session !== undefined) {
32511cb0ef41Sopenharmony_ci    debugSessionObj(session, 'socket closed');
32521cb0ef41Sopenharmony_ci    const err = session.connecting ? new ERR_SOCKET_CLOSED() : null;
32531cb0ef41Sopenharmony_ci    const state = session[kState];
32541cb0ef41Sopenharmony_ci    state.streams.forEach((stream) => stream.close(NGHTTP2_CANCEL));
32551cb0ef41Sopenharmony_ci    state.pendingStreams.forEach((stream) => stream.close(NGHTTP2_CANCEL));
32561cb0ef41Sopenharmony_ci    session.close();
32571cb0ef41Sopenharmony_ci    session[kMaybeDestroy](err);
32581cb0ef41Sopenharmony_ci  }
32591cb0ef41Sopenharmony_ci}
32601cb0ef41Sopenharmony_ci
32611cb0ef41Sopenharmony_cifunction connect(authority, options, listener) {
32621cb0ef41Sopenharmony_ci  if (typeof options === 'function') {
32631cb0ef41Sopenharmony_ci    listener = options;
32641cb0ef41Sopenharmony_ci    options = undefined;
32651cb0ef41Sopenharmony_ci  }
32661cb0ef41Sopenharmony_ci
32671cb0ef41Sopenharmony_ci  assertIsObject(options, 'options');
32681cb0ef41Sopenharmony_ci  options = { ...options };
32691cb0ef41Sopenharmony_ci
32701cb0ef41Sopenharmony_ci  if (typeof authority === 'string')
32711cb0ef41Sopenharmony_ci    authority = new URL(authority);
32721cb0ef41Sopenharmony_ci
32731cb0ef41Sopenharmony_ci  assertIsObject(authority, 'authority', ['string', 'Object', 'URL']);
32741cb0ef41Sopenharmony_ci
32751cb0ef41Sopenharmony_ci  const protocol = authority.protocol || options.protocol || 'https:';
32761cb0ef41Sopenharmony_ci  const port = '' + (authority.port !== '' ?
32771cb0ef41Sopenharmony_ci    authority.port : (authority.protocol === 'http:' ? 80 : 443));
32781cb0ef41Sopenharmony_ci  let host = 'localhost';
32791cb0ef41Sopenharmony_ci
32801cb0ef41Sopenharmony_ci  if (authority.hostname) {
32811cb0ef41Sopenharmony_ci    host = authority.hostname;
32821cb0ef41Sopenharmony_ci
32831cb0ef41Sopenharmony_ci    if (host[0] === '[')
32841cb0ef41Sopenharmony_ci      host = StringPrototypeSlice(host, 1, -1);
32851cb0ef41Sopenharmony_ci  } else if (authority.host) {
32861cb0ef41Sopenharmony_ci    host = authority.host;
32871cb0ef41Sopenharmony_ci  }
32881cb0ef41Sopenharmony_ci
32891cb0ef41Sopenharmony_ci  let socket;
32901cb0ef41Sopenharmony_ci  if (typeof options.createConnection === 'function') {
32911cb0ef41Sopenharmony_ci    socket = options.createConnection(authority, options);
32921cb0ef41Sopenharmony_ci  } else {
32931cb0ef41Sopenharmony_ci    switch (protocol) {
32941cb0ef41Sopenharmony_ci      case 'http:':
32951cb0ef41Sopenharmony_ci        socket = net.connect({ port, host, ...options });
32961cb0ef41Sopenharmony_ci        break;
32971cb0ef41Sopenharmony_ci      case 'https:':
32981cb0ef41Sopenharmony_ci        socket = tls.connect(port, host, initializeTLSOptions(options, host));
32991cb0ef41Sopenharmony_ci        break;
33001cb0ef41Sopenharmony_ci      default:
33011cb0ef41Sopenharmony_ci        throw new ERR_HTTP2_UNSUPPORTED_PROTOCOL(protocol);
33021cb0ef41Sopenharmony_ci    }
33031cb0ef41Sopenharmony_ci  }
33041cb0ef41Sopenharmony_ci
33051cb0ef41Sopenharmony_ci  const session = new ClientHttp2Session(options, socket);
33061cb0ef41Sopenharmony_ci
33071cb0ef41Sopenharmony_ci  session[kAuthority] = `${options.servername || host}:${port}`;
33081cb0ef41Sopenharmony_ci  session[kProtocol] = protocol;
33091cb0ef41Sopenharmony_ci
33101cb0ef41Sopenharmony_ci  if (typeof listener === 'function')
33111cb0ef41Sopenharmony_ci    session.once('connect', listener);
33121cb0ef41Sopenharmony_ci
33131cb0ef41Sopenharmony_ci  return session;
33141cb0ef41Sopenharmony_ci}
33151cb0ef41Sopenharmony_ci
33161cb0ef41Sopenharmony_ci// Support util.promisify
33171cb0ef41Sopenharmony_ciObjectDefineProperty(connect, promisify.custom, {
33181cb0ef41Sopenharmony_ci  __proto__: null,
33191cb0ef41Sopenharmony_ci  value: (authority, options) => {
33201cb0ef41Sopenharmony_ci    return new Promise((resolve) => {
33211cb0ef41Sopenharmony_ci      const server = connect(authority, options, () => resolve(server));
33221cb0ef41Sopenharmony_ci    });
33231cb0ef41Sopenharmony_ci  },
33241cb0ef41Sopenharmony_ci});
33251cb0ef41Sopenharmony_ci
33261cb0ef41Sopenharmony_cifunction createSecureServer(options, handler) {
33271cb0ef41Sopenharmony_ci  return new Http2SecureServer(options, handler);
33281cb0ef41Sopenharmony_ci}
33291cb0ef41Sopenharmony_ci
33301cb0ef41Sopenharmony_cifunction createServer(options, handler) {
33311cb0ef41Sopenharmony_ci  if (typeof options === 'function') {
33321cb0ef41Sopenharmony_ci    handler = options;
33331cb0ef41Sopenharmony_ci    options = kEmptyObject;
33341cb0ef41Sopenharmony_ci  }
33351cb0ef41Sopenharmony_ci  return new Http2Server(options, handler);
33361cb0ef41Sopenharmony_ci}
33371cb0ef41Sopenharmony_ci
33381cb0ef41Sopenharmony_ci// Returns a Base64 encoded settings frame payload from the given
33391cb0ef41Sopenharmony_ci// object. The value is suitable for passing as the value of the
33401cb0ef41Sopenharmony_ci// HTTP2-Settings header frame.
33411cb0ef41Sopenharmony_cifunction getPackedSettings(settings) {
33421cb0ef41Sopenharmony_ci  assertIsObject(settings, 'settings');
33431cb0ef41Sopenharmony_ci  validateSettings(settings);
33441cb0ef41Sopenharmony_ci  updateSettingsBuffer({ ...settings });
33451cb0ef41Sopenharmony_ci  return binding.packSettings();
33461cb0ef41Sopenharmony_ci}
33471cb0ef41Sopenharmony_ci
33481cb0ef41Sopenharmony_cifunction getUnpackedSettings(buf, options = kEmptyObject) {
33491cb0ef41Sopenharmony_ci  if (!isArrayBufferView(buf) || buf.length === undefined) {
33501cb0ef41Sopenharmony_ci    throw new ERR_INVALID_ARG_TYPE('buf',
33511cb0ef41Sopenharmony_ci                                   ['Buffer', 'TypedArray'], buf);
33521cb0ef41Sopenharmony_ci  }
33531cb0ef41Sopenharmony_ci  if (buf.length % 6 !== 0)
33541cb0ef41Sopenharmony_ci    throw new ERR_HTTP2_INVALID_PACKED_SETTINGS_LENGTH();
33551cb0ef41Sopenharmony_ci  const settings = {};
33561cb0ef41Sopenharmony_ci  let offset = 0;
33571cb0ef41Sopenharmony_ci  while (offset < buf.length) {
33581cb0ef41Sopenharmony_ci    const id = ReflectApply(readUInt16BE, buf, [offset]);
33591cb0ef41Sopenharmony_ci    offset += 2;
33601cb0ef41Sopenharmony_ci    const value = ReflectApply(readUInt32BE, buf, [offset]);
33611cb0ef41Sopenharmony_ci    switch (id) {
33621cb0ef41Sopenharmony_ci      case NGHTTP2_SETTINGS_HEADER_TABLE_SIZE:
33631cb0ef41Sopenharmony_ci        settings.headerTableSize = value;
33641cb0ef41Sopenharmony_ci        break;
33651cb0ef41Sopenharmony_ci      case NGHTTP2_SETTINGS_ENABLE_PUSH:
33661cb0ef41Sopenharmony_ci        settings.enablePush = value !== 0;
33671cb0ef41Sopenharmony_ci        break;
33681cb0ef41Sopenharmony_ci      case NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS:
33691cb0ef41Sopenharmony_ci        settings.maxConcurrentStreams = value;
33701cb0ef41Sopenharmony_ci        break;
33711cb0ef41Sopenharmony_ci      case NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE:
33721cb0ef41Sopenharmony_ci        settings.initialWindowSize = value;
33731cb0ef41Sopenharmony_ci        break;
33741cb0ef41Sopenharmony_ci      case NGHTTP2_SETTINGS_MAX_FRAME_SIZE:
33751cb0ef41Sopenharmony_ci        settings.maxFrameSize = value;
33761cb0ef41Sopenharmony_ci        break;
33771cb0ef41Sopenharmony_ci      case NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE:
33781cb0ef41Sopenharmony_ci        settings.maxHeaderListSize = settings.maxHeaderSize = value;
33791cb0ef41Sopenharmony_ci        break;
33801cb0ef41Sopenharmony_ci      case NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL:
33811cb0ef41Sopenharmony_ci        settings.enableConnectProtocol = value !== 0;
33821cb0ef41Sopenharmony_ci    }
33831cb0ef41Sopenharmony_ci    offset += 4;
33841cb0ef41Sopenharmony_ci  }
33851cb0ef41Sopenharmony_ci
33861cb0ef41Sopenharmony_ci  if (options != null && options.validate)
33871cb0ef41Sopenharmony_ci    validateSettings(settings);
33881cb0ef41Sopenharmony_ci
33891cb0ef41Sopenharmony_ci  return settings;
33901cb0ef41Sopenharmony_ci}
33911cb0ef41Sopenharmony_ci
33921cb0ef41Sopenharmony_cibinding.setCallbackFunctions(
33931cb0ef41Sopenharmony_ci  onSessionInternalError,
33941cb0ef41Sopenharmony_ci  onPriority,
33951cb0ef41Sopenharmony_ci  onSettings,
33961cb0ef41Sopenharmony_ci  onPing,
33971cb0ef41Sopenharmony_ci  onSessionHeaders,
33981cb0ef41Sopenharmony_ci  onFrameError,
33991cb0ef41Sopenharmony_ci  onGoawayData,
34001cb0ef41Sopenharmony_ci  onAltSvc,
34011cb0ef41Sopenharmony_ci  onOrigin,
34021cb0ef41Sopenharmony_ci  onStreamTrailers,
34031cb0ef41Sopenharmony_ci  onStreamClose,
34041cb0ef41Sopenharmony_ci);
34051cb0ef41Sopenharmony_ci
34061cb0ef41Sopenharmony_ci// Exports
34071cb0ef41Sopenharmony_cimodule.exports = {
34081cb0ef41Sopenharmony_ci  connect,
34091cb0ef41Sopenharmony_ci  constants,
34101cb0ef41Sopenharmony_ci  createServer,
34111cb0ef41Sopenharmony_ci  createSecureServer,
34121cb0ef41Sopenharmony_ci  getDefaultSettings,
34131cb0ef41Sopenharmony_ci  getPackedSettings,
34141cb0ef41Sopenharmony_ci  getUnpackedSettings,
34151cb0ef41Sopenharmony_ci  sensitiveHeaders: kSensitiveHeaders,
34161cb0ef41Sopenharmony_ci  Http2Session,
34171cb0ef41Sopenharmony_ci  Http2Stream,
34181cb0ef41Sopenharmony_ci  ServerHttp2Session,
34191cb0ef41Sopenharmony_ci  Http2ServerRequest,
34201cb0ef41Sopenharmony_ci  Http2ServerResponse,
34211cb0ef41Sopenharmony_ci};
3422