How to use the response from DispatchHttpCall to modify the request headers
amar1104 opened this issue · 6 comments
Hi, I am trying to build an envoy filter on istio using proxy-wasm-go. I want to intercept the requests using wasm filter and send a http request to an external service and use the response to modify the original request headers before passing it to next filter. I have tried using DispatchHttpCall but not able to update the original request from the callback. I tried using channels but the filter panics with the below error.
2023-06-01T11:28:49.027232Z error envoy wasm external/envoy/source/extensions/common/wasm/wasm_vm.cc:38 Function: proxy_on_request_headers failed: Uncaught RuntimeError: unreachable Proxy-Wasm plugin in-VM backtrace: 0: 0x5d4c - runtime.runtimePanic 1: 0x2972 - runtime.nilPanic 2: 0x21134 - proxy_on_request_headers thread=24 2023-06-01T11:58:19.234217Z info xdsproxy connected to upstream XDS server: istiod.istio-system.svc:15012
Is there any way to solve this issue?
Hi @jcchavezs please find the code below
func (ctx *httpHeaders) OnHttpRequestHeaders(numHeaders int, endOfStream bool) types.Action {
gatewayLoggerReqHeaders := [][2]string{
{":method", "GET"}, {":path", "/node"}, {":authority", "service.external.in"}, {":scheme", "http"},
}
var nodeHeader string
//ch := make(chan string)
if _, err := DispatchHttpCall("outbound|8080||service.external.in", gatewayLoggerReqHeaders, nil,
nil, 5000, func(numHeaders, bodySize, numTrailers int) {
headers, err := proxywasm.GetHttpCallResponseHeaders()
if err != nil && err != types.ErrorStatusNotFound {
proxywasm.LogError(err.Error())
}
for _, h := range headers {
proxywasm.LogWarnf("response header for the dispatched call: %s: %s", h[0], h[1])
if strings.ToLower(h[0]) == "x-authz-node" {
nodeHeader = strings.ToLower(h[1])
}
}
//ch <- "done"
}); err != nil {
proxywasm.LogCriticalf("dispatch httpcall failed: %v", err)
}
//_ = <- ch
_ = proxywasm.AddHttpRequestHeader("X-Authz-Node",nodeHeader)
return types.ActionContinue
}
Command to build the wasm
tinygo build -o main.wasm -scheduler=none -target=wasi main.go
@jcchavezs Can you please provide your thoughts. Also can we make synchronous httpCall inside OnHttpRequestHeaders.
@amar1104
My understanding is you did not pause your request in the main flow. So that the original request will continue to the next filter immediately. And when the callback is evoked, the request is at another filter or context which leads to the error.
Here is a pseudo-code that should work.
if _, err := proxywasm.DispatchHttpCall(
"outbound|80||a-svc.default.svc.cluster.local",
headers,
nil,
nil,
5000,
dispatchCallback,
); err != nil {
panic(err)
}
return types.ActionPause
func () dispatchCallback(numHeaders, bodySize, numTrailers int) {
proxywasm.LogInfof("executing the callback")
response, _ := GetResponse()
responseBody, _ := response.GetBody()
proxywasm.LogInfof("Response body in callback: %s", responseBody)
proxywasm.ReplaceHttpRequestHeader("body", responseBody)
proxywasm.ResumeHttpRequest()
}
@MengjiaLiang Thanks for the suggestion, this is working. Earlier I tried this by putting proxywasm.ResumeHttpRequest()
before proxywasm.ReplaceHttpRequestHeader("body", responseBody)
and it was not working. Looks like ResumeHttpRequest should happen at the end of the callback
@amar1104 You are welcome! Yep, the ResumeHttpRequest should be the end of the callback func. That host call basically takes effect immediately.