Skip to content

Commit

Permalink
http: improve parser error messages
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
addaleax authored and targos committed Jul 20, 2019
1 parent 0777e09 commit 38f8cd5
Show file tree
Hide file tree
Showing 8 changed files with 49 additions and 6 deletions.
2 changes: 2 additions & 0 deletions lib/_http_client.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const {
httpSocketSetup,
parsers,
HTTPParser,
prepareError,
} = require('_http_common');
const { OutgoingMessage } = require('_http_outgoing');
const Agent = require('_http_agent');
Expand Down Expand Up @@ -451,6 +452,7 @@ function socketOnData(d) {

const ret = parser.execute(d);
if (ret instanceof Error) {
prepareError(ret, parser, d);
debug('parse error', ret);
freeParser(parser, req, socket);
socket.destroy();
Expand Down
9 changes: 8 additions & 1 deletion lib/_http_common.js
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,12 @@ function cleanParser(parser) {
parser._consumed = false;
}

function prepareError(err, parser, rawPacket) {
err.rawPacket = rawPacket || parser.getCurrentBuffer();
if (typeof err.reason === 'string')
err.message = `Parse Error: ${err.reason}`;
}

module.exports = {
_checkInvalidHeaderChar: checkInvalidHeaderChar,
_checkIsHttpToken: checkIsHttpToken,
Expand All @@ -251,5 +257,6 @@ module.exports = {
methods,
parsers,
kIncomingMessage,
HTTPParser
HTTPParser,
prepareError,
};
4 changes: 3 additions & 1 deletion lib/_http_server.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ const {
httpSocketSetup,
kIncomingMessage,
HTTPParser,
_checkInvalidHeaderChar: checkInvalidHeaderChar
_checkInvalidHeaderChar: checkInvalidHeaderChar,
prepareError,
} = require('_http_common');
const { OutgoingMessage } = require('_http_outgoing');
const { outHeadersKey, ondrain, nowDate } = require('internal/http');
Expand Down Expand Up @@ -553,6 +554,7 @@ function onParserExecuteCommon(server, socket, parser, state, ret, d) {
resetSocketTimeout(server, socket, state);

if (ret instanceof Error) {
prepareError(ret, parser, d);
ret.rawPacket = d || parser.getCurrentBuffer();
debug('parse error', ret);
socketOnError.call(socket, ret);
Expand Down
32 changes: 32 additions & 0 deletions test/parallel/test-http-client-error-rawbytes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
'use strict';
const common = require('../common');
const assert = require('assert');
const http = require('http');
const net = require('net');

const response = Buffer.from('HTTP/1.1 200 OK\r\n' +
'Content-Length: 6\r\n' +
'Transfer-Encoding: Chunked\r\n' +
'\r\n' +
'6\r\nfoobar' +
'0\r\n');

const server = net.createServer(common.mustCall((conn) => {
conn.write(response);
}));

server.listen(0, common.mustCall(() => {
const req = http.get(`http://localhost:${server.address().port}/`);
req.end();
req.on('error', common.mustCall((err) => {
const reason = 'Content-Length can\'t be present with chunked encoding';
assert.strictEqual(err.message, `Parse Error: ${reason}`);
assert(err.bytesParsed < response.length);
assert(err.bytesParsed >= response.indexOf('Transfer-Encoding'));
assert.strictEqual(err.code, 'HPE_UNEXPECTED_CONTENT_LENGTH');
assert.strictEqual(err.reason, reason);
assert.deepStrictEqual(err.rawPacket, response);

server.close();
}));
}));
2 changes: 1 addition & 1 deletion test/parallel/test-http-client-parse-error.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ server.listen(0, common.mustCall(() => {
}).on('error', common.mustCall((e) => {
common.expectsError({
code: 'HPE_INVALID_CONSTANT',
message: 'Parse Error'
message: 'Parse Error: Expected HTTP/'
})(e);
countdown.dec();
}));
Expand Down
2 changes: 1 addition & 1 deletion test/parallel/test-http-header-overflow.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const server = createServer();
server.on('connection', mustCall((socket) => {
socket.on('error', expectsError({
type: Error,
message: 'Parse Error',
message: 'Parse Error: Header overflow',
code: 'HPE_HEADER_OVERFLOW',
bytesParsed: maxHeaderSize + PAYLOAD_GET.length,
rawPacket: Buffer.from(PAYLOAD)
Expand Down
2 changes: 1 addition & 1 deletion test/parallel/test-http-server-client-error.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ server.on('clientError', common.mustCall(function(err, socket) {
assert.strictEqual(err instanceof Error, true);
assert.strictEqual(err.code, 'HPE_INVALID_METHOD');
assert.strictEqual(err.bytesParsed, 1);
assert.strictEqual(err.message, 'Parse Error');
assert.strictEqual(err.message, 'Parse Error: Invalid method encountered');
assert.strictEqual(err.rawPacket.toString(), 'Oopsie-doopsie\r\n');

socket.end('HTTP/1.1 400 Bad Request\r\n\r\n');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const server = createServer();
server.on('connection', mustCall((socket) => {
socket.on('error', expectsError({
type: Error,
message: 'Parse Error',
message: 'Parse Error: Invalid method encountered',
code: 'HPE_INVALID_METHOD',
bytesParsed: 0,
rawPacket: Buffer.from('FOO /\r\n')
Expand Down

0 comments on commit 38f8cd5

Please sign in to comment.