update dependencies (#6267)
Signed-off-by: hongming <coder.scala@gmail.com>
This commit is contained in:
81
vendor/github.com/open-policy-agent/opa/util/read_gzip_body.go
generated
vendored
Normal file
81
vendor/github.com/open-policy-agent/opa/util/read_gzip_body.go
generated
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/open-policy-agent/opa/util/decoding"
|
||||
)
|
||||
|
||||
var gzipReaderPool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
reader := new(gzip.Reader)
|
||||
return reader
|
||||
},
|
||||
}
|
||||
|
||||
// Note(philipc): Originally taken from server/server.go
|
||||
// The DecodingLimitHandler handles validating that the gzip payload is within the
|
||||
// allowed max size limit. Thus, in the event of a forged payload size trailer,
|
||||
// the worst that can happen is that we waste memory up to the allowed max gzip
|
||||
// payload size, but not an unbounded amount of memory, as was potentially
|
||||
// possible before.
|
||||
func ReadMaybeCompressedBody(r *http.Request) ([]byte, error) {
|
||||
var content *bytes.Buffer
|
||||
// Note(philipc): If the request body is of unknown length (such as what
|
||||
// happens when 'Transfer-Encoding: chunked' is set), we have to do an
|
||||
// incremental read of the body. In this case, we can't be too clever, we
|
||||
// just do the best we can with whatever is streamed over to us.
|
||||
// Fetch gzip payload size limit from request context.
|
||||
if maxLength, ok := decoding.GetServerDecodingMaxLen(r.Context()); ok {
|
||||
bs, err := io.ReadAll(io.LimitReader(r.Body, maxLength))
|
||||
if err != nil {
|
||||
return bs, err
|
||||
}
|
||||
content = bytes.NewBuffer(bs)
|
||||
} else {
|
||||
// Read content from the request body into a buffer of known size.
|
||||
content = bytes.NewBuffer(make([]byte, 0, r.ContentLength))
|
||||
if _, err := io.CopyN(content, r.Body, r.ContentLength); err != nil {
|
||||
return content.Bytes(), err
|
||||
}
|
||||
}
|
||||
|
||||
// Decompress gzip content by reading from the buffer.
|
||||
if strings.Contains(r.Header.Get("Content-Encoding"), "gzip") {
|
||||
// Fetch gzip payload size limit from request context.
|
||||
gzipMaxLength, _ := decoding.GetServerDecodingGzipMaxLen(r.Context())
|
||||
|
||||
// Note(philipc): The last 4 bytes of a well-formed gzip blob will
|
||||
// always be a little-endian uint32, representing the decompressed
|
||||
// content size, modulo 2^32. We validate that the size is safe,
|
||||
// earlier in DecodingLimitHandler.
|
||||
sizeTrailerField := binary.LittleEndian.Uint32(content.Bytes()[content.Len()-4:])
|
||||
if sizeTrailerField > uint32(gzipMaxLength) {
|
||||
return content.Bytes(), fmt.Errorf("gzip payload too large")
|
||||
}
|
||||
// Pull a gzip decompressor from the pool, and assign it to the current
|
||||
// buffer, using Reset(). Later, return it back to the pool for another
|
||||
// request to use.
|
||||
gzReader := gzipReaderPool.Get().(*gzip.Reader)
|
||||
if err := gzReader.Reset(content); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer gzReader.Close()
|
||||
defer gzipReaderPool.Put(gzReader)
|
||||
decompressedContent := bytes.NewBuffer(make([]byte, 0, sizeTrailerField))
|
||||
if _, err := io.CopyN(decompressedContent, gzReader, int64(sizeTrailerField)); err != nil {
|
||||
return decompressedContent.Bytes(), err
|
||||
}
|
||||
return decompressedContent.Bytes(), nil
|
||||
}
|
||||
|
||||
// Request was not compressed; return the content bytes.
|
||||
return content.Bytes(), nil
|
||||
}
|
||||
Reference in New Issue
Block a user