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

feat(lua): allow setting response body when the upstream response body is empty #14486

Merged
merged 13 commits into from
Jan 6, 2021

Conversation

spacewander
Copy link
Contributor

@spacewander spacewander commented Dec 20, 2020

Commit Message: allow setting response body when the upstream response body is empty
Additional Description:
Risk Level: Medium
Testing: unit and integration tests
Docs Changes: TBA
Release Notes: Lua body() will no longer return nil when the response body is empty. Can be changed via runtime flag.
Platform Specific Features: N/A
Fixes #14226

Signed-off-by: spacewander spacewanderlzx@gmail.com

…y is empty

Close envoyproxy#14226.

Signed-off-by: spacewander <spacewanderlzx@gmail.com>
@spacewander spacewander marked this pull request as ready for review December 20, 2020 13:21
@dio
Copy link
Member

dio commented Dec 22, 2020

Can you merge master? Thanks!

Copy link
Member

@dio dio left a comment

Choose a reason for hiding this comment

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

The approach seems OK. A nit and a request for refactoring the test helper.

source/extensions/filters/http/lua/lua_filter.cc Outdated Show resolved Hide resolved
end
)EOF";

testRewriteResponseWithoutUpstreamBody(FILTER_AND_CODE);
Copy link
Member

Choose a reason for hiding this comment

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

While you're here, can we refactor this a bit to have e.g. expectResponseBodyRewrite(), parameterized with the body from upstream (this can be empty or filled (buffered)) and the expected rewritten body?

So we can reuse this to test both cases.

Thank you!

Signed-off-by: spacewander <spacewanderlzx@gmail.com>
Signed-off-by: spacewander <spacewanderlzx@gmail.com>
Signed-off-by: spacewander <spacewanderlzx@gmail.com>
Signed-off-by: spacewander <spacewanderlzx@gmail.com>
Signed-off-by: spacewander <spacewanderlzx@gmail.com>
@dio
Copy link
Member

dio commented Dec 27, 2020

Thanks, @spacewander, could you merge main? Probably it will help to remedy:

2020-12-27T03:11:40.3528486Z Code coverage for source/common/network is lower than limit of 95.3 (95.2)

/wait

Signed-off-by: spacewander <spacewanderlzx@gmail.com>
@dio
Copy link
Member

dio commented Dec 28, 2020

Interesting since "master" has that 95.3% coverage for source/common/network. https://storage.googleapis.com/envoy-postsubmit/master/coverage/index.html. Need to add more coverage on that to make it pass :).

Signed-off-by: spacewander <spacewanderlzx@gmail.com>
@spacewander
Copy link
Contributor Author

@dio
I looked into source/common/network and can't find anywhere I can add test. It is quite weird since I don't touch this part of code.
Now I rerun the test and it failed on source/extensions/common/wasm: https://dev.azure.com/cncf/envoy/_build/results?buildId=62373&view=logs&j=bbe4b42d-86e6-5e9c-8a0b-fea01d818a24&t=e00c5a13-c6dc-5e9a-6104-69976170e881
I don't touch source/extensions/common/wasm too...
Maybe we can relax this limitation since it causes flaky report?

@dio
Copy link
Member

dio commented Dec 29, 2020

Since this https://github.com/envoyproxy/envoy/pull/14528/files is merged. I think we can do another main branch merging. Sorry for the hassle.

Signed-off-by: spacewander <spacewanderlzx@gmail.com>
@spacewander
Copy link
Contributor Author

@dio
Thanks! Finally it pass all the checks.

dio
dio previously approved these changes Dec 30, 2020
Copy link
Member

@dio dio left a comment

Choose a reason for hiding this comment

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

Thanks!

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 for working on this. A question on overall design to get started. Thank you!

/wait

@@ -24,6 +24,7 @@ Minor Behavior Changes
* jwt_authn filter: added support of Jwt time constraint verification with a clock skew (default to 60 seconds) and added a filter config field :ref:`clock_skew_seconds <envoy_v3_api_field_extensions.filters.http.jwt_authn.v3.JwtProvider.clock_skew_seconds>` to configure it.
* kill_request: enable a way to configure kill header name in KillRequest proto.
* listener: injection of the :ref:`TLS inspector <config_listener_filters_tls_inspector>` has been disabled by default. This feature is controlled by the runtime guard `envoy.reloadable_features.disable_tls_inspector_injection`.
* lua: always return a :ref:`buffer object <config_http_filters_lua_buffer_wrapper>` even the body is empty. This feature is controlled by the runtime guard `envoy.reloadable_features.lua_always_wrap_body`.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
* lua: always return a :ref:`buffer object <config_http_filters_lua_buffer_wrapper>` even the body is empty. This feature is controlled by the runtime guard `envoy.reloadable_features.lua_always_wrap_body`.
* lua: always return a :ref:`buffer object <config_http_filters_lua_buffer_wrapper>` even if the body is empty. This feature is controlled by the runtime guard `envoy.reloadable_features.lua_always_wrap_body` and defaults to enabled.

@@ -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
Copy link
Member

Choose a reason for hiding this comment

The 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 body() to take an optional boolean which enables the behavior? This could default to the existing behavior? I think I'm probably leaning towards that now that I think about it? @dio WDYT?

Copy link
Member

Choose a reason for hiding this comment

The 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 (Envoy.ALWAYS_WRAP_BODY)? for syntactic sugar, similar to this PR) or a new API (e.g. wrappedBody(), this new API always has a non-nil "buffer").

-- 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")

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 will vote for the first one, because:

  1. argument is enough to distinguish them, not need to add an extra method
  2. there is only "always wrap body" and "not always wrap body", so a boolean is enough.

Copy link
Member

Choose a reason for hiding this comment

The 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.

@mattklein123 mattklein123 self-assigned this Jan 3, 2021
Signed-off-by: spacewander <spacewanderlzx@gmail.com>
Signed-off-by: spacewander <spacewanderlzx@gmail.com>
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 this looks good. Can you check CI also?

/wait

@@ -418,16 +418,31 @@ int StreamHandleWrapper::luaHeaders(lua_State* state) {
int StreamHandleWrapper::luaBody(lua_State* state) {
ASSERT(state_ == State::Running);

int always_wrap_body = 0;
Copy link
Member

Choose a reason for hiding this comment

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

nit: use bool here

Signed-off-by: spacewander <spacewanderlzx@gmail.com>
@spacewander
Copy link
Contributor Author

@mattklein123
All tests pass.

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 at a high level with some test comments.

/wait

@@ -974,6 +992,47 @@ name: lua
testRewriteResponse(FILTER_AND_CODE);
}

// Rewrite response buffer, without original upstream response body
// and always warp body.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
// and always warp body.
// and always wrap body.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@mattklein123
Typo fixed.

inline_code: |
function envoy_on_response(response_handle)
if response_handle:body(false) then
local content_length = response_handle:body():setBytes("ok")
Copy link
Member

Choose a reason for hiding this comment

The 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?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The response_handle:body(false) always returns nil so this branch is skipped. It is just a mirror of the previous test but with the false given.

Copy link
Member

Choose a reason for hiding this comment

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

Ah sorry, I missed that. OK LGTM modulo the typo.

Signed-off-by: spacewander <spacewanderlzx@gmail.com>
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!

@mattklein123 mattklein123 merged commit d9f5edd into envoyproxy:master Jan 6, 2021
mpuncel added a commit to mpuncel/envoy that referenced this pull request Jan 8, 2021
* master: (48 commits)
  Resolve 14506, avoid libidn2 for our curl dependency (envoyproxy#14601)
  fix new/free mismatch in Mainthread utility (envoyproxy#14596)
  opencensus: deprecate Zipkin configuration. (envoyproxy#14576)
  upstream: clean up code location (envoyproxy#14580)
  configuration impl: add cast for ios compilation (envoyproxy#14590)
  buffer impl: add cast for android compilation (envoyproxy#14589)
  ratelimit: add dynamic metadata to ratelimit response (envoyproxy#14508)
  tcp_proxy: wait for CONNECT response before start streaming data (envoyproxy#14317)
  stream info: cleanup address handling (envoyproxy#14432)
  [deps] update upb to latest commit (envoyproxy#14582)
  Add utility to check whether the execution is in main thread. (envoyproxy#14457)
  listener: undeprecate bind_to_port (envoyproxy#14480)
  Fix data race in overload integration test (envoyproxy#14586)
  deps: update PGV (envoyproxy#14571)
  dependencies: update cve_scan.py for some libcurl 7.74.0 false positives. (envoyproxy#14572)
  Network::Connection: Add L4 crash dumping support (envoyproxy#14509)
  ssl: remember stat names for configured ciphers. (envoyproxy#14534)
  formatter: add custom date formatting to downstream cert start and end dates (envoyproxy#14502)
  feat(lua): allow setting response body when the upstream response body is empty (envoyproxy#14486)
  Generalize the gRPC access logger base classes (envoyproxy#14469)
  ...

Signed-off-by: Michael Puncel <mpuncel@squareup.com>
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.

Create upstream response body in LUA when it is NIL
3 participants