@@ -3,6 +3,7 @@ package proto
33import (
44 "bytes"
55 "compress/gzip"
6+ "io"
67 "io/ioutil"
78
89 "golang.org/x/xerrors"
@@ -21,6 +22,26 @@ type GZIP struct {
2122// GZIPTypeID is TL type id of GZIP.
2223const GZIPTypeID = 0x3072cfa1
2324
25+ // Encode implements bin.Encoder.
26+ func (g GZIP ) Encode (b * bin.Buffer ) error {
27+ b .PutID (GZIPTypeID )
28+
29+ // Writing compressed data to buf.
30+ buf := new (bytes.Buffer )
31+ w := gzip .NewWriter (buf )
32+ if _ , err := io .Copy (w , bytes .NewReader (g .Data )); err != nil {
33+ return xerrors .Errorf ("compress: %w" , err )
34+ }
35+ if err := w .Close (); err != nil {
36+ return xerrors .Errorf ("close: %w" , err )
37+ }
38+
39+ // Writing compressed data as bytes.
40+ b .PutBytes (buf .Bytes ())
41+
42+ return nil
43+ }
44+
2445// Decode implements bin.Decoder.
2546func (g * GZIP ) Decode (b * bin.Buffer ) error {
2647 if err := b .ConsumeID (GZIPTypeID ); err != nil {
@@ -37,13 +58,17 @@ func (g *GZIP) Decode(b *bin.Buffer) error {
3758 }
3859 defer func () { _ = r .Close () }()
3960
40- if g .Data , err = ioutil .ReadAll (r ); err != nil {
41- return err
61+ // Apply mitigation for reading too much data which can result in OOM.
62+ const maxUncompressedSize = 1024 * 1024 * 10 // 10 mb
63+ // TODO(ernado): fail explicitly if limit is reached
64+ // Currently we just return nil, but it is better than failing with OOM.
65+ if g .Data , err = ioutil .ReadAll (io .LimitReader (r , maxUncompressedSize )); err != nil {
66+ return xerrors .Errorf ("decompress: %w" , err )
4267 }
4368
4469 if err := r .Close (); err != nil {
45- // This will verify checksum.
46- return xerrors .Errorf ("gzip error : %w" , err )
70+ // This will verify checksum only if limit is not reached .
71+ return xerrors .Errorf ("checksum : %w" , err )
4772 }
4873
4974 return nil
0 commit comments