-
Notifications
You must be signed in to change notification settings - Fork 268
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
4e0ba1e
commit 319a7c5
Showing
12 changed files
with
309 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,5 +7,7 @@ copyid | |
deletetype | ||
incrementalcopy | ||
legalhold | ||
missingcontainer | ||
RAGRS | ||
restype | ||
testcontainer |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,69 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
|
||
use crate::{ | ||
models::BlobProperties, pipeline::StorageHeadersPolicy, BlobBlobClientGetPropertiesOptions, | ||
BlobClientOptions, GeneratedBlobClient, | ||
}; | ||
use azure_core::{credentials::TokenCredential, BearerTokenCredentialPolicy, Policy, Result, Url}; | ||
use std::sync::Arc; | ||
|
||
pub struct BlobClient { | ||
endpoint: Url, | ||
container_name: String, | ||
blob_name: String, | ||
client: GeneratedBlobClient, | ||
} | ||
|
||
impl BlobClient { | ||
pub fn new( | ||
endpoint: &str, | ||
container_name: String, | ||
blob_name: String, | ||
credential: Arc<dyn TokenCredential>, | ||
options: Option<BlobClientOptions>, | ||
) -> Result<Self> { | ||
let mut options = options.unwrap_or_default(); | ||
|
||
let storage_headers_policy = Arc::new(StorageHeadersPolicy); | ||
options | ||
.client_options | ||
.per_call_policies | ||
.push(storage_headers_policy); | ||
|
||
let oauth_token_policy = BearerTokenCredentialPolicy::new( | ||
credential.clone(), | ||
["https://storage.azure.com/.default"], | ||
); | ||
options | ||
.client_options | ||
.per_try_policies | ||
.push(Arc::new(oauth_token_policy) as Arc<dyn Policy>); | ||
|
||
let client = GeneratedBlobClient::new(endpoint, credential, Some(options))?; | ||
Ok(Self { | ||
endpoint: endpoint.parse()?, | ||
container_name, | ||
blob_name, | ||
client, | ||
}) | ||
} | ||
|
||
pub fn endpoint(&self) -> &Url { | ||
&self.endpoint | ||
} | ||
|
||
pub async fn get_blob_properties( | ||
&self, | ||
options: Option<BlobBlobClientGetPropertiesOptions<'_>>, | ||
) -> Result<BlobProperties> { | ||
let response = self | ||
.client | ||
.get_blob_blob_client(self.container_name.clone(), self.blob_name.clone()) | ||
.get_properties(options) | ||
.await?; | ||
|
||
let blob_properties: BlobProperties = response.headers().get()?; | ||
Ok(blob_properties) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,3 +4,5 @@ | |
mod blob_client; | ||
mod blob_container_client; | ||
mod blob_service_client; | ||
|
||
pub use blob_client::BlobClient; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
104 changes: 104 additions & 0 deletions
104
sdk/storage/azure_storage_blob/src/models/blob_properties.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
|
||
use azure_core::{ | ||
headers::{ | ||
FromHeaders, HeaderName, Headers, BLOB_ACCESS_TIER, BLOB_TYPE, CREATION_TIME, LEASE_STATE, | ||
LEASE_STATUS, SERVER_ENCRYPTED, | ||
}, | ||
Error, Etag, LeaseStatus, | ||
}; | ||
use typespec_client_core::fmt::SafeDebug; | ||
|
||
use crate::models::{AccessTier, BlobType, LeaseState}; | ||
|
||
pub const CONTENT_LENGTH: HeaderName = HeaderName::from_static("content-length"); | ||
pub const CONTENT_MD5: HeaderName = HeaderName::from_static("content-md5"); | ||
pub const CONTENT_TYPE: HeaderName = HeaderName::from_static("content-type"); | ||
pub const ETAG: HeaderName = HeaderName::from_static("etag"); | ||
pub const LAST_MODIFIED: HeaderName = HeaderName::from_static("last-modified"); | ||
pub const BLOB_ACCESS_TIER_INFERRED: HeaderName = | ||
HeaderName::from_static("x-ms-access-tier-inferred"); | ||
|
||
/// Properties of an Azure Storage blob. | ||
/// | ||
#[derive(Clone, Default, SafeDebug)] | ||
pub struct BlobProperties { | ||
pub access_tier_inferred: Option<bool>, | ||
pub access_tier: Option<AccessTier>, | ||
pub blob_type: Option<BlobType>, | ||
pub content_length: Option<i64>, | ||
pub content_md5: Option<String>, | ||
pub content_type: Option<String>, | ||
pub creation_time: Option<String>, | ||
pub etag: Option<Etag>, | ||
pub last_modified: Option<String>, | ||
pub lease_state: Option<LeaseState>, | ||
pub lease_status: Option<LeaseStatus>, | ||
pub server_encrypted: Option<bool>, | ||
} | ||
|
||
impl FromHeaders for BlobProperties { | ||
type Error = Error; | ||
fn header_names() -> &'static [&'static str] { | ||
&[ | ||
"content-length", | ||
"content-md5", | ||
"content-type", | ||
"etag", | ||
"last-modified", | ||
"x-ms-access-tier-inferred", | ||
"x-ms-access-tier", | ||
"x-ms-blob-type", | ||
"x-ms-creation-time", | ||
"x-ms-lease-state", | ||
"x-ms-lease-status", | ||
"x-ms-server-encrypted", | ||
] | ||
} | ||
|
||
fn from_headers(headers: &Headers) -> Result<Option<Self>, Error> { | ||
let mut properties = BlobProperties { | ||
..Default::default() | ||
}; | ||
|
||
let access_tier_inferred: Option<bool> = | ||
headers.get_optional_as(&BLOB_ACCESS_TIER_INFERRED)?; | ||
properties.access_tier_inferred = access_tier_inferred; | ||
|
||
let access_tier: Option<AccessTier> = headers.get_optional_as(&BLOB_ACCESS_TIER)?; | ||
properties.access_tier = access_tier; | ||
|
||
let blob_type: Option<BlobType> = headers.get_optional_as(&BLOB_TYPE)?; | ||
properties.blob_type = blob_type; | ||
|
||
let content_length: Option<i64> = headers.get_optional_as(&CONTENT_LENGTH)?; | ||
properties.content_length = content_length; | ||
|
||
let content_md5 = headers.get_optional_str(&CONTENT_MD5); | ||
properties.content_md5 = content_md5.map(|s| s.to_string()); | ||
|
||
let content_type = headers.get_optional_str(&CONTENT_TYPE); | ||
properties.content_type = content_type.map(|s| s.to_string()); | ||
|
||
let creation_time = headers.get_optional_str(&CREATION_TIME); | ||
properties.creation_time = creation_time.map(|s| s.to_string()); | ||
|
||
let etag: Option<Etag> = headers.get_optional_as(&ETAG)?; | ||
properties.etag = etag; | ||
|
||
let last_modified = headers.get_optional_str(&LAST_MODIFIED); | ||
properties.last_modified = last_modified.map(|s| s.to_string()); | ||
|
||
let lease_state: Option<LeaseState> = headers.get_optional_as(&LEASE_STATE)?; | ||
properties.lease_state = lease_state; | ||
|
||
let lease_status: Option<LeaseStatus> = headers.get_optional_as(&LEASE_STATUS)?; | ||
properties.lease_status = lease_status; | ||
|
||
let server_encrypted: Option<bool> = headers.get_optional_as(&SERVER_ENCRYPTED)?; | ||
properties.server_encrypted = server_encrypted; | ||
|
||
Ok(Some(properties)) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
|
||
mod blob_properties; | ||
|
||
pub use crate::generated::enums::*; | ||
pub use crate::generated::models::*; | ||
|
||
pub use blob_properties::BlobProperties; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
|
||
mod storage_headers_policy; | ||
|
||
pub use storage_headers_policy::StorageHeadersPolicy; |
31 changes: 31 additions & 0 deletions
31
sdk/storage/azure_storage_blob/src/pipeline/storage_headers_policy.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
|
||
use async_trait::async_trait; | ||
use azure_core::{headers::CLIENT_REQUEST_ID, Context, Policy, PolicyResult, Request}; | ||
use std::sync::Arc; | ||
use uuid::Uuid; | ||
|
||
#[derive(Debug, Clone)] | ||
pub struct StorageHeadersPolicy; | ||
|
||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] | ||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)] | ||
impl Policy for StorageHeadersPolicy { | ||
async fn send( | ||
&self, | ||
ctx: &Context, | ||
request: &mut Request, | ||
next: &[Arc<dyn Policy>], | ||
) -> PolicyResult { | ||
if request | ||
.headers() | ||
.get_optional_string(&CLIENT_REQUEST_ID) | ||
.is_none() | ||
{ | ||
let request_id = Uuid::new_v4().to_string(); | ||
request.insert_header(CLIENT_REQUEST_ID, &request_id); | ||
} | ||
next[0].send(ctx, request, &next[1..]).await | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
|
||
use azure_core_test::recorded; | ||
use azure_identity::DefaultAzureCredential; | ||
use azure_storage_blob::{BlobBlobClientGetPropertiesOptions, BlobClient}; | ||
use std::{env, error::Error}; | ||
|
||
#[recorded::test(live)] | ||
async fn test_get_blob_properties() -> Result<(), Box<dyn Error>> { | ||
// Setup | ||
let storage_account_name = env::var("AZURE_STORAGE_ACCOUNT_NAME") | ||
.expect("Failed to get environment variable: AZURE_STORAGE_ACCOUNT_NAME"); | ||
let endpoint = format!("https://{}.blob.core.windows.net/", storage_account_name); | ||
let credential = DefaultAzureCredential::new()?; | ||
|
||
// Act | ||
let blob_client = BlobClient::new( | ||
&endpoint, | ||
String::from("testcontainer"), | ||
String::from("test_blob.txt"), | ||
credential, | ||
None, | ||
)?; | ||
blob_client | ||
.get_blob_properties(Some(BlobBlobClientGetPropertiesOptions::default())) | ||
.await?; | ||
|
||
// Assert | ||
Ok(()) | ||
} | ||
|
||
#[recorded::test(live)] | ||
async fn test_get_blob_properties_invalid_container() -> Result<(), Box<dyn Error>> { | ||
// Setup | ||
let storage_account_name = env::var("AZURE_STORAGE_ACCOUNT_NAME") | ||
.expect("Failed to get environment variable: AZURE_STORAGE_ACCOUNT_NAME"); | ||
let endpoint = format!("https://{}.blob.core.windows.net/", storage_account_name); | ||
let credential = DefaultAzureCredential::new()?; | ||
|
||
// Act | ||
let blob_client = BlobClient::new( | ||
&endpoint, | ||
String::from("missingcontainer"), | ||
String::from("test_blob.txt"), | ||
credential, | ||
None, | ||
)?; | ||
let response = blob_client | ||
.get_blob_properties(Some(BlobBlobClientGetPropertiesOptions::default())) | ||
.await; | ||
|
||
// Assert | ||
assert_eq!( | ||
String::from("HttpResponse(NotFound, \"ContainerNotFound\")"), | ||
response.unwrap_err().kind().to_string() | ||
); | ||
|
||
Ok(()) | ||
} |