summaryrefslogtreecommitdiff
path: root/vendor/github.com/minio/minio-go/v7/pkg/signer/request-signature-streaming.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/minio/minio-go/v7/pkg/signer/request-signature-streaming.go')
-rw-r--r--vendor/github.com/minio/minio-go/v7/pkg/signer/request-signature-streaming.go111
1 files changed, 97 insertions, 14 deletions
diff --git a/vendor/github.com/minio/minio-go/v7/pkg/signer/request-signature-streaming.go b/vendor/github.com/minio/minio-go/v7/pkg/signer/request-signature-streaming.go
index b1296d2b1..49e999b01 100644
--- a/vendor/github.com/minio/minio-go/v7/pkg/signer/request-signature-streaming.go
+++ b/vendor/github.com/minio/minio-go/v7/pkg/signer/request-signature-streaming.go
@@ -32,13 +32,17 @@ import (
// Reference for constants used below -
// http://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-streaming.html#example-signature-calculations-streaming
const (
- streamingSignAlgorithm = "STREAMING-AWS4-HMAC-SHA256-PAYLOAD"
- streamingPayloadHdr = "AWS4-HMAC-SHA256-PAYLOAD"
- emptySHA256 = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
- payloadChunkSize = 64 * 1024
- chunkSigConstLen = 17 // ";chunk-signature="
- signatureStrLen = 64 // e.g. "f2ca1bb6c7e907d06dafe4687e579fce76b37e4e93b7605022da52e6ccc26fd2"
- crlfLen = 2 // CRLF
+ streamingSignAlgorithm = "STREAMING-AWS4-HMAC-SHA256-PAYLOAD"
+ streamingSignTrailerAlgorithm = "STREAMING-AWS4-HMAC-SHA256-PAYLOAD-TRAILER"
+ streamingPayloadHdr = "AWS4-HMAC-SHA256-PAYLOAD"
+ streamingTrailerHdr = "AWS4-HMAC-SHA256-TRAILER"
+ emptySHA256 = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+ payloadChunkSize = 64 * 1024
+ chunkSigConstLen = 17 // ";chunk-signature="
+ signatureStrLen = 64 // e.g. "f2ca1bb6c7e907d06dafe4687e579fce76b37e4e93b7605022da52e6ccc26fd2"
+ crlfLen = 2 // CRLF
+ trailerKVSeparator = ":"
+ trailerSignature = "x-amz-trailer-signature"
)
// Request headers to be ignored while calculating seed signature for
@@ -60,7 +64,7 @@ func getSignedChunkLength(chunkDataSize int64) int64 {
}
// getStreamLength - calculates the length of the overall stream (data + metadata)
-func getStreamLength(dataLen, chunkSize int64) int64 {
+func getStreamLength(dataLen, chunkSize int64, trailers http.Header) int64 {
if dataLen <= 0 {
return 0
}
@@ -73,6 +77,15 @@ func getStreamLength(dataLen, chunkSize int64) int64 {
streamLen += getSignedChunkLength(remainingBytes)
}
streamLen += getSignedChunkLength(0)
+ if len(trailers) > 0 {
+ for name, placeholder := range trailers {
+ if len(placeholder) > 0 {
+ streamLen += int64(len(name) + len(trailerKVSeparator) + len(placeholder[0]) + 1)
+ }
+ }
+ streamLen += int64(len(trailerSignature)+len(trailerKVSeparator)) + signatureStrLen + crlfLen + crlfLen
+ }
+
return streamLen
}
@@ -91,18 +104,41 @@ func buildChunkStringToSign(t time.Time, region, previousSig string, chunkData [
return strings.Join(stringToSignParts, "\n")
}
+// buildTrailerChunkStringToSign - returns the string to sign given chunk data
+// and previous signature.
+func buildTrailerChunkStringToSign(t time.Time, region, previousSig string, chunkData []byte) string {
+ stringToSignParts := []string{
+ streamingTrailerHdr,
+ t.Format(iso8601DateFormat),
+ getScope(region, t, ServiceTypeS3),
+ previousSig,
+ hex.EncodeToString(sum256(chunkData)),
+ }
+
+ return strings.Join(stringToSignParts, "\n")
+}
+
// prepareStreamingRequest - prepares a request with appropriate
// headers before computing the seed signature.
func prepareStreamingRequest(req *http.Request, sessionToken string, dataLen int64, timestamp time.Time) {
// Set x-amz-content-sha256 header.
- req.Header.Set("X-Amz-Content-Sha256", streamingSignAlgorithm)
+ if len(req.Trailer) == 0 {
+ req.Header.Set("X-Amz-Content-Sha256", streamingSignAlgorithm)
+ } else {
+ req.Header.Set("X-Amz-Content-Sha256", streamingSignTrailerAlgorithm)
+ for k := range req.Trailer {
+ req.Header.Add("X-Amz-Trailer", strings.ToLower(k))
+ }
+ req.TransferEncoding = []string{"aws-chunked"}
+ }
+
if sessionToken != "" {
req.Header.Set("X-Amz-Security-Token", sessionToken)
}
req.Header.Set("X-Amz-Date", timestamp.Format(iso8601DateFormat))
// Set content length with streaming signature for each chunk included.
- req.ContentLength = getStreamLength(dataLen, int64(payloadChunkSize))
+ req.ContentLength = getStreamLength(dataLen, int64(payloadChunkSize), req.Trailer)
req.Header.Set("x-amz-decoded-content-length", strconv.FormatInt(dataLen, 10))
}
@@ -122,6 +158,16 @@ func buildChunkSignature(chunkData []byte, reqTime time.Time, region,
return getSignature(signingKey, chunkStringToSign)
}
+// buildChunkSignature - returns chunk signature for a given chunk and previous signature.
+func buildTrailerChunkSignature(chunkData []byte, reqTime time.Time, region,
+ previousSignature, secretAccessKey string,
+) string {
+ chunkStringToSign := buildTrailerChunkStringToSign(reqTime, region,
+ previousSignature, chunkData)
+ signingKey := getSigningKey(secretAccessKey, region, reqTime, ServiceTypeS3)
+ return getSignature(signingKey, chunkStringToSign)
+}
+
// getSeedSignature - returns the seed signature for a given request.
func (s *StreamingReader) setSeedSignature(req *http.Request) {
// Get canonical request
@@ -156,10 +202,11 @@ type StreamingReader struct {
chunkNum int
totalChunks int
lastChunkSize int
+ trailer http.Header
}
// signChunk - signs a chunk read from s.baseReader of chunkLen size.
-func (s *StreamingReader) signChunk(chunkLen int) {
+func (s *StreamingReader) signChunk(chunkLen int, addCrLf bool) {
// Compute chunk signature for next header
signature := buildChunkSignature(s.chunkBuf[:chunkLen], s.reqTime,
s.region, s.prevSignature, s.secretAccessKey)
@@ -175,13 +222,40 @@ func (s *StreamingReader) signChunk(chunkLen int) {
s.buf.Write(s.chunkBuf[:chunkLen])
// Write the chunk trailer.
- s.buf.Write([]byte("\r\n"))
+ if addCrLf {
+ s.buf.Write([]byte("\r\n"))
+ }
// Reset chunkBufLen for next chunk read.
s.chunkBufLen = 0
s.chunkNum++
}
+// addSignedTrailer - adds a trailer with the provided headers,
+// then signs a chunk and adds it to output.
+func (s *StreamingReader) addSignedTrailer(h http.Header) {
+ olen := len(s.chunkBuf)
+ s.chunkBuf = s.chunkBuf[:0]
+ for k, v := range h {
+ s.chunkBuf = append(s.chunkBuf, []byte(strings.ToLower(k)+trailerKVSeparator+v[0]+"\n")...)
+ }
+
+ // Compute chunk signature
+ signature := buildTrailerChunkSignature(s.chunkBuf, s.reqTime,
+ s.region, s.prevSignature, s.secretAccessKey)
+
+ // For next chunk signature computation
+ s.prevSignature = signature
+
+ s.buf.Write(s.chunkBuf)
+ s.buf.WriteString("\r\n" + trailerSignature + trailerKVSeparator + signature + "\r\n\r\n")
+
+ // Reset chunkBufLen for next chunk read.
+ s.chunkBuf = s.chunkBuf[:olen]
+ s.chunkBufLen = 0
+ s.chunkNum++
+}
+
// setStreamingAuthHeader - builds and sets authorization header value
// for streaming signature.
func (s *StreamingReader) setStreamingAuthHeader(req *http.Request) {
@@ -222,6 +296,11 @@ func StreamingSignV4(req *http.Request, accessKeyID, secretAccessKey, sessionTok
totalChunks: int((dataLen+payloadChunkSize-1)/payloadChunkSize) + 1,
lastChunkSize: int(dataLen % payloadChunkSize),
}
+ if len(req.Trailer) > 0 {
+ stReader.trailer = req.Trailer
+ // Remove...
+ req.Trailer = nil
+ }
// Add the request headers required for chunk upload signing.
@@ -272,7 +351,7 @@ func (s *StreamingReader) Read(buf []byte) (int, error) {
(s.chunkNum == s.totalChunks-1 &&
s.chunkBufLen == s.lastChunkSize) {
// Sign the chunk and write it to s.buf.
- s.signChunk(s.chunkBufLen)
+ s.signChunk(s.chunkBufLen, true)
break
}
}
@@ -289,7 +368,11 @@ func (s *StreamingReader) Read(buf []byte) (int, error) {
}
// Sign the chunk and write it to s.buf.
- s.signChunk(0)
+ s.signChunk(0, len(s.trailer) == 0)
+ if len(s.trailer) > 0 {
+ // Trailer must be set now.
+ s.addSignedTrailer(s.trailer)
+ }
break
}
return 0, err