From 829dbae609205d9245c927c6234d346957a1f94f Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Thu, 4 Oct 2018 21:14:18 -0700 Subject: [PATCH] cleanups and tests --- Cargo.toml | 2 +- src/body.rs | 1 - src/config.rs | 17 +- src/error.rs | 38 +- src/h1/codec.rs | 5 +- src/h1/decoder.rs | 666 ++++++++++++++++++++- src/h1/dispatcher.rs | 14 +- src/h1/mod.rs | 2 +- src/h1/service.rs | 4 +- src/header/common/accept.rs | 18 +- src/header/common/accept_charset.rs | 18 +- src/header/common/accept_language.rs | 12 +- src/header/common/allow.rs | 19 +- src/header/common/cache_control.rs | 10 +- src/header/common/content_disposition.rs | 9 +- src/header/common/content_language.rs | 12 +- src/header/common/content_type.rs | 10 +- src/header/common/date.rs | 4 +- src/header/common/etag.rs | 8 +- src/header/common/expires.rs | 4 +- src/header/common/if_match.rs | 8 +- src/header/common/if_modified_since.rs | 4 +- src/header/common/if_none_match.rs | 8 +- src/header/common/if_range.rs | 14 +- src/header/common/if_unmodified_since.rs | 4 +- src/header/common/last_modified.rs | 4 +- src/httpmessage.rs | 6 +- src/httpresponse.rs | 121 ++-- src/json.rs | 47 +- src/lib.rs | 29 +- src/request.rs | 25 +- src/server/mod.rs | 17 +- src/server/output.rs | 1 + src/test.rs | 712 +++++++---------------- tests/test_h1v2.rs | 1 - 35 files changed, 1063 insertions(+), 811 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 60f14485f..86012175f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -96,6 +96,7 @@ bytes = "0.4" byteorder = "1.2" futures = "0.1" tokio-codec = "0.1" +tokio = "0.1" tokio-io = "0.1" tokio-tcp = "0.1" tokio-timer = "0.2" @@ -123,7 +124,6 @@ tokio-uds = { version="0.2", optional = true } actix-web = "0.7" env_logger = "0.5" serde_derive = "1.0" -tokio = "0.1" [build-dependencies] version_check = "0.1" diff --git a/src/body.rs b/src/body.rs index e689b704c..db06bef22 100644 --- a/src/body.rs +++ b/src/body.rs @@ -4,7 +4,6 @@ use std::sync::Arc; use std::{fmt, mem}; use error::Error; -use httpresponse::HttpResponse; /// Type represent streaming body pub type BodyStream = Box>; diff --git a/src/config.rs b/src/config.rs index 508cd5dde..543e78acd 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,20 +1,15 @@ -use std::cell::{RefCell, RefMut, UnsafeCell}; -use std::collections::VecDeque; +use std::cell::UnsafeCell; use std::fmt::Write; use std::rc::Rc; use std::time::{Duration, Instant}; -use std::{env, fmt, net}; +use std::{fmt, net}; use bytes::BytesMut; use futures::{future, Future}; -use http::StatusCode; use time; use tokio_current_thread::spawn; use tokio_timer::{sleep, Delay}; -use body::Body; -use httpresponse::{HttpResponse, HttpResponseBuilder, HttpResponsePool}; -use request::{Request, RequestPool}; use server::KeepAlive; // "Sun, 06 Nov 1994 08:49:37 GMT".len() @@ -336,13 +331,7 @@ mod tests { let mut rt = current_thread::Runtime::new().unwrap(); let _ = rt.block_on(future::lazy(|| { - let settings = ServiceConfig::<()>::new( - (), - KeepAlive::Os, - 0, - 0, - ServerSettings::default(), - ); + let settings = ServiceConfig::new(KeepAlive::Os, 0, 0); let mut buf1 = BytesMut::with_capacity(DATE_VALUE_LENGTH + 10); settings.set_date(&mut buf1, true); let mut buf2 = BytesMut::with_capacity(DATE_VALUE_LENGTH + 10); diff --git a/src/error.rs b/src/error.rs index e39dea9b2..21aabac49 100644 --- a/src/error.rs +++ b/src/error.rs @@ -28,7 +28,7 @@ use httpresponse::{HttpResponse, HttpResponseParts}; /// for actix web operations /// /// This typedef is generally used to avoid writing out -/// `actix_web::error::Error` directly and is otherwise a direct mapping to +/// `actix_http::error::Error` directly and is otherwise a direct mapping to /// `Result`. pub type Result = result::Result; @@ -589,13 +589,12 @@ impl From for UrlGenerationError { /// default. /// /// ```rust -/// # extern crate actix_web; -/// # use actix_web::*; -/// use actix_web::fs::NamedFile; +/// # extern crate actix_http; +/// # use std::io; +/// # use actix_http::*; /// -/// fn index(req: HttpRequest) -> Result { -/// let f = NamedFile::open("test.txt").map_err(error::ErrorBadRequest)?; -/// Ok(f) +/// fn index(req: Request) -> Result<&'static str> { +/// Err(error::ErrorBadRequest(io::Error::new(io::ErrorKind::Other, "error"))) /// } /// # fn main() {} /// ``` @@ -837,14 +836,6 @@ mod tests { use std::error::Error as StdError; use std::io; - #[test] - #[cfg(actix_nightly)] - fn test_nightly() { - let resp: HttpResponse = - IoError::new(io::ErrorKind::Other, "test").error_response(); - assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR); - } - #[test] fn test_into_response() { let resp: HttpResponse = ParseError::Incomplete.error_response(); @@ -853,9 +844,6 @@ mod tests { let resp: HttpResponse = CookieParseError::EmptyName.error_response(); assert_eq!(resp.status(), StatusCode::BAD_REQUEST); - let resp: HttpResponse = MultipartError::Boundary.error_response(); - assert_eq!(resp.status(), StatusCode::BAD_REQUEST); - let err: HttpError = StatusCode::from_u16(10000).err().unwrap().into(); let resp: HttpResponse = err.error_response(); assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR); @@ -899,14 +887,6 @@ mod tests { assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR); } - #[test] - fn test_expect_error() { - let resp: HttpResponse = ExpectError::Encoding.error_response(); - assert_eq!(resp.status(), StatusCode::EXPECTATION_FAILED); - let resp: HttpResponse = ExpectError::UnknownExpect.error_response(); - assert_eq!(resp.status(), StatusCode::EXPECTATION_FAILED); - } - macro_rules! from { ($from:expr => $error:pat) => { match ParseError::from($from) { @@ -963,10 +943,8 @@ mod tests { #[test] fn test_internal_error() { - let err = InternalError::from_response( - ExpectError::Encoding, - HttpResponse::Ok().into(), - ); + let err = + InternalError::from_response(ParseError::Method, HttpResponse::Ok().into()); let resp: HttpResponse = err.error_response(); assert_eq!(resp.status(), StatusCode::OK); } diff --git a/src/h1/codec.rs b/src/h1/codec.rs index 011883575..f1b526d52 100644 --- a/src/h1/codec.rs +++ b/src/h1/codec.rs @@ -15,8 +15,11 @@ use httpresponse::HttpResponse; use request::RequestPool; use server::output::{ResponseInfo, ResponseLength}; +/// Http response pub enum OutMessage { + /// Http response message Response(HttpResponse), + /// Payload chunk Payload(Bytes), } @@ -35,7 +38,7 @@ impl Codec { /// Create HTTP/1 codec with request's pool pub(crate) fn with_pool(pool: &'static RequestPool) -> Self { Codec { - decoder: H1Decoder::new(pool), + decoder: H1Decoder::with_pool(pool), encoder: H1Writer::new(), } } diff --git a/src/h1/decoder.rs b/src/h1/decoder.rs index 47cc5fdf1..66f24628c 100644 --- a/src/h1/decoder.rs +++ b/src/h1/decoder.rs @@ -18,16 +18,26 @@ pub(crate) struct H1Decoder { pool: &'static RequestPool, } +/// Incoming http/1 request #[derive(Debug)] pub enum InMessage { + /// Request Message(Request), + /// Request with payload MessageWithPayload(Request), + /// Payload chunk Chunk(Bytes), + /// End of payload Eof, } impl H1Decoder { - pub fn new(pool: &'static RequestPool) -> H1Decoder { + #[cfg(test)] + pub fn new() -> H1Decoder { + H1Decoder::with_pool(RequestPool::pool()) + } + + pub fn with_pool(pool: &'static RequestPool) -> H1Decoder { H1Decoder { pool, decoder: None, @@ -497,3 +507,657 @@ impl ChunkedState { } } } + +#[cfg(test)] +mod tests { + use std::net::Shutdown; + use std::{cmp, io, time}; + + use actix::System; + use bytes::{Buf, Bytes, BytesMut}; + use futures::{future, future::ok}; + use http::{Method, Version}; + use tokio_io::{AsyncRead, AsyncWrite}; + + use super::*; + use error::ParseError; + use h1::{Dispatcher, InMessage}; + use httpmessage::HttpMessage; + use request::Request; + use server::KeepAlive; + + impl InMessage { + fn message(self) -> Request { + match self { + InMessage::Message(msg) => msg, + InMessage::MessageWithPayload(msg) => msg, + _ => panic!("error"), + } + } + fn is_payload(&self) -> bool { + match *self { + InMessage::MessageWithPayload(_) => true, + _ => panic!("error"), + } + } + fn chunk(self) -> Bytes { + match self { + InMessage::Chunk(chunk) => chunk, + _ => panic!("error"), + } + } + fn eof(&self) -> bool { + match *self { + InMessage::Eof => true, + _ => false, + } + } + } + + macro_rules! parse_ready { + ($e:expr) => {{ + match H1Decoder::new().decode($e) { + Ok(Some(msg)) => msg.message(), + Ok(_) => unreachable!("Eof during parsing http request"), + Err(err) => unreachable!("Error during parsing http request: {:?}", err), + } + }}; + } + + macro_rules! expect_parse_err { + ($e:expr) => {{ + match H1Decoder::new().decode($e) { + Err(err) => match err { + ParseError::Io(_) => unreachable!("Parse error expected"), + _ => (), + }, + _ => unreachable!("Error expected"), + } + }}; + } + + struct Buffer { + buf: Bytes, + err: Option, + } + + impl Buffer { + fn new(data: &'static str) -> Buffer { + Buffer { + buf: Bytes::from(data), + err: None, + } + } + } + + impl AsyncRead for Buffer {} + impl io::Read for Buffer { + fn read(&mut self, dst: &mut [u8]) -> Result { + if self.buf.is_empty() { + if self.err.is_some() { + Err(self.err.take().unwrap()) + } else { + Err(io::Error::new(io::ErrorKind::WouldBlock, "")) + } + } else { + let size = cmp::min(self.buf.len(), dst.len()); + let b = self.buf.split_to(size); + dst[..size].copy_from_slice(&b); + Ok(size) + } + } + } + + impl io::Write for Buffer { + fn write(&mut self, buf: &[u8]) -> io::Result { + Ok(buf.len()) + } + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } + } + impl AsyncWrite for Buffer { + fn shutdown(&mut self) -> Poll<(), io::Error> { + Ok(Async::Ready(())) + } + fn write_buf(&mut self, _: &mut B) -> Poll { + Ok(Async::NotReady) + } + } + + // #[test] + // fn test_req_parse_err() { + // let mut sys = System::new("test"); + // let _ = sys.block_on(future::lazy(|| { + // let buf = Buffer::new("GET /test HTTP/1\r\n\r\n"); + // let readbuf = BytesMut::new(); + + // let mut h1 = Dispatcher::new(buf, |req| ok(HttpResponse::Ok().finish())); + // assert!(h1.poll_io().is_ok()); + // assert!(h1.poll_io().is_ok()); + // assert!(h1.flags.contains(Flags::READ_DISCONNECTED)); + // assert_eq!(h1.tasks.len(), 1); + // future::ok::<_, ()>(()) + // })); + // } + + #[test] + fn test_parse() { + let mut buf = BytesMut::from("GET /test HTTP/1.1\r\n\r\n"); + + let mut reader = H1Decoder::new(); + match reader.decode(&mut buf) { + Ok(Some(msg)) => { + let req = msg.message(); + assert_eq!(req.version(), Version::HTTP_11); + assert_eq!(*req.method(), Method::GET); + assert_eq!(req.path(), "/test"); + } + Ok(_) | Err(_) => unreachable!("Error during parsing http request"), + } + } + + #[test] + fn test_parse_partial() { + let mut buf = BytesMut::from("PUT /test HTTP/1"); + + let mut reader = H1Decoder::new(); + match reader.decode(&mut buf) { + Ok(None) => (), + _ => unreachable!("Error"), + } + + buf.extend(b".1\r\n\r\n"); + match reader.decode(&mut buf) { + Ok(Some(msg)) => { + let mut req = msg.message(); + assert_eq!(req.version(), Version::HTTP_11); + assert_eq!(*req.method(), Method::PUT); + assert_eq!(req.path(), "/test"); + } + Ok(_) | Err(_) => unreachable!("Error during parsing http request"), + } + } + + #[test] + fn test_parse_post() { + let mut buf = BytesMut::from("POST /test2 HTTP/1.0\r\n\r\n"); + + let mut reader = H1Decoder::new(); + match reader.decode(&mut buf) { + Ok(Some(msg)) => { + let mut req = msg.message(); + assert_eq!(req.version(), Version::HTTP_10); + assert_eq!(*req.method(), Method::POST); + assert_eq!(req.path(), "/test2"); + } + Ok(_) | Err(_) => unreachable!("Error during parsing http request"), + } + } + + #[test] + fn test_parse_body() { + let mut buf = + BytesMut::from("GET /test HTTP/1.1\r\nContent-Length: 4\r\n\r\nbody"); + + let mut reader = H1Decoder::new(); + match reader.decode(&mut buf) { + Ok(Some(msg)) => { + let mut req = msg.message(); + assert_eq!(req.version(), Version::HTTP_11); + assert_eq!(*req.method(), Method::GET); + assert_eq!(req.path(), "/test"); + assert_eq!( + reader.decode(&mut buf).unwrap().unwrap().chunk().as_ref(), + b"body" + ); + } + Ok(_) | Err(_) => unreachable!("Error during parsing http request"), + } + } + + #[test] + fn test_parse_body_crlf() { + let mut buf = + BytesMut::from("\r\nGET /test HTTP/1.1\r\nContent-Length: 4\r\n\r\nbody"); + + let mut reader = H1Decoder::new(); + match reader.decode(&mut buf) { + Ok(Some(msg)) => { + let mut req = msg.message(); + assert_eq!(req.version(), Version::HTTP_11); + assert_eq!(*req.method(), Method::GET); + assert_eq!(req.path(), "/test"); + assert_eq!( + reader.decode(&mut buf).unwrap().unwrap().chunk().as_ref(), + b"body" + ); + } + Ok(_) | Err(_) => unreachable!("Error during parsing http request"), + } + } + + #[test] + fn test_parse_partial_eof() { + let mut buf = BytesMut::from("GET /test HTTP/1.1\r\n"); + let mut reader = H1Decoder::new(); + assert!(reader.decode(&mut buf).unwrap().is_none()); + + buf.extend(b"\r\n"); + match reader.decode(&mut buf) { + Ok(Some(msg)) => { + let req = msg.message(); + assert_eq!(req.version(), Version::HTTP_11); + assert_eq!(*req.method(), Method::GET); + assert_eq!(req.path(), "/test"); + } + Ok(_) | Err(_) => unreachable!("Error during parsing http request"), + } + } + + #[test] + fn test_headers_split_field() { + let mut buf = BytesMut::from("GET /test HTTP/1.1\r\n"); + + let mut reader = H1Decoder::new(); + assert!{ reader.decode(&mut buf).unwrap().is_none() } + + buf.extend(b"t"); + assert!{ reader.decode(&mut buf).unwrap().is_none() } + + buf.extend(b"es"); + assert!{ reader.decode(&mut buf).unwrap().is_none() } + + buf.extend(b"t: value\r\n\r\n"); + match reader.decode(&mut buf) { + Ok(Some(msg)) => { + let req = msg.message(); + assert_eq!(req.version(), Version::HTTP_11); + assert_eq!(*req.method(), Method::GET); + assert_eq!(req.path(), "/test"); + assert_eq!(req.headers().get("test").unwrap().as_bytes(), b"value"); + } + Ok(_) | Err(_) => unreachable!("Error during parsing http request"), + } + } + + #[test] + fn test_headers_multi_value() { + let mut buf = BytesMut::from( + "GET /test HTTP/1.1\r\n\ + Set-Cookie: c1=cookie1\r\n\ + Set-Cookie: c2=cookie2\r\n\r\n", + ); + let mut reader = H1Decoder::new(); + let msg = reader.decode(&mut buf).unwrap().unwrap(); + let req = msg.message(); + + let val: Vec<_> = req + .headers() + .get_all("Set-Cookie") + .iter() + .map(|v| v.to_str().unwrap().to_owned()) + .collect(); + assert_eq!(val[0], "c1=cookie1"); + assert_eq!(val[1], "c2=cookie2"); + } + + #[test] + fn test_conn_default_1_0() { + let mut buf = BytesMut::from("GET /test HTTP/1.0\r\n\r\n"); + let req = parse_ready!(&mut buf); + + assert!(!req.keep_alive()); + } + + #[test] + fn test_conn_default_1_1() { + let mut buf = BytesMut::from("GET /test HTTP/1.1\r\n\r\n"); + let req = parse_ready!(&mut buf); + + assert!(req.keep_alive()); + } + + #[test] + fn test_conn_close() { + let mut buf = BytesMut::from( + "GET /test HTTP/1.1\r\n\ + connection: close\r\n\r\n", + ); + let req = parse_ready!(&mut buf); + + assert!(!req.keep_alive()); + } + + #[test] + fn test_conn_close_1_0() { + let mut buf = BytesMut::from( + "GET /test HTTP/1.0\r\n\ + connection: close\r\n\r\n", + ); + let req = parse_ready!(&mut buf); + + assert!(!req.keep_alive()); + } + + #[test] + fn test_conn_keep_alive_1_0() { + let mut buf = BytesMut::from( + "GET /test HTTP/1.0\r\n\ + connection: keep-alive\r\n\r\n", + ); + let req = parse_ready!(&mut buf); + + assert!(req.keep_alive()); + } + + #[test] + fn test_conn_keep_alive_1_1() { + let mut buf = BytesMut::from( + "GET /test HTTP/1.1\r\n\ + connection: keep-alive\r\n\r\n", + ); + let req = parse_ready!(&mut buf); + + assert!(req.keep_alive()); + } + + #[test] + fn test_conn_other_1_0() { + let mut buf = BytesMut::from( + "GET /test HTTP/1.0\r\n\ + connection: other\r\n\r\n", + ); + let req = parse_ready!(&mut buf); + + assert!(!req.keep_alive()); + } + + #[test] + fn test_conn_other_1_1() { + let mut buf = BytesMut::from( + "GET /test HTTP/1.1\r\n\ + connection: other\r\n\r\n", + ); + let req = parse_ready!(&mut buf); + + assert!(req.keep_alive()); + } + + #[test] + fn test_conn_upgrade() { + let mut buf = BytesMut::from( + "GET /test HTTP/1.1\r\n\ + upgrade: websockets\r\n\ + connection: upgrade\r\n\r\n", + ); + let req = parse_ready!(&mut buf); + + assert!(req.upgrade()); + } + + #[test] + fn test_conn_upgrade_connect_method() { + let mut buf = BytesMut::from( + "CONNECT /test HTTP/1.1\r\n\ + content-type: text/plain\r\n\r\n", + ); + let req = parse_ready!(&mut buf); + + assert!(req.upgrade()); + } + + #[test] + fn test_request_chunked() { + let mut buf = BytesMut::from( + "GET /test HTTP/1.1\r\n\ + transfer-encoding: chunked\r\n\r\n", + ); + let req = parse_ready!(&mut buf); + + if let Ok(val) = req.chunked() { + assert!(val); + } else { + unreachable!("Error"); + } + + // type in chunked + let mut buf = BytesMut::from( + "GET /test HTTP/1.1\r\n\ + transfer-encoding: chnked\r\n\r\n", + ); + let req = parse_ready!(&mut buf); + + if let Ok(val) = req.chunked() { + assert!(!val); + } else { + unreachable!("Error"); + } + } + + #[test] + fn test_headers_content_length_err_1() { + let mut buf = BytesMut::from( + "GET /test HTTP/1.1\r\n\ + content-length: line\r\n\r\n", + ); + + expect_parse_err!(&mut buf) + } + + #[test] + fn test_headers_content_length_err_2() { + let mut buf = BytesMut::from( + "GET /test HTTP/1.1\r\n\ + content-length: -1\r\n\r\n", + ); + + expect_parse_err!(&mut buf); + } + + #[test] + fn test_invalid_header() { + let mut buf = BytesMut::from( + "GET /test HTTP/1.1\r\n\ + test line\r\n\r\n", + ); + + expect_parse_err!(&mut buf); + } + + #[test] + fn test_invalid_name() { + let mut buf = BytesMut::from( + "GET /test HTTP/1.1\r\n\ + test[]: line\r\n\r\n", + ); + + expect_parse_err!(&mut buf); + } + + #[test] + fn test_http_request_bad_status_line() { + let mut buf = BytesMut::from("getpath \r\n\r\n"); + expect_parse_err!(&mut buf); + } + + #[test] + fn test_http_request_upgrade() { + let mut buf = BytesMut::from( + "GET /test HTTP/1.1\r\n\ + connection: upgrade\r\n\ + upgrade: websocket\r\n\r\n\ + some raw data", + ); + let mut reader = H1Decoder::new(); + let msg = reader.decode(&mut buf).unwrap().unwrap(); + assert!(msg.is_payload()); + let req = msg.message(); + assert!(!req.keep_alive()); + assert!(req.upgrade()); + assert_eq!( + reader.decode(&mut buf).unwrap().unwrap().chunk().as_ref(), + b"some raw data" + ); + } + + #[test] + fn test_http_request_parser_utf8() { + let mut buf = BytesMut::from( + "GET /test HTTP/1.1\r\n\ + x-test: тест\r\n\r\n", + ); + let req = parse_ready!(&mut buf); + + assert_eq!( + req.headers().get("x-test").unwrap().as_bytes(), + "тест".as_bytes() + ); + } + + #[test] + fn test_http_request_parser_two_slashes() { + let mut buf = BytesMut::from("GET //path HTTP/1.1\r\n\r\n"); + let req = parse_ready!(&mut buf); + + assert_eq!(req.path(), "//path"); + } + + #[test] + fn test_http_request_parser_bad_method() { + let mut buf = BytesMut::from("!12%()+=~$ /get HTTP/1.1\r\n\r\n"); + + expect_parse_err!(&mut buf); + } + + #[test] + fn test_http_request_parser_bad_version() { + let mut buf = BytesMut::from("GET //get HT/11\r\n\r\n"); + + expect_parse_err!(&mut buf); + } + + #[test] + fn test_http_request_chunked_payload() { + let mut buf = BytesMut::from( + "GET /test HTTP/1.1\r\n\ + transfer-encoding: chunked\r\n\r\n", + ); + let mut reader = H1Decoder::new(); + let msg = reader.decode(&mut buf).unwrap().unwrap(); + assert!(msg.is_payload()); + let req = msg.message(); + assert!(req.chunked().unwrap()); + + buf.extend(b"4\r\ndata\r\n4\r\nline\r\n0\r\n\r\n"); + assert_eq!( + reader.decode(&mut buf).unwrap().unwrap().chunk().as_ref(), + b"data" + ); + assert_eq!( + reader.decode(&mut buf).unwrap().unwrap().chunk().as_ref(), + b"line" + ); + assert!(reader.decode(&mut buf).unwrap().unwrap().eof()); + } + + #[test] + fn test_http_request_chunked_payload_and_next_message() { + let mut buf = BytesMut::from( + "GET /test HTTP/1.1\r\n\ + transfer-encoding: chunked\r\n\r\n", + ); + let mut reader = H1Decoder::new(); + let msg = reader.decode(&mut buf).unwrap().unwrap(); + assert!(msg.is_payload()); + let req = msg.message(); + assert!(req.chunked().unwrap()); + + buf.extend( + b"4\r\ndata\r\n4\r\nline\r\n0\r\n\r\n\ + POST /test2 HTTP/1.1\r\n\ + transfer-encoding: chunked\r\n\r\n" + .iter(), + ); + let msg = reader.decode(&mut buf).unwrap().unwrap(); + assert_eq!(msg.chunk().as_ref(), b"data"); + let msg = reader.decode(&mut buf).unwrap().unwrap(); + assert_eq!(msg.chunk().as_ref(), b"line"); + let msg = reader.decode(&mut buf).unwrap().unwrap(); + assert!(msg.eof()); + + let msg = reader.decode(&mut buf).unwrap().unwrap(); + assert!(msg.is_payload()); + let req2 = msg.message(); + assert!(req2.chunked().unwrap()); + assert_eq!(*req2.method(), Method::POST); + assert!(req2.chunked().unwrap()); + } + + #[test] + fn test_http_request_chunked_payload_chunks() { + let mut buf = BytesMut::from( + "GET /test HTTP/1.1\r\n\ + transfer-encoding: chunked\r\n\r\n", + ); + + let mut reader = H1Decoder::new(); + let msg = reader.decode(&mut buf).unwrap().unwrap(); + assert!(msg.is_payload()); + let req = msg.message(); + assert!(req.chunked().unwrap()); + + buf.extend(b"4\r\n1111\r\n"); + let msg = reader.decode(&mut buf).unwrap().unwrap(); + assert_eq!(msg.chunk().as_ref(), b"1111"); + + buf.extend(b"4\r\ndata\r"); + let msg = reader.decode(&mut buf).unwrap().unwrap(); + assert_eq!(msg.chunk().as_ref(), b"data"); + + buf.extend(b"\n4"); + assert!(reader.decode(&mut buf).unwrap().is_none()); + + buf.extend(b"\r"); + assert!(reader.decode(&mut buf).unwrap().is_none()); + buf.extend(b"\n"); + assert!(reader.decode(&mut buf).unwrap().is_none()); + + buf.extend(b"li"); + let msg = reader.decode(&mut buf).unwrap().unwrap(); + assert_eq!(msg.chunk().as_ref(), b"li"); + + //trailers + //buf.feed_data("test: test\r\n"); + //not_ready!(reader.parse(&mut buf, &mut readbuf)); + + buf.extend(b"ne\r\n0\r\n"); + let msg = reader.decode(&mut buf).unwrap().unwrap(); + assert_eq!(msg.chunk().as_ref(), b"ne"); + assert!(reader.decode(&mut buf).unwrap().is_none()); + + buf.extend(b"\r\n"); + assert!(reader.decode(&mut buf).unwrap().unwrap().eof()); + } + + #[test] + fn test_parse_chunked_payload_chunk_extension() { + let mut buf = BytesMut::from( + &"GET /test HTTP/1.1\r\n\ + transfer-encoding: chunked\r\n\r\n"[..], + ); + + let mut reader = H1Decoder::new(); + let msg = reader.decode(&mut buf).unwrap().unwrap(); + assert!(msg.is_payload()); + assert!(msg.message().chunked().unwrap()); + + buf.extend(b"4;test\r\ndata\r\n4\r\nline\r\n0\r\n\r\n"); // test: test\r\n\r\n") + let chunk = reader.decode(&mut buf).unwrap().unwrap().chunk(); + assert_eq!(chunk, Bytes::from_static(b"data")); + let chunk = reader.decode(&mut buf).unwrap().unwrap().chunk(); + assert_eq!(chunk, Bytes::from_static(b"line")); + let msg = reader.decode(&mut buf).unwrap().unwrap(); + assert!(msg.eof()); + } +} diff --git a/src/h1/dispatcher.rs b/src/h1/dispatcher.rs index 6e5672d35..eda8ebf00 100644 --- a/src/h1/dispatcher.rs +++ b/src/h1/dispatcher.rs @@ -1,7 +1,6 @@ // #![allow(unused_imports, unused_variables, dead_code)] use std::collections::VecDeque; use std::fmt::{Debug, Display}; -use std::net::SocketAddr; // use std::time::{Duration, Instant}; use actix_net::service::Service; @@ -16,10 +15,10 @@ use error::{ParseError, PayloadError}; use payload::{Payload, PayloadStatus, PayloadWriter}; use body::Body; +use config::ServiceConfig; use error::DispatchError; use httpresponse::HttpResponse; - -use request::{Request, RequestPool}; +use request::Request; use server::input::PayloadType; use super::codec::{Codec, InMessage, OutMessage}; @@ -52,6 +51,8 @@ where state: State, payload: Option, messages: VecDeque, + + config: ServiceConfig, } enum State { @@ -79,7 +80,7 @@ where S::Error: Debug + Display, { /// Create http/1 dispatcher. - pub fn new(stream: T, service: S) -> Self { + pub fn new(stream: T, config: ServiceConfig, service: S) -> Self { let flags = Flags::FLUSHED; let framed = Framed::new(stream, Codec::new()); @@ -91,6 +92,7 @@ where service, flags, framed, + config, } } @@ -108,7 +110,7 @@ where } // if checked is set to true, delay disconnect until all tasks have finished. - fn client_disconnected(&mut self, checked: bool) { + fn client_disconnected(&mut self, _checked: bool) { self.flags.insert(Flags::READ_DISCONNECTED); if let Some(mut payload) = self.payload.take() { payload.set_error(PayloadError::Incomplete); @@ -187,7 +189,7 @@ where None }; }, - State::Payload(ref mut body) => unimplemented!(), + State::Payload(ref mut _body) => unimplemented!(), State::Response(ref mut fut) => { match fut.poll() { Ok(Async::Ready(res)) => { diff --git a/src/h1/mod.rs b/src/h1/mod.rs index 245f2fc23..1a2bb0183 100644 --- a/src/h1/mod.rs +++ b/src/h1/mod.rs @@ -4,6 +4,6 @@ mod decoder; mod dispatcher; mod service; -pub use self::codec::Codec; +pub use self::codec::{Codec, InMessage, OutMessage}; pub use self::dispatcher::Dispatcher; pub use self::service::{H1Service, H1ServiceHandler}; diff --git a/src/h1/service.rs b/src/h1/service.rs index 3017a3ef7..436e77a55 100644 --- a/src/h1/service.rs +++ b/src/h1/service.rs @@ -1,9 +1,7 @@ use std::fmt::{Debug, Display}; use std::marker::PhantomData; -use std::time::Duration; use actix_net::service::{IntoNewService, NewService, Service}; -use futures::future::{ok, FutureResult}; use futures::{Async, Future, Poll}; use tokio_io::{AsyncRead, AsyncWrite}; @@ -120,6 +118,6 @@ where } fn call(&mut self, req: Self::Request) -> Self::Future { - Dispatcher::new(req, self.srv.clone()) + Dispatcher::new(req, self.cfg.clone(), self.srv.clone()) } } diff --git a/src/header/common/accept.rs b/src/header/common/accept.rs index d736e53af..1ba321ce8 100644 --- a/src/header/common/accept.rs +++ b/src/header/common/accept.rs @@ -30,10 +30,10 @@ header! { /// /// # Examples /// ```rust - /// # extern crate actix_web; + /// # extern crate actix_http; /// extern crate mime; - /// use actix_web::HttpResponse; - /// use actix_web::http::header::{Accept, qitem}; + /// use actix_http::HttpResponse; + /// use actix_http::http::header::{Accept, qitem}; /// /// # fn main() { /// let mut builder = HttpResponse::Ok(); @@ -47,10 +47,10 @@ header! { /// ``` /// /// ```rust - /// # extern crate actix_web; + /// # extern crate actix_http; /// extern crate mime; - /// use actix_web::HttpResponse; - /// use actix_web::http::header::{Accept, qitem}; + /// use actix_http::HttpResponse; + /// use actix_http::http::header::{Accept, qitem}; /// /// # fn main() { /// let mut builder = HttpResponse::Ok(); @@ -64,10 +64,10 @@ header! { /// ``` /// /// ```rust - /// # extern crate actix_web; + /// # extern crate actix_http; /// extern crate mime; - /// use actix_web::HttpResponse; - /// use actix_web::http::header::{Accept, QualityItem, q, qitem}; + /// use actix_http::HttpResponse; + /// use actix_http::http::header::{Accept, QualityItem, q, qitem}; /// /// # fn main() { /// let mut builder = HttpResponse::Ok(); diff --git a/src/header/common/accept_charset.rs b/src/header/common/accept_charset.rs index 674415fba..49a7237aa 100644 --- a/src/header/common/accept_charset.rs +++ b/src/header/common/accept_charset.rs @@ -22,9 +22,9 @@ header! { /// /// # Examples /// ```rust - /// # extern crate actix_web; - /// use actix_web::HttpResponse; - /// use actix_web::http::header::{AcceptCharset, Charset, qitem}; + /// # extern crate actix_http; + /// use actix_http::HttpResponse; + /// use actix_http::http::header::{AcceptCharset, Charset, qitem}; /// /// # fn main() { /// let mut builder = HttpResponse::Ok(); @@ -34,9 +34,9 @@ header! { /// # } /// ``` /// ```rust - /// # extern crate actix_web; - /// use actix_web::HttpResponse; - /// use actix_web::http::header::{AcceptCharset, Charset, q, QualityItem}; + /// # extern crate actix_http; + /// use actix_http::HttpResponse; + /// use actix_http::http::header::{AcceptCharset, Charset, q, QualityItem}; /// /// # fn main() { /// let mut builder = HttpResponse::Ok(); @@ -49,9 +49,9 @@ header! { /// # } /// ``` /// ```rust - /// # extern crate actix_web; - /// use actix_web::HttpResponse; - /// use actix_web::http::header::{AcceptCharset, Charset, qitem}; + /// # extern crate actix_http; + /// use actix_http::HttpResponse; + /// use actix_http::http::header::{AcceptCharset, Charset, qitem}; /// /// # fn main() { /// let mut builder = HttpResponse::Ok(); diff --git a/src/header/common/accept_language.rs b/src/header/common/accept_language.rs index 12593e1ac..25fd97df4 100644 --- a/src/header/common/accept_language.rs +++ b/src/header/common/accept_language.rs @@ -23,10 +23,10 @@ header! { /// # Examples /// /// ```rust - /// # extern crate actix_web; + /// # extern crate actix_http; /// # extern crate language_tags; - /// use actix_web::HttpResponse; - /// use actix_web::http::header::{AcceptLanguage, LanguageTag, qitem}; + /// use actix_http::HttpResponse; + /// use actix_http::http::header::{AcceptLanguage, LanguageTag, qitem}; /// /// # fn main() { /// let mut builder = HttpResponse::Ok(); @@ -42,10 +42,10 @@ header! { /// ``` /// /// ```rust - /// # extern crate actix_web; + /// # extern crate actix_http; /// # #[macro_use] extern crate language_tags; - /// use actix_web::HttpResponse; - /// use actix_web::http::header::{AcceptLanguage, QualityItem, q, qitem}; + /// use actix_http::HttpResponse; + /// use actix_http::http::header::{AcceptLanguage, QualityItem, q, qitem}; /// # /// # fn main() { /// let mut builder = HttpResponse::Ok(); diff --git a/src/header/common/allow.rs b/src/header/common/allow.rs index 5046290de..089c823d0 100644 --- a/src/header/common/allow.rs +++ b/src/header/common/allow.rs @@ -1,5 +1,5 @@ -use http::Method; use http::header; +use http::Method; header! { /// `Allow` header, defined in [RFC7231](http://tools.ietf.org/html/rfc7231#section-7.4.1) @@ -23,11 +23,10 @@ header! { /// # Examples /// /// ```rust - /// # extern crate http; - /// # extern crate actix_web; - /// use actix_web::HttpResponse; - /// use actix_web::http::header::Allow; - /// use http::Method; + /// # extern crate actix_http; + /// use actix_http::HttpResponse; + /// use actix_http::http::header::Allow; + /// use actix_http::http::Method; /// /// # fn main() { /// let mut builder = HttpResponse::Ok(); @@ -38,11 +37,9 @@ header! { /// ``` /// /// ```rust - /// # extern crate http; - /// # extern crate actix_web; - /// use actix_web::HttpResponse; - /// use actix_web::http::header::Allow; - /// use http::Method; + /// # extern crate actix_http; + /// use actix_http::HttpResponse; + /// use actix_http::http::{Method, header::Allow}; /// /// # fn main() { /// let mut builder = HttpResponse::Ok(); diff --git a/src/header/common/cache_control.rs b/src/header/common/cache_control.rs index adc60e4a5..4379b6f7a 100644 --- a/src/header/common/cache_control.rs +++ b/src/header/common/cache_control.rs @@ -1,5 +1,5 @@ -use header::{Header, IntoHeaderValue, Writer}; use header::{fmt_comma_delimited, from_comma_delimited}; +use header::{Header, IntoHeaderValue, Writer}; use http::header; use std::fmt::{self, Write}; use std::str::FromStr; @@ -26,16 +26,16 @@ use std::str::FromStr; /// /// # Examples /// ```rust -/// use actix_web::HttpResponse; -/// use actix_web::http::header::{CacheControl, CacheDirective}; +/// use actix_http::HttpResponse; +/// use actix_http::http::header::{CacheControl, CacheDirective}; /// /// let mut builder = HttpResponse::Ok(); /// builder.set(CacheControl(vec![CacheDirective::MaxAge(86400u32)])); /// ``` /// /// ```rust -/// use actix_web::HttpResponse; -/// use actix_web::http::header::{CacheControl, CacheDirective}; +/// use actix_http::HttpResponse; +/// use actix_http::http::header::{CacheControl, CacheDirective}; /// /// let mut builder = HttpResponse::Ok(); /// builder.set(CacheControl(vec![ diff --git a/src/header/common/content_disposition.rs b/src/header/common/content_disposition.rs index 5e8cbd67a..0efc4fb0b 100644 --- a/src/header/common/content_disposition.rs +++ b/src/header/common/content_disposition.rs @@ -64,7 +64,7 @@ impl<'a> From<&'a str> for DispositionType { /// /// # Examples /// ``` -/// use actix_web::http::header::DispositionParam; +/// use actix_http::http::header::DispositionParam; /// /// let param = DispositionParam::Filename(String::from("sample.txt")); /// assert!(param.is_filename()); @@ -226,7 +226,7 @@ impl DispositionParam { /// # Example /// /// ``` -/// use actix_web::http::header::{ +/// use actix_http::http::header::{ /// Charset, ContentDisposition, DispositionParam, DispositionType, /// ExtendedValue, /// }; @@ -327,7 +327,8 @@ impl ContentDisposition { left = &left[end.ok_or(::error::ParseError::Header)? + 1..]; left = split_once(left, ';').1.trim_left(); // In fact, it should not be Err if the above code is correct. - String::from_utf8(quoted_string).map_err(|_| ::error::ParseError::Header)? + String::from_utf8(quoted_string) + .map_err(|_| ::error::ParseError::Header)? } else { // token: won't contains semicolon according to RFC 2616 Section 2.2 let (token, new_left) = split_once_and_trim(left, ';'); @@ -874,7 +875,7 @@ mod tests { "attachment; filename=\"carriage\\\rreturn.png\"", display_rendered );*/ - // No way to create a HeaderValue containing a carriage return. + // No way to create a HeaderValue containing a carriage return. let a: ContentDisposition = ContentDisposition { disposition: DispositionType::Inline, diff --git a/src/header/common/content_language.rs b/src/header/common/content_language.rs index e12d34d0d..c1f87d513 100644 --- a/src/header/common/content_language.rs +++ b/src/header/common/content_language.rs @@ -24,10 +24,10 @@ header! { /// # Examples /// /// ```rust - /// # extern crate actix_web; + /// # extern crate actix_http; /// # #[macro_use] extern crate language_tags; - /// use actix_web::HttpResponse; - /// # use actix_web::http::header::{ContentLanguage, qitem}; + /// use actix_http::HttpResponse; + /// # use actix_http::http::header::{ContentLanguage, qitem}; /// # /// # fn main() { /// let mut builder = HttpResponse::Ok(); @@ -40,10 +40,10 @@ header! { /// ``` /// /// ```rust - /// # extern crate actix_web; + /// # extern crate actix_http; /// # #[macro_use] extern crate language_tags; - /// use actix_web::HttpResponse; - /// # use actix_web::http::header::{ContentLanguage, qitem}; + /// use actix_http::HttpResponse; + /// # use actix_http::http::header::{ContentLanguage, qitem}; /// # /// # fn main() { /// diff --git a/src/header/common/content_type.rs b/src/header/common/content_type.rs index 08900e1cc..3286d4cae 100644 --- a/src/header/common/content_type.rs +++ b/src/header/common/content_type.rs @@ -31,8 +31,8 @@ header! { /// # Examples /// /// ```rust - /// use actix_web::HttpResponse; - /// use actix_web::http::header::ContentType; + /// use actix_http::HttpResponse; + /// use actix_http::http::header::ContentType; /// /// # fn main() { /// let mut builder = HttpResponse::Ok(); @@ -44,10 +44,10 @@ header! { /// /// ```rust /// # extern crate mime; - /// # extern crate actix_web; + /// # extern crate actix_http; /// use mime::TEXT_HTML; - /// use actix_web::HttpResponse; - /// use actix_web::http::header::ContentType; + /// use actix_http::HttpResponse; + /// use actix_http::http::header::ContentType; /// /// # fn main() { /// let mut builder = HttpResponse::Ok(); diff --git a/src/header/common/date.rs b/src/header/common/date.rs index 88a47bc3f..9ce2bd65f 100644 --- a/src/header/common/date.rs +++ b/src/header/common/date.rs @@ -20,8 +20,8 @@ header! { /// # Example /// /// ```rust - /// use actix_web::HttpResponse; - /// use actix_web::http::header::Date; + /// use actix_http::HttpResponse; + /// use actix_http::http::header::Date; /// use std::time::SystemTime; /// /// let mut builder = HttpResponse::Ok(); diff --git a/src/header/common/etag.rs b/src/header/common/etag.rs index 39dd908c1..ea4be2a77 100644 --- a/src/header/common/etag.rs +++ b/src/header/common/etag.rs @@ -28,16 +28,16 @@ header! { /// # Examples /// /// ```rust - /// use actix_web::HttpResponse; - /// use actix_web::http::header::{ETag, EntityTag}; + /// use actix_http::HttpResponse; + /// use actix_http::http::header::{ETag, EntityTag}; /// /// let mut builder = HttpResponse::Ok(); /// builder.set(ETag(EntityTag::new(false, "xyzzy".to_owned()))); /// ``` /// /// ```rust - /// use actix_web::HttpResponse; - /// use actix_web::http::header::{ETag, EntityTag}; + /// use actix_http::HttpResponse; + /// use actix_http::http::header::{ETag, EntityTag}; /// /// let mut builder = HttpResponse::Ok(); /// builder.set(ETag(EntityTag::new(true, "xyzzy".to_owned()))); diff --git a/src/header/common/expires.rs b/src/header/common/expires.rs index 4ec66b880..bdd25fdb9 100644 --- a/src/header/common/expires.rs +++ b/src/header/common/expires.rs @@ -22,8 +22,8 @@ header! { /// # Example /// /// ```rust - /// use actix_web::HttpResponse; - /// use actix_web::http::header::Expires; + /// use actix_http::HttpResponse; + /// use actix_http::http::header::Expires; /// use std::time::{SystemTime, Duration}; /// /// let mut builder = HttpResponse::Ok(); diff --git a/src/header/common/if_match.rs b/src/header/common/if_match.rs index 20a2b1e6b..5f7976a4a 100644 --- a/src/header/common/if_match.rs +++ b/src/header/common/if_match.rs @@ -30,16 +30,16 @@ header! { /// # Examples /// /// ```rust - /// use actix_web::HttpResponse; - /// use actix_web::http::header::IfMatch; + /// use actix_http::HttpResponse; + /// use actix_http::http::header::IfMatch; /// /// let mut builder = HttpResponse::Ok(); /// builder.set(IfMatch::Any); /// ``` /// /// ```rust - /// use actix_web::HttpResponse; - /// use actix_web::http::header::{IfMatch, EntityTag}; + /// use actix_http::HttpResponse; + /// use actix_http::http::header::{IfMatch, EntityTag}; /// /// let mut builder = HttpResponse::Ok(); /// builder.set( diff --git a/src/header/common/if_modified_since.rs b/src/header/common/if_modified_since.rs index 1914d34d3..41d6fba27 100644 --- a/src/header/common/if_modified_since.rs +++ b/src/header/common/if_modified_since.rs @@ -22,8 +22,8 @@ header! { /// # Example /// /// ```rust - /// use actix_web::HttpResponse; - /// use actix_web::http::header::IfModifiedSince; + /// use actix_http::HttpResponse; + /// use actix_http::http::header::IfModifiedSince; /// use std::time::{SystemTime, Duration}; /// /// let mut builder = HttpResponse::Ok(); diff --git a/src/header/common/if_none_match.rs b/src/header/common/if_none_match.rs index 124f4b8e0..8b3905bab 100644 --- a/src/header/common/if_none_match.rs +++ b/src/header/common/if_none_match.rs @@ -32,16 +32,16 @@ header! { /// # Examples /// /// ```rust - /// use actix_web::HttpResponse; - /// use actix_web::http::header::IfNoneMatch; + /// use actix_http::HttpResponse; + /// use actix_http::http::header::IfNoneMatch; /// /// let mut builder = HttpResponse::Ok(); /// builder.set(IfNoneMatch::Any); /// ``` /// /// ```rust - /// use actix_web::HttpResponse; - /// use actix_web::http::header::{IfNoneMatch, EntityTag}; + /// use actix_http::HttpResponse; + /// use actix_http::http::header::{IfNoneMatch, EntityTag}; /// /// let mut builder = HttpResponse::Ok(); /// builder.set( diff --git a/src/header/common/if_range.rs b/src/header/common/if_range.rs index dd95b7ba8..8cbb8c897 100644 --- a/src/header/common/if_range.rs +++ b/src/header/common/if_range.rs @@ -1,7 +1,9 @@ use error::ParseError; use header::from_one_raw_str; -use header::{EntityTag, Header, HeaderName, HeaderValue, HttpDate, IntoHeaderValue, - InvalidHeaderValueBytes, Writer}; +use header::{ + EntityTag, Header, HeaderName, HeaderValue, HttpDate, IntoHeaderValue, + InvalidHeaderValueBytes, Writer, +}; use http::header; use httpmessage::HttpMessage; use std::fmt::{self, Display, Write}; @@ -35,8 +37,8 @@ use std::fmt::{self, Display, Write}; /// # Examples /// /// ```rust -/// use actix_web::HttpResponse; -/// use actix_web::http::header::{EntityTag, IfRange}; +/// use actix_http::HttpResponse; +/// use actix_http::http::header::{EntityTag, IfRange}; /// /// let mut builder = HttpResponse::Ok(); /// builder.set(IfRange::EntityTag(EntityTag::new( @@ -46,8 +48,8 @@ use std::fmt::{self, Display, Write}; /// ``` /// /// ```rust -/// use actix_web::HttpResponse; -/// use actix_web::http::header::IfRange; +/// use actix_http::HttpResponse; +/// use actix_http::http::header::IfRange; /// use std::time::{Duration, SystemTime}; /// /// let mut builder = HttpResponse::Ok(); diff --git a/src/header/common/if_unmodified_since.rs b/src/header/common/if_unmodified_since.rs index f87e760c0..02f9252e2 100644 --- a/src/header/common/if_unmodified_since.rs +++ b/src/header/common/if_unmodified_since.rs @@ -23,8 +23,8 @@ header! { /// # Example /// /// ```rust - /// use actix_web::HttpResponse; - /// use actix_web::http::header::IfUnmodifiedSince; + /// use actix_http::HttpResponse; + /// use actix_http::http::header::IfUnmodifiedSince; /// use std::time::{SystemTime, Duration}; /// /// let mut builder = HttpResponse::Ok(); diff --git a/src/header/common/last_modified.rs b/src/header/common/last_modified.rs index aba828883..608f43138 100644 --- a/src/header/common/last_modified.rs +++ b/src/header/common/last_modified.rs @@ -22,8 +22,8 @@ header! { /// # Example /// /// ```rust - /// use actix_web::HttpResponse; - /// use actix_web::http::header::LastModified; + /// use actix_http::HttpResponse; + /// use actix_http::http::header::LastModified; /// use std::time::{SystemTime, Duration}; /// /// let mut builder = HttpResponse::Ok(); diff --git a/src/httpmessage.rs b/src/httpmessage.rs index 8c972bd13..531aa1a72 100644 --- a/src/httpmessage.rs +++ b/src/httpmessage.rs @@ -106,7 +106,7 @@ pub trait HttpMessage: Sized { /// /// ## Server example /// - /// ```rust + /// ```rust,ignore /// # extern crate bytes; /// # extern crate actix_web; /// # extern crate futures; @@ -143,7 +143,7 @@ pub trait HttpMessage: Sized { /// /// ## Server example /// - /// ```rust + /// ```rust,ignore /// # extern crate actix_web; /// # extern crate futures; /// # use futures::Future; @@ -176,7 +176,7 @@ pub trait HttpMessage: Sized { /// /// ## Server example /// - /// ```rust + /// ```rust,ignore /// # extern crate actix_web; /// # extern crate futures; /// # #[macro_use] extern crate serde_derive; diff --git a/src/httpresponse.rs b/src/httpresponse.rs index 73de380ad..cdcdea94a 100644 --- a/src/httpresponse.rs +++ b/src/httpresponse.rs @@ -15,7 +15,7 @@ use serde_json; use body::Body; use error::Error; use header::{ContentEncoding, Header, IntoHeaderValue}; -use httpmessage::HttpMessage; +// use httpmessage::HttpMessage; // use httprequest::HttpRequest; /// max write buffer size 64k @@ -366,7 +366,7 @@ impl HttpResponseBuilder { /// Set a header. /// - /// ```rust + /// ```rust,ignore /// # extern crate actix_web; /// use actix_web::{http, HttpRequest, HttpResponse, Result}; /// @@ -394,7 +394,7 @@ impl HttpResponseBuilder { /// Set a header. /// - /// ```rust + /// ```rust,ignore /// # extern crate actix_web; /// use actix_web::{http, HttpRequest, HttpResponse}; /// @@ -516,7 +516,7 @@ impl HttpResponseBuilder { /// Set a cookie /// - /// ```rust + /// ```rust,ignore /// # extern crate actix_web; /// use actix_web::{http, HttpRequest, HttpResponse, Result}; /// @@ -546,7 +546,7 @@ impl HttpResponseBuilder { /// Remove cookie /// - /// ```rust + /// ```rust,ignore /// # extern crate actix_web; /// use actix_web::{http, HttpRequest, HttpResponse, Result}; /// @@ -956,38 +956,38 @@ mod tests { assert!(dbg.contains("HttpResponse")); } - #[test] - fn test_response_cookies() { - let req = TestRequest::default() - .header(COOKIE, "cookie1=value1") - .header(COOKIE, "cookie2=value2") - .finish(); - let cookies = req.cookies().unwrap(); + // #[test] + // fn test_response_cookies() { + // let req = TestRequest::default() + // .header(COOKIE, "cookie1=value1") + // .header(COOKIE, "cookie2=value2") + // .finish(); + // let cookies = req.cookies().unwrap(); - let resp = HttpResponse::Ok() - .cookie( - http::Cookie::build("name", "value") - .domain("www.rust-lang.org") - .path("/test") - .http_only(true) - .max_age(Duration::days(1)) - .finish(), - ).del_cookie(&cookies[0]) - .finish(); + // let resp = HttpResponse::Ok() + // .cookie( + // http::Cookie::build("name", "value") + // .domain("www.rust-lang.org") + // .path("/test") + // .http_only(true) + // .max_age(Duration::days(1)) + // .finish(), + // ).del_cookie(&cookies[0]) + // .finish(); - let mut val: Vec<_> = resp - .headers() - .get_all("Set-Cookie") - .iter() - .map(|v| v.to_str().unwrap().to_owned()) - .collect(); - val.sort(); - assert!(val[0].starts_with("cookie1=; Max-Age=0;")); - assert_eq!( - val[1], - "name=value; HttpOnly; Path=/test; Domain=www.rust-lang.org; Max-Age=86400" - ); - } + // let mut val: Vec<_> = resp + // .headers() + // .get_all("Set-Cookie") + // .iter() + // .map(|v| v.to_str().unwrap().to_owned()) + // .collect(); + // val.sort(); + // assert!(val[0].starts_with("cookie1=; Max-Age=0;")); + // assert_eq!( + // val[1], + // "name=value; HttpOnly; Path=/test; Domain=www.rust-lang.org; Max-Age=86400" + // ); + // } #[test] fn test_update_response_cookies() { @@ -1131,15 +1131,6 @@ mod tests { assert_eq!(resp.status(), StatusCode::OK); assert_eq!(resp.body().bin_ref(), &Binary::from("test")); - let resp: HttpResponse = "test".respond_to(&req).ok().unwrap(); - assert_eq!(resp.status(), StatusCode::OK); - assert_eq!( - resp.headers().get(CONTENT_TYPE).unwrap(), - HeaderValue::from_static("text/plain; charset=utf-8") - ); - assert_eq!(resp.status(), StatusCode::OK); - assert_eq!(resp.body().bin_ref(), &Binary::from("test")); - let resp: HttpResponse = b"test".as_ref().into(); assert_eq!(resp.status(), StatusCode::OK); assert_eq!( @@ -1149,15 +1140,6 @@ mod tests { assert_eq!(resp.status(), StatusCode::OK); assert_eq!(resp.body().bin_ref(), &Binary::from(b"test".as_ref())); - let resp: HttpResponse = b"test".as_ref().respond_to(&req).ok().unwrap(); - assert_eq!(resp.status(), StatusCode::OK); - assert_eq!( - resp.headers().get(CONTENT_TYPE).unwrap(), - HeaderValue::from_static("application/octet-stream") - ); - assert_eq!(resp.status(), StatusCode::OK); - assert_eq!(resp.body().bin_ref(), &Binary::from(b"test".as_ref())); - let resp: HttpResponse = "test".to_owned().into(); assert_eq!(resp.status(), StatusCode::OK); assert_eq!( @@ -1167,15 +1149,6 @@ mod tests { assert_eq!(resp.status(), StatusCode::OK); assert_eq!(resp.body().bin_ref(), &Binary::from("test".to_owned())); - let resp: HttpResponse = "test".to_owned().respond_to(&req).ok().unwrap(); - assert_eq!(resp.status(), StatusCode::OK); - assert_eq!( - resp.headers().get(CONTENT_TYPE).unwrap(), - HeaderValue::from_static("text/plain; charset=utf-8") - ); - assert_eq!(resp.status(), StatusCode::OK); - assert_eq!(resp.body().bin_ref(), &Binary::from("test".to_owned())); - let resp: HttpResponse = (&"test".to_owned()).into(); assert_eq!(resp.status(), StatusCode::OK); assert_eq!( @@ -1185,15 +1158,6 @@ mod tests { assert_eq!(resp.status(), StatusCode::OK); assert_eq!(resp.body().bin_ref(), &Binary::from(&"test".to_owned())); - let resp: HttpResponse = (&"test".to_owned()).respond_to(&req).ok().unwrap(); - assert_eq!(resp.status(), StatusCode::OK); - assert_eq!( - resp.headers().get(CONTENT_TYPE).unwrap(), - HeaderValue::from_static("text/plain; charset=utf-8") - ); - assert_eq!(resp.status(), StatusCode::OK); - assert_eq!(resp.body().bin_ref(), &Binary::from(&"test".to_owned())); - let b = Bytes::from_static(b"test"); let resp: HttpResponse = b.into(); assert_eq!(resp.status(), StatusCode::OK); @@ -1208,19 +1172,6 @@ mod tests { ); let b = Bytes::from_static(b"test"); - let resp: HttpResponse = b.respond_to(&req).ok().unwrap(); - assert_eq!(resp.status(), StatusCode::OK); - assert_eq!( - resp.headers().get(CONTENT_TYPE).unwrap(), - HeaderValue::from_static("application/octet-stream") - ); - assert_eq!(resp.status(), StatusCode::OK); - assert_eq!( - resp.body().bin_ref(), - &Binary::from(Bytes::from_static(b"test")) - ); - - let b = BytesMut::from("test"); let resp: HttpResponse = b.into(); assert_eq!(resp.status(), StatusCode::OK); assert_eq!( @@ -1231,7 +1182,7 @@ mod tests { assert_eq!(resp.body().bin_ref(), &Binary::from(BytesMut::from("test"))); let b = BytesMut::from("test"); - let resp: HttpResponse = b.respond_to(&req).ok().unwrap(); + let resp: HttpResponse = b.into(); assert_eq!(resp.status(), StatusCode::OK); assert_eq!( resp.headers().get(CONTENT_TYPE).unwrap(), diff --git a/src/json.rs b/src/json.rs index 04dd369eb..5c64b9bdd 100644 --- a/src/json.rs +++ b/src/json.rs @@ -3,18 +3,13 @@ use futures::{Future, Poll, Stream}; use http::header::CONTENT_LENGTH; use std::fmt; use std::ops::{Deref, DerefMut}; -use std::rc::Rc; use mime; use serde::de::DeserializeOwned; -use serde::Serialize; use serde_json; -use error::{Error, JsonPayloadError}; -use http::StatusCode; +use error::JsonPayloadError; use httpmessage::HttpMessage; -// use httprequest::HttpRequest; -use httpresponse::HttpResponse; /// Json helper /// @@ -30,7 +25,7 @@ use httpresponse::HttpResponse; /// /// ## Example /// -/// ```rust +/// ```rust,ignore /// # extern crate actix_web; /// #[macro_use] extern crate serde_derive; /// use actix_web::{App, Json, Result, http}; @@ -57,7 +52,7 @@ use httpresponse::HttpResponse; /// to serialize into *JSON*. The type `T` must implement the `Serialize` /// trait from *serde*. /// -/// ```rust +/// ```rust,ignore /// # extern crate actix_web; /// # #[macro_use] extern crate serde_derive; /// # use actix_web::*; @@ -124,7 +119,7 @@ where /// /// # Server example /// -/// ```rust +/// ```rust,ignore /// # extern crate actix_web; /// # extern crate futures; /// # #[macro_use] extern crate serde_derive; @@ -243,9 +238,7 @@ mod tests { use futures::Async; use http::header; - use handler::Handler; use test::TestRequest; - use with::With; impl PartialEq for JsonPayloadError { fn eq(&self, other: &JsonPayloadError) -> bool { @@ -268,18 +261,6 @@ mod tests { name: String, } - #[test] - fn test_json() { - let json = Json(MyObject { - name: "test".to_owned(), - }); - let resp = json.respond_to(&TestRequest::default().finish()).unwrap(); - assert_eq!( - resp.headers().get(header::CONTENT_TYPE).unwrap(), - "application/json" - ); - } - #[test] fn test_json_body() { let req = TestRequest::default().finish(); @@ -323,24 +304,4 @@ mod tests { }) ); } - - #[test] - fn test_with_json() { - let mut cfg = JsonConfig::default(); - cfg.limit(4096); - let handler = With::new(|data: Json| data, cfg); - - let req = TestRequest::default().finish(); - assert!(handler.handle(&req).as_err().is_some()); - - let req = TestRequest::with_header( - header::CONTENT_TYPE, - header::HeaderValue::from_static("application/json"), - ).header( - header::CONTENT_LENGTH, - header::HeaderValue::from_static("16"), - ).set_payload(Bytes::from_static(b"{\"name\": \"test\"}")) - .finish(); - assert!(handler.handle(&req).as_err().is_none()) - } } diff --git a/src/lib.rs b/src/lib.rs index ec86f0320..b9f90c7a2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,7 @@ //! Actix web is a small, pragmatic, and extremely fast web framework //! for Rust. //! -//! ```rust +//! ```rust,ignore //! use actix_web::{server, App, Path, Responder}; //! # use std::thread; //! @@ -78,10 +78,11 @@ //! `gzip`, `deflate` compression. //! #![cfg_attr(actix_nightly, feature(tool_lints))] -#![warn(missing_docs)] -#![allow(unused_imports, unused_variables, dead_code)] +// #![warn(missing_docs)] +// #![allow(unused_imports, unused_variables, dead_code)] extern crate actix; +extern crate actix_net; #[macro_use] extern crate log; extern crate base64; @@ -98,7 +99,12 @@ extern crate failure; extern crate lazy_static; #[macro_use] extern crate futures; +#[cfg(feature = "brotli")] +extern crate brotli2; extern crate cookie; +extern crate encoding; +#[cfg(feature = "flate2")] +extern crate flate2; extern crate http as modhttp; extern crate httparse; extern crate language_tags; @@ -106,6 +112,8 @@ extern crate mime; extern crate mime_guess; extern crate net2; extern crate rand; +extern crate serde; +extern crate serde_urlencoded; extern crate tokio_codec; extern crate tokio_current_thread; extern crate tokio_io; @@ -116,19 +124,10 @@ extern crate tokio_timer; extern crate tokio_uds; extern crate url; #[macro_use] -extern crate serde; -#[cfg(feature = "brotli")] -extern crate brotli2; -extern crate encoding; -#[cfg(feature = "flate2")] -extern crate flate2; -extern crate serde_urlencoded; -#[macro_use] extern crate percent_encoding; extern crate serde_json; extern crate smallvec; - -extern crate actix_net; +extern crate tokio; #[cfg(test)] #[macro_use] @@ -150,7 +149,7 @@ pub mod error; pub mod h1; pub(crate) mod helpers; pub mod server; -//pub mod test; +pub mod test; //pub mod ws; pub use body::{Binary, Body}; pub use error::{Error, ResponseError, Result}; @@ -170,7 +169,7 @@ pub mod dev { //! //! ``` //! # #![allow(unused_imports)] - //! use actix_web::dev::*; + //! use actix_http::dev::*; //! ``` pub use body::BodyStream; diff --git a/src/request.rs b/src/request.rs index a75fda3a0..82d8c22fa 100644 --- a/src/request.rs +++ b/src/request.rs @@ -1,7 +1,6 @@ use std::cell::{Cell, Ref, RefCell, RefMut}; use std::collections::VecDeque; use std::fmt; -use std::net::SocketAddr; use std::rc::Rc; use http::{header, HeaderMap, Method, Uri, Version}; @@ -31,7 +30,6 @@ pub(crate) struct InnerRequest { pub(crate) headers: HeaderMap, pub(crate) extensions: RefCell, pub(crate) payload: RefCell>, - pub(crate) stream_extensions: Option>, pool: &'static RequestPool, } @@ -81,7 +79,6 @@ impl Request { flags: Cell::new(MessageFlags::empty()), payload: RefCell::new(None), extensions: RefCell::new(Extensions::new()), - stream_extensions: None, }), } } @@ -170,15 +167,13 @@ impl Request { inner: self.inner.clone(), } } +} - pub(crate) fn release(self) { - let mut inner = self.inner; - if let Some(r) = Rc::get_mut(&mut inner) { - r.reset(); - } else { - return; +impl Drop for Request { + fn drop(&mut self) { + if Rc::strong_count(&self.inner) == 1 { + self.inner.pool.release(self.inner.clone()); } - inner.pool.release(inner); } } @@ -221,11 +216,13 @@ impl RequestPool { /// Get Request object #[inline] pub fn get(pool: &'static RequestPool) -> Request { - if let Some(msg) = pool.0.borrow_mut().pop_front() { - Request { inner: msg } - } else { - Request::with_pool(pool) + if let Some(mut msg) = pool.0.borrow_mut().pop_front() { + if let Some(r) = Rc::get_mut(&mut msg) { + r.reset(); + } + return Request { inner: msg }; } + Request::with_pool(pool) } #[inline] diff --git a/src/server/mod.rs b/src/server/mod.rs index 068094c2a..0abd7c216 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -106,12 +106,9 @@ //! let _ = sys.run(); //!} //! ``` -use std::net::{Shutdown, SocketAddr}; -use std::rc::Rc; +use std::net::SocketAddr; use std::{io, time}; -use bytes::{BufMut, BytesMut}; -use futures::{Async, Poll}; use tokio_io::{AsyncRead, AsyncWrite}; use tokio_tcp::TcpStream; @@ -123,16 +120,8 @@ pub(crate) mod output; #[doc(hidden)] pub use super::helpers::write_content_length; -use body::Binary; -use extensions::Extensions; -use header::ContentEncoding; -use httpresponse::HttpResponse; - -/// max buffer size 64k -pub(crate) const MAX_WRITE_BUFFER_SIZE: usize = 65_536; - -const LW_BUFFER_SIZE: usize = 4096; -const HW_BUFFER_SIZE: usize = 32_768; +// /// max buffer size 64k +// pub(crate) const MAX_WRITE_BUFFER_SIZE: usize = 65_536; #[derive(Debug, PartialEq, Clone, Copy)] /// Server keep-alive setting diff --git a/src/server/output.rs b/src/server/output.rs index f20bd3266..cfc85e4bc 100644 --- a/src/server/output.rs +++ b/src/server/output.rs @@ -1,3 +1,4 @@ +#![allow(unused_imports, unused_variables, dead_code)] use std::fmt::Write as FmtWrite; use std::io::Write; use std::str::FromStr; diff --git a/src/test.rs b/src/test.rs index d0cfb255a..3c48df643 100644 --- a/src/test.rs +++ b/src/test.rs @@ -1,10 +1,8 @@ //! Various helpers for Actix applications to use during testing. -use std::rc::Rc; +use std::net; use std::str::FromStr; -use std::sync::mpsc; -use std::{net, thread}; -use actix_inner::{Actor, Addr, System}; +use actix::System; use cookie::Cookie; use futures::Future; @@ -13,28 +11,12 @@ use http::{HeaderMap, HttpTryFrom, Method, Uri, Version}; use net2::TcpBuilder; use tokio::runtime::current_thread::Runtime; -#[cfg(any(feature = "alpn", feature = "ssl"))] -use openssl::ssl::SslAcceptorBuilder; -#[cfg(feature = "rust-tls")] -use rustls::ServerConfig; - -use application::{App, HttpApplication}; use body::Binary; -use client::{ClientConnector, ClientRequest, ClientRequestBuilder}; -use error::Error; -use handler::{AsyncResult, AsyncResultItem, Handler, Responder}; use header::{Header, IntoHeaderValue}; -use httprequest::HttpRequest; -use httpresponse::HttpResponse; -use middleware::Middleware; -use param::Params; use payload::Payload; -use resource::Resource; -use router::Router; -use server::message::{Request, RequestPool}; -use server::{HttpServer, IntoHttpHandler, ServerSettings}; +use request::Request; use uri::Url as InnerUrl; -use ws; +// use ws; /// The `TestServer` type. /// @@ -63,9 +45,8 @@ use ws; /// ``` pub struct TestServer { addr: net::SocketAddr, - ssl: bool, - conn: Addr, rt: Runtime, + ssl: bool, } impl TestServer { @@ -73,92 +54,11 @@ impl TestServer { /// /// This method accepts configuration method. You can add /// middlewares or set handlers for test application. - pub fn new(config: F) -> Self + pub fn new(_config: F) -> Self where - F: Clone + Send + 'static + Fn(&mut TestApp<()>), + F: Fn() + Clone + Send + 'static, { - TestServerBuilder::new(|| ()).start(config) - } - - /// Create test server builder - pub fn build() -> TestServerBuilder<(), impl Fn() -> () + Clone + Send + 'static> { - TestServerBuilder::new(|| ()) - } - - /// Create test server builder with specific state factory - /// - /// This method can be used for constructing application state. - /// Also it can be used for external dependency initialization, - /// like creating sync actors for diesel integration. - pub fn build_with_state(state: F) -> TestServerBuilder - where - F: Fn() -> S + Clone + Send + 'static, - S: 'static, - { - TestServerBuilder::new(state) - } - - /// Start new test server with application factory - pub fn with_factory(factory: F) -> Self - where - F: Fn() -> H + Send + Clone + 'static, - H: IntoHttpHandler + 'static, - { - let (tx, rx) = mpsc::channel(); - - // run server in separate thread - thread::spawn(move || { - let sys = System::new("actix-test-server"); - let tcp = net::TcpListener::bind("127.0.0.1:0").unwrap(); - let local_addr = tcp.local_addr().unwrap(); - - let _ = HttpServer::new(factory) - .disable_signals() - .listen(tcp) - .keep_alive(5) - .start(); - - tx.send((System::current(), local_addr, TestServer::get_conn())) - .unwrap(); - sys.run(); - }); - - let (system, addr, conn) = rx.recv().unwrap(); - System::set_current(system); - TestServer { - addr, - conn, - ssl: false, - rt: Runtime::new().unwrap(), - } - } - - fn get_conn() -> Addr { - #[cfg(any(feature = "alpn", feature = "ssl"))] - { - use openssl::ssl::{SslConnector, SslMethod, SslVerifyMode}; - - let mut builder = SslConnector::builder(SslMethod::tls()).unwrap(); - builder.set_verify(SslVerifyMode::NONE); - ClientConnector::with_connector(builder.build()).start() - } - #[cfg(all( - feature = "rust-tls", - not(any(feature = "alpn", feature = "ssl")) - ))] - { - use rustls::ClientConfig; - use std::fs::File; - use std::io::BufReader; - let mut config = ClientConfig::new(); - let pem_file = &mut BufReader::new(File::open("tests/cert.pem").unwrap()); - config.root_store.add_pem_file(pem_file).unwrap(); - ClientConnector::with_connector(config).start() - } - #[cfg(not(any(feature = "alpn", feature = "ssl", feature = "rust-tls")))] - { - ClientConnector::default().start() - } + unimplemented!() } /// Get firat available unused address @@ -208,45 +108,45 @@ impl TestServer { self.rt.block_on(fut) } - /// Connect to websocket server at a given path - pub fn ws_at( - &mut self, path: &str, - ) -> Result<(ws::ClientReader, ws::ClientWriter), ws::ClientError> { - let url = self.url(path); - self.rt - .block_on(ws::Client::with_connector(url, self.conn.clone()).connect()) - } + // /// Connect to websocket server at a given path + // pub fn ws_at( + // &mut self, path: &str, + // ) -> Result<(ws::ClientReader, ws::ClientWriter), ws::ClientError> { + // let url = self.url(path); + // self.rt + // .block_on(ws::Client::with_connector(url, self.conn.clone()).connect()) + // } - /// Connect to a websocket server - pub fn ws( - &mut self, - ) -> Result<(ws::ClientReader, ws::ClientWriter), ws::ClientError> { - self.ws_at("/") - } + // /// Connect to a websocket server + // pub fn ws( + // &mut self, + // ) -> Result<(ws::ClientReader, ws::ClientWriter), ws::ClientError> { + // self.ws_at("/") + // } - /// Create `GET` request - pub fn get(&self) -> ClientRequestBuilder { - ClientRequest::get(self.url("/").as_str()) - } + // /// Create `GET` request + // pub fn get(&self) -> ClientRequestBuilder { + // ClientRequest::get(self.url("/").as_str()) + // } - /// Create `POST` request - pub fn post(&self) -> ClientRequestBuilder { - ClientRequest::post(self.url("/").as_str()) - } + // /// Create `POST` request + // pub fn post(&self) -> ClientRequestBuilder { + // ClientRequest::post(self.url("/").as_str()) + // } - /// Create `HEAD` request - pub fn head(&self) -> ClientRequestBuilder { - ClientRequest::head(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()) - .with_connector(self.conn.clone()) - .take() - } + // /// Connect to test http server + // pub fn client(&self, meth: Method, path: &str) -> ClientRequestBuilder { + // ClientRequest::build() + // .method(meth) + // .uri(self.url(path).as_str()) + // .with_connector(self.conn.clone()) + // .take() + // } } impl Drop for TestServer { @@ -255,183 +155,98 @@ impl Drop for TestServer { } } -/// An `TestServer` builder -/// -/// This type can be used to construct an instance of `TestServer` through a -/// builder-like pattern. -pub struct TestServerBuilder -where - F: Fn() -> S + Send + Clone + 'static, -{ - state: F, - #[cfg(any(feature = "alpn", feature = "ssl"))] - ssl: Option, - #[cfg(feature = "rust-tls")] - rust_ssl: Option, -} +// /// An `TestServer` builder +// /// +// /// This type can be used to construct an instance of `TestServer` through a +// /// builder-like pattern. +// pub struct TestServerBuilder +// where +// F: Fn() -> S + Send + Clone + 'static, +// { +// state: F, +// } -impl TestServerBuilder -where - F: Fn() -> S + Send + Clone + 'static, -{ - /// Create a new test server - pub fn new(state: F) -> TestServerBuilder { - TestServerBuilder { - state, - #[cfg(any(feature = "alpn", feature = "ssl"))] - ssl: None, - #[cfg(feature = "rust-tls")] - rust_ssl: None, - } - } +// impl TestServerBuilder +// where +// F: Fn() -> S + Send + Clone + 'static, +// { +// /// Create a new test server +// pub fn new(state: F) -> TestServerBuilder { +// TestServerBuilder { state } +// } - #[cfg(any(feature = "alpn", feature = "ssl"))] - /// Create ssl server - pub fn ssl(mut self, ssl: SslAcceptorBuilder) -> Self { - self.ssl = Some(ssl); - self - } +// #[allow(unused_mut)] +// /// Configure test application and run test server +// pub fn start(mut self, config: C) -> TestServer +// where +// C: Fn(&mut TestApp) + Clone + Send + 'static, +// { +// let (tx, rx) = mpsc::channel(); - #[cfg(feature = "rust-tls")] - /// Create rust tls server - pub fn rustls(mut self, ssl: ServerConfig) -> Self { - self.rust_ssl = Some(ssl); - self - } +// let mut has_ssl = false; - #[allow(unused_mut)] - /// Configure test application and run test server - pub fn start(mut self, config: C) -> TestServer - where - C: Fn(&mut TestApp) + Clone + Send + 'static, - { - let (tx, rx) = mpsc::channel(); +// #[cfg(any(feature = "alpn", feature = "ssl"))] +// { +// has_ssl = has_ssl || self.ssl.is_some(); +// } - let mut has_ssl = false; +// #[cfg(feature = "rust-tls")] +// { +// has_ssl = has_ssl || self.rust_ssl.is_some(); +// } - #[cfg(any(feature = "alpn", feature = "ssl"))] - { - has_ssl = has_ssl || self.ssl.is_some(); - } +// // run server in separate thread +// thread::spawn(move || { +// let addr = TestServer::unused_addr(); - #[cfg(feature = "rust-tls")] - { - has_ssl = has_ssl || self.rust_ssl.is_some(); - } +// let sys = System::new("actix-test-server"); +// let state = self.state; +// let mut srv = HttpServer::new(move || { +// let mut app = TestApp::new(state()); +// config(&mut app); +// app +// }).workers(1) +// .keep_alive(5) +// .disable_signals(); - // run server in separate thread - thread::spawn(move || { - let addr = TestServer::unused_addr(); +// tx.send((System::current(), addr, TestServer::get_conn())) +// .unwrap(); - let sys = System::new("actix-test-server"); - let state = self.state; - let mut srv = HttpServer::new(move || { - let mut app = TestApp::new(state()); - config(&mut app); - app - }).workers(1) - .keep_alive(5) - .disable_signals(); +// #[cfg(any(feature = "alpn", feature = "ssl"))] +// { +// let ssl = self.ssl.take(); +// if let Some(ssl) = ssl { +// let tcp = net::TcpListener::bind(addr).unwrap(); +// srv = srv.listen_ssl(tcp, ssl).unwrap(); +// } +// } +// #[cfg(feature = "rust-tls")] +// { +// let ssl = self.rust_ssl.take(); +// if let Some(ssl) = ssl { +// let tcp = net::TcpListener::bind(addr).unwrap(); +// srv = srv.listen_rustls(tcp, ssl); +// } +// } +// if !has_ssl { +// let tcp = net::TcpListener::bind(addr).unwrap(); +// srv = srv.listen(tcp); +// } +// srv.start(); - tx.send((System::current(), addr, TestServer::get_conn())) - .unwrap(); +// sys.run(); +// }); - #[cfg(any(feature = "alpn", feature = "ssl"))] - { - let ssl = self.ssl.take(); - if let Some(ssl) = ssl { - let tcp = net::TcpListener::bind(addr).unwrap(); - srv = srv.listen_ssl(tcp, ssl).unwrap(); - } - } - #[cfg(feature = "rust-tls")] - { - let ssl = self.rust_ssl.take(); - if let Some(ssl) = ssl { - let tcp = net::TcpListener::bind(addr).unwrap(); - srv = srv.listen_rustls(tcp, ssl); - } - } - if !has_ssl { - let tcp = net::TcpListener::bind(addr).unwrap(); - srv = srv.listen(tcp); - } - srv.start(); - - sys.run(); - }); - - let (system, addr, conn) = rx.recv().unwrap(); - System::set_current(system); - TestServer { - addr, - conn, - ssl: has_ssl, - rt: Runtime::new().unwrap(), - } - } -} - -/// Test application helper for testing request handlers. -pub struct TestApp { - app: Option>, -} - -impl TestApp { - fn new(state: S) -> TestApp { - let app = App::with_state(state); - TestApp { app: Some(app) } - } - - /// Register handler for "/" - pub fn handler(&mut self, handler: F) - where - F: Fn(&HttpRequest) -> R + 'static, - R: Responder + 'static, - { - self.app = Some(self.app.take().unwrap().resource("/", |r| r.f(handler))); - } - - /// Register middleware - pub fn middleware(&mut self, mw: T) -> &mut TestApp - where - T: Middleware + 'static, - { - self.app = Some(self.app.take().unwrap().middleware(mw)); - self - } - - /// Register resource. This method is similar - /// to `App::resource()` method. - pub fn resource(&mut self, path: &str, f: F) -> &mut TestApp - where - F: FnOnce(&mut Resource) -> R + 'static, - { - self.app = Some(self.app.take().unwrap().resource(path, f)); - self - } -} - -impl IntoHttpHandler for TestApp { - type Handler = HttpApplication; - - fn into_handler(mut self) -> HttpApplication { - self.app.take().unwrap().into_handler() - } -} - -#[doc(hidden)] -impl Iterator for TestApp { - type Item = HttpApplication; - - fn next(&mut self) -> Option { - if let Some(mut app) = self.app.take() { - Some(app.finish()) - } else { - None - } - } -} +// let (system, addr, conn) = rx.recv().unwrap(); +// System::set_current(system); +// TestServer { +// addr, +// conn, +// ssl: has_ssl, +// rt: Runtime::new().unwrap(), +// } +// } +// } /// Test `HttpRequest` builder /// @@ -460,70 +275,49 @@ impl Iterator for TestApp { /// assert_eq!(resp.status(), StatusCode::BAD_REQUEST); /// } /// ``` -pub struct TestRequest { - state: S, +pub struct TestRequest { version: Version, method: Method, uri: Uri, headers: HeaderMap, - params: Params, - cookies: Option>>, + _cookies: Option>>, payload: Option, prefix: u16, } -impl Default for TestRequest<()> { - fn default() -> TestRequest<()> { +impl Default for TestRequest { + fn default() -> TestRequest { TestRequest { - state: (), method: Method::GET, uri: Uri::from_str("/").unwrap(), version: Version::HTTP_11, headers: HeaderMap::new(), - params: Params::new(), - cookies: None, + _cookies: None, payload: None, prefix: 0, } } } -impl TestRequest<()> { +impl TestRequest { /// Create TestRequest and set request uri - pub fn with_uri(path: &str) -> TestRequest<()> { + pub fn with_uri(path: &str) -> TestRequest { TestRequest::default().uri(path) } /// Create TestRequest and set header - pub fn with_hdr(hdr: H) -> TestRequest<()> { + pub fn with_hdr(hdr: H) -> TestRequest { TestRequest::default().set(hdr) } /// Create TestRequest and set header - pub fn with_header(key: K, value: V) -> TestRequest<()> + pub fn with_header(key: K, value: V) -> TestRequest where HeaderName: HttpTryFrom, V: IntoHeaderValue, { TestRequest::default().header(key, value) } -} - -impl TestRequest { - /// Start HttpRequest build process with application state - pub fn with_state(state: S) -> TestRequest { - TestRequest { - state, - method: Method::GET, - uri: Uri::from_str("/").unwrap(), - version: Version::HTTP_11, - headers: HeaderMap::new(), - params: Params::new(), - cookies: None, - payload: None, - prefix: 0, - } - } /// Set HTTP version of this request pub fn version(mut self, ver: Version) -> Self { @@ -567,12 +361,6 @@ impl TestRequest { panic!("Can not create header"); } - /// Set request path pattern parameter - pub fn param(mut self, name: &'static str, value: &'static str) -> Self { - self.params.add_static(name, value); - self - } - /// Set request payload pub fn set_payload>(mut self, data: B) -> Self { let mut data = data.into(); @@ -588,23 +376,19 @@ impl TestRequest { self } - /// Complete request creation and generate `HttpRequest` instance - pub fn finish(self) -> HttpRequest { + /// Complete request creation and generate `Request` instance + pub fn finish(self) -> Request { let TestRequest { - state, method, uri, version, headers, - mut params, - cookies, + _cookies: _, payload, - prefix, + prefix: _, } = self; - let router = Router::<()>::default(); - let pool = RequestPool::pool(ServerSettings::default()); - let mut req = RequestPool::get(pool); + let mut req = Request::new(); { let inner = req.inner_mut(); inner.method = method; @@ -613,156 +397,94 @@ impl TestRequest { inner.headers = headers; *inner.payload.borrow_mut() = payload; } - params.set_url(req.url().clone()); - let mut info = router.route_info_params(0, params); - info.set_prefix(prefix); - - let mut req = HttpRequest::new(req, Rc::new(state), info); - req.set_cookies(cookies); + // req.set_cookies(cookies); req } - #[cfg(test)] - /// Complete request creation and generate `HttpRequest` instance - pub(crate) fn finish_with_router(self, router: Router) -> HttpRequest { - let TestRequest { - state, - method, - uri, - version, - headers, - mut params, - cookies, - payload, - prefix, - } = self; + // /// This method generates `HttpRequest` instance and runs handler + // /// with generated request. + // pub fn run>(self, h: &H) -> Result { + // let req = self.finish(); + // let resp = h.handle(&req); - let pool = RequestPool::pool(ServerSettings::default()); - let mut req = RequestPool::get(pool); - { - let inner = req.inner_mut(); - inner.method = method; - inner.url = InnerUrl::new(uri); - inner.version = version; - inner.headers = headers; - *inner.payload.borrow_mut() = payload; - } - params.set_url(req.url().clone()); - let mut info = router.route_info_params(0, params); - info.set_prefix(prefix); - let mut req = HttpRequest::new(req, Rc::new(state), info); - req.set_cookies(cookies); - req - } + // match resp.respond_to(&req) { + // Ok(resp) => match resp.into().into() { + // AsyncResultItem::Ok(resp) => Ok(resp), + // AsyncResultItem::Err(err) => Err(err), + // AsyncResultItem::Future(fut) => { + // let mut sys = System::new("test"); + // sys.block_on(fut) + // } + // }, + // Err(err) => Err(err.into()), + // } + // } - /// Complete request creation and generate server `Request` instance - pub fn request(self) -> Request { - let TestRequest { - method, - uri, - version, - headers, - payload, - .. - } = self; + // /// This method generates `HttpRequest` instance and runs handler + // /// with generated request. + // /// + // /// This method panics is handler returns actor. + // pub fn run_async(self, h: H) -> Result + // where + // H: Fn(HttpRequest) -> F + 'static, + // F: Future + 'static, + // R: Responder + 'static, + // E: Into + 'static, + // { + // let req = self.finish(); + // let fut = h(req.clone()); - let pool = RequestPool::pool(ServerSettings::default()); - let mut req = RequestPool::get(pool); - { - let inner = req.inner_mut(); - inner.method = method; - inner.url = InnerUrl::new(uri); - inner.version = version; - inner.headers = headers; - *inner.payload.borrow_mut() = payload; - } - req - } + // let mut sys = System::new("test"); + // match sys.block_on(fut) { + // Ok(r) => match r.respond_to(&req) { + // Ok(reply) => match reply.into().into() { + // AsyncResultItem::Ok(resp) => Ok(resp), + // _ => panic!("Nested async replies are not supported"), + // }, + // Err(e) => Err(e), + // }, + // Err(err) => Err(err), + // } + // } - /// This method generates `HttpRequest` instance and runs handler - /// with generated request. - pub fn run>(self, h: &H) -> Result { - let req = self.finish(); - let resp = h.handle(&req); + // /// This method generates `HttpRequest` instance and executes handler + // pub fn run_async_result(self, f: F) -> Result + // where + // F: FnOnce(&HttpRequest) -> R, + // R: Into>, + // { + // let req = self.finish(); + // let res = f(&req); - match resp.respond_to(&req) { - Ok(resp) => match resp.into().into() { - AsyncResultItem::Ok(resp) => Ok(resp), - AsyncResultItem::Err(err) => Err(err), - AsyncResultItem::Future(fut) => { - let mut sys = System::new("test"); - sys.block_on(fut) - } - }, - Err(err) => Err(err.into()), - } - } + // match res.into().into() { + // AsyncResultItem::Ok(resp) => Ok(resp), + // AsyncResultItem::Err(err) => Err(err), + // AsyncResultItem::Future(fut) => { + // let mut sys = System::new("test"); + // sys.block_on(fut) + // } + // } + // } - /// This method generates `HttpRequest` instance and runs handler - /// with generated request. - /// - /// This method panics is handler returns actor. - pub fn run_async(self, h: H) -> Result - where - H: Fn(HttpRequest) -> F + 'static, - F: Future + 'static, - R: Responder + 'static, - E: Into + 'static, - { - let req = self.finish(); - let fut = h(req.clone()); + // /// This method generates `HttpRequest` instance and executes handler + // pub fn execute(self, f: F) -> Result + // where + // F: FnOnce(&HttpRequest) -> R, + // R: Responder + 'static, + // { + // let req = self.finish(); + // let resp = f(&req); - let mut sys = System::new("test"); - match sys.block_on(fut) { - Ok(r) => match r.respond_to(&req) { - Ok(reply) => match reply.into().into() { - AsyncResultItem::Ok(resp) => Ok(resp), - _ => panic!("Nested async replies are not supported"), - }, - Err(e) => Err(e), - }, - Err(err) => Err(err), - } - } - - /// This method generates `HttpRequest` instance and executes handler - pub fn run_async_result(self, f: F) -> Result - where - F: FnOnce(&HttpRequest) -> R, - R: Into>, - { - let req = self.finish(); - let res = f(&req); - - match res.into().into() { - AsyncResultItem::Ok(resp) => Ok(resp), - AsyncResultItem::Err(err) => Err(err), - AsyncResultItem::Future(fut) => { - let mut sys = System::new("test"); - sys.block_on(fut) - } - } - } - - /// This method generates `HttpRequest` instance and executes handler - pub fn execute(self, f: F) -> Result - where - F: FnOnce(&HttpRequest) -> R, - R: Responder + 'static, - { - let req = self.finish(); - let resp = f(&req); - - match resp.respond_to(&req) { - Ok(resp) => match resp.into().into() { - AsyncResultItem::Ok(resp) => Ok(resp), - AsyncResultItem::Err(err) => Err(err), - AsyncResultItem::Future(fut) => { - let mut sys = System::new("test"); - sys.block_on(fut) - } - }, - Err(err) => Err(err.into()), - } - } + // match resp.respond_to(&req) { + // Ok(resp) => match resp.into().into() { + // AsyncResultItem::Ok(resp) => Ok(resp), + // AsyncResultItem::Err(err) => Err(err), + // AsyncResultItem::Future(fut) => { + // let mut sys = System::new("test"); + // sys.block_on(fut) + // } + // }, + // Err(err) => Err(err.into()), + // } + // } } diff --git a/tests/test_h1v2.rs b/tests/test_h1v2.rs index e32481bc2..d06777b75 100644 --- a/tests/test_h1v2.rs +++ b/tests/test_h1v2.rs @@ -8,7 +8,6 @@ use std::thread; use actix::System; use actix_net::server::Server; -use actix_net::service::{IntoNewService, IntoService}; use actix_web::{client, test}; use futures::future;