mirror of https://github.com/fafhrd91/actix-web
Merge branch 'master' into master
This commit is contained in:
commit
c2598b7f8c
|
@ -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`
|
||||
|
|
17
Cargo.toml
17
Cargo.toml
|
@ -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,9 +116,8 @@ 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" }
|
||||
actix-files = { path = "actix-files" }
|
||||
awc = { path = "awc" }
|
||||
awc = { path = "awc" }
|
||||
|
|
|
@ -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| {
|
||||
|
|
|
@ -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"] }
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
# Changes
|
||||
|
||||
## [0.1.0] - 2019-04-16
|
||||
|
||||
* Update tests
|
||||
|
||||
|
||||
## [0.1.0-alpha.1] - 2019-04-12
|
||||
|
||||
* Initial release
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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" }
|
||||
|
|
|
@ -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(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>>,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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()),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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())
|
||||
})
|
||||
|
|
|
@ -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"
|
|
@ -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"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"] }
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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" }
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -1 +1,33 @@
|
|||
# Actix http client [](https://travis-ci.org/actix/actix-web) [](https://codecov.io/gh/actix/actix-web) [](https://crates.io/crates/awc) [](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(())
|
||||
})
|
||||
}));
|
||||
}
|
||||
```
|
||||
|
|
|
@ -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.
|
||||
|
|
10
src/info.rs
10
src/info.rs
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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)) => {
|
||||
|
|
|
@ -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.
|
||||
|
|
65
src/test.rs
65
src/test.rs
|
@ -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)]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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() {
|
||||
|
|
Loading…
Reference in New Issue