use super::*;
impl BucketWarden {
pub fn create_multipart_upload(
&mut self,
principal: &str,
request: CreateMultipartUploadRequest,
lock: ObjectLock,
) -> Result<CreateMultipartUploadResult, RuntimeError> {
if !validate_object_key(&request.key) {
return Err(RuntimeError::InvalidObjectKey(request.key));
}
let resource = object_resource(&request.bucket, &request.key);
self.authorize(principal, S3Action::CreateMultipartUpload, &resource)?;
self.require_bucket(&request.bucket)?;
let upload_id = self.next_upload_id();
self.multipart_uploads.insert(
upload_id.clone(),
MultipartUploadState {
bucket: request.bucket.clone(),
key: request.key.clone(),
metadata: request.metadata,
lock,
initiated_epoch_seconds: self.clock_epoch_seconds,
parts: BTreeMap::new(),
},
);
self.audit_allowed(
principal,
S3Action::CreateMultipartUpload,
&resource,
Some(upload_id.clone()),
);
Ok(CreateMultipartUploadResult {
bucket: request.bucket,
key: request.key,
upload_id,
})
}
pub fn upload_part(
&mut self,
principal: &str,
request: UploadPartRequest,
) -> Result<UploadPartResult, RuntimeError> {
validate_part_number(request.part_number)?;
let resource = object_resource(&request.bucket, &request.key);
self.authorize(principal, S3Action::UploadPart, &resource)?;
let upload = self.multipart_upload(&request.upload_id, &request.bucket, &request.key)?;
let etag = multipart_etag(&request.body);
let checksum_sha256 = sha256_hex(&request.body);
upload.parts.insert(
request.part_number,
MultipartPartState {
etag: etag.clone(),
body: request.body,
checksum_sha256,
},
);
self.audit_allowed(
principal,
S3Action::UploadPart,
&resource,
Some(format!("{}:{}", request.upload_id, request.part_number)),
);
Ok(UploadPartResult {
bucket: request.bucket,
key: request.key,
upload_id: request.upload_id,
part_number: request.part_number,
etag,
})
}
pub fn upload_part_copy(
&mut self,
principal: &str,
source_bucket: &str,
source_key: &str,
source_version_id: Option<&str>,
mut request: UploadPartRequest,
source_range: Option<&str>,
) -> Result<UploadPartResult, RuntimeError> {
validate_part_number(request.part_number)?;
let source_resource = object_resource(source_bucket, source_key);
let destination_resource = object_resource(&request.bucket, &request.key);
self.authorize(principal, S3Action::GetObject, &source_resource)?;
self.authorize(principal, S3Action::UploadPartCopy, &destination_resource)?;
let mut body = {
let source = if let Some(version_id) = source_version_id {
self.version_by_id(source_bucket, source_key, version_id)?
} else {
self.current_version(source_bucket, source_key)?
};
if source.delete_marker {
return Err(RuntimeError::NoSuchKey(object_resource(
source_bucket,
source_key,
)));
}
let source_ciphertext = source.ciphertext.clone();
let source_integrity = source.integrity.clone();
let body = match self.kms.decrypt(&source_ciphertext) {
Ok(body) => body,
Err(error) => {
self.audit_kms_failure(
principal,
"kms:Decrypt",
&source_resource,
&source_ciphertext.key_id,
&error.to_string(),
);
return Err(RuntimeError::Kms(error));
}
};
self.verify_integrity_record(&source_integrity, &body)?;
body
};
if let Some(source_range) = source_range {
let range = parse_copy_source_range(source_range, body.len())?;
body = body[range.start..=range.end].to_vec();
}
request.body = body;
let upload = self.multipart_upload(&request.upload_id, &request.bucket, &request.key)?;
let etag = multipart_etag(&request.body);
let checksum_sha256 = sha256_hex(&request.body);
upload.parts.insert(
request.part_number,
MultipartPartState {
etag: etag.clone(),
body: request.body,
checksum_sha256,
},
);
self.audit_allowed(
principal,
S3Action::UploadPartCopy,
&destination_resource,
Some(format!(
"{}:{}:{}",
source_resource, request.upload_id, request.part_number
)),
);
Ok(UploadPartResult {
bucket: request.bucket,
key: request.key,
upload_id: request.upload_id,
part_number: request.part_number,
etag,
})
}
}