Skip to content

Commit 6ed8467

Browse files
committed
fix: Do not allow OBS fold in headers by default.
Port nodejs#350 to 2.1.x.
1 parent ccef2c7 commit 6ed8467

9 files changed

Lines changed: 89 additions & 14 deletions

File tree

src/llhttp/http.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -598,11 +598,14 @@ export class HTTP {
598598
'Missing expected LF after header value'));
599599

600600
n('header_value_lws')
601-
.peek([ ' ', '\t' ],
602-
this.load('header_state', {
603-
[HEADER_STATE.TRANSFER_ENCODING_CHUNKED]:
604-
this.resetHeaderState(span.headerValue.start(n('header_value_start'))),
605-
}, span.headerValue.start(n('header_value_start'))))
601+
.peek(
602+
[ ' ', '\t' ],
603+
this.testFlags(FLAGS.LENIENT, {
604+
1: this.load('header_state', {
605+
[HEADER_STATE.TRANSFER_ENCODING_CHUNKED]:
606+
this.resetHeaderState(span.headerValue.start(n('header_value_start'))),
607+
}, span.headerValue.start(n('header_value_start'))),
608+
}, p.error(ERROR.INVALID_HEADER_TOKEN, 'Unexpected whitespace after header value')))
606609
.otherwise(this.setHeaderFlags('header_field_start'));
607610

608611
const checkTrailing = this.testFlags(FLAGS.TRAILING, {

test/fixtures/index.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import * as path from 'path';
99
import * as llhttp from '../../src/llhttp';
1010

1111
export type TestType = 'request' | 'response' | 'request-lenient' |
12-
'request-finish' | 'response-finish' | 'none' | 'url';
12+
'request-finish' | 'response-lenient-headers' | 'response-finish' | 'none' | 'url';
1313

1414
export { FixtureResult };
1515

@@ -58,7 +58,8 @@ export async function build(
5858
}
5959

6060
const extra = options.extra === undefined ? [] : options.extra.slice();
61-
if (ty === 'request' || ty === 'response' || ty === 'request-lenient') {
61+
if (ty === 'request' || ty === 'response' || ty === 'request-lenient' ||
62+
ty === 'response-lenient-headers') {
6263
extra.push(
6364
`-DLLPARSE__TEST_INIT=llhttp__test_init_${ty.replace(/-/g, '_')}`);
6465
} else if (ty === 'request-finish' || ty === 'response-finish') {

test/md-test.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ const http: IFixtureMap = {
8282
'request-lenient': buildMode('loose', 'request-lenient'),
8383
'response': buildMode('loose', 'response'),
8484
'response-finish': buildMode('loose', 'response-finish'),
85+
'response-lenient-headers': buildMode( 'loose', 'response-lenient-headers'),
8586
'url': buildMode('loose', 'url'),
8687
},
8788
strict: {
@@ -91,6 +92,7 @@ const http: IFixtureMap = {
9192
'request-lenient': buildMode('strict', 'request-lenient'),
9293
'response': buildMode('strict', 'response'),
9394
'response-finish': buildMode('strict', 'response-finish'),
95+
'response-lenient-headers': buildMode('strict', 'response-lenient-headers'),
9496
'url': buildMode('strict', 'url'),
9597
},
9698
};
@@ -153,6 +155,8 @@ function run(name: string): void {
153155
types = [ 'response' ];
154156
} else if (meta.type === 'request-finish') {
155157
types = [ 'request-finish' ];
158+
} else if (meta.type === 'response-lenient-headers') {
159+
types = [ 'response-lenient-headers' ];
156160
} else if (meta.type === 'response-finish') {
157161
types = [ 'response-finish' ];
158162
} else {

test/request/connection.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ off=75 message complete
263263

264264
### Multiple tokens with folding
265265

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

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

329-
<!-- meta={"type": "request"} -->
329+
<!-- meta={"type": "request-lenient"} -->
330330
```http
331331
GET /demo HTTP/1.1
332332
Connection: keep-alive, \r\n upgrade

test/request/invalid.md

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,4 +222,70 @@ off=22 len=9 span[header_value]="localhost"
222222
off=33 len=5 span[header_field]="Dummy"
223223
off=40 len=1 span[header_value]="x"
224224
off=41 error code=10 reason="Invalid header value char"
225-
```
225+
```
226+
227+
### Spaces before headers
228+
229+
<!-- meta={ "type": "request" } -->
230+
231+
```http
232+
POST /hello HTTP/1.1
233+
Host: localhost
234+
Foo: bar
235+
Content-Length: 38
236+
GET /bye HTTP/1.1
237+
Host: localhost
238+
```
239+
240+
```log
241+
off=0 message begin
242+
off=5 len=6 span[url]="/hello"
243+
off=12 url complete
244+
off=22 len=4 span[header_field]="Host"
245+
off=27 header_field complete
246+
off=28 len=9 span[header_value]="localhost"
247+
off=39 header_value complete
248+
off=39 len=3 span[header_field]="Foo"
249+
off=43 header_field complete
250+
off=44 len=3 span[header_value]="bar"
251+
off=49 error code=10 reason="Unexpected whitespace after header value"
252+
```
253+
254+
### Spaces before headers (lenient)
255+
256+
<!-- meta={ "type": "request-lenient" } -->
257+
258+
```http
259+
POST /hello HTTP/1.1
260+
Host: localhost
261+
Foo: bar
262+
Content-Length: 38
263+
GET /bye HTTP/1.1
264+
Host: localhost
265+
```
266+
267+
```log
268+
off=0 message begin
269+
off=5 len=6 span[url]="/hello"
270+
off=12 url complete
271+
off=22 len=4 span[header_field]="Host"
272+
off=27 header_field complete
273+
off=28 len=9 span[header_value]="localhost"
274+
off=39 header_value complete
275+
off=39 len=3 span[header_field]="Foo"
276+
off=43 header_field complete
277+
off=44 len=3 span[header_value]="bar"
278+
off=49 len=19 span[header_value]=" Content-Length: 38"
279+
off=70 header_value complete
280+
off=72 headers complete method=3 v=1/1 flags=0 content_length=0
281+
off=72 message complete
282+
off=72 message begin
283+
off=76 len=4 span[url]="/bye"
284+
off=81 url complete
285+
off=91 len=4 span[header_field]="Host"
286+
off=96 header_field complete
287+
off=97 len=9 span[header_value]="localhost"
288+
off=108 header_value complete
289+
off=110 headers complete method=1 v=1/1 flags=0 content_length=0
290+
off=110 message complete
291+
```

test/request/sample.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,7 @@ off=61 message complete
369369

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

372-
<!-- meta={"type": "request"} -->
372+
<!-- meta={"type": "request-lenient"} -->
373373
```http
374374
GET / HTTP/1.1
375375
X-SSL-Nonsense: -----BEGIN CERTIFICATE-----

test/request/transfer-encoding.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -518,7 +518,7 @@ off=50 error code=12 reason="Invalid character in chunk size"
518518

519519
## Invalid OBS fold after chunked value
520520

521-
<!-- meta={"type": "request", "mode": "strict"} -->
521+
<!-- meta={"type": "request-lenient", "mode": "strict"} -->
522522
```http
523523
PUT /url HTTP/1.1
524524
Transfer-Encoding: chunked

test/response/transfer-encoding.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ off=78 len=1 span[body]=lf
118118

119119
## Invalid OBS fold after chunked value
120120

121-
<!-- meta={"type": "response" } -->
121+
<!-- meta={"type": "response-lenient-headers"} -->
122122
```http
123123
HTTP/1.1 200 OK
124124
Transfer-Encoding: chunked

tsconfig.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
"outDir": "./lib",
88
"declaration": true,
99
"pretty": true,
10-
"sourceMap": true
10+
"sourceMap": true,
11+
"skipLibCheck": true
1112
},
1213
"include": [
1314
"src/**/*.ts"

0 commit comments

Comments
 (0)