Skip to content

Commit

Permalink
remove AssumeNoWebCachingOfPreflightResponses option
Browse files Browse the repository at this point in the history
  • Loading branch information
jub0bs committed Apr 4, 2024
1 parent 6abdd6d commit 3dfd279
Show file tree
Hide file tree
Showing 5 changed files with 34 additions and 321 deletions.
232 changes: 0 additions & 232 deletions fcors_anonymous_multiple_origins_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -793,238 +793,6 @@ func Test_AllowAccess_From_Multiple_Origins_And_Expose_Header_With_PrivateNetwor
process(t, cors(dummyHandler), cases)
}

func Test_AllowAccess_From_Multiple_Origins_And_AssumeNoWebCachingOfPreflightResponses(t *testing.T) {
const (
dummyVaryValue = "whatever"
dummyStatusCode = 299
)
dummyHandler := http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
// remarkable Vary header value to make sure
// it isn't suppressed by the middleware
w.Header().Add(headerVary, dummyVaryValue)
w.WriteHeader(dummyStatusCode)
})
const (
dummyPreflightSuccessStatus = 279
dummyMaxAge = 30
exposedResponseHeader = "dummyResponseHeader"
)
cors, err := fcors.AllowAccess(
fcors.FromOrigins("https://*.example.com"),
fcors.PreflightSuccessStatus(dummyPreflightSuccessStatus),
fcors.MaxAgeInSeconds(dummyMaxAge),
risky.AssumeNoWebCachingOfPreflightResponses(),
)
if err != nil {
t.Errorf("got error with message %q; want nil error", err.Error())
return
}
const (
allowedOrigin = "https://foo.example.com"
disallowedBaseOrigin = "https://example.com"
)
cases := []TestCase{
{
name: "non-CORS GET request",
reqMethod: http.MethodGet,
expectedStatus: dummyStatusCode,
expectedRespHeaders: http.Header{
headerVary: []string{headerOrigin, dummyVaryValue},
},
}, {
name: "non-CORS OPTIONS request",
reqMethod: http.MethodOptions,
expectedStatus: dummyStatusCode,
expectedRespHeaders: http.Header{
headerVary: []string{headerOrigin, dummyVaryValue},
},
}, {
name: "CORS GET request from a valid and allowed origin",
reqMethod: http.MethodGet,
reqHeaders: http.Header{
headerOrigin: []string{allowedOrigin},
},
expectedStatus: dummyStatusCode,
expectedRespHeaders: http.Header{
headerACAO: []string{allowedOrigin},
headerVary: []string{headerOrigin, dummyVaryValue},
},
}, {
name: "CORS GET request from a valid but disallowed origin",
reqMethod: http.MethodGet,
reqHeaders: http.Header{
headerOrigin: []string{disallowedBaseOrigin},
},
expectedStatus: dummyStatusCode,
expectedRespHeaders: http.Header{
headerVary: []string{headerOrigin, dummyVaryValue},
},
}, {
name: "CORS GET request from an invalid origin",
reqMethod: http.MethodGet,
reqHeaders: http.Header{
headerOrigin: []string{dummyInvalidOrigin},
},
expectedStatus: dummyStatusCode,
expectedRespHeaders: http.Header{
headerVary: []string{headerOrigin, dummyVaryValue},
},
}, {
name: "CORS GET request from an abnormally long and disallowed origin",
reqMethod: http.MethodGet,
reqHeaders: http.Header{
headerOrigin: []string{abnormallyLongOrigin},
},
expectedStatus: dummyStatusCode,
expectedRespHeaders: http.Header{
headerVary: []string{headerOrigin, dummyVaryValue},
},
}, {
name: "non-preflight CORS OPTIONS request from a valid and allowed origin",
reqMethod: http.MethodOptions,
reqHeaders: http.Header{
headerOrigin: []string{allowedOrigin},
},
expectedStatus: dummyStatusCode,
expectedRespHeaders: http.Header{
headerACAO: []string{allowedOrigin},
headerVary: []string{headerOrigin, dummyVaryValue},
},
}, {
name: "non-preflight CORS OPTIONS request from a valid but disallowed origin",
reqMethod: http.MethodOptions,
reqHeaders: http.Header{
headerOrigin: []string{disallowedBaseOrigin},
},
expectedStatus: dummyStatusCode,
expectedRespHeaders: http.Header{
headerVary: []string{headerOrigin, dummyVaryValue},
},
}, {
name: "CORS preflight request with GET from a valid and allowed origin",
reqMethod: http.MethodOptions,
reqHeaders: http.Header{
headerOrigin: []string{allowedOrigin},
headerACRM: []string{http.MethodGet},
},
expectedStatus: dummyPreflightSuccessStatus,
expectedRespHeaders: http.Header{
headerACAO: []string{allowedOrigin},
headerACMA: []string{stringFromUint(dummyMaxAge)},
},
}, {
name: "CORS preflight request with GET from a valid but disallowed origin",
reqMethod: http.MethodOptions,
reqHeaders: http.Header{
headerOrigin: []string{disallowedBaseOrigin},
headerACRM: []string{http.MethodGet},
},
expectedStatus: http.StatusForbidden,
}, {
name: "CORS preflight request with GET from an invalid origin",
reqMethod: http.MethodOptions,
reqHeaders: http.Header{
headerOrigin: []string{dummyInvalidOrigin},
headerACRM: []string{http.MethodGet},
},
expectedStatus: http.StatusForbidden,
}, {
name: "CORS preflight request with GET from an abnormally long and disallowed origin",
reqMethod: http.MethodOptions,
reqHeaders: http.Header{
headerOrigin: []string{abnormallyLongOrigin},
headerACRM: []string{http.MethodGet},
},
expectedStatus: http.StatusForbidden,
}, {
name: "CORS preflight request with disallowed PUT from a valid and allowed origin",
reqMethod: http.MethodOptions,
reqHeaders: http.Header{
headerOrigin: []string{allowedOrigin},
headerACRM: []string{http.MethodPut},
},
expectedStatus: dummyPreflightSuccessStatus,
expectedRespHeaders: http.Header{
headerACAO: []string{allowedOrigin},
},
}, {
name: "CORS preflight request with disallowed PUT from a valid but disallowed origin",
reqMethod: http.MethodOptions,
reqHeaders: http.Header{
headerOrigin: []string{disallowedBaseOrigin},
headerACRM: []string{http.MethodPut},
},
expectedStatus: http.StatusForbidden,
}, {
name: "CORS preflight request with GET with non-safelisted header names from a valid and allowed origin",
reqMethod: http.MethodOptions,
reqHeaders: http.Header{
headerOrigin: []string{allowedOrigin},
headerACRM: []string{http.MethodGet},
headerACRH: []string{"foo,bar,baz"},
},
expectedStatus: dummyPreflightSuccessStatus,
expectedRespHeaders: http.Header{
headerACAO: []string{allowedOrigin},
},
}, {
name: "CORS preflight request with GET with non-safelisted header names from a valid but disallowed origin",
reqMethod: http.MethodOptions,
reqHeaders: http.Header{
headerOrigin: []string{disallowedBaseOrigin},
headerACRM: []string{http.MethodGet},
headerACRH: []string{"foo,bar,baz"},
},
expectedStatus: http.StatusForbidden,
}, {
name: "CORS preflight request with GET with ACRPN from a valid and allowed origin",
reqMethod: http.MethodOptions,
reqHeaders: http.Header{
headerOrigin: []string{allowedOrigin},
headerACRM: []string{http.MethodGet},
headerACRPN: []string{headerValueTrue},
},
expectedStatus: dummyPreflightSuccessStatus,
expectedRespHeaders: http.Header{
headerACAO: []string{allowedOrigin},
},
}, {
name: "CORS preflight request with PUT with non-safelisted header names with ACRPN from a valid and allowed origin",
reqMethod: http.MethodOptions,
reqHeaders: http.Header{
headerOrigin: []string{allowedOrigin},
headerACRM: []string{http.MethodPut},
headerACRH: []string{"foo,bar,baz"},
headerACRPN: []string{headerValueTrue},
},
expectedStatus: dummyPreflightSuccessStatus,
expectedRespHeaders: http.Header{
headerACAO: []string{allowedOrigin},
},
}, {
name: "CORS preflight request with GET with ACRPN from a valid but disallowed origin",
reqMethod: http.MethodOptions,
reqHeaders: http.Header{
headerOrigin: []string{disallowedBaseOrigin},
headerACRM: []string{http.MethodGet},
headerACRPN: []string{headerValueTrue},
},
expectedStatus: http.StatusForbidden,
}, {
name: "CORS preflight request with PUT with non-safelisted header names with ACRPN from a valid but disallowed origin",
reqMethod: http.MethodOptions,
reqHeaders: http.Header{
headerOrigin: []string{disallowedBaseOrigin},
headerACRM: []string{http.MethodPut},
headerACRH: []string{"foo,bar,baz"},
headerACRPN: []string{headerValueTrue},
},
expectedStatus: http.StatusForbidden,
},
}
process(t, cors(dummyHandler), cases)
}

func Test_AllowAccess_From_Subdomains_Of_Public_Suffix(t *testing.T) {
const (
dummyVaryValue = "whatever"
Expand Down
16 changes: 0 additions & 16 deletions fcors_invalid_policies_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -430,14 +430,6 @@ func TestInvalidPoliciesForAllowAccess(t *testing.T) {
fcors.PreflightSuccessStatus(202),
},
errorMsg: `fcors: option PreflightSuccessStatus used multiple times`,
}, {
desc: "option AssumeNoWebCachingOfPreflightResponses used multiple times",
options: []fcors.OptionAnon{
fcors.FromOrigins("https://example.com"),
risky.AssumeNoWebCachingOfPreflightResponses(),
risky.AssumeNoWebCachingOfPreflightResponses(),
},
errorMsg: `fcors/risky: option AssumeNoWebCachingOfPreflightResponses used multiple times`,
}, {
desc: "option PrivateNetworkAccess used multiple times",
options: []fcors.OptionAnon{
Expand Down Expand Up @@ -989,14 +981,6 @@ func TestInvalidPoliciesForAllowAccessWithCredentials(t *testing.T) {
fcors.PreflightSuccessStatus(202),
},
errorMsg: `fcors: option PreflightSuccessStatus used multiple times`,
}, {
desc: "option AssumeNoWebCachingOfPreflightResponses used multiple times",
options: []fcors.Option{
fcors.FromOrigins("https://example.com"),
risky.AssumeNoWebCachingOfPreflightResponses(),
risky.AssumeNoWebCachingOfPreflightResponses(),
},
errorMsg: `fcors/risky: option AssumeNoWebCachingOfPreflightResponses used multiple times`,
}, {
desc: "option PrivateNetworkAccess used multiple times",
options: []fcors.Option{
Expand Down
43 changes: 20 additions & 23 deletions internal/middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,22 +75,21 @@ type TempConfig struct {
type Config struct {
// A nil ACAO indicates that the corresponding header
// is set dynamically.
ACAO []string
ACAM []string
Corpus origin.Corpus
tmp *TempConfig
ACAH []string
ACMA []string
PreflightSuccessStatus int
AllowAnyMethod bool
AllowAnyRequestHeaders bool
AllowAnyOrigin bool
AllowCredentials bool
ExposeAllResponseHeaders bool
PrivateNetworkAccess bool
PrivateNetworkAccessInNoCORSModeOnly bool
AssumeNoWebCachingOfPreflightResponses bool
ACEH []string
ACAO []string
ACAM []string
Corpus origin.Corpus
tmp *TempConfig
ACAH []string
ACMA []string
PreflightSuccessStatus int
AllowAnyMethod bool
AllowAnyRequestHeaders bool
AllowAnyOrigin bool
AllowCredentials bool
ExposeAllResponseHeaders bool
PrivateNetworkAccess bool
PrivateNetworkAccessInNoCORSModeOnly bool
ACEH []string
//lint:ignore U1000 because we pad to the end of the 3rd cache line
_padding40 [40]bool
}
Expand Down Expand Up @@ -265,13 +264,13 @@ func (cfg *Config) middleware() Middleware {
func (cfg *Config) handleNonCORSRequest(respHeaders http.Header, isOptionsReq bool) {
// see https://wicg.github.io/private-network-access/#shortlinks
if cfg.PrivateNetworkAccessInNoCORSModeOnly {
if isOptionsReq && !cfg.AssumeNoWebCachingOfPreflightResponses {
if isOptionsReq {
fastAdd(respHeaders, headerVary, precomputedPreflightVaryValue)
}
return
}
var varyHeaderAdded bool
if isOptionsReq && !cfg.AssumeNoWebCachingOfPreflightResponses {
if isOptionsReq {
fastAdd(respHeaders, headerVary, precomputedPreflightVaryValue)
varyHeaderAdded = true
}
Expand Down Expand Up @@ -304,9 +303,7 @@ func (cfg *Config) handleCORSPreflightRequest(
acrm []string, // assumed non-empty
) {
respHeaders := w.Header()
if !cfg.AssumeNoWebCachingOfPreflightResponses {
fastAdd(respHeaders, headerVary, precomputedPreflightVaryValue)
}
fastAdd(respHeaders, headerVary, precomputedPreflightVaryValue)
if !cfg.processOriginForPreflight(respHeaders, origins) {
w.WriteHeader(http.StatusForbidden)
return
Expand Down Expand Up @@ -392,13 +389,13 @@ func (cfg *Config) handleNonPreflightCORSRequest(
respHeaders := w.Header()
// see https://wicg.github.io/private-network-access/#shortlinks
if cfg.PrivateNetworkAccessInNoCORSModeOnly {
if isOptionsReq && !cfg.AssumeNoWebCachingOfPreflightResponses {
if isOptionsReq {
fastAdd(respHeaders, headerVary, precomputedPreflightVaryValue)
}
return
}
switch {
case isOptionsReq && !cfg.AssumeNoWebCachingOfPreflightResponses:
case isOptionsReq:
fastAdd(respHeaders, headerVary, precomputedPreflightVaryValue)
case cfg.ACAO == nil:
fastAdd(respHeaders, headerVary, precomputedHeaderOrigin)
Expand Down
Loading

0 comments on commit 3dfd279

Please sign in to comment.