diff --git a/lib/adapters/http.js b/lib/adapters/http.js index ea69ff2..5326dd0 100755 --- a/lib/adapters/http.js +++ b/lib/adapters/http.js @@ -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}'`); } diff --git a/test/unit/adapters/http.js b/test/unit/adapters/http.js index 2f63bbf..7d0cf18 100644 --- a/test/unit/adapters/http.js +++ b/test/unit/adapters/http.js @@ -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'); }); }); });