| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent f912692 commit f24177c
2 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -51,6 +51,7 @@ const { | |||
| 51 | 51 | kSkipPendingData, | |
| 52 | 52 | } = require('_http_common'); | |
| 53 | 53 | const { | |
| 54 | + kHighWaterMark, | ||
| 54 | 55 | kUniqueHeaders, | |
| 55 | 56 | parseUniqueHeadersOption, | |
| 56 | 57 | OutgoingMessage, | |
@@ -348,6 +349,14 @@ function ClientRequest(input, options, cb) { | |||
| 348 | 349 | options = ObjectAssign({ __proto__: null }, input, options); | |
| 349 | 350 | } | |
| 350 | 351 | ||
| 352 | + // Propagate the user's highWaterMark to OutgoingMessage so that | ||
| 353 | + // _writeRaw() uses the correct threshold for writes buffered before | ||
| 354 | + // the socket connects (Path B). Without this, the OutgoingMessage | ||
| 355 | + // defaults to 64 KB regardless of what the caller requested. | ||
| 356 | + if (options.highWaterMark != null) { | ||
| 357 | + this[kHighWaterMark] = options.highWaterMark; | ||
| 358 | + } | ||
| 359 | + | ||
| 351 | 360 | let agent = options.agent; | |
| 352 | 361 | const defaultAgent = options._defaultAgent || Agent.globalAgent; | |
| 353 | 362 | if (agent === false) { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,81 @@ | |||
| 1 | + // Flags: --expose-internals | ||
| 2 | + 'use strict'; | ||
| 3 | + | ||
| 4 | + // Regression test: http.request({ highWaterMark }) must propagate the value | ||
| 5 | + // to OutgoingMessage's kHighWaterMark so that _writeRaw() Path B (buffering | ||
| 6 | + // before socket connects) uses the correct threshold. | ||
| 7 | + // | ||
| 8 | + // Without the fix: | ||
| 9 | + // - write() returns the wrong boolean (compares against default 64KB) | ||
| 10 | + // - On Node >= 24.16.0 (post #62936), this causes a deadlock when | ||
| 11 | + // the user awaits 'drain' after write() incorrectly returns false. | ||
| 12 | + // | ||
| 13 | + // Fixes: https://github.com/nodejs/node/issues/64645 | ||
| 14 | + | ||
| 15 | + const common = require('../common'); | ||
| 16 | + const assert = require('assert'); | ||
| 17 | + const http = require('http'); | ||
| 18 | + const { kHighWaterMark } = require('_http_outgoing'); | ||
| 19 | + const { getDefaultHighWaterMark } = require('internal/streams/state'); | ||
| 20 | + | ||
| 21 | + const server = http.createServer(common.mustCall((req, res) => { | ||
| 22 | + req.resume(); | ||
| 23 | + req.on('end', () => res.end('ok')); | ||
| 24 | + }, 3)); | ||
| 25 | + | ||
| 26 | + server.listen(0, common.mustCall(() => { | ||
| 27 | + const port = server.address().port; | ||
| 28 | + let completed = 0; | ||
| 29 | + | ||
| 30 | + function done() { | ||
| 31 | + if (++completed === 3) server.close(); | ||
| 32 | + } | ||
| 33 | + | ||
| 34 | + // Test 1: kHighWaterMark is set to user value on the ClientRequest. | ||
| 35 | + { | ||
| 36 | + const hwm = getDefaultHighWaterMark() * 2; | ||
| 37 | + const req = http.request({ port, method: 'POST', highWaterMark: hwm }); | ||
| 38 | + assert.strictEqual(req[kHighWaterMark], hwm); | ||
| 39 | + req.end(); | ||
| 40 | + req.on('response', (res) => { res.resume(); res.on('end', done); }); | ||
| 41 | + } | ||
| 42 | + | ||
| 43 | + // Test 2: Large HWM — write below threshold returns true before socket connects. | ||
| 44 | + { | ||
| 45 | + const req = http.request({ | ||
| 46 | + port, | ||
| 47 | + method: 'POST', | ||
| 48 | + highWaterMark: 100_000, | ||
| 49 | + }, common.mustCall((res) => { | ||
| 50 | + res.resume(); | ||
| 51 | + res.on('end', done); | ||
| 52 | + })); | ||
| 53 | + | ||
| 54 | + // 64KB write in the same tick — socket not yet connected (Path B). | ||
| 55 | + // With HWM=100KB, write() must return true. | ||
| 56 | + const result = req.write(Buffer.alloc(64 * 1024)); | ||
| 57 | + assert.strictEqual(result, true); | ||
| 58 | + req.end(); | ||
| 59 | + } | ||
| 60 | + | ||
| 61 | + // Test 3: Small HWM — write above threshold returns false, drain fires. | ||
| 62 | + { | ||
| 63 | + const req = http.request({ | ||
| 64 | + port, | ||
| 65 | + method: 'POST', | ||
| 66 | + highWaterMark: 512, | ||
| 67 | + }, common.mustCall((res) => { | ||
| 68 | + res.resume(); | ||
| 69 | + res.on('end', done); | ||
| 70 | + })); | ||
| 71 | + | ||
| 72 | + // 2KB write in the same tick — exceeds HWM of 512 bytes. | ||
| 73 | + const result = req.write(Buffer.alloc(2 * 1024)); | ||
| 74 | + assert.strictEqual(result, false); | ||
| 75 | + | ||
| 76 | + // Drain must fire (no deadlock) so we can complete the request. | ||
| 77 | + req.on('drain', common.mustCall(() => { | ||
| 78 | + req.end(); | ||
| 79 | + })); | ||
| 80 | + } | ||
| 81 | + })); | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments