1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
|
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 {
storage *Storage
bucketChecker BucketChecker
corsConfigGetter CORSConfigGetter
}
// NewMiddleware creates a new CORS middleware instance
func NewMiddleware(storage *Storage, bucketChecker BucketChecker, corsConfigGetter CORSConfigGetter) *Middleware {
return &Middleware{
storage: storage,
bucketChecker: bucketChecker,
corsConfigGetter: corsConfigGetter,
}
}
// evaluateCORSRequest performs the common CORS request evaluation logic
// 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
corsReq := ParseRequest(r)
if corsReq.Origin == "" {
// Not a CORS request
return nil, false, true
}
// Extract bucket from request
bucket, _ := s3_constants.GetBucketAndObject(r)
if bucket == "" {
return nil, false, true
}
// 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
return nil, false, true
}
// 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 nil, true, false // Response written, don't continue
}
// Non-preflight request, continue normally
return nil, false, true
}
// 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 nil, true, false // Response written, don't continue
}
// Non-preflight request, continue normally but without CORS headers
return nil, false, true
}
return corsResp, false, false
}
// 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) {
// Use the common evaluation logic
corsResp, responseWritten, shouldContinue := m.evaluateCORSRequest(w, r)
if responseWritten {
// Response was already written (error case)
return
}
if shouldContinue {
// Continue with normal request processing
next.ServeHTTP(w, r)
return
}
// Parse request to check if it's a preflight request
corsReq := ParseRequest(r)
// Apply CORS headers to response
ApplyHeaders(w, corsResp)
// Handle preflight requests
if corsReq.IsPreflightRequest {
// Preflight request should return 200 OK with just CORS headers
w.WriteHeader(http.StatusOK)
return
}
// Continue with normal request processing
next.ServeHTTP(w, r)
})
}
// HandleOptionsRequest handles OPTIONS requests for CORS preflight
func (m *Middleware) HandleOptionsRequest(w http.ResponseWriter, r *http.Request) {
// Use the common evaluation logic
corsResp, responseWritten, shouldContinue := m.evaluateCORSRequest(w, r)
if responseWritten {
// Response was already written (error case)
return
}
if shouldContinue || corsResp == nil {
// Not a CORS request or should continue normally
w.WriteHeader(http.StatusOK)
return
}
// Apply CORS headers and return success
ApplyHeaders(w, corsResp)
w.WriteHeader(http.StatusOK)
}
|