hotfix #186

Merged
vtolstov merged 8 commits from kgorbunov/micro-server-http:hotfix into master 2024-03-26 14:53:15 +03:00
5 changed files with 95 additions and 39 deletions

View File

@ -109,20 +109,20 @@ func (h *Server) HTTPHandlerFunc(handler interface{}) (http.HandlerFunc, error)
md = metadata.New(len(r.Header) + 8) md = metadata.New(len(r.Header) + 8)
} }
for k, v := range r.Header { for k, v := range r.Header {
md[k] = v md[k] = v[0]
} }
md["RemoteAddr"] = []string{r.RemoteAddr} md["RemoteAddr"] = r.RemoteAddr
md["Method"] = []string{r.Method} md["Method"] = r.Method
md["URL"] = []string{r.URL.String()} md["URL"] = r.URL.String()
md["Proto"] = []string{r.Proto} md["Proto"] = r.Proto
md["Content-Length"] = []string{fmt.Sprintf("%d", r.ContentLength)} md["Content-Length"] = fmt.Sprintf("%d", r.ContentLength)
md["Transfer-Encoding"] = r.TransferEncoding md["Transfer-Encoding"] = r.TransferEncoding[0]
md["Host"] = []string{r.Host} md["Host"] = r.Host
md["RequestURI"] = []string{r.RequestURI} md["RequestURI"] = r.RequestURI
if r.TLS != nil { if r.TLS != nil {
md["TLS"] = []string{"true"} md["TLS"] = "true"
md["TLS-ALPN"] = []string{r.TLS.NegotiatedProtocol} md["TLS-ALPN"] = r.TLS.NegotiatedProtocol
md["TLS-ServerName"] = []string{r.TLS.ServerName} md["TLS-ServerName"] = r.TLS.ServerName
} }
ctx = metadata.NewIncomingContext(ctx, md) ctx = metadata.NewIncomingContext(ctx, md)
@ -290,7 +290,7 @@ func (h *Server) HTTPHandlerFunc(handler interface{}) (http.HandlerFunc, error)
w.Header().Set(metadata.HeaderContentType, 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()[k] = v w.Header()[k] = []string{v}
} }
} }
if md := getRspHeader(ctx); md != nil { if md := getRspHeader(ctx); md != nil {
@ -349,23 +349,23 @@ func (h *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
md = metadata.New(len(r.Header) + 8) md = metadata.New(len(r.Header) + 8)
} }
for k, v := range r.Header { for k, v := range r.Header {
md[k] = v md[k] = v[0]
} }
md["RemoteAddr"] = []string{r.RemoteAddr} md["RemoteAddr"] = r.RemoteAddr
if r.TLS != nil { if r.TLS != nil {
md["Scheme"] = []string{"https"} md["Scheme"] = "https"
} else { } else {
md["Scheme"] = []string{"http"} md["Scheme"] = "http"
} }
md["Method"] = []string{r.Method} md["Method"] = r.Method
md["URL"] = []string{r.URL.String()} md["URL"] = r.URL.String()
md["Proto"] = []string{r.Proto} md["Proto"] = r.Proto
md["Content-Length"] = []string{fmt.Sprintf("%d", r.ContentLength)} md["Content-Length"] = fmt.Sprintf("%d", r.ContentLength)
if len(r.TransferEncoding) > 0 { if len(r.TransferEncoding) > 0 {
md["Transfer-Encoding"] = r.TransferEncoding md["Transfer-Encoding"] = r.TransferEncoding[0]
} }
md["Host"] = []string{r.Host} md["Host"] = r.Host
md["RequestURI"] = []string{r.RequestURI} md["RequestURI"] = r.RequestURI
ctx = metadata.NewIncomingContext(ctx, md) ctx = metadata.NewIncomingContext(ctx, md)
path := r.URL.Path path := r.URL.Path
@ -550,7 +550,7 @@ func (h *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
w.Header().Set(metadata.HeaderContentType, 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()[k] = v w.Header()[k] = []string{v}
} }
} }
if md := getRspHeader(ctx); md != nil { if md := getRspHeader(ctx); md != nil {

View File

@ -42,9 +42,10 @@ type Handler struct {
type Option func(*Options) type Option func(*Options)
type Options struct { type Options struct {
Meter meter.Meter Meter meter.Meter
Name string Name string
MeterOptions []options.Option MeterOptions []options.Option
DisableCompress bool
} }
func Meter(m meter.Meter) Option { func Meter(m meter.Meter) Option {
@ -59,6 +60,12 @@ func Name(name string) Option {
} }
} }
func DisableCompress(g bool) Option {
return func(o *Options) {
o.DisableCompress = g
}
}
func MeterOptions(opts ...options.Option) Option { func MeterOptions(opts ...options.Option) Option {
return func(o *Options) { return func(o *Options) {
o.MeterOptions = append(o.MeterOptions, opts...) o.MeterOptions = append(o.MeterOptions, opts...)
@ -66,7 +73,7 @@ func MeterOptions(opts ...options.Option) Option {
} }
func NewOptions(opts ...Option) Options { func NewOptions(opts ...Option) Options {
options := Options{Meter: meter.DefaultMeter} options := Options{Meter: meter.DefaultMeter, DisableCompress: false}
for _, o := range opts { for _, o := range opts {
o(&options) o(&options)
} }
@ -90,8 +97,9 @@ func (h *Handler) Metrics(ctx context.Context, req *codecpb.Frame, rsp *codecpb.
w := io.Writer(buf) w := io.Writer(buf)
if md, ok := metadata.FromContext(ctx); gzipAccepted(md) && ok { if md, ok := metadata.FromIncomingContext(ctx); gzipAccepted(md) && ok && !h.opts.DisableCompress {
md.Set(contentEncodingHeader, "gzip") omd, _ := metadata.FromOutgoingContext(ctx)
omd.Set(contentEncodingHeader, "gzip")
gz := gzipPool.Get().(*gzip.Writer) gz := gzipPool.Get().(*gzip.Writer)
defer gzipPool.Put(gz) defer gzipPool.Put(gz)
@ -99,6 +107,7 @@ func (h *Handler) Metrics(ctx context.Context, req *codecpb.Frame, rsp *codecpb.
defer gz.Close() defer gz.Close()
w = gz w = gz
gz.Flush()
} }
if err := h.opts.Meter.Write(w, h.opts.MeterOptions...); err != nil { if err := h.opts.Meter.Write(w, h.opts.MeterOptions...); err != nil {

View File

@ -0,0 +1,49 @@
package meter
import (
"context"
"testing"
codecpb "go.unistack.org/micro-proto/v4/codec"
)
func TestHandler_Metrics(t *testing.T) {
type fields struct {
opts Options
}
type args struct {
ctx context.Context
req *codecpb.Frame
rsp *codecpb.Frame
}
tests := []struct {
name string
fields fields
args args
wantErr bool
}{
{
"Test #1",
fields{
opts: NewOptions(),
},
args{
context.Background(),
&codecpb.Frame{Data: []byte("gzip")},
&codecpb.Frame{},
},
true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
h := &Handler{
opts: tt.fields.opts,
}
if err := h.Metrics(tt.args.ctx, tt.args.req, tt.args.rsp); (err != nil) != tt.wantErr {
t.Errorf("Metrics() error = %v, wantErr %v", err, tt.wantErr)
}
t.Logf("RSP: %v", tt.args.rsp.Data)
})
}
}

View File

@ -217,7 +217,7 @@ func (h *Server) newHTTPHandler(handler interface{}, opts ...options.Option) *ht
pth := &patHandler{mtype: mtype, name: name, rcvr: rcvr} pth := &patHandler{mtype: mtype, name: name, rcvr: rcvr}
hdlr.name = name hdlr.name = name
if err := hdlr.handlers.Insert(md["Method"], md["Path"][0], pth); err != nil { if err := hdlr.handlers.Insert([]string{md["Method"]}, md["Path"], pth); err != nil {
h.opts.Logger.Error(h.opts.Context, fmt.Sprintf("cant add handler for %s %s", md["Method"][0], md["Path"][0])) h.opts.Logger.Error(h.opts.Context, fmt.Sprintf("cant add handler for %s %s", md["Method"][0], md["Path"][0]))
} }
@ -468,7 +468,7 @@ func (h *Server) Start() error {
go func() { go func() {
if cerr := hs.Serve(ts); cerr != nil && !errors.Is(cerr, net.ErrClosed) { if cerr := hs.Serve(ts); cerr != nil && !errors.Is(cerr, net.ErrClosed) {
h.opts.Logger.Error(h.opts.Context, cerr) h.opts.Logger.Error(h.opts.Context, cerr.Error())
} }
}() }()

10
util.go
View File

@ -33,13 +33,11 @@ func FillRequest(ctx context.Context, req interface{}, opts ...FillRequestOption
cookies := md["Cookie"] cookies := md["Cookie"]
cmd := make(map[string]string, len(cookies)) cmd := make(map[string]string, len(cookies))
for _, cookie := range cookies { kv := strings.Split(cookies, "=")
kv := strings.Split(cookie, "=") if len(kv) != 2 {
if len(kv) != 2 { return nil
continue
}
cmd[strings.TrimSpace(kv[0])] = strings.TrimSpace(kv[1])
} }
cmd[strings.TrimSpace(kv[0])] = strings.TrimSpace(kv[1])
for idx := 0; idx < len(options.cookies)/2; idx += 2 { for idx := 0; idx < len(options.cookies)/2; idx += 2 {
k := http.CanonicalHeaderKey(options.cookies[idx]) k := http.CanonicalHeaderKey(options.cookies[idx])
v, ok := cmd[k] v, ok := cmd[k]