1 // Copyright 2017 The Gorilla WebSocket Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
16 minCompressionLevel = -2 // flate.HuffmanOnly not defined in Go < 1.6
17 maxCompressionLevel = flate.BestCompression
18 defaultCompressionLevel = 1
22 flateWriterPools [maxCompressionLevel - minCompressionLevel + 1]sync.Pool
23 flateReaderPool = sync.Pool{New: func() interface{} {
24 return flate.NewReader(nil)
28 func decompressNoContextTakeover(r io.Reader) io.ReadCloser {
30 // Add four bytes as specified in RFC
32 // Add final block to squelch unexpected EOF error from flate reader.
33 "\x01\x00\x00\xff\xff"
35 fr, _ := flateReaderPool.Get().(io.ReadCloser)
36 fr.(flate.Resetter).Reset(io.MultiReader(r, strings.NewReader(tail)), nil)
37 return &flateReadWrapper{fr}
40 func isValidCompressionLevel(level int) bool {
41 return minCompressionLevel <= level && level <= maxCompressionLevel
44 func compressNoContextTakeover(w io.WriteCloser, level int) io.WriteCloser {
45 p := &flateWriterPools[level-minCompressionLevel]
46 tw := &truncWriter{w: w}
47 fw, _ := p.Get().(*flate.Writer)
49 fw, _ = flate.NewWriter(tw, level)
53 return &flateWriteWrapper{fw: fw, tw: tw, p: p}
56 // truncWriter is an io.Writer that writes all but the last four bytes of the
57 // stream to another io.Writer.
58 type truncWriter struct {
64 func (w *truncWriter) Write(p []byte) (int, error) {
67 // fill buffer first for simplicity.
69 n = copy(w.p[w.n:], p)
82 if nn, err := w.w.Write(w.p[:m]); err != nil {
87 copy(w.p[len(w.p)-m:], p[len(p)-m:])
88 nn, err := w.w.Write(p[:len(p)-m])
92 type flateWriteWrapper struct {
98 func (w *flateWriteWrapper) Write(p []byte) (int, error) {
100 return 0, errWriteClosed
105 func (w *flateWriteWrapper) Close() error {
107 return errWriteClosed
112 if w.tw.p != [4]byte{0, 0, 0xff, 0xff} {
113 return errors.New("websocket: internal error, unexpected bytes at end of flate stream")
115 err2 := w.tw.w.Close()
122 type flateReadWrapper struct {
126 func (r *flateReadWrapper) Read(p []byte) (int, error) {
128 return 0, io.ErrClosedPipe
130 n, err := r.fr.Read(p)
132 // Preemptively place the reader back in the pool. This helps with
133 // scenarios where the application does not call NextReader() soon after
140 func (r *flateReadWrapper) Close() error {
142 return io.ErrClosedPipe
145 flateReaderPool.Put(r.fr)