From d7cef210b37a9cdeb02103404be73a8ce6e7c90f Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Fri, 15 Jan 2021 06:50:09 +0000 Subject: [PATCH] unfinished revive tests --- .../src/header/common/content_encoding.rs | 44 +++- awc/tests/test_client.rs | 245 ++++++++---------- src/middleware/compress.rs | 3 +- tests/test_server.rs | 101 ++++---- 4 files changed, 210 insertions(+), 183 deletions(-) diff --git a/actix-http/src/header/common/content_encoding.rs b/actix-http/src/header/common/content_encoding.rs index 49f0ff78f..b93d66101 100644 --- a/actix-http/src/header/common/content_encoding.rs +++ b/actix-http/src/header/common/content_encoding.rs @@ -1,3 +1,13 @@ +use std::{convert::Infallible, str::FromStr}; + +use http::header::InvalidHeaderValue; + +use crate::{ + error::ParseError, + header::{self, from_one_raw_str, Header, HeaderName, HeaderValue, IntoHeaderValue}, + HttpMessage, +}; + /// Represents a supported content encoding. #[derive(Copy, Clone, PartialEq, Debug)] pub enum ContentEncoding { @@ -47,6 +57,20 @@ impl ContentEncoding { } } +impl Default for ContentEncoding { + fn default() -> Self { + Self::Identity + } +} + +impl FromStr for ContentEncoding { + type Err = Infallible; + + fn from_str(val: &str) -> Result { + Ok(Self::from(val)) + } +} + impl From<&str> for ContentEncoding { fn from(val: &str) -> ContentEncoding { let val = val.trim(); @@ -58,7 +82,25 @@ impl From<&str> for ContentEncoding { } else if val.eq_ignore_ascii_case("deflate") { ContentEncoding::Deflate } else { - ContentEncoding::Identity + ContentEncoding::default() } } } + +impl IntoHeaderValue for ContentEncoding { + type Error = InvalidHeaderValue; + + fn try_into_value(self) -> Result { + Ok(HeaderValue::from_static(self.as_str())) + } +} + +impl Header for ContentEncoding { + fn name() -> HeaderName { + header::CONTENT_ENCODING + } + + fn parse(msg: &T) -> Result { + from_one_raw_str(msg.headers().get(Self::name())) + } +} diff --git a/awc/tests/test_client.rs b/awc/tests/test_client.rs index 3f5bf2958..a10fed106 100644 --- a/awc/tests/test_client.rs +++ b/awc/tests/test_client.rs @@ -9,17 +9,20 @@ use bytes::Bytes; use flate2::read::GzDecoder; use flate2::write::GzEncoder; use flate2::Compression; -use futures_util::future::ok; +use futures_util::{future::ok, stream}; use rand::Rng; -use actix_http::HttpService; +use actix_http::{ + http::{self, StatusCode}, + HttpService, +}; use actix_http_test::test_server; use actix_service::{map_config, pipeline_factory}; -use actix_web::dev::{AppConfig, BodyEncoding}; -use actix_web::http::Cookie; -use actix_web::middleware::Compress; use actix_web::{ - http::header, test, web, App, Error, HttpMessage, HttpRequest, HttpResponse, + dev::{AppConfig, BodyEncoding}, + http::{header, Cookie}, + middleware::Compress, + test, web, App, Error, HttpMessage, HttpRequest, HttpResponse, }; use awc::error::SendRequestError; @@ -557,117 +560,100 @@ async fn test_client_brotli_encoding_large_random() { assert_eq!(bytes, Bytes::from(data)); } -// TODO: why is test ignored -// #[actix_rt::test] -// async fn test_client_deflate_encoding() { -// let srv = test::TestServer::start(|app| { -// app.handler(|req: &HttpRequest| { -// req.body() -// .and_then(|bytes: Bytes| { -// Ok(HttpResponse::Ok() -// .content_encoding(http::ContentEncoding::Br) -// .body(bytes)) -// }) -// .responder() -// }) -// }); +#[actix_rt::test] +async fn test_client_deflate_encoding() { + let srv = test::start(|| { + App::new().default_service(web::to(|body: Bytes| async move { + HttpResponse::Ok() + .encoding(http::ContentEncoding::Br) + .body(body) + })) + }); -// // client request -// let request = srv -// .post() -// .content_encoding(http::ContentEncoding::Deflate) -// .body(STR) -// .unwrap(); -// let response = srv.execute(request.send()).unwrap(); -// assert!(response.status().is_success()); + let req = srv + .post("/") + .insert_header(header::ContentEncoding::Deflate) + .send_body(STR); -// // read response -// let bytes = srv.execute(response.body()).unwrap(); -// assert_eq!(bytes, Bytes::from_static(STR.as_ref())); -// } + let mut res = req.await.unwrap(); + assert_eq!(res.status(), StatusCode::OK); -// TODO: why is test ignored -// #[actix_rt::test] -// async fn test_client_deflate_encoding_large_random() { -// let data = rand::thread_rng() -// .sample_iter(&rand::distributions::Alphanumeric) -// .take(70_000) -// .collect::(); + let bytes = res.body().await.unwrap(); + assert_eq!(bytes, Bytes::from_static(STR.as_ref())); +} -// let srv = test::TestServer::start(|app| { -// app.handler(|req: &HttpRequest| { -// req.body() -// .and_then(|bytes: Bytes| { -// Ok(HttpResponse::Ok() -// .content_encoding(http::ContentEncoding::Br) -// .body(bytes)) -// }) -// .responder() -// }) -// }); +#[actix_rt::test] +async fn test_client_deflate_encoding_large_random() { + let data = rand::thread_rng() + .sample_iter(rand::distributions::Alphanumeric) + .map(char::from) + .take(70_000) + .collect::(); -// // client request -// let request = srv -// .post() -// .content_encoding(http::ContentEncoding::Deflate) -// .body(data.clone()) -// .unwrap(); -// let response = srv.execute(request.send()).unwrap(); -// assert!(response.status().is_success()); + let srv = test::start(|| { + App::new().default_service(web::to(|body: Bytes| async move { + HttpResponse::Ok() + .encoding(http::ContentEncoding::Br) + .body(body) + })) + }); -// // read response -// let bytes = srv.execute(response.body()).unwrap(); -// assert_eq!(bytes, Bytes::from(data)); -// } + let req = srv + .post("/") + .insert_header(header::ContentEncoding::Deflate) + .send_body(data.clone()); -// TODO: why is test ignored -// #[actix_rt::test] -// async fn test_client_streaming_explicit() { -// let srv = test::TestServer::start(|app| { -// app.handler(|req: &HttpRequest| { -// req.body() -// .map_err(Error::from) -// .and_then(|body| { -// Ok(HttpResponse::Ok() -// .chunked() -// .content_encoding(http::ContentEncoding::Identity) -// .body(body)) -// }) -// .responder() -// }) -// }); + let mut res = req.await.unwrap(); + assert_eq!(res.status(), StatusCode::OK); -// let body = once(Ok(Bytes::from_static(STR.as_ref()))); + let bytes = res.body().await.unwrap(); + assert_eq!(bytes, Bytes::from(data)); +} -// let request = srv.get("/").body(Body::Streaming(Box::new(body))).unwrap(); -// let response = srv.execute(request.send()).unwrap(); -// assert!(response.status().is_success()); +#[actix_rt::test] +async fn test_client_streaming_explicit() { + let srv = test::start(|| { + App::new().default_service(web::to(|body: web::Payload| async move { + HttpResponse::Ok() + .encoding(http::ContentEncoding::Identity) + .streaming(body) + })) + }); -// // read response -// let bytes = srv.execute(response.body()).unwrap(); -// assert_eq!(bytes, Bytes::from_static(STR.as_ref())); -// } + let body = stream::once(async { + Ok::<_, actix_http::Error>(Bytes::from_static(STR.as_bytes())) + }); + let req = srv.post("/").send_stream(Box::pin(body)); -// TODO: why is test ignored -// #[actix_rt::test] -// async fn test_body_streaming_implicit() { -// let srv = test::TestServer::start(|app| { -// app.handler(|_| { -// let body = once(Ok(Bytes::from_static(STR.as_ref()))); -// HttpResponse::Ok() -// .content_encoding(http::ContentEncoding::Gzip) -// .body(Body::Streaming(Box::new(body))) -// }) -// }); + let mut res = req.await.unwrap(); + assert!(res.status().is_success()); -// let request = srv.get("/").finish().unwrap(); -// let response = srv.execute(request.send()).unwrap(); -// assert!(response.status().is_success()); + let bytes = res.body().await.unwrap(); + assert_eq!(bytes, Bytes::from_static(STR.as_ref())); +} -// // read response -// let bytes = srv.execute(response.body()).unwrap(); -// assert_eq!(bytes, Bytes::from_static(STR.as_ref())); -// } +#[actix_rt::test] +async fn test_body_streaming_implicit() { + let srv = test::start(|| { + App::new().default_service(web::to(|| { + let body = stream::once(async { + Ok::<_, actix_http::Error>(Bytes::from_static(STR.as_bytes())) + }); + + HttpResponse::Ok() + .encoding(http::ContentEncoding::Gzip) + .streaming(Box::pin(body)) + })) + }); + + let req = srv.get("/").send(); + + let mut res = req.await.unwrap(); + assert!(res.status().is_success()); + + let bytes = res.body().await.unwrap(); + assert_eq!(bytes, Bytes::from_static(STR.as_ref())); +} #[actix_rt::test] async fn test_client_cookie_handling() { @@ -738,36 +724,35 @@ async fn test_client_cookie_handling() { assert_eq!(c2, cookie2); } -// TODO: why is test ignored -// #[actix_rt::test] -// fn client_read_until_eof() { -// let addr = test::TestServer::unused_addr(); +#[actix_rt::test] +async fn client_unread_response() { + let addr = test::unused_addr(); -// thread::spawn(move || { -// let lst = net::TcpListener::bind(addr).unwrap(); + std::thread::spawn(move || { + let lst = std::net::TcpListener::bind(addr).unwrap(); -// for stream in lst.incoming() { -// let mut stream = stream.unwrap(); -// let mut b = [0; 1000]; -// let _ = stream.read(&mut b).unwrap(); -// let _ = stream -// .write_all(b"HTTP/1.1 200 OK\r\nconnection: close\r\n\r\nwelcome!"); -// } -// }); + for stream in lst.incoming() { + let mut stream = stream.unwrap(); + let mut b = [0; 1000]; + let _ = stream.read(&mut b).unwrap(); + let _ = stream.write_all( + b"HTTP/1.1 200 OK\r\n\ + connection: close\r\n\ + \r\n\ + welcome!", + ); + } + }); -// let mut sys = actix::System::new("test"); + // client request + let req = awc::Client::new().get(format!("http://{}/", addr).as_str()); + let mut res = req.send().await.unwrap(); + assert!(res.status().is_success()); -// // client request -// let req = client::ClientRequest::get(format!("http://{}/", addr).as_str()) -// .finish() -// .unwrap(); -// let response = req.send().await.unwrap(); -// assert!(response.status().is_success()); - -// // read response -// let bytes = response.body().await.unwrap(); -// assert_eq!(bytes, Bytes::from_static(b"welcome!")); -// } + // awc does not read all bytes unless content-length is specified + let bytes = res.body().await.unwrap(); + assert_eq!(bytes, Bytes::from_static(b"")); +} #[actix_rt::test] async fn client_basic_auth() { diff --git a/src/middleware/compress.rs b/src/middleware/compress.rs index 376719ab2..1f05b7ae3 100644 --- a/src/middleware/compress.rs +++ b/src/middleware/compress.rs @@ -16,6 +16,7 @@ use actix_http::{ Error, }; use actix_service::{Service, Transform}; +use futures_core::ready; use futures_util::future::{ok, Ready}; use pin_project::pin_project; @@ -131,7 +132,7 @@ where fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let this = self.project(); - match futures_util::ready!(this.fut.poll(cx)) { + match ready!(this.fut.poll(cx)) { Ok(resp) => { let enc = if let Some(enc) = resp.response().get_encoding() { enc diff --git a/tests/test_server.rs b/tests/test_server.rs index 7756d44d2..732a69d31 100644 --- a/tests/test_server.rs +++ b/tests/test_server.rs @@ -800,62 +800,61 @@ async fn test_reading_deflate_encoding_large_random_rustls() { assert_eq!(bytes, Bytes::from(data)); } -// TODO: why is test ignored -// #[test] -// fn test_server_cookies() { -// use actix_web::http; +#[actix_rt::test] +async fn test_server_cookies() { + use actix_web::http; -// let srv = test::TestServer::with_factory(|| { -// App::new().resource("/", |r| { -// r.f(|_| { -// HttpResponse::Ok() -// .cookie( -// http::CookieBuilder::new("first", "first_value") -// .http_only(true) -// .finish(), -// ) -// .cookie(http::Cookie::new("second", "first_value")) -// .cookie(http::Cookie::new("second", "second_value")) -// .finish() -// }) -// }) -// }); + let srv = test::TestServer::with_factory(|| { + App::new().resource("/", |r| { + r.f(|_| { + HttpResponse::Ok() + .cookie( + http::CookieBuilder::new("first", "first_value") + .http_only(true) + .finish(), + ) + .cookie(http::Cookie::new("second", "first_value")) + .cookie(http::Cookie::new("second", "second_value")) + .finish() + }) + }) + }); -// let first_cookie = http::CookieBuilder::new("first", "first_value") -// .http_only(true) -// .finish(); -// let second_cookie = http::Cookie::new("second", "second_value"); + let first_cookie = http::CookieBuilder::new("first", "first_value") + .http_only(true) + .finish(); + let second_cookie = http::Cookie::new("second", "second_value"); -// let request = srv.get("/").finish().unwrap(); -// let response = srv.execute(request.send()).unwrap(); -// assert!(response.status().is_success()); + let request = srv.get("/").finish().unwrap(); + let response = srv.execute(request.send()).unwrap(); + assert!(response.status().is_success()); -// let cookies = response.cookies().expect("To have cookies"); -// assert_eq!(cookies.len(), 2); -// if cookies[0] == first_cookie { -// assert_eq!(cookies[1], second_cookie); -// } else { -// assert_eq!(cookies[0], second_cookie); -// assert_eq!(cookies[1], first_cookie); -// } + let cookies = response.cookies().expect("To have cookies"); + assert_eq!(cookies.len(), 2); + if cookies[0] == first_cookie { + assert_eq!(cookies[1], second_cookie); + } else { + assert_eq!(cookies[0], second_cookie); + assert_eq!(cookies[1], first_cookie); + } -// let first_cookie = first_cookie.to_string(); -// let second_cookie = second_cookie.to_string(); -// //Check that we have exactly two instances of raw cookie headers -// let cookies = response -// .headers() -// .get_all(http::header::SET_COOKIE) -// .iter() -// .map(|header| header.to_str().expect("To str").to_string()) -// .collect::>(); -// assert_eq!(cookies.len(), 2); -// if cookies[0] == first_cookie { -// assert_eq!(cookies[1], second_cookie); -// } else { -// assert_eq!(cookies[0], second_cookie); -// assert_eq!(cookies[1], first_cookie); -// } -// } + let first_cookie = first_cookie.to_string(); + let second_cookie = second_cookie.to_string(); + //Check that we have exactly two instances of raw cookie headers + let cookies = response + .headers() + .get_all(http::header::SET_COOKIE) + .iter() + .map(|header| header.to_str().expect("To str").to_string()) + .collect::>(); + assert_eq!(cookies.len(), 2); + if cookies[0] == first_cookie { + assert_eq!(cookies[1], second_cookie); + } else { + assert_eq!(cookies[0], second_cookie); + assert_eq!(cookies[1], first_cookie); + } +} #[actix_rt::test] async fn test_slow_request() {