|
'use strict';
|
|
const {PassThrough} = require('stream');
|
|
const duplexer3 = require('duplexer3');
|
|
const requestAsEventEmitter = require('./request-as-event-emitter');
|
|
const {HTTPError, ReadError} = require('./errors');
|
|
|
|
module.exports = options => {
|
|
const input = new PassThrough();
|
|
const output = new PassThrough();
|
|
const proxy = duplexer3(input, output);
|
|
const piped = new Set();
|
|
let isFinished = false;
|
|
|
|
options.retry.retries = () => 0;
|
|
|
|
if (options.body) {
|
|
proxy.write = () => {
|
|
throw new Error('Got\'s stream is not writable when the `body` option is used');
|
|
};
|
|
}
|
|
|
|
const emitter = requestAsEventEmitter(options, input);
|
|
|
|
// Cancels the request
|
|
proxy._destroy = emitter.abort;
|
|
|
|
emitter.on('response', response => {
|
|
const {statusCode} = response;
|
|
|
|
response.on('error', error => {
|
|
proxy.emit('error', new ReadError(error, options));
|
|
});
|
|
|
|
if (options.throwHttpErrors && statusCode !== 304 && (statusCode < 200 || statusCode > 299)) {
|
|
proxy.emit('error', new HTTPError(response, options), null, response);
|
|
return;
|
|
}
|
|
|
|
isFinished = true;
|
|
|
|
response.pipe(output);
|
|
|
|
for (const destination of piped) {
|
|
if (destination.headersSent) {
|
|
continue;
|
|
}
|
|
|
|
for (const [key, value] of Object.entries(response.headers)) {
|
|
// Got gives *decompressed* data. Overriding `content-encoding` header would result in an error.
|
|
// It's not possible to decompress already decompressed data, is it?
|
|
const allowed = options.decompress ? key !== 'content-encoding' : true;
|
|
if (allowed) {
|
|
destination.setHeader(key, value);
|
|
}
|
|
}
|
|
|
|
destination.statusCode = response.statusCode;
|
|
}
|
|
|
|
proxy.emit('response', response);
|
|
});
|
|
|
|
[
|
|
'error',
|
|
'request',
|
|
'redirect',
|
|
'uploadProgress',
|
|
'downloadProgress'
|
|
].forEach(event => emitter.on(event, (...args) => proxy.emit(event, ...args)));
|
|
|
|
const pipe = proxy.pipe.bind(proxy);
|
|
const unpipe = proxy.unpipe.bind(proxy);
|
|
proxy.pipe = (destination, options) => {
|
|
if (isFinished) {
|
|
throw new Error('Failed to pipe. The response has been emitted already.');
|
|
}
|
|
|
|
const result = pipe(destination, options);
|
|
|
|
if (Reflect.has(destination, 'setHeader')) {
|
|
piped.add(destination);
|
|
}
|
|
|
|
return result;
|
|
};
|
|
proxy.unpipe = stream => {
|
|
piped.delete(stream);
|
|
return unpipe(stream);
|
|
};
|
|
|
|
return proxy;
|
|
};
|