Skip to content

Commit

Permalink
http: Fix 503 on max reached
Browse files Browse the repository at this point in the history
  • Loading branch information
fatal10110 committed Sep 12, 2021
1 parent 3f37e70 commit f533750
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 7 deletions.
6 changes: 5 additions & 1 deletion lib/_http_outgoing.js
Expand Up @@ -113,6 +113,7 @@ function OutgoingMessage() {
this._last = false;
this.chunkedEncoding = false;
this.shouldKeepAlive = true;
this.maxRequestsOnConnectionReached = false;
this._defaultKeepAlive = true;
this.useChunkedEncodingByDefault = true;
this.sendDate = false;
Expand Down Expand Up @@ -447,7 +448,10 @@ function _storeHeader(firstLine, headers) {
} else if (!state.connection) {
const shouldSendKeepAlive = this.shouldKeepAlive &&
(state.contLen || this.useChunkedEncodingByDefault || this.agent);
if (shouldSendKeepAlive) {

if (shouldSendKeepAlive && this.maxRequestsOnConnectionReached) {
header += 'Connection: close' + CRLF;
} else if (shouldSendKeepAlive) {
header += 'Connection: keep-alive' + CRLF;

if (this._defaultKeepAlive) {
Expand Down
6 changes: 3 additions & 3 deletions lib/_http_server.js
Expand Up @@ -911,13 +911,13 @@ function parserOnIncoming(server, socket, state, req, keepAlive) {

if (req.httpVersionMajor === 1 && req.httpVersionMinor === 1) {
if (typeof server.maxRequestsPerSocket === 'number') {
state.requestsCount++
res.shouldKeepAlive = server.maxRequestsPerSocket > state.requestsCount
state.requestsCount++;
res.maxRequestsOnConnectionReached = server.maxRequestsPerSocket <= state.requestsCount
}

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

res.writeHead(503);
res.end();
Expand Down
5 changes: 2 additions & 3 deletions test/parallel/test-http-keep-alive-max-requests.js
Expand Up @@ -4,7 +4,6 @@ const net = require('net');
const http = require('http');
const assert = require('assert');
const common = require('../common');
const { mustCall } = require('../common');

const bodySent = 'This is my request';

Expand Down Expand Up @@ -79,12 +78,12 @@ server.listen(0, common.mustCall((res) => {
const socket = new net.Socket();
const anotherSocket = new net.Socket();

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

socket.on('ready', common.mustCall(() => {
// Do two of 3 requests and ensure they still alive
// Do 2 of 3 allowed requests and ensure they still alive
initialRequests(socket, 2, common.mustCall(() => {
anotherSocket.connect({ port: server.address().port });
}))
Expand Down
86 changes: 86 additions & 0 deletions test/parallel/test-http-keep-alive-pipeline-max-requests.js
@@ -0,0 +1,86 @@
'use strict';

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

const bodySent = 'This is my request';

function assertResponse(headers, body, expectClosed) {
if (expectClosed) {
assert.match(headers, /Connection: close\r\n/m);
assert(headers.search(/Keep-Alive: timeout=5, max=3\r\n/m) === -1);
assert.match(body, /Hello World!/m);
} else {
assert.match(headers, /Connection: keep-alive\r\n/m);
assert.match(headers, /Keep-Alive: timeout=5, max=3\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(function (req, res) {
let body = ''
req.on('data', (data) => {
body += data
});

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

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

server.maxRequestsPerSocket = 3;

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], true);

assert.match(responseParts[6], /HTTP\/1.1 503 Service Unavailable/m)
assert.match(responseParts[6], /Connection: close\r\n/m);
assert(responseParts[6].search(/Keep-Alive: timeout=5, max=3\r\n/m) === -1);
assert(responseParts[7].search(/Hello World!/m) === -1);

socket.end();
}
})

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

0 comments on commit f533750

Please sign in to comment.