|
|
@ -28,6 +28,7 @@ import ( |
|
|
|
"sort" |
|
|
|
"sort" |
|
|
|
"strconv" |
|
|
|
"strconv" |
|
|
|
"strings" |
|
|
|
"strings" |
|
|
|
|
|
|
|
"sync" |
|
|
|
"time" |
|
|
|
"time" |
|
|
|
|
|
|
|
|
|
|
|
mux "github.com/gorilla/mux" |
|
|
|
mux "github.com/gorilla/mux" |
|
|
@ -570,14 +571,20 @@ func (api objectAPIHandlers) PutObjectHandler(w http.ResponseWriter, r *http.Req |
|
|
|
case authTypePresigned, authTypeSigned: |
|
|
|
case authTypePresigned, authTypeSigned: |
|
|
|
// Initialize a pipe for data pipe line.
|
|
|
|
// Initialize a pipe for data pipe line.
|
|
|
|
reader, writer := io.Pipe() |
|
|
|
reader, writer := io.Pipe() |
|
|
|
|
|
|
|
var wg = &sync.WaitGroup{} |
|
|
|
// Start writing in a routine.
|
|
|
|
// Start writing in a routine.
|
|
|
|
|
|
|
|
wg.Add(1) |
|
|
|
go func() { |
|
|
|
go func() { |
|
|
|
|
|
|
|
defer wg.Done() |
|
|
|
shaWriter := sha256.New() |
|
|
|
shaWriter := sha256.New() |
|
|
|
multiWriter := io.MultiWriter(shaWriter, writer) |
|
|
|
multiWriter := io.MultiWriter(shaWriter, writer) |
|
|
|
if _, cerr := io.CopyN(multiWriter, r.Body, size); cerr != nil { |
|
|
|
if _, wErr := io.CopyN(multiWriter, r.Body, size); wErr != nil { |
|
|
|
errorIf(cerr, "Unable to read HTTP body.", nil) |
|
|
|
// Pipe closed.
|
|
|
|
writer.CloseWithError(err) |
|
|
|
if wErr == io.ErrClosedPipe { |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
errorIf(wErr, "Unable to read HTTP body.", nil) |
|
|
|
|
|
|
|
writer.CloseWithError(wErr) |
|
|
|
return |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
shaPayload := shaWriter.Sum(nil) |
|
|
|
shaPayload := shaWriter.Sum(nil) |
|
|
@ -588,15 +595,16 @@ func (api objectAPIHandlers) PutObjectHandler(w http.ResponseWriter, r *http.Req |
|
|
|
} else if isRequestPresignedSignatureV4(r) { |
|
|
|
} else if isRequestPresignedSignatureV4(r) { |
|
|
|
s3Error = doesPresignedSignatureMatch(hex.EncodeToString(shaPayload), r, validateRegion) |
|
|
|
s3Error = doesPresignedSignatureMatch(hex.EncodeToString(shaPayload), r, validateRegion) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
var sErr error |
|
|
|
if s3Error != ErrNone { |
|
|
|
if s3Error != ErrNone { |
|
|
|
if s3Error == ErrSignatureDoesNotMatch { |
|
|
|
if s3Error == ErrSignatureDoesNotMatch { |
|
|
|
writer.CloseWithError(errSignatureMismatch) |
|
|
|
sErr = errSignatureMismatch |
|
|
|
return |
|
|
|
} else { |
|
|
|
|
|
|
|
sErr = fmt.Errorf("%v", getAPIError(s3Error)) |
|
|
|
} |
|
|
|
} |
|
|
|
writer.CloseWithError(fmt.Errorf("%v", getAPIError(s3Error))) |
|
|
|
writer.CloseWithError(sErr) |
|
|
|
return |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
// Close the writer.
|
|
|
|
|
|
|
|
writer.Close() |
|
|
|
writer.Close() |
|
|
|
}() |
|
|
|
}() |
|
|
|
|
|
|
|
|
|
|
@ -606,6 +614,10 @@ func (api objectAPIHandlers) PutObjectHandler(w http.ResponseWriter, r *http.Req |
|
|
|
metadata["md5Sum"] = hex.EncodeToString(md5Bytes) |
|
|
|
metadata["md5Sum"] = hex.EncodeToString(md5Bytes) |
|
|
|
// Create object.
|
|
|
|
// Create object.
|
|
|
|
md5Sum, err = api.ObjectAPI.PutObject(bucket, object, size, reader, metadata) |
|
|
|
md5Sum, err = api.ObjectAPI.PutObject(bucket, object, size, reader, metadata) |
|
|
|
|
|
|
|
// Close the pipe.
|
|
|
|
|
|
|
|
reader.Close() |
|
|
|
|
|
|
|
// Wait for all the routines to finish.
|
|
|
|
|
|
|
|
wg.Wait() |
|
|
|
} |
|
|
|
} |
|
|
|
if err != nil { |
|
|
|
if err != nil { |
|
|
|
errorIf(err, "PutObject failed.", nil) |
|
|
|
errorIf(err, "PutObject failed.", nil) |
|
|
@ -710,22 +722,29 @@ func (api objectAPIHandlers) PutObjectPartHandler(w http.ResponseWriter, r *http |
|
|
|
} |
|
|
|
} |
|
|
|
// No need to verify signature, anonymous request access is
|
|
|
|
// No need to verify signature, anonymous request access is
|
|
|
|
// already allowed.
|
|
|
|
// already allowed.
|
|
|
|
partMD5, err = api.ObjectAPI.PutObjectPart(bucket, object, uploadID, partID, size, r.Body, hex.EncodeToString(md5Bytes)) |
|
|
|
hexMD5 := hex.EncodeToString(md5Bytes) |
|
|
|
|
|
|
|
partMD5, err = api.ObjectAPI.PutObjectPart(bucket, object, uploadID, partID, size, r.Body, hexMD5) |
|
|
|
case authTypePresigned, authTypeSigned: |
|
|
|
case authTypePresigned, authTypeSigned: |
|
|
|
validateRegion := true // Validate region.
|
|
|
|
|
|
|
|
// Initialize a pipe for data pipe line.
|
|
|
|
// Initialize a pipe for data pipe line.
|
|
|
|
reader, writer := io.Pipe() |
|
|
|
reader, writer := io.Pipe() |
|
|
|
|
|
|
|
var wg = &sync.WaitGroup{} |
|
|
|
// Start writing in a routine.
|
|
|
|
// Start writing in a routine.
|
|
|
|
|
|
|
|
wg.Add(1) |
|
|
|
go func() { |
|
|
|
go func() { |
|
|
|
|
|
|
|
defer wg.Done() |
|
|
|
shaWriter := sha256.New() |
|
|
|
shaWriter := sha256.New() |
|
|
|
multiWriter := io.MultiWriter(shaWriter, writer) |
|
|
|
multiWriter := io.MultiWriter(shaWriter, writer) |
|
|
|
if _, err = io.CopyN(multiWriter, r.Body, size); err != nil { |
|
|
|
if _, wErr := io.CopyN(multiWriter, r.Body, size); wErr != nil { |
|
|
|
errorIf(err, "Unable to read HTTP body.", nil) |
|
|
|
// Pipe closed, just ignore it.
|
|
|
|
writer.CloseWithError(err) |
|
|
|
if wErr == io.ErrClosedPipe { |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
errorIf(wErr, "Unable to read HTTP body.", nil) |
|
|
|
|
|
|
|
writer.CloseWithError(wErr) |
|
|
|
return |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
shaPayload := shaWriter.Sum(nil) |
|
|
|
shaPayload := shaWriter.Sum(nil) |
|
|
|
|
|
|
|
validateRegion := true // Validate region.
|
|
|
|
var s3Error APIErrorCode |
|
|
|
var s3Error APIErrorCode |
|
|
|
if isRequestSignatureV4(r) { |
|
|
|
if isRequestSignatureV4(r) { |
|
|
|
s3Error = doesSignatureMatch(hex.EncodeToString(shaPayload), r, validateRegion) |
|
|
|
s3Error = doesSignatureMatch(hex.EncodeToString(shaPayload), r, validateRegion) |
|
|
@ -734,10 +753,11 @@ func (api objectAPIHandlers) PutObjectPartHandler(w http.ResponseWriter, r *http |
|
|
|
} |
|
|
|
} |
|
|
|
if s3Error != ErrNone { |
|
|
|
if s3Error != ErrNone { |
|
|
|
if s3Error == ErrSignatureDoesNotMatch { |
|
|
|
if s3Error == ErrSignatureDoesNotMatch { |
|
|
|
writer.CloseWithError(errSignatureMismatch) |
|
|
|
err = errSignatureMismatch |
|
|
|
return |
|
|
|
} else { |
|
|
|
|
|
|
|
err = fmt.Errorf("%v", getAPIError(s3Error)) |
|
|
|
} |
|
|
|
} |
|
|
|
writer.CloseWithError(fmt.Errorf("%v", getAPIError(s3Error))) |
|
|
|
writer.CloseWithError(err) |
|
|
|
return |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
// Close the writer.
|
|
|
|
// Close the writer.
|
|
|
@ -745,6 +765,10 @@ func (api objectAPIHandlers) PutObjectPartHandler(w http.ResponseWriter, r *http |
|
|
|
}() |
|
|
|
}() |
|
|
|
md5SumHex := hex.EncodeToString(md5Bytes) |
|
|
|
md5SumHex := hex.EncodeToString(md5Bytes) |
|
|
|
partMD5, err = api.ObjectAPI.PutObjectPart(bucket, object, uploadID, partID, size, reader, md5SumHex) |
|
|
|
partMD5, err = api.ObjectAPI.PutObjectPart(bucket, object, uploadID, partID, size, reader, md5SumHex) |
|
|
|
|
|
|
|
// Close the pipe.
|
|
|
|
|
|
|
|
reader.Close() |
|
|
|
|
|
|
|
// Wait for all the routines to finish.
|
|
|
|
|
|
|
|
wg.Wait() |
|
|
|
} |
|
|
|
} |
|
|
|
if err != nil { |
|
|
|
if err != nil { |
|
|
|
errorIf(err, "PutObjectPart failed.", nil) |
|
|
|
errorIf(err, "PutObjectPart failed.", nil) |
|
|
|