diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index c1a3b12..5ee2bf7 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -57,7 +57,7 @@ jobs: - name: run goimports working-directory: ./ run: | - go get golang.org/x/tools/cmd/goimports + go install golang.org/x/tools/cmd/goimports@v0.15.0 export PATH=$PATH:$(go env GOPATH)/bin/ diffs=`goimports -d .` if [[ -n $diffs ]]; then diff --git a/internal/http/header.go b/internal/http/header.go index 0723712..e57eb12 100644 --- a/internal/http/header.go +++ b/internal/http/header.go @@ -17,18 +17,103 @@ package http -import "net/http" +import ( + "net/http" + + "github.com/api7/ext-plugin-proto/go/A6" + hrc "github.com/api7/ext-plugin-proto/go/A6/HTTPReqCall" + flatbuffers "github.com/google/flatbuffers/go" +) + +type ReadHeader interface { + HeadersLength() int + Headers(*A6.TextEntry, int) bool +} type Header struct { - http.Header + hdr http.Header + rawHdr http.Header + + deleteField map[string]struct{} } -func newHeader() *Header { +func newHeader(r ReadHeader) *Header { + hh := http.Header{} + size := r.HeadersLength() + obj := A6.TextEntry{} + for i := 0; i < size; i++ { + if r.Headers(&obj, i) { + hh.Add(string(obj.Name()), string(obj.Value())) + } + } + return &Header{ - Header: http.Header{}, + hdr: http.Header{}, + rawHdr: hh, + + deleteField: make(map[string]struct{}), + } +} + +func (h *Header) Set(key, value string) { + h.hdr.Set(key, value) + delete(h.deleteField, key) +} + +func (h *Header) Del(key string) { + if h.rawHdr.Get(key) != "" { + h.deleteField[key] = struct{}{} + h.rawHdr.Del(key) + } + + h.hdr.Del(key) +} + +func (h *Header) Get(key string) string { + if v := h.hdr.Get(key); v != "" { + return v } + + return h.rawHdr.Get(key) } +// View +// Deprecated: refactoring func (h *Header) View() http.Header { - return h.Header + return h.hdr +} + +func (h *Header) Build(builder *flatbuffers.Builder) flatbuffers.UOffsetT { + var hdrs []flatbuffers.UOffsetT + + // deleted + for d := range h.deleteField { + name := builder.CreateString(d) + A6.TextEntryStart(builder) + A6.TextEntryAddName(builder, name) + te := A6.TextEntryEnd(builder) + hdrs = append(hdrs, te) + } + + // set + for hKey, hVal := range h.hdr { + if raw, ok := h.rawHdr[hKey]; !ok || raw[0] != hVal[0] { + name := builder.CreateString(hKey) + value := builder.CreateString(hVal[0]) + A6.TextEntryStart(builder) + A6.TextEntryAddName(builder, name) + A6.TextEntryAddValue(builder, value) + te := A6.TextEntryEnd(builder) + hdrs = append(hdrs, te) + } + } + + size := len(hdrs) + hrc.RewriteStartHeadersVector(builder, size) + for i := size - 1; i >= 0; i-- { + te := hdrs[i] + builder.PrependUOffsetT(te) + } + + return builder.EndVector(size) } diff --git a/internal/http/request.go b/internal/http/request.go index 005c5f2..21295a3 100644 --- a/internal/http/request.go +++ b/internal/http/request.go @@ -47,8 +47,7 @@ type Request struct { path []byte - hdr *Header - rawHdr http.Header + hdr *Header args url.Values rawArgs url.Values @@ -91,18 +90,9 @@ func (r *Request) SetPath(path []byte) { func (r *Request) Header() pkgHTTP.Header { if r.hdr == nil { - hdr := newHeader() - hh := hdr.View() - size := r.r.HeadersLength() - obj := A6.TextEntry{} - for i := 0; i < size; i++ { - if r.r.Headers(&obj, i) { - hh.Add(string(obj.Name()), string(obj.Value())) - } - } - r.hdr = hdr - r.rawHdr = hdr.Clone() + r.hdr = newHeader(r.r) } + return r.hdr } @@ -225,38 +215,7 @@ func (r *Request) FetchChanges(id uint32, builder *flatbuffers.Builder) bool { var hdrVec, respHdrVec flatbuffers.UOffsetT if r.hdr != nil { - hdrs := []flatbuffers.UOffsetT{} - oldHdr := r.rawHdr - newHdr := r.hdr.View() - for n := range oldHdr { - if _, ok := newHdr[n]; !ok { - // deleted - name := builder.CreateString(n) - A6.TextEntryStart(builder) - A6.TextEntryAddName(builder, name) - te := A6.TextEntryEnd(builder) - hdrs = append(hdrs, te) - } - } - for n, v := range newHdr { - if raw, ok := oldHdr[n]; !ok || raw[0] != v[0] { - // set - name := builder.CreateString(n) - value := builder.CreateString(v[0]) - A6.TextEntryStart(builder) - A6.TextEntryAddName(builder, name) - A6.TextEntryAddValue(builder, value) - te := A6.TextEntryEnd(builder) - hdrs = append(hdrs, te) - } - } - size := len(hdrs) - hrc.RewriteStartHeadersVector(builder, size) - for i := size - 1; i >= 0; i-- { - te := hdrs[i] - builder.PrependUOffsetT(te) - } - hdrVec = builder.EndVector(size) + hdrVec = r.hdr.Build(builder) } if r.respHdr != nil { diff --git a/internal/http/response.go b/internal/http/response.go index 7d7870e..c48fbaf 100644 --- a/internal/http/response.go +++ b/internal/http/response.go @@ -21,7 +21,6 @@ import ( "bytes" "encoding/binary" "net" - "net/http" "sync" "github.com/apache/apisix-go-plugin-runner/internal/util" @@ -30,7 +29,6 @@ import ( pkgHTTP "github.com/apache/apisix-go-plugin-runner/pkg/http" "github.com/apache/apisix-go-plugin-runner/pkg/log" - "github.com/api7/ext-plugin-proto/go/A6" hrc "github.com/api7/ext-plugin-proto/go/A6/HTTPRespCall" flatbuffers "github.com/google/flatbuffers/go" ) @@ -41,8 +39,7 @@ type Response struct { conn net.Conn extraInfoHeader []byte - hdr *Header - rawHdr http.Header + hdr *Header statusCode int @@ -120,18 +117,9 @@ func (r *Response) StatusCode() int { func (r *Response) Header() pkgHTTP.Header { if r.hdr == nil { - hdr := newHeader() - hh := hdr.View() - size := r.r.HeadersLength() - obj := A6.TextEntry{} - for i := 0; i < size; i++ { - if r.r.Headers(&obj, i) { - hh.Add(string(obj.Name()), string(obj.Value())) - } - } - r.hdr = hdr - r.rawHdr = hdr.Clone() + r.hdr = newHeader(r.r) } + return r.hdr } @@ -214,38 +202,7 @@ func (r *Response) FetchChanges(builder *flatbuffers.Builder) bool { var hdrVec flatbuffers.UOffsetT if r.hdr != nil { - hdrs := []flatbuffers.UOffsetT{} - oldHdr := r.rawHdr - newHdr := r.hdr.View() - for n := range oldHdr { - if _, ok := newHdr[n]; !ok { - // deleted - name := builder.CreateString(n) - A6.TextEntryStart(builder) - A6.TextEntryAddName(builder, name) - te := A6.TextEntryEnd(builder) - hdrs = append(hdrs, te) - } - } - for n, v := range newHdr { - if raw, ok := oldHdr[n]; !ok || raw[0] != v[0] { - // set - name := builder.CreateString(n) - value := builder.CreateString(v[0]) - A6.TextEntryStart(builder) - A6.TextEntryAddName(builder, name) - A6.TextEntryAddValue(builder, value) - te := A6.TextEntryEnd(builder) - hdrs = append(hdrs, te) - } - } - size := len(hdrs) - hrc.RespStartHeadersVector(builder, size) - for i := size - 1; i >= 0; i-- { - te := hdrs[i] - builder.PrependUOffsetT(te) - } - hdrVec = builder.EndVector(size) + hdrVec = r.hdr.Build(builder) } var bodyVec flatbuffers.UOffsetT diff --git a/pkg/http/http.go b/pkg/http/http.go index fdb0294..600eaa6 100644 --- a/pkg/http/http.go +++ b/pkg/http/http.go @@ -134,14 +134,18 @@ type Header interface { // It replaces any existing values associated with key. // The key is case insensitive Set(key, value string) + // Del deletes the values associated with key. The key is case insensitive Del(key string) + // Get gets the first value associated with the given key. // If there are no values associated with the key, Get returns "". // It is case insensitive Get(key string) string + // View returns the internal structure. It is expected for read operations. Any write operation // won't be recorded + //Deprecated: refactoring View() http.Header // TODO: support Add