From a483e08ffa7536e18a89b2cc5da2de1070e65d78 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 12:31:19 +0300 Subject: [PATCH] add gzip rsp #153 (#182) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Pull Request template Please, go through these steps before clicking submit on this PR. 1. Give a descriptive title to your PR. 2. Provide a description of your changes. 3. Make sure you have some relevant tests. 4. Put `closes #XXXX` in your comment to auto-close the issue that your PR fixes (if applicable). **PLEASE REMOVE THIS TEMPLATE BEFORE SUBMITTING** Co-authored-by: Gorbunov Kirill Andreevich Reviewed-on: https://git.unistack.org/unistack-org/micro-server-http/pulls/182 Co-authored-by: Кирилл Горбунов Co-committed-by: Кирилл Горбунов --- handler/meter/meter.go | 65 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 61 insertions(+), 4 deletions(-) diff --git a/handler/meter/meter.go b/handler/meter/meter.go index cd31576..037fdc7 100644 --- a/handler/meter/meter.go +++ b/handler/meter/meter.go @@ -2,14 +2,37 @@ package meter // import "go.unistack.org/micro-server-http/v4/handler/meter" import ( "bytes" + "compress/gzip" "context" + "io" + "strings" + "sync" codecpb "go.unistack.org/micro-proto/v4/codec" "go.unistack.org/micro/v4/errors" + "go.unistack.org/micro/v4/logger" + "go.unistack.org/micro/v4/metadata" "go.unistack.org/micro/v4/meter" - options "go.unistack.org/micro/v4/options" + "go.unistack.org/micro/v4/options" ) +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)(nil) @@ -57,12 +80,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.FromContext(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 +}