You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
154 lines
4.1 KiB
154 lines
4.1 KiB
5 years ago
|
var url = require('url');
|
||
|
var http = require('http');
|
||
|
var https = require('https');
|
||
|
var through = require('through2');
|
||
|
var duplexer = require('duplexer2');
|
||
|
var bufferFrom = require('buffer-from');
|
||
|
|
||
|
module.exports = hyperquest;
|
||
|
|
||
|
function bind (obj, fn) {
|
||
|
var args = Array.prototype.slice.call(arguments, 2);
|
||
|
return function () {
|
||
|
var argv = args.concat(Array.prototype.slice.call(arguments));
|
||
|
return fn.apply(obj, argv);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function hyperquest (uri, opts, cb, extra) {
|
||
|
if (typeof uri === 'object') {
|
||
|
cb = opts;
|
||
|
opts = uri;
|
||
|
uri = undefined;
|
||
|
}
|
||
|
if (typeof opts === 'function') {
|
||
|
cb = opts;
|
||
|
opts = undefined;
|
||
|
}
|
||
|
if (!opts) opts = {};
|
||
|
if (uri !== undefined) opts.uri = uri;
|
||
|
if (extra) opts.method = extra.method;
|
||
|
|
||
|
var req = new Req(opts);
|
||
|
var ws = req.duplex && through();
|
||
|
var rs = through();
|
||
|
|
||
|
var dup = req.duplex ? duplexer(ws, rs) : rs;
|
||
|
if (!req.duplex) {
|
||
|
rs.writable = false;
|
||
|
}
|
||
|
dup.request = req;
|
||
|
dup.setHeader = bind(req, req.setHeader);
|
||
|
dup.setLocation = bind(req, req.setLocation);
|
||
|
|
||
|
var closed = false;
|
||
|
dup.on('close', function () { closed = true });
|
||
|
|
||
|
process.nextTick(function () {
|
||
|
if (closed) return;
|
||
|
dup.on('close', function () { r.destroy() });
|
||
|
|
||
|
var r = req._send();
|
||
|
r.on('error', bind(dup, dup.emit, 'error'));
|
||
|
dup.emit('request', r);
|
||
|
|
||
|
r.on('response', function (res) {
|
||
|
dup.response = res;
|
||
|
dup.emit('response', res);
|
||
|
if (req.duplex) res.pipe(rs)
|
||
|
else {
|
||
|
res.on('data', function (buf) { rs.push(buf) });
|
||
|
res.on('end', function () { rs.push(null) });
|
||
|
}
|
||
|
});
|
||
|
|
||
|
if (req.duplex) {
|
||
|
ws.pipe(r);
|
||
|
}
|
||
|
else r.end();
|
||
|
});
|
||
|
|
||
|
if (cb) {
|
||
|
dup.on('error', cb);
|
||
|
dup.on('response', bind(dup, cb, null));
|
||
|
}
|
||
|
return dup;
|
||
|
}
|
||
|
|
||
|
hyperquest.get = hyperquest;
|
||
|
|
||
|
hyperquest.post = function (uri, opts, cb) {
|
||
|
return hyperquest(uri, opts, cb, { method: 'POST' });
|
||
|
};
|
||
|
|
||
|
hyperquest.put = function (uri, opts, cb) {
|
||
|
return hyperquest(uri, opts, cb, { method: 'PUT' });
|
||
|
};
|
||
|
|
||
|
hyperquest['delete'] = function (uri, opts, cb) {
|
||
|
return hyperquest(uri, opts, cb, { method: 'DELETE' });
|
||
|
};
|
||
|
|
||
|
function Req (opts) {
|
||
|
this.headers = opts.headers || {};
|
||
|
|
||
|
var method = (opts.method || 'GET').toUpperCase();
|
||
|
this.method = method;
|
||
|
this.duplex = !(method === 'GET' || method === 'HEAD');
|
||
|
this.auth = opts.auth;
|
||
|
|
||
|
this.options = opts;
|
||
|
|
||
|
if (opts.uri) this.setLocation(opts.uri);
|
||
|
}
|
||
|
|
||
|
Req.prototype._send = function () {
|
||
|
this._sent = true;
|
||
|
|
||
|
var headers = this.headers || {};
|
||
|
var u = url.parse(this.uri);
|
||
|
var au = u.auth || this.auth;
|
||
|
if (au) {
|
||
|
headers.authorization = 'Basic ' + bufferFrom(au).toString('base64');
|
||
|
}
|
||
|
|
||
|
var protocol = u.protocol || '';
|
||
|
var iface = protocol === 'https:' ? https : http;
|
||
|
var opts = {
|
||
|
scheme: protocol.replace(/:$/, ''),
|
||
|
method: this.method,
|
||
|
host: u.hostname,
|
||
|
port: Number(u.port) || (protocol === 'https:' ? 443 : 80),
|
||
|
path: u.path,
|
||
|
agent: this.options.agent || false,
|
||
|
headers: headers,
|
||
|
withCredentials: this.options.withCredentials,
|
||
|
localAddress: this.options.localAddress
|
||
|
};
|
||
|
if (protocol === 'https:') {
|
||
|
opts.pfx = this.options.pfx;
|
||
|
opts.key = this.options.key;
|
||
|
opts.cert = this.options.cert;
|
||
|
opts.ca = this.options.ca;
|
||
|
opts.ciphers = this.options.ciphers;
|
||
|
opts.rejectUnauthorized = this.options.rejectUnauthorized;
|
||
|
opts.secureProtocol = this.options.secureProtocol;
|
||
|
}
|
||
|
var req = iface.request(opts);
|
||
|
|
||
|
var timeout = this.options.timeout || 2147483647;
|
||
|
if (req.setTimeout) req.setTimeout(timeout);
|
||
|
return req;
|
||
|
};
|
||
|
|
||
|
Req.prototype.setHeader = function (key, value) {
|
||
|
if (this._sent) throw new Error('request already sent');
|
||
|
this.headers[key] = value;
|
||
|
return this;
|
||
|
};
|
||
|
|
||
|
Req.prototype.setLocation = function (uri) {
|
||
|
this.uri = uri;
|
||
|
return this;
|
||
|
};
|