Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
http: disable whitespace for special headers
  • Loading branch information
kumarak authored and ShogunPanda committed Sep 1, 2022
commit 4b2a04b0eb3cf6d6f2536a3570c91153464172d2
22 changes: 21 additions & 1 deletion src/llhttp/http.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ const NODES: ReadonlyArray<string> = [
'header_field_start',
'header_field',
'header_field_colon',
'header_field_colon_discard_ws',
'header_field_general',
'header_field_general_otherwise',
'header_value_discard_ws',
Expand Down Expand Up @@ -372,13 +373,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'));
Expand Down
46 changes: 46 additions & 0 deletions test/request/connection.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

<!-- meta={"type": "request"} -->
```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)

<!-- meta={"type": "request-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
Expand Down
48 changes: 48 additions & 0 deletions test/request/content-length.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

<!-- meta={"type": "request"} -->
```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)

<!-- meta={"type": "request-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

<!-- meta={"type": "request"} -->
Expand Down