215 lines
6.2 KiB
JavaScript
215 lines
6.2 KiB
JavaScript
|
"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;
|