This is an automated email from the ASF dual-hosted git repository. spacewander pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/apisix-go-plugin-runner.git
commit 05f40828227555cb4b1e181dcaddd2a70cfb543a Author: spacewander <[email protected]> AuthorDate: Fri May 28 10:18:14 2021 +0800 feat: add Args --- internal/http/request.go | 80 ++++++++++++++++++++++++++++++++++++++++++- internal/http/request_test.go | 66 ++++++++++++++++++++++++++++++++++- pkg/http/http.go | 3 ++ 3 files changed, 147 insertions(+), 2 deletions(-) diff --git a/internal/http/request.go b/internal/http/request.go index c7f2e8d..33b9f74 100644 --- a/internal/http/request.go +++ b/internal/http/request.go @@ -17,6 +17,8 @@ package http import ( "net" "net/http" + "net/url" + "reflect" "sync" pkgHTTP "github.com/apache/apisix-go-plugin-runner/pkg/http" @@ -33,6 +35,9 @@ type Request struct { hdr *Header rawHdr http.Header + + args url.Values + rawArgs url.Values } func (r *Request) ConfToken() uint32 { @@ -79,13 +84,45 @@ func (r *Request) Header() pkgHTTP.Header { return r.hdr } +func cloneUrlValues(oldV url.Values) url.Values { + nv := 0 + for _, vv := range oldV { + nv += len(vv) + } + sv := make([]string, nv) + newV := make(url.Values, len(oldV)) + for k, vv := range oldV { + n := copy(sv, vv) + newV[k] = sv[:n:n] + sv = sv[n:] + } + return newV +} + +func (r *Request) Args() url.Values { + if r.args == nil { + args := url.Values{} + size := r.r.ArgsLength() + obj := A6.TextEntry{} + for i := 0; i < size; i++ { + if r.r.Args(&obj, i) { + args.Add(string(obj.Name()), string(obj.Value())) + } + } + r.args = args + r.rawArgs = cloneUrlValues(args) + } + return r.args +} + func (r *Request) Reset() { r.path = nil r.hdr = nil + r.args = nil } func (r *Request) FetchChanges(id uint32, builder *flatbuffers.Builder) bool { - if r.path == nil && r.hdr == nil { + if r.path == nil && r.hdr == nil && r.args == nil { return false } @@ -130,6 +167,44 @@ func (r *Request) FetchChanges(id uint32, builder *flatbuffers.Builder) bool { hdrVec = builder.EndVector(size) } + var argsVec flatbuffers.UOffsetT + if r.args != nil { + args := []flatbuffers.UOffsetT{} + oldArgs := r.rawArgs + newArgs := r.args + for n := range oldArgs { + if _, ok := newArgs[n]; !ok { + // deleted + name := builder.CreateString(n) + A6.TextEntryStart(builder) + A6.TextEntryAddName(builder, name) + te := A6.TextEntryEnd(builder) + args = append(args, te) + } + } + for n, v := range newArgs { + if raw, ok := oldArgs[n]; !ok || !reflect.DeepEqual(raw, v) { + // set / add + for _, vv := range v { + name := builder.CreateString(n) + value := builder.CreateString(vv) + A6.TextEntryStart(builder) + A6.TextEntryAddName(builder, name) + A6.TextEntryAddValue(builder, value) + te := A6.TextEntryEnd(builder) + args = append(args, te) + } + } + } + size := len(args) + hrc.RewriteStartArgsVector(builder, size) + for i := size - 1; i >= 0; i-- { + te := args[i] + builder.PrependUOffsetT(te) + } + argsVec = builder.EndVector(size) + } + hrc.RewriteStart(builder) if path > 0 { hrc.RewriteAddPath(builder, path) @@ -137,6 +212,9 @@ func (r *Request) FetchChanges(id uint32, builder *flatbuffers.Builder) bool { if hdrVec > 0 { hrc.RewriteAddHeaders(builder, hdrVec) } + if argsVec > 0 { + hrc.RewriteAddArgs(builder, argsVec) + } rewrite := hrc.RewriteEnd(builder) hrc.RespStart(builder) diff --git a/internal/http/request_test.go b/internal/http/request_test.go index accaa38..64f3ebf 100644 --- a/internal/http/request_test.go +++ b/internal/http/request_test.go @@ -17,6 +17,7 @@ package http import ( "net" "net/http" + "net/url" "testing" "github.com/apache/apisix-go-plugin-runner/internal/util" @@ -49,6 +50,7 @@ type reqOpt struct { method A6.Method path string headers []pair + args []pair } func buildReq(opt reqOpt) []byte { @@ -78,7 +80,7 @@ func buildReq(opt reqOpt) []byte { hdrs = append(hdrs, te) } size := len(hdrs) - hrc.StopStartHeadersVector(builder, size) + hrc.RewriteStartHeadersVector(builder, size) for i := size - 1; i >= 0; i-- { te := hdrs[i] builder.PrependUOffsetT(te) @@ -86,6 +88,28 @@ func buildReq(opt reqOpt) []byte { hdrVec = builder.EndVector(size) } + argsLen := len(opt.args) + var argsVec flatbuffers.UOffsetT + if argsLen > 0 { + args := []flatbuffers.UOffsetT{} + for _, v := range opt.args { + name := builder.CreateString(v.name) + value := builder.CreateString(v.value) + A6.TextEntryStart(builder) + A6.TextEntryAddName(builder, name) + A6.TextEntryAddValue(builder, value) + te := A6.TextEntryEnd(builder) + args = append(args, te) + } + size := len(args) + hrc.RewriteStartArgsVector(builder, size) + for i := size - 1; i >= 0; i-- { + te := args[i] + builder.PrependUOffsetT(te) + } + argsVec = builder.EndVector(size) + } + hrc.ReqStart(builder) hrc.ReqAddId(builder, 233) hrc.ReqAddConfToken(builder, 1) @@ -101,6 +125,9 @@ func buildReq(opt reqOpt) []byte { if hdrVec > 0 { hrc.ReqAddHeaders(builder, hdrVec) } + if argsVec > 0 { + hrc.ReqAddArgs(builder, argsVec) + } r := hrc.ReqEnd(builder) builder.Finish(r) return builder.FinishedBytes() @@ -187,3 +214,40 @@ func TestHeader(t *testing.T) { } assert.Equal(t, exp, res) } + +func TestArgs(t *testing.T) { + out := buildReq(reqOpt{args: []pair{ + {"del", "a"}, + {"override", "a"}, + {"add", "a"}, + }}) + r := CreateRequest(out) + args := r.Args() + args.Add("add", "b") + args.Set("set", "a") + args.Set("override", "b") + args.Del("del") + + builder := util.GetBuilder() + assert.True(t, r.FetchChanges(1, builder)) + rewrite := getRewriteAction(t, builder) + + exp := url.Values{} + exp.Set("set", "a") + exp.Set("override", "b") + exp.Add("add", "a") + exp.Add("add", "b") + deleted := "" + res := url.Values{} + for i := 0; i < rewrite.ArgsLength(); i++ { + e := &A6.TextEntry{} + rewrite.Args(e, i) + if e.Value() == nil { + deleted = string(e.Name()) + } else { + res.Add(string(e.Name()), string(e.Value())) + } + } + assert.Equal(t, exp, res) + assert.Equal(t, "del", deleted) +} diff --git a/pkg/http/http.go b/pkg/http/http.go index cbbceeb..cfc4284 100644 --- a/pkg/http/http.go +++ b/pkg/http/http.go @@ -17,6 +17,7 @@ package http import ( "net" "net/http" + "net/url" ) // Request represents the HTTP request received by APISIX. @@ -43,6 +44,8 @@ type Request interface { SetPath([]byte) // Header returns the HTTP headers Header() Header + // Args returns the query string + Args() url.Values } // Header is like http.Header, but only implements the subset of its methods
