middleware.go 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. package cors
  2. import (
  3. "net/http"
  4. "github.com/seaweedfs/seaweedfs/weed/glog"
  5. "github.com/seaweedfs/seaweedfs/weed/s3api/s3_constants"
  6. "github.com/seaweedfs/seaweedfs/weed/s3api/s3err"
  7. )
  8. // BucketChecker interface for checking bucket existence
  9. type BucketChecker interface {
  10. CheckBucket(r *http.Request, bucket string) s3err.ErrorCode
  11. }
  12. // CORSConfigGetter interface for getting CORS configuration
  13. type CORSConfigGetter interface {
  14. GetCORSConfiguration(bucket string) (*CORSConfiguration, s3err.ErrorCode)
  15. }
  16. // Middleware handles CORS evaluation for all S3 API requests
  17. type Middleware struct {
  18. bucketChecker BucketChecker
  19. corsConfigGetter CORSConfigGetter
  20. }
  21. // NewMiddleware creates a new CORS middleware instance
  22. func NewMiddleware(bucketChecker BucketChecker, corsConfigGetter CORSConfigGetter) *Middleware {
  23. return &Middleware{
  24. bucketChecker: bucketChecker,
  25. corsConfigGetter: corsConfigGetter,
  26. }
  27. }
  28. // Handler returns the CORS middleware handler
  29. func (m *Middleware) Handler(next http.Handler) http.Handler {
  30. return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  31. // Parse CORS request
  32. corsReq := ParseRequest(r)
  33. // If not a CORS request, continue normally
  34. if corsReq.Origin == "" {
  35. next.ServeHTTP(w, r)
  36. return
  37. }
  38. // Extract bucket from request
  39. bucket, _ := s3_constants.GetBucketAndObject(r)
  40. if bucket == "" {
  41. next.ServeHTTP(w, r)
  42. return
  43. }
  44. // Check if bucket exists
  45. if err := m.bucketChecker.CheckBucket(r, bucket); err != s3err.ErrNone {
  46. // For non-existent buckets, let the normal handler deal with it
  47. next.ServeHTTP(w, r)
  48. return
  49. }
  50. // Load CORS configuration from cache
  51. config, errCode := m.corsConfigGetter.GetCORSConfiguration(bucket)
  52. if errCode != s3err.ErrNone || config == nil {
  53. // No CORS configuration, handle based on request type
  54. if corsReq.IsPreflightRequest {
  55. // Preflight request without CORS config should fail
  56. s3err.WriteErrorResponse(w, r, s3err.ErrAccessDenied)
  57. return
  58. }
  59. // Non-preflight request, continue normally
  60. next.ServeHTTP(w, r)
  61. return
  62. }
  63. // Evaluate CORS request
  64. corsResp, err := EvaluateRequest(config, corsReq)
  65. if err != nil {
  66. glog.V(3).Infof("CORS evaluation failed for bucket %s: %v", bucket, err)
  67. if corsReq.IsPreflightRequest {
  68. // Preflight request that doesn't match CORS rules should fail
  69. s3err.WriteErrorResponse(w, r, s3err.ErrAccessDenied)
  70. return
  71. }
  72. // Non-preflight request, continue normally but without CORS headers
  73. next.ServeHTTP(w, r)
  74. return
  75. }
  76. // Apply CORS headers
  77. ApplyHeaders(w, corsResp)
  78. // Handle preflight requests
  79. if corsReq.IsPreflightRequest {
  80. // Preflight request should return 200 OK with just CORS headers
  81. w.WriteHeader(http.StatusOK)
  82. return
  83. }
  84. // For actual requests, continue with normal processing
  85. next.ServeHTTP(w, r)
  86. })
  87. }
  88. // HandleOptionsRequest handles OPTIONS requests for CORS preflight
  89. func (m *Middleware) HandleOptionsRequest(w http.ResponseWriter, r *http.Request) {
  90. // Parse CORS request
  91. corsReq := ParseRequest(r)
  92. // If not a CORS request, return OK
  93. if corsReq.Origin == "" {
  94. w.WriteHeader(http.StatusOK)
  95. return
  96. }
  97. // Extract bucket from request
  98. bucket, _ := s3_constants.GetBucketAndObject(r)
  99. if bucket == "" {
  100. w.WriteHeader(http.StatusOK)
  101. return
  102. }
  103. // Check if bucket exists
  104. if err := m.bucketChecker.CheckBucket(r, bucket); err != s3err.ErrNone {
  105. // For non-existent buckets, return OK (let other handlers deal with bucket existence)
  106. w.WriteHeader(http.StatusOK)
  107. return
  108. }
  109. // Load CORS configuration from cache
  110. config, errCode := m.corsConfigGetter.GetCORSConfiguration(bucket)
  111. if errCode != s3err.ErrNone || config == nil {
  112. // No CORS configuration for OPTIONS request should return access denied
  113. if corsReq.IsPreflightRequest {
  114. s3err.WriteErrorResponse(w, r, s3err.ErrAccessDenied)
  115. return
  116. }
  117. w.WriteHeader(http.StatusOK)
  118. return
  119. }
  120. // Evaluate CORS request
  121. corsResp, err := EvaluateRequest(config, corsReq)
  122. if err != nil {
  123. glog.V(3).Infof("CORS evaluation failed for bucket %s: %v", bucket, err)
  124. if corsReq.IsPreflightRequest {
  125. s3err.WriteErrorResponse(w, r, s3err.ErrAccessDenied)
  126. return
  127. }
  128. w.WriteHeader(http.StatusOK)
  129. return
  130. }
  131. // Apply CORS headers and return success
  132. ApplyHeaders(w, corsResp)
  133. w.WriteHeader(http.StatusOK)
  134. }