Skip to content

Commit

Permalink
feat: use multipart metadata
Browse files Browse the repository at this point in the history
  • Loading branch information
jorgehermo9 committed Nov 4, 2024
1 parent bcdc518 commit c207410
Showing 1 changed file with 53 additions and 38 deletions.
91 changes: 53 additions & 38 deletions core/src/services/gcs/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ use reqsign::GoogleToken;
use reqsign::GoogleTokenLoader;
use serde::Deserialize;
use serde::Serialize;
use serde_json::json;

use super::uri::percent_encode_path;
use crate::raw::*;
Expand Down Expand Up @@ -250,19 +249,18 @@ impl GcsCore {
) -> Result<Request<Buffer>> {
let p = build_abs_path(&self.root, path);

let mut metadata = HashMap::new();
if let Some(storage_class) = &self.default_storage_class {
metadata.insert("storageClass", storage_class.as_str());
}
if let Some(cache_control) = op.cache_control() {
metadata.insert("cacheControl", cache_control);
}
let mut request_metadata = InsertRequestMetadata::default();

request_metadata.storage_class = self.default_storage_class.as_ref().map(String::as_str);
request_metadata.cache_control = op.cache_control();
request_metadata.content_type = op.content_type();
request_metadata.metadata = op.user_metadata();

let mut url = format!(
"{}/upload/storage/v1/b/{}/o?uploadType={}&name={}",
self.endpoint,
self.bucket,
if metadata.is_empty() {
if request_metadata.is_empty() {
"media"
} else {
"multipart"
Expand All @@ -276,45 +274,30 @@ impl GcsCore {

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

if let Some(user_metadata) = op.user_metadata() {
for (key, value) in user_metadata {
req = req.header(format!("{X_GOOG_META_PREFIX}{key}"), value)
}
}

req = req.header(CONTENT_LENGTH, size.unwrap_or_default());

if metadata.is_empty() {
if let Some(content_type) = op.content_type() {
req = req.header(CONTENT_TYPE, content_type);
}

if request_metadata.is_empty() {
// If the metadata is empty, we do not set any `Content-Type` header,
// since if we had it in the `op.content_type()`, it would be alrady set in the

Check warning on line 281 in core/src/services/gcs/core.rs

View workflow job for this annotation

GitHub Actions / typos

"alrady" should be "already".
// `multipart` metadata body and this branch won't be executed.
let req = req.body(body).map_err(new_request_build_error)?;
Ok(req)
} else {
let mut multipart = Multipart::new();

multipart = multipart.part(
FormDataPart::new("metadata")
.header(
CONTENT_TYPE,
"application/json; charset=UTF-8".parse().unwrap(),
)
.content(json!(metadata).to_string()),
);

let mut media_part = FormDataPart::new("media").content(body);

if let Some(content_type) = op.content_type() {
media_part = media_part.header(
let metadata_part = FormDataPart::new("metadata")
.header(
CONTENT_TYPE,
content_type
.parse()
.map_err(|_| Error::new(ErrorKind::Unexpected, "invalid header value"))?,
"application/json; charset=UTF-8".parse().unwrap(),
)
.content(
serde_json::to_string(&request_metadata)
.expect("metadata serialization should success"),
);
}
multipart = multipart.part(metadata_part);

let media_part = FormDataPart::new("media").content(body);
multipart = multipart.part(media_part);

let req = multipart.apply(Request::post(url))?;
Ok(req)
}
Expand Down Expand Up @@ -629,6 +612,38 @@ impl GcsCore {
}
}

#[derive(Debug, Serialize)]
#[serde(default, rename_all = "camelCase")]
pub struct InsertRequestMetadata<'a> {
#[serde(skip_serializing_if = "Option::is_none")]
content_type: Option<&'a str>,
#[serde(skip_serializing_if = "Option::is_none")]
storage_class: Option<&'a str>,
#[serde(skip_serializing_if = "Option::is_none")]
cache_control: Option<&'a str>,
#[serde(skip_serializing_if = "Option::is_none")]
metadata: Option<&'a HashMap<String, String>>,
}

impl Default for InsertRequestMetadata<'_> {
fn default() -> Self {
Self {
content_type: None,
storage_class: None,
cache_control: None,
metadata: None,
}
}
}

impl InsertRequestMetadata<'_> {
pub fn is_empty(&self) -> bool {
self.content_type.is_none()
&& self.storage_class.is_none()
&& self.cache_control.is_none()
&& self.metadata.is_none()
}
}
/// Response JSON from GCS list objects API.
///
/// refer to https://cloud.google.com/storage/docs/json_api/v1/objects/list for details
Expand Down

0 comments on commit c207410

Please sign in to comment.