Skip to main content

s3_wire/client/multipart/
copy.rs

1use http::{HeaderMap, HeaderName, Method};
2
3use crate::client::S3Client;
4use crate::client::object::{copy_source_header, insert_conditions};
5use crate::client::request::{insert_header, protocol_error};
6use crate::error::S3Error;
7use crate::operation::{UploadPartCopyOutput, UploadPartCopyRequest};
8use crate::protocol::{
9    ParsedS3Error, ProtocolError, UploadPartCopyResponse, parse_upload_part_copy,
10};
11
12use super::headers::request_ids;
13use super::query::upload_part_query;
14
15impl S3Client {
16    /// Uploads one multipart part by copying an existing S3 object or range.
17    ///
18    /// # Errors
19    ///
20    /// Returns an error for invalid headers, transport or service failures,
21    /// malformed bounded XML, embedded S3 errors, or a missing part ETag.
22    pub async fn upload_part_copy(
23        &self,
24        request: UploadPartCopyRequest,
25    ) -> Result<UploadPartCopyOutput, S3Error> {
26        let mut headers = HeaderMap::new();
27        insert_header(
28            &mut headers,
29            HeaderName::from_static("x-amz-copy-source"),
30            &copy_source_header(&request.source),
31        )?;
32        if let Some(range) = request.source_range {
33            insert_header(
34                &mut headers,
35                HeaderName::from_static("x-amz-copy-source-range"),
36                &range.header_value(),
37            )?;
38        }
39        insert_conditions(
40            &mut headers,
41            &request.source_conditions,
42            "x-amz-copy-source-",
43        )?;
44        let target = self.operation_target(Some(request.destination().as_str()))?;
45        let query = upload_part_query(request.part_number().get(), request.upload_id());
46        let deadline = self.deadline();
47        let maximum = self.config().max_xml_response_size();
48        let response = self
49            .send_signed_collected_xml(
50                Method::PUT,
51                target,
52                &query,
53                headers,
54                None,
55                &deadline,
56                maximum,
57                upload_part_copy_embedded_error,
58            )
59            .await?;
60        match parse_upload_part_copy(&response.body, maximum).map_err(protocol_error)? {
61            UploadPartCopyResponse::Complete(result) => Ok(UploadPartCopyOutput {
62                part_number: request.part_number(),
63                e_tag: result.e_tag,
64                last_modified: result.last_modified,
65                checksum: result.checksum,
66                request_ids: request_ids(&response.headers),
67            }),
68            UploadPartCopyResponse::EmbeddedError(_) => {
69                unreachable!("embedded part-copy errors are handled by request execution")
70            }
71        }
72    }
73}
74
75fn upload_part_copy_embedded_error(
76    body: &[u8],
77    maximum: usize,
78) -> Result<Option<ParsedS3Error>, ProtocolError> {
79    match parse_upload_part_copy(body, maximum)? {
80        UploadPartCopyResponse::Complete(_) => Ok(None),
81        UploadPartCopyResponse::EmbeddedError(error) => Ok(Some(error)),
82    }
83}