You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@apisix.apache.org by sp...@apache.org on 2021/05/31 02:07:27 UTC

[apisix-go-plugin-runner] 20/22: feat: add Args

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 <sp...@gmail.com>
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