feat(lib): implement compatibility with http crate
This commit is contained in:
		| @@ -8,6 +8,8 @@ matrix: | ||||
|           env: FEATURES="--features nightly" | ||||
|         - rust: beta | ||||
|         - rust: stable | ||||
|         - rust: stable | ||||
|           env: FEATURES="--features compat" | ||||
|         - rust: 1.15.0 | ||||
|  | ||||
| cache: | ||||
|   | ||||
| @@ -23,6 +23,7 @@ base64 = "0.6" | ||||
| bytes = "0.4.4" | ||||
| futures = "0.1.14" | ||||
| futures-cpupool = "0.1" | ||||
| http = { version = "0.1", optional = true } | ||||
| httparse = "1.0" | ||||
| language-tags = "0.2" | ||||
| log = "0.3" | ||||
| @@ -45,3 +46,4 @@ spmc = "0.2" | ||||
| default = [] | ||||
| nightly = [] | ||||
| raw_status = [] | ||||
| compat = [ "http" ] | ||||
							
								
								
									
										6
									
								
								src/client/compat.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								src/client/compat.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| //! Wrappers to build compatibility with the `http` crate. | ||||
|  | ||||
| pub use super::compat_impl::{ | ||||
|     CompatClient, | ||||
|     CompatFutureResponse | ||||
| }; | ||||
							
								
								
									
										53
									
								
								src/client/compat_impl.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								src/client/compat_impl.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,53 @@ | ||||
| use futures::{Future, Poll, Stream}; | ||||
| use http_types; | ||||
| use tokio_service::Service; | ||||
|  | ||||
| use client::{Connect, Client, FutureResponse}; | ||||
| use error::Error; | ||||
| use http::Body; | ||||
|  | ||||
| /// A Client to make outgoing HTTP requests. | ||||
| #[derive(Debug)] | ||||
| pub struct CompatClient<C, B = Body> { | ||||
|     inner: Client<C, B> | ||||
| } | ||||
|  | ||||
| pub fn client<C, B>(client: Client<C, B>) -> CompatClient<C, B> { | ||||
|     CompatClient { inner: client } | ||||
| } | ||||
|  | ||||
| impl<C, B> Service for CompatClient<C, B> | ||||
| where C: Connect, | ||||
|       B: Stream<Error=Error> + 'static, | ||||
|       B::Item: AsRef<[u8]>, | ||||
| { | ||||
|     type Request = http_types::Request<B>; | ||||
|     type Response = http_types::Response<Body>; | ||||
|     type Error = Error; | ||||
|     type Future = CompatFutureResponse; | ||||
|  | ||||
|     fn call(&self, req: Self::Request) -> Self::Future { | ||||
|         future(self.inner.call(req.into())) | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// A `Future` that will resolve to an `http::Response`. | ||||
| #[must_use = "futures do nothing unless polled"] | ||||
| #[derive(Debug)] | ||||
| pub struct CompatFutureResponse { | ||||
|     inner: FutureResponse | ||||
| } | ||||
|  | ||||
| pub fn future(fut: FutureResponse) -> CompatFutureResponse { | ||||
|     CompatFutureResponse { inner: fut } | ||||
| } | ||||
|  | ||||
| impl Future for CompatFutureResponse { | ||||
|     type Item = http_types::Response<Body>; | ||||
|     type Error = Error; | ||||
|  | ||||
|     fn poll(&mut self) -> Poll<Self::Item, Error> { | ||||
|         self.inner.poll() | ||||
|             .map(|a| a.map(|r| r.into())) | ||||
|     } | ||||
| } | ||||
| @@ -9,6 +9,8 @@ use std::time::Duration; | ||||
|  | ||||
| use futures::{future, Poll, Async, Future, Stream}; | ||||
| use futures::unsync::oneshot; | ||||
| #[cfg(feature = "compat")] | ||||
| use http_types; | ||||
| use tokio_io::{AsyncRead, AsyncWrite}; | ||||
| use tokio::reactor::Handle; | ||||
| use tokio_proto::BindClient; | ||||
| @@ -33,6 +35,10 @@ pub use self::connect::{HttpConnector, Connect}; | ||||
| mod connect; | ||||
| mod dns; | ||||
| mod pool; | ||||
| #[cfg(feature = "compat")] | ||||
| mod compat_impl; | ||||
| #[cfg(feature = "compat")] | ||||
| pub mod compat; | ||||
|  | ||||
| /// A Client to make outgoing HTTP requests. | ||||
| // If the Connector is clone, then the Client can be clone easily. | ||||
| @@ -108,6 +114,19 @@ where C: Connect, | ||||
|     pub fn request(&self, req: Request<B>) -> FutureResponse { | ||||
|         self.call(req) | ||||
|     } | ||||
|  | ||||
|     /// Send an `http::Request` using this Client. | ||||
|     #[inline] | ||||
|     #[cfg(feature = "compat")] | ||||
|     pub fn request_compat(&self, req: http_types::Request<B>) -> compat::CompatFutureResponse { | ||||
|         self::compat_impl::future(self.call(req.into())) | ||||
|     } | ||||
|  | ||||
|     /// Convert into a client accepting `http::Request`. | ||||
|     #[cfg(feature = "compat")] | ||||
|     pub fn into_compat(self) -> compat::CompatClient<C, B> { | ||||
|         self::compat_impl::client(self) | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// A `Future` that will resolve to an HTTP Response. | ||||
|   | ||||
| @@ -29,6 +29,11 @@ impl ByteStr { | ||||
|     pub fn as_str(&self) -> &str { | ||||
|         unsafe { str::from_utf8_unchecked(self.0.as_ref()) } | ||||
|     } | ||||
|  | ||||
|     #[cfg(feature = "compat")] | ||||
|     pub fn into_bytes(self) -> Bytes { | ||||
|         self.0 | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl Deref for ByteStr { | ||||
|   | ||||
| @@ -77,9 +77,14 @@ | ||||
| //! } | ||||
| //! ``` | ||||
| use std::borrow::{Cow, ToOwned}; | ||||
| #[cfg(feature = "compat")] | ||||
| use std::convert::From; | ||||
| use std::iter::{FromIterator, IntoIterator}; | ||||
| use std::{mem, fmt}; | ||||
|  | ||||
| #[cfg(feature = "compat")] | ||||
| use http_types; | ||||
|  | ||||
| use unicase::Ascii; | ||||
|  | ||||
| use self::internals::{Item, VecMap, Entry}; | ||||
| @@ -546,6 +551,54 @@ impl fmt::Debug for Headers { | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[cfg(feature = "compat")] | ||||
| impl From<http_types::HeaderMap> for Headers { | ||||
|     fn from(mut header_map: http_types::HeaderMap) -> Headers { | ||||
|         let mut headers = Headers::new(); | ||||
|         for (name, mut value_drain) in header_map.drain() { | ||||
|             if let Some(first_value) = value_drain.next() { | ||||
|                 let mut raw: Raw = first_value.as_bytes().into(); | ||||
|                 for value in value_drain { | ||||
|                     raw.push(value.as_bytes()); | ||||
|                 } | ||||
|                 headers.append_raw(name.as_str().to_string(), raw);         | ||||
|             } | ||||
|         } | ||||
|         headers | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[cfg(feature = "compat")] | ||||
| impl From<Headers> for http_types::HeaderMap { | ||||
|     fn from(headers: Headers) -> http_types::HeaderMap { | ||||
|         let mut header_map = http_types::HeaderMap::new(); | ||||
|         for header in headers.iter() { | ||||
|             let entry = header_map.entry(header.name()) | ||||
|                 .expect("attempted to convert invalid header name"); | ||||
|             let mut value_iter = header.raw().iter().map(|line| { | ||||
|                 http_types::header::HeaderValue::from_bytes(line) | ||||
|                     .expect("attempted to convert invalid header value") | ||||
|             }); | ||||
|             match entry { | ||||
|                 http_types::header::Entry::Occupied(mut  occupied) => { | ||||
|                     for value in value_iter { | ||||
|                         occupied.append(value); | ||||
|                     } | ||||
|                 }, | ||||
|                 http_types::header::Entry::Vacant(vacant) => { | ||||
|                     if let Some(first_value) = value_iter.next() { | ||||
|                         let mut occupied = vacant.insert_entry(first_value); | ||||
|                         for value in value_iter { | ||||
|                             occupied.append(value); | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         header_map | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// An `Iterator` over the fields in a `Headers` map. | ||||
| #[allow(missing_debug_implementations)] | ||||
| pub struct HeadersItems<'a> { | ||||
| @@ -940,6 +993,29 @@ mod tests { | ||||
|         assert_ne!(headers1, headers2); | ||||
|     } | ||||
|  | ||||
|     #[test] | ||||
|     #[cfg(feature = "compat")] | ||||
|     fn test_compat() { | ||||
|         use http_types; | ||||
|  | ||||
|         let mut orig_hyper_headers = Headers::new(); | ||||
|         orig_hyper_headers.set(ContentLength(11)); | ||||
|         orig_hyper_headers.set(Host::new("foo.bar", None)); | ||||
|         orig_hyper_headers.append_raw("x-foo", b"bar".to_vec()); | ||||
|         orig_hyper_headers.append_raw("x-foo", b"quux".to_vec()); | ||||
|  | ||||
|         let mut orig_http_headers = http_types::HeaderMap::new(); | ||||
|         orig_http_headers.insert(http_types::header::CONTENT_LENGTH, "11".parse().unwrap()); | ||||
|         orig_http_headers.insert(http_types::header::HOST, "foo.bar".parse().unwrap()); | ||||
|         orig_http_headers.append("x-foo", "bar".parse().unwrap()); | ||||
|         orig_http_headers.append("x-foo", "quux".parse().unwrap()); | ||||
|  | ||||
|         let conv_hyper_headers: Headers = orig_http_headers.clone().into(); | ||||
|         let conv_http_headers: http_types::HeaderMap = orig_hyper_headers.clone().into(); | ||||
|         assert_eq!(orig_hyper_headers, conv_hyper_headers); | ||||
|         assert_eq!(orig_http_headers, conv_http_headers); | ||||
|     } | ||||
|  | ||||
|     #[cfg(feature = "nightly")] | ||||
|     #[bench] | ||||
|     fn bench_headers_new(b: &mut Bencher) { | ||||
|   | ||||
| @@ -1,11 +1,16 @@ | ||||
| use std::fmt; | ||||
| #[cfg(feature = "compat")] | ||||
| use std::mem::replace; | ||||
| use std::net::SocketAddr; | ||||
|  | ||||
| #[cfg(feature = "compat")] | ||||
| use http_types; | ||||
|  | ||||
| use header::Headers; | ||||
| use http::{Body, MessageHead, RequestHead, RequestLine}; | ||||
| use method::Method; | ||||
| use uri::{self, Uri}; | ||||
| use version::HttpVersion; | ||||
| use std::net::SocketAddr; | ||||
|  | ||||
| /// An HTTP Request | ||||
| pub struct Request<B = Body> { | ||||
| @@ -132,6 +137,36 @@ impl<B> fmt::Debug for Request<B> { | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[cfg(feature = "compat")] | ||||
| impl From<Request> for http_types::Request<Body> { | ||||
|     fn from(from_req: Request) -> http_types::Request<Body> { | ||||
|         let (m, u, v, h, b) = from_req.deconstruct(); | ||||
|  | ||||
|         let to_req = http_types::Request::new(()); | ||||
|         let (mut to_parts, _) = to_req.into_parts(); | ||||
|  | ||||
|         to_parts.method = m.into(); | ||||
|         to_parts.uri = u.into(); | ||||
|         to_parts.version = v.into(); | ||||
|         to_parts.headers = h.into(); | ||||
|  | ||||
|         http_types::Request::from_parts(to_parts, b) | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[cfg(feature = "compat")] | ||||
| impl<B> From<http_types::Request<B>> for Request<B> { | ||||
|     fn from(from_req: http_types::Request<B>) -> Request<B> { | ||||
|         let (from_parts, body) = from_req.into_parts(); | ||||
|  | ||||
|         let mut to_req = Request::new(from_parts.method.into(), from_parts.uri.into()); | ||||
|         to_req.set_version(from_parts.version.into()); | ||||
|         replace(to_req.headers_mut(), from_parts.headers.into()); | ||||
|         to_req.set_body(body); | ||||
|         to_req | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// Constructs a request using a received ResponseHead and optional body | ||||
| pub fn from_wire<B>(addr: Option<SocketAddr>, incoming: RequestHead, body: B) -> Request<B> { | ||||
|     let MessageHead { version, subject: RequestLine(method, uri), headers } = incoming; | ||||
|   | ||||
| @@ -1,4 +1,9 @@ | ||||
| use std::fmt; | ||||
| #[cfg(feature = "compat")] | ||||
| use std::mem::replace; | ||||
|  | ||||
| #[cfg(feature = "compat")] | ||||
| use http_types; | ||||
|  | ||||
| use header::{Header, Headers}; | ||||
| use http::{MessageHead, ResponseHead, Body}; | ||||
| @@ -142,6 +147,30 @@ impl fmt::Debug for Response { | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[cfg(feature = "compat")] | ||||
| impl<B> From<http_types::Response<B>> for Response<B> { | ||||
|     fn from(from_res: http_types::Response<B>) -> Response<B> { | ||||
|         let (from_parts, body) = from_res.into_parts(); | ||||
|         let mut to_res = Response::new(); | ||||
|         to_res.version = from_parts.version.into(); | ||||
|         to_res.set_status(from_parts.status.into()); | ||||
|         replace(to_res.headers_mut(), from_parts.headers.into()); | ||||
|         to_res.with_body(body) | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[cfg(feature = "compat")] | ||||
| impl From<Response> for http_types::Response<Body> { | ||||
|     fn from(mut from_res: Response) -> http_types::Response<Body> { | ||||
|         let (mut to_parts, ()) = http_types::Response::new(()).into_parts(); | ||||
|         to_parts.version = from_res.version().into(); | ||||
|         to_parts.status = from_res.status().into(); | ||||
|         let from_headers = replace(from_res.headers_mut(), Headers::new()); | ||||
|         to_parts.headers = from_headers.into(); | ||||
|         http_types::Response::from_parts(to_parts, from_res.body()) | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// Constructs a response using a received ResponseHead and optional body | ||||
| #[inline] | ||||
| #[cfg(not(feature = "raw_status"))] | ||||
|   | ||||
| @@ -21,6 +21,8 @@ extern crate base64; | ||||
| extern crate bytes; | ||||
| #[macro_use] extern crate futures; | ||||
| extern crate futures_cpupool; | ||||
| #[cfg(feature = "compat")] | ||||
| extern crate http as http_types; | ||||
| extern crate httparse; | ||||
| extern crate language_tags; | ||||
| #[macro_use] extern crate log; | ||||
|   | ||||
| @@ -3,6 +3,9 @@ use std::fmt; | ||||
| use std::str::FromStr; | ||||
| use std::convert::AsRef; | ||||
|  | ||||
| #[cfg(feature = "compat")] | ||||
| use http_types; | ||||
|  | ||||
| use error::Error; | ||||
| use self::Method::{Options, Get, Post, Put, Delete, Head, Trace, Connect, Patch, | ||||
|                    Extension}; | ||||
| @@ -156,6 +159,68 @@ impl Default for Method { | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[cfg(feature = "compat")] | ||||
| impl From<http_types::Method> for Method { | ||||
|     fn from(method: http_types::Method) -> Method { | ||||
|         match method { | ||||
|             http_types::Method::GET => | ||||
|                 Method::Get, | ||||
|             http_types::Method::POST => | ||||
|                 Method::Post, | ||||
|             http_types::Method::PUT => | ||||
|                 Method::Put, | ||||
|             http_types::Method::DELETE => | ||||
|                 Method::Delete, | ||||
|             http_types::Method::HEAD => | ||||
|                 Method::Head, | ||||
|             http_types::Method::OPTIONS => | ||||
|                 Method::Options, | ||||
|             http_types::Method::CONNECT => | ||||
|                 Method::Connect, | ||||
|             http_types::Method::PATCH => | ||||
|                 Method::Patch, | ||||
|             http_types::Method::TRACE => | ||||
|                 Method::Trace, | ||||
|             _ => { | ||||
|                 method.as_ref().parse() | ||||
|                     .expect("attempted to convert invalid method") | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[cfg(feature = "compat")] | ||||
| impl From<Method> for http_types::Method { | ||||
|     fn from(method: Method) -> http_types::Method { | ||||
|         use http_types::HttpTryFrom; | ||||
|  | ||||
|         match method { | ||||
|             Method::Get => | ||||
|                 http_types::Method::GET, | ||||
|             Method::Post => | ||||
|                 http_types::Method::POST, | ||||
|             Method::Put => | ||||
|                 http_types::Method::PUT, | ||||
|             Method::Delete => | ||||
|                 http_types::Method::DELETE, | ||||
|             Method::Head => | ||||
|                 http_types::Method::HEAD, | ||||
|             Method::Options => | ||||
|                 http_types::Method::OPTIONS, | ||||
|             Method::Connect => | ||||
|                 http_types::Method::CONNECT, | ||||
|             Method::Patch => | ||||
|                 http_types::Method::PATCH, | ||||
|             Method::Trace => | ||||
|                 http_types::Method::TRACE, | ||||
|             Method::Extension(s) => { | ||||
|                 HttpTryFrom::try_from(s.as_str()) | ||||
|                     .expect("attempted to convert invalid method") | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[cfg(test)] | ||||
| mod tests { | ||||
|     use std::collections::HashMap; | ||||
| @@ -210,4 +275,25 @@ mod tests { | ||||
|         assert_eq!(Put.as_ref(), "PUT"); | ||||
|         assert_eq!(Extension("MOVE".to_owned()).as_ref(), "MOVE"); | ||||
|     } | ||||
|  | ||||
|     #[test] | ||||
|     #[cfg(feature = "compat")] | ||||
|     fn test_compat() { | ||||
|         use http_types::{self, HttpTryFrom}; | ||||
|  | ||||
|         let methods = vec![ | ||||
|             "GET", | ||||
|             "POST", | ||||
|             "PUT", | ||||
|             "MOVE" | ||||
|         ]; | ||||
|         for method in methods { | ||||
|             let orig_hyper_method = Method::from_str(method).unwrap(); | ||||
|             let orig_http_method = http_types::Method::try_from(method).unwrap(); | ||||
|             let conv_hyper_method: Method = orig_http_method.clone().into(); | ||||
|             let conv_http_method: http_types::Method = orig_hyper_method.clone().into(); | ||||
|             assert_eq!(orig_hyper_method, conv_hyper_method); | ||||
|             assert_eq!(orig_http_method, conv_http_method); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
							
								
								
									
										7
									
								
								src/server/compat.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/server/compat.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| //! Wrappers to build compatibility with the `http` crate. | ||||
|  | ||||
| pub use super::compat_impl::{ | ||||
|     CompatFuture, | ||||
|     CompatService, | ||||
|     NewCompatService | ||||
| }; | ||||
							
								
								
									
										82
									
								
								src/server/compat_impl.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								src/server/compat_impl.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,82 @@ | ||||
| use std::io::{Error as IoError}; | ||||
|  | ||||
| use futures::{Future, Poll}; | ||||
| use http_types; | ||||
| use tokio_service::{NewService, Service}; | ||||
|  | ||||
| use error::Error; | ||||
| use http::Body; | ||||
| use http::request::Request; | ||||
| use http::response::Response; | ||||
|  | ||||
| /// Wraps a `Future` returning an `http::Response` into | ||||
| /// a `Future` returning a `hyper::server::Response`. | ||||
| #[derive(Debug)] | ||||
| pub struct CompatFuture<F> { | ||||
|     future: F | ||||
| } | ||||
|  | ||||
| impl<F, Bd> Future for CompatFuture<F> | ||||
|     where F: Future<Item=http_types::Response<Bd>, Error=Error> | ||||
| { | ||||
|     type Item = Response<Bd>; | ||||
|     type Error = Error; | ||||
|  | ||||
|     fn poll(&mut self) -> Poll<Self::Item, Self::Error> { | ||||
|         self.future.poll() | ||||
|             .map(|a| a.map(|res| res.into())) | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// Wraps a `Service` taking an `http::Request` and returning | ||||
| /// an `http::Response` into a `Service` taking a `hyper::server::Request`, | ||||
| /// and returning a `hyper::server::Response`. | ||||
| #[derive(Debug)] | ||||
| pub struct CompatService<S> { | ||||
|     service: S | ||||
| } | ||||
|  | ||||
| pub fn service<S>(service: S) -> CompatService<S> { | ||||
|     CompatService { service: service } | ||||
| } | ||||
|  | ||||
| impl<S, Bd> Service for CompatService<S> | ||||
|     where S: Service<Request=http_types::Request<Body>, Response=http_types::Response<Bd>, Error=Error> | ||||
| { | ||||
|     type Request = Request; | ||||
|     type Response = Response<Bd>; | ||||
|     type Error = Error; | ||||
|     type Future = CompatFuture<S::Future>; | ||||
|  | ||||
|     fn call(&self, req: Self::Request) -> Self::Future { | ||||
|         CompatFuture { | ||||
|             future: self.service.call(req.into()) | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// Wraps a `NewService` taking an `http::Request` and returning | ||||
| /// an `http::Response` into a `NewService` taking a `hyper::server::Request`, | ||||
| /// and returning a `hyper::server::Response`. | ||||
| #[derive(Debug)] | ||||
| pub struct NewCompatService<S> { | ||||
|     new_service: S | ||||
| } | ||||
|  | ||||
| pub fn new_service<S>(new_service: S) -> NewCompatService<S> { | ||||
|     NewCompatService { new_service: new_service } | ||||
| } | ||||
|  | ||||
| impl<S, Bd> NewService for NewCompatService<S> | ||||
|     where S: NewService<Request=http_types::Request<Body>, Response=http_types::Response<Bd>, Error=Error> | ||||
| { | ||||
|     type Request = Request; | ||||
|     type Response = Response<Bd>; | ||||
|     type Error = Error; | ||||
|     type Instance = CompatService<S::Instance>; | ||||
|  | ||||
|     fn new_service(&self) -> Result<Self::Instance, IoError> { | ||||
|         self.new_service.new_service() | ||||
|             .map(service) | ||||
|     } | ||||
| } | ||||
| @@ -3,6 +3,11 @@ | ||||
| //! A `Server` is created to listen on a port, parse HTTP requests, and hand | ||||
| //! them off to a `Service`. | ||||
|  | ||||
| #[cfg(feature = "compat")] | ||||
| mod compat_impl; | ||||
| #[cfg(feature = "compat")] | ||||
| pub mod compat; | ||||
|  | ||||
| use std::cell::RefCell; | ||||
| use std::fmt; | ||||
| use std::io; | ||||
| @@ -16,6 +21,9 @@ use futures::task::{self, Task}; | ||||
| use futures::{Future, Stream, Poll, Async, Sink, StartSend, AsyncSink}; | ||||
| use futures::future::Map; | ||||
|  | ||||
| #[cfg(feature = "compat")] | ||||
| use http_types; | ||||
|  | ||||
| use tokio_io::{AsyncRead, AsyncWrite}; | ||||
| use tokio::reactor::{Core, Handle, Timeout}; | ||||
| use tokio::net::TcpListener; | ||||
| @@ -27,6 +35,8 @@ pub use tokio_service::{NewService, Service}; | ||||
| use http; | ||||
| use http::response; | ||||
| use http::request; | ||||
| #[cfg(feature = "compat")] | ||||
| use http::Body; | ||||
|  | ||||
| pub use http::response::Response; | ||||
| pub use http::request::Request; | ||||
| @@ -103,6 +113,18 @@ impl<B: AsRef<[u8]> + 'static> Http<B> { | ||||
|         }) | ||||
|     } | ||||
|  | ||||
|     /// Bind a `NewService` using types from the `http` crate. | ||||
|     /// | ||||
|     /// See `Http::bind`. | ||||
|     #[cfg(feature = "compat")] | ||||
|     pub fn bind_compat<S, Bd>(&self, addr: &SocketAddr, new_service: S) -> ::Result<Server<compat::NewCompatService<S>, Bd>> | ||||
|         where S: NewService<Request = http_types::Request<Body>, Response = http_types::Response<Bd>, Error = ::Error> + | ||||
|                     Send + Sync + 'static, | ||||
|               Bd: Stream<Item=B, Error=::Error>, | ||||
|     { | ||||
|         self.bind(addr, self::compat_impl::new_service(new_service)) | ||||
|     } | ||||
|  | ||||
|     /// Use this `Http` instance to create a new server task which handles the | ||||
|     /// connection `io` provided. | ||||
|     /// | ||||
| @@ -131,6 +153,25 @@ impl<B: AsRef<[u8]> + 'static> Http<B> { | ||||
|             remote_addr: remote_addr, | ||||
|         }) | ||||
|     } | ||||
|  | ||||
|     /// Bind a `Service` using types from the `http` crate. | ||||
|     /// | ||||
|     /// See `Http::bind_connection`. | ||||
|     #[cfg(feature = "compat")] | ||||
|     pub fn bind_connection_compat<S, I, Bd>(&self, | ||||
|                                  handle: &Handle, | ||||
|                                  io: I, | ||||
|                                  remote_addr: SocketAddr, | ||||
|                                  service: S) | ||||
|         where S: Service<Request = http_types::Request<Body>, Response = http_types::Response<Bd>, Error = ::Error> + 'static, | ||||
|               Bd: Stream<Item=B, Error=::Error> + 'static, | ||||
|               I: AsyncRead + AsyncWrite + 'static, | ||||
|     { | ||||
|         self.bind_server(handle, io, HttpService { | ||||
|             inner: compat_impl::service(service), | ||||
|             remote_addr: remote_addr, | ||||
|         }) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<B> Clone for Http<B> { | ||||
|   | ||||
| @@ -2,6 +2,9 @@ | ||||
| use std::fmt; | ||||
| use std::cmp::Ordering; | ||||
|  | ||||
| #[cfg(feature = "compat")] | ||||
| use http_types; | ||||
|  | ||||
| /// An HTTP status code (`status-code` in RFC 7230 et al.). | ||||
| /// | ||||
| /// This enum contains all common status codes and an Unregistered | ||||
| @@ -596,6 +599,22 @@ impl From<StatusCode> for u16 { | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[cfg(feature = "compat")] | ||||
| impl From<http_types::StatusCode> for StatusCode { | ||||
|     fn from(status: http_types::StatusCode) -> StatusCode { | ||||
|         StatusCode::try_from(status.as_u16()) | ||||
|             .expect("attempted to convert invalid status code") | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[cfg(feature = "compat")] | ||||
| impl From<StatusCode> for http_types::StatusCode { | ||||
|     fn from(status: StatusCode) -> http_types::StatusCode { | ||||
|         http_types::StatusCode::from_u16(status.as_u16()) | ||||
|             .expect("attempted to convert invalid status code") | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// The class of an HTTP `status-code`. | ||||
| /// | ||||
| /// [RFC 7231, section 6 (Response Status Codes)](https://tools.ietf.org/html/rfc7231#section-6): | ||||
| @@ -746,4 +765,18 @@ mod tests { | ||||
|         StatusCode::try_from(0).unwrap_err(); | ||||
|         StatusCode::try_from(1000).unwrap_err(); | ||||
|     } | ||||
|  | ||||
|     #[test] | ||||
|     #[cfg(feature = "compat")] | ||||
|     fn test_compat() { | ||||
|         use http_types::{self, HttpTryFrom}; | ||||
|         for i in 100..600 { | ||||
|             let orig_hyper_status = StatusCode::try_from(i).unwrap(); | ||||
|             let orig_http_status = http_types::StatusCode::try_from(i).unwrap(); | ||||
|             let conv_hyper_status: StatusCode = orig_http_status.into(); | ||||
|             let conv_http_status: http_types::StatusCode = orig_hyper_status.into(); | ||||
|             assert_eq!(orig_hyper_status, conv_hyper_status); | ||||
|             assert_eq!(orig_http_status, conv_http_status); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
							
								
								
									
										20
									
								
								src/uri.rs
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								src/uri.rs
									
									
									
									
									
								
							| @@ -2,6 +2,9 @@ use std::error::Error as StdError; | ||||
| use std::fmt::{Display, self}; | ||||
| use std::str::{self, FromStr}; | ||||
|  | ||||
| #[cfg(feature = "compat")] | ||||
| use http_types; | ||||
|  | ||||
| use ::common::ByteStr; | ||||
| use bytes::{BufMut, Bytes, BytesMut}; | ||||
|  | ||||
| @@ -315,6 +318,23 @@ impl Display for Uri { | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[cfg(feature = "compat")] | ||||
| impl From<http_types::Uri> for Uri { | ||||
|     fn from(uri: http_types::Uri) -> Uri { | ||||
|         uri.to_string().parse() | ||||
|             .expect("attempted to convert invalid uri") | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[cfg(feature = "compat")] | ||||
| impl From<Uri> for http_types::Uri { | ||||
|     fn from(uri: Uri) -> http_types::Uri { | ||||
|         let bytes = uri.source.into_bytes(); | ||||
|         http_types::Uri::from_shared(bytes) | ||||
|             .expect("attempted to convert invalid uri") | ||||
|     } | ||||
| } | ||||
|  | ||||
| pub unsafe fn from_utf8_unchecked(slice: Bytes) -> Result<Uri, UriError> { | ||||
|     Uri::new(ByteStr::from_utf8_unchecked(slice)) | ||||
| } | ||||
|   | ||||
| @@ -5,6 +5,9 @@ | ||||
| use std::fmt; | ||||
| use std::str::FromStr; | ||||
|  | ||||
| #[cfg(feature = "compat")] | ||||
| use http_types; | ||||
|  | ||||
| use error::Error; | ||||
| use self::HttpVersion::{Http09, Http10, Http11, H2, H2c}; | ||||
|  | ||||
| @@ -58,6 +61,39 @@ impl Default for HttpVersion { | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[cfg(feature = "compat")] | ||||
| impl From<http_types::Version> for HttpVersion { | ||||
|     fn from(v: http_types::Version) -> HttpVersion { | ||||
|         match v { | ||||
|             http_types::Version::HTTP_09 => | ||||
|                 HttpVersion::Http09, | ||||
|             http_types::Version::HTTP_10 => | ||||
|                 HttpVersion::Http10, | ||||
|             http_types::Version::HTTP_11 => | ||||
|                 HttpVersion::Http11, | ||||
|             http_types::Version::HTTP_2 => | ||||
|                 HttpVersion::H2 | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[cfg(feature = "compat")] | ||||
| impl From<HttpVersion> for http_types::Version { | ||||
|     fn from(v: HttpVersion) -> http_types::Version { | ||||
|         match v { | ||||
|             HttpVersion::Http09 => | ||||
|                 http_types::Version::HTTP_09, | ||||
|             HttpVersion::Http10 => | ||||
|                 http_types::Version::HTTP_10, | ||||
|             HttpVersion::Http11 => | ||||
|                 http_types::Version::HTTP_11, | ||||
|             HttpVersion::H2 => | ||||
|                 http_types::Version::HTTP_2, | ||||
|             _ => panic!("attempted to convert unexpected http version") | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[cfg(test)] | ||||
| mod tests { | ||||
|     use std::str::FromStr; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user