-
Notifications
You must be signed in to change notification settings - Fork 4.9k
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
Removed exception in getResponseStatus() #13314
Removed exception in getResponseStatus() #13314
Conversation
Signed-off-by: Zach <zasweq@google.com>
Signed-off-by: Zach <zasweq@google.com>
@@ -346,6 +346,8 @@ void ResponseEncoderImpl::encodeHeaders(const ResponseHeaderMap& headers, bool e | |||
|
|||
// The contract is that client codecs must ensure that :status is present. | |||
ASSERT(headers.Status() != nullptr); | |||
// encodeHeaders() is not supposed to throw any exceptions. This will crash on a release assert if |
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 think it is possible that it could throw exception and exception and not crash when processing upstream response. The exception would have been caught by the dispatch() method of the client connection. Do we have an integration test where upstream responds with a garbage status?
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.
Thanks!
Please add tests like ProtocolIntegrationTest.UnknownResponsecode but with status strings that are not a number or overflowing uint64_t to cover the new RELEASE_ASSERT |
Signed-off-by: Zach <zasweq@google.com>
Yan, just to officially document this, that test crashes on the release assert on this code change, and when I run that integration test against master, it also crashes. Hopefully it's caused by the mocks. |
Yes, it is crashing in the codec used for faking the upstream server. We'll discuss tomorrow how to proceed. |
…eger response status. Signed-off-by: Zach <zasweq@google.com>
Signed-off-by: Zach <zasweq@google.com>
This pull request has been automatically marked as stale because it has not had activity in the last 7 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! |
Signed-off-by: Zach <zasweq@google.com>
Signed-off-by: Zach <zasweq@google.com>
Signed-off-by: Zach <zasweq@google.com>
/azp run |
Azure Pipelines successfully started running 1 pipeline(s). |
source/common/http/utility.cc
Outdated
return response_status_or_absl_status.value(); | ||
} | ||
|
||
absl::StatusOr<uint64_t> Utility::getResponseStatusOr(const ResponseHeaderMap& headers) { |
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.
When this method is only called from the ConnectionImpl::ClientStreamImpl::decodeHeaders()
. Given that the H/2 codec verifies validity of the Status header, the only case where this can fail is if the Status header is missing altogether.
I think we should just move the check for Status header presence into the ConnectionImpl::ClientStreamImpl::decodeHeaders()
and here just ASSERT success of the absl::SimpleAtoi
with the comment that invalid Status values should not get past response parsing in codec.
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.
Interesting. I liked how this got rid of exceptions, but your suggestion is a much cleaner way to remove the exceptions. Take the two things in the if and move one thing (simpleAtoi() call) to an assert and another (status presence) to codebase. However, I do believe the codecs already account for missing status headers similarly to overflowing status, so why even add a check there? @asraa what are your thoughts
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.
Quickly glanced around codebase, couldn't seem to find a missing status integration test? If not there (perhaps ctrl f in GitHub missed it :)) I can add one!
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.
Out of my own interest I wrote an http2 frame method for header frames without statuses breaking the HTTP/2 requirement and wrote an integration test for it. I got "[2020-10-22 05:28:34.375][31][trace][http2] [source/common/http/http2/codec_impl.cc:715] [C2] about to recv frame type=1, flags=5
[2020-10-22 05:28:34.375][31][debug][http2] [source/common/http/http2/codec_impl.cc:890] [C2] invalid frame: Violation in HTTP messaging rule on stream 1". Thus, this is similar to overflowing statuses. Let me know if you want me to check that test in too, because it would potentially hit this line and if the codec didn't validate status presence which is what the test checked for.
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.
Hey Yan, I discussed this with Asra in our standup. Asra wants to keep it consistent, and is indifferent to whether we ASSERT or have a check, however wants to keep it consistent, and not an assert on atoi and a check for headers, because that would be unneeded complexity by splitting them.
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.
Ok, I understand. I think given that we also verify that missing status from the response headers is rejected, I think we could either ENVOY_BUG or RELEASE_ASSERT that status header is present.
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.
So release assert on both conditions in the utility function?
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.
"Both" meaning missing status and overflowed status
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.
Hey - so just to make sure - what you want is to keep the function as is, but instead of throwing up an exception with the if clause, wrap those two booleans (headers present, atoi call okay) in a RELASE_ASSERT. Basically, since we have validated that across both codecs the codecs handle it, we can move it.
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.
"Keep the function as is" meaning what is currently checked into master for getResponseStatus? Both utility function and not having my error handling in codecs.
source/common/http/utility.cc
Outdated
@@ -369,10 +370,18 @@ std::string Utility::makeSetCookieValue(const std::string& key, const std::strin | |||
} | |||
|
|||
uint64_t Utility::getResponseStatus(const ResponseHeaderMap& headers) { | |||
absl::StatusOr<uint64_t> response_status_or_absl_status = getResponseStatusOr(headers); |
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.
Is there a case where this function can fail parsing the Status header now that there are tests that verify that invalid Status header is rejected by both H/1 and H/2 codecs?
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.
No, but you don't think it's worth removing exceptions (removing meaning converting to error earlier instead of in try catch block) for any future iterations, considering if we keep the exception then it'll still be there in the long run, even though currently not triggerable?
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 think it is totally worth removing this exception. We have proven with the test that the code does the right thing and does not accept responses with invalid Status header. Given this I think we should just assert that the parsing of the status number was successful. I think we could use ENVOY_BUG or event RELEASE_ASSERT here, given that we have solid test.
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.
Hey Yan, I've been thinking about this some, and I think that the problem is that getResponseStatus() is called all around the codebase, and the problem is that if we make it an assert rather than an exception for other parts of the codebase, it would introduce a point of failure out of nothing? Let me know what you're thinking :)
Signed-off-by: Zach <zasweq@google.com>
Signed-off-by: Zach <zasweq@google.com>
To make sure I'm understanding the whole picture, because I am confused reading the threads:
|
Signed-off-by: Zach <zasweq@google.com>
Sorry about the confusion. I was thinking more about this case. It is a bit of a mess. |
Faulty filters will be handled in PR #13470 after which the exception can be removed. |
Hey Yan, thanks for taking a look at this. Weirdly, I forgot to check in the utility source file where I switched it to an ASSERT. Perhaps we can just check in the tests for now, since switching to an ASSERT at a later time would be a one line change :). |
* master: (83 commits) tls: Typesafe tls slots (envoyproxy#13789) docs(example): Correct URL for caching example page (envoyproxy#13810) [fuzz] Made health check fuzz more efficient (envoyproxy#13747) rtds: properly scope rtds stats (envoyproxy#13764) http: fixing a bug with IPv6 hosts (envoyproxy#13798) connection: Remember transport socket read resumption requests and replay them when re-enabling read. (envoyproxy#13772) network: adding some accessors for ALPN work. (envoyproxy#13785) docs: added a step about how to handle platform specific extensions (envoyproxy#13759) Fix identation in ip transparency code snippet (envoyproxy#13743) wasm: enable WAVM's stack unwinding feature (envoyproxy#13792) log: set route name for direct response (envoyproxy#13683) Use nghttp2 as external dependsncy in protocol_constraints_lib (envoyproxy#13763) [Windows] Update windows dev docs (envoyproxy#13741) cel: patch thread safety issue (envoyproxy#13739) Windows: Fix ssl_socket_test (envoyproxy#13264) apple dns: add fake api test suite (envoyproxy#13780) overload: scale selected timers in response to load (envoyproxy#13475) examples: Add dynamic configuration (control plane) sandbox (envoyproxy#13746) Removed exception in getResponseStatus() (envoyproxy#13314) network: add timeout for transport connect (envoyproxy#13610) ... Signed-off-by: Michael Puncel <mpuncel@squareup.com>
Signed-off-by: Zach Reyes zasweq@google.com
Commit Message: Removed exception in getResponseStatus().
Additional Description: Falls within #10878. getResponseStatus() is called on the data plane in the codecs. Thus, for security reasons changed from throw Exception -> Release Assert for the function calls in codebase. For HTTP/2 codec's, changed decodeHeaders() to return a status rather than exception, which logically amounts to the same logic after the try catch around dispatch.
Risk Level: Low
Testing: N/A
Docs Changes: N/A
Release Notes: N/A