Skip to content

Commit

Permalink
feat(core): add content_encoding to OpWrite
Browse files Browse the repository at this point in the history
  • Loading branch information
Frank-III committed Dec 4, 2024
1 parent 311097c commit c3bedc6
Show file tree
Hide file tree
Showing 7 changed files with 75 additions and 2 deletions.
12 changes: 12 additions & 0 deletions core/src/raw/ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -575,6 +575,7 @@ pub struct OpWrite {
concurrent: usize,
content_type: Option<String>,
content_disposition: Option<String>,
content_encoding: Option<String>,
cache_control: Option<String>,
executor: Option<Executor>,
if_match: Option<String>,
Expand Down Expand Up @@ -632,6 +633,17 @@ impl OpWrite {
self
}

/// Get the content encoding from option
pub fn content_encoding(&self) -> Option<&str> {
self.content_encoding.as_deref()
}

/// Set the content encoding of option
pub fn with_content_encoding(mut self, content_encoding: &str) -> Self {
self.content_encoding = Some(content_encoding.to_string());
self
}

/// Get the cache control from option
pub fn cache_control(&self) -> Option<&str> {
self.cache_control.as_deref()
Expand Down
1 change: 1 addition & 0 deletions core/src/services/s3/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -931,6 +931,7 @@ impl Access for S3Backend {
write_can_multi: true,
write_with_cache_control: true,
write_with_content_type: true,
write_with_content_encoding: true,
write_with_if_match: !self.core.disable_write_with_if_match,
write_with_if_not_exists: true,
write_with_user_metadata: true,
Expand Down
5 changes: 5 additions & 0 deletions core/src/services/s3/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ use constants::X_AMZ_META_PREFIX;
use http::header::HeaderName;
use http::header::CACHE_CONTROL;
use http::header::CONTENT_DISPOSITION;
use http::header::CONTENT_ENCODING;
use http::header::CONTENT_LENGTH;
use http::header::CONTENT_TYPE;
use http::header::HOST;
Expand Down Expand Up @@ -448,6 +449,10 @@ impl S3Core {
req = req.header(CONTENT_TYPE, mime)
}

if let Some(encoding) = args.content_encoding() {
req = req.header(CONTENT_ENCODING, encoding);
}

if let Some(pos) = args.content_disposition() {
req = req.header(CONTENT_DISPOSITION, pos)
}
Expand Down
2 changes: 2 additions & 0 deletions core/src/types/capability.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,8 @@ pub struct Capability {
pub write_with_content_type: bool,
/// Indicates if Content-Disposition can be specified during write operations.
pub write_with_content_disposition: bool,
/// Indicates if Content-Encoding can be specified during write operations.
pub write_with_content_encoding: bool,
/// Indicates if Cache-Control can be specified during write operations.
pub write_with_cache_control: bool,
/// Indicates if conditional write operations using If-Match are supported.
Expand Down
33 changes: 31 additions & 2 deletions core/src/types/operator/operator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1414,9 +1414,38 @@ impl Operator {
/// # }
/// ```
///
/// ## `if_none_match`
/// ## `content_encoding`
///
/// Sets Content-Encoding header for this write request.
///
/// ### Capability
///
/// Check [`Capability::write_with_content_encoding`] before using this feature.
///
/// ### Behavior
///
/// - If supported, sets Content-Encoding as system metadata on the target file
/// - The value should follow HTTP Content-Encoding header format
/// - If not supported, the value will be ignored
///
/// This operation allows specifying the content encoding for the written content.
///
/// ## Example
///
/// Sets an `if none match` condition with specified ETag for this write request.
/// ```no_run
/// # use opendal::Result;
/// # use opendal::Operator;
/// use bytes::Bytes;
/// # async fn test(op: Operator) -> Result<()> {
/// let _ = op
/// .write_with("path/to/file", bs)
/// .content_encoding("br")
/// .await?;
/// # Ok(())
/// # }
/// ```
///
/// ## `if_none_match`
///
/// ### Capability
///
Expand Down
5 changes: 5 additions & 0 deletions core/src/types/operator/operator_futures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,11 @@ impl<F: Future<Output = Result<()>>> FutureWrite<F> {
self.map(|(args, options, bs)| (args.with_content_disposition(v), options, bs))
}

/// Set the content encoding of option
pub fn content_encoding(self, v: &str) -> Self {
self.map(|(args, options, bs)| (args.with_content_encoding(v), options, bs))
}

/// Set the executor for this operation.
pub fn executor(self, executor: Executor) -> Self {
self.map(|(args, options, bs)| (args.with_executor(executor), options, bs))
Expand Down
19 changes: 19 additions & 0 deletions core/tests/behavior/async_write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ pub fn tests(op: &Operator, tests: &mut Vec<Trial>) {
test_write_with_cache_control,
test_write_with_content_type,
test_write_with_content_disposition,
test_write_with_content_encoding,
test_write_with_if_none_match,
test_write_with_if_not_exists,
test_write_with_if_match,
Expand Down Expand Up @@ -211,6 +212,24 @@ pub async fn test_write_with_content_disposition(op: Operator) -> Result<()> {
Ok(())
}

/// Write a single file with content encoding should succeed.
pub async fn test_write_with_content_encoding(op: Operator) -> Result<()> {
if !op.info().full_capability().write_with_content_encoding {
return Ok(());
}

let (path, content, size) = TEST_FIXTURE.new_file(op.clone());

let target_content_encoding = "gzip";
op.write_with(&path, content)
.content_encoding(target_content_encoding)
.await?;

// TODO: check the content encoding in the stat op response?

Ok(())
}

/// write a single file with user defined metadata should succeed.
pub async fn test_write_with_user_metadata(op: Operator) -> Result<()> {
if !op.info().full_capability().write_with_user_metadata {
Expand Down

0 comments on commit c3bedc6

Please sign in to comment.