* PUT part of object during a multipart upload. Steps include: * validating metadata for authorization, bucket existence * and multipart upload initiation existence, * store object data in datastore upon successful authorization, * store object location returned by datastore in metadata and * r
(authInfo, request, streamingV4Params, log,
cb)
| 59 | * @return {undefined} |
| 60 | */ |
| 61 | function objectPutPart(authInfo, request, streamingV4Params, log, |
| 62 | cb) { |
| 63 | log.debug('processing request', { method: 'objectPutPart' }); |
| 64 | const size = request.parsedContentLength; |
| 65 | |
| 66 | const putVersionId = request.headers['x-scal-s3-version-id']; |
| 67 | const isPutVersion = putVersionId || putVersionId === ''; |
| 68 | |
| 69 | if (Number.parseInt(size, 10) > constants.maximumAllowedPartSize) { |
| 70 | log.debug('put part size too large', { size }); |
| 71 | monitoring.promMetrics('PUT', request.bucketName, 400, |
| 72 | 'putObjectPart'); |
| 73 | return cb(errors.EntityTooLarge); |
| 74 | } |
| 75 | |
| 76 | const checksumHeaderErr = validateChecksumHeaders(request.headers); |
| 77 | if (checksumHeaderErr) { |
| 78 | return cb(checksumHeaderErr); |
| 79 | } |
| 80 | |
| 81 | // Note: Part sizes cannot be less than 5MB in size except for the last. |
| 82 | // However, we do not check this value here because we cannot know which |
| 83 | // part will be the last until a complete MPU request is made. Thus, we let |
| 84 | // the completeMultipartUpload API check that all parts except the last are |
| 85 | // at least 5MB. |
| 86 | |
| 87 | const partNumber = Number.parseInt(request.query.partNumber, 10); |
| 88 | // AWS caps partNumbers at 10,000 |
| 89 | if (partNumber > 10000) { |
| 90 | monitoring.promMetrics('PUT', request.bucketName, 400, |
| 91 | 'putObjectPart'); |
| 92 | return cb(errors.TooManyParts); |
| 93 | } |
| 94 | if (!Number.isInteger(partNumber) || partNumber < 1) { |
| 95 | monitoring.promMetrics('PUT', request.bucketName, 400, |
| 96 | 'putObjectPart'); |
| 97 | return cb(errors.InvalidArgument); |
| 98 | } |
| 99 | const bucketName = request.bucketName; |
| 100 | assert.strictEqual(typeof bucketName, 'string'); |
| 101 | const canonicalID = authInfo.getCanonicalID(); |
| 102 | assert.strictEqual(typeof canonicalID, 'string'); |
| 103 | log.trace('owner canonicalid to send to data', { |
| 104 | canonicalID: authInfo.getCanonicalID, |
| 105 | }); |
| 106 | // Note that keys in the query object retain their case, so |
| 107 | // `request.query.uploadId` must be called with that exact capitalization. |
| 108 | const { query: { uploadId } } = request; |
| 109 | const mpuBucketName = `${constants.mpuBucketPrefix}${bucketName}`; |
| 110 | const { objectKey } = request; |
| 111 | const originalIdentityAuthzResults = request.actionImplicitDenies; |
| 112 | // For validating the request at the destinationBucket level the |
| 113 | // `requestType` is the general 'objectPut'. |
| 114 | const requestType = request.apiMethods || 'objectPutPart'; |
| 115 | |
| 116 | return async.waterfall([ |
| 117 | // Get the destination bucket. |
| 118 | next => metadata.getBucket(bucketName, log, |
no test coverage detected