Skip to content

Commit ba565a3

Browse files
addaleaxTrott
authored andcommitted
http: improve parser error messages
Include the library-provided reason in the Error’s `message`. Fixes: #28468 PR-URL: #28487 Reviewed-By: Anto Aravinth <anto.aravinth.cse@gmail.com> Reviewed-By: Daniel Bevenius <daniel.bevenius@gmail.com> Reviewed-By: Fedor Indutny <fedor.indutny@gmail.com> Reviewed-By: Rich Trott <rtrott@gmail.com> Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
1 parent fd23c12 commit ba565a3

8 files changed

+49
-6
lines changed

lib/_http_client.js

+2
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ const {
3333
httpSocketSetup,
3434
parsers,
3535
HTTPParser,
36+
prepareError,
3637
} = require('_http_common');
3738
const { OutgoingMessage } = require('_http_outgoing');
3839
const Agent = require('_http_agent');
@@ -451,6 +452,7 @@ function socketOnData(d) {
451452

452453
const ret = parser.execute(d);
453454
if (ret instanceof Error) {
455+
prepareError(ret, parser, d);
454456
debug('parse error', ret);
455457
freeParser(parser, req, socket);
456458
socket.destroy();

lib/_http_common.js

+8-1
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,12 @@ function cleanParser(parser) {
239239
parser._consumed = false;
240240
}
241241

242+
function prepareError(err, parser, rawPacket) {
243+
err.rawPacket = rawPacket || parser.getCurrentBuffer();
244+
if (typeof err.reason === 'string')
245+
err.message = `Parse Error: ${err.reason}`;
246+
}
247+
242248
module.exports = {
243249
_checkInvalidHeaderChar: checkInvalidHeaderChar,
244250
_checkIsHttpToken: checkIsHttpToken,
@@ -251,5 +257,6 @@ module.exports = {
251257
methods,
252258
parsers,
253259
kIncomingMessage,
254-
HTTPParser
260+
HTTPParser,
261+
prepareError,
255262
};

lib/_http_server.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ const {
3535
httpSocketSetup,
3636
kIncomingMessage,
3737
HTTPParser,
38-
_checkInvalidHeaderChar: checkInvalidHeaderChar
38+
_checkInvalidHeaderChar: checkInvalidHeaderChar,
39+
prepareError,
3940
} = require('_http_common');
4041
const { OutgoingMessage } = require('_http_outgoing');
4142
const { outHeadersKey, ondrain, nowDate } = require('internal/http');
@@ -550,6 +551,7 @@ function onParserExecuteCommon(server, socket, parser, state, ret, d) {
550551
resetSocketTimeout(server, socket, state);
551552

552553
if (ret instanceof Error) {
554+
prepareError(ret, parser, d);
553555
ret.rawPacket = d || parser.getCurrentBuffer();
554556
debug('parse error', ret);
555557
socketOnError.call(socket, ret);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
'use strict';
2+
const common = require('../common');
3+
const assert = require('assert');
4+
const http = require('http');
5+
const net = require('net');
6+
7+
const response = Buffer.from('HTTP/1.1 200 OK\r\n' +
8+
'Content-Length: 6\r\n' +
9+
'Transfer-Encoding: Chunked\r\n' +
10+
'\r\n' +
11+
'6\r\nfoobar' +
12+
'0\r\n');
13+
14+
const server = net.createServer(common.mustCall((conn) => {
15+
conn.write(response);
16+
}));
17+
18+
server.listen(0, common.mustCall(() => {
19+
const req = http.get(`http://localhost:${server.address().port}/`);
20+
req.end();
21+
req.on('error', common.mustCall((err) => {
22+
const reason = 'Content-Length can\'t be present with chunked encoding';
23+
assert.strictEqual(err.message, `Parse Error: ${reason}`);
24+
assert(err.bytesParsed < response.length);
25+
assert(err.bytesParsed >= response.indexOf('Transfer-Encoding'));
26+
assert.strictEqual(err.code, 'HPE_UNEXPECTED_CONTENT_LENGTH');
27+
assert.strictEqual(err.reason, reason);
28+
assert.deepStrictEqual(err.rawPacket, response);
29+
30+
server.close();
31+
}));
32+
}));

test/parallel/test-http-client-parse-error.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ server.listen(0, common.mustCall(() => {
4444
}).on('error', common.mustCall((e) => {
4545
common.expectsError({
4646
code: 'HPE_INVALID_CONSTANT',
47-
message: 'Parse Error'
47+
message: 'Parse Error: Expected HTTP/'
4848
})(e);
4949
countdown.dec();
5050
}));

test/parallel/test-http-header-overflow.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ const server = createServer();
1919
server.on('connection', mustCall((socket) => {
2020
socket.on('error', expectsError({
2121
type: Error,
22-
message: 'Parse Error',
22+
message: 'Parse Error: Header overflow',
2323
code: 'HPE_HEADER_OVERFLOW',
2424
bytesParsed: maxHeaderSize + PAYLOAD_GET.length,
2525
rawPacket: Buffer.from(PAYLOAD)

test/parallel/test-http-server-client-error.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ server.on('clientError', common.mustCall(function(err, socket) {
1313
assert.strictEqual(err instanceof Error, true);
1414
assert.strictEqual(err.code, 'HPE_INVALID_METHOD');
1515
assert.strictEqual(err.bytesParsed, 1);
16-
assert.strictEqual(err.message, 'Parse Error');
16+
assert.strictEqual(err.message, 'Parse Error: Invalid method encountered');
1717
assert.strictEqual(err.rawPacket.toString(), 'Oopsie-doopsie\r\n');
1818

1919
socket.end('HTTP/1.1 400 Bad Request\r\n\r\n');

test/parallel/test-http-server-destroy-socket-on-client-error.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ const server = createServer();
1414
server.on('connection', mustCall((socket) => {
1515
socket.on('error', expectsError({
1616
type: Error,
17-
message: 'Parse Error',
17+
message: 'Parse Error: Invalid method encountered',
1818
code: 'HPE_INVALID_METHOD',
1919
bytesParsed: 0,
2020
rawPacket: Buffer.from('FOO /\r\n')

0 commit comments

Comments
 (0)