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

SetBuffer OnRequestBody return 400 Bad Request occasionally #127

Closed
Xunzhuo opened this issue Aug 2, 2021 · 4 comments
Closed

SetBuffer OnRequestBody return 400 Bad Request occasionally #127

Xunzhuo opened this issue Aug 2, 2021 · 4 comments

Comments

@Xunzhuo
Copy link
Contributor

Xunzhuo commented Aug 2, 2021

When I try to change request body, I got 400 response occasionally. Sometimes envoy respond in expectation and sometimes respond in 400 Bad request

I use curl -d "Hello,World" localhost:18000/ to send request

Envoy log is below:

[2021-08-02 17:19:08.426][3314310][debug][conn_handler] [source/server/active_tcp_listener.cc:328] [C2] new connection
[2021-08-02 17:19:08.426][3314310][debug][http] [source/common/http/conn_manager_impl.cc:261] [C2] new stream
[2021-08-02 17:19:08.426][3314310][debug][http] [source/common/http/conn_manager_impl.cc:882] [C2][S7336547734171909877] request headers complete (end_stream=false):
':authority', 'localhost:18000'
':path', '/'
':method', 'POST'
'user-agent', 'curl/7.61.1'
'accept', '*/*'
'content-length', '11'
'content-type', 'application/x-www-form-urlencoded'

[2021-08-02 17:19:08.426][3314310][debug][router] [source/common/router/router.cc:445] [C2][S7336547734171909877] cluster 'httpbin' match for URL '/'
[2021-08-02 17:19:08.426][3314310][debug][router] [source/common/router/router.cc:631] [C2][S7336547734171909877] router decoding headers:
':authority', 'localhost:18000'
':path', '/'
':method', 'POST'
':scheme', 'http'
'user-agent', 'curl/7.61.1'
'accept', '*/*'
'content-length', '11'
'content-type', 'application/x-www-form-urlencoded'
'x-forwarded-proto', 'http'
'x-request-id', 'c89942ff-89da-461e-a70d-bed81b3efbe6'
'x-envoy-expected-rq-timeout-ms', '15000'

[2021-08-02 17:19:08.426][3314310][debug][pool] [source/common/conn_pool/conn_pool_base.cc:232] [C1] using existing connection
[2021-08-02 17:19:08.426][3314310][debug][pool] [source/common/conn_pool/conn_pool_base.cc:171] [C1] creating stream
[2021-08-02 17:19:08.426][3314310][debug][router] [source/common/router/upstream_request.cc:371] [C2][S7336547734171909877] pool ready
[2021-08-02 17:19:08.426][3314310][debug][http] [source/common/http/filter_manager.cc:779] [C2][S7336547734171909877] request end stream
[2021-08-02 17:19:08.426][3314310][debug][router] [source/common/router/router.cc:1244] [C2][S7336547734171909877] upstream headers complete: end_stream=false
[2021-08-02 17:19:08.426][3314310][debug][http] [source/common/http/conn_manager_impl.cc:1469] [C2][S7336547734171909877] encoding headers via codec (end_stream=false):
':status', '400'
'content-type', 'text/plain; charset=utf-8'
'x-envoy-upstream-service-time', '0'
'date', 'Mon, 02 Aug 2021 09:19:08 GMT'
'server', 'envoy'

[2021-08-02 17:19:08.426][3314310][debug][connection] [source/common/network/connection_impl.cc:633] [C1] remote close
[2021-08-02 17:19:08.426][3314310][debug][connection] [source/common/network/connection_impl.cc:243] [C1] closing socket: 0
[2021-08-02 17:19:08.426][3314310][debug][client] [source/common/http/codec_client.cc:124] [C1] response complete
[2021-08-02 17:19:08.426][3314310][debug][pool] [source/common/http/http1/conn_pool.cc:53] [C1] response complete
[2021-08-02 17:19:08.426][3314310][debug][pool] [source/common/http/http1/conn_pool.cc:59] [C1] saw upstream close connection
[2021-08-02 17:19:08.426][3314310][debug][client] [source/common/http/codec_client.cc:101] [C1] disconnect. resetting 0 pending requests
[2021-08-02 17:19:08.426][3314310][debug][pool] [source/common/conn_pool/conn_pool_base.cc:393] [C1] client disconnected, failure reason: 
[2021-08-02 17:19:08.426][3314310][debug][pool] [source/common/conn_pool/conn_pool_base.cc:200] [C1] destroying stream: 1 remaining
[2021-08-02 17:19:08.426][3314310][debug][connection] [source/common/network/connection_impl.cc:633] [C2] remote close
[2021-08-02 17:19:08.426][3314310][debug][connection] [source/common/network/connection_impl.cc:243] [C2] closing socket: 0
[2021-08-02 17:19:08.426][3314310][debug][conn_handler] [source/server/active_tcp_listener.cc:76] [C2] adding to cleanup list

wasm c++ code:

#include <string>
#include <string_view>
#include <unordered_map>

#include "proxy_wasm_intrinsics.h"

class ExampleContext : public Context {
public:
  explicit ExampleContext(uint32_t id, RootContext *root) : Context(id, root) {}
  FilterDataStatus onRequestBody(size_t body_buffer_length, bool end_of_stream) override;

};
static RegisterContextFactory register_ExampleContext(CONTEXT_FACTORY(ExampleContext),
                                                      "my_root_id");

FilterDataStatus ExampleContext::onRequestBody(size_t body_buffer_length,
                                               bool /* end_of_stream */) {
  setBuffer(WasmBufferType::HttpRequestBody, 0, body_buffer_length , "Hello Envoy!");
  return FilterDataStatus::Continue;
}

envoy config is:

static_resources:
  listeners:
    - name: main
      address:
        socket_address:
          address: 0.0.0.0
          port_value: 18000
      filter_chains:
        - filters:
            - name: envoy.http_connection_manager
              typed_config:
                "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
                stat_prefix: ingress_http
                codec_type: auto
                route_config:
                  name: httpbin
                  virtual_hosts:
                    - name: httpbin
                      domains:
                        - "*"
                      routes:
                        - match:
                            prefix: "/"
                          route:
                            cluster: httpbin
                http_filters:
                  - name: envoy.filters.http.wasm
                    typed_config:
                      "@type": type.googleapis.com/envoy.extensions.filters.http.wasm.v3.Wasm
                      config:
                        name: "my_plugin"
                        root_id: "my_root_id"
                        vm_config:
                          vm_id: "my_vm_id"
                          runtime: "envoy.wasm.runtime.v8"
                          code:
                            local:
                              filename: "./resbody.wasm"
                          allow_precompiled: true
              
                  - name: envoy.filters.http.router
                    typed_config: {}

  clusters:
    - name: httpbin
      connect_timeout: 5000s
      type: strict_dns
      lb_policy: round_robin
      load_assignment:
        cluster_name: httpbin
        endpoints:
          - lb_endpoints:
              - endpoint:
                  address:
                    socket_address:
                      address: 0.0.0.0
                      port_value: 9000

admin:
  access_log_path: "/dev/null"
  address:
    socket_address:
      address: 0.0.0.0
      port_value: 8002

upstream is coded by Golang http package:

package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
)

func hello(w http.ResponseWriter, req *http.Request) {
	requestMessage(w, req)
	log.Println("Get connection Success!")
	w.Write([]byte("Hello Envoy at 0.0.0.0:9000!"))
}

func requestMessage(w http.ResponseWriter, req *http.Request) {
	for name, headers := range req.Header {
		for _, h := range headers {
			fmt.Fprintf(w, "%v: %v\n", name, h)
		}
	}
	s, err := ioutil.ReadAll(req.Body)
	if err != nil {
		fmt.Fprintf(w, "Read Body failed")
		return
	}
	fmt.Fprintf(w, "Request body is: %s\n", s)
}

func main() {
	log.Println("Start to listen 0.0.0.0:9000, prefix: /")
	http.HandleFunc("/", hello)
	http.ListenAndServe(":9000", nil)
}

Expected response from upstream is:

image

Sometimes it return:

image

@Xunzhuo Xunzhuo changed the title SetBuffer OnRequestBody return 400 Bad Request SetBuffer OnRequestBody return 400 Bad Request occasionally Aug 2, 2021
@Xunzhuo
Copy link
Contributor Author

Xunzhuo commented Aug 2, 2021

@PiotrSikora @mathetake This problem confused me, please check this when u are free.

@mathetake mathetake transferred this issue from proxy-wasm/proxy-wasm-cpp-host Aug 2, 2021
@PiotrSikora
Copy link
Contributor

@Xunzhuo you're replacing request body, possibly mutliple times (OnRequestBody is called for each request body chunk), but you don't modify the headers that include Content-Length header, so the updated body doesn't match expected length, hence 400 Bad Request.

If you want to replace complete body, you need to remove Content-Length header (or replace it if you know the correct value ahead of time), and then you can either wait until end_of_stream is true, or simply replace request body the first callback, and discard future chunks in subsequent calls, but you need to code that in your plugin, since that's not something that works out of the box right now.

@Xunzhuo
Copy link
Contributor Author

Xunzhuo commented Aug 3, 2021

@PiotrSikora Thanks, problems have been solved by your guide😊

@Xunzhuo Xunzhuo closed this as completed Aug 3, 2021
@coolg92003
Copy link

@PiotrSikora Thanks, problems have been solved by your guide😊

How do u change the Content-Length header in onRequestBody(), according to WASM doc, it can't modify HTTP header in onRequestBody().
Would you share your code?
thanks
Cliff

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

No branches or pull requests

3 participants