From<http::Response> for Response (#360)
This adds an implementation to convert a `Response` type from the `http` crate to the `async_impl::Response` type. This is the first step to allow us to convert `http::Response` objects to `request::Response` objects This also adds an extension trait for the `http::response::Builder` type. The `http::Response` object does not provide a way to access the "final" url that the response is derived from, so we can't easily provide that in the `From<http::Response>` implementation. For users who are manually constructing `http::Response` objects for use in tests, etc, they can import this extension trait, which adds a `.url()` builder method that will allow them to pass a `Url`, which we then convert to our newtype'd Url and add to the `http::Response`'s `extensions`. Then, when converting from `http::Response` to `async_impl::Response` we can pull that value out of the `extensions` and use it to construct the `async_impl::Response` Closes #333
This commit is contained in:
		
				
					committed by
					
						 Sean McArthur
						Sean McArthur
					
				
			
			
				
	
			
			
			
						parent
						
							22fa725f48
						
					
				
				
					commit
					4857a5917d
				
			| @@ -2,7 +2,7 @@ pub use self::body::{Body, Chunk}; | ||||
| pub use self::decoder::{Decoder, ReadableChunks}; | ||||
| pub use self::client::{Client, ClientBuilder}; | ||||
| pub use self::request::{Request, RequestBuilder}; | ||||
| pub use self::response::Response; | ||||
| pub use self::response::{Response, ResponseBuilderExt}; | ||||
|  | ||||
| pub mod body; | ||||
| pub mod client; | ||||
|   | ||||
| @@ -8,6 +8,7 @@ use hyper::{HeaderMap, StatusCode, Version}; | ||||
| use serde::de::DeserializeOwned; | ||||
| use serde_json; | ||||
| use url::Url; | ||||
| use http; | ||||
|  | ||||
| use super::{decoder, body, Decoder}; | ||||
|  | ||||
| @@ -144,6 +145,25 @@ impl fmt::Debug for Response { | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T: Into<body::Body>> From<http::Response<T>> for Response { | ||||
|     fn from(r: http::Response<T>) -> Response { | ||||
|         let (mut parts, body) = r.into_parts(); | ||||
|         let body = body.into(); | ||||
|         let body = decoder::detect(&mut parts.headers, body, false); | ||||
|         let url = parts.extensions | ||||
|             .remove::<ResponseUrl>() | ||||
|             .unwrap_or_else(|| ResponseUrl(Url::parse("http://no.url.provided.local").unwrap())); | ||||
|         let url = url.0; | ||||
|         Response { | ||||
|             status: parts.status, | ||||
|             headers: parts.headers, | ||||
|             url: Box::new(url), | ||||
|             body: body, | ||||
|             version: parts.version, | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| pub struct Json<T> { | ||||
|     concat: Concat2<Decoder>, | ||||
|     _marker: PhantomData<T>, | ||||
| @@ -166,3 +186,72 @@ impl<T> fmt::Debug for Json<T> { | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[derive(Debug, Clone, PartialEq)] | ||||
| struct ResponseUrl(Url); | ||||
|  | ||||
| /// Extension trait for http::response::Builder objects | ||||
| /// | ||||
| /// Allows the user to add a `Url` to the http::Response | ||||
| pub trait ResponseBuilderExt { | ||||
|     /// A builder method for the `http::response::Builder` type that allows the user to add a `Url` | ||||
|     /// to the `http::Response` | ||||
|     /// | ||||
|     /// # Example | ||||
|     /// | ||||
|     /// ``` | ||||
|     /// # extern crate url; | ||||
|     /// # extern crate http; | ||||
|     /// # extern crate reqwest; | ||||
|     /// # use std::error::Error; | ||||
|     /// use url::Url; | ||||
|     /// use http::response::Builder; | ||||
|     /// use reqwest::async::ResponseBuilderExt; | ||||
|     /// # fn main() -> Result<(), Box<Error>> { | ||||
|     /// let response = Builder::new() | ||||
|     ///     .status(200) | ||||
|     ///     .url(Url::parse("http://example.com")?) | ||||
|     ///     .body(())?; | ||||
|     /// | ||||
|     /// #   Ok(()) | ||||
|     /// # } | ||||
|     fn url(&mut self, url: Url) -> &mut Self; | ||||
| } | ||||
|  | ||||
| impl ResponseBuilderExt for http::response::Builder { | ||||
|     fn url(&mut self, url: Url) -> &mut Self { | ||||
|         self.extension(ResponseUrl(url)) | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[cfg(test)] | ||||
| mod tests { | ||||
|     use url::Url; | ||||
|     use http::response::Builder; | ||||
|     use super::{Response, ResponseUrl, ResponseBuilderExt}; | ||||
|  | ||||
|     #[test] | ||||
|     fn test_response_builder_ext() { | ||||
|         let url = Url::parse("http://example.com").unwrap(); | ||||
|         let response = Builder::new() | ||||
|             .status(200) | ||||
|             .url(url.clone()) | ||||
|             .body(()) | ||||
|             .unwrap(); | ||||
|  | ||||
|         assert_eq!(response.extensions().get::<ResponseUrl>(), Some(&ResponseUrl(url))); | ||||
|     } | ||||
|  | ||||
|     #[test] | ||||
|     fn test_from_http_response() { | ||||
|         let url = Url::parse("http://example.com").unwrap(); | ||||
|         let response = Builder::new() | ||||
|             .status(200) | ||||
|             .url(url.clone()) | ||||
|             .body("foo") | ||||
|             .unwrap(); | ||||
|         let response = Response::from(response); | ||||
|  | ||||
|         assert_eq!(response.status, 200); | ||||
|         assert_eq!(response.url, Box::new(url)); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -500,7 +500,7 @@ impl ClientHandle { | ||||
|             } | ||||
|         }; | ||||
|         res.map(|res| { | ||||
|             response::new(res, self.timeout.0, KeepCoreThreadAlive(self.inner.clone())) | ||||
|             response::new(res, self.timeout.0, KeepCoreThreadAlive(Some(self.inner.clone()))) | ||||
|         }) | ||||
|     } | ||||
| } | ||||
| @@ -517,4 +517,10 @@ impl Default for Timeout { | ||||
|  | ||||
| // pub(crate) | ||||
|  | ||||
| pub struct KeepCoreThreadAlive(Arc<InnerClientHandle>); | ||||
| pub struct KeepCoreThreadAlive(Option<Arc<InnerClientHandle>>); | ||||
|  | ||||
| impl KeepCoreThreadAlive { | ||||
|     pub(crate) fn empty() -> KeepCoreThreadAlive { | ||||
|         KeepCoreThreadAlive(None) | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -203,6 +203,7 @@ pub mod async { | ||||
|         Request, | ||||
|         RequestBuilder, | ||||
|         Response, | ||||
|         ResponseBuilderExt, | ||||
|     }; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -6,6 +6,7 @@ use std::borrow::Cow; | ||||
|  | ||||
| use encoding_rs::{Encoding, UTF_8}; | ||||
| use futures::{Async, Poll, Stream}; | ||||
| use http; | ||||
| use mime::Mime; | ||||
| use serde::de::DeserializeOwned; | ||||
| use serde_json; | ||||
| @@ -336,3 +337,9 @@ pub fn new(mut res: async_impl::Response, timeout: Option<Duration>, thread: Kee | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<T: Into<async_impl::body::Body>> From<http::Response<T>> for Response { | ||||
|     fn from(r: http::Response<T>) -> Response { | ||||
|         let response = async_impl::Response::from(r); | ||||
|         new(response, None, KeepCoreThreadAlive::empty()) | ||||
|     } | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user