check / check (push) Successful in 15s
README.md documented access_control_allow_origin, upstream_fetch_timeout, upstream_max_response_size and downstream_timeout, but pixa did not know them, so a config following the README aborted startup. Each is now a setting with its PIXA_ variable, defaulting to the value that was fixed in the code: *, 30s, 50 MiB and 60s. Durations are Go duration strings and must be positive; the size is whole bytes, at most 1 GiB. The origin is * or one http or https origin written exactly as a browser sends it; anything else aborts startup. downstream_timeout sets both the server's write timeout and the per-request timeout. The owner approved the edits to existing tests. Model: opus-5-5
70 lines
2.0 KiB
Go
70 lines
2.0 KiB
Go
package server
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
|
|
"sneak.berlin/go/pixa/internal/config"
|
|
)
|
|
|
|
// TestNewHTTPServerTimeouts verifies that the constructed http.Server
|
|
// carries every hardening timeout wired onto it, including the slowloris
|
|
// defense (ReadHeaderTimeout) and the keep-alive bound (IdleTimeout). This
|
|
// guards against a field being defined but never set on the server, so
|
|
// each assertion compares the server field to its constant, or, for
|
|
// WriteTimeout, to downstream_timeout from the config.
|
|
func TestNewHTTPServerTimeouts(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
s := &Server{config: &config.Config{
|
|
Port: 8080,
|
|
DownstreamTimeout: 45 * time.Second,
|
|
}}
|
|
|
|
srv := s.newHTTPServer()
|
|
|
|
fields := []struct {
|
|
name string
|
|
got time.Duration
|
|
want time.Duration
|
|
}{
|
|
{"ReadTimeout", srv.ReadTimeout, HTTPReadTimeout},
|
|
{"ReadHeaderTimeout", srv.ReadHeaderTimeout, HTTPReadHeaderTimeout},
|
|
{"WriteTimeout", srv.WriteTimeout, 45 * time.Second},
|
|
{"IdleTimeout", srv.IdleTimeout, HTTPIdleTimeout},
|
|
}
|
|
|
|
for _, f := range fields {
|
|
if f.got != f.want {
|
|
t.Errorf("%s = %v, want %v", f.name, f.got, f.want)
|
|
}
|
|
}
|
|
|
|
if srv.MaxHeaderBytes != HTTPMaxHeaderBytes {
|
|
t.Errorf("MaxHeaderBytes = %d, want %d",
|
|
srv.MaxHeaderBytes, HTTPMaxHeaderBytes)
|
|
}
|
|
|
|
if srv.Handler != s {
|
|
t.Error("Handler is not the server")
|
|
}
|
|
}
|
|
|
|
// TestHardeningTimeoutValues pins the intent behind the two new timeouts
|
|
// without hard-coding brittle exact durations: the header-read phase is
|
|
// bounded strictly shorter than the whole-request read (the slowloris
|
|
// dribble), and idle keep-alive connections are bounded rather than held
|
|
// open forever.
|
|
func TestHardeningTimeoutValues(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
if HTTPReadHeaderTimeout <= 0 || HTTPReadHeaderTimeout > HTTPReadTimeout {
|
|
t.Errorf("ReadHeaderTimeout = %v, want positive and <= ReadTimeout %v",
|
|
HTTPReadHeaderTimeout, HTTPReadTimeout)
|
|
}
|
|
|
|
if HTTPIdleTimeout <= 0 {
|
|
t.Errorf("IdleTimeout = %v, want positive bound", HTTPIdleTimeout)
|
|
}
|
|
}
|