From 5484dc42f2884369d23112ca0da4dcd837f3ac8d Mon Sep 17 00:00:00 2001 From: Emmanuel T Odeke Date: Sun, 27 Dec 2020 13:12:41 -0800 Subject: [PATCH] CORS: add AllowCredentials With this change, setting CORS.AllowCredentials will permit set the "Access-Control-Allow-Credentials" header which when combined with a client XHR's withCredentials allows cookies to be used in subsequent Ajax requests. Fixes #16 --- cors_test.go | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++ otils.go | 12 +++++++++++ 2 files changed, 69 insertions(+) create mode 100644 cors_test.go diff --git a/cors_test.go b/cors_test.go new file mode 100644 index 0000000..293c6ba --- /dev/null +++ b/cors_test.go @@ -0,0 +1,57 @@ +package otils + +import ( + "encoding/json" + "net/http" + "net/http/httptest" + "reflect" + "testing" +) + +func TestCORSHeader(t *testing.T) { + tests := []struct { + name string + cors *CORS + want http.Header + }{ + { + name: "with allowCredentials", + cors: &CORS{ + AllowCredentials: true, + }, + want: http.Header{ + "Access-Control-Allow-Credentials": {"true"}, + }, + }, + { + name: "all enabled", + cors: CORSMiddlewareAllInclusive(nil).(*CORS), + want: http.Header{ + "Access-Control-Allow-Credentials": {"true"}, + "Access-Control-Allow-Headers": {"*"}, + "Access-Control-Allow-Methods": {"*"}, + "Access-Control-Allow-Origin": {"*"}, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + rec := httptest.NewRecorder() + tt.cors.setCORSForResponseWriter(rec) + res := rec.Result() + got := res.Header + if !reflect.DeepEqual(got, tt.want) { + t.Fatalf("Mismatched end headers\nGot: %s\nWant: %s", asJSON(got), asJSON(tt.want)) + } + }) + } +} + +func asJSON(v interface{}) []byte { + blob, err := json.MarshalIndent(v, "", " ") + if err != nil { + panic(err) + } + return blob +} diff --git a/otils.go b/otils.go index 359f27c..308a327 100644 --- a/otils.go +++ b/otils.go @@ -448,6 +448,12 @@ type CORS struct { Methods []string Headers []string + // AllowCredentials when set signifies that the header + // "Access-Control-Allow-Credentials" which will allow + // the possibility of the frontend XHR's withCredentials=true + // to be set. + AllowCredentials bool + next http.Handler } @@ -465,6 +471,8 @@ var allInclusiveCORS = &CORS{ Origins: []string{"*"}, Methods: []string{"*"}, Headers: []string{"*"}, + + AllowCredentials: true, } // CORSMiddlewareAllInclusive is a convenience helper that uses the @@ -472,6 +480,7 @@ var allInclusiveCORS = &CORS{ // Access-Control-Allow-Origin: * // Access-Control-Allow-Methods: * // Access-Control-Allow-Headers: * +// Access-Control-Allow-Credentials: * // thus enabling all origins, all methods and all headers. func CORSMiddlewareAllInclusive(next http.Handler) http.Handler { return CORSMiddleware(allInclusiveCORS, next) @@ -496,6 +505,9 @@ func (c *CORS) setCORSForResponseWriter(rw http.ResponseWriter) { for _, hdr := range c.Headers { rw.Header().Add("Access-Control-Allow-Headers", hdr) } + if c.AllowCredentials { + rw.Header().Add("Access-Control-Allow-Credentials", "true") + } } func EnvOrAlternates(envVar string, alternates ...string) string {