mirror of
https://github.com/tenrok/axios.git
synced 2026-05-15 11:59:42 +03:00
fix(http2): fix possible race condition when handling http2 stream on almost timed out session by improving timeout out algorithm; (#7186)
This commit is contained in:
+46
-10
@@ -87,7 +87,15 @@ class Http2Sessions {
|
||||
|
||||
const session = connect(authority, options);
|
||||
|
||||
session.once('close', () => {
|
||||
let removed;
|
||||
|
||||
const removeSession = () => {
|
||||
if (removed) {
|
||||
return;
|
||||
}
|
||||
|
||||
removed = true;
|
||||
|
||||
let entries = authoritySessions, len = entries.length, i = len;
|
||||
|
||||
while (i--) {
|
||||
@@ -99,9 +107,41 @@ class Http2Sessions {
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
Http2Sessions.setTimeout(session, options.sessionTimeout);
|
||||
const originalRequestFn = session.request;
|
||||
|
||||
const {sessionTimeout} = options;
|
||||
|
||||
if(sessionTimeout != null) {
|
||||
|
||||
let timer;
|
||||
let streamsCount = 0;
|
||||
|
||||
session.request = function () {
|
||||
const stream = originalRequestFn.apply(this, arguments);
|
||||
|
||||
streamsCount++;
|
||||
|
||||
if (timer) {
|
||||
clearTimeout(timer);
|
||||
timer = null;
|
||||
}
|
||||
|
||||
stream.once('close', () => {
|
||||
if (!--streamsCount) {
|
||||
timer = setTimeout(() => {
|
||||
timer = null;
|
||||
removeSession();
|
||||
}, sessionTimeout);
|
||||
}
|
||||
});
|
||||
|
||||
return stream;
|
||||
}
|
||||
}
|
||||
|
||||
session.once('close', removeSession);
|
||||
|
||||
let entries = this.sessions[authority], entry = [
|
||||
session,
|
||||
@@ -112,12 +152,6 @@ class Http2Sessions {
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
static setTimeout(session, timeout = 1000) {
|
||||
session && session.setTimeout(timeout, () => {
|
||||
session.close();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const http2Sessions = new Http2Sessions();
|
||||
@@ -284,10 +318,12 @@ export default isHttpAdapterSupported && function httpAdapter(config) {
|
||||
let rejected = false;
|
||||
let req;
|
||||
|
||||
httpVersion = Number(httpVersion);
|
||||
httpVersion = +httpVersion;
|
||||
|
||||
if (Number.isNaN(httpVersion)) {
|
||||
throw TypeError(`Invalid protocol version: '${config.httpVersion}' is not a number`);
|
||||
}
|
||||
|
||||
if (httpVersion !== 1 && httpVersion !== 2) {
|
||||
throw TypeError(`Unsupported protocol version '${httpVersion}'`);
|
||||
}
|
||||
|
||||
+16
-11
@@ -2423,7 +2423,7 @@ describe('supports http with nodejs', function () {
|
||||
});
|
||||
|
||||
it('should support request cancellation', async function (){
|
||||
if (typeof AbortSignal !== 'function') {
|
||||
if (typeof AbortSignal !== 'function' || !AbortSignal.timeout) {
|
||||
this.skip();
|
||||
}
|
||||
|
||||
@@ -2525,13 +2525,17 @@ describe('supports http with nodejs', function () {
|
||||
|
||||
it("should use different sessions for different authorities", async() => {
|
||||
server = await startHTTPServer((req, res) => {
|
||||
setTimeout(() => res.end('OK'), 1000);
|
||||
setTimeout(() => {
|
||||
res.end('OK');
|
||||
}, 2000);
|
||||
}, {
|
||||
useHTTP2: true
|
||||
});
|
||||
|
||||
server2 = await startHTTPServer((req, res) => {
|
||||
setTimeout(() => res.end('OK'), 1000);
|
||||
setTimeout(() => {
|
||||
res.end('OK');
|
||||
}, 2000);
|
||||
}, {
|
||||
useHTTP2: true,
|
||||
port: SERVER_PORT2
|
||||
@@ -2559,7 +2563,9 @@ describe('supports http with nodejs', function () {
|
||||
|
||||
it("should use different sessions for requests with different http2Options set", async() => {
|
||||
server = await startHTTPServer((req, res) => {
|
||||
setTimeout(() => res.end('OK'), 1000);
|
||||
setTimeout(() => {
|
||||
res.end('OK')
|
||||
}, 1000);
|
||||
}, {
|
||||
useHTTP2: true
|
||||
});
|
||||
@@ -2639,6 +2645,8 @@ describe('supports http with nodejs', function () {
|
||||
}
|
||||
});
|
||||
|
||||
const data1 = await getStream(response1.data);
|
||||
|
||||
await setTimeoutAsync(5000);
|
||||
|
||||
const response2 = await http2Axios.get(LOCAL_SERVER_URL, {
|
||||
@@ -2648,15 +2656,12 @@ describe('supports http with nodejs', function () {
|
||||
}
|
||||
});
|
||||
|
||||
const data2 = await getStream(response2.data);
|
||||
|
||||
assert.notStrictEqual(response1.data.session, response2.data.session);
|
||||
|
||||
assert.deepStrictEqual(
|
||||
await Promise.all([
|
||||
getStream(response1.data),
|
||||
getStream(response2.data)
|
||||
]),
|
||||
['OK', 'OK']
|
||||
);
|
||||
assert.strictEqual(data1, 'OK');
|
||||
assert.strictEqual(data2, 'OK');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user