"use strict"; function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } var Stream = require('stream'); var util = require('util'); var net = require('net'); var tls = require('tls'); // eslint-disable-next-line node/no-deprecated-api var _require = require('url'), parse = _require.parse; var semver = require('semver'); var http2; if (semver.gte(process.version, 'v10.10.0')) http2 = require('http2');else throw new Error('superagent: this version of Node.js does not support http2'); var _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: function request(options) { return new Request(protocol, options); } }; } function Request(protocol, options) { var _this = this; Stream.call(this); var defaultPort = protocol === 'https:' ? 443 : 80; var defaultHost = 'localhost'; var port = options.port || defaultPort; var 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; var sessionOptions = _objectSpread({}, options); if (options.socketPath) { sessionOptions.socketPath = options.socketPath; sessionOptions.createConnection = this.createUnixConnection.bind(this); } this._headers = {}; var session = http2.connect("".concat(protocol, "//").concat(host, ":").concat(port), sessionOptions); this.setHeader('host', "".concat(host, ":").concat(port)); session.on('error', function (err) { return _this.emit('error', err); }); this.session = session; } /** * Inherit from `Stream` (which inherits from `EventEmitter`). */ util.inherits(Request, Stream); Request.prototype.createUnixConnection = function (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); } }; // eslint-disable-next-line no-unused-vars Request.prototype.setNoDelay = function (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 }; Request.prototype.getFrame = function () { var _method, _this2 = this; if (this.frame) { return this.frame; } var method = (_method = {}, _defineProperty(_method, HTTP2_HEADER_PATH, this.path), _defineProperty(_method, HTTP2_HEADER_METHOD, this.method), _method); var headers = this.mapToHttp2Header(this._headers); headers = Object.assign(headers, method); var frame = this.session.request(headers); // eslint-disable-next-line no-unused-vars frame.once('response', function (headers, flags) { headers = _this2.mapToHttpHeader(headers); frame.headers = headers; frame.statusCode = headers[HTTP2_HEADER_STATUS]; frame.status = frame.statusCode; _this2.emit('response', frame); }); this._headerSent = true; frame.once('drain', function () { return _this2.emit('drain'); }); frame.on('error', function (err) { return _this2.emit('error', err); }); frame.on('close', function () { return _this2.session.close(); }); this.frame = frame; return frame; }; Request.prototype.mapToHttpHeader = function (headers) { var keys = Object.keys(headers); var http2Headers = {}; for (var i = 0; i < keys.length; i++) { var key = keys[i]; var 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; }; Request.prototype.mapToHttp2Header = function (headers) { var keys = Object.keys(headers); var http2Headers = {}; for (var i = 0; i < keys.length; i++) { var key = keys[i]; var 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; }; Request.prototype.setHeader = function (name, value) { this._headers[name.toLowerCase()] = value; }; Request.prototype.getHeader = function (name) { return this._headers[name.toLowerCase()]; }; Request.prototype.write = function (data, encoding) { var frame = this.getFrame(); return frame.write(data, encoding); }; Request.prototype.pipe = function (stream, options) { var frame = this.getFrame(); return frame.pipe(stream, options); }; Request.prototype.end = function (data) { var frame = this.getFrame(); frame.end(data); }; // eslint-disable-next-line no-unused-vars Request.prototype.abort = function (data) { var frame = this.getFrame(); frame.close(NGHTTP2_CANCEL); this.session.destroy(); }; exports.setProtocol = setProtocol;