* gets object metadata and deletes object * @param {AuthInfo} authInfo - Instance of AuthInfo class with requester's info * @param {string} canonicalID - canonicalId of requester * @param {object} request - http request * @param {string} bucketName - bucketName * @param {BucketInfo} bucket - bucket
(authInfo, canonicalID, request,
bucketName, bucket, quietSetting, errorResults, inPlay, log, next)
| 249 | * successfullyDeleted, totalContentLengthDeleted) |
| 250 | */ |
| 251 | function getObjMetadataAndDelete(authInfo, canonicalID, request, |
| 252 | bucketName, bucket, quietSetting, errorResults, inPlay, log, next) { |
| 253 | const successfullyDeleted = []; |
| 254 | let totalContentLengthDeleted = 0; |
| 255 | let numOfObjectsRemoved = 0; |
| 256 | const skipError = new Error('skip'); |
| 257 | const objectLockedError = new Error('object locked'); |
| 258 | let deleteFromStorage = []; |
| 259 | |
| 260 | // Initialize the queue for internal log request logging before concurrent execution |
| 261 | initializeInternalLogRequestQueue(request); |
| 262 | |
| 263 | return async.waterfall([ |
| 264 | callback => initializeMultiObjectDeleteWithBatchingSupport(bucketName, inPlay, log, callback), |
| 265 | (cache, callback) => async.forEachLimit(inPlay, config.multiObjectDeleteConcurrency, (entry, moveOn) => { |
| 266 | async.waterfall([ |
| 267 | callback => callback(...decodeObjectVersion(entry, bucketName)), |
| 268 | // for obj deletes, no need to check acl's at object level |
| 269 | // (authority is at the bucket level for obj deletes) |
| 270 | (versionId, callback) => metadataUtils.metadataGetObject(bucketName, entry.key, |
| 271 | versionId, cache, log, (err, objMD) => callback(err, objMD, versionId)), |
| 272 | (objMD, versionId, callback) => { |
| 273 | if (!objMD) { |
| 274 | const verCfg = bucket.getVersioningConfiguration(); |
| 275 | // To adhere to AWS behavior, create a delete marker |
| 276 | // if trying to delete an object that does not exist |
| 277 | // when versioning has been configured |
| 278 | if (verCfg && !entry.versionId) { |
| 279 | log.debug('trying to delete specific version ' + |
| 280 | 'that does not exist'); |
| 281 | return callback(null, objMD, versionId); |
| 282 | } |
| 283 | // otherwise if particular key does not exist, AWS |
| 284 | // returns success for key so add to successfullyDeleted |
| 285 | // list and move on |
| 286 | successfullyDeleted.push({ entry }); |
| 287 | return callback(skipError); |
| 288 | } |
| 289 | if (versionId && objMD.location && |
| 290 | Array.isArray(objMD.location) && objMD.location[0]) { |
| 291 | // we need this information for data deletes to AWS |
| 292 | // eslint-disable-next-line no-param-reassign |
| 293 | objMD.location[0].deleteVersion = true; |
| 294 | } |
| 295 | return callback(null, objMD, versionId); |
| 296 | }, |
| 297 | (objMD, versionId, callback) => { |
| 298 | // AWS only returns an object lock error if a version id |
| 299 | // is specified, else continue to create a delete marker |
| 300 | if (!versionId || !bucket.isObjectLockEnabled()) { |
| 301 | return callback(null, null, objMD, versionId); |
| 302 | } |
| 303 | const hasGovernanceBypass = hasGovernanceBypassHeader(request.headers); |
| 304 | if (hasGovernanceBypass && isRequesterNonAccountUser(authInfo)) { |
| 305 | return checkUserGovernanceBypass(request, authInfo, bucket, entry.key, log, error => { |
| 306 | if (error && error.is.AccessDenied) { |
| 307 | log.debug('user does not have BypassGovernanceRetention and object is locked', |
| 308 | { error }); |
no test coverage detected