|
|
|
@ -489,6 +489,84 @@ func TestPutObjectWithStreamEmptyBodyAWSExample(t *testing.T) {
|
|
|
|
|
require.Empty(t, res.Contents[0].Size)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestPutObjectWithStreamEmptyBody(t *testing.T) {
|
|
|
|
|
hc := prepareHandlerContext(t)
|
|
|
|
|
|
|
|
|
|
bktName := "bucket"
|
|
|
|
|
createTestBucket(hc, bktName)
|
|
|
|
|
|
|
|
|
|
t.Run("unsigned", func(t *testing.T) {
|
|
|
|
|
t.Run("trailer", func(t *testing.T) {
|
|
|
|
|
objName := "unsigned trailer"
|
|
|
|
|
|
|
|
|
|
w, req := getEmptyChunkedRequestUnsigned(hc.context, t, bktName, objName)
|
|
|
|
|
req.Header.Del(api.ContentType)
|
|
|
|
|
hc.Handler().PutObjectHandler(w, req)
|
|
|
|
|
assertStatus(t, w, http.StatusOK)
|
|
|
|
|
|
|
|
|
|
d, h := getObject(hc, bktName, objName)
|
|
|
|
|
require.Empty(t, d)
|
|
|
|
|
require.Equal(t, "0", h.Get(api.ContentLength))
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
t.Run("sigv4", func(t *testing.T) {
|
|
|
|
|
t.Run("trailer", func(t *testing.T) {
|
|
|
|
|
objName := "sigv4 trailer"
|
|
|
|
|
|
|
|
|
|
w, req := getEmptyChunkedRequestWithTrailers(hc.context, t, bktName, objName)
|
|
|
|
|
req.Header.Del(api.ContentType)
|
|
|
|
|
hc.Handler().PutObjectHandler(w, req)
|
|
|
|
|
assertStatus(t, w, http.StatusOK)
|
|
|
|
|
|
|
|
|
|
d, h := getObject(hc, bktName, objName)
|
|
|
|
|
require.Empty(t, d)
|
|
|
|
|
require.Equal(t, "0", h.Get(api.ContentLength))
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
t.Run("no trailer", func(t *testing.T) {
|
|
|
|
|
objName := "sigv4 no trailer"
|
|
|
|
|
|
|
|
|
|
w, req := getEmptyChunkedRequest(hc.context, t, bktName, objName)
|
|
|
|
|
req.Header.Del(api.ContentType)
|
|
|
|
|
hc.Handler().PutObjectHandler(w, req)
|
|
|
|
|
assertStatus(t, w, http.StatusOK)
|
|
|
|
|
|
|
|
|
|
d, h := getObject(hc, bktName, objName)
|
|
|
|
|
require.Empty(t, d)
|
|
|
|
|
require.Equal(t, "0", h.Get(api.ContentLength))
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
t.Run("sigv4a", func(t *testing.T) {
|
|
|
|
|
t.Run("trailer", func(t *testing.T) {
|
|
|
|
|
objName := "sigv4a trailer"
|
|
|
|
|
|
|
|
|
|
w, req := getEmptyChunkedRequestSigv4aWithTrailers(hc.context, t, bktName, objName)
|
|
|
|
|
req.Header.Del(api.ContentType)
|
|
|
|
|
hc.Handler().PutObjectHandler(w, req)
|
|
|
|
|
assertStatus(t, w, http.StatusOK)
|
|
|
|
|
|
|
|
|
|
d, h := getObject(hc, bktName, objName)
|
|
|
|
|
require.Empty(t, d)
|
|
|
|
|
require.Equal(t, "0", h.Get(api.ContentLength))
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
t.Run("no trailer", func(t *testing.T) {
|
|
|
|
|
objName := "sigv4a no trailer"
|
|
|
|
|
|
|
|
|
|
w, req := getEmptyChunkedRequestSigv4a(hc.context, t, bktName, objName)
|
|
|
|
|
req.Header.Del(api.ContentType)
|
|
|
|
|
hc.Handler().PutObjectHandler(w, req)
|
|
|
|
|
assertStatus(t, w, http.StatusOK)
|
|
|
|
|
|
|
|
|
|
d, h := getObject(hc, bktName, objName)
|
|
|
|
|
require.Empty(t, d)
|
|
|
|
|
require.Equal(t, "0", h.Get(api.ContentLength))
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestPutChunkedTestContentEncoding(t *testing.T) {
|
|
|
|
|
hc := prepareHandlerContext(t)
|
|
|
|
|
|
|
|
|
@ -818,6 +896,162 @@ func getEmptyChunkedRequest(ctx context.Context, t *testing.T, bktName, objName
|
|
|
|
|
return w, req
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func getEmptyChunkedRequestWithTrailers(ctx context.Context, t *testing.T, bktName, objName string) (*httptest.ResponseRecorder, *http.Request) {
|
|
|
|
|
AWSAccessKeyID := "3jNrmDtHtuj1uLcixaSMA4KNUhNYhv1EpUNdFnbTXgUP071pGdSZfHSLtoC8gzjF5HoD6sC3Scq33t1WvvEvjmPnt"
|
|
|
|
|
AWSSecretAccessKey := "f1a0d650b650149f1a83140418e88a3c5572a0103e912e326492a91c19c4488a"
|
|
|
|
|
|
|
|
|
|
body := "0;chunk-signature=4c066652066847b79395ff24db333006b4300301c92ba2055e14169d74903a59\r\n" +
|
|
|
|
|
"x-amz-checksum-crc32:AAAAAA==\r\n" +
|
|
|
|
|
"x-amz-trailer-signature:2c1dc60c130c889217ae3a9412145202e4999baa54a864d671c1c6967069eaec\r\n\r\n"
|
|
|
|
|
|
|
|
|
|
req, err := http.NewRequest("PUT", "http://localhost:8084/"+bktName+"/"+objName, bytes.NewBufferString(body))
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
req.Header.Set("Amz-Sdk-Invocation-Id", "dc96840e-24bc-9e6c-1c9c-c1e4f616c524")
|
|
|
|
|
req.Header.Set("Amz-Sdk-Request", "attempt=1; max=2")
|
|
|
|
|
req.Header.Set(api.Authorization, "AWS4-HMAC-SHA256 Credential=3jNrmDtHtuj1uLcixaSMA4KNUhNYhv1EpUNdFnbTXgUP071pGdSZfHSLtoC8gzjF5HoD6sC3Scq33t1WvvEvjmPnt/20250213/us-east-1/s3/aws4_request, SignedHeaders=amz-sdk-invocation-id;amz-sdk-request;content-encoding;content-length;content-type;host;x-amz-content-sha256;x-amz-date;x-amz-decoded-content-length;x-amz-sdk-checksum-algorithm;x-amz-trailer, Signature=8de71c9fb6da8156b52c2e52ff2c6bb035fe58996c7e46c403197327760456d7")
|
|
|
|
|
req.Header.Set(api.ContentEncoding, "aws-chunked")
|
|
|
|
|
req.Header.Set(api.ContentLength, "207")
|
|
|
|
|
req.Header.Set(api.ContentType, "text/plain; charset=UTF-8")
|
|
|
|
|
req.Header.Set(api.AmzDate, "20250213T140939Z")
|
|
|
|
|
req.Header.Set(api.AmzContentSha256, api.StreamingContentSHA256Trailer)
|
|
|
|
|
req.Header.Set(api.AmzDecodedContentLength, "0")
|
|
|
|
|
req.Header.Set("X-Amz-Trailer", "x-amz-checksum-crc32")
|
|
|
|
|
req.Header.Set("X-Amz-Sdk-Checksum-Algorithm", "CRC32")
|
|
|
|
|
|
|
|
|
|
signTime, err := time.Parse("20060102T150405Z", req.Header.Get(api.AmzDate))
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
|
|
w := httptest.NewRecorder()
|
|
|
|
|
reqInfo := middleware.NewReqInfo(w, req, middleware.ObjectRequest{Bucket: bktName, Object: objName}, "")
|
|
|
|
|
req = req.WithContext(middleware.SetReqInfo(ctx, reqInfo))
|
|
|
|
|
req = req.WithContext(middleware.SetBox(req.Context(), &middleware.Box{
|
|
|
|
|
ClientTime: signTime,
|
|
|
|
|
AuthHeaders: &middleware.AuthHeader{
|
|
|
|
|
AccessKeyID: AWSAccessKeyID,
|
|
|
|
|
SignatureV4: "8de71c9fb6da8156b52c2e52ff2c6bb035fe58996c7e46c403197327760456d7",
|
|
|
|
|
Region: "us-east-1",
|
|
|
|
|
},
|
|
|
|
|
AccessBox: &accessbox.Box{Gate: &accessbox.GateData{SecretKey: AWSSecretAccessKey}},
|
|
|
|
|
}))
|
|
|
|
|
|
|
|
|
|
return w, req
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func getEmptyChunkedRequestUnsigned(ctx context.Context, t *testing.T, bktName, objName string) (*httptest.ResponseRecorder, *http.Request) {
|
|
|
|
|
AWSAccessKeyID := "3jNrmDtHtuj1uLcixaSMA4KNUhNYhv1EpUNdFnbTXgUP071pGdSZfHSLtoC8gzjF5HoD6sC3Scq33t1WvvEvjmPnt"
|
|
|
|
|
AWSSecretAccessKey := "f1a0d650b650149f1a83140418e88a3c5572a0103e912e326492a91c19c4488a"
|
|
|
|
|
|
|
|
|
|
reqBody := bytes.NewBufferString("0\r\nx-amz-checksum-crc64nvme:AAAAAAAAAAA=\r\n\r\n")
|
|
|
|
|
|
|
|
|
|
req, err := http.NewRequest("PUT", "http://localhost:8084/"+bktName+"/"+objName, reqBody)
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
req.Header.Set(api.Authorization, "AWS4-HMAC-SHA256 Credential=3jNrmDtHtuj1uLcixaSMA4KNUhNYhv1EpUNdFnbTXgUP071pGdSZfHSLtoC8gzjF5HoD6sC3Scq33t1WvvEvjmPnt/20250213/ru/s3/aws4_request, SignedHeaders=content-encoding;host;x-amz-content-sha256;x-amz-date;x-amz-decoded-content-length;x-amz-sdk-checksum-algorithm;x-amz-trailer, Signature=1231b012c0ac313770c5a95ccf77b95b6c9b1c3760d6aa24cb8309801d56eb4a")
|
|
|
|
|
req.Header.Set(api.ContentEncoding, api.AwsChunked)
|
|
|
|
|
req.Header.Set(api.AmzDate, "20250213T124858Z")
|
|
|
|
|
req.Header.Set(api.AmzContentSha256, api.StreamingUnsignedPayloadTrailer)
|
|
|
|
|
req.Header.Set(api.AmzDecodedContentLength, "0")
|
|
|
|
|
req.Header.Set("X-Amz-Trailer", "x-amz-checksum-crc64nvme")
|
|
|
|
|
req.Header.Set("X-Amz-Sdk-Checksum-Algorithm", "CRC64NVME")
|
|
|
|
|
|
|
|
|
|
signTime, err := time.Parse("20060102T150405Z", req.Header.Get(api.AmzDate))
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
|
|
w := httptest.NewRecorder()
|
|
|
|
|
reqInfo := middleware.NewReqInfo(w, req, middleware.ObjectRequest{Bucket: bktName, Object: objName}, "")
|
|
|
|
|
req = req.WithContext(middleware.SetReqInfo(ctx, reqInfo))
|
|
|
|
|
req = req.WithContext(middleware.SetBox(req.Context(), &middleware.Box{
|
|
|
|
|
ClientTime: signTime,
|
|
|
|
|
AuthHeaders: &middleware.AuthHeader{
|
|
|
|
|
AccessKeyID: AWSAccessKeyID,
|
|
|
|
|
SignatureV4: "1231b012c0ac313770c5a95ccf77b95b6c9b1c3760d6aa24cb8309801d56eb4a",
|
|
|
|
|
Region: "ru",
|
|
|
|
|
},
|
|
|
|
|
AccessBox: &accessbox.Box{Gate: &accessbox.GateData{SecretKey: AWSSecretAccessKey}},
|
|
|
|
|
}))
|
|
|
|
|
|
|
|
|
|
return w, req
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func getEmptyChunkedRequestSigv4aWithTrailers(ctx context.Context, t *testing.T, bktName, objName string) (*httptest.ResponseRecorder, *http.Request) {
|
|
|
|
|
AWSAccessKeyID := "3jNrmDtHtuj1uLcixaSMA4KNUhNYhv1EpUNdFnbTXgUP071pGdSZfHSLtoC8gzjF5HoD6sC3Scq33t1WvvEvjmPnt"
|
|
|
|
|
AWSSecretAccessKey := "f1a0d650b650149f1a83140418e88a3c5572a0103e912e326492a91c19c4488a"
|
|
|
|
|
|
|
|
|
|
body := "0;chunk-signature=3046022100ab9229a80d70f4d004768992881821a441a4ad4102e18de567e68216659bf497022100ec47a7a445351683557eedf893e6ed250c97af4b0415814671770b83766d69be\r\n" +
|
|
|
|
|
"x-amz-checksum-crc32:AAAAAA==\r\n" +
|
|
|
|
|
"x-amz-trailer-signature:3046022100a0a66c1adcee8d99460b4631b23c95fbad9eb4e6c56f1afb9e255715ba141169022100b2cfc8adc8036eb985f1ab0e770b575284c5fc8ca75c226558d3142cbaab83ce\r\n\r\n"
|
|
|
|
|
|
|
|
|
|
req, err := http.NewRequest("PUT", "http://localhost:8084/"+bktName+"/"+objName, bytes.NewBufferString(body))
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
req.Header.Set(api.Authorization, "AWS4-ECDSA-P256-SHA256 Credential=3jNrmDtHtuj1uLcixaSMA4KNUhNYhv1EpUNdFnbTXgUP071pGdSZfHSLtoC8gzjF5HoD6sC3Scq33t1WvvEvjmPnt/20250213/s3/aws4_request, SignedHeaders=amz-sdk-invocation-id;amz-sdk-request;content-length;content-type;host;x-amz-content-sha256;x-amz-date;x-amz-decoded-content-length;x-amz-region-set;x-amz-sdk-checksum-algorithm;x-amz-trailer, Signature=304402202e1f1efcc56c588d9a94a3d8f20368686df8bfd5e8aad01fc4eff569ff38f1800220215198e3f1ba785492fe6703c4722872909ce8a09e8c9a13da90a9230c7a24b7")
|
|
|
|
|
req.Header.Set("Amz-Sdk-Invocation-Id", "d42dc16d-7899-55fb-5b72-a654bd482f4f")
|
|
|
|
|
req.Header.Set("Amz-Sdk-Request", "attempt=1; max=2")
|
|
|
|
|
req.Header.Set(api.ContentEncoding, api.AwsChunked)
|
|
|
|
|
req.Header.Set(api.AmzDate, "20250213T132401Z")
|
|
|
|
|
req.Header.Set(api.AmzContentSha256, api.StreamingContentV4aSHA256Trailer)
|
|
|
|
|
req.Header.Set(api.AmzDecodedContentLength, "0")
|
|
|
|
|
req.Header.Set(api.ContentLength, "367")
|
|
|
|
|
req.Header.Set(api.ContentType, "text/plain: charset=UTF-8")
|
|
|
|
|
req.Header.Set("X-Amz-Region-Set", "use-east-1")
|
|
|
|
|
req.Header.Set("X-Amz-Trailer", "x-amz-checksum-crc32")
|
|
|
|
|
req.Header.Set("X-Amz-Sdk-Checksum-Algorithm", "CRC32")
|
|
|
|
|
|
|
|
|
|
signTime, err := time.Parse("20060102T150405Z", req.Header.Get(api.AmzDate))
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
|
|
w := httptest.NewRecorder()
|
|
|
|
|
reqInfo := middleware.NewReqInfo(w, req, middleware.ObjectRequest{Bucket: bktName, Object: objName}, "")
|
|
|
|
|
req = req.WithContext(middleware.SetReqInfo(ctx, reqInfo))
|
|
|
|
|
req = req.WithContext(middleware.SetBox(req.Context(), &middleware.Box{
|
|
|
|
|
ClientTime: signTime,
|
|
|
|
|
AuthHeaders: &middleware.AuthHeader{
|
|
|
|
|
AccessKeyID: AWSAccessKeyID,
|
|
|
|
|
SignatureV4: "304402202e1f1efcc56c588d9a94a3d8f20368686df8bfd5e8aad01fc4eff569ff38f1800220215198e3f1ba785492fe6703c4722872909ce8a09e8c9a13da90a9230c7a24b7",
|
|
|
|
|
Region: "us-east-1",
|
|
|
|
|
},
|
|
|
|
|
AccessBox: &accessbox.Box{Gate: &accessbox.GateData{SecretKey: AWSSecretAccessKey}},
|
|
|
|
|
}))
|
|
|
|
|
|
|
|
|
|
return w, req
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func getEmptyChunkedRequestSigv4a(ctx context.Context, t *testing.T, bktName, objName string) (*httptest.ResponseRecorder, *http.Request) {
|
|
|
|
|
AWSAccessKeyID := "3jNrmDtHtuj1uLcixaSMA4KNUhNYhv1EpUNdFnbTXgUP071pGdSZfHSLtoC8gzjF5HoD6sC3Scq33t1WvvEvjmPnt"
|
|
|
|
|
AWSSecretAccessKey := "f1a0d650b650149f1a83140418e88a3c5572a0103e912e326492a91c19c4488a"
|
|
|
|
|
|
|
|
|
|
body := "0;chunk-signature=304502203f7c598a2e9a6673bf1ca30f5f6bebd0d76a4e9d3c16531448e96c2cda22d16a0221009e7ed578da0a9781366f1461a1484e64f15707f26d4310e59514db6ff9f7e0f1**\r\n\r\n"
|
|
|
|
|
|
|
|
|
|
req, err := http.NewRequest("PUT", "http://localhost:8084/"+bktName+"/"+objName, bytes.NewBufferString(body))
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
req.Header.Set(api.Authorization, "AWS4-ECDSA-P256-SHA256 Credential=3jNrmDtHtuj1uLcixaSMA4KNUhNYhv1EpUNdFnbTXgUP071pGdSZfHSLtoC8gzjF5HoD6sC3Scq33t1WvvEvjmPnt/20250213/s3/aws4_request, SignedHeaders=amz-sdk-invocation-id;amz-sdk-request;content-length;content-type;host;x-amz-content-sha256;x-amz-date;x-amz-decoded-content-length;x-amz-region-set, Signature=3046022100dc589ea513448b996809db4b314a0b8a4a775c1165c6203c7104b2f1aae1243c0221009bf3a256e7c33415eaad20c1dbfb4e14cb00b362758bc4d2aaf94ca96a5f13f9")
|
|
|
|
|
req.Header.Set("Amz-Sdk-Invocation-Id", "f0814a40-0d74-066f-d01f-ed14f28ebfa4")
|
|
|
|
|
req.Header.Set("Amz-Sdk-Request", "attempt=1; max=2")
|
|
|
|
|
req.Header.Set(api.ContentEncoding, api.AwsChunked)
|
|
|
|
|
req.Header.Set(api.AmzDate, "20250213T135717Z")
|
|
|
|
|
req.Header.Set(api.AmzContentSha256, api.StreamingContentV4aSHA256)
|
|
|
|
|
req.Header.Set(api.AmzDecodedContentLength, "0")
|
|
|
|
|
req.Header.Set(api.ContentLength, "166")
|
|
|
|
|
req.Header.Set(api.ContentType, "text/plain: charset=UTF-8")
|
|
|
|
|
req.Header.Set("X-Amz-Region-Set", "use-east-1")
|
|
|
|
|
|
|
|
|
|
signTime, err := time.Parse("20060102T150405Z", req.Header.Get(api.AmzDate))
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
|
|
w := httptest.NewRecorder()
|
|
|
|
|
reqInfo := middleware.NewReqInfo(w, req, middleware.ObjectRequest{Bucket: bktName, Object: objName}, "")
|
|
|
|
|
req = req.WithContext(middleware.SetReqInfo(ctx, reqInfo))
|
|
|
|
|
req = req.WithContext(middleware.SetBox(req.Context(), &middleware.Box{
|
|
|
|
|
ClientTime: signTime,
|
|
|
|
|
AuthHeaders: &middleware.AuthHeader{
|
|
|
|
|
AccessKeyID: AWSAccessKeyID,
|
|
|
|
|
SignatureV4: "3046022100dc589ea513448b996809db4b314a0b8a4a775c1165c6203c7104b2f1aae1243c0221009bf3a256e7c33415eaad20c1dbfb4e14cb00b362758bc4d2aaf94ca96a5f13f9",
|
|
|
|
|
Region: "us-east-1",
|
|
|
|
|
},
|
|
|
|
|
AccessBox: &accessbox.Box{Gate: &accessbox.GateData{SecretKey: AWSSecretAccessKey}},
|
|
|
|
|
}))
|
|
|
|
|
|
|
|
|
|
return w, req
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestCreateBucket(t *testing.T) {
|
|
|
|
|
hc := prepareHandlerContext(t)
|
|
|
|
|
bktName := "bkt-name"
|
|
|
|
|