zxyao145 commented on issue #9887:
URL: https://github.com/apache/apisix/issues/9887#issuecomment-1649553951
@Revolyssup Hi, `TestDispatchHttpCall` is my business logic, only blurring
the domain name and path, all I have to do is call the external http api to get
some configuration information in the wasm plugin.
I copied the forward-auth plugin and modified the dispatchHttpCall method,
but now I have another error:
```
2023/07/25 18:00:00 [error] 188#188: failed to call function: wasm trap:
wasm `unreachable` instruction executed
wasm backtrace:
0: 0x40bb - <unknown>!runtime.runtimePanic
1: 0x40a2 - <unknown>!internal/task.Pause
2: 0x28292 - <unknown>!proxy_on_request_headers
```
This time it didn't even reach `proxywasm.LogErrorf("TestDispatchHttpCall
Error: %+v", err)`
And my code for the plugin is as follows:
<details><summary>plugin.go</summary>
```go
package main
import (
"encoding/json"
"fmt"
"net/url"
"strconv"
"strings"
"time"
"github.com/tetratelabs/proxy-wasm-go-sdk/proxywasm"
"github.com/tetratelabs/proxy-wasm-go-sdk/proxywasm/types"
"github.com/valyala/fastjson"
)
func main() {
proxywasm.SetVMContext(&vmContext{})
}
type vmContext struct {
types.DefaultVMContext
}
func (*vmContext) NewPluginContext(contextID uint32) types.PluginContext {
return &pluginContext{
contextID: contextID,
upstreamHeaders: map[string]struct{}{},
clientHeaders: map[string]struct{}{},
requestHeaders: map[string]struct{}{},
}
}
type pluginContext struct {
types.DefaultPluginContext
contextID uint32
host string
path string
scheme string
upstreamHeaders map[string]struct{}
clientHeaders map[string]struct{}
requestHeaders map[string]struct{}
timeout uint32
}
func (ctx *pluginContext) OnPluginStart(pluginConfigurationSize int)
types.OnPluginStartStatus {
data, err := proxywasm.GetPluginConfiguration()
if err != nil {
proxywasm.LogErrorf("error reading plugin configuration: %v",
err)
return types.OnPluginStartStatusFailed
}
var p fastjson.Parser
v, err := p.ParseBytes(data)
if err != nil {
proxywasm.LogErrorf("error decoding plugin configuration: %v",
err)
return types.OnPluginStartStatusFailed
}
ctx.timeout = uint32(v.GetUint("timeout"))
if ctx.timeout == 0 {
ctx.timeout = 3000
}
// schema check
if ctx.timeout < 1 || ctx.timeout > 60000 {
proxywasm.LogError("bad timeout")
return types.OnPluginStartStatusFailed
}
s := string(v.GetStringBytes("uri"))
if s == "" {
proxywasm.LogError("bad uri")
return types.OnPluginStartStatusFailed
}
uri, err := url.Parse(s)
if err != nil {
proxywasm.LogErrorf("bad uri: %v", err)
return types.OnPluginStartStatusFailed
}
ctx.host = uri.Host
ctx.path = uri.Path
ctx.scheme = uri.Scheme
arr := v.GetArray("upstream_headers")
for _, a := range arr {
ctx.upstreamHeaders[strings.ToLower(string(a.GetStringBytes()))] = struct{}{}
}
arr = v.GetArray("request_headers")
for _, a := range arr {
ctx.requestHeaders[string(a.GetStringBytes())] = struct{}{}
}
arr = v.GetArray("client_headers")
for _, a := range arr {
ctx.clientHeaders[strings.ToLower(string(a.GetStringBytes()))]
= struct{}{}
}
return types.OnPluginStartStatusOK
}
func (pluginCtx *pluginContext) NewHttpContext(contextID uint32)
types.HttpContext {
ctx := &httpContext{contextID: contextID, pluginCtx: pluginCtx}
return ctx
}
type httpContext struct {
types.DefaultHttpContext
contextID uint32
pluginCtx *pluginContext
}
func (ctx *httpContext) dispatchHttpCall(elem *fastjson.Value) {
TestDispatchHttpCall()
// method, _ := proxywasm.GetHttpRequestHeader(":method")
// uri, _ := proxywasm.GetHttpRequestHeader(":path")
// scheme, _ := proxywasm.GetHttpRequestHeader(":scheme")
// host, _ := proxywasm.GetHttpRequestHeader("host")
// addr, _ := proxywasm.GetProperty([]string{"remote_addr"})
// pctx := ctx.pluginCtx
// hs := [][2]string{}
// hs = append(hs, [2]string{":scheme", pctx.scheme})
// hs = append(hs, [2]string{"host", pctx.host})
// hs = append(hs, [2]string{":path", pctx.path})
// hs = append(hs, [2]string{"X-Forwarded-Proto", scheme})
// hs = append(hs, [2]string{"X-Forwarded-Method", method})
// hs = append(hs, [2]string{"X-Forwarded-Host", host})
// hs = append(hs, [2]string{"X-Forwarded-Uri", uri})
// hs = append(hs, [2]string{"X-Forwarded-For", string(addr)})
// for k := range pctx.requestHeaders {
// h, err := proxywasm.GetHttpRequestHeader(k)
// if err != nil && err != types.ErrorStatusNotFound {
// proxywasm.LogErrorf("httpcall failed: %v", err)
// return
// }
// hs = append(hs, [2]string{k, h})
// }
// calloutID, err := proxywasm.DispatchHttpCall(pctx.host, hs, nil, nil,
// pctx.timeout, ctx.httpCallback)
// if err != nil {
// proxywasm.LogErrorf("httpcall failed: %v", err)
// return
// }
// proxywasm.LogInfof("httpcall calloutID %d, pluginCtxID %d",
calloutID, ctx.pluginCtx.contextID)
}
func (ctx *httpContext) OnHttpRequestHeaders(numHeaders int, endOfStream
bool) types.Action {
data, err := proxywasm.GetPluginConfiguration()
if err != nil {
proxywasm.LogErrorf("error reading plugin configuration: %v",
err)
return types.ActionContinue
}
var p fastjson.Parser
v, err := p.ParseBytes(data)
if err != nil {
proxywasm.LogErrorf("error decoding plugin configuration: %v",
err)
return types.ActionContinue
}
ctx.dispatchHttpCall(v)
return types.ActionContinue
}
func (ctx *httpContext) httpCallback(numHeaders int, bodySize int,
numTrailers int) {
hs, err := proxywasm.GetHttpCallResponseHeaders()
if err != nil {
proxywasm.LogErrorf("callback err: %v", err)
return
}
var status int
for _, h := range hs {
if h[0] == ":status" {
status, _ = strconv.Atoi(h[1])
}
if _, ok := ctx.pluginCtx.upstreamHeaders[h[0]]; ok {
err := proxywasm.ReplaceHttpRequestHeader(h[0], h[1])
if err != nil {
proxywasm.LogErrorf("set header failed: %v",
err)
}
}
}
if status >= 300 {
chs := [][2]string{}
for _, h := range hs {
if _, ok := ctx.pluginCtx.clientHeaders[h[0]]; ok {
chs = append(chs, [2]string{h[0], h[1]})
}
}
if err := proxywasm.SendHttpResponse(403, chs, nil, -1); err !=
nil {
proxywasm.LogErrorf("send http failed: %v", err)
return
}
}
}
func TestDispatchHttpCall() (string, error) {
proxywasm.LogWarnf("TestDispatchHttpCall!")
defer func() {
if err := recover(); err != nil {
proxywasm.LogErrorf("TestDispatchHttpCall panic! %+v",
err)
}
}()
urlStr := "http://xxx.com/api/healthz"
uri, err := url.Parse(urlStr)
if err != nil {
proxywasm.LogErrorf("TestDispatchHttpCall url.Parse Error:
%+v", err)
return "", err
}
hs := [][2]string{}
hs = append(hs, [2]string{":scheme", uri.Scheme})
hs = append(hs, [2]string{"host", uri.Host})
hs = append(hs, [2]string{":path", uri.Path})
hs = append(hs, [2]string{":method", "GET"})
var bodyCh = make(chan []byte)
defer close(bodyCh)
proxywasm.LogWarnf("TestDispatchHttpCall info: %s, %+v", uri.Host, hs)
_, err = proxywasm.DispatchHttpCall(uri.Host, hs, nil, nil, 5000,
func(numHeaders, bodySize, numTrailers int) {
proxywasm.LogWarn("TestDispatchHttpCall callback!")
bodyBytes, err := proxywasm.GetHttpCallResponseBody(0, bodySize)
if err != nil {
proxywasm.LogErrorf("TestDispatchHttpCall callback
Error: %+v", err)
return
}
bodyCh <- bodyBytes
})
if err != nil {
proxywasm.LogErrorf("TestDispatchHttpCall Error: %+v", err)
return "", err
}
select {
case body := <-bodyCh:
proxywasm.LogWarnf("TestDispatchHttpCall receive body! %s", "")
var rspJson map[string]string
err = json.Unmarshal(body, &rspJson)
if err != nil {
proxywasm.LogErrorf("Error: %+v", err)
return "", err
}
proxywasm.LogWarnf("TestDispatchHttpCall receive rspJson %s",
rspJson)
return "", nil
case <-time.After(time.Second * 2):
return "", fmt.Errorf("call timeout")
}
}
```
</details>
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]