aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorkillagu <killa123@126.com>2018-06-08 12:42:27 +0800
committerAnna Henningsen <anna@addaleax.net>2018-07-13 18:44:03 +0200
commit949e8851484c016c07f6cc9e5889f0f2e56baf2a (patch)
treeaaf19ca5fde1600bd8000228f368ec96afc7c43b /lib
parentd462f8cfe34019ab8bf1d57d33bf16e64c8fb815 (diff)
downloadandroid-node-v8-949e8851484c016c07f6cc9e5889f0f2e56baf2a.tar.gz
android-node-v8-949e8851484c016c07f6cc9e5889f0f2e56baf2a.tar.bz2
android-node-v8-949e8851484c016c07f6cc9e5889f0f2e56baf2a.zip
http: fix request with option timeout and agent
When request with both timeout and agent, timeout not work. This patch will fix it, socket timeout will set to request timeout before socket is connected, and socket timeout will reset to agent timeout after response end. Fixes: https://github.com/nodejs/node/issues/21185 PR-URL: https://github.com/nodejs/node/pull/21204 Reviewed-By: Khaidi Chu <i@2333.moe> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Ujjwal Sharma <usharma1998@gmail.com>
Diffstat (limited to 'lib')
-rw-r--r--lib/_http_agent.js33
-rw-r--r--lib/_http_client.js74
-rw-r--r--lib/net.js1
3 files changed, 66 insertions, 42 deletions
diff --git a/lib/_http_agent.js b/lib/_http_agent.js
index 67f3d667b2..1a2920cf09 100644
--- a/lib/_http_agent.js
+++ b/lib/_http_agent.js
@@ -66,7 +66,8 @@ function Agent(options) {
if (socket.writable &&
this.requests[name] && this.requests[name].length) {
- this.requests[name].shift().onSocket(socket);
+ const req = this.requests[name].shift();
+ setRequestSocket(this, req, socket);
if (this.requests[name].length === 0) {
// don't leak
delete this.requests[name];
@@ -176,12 +177,12 @@ Agent.prototype.addRequest = function addRequest(req, options, port/* legacy */,
delete this.freeSockets[name];
this.reuseSocket(socket, req);
- req.onSocket(socket);
+ setRequestSocket(this, req, socket);
this.sockets[name].push(socket);
} else if (sockLen < this.maxSockets) {
debug('call onSocket', sockLen, freeLen);
// If we are under maxSockets create a new one.
- this.createSocket(req, options, handleSocketCreation(req, true));
+ this.createSocket(req, options, handleSocketCreation(this, req, true));
} else {
debug('wait for socket');
// We are over limit so we'll add it to the queue.
@@ -305,9 +306,10 @@ Agent.prototype.removeSocket = function removeSocket(s, options) {
if (this.requests[name] && this.requests[name].length) {
debug('removeSocket, have a request, make a socket');
- var req = this.requests[name][0];
+ const req = this.requests[name][0];
// If we have pending requests and a socket gets closed make a new one
- this.createSocket(req, options, handleSocketCreation(req, false));
+ const socketCreationHandler = handleSocketCreation(this, req, false);
+ this.createSocket(req, options, socketCreationHandler);
}
};
@@ -337,19 +339,36 @@ Agent.prototype.destroy = function destroy() {
}
};
-function handleSocketCreation(request, informRequest) {
+function handleSocketCreation(agent, request, informRequest) {
return function handleSocketCreation_Inner(err, socket) {
if (err) {
process.nextTick(emitErrorNT, request, err);
return;
}
if (informRequest)
- request.onSocket(socket);
+ setRequestSocket(agent, request, socket);
else
socket.emit('free');
};
}
+function setRequestSocket(agent, req, socket) {
+ req.onSocket(socket);
+ const agentTimeout = agent.options.timeout || 0;
+ if (req.timeout === undefined || req.timeout === agentTimeout) {
+ return;
+ }
+ socket.setTimeout(req.timeout);
+ // reset timeout after response end
+ req.once('response', (res) => {
+ res.once('end', () => {
+ if (socket.timeout !== agentTimeout) {
+ socket.setTimeout(agentTimeout);
+ }
+ });
+ });
+}
+
function emitErrorNT(emitter, err) {
emitter.emit('error', err);
}
diff --git a/lib/_http_client.js b/lib/_http_client.js
index c4f753412c..7d28cda681 100644
--- a/lib/_http_client.js
+++ b/lib/_http_client.js
@@ -656,18 +656,35 @@ function tickOnSocket(req, socket) {
socket.on('end', socketOnEnd);
socket.on('close', socketCloseListener);
- if (req.timeout) {
- const emitRequestTimeout = () => req.emit('timeout');
- socket.once('timeout', emitRequestTimeout);
- req.once('response', (res) => {
- res.once('end', () => {
- socket.removeListener('timeout', emitRequestTimeout);
- });
- });
+ if (req.timeout !== undefined) {
+ listenSocketTimeout(req);
}
req.emit('socket', socket);
}
+function listenSocketTimeout(req) {
+ if (req.timeoutCb) {
+ return;
+ }
+ const emitRequestTimeout = () => req.emit('timeout');
+ // Set timeoutCb so it will get cleaned up on request end.
+ req.timeoutCb = emitRequestTimeout;
+ // Delegate socket timeout event.
+ if (req.socket) {
+ req.socket.once('timeout', emitRequestTimeout);
+ } else {
+ req.on('socket', (socket) => {
+ socket.once('timeout', emitRequestTimeout);
+ });
+ }
+ // Remove socket timeout listener after response end.
+ req.once('response', (res) => {
+ res.once('end', () => {
+ req.socket.removeListener('timeout', emitRequestTimeout);
+ });
+ });
+}
+
ClientRequest.prototype.onSocket = function onSocket(socket) {
process.nextTick(onSocketNT, this, socket);
};
@@ -717,42 +734,29 @@ function _deferToConnect(method, arguments_, cb) {
}
ClientRequest.prototype.setTimeout = function setTimeout(msecs, callback) {
+ listenSocketTimeout(this);
msecs = validateTimerDuration(msecs);
if (callback) this.once('timeout', callback);
- const emitTimeout = () => this.emit('timeout');
-
- if (this.socket && this.socket.writable) {
- if (this.timeoutCb)
- this.socket.setTimeout(0, this.timeoutCb);
- this.timeoutCb = emitTimeout;
- this.socket.setTimeout(msecs, emitTimeout);
- return this;
- }
-
- // Set timeoutCb so that it'll get cleaned up on request end
- this.timeoutCb = emitTimeout;
if (this.socket) {
- var sock = this.socket;
- this.socket.once('connect', function() {
- sock.setTimeout(msecs, emitTimeout);
- });
- return this;
+ setSocketTimeout(this.socket, msecs);
+ } else {
+ this.once('socket', (sock) => setSocketTimeout(sock, msecs));
}
- this.once('socket', function(sock) {
- if (sock.connecting) {
- sock.once('connect', function() {
- sock.setTimeout(msecs, emitTimeout);
- });
- } else {
- sock.setTimeout(msecs, emitTimeout);
- }
- });
-
return this;
};
+function setSocketTimeout(sock, msecs) {
+ if (sock.connecting) {
+ sock.once('connect', function() {
+ sock.setTimeout(msecs);
+ });
+ } else {
+ sock.setTimeout(msecs);
+ }
+}
+
ClientRequest.prototype.setNoDelay = function setNoDelay(noDelay) {
this._deferToConnect('setNoDelay', [noDelay]);
};
diff --git a/lib/net.js b/lib/net.js
index 2393539737..889f28b0aa 100644
--- a/lib/net.js
+++ b/lib/net.js
@@ -408,6 +408,7 @@ function writeAfterFIN(chunk, encoding, cb) {
}
Socket.prototype.setTimeout = function(msecs, callback) {
+ this.timeout = msecs;
// Type checking identical to timers.enroll()
msecs = validateTimerDuration(msecs);