From 548f4e4d62435822e0272001f3710f7593680a67 Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Mon, 19 Feb 2018 13:18:18 -0800 Subject: [PATCH] replace reqwest with actix::client --- Cargo.toml | 1 - guide/book.toml | 1 + guide/src/qs_8.md | 27 ++- src/client/mod.rs | 3 +- src/client/parser.rs | 8 +- src/client/pipeline.rs | 15 +- src/client/request.rs | 9 + src/client/response.rs | 72 +++++++- src/client/writer.rs | 9 +- src/server/encoding.rs | 3 +- src/test.rs | 30 ++- tests/test_server.rs | 403 ++++++++++++++++++++++++++++------------- 12 files changed, 430 insertions(+), 151 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index dc05008e8..b7999b743 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -82,7 +82,6 @@ version = "0.5" [dev-dependencies] env_logger = "0.5" -reqwest = "0.8" skeptic = "0.13" serde_derive = "1.0" diff --git a/guide/book.toml b/guide/book.toml index 57bb58213..5549978d7 100644 --- a/guide/book.toml +++ b/guide/book.toml @@ -1,3 +1,4 @@ +[book] title = "Actix web" description = "Actix web framework guide" author = "Actix Project and Contributors" diff --git a/guide/src/qs_8.md b/guide/src/qs_8.md index c2e533aaa..2e2b54201 100644 --- a/guide/src/qs_8.md +++ b/guide/src/qs_8.md @@ -45,8 +45,8 @@ fn main() { There are several methods how you can test your application. Actix provides [*TestServer*](../actix_web/test/struct.TestServer.html) server that could be used to run whole application of just specific handlers -in real http server. At the moment it is required to use third-party libraries -to make actual requests, libraries like [reqwest](https://crates.io/crates/reqwest). +in real http server. *TrstServer::get()*, *TrstServer::post()* or *TrstServer::client()* +methods could be used to send request to test server. In simple form *TestServer* could be configured to use handler. *TestServer::new* method accepts configuration function, only argument for this function is *test application* @@ -55,7 +55,6 @@ for more information. ```rust # extern crate actix_web; -extern crate reqwest; use actix_web::*; use actix_web::test::TestServer; @@ -64,9 +63,13 @@ fn index(req: HttpRequest) -> HttpResponse { } fn main() { - let srv = TestServer::new(|app| app.handler(index)); // <- Start new test server - let url = srv.url("/"); // <- get handler url - assert!(reqwest::get(&url).unwrap().status().is_success()); // <- make request + let mut srv = TestServer::new(|app| app.handler(index)); // <- Start new test server + + let request = srv.get().finish().unwrap(); // <- create client request + let response = srv.execute(request.send()).unwrap(); // <- send request to the server + assert!(response.status().is_success()); // <- check response + + let bytes = srv.execute(response.body()).unwrap(); // <- read response body } ``` @@ -74,8 +77,9 @@ Other option is to use application factory. In this case you need to pass factor same as you use for real http server configuration. ```rust +# extern crate http; # extern crate actix_web; -extern crate reqwest; +use http::Method; use actix_web::*; use actix_web::test::TestServer; @@ -90,9 +94,12 @@ fn create_app() -> Application { } fn main() { - let srv = TestServer::with_factory(create_app); // <- Start new test server - let url = srv.url("/test"); // <- get handler url - assert!(reqwest::get(&url).unwrap().status().is_success()); // <- make request + let mut srv = TestServer::with_factory(create_app); // <- Start new test server + + let request = srv.client(Method::GET, "/test").finish().unwrap(); // <- create client request + let response = srv.execute(request.send()).unwrap(); // <- send request to the server + + assert!(response.status().is_success()); // <- check response } ``` diff --git a/src/client/mod.rs b/src/client/mod.rs index 4240aa3c4..f7b735437 100644 --- a/src/client/mod.rs +++ b/src/client/mod.rs @@ -1,3 +1,4 @@ +//! Http client mod connector; mod parser; mod request; @@ -7,7 +8,7 @@ mod writer; pub use self::pipeline::{SendRequest, SendRequestError}; pub use self::request::{ClientRequest, ClientRequestBuilder}; -pub use self::response::{ClientResponse, JsonResponse, UrlEncoded}; +pub use self::response::{ClientResponse, ResponseBody, JsonResponse, UrlEncoded}; pub use self::connector::{Connect, Connection, ClientConnector, ClientConnectorError}; pub(crate) use self::writer::HttpClientWriter; pub(crate) use self::parser::{HttpResponseParser, HttpResponseParserError}; diff --git a/src/client/parser.rs b/src/client/parser.rs index 67f65374c..b4ce9b2b2 100644 --- a/src/client/parser.rs +++ b/src/client/parser.rs @@ -21,11 +21,13 @@ pub struct HttpResponseParser { decoder: Option, } -#[derive(Debug)] +#[derive(Debug, Fail)] pub enum HttpResponseParserError { + /// Server disconnected + #[fail(display="Server disconnected")] Disconnect, - Payload, - Error(ParseError), + #[fail(display="{}", _0)] + Error(#[cause] ParseError), } impl HttpResponseParser { diff --git a/src/client/pipeline.rs b/src/client/pipeline.rs index 8dfdb855d..2cb3d635d 100644 --- a/src/client/pipeline.rs +++ b/src/client/pipeline.rs @@ -11,10 +11,18 @@ use super::{Connect, Connection, ClientConnector, ClientConnectorError}; use super::HttpClientWriter; use super::{HttpResponseParser, HttpResponseParserError}; +/// A set of errors that can occur during sending request and reading response +#[derive(Fail, Debug)] pub enum SendRequestError { - Connector(ClientConnectorError), - ParseError(HttpResponseParserError), - Io(io::Error), + /// Failed to connect to host + #[fail(display="Failed to connect to host: {}", _0)] + Connector(#[cause] ClientConnectorError), + /// Error parsing response + #[fail(display="{}", _0)] + ParseError(#[cause] HttpResponseParserError), + /// Error reading response payload + #[fail(display="Error reading response payload: {}", _0)] + Io(#[cause] io::Error), } impl From for SendRequestError { @@ -116,6 +124,7 @@ impl Pipeline { #[inline] pub fn poll(&mut self) -> Poll, PayloadError> { + self.poll_write()?; self.parser.parse_payload(&mut self.conn, &mut self.parser_buf) } diff --git a/src/client/request.rs b/src/client/request.rs index 2983094fe..c5aa487a5 100644 --- a/src/client/request.rs +++ b/src/client/request.rs @@ -463,6 +463,15 @@ impl ClientRequestBuilder { pub fn finish(&mut self) -> Result { self.body(Body::Empty) } + + /// This method construct new `ClientRequestBuilder` + pub fn take(&mut self) -> ClientRequestBuilder { + ClientRequestBuilder { + request: self.request.take(), + err: self.err.take(), + cookies: self.cookies.take(), + } + } } #[inline] diff --git a/src/client/response.rs b/src/client/response.rs index 06ccf0837..4bb7c2d66 100644 --- a/src/client/response.rs +++ b/src/client/response.rs @@ -158,6 +158,15 @@ impl ClientResponse { } } + /// Load request body. + /// + /// By default only 256Kb payload reads to a memory, then connection get dropped + /// and `PayloadError` get returned. Use `ResponseBody::limit()` + /// method to change upper limit. + pub fn body(self) -> ResponseBody { + ResponseBody::new(self) + } + // /// Return stream to http payload processes as multipart. // /// // /// Content-type: multipart/form-data; @@ -221,6 +230,67 @@ impl Stream for ClientResponse { } } +/// Future that resolves to a complete response body. +#[must_use = "ResponseBody does nothing unless polled"] +pub struct ResponseBody { + limit: usize, + resp: Option, + fut: Option>>, +} + +impl ResponseBody { + + /// Create `ResponseBody` for request. + pub fn new(resp: ClientResponse) -> Self { + ResponseBody { + limit: 262_144, + resp: Some(resp), + fut: None, + } + } + + /// Change max size of payload. By default max size is 256Kb + pub fn limit(mut self, limit: usize) -> Self { + self.limit = limit; + self + } +} + +impl Future for ResponseBody { + type Item = Bytes; + type Error = PayloadError; + + fn poll(&mut self) -> Poll { + if let Some(resp) = self.resp.take() { + if let Some(len) = resp.headers().get(header::CONTENT_LENGTH) { + if let Ok(s) = len.to_str() { + if let Ok(len) = s.parse::() { + if len > self.limit { + return Err(PayloadError::Overflow); + } + } else { + return Err(PayloadError::Overflow); + } + } + } + let limit = self.limit; + let fut = resp.from_err() + .fold(BytesMut::new(), move |mut body, chunk| { + if (body.len() + chunk.len()) > limit { + Err(PayloadError::Overflow) + } else { + body.extend_from_slice(&chunk); + Ok(body) + } + }) + .map(|bytes| bytes.freeze()); + self.fut = Some(Box::new(fut)); + } + + self.fut.as_mut().expect("ResponseBody could not be used second time").poll() + } +} + /// Client response json parser that resolves to a deserialized `T` value. /// /// Returns error: @@ -237,7 +307,7 @@ pub struct JsonResponse{ impl JsonResponse { - /// Create `JsonBody` for request. + /// Create `JsonResponse` for request. pub fn from_response(resp: ClientResponse) -> Self { JsonResponse{ limit: 262_144, diff --git a/src/client/writer.rs b/src/client/writer.rs index 17d43a966..432baea92 100644 --- a/src/client/writer.rs +++ b/src/client/writer.rs @@ -212,8 +212,10 @@ fn content_encoder(buf: SharedBytes, req: &mut ClientRequest) -> ContentEncoder // TODO return error! let _ = enc.write(bytes.clone()); let _ = enc.write_eof(); - *bytes = Binary::from(tmp.take()); + + req.headers_mut().insert( + CONTENT_ENCODING, HeaderValue::from_static(encoding.as_str())); encoding = ContentEncoding::Identity; } let mut b = BytesMut::new(); @@ -240,6 +242,11 @@ fn content_encoder(buf: SharedBytes, req: &mut ClientRequest) -> ContentEncoder } }; + if encoding.is_compression() { + req.headers_mut().insert( + CONTENT_ENCODING, HeaderValue::from_static(encoding.as_str())); + } + req.replace_body(body); match encoding { ContentEncoding::Deflate => ContentEncoder::Deflate( diff --git a/src/server/encoding.rs b/src/server/encoding.rs index d53f921ce..2a503bfbc 100644 --- a/src/server/encoding.rs +++ b/src/server/encoding.rs @@ -33,7 +33,8 @@ impl ContentEncoding { } } - fn as_str(&self) -> &'static str { + #[inline] + pub fn as_str(&self) -> &'static str { match *self { ContentEncoding::Br => "br", ContentEncoding::Gzip => "gzip", diff --git a/src/test.rs b/src/test.rs index 29f01ab31..86940bc04 100644 --- a/src/test.rs +++ b/src/test.rs @@ -26,6 +26,7 @@ use httprequest::HttpRequest; use httpresponse::HttpResponse; use server::{HttpServer, IntoHttpHandler, ServerSettings}; use ws::{WsClient, WsClientError, WsClientReader, WsClientWriter}; +use client::{ClientRequest, ClientRequestBuilder}; /// The `TestServer` type. /// @@ -38,7 +39,6 @@ use ws::{WsClient, WsClientError, WsClientReader, WsClientWriter}; /// # extern crate actix; /// # extern crate actix_web; /// # use actix_web::*; -/// # extern crate reqwest; /// # /// # fn my_handler(req: HttpRequest) -> HttpResponse { /// # httpcodes::HTTPOk.into() @@ -47,9 +47,11 @@ use ws::{WsClient, WsClientError, WsClientReader, WsClientWriter}; /// # fn main() { /// use actix_web::test::TestServer; /// -/// let srv = TestServer::new(|app| app.handler(my_handler)); +/// let mut srv = TestServer::new(|app| app.handler(my_handler)); /// -/// assert!(reqwest::get(&srv.url("/")).unwrap().status().is_success()); +/// let req = srv.get().finish().unwrap(); +/// let response = srv.execute(req.send()).unwrap(); +/// assert!(response.status().is_success()); /// # } /// ``` pub struct TestServer { @@ -182,6 +184,28 @@ impl TestServer { let url = self.url("/"); self.system.run_until_complete(WsClient::new(url).connect().unwrap()) } + + /// Create `GET` request + pub fn get(&self) -> ClientRequestBuilder { + ClientRequest::get(self.url("/").as_str()) + } + + /// Create `POST` request + pub fn post(&self) -> ClientRequestBuilder { + ClientRequest::get(self.url("/").as_str()) + } + + /// Create `HEAD` request + pub fn head(&self) -> ClientRequestBuilder { + ClientRequest::head(self.url("/").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() + } } impl Drop for TestServer { diff --git a/tests/test_server.rs b/tests/test_server.rs index e84c9211b..cbe289203 100644 --- a/tests/test_server.rs +++ b/tests/test_server.rs @@ -1,7 +1,6 @@ extern crate actix; extern crate actix_web; extern crate tokio_core; -extern crate reqwest; extern crate futures; extern crate h2; extern crate http; @@ -10,23 +9,24 @@ extern crate flate2; extern crate brotli2; use std::{net, thread, time}; -use std::io::Write; +use std::io::{Read, Write}; use std::sync::{Arc, mpsc}; use std::sync::atomic::{AtomicUsize, Ordering}; use flate2::Compression; +use flate2::read::GzDecoder; use flate2::write::{GzEncoder, DeflateEncoder, DeflateDecoder}; use brotli2::write::{BrotliEncoder, BrotliDecoder}; use futures::{Future, Stream}; use futures::stream::once; -use h2::client; -use bytes::{Bytes, BytesMut, BufMut}; -use http::Request; +use h2::client as h2client; +use bytes::{Bytes, BytesMut}; +use http::{header, Request}; use tokio_core::net::TcpStream; use tokio_core::reactor::Core; -use reqwest::header::{Encoding, ContentEncoding}; -use actix_web::*; use actix::System; +use actix_web::*; + const STR: &str = "Hello World Hello World Hello World Hello World Hello World \ @@ -69,7 +69,14 @@ fn test_start() { sys.run(); }); let (addr, srv_addr) = rx.recv().unwrap(); - assert!(reqwest::get(&format!("http://{}/", addr)).unwrap().status().is_success()); + + let mut sys = System::new("test-server"); + + { + let req = client::ClientRequest::get(format!("http://{}/", addr).as_str()).finish().unwrap(); + let response = sys.run_until_complete(req.send()).unwrap(); + assert!(response.status().is_success()); + } // pause let _ = srv_addr.send(server::PauseServer).wait(); @@ -78,74 +85,98 @@ fn test_start() { // resume let _ = srv_addr.send(server::ResumeServer).wait(); - assert!(reqwest::get(&format!("http://{}/", addr)).unwrap().status().is_success()); + + { + let req = client::ClientRequest::get(format!("http://{}/", addr).as_str()).finish().unwrap(); + let response = sys.run_until_complete(req.send()).unwrap(); + assert!(response.status().is_success()); + } } #[test] fn test_simple() { - let srv = test::TestServer::new(|app| app.handler(httpcodes::HTTPOk)); - assert!(reqwest::get(&srv.url("/")).unwrap().status().is_success()); + let mut srv = test::TestServer::new(|app| app.handler(httpcodes::HTTPOk)); + let req = srv.get().finish().unwrap(); + let response = srv.execute(req.send()).unwrap(); + assert!(response.status().is_success()); } #[test] fn test_body() { - let srv = test::TestServer::new( + let mut srv = test::TestServer::new( |app| app.handler(|_| httpcodes::HTTPOk.build().body(STR))); - let mut res = reqwest::get(&srv.url("/")).unwrap(); - assert!(res.status().is_success()); - let mut bytes = BytesMut::with_capacity(2048).writer(); - let _ = res.copy_to(&mut bytes); - let bytes = bytes.into_inner(); + + let request = srv.get().finish().unwrap(); + let response = srv.execute(request.send()).unwrap(); + assert!(response.status().is_success()); + + // read response + let bytes = srv.execute(response.body()).unwrap(); assert_eq!(bytes, Bytes::from_static(STR.as_ref())); } #[test] fn test_body_gzip() { - let srv = test::TestServer::new( + let mut srv = test::TestServer::new( |app| app.handler( |_| httpcodes::HTTPOk.build() .content_encoding(headers::ContentEncoding::Gzip) .body(STR))); - let mut res = reqwest::get(&srv.url("/")).unwrap(); - assert!(res.status().is_success()); - let mut bytes = BytesMut::with_capacity(2048).writer(); - let _ = res.copy_to(&mut bytes); - let bytes = bytes.into_inner(); - assert_eq!(bytes, Bytes::from_static(STR.as_ref())); + + let request = srv.get().finish().unwrap(); + let response = srv.execute(request.send()).unwrap(); + assert!(response.status().is_success()); + + // read response + let bytes = srv.execute(response.body()).unwrap(); + + // decode + let mut e = GzDecoder::new(&bytes[..]); + let mut dec = Vec::new(); + e.read_to_end(&mut dec).unwrap(); + assert_eq!(Bytes::from(dec), Bytes::from_static(STR.as_ref())); } #[test] fn test_body_streaming_implicit() { - let srv = test::TestServer::new( + let mut srv = test::TestServer::new( |app| app.handler(|_| { let body = once(Ok(Bytes::from_static(STR.as_ref()))); httpcodes::HTTPOk.build() .content_encoding(headers::ContentEncoding::Gzip) .body(Body::Streaming(Box::new(body)))})); - let mut res = reqwest::get(&srv.url("/")).unwrap(); - assert!(res.status().is_success()); - let mut bytes = BytesMut::with_capacity(2048).writer(); - let _ = res.copy_to(&mut bytes); - let bytes = bytes.into_inner(); - assert_eq!(bytes, Bytes::from_static(STR.as_ref())); + let request = srv.get().finish().unwrap(); + let response = srv.execute(request.send()).unwrap(); + assert!(response.status().is_success()); + + // read response + let bytes = srv.execute(response.body()).unwrap(); + + // decode + let mut e = GzDecoder::new(&bytes[..]); + let mut dec = Vec::new(); + e.read_to_end(&mut dec).unwrap(); + assert_eq!(Bytes::from(dec), Bytes::from_static(STR.as_ref())); } #[test] fn test_body_br_streaming() { - let srv = test::TestServer::new( + let mut srv = test::TestServer::new( |app| app.handler(|_| { let body = once(Ok(Bytes::from_static(STR.as_ref()))); httpcodes::HTTPOk.build() .content_encoding(headers::ContentEncoding::Br) .body(Body::Streaming(Box::new(body)))})); - let mut res = reqwest::get(&srv.url("/")).unwrap(); - assert!(res.status().is_success()); - let mut bytes = BytesMut::with_capacity(2048).writer(); - let _ = res.copy_to(&mut bytes); - let bytes = bytes.into_inner(); + let request = srv.get().finish().unwrap(); + let response = srv.execute(request.send()).unwrap(); + assert!(response.status().is_success()); + // read response + let bytes = srv.execute(response.body()).unwrap(); + + // decode br let mut e = BrotliDecoder::new(Vec::with_capacity(2048)); e.write_all(bytes.as_ref()).unwrap(); let dec = e.finish().unwrap(); @@ -154,84 +185,87 @@ fn test_body_br_streaming() { #[test] fn test_head_empty() { - let srv = test::TestServer::new( + let mut srv = test::TestServer::new( |app| app.handler(|_| { httpcodes::HTTPOk.build() .content_length(STR.len() as u64).finish()})); - let client = reqwest::Client::new(); - let mut res = client.head(&srv.url("/")).send().unwrap(); - assert!(res.status().is_success()); - let mut bytes = BytesMut::with_capacity(2048).writer(); - let len = res.headers() - .get::().map(|ct_len| **ct_len).unwrap(); - assert_eq!(len, STR.len() as u64); - let _ = res.copy_to(&mut bytes); - let bytes = bytes.into_inner(); - assert!(bytes.is_empty()); + let request = srv.head().finish().unwrap(); + let response = srv.execute(request.send()).unwrap(); + assert!(response.status().is_success()); + + { + let len = response.headers().get(header::CONTENT_LENGTH).unwrap(); + assert_eq!(format!("{}", STR.len()), len.to_str().unwrap()); + } + + // read response + //let bytes = srv.execute(response.body()).unwrap(); + //assert!(bytes.is_empty()); } #[test] fn test_head_binary() { - let srv = test::TestServer::new( + let mut srv = test::TestServer::new( |app| app.handler(|_| { httpcodes::HTTPOk.build() .content_encoding(headers::ContentEncoding::Identity) .content_length(100).body(STR)})); - let client = reqwest::Client::new(); - let mut res = client.head(&srv.url("/")).send().unwrap(); - assert!(res.status().is_success()); - let mut bytes = BytesMut::with_capacity(2048).writer(); - let len = res.headers() - .get::().map(|ct_len| **ct_len).unwrap(); - assert_eq!(len, STR.len() as u64); - let _ = res.copy_to(&mut bytes); - let bytes = bytes.into_inner(); - assert!(bytes.is_empty()); + let request = srv.head().finish().unwrap(); + let response = srv.execute(request.send()).unwrap(); + assert!(response.status().is_success()); + + { + let len = response.headers().get(header::CONTENT_LENGTH).unwrap(); + assert_eq!(format!("{}", STR.len()), len.to_str().unwrap()); + } + + // read response + //let bytes = srv.execute(response.body()).unwrap(); + //assert!(bytes.is_empty()); } #[test] fn test_head_binary2() { - let srv = test::TestServer::new( + let mut srv = test::TestServer::new( |app| app.handler(|_| { httpcodes::HTTPOk.build() .content_encoding(headers::ContentEncoding::Identity) .body(STR) })); - let client = reqwest::Client::new(); - let mut res = client.head(&srv.url("/")).send().unwrap(); - assert!(res.status().is_success()); - let mut bytes = BytesMut::with_capacity(2048).writer(); - let len = res.headers() - .get::().map(|ct_len| **ct_len).unwrap(); - assert_eq!(len, STR.len() as u64); - let _ = res.copy_to(&mut bytes); - let bytes = bytes.into_inner(); - assert!(bytes.is_empty()); + let request = srv.head().finish().unwrap(); + let response = srv.execute(request.send()).unwrap(); + assert!(response.status().is_success()); + + { + let len = response.headers().get(header::CONTENT_LENGTH).unwrap(); + assert_eq!(format!("{}", STR.len()), len.to_str().unwrap()); + } } #[test] fn test_body_length() { - let srv = test::TestServer::new( + let mut srv = test::TestServer::new( |app| app.handler(|_| { let body = once(Ok(Bytes::from_static(STR.as_ref()))); httpcodes::HTTPOk.build() .content_length(STR.len() as u64) .body(Body::Streaming(Box::new(body)))})); - let mut res = reqwest::get(&srv.url("/")).unwrap(); - assert!(res.status().is_success()); - let mut bytes = BytesMut::with_capacity(2048).writer(); - let _ = res.copy_to(&mut bytes); - let bytes = bytes.into_inner(); + let request = srv.get().finish().unwrap(); + let response = srv.execute(request.send()).unwrap(); + assert!(response.status().is_success()); + + // read response + let bytes = srv.execute(response.body()).unwrap(); assert_eq!(bytes, Bytes::from_static(STR.as_ref())); } #[test] fn test_body_streaming_explicit() { - let srv = test::TestServer::new( + let mut srv = test::TestServer::new( |app| app.handler(|_| { let body = once(Ok(Bytes::from_static(STR.as_ref()))); httpcodes::HTTPOk.build() @@ -239,28 +273,38 @@ fn test_body_streaming_explicit() { .content_encoding(headers::ContentEncoding::Gzip) .body(Body::Streaming(Box::new(body)))})); - let mut res = reqwest::get(&srv.url("/")).unwrap(); - assert!(res.status().is_success()); - let mut bytes = BytesMut::with_capacity(2048).writer(); - let _ = res.copy_to(&mut bytes); - let bytes = bytes.into_inner(); - assert_eq!(bytes, Bytes::from_static(STR.as_ref())); + let request = srv.get().finish().unwrap(); + let response = srv.execute(request.send()).unwrap(); + assert!(response.status().is_success()); + + // read response + let bytes = srv.execute(response.body()).unwrap(); + + // decode + let mut e = GzDecoder::new(&bytes[..]); + let mut dec = Vec::new(); + e.read_to_end(&mut dec).unwrap(); + assert_eq!(Bytes::from(dec), Bytes::from_static(STR.as_ref())); } #[test] fn test_body_deflate() { - let srv = test::TestServer::new( + let mut srv = test::TestServer::new( |app| app.handler( |_| httpcodes::HTTPOk .build() .content_encoding(headers::ContentEncoding::Deflate) .body(STR))); - let mut res = reqwest::get(&srv.url("/")).unwrap(); - assert!(res.status().is_success()); - let mut bytes = BytesMut::with_capacity(2048).writer(); - let _ = res.copy_to(&mut bytes); - let bytes = bytes.into_inner(); + // client request + let request = srv.get().finish().unwrap(); + let response = srv.execute(request.send()).unwrap(); + assert!(response.status().is_success()); + + // read response + let bytes = srv.execute(response.body()).unwrap(); + + // decode deflate let mut e = DeflateDecoder::new(Vec::new()); e.write_all(bytes.as_ref()).unwrap(); let dec = e.finish().unwrap(); @@ -269,18 +313,22 @@ fn test_body_deflate() { #[test] fn test_body_brotli() { - let srv = test::TestServer::new( + let mut srv = test::TestServer::new( |app| app.handler( |_| httpcodes::HTTPOk .build() .content_encoding(headers::ContentEncoding::Br) .body(STR))); - let mut res = reqwest::get(&srv.url("/")).unwrap(); - assert!(res.status().is_success()); - let mut bytes = BytesMut::with_capacity(2048).writer(); - let _ = res.copy_to(&mut bytes); - let bytes = bytes.into_inner(); + // client request + let request = srv.get().finish().unwrap(); + let response = srv.execute(request.send()).unwrap(); + assert!(response.status().is_success()); + + // read response + let bytes = srv.execute(response.body()).unwrap(); + + // decode brotli let mut e = BrotliDecoder::new(Vec::with_capacity(2048)); e.write_all(bytes.as_ref()).unwrap(); let dec = e.finish().unwrap(); @@ -289,7 +337,7 @@ fn test_body_brotli() { #[test] fn test_gzip_encoding() { - let srv = test::TestServer::new(|app| app.handler(|req: HttpRequest| { + let mut srv = test::TestServer::new(|app| app.handler(|req: HttpRequest| { req.body() .and_then(|bytes: Bytes| { Ok(httpcodes::HTTPOk @@ -299,23 +347,53 @@ fn test_gzip_encoding() { }).responder()} )); + // client request let mut e = GzEncoder::new(Vec::new(), Compression::default()); e.write_all(STR.as_ref()).unwrap(); let enc = e.finish().unwrap(); - let client = reqwest::Client::new(); - let mut res = client.post(&srv.url("/")) - .header(ContentEncoding(vec![Encoding::Gzip])) - .body(enc.clone()).send().unwrap(); - let mut bytes = BytesMut::with_capacity(2048).writer(); - let _ = res.copy_to(&mut bytes); - let bytes = bytes.into_inner(); + let request = srv.post() + .header(header::CONTENT_ENCODING, "gzip") + .body(enc.clone()).unwrap(); + let response = srv.execute(request.send()).unwrap(); + assert!(response.status().is_success()); + + // read response + let bytes = srv.execute(response.body()).unwrap(); assert_eq!(bytes, Bytes::from_static(STR.as_ref())); } +#[test] +fn test_client_gzip_encoding() { + let mut srv = test::TestServer::new(|app| app.handler(|req: HttpRequest| { + req.body() + .and_then(|bytes: Bytes| { + Ok(httpcodes::HTTPOk + .build() + .content_encoding(headers::ContentEncoding::Deflate) + .body(bytes)) + }).responder()} + )); + + // client request + let request = srv.post() + .content_encoding(headers::ContentEncoding::Gzip) + .body(STR).unwrap(); + let response = srv.execute(request.send()).unwrap(); + assert!(response.status().is_success()); + + // read response + let bytes = srv.execute(response.body()).unwrap(); + + let mut e = DeflateDecoder::new(Vec::new()); + e.write_all(bytes.as_ref()).unwrap(); + let dec = e.finish().unwrap(); + assert_eq!(Bytes::from(dec), Bytes::from_static(STR.as_ref())); +} + #[test] fn test_deflate_encoding() { - let srv = test::TestServer::new(|app| app.handler(|req: HttpRequest| { + let mut srv = test::TestServer::new(|app| app.handler(|req: HttpRequest| { req.body() .and_then(|bytes: Bytes| { Ok(httpcodes::HTTPOk @@ -329,19 +407,50 @@ fn test_deflate_encoding() { e.write_all(STR.as_ref()).unwrap(); let enc = e.finish().unwrap(); - let client = reqwest::Client::new(); - let mut res = client.post(&srv.url("/")) - .header(ContentEncoding(vec![Encoding::Deflate])) - .body(enc.clone()).send().unwrap(); - let mut bytes = BytesMut::with_capacity(2048).writer(); - let _ = res.copy_to(&mut bytes); - let bytes = bytes.into_inner(); + // client request + let request = srv.post() + .header(header::CONTENT_ENCODING, "deflate") + .body(enc).unwrap(); + let response = srv.execute(request.send()).unwrap(); + assert!(response.status().is_success()); + + // read response + let bytes = srv.execute(response.body()).unwrap(); assert_eq!(bytes, Bytes::from_static(STR.as_ref())); } +#[test] +fn test_client_deflate_encoding() { + let mut srv = test::TestServer::new(|app| app.handler(|req: HttpRequest| { + req.body() + .and_then(|bytes: Bytes| { + Ok(httpcodes::HTTPOk + .build() + .content_encoding(headers::ContentEncoding::Br) + .body(bytes)) + }).responder()} + )); + + // client request + let request = srv.post() + .content_encoding(headers::ContentEncoding::Deflate) + .body(STR).unwrap(); + let response = srv.execute(request.send()).unwrap(); + assert!(response.status().is_success()); + + // read response + let bytes = srv.execute(response.body()).unwrap(); + + // decode brotli + let mut e = BrotliDecoder::new(Vec::with_capacity(2048)); + e.write_all(bytes.as_ref()).unwrap(); + let dec = e.finish().unwrap(); + assert_eq!(Bytes::from(dec), Bytes::from_static(STR.as_ref())); +} + #[test] fn test_brotli_encoding() { - let srv = test::TestServer::new(|app| app.handler(|req: HttpRequest| { + let mut srv = test::TestServer::new(|app| app.handler(|req: HttpRequest| { req.body() .and_then(|bytes: Bytes| { Ok(httpcodes::HTTPOk @@ -355,16 +464,47 @@ fn test_brotli_encoding() { e.write_all(STR.as_ref()).unwrap(); let enc = e.finish().unwrap(); - let client = reqwest::Client::new(); - let mut res = client.post(&srv.url("/")) - .header(ContentEncoding(vec![Encoding::Brotli])) - .body(enc.clone()).send().unwrap(); - let mut bytes = BytesMut::with_capacity(2048).writer(); - let _ = res.copy_to(&mut bytes); - let bytes = bytes.into_inner(); + // client request + let request = srv.post() + .header(header::CONTENT_ENCODING, "br") + .body(enc).unwrap(); + let response = srv.execute(request.send()).unwrap(); + assert!(response.status().is_success()); + + // read response + let bytes = srv.execute(response.body()).unwrap(); assert_eq!(bytes, Bytes::from_static(STR.as_ref())); } +#[test] +fn test_client_brotli_encoding() { + let mut srv = test::TestServer::new(|app| app.handler(|req: HttpRequest| { + req.body() + .and_then(|bytes: Bytes| { + Ok(httpcodes::HTTPOk + .build() + .content_encoding(headers::ContentEncoding::Deflate) + .body(bytes)) + }).responder()} + )); + + // client request + let request = srv.client(Method::POST, "/") + .content_encoding(headers::ContentEncoding::Br) + .body(STR).unwrap(); + let response = srv.execute(request.send()).unwrap(); + assert!(response.status().is_success()); + + // read response + let bytes = srv.execute(response.body()).unwrap(); + + // decode brotli + let mut e = DeflateDecoder::new(Vec::with_capacity(2048)); + e.write_all(bytes.as_ref()).unwrap(); + let dec = e.finish().unwrap(); + assert_eq!(Bytes::from(dec), Bytes::from_static(STR.as_ref())); +} + #[test] fn test_h2() { let srv = test::TestServer::new(|app| app.handler(|_|{ @@ -377,7 +517,7 @@ fn test_h2() { let tcp = TcpStream::connect(&addr, &handle); let tcp = tcp.then(|res| { - client::handshake(res.unwrap()) + h2client::handshake(res.unwrap()) }).then(move |res| { let (mut client, h2) = res.unwrap(); @@ -407,9 +547,12 @@ fn test_h2() { #[test] fn test_application() { - let srv = test::TestServer::with_factory( + let mut srv = test::TestServer::with_factory( || Application::new().resource("/", |r| r.h(httpcodes::HTTPOk))); - assert!(reqwest::get(&srv.url("/")).unwrap().status().is_success()); + + let request = srv.get().finish().unwrap(); + let response = srv.execute(request.send()).unwrap(); + assert!(response.status().is_success()); } struct MiddlewareTest { @@ -445,14 +588,17 @@ fn test_middlewares() { let act_num2 = Arc::clone(&num2); let act_num3 = Arc::clone(&num3); - let srv = test::TestServer::new( + let mut srv = test::TestServer::new( move |app| app.middleware(MiddlewareTest{start: Arc::clone(&act_num1), response: Arc::clone(&act_num2), finish: Arc::clone(&act_num3)}) .handler(httpcodes::HTTPOk) ); - - assert!(reqwest::get(&srv.url("/")).unwrap().status().is_success()); + + let request = srv.get().finish().unwrap(); + let response = srv.execute(request.send()).unwrap(); + assert!(response.status().is_success()); + assert_eq!(num1.load(Ordering::Relaxed), 1); assert_eq!(num2.load(Ordering::Relaxed), 1); assert_eq!(num3.load(Ordering::Relaxed), 1); @@ -469,7 +615,7 @@ fn test_resource_middlewares() { let act_num2 = Arc::clone(&num2); let act_num3 = Arc::clone(&num3); - let srv = test::TestServer::new( + let mut srv = test::TestServer::new( move |app| app.handler2( httpcodes::HTTPOk, MiddlewareTest{start: Arc::clone(&act_num1), @@ -477,7 +623,10 @@ fn test_resource_middlewares() { finish: Arc::clone(&act_num3)}) ); - assert!(reqwest::get(&srv.url("/")).unwrap().status().is_success()); + let request = srv.get().finish().unwrap(); + let response = srv.execute(request.send()).unwrap(); + assert!(response.status().is_success()); + assert_eq!(num1.load(Ordering::Relaxed), 1); assert_eq!(num2.load(Ordering::Relaxed), 1); // assert_eq!(num3.load(Ordering::Relaxed), 1);