envoyproxy / envoy

Cloud-native high-performance edge/middle/service proxy
https://www.envoyproxy.io
Apache License 2.0
24.96k stars 4.8k forks source link

Accessing request headers in envoy_on_response (lua HTTP filter). #4613

Open ashwinphatak opened 6 years ago

ashwinphatak commented 6 years ago

I'm trying to use a lua HTTP filter to set a response header whose value depends on a request header.

As a simple example, suppose we want to copy a header from the request to the response. How can we do this using a lua filter?

Maybe we can store the request header in a "global" table during envoy_on_request and read it later when envoy_on_response is called. However, even if this approach makes sense, how can we correlate responses with requests to be able to do this?

stale[bot] commented 6 years ago

This issue has been automatically marked as stale because it has not had activity in the last 30 days. It will be closed in the next 7 days unless it is tagged "help wanted" or other activity occurs. Thank you for your contributions.

stale[bot] commented 5 years ago

This issue has been automatically closed because it has not had activity in the last 37 days. If this issue is still valid, please ping a maintainer and ask them to label it as "help wanted". Thank you for your contributions.

mderazon commented 5 years ago

This will be very helpful. One use case for this: datawire/ambassador#1847

Stono commented 4 years ago

Could we please reopen this as it's an excellent use case? For example; we wish to write a response handler which logs information about the request in error scenarios!

vbuciuc commented 4 years ago

see the example here:

https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_filters/lua_filter#set

it stores headers in dynamic metadata in the request handler which are then available in the response handler

vbuciuc commented 4 years ago

see the example here:

https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_filters/lua_filter#set

it stores headers in dynamic metadata in the request handler which are then available in the response handler

ErikXu commented 4 years ago

@vbuciuc Works for me. But the filterName in dynamicMetadata:set(filterName, key, value) confuses me. I have my own http filter named my-filter. Which name should I use, my-filter, my-filter.lua or envoy.filters.http.lua? In addition, is the data stored in a lua file?

dio commented 4 years ago

@ErikXu sorry for confusing docs and late reply. So the filterName can be anything, think about a namespace (we need to update the docs).

As an example:

          - name: envoy.filters.http.lua
            typed_config:
              "@type": type.googleapis.com/envoy.config.filter.http.lua.v2.Lua
              inline_code: |
                function envoy_on_request(request_handle)
                  request_handle:streamInfo():dynamicMetadata():set("context", "foo", "bar")
                end
                function envoy_on_response(response_handle)
                  local foo = response_handle:streamInfo():dynamicMetadata():get("context")["foo"]
                  response_handle:logInfo(foo)
                end
Arsen-Uulu commented 3 years ago

@dio I have this filter and it doesn't seem to be working

        name: envoy.lua
        typed_config:
          "@type": "type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua"
          inlineCode: |
            function envoy_on_request(request_handle)
              request_handle:streamInfo():dynamicMetadata():set("context","bar ", "foo")
            end
            function envoy_on_response(response_handle)
              local val = response_handle:streamInfo():dynamicMetadata():get("context")["foo"]
              response_handle:headers():add("x-custom-header", val)
            end
Arsen-Uulu commented 3 years ago

@dio is it possible to get SIDECAR_INBOUND request headers and pass it to SIDECAR_OUTBOUND envoy_on_request() ?

Stono commented 3 years ago

@Arsen-Uulu i do it by storing them on the dynamic metadata, similar to how you've done it, but i build up a map first

              function envoy_on_request(request_handle)
                local request_headers = request_handle:headers()
                local headers = {}
                for key, value in pairs(request_headers) do
                  headers[key] = value
                end
                request_handle:streamInfo():dynamicMetadata():set("context", "request.info", headers)
              end

              function envoy_on_response(response_handle)
                local request_headers = response_handle:streamInfo():dynamicMetadata():get("context")["request.info"]
                local response_headers = response_handle:headers()
                local status = response_headers:get(":status")
                if not isempty(status) then
                  local asNumber = tonumber(status)
                  if asNumber == 400 or asNumber == 401 or asNumber >= 500 then
                    print_headers(request_headers, response_headers)
                  end
                end
              end
Arsen-Uulu commented 3 years ago

@Stono Hey than you for suggestion.
I don't wanna handle the response.

What I want is capture req_headers from upstream and when my app makes a new request(outbound) I wanna add that header that I captured from inbound request

dio commented 3 years ago

@dio is it possible to get SIDECAR_INBOUND request headers and pass it to SIDECAR_OUTBOUND envoy_on_request() ?

Hum, seems like you need your service to collaborate? Unless you call it directly using https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_filters/lua_filter#httpcall (not sure if that is what you want).

631068264 commented 2 years ago

@dio I have this filter and it doesn't seem to be working

        name: envoy.lua
        typed_config:
          "@type": "type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua"
          inlineCode: |
            function envoy_on_request(request_handle)
              request_handle:streamInfo():dynamicMetadata():set("context","bar ", "foo")
            end
            function envoy_on_response(response_handle)
              local val = response_handle:streamInfo():dynamicMetadata():get("context")["foo"]
              response_handle:headers():add("x-custom-header", val)
            end

change context to envoy.lua

adamf-sendblocks commented 6 months ago

@ErikXu sorry for confusing docs and late reply. So the filterName can be anything, think about a namespace (we need to update the docs).

I found the docs exceptionally unhelpful, but I'm really pleased to have eventually stumbled across this thread!

For the next poor soul, I warmly recommend making it clearer to new users like myself that the header_to_metadata_filter's "namespace" field needs to be the name of the filter that uses it, and ask that you provide an example of chaining a header -> metadata -> lua handler. It might even be worthwhile linking that documentation to the set / get example.

Thanks again!