Skip to content

Commit

Permalink
*: Use chunked according to headers
Browse files Browse the repository at this point in the history
Closes #1009.

The amazon docs https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-streaming.html chunked payload maybe sent without `content-encoding:aws-chunked` header. Meanwhile the header `x-amz-content-sha256:STREAMING-AWS4-HMAC-SHA256-PAYLOAD` still should exists.

Signed-off-by: Evgenii Baidakov <[email protected]>
  • Loading branch information
smallhive committed Sep 30, 2024
1 parent 0eb69b0 commit c6d7474
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 2 deletions.
6 changes: 5 additions & 1 deletion api/auth/center.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,12 @@ const (
AmzSignedHeaders = "X-Amz-SignedHeaders"
AmzExpires = "X-Amz-Expires"
AmzDate = "X-Amz-Date"
AmzContentSha256 = "X-Amz-Content-Sha256"
AuthorizationHdr = "Authorization"
ContentTypeHdr = "Content-Type"
ContentEncodingHdr = "Content-Encoding"
ContentEncodingAwsChunked = "aws-chunked"
ContentEncodingChunked = "STREAMING-AWS4-HMAC-SHA256-PAYLOAD"

timeFormatISO8601 = "20060102T150405Z"
)
Expand Down Expand Up @@ -209,7 +211,9 @@ func (c *center) Authenticate(r *http.Request) (*Box, error) {
return nil, err
}

if hdr := r.Header.Get(ContentEncodingHdr); hdr == ContentEncodingAwsChunked {
amzContent := r.Header.Get(AmzContentSha256)

if contentEncodingHdr := r.Header.Get(ContentEncodingHdr); contentEncodingHdr == ContentEncodingAwsChunked || amzContent == ContentEncodingChunked {
sig, err := hex.DecodeString(authHdr.SignatureV4)
if err != nil {
return nil, fmt.Errorf("DecodeString: %w", err)
Expand Down
8 changes: 7 additions & 1 deletion api/handler/put.go
Original file line number Diff line number Diff line change
Expand Up @@ -224,11 +224,17 @@ func (h *handler) PutObjectHandler(w http.ResponseWriter, r *http.Request) {
return
}

cl, err := contentLengthFromRequest(r)
if err != nil {
h.logAndSendError(w, "content length parse failed", reqInfo, err)
return
}

params := &layer.PutObjectParams{
BktInfo: bktInfo,
Object: reqInfo.ObjectName,
Reader: r.Body,
Size: r.ContentLength,
Size: cl,
Header: metadata,
Encryption: encryptionParams,
CopiesNumber: copiesNumber,
Expand Down
21 changes: 21 additions & 0 deletions api/handler/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package handler
import (
"context"
"errors"
"fmt"
"net/http"
"strconv"
"strings"
Expand All @@ -15,6 +16,10 @@ import (
"go.uber.org/zap"
)

const (
xAmzDecodedContentLength = "X-Amz-Decoded-Content-Length"
)

func (h *handler) logAndSendError(w http.ResponseWriter, logText string, reqInfo *api.ReqInfo, err error, additional ...zap.Field) {
code := api.WriteErrorResponse(w, reqInfo, transformToS3Error(err))
fields := []zap.Field{
Expand Down Expand Up @@ -127,3 +132,19 @@ func getSessionTokenSetEACL(ctx context.Context) (*session.Container, error) {

return sessionToken, nil
}

func contentLengthFromRequest(r *http.Request) (int64, error) {
var (
cl = r.ContentLength
err error
)

if value := r.Header.Get(xAmzDecodedContentLength); value != "" {
cl, err = strconv.ParseInt(value, 10, 64)
if err != nil {
return 0, fmt.Errorf("invalid content length value %q inside %s header", value, xAmzDecodedContentLength)
}
}

return cl, nil
}

0 comments on commit c6d7474

Please sign in to comment.