Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit fc29cf9

Browse filesBrowse files
themeztargos
authored andcommitted
http: add reusedSocket property on client request
Set ClientRequest.reusedSocket property when reusing socket for request, so user can handle retry base on wether the request is reusing a socket. Refs: request/request#3131 PR-URL: #29715 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: Weijia Wang <starkwang@126.com>
1 parent e6397aa commit fc29cf9
Copy full SHA for fc29cf9

File tree

Expand file treeCollapse file tree

4 files changed

+64
-3
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

4 files changed

+64
-3
lines changed
Open diff view settings
Collapse file

‎doc/api/http.md‎

Copy file name to clipboardExpand all lines: doc/api/http.md
+56Lines changed: 56 additions & 0 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -673,6 +673,62 @@ Removes a header that's already defined into headers object.
673673
request.removeHeader('Content-Type');
674674
```
675675

676+
### `request.reusedSocket`
677+
678+
<!-- YAML
679+
added: REPLACEME
680+
-->
681+
682+
* {boolean} Whether the request is send through a reused socket.
683+
684+
When sending request through a keep-alive enabled agent, the underlying socket
685+
might be reused. But if server closes connection at unfortunate time, client
686+
may run into a 'ECONNRESET' error.
687+
688+
```js
689+
const http = require('http');
690+
691+
// Server has a 5 seconds keep-alive timeout by default
692+
http
693+
.createServer((req, res) => {
694+
res.write('hello\n');
695+
res.end();
696+
})
697+
.listen(3000);
698+
699+
setInterval(() => {
700+
// Adapting a keep-alive agent
701+
http.get('http://localhost:3000', { agent }, (res) => {
702+
res.on('data', (data) => {
703+
// Do nothing
704+
});
705+
});
706+
}, 5000); // Sending request on 5s interval so it's easy to hit idle timeout
707+
```
708+
709+
By marking a request whether it reused socket or not, we can do
710+
automatic error retry base on it.
711+
712+
```js
713+
const http = require('http');
714+
const agent = new http.Agent({ keepAlive: true });
715+
716+
function retriableRequest() {
717+
const req = http
718+
.get('http://localhost:3000', { agent }, (res) => {
719+
// ...
720+
})
721+
.on('error', (err) => {
722+
// Check if retry is needed
723+
if (req.reusedSocket && err.code === 'ECONNRESET') {
724+
retriableRequest();
725+
}
726+
});
727+
}
728+
729+
retriableRequest();
730+
```
731+
676732
### `request.setHeader(name, value)`
677733
<!-- YAML
678734
added: v1.6.0
Collapse file

‎lib/_http_agent.js‎

Copy file name to clipboardExpand all lines: lib/_http_agent.js
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,7 @@ Agent.prototype.keepSocketAlive = function keepSocketAlive(socket) {
340340

341341
Agent.prototype.reuseSocket = function reuseSocket(socket, req) {
342342
debug('have free socket');
343+
req.reusedSocket = true;
343344
socket.ref();
344345
};
345346

Collapse file

‎lib/_http_client.js‎

Copy file name to clipboardExpand all lines: lib/_http_client.js
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,7 @@ function ClientRequest(input, options, cb) {
195195
this.upgradeOrConnect = false;
196196
this.parser = null;
197197
this.maxHeadersCount = null;
198+
this.reusedSocket = false;
198199

199200
let called = false;
200201

Collapse file

‎test/parallel/test-http-agent-keepalive.js‎

Copy file name to clipboardExpand all lines: test/parallel/test-http-agent-keepalive.js
+6-3Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,8 @@ function checkDataAndSockets(body) {
6363

6464
function second() {
6565
// Request second, use the same socket
66-
get('/second', common.mustCall((res) => {
66+
const req = get('/second', common.mustCall((res) => {
67+
assert.strictEqual(req.reusedSocket, true);
6768
assert.strictEqual(res.statusCode, 200);
6869
res.on('data', checkDataAndSockets);
6970
res.on('end', common.mustCall(() => {
@@ -80,7 +81,8 @@ function second() {
8081

8182
function remoteClose() {
8283
// Mock remote server close the socket
83-
get('/remote_close', common.mustCall((res) => {
84+
const req = get('/remote_close', common.mustCall((res) => {
85+
assert.deepStrictEqual(req.reusedSocket, true);
8486
assert.deepStrictEqual(res.statusCode, 200);
8587
res.on('data', checkDataAndSockets);
8688
res.on('end', common.mustCall(() => {
@@ -120,7 +122,8 @@ function remoteError() {
120122
server.listen(0, common.mustCall(() => {
121123
name = `localhost:${server.address().port}:`;
122124
// Request first, and keep alive
123-
get('/first', common.mustCall((res) => {
125+
const req = get('/first', common.mustCall((res) => {
126+
assert.strictEqual(req.reusedSocket, false);
124127
assert.strictEqual(res.statusCode, 200);
125128
res.on('data', checkDataAndSockets);
126129
res.on('end', common.mustCall(() => {

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.