Merge branch 'master' into master

This commit is contained in:
Darin 2019-04-18 13:58:12 -04:00 committed by GitHub
commit c2598b7f8c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
37 changed files with 477 additions and 195 deletions

View File

@ -1,12 +1,14 @@
# Changes
## [1.0.0-alpha.7] - 2019-04-xx
## [1.0.0-beta.1] - 2019-04-xx
### Added
* Added helper functions for reading test response body,
* Add helper functions for reading test response body,
`test::read_response()` and test::read_response_json()`
* Add `.peer_addr()` #744
### Changed
* Rename `RouterConfig` to `ServiceConfig`

View File

@ -71,17 +71,17 @@ actix-utils = "0.3.4"
actix-router = "0.1.2"
actix-rt = "0.2.2"
actix-web-codegen = "0.1.0-alpha.6"
actix-http = { version = "0.1.0-alpha.5", features=["fail"] }
actix-server = "0.4.2"
actix-server-config = "0.1.0"
actix-http = { version = "0.1.0", features=["fail"] }
actix-server = "0.4.3"
actix-server-config = "0.1.1"
actix-threadpool = "0.1.0"
awc = { version = "0.1.0-alpha.6", optional = true }
awc = { version = "0.1.0", optional = true }
bytes = "0.4"
derive_more = "0.14"
encoding = "0.2"
futures = "0.1"
hashbrown = "0.2.1"
hashbrown = "0.2.2"
log = "0.4"
mime = "0.3"
net2 = "0.2.33"
@ -98,8 +98,8 @@ openssl = { version="0.10", optional = true }
rustls = { version = "^0.15", optional = true }
[dev-dependencies]
actix-http = { version = "0.1.0-alpha.5", features=["ssl", "brotli", "flate2-zlib"] }
actix-http-test = { version = "0.1.0-alpha.3", features=["ssl"] }
actix-http = { version = "0.1.0", features=["ssl", "brotli", "flate2-zlib"] }
actix-http-test = { version = "0.1.0", features=["ssl"] }
actix-files = { version = "0.1.0-alpha.6" }
rand = "0.6"
env_logger = "0.6"
@ -116,7 +116,6 @@ codegen-units = 1
[patch.crates-io]
actix-web = { path = "." }
actix-http = { path = "actix-http" }
actix-http-test = { path = "test-server" }
actix-web-codegen = { path = "actix-web-codegen" }
actix-web-actors = { path = "actix-web-actors" }
actix-session = { path = "actix-session" }

View File

@ -775,7 +775,7 @@ mod tests {
);
let request = TestRequest::get().uri("/").to_request();
let response = test::call_success(&mut srv, request);
let response = test::call_service(&mut srv, request);
assert_eq!(response.status(), StatusCode::OK);
let content_disposition = response
@ -799,7 +799,7 @@ mod tests {
.uri("/t%65st/Cargo.toml")
.header(header::RANGE, "bytes=10-20")
.to_request();
let response = test::call_success(&mut srv, request);
let response = test::call_service(&mut srv, request);
assert_eq!(response.status(), StatusCode::PARTIAL_CONTENT);
// Invalid range header
@ -807,7 +807,7 @@ mod tests {
.uri("/t%65st/Cargo.toml")
.header(header::RANGE, "bytes=1-0")
.to_request();
let response = test::call_success(&mut srv, request);
let response = test::call_service(&mut srv, request);
assert_eq!(response.status(), StatusCode::RANGE_NOT_SATISFIABLE);
}
@ -824,7 +824,7 @@ mod tests {
.header(header::RANGE, "bytes=10-20")
.to_request();
let response = test::call_success(&mut srv, request);
let response = test::call_service(&mut srv, request);
let contentrange = response
.headers()
.get(header::CONTENT_RANGE)
@ -839,7 +839,7 @@ mod tests {
.uri("/t%65st/tests/test.binary")
.header(header::RANGE, "bytes=10-5")
.to_request();
let response = test::call_success(&mut srv, request);
let response = test::call_service(&mut srv, request);
let contentrange = response
.headers()
@ -862,7 +862,7 @@ mod tests {
.uri("/t%65st/tests/test.binary")
.header(header::RANGE, "bytes=10-20")
.to_request();
let response = test::call_success(&mut srv, request);
let response = test::call_service(&mut srv, request);
let contentlength = response
.headers()
@ -878,7 +878,7 @@ mod tests {
.uri("/t%65st/tests/test.binary")
.header(header::RANGE, "bytes=10-8")
.to_request();
let response = test::call_success(&mut srv, request);
let response = test::call_service(&mut srv, request);
assert_eq!(response.status(), StatusCode::RANGE_NOT_SATISFIABLE);
// Without range header
@ -886,7 +886,7 @@ mod tests {
.uri("/t%65st/tests/test.binary")
// .no_default_headers()
.to_request();
let response = test::call_success(&mut srv, request);
let response = test::call_service(&mut srv, request);
let contentlength = response
.headers()
@ -901,7 +901,7 @@ mod tests {
let request = TestRequest::get()
.uri("/t%65st/tests/test.binary")
.to_request();
let mut response = test::call_success(&mut srv, request);
let mut response = test::call_service(&mut srv, request);
// with enabled compression
// {
@ -932,7 +932,7 @@ mod tests {
let request = TestRequest::get()
.uri("/tests/test%20space.binary")
.to_request();
let mut response = test::call_success(&mut srv, request);
let mut response = test::call_service(&mut srv, request);
assert_eq!(response.status(), StatusCode::OK);
let bytes =
@ -975,7 +975,7 @@ mod tests {
.uri("/")
.header(header::ACCEPT_ENCODING, "gzip")
.to_request();
let res = test::call_success(&mut srv, request);
let res = test::call_service(&mut srv, request);
assert_eq!(res.status(), StatusCode::OK);
assert!(!res.headers().contains_key(header::CONTENT_ENCODING));
}
@ -994,7 +994,7 @@ mod tests {
.uri("/")
.header(header::ACCEPT_ENCODING, "gzip")
.to_request();
let res = test::call_success(&mut srv, request);
let res = test::call_service(&mut srv, request);
assert_eq!(res.status(), StatusCode::OK);
assert_eq!(
res.headers()
@ -1021,20 +1021,20 @@ mod tests {
);
let req = TestRequest::with_uri("/missing").to_request();
let resp = test::call_success(&mut srv, req);
let resp = test::call_service(&mut srv, req);
assert_eq!(resp.status(), StatusCode::NOT_FOUND);
let mut srv = test::init_service(App::new().service(Files::new("/", ".")));
let req = TestRequest::default().to_request();
let resp = test::call_success(&mut srv, req);
let resp = test::call_service(&mut srv, req);
assert_eq!(resp.status(), StatusCode::NOT_FOUND);
let mut srv = test::init_service(
App::new().service(Files::new("/", ".").show_files_listing()),
);
let req = TestRequest::with_uri("/tests").to_request();
let mut resp = test::call_success(&mut srv, req);
let mut resp = test::call_service(&mut srv, req);
assert_eq!(
resp.headers().get(header::CONTENT_TYPE).unwrap(),
"text/html; charset=utf-8"
@ -1067,7 +1067,7 @@ mod tests {
.unwrap();
let req = TestRequest::with_uri("/missing").to_srv_request();
let mut resp = test::call_success(&mut st, req);
let mut resp = test::call_service(&mut st, req);
assert_eq!(resp.status(), StatusCode::OK);
let bytes =
test::block_on(resp.take_body().fold(BytesMut::new(), |mut b, c| {

View File

@ -1,6 +1,6 @@
[package]
name = "actix-framed"
version = "0.1.0-alpha.1"
version = "0.1.0"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
description = "Actix framed app server"
readme = "README.md"
@ -25,13 +25,13 @@ actix-service = "0.3.6"
actix-utils = "0.3.4"
actix-router = "0.1.2"
actix-rt = "0.2.2"
actix-http = "0.1.0-alpha.5"
actix-http = "0.1.0"
bytes = "0.4"
futures = "0.1.25"
log = "0.4"
[dev-dependencies]
actix-server = { version = "0.4.1", features=["ssl"] }
actix-server = { version = "0.4.3", features=["ssl"] }
actix-connect = { version = "0.1.4", features=["ssl"] }
actix-http-test = { version = "0.1.0-alpha.3", features=["ssl"] }
actix-http-test = { version = "0.1.0", features=["ssl"] }

View File

@ -1,5 +1,10 @@
# Changes
## [0.1.0] - 2019-04-16
* Update tests
## [0.1.0-alpha.1] - 2019-04-12
* Initial release

View File

@ -1,9 +1,15 @@
# Changes
## [0.1.0] - 2019-04-xx
## [0.1.0] - 2019-04-16
### Added
* Expose peer addr via `Request::peer_addr()` and `RequestHead::peer_addr`
### Changed
* `actix_http::encoding` always available
* use trust-dns-resolver 0.11.0

View File

@ -1,6 +1,6 @@
[package]
name = "actix-http"
version = "0.1.0-alpha.5"
version = "0.1.0"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
description = "Actix http primitives"
readme = "README.md"
@ -48,7 +48,7 @@ actix-service = "0.3.6"
actix-codec = "0.1.2"
actix-connect = "0.1.4"
actix-utils = "0.3.5"
actix-server-config = "0.1.0"
actix-server-config = "0.1.1"
actix-threadpool = "0.1.0"
base64 = "0.10"
@ -60,7 +60,7 @@ derive_more = "0.14"
either = "1.5.2"
encoding = "0.2"
futures = "0.1"
hashbrown = "0.2.0"
hashbrown = "0.2.2"
h2 = "0.1.16"
http = "0.1.17"
httparse = "1.3"
@ -76,10 +76,10 @@ serde = "1.0"
serde_json = "1.0"
sha1 = "0.6"
slab = "0.4"
serde_urlencoded = "0.5.3"
serde_urlencoded = "0.5.5"
time = "0.1"
tokio-tcp = "0.1.3"
tokio-timer = "0.2"
tokio-timer = "0.2.8"
tokio-current-thread = "0.1"
trust-dns-resolver = { version="0.11.0", default-features = false }
@ -96,9 +96,9 @@ openssl = { version="0.10", optional = true }
[dev-dependencies]
actix-rt = "0.2.2"
actix-server = { version = "0.4.1", features=["ssl"] }
actix-server = { version = "0.4.3", features=["ssl"] }
actix-connect = { version = "0.1.4", features=["ssl"] }
actix-http-test = { version = "0.1.0-alpha.3", features=["ssl"] }
actix-http-test = { version = "0.1.0", features=["ssl"] }
env_logger = "0.6"
serde_derive = "1.0"
openssl = { version="0.10" }

View File

@ -1,6 +1,6 @@
#![allow(unused_imports, unused_variables, dead_code)]
use std::fmt;
use std::io::{self, Write};
use std::io::Write;
use std::{fmt, io, net};
use actix_codec::{Decoder, Encoder};
use bitflags::bitflags;
@ -40,7 +40,6 @@ pub struct Codec {
// encoder part
flags: Flags,
encoder: encoder::MessageEncoder<Response<()>>,
// headers_size: u32,
}
impl Default for Codec {
@ -67,13 +66,11 @@ impl Codec {
};
Codec {
config,
flags,
decoder: decoder::MessageDecoder::default(),
payload: None,
version: Version::HTTP_11,
ctype: ConnectionType::Close,
flags,
// headers_size: 0,
encoder: encoder::MessageEncoder::default(),
}
}

View File

@ -1,8 +1,9 @@
use std::collections::VecDeque;
use std::time::Instant;
use std::{fmt, io};
use std::{fmt, io, net};
use actix_codec::{AsyncRead, AsyncWrite, Decoder, Encoder, Framed, FramedParts};
use actix_codec::{Decoder, Encoder, Framed, FramedParts};
use actix_server_config::IoStream;
use actix_service::Service;
use actix_utils::cloneable::CloneableService;
use bitflags::bitflags;
@ -81,6 +82,7 @@ where
expect: CloneableService<X>,
upgrade: Option<CloneableService<U>>,
flags: Flags,
peer_addr: Option<net::SocketAddr>,
error: Option<DispatchError>,
state: State<S, B, X>,
@ -161,7 +163,7 @@ impl PartialEq for PollResponse {
impl<T, S, B, X, U> Dispatcher<T, S, B, X, U>
where
T: AsyncRead + AsyncWrite,
T: IoStream,
S: Service<Request = Request>,
S::Error: Into<Error>,
S::Response: Into<Response<B>>,
@ -220,14 +222,15 @@ where
Dispatcher {
inner: DispatcherState::Normal(InnerDispatcher {
io,
codec,
read_buf,
write_buf: BytesMut::with_capacity(HW_BUFFER_SIZE),
payload: None,
state: State::None,
error: None,
peer_addr: io.peer_addr(),
messages: VecDeque::new(),
io,
codec,
read_buf,
service,
expect,
upgrade,
@ -241,7 +244,7 @@ where
impl<T, S, B, X, U> InnerDispatcher<T, S, B, X, U>
where
T: AsyncRead + AsyncWrite,
T: IoStream,
S: Service<Request = Request>,
S::Error: Into<Error>,
S::Response: Into<Response<B>>,
@ -490,6 +493,7 @@ where
match msg {
Message::Item(mut req) => {
let pl = self.codec.message_type();
req.head_mut().peer_addr = self.peer_addr;
if pl == MessageType::Stream && self.upgrade.is_some() {
self.messages.push_back(DispatcherMessage::Upgrade(req));
@ -649,7 +653,7 @@ where
impl<T, S, B, X, U> Future for Dispatcher<T, S, B, X, U>
where
T: AsyncRead + AsyncWrite,
T: IoStream,
S: Service<Request = Request>,
S::Error: Into<Error>,
S::Response: Into<Response<B>>,

View File

@ -1,8 +1,8 @@
use std::fmt;
use std::marker::PhantomData;
use actix_codec::{AsyncRead, AsyncWrite, Framed};
use actix_server_config::{Io, ServerConfig as SrvConfig};
use actix_codec::Framed;
use actix_server_config::{Io, IoStream, ServerConfig as SrvConfig};
use actix_service::{IntoNewService, NewService, Service};
use actix_utils::cloneable::CloneableService;
use futures::future::{ok, FutureResult};
@ -104,7 +104,7 @@ where
impl<T, P, S, B, X, U> NewService<SrvConfig> for H1Service<T, P, S, B, X, U>
where
T: AsyncRead + AsyncWrite,
T: IoStream,
S: NewService<SrvConfig, Request = Request>,
S::Error: Into<Error>,
S::Response: Into<Response<B>>,
@ -161,7 +161,7 @@ where
impl<T, P, S, B, X, U> Future for H1ServiceResponse<T, P, S, B, X, U>
where
T: AsyncRead + AsyncWrite,
T: IoStream,
S: NewService<SrvConfig, Request = Request>,
S::Error: Into<Error>,
S::Response: Into<Response<B>>,
@ -245,7 +245,7 @@ where
impl<T, P, S, B, X, U> Service for H1ServiceHandler<T, P, S, B, X, U>
where
T: AsyncRead + AsyncWrite,
T: IoStream,
S: Service<Request = Request>,
S::Error: Into<Error>,
S::Response: Into<Response<B>>,
@ -309,7 +309,7 @@ pub struct OneRequest<T, P> {
impl<T, P> OneRequest<T, P>
where
T: AsyncRead + AsyncWrite,
T: IoStream,
{
/// Create new `H1SimpleService` instance.
pub fn new() -> Self {
@ -322,7 +322,7 @@ where
impl<T, P> NewService<SrvConfig> for OneRequest<T, P>
where
T: AsyncRead + AsyncWrite,
T: IoStream,
{
type Request = Io<T, P>;
type Response = (Request, Framed<T, Codec>);
@ -348,7 +348,7 @@ pub struct OneRequestService<T, P> {
impl<T, P> Service for OneRequestService<T, P>
where
T: AsyncRead + AsyncWrite,
T: IoStream,
{
type Request = Io<T, P>;
type Response = (Request, Framed<T, Codec>);
@ -372,14 +372,14 @@ where
#[doc(hidden)]
pub struct OneRequestServiceResponse<T>
where
T: AsyncRead + AsyncWrite,
T: IoStream,
{
framed: Option<Framed<T, Codec>>,
}
impl<T> Future for OneRequestServiceResponse<T>
where
T: AsyncRead + AsyncWrite,
T: IoStream,
{
type Item = (Request, Framed<T, Codec>);
type Error = ParseError;

View File

@ -1,9 +1,10 @@
use std::collections::VecDeque;
use std::marker::PhantomData;
use std::time::Instant;
use std::{fmt, mem};
use std::{fmt, mem, net};
use actix_codec::{AsyncRead, AsyncWrite};
use actix_server_config::IoStream;
use actix_service::Service;
use actix_utils::cloneable::CloneableService;
use bitflags::bitflags;
@ -29,14 +30,11 @@ use crate::response::Response;
const CHUNK_SIZE: usize = 16_384;
/// Dispatcher for HTTP/2 protocol
pub struct Dispatcher<
T: AsyncRead + AsyncWrite,
S: Service<Request = Request>,
B: MessageBody,
> {
pub struct Dispatcher<T: IoStream, S: Service<Request = Request>, B: MessageBody> {
service: CloneableService<S>,
connection: Connection<T, Bytes>,
config: ServiceConfig,
peer_addr: Option<net::SocketAddr>,
ka_expire: Instant,
ka_timer: Option<Delay>,
_t: PhantomData<B>,
@ -44,7 +42,7 @@ pub struct Dispatcher<
impl<T, S, B> Dispatcher<T, S, B>
where
T: AsyncRead + AsyncWrite,
T: IoStream,
S: Service<Request = Request>,
S::Error: Into<Error>,
S::Future: 'static,
@ -56,6 +54,7 @@ where
connection: Connection<T, Bytes>,
config: ServiceConfig,
timeout: Option<Delay>,
peer_addr: Option<net::SocketAddr>,
) -> Self {
// let keepalive = config.keep_alive_enabled();
// let flags = if keepalive {
@ -76,9 +75,10 @@ where
Dispatcher {
service,
config,
peer_addr,
connection,
ka_expire,
ka_timer,
connection,
_t: PhantomData,
}
}
@ -86,7 +86,7 @@ where
impl<T, S, B> Future for Dispatcher<T, S, B>
where
T: AsyncRead + AsyncWrite,
T: IoStream,
S: Service<Request = Request>,
S::Error: Into<Error>,
S::Future: 'static,
@ -117,6 +117,7 @@ where
head.method = parts.method;
head.version = parts.version;
head.headers = parts.headers.into();
head.peer_addr = self.peer_addr;
tokio_current_thread::spawn(ServiceResponse::<S::Future, B> {
state: ServiceResponseState::ServiceCall(
self.service.call(req),

View File

@ -3,7 +3,7 @@ use std::marker::PhantomData;
use std::{io, net};
use actix_codec::{AsyncRead, AsyncWrite, Framed};
use actix_server_config::{Io, ServerConfig as SrvConfig};
use actix_server_config::{Io, IoStream, ServerConfig as SrvConfig};
use actix_service::{IntoNewService, NewService, Service};
use actix_utils::cloneable::CloneableService;
use bytes::Bytes;
@ -63,7 +63,7 @@ where
impl<T, P, S, B> NewService<SrvConfig> for H2Service<T, P, S, B>
where
T: AsyncRead + AsyncWrite,
T: IoStream,
S: NewService<SrvConfig, Request = Request>,
S::Error: Into<Error>,
S::Response: Into<Response<B>>,
@ -95,7 +95,7 @@ pub struct H2ServiceResponse<T, P, S: NewService<SrvConfig, Request = Request>,
impl<T, P, S, B> Future for H2ServiceResponse<T, P, S, B>
where
T: AsyncRead + AsyncWrite,
T: IoStream,
S: NewService<SrvConfig, Request = Request>,
S::Error: Into<Error>,
S::Response: Into<Response<B>>,
@ -140,7 +140,7 @@ where
impl<T, P, S, B> Service for H2ServiceHandler<T, P, S, B>
where
T: AsyncRead + AsyncWrite,
T: IoStream,
S: Service<Request = Request>,
S::Error: Into<Error>,
S::Future: 'static,
@ -161,17 +161,20 @@ where
}
fn call(&mut self, req: Self::Request) -> Self::Future {
let io = req.into_parts().0;
let peer_addr = io.peer_addr();
H2ServiceHandlerResponse {
state: State::Handshake(
Some(self.srv.clone()),
Some(self.cfg.clone()),
server::handshake(req.into_parts().0),
peer_addr,
server::handshake(io),
),
}
}
}
enum State<T: AsyncRead + AsyncWrite, S: Service<Request = Request>, B: MessageBody>
enum State<T: IoStream, S: Service<Request = Request>, B: MessageBody>
where
S::Future: 'static,
{
@ -179,13 +182,14 @@ where
Handshake(
Option<CloneableService<S>>,
Option<ServiceConfig>,
Option<net::SocketAddr>,
Handshake<T, Bytes>,
),
}
pub struct H2ServiceHandlerResponse<T, S, B>
where
T: AsyncRead + AsyncWrite,
T: IoStream,
S: Service<Request = Request>,
S::Error: Into<Error>,
S::Future: 'static,
@ -197,7 +201,7 @@ where
impl<T, S, B> Future for H2ServiceHandlerResponse<T, S, B>
where
T: AsyncRead + AsyncWrite,
T: IoStream,
S: Service<Request = Request>,
S::Error: Into<Error>,
S::Future: 'static,
@ -210,24 +214,28 @@ where
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
match self.state {
State::Incoming(ref mut disp) => disp.poll(),
State::Handshake(ref mut srv, ref mut config, ref mut handshake) => {
match handshake.poll() {
Ok(Async::Ready(conn)) => {
self.state = State::Incoming(Dispatcher::new(
srv.take().unwrap(),
conn,
config.take().unwrap(),
None,
));
self.poll()
}
Ok(Async::NotReady) => Ok(Async::NotReady),
Err(err) => {
trace!("H2 handshake error: {}", err);
Err(err.into())
}
State::Handshake(
ref mut srv,
ref mut config,
ref peer_addr,
ref mut handshake,
) => match handshake.poll() {
Ok(Async::Ready(conn)) => {
self.state = State::Incoming(Dispatcher::new(
srv.take().unwrap(),
conn,
config.take().unwrap(),
None,
peer_addr.clone(),
));
self.poll()
}
}
Ok(Async::NotReady) => Ok(Async::NotReady),
Err(err) => {
trace!("H2 handshake error: {}", err);
Err(err.into())
}
},
}
}
}

View File

@ -60,6 +60,7 @@ impl Response {
STATIC_RESP!(UnsupportedMediaType, StatusCode::UNSUPPORTED_MEDIA_TYPE);
STATIC_RESP!(RangeNotSatisfiable, StatusCode::RANGE_NOT_SATISFIABLE);
STATIC_RESP!(ExpectationFailed, StatusCode::EXPECTATION_FAILED);
STATIC_RESP!(UnprocessableEntity, StatusCode::UNPROCESSABLE_ENTITY);
STATIC_RESP!(InternalServerError, StatusCode::INTERNAL_SERVER_ERROR);
STATIC_RESP!(NotImplemented, StatusCode::NOT_IMPLEMENTED);

View File

@ -12,7 +12,6 @@ pub mod body;
mod builder;
pub mod client;
mod config;
#[cfg(any(feature = "flate2-zlib", feature = "flate2-rust", feature = "brotli"))]
pub mod encoding;
mod extensions;
mod header;

View File

@ -1,4 +1,5 @@
use std::cell::{Ref, RefCell, RefMut};
use std::net;
use std::rc::Rc;
use bitflags::bitflags;
@ -43,6 +44,7 @@ pub struct RequestHead {
pub version: Version,
pub headers: HeaderMap,
pub extensions: RefCell<Extensions>,
pub peer_addr: Option<net::SocketAddr>,
flags: Flags,
}
@ -54,6 +56,7 @@ impl Default for RequestHead {
version: Version::HTTP_11,
headers: HeaderMap::with_capacity(16),
flags: Flags::empty(),
peer_addr: None,
extensions: RefCell::new(Extensions::new()),
}
}

View File

@ -1,5 +1,5 @@
use std::cell::{Ref, RefMut};
use std::fmt;
use std::{fmt, net};
use http::{header, Method, Uri, Version};
@ -139,6 +139,7 @@ impl<P> Request<P> {
}
/// Check if request requires connection upgrade
#[inline]
pub fn upgrade(&self) -> bool {
if let Some(conn) = self.head().headers.get(header::CONNECTION) {
if let Ok(s) = conn.to_str() {
@ -147,6 +148,15 @@ impl<P> Request<P> {
}
self.head().method == Method::CONNECT
}
/// Peer socket address
///
/// Peer address is actual socket address, if proxy is used in front of
/// actix http server, then peer address would be address of this proxy.
#[inline]
pub fn peer_addr(&self) -> Option<net::SocketAddr> {
self.head().peer_addr
}
}
impl<P> fmt::Debug for Request<P> {
@ -168,3 +178,28 @@ impl<P> fmt::Debug for Request<P> {
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use http::HttpTryFrom;
#[test]
fn test_basics() {
let msg = Message::new();
let mut req = Request::from(msg);
req.headers_mut().insert(
header::CONTENT_TYPE,
header::HeaderValue::from_static("text/plain"),
);
assert!(req.headers().contains_key(header::CONTENT_TYPE));
*req.uri_mut() = Uri::try_from("/index.html?q=1").unwrap();
assert_eq!(req.uri().path(), "/index.html");
assert_eq!(req.uri().query(), Some("q=1"));
let s = format!("{:?}", req);
println!("T: {:?}", s);
assert!(s.contains("Request HTTP/1.1 GET:/index.html"));
}
}

View File

@ -1,8 +1,10 @@
use std::marker::PhantomData;
use std::{fmt, io};
use std::{fmt, io, net};
use actix_codec::{AsyncRead, AsyncWrite, Framed};
use actix_server_config::{Io as ServerIo, Protocol, ServerConfig as SrvConfig};
use actix_server_config::{
Io as ServerIo, IoStream, Protocol, ServerConfig as SrvConfig,
};
use actix_service::{IntoNewService, NewService, Service};
use actix_utils::cloneable::CloneableService;
use bytes::{Buf, BufMut, Bytes, BytesMut};
@ -128,7 +130,7 @@ where
impl<T, P, S, B, X, U> NewService<SrvConfig> for HttpService<T, P, S, B, X, U>
where
T: AsyncRead + AsyncWrite,
T: IoStream,
S: NewService<SrvConfig, Request = Request>,
S::Error: Into<Error>,
S::InitError: fmt::Debug,
@ -182,7 +184,7 @@ pub struct HttpServiceResponse<
impl<T, P, S, B, X, U> Future for HttpServiceResponse<T, P, S, B, X, U>
where
T: AsyncRead + AsyncWrite,
T: IoStream,
S: NewService<SrvConfig, Request = Request>,
S::Error: Into<Error>,
S::InitError: fmt::Debug,
@ -268,7 +270,7 @@ where
impl<T, P, S, B, X, U> Service for HttpServiceHandler<T, P, S, B, X, U>
where
T: AsyncRead + AsyncWrite,
T: IoStream,
S: Service<Request = Request>,
S::Error: Into<Error>,
S::Future: 'static,
@ -317,6 +319,7 @@ where
let (io, _, proto) = req.into_parts();
match proto {
Protocol::Http2 => {
let peer_addr = io.peer_addr();
let io = Io {
inner: io,
unread: None,
@ -326,6 +329,7 @@ where
server::handshake(io),
self.cfg.clone(),
self.srv.clone(),
peer_addr,
))),
}
}
@ -357,7 +361,7 @@ where
S: Service<Request = Request>,
S::Future: 'static,
S::Error: Into<Error>,
T: AsyncRead + AsyncWrite,
T: IoStream,
B: MessageBody,
X: Service<Request = Request, Response = Request>,
X::Error: Into<Error>,
@ -376,12 +380,19 @@ where
Option<CloneableService<U>>,
)>,
),
Handshake(Option<(Handshake<Io<T>, Bytes>, ServiceConfig, CloneableService<S>)>),
Handshake(
Option<(
Handshake<Io<T>, Bytes>,
ServiceConfig,
CloneableService<S>,
Option<net::SocketAddr>,
)>,
),
}
pub struct HttpServiceHandlerResponse<T, S, B, X, U>
where
T: AsyncRead + AsyncWrite,
T: IoStream,
S: Service<Request = Request>,
S::Error: Into<Error>,
S::Future: 'static,
@ -399,7 +410,7 @@ const HTTP2_PREFACE: [u8; 14] = *b"PRI * HTTP/2.0";
impl<T, S, B, X, U> Future for HttpServiceHandlerResponse<T, S, B, X, U>
where
T: AsyncRead + AsyncWrite,
T: IoStream,
S: Service<Request = Request>,
S::Error: Into<Error>,
S::Future: 'static,
@ -437,12 +448,17 @@ where
}
let (io, buf, cfg, srv, expect, upgrade) = data.take().unwrap();
if buf[..14] == HTTP2_PREFACE[..] {
let peer_addr = io.peer_addr();
let io = Io {
inner: io,
unread: Some(buf),
};
self.state =
State::Handshake(Some((server::handshake(io), cfg, srv)));
self.state = State::Handshake(Some((
server::handshake(io),
cfg,
srv,
peer_addr,
)));
} else {
self.state = State::H1(h1::Dispatcher::with_timeout(
io,
@ -470,8 +486,8 @@ where
} else {
panic!()
};
let (_, cfg, srv) = data.take().unwrap();
self.state = State::H2(Dispatcher::new(srv, conn, cfg, None));
let (_, cfg, srv, peer_addr) = data.take().unwrap();
self.state = State::H2(Dispatcher::new(srv, conn, cfg, None, peer_addr));
self.poll()
}
}
@ -523,3 +539,25 @@ impl<T: AsyncWrite> AsyncWrite for Io<T> {
self.inner.write_buf(buf)
}
}
impl<T: IoStream> IoStream for Io<T> {
#[inline]
fn peer_addr(&self) -> Option<net::SocketAddr> {
self.inner.peer_addr()
}
#[inline]
fn set_nodelay(&mut self, nodelay: bool) -> io::Result<()> {
self.inner.set_nodelay(nodelay)
}
#[inline]
fn set_linger(&mut self, dur: Option<std::time::Duration>) -> io::Result<()> {
self.inner.set_linger(dur)
}
#[inline]
fn set_keepalive(&mut self, dur: Option<std::time::Duration>) -> io::Result<()> {
self.inner.set_keepalive(dur)
}
}

View File

@ -4,6 +4,7 @@ use std::io;
use std::str::FromStr;
use actix_codec::{AsyncRead, AsyncWrite};
use actix_server_config::IoStream;
use bytes::{Buf, Bytes, BytesMut};
use futures::{Async, Poll};
use http::header::{self, HeaderName, HeaderValue};
@ -253,3 +254,17 @@ impl AsyncWrite for TestBuffer {
Ok(Async::NotReady)
}
}
impl IoStream for TestBuffer {
fn set_nodelay(&mut self, _nodelay: bool) -> io::Result<()> {
Ok(())
}
fn set_linger(&mut self, _dur: Option<std::time::Duration>) -> io::Result<()> {
Ok(())
}
fn set_keepalive(&mut self, _dur: Option<std::time::Duration>) -> io::Result<()> {
Ok(())
}
}

View File

@ -35,7 +35,10 @@ fn test_h1() {
.keep_alive(KeepAlive::Disabled)
.client_timeout(1000)
.client_disconnect(1000)
.h1(|_| future::ok::<_, ()>(Response::Ok().finish()))
.h1(|req: Request| {
assert!(req.peer_addr().is_some());
future::ok::<_, ()>(Response::Ok().finish())
})
});
let response = srv.block_on(srv.get("/").send()).unwrap();
@ -50,6 +53,7 @@ fn test_h1_2() {
.client_timeout(1000)
.client_disconnect(1000)
.finish(|req: Request| {
assert!(req.peer_addr().is_some());
assert_eq!(req.version(), http::Version::HTTP_11);
future::ok::<_, ()>(Response::Ok().finish())
})
@ -115,6 +119,7 @@ fn test_h2_1() -> std::io::Result<()> {
.and_then(
HttpService::build()
.finish(|req: Request| {
assert!(req.peer_addr().is_some());
assert_eq!(req.version(), http::Version::HTTP_2);
future::ok::<_, Error>(Response::Ok().finish())
})

View File

@ -18,7 +18,7 @@ name = "actix_multipart"
path = "src/lib.rs"
[dependencies]
actix-web = "1.0.0-alpha.3"
actix-web = "1.0.0-alpha.6"
actix-service = "0.3.4"
bytes = "0.4"
derive_more = "0.14"
@ -31,4 +31,4 @@ twoway = "0.2"
[dev-dependencies]
actix-rt = "0.2.2"
actix-http = "0.1.0-alpha.3"
actix-http = "0.1.0"

View File

@ -17,6 +17,7 @@
use std::collections::HashMap;
use std::rc::Rc;
use std::time::Duration;
use actix_service::{Service, Transform};
use actix_web::cookie::{Cookie, CookieJar, Key, SameSite};
@ -27,7 +28,6 @@ use derive_more::{Display, From};
use futures::future::{ok, Future, FutureResult};
use futures::Poll;
use serde_json::error::Error as JsonError;
use time::Duration;
use crate::Session;
@ -98,7 +98,7 @@ impl CookieSessionInner {
}
if let Some(max_age) = self.max_age {
cookie.set_max_age(max_age);
cookie.set_max_age(time::Duration::from_std(max_age).unwrap());
}
if let Some(same_site) = self.same_site {
@ -317,6 +317,7 @@ where
mod tests {
use super::*;
use actix_web::{test, web, App};
use bytes::Bytes;
#[test]
fn cookie_session() {
@ -338,6 +339,26 @@ mod tests {
.is_some());
}
#[test]
fn private_cookie() {
let mut app = test::init_service(
App::new()
.wrap(CookieSession::private(&[0; 32]).secure(false))
.service(web::resource("/").to(|ses: Session| {
let _ = ses.set("counter", 100);
"test"
})),
);
let request = test::TestRequest::get().to_request();
let response = test::block_on(app.call(request)).unwrap();
assert!(response
.response()
.cookies()
.find(|c| c.name() == "actix-session")
.is_some());
}
#[test]
fn cookie_session_extractor() {
let mut app = test::init_service(
@ -357,4 +378,44 @@ mod tests {
.find(|c| c.name() == "actix-session")
.is_some());
}
#[test]
fn basics() {
let mut app = test::init_service(
App::new()
.wrap(
CookieSession::signed(&[0; 32])
.path("/test/")
.name("actix-test")
.domain("localhost")
.http_only(true)
.same_site(SameSite::Lax)
.max_age(Duration::from_secs(100)),
)
.service(web::resource("/").to(|ses: Session| {
let _ = ses.set("counter", 100);
"test"
}))
.service(web::resource("/test/").to(|ses: Session| {
let val: usize = ses.get("counter").unwrap().unwrap();
format!("counter: {}", val)
})),
);
let request = test::TestRequest::get().to_request();
let response = test::block_on(app.call(request)).unwrap();
let cookie = response
.response()
.cookies()
.find(|c| c.name() == "actix-test")
.unwrap()
.clone();
assert_eq!(cookie.path().unwrap(), "/test/");
let request = test::TestRequest::with_uri("/test/")
.cookie(cookie)
.to_request();
let body = test::read_response(&mut app, request);
assert_eq!(body, Bytes::from_static(b"counter: 100"));
}
}

View File

@ -20,11 +20,11 @@ path = "src/lib.rs"
[dependencies]
actix = "0.8.0"
actix-web = "1.0.0-alpha.5"
actix-http = "0.1.0-alpha.5"
actix-http = "0.1.0"
actix-codec = "0.1.2"
bytes = "0.4"
futures = "0.1.25"
[dev-dependencies]
env_logger = "0.6"
actix-http-test = { version = "0.1.0-alpha.3", features=["ssl"] }
actix-http-test = { version = "0.1.0", features=["ssl"] }

View File

@ -199,7 +199,7 @@ mod tests {
use actix::Actor;
use actix_web::http::StatusCode;
use actix_web::test::{block_on, call_success, init_service, TestRequest};
use actix_web::test::{block_on, call_service, init_service, TestRequest};
use actix_web::{web, App, HttpResponse};
use bytes::{Bytes, BytesMut};
@ -237,7 +237,7 @@ mod tests {
})));
let req = TestRequest::with_uri("/test").to_request();
let mut resp = call_success(&mut srv, req);
let mut resp = call_service(&mut srv, req);
assert_eq!(resp.status(), StatusCode::OK);
let body = block_on(resp.take_body().fold(

View File

@ -17,6 +17,6 @@ syn = { version = "0.15", features = ["full", "parsing"] }
[dev-dependencies]
actix-web = { version = "1.0.0-alpha.6" }
actix-http = { version = "0.1.0-alpha.5", features=["ssl"] }
actix-http-test = { version = "0.1.0-alpha.3", features=["ssl"] }
actix-http = { version = "0.1.0", features=["ssl"] }
actix-http-test = { version = "0.1.0", features=["ssl"] }
futures = { version = "0.1" }

View File

@ -1,5 +1,17 @@
# Changes
## [0.1.1] - 2019-04-xx
### Changed
* `ClientRequest::if_true()` and `ClientRequest::if_some()` use instance instead of ref
## [0.1.0] - 2019-04-16
* No changes
## [0.1.0-alpha.6] - 2019-04-14
### Changed

View File

@ -1,6 +1,6 @@
[package]
name = "awc"
version = "0.1.0-alpha.6"
version = "0.1.0"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
description = "Actix http client."
readme = "README.md"
@ -38,7 +38,7 @@ flate2-rust = ["actix-http/flate2-rust"]
[dependencies]
actix-codec = "0.1.2"
actix-service = "0.3.6"
actix-http = "0.1.0-alpha.5"
actix-http = "0.1.0"
base64 = "0.10.1"
bytes = "0.4"
derive_more = "0.14"
@ -56,10 +56,10 @@ openssl = { version="0.10", optional = true }
[dev-dependencies]
actix-rt = "0.2.2"
actix-web = { version = "1.0.0-alpha.6", features=["ssl"] }
actix-http = { version = "0.1.0-alpha.5", features=["ssl"] }
actix-http-test = { version = "0.1.0-alpha.3", features=["ssl"] }
actix-http = { version = "0.1.0", features=["ssl"] }
actix-http-test = { version = "0.1.0", features=["ssl"] }
actix-utils = "0.3.4"
actix-server = { version = "0.4.1", features=["ssl"] }
actix-server = { version = "0.4.3", features=["ssl"] }
brotli2 = { version="0.3.2" }
flate2 = { version="1.0.2" }
env_logger = "0.6"

View File

@ -1 +1,33 @@
# Actix http client [![Build Status](https://travis-ci.org/actix/actix-web.svg?branch=master)](https://travis-ci.org/actix/actix-web) [![codecov](https://codecov.io/gh/actix/actix-web/branch/master/graph/badge.svg)](https://codecov.io/gh/actix/actix-web) [![crates.io](https://meritbadge.herokuapp.com/awc)](https://crates.io/crates/awc) [![Join the chat at https://gitter.im/actix/actix](https://badges.gitter.im/actix/actix.svg)](https://gitter.im/actix/actix?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
An HTTP Client
## Documentation & community resources
* [User Guide](https://actix.rs/docs/)
* [API Documentation](https://docs.rs/awc/)
* [Chat on gitter](https://gitter.im/actix/actix)
* Cargo package: [awc](https://crates.io/crates/awc)
* Minimum supported Rust version: 1.33 or later
## Example
```rust
use actix_rt::System;
use awc::Client;
use futures::future::{Future, lazy};
fn main() {
System::new("test").block_on(lazy(|| {
let mut client = Client::default();
client.get("http://www.rust-lang.org") // <- Create request builder
.header("User-Agent", "Actix-web")
.send() // <- Send http request
.and_then(|response| { // <- server http response
println!("Response: {:?}", response);
Ok(())
})
}));
}
```

View File

@ -331,26 +331,28 @@ impl ClientRequest {
/// This method calls provided closure with builder reference if
/// value is `true`.
pub fn if_true<F>(mut self, value: bool, f: F) -> Self
pub fn if_true<F>(self, value: bool, f: F) -> Self
where
F: FnOnce(&mut ClientRequest),
F: FnOnce(ClientRequest) -> ClientRequest,
{
if value {
f(&mut self);
f(self)
} else {
self
}
self
}
/// This method calls provided closure with builder reference if
/// value is `Some`.
pub fn if_some<T, F>(mut self, value: Option<T>, f: F) -> Self
pub fn if_some<T, F>(self, value: Option<T>, f: F) -> Self
where
F: FnOnce(T, &mut ClientRequest),
F: FnOnce(T, ClientRequest) -> ClientRequest,
{
if let Some(val) = value {
f(val, &mut self);
f(val, self)
} else {
self
}
self
}
/// Complete request construction and send body.

View File

@ -30,7 +30,7 @@ impl ConnectionInfo {
let mut host = None;
let mut scheme = None;
let mut remote = None;
let peer = None;
let mut peer = None;
// load forwarded header
for hdr in req.headers.get_all(&header::FORWARDED) {
@ -116,10 +116,10 @@ impl ConnectionInfo {
remote = h.split(',').next().map(|v| v.trim());
}
}
// if remote.is_none() {
// get peeraddr from socketaddr
// peer = req.peer_addr().map(|addr| format!("{}", addr));
// }
if remote.is_none() {
// get peeraddr from socketaddr
peer = req.peer_addr.map(|addr| format!("{}", addr));
}
}
ConnectionInfo {

View File

@ -363,13 +363,6 @@ impl FormatText {
let rt = (rt.num_nanoseconds().unwrap_or(0) as f64) / 1_000_000.0;
fmt.write_fmt(format_args!("{:.6}", rt))
}
// FormatText::RemoteAddr => {
// if let Some(remote) = req.connection_info().remote() {
// return remote.fmt(fmt);
// } else {
// "-".fmt(fmt)
// }
// }
FormatText::EnvironHeader(ref name) => {
if let Ok(val) = env::var(name) {
fmt.write_fmt(format_args!("{}", val))
@ -441,6 +434,14 @@ impl FormatText {
};
*self = FormatText::Str(s.to_string());
}
FormatText::RemoteAddr => {
let s = if let Some(remote) = req.connection_info().remote() {
FormatText::Str(remote.to_string())
} else {
FormatText::Str("-".to_string())
};
*self = s;
}
_ => (),
}
}

View File

@ -1,6 +1,6 @@
use std::cell::{Ref, RefCell, RefMut};
use std::fmt;
use std::rc::Rc;
use std::{fmt, net};
use actix_http::http::{HeaderMap, Method, Uri, Version};
use actix_http::{Error, Extensions, HttpMessage, Message, Payload, RequestHead};
@ -170,6 +170,17 @@ impl HttpRequest {
self.url_for(name, &NO_PARAMS)
}
/// Peer socket address
///
/// Peer address is actual socket address, if proxy is used in front of
/// actix http server, then peer address would be address of this proxy.
///
/// To get client connection information `.connection_info()` should be used.
#[inline]
pub fn peer_addr(&self) -> Option<net::SocketAddr> {
self.head().peer_addr
}
/// Get *ConnectionInfo* for the current request.
#[inline]
pub fn connection_info(&self) -> Ref<ConnectionInfo> {

View File

@ -307,11 +307,11 @@ pub(crate) mod tests {
);
let req = TestRequest::with_uri("/none").to_request();
let resp = TestRequest::block_on(srv.call(req)).unwrap();
let resp = block_on(srv.call(req)).unwrap();
assert_eq!(resp.status(), StatusCode::NOT_FOUND);
let req = TestRequest::with_uri("/some").to_request();
let resp = TestRequest::block_on(srv.call(req)).unwrap();
let resp = block_on(srv.call(req)).unwrap();
assert_eq!(resp.status(), StatusCode::OK);
match resp.response().body() {
ResponseBody::Body(Body::Bytes(ref b)) => {

View File

@ -1,5 +1,5 @@
use std::cell::{Ref, RefMut};
use std::fmt;
use std::{fmt, net};
use actix_http::body::{Body, MessageBody, ResponseBody};
use actix_http::http::{HeaderMap, Method, StatusCode, Uri, Version};
@ -12,6 +12,7 @@ use futures::future::{ok, FutureResult, IntoFuture};
use crate::config::{AppConfig, AppService};
use crate::data::Data;
use crate::info::ConnectionInfo;
use crate::request::HttpRequest;
pub trait HttpServiceFactory {
@ -134,6 +135,23 @@ impl ServiceRequest {
}
}
/// Peer socket address
///
/// Peer address is actual socket address, if proxy is used in front of
/// actix http server, then peer address would be address of this proxy.
///
/// To get client connection information `ConnectionInfo` should be used.
#[inline]
pub fn peer_addr(&self) -> Option<net::SocketAddr> {
self.head().peer_addr
}
/// Get *ConnectionInfo* for the current request.
#[inline]
pub fn connection_info(&self) -> Ref<ConnectionInfo> {
ConnectionInfo::get(self.head(), &*self.app_config())
}
/// Get a reference to the Path parameters.
///
/// Params is a container for url parameters.

View File

@ -58,7 +58,7 @@ where
/// This function panics on nested call.
pub fn run_on<F, R>(f: F) -> R
where
F: Fn() -> R,
F: FnOnce() -> R,
{
RT.with(move |rt| rt.borrow_mut().block_on(lazy(|| Ok::<_, ()>(f()))))
.unwrap()
@ -117,7 +117,9 @@ where
S::InitError: std::fmt::Debug,
{
let cfg = ServerConfig::new("127.0.0.1:8080".parse().unwrap());
block_on(app.into_new_service().new_service(&cfg)).unwrap()
let srv = app.into_new_service();
let fut = run_on(move || srv.new_service(&cfg));
block_on(fut).unwrap()
}
/// Calls service and waits for response future completion.
@ -146,7 +148,7 @@ where
S: Service<Request = R, Response = ServiceResponse<B>, Error = E>,
E: std::fmt::Debug,
{
block_on(app.call(req)).unwrap()
block_on(run_on(move || app.call(req))).unwrap()
}
/// Helper function that returns a response body of a TestRequest
@ -178,13 +180,15 @@ where
S: Service<Request = Request, Response = ServiceResponse<B>, Error = Error>,
B: MessageBody,
{
block_on(app.call(req).and_then(|mut resp: ServiceResponse<B>| {
resp.take_body()
.fold(BytesMut::new(), move |mut body, chunk| {
body.extend_from_slice(&chunk);
Ok::<_, Error>(body)
})
.map(|body: BytesMut| body.freeze())
block_on(run_on(move || {
app.call(req).and_then(|mut resp: ServiceResponse<B>| {
resp.take_body()
.fold(BytesMut::new(), move |mut body, chunk| {
body.extend_from_slice(&chunk);
Ok::<_, Error>(body)
})
.map(|body: BytesMut| body.freeze())
})
}))
.unwrap_or_else(|_| panic!("read_response failed at block_on unwrap"))
}
@ -229,17 +233,19 @@ where
B: MessageBody,
T: DeserializeOwned,
{
block_on(app.call(req).and_then(|mut resp: ServiceResponse<B>| {
resp.take_body()
.fold(BytesMut::new(), move |mut body, chunk| {
body.extend_from_slice(&chunk);
Ok::<_, Error>(body)
})
.and_then(|body: BytesMut| {
ok(serde_json::from_slice(&body).unwrap_or_else(|_| {
panic!("read_response_json failed during deserialization")
}))
})
block_on(run_on(move || {
app.call(req).and_then(|mut resp: ServiceResponse<B>| {
resp.take_body()
.fold(BytesMut::new(), move |mut body, chunk| {
body.extend_from_slice(&chunk);
Ok::<_, Error>(body)
})
.and_then(|body: BytesMut| {
ok(serde_json::from_slice(&body).unwrap_or_else(|_| {
panic!("read_response_json failed during deserialization")
}))
})
})
}))
.unwrap_or_else(|_| panic!("read_response_json failed at block_on unwrap"))
}
@ -468,23 +474,6 @@ impl TestRequest {
req.set_route_data(Some(Rc::new(self.route_data)));
(req, payload)
}
/// Runs the provided future, blocking the current thread until the future
/// completes.
///
/// This function can be used to synchronously block the current thread
/// until the provided `future` has resolved either successfully or with an
/// error. The result of the future is then returned from this function
/// call.
///
/// Note that this function is intended to be used only for testing purpose.
/// This function panics on nested call.
pub fn block_on<F>(f: F) -> Result<F::Item, F::Error>
where
F: Future,
{
block_on(f)
}
}
#[cfg(test)]

View File

@ -1,5 +1,10 @@
# Changes
## [0.1.0] - 2019-04-16
* No changes
## [0.1.0-alpha.3] - 2019-04-02
* Request functions accept path #743

View File

@ -1,6 +1,6 @@
[package]
name = "actix-http-test"
version = "0.1.0-alpha.3"
version = "0.1.0"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
description = "Actix http test server"
readme = "README.md"
@ -33,9 +33,9 @@ ssl = ["openssl", "actix-server/ssl", "awc/ssl"]
actix-codec = "0.1.2"
actix-rt = "0.2.2"
actix-service = "0.3.6"
actix-server = "0.4.1"
actix-server = "0.4.3"
actix-utils = "0.3.5"
awc = "0.1.0-alpha.5"
awc = "0.1.0"
base64 = "0.10"
bytes = "0.4"
@ -56,4 +56,4 @@ openssl = { version="0.10", optional = true }
[dev-dependencies]
actix-web = "1.0.0-alpha.5"
actix-http = "0.1.0-alpha.5"
actix-http = "0.1.0"

View File

@ -17,7 +17,7 @@ use futures::stream::once;
use rand::{distributions::Alphanumeric, Rng};
use actix_web::middleware::{BodyEncoding, Compress};
use actix_web::{http, test, web, App, HttpResponse, HttpServer};
use actix_web::{dev, http, test, web, App, HttpResponse, HttpServer};
const STR: &str = "Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
@ -89,6 +89,39 @@ fn test_body_gzip() {
assert_eq!(Bytes::from(dec), Bytes::from_static(STR.as_ref()));
}
#[cfg(any(feature = "flate2-zlib", feature = "flate2-rust"))]
#[test]
fn test_body_gzip2() {
let mut srv = TestServer::new(|| {
h1::H1Service::new(
App::new()
.wrap(Compress::new(ContentEncoding::Gzip))
.service(web::resource("/").route(web::to(|| {
Response::Ok().body(STR).into_body::<dev::Body>()
}))),
)
});
let mut response = srv
.block_on(
srv.get("/")
.no_decompress()
.header(ACCEPT_ENCODING, "gzip")
.send(),
)
.unwrap();
assert!(response.status().is_success());
// read response
let bytes = srv.block_on(response.body()).unwrap();
// decode
let mut e = GzDecoder::new(&bytes[..]);
let mut dec = Vec::new();
e.read_to_end(&mut dec).unwrap();
assert_eq!(Bytes::from(dec), Bytes::from_static(STR.as_ref()));
}
#[cfg(any(feature = "flate2-zlib", feature = "flate2-rust"))]
#[test]
fn test_body_encoding_override() {