diff --git a/rustfs/src/app/object_usecase.rs b/rustfs/src/app/object_usecase.rs index 125ac82ba..a22f18a7f 100644 --- a/rustfs/src/app/object_usecase.rs +++ b/rustfs/src/app/object_usecase.rs @@ -18,11 +18,9 @@ mod get_object_flow; mod get_object_zero_copy; mod put_object_extract; mod put_object_flow; -mod types; #[cfg(test)] mod zero_copy_tests; use self::get_object_flow::GetObjectBootstrap; -use self::types::*; use crate::app::context::{AppContext, default_notify_interface, get_global_app_context}; use crate::capacity::record_capacity_write; @@ -141,6 +139,34 @@ struct DeadlockRequestGuard { request_id: String, } +#[derive(Clone)] +pub(super) struct GetObjectRequestContext { + pub(super) bucket: String, + pub(super) key: String, + pub(super) part_number: Option, + pub(super) rs: Option, + pub(super) opts: ObjectOptions, + pub(super) headers: HeaderMap, + pub(super) sse_customer_key: Option, + pub(super) sse_customer_key_md5: Option, +} + +pub(super) type PutObjectChecksums = rustfs_object_io::put::PutObjectChecksums; + +#[derive(Clone)] +pub(super) struct PutObjectRequestContext { + pub(super) headers: HeaderMap, + pub(super) trailing_headers: Option, + pub(super) uri_query: Option, + pub(super) is_post_object: bool, + pub(super) method: hyper::Method, + pub(super) uri: hyper::Uri, + pub(super) extensions: http::Extensions, + pub(super) credentials: Option, + pub(super) region: Option, + pub(super) service: Option, +} + impl DeadlockRequestGuard { fn new(deadlock_detector: Arc, request_id: String) -> Self { Self { @@ -315,6 +341,58 @@ fn build_put_object_expiration_header(event: &lifecycle::Event) -> Option) -> S3Result { + let GetObjectInput { + bucket, + key, + version_id, + part_number, + range, + .. + } = req.input.clone(); + + validate_object_key(&key, "GET")?; + + let part_number = part_number.map(|value| value as usize); + if let Some(part_number) = part_number + && part_number == 0 + { + return Err(s3_error!(InvalidArgument, "Invalid part number: part number must be greater than 0")); + } + + let rs = range.map(|value| match value { + Range::Int { first, last } => HTTPRangeSpec { + is_suffix_length: false, + start: first as i64, + end: last.map_or(-1, |last| last as i64), + }, + Range::Suffix { length } => HTTPRangeSpec { + is_suffix_length: true, + start: length as i64, + end: -1, + }, + }); + + if rs.is_some() && part_number.is_some() { + return Err(s3_error!(InvalidArgument, "range and part_number invalid")); + } + + let opts: ObjectOptions = get_opts(&bucket, &key, version_id, part_number, &req.headers) + .await + .map_err(ApiError::from)?; + + Ok(GetObjectRequestContext { + bucket, + key, + part_number, + rs, + opts, + headers: req.headers.clone(), + sse_customer_key: req.input.sse_customer_key.clone(), + sse_customer_key_md5: req.input.sse_customer_key_md5.clone(), + }) +} + #[allow(clippy::too_many_arguments)] fn apply_put_request_metadata( metadata: &mut HashMap, @@ -1065,60 +1143,8 @@ impl DefaultObjectUsecase { _deadlock_request_guard: deadlock_request_guard, } }; - let (request_context, version_id_for_event) = { - let GetObjectInput { - bucket, - key, - version_id, - part_number, - range, - .. - } = req.input.clone(); - - validate_object_key(&key, "GET")?; - - let part_number = part_number.map(|value| value as usize); - if let Some(part_number) = part_number - && part_number == 0 - { - return Err(s3_error!(InvalidArgument, "Invalid part number: part number must be greater than 0")); - } - - let rs = range.map(|value| match value { - Range::Int { first, last } => HTTPRangeSpec { - is_suffix_length: false, - start: first as i64, - end: last.map_or(-1, |last| last as i64), - }, - Range::Suffix { length } => HTTPRangeSpec { - is_suffix_length: true, - start: length as i64, - end: -1, - }, - }); - - if rs.is_some() && part_number.is_some() { - return Err(s3_error!(InvalidArgument, "range and part_number invalid")); - } - - let opts: ObjectOptions = get_opts(&bucket, &key, version_id.clone(), part_number, &req.headers) - .await - .map_err(ApiError::from)?; - - ( - GetObjectRequestContext { - bucket, - key, - part_number, - rs, - opts, - headers: req.headers.clone(), - sse_customer_key: req.input.sse_customer_key.clone(), - sse_customer_key_md5: req.input.sse_customer_key_md5.clone(), - }, - version_id.unwrap_or_default(), - ) - }; + let version_id_for_event = req.input.version_id.clone().unwrap_or_default(); + let request_context = prepare_get_object_request_context(&req).await?; let base_buffer_size = self.base_buffer_size(); let manager = get_concurrency_manager(); let cors_bucket = request_context.bucket.clone(); diff --git a/rustfs/src/app/object_usecase/get_object_flow.rs b/rustfs/src/app/object_usecase/get_object_flow.rs index 98b63d871..c112ff24f 100644 --- a/rustfs/src/app/object_usecase/get_object_flow.rs +++ b/rustfs/src/app/object_usecase/get_object_flow.rs @@ -13,8 +13,8 @@ // limitations under the License. use super::DeadlockRequestGuard; +use super::GetObjectRequestContext; use super::get_object_zero_copy::{GetObjectIoPlanning, GetObjectPreparedRead, prepare_get_object_read_execution}; -use super::types::GetObjectRequestContext; use crate::error::ApiError; use crate::storage::concurrency::{ConcurrencyManager, GetObjectGuard, get_buffer_size_opt_in}; use crate::storage::options::filter_object_metadata; diff --git a/rustfs/src/app/object_usecase/get_object_zero_copy.rs b/rustfs/src/app/object_usecase/get_object_zero_copy.rs index cc05b5b48..bd2bb02ce 100644 --- a/rustfs/src/app/object_usecase/get_object_zero_copy.rs +++ b/rustfs/src/app/object_usecase/get_object_zero_copy.rs @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use super::types::GetObjectRequestContext; +use super::GetObjectRequestContext; use crate::error::ApiError; use crate::storage::concurrency::{self, ConcurrencyManager}; use crate::storage::timeout_wrapper::{RequestTimeoutWrapper, TimeoutConfig}; diff --git a/rustfs/src/app/object_usecase/types.rs b/rustfs/src/app/object_usecase/types.rs deleted file mode 100644 index c7f0288c8..000000000 --- a/rustfs/src/app/object_usecase/types.rs +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2024 RustFS Team -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use super::*; - -#[derive(Clone)] -pub(super) struct GetObjectRequestContext { - pub(super) bucket: String, - pub(super) key: String, - pub(super) part_number: Option, - pub(super) rs: Option, - pub(super) opts: ObjectOptions, - pub(super) headers: HeaderMap, - pub(super) sse_customer_key: Option, - pub(super) sse_customer_key_md5: Option, -} - -pub(super) type PutObjectChecksums = rustfs_object_io::put::PutObjectChecksums; - -#[derive(Clone)] -pub(super) struct PutObjectRequestContext { - pub(super) headers: HeaderMap, - pub(super) trailing_headers: Option, - pub(super) uri_query: Option, - pub(super) is_post_object: bool, - pub(super) method: hyper::Method, - pub(super) uri: hyper::Uri, - pub(super) extensions: http::Extensions, - pub(super) credentials: Option, - pub(super) region: Option, - pub(super) service: Option, -} diff --git a/rustfs/src/app/object_usecase/zero_copy_tests.rs b/rustfs/src/app/object_usecase/zero_copy_tests.rs index 1554dd3d7..fe0701a6e 100644 --- a/rustfs/src/app/object_usecase/zero_copy_tests.rs +++ b/rustfs/src/app/object_usecase/zero_copy_tests.rs @@ -40,58 +40,6 @@ static DIRECT_CHUNK_TEST_ENV: OnceLock<(Vec, Arc)> = OnceLock: static DIRECT_CHUNK_MULTI_DISK_TEST_ENV: OnceLock<(Vec, Arc)> = OnceLock::new(); static DIRECT_CHUNK_TEST_INIT: Once = Once::new(); -async fn prepare_get_object_request_context(req: &S3Request) -> S3Result { - let GetObjectInput { - bucket, - key, - version_id, - part_number, - range, - .. - } = req.input.clone(); - - validate_object_key(&key, "GET")?; - - let part_number = part_number.map(|value| value as usize); - if let Some(part_number) = part_number - && part_number == 0 - { - return Err(s3_error!(InvalidArgument, "Invalid part number: part number must be greater than 0")); - } - - let rs = range.map(|value| match value { - Range::Int { first, last } => HTTPRangeSpec { - is_suffix_length: false, - start: first as i64, - end: last.map_or(-1, |last| last as i64), - }, - Range::Suffix { length } => HTTPRangeSpec { - is_suffix_length: true, - start: length as i64, - end: -1, - }, - }); - - if rs.is_some() && part_number.is_some() { - return Err(s3_error!(InvalidArgument, "range and part_number invalid")); - } - - let opts: ObjectOptions = get_opts(&bucket, &key, version_id.clone(), part_number, &req.headers) - .await - .map_err(ApiError::from)?; - - Ok(GetObjectRequestContext { - bucket, - key, - part_number, - rs, - opts, - headers: req.headers.clone(), - sse_customer_key: req.input.sse_customer_key.clone(), - sse_customer_key_md5: req.input.sse_customer_key_md5.clone(), - }) -} - fn init_direct_chunk_test_tracing() { DIRECT_CHUNK_TEST_INIT.call_once(|| {}); }