-
Notifications
You must be signed in to change notification settings - Fork 4.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[http] add llhttp parser implementation #15814
Conversation
Co-authored-by: Derek Argueta <[email protected]> Signed-off-by: Asra Ali <[email protected]>
Signed-off-by: Asra Ali <[email protected]>
/lgtm deps |
Signed-off-by: Asra Ali <[email protected]>
Very confused about the ASan error. It is reproducible via bazel test, but not by gdb or running the binary directly. When I bazel test, it appears the function doesn't enter envoy/source/common/http/http1/parser_impl.cc Lines 102 to 106 in 591811f
|
Signed-off-by: Asra Ali <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is really exciting to see progress on Envoy moving to a http1 parser that is under active development.
@@ -766,6 +771,7 @@ StatusOr<ParserStatus> ConnectionImpl::onHeadersComplete() { | |||
return codecProtocolError("http/1.1 protocol error: unsupported transfer encoding"); | |||
} | |||
} | |||
parser_->hasContentLength(request_or_response_headers.ContentLength() != nullptr); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens if a request has both transfer-encoding: chunked and content-length?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's handled with an error. Actually this is just because llhttp doesn't have an initial value for unset content length. http_parser
uses all 1 bits set to indicate there is no content length. Added comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should have tests in envoy to cover these cases. This is related to my question regarding use of lenient parsing further down in this file. It seems that those lenient options were added for the benefit of Envoy's H1 implementation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
envoy/test/common/http/http1/codec_impl_test.cc
Line 1945 in 56d3f8a
TEST_F(Http1ServerConnectionImplTest, TestSmugglingDisallowChunkedContentLength0) { |
There are tests for both content length and chunked.
void resume() { llhttp_resume(&parser_); } | ||
|
||
ParserStatus pause() { | ||
// llhttp can only pause by returning a paused status in user callbacks. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we do something to reconcile this behavior with http_parser? How do we ensure that nothing depends on this function having side effects for http_parser?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The http_parser implementation of pause()
uses the http parser method to pause (https://github.com/nodejs/http-parser/blob/ec8b5ee63f0e51191ea43bb0c6eac7bfbff3141d/http_parser.h#L438) and an OK. That's the same as returning pause from llhttp parser. I think it's already reconciled
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess this is an area to cleanup once llhttp is the only implementation.
In the current world I would consider something like:
ParserStatus maybePause(ParserStatus status);
The http_parser version would detect status == Paused and call its pause method and return Success, while the llhttp version would just return the status that was passed in.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the current world I would consider something like:
To me that seems strange because Paused is the only status that maybePause would ever call.
Technically returning HPE_PAUSED from http-parser will also cause the parser to pause, but I don't trust making the change because there's very little http-parser docs and I don't know if it changes how it handles errors. (All http_parser_pause() does is cause HPE_PAUSED to be returning from execute. we could just return it directly).
Signed-off-by: Asra Ali <[email protected]>
I would appreciate if you could upgrade llhttp to 5.1.0 or 4.1.0, which was just released: nodejs/llhttp#95 |
Signed-off-by: Asra Ali <[email protected]>
Signed-off-by: Asra Ali <[email protected]>
Updated, sorry for the delay! (This is an evening thing right now)
|
Signed-off-by: Asra Ali <[email protected]>
Still working on the asan issue (comment above) and a tsan one. TSan is from running existing parser, reproducible, so something must have went wrong there... all the issues are about allowing chunked... and run into data race at destruction |
public: | ||
Impl(llhttp_type_t type) { | ||
llhttp_init(&parser_, type, &settings_); | ||
llhttp_set_lenient_chunked_length(&parser_, 1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What code in Envoy is generating the error response when both transfer-encoding: chunked and content-length is set?
@@ -0,0 +1,62 @@ | |||
actions { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What fixes are needed to make this corpus entry run successfully? I assume it's the changes to the fuzz harness?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It does run successfully now, with the changes in the diff that close that reset stream when the response ends before the request does.
Signed-off-by: Asra Ali <[email protected]>
I tried to do some debugging but the conclusion I got to was along the lines that the stall happens even if I disable the cache filter. This may be a real issue processing multiple requests on the same connection with the new parser. Is there a chance that some state is not being reset in the parser between requests? Debugging the state of the llhttp parser isn't easy between the typescript to c transcoding and it being an external dep for the build. Would it be possible to add methods to dump info about the state of the parser or debug accessors which can be used to implement said debug methods in ParserImpl? |
|
Signed-off-by: Asra Ali <[email protected]>
Signed-off-by: Asra Ali <[email protected]>
Please see precheck format presubmit error. /wait
|
Signed-off-by: Asra Ali <[email protected]>
Signed-off-by: Asra Ali <[email protected]>
cache filter integration test still failing /wait |
|
This pull request has been automatically marked as stale because it has not had activity in the last 30 days. It will be closed in 7 days if no further activity occurs. Please feel free to give a status update now, ping for review, or re-open when it's ready. Thank you for your contributions! |
|
Obsolete. QUICHE H/1 code (Balsa) is currently being integrated. |
Signed-off-by: Asra Ali [email protected]
Commit Message: Add llhttp parser implementation.
Risk Level: High, but off by default.
Testing: H/1 codec impl and unit tests that use actual codecs have two targets now, a legacy and new version. Integration tests are parametrized by enabling the runtime flag via the config setting and is enabled in compile_time_options. Codec fuzz test enables the new parser.
Release Notes: Added
Runtime guard:
envoy.reloadable_features.enable_new_http1_parser
. Off by default.Fixes: #5155
https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=25777 (see note below)
CHANGES
http1.invalid_characters
response codes appear ashttp1.codec_error
. and the status message readsHPE_INVALID_HEADER_TOKEN
.NOTES FOR CLEANUP