Skip to content

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

Merged
snowp merged 19 commits intoenvoyproxy:masterfrom
snowp:fix-local-reply-grpc
Oct 6, 2020
Merged

hcm: fix sending local reply during encode + grpc request classification#13256
snowp merged 19 commits intoenvoyproxy:masterfrom
snowp:fix-local-reply-grpc

Conversation

@snowp
Copy link
Copy Markdown
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 snowp@lyft.com

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 <snowp@lyft.com>
@snowp
Copy link
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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

filter_manager_callbacks_.encodeHeaders(*filter_manager_callbacks_.responseHeaders(),
end_stream);
maybeEndEncode(end_stream);
maybeEndEncode(end_stream && !state_.local_complete_);
Copy link
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
Contributor Author

snowp commented Sep 24, 2020

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

Snow Pettersen added 7 commits September 28, 2020 16:46
Signed-off-by: Snow Pettersen <snowp@lyft.com>
Signed-off-by: Snow Pettersen <snowp@lyft.com>
Signed-off-by: Snow Pettersen <snowp@lyft.com>
Signed-off-by: Snow Pettersen <snowp@lyft.com>
Signed-off-by: Snow Pettersen <snowp@lyft.com>
Signed-off-by: Snow Pettersen <snowp@lyft.com>
Signed-off-by: Snow Pettersen <snowp@lyft.com>
Signed-off-by: Snow Pettersen <snowp@lyft.com>
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
Copy Markdown
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
Copy Markdown
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

Snow Pettersen added 2 commits September 29, 2020 21:34
ci
Signed-off-by: Snow Pettersen <snowp@lyft.com>
Signed-off-by: Snow Pettersen <snowp@lyft.com>
Copy link
Copy Markdown
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

ASSERT_TRUE(fake_upstream_connection_->waitForDisconnect());
}

TEST_P(ReverseBridgeIntegrationTest, EnabledRouteBadContentType) {
Copy link
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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

Snow Pettersen added 5 commits September 30, 2020 19:34
This reverts commit 2f4d2f6.

Signed-off-by: Snow Pettersen <snowp@lyft.com>
Signed-off-by: Snow Pettersen <snowp@lyft.com>
Signed-off-by: Snow Pettersen <snowp@lyft.com>
Signed-off-by: Snow Pettersen <snowp@lyft.com>
Signed-off-by: Snow Pettersen <snowp@lyft.com>
Signed-off-by: Snow Pettersen <snowp@lyft.com>
mattklein123
mattklein123 previously approved these changes Oct 1, 2020
Copy link
Copy Markdown
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
Copy Markdown
Contributor Author

snowp commented Oct 1, 2020

/retest

@repokitteh-read-only
Copy link
Copy Markdown

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
Copy Markdown
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
Copy Markdown
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.

filter_manager_callbacks_.encodeHeaders(*filter_manager_callbacks_.responseHeaders(),
end_stream);
maybeEndEncode(end_stream);
maybeEndEncode(end_stream && !state_.local_complete_);
Copy link
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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 <snowp@lyft.com>
Signed-off-by: Snow Pettersen <snowp@lyft.com>
Copy link
Copy Markdown
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
Copy Markdown
Contributor Author

snowp commented Oct 6, 2020

/retests

@snowp
Copy link
Copy Markdown
Contributor Author

snowp commented Oct 6, 2020

/retest

@repokitteh-read-only
Copy link
Copy Markdown

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