diff --git a/server/media/media.go b/server/media/media.go index 06892646..110ab745 100644 --- a/server/media/media.go +++ b/server/media/media.go @@ -80,6 +80,7 @@ func matchCORSOrigin(allowed []string, origin string) string { return "" } +// allowMethods must be in UPPERCASE. func matchCORSMethod(allowMethods []string, method string) bool { if method == "" { // Request has no Method header. @@ -88,7 +89,7 @@ func matchCORSMethod(allowMethods []string, method string) bool { method = strings.ToUpper(method) for _, mm := range allowMethods { - if strings.ToUpper(mm) == method { + if mm == method { return true } } @@ -96,41 +97,51 @@ func matchCORSMethod(allowMethods []string, method string) bool { return false } -// CORSHandler is the default preflight OPTIONS processor for use by media handlers. +// CORSHandler is the default CORS processor for use by media handlers. func CORSHandler(req *http.Request, allowedOrigins []string, serve bool) (http.Header, int) { - if req.Method != http.MethodOptions { - // Not an OPTIONS request. No special handling for all other requests. - return nil, 0 - } - - var allowMethods []string - if serve { - allowMethods = []string{http.MethodGet, http.MethodHead, http.MethodOptions} - } else { - allowMethods = []string{http.MethodPost, http.MethodPut, http.MethodHead, http.MethodOptions} - } - headers := map[string][]string{ // Always add Vary because of possible intermediate caches. - "Vary": {"Origin", "Access-Control-Request-Method"}, - "Access-Control-Allow-Headers": {"*"}, - "Access-Control-Max-Age": {"86400"}, - "Access-Control-Allow-Credentials": {"true"}, - "Access-Control-Allow-Methods": {strings.Join(allowMethods, ", ")}, + "Vary": {"Origin", "Access-Control-Request-Method, Access-Control-Request-Headers"}, } - if !matchCORSMethod(allowMethods, req.Header.Get("Access-Control-Request-Method")) { - // CORS policy does not allow this method. + origin := req.Header.Get("Origin") + + allowedOrigin := matchCORSOrigin(allowedOrigins, origin) + requestMethod := req.Header.Get("Access-Control-Request-Method") + if req.Method == http.MethodOptions && requestMethod != "" { + // Preflight request. + + if allowedOrigin == "" { + return headers, http.StatusNoContent + } + + var allowMethods []string + if serve { + allowMethods = []string{http.MethodGet, http.MethodHead, http.MethodOptions} + } else { + allowMethods = []string{http.MethodPost, http.MethodPut, http.MethodHead, http.MethodOptions} + } + + if !matchCORSMethod(allowMethods, requestMethod) { + // CORS policy does not allow this method. + return headers, http.StatusNoContent + } + + headers["Access-Control-Allow-Headers"] = []string{"*"} + headers["Access-Control-Allow-Credentials"] = []string{"true"} + headers["Access-Control-Allow-Methods"] = []string{strings.Join(allowMethods, ", ")} + headers["Access-Control-Max-Age"] = []string{"86400"} + headers["Access-Control-Allow-Origin"] = []string{allowedOrigin} + return headers, http.StatusNoContent } - allowedOrigin := matchCORSOrigin(allowedOrigins, req.Header.Get("Origin")) - if allowedOrigin == "" { - // CORS policy does not match the origin. - return headers, http.StatusNoContent + // Regular request, not a preflight. + + if allowedOrigin != "" { + // Returning Origin from the actual request instead of '*', otherwise there could be an issue with Credentials. + headers["Access-Control-Allow-Origin"] = []string{origin} } - headers["Access-Control-Allow-Origin"] = []string{allowedOrigin} - - return headers, http.StatusNoContent + return headers, 0 }