| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent f3a16b6 commit cbd5768
1 file changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,83 @@ | |||
| 1 | + 'use strict'; | ||
| 2 | + const common = require('../common'); | ||
| 3 | + const assert = require('node:assert'); | ||
| 4 | + const { AsyncLocalStorage } = require('node:async_hooks'); | ||
| 5 | + const http = require('node:http'); | ||
| 6 | + | ||
| 7 | + // Similar as test-async-hooks-http-agent added via | ||
| 8 | + // https://github.com/nodejs/node/issues/13325 but verifies | ||
| 9 | + // AsyncLocalStorage functionality instead async_hooks | ||
| 10 | + | ||
| 11 | + const cls = new AsyncLocalStorage(); | ||
| 12 | + | ||
| 13 | + // Make sure a single socket is transparently reused for 2 requests. | ||
| 14 | + const agent = new http.Agent({ | ||
| 15 | + keepAlive: true, | ||
| 16 | + keepAliveMsecs: Infinity, | ||
| 17 | + maxSockets: 1 | ||
| 18 | + }); | ||
| 19 | + | ||
| 20 | + const server = http.createServer(common.mustCall((req, res) => { | ||
| 21 | + req.once('data', common.mustCallAtLeast(() => { | ||
| 22 | + res.writeHead(200, { 'Content-Type': 'text/plain' }); | ||
| 23 | + res.write('foo'); | ||
| 24 | + })); | ||
| 25 | + req.on('end', common.mustCall(() => { | ||
| 26 | + res.end('bar'); | ||
| 27 | + })); | ||
| 28 | + }, 2)).listen(0, common.mustCall(() => { | ||
| 29 | + const port = server.address().port; | ||
| 30 | + const payload = 'hello world'; | ||
| 31 | + | ||
| 32 | + // First request. This is useless except for adding a socket to the | ||
| 33 | + // agent’s pool for reuse. | ||
| 34 | + cls.run('first', common.mustCall(() => { | ||
| 35 | + assert.strictEqual(cls.getStore(), 'first'); | ||
| 36 | + const r1 = http.request({ | ||
| 37 | + agent, port, method: 'POST' | ||
| 38 | + }, common.mustCall((res) => { | ||
| 39 | + assert.strictEqual(cls.getStore(), 'first'); | ||
| 40 | + res.on('data', common.mustCallAtLeast(() => { | ||
| 41 | + assert.strictEqual(cls.getStore(), 'first'); | ||
| 42 | + })); | ||
| 43 | + res.on('end', common.mustCall(() => { | ||
| 44 | + assert.strictEqual(cls.getStore(), 'first'); | ||
| 45 | + // setImmediate() to give the agent time to register the freed socket. | ||
| 46 | + setImmediate(common.mustCall(() => { | ||
| 47 | + assert.strictEqual(cls.getStore(), 'first'); | ||
| 48 | + | ||
| 49 | + cls.run('second', common.mustCall(() => { | ||
| 50 | + // Second request. To re-create the exact conditions from the | ||
| 51 | + // referenced issue, we use a POST request without chunked encoding | ||
| 52 | + // (hence the Content-Length header) and call .end() after the | ||
| 53 | + // response header has already been received. | ||
| 54 | + const r2 = http.request({ | ||
| 55 | + agent, port, method: 'POST', headers: { | ||
| 56 | + 'Content-Length': payload.length | ||
| 57 | + } | ||
| 58 | + }, common.mustCall((res) => { | ||
| 59 | + assert.strictEqual(cls.getStore(), 'second'); | ||
| 60 | + // Empty payload, to hit the “right” code path. | ||
| 61 | + r2.end(''); | ||
| 62 | + | ||
| 63 | + res.on('data', common.mustCallAtLeast(() => { | ||
| 64 | + assert.strictEqual(cls.getStore(), 'second'); | ||
| 65 | + })); | ||
| 66 | + res.on('end', common.mustCall(() => { | ||
| 67 | + assert.strictEqual(cls.getStore(), 'second'); | ||
| 68 | + // Clean up to let the event loop stop. | ||
| 69 | + server.close(); | ||
| 70 | + agent.destroy(); | ||
| 71 | + })); | ||
| 72 | + })); | ||
| 73 | + | ||
| 74 | + // Schedule a payload to be written immediately, but do not end the | ||
| 75 | + // request just yet. | ||
| 76 | + r2.write(payload); | ||
| 77 | + })); | ||
| 78 | + })); | ||
| 79 | + })); | ||
| 80 | + })); | ||
| 81 | + r1.end(payload); | ||
| 82 | + })); | ||
| 83 | + })); | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments