[#641] Rework CORS bucket behaviour

Signed-off-by: Marina Biryukova <m.biryukova@yadro.com>
This commit is contained in:
Marina Biryukova 2025-02-19 19:09:19 +03:00 committed by Alexey Vanin
parent 1fac8e3ef2
commit 9edec7d573
16 changed files with 490 additions and 138 deletions

View file

@ -1,12 +1,19 @@
package handler
import (
"encoding/xml"
"net/http"
"net/http/httptest"
"strings"
"testing"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware"
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
oidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id/test"
"github.com/stretchr/testify/require"
)
@ -37,26 +44,14 @@ func TestCORSOriginWildcard(t *testing.T) {
hc.Handler().CreateBucketHandler(w, r)
assertStatus(t, w, http.StatusOK)
w, r = prepareTestPayloadRequest(hc, bktName, "", strings.NewReader(body))
ctx = middleware.SetBox(r.Context(), &middleware.Box{AccessBox: box})
r = r.WithContext(ctx)
hc.Handler().PutBucketCorsHandler(w, r)
assertStatus(t, w, http.StatusOK)
putBucketCORS(hc, bktName, body)
w, r = prepareTestPayloadRequest(hc, bktName, "", nil)
hc.Handler().GetBucketCorsHandler(w, r)
assertStatus(t, w, http.StatusOK)
getBucketCORS(hc, bktName)
hc.config.useDefaultXMLNS = true
w, r = prepareTestPayloadRequest(hc, bktName, "", strings.NewReader(bodyNoXmlns))
ctx = middleware.SetBox(r.Context(), &middleware.Box{AccessBox: box})
r = r.WithContext(ctx)
hc.Handler().PutBucketCorsHandler(w, r)
assertStatus(t, w, http.StatusOK)
putBucketCORS(hc, bktName, bodyNoXmlns)
w, r = prepareTestPayloadRequest(hc, bktName, "", nil)
hc.Handler().GetBucketCorsHandler(w, r)
assertStatus(t, w, http.StatusOK)
getBucketCORS(hc, bktName)
}
func TestPreflight(t *testing.T) {
@ -170,11 +165,7 @@ func TestPreflightWildcardOrigin(t *testing.T) {
hc.Handler().CreateBucketHandler(w, r)
assertStatus(t, w, http.StatusOK)
w, r = prepareTestPayloadRequest(hc, bktName, "", strings.NewReader(body))
ctx = middleware.SetBox(r.Context(), &middleware.Box{AccessBox: box})
r = r.WithContext(ctx)
hc.Handler().PutBucketCorsHandler(w, r)
assertStatus(t, w, http.StatusOK)
putBucketCORS(hc, bktName, body)
for _, tc := range []struct {
name string
@ -236,3 +227,183 @@ func TestPreflightWildcardOrigin(t *testing.T) {
})
}
}
func TestDeleteAllCORSVersions(t *testing.T) {
body := `
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
<AllowedMethod>GET</AllowedMethod>
<AllowedMethod>PUT</AllowedMethod>
<AllowedOrigin>*</AllowedOrigin>
<AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>
`
hc := prepareHandlerContext(t)
bktName := "bucket-delete-all-cors-version"
createBucket(hc, bktName)
require.Len(t, hc.tp.Objects(), 0)
for range 5 {
putBucketCORS(hc, bktName, body)
}
require.Len(t, hc.tp.Objects(), 5)
deleteBucketCORS(hc, bktName)
require.Len(t, hc.tp.Objects(), 0)
}
func TestGetLatestCORSVersion(t *testing.T) {
bodyTree := `
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
<AllowedMethod>GET</AllowedMethod>
<AllowedMethod>PUT</AllowedMethod>
<AllowedOrigin>*</AllowedOrigin>
<AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>
`
body := `
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
<AllowedMethod>DELETE</AllowedMethod>
<AllowedOrigin>*</AllowedOrigin>
<AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>
`
hc := prepareHandlerContextWithMinCache(t)
bktName := "bucket-get-latest-cors"
info := createBucket(hc, bktName)
addCORSToTree(hc, bodyTree, info.BktInfo, info.BktInfo.CID)
w := getBucketCORS(hc, bktName)
requireEqualCORS(hc.t, bodyTree, w.Body.String())
hc.tp.AddCORSObject(info.BktInfo, hc.corsCnrID, body)
w = getBucketCORS(hc, bktName)
requireEqualCORS(hc.t, body, w.Body.String())
hc.tp.AddCORSObject(info.BktInfo, hc.corsCnrID, bodyTree)
w = getBucketCORS(hc, bktName)
requireEqualCORS(hc.t, bodyTree, w.Body.String())
}
func TestDeleteTreeCORSVersions(t *testing.T) {
body := `
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
<AllowedMethod>GET</AllowedMethod>
<AllowedMethod>PUT</AllowedMethod>
<AllowedOrigin>*</AllowedOrigin>
<AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>
`
hc := prepareHandlerContext(t)
bktName := "bucket-delete-tree-cors-versions"
info := createBucket(hc, bktName)
addCORSToTree(hc, body, info.BktInfo, info.BktInfo.CID)
addCORSToTree(hc, body, info.BktInfo, hc.corsCnrID)
require.Len(t, hc.tp.Objects(), 2)
putBucketCORS(hc, bktName, body)
require.Len(t, hc.tp.Objects(), 1)
addCORSToTree(hc, body, info.BktInfo, info.BktInfo.CID)
addCORSToTree(hc, body, info.BktInfo, hc.corsCnrID)
require.Len(t, hc.tp.Objects(), 3)
deleteBucketCORS(hc, bktName)
require.Len(t, hc.tp.Objects(), 0)
}
func TestDeleteCORSInDeleteBucket(t *testing.T) {
body := `
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
<AllowedMethod>GET</AllowedMethod>
<AllowedMethod>PUT</AllowedMethod>
<AllowedOrigin>*</AllowedOrigin>
<AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>
`
hc := prepareHandlerContext(t)
bktName := "bucket-delete-cors-in-delete-bucket"
info := createBucket(hc, bktName)
addCORSToTree(hc, body, info.BktInfo, hc.corsCnrID)
addCORSToTree(hc, body, info.BktInfo, info.BktInfo.CID)
hc.tp.AddCORSObject(info.BktInfo, hc.corsCnrID, body)
require.Len(t, hc.tp.Objects(), 3)
hc.owner = info.BktInfo.Owner
deleteBucket(t, hc, bktName, http.StatusNoContent)
require.Len(t, hc.tp.Objects(), 1) // CORS object in bucket container is not deleted
}
func addCORSToTree(hc *handlerContext, cors string, bkt *data.BucketInfo, corsCnrID cid.ID) {
var addr oid.Address
addr.SetContainer(corsCnrID)
addr.SetObject(oidtest.ID())
var obj object.Object
obj.SetPayload([]byte(cors))
obj.SetPayloadSize(uint64(len(cors)))
hc.tp.SetObject(addr, &obj)
meta := make(map[string]string)
meta["FileName"] = "bucket-cors"
meta["OID"] = addr.Object().EncodeToString()
meta["CID"] = addr.Container().EncodeToString()
_, err := hc.treeMock.AddNode(hc.context, bkt, "system", 0, meta)
require.NoError(hc.t, err)
}
func requireEqualCORS(t *testing.T, expected string, actual string) {
expectedCORS := &data.CORSConfiguration{}
err := xml.NewDecoder(strings.NewReader(expected)).Decode(expectedCORS)
require.NoError(t, err)
actualCORS := &data.CORSConfiguration{}
err = xml.NewDecoder(strings.NewReader(actual)).Decode(actualCORS)
require.NoError(t, err)
require.Equal(t, expectedCORS, actualCORS)
}
func putBucketCORS(hc *handlerContext, bktName string, body string) {
w, r := prepareTestPayloadRequest(hc, bktName, "", strings.NewReader(body))
box, _ := createAccessBox(hc.t)
r = r.WithContext(middleware.SetBox(r.Context(), &middleware.Box{AccessBox: box}))
hc.Handler().PutBucketCorsHandler(w, r)
assertStatus(hc.t, w, http.StatusOK)
}
func deleteBucketCORS(hc *handlerContext, bktName string) {
w, r := prepareTestPayloadRequest(hc, bktName, "", nil)
box, _ := createAccessBox(hc.t)
r = r.WithContext(middleware.SetBox(r.Context(), &middleware.Box{AccessBox: box}))
hc.Handler().DeleteBucketCorsHandler(w, r)
assertStatus(hc.t, w, http.StatusNoContent)
}
func getBucketCORS(hc *handlerContext, bktName string) *httptest.ResponseRecorder {
w, r := prepareTestPayloadRequest(hc, bktName, "", nil)
hc.Handler().GetBucketCorsHandler(w, r)
assertStatus(hc.t, w, http.StatusOK)
return w
}