660 lines
20 KiB
Diff
660 lines
20 KiB
Diff
commit b13b4a9ffb6038be1c21c20ece50d5fe367807b3
|
|
Author: Matteo Collina <hello@matteocollina.com>
|
|
Date: Sat Dec 1 16:29:13 2018 +0100
|
|
|
|
http: prevent slowloris with keepalive connections
|
|
|
|
Fixes: https://github.com/nodejs-private/security/issues/214
|
|
PR-URL: https://github.com/nodejs-private/node-private/pull/162
|
|
Reviewed-By: Rod Vagg <rod@vagg.org>
|
|
Reviewed-By: Sam Roberts <vieuxtech@gmail.com>
|
|
Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com>
|
|
|
|
|
|
commit e9ae4aaaad5947075bdb3d1f558281aa1a729b36
|
|
Author: Alexey Orlenko <eaglexrlnk@gmail.com>
|
|
Date: Thu Jun 8 17:20:24 2017 +0300
|
|
|
|
http: fix timeout reset after keep-alive timeout
|
|
|
|
Fix the logic of resetting the socket timeout of keep-alive HTTP
|
|
connections and add two tests:
|
|
|
|
* `test-http-server-keep-alive-timeout-slow-server` is a regression test
|
|
for GH-13391. It ensures that the server-side keep-alive timeout will
|
|
not fire during processing of a request.
|
|
|
|
* `test-http-server-keep-alive-timeout-slow-client-headers` ensures that
|
|
the regular socket timeout is restored as soon as a client starts
|
|
sending a new request, not as soon as the whole message is received,
|
|
so that the keep-alive timeout will not fire while, e.g., the client
|
|
is sending large cookies.
|
|
|
|
commit 06a208d3166493cc5bbc63b5cdbe473dbf4ad0ec
|
|
Author: realwakka <realwakka@gmail.com>
|
|
Date: Sun Jun 4 14:03:11 2017 +0900
|
|
|
|
test: refactor test-http-server-keep-alive-timeout
|
|
|
|
Make the same reliability changes that were applied to the https test in
|
|
ce5745bf92f586c58366e9f738441d69118f2c18.
|
|
|
|
Refs: https://github.com/nodejs/node/pull/13312
|
|
PR-URL: https://github.com/nodejs/node/pull/13448
|
|
Reviewed-By: Rich Trott <rtrott@gmail.com>
|
|
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
|
|
Reviewed-By: Refael Ackermann <refack@gmail.com>
|
|
Reviewed-By: James M Snell <jasnell@gmail.com>
|
|
Reviewed-By: Alexey Orlenko <eaglexrlnk@gmail.com>
|
|
|
|
commit 1c7fbdc53bbf8bf43ca32b2c6e9f513508ac90fa
|
|
Author: Rich Trott <rtrott@gmail.com>
|
|
Date: Tue May 30 13:06:52 2017 -0700
|
|
|
|
test: improve test-https-server-keep-alive-timeout
|
|
|
|
The test is flaky under load. These changes greatly improve reliability.
|
|
|
|
* Use a recurring interval to determine when the test should end rather
|
|
than a timer.
|
|
* Increase server timeout to 500ms to allow for events being delayed by
|
|
system load
|
|
|
|
Changing to an interval has the added benefit of reducing the test run
|
|
time from over 2 seconds to under 1 second.
|
|
|
|
Fixes: https://github.com/nodejs/node/issues/13307
|
|
|
|
PR-URL: https://github.com/nodejs/node/pull/13312
|
|
Reviewed-By: Refael Ackermann <refack@gmail.com>
|
|
Reviewed-By: James M Snell <jasnell@gmail.com>
|
|
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
|
|
Reviewed-By: Alexey Orlenko <eaglexrlnk@gmail.com>
|
|
|
|
commit f23b3b6bad391cc3efe4cc815954f009c05fe63a
|
|
Author: Timur Shemsedinov <timur.shemsedinov@gmail.com>
|
|
Date: Thu Oct 29 21:53:43 2015 +0200
|
|
|
|
http: destroy sockets after keepAliveTimeout
|
|
|
|
Implement server.keepAliveTimeout in addition to server.timeout to
|
|
prevent temporary socket/memory leaking in keep-alive mode.
|
|
|
|
PR-URL: https://github.com/nodejs/node/pull/2534
|
|
Author: Timur Shemsedinov <timur.shemsedinov@gmail.com>
|
|
Author: Alexey Orlenko <eaglexrlnk@gmail.com>
|
|
Reviewed-By: James M Snell <jasnell@gmail.com>
|
|
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
|
|
Reviewed-By: Franziska Hinkelmann <franziska.hinkelmann@gmail.com>
|
|
Reviewed-By: Refael Ackermann <refack@gmail.com>
|
|
|
|
|
|
Index: node-v4.9.1/lib/_http_server.js
|
|
===================================================================
|
|
--- node-v4.9.1.orig/lib/_http_server.js
|
|
+++ node-v4.9.1/lib/_http_server.js
|
|
@@ -250,6 +250,7 @@ function Server(requestListener) {
|
|
});
|
|
|
|
this.timeout = 2 * 60 * 1000;
|
|
+ this.keepAliveTimeout = 5000;
|
|
|
|
this._pendingResponseData = 0;
|
|
this.headersTimeout = 40 * 1000; // 40 seconds
|
|
@@ -323,6 +324,8 @@ function connectionListener(socket) {
|
|
socket.destroy();
|
|
});
|
|
|
|
+ socket._keepAliveTimeoutSet = false;
|
|
+
|
|
var parser = parsers.alloc();
|
|
parser.reinitialize(HTTPParser.REQUEST);
|
|
parser.socket = socket;
|
|
@@ -373,6 +376,15 @@ function connectionListener(socket) {
|
|
function socketOnData(d) {
|
|
assert(!socket._paused);
|
|
debug('SERVER socketOnData %d', d.length);
|
|
+
|
|
+ if (socket._keepAliveTimeoutSet) {
|
|
+ socket.setTimeout(0);
|
|
+ if (self.timeout) {
|
|
+ socket.setTimeout(self.timeout);
|
|
+ }
|
|
+ socket._keepAliveTimeoutSet = false;
|
|
+ }
|
|
+
|
|
var ret = parser.execute(d);
|
|
|
|
onParserExecuteCommon(ret, d);
|
|
@@ -399,6 +411,8 @@ function connectionListener(socket) {
|
|
}
|
|
|
|
function onParserExecuteCommon(ret, d) {
|
|
+ resetSocketTimeout(self, socket);
|
|
+
|
|
if (ret instanceof Error) {
|
|
debug('parse error');
|
|
socket.destroy(ret);
|
|
@@ -481,8 +495,14 @@ function connectionListener(socket) {
|
|
}
|
|
|
|
function parserOnIncoming(req, shouldKeepAlive) {
|
|
+ resetSocketTimeout(self, socket);
|
|
+
|
|
incoming.push(req);
|
|
|
|
+ if (self.keepAliveTimeout > 0) {
|
|
+ req.on('end', resetHeadersTimeoutOnReqEnd);
|
|
+ }
|
|
+
|
|
// If the writable end isn't consuming, then stop reading
|
|
// so that we don't become overwhelmed by a flood of
|
|
// pipelined requests that may never be resolved.
|
|
@@ -534,6 +554,12 @@ function connectionListener(socket) {
|
|
|
|
if (res._last) {
|
|
socket.destroySoon();
|
|
+ } else if (outgoing.length === 0) {
|
|
+ if (self.keepAliveTimeout) {
|
|
+ socket.setTimeout(0);
|
|
+ socket.setTimeout(self.keepAliveTimeout);
|
|
+ socket._keepAliveTimeoutSet = true;
|
|
+ }
|
|
} else {
|
|
// start sending the next message
|
|
var m = outgoing.shift();
|
|
@@ -561,6 +587,14 @@ function connectionListener(socket) {
|
|
}
|
|
exports._connectionListener = connectionListener;
|
|
|
|
+function resetSocketTimeout(server, socket) {
|
|
+ if (!socket._keepAliveTimeoutSet)
|
|
+ return;
|
|
+
|
|
+ socket.setTimeout(server.timeout || 0);
|
|
+ socket._keepAliveTimeoutSet = false;
|
|
+}
|
|
+
|
|
function onSocketResume() {
|
|
// It may seem that the socket is resumed, but this is an enemy's trick to
|
|
// deceive us! `resume` is emitted asynchronously, and may be called from
|
|
@@ -608,3 +642,15 @@ function socketOnWrap(ev, fn) {
|
|
|
|
return res;
|
|
}
|
|
+
|
|
+function resetHeadersTimeoutOnReqEnd() {
|
|
+ debug('resetHeadersTimeoutOnReqEnd');
|
|
+
|
|
+ var parser = this.socket.parser;
|
|
+ // Parser can be null if the socket was destroyed
|
|
+ // in that case, there is nothing to do.
|
|
+ if (parser !== null) {
|
|
+ parser.parsingHeadersStart = nowDate();
|
|
+ }
|
|
+}
|
|
+
|
|
Index: node-v4.9.1/test/parallel/test-http-server-keep-alive-timeout-slow-client-headers.js
|
|
===================================================================
|
|
--- /dev/null
|
|
+++ node-v4.9.1/test/parallel/test-http-server-keep-alive-timeout-slow-client-headers.js
|
|
@@ -0,0 +1,57 @@
|
|
+'use strict';
|
|
+
|
|
+const common = require('../common');
|
|
+const assert = require('assert');
|
|
+const http = require('http');
|
|
+const net = require('net');
|
|
+
|
|
+const server = http.createServer(common.mustCall((req, res) => {
|
|
+ res.end();
|
|
+}, 2));
|
|
+
|
|
+server.keepAliveTimeout = common.platformTimeout(100);
|
|
+
|
|
+server.listen(0, common.mustCall(() => {
|
|
+ const port = server.address().port;
|
|
+ const socket = net.connect({ port }, common.mustCall(() => {
|
|
+ request(common.mustCall(() => {
|
|
+ // Make a second request on the same socket, after the keep-alive timeout
|
|
+ // has been set on the server side.
|
|
+ request(common.mustCall(() => {}));
|
|
+ }));
|
|
+ }));
|
|
+
|
|
+ server.on('timeout', common.mustCall(() => {
|
|
+ socket.end();
|
|
+ server.close();
|
|
+ }));
|
|
+
|
|
+ function request(callback) {
|
|
+ socket.setEncoding('utf8');
|
|
+ socket.on('data', onData);
|
|
+ let response = '';
|
|
+
|
|
+ // Simulate a client that sends headers slowly (with a period of inactivity
|
|
+ // that is longer than the keep-alive timeout).
|
|
+ socket.write('GET / HTTP/1.1\r\n' +
|
|
+ `Host: localhost:${port}\r\n`);
|
|
+ setTimeout(() => {
|
|
+ socket.write('Connection: keep-alive\r\n' +
|
|
+ '\r\n');
|
|
+ }, common.platformTimeout(300));
|
|
+
|
|
+ function onData(chunk) {
|
|
+ response += chunk;
|
|
+ if (chunk.includes('\r\n')) {
|
|
+ socket.removeListener('data', onData);
|
|
+ onHeaders();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ function onHeaders() {
|
|
+ assert.ok(response.includes('HTTP/1.1 200 OK\r\n'));
|
|
+ assert.ok(response.includes('Connection: keep-alive\r\n'));
|
|
+ callback();
|
|
+ }
|
|
+ }
|
|
+}));
|
|
Index: node-v4.9.1/test/parallel/test-http-slow-headers-keepalive.js
|
|
===================================================================
|
|
--- /dev/null
|
|
+++ node-v4.9.1/test/parallel/test-http-slow-headers-keepalive.js
|
|
@@ -0,0 +1,59 @@
|
|
+'use strict';
|
|
+
|
|
+const common = require('../common');
|
|
+const http = require('http');
|
|
+const net = require('net');
|
|
+
|
|
+const headers =
|
|
+ 'GET / HTTP/1.1\r\n' +
|
|
+ 'Host: localhost\r\n' +
|
|
+ 'Connection: keep-alive' +
|
|
+ 'Agent: node\r\n';
|
|
+
|
|
+let sendCharEvery = 1000;
|
|
+
|
|
+const server = http.createServer(common.mustCall((req, res) => {
|
|
+ res.writeHead(200);
|
|
+ res.end();
|
|
+}));
|
|
+
|
|
+// Pass a REAL env variable to shortening up the default
|
|
+// value which is 40s otherwise this is useful for manual
|
|
+// testing
|
|
+if (!process.env.REAL) {
|
|
+ sendCharEvery = common.platformTimeout(10);
|
|
+ server.headersTimeout = 2 * sendCharEvery;
|
|
+}
|
|
+
|
|
+server.once('timeout', common.mustCall((socket) => {
|
|
+ socket.destroy();
|
|
+}));
|
|
+
|
|
+server.listen(0, () => {
|
|
+ const client = net.connect(server.address().port);
|
|
+ client.write(headers);
|
|
+ // finish the first request
|
|
+ client.write('\r\n');
|
|
+ // second request
|
|
+ client.write(headers);
|
|
+ client.write('X-CRASH: ');
|
|
+
|
|
+ const interval = setInterval(() => {
|
|
+ client.write('a');
|
|
+ }, sendCharEvery);
|
|
+
|
|
+ client.resume();
|
|
+
|
|
+ const onClose = common.mustCall(() => {
|
|
+ client.removeListener('close', onClose);
|
|
+ client.removeListener('error', onClose);
|
|
+ client.removeListener('end', onClose);
|
|
+ clearInterval(interval);
|
|
+ server.close();
|
|
+ });
|
|
+
|
|
+ client.on('error', onClose);
|
|
+ client.on('close', onClose);
|
|
+ client.on('end', onClose);
|
|
+});
|
|
+
|
|
Index: node-v4.9.1/test/parallel/test-http-server-keep-alive-timeout-slow-server.js
|
|
===================================================================
|
|
--- /dev/null
|
|
+++ node-v4.9.1/test/parallel/test-http-server-keep-alive-timeout-slow-server.js
|
|
@@ -0,0 +1,50 @@
|
|
+'use strict';
|
|
+
|
|
+const common = require('../common');
|
|
+const assert = require('assert');
|
|
+const http = require('http');
|
|
+
|
|
+const server = http.createServer(common.mustCall((req, res) => {
|
|
+ if (req.url === '/first') {
|
|
+ res.end('ok');
|
|
+ return;
|
|
+ }
|
|
+ setTimeout(() => {
|
|
+ res.end('ok');
|
|
+ }, common.platformTimeout(500));
|
|
+}, 2));
|
|
+
|
|
+server.keepAliveTimeout = common.platformTimeout(200);
|
|
+
|
|
+const agent = new http.Agent({
|
|
+ keepAlive: true,
|
|
+ maxSockets: 1
|
|
+});
|
|
+
|
|
+function request(path, callback) {
|
|
+ const port = server.address().port;
|
|
+ const req = http.request({ agent, path, port }, common.mustCall((res) => {
|
|
+ assert.strictEqual(res.statusCode, 200);
|
|
+
|
|
+ res.setEncoding('utf8');
|
|
+
|
|
+ let result = '';
|
|
+ res.on('data', (chunk) => {
|
|
+ result += chunk;
|
|
+ });
|
|
+
|
|
+ res.on('end', common.mustCall(() => {
|
|
+ assert.strictEqual(result, 'ok');
|
|
+ callback();
|
|
+ }));
|
|
+ }));
|
|
+ req.end();
|
|
+}
|
|
+
|
|
+server.listen(0, common.mustCall(() => {
|
|
+ request('/first', () => {
|
|
+ request('/second', () => {
|
|
+ server.close();
|
|
+ });
|
|
+ });
|
|
+}));
|
|
Index: node-v4.9.1/doc/api/http.md
|
|
===================================================================
|
|
--- node-v4.9.1.orig/doc/api/http.md
|
|
+++ node-v4.9.1/doc/api/http.md
|
|
@@ -729,17 +729,33 @@ customised.
|
|
added: v0.9.12
|
|
-->
|
|
|
|
-* {Number} Default = 120000 (2 minutes)
|
|
+* {number} Timeout in milliseconds. Defaults to 120000 (2 minutes).
|
|
|
|
The number of milliseconds of inactivity before a socket is presumed
|
|
to have timed out.
|
|
|
|
-Note that the socket timeout logic is set up on connection, so
|
|
-changing this value only affects *new* connections to the server, not
|
|
-any existing connections.
|
|
+A value of 0 will disable the timeout behavior on incoming connections.
|
|
|
|
-Set to 0 to disable any kind of automatic timeout behavior on incoming
|
|
-connections.
|
|
+*Note*: The socket timeout logic is set up on connection, so changing this
|
|
+value only affects new connections to the server, not any existing connections.
|
|
+
|
|
+### server.keepAliveTimeout
|
|
+<!-- YAML
|
|
+added: REPLACEME
|
|
+-->
|
|
+
|
|
+* {number} Timeout in milliseconds. Defaults to 5000 (5 seconds).
|
|
+
|
|
+The number of milliseconds of inactivity a server needs to wait for additional
|
|
+incoming data, after it has finished writing the last response, before a socket
|
|
+will be destroyed. If the server receives new data before the keep-alive
|
|
+timeout has fired, it will reset the regular inactivity timeout, i.e.,
|
|
+[`server.timeout`][].
|
|
+
|
|
+A value of 0 will disable the keep-alive timeout behavior on incoming connections.
|
|
+
|
|
+*Note*: The socket timeout logic is set up on connection, so changing this
|
|
+value only affects new connections to the server, not any existing connections.
|
|
|
|
## Class: http.ServerResponse
|
|
<!-- YAML
|
|
@@ -1498,6 +1514,7 @@ There are a few special headers that sho
|
|
[`response.write(data, encoding)`]: #http_response_write_chunk_encoding_callback
|
|
[`response.writeContinue()`]: #http_response_writecontinue
|
|
[`response.writeHead()`]: #http_response_writehead_statuscode_statusmessage_headers
|
|
+[`server.timeout`]: #http_server_timeout
|
|
[`socket.setKeepAlive()`]: net.html#net_socket_setkeepalive_enable_initialdelay
|
|
[`socket.setNoDelay()`]: net.html#net_socket_setnodelay_nodelay
|
|
[`socket.setTimeout()`]: net.html#net_socket_settimeout_timeout_callback
|
|
Index: node-v4.9.1/doc/api/https.md
|
|
===================================================================
|
|
--- node-v4.9.1.orig/doc/api/https.md
|
|
+++ node-v4.9.1/doc/api/https.md
|
|
@@ -41,6 +41,14 @@ added: v0.11.2
|
|
|
|
See [`http.Server#timeout`][].
|
|
|
|
+### server.keepAliveTimeout
|
|
+<!-- YAML
|
|
+added: REPLACEME
|
|
+-->
|
|
+- {number} Defaults to 5000 (5 seconds).
|
|
+
|
|
+See [`http.Server#keepAliveTimeout`][].
|
|
+
|
|
## https.createServer(options[, requestListener])
|
|
<!-- YAML
|
|
added: v0.3.4
|
|
@@ -264,6 +272,7 @@ var req = https.request(options, (res) =
|
|
[`globalAgent`]: #https_https_globalagent
|
|
[`http.Agent`]: http.html#http_class_http_agent
|
|
[`http.Server#headersTimeout`]: http.html#http_server_headerstimeout
|
|
+[`http.Server#keepAliveTimeout`]: http.html#http_server_keepalivetimeout
|
|
[`http.close()`]: http.html#http_server_close_callback
|
|
[`http.get()`]: http.html#http_http_get_options_callback
|
|
[`http.listen()`]: http.html#http_server_listen_port_hostname_backlog_callback
|
|
Index: node-v4.9.1/lib/https.js
|
|
===================================================================
|
|
--- node-v4.9.1.orig/lib/https.js
|
|
+++ node-v4.9.1/lib/https.js
|
|
@@ -34,7 +34,7 @@ function Server(opts, requestListener) {
|
|
});
|
|
|
|
this.timeout = 2 * 60 * 1000;
|
|
-
|
|
+ this.keepAliveTimeout = 5000;
|
|
this.headersTimeout = 40 * 1000; // 40 seconds
|
|
}
|
|
inherits(Server, tls.Server);
|
|
Index: node-v4.9.1/test/parallel/test-http-server-keep-alive-timeout.js
|
|
===================================================================
|
|
--- /dev/null
|
|
+++ node-v4.9.1/test/parallel/test-http-server-keep-alive-timeout.js
|
|
@@ -0,0 +1,95 @@
|
|
+'use strict';
|
|
+
|
|
+const common = require('../common');
|
|
+const assert = require('assert');
|
|
+const http = require('http');
|
|
+const net = require('net');
|
|
+
|
|
+const tests = [];
|
|
+
|
|
+function test(fn) {
|
|
+ if (!tests.length) {
|
|
+ process.nextTick(run);
|
|
+ }
|
|
+ tests.push(fn);
|
|
+}
|
|
+
|
|
+function run() {
|
|
+ const fn = tests.shift();
|
|
+ if (fn) fn(run);
|
|
+}
|
|
+
|
|
+test(function serverEndKeepAliveTimeoutWithPipeline(cb) {
|
|
+ let socket;
|
|
+ let destroyedSockets = 0;
|
|
+ let timeoutCount = 0;
|
|
+ let requestCount = 0;
|
|
+ process.on('exit', () => {
|
|
+ assert.strictEqual(timeoutCount, 1);
|
|
+ assert.strictEqual(requestCount, 3);
|
|
+ assert.strictEqual(destroyedSockets, 1);
|
|
+ });
|
|
+ const server = http.createServer((req, res) => {
|
|
+ socket = req.socket;
|
|
+ requestCount++;
|
|
+ res.end();
|
|
+ });
|
|
+ server.setTimeout(200, (socket) => {
|
|
+ timeoutCount++;
|
|
+ socket.destroy();
|
|
+ });
|
|
+ server.keepAliveTimeout = 50;
|
|
+ server.listen(0, common.mustCall(() => {
|
|
+ const options = {
|
|
+ port: server.address().port,
|
|
+ allowHalfOpen: true
|
|
+ };
|
|
+ const c = net.connect(options, () => {
|
|
+ c.write('GET /1 HTTP/1.1\r\nHost: localhost\r\n\r\n');
|
|
+ c.write('GET /2 HTTP/1.1\r\nHost: localhost\r\n\r\n');
|
|
+ c.write('GET /3 HTTP/1.1\r\nHost: localhost\r\n\r\n');
|
|
+ });
|
|
+ setTimeout(() => {
|
|
+ server.close();
|
|
+ if (socket.destroyed) destroyedSockets++;
|
|
+ cb();
|
|
+ }, 1000);
|
|
+ }));
|
|
+});
|
|
+
|
|
+test(function serverNoEndKeepAliveTimeoutWithPipeline(cb) {
|
|
+ let socket;
|
|
+ let destroyedSockets = 0;
|
|
+ let timeoutCount = 0;
|
|
+ let requestCount = 0;
|
|
+ process.on('exit', () => {
|
|
+ assert.strictEqual(timeoutCount, 1);
|
|
+ assert.strictEqual(requestCount, 3);
|
|
+ assert.strictEqual(destroyedSockets, 1);
|
|
+ });
|
|
+ const server = http.createServer((req, res) => {
|
|
+ socket = req.socket;
|
|
+ requestCount++;
|
|
+ });
|
|
+ server.setTimeout(200, (socket) => {
|
|
+ timeoutCount++;
|
|
+ socket.destroy();
|
|
+ });
|
|
+ server.keepAliveTimeout = 50;
|
|
+ server.listen(0, common.mustCall(() => {
|
|
+ const options = {
|
|
+ port: server.address().port,
|
|
+ allowHalfOpen: true
|
|
+ };
|
|
+ const c = net.connect(options, () => {
|
|
+ c.write('GET /1 HTTP/1.1\r\nHost: localhost\r\n\r\n');
|
|
+ c.write('GET /2 HTTP/1.1\r\nHost: localhost\r\n\r\n');
|
|
+ c.write('GET /3 HTTP/1.1\r\nHost: localhost\r\n\r\n');
|
|
+ });
|
|
+ setTimeout(() => {
|
|
+ server.close();
|
|
+ if (socket.destroyed) destroyedSockets++;
|
|
+ cb();
|
|
+ }, 1000);
|
|
+ }));
|
|
+});
|
|
Index: node-v4.9.1/test/parallel/test-https-server-keep-alive-timeout.js
|
|
===================================================================
|
|
--- /dev/null
|
|
+++ node-v4.9.1/test/parallel/test-https-server-keep-alive-timeout.js
|
|
@@ -0,0 +1,85 @@
|
|
+'use strict';
|
|
+
|
|
+const common = require('../common');
|
|
+const assert = require('assert');
|
|
+const https = require('https');
|
|
+const tls = require('tls');
|
|
+const fs = require('fs');
|
|
+
|
|
+const tests = [];
|
|
+
|
|
+const serverOptions = {
|
|
+ key: fs.readFileSync(common.fixturesDir + '/keys/agent1-key.pem'),
|
|
+ cert: fs.readFileSync(common.fixturesDir + '/keys/agent1-cert.pem')
|
|
+};
|
|
+
|
|
+function test(fn) {
|
|
+ if (!tests.length) {
|
|
+ process.nextTick(run);
|
|
+ }
|
|
+ tests.push(fn);
|
|
+}
|
|
+
|
|
+function run() {
|
|
+ const fn = tests.shift();
|
|
+ if (fn) fn(run);
|
|
+}
|
|
+
|
|
+test(function serverKeepAliveTimeoutWithPipeline(cb) {
|
|
+ let requestCount = 0;
|
|
+ process.on('exit', function() {
|
|
+ assert.strictEqual(requestCount, 3);
|
|
+ });
|
|
+ const server = https.createServer(serverOptions, (req, res) => {
|
|
+ requestCount++;
|
|
+ res.end();
|
|
+ });
|
|
+ server.setTimeout(500, common.mustCall((socket) => {
|
|
+ // End this test and call `run()` for the next test (if any).
|
|
+ socket.destroy();
|
|
+ server.close();
|
|
+ cb();
|
|
+ }));
|
|
+ server.keepAliveTimeout = 50;
|
|
+ server.listen(0, common.mustCall(() => {
|
|
+ const options = {
|
|
+ port: server.address().port,
|
|
+ allowHalfOpen: true,
|
|
+ rejectUnauthorized: false
|
|
+ };
|
|
+ const c = tls.connect(options, () => {
|
|
+ c.write('GET /1 HTTP/1.1\r\nHost: localhost\r\n\r\n');
|
|
+ c.write('GET /2 HTTP/1.1\r\nHost: localhost\r\n\r\n');
|
|
+ c.write('GET /3 HTTP/1.1\r\nHost: localhost\r\n\r\n');
|
|
+ });
|
|
+ }));
|
|
+});
|
|
+
|
|
+test(function serverNoEndKeepAliveTimeoutWithPipeline(cb) {
|
|
+ let requestCount = 0;
|
|
+ process.on('exit', () => {
|
|
+ assert.strictEqual(requestCount, 3);
|
|
+ });
|
|
+ const server = https.createServer(serverOptions, (req, res) => {
|
|
+ requestCount++;
|
|
+ });
|
|
+ server.setTimeout(500, common.mustCall((socket) => {
|
|
+ // End this test and call `run()` for the next test (if any).
|
|
+ socket.destroy();
|
|
+ server.close();
|
|
+ cb();
|
|
+ }));
|
|
+ server.keepAliveTimeout = 50;
|
|
+ server.listen(0, common.mustCall(() => {
|
|
+ const options = {
|
|
+ port: server.address().port,
|
|
+ allowHalfOpen: true,
|
|
+ rejectUnauthorized: false
|
|
+ };
|
|
+ const c = tls.connect(options, () => {
|
|
+ c.write('GET /1 HTTP/1.1\r\nHost: localhost\r\n\r\n');
|
|
+ c.write('GET /2 HTTP/1.1\r\nHost: localhost\r\n\r\n');
|
|
+ c.write('GET /3 HTTP/1.1\r\nHost: localhost\r\n\r\n');
|
|
+ });
|
|
+ }));
|
|
+});
|