diff --git a/src/llhttp/http.ts b/src/llhttp/http.ts index e1e44d50..5dd9f631 100644 --- a/src/llhttp/http.ts +++ b/src/llhttp/http.ts @@ -84,6 +84,7 @@ const NODES: ReadonlyArray = [ 'chunk_size_almost_done', 'chunk_size_almost_done_lf', 'chunk_parameters', + 'chunk_parameters_ows', 'chunk_data', 'chunk_data_almost_done', 'chunk_data_almost_done_skip', @@ -101,6 +102,7 @@ const NODES: ReadonlyArray = [ interface ISpanMap { readonly body: source.Span; + readonly chunkParameters: source.Span; readonly headerField: source.Span; readonly headerValue: source.Span; readonly status: source.Span; @@ -157,6 +159,7 @@ export class HTTP { this.span = { body: p.span(p.code.span('llhttp__on_body')), + chunkParameters: p.span(p.code.span('llhttp__on_chunk_parameters')), headerField: p.span(p.code.span('llhttp__on_header_field')), headerValue: p.span(p.code.span('llhttp__on_header_value')), status: p.span(p.code.span('llhttp__on_status')), @@ -798,12 +801,16 @@ export class HTTP { n('chunk_size_otherwise') .match('\r', n('chunk_size_almost_done')) - .match([ ';', ' ' ], n('chunk_parameters')) + .match([ ';' ], n('chunk_parameters_ows')) .otherwise(p.error(ERROR.INVALID_CHUNK_SIZE, 'Invalid character in chunk size')); + n('chunk_parameters_ows') + .match(' ', n('chunk_parameters_ows')) + .otherwise(span.chunkParameters.start(n('chunk_parameters'))); + n('chunk_parameters') - .match('\r', n('chunk_size_almost_done')) + .peek('\r', span.chunkParameters.end().skipTo(n('chunk_size_almost_done'))) .match(HEADER_CHARS, n('chunk_parameters')) .otherwise(p.error(ERROR.STRICT, 'Invalid character in chunk parameters')); diff --git a/src/native/api.c b/src/native/api.c index c4ce197c..d3065b36 100644 --- a/src/native/api.c +++ b/src/native/api.c @@ -355,6 +355,13 @@ int llhttp__on_chunk_header(llhttp_t* s, const char* p, const char* endp) { } +int llhttp__on_chunk_parameters(llhttp_t* s, const char* p, const char* endp) { + int err; + SPAN_CALLBACK_MAYBE(s, on_chunk_parameters, p, endp - p); + return err; +} + + int llhttp__on_chunk_complete(llhttp_t* s, const char* p, const char* endp) { int err; CALLBACK_MAYBE(s, on_chunk_complete); diff --git a/src/native/api.h b/src/native/api.h index 0e71d1a6..445aa9c8 100644 --- a/src/native/api.h +++ b/src/native/api.h @@ -38,6 +38,9 @@ struct llhttp_settings_s { */ llhttp_cb on_headers_complete; + /* Possible return values 0, -1, HPE_USER */ + llhttp_data_cb on_chunk_parameters; + /* Possible return values 0, -1, HPE_USER */ llhttp_data_cb on_body; diff --git a/test/fixtures/extra.c b/test/fixtures/extra.c index 7528a036..7e85a36b 100644 --- a/test/fixtures/extra.c +++ b/test/fixtures/extra.c @@ -203,6 +203,12 @@ int llhttp__on_body(llparse_t* s, const char* p, const char* endp) { return llparse__print_span("body", p, endp); } +int llhttp__on_chunk_parameters(llparse_t* s, const char* p, const char* endp) { + if (llparse__in_bench) + return 0; + return llparse__print_span("chunk parameters", p, endp); +} + int llhttp__on_chunk_header(llparse_t* s, const char* p, const char* endp) { if (llparse__in_bench) diff --git a/test/request/transfer-encoding.md b/test/request/transfer-encoding.md index 3a596b9f..e0c4ae5e 100644 --- a/test/request/transfer-encoding.md +++ b/test/request/transfer-encoding.md @@ -223,9 +223,11 @@ off=66 header_field complete off=67 len=7 span[header_value]="chunked" off=76 header_value complete off=78 headers complete method=3 v=1/1 flags=208 content_length=0 +off=81 len=40 span[chunk parameters]="ilovew3;somuchlove=aretheseparametersfor" off=123 chunk header len=5 off=123 len=5 span[body]="hello" off=130 chunk complete +off=133 len=14 span[chunk parameters]="blahblah; blah" off=149 chunk header len=6 off=149 len=6 span[body]=" world" off=157 chunk complete @@ -598,7 +600,7 @@ off=37 header_field complete off=38 len=7 span[header_value]="chunked" off=47 header_value complete off=49 headers complete method=4 v=1/1 flags=208 content_length=0 -off=51 error code=2 reason="Invalid character in chunk parameters" +off=50 error code=12 reason="Invalid character in chunk size" ``` ## Invalid OBS fold after chunked value diff --git a/test/response/transfer-encoding.md b/test/response/transfer-encoding.md index 6005e049..c43e3590 100644 --- a/test/response/transfer-encoding.md +++ b/test/response/transfer-encoding.md @@ -33,19 +33,7 @@ off=61 header_field complete off=62 len=7 span[header_value]="chunked" off=71 header_value complete off=73 headers complete status=200 v=1/1 flags=208 content_length=0 -off=79 chunk header len=37 -off=79 len=35 span[body]="This is the data in the first chunk" -off=114 len=1 span[body]=cr -off=115 len=1 span[body]=lf -off=118 chunk complete -off=122 chunk header len=28 -off=122 len=26 span[body]="and this is the second one" -off=148 len=1 span[body]=cr -off=149 len=1 span[body]=lf -off=152 chunk complete -off=157 chunk header len=0 -off=159 chunk complete -off=159 message complete +off=75 error code=12 reason="Invalid character in chunk size" ``` ### `chunked` before other transfer-encoding