2
0
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:
mixelburg
2026-06-15 15:20:25 +03:00
committed by GitHub
parent 885b3e8507
commit 227c788eb7
3 changed files with 63 additions and 1 deletions
+6
View File
@@ -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**)
+5 -1
View File
@@ -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
+52
View File
@@ -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', () => {