diff --git a/doc/api/http.md b/doc/api/http.md index 83a401d97ee2eb..d9eaf2cc3332f3 100644 --- a/doc/api/http.md +++ b/doc/api/http.md @@ -2865,6 +2865,14 @@ changes: [`--max-http-header-size`][] for requests received by this server, i.e. the maximum length of request headers in bytes. **Default:** 16384 (16 KB). + * `noDelay` {boolean} If set to `true`, it disables the use of Nagle's algorithm immediately + after a new incoming connection is received. **Default:** `false`. + * `keepAlive` {boolean} If set to `true`, it enables keep-alive functionality on the socket + immediately after a new incoming connection is received, similarly on what is done in + [`socket.setKeepAlive([enable][, initialDelay])`][`socket.setKeepAlive(enable, initialDelay)`]. + **Default:** `false`. + * `keepAliveInitialDelay` {number} If set to a positive number, it sets the initial delay before + the first keepalive probe is sent on an idle socket.**Default:** `0`. * `requestListener` {Function} @@ -3108,6 +3116,8 @@ changes: * `callback` {Function} * Returns: {http.ClientRequest} +`options` in [`socket.connect()`][] are also supported. + Node.js maintains several connections per server to make HTTP requests. This function allows one to transparently issue requests. diff --git a/doc/api/net.md b/doc/api/net.md index f8bcb8dfc9db2e..8f1a13570cb8a3 100644 --- a/doc/api/net.md +++ b/doc/api/net.md @@ -850,6 +850,14 @@ For TCP connections, available `options` are: `0` indicates that both IPv4 and IPv6 addresses are allowed. **Default:** `0`. * `hints` {number} Optional [`dns.lookup()` hints][]. * `lookup` {Function} Custom lookup function. **Default:** [`dns.lookup()`][]. +* `noDelay` {boolean} If set to `true`, it disables the use of Nagle's algorithm immediately + after the socket is established. **Default:** `false`. +* `keepAlive` {boolean} If set to `true`, it enables keep-alive functionality on the socket + immediately after the connection is established, similarly on what is done in + [`socket.setKeepAlive([enable][, initialDelay])`][`socket.setKeepAlive(enable, initialDelay)`]. + **Default:** `false`. +* `keepAliveInitialDelay` {number} If set to a positive number, it sets the initial delay before + the first keepalive probe is sent on an idle socket.**Default:** `0`. For [IPC][] connections, available `options` are: @@ -1405,6 +1413,15 @@ added: v0.5.0 **Default:** `false`. * `pauseOnConnect` {boolean} Indicates whether the socket should be paused on incoming connections. **Default:** `false`. + * `noDelay` {boolean} If set to `true`, it disables the use of Nagle's algorithm immediately + after a new incoming connection is received. **Default:** `false`. + * `keepAlive` {boolean} If set to `true`, it enables keep-alive functionality on the socket + immediately after a new incoming connection is received, similarly on what is done in + [`socket.setKeepAlive([enable][, initialDelay])`][`socket.setKeepAlive(enable, initialDelay)`]. + **Default:** `false`. + * `keepAliveInitialDelay` {number} If set to a positive number, it sets the initial delay before + the first keepalive probe is sent on an idle socket.**Default:** `0`. + * `connectionListener` {Function} Automatically set as a listener for the [`'connection'`][] event. * Returns: {net.Server} @@ -1572,6 +1589,7 @@ net.isIPv6('fhqwhgads'); // returns false [`socket.pause()`]: #socketpause [`socket.resume()`]: #socketresume [`socket.setEncoding()`]: #socketsetencodingencoding +[`socket.setKeepAlive(enable, initialDelay)`]: #socketsetkeepaliveenable-initialdelay [`socket.setTimeout()`]: #socketsettimeouttimeout-callback [`socket.setTimeout(timeout)`]: #socketsettimeouttimeout-callback [`writable.destroy()`]: stream.md#writabledestroyerror diff --git a/lib/_http_server.js b/lib/_http_server.js index 0d06919ea017a4..d7936d1fb233cc 100644 --- a/lib/_http_server.js +++ b/lib/_http_server.js @@ -378,7 +378,12 @@ function Server(options, requestListener) { } storeHTTPOptions.call(this, options); - net.Server.call(this, { allowHalfOpen: true }); + net.Server.call(this, { + allowHalfOpen: true, + noDelay: options.noDelay, + keepAlive: options.keepAlive, + keepAliveInitialDelay: options.keepAliveInitialDelay + }); if (requestListener) { this.on('request', requestListener); diff --git a/lib/net.js b/lib/net.js index 3bbe96f1e04af0..ee44e5814880a2 100644 --- a/lib/net.js +++ b/lib/net.js @@ -279,6 +279,8 @@ function initSocketHandle(self) { const kBytesRead = Symbol('kBytesRead'); const kBytesWritten = Symbol('kBytesWritten'); const kSetNoDelay = Symbol('kSetNoDelay'); +const kSetKeepAlive = Symbol('kSetKeepAlive'); +const kSetKeepAliveInitialDelay = Symbol('kSetKeepAliveInitialDelay'); function Socket(options) { if (!(this instanceof Socket)) return new Socket(options); @@ -297,6 +299,9 @@ function Socket(options) { 'is not supported' ); } + if (typeof options?.keepAliveInitialDelay !== 'undefined') { + validateNumber(options?.keepAliveInitialDelay, 'options.keepAliveInitialDelay'); + } this.connecting = false; // Problem with this is that users can supply their own handle, that may not @@ -307,7 +312,9 @@ function Socket(options) { this[kHandle] = null; this._parent = null; this._host = null; - this[kSetNoDelay] = false; + this[kSetNoDelay] = Boolean(options.noDelay); + this[kSetKeepAlive] = Boolean(options.keepAlive); + this[kSetKeepAliveInitialDelay] = ~~((options.keepAliveInitialDelay < 0 ? 0 : options.keepAliveInitialDelay) / 1000) this[kLastWriteQueueSize] = 0; this[kTimeout] = null; this[kBuffer] = null; @@ -520,14 +527,18 @@ Socket.prototype.setNoDelay = function(enable) { }; -Socket.prototype.setKeepAlive = function(setting, msecs) { +Socket.prototype.setKeepAlive = function(enable, initialDelayMsecs) { if (!this._handle) { - this.once('connect', () => this.setKeepAlive(setting, msecs)); + this.once('connect', () => this.setKeepAlive(enable, initialDelayMsecs)); return this; } - if (this._handle.setKeepAlive) - this._handle.setKeepAlive(setting, ~~(msecs / 1000)); + if (this._handle.setKeepAlive && enable !== this[kSetKeepAlive]) { + const initialDelay = ~~(initialDelayMsecs / 1000); + this[kSetKeepAlive] = enable; + this[kSetKeepAliveInitialDelay] = initialDelay; + this._handle.setKeepAlive(enable, initialDelay); + } return this; }; @@ -1140,6 +1151,14 @@ function afterConnect(status, handle, req, readable, writable) { } self._unrefTimer(); + if(self[kSetNoDelay]) { + self._handle.setNoDelay(true); + } + + if(self[kSetKeepAlive]) { + self._handle.setKeepAlive(true, self[kSetKeepAliveInitialDelay]); + } + self.emit('connect'); self.emit('ready'); @@ -1203,6 +1222,9 @@ function Server(options, connectionListener) { } else { throw new ERR_INVALID_ARG_TYPE('options', 'Object', options); } + if (typeof options.keepAliveInitialDelay !== 'undefined') { + validateNumber(options.keepAliveInitialDelay, 'options.keepAliveInitialDelay'); + } this._connections = 0; @@ -1214,6 +1236,9 @@ function Server(options, connectionListener) { this.allowHalfOpen = options.allowHalfOpen || false; this.pauseOnConnect = !!options.pauseOnConnect; + this.noDelay = Boolean(options.noDelay); + this.keepAlive = Boolean(options.keepAlive); + this.keepAliveInitialDelay = ~~((options.keepAliveInitialDelay < 0 ? 0 : options.keepAliveInitialDelay) / 1000) } ObjectSetPrototypeOf(Server.prototype, EventEmitter.prototype); ObjectSetPrototypeOf(Server, EventEmitter); @@ -1565,6 +1590,14 @@ function onconnection(err, clientHandle) { writable: true }); + if(self.noDelay) { + handle.setNoDelay(true); + } + + if(self.keepAlive) { + handle.setKeepAlive(true, handle.keepAliveInitialDelay); + } + self._connections++; socket.server = self; socket._server = self;