Skip to content

Commit 7cef6aa

Browse files
HinataKah0MoLow
authored andcommitted
http: add highWaterMark opt in http.createServer
Add highWaterMark option when creating a new HTTP server. This option will override the default (readable|writable) highWaterMark values on sockets created. Fixes: #46606 PR-URL: #47405 Reviewed-By: Robert Nagy <ronagy@icloud.com> Reviewed-By: Paolo Insogna <paolo@cowtech.it> Reviewed-By: Debadree Chatterjee <debadree333@gmail.com>
1 parent 0ea6371 commit 7cef6aa

7 files changed

+84
-6
lines changed

doc/api/http.md

+8
Original file line numberDiff line numberDiff line change
@@ -3167,6 +3167,9 @@ Found'`.
31673167
<!-- YAML
31683168
added: v0.1.13
31693169
changes:
3170+
- version: REPLACEME
3171+
pr-url: https://github.com/nodejs/node/pull/47405
3172+
description: The `highWaterMark` option is supported now.
31703173
- version: v18.0.0
31713174
pr-url: https://github.com/nodejs/node/pull/41263
31723175
description: The `requestTimeout`, `headersTimeout`, `keepAliveTimeout`, and
@@ -3202,6 +3205,10 @@ changes:
32023205
the complete HTTP headers from the client.
32033206
See [`server.headersTimeout`][] for more information.
32043207
**Default:** `60000`.
3208+
* `highWaterMark` {number} Optionally overrides all `socket`s'
3209+
`readableHighWaterMark` and `writableHighWaterMark`. This affects
3210+
`highWaterMark` property of both `IncomingMessage` and `ServerResponse`.
3211+
**Default:** See [`stream.getDefaultHighWaterMark()`][].
32053212
* `insecureHTTPParser` {boolean} Use an insecure HTTP parser that accepts
32063213
invalid HTTP headers when `true`. Using the insecure parser should be
32073214
avoided. See [`--insecure-http-parser`][] for more information.
@@ -3845,6 +3852,7 @@ Set the maximum number of idle HTTP parsers.
38453852
[`socket.setNoDelay()`]: net.md#socketsetnodelaynodelay
38463853
[`socket.setTimeout()`]: net.md#socketsettimeouttimeout-callback
38473854
[`socket.unref()`]: net.md#socketunref
3855+
[`stream.getDefaultHighWaterMark()`]: stream.md#streamgetdefaulthighwatermarkobjectmode
38483856
[`url.parse()`]: url.md#urlparseurlstring-parsequerystring-slashesdenotehost
38493857
[`writable.cork()`]: stream.md#writablecork
38503858
[`writable.destroy()`]: stream.md#writabledestroyerror

doc/api/net.md

+7
Original file line numberDiff line numberDiff line change
@@ -1502,6 +1502,9 @@ then returns the `net.Socket` that starts the connection.
15021502
<!-- YAML
15031503
added: v0.5.0
15041504
changes:
1505+
- version: REPLACEME
1506+
pr-url: https://github.com/nodejs/node/pull/47405
1507+
description: The `highWaterMark` option is supported now.
15051508
- version:
15061509
- v17.7.0
15071510
- v16.15.0
@@ -1514,6 +1517,9 @@ changes:
15141517
* `allowHalfOpen` {boolean} If set to `false`, then the socket will
15151518
automatically end the writable side when the readable side ends.
15161519
**Default:** `false`.
1520+
* `highWaterMark` {number} Optionally overrides all [`net.Socket`][]s'
1521+
`readableHighWaterMark` and `writableHighWaterMark`.
1522+
**Default:** See [`stream.getDefaultHighWaterMark()`][].
15171523
* `pauseOnConnect` {boolean} Indicates whether the socket should be
15181524
paused on incoming connections. **Default:** `false`.
15191525
* `noDelay` {boolean} If set to `true`, it disables the use of Nagle's algorithm immediately
@@ -1697,6 +1703,7 @@ net.isIPv6('fhqwhgads'); // returns false
16971703
[`socket.setKeepAlive(enable, initialDelay)`]: #socketsetkeepaliveenable-initialdelay
16981704
[`socket.setTimeout()`]: #socketsettimeouttimeout-callback
16991705
[`socket.setTimeout(timeout)`]: #socketsettimeouttimeout-callback
1706+
[`stream.getDefaultHighWaterMark()`]: stream.md#streamgetdefaulthighwatermarkobjectmode
17001707
[`writable.destroy()`]: stream.md#writabledestroyerror
17011708
[`writable.destroyed`]: stream.md#writabledestroyed
17021709
[`writable.end()`]: stream.md#writableendchunk-encoding-callback

lib/_http_outgoing.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ function isContentDispositionField(s) {
102102
return s.length === 19 && StringPrototypeToLowerCase(s) === 'content-disposition';
103103
}
104104

105-
function OutgoingMessage() {
105+
function OutgoingMessage(options) {
106106
Stream.call(this);
107107

108108
// Queue that holds all currently pending data, until the response will be
@@ -150,7 +150,7 @@ function OutgoingMessage() {
150150
this._onPendingData = nop;
151151

152152
this[kErrored] = null;
153-
this[kHighWaterMark] = getDefaultHighWaterMark();
153+
this[kHighWaterMark] = options?.highWaterMark ?? getDefaultHighWaterMark();
154154
}
155155
ObjectSetPrototypeOf(OutgoingMessage.prototype, Stream.prototype);
156156
ObjectSetPrototypeOf(OutgoingMessage, Stream);
@@ -1167,6 +1167,7 @@ function(err, event) {
11671167
};
11681168

11691169
module.exports = {
1170+
kHighWaterMark,
11701171
kUniqueHeaders,
11711172
parseUniqueHeadersOption,
11721173
validateHeaderName,

lib/_http_server.js

+5-4
Original file line numberDiff line numberDiff line change
@@ -190,8 +190,8 @@ class HTTPServerAsyncResource {
190190
}
191191
}
192192

193-
function ServerResponse(req) {
194-
OutgoingMessage.call(this);
193+
function ServerResponse(req, options) {
194+
OutgoingMessage.call(this, options);
195195

196196
if (req.method === 'HEAD') this._hasBody = false;
197197

@@ -509,7 +509,8 @@ function Server(options, requestListener) {
509509
this,
510510
{ allowHalfOpen: true, noDelay: options.noDelay,
511511
keepAlive: options.keepAlive,
512-
keepAliveInitialDelay: options.keepAliveInitialDelay });
512+
keepAliveInitialDelay: options.keepAliveInitialDelay,
513+
highWaterMark: options.highWaterMark });
513514

514515
if (requestListener) {
515516
this.on('request', requestListener);
@@ -1014,7 +1015,7 @@ function parserOnIncoming(server, socket, state, req, keepAlive) {
10141015
}
10151016
}
10161017

1017-
const res = new server[kServerResponse](req);
1018+
const res = new server[kServerResponse](req, { highWaterMark: socket.writableHighWaterMark });
10181019
res._keepAliveTimeout = server.keepAliveTimeout;
10191020
res._maxRequestsPerSocket = server.maxRequestsPerSocket;
10201021
res._onPendingData = updateOutgoingData.bind(undefined,

lib/http.js

+1
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ let maxHeaderSize;
5353
* insecureHTTPParser?: boolean;
5454
* maxHeaderSize?: number;
5555
* joinDuplicateHeaders?: boolean;
56+
* highWaterMark?: number;
5657
* }} [opts]
5758
* @param {Function} [requestListener]
5859
* @returns {Server}

lib/net.js

+13
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ const {
164164
startPerf,
165165
stopPerf,
166166
} = require('internal/perf/observe');
167+
const { getDefaultHighWaterMark } = require('internal/streams/state');
167168

168169
function getFlags(ipv6Only) {
169170
return ipv6Only === true ? TCPConstants.UV_TCP_IPV6ONLY : 0;
@@ -1610,6 +1611,15 @@ function Server(options, connectionListener) {
16101611
options.keepAliveInitialDelay = 0;
16111612
}
16121613
}
1614+
if (typeof options.highWaterMark !== 'undefined') {
1615+
validateNumber(
1616+
options.highWaterMark, 'options.highWaterMark',
1617+
);
1618+
1619+
if (options.highWaterMark < 0) {
1620+
options.highWaterMark = getDefaultHighWaterMark();
1621+
}
1622+
}
16131623

16141624
this._connections = 0;
16151625

@@ -1624,6 +1634,7 @@ function Server(options, connectionListener) {
16241634
this.noDelay = Boolean(options.noDelay);
16251635
this.keepAlive = Boolean(options.keepAlive);
16261636
this.keepAliveInitialDelay = ~~(options.keepAliveInitialDelay / 1000);
1637+
this.highWaterMark = options.highWaterMark ?? getDefaultHighWaterMark();
16271638
}
16281639
ObjectSetPrototypeOf(Server.prototype, EventEmitter.prototype);
16291640
ObjectSetPrototypeOf(Server, EventEmitter);
@@ -2005,6 +2016,8 @@ function onconnection(err, clientHandle) {
20052016
pauseOnCreate: self.pauseOnConnect,
20062017
readable: true,
20072018
writable: true,
2019+
readableHighWaterMark: self.highWaterMark,
2020+
writableHighWaterMark: self.highWaterMark,
20082021
});
20092022

20102023
if (self.noDelay && clientHandle.setNoDelay) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// Flags: --expose-internals
2+
'use strict';
3+
const common = require('../common');
4+
const assert = require('assert');
5+
const http = require('http');
6+
const { kHighWaterMark } = require('_http_outgoing');
7+
8+
const { getDefaultHighWaterMark } = require('internal/streams/state');
9+
10+
function listen(server) {
11+
server.listen(0, common.mustCall(() => {
12+
http.get({
13+
port: server.address().port,
14+
}, (res) => {
15+
assert.strictEqual(res.statusCode, 200);
16+
res.resume().on('end', common.mustCall(() => {
17+
server.close();
18+
}));
19+
});
20+
}));
21+
}
22+
23+
{
24+
const server = http.createServer({
25+
highWaterMark: getDefaultHighWaterMark() * 2,
26+
}, common.mustCall((req, res) => {
27+
assert.strictEqual(req._readableState.highWaterMark, getDefaultHighWaterMark() * 2);
28+
assert.strictEqual(res[kHighWaterMark], getDefaultHighWaterMark() * 2);
29+
res.statusCode = 200;
30+
res.end();
31+
}));
32+
33+
listen(server);
34+
}
35+
36+
{
37+
const server = http.createServer(
38+
common.mustCall((req, res) => {
39+
assert.strictEqual(req._readableState.highWaterMark, getDefaultHighWaterMark());
40+
assert.strictEqual(res[kHighWaterMark], getDefaultHighWaterMark());
41+
res.statusCode = 200;
42+
res.end();
43+
})
44+
);
45+
46+
listen(server);
47+
}

0 commit comments

Comments
 (0)