From 95dcdd6025ecb607d515b5101e66fb966ca8ada3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=B8=D1=80=D0=B8=D0=BB=D0=BB=20=D0=93=D0=BE=D1=80?= =?UTF-8?q?=D0=B1=D1=83=D0=BD=D0=BE=D0=B2?= Date: Mon, 11 Mar 2024 13:21:11 +0300 Subject: [PATCH 1/4] =?UTF-8?q?gzip=20for=20v3=20#153=20(#183)=20Co-author?= =?UTF-8?q?ed-by:=20=D0=9A=D0=B8=D1=80=D0=B8=D0=BB=D0=BB=20=D0=93=D0=BE?= =?UTF-8?q?=D1=80=D0=B1=D1=83=D0=BD=D0=BE=D0=B2=20=20Co-committed-by:=20=D0=9A=D0=B8=D1=80=D0=B8=D0=BB?= =?UTF-8?q?=D0=BB=20=D0=93=D0=BE=D1=80=D0=B1=D1=83=D0=BD=D0=BE=D0=B2=20?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- handler/meter/meter.go | 63 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 60 insertions(+), 3 deletions(-) diff --git a/handler/meter/meter.go b/handler/meter/meter.go index f92830e..76974ce 100644 --- a/handler/meter/meter.go +++ b/handler/meter/meter.go @@ -2,13 +2,36 @@ package meter // import "go.unistack.org/micro-server-http/v3/handler/meter" import ( "bytes" + "compress/gzip" "context" + "io" + "strings" + "sync" codecpb "go.unistack.org/micro-proto/v3/codec" "go.unistack.org/micro/v3/errors" + "go.unistack.org/micro/v3/logger" + "go.unistack.org/micro/v3/metadata" "go.unistack.org/micro/v3/meter" ) +const ( + contentEncodingHeader = "Content-Encoding" + acceptEncodingHeader = "Accept-Encoding" +) + +var gzipPool = sync.Pool{ + New: func() interface{} { + return gzip.NewWriter(nil) + }, +} + +var bufPool = sync.Pool{ + New: func() interface{} { + return bytes.NewBuffer(nil) + }, +} + // guard to fail early var _ MeterServiceServer = &Handler{} @@ -56,12 +79,46 @@ func NewHandler(opts ...Option) *Handler { } func (h *Handler) Metrics(ctx context.Context, req *codecpb.Frame, rsp *codecpb.Frame) error { - buf := bytes.NewBuffer(nil) - if err := h.opts.Meter.Write(buf, h.opts.MeterOptions...); err != nil { - return errors.InternalServerError(h.opts.Name, "%v", err) + log, ok := logger.FromContext(ctx) + if !ok { + log = logger.DefaultLogger() + } + + buf := bufPool.Get().(*bytes.Buffer) + defer bufPool.Put(buf) + buf.Reset() + + w := io.Writer(buf) + + if md, ok := metadata.FromIncomingContext(ctx); gzipAccepted(md) && ok { + md.Set(contentEncodingHeader, "gzip") + gz := gzipPool.Get().(*gzip.Writer) + defer gzipPool.Put(gz) + + gz.Reset(w) + defer gz.Close() + + w = gz + } + + if err := h.opts.Meter.Write(w, h.opts.MeterOptions...); err != nil { + log.Error(ctx, errors.InternalServerError(h.opts.Name, "%v", err)) + return nil } rsp.Data = buf.Bytes() return nil } + +// gzipAccepted returns whether the client will accept gzip-encoded content. +func gzipAccepted(md metadata.Metadata) bool { + a, ok := md.Get(acceptEncodingHeader) + if !ok { + return false + } + if strings.Contains(a, "gzip") { + return true + } + return false +} From b89d9fdc5b39ecb025cdbcebd9bfb6283fc42545 Mon Sep 17 00:00:00 2001 From: Vasiliy Tolstov Date: Mon, 11 Mar 2024 23:30:33 +0300 Subject: [PATCH 2/4] fixup headers Signed-off-by: Vasiliy Tolstov --- handler.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/handler.go b/handler.go index f84ec83..9dc8f54 100644 --- a/handler.go +++ b/handler.go @@ -115,14 +115,14 @@ func (h *Server) HTTPHandlerFunc(handler interface{}) (http.HandlerFunc, error) md["Method"] = r.Method md["URL"] = r.URL.String() md["Proto"] = r.Proto - md["ContentLength"] = fmt.Sprintf("%d", r.ContentLength) - md["TransferEncoding"] = strings.Join(r.TransferEncoding, ",") + md["Content-Length"] = fmt.Sprintf("%d", r.ContentLength) + md["Transfer-Encoding"] = strings.Join(r.TransferEncoding, ",") md["Host"] = r.Host md["RequestURI"] = r.RequestURI if r.TLS != nil { md["TLS"] = "true" - md["TLS_ALPN"] = r.TLS.NegotiatedProtocol - md["TLS_ServerName"] = r.TLS.ServerName + md["TLS-ALPN"] = r.TLS.NegotiatedProtocol + md["TLS-ServerName"] = r.TLS.ServerName } ctx = metadata.NewIncomingContext(ctx, md) From b3e58d2cb698bda8df82693a92c32813dc3b2914 Mon Sep 17 00:00:00 2001 From: Vasiliy Tolstov Date: Tue, 12 Mar 2024 00:03:51 +0300 Subject: [PATCH 3/4] fixup handlers Signed-off-by: Vasiliy Tolstov --- handler/meter/meter.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/handler/meter/meter.go b/handler/meter/meter.go index 76974ce..7fc3978 100644 --- a/handler/meter/meter.go +++ b/handler/meter/meter.go @@ -9,7 +9,6 @@ import ( "sync" codecpb "go.unistack.org/micro-proto/v3/codec" - "go.unistack.org/micro/v3/errors" "go.unistack.org/micro/v3/logger" "go.unistack.org/micro/v3/metadata" "go.unistack.org/micro/v3/meter" @@ -81,7 +80,7 @@ func NewHandler(opts ...Option) *Handler { func (h *Handler) Metrics(ctx context.Context, req *codecpb.Frame, rsp *codecpb.Frame) error { log, ok := logger.FromContext(ctx) if !ok { - log = logger.DefaultLogger() + log = logger.DefaultLogger } buf := bufPool.Get().(*bytes.Buffer) @@ -102,7 +101,7 @@ func (h *Handler) Metrics(ctx context.Context, req *codecpb.Frame, rsp *codecpb. } if err := h.opts.Meter.Write(w, h.opts.MeterOptions...); err != nil { - log.Error(ctx, errors.InternalServerError(h.opts.Name, "%v", err)) + log.Error(ctx, "http/meter write failed", err) return nil } From 9ef26caf40924ffb77c71d9c4c2b61ec14e9eaa6 Mon Sep 17 00:00:00 2001 From: Vasiliy Tolstov Date: Tue, 12 Mar 2024 00:50:08 +0300 Subject: [PATCH 4/4] fixup panic Signed-off-by: Vasiliy Tolstov --- http.go | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/http.go b/http.go index 42551e8..f623512 100644 --- a/http.go +++ b/http.go @@ -552,6 +552,7 @@ func (h *Server) Start() error { fn := handler var hs *http.Server + var srvFunc func(net.Listener) error if h.opts.Context != nil { if mwf, ok := h.opts.Context.Value(middlewareKey{}).([]func(http.Handler) http.Handler); ok && len(mwf) > 0 { // wrap the handler func @@ -562,14 +563,24 @@ func (h *Server) Start() error { var ok bool if hs, ok = h.opts.Context.Value(serverKey{}).(*http.Server); ok && hs != nil { hs.Handler = fn + srvFunc = hs.Serve } } - go func() { - if cerr := hs.Serve(ts); cerr != nil && !errors.Is(cerr, net.ErrClosed) { - h.opts.Logger.Error(h.opts.Context, cerr) - } - }() + if srvFunc != nil { + go func() { + if cerr := srvFunc(ts); cerr != nil && !errors.Is(cerr, net.ErrClosed) { + h.opts.Logger.Error(h.opts.Context, cerr) + } + }() + } else { + go func() { + hs = &http.Server{Handler: fn} + if cerr := hs.Serve(ts); cerr != nil && !errors.Is(cerr, net.ErrClosed) { + h.opts.Logger.Error(h.opts.Context, cerr) + } + }() + } go func() { t := new(time.Ticker)