From 2c7da28ef9fab2265c8149daedfdfc60b7ba3641 Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Tue, 26 Mar 2019 11:43:22 -0700 Subject: [PATCH] move high level client code to awc crate --- src/client/connection.rs | 10 +- src/client/h1proto.rs | 38 +-- src/client/h2proto.rs | 9 +- src/client/mod.rs | 4 - src/client/request.rs | 699 --------------------------------------- src/client/response.rs | 116 ------- src/h1/client.rs | 9 +- src/h1/decoder.rs | 15 +- src/h1/dispatcher.rs | 2 +- src/lib.rs | 62 +--- src/response.rs | 2 - src/ws/client/connect.rs | 37 ++- src/ws/client/service.rs | 50 +-- test-server/Cargo.toml | 3 +- test-server/src/lib.rs | 121 ++++--- tests/test_client.rs | 31 +- tests/test_server.rs | 129 +++----- 17 files changed, 211 insertions(+), 1126 deletions(-) delete mode 100644 src/client/request.rs delete mode 100644 src/client/response.rs diff --git a/src/client/connection.rs b/src/client/connection.rs index 8de23bd2..e8c1201a 100644 --- a/src/client/connection.rs +++ b/src/client/connection.rs @@ -6,11 +6,11 @@ use futures::Future; use h2::client::SendRequest; use crate::body::MessageBody; -use crate::message::RequestHead; +use crate::message::{RequestHead, ResponseHead}; +use crate::payload::Payload; use super::error::SendRequestError; use super::pool::Acquired; -use super::response::ClientResponse; use super::{h1proto, h2proto}; pub(crate) enum ConnectionType { @@ -19,7 +19,7 @@ pub(crate) enum ConnectionType { } pub trait Connection { - type Future: Future; + type Future: Future; /// Send request and body fn send_request( @@ -80,7 +80,7 @@ impl Connection for IoConnection where T: AsyncRead + AsyncWrite + 'static, { - type Future = Box>; + type Future = Box>; fn send_request( mut self, @@ -117,7 +117,7 @@ where A: AsyncRead + AsyncWrite + 'static, B: AsyncRead + AsyncWrite + 'static, { - type Future = Box>; + type Future = Box>; fn send_request( self, diff --git a/src/client/h1proto.rs b/src/client/h1proto.rs index 34521cc2..2e29484f 100644 --- a/src/client/h1proto.rs +++ b/src/client/h1proto.rs @@ -2,17 +2,18 @@ use std::{io, time}; use actix_codec::{AsyncRead, AsyncWrite, Framed}; use bytes::Bytes; -use futures::future::{err, ok, Either}; +use futures::future::{ok, Either}; use futures::{Async, Future, Poll, Sink, Stream}; +use crate::error::PayloadError; +use crate::h1; +use crate::message::{RequestHead, ResponseHead}; +use crate::payload::{Payload, PayloadStream}; + use super::connection::{ConnectionLifetime, ConnectionType, IoConnection}; use super::error::{ConnectError, SendRequestError}; use super::pool::Acquired; -use super::response::ClientResponse; use crate::body::{BodyLength, MessageBody}; -use crate::error::PayloadError; -use crate::h1; -use crate::message::RequestHead; pub(crate) fn send_request( io: T, @@ -20,7 +21,7 @@ pub(crate) fn send_request( body: B, created: time::Instant, pool: Option>, -) -> impl Future +) -> impl Future where T: AsyncRead + AsyncWrite + 'static, B: MessageBody, @@ -50,19 +51,20 @@ where .into_future() .map_err(|(e, _)| SendRequestError::from(e)) .and_then(|(item, framed)| { - if let Some(mut res) = item { + if let Some(res) = item { match framed.get_codec().message_type() { h1::MessageType::None => { let force_close = !framed.get_codec().keepalive(); - release_connection(framed, force_close) + release_connection(framed, force_close); + Ok((res, Payload::None)) } _ => { - res.set_payload(Payload::stream(framed).into()); + let pl: PayloadStream = Box::new(PlStream::new(framed)); + Ok((res, pl.into())) } } - ok(res) } else { - err(ConnectError::Disconnected.into()) + Err(ConnectError::Disconnected.into()) } }) }) @@ -199,21 +201,19 @@ where } } -pub(crate) struct Payload { +pub(crate) struct PlStream { framed: Option>, } -impl Payload { - pub fn stream( - framed: Framed, - ) -> Box> { - Box::new(Payload { +impl PlStream { + fn new(framed: Framed) -> Self { + PlStream { framed: Some(framed.map_codec(|codec| codec.into_payload_codec())), - }) + } } } -impl Stream for Payload { +impl Stream for PlStream { type Item = Bytes; type Error = PayloadError; diff --git a/src/client/h2proto.rs b/src/client/h2proto.rs index bf2d3e1b..9ad72262 100644 --- a/src/client/h2proto.rs +++ b/src/client/h2proto.rs @@ -9,13 +9,12 @@ use http::header::{HeaderValue, CONNECTION, CONTENT_LENGTH, TRANSFER_ENCODING}; use http::{request::Request, HttpTryFrom, Method, Version}; use crate::body::{BodyLength, MessageBody}; -use crate::message::{Message, RequestHead, ResponseHead}; +use crate::message::{RequestHead, ResponseHead}; use crate::payload::Payload; use super::connection::{ConnectionType, IoConnection}; use super::error::SendRequestError; use super::pool::Acquired; -use super::response::ClientResponse; pub(crate) fn send_request( io: SendRequest, @@ -23,7 +22,7 @@ pub(crate) fn send_request( body: B, created: time::Instant, pool: Option>, -) -> impl Future +) -> impl Future where T: AsyncRead + AsyncWrite + 'static, B: MessageBody, @@ -105,12 +104,12 @@ where let (parts, body) = resp.into_parts(); let payload = if head_req { Payload::None } else { body.into() }; - let mut head: Message = Message::new(); + let mut head = ResponseHead::default(); head.version = parts.version; head.status = parts.status; head.headers = parts.headers; - Ok(ClientResponse { head, payload }) + Ok((head, payload)) }) .from_err() } diff --git a/src/client/mod.rs b/src/client/mod.rs index 86b1a0cc..87c37474 100644 --- a/src/client/mod.rs +++ b/src/client/mod.rs @@ -5,11 +5,7 @@ mod error; mod h1proto; mod h2proto; mod pool; -mod request; -mod response; pub use self::connection::Connection; pub use self::connector::Connector; pub use self::error::{ConnectError, InvalidUrl, SendRequestError}; -pub use self::request::{ClientRequest, ClientRequestBuilder}; -pub use self::response::ClientResponse; diff --git a/src/client/request.rs b/src/client/request.rs deleted file mode 100644 index 134a4264..00000000 --- a/src/client/request.rs +++ /dev/null @@ -1,699 +0,0 @@ -use std::fmt; -use std::io::Write; - -use actix_service::Service; -use bytes::{BufMut, Bytes, BytesMut}; -#[cfg(feature = "cookies")] -use cookie::{Cookie, CookieJar}; -use futures::future::{err, Either}; -use futures::{Future, Stream}; -use serde::Serialize; -use serde_json; - -use crate::body::{BodyStream, MessageBody}; -use crate::error::Error; -use crate::header::{self, Header, IntoHeaderValue}; -use crate::http::{ - uri, Error as HttpError, HeaderMap, HeaderName, HeaderValue, HttpTryFrom, Method, - Uri, Version, -}; -use crate::message::{ConnectionType, Head, RequestHead}; - -use super::connection::Connection; -use super::error::{ConnectError, InvalidUrl, SendRequestError}; -use super::response::ClientResponse; - -/// An HTTP Client Request -/// -/// ```rust -/// use futures::future::{Future, lazy}; -/// use actix_rt::System; -/// use actix_http::client; -/// -/// fn main() { -/// System::new("test").block_on(lazy(|| { -/// let mut connector = client::Connector::new().service(); -/// -/// client::ClientRequest::get("http://www.rust-lang.org") // <- Create request builder -/// .header("User-Agent", "Actix-web") -/// .finish().unwrap() -/// .send(&mut connector) // <- Send http request -/// .map_err(|_| ()) -/// .and_then(|response| { // <- server http response -/// println!("Response: {:?}", response); -/// Ok(()) -/// }) -/// })); -/// } -/// ``` -pub struct ClientRequest { - head: RequestHead, - body: B, -} - -impl ClientRequest<()> { - /// Create client request builder - pub fn build() -> ClientRequestBuilder { - ClientRequestBuilder { - head: Some(RequestHead::default()), - err: None, - #[cfg(feature = "cookies")] - cookies: None, - default_headers: true, - } - } - - /// Create request builder for `GET` request - pub fn get(uri: U) -> ClientRequestBuilder - where - Uri: HttpTryFrom, - { - let mut builder = ClientRequest::build(); - builder.method(Method::GET).uri(uri); - builder - } - - /// Create request builder for `HEAD` request - pub fn head(uri: U) -> ClientRequestBuilder - where - Uri: HttpTryFrom, - { - let mut builder = ClientRequest::build(); - builder.method(Method::HEAD).uri(uri); - builder - } - - /// Create request builder for `POST` request - pub fn post(uri: U) -> ClientRequestBuilder - where - Uri: HttpTryFrom, - { - let mut builder = ClientRequest::build(); - builder.method(Method::POST).uri(uri); - builder - } - - /// Create request builder for `PUT` request - pub fn put(uri: U) -> ClientRequestBuilder - where - Uri: HttpTryFrom, - { - let mut builder = ClientRequest::build(); - builder.method(Method::PUT).uri(uri); - builder - } - - /// Create request builder for `DELETE` request - pub fn delete(uri: U) -> ClientRequestBuilder - where - Uri: HttpTryFrom, - { - let mut builder = ClientRequest::build(); - builder.method(Method::DELETE).uri(uri); - builder - } -} - -impl ClientRequest -where - B: MessageBody, -{ - /// Create new client request - pub fn new(head: RequestHead, body: B) -> Self { - ClientRequest { head, body } - } - - /// Get the request URI - #[inline] - pub fn uri(&self) -> &Uri { - &self.head.uri - } - - /// Set client request URI - #[inline] - pub fn set_uri(&mut self, uri: Uri) { - self.head.uri = uri - } - - /// Get the request method - #[inline] - pub fn method(&self) -> &Method { - &self.head.method - } - - /// Set HTTP `Method` for the request - #[inline] - pub fn set_method(&mut self, method: Method) { - self.head.method = method - } - - /// Get HTTP version for the request - #[inline] - pub fn version(&self) -> Version { - self.head.version - } - - /// Set http `Version` for the request - #[inline] - pub fn set_version(&mut self, version: Version) { - self.head.version = version - } - - /// Get the headers from the request - #[inline] - pub fn headers(&self) -> &HeaderMap { - &self.head.headers - } - - /// Get a mutable reference to the headers - #[inline] - pub fn headers_mut(&mut self) -> &mut HeaderMap { - &mut self.head.headers - } - - /// Deconstruct ClientRequest to a RequestHead and body tuple - pub fn into_parts(self) -> (RequestHead, B) { - (self.head, self.body) - } - - // Send request - /// - /// This method returns a future that resolves to a ClientResponse - pub fn send( - self, - connector: &mut T, - ) -> impl Future - where - B: 'static, - T: Service, - T::Response: Connection, - { - let Self { head, body } = self; - - let uri = head.uri.clone(); - - // validate uri - if uri.host().is_none() { - Either::A(err(InvalidUrl::MissingHost.into())) - } else if uri.scheme_part().is_none() { - Either::A(err(InvalidUrl::MissingScheme.into())) - } else if let Some(scheme) = uri.scheme_part() { - match scheme.as_str() { - "http" | "ws" | "https" | "wss" => Either::B( - connector - // connect to the host - .call(uri) - .from_err() - // send request - .and_then(move |connection| connection.send_request(head, body)), - ), - _ => Either::A(err(InvalidUrl::UnknownScheme.into())), - } - } else { - Either::A(err(InvalidUrl::UnknownScheme.into())) - } - } -} - -impl fmt::Debug for ClientRequest -where - B: MessageBody, -{ - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - writeln!( - f, - "\nClientRequest {:?} {}:{}", - self.head.version, self.head.method, self.head.uri - )?; - writeln!(f, " headers:")?; - for (key, val) in self.head.headers.iter() { - writeln!(f, " {:?}: {:?}", key, val)?; - } - Ok(()) - } -} - -/// An HTTP Client request builder -/// -/// This type can be used to construct an instance of `ClientRequest` through a -/// builder-like pattern. -pub struct ClientRequestBuilder { - head: Option, - err: Option, - #[cfg(feature = "cookies")] - cookies: Option, - default_headers: bool, -} - -impl ClientRequestBuilder { - /// Set HTTP URI of request. - #[inline] - pub fn uri(&mut self, uri: U) -> &mut Self - where - Uri: HttpTryFrom, - { - match Uri::try_from(uri) { - Ok(uri) => { - if let Some(parts) = parts(&mut self.head, &self.err) { - parts.uri = uri; - } - } - Err(e) => self.err = Some(e.into()), - } - self - } - - /// Set HTTP method of this request. - #[inline] - pub fn method(&mut self, method: Method) -> &mut Self { - if let Some(parts) = parts(&mut self.head, &self.err) { - parts.method = method; - } - self - } - - /// Set HTTP method of this request. - #[inline] - pub fn get_method(&mut self) -> &Method { - let parts = self.head.as_ref().expect("cannot reuse request builder"); - &parts.method - } - - /// Set HTTP version of this request. - /// - /// By default requests's HTTP version depends on network stream - #[inline] - pub fn version(&mut self, version: Version) -> &mut Self { - if let Some(parts) = parts(&mut self.head, &self.err) { - parts.version = version; - } - self - } - - /// Set a header. - /// - /// ```rust - /// # extern crate mime; - /// # extern crate actix_http; - /// # - /// use actix_http::{client, http}; - /// - /// fn main() { - /// let req = client::ClientRequest::build() - /// .set(http::header::Date::now()) - /// .set(http::header::ContentType(mime::TEXT_HTML)) - /// .finish() - /// .unwrap(); - /// } - /// ``` - pub fn set(&mut self, hdr: H) -> &mut Self { - if let Some(parts) = parts(&mut self.head, &self.err) { - match hdr.try_into() { - Ok(value) => { - parts.headers.insert(H::name(), value); - } - Err(e) => self.err = Some(e.into()), - } - } - self - } - - /// Append a header. - /// - /// Header gets appended to existing header. - /// To override header use `set_header()` method. - /// - /// ```rust - /// # extern crate actix_http; - /// # - /// use actix_http::{client, http}; - /// - /// fn main() { - /// let req = client::ClientRequest::build() - /// .header("X-TEST", "value") - /// .header(http::header::CONTENT_TYPE, "application/json") - /// .finish() - /// .unwrap(); - /// } - /// ``` - pub fn header(&mut self, key: K, value: V) -> &mut Self - where - HeaderName: HttpTryFrom, - V: IntoHeaderValue, - { - if let Some(parts) = parts(&mut self.head, &self.err) { - match HeaderName::try_from(key) { - Ok(key) => match value.try_into() { - Ok(value) => { - parts.headers.append(key, value); - } - Err(e) => self.err = Some(e.into()), - }, - Err(e) => self.err = Some(e.into()), - }; - } - self - } - - /// Set a header. - pub fn set_header(&mut self, key: K, value: V) -> &mut Self - where - HeaderName: HttpTryFrom, - V: IntoHeaderValue, - { - if let Some(parts) = parts(&mut self.head, &self.err) { - match HeaderName::try_from(key) { - Ok(key) => match value.try_into() { - Ok(value) => { - parts.headers.insert(key, value); - } - Err(e) => self.err = Some(e.into()), - }, - Err(e) => self.err = Some(e.into()), - }; - } - self - } - - /// Set a header only if it is not yet set. - pub fn set_header_if_none(&mut self, key: K, value: V) -> &mut Self - where - HeaderName: HttpTryFrom, - V: IntoHeaderValue, - { - if let Some(parts) = parts(&mut self.head, &self.err) { - match HeaderName::try_from(key) { - Ok(key) => { - if !parts.headers.contains_key(&key) { - match value.try_into() { - Ok(value) => { - parts.headers.insert(key, value); - } - Err(e) => self.err = Some(e.into()), - } - } - } - Err(e) => self.err = Some(e.into()), - }; - } - self - } - - /// Enable connection upgrade - #[inline] - pub fn upgrade(&mut self, value: V) -> &mut Self - where - V: IntoHeaderValue, - { - { - if let Some(parts) = parts(&mut self.head, &self.err) { - parts.set_connection_type(ConnectionType::Upgrade); - } - } - self.set_header(header::UPGRADE, value) - } - - /// Close connection - #[inline] - pub fn close(&mut self) -> &mut Self { - if let Some(parts) = parts(&mut self.head, &self.err) { - parts.set_connection_type(ConnectionType::Close); - } - self - } - - /// Set request's content type - #[inline] - pub fn content_type(&mut self, value: V) -> &mut Self - where - HeaderValue: HttpTryFrom, - { - if let Some(parts) = parts(&mut self.head, &self.err) { - match HeaderValue::try_from(value) { - Ok(value) => { - parts.headers.insert(header::CONTENT_TYPE, value); - } - Err(e) => self.err = Some(e.into()), - }; - } - self - } - - /// Set content length - #[inline] - pub fn content_length(&mut self, len: u64) -> &mut Self { - let mut wrt = BytesMut::new().writer(); - let _ = write!(wrt, "{}", len); - self.header(header::CONTENT_LENGTH, wrt.get_mut().take().freeze()) - } - - #[cfg(feature = "cookies")] - /// Set a cookie - /// - /// ```rust - /// # extern crate actix_http; - /// use actix_http::{client, http}; - /// - /// fn main() { - /// let req = client::ClientRequest::build() - /// .cookie( - /// http::Cookie::build("name", "value") - /// .domain("www.rust-lang.org") - /// .path("/") - /// .secure(true) - /// .http_only(true) - /// .finish(), - /// ) - /// .finish() - /// .unwrap(); - /// } - /// ``` - pub fn cookie<'c>(&mut self, cookie: Cookie<'c>) -> &mut Self { - if self.cookies.is_none() { - let mut jar = CookieJar::new(); - jar.add(cookie.into_owned()); - self.cookies = Some(jar) - } else { - self.cookies.as_mut().unwrap().add(cookie.into_owned()); - } - self - } - - /// Do not add default request headers. - /// By default `Accept-Encoding` and `User-Agent` headers are set. - pub fn no_default_headers(&mut self) -> &mut Self { - self.default_headers = false; - self - } - - /// This method calls provided closure with builder reference if - /// value is `true`. - pub fn if_true(&mut self, value: bool, f: F) -> &mut Self - where - F: FnOnce(&mut ClientRequestBuilder), - { - if value { - f(self); - } - self - } - - /// This method calls provided closure with builder reference if - /// value is `Some`. - pub fn if_some(&mut self, value: Option, f: F) -> &mut Self - where - F: FnOnce(T, &mut ClientRequestBuilder), - { - if let Some(val) = value { - f(val, self); - } - self - } - - /// Set a body and generate `ClientRequest`. - /// - /// `ClientRequestBuilder` can not be used after this call. - pub fn body( - &mut self, - body: B, - ) -> Result, HttpError> { - if let Some(e) = self.err.take() { - return Err(e); - } - - if self.default_headers { - // enable br only for https - let https = if let Some(parts) = parts(&mut self.head, &self.err) { - parts - .uri - .scheme_part() - .map(|s| s == &uri::Scheme::HTTPS) - .unwrap_or(true) - } else { - true - }; - - if https { - self.set_header_if_none(header::ACCEPT_ENCODING, "br, gzip, deflate"); - } else { - self.set_header_if_none(header::ACCEPT_ENCODING, "gzip, deflate"); - } - - // set request host header - if let Some(parts) = parts(&mut self.head, &self.err) { - if let Some(host) = parts.uri.host() { - if !parts.headers.contains_key(header::HOST) { - let mut wrt = BytesMut::with_capacity(host.len() + 5).writer(); - - let _ = match parts.uri.port_u16() { - None | Some(80) | Some(443) => write!(wrt, "{}", host), - Some(port) => write!(wrt, "{}:{}", host, port), - }; - - match wrt.get_mut().take().freeze().try_into() { - Ok(value) => { - parts.headers.insert(header::HOST, value); - } - Err(e) => self.err = Some(e.into()), - } - } - } - } - - // user agent - self.set_header_if_none( - header::USER_AGENT, - concat!("actix-http/", env!("CARGO_PKG_VERSION")), - ); - } - - #[allow(unused_mut)] - let mut head = self.head.take().expect("cannot reuse request builder"); - - #[cfg(feature = "cookies")] - { - use percent_encoding::{percent_encode, USERINFO_ENCODE_SET}; - use std::fmt::Write; - - // set cookies - if let Some(ref mut jar) = self.cookies { - let mut cookie = String::new(); - for c in jar.delta() { - let name = percent_encode(c.name().as_bytes(), USERINFO_ENCODE_SET); - let value = - percent_encode(c.value().as_bytes(), USERINFO_ENCODE_SET); - let _ = write!(&mut cookie, "; {}={}", name, value); - } - head.headers.insert( - header::COOKIE, - HeaderValue::from_str(&cookie.as_str()[2..]).unwrap(), - ); - } - } - Ok(ClientRequest { head, body }) - } - - /// Set a JSON body and generate `ClientRequest` - /// - /// `ClientRequestBuilder` can not be used after this call. - pub fn json( - &mut self, - value: T, - ) -> Result, Error> { - let body = serde_json::to_string(&value)?; - - let contains = if let Some(head) = parts(&mut self.head, &self.err) { - head.headers.contains_key(header::CONTENT_TYPE) - } else { - true - }; - if !contains { - self.header(header::CONTENT_TYPE, "application/json"); - } - - Ok(self.body(body)?) - } - - /// Set a urlencoded body and generate `ClientRequest` - /// - /// `ClientRequestBuilder` can not be used after this call. - pub fn form( - &mut self, - value: T, - ) -> Result, Error> { - let body = serde_urlencoded::to_string(&value)?; - - let contains = if let Some(head) = parts(&mut self.head, &self.err) { - head.headers.contains_key(header::CONTENT_TYPE) - } else { - true - }; - if !contains { - self.header(header::CONTENT_TYPE, "application/x-www-form-urlencoded"); - } - - Ok(self.body(body)?) - } - - /// Set an streaming body and generate `ClientRequest`. - /// - /// `ClientRequestBuilder` can not be used after this call. - pub fn stream( - &mut self, - stream: S, - ) -> Result, HttpError> - where - S: Stream, - E: Into + 'static, - { - self.body(BodyStream::new(stream)) - } - - /// Set an empty body and generate `ClientRequest`. - /// - /// `ClientRequestBuilder` can not be used after this call. - pub fn finish(&mut self) -> Result, HttpError> { - self.body(()) - } - - /// This method construct new `ClientRequestBuilder` - pub fn take(&mut self) -> ClientRequestBuilder { - ClientRequestBuilder { - head: self.head.take(), - err: self.err.take(), - #[cfg(feature = "cookies")] - cookies: self.cookies.take(), - default_headers: self.default_headers, - } - } -} - -#[inline] -fn parts<'a>( - parts: &'a mut Option, - err: &Option, -) -> Option<&'a mut RequestHead> { - if err.is_some() { - return None; - } - parts.as_mut() -} - -impl fmt::Debug for ClientRequestBuilder { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - if let Some(ref parts) = self.head { - writeln!( - f, - "\nClientRequestBuilder {:?} {}:{}", - parts.version, parts.method, parts.uri - )?; - writeln!(f, " headers:")?; - for (key, val) in parts.headers.iter() { - writeln!(f, " {:?}: {:?}", key, val)?; - } - Ok(()) - } else { - write!(f, "ClientRequestBuilder(Consumed)") - } - } -} diff --git a/src/client/response.rs b/src/client/response.rs deleted file mode 100644 index 7c6cdf64..00000000 --- a/src/client/response.rs +++ /dev/null @@ -1,116 +0,0 @@ -use std::cell::{Ref, RefMut}; -use std::fmt; - -use bytes::Bytes; -use futures::{Poll, Stream}; -use http::{HeaderMap, StatusCode, Version}; - -use crate::error::PayloadError; -use crate::extensions::Extensions; -use crate::httpmessage::HttpMessage; -use crate::message::{Head, Message, ResponseHead}; -use crate::payload::{Payload, PayloadStream}; - -/// Client Response -pub struct ClientResponse { - pub(crate) head: Message, - pub(crate) payload: Payload, -} - -impl HttpMessage for ClientResponse { - type Stream = PayloadStream; - - fn headers(&self) -> &HeaderMap { - &self.head.headers - } - - fn extensions(&self) -> Ref { - self.head.extensions() - } - - fn extensions_mut(&self) -> RefMut { - self.head.extensions_mut() - } - - fn take_payload(&mut self) -> Payload { - std::mem::replace(&mut self.payload, Payload::None) - } -} - -impl ClientResponse { - /// Create new Request instance - pub fn new() -> ClientResponse { - let head: Message = Message::new(); - head.extensions_mut().clear(); - - ClientResponse { - head, - payload: Payload::None, - } - } - - #[inline] - pub(crate) fn head(&self) -> &ResponseHead { - &self.head - } - - #[inline] - pub(crate) fn head_mut(&mut self) -> &mut ResponseHead { - &mut self.head - } - - /// Read the Request Version. - #[inline] - pub fn version(&self) -> Version { - self.head().version - } - - /// Get the status from the server. - #[inline] - pub fn status(&self) -> StatusCode { - self.head().status - } - - #[inline] - /// Returns Request's headers. - pub fn headers(&self) -> &HeaderMap { - &self.head().headers - } - - #[inline] - /// Returns mutable Request's headers. - pub fn headers_mut(&mut self) -> &mut HeaderMap { - &mut self.head_mut().headers - } - - /// Checks if a connection should be kept alive. - #[inline] - pub fn keep_alive(&self) -> bool { - self.head().keep_alive() - } - - /// Set response payload - pub fn set_payload(&mut self, payload: Payload) { - self.payload = payload; - } -} - -impl Stream for ClientResponse { - type Item = Bytes; - type Error = PayloadError; - - fn poll(&mut self) -> Poll, Self::Error> { - self.payload.poll() - } -} - -impl fmt::Debug for ClientResponse { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - writeln!(f, "\nClientResponse {:?} {}", self.version(), self.status(),)?; - writeln!(f, " headers:")?; - for (key, val) in self.headers().iter() { - writeln!(f, " {:?}: {:?}", key, val)?; - } - Ok(()) - } -} diff --git a/src/h1/client.rs b/src/h1/client.rs index 85185126..b3a5a5d9 100644 --- a/src/h1/client.rs +++ b/src/h1/client.rs @@ -13,11 +13,10 @@ use super::decoder::{PayloadDecoder, PayloadItem, PayloadType}; use super::{decoder, encoder}; use super::{Message, MessageType}; use crate::body::BodyLength; -use crate::client::ClientResponse; use crate::config::ServiceConfig; use crate::error::{ParseError, PayloadError}; use crate::helpers; -use crate::message::{ConnectionType, Head, MessagePool, RequestHead}; +use crate::message::{ConnectionType, Head, MessagePool, RequestHead, ResponseHead}; bitflags! { struct Flags: u8 { @@ -41,7 +40,7 @@ pub struct ClientPayloadCodec { struct ClientCodecInner { config: ServiceConfig, - decoder: decoder::MessageDecoder, + decoder: decoder::MessageDecoder, payload: Option, version: Version, ctype: ConnectionType, @@ -123,14 +122,14 @@ impl ClientPayloadCodec { } impl Decoder for ClientCodec { - type Item = ClientResponse; + type Item = ResponseHead; type Error = ParseError; fn decode(&mut self, src: &mut BytesMut) -> Result, Self::Error> { debug_assert!(!self.inner.payload.is_some(), "Payload decoder is set"); if let Some((req, payload)) = self.inner.decoder.decode(src)? { - if let Some(ctype) = req.head().ctype { + if let Some(ctype) = req.ctype { // do not use peer's keep-alive self.inner.ctype = if ctype == ConnectionType::KeepAlive { self.inner.ctype diff --git a/src/h1/decoder.rs b/src/h1/decoder.rs index 77b76c24..a1b221c0 100644 --- a/src/h1/decoder.rs +++ b/src/h1/decoder.rs @@ -9,9 +9,8 @@ use http::{header, HeaderMap, HttpTryFrom, Method, StatusCode, Uri, Version}; use httparse; use log::{debug, error, trace}; -use crate::client::ClientResponse; use crate::error::ParseError; -use crate::message::ConnectionType; +use crate::message::{ConnectionType, ResponseHead}; use crate::request::Request; const MAX_BUFFER_SIZE: usize = 131_072; @@ -227,13 +226,13 @@ impl MessageType for Request { } } -impl MessageType for ClientResponse { +impl MessageType for ResponseHead { fn set_connection_type(&mut self, ctype: Option) { - self.head.ctype = ctype; + self.ctype = ctype; } fn headers_mut(&mut self) -> &mut HeaderMap { - self.headers_mut() + &mut self.headers } fn decode(src: &mut BytesMut) -> Result, ParseError> { @@ -263,7 +262,7 @@ impl MessageType for ClientResponse { } }; - let mut msg = ClientResponse::new(); + let mut msg = ResponseHead::default(); // convert headers let len = msg.set_headers(&src.split_to(len).freeze(), &headers[..h_len])?; @@ -281,8 +280,8 @@ impl MessageType for ClientResponse { PayloadType::None }; - msg.head.status = status; - msg.head.version = ver; + msg.status = status; + msg.version = ver; Ok(Some((msg, decoder))) } diff --git a/src/h1/dispatcher.rs b/src/h1/dispatcher.rs index afeabc82..09a17fcf 100644 --- a/src/h1/dispatcher.rs +++ b/src/h1/dispatcher.rs @@ -553,7 +553,7 @@ mod tests { use actix_codec::{AsyncRead, AsyncWrite}; use actix_service::IntoService; - use bytes::{Buf, Bytes, BytesMut}; + use bytes::{Buf, Bytes}; use futures::future::{lazy, ok}; use super::*; diff --git a/src/lib.rs b/src/lib.rs index 85efe5e4..b41ce7ae 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,64 +1,4 @@ -//! Actix web is a small, pragmatic, and extremely fast web framework -//! for Rust. -//! -//! ```rust,ignore -//! use actix_web::{server, App, Path, Responder}; -//! # use std::thread; -//! -//! fn index(info: Path<(String, u32)>) -> impl Responder { -//! format!("Hello {}! id:{}", info.0, info.1) -//! } -//! -//! fn main() { -//! # thread::spawn(|| { -//! server::new(|| { -//! App::new().resource("/{name}/{id}/index.html", |r| r.with(index)) -//! }).bind("127.0.0.1:8080") -//! .unwrap() -//! .run(); -//! # }); -//! } -//! ``` -//! -//! ## Documentation & community resources -//! -//! Besides the API documentation (which you are currently looking -//! at!), several other resources are available: -//! -//! * [User Guide](https://actix.rs/docs/) -//! * [Chat on gitter](https://gitter.im/actix/actix) -//! * [GitHub repository](https://github.com/actix/actix-web) -//! * [Cargo package](https://crates.io/crates/actix-web) -//! -//! To get started navigating the API documentation you may want to -//! consider looking at the following pages: -//! -//! * [App](struct.App.html): This struct represents an actix-web -//! application and is used to configure routes and other common -//! settings. -//! -//! * [HttpServer](server/struct.HttpServer.html): This struct -//! represents an HTTP server instance and is used to instantiate and -//! configure servers. -//! -//! * [Request](struct.Request.html) and -//! [Response](struct.Response.html): These structs -//! represent HTTP requests and responses and expose various methods -//! for inspecting, creating and otherwise utilizing them. -//! -//! ## Features -//! -//! * Supported *HTTP/1.x* protocol -//! * Streaming and pipelining -//! * Keep-alive and slow requests handling -//! * `WebSockets` server/client -//! * Supported Rust version: 1.26 or later -//! -//! ## Package feature -//! -//! * `session` - enables session support, includes `ring` crate as -//! dependency -//! +//! Basic http primitives for actix-net framework. #![allow( clippy::type_complexity, clippy::new_without_default, diff --git a/src/response.rs b/src/response.rs index 5281c2d9..31c0010a 100644 --- a/src/response.rs +++ b/src/response.rs @@ -1042,8 +1042,6 @@ mod tests { #[test] #[cfg(feature = "cookies")] fn test_into_builder() { - use crate::httpmessage::HttpMessage; - let mut resp: Response = "test".into(); assert_eq!(resp.status(), StatusCode::OK); diff --git a/src/ws/client/connect.rs b/src/ws/client/connect.rs index 5e877a64..2760967e 100644 --- a/src/ws/client/connect.rs +++ b/src/ws/client/connect.rs @@ -4,15 +4,15 @@ use std::str; #[cfg(feature = "cookies")] use cookie::Cookie; use http::header::{HeaderName, HeaderValue}; -use http::{Error as HttpError, HttpTryFrom}; +use http::{Error as HttpError, HttpTryFrom, Uri}; use super::ClientError; -use crate::client::{ClientRequest, ClientRequestBuilder}; use crate::header::IntoHeaderValue; +use crate::message::RequestHead; /// `WebSocket` connection pub struct Connect { - pub(super) request: ClientRequestBuilder, + pub(super) head: RequestHead, pub(super) err: Option, pub(super) http_err: Option, pub(super) origin: Option, @@ -25,7 +25,7 @@ impl Connect { /// Create new websocket connection pub fn new>(uri: S) -> Connect { let mut cl = Connect { - request: ClientRequest::build(), + head: RequestHead::default(), err: None, http_err: None, origin: None, @@ -33,7 +33,12 @@ impl Connect { max_size: 65_536, server_mode: false, }; - cl.request.uri(uri.as_ref()); + + match Uri::try_from(uri.as_ref()) { + Ok(uri) => cl.head.uri = uri, + Err(e) => cl.http_err = Some(e.into()), + } + cl } @@ -51,12 +56,12 @@ impl Connect { self } - #[cfg(feature = "cookies")] - /// Set cookie for handshake request - pub fn cookie(mut self, cookie: Cookie) -> Self { - self.request.cookie(cookie); - self - } + // #[cfg(feature = "cookies")] + // /// Set cookie for handshake request + // pub fn cookie(mut self, cookie: Cookie) -> Self { + // self.request.cookie(cookie); + // self + // } /// Set request Origin pub fn origin(mut self, origin: V) -> Self @@ -90,7 +95,15 @@ impl Connect { HeaderName: HttpTryFrom, V: IntoHeaderValue, { - self.request.header(key, value); + match HeaderName::try_from(key) { + Ok(key) => match value.try_into() { + Ok(value) => { + self.head.headers.append(key, value); + } + Err(e) => self.http_err = Some(e.into()), + }, + Err(e) => self.http_err = Some(e.into()), + } self } } diff --git a/src/ws/client/service.rs b/src/ws/client/service.rs index a0a9b203..8a0840f9 100644 --- a/src/ws/client/service.rs +++ b/src/ws/client/service.rs @@ -14,8 +14,8 @@ use rand; use sha1::Sha1; use crate::body::BodyLength; -use crate::client::ClientResponse; use crate::h1; +use crate::message::{ConnectionType, Head, ResponseHead}; use crate::ws::Codec; use super::{ClientError, Connect, Protocol}; @@ -89,27 +89,35 @@ where } else { // origin if let Some(origin) = req.origin.take() { - req.request.set_header(header::ORIGIN, origin); + req.head.headers.insert(header::ORIGIN, origin); } - req.request.upgrade("websocket"); - req.request.set_header(header::SEC_WEBSOCKET_VERSION, "13"); + req.head.set_connection_type(ConnectionType::Upgrade); + req.head + .headers + .insert(header::UPGRADE, HeaderValue::from_static("websocket")); + req.head.headers.insert( + header::SEC_WEBSOCKET_VERSION, + HeaderValue::from_static("13"), + ); if let Some(protocols) = req.protocols.take() { - req.request - .set_header(header::SEC_WEBSOCKET_PROTOCOL, protocols.as_str()); + req.head.headers.insert( + header::SEC_WEBSOCKET_PROTOCOL, + HeaderValue::try_from(protocols.as_str()).unwrap(), + ); } - let mut request = match req.request.finish() { - Ok(req) => req, - Err(e) => return Either::A(err(e.into())), + if let Some(e) = req.http_err { + return Either::A(err(e.into())); }; - if request.uri().host().is_none() { + let mut request = req.head; + if request.uri.host().is_none() { return Either::A(err(ClientError::InvalidUrl)); } // supported protocols - let proto = if let Some(scheme) = request.uri().scheme_part() { + let proto = if let Some(scheme) = request.uri.scheme_part() { match Protocol::from(scheme.as_str()) { Some(proto) => proto, None => return Either::A(err(ClientError::InvalidUrl)), @@ -124,14 +132,14 @@ where let sec_key: [u8; 16] = rand::random(); let key = base64::encode(&sec_key); - request.headers_mut().insert( + request.headers.insert( header::SEC_WEBSOCKET_KEY, HeaderValue::try_from(key.as_str()).unwrap(), ); // prep connection - let connect = TcpConnect::new(request.uri().host().unwrap().to_string()) - .set_port(request.uri().port_u16().unwrap_or_else(|| proto.port())); + let connect = TcpConnect::new(request.uri.host().unwrap().to_string()) + .set_port(request.uri.port_u16().unwrap_or_else(|| proto.port())); let fut = Box::new( self.connector @@ -141,7 +149,7 @@ where // h1 protocol let framed = Framed::new(io, h1::ClientCodec::default()); framed - .send((request.into_parts().0, BodyLength::None).into()) + .send((request, BodyLength::None).into()) .map_err(ClientError::from) .and_then(|framed| { framed @@ -172,7 +180,7 @@ where { fut: Box< Future< - Item = (Option, Framed), + Item = (Option, Framed), Error = ClientError, >, >, @@ -198,11 +206,11 @@ where }; // verify response - if res.status() != StatusCode::SWITCHING_PROTOCOLS { - return Err(ClientError::InvalidResponseStatus(res.status())); + if res.status != StatusCode::SWITCHING_PROTOCOLS { + return Err(ClientError::InvalidResponseStatus(res.status)); } // Check for "UPGRADE" to websocket header - let has_hdr = if let Some(hdr) = res.headers().get(header::UPGRADE) { + let has_hdr = if let Some(hdr) = res.headers.get(header::UPGRADE) { if let Ok(s) = hdr.to_str() { s.to_lowercase().contains("websocket") } else { @@ -216,7 +224,7 @@ where return Err(ClientError::InvalidUpgradeHeader); } // Check for "CONNECTION" header - if let Some(conn) = res.headers().get(header::CONNECTION) { + if let Some(conn) = res.headers.get(header::CONNECTION) { if let Ok(s) = conn.to_str() { if !s.to_lowercase().contains("upgrade") { trace!("Invalid connection header: {}", s); @@ -231,7 +239,7 @@ where return Err(ClientError::MissingConnectionHeader); } - if let Some(key) = res.headers().get(header::SEC_WEBSOCKET_ACCEPT) { + if let Some(key) = res.headers.get(header::SEC_WEBSOCKET_ACCEPT) { // field is constructed by concatenating /key/ // with the string "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" (RFC 6455) const WS_GUID: &[u8] = b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; diff --git a/test-server/Cargo.toml b/test-server/Cargo.toml index b7535f99..313bc55c 100644 --- a/test-server/Cargo.toml +++ b/test-server/Cargo.toml @@ -29,7 +29,7 @@ default = ["session"] session = ["cookie/secure"] # openssl -ssl = ["openssl", "actix-http/ssl", "actix-server/ssl"] +ssl = ["openssl", "actix-http/ssl", "actix-server/ssl", "awc/ssl"] [dependencies] actix-codec = "0.1.1" @@ -38,6 +38,7 @@ actix-http = { path=".." } actix-service = "0.3.4" actix-server = "0.4.0" actix-utils = "0.3.4" +awc = { git = "https://github.com/actix/actix-web.git" } base64 = "0.10" bytes = "0.4" diff --git a/test-server/src/lib.rs b/test-server/src/lib.rs index 26bca787..77329e70 100644 --- a/test-server/src/lib.rs +++ b/test-server/src/lib.rs @@ -3,15 +3,12 @@ use std::sync::mpsc; use std::{net, thread, time}; use actix_codec::{AsyncRead, AsyncWrite, Framed}; -use actix_http::body::MessageBody; -use actix_http::client::{ - ClientRequest, ClientRequestBuilder, ClientResponse, ConnectError, Connection, - Connector, SendRequestError, -}; -use actix_http::{http::Uri, ws}; +use actix_http::client::Connector; +use actix_http::ws; use actix_rt::{Runtime, System}; use actix_server::{Server, StreamServiceFactory}; use actix_service::Service; +use awc::{Client, ClientRequest}; use futures::future::{lazy, Future}; use http::Method; use net2::TcpBuilder; @@ -47,6 +44,7 @@ pub struct TestServer; pub struct TestServerRuntime { addr: net::SocketAddr, rt: Runtime, + client: Client, } impl TestServer { @@ -71,11 +69,39 @@ impl TestServer { }); let (system, addr) = rx.recv().unwrap(); + let mut rt = Runtime::new().unwrap(); + + let client = rt + .block_on(lazy(move || { + let connector = { + #[cfg(feature = "ssl")] + { + use openssl::ssl::{SslConnector, SslMethod, SslVerifyMode}; + + let mut builder = + SslConnector::builder(SslMethod::tls()).unwrap(); + builder.set_verify(SslVerifyMode::NONE); + let _ = builder.set_alpn_protos(b"\x02h2\x08http/1.1").map_err( + |e| log::error!("Can not set alpn protocol: {:?}", e), + ); + Connector::new() + .timeout(time::Duration::from_millis(500)) + .ssl(builder.build()) + .service() + } + #[cfg(not(feature = "ssl"))] + { + Connector::new() + .timeout(time::Duration::from_millis(500)) + .service() + } + }; + + Ok::(Client::build().connector(connector).finish()) + })) + .unwrap(); System::set_current(system); - TestServerRuntime { - addr, - rt: Runtime::new().unwrap(), - } + TestServerRuntime { addr, rt, client } } /// Get firat available unused address @@ -130,64 +156,38 @@ impl TestServerRuntime { } /// Create `GET` request - pub fn get(&self) -> ClientRequestBuilder { - ClientRequest::get(self.url("/").as_str()) + pub fn get(&self) -> ClientRequest { + self.client.get(self.url("/").as_str()) } /// Create https `GET` request - pub fn sget(&self) -> ClientRequestBuilder { - ClientRequest::get(self.surl("/").as_str()) + pub fn sget(&self) -> ClientRequest { + self.client.get(self.surl("/").as_str()) } /// Create `POST` request - pub fn post(&self) -> ClientRequestBuilder { - ClientRequest::post(self.url("/").as_str()) + pub fn post(&self) -> ClientRequest { + self.client.post(self.url("/").as_str()) + } + + /// Create https `POST` request + pub fn spost(&self) -> ClientRequest { + self.client.post(self.surl("/").as_str()) } /// Create `HEAD` request - pub fn head(&self) -> ClientRequestBuilder { - ClientRequest::head(self.url("/").as_str()) + pub fn head(&self) -> ClientRequest { + self.client.head(self.url("/").as_str()) + } + + /// Create https `HEAD` request + pub fn shead(&self) -> ClientRequest { + self.client.head(self.surl("/").as_str()) } /// Connect to test http server - pub fn client(&self, meth: Method, path: &str) -> ClientRequestBuilder { - ClientRequest::build() - .method(meth) - .uri(self.url(path).as_str()) - .take() - } - - fn new_connector( - ) -> impl Service + Clone - { - #[cfg(feature = "ssl")] - { - use openssl::ssl::{SslConnector, SslMethod, SslVerifyMode}; - - let mut builder = SslConnector::builder(SslMethod::tls()).unwrap(); - builder.set_verify(SslVerifyMode::NONE); - let _ = builder - .set_alpn_protos(b"\x02h2\x08http/1.1") - .map_err(|e| log::error!("Can not set alpn protocol: {:?}", e)); - Connector::new() - .timeout(time::Duration::from_millis(500)) - .ssl(builder.build()) - .service() - } - #[cfg(not(feature = "ssl"))] - { - Connector::new() - .timeout(time::Duration::from_millis(500)) - .service() - } - } - - /// Http connector - pub fn connector( - &mut self, - ) -> impl Service + Clone - { - self.execute(|| TestServerRuntime::new_connector()) + pub fn request>(&self, method: Method, path: S) -> ClientRequest { + self.client.request(method, path.as_ref()) } /// Stop http server @@ -213,15 +213,6 @@ impl TestServerRuntime { ) -> Result, ws::ClientError> { self.ws_at("/") } - - /// Send request and read response message - pub fn send_request( - &mut self, - req: ClientRequest, - ) -> Result { - let mut conn = self.connector(); - self.rt.block_on(req.send(&mut conn)) - } } impl Drop for TestServerRuntime { diff --git a/tests/test_client.rs b/tests/test_client.rs index 2832b1b7..1ca7437d 100644 --- a/tests/test_client.rs +++ b/tests/test_client.rs @@ -4,7 +4,7 @@ use futures::future::{self, ok}; use futures::{Future, Stream}; use actix_http::{ - client, error::PayloadError, HttpMessage, HttpService, Request, Response, + error::PayloadError, http, HttpMessage, HttpService, Request, Response, }; use actix_http_test::TestServer; @@ -48,26 +48,18 @@ fn test_h1_v2() { .finish(|_| future::ok::<_, ()>(Response::Ok().body(STR))) .map(|_| ()) }); - let mut connector = srv.connector(); - - let request = srv.get().finish().unwrap(); - let response = srv.block_on(request.send(&mut connector)).unwrap(); + let response = srv.block_on(srv.get().send()).unwrap(); assert!(response.status().is_success()); - let request = srv.get().header("x-test", "111").finish().unwrap(); - let repr = format!("{:?}", request); - assert!(repr.contains("ClientRequest")); - assert!(repr.contains("x-test")); - - let mut response = srv.block_on(request.send(&mut connector)).unwrap(); + let request = srv.get().header("x-test", "111").send(); + let mut response = srv.block_on(request).unwrap(); assert!(response.status().is_success()); // read response let bytes = srv.block_on(load_body(response.take_payload())).unwrap(); assert_eq!(bytes, Bytes::from_static(STR.as_ref())); - let request = srv.post().finish().unwrap(); - let mut response = srv.block_on(request.send(&mut connector)).unwrap(); + let mut response = srv.block_on(srv.post().send()).unwrap(); assert!(response.status().is_success()); // read response @@ -82,10 +74,7 @@ fn test_connection_close() { .finish(|_| ok::<_, ()>(Response::Ok().body(STR))) .map(|_| ()) }); - let mut connector = srv.connector(); - - let request = srv.get().close().finish().unwrap(); - let response = srv.block_on(request.send(&mut connector)).unwrap(); + let response = srv.block_on(srv.get().close_connection().send()).unwrap(); assert!(response.status().is_success()); } @@ -102,12 +91,8 @@ fn test_with_query_parameter() { }) .map(|_| ()) }); - let mut connector = srv.connector(); - let request = client::ClientRequest::get(srv.url("/?qp=5")) - .finish() - .unwrap(); - - let response = srv.block_on(request.send(&mut connector)).unwrap(); + let request = srv.request(http::Method::GET, srv.url("/?qp=5")).send(); + let response = srv.block_on(request).unwrap(); assert!(response.status().is_success()); } diff --git a/tests/test_server.rs b/tests/test_server.rs index 8a7316cd..5777c569 100644 --- a/tests/test_server.rs +++ b/tests/test_server.rs @@ -13,8 +13,8 @@ use futures::stream::{once, Stream}; use actix_http::body::Body; use actix_http::error::PayloadError; use actix_http::{ - body, client, error, http, http::header, Error, HttpMessage as HttpMessage2, - HttpService, KeepAlive, Request, Response, + body, error, http, http::header, Error, HttpMessage as HttpMessage2, HttpService, + KeepAlive, Request, Response, }; fn load_body(stream: S) -> impl Future @@ -37,8 +37,7 @@ fn test_h1() { .h1(|_| future::ok::<_, ()>(Response::Ok().finish())) }); - let req = client::ClientRequest::get(srv.url("/")).finish().unwrap(); - let response = srv.send_request(req).unwrap(); + let response = srv.block_on(srv.get().send()).unwrap(); assert!(response.status().is_success()); } @@ -56,8 +55,7 @@ fn test_h1_2() { .map(|_| ()) }); - let req = client::ClientRequest::get(srv.url("/")).finish().unwrap(); - let response = srv.send_request(req).unwrap(); + let response = srv.block_on(srv.get().send()).unwrap(); assert!(response.status().is_success()); } @@ -100,8 +98,7 @@ fn test_h2() -> std::io::Result<()> { ) }); - let req = client::ClientRequest::get(srv.surl("/")).finish().unwrap(); - let response = srv.send_request(req).unwrap(); + let response = srv.block_on(srv.sget().send()).unwrap(); assert!(response.status().is_success()); Ok(()) } @@ -124,8 +121,7 @@ fn test_h2_1() -> std::io::Result<()> { ) }); - let req = client::ClientRequest::get(srv.surl("/")).finish().unwrap(); - let response = srv.send_request(req).unwrap(); + let response = srv.block_on(srv.sget().send()).unwrap(); assert!(response.status().is_success()); Ok(()) } @@ -149,10 +145,7 @@ fn test_h2_body() -> std::io::Result<()> { ) }); - let req = client::ClientRequest::get(srv.surl("/")) - .body(data.clone()) - .unwrap(); - let mut response = srv.send_request(req).unwrap(); + let mut response = srv.block_on(srv.sget().send_body(data.clone())).unwrap(); assert!(response.status().is_success()); let body = srv.block_on(load_body(response.take_payload())).unwrap(); @@ -331,24 +324,24 @@ fn test_content_length() { { for i in 0..4 { - let req = client::ClientRequest::get(srv.url(&format!("/{}", i))) - .finish() - .unwrap(); - let response = srv.send_request(req).unwrap(); + let req = srv + .request(http::Method::GET, srv.url(&format!("/{}", i))) + .send(); + let response = srv.block_on(req).unwrap(); assert_eq!(response.headers().get(&header), None); - let req = client::ClientRequest::head(srv.url(&format!("/{}", i))) - .finish() - .unwrap(); - let response = srv.send_request(req).unwrap(); + let req = srv + .request(http::Method::HEAD, srv.url(&format!("/{}", i))) + .send(); + let response = srv.block_on(req).unwrap(); assert_eq!(response.headers().get(&header), None); } for i in 4..6 { - let req = client::ClientRequest::get(srv.url(&format!("/{}", i))) - .finish() - .unwrap(); - let response = srv.send_request(req).unwrap(); + let req = srv + .request(http::Method::GET, srv.url(&format!("/{}", i))) + .send(); + let response = srv.block_on(req).unwrap(); assert_eq!(response.headers().get(&header), Some(&value)); } } @@ -389,24 +382,24 @@ fn test_h2_content_length() { { for i in 0..4 { - let req = client::ClientRequest::get(srv.surl(&format!("/{}", i))) - .finish() - .unwrap(); - let response = srv.send_request(req).unwrap(); + let req = srv + .request(http::Method::GET, srv.surl(&format!("/{}", i))) + .send(); + let response = srv.block_on(req).unwrap(); assert_eq!(response.headers().get(&header), None); - let req = client::ClientRequest::head(srv.surl(&format!("/{}", i))) - .finish() - .unwrap(); - let response = srv.send_request(req).unwrap(); + let req = srv + .request(http::Method::HEAD, srv.surl(&format!("/{}", i))) + .send(); + let response = srv.block_on(req).unwrap(); assert_eq!(response.headers().get(&header), None); } for i in 4..6 { - let req = client::ClientRequest::get(srv.surl(&format!("/{}", i))) - .finish() - .unwrap(); - let response = srv.send_request(req).unwrap(); + let req = srv + .request(http::Method::GET, srv.surl(&format!("/{}", i))) + .send(); + let response = srv.block_on(req).unwrap(); assert_eq!(response.headers().get(&header), Some(&value)); } } @@ -442,11 +435,8 @@ fn test_h1_headers() { future::ok::<_, ()>(builder.body(data.clone())) }) }); - let mut connector = srv.connector(); - let req = srv.get().finish().unwrap(); - - let mut response = srv.block_on(req.send(&mut connector)).unwrap(); + let mut response = srv.block_on(srv.get().send()).unwrap(); assert!(response.status().is_success()); // read response @@ -489,10 +479,8 @@ fn test_h2_headers() { future::ok::<_, ()>(builder.body(data.clone())) }).map_err(|_| ())) }); - let mut connector = srv.connector(); - let req = client::ClientRequest::get(srv.surl("/")).finish().unwrap(); - let mut response = srv.block_on(req.send(&mut connector)).unwrap(); + let mut response = srv.block_on(srv.sget().send()).unwrap(); assert!(response.status().is_success()); // read response @@ -528,8 +516,7 @@ fn test_h1_body() { HttpService::build().h1(|_| future::ok::<_, ()>(Response::Ok().body(STR))) }); - let req = srv.get().finish().unwrap(); - let mut response = srv.send_request(req).unwrap(); + let mut response = srv.block_on(srv.get().send()).unwrap(); assert!(response.status().is_success()); // read response @@ -551,8 +538,7 @@ fn test_h2_body2() { ) }); - let req = srv.sget().finish().unwrap(); - let mut response = srv.send_request(req).unwrap(); + let mut response = srv.block_on(srv.sget().send()).unwrap(); assert!(response.status().is_success()); // read response @@ -566,8 +552,7 @@ fn test_h1_head_empty() { HttpService::build().h1(|_| ok::<_, ()>(Response::Ok().body(STR))) }); - let req = client::ClientRequest::head(srv.url("/")).finish().unwrap(); - let mut response = srv.send_request(req).unwrap(); + let mut response = srv.block_on(srv.head().send()).unwrap(); assert!(response.status().is_success()); { @@ -597,8 +582,7 @@ fn test_h2_head_empty() { ) }); - let req = client::ClientRequest::head(srv.surl("/")).finish().unwrap(); - let mut response = srv.send_request(req).unwrap(); + let mut response = srv.block_on(srv.shead().send()).unwrap(); assert!(response.status().is_success()); assert_eq!(response.version(), http::Version::HTTP_2); @@ -623,8 +607,7 @@ fn test_h1_head_binary() { }) }); - let req = client::ClientRequest::head(srv.url("/")).finish().unwrap(); - let mut response = srv.send_request(req).unwrap(); + let mut response = srv.block_on(srv.head().send()).unwrap(); assert!(response.status().is_success()); { @@ -658,8 +641,7 @@ fn test_h2_head_binary() { ) }); - let req = client::ClientRequest::head(srv.surl("/")).finish().unwrap(); - let mut response = srv.send_request(req).unwrap(); + let mut response = srv.block_on(srv.shead().send()).unwrap(); assert!(response.status().is_success()); { @@ -681,8 +663,7 @@ fn test_h1_head_binary2() { HttpService::build().h1(|_| ok::<_, ()>(Response::Ok().body(STR))) }); - let req = client::ClientRequest::head(srv.url("/")).finish().unwrap(); - let response = srv.send_request(req).unwrap(); + let response = srv.block_on(srv.head().send()).unwrap(); assert!(response.status().is_success()); { @@ -708,8 +689,7 @@ fn test_h2_head_binary2() { ) }); - let req = client::ClientRequest::head(srv.surl("/")).finish().unwrap(); - let response = srv.send_request(req).unwrap(); + let response = srv.block_on(srv.shead().send()).unwrap(); assert!(response.status().is_success()); { @@ -733,8 +713,7 @@ fn test_h1_body_length() { }) }); - let req = srv.get().finish().unwrap(); - let mut response = srv.send_request(req).unwrap(); + let mut response = srv.block_on(srv.get().send()).unwrap(); assert!(response.status().is_success()); // read response @@ -761,8 +740,7 @@ fn test_h2_body_length() { ) }); - let req = srv.sget().finish().unwrap(); - let mut response = srv.send_request(req).unwrap(); + let mut response = srv.block_on(srv.sget().send()).unwrap(); assert!(response.status().is_success()); // read response @@ -783,8 +761,7 @@ fn test_h1_body_chunked_explicit() { }) }); - let req = srv.get().finish().unwrap(); - let mut response = srv.send_request(req).unwrap(); + let mut response = srv.block_on(srv.get().send()).unwrap(); assert!(response.status().is_success()); assert_eq!( response @@ -825,8 +802,7 @@ fn test_h2_body_chunked_explicit() { ) }); - let req = srv.sget().finish().unwrap(); - let mut response = srv.send_request(req).unwrap(); + let mut response = srv.block_on(srv.sget().send()).unwrap(); assert!(response.status().is_success()); assert!(!response.headers().contains_key(header::TRANSFER_ENCODING)); @@ -846,8 +822,7 @@ fn test_h1_body_chunked_implicit() { }) }); - let req = srv.get().finish().unwrap(); - let mut response = srv.send_request(req).unwrap(); + let mut response = srv.block_on(srv.get().send()).unwrap(); assert!(response.status().is_success()); assert_eq!( response @@ -879,8 +854,7 @@ fn test_h1_response_http_error_handling() { })) }); - let req = srv.get().finish().unwrap(); - let mut response = srv.send_request(req).unwrap(); + let mut response = srv.block_on(srv.get().send()).unwrap(); assert_eq!(response.status(), http::StatusCode::INTERNAL_SERVER_ERROR); // read response @@ -912,8 +886,7 @@ fn test_h2_response_http_error_handling() { ) }); - let req = srv.sget().finish().unwrap(); - let mut response = srv.send_request(req).unwrap(); + let mut response = srv.block_on(srv.sget().send()).unwrap(); assert_eq!(response.status(), http::StatusCode::INTERNAL_SERVER_ERROR); // read response @@ -928,8 +901,7 @@ fn test_h1_service_error() { .h1(|_| Err::(error::ErrorBadRequest("error"))) }); - let req = srv.get().finish().unwrap(); - let mut response = srv.send_request(req).unwrap(); + let mut response = srv.block_on(srv.get().send()).unwrap(); assert_eq!(response.status(), http::StatusCode::INTERNAL_SERVER_ERROR); // read response @@ -952,8 +924,7 @@ fn test_h2_service_error() { ) }); - let req = srv.sget().finish().unwrap(); - let mut response = srv.send_request(req).unwrap(); + let mut response = srv.block_on(srv.sget().send()).unwrap(); assert_eq!(response.status(), http::StatusCode::INTERNAL_SERVER_ERROR); // read response