Skip to content

Commit

Permalink
fix: Do not allow OBS fold in headers by default.
Browse files Browse the repository at this point in the history
Port nodejs#350 to 2.1.x.
  • Loading branch information
richardlau committed Apr 11, 2024
1 parent ccef2c7 commit e566d8e
Show file tree
Hide file tree
Showing 9 changed files with 93 additions and 15 deletions.
13 changes: 8 additions & 5 deletions src/llhttp/http.ts
Original file line number Diff line number Diff line change
Expand Up @@ -598,11 +598,14 @@ export class HTTP {
'Missing expected LF after header value'));

n('header_value_lws')
.peek([ ' ', '\t' ],
this.load('header_state', {
[HEADER_STATE.TRANSFER_ENCODING_CHUNKED]:
this.resetHeaderState(span.headerValue.start(n('header_value_start'))),
}, span.headerValue.start(n('header_value_start'))))
.peek(
[ ' ', '\t' ],
this.testFlags(FLAGS.LENIENT, {
1: this.load('header_state', {
[HEADER_STATE.TRANSFER_ENCODING_CHUNKED]:
this.resetHeaderState(span.headerValue.start(n('header_value_start'))),
}, span.headerValue.start(n('header_value_start'))),
}, p.error(ERROR.INVALID_HEADER_TOKEN, 'Unexpected whitespace after header value')))
.otherwise(this.setHeaderFlags('header_field_start'));

const checkTrailing = this.testFlags(FLAGS.TRAILING, {
Expand Down
6 changes: 3 additions & 3 deletions test/fixtures/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import * as path from 'path';

import * as llhttp from '../../src/llhttp';

export type TestType = 'request' | 'response' | 'request-lenient' |
'request-finish' | 'response-finish' | 'none' | 'url';
export type TestType = 'request' | 'response' | 'request-lenient' | 'request-lenient-headers' |
'request-finish' | 'response-lenient-headers' | 'response-finish' | 'none' | 'url';

export { FixtureResult };

Expand Down Expand Up @@ -58,7 +58,7 @@ export async function build(
}

const extra = options.extra === undefined ? [] : options.extra.slice();
if (ty === 'request' || ty === 'response' || ty === 'request-lenient') {
if (ty === 'request' || ty === 'response' || ty === 'request-lenient-headers') {
extra.push(
`-DLLPARSE__TEST_INIT=llhttp__test_init_${ty.replace(/-/g, '_')}`);
} else if (ty === 'request-finish' || ty === 'response-finish') {
Expand Down
8 changes: 8 additions & 0 deletions test/md-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,17 +80,21 @@ const http: IFixtureMap = {
'request': buildMode('loose', 'request'),
'request-finish': buildMode('loose', 'request-finish'),
'request-lenient': buildMode('loose', 'request-lenient'),
'request-lenient-headers': buildMode('loose', 'request-lenient-headers'),
'response': buildMode('loose', 'response'),
'response-finish': buildMode('loose', 'response-finish'),
'response-lenient-headers': buildMode( 'loose', 'response-lenient-headers'),
'url': buildMode('loose', 'url'),
},
strict: {
'none': buildMode('strict', 'none'),
'request': buildMode('strict', 'request'),
'request-finish': buildMode('strict', 'request-finish'),
'request-lenient': buildMode('strict', 'request-lenient'),
'request-lenient-headers': buildMode('strict', 'request-lenient-headers'),
'response': buildMode('strict', 'response'),
'response-finish': buildMode('strict', 'response-finish'),
'response-lenient-headers': buildMode('strict', 'response-lenient-headers'),
'url': buildMode('strict', 'url'),
},
};
Expand Down Expand Up @@ -149,10 +153,14 @@ function run(name: string): void {
types = [ 'request' ];
} else if (meta.type === 'request-lenient') {
types = [ 'request-lenient' ];
} else if (meta.type === 'request-lenient-headers') {
types = [ 'request-lenient-headers' ];
} else if (meta.type === 'response-only') {
types = [ 'response' ];
} else if (meta.type === 'request-finish') {
types = [ 'request-finish' ];
} else if (meta.type === 'response-lenient-headers') {
types = [ 'response-lenient-headers' ];
} else if (meta.type === 'response-finish') {
types = [ 'response-finish' ];
} else {
Expand Down
4 changes: 2 additions & 2 deletions test/request/connection.md
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ off=75 message complete

### Multiple tokens with folding

<!-- meta={"type": "request"} -->
<!-- meta={"type": "request-lenient-headers"} -->
```http
GET /demo HTTP/1.1
Host: example.com
Expand Down Expand Up @@ -326,7 +326,7 @@ off=75 error code=22 reason="Pause on CONNECT/Upgrade"

### Multiple tokens with folding, LWS, and CRLF

<!-- meta={"type": "request"} -->
<!-- meta={"type": "request-lenient-headers"} -->
```http
GET /demo HTTP/1.1
Connection: keep-alive, \r\n upgrade
Expand Down
68 changes: 67 additions & 1 deletion test/request/invalid.md
Original file line number Diff line number Diff line change
Expand Up @@ -222,4 +222,70 @@ off=22 len=9 span[header_value]="localhost"
off=33 len=5 span[header_field]="Dummy"
off=40 len=1 span[header_value]="x"
off=41 error code=10 reason="Invalid header value char"
```
```

### Spaces before headers

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

```http
POST /hello HTTP/1.1
Host: localhost
Foo: bar
Content-Length: 38
GET /bye HTTP/1.1
Host: localhost
```

```log
off=0 message begin
off=5 len=6 span[url]="/hello"
off=12 url complete
off=22 len=4 span[header_field]="Host"
off=27 header_field complete
off=28 len=9 span[header_value]="localhost"
off=39 header_value complete
off=39 len=3 span[header_field]="Foo"
off=43 header_field complete
off=44 len=3 span[header_value]="bar"
off=49 error code=10 reason="Unexpected whitespace after header value"
```

### Spaces before headers (lenient)

<!-- meta={ "type": "request-lenient-headers" } -->

```http
POST /hello HTTP/1.1
Host: localhost
Foo: bar
Content-Length: 38
GET /bye HTTP/1.1
Host: localhost
```

```log
off=0 message begin
off=5 len=6 span[url]="/hello"
off=12 url complete
off=22 len=4 span[header_field]="Host"
off=27 header_field complete
off=28 len=9 span[header_value]="localhost"
off=39 header_value complete
off=39 len=3 span[header_field]="Foo"
off=43 header_field complete
off=44 len=3 span[header_value]="bar"
off=49 len=19 span[header_value]=" Content-Length: 38"
off=70 header_value complete
off=72 headers complete method=3 v=1/1 flags=0 content_length=0
off=72 message complete
off=72 message begin
off=76 len=4 span[url]="/bye"
off=81 url complete
off=91 len=4 span[header_field]="Host"
off=96 header_field complete
off=97 len=9 span[header_value]="localhost"
off=108 header_value complete
off=110 headers complete method=1 v=1/1 flags=0 content_length=0
off=110 message complete
```
2 changes: 1 addition & 1 deletion test/request/sample.md
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,7 @@ off=61 message complete

See nodejs/test/parallel/test-http-headers-obstext.js

<!-- meta={"type": "request"} -->
<!-- meta={"type": "request-lenient-headers"} -->
```http
GET / HTTP/1.1
X-SSL-Nonsense: -----BEGIN CERTIFICATE-----
Expand Down
2 changes: 1 addition & 1 deletion test/request/transfer-encoding.md
Original file line number Diff line number Diff line change
Expand Up @@ -518,7 +518,7 @@ off=50 error code=12 reason="Invalid character in chunk size"

## Invalid OBS fold after chunked value

<!-- meta={"type": "request", "mode": "strict"} -->
<!-- meta={"type": "request-lenient-headers", "mode": "strict"} -->
```http
PUT /url HTTP/1.1
Transfer-Encoding: chunked
Expand Down
2 changes: 1 addition & 1 deletion test/response/transfer-encoding.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ off=78 len=1 span[body]=lf

## Invalid OBS fold after chunked value

<!-- meta={"type": "response" } -->
<!-- meta={"type": "response-lenient-headers"} -->
```http
HTTP/1.1 200 OK
Transfer-Encoding: chunked
Expand Down
3 changes: 2 additions & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
"outDir": "./lib",
"declaration": true,
"pretty": true,
"sourceMap": true
"sourceMap": true,
"skipLibCheck": true
},
"include": [
"src/**/*.ts"
Expand Down

0 comments on commit e566d8e

Please sign in to comment.