Skip to content

Commit

Permalink
http: disable whitespace for special headers
Browse files Browse the repository at this point in the history
  • Loading branch information
kumarak authored and mcollina committed Oct 19, 2021
1 parent a835370 commit 15ecd20
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 1 deletion.
22 changes: 21 additions & 1 deletion src/llhttp/http.ts
Expand Up @@ -45,6 +45,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 @@ -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'));
Expand Down
46 changes: 46 additions & 0 deletions test/request/connection.md
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
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

0 comments on commit 15ecd20

Please sign in to comment.