diff --git a/http.go b/http.go index 384a7b3ffd..bc314fc5aa 100644 --- a/http.go +++ b/http.go @@ -486,6 +486,50 @@ func inflateData(p []byte) ([]byte, error) { return bb.B, nil } +var ErrContentEncodingUnsupported = errors.New("unsupported Content-Encoding") + +// BodyDecoded returns body data and if needed decompress it from gzip, deflate or Brotli. +// +// This method may be used if the response header contains +// 'Content-Encoding' for reading uncompressed request body. +// Use Body for reading the raw request body. +func (req *Request) BodyDecoded() ([]byte, error) { + ce := req.Header.Peek(HeaderContentEncoding) + switch string(ce) { + case "": + return req.Body(), nil + case "deflate": + return req.BodyInflate() + case "gzip": + return req.BodyGunzip() + case "br": + return req.BodyUnbrotli() + default: + return nil, ErrContentEncodingUnsupported + } +} + +// BodyDecoded returns body data and if needed decompress it from gzip, deflate or Brotli. +// +// This method may be used if the response header contains +// 'Content-Encoding' for reading uncompressed response body. +// Use Body for reading the raw response body. +func (resp *Response) BodyDecoded() ([]byte, error) { + ce := resp.Header.Peek(HeaderContentEncoding) + switch string(ce) { + case "": + return resp.Body(), nil + case "deflate": + return resp.BodyInflate() + case "gzip": + return resp.BodyGunzip() + case "br": + return resp.BodyUnbrotli() + default: + return nil, ErrContentEncodingUnsupported + } +} + // BodyWriteTo writes request body to w. func (req *Request) BodyWriteTo(w io.Writer) error { if req.bodyStream != nil { diff --git a/http_test.go b/http_test.go index 71d5c6e98d..7169bec152 100644 --- a/http_test.go +++ b/http_test.go @@ -347,6 +347,12 @@ func testResponseBodyStreamDeflate(t *testing.T, body []byte, bodySize int) { if !bytes.Equal(respBody, body) { t.Fatalf("unexpected body: %q. Expecting %q", respBody, body) } + // check for invalid + resp.SetBodyRaw([]byte("invalid")) + respBody, err = resp.BodyInflate() + if err == nil || err.Error() != "zlib: invalid header" { + t.Fatalf("expected error: 'zlib: invalid header' but was %v", err) + } } func testResponseBodyStreamGzip(t *testing.T, body []byte, bodySize int) { @@ -375,6 +381,12 @@ func testResponseBodyStreamGzip(t *testing.T, body []byte, bodySize int) { if !bytes.Equal(respBody, body) { t.Fatalf("unexpected body: %q. Expecting %q", respBody, body) } + // check for invalid + resp.SetBodyRaw([]byte("invalid")) + respBody, err = resp.BodyGunzip() + if err == nil || err.Error() != "unexpected EOF" { + t.Fatalf("expected error: 'unexpected EOF' but was %v", err) + } } func TestResponseWriteGzipNilBody(t *testing.T) { @@ -405,6 +417,46 @@ func TestResponseWriteDeflateNilBody(t *testing.T) { } } +func TestResponseBodyDecoded(t *testing.T) { + body := "body" + var r Response + r.SetBodyStream(bytes.NewReader([]byte(body)), len(body)) + + w := &bytes.Buffer{} + bw := bufio.NewWriter(w) + if err := r.WriteDeflate(bw); err != nil { + t.Fatalf("unexpected error: %v", err) + } + if err := bw.Flush(); err != nil { + t.Fatalf("unexpected error: %v", err) + } + + var resp Response + br := bufio.NewReader(w) + if err := resp.Read(br); err != nil { + t.Fatalf("unexpected error: %v", err) + } + + ce := resp.Header.Peek("Content-Encoding") + if string(ce) != "deflate" { + t.Fatalf("unexpected Content-Encoding: %s", ce) + } + respBody, err := resp.BodyDecoded() + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if string(respBody) != body { + t.Fatalf("unexpected body: %q. Expecting %q", respBody, body) + } + + // check for invalid encoding + resp.Header.Set("Content-Encoding", "invalid") + _, err = resp.BodyDecoded() + if err != ErrContentEncodingUnsupported { + t.Fatalf("unexpected error: %v", err) + } +} + func TestResponseSwapBodySerial(t *testing.T) { t.Parallel()