"use strict";

function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
function _toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
const Stream = require('stream');
const net = require('net');
const tls = require('tls');
// eslint-disable-next-line node/no-deprecated-api
const _require = require('url'),
  parse = _require.parse;
const process = require('process');
const semverGte = require('semver/functions/gte');
let http2;
if (semverGte(process.version, 'v10.10.0')) http2 = require('http2');else throw new Error('superagent: this version of Node.js does not support http2');
const _http2$constants = http2.constants,
  HTTP2_HEADER_PATH = _http2$constants.HTTP2_HEADER_PATH,
  HTTP2_HEADER_STATUS = _http2$constants.HTTP2_HEADER_STATUS,
  HTTP2_HEADER_METHOD = _http2$constants.HTTP2_HEADER_METHOD,
  HTTP2_HEADER_AUTHORITY = _http2$constants.HTTP2_HEADER_AUTHORITY,
  HTTP2_HEADER_HOST = _http2$constants.HTTP2_HEADER_HOST,
  HTTP2_HEADER_SET_COOKIE = _http2$constants.HTTP2_HEADER_SET_COOKIE,
  NGHTTP2_CANCEL = _http2$constants.NGHTTP2_CANCEL;
function setProtocol(protocol) {
  return {
    request(options) {
      return new Request(protocol, options);
    }
  };
}
class Request extends Stream {
  constructor(protocol, options) {
    super();
    const defaultPort = protocol === 'https:' ? 443 : 80;
    const defaultHost = 'localhost';
    const port = options.port || defaultPort;
    const host = options.host || defaultHost;
    delete options.port;
    delete options.host;
    this.method = options.method;
    this.path = options.path;
    this.protocol = protocol;
    this.host = host;
    delete options.method;
    delete options.path;
    const sessionOptions = _objectSpread({}, options);
    if (options.socketPath) {
      sessionOptions.socketPath = options.socketPath;
      sessionOptions.createConnection = this.createUnixConnection.bind(this);
    }
    this._headers = {};
    const session = http2.connect(`${protocol}//${host}:${port}`, sessionOptions);
    this.setHeader('host', `${host}:${port}`);
    session.on('error', error => this.emit('error', error));
    this.session = session;
  }
  createUnixConnection(authority, options) {
    switch (this.protocol) {
      case 'http:':
        return net.connect(options.socketPath);
      case 'https:':
        options.ALPNProtocols = ['h2'];
        options.servername = this.host;
        options.allowHalfOpen = true;
        return tls.connect(options.socketPath, options);
      default:
        throw new Error('Unsupported protocol', this.protocol);
    }
  }
  setNoDelay(bool) {
    // We can not use setNoDelay with HTTP/2.
    // Node 10 limits http2session.socket methods to ones safe to use with HTTP/2.
    // See also https://nodejs.org/api/http2.html#http2_http2session_socket
  }
  getFrame() {
    if (this.frame) {
      return this.frame;
    }
    const method = {
      [HTTP2_HEADER_PATH]: this.path,
      [HTTP2_HEADER_METHOD]: this.method
    };
    let headers = this.mapToHttp2Header(this._headers);
    headers = Object.assign(headers, method);
    const frame = this.session.request(headers);
    frame.once('response', (headers, flags) => {
      headers = this.mapToHttpHeader(headers);
      frame.headers = headers;
      frame.statusCode = headers[HTTP2_HEADER_STATUS];
      frame.status = frame.statusCode;
      this.emit('response', frame);
    });
    this._headerSent = true;
    frame.once('drain', () => this.emit('drain'));
    frame.on('error', error => this.emit('error', error));
    frame.on('close', () => this.session.close());
    this.frame = frame;
    return frame;
  }
  mapToHttpHeader(headers) {
    const keys = Object.keys(headers);
    const http2Headers = {};
    for (var _i = 0, _keys = keys; _i < _keys.length; _i++) {
      let key = _keys[_i];
      let value = headers[key];
      key = key.toLowerCase();
      switch (key) {
        case HTTP2_HEADER_SET_COOKIE:
          value = Array.isArray(value) ? value : [value];
          break;
        default:
          break;
      }
      http2Headers[key] = value;
    }
    return http2Headers;
  }
  mapToHttp2Header(headers) {
    const keys = Object.keys(headers);
    const http2Headers = {};
    for (var _i2 = 0, _keys2 = keys; _i2 < _keys2.length; _i2++) {
      let key = _keys2[_i2];
      let value = headers[key];
      key = key.toLowerCase();
      switch (key) {
        case HTTP2_HEADER_HOST:
          key = HTTP2_HEADER_AUTHORITY;
          value = /^http:\/\/|^https:\/\//.test(value) ? parse(value).host : value;
          break;
        default:
          break;
      }
      http2Headers[key] = value;
    }
    return http2Headers;
  }
  setHeader(name, value) {
    this._headers[name.toLowerCase()] = value;
  }
  getHeader(name) {
    return this._headers[name.toLowerCase()];
  }
  write(data, encoding) {
    const frame = this.getFrame();
    return frame.write(data, encoding);
  }
  pipe(stream, options) {
    const frame = this.getFrame();
    return frame.pipe(stream, options);
  }
  end(data) {
    const frame = this.getFrame();
    frame.end(data);
  }
  abort(data) {
    const frame = this.getFrame();
    frame.close(NGHTTP2_CANCEL);
    this.session.destroy();
  }
}
exports.setProtocol = setProtocol;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,[encoded data, 15420 characters]