1
0
mirror of https://github.com/actix/actix-extras.git synced 2024-11-28 01:32:57 +01:00

cleanups and tests

This commit is contained in:
Nikolay Kim 2018-10-04 21:14:18 -07:00
parent 4ca711909b
commit 829dbae609
35 changed files with 1063 additions and 811 deletions

View File

@ -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"

View File

@ -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<Stream<Item = Bytes, Error = Error>>;

View File

@ -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);

View File

@ -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<T, E = Error> = result::Result<T, E>;
@ -589,13 +589,12 @@ impl From<UrlParseError> 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<fs::NamedFile> {
/// 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);
}

View File

@ -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(),
}
}

View File

@ -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<io::Error>,
}
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<usize, io::Error> {
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<usize> {
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<B: Buf>(&mut self, _: &mut B) -> Poll<usize, io::Error> {
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());
}
}

View File

@ -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<S>,
payload: Option<PayloadType>,
messages: VecDeque<Request>,
config: ServiceConfig,
}
enum State<S: Service> {
@ -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)) => {

View File

@ -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};

View File

@ -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())
}
}

View File

@ -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();

View File

@ -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();

View File

@ -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();

View File

@ -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();

View File

@ -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![

View File

@ -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,

View File

@ -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() {
///

View File

@ -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();

View File

@ -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();

View File

@ -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())));

View File

@ -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();

View File

@ -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(

View File

@ -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();

View File

@ -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(

View File

@ -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();

View File

@ -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();

View File

@ -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();

View File

@ -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;

View File

@ -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(),

View File

@ -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<MyObject>| 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())
}
}

View File

@ -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;

View File

@ -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<Extensions>,
pub(crate) payload: RefCell<Option<Payload>>,
pub(crate) stream_extensions: Option<Rc<Extensions>>,
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]

View File

@ -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

View File

@ -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;

View File

@ -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<ClientConnector>,
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<F>(config: F) -> Self
pub fn new<F>(_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<S, F>(state: F) -> TestServerBuilder<S, F>
where
F: Fn() -> S + Clone + Send + 'static,
S: 'static,
{
TestServerBuilder::new(state)
}
/// Start new test server with application factory
pub fn with_factory<F, H>(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<ClientConnector> {
#[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<S, F>
where
F: Fn() -> S + Send + Clone + 'static,
{
state: F,
#[cfg(any(feature = "alpn", feature = "ssl"))]
ssl: Option<SslAcceptorBuilder>,
#[cfg(feature = "rust-tls")]
rust_ssl: Option<ServerConfig>,
}
// /// An `TestServer` builder
// ///
// /// This type can be used to construct an instance of `TestServer` through a
// /// builder-like pattern.
// pub struct TestServerBuilder<S, F>
// where
// F: Fn() -> S + Send + Clone + 'static,
// {
// state: F,
// }
impl<S: 'static, F> TestServerBuilder<S, F>
where
F: Fn() -> S + Send + Clone + 'static,
{
/// Create a new test server
pub fn new(state: F) -> TestServerBuilder<S, F> {
TestServerBuilder {
state,
#[cfg(any(feature = "alpn", feature = "ssl"))]
ssl: None,
#[cfg(feature = "rust-tls")]
rust_ssl: None,
}
}
// impl<S: 'static, F> TestServerBuilder<S, F>
// where
// F: Fn() -> S + Send + Clone + 'static,
// {
// /// Create a new test server
// pub fn new(state: F) -> TestServerBuilder<S, F> {
// 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<C>(mut self, config: C) -> TestServer
// where
// C: Fn(&mut TestApp<S>) + 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<C>(mut self, config: C) -> TestServer
where
C: Fn(&mut TestApp<S>) + 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<S = ()> {
app: Option<App<S>>,
}
impl<S: 'static> TestApp<S> {
fn new(state: S) -> TestApp<S> {
let app = App::with_state(state);
TestApp { app: Some(app) }
}
/// Register handler for "/"
pub fn handler<F, R>(&mut self, handler: F)
where
F: Fn(&HttpRequest<S>) -> R + 'static,
R: Responder + 'static,
{
self.app = Some(self.app.take().unwrap().resource("/", |r| r.f(handler)));
}
/// Register middleware
pub fn middleware<T>(&mut self, mw: T) -> &mut TestApp<S>
where
T: Middleware<S> + 'static,
{
self.app = Some(self.app.take().unwrap().middleware(mw));
self
}
/// Register resource. This method is similar
/// to `App::resource()` method.
pub fn resource<F, R>(&mut self, path: &str, f: F) -> &mut TestApp<S>
where
F: FnOnce(&mut Resource<S>) -> R + 'static,
{
self.app = Some(self.app.take().unwrap().resource(path, f));
self
}
}
impl<S: 'static> IntoHttpHandler for TestApp<S> {
type Handler = HttpApplication<S>;
fn into_handler(mut self) -> HttpApplication<S> {
self.app.take().unwrap().into_handler()
}
}
#[doc(hidden)]
impl<S: 'static> Iterator for TestApp<S> {
type Item = HttpApplication<S>;
fn next(&mut self) -> Option<Self::Item> {
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<S: 'static> Iterator for TestApp<S> {
/// assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
/// }
/// ```
pub struct TestRequest<S> {
state: S,
pub struct TestRequest {
version: Version,
method: Method,
uri: Uri,
headers: HeaderMap,
params: Params,
cookies: Option<Vec<Cookie<'static>>>,
_cookies: Option<Vec<Cookie<'static>>>,
payload: Option<Payload>,
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<H: Header>(hdr: H) -> TestRequest<()> {
pub fn with_hdr<H: Header>(hdr: H) -> TestRequest {
TestRequest::default().set(hdr)
}
/// Create TestRequest and set header
pub fn with_header<K, V>(key: K, value: V) -> TestRequest<()>
pub fn with_header<K, V>(key: K, value: V) -> TestRequest
where
HeaderName: HttpTryFrom<K>,
V: IntoHeaderValue,
{
TestRequest::default().header(key, value)
}
}
impl<S: 'static> TestRequest<S> {
/// Start HttpRequest build process with application state
pub fn with_state(state: S) -> TestRequest<S> {
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<S: 'static> TestRequest<S> {
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<B: Into<Binary>>(mut self, data: B) -> Self {
let mut data = data.into();
@ -588,23 +376,19 @@ impl<S: 'static> TestRequest<S> {
self
}
/// Complete request creation and generate `HttpRequest` instance
pub fn finish(self) -> HttpRequest<S> {
/// 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<S: 'static> TestRequest<S> {
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<S>) -> HttpRequest<S> {
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<H: Handler<S>>(self, h: &H) -> Result<HttpResponse, Error> {
// 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<H, R, F, E>(self, h: H) -> Result<HttpResponse, E>
// where
// H: Fn(HttpRequest<S>) -> F + 'static,
// F: Future<Item = R, Error = E> + 'static,
// R: Responder<Error = E> + 'static,
// E: Into<Error> + '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<H: Handler<S>>(self, h: &H) -> Result<HttpResponse, Error> {
let req = self.finish();
let resp = h.handle(&req);
// /// This method generates `HttpRequest` instance and executes handler
// pub fn run_async_result<F, R, I, E>(self, f: F) -> Result<I, E>
// where
// F: FnOnce(&HttpRequest<S>) -> R,
// R: Into<AsyncResult<I, E>>,
// {
// 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<H, R, F, E>(self, h: H) -> Result<HttpResponse, E>
where
H: Fn(HttpRequest<S>) -> F + 'static,
F: Future<Item = R, Error = E> + 'static,
R: Responder<Error = E> + 'static,
E: Into<Error> + 'static,
{
let req = self.finish();
let fut = h(req.clone());
// /// This method generates `HttpRequest` instance and executes handler
// pub fn execute<F, R>(self, f: F) -> Result<HttpResponse, Error>
// where
// F: FnOnce(&HttpRequest<S>) -> 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<F, R, I, E>(self, f: F) -> Result<I, E>
where
F: FnOnce(&HttpRequest<S>) -> R,
R: Into<AsyncResult<I, E>>,
{
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<F, R>(self, f: F) -> Result<HttpResponse, Error>
where
F: FnOnce(&HttpRequest<S>) -> 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()),
// }
// }
}

View File

@ -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;