Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: rs/cors
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v1.8.2
Choose a base ref
...
head repository: rs/cors
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v1.8.3
Choose a head ref
  • 3 commits
  • 2 files changed
  • 2 contributors

Commits on Feb 23, 2022

  1. Copy the full SHA
    a4a5ce8 View commit details

Commits on Jun 19, 2022

  1. Copy the full SHA
    da52b07 View commit details

Commits on Oct 3, 2022

  1. Copy the full SHA
    fcebdb4 View commit details
Showing with 108 additions and 0 deletions.
  1. +11 −0 cors.go
  2. +97 −0 cors_test.go
11 changes: 11 additions & 0 deletions cors.go
Original file line number Diff line number Diff line change
@@ -62,6 +62,9 @@ type Options struct {
// AllowCredentials indicates whether the request can include user credentials like
// cookies, HTTP authentication or client side SSL certificates.
AllowCredentials bool
// AllowPrivateNetwork indicates whether to accept cross-origin requests over a
// private network.
AllowPrivateNetwork bool
// OptionsPassthrough instructs preflight to let other potential next handlers to
// process the OPTIONS method. Turn this on if your application handles OPTIONS.
OptionsPassthrough bool
@@ -103,6 +106,7 @@ type Cors struct {
// Status code to use for successful OPTIONS requests
optionsSuccessStatus int
allowCredentials bool
allowPrivateNetwork bool
optionPassthrough bool
}

@@ -113,6 +117,7 @@ func New(options Options) *Cors {
allowOriginFunc: options.AllowOriginFunc,
allowOriginRequestFunc: options.AllowOriginRequestFunc,
allowCredentials: options.AllowCredentials,
allowPrivateNetwork: options.AllowPrivateNetwork,
maxAge: options.MaxAge,
optionPassthrough: options.OptionsPassthrough,
}
@@ -282,6 +287,9 @@ func (c *Cors) handlePreflight(w http.ResponseWriter, r *http.Request) {
headers.Add("Vary", "Origin")
headers.Add("Vary", "Access-Control-Request-Method")
headers.Add("Vary", "Access-Control-Request-Headers")
if c.allowPrivateNetwork {
headers.Add("Vary", "Access-Control-Request-Private-Network")
}

if origin == "" {
c.logf(" Preflight aborted: empty origin")
@@ -319,6 +327,9 @@ func (c *Cors) handlePreflight(w http.ResponseWriter, r *http.Request) {
if c.allowCredentials {
headers.Set("Access-Control-Allow-Credentials", "true")
}
if c.allowPrivateNetwork && r.Header.Get("Access-Control-Request-Private-Network") == "true" {
headers.Set("Access-Control-Allow-Private-Network", "true")
}
if c.maxAge > 0 {
headers.Set("Access-Control-Max-Age", strconv.Itoa(c.maxAge))
}
97 changes: 97 additions & 0 deletions cors_test.go
Original file line number Diff line number Diff line change
@@ -18,6 +18,7 @@ var allHeaders = []string{
"Access-Control-Allow-Methods",
"Access-Control-Allow-Headers",
"Access-Control-Allow-Credentials",
"Access-Control-Allow-Private-Network",
"Access-Control-Max-Age",
"Access-Control-Expose-Headers",
}
@@ -387,6 +388,44 @@ func TestSpec(t *testing.T) {
},
true,
},
{
"AllowedPrivateNetwork",
Options{
AllowedOrigins: []string{"http://foobar.com"},
AllowPrivateNetwork: true,
},
"OPTIONS",
map[string]string{
"Origin": "http://foobar.com",
"Access-Control-Request-Method": "GET",
"Access-Control-Request-Private-Network": "true",
},
map[string]string{
"Vary": "Origin, Access-Control-Request-Method, Access-Control-Request-Headers, Access-Control-Request-Private-Network",
"Access-Control-Allow-Origin": "http://foobar.com",
"Access-Control-Allow-Methods": "GET",
"Access-Control-Allow-Private-Network": "true",
},
true,
},
{
"DisallowedPrivateNetwork",
Options{
AllowedOrigins: []string{"http://foobar.com"},
},
"OPTIONS",
map[string]string{
"Origin": "http://foobar.com",
"Access-Control-Request-Method": "GET",
"Access-Control-Request-PrivateNetwork": "true",
},
map[string]string{
"Vary": "Origin, Access-Control-Request-Method, Access-Control-Request-Headers",
"Access-Control-Allow-Origin": "http://foobar.com",
"Access-Control-Allow-Methods": "GET",
},
true,
},
{
"OptionPassthrough",
Options{
@@ -608,3 +647,61 @@ func TestOptionsSuccessStatusCodeOverride(t *testing.T) {
assertResponse(t, res, http.StatusOK)
})
}

func TestCorsAreHeadersAllowed(t *testing.T) {
cases := []struct {
name string
allowedHeaders []string
requestedHeaders []string
want bool
}{
{
name: "nil allowedHeaders",
allowedHeaders: nil,
requestedHeaders: parseHeaderList("X-PINGOTHER, Content-Type"),
want: false,
},
{
name: "star allowedHeaders",
allowedHeaders: []string{"*"},
requestedHeaders: parseHeaderList("X-PINGOTHER, Content-Type"),
want: true,
},
{
name: "empty reqHeader",
allowedHeaders: nil,
requestedHeaders: parseHeaderList(""),
want: true,
},
{
name: "match allowedHeaders",
allowedHeaders: []string{"Content-Type", "X-PINGOTHER", "X-APP-KEY"},
requestedHeaders: parseHeaderList("X-PINGOTHER, Content-Type"),
want: true,
},
{
name: "not matched allowedHeaders",
allowedHeaders: []string{"X-PINGOTHER"},
requestedHeaders: parseHeaderList("X-API-KEY, Content-Type"),
want: false,
},
{
name: "allowedHeaders should be a superset of requestedHeaders",
allowedHeaders: []string{"X-PINGOTHER"},
requestedHeaders: parseHeaderList("X-PINGOTHER, Content-Type"),
want: false,
},
}

for _, tt := range cases {
tt := tt

t.Run(tt.name, func(t *testing.T) {
c := New(Options{AllowedHeaders: tt.allowedHeaders})
have := c.areHeadersAllowed(tt.requestedHeaders)
if have != tt.want {
t.Errorf("Cors.areHeadersAllowed() have: %t want: %t", have, tt.want)
}
})
}
}