@@ -54,7 +54,8 @@ type Options struct {
54
54
// Default value is [] but "Origin" is always appended to the list.
55
55
AllowedHeaders []string
56
56
// 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.
58
59
ExposedHeaders []string
59
60
// MaxAge indicates how long (in seconds) the results of a preflight request
60
61
// can be cached
@@ -194,6 +195,7 @@ func AllowAll() *Cors {
194
195
},
195
196
AllowedHeaders : []string {"*" },
196
197
AllowCredentials : false ,
198
+ ExposedHeaders : []string {"*" },
197
199
})
198
200
}
199
201
@@ -216,6 +218,7 @@ func (c *Cors) Handler(h http.Handler) http.Handler {
216
218
} else {
217
219
c .logf ("Handler: Actual request" )
218
220
c .handleActualRequest (w , r )
221
+ w = & ExposeAllRespWriter {w , false }
219
222
h .ServeHTTP (w , r )
220
223
}
221
224
})
@@ -249,6 +252,7 @@ func (c *Cors) ServeHTTP(w http.ResponseWriter, r *http.Request, next http.Handl
249
252
} else {
250
253
c .logf ("ServeHTTP: Actual request" )
251
254
c .handleActualRequest (w , r )
255
+ w = & ExposeAllRespWriter {w , false }
252
256
next (w , r )
253
257
}
254
258
}
@@ -427,3 +431,54 @@ func (c *Cors) areHeadersAllowed(requestedHeaders []string) bool {
427
431
}
428
432
return true
429
433
}
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