Skip to content

Commit

Permalink
Fix chunk extensions quoted-string value parsing
Browse files Browse the repository at this point in the history
According to [rfc9112](https://datatracker.ietf.org/doc/html/rfc9112) quoted string is defined
by [rfc9110](https://datatracker.ietf.org/doc/html/rfc9110)

```
quoted-string = <quoted-string, see [HTTP], Section 5.6.4>
```

The definition of quoted-string also uses a notion of quoted-pair:

```
quoted-pair    = "\" ( HTAB / SP / VCHAR / obs-text )
```

This change makes the parsing of quoted-string aware of quoted-pairs and makes it possile
to handle valid quoted strings.

References:

* https://datatracker.ietf.org/doc/html/rfc9112#name-syntax-notation
* https://datatracker.ietf.org/doc/html/rfc9112#name-chunk-extensions
* https://datatracker.ietf.org/doc/html/rfc9110#section-5.6.4
  • Loading branch information
ngrodzitski committed Oct 1, 2023
1 parent e059b1b commit 8328f35
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 25 deletions.
11 changes: 11 additions & 0 deletions src/llhttp/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,17 @@ for (let i = 0x21; i <= 0xff; i++) {
}
}

export const HTAB_SP_VCHAR_OBS_TEXT: CharList = [ '\t', ' ' ];

// VCHAR: https://tools.ietf.org/html/rfc5234#appendix-B.1
for (let i = 0x21; i <= 0x7E; i++) {
HTAB_SP_VCHAR_OBS_TEXT.push(i);
}
// OBS_TEXT: https://datatracker.ietf.org/doc/html/rfc9110#name-collected-abnf
for (let i = 0x80; i <= 0xff; i++) {
HTAB_SP_VCHAR_OBS_TEXT.push(i);
}

export const MAJOR = NUM_MAP;
export const MINOR = MAJOR;

Expand Down
10 changes: 9 additions & 1 deletion src/llhttp/http.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import Node = source.node.Node;
import {
CharList,
CONNECTION_TOKEN_CHARS, ERROR, FINISH, FLAGS, H_METHOD_MAP, HEADER_CHARS,
HEADER_STATE, HEX_MAP,
HEADER_STATE, HEX_MAP, HTAB_SP_VCHAR_OBS_TEXT,
LENIENT_FLAGS,
MAJOR, METHOD_MAP, METHODS, METHODS_HTTP, METHODS_ICE, METHODS_RTSP,
MINOR, NUM_MAP, QUOTED_STRING, SPECIAL_HEADERS,
Expand Down Expand Up @@ -94,6 +94,7 @@ const NODES: ReadonlyArray<string> = [
'chunk_extension_name',
'chunk_extension_value',
'chunk_extension_quoted_value',
'chunk_extension_quoted_value_quoted_pair',
'chunk_extension_quoted_value_done',
'chunk_data',
'chunk_data_almost_done',
Expand Down Expand Up @@ -989,10 +990,17 @@ export class HTTP {
.match('"', this.span.chunkExtensionValue.end(
onChunkExtensionValueCompleted(n('chunk_extension_quoted_value_done')),
))
.match('\\', n('chunk_extension_quoted_value_quoted_pair'))
.otherwise(this.span.chunkExtensionValue.end().skipTo(
p.error(ERROR.STRICT, 'Invalid character in chunk extensions quoted value'),
));

n('chunk_extension_quoted_value_quoted_pair')
.match(HTAB_SP_VCHAR_OBS_TEXT, n('chunk_extension_quoted_value'))
.otherwise(this.span.chunkExtensionValue.end().skipTo(
p.error(ERROR.STRICT, 'Invalid quoted-pair in chunk extensions quoted value'),
));

n('chunk_extension_quoted_value_done')
.match(';', n('chunk_extensions'))
.match('\r', n('chunk_size_almost_done'))
Expand Down
48 changes: 24 additions & 24 deletions test/request/transfer-encoding.md
Original file line number Diff line number Diff line change
Expand Up @@ -352,7 +352,7 @@ off=98 error code=2 reason="Invalid character in chunk extensions"
POST /chunked_w_unicorns_after_length HTTP/1.1
Transfer-Encoding: chunked
5;ilovew3="I love; extensions";somuchlove="aretheseparametersfor";blah;foo=bar
5;ilovew3="I \"love\"; \\extensions\\";somuchlove="aretheseparametersfor";blah;foo=bar
hello
6;blahblah;blah
world
Expand All @@ -375,29 +375,29 @@ off=76 header_value complete
off=78 headers complete method=3 v=1/1 flags=208 content_length=0
off=80 len=7 span[chunk_extension_name]="ilovew3"
off=88 chunk_extension_name complete
off=88 len=20 span[chunk_extension_value]=""I love; extensions""
off=108 chunk_extension_value complete
off=109 len=10 span[chunk_extension_name]="somuchlove"
off=120 chunk_extension_name complete
off=120 len=23 span[chunk_extension_value]=""aretheseparametersfor""
off=143 chunk_extension_value complete
off=144 len=4 span[chunk_extension_name]="blah"
off=149 chunk_extension_name complete
off=149 len=3 span[chunk_extension_name]="foo"
off=153 chunk_extension_name complete
off=153 len=3 span[chunk_extension_value]="bar"
off=157 chunk_extension_value complete
off=158 chunk header len=5
off=158 len=5 span[body]="hello"
off=165 chunk complete
off=167 len=8 span[chunk_extension_name]="blahblah"
off=176 chunk_extension_name complete
off=176 len=4 span[chunk_extension_name]="blah"
off=181 chunk_extension_name complete
off=182 chunk header len=6
off=182 len=6 span[body]=" world"
off=190 chunk complete
off=193 chunk header len=0
off=88 len=28 span[chunk_extension_value]=""I \"love\"; \\extensions\\""
off=116 chunk_extension_value complete
off=117 len=10 span[chunk_extension_name]="somuchlove"
off=128 chunk_extension_name complete
off=128 len=23 span[chunk_extension_value]=""aretheseparametersfor""
off=151 chunk_extension_value complete
off=152 len=4 span[chunk_extension_name]="blah"
off=157 chunk_extension_name complete
off=157 len=3 span[chunk_extension_name]="foo"
off=161 chunk_extension_name complete
off=161 len=3 span[chunk_extension_value]="bar"
off=165 chunk_extension_value complete
off=166 chunk header len=5
off=166 len=5 span[body]="hello"
off=173 chunk complete
off=175 len=8 span[chunk_extension_name]="blahblah"
off=184 chunk_extension_name complete
off=184 len=4 span[chunk_extension_name]="blah"
off=189 chunk_extension_name complete
off=190 chunk header len=6
off=190 len=6 span[body]=" world"
off=198 chunk complete
off=201 chunk header len=0
```


Expand Down

0 comments on commit 8328f35

Please sign in to comment.