@@ -54,7 +54,8 @@ type Options struct {
5454 // Default value is [] but "Origin" is always appended to the list.
5555 AllowedHeaders []string
5656 // ExposedHeaders indicates which headers are safe to expose to the API of a CORS
57- // API specification
57+ // API specification.
58+ // If the special "*" value is present in the list, all headers will be allowed.
5859 ExposedHeaders []string
5960 // MaxAge indicates how long (in seconds) the results of a preflight request
6061 // can be cached
@@ -194,6 +195,7 @@ func AllowAll() *Cors {
194195 },
195196 AllowedHeaders : []string {"*" },
196197 AllowCredentials : false ,
198+ ExposedHeaders : []string {"*" },
197199 })
198200}
199201
@@ -216,6 +218,7 @@ func (c *Cors) Handler(h http.Handler) http.Handler {
216218 } else {
217219 c .logf ("Handler: Actual request" )
218220 c .handleActualRequest (w , r )
221+ w = & ExposeAllRespWriter {w , false }
219222 h .ServeHTTP (w , r )
220223 }
221224 })
@@ -249,6 +252,7 @@ func (c *Cors) ServeHTTP(w http.ResponseWriter, r *http.Request, next http.Handl
249252 } else {
250253 c .logf ("ServeHTTP: Actual request" )
251254 c .handleActualRequest (w , r )
255+ w = & ExposeAllRespWriter {w , false }
252256 next (w , r )
253257 }
254258}
@@ -427,3 +431,54 @@ func (c *Cors) areHeadersAllowed(requestedHeaders []string) bool {
427431 }
428432 return true
429433}
434+
435+ // ExposeAllRespWriter echos back any headers that are set in the wrapped response writer
436+ // to support the wildcard "*" case for Access-Control-Expose-Headers since
437+ // browsers do not currently have good compatibility with wildcard.
438+ type ExposeAllRespWriter struct {
439+ http.ResponseWriter
440+ applied bool
441+ }
442+
443+ func (w * ExposeAllRespWriter ) Write (b []byte ) (int , error ) {
444+ w .setHeaders ()
445+ return w .ResponseWriter .Write (b )
446+ }
447+
448+ func (w * ExposeAllRespWriter ) WriteHeader (c int ) {
449+ w .setHeaders ()
450+ w .ResponseWriter .WriteHeader (c )
451+ }
452+
453+ func (w * ExposeAllRespWriter ) setHeaders () {
454+ if w .applied {
455+ return
456+ }
457+ w .applied = true
458+
459+ if w .ResponseWriter .Header ().Get ("Access-Control-Expose-Headers" ) != "*" {
460+ return
461+ }
462+
463+ var toExpose []string
464+ for k := range w .ResponseWriter .Header () {
465+ switch k {
466+ case
467+ // CORs headers that could be set when Access-Control-Expose-Headers is set
468+ "Access-Control-Allow-Origin" , "Access-Control-Allow-Credentials" , "Access-Control-Expose-Headers" ,
469+
470+ // already allowed by spec
471+ "Cache-Control" , "Content-Language" , "Content-Type" , "Expires" , "Last-Modified" , "Pragma" :
472+ continue
473+ default :
474+ toExpose = append (toExpose , k )
475+ }
476+ }
477+
478+ if len (toExpose ) == 0 {
479+ w .ResponseWriter .Header ().Del ("Access-Control-Expose-Headers" )
480+ return
481+ }
482+
483+ w .ResponseWriter .Header ().Set ("Access-Control-Expose-Headers" , strings .Join (toExpose , ", " ))
484+ }
0 commit comments