Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add Method & StatusCode to azure_core #852

Merged
merged 10 commits into from
Jun 27, 2022
Merged
Show file tree
Hide file tree
Changes from 3 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
16 changes: 9 additions & 7 deletions sdk/core/src/error/http_error.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{headers, Response};
use crate::{headers, response, Response, INVALID_BODY};
cataggar marked this conversation as resolved.
Show resolved Hide resolved
use bytes::Bytes;
use std::collections::HashMap;

Expand All @@ -16,19 +16,21 @@ impl HttpError {
///
/// This does not check whether the response was a success and should only be used with unsuccessful responses.
pub async fn new(response: Response) -> Self {
let status = response.status();
let mut error_code = get_error_code_from_header(&response);
let mut headers = HashMap::new();
let (status, headers, body) = response.deconstruct();
let mut error_headers = HashMap::new();

for (name, value) in response.headers().iter() {
headers.insert(name.as_str().to_string(), value.as_str().to_string());
for (name, value) in headers.iter() {
error_headers.insert(name.as_str().to_string(), value.as_str().to_string());
cataggar marked this conversation as resolved.
Show resolved Hide resolved
}

let body = response.into_body().await;
let body = response::collect_pinned_stream(body)
.await
.unwrap_or_else(|_| Bytes::from_static(INVALID_BODY));
error_code = error_code.or_else(|| get_error_code_from_body(&body));
HttpError {
status: status.as_u16(),
headers,
headers: error_headers,
error_code,
body,
}
Expand Down
34 changes: 0 additions & 34 deletions sdk/core/src/error/hyperium_http.rs

This file was deleted.

1 change: 0 additions & 1 deletion sdk/core/src/error/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use std::borrow::Cow;
use std::fmt::{Debug, Display};
mod http_error;
mod hyperium_http;
mod macros;
pub use http_error::HttpError;

Expand Down
18 changes: 1 addition & 17 deletions sdk/core/src/headers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
mod utilities;

use crate::error::{Error, ErrorKind, ResultExt};
use std::{collections::HashMap, fmt::Debug, str::FromStr};
use std::{fmt::Debug, str::FromStr};
pub use utilities::*;

/// A trait for converting a type into request headers
Expand Down Expand Up @@ -162,22 +162,6 @@ impl From<std::collections::HashMap<HeaderName, HeaderValue>> for Headers {
}
}

impl From<&http::HeaderMap> for Headers {
fn from(map: &http::HeaderMap) -> Self {
let map = map
.into_iter()
.map(|(k, v)| {
let key = k.as_str().to_owned();
let value = std::str::from_utf8(v.as_bytes())
.expect("non-UTF8 header value")
.to_owned();
(key.into(), value.into())
})
.collect::<HashMap<HeaderName, HeaderValue>>();
Self(map)
}
}

/// A header name
#[derive(Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)]
pub struct HeaderName(std::borrow::Cow<'static, str>);
Expand Down
61 changes: 7 additions & 54 deletions sdk/core/src/http_client.rs → sdk/core/src/http_client/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
#[cfg(any(feature = "enable_reqwest", feature = "enable_reqwest_rustls"))]
#[cfg(not(target_arch = "wasm32"))]
mod reqwest;

#[cfg(any(feature = "enable_reqwest", feature = "enable_reqwest_rustls"))]
#[cfg(not(target_arch = "wasm32"))]
pub use self::reqwest::*;
#[allow(unused_imports)]
use crate::error::{Error, ErrorKind, ResultExt};
#[allow(unused_imports)]
Expand All @@ -10,13 +17,6 @@ use bytes::Bytes;
use futures::TryStreamExt;
use serde::Serialize;

/// Construct a new `HttpClient` with the `reqwest` backend.
#[cfg(any(feature = "enable_reqwest", feature = "enable_reqwest_rustls"))]
#[cfg(not(target_arch = "wasm32"))]
pub fn new_http_client() -> std::sync::Arc<dyn HttpClient> {
std::sync::Arc::new(reqwest::Client::new())
}

/// An HTTP client which can send requests.
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
Expand Down Expand Up @@ -45,53 +45,6 @@ pub trait HttpClient: Send + Sync + std::fmt::Debug {
}
}

#[cfg(any(feature = "enable_reqwest", feature = "enable_reqwest_rustls"))]
#[cfg(not(target_arch = "wasm32"))]
#[async_trait]
impl HttpClient for reqwest::Client {
async fn execute_request(&self, request: &crate::Request) -> crate::Result<crate::Response> {
let url = request.url().clone();
let mut reqwest_request = self.request(request.method().clone(), url);
for (name, value) in request.headers().iter() {
reqwest_request = reqwest_request.header(name.as_str(), value.as_str());
}

let body = request.body().clone();

let reqwest_request = match body {
Body::Bytes(bytes) => reqwest_request
.body(bytes)
.build()
.context(ErrorKind::Other, "failed to build request")?,
Body::SeekableStream(mut seekable_stream) => {
seekable_stream.reset().await.unwrap(); // TODO: remove unwrap when `HttpError` has been removed

reqwest_request
.body(reqwest::Body::wrap_stream(seekable_stream))
.build()
.context(ErrorKind::Other, "failed to build request")?
}
};

let reqwest_response = self
.execute(reqwest_request)
.await
.context(ErrorKind::Io, "failed to execute request")?;

let status = reqwest_response.status();
let headers = Headers::from(reqwest_response.headers());
let body: PinnedStream = Box::pin(reqwest_response.bytes_stream().map_err(|error| {
Error::full(
ErrorKind::Io,
error,
"error converting `reqwest` request into a byte stream",
)
}));

Ok(crate::Response::new(status, headers, body))
}
}

/// Serialize a type to json.
pub fn to_json<T>(value: &T) -> crate::Result<Bytes>
where
Expand Down
65 changes: 65 additions & 0 deletions sdk/core/src/http_client/reqwest.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
use super::*;
use std::collections::HashMap;

/// Construct a new `HttpClient` with the `reqwest` backend.
pub fn new_http_client() -> std::sync::Arc<dyn HttpClient> {
std::sync::Arc::new(::reqwest::Client::new())
}

#[async_trait]
impl HttpClient for ::reqwest::Client {
async fn execute_request(&self, request: &crate::Request) -> crate::Result<crate::Response> {
let url = request.url().clone();
let mut req = self.request(request.method().clone(), url);
for (name, value) in request.headers().iter() {
req = req.header(name.as_str(), value.as_str());
}

let body = request.body().clone();

let reqwest_request = match body {
Body::Bytes(bytes) => req
.body(bytes)
.build()
.context(ErrorKind::Other, "failed to build request")?,
cataggar marked this conversation as resolved.
Show resolved Hide resolved
Body::SeekableStream(mut seekable_stream) => {
seekable_stream.reset().await.unwrap(); // TODO: remove unwrap when `HttpError` has been removed
req.body(::reqwest::Body::wrap_stream(seekable_stream))
.build()
.context(ErrorKind::Other, "failed to build request")?
cataggar marked this conversation as resolved.
Show resolved Hide resolved
}
};

let rsp = self
.execute(reqwest_request)
.await
.context(ErrorKind::Io, "failed to execute request")?;

let status = rsp.status();
let headers = to_headers(rsp.headers())?;
let body: PinnedStream = Box::pin(rsp.bytes_stream().map_err(|error| {
Error::full(
ErrorKind::Io,
error,
"error converting `reqwest` request into a byte stream",
cataggar marked this conversation as resolved.
Show resolved Hide resolved
)
}));

Ok(crate::Response::new(status, headers, body))
}
}

fn to_headers(map: &::reqwest::header::HeaderMap) -> crate::Result<crate::headers::Headers> {
let map = map
.iter()
.map(|(k, v)| {
let key = k.as_str();
let value = std::str::from_utf8(v.as_bytes()).expect("non-UTF8 header value");
cataggar marked this conversation as resolved.
Show resolved Hide resolved
(
crate::headers::HeaderName::from(key.to_owned()),
crate::headers::HeaderValue::from(value.to_owned()),
)
})
.collect::<HashMap<_, _>>();
Ok(crate::headers::Headers::from(map))
}
7 changes: 7 additions & 0 deletions sdk/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,13 @@ pub use response::*;
pub use seekable_stream::*;
pub use sleep::sleep;

// re-export packages
pub use http;
pub use url;
cataggar marked this conversation as resolved.
Show resolved Hide resolved

// re-export important types at crate level
pub use http::Method;
pub use http::StatusCode;
pub use url::Url;

/// A unique identifier for a request.
Expand Down
2 changes: 1 addition & 1 deletion sdk/core/src/mock/mock_request.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::Method;
use crate::{Body, Request};
use http::Method;
use serde::de::Visitor;
use serde::ser::{Serialize, SerializeStruct, Serializer};
use serde::{Deserialize, Deserializer};
Expand Down
12 changes: 5 additions & 7 deletions sdk/core/src/mock/mock_response.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
use bytes::Bytes;
use http::StatusCode;
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;

use crate::{
collect_pinned_stream, error,
headers::{HeaderName, HeaderValue, Headers},
BytesStream, Response,
BytesStream, Response, StatusCode,
};
use bytes::Bytes;
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;

#[derive(Debug, Clone, PartialEq)]
pub(crate) struct MockResponse {
Expand Down Expand Up @@ -48,7 +46,7 @@ impl MockResponse {
)?;

let response = Response::new(
status_code,
status_code.clone(),
cataggar marked this conversation as resolved.
Show resolved Hide resolved
header_map.clone(),
Box::pin(BytesStream::new(response_bytes.clone())),
);
Expand Down
2 changes: 1 addition & 1 deletion sdk/core/src/mock/player_policy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ impl Policy for MockTransportPlayerPolicy {
if expected_request.method() != request.method() {
return Err(Error::with_message(ErrorKind::MockFramework, || {
format!(
"mismatched HTTP request method. Actual: {0}, Expected: {1}",
"mismatched HTTP request method. Actual: {0:?}, Expected: {1:?}",
cataggar marked this conversation as resolved.
Show resolved Hide resolved
expected_request.method(),
request.method(),
)
Expand Down
4 changes: 1 addition & 3 deletions sdk/core/src/policies/retry_policies/retry_policy.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
use crate::error::{Error, ErrorKind, HttpError};
use crate::policies::{Policy, PolicyResult, Request};
use crate::sleep::sleep;
use crate::Context;

use crate::{Context, StatusCode};
use chrono::{DateTime, Local};
use http::StatusCode;
use std::sync::Arc;
use std::time::Duration;

Expand Down
3 changes: 1 addition & 2 deletions sdk/core/src/request.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use crate::headers::{AsHeaders, Headers};
use crate::SeekableStream;
use crate::{Method, SeekableStream};
use bytes::Bytes;
use http::Method;
use std::fmt::Debug;
use url::Url;

Expand Down
10 changes: 6 additions & 4 deletions sdk/core/src/response.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
use crate::headers::Headers;
use crate::StatusCode;
use bytes::Bytes;
use futures::Stream;
use futures::StreamExt;
use http::StatusCode;
use std::pin::Pin;

pub type PinnedStream = Pin<Box<dyn Stream<Item = crate::Result<Bytes>> + Send + Sync>>;

pub(crate) const INVALID_BODY: &[u8] = b"<INVALID BODY>";

/// An HTTP Response.
pub struct Response {
status: StatusCode,
Expand All @@ -26,8 +28,8 @@ impl Response {
}

/// Get the status code from the response.
pub fn status(&self) -> StatusCode {
self.status
pub fn status(&self) -> &StatusCode {
cataggar marked this conversation as resolved.
Show resolved Hide resolved
&self.status
}

/// Get the headers from the response.
Expand All @@ -44,7 +46,7 @@ impl Response {
pub async fn into_body(self) -> Bytes {
collect_pinned_stream(self.body)
.await
.unwrap_or_else(|_| Bytes::from_static(b"<INVALID BODY>"))
.unwrap_or_else(|_| Bytes::from_static(INVALID_BODY))
}

/// Consume the HTTP response and read the HTTP body into a string.
Expand Down
1 change: 0 additions & 1 deletion sdk/data_cosmos/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ async-trait = "0.1"
azure_core = { path = "../core", version = "0.3" }
base64 = "0.13"
chrono = "0.4"
http = "0.2"
futures = "0.3"
log = "0.4"
serde = { version = "1.0", features = ["derive"] }
Expand Down
Loading