Skip to content

Commit 5be8521

Browse files
renewebjasnell
authored andcommitted
http: socket connection timeout for http request
This allows passing the socket connection timeout to http#request such that it will be set before the socket is connecting PR-URL: #8101 Fixes: #7580 Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Ilkka Myller <[email protected]>
1 parent f3da02a commit 5be8521

6 files changed

+58
-18
lines changed

doc/api/http.md

+2
Original file line numberDiff line numberDiff line change
@@ -1419,6 +1419,8 @@ Options:
14191419
request when the `agent` option is not used. This can be used to avoid
14201420
creating a custom Agent class just to override the default `createConnection`
14211421
function. See [`agent.createConnection()`][] for more details.
1422+
- `timeout`: A number specifying the socket timeout in milliseconds.
1423+
This will set the timeout before the socket is connected.
14221424

14231425
The optional `callback` parameter will be added as a one time listener for
14241426
the [`'response'`][] event.

doc/api/net.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -765,7 +765,9 @@ A factory function, which returns a new [`net.Socket`][] and automatically
765765
connects with the supplied `options`.
766766

767767
The options are passed to both the [`net.Socket`][] constructor and the
768-
[`socket.connect`][] method.
768+
[`socket.connect`][] method.
769+
770+
Passing `timeout` as an option will call [`socket.setTimeout()`][] after the socket is created, but before it is connecting.
769771

770772
The `connectListener` parameter will be added as a listener for the
771773
[`'connect'`][] event once.

lib/_http_client.js

+7-1
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ function ClientRequest(options, cb) {
6767
}
6868

6969
self.socketPath = options.socketPath;
70+
self.timeout = options.timeout;
7071

7172
var method = self.method = (options.method || 'GET').toUpperCase();
7273
if (!common._checkIsHttpToken(method)) {
@@ -134,7 +135,8 @@ function ClientRequest(options, cb) {
134135
self._last = true;
135136
self.shouldKeepAlive = false;
136137
const optionsPath = {
137-
path: self.socketPath
138+
path: self.socketPath,
139+
timeout: self.timeout
138140
};
139141
const newSocket = self.agent.createConnection(optionsPath, oncreate);
140142
if (newSocket && !called) {
@@ -559,6 +561,10 @@ function tickOnSocket(req, socket) {
559561
socket.on('data', socketOnData);
560562
socket.on('end', socketOnEnd);
561563
socket.on('close', socketCloseListener);
564+
565+
if (req.timeout) {
566+
socket.once('timeout', () => req.emit('timeout'));
567+
}
562568
req.emit('socket', socket);
563569
}
564570

lib/net.js

+5
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,11 @@ exports.connect = exports.createConnection = function() {
6666
args = normalizeArgs(args);
6767
debug('createConnection', args);
6868
var s = new Socket(args[0]);
69+
70+
if (args[0].timeout) {
71+
s.setTimeout(args[0].timeout);
72+
}
73+
6974
return Socket.prototype.connect.apply(s, args);
7075
};
7176

test/parallel/test-http-client-timeout-event.js

+8-16
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
'use strict';
2-
var common = require('../common');
3-
var assert = require('assert');
4-
var http = require('http');
2+
const common = require('../common');
3+
const assert = require('assert');
4+
const http = require('http');
55

66
var options = {
77
method: 'GET',
@@ -10,30 +10,22 @@ var options = {
1010
path: '/'
1111
};
1212

13-
var server = http.createServer(function(req, res) {
14-
// this space intentionally left blank
15-
});
13+
var server = http.createServer();
1614

1715
server.listen(0, options.host, function() {
1816
options.port = this.address().port;
19-
var req = http.request(options, function(res) {
20-
// this space intentionally left blank
21-
});
17+
var req = http.request(options);
2218
req.on('error', function() {
2319
// this space is intentionally left blank
2420
});
25-
req.on('close', function() {
26-
server.close();
27-
});
21+
req.on('close', common.mustCall(() => server.close()));
2822

2923
var timeout_events = 0;
3024
req.setTimeout(1);
31-
req.on('timeout', function() {
32-
timeout_events += 1;
33-
});
25+
req.on('timeout', common.mustCall(() => timeout_events += 1));
3426
setTimeout(function() {
3527
req.destroy();
36-
assert.equal(timeout_events, 1);
28+
assert.strictEqual(timeout_events, 1);
3729
}, common.platformTimeout(100));
3830
setTimeout(function() {
3931
req.end();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
'use strict';
2+
const common = require('../common');
3+
const assert = require('assert');
4+
const http = require('http');
5+
6+
var options = {
7+
method: 'GET',
8+
port: undefined,
9+
host: '127.0.0.1',
10+
path: '/',
11+
timeout: 1
12+
};
13+
14+
var server = http.createServer();
15+
16+
server.listen(0, options.host, function() {
17+
options.port = this.address().port;
18+
var req = http.request(options);
19+
req.on('error', function() {
20+
// this space is intentionally left blank
21+
});
22+
req.on('close', common.mustCall(() => server.close()));
23+
24+
var timeout_events = 0;
25+
req.on('timeout', common.mustCall(() => timeout_events += 1));
26+
setTimeout(function() {
27+
req.destroy();
28+
assert.strictEqual(timeout_events, 1);
29+
}, common.platformTimeout(100));
30+
setTimeout(function() {
31+
req.end();
32+
}, common.platformTimeout(10));
33+
});

0 commit comments

Comments
 (0)