@@ -29,6 +29,9 @@ const (
2929 BackendErrorsURL = "/v1/errors"
3030 FrontendErrorsURL = "/v1/client-side/errors"
3131 HealthCheckURL = "/healthcheck"
32+
33+ supportedHeaders = "Content-Type, Content-Encoding, Accept"
34+ supportedMethods = "POST, OPTIONS"
3235)
3336
3437type ProcessorFactory func () processor.Processor
@@ -79,7 +82,8 @@ func backendHandler(pf ProcessorFactory, config Config, report reporter) http.Ha
7982func frontendHandler (pf ProcessorFactory , config Config , report reporter ) http.Handler {
8083 return logHandler (
8184 frontendSwitchHandler (config .EnableFrontend ,
82- processRequestHandler (pf , config , report )))
85+ corsHandler (config .AllowOrigins ,
86+ processRequestHandler (pf , config , report ))))
8387}
8488
8589func healthCheckHandler (_ ProcessorFactory , _ Config , _ reporter ) http.Handler {
@@ -133,6 +137,55 @@ func isAuthorized(req *http.Request, secretToken string) bool {
133137 return subtle .ConstantTimeCompare ([]byte (parts [1 ]), []byte (secretToken )) == 1
134138}
135139
140+ func corsHandler (allowedOrigins []string , h http.Handler ) http.Handler {
141+
142+ var isAllowed = func (origin string ) bool {
143+ for _ , allowed := range allowedOrigins {
144+ if origin == allowed || allowed == "*" {
145+ return true
146+ }
147+ }
148+ return false
149+ }
150+
151+ return http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
152+
153+ // origin header is always set by the browser
154+ origin := r .Header .Get ("Origin" )
155+ validOrigin := isAllowed (origin )
156+
157+ if r .Method == "OPTIONS" {
158+
159+ // setting the ACAO header is the way to tell the browser to go ahead with the request
160+ if validOrigin {
161+ // do not set the configured origin(s), echo the received origin instead
162+ w .Header ().Set ("Access-Control-Allow-Origin" , origin )
163+ }
164+
165+ // tell browsers to cache response requestHeaders for up to 1 hour (browsers might ignore this)
166+ w .Header ().Set ("Access-Control-Max-Age" , "3600" )
167+ // origin must be part of the cache key so that we can handle multiple allowed origins
168+ w .Header ().Set ("Vary" , "Origin" )
169+
170+ // required if Access-Control-Request-Method and Access-Control-Request-Headers are in the requestHeaders
171+ w .Header ().Set ("Access-Control-Allow-Methods" , supportedMethods )
172+ w .Header ().Set ("Access-Control-Allow-Headers" , supportedHeaders )
173+
174+ w .Header ().Set ("Content-Length" , "0" )
175+
176+ sendStatus (w , r , 200 , nil )
177+
178+ } else if validOrigin {
179+ // we need to check the origin and set the ACAO header in both the OPTIONS preflight and the actual request
180+ w .Header ().Set ("Access-Control-Allow-Origin" , origin )
181+ h .ServeHTTP (w , r )
182+
183+ } else {
184+ sendStatus (w , r , 403 , errForbidden )
185+ }
186+ })
187+ }
188+
136189func processRequestHandler (pf ProcessorFactory , config Config , report reporter ) http.Handler {
137190 return http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
138191 code , err := processRequest (r , pf , config .MaxUnzippedSize , report )
0 commit comments