Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion sdk/core/azure_core/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,23 @@

### Features Added

- Added `RawResponse` to `ErrorKind::HttpResponse` that contains the HTTP status code, headers, and complete error response body.
- Added `RequestContent::from_slice()`.
- Added `TryFrom<T> for RequestContent<T, JsonFormat>` for JSON primitives.
- Added support for WASM to the `async_runtime` module.
- Added logging policy to log HTTP requests and responses in the pipeline. As a part of this change, sanitization support was added to places which log HTTP headers and URLs. The `azure_core::http::ClientOptions` has been enhanced with a `LoggingOptions` which allows a user/service client to specify headers or URL query parameters which should be allowed. Note that the sanitization feature is disabled if you build with the `debug` feature enabled.

### Breaking Changes

- Added the ability to configure pipeline configuration independently from `ClientOptions`. This adds a new optional `PipelineOptions` parameter to `azure_core::http::Pipeline::new()`. If not specified, it defaults to the expected options for `azure_core` services.
- Changed `FromStr for RequestContent<T, F>` to `RequestContent::from_str()`.
- Changed `TryFrom<&'static str> for RequestContent<T, F>` to `RequestContent::from_static()`.
- Changed `TryFrom<Bytes> for RequestContent<T, F>` to `From<Bytes> for RequestContent<T, F>` because it was already infallible.
- Removed `TryFrom<Vec<u8>> for RequestContent<T, F>` since `RequestContent::from()` already exists.
- Removed feature `reqwest_rustls_tls`. See [README.md](https://github.com/heaths/azure-sdk-for-rust/blob/main/sdk/core/azure_core/README.md) for alternative HTTP client configuration.
- Removed the `fs` module including the `FileStream` and `FileStreamBuilder` types. Moved to `examples/` for `typespec_client_core` to copy if needed.
- Removed the `setters` macro.
- Added the ability to configure pipeline configuration independently from `ClientOptions`. This adds a new optional `PipelineOptions` parameter to `azure_core::http::Pipeline::new()`. If not specified, it defaults to the expected options for `azure_core` services.
- Renamed `RawResponse` to `BufResponse`. New `RawResponse` contains complete body as `Bytes` used in `ErrorKind::HttpResponse`.

## 0.27.0 (2025-08-01)

Expand Down
4 changes: 2 additions & 2 deletions sdk/core/azure_core/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -483,7 +483,7 @@ ureq = { version = "3", default-features = false, features = [
Then we need to implement `HttpClient` for another HTTP client like [`ureq`](https://docs.rs/ureq):

```rust no_run
use azure_core::{error::{ErrorKind, ResultExt as _}, http::{HttpClient, RawResponse, Request}};
use azure_core::{error::{ErrorKind, ResultExt as _}, http::{HttpClient, BufResponse, Request}};
use ureq::tls::{TlsConfig, TlsProvider};

#[derive(Debug)]
Expand All @@ -507,7 +507,7 @@ impl Default for Agent {

#[async_trait::async_trait]
impl HttpClient for Agent {
async fn execute_request(&self, request: &Request) -> azure_core::Result<RawResponse> {
async fn execute_request(&self, request: &Request) -> azure_core::Result<BufResponse> {
let request: ::http::request::Request<Vec<u8>> = todo!("convert our request into their request");
let response = self
.0
Expand Down
4 changes: 2 additions & 2 deletions sdk/core/azure_core/benches/benchmarks.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use azure_core::http::{
headers::Headers, HttpClient, Method, RawResponse, Request, StatusCode, Url,
headers::Headers, BufResponse, HttpClient, Method, Request, StatusCode, Url,
};
use azure_core_test::http::MockHttpClient;
use criterion::{black_box, criterion_group, criterion_main, Criterion};
Expand Down Expand Up @@ -31,7 +31,7 @@ fn http_transport_test(c: &mut Criterion) {
// client to be used in the benchmark
let mock_client = Arc::new(MockHttpClient::new(move |_| {
async move {
Ok(RawResponse::from_bytes(
Ok(BufResponse::from_bytes(
StatusCode::Ok,
Headers::new(),
vec![],
Expand Down
5 changes: 3 additions & 2 deletions sdk/core/azure_core/benches/http_transport_benchmarks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use azure_core::{
credentials::TokenCredential,
fmt::SafeDebug,
http::{
ClientMethodOptions, ClientOptions, HttpClient, Method, Pipeline, RawResponse, Request,
BufResponse, ClientMethodOptions, ClientOptions, HttpClient, Method, Pipeline, Request,
TransportOptions, Url,
},
Result,
Expand Down Expand Up @@ -85,7 +85,7 @@ impl TestServiceClient {
&self,
path: &str,
options: Option<TestServiceClientGetMethodOptions<'_>>,
) -> Result<RawResponse> {
) -> Result<BufResponse> {
let options = options.unwrap_or_default();
let mut url = self.endpoint.clone();
url.set_path(path);
Expand All @@ -103,6 +103,7 @@ impl TestServiceClient {
azure_core::error::ErrorKind::HttpResponse {
status: response.status(),
error_code: None,
raw_response: None,
},
format!("Failed to GET {}: {}", request.url(), response.status()),
));
Expand Down
6 changes: 3 additions & 3 deletions sdk/core/azure_core/examples/core_pager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

use azure_core::{
credentials::TokenCredential,
http::{headers::Headers, HttpClient, Method, RawResponse, StatusCode, TransportOptions},
http::{headers::Headers, BufResponse, HttpClient, Method, StatusCode, TransportOptions},
};
use azure_core_test::{credentials::MockCredential, http::MockHttpClient};
use azure_security_keyvault_secrets::{ResourceExt, SecretClient, SecretClientOptions};
Expand Down Expand Up @@ -64,7 +64,7 @@ fn setup() -> Result<(Arc<dyn TokenCredential>, Arc<dyn HttpClient>), Box<dyn st
assert_eq!(request.method(), Method::Get);
assert_eq!(request.url().path(), "/secrets");
match idx {
0 => Ok(RawResponse::from_bytes(
0 => Ok(BufResponse::from_bytes(
StatusCode::Ok,
Headers::new(),
// First page with continuation (nextLink)
Expand All @@ -74,7 +74,7 @@ fn setup() -> Result<(Arc<dyn TokenCredential>, Arc<dyn HttpClient>), Box<dyn st
],
"nextLink":"https://my-vault.vault.azure.net/secrets?api-version=7.4&$skiptoken=page2"}"#,
)),
1 => Ok(RawResponse::from_bytes(
1 => Ok(BufResponse::from_bytes(
StatusCode::Ok,
Headers::new(),
// Second (final) page without nextLink
Expand Down
6 changes: 3 additions & 3 deletions sdk/core/azure_core/examples/core_poller.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use azure_core::{
credentials::TokenCredential,
http::{
headers::{Headers, RETRY_AFTER},
HttpClient, Method, RawResponse, StatusCode, TransportOptions,
BufResponse, HttpClient, Method, StatusCode, TransportOptions,
},
};
use azure_core_test::{credentials::MockCredential, http::MockHttpClient};
Expand Down Expand Up @@ -78,7 +78,7 @@ fn setup() -> Result<(Arc<dyn TokenCredential>, Arc<dyn HttpClient>), Box<dyn st
assert!(request.url().path().starts_with("/certificates/my-cert/create"));
let mut headers = Headers::new();
headers.insert(RETRY_AFTER, "0");
Ok(RawResponse::from_bytes(
Ok(BufResponse::from_bytes(
StatusCode::Ok,
headers,
r#"{"id":"https://my-vault.vault.azure.net/certificates/my-cert/pending","status":"inProgress"}"#,
Expand All @@ -88,7 +88,7 @@ fn setup() -> Result<(Arc<dyn TokenCredential>, Arc<dyn HttpClient>), Box<dyn st
// Polling GET for status
assert_eq!(request.method(), Method::Get);
assert!(request.url().path().starts_with("/certificates/my-cert/pending"));
Ok(RawResponse::from_bytes(
Ok(BufResponse::from_bytes(
StatusCode::Ok,
Headers::new(),
r#"{"id":"https://my-vault.vault.azure.net/certificates/my-cert/pending","status":"completed","target":"https://my-vault.vault.azure.net/certificates/my-cert"}"#,
Expand Down
4 changes: 2 additions & 2 deletions sdk/core/azure_core/examples/core_remove_user_agent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use azure_core::{
http::{
headers::Headers,
policies::{Policy, PolicyResult},
Context, HttpClient, Method, RawResponse, Request, StatusCode, TransportOptions,
BufResponse, Context, HttpClient, Method, Request, StatusCode, TransportOptions,
},
};
use azure_core_test::{credentials::MockCredential, http::MockHttpClient};
Expand Down Expand Up @@ -96,7 +96,7 @@ fn setup() -> Result<(Arc<dyn TokenCredential>, Arc<dyn HttpClient>), Box<dyn st
.any(|(name, _)| name.as_str().eq_ignore_ascii_case("user-agent")),
"user-agent header should be absent"
);
Ok(RawResponse::from_bytes(
Ok(BufResponse::from_bytes(
StatusCode::Ok,
Headers::new(),
r#"{"value":"secret-value"}"#,
Expand Down
8 changes: 4 additions & 4 deletions sdk/core/azure_core/examples/core_ureq_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
use async_trait::async_trait;
use azure_core::{
error::ErrorKind,
http::{headers::Headers, ClientOptions, HttpClient, RawResponse, Request, TransportOptions},
http::{headers::Headers, BufResponse, ClientOptions, HttpClient, Request, TransportOptions},
};
use azure_identity::DeveloperToolsCredential;
use azure_security_keyvault_secrets::{ResourceExt as _, SecretClient, SecretClientOptions};
Expand Down Expand Up @@ -35,7 +35,7 @@ impl Default for Agent {
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
impl HttpClient for Agent {
async fn execute_request(&self, request: &Request) -> azure_core::Result<RawResponse> {
async fn execute_request(&self, request: &Request) -> azure_core::Result<BufResponse> {
let request = into_request(request)?;
let response = self
.0
Expand Down Expand Up @@ -102,7 +102,7 @@ fn into_request(request: &Request) -> azure_core::Result<::http::Request<Vec<u8>
Ok(req)
}

fn into_response(response: ::http::Response<ureq::Body>) -> azure_core::Result<RawResponse> {
fn into_response(response: ::http::Response<ureq::Body>) -> azure_core::Result<BufResponse> {
use ::http::response::Parts;
use azure_core::http::StatusCode;

Expand All @@ -128,5 +128,5 @@ fn into_response(response: ::http::Response<ureq::Body>) -> azure_core::Result<R
.read_to_vec()
.with_context(ErrorKind::Io, || "failed to read response body")?;

Ok(RawResponse::from_bytes(status, response_headers, body))
Ok(BufResponse::from_bytes(status, response_headers, body))
}
2 changes: 1 addition & 1 deletion sdk/core/azure_core/src/http/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ pub use pager::{ItemIterator, PageIterator, Pager};
pub use pipeline::*;
pub use poller::Poller;
pub use request::{Body, Request, RequestContent};
pub use response::{RawResponse, Response};
pub use response::{BufResponse, Response};

pub use typespec_client_core::http::response;
pub use typespec_client_core::http::{
Expand Down
24 changes: 12 additions & 12 deletions sdk/core/azure_core/src/http/pager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ impl<P: Page> ItemIterator<P> {
/// To page results using a next link:
///
/// ```rust,no_run
/// # use azure_core::{Result, http::{Context, ItemIterator, pager::{Page, PagerResult, PagerState}, Pipeline, RawResponse, Request, Response, Method, Url}, json};
/// # use azure_core::{Result, http::{BufResponse, Context, ItemIterator, pager::{Page, PagerResult, PagerState}, Pipeline, Request, Response, Method, Url}, json};
/// # let api_version = "2025-06-04".to_string();
/// # let pipeline: Pipeline = panic!("Not a runnable example");
/// #[derive(serde::Deserialize)]
Expand Down Expand Up @@ -220,7 +220,7 @@ impl<P: Page> ItemIterator<P> {
/// let (status, headers, body) = resp.deconstruct();
/// let bytes = body.collect().await?;
/// let result: ListItemsResult = json::from_json(&bytes)?;
/// let resp: Response<ListItemsResult> = RawResponse::from_bytes(status, headers, bytes).into();
/// let resp: Response<ListItemsResult> = BufResponse::from_bytes(status, headers, bytes).into();
/// Ok(match result.next_link {
/// Some(next_link) => PagerResult::More {
/// response: resp,
Expand Down Expand Up @@ -379,7 +379,7 @@ impl<P> PageIterator<P> {
/// To page results using a next link:
///
/// ```rust,no_run
/// # use azure_core::{Result, http::{Context, pager::{PageIterator, PagerResult, PagerState}, Pipeline, RawResponse, Request, Response, Method, Url}, json};
/// # use azure_core::{Result, http::{BufResponse, Context, pager::{PageIterator, PagerResult, PagerState}, Pipeline, Request, Response, Method, Url}, json};
/// # let api_version = "2025-06-04".to_string();
/// # let pipeline: Pipeline = panic!("Not a runnable example");
/// #[derive(serde::Deserialize)]
Expand Down Expand Up @@ -413,7 +413,7 @@ impl<P> PageIterator<P> {
/// let (status, headers, body) = resp.deconstruct();
/// let bytes = body.collect().await?;
/// let result: ListItemsResult = json::from_json(&bytes)?;
/// let resp: Response<ListItemsResult> = RawResponse::from_bytes(status, headers, bytes).into();
/// let resp: Response<ListItemsResult> = BufResponse::from_bytes(status, headers, bytes).into();
/// Ok(match result.next_link {
/// Some(next_link) => PagerResult::More {
/// response: resp,
Expand Down Expand Up @@ -649,7 +649,7 @@ mod tests {
use crate::http::{
headers::{HeaderName, HeaderValue},
pager::{PageIterator, Pager, PagerResult, PagerState},
RawResponse, Response, StatusCode,
BufResponse, Response, StatusCode,
};
use async_trait::async_trait;
use futures::{StreamExt as _, TryStreamExt as _};
Expand Down Expand Up @@ -678,7 +678,7 @@ mod tests {
let pager: Pager<Page> = Pager::from_callback(|continuation| async move {
match continuation {
PagerState::Initial => Ok(PagerResult::More {
response: RawResponse::from_bytes(
response: BufResponse::from_bytes(
StatusCode::Ok,
HashMap::from([(
HeaderName::from_static("x-test-header"),
Expand All @@ -691,7 +691,7 @@ mod tests {
continuation: "1",
}),
PagerState::More("1") => Ok(PagerResult::More {
response: RawResponse::from_bytes(
response: BufResponse::from_bytes(
StatusCode::Ok,
HashMap::from([(
HeaderName::from_static("x-test-header"),
Expand All @@ -704,7 +704,7 @@ mod tests {
continuation: "2",
}),
PagerState::More("2") => Ok(PagerResult::Done {
response: RawResponse::from_bytes(
response: BufResponse::from_bytes(
StatusCode::Ok,
HashMap::from([(
HeaderName::from_static("x-test-header"),
Expand All @@ -729,7 +729,7 @@ mod tests {
let pager: Pager<Page> = Pager::from_callback(|continuation| async move {
match continuation {
PagerState::Initial => Ok(PagerResult::More {
response: RawResponse::from_bytes(
response: BufResponse::from_bytes(
StatusCode::Ok,
HashMap::from([(
HeaderName::from_static("x-test-header"),
Expand Down Expand Up @@ -786,7 +786,7 @@ mod tests {
|continuation: PagerState<String>| async move {
match continuation.as_deref() {
PagerState::Initial => Ok(PagerResult::More {
response: RawResponse::from_bytes(
response: BufResponse::from_bytes(
StatusCode::Ok,
Default::default(),
r#"{"items":[1],"page":1}"#,
Expand All @@ -795,7 +795,7 @@ mod tests {
continuation: "next-token-1".to_string(),
}),
PagerState::More("next-token-1") => Ok(PagerResult::More {
response: RawResponse::from_bytes(
response: BufResponse::from_bytes(
StatusCode::Ok,
HashMap::from([(
HeaderName::from_static("x-test-header"),
Expand All @@ -808,7 +808,7 @@ mod tests {
continuation: "next-token-2".to_string(),
}),
PagerState::More("next-token-2") => Ok(PagerResult::Done {
response: RawResponse::from_bytes(
response: BufResponse::from_bytes(
StatusCode::Ok,
HashMap::from([(
HeaderName::from_static("x-test-header"),
Expand Down
12 changes: 6 additions & 6 deletions sdk/core/azure_core/src/http/pipeline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ use typespec_client_core::http::{
/// re-executed in case of retries.
/// 6. User-specified per-retry policies in [`ClientOptions::per_try_policies`] are executed.
/// 7. The transport policy is executed. Transport policy is always the last policy and is the policy that
/// actually constructs the [`RawResponse`](http::RawResponse) to be passed up the pipeline.
/// actually constructs the [`BufResponse`](http::BufResponse) to be passed up the pipeline.
///
/// A pipeline is immutable. In other words a policy can either succeed and call the following
/// policy of fail and return to the calling policy. Arbitrary policy "skip" must be avoided (but
Expand Down Expand Up @@ -142,7 +142,7 @@ mod tests {
headers::{self, HeaderName, Headers},
policies::Policy,
request::options::ClientRequestId,
ClientOptions, Context, Method, RawResponse, Request, StatusCode, TransportOptions,
BufResponse, ClientOptions, Context, Method, Request, StatusCode, TransportOptions,
UserAgentOptions,
},
Bytes,
Expand Down Expand Up @@ -173,7 +173,7 @@ mod tests {
"Custom header value should match the client request ID"
);

Ok(RawResponse::from_bytes(
Ok(BufResponse::from_bytes(
StatusCode::Ok,
Headers::new(),
Bytes::new(),
Expand Down Expand Up @@ -231,7 +231,7 @@ mod tests {
"Default header value should match the client request ID"
);

Ok(RawResponse::from_bytes(
Ok(BufResponse::from_bytes(
StatusCode::Ok,
Headers::new(),
Bytes::new(),
Expand Down Expand Up @@ -285,7 +285,7 @@ mod tests {
user_agent
);

Ok(RawResponse::from_bytes(
Ok(BufResponse::from_bytes(
StatusCode::Ok,
Headers::new(),
Bytes::new(),
Expand Down Expand Up @@ -340,7 +340,7 @@ mod tests {
user_agent
);

Ok(RawResponse::from_bytes(
Ok(BufResponse::from_bytes(
StatusCode::Ok,
Headers::new(),
Bytes::new(),
Expand Down
Loading