diff options
author | Erik Dubbelboer <erik@dubbelboer.com> | 2020-05-15 15:36:26 +0200 |
---|---|---|
committer | Erik Dubbelboer <erik@dubbelboer.com> | 2020-05-15 15:36:26 +0200 |
commit | 339ad36634b68ab5b4d90fb9991e38d5020a1039 (patch) | |
tree | 167e613ce9b8eef1d3b92c18b00d4039cbc8df91 /brotli_test.go | |
parent | Don't wrap conn with a TLS Client if it's already a TLS Conn (diff) | |
download | fasthttp-339ad36634b68ab5b4d90fb9991e38d5020a1039.tar.gz fasthttp-339ad36634b68ab5b4d90fb9991e38d5020a1039.tar.bz2 fasthttp-339ad36634b68ab5b4d90fb9991e38d5020a1039.zip |
Add Brotli support
New Functions:
CompressHandlerBrotliLevel(h RequestHandler, brotliLevel, otherLevel int) RequestHandler
Request.BodyUnbrotli() ([]byte, error)
Response.BodyUnbrotli() ([]byte, error)
AppendBrotliBytesLevel(dst, src []byte, level int) []byte
WriteBrotliLevel(w io.Writer, p []byte, level int) (int, error)
WriteBrotli(w io.Writer, p []byte) (int, error)
AppendBrotliBytes(dst, src []byte) []byte
WriteUnbrotli(w io.Writer, p []byte) (int, error)
AppendUnbrotliBytes(dst, src []byte) ([]byte, error)
New Constants:
CompressBrotliNoCompression
CompressBrotliBestSpeed
CompressBrotliBestCompression
CompressBrotliDefaultCompression
Brotli compression levels are different from gzip/flate. Because of this we have separate level constants and CompressHandlerBrotliLevel takes 2 levels.
I didn't add Brotli support to CompressHandler as this could cause a spike in CPU usage when users upgrade fasthttp.
fasthttp.CompressBrotliDefaultCompression is not the same as
brotli.DefaultCompression. brotli.DefaultCompression is more than twice
as slow as fasthttp.CompressBrotliDefaultCompression which I thought was
unreasonable as default.
Diffstat (limited to 'brotli_test.go')
-rw-r--r-- | brotli_test.go | 177 |
1 files changed, 177 insertions, 0 deletions
diff --git a/brotli_test.go b/brotli_test.go new file mode 100644 index 0000000..1ac94dd --- /dev/null +++ b/brotli_test.go @@ -0,0 +1,177 @@ +package fasthttp + +import ( + "bufio" + "bytes" + "fmt" + "io/ioutil" + "testing" +) + +func TestBrotliBytesSerial(t *testing.T) { + t.Parallel() + + if err := testBrotliBytes(); err != nil { + t.Fatal(err) + } +} + +func TestBrotliBytesConcurrent(t *testing.T) { + t.Parallel() + + if err := testConcurrent(10, testBrotliBytes); err != nil { + t.Fatal(err) + } +} + +func testBrotliBytes() error { + for _, s := range compressTestcases { + if err := testBrotliBytesSingleCase(s); err != nil { + return err + } + } + return nil +} + +func testBrotliBytesSingleCase(s string) error { + prefix := []byte("foobar") + brotlipedS := AppendBrotliBytes(prefix, []byte(s)) + if !bytes.Equal(brotlipedS[:len(prefix)], prefix) { + return fmt.Errorf("unexpected prefix when compressing %q: %q. Expecting %q", s, brotlipedS[:len(prefix)], prefix) + } + + unbrotliedS, err := AppendUnbrotliBytes(prefix, brotlipedS[len(prefix):]) + if err != nil { + return fmt.Errorf("unexpected error when uncompressing %q: %s", s, err) + } + if !bytes.Equal(unbrotliedS[:len(prefix)], prefix) { + return fmt.Errorf("unexpected prefix when uncompressing %q: %q. Expecting %q", s, unbrotliedS[:len(prefix)], prefix) + } + unbrotliedS = unbrotliedS[len(prefix):] + if string(unbrotliedS) != s { + return fmt.Errorf("unexpected uncompressed string %q. Expecting %q", unbrotliedS, s) + } + return nil +} + +func TestBrotliCompressSerial(t *testing.T) { + t.Parallel() + + if err := testBrotliCompress(); err != nil { + t.Fatal(err) + } +} + +func TestBrotliCompressConcurrent(t *testing.T) { + t.Parallel() + + if err := testConcurrent(10, testBrotliCompress); err != nil { + t.Fatal(err) + } +} + +func testBrotliCompress() error { + for _, s := range compressTestcases { + if err := testBrotliCompressSingleCase(s); err != nil { + return err + } + } + return nil +} + +func testBrotliCompressSingleCase(s string) error { + var buf bytes.Buffer + zw := acquireStacklessBrotliWriter(&buf, CompressDefaultCompression) + if _, err := zw.Write([]byte(s)); err != nil { + return fmt.Errorf("unexpected error: %s. s=%q", err, s) + } + releaseStacklessBrotliWriter(zw, CompressDefaultCompression) + + zr, err := acquireBrotliReader(&buf) + if err != nil { + return fmt.Errorf("unexpected error: %s. s=%q", err, s) + } + body, err := ioutil.ReadAll(zr) + if err != nil { + return fmt.Errorf("unexpected error: %s. s=%q", err, s) + } + if string(body) != s { + return fmt.Errorf("unexpected string after decompression: %q. Expecting %q", body, s) + } + releaseBrotliReader(zr) + return nil +} + +func TestCompressHandlerBrotliLevel(t *testing.T) { + t.Parallel() + + expectedBody := string(createFixedBody(2e4)) + h := CompressHandlerBrotliLevel(func(ctx *RequestCtx) { + ctx.Write([]byte(expectedBody)) //nolint:errcheck + }, CompressBrotliDefaultCompression, CompressDefaultCompression) + + var ctx RequestCtx + var resp Response + + // verify uncompressed response + h(&ctx) + s := ctx.Response.String() + br := bufio.NewReader(bytes.NewBufferString(s)) + if err := resp.Read(br); err != nil { + t.Fatalf("unexpected error: %s", err) + } + ce := resp.Header.Peek(HeaderContentEncoding) + if string(ce) != "" { + t.Fatalf("unexpected Content-Encoding: %q. Expecting %q", ce, "") + } + body := resp.Body() + if string(body) != expectedBody { + t.Fatalf("unexpected body %q. Expecting %q", body, expectedBody) + } + + // verify gzip-compressed response + ctx.Request.Reset() + ctx.Response.Reset() + ctx.Request.Header.Set("Accept-Encoding", "gzip, deflate, sdhc") + + h(&ctx) + s = ctx.Response.String() + br = bufio.NewReader(bytes.NewBufferString(s)) + if err := resp.Read(br); err != nil { + t.Fatalf("unexpected error: %s", err) + } + ce = resp.Header.Peek(HeaderContentEncoding) + if string(ce) != "gzip" { + t.Fatalf("unexpected Content-Encoding: %q. Expecting %q", ce, "gzip") + } + body, err := resp.BodyGunzip() + if err != nil { + t.Fatalf("unexpected error: %s", err) + } + if string(body) != expectedBody { + t.Fatalf("unexpected body %q. Expecting %q", body, expectedBody) + } + + // verify brotli-compressed response + ctx.Request.Reset() + ctx.Response.Reset() + ctx.Request.Header.Set("Accept-Encoding", "gzip, deflate, sdhc, br") + + h(&ctx) + s = ctx.Response.String() + br = bufio.NewReader(bytes.NewBufferString(s)) + if err := resp.Read(br); err != nil { + t.Fatalf("unexpected error: %s", err) + } + ce = resp.Header.Peek(HeaderContentEncoding) + if string(ce) != "br" { + t.Fatalf("unexpected Content-Encoding: %q. Expecting %q", ce, "br") + } + body, err = resp.BodyUnbrotli() + if err != nil { + t.Fatalf("unexpected error: %s", err) + } + if string(body) != expectedBody { + t.Fatalf("unexpected body %q. Expecting %q", body, expectedBody) + } +} |