From c7e6c9ebec6c9498901b040752f3ece4d9984373 Mon Sep 17 00:00:00 2001 From: Hans Hasselberg Date: Mon, 8 Jun 2020 10:10:08 +0200 Subject: [PATCH] http: use default minsize for gzip handler. (#7354) Fixes #6306 --- agent/agent_endpoint_test.go | 37 +++++++++++++++++++++++++++++++++ agent/http.go | 13 ++++++++++-- agent/http_test.go | 40 ++++++++++++++++++++++++++++++++++++ 3 files changed, 88 insertions(+), 2 deletions(-) diff --git a/agent/agent_endpoint_test.go b/agent/agent_endpoint_test.go index facfb0ea3f..c91c1d49cf 100644 --- a/agent/agent_endpoint_test.go +++ b/agent/agent_endpoint_test.go @@ -4451,6 +4451,43 @@ func TestAgent_Monitor(t *testing.T) { }) }) + t.Run("stream compressed unstructured logs", func(t *testing.T) { + // The only purpose of this test is to see something being + // logged. Because /v1/agent/monitor is streaming the response + // it needs special handling with the compression. + retry.Run(t, func(r *retry.R) { + req, _ := http.NewRequest("GET", "/v1/agent/monitor?loglevel=debug", nil) + // Usually this would be automatically set by transport content + // negotiation, but since this call doesn't go through a real + // transport, the header has to be set manually + req.Header["Accept-Encoding"] = []string{"gzip"} + cancelCtx, cancelFunc := context.WithCancel(context.Background()) + req = req.WithContext(cancelCtx) + + resp := httptest.NewRecorder() + go a.srv.Handler.ServeHTTP(resp, req) + + args := &structs.ServiceDefinition{ + Name: "monitor", + Port: 8000, + Check: structs.CheckType{ + TTL: 15 * time.Second, + }, + } + + registerReq, _ := http.NewRequest("PUT", "/v1/agent/service/register", jsonReader(args)) + if _, err := a.srv.AgentRegisterService(nil, registerReq); err != nil { + t.Fatalf("err: %v", err) + } + + // Wait until we have received some type of logging output + require.Eventually(t, func() bool { + return len(resp.Body.Bytes()) > 0 + }, 3*time.Second, 100*time.Millisecond) + cancelFunc() + }) + }) + t.Run("stream JSON logs", func(t *testing.T) { // Try to stream logs until we see the expected log line retry.Run(t, func(r *retry.R) { diff --git a/agent/http.go b/agent/http.go index 222d18e73b..58c7a2c41a 100644 --- a/agent/http.go +++ b/agent/http.go @@ -258,8 +258,17 @@ func (s *HTTPServer) handler(enableDebug bool) http.Handler { metrics.MeasureSince(key, start) } - gzipWrapper, _ := gziphandler.GzipHandlerWithOpts(gziphandler.MinSize(0)) - gzipHandler := gzipWrapper(http.HandlerFunc(wrapper)) + var gzipHandler http.Handler + minSize := gziphandler.DefaultMinSize + if pattern == "/v1/agent/monitor" { + minSize = 0 + } + gzipWrapper, err := gziphandler.GzipHandlerWithOpts(gziphandler.MinSize(minSize)) + if err == nil { + gzipHandler = gzipWrapper(http.HandlerFunc(wrapper)) + } else { + gzipHandler = gziphandler.GzipHandler(http.HandlerFunc(wrapper)) + } mux.Handle(pattern, gzipHandler) } diff --git a/agent/http_test.go b/agent/http_test.go index 56025966e5..7424fd6e32 100644 --- a/agent/http_test.go +++ b/agent/http_test.go @@ -18,6 +18,7 @@ import ( "testing" "time" + "github.com/NYTimes/gziphandler" "github.com/hashicorp/consul/agent/structs" tokenStore "github.com/hashicorp/consul/agent/token" "github.com/hashicorp/consul/api" @@ -462,6 +463,45 @@ func TestUIResponseHeaders(t *testing.T) { } } +func TestAcceptEncodingGzip(t *testing.T) { + t.Parallel() + a := NewTestAgent(t, "") + defer a.Shutdown() + + // Setting up the KV to store a short and a long value + buf := bytes.NewBuffer([]byte("short")) + req, _ := http.NewRequest("PUT", "/v1/kv/short", buf) + resp := httptest.NewRecorder() + _, err := a.srv.KVSEndpoint(resp, req) + require.NoError(t, err) + + // this generates a string which is longer than + // gziphandler.DefaultMinSize to trigger compression. + long := fmt.Sprintf(fmt.Sprintf("%%0%dd", gziphandler.DefaultMinSize+1), 1) + buf = bytes.NewBuffer([]byte(long)) + req, _ = http.NewRequest("PUT", "/v1/kv/long", buf) + resp = httptest.NewRecorder() + _, err = a.srv.KVSEndpoint(resp, req) + require.NoError(t, err) + + resp = httptest.NewRecorder() + req, _ = http.NewRequest("GET", "/v1/kv/short", nil) + // Usually this would be automatically set by transport content + // negotiation, but since this call doesn't go through a real + // transport, the header has to be set manually + req.Header["Accept-Encoding"] = []string{"gzip"} + a.srv.Handler.ServeHTTP(resp, req) + require.Equal(t, 200, resp.Code) + require.Equal(t, "", resp.Header().Get("Content-Encoding")) + + resp = httptest.NewRecorder() + req, _ = http.NewRequest("GET", "/v1/kv/long", nil) + req.Header["Accept-Encoding"] = []string{"gzip"} + a.srv.Handler.ServeHTTP(resp, req) + require.Equal(t, 200, resp.Code) + require.Equal(t, "gzip", resp.Header().Get("Content-Encoding")) +} + func TestContentTypeIsJSON(t *testing.T) { t.Parallel() a := NewTestAgent(t, "")