From 505c59ba7524162d7ad15882a3bbb78003ceb7a4 Mon Sep 17 00:00:00 2001 From: Vasiliy Tolstov Date: Tue, 26 Oct 2021 22:36:04 +0300 Subject: [PATCH] fill request with header and cookie data Signed-off-by: Vasiliy Tolstov --- go.mod | 6 +++--- go.sum | 11 +++++----- handler.go | 27 +++++++++++-------------- http.go | 12 +++++------ message.go | 4 ++-- options.go | 23 ++++++++++++++++++++- request.go | 6 +++--- server.go | 2 +- subscriber.go | 10 ++++----- util.go | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++ util_test.go | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++ 11 files changed, 171 insertions(+), 41 deletions(-) create mode 100644 util.go create mode 100644 util_test.go diff --git a/go.mod b/go.mod index 5fb4e09..c03d21a 100644 --- a/go.mod +++ b/go.mod @@ -1,8 +1,8 @@ -module github.com/unistack-org/micro-server-http/v3 +module go.unistack.org/micro-server-http/v3 go 1.16 require ( - github.com/unistack-org/micro/v3 v3.7.6 - golang.org/x/net v0.0.0-20210928044308-7d9f5e0b762b + go.unistack.org/micro/v3 v3.8.5 + golang.org/x/net v0.0.0-20211020060615-d418f374d309 ) diff --git a/go.sum b/go.sum index dbd5563..1aba847 100644 --- a/go.sum +++ b/go.sum @@ -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/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= 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= -github.com/unistack-org/micro-proto v0.0.9/go.mod h1:Cckwmzd89gvS7ThxzZp9kQR/EOdksFQcsTAtDDyKwrg= -github.com/unistack-org/micro/v3 v3.7.6 h1:cobNkaicZR+8nbDWRUmX3/CSLh6ZNSytK2zWth4s4IM= -github.com/unistack-org/micro/v3 v3.7.6/go.mod h1:Ke/8WJlNZi4ZYwL9HcsANAbQ66/HocTBEZM+od99/mM= -golang.org/x/net v0.0.0-20210928044308-7d9f5e0b762b h1:eB48h3HiRycXNy8E0Gf5e0hv7YT6Kt14L/D73G1fuwo= +go.unistack.org/micro-proto/v3 v3.1.0 h1:q39FwjFiRZn+Ux/tt+d3bJTmDtsQQWa+3SLYVo1vLfA= +go.unistack.org/micro-proto/v3 v3.1.0/go.mod h1:DpRhYCBXlmSJ/AAXTmntvlh7kQkYU6eFvlmYAx4BQS8= +go.unistack.org/micro/v3 v3.8.5 h1:DIYWRsQF+NPhKZP45sCtNsUhaRw6u2+Ps7U+pKU7i3s= +go.unistack.org/micro/v3 v3.8.5/go.mod h1:KMMmOmbgo/D52/rCAbqeKbBsgEEbSKM69he54J3ZIuA= 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-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= diff --git a/handler.go b/handler.go index 9764c83..f326d4d 100644 --- a/handler.go +++ b/handler.go @@ -9,13 +9,13 @@ import ( "strings" "sync" - "github.com/unistack-org/micro/v3/errors" - "github.com/unistack-org/micro/v3/logger" - "github.com/unistack-org/micro/v3/metadata" - "github.com/unistack-org/micro/v3/register" - "github.com/unistack-org/micro/v3/server" - rhttp "github.com/unistack-org/micro/v3/util/http" - rflutil "github.com/unistack-org/micro/v3/util/reflect" + "go.unistack.org/micro/v3/errors" + "go.unistack.org/micro/v3/logger" + "go.unistack.org/micro/v3/metadata" + "go.unistack.org/micro/v3/register" + "go.unistack.org/micro/v3/server" + rhttp "go.unistack.org/micro/v3/util/http" + rflutil "go.unistack.org/micro/v3/util/reflect" ) var ( @@ -31,8 +31,8 @@ var ( type patHandler struct { mtype *methodType rcvr reflect.Value - name string pat *rhttp.Trie + name string } type httpHandler struct { @@ -68,7 +68,7 @@ func (h *httpServer) ServeHTTP(w http.ResponseWriter, r *http.Request) { } ct := DefaultContentType - if htype := r.Header.Get("Content-Type"); htype != "" { + if htype := r.Header.Get(metadata.HeaderContentType); htype != "" { ct = htype } @@ -101,7 +101,7 @@ func (h *httpServer) ServeHTTP(w http.ResponseWriter, r *http.Request) { path := r.URL.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 } @@ -117,11 +117,9 @@ func (h *httpServer) ServeHTTP(w http.ResponseWriter, r *http.Request) { var hldr patHandler var handler *httpHandler - //fmt.Printf("try to find handler\n") for _, hpat := range h.handlers { handlertmp := hpat.(*httpHandler) 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) if ok { match = true @@ -171,7 +169,6 @@ func (h *httpServer) ServeHTTP(w http.ResponseWriter, r *http.Request) { replyv = reflect.New(hldr.mtype.ReplyType.Elem()) function := hldr.mtype.method.Func - // function := hldr.rcvr var returnValues []reflect.Value 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) 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 { for k, v := range md { 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 { h.errorHandler(ctx, nil, w, r, err, http.StatusBadRequest) return diff --git a/http.go b/http.go index ece6b1c..1c0ddf2 100644 --- a/http.go +++ b/http.go @@ -13,12 +13,12 @@ import ( "sync" "time" - "github.com/unistack-org/micro/v3/broker" - "github.com/unistack-org/micro/v3/codec" - "github.com/unistack-org/micro/v3/logger" - "github.com/unistack-org/micro/v3/register" - "github.com/unistack-org/micro/v3/server" - rhttp "github.com/unistack-org/micro/v3/util/http" + "go.unistack.org/micro/v3/broker" + "go.unistack.org/micro/v3/codec" + "go.unistack.org/micro/v3/logger" + "go.unistack.org/micro/v3/register" + "go.unistack.org/micro/v3/server" + rhttp "go.unistack.org/micro/v3/util/http" "golang.org/x/net/netutil" ) diff --git a/message.go b/message.go index 7995379..f6d3763 100644 --- a/message.go +++ b/message.go @@ -1,8 +1,8 @@ package http import ( - "github.com/unistack-org/micro/v3/codec" - "github.com/unistack-org/micro/v3/metadata" + "go.unistack.org/micro/v3/codec" + "go.unistack.org/micro/v3/metadata" ) type httpMessage struct { diff --git a/options.go b/options.go index cfa3c13..2b7c805 100644 --- a/options.go +++ b/options.go @@ -5,7 +5,7 @@ import ( "fmt" "net/http" - "github.com/unistack-org/micro/v3/server" + "go.unistack.org/micro/v3/server" ) // SetError pass error to caller @@ -125,3 +125,24 @@ type registerRPCHandlerKey struct{} func RegisterRPCHandler(b bool) server.Option { 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...) + } +} diff --git a/request.go b/request.go index 6ee7c05..4afa92d 100644 --- a/request.go +++ b/request.go @@ -3,9 +3,9 @@ package http import ( "io" - "github.com/unistack-org/micro/v3/codec" - "github.com/unistack-org/micro/v3/metadata" - "github.com/unistack-org/micro/v3/server" + "go.unistack.org/micro/v3/codec" + "go.unistack.org/micro/v3/metadata" + "go.unistack.org/micro/v3/server" ) var ( diff --git a/server.go b/server.go index 9f9bfce..7508467 100644 --- a/server.go +++ b/server.go @@ -7,7 +7,7 @@ import ( "unicode" "unicode/utf8" - "github.com/unistack-org/micro/v3/server" + "go.unistack.org/micro/v3/server" ) type methodType struct { diff --git a/subscriber.go b/subscriber.go index 7a5c0b3..8880a95 100644 --- a/subscriber.go +++ b/subscriber.go @@ -7,11 +7,11 @@ import ( "reflect" "strings" - "github.com/unistack-org/micro/v3/broker" - "github.com/unistack-org/micro/v3/codec" - "github.com/unistack-org/micro/v3/metadata" - "github.com/unistack-org/micro/v3/register" - "github.com/unistack-org/micro/v3/server" + "go.unistack.org/micro/v3/broker" + "go.unistack.org/micro/v3/codec" + "go.unistack.org/micro/v3/metadata" + "go.unistack.org/micro/v3/register" + "go.unistack.org/micro/v3/server" ) var typeOfError = reflect.TypeOf((*error)(nil)).Elem() diff --git a/util.go b/util.go new file mode 100644 index 0000000..99576d3 --- /dev/null +++ b/util.go @@ -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 +} diff --git a/util_test.go b/util_test.go new file mode 100644 index 0000000..76c7cd3 --- /dev/null +++ b/util_test.go @@ -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) + } +}