Skip to content

Commit e3b692a

Browse files
committed
fix: send keep-alive timeout
Provide a hint for the server to keep connection alive until it is considered no longer re-usable by client. This reduces the risk of a race where the client sends a request and the server closes it before receiving it.
1 parent 5ef4905 commit e3b692a

3 files changed

Lines changed: 25 additions & 1 deletion

File tree

lib/client.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,7 @@ class Parser extends HTTPParser {
412412
const request = client[kQueue][client[kRunningIdx]]
413413

414414
// TODO: Check for content-length mismatch?
415+
// TODO: keep-alive timeout & max?
415416

416417
assert(this.statusCode < 200)
417418

@@ -797,6 +798,14 @@ function write (client, request) {
797798
socket.write(`content-length: ${contentLength}\r\n`, 'ascii')
798799
}
799800

801+
if (client[kSocketTimeout]) {
802+
// Provide a hint for the server to keep connection alive until it is
803+
// considered no longer re-usable by client. This reduces the risk of
804+
// a race where the client sends a request and the server closes it
805+
// before receiving it.
806+
socket.write(`keep-alive: timeout=${Math.ceil(client[kSocketTimeout] * 2) / 1000}\r\n`)
807+
}
808+
800809
if (method === 'HEAD') {
801810
// https://github.com/mcollina/undici/issues/258
802811

lib/request.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,11 @@ class Request extends AsyncResource {
122122
key.toLowerCase() === 'connection'
123123
) {
124124
throw new InvalidArgumentError('invalid connection header')
125+
} else if (
126+
key.length === 10 &&
127+
key.toLowerCase() === 'keep-alive'
128+
) {
129+
throw new InvalidArgumentError('invalid keep-alive header')
125130
} else {
126131
header += `${key}: ${val}\r\n`
127132
}

test/invalid-headers.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ const { test } = require('tap')
44
const { Client, errors } = require('..')
55

66
test('invalid headers', (t) => {
7-
t.plan(5)
7+
t.plan(6)
88

99
const client = new Client('http://localhost:3000')
1010
t.teardown(client.destroy.bind(client))
@@ -38,6 +38,16 @@ test('invalid headers', (t) => {
3838
t.ok(err instanceof errors.InvalidArgumentError)
3939
})
4040

41+
client.request({
42+
path: '/',
43+
method: 'GET',
44+
headers: {
45+
'keep-alive': 'timeout=5'
46+
}
47+
}, (err, data) => {
48+
t.ok(err instanceof errors.InvalidArgumentError)
49+
})
50+
4151
client.request({
4252
path: '/',
4353
method: 'GET',

0 commit comments

Comments
 (0)