Skip to content

Commit

Permalink
fix: write response header should not break req (#65)
Browse files Browse the repository at this point in the history
  • Loading branch information
spacewander committed Feb 14, 2022
1 parent 6bb1c4b commit 1a00a4b
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 5 deletions.
7 changes: 5 additions & 2 deletions docs/en/latest/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,12 @@ func (p *Say) Filter(conf interface{}, w http.ResponseWriter, r pkgHTTP.Request)
}
```

We can see that the Filter takes the value of the body set in the configuration as the response body. If we respond directly in the plugin, it will response directly in the APISIX without touching the upstream.
We can see that the Filter takes the value of the body set in the configuration as the response body. If we call `Write` or `WriteHeader` of the `http.ResponseWriter`
(respond directly in the plugin), it will response directly in the APISIX without touching the upstream. As we only support setting headers of local response,
calling `Header` won't take any effects without calling `Write` or `WriteHeader`. (TODO: support setting response header separately)

Here you can read the API documentation provided by the Go Runner SDK: https://pkg.go.dev/github.com/apache/apisix-go-plugin-runner
For the `pkgHTTP.Request`, you can refer to the API documentation provided by the Go Runner SDK:
https://pkg.go.dev/github.com/apache/apisix-go-plugin-runner

After building the application (`make build` in the example), we need to set some environment variables at runtime:

Expand Down
4 changes: 3 additions & 1 deletion internal/http/response.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ func (r *Response) Write(b []byte) (int, error) {
r.body = &bytes.Buffer{}
}

// APISIX will convert code 0 to 200, so we don't need to WriteHeader(http.StatusOK)
// before writing the data
return r.body.Write(b)
}

Expand All @@ -64,7 +66,7 @@ func (r *Response) Reset() {
}

func (r *Response) HasChange() bool {
return !(r.body == nil && r.code == 0 && len(r.hdr) == 0)
return !(r.body == nil && r.code == 0)
}

func (r *Response) FetchChanges(id uint32, builder *flatbuffers.Builder) bool {
Expand Down
4 changes: 2 additions & 2 deletions internal/plugin/conf.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,8 @@ func (cc *ConfCache) Set(req *pc.Req) (uint32, error) {
conf, err := plugin.ParseConf(v)
if err != nil {
log.Errorf(
"failed to parse configuration for plugin %s, configuration: %s",
name, string(v))
"failed to parse configuration for plugin %s, configuration: %s, err: %v",
name, string(v), err)
continue
}

Expand Down
42 changes: 42 additions & 0 deletions internal/plugin/plugin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,7 @@ func TestFilter(t *testing.T) {
}
fooFilter := func(conf interface{}, w http.ResponseWriter, r pkgHTTP.Request) {
w.Header().Add("foo", "bar")
w.WriteHeader(200)
assert.Equal(t, "foo", conf.(string))
}
barParseConf := func(in []byte) (conf interface{}, err error) {
Expand Down Expand Up @@ -333,3 +334,44 @@ func TestFilter(t *testing.T) {
assert.Equal(t, "bar", resp.Header().Get("foo"))
assert.Equal(t, "bar", req.Header().Get("foo"))
}

func TestFilter_SetRespHeaderDoNotBreakReq(t *testing.T) {
InitConfCache(1 * time.Millisecond)

barParseConf := func(in []byte) (conf interface{}, err error) {
return "", nil
}
barFilter := func(conf interface{}, w http.ResponseWriter, r pkgHTTP.Request) {
r.Header().Set("foo", "bar")
}
filterSetRespParseConf := func(in []byte) (conf interface{}, err error) {
return "", nil
}
filterSetRespFilter := func(conf interface{}, w http.ResponseWriter, r pkgHTTP.Request) {
w.Header().Add("foo", "baz")
}
RegisterPlugin("bar", barParseConf, barFilter)
RegisterPlugin("filterSetResp", filterSetRespParseConf, filterSetRespFilter)

builder := flatbuffers.NewBuilder(1024)
barName := builder.CreateString("bar")
barConf := builder.CreateString("a")
filterSetRespName := builder.CreateString("filterSetResp")
filterSetRespConf := builder.CreateString("a")
prepareConfWithData(builder, filterSetRespName, filterSetRespConf, barName, barConf)

res, _ := GetRuleConf(1)
hrc.ReqStart(builder)
hrc.ReqAddId(builder, 233)
hrc.ReqAddConfToken(builder, 1)
r := hrc.ReqEnd(builder)
builder.Finish(r)
out := builder.FinishedBytes()

req := inHTTP.CreateRequest(out)
resp := inHTTP.CreateResponse()
filter(res, resp, req)

assert.Equal(t, "bar", req.Header().Get("foo"))
assert.Equal(t, "baz", resp.Header().Get("foo"))
}

0 comments on commit 1a00a4b

Please sign in to comment.