2022-06-01 14:50:30 +00:00
|
|
|
package handler
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"net/http"
|
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
2023-03-07 14:38:08 +00:00
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api"
|
2023-06-29 12:46:42 +00:00
|
|
|
s3errors "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
2023-03-07 14:38:08 +00:00
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/creds/accessbox"
|
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer"
|
2023-06-29 12:46:42 +00:00
|
|
|
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
|
2023-03-07 14:38:08 +00:00
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/eacl"
|
2022-10-04 08:31:09 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
2022-06-01 14:50:30 +00:00
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestConditionalHead(t *testing.T) {
|
|
|
|
tc := prepareHandlerContext(t)
|
|
|
|
|
2022-10-04 08:31:09 +00:00
|
|
|
bktName, objName := "bucket-for-conditional", "object"
|
|
|
|
_, objInfo := createBucketAndObject(tc, bktName, objName)
|
2022-06-01 14:50:30 +00:00
|
|
|
|
2022-10-04 08:31:09 +00:00
|
|
|
w, r := prepareTestRequest(tc, bktName, objName, nil)
|
2022-06-01 14:50:30 +00:00
|
|
|
tc.Handler().HeadObjectHandler(w, r)
|
|
|
|
assertStatus(t, w, http.StatusOK)
|
|
|
|
etag := w.Result().Header.Get(api.ETag)
|
|
|
|
|
2022-10-04 08:31:09 +00:00
|
|
|
headers := map[string]string{api.IfMatch: etag}
|
|
|
|
headObject(t, tc, bktName, objName, headers, http.StatusOK)
|
2022-06-01 14:50:30 +00:00
|
|
|
|
2022-10-04 08:31:09 +00:00
|
|
|
headers = map[string]string{api.IfMatch: "etag"}
|
|
|
|
headObject(t, tc, bktName, objName, headers, http.StatusPreconditionFailed)
|
2022-06-01 14:50:30 +00:00
|
|
|
|
2022-10-04 08:31:09 +00:00
|
|
|
headers = map[string]string{api.IfUnmodifiedSince: objInfo.Created.Add(time.Minute).Format(http.TimeFormat)}
|
|
|
|
headObject(t, tc, bktName, objName, headers, http.StatusOK)
|
2022-06-01 14:50:30 +00:00
|
|
|
|
|
|
|
var zeroTime time.Time
|
2022-10-04 08:31:09 +00:00
|
|
|
headers = map[string]string{api.IfUnmodifiedSince: zeroTime.UTC().Format(http.TimeFormat)}
|
|
|
|
headObject(t, tc, bktName, objName, headers, http.StatusPreconditionFailed)
|
2022-06-01 14:50:30 +00:00
|
|
|
|
2022-10-04 08:31:09 +00:00
|
|
|
headers = map[string]string{
|
|
|
|
api.IfMatch: etag,
|
|
|
|
api.IfUnmodifiedSince: zeroTime.UTC().Format(http.TimeFormat),
|
|
|
|
}
|
|
|
|
headObject(t, tc, bktName, objName, headers, http.StatusOK)
|
2022-06-01 14:50:30 +00:00
|
|
|
|
2022-10-04 08:31:09 +00:00
|
|
|
headers = map[string]string{api.IfNoneMatch: etag}
|
|
|
|
headObject(t, tc, bktName, objName, headers, http.StatusNotModified)
|
2022-06-01 14:50:30 +00:00
|
|
|
|
2022-10-04 08:31:09 +00:00
|
|
|
headers = map[string]string{api.IfNoneMatch: "etag"}
|
|
|
|
headObject(t, tc, bktName, objName, headers, http.StatusOK)
|
2022-06-01 14:50:30 +00:00
|
|
|
|
2022-10-04 08:31:09 +00:00
|
|
|
headers = map[string]string{api.IfModifiedSince: zeroTime.UTC().Format(http.TimeFormat)}
|
|
|
|
headObject(t, tc, bktName, objName, headers, http.StatusOK)
|
2022-06-01 14:50:30 +00:00
|
|
|
|
2022-10-04 08:31:09 +00:00
|
|
|
headers = map[string]string{api.IfModifiedSince: time.Now().Add(time.Minute).UTC().Format(http.TimeFormat)}
|
|
|
|
headObject(t, tc, bktName, objName, headers, http.StatusNotModified)
|
|
|
|
|
|
|
|
headers = map[string]string{
|
|
|
|
api.IfNoneMatch: etag,
|
|
|
|
api.IfModifiedSince: zeroTime.UTC().Format(http.TimeFormat),
|
|
|
|
}
|
|
|
|
headObject(t, tc, bktName, objName, headers, http.StatusNotModified)
|
|
|
|
}
|
|
|
|
|
|
|
|
func headObject(t *testing.T, tc *handlerContext, bktName, objName string, headers map[string]string, status int) {
|
|
|
|
w, r := prepareTestRequest(tc, bktName, objName, nil)
|
|
|
|
|
|
|
|
for key, val := range headers {
|
|
|
|
r.Header.Set(key, val)
|
|
|
|
}
|
2022-06-01 14:50:30 +00:00
|
|
|
|
|
|
|
tc.Handler().HeadObjectHandler(w, r)
|
2022-10-04 08:31:09 +00:00
|
|
|
assertStatus(t, w, status)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestInvalidAccessThroughCache(t *testing.T) {
|
|
|
|
tc := prepareHandlerContext(t)
|
|
|
|
bktName, objName := "bucket-for-cache", "obj-for-cache"
|
|
|
|
createBucketAndObject(tc, bktName, objName)
|
|
|
|
|
|
|
|
headObject(t, tc, bktName, objName, nil, http.StatusOK)
|
|
|
|
|
|
|
|
w, r := prepareTestRequest(tc, bktName, objName, nil)
|
|
|
|
tc.Handler().HeadObjectHandler(w, r.WithContext(context.WithValue(r.Context(), api.BoxData, newTestAccessBox(t, nil))))
|
|
|
|
assertStatus(t, w, http.StatusForbidden)
|
|
|
|
}
|
|
|
|
|
2023-06-29 12:46:42 +00:00
|
|
|
func TestHeadObject(t *testing.T) {
|
|
|
|
hc := prepareHandlerContextWithMinCache(t)
|
|
|
|
bktName, objName := "bucket", "obj"
|
|
|
|
bktInfo, objInfo := createVersionedBucketAndObject(hc.t, hc, bktName, objName)
|
|
|
|
|
|
|
|
putObject(hc.t, hc, bktName, objName)
|
|
|
|
|
|
|
|
checkFound(hc.t, hc, bktName, objName, objInfo.VersionID())
|
|
|
|
checkFound(hc.t, hc, bktName, objName, emptyVersion)
|
|
|
|
|
|
|
|
addr := getAddressOfLastVersion(hc, bktInfo, objName)
|
|
|
|
hc.tp.SetObjectError(addr, apistatus.ObjectNotFound{})
|
|
|
|
hc.tp.SetObjectError(objInfo.Address(), apistatus.ObjectNotFound{})
|
|
|
|
|
|
|
|
headObjectAssertS3Error(hc, bktName, objName, objInfo.VersionID(), s3errors.ErrNoSuchVersion)
|
|
|
|
headObjectAssertS3Error(hc, bktName, objName, emptyVersion, s3errors.ErrNoSuchKey)
|
|
|
|
}
|
|
|
|
|
2023-02-10 12:19:29 +00:00
|
|
|
func TestIsAvailableToResolve(t *testing.T) {
|
|
|
|
list := []string{"container", "s3"}
|
|
|
|
|
|
|
|
for i, testCase := range [...]struct {
|
|
|
|
isAllowList bool
|
|
|
|
list []string
|
|
|
|
zone string
|
|
|
|
expected bool
|
|
|
|
}{
|
|
|
|
{isAllowList: true, list: list, zone: "container", expected: true},
|
|
|
|
{isAllowList: true, list: list, zone: "sftp", expected: false},
|
|
|
|
{isAllowList: false, list: list, zone: "s3", expected: false},
|
|
|
|
{isAllowList: false, list: list, zone: "system", expected: true},
|
|
|
|
{isAllowList: true, list: list, zone: "", expected: false},
|
|
|
|
} {
|
|
|
|
result := isAvailableToResolve(testCase.zone, testCase.list, testCase.isAllowList)
|
|
|
|
require.Equal(t, testCase.expected, result, "case %d", i+1)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-04 08:31:09 +00:00
|
|
|
func newTestAccessBox(t *testing.T, key *keys.PrivateKey) *accessbox.Box {
|
|
|
|
var err error
|
|
|
|
if key == nil {
|
|
|
|
key, err = keys.NewPrivateKey()
|
|
|
|
require.NoError(t, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
var btoken bearer.Token
|
|
|
|
btoken.SetEACLTable(*eacl.NewTable())
|
|
|
|
err = btoken.Sign(key.PrivateKey)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
return &accessbox.Box{
|
|
|
|
Gate: &accessbox.GateData{
|
|
|
|
BearerToken: &btoken,
|
|
|
|
},
|
|
|
|
}
|
2022-06-01 14:50:30 +00:00
|
|
|
}
|