diff --git a/core/src/services/azblob/core.rs b/core/src/services/azblob/core.rs index 235f99550496..00bbc63e3ae1 100644 --- a/core/src/services/azblob/core.rs +++ b/core/src/services/azblob/core.rs @@ -15,8 +15,11 @@ // specific language governing permissions and limitations // under the License. +use base64::prelude::BASE64_STANDARD; +use base64::Engine; use bytes::Bytes; use http::header::HeaderName; + use http::header::CONTENT_LENGTH; use http::header::CONTENT_TYPE; use http::header::IF_MATCH; @@ -27,7 +30,7 @@ use http::Response; use reqsign::AzureStorageCredential; use reqsign::AzureStorageLoader; use reqsign::AzureStorageSigner; -use serde::Deserialize; +use serde::{Deserialize, Serialize}; use std::fmt; use std::fmt::Debug; use std::fmt::Formatter; @@ -449,20 +452,17 @@ impl AzblobCore { "BlockBlob", ); - // Set body - // refer to https://learn.microsoft.com/en-us/rest/api/storageservices/put-block-list? - let req_body = { - let block_list = block_ids - .iter() - .map(|block_id| format!(" {}", block_id)) - .collect::>() - .join("\n"); - - format!("\n{}\n", block_list) - }; + let content = quick_xml::se::to_string(&PutBlockListRequest { + uncommitted: block_ids + .into_iter() + .map(|block_id| BASE64_STANDARD.encode(block_id)) + .collect(), + }) + .map_err(new_xml_deserialize_error)?; + let req = req + .body(AsyncBody::Bytes(Bytes::from(content))) + .map_err(new_request_build_error)?; - let body = AsyncBody::Bytes(Bytes::from(req_body)); - let req = req.body(body).map_err(new_request_build_error)?; Ok(req) } @@ -643,6 +643,13 @@ impl AzblobCore { } } +/// Request of CompleteMultipartUploadRequest +#[derive(Default, Debug, Serialize)] +#[serde(default, rename = "", rename_all = "PascalCase")] +pub struct PutBlockListRequest { + pub uncommitted: Vec, +} + #[derive(Default, Debug, Deserialize)] #[serde(default, rename_all = "PascalCase")] pub struct ListBlobsOutput { @@ -871,4 +878,27 @@ mod tests { de::from_reader(Bytes::from(bs).reader()).expect("must success") } + + /// This example is from https://learn.microsoft.com/en-us/rest/api/storageservices/put-block-list?tabs=microsoft-entra-id + #[test] + fn test_serialize_put_block_list_request() { + let req = PutBlockListRequest { + uncommitted: vec!["1".to_string(), "2".to_string(), "3".to_string()], + }; + + let actual = quick_xml::se::to_string(&req).expect("must succeed"); + + pretty_assertions::assert_eq!( + actual, + r#" + 1 + 2 + 3 + "# + // Cleanup space and new line + .replace([' ', '\n'], "") + // Escape `"` by hand to address + .replace('"', """) + ) + } }