mirror of
https://github.com/actix/actix-extras.git
synced 2024-12-01 02:44:37 +01:00
cleanups and tests
This commit is contained in:
parent
4ca711909b
commit
829dbae609
@ -96,6 +96,7 @@ bytes = "0.4"
|
|||||||
byteorder = "1.2"
|
byteorder = "1.2"
|
||||||
futures = "0.1"
|
futures = "0.1"
|
||||||
tokio-codec = "0.1"
|
tokio-codec = "0.1"
|
||||||
|
tokio = "0.1"
|
||||||
tokio-io = "0.1"
|
tokio-io = "0.1"
|
||||||
tokio-tcp = "0.1"
|
tokio-tcp = "0.1"
|
||||||
tokio-timer = "0.2"
|
tokio-timer = "0.2"
|
||||||
@ -123,7 +124,6 @@ tokio-uds = { version="0.2", optional = true }
|
|||||||
actix-web = "0.7"
|
actix-web = "0.7"
|
||||||
env_logger = "0.5"
|
env_logger = "0.5"
|
||||||
serde_derive = "1.0"
|
serde_derive = "1.0"
|
||||||
tokio = "0.1"
|
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
version_check = "0.1"
|
version_check = "0.1"
|
||||||
|
@ -4,7 +4,6 @@ use std::sync::Arc;
|
|||||||
use std::{fmt, mem};
|
use std::{fmt, mem};
|
||||||
|
|
||||||
use error::Error;
|
use error::Error;
|
||||||
use httpresponse::HttpResponse;
|
|
||||||
|
|
||||||
/// Type represent streaming body
|
/// Type represent streaming body
|
||||||
pub type BodyStream = Box<Stream<Item = Bytes, Error = Error>>;
|
pub type BodyStream = Box<Stream<Item = Bytes, Error = Error>>;
|
||||||
|
@ -1,20 +1,15 @@
|
|||||||
use std::cell::{RefCell, RefMut, UnsafeCell};
|
use std::cell::UnsafeCell;
|
||||||
use std::collections::VecDeque;
|
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
use std::{env, fmt, net};
|
use std::{fmt, net};
|
||||||
|
|
||||||
use bytes::BytesMut;
|
use bytes::BytesMut;
|
||||||
use futures::{future, Future};
|
use futures::{future, Future};
|
||||||
use http::StatusCode;
|
|
||||||
use time;
|
use time;
|
||||||
use tokio_current_thread::spawn;
|
use tokio_current_thread::spawn;
|
||||||
use tokio_timer::{sleep, Delay};
|
use tokio_timer::{sleep, Delay};
|
||||||
|
|
||||||
use body::Body;
|
|
||||||
use httpresponse::{HttpResponse, HttpResponseBuilder, HttpResponsePool};
|
|
||||||
use request::{Request, RequestPool};
|
|
||||||
use server::KeepAlive;
|
use server::KeepAlive;
|
||||||
|
|
||||||
// "Sun, 06 Nov 1994 08:49:37 GMT".len()
|
// "Sun, 06 Nov 1994 08:49:37 GMT".len()
|
||||||
@ -336,13 +331,7 @@ mod tests {
|
|||||||
let mut rt = current_thread::Runtime::new().unwrap();
|
let mut rt = current_thread::Runtime::new().unwrap();
|
||||||
|
|
||||||
let _ = rt.block_on(future::lazy(|| {
|
let _ = rt.block_on(future::lazy(|| {
|
||||||
let settings = ServiceConfig::<()>::new(
|
let settings = ServiceConfig::new(KeepAlive::Os, 0, 0);
|
||||||
(),
|
|
||||||
KeepAlive::Os,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
ServerSettings::default(),
|
|
||||||
);
|
|
||||||
let mut buf1 = BytesMut::with_capacity(DATE_VALUE_LENGTH + 10);
|
let mut buf1 = BytesMut::with_capacity(DATE_VALUE_LENGTH + 10);
|
||||||
settings.set_date(&mut buf1, true);
|
settings.set_date(&mut buf1, true);
|
||||||
let mut buf2 = BytesMut::with_capacity(DATE_VALUE_LENGTH + 10);
|
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
|
/// for actix web operations
|
||||||
///
|
///
|
||||||
/// This typedef is generally used to avoid writing out
|
/// 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`.
|
/// `Result`.
|
||||||
pub type Result<T, E = Error> = result::Result<T, E>;
|
pub type Result<T, E = Error> = result::Result<T, E>;
|
||||||
|
|
||||||
@ -589,13 +589,12 @@ impl From<UrlParseError> for UrlGenerationError {
|
|||||||
/// default.
|
/// default.
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// # extern crate actix_web;
|
/// # extern crate actix_http;
|
||||||
/// # use actix_web::*;
|
/// # use std::io;
|
||||||
/// use actix_web::fs::NamedFile;
|
/// # use actix_http::*;
|
||||||
///
|
///
|
||||||
/// fn index(req: HttpRequest) -> Result<fs::NamedFile> {
|
/// fn index(req: Request) -> Result<&'static str> {
|
||||||
/// let f = NamedFile::open("test.txt").map_err(error::ErrorBadRequest)?;
|
/// Err(error::ErrorBadRequest(io::Error::new(io::ErrorKind::Other, "error")))
|
||||||
/// Ok(f)
|
|
||||||
/// }
|
/// }
|
||||||
/// # fn main() {}
|
/// # fn main() {}
|
||||||
/// ```
|
/// ```
|
||||||
@ -837,14 +836,6 @@ mod tests {
|
|||||||
use std::error::Error as StdError;
|
use std::error::Error as StdError;
|
||||||
use std::io;
|
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]
|
#[test]
|
||||||
fn test_into_response() {
|
fn test_into_response() {
|
||||||
let resp: HttpResponse = ParseError::Incomplete.error_response();
|
let resp: HttpResponse = ParseError::Incomplete.error_response();
|
||||||
@ -853,9 +844,6 @@ mod tests {
|
|||||||
let resp: HttpResponse = CookieParseError::EmptyName.error_response();
|
let resp: HttpResponse = CookieParseError::EmptyName.error_response();
|
||||||
assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
|
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 err: HttpError = StatusCode::from_u16(10000).err().unwrap().into();
|
||||||
let resp: HttpResponse = err.error_response();
|
let resp: HttpResponse = err.error_response();
|
||||||
assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR);
|
assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR);
|
||||||
@ -899,14 +887,6 @@ mod tests {
|
|||||||
assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR);
|
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 {
|
macro_rules! from {
|
||||||
($from:expr => $error:pat) => {
|
($from:expr => $error:pat) => {
|
||||||
match ParseError::from($from) {
|
match ParseError::from($from) {
|
||||||
@ -963,10 +943,8 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_internal_error() {
|
fn test_internal_error() {
|
||||||
let err = InternalError::from_response(
|
let err =
|
||||||
ExpectError::Encoding,
|
InternalError::from_response(ParseError::Method, HttpResponse::Ok().into());
|
||||||
HttpResponse::Ok().into(),
|
|
||||||
);
|
|
||||||
let resp: HttpResponse = err.error_response();
|
let resp: HttpResponse = err.error_response();
|
||||||
assert_eq!(resp.status(), StatusCode::OK);
|
assert_eq!(resp.status(), StatusCode::OK);
|
||||||
}
|
}
|
||||||
|
@ -15,8 +15,11 @@ use httpresponse::HttpResponse;
|
|||||||
use request::RequestPool;
|
use request::RequestPool;
|
||||||
use server::output::{ResponseInfo, ResponseLength};
|
use server::output::{ResponseInfo, ResponseLength};
|
||||||
|
|
||||||
|
/// Http response
|
||||||
pub enum OutMessage {
|
pub enum OutMessage {
|
||||||
|
/// Http response message
|
||||||
Response(HttpResponse),
|
Response(HttpResponse),
|
||||||
|
/// Payload chunk
|
||||||
Payload(Bytes),
|
Payload(Bytes),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,7 +38,7 @@ impl Codec {
|
|||||||
/// Create HTTP/1 codec with request's pool
|
/// Create HTTP/1 codec with request's pool
|
||||||
pub(crate) fn with_pool(pool: &'static RequestPool) -> Self {
|
pub(crate) fn with_pool(pool: &'static RequestPool) -> Self {
|
||||||
Codec {
|
Codec {
|
||||||
decoder: H1Decoder::new(pool),
|
decoder: H1Decoder::with_pool(pool),
|
||||||
encoder: H1Writer::new(),
|
encoder: H1Writer::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,16 +18,26 @@ pub(crate) struct H1Decoder {
|
|||||||
pool: &'static RequestPool,
|
pool: &'static RequestPool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Incoming http/1 request
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum InMessage {
|
pub enum InMessage {
|
||||||
|
/// Request
|
||||||
Message(Request),
|
Message(Request),
|
||||||
|
/// Request with payload
|
||||||
MessageWithPayload(Request),
|
MessageWithPayload(Request),
|
||||||
|
/// Payload chunk
|
||||||
Chunk(Bytes),
|
Chunk(Bytes),
|
||||||
|
/// End of payload
|
||||||
Eof,
|
Eof,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl H1Decoder {
|
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 {
|
H1Decoder {
|
||||||
pool,
|
pool,
|
||||||
decoder: None,
|
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)]
|
// #![allow(unused_imports, unused_variables, dead_code)]
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::fmt::{Debug, Display};
|
use std::fmt::{Debug, Display};
|
||||||
use std::net::SocketAddr;
|
|
||||||
// use std::time::{Duration, Instant};
|
// use std::time::{Duration, Instant};
|
||||||
|
|
||||||
use actix_net::service::Service;
|
use actix_net::service::Service;
|
||||||
@ -16,10 +15,10 @@ use error::{ParseError, PayloadError};
|
|||||||
use payload::{Payload, PayloadStatus, PayloadWriter};
|
use payload::{Payload, PayloadStatus, PayloadWriter};
|
||||||
|
|
||||||
use body::Body;
|
use body::Body;
|
||||||
|
use config::ServiceConfig;
|
||||||
use error::DispatchError;
|
use error::DispatchError;
|
||||||
use httpresponse::HttpResponse;
|
use httpresponse::HttpResponse;
|
||||||
|
use request::Request;
|
||||||
use request::{Request, RequestPool};
|
|
||||||
use server::input::PayloadType;
|
use server::input::PayloadType;
|
||||||
|
|
||||||
use super::codec::{Codec, InMessage, OutMessage};
|
use super::codec::{Codec, InMessage, OutMessage};
|
||||||
@ -52,6 +51,8 @@ where
|
|||||||
state: State<S>,
|
state: State<S>,
|
||||||
payload: Option<PayloadType>,
|
payload: Option<PayloadType>,
|
||||||
messages: VecDeque<Request>,
|
messages: VecDeque<Request>,
|
||||||
|
|
||||||
|
config: ServiceConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum State<S: Service> {
|
enum State<S: Service> {
|
||||||
@ -79,7 +80,7 @@ where
|
|||||||
S::Error: Debug + Display,
|
S::Error: Debug + Display,
|
||||||
{
|
{
|
||||||
/// Create http/1 dispatcher.
|
/// 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 flags = Flags::FLUSHED;
|
||||||
let framed = Framed::new(stream, Codec::new());
|
let framed = Framed::new(stream, Codec::new());
|
||||||
|
|
||||||
@ -91,6 +92,7 @@ where
|
|||||||
service,
|
service,
|
||||||
flags,
|
flags,
|
||||||
framed,
|
framed,
|
||||||
|
config,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,7 +110,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
// if checked is set to true, delay disconnect until all tasks have finished.
|
// 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);
|
self.flags.insert(Flags::READ_DISCONNECTED);
|
||||||
if let Some(mut payload) = self.payload.take() {
|
if let Some(mut payload) = self.payload.take() {
|
||||||
payload.set_error(PayloadError::Incomplete);
|
payload.set_error(PayloadError::Incomplete);
|
||||||
@ -187,7 +189,7 @@ where
|
|||||||
None
|
None
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
State::Payload(ref mut body) => unimplemented!(),
|
State::Payload(ref mut _body) => unimplemented!(),
|
||||||
State::Response(ref mut fut) => {
|
State::Response(ref mut fut) => {
|
||||||
match fut.poll() {
|
match fut.poll() {
|
||||||
Ok(Async::Ready(res)) => {
|
Ok(Async::Ready(res)) => {
|
||||||
|
@ -4,6 +4,6 @@ mod decoder;
|
|||||||
mod dispatcher;
|
mod dispatcher;
|
||||||
mod service;
|
mod service;
|
||||||
|
|
||||||
pub use self::codec::Codec;
|
pub use self::codec::{Codec, InMessage, OutMessage};
|
||||||
pub use self::dispatcher::Dispatcher;
|
pub use self::dispatcher::Dispatcher;
|
||||||
pub use self::service::{H1Service, H1ServiceHandler};
|
pub use self::service::{H1Service, H1ServiceHandler};
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
use std::fmt::{Debug, Display};
|
use std::fmt::{Debug, Display};
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::time::Duration;
|
|
||||||
|
|
||||||
use actix_net::service::{IntoNewService, NewService, Service};
|
use actix_net::service::{IntoNewService, NewService, Service};
|
||||||
use futures::future::{ok, FutureResult};
|
|
||||||
use futures::{Async, Future, Poll};
|
use futures::{Async, Future, Poll};
|
||||||
use tokio_io::{AsyncRead, AsyncWrite};
|
use tokio_io::{AsyncRead, AsyncWrite};
|
||||||
|
|
||||||
@ -120,6 +118,6 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn call(&mut self, req: Self::Request) -> Self::Future {
|
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
|
/// # Examples
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// # extern crate actix_web;
|
/// # extern crate actix_http;
|
||||||
/// extern crate mime;
|
/// extern crate mime;
|
||||||
/// use actix_web::HttpResponse;
|
/// use actix_http::HttpResponse;
|
||||||
/// use actix_web::http::header::{Accept, qitem};
|
/// use actix_http::http::header::{Accept, qitem};
|
||||||
///
|
///
|
||||||
/// # fn main() {
|
/// # fn main() {
|
||||||
/// let mut builder = HttpResponse::Ok();
|
/// let mut builder = HttpResponse::Ok();
|
||||||
@ -47,10 +47,10 @@ header! {
|
|||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// # extern crate actix_web;
|
/// # extern crate actix_http;
|
||||||
/// extern crate mime;
|
/// extern crate mime;
|
||||||
/// use actix_web::HttpResponse;
|
/// use actix_http::HttpResponse;
|
||||||
/// use actix_web::http::header::{Accept, qitem};
|
/// use actix_http::http::header::{Accept, qitem};
|
||||||
///
|
///
|
||||||
/// # fn main() {
|
/// # fn main() {
|
||||||
/// let mut builder = HttpResponse::Ok();
|
/// let mut builder = HttpResponse::Ok();
|
||||||
@ -64,10 +64,10 @@ header! {
|
|||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// # extern crate actix_web;
|
/// # extern crate actix_http;
|
||||||
/// extern crate mime;
|
/// extern crate mime;
|
||||||
/// use actix_web::HttpResponse;
|
/// use actix_http::HttpResponse;
|
||||||
/// use actix_web::http::header::{Accept, QualityItem, q, qitem};
|
/// use actix_http::http::header::{Accept, QualityItem, q, qitem};
|
||||||
///
|
///
|
||||||
/// # fn main() {
|
/// # fn main() {
|
||||||
/// let mut builder = HttpResponse::Ok();
|
/// let mut builder = HttpResponse::Ok();
|
||||||
|
@ -22,9 +22,9 @@ header! {
|
|||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// # extern crate actix_web;
|
/// # extern crate actix_http;
|
||||||
/// use actix_web::HttpResponse;
|
/// use actix_http::HttpResponse;
|
||||||
/// use actix_web::http::header::{AcceptCharset, Charset, qitem};
|
/// use actix_http::http::header::{AcceptCharset, Charset, qitem};
|
||||||
///
|
///
|
||||||
/// # fn main() {
|
/// # fn main() {
|
||||||
/// let mut builder = HttpResponse::Ok();
|
/// let mut builder = HttpResponse::Ok();
|
||||||
@ -34,9 +34,9 @@ header! {
|
|||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// # extern crate actix_web;
|
/// # extern crate actix_http;
|
||||||
/// use actix_web::HttpResponse;
|
/// use actix_http::HttpResponse;
|
||||||
/// use actix_web::http::header::{AcceptCharset, Charset, q, QualityItem};
|
/// use actix_http::http::header::{AcceptCharset, Charset, q, QualityItem};
|
||||||
///
|
///
|
||||||
/// # fn main() {
|
/// # fn main() {
|
||||||
/// let mut builder = HttpResponse::Ok();
|
/// let mut builder = HttpResponse::Ok();
|
||||||
@ -49,9 +49,9 @@ header! {
|
|||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// # extern crate actix_web;
|
/// # extern crate actix_http;
|
||||||
/// use actix_web::HttpResponse;
|
/// use actix_http::HttpResponse;
|
||||||
/// use actix_web::http::header::{AcceptCharset, Charset, qitem};
|
/// use actix_http::http::header::{AcceptCharset, Charset, qitem};
|
||||||
///
|
///
|
||||||
/// # fn main() {
|
/// # fn main() {
|
||||||
/// let mut builder = HttpResponse::Ok();
|
/// let mut builder = HttpResponse::Ok();
|
||||||
|
@ -23,10 +23,10 @@ header! {
|
|||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// # extern crate actix_web;
|
/// # extern crate actix_http;
|
||||||
/// # extern crate language_tags;
|
/// # extern crate language_tags;
|
||||||
/// use actix_web::HttpResponse;
|
/// use actix_http::HttpResponse;
|
||||||
/// use actix_web::http::header::{AcceptLanguage, LanguageTag, qitem};
|
/// use actix_http::http::header::{AcceptLanguage, LanguageTag, qitem};
|
||||||
///
|
///
|
||||||
/// # fn main() {
|
/// # fn main() {
|
||||||
/// let mut builder = HttpResponse::Ok();
|
/// let mut builder = HttpResponse::Ok();
|
||||||
@ -42,10 +42,10 @@ header! {
|
|||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// # extern crate actix_web;
|
/// # extern crate actix_http;
|
||||||
/// # #[macro_use] extern crate language_tags;
|
/// # #[macro_use] extern crate language_tags;
|
||||||
/// use actix_web::HttpResponse;
|
/// use actix_http::HttpResponse;
|
||||||
/// use actix_web::http::header::{AcceptLanguage, QualityItem, q, qitem};
|
/// use actix_http::http::header::{AcceptLanguage, QualityItem, q, qitem};
|
||||||
/// #
|
/// #
|
||||||
/// # fn main() {
|
/// # fn main() {
|
||||||
/// let mut builder = HttpResponse::Ok();
|
/// let mut builder = HttpResponse::Ok();
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use http::Method;
|
|
||||||
use http::header;
|
use http::header;
|
||||||
|
use http::Method;
|
||||||
|
|
||||||
header! {
|
header! {
|
||||||
/// `Allow` header, defined in [RFC7231](http://tools.ietf.org/html/rfc7231#section-7.4.1)
|
/// `Allow` header, defined in [RFC7231](http://tools.ietf.org/html/rfc7231#section-7.4.1)
|
||||||
@ -23,11 +23,10 @@ header! {
|
|||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// # extern crate http;
|
/// # extern crate actix_http;
|
||||||
/// # extern crate actix_web;
|
/// use actix_http::HttpResponse;
|
||||||
/// use actix_web::HttpResponse;
|
/// use actix_http::http::header::Allow;
|
||||||
/// use actix_web::http::header::Allow;
|
/// use actix_http::http::Method;
|
||||||
/// use http::Method;
|
|
||||||
///
|
///
|
||||||
/// # fn main() {
|
/// # fn main() {
|
||||||
/// let mut builder = HttpResponse::Ok();
|
/// let mut builder = HttpResponse::Ok();
|
||||||
@ -38,11 +37,9 @@ header! {
|
|||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// # extern crate http;
|
/// # extern crate actix_http;
|
||||||
/// # extern crate actix_web;
|
/// use actix_http::HttpResponse;
|
||||||
/// use actix_web::HttpResponse;
|
/// use actix_http::http::{Method, header::Allow};
|
||||||
/// use actix_web::http::header::Allow;
|
|
||||||
/// use http::Method;
|
|
||||||
///
|
///
|
||||||
/// # fn main() {
|
/// # fn main() {
|
||||||
/// let mut builder = HttpResponse::Ok();
|
/// let mut builder = HttpResponse::Ok();
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use header::{Header, IntoHeaderValue, Writer};
|
|
||||||
use header::{fmt_comma_delimited, from_comma_delimited};
|
use header::{fmt_comma_delimited, from_comma_delimited};
|
||||||
|
use header::{Header, IntoHeaderValue, Writer};
|
||||||
use http::header;
|
use http::header;
|
||||||
use std::fmt::{self, Write};
|
use std::fmt::{self, Write};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
@ -26,16 +26,16 @@ use std::str::FromStr;
|
|||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// use actix_web::HttpResponse;
|
/// use actix_http::HttpResponse;
|
||||||
/// use actix_web::http::header::{CacheControl, CacheDirective};
|
/// use actix_http::http::header::{CacheControl, CacheDirective};
|
||||||
///
|
///
|
||||||
/// let mut builder = HttpResponse::Ok();
|
/// let mut builder = HttpResponse::Ok();
|
||||||
/// builder.set(CacheControl(vec![CacheDirective::MaxAge(86400u32)]));
|
/// builder.set(CacheControl(vec![CacheDirective::MaxAge(86400u32)]));
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// use actix_web::HttpResponse;
|
/// use actix_http::HttpResponse;
|
||||||
/// use actix_web::http::header::{CacheControl, CacheDirective};
|
/// use actix_http::http::header::{CacheControl, CacheDirective};
|
||||||
///
|
///
|
||||||
/// let mut builder = HttpResponse::Ok();
|
/// let mut builder = HttpResponse::Ok();
|
||||||
/// builder.set(CacheControl(vec![
|
/// builder.set(CacheControl(vec![
|
||||||
|
@ -64,7 +64,7 @@ impl<'a> From<&'a str> for DispositionType {
|
|||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
/// ```
|
/// ```
|
||||||
/// use actix_web::http::header::DispositionParam;
|
/// use actix_http::http::header::DispositionParam;
|
||||||
///
|
///
|
||||||
/// let param = DispositionParam::Filename(String::from("sample.txt"));
|
/// let param = DispositionParam::Filename(String::from("sample.txt"));
|
||||||
/// assert!(param.is_filename());
|
/// assert!(param.is_filename());
|
||||||
@ -226,7 +226,7 @@ impl DispositionParam {
|
|||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use actix_web::http::header::{
|
/// use actix_http::http::header::{
|
||||||
/// Charset, ContentDisposition, DispositionParam, DispositionType,
|
/// Charset, ContentDisposition, DispositionParam, DispositionType,
|
||||||
/// ExtendedValue,
|
/// ExtendedValue,
|
||||||
/// };
|
/// };
|
||||||
@ -327,7 +327,8 @@ impl ContentDisposition {
|
|||||||
left = &left[end.ok_or(::error::ParseError::Header)? + 1..];
|
left = &left[end.ok_or(::error::ParseError::Header)? + 1..];
|
||||||
left = split_once(left, ';').1.trim_left();
|
left = split_once(left, ';').1.trim_left();
|
||||||
// In fact, it should not be Err if the above code is correct.
|
// 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 {
|
} else {
|
||||||
// token: won't contains semicolon according to RFC 2616 Section 2.2
|
// token: won't contains semicolon according to RFC 2616 Section 2.2
|
||||||
let (token, new_left) = split_once_and_trim(left, ';');
|
let (token, new_left) = split_once_and_trim(left, ';');
|
||||||
@ -874,7 +875,7 @@ mod tests {
|
|||||||
"attachment; filename=\"carriage\\\rreturn.png\"",
|
"attachment; filename=\"carriage\\\rreturn.png\"",
|
||||||
display_rendered
|
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 {
|
let a: ContentDisposition = ContentDisposition {
|
||||||
disposition: DispositionType::Inline,
|
disposition: DispositionType::Inline,
|
||||||
|
@ -24,10 +24,10 @@ header! {
|
|||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// # extern crate actix_web;
|
/// # extern crate actix_http;
|
||||||
/// # #[macro_use] extern crate language_tags;
|
/// # #[macro_use] extern crate language_tags;
|
||||||
/// use actix_web::HttpResponse;
|
/// use actix_http::HttpResponse;
|
||||||
/// # use actix_web::http::header::{ContentLanguage, qitem};
|
/// # use actix_http::http::header::{ContentLanguage, qitem};
|
||||||
/// #
|
/// #
|
||||||
/// # fn main() {
|
/// # fn main() {
|
||||||
/// let mut builder = HttpResponse::Ok();
|
/// let mut builder = HttpResponse::Ok();
|
||||||
@ -40,10 +40,10 @@ header! {
|
|||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// # extern crate actix_web;
|
/// # extern crate actix_http;
|
||||||
/// # #[macro_use] extern crate language_tags;
|
/// # #[macro_use] extern crate language_tags;
|
||||||
/// use actix_web::HttpResponse;
|
/// use actix_http::HttpResponse;
|
||||||
/// # use actix_web::http::header::{ContentLanguage, qitem};
|
/// # use actix_http::http::header::{ContentLanguage, qitem};
|
||||||
/// #
|
/// #
|
||||||
/// # fn main() {
|
/// # fn main() {
|
||||||
///
|
///
|
||||||
|
@ -31,8 +31,8 @@ header! {
|
|||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// use actix_web::HttpResponse;
|
/// use actix_http::HttpResponse;
|
||||||
/// use actix_web::http::header::ContentType;
|
/// use actix_http::http::header::ContentType;
|
||||||
///
|
///
|
||||||
/// # fn main() {
|
/// # fn main() {
|
||||||
/// let mut builder = HttpResponse::Ok();
|
/// let mut builder = HttpResponse::Ok();
|
||||||
@ -44,10 +44,10 @@ header! {
|
|||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// # extern crate mime;
|
/// # extern crate mime;
|
||||||
/// # extern crate actix_web;
|
/// # extern crate actix_http;
|
||||||
/// use mime::TEXT_HTML;
|
/// use mime::TEXT_HTML;
|
||||||
/// use actix_web::HttpResponse;
|
/// use actix_http::HttpResponse;
|
||||||
/// use actix_web::http::header::ContentType;
|
/// use actix_http::http::header::ContentType;
|
||||||
///
|
///
|
||||||
/// # fn main() {
|
/// # fn main() {
|
||||||
/// let mut builder = HttpResponse::Ok();
|
/// let mut builder = HttpResponse::Ok();
|
||||||
|
@ -20,8 +20,8 @@ header! {
|
|||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// use actix_web::HttpResponse;
|
/// use actix_http::HttpResponse;
|
||||||
/// use actix_web::http::header::Date;
|
/// use actix_http::http::header::Date;
|
||||||
/// use std::time::SystemTime;
|
/// use std::time::SystemTime;
|
||||||
///
|
///
|
||||||
/// let mut builder = HttpResponse::Ok();
|
/// let mut builder = HttpResponse::Ok();
|
||||||
|
@ -28,16 +28,16 @@ header! {
|
|||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// use actix_web::HttpResponse;
|
/// use actix_http::HttpResponse;
|
||||||
/// use actix_web::http::header::{ETag, EntityTag};
|
/// use actix_http::http::header::{ETag, EntityTag};
|
||||||
///
|
///
|
||||||
/// let mut builder = HttpResponse::Ok();
|
/// let mut builder = HttpResponse::Ok();
|
||||||
/// builder.set(ETag(EntityTag::new(false, "xyzzy".to_owned())));
|
/// builder.set(ETag(EntityTag::new(false, "xyzzy".to_owned())));
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// use actix_web::HttpResponse;
|
/// use actix_http::HttpResponse;
|
||||||
/// use actix_web::http::header::{ETag, EntityTag};
|
/// use actix_http::http::header::{ETag, EntityTag};
|
||||||
///
|
///
|
||||||
/// let mut builder = HttpResponse::Ok();
|
/// let mut builder = HttpResponse::Ok();
|
||||||
/// builder.set(ETag(EntityTag::new(true, "xyzzy".to_owned())));
|
/// builder.set(ETag(EntityTag::new(true, "xyzzy".to_owned())));
|
||||||
|
@ -22,8 +22,8 @@ header! {
|
|||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// use actix_web::HttpResponse;
|
/// use actix_http::HttpResponse;
|
||||||
/// use actix_web::http::header::Expires;
|
/// use actix_http::http::header::Expires;
|
||||||
/// use std::time::{SystemTime, Duration};
|
/// use std::time::{SystemTime, Duration};
|
||||||
///
|
///
|
||||||
/// let mut builder = HttpResponse::Ok();
|
/// let mut builder = HttpResponse::Ok();
|
||||||
|
@ -30,16 +30,16 @@ header! {
|
|||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// use actix_web::HttpResponse;
|
/// use actix_http::HttpResponse;
|
||||||
/// use actix_web::http::header::IfMatch;
|
/// use actix_http::http::header::IfMatch;
|
||||||
///
|
///
|
||||||
/// let mut builder = HttpResponse::Ok();
|
/// let mut builder = HttpResponse::Ok();
|
||||||
/// builder.set(IfMatch::Any);
|
/// builder.set(IfMatch::Any);
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// use actix_web::HttpResponse;
|
/// use actix_http::HttpResponse;
|
||||||
/// use actix_web::http::header::{IfMatch, EntityTag};
|
/// use actix_http::http::header::{IfMatch, EntityTag};
|
||||||
///
|
///
|
||||||
/// let mut builder = HttpResponse::Ok();
|
/// let mut builder = HttpResponse::Ok();
|
||||||
/// builder.set(
|
/// builder.set(
|
||||||
|
@ -22,8 +22,8 @@ header! {
|
|||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// use actix_web::HttpResponse;
|
/// use actix_http::HttpResponse;
|
||||||
/// use actix_web::http::header::IfModifiedSince;
|
/// use actix_http::http::header::IfModifiedSince;
|
||||||
/// use std::time::{SystemTime, Duration};
|
/// use std::time::{SystemTime, Duration};
|
||||||
///
|
///
|
||||||
/// let mut builder = HttpResponse::Ok();
|
/// let mut builder = HttpResponse::Ok();
|
||||||
|
@ -32,16 +32,16 @@ header! {
|
|||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// use actix_web::HttpResponse;
|
/// use actix_http::HttpResponse;
|
||||||
/// use actix_web::http::header::IfNoneMatch;
|
/// use actix_http::http::header::IfNoneMatch;
|
||||||
///
|
///
|
||||||
/// let mut builder = HttpResponse::Ok();
|
/// let mut builder = HttpResponse::Ok();
|
||||||
/// builder.set(IfNoneMatch::Any);
|
/// builder.set(IfNoneMatch::Any);
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// use actix_web::HttpResponse;
|
/// use actix_http::HttpResponse;
|
||||||
/// use actix_web::http::header::{IfNoneMatch, EntityTag};
|
/// use actix_http::http::header::{IfNoneMatch, EntityTag};
|
||||||
///
|
///
|
||||||
/// let mut builder = HttpResponse::Ok();
|
/// let mut builder = HttpResponse::Ok();
|
||||||
/// builder.set(
|
/// builder.set(
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
use error::ParseError;
|
use error::ParseError;
|
||||||
use header::from_one_raw_str;
|
use header::from_one_raw_str;
|
||||||
use header::{EntityTag, Header, HeaderName, HeaderValue, HttpDate, IntoHeaderValue,
|
use header::{
|
||||||
InvalidHeaderValueBytes, Writer};
|
EntityTag, Header, HeaderName, HeaderValue, HttpDate, IntoHeaderValue,
|
||||||
|
InvalidHeaderValueBytes, Writer,
|
||||||
|
};
|
||||||
use http::header;
|
use http::header;
|
||||||
use httpmessage::HttpMessage;
|
use httpmessage::HttpMessage;
|
||||||
use std::fmt::{self, Display, Write};
|
use std::fmt::{self, Display, Write};
|
||||||
@ -35,8 +37,8 @@ use std::fmt::{self, Display, Write};
|
|||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// use actix_web::HttpResponse;
|
/// use actix_http::HttpResponse;
|
||||||
/// use actix_web::http::header::{EntityTag, IfRange};
|
/// use actix_http::http::header::{EntityTag, IfRange};
|
||||||
///
|
///
|
||||||
/// let mut builder = HttpResponse::Ok();
|
/// let mut builder = HttpResponse::Ok();
|
||||||
/// builder.set(IfRange::EntityTag(EntityTag::new(
|
/// builder.set(IfRange::EntityTag(EntityTag::new(
|
||||||
@ -46,8 +48,8 @@ use std::fmt::{self, Display, Write};
|
|||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// use actix_web::HttpResponse;
|
/// use actix_http::HttpResponse;
|
||||||
/// use actix_web::http::header::IfRange;
|
/// use actix_http::http::header::IfRange;
|
||||||
/// use std::time::{Duration, SystemTime};
|
/// use std::time::{Duration, SystemTime};
|
||||||
///
|
///
|
||||||
/// let mut builder = HttpResponse::Ok();
|
/// let mut builder = HttpResponse::Ok();
|
||||||
|
@ -23,8 +23,8 @@ header! {
|
|||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// use actix_web::HttpResponse;
|
/// use actix_http::HttpResponse;
|
||||||
/// use actix_web::http::header::IfUnmodifiedSince;
|
/// use actix_http::http::header::IfUnmodifiedSince;
|
||||||
/// use std::time::{SystemTime, Duration};
|
/// use std::time::{SystemTime, Duration};
|
||||||
///
|
///
|
||||||
/// let mut builder = HttpResponse::Ok();
|
/// let mut builder = HttpResponse::Ok();
|
||||||
|
@ -22,8 +22,8 @@ header! {
|
|||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// use actix_web::HttpResponse;
|
/// use actix_http::HttpResponse;
|
||||||
/// use actix_web::http::header::LastModified;
|
/// use actix_http::http::header::LastModified;
|
||||||
/// use std::time::{SystemTime, Duration};
|
/// use std::time::{SystemTime, Duration};
|
||||||
///
|
///
|
||||||
/// let mut builder = HttpResponse::Ok();
|
/// let mut builder = HttpResponse::Ok();
|
||||||
|
@ -106,7 +106,7 @@ pub trait HttpMessage: Sized {
|
|||||||
///
|
///
|
||||||
/// ## Server example
|
/// ## Server example
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust,ignore
|
||||||
/// # extern crate bytes;
|
/// # extern crate bytes;
|
||||||
/// # extern crate actix_web;
|
/// # extern crate actix_web;
|
||||||
/// # extern crate futures;
|
/// # extern crate futures;
|
||||||
@ -143,7 +143,7 @@ pub trait HttpMessage: Sized {
|
|||||||
///
|
///
|
||||||
/// ## Server example
|
/// ## Server example
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust,ignore
|
||||||
/// # extern crate actix_web;
|
/// # extern crate actix_web;
|
||||||
/// # extern crate futures;
|
/// # extern crate futures;
|
||||||
/// # use futures::Future;
|
/// # use futures::Future;
|
||||||
@ -176,7 +176,7 @@ pub trait HttpMessage: Sized {
|
|||||||
///
|
///
|
||||||
/// ## Server example
|
/// ## Server example
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust,ignore
|
||||||
/// # extern crate actix_web;
|
/// # extern crate actix_web;
|
||||||
/// # extern crate futures;
|
/// # extern crate futures;
|
||||||
/// # #[macro_use] extern crate serde_derive;
|
/// # #[macro_use] extern crate serde_derive;
|
||||||
|
@ -15,7 +15,7 @@ use serde_json;
|
|||||||
use body::Body;
|
use body::Body;
|
||||||
use error::Error;
|
use error::Error;
|
||||||
use header::{ContentEncoding, Header, IntoHeaderValue};
|
use header::{ContentEncoding, Header, IntoHeaderValue};
|
||||||
use httpmessage::HttpMessage;
|
// use httpmessage::HttpMessage;
|
||||||
// use httprequest::HttpRequest;
|
// use httprequest::HttpRequest;
|
||||||
|
|
||||||
/// max write buffer size 64k
|
/// max write buffer size 64k
|
||||||
@ -366,7 +366,7 @@ impl HttpResponseBuilder {
|
|||||||
|
|
||||||
/// Set a header.
|
/// Set a header.
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust,ignore
|
||||||
/// # extern crate actix_web;
|
/// # extern crate actix_web;
|
||||||
/// use actix_web::{http, HttpRequest, HttpResponse, Result};
|
/// use actix_web::{http, HttpRequest, HttpResponse, Result};
|
||||||
///
|
///
|
||||||
@ -394,7 +394,7 @@ impl HttpResponseBuilder {
|
|||||||
|
|
||||||
/// Set a header.
|
/// Set a header.
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust,ignore
|
||||||
/// # extern crate actix_web;
|
/// # extern crate actix_web;
|
||||||
/// use actix_web::{http, HttpRequest, HttpResponse};
|
/// use actix_web::{http, HttpRequest, HttpResponse};
|
||||||
///
|
///
|
||||||
@ -516,7 +516,7 @@ impl HttpResponseBuilder {
|
|||||||
|
|
||||||
/// Set a cookie
|
/// Set a cookie
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust,ignore
|
||||||
/// # extern crate actix_web;
|
/// # extern crate actix_web;
|
||||||
/// use actix_web::{http, HttpRequest, HttpResponse, Result};
|
/// use actix_web::{http, HttpRequest, HttpResponse, Result};
|
||||||
///
|
///
|
||||||
@ -546,7 +546,7 @@ impl HttpResponseBuilder {
|
|||||||
|
|
||||||
/// Remove cookie
|
/// Remove cookie
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust,ignore
|
||||||
/// # extern crate actix_web;
|
/// # extern crate actix_web;
|
||||||
/// use actix_web::{http, HttpRequest, HttpResponse, Result};
|
/// use actix_web::{http, HttpRequest, HttpResponse, Result};
|
||||||
///
|
///
|
||||||
@ -956,38 +956,38 @@ mod tests {
|
|||||||
assert!(dbg.contains("HttpResponse"));
|
assert!(dbg.contains("HttpResponse"));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
// #[test]
|
||||||
fn test_response_cookies() {
|
// fn test_response_cookies() {
|
||||||
let req = TestRequest::default()
|
// let req = TestRequest::default()
|
||||||
.header(COOKIE, "cookie1=value1")
|
// .header(COOKIE, "cookie1=value1")
|
||||||
.header(COOKIE, "cookie2=value2")
|
// .header(COOKIE, "cookie2=value2")
|
||||||
.finish();
|
// .finish();
|
||||||
let cookies = req.cookies().unwrap();
|
// let cookies = req.cookies().unwrap();
|
||||||
|
|
||||||
let resp = HttpResponse::Ok()
|
// let resp = HttpResponse::Ok()
|
||||||
.cookie(
|
// .cookie(
|
||||||
http::Cookie::build("name", "value")
|
// http::Cookie::build("name", "value")
|
||||||
.domain("www.rust-lang.org")
|
// .domain("www.rust-lang.org")
|
||||||
.path("/test")
|
// .path("/test")
|
||||||
.http_only(true)
|
// .http_only(true)
|
||||||
.max_age(Duration::days(1))
|
// .max_age(Duration::days(1))
|
||||||
.finish(),
|
// .finish(),
|
||||||
).del_cookie(&cookies[0])
|
// ).del_cookie(&cookies[0])
|
||||||
.finish();
|
// .finish();
|
||||||
|
|
||||||
let mut val: Vec<_> = resp
|
// let mut val: Vec<_> = resp
|
||||||
.headers()
|
// .headers()
|
||||||
.get_all("Set-Cookie")
|
// .get_all("Set-Cookie")
|
||||||
.iter()
|
// .iter()
|
||||||
.map(|v| v.to_str().unwrap().to_owned())
|
// .map(|v| v.to_str().unwrap().to_owned())
|
||||||
.collect();
|
// .collect();
|
||||||
val.sort();
|
// val.sort();
|
||||||
assert!(val[0].starts_with("cookie1=; Max-Age=0;"));
|
// assert!(val[0].starts_with("cookie1=; Max-Age=0;"));
|
||||||
assert_eq!(
|
// assert_eq!(
|
||||||
val[1],
|
// val[1],
|
||||||
"name=value; HttpOnly; Path=/test; Domain=www.rust-lang.org; Max-Age=86400"
|
// "name=value; HttpOnly; Path=/test; Domain=www.rust-lang.org; Max-Age=86400"
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_update_response_cookies() {
|
fn test_update_response_cookies() {
|
||||||
@ -1131,15 +1131,6 @@ mod tests {
|
|||||||
assert_eq!(resp.status(), StatusCode::OK);
|
assert_eq!(resp.status(), StatusCode::OK);
|
||||||
assert_eq!(resp.body().bin_ref(), &Binary::from("test"));
|
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();
|
let resp: HttpResponse = b"test".as_ref().into();
|
||||||
assert_eq!(resp.status(), StatusCode::OK);
|
assert_eq!(resp.status(), StatusCode::OK);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -1149,15 +1140,6 @@ mod tests {
|
|||||||
assert_eq!(resp.status(), StatusCode::OK);
|
assert_eq!(resp.status(), StatusCode::OK);
|
||||||
assert_eq!(resp.body().bin_ref(), &Binary::from(b"test".as_ref()));
|
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();
|
let resp: HttpResponse = "test".to_owned().into();
|
||||||
assert_eq!(resp.status(), StatusCode::OK);
|
assert_eq!(resp.status(), StatusCode::OK);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -1167,15 +1149,6 @@ mod tests {
|
|||||||
assert_eq!(resp.status(), StatusCode::OK);
|
assert_eq!(resp.status(), StatusCode::OK);
|
||||||
assert_eq!(resp.body().bin_ref(), &Binary::from("test".to_owned()));
|
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();
|
let resp: HttpResponse = (&"test".to_owned()).into();
|
||||||
assert_eq!(resp.status(), StatusCode::OK);
|
assert_eq!(resp.status(), StatusCode::OK);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -1185,15 +1158,6 @@ mod tests {
|
|||||||
assert_eq!(resp.status(), StatusCode::OK);
|
assert_eq!(resp.status(), StatusCode::OK);
|
||||||
assert_eq!(resp.body().bin_ref(), &Binary::from(&"test".to_owned()));
|
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 b = Bytes::from_static(b"test");
|
||||||
let resp: HttpResponse = b.into();
|
let resp: HttpResponse = b.into();
|
||||||
assert_eq!(resp.status(), StatusCode::OK);
|
assert_eq!(resp.status(), StatusCode::OK);
|
||||||
@ -1208,19 +1172,6 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let b = Bytes::from_static(b"test");
|
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();
|
let resp: HttpResponse = b.into();
|
||||||
assert_eq!(resp.status(), StatusCode::OK);
|
assert_eq!(resp.status(), StatusCode::OK);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -1231,7 +1182,7 @@ mod tests {
|
|||||||
assert_eq!(resp.body().bin_ref(), &Binary::from(BytesMut::from("test")));
|
assert_eq!(resp.body().bin_ref(), &Binary::from(BytesMut::from("test")));
|
||||||
|
|
||||||
let b = 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.status(), StatusCode::OK);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
resp.headers().get(CONTENT_TYPE).unwrap(),
|
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 http::header::CONTENT_LENGTH;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
use mime;
|
use mime;
|
||||||
use serde::de::DeserializeOwned;
|
use serde::de::DeserializeOwned;
|
||||||
use serde::Serialize;
|
|
||||||
use serde_json;
|
use serde_json;
|
||||||
|
|
||||||
use error::{Error, JsonPayloadError};
|
use error::JsonPayloadError;
|
||||||
use http::StatusCode;
|
|
||||||
use httpmessage::HttpMessage;
|
use httpmessage::HttpMessage;
|
||||||
// use httprequest::HttpRequest;
|
|
||||||
use httpresponse::HttpResponse;
|
|
||||||
|
|
||||||
/// Json helper
|
/// Json helper
|
||||||
///
|
///
|
||||||
@ -30,7 +25,7 @@ use httpresponse::HttpResponse;
|
|||||||
///
|
///
|
||||||
/// ## Example
|
/// ## Example
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust,ignore
|
||||||
/// # extern crate actix_web;
|
/// # extern crate actix_web;
|
||||||
/// #[macro_use] extern crate serde_derive;
|
/// #[macro_use] extern crate serde_derive;
|
||||||
/// use actix_web::{App, Json, Result, http};
|
/// 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`
|
/// to serialize into *JSON*. The type `T` must implement the `Serialize`
|
||||||
/// trait from *serde*.
|
/// trait from *serde*.
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust,ignore
|
||||||
/// # extern crate actix_web;
|
/// # extern crate actix_web;
|
||||||
/// # #[macro_use] extern crate serde_derive;
|
/// # #[macro_use] extern crate serde_derive;
|
||||||
/// # use actix_web::*;
|
/// # use actix_web::*;
|
||||||
@ -124,7 +119,7 @@ where
|
|||||||
///
|
///
|
||||||
/// # Server example
|
/// # Server example
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust,ignore
|
||||||
/// # extern crate actix_web;
|
/// # extern crate actix_web;
|
||||||
/// # extern crate futures;
|
/// # extern crate futures;
|
||||||
/// # #[macro_use] extern crate serde_derive;
|
/// # #[macro_use] extern crate serde_derive;
|
||||||
@ -243,9 +238,7 @@ mod tests {
|
|||||||
use futures::Async;
|
use futures::Async;
|
||||||
use http::header;
|
use http::header;
|
||||||
|
|
||||||
use handler::Handler;
|
|
||||||
use test::TestRequest;
|
use test::TestRequest;
|
||||||
use with::With;
|
|
||||||
|
|
||||||
impl PartialEq for JsonPayloadError {
|
impl PartialEq for JsonPayloadError {
|
||||||
fn eq(&self, other: &JsonPayloadError) -> bool {
|
fn eq(&self, other: &JsonPayloadError) -> bool {
|
||||||
@ -268,18 +261,6 @@ mod tests {
|
|||||||
name: String,
|
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]
|
#[test]
|
||||||
fn test_json_body() {
|
fn test_json_body() {
|
||||||
let req = TestRequest::default().finish();
|
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
|
//! Actix web is a small, pragmatic, and extremely fast web framework
|
||||||
//! for Rust.
|
//! for Rust.
|
||||||
//!
|
//!
|
||||||
//! ```rust
|
//! ```rust,ignore
|
||||||
//! use actix_web::{server, App, Path, Responder};
|
//! use actix_web::{server, App, Path, Responder};
|
||||||
//! # use std::thread;
|
//! # use std::thread;
|
||||||
//!
|
//!
|
||||||
@ -78,10 +78,11 @@
|
|||||||
//! `gzip`, `deflate` compression.
|
//! `gzip`, `deflate` compression.
|
||||||
//!
|
//!
|
||||||
#![cfg_attr(actix_nightly, feature(tool_lints))]
|
#![cfg_attr(actix_nightly, feature(tool_lints))]
|
||||||
#![warn(missing_docs)]
|
// #![warn(missing_docs)]
|
||||||
#![allow(unused_imports, unused_variables, dead_code)]
|
// #![allow(unused_imports, unused_variables, dead_code)]
|
||||||
|
|
||||||
extern crate actix;
|
extern crate actix;
|
||||||
|
extern crate actix_net;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
extern crate base64;
|
extern crate base64;
|
||||||
@ -98,7 +99,12 @@ extern crate failure;
|
|||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate futures;
|
extern crate futures;
|
||||||
|
#[cfg(feature = "brotli")]
|
||||||
|
extern crate brotli2;
|
||||||
extern crate cookie;
|
extern crate cookie;
|
||||||
|
extern crate encoding;
|
||||||
|
#[cfg(feature = "flate2")]
|
||||||
|
extern crate flate2;
|
||||||
extern crate http as modhttp;
|
extern crate http as modhttp;
|
||||||
extern crate httparse;
|
extern crate httparse;
|
||||||
extern crate language_tags;
|
extern crate language_tags;
|
||||||
@ -106,6 +112,8 @@ extern crate mime;
|
|||||||
extern crate mime_guess;
|
extern crate mime_guess;
|
||||||
extern crate net2;
|
extern crate net2;
|
||||||
extern crate rand;
|
extern crate rand;
|
||||||
|
extern crate serde;
|
||||||
|
extern crate serde_urlencoded;
|
||||||
extern crate tokio_codec;
|
extern crate tokio_codec;
|
||||||
extern crate tokio_current_thread;
|
extern crate tokio_current_thread;
|
||||||
extern crate tokio_io;
|
extern crate tokio_io;
|
||||||
@ -116,19 +124,10 @@ extern crate tokio_timer;
|
|||||||
extern crate tokio_uds;
|
extern crate tokio_uds;
|
||||||
extern crate url;
|
extern crate url;
|
||||||
#[macro_use]
|
#[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 percent_encoding;
|
||||||
extern crate serde_json;
|
extern crate serde_json;
|
||||||
extern crate smallvec;
|
extern crate smallvec;
|
||||||
|
extern crate tokio;
|
||||||
extern crate actix_net;
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
@ -150,7 +149,7 @@ pub mod error;
|
|||||||
pub mod h1;
|
pub mod h1;
|
||||||
pub(crate) mod helpers;
|
pub(crate) mod helpers;
|
||||||
pub mod server;
|
pub mod server;
|
||||||
//pub mod test;
|
pub mod test;
|
||||||
//pub mod ws;
|
//pub mod ws;
|
||||||
pub use body::{Binary, Body};
|
pub use body::{Binary, Body};
|
||||||
pub use error::{Error, ResponseError, Result};
|
pub use error::{Error, ResponseError, Result};
|
||||||
@ -170,7 +169,7 @@ pub mod dev {
|
|||||||
//!
|
//!
|
||||||
//! ```
|
//! ```
|
||||||
//! # #![allow(unused_imports)]
|
//! # #![allow(unused_imports)]
|
||||||
//! use actix_web::dev::*;
|
//! use actix_http::dev::*;
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
pub use body::BodyStream;
|
pub use body::BodyStream;
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
use std::cell::{Cell, Ref, RefCell, RefMut};
|
use std::cell::{Cell, Ref, RefCell, RefMut};
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::net::SocketAddr;
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use http::{header, HeaderMap, Method, Uri, Version};
|
use http::{header, HeaderMap, Method, Uri, Version};
|
||||||
@ -31,7 +30,6 @@ pub(crate) struct InnerRequest {
|
|||||||
pub(crate) headers: HeaderMap,
|
pub(crate) headers: HeaderMap,
|
||||||
pub(crate) extensions: RefCell<Extensions>,
|
pub(crate) extensions: RefCell<Extensions>,
|
||||||
pub(crate) payload: RefCell<Option<Payload>>,
|
pub(crate) payload: RefCell<Option<Payload>>,
|
||||||
pub(crate) stream_extensions: Option<Rc<Extensions>>,
|
|
||||||
pool: &'static RequestPool,
|
pool: &'static RequestPool,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,7 +79,6 @@ impl Request {
|
|||||||
flags: Cell::new(MessageFlags::empty()),
|
flags: Cell::new(MessageFlags::empty()),
|
||||||
payload: RefCell::new(None),
|
payload: RefCell::new(None),
|
||||||
extensions: RefCell::new(Extensions::new()),
|
extensions: RefCell::new(Extensions::new()),
|
||||||
stream_extensions: None,
|
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -170,15 +167,13 @@ impl Request {
|
|||||||
inner: self.inner.clone(),
|
inner: self.inner.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn release(self) {
|
impl Drop for Request {
|
||||||
let mut inner = self.inner;
|
fn drop(&mut self) {
|
||||||
if let Some(r) = Rc::get_mut(&mut inner) {
|
if Rc::strong_count(&self.inner) == 1 {
|
||||||
r.reset();
|
self.inner.pool.release(self.inner.clone());
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
inner.pool.release(inner);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -221,11 +216,13 @@ impl RequestPool {
|
|||||||
/// Get Request object
|
/// Get Request object
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get(pool: &'static RequestPool) -> Request {
|
pub fn get(pool: &'static RequestPool) -> Request {
|
||||||
if let Some(msg) = pool.0.borrow_mut().pop_front() {
|
if let Some(mut msg) = pool.0.borrow_mut().pop_front() {
|
||||||
Request { inner: msg }
|
if let Some(r) = Rc::get_mut(&mut msg) {
|
||||||
} else {
|
r.reset();
|
||||||
Request::with_pool(pool)
|
}
|
||||||
|
return Request { inner: msg };
|
||||||
}
|
}
|
||||||
|
Request::with_pool(pool)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -106,12 +106,9 @@
|
|||||||
//! let _ = sys.run();
|
//! let _ = sys.run();
|
||||||
//!}
|
//!}
|
||||||
//! ```
|
//! ```
|
||||||
use std::net::{Shutdown, SocketAddr};
|
use std::net::SocketAddr;
|
||||||
use std::rc::Rc;
|
|
||||||
use std::{io, time};
|
use std::{io, time};
|
||||||
|
|
||||||
use bytes::{BufMut, BytesMut};
|
|
||||||
use futures::{Async, Poll};
|
|
||||||
use tokio_io::{AsyncRead, AsyncWrite};
|
use tokio_io::{AsyncRead, AsyncWrite};
|
||||||
use tokio_tcp::TcpStream;
|
use tokio_tcp::TcpStream;
|
||||||
|
|
||||||
@ -123,16 +120,8 @@ pub(crate) mod output;
|
|||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub use super::helpers::write_content_length;
|
pub use super::helpers::write_content_length;
|
||||||
|
|
||||||
use body::Binary;
|
// /// max buffer size 64k
|
||||||
use extensions::Extensions;
|
// pub(crate) const MAX_WRITE_BUFFER_SIZE: usize = 65_536;
|
||||||
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;
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone, Copy)]
|
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||||
/// Server keep-alive setting
|
/// Server keep-alive setting
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
#![allow(unused_imports, unused_variables, dead_code)]
|
||||||
use std::fmt::Write as FmtWrite;
|
use std::fmt::Write as FmtWrite;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::str::FromStr;
|
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.
|
//! Various helpers for Actix applications to use during testing.
|
||||||
use std::rc::Rc;
|
use std::net;
|
||||||
use std::str::FromStr;
|
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 cookie::Cookie;
|
||||||
use futures::Future;
|
use futures::Future;
|
||||||
@ -13,28 +11,12 @@ use http::{HeaderMap, HttpTryFrom, Method, Uri, Version};
|
|||||||
use net2::TcpBuilder;
|
use net2::TcpBuilder;
|
||||||
use tokio::runtime::current_thread::Runtime;
|
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 body::Binary;
|
||||||
use client::{ClientConnector, ClientRequest, ClientRequestBuilder};
|
|
||||||
use error::Error;
|
|
||||||
use handler::{AsyncResult, AsyncResultItem, Handler, Responder};
|
|
||||||
use header::{Header, IntoHeaderValue};
|
use header::{Header, IntoHeaderValue};
|
||||||
use httprequest::HttpRequest;
|
|
||||||
use httpresponse::HttpResponse;
|
|
||||||
use middleware::Middleware;
|
|
||||||
use param::Params;
|
|
||||||
use payload::Payload;
|
use payload::Payload;
|
||||||
use resource::Resource;
|
use request::Request;
|
||||||
use router::Router;
|
|
||||||
use server::message::{Request, RequestPool};
|
|
||||||
use server::{HttpServer, IntoHttpHandler, ServerSettings};
|
|
||||||
use uri::Url as InnerUrl;
|
use uri::Url as InnerUrl;
|
||||||
use ws;
|
// use ws;
|
||||||
|
|
||||||
/// The `TestServer` type.
|
/// The `TestServer` type.
|
||||||
///
|
///
|
||||||
@ -63,9 +45,8 @@ use ws;
|
|||||||
/// ```
|
/// ```
|
||||||
pub struct TestServer {
|
pub struct TestServer {
|
||||||
addr: net::SocketAddr,
|
addr: net::SocketAddr,
|
||||||
ssl: bool,
|
|
||||||
conn: Addr<ClientConnector>,
|
|
||||||
rt: Runtime,
|
rt: Runtime,
|
||||||
|
ssl: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TestServer {
|
impl TestServer {
|
||||||
@ -73,92 +54,11 @@ impl TestServer {
|
|||||||
///
|
///
|
||||||
/// This method accepts configuration method. You can add
|
/// This method accepts configuration method. You can add
|
||||||
/// middlewares or set handlers for test application.
|
/// middlewares or set handlers for test application.
|
||||||
pub fn new<F>(config: F) -> Self
|
pub fn new<F>(_config: F) -> Self
|
||||||
where
|
where
|
||||||
F: Clone + Send + 'static + Fn(&mut TestApp<()>),
|
F: Fn() + Clone + Send + 'static,
|
||||||
{
|
{
|
||||||
TestServerBuilder::new(|| ()).start(config)
|
unimplemented!()
|
||||||
}
|
|
||||||
|
|
||||||
/// 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()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get firat available unused address
|
/// Get firat available unused address
|
||||||
@ -208,45 +108,45 @@ impl TestServer {
|
|||||||
self.rt.block_on(fut)
|
self.rt.block_on(fut)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Connect to websocket server at a given path
|
// /// Connect to websocket server at a given path
|
||||||
pub fn ws_at(
|
// pub fn ws_at(
|
||||||
&mut self, path: &str,
|
// &mut self, path: &str,
|
||||||
) -> Result<(ws::ClientReader, ws::ClientWriter), ws::ClientError> {
|
// ) -> Result<(ws::ClientReader, ws::ClientWriter), ws::ClientError> {
|
||||||
let url = self.url(path);
|
// let url = self.url(path);
|
||||||
self.rt
|
// self.rt
|
||||||
.block_on(ws::Client::with_connector(url, self.conn.clone()).connect())
|
// .block_on(ws::Client::with_connector(url, self.conn.clone()).connect())
|
||||||
}
|
// }
|
||||||
|
|
||||||
/// Connect to a websocket server
|
// /// Connect to a websocket server
|
||||||
pub fn ws(
|
// pub fn ws(
|
||||||
&mut self,
|
// &mut self,
|
||||||
) -> Result<(ws::ClientReader, ws::ClientWriter), ws::ClientError> {
|
// ) -> Result<(ws::ClientReader, ws::ClientWriter), ws::ClientError> {
|
||||||
self.ws_at("/")
|
// self.ws_at("/")
|
||||||
}
|
// }
|
||||||
|
|
||||||
/// Create `GET` request
|
// /// Create `GET` request
|
||||||
pub fn get(&self) -> ClientRequestBuilder {
|
// pub fn get(&self) -> ClientRequestBuilder {
|
||||||
ClientRequest::get(self.url("/").as_str())
|
// ClientRequest::get(self.url("/").as_str())
|
||||||
}
|
// }
|
||||||
|
|
||||||
/// Create `POST` request
|
// /// Create `POST` request
|
||||||
pub fn post(&self) -> ClientRequestBuilder {
|
// pub fn post(&self) -> ClientRequestBuilder {
|
||||||
ClientRequest::post(self.url("/").as_str())
|
// ClientRequest::post(self.url("/").as_str())
|
||||||
}
|
// }
|
||||||
|
|
||||||
/// Create `HEAD` request
|
// /// Create `HEAD` request
|
||||||
pub fn head(&self) -> ClientRequestBuilder {
|
// pub fn head(&self) -> ClientRequestBuilder {
|
||||||
ClientRequest::head(self.url("/").as_str())
|
// ClientRequest::head(self.url("/").as_str())
|
||||||
}
|
// }
|
||||||
|
|
||||||
/// Connect to test http server
|
// /// Connect to test http server
|
||||||
pub fn client(&self, meth: Method, path: &str) -> ClientRequestBuilder {
|
// pub fn client(&self, meth: Method, path: &str) -> ClientRequestBuilder {
|
||||||
ClientRequest::build()
|
// ClientRequest::build()
|
||||||
.method(meth)
|
// .method(meth)
|
||||||
.uri(self.url(path).as_str())
|
// .uri(self.url(path).as_str())
|
||||||
.with_connector(self.conn.clone())
|
// .with_connector(self.conn.clone())
|
||||||
.take()
|
// .take()
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for TestServer {
|
impl Drop for TestServer {
|
||||||
@ -255,183 +155,98 @@ impl Drop for TestServer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An `TestServer` builder
|
// /// An `TestServer` builder
|
||||||
///
|
// ///
|
||||||
/// This type can be used to construct an instance of `TestServer` through a
|
// /// This type can be used to construct an instance of `TestServer` through a
|
||||||
/// builder-like pattern.
|
// /// builder-like pattern.
|
||||||
pub struct TestServerBuilder<S, F>
|
// pub struct TestServerBuilder<S, F>
|
||||||
where
|
// where
|
||||||
F: Fn() -> S + Send + Clone + 'static,
|
// F: Fn() -> S + Send + Clone + 'static,
|
||||||
{
|
// {
|
||||||
state: F,
|
// state: F,
|
||||||
#[cfg(any(feature = "alpn", feature = "ssl"))]
|
// }
|
||||||
ssl: Option<SslAcceptorBuilder>,
|
|
||||||
#[cfg(feature = "rust-tls")]
|
|
||||||
rust_ssl: Option<ServerConfig>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S: 'static, F> TestServerBuilder<S, F>
|
// impl<S: 'static, F> TestServerBuilder<S, F>
|
||||||
where
|
// where
|
||||||
F: Fn() -> S + Send + Clone + 'static,
|
// F: Fn() -> S + Send + Clone + 'static,
|
||||||
{
|
// {
|
||||||
/// Create a new test server
|
// /// Create a new test server
|
||||||
pub fn new(state: F) -> TestServerBuilder<S, F> {
|
// pub fn new(state: F) -> TestServerBuilder<S, F> {
|
||||||
TestServerBuilder {
|
// TestServerBuilder { state }
|
||||||
state,
|
// }
|
||||||
#[cfg(any(feature = "alpn", feature = "ssl"))]
|
|
||||||
ssl: None,
|
|
||||||
#[cfg(feature = "rust-tls")]
|
|
||||||
rust_ssl: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(any(feature = "alpn", feature = "ssl"))]
|
// #[allow(unused_mut)]
|
||||||
/// Create ssl server
|
// /// Configure test application and run test server
|
||||||
pub fn ssl(mut self, ssl: SslAcceptorBuilder) -> Self {
|
// pub fn start<C>(mut self, config: C) -> TestServer
|
||||||
self.ssl = Some(ssl);
|
// where
|
||||||
self
|
// C: Fn(&mut TestApp<S>) + Clone + Send + 'static,
|
||||||
}
|
// {
|
||||||
|
// let (tx, rx) = mpsc::channel();
|
||||||
|
|
||||||
#[cfg(feature = "rust-tls")]
|
// let mut has_ssl = false;
|
||||||
/// Create rust tls server
|
|
||||||
pub fn rustls(mut self, ssl: ServerConfig) -> Self {
|
|
||||||
self.rust_ssl = Some(ssl);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(unused_mut)]
|
// #[cfg(any(feature = "alpn", feature = "ssl"))]
|
||||||
/// Configure test application and run test server
|
// {
|
||||||
pub fn start<C>(mut self, config: C) -> TestServer
|
// has_ssl = has_ssl || self.ssl.is_some();
|
||||||
where
|
// }
|
||||||
C: Fn(&mut TestApp<S>) + Clone + Send + 'static,
|
|
||||||
{
|
|
||||||
let (tx, rx) = mpsc::channel();
|
|
||||||
|
|
||||||
let mut has_ssl = false;
|
// #[cfg(feature = "rust-tls")]
|
||||||
|
// {
|
||||||
|
// has_ssl = has_ssl || self.rust_ssl.is_some();
|
||||||
|
// }
|
||||||
|
|
||||||
#[cfg(any(feature = "alpn", feature = "ssl"))]
|
// // run server in separate thread
|
||||||
{
|
// thread::spawn(move || {
|
||||||
has_ssl = has_ssl || self.ssl.is_some();
|
// let addr = TestServer::unused_addr();
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "rust-tls")]
|
// let sys = System::new("actix-test-server");
|
||||||
{
|
// let state = self.state;
|
||||||
has_ssl = has_ssl || self.rust_ssl.is_some();
|
// 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
|
// tx.send((System::current(), addr, TestServer::get_conn()))
|
||||||
thread::spawn(move || {
|
// .unwrap();
|
||||||
let addr = TestServer::unused_addr();
|
|
||||||
|
|
||||||
let sys = System::new("actix-test-server");
|
// #[cfg(any(feature = "alpn", feature = "ssl"))]
|
||||||
let state = self.state;
|
// {
|
||||||
let mut srv = HttpServer::new(move || {
|
// let ssl = self.ssl.take();
|
||||||
let mut app = TestApp::new(state());
|
// if let Some(ssl) = ssl {
|
||||||
config(&mut app);
|
// let tcp = net::TcpListener::bind(addr).unwrap();
|
||||||
app
|
// srv = srv.listen_ssl(tcp, ssl).unwrap();
|
||||||
}).workers(1)
|
// }
|
||||||
.keep_alive(5)
|
// }
|
||||||
.disable_signals();
|
// #[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()))
|
// sys.run();
|
||||||
.unwrap();
|
// });
|
||||||
|
|
||||||
#[cfg(any(feature = "alpn", feature = "ssl"))]
|
// let (system, addr, conn) = rx.recv().unwrap();
|
||||||
{
|
// System::set_current(system);
|
||||||
let ssl = self.ssl.take();
|
// TestServer {
|
||||||
if let Some(ssl) = ssl {
|
// addr,
|
||||||
let tcp = net::TcpListener::bind(addr).unwrap();
|
// conn,
|
||||||
srv = srv.listen_ssl(tcp, ssl).unwrap();
|
// ssl: has_ssl,
|
||||||
}
|
// rt: Runtime::new().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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Test `HttpRequest` builder
|
/// Test `HttpRequest` builder
|
||||||
///
|
///
|
||||||
@ -460,70 +275,49 @@ impl<S: 'static> Iterator for TestApp<S> {
|
|||||||
/// assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
|
/// assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub struct TestRequest<S> {
|
pub struct TestRequest {
|
||||||
state: S,
|
|
||||||
version: Version,
|
version: Version,
|
||||||
method: Method,
|
method: Method,
|
||||||
uri: Uri,
|
uri: Uri,
|
||||||
headers: HeaderMap,
|
headers: HeaderMap,
|
||||||
params: Params,
|
_cookies: Option<Vec<Cookie<'static>>>,
|
||||||
cookies: Option<Vec<Cookie<'static>>>,
|
|
||||||
payload: Option<Payload>,
|
payload: Option<Payload>,
|
||||||
prefix: u16,
|
prefix: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for TestRequest<()> {
|
impl Default for TestRequest {
|
||||||
fn default() -> TestRequest<()> {
|
fn default() -> TestRequest {
|
||||||
TestRequest {
|
TestRequest {
|
||||||
state: (),
|
|
||||||
method: Method::GET,
|
method: Method::GET,
|
||||||
uri: Uri::from_str("/").unwrap(),
|
uri: Uri::from_str("/").unwrap(),
|
||||||
version: Version::HTTP_11,
|
version: Version::HTTP_11,
|
||||||
headers: HeaderMap::new(),
|
headers: HeaderMap::new(),
|
||||||
params: Params::new(),
|
_cookies: None,
|
||||||
cookies: None,
|
|
||||||
payload: None,
|
payload: None,
|
||||||
prefix: 0,
|
prefix: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TestRequest<()> {
|
impl TestRequest {
|
||||||
/// Create TestRequest and set request uri
|
/// Create TestRequest and set request uri
|
||||||
pub fn with_uri(path: &str) -> TestRequest<()> {
|
pub fn with_uri(path: &str) -> TestRequest {
|
||||||
TestRequest::default().uri(path)
|
TestRequest::default().uri(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create TestRequest and set header
|
/// 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)
|
TestRequest::default().set(hdr)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create TestRequest and set header
|
/// 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
|
where
|
||||||
HeaderName: HttpTryFrom<K>,
|
HeaderName: HttpTryFrom<K>,
|
||||||
V: IntoHeaderValue,
|
V: IntoHeaderValue,
|
||||||
{
|
{
|
||||||
TestRequest::default().header(key, value)
|
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
|
/// Set HTTP version of this request
|
||||||
pub fn version(mut self, ver: Version) -> Self {
|
pub fn version(mut self, ver: Version) -> Self {
|
||||||
@ -567,12 +361,6 @@ impl<S: 'static> TestRequest<S> {
|
|||||||
panic!("Can not create header");
|
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
|
/// Set request payload
|
||||||
pub fn set_payload<B: Into<Binary>>(mut self, data: B) -> Self {
|
pub fn set_payload<B: Into<Binary>>(mut self, data: B) -> Self {
|
||||||
let mut data = data.into();
|
let mut data = data.into();
|
||||||
@ -588,23 +376,19 @@ impl<S: 'static> TestRequest<S> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Complete request creation and generate `HttpRequest` instance
|
/// Complete request creation and generate `Request` instance
|
||||||
pub fn finish(self) -> HttpRequest<S> {
|
pub fn finish(self) -> Request {
|
||||||
let TestRequest {
|
let TestRequest {
|
||||||
state,
|
|
||||||
method,
|
method,
|
||||||
uri,
|
uri,
|
||||||
version,
|
version,
|
||||||
headers,
|
headers,
|
||||||
mut params,
|
_cookies: _,
|
||||||
cookies,
|
|
||||||
payload,
|
payload,
|
||||||
prefix,
|
prefix: _,
|
||||||
} = self;
|
} = self;
|
||||||
let router = Router::<()>::default();
|
|
||||||
|
|
||||||
let pool = RequestPool::pool(ServerSettings::default());
|
let mut req = Request::new();
|
||||||
let mut req = RequestPool::get(pool);
|
|
||||||
{
|
{
|
||||||
let inner = req.inner_mut();
|
let inner = req.inner_mut();
|
||||||
inner.method = method;
|
inner.method = method;
|
||||||
@ -613,156 +397,94 @@ impl<S: 'static> TestRequest<S> {
|
|||||||
inner.headers = headers;
|
inner.headers = headers;
|
||||||
*inner.payload.borrow_mut() = payload;
|
*inner.payload.borrow_mut() = payload;
|
||||||
}
|
}
|
||||||
params.set_url(req.url().clone());
|
// req.set_cookies(cookies);
|
||||||
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
|
req
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
// /// This method generates `HttpRequest` instance and runs handler
|
||||||
/// Complete request creation and generate `HttpRequest` instance
|
// /// with generated request.
|
||||||
pub(crate) fn finish_with_router(self, router: Router<S>) -> HttpRequest<S> {
|
// pub fn run<H: Handler<S>>(self, h: &H) -> Result<HttpResponse, Error> {
|
||||||
let TestRequest {
|
// let req = self.finish();
|
||||||
state,
|
// let resp = h.handle(&req);
|
||||||
method,
|
|
||||||
uri,
|
|
||||||
version,
|
|
||||||
headers,
|
|
||||||
mut params,
|
|
||||||
cookies,
|
|
||||||
payload,
|
|
||||||
prefix,
|
|
||||||
} = self;
|
|
||||||
|
|
||||||
let pool = RequestPool::pool(ServerSettings::default());
|
// match resp.respond_to(&req) {
|
||||||
let mut req = RequestPool::get(pool);
|
// Ok(resp) => match resp.into().into() {
|
||||||
{
|
// AsyncResultItem::Ok(resp) => Ok(resp),
|
||||||
let inner = req.inner_mut();
|
// AsyncResultItem::Err(err) => Err(err),
|
||||||
inner.method = method;
|
// AsyncResultItem::Future(fut) => {
|
||||||
inner.url = InnerUrl::new(uri);
|
// let mut sys = System::new("test");
|
||||||
inner.version = version;
|
// sys.block_on(fut)
|
||||||
inner.headers = headers;
|
// }
|
||||||
*inner.payload.borrow_mut() = payload;
|
// },
|
||||||
}
|
// Err(err) => Err(err.into()),
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Complete request creation and generate server `Request` instance
|
// /// This method generates `HttpRequest` instance and runs handler
|
||||||
pub fn request(self) -> Request {
|
// /// with generated request.
|
||||||
let TestRequest {
|
// ///
|
||||||
method,
|
// /// This method panics is handler returns actor.
|
||||||
uri,
|
// pub fn run_async<H, R, F, E>(self, h: H) -> Result<HttpResponse, E>
|
||||||
version,
|
// where
|
||||||
headers,
|
// H: Fn(HttpRequest<S>) -> F + 'static,
|
||||||
payload,
|
// F: Future<Item = R, Error = E> + 'static,
|
||||||
..
|
// R: Responder<Error = E> + 'static,
|
||||||
} = self;
|
// E: Into<Error> + 'static,
|
||||||
|
// {
|
||||||
|
// let req = self.finish();
|
||||||
|
// let fut = h(req.clone());
|
||||||
|
|
||||||
let pool = RequestPool::pool(ServerSettings::default());
|
// let mut sys = System::new("test");
|
||||||
let mut req = RequestPool::get(pool);
|
// match sys.block_on(fut) {
|
||||||
{
|
// Ok(r) => match r.respond_to(&req) {
|
||||||
let inner = req.inner_mut();
|
// Ok(reply) => match reply.into().into() {
|
||||||
inner.method = method;
|
// AsyncResultItem::Ok(resp) => Ok(resp),
|
||||||
inner.url = InnerUrl::new(uri);
|
// _ => panic!("Nested async replies are not supported"),
|
||||||
inner.version = version;
|
// },
|
||||||
inner.headers = headers;
|
// Err(e) => Err(e),
|
||||||
*inner.payload.borrow_mut() = payload;
|
// },
|
||||||
}
|
// Err(err) => Err(err),
|
||||||
req
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
/// This method generates `HttpRequest` instance and runs handler
|
// /// This method generates `HttpRequest` instance and executes handler
|
||||||
/// with generated request.
|
// pub fn run_async_result<F, R, I, E>(self, f: F) -> Result<I, E>
|
||||||
pub fn run<H: Handler<S>>(self, h: &H) -> Result<HttpResponse, Error> {
|
// where
|
||||||
let req = self.finish();
|
// F: FnOnce(&HttpRequest<S>) -> R,
|
||||||
let resp = h.handle(&req);
|
// R: Into<AsyncResult<I, E>>,
|
||||||
|
// {
|
||||||
|
// let req = self.finish();
|
||||||
|
// let res = f(&req);
|
||||||
|
|
||||||
match resp.respond_to(&req) {
|
// match res.into().into() {
|
||||||
Ok(resp) => match resp.into().into() {
|
// AsyncResultItem::Ok(resp) => Ok(resp),
|
||||||
AsyncResultItem::Ok(resp) => Ok(resp),
|
// AsyncResultItem::Err(err) => Err(err),
|
||||||
AsyncResultItem::Err(err) => Err(err),
|
// AsyncResultItem::Future(fut) => {
|
||||||
AsyncResultItem::Future(fut) => {
|
// let mut sys = System::new("test");
|
||||||
let mut sys = System::new("test");
|
// sys.block_on(fut)
|
||||||
sys.block_on(fut)
|
// }
|
||||||
}
|
// }
|
||||||
},
|
// }
|
||||||
Err(err) => Err(err.into()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This method generates `HttpRequest` instance and runs handler
|
// /// This method generates `HttpRequest` instance and executes handler
|
||||||
/// with generated request.
|
// pub fn execute<F, R>(self, f: F) -> Result<HttpResponse, Error>
|
||||||
///
|
// where
|
||||||
/// This method panics is handler returns actor.
|
// F: FnOnce(&HttpRequest<S>) -> R,
|
||||||
pub fn run_async<H, R, F, E>(self, h: H) -> Result<HttpResponse, E>
|
// R: Responder + 'static,
|
||||||
where
|
// {
|
||||||
H: Fn(HttpRequest<S>) -> F + 'static,
|
// let req = self.finish();
|
||||||
F: Future<Item = R, Error = E> + 'static,
|
// let resp = f(&req);
|
||||||
R: Responder<Error = E> + 'static,
|
|
||||||
E: Into<Error> + 'static,
|
|
||||||
{
|
|
||||||
let req = self.finish();
|
|
||||||
let fut = h(req.clone());
|
|
||||||
|
|
||||||
let mut sys = System::new("test");
|
// match resp.respond_to(&req) {
|
||||||
match sys.block_on(fut) {
|
// Ok(resp) => match resp.into().into() {
|
||||||
Ok(r) => match r.respond_to(&req) {
|
// AsyncResultItem::Ok(resp) => Ok(resp),
|
||||||
Ok(reply) => match reply.into().into() {
|
// AsyncResultItem::Err(err) => Err(err),
|
||||||
AsyncResultItem::Ok(resp) => Ok(resp),
|
// AsyncResultItem::Future(fut) => {
|
||||||
_ => panic!("Nested async replies are not supported"),
|
// let mut sys = System::new("test");
|
||||||
},
|
// sys.block_on(fut)
|
||||||
Err(e) => Err(e),
|
// }
|
||||||
},
|
// },
|
||||||
Err(err) => Err(err),
|
// Err(err) => Err(err.into()),
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
/// 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()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,6 @@ use std::thread;
|
|||||||
|
|
||||||
use actix::System;
|
use actix::System;
|
||||||
use actix_net::server::Server;
|
use actix_net::server::Server;
|
||||||
use actix_net::service::{IntoNewService, IntoService};
|
|
||||||
use actix_web::{client, test};
|
use actix_web::{client, test};
|
||||||
use futures::future;
|
use futures::future;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user