Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 21 additions & 3 deletions core/services/cos/src/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,16 @@ impl CosCore {
req = req.header(CACHE_CONTROL, cache_control)
}

// COS evaluates x-cos-forbid-overwrite on both InitiateMultipartUpload and
// CompleteMultipartUpload, so a multipart if_not_exists write has to carry it
// on both requests. Setting it only on the simple PutObject path lets large
// uploads silently overwrite an existing object.
//
// ref: https://www.tencentcloud.com/document/product/436/7746
if args.if_not_exists() {
req = req.header("x-cos-forbid-overwrite", "true");
}

// Set user metadata headers.
if let Some(user_metadata) = args.user_metadata() {
for (key, value) in user_metadata {
Expand Down Expand Up @@ -504,6 +514,7 @@ impl CosCore {
path: &str,
upload_id: &str,
parts: Vec<CompleteMultipartUploadRequestPart>,
args: &OpWrite,
) -> Result<Response<Buffer>> {
let p = build_abs_path(&self.root, path);

Expand All @@ -514,14 +525,21 @@ impl CosCore {
percent_encode_path(upload_id)
);

let req = Request::post(&url);
let mut req = Request::post(&url);

let content = quick_xml::se::to_string(&CompleteMultipartUploadRequest { part: parts })
.map_err(new_xml_serialize_error)?;
// Make sure content length has been set to avoid post with chunked encoding.
let req = req.header(CONTENT_LENGTH, content.len());
req = req.header(CONTENT_LENGTH, content.len());
// Set content-type to `application/xml` to avoid mixed with form post.
let req = req.header(CONTENT_TYPE, "application/xml");
req = req.header(CONTENT_TYPE, "application/xml");
// CompleteMultipartUpload is the request that commits the object, so the
// if_not_exists guard has to be repeated here alongside InitiateMultipartUpload.
//
// ref: https://www.tencentcloud.com/document/product/436/7742
if args.if_not_exists() {
req = req.header("x-cos-forbid-overwrite", "true");
}

let req = req
.extension(Operation::Write)
Expand Down
2 changes: 1 addition & 1 deletion core/services/cos/src/writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ impl oio::MultipartWrite for CosWriter {

let mut resp = self
.core
.cos_complete_multipart_upload(&self.ctx, &self.path, upload_id, parts)
.cos_complete_multipart_upload(&self.ctx, &self.path, upload_id, parts, &self.op)
.await?;

let mut meta = Self::parse_metadata(resp.headers())?;
Expand Down
Loading