diff --git a/lib/_http_outgoing.js b/lib/_http_outgoing.js index c6f68d4329c7da..c256e74260673d 100644 --- a/lib/_http_outgoing.js +++ b/lib/_http_outgoing.js @@ -134,6 +134,7 @@ function OutgoingMessage() { this._header = null; this[kOutHeaders] = null; + this._maxRequestsPerSocket = null; this._keepAliveTimeout = 0; this._onPendingData = nop; @@ -448,9 +449,23 @@ function _storeHeader(firstLine, headers) { (state.contLen || this.useChunkedEncodingByDefault || this.agent); if (shouldSendKeepAlive) { header += 'Connection: keep-alive' + CRLF; - if (this._keepAliveTimeout && this._defaultKeepAlive) { - const timeoutSeconds = MathFloor(this._keepAliveTimeout / 1000); - header += `Keep-Alive: timeout=${timeoutSeconds}${CRLF}`; + + if (this._defaultKeepAlive) { + let keepAliveParameters = ''; + + if (this._keepAliveTimeout) { + const timeoutSeconds = MathFloor(this._keepAliveTimeout / 1000); + keepAliveParameters += `timeout=${timeoutSeconds}`; + } + + if (this._maxRequestsPerSocket) { + if (keepAliveParameters.length > 0) keepAliveParameters += ', '; + keepAliveParameters += `max=${this._maxRequestsPerSocket}`; + } + + if (keepAliveParameters.length > 0) { + header += `Keep-Alive: ${keepAliveParameters}${CRLF}`; + } } } else { this._last = true; diff --git a/lib/_http_server.js b/lib/_http_server.js index 64cd44c066cf8a..54ef34738b17cb 100644 --- a/lib/_http_server.js +++ b/lib/_http_server.js @@ -395,6 +395,7 @@ function Server(options, requestListener) { this.timeout = 0; this.keepAliveTimeout = 5000; this.maxHeadersCount = null; + this.maxRequestsPerSocket = null; this.headersTimeout = 60 * 1000; // 60 seconds this.requestTimeout = 0; } @@ -486,6 +487,7 @@ function connectionListenerInternal(server, socket) { // need to pause TCP socket/HTTP parser, and wait until the data will be // sent to the client. outgoingData: 0, + requestsCount: 0, keepAliveTimeoutSet: false }; state.onData = socketOnData.bind(undefined, @@ -876,6 +878,7 @@ function parserOnIncoming(server, socket, state, req, keepAlive) { const res = new server[kServerResponse](req); res._keepAliveTimeout = server.keepAliveTimeout; + res._maxRequestsPerSocket = server.maxRequestsPerSocket; res._onPendingData = updateOutgoingData.bind(undefined, socket, state); @@ -904,6 +907,16 @@ function parserOnIncoming(server, socket, state, req, keepAlive) { resOnFinish.bind(undefined, req, res, socket, state, server)); + if (req.httpVersionMajor === 1 && req.httpVersionMinor === 1 + && typeof server.maxRequestsPerSocket === 'number' + && server.maxRequestsPerSocket > ++state.requestsCount) { + res.shouldKeepAlive = false; + res.writeHead(503, { + 'Connection': 'close' + }); + res.end(); + } + if (req.headers.expect !== undefined && (req.httpVersionMajor === 1 && req.httpVersionMinor === 1)) { if (RegExpPrototypeTest(continueExpression, req.headers.expect)) {