fill request with header and cookie data

Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
This commit is contained in:
Василий Толстов 2021-10-26 22:36:04 +03:00
parent 7a39d86018
commit 505c59ba75
11 changed files with 171 additions and 41 deletions

6
go.mod
View File

@ -1,8 +1,8 @@
module github.com/unistack-org/micro-server-http/v3 module go.unistack.org/micro-server-http/v3
go 1.16 go 1.16
require ( require (
github.com/unistack-org/micro/v3 v3.7.6 go.unistack.org/micro/v3 v3.8.5
golang.org/x/net v0.0.0-20210928044308-7d9f5e0b762b golang.org/x/net v0.0.0-20211020060615-d418f374d309
) )

11
go.sum
View File

@ -7,12 +7,13 @@ github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
github.com/silas/dag v0.0.0-20210626123444-3804bac2d6d4/go.mod h1:7RTUFBdIRC9nZ7/3RyRNH1bdqIShrDejd1YbLwgPS+I= github.com/silas/dag v0.0.0-20210626123444-3804bac2d6d4/go.mod h1:7RTUFBdIRC9nZ7/3RyRNH1bdqIShrDejd1YbLwgPS+I=
github.com/unistack-org/micro-proto v0.0.9 h1:KrWLS4FUX7UAWNAilQf70uad6ZPf/0EudeddCXllRVc= go.unistack.org/micro-proto/v3 v3.1.0 h1:q39FwjFiRZn+Ux/tt+d3bJTmDtsQQWa+3SLYVo1vLfA=
github.com/unistack-org/micro-proto v0.0.9/go.mod h1:Cckwmzd89gvS7ThxzZp9kQR/EOdksFQcsTAtDDyKwrg= go.unistack.org/micro-proto/v3 v3.1.0/go.mod h1:DpRhYCBXlmSJ/AAXTmntvlh7kQkYU6eFvlmYAx4BQS8=
github.com/unistack-org/micro/v3 v3.7.6 h1:cobNkaicZR+8nbDWRUmX3/CSLh6ZNSytK2zWth4s4IM= go.unistack.org/micro/v3 v3.8.5 h1:DIYWRsQF+NPhKZP45sCtNsUhaRw6u2+Ps7U+pKU7i3s=
github.com/unistack-org/micro/v3 v3.7.6/go.mod h1:Ke/8WJlNZi4ZYwL9HcsANAbQ66/HocTBEZM+od99/mM= go.unistack.org/micro/v3 v3.8.5/go.mod h1:KMMmOmbgo/D52/rCAbqeKbBsgEEbSKM69he54J3ZIuA=
golang.org/x/net v0.0.0-20210928044308-7d9f5e0b762b h1:eB48h3HiRycXNy8E0Gf5e0hv7YT6Kt14L/D73G1fuwo=
golang.org/x/net v0.0.0-20210928044308-7d9f5e0b762b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210928044308-7d9f5e0b762b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211020060615-d418f374d309 h1:A0lJIi+hcTR6aajJH4YqKWwohY4aW9RO7oRMcdv+HKI=
golang.org/x/net v0.0.0-20211020060615-d418f374d309/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=

View File

@ -9,13 +9,13 @@ import (
"strings" "strings"
"sync" "sync"
"github.com/unistack-org/micro/v3/errors" "go.unistack.org/micro/v3/errors"
"github.com/unistack-org/micro/v3/logger" "go.unistack.org/micro/v3/logger"
"github.com/unistack-org/micro/v3/metadata" "go.unistack.org/micro/v3/metadata"
"github.com/unistack-org/micro/v3/register" "go.unistack.org/micro/v3/register"
"github.com/unistack-org/micro/v3/server" "go.unistack.org/micro/v3/server"
rhttp "github.com/unistack-org/micro/v3/util/http" rhttp "go.unistack.org/micro/v3/util/http"
rflutil "github.com/unistack-org/micro/v3/util/reflect" rflutil "go.unistack.org/micro/v3/util/reflect"
) )
var ( var (
@ -31,8 +31,8 @@ var (
type patHandler struct { type patHandler struct {
mtype *methodType mtype *methodType
rcvr reflect.Value rcvr reflect.Value
name string
pat *rhttp.Trie pat *rhttp.Trie
name string
} }
type httpHandler struct { type httpHandler struct {
@ -68,7 +68,7 @@ func (h *httpServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
} }
ct := DefaultContentType ct := DefaultContentType
if htype := r.Header.Get("Content-Type"); htype != "" { if htype := r.Header.Get(metadata.HeaderContentType); htype != "" {
ct = htype ct = htype
} }
@ -101,7 +101,7 @@ func (h *httpServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
path := r.URL.Path path := r.URL.Path
if !strings.HasPrefix(path, "/") { if !strings.HasPrefix(path, "/") {
h.errorHandler(ctx, nil, w, r, fmt.Errorf("path must contains /"), http.StatusBadRequest) h.errorHandler(ctx, nil, w, r, fmt.Errorf("path must starts with /"), http.StatusBadRequest)
return return
} }
@ -117,11 +117,9 @@ func (h *httpServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
var hldr patHandler var hldr patHandler
var handler *httpHandler var handler *httpHandler
//fmt.Printf("try to find handler\n")
for _, hpat := range h.handlers { for _, hpat := range h.handlers {
handlertmp := hpat.(*httpHandler) handlertmp := hpat.(*httpHandler)
for _, hldrtmp := range handlertmp.handlers[r.Method] { for _, hldrtmp := range handlertmp.handlers[r.Method] {
//fmt.Printf("ssss method %v path %v %#+v\n", r.Method, path, hldrtmp)
_, mp, ok := hldrtmp.pat.Search(r.Method, path) _, mp, ok := hldrtmp.pat.Search(r.Method, path)
if ok { if ok {
match = true match = true
@ -171,7 +169,6 @@ func (h *httpServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
replyv = reflect.New(hldr.mtype.ReplyType.Elem()) replyv = reflect.New(hldr.mtype.ReplyType.Elem())
function := hldr.mtype.method.Func function := hldr.mtype.method.Func
// function := hldr.rcvr
var returnValues []reflect.Value var returnValues []reflect.Value
if err = cf.ReadBody(r.Body, argv.Interface()); err != nil && err != io.EOF { if err = cf.ReadBody(r.Body, argv.Interface()); err != nil && err != io.EOF {
@ -241,13 +238,13 @@ func (h *httpServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
scode := int(200) scode := int(200)
appErr := fn(ctx, hr, replyv.Interface()) appErr := fn(ctx, hr, replyv.Interface())
w.Header().Set("Content-Type", ct) w.Header().Set(metadata.HeaderContentType, ct)
if md, ok := metadata.FromOutgoingContext(ctx); ok { if md, ok := metadata.FromOutgoingContext(ctx); ok {
for k, v := range md { for k, v := range md {
w.Header().Set(k, v) w.Header().Set(k, v)
} }
} }
if nct := w.Header().Get("Content-Type"); nct != ct { if nct := w.Header().Get(metadata.HeaderContentType); nct != ct {
if cf, err = h.newCodec(nct); err != nil { if cf, err = h.newCodec(nct); err != nil {
h.errorHandler(ctx, nil, w, r, err, http.StatusBadRequest) h.errorHandler(ctx, nil, w, r, err, http.StatusBadRequest)
return return

12
http.go
View File

@ -13,12 +13,12 @@ import (
"sync" "sync"
"time" "time"
"github.com/unistack-org/micro/v3/broker" "go.unistack.org/micro/v3/broker"
"github.com/unistack-org/micro/v3/codec" "go.unistack.org/micro/v3/codec"
"github.com/unistack-org/micro/v3/logger" "go.unistack.org/micro/v3/logger"
"github.com/unistack-org/micro/v3/register" "go.unistack.org/micro/v3/register"
"github.com/unistack-org/micro/v3/server" "go.unistack.org/micro/v3/server"
rhttp "github.com/unistack-org/micro/v3/util/http" rhttp "go.unistack.org/micro/v3/util/http"
"golang.org/x/net/netutil" "golang.org/x/net/netutil"
) )

View File

@ -1,8 +1,8 @@
package http package http
import ( import (
"github.com/unistack-org/micro/v3/codec" "go.unistack.org/micro/v3/codec"
"github.com/unistack-org/micro/v3/metadata" "go.unistack.org/micro/v3/metadata"
) )
type httpMessage struct { type httpMessage struct {

View File

@ -5,7 +5,7 @@ import (
"fmt" "fmt"
"net/http" "net/http"
"github.com/unistack-org/micro/v3/server" "go.unistack.org/micro/v3/server"
) )
// SetError pass error to caller // SetError pass error to caller
@ -125,3 +125,24 @@ type registerRPCHandlerKey struct{}
func RegisterRPCHandler(b bool) server.Option { func RegisterRPCHandler(b bool) server.Option {
return server.SetOption(registerRPCHandlerKey{}, b) return server.SetOption(registerRPCHandlerKey{}, b)
} }
type headerKey struct{}
type handlerOptions struct {
headers []string
cookies []string
}
type FillRequestOption func(*handlerOptions)
func Header(headers ...string) FillRequestOption {
return func(o *handlerOptions) {
o.headers = append(o.headers, headers...)
}
}
func Cookie(cookies ...string) FillRequestOption {
return func(o *handlerOptions) {
o.cookies = append(o.cookies, cookies...)
}
}

View File

@ -3,9 +3,9 @@ package http
import ( import (
"io" "io"
"github.com/unistack-org/micro/v3/codec" "go.unistack.org/micro/v3/codec"
"github.com/unistack-org/micro/v3/metadata" "go.unistack.org/micro/v3/metadata"
"github.com/unistack-org/micro/v3/server" "go.unistack.org/micro/v3/server"
) )
var ( var (

View File

@ -7,7 +7,7 @@ import (
"unicode" "unicode"
"unicode/utf8" "unicode/utf8"
"github.com/unistack-org/micro/v3/server" "go.unistack.org/micro/v3/server"
) )
type methodType struct { type methodType struct {

View File

@ -7,11 +7,11 @@ import (
"reflect" "reflect"
"strings" "strings"
"github.com/unistack-org/micro/v3/broker" "go.unistack.org/micro/v3/broker"
"github.com/unistack-org/micro/v3/codec" "go.unistack.org/micro/v3/codec"
"github.com/unistack-org/micro/v3/metadata" "go.unistack.org/micro/v3/metadata"
"github.com/unistack-org/micro/v3/register" "go.unistack.org/micro/v3/register"
"github.com/unistack-org/micro/v3/server" "go.unistack.org/micro/v3/server"
) )
var typeOfError = reflect.TypeOf((*error)(nil)).Elem() var typeOfError = reflect.TypeOf((*error)(nil)).Elem()

55
util.go Normal file
View File

@ -0,0 +1,55 @@
package http
import (
"context"
"net/http"
"strings"
"go.unistack.org/micro/v3/metadata"
rutil "go.unistack.org/micro/v3/util/reflect"
)
func FillRequest(ctx context.Context, req interface{}, opts ...FillRequestOption) error {
var err error
options := handlerOptions{}
for _, o := range opts {
o(&options)
}
md, ok := metadata.FromIncomingContext(ctx)
if !ok {
return nil
}
for idx := 0; idx < len(options.headers)/2; idx += 2 {
k := http.CanonicalHeaderKey(options.headers[idx])
v, ok := md[k]
if !ok {
continue
}
if err = rutil.SetFieldByPath(req, v, k); err != nil {
return err
}
}
cookies := strings.Split(md["Cookie"], ";")
cmd := make(map[string]string, len(cookies))
for _, cookie := range cookies {
kv := strings.Split(cookie, "=")
if len(kv) != 2 {
continue
}
cmd[strings.TrimSpace(kv[0])] = strings.TrimSpace(kv[1])
}
for idx := 0; idx < len(options.cookies)/2; idx += 2 {
k := http.CanonicalHeaderKey(options.cookies[idx])
v, ok := cmd[k]
if !ok {
continue
}
if err = rutil.SetFieldByPath(req, v, k); err != nil {
return err
}
}
return nil
}

56
util_test.go Normal file
View File

@ -0,0 +1,56 @@
package http
import (
"bytes"
"context"
"net/http"
"strings"
"testing"
"go.unistack.org/micro/v3/metadata"
)
func TestFillrequest(t *testing.T) {
md := metadata.New(1)
md.Set("ClientID", "xxx")
type request struct {
Token string
ClientID string
}
ctx := context.Background()
hreq, _ := http.NewRequestWithContext(ctx, http.MethodGet, "/v1", nil)
cookie1 := &http.Cookie{Name: "Token", Value: "zzz"}
cookie2 := &http.Cookie{Name: "Token", Value: "zzz"}
hreq.AddCookie(cookie1)
hreq.AddCookie(cookie2)
buf := bytes.NewBuffer(nil)
_ = hreq.Write(buf)
var cookie string
var line string
var err error
for {
line, err = buf.ReadString('\n')
if err != nil {
break
}
if strings.Contains(line, "Cookie") {
cookie = strings.TrimSpace(strings.Split(line, ":")[1])
break
}
}
md.Set("Cookie", cookie)
ctx = metadata.NewIncomingContext(ctx, md)
req := &request{}
if err := FillRequest(ctx, req, Cookie("Token", "true"), Header("ClientID", "true")); err != nil {
t.Fatal(err)
}
if req.ClientID != "xxx" {
t.Fatalf("FillRequest error: %#+v", req)
}
if req.Token != "zzz" {
t.Fatalf("FillRequest error: %#+v", req)
}
}