Skip to content

Commit 4fa7739

Browse files
HinataKah0targos
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 <[email protected]> Reviewed-By: Paolo Insogna <[email protected]> Reviewed-By: Debadree Chatterjee <[email protected]>
1 parent 21ff331 commit 4fa7739

File tree

7 files changed

+84
-6
lines changed

7 files changed

+84
-6
lines changed

doc/api/http.md

+8
Original file line numberDiff line numberDiff line change
@@ -3192,6 +3192,9 @@ Found'`.
31923192
<!-- YAML
31933193
added: v0.1.13
31943194
changes:
3195+
- version: REPLACEME
3196+
pr-url: https://github.com/nodejs/node/pull/47405
3197+
description: The `highWaterMark` option is supported now.
31953198
- version: v18.0.0
31963199
pr-url: https://github.com/nodejs/node/pull/41263
31973200
description: The `requestTimeout`, `headersTimeout`, `keepAliveTimeout`, and
@@ -3229,6 +3232,10 @@ changes:
32293232
the complete HTTP headers from the client.
32303233
See [`server.headersTimeout`][] for more information.
32313234
**Default:** `60000`.
3235+
* `highWaterMark` {number} Optionally overrides all `socket`s'
3236+
`readableHighWaterMark` and `writableHighWaterMark`. This affects
3237+
`highWaterMark` property of both `IncomingMessage` and `ServerResponse`.
3238+
**Default:** See [`stream.getDefaultHighWaterMark()`][].
32323239
* `insecureHTTPParser` {boolean} Use an insecure HTTP parser that accepts
32333240
invalid HTTP headers when `true`. Using the insecure parser should be
32343241
avoided. See [`--insecure-http-parser`][] for more information.
@@ -3898,6 +3905,7 @@ Set the maximum number of idle HTTP parsers.
38983905
[`socket.setNoDelay()`]: net.md#socketsetnodelaynodelay
38993906
[`socket.setTimeout()`]: net.md#socketsettimeouttimeout-callback
39003907
[`socket.unref()`]: net.md#socketunref
3908+
[`stream.getDefaultHighWaterMark()`]: stream.md#streamgetdefaulthighwatermarkobjectmode
39013909
[`url.parse()`]: url.md#urlparseurlstring-parsequerystring-slashesdenotehost
39023910
[`writable.cork()`]: stream.md#writablecork
39033911
[`writable.destroy()`]: stream.md#writabledestroyerror

doc/api/net.md

+7
Original file line numberDiff line numberDiff line change
@@ -1539,6 +1539,9 @@ then returns the `net.Socket` that starts the connection.
15391539
<!-- YAML
15401540
added: v0.5.0
15411541
changes:
1542+
- version: REPLACEME
1543+
pr-url: https://github.com/nodejs/node/pull/47405
1544+
description: The `highWaterMark` option is supported now.
15421545
- version:
15431546
- v17.7.0
15441547
- v16.15.0
@@ -1551,6 +1554,9 @@ changes:
15511554
* `allowHalfOpen` {boolean} If set to `false`, then the socket will
15521555
automatically end the writable side when the readable side ends.
15531556
**Default:** `false`.
1557+
* `highWaterMark` {number} Optionally overrides all [`net.Socket`][]s'
1558+
`readableHighWaterMark` and `writableHighWaterMark`.
1559+
**Default:** See [`stream.getDefaultHighWaterMark()`][].
15541560
* `pauseOnConnect` {boolean} Indicates whether the socket should be
15551561
paused on incoming connections. **Default:** `false`.
15561562
* `noDelay` {boolean} If set to `true`, it disables the use of Nagle's algorithm immediately
@@ -1780,6 +1786,7 @@ net.isIPv6('fhqwhgads'); // returns false
17801786
[`socket.setKeepAlive(enable, initialDelay)`]: #socketsetkeepaliveenable-initialdelay
17811787
[`socket.setTimeout()`]: #socketsettimeouttimeout-callback
17821788
[`socket.setTimeout(timeout)`]: #socketsettimeouttimeout-callback
1789+
[`stream.getDefaultHighWaterMark()`]: stream.md#streamgetdefaulthighwatermarkobjectmode
17831790
[`writable.destroy()`]: stream.md#writabledestroyerror
17841791
[`writable.destroyed`]: stream.md#writabledestroyed
17851792
[`writable.end()`]: stream.md#writableendchunk-encoding-callback

lib/_http_outgoing.js

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

104-
function OutgoingMessage() {
104+
function OutgoingMessage(options) {
105105
Stream.call(this);
106106

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

151151
this[kErrored] = null;
152-
this[kHighWaterMark] = getDefaultHighWaterMark();
152+
this[kHighWaterMark] = options?.highWaterMark ?? getDefaultHighWaterMark();
153153
}
154154
ObjectSetPrototypeOf(OutgoingMessage.prototype, Stream.prototype);
155155
ObjectSetPrototypeOf(OutgoingMessage, Stream);
@@ -1171,6 +1171,7 @@ function(err, event) {
11711171
};
11721172

11731173
module.exports = {
1174+
kHighWaterMark,
11741175
kUniqueHeaders,
11751176
parseUniqueHeadersOption,
11761177
validateHeaderName,

lib/_http_server.js

+5-4
Original file line numberDiff line numberDiff line change
@@ -188,8 +188,8 @@ class HTTPServerAsyncResource {
188188
}
189189
}
190190

191-
function ServerResponse(req) {
192-
OutgoingMessage.call(this);
191+
function ServerResponse(req, options) {
192+
OutgoingMessage.call(this, options);
193193

194194
if (req.method === 'HEAD') this._hasBody = false;
195195

@@ -513,7 +513,8 @@ function Server(options, requestListener) {
513513
this,
514514
{ allowHalfOpen: true, noDelay: options.noDelay ?? true,
515515
keepAlive: options.keepAlive,
516-
keepAliveInitialDelay: options.keepAliveInitialDelay });
516+
keepAliveInitialDelay: options.keepAliveInitialDelay,
517+
highWaterMark: options.highWaterMark });
517518

518519
if (requestListener) {
519520
this.on('request', requestListener);
@@ -1019,7 +1020,7 @@ function parserOnIncoming(server, socket, state, req, keepAlive) {
10191020
}
10201021
}
10211022

1022-
const res = new server[kServerResponse](req);
1023+
const res = new server[kServerResponse](req, { highWaterMark: socket.writableHighWaterMark });
10231024
res._keepAliveTimeout = server.keepAliveTimeout;
10241025
res._maxRequestsPerSocket = server.maxRequestsPerSocket;
10251026
res._onPendingData = updateOutgoingData.bind(undefined,

lib/http.js

+1
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ let maxHeaderSize;
5454
* maxHeaderSize?: number;
5555
* requireHostHeader?: boolean;
5656
* joinDuplicateHeaders?: boolean;
57+
* highWaterMark?: number;
5758
* }} [opts]
5859
* @param {Function} [requestListener]
5960
* @returns {Server}

lib/net.js

+13
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ const {
154154
startPerf,
155155
stopPerf,
156156
} = require('internal/perf/observe');
157+
const { getDefaultHighWaterMark } = require('internal/streams/state');
157158

158159
function getFlags(ipv6Only) {
159160
return ipv6Only === true ? TCPConstants.UV_TCP_IPV6ONLY : 0;
@@ -1682,6 +1683,15 @@ function Server(options, connectionListener) {
16821683
options.keepAliveInitialDelay = 0;
16831684
}
16841685
}
1686+
if (typeof options.highWaterMark !== 'undefined') {
1687+
validateNumber(
1688+
options.highWaterMark, 'options.highWaterMark',
1689+
);
1690+
1691+
if (options.highWaterMark < 0) {
1692+
options.highWaterMark = getDefaultHighWaterMark();
1693+
}
1694+
}
16851695

16861696
this._connections = 0;
16871697

@@ -1696,6 +1706,7 @@ function Server(options, connectionListener) {
16961706
this.noDelay = Boolean(options.noDelay);
16971707
this.keepAlive = Boolean(options.keepAlive);
16981708
this.keepAliveInitialDelay = ~~(options.keepAliveInitialDelay / 1000);
1709+
this.highWaterMark = options.highWaterMark ?? getDefaultHighWaterMark();
16991710
}
17001711
ObjectSetPrototypeOf(Server.prototype, EventEmitter.prototype);
17011712
ObjectSetPrototypeOf(Server, EventEmitter);
@@ -2077,6 +2088,8 @@ function onconnection(err, clientHandle) {
20772088
pauseOnCreate: self.pauseOnConnect,
20782089
readable: true,
20792090
writable: true,
2091+
readableHighWaterMark: self.highWaterMark,
2092+
writableHighWaterMark: self.highWaterMark,
20802093
});
20812094

20822095
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)