Skip to content

Enovy as forward proxy doesn't pass query parameters from request #6459

@lukidzi

Description

@lukidzi

Title: Enovy as forward proxy doesn't pass query parameters from request

Description:
I found a problem with envoy as forward proxy for egress traffic. When I am doing request to another service through envoy, query parameters are missing.

Example:
On my localhost I have envoy running with 2 listeners ingress and egress.
So when I am doing request with curl through envoy to cluster my-service:

curl -x localhost:6002 "http://my-service/test?username=test" -v

in logs I can see that my request failed because there is missing query parameter username

envoy_wrapper_1  | [envoy][2019-04-02 08:32:44.022][33][debug][http] [source/common/http/conn_manager_impl.cc:576] [C11][S4906893650903990186] request headers complete (end_stream=true):
envoy_wrapper_1  | ':authority', 'my-service'
envoy_wrapper_1  | ':path', '/test'
envoy_wrapper_1  | ':method', 'GET'
envoy_wrapper_1  | 'user-agent', 'curl/7.54.0'
envoy_wrapper_1  | 'accept', '*/*'
envoy_wrapper_1  | 'proxy-connection', 'Keep-Alive'
envoy_wrapper_1  |
envoy_wrapper_1  | [envoy][2019-04-02 08:32:44.022][33][debug][http] [source/common/http/conn_manager_impl.cc:1021] [C11][S4906893650903990186] request end stream
envoy_wrapper_1  | [envoy][2019-04-02 08:32:44.022][33][debug][router] [source/common/router/router.cc:320] [C11][S4906893650903990186] cluster 'my-service' match for URL '/test'
envoy_wrapper_1  | [envoy][2019-04-02 08:32:44.022][33][debug][router] [source/common/router/router.cc:381] [C11][S4906893650903990186] router decoding headers:
envoy_wrapper_1  | ':authority', 'myservice'
envoy_wrapper_1  | ':path', '/test'
envoy_wrapper_1  | ':method', 'GET'
envoy_wrapper_1  | ':scheme', 'http'
envoy_wrapper_1  | 'user-agent', 'curl/7.54.0'
envoy_wrapper_1  | 'accept', '*/*'
envoy_wrapper_1  | 'x-forwarded-proto', 'http'
envoy_wrapper_1  | 'x-request-id', 'bf18935a-bdb2-4cf4-9825-7cb127bd7285'
envoy_wrapper_1  | 'x-envoy-expected-rq-timeout-ms', '15000'

envoy_wrapper_1  | [envoy][2019-04-02 08:32:44.067][33][debug][http] [source/common/http/conn_manager_impl.cc:1256] [C11][S4906893650903990186] encoding headers via codec (end_stream=false):
envoy_wrapper_1  | ':status', '400'
envoy_wrapper_1  | 'access-control-allow-origin', '*'
envoy_wrapper_1  | 'access-control-allow-headers', 'origin, Content-Type, Accept, Authorization'
envoy_wrapper_1  | 'content-type', 'application/json;charset=UTF-8'
envoy_wrapper_1  | 'access-control-allow-methods', 'POST, PUT, GET, OPTIONS, DELETE'
envoy_wrapper_1  | 'access-control-max-age', '3600'
envoy_wrapper_1  | 'date', 'Tue, 02 Apr 2019 08:32:43 GMT'
envoy_wrapper_1  | 'x-envoy-upstream-service-time', '44'
envoy_wrapper_1  | 'server', 'envoy'

But if I make request:
curl -H "host: my-service" "http://localhost:6002/test?username=test" -v
everything works fine.

envoy_wrapper_1  | ':authority', 'my-service'
envoy_wrapper_1  | ':path', '/test?username=test'
envoy_wrapper_1  | ':method', 'GET'
envoy_wrapper_1  | 'user-agent', 'curl/7.54.0'
envoy_wrapper_1  | 'accept', '*/*'
envoy_wrapper_1  | 'accept-language', 'pl'
envoy_wrapper_1  |
envoy_wrapper_1  | [envoy][2019-04-02 08:37:11.909][35][debug][http] [source/common/http/conn_manager_impl.cc:1021] [C15][S14347542195339788614] request end stream
envoy_wrapper_1  | [envoy][2019-04-02 08:37:11.909][35][debug][router] [source/common/router/router.cc:320] [C15][S14347542195339788614] cluster 'my-service' match for URL '/test?username=test'
envoy_wrapper_1  | [envoy][2019-04-02 08:37:11.909][35][debug][router] [source/common/router/router.cc:381] [C15][S14347542195339788614] router decoding headers:
envoy_wrapper_1  | ':authority', 'my-service'
envoy_wrapper_1  | ':path', '/test?username=test'
envoy_wrapper_1  | ':method', 'GET'
envoy_wrapper_1  | ':scheme', 'http'
envoy_wrapper_1  | 'user-agent', 'curl/7.54.0'
envoy_wrapper_1  | 'accept', '*/*'
envoy_wrapper_1  | 'accept-language', 'pl'
envoy_wrapper_1  | 'x-forwarded-proto', 'http'
envoy_wrapper_1  | 'x-request-id', '65c9abab-ba2d-494e-ad60-c79e286181cb'
envoy_wrapper_1  | 'x-envoy-expected-rq-timeout-ms', '15000'

envoy_wrapper_1  | ':status', '200'
envoy_wrapper_1  | 'access-control-allow-origin', '*'
envoy_wrapper_1  | 'access-control-allow-headers', 'origin, Content-Type, Accept, Authorization'
envoy_wrapper_1  | 'content-type', 'application/json;charset=UTF-8'
envoy_wrapper_1  | 'access-control-allow-methods', 'POST, PUT, GET, OPTIONS, DELETE'
envoy_wrapper_1  | 'access-control-max-age', '3600'
envoy_wrapper_1  | 'date', 'Tue, 02 Apr 2019 08:37:11 GMT'
envoy_wrapper_1  | 'x-envoy-upstream-service-time', '146'
envoy_wrapper_1  | 'server', 'envoy'

Config

This is my route config

 "name": "default_routes",
 "virtual_hosts": [
 {
   "name": "my-service",
   "domains": [
     "my-service"
   ],
   "routes": [
   {
     "match": {
       "prefix": "/"
     },
     "route": {
       "cluster": "my-service"
     }
   }
   ]
 }]
}

Egress listener config

{
    "listener": {
     "name": "egress_listener",
     "address": {
      "socket_address": {
       "address": "0.0.0.0",
       "port_value": 6002
      }
     },
     "filter_chains": [
      {
       "filters": [
        {
         "name": "envoy.http_connection_manager",
         "config": {
          "access_log": [],
          "http_filters": [
           {
            "name": "envoy.router"
           }
          ],
          "http_protocol_options": {
           "allow_absolute_url": true
          },
          "rds": {
           "route_config_name": "default_routes",
           "config_source": {
            "ads": {},
            "initial_fetch_timeout": "20s"
           }
          },
          "stat_prefix": "egress_http"
         }
        }
       ]
      }

If you need same more information I am ready to help.

Also edited test in envoy which fails bazel test //test/common/http/http1:codec_impl_test(when I changed expected_headers : {":path", "/foo/bar"} test passed ) :

TEST_F(Http1ServerConnectionImplTest, Http11AbsolutePathWithPort) {
  TestHeaderMapImpl expected_headers{
      {":authority", "www.somewhere.com:4532"}, {":path", "/foo/bar?test=test"}, {":method", "GET"}};
  Buffer::OwnedImpl buffer(
      "GET http://www.somewhere.com:4532/foo/bar?test=test HTTP/1.1\r\nHost: bah\r\n\r\n");
  expectHeadersTest(Protocol::Http11, true, buffer, expected_headers);
}
[ RUN      ] Http1ServerConnectionImplTest.Http11AbsolutePathWithPort
unknown file: Failure

Unexpected mock function call - returning directly.
    Function call: decodeHeaders_(@0x7fd2df00c5f0 0x7fd2df00d140, true)
Google Mock tried the following 1 expectation, but it didn't match:

test/common/http/http1/codec_impl_test.cc:86: EXPECT_CALL(decoder, decodeHeaders_(HeaderMapEqual(&expected_headers), true))...
  Expected arg #0: header map equal 0x7ffee47b3d40
           Actual: 0x7fd2df00d140
         Expected: to be called once
           Actual: never called - unsatisfied and active
test/common/http/http1/codec_impl_test.cc:86: Failure
Actual function call count doesn't match EXPECT_CALL(decoder, decodeHeaders_(HeaderMapEqual(&expected_headers), true))...
         Expected: to be called once
           Actual: never called - unsatisfied and active
[  FAILED  ] Http1ServerConnectionImplTest.Http11AbsolutePathWithPort

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions