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:
parent
4ca711909b
commit
829dbae609
@ -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"
|
||||
|
@ -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>>;
|
||||
|
@ -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);
|
||||
|
38
src/error.rs
38
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<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);
|
||||
}
|
||||
|
@ -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(),
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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)) => {
|
||||
|
@ -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};
|
||||
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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![
|
||||
|
@ -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,
|
||||
|
@ -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() {
|
||||
///
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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())));
|
||||
|
@ -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();
|
||||
|
@ -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(
|
||||
|
@ -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();
|
||||
|
@ -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(
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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(),
|
||||
|
47
src/json.rs
47
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<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())
|
||||
}
|
||||
}
|
||||
|
29
src/lib.rs
29
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;
|
||||
|
@ -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]
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
712
src/test.rs
712
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<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()),
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user