Skip to content

Commit

Permalink
Support wildcard for ExposedHeaders option.
Browse files Browse the repository at this point in the history
Via echoing back all headers in a wrapped response writer since browsers
don't currently support the wildcard.

Fixes rs#79
  • Loading branch information
Jonathan Gaillard committed Jun 14, 2019
1 parent 33ffc07 commit 881667a
Show file tree
Hide file tree
Showing 2 changed files with 151 additions and 29 deletions.
57 changes: 56 additions & 1 deletion cors.go
Expand Up @@ -54,7 +54,8 @@ type Options struct {
// Default value is [] but "Origin" is always appended to the list.
AllowedHeaders []string
// ExposedHeaders indicates which headers are safe to expose to the API of a CORS
// API specification
// API specification.
// If the special "*" value is present in the list, all headers will be allowed.
ExposedHeaders []string
// MaxAge indicates how long (in seconds) the results of a preflight request
// can be cached
Expand Down Expand Up @@ -194,6 +195,7 @@ func AllowAll() *Cors {
},
AllowedHeaders: []string{"*"},
AllowCredentials: false,
ExposedHeaders: []string{"*"},
})
}

Expand All @@ -216,6 +218,7 @@ func (c *Cors) Handler(h http.Handler) http.Handler {
} else {
c.logf("Handler: Actual request")
c.handleActualRequest(w, r)
w = &ExposeAllRespWriter{w, false}
h.ServeHTTP(w, r)
}
})
Expand Down Expand Up @@ -249,6 +252,7 @@ func (c *Cors) ServeHTTP(w http.ResponseWriter, r *http.Request, next http.Handl
} else {
c.logf("ServeHTTP: Actual request")
c.handleActualRequest(w, r)
w = &ExposeAllRespWriter{w, false}
next(w, r)
}
}
Expand Down Expand Up @@ -427,3 +431,54 @@ func (c *Cors) areHeadersAllowed(requestedHeaders []string) bool {
}
return true
}

// ExposeAllRespWriter echos back any headers that are set in the wrapped response writer
// to support the wildcard "*" case for Access-Control-Expose-Headers since
// browsers do not currently have good compatibility with wildcard.
type ExposeAllRespWriter struct {
http.ResponseWriter
applied bool
}

func (w *ExposeAllRespWriter) Write(b []byte) (int, error) {
w.setHeaders()
return w.ResponseWriter.Write(b)
}

func (w *ExposeAllRespWriter) WriteHeader(c int) {
w.setHeaders()
w.ResponseWriter.WriteHeader(c)
}

func (w *ExposeAllRespWriter) setHeaders() {
if w.applied {
return
}
w.applied = true

if w.ResponseWriter.Header().Get("Access-Control-Expose-Headers") != "*" {
return
}

var toExpose []string
for k := range w.ResponseWriter.Header() {
switch k {
case
// CORs headers that could be set when Access-Control-Expose-Headers is set
"Access-Control-Allow-Origin", "Access-Control-Allow-Credentials", "Access-Control-Expose-Headers",

// already allowed by spec
"Cache-Control", "Content-Language", "Content-Type", "Expires", "Last-Modified", "Pragma":
continue
default:
toExpose = append(toExpose, k)
}
}

if len(toExpose) == 0 {
w.ResponseWriter.Header().Del("Access-Control-Expose-Headers")
return
}

w.ResponseWriter.Header().Set("Access-Control-Expose-Headers", strings.Join(toExpose, ", "))
}

0 comments on commit 881667a

Please sign in to comment.