diff --git a/weed/s3api/s3api_bucket_config.go b/weed/s3api/s3api_bucket_config.go index 8cbb190af..61f0f7f62 100644 --- a/weed/s3api/s3api_bucket_config.go +++ b/weed/s3api/s3api_bucket_config.go @@ -280,7 +280,7 @@ func (s3a *S3ApiServer) loadCORSFromMetadata(bucket string) (*cors.CORSConfigura return nil, fmt.Errorf("no metadata content") } - var metadata map[string]interface{} + var metadata map[string]json.RawMessage if err := json.Unmarshal(entry.Content, &metadata); err != nil { return nil, fmt.Errorf("failed to unmarshal metadata: %v", err) } @@ -290,14 +290,9 @@ func (s3a *S3ApiServer) loadCORSFromMetadata(bucket string) (*cors.CORSConfigura return nil, fmt.Errorf("no CORS configuration found") } - // Convert back to CORSConfiguration - corsBytes, err := json.Marshal(corsData) - if err != nil { - return nil, fmt.Errorf("failed to marshal CORS data: %v", err) - } - + // Directly unmarshal the raw JSON to CORSConfiguration to avoid round-trip allocations var config cors.CORSConfiguration - if err := json.Unmarshal(corsBytes, &config); err != nil { + if err := json.Unmarshal(corsData, &config); err != nil { return nil, fmt.Errorf("failed to unmarshal CORS configuration: %v", err) } diff --git a/weed/s3api/s3api_object_handlers.go b/weed/s3api/s3api_object_handlers.go index 5bc1ba899..c8bea1bc5 100644 --- a/weed/s3api/s3api_object_handlers.go +++ b/weed/s3api/s3api_object_handlers.go @@ -394,10 +394,10 @@ func setUserMetadataKeyToLowercase(resp *http.Response) { func passThroughResponse(proxyResponse *http.Response, w http.ResponseWriter) (statusCode int, bytesTransferred int64) { // Preserve existing CORS headers that may have been set by middleware - existingCORSHeaders := make(map[string]string) + existingCORSHeaders := make(map[string][]string) for _, corsHeader := range corsHeaders { - if value := w.Header().Get(corsHeader); value != "" { - existingCORSHeaders[corsHeader] = value + if values, ok := w.Header()[corsHeader]; ok { + existingCORSHeaders[corsHeader] = append([]string{}, values...) } } @@ -407,8 +407,8 @@ func passThroughResponse(proxyResponse *http.Response, w http.ResponseWriter) (s } // Restore CORS headers that were set by middleware - for corsHeader, value := range existingCORSHeaders { - w.Header().Set(corsHeader, value) + for corsHeader, values := range existingCORSHeaders { + w.Header()[corsHeader] = values } if proxyResponse.Header.Get("Content-Range") != "" && proxyResponse.StatusCode == 200 { diff --git a/weed/s3api/s3api_server.go b/weed/s3api/s3api_server.go index 8b0cf1554..bd2a31e6a 100644 --- a/weed/s3api/s3api_server.go +++ b/weed/s3api/s3api_server.go @@ -130,9 +130,17 @@ func (s3a *S3ApiServer) registerRouter(router *mux.Router) { apiRouter.Methods(http.MethodGet).Path("/healthz").HandlerFunc(s3a.StatusHandler) // Global OPTIONS handler for service-level requests (non-bucket requests) - // This handles requests like OPTIONS / but not OPTIONS /bucket/object - apiRouter.Methods(http.MethodOptions).Path("/").HandlerFunc( + // This handles requests like OPTIONS /, OPTIONS /status, OPTIONS /healthz + apiRouter.Methods(http.MethodOptions).PathPrefix("/").HandlerFunc( func(w http.ResponseWriter, r *http.Request) { + // Only handle if this is not a bucket-specific request + vars := mux.Vars(r) + bucket := vars["bucket"] + if bucket != "" { + // This is a bucket-specific request, skip + return + } + origin := r.Header.Get("Origin") if origin != "" { if len(s3a.option.AllowedOrigins) == 0 || s3a.option.AllowedOrigins[0] == "*" { diff --git a/weed/s3api/s3err/error_handler.go b/weed/s3api/s3err/error_handler.go index 842efbe7d..2c0579770 100644 --- a/weed/s3api/s3err/error_handler.go +++ b/weed/s3api/s3err/error_handler.go @@ -80,17 +80,10 @@ func setCommonHeaders(w http.ResponseWriter, r *http.Request) { // Only set static CORS headers for service-level requests, not bucket-specific requests if r.Header.Get("Origin") != "" { - // Check if this is a bucket-specific request - path := r.URL.Path - isBucketRequest := false - - // A bucket-specific request has a path like /bucket or /bucket/object - if path != "/" && path != "" { - pathParts := strings.Split(strings.TrimPrefix(path, "/"), "/") - if len(pathParts) >= 1 && pathParts[0] != "" { - isBucketRequest = true - } - } + // Use mux.Vars to detect bucket-specific requests more reliably + vars := mux.Vars(r) + bucket := vars["bucket"] + isBucketRequest := bucket != "" // Only apply static CORS headers if this is NOT a bucket-specific request // and no bucket-specific CORS headers were already set