From a1f50ad4832345fe0b32c631ef55372b2202c303 Mon Sep 17 00:00:00 2001 From: Ilya Isaev Date: Mon, 13 Jan 2025 17:15:27 +0000 Subject: [PATCH] Add source uri to headers for COPY request --- .../src/s3_crt_client/copy_object.rs | 31 ++++++++++++++++--- mountpoint-s3-crt/src/s3/client.rs | 8 +++++ 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/mountpoint-s3-client/src/s3_crt_client/copy_object.rs b/mountpoint-s3-client/src/s3_crt_client/copy_object.rs index 422c07079..db1727689 100644 --- a/mountpoint-s3-client/src/s3_crt_client/copy_object.rs +++ b/mountpoint-s3-client/src/s3_crt_client/copy_object.rs @@ -1,10 +1,16 @@ use std::ops::Deref; use std::os::unix::prelude::OsStrExt; - +use tracing::trace; use mountpoint_s3_crt::{http::request_response::Header, s3::client::MetaRequestResult}; - +use crate::endpoint_config::EndpointError; use crate::object_client::{CopyObjectError, CopyObjectParams, CopyObjectResult, ObjectClientResult}; -use crate::s3_crt_client::{S3CrtClient, S3Operation, S3RequestError}; +use crate::s3_crt_client::{ConstructionError, S3CrtClient, S3CrtClientInner, S3Operation, S3RequestError}; + +impl From for S3RequestError { + fn from(error: EndpointError) -> Self { + S3RequestError::ConstructionFailure(ConstructionError::InvalidEndpoint(error)) + } +} impl S3CrtClient { /// Create and begin a new CopyObject request. @@ -40,8 +46,23 @@ impl S3CrtClient { destination_key ); - self.inner - .make_simple_http_request(message, S3Operation::CopyObject, span, parse_copy_object_error)? + let mut options = S3CrtClientInner::new_meta_request_options(message, S3Operation::CopyObject); + let endpoint = self.inner.endpoint_config.resolve_for_bucket(source_bucket) + .map_err(|e| S3RequestError::from(e))?; + let uri = endpoint.uri() + .map_err(|e| S3RequestError::from(e))?; + let hostname = uri.host_name().to_str().unwrap(); + let path_prefix = uri.path().to_os_string().into_string().unwrap(); + let port = uri.host_port(); + let hostname_header = if port > 0 { + format!("{}:{}", hostname, port) + } else { + hostname.to_string() + }; + let source_uri = format!("{hostname_header}{path_prefix}/{source_key}"); + trace!(source_uri, "resolved source uri"); + options.copy_source_uri(&source_uri); + self.inner.make_simple_http_request_from_options(options, span, |_| {}, parse_copy_object_error, |_, _| ())? }; let _body = request.await?; diff --git a/mountpoint-s3-crt/src/s3/client.rs b/mountpoint-s3-crt/src/s3/client.rs index 5b94c1c25..670c9c08b 100644 --- a/mountpoint-s3-crt/src/s3/client.rs +++ b/mountpoint-s3-crt/src/s3/client.rs @@ -462,6 +462,14 @@ impl<'a> MetaRequestOptions<'a> { options.inner.send_using_async_writes = send_using_async_writes; self } + + /// Set the URI of source bucket/key for COPY request only + pub fn copy_source_uri(&mut self, source_uri: &str) -> &mut Self { + // SAFETY: we aren't moving out of the struct. + let options = unsafe { Pin::get_unchecked_mut(Pin::as_mut(&mut self.0)) }; + options.inner.copy_source_uri = unsafe { source_uri.as_aws_byte_cursor() }; + self + } } impl Default for MetaRequestOptions<'_> {