Skip to content

Commit ce4b71c

Browse files
authored
Merge pull request #201 from bboozzoo/bboozzoo/cors-access-control-request-headers
Empty Access-Control-Request-Headers in CORS preflight triggers 403 Forbidden
2 parents 709bbe3 + 7535cd0 commit ce4b71c

File tree

3 files changed

+84
-0
lines changed

3 files changed

+84
-0
lines changed

rest/cors_test.go

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package rest
2+
3+
import (
4+
"net/http"
5+
"testing"
6+
7+
"github.com/ant0ine/go-json-rest/rest/test"
8+
)
9+
10+
func TestCorsMiddlewareEmptyAccessControlRequestHeaders(t *testing.T) {
11+
api := NewApi()
12+
13+
// the middleware to test
14+
api.Use(&CorsMiddleware{
15+
OriginValidator: func(_ string, _ *Request) bool {
16+
return true
17+
},
18+
AllowedMethods: []string{
19+
"GET",
20+
"POST",
21+
"PUT",
22+
},
23+
AllowedHeaders: []string{
24+
"Origin",
25+
"Referer",
26+
},
27+
})
28+
29+
// wrap all
30+
handler := api.MakeHandler()
31+
32+
req, _ := http.NewRequest("OPTIONS", "http://localhost", nil)
33+
req.Header.Set("Origin", "http://another.host")
34+
req.Header.Set("Access-Control-Request-Method", "PUT")
35+
req.Header.Set("Access-Control-Request-Headers", "")
36+
37+
recorded := test.RunRequest(t, handler, req)
38+
t.Logf("recorded: %+v\n", recorded.Recorder)
39+
recorded.CodeIs(200)
40+
recorded.HeaderIs("Access-Control-Allow-Methods", "GET,POST,PUT")
41+
recorded.HeaderIs("Access-Control-Allow-Headers", "Origin,Referer")
42+
recorded.HeaderIs("Access-Control-Allow-Origin", "http://another.host")
43+
}

rest/request.go

+3
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,9 @@ func (r *Request) GetCorsInfo() *CorsInfo {
120120
reqHeaders := []string{}
121121
rawReqHeaders := r.Header[http.CanonicalHeaderKey("Access-Control-Request-Headers")]
122122
for _, rawReqHeader := range rawReqHeaders {
123+
if len(rawReqHeader) == 0 {
124+
continue
125+
}
123126
// net/http does not handle comma delimited headers for us
124127
for _, reqHeader := range strings.Split(rawReqHeader, ",") {
125128
reqHeaders = append(reqHeaders, http.CanonicalHeaderKey(strings.TrimSpace(reqHeader)))

rest/request_test.go

+38
Original file line numberDiff line numberDiff line change
@@ -148,3 +148,41 @@ func TestCorsInfoPreflightCors(t *testing.T) {
148148
t.Error("OriginUrl must be set")
149149
}
150150
}
151+
152+
func TestCorsInfoEmptyAccessControlRequestHeaders(t *testing.T) {
153+
req := defaultRequest("OPTIONS", "http://localhost", nil, t)
154+
req.Request.Header.Set("Origin", "http://another.host")
155+
156+
// make it a preflight request
157+
req.Request.Header.Set("Access-Control-Request-Method", "PUT")
158+
159+
// WebKit based browsers may send `Access-Control-Request-Headers:` with
160+
// no value, in which case, the header will be present in requests
161+
// Header map, but its value is an empty string.
162+
req.Request.Header.Set("Access-Control-Request-Headers", "")
163+
corsInfo := req.GetCorsInfo()
164+
if corsInfo == nil {
165+
t.Error("Expected non nil CorsInfo")
166+
}
167+
if corsInfo.IsCors == false {
168+
t.Error("This is a CORS request")
169+
}
170+
if len(corsInfo.AccessControlRequestHeaders) > 0 {
171+
t.Error("Access-Control-Request-Headers should have been removed")
172+
}
173+
174+
req.Request.Header.Set("Access-Control-Request-Headers", "")
175+
corsInfo = req.GetCorsInfo()
176+
if corsInfo == nil {
177+
t.Error("Expected non nil CorsInfo")
178+
}
179+
if corsInfo.IsCors == false {
180+
t.Error("This is a CORS request")
181+
}
182+
if corsInfo.IsPreflight == false {
183+
t.Error("This is a Preflight request")
184+
}
185+
if len(corsInfo.AccessControlRequestHeaders) > 0 {
186+
t.Error("Empty Access-Control-Request-Headers header should have been removed")
187+
}
188+
}

0 commit comments

Comments
 (0)