| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156 |
- package cors
- import (
- "net/http"
- "github.com/seaweedfs/seaweedfs/weed/glog"
- "github.com/seaweedfs/seaweedfs/weed/s3api/s3_constants"
- "github.com/seaweedfs/seaweedfs/weed/s3api/s3err"
- )
- // BucketChecker interface for checking bucket existence
- type BucketChecker interface {
- CheckBucket(r *http.Request, bucket string) s3err.ErrorCode
- }
- // CORSConfigGetter interface for getting CORS configuration
- type CORSConfigGetter interface {
- GetCORSConfiguration(bucket string) (*CORSConfiguration, s3err.ErrorCode)
- }
- // Middleware handles CORS evaluation for all S3 API requests
- type Middleware struct {
- bucketChecker BucketChecker
- corsConfigGetter CORSConfigGetter
- }
- // NewMiddleware creates a new CORS middleware instance
- func NewMiddleware(bucketChecker BucketChecker, corsConfigGetter CORSConfigGetter) *Middleware {
- return &Middleware{
- bucketChecker: bucketChecker,
- corsConfigGetter: corsConfigGetter,
- }
- }
- // 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
- }
- // Check if bucket exists
- if err := m.bucketChecker.CheckBucket(r, bucket); err != s3err.ErrNone {
- // For non-existent buckets, let the normal handler deal with it
- next.ServeHTTP(w, r)
- 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
- }
- // Apply CORS headers
- ApplyHeaders(w, corsResp)
- // Handle preflight requests
- 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
- next.ServeHTTP(w, r)
- })
- }
- // HandleOptionsRequest handles OPTIONS requests for CORS preflight
- func (m *Middleware) HandleOptionsRequest(w http.ResponseWriter, r *http.Request) {
- // Parse CORS request
- corsReq := ParseRequest(r)
- // If not a CORS request, return OK
- if corsReq.Origin == "" {
- w.WriteHeader(http.StatusOK)
- return
- }
- // Extract bucket from request
- bucket, _ := s3_constants.GetBucketAndObject(r)
- if bucket == "" {
- w.WriteHeader(http.StatusOK)
- return
- }
- // Check if bucket exists
- if err := m.bucketChecker.CheckBucket(r, bucket); err != s3err.ErrNone {
- // For non-existent buckets, return OK (let other handlers deal with bucket existence)
- w.WriteHeader(http.StatusOK)
- return
- }
- // Load CORS configuration from cache
- config, errCode := m.corsConfigGetter.GetCORSConfiguration(bucket)
- if errCode != s3err.ErrNone || config == nil {
- // No CORS configuration for OPTIONS request should return access denied
- if corsReq.IsPreflightRequest {
- s3err.WriteErrorResponse(w, r, s3err.ErrAccessDenied)
- return
- }
- w.WriteHeader(http.StatusOK)
- 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 {
- s3err.WriteErrorResponse(w, r, s3err.ErrAccessDenied)
- return
- }
- w.WriteHeader(http.StatusOK)
- return
- }
- // Apply CORS headers and return success
- ApplyHeaders(w, corsResp)
- w.WriteHeader(http.StatusOK)
- }
|