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

Reply via email to