Skip to content

Commit f533750

Browse files
committed
http: Fix 503 on max reached
1 parent 3f37e70 commit f533750

File tree

4 files changed

+96
-7
lines changed

4 files changed

+96
-7
lines changed

lib/_http_outgoing.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ function OutgoingMessage() {
113113
this._last = false;
114114
this.chunkedEncoding = false;
115115
this.shouldKeepAlive = true;
116+
this.maxRequestsOnConnectionReached = false;
116117
this._defaultKeepAlive = true;
117118
this.useChunkedEncodingByDefault = true;
118119
this.sendDate = false;
@@ -447,7 +448,10 @@ function _storeHeader(firstLine, headers) {
447448
} else if (!state.connection) {
448449
const shouldSendKeepAlive = this.shouldKeepAlive &&
449450
(state.contLen || this.useChunkedEncodingByDefault || this.agent);
450-
if (shouldSendKeepAlive) {
451+
452+
if (shouldSendKeepAlive && this.maxRequestsOnConnectionReached) {
453+
header += 'Connection: close' + CRLF;
454+
} else if (shouldSendKeepAlive) {
451455
header += 'Connection: keep-alive' + CRLF;
452456

453457
if (this._defaultKeepAlive) {

lib/_http_server.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -911,13 +911,13 @@ function parserOnIncoming(server, socket, state, req, keepAlive) {
911911

912912
if (req.httpVersionMajor === 1 && req.httpVersionMinor === 1) {
913913
if (typeof server.maxRequestsPerSocket === 'number') {
914-
state.requestsCount++
915-
res.shouldKeepAlive = server.maxRequestsPerSocket > state.requestsCount
914+
state.requestsCount++;
915+
res.maxRequestsOnConnectionReached = server.maxRequestsPerSocket <= state.requestsCount
916916
}
917917

918918
if (typeof server.maxRequestsPerSocket === 'number'
919919
&& (server.maxRequestsPerSocket < state.requestsCount)) {
920-
handled = true
920+
handled = true;
921921

922922
res.writeHead(503);
923923
res.end();

test/parallel/test-http-keep-alive-max-requests.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ const net = require('net');
44
const http = require('http');
55
const assert = require('assert');
66
const common = require('../common');
7-
const { mustCall } = require('../common');
87

98
const bodySent = 'This is my request';
109

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

82-
socket.on('end', mustCall(() => {
81+
socket.on('end', common.mustCall(() => {
8382
server.close();
8483
}));
8584

8685
socket.on('ready', common.mustCall(() => {
87-
// Do two of 3 requests and ensure they still alive
86+
// Do 2 of 3 allowed requests and ensure they still alive
8887
initialRequests(socket, 2, common.mustCall(() => {
8988
anotherSocket.connect({ port: server.address().port });
9089
}))
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
'use strict';
2+
3+
const net = require('net');
4+
const http = require('http');
5+
const assert = require('assert');
6+
const common = require('../common');
7+
8+
const bodySent = 'This is my request';
9+
10+
function assertResponse(headers, body, expectClosed) {
11+
if (expectClosed) {
12+
assert.match(headers, /Connection: close\r\n/m);
13+
assert(headers.search(/Keep-Alive: timeout=5, max=3\r\n/m) === -1);
14+
assert.match(body, /Hello World!/m);
15+
} else {
16+
assert.match(headers, /Connection: keep-alive\r\n/m);
17+
assert.match(headers, /Keep-Alive: timeout=5, max=3\r\n/m);
18+
assert.match(body, /Hello World!/m);
19+
}
20+
}
21+
22+
function writeRequest(socket) {
23+
socket.write('POST / HTTP/1.1\r\n');
24+
socket.write('Connection: keep-alive\r\n');
25+
socket.write('Content-Type: text/plain\r\n');
26+
socket.write(`Content-Length: ${bodySent.length}\r\n\r\n`);
27+
socket.write(`${bodySent}\r\n`);
28+
socket.write('\r\n\r\n')
29+
}
30+
31+
const server = http.createServer(function (req, res) {
32+
let body = ''
33+
req.on('data', (data) => {
34+
body += data
35+
});
36+
37+
req.on('end', () => {
38+
if (req.method === 'POST') {
39+
assert(bodySent === body)
40+
}
41+
42+
res.writeHead(200, {'Content-Type': 'text/plain'});
43+
res.write('Hello World!');
44+
res.end();
45+
})
46+
})
47+
48+
server.maxRequestsPerSocket = 3;
49+
50+
server.listen(0, common.mustCall((res) => {
51+
const socket = new net.Socket();
52+
53+
socket.on('end', common.mustCall(() => {
54+
server.close();
55+
}));
56+
57+
socket.on('ready', common.mustCall(() => {
58+
writeRequest(socket);
59+
writeRequest(socket);
60+
writeRequest(socket);
61+
writeRequest(socket);
62+
}));
63+
64+
let buffer = ''
65+
66+
socket.on('data', (data) => {
67+
buffer += data;
68+
69+
const responseParts = buffer.trim().split('\r\n\r\n');
70+
71+
if (responseParts.length === 8) {
72+
assertResponse(responseParts[0], responseParts[1]);
73+
assertResponse(responseParts[2], responseParts[3]);
74+
assertResponse(responseParts[4], responseParts[5], true);
75+
76+
assert.match(responseParts[6], /HTTP\/1.1 503 Service Unavailable/m)
77+
assert.match(responseParts[6], /Connection: close\r\n/m);
78+
assert(responseParts[6].search(/Keep-Alive: timeout=5, max=3\r\n/m) === -1);
79+
assert(responseParts[7].search(/Hello World!/m) === -1);
80+
81+
socket.end();
82+
}
83+
})
84+
85+
socket.connect({ port: server.address().port });
86+
}));

0 commit comments

Comments
 (0)