-
Notifications
You must be signed in to change notification settings - Fork 0
/
cors.go
69 lines (64 loc) · 1.8 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
package main
import (
"net/http"
"regexp"
"strings"
)
type corsACL struct {
path *regexp.Regexp
domain *regexp.Regexp
}
// CORSHandler adds "Access-Control-Allow-Origin" header to response if specified Origin is in request
type CORSHandler struct {
http.Handler
allowed []corsACL
}
// AddRecord make path accessible from origin
func (ch *CORSHandler) AddRecord(path, origin string) error {
if ch.allowed == nil {
ch.allowed = make([]corsACL, 0)
}
pathRe, err := regexp.Compile(path)
if err != nil {
return err
}
originRe, err := regexp.Compile(origin)
if err != nil {
return err
}
logf(nil, logLevelInfo, "CORS: Adding origin %#v on %#v", origin, path)
ch.allowed = append(ch.allowed, corsACL{pathRe, originRe})
return nil
}
func (ch *CORSHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
next := ch.Handler
if next == nil {
next = http.DefaultServeMux
}
if origin := r.Header.Get("Origin"); origin != "" {
matched := false
for _, acl := range ch.allowed {
if acl.path.MatchString(r.URL.Path) && acl.domain.MatchString(origin) {
matched = true
w.Header().Add("Access-Control-Allow-Origin", origin)
varyHeaders := []string{"Origin"}
if method := r.Header.Get("Access-Control-Request-Method"); method != "" {
w.Header().Add("Access-Control-Allow-Methods", "*")
}
if header := r.Header.Get("Access-Control-Request-Headers"); header != "" {
w.Header().Add("Access-Control-Allow-Headers", header)
varyHeaders = append(varyHeaders, header)
}
if r.Method == "OPTIONS" {
w.Header().Add("Vary", strings.Join(varyHeaders, ", "))
w.WriteHeader(http.StatusOK)
return
}
}
}
if !matched {
logf(r, logLevelWarning, "CORS: Could not match origin %#v on %#v, passing to backend", origin, r.URL.Path)
}
}
next.ServeHTTP(w, r)
}