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
|
||||
|
||||
## 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) {
|
||||
// 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
|
||||
// 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'
|
||||
);
|
||||
});
|
||||
|
||||
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', () => {
|
||||
|
||||
Reference in New Issue
Block a user