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:21 UTC

[apisix-go-plugin-runner] 14/22: feat: extend pkg Request

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 d8647f9bf36785c976fd0400abab488ead73212d
Author: spacewander <sp...@gmail.com>
AuthorDate: Tue May 25 14:58:51 2021 +0800

    feat: extend pkg Request
---
 internal/http/request.go      |  54 +++++++++++++++++++-
 internal/http/request_test.go | 113 ++++++++++++++++++++++++++++++++++++++++++
 internal/plugin/plugin.go     |   2 +-
 pkg/http/http.go              |  16 +++++-
 4 files changed, 180 insertions(+), 5 deletions(-)

diff --git a/internal/http/request.go b/internal/http/request.go
index 596b0c4..570c245 100644
--- a/internal/http/request.go
+++ b/internal/http/request.go
@@ -15,22 +15,72 @@
 package http
 
 import (
+	"net"
+
 	hrc "github.com/api7/ext-plugin-proto/go/A6/HTTPReqCall"
+	flatbuffers "github.com/google/flatbuffers/go"
 )
 
 type Request struct {
 	// the root of the flatbuffers HTTPReqCall Request msg
 	r *hrc.Req
+
+	path []byte
 }
 
-func (r Request) ConfToken() uint32 {
+func (r *Request) ConfToken() uint32 {
 	return r.r.ConfToken()
 }
 
-func (r Request) Id() uint32 {
+func (r *Request) ID() uint32 {
 	return r.r.Id()
 }
 
+func (r *Request) SrcIP() net.IP {
+	return r.r.SrcIpBytes()
+}
+
+func (r *Request) Method() string {
+	return r.r.Method().String()
+}
+
+func (r *Request) Path() []byte {
+	if r.path == nil {
+		return r.r.Path()
+	}
+	return r.path
+}
+
+func (r *Request) SetPath(path []byte) {
+	r.path = path
+}
+
+func (r *Request) FetchChanges(id uint32, builder *flatbuffers.Builder) bool {
+	if r.path == nil {
+		return false
+	}
+
+	var path flatbuffers.UOffsetT
+	if r.path != nil {
+		path = builder.CreateByteString(r.path)
+	}
+
+	hrc.RewriteStart(builder)
+	if path > 0 {
+		hrc.RewriteAddPath(builder, path)
+	}
+	rewrite := hrc.RewriteEnd(builder)
+
+	hrc.RespStart(builder)
+	hrc.RespAddId(builder, id)
+	hrc.RespAddActionType(builder, hrc.ActionRewrite)
+	hrc.RespAddAction(builder, rewrite)
+	res := hrc.RespEnd(builder)
+	builder.Finish(res)
+
+	return true
+}
+
 func CreateRequest(buf []byte) *Request {
 	req := &Request{
 		r: hrc.GetRootAsReq(buf, 0),
diff --git a/internal/http/request_test.go b/internal/http/request_test.go
new file mode 100644
index 0000000..667138e
--- /dev/null
+++ b/internal/http/request_test.go
@@ -0,0 +1,113 @@
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements.  See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package http
+
+import (
+	"net"
+	"testing"
+
+	"github.com/apache/apisix-go-plugin-runner/internal/util"
+	"github.com/api7/ext-plugin-proto/go/A6"
+	hrc "github.com/api7/ext-plugin-proto/go/A6/HTTPReqCall"
+	flatbuffers "github.com/google/flatbuffers/go"
+	"github.com/stretchr/testify/assert"
+)
+
+func getRewriteAction(t *testing.T, b *flatbuffers.Builder) *hrc.Rewrite {
+	buf := b.FinishedBytes()
+	res := hrc.GetRootAsResp(buf, 0)
+	tab := &flatbuffers.Table{}
+	if res.Action(tab) {
+		assert.Equal(t, hrc.ActionRewrite, res.ActionType())
+		rewrite := &hrc.Rewrite{}
+		rewrite.Init(tab.Bytes, tab.Pos)
+		return rewrite
+	}
+	return nil
+}
+
+type reqOpt struct {
+	srcIP  []byte
+	method A6.Method
+	path   string
+}
+
+func buildReq(opt reqOpt) []byte {
+	builder := flatbuffers.NewBuilder(1024)
+
+	var ip flatbuffers.UOffsetT
+	if len(opt.srcIP) > 0 {
+		ip = builder.CreateByteVector(opt.srcIP)
+	}
+
+	var path flatbuffers.UOffsetT
+	if opt.path != "" {
+		path = builder.CreateString(opt.path)
+	}
+
+	hrc.ReqStart(builder)
+	hrc.ReqAddId(builder, 233)
+	hrc.ReqAddConfToken(builder, 1)
+	if ip > 0 {
+		hrc.ReqAddSrcIp(builder, ip)
+	}
+	if opt.method != 0 {
+		hrc.ReqAddMethod(builder, opt.method)
+	}
+	if path > 0 {
+		hrc.ReqAddPath(builder, path)
+	}
+	r := hrc.ReqEnd(builder)
+	builder.Finish(r)
+	return builder.FinishedBytes()
+}
+
+func TestSrcIp(t *testing.T) {
+	for _, ip := range []net.IP{
+		net.IPv4(127, 0, 0, 1),
+		net.IPv4(127, 2, 3, 1),
+		net.ParseIP("2001:db8::68"),
+		net.ParseIP("::12"),
+	} {
+		out := buildReq(reqOpt{srcIP: ip})
+		r := CreateRequest(out)
+		assert.Equal(t, ip, r.SrcIP())
+	}
+}
+
+func TestMethod(t *testing.T) {
+	for _, m := range []A6.Method{
+		A6.MethodGET,
+		A6.MethodPATCH,
+	} {
+		out := buildReq(reqOpt{method: m})
+		r := CreateRequest(out)
+		assert.Equal(t, m.String(), r.Method())
+	}
+}
+
+func TestPath(t *testing.T) {
+	out := buildReq(reqOpt{path: "/apisix"})
+	r := CreateRequest(out)
+	assert.Equal(t, "/apisix", string(r.Path()))
+
+	r.SetPath([]byte("/go"))
+	assert.Equal(t, "/go", string(r.Path()))
+
+	builder := util.GetBuilder()
+	assert.True(t, r.FetchChanges(1, builder))
+	rewrite := getRewriteAction(t, builder)
+	assert.Equal(t, "/go", string(rewrite.Path()))
+}
diff --git a/internal/plugin/plugin.go b/internal/plugin/plugin.go
index e4d9ef6..3ca4159 100644
--- a/internal/plugin/plugin.go
+++ b/internal/plugin/plugin.go
@@ -57,7 +57,7 @@ func HTTPReqCall(buf []byte) (*flatbuffers.Builder, error) {
 		return nil, err
 	}
 
-	id := req.Id()
+	id := req.ID()
 	builder := reportAction(id, req, resp)
 	return builder, nil
 }
diff --git a/pkg/http/http.go b/pkg/http/http.go
index de83956..ebae8ac 100644
--- a/pkg/http/http.go
+++ b/pkg/http/http.go
@@ -14,6 +14,8 @@
 // limitations under the License.
 package http
 
+import "net"
+
 // Request represents the HTTP request received by APISIX.
 // We don't use net/http's Request because it doesn't suit our purpose.
 // Take `Request.Header` as an example:
@@ -24,6 +26,16 @@ package http
 // So the server must parse all the headers, ...". The official API is suboptimal, which
 // is even worse in our case as it is not a real HTTP server.
 type Request interface {
-	// Id returns the request id
-	Id() uint32
+	// ID returns the request id
+	ID() uint32
+	// SrcIP returns the client's IP
+	SrcIP() net.IP
+	// Method returns the HTTP method (GET, POST, PUT, etc.)
+	Method() string
+	// Path returns the path part of the client's URI (without query string and the other parts)
+	// It won't be equal to the one in the Request-Line sent by the client if it has
+	// been rewritten by APISIX
+	Path() []byte
+	// SetPath is the setter for Path
+	SetPath([]byte)
 }