Skip to content

Commit

Permalink
http: use 0 as default for requests limit
Browse files Browse the repository at this point in the history
PR-URL: #40192
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Khaidi Chu <i@2333.moe>
  • Loading branch information
fatal10110 authored and mcollina committed Sep 27, 2021
1 parent 0ee0ed1 commit 44b173e
Show file tree
Hide file tree
Showing 4 changed files with 161 additions and 5 deletions.
4 changes: 2 additions & 2 deletions doc/api/http.md
Original file line number Diff line number Diff line change
Expand Up @@ -1357,12 +1357,12 @@ explicitly.
added: v16.10.0
-->

* {number} Requests per socket. **Default:** null (no limit)
* {number} Requests per socket. **Default:** 0 (no limit)

The maximum number of requests socket can handle
before closing keep alive connection.

A value of `null` will disable the limit.
A value of `0` will disable the limit.

When the limit is reached it will set the `Connection` header value to `close`,
but will not actually close the connection, subsequent requests sent
Expand Down
11 changes: 8 additions & 3 deletions lib/_http_server.js
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,7 @@ function Server(options, requestListener) {
this.timeout = 0;
this.keepAliveTimeout = 5000;
this.maxHeadersCount = null;
this.maxRequestsPerSocket = null;
this.maxRequestsPerSocket = 0;
this.headersTimeout = 60 * 1000; // 60 seconds
this.requestTimeout = 0;
}
Expand Down Expand Up @@ -908,13 +908,18 @@ function parserOnIncoming(server, socket, state, req, keepAlive) {
let handled = false;

if (req.httpVersionMajor === 1 && req.httpVersionMinor === 1) {
if (typeof server.maxRequestsPerSocket === 'number') {
const isRequestsLimitSet = (
typeof server.maxRequestsPerSocket === 'number' &&
server.maxRequestsPerSocket > 0
);

if (isRequestsLimitSet) {
state.requestsCount++;
res.maxRequestsOnConnectionReached = (
server.maxRequestsPerSocket <= state.requestsCount);
}

if (typeof server.maxRequestsPerSocket === 'number' &&
if (isRequestsLimitSet &&
(server.maxRequestsPerSocket < state.requestsCount)) {
handled = true;

Expand Down
76 changes: 76 additions & 0 deletions test/parallel/test-http-server-keep-alive-defaults.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
'use strict';

const common = require('../common');
const net = require('net');
const http = require('http');
const assert = require('assert');

const bodySent = 'This is my request';

function assertResponse(headers, body, expectClosed) {
assert.match(headers, /Connection: keep-alive\r\n/m);
assert.match(headers, /Keep-Alive: timeout=5\r\n/m);
assert.match(body, /Hello World!/m);
}

function writeRequest(socket) {
socket.write('POST / HTTP/1.1\r\n');
socket.write('Connection: keep-alive\r\n');
socket.write('Content-Type: text/plain\r\n');
socket.write(`Content-Length: ${bodySent.length}\r\n\r\n`);
socket.write(`${bodySent}\r\n`);
socket.write('\r\n\r\n');
}

const server = http.createServer((req, res) => {
let body = '';
req.on('data', (data) => {
body += data;
});

req.on('end', () => {
if (req.method === 'POST') {
assert.strictEqual(bodySent, body);
}

res.writeHead(200, { 'Content-Type': 'text/plain' });
res.write('Hello World!');
res.end();
});
});

server.listen(0, common.mustCall((res) => {
assert.strictEqual(server.maxRequestsPerSocket, 0);

const socket = new net.Socket();

socket.on('end', common.mustCall(() => {
server.close();
}));

socket.on('ready', common.mustCall(() => {
writeRequest(socket);
writeRequest(socket);
writeRequest(socket);
writeRequest(socket);
}));

let buffer = '';

socket.on('data', (data) => {
buffer += data;

const responseParts = buffer.trim().split('\r\n\r\n');

if (responseParts.length === 8) {
assertResponse(responseParts[0], responseParts[1]);
assertResponse(responseParts[2], responseParts[3]);
assertResponse(responseParts[4], responseParts[5]);
assertResponse(responseParts[6], responseParts[7]);

socket.end();
}
});

socket.connect({ port: server.address().port });
}));
75 changes: 75 additions & 0 deletions test/parallel/test-http-server-keep-alive-max-requests-null.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
'use strict';

const common = require('../common');
const net = require('net');
const http = require('http');
const assert = require('assert');

const bodySent = 'This is my request';

function assertResponse(headers, body, expectClosed) {
assert.match(headers, /Connection: keep-alive\r\n/m);
assert.match(headers, /Keep-Alive: timeout=5\r\n/m);
assert.match(body, /Hello World!/m);
}

function writeRequest(socket) {
socket.write('POST / HTTP/1.1\r\n');
socket.write('Connection: keep-alive\r\n');
socket.write('Content-Type: text/plain\r\n');
socket.write(`Content-Length: ${bodySent.length}\r\n\r\n`);
socket.write(`${bodySent}\r\n`);
socket.write('\r\n\r\n');
}

const server = http.createServer((req, res) => {
let body = '';
req.on('data', (data) => {
body += data;
});

req.on('end', () => {
if (req.method === 'POST') {
assert.strictEqual(bodySent, body);
}

res.writeHead(200, { 'Content-Type': 'text/plain' });
res.write('Hello World!');
res.end();
});
});

server.maxRequestsPerSocket = null;
server.listen(0, common.mustCall((res) => {
const socket = new net.Socket();

socket.on('end', common.mustCall(() => {
server.close();
}));

socket.on('ready', common.mustCall(() => {
writeRequest(socket);
writeRequest(socket);
writeRequest(socket);
writeRequest(socket);
}));

let buffer = '';

socket.on('data', (data) => {
buffer += data;

const responseParts = buffer.trim().split('\r\n\r\n');

if (responseParts.length === 8) {
assertResponse(responseParts[0], responseParts[1]);
assertResponse(responseParts[2], responseParts[3]);
assertResponse(responseParts[4], responseParts[5]);
assertResponse(responseParts[6], responseParts[7]);

socket.end();
}
});

socket.connect({ port: server.address().port });
}));

0 comments on commit 44b173e

Please sign in to comment.