diff --git a/api/handler/put_test.go b/api/handler/put_test.go index 7b92236..d88dab9 100644 --- a/api/handler/put_test.go +++ b/api/handler/put_test.go @@ -294,6 +294,26 @@ func TestPutObjectWithStreamBodyAWSExample(t *testing.T) { } } +func TestPutObjectWithStreamEmptyBodyAWSExample(t *testing.T) { + hc := prepareHandlerContext(t) + + bktName, objName := "dkirillov", "tmp" + createTestBucket(hc, bktName) + + w, req := getEmptyChunkedRequest(hc.context, t, bktName, objName) + hc.Handler().PutObjectHandler(w, req) + assertStatus(t, w, http.StatusOK) + + w, req = prepareTestRequest(hc, bktName, objName, nil) + hc.Handler().HeadObjectHandler(w, req) + assertStatus(t, w, http.StatusOK) + require.Equal(t, "0", w.Header().Get(api.ContentLength)) + + res := listObjectsV1(hc, bktName, "", "", "", -1) + require.Len(t, res.Contents, 1) + require.Empty(t, res.Contents[0].Size) +} + func TestPutChunkedTestContentEncoding(t *testing.T) { hc := prepareHandlerContext(t) @@ -386,6 +406,50 @@ func getChunkedRequest(ctx context.Context, t *testing.T, bktName, objName strin return w, req, chunk } +func getEmptyChunkedRequest(ctx context.Context, t *testing.T, bktName, objName string) (*httptest.ResponseRecorder, *http.Request) { + AWSAccessKeyID := "48c1K4PLVb7SvmV3PjDKEuXaMh8yZMXZ8Wx9msrkKcYw06dZeaxeiPe8vyFm2WsoeVaNt7UWEjNsVkagDs8oX4XXh" + AWSSecretAccessKey := "09260955b4eb0279dc017ba20a1ddac909cbd226c86cbb2d868e55534c8e64b0" + + //awsCreds := credentials.NewStaticCredentials(AWSAccessKeyID, AWSSecretAccessKey, "") + //signer := v4.NewSigner(awsCreds) + + reqBody := bytes.NewBufferString("0;chunk-signature=311a7142c8f3a07972c3aca65c36484b513a8fee48ab7178c7225388f2ae9894\r\n\r\n") + + req, err := http.NewRequest("PUT", "http://localhost:8084/"+bktName+"/"+objName, reqBody) + require.NoError(t, err) + req.Header.Set("Amz-Sdk-Invocation-Id", "8a8cd4be-aef8-8034-f08d-a6144ade41f9") + req.Header.Set("Amz-Sdk-Request", "attempt=1; max=2") + req.Header.Set(api.Authorization, "AWS4-HMAC-SHA256 Credential=48c1K4PLVb7SvmV3PjDKEuXaMh8yZMXZ8Wx9msrkKcYw06dZeaxeiPe8vyFm2WsoeVaNt7UWEjNsVkagDs8oX4XXh/20241003/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, Signature=4b530ab4af2381f214941af591266b209968264a2c94337fa1efc048c7dff352") + req.Header.Set(api.ContentEncoding, "aws-chunked") + req.Header.Set(api.ContentLength, "86") + req.Header.Set(api.ContentType, "text/plain; charset=UTF-8") + req.Header.Set(api.AmzDate, "20241003T100055Z") + req.Header.Set(api.AmzContentSha256, "STREAMING-AWS4-HMAC-SHA256-PAYLOAD") + req.Header.Set(api.AmzDecodedContentLength, "0") + + signTime, err := time.Parse("20060102T150405Z", "20241003T100055Z") + 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: "4b530ab4af2381f214941af591266b209968264a2c94337fa1efc048c7dff352", + 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" diff --git a/api/handler/util.go b/api/handler/util.go index 3665488..7c45560 100644 --- a/api/handler/util.go +++ b/api/handler/util.go @@ -110,17 +110,13 @@ func (h *handler) getPutPayloadSize(r *http.Request) uint64 { decodeContentSize := r.Header.Get(api.AmzDecodedContentLength) decodedSize, err := strconv.Atoi(decodeContentSize) if err != nil { - decodedSize = 0 + if r.ContentLength >= 0 { + return uint64(r.ContentLength) + } + return 0 } - var size uint64 - if decodedSize > 0 { - size = uint64(decodedSize) - } else if r.ContentLength > 0 { - size = uint64(r.ContentLength) - } - - return size + return uint64(decodedSize) } func parseRange(s string) (*layer.RangeParams, error) {