Test origin host and port checks and a 1 GiB size maximum (closes #61)

Failing cases: access_control_allow_origin with two hosts, an empty
port, no host, port 0, port 99999 or a non-ASCII host name, and
upstream_max_response_size above 1 GiB, up to the largest 64-bit
integer, where the image processor's limit wraps negative. Each must
abort startup naming the key and the value. The bad origins are now one
list so the table fits the linter's function length limit; the size
test uses 1 GiB to show the maximum itself is accepted, and IPv4 and
IPv6 origins are shown to be accepted.

Model: opus-5-5
This commit is contained in:
2026-09-29 06:11:44 +00:00
parent 4370ccb083
commit ff50a59bae
@@ -633,14 +633,14 @@ func TestOmittedOriginTimeoutsAndSizeUseDefaults(t *testing.T) {
// TestExplicitOriginTimeoutsAndSizeAreUsed checks that valid values for // TestExplicitOriginTimeoutsAndSizeAreUsed checks that valid values for
// the CORS origin, the two timeouts and the response size limit are used // the CORS origin, the two timeouts and the response size limit are used
// as given. // as given. The size is the largest accepted, 1 GiB.
func TestExplicitOriginTimeoutsAndSizeAreUsed(t *testing.T) { func TestExplicitOriginTimeoutsAndSizeAreUsed(t *testing.T) {
t.Parallel() t.Parallel()
c, err := configFromYAML(t, signingKeyLine+` c, err := configFromYAML(t, signingKeyLine+`
access_control_allow_origin: https://app.example.com access_control_allow_origin: https://app.example.com
upstream_fetch_timeout: 10s upstream_fetch_timeout: 10s
upstream_max_response_size: 1048576 upstream_max_response_size: 1073741824
downstream_timeout: 2m downstream_timeout: 2m
`) `)
if err != nil { if err != nil {
@@ -656,8 +656,8 @@ downstream_timeout: 2m
t.Errorf("UpstreamFetchTimeout = %v, want 10s", c.UpstreamFetchTimeout) t.Errorf("UpstreamFetchTimeout = %v, want 10s", c.UpstreamFetchTimeout)
} }
if c.UpstreamMaxResponseSize != 1048576 { if c.UpstreamMaxResponseSize != 1073741824 {
t.Errorf("UpstreamMaxResponseSize = %d, want 1048576", t.Errorf("UpstreamMaxResponseSize = %d, want 1073741824",
c.UpstreamMaxResponseSize) c.UpstreamMaxResponseSize)
} }
@@ -667,11 +667,14 @@ downstream_timeout: 2m
} }
// TestOriginWithPortOrAnyOriginIsAccepted checks the other accepted forms // TestOriginWithPortOrAnyOriginIsAccepted checks the other accepted forms
// of access_control_allow_origin: "*", and an origin with a port. // of access_control_allow_origin: "*", an origin with a port, and origins
// whose host is an IPv4 or IPv6 address.
func TestOriginWithPortOrAnyOriginIsAccepted(t *testing.T) { func TestOriginWithPortOrAnyOriginIsAccepted(t *testing.T) {
t.Parallel() t.Parallel()
for _, origin := range []string{"*", "http://localhost:3000"} { for _, origin := range []string{
"*", "http://localhost:3000", "http://192.0.2.1", "http://[2001:db8::1]:8080",
} {
c, err := configFromYAML(t, signingKeyLine+ c, err := configFromYAML(t, signingKeyLine+
"access_control_allow_origin: \""+origin+"\"\n") "access_control_allow_origin: \""+origin+"\"\n")
if err != nil { if err != nil {
@@ -739,11 +742,44 @@ func invalidTimeoutCases() []abortCase {
} }
// invalidSizeAndOriginCases are configs where upstream_max_response_size // invalidSizeAndOriginCases are configs where upstream_max_response_size
// is not a positive whole number of bytes, or access_control_allow_origin // is not a whole number of bytes from 1 to 1 GiB, or
// is neither "*" nor an origin; each must abort startup naming the key // access_control_allow_origin is neither "*" nor an origin; each must
// and the value. // abort startup naming the key and the value.
func invalidSizeAndOriginCases() []abortCase { func invalidSizeAndOriginCases() []abortCase {
return []abortCase{ badOrigins := []string{
"", // empty
"example.com", // no scheme
"https://example.com/images", // a path
"https://example.com/", // a trailing slash
// The CORS middleware reads a * inside an origin as a pattern
// that lets other sites read responses.
"https://*",
"https://*.example.com",
"https://*example.com",
"https://a.com,b.com", // two hosts
"https://example.com:", // an empty port
"https://:8443", // no host
"https://example.com:0", // a port below 1
"https://example.com:99999", // a port above 65535
"https://exämple.com", // a host name that is not ASCII
}
cases := make([]abortCase, 0, len(badOrigins))
for _, origin := range badOrigins {
cases = append(cases, abortCase{
name: "access_control_allow_origin " + origin,
yaml: signingKeyLine +
"access_control_allow_origin: \"" + origin + "\"\n",
wantErrSubstrings: []string{keyAccessControlAllowOrigin, origin},
})
}
return append(cases, []abortCase{
{
name: "access_control_allow_origin null",
yaml: signingKeyLine + "access_control_allow_origin: null\n",
wantErrSubstrings: []string{keyAccessControlAllowOrigin, nullValueText},
},
{ {
name: "upstream_max_response_size with a unit", name: "upstream_max_response_size with a unit",
yaml: signingKeyLine + "upstream_max_response_size: 50MB\n", yaml: signingKeyLine + "upstream_max_response_size: 50MB\n",
@@ -770,56 +806,19 @@ func invalidSizeAndOriginCases() []abortCase {
wantErrSubstrings: []string{keyUpstreamMaxResponseSize, nullValueText}, wantErrSubstrings: []string{keyUpstreamMaxResponseSize, nullValueText},
}, },
{ {
name: "access_control_allow_origin bare hostname", name: "upstream_max_response_size above 1 GiB",
yaml: signingKeyLine + "access_control_allow_origin: example.com\n", yaml: signingKeyLine + "upstream_max_response_size: 1073741825\n",
wantErrSubstrings: []string{keyUpstreamMaxResponseSize, "1073741825"},
},
{
name: "upstream_max_response_size largest 64-bit integer",
yaml: signingKeyLine +
"upstream_max_response_size: 9223372036854775807\n",
wantErrSubstrings: []string{ wantErrSubstrings: []string{
keyAccessControlAllowOrigin, "example.com", keyUpstreamMaxResponseSize, "9223372036854775807",
}, },
}, },
{ }...)
name: "access_control_allow_origin with a path",
yaml: signingKeyLine +
"access_control_allow_origin: https://example.com/images\n",
wantErrSubstrings: []string{
keyAccessControlAllowOrigin, "https://example.com/images",
},
},
{
name: "access_control_allow_origin trailing slash",
yaml: signingKeyLine +
"access_control_allow_origin: https://example.com/\n",
wantErrSubstrings: []string{
keyAccessControlAllowOrigin, "https://example.com/",
},
},
{
name: "access_control_allow_origin host *",
yaml: signingKeyLine + "access_control_allow_origin: https://*\n",
wantErrSubstrings: []string{keyAccessControlAllowOrigin, "https://*"},
},
{
name: "access_control_allow_origin host *.example.com",
yaml: signingKeyLine +
"access_control_allow_origin: https://*.example.com\n",
wantErrSubstrings: []string{keyAccessControlAllowOrigin, "https://*.example.com"},
},
{
name: "access_control_allow_origin host *example.com",
yaml: signingKeyLine +
"access_control_allow_origin: https://*example.com\n",
wantErrSubstrings: []string{keyAccessControlAllowOrigin, "https://*example.com"},
},
{
name: "access_control_allow_origin empty",
yaml: signingKeyLine + "access_control_allow_origin: \"\"\n",
wantErrSubstrings: []string{keyAccessControlAllowOrigin},
},
{
name: "access_control_allow_origin null",
yaml: signingKeyLine + "access_control_allow_origin: null\n",
wantErrSubstrings: []string{keyAccessControlAllowOrigin, nullValueText},
},
}
} }
// TestInvalidOriginTimeoutOrSizeAbortsStartup verifies the // TestInvalidOriginTimeoutOrSizeAbortsStartup verifies the