-
Notifications
You must be signed in to change notification settings - Fork 5.5k
feat(lua): allow setting response body when the upstream response body is empty #14486
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
Changes from 9 commits
c1144f3
9ad27b2
b209dcf
240ff41
d387335
229d2de
ade3534
40fd113
09b05bb
0101c9c
63d1354
d59c8e1
c8cf954
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -181,7 +181,7 @@ class LuaHttpFilterTest : public testing::Test { | |
| function envoy_on_request(request_handle) | ||
| request_handle:logTrace(request_handle:headers():get(":path")) | ||
|
|
||
| if request_handle:body() ~= nil then | ||
| if request_handle:body():length() ~= 0 then | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm a little worried about this change breaking scripts, but I'm not sure how likely that is. I guess with a runtime guard we can see how it goes? The alternative would be to allow
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, this PR introduces a new runtime feature flag (and tested in integration test). But yeah, thinking it again, to have a cleaner approach: seems like bool (or enum ( -- with bool.
response_handle:body(true):setBytes("ok")
-- with "enum".
response_handle:body(Envoy.ALWAYS_WRAP_BODY):setBytes("ok")
-- with new API.
response_handle:wrappedBody():setBytes("ok")
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I will vote for the first one, because:
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. SG. The reason for offering new API is for readability in the Lua code. |
||
| request_handle:logTrace(request_handle:body():length()) | ||
| else | ||
| request_handle:logTrace("no body") | ||
|
|
@@ -193,7 +193,7 @@ class LuaHttpFilterTest : public testing::Test { | |
| function envoy_on_request(request_handle) | ||
| request_handle:logTrace(request_handle:headers():get(":path")) | ||
|
|
||
| if request_handle:body() ~= nil then | ||
| if request_handle:body():length() ~= 0 then | ||
|
dio marked this conversation as resolved.
Outdated
|
||
| request_handle:logTrace(request_handle:body():length()) | ||
| else | ||
| request_handle:logTrace("no body") | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -146,7 +146,11 @@ class LuaIntegrationTest : public testing::TestWithParam<Network::Address::IpVer | |
| registerTestServerPorts({"http"}); | ||
| } | ||
|
|
||
| void testRewriteResponse(const std::string& code) { | ||
| void expectResponseBodyRewrite(const std::string& code, bool empty_body, bool enable_wrap_body) { | ||
| if (!enable_wrap_body) { | ||
| config_helper_.addRuntimeOverride("envoy.reloadable_features.lua_always_wrap_body", "false"); | ||
| } | ||
|
|
||
| initializeFilter(code); | ||
| codec_client_ = makeHttpConnection(makeClientConnection(lookupPort("http"))); | ||
| Http::TestRequestHeaderMapImpl request_headers{{":method", "POST"}, | ||
|
|
@@ -164,22 +168,40 @@ class LuaIntegrationTest : public testing::TestWithParam<Network::Address::IpVer | |
| waitForNextUpstreamRequest(); | ||
|
|
||
| Http::TestResponseHeaderMapImpl response_headers{{":status", "200"}, {"foo", "bar"}}; | ||
| upstream_request_->encodeHeaders(response_headers, false); | ||
| Buffer::OwnedImpl response_data1("good"); | ||
| upstream_request_->encodeData(response_data1, false); | ||
| Buffer::OwnedImpl response_data2("bye"); | ||
| upstream_request_->encodeData(response_data2, true); | ||
|
|
||
| if (empty_body) { | ||
| upstream_request_->encodeHeaders(response_headers, true); | ||
| } else { | ||
| upstream_request_->encodeHeaders(response_headers, false); | ||
| Buffer::OwnedImpl response_data1("good"); | ||
| upstream_request_->encodeData(response_data1, false); | ||
| Buffer::OwnedImpl response_data2("bye"); | ||
| upstream_request_->encodeData(response_data2, true); | ||
| } | ||
|
|
||
| response->waitForEndStream(); | ||
|
|
||
| EXPECT_EQ("2", response->headers() | ||
| .get(Http::LowerCaseString("content-length"))[0] | ||
| ->value() | ||
| .getStringView()); | ||
| EXPECT_EQ("ok", response->body()); | ||
| if (enable_wrap_body) { | ||
| EXPECT_EQ("2", response->headers() | ||
| .get(Http::LowerCaseString("content-length"))[0] | ||
| ->value() | ||
| .getStringView()); | ||
| EXPECT_EQ("ok", response->body()); | ||
| } else { | ||
| EXPECT_EQ("", response->body()); | ||
| } | ||
|
|
||
| cleanup(); | ||
| } | ||
|
|
||
| void testRewriteResponse(const std::string& code) { | ||
| expectResponseBodyRewrite(code, false, true); | ||
| } | ||
|
|
||
| void testRewriteResponseWithoutUpstreamBody(const std::string& code, bool enable_wrap_body) { | ||
| expectResponseBodyRewrite(code, true, enable_wrap_body); | ||
| } | ||
|
|
||
| void cleanup() { | ||
| codec_client_->close(); | ||
| if (fake_lua_connection_ != nullptr) { | ||
|
|
@@ -974,6 +996,46 @@ name: lua | |
| testRewriteResponse(FILTER_AND_CODE); | ||
| } | ||
|
|
||
| // Rewrite response buffer, without original upstream response body. | ||
| TEST_P(LuaIntegrationTest, RewriteResponseBufferWithoutUpstreamBody) { | ||
| const std::string FILTER_AND_CODE = | ||
| R"EOF( | ||
| name: lua | ||
| typed_config: | ||
| "@type": type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua | ||
| inline_code: | | ||
| function envoy_on_response(response_handle) | ||
| local content_length = response_handle:body():setBytes("ok") | ||
| response_handle:logTrace(content_length) | ||
|
|
||
| response_handle:headers():replace("content-length", content_length) | ||
| end | ||
| )EOF"; | ||
|
|
||
| testRewriteResponseWithoutUpstreamBody(FILTER_AND_CODE, true); | ||
| } | ||
|
|
||
| // Rewrite response buffer, without original upstream response body | ||
| // and disable lua_always_wrap_body feature. | ||
| TEST_P(LuaIntegrationTest, RewriteResponseBufferWithoutUpstreamBodyAndDisableWrapBody) { | ||
| const std::string FILTER_AND_CODE = | ||
| R"EOF( | ||
| name: lua | ||
| typed_config: | ||
| "@type": type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua | ||
| inline_code: | | ||
| function envoy_on_response(response_handle) | ||
| if response_handle:body() then | ||
| local content_length = response_handle:body():setBytes("ok") | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm confused. Shouldn't this end up returning nil and the script should crash? Shouldn't we be verifying nil here instead?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah sorry, I missed that. OK LGTM modulo the typo. |
||
| response_handle:logTrace(content_length) | ||
| response_handle:headers():replace("content-length", content_length) | ||
| end | ||
| end | ||
| )EOF"; | ||
|
|
||
| testRewriteResponseWithoutUpstreamBody(FILTER_AND_CODE, false); | ||
| } | ||
|
|
||
| // Rewrite chunked response body. | ||
| TEST_P(LuaIntegrationTest, RewriteChunkedBody) { | ||
| const std::string FILTER_AND_CODE = | ||
|
|
||
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.