From 51a9d1bdb7f5fcc6d4f74b9f9ccc7f5aef19fab6 Mon Sep 17 00:00:00 2001 From: Harshavardhana Date: Sun, 23 Feb 2020 09:06:46 +0530 Subject: [PATCH] Avoid unnecessary allocations for XML parsing (#9017) --- cmd/bucket-handlers.go | 16 ++++++++-------- cmd/object-handlers.go | 17 +++++++++-------- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/cmd/bucket-handlers.go b/cmd/bucket-handlers.go index 53c507726..14c018c0b 100644 --- a/cmd/bucket-handlers.go +++ b/cmd/bucket-handlers.go @@ -342,13 +342,6 @@ func (api objectAPIHandlers) DeleteMultipleObjectsHandler(w http.ResponseWriter, return } - // Content-Length is required and should be non-zero - // http://docs.aws.amazon.com/AmazonS3/latest/API/multiobjectdeleteapi.html - if r.ContentLength <= 0 { - writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrMissingContentLength), r.URL, guessIsBrowserReq(r)) - return - } - // Content-Md5 is requied should be set // http://docs.aws.amazon.com/AmazonS3/latest/API/multiobjectdeleteapi.html if _, ok := r.Header[xhttp.ContentMD5]; !ok { @@ -356,6 +349,13 @@ func (api objectAPIHandlers) DeleteMultipleObjectsHandler(w http.ResponseWriter, return } + // Content-Length is required and should be non-zero + // http://docs.aws.amazon.com/AmazonS3/latest/API/multiobjectdeleteapi.html + if r.ContentLength <= 0 { + writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrMissingContentLength), r.URL, guessIsBrowserReq(r)) + return + } + // The max. XML contains 100000 object names (each at most 1024 bytes long) + XML overhead const maxBodySize = 2 * 100000 * 1024 @@ -363,7 +363,7 @@ func (api objectAPIHandlers) DeleteMultipleObjectsHandler(w http.ResponseWriter, deleteObjects := &DeleteObjectsRequest{} if err := xmlDecoder(r.Body, deleteObjects, maxBodySize); err != nil { logger.LogIf(ctx, err, logger.Application) - writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrMalformedXML), r.URL, guessIsBrowserReq(r)) + writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } diff --git a/cmd/object-handlers.go b/cmd/object-handlers.go index dc0204b41..41c94e696 100644 --- a/cmd/object-handlers.go +++ b/cmd/object-handlers.go @@ -24,7 +24,6 @@ import ( "encoding/hex" "encoding/xml" "io" - goioutil "io/ioutil" "net/http" "net/url" "sort" @@ -2331,12 +2330,19 @@ func (api objectAPIHandlers) CompleteMultipartUploadHandler(w http.ResponseWrite return } + // Content-Length is required and should be non-zero + if r.ContentLength <= 0 { + writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrMissingContentLength), r.URL, guessIsBrowserReq(r)) + return + } + // Reject retention or governance headers if set, CompleteMultipartUpload spec // does not use these headers, and should not be passed down to checkPutObjectLockAllowed if objectlock.IsObjectLockRequested(r.Header) || objectlock.IsObjectLockGovernanceBypassSet(r.Header) { writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrInvalidRequest), r.URL, guessIsBrowserReq(r)) return } + // Enforce object lock governance in case a competing upload finalized first. retPerms := isPutActionAllowed(getRequestAuthType(r), bucket, object, r, iampolicy.PutObjectRetentionAction) holdPerms := isPutActionAllowed(getRequestAuthType(r), bucket, object, r, iampolicy.PutObjectLegalHoldAction) @@ -2353,14 +2359,9 @@ func (api objectAPIHandlers) CompleteMultipartUploadHandler(w http.ResponseWrite return } - completeMultipartBytes, err := goioutil.ReadAll(r.Body) - if err != nil { - writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) - return - } complMultipartUpload := &CompleteMultipartUpload{} - if err = xml.Unmarshal(completeMultipartBytes, complMultipartUpload); err != nil { - writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrMalformedXML), r.URL, guessIsBrowserReq(r)) + if err = xmlDecoder(r.Body, complMultipartUpload, r.ContentLength); err != nil { + writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return } if len(complMultipartUpload.Parts) == 0 {