Fix gzip support in socket_listener with tcp sockets (#7446)
This commit is contained in:
@@ -1,18 +1,78 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"errors"
|
||||
"io"
|
||||
)
|
||||
|
||||
// NewStreamContentDecoder returns a reader that will decode the stream
|
||||
// according to the encoding type.
|
||||
func NewStreamContentDecoder(encoding string, r io.Reader) (io.Reader, error) {
|
||||
switch encoding {
|
||||
case "gzip":
|
||||
return NewGzipReader(r)
|
||||
case "identity", "":
|
||||
return r, nil
|
||||
default:
|
||||
return nil, errors.New("invalid value for content_encoding")
|
||||
}
|
||||
}
|
||||
|
||||
// GzipReader is similar to gzip.Reader but reads only a single gzip stream per read.
|
||||
type GzipReader struct {
|
||||
r io.Reader
|
||||
z *gzip.Reader
|
||||
endOfStream bool
|
||||
}
|
||||
|
||||
func NewGzipReader(r io.Reader) (io.Reader, error) {
|
||||
// We need a read that implements ByteReader in order to line up the next
|
||||
// stream.
|
||||
br := bufio.NewReader(r)
|
||||
|
||||
// Reads the first gzip stream header.
|
||||
z, err := gzip.NewReader(br)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Prevent future calls to Read from reading the following gzip header.
|
||||
z.Multistream(false)
|
||||
|
||||
return &GzipReader{r: br, z: z}, nil
|
||||
}
|
||||
|
||||
func (r *GzipReader) Read(b []byte) (int, error) {
|
||||
if r.endOfStream {
|
||||
// Reads the next gzip header and prepares for the next stream.
|
||||
err := r.z.Reset(r.r)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
r.z.Multistream(false)
|
||||
r.endOfStream = false
|
||||
}
|
||||
|
||||
n, err := r.z.Read(b)
|
||||
|
||||
// Since multistream is disabled, io.EOF indicates the end of the gzip
|
||||
// sequence. On the next read we must read the next gzip header.
|
||||
if err == io.EOF {
|
||||
r.endOfStream = true
|
||||
return n, nil
|
||||
}
|
||||
return n, err
|
||||
|
||||
}
|
||||
|
||||
// NewContentEncoder returns a ContentEncoder for the encoding type.
|
||||
func NewContentEncoder(encoding string) (ContentEncoder, error) {
|
||||
switch encoding {
|
||||
case "gzip":
|
||||
return NewGzipEncoder()
|
||||
|
||||
case "identity", "":
|
||||
return NewIdentityEncoder(), nil
|
||||
default:
|
||||
|
||||
Reference in New Issue
Block a user