mirror of
https://github.com/tenrok/axios.git
synced 2026-06-17 19:21:29 +03:00
fix(http): guard socket.setKeepAlive for proxy agent streams (#10917)
Co-authored-by: Maks Pikov <mixelburg@users.noreply.github.com> Co-authored-by: Jay <jasonsaayman@gmail.com>
This commit is contained in:
@@ -1 +1,7 @@
|
|||||||
# Pre-Release Changelog
|
# Pre-Release Changelog
|
||||||
|
|
||||||
|
## Unreleased
|
||||||
|
|
||||||
|
## Bug Fixes
|
||||||
|
|
||||||
|
- **Proxy Agent Streams:** Guarded Node HTTP adapter TCP keep-alive setup so proxy agents that return generic Duplex streams do not throw when `setKeepAlive` is unavailable. (**#10917**, closes **#10908**)
|
||||||
@@ -1205,7 +1205,11 @@ export default isHttpAdapterSupported &&
|
|||||||
|
|
||||||
req.on('socket', function handleRequestSocket(socket) {
|
req.on('socket', function handleRequestSocket(socket) {
|
||||||
// default interval of sending ack packet is 1 minute
|
// default interval of sending ack packet is 1 minute
|
||||||
socket.setKeepAlive(true, 1000 * 60);
|
// proxy agents (e.g. agent-base) may return a generic Duplex stream
|
||||||
|
// that doesn't have setKeepAlive, so guard before calling
|
||||||
|
if (typeof socket.setKeepAlive === 'function') {
|
||||||
|
socket.setKeepAlive(true, 1000 * 60);
|
||||||
|
}
|
||||||
|
|
||||||
// Install a single 'error' listener per socket (not per request) to avoid
|
// Install a single 'error' listener per socket (not per request) to avoid
|
||||||
// accumulating listeners on pooled keep-alive sockets that get reassigned
|
// accumulating listeners on pooled keep-alive sockets that get reassigned
|
||||||
|
|||||||
@@ -6169,6 +6169,58 @@ describe('supports http with nodejs', () => {
|
|||||||
'second request should be destroyed by its own active socket error'
|
'second request should be destroyed by its own active socket error'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should not throw TypeError when a proxy agent stream does not define setKeepAlive (regression #10908)', async () => {
|
||||||
|
// proxy agents (e.g. agent-base) may provide a generic Duplex stream as
|
||||||
|
// the socket; that stream does not define setKeepAlive.
|
||||||
|
const socket = new stream.Duplex({
|
||||||
|
read() {},
|
||||||
|
write(_chunk, _encoding, callback) {
|
||||||
|
callback();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
assert.strictEqual(typeof socket.setKeepAlive, 'undefined');
|
||||||
|
|
||||||
|
const transport = {
|
||||||
|
request(_, cb) {
|
||||||
|
return new (class MockRequest extends EventEmitter {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.destroyed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout() {}
|
||||||
|
write() {}
|
||||||
|
|
||||||
|
end() {
|
||||||
|
this.emit('socket', socket);
|
||||||
|
|
||||||
|
setImmediate(() => {
|
||||||
|
const response = stream.Readable.from(['ok']);
|
||||||
|
response.statusCode = 200;
|
||||||
|
response.headers = {};
|
||||||
|
cb(response);
|
||||||
|
this.emit('close');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
destroy(err) {
|
||||||
|
if (this.destroyed) return;
|
||||||
|
this.destroyed = true;
|
||||||
|
err && this.emit('error', err);
|
||||||
|
this.emit('close');
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = await axios.get('http://example.com/', {
|
||||||
|
transport,
|
||||||
|
maxRedirects: 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.strictEqual(result.status, 200);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('redirect listener accumulation', () => {
|
describe('redirect listener accumulation', () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user