From a835370c29ce7c793bd2cb40cacf626d18669371 Mon Sep 17 00:00:00 2001 From: Robert Nagy Date: Tue, 13 Jul 2021 13:43:48 +0200 Subject: [PATCH 1/3] http: verify chunk parameters --- src/llhttp/http.ts | 5 +++-- test/request/transfer-encoding.md | 22 ++++++++++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/llhttp/http.ts b/src/llhttp/http.ts index f86d4fbf..092a8e04 100644 --- a/src/llhttp/http.ts +++ b/src/llhttp/http.ts @@ -683,10 +683,11 @@ export class HTTP { .otherwise(p.error(ERROR.INVALID_CHUNK_SIZE, 'Invalid character in chunk size')); - // just ignore this. n('chunk_parameters') .match('\r', n('chunk_size_almost_done')) - .skipTo(n('chunk_parameters')); + .match(HEADER_CHARS, n('chunk_parameters')) + .otherwise(p.error(ERROR.STRICT, + 'Invalid character in chunk parameters')); if (this.mode === 'strict') { n('chunk_size_almost_done') diff --git a/test/request/transfer-encoding.md b/test/request/transfer-encoding.md index fdf89a12..31f970ea 100644 --- a/test/request/transfer-encoding.md +++ b/test/request/transfer-encoding.md @@ -386,3 +386,25 @@ off=52 len=3 span[body]="foo" off=57 chunk complete off=57 error code=12 reason="Invalid character in chunk size" ``` + +## Validate chunk parameters + + +```http +PUT /url HTTP/1.1 +Transfer-Encoding: chunked + +3 \n \r\n\ +foo + + +``` + +```log +off=0 message begin +off=4 len=4 span[url]="/url" +off=19 len=17 span[header_field]="Transfer-Encoding" +off=38 len=7 span[header_value]="chunked" +off=49 headers complete method=4 v=1/1 flags=208 content_length=0 +off=51 error code=2 reason="Invalid character in chunk parameters" +``` From 15ecd206262481bb87f2f9cfbf377278f5513787 Mon Sep 17 00:00:00 2001 From: Akshay K Date: Thu, 1 Jul 2021 01:33:15 -0400 Subject: [PATCH 2/3] http: disable whitespace for special headers --- src/llhttp/http.ts | 22 +++++++++++++++- test/request/connection.md | 46 ++++++++++++++++++++++++++++++++ test/request/content-length.md | 48 ++++++++++++++++++++++++++++++++++ 3 files changed, 115 insertions(+), 1 deletion(-) diff --git a/src/llhttp/http.ts b/src/llhttp/http.ts index 092a8e04..db976514 100644 --- a/src/llhttp/http.ts +++ b/src/llhttp/http.ts @@ -45,6 +45,7 @@ const NODES: ReadonlyArray = [ 'header_field_start', 'header_field', 'header_field_colon', + 'header_field_colon_discard_ws', 'header_field_general', 'header_field_general_otherwise', 'header_value_discard_ws', @@ -361,13 +362,32 @@ export class HTTP { .select(SPECIAL_HEADERS, this.store('header_state', 'header_field_colon')) .otherwise(this.resetHeaderState('header_field_general')); + const onInvalidHeaderFieldChar = + p.error(ERROR.INVALID_HEADER_TOKEN, 'Invalid header field char'); + + const checkLenientFlagsOnColon = + this.testFlags(FLAGS.LENIENT, { + 1: n('header_field_colon_discard_ws'), + }, span.headerField.end().skipTo(onInvalidHeaderFieldChar)); + n('header_field_colon') - .match(' ', n('header_field_colon')) + // https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.4 + // Whitespace character is not allowed between the header field-name + // and colon. If the next token matches whitespace then throw an error. + // + // Add a check for the lenient flag. If the lenient flag is set, the + // whitespace token is allowed to support legacy code not following + // http specs. + .peek(' ', checkLenientFlagsOnColon) .peek(':', span.headerField.end().skipTo(n('header_value_discard_ws'))) // Fallback to general header, there're additional characters: // `Connection-Duration` instead of `Connection` and so on. .otherwise(this.resetHeaderState('header_field_general')); + n('header_field_colon_discard_ws') + .match(' ', n('header_field_colon_discard_ws')) + .otherwise(n('header_field_colon')); + n('header_field_general') .match(this.TOKEN, n('header_field_general')) .otherwise(n('header_field_general_otherwise')); diff --git a/test/request/connection.md b/test/request/connection.md index f6e4007e..f2b69c7a 100644 --- a/test/request/connection.md +++ b/test/request/connection.md @@ -348,6 +348,52 @@ off=78 message complete off=78 error code=22 reason="Pause on CONNECT/Upgrade" ``` +### Invalid whitespace token with `Connection` header field + + +```http +PUT /url HTTP/1.1 +Connection : upgrade +Content-Length: 4 +Upgrade: ws + +abcdefgh +``` + +```log +off=0 message begin +off=4 len=4 span[url]="/url" +off=19 len=10 span[header_field]="Connection" +off=30 error code=10 reason="Invalid header field char" +``` + +### Invalid whitespace token with `Connection` header field (lenient) + + +```http +PUT /url HTTP/1.1 +Connection : upgrade +Content-Length: 4 +Upgrade: ws + +abcdefgh +``` + +```log +off=0 message begin +off=4 len=4 span[url]="/url" +off=19 len=11 span[header_field]="Connection " +off=32 len=7 span[header_value]="upgrade" +off=41 len=14 span[header_field]="Content-Length" +off=57 len=1 span[header_value]="4" +off=60 len=7 span[header_field]="Upgrade" +off=69 len=2 span[header_value]="ws" +off=75 headers complete method=4 v=1/1 flags=134 content_length=4 +off=75 len=4 span[body]="abcd" +off=79 message complete +off=79 error code=22 reason="Pause on CONNECT/Upgrade" +``` + ## `upgrade` ### Setting a flag and pausing diff --git a/test/request/content-length.md b/test/request/content-length.md index 80c2f646..a4cad060 100644 --- a/test/request/content-length.md +++ b/test/request/content-length.md @@ -151,6 +151,54 @@ off=57 len=8 span[header_value]="identity" off=69 headers complete method=4 v=1/1 flags=320 content_length=1 ``` +## Invalid whitespace token with `Content-Length` header field + + +```http +PUT /url HTTP/1.1 +Connection: upgrade +Content-Length : 4 +Upgrade: ws + +abcdefgh +``` + +```log +off=0 message begin +off=4 len=4 span[url]="/url" +off=19 len=10 span[header_field]="Connection" +off=31 len=7 span[header_value]="upgrade" +off=40 len=14 span[header_field]="Content-Length" +off=55 error code=10 reason="Invalid header field char" +``` + +## Invalid whitespace token with `Content-Length` header field (lenient) + + +```http +PUT /url HTTP/1.1 +Connection: upgrade +Content-Length : 4 +Upgrade: ws + +abcdefgh +``` + +```log +off=0 message begin +off=4 len=4 span[url]="/url" +off=19 len=10 span[header_field]="Connection" +off=31 len=7 span[header_value]="upgrade" +off=40 len=15 span[header_field]="Content-Length " +off=57 len=1 span[header_value]="4" +off=60 len=7 span[header_field]="Upgrade" +off=69 len=2 span[header_value]="ws" +off=75 headers complete method=4 v=1/1 flags=134 content_length=4 +off=75 len=4 span[body]="abcd" +off=79 message complete +off=79 error code=22 reason="Pause on CONNECT/Upgrade" +``` + ## Funky `Content-Length` with body From d6ea943d8d1c5092f4bf6e10a6a32cfb2dbeaae3 Mon Sep 17 00:00:00 2001 From: Matteo Collina Date: Tue, 12 Oct 2021 19:46:02 +0200 Subject: [PATCH 3/3] Bumped v2.1.4 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 787eff60..d041f128 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "llhttp", - "version": "2.1.3", + "version": "2.1.4", "description": "HTTP parser in LLVM IR", "main": "lib/llhttp.js", "types": "lib/llhttp.d.ts",