mirror of
https://github.com/open-policy-agent/opa.git
synced 2026-08-12 19:32:48 -06:00
c5706eef7c
This commit introduces a few major changes: - (Breaking change) Limits now exist for maximum request body sizes. - Buffers are preallocated for reading request bodies. - Buffers are preallocated for decompressing request bodies. - Gzip decoder instances are reused in a `sync.Pool` across requests. The effect on garbage collection is dramatically fewer GC pauses, giving a roughly 9% RPS improvement in load tests with gzipped request bodies. For larger request sizes, the number of GC pauses is dramatically reduced, although the peak pause time may increase by a few percent. Implementation notes: - The DecodingLimits handler enforces the max request body size both through a Content-Length check, and a MaxBytesReader wrapper around the payload. - The DecodingLimits handler passes the gzip payload size limit down using a context key. Signed-off-by: Philip Conrad <philipaconrad@gmail.com>
109 lines
2.4 KiB
Go
109 lines
2.4 KiB
Go
package decoding
|
|
|
|
import (
|
|
"fmt"
|
|
"testing"
|
|
)
|
|
|
|
func TestConfigValidation(t *testing.T) {
|
|
tests := []struct {
|
|
input string
|
|
wantErr bool
|
|
}{
|
|
{
|
|
input: `{}`,
|
|
wantErr: false,
|
|
},
|
|
{
|
|
input: `{"gzip": {"max_length": "not-a-number"}}`,
|
|
wantErr: true,
|
|
},
|
|
{
|
|
input: `{"gzip": {max_length": 42}}`,
|
|
wantErr: false,
|
|
},
|
|
{
|
|
input: `{"gzip":{"max_length": "42"}}`,
|
|
wantErr: true,
|
|
},
|
|
{
|
|
input: `{"gzip":{"max_length": 0}}`,
|
|
wantErr: true,
|
|
},
|
|
{
|
|
input: `{"gzip":{"max_length": -10}}`,
|
|
wantErr: true,
|
|
},
|
|
{
|
|
input: `{"gzip":{"random_key": 0}}`,
|
|
wantErr: false,
|
|
},
|
|
{
|
|
input: `{"gzip": {"max_length": -10}}`,
|
|
wantErr: true,
|
|
},
|
|
{
|
|
input: `{"max_length": "not-a-number"}`,
|
|
wantErr: true,
|
|
},
|
|
{
|
|
input: `{"gzip":{}}`,
|
|
wantErr: false,
|
|
},
|
|
{
|
|
input: `{"max_length": "not-a-number", "gzip":{}}`,
|
|
wantErr: true,
|
|
},
|
|
{
|
|
input: `{"max_length": 42, "gzip":{"max_length": 42}}`,
|
|
wantErr: false,
|
|
},
|
|
}
|
|
|
|
for i, test := range tests {
|
|
t.Run(fmt.Sprintf("TestConfigValidation_case_%d", i), func(t *testing.T) {
|
|
_, err := NewConfigBuilder().WithBytes([]byte(test.input)).Parse()
|
|
if err != nil && !test.wantErr {
|
|
t.Fatalf("Unexpected error: %s", err.Error())
|
|
}
|
|
if err == nil && test.wantErr {
|
|
t.Fail()
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestConfigValue(t *testing.T) {
|
|
tests := []struct {
|
|
input string
|
|
maxLengthExpectedValue int64
|
|
gzipMaxLengthExpectedValue int64
|
|
}{
|
|
{
|
|
input: `{}`,
|
|
maxLengthExpectedValue: 268435456,
|
|
gzipMaxLengthExpectedValue: 536870912,
|
|
},
|
|
{
|
|
input: `{"max_length": 5, "gzip":{"max_length": 42}}`,
|
|
maxLengthExpectedValue: 5,
|
|
gzipMaxLengthExpectedValue: 42,
|
|
},
|
|
}
|
|
|
|
for i, test := range tests {
|
|
t.Run(fmt.Sprintf("TestConfigValue_case_%d", i), func(t *testing.T) {
|
|
config, err := NewConfigBuilder().WithBytes([]byte(test.input)).Parse()
|
|
if err != nil {
|
|
t.Fatalf("Error building configuration: %s", err.Error())
|
|
}
|
|
if *config.MaxLength != test.maxLengthExpectedValue {
|
|
t.Fatalf("Unexpected config value for max_length (exp/actual): %d, %d", test.maxLengthExpectedValue, *config.MaxLength)
|
|
}
|
|
if *config.Gzip.MaxLength != test.gzipMaxLengthExpectedValue {
|
|
t.Fatalf("Unexpected config value for gzip.max_length (exp/actual): %d, %d", test.gzipMaxLengthExpectedValue, *config.Gzip.MaxLength)
|
|
}
|
|
})
|
|
}
|
|
}
|