Skip to content

Commit

Permalink
Compressors error handling problem, brotli missing buffer reuse
Browse files Browse the repository at this point in the history
  • Loading branch information
D3vl0per committed Jan 7, 2024
1 parent e06ec51 commit dcdbb90
Show file tree
Hide file tree
Showing 4 changed files with 285 additions and 106 deletions.
91 changes: 75 additions & 16 deletions compression/compression.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ type Compressor interface {
GetLevel() int
SetLevel(int)
GetName() string
GetModes() []int
}

type Gzip struct {
Expand All @@ -69,7 +70,7 @@ func (g *Gzip) Compress(in []byte) ([]byte, error) {

err := g.CompressStream(reader, &g.compressedBuff)
if err != nil {
return nil, nil
return nil, err
}

return g.compressedBuff.Bytes(), nil
Expand All @@ -96,7 +97,7 @@ func (g *Gzip) Decompress(in []byte) ([]byte, error) {

err := g.DecompressStream(reader, &g.deCompressedBuff)
if err != nil {
return nil, nil
return nil, err
}

return g.deCompressedBuff.Bytes(), nil
Expand Down Expand Up @@ -125,6 +126,18 @@ func (g *Gzip) GetName() string {
return "gzip"
}

func (g *Gzip) GetModes() []int {
return []int{
NoCompression,
BestSpeed,
ConstantCompression,
DefaultCompression,
BestCompression,
HuffmanOnly,
StatelessCompression,
}
}

type Zstd struct {
Level int
compressedBuff bytes.Buffer
Expand All @@ -137,7 +150,7 @@ func (z *Zstd) Compress(in []byte) ([]byte, error) {

err := z.CompressStream(reader, &z.compressedBuff)
if err != nil {
return nil, nil
return nil, err
}

return z.compressedBuff.Bytes(), nil
Expand All @@ -163,7 +176,7 @@ func (z *Zstd) Decompress(in []byte) ([]byte, error) {

err := z.DecompressStream(reader, &z.deCompressedBuff)
if err != nil {
return nil, nil
return nil, err
}

return z.deCompressedBuff.Bytes(), nil
Expand Down Expand Up @@ -192,6 +205,15 @@ func (z *Zstd) GetName() string {
return "zstd"
}

func (z *Zstd) GetModes() []int {
return []int{
ZstdSpeedFastest,
ZstdSpeedDefault,
ZstdSpeedBetterCompression,
ZstdSpeedBestCompression,
}
}

type Flate struct {
Level int
compressedBuff bytes.Buffer
Expand All @@ -204,7 +226,7 @@ func (f *Flate) Compress(in []byte) ([]byte, error) {

err := f.CompressStream(reader, &f.compressedBuff)
if err != nil {
return nil, nil
return nil, err
}

return f.compressedBuff.Bytes(), nil
Expand All @@ -230,7 +252,7 @@ func (f *Flate) Decompress(in []byte) ([]byte, error) {

err := f.DecompressStream(reader, &f.deCompressedBuff)
if err != nil {
return nil, nil
return nil, err
}

return f.deCompressedBuff.Bytes(), nil
Expand All @@ -255,6 +277,18 @@ func (f *Flate) GetName() string {
return "deflate"
}

func (f *Flate) GetModes() []int {
return []int{
NoCompression,
BestSpeed,
ConstantCompression,
DefaultCompression,
BestCompression,
HuffmanOnly,
StatelessCompression,
}
}

type Zlib struct {
Level int
compressedBuff bytes.Buffer
Expand All @@ -267,7 +301,7 @@ func (zl *Zlib) Compress(in []byte) ([]byte, error) {

err := zl.CompressStream(reader, &zl.compressedBuff)
if err != nil {
return nil, nil
return nil, err
}

return zl.compressedBuff.Bytes(), nil
Expand All @@ -293,7 +327,7 @@ func (zl *Zlib) Decompress(in []byte) ([]byte, error) {

err := zl.DecompressStream(reader, &zl.deCompressedBuff)
if err != nil {
return nil, nil
return nil, err
}

return zl.deCompressedBuff.Bytes(), nil
Expand Down Expand Up @@ -322,23 +356,38 @@ func (zl *Zlib) GetName() string {
return "zlib"
}

func (zl *Zlib) GetModes() []int {
return []int{
NoCompression,
BestSpeed,
ConstantCompression,
DefaultCompression,
BestCompression,
HuffmanOnly,
StatelessCompression,
}
}

type Brotli struct {
Level int
bw *brotli.Writer
br *brotli.Reader
compressedBuff bytes.Buffer
deCompressedBuff bytes.Buffer
}

func (b *Brotli) Compress(in []byte) ([]byte, error) {
b.compressedBuff.Reset()
reader := bytes.NewReader(in)
var compressedBuff bytes.Buffer

err := b.CompressStream(reader, &compressedBuff)
err := b.CompressStream(reader, &b.compressedBuff)
if err != nil {
return nil, nil
return nil, err
}

return compressedBuff.Bytes(), nil
return b.compressedBuff.Bytes(), nil
}

func (b *Brotli) CompressStream(in io.Reader, out io.Writer) error {

b.bw.Reset(out)
Expand All @@ -353,17 +402,19 @@ func (b *Brotli) CompressStream(in io.Reader, out io.Writer) error {

return nil
}

func (b *Brotli) Decompress(in []byte) ([]byte, error) {
b.deCompressedBuff.Reset()
reader := bytes.NewReader(in)
var deCompressedBuff bytes.Buffer

err := b.DecompressStream(reader, &deCompressedBuff)
err := b.DecompressStream(reader, &b.deCompressedBuff)
if err != nil {
return nil, nil
return nil, err
}

return deCompressedBuff.Bytes(), nil
return b.deCompressedBuff.Bytes(), nil
}

func (b *Brotli) DecompressStream(in io.Reader, out io.Writer) error {

if err := b.br.Reset(in); err != nil {
Expand All @@ -388,3 +439,11 @@ func (b *Brotli) SetLevel(level int) {
func (b *Brotli) GetName() string {
return "br"
}

func (b *Brotli) GetModes() []int {
return []int{
BrotliBestSpeed,
BrotliDefaultCompression,
BrotliBestCompression,
}
}
132 changes: 120 additions & 12 deletions compression/compression_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -192,19 +192,127 @@ func testRoundTrip(t *testing.T, compressor compression.Compressor, data []byte)
t.Log("=============")
}

func TestGzipCompressRoundTrip(t *testing.T) {
data, err := generic.CSPRNG(256)
r.NoError(t, err)
func TestRoundTripsFault(t *testing.T) {
type cases struct {
name string
level int
data []byte
expectedErr string
}

for i := 0; i <= 9; i++ {
gzip := compression.Gzip{
Level: i,
}
cmp, err := gzip.Compress(data)
r.NoError(t, err)
dcmp, err := gzip.Decompress(cmp)
r.NoError(t, err)
r.Equal(t, data, dcmp)
type testStructue struct {
name string
compressor compression.Compressor
compress []cases
decompress []cases
}

testCases := []testStructue{
{
name: "gzip",
compressor: &compression.Gzip{},
compress: []cases{
{
name: "level 10, invalid level",
level: 10,
data: []byte("test"),
expectedErr: "gzip: invalid compression level: 10",
},
{
name: "level -4, invalid level",
level: -4,
data: []byte("test"),
expectedErr: "gzip: invalid compression level: -4",
},
},
},
{
name: "zsdt",
compressor: &compression.Zstd{},
decompress: []cases{
{
name: "invalid payload, invalid header",
data: make([]byte, 32),
level: 1,
expectedErr: "invalid input: magic number mismatch",
},
},
},
{
name: "flate",
compressor: &compression.Flate{},
compress: []cases{
{
name: "level 10, invalid level",
level: 10,
data: []byte("test"),
expectedErr: "flate: invalid compression level 10: want value in range [-2, 9]",
},
{
name: "level -3, invalid level",
level: -3,
data: []byte("test"),
expectedErr: "flate: invalid compression level -3: want value in range [-2, 9]",
},
},
decompress: []cases{
{
name: "invalid payload, invalid header",
data: make([]byte, 32),
level: 1,
expectedErr: "invalid header",
},
},
},
{
name: "zlib",
compressor: &compression.Zlib{},
compress: []cases{
{
name: "level 10, invalid level",
level: 10,
data: []byte("test"),
expectedErr: "invalid compression level",
},
{
name: "level -3, invalid level",
level: -3,
data: []byte("test"),
expectedErr: "invalid compression level",
},
},
},
{
name: "brotli",
compressor: &compression.Brotli{},
decompress: []cases{
{
name: "invalid payload, invalid header",
data: make([]byte, 32),
level: 1,
expectedErr: "invalid header",
},
},
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
for _, c := range tc.compress {
t.Run(c.name, func(t *testing.T) {
tc.compressor.SetLevel(c.level)
_, err := tc.compressor.Compress(c.data)
r.Error(t, err)
})
}
for _, c := range tc.decompress {
t.Run(c.name, func(t *testing.T) {
tc.compressor.SetLevel(c.level)
_, err := tc.compressor.Decompress(c.data)
r.Error(t, err)
})
}
})
}
}

Expand Down
Loading

0 comments on commit dcdbb90

Please sign in to comment.