Skip to content

Commit 76d03a7

Browse files
committed
perf: allow keep alive for HEAD requests
1 parent f9aa0f1 commit 76d03a7

File tree

3 files changed

+75
-6
lines changed

3 files changed

+75
-6
lines changed

lib/client.js

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,7 @@ class Parser {
441441

442442
this.keepAlive = ''
443443
this.contentLength = ''
444+
this.connection = ''
444445
this.maxResponseSize = client[kMaxResponseSize]
445446
}
446447

@@ -616,6 +617,8 @@ class Parser {
616617
const key = this.headers[len - 2]
617618
if (key.length === 10 && key.toString().toLowerCase() === 'keep-alive') {
618619
this.keepAlive += buf.toString()
620+
} else if (key.length === 10 && key.toString().toLowerCase() === 'connection') {
621+
this.connection += buf.toString()
619622
} else if (key.length === 14 && key.toString().toLowerCase() === 'content-length') {
620623
this.contentLength += buf.toString()
621624
}
@@ -709,7 +712,11 @@ class Parser {
709712
assert.strictEqual(this.timeoutType, TIMEOUT_HEADERS)
710713

711714
this.statusCode = statusCode
712-
this.shouldKeepAlive = shouldKeepAlive
715+
this.shouldKeepAlive = (
716+
shouldKeepAlive ||
717+
// Override llhttp value which does not allow keepAlive for HEAD.
718+
(request.method === 'HEAD' && !socket[kReset] && this.connection.toLowerCase() === 'keep-alive')
719+
)
713720

714721
if (this.statusCode >= 200) {
715722
const bodyTimeout = request.bodyTimeout != null
@@ -739,7 +746,7 @@ class Parser {
739746
this.headers = []
740747
this.headersSize = 0
741748

742-
if (shouldKeepAlive && client[kPipelining]) {
749+
if (this.shouldKeepAlive && client[kPipelining]) {
743750
const keepAliveTimeout = this.keepAlive ? util.parseKeepAliveTimeout(this.keepAlive) : null
744751

745752
if (keepAliveTimeout != null) {
@@ -769,7 +776,6 @@ class Parser {
769776
}
770777

771778
if (request.method === 'HEAD') {
772-
assert(socket[kReset])
773779
return 1
774780
}
775781

@@ -843,6 +849,7 @@ class Parser {
843849
this.bytesRead = 0
844850
this.contentLength = ''
845851
this.keepAlive = ''
852+
this.connection = ''
846853

847854
assert(this.headers.length % 2 === 0)
848855
this.headers = []
@@ -1376,8 +1383,8 @@ function write (client, request) {
13761383
socket[kReset] = true
13771384
}
13781385

1379-
if (reset) {
1380-
socket[kReset] = true
1386+
if (reset != null) {
1387+
socket[kReset] = reset
13811388
}
13821389

13831390
if (client[kMaxRequests] && socket[kCounter]++ >= client[kMaxRequests]) {

lib/core/request.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ class Request {
144144

145145
this.blocking = blocking == null ? false : blocking
146146

147-
this.reset = reset == null ? false : reset
147+
this.reset = reset == null ? null : reset
148148

149149
this.host = null
150150

test/client-head-reset-override.js

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
'use strict'
2+
3+
const { createServer } = require('http')
4+
const { test } = require('tap')
5+
const { Client } = require('..')
6+
7+
test('override HEAD reset', (t) => {
8+
const expected = 'testing123'
9+
const server = createServer((req, res) => {
10+
if (req.method === 'GET') {
11+
res.write(expected)
12+
}
13+
res.end()
14+
})
15+
t.teardown(server.close.bind(server))
16+
17+
server.listen(0, () => {
18+
const client = new Client(`http://localhost:${server.address().port}`)
19+
t.teardown(client.close.bind(client))
20+
21+
let done
22+
client.on('disconnect', () => {
23+
if (!done) {
24+
t.fail()
25+
}
26+
})
27+
28+
client.request({
29+
path: '/',
30+
method: 'HEAD',
31+
reset: false
32+
}, (err, res) => {
33+
t.error(err)
34+
res.body.resume()
35+
})
36+
37+
client.request({
38+
path: '/',
39+
method: 'HEAD',
40+
reset: false
41+
}, (err, res) => {
42+
t.error(err)
43+
res.body.resume()
44+
})
45+
46+
client.request({
47+
path: '/',
48+
method: 'GET',
49+
reset: false
50+
}, (err, res) => {
51+
t.error(err)
52+
let str = ''
53+
res.body.on('data', (data) => {
54+
str += data
55+
}).on('end', () => {
56+
t.same(str, expected)
57+
done = true
58+
t.end()
59+
})
60+
})
61+
})
62+
})

0 commit comments

Comments
 (0)