-
Notifications
You must be signed in to change notification settings - Fork 7
/
cors.go
132 lines (113 loc) · 3.18 KB
/
cors.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
package bahamut
import (
"net/http"
"strconv"
"strings"
)
// CORSOriginMirror instruts to mirror any incoming origin.
// This should not be used in production as this is a development
// feature that is not secure.
const CORSOriginMirror = "_mirror_"
// CORSPolicy allows to configure
// CORS Access Control header of a response.
type CORSPolicy struct {
additionalOrigins map[string]struct{}
AllowOrigin string
AllowHeaders []string
AllowMethods []string
ExposeHeaders []string
MaxAge int
AllowCredentials bool
}
type corsPolicyController struct {
policy *CORSPolicy
}
// NewDefaultCORSController returns a CORSPolicyController that always returns a CORSAccessControlPolicy
// with sensible defaults.
func NewDefaultCORSController(origin string, additionalOrigins []string) CORSPolicyController {
additionalOriginsMap := make(map[string]struct{}, len(additionalOrigins))
if len(additionalOrigins) > 0 {
for _, o := range additionalOrigins {
additionalOriginsMap[o] = struct{}{}
}
}
return &corsPolicyController{
policy: &CORSPolicy{
AllowOrigin: origin,
additionalOrigins: additionalOriginsMap,
AllowCredentials: true,
MaxAge: 1500,
AllowHeaders: []string{
"Authorization",
"Accept",
"Content-Type",
"Cache-Control",
"Cookie",
"If-Modified-Since",
"X-Requested-With",
"X-Count-Total",
"X-Namespace",
"X-External-Tracking-Type",
"X-External-Tracking-ID",
"X-TLS-Client-Certificate",
"Accept-Encoding",
"X-Fields",
"X-Read-Consistency",
"X-Write-Consistency",
"Idempotency-Key",
},
AllowMethods: []string{
"GET",
"POST",
"PUT",
"DELETE",
"PATCH",
"HEAD",
"OPTIONS",
},
ExposeHeaders: []string{
"X-Requested-With",
"X-Count-Total",
"X-Namespace",
"X-Messages",
"X-Fields",
"X-Next",
},
},
}
}
func (c *corsPolicyController) PolicyForRequest(*http.Request) *CORSPolicy {
return c.policy
}
// Inject injects the CORS header on the given http.Header. It will use
// the given request origin to determine the allow origin policy and the method
// to determine if it should inject pre-flight OPTIONS header.
// If the given http.Header is nil, this function is a no op.
func (a *CORSPolicy) Inject(h http.Header, origin string, preflight bool) {
if h == nil {
return
}
corsOrigin := a.AllowOrigin
switch {
case a.AllowOrigin == "*":
corsOrigin = "*"
case a.AllowOrigin == CORSOriginMirror && origin != "":
corsOrigin = origin
case a.AllowOrigin == CORSOriginMirror && origin == "":
corsOrigin = ""
case func() bool { _, ok := a.additionalOrigins[origin]; return ok }():
corsOrigin = origin
}
if preflight {
h.Set("Access-Control-Allow-Headers", strings.Join(a.AllowHeaders, ", "))
h.Set("Access-Control-Allow-Methods", strings.Join(a.AllowMethods, ", "))
h.Set("Access-Control-Max-Age", strconv.Itoa(a.MaxAge))
}
if corsOrigin != "" {
h.Set("Access-Control-Allow-Origin", corsOrigin)
}
h.Set("Access-Control-Expose-Headers", strings.Join(a.ExposeHeaders, ", "))
if a.AllowCredentials && corsOrigin != "*" && corsOrigin != "" {
h.Set("Access-Control-Allow-Credentials", "true")
}
}