aboutsummaryrefslogtreecommitdiff
path: root/weed/s3api/s3api_bucket_cors_handlers.go
blob: bd27785e2b88cf70ee68bb560cf9a92780ace233 (plain)
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
package s3api

import (
	"encoding/xml"
	"net/http"

	"github.com/seaweedfs/seaweedfs/weed/glog"
	"github.com/seaweedfs/seaweedfs/weed/s3api/cors"
	"github.com/seaweedfs/seaweedfs/weed/s3api/s3_constants"
	"github.com/seaweedfs/seaweedfs/weed/s3api/s3err"
)

// S3BucketChecker implements cors.BucketChecker interface
type S3BucketChecker struct {
	server *S3ApiServer
}

func (c *S3BucketChecker) CheckBucket(r *http.Request, bucket string) s3err.ErrorCode {
	return c.server.checkBucket(r, bucket)
}

// S3CORSConfigGetter implements cors.CORSConfigGetter interface
type S3CORSConfigGetter struct {
	server *S3ApiServer
}

func (g *S3CORSConfigGetter) GetCORSConfiguration(bucket string) (*cors.CORSConfiguration, s3err.ErrorCode) {
	return g.server.getCORSConfiguration(bucket)
}

// getCORSMiddleware returns a CORS middleware instance with caching
func (s3a *S3ApiServer) getCORSMiddleware() *cors.Middleware {
	bucketChecker := &S3BucketChecker{server: s3a}
	corsConfigGetter := &S3CORSConfigGetter{server: s3a}

	return cors.NewMiddleware(bucketChecker, corsConfigGetter)
}

// GetBucketCorsHandler handles Get bucket CORS configuration
// https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketCors.html
func (s3a *S3ApiServer) GetBucketCorsHandler(w http.ResponseWriter, r *http.Request) {
	bucket, _ := s3_constants.GetBucketAndObject(r)
	glog.V(3).Infof("GetBucketCorsHandler %s", bucket)

	if err := s3a.checkBucket(r, bucket); err != s3err.ErrNone {
		s3err.WriteErrorResponse(w, r, err)
		return
	}

	// Load CORS configuration from cache
	config, errCode := s3a.getCORSConfiguration(bucket)
	if errCode != s3err.ErrNone {
		if errCode == s3err.ErrNoSuchBucket {
			s3err.WriteErrorResponse(w, r, s3err.ErrNoSuchBucket)
		} else {
			s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
		}
		return
	}

	if config == nil {
		s3err.WriteErrorResponse(w, r, s3err.ErrNoSuchCORSConfiguration)
		return
	}

	// Return CORS configuration as XML
	writeSuccessResponseXML(w, r, config)
}

// PutBucketCorsHandler handles Put bucket CORS configuration
// https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketCors.html
func (s3a *S3ApiServer) PutBucketCorsHandler(w http.ResponseWriter, r *http.Request) {
	bucket, _ := s3_constants.GetBucketAndObject(r)
	glog.V(3).Infof("PutBucketCorsHandler %s", bucket)

	if err := s3a.checkBucket(r, bucket); err != s3err.ErrNone {
		s3err.WriteErrorResponse(w, r, err)
		return
	}

	// Parse CORS configuration from request body
	var config cors.CORSConfiguration
	if err := xml.NewDecoder(r.Body).Decode(&config); err != nil {
		glog.V(1).Infof("Failed to parse CORS configuration: %v", err)
		s3err.WriteErrorResponse(w, r, s3err.ErrMalformedXML)
		return
	}

	// Validate CORS configuration
	if err := cors.ValidateConfiguration(&config); err != nil {
		glog.V(1).Infof("Invalid CORS configuration: %v", err)
		s3err.WriteErrorResponse(w, r, s3err.ErrInvalidRequest)
		return
	}

	// Store CORS configuration and update cache
	// This handles both cache update and persistent storage through the unified bucket config system
	if err := s3a.updateCORSConfiguration(bucket, &config); err != s3err.ErrNone {
		glog.Errorf("Failed to update CORS configuration: %v", err)
		s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
		return
	}

	// Return success
	writeSuccessResponseEmpty(w, r)
}

// DeleteBucketCorsHandler handles Delete bucket CORS configuration
// https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucketCors.html
func (s3a *S3ApiServer) DeleteBucketCorsHandler(w http.ResponseWriter, r *http.Request) {
	bucket, _ := s3_constants.GetBucketAndObject(r)
	glog.V(3).Infof("DeleteBucketCorsHandler %s", bucket)

	if err := s3a.checkBucket(r, bucket); err != s3err.ErrNone {
		s3err.WriteErrorResponse(w, r, err)
		return
	}

	// Remove CORS configuration from cache and persistent storage
	// This handles both cache invalidation and persistent storage cleanup through the unified bucket config system
	if err := s3a.removeCORSConfiguration(bucket); err != s3err.ErrNone {
		glog.Errorf("Failed to remove CORS configuration: %v", err)
		s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
		return
	}

	// Return success (204 No Content)
	w.WriteHeader(http.StatusNoContent)
}