@ -69,103 +69,56 @@ func (m *Middleware) getCORSConfig(bucket string) (*CORSConfiguration, bool) {
// Handler returns the CORS middleware handler
func ( m * Middleware ) Handler ( next http . Handler ) http . Handler {
return http . HandlerFunc ( func ( w http . ResponseWriter , r * http . Request ) {
// Parse CORS request
corsReq := ParseRequest ( r )
// If not a CORS request, continue normally
if corsReq . Origin == "" {
next . ServeHTTP ( w , r )
return
}
// Extract bucket from request
bucket , _ := s3_constants . GetBucketAndObject ( r )
if bucket == "" {
next . ServeHTTP ( w , r )
return
}
// Get CORS configuration (bucket-specific or fallback) BEFORE checking bucket existence
// This ensures CORS headers are applied consistently regardless of bucket existence,
// preventing information disclosure about whether a bucket exists
config , found := m . getCORSConfig ( bucket )
if ! found {
// No CORS configuration at all, handle based on request type
if corsReq . IsPreflightRequest {
// Preflight request without CORS config should fail
s3err . WriteErrorResponse ( w , r , s3err . ErrAccessDenied )
return
}
// Non-preflight request, continue normally
next . ServeHTTP ( w , r )
return
}
// Evaluate CORS request
corsResp , err := EvaluateRequest ( config , corsReq )
if err != nil {
glog . V ( 3 ) . Infof ( "CORS evaluation failed for bucket %s: %v" , bucket , err )
if corsReq . IsPreflightRequest {
// Preflight request that doesn't match CORS rules should fail
s3err . WriteErrorResponse ( w , r , s3err . ErrAccessDenied )
return
}
// Non-preflight request, continue normally but without CORS headers
m . processCORS ( w , r , func ( ) {
next . ServeHTTP ( w , r )
return
}
// Apply CORS headers early, before bucket existence check
// This ensures consistent CORS behavior and prevents information disclosure
ApplyHeaders ( w , corsResp )
// Handle preflight requests - return success immediately without checking bucket existence
// This matches AWS S3 behavior where preflight requests succeed even for non-existent buckets
if corsReq . IsPreflightRequest {
// Preflight request should return 200 OK with just CORS headers
w . WriteHeader ( http . StatusOK )
return
}
// For actual requests, continue with normal processing
// The handler will check bucket existence and return appropriate errors (e.g., NoSuchBucket)
// but CORS headers have already been applied above
next . ServeHTTP ( w , r )
} )
} )
}
// HandleOptionsRequest handles OPTIONS requests for CORS preflight
func ( m * Middleware ) HandleOptionsRequest ( w http . ResponseWriter , r * http . Request ) {
// Parse CORS request
m . processCORS ( w , r , func ( ) {
w . WriteHeader ( http . StatusOK )
} )
}
// processCORS handles the common CORS logic for both regular and preflight requests.
// It takes a next callback which is executed if the request flow proceeds (i.e., not short-circuited by CORS errors or preflight responses).
func ( m * Middleware ) processCORS ( w http . ResponseWriter , r * http . Request , next func ( ) ) {
corsReq := ParseRequest ( r )
bucket , _ := s3_constants . GetBucketAndObject ( r )
// If not a CORS request, return OK
if corsReq . Origin == "" {
w . WriteHeader ( http . StatusOK )
// 1. Basic Validation
if bucket == "" {
next ( )
return
}
// Extract bucket from request
bucket , _ := s3_constants . GetBucketAndObject ( r )
if bucket == "" {
w . WriteHeader ( http . StatusOK )
// 2. Load Configuration
config , hasConfig := m . getCORSConfig ( bucket )
// 3. Apply Vary Header (Always applied if config exists)
if hasConfig {
w . Header ( ) . Add ( "Vary" , "Origin" )
}
// 4. Handle Non-CORS Requests
if corsReq . Origin == "" {
next ( )
return
}
// Get CORS configuration (bucket-specific or fallback) BEFORE checking bucket existence
// This ensures CORS headers are applied consistently regardless of bucket existence
config , found := m . getCORSConfig ( bucket )
if ! found {
// No CORS configuration at all for OPTIONS request should return access denied
// 5. Handle Missing Configuration
if ! hasConfig {
if corsReq . IsPreflightRequest {
s3err . WriteErrorResponse ( w , r , s3err . ErrAccessDenied )
return
}
w . WriteHeader ( http . StatusOK )
next ( )
return
}
// Evaluate CORS r equest
// 6. Evaluate CORS R equest
corsResp , err := EvaluateRequest ( config , corsReq )
if err != nil {
glog . V ( 3 ) . Infof ( "CORS evaluation failed for bucket %s: %v" , bucket , err )
@ -173,11 +126,17 @@ func (m *Middleware) HandleOptionsRequest(w http.ResponseWriter, r *http.Request
s3err . WriteErrorResponse ( w , r , s3err . ErrAccessDenied )
return
}
w . WriteHeader ( http . StatusOK )
next ( )
return
}
// Apply CORS headers and return success
// 7. Success Case
ApplyHeaders ( w , corsResp )
w . WriteHeader ( http . StatusOK )
if corsReq . IsPreflightRequest {
w . WriteHeader ( http . StatusOK )
return
}
next ( )
}