-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcors_handler.go
145 lines (124 loc) · 4.61 KB
/
cors_handler.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
package middlewares
import (
"net/http"
"strings"
)
var (
allowedCORSMethods = []string{}
allowedOrigins = []string{}
allowedHeaders = []string{}
exposedHeaders = []string{}
)
var (
corsAccessControlRequestMethod = "Access-Control-Request-Method" //to let the server know which method will be used in the upcoming request
corsAccessControlRequestHeaders = "Access-Control-Request-Headers" //used when issuing a preflight req to let the server know what HTTP headers will be used in the upcoming request
corsOrigin = "Origin" //origin of the request or preflight request, only server name, can be an empty string (e.g. when the source is a data URL)
corsVary = "Vary"
corsAccessControlAllowOrigin = "Access-Control-Allow-Origin"
corsAccessControlExposeHeaders = "Access-Control-Expose-Headers" // lets a server whitelist headers that browsers are allowed to access
corsAccessControlMaxAge = "Access-Control-Max-Age" // how long the results of a preflight request <delta-seconds>
corsAccessControlAllowCredentials = "Access-Control-Allow-Credentials" // when used as part of preflight response, indicates if the actual request can be made using credentials
corsAccessControlAllowMethods = "Access-Control-Allow-Methods" // method or methods allowed for the resource <method>[, <method>]*
corsAccessControlAllowHeaders = "Access-Control-Allow-Headers" // indicate which http headers that can be used when making the actual request
)
var (
supportCredentials bool
)
func init() {
supportCredentials = false //disallow credentials by default
}
//AllowCORSMethods specified which methods that are allowed for CORS
func AllowCORSMethods(methods ...string) {
allowedCORSMethods = append(allowedCORSMethods, methods...)
}
//AllowCORSOrigins specifies which origins to allow
func AllowCORSOrigins(origins ...string) {
allowedOrigins = append(allowedOrigins, origins...)
}
//AllowCORSHeaders specifies which headers that can be used
func AllowCORSHeaders(headers ...string) {
allowedHeaders = append(allowedHeaders, headers...)
}
//AllowCORSExposedHeaders whitelists which headers are allowed for the browsers to access
func AllowCORSExposedHeaders(headers ...string) {
exposedHeaders = append(exposedHeaders, headers...)
}
//SupportCredentials sets the Support-Credentials header to b
func SupportCredentials(b bool) {
supportCredentials = b
}
//CORSHandler appends CORS headers to the response if any CORS headers are present in the request or as a preflight request. For detailed documentation regarding CORS and what headers mean, please see https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
func CORSHandler(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
origin := r.Header.Get(corsOrigin)
if !isAllowedOrigin(origin) {
next.ServeHTTP(w, r)
return
}
w.Header().Set(corsAccessControlAllowOrigin, origin) // we allow this origin
if r.Method == http.MethodOptions {
if isAllowedMethod(r.Header.Get(corsAccessControlRequestMethod)) {
w.Header().Set(corsAccessControlAllowMethods, strings.Join(allowedCORSMethods, ", "))
}
w.Header().Set(corsAccessControlMaxAge, "0")
//Request-headers are only set on preflight requests
sv := getAllowedHeaders(strings.Split(r.Header.Get(corsAccessControlRequestHeaders), ","))
if len(sv) > 0 {
w.Header().Set(corsAccessControlAllowHeaders, strings.Join(sv, ", "))
}
if len(exposedHeaders) > 0 {
w.Header().Set(corsAccessControlExposeHeaders, strings.Join(exposedHeaders, ", "))
}
}
if allowAll() {
if allowAll() {
w.Header().Set(corsVary, "Origin") // tell the client the origin might be changing depending on who's asking
}
}
if supportCredentials {
w.Header().Set(corsAccessControlAllowCredentials, "true")
}
next.ServeHTTP(w, r)
})
}
func getAllowedHeaders(req []string) (all []string) {
all = []string{}
for _, s := range req {
for _, c := range allowedHeaders {
if strings.ToLower(strings.TrimSpace(s)) == strings.ToLower(strings.TrimSpace(c)) {
all = append(all, c)
}
}
}
return
}
func allowAll() bool {
for _, ao := range allowedOrigins {
if ao == "*" {
return true
}
}
return false
}
func isAllowedOrigin(o string) bool {
if o == "" {
return false
}
for _, ao := range allowedOrigins {
if ao == o || ao == "*" {
return true
}
}
return false
}
func isAllowedMethod(m string) bool {
if m == "" {
return false
}
for _, am := range allowedCORSMethods {
if am == m || am == "*" {
return true
}
}
return false
}