Skip to content

Commit d80dc8b

Browse files
API methods for bucket-level CORS configuration settings (#1987)
1 parent cc7769f commit d80dc8b

File tree

7 files changed

+1195
-14
lines changed

7 files changed

+1195
-14
lines changed

api-bucket-cors.go

+136
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
/*
2+
* MinIO Go Library for Amazon S3 Compatible Cloud Storage
3+
* Copyright 2024 MinIO, Inc.
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package minio
18+
19+
import (
20+
"bytes"
21+
"context"
22+
"net/http"
23+
"net/url"
24+
25+
"github.com/minio/minio-go/v7/pkg/cors"
26+
"github.com/minio/minio-go/v7/pkg/s3utils"
27+
)
28+
29+
// SetBucketCors sets the cors configuration for the bucket
30+
func (c *Client) SetBucketCors(ctx context.Context, bucketName string, corsConfig *cors.Config) error {
31+
if err := s3utils.CheckValidBucketName(bucketName); err != nil {
32+
return err
33+
}
34+
35+
if corsConfig == nil {
36+
return c.removeBucketCors(ctx, bucketName)
37+
}
38+
39+
return c.putBucketCors(ctx, bucketName, corsConfig)
40+
}
41+
42+
func (c *Client) putBucketCors(ctx context.Context, bucketName string, corsConfig *cors.Config) error {
43+
urlValues := make(url.Values)
44+
urlValues.Set("cors", "")
45+
46+
corsStr, err := corsConfig.ToXML()
47+
if err != nil {
48+
return err
49+
}
50+
51+
reqMetadata := requestMetadata{
52+
bucketName: bucketName,
53+
queryValues: urlValues,
54+
contentBody: bytes.NewReader(corsStr),
55+
contentLength: int64(len(corsStr)),
56+
contentMD5Base64: sumMD5Base64([]byte(corsStr)),
57+
}
58+
59+
resp, err := c.executeMethod(ctx, http.MethodPut, reqMetadata)
60+
defer closeResponse(resp)
61+
if err != nil {
62+
return err
63+
}
64+
if resp != nil {
65+
if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusNoContent {
66+
return httpRespToErrorResponse(resp, bucketName, "")
67+
}
68+
}
69+
return nil
70+
}
71+
72+
func (c *Client) removeBucketCors(ctx context.Context, bucketName string) error {
73+
urlValues := make(url.Values)
74+
urlValues.Set("cors", "")
75+
76+
resp, err := c.executeMethod(ctx, http.MethodDelete, requestMetadata{
77+
bucketName: bucketName,
78+
queryValues: urlValues,
79+
contentSHA256Hex: emptySHA256Hex,
80+
})
81+
defer closeResponse(resp)
82+
if err != nil {
83+
return err
84+
}
85+
86+
if resp.StatusCode != http.StatusNoContent {
87+
return httpRespToErrorResponse(resp, bucketName, "")
88+
}
89+
90+
return nil
91+
}
92+
93+
// GetBucketCors returns the current cors
94+
func (c *Client) GetBucketCors(ctx context.Context, bucketName string) (*cors.Config, error) {
95+
if err := s3utils.CheckValidBucketName(bucketName); err != nil {
96+
return nil, err
97+
}
98+
bucketCors, err := c.getBucketCors(ctx, bucketName)
99+
if err != nil {
100+
errResponse := ToErrorResponse(err)
101+
if errResponse.Code == "NoSuchCORSConfiguration" {
102+
return nil, nil
103+
}
104+
return nil, err
105+
}
106+
return bucketCors, nil
107+
}
108+
109+
func (c *Client) getBucketCors(ctx context.Context, bucketName string) (*cors.Config, error) {
110+
urlValues := make(url.Values)
111+
urlValues.Set("cors", "")
112+
113+
resp, err := c.executeMethod(ctx, http.MethodGet, requestMetadata{
114+
bucketName: bucketName,
115+
queryValues: urlValues,
116+
contentSHA256Hex: emptySHA256Hex, // TODO: needed? copied over from other example, but not spec'd in API.
117+
})
118+
119+
defer closeResponse(resp)
120+
if err != nil {
121+
return nil, err
122+
}
123+
124+
if resp != nil {
125+
if resp.StatusCode != http.StatusOK {
126+
return nil, httpRespToErrorResponse(resp, bucketName, "")
127+
}
128+
}
129+
130+
corsConfig, err := cors.ParseBucketCorsConfig(resp.Body)
131+
if err != nil {
132+
return nil, err
133+
}
134+
135+
return corsConfig, nil
136+
}

examples/s3/putbucketcors.go

+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
//go:build example
2+
// +build example
3+
4+
/*
5+
* MinIO Go Library for Amazon S3 Compatible Cloud Storage
6+
* Copyright 2015-2024 MinIO, Inc.
7+
*
8+
* Licensed under the Apache License, Version 2.0 (the "License");
9+
* you may not use this file except in compliance with the License.
10+
* You may obtain a copy of the License at
11+
*
12+
* http://www.apache.org/licenses/LICENSE-2.0
13+
*
14+
* Unless required by applicable law or agreed to in writing, software
15+
* distributed under the License is distributed on an "AS IS" BASIS,
16+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17+
* See the License for the specific language governing permissions and
18+
* limitations under the License.
19+
*/
20+
21+
package main
22+
23+
import (
24+
"context"
25+
"fmt"
26+
"log"
27+
28+
"github.com/minio/minio-go/v7"
29+
"github.com/minio/minio-go/v7/pkg/cors"
30+
"github.com/minio/minio-go/v7/pkg/credentials"
31+
)
32+
33+
func main() {
34+
// Note: YOUR-ACCESSKEYID, YOUR-SECRETACCESSKEY, my-bucketname and my-prefixname
35+
// are dummy values, please replace them with original values.
36+
37+
// Requests are always secure (HTTPS) by default. Set secure=false to enable insecure (HTTP) access.
38+
// This boolean value is the last argument for New().
39+
40+
// New returns an Amazon S3 compatible client object. API compatibility (v2 or v4) is automatically
41+
// determined based on the Endpoint value.
42+
s3Client, err := minio.New("s3.amazonaws.com", &minio.Options{
43+
Creds: credentials.NewStaticV4("YOUR-ACCESSKEYID", "YOUR-SECRETACCESSKEY", ""),
44+
Secure: true,
45+
})
46+
if err != nil {
47+
log.Fatalln(err)
48+
}
49+
bucket := "my-bucket-name"
50+
51+
corsRules := []cors.Rule{
52+
{
53+
AllowedHeader: []string{"*"},
54+
AllowedMethod: []string{"GET", "PUT"},
55+
AllowedOrigin: []string{"https://example.com"},
56+
},
57+
}
58+
corsConfig := cors.NewConfig(corsRules)
59+
60+
err = s3Client.SetBucketCors(context.Background(), bucket, corsConfig)
61+
if err != nil {
62+
log.Fatalln(fmt.Errorf("Error setting bucket cors: %v", err))
63+
}
64+
65+
retCors, err := s3Client.GetBucketCors(context.Background(), bucket)
66+
if err != nil {
67+
log.Fatalln(fmt.Errorf("Error getting bucket cors: %v", err))
68+
}
69+
70+
fmt.Printf("Returned Bucket CORS configuration: %+v\n", retCors)
71+
72+
err = s3Client.SetBucketCors(context.Background(), bucket, nil)
73+
if err != nil {
74+
log.Fatalln(fmt.Errorf("Error removing bucket cors: %v", err))
75+
}
76+
}

0 commit comments

Comments
 (0)