Files
releases/plugins/server/encoding/config.go
T
AdrianArnautu 9e97f98d12 This change allows the HTTP clients to consume and send gzip compressed response and request body. (#5696)
It is available for the following REST API endpoints:
- GET & POST HTTP methods on /v0/data & /v1/data endpoints
- POST HTTP method on /v1/compile endpoint

HTTP clients can optionally:
- send 'Accept-Encoding: gzip' header and expect a gzip compressed body and a Content-Encoding: gzip response header. The server will send the content encoded as gzip only after a threshold defined by server.encoding.gzip.min_length (default value is 1024). If the size is below the threshold, the body is not compressed
- send 'Content-Encoding: gzip' header and a gzip compressed body and expect the server to correctly interpret the request

Fixes #5310

Signed-off-by: aarnautu <aarnautu@adobe.com>
2023-03-09 09:38:39 +01:00

92 lines
2.3 KiB
Go

package encoding
import (
"compress/gzip"
"fmt"
"github.com/open-policy-agent/opa/util"
)
var defaultGzipMinLength = 1024
var defaultGzipCompressionLevel = gzip.BestCompression
// Config represents the configuration for the Server.Encoding settings
type Config struct {
Gzip *Gzip `json:"gzip,omitempty"`
}
// Gzip represents the configuration for the Server.Encoding.Gzip settings
type Gzip struct {
MinLength *int `json:"min_length,omitempty"` // the minimum length of a response that will be gzipped
CompressionLevel *int `json:"compression_level,omitempty"` // the compression level for gzip
}
// ConfigBuilder assists in the construction of the plugin configuration.
type ConfigBuilder struct {
raw []byte
}
// NewConfigBuilder returns a new ConfigBuilder to build and parse the server config
func NewConfigBuilder() *ConfigBuilder {
return &ConfigBuilder{}
}
// WithBytes sets the raw server config
func (b *ConfigBuilder) WithBytes(config []byte) *ConfigBuilder {
b.raw = config
return b
}
// Parse returns a valid Config object with defaults injected.
func (b *ConfigBuilder) Parse() (*Config, error) {
if b.raw == nil {
defaultConfig := &Config{
Gzip: &Gzip{
MinLength: &defaultGzipMinLength,
CompressionLevel: &defaultGzipCompressionLevel,
},
}
return defaultConfig, nil
}
var result Config
if err := util.Unmarshal(b.raw, &result); err != nil {
return nil, err
}
return &result, result.validateAndInjectDefaults()
}
func (c *Config) validateAndInjectDefaults() error {
if c.Gzip == nil {
c.Gzip = &Gzip{
MinLength: &defaultGzipMinLength,
CompressionLevel: &defaultGzipCompressionLevel,
}
}
if c.Gzip.MinLength == nil {
c.Gzip.MinLength = &defaultGzipMinLength
}
if c.Gzip.CompressionLevel == nil {
c.Gzip.CompressionLevel = &defaultGzipCompressionLevel
}
if *c.Gzip.MinLength <= 0 {
return fmt.Errorf("invalid value for server.encoding.gzip.min_length field, should be a positive number")
}
acceptedCompressionLevels := map[int]bool{
gzip.NoCompression: true,
gzip.BestSpeed: true,
gzip.BestCompression: true,
}
_, compressionLevelAccepted := acceptedCompressionLevels[*c.Gzip.CompressionLevel]
if !compressionLevelAccepted {
return fmt.Errorf("invalid value for server.encoding.gzip.compression_level field, accepted values are 0, 1 or 9")
}
return nil
}