@@ -77,10 +77,38 @@ func Decode(dst, src []byte) ([]byte, error) {
77
77
// NewReader returns a new Reader that decompresses from r, using the framing
78
78
// format described at
79
79
// https://github.com/google/snappy/blob/master/framing_format.txt with S2 changes.
80
- func NewReader (r io.Reader ) * Reader {
81
- return & Reader {
82
- r : r ,
83
- buf : make ([]byte , MaxEncodedLen (maxBlockSize )+ checksumSize ),
80
+ func NewReader (r io.Reader , opts ... ReaderOption ) * Reader {
81
+ nr := Reader {
82
+ r : r ,
83
+ maxBlock : maxBlockSize ,
84
+ }
85
+ for _ , opt := range opts {
86
+ if err := opt (& nr ); err != nil {
87
+ nr .err = err
88
+ return & nr
89
+ }
90
+ }
91
+ nr .buf = make ([]byte , MaxEncodedLen (nr .maxBlock )+ checksumSize )
92
+ nr .paramsOK = true
93
+ return & nr
94
+ }
95
+
96
+ // ReaderOption is an option for creating a decoder.
97
+ type ReaderOption func (* Reader ) error
98
+
99
+ // ReaderMaxBlockSize allows to control allocations if the stream
100
+ // has been compressed with a smaller WriterBlockSize, or with the default 1MB.
101
+ // Blocks must be this size or smaller to decompress,
102
+ // otherwise the decoder will return ErrUnsupported.
103
+ //
104
+ // Default is the maximum limit of 4MB.
105
+ func ReaderMaxBlockSize (n int ) ReaderOption {
106
+ return func (r * Reader ) error {
107
+ if n > maxBlockSize || n <= 0 {
108
+ return errors .New ("s2: block size too large. Must be <= 4MB and > 0" )
109
+ }
110
+ r .maxBlock = n
111
+ return nil
84
112
}
85
113
}
86
114
@@ -92,13 +120,18 @@ type Reader struct {
92
120
buf []byte
93
121
// decoded[i:j] contains decoded bytes that have not yet been passed on.
94
122
i , j int
123
+ maxBlock int
95
124
readHeader bool
125
+ paramsOK bool
96
126
}
97
127
98
128
// Reset discards any buffered data, resets all state, and switches the Snappy
99
129
// reader to read from r. This permits reusing a Reader rather than allocating
100
130
// a new one.
101
131
func (r * Reader ) Reset (reader io.Reader ) {
132
+ if ! r .paramsOK {
133
+ return
134
+ }
102
135
r .r = reader
103
136
r .err = nil
104
137
r .i = 0
@@ -116,6 +149,36 @@ func (r *Reader) readFull(p []byte, allowEOF bool) (ok bool) {
116
149
return true
117
150
}
118
151
152
+ // skipN will skip n bytes.
153
+ // If the supplied reader supports seeking that is used.
154
+ // tmp is used as a temporary buffer for reading.
155
+ // The supplied slice does not need to be the size of the read.
156
+ func (r * Reader ) skipN (tmp []byte , n int , allowEOF bool ) (ok bool ) {
157
+ if rs , ok := r .r .(io.ReadSeeker ); ok {
158
+ _ , err := rs .Seek (int64 (n ), io .SeekCurrent )
159
+ if err == nil {
160
+ return true
161
+ }
162
+ if err == io .ErrUnexpectedEOF || (r .err == io .EOF && ! allowEOF ) {
163
+ r .err = ErrCorrupt
164
+ return false
165
+ }
166
+ }
167
+ for n > 0 {
168
+ if n < len (tmp ) {
169
+ tmp = tmp [:n ]
170
+ }
171
+ if _ , r .err = io .ReadFull (r .r , tmp ); r .err != nil {
172
+ if r .err == io .ErrUnexpectedEOF || (r .err == io .EOF && ! allowEOF ) {
173
+ r .err = ErrCorrupt
174
+ }
175
+ return false
176
+ }
177
+ n -= len (tmp )
178
+ }
179
+ return true
180
+ }
181
+
119
182
// Read satisfies the io.Reader interface.
120
183
func (r * Reader ) Read (p []byte ) (int , error ) {
121
184
if r .err != nil {
@@ -139,10 +202,6 @@ func (r *Reader) Read(p []byte) (int, error) {
139
202
r .readHeader = true
140
203
}
141
204
chunkLen := int (r .buf [1 ]) | int (r .buf [2 ])<< 8 | int (r .buf [3 ])<< 16
142
- if chunkLen > len (r .buf ) {
143
- r .err = ErrUnsupported
144
- return 0 , r .err
145
- }
146
205
147
206
// The chunk types are specified at
148
207
// https://github.com/google/snappy/blob/master/framing_format.txt
@@ -153,6 +212,10 @@ func (r *Reader) Read(p []byte) (int, error) {
153
212
r .err = ErrCorrupt
154
213
return 0 , r .err
155
214
}
215
+ if chunkLen > len (r .buf ) {
216
+ r .err = ErrUnsupported
217
+ return 0 , r .err
218
+ }
156
219
buf := r .buf [:chunkLen ]
157
220
if ! r .readFull (buf , false ) {
158
221
return 0 , r .err
@@ -166,7 +229,7 @@ func (r *Reader) Read(p []byte) (int, error) {
166
229
return 0 , r .err
167
230
}
168
231
if n > len (r .decoded ) {
169
- if n > maxBlockSize {
232
+ if n > r . maxBlock {
170
233
r .err = ErrCorrupt
171
234
return 0 , r .err
172
235
}
@@ -189,6 +252,10 @@ func (r *Reader) Read(p []byte) (int, error) {
189
252
r .err = ErrCorrupt
190
253
return 0 , r .err
191
254
}
255
+ if chunkLen > len (r .buf ) {
256
+ r .err = ErrUnsupported
257
+ return 0 , r .err
258
+ }
192
259
buf := r .buf [:checksumSize ]
193
260
if ! r .readFull (buf , false ) {
194
261
return 0 , r .err
@@ -197,7 +264,7 @@ func (r *Reader) Read(p []byte) (int, error) {
197
264
// Read directly into r.decoded instead of via r.buf.
198
265
n := chunkLen - checksumSize
199
266
if n > len (r .decoded ) {
200
- if n > maxBlockSize {
267
+ if n > r . maxBlock {
201
268
r .err = ErrCorrupt
202
269
return 0 , r .err
203
270
}
@@ -238,7 +305,12 @@ func (r *Reader) Read(p []byte) (int, error) {
238
305
}
239
306
// Section 4.4 Padding (chunk type 0xfe).
240
307
// Section 4.6. Reserved skippable chunks (chunk types 0x80-0xfd).
241
- if ! r .readFull (r .buf [:chunkLen ], false ) {
308
+ if chunkLen > maxBlockSize {
309
+ r .err = ErrUnsupported
310
+ return 0 , r .err
311
+ }
312
+
313
+ if ! r .skipN (r .buf , chunkLen , false ) {
242
314
return 0 , r .err
243
315
}
244
316
}
@@ -286,10 +358,6 @@ func (r *Reader) Skip(n int64) error {
286
358
r .readHeader = true
287
359
}
288
360
chunkLen := int (r .buf [1 ]) | int (r .buf [2 ])<< 8 | int (r .buf [3 ])<< 16
289
- if chunkLen > len (r .buf ) {
290
- r .err = ErrUnsupported
291
- return r .err
292
- }
293
361
294
362
// The chunk types are specified at
295
363
// https://github.com/google/snappy/blob/master/framing_format.txt
@@ -300,6 +368,10 @@ func (r *Reader) Skip(n int64) error {
300
368
r .err = ErrCorrupt
301
369
return r .err
302
370
}
371
+ if chunkLen > len (r .buf ) {
372
+ r .err = ErrUnsupported
373
+ return r .err
374
+ }
303
375
buf := r .buf [:chunkLen ]
304
376
if ! r .readFull (buf , false ) {
305
377
return r .err
@@ -312,7 +384,7 @@ func (r *Reader) Skip(n int64) error {
312
384
r .err = err
313
385
return r .err
314
386
}
315
- if dLen > maxBlockSize {
387
+ if dLen > r . maxBlock {
316
388
r .err = ErrCorrupt
317
389
return r .err
318
390
}
@@ -342,6 +414,10 @@ func (r *Reader) Skip(n int64) error {
342
414
r .err = ErrCorrupt
343
415
return r .err
344
416
}
417
+ if chunkLen > len (r .buf ) {
418
+ r .err = ErrUnsupported
419
+ return r .err
420
+ }
345
421
buf := r .buf [:checksumSize ]
346
422
if ! r .readFull (buf , false ) {
347
423
return r .err
@@ -350,7 +426,7 @@ func (r *Reader) Skip(n int64) error {
350
426
// Read directly into r.decoded instead of via r.buf.
351
427
n2 := chunkLen - checksumSize
352
428
if n2 > len (r .decoded ) {
353
- if n2 > maxBlockSize {
429
+ if n2 > r . maxBlock {
354
430
r .err = ErrCorrupt
355
431
return r .err
356
432
}
@@ -391,13 +467,15 @@ func (r *Reader) Skip(n int64) error {
391
467
r .err = ErrUnsupported
392
468
return r .err
393
469
}
470
+ if chunkLen > maxBlockSize {
471
+ r .err = ErrUnsupported
472
+ return r .err
473
+ }
394
474
// Section 4.4 Padding (chunk type 0xfe).
395
475
// Section 4.6. Reserved skippable chunks (chunk types 0x80-0xfd).
396
- if ! r .readFull (r .buf [: chunkLen ] , false ) {
476
+ if ! r .skipN (r .buf , chunkLen , false ) {
397
477
return r .err
398
478
}
399
-
400
- return io .ErrUnexpectedEOF
401
479
}
402
480
return nil
403
481
}
0 commit comments