|
@ -35,97 +35,77 @@ func NewMiddleware(storage *Storage, bucketChecker BucketChecker, corsConfigGett |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// evaluateCORSRequest performs the common CORS request evaluation logic
|
|
|
// evaluateCORSRequest performs the common CORS request evaluation logic
|
|
|
func (m *Middleware) evaluateCORSRequest(w http.ResponseWriter, r *http.Request) (*CORSResponse, bool) { |
|
|
|
|
|
|
|
|
// Returns: (corsResponse, responseWritten, shouldContinue)
|
|
|
|
|
|
// - corsResponse: the CORS response if evaluation succeeded
|
|
|
|
|
|
// - responseWritten: true if an error response was already written
|
|
|
|
|
|
// - shouldContinue: true if the request should continue to the next handler
|
|
|
|
|
|
func (m *Middleware) evaluateCORSRequest(w http.ResponseWriter, r *http.Request) (*CORSResponse, bool, bool) { |
|
|
// Parse CORS request
|
|
|
// Parse CORS request
|
|
|
corsReq := ParseRequest(r) |
|
|
corsReq := ParseRequest(r) |
|
|
if corsReq.Origin == "" { |
|
|
if corsReq.Origin == "" { |
|
|
// Not a CORS request
|
|
|
// Not a CORS request
|
|
|
return nil, false |
|
|
|
|
|
|
|
|
return nil, false, true |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Extract bucket from request
|
|
|
// Extract bucket from request
|
|
|
bucket, _ := s3_constants.GetBucketAndObject(r) |
|
|
bucket, _ := s3_constants.GetBucketAndObject(r) |
|
|
if bucket == "" { |
|
|
if bucket == "" { |
|
|
return nil, false |
|
|
|
|
|
|
|
|
return nil, false, true |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Check if bucket exists
|
|
|
// Check if bucket exists
|
|
|
if err := m.bucketChecker.CheckBucket(r, bucket); err != s3err.ErrNone { |
|
|
if err := m.bucketChecker.CheckBucket(r, bucket); err != s3err.ErrNone { |
|
|
s3err.WriteErrorResponse(w, r, err) |
|
|
|
|
|
return nil, true // Return true to indicate response was written
|
|
|
|
|
|
|
|
|
// For non-existent buckets, let the normal handler deal with it
|
|
|
|
|
|
return nil, false, true |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Load CORS configuration from cache
|
|
|
// Load CORS configuration from cache
|
|
|
config, errCode := m.corsConfigGetter.GetCORSConfiguration(bucket) |
|
|
config, errCode := m.corsConfigGetter.GetCORSConfiguration(bucket) |
|
|
if errCode != s3err.ErrNone || config == nil { |
|
|
if errCode != s3err.ErrNone || config == nil { |
|
|
s3err.WriteErrorResponse(w, r, s3err.ErrAccessDenied) |
|
|
|
|
|
return nil, true // Return true to indicate response was written
|
|
|
|
|
|
|
|
|
// No CORS configuration, handle based on request type
|
|
|
|
|
|
if corsReq.IsPreflightRequest { |
|
|
|
|
|
// Preflight request without CORS config should fail
|
|
|
|
|
|
s3err.WriteErrorResponse(w, r, s3err.ErrAccessDenied) |
|
|
|
|
|
return nil, true, false // Response written, don't continue
|
|
|
|
|
|
} |
|
|
|
|
|
// Non-preflight request, continue normally
|
|
|
|
|
|
return nil, false, true |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Evaluate CORS request
|
|
|
// Evaluate CORS request
|
|
|
corsResp, err := EvaluateRequest(config, corsReq) |
|
|
corsResp, err := EvaluateRequest(config, corsReq) |
|
|
if err != nil { |
|
|
if err != nil { |
|
|
glog.V(3).Infof("CORS evaluation failed for bucket %s: %v", bucket, err) |
|
|
glog.V(3).Infof("CORS evaluation failed for bucket %s: %v", bucket, err) |
|
|
s3err.WriteErrorResponse(w, r, s3err.ErrAccessDenied) |
|
|
|
|
|
return nil, true // Return true to indicate response was written
|
|
|
|
|
|
|
|
|
if corsReq.IsPreflightRequest { |
|
|
|
|
|
// Preflight request that doesn't match CORS rules should fail
|
|
|
|
|
|
s3err.WriteErrorResponse(w, r, s3err.ErrAccessDenied) |
|
|
|
|
|
return nil, true, false // Response written, don't continue
|
|
|
|
|
|
} |
|
|
|
|
|
// Non-preflight request, continue normally but without CORS headers
|
|
|
|
|
|
return nil, false, true |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
return corsResp, false |
|
|
|
|
|
|
|
|
return corsResp, false, false |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Handler returns the CORS middleware handler
|
|
|
// Handler returns the CORS middleware handler
|
|
|
func (m *Middleware) Handler(next http.Handler) http.Handler { |
|
|
func (m *Middleware) Handler(next http.Handler) http.Handler { |
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
|
|
// Check if this is a CORS request
|
|
|
|
|
|
corsReq := ParseRequest(r) |
|
|
|
|
|
if corsReq.Origin == "" { |
|
|
|
|
|
// Not a CORS request, continue normally
|
|
|
|
|
|
next.ServeHTTP(w, r) |
|
|
|
|
|
return |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Extract bucket from request
|
|
|
|
|
|
bucket, _ := s3_constants.GetBucketAndObject(r) |
|
|
|
|
|
if bucket == "" { |
|
|
|
|
|
// No bucket in request, continue normally
|
|
|
|
|
|
next.ServeHTTP(w, r) |
|
|
|
|
|
|
|
|
// Use the common evaluation logic
|
|
|
|
|
|
corsResp, responseWritten, shouldContinue := m.evaluateCORSRequest(w, r) |
|
|
|
|
|
if responseWritten { |
|
|
|
|
|
// Response was already written (error case)
|
|
|
return |
|
|
return |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Check if bucket exists
|
|
|
|
|
|
if err := m.bucketChecker.CheckBucket(r, bucket); err != s3err.ErrNone { |
|
|
|
|
|
// Bucket doesn't exist, let the normal handler deal with it
|
|
|
|
|
|
|
|
|
if shouldContinue { |
|
|
|
|
|
// Continue with normal request processing
|
|
|
next.ServeHTTP(w, r) |
|
|
next.ServeHTTP(w, r) |
|
|
return |
|
|
return |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Load CORS configuration from cache
|
|
|
|
|
|
config, errCode := m.corsConfigGetter.GetCORSConfiguration(bucket) |
|
|
|
|
|
if errCode != s3err.ErrNone || config == nil { |
|
|
|
|
|
// No CORS configuration, 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
|
|
|
|
|
|
next.ServeHTTP(w, r) |
|
|
|
|
|
return |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
// Parse request to check if it's a preflight request
|
|
|
|
|
|
corsReq := ParseRequest(r) |
|
|
|
|
|
|
|
|
// Apply CORS headers to response
|
|
|
// Apply CORS headers to response
|
|
|
ApplyHeaders(w, corsResp) |
|
|
ApplyHeaders(w, corsResp) |
|
@ -145,14 +125,14 @@ func (m *Middleware) Handler(next http.Handler) http.Handler { |
|
|
// HandleOptionsRequest handles OPTIONS requests for CORS preflight
|
|
|
// HandleOptionsRequest handles OPTIONS requests for CORS preflight
|
|
|
func (m *Middleware) HandleOptionsRequest(w http.ResponseWriter, r *http.Request) { |
|
|
func (m *Middleware) HandleOptionsRequest(w http.ResponseWriter, r *http.Request) { |
|
|
// Use the common evaluation logic
|
|
|
// Use the common evaluation logic
|
|
|
corsResp, responseWritten := m.evaluateCORSRequest(w, r) |
|
|
|
|
|
|
|
|
corsResp, responseWritten, shouldContinue := m.evaluateCORSRequest(w, r) |
|
|
if responseWritten { |
|
|
if responseWritten { |
|
|
// Response was already written (error case)
|
|
|
// Response was already written (error case)
|
|
|
return |
|
|
return |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if corsResp == nil { |
|
|
|
|
|
// Not a CORS request
|
|
|
|
|
|
|
|
|
if shouldContinue || corsResp == nil { |
|
|
|
|
|
// Not a CORS request or should continue normally
|
|
|
w.WriteHeader(http.StatusOK) |
|
|
w.WriteHeader(http.StatusOK) |
|
|
return |
|
|
return |
|
|
} |
|
|
} |
|
|