Skip to content
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

hcm: fix sending local reply during encode + grpc request classification #13256

Merged
merged 19 commits into from
Oct 6, 2020

Conversation

snowp
Copy link
Contributor

@snowp snowp commented Sep 24, 2020

Fixes two issues that surfaced when adding an integration test for the
gRPC reverse bridge:

  1. when sending a local reply during the encoding path, local_complete_
    is set to true which results in endStream being called twice. We fix
    this by not calling endStream during the header/body callback when
    local_complete_ is true
  2. the direct reply function was not using the state variable to detect
    is_grpc_request, which meant that for the reverse bridge is was using
    the modified headers which no longer have a gRPC content type.

Signed-off-by: Snow Pettersen [email protected]

Risk Level: Medium, HCM changes
Testing: New integration test
Docs Changes: n/a
Release Notes: n/a

Fixes two issues that surfaced when adding an integration test for the
gRPC reverse bridge:

1) when sending a local reply during the encoding path, local_complete_
is set to true which results in endStream being called twice. We fix
this by not calling endStream during the header/body callback when
local_complete_ is true
2) the direct reply function was not using the state variable to detect
is_grpc_request, which meant that for the reverse bridge is was using
the modified headers which no longer have a gRPC content type.

Signed-off-by: Snow Pettersen <[email protected]>
@snowp
Copy link
Contributor Author

snowp commented Sep 24, 2020

Locally this seems to work and cause no issues with integration tests, lmk if you want to proceed with this or revert the other PR @mattklein123

@snowp
Copy link
Contributor Author

snowp commented Sep 24, 2020

@zuercher Turns out there was a bug around text/plain as well, because during integration tests we end up taking a different flow and hit code that wasn't checking the state variable but instead checked the request headers that we'd already modified to not be grpc anymore.

Lesson to be learnt: integration test it!

Copy link
Member

@mattklein123 mattklein123 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At a high level this makes sense to me. But I would like to see:

  1. conn_manager_impl unit tests
  2. non-extension specific integration tests

If it's easier to revert the other PR for now and re-apply with ^ that's fine with me. Thank you!

/wait

@@ -880,16 +880,13 @@ void FilterManager::sendDirectLocalReply(
state_.non_100_response_headers_encoded_ = true;
filter_manager_callbacks_.encodeHeaders(*filter_manager_callbacks_.responseHeaders(),
end_stream);
maybeEndEncode(end_stream);
maybeEndEncode(end_stream && !state_.local_complete_);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry where is local_complete_ set to true? Before the filter chain starts iterating? This is not super intuitive. Can you add more comments?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but why do we need to sometimes end encode after encode headers / encode data, and sometimes outside of the EncodeFunctions? Can't we just remove the one at the end, or remove these two calls?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I looked through the code and I think it was there because the call to encode headers could trigger a reset, in which case encodeData wouldn't be called, so in that case endStream wouldn't be called. Calling reset would call local_complete_, and so endStream would be called at the end of the function.

That said, I tried removing it and no integration tests seem to fail. Seems like doEndStream is called as part of reset anyways, so it might not be necessary? Pushed this change, so let's see if CI passes

@snowp
Copy link
Contributor Author

snowp commented Sep 24, 2020

Yeah that's reasonable, let's revert the other PR now to keep HEAD healthy.

Signed-off-by: Snow Pettersen <[email protected]>
constexpr static char name[] = "local-reply-during-encode";

Http::FilterHeadersStatus encodeHeaders(Http::ResponseHeaderMap&, bool) override {
decoder_callbacks_->sendLocalReply(Http::Code::InternalServerError, "", nullptr, absl::nullopt,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make sense to add sendLocalReply to the StreamEncoderFilterCallbacks interface?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 per slack convo also

Signed-off-by: Snow Pettersen <[email protected]>
Signed-off-by: Snow Pettersen <[email protected]>
Copy link
Member

@mattklein123 mattklein123 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks LGTM other than remaining comments.

/wait

@@ -173,50 +173,5 @@ TEST_P(ReverseBridgeIntegrationTest, EnabledRoute) {
ASSERT_TRUE(fake_upstream_connection_->waitForDisconnect());
}

TEST_P(ReverseBridgeIntegrationTest, EnabledRouteBadContentType) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW I don't see the harm of leaving this test.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking that it wouldn't pass without the other PR but I'm not sure if that's true, I'll try adding it back

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh sorry I forgot about that. OK if you want to add it back there that's fine.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was able to get it working, seems like it just tested an existing feature so it passes now and should nicely serve as a regression test to make sure that we're not breaking this feature with the change to use sendLocalReply in the future

constexpr static char name[] = "local-reply-during-encode";

Http::FilterHeadersStatus encodeHeaders(Http::ResponseHeaderMap&, bool) override {
decoder_callbacks_->sendLocalReply(Http::Code::InternalServerError, "", nullptr, absl::nullopt,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 per slack convo also

This reverts commit 2f4d2f6.

Signed-off-by: Snow Pettersen <[email protected]>
Signed-off-by: Snow Pettersen <[email protected]>
Signed-off-by: Snow Pettersen <[email protected]>
Signed-off-by: Snow Pettersen <[email protected]>
Signed-off-by: Snow Pettersen <[email protected]>
Signed-off-by: Snow Pettersen <[email protected]>
mattklein123
mattklein123 previously approved these changes Oct 1, 2020
Copy link
Member

@mattklein123 mattklein123 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome, thanks!

@snowp
Copy link
Contributor Author

snowp commented Oct 1, 2020

/retest

@repokitteh-read-only
Copy link

Retrying Azure Pipelines, to retry CircleCI checks, use /retest-circle.
Retried failed jobs in: envoy-presubmit

🐱

Caused by: a #13256 (comment) was created by @snowp.

see: more, trace.

@snowp
Copy link
Contributor Author

snowp commented Oct 1, 2020

@alyssawilk do you wanna take a look at this as well?

@alyssawilk alyssawilk self-assigned this Oct 1, 2020
Copy link
Contributor

@alyssawilk alyssawilk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good overall! Really only the one question and the test nits.

@@ -880,16 +880,13 @@ void FilterManager::sendDirectLocalReply(
state_.non_100_response_headers_encoded_ = true;
filter_manager_callbacks_.encodeHeaders(*filter_manager_callbacks_.responseHeaders(),
end_stream);
maybeEndEncode(end_stream);
maybeEndEncode(end_stream && !state_.local_complete_);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but why do we need to sometimes end encode after encode headers / encode data, and sometimes outside of the EncodeFunctions? Can't we just remove the one at the end, or remove these two calls?

ASSERT_TRUE(upstream_request_->waitForEndStream(*dispatcher_));

// Ensure that we stripped the length prefix and set the appropriate headers.
EXPECT_EQ("f", upstream_request_->body().toString());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think a bunch of these are tested in another test.

WDYT of just using sendRequestAndWaitForReponse() and cutting out all the duplicate stuff?


// Wait for the upstream request and begin sending a response with end_stream = false.
waitForNextUpstreamRequest();
upstream_request_->encodeHeaders(Http::TestResponseHeaderMapImpl{{":status", "503"}}, true);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

again I think you can just sendRequestAndWaitForResponse with default request and response headers, since all you want to do is make sure the status code is set correctly.

Signed-off-by: Snow Pettersen <[email protected]>
Copy link
Contributor

@alyssawilk alyssawilk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM modulo ci investigation

@snowp
Copy link
Contributor Author

snowp commented Oct 6, 2020

/retests

@snowp
Copy link
Contributor Author

snowp commented Oct 6, 2020

/retest

@repokitteh-read-only
Copy link

Retrying Azure Pipelines, to retry CircleCI checks, use /retest-circle.
Retried failed jobs in: envoy-presubmit

🐱

Caused by: a #13256 (comment) was created by @snowp.

see: more, trace.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants