Skip to content

Commit 626ce6e

Browse files
yeya24alanprot
andcommitted
fix response error to be ungzipped when status code is not 2xx (#4975)
* fix response to be gzipped when status code is not 2xx Signed-off-by: Ben Ye <[email protected]> * adding tests Signed-off-by: Alan Protasio <[email protected]> * lint Signed-off-by: Alan Protasio <[email protected]> * changelog Signed-off-by: Alan Protasio <[email protected]> Signed-off-by: Ben Ye <[email protected]> Signed-off-by: Alan Protasio <[email protected]> Co-authored-by: Alan Protasio <[email protected]>
1 parent df6af0b commit 626ce6e

File tree

5 files changed

+124
-9
lines changed

5 files changed

+124
-9
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@
7878
* [BUGFIX] Ingester: fixed incorrect logging at the start of ingester block shipping logic. #4934
7979
* [BUGFIX] Storage/Bucket: fixed global mark missing on deletion. #4949
8080
* [BUGFIX] QueryFrontend/Querier: fixed regression added by #4863 where we stopped compressing the response between querier and query frontend. #4960
81+
* [BUGFIX] QueryFrontend/Querier: fixed fix response error to be ungzipped when status code is not 2xx. #4975
8182

8283
## 1.13.0 2022-07-14
8384

pkg/querier/tripperware/instantquery/instant_query.go

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -152,11 +152,6 @@ func (c instantQueryCodec) DecodeRequest(_ context.Context, r *http.Request, for
152152
}
153153

154154
func (instantQueryCodec) DecodeResponse(ctx context.Context, r *http.Response, _ tripperware.Request) (tripperware.Response, error) {
155-
if r.StatusCode/100 != 2 {
156-
body, _ := io.ReadAll(r.Body)
157-
return nil, httpgrpc.Errorf(r.StatusCode, string(body))
158-
}
159-
160155
log, ctx := spanlogger.New(ctx, "PrometheusInstantQueryResponse") //nolint:ineffassign,staticcheck
161156
defer log.Finish()
162157

@@ -165,6 +160,10 @@ func (instantQueryCodec) DecodeResponse(ctx context.Context, r *http.Response, _
165160
log.Error(err)
166161
return nil, err
167162
}
163+
if r.StatusCode/100 != 2 {
164+
return nil, httpgrpc.Errorf(r.StatusCode, string(buf))
165+
}
166+
168167
var resp PrometheusInstantQueryResponse
169168
if err := json.Unmarshal(buf, &resp); err != nil {
170169
return nil, httpgrpc.Errorf(http.StatusInternalServerError, "error decoding response: %v", err)

pkg/querier/tripperware/instantquery/instant_query_test.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package instantquery
22

33
import (
44
"bytes"
5+
"compress/gzip"
56
"context"
67
"fmt"
78
"io"
@@ -12,6 +13,7 @@ import (
1213

1314
"github.com/stretchr/testify/assert"
1415
"github.com/stretchr/testify/require"
16+
"github.com/weaveworks/common/httpgrpc"
1517
"github.com/weaveworks/common/user"
1618

1719
"github.com/cortexproject/cortex/pkg/querier/tripperware"
@@ -93,6 +95,62 @@ func TestRequest(t *testing.T) {
9395
}
9496
}
9597

98+
func TestGzippedResponse(t *testing.T) {
99+
for _, tc := range []struct {
100+
body string
101+
status int
102+
err error
103+
}{
104+
{
105+
body: `{"status":"success","data":{"resultType":"string","result":[1,"foo"]}}`,
106+
status: 200,
107+
},
108+
{
109+
body: `error generic 400`,
110+
status: 400,
111+
err: httpgrpc.Errorf(400, "error generic 400"),
112+
},
113+
{
114+
status: 400,
115+
err: httpgrpc.Errorf(400, ""),
116+
},
117+
} {
118+
for _, c := range []bool{true, false} {
119+
t.Run(fmt.Sprintf("compressed %t [%s]", c, tc.body), func(t *testing.T) {
120+
h := http.Header{
121+
"Content-Type": []string{"application/json"},
122+
}
123+
124+
responseBody := bytes.NewBuffer([]byte(tc.body))
125+
if c {
126+
h.Set("Content-Encoding", "gzip")
127+
var buf bytes.Buffer
128+
w := gzip.NewWriter(&buf)
129+
_, err := w.Write([]byte(tc.body))
130+
require.NoError(t, err)
131+
w.Close()
132+
responseBody = &buf
133+
}
134+
135+
response := &http.Response{
136+
StatusCode: tc.status,
137+
Header: h,
138+
Body: io.NopCloser(responseBody),
139+
}
140+
r, err := InstantQueryCodec.DecodeResponse(context.Background(), response, nil)
141+
require.Equal(t, tc.err, err)
142+
143+
if err == nil {
144+
resp, err := json.Marshal(r)
145+
require.NoError(t, err)
146+
147+
require.Equal(t, tc.body, string(resp))
148+
}
149+
})
150+
}
151+
}
152+
}
153+
96154
func TestResponse(t *testing.T) {
97155
for i, tc := range []struct {
98156
body string

pkg/querier/tripperware/queryrange/query_range.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -258,10 +258,6 @@ func (prometheusCodec) EncodeRequest(ctx context.Context, r tripperware.Request)
258258
}
259259

260260
func (prometheusCodec) DecodeResponse(ctx context.Context, r *http.Response, _ tripperware.Request) (tripperware.Response, error) {
261-
if r.StatusCode/100 != 2 {
262-
body, _ := io.ReadAll(r.Body)
263-
return nil, httpgrpc.Errorf(r.StatusCode, string(body))
264-
}
265261
log, ctx := spanlogger.New(ctx, "ParseQueryRangeResponse") //nolint:ineffassign,staticcheck
266262
defer log.Finish()
267263

@@ -270,6 +266,9 @@ func (prometheusCodec) DecodeResponse(ctx context.Context, r *http.Response, _ t
270266
log.Error(err)
271267
return nil, err
272268
}
269+
if r.StatusCode/100 != 2 {
270+
return nil, httpgrpc.Errorf(r.StatusCode, string(buf))
271+
}
273272
log.LogFields(otlog.Int("bytes", len(buf)))
274273

275274
var resp PrometheusResponse

pkg/querier/tripperware/queryrange/query_range_test.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ package queryrange
22

33
import (
44
"bytes"
5+
"compress/gzip"
56
"context"
7+
"fmt"
68
io "io"
79
"net/http"
810
"strconv"
@@ -657,6 +659,62 @@ func TestMergeAPIResponses(t *testing.T) {
657659
}
658660
}
659661

662+
func TestGzippedResponse(t *testing.T) {
663+
for _, tc := range []struct {
664+
body string
665+
status int
666+
err error
667+
}{
668+
{
669+
body: `{"status":"success","data":{"resultType":"matrix","result":[{"metric":{"a":"b","c":"d"},"values":[[2,"2"],[3,"3"]]}],"stats":{"samples":{"totalQueryableSamples":20,"totalQueryableSamplesPerStep":[[2,2],[3,3]]}}}}`,
670+
status: 200,
671+
},
672+
{
673+
body: `error generic 400`,
674+
status: 400,
675+
err: httpgrpc.Errorf(400, `error generic 400`),
676+
},
677+
{
678+
status: 400,
679+
err: httpgrpc.Errorf(400, ""),
680+
},
681+
} {
682+
for _, c := range []bool{true, false} {
683+
t.Run(fmt.Sprintf("compressed %t [%s]", c, tc.body), func(t *testing.T) {
684+
h := http.Header{
685+
"Content-Type": []string{"application/json"},
686+
}
687+
688+
responseBody := bytes.NewBuffer([]byte(tc.body))
689+
if c {
690+
h.Set("Content-Encoding", "gzip")
691+
var buf bytes.Buffer
692+
w := gzip.NewWriter(&buf)
693+
_, err := w.Write([]byte(tc.body))
694+
require.NoError(t, err)
695+
w.Close()
696+
responseBody = &buf
697+
}
698+
699+
response := &http.Response{
700+
StatusCode: tc.status,
701+
Header: h,
702+
Body: io.NopCloser(responseBody),
703+
}
704+
r, err := PrometheusCodec.DecodeResponse(context.Background(), response, nil)
705+
require.Equal(t, tc.err, err)
706+
707+
if err == nil {
708+
resp, err := json.Marshal(r)
709+
require.NoError(t, err)
710+
711+
require.Equal(t, tc.body, string(resp))
712+
}
713+
})
714+
}
715+
}
716+
}
717+
660718
func mustParse(t *testing.T, response string) tripperware.Response {
661719
var resp PrometheusResponse
662720
// Needed as goimports automatically add a json import otherwise.

0 commit comments

Comments
 (0)