mirror of https://github.com/fafhrd91/actix-web
Merge branch 'master' into feat/scoped-middleware
This commit is contained in:
commit
589abb76f6
10
CHANGES.md
10
CHANGES.md
|
@ -1,17 +1,23 @@
|
|||
# Changes
|
||||
|
||||
## Unreleased - 2020-xx-xx
|
||||
## Unreleased - 2021-xx-xx
|
||||
### Changed
|
||||
* Bumped `rand` to `0.8`
|
||||
* Update `actix-*` dependencies to tokio `1.0` based versions. [#1813]
|
||||
* Bumped `rand` to `0.8`.
|
||||
* Update `rust-tls` to `0.19`. [#1813]
|
||||
* Rename `Handler` to `HandlerService` and rename `Factory` to `Handler`. [#1852]
|
||||
* MSRV is now 1.46.0.
|
||||
|
||||
[#1813]: https://github.com/actix/actix-web/pull/1813
|
||||
|
||||
|
||||
### Fixed
|
||||
* added the actual parsing error to `test::read_body_json` [#1812]
|
||||
|
||||
[#1812]: https://github.com/actix/actix-web/pull/1812
|
||||
[#1852]: https://github.com/actix/actix-web/pull/1852
|
||||
|
||||
|
||||
## 3.3.2 - 2020-12-01
|
||||
### Fixed
|
||||
* Removed an occasional `unwrap` on `None` panic in `NormalizePathNormalization`. [#1762]
|
||||
|
|
36
Cargo.toml
36
Cargo.toml
|
@ -47,10 +47,10 @@ compress = ["actix-http/compress", "awc/compress"]
|
|||
secure-cookies = ["actix-http/secure-cookies"]
|
||||
|
||||
# openssl
|
||||
openssl = ["actix-tls/openssl", "awc/openssl", "open-ssl"]
|
||||
openssl = ["actix-tls/accept", "actix-tls/openssl", "awc/openssl", "open-ssl"]
|
||||
|
||||
# rustls
|
||||
rustls = ["actix-tls/rustls", "awc/rustls", "rust-tls"]
|
||||
rustls = ["actix-tls/accept", "actix-tls/rustls", "awc/rustls", "rust-tls"]
|
||||
|
||||
[[example]]
|
||||
name = "basic"
|
||||
|
@ -73,28 +73,26 @@ name = "client"
|
|||
required-features = ["rustls"]
|
||||
|
||||
[dependencies]
|
||||
actix-codec = "0.3.0"
|
||||
actix-service = "1.0.6"
|
||||
actix-utils = "2.0.0"
|
||||
actix-router = "0.2.4"
|
||||
actix-rt = "1.1.1"
|
||||
actix-server = "1.0.0"
|
||||
actix-testing = "1.0.0"
|
||||
actix-codec = "0.4.0-beta.1"
|
||||
actix-macros = "0.1.0"
|
||||
actix-router = "0.2.4"
|
||||
actix-rt = "2.0.0-beta.1"
|
||||
actix-server = "2.0.0-beta.2"
|
||||
actix-service = "2.0.0-beta.2"
|
||||
actix-utils = "3.0.0-beta.1"
|
||||
actix-threadpool = "0.3.1"
|
||||
actix-tls = "2.0.0"
|
||||
actix-tls = { version = "3.0.0-beta.2", default-features = false, optional = true }
|
||||
|
||||
actix-web-codegen = "0.4.0"
|
||||
actix-http = "2.2.0"
|
||||
awc = { version = "2.0.3", default-features = false }
|
||||
|
||||
bytes = "0.5.3"
|
||||
ahash = "0.6"
|
||||
bytes = "1"
|
||||
derive_more = "0.99.5"
|
||||
encoding_rs = "0.8"
|
||||
futures-channel = { version = "0.3.5", default-features = false }
|
||||
futures-core = { version = "0.3.5", default-features = false }
|
||||
futures-util = { version = "0.3.5", default-features = false }
|
||||
fxhash = "0.2.1"
|
||||
futures-core = { version = "0.3.7", default-features = false }
|
||||
futures-util = { version = "0.3.7", default-features = false }
|
||||
log = "0.4"
|
||||
mime = "0.3"
|
||||
socket2 = "0.3.16"
|
||||
|
@ -106,12 +104,12 @@ serde_urlencoded = "0.7"
|
|||
time = { version = "0.2.7", default-features = false, features = ["std"] }
|
||||
url = "2.1"
|
||||
open-ssl = { package = "openssl", version = "0.10", optional = true }
|
||||
rust-tls = { package = "rustls", version = "0.18.0", optional = true }
|
||||
tinyvec = { version = "1", features = ["alloc"] }
|
||||
rust-tls = { package = "rustls", version = "0.19.0", optional = true }
|
||||
smallvec = "1.6"
|
||||
|
||||
[dev-dependencies]
|
||||
actix = "0.10.0"
|
||||
actix-http = { version = "2.1.0", features = ["actors"] }
|
||||
actix = "0.11.0-beta.1"
|
||||
actix-http = { version = "2.2.0", features = ["actors"] }
|
||||
rand = "0.8"
|
||||
env_logger = "0.8"
|
||||
serde_derive = "1.0"
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
# Changes
|
||||
|
||||
## Unreleased - 2020-xx-xx
|
||||
## Unreleased - 2021-xx-xx
|
||||
* `HttpRange::parse` now has its own error type.
|
||||
* Update `bytes` to `1.0`. [#1813]
|
||||
|
||||
[#1813]: https://github.com/actix/actix-web/pull/1813
|
||||
|
||||
|
||||
## 0.5.0 - 2020-12-26
|
||||
|
|
|
@ -18,9 +18,9 @@ path = "src/lib.rs"
|
|||
|
||||
[dependencies]
|
||||
actix-web = { version = "3.0.0", default-features = false }
|
||||
actix-service = "1.0.6"
|
||||
actix-service = "2.0.0-beta.2"
|
||||
bitflags = "1"
|
||||
bytes = "0.5.3"
|
||||
bytes = "1"
|
||||
futures-core = { version = "0.3.7", default-features = false }
|
||||
futures-util = { version = "0.3.7", default-features = false }
|
||||
derive_more = "0.99.5"
|
||||
|
@ -31,5 +31,5 @@ percent-encoding = "2.1"
|
|||
v_htmlescape = "0.12"
|
||||
|
||||
[dev-dependencies]
|
||||
actix-rt = "1.0.0"
|
||||
actix-rt = "2.0.0-beta.1"
|
||||
actix-web = "3.0.0"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::{cell::RefCell, fmt, io, path::PathBuf, rc::Rc};
|
||||
|
||||
use actix_service::{boxed, IntoServiceFactory, ServiceFactory};
|
||||
use actix_service::{boxed, IntoServiceFactory, ServiceFactory, ServiceFactoryExt};
|
||||
use actix_web::{
|
||||
dev::{
|
||||
AppService, HttpServiceFactory, ResourceDef, ServiceRequest, ServiceResponse,
|
||||
|
@ -201,10 +201,10 @@ impl Files {
|
|||
/// Sets default handler which is used when no matched file could be found.
|
||||
pub fn default_handler<F, U>(mut self, f: F) -> Self
|
||||
where
|
||||
F: IntoServiceFactory<U>,
|
||||
F: IntoServiceFactory<U, ServiceRequest>,
|
||||
U: ServiceFactory<
|
||||
ServiceRequest,
|
||||
Config = (),
|
||||
Request = ServiceRequest,
|
||||
Response = ServiceResponse,
|
||||
Error = Error,
|
||||
> + 'static,
|
||||
|
@ -241,8 +241,7 @@ impl HttpServiceFactory for Files {
|
|||
}
|
||||
}
|
||||
|
||||
impl ServiceFactory for Files {
|
||||
type Request = ServiceRequest;
|
||||
impl ServiceFactory<ServiceRequest> for Files {
|
||||
type Response = ServiceResponse;
|
||||
type Error = Error;
|
||||
type Config = ();
|
||||
|
|
|
@ -57,8 +57,7 @@ impl fmt::Debug for FilesService {
|
|||
}
|
||||
}
|
||||
|
||||
impl Service for FilesService {
|
||||
type Request = ServiceRequest;
|
||||
impl Service<ServiceRequest> for FilesService {
|
||||
type Response = ServiceResponse;
|
||||
type Error = Error;
|
||||
type Future = FilesServiceFuture;
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
# Changes
|
||||
|
||||
## Unreleased - 2020-xx-xx
|
||||
## Unreleased - 2021-xx-xx
|
||||
* Update `bytes` to `1.0`. [#1813]
|
||||
|
||||
[#1813]: https://github.com/actix/actix-web/pull/1813
|
||||
|
||||
|
||||
## 2.1.0 - 2020-11-25
|
||||
|
|
|
@ -29,19 +29,18 @@ default = []
|
|||
openssl = ["open-ssl", "awc/openssl"]
|
||||
|
||||
[dependencies]
|
||||
actix-service = "1.0.6"
|
||||
actix-codec = "0.3.0"
|
||||
actix-connect = "2.0.0"
|
||||
actix-utils = "2.0.0"
|
||||
actix-rt = "1.1.1"
|
||||
actix-server = "1.0.0"
|
||||
actix-testing = "1.0.0"
|
||||
actix-service = "2.0.0-beta.2"
|
||||
actix-codec = "0.4.0-beta.1"
|
||||
actix-tls = "3.0.0-beta.2"
|
||||
actix-utils = "3.0.0-beta.1"
|
||||
actix-rt = "2.0.0-beta.1"
|
||||
actix-server = "2.0.0-beta.2"
|
||||
awc = "2.0.0"
|
||||
|
||||
base64 = "0.13"
|
||||
bytes = "0.5.3"
|
||||
futures-core = { version = "0.3.5", default-features = false }
|
||||
http = "0.2.0"
|
||||
bytes = "1"
|
||||
futures-core = { version = "0.3.7", default-features = false }
|
||||
http = "0.2.2"
|
||||
log = "0.4"
|
||||
socket2 = "0.3"
|
||||
serde = "1.0"
|
||||
|
|
|
@ -16,8 +16,6 @@ use futures_core::stream::Stream;
|
|||
use http::Method;
|
||||
use socket2::{Domain, Protocol, Socket, Type};
|
||||
|
||||
pub use actix_testing::*;
|
||||
|
||||
/// Start test server
|
||||
///
|
||||
/// `TestServer` is very simple test server that simplify process of writing
|
||||
|
@ -65,13 +63,16 @@ pub async fn test_server_with_addr<F: ServiceFactory<TcpStream>>(
|
|||
let sys = System::new("actix-test-server");
|
||||
let local_addr = tcp.local_addr().unwrap();
|
||||
|
||||
Server::build()
|
||||
let srv = Server::build()
|
||||
.listen("test", tcp, factory)?
|
||||
.workers(1)
|
||||
.disable_signals()
|
||||
.start();
|
||||
.disable_signals();
|
||||
|
||||
sys.block_on(async {
|
||||
srv.start();
|
||||
tx.send((System::current(), local_addr)).unwrap();
|
||||
});
|
||||
|
||||
tx.send((System::current(), local_addr)).unwrap();
|
||||
sys.run()
|
||||
});
|
||||
|
||||
|
@ -105,7 +106,7 @@ pub async fn test_server_with_addr<F: ServiceFactory<TcpStream>>(
|
|||
|
||||
Client::builder().connector(connector).finish()
|
||||
};
|
||||
actix_connect::start_default_resolver().await.unwrap();
|
||||
actix_tls::connect::start_default_resolver().await.unwrap();
|
||||
|
||||
TestServer {
|
||||
addr,
|
||||
|
|
|
@ -1,13 +1,26 @@
|
|||
# Changes
|
||||
|
||||
## Unreleased - 2020-xx-xx
|
||||
## Unreleased - 2021-xx-xx
|
||||
### Changed
|
||||
* Bumped `rand` to `0.8`
|
||||
* Bumped `rand` to `0.8`.
|
||||
* Update `actix-*` dependencies to tokio `1.0` based versions. [#1813]
|
||||
* Update `bytes` to `1.0`. [#1813]
|
||||
* Update `h2` to `0.3`. [#1813]
|
||||
|
||||
|
||||
[#1813]: https://github.com/actix/actix-web/pull/1813
|
||||
|
||||
|
||||
### Removed
|
||||
* Deprecated `on_connect` methods have been removed. Prefer the new
|
||||
`on_connect_ext` technique. [#1857]
|
||||
* Remove `ResponseError` impl for `actix::actors::resolver::ResolverError`
|
||||
due to deprecate of resolver actor. [#1813]
|
||||
* Remove `ConnectError::SslHandshakeError` and re-export of `HandshakeError`.
|
||||
due to the removal of this type from `tokio-openssl` crate. openssl handshake
|
||||
error would return as `ConnectError::SslError`. [#1813]
|
||||
|
||||
[#1813]: https://github.com/actix/actix-web/pull/1813
|
||||
[#1857]: https://github.com/actix/actix-web/pull/1857
|
||||
|
||||
|
||||
|
|
|
@ -25,10 +25,10 @@ path = "src/lib.rs"
|
|||
default = []
|
||||
|
||||
# openssl
|
||||
openssl = ["actix-tls/openssl", "actix-connect/openssl"]
|
||||
openssl = ["actix-tls/openssl"]
|
||||
|
||||
# rustls support
|
||||
rustls = ["actix-tls/rustls", "actix-connect/rustls"]
|
||||
rustls = ["actix-tls/rustls"]
|
||||
|
||||
# enable compressison support
|
||||
compress = ["flate2", "brotli2"]
|
||||
|
@ -40,29 +40,28 @@ secure-cookies = ["cookie/secure"]
|
|||
actors = ["actix"]
|
||||
|
||||
[dependencies]
|
||||
actix-service = "1.0.6"
|
||||
actix-codec = "0.3.0"
|
||||
actix-connect = "2.0.0"
|
||||
actix-utils = "2.0.0"
|
||||
actix-rt = "1.0.0"
|
||||
actix-service = "2.0.0-beta.2"
|
||||
actix-codec = "0.4.0-beta.1"
|
||||
actix-utils = "3.0.0-beta.1"
|
||||
actix-rt = "2.0.0-beta.1"
|
||||
actix-threadpool = "0.3.1"
|
||||
actix-tls = { version = "2.0.0", optional = true }
|
||||
actix = { version = "0.10.0", optional = true }
|
||||
actix-tls = "3.0.0-beta.2"
|
||||
actix = { version = "0.11.0-beta.1", optional = true }
|
||||
|
||||
base64 = "0.13"
|
||||
bitflags = "1.2"
|
||||
bytes = "0.5.3"
|
||||
bytes = "1"
|
||||
cookie = { version = "0.14.1", features = ["percent-encode"] }
|
||||
copyless = "0.1.4"
|
||||
derive_more = "0.99.2"
|
||||
either = "1.5.3"
|
||||
encoding_rs = "0.8"
|
||||
futures-channel = { version = "0.3.5", default-features = false }
|
||||
futures-core = { version = "0.3.5", default-features = false }
|
||||
futures-util = { version = "0.3.5", default-features = false }
|
||||
futures-channel = { version = "0.3.7", default-features = false }
|
||||
futures-core = { version = "0.3.7", default-features = false }
|
||||
futures-util = { version = "0.3.7", default-features = false, features = ["sink"] }
|
||||
fxhash = "0.2.1"
|
||||
h2 = "0.2.1"
|
||||
http = "0.2.0"
|
||||
h2 = "0.3.0"
|
||||
http = "0.2.2"
|
||||
httparse = "1.3"
|
||||
indexmap = "1.3"
|
||||
itoa = "0.4"
|
||||
|
@ -86,18 +85,17 @@ brotli2 = { version="0.3.2", optional = true }
|
|||
flate2 = { version = "1.0.13", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
actix-server = "1.0.1"
|
||||
actix-connect = { version = "2.0.0", features = ["openssl"] }
|
||||
actix-server = "2.0.0-beta.2"
|
||||
actix-http-test = { version = "2.0.0", features = ["openssl"] }
|
||||
actix-tls = { version = "2.0.0", features = ["openssl"] }
|
||||
actix-tls = { version = "3.0.0-beta.2", features = ["openssl"] }
|
||||
criterion = "0.3"
|
||||
env_logger = "0.7"
|
||||
serde_derive = "1.0"
|
||||
open-ssl = { version="0.10", package = "openssl" }
|
||||
rust-tls = { version="0.18", package = "rustls" }
|
||||
rust-tls = { version="0.19", package = "rustls" }
|
||||
|
||||
[[bench]]
|
||||
name = "content-length"
|
||||
name = "write-camel-case"
|
||||
harness = false
|
||||
|
||||
[[bench]]
|
||||
|
|
|
@ -1,291 +0,0 @@
|
|||
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
|
||||
|
||||
use bytes::BytesMut;
|
||||
|
||||
// benchmark sending all requests at the same time
|
||||
fn bench_write_content_length(c: &mut Criterion) {
|
||||
let mut group = c.benchmark_group("write_content_length");
|
||||
|
||||
let sizes = [
|
||||
0, 1, 11, 83, 101, 653, 1001, 6323, 10001, 56329, 100001, 123456, 98724245,
|
||||
4294967202,
|
||||
];
|
||||
|
||||
for i in sizes.iter() {
|
||||
group.bench_with_input(BenchmarkId::new("Original (unsafe)", i), i, |b, &i| {
|
||||
b.iter(|| {
|
||||
let mut b = BytesMut::with_capacity(35);
|
||||
_original::write_content_length(i, &mut b)
|
||||
})
|
||||
});
|
||||
|
||||
group.bench_with_input(BenchmarkId::new("New (safe)", i), i, |b, &i| {
|
||||
b.iter(|| {
|
||||
let mut b = BytesMut::with_capacity(35);
|
||||
_new::write_content_length(i, &mut b)
|
||||
})
|
||||
});
|
||||
|
||||
group.bench_with_input(BenchmarkId::new("itoa", i), i, |b, &i| {
|
||||
b.iter(|| {
|
||||
let mut b = BytesMut::with_capacity(35);
|
||||
_itoa::write_content_length(i, &mut b)
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
group.finish();
|
||||
}
|
||||
|
||||
criterion_group!(benches, bench_write_content_length);
|
||||
criterion_main!(benches);
|
||||
|
||||
mod _itoa {
|
||||
use bytes::{BufMut, BytesMut};
|
||||
|
||||
pub fn write_content_length(n: usize, bytes: &mut BytesMut) {
|
||||
if n == 0 {
|
||||
bytes.put_slice(b"\r\ncontent-length: 0\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
let mut buf = itoa::Buffer::new();
|
||||
|
||||
bytes.put_slice(b"\r\ncontent-length: ");
|
||||
bytes.put_slice(buf.format(n).as_bytes());
|
||||
bytes.put_slice(b"\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
mod _new {
|
||||
use bytes::{BufMut, BytesMut};
|
||||
|
||||
const DIGITS_START: u8 = b'0';
|
||||
|
||||
/// NOTE: bytes object has to contain enough space
|
||||
pub fn write_content_length(n: usize, bytes: &mut BytesMut) {
|
||||
if n == 0 {
|
||||
bytes.put_slice(b"\r\ncontent-length: 0\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
bytes.put_slice(b"\r\ncontent-length: ");
|
||||
|
||||
if n < 10 {
|
||||
bytes.put_u8(DIGITS_START + (n as u8));
|
||||
} else if n < 100 {
|
||||
let n = n as u8;
|
||||
|
||||
let d10 = n / 10;
|
||||
let d1 = n % 10;
|
||||
|
||||
bytes.put_u8(DIGITS_START + d10);
|
||||
bytes.put_u8(DIGITS_START + d1);
|
||||
} else if n < 1000 {
|
||||
let n = n as u16;
|
||||
|
||||
let d100 = (n / 100) as u8;
|
||||
let d10 = ((n / 10) % 10) as u8;
|
||||
let d1 = (n % 10) as u8;
|
||||
|
||||
bytes.put_u8(DIGITS_START + d100);
|
||||
bytes.put_u8(DIGITS_START + d10);
|
||||
bytes.put_u8(DIGITS_START + d1);
|
||||
} else if n < 10_000 {
|
||||
let n = n as u16;
|
||||
|
||||
let d1000 = (n / 1000) as u8;
|
||||
let d100 = ((n / 100) % 10) as u8;
|
||||
let d10 = ((n / 10) % 10) as u8;
|
||||
let d1 = (n % 10) as u8;
|
||||
|
||||
bytes.put_u8(DIGITS_START + d1000);
|
||||
bytes.put_u8(DIGITS_START + d100);
|
||||
bytes.put_u8(DIGITS_START + d10);
|
||||
bytes.put_u8(DIGITS_START + d1);
|
||||
} else if n < 100_000 {
|
||||
let n = n as u32;
|
||||
|
||||
let d10000 = (n / 10000) as u8;
|
||||
let d1000 = ((n / 1000) % 10) as u8;
|
||||
let d100 = ((n / 100) % 10) as u8;
|
||||
let d10 = ((n / 10) % 10) as u8;
|
||||
let d1 = (n % 10) as u8;
|
||||
|
||||
bytes.put_u8(DIGITS_START + d10000);
|
||||
bytes.put_u8(DIGITS_START + d1000);
|
||||
bytes.put_u8(DIGITS_START + d100);
|
||||
bytes.put_u8(DIGITS_START + d10);
|
||||
bytes.put_u8(DIGITS_START + d1);
|
||||
} else if n < 1_000_000 {
|
||||
let n = n as u32;
|
||||
|
||||
let d100000 = (n / 100000) as u8;
|
||||
let d10000 = ((n / 10000) % 10) as u8;
|
||||
let d1000 = ((n / 1000) % 10) as u8;
|
||||
let d100 = ((n / 100) % 10) as u8;
|
||||
let d10 = ((n / 10) % 10) as u8;
|
||||
let d1 = (n % 10) as u8;
|
||||
|
||||
bytes.put_u8(DIGITS_START + d100000);
|
||||
bytes.put_u8(DIGITS_START + d10000);
|
||||
bytes.put_u8(DIGITS_START + d1000);
|
||||
bytes.put_u8(DIGITS_START + d100);
|
||||
bytes.put_u8(DIGITS_START + d10);
|
||||
bytes.put_u8(DIGITS_START + d1);
|
||||
} else {
|
||||
write_usize(n, bytes);
|
||||
}
|
||||
|
||||
bytes.put_slice(b"\r\n");
|
||||
}
|
||||
|
||||
fn write_usize(n: usize, bytes: &mut BytesMut) {
|
||||
let mut n = n;
|
||||
|
||||
// 20 chars is max length of a usize (2^64)
|
||||
// digits will be added to the buffer from lsd to msd
|
||||
let mut buf = BytesMut::with_capacity(20);
|
||||
|
||||
while n > 9 {
|
||||
// "pop" the least-significant digit
|
||||
let lsd = (n % 10) as u8;
|
||||
|
||||
// remove the lsd from n
|
||||
n = n / 10;
|
||||
|
||||
buf.put_u8(DIGITS_START + lsd);
|
||||
}
|
||||
|
||||
// put msd to result buffer
|
||||
bytes.put_u8(DIGITS_START + (n as u8));
|
||||
|
||||
// put, in reverse (msd to lsd), remaining digits to buffer
|
||||
for i in (0..buf.len()).rev() {
|
||||
bytes.put_u8(buf[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod _original {
|
||||
use std::{mem, ptr, slice};
|
||||
|
||||
use bytes::{BufMut, BytesMut};
|
||||
|
||||
const DEC_DIGITS_LUT: &[u8] = b"0001020304050607080910111213141516171819\
|
||||
2021222324252627282930313233343536373839\
|
||||
4041424344454647484950515253545556575859\
|
||||
6061626364656667686970717273747576777879\
|
||||
8081828384858687888990919293949596979899";
|
||||
|
||||
/// NOTE: bytes object has to contain enough space
|
||||
pub fn write_content_length(mut n: usize, bytes: &mut BytesMut) {
|
||||
if n < 10 {
|
||||
let mut buf: [u8; 21] = [
|
||||
b'\r', b'\n', b'c', b'o', b'n', b't', b'e', b'n', b't', b'-', b'l',
|
||||
b'e', b'n', b'g', b't', b'h', b':', b' ', b'0', b'\r', b'\n',
|
||||
];
|
||||
buf[18] = (n as u8) + b'0';
|
||||
bytes.put_slice(&buf);
|
||||
} else if n < 100 {
|
||||
let mut buf: [u8; 22] = [
|
||||
b'\r', b'\n', b'c', b'o', b'n', b't', b'e', b'n', b't', b'-', b'l',
|
||||
b'e', b'n', b'g', b't', b'h', b':', b' ', b'0', b'0', b'\r', b'\n',
|
||||
];
|
||||
let d1 = n << 1;
|
||||
unsafe {
|
||||
ptr::copy_nonoverlapping(
|
||||
DEC_DIGITS_LUT.as_ptr().add(d1),
|
||||
buf.as_mut_ptr().offset(18),
|
||||
2,
|
||||
);
|
||||
}
|
||||
bytes.put_slice(&buf);
|
||||
} else if n < 1000 {
|
||||
let mut buf: [u8; 23] = [
|
||||
b'\r', b'\n', b'c', b'o', b'n', b't', b'e', b'n', b't', b'-', b'l',
|
||||
b'e', b'n', b'g', b't', b'h', b':', b' ', b'0', b'0', b'0', b'\r',
|
||||
b'\n',
|
||||
];
|
||||
// decode 2 more chars, if > 2 chars
|
||||
let d1 = (n % 100) << 1;
|
||||
n /= 100;
|
||||
unsafe {
|
||||
ptr::copy_nonoverlapping(
|
||||
DEC_DIGITS_LUT.as_ptr().add(d1),
|
||||
buf.as_mut_ptr().offset(19),
|
||||
2,
|
||||
)
|
||||
};
|
||||
|
||||
// decode last 1
|
||||
buf[18] = (n as u8) + b'0';
|
||||
|
||||
bytes.put_slice(&buf);
|
||||
} else {
|
||||
bytes.put_slice(b"\r\ncontent-length: ");
|
||||
convert_usize(n, bytes);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn convert_usize(mut n: usize, bytes: &mut BytesMut) {
|
||||
let mut curr: isize = 39;
|
||||
let mut buf: [u8; 41] = unsafe { mem::MaybeUninit::uninit().assume_init() };
|
||||
buf[39] = b'\r';
|
||||
buf[40] = b'\n';
|
||||
let buf_ptr = buf.as_mut_ptr();
|
||||
let lut_ptr = DEC_DIGITS_LUT.as_ptr();
|
||||
|
||||
// eagerly decode 4 characters at a time
|
||||
while n >= 10_000 {
|
||||
let rem = (n % 10_000) as isize;
|
||||
n /= 10_000;
|
||||
|
||||
let d1 = (rem / 100) << 1;
|
||||
let d2 = (rem % 100) << 1;
|
||||
curr -= 4;
|
||||
unsafe {
|
||||
ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
|
||||
ptr::copy_nonoverlapping(
|
||||
lut_ptr.offset(d2),
|
||||
buf_ptr.offset(curr + 2),
|
||||
2,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// if we reach here numbers are <= 9999, so at most 4 chars long
|
||||
let mut n = n as isize; // possibly reduce 64bit math
|
||||
|
||||
// decode 2 more chars, if > 2 chars
|
||||
if n >= 100 {
|
||||
let d1 = (n % 100) << 1;
|
||||
n /= 100;
|
||||
curr -= 2;
|
||||
unsafe {
|
||||
ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
|
||||
}
|
||||
}
|
||||
|
||||
// decode last 1 or 2 chars
|
||||
if n < 10 {
|
||||
curr -= 1;
|
||||
unsafe {
|
||||
*buf_ptr.offset(curr) = (n as u8) + b'0';
|
||||
}
|
||||
} else {
|
||||
let d1 = n << 1;
|
||||
curr -= 2;
|
||||
unsafe {
|
||||
ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
|
||||
}
|
||||
}
|
||||
|
||||
unsafe {
|
||||
bytes.extend_from_slice(slice::from_raw_parts(
|
||||
buf_ptr.offset(curr),
|
||||
41 - curr as usize,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -176,7 +176,7 @@ mod _original {
|
|||
buf[5] = b'0';
|
||||
buf[7] = b'9';
|
||||
}
|
||||
_ => (),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
let mut curr: isize = 12;
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion};
|
||||
|
||||
fn bench_write_camel_case(c: &mut Criterion) {
|
||||
let mut group = c.benchmark_group("write_camel_case");
|
||||
|
||||
let names = ["connection", "Transfer-Encoding", "transfer-encoding"];
|
||||
|
||||
for &i in &names {
|
||||
let bts = i.as_bytes();
|
||||
|
||||
group.bench_with_input(BenchmarkId::new("Original", i), bts, |b, bts| {
|
||||
b.iter(|| {
|
||||
let mut buf = black_box([0; 24]);
|
||||
_original::write_camel_case(black_box(bts), &mut buf)
|
||||
});
|
||||
});
|
||||
|
||||
group.bench_with_input(BenchmarkId::new("New", i), bts, |b, bts| {
|
||||
b.iter(|| {
|
||||
let mut buf = black_box([0; 24]);
|
||||
_new::write_camel_case(black_box(bts), &mut buf)
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
group.finish();
|
||||
}
|
||||
|
||||
criterion_group!(benches, bench_write_camel_case);
|
||||
criterion_main!(benches);
|
||||
|
||||
mod _new {
|
||||
pub fn write_camel_case(value: &[u8], buffer: &mut [u8]) {
|
||||
// first copy entire (potentially wrong) slice to output
|
||||
buffer[..value.len()].copy_from_slice(value);
|
||||
|
||||
let mut iter = value.iter();
|
||||
|
||||
// first character should be uppercase
|
||||
if let Some(c @ b'a'..=b'z') = iter.next() {
|
||||
buffer[0] = c & 0b1101_1111;
|
||||
}
|
||||
|
||||
// track 1 ahead of the current position since that's the location being assigned to
|
||||
let mut index = 2;
|
||||
|
||||
// remaining characters after hyphens should also be uppercase
|
||||
while let Some(&c) = iter.next() {
|
||||
if c == b'-' {
|
||||
// advance iter by one and uppercase if needed
|
||||
if let Some(c @ b'a'..=b'z') = iter.next() {
|
||||
buffer[index] = c & 0b1101_1111;
|
||||
}
|
||||
}
|
||||
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod _original {
|
||||
pub fn write_camel_case(value: &[u8], buffer: &mut [u8]) {
|
||||
let mut index = 0;
|
||||
let key = value;
|
||||
let mut key_iter = key.iter();
|
||||
|
||||
if let Some(c) = key_iter.next() {
|
||||
if *c >= b'a' && *c <= b'z' {
|
||||
buffer[index] = *c ^ b' ';
|
||||
index += 1;
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
while let Some(c) = key_iter.next() {
|
||||
buffer[index] = *c;
|
||||
index += 1;
|
||||
if *c == b'-' {
|
||||
if let Some(c) = key_iter.next() {
|
||||
if *c >= b'a' && *c <= b'z' {
|
||||
buffer[index] = *c ^ b' ';
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -371,7 +371,7 @@ impl MessageBody for String {
|
|||
pub struct BodyStream<S: Unpin, E> {
|
||||
#[pin]
|
||||
stream: S,
|
||||
_t: PhantomData<E>,
|
||||
_phantom: PhantomData<E>,
|
||||
}
|
||||
|
||||
impl<S, E> BodyStream<S, E>
|
||||
|
@ -382,7 +382,7 @@ where
|
|||
pub fn new(stream: S) -> Self {
|
||||
BodyStream {
|
||||
stream,
|
||||
_t: PhantomData,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ use crate::{ConnectCallback, Extensions};
|
|||
///
|
||||
/// This type can be used to construct an instance of [`HttpService`] through a
|
||||
/// builder-like pattern.
|
||||
pub struct HttpServiceBuilder<T, S, X = ExpectHandler, U = UpgradeHandler<T>> {
|
||||
pub struct HttpServiceBuilder<T, S, X = ExpectHandler, U = UpgradeHandler> {
|
||||
keep_alive: KeepAlive,
|
||||
client_timeout: u64,
|
||||
client_disconnect: u64,
|
||||
|
@ -28,15 +28,15 @@ pub struct HttpServiceBuilder<T, S, X = ExpectHandler, U = UpgradeHandler<T>> {
|
|||
expect: X,
|
||||
upgrade: Option<U>,
|
||||
on_connect_ext: Option<Rc<ConnectCallback<T>>>,
|
||||
_t: PhantomData<(T, S)>,
|
||||
_phantom: PhantomData<S>,
|
||||
}
|
||||
|
||||
impl<T, S> HttpServiceBuilder<T, S, ExpectHandler, UpgradeHandler<T>>
|
||||
impl<T, S> HttpServiceBuilder<T, S, ExpectHandler, UpgradeHandler>
|
||||
where
|
||||
S: ServiceFactory<Config = (), Request = Request>,
|
||||
S: ServiceFactory<Request, Config = ()>,
|
||||
S::Error: Into<Error> + 'static,
|
||||
S::InitError: fmt::Debug,
|
||||
<S::Service as Service>::Future: 'static,
|
||||
<S::Service as Service<Request>>::Future: 'static,
|
||||
{
|
||||
/// Create instance of `ServiceConfigBuilder`
|
||||
pub fn new() -> Self {
|
||||
|
@ -49,25 +49,25 @@ where
|
|||
expect: ExpectHandler,
|
||||
upgrade: None,
|
||||
on_connect_ext: None,
|
||||
_t: PhantomData,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, S, X, U> HttpServiceBuilder<T, S, X, U>
|
||||
where
|
||||
S: ServiceFactory<Config = (), Request = Request>,
|
||||
S: ServiceFactory<Request, Config = ()>,
|
||||
S::Error: Into<Error> + 'static,
|
||||
S::InitError: fmt::Debug,
|
||||
<S::Service as Service>::Future: 'static,
|
||||
X: ServiceFactory<Config = (), Request = Request, Response = Request>,
|
||||
<S::Service as Service<Request>>::Future: 'static,
|
||||
X: ServiceFactory<Request, Config = (), Response = Request>,
|
||||
X::Error: Into<Error>,
|
||||
X::InitError: fmt::Debug,
|
||||
<X::Service as Service>::Future: 'static,
|
||||
U: ServiceFactory<Config = (), Request = (Request, Framed<T, Codec>), Response = ()>,
|
||||
<X::Service as Service<Request>>::Future: 'static,
|
||||
U: ServiceFactory<(Request, Framed<T, Codec>), Config = (), Response = ()>,
|
||||
U::Error: fmt::Display,
|
||||
U::InitError: fmt::Debug,
|
||||
<U::Service as Service>::Future: 'static,
|
||||
<U::Service as Service<(Request, Framed<T, Codec>)>>::Future: 'static,
|
||||
{
|
||||
/// Set server keep-alive setting.
|
||||
///
|
||||
|
@ -123,11 +123,11 @@ where
|
|||
/// request will be forwarded to main service.
|
||||
pub fn expect<F, X1>(self, expect: F) -> HttpServiceBuilder<T, S, X1, U>
|
||||
where
|
||||
F: IntoServiceFactory<X1>,
|
||||
X1: ServiceFactory<Config = (), Request = Request, Response = Request>,
|
||||
F: IntoServiceFactory<X1, Request>,
|
||||
X1: ServiceFactory<Request, Config = (), Response = Request>,
|
||||
X1::Error: Into<Error>,
|
||||
X1::InitError: fmt::Debug,
|
||||
<X1::Service as Service>::Future: 'static,
|
||||
<X1::Service as Service<Request>>::Future: 'static,
|
||||
{
|
||||
HttpServiceBuilder {
|
||||
keep_alive: self.keep_alive,
|
||||
|
@ -138,7 +138,7 @@ where
|
|||
expect: expect.into_factory(),
|
||||
upgrade: self.upgrade,
|
||||
on_connect_ext: self.on_connect_ext,
|
||||
_t: PhantomData,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -148,15 +148,11 @@ where
|
|||
/// and this service get called with original request and framed object.
|
||||
pub fn upgrade<F, U1>(self, upgrade: F) -> HttpServiceBuilder<T, S, X, U1>
|
||||
where
|
||||
F: IntoServiceFactory<U1>,
|
||||
U1: ServiceFactory<
|
||||
Config = (),
|
||||
Request = (Request, Framed<T, Codec>),
|
||||
Response = (),
|
||||
>,
|
||||
F: IntoServiceFactory<U1, (Request, Framed<T, Codec>)>,
|
||||
U1: ServiceFactory<(Request, Framed<T, Codec>), Config = (), Response = ()>,
|
||||
U1::Error: fmt::Display,
|
||||
U1::InitError: fmt::Debug,
|
||||
<U1::Service as Service>::Future: 'static,
|
||||
<U1::Service as Service<(Request, Framed<T, Codec>)>>::Future: 'static,
|
||||
{
|
||||
HttpServiceBuilder {
|
||||
keep_alive: self.keep_alive,
|
||||
|
@ -167,7 +163,7 @@ where
|
|||
expect: self.expect,
|
||||
upgrade: Some(upgrade.into_factory()),
|
||||
on_connect_ext: self.on_connect_ext,
|
||||
_t: PhantomData,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -188,7 +184,7 @@ where
|
|||
pub fn h1<F, B>(self, service: F) -> H1Service<T, S, B, X, U>
|
||||
where
|
||||
B: MessageBody,
|
||||
F: IntoServiceFactory<S>,
|
||||
F: IntoServiceFactory<S, Request>,
|
||||
S::Error: Into<Error>,
|
||||
S::InitError: fmt::Debug,
|
||||
S::Response: Into<Response<B>>,
|
||||
|
@ -211,11 +207,11 @@ where
|
|||
pub fn h2<F, B>(self, service: F) -> H2Service<T, S, B>
|
||||
where
|
||||
B: MessageBody + 'static,
|
||||
F: IntoServiceFactory<S>,
|
||||
F: IntoServiceFactory<S, Request>,
|
||||
S::Error: Into<Error> + 'static,
|
||||
S::InitError: fmt::Debug,
|
||||
S::Response: Into<Response<B>> + 'static,
|
||||
<S::Service as Service>::Future: 'static,
|
||||
<S::Service as Service<Request>>::Future: 'static,
|
||||
{
|
||||
let cfg = ServiceConfig::new(
|
||||
self.keep_alive,
|
||||
|
@ -233,11 +229,11 @@ where
|
|||
pub fn finish<F, B>(self, service: F) -> HttpService<T, S, B, X, U>
|
||||
where
|
||||
B: MessageBody + 'static,
|
||||
F: IntoServiceFactory<S>,
|
||||
F: IntoServiceFactory<S, Request>,
|
||||
S::Error: Into<Error> + 'static,
|
||||
S::InitError: fmt::Debug,
|
||||
S::Response: Into<Response<B>> + 'static,
|
||||
<S::Service as Service>::Future: 'static,
|
||||
<S::Service as Service<Request>>::Future: 'static,
|
||||
{
|
||||
let cfg = ServiceConfig::new(
|
||||
self.keep_alive,
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
use std::future::Future;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
use std::{fmt, io, mem, time};
|
||||
use std::{fmt, io, time};
|
||||
|
||||
use actix_codec::{AsyncRead, AsyncWrite, Framed};
|
||||
use bytes::{Buf, Bytes};
|
||||
use actix_codec::{AsyncRead, AsyncWrite, Framed, ReadBuf};
|
||||
use bytes::Bytes;
|
||||
use futures_util::future::{err, Either, FutureExt, LocalBoxFuture, Ready};
|
||||
use h2::client::SendRequest;
|
||||
use pin_project::pin_project;
|
||||
|
@ -223,23 +223,13 @@ where
|
|||
fn poll_read(
|
||||
self: Pin<&mut Self>,
|
||||
cx: &mut Context<'_>,
|
||||
buf: &mut [u8],
|
||||
) -> Poll<io::Result<usize>> {
|
||||
buf: &mut ReadBuf<'_>,
|
||||
) -> Poll<io::Result<()>> {
|
||||
match self.project() {
|
||||
EitherIoProj::A(val) => val.poll_read(cx, buf),
|
||||
EitherIoProj::B(val) => val.poll_read(cx, buf),
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn prepare_uninitialized_buffer(
|
||||
&self,
|
||||
buf: &mut [mem::MaybeUninit<u8>],
|
||||
) -> bool {
|
||||
match self {
|
||||
EitherIo::A(ref val) => val.prepare_uninitialized_buffer(buf),
|
||||
EitherIo::B(ref val) => val.prepare_uninitialized_buffer(buf),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, B> AsyncWrite for EitherIo<A, B>
|
||||
|
@ -274,18 +264,4 @@ where
|
|||
EitherIoProj::B(val) => val.poll_shutdown(cx),
|
||||
}
|
||||
}
|
||||
|
||||
fn poll_write_buf<U: Buf>(
|
||||
self: Pin<&mut Self>,
|
||||
cx: &mut Context<'_>,
|
||||
buf: &mut U,
|
||||
) -> Poll<Result<usize, io::Error>>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
match self.project() {
|
||||
EitherIoProj::A(val) => val.poll_write_buf(cx, buf),
|
||||
EitherIoProj::B(val) => val.poll_write_buf(cx, buf),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,11 +3,11 @@ use std::marker::PhantomData;
|
|||
use std::time::Duration;
|
||||
|
||||
use actix_codec::{AsyncRead, AsyncWrite};
|
||||
use actix_connect::{
|
||||
use actix_rt::net::TcpStream;
|
||||
use actix_service::{apply_fn, Service, ServiceExt};
|
||||
use actix_tls::connect::{
|
||||
default_connector, Connect as TcpConnect, Connection as TcpConnection,
|
||||
};
|
||||
use actix_rt::net::TcpStream;
|
||||
use actix_service::{apply_fn, Service};
|
||||
use actix_utils::timeout::{TimeoutError, TimeoutService};
|
||||
use http::Uri;
|
||||
|
||||
|
@ -18,10 +18,10 @@ use super::pool::{ConnectionPool, Protocol};
|
|||
use super::Connect;
|
||||
|
||||
#[cfg(feature = "openssl")]
|
||||
use actix_connect::ssl::openssl::SslConnector as OpensslConnector;
|
||||
use actix_tls::connect::ssl::openssl::SslConnector as OpensslConnector;
|
||||
|
||||
#[cfg(feature = "rustls")]
|
||||
use actix_connect::ssl::rustls::ClientConfig;
|
||||
use actix_tls::connect::ssl::rustls::ClientConfig;
|
||||
#[cfg(feature = "rustls")]
|
||||
use std::sync::Arc;
|
||||
|
||||
|
@ -52,7 +52,7 @@ pub struct Connector<T, U> {
|
|||
config: ConnectorConfig,
|
||||
#[allow(dead_code)]
|
||||
ssl: SslConnector,
|
||||
_t: PhantomData<U>,
|
||||
_phantom: PhantomData<U>,
|
||||
}
|
||||
|
||||
trait Io: AsyncRead + AsyncWrite + Unpin {}
|
||||
|
@ -62,9 +62,9 @@ impl Connector<(), ()> {
|
|||
#[allow(clippy::new_ret_no_self, clippy::let_unit_value)]
|
||||
pub fn new() -> Connector<
|
||||
impl Service<
|
||||
Request = TcpConnect<Uri>,
|
||||
TcpConnect<Uri>,
|
||||
Response = TcpConnection<Uri, TcpStream>,
|
||||
Error = actix_connect::ConnectError,
|
||||
Error = actix_tls::connect::ConnectError,
|
||||
> + Clone,
|
||||
TcpStream,
|
||||
> {
|
||||
|
@ -72,14 +72,14 @@ impl Connector<(), ()> {
|
|||
ssl: Self::build_ssl(vec![b"h2".to_vec(), b"http/1.1".to_vec()]),
|
||||
connector: default_connector(),
|
||||
config: ConnectorConfig::default(),
|
||||
_t: PhantomData,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
// Build Ssl connector with openssl, based on supplied alpn protocols
|
||||
#[cfg(feature = "openssl")]
|
||||
fn build_ssl(protocols: Vec<Vec<u8>>) -> SslConnector {
|
||||
use actix_connect::ssl::openssl::SslMethod;
|
||||
use actix_tls::connect::ssl::openssl::SslMethod;
|
||||
use bytes::{BufMut, BytesMut};
|
||||
|
||||
let mut alpn = BytesMut::with_capacity(20);
|
||||
|
@ -102,7 +102,7 @@ impl Connector<(), ()> {
|
|||
config.set_protocols(&protocols);
|
||||
config
|
||||
.root_store
|
||||
.add_server_trust_anchors(&actix_tls::rustls::TLS_SERVER_ROOTS);
|
||||
.add_server_trust_anchors(&actix_tls::accept::rustls::TLS_SERVER_ROOTS);
|
||||
SslConnector::Rustls(Arc::new(config))
|
||||
}
|
||||
|
||||
|
@ -117,16 +117,16 @@ impl<T, U> Connector<T, U> {
|
|||
where
|
||||
U1: AsyncRead + AsyncWrite + Unpin + fmt::Debug,
|
||||
T1: Service<
|
||||
Request = TcpConnect<Uri>,
|
||||
TcpConnect<Uri>,
|
||||
Response = TcpConnection<Uri, U1>,
|
||||
Error = actix_connect::ConnectError,
|
||||
Error = actix_tls::connect::ConnectError,
|
||||
> + Clone,
|
||||
{
|
||||
Connector {
|
||||
connector,
|
||||
config: self.config,
|
||||
ssl: self.ssl,
|
||||
_t: PhantomData,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -135,9 +135,9 @@ impl<T, U> Connector<T, U>
|
|||
where
|
||||
U: AsyncRead + AsyncWrite + Unpin + fmt::Debug + 'static,
|
||||
T: Service<
|
||||
Request = TcpConnect<Uri>,
|
||||
TcpConnect<Uri>,
|
||||
Response = TcpConnection<Uri, U>,
|
||||
Error = actix_connect::ConnectError,
|
||||
Error = actix_tls::connect::ConnectError,
|
||||
> + Clone
|
||||
+ 'static,
|
||||
{
|
||||
|
@ -241,8 +241,8 @@ where
|
|||
/// its combinator chain.
|
||||
pub fn finish(
|
||||
self,
|
||||
) -> impl Service<Request = Connect, Response = impl Connection, Error = ConnectError>
|
||||
+ Clone {
|
||||
) -> impl Service<Connect, Response = impl Connection, Error = ConnectError> + Clone
|
||||
{
|
||||
#[cfg(not(any(feature = "openssl", feature = "rustls")))]
|
||||
{
|
||||
let connector = TimeoutService::new(
|
||||
|
@ -268,11 +268,11 @@ where
|
|||
#[cfg(any(feature = "openssl", feature = "rustls"))]
|
||||
{
|
||||
const H2: &[u8] = b"h2";
|
||||
#[cfg(feature = "openssl")]
|
||||
use actix_connect::ssl::openssl::OpensslConnector;
|
||||
#[cfg(feature = "rustls")]
|
||||
use actix_connect::ssl::rustls::{RustlsConnector, Session};
|
||||
use actix_service::{boxed::service, pipeline};
|
||||
#[cfg(feature = "openssl")]
|
||||
use actix_tls::connect::ssl::openssl::OpensslConnector;
|
||||
#[cfg(feature = "rustls")]
|
||||
use actix_tls::connect::ssl::rustls::{RustlsConnector, Session};
|
||||
|
||||
let ssl_service = TimeoutService::new(
|
||||
self.config.timeout,
|
||||
|
@ -363,8 +363,7 @@ mod connect_impl {
|
|||
pub(crate) struct InnerConnector<T, Io>
|
||||
where
|
||||
Io: AsyncRead + AsyncWrite + Unpin + 'static,
|
||||
T: Service<Request = Connect, Response = (Io, Protocol), Error = ConnectError>
|
||||
+ 'static,
|
||||
T: Service<Connect, Response = (Io, Protocol), Error = ConnectError> + 'static,
|
||||
{
|
||||
pub(crate) tcp_pool: ConnectionPool<T, Io>,
|
||||
}
|
||||
|
@ -372,8 +371,7 @@ mod connect_impl {
|
|||
impl<T, Io> Clone for InnerConnector<T, Io>
|
||||
where
|
||||
Io: AsyncRead + AsyncWrite + Unpin + 'static,
|
||||
T: Service<Request = Connect, Response = (Io, Protocol), Error = ConnectError>
|
||||
+ 'static,
|
||||
T: Service<Connect, Response = (Io, Protocol), Error = ConnectError> + 'static,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
InnerConnector {
|
||||
|
@ -382,17 +380,15 @@ mod connect_impl {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T, Io> Service for InnerConnector<T, Io>
|
||||
impl<T, Io> Service<Connect> for InnerConnector<T, Io>
|
||||
where
|
||||
Io: AsyncRead + AsyncWrite + Unpin + 'static,
|
||||
T: Service<Request = Connect, Response = (Io, Protocol), Error = ConnectError>
|
||||
+ 'static,
|
||||
T: Service<Connect, Response = (Io, Protocol), Error = ConnectError> + 'static,
|
||||
{
|
||||
type Request = Connect;
|
||||
type Response = IoConnection<Io>;
|
||||
type Error = ConnectError;
|
||||
type Future = Either<
|
||||
<ConnectionPool<T, Io> as Service>::Future,
|
||||
<ConnectionPool<T, Io> as Service<Connect>>::Future,
|
||||
Ready<Result<IoConnection<Io>, ConnectError>>,
|
||||
>;
|
||||
|
||||
|
@ -428,8 +424,8 @@ mod connect_impl {
|
|||
where
|
||||
Io1: AsyncRead + AsyncWrite + Unpin + 'static,
|
||||
Io2: AsyncRead + AsyncWrite + Unpin + 'static,
|
||||
T1: Service<Request = Connect, Response = (Io1, Protocol), Error = ConnectError>,
|
||||
T2: Service<Request = Connect, Response = (Io2, Protocol), Error = ConnectError>,
|
||||
T1: Service<Connect, Response = (Io1, Protocol), Error = ConnectError>,
|
||||
T2: Service<Connect, Response = (Io2, Protocol), Error = ConnectError>,
|
||||
{
|
||||
pub(crate) tcp_pool: ConnectionPool<T1, Io1>,
|
||||
pub(crate) ssl_pool: ConnectionPool<T2, Io2>,
|
||||
|
@ -439,10 +435,8 @@ mod connect_impl {
|
|||
where
|
||||
Io1: AsyncRead + AsyncWrite + Unpin + 'static,
|
||||
Io2: AsyncRead + AsyncWrite + Unpin + 'static,
|
||||
T1: Service<Request = Connect, Response = (Io1, Protocol), Error = ConnectError>
|
||||
+ 'static,
|
||||
T2: Service<Request = Connect, Response = (Io2, Protocol), Error = ConnectError>
|
||||
+ 'static,
|
||||
T1: Service<Connect, Response = (Io1, Protocol), Error = ConnectError> + 'static,
|
||||
T2: Service<Connect, Response = (Io2, Protocol), Error = ConnectError> + 'static,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
InnerConnector {
|
||||
|
@ -452,16 +446,13 @@ mod connect_impl {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T1, T2, Io1, Io2> Service for InnerConnector<T1, T2, Io1, Io2>
|
||||
impl<T1, T2, Io1, Io2> Service<Connect> for InnerConnector<T1, T2, Io1, Io2>
|
||||
where
|
||||
Io1: AsyncRead + AsyncWrite + Unpin + 'static,
|
||||
Io2: AsyncRead + AsyncWrite + Unpin + 'static,
|
||||
T1: Service<Request = Connect, Response = (Io1, Protocol), Error = ConnectError>
|
||||
+ 'static,
|
||||
T2: Service<Request = Connect, Response = (Io2, Protocol), Error = ConnectError>
|
||||
+ 'static,
|
||||
T1: Service<Connect, Response = (Io1, Protocol), Error = ConnectError> + 'static,
|
||||
T2: Service<Connect, Response = (Io2, Protocol), Error = ConnectError> + 'static,
|
||||
{
|
||||
type Request = Connect;
|
||||
type Response = EitherConnection<Io1, Io2>;
|
||||
type Error = ConnectError;
|
||||
type Future = Either<
|
||||
|
@ -477,11 +468,11 @@ mod connect_impl {
|
|||
match req.uri.scheme_str() {
|
||||
Some("https") | Some("wss") => Either::Right(InnerConnectorResponseB {
|
||||
fut: self.ssl_pool.call(req),
|
||||
_t: PhantomData,
|
||||
_phantom: PhantomData,
|
||||
}),
|
||||
_ => Either::Left(InnerConnectorResponseA {
|
||||
fut: self.tcp_pool.call(req),
|
||||
_t: PhantomData,
|
||||
_phantom: PhantomData,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
@ -491,18 +482,16 @@ mod connect_impl {
|
|||
pub(crate) struct InnerConnectorResponseA<T, Io1, Io2>
|
||||
where
|
||||
Io1: AsyncRead + AsyncWrite + Unpin + 'static,
|
||||
T: Service<Request = Connect, Response = (Io1, Protocol), Error = ConnectError>
|
||||
+ 'static,
|
||||
T: Service<Connect, Response = (Io1, Protocol), Error = ConnectError> + 'static,
|
||||
{
|
||||
#[pin]
|
||||
fut: <ConnectionPool<T, Io1> as Service>::Future,
|
||||
_t: PhantomData<Io2>,
|
||||
fut: <ConnectionPool<T, Io1> as Service<Connect>>::Future,
|
||||
_phantom: PhantomData<Io2>,
|
||||
}
|
||||
|
||||
impl<T, Io1, Io2> Future for InnerConnectorResponseA<T, Io1, Io2>
|
||||
where
|
||||
T: Service<Request = Connect, Response = (Io1, Protocol), Error = ConnectError>
|
||||
+ 'static,
|
||||
T: Service<Connect, Response = (Io1, Protocol), Error = ConnectError> + 'static,
|
||||
Io1: AsyncRead + AsyncWrite + Unpin + 'static,
|
||||
Io2: AsyncRead + AsyncWrite + Unpin + 'static,
|
||||
{
|
||||
|
@ -520,18 +509,16 @@ mod connect_impl {
|
|||
pub(crate) struct InnerConnectorResponseB<T, Io1, Io2>
|
||||
where
|
||||
Io2: AsyncRead + AsyncWrite + Unpin + 'static,
|
||||
T: Service<Request = Connect, Response = (Io2, Protocol), Error = ConnectError>
|
||||
+ 'static,
|
||||
T: Service<Connect, Response = (Io2, Protocol), Error = ConnectError> + 'static,
|
||||
{
|
||||
#[pin]
|
||||
fut: <ConnectionPool<T, Io2> as Service>::Future,
|
||||
_t: PhantomData<Io1>,
|
||||
fut: <ConnectionPool<T, Io2> as Service<Connect>>::Future,
|
||||
_phantom: PhantomData<Io1>,
|
||||
}
|
||||
|
||||
impl<T, Io1, Io2> Future for InnerConnectorResponseB<T, Io1, Io2>
|
||||
where
|
||||
T: Service<Request = Connect, Response = (Io2, Protocol), Error = ConnectError>
|
||||
+ 'static,
|
||||
T: Service<Connect, Response = (Io2, Protocol), Error = ConnectError> + 'static,
|
||||
Io1: AsyncRead + AsyncWrite + Unpin + 'static,
|
||||
Io2: AsyncRead + AsyncWrite + Unpin + 'static,
|
||||
{
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
use std::io;
|
||||
|
||||
use actix_connect::resolver::ResolveError;
|
||||
use actix_tls::connect::resolver::ResolveError;
|
||||
use derive_more::{Display, From};
|
||||
|
||||
#[cfg(feature = "openssl")]
|
||||
use actix_connect::ssl::openssl::{HandshakeError, SslError};
|
||||
use actix_tls::accept::openssl::SslError;
|
||||
|
||||
use crate::error::{Error, ParseError, ResponseError};
|
||||
use crate::http::{Error as HttpError, StatusCode};
|
||||
|
@ -21,11 +21,6 @@ pub enum ConnectError {
|
|||
#[display(fmt = "{}", _0)]
|
||||
SslError(SslError),
|
||||
|
||||
/// SSL Handshake error
|
||||
#[cfg(feature = "openssl")]
|
||||
#[display(fmt = "{}", _0)]
|
||||
SslHandshakeError(String),
|
||||
|
||||
/// Failed to resolve the hostname
|
||||
#[display(fmt = "Failed resolving hostname: {}", _0)]
|
||||
Resolver(ResolveError),
|
||||
|
@ -57,25 +52,18 @@ pub enum ConnectError {
|
|||
|
||||
impl std::error::Error for ConnectError {}
|
||||
|
||||
impl From<actix_connect::ConnectError> for ConnectError {
|
||||
fn from(err: actix_connect::ConnectError) -> ConnectError {
|
||||
impl From<actix_tls::connect::ConnectError> for ConnectError {
|
||||
fn from(err: actix_tls::connect::ConnectError) -> ConnectError {
|
||||
match err {
|
||||
actix_connect::ConnectError::Resolver(e) => ConnectError::Resolver(e),
|
||||
actix_connect::ConnectError::NoRecords => ConnectError::NoRecords,
|
||||
actix_connect::ConnectError::InvalidInput => panic!(),
|
||||
actix_connect::ConnectError::Unresolved => ConnectError::Unresolved,
|
||||
actix_connect::ConnectError::Io(e) => ConnectError::Io(e),
|
||||
actix_tls::connect::ConnectError::Resolver(e) => ConnectError::Resolver(e),
|
||||
actix_tls::connect::ConnectError::NoRecords => ConnectError::NoRecords,
|
||||
actix_tls::connect::ConnectError::InvalidInput => panic!(),
|
||||
actix_tls::connect::ConnectError::Unresolved => ConnectError::Unresolved,
|
||||
actix_tls::connect::ConnectError::Io(e) => ConnectError::Io(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "openssl")]
|
||||
impl<T: std::fmt::Debug> From<HandshakeError<T>> for ConnectError {
|
||||
fn from(err: HandshakeError<T>) -> ConnectError {
|
||||
ConnectError::SslHandshakeError(format!("{:?}", err))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Display, From)]
|
||||
pub enum InvalidUrl {
|
||||
#[display(fmt = "Missing url scheme")]
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
use std::io::Write;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
use std::{io, mem, time};
|
||||
use std::{io, time};
|
||||
|
||||
use actix_codec::{AsyncRead, AsyncWrite, Framed};
|
||||
use bytes::buf::BufMutExt;
|
||||
use actix_codec::{AsyncRead, AsyncWrite, Framed, ReadBuf};
|
||||
use bytes::buf::BufMut;
|
||||
use bytes::{Bytes, BytesMut};
|
||||
use futures_core::Stream;
|
||||
use futures_util::future::poll_fn;
|
||||
|
@ -72,7 +72,7 @@ where
|
|||
|
||||
// send request body
|
||||
match body.size() {
|
||||
BodySize::None | BodySize::Empty | BodySize::Sized(0) => (),
|
||||
BodySize::None | BodySize::Empty | BodySize::Sized(0) => {}
|
||||
_ => send_body(body, Pin::new(&mut framed_inner)).await?,
|
||||
};
|
||||
|
||||
|
@ -204,18 +204,11 @@ where
|
|||
}
|
||||
|
||||
impl<T: AsyncRead + AsyncWrite + Unpin + 'static> AsyncRead for H1Connection<T> {
|
||||
unsafe fn prepare_uninitialized_buffer(
|
||||
&self,
|
||||
buf: &mut [mem::MaybeUninit<u8>],
|
||||
) -> bool {
|
||||
self.io.as_ref().unwrap().prepare_uninitialized_buffer(buf)
|
||||
}
|
||||
|
||||
fn poll_read(
|
||||
mut self: Pin<&mut Self>,
|
||||
cx: &mut Context<'_>,
|
||||
buf: &mut [u8],
|
||||
) -> Poll<io::Result<usize>> {
|
||||
buf: &mut ReadBuf<'_>,
|
||||
) -> Poll<io::Result<()>> {
|
||||
Pin::new(&mut self.io.as_mut().unwrap()).poll_read(cx, buf)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -89,7 +89,7 @@ where
|
|||
CONNECTION | TRANSFER_ENCODING => continue, // http2 specific
|
||||
CONTENT_LENGTH if skip_len => continue,
|
||||
// DATE => has_date = true,
|
||||
_ => (),
|
||||
_ => {}
|
||||
}
|
||||
req.headers_mut().append(key, value.clone());
|
||||
}
|
||||
|
|
|
@ -6,8 +6,8 @@ use std::rc::Rc;
|
|||
use std::task::{Context, Poll};
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use actix_codec::{AsyncRead, AsyncWrite};
|
||||
use actix_rt::time::{delay_for, Delay};
|
||||
use actix_codec::{AsyncRead, AsyncWrite, ReadBuf};
|
||||
use actix_rt::time::{sleep, Sleep};
|
||||
use actix_service::Service;
|
||||
use actix_utils::task::LocalWaker;
|
||||
use bytes::Bytes;
|
||||
|
@ -50,8 +50,7 @@ pub(crate) struct ConnectionPool<T, Io: 'static>(Rc<RefCell<T>>, Rc<RefCell<Inne
|
|||
impl<T, Io> ConnectionPool<T, Io>
|
||||
where
|
||||
Io: AsyncRead + AsyncWrite + Unpin + 'static,
|
||||
T: Service<Request = Connect, Response = (Io, Protocol), Error = ConnectError>
|
||||
+ 'static,
|
||||
T: Service<Connect, Response = (Io, Protocol), Error = ConnectError> + 'static,
|
||||
{
|
||||
pub(crate) fn new(connector: T, config: ConnectorConfig) -> Self {
|
||||
let connector_rc = Rc::new(RefCell::new(connector));
|
||||
|
@ -90,13 +89,11 @@ impl<T, Io> Drop for ConnectionPool<T, Io> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T, Io> Service for ConnectionPool<T, Io>
|
||||
impl<T, Io> Service<Connect> for ConnectionPool<T, Io>
|
||||
where
|
||||
Io: AsyncRead + AsyncWrite + Unpin + 'static,
|
||||
T: Service<Request = Connect, Response = (Io, Protocol), Error = ConnectError>
|
||||
+ 'static,
|
||||
T: Service<Connect, Response = (Io, Protocol), Error = ConnectError> + 'static,
|
||||
{
|
||||
type Request = Connect;
|
||||
type Response = IoConnection<Io>;
|
||||
type Error = ConnectError;
|
||||
type Future = LocalBoxFuture<'static, Result<IoConnection<Io>, ConnectError>>;
|
||||
|
@ -334,10 +331,11 @@ where
|
|||
} else {
|
||||
let mut io = conn.io;
|
||||
let mut buf = [0; 2];
|
||||
let mut read_buf = ReadBuf::new(&mut buf);
|
||||
if let ConnectionType::H1(ref mut s) = io {
|
||||
match Pin::new(s).poll_read(cx, &mut buf) {
|
||||
Poll::Pending => (),
|
||||
Poll::Ready(Ok(n)) if n > 0 => {
|
||||
match Pin::new(s).poll_read(cx, &mut read_buf) {
|
||||
Poll::Pending => {}
|
||||
Poll::Ready(Ok(())) if !read_buf.filled().is_empty() => {
|
||||
if let Some(timeout) = self.config.disconnect_timeout {
|
||||
if let ConnectionType::H1(io) = io {
|
||||
actix_rt::spawn(CloseConnection::new(
|
||||
|
@ -387,9 +385,11 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
#[pin_project::pin_project]
|
||||
struct CloseConnection<T> {
|
||||
io: T,
|
||||
timeout: Delay,
|
||||
#[pin]
|
||||
timeout: Sleep,
|
||||
}
|
||||
|
||||
impl<T> CloseConnection<T>
|
||||
|
@ -399,7 +399,7 @@ where
|
|||
fn new(io: T, timeout: Duration) -> Self {
|
||||
CloseConnection {
|
||||
io,
|
||||
timeout: delay_for(timeout),
|
||||
timeout: sleep(timeout),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -411,11 +411,11 @@ where
|
|||
type Output = ();
|
||||
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
|
||||
let this = self.get_mut();
|
||||
let this = self.project();
|
||||
|
||||
match Pin::new(&mut this.timeout).poll(cx) {
|
||||
match this.timeout.poll(cx) {
|
||||
Poll::Ready(_) => Poll::Ready(()),
|
||||
Poll::Pending => match Pin::new(&mut this.io).poll_shutdown(cx) {
|
||||
Poll::Pending => match Pin::new(this.io).poll_shutdown(cx) {
|
||||
Poll::Ready(_) => Poll::Ready(()),
|
||||
Poll::Pending => Poll::Pending,
|
||||
},
|
||||
|
@ -435,7 +435,7 @@ where
|
|||
impl<T, Io> Future for ConnectorPoolSupport<T, Io>
|
||||
where
|
||||
Io: AsyncRead + AsyncWrite + Unpin + 'static,
|
||||
T: Service<Request = Connect, Response = (Io, Protocol), Error = ConnectError>,
|
||||
T: Service<Connect, Response = (Io, Protocol), Error = ConnectError>,
|
||||
T::Future: 'static,
|
||||
{
|
||||
type Output = ();
|
||||
|
|
|
@ -10,22 +10,21 @@ use actix_service::Service;
|
|||
/// CloneableService might panic with some creative use of thread local storage.
|
||||
/// See https://github.com/actix/actix-web/issues/1295 for example
|
||||
#[doc(hidden)]
|
||||
pub(crate) struct CloneableService<T: Service>(Rc<RefCell<T>>);
|
||||
pub(crate) struct CloneableService<T>(Rc<RefCell<T>>);
|
||||
|
||||
impl<T: Service> CloneableService<T> {
|
||||
impl<T> CloneableService<T> {
|
||||
pub(crate) fn new(service: T) -> Self {
|
||||
Self(Rc::new(RefCell::new(service)))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Service> Clone for CloneableService<T> {
|
||||
impl<T> Clone for CloneableService<T> {
|
||||
fn clone(&self) -> Self {
|
||||
Self(self.0.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Service> Service for CloneableService<T> {
|
||||
type Request = T::Request;
|
||||
impl<T: Service<Req>, Req> Service<Req> for CloneableService<T> {
|
||||
type Response = T::Response;
|
||||
type Error = T::Error;
|
||||
type Future = T::Future;
|
||||
|
@ -34,7 +33,7 @@ impl<T: Service> Service for CloneableService<T> {
|
|||
self.0.borrow_mut().poll_ready(cx)
|
||||
}
|
||||
|
||||
fn call(&mut self, req: T::Request) -> Self::Future {
|
||||
fn call(&mut self, req: Req) -> Self::Future {
|
||||
self.0.borrow_mut().call(req)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ use std::rc::Rc;
|
|||
use std::time::Duration;
|
||||
use std::{fmt, net};
|
||||
|
||||
use actix_rt::time::{delay_for, delay_until, Delay, Instant};
|
||||
use actix_rt::time::{sleep, sleep_until, Instant, Sleep};
|
||||
use bytes::BytesMut;
|
||||
use futures_util::{future, FutureExt};
|
||||
use time::OffsetDateTime;
|
||||
|
@ -121,10 +121,10 @@ impl ServiceConfig {
|
|||
|
||||
#[inline]
|
||||
/// Client timeout for first request.
|
||||
pub fn client_timer(&self) -> Option<Delay> {
|
||||
pub fn client_timer(&self) -> Option<Sleep> {
|
||||
let delay_time = self.0.client_timeout;
|
||||
if delay_time != 0 {
|
||||
Some(delay_until(
|
||||
Some(sleep_until(
|
||||
self.0.timer.now() + Duration::from_millis(delay_time),
|
||||
))
|
||||
} else {
|
||||
|
@ -154,9 +154,9 @@ impl ServiceConfig {
|
|||
|
||||
#[inline]
|
||||
/// Return keep-alive timer delay is configured.
|
||||
pub fn keep_alive_timer(&self) -> Option<Delay> {
|
||||
pub fn keep_alive_timer(&self) -> Option<Sleep> {
|
||||
if let Some(ka) = self.0.keep_alive {
|
||||
Some(delay_until(self.0.timer.now() + ka))
|
||||
Some(sleep_until(self.0.timer.now() + ka))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
@ -266,7 +266,7 @@ impl DateService {
|
|||
|
||||
// periodic date update
|
||||
let s = self.clone();
|
||||
actix_rt::spawn(delay_for(Duration::from_millis(500)).then(move |_| {
|
||||
actix_rt::spawn(sleep(Duration::from_millis(500)).then(move |_| {
|
||||
s.0.reset();
|
||||
future::ready(())
|
||||
}));
|
||||
|
|
|
@ -178,11 +178,7 @@ impl ResponseError for FormError {}
|
|||
|
||||
#[cfg(feature = "openssl")]
|
||||
/// `InternalServerError` for `openssl::ssl::Error`
|
||||
impl ResponseError for actix_connect::ssl::openssl::SslError {}
|
||||
|
||||
#[cfg(feature = "openssl")]
|
||||
/// `InternalServerError` for `openssl::ssl::HandshakeError`
|
||||
impl<T: std::fmt::Debug> ResponseError for actix_tls::openssl::HandshakeError<T> {}
|
||||
impl ResponseError for actix_tls::accept::openssl::SslError {}
|
||||
|
||||
/// Return `BAD_REQUEST` for `de::value::Error`
|
||||
impl ResponseError for DeError {
|
||||
|
@ -956,11 +952,6 @@ where
|
|||
/// This is supported on feature=`actors` only
|
||||
impl ResponseError for actix::MailboxError {}
|
||||
|
||||
#[cfg(feature = "actors")]
|
||||
/// `InternalServerError` for `actix::ResolverError`
|
||||
/// This is supported on feature=`actors` only
|
||||
impl ResponseError for actix::actors::resolver::ResolverError {}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
|
|
@ -137,7 +137,7 @@ pub(crate) trait MessageType: Sized {
|
|||
expect = true;
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
headers.append(name, value);
|
||||
|
@ -685,7 +685,7 @@ mod tests {
|
|||
match MessageDecoder::<Request>::default().decode($e) {
|
||||
Err(err) => match err {
|
||||
ParseError::Io(_) => unreachable!("Parse error expected"),
|
||||
_ => (),
|
||||
_ => {}
|
||||
},
|
||||
_ => unreachable!("Error expected"),
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ use std::{
|
|||
};
|
||||
|
||||
use actix_codec::{AsyncRead, AsyncWrite, Decoder, Encoder, Framed, FramedParts};
|
||||
use actix_rt::time::{delay_until, Delay, Instant};
|
||||
use actix_rt::time::{sleep_until, Instant, Sleep};
|
||||
use actix_service::Service;
|
||||
use bitflags::bitflags;
|
||||
use bytes::{Buf, BytesMut};
|
||||
|
@ -51,12 +51,12 @@ bitflags! {
|
|||
/// Dispatcher for HTTP/1.1 protocol
|
||||
pub struct Dispatcher<T, S, B, X, U>
|
||||
where
|
||||
S: Service<Request = Request>,
|
||||
S: Service<Request>,
|
||||
S::Error: Into<Error>,
|
||||
B: MessageBody,
|
||||
X: Service<Request = Request, Response = Request>,
|
||||
X: Service<Request, Response = Request>,
|
||||
X::Error: Into<Error>,
|
||||
U: Service<Request = (Request, Framed<T, Codec>), Response = ()>,
|
||||
U: Service<(Request, Framed<T, Codec>), Response = ()>,
|
||||
U::Error: fmt::Display,
|
||||
{
|
||||
#[pin]
|
||||
|
@ -69,12 +69,12 @@ where
|
|||
#[pin_project(project = DispatcherStateProj)]
|
||||
enum DispatcherState<T, S, B, X, U>
|
||||
where
|
||||
S: Service<Request = Request>,
|
||||
S: Service<Request>,
|
||||
S::Error: Into<Error>,
|
||||
B: MessageBody,
|
||||
X: Service<Request = Request, Response = Request>,
|
||||
X: Service<Request, Response = Request>,
|
||||
X::Error: Into<Error>,
|
||||
U: Service<Request = (Request, Framed<T, Codec>), Response = ()>,
|
||||
U: Service<(Request, Framed<T, Codec>), Response = ()>,
|
||||
U::Error: fmt::Display,
|
||||
{
|
||||
Normal(#[pin] InnerDispatcher<T, S, B, X, U>),
|
||||
|
@ -84,12 +84,12 @@ where
|
|||
#[pin_project(project = InnerDispatcherProj)]
|
||||
struct InnerDispatcher<T, S, B, X, U>
|
||||
where
|
||||
S: Service<Request = Request>,
|
||||
S: Service<Request>,
|
||||
S::Error: Into<Error>,
|
||||
B: MessageBody,
|
||||
X: Service<Request = Request, Response = Request>,
|
||||
X: Service<Request, Response = Request>,
|
||||
X::Error: Into<Error>,
|
||||
U: Service<Request = (Request, Framed<T, Codec>), Response = ()>,
|
||||
U: Service<(Request, Framed<T, Codec>), Response = ()>,
|
||||
U::Error: fmt::Display,
|
||||
{
|
||||
service: CloneableService<S>,
|
||||
|
@ -106,7 +106,8 @@ where
|
|||
messages: VecDeque<DispatcherMessage>,
|
||||
|
||||
ka_expire: Instant,
|
||||
ka_timer: Option<Delay>,
|
||||
#[pin]
|
||||
ka_timer: Option<Sleep>,
|
||||
|
||||
io: Option<T>,
|
||||
read_buf: BytesMut,
|
||||
|
@ -123,8 +124,8 @@ enum DispatcherMessage {
|
|||
#[pin_project(project = StateProj)]
|
||||
enum State<S, B, X>
|
||||
where
|
||||
S: Service<Request = Request>,
|
||||
X: Service<Request = Request, Response = Request>,
|
||||
S: Service<Request>,
|
||||
X: Service<Request, Response = Request>,
|
||||
B: MessageBody,
|
||||
{
|
||||
None,
|
||||
|
@ -135,8 +136,8 @@ where
|
|||
|
||||
impl<S, B, X> State<S, B, X>
|
||||
where
|
||||
S: Service<Request = Request>,
|
||||
X: Service<Request = Request, Response = Request>,
|
||||
S: Service<Request>,
|
||||
X: Service<Request, Response = Request>,
|
||||
B: MessageBody,
|
||||
{
|
||||
fn is_empty(&self) -> bool {
|
||||
|
@ -166,13 +167,13 @@ impl PartialEq for PollResponse {
|
|||
impl<T, S, B, X, U> Dispatcher<T, S, B, X, U>
|
||||
where
|
||||
T: AsyncRead + AsyncWrite + Unpin,
|
||||
S: Service<Request = Request>,
|
||||
S: Service<Request>,
|
||||
S::Error: Into<Error>,
|
||||
S::Response: Into<Response<B>>,
|
||||
B: MessageBody,
|
||||
X: Service<Request = Request, Response = Request>,
|
||||
X: Service<Request, Response = Request>,
|
||||
X::Error: Into<Error>,
|
||||
U: Service<Request = (Request, Framed<T, Codec>), Response = ()>,
|
||||
U: Service<(Request, Framed<T, Codec>), Response = ()>,
|
||||
U::Error: fmt::Display,
|
||||
{
|
||||
/// Create HTTP/1 dispatcher.
|
||||
|
@ -205,7 +206,7 @@ where
|
|||
codec: Codec,
|
||||
config: ServiceConfig,
|
||||
read_buf: BytesMut,
|
||||
timeout: Option<Delay>,
|
||||
timeout: Option<Sleep>,
|
||||
service: CloneableService<S>,
|
||||
expect: CloneableService<X>,
|
||||
upgrade: Option<CloneableService<U>>,
|
||||
|
@ -257,13 +258,13 @@ where
|
|||
impl<T, S, B, X, U> InnerDispatcher<T, S, B, X, U>
|
||||
where
|
||||
T: AsyncRead + AsyncWrite + Unpin,
|
||||
S: Service<Request = Request>,
|
||||
S: Service<Request>,
|
||||
S::Error: Into<Error>,
|
||||
S::Response: Into<Response<B>>,
|
||||
B: MessageBody,
|
||||
X: Service<Request = Request, Response = Request>,
|
||||
X: Service<Request, Response = Request>,
|
||||
X::Error: Into<Error>,
|
||||
U: Service<Request = (Request, Framed<T, Codec>), Response = ()>,
|
||||
U: Service<(Request, Framed<T, Codec>), Response = ()>,
|
||||
U::Error: fmt::Display,
|
||||
{
|
||||
fn can_read(&self, cx: &mut Context<'_>) -> bool {
|
||||
|
@ -660,7 +661,7 @@ where
|
|||
// shutdown timeout
|
||||
if this.flags.contains(Flags::SHUTDOWN) {
|
||||
if let Some(interval) = this.codec.config().client_disconnect_timer() {
|
||||
*this.ka_timer = Some(delay_until(interval));
|
||||
this.ka_timer.set(Some(sleep_until(interval)));
|
||||
} else {
|
||||
this.flags.insert(Flags::READ_DISCONNECT);
|
||||
if let Some(mut payload) = this.payload.take() {
|
||||
|
@ -673,12 +674,14 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
match Pin::new(&mut this.ka_timer.as_mut().unwrap()).poll(cx) {
|
||||
match this.ka_timer.as_mut().as_pin_mut().unwrap().poll(cx) {
|
||||
Poll::Ready(()) => {
|
||||
// if we get timeout during shutdown, drop connection
|
||||
if this.flags.contains(Flags::SHUTDOWN) {
|
||||
return Err(DispatchError::DisconnectTimeout);
|
||||
} else if this.ka_timer.as_mut().unwrap().deadline() >= *this.ka_expire {
|
||||
} else if this.ka_timer.as_mut().as_pin_mut().unwrap().deadline()
|
||||
>= *this.ka_expire
|
||||
{
|
||||
// check for any outstanding tasks
|
||||
if this.state.is_empty() && this.write_buf.is_empty() {
|
||||
if this.flags.contains(Flags::STARTED) {
|
||||
|
@ -689,9 +692,15 @@ where
|
|||
if let Some(deadline) =
|
||||
this.codec.config().client_disconnect_timer()
|
||||
{
|
||||
if let Some(mut timer) = this.ka_timer.as_mut() {
|
||||
if let Some(timer) = this.ka_timer.as_mut().as_pin_mut()
|
||||
{
|
||||
timer.reset(deadline);
|
||||
let _ = Pin::new(&mut timer).poll(cx);
|
||||
let _ = this
|
||||
.ka_timer
|
||||
.as_mut()
|
||||
.as_pin_mut()
|
||||
.unwrap()
|
||||
.poll(cx);
|
||||
}
|
||||
} else {
|
||||
// no shutdown timeout, drop socket
|
||||
|
@ -716,17 +725,18 @@ where
|
|||
} else if let Some(deadline) =
|
||||
this.codec.config().keep_alive_expire()
|
||||
{
|
||||
if let Some(mut timer) = this.ka_timer.as_mut() {
|
||||
if let Some(timer) = this.ka_timer.as_mut().as_pin_mut() {
|
||||
timer.reset(deadline);
|
||||
let _ = Pin::new(&mut timer).poll(cx);
|
||||
let _ =
|
||||
this.ka_timer.as_mut().as_pin_mut().unwrap().poll(cx);
|
||||
}
|
||||
}
|
||||
} else if let Some(mut timer) = this.ka_timer.as_mut() {
|
||||
} else if let Some(timer) = this.ka_timer.as_mut().as_pin_mut() {
|
||||
timer.reset(*this.ka_expire);
|
||||
let _ = Pin::new(&mut timer).poll(cx);
|
||||
let _ = this.ka_timer.as_mut().as_pin_mut().unwrap().poll(cx);
|
||||
}
|
||||
}
|
||||
Poll::Pending => (),
|
||||
Poll::Pending => {}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -736,13 +746,13 @@ where
|
|||
impl<T, S, B, X, U> Future for Dispatcher<T, S, B, X, U>
|
||||
where
|
||||
T: AsyncRead + AsyncWrite + Unpin,
|
||||
S: Service<Request = Request>,
|
||||
S: Service<Request>,
|
||||
S::Error: Into<Error>,
|
||||
S::Response: Into<Response<B>>,
|
||||
B: MessageBody,
|
||||
X: Service<Request = Request, Response = Request>,
|
||||
X: Service<Request, Response = Request>,
|
||||
X::Error: Into<Error>,
|
||||
U: Service<Request = (Request, Framed<T, Codec>), Response = ()>,
|
||||
U: Service<(Request, Framed<T, Codec>), Response = ()>,
|
||||
U::Error: fmt::Display,
|
||||
{
|
||||
type Output = Result<(), DispatchError>;
|
||||
|
@ -951,12 +961,12 @@ fn read<T>(
|
|||
where
|
||||
T: AsyncRead + Unpin,
|
||||
{
|
||||
Pin::new(io).poll_read_buf(cx, buf)
|
||||
actix_codec::poll_read_buf(Pin::new(io), cx, buf)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::{marker::PhantomData, str};
|
||||
use std::str;
|
||||
|
||||
use actix_service::fn_service;
|
||||
use futures_util::future::{lazy, ready};
|
||||
|
@ -985,21 +995,19 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
fn ok_service() -> impl Service<Request = Request, Response = Response, Error = Error>
|
||||
{
|
||||
fn ok_service() -> impl Service<Request, Response = Response, Error = Error> {
|
||||
fn_service(|_req: Request| ready(Ok::<_, Error>(Response::Ok().finish())))
|
||||
}
|
||||
|
||||
fn echo_path_service(
|
||||
) -> impl Service<Request = Request, Response = Response, Error = Error> {
|
||||
fn echo_path_service() -> impl Service<Request, Response = Response, Error = Error> {
|
||||
fn_service(|req: Request| {
|
||||
let path = req.path().as_bytes();
|
||||
ready(Ok::<_, Error>(Response::Ok().body(Body::from_slice(path))))
|
||||
})
|
||||
}
|
||||
|
||||
fn echo_payload_service(
|
||||
) -> impl Service<Request = Request, Response = Response, Error = Error> {
|
||||
fn echo_payload_service() -> impl Service<Request, Response = Response, Error = Error>
|
||||
{
|
||||
fn_service(|mut req: Request| {
|
||||
Box::pin(async move {
|
||||
use futures_util::stream::StreamExt as _;
|
||||
|
@ -1007,7 +1015,7 @@ mod tests {
|
|||
let mut pl = req.take_payload();
|
||||
let mut body = BytesMut::new();
|
||||
while let Some(chunk) = pl.next().await {
|
||||
body.extend_from_slice(chunk.unwrap().bytes())
|
||||
body.extend_from_slice(chunk.unwrap().chunk())
|
||||
}
|
||||
|
||||
Ok::<_, Error>(Response::Ok().body(body))
|
||||
|
@ -1020,7 +1028,7 @@ mod tests {
|
|||
lazy(|cx| {
|
||||
let buf = TestBuffer::new("GET /test HTTP/1\r\n\r\n");
|
||||
|
||||
let h1 = Dispatcher::<_, _, _, _, UpgradeHandler<TestBuffer>>::new(
|
||||
let h1 = Dispatcher::<_, _, _, _, UpgradeHandler>::new(
|
||||
buf,
|
||||
ServiceConfig::default(),
|
||||
CloneableService::new(ok_service()),
|
||||
|
@ -1060,7 +1068,7 @@ mod tests {
|
|||
|
||||
let cfg = ServiceConfig::new(KeepAlive::Disabled, 1, 1, false, None);
|
||||
|
||||
let h1 = Dispatcher::<_, _, _, _, UpgradeHandler<TestBuffer>>::new(
|
||||
let h1 = Dispatcher::<_, _, _, _, UpgradeHandler>::new(
|
||||
buf,
|
||||
cfg,
|
||||
CloneableService::new(echo_path_service()),
|
||||
|
@ -1114,7 +1122,7 @@ mod tests {
|
|||
|
||||
let cfg = ServiceConfig::new(KeepAlive::Disabled, 1, 1, false, None);
|
||||
|
||||
let h1 = Dispatcher::<_, _, _, _, UpgradeHandler<TestBuffer>>::new(
|
||||
let h1 = Dispatcher::<_, _, _, _, UpgradeHandler>::new(
|
||||
buf,
|
||||
cfg,
|
||||
CloneableService::new(echo_path_service()),
|
||||
|
@ -1163,7 +1171,7 @@ mod tests {
|
|||
lazy(|cx| {
|
||||
let mut buf = TestSeqBuffer::empty();
|
||||
let cfg = ServiceConfig::new(KeepAlive::Disabled, 0, 0, false, None);
|
||||
let h1 = Dispatcher::<_, _, _, _, UpgradeHandler<_>>::new(
|
||||
let h1 = Dispatcher::<_, _, _, _, UpgradeHandler>::new(
|
||||
buf.clone(),
|
||||
cfg,
|
||||
CloneableService::new(echo_payload_service()),
|
||||
|
@ -1234,7 +1242,7 @@ mod tests {
|
|||
lazy(|cx| {
|
||||
let mut buf = TestSeqBuffer::empty();
|
||||
let cfg = ServiceConfig::new(KeepAlive::Disabled, 0, 0, false, None);
|
||||
let h1 = Dispatcher::<_, _, _, _, UpgradeHandler<_>>::new(
|
||||
let h1 = Dispatcher::<_, _, _, _, UpgradeHandler>::new(
|
||||
buf.clone(),
|
||||
cfg,
|
||||
CloneableService::new(echo_path_service()),
|
||||
|
@ -1293,12 +1301,12 @@ mod tests {
|
|||
lazy(|cx| {
|
||||
let mut buf = TestSeqBuffer::empty();
|
||||
let cfg = ServiceConfig::new(KeepAlive::Disabled, 0, 0, false, None);
|
||||
let h1 = Dispatcher::<_, _, _, _, UpgradeHandler<_>>::new(
|
||||
let h1 = Dispatcher::<_, _, _, _, UpgradeHandler>::new(
|
||||
buf.clone(),
|
||||
cfg,
|
||||
CloneableService::new(ok_service()),
|
||||
CloneableService::new(ExpectHandler),
|
||||
Some(CloneableService::new(UpgradeHandler(PhantomData))),
|
||||
Some(CloneableService::new(UpgradeHandler)),
|
||||
Extensions::new(),
|
||||
None,
|
||||
);
|
||||
|
|
|
@ -21,7 +21,7 @@ const AVERAGE_HEADER_SIZE: usize = 30;
|
|||
pub(crate) struct MessageEncoder<T: MessageType> {
|
||||
pub length: BodySize,
|
||||
pub te: TransferEncoding,
|
||||
_t: PhantomData<T>,
|
||||
_phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T: MessageType> Default for MessageEncoder<T> {
|
||||
|
@ -29,7 +29,7 @@ impl<T: MessageType> Default for MessageEncoder<T> {
|
|||
MessageEncoder {
|
||||
length: BodySize::None,
|
||||
te: TransferEncoding::empty(),
|
||||
_t: PhantomData,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -118,7 +118,7 @@ pub(crate) trait MessageType: Sized {
|
|||
dst.put_slice(b"connection: close\r\n")
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// merging headers from head and extra headers. HeaderMap::new() does not allocate.
|
||||
|
@ -135,7 +135,7 @@ pub(crate) trait MessageType: Sized {
|
|||
|
||||
let mut has_date = false;
|
||||
|
||||
let mut buf = dst.bytes_mut().as_mut_ptr() as *mut u8;
|
||||
let mut buf = dst.chunk_mut().as_mut_ptr() as *mut u8;
|
||||
let mut remaining = dst.capacity() - dst.len();
|
||||
|
||||
// tracks bytes written since last buffer resize
|
||||
|
@ -148,7 +148,7 @@ pub(crate) trait MessageType: Sized {
|
|||
CONNECTION => continue,
|
||||
TRANSFER_ENCODING | CONTENT_LENGTH if skip_len => continue,
|
||||
DATE => has_date = true,
|
||||
_ => (),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
let k = key.as_str().as_bytes();
|
||||
|
@ -177,7 +177,7 @@ pub(crate) trait MessageType: Sized {
|
|||
|
||||
// re-assign buf raw pointer since it's possible that the buffer was
|
||||
// reallocated and/or resized
|
||||
buf = dst.bytes_mut().as_mut_ptr() as *mut u8;
|
||||
buf = dst.chunk_mut().as_mut_ptr() as *mut u8;
|
||||
}
|
||||
|
||||
// SAFETY: on each write, it is enough to ensure that the advancement of the
|
||||
|
@ -224,7 +224,7 @@ pub(crate) trait MessageType: Sized {
|
|||
|
||||
// re-assign buf raw pointer since it's possible that the buffer was
|
||||
// reallocated and/or resized
|
||||
buf = dst.bytes_mut().as_mut_ptr() as *mut u8;
|
||||
buf = dst.chunk_mut().as_mut_ptr() as *mut u8;
|
||||
}
|
||||
|
||||
// SAFETY: on each write, it is enough to ensure that the advancement of
|
||||
|
@ -532,30 +532,29 @@ unsafe fn write_data(value: &[u8], buf: *mut u8, len: usize) {
|
|||
}
|
||||
|
||||
fn write_camel_case(value: &[u8], buffer: &mut [u8]) {
|
||||
let mut index = 0;
|
||||
let key = value;
|
||||
let mut key_iter = key.iter();
|
||||
// first copy entire (potentially wrong) slice to output
|
||||
buffer[..value.len()].copy_from_slice(value);
|
||||
|
||||
if let Some(c) = key_iter.next() {
|
||||
if *c >= b'a' && *c <= b'z' {
|
||||
buffer[index] = *c ^ b' ';
|
||||
index += 1;
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
let mut iter = value.iter();
|
||||
|
||||
// first character should be uppercase
|
||||
if let Some(c @ b'a'..=b'z') = iter.next() {
|
||||
buffer[0] = c & 0b1101_1111;
|
||||
}
|
||||
|
||||
while let Some(c) = key_iter.next() {
|
||||
buffer[index] = *c;
|
||||
index += 1;
|
||||
if *c == b'-' {
|
||||
if let Some(c) = key_iter.next() {
|
||||
if *c >= b'a' && *c <= b'z' {
|
||||
buffer[index] = *c ^ b' ';
|
||||
index += 1;
|
||||
}
|
||||
// track 1 ahead of the current position since that's the location being assigned to
|
||||
let mut index = 2;
|
||||
|
||||
// remaining characters after hyphens should also be uppercase
|
||||
while let Some(&c) = iter.next() {
|
||||
if c == b'-' {
|
||||
// advance iter by one and uppercase if needed
|
||||
if let Some(c @ b'a'..=b'z') = iter.next() {
|
||||
buffer[index] = c & 0b1101_1111;
|
||||
}
|
||||
}
|
||||
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -604,6 +603,8 @@ mod tests {
|
|||
);
|
||||
let data =
|
||||
String::from_utf8(Vec::from(bytes.split().freeze().as_ref())).unwrap();
|
||||
eprintln!("{}", &data);
|
||||
|
||||
assert!(data.contains("Content-Length: 0\r\n"));
|
||||
assert!(data.contains("Connection: close\r\n"));
|
||||
assert!(data.contains("Content-Type: plain/text\r\n"));
|
||||
|
|
|
@ -8,11 +8,10 @@ use crate::request::Request;
|
|||
|
||||
pub struct ExpectHandler;
|
||||
|
||||
impl ServiceFactory for ExpectHandler {
|
||||
type Config = ();
|
||||
type Request = Request;
|
||||
impl ServiceFactory<Request> for ExpectHandler {
|
||||
type Response = Request;
|
||||
type Error = Error;
|
||||
type Config = ();
|
||||
type Service = ExpectHandler;
|
||||
type InitError = Error;
|
||||
type Future = Ready<Result<Self::Service, Self::InitError>>;
|
||||
|
@ -22,8 +21,7 @@ impl ServiceFactory for ExpectHandler {
|
|||
}
|
||||
}
|
||||
|
||||
impl Service for ExpectHandler {
|
||||
type Request = Request;
|
||||
impl Service<Request> for ExpectHandler {
|
||||
type Response = Request;
|
||||
type Error = Error;
|
||||
type Future = Ready<Result<Self::Response, Self::Error>>;
|
||||
|
|
|
@ -24,25 +24,25 @@ use super::dispatcher::Dispatcher;
|
|||
use super::{ExpectHandler, UpgradeHandler};
|
||||
|
||||
/// `ServiceFactory` implementation for HTTP1 transport
|
||||
pub struct H1Service<T, S, B, X = ExpectHandler, U = UpgradeHandler<T>> {
|
||||
pub struct H1Service<T, S, B, X = ExpectHandler, U = UpgradeHandler> {
|
||||
srv: S,
|
||||
cfg: ServiceConfig,
|
||||
expect: X,
|
||||
upgrade: Option<U>,
|
||||
on_connect_ext: Option<Rc<ConnectCallback<T>>>,
|
||||
_t: PhantomData<(T, B)>,
|
||||
_phantom: PhantomData<B>,
|
||||
}
|
||||
|
||||
impl<T, S, B> H1Service<T, S, B>
|
||||
where
|
||||
S: ServiceFactory<Config = (), Request = Request>,
|
||||
S: ServiceFactory<Request, Config = ()>,
|
||||
S::Error: Into<Error>,
|
||||
S::InitError: fmt::Debug,
|
||||
S::Response: Into<Response<B>>,
|
||||
B: MessageBody,
|
||||
{
|
||||
/// Create new `HttpService` instance with config.
|
||||
pub(crate) fn with_config<F: IntoServiceFactory<S>>(
|
||||
pub(crate) fn with_config<F: IntoServiceFactory<S, Request>>(
|
||||
cfg: ServiceConfig,
|
||||
service: F,
|
||||
) -> Self {
|
||||
|
@ -52,26 +52,22 @@ where
|
|||
expect: ExpectHandler,
|
||||
upgrade: None,
|
||||
on_connect_ext: None,
|
||||
_t: PhantomData,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<S, B, X, U> H1Service<TcpStream, S, B, X, U>
|
||||
where
|
||||
S: ServiceFactory<Config = (), Request = Request>,
|
||||
S: ServiceFactory<Request, Config = ()>,
|
||||
S::Error: Into<Error>,
|
||||
S::InitError: fmt::Debug,
|
||||
S::Response: Into<Response<B>>,
|
||||
B: MessageBody,
|
||||
X: ServiceFactory<Config = (), Request = Request, Response = Request>,
|
||||
X: ServiceFactory<Request, Config = (), Response = Request>,
|
||||
X::Error: Into<Error>,
|
||||
X::InitError: fmt::Debug,
|
||||
U: ServiceFactory<
|
||||
Config = (),
|
||||
Request = (Request, Framed<TcpStream, Codec>),
|
||||
Response = (),
|
||||
>,
|
||||
U: ServiceFactory<(Request, Framed<TcpStream, Codec>), Config = (), Response = ()>,
|
||||
U::Error: fmt::Display + Into<Error>,
|
||||
U::InitError: fmt::Debug,
|
||||
{
|
||||
|
@ -79,8 +75,8 @@ where
|
|||
pub fn tcp(
|
||||
self,
|
||||
) -> impl ServiceFactory<
|
||||
TcpStream,
|
||||
Config = (),
|
||||
Request = TcpStream,
|
||||
Response = (),
|
||||
Error = DispatchError,
|
||||
InitError = (),
|
||||
|
@ -97,22 +93,23 @@ where
|
|||
mod openssl {
|
||||
use super::*;
|
||||
|
||||
use actix_tls::openssl::{Acceptor, SslAcceptor, SslStream};
|
||||
use actix_tls::{openssl::HandshakeError, TlsError};
|
||||
use actix_service::ServiceFactoryExt;
|
||||
use actix_tls::accept::openssl::{Acceptor, SslAcceptor, SslError, SslStream};
|
||||
use actix_tls::accept::TlsError;
|
||||
|
||||
impl<S, B, X, U> H1Service<SslStream<TcpStream>, S, B, X, U>
|
||||
where
|
||||
S: ServiceFactory<Config = (), Request = Request>,
|
||||
S: ServiceFactory<Request, Config = ()>,
|
||||
S::Error: Into<Error>,
|
||||
S::InitError: fmt::Debug,
|
||||
S::Response: Into<Response<B>>,
|
||||
B: MessageBody,
|
||||
X: ServiceFactory<Config = (), Request = Request, Response = Request>,
|
||||
X: ServiceFactory<Request, Config = (), Response = Request>,
|
||||
X::Error: Into<Error>,
|
||||
X::InitError: fmt::Debug,
|
||||
U: ServiceFactory<
|
||||
(Request, Framed<SslStream<TcpStream>, Codec>),
|
||||
Config = (),
|
||||
Request = (Request, Framed<SslStream<TcpStream>, Codec>),
|
||||
Response = (),
|
||||
>,
|
||||
U::Error: fmt::Display + Into<Error>,
|
||||
|
@ -123,10 +120,10 @@ mod openssl {
|
|||
self,
|
||||
acceptor: SslAcceptor,
|
||||
) -> impl ServiceFactory<
|
||||
TcpStream,
|
||||
Config = (),
|
||||
Request = TcpStream,
|
||||
Response = (),
|
||||
Error = TlsError<HandshakeError<TcpStream>, DispatchError>,
|
||||
Error = TlsError<SslError, DispatchError>,
|
||||
InitError = (),
|
||||
> {
|
||||
pipeline_factory(
|
||||
|
@ -146,23 +143,24 @@ mod openssl {
|
|||
#[cfg(feature = "rustls")]
|
||||
mod rustls {
|
||||
use super::*;
|
||||
use actix_tls::rustls::{Acceptor, ServerConfig, TlsStream};
|
||||
use actix_tls::TlsError;
|
||||
use actix_service::ServiceFactoryExt;
|
||||
use actix_tls::accept::rustls::{Acceptor, ServerConfig, TlsStream};
|
||||
use actix_tls::accept::TlsError;
|
||||
use std::{fmt, io};
|
||||
|
||||
impl<S, B, X, U> H1Service<TlsStream<TcpStream>, S, B, X, U>
|
||||
where
|
||||
S: ServiceFactory<Config = (), Request = Request>,
|
||||
S: ServiceFactory<Request, Config = ()>,
|
||||
S::Error: Into<Error>,
|
||||
S::InitError: fmt::Debug,
|
||||
S::Response: Into<Response<B>>,
|
||||
B: MessageBody,
|
||||
X: ServiceFactory<Config = (), Request = Request, Response = Request>,
|
||||
X: ServiceFactory<Request, Config = (), Response = Request>,
|
||||
X::Error: Into<Error>,
|
||||
X::InitError: fmt::Debug,
|
||||
U: ServiceFactory<
|
||||
(Request, Framed<TlsStream<TcpStream>, Codec>),
|
||||
Config = (),
|
||||
Request = (Request, Framed<TlsStream<TcpStream>, Codec>),
|
||||
Response = (),
|
||||
>,
|
||||
U::Error: fmt::Display + Into<Error>,
|
||||
|
@ -173,8 +171,8 @@ mod rustls {
|
|||
self,
|
||||
config: ServerConfig,
|
||||
) -> impl ServiceFactory<
|
||||
TcpStream,
|
||||
Config = (),
|
||||
Request = TcpStream,
|
||||
Response = (),
|
||||
Error = TlsError<io::Error, DispatchError>,
|
||||
InitError = (),
|
||||
|
@ -195,7 +193,7 @@ mod rustls {
|
|||
|
||||
impl<T, S, B, X, U> H1Service<T, S, B, X, U>
|
||||
where
|
||||
S: ServiceFactory<Config = (), Request = Request>,
|
||||
S: ServiceFactory<Request, Config = ()>,
|
||||
S::Error: Into<Error>,
|
||||
S::Response: Into<Response<B>>,
|
||||
S::InitError: fmt::Debug,
|
||||
|
@ -203,7 +201,7 @@ where
|
|||
{
|
||||
pub fn expect<X1>(self, expect: X1) -> H1Service<T, S, B, X1, U>
|
||||
where
|
||||
X1: ServiceFactory<Request = Request, Response = Request>,
|
||||
X1: ServiceFactory<Request, Response = Request>,
|
||||
X1::Error: Into<Error>,
|
||||
X1::InitError: fmt::Debug,
|
||||
{
|
||||
|
@ -213,13 +211,13 @@ where
|
|||
srv: self.srv,
|
||||
upgrade: self.upgrade,
|
||||
on_connect_ext: self.on_connect_ext,
|
||||
_t: PhantomData,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn upgrade<U1>(self, upgrade: Option<U1>) -> H1Service<T, S, B, X, U1>
|
||||
where
|
||||
U1: ServiceFactory<Request = (Request, Framed<T, Codec>), Response = ()>,
|
||||
U1: ServiceFactory<(Request, Framed<T, Codec>), Response = ()>,
|
||||
U1::Error: fmt::Display,
|
||||
U1::InitError: fmt::Debug,
|
||||
{
|
||||
|
@ -229,7 +227,7 @@ where
|
|||
srv: self.srv,
|
||||
expect: self.expect,
|
||||
on_connect_ext: self.on_connect_ext,
|
||||
_t: PhantomData,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -240,27 +238,27 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<T, S, B, X, U> ServiceFactory for H1Service<T, S, B, X, U>
|
||||
impl<T, S, B, X, U> ServiceFactory<(T, Option<net::SocketAddr>)>
|
||||
for H1Service<T, S, B, X, U>
|
||||
where
|
||||
T: AsyncRead + AsyncWrite + Unpin,
|
||||
S: ServiceFactory<Config = (), Request = Request>,
|
||||
S: ServiceFactory<Request, Config = ()>,
|
||||
S::Error: Into<Error>,
|
||||
S::Response: Into<Response<B>>,
|
||||
S::InitError: fmt::Debug,
|
||||
B: MessageBody,
|
||||
X: ServiceFactory<Config = (), Request = Request, Response = Request>,
|
||||
X: ServiceFactory<Request, Config = (), Response = Request>,
|
||||
X::Error: Into<Error>,
|
||||
X::InitError: fmt::Debug,
|
||||
U: ServiceFactory<Config = (), Request = (Request, Framed<T, Codec>), Response = ()>,
|
||||
U: ServiceFactory<(Request, Framed<T, Codec>), Config = (), Response = ()>,
|
||||
U::Error: fmt::Display + Into<Error>,
|
||||
U::InitError: fmt::Debug,
|
||||
{
|
||||
type Config = ();
|
||||
type Request = (T, Option<net::SocketAddr>);
|
||||
type Response = ();
|
||||
type Error = DispatchError;
|
||||
type InitError = ();
|
||||
type Config = ();
|
||||
type Service = H1ServiceHandler<T, S::Service, B, X::Service, U::Service>;
|
||||
type InitError = ();
|
||||
type Future = H1ServiceResponse<T, S, B, X, U>;
|
||||
|
||||
fn new_service(&self, _: ()) -> Self::Future {
|
||||
|
@ -272,7 +270,7 @@ where
|
|||
upgrade: None,
|
||||
on_connect_ext: self.on_connect_ext.clone(),
|
||||
cfg: Some(self.cfg.clone()),
|
||||
_t: PhantomData,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -281,13 +279,13 @@ where
|
|||
#[pin_project::pin_project]
|
||||
pub struct H1ServiceResponse<T, S, B, X, U>
|
||||
where
|
||||
S: ServiceFactory<Request = Request>,
|
||||
S: ServiceFactory<Request>,
|
||||
S::Error: Into<Error>,
|
||||
S::InitError: fmt::Debug,
|
||||
X: ServiceFactory<Request = Request, Response = Request>,
|
||||
X: ServiceFactory<Request, Response = Request>,
|
||||
X::Error: Into<Error>,
|
||||
X::InitError: fmt::Debug,
|
||||
U: ServiceFactory<Request = (Request, Framed<T, Codec>), Response = ()>,
|
||||
U: ServiceFactory<(Request, Framed<T, Codec>), Response = ()>,
|
||||
U::Error: fmt::Display,
|
||||
U::InitError: fmt::Debug,
|
||||
{
|
||||
|
@ -301,21 +299,21 @@ where
|
|||
upgrade: Option<U::Service>,
|
||||
on_connect_ext: Option<Rc<ConnectCallback<T>>>,
|
||||
cfg: Option<ServiceConfig>,
|
||||
_t: PhantomData<(T, B)>,
|
||||
_phantom: PhantomData<(T, B)>,
|
||||
}
|
||||
|
||||
impl<T, S, B, X, U> Future for H1ServiceResponse<T, S, B, X, U>
|
||||
where
|
||||
T: AsyncRead + AsyncWrite + Unpin,
|
||||
S: ServiceFactory<Request = Request>,
|
||||
S: ServiceFactory<Request>,
|
||||
S::Error: Into<Error>,
|
||||
S::Response: Into<Response<B>>,
|
||||
S::InitError: fmt::Debug,
|
||||
B: MessageBody,
|
||||
X: ServiceFactory<Request = Request, Response = Request>,
|
||||
X: ServiceFactory<Request, Response = Request>,
|
||||
X::Error: Into<Error>,
|
||||
X::InitError: fmt::Debug,
|
||||
U: ServiceFactory<Request = (Request, Framed<T, Codec>), Response = ()>,
|
||||
U: ServiceFactory<(Request, Framed<T, Codec>), Response = ()>,
|
||||
U::Error: fmt::Display,
|
||||
U::InitError: fmt::Debug,
|
||||
{
|
||||
|
@ -362,24 +360,29 @@ where
|
|||
}
|
||||
|
||||
/// `Service` implementation for HTTP/1 transport
|
||||
pub struct H1ServiceHandler<T, S: Service, B, X: Service, U: Service> {
|
||||
pub struct H1ServiceHandler<T, S, B, X, U>
|
||||
where
|
||||
S: Service<Request>,
|
||||
X: Service<Request>,
|
||||
U: Service<(Request, Framed<T, Codec>)>,
|
||||
{
|
||||
srv: CloneableService<S>,
|
||||
expect: CloneableService<X>,
|
||||
upgrade: Option<CloneableService<U>>,
|
||||
on_connect_ext: Option<Rc<ConnectCallback<T>>>,
|
||||
cfg: ServiceConfig,
|
||||
_t: PhantomData<(T, B)>,
|
||||
_phantom: PhantomData<B>,
|
||||
}
|
||||
|
||||
impl<T, S, B, X, U> H1ServiceHandler<T, S, B, X, U>
|
||||
where
|
||||
S: Service<Request = Request>,
|
||||
S: Service<Request>,
|
||||
S::Error: Into<Error>,
|
||||
S::Response: Into<Response<B>>,
|
||||
B: MessageBody,
|
||||
X: Service<Request = Request, Response = Request>,
|
||||
X: Service<Request, Response = Request>,
|
||||
X::Error: Into<Error>,
|
||||
U: Service<Request = (Request, Framed<T, Codec>), Response = ()>,
|
||||
U: Service<(Request, Framed<T, Codec>), Response = ()>,
|
||||
U::Error: fmt::Display,
|
||||
{
|
||||
fn new(
|
||||
|
@ -395,24 +398,24 @@ where
|
|||
upgrade: upgrade.map(CloneableService::new),
|
||||
cfg,
|
||||
on_connect_ext,
|
||||
_t: PhantomData,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, S, B, X, U> Service for H1ServiceHandler<T, S, B, X, U>
|
||||
impl<T, S, B, X, U> Service<(T, Option<net::SocketAddr>)>
|
||||
for H1ServiceHandler<T, S, B, X, U>
|
||||
where
|
||||
T: AsyncRead + AsyncWrite + Unpin,
|
||||
S: Service<Request = Request>,
|
||||
S: Service<Request>,
|
||||
S::Error: Into<Error>,
|
||||
S::Response: Into<Response<B>>,
|
||||
B: MessageBody,
|
||||
X: Service<Request = Request, Response = Request>,
|
||||
X: Service<Request, Response = Request>,
|
||||
X::Error: Into<Error>,
|
||||
U: Service<Request = (Request, Framed<T, Codec>), Response = ()>,
|
||||
U: Service<(Request, Framed<T, Codec>), Response = ()>,
|
||||
U::Error: fmt::Display + Into<Error>,
|
||||
{
|
||||
type Request = (T, Option<net::SocketAddr>);
|
||||
type Response = ();
|
||||
type Error = DispatchError;
|
||||
type Future = Dispatcher<T, S, B, X, U>;
|
||||
|
@ -459,7 +462,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
fn call(&mut self, (io, addr): Self::Request) -> Self::Future {
|
||||
fn call(&mut self, (io, addr): (T, Option<net::SocketAddr>)) -> Self::Future {
|
||||
let mut connect_extensions = Extensions::new();
|
||||
if let Some(ref handler) = self.on_connect_ext {
|
||||
// run on_connect_ext callback, populating connect extensions
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
use std::marker::PhantomData;
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
use actix_codec::Framed;
|
||||
|
@ -9,14 +8,13 @@ use crate::error::Error;
|
|||
use crate::h1::Codec;
|
||||
use crate::request::Request;
|
||||
|
||||
pub struct UpgradeHandler<T>(pub(crate) PhantomData<T>);
|
||||
pub struct UpgradeHandler;
|
||||
|
||||
impl<T> ServiceFactory for UpgradeHandler<T> {
|
||||
type Config = ();
|
||||
type Request = (Request, Framed<T, Codec>);
|
||||
impl<T> ServiceFactory<(Request, Framed<T, Codec>)> for UpgradeHandler {
|
||||
type Response = ();
|
||||
type Error = Error;
|
||||
type Service = UpgradeHandler<T>;
|
||||
type Config = ();
|
||||
type Service = UpgradeHandler;
|
||||
type InitError = Error;
|
||||
type Future = Ready<Result<Self::Service, Self::InitError>>;
|
||||
|
||||
|
@ -25,8 +23,7 @@ impl<T> ServiceFactory for UpgradeHandler<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T> Service for UpgradeHandler<T> {
|
||||
type Request = (Request, Framed<T, Codec>);
|
||||
impl<T> Service<(Request, Framed<T, Codec>)> for UpgradeHandler {
|
||||
type Response = ();
|
||||
type Error = Error;
|
||||
type Future = Ready<Result<Self::Response, Self::Error>>;
|
||||
|
@ -35,7 +32,7 @@ impl<T> Service for UpgradeHandler<T> {
|
|||
Poll::Ready(Ok(()))
|
||||
}
|
||||
|
||||
fn call(&mut self, _: Self::Request) -> Self::Future {
|
||||
fn call(&mut self, _: (Request, Framed<T, Codec>)) -> Self::Future {
|
||||
ready(Ok(()))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
use std::convert::TryFrom;
|
||||
use std::future::Future;
|
||||
use std::marker::PhantomData;
|
||||
use std::net;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
use std::{cmp, convert::TryFrom};
|
||||
|
||||
use actix_codec::{AsyncRead, AsyncWrite};
|
||||
use actix_rt::time::{Delay, Instant};
|
||||
use actix_rt::time::{Instant, Sleep};
|
||||
use actix_service::Service;
|
||||
use bytes::{Bytes, BytesMut};
|
||||
use futures_core::ready;
|
||||
use h2::server::{Connection, SendResponse};
|
||||
use h2::SendStream;
|
||||
use http::header::{HeaderValue, CONNECTION, CONTENT_LENGTH, DATE, TRANSFER_ENCODING};
|
||||
|
@ -27,11 +28,13 @@ use crate::Extensions;
|
|||
|
||||
const CHUNK_SIZE: usize = 16_384;
|
||||
|
||||
/// Dispatcher for HTTP/2 protocol
|
||||
/// Dispatcher for HTTP/2 protocol.
|
||||
#[pin_project::pin_project]
|
||||
pub struct Dispatcher<T, S: Service<Request = Request>, B: MessageBody>
|
||||
pub struct Dispatcher<T, S, B>
|
||||
where
|
||||
T: AsyncRead + AsyncWrite + Unpin,
|
||||
S: Service<Request>,
|
||||
B: MessageBody,
|
||||
{
|
||||
service: CloneableService<S>,
|
||||
connection: Connection<T, Bytes>,
|
||||
|
@ -39,16 +42,15 @@ where
|
|||
config: ServiceConfig,
|
||||
peer_addr: Option<net::SocketAddr>,
|
||||
ka_expire: Instant,
|
||||
ka_timer: Option<Delay>,
|
||||
_t: PhantomData<B>,
|
||||
ka_timer: Option<Sleep>,
|
||||
_phantom: PhantomData<B>,
|
||||
}
|
||||
|
||||
impl<T, S, B> Dispatcher<T, S, B>
|
||||
where
|
||||
T: AsyncRead + AsyncWrite + Unpin,
|
||||
S: Service<Request = Request>,
|
||||
S: Service<Request>,
|
||||
S::Error: Into<Error>,
|
||||
// S::Future: 'static,
|
||||
S::Response: Into<Response<B>>,
|
||||
B: MessageBody,
|
||||
{
|
||||
|
@ -57,7 +59,7 @@ where
|
|||
connection: Connection<T, Bytes>,
|
||||
on_connect_data: Extensions,
|
||||
config: ServiceConfig,
|
||||
timeout: Option<Delay>,
|
||||
timeout: Option<Sleep>,
|
||||
peer_addr: Option<net::SocketAddr>,
|
||||
) -> Self {
|
||||
// let keepalive = config.keep_alive_enabled();
|
||||
|
@ -84,7 +86,7 @@ where
|
|||
on_connect_data,
|
||||
ka_expire,
|
||||
ka_timer,
|
||||
_t: PhantomData,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -92,7 +94,7 @@ where
|
|||
impl<T, S, B> Future for Dispatcher<T, S, B>
|
||||
where
|
||||
T: AsyncRead + AsyncWrite + Unpin,
|
||||
S: Service<Request = Request>,
|
||||
S: Service<Request>,
|
||||
S::Error: Into<Error> + 'static,
|
||||
S::Future: 'static,
|
||||
S::Response: Into<Response<B>> + 'static,
|
||||
|
@ -105,10 +107,12 @@ where
|
|||
let this = self.get_mut();
|
||||
|
||||
loop {
|
||||
match Pin::new(&mut this.connection).poll_accept(cx) {
|
||||
Poll::Ready(None) => return Poll::Ready(Ok(())),
|
||||
Poll::Ready(Some(Err(err))) => return Poll::Ready(Err(err.into())),
|
||||
Poll::Ready(Some(Ok((req, res)))) => {
|
||||
match ready!(Pin::new(&mut this.connection).poll_accept(cx)) {
|
||||
None => return Poll::Ready(Ok(())),
|
||||
|
||||
Some(Err(err)) => return Poll::Ready(Err(err.into())),
|
||||
|
||||
Some(Ok((req, res))) => {
|
||||
// update keep-alive expire
|
||||
if this.ka_timer.is_some() {
|
||||
if let Some(expire) = this.config.keep_alive_expire() {
|
||||
|
@ -117,11 +121,9 @@ where
|
|||
}
|
||||
|
||||
let (parts, body) = req.into_parts();
|
||||
let mut req = Request::with_payload(Payload::<
|
||||
crate::payload::PayloadStream,
|
||||
>::H2(
|
||||
crate::h2::Payload::new(body)
|
||||
));
|
||||
let pl = crate::h2::Payload::new(body);
|
||||
let pl = Payload::<crate::payload::PayloadStream>::H2(pl);
|
||||
let mut req = Request::with_payload(pl);
|
||||
|
||||
let head = &mut req.head_mut();
|
||||
head.uri = parts.uri;
|
||||
|
@ -133,22 +135,18 @@ where
|
|||
// merge on_connect_ext data into request extensions
|
||||
req.extensions_mut().drain_from(&mut this.on_connect_data);
|
||||
|
||||
actix_rt::spawn(ServiceResponse::<
|
||||
S::Future,
|
||||
S::Response,
|
||||
S::Error,
|
||||
B,
|
||||
> {
|
||||
let svc = ServiceResponse::<S::Future, S::Response, S::Error, B> {
|
||||
state: ServiceResponseState::ServiceCall(
|
||||
this.service.call(req),
|
||||
Some(res),
|
||||
),
|
||||
config: this.config.clone(),
|
||||
buffer: None,
|
||||
_t: PhantomData,
|
||||
});
|
||||
_phantom: PhantomData,
|
||||
};
|
||||
|
||||
actix_rt::spawn(svc);
|
||||
}
|
||||
Poll::Pending => return Poll::Pending,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -160,7 +158,7 @@ struct ServiceResponse<F, I, E, B> {
|
|||
state: ServiceResponseState<F, B>,
|
||||
config: ServiceConfig,
|
||||
buffer: Option<Bytes>,
|
||||
_t: PhantomData<(I, E)>,
|
||||
_phantom: PhantomData<(I, E)>,
|
||||
}
|
||||
|
||||
#[pin_project::pin_project(project = ServiceResponseStateProj)]
|
||||
|
@ -197,8 +195,9 @@ where
|
|||
skip_len = true;
|
||||
*size = BodySize::Stream;
|
||||
}
|
||||
_ => (),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
let _ = match size {
|
||||
BodySize::None | BodySize::Stream => None,
|
||||
BodySize::Empty => res
|
||||
|
@ -213,11 +212,13 @@ where
|
|||
// copy headers
|
||||
for (key, value) in head.headers.iter() {
|
||||
match *key {
|
||||
CONNECTION | TRANSFER_ENCODING => continue, // http2 specific
|
||||
// omit HTTP/1 only headers
|
||||
CONNECTION | TRANSFER_ENCODING => continue,
|
||||
CONTENT_LENGTH if skip_len => continue,
|
||||
DATE => has_date = true,
|
||||
_ => (),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
res.headers_mut().append(key, value.clone());
|
||||
}
|
||||
|
||||
|
@ -249,109 +250,117 @@ where
|
|||
let mut this = self.as_mut().project();
|
||||
|
||||
match this.state.project() {
|
||||
ServiceResponseStateProj::ServiceCall(call, send) => match call.poll(cx) {
|
||||
Poll::Ready(Ok(res)) => {
|
||||
let (res, body) = res.into().replace_body(());
|
||||
ServiceResponseStateProj::ServiceCall(call, send) => {
|
||||
match ready!(call.poll(cx)) {
|
||||
Ok(res) => {
|
||||
let (res, body) = res.into().replace_body(());
|
||||
|
||||
let mut send = send.take().unwrap();
|
||||
let mut size = body.size();
|
||||
let h2_res = self.as_mut().prepare_response(res.head(), &mut size);
|
||||
this = self.as_mut().project();
|
||||
let mut send = send.take().unwrap();
|
||||
let mut size = body.size();
|
||||
let h2_res =
|
||||
self.as_mut().prepare_response(res.head(), &mut size);
|
||||
this = self.as_mut().project();
|
||||
|
||||
let stream = match send.send_response(h2_res, size.is_eof()) {
|
||||
Err(e) => {
|
||||
trace!("Error sending h2 response: {:?}", e);
|
||||
return Poll::Ready(());
|
||||
let stream = match send.send_response(h2_res, size.is_eof()) {
|
||||
Err(e) => {
|
||||
trace!("Error sending HTTP/2 response: {:?}", e);
|
||||
return Poll::Ready(());
|
||||
}
|
||||
Ok(stream) => stream,
|
||||
};
|
||||
|
||||
if size.is_eof() {
|
||||
Poll::Ready(())
|
||||
} else {
|
||||
this.state
|
||||
.set(ServiceResponseState::SendPayload(stream, body));
|
||||
self.poll(cx)
|
||||
}
|
||||
Ok(stream) => stream,
|
||||
};
|
||||
}
|
||||
|
||||
if size.is_eof() {
|
||||
Poll::Ready(())
|
||||
} else {
|
||||
this.state
|
||||
.set(ServiceResponseState::SendPayload(stream, body));
|
||||
self.poll(cx)
|
||||
Err(e) => {
|
||||
let res: Response = e.into().into();
|
||||
let (res, body) = res.replace_body(());
|
||||
|
||||
let mut send = send.take().unwrap();
|
||||
let mut size = body.size();
|
||||
let h2_res =
|
||||
self.as_mut().prepare_response(res.head(), &mut size);
|
||||
this = self.as_mut().project();
|
||||
|
||||
let stream = match send.send_response(h2_res, size.is_eof()) {
|
||||
Err(e) => {
|
||||
trace!("Error sending HTTP/2 response: {:?}", e);
|
||||
return Poll::Ready(());
|
||||
}
|
||||
Ok(stream) => stream,
|
||||
};
|
||||
|
||||
if size.is_eof() {
|
||||
Poll::Ready(())
|
||||
} else {
|
||||
this.state.set(ServiceResponseState::SendPayload(
|
||||
stream,
|
||||
body.into_body(),
|
||||
));
|
||||
self.poll(cx)
|
||||
}
|
||||
}
|
||||
}
|
||||
Poll::Pending => Poll::Pending,
|
||||
Poll::Ready(Err(e)) => {
|
||||
let res: Response = e.into().into();
|
||||
let (res, body) = res.replace_body(());
|
||||
}
|
||||
|
||||
let mut send = send.take().unwrap();
|
||||
let mut size = body.size();
|
||||
let h2_res = self.as_mut().prepare_response(res.head(), &mut size);
|
||||
this = self.as_mut().project();
|
||||
|
||||
let stream = match send.send_response(h2_res, size.is_eof()) {
|
||||
Err(e) => {
|
||||
trace!("Error sending h2 response: {:?}", e);
|
||||
return Poll::Ready(());
|
||||
}
|
||||
Ok(stream) => stream,
|
||||
};
|
||||
|
||||
if size.is_eof() {
|
||||
Poll::Ready(())
|
||||
} else {
|
||||
this.state.set(ServiceResponseState::SendPayload(
|
||||
stream,
|
||||
body.into_body(),
|
||||
));
|
||||
self.poll(cx)
|
||||
}
|
||||
}
|
||||
},
|
||||
ServiceResponseStateProj::SendPayload(ref mut stream, ref mut body) => {
|
||||
loop {
|
||||
loop {
|
||||
if let Some(ref mut buffer) = this.buffer {
|
||||
match stream.poll_capacity(cx) {
|
||||
Poll::Pending => return Poll::Pending,
|
||||
Poll::Ready(None) => return Poll::Ready(()),
|
||||
Poll::Ready(Some(Ok(cap))) => {
|
||||
let len = buffer.len();
|
||||
let bytes = buffer.split_to(std::cmp::min(cap, len));
|
||||
match this.buffer {
|
||||
Some(ref mut buffer) => {
|
||||
match ready!(stream.poll_capacity(cx)) {
|
||||
None => return Poll::Ready(()),
|
||||
|
||||
if let Err(e) = stream.send_data(bytes, false) {
|
||||
Some(Ok(cap)) => {
|
||||
let len = buffer.len();
|
||||
let bytes = buffer.split_to(cmp::min(cap, len));
|
||||
|
||||
if let Err(e) = stream.send_data(bytes, false) {
|
||||
warn!("{:?}", e);
|
||||
return Poll::Ready(());
|
||||
} else if !buffer.is_empty() {
|
||||
let cap = cmp::min(buffer.len(), CHUNK_SIZE);
|
||||
stream.reserve_capacity(cap);
|
||||
} else {
|
||||
this.buffer.take();
|
||||
}
|
||||
}
|
||||
|
||||
Some(Err(e)) => {
|
||||
warn!("{:?}", e);
|
||||
return Poll::Ready(());
|
||||
} else if !buffer.is_empty() {
|
||||
let cap =
|
||||
std::cmp::min(buffer.len(), CHUNK_SIZE);
|
||||
stream.reserve_capacity(cap);
|
||||
} else {
|
||||
this.buffer.take();
|
||||
}
|
||||
}
|
||||
Poll::Ready(Some(Err(e))) => {
|
||||
warn!("{:?}", e);
|
||||
return Poll::Ready(());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
match body.as_mut().poll_next(cx) {
|
||||
Poll::Pending => return Poll::Pending,
|
||||
Poll::Ready(None) => {
|
||||
|
||||
None => match ready!(body.as_mut().poll_next(cx)) {
|
||||
None => {
|
||||
if let Err(e) = stream.send_data(Bytes::new(), true)
|
||||
{
|
||||
warn!("{:?}", e);
|
||||
}
|
||||
return Poll::Ready(());
|
||||
}
|
||||
Poll::Ready(Some(Ok(chunk))) => {
|
||||
stream.reserve_capacity(std::cmp::min(
|
||||
|
||||
Some(Ok(chunk)) => {
|
||||
stream.reserve_capacity(cmp::min(
|
||||
chunk.len(),
|
||||
CHUNK_SIZE,
|
||||
));
|
||||
*this.buffer = Some(chunk);
|
||||
}
|
||||
Poll::Ready(Some(Err(e))) => {
|
||||
|
||||
Some(Err(e)) => {
|
||||
error!("Response payload stream error: {:?}", e);
|
||||
return Poll::Ready(());
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
//! HTTP/2 implementation
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
//! HTTP/2 implementation.
|
||||
|
||||
use std::{
|
||||
pin::Pin,
|
||||
task::{Context, Poll},
|
||||
};
|
||||
|
||||
use bytes::Bytes;
|
||||
use futures_core::Stream;
|
||||
use futures_core::{ready, Stream};
|
||||
use h2::RecvStream;
|
||||
|
||||
mod dispatcher;
|
||||
|
@ -13,14 +16,14 @@ pub use self::dispatcher::Dispatcher;
|
|||
pub use self::service::H2Service;
|
||||
use crate::error::PayloadError;
|
||||
|
||||
/// H2 receive stream
|
||||
/// HTTP/2 peer stream.
|
||||
pub struct Payload {
|
||||
pl: RecvStream,
|
||||
stream: RecvStream,
|
||||
}
|
||||
|
||||
impl Payload {
|
||||
pub(crate) fn new(pl: RecvStream) -> Self {
|
||||
Self { pl }
|
||||
pub(crate) fn new(stream: RecvStream) -> Self {
|
||||
Self { stream }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -33,18 +36,17 @@ impl Stream for Payload {
|
|||
) -> Poll<Option<Self::Item>> {
|
||||
let this = self.get_mut();
|
||||
|
||||
match Pin::new(&mut this.pl).poll_data(cx) {
|
||||
Poll::Ready(Some(Ok(chunk))) => {
|
||||
match ready!(Pin::new(&mut this.stream).poll_data(cx)) {
|
||||
Some(Ok(chunk)) => {
|
||||
let len = chunk.len();
|
||||
if let Err(err) = this.pl.flow_control().release_capacity(len) {
|
||||
Poll::Ready(Some(Err(err.into())))
|
||||
} else {
|
||||
Poll::Ready(Some(Ok(chunk)))
|
||||
|
||||
match this.stream.flow_control().release_capacity(len) {
|
||||
Ok(()) => Poll::Ready(Some(Ok(chunk))),
|
||||
Err(err) => Poll::Ready(Some(Err(err.into()))),
|
||||
}
|
||||
}
|
||||
Poll::Ready(Some(Err(err))) => Poll::Ready(Some(Err(err.into()))),
|
||||
Poll::Pending => Poll::Pending,
|
||||
Poll::Ready(None) => Poll::Ready(None),
|
||||
Some(Err(err)) => Poll::Ready(Some(Err(err.into()))),
|
||||
None => Poll::Ready(None),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,24 +26,24 @@ use crate::{ConnectCallback, Extensions};
|
|||
|
||||
use super::dispatcher::Dispatcher;
|
||||
|
||||
/// `ServiceFactory` implementation for HTTP2 transport
|
||||
/// `ServiceFactory` implementation for HTTP/2 transport
|
||||
pub struct H2Service<T, S, B> {
|
||||
srv: S,
|
||||
cfg: ServiceConfig,
|
||||
on_connect_ext: Option<Rc<ConnectCallback<T>>>,
|
||||
_t: PhantomData<(T, B)>,
|
||||
_phantom: PhantomData<(T, B)>,
|
||||
}
|
||||
|
||||
impl<T, S, B> H2Service<T, S, B>
|
||||
where
|
||||
S: ServiceFactory<Config = (), Request = Request>,
|
||||
S: ServiceFactory<Request, Config = ()>,
|
||||
S::Error: Into<Error> + 'static,
|
||||
S::Response: Into<Response<B>> + 'static,
|
||||
<S::Service as Service>::Future: 'static,
|
||||
<S::Service as Service<Request>>::Future: 'static,
|
||||
B: MessageBody + 'static,
|
||||
{
|
||||
/// Create new `HttpService` instance with config.
|
||||
pub(crate) fn with_config<F: IntoServiceFactory<S>>(
|
||||
/// Create new `H2Service` instance with config.
|
||||
pub(crate) fn with_config<F: IntoServiceFactory<S, Request>>(
|
||||
cfg: ServiceConfig,
|
||||
service: F,
|
||||
) -> Self {
|
||||
|
@ -51,7 +51,7 @@ where
|
|||
cfg,
|
||||
on_connect_ext: None,
|
||||
srv: service.into_factory(),
|
||||
_t: PhantomData,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -64,18 +64,18 @@ where
|
|||
|
||||
impl<S, B> H2Service<TcpStream, S, B>
|
||||
where
|
||||
S: ServiceFactory<Config = (), Request = Request>,
|
||||
S: ServiceFactory<Request, Config = ()>,
|
||||
S::Error: Into<Error> + 'static,
|
||||
S::Response: Into<Response<B>> + 'static,
|
||||
<S::Service as Service>::Future: 'static,
|
||||
<S::Service as Service<Request>>::Future: 'static,
|
||||
B: MessageBody + 'static,
|
||||
{
|
||||
/// Create simple tcp based service
|
||||
/// Create plain TCP based service
|
||||
pub fn tcp(
|
||||
self,
|
||||
) -> impl ServiceFactory<
|
||||
TcpStream,
|
||||
Config = (),
|
||||
Request = TcpStream,
|
||||
Response = (),
|
||||
Error = DispatchError,
|
||||
InitError = S::InitError,
|
||||
|
@ -92,29 +92,29 @@ where
|
|||
|
||||
#[cfg(feature = "openssl")]
|
||||
mod openssl {
|
||||
use actix_service::{fn_factory, fn_service};
|
||||
use actix_tls::openssl::{Acceptor, SslAcceptor, SslStream};
|
||||
use actix_tls::{openssl::HandshakeError, TlsError};
|
||||
use actix_service::{fn_factory, fn_service, ServiceFactoryExt};
|
||||
use actix_tls::accept::openssl::{Acceptor, SslAcceptor, SslError, SslStream};
|
||||
use actix_tls::accept::TlsError;
|
||||
|
||||
use super::*;
|
||||
|
||||
impl<S, B> H2Service<SslStream<TcpStream>, S, B>
|
||||
where
|
||||
S: ServiceFactory<Config = (), Request = Request>,
|
||||
S: ServiceFactory<Request, Config = ()>,
|
||||
S::Error: Into<Error> + 'static,
|
||||
S::Response: Into<Response<B>> + 'static,
|
||||
<S::Service as Service>::Future: 'static,
|
||||
<S::Service as Service<Request>>::Future: 'static,
|
||||
B: MessageBody + 'static,
|
||||
{
|
||||
/// Create ssl based service
|
||||
/// Create OpenSSL based service
|
||||
pub fn openssl(
|
||||
self,
|
||||
acceptor: SslAcceptor,
|
||||
) -> impl ServiceFactory<
|
||||
TcpStream,
|
||||
Config = (),
|
||||
Request = TcpStream,
|
||||
Response = (),
|
||||
Error = TlsError<HandshakeError<TcpStream>, DispatchError>,
|
||||
Error = TlsError<SslError, DispatchError>,
|
||||
InitError = S::InitError,
|
||||
> {
|
||||
pipeline_factory(
|
||||
|
@ -136,25 +136,26 @@ mod openssl {
|
|||
#[cfg(feature = "rustls")]
|
||||
mod rustls {
|
||||
use super::*;
|
||||
use actix_tls::rustls::{Acceptor, ServerConfig, TlsStream};
|
||||
use actix_tls::TlsError;
|
||||
use actix_service::ServiceFactoryExt;
|
||||
use actix_tls::accept::rustls::{Acceptor, ServerConfig, TlsStream};
|
||||
use actix_tls::accept::TlsError;
|
||||
use std::io;
|
||||
|
||||
impl<S, B> H2Service<TlsStream<TcpStream>, S, B>
|
||||
where
|
||||
S: ServiceFactory<Config = (), Request = Request>,
|
||||
S: ServiceFactory<Request, Config = ()>,
|
||||
S::Error: Into<Error> + 'static,
|
||||
S::Response: Into<Response<B>> + 'static,
|
||||
<S::Service as Service>::Future: 'static,
|
||||
<S::Service as Service<Request>>::Future: 'static,
|
||||
B: MessageBody + 'static,
|
||||
{
|
||||
/// Create openssl based service
|
||||
/// Create Rustls based service
|
||||
pub fn rustls(
|
||||
self,
|
||||
mut config: ServerConfig,
|
||||
) -> impl ServiceFactory<
|
||||
TcpStream,
|
||||
Config = (),
|
||||
Request = TcpStream,
|
||||
Response = (),
|
||||
Error = TlsError<io::Error, DispatchError>,
|
||||
InitError = S::InitError,
|
||||
|
@ -178,21 +179,20 @@ mod rustls {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T, S, B> ServiceFactory for H2Service<T, S, B>
|
||||
impl<T, S, B> ServiceFactory<(T, Option<net::SocketAddr>)> for H2Service<T, S, B>
|
||||
where
|
||||
T: AsyncRead + AsyncWrite + Unpin,
|
||||
S: ServiceFactory<Config = (), Request = Request>,
|
||||
S: ServiceFactory<Request, Config = ()>,
|
||||
S::Error: Into<Error> + 'static,
|
||||
S::Response: Into<Response<B>> + 'static,
|
||||
<S::Service as Service>::Future: 'static,
|
||||
<S::Service as Service<Request>>::Future: 'static,
|
||||
B: MessageBody + 'static,
|
||||
{
|
||||
type Config = ();
|
||||
type Request = (T, Option<net::SocketAddr>);
|
||||
type Response = ();
|
||||
type Error = DispatchError;
|
||||
type InitError = S::InitError;
|
||||
type Config = ();
|
||||
type Service = H2ServiceHandler<T, S::Service, B>;
|
||||
type InitError = S::InitError;
|
||||
type Future = H2ServiceResponse<T, S, B>;
|
||||
|
||||
fn new_service(&self, _: ()) -> Self::Future {
|
||||
|
@ -200,28 +200,31 @@ where
|
|||
fut: self.srv.new_service(()),
|
||||
cfg: Some(self.cfg.clone()),
|
||||
on_connect_ext: self.on_connect_ext.clone(),
|
||||
_t: PhantomData,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[pin_project::pin_project]
|
||||
pub struct H2ServiceResponse<T, S: ServiceFactory, B> {
|
||||
pub struct H2ServiceResponse<T, S, B>
|
||||
where
|
||||
S: ServiceFactory<Request>,
|
||||
{
|
||||
#[pin]
|
||||
fut: S::Future,
|
||||
cfg: Option<ServiceConfig>,
|
||||
on_connect_ext: Option<Rc<ConnectCallback<T>>>,
|
||||
_t: PhantomData<(T, B)>,
|
||||
_phantom: PhantomData<B>,
|
||||
}
|
||||
|
||||
impl<T, S, B> Future for H2ServiceResponse<T, S, B>
|
||||
where
|
||||
T: AsyncRead + AsyncWrite + Unpin,
|
||||
S: ServiceFactory<Config = (), Request = Request>,
|
||||
S: ServiceFactory<Request, Config = ()>,
|
||||
S::Error: Into<Error> + 'static,
|
||||
S::Response: Into<Response<B>> + 'static,
|
||||
<S::Service as Service>::Future: 'static,
|
||||
<S::Service as Service<Request>>::Future: 'static,
|
||||
B: MessageBody + 'static,
|
||||
{
|
||||
type Output = Result<H2ServiceHandler<T, S::Service, B>, S::InitError>;
|
||||
|
@ -229,28 +232,31 @@ where
|
|||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let this = self.as_mut().project();
|
||||
|
||||
Poll::Ready(ready!(this.fut.poll(cx)).map(|service| {
|
||||
this.fut.poll(cx).map_ok(|service| {
|
||||
let this = self.as_mut().project();
|
||||
H2ServiceHandler::new(
|
||||
this.cfg.take().unwrap(),
|
||||
this.on_connect_ext.clone(),
|
||||
service,
|
||||
)
|
||||
}))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// `Service` implementation for http/2 transport
|
||||
pub struct H2ServiceHandler<T, S: Service, B> {
|
||||
pub struct H2ServiceHandler<T, S, B>
|
||||
where
|
||||
S: Service<Request>,
|
||||
{
|
||||
srv: CloneableService<S>,
|
||||
cfg: ServiceConfig,
|
||||
on_connect_ext: Option<Rc<ConnectCallback<T>>>,
|
||||
_t: PhantomData<(T, B)>,
|
||||
_phantom: PhantomData<B>,
|
||||
}
|
||||
|
||||
impl<T, S, B> H2ServiceHandler<T, S, B>
|
||||
where
|
||||
S: Service<Request = Request>,
|
||||
S: Service<Request>,
|
||||
S::Error: Into<Error> + 'static,
|
||||
S::Future: 'static,
|
||||
S::Response: Into<Response<B>> + 'static,
|
||||
|
@ -265,21 +271,20 @@ where
|
|||
cfg,
|
||||
on_connect_ext,
|
||||
srv: CloneableService::new(srv),
|
||||
_t: PhantomData,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, S, B> Service for H2ServiceHandler<T, S, B>
|
||||
impl<T, S, B> Service<(T, Option<net::SocketAddr>)> for H2ServiceHandler<T, S, B>
|
||||
where
|
||||
T: AsyncRead + AsyncWrite + Unpin,
|
||||
S: Service<Request = Request>,
|
||||
S: Service<Request>,
|
||||
S::Error: Into<Error> + 'static,
|
||||
S::Future: 'static,
|
||||
S::Response: Into<Response<B>> + 'static,
|
||||
B: MessageBody + 'static,
|
||||
{
|
||||
type Request = (T, Option<net::SocketAddr>);
|
||||
type Response = ();
|
||||
type Error = DispatchError;
|
||||
type Future = H2ServiceHandlerResponse<T, S, B>;
|
||||
|
@ -292,7 +297,7 @@ where
|
|||
})
|
||||
}
|
||||
|
||||
fn call(&mut self, (io, addr): Self::Request) -> Self::Future {
|
||||
fn call(&mut self, (io, addr): (T, Option<net::SocketAddr>)) -> Self::Future {
|
||||
let mut connect_extensions = Extensions::new();
|
||||
if let Some(ref handler) = self.on_connect_ext {
|
||||
// run on_connect_ext callback, populating connect extensions
|
||||
|
@ -311,7 +316,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
enum State<T, S: Service<Request = Request>, B: MessageBody>
|
||||
enum State<T, S: Service<Request>, B: MessageBody>
|
||||
where
|
||||
T: AsyncRead + AsyncWrite + Unpin,
|
||||
S::Future: 'static,
|
||||
|
@ -329,7 +334,7 @@ where
|
|||
pub struct H2ServiceHandlerResponse<T, S, B>
|
||||
where
|
||||
T: AsyncRead + AsyncWrite + Unpin,
|
||||
S: Service<Request = Request>,
|
||||
S: Service<Request>,
|
||||
S::Error: Into<Error> + 'static,
|
||||
S::Future: 'static,
|
||||
S::Response: Into<Response<B>> + 'static,
|
||||
|
@ -341,7 +346,7 @@ where
|
|||
impl<T, S, B> Future for H2ServiceHandlerResponse<T, S, B>
|
||||
where
|
||||
T: AsyncRead + AsyncWrite + Unpin,
|
||||
S: Service<Request = Request>,
|
||||
S: Service<Request>,
|
||||
S::Error: Into<Error> + 'static,
|
||||
S::Future: 'static,
|
||||
S::Response: Into<Response<B>> + 'static,
|
||||
|
@ -358,8 +363,8 @@ where
|
|||
ref peer_addr,
|
||||
ref mut on_connect_data,
|
||||
ref mut handshake,
|
||||
) => match Pin::new(handshake).poll(cx) {
|
||||
Poll::Ready(Ok(conn)) => {
|
||||
) => match ready!(Pin::new(handshake).poll(cx)) {
|
||||
Ok(conn) => {
|
||||
self.state = State::Incoming(Dispatcher::new(
|
||||
srv.take().unwrap(),
|
||||
conn,
|
||||
|
@ -370,11 +375,10 @@ where
|
|||
));
|
||||
self.poll(cx)
|
||||
}
|
||||
Poll::Ready(Err(err)) => {
|
||||
Err(err) => {
|
||||
trace!("H2 handshake error: {}", err);
|
||||
Poll::Ready(Err(err.into()))
|
||||
}
|
||||
Poll::Pending => Poll::Pending,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,8 @@ use std::io::Write;
|
|||
use std::str::FromStr;
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
use bytes::{buf::BufMutExt, BytesMut};
|
||||
use bytes::buf::BufMut;
|
||||
use bytes::BytesMut;
|
||||
use http::header::{HeaderValue, InvalidHeaderValue};
|
||||
use time::{offset, OffsetDateTime, PrimitiveDateTime};
|
||||
|
||||
|
|
|
@ -23,6 +23,10 @@ impl<P> HttpMessage for Request<P> {
|
|||
&self.head().headers
|
||||
}
|
||||
|
||||
fn take_payload(&mut self) -> Payload<P> {
|
||||
std::mem::replace(&mut self.payload, Payload::None)
|
||||
}
|
||||
|
||||
/// Request extensions
|
||||
#[inline]
|
||||
fn extensions(&self) -> Ref<'_, Extensions> {
|
||||
|
@ -34,10 +38,6 @@ impl<P> HttpMessage for Request<P> {
|
|||
fn extensions_mut(&self) -> RefMut<'_, Extensions> {
|
||||
self.head.extensions_mut()
|
||||
}
|
||||
|
||||
fn take_payload(&mut self) -> Payload<P> {
|
||||
std::mem::replace(&mut self.payload, Payload::None)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Message<RequestHead>> for Request<PayloadStream> {
|
||||
|
|
|
@ -22,22 +22,22 @@ use crate::response::Response;
|
|||
use crate::{h1, h2::Dispatcher, ConnectCallback, Extensions, Protocol};
|
||||
|
||||
/// A `ServiceFactory` for HTTP/1.1 or HTTP/2 protocol.
|
||||
pub struct HttpService<T, S, B, X = h1::ExpectHandler, U = h1::UpgradeHandler<T>> {
|
||||
pub struct HttpService<T, S, B, X = h1::ExpectHandler, U = h1::UpgradeHandler> {
|
||||
srv: S,
|
||||
cfg: ServiceConfig,
|
||||
expect: X,
|
||||
upgrade: Option<U>,
|
||||
on_connect_ext: Option<Rc<ConnectCallback<T>>>,
|
||||
_t: PhantomData<(T, B)>,
|
||||
_phantom: PhantomData<B>,
|
||||
}
|
||||
|
||||
impl<T, S, B> HttpService<T, S, B>
|
||||
where
|
||||
S: ServiceFactory<Config = (), Request = Request>,
|
||||
S: ServiceFactory<Request, Config = ()>,
|
||||
S::Error: Into<Error> + 'static,
|
||||
S::InitError: fmt::Debug,
|
||||
S::Response: Into<Response<B>> + 'static,
|
||||
<S::Service as Service>::Future: 'static,
|
||||
<S::Service as Service<Request>>::Future: 'static,
|
||||
B: MessageBody + 'static,
|
||||
{
|
||||
/// Create builder for `HttpService` instance.
|
||||
|
@ -48,15 +48,15 @@ where
|
|||
|
||||
impl<T, S, B> HttpService<T, S, B>
|
||||
where
|
||||
S: ServiceFactory<Config = (), Request = Request>,
|
||||
S: ServiceFactory<Request, Config = ()>,
|
||||
S::Error: Into<Error> + 'static,
|
||||
S::InitError: fmt::Debug,
|
||||
S::Response: Into<Response<B>> + 'static,
|
||||
<S::Service as Service>::Future: 'static,
|
||||
<S::Service as Service<Request>>::Future: 'static,
|
||||
B: MessageBody + 'static,
|
||||
{
|
||||
/// Create new `HttpService` instance.
|
||||
pub fn new<F: IntoServiceFactory<S>>(service: F) -> Self {
|
||||
pub fn new<F: IntoServiceFactory<S, Request>>(service: F) -> Self {
|
||||
let cfg = ServiceConfig::new(KeepAlive::Timeout(5), 5000, 0, false, None);
|
||||
|
||||
HttpService {
|
||||
|
@ -65,12 +65,12 @@ where
|
|||
expect: h1::ExpectHandler,
|
||||
upgrade: None,
|
||||
on_connect_ext: None,
|
||||
_t: PhantomData,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Create new `HttpService` instance with config.
|
||||
pub(crate) fn with_config<F: IntoServiceFactory<S>>(
|
||||
pub(crate) fn with_config<F: IntoServiceFactory<S, Request>>(
|
||||
cfg: ServiceConfig,
|
||||
service: F,
|
||||
) -> Self {
|
||||
|
@ -80,18 +80,18 @@ where
|
|||
expect: h1::ExpectHandler,
|
||||
upgrade: None,
|
||||
on_connect_ext: None,
|
||||
_t: PhantomData,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, S, B, X, U> HttpService<T, S, B, X, U>
|
||||
where
|
||||
S: ServiceFactory<Config = (), Request = Request>,
|
||||
S: ServiceFactory<Request, Config = ()>,
|
||||
S::Error: Into<Error> + 'static,
|
||||
S::InitError: fmt::Debug,
|
||||
S::Response: Into<Response<B>> + 'static,
|
||||
<S::Service as Service>::Future: 'static,
|
||||
<S::Service as Service<Request>>::Future: 'static,
|
||||
B: MessageBody,
|
||||
{
|
||||
/// Provide service for `EXPECT: 100-Continue` support.
|
||||
|
@ -101,10 +101,10 @@ where
|
|||
/// request will be forwarded to main service.
|
||||
pub fn expect<X1>(self, expect: X1) -> HttpService<T, S, B, X1, U>
|
||||
where
|
||||
X1: ServiceFactory<Config = (), Request = Request, Response = Request>,
|
||||
X1: ServiceFactory<Request, Config = (), Response = Request>,
|
||||
X1::Error: Into<Error>,
|
||||
X1::InitError: fmt::Debug,
|
||||
<X1::Service as Service>::Future: 'static,
|
||||
<X1::Service as Service<Request>>::Future: 'static,
|
||||
{
|
||||
HttpService {
|
||||
expect,
|
||||
|
@ -112,7 +112,7 @@ where
|
|||
srv: self.srv,
|
||||
upgrade: self.upgrade,
|
||||
on_connect_ext: self.on_connect_ext,
|
||||
_t: PhantomData,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -122,14 +122,10 @@ where
|
|||
/// and this service get called with original request and framed object.
|
||||
pub fn upgrade<U1>(self, upgrade: Option<U1>) -> HttpService<T, S, B, X, U1>
|
||||
where
|
||||
U1: ServiceFactory<
|
||||
Config = (),
|
||||
Request = (Request, Framed<T, h1::Codec>),
|
||||
Response = (),
|
||||
>,
|
||||
U1: ServiceFactory<(Request, Framed<T, h1::Codec>), Config = (), Response = ()>,
|
||||
U1::Error: fmt::Display,
|
||||
U1::InitError: fmt::Debug,
|
||||
<U1::Service as Service>::Future: 'static,
|
||||
<U1::Service as Service<(Request, Framed<T, h1::Codec>)>>::Future: 'static,
|
||||
{
|
||||
HttpService {
|
||||
upgrade,
|
||||
|
@ -137,7 +133,7 @@ where
|
|||
srv: self.srv,
|
||||
expect: self.expect,
|
||||
on_connect_ext: self.on_connect_ext,
|
||||
_t: PhantomData,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -150,31 +146,31 @@ where
|
|||
|
||||
impl<S, B, X, U> HttpService<TcpStream, S, B, X, U>
|
||||
where
|
||||
S: ServiceFactory<Config = (), Request = Request>,
|
||||
S: ServiceFactory<Request, Config = ()>,
|
||||
S::Error: Into<Error> + 'static,
|
||||
S::InitError: fmt::Debug,
|
||||
S::Response: Into<Response<B>> + 'static,
|
||||
<S::Service as Service>::Future: 'static,
|
||||
<S::Service as Service<Request>>::Future: 'static,
|
||||
B: MessageBody + 'static,
|
||||
X: ServiceFactory<Config = (), Request = Request, Response = Request>,
|
||||
X: ServiceFactory<Request, Config = (), Response = Request>,
|
||||
X::Error: Into<Error>,
|
||||
X::InitError: fmt::Debug,
|
||||
<X::Service as Service>::Future: 'static,
|
||||
<X::Service as Service<Request>>::Future: 'static,
|
||||
U: ServiceFactory<
|
||||
(Request, Framed<TcpStream, h1::Codec>),
|
||||
Config = (),
|
||||
Request = (Request, Framed<TcpStream, h1::Codec>),
|
||||
Response = (),
|
||||
>,
|
||||
U::Error: fmt::Display + Into<Error>,
|
||||
U::InitError: fmt::Debug,
|
||||
<U::Service as Service>::Future: 'static,
|
||||
<U::Service as Service<(Request, Framed<TcpStream, h1::Codec>)>>::Future: 'static,
|
||||
{
|
||||
/// Create simple tcp stream service
|
||||
pub fn tcp(
|
||||
self,
|
||||
) -> impl ServiceFactory<
|
||||
TcpStream,
|
||||
Config = (),
|
||||
Request = TcpStream,
|
||||
Response = (),
|
||||
Error = DispatchError,
|
||||
InitError = (),
|
||||
|
@ -190,39 +186,40 @@ where
|
|||
#[cfg(feature = "openssl")]
|
||||
mod openssl {
|
||||
use super::*;
|
||||
use actix_tls::openssl::{Acceptor, SslAcceptor, SslStream};
|
||||
use actix_tls::{openssl::HandshakeError, TlsError};
|
||||
use actix_service::ServiceFactoryExt;
|
||||
use actix_tls::accept::openssl::{Acceptor, SslAcceptor, SslError, SslStream};
|
||||
use actix_tls::accept::TlsError;
|
||||
|
||||
impl<S, B, X, U> HttpService<SslStream<TcpStream>, S, B, X, U>
|
||||
where
|
||||
S: ServiceFactory<Config = (), Request = Request>,
|
||||
S: ServiceFactory<Request, Config = ()>,
|
||||
S::Error: Into<Error> + 'static,
|
||||
S::InitError: fmt::Debug,
|
||||
S::Response: Into<Response<B>> + 'static,
|
||||
<S::Service as Service>::Future: 'static,
|
||||
<S::Service as Service<Request>>::Future: 'static,
|
||||
B: MessageBody + 'static,
|
||||
X: ServiceFactory<Config = (), Request = Request, Response = Request>,
|
||||
X: ServiceFactory<Request, Config = (), Response = Request>,
|
||||
X::Error: Into<Error>,
|
||||
X::InitError: fmt::Debug,
|
||||
<X::Service as Service>::Future: 'static,
|
||||
<X::Service as Service<Request>>::Future: 'static,
|
||||
U: ServiceFactory<
|
||||
(Request, Framed<SslStream<TcpStream>, h1::Codec>),
|
||||
Config = (),
|
||||
Request = (Request, Framed<SslStream<TcpStream>, h1::Codec>),
|
||||
Response = (),
|
||||
>,
|
||||
U::Error: fmt::Display + Into<Error>,
|
||||
U::InitError: fmt::Debug,
|
||||
<U::Service as Service>::Future: 'static,
|
||||
<U::Service as Service<(Request, Framed<SslStream<TcpStream>, h1::Codec>)>>::Future: 'static,
|
||||
{
|
||||
/// Create openssl based service
|
||||
pub fn openssl(
|
||||
self,
|
||||
acceptor: SslAcceptor,
|
||||
) -> impl ServiceFactory<
|
||||
TcpStream,
|
||||
Config = (),
|
||||
Request = TcpStream,
|
||||
Response = (),
|
||||
Error = TlsError<HandshakeError<TcpStream>, DispatchError>,
|
||||
Error = TlsError<SslError, DispatchError>,
|
||||
InitError = (),
|
||||
> {
|
||||
pipeline_factory(
|
||||
|
@ -250,39 +247,42 @@ mod openssl {
|
|||
|
||||
#[cfg(feature = "rustls")]
|
||||
mod rustls {
|
||||
use super::*;
|
||||
use actix_tls::rustls::{Acceptor, ServerConfig, Session, TlsStream};
|
||||
use actix_tls::TlsError;
|
||||
use std::io;
|
||||
|
||||
use actix_tls::accept::rustls::{Acceptor, ServerConfig, Session, TlsStream};
|
||||
use actix_tls::accept::TlsError;
|
||||
|
||||
use super::*;
|
||||
use actix_service::ServiceFactoryExt;
|
||||
|
||||
impl<S, B, X, U> HttpService<TlsStream<TcpStream>, S, B, X, U>
|
||||
where
|
||||
S: ServiceFactory<Config = (), Request = Request>,
|
||||
S: ServiceFactory<Request, Config = ()>,
|
||||
S::Error: Into<Error> + 'static,
|
||||
S::InitError: fmt::Debug,
|
||||
S::Response: Into<Response<B>> + 'static,
|
||||
<S::Service as Service>::Future: 'static,
|
||||
<S::Service as Service<Request>>::Future: 'static,
|
||||
B: MessageBody + 'static,
|
||||
X: ServiceFactory<Config = (), Request = Request, Response = Request>,
|
||||
X: ServiceFactory<Request, Config = (), Response = Request>,
|
||||
X::Error: Into<Error>,
|
||||
X::InitError: fmt::Debug,
|
||||
<X::Service as Service>::Future: 'static,
|
||||
<X::Service as Service<Request>>::Future: 'static,
|
||||
U: ServiceFactory<
|
||||
(Request, Framed<TlsStream<TcpStream>, h1::Codec>),
|
||||
Config = (),
|
||||
Request = (Request, Framed<TlsStream<TcpStream>, h1::Codec>),
|
||||
Response = (),
|
||||
>,
|
||||
U::Error: fmt::Display + Into<Error>,
|
||||
U::InitError: fmt::Debug,
|
||||
<U::Service as Service>::Future: 'static,
|
||||
<U::Service as Service<(Request, Framed<TlsStream<TcpStream>, h1::Codec>)>>::Future: 'static,
|
||||
{
|
||||
/// Create openssl based service
|
||||
pub fn rustls(
|
||||
self,
|
||||
mut config: ServerConfig,
|
||||
) -> impl ServiceFactory<
|
||||
TcpStream,
|
||||
Config = (),
|
||||
Request = TcpStream,
|
||||
Response = (),
|
||||
Error = TlsError<io::Error, DispatchError>,
|
||||
InitError = (),
|
||||
|
@ -313,34 +313,30 @@ mod rustls {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T, S, B, X, U> ServiceFactory for HttpService<T, S, B, X, U>
|
||||
impl<T, S, B, X, U> ServiceFactory<(T, Protocol, Option<net::SocketAddr>)>
|
||||
for HttpService<T, S, B, X, U>
|
||||
where
|
||||
T: AsyncRead + AsyncWrite + Unpin,
|
||||
S: ServiceFactory<Config = (), Request = Request>,
|
||||
S: ServiceFactory<Request, Config = ()>,
|
||||
S::Error: Into<Error> + 'static,
|
||||
S::InitError: fmt::Debug,
|
||||
S::Response: Into<Response<B>> + 'static,
|
||||
<S::Service as Service>::Future: 'static,
|
||||
<S::Service as Service<Request>>::Future: 'static,
|
||||
B: MessageBody + 'static,
|
||||
X: ServiceFactory<Config = (), Request = Request, Response = Request>,
|
||||
X: ServiceFactory<Request, Config = (), Response = Request>,
|
||||
X::Error: Into<Error>,
|
||||
X::InitError: fmt::Debug,
|
||||
<X::Service as Service>::Future: 'static,
|
||||
U: ServiceFactory<
|
||||
Config = (),
|
||||
Request = (Request, Framed<T, h1::Codec>),
|
||||
Response = (),
|
||||
>,
|
||||
<X::Service as Service<Request>>::Future: 'static,
|
||||
U: ServiceFactory<(Request, Framed<T, h1::Codec>), Config = (), Response = ()>,
|
||||
U::Error: fmt::Display + Into<Error>,
|
||||
U::InitError: fmt::Debug,
|
||||
<U::Service as Service>::Future: 'static,
|
||||
<U::Service as Service<(Request, Framed<T, h1::Codec>)>>::Future: 'static,
|
||||
{
|
||||
type Config = ();
|
||||
type Request = (T, Protocol, Option<net::SocketAddr>);
|
||||
type Response = ();
|
||||
type Error = DispatchError;
|
||||
type InitError = ();
|
||||
type Config = ();
|
||||
type Service = HttpServiceHandler<T, S::Service, B, X::Service, U::Service>;
|
||||
type InitError = ();
|
||||
type Future = HttpServiceResponse<T, S, B, X, U>;
|
||||
|
||||
fn new_service(&self, _: ()) -> Self::Future {
|
||||
|
@ -352,20 +348,19 @@ where
|
|||
upgrade: None,
|
||||
on_connect_ext: self.on_connect_ext.clone(),
|
||||
cfg: self.cfg.clone(),
|
||||
_t: PhantomData,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[pin_project]
|
||||
pub struct HttpServiceResponse<
|
||||
T,
|
||||
S: ServiceFactory,
|
||||
B,
|
||||
X: ServiceFactory,
|
||||
U: ServiceFactory,
|
||||
> {
|
||||
pub struct HttpServiceResponse<T, S, B, X, U>
|
||||
where
|
||||
S: ServiceFactory<Request>,
|
||||
X: ServiceFactory<Request>,
|
||||
U: ServiceFactory<(Request, Framed<T, h1::Codec>)>,
|
||||
{
|
||||
#[pin]
|
||||
fut: S::Future,
|
||||
#[pin]
|
||||
|
@ -376,26 +371,26 @@ pub struct HttpServiceResponse<
|
|||
upgrade: Option<U::Service>,
|
||||
on_connect_ext: Option<Rc<ConnectCallback<T>>>,
|
||||
cfg: ServiceConfig,
|
||||
_t: PhantomData<(T, B)>,
|
||||
_phantom: PhantomData<(T, B)>,
|
||||
}
|
||||
|
||||
impl<T, S, B, X, U> Future for HttpServiceResponse<T, S, B, X, U>
|
||||
where
|
||||
T: AsyncRead + AsyncWrite + Unpin,
|
||||
S: ServiceFactory<Request = Request>,
|
||||
S: ServiceFactory<Request>,
|
||||
S::Error: Into<Error> + 'static,
|
||||
S::InitError: fmt::Debug,
|
||||
S::Response: Into<Response<B>> + 'static,
|
||||
<S::Service as Service>::Future: 'static,
|
||||
<S::Service as Service<Request>>::Future: 'static,
|
||||
B: MessageBody + 'static,
|
||||
X: ServiceFactory<Request = Request, Response = Request>,
|
||||
X: ServiceFactory<Request, Response = Request>,
|
||||
X::Error: Into<Error>,
|
||||
X::InitError: fmt::Debug,
|
||||
<X::Service as Service>::Future: 'static,
|
||||
U: ServiceFactory<Request = (Request, Framed<T, h1::Codec>), Response = ()>,
|
||||
<X::Service as Service<Request>>::Future: 'static,
|
||||
U: ServiceFactory<(Request, Framed<T, h1::Codec>), Response = ()>,
|
||||
U::Error: fmt::Display,
|
||||
U::InitError: fmt::Debug,
|
||||
<U::Service as Service>::Future: 'static,
|
||||
<U::Service as Service<(Request, Framed<T, h1::Codec>)>>::Future: 'static,
|
||||
{
|
||||
type Output =
|
||||
Result<HttpServiceHandler<T, S::Service, B, X::Service, U::Service>, ()>;
|
||||
|
@ -440,25 +435,30 @@ where
|
|||
}
|
||||
|
||||
/// `Service` implementation for http transport
|
||||
pub struct HttpServiceHandler<T, S: Service, B, X: Service, U: Service> {
|
||||
pub struct HttpServiceHandler<T, S, B, X, U>
|
||||
where
|
||||
S: Service<Request>,
|
||||
X: Service<Request>,
|
||||
U: Service<(Request, Framed<T, h1::Codec>)>,
|
||||
{
|
||||
srv: CloneableService<S>,
|
||||
expect: CloneableService<X>,
|
||||
upgrade: Option<CloneableService<U>>,
|
||||
cfg: ServiceConfig,
|
||||
on_connect_ext: Option<Rc<ConnectCallback<T>>>,
|
||||
_t: PhantomData<(T, B, X)>,
|
||||
_phantom: PhantomData<B>,
|
||||
}
|
||||
|
||||
impl<T, S, B, X, U> HttpServiceHandler<T, S, B, X, U>
|
||||
where
|
||||
S: Service<Request = Request>,
|
||||
S: Service<Request>,
|
||||
S::Error: Into<Error> + 'static,
|
||||
S::Future: 'static,
|
||||
S::Response: Into<Response<B>> + 'static,
|
||||
B: MessageBody + 'static,
|
||||
X: Service<Request = Request, Response = Request>,
|
||||
X: Service<Request, Response = Request>,
|
||||
X::Error: Into<Error>,
|
||||
U: Service<Request = (Request, Framed<T, h1::Codec>), Response = ()>,
|
||||
U: Service<(Request, Framed<T, h1::Codec>), Response = ()>,
|
||||
U::Error: fmt::Display,
|
||||
{
|
||||
fn new(
|
||||
|
@ -474,25 +474,25 @@ where
|
|||
srv: CloneableService::new(srv),
|
||||
expect: CloneableService::new(expect),
|
||||
upgrade: upgrade.map(CloneableService::new),
|
||||
_t: PhantomData,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, S, B, X, U> Service for HttpServiceHandler<T, S, B, X, U>
|
||||
impl<T, S, B, X, U> Service<(T, Protocol, Option<net::SocketAddr>)>
|
||||
for HttpServiceHandler<T, S, B, X, U>
|
||||
where
|
||||
T: AsyncRead + AsyncWrite + Unpin,
|
||||
S: Service<Request = Request>,
|
||||
S: Service<Request>,
|
||||
S::Error: Into<Error> + 'static,
|
||||
S::Future: 'static,
|
||||
S::Response: Into<Response<B>> + 'static,
|
||||
B: MessageBody + 'static,
|
||||
X: Service<Request = Request, Response = Request>,
|
||||
X: Service<Request, Response = Request>,
|
||||
X::Error: Into<Error>,
|
||||
U: Service<Request = (Request, Framed<T, h1::Codec>), Response = ()>,
|
||||
U: Service<(Request, Framed<T, h1::Codec>), Response = ()>,
|
||||
U::Error: fmt::Display + Into<Error>,
|
||||
{
|
||||
type Request = (T, Protocol, Option<net::SocketAddr>);
|
||||
type Response = ();
|
||||
type Error = DispatchError;
|
||||
type Future = HttpServiceHandlerResponse<T, S, B, X, U>;
|
||||
|
@ -539,7 +539,10 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
fn call(&mut self, (io, proto, peer_addr): Self::Request) -> Self::Future {
|
||||
fn call(
|
||||
&mut self,
|
||||
(io, proto, peer_addr): (T, Protocol, Option<net::SocketAddr>),
|
||||
) -> Self::Future {
|
||||
let mut connect_extensions = Extensions::new();
|
||||
|
||||
if let Some(ref handler) = self.on_connect_ext {
|
||||
|
@ -575,14 +578,14 @@ where
|
|||
#[pin_project(project = StateProj)]
|
||||
enum State<T, S, B, X, U>
|
||||
where
|
||||
S: Service<Request = Request>,
|
||||
S: Service<Request>,
|
||||
S::Future: 'static,
|
||||
S::Error: Into<Error>,
|
||||
T: AsyncRead + AsyncWrite + Unpin,
|
||||
B: MessageBody,
|
||||
X: Service<Request = Request, Response = Request>,
|
||||
X: Service<Request, Response = Request>,
|
||||
X::Error: Into<Error>,
|
||||
U: Service<Request = (Request, Framed<T, h1::Codec>), Response = ()>,
|
||||
U: Service<(Request, Framed<T, h1::Codec>), Response = ()>,
|
||||
U::Error: fmt::Display,
|
||||
{
|
||||
H1(#[pin] h1::Dispatcher<T, S, B, X, U>),
|
||||
|
@ -602,14 +605,14 @@ where
|
|||
pub struct HttpServiceHandlerResponse<T, S, B, X, U>
|
||||
where
|
||||
T: AsyncRead + AsyncWrite + Unpin,
|
||||
S: Service<Request = Request>,
|
||||
S: Service<Request>,
|
||||
S::Error: Into<Error> + 'static,
|
||||
S::Future: 'static,
|
||||
S::Response: Into<Response<B>> + 'static,
|
||||
B: MessageBody + 'static,
|
||||
X: Service<Request = Request, Response = Request>,
|
||||
X: Service<Request, Response = Request>,
|
||||
X::Error: Into<Error>,
|
||||
U: Service<Request = (Request, Framed<T, h1::Codec>), Response = ()>,
|
||||
U: Service<(Request, Framed<T, h1::Codec>), Response = ()>,
|
||||
U::Error: fmt::Display,
|
||||
{
|
||||
#[pin]
|
||||
|
@ -619,14 +622,14 @@ where
|
|||
impl<T, S, B, X, U> Future for HttpServiceHandlerResponse<T, S, B, X, U>
|
||||
where
|
||||
T: AsyncRead + AsyncWrite + Unpin,
|
||||
S: Service<Request = Request>,
|
||||
S: Service<Request>,
|
||||
S::Error: Into<Error> + 'static,
|
||||
S::Future: 'static,
|
||||
S::Response: Into<Response<B>> + 'static,
|
||||
B: MessageBody,
|
||||
X: Service<Request = Request, Response = Request>,
|
||||
X: Service<Request, Response = Request>,
|
||||
X::Error: Into<Error>,
|
||||
U: Service<Request = (Request, Framed<T, h1::Codec>), Response = ()>,
|
||||
U: Service<(Request, Framed<T, h1::Codec>), Response = ()>,
|
||||
U::Error: fmt::Display,
|
||||
{
|
||||
type Output = Result<(), DispatchError>;
|
||||
|
@ -639,13 +642,13 @@ where
|
|||
impl<T, S, B, X, U> State<T, S, B, X, U>
|
||||
where
|
||||
T: AsyncRead + AsyncWrite + Unpin,
|
||||
S: Service<Request = Request>,
|
||||
S: Service<Request>,
|
||||
S::Error: Into<Error> + 'static,
|
||||
S::Response: Into<Response<B>> + 'static,
|
||||
B: MessageBody + 'static,
|
||||
X: Service<Request = Request, Response = Request>,
|
||||
X: Service<Request, Response = Request>,
|
||||
X::Error: Into<Error>,
|
||||
U: Service<Request = (Request, Framed<T, h1::Codec>), Response = ()>,
|
||||
U: Service<(Request, Framed<T, h1::Codec>), Response = ()>,
|
||||
U::Error: fmt::Display,
|
||||
{
|
||||
fn poll(
|
||||
|
|
|
@ -10,7 +10,7 @@ use std::{
|
|||
task::{Context, Poll},
|
||||
};
|
||||
|
||||
use actix_codec::{AsyncRead, AsyncWrite};
|
||||
use actix_codec::{AsyncRead, AsyncWrite, ReadBuf};
|
||||
use bytes::{Bytes, BytesMut};
|
||||
use http::header::{self, HeaderName, HeaderValue};
|
||||
use http::{Error as HttpError, Method, Uri, Version};
|
||||
|
@ -251,9 +251,11 @@ impl AsyncRead for TestBuffer {
|
|||
fn poll_read(
|
||||
self: Pin<&mut Self>,
|
||||
_: &mut Context<'_>,
|
||||
buf: &mut [u8],
|
||||
) -> Poll<io::Result<usize>> {
|
||||
Poll::Ready(self.get_mut().read(buf))
|
||||
buf: &mut ReadBuf<'_>,
|
||||
) -> Poll<io::Result<()>> {
|
||||
let dst = buf.initialize_unfilled();
|
||||
let res = self.get_mut().read(dst).map(|n| buf.advance(n));
|
||||
Poll::Ready(res)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -356,11 +358,15 @@ impl AsyncRead for TestSeqBuffer {
|
|||
fn poll_read(
|
||||
self: Pin<&mut Self>,
|
||||
_: &mut Context<'_>,
|
||||
buf: &mut [u8],
|
||||
) -> Poll<io::Result<usize>> {
|
||||
let r = self.get_mut().read(buf);
|
||||
buf: &mut ReadBuf<'_>,
|
||||
) -> Poll<io::Result<()>> {
|
||||
let dst = buf.initialize_unfilled();
|
||||
let r = self.get_mut().read(dst);
|
||||
match r {
|
||||
Ok(n) => Poll::Ready(Ok(n)),
|
||||
Ok(n) => {
|
||||
buf.advance(n);
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
Err(err) if err.kind() == io::ErrorKind::WouldBlock => Poll::Pending,
|
||||
Err(err) => Poll::Ready(Err(err)),
|
||||
}
|
||||
|
|
|
@ -184,7 +184,7 @@ impl Encoder<Message> for Codec {
|
|||
}
|
||||
}
|
||||
},
|
||||
Message::Nop => (),
|
||||
Message::Nop => {}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ use super::{Codec, Frame, Message};
|
|||
#[pin_project::pin_project]
|
||||
pub struct Dispatcher<S, T>
|
||||
where
|
||||
S: Service<Request = Frame, Response = Message> + 'static,
|
||||
S: Service<Frame, Response = Message> + 'static,
|
||||
T: AsyncRead + AsyncWrite,
|
||||
{
|
||||
#[pin]
|
||||
|
@ -21,17 +21,17 @@ where
|
|||
impl<S, T> Dispatcher<S, T>
|
||||
where
|
||||
T: AsyncRead + AsyncWrite,
|
||||
S: Service<Request = Frame, Response = Message>,
|
||||
S: Service<Frame, Response = Message>,
|
||||
S::Future: 'static,
|
||||
S::Error: 'static,
|
||||
{
|
||||
pub fn new<F: IntoService<S>>(io: T, service: F) -> Self {
|
||||
pub fn new<F: IntoService<S, Frame>>(io: T, service: F) -> Self {
|
||||
Dispatcher {
|
||||
inner: InnerDispatcher::new(Framed::new(io, Codec::new()), service),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with<F: IntoService<S>>(framed: Framed<T, Codec>, service: F) -> Self {
|
||||
pub fn with<F: IntoService<S, Frame>>(framed: Framed<T, Codec>, service: F) -> Self {
|
||||
Dispatcher {
|
||||
inner: InnerDispatcher::new(framed, service),
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ where
|
|||
impl<S, T> Future for Dispatcher<S, T>
|
||||
where
|
||||
T: AsyncRead + AsyncWrite,
|
||||
S: Service<Request = Frame, Response = Message>,
|
||||
S: Service<Frame, Response = Message>,
|
||||
S::Future: 'static,
|
||||
S::Error: 'static,
|
||||
{
|
||||
|
|
|
@ -125,7 +125,7 @@ impl Parser {
|
|||
debug!("Received close frame with payload length exceeding 125. Morphing to protocol close frame.");
|
||||
return Ok(Some((true, OpCode::Close, None)));
|
||||
}
|
||||
_ => (),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// unmask
|
||||
|
|
|
@ -222,7 +222,7 @@ mod test {
|
|||
macro_rules! opcode_into {
|
||||
($from:expr => $opcode:pat) => {
|
||||
match OpCode::from($from) {
|
||||
e @ $opcode => (),
|
||||
e @ $opcode => {}
|
||||
e => unreachable!("{:?}", e),
|
||||
}
|
||||
};
|
||||
|
@ -232,7 +232,7 @@ mod test {
|
|||
($from:expr => $opcode:pat) => {
|
||||
let res: u8 = $from.into();
|
||||
match res {
|
||||
e @ $opcode => (),
|
||||
e @ $opcode => {}
|
||||
e => unreachable!("{:?}", e),
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
use actix_service::ServiceFactory;
|
||||
use bytes::Bytes;
|
||||
use futures_util::future::{self, ok};
|
||||
|
||||
use actix_http::{http, HttpService, Request, Response};
|
||||
use actix_http_test::test_server;
|
||||
use actix_service::ServiceFactoryExt;
|
||||
use bytes::Bytes;
|
||||
use futures_util::future::{self, ok};
|
||||
|
||||
const STR: &str = "Hello World Hello World Hello World Hello World Hello World \
|
||||
Hello World Hello World Hello World Hello World Hello World \
|
||||
|
|
|
@ -1,19 +1,17 @@
|
|||
#![cfg(feature = "openssl")]
|
||||
use std::io;
|
||||
|
||||
use actix_http_test::test_server;
|
||||
use actix_service::{fn_service, ServiceFactory};
|
||||
|
||||
use bytes::{Bytes, BytesMut};
|
||||
use futures_util::future::{err, ok, ready};
|
||||
use futures_util::stream::{once, Stream, StreamExt};
|
||||
use open_ssl::ssl::{AlpnError, SslAcceptor, SslFiletype, SslMethod};
|
||||
|
||||
use actix_http::error::{ErrorBadRequest, PayloadError};
|
||||
use actix_http::http::header::{self, HeaderName, HeaderValue};
|
||||
use actix_http::http::{Method, StatusCode, Version};
|
||||
use actix_http::httpmessage::HttpMessage;
|
||||
use actix_http::{body, Error, HttpService, Request, Response};
|
||||
use actix_http_test::test_server;
|
||||
use actix_service::{fn_service, ServiceFactoryExt};
|
||||
use bytes::{Bytes, BytesMut};
|
||||
use futures_util::future::{err, ok, ready};
|
||||
use futures_util::stream::{once, Stream, StreamExt};
|
||||
use open_ssl::ssl::{AlpnError, SslAcceptor, SslFiletype, SslMethod};
|
||||
|
||||
async fn load_body<S>(stream: S) -> Result<BytesMut, PayloadError>
|
||||
where
|
||||
|
|
|
@ -3,7 +3,7 @@ use std::time::Duration;
|
|||
use std::{net, thread};
|
||||
|
||||
use actix_http_test::test_server;
|
||||
use actix_rt::time::delay_for;
|
||||
use actix_rt::time::sleep;
|
||||
use actix_service::fn_service;
|
||||
use bytes::Bytes;
|
||||
use futures_util::future::{self, err, ok, ready, FutureExt};
|
||||
|
@ -88,7 +88,7 @@ async fn test_expect_continue_h1() {
|
|||
let srv = test_server(|| {
|
||||
HttpService::build()
|
||||
.expect(fn_service(|req: Request| {
|
||||
delay_for(Duration::from_millis(20)).then(move |_| {
|
||||
sleep(Duration::from_millis(20)).then(move |_| {
|
||||
if req.head().uri.query() == Some("yes=") {
|
||||
ok(req)
|
||||
} else {
|
||||
|
|
|
@ -36,11 +36,10 @@ impl<T> Clone for WsService<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T> Service for WsService<T>
|
||||
impl<T> Service<(Request, Framed<T, h1::Codec>)> for WsService<T>
|
||||
where
|
||||
T: AsyncRead + AsyncWrite + Unpin + 'static,
|
||||
{
|
||||
type Request = (Request, Framed<T, h1::Codec>);
|
||||
type Response = ();
|
||||
type Error = Error;
|
||||
type Future = Pin<Box<dyn Future<Output = Result<(), Error>>>>;
|
||||
|
@ -50,7 +49,10 @@ where
|
|||
Poll::Ready(Ok(()))
|
||||
}
|
||||
|
||||
fn call(&mut self, (req, mut framed): Self::Request) -> Self::Future {
|
||||
fn call(
|
||||
&mut self,
|
||||
(req, mut framed): (Request, Framed<T, h1::Codec>),
|
||||
) -> Self::Future {
|
||||
let fut = async move {
|
||||
let res = ws::handshake(req.head()).unwrap().message_body(());
|
||||
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
# Changes
|
||||
|
||||
## Unreleased - 2020-xx-xx
|
||||
## Unreleased - 2021-xx-xx
|
||||
* Fix multipart consuming payload before header checks #1513
|
||||
* Update `bytes` to `1.0`. [#1813]
|
||||
|
||||
[#1813]: https://github.com/actix/actix-web/pull/1813
|
||||
|
||||
|
||||
## 3.0.0 - 2020-09-11
|
||||
|
|
|
@ -17,16 +17,16 @@ path = "src/lib.rs"
|
|||
|
||||
[dependencies]
|
||||
actix-web = { version = "3.0.0", default-features = false }
|
||||
actix-service = "1.0.6"
|
||||
actix-utils = "2.0.0"
|
||||
bytes = "0.5.3"
|
||||
actix-utils = "3.0.0-beta.1"
|
||||
|
||||
bytes = "1"
|
||||
derive_more = "0.99.2"
|
||||
httparse = "1.3"
|
||||
futures-util = { version = "0.3.5", default-features = false }
|
||||
futures-util = { version = "0.3.7", default-features = false }
|
||||
log = "0.4"
|
||||
mime = "0.3"
|
||||
twoway = "0.2"
|
||||
|
||||
[dev-dependencies]
|
||||
actix-rt = "1.0.0"
|
||||
actix-rt = "2.0.0-beta.1"
|
||||
actix-http = "2.0.0"
|
||||
|
|
|
@ -326,7 +326,7 @@ impl InnerMultipart {
|
|||
}
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// read field headers for next field
|
||||
|
@ -835,7 +835,7 @@ mod tests {
|
|||
async fn test_boundary() {
|
||||
let headers = HeaderMap::new();
|
||||
match Multipart::boundary(&headers) {
|
||||
Err(MultipartError::NoContentType) => (),
|
||||
Err(MultipartError::NoContentType) => {}
|
||||
_ => unreachable!("should not happen"),
|
||||
}
|
||||
|
||||
|
@ -846,7 +846,7 @@ mod tests {
|
|||
);
|
||||
|
||||
match Multipart::boundary(&headers) {
|
||||
Err(MultipartError::ParseContentType) => (),
|
||||
Err(MultipartError::ParseContentType) => {}
|
||||
_ => unreachable!("should not happen"),
|
||||
}
|
||||
|
||||
|
@ -856,7 +856,7 @@ mod tests {
|
|||
header::HeaderValue::from_static("multipart/mixed"),
|
||||
);
|
||||
match Multipart::boundary(&headers) {
|
||||
Err(MultipartError::Boundary) => (),
|
||||
Err(MultipartError::Boundary) => {}
|
||||
_ => unreachable!("should not happen"),
|
||||
}
|
||||
|
||||
|
@ -956,17 +956,17 @@ mod tests {
|
|||
let mut multipart = Multipart::new(&headers, payload);
|
||||
|
||||
match multipart.next().await.unwrap() {
|
||||
Ok(_) => (),
|
||||
Ok(_) => {}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
match multipart.next().await.unwrap() {
|
||||
Ok(_) => (),
|
||||
Ok(_) => {}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
match multipart.next().await {
|
||||
None => (),
|
||||
None => {}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
@ -993,7 +993,7 @@ mod tests {
|
|||
_ => unreachable!(),
|
||||
}
|
||||
match field.next().await {
|
||||
None => (),
|
||||
None => {}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
@ -1010,7 +1010,7 @@ mod tests {
|
|||
_ => unreachable!(),
|
||||
}
|
||||
match field.next().await {
|
||||
None => (),
|
||||
None => {}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
@ -1018,7 +1018,7 @@ mod tests {
|
|||
}
|
||||
|
||||
match multipart.next().await {
|
||||
None => (),
|
||||
None => {}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
@ -1066,7 +1066,7 @@ mod tests {
|
|||
}
|
||||
|
||||
match multipart.next().await {
|
||||
None => (),
|
||||
None => {}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
# Changes
|
||||
|
||||
## Unreleased - 2020-xx-xx
|
||||
* Upgrade `pin-project` to `1.0`.
|
||||
## Unreleased - 2021-xx-xx
|
||||
* Update `pin-project` to `1.0`.
|
||||
* Update `bytes` to `1.0`. [#1813]
|
||||
|
||||
[#1813]: https://github.com/actix/actix-web/pull/1813
|
||||
|
||||
## 3.0.0 - 2020-09-11
|
||||
* No significant changes from `3.0.0-beta.2`.
|
||||
|
|
|
@ -16,16 +16,17 @@ name = "actix_web_actors"
|
|||
path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
actix = "0.10.0"
|
||||
actix-web = { version = "3.0.0", default-features = false }
|
||||
actix = "0.11.0-beta.1"
|
||||
actix-codec = "0.4.0-beta.1"
|
||||
actix-http = "2.0.0"
|
||||
actix-codec = "0.3.0"
|
||||
bytes = "0.5.2"
|
||||
futures-channel = { version = "0.3.5", default-features = false }
|
||||
futures-core = { version = "0.3.5", default-features = false }
|
||||
actix-web = { version = "3.0.0", default-features = false }
|
||||
|
||||
bytes = "1"
|
||||
futures-core = { version = "0.3.7", default-features = false }
|
||||
pin-project = "1.0.0"
|
||||
tokio = { version = "1", features = ["sync"] }
|
||||
|
||||
[dev-dependencies]
|
||||
actix-rt = "1.1.1"
|
||||
actix-rt = "2.0.0-beta.1"
|
||||
env_logger = "0.7"
|
||||
futures-util = { version = "0.3.5", default-features = false }
|
||||
futures-util = { version = "0.3.7", default-features = false }
|
||||
|
|
|
@ -12,8 +12,8 @@ use actix::{
|
|||
};
|
||||
use actix_web::error::Error;
|
||||
use bytes::Bytes;
|
||||
use futures_channel::oneshot::Sender;
|
||||
use futures_core::Stream;
|
||||
use tokio::sync::oneshot::Sender;
|
||||
|
||||
/// Execution context for http actors
|
||||
pub struct HttpContext<A>
|
||||
|
|
|
@ -24,8 +24,8 @@ use actix_web::error::{Error, PayloadError};
|
|||
use actix_web::http::{header, Method, StatusCode};
|
||||
use actix_web::{HttpRequest, HttpResponse};
|
||||
use bytes::{Bytes, BytesMut};
|
||||
use futures_channel::oneshot::Sender;
|
||||
use futures_core::Stream;
|
||||
use tokio::sync::oneshot::Sender;
|
||||
|
||||
/// Do websocket handshake and start ws actor.
|
||||
pub fn start<A, T>(actor: A, req: &HttpRequest, stream: T) -> Result<HttpResponse, Error>
|
||||
|
|
|
@ -21,7 +21,7 @@ impl StreamHandler<Result<ws::Message, ws::ProtocolError>> for Ws {
|
|||
ws::Message::Text(text) => ctx.text(text),
|
||||
ws::Message::Binary(bin) => ctx.binary(bin),
|
||||
ws::Message::Close(reason) => ctx.close(reason),
|
||||
_ => (),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# Changes
|
||||
|
||||
## Unreleased - 2020-xx-xx
|
||||
## Unreleased - 2021-xx-xx
|
||||
|
||||
|
||||
## 0.4.0 - 2020-09-20
|
||||
|
|
|
@ -19,8 +19,8 @@ syn = { version = "1", features = ["full", "parsing"] }
|
|||
proc-macro2 = "1"
|
||||
|
||||
[dev-dependencies]
|
||||
actix-rt = "1.1.1"
|
||||
actix-rt = "2.0.0-beta.1"
|
||||
actix-web = "3.0.0"
|
||||
futures-util = { version = "0.3.5", default-features = false }
|
||||
futures-util = { version = "0.3.7", default-features = false }
|
||||
trybuild = "1"
|
||||
rustversion = "1"
|
||||
|
|
|
@ -88,17 +88,16 @@ async fn route_test() -> impl Responder {
|
|||
|
||||
pub struct ChangeStatusCode;
|
||||
|
||||
impl<S, B> Transform<S> for ChangeStatusCode
|
||||
impl<S, B> Transform<S, ServiceRequest> for ChangeStatusCode
|
||||
where
|
||||
S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
||||
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
||||
S::Future: 'static,
|
||||
B: 'static,
|
||||
{
|
||||
type Request = ServiceRequest;
|
||||
type Response = ServiceResponse<B>;
|
||||
type Error = Error;
|
||||
type InitError = ();
|
||||
type Transform = ChangeStatusCodeMiddleware<S>;
|
||||
type InitError = ();
|
||||
type Future = future::Ready<Result<Self::Transform, Self::InitError>>;
|
||||
|
||||
fn new_transform(&self, service: S) -> Self::Future {
|
||||
|
@ -110,13 +109,12 @@ pub struct ChangeStatusCodeMiddleware<S> {
|
|||
service: S,
|
||||
}
|
||||
|
||||
impl<S, B> Service for ChangeStatusCodeMiddleware<S>
|
||||
impl<S, B> Service<ServiceRequest> for ChangeStatusCodeMiddleware<S>
|
||||
where
|
||||
S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
||||
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
||||
S::Future: 'static,
|
||||
B: 'static,
|
||||
{
|
||||
type Request = ServiceRequest;
|
||||
type Response = ServiceResponse<B>;
|
||||
type Error = Error;
|
||||
#[allow(clippy::type_complexity)]
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
# Changes
|
||||
|
||||
## Unreleased - 2020-xx-xx
|
||||
## Unreleased - 2021-xx-xx
|
||||
### Changed
|
||||
* Bumped `rand` to `0.8`
|
||||
* Update `rand` to `0.8`
|
||||
* Update `bytes` to `1.0`. [#1813]
|
||||
* Update `rust-tls` to `0.19`. [#1813]
|
||||
|
||||
[#1813]: https://github.com/actix/actix-web/pull/1813
|
||||
|
||||
|
||||
## 2.0.3 - 2020-11-29
|
||||
|
|
|
@ -37,16 +37,16 @@ rustls = ["rust-tls", "actix-http/rustls"]
|
|||
compress = ["actix-http/compress"]
|
||||
|
||||
[dependencies]
|
||||
actix-codec = "0.3.0"
|
||||
actix-service = "1.0.6"
|
||||
actix-codec = "0.4.0-beta.1"
|
||||
actix-service = "2.0.0-beta.2"
|
||||
actix-http = "2.2.0"
|
||||
actix-rt = "1.0.0"
|
||||
actix-rt = "2.0.0-beta.1"
|
||||
|
||||
base64 = "0.13"
|
||||
bytes = "0.5.3"
|
||||
bytes = "1"
|
||||
cfg-if = "1.0"
|
||||
derive_more = "0.99.2"
|
||||
futures-core = { version = "0.3.5", default-features = false }
|
||||
futures-core = { version = "0.3.7", default-features = false }
|
||||
log =" 0.4"
|
||||
mime = "0.3"
|
||||
percent-encoding = "2.1"
|
||||
|
@ -55,18 +55,20 @@ serde = "1.0"
|
|||
serde_json = "1.0"
|
||||
serde_urlencoded = "0.7"
|
||||
open-ssl = { version = "0.10", package = "openssl", optional = true }
|
||||
rust-tls = { version = "0.18.0", package = "rustls", optional = true, features = ["dangerous_configuration"] }
|
||||
rust-tls = { version = "0.19.0", package = "rustls", optional = true, features = ["dangerous_configuration"] }
|
||||
|
||||
[dev-dependencies]
|
||||
actix-connect = { version = "2.0.0", features = ["openssl"] }
|
||||
# TODO: actix is temporary added as dev dep for actix-macro reason.
|
||||
# Can be removed when it does not impact tests.
|
||||
actix = "0.11.0-beta.1"
|
||||
actix-web = { version = "3.0.0", features = ["openssl"] }
|
||||
actix-http = { version = "2.0.0", features = ["openssl"] }
|
||||
actix-http-test = { version = "2.0.0", features = ["openssl"] }
|
||||
actix-utils = "2.0.0"
|
||||
actix-server = "1.0.0"
|
||||
actix-tls = { version = "2.0.0", features = ["openssl", "rustls"] }
|
||||
actix-utils = "3.0.0-beta.1"
|
||||
actix-server = "2.0.0-beta.2"
|
||||
actix-tls = { version = "3.0.0-beta.2", features = ["openssl", "rustls"] }
|
||||
brotli2 = "0.3.2"
|
||||
flate2 = "1.0.13"
|
||||
futures-util = { version = "0.3.5", default-features = false }
|
||||
futures-util = { version = "0.3.7", default-features = false }
|
||||
env_logger = "0.7"
|
||||
webpki = "0.21"
|
||||
|
|
|
@ -51,7 +51,7 @@ impl ClientBuilder {
|
|||
/// Use custom connector service.
|
||||
pub fn connector<T>(mut self, connector: T) -> Self
|
||||
where
|
||||
T: Service<Request = HttpConnect, Error = ConnectError> + 'static,
|
||||
T: Service<HttpConnect, Error = ConnectError> + 'static,
|
||||
T::Response: Connection,
|
||||
<T::Response as Connection>::Future: 'static,
|
||||
T::Future: 'static,
|
||||
|
|
|
@ -2,9 +2,9 @@ use std::future::Future;
|
|||
use std::pin::Pin;
|
||||
use std::rc::Rc;
|
||||
use std::task::{Context, Poll};
|
||||
use std::{fmt, io, mem, net};
|
||||
use std::{fmt, io, net};
|
||||
|
||||
use actix_codec::{AsyncRead, AsyncWrite, Framed};
|
||||
use actix_codec::{AsyncRead, AsyncWrite, Framed, ReadBuf};
|
||||
use actix_http::body::Body;
|
||||
use actix_http::client::{
|
||||
Connect as ClientConnect, ConnectError, Connection, SendRequestError,
|
||||
|
@ -70,7 +70,7 @@ pub(crate) trait Connect {
|
|||
|
||||
impl<T> Connect for ConnectorWrapper<T>
|
||||
where
|
||||
T: Service<Request = ClientConnect, Error = ConnectError>,
|
||||
T: Service<ClientConnect, Error = ConnectError>,
|
||||
T::Response: Connection,
|
||||
<T::Response as Connection>::Io: 'static,
|
||||
<T::Response as Connection>::Future: 'static,
|
||||
|
@ -221,18 +221,11 @@ impl fmt::Debug for BoxedSocket {
|
|||
}
|
||||
|
||||
impl AsyncRead for BoxedSocket {
|
||||
unsafe fn prepare_uninitialized_buffer(
|
||||
&self,
|
||||
buf: &mut [mem::MaybeUninit<u8>],
|
||||
) -> bool {
|
||||
self.0.as_read().prepare_uninitialized_buffer(buf)
|
||||
}
|
||||
|
||||
fn poll_read(
|
||||
self: Pin<&mut Self>,
|
||||
cx: &mut Context<'_>,
|
||||
buf: &mut [u8],
|
||||
) -> Poll<io::Result<usize>> {
|
||||
buf: &mut ReadBuf<'_>,
|
||||
) -> Poll<io::Result<()>> {
|
||||
Pin::new(self.get_mut().0.as_read_mut()).poll_read(cx, buf)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -523,7 +523,7 @@ impl ClientRequest {
|
|||
return Err(InvalidUrl::MissingScheme.into());
|
||||
} else if let Some(scheme) = uri.scheme() {
|
||||
match scheme.as_str() {
|
||||
"http" | "ws" | "https" | "wss" => (),
|
||||
"http" | "ws" | "https" | "wss" => {}
|
||||
_ => return Err(InvalidUrl::UnknownScheme.into()),
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -234,7 +234,7 @@ pub struct JsonBody<S, U> {
|
|||
length: Option<usize>,
|
||||
err: Option<JsonPayloadError>,
|
||||
fut: Option<ReadBody<S>>,
|
||||
_t: PhantomData<U>,
|
||||
_phantom: PhantomData<U>,
|
||||
}
|
||||
|
||||
impl<S, U> JsonBody<S, U>
|
||||
|
@ -255,7 +255,7 @@ where
|
|||
length: None,
|
||||
fut: None,
|
||||
err: Some(JsonPayloadError::ContentType),
|
||||
_t: PhantomData,
|
||||
_phantom: PhantomData,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -272,7 +272,7 @@ where
|
|||
length: len,
|
||||
err: None,
|
||||
fut: Some(ReadBody::new(req.take_payload(), 65536)),
|
||||
_t: PhantomData,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -370,14 +370,14 @@ mod tests {
|
|||
async fn test_body() {
|
||||
let mut req = TestResponse::with_header(header::CONTENT_LENGTH, "xxxx").finish();
|
||||
match req.body().await.err().unwrap() {
|
||||
PayloadError::UnknownLength => (),
|
||||
PayloadError::UnknownLength => {}
|
||||
_ => unreachable!("error"),
|
||||
}
|
||||
|
||||
let mut req =
|
||||
TestResponse::with_header(header::CONTENT_LENGTH, "1000000").finish();
|
||||
match req.body().await.err().unwrap() {
|
||||
PayloadError::Overflow => (),
|
||||
PayloadError::Overflow => {}
|
||||
_ => unreachable!("error"),
|
||||
}
|
||||
|
||||
|
@ -390,7 +390,7 @@ mod tests {
|
|||
.set_payload(Bytes::from_static(b"11111111111111"))
|
||||
.finish();
|
||||
match req.body().limit(5).await.err().unwrap() {
|
||||
PayloadError::Overflow => (),
|
||||
PayloadError::Overflow => {}
|
||||
_ => unreachable!("error"),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ use std::rc::Rc;
|
|||
use std::task::{Context, Poll};
|
||||
use std::time::Duration;
|
||||
|
||||
use actix_rt::time::{delay_for, Delay};
|
||||
use actix_rt::time::{sleep, Sleep};
|
||||
use bytes::Bytes;
|
||||
use derive_more::From;
|
||||
use futures_core::Stream;
|
||||
|
@ -56,7 +56,8 @@ impl Into<SendRequestError> for PrepForSendingError {
|
|||
pub enum SendClientRequest {
|
||||
Fut(
|
||||
Pin<Box<dyn Future<Output = Result<ClientResponse, SendRequestError>>>>,
|
||||
Option<Delay>,
|
||||
// FIXME: use a pinned Sleep instead of box.
|
||||
Option<Pin<Box<Sleep>>>,
|
||||
bool,
|
||||
),
|
||||
Err(Option<SendRequestError>),
|
||||
|
@ -68,7 +69,7 @@ impl SendClientRequest {
|
|||
response_decompress: bool,
|
||||
timeout: Option<Duration>,
|
||||
) -> SendClientRequest {
|
||||
let delay = timeout.map(delay_for);
|
||||
let delay = timeout.map(|d| Box::pin(sleep(d)));
|
||||
SendClientRequest::Fut(send, delay, response_decompress)
|
||||
}
|
||||
}
|
||||
|
@ -85,7 +86,7 @@ impl Future for SendClientRequest {
|
|||
SendClientRequest::Fut(send, delay, response_decompress) => {
|
||||
if delay.is_some() {
|
||||
match Pin::new(delay.as_mut().unwrap()).poll(cx) {
|
||||
Poll::Pending => (),
|
||||
Poll::Pending => {}
|
||||
_ => return Poll::Ready(Err(SendRequestError::Timeout)),
|
||||
}
|
||||
}
|
||||
|
@ -126,7 +127,7 @@ impl Future for SendClientRequest {
|
|||
SendClientRequest::Fut(send, delay, _) => {
|
||||
if delay.is_some() {
|
||||
match Pin::new(delay.as_mut().unwrap()).poll(cx) {
|
||||
Poll::Pending => (),
|
||||
Poll::Pending => {}
|
||||
_ => return Poll::Ready(Err(SendRequestError::Timeout)),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -259,7 +259,7 @@ impl WebsocketsRequest {
|
|||
return Err(InvalidUrl::MissingScheme.into());
|
||||
} else if let Some(scheme) = uri.scheme() {
|
||||
match scheme.as_str() {
|
||||
"http" | "ws" | "https" | "wss" => (),
|
||||
"http" | "ws" | "https" | "wss" => {}
|
||||
_ => return Err(InvalidUrl::UnknownScheme.into()),
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -108,14 +108,14 @@ async fn test_form() {
|
|||
async fn test_timeout() {
|
||||
let srv = test::start(|| {
|
||||
App::new().service(web::resource("/").route(web::to(|| async {
|
||||
actix_rt::time::delay_for(Duration::from_millis(200)).await;
|
||||
actix_rt::time::sleep(Duration::from_millis(200)).await;
|
||||
Ok::<_, Error>(HttpResponse::Ok().body(STR))
|
||||
})))
|
||||
});
|
||||
|
||||
let connector = awc::Connector::new()
|
||||
.connector(actix_connect::new_connector(
|
||||
actix_connect::start_default_resolver().await.unwrap(),
|
||||
.connector(actix_tls::connect::new_connector(
|
||||
actix_tls::connect::start_default_resolver().await.unwrap(),
|
||||
))
|
||||
.timeout(Duration::from_secs(15))
|
||||
.finish();
|
||||
|
@ -127,7 +127,7 @@ async fn test_timeout() {
|
|||
|
||||
let request = client.get(srv.url("/")).send();
|
||||
match request.await {
|
||||
Err(SendRequestError::Timeout) => (),
|
||||
Err(SendRequestError::Timeout) => {}
|
||||
_ => panic!(),
|
||||
}
|
||||
}
|
||||
|
@ -136,7 +136,7 @@ async fn test_timeout() {
|
|||
async fn test_timeout_override() {
|
||||
let srv = test::start(|| {
|
||||
App::new().service(web::resource("/").route(web::to(|| async {
|
||||
actix_rt::time::delay_for(Duration::from_millis(200)).await;
|
||||
actix_rt::time::sleep(Duration::from_millis(200)).await;
|
||||
Ok::<_, Error>(HttpResponse::Ok().body(STR))
|
||||
})))
|
||||
});
|
||||
|
@ -149,7 +149,7 @@ async fn test_timeout_override() {
|
|||
.timeout(Duration::from_millis(50))
|
||||
.send();
|
||||
match request.await {
|
||||
Err(SendRequestError::Timeout) => (),
|
||||
Err(SendRequestError::Timeout) => {}
|
||||
_ => panic!(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#![cfg(feature = "openssl")]
|
||||
use actix_http::HttpService;
|
||||
use actix_http_test::test_server;
|
||||
use actix_service::{map_config, ServiceFactory};
|
||||
use actix_service::{map_config, ServiceFactoryExt};
|
||||
use actix_web::http::Version;
|
||||
use actix_web::{dev::AppConfig, web, App, HttpResponse};
|
||||
use open_ssl::ssl::{SslAcceptor, SslConnector, SslFiletype, SslMethod, SslVerifyMode};
|
||||
|
|
|
@ -4,7 +4,7 @@ use std::sync::Arc;
|
|||
|
||||
use actix_http::HttpService;
|
||||
use actix_http_test::test_server;
|
||||
use actix_service::{map_config, pipeline_factory, ServiceFactory};
|
||||
use actix_service::{map_config, pipeline_factory, ServiceFactoryExt};
|
||||
use actix_web::http::Version;
|
||||
use actix_web::{dev::AppConfig, web, App, HttpResponse};
|
||||
use futures_util::future::ok;
|
||||
|
|
|
@ -4,7 +4,7 @@ use std::sync::Arc;
|
|||
|
||||
use actix_http::HttpService;
|
||||
use actix_http_test::test_server;
|
||||
use actix_service::{map_config, pipeline_factory, ServiceFactory};
|
||||
use actix_service::{map_config, pipeline_factory, ServiceFactoryExt};
|
||||
use actix_web::http::Version;
|
||||
use actix_web::{dev::AppConfig, web, App, HttpResponse};
|
||||
use futures_util::future::ok;
|
||||
|
|
|
@ -29,18 +29,22 @@ const STR: &str = "Hello World Hello World Hello World Hello World Hello World \
|
|||
fn bench_async_burst(c: &mut Criterion) {
|
||||
// We are using System here, since Runtime requires preinitialized tokio
|
||||
// Maybe add to actix_rt docs
|
||||
let mut rt = actix_rt::System::new("test");
|
||||
let rt = actix_rt::System::new("test");
|
||||
|
||||
let srv = test::start(|| {
|
||||
App::new()
|
||||
.service(web::resource("/").route(web::to(|| HttpResponse::Ok().body(STR))))
|
||||
let srv = rt.block_on(async {
|
||||
test::start(|| {
|
||||
App::new().service(
|
||||
web::resource("/").route(web::to(|| HttpResponse::Ok().body(STR))),
|
||||
)
|
||||
})
|
||||
});
|
||||
|
||||
let url = srv.url("/");
|
||||
|
||||
c.bench_function("get_body_async_burst", move |b| {
|
||||
b.iter_custom(|iters| {
|
||||
let client = Client::new().get(url.clone()).freeze().unwrap();
|
||||
let client =
|
||||
rt.block_on(async { Client::new().get(url.clone()).freeze().unwrap() });
|
||||
|
||||
let start = std::time::Instant::now();
|
||||
// benchmark body
|
||||
|
|
|
@ -23,10 +23,9 @@ use actix_web::test::{init_service, ok_service, TestRequest};
|
|||
/// async_service_direct time: [1.0908 us 1.1656 us 1.2613 us]
|
||||
pub fn bench_async_service<S>(c: &mut Criterion, srv: S, name: &str)
|
||||
where
|
||||
S: Service<Request = ServiceRequest, Response = ServiceResponse, Error = Error>
|
||||
+ 'static,
|
||||
S: Service<ServiceRequest, Response = ServiceResponse, Error = Error> + 'static,
|
||||
{
|
||||
let mut rt = actix_rt::System::new("test");
|
||||
let rt = actix_rt::System::new("test");
|
||||
let srv = Rc::new(RefCell::new(srv));
|
||||
|
||||
let req = TestRequest::default().to_srv_request();
|
||||
|
@ -41,14 +40,15 @@ where
|
|||
b.iter_custom(|iters| {
|
||||
let srv = srv.clone();
|
||||
// exclude request generation, it appears it takes significant time vs call (3us vs 1us)
|
||||
let reqs: Vec<_> = (0..iters)
|
||||
let futs = (0..iters)
|
||||
.map(|_| TestRequest::default().to_srv_request())
|
||||
.collect();
|
||||
.map(|req| srv.borrow_mut().call(req));
|
||||
|
||||
let start = std::time::Instant::now();
|
||||
// benchmark body
|
||||
rt.block_on(async move {
|
||||
for req in reqs {
|
||||
srv.borrow_mut().call(req).await.unwrap();
|
||||
for fut in futs {
|
||||
fut.await.unwrap();
|
||||
}
|
||||
});
|
||||
let elapsed = start.elapsed();
|
||||
|
@ -67,7 +67,7 @@ async fn index(req: ServiceRequest) -> Result<ServiceResponse, Error> {
|
|||
// Sample results on MacBook Pro '14
|
||||
// time: [2.0724 us 2.1345 us 2.2074 us]
|
||||
fn async_web_service(c: &mut Criterion) {
|
||||
let mut rt = actix_rt::System::new("test");
|
||||
let rt = actix_rt::System::new("test");
|
||||
let srv = Rc::new(RefCell::new(rt.block_on(init_service(
|
||||
App::new().service(web::service("/").finish(index)),
|
||||
))));
|
||||
|
@ -83,13 +83,14 @@ fn async_web_service(c: &mut Criterion) {
|
|||
c.bench_function("async_web_service_direct", move |b| {
|
||||
b.iter_custom(|iters| {
|
||||
let srv = srv.clone();
|
||||
let reqs = (0..iters).map(|_| TestRequest::get().uri("/").to_request());
|
||||
|
||||
let futs = (0..iters)
|
||||
.map(|_| TestRequest::get().uri("/").to_request())
|
||||
.map(|req| srv.borrow_mut().call(req));
|
||||
let start = std::time::Instant::now();
|
||||
// benchmark body
|
||||
rt.block_on(async move {
|
||||
for req in reqs {
|
||||
srv.borrow_mut().call(req).await.unwrap();
|
||||
for fut in futs {
|
||||
fut.await.unwrap();
|
||||
}
|
||||
});
|
||||
let elapsed = start.elapsed();
|
||||
|
|
29
src/app.rs
29
src/app.rs
|
@ -5,10 +5,11 @@ use std::marker::PhantomData;
|
|||
use std::rc::Rc;
|
||||
|
||||
use actix_http::body::{Body, MessageBody};
|
||||
use actix_http::Extensions;
|
||||
use actix_http::{Extensions, Request};
|
||||
use actix_service::boxed::{self, BoxServiceFactory};
|
||||
use actix_service::{
|
||||
apply, apply_fn_factory, IntoServiceFactory, ServiceFactory, Transform,
|
||||
apply, apply_fn_factory, IntoServiceFactory, ServiceFactory, ServiceFactoryExt,
|
||||
Transform,
|
||||
};
|
||||
use futures_util::future::FutureExt;
|
||||
|
||||
|
@ -37,7 +38,7 @@ pub struct App<T, B> {
|
|||
data_factories: Vec<FnDataFactory>,
|
||||
external: Vec<ResourceDef>,
|
||||
extensions: Extensions,
|
||||
_t: PhantomData<B>,
|
||||
_phantom: PhantomData<B>,
|
||||
}
|
||||
|
||||
impl App<AppEntry, Body> {
|
||||
|
@ -54,7 +55,7 @@ impl App<AppEntry, Body> {
|
|||
factory_ref: fref,
|
||||
external: Vec::new(),
|
||||
extensions: Extensions::new(),
|
||||
_t: PhantomData,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -63,8 +64,8 @@ impl<T, B> App<T, B>
|
|||
where
|
||||
B: MessageBody,
|
||||
T: ServiceFactory<
|
||||
ServiceRequest,
|
||||
Config = (),
|
||||
Request = ServiceRequest,
|
||||
Response = ServiceResponse<B>,
|
||||
Error = Error,
|
||||
InitError = (),
|
||||
|
@ -268,10 +269,10 @@ where
|
|||
/// ```
|
||||
pub fn default_service<F, U>(mut self, f: F) -> Self
|
||||
where
|
||||
F: IntoServiceFactory<U>,
|
||||
F: IntoServiceFactory<U, ServiceRequest>,
|
||||
U: ServiceFactory<
|
||||
ServiceRequest,
|
||||
Config = (),
|
||||
Request = ServiceRequest,
|
||||
Response = ServiceResponse,
|
||||
Error = Error,
|
||||
> + 'static,
|
||||
|
@ -353,8 +354,8 @@ where
|
|||
mw: M,
|
||||
) -> App<
|
||||
impl ServiceFactory<
|
||||
ServiceRequest,
|
||||
Config = (),
|
||||
Request = ServiceRequest,
|
||||
Response = ServiceResponse<B1>,
|
||||
Error = Error,
|
||||
InitError = (),
|
||||
|
@ -364,7 +365,7 @@ where
|
|||
where
|
||||
M: Transform<
|
||||
T::Service,
|
||||
Request = ServiceRequest,
|
||||
ServiceRequest,
|
||||
Response = ServiceResponse<B1>,
|
||||
Error = Error,
|
||||
InitError = (),
|
||||
|
@ -380,7 +381,7 @@ where
|
|||
factory_ref: self.factory_ref,
|
||||
external: self.external,
|
||||
extensions: self.extensions,
|
||||
_t: PhantomData,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -420,8 +421,8 @@ where
|
|||
mw: F,
|
||||
) -> App<
|
||||
impl ServiceFactory<
|
||||
ServiceRequest,
|
||||
Config = (),
|
||||
Request = ServiceRequest,
|
||||
Response = ServiceResponse<B1>,
|
||||
Error = Error,
|
||||
InitError = (),
|
||||
|
@ -442,17 +443,17 @@ where
|
|||
factory_ref: self.factory_ref,
|
||||
external: self.external,
|
||||
extensions: self.extensions,
|
||||
_t: PhantomData,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, B> IntoServiceFactory<AppInit<T, B>> for App<T, B>
|
||||
impl<T, B> IntoServiceFactory<AppInit<T, B>, Request> for App<T, B>
|
||||
where
|
||||
B: MessageBody,
|
||||
T: ServiceFactory<
|
||||
ServiceRequest,
|
||||
Config = (),
|
||||
Request = ServiceRequest,
|
||||
Response = ServiceResponse<B>,
|
||||
Error = Error,
|
||||
InitError = (),
|
||||
|
|
|
@ -10,7 +10,6 @@ use actix_router::{Path, ResourceDef, ResourceInfo, Router, Url};
|
|||
use actix_service::boxed::{self, BoxService, BoxServiceFactory};
|
||||
use actix_service::{fn_service, Service, ServiceFactory};
|
||||
use futures_util::future::{join_all, ok, FutureExt, LocalBoxFuture};
|
||||
use tinyvec::tiny_vec;
|
||||
|
||||
use crate::config::{AppConfig, AppService};
|
||||
use crate::data::{DataFactory, FnDataFactory};
|
||||
|
@ -30,8 +29,8 @@ type BoxResponse = LocalBoxFuture<'static, Result<ServiceResponse, Error>>;
|
|||
pub struct AppInit<T, B>
|
||||
where
|
||||
T: ServiceFactory<
|
||||
ServiceRequest,
|
||||
Config = (),
|
||||
Request = ServiceRequest,
|
||||
Response = ServiceResponse<B>,
|
||||
Error = Error,
|
||||
InitError = (),
|
||||
|
@ -47,22 +46,21 @@ where
|
|||
pub(crate) external: RefCell<Vec<ResourceDef>>,
|
||||
}
|
||||
|
||||
impl<T, B> ServiceFactory for AppInit<T, B>
|
||||
impl<T, B> ServiceFactory<Request> for AppInit<T, B>
|
||||
where
|
||||
T: ServiceFactory<
|
||||
ServiceRequest,
|
||||
Config = (),
|
||||
Request = ServiceRequest,
|
||||
Response = ServiceResponse<B>,
|
||||
Error = Error,
|
||||
InitError = (),
|
||||
>,
|
||||
{
|
||||
type Config = AppConfig;
|
||||
type Request = Request;
|
||||
type Response = ServiceResponse<B>;
|
||||
type Error = T::Error;
|
||||
type InitError = T::InitError;
|
||||
type Config = AppConfig;
|
||||
type Service = AppInitService<T::Service, B>;
|
||||
type InitError = T::InitError;
|
||||
type Future = AppInitResult<T, B>;
|
||||
|
||||
fn new_service(&self, config: AppConfig) -> Self::Future {
|
||||
|
@ -125,7 +123,7 @@ where
|
|||
),
|
||||
config,
|
||||
rmap,
|
||||
_t: PhantomData,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -133,7 +131,7 @@ where
|
|||
#[pin_project::pin_project]
|
||||
pub struct AppInitResult<T, B>
|
||||
where
|
||||
T: ServiceFactory,
|
||||
T: ServiceFactory<ServiceRequest>,
|
||||
{
|
||||
#[pin]
|
||||
endpoint_fut: T::Future,
|
||||
|
@ -150,14 +148,14 @@ where
|
|||
data: Rc<[Box<dyn DataFactory>]>,
|
||||
extensions: Option<Extensions>,
|
||||
|
||||
_t: PhantomData<B>,
|
||||
_phantom: PhantomData<B>,
|
||||
}
|
||||
|
||||
impl<T, B> Future for AppInitResult<T, B>
|
||||
where
|
||||
T: ServiceFactory<
|
||||
ServiceRequest,
|
||||
Config = (),
|
||||
Request = ServiceRequest,
|
||||
Response = ServiceResponse<B>,
|
||||
Error = Error,
|
||||
InitError = (),
|
||||
|
@ -215,7 +213,7 @@ where
|
|||
/// Service to convert `Request` to a `ServiceRequest<S>`
|
||||
pub struct AppInitService<T, B>
|
||||
where
|
||||
T: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
||||
T: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
||||
{
|
||||
service: T,
|
||||
rmap: Rc<ResourceMap>,
|
||||
|
@ -224,11 +222,10 @@ where
|
|||
pool: &'static HttpRequestPool,
|
||||
}
|
||||
|
||||
impl<T, B> Service for AppInitService<T, B>
|
||||
impl<T, B> Service<Request> for AppInitService<T, B>
|
||||
where
|
||||
T: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
||||
T: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
||||
{
|
||||
type Request = Request;
|
||||
type Response = ServiceResponse<B>;
|
||||
type Error = T::Error;
|
||||
type Future = T::Future;
|
||||
|
@ -241,12 +238,11 @@ where
|
|||
let (head, payload) = req.into_parts();
|
||||
|
||||
let req = if let Some(mut req) = self.pool.get_request() {
|
||||
let inner = Rc::get_mut(&mut req.0).unwrap();
|
||||
let inner = Rc::get_mut(&mut req.inner).unwrap();
|
||||
inner.path.get_mut().update(&head.uri);
|
||||
inner.path.reset();
|
||||
inner.head = head;
|
||||
inner.payload = payload;
|
||||
inner.app_data = tiny_vec![self.data.clone()];
|
||||
req
|
||||
} else {
|
||||
HttpRequest::new(
|
||||
|
@ -265,7 +261,7 @@ where
|
|||
|
||||
impl<T, B> Drop for AppInitService<T, B>
|
||||
where
|
||||
T: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
||||
T: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
||||
{
|
||||
fn drop(&mut self) {
|
||||
self.pool.clear();
|
||||
|
@ -277,9 +273,8 @@ pub struct AppRoutingFactory {
|
|||
default: Rc<HttpNewService>,
|
||||
}
|
||||
|
||||
impl ServiceFactory for AppRoutingFactory {
|
||||
impl ServiceFactory<ServiceRequest> for AppRoutingFactory {
|
||||
type Config = ();
|
||||
type Request = ServiceRequest;
|
||||
type Response = ServiceResponse;
|
||||
type Error = Error;
|
||||
type InitError = ();
|
||||
|
@ -388,8 +383,7 @@ pub struct AppRouting {
|
|||
default: Option<HttpService>,
|
||||
}
|
||||
|
||||
impl Service for AppRouting {
|
||||
type Request = ServiceRequest;
|
||||
impl Service<ServiceRequest> for AppRouting {
|
||||
type Response = ServiceResponse;
|
||||
type Error = Error;
|
||||
type Future = BoxResponse;
|
||||
|
@ -436,9 +430,8 @@ impl AppEntry {
|
|||
}
|
||||
}
|
||||
|
||||
impl ServiceFactory for AppEntry {
|
||||
impl ServiceFactory<ServiceRequest> for AppEntry {
|
||||
type Config = ();
|
||||
type Request = ServiceRequest;
|
||||
type Response = ServiceResponse;
|
||||
type Error = Error;
|
||||
type InitError = ();
|
||||
|
|
|
@ -105,10 +105,10 @@ impl AppService {
|
|||
factory: F,
|
||||
nested: Option<Rc<ResourceMap>>,
|
||||
) where
|
||||
F: IntoServiceFactory<S>,
|
||||
F: IntoServiceFactory<S, ServiceRequest>,
|
||||
S: ServiceFactory<
|
||||
ServiceRequest,
|
||||
Config = (),
|
||||
Request = ServiceRequest,
|
||||
Response = ServiceResponse,
|
||||
Error = Error,
|
||||
InitError = (),
|
||||
|
|
|
@ -49,7 +49,7 @@ where
|
|||
R::Output: Responder,
|
||||
{
|
||||
hnd: F,
|
||||
_t: PhantomData<(T, R)>,
|
||||
_phantom: PhantomData<(T, R)>,
|
||||
}
|
||||
|
||||
impl<F, T, R> HandlerService<F, T, R>
|
||||
|
@ -62,7 +62,7 @@ where
|
|||
pub fn new(hnd: F) -> Self {
|
||||
Self {
|
||||
hnd,
|
||||
_t: PhantomData,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -77,19 +77,18 @@ where
|
|||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
hnd: self.hnd.clone(),
|
||||
_t: PhantomData,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<F, T, R> ServiceFactory for HandlerService<F, T, R>
|
||||
impl<F, T, R> ServiceFactory<ServiceRequest> for HandlerService<F, T, R>
|
||||
where
|
||||
F: Handler<T, R>,
|
||||
T: FromRequest,
|
||||
R: Future,
|
||||
R::Output: Responder,
|
||||
{
|
||||
type Request = ServiceRequest;
|
||||
type Response = ServiceResponse;
|
||||
type Error = Error;
|
||||
type Config = ();
|
||||
|
@ -102,15 +101,14 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
// Handler is both it's ServiceHandler and Service Type.
|
||||
impl<F, T, R> Service for HandlerService<F, T, R>
|
||||
// HandlerService is both it's ServiceFactory and Service Type.
|
||||
impl<F, T, R> Service<ServiceRequest> for HandlerService<F, T, R>
|
||||
where
|
||||
F: Handler<T, R>,
|
||||
T: FromRequest,
|
||||
R: Future,
|
||||
R::Output: Responder,
|
||||
{
|
||||
type Request = ServiceRequest;
|
||||
type Response = ServiceResponse;
|
||||
type Error = Error;
|
||||
type Future = HandlerServiceFuture<F, T, R>;
|
||||
|
@ -119,7 +117,7 @@ where
|
|||
Poll::Ready(Ok(()))
|
||||
}
|
||||
|
||||
fn call(&mut self, req: Self::Request) -> Self::Future {
|
||||
fn call(&mut self, req: ServiceRequest) -> Self::Future {
|
||||
let (req, mut payload) = req.into_parts();
|
||||
let fut = T::from_request(&req, &mut payload);
|
||||
HandlerServiceFuture::Extract(fut, Some(req), self.hnd.clone())
|
||||
|
|
|
@ -55,7 +55,7 @@ impl ConnectionInfo {
|
|||
host = Some(val.trim());
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,16 +51,15 @@ impl Default for Compress {
|
|||
}
|
||||
}
|
||||
|
||||
impl<S, B> Transform<S> for Compress
|
||||
impl<S, B> Transform<S, ServiceRequest> for Compress
|
||||
where
|
||||
B: MessageBody,
|
||||
S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
||||
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
||||
{
|
||||
type Request = ServiceRequest;
|
||||
type Response = ServiceResponse<Encoder<B>>;
|
||||
type Error = Error;
|
||||
type InitError = ();
|
||||
type Transform = CompressMiddleware<S>;
|
||||
type InitError = ();
|
||||
type Future = Ready<Result<Self::Transform, Self::InitError>>;
|
||||
|
||||
fn new_transform(&self, service: S) -> Self::Future {
|
||||
|
@ -76,12 +75,11 @@ pub struct CompressMiddleware<S> {
|
|||
encoding: ContentEncoding,
|
||||
}
|
||||
|
||||
impl<S, B> Service for CompressMiddleware<S>
|
||||
impl<S, B> Service<ServiceRequest> for CompressMiddleware<S>
|
||||
where
|
||||
B: MessageBody,
|
||||
S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
||||
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
||||
{
|
||||
type Request = ServiceRequest;
|
||||
type Response = ServiceResponse<Encoder<B>>;
|
||||
type Error = Error;
|
||||
type Future = CompressResponse<S, B>;
|
||||
|
@ -106,7 +104,7 @@ where
|
|||
CompressResponse {
|
||||
encoding,
|
||||
fut: self.service.call(req),
|
||||
_t: PhantomData,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -115,19 +113,19 @@ where
|
|||
#[pin_project]
|
||||
pub struct CompressResponse<S, B>
|
||||
where
|
||||
S: Service,
|
||||
S: Service<ServiceRequest>,
|
||||
B: MessageBody,
|
||||
{
|
||||
#[pin]
|
||||
fut: S::Future,
|
||||
encoding: ContentEncoding,
|
||||
_t: PhantomData<B>,
|
||||
_phantom: PhantomData<B>,
|
||||
}
|
||||
|
||||
impl<S, B> Future for CompressResponse<S, B>
|
||||
where
|
||||
B: MessageBody,
|
||||
S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
||||
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
||||
{
|
||||
type Output = Result<ServiceResponse<Encoder<B>>, Error>;
|
||||
|
||||
|
|
|
@ -33,19 +33,18 @@ impl<T> Condition<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<S, T> Transform<S> for Condition<T>
|
||||
impl<S, T, Req> Transform<S, Req> for Condition<T>
|
||||
where
|
||||
S: Service + 'static,
|
||||
T: Transform<S, Request = S::Request, Response = S::Response, Error = S::Error>,
|
||||
S: Service<Req> + 'static,
|
||||
T: Transform<S, Req, Response = S::Response, Error = S::Error>,
|
||||
T::Future: 'static,
|
||||
T::InitError: 'static,
|
||||
T::Transform: 'static,
|
||||
{
|
||||
type Request = S::Request;
|
||||
type Response = S::Response;
|
||||
type Error = S::Error;
|
||||
type InitError = T::InitError;
|
||||
type Transform = ConditionMiddleware<T::Transform, S>;
|
||||
type InitError = T::InitError;
|
||||
type Future = LocalBoxFuture<'static, Result<Self::Transform, Self::InitError>>;
|
||||
|
||||
fn new_transform(&self, service: S) -> Self::Future {
|
||||
|
@ -68,12 +67,11 @@ pub enum ConditionMiddleware<E, D> {
|
|||
Disable(D),
|
||||
}
|
||||
|
||||
impl<E, D> Service for ConditionMiddleware<E, D>
|
||||
impl<E, D, Req> Service<Req> for ConditionMiddleware<E, D>
|
||||
where
|
||||
E: Service,
|
||||
D: Service<Request = E::Request, Response = E::Response, Error = E::Error>,
|
||||
E: Service<Req>,
|
||||
D: Service<Req, Response = E::Response, Error = E::Error>,
|
||||
{
|
||||
type Request = E::Request;
|
||||
type Response = E::Response;
|
||||
type Error = E::Error;
|
||||
type Future = Either<E::Future, D::Future>;
|
||||
|
@ -86,7 +84,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
fn call(&mut self, req: E::Request) -> Self::Future {
|
||||
fn call(&mut self, req: Req) -> Self::Future {
|
||||
use ConditionMiddleware::*;
|
||||
match self {
|
||||
Enable(service) => Either::Left(service.call(req)),
|
||||
|
|
|
@ -93,12 +93,11 @@ impl DefaultHeaders {
|
|||
}
|
||||
}
|
||||
|
||||
impl<S, B> Transform<S> for DefaultHeaders
|
||||
impl<S, B> Transform<S, ServiceRequest> for DefaultHeaders
|
||||
where
|
||||
S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
||||
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
||||
S::Future: 'static,
|
||||
{
|
||||
type Request = ServiceRequest;
|
||||
type Response = ServiceResponse<B>;
|
||||
type Error = Error;
|
||||
type Transform = DefaultHeadersMiddleware<S>;
|
||||
|
@ -118,12 +117,11 @@ pub struct DefaultHeadersMiddleware<S> {
|
|||
inner: Rc<Inner>,
|
||||
}
|
||||
|
||||
impl<S, B> Service for DefaultHeadersMiddleware<S>
|
||||
impl<S, B> Service<ServiceRequest> for DefaultHeadersMiddleware<S>
|
||||
where
|
||||
S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
||||
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
||||
S::Future: 'static,
|
||||
{
|
||||
type Request = ServiceRequest;
|
||||
type Response = ServiceResponse<B>;
|
||||
type Error = Error;
|
||||
type Future = DefaultHeaderFuture<S, B>;
|
||||
|
@ -145,7 +143,7 @@ where
|
|||
}
|
||||
|
||||
#[pin_project::pin_project]
|
||||
pub struct DefaultHeaderFuture<S: Service, B> {
|
||||
pub struct DefaultHeaderFuture<S: Service<ServiceRequest>, B> {
|
||||
#[pin]
|
||||
fut: S::Future,
|
||||
inner: Rc<Inner>,
|
||||
|
@ -154,7 +152,7 @@ pub struct DefaultHeaderFuture<S: Service, B> {
|
|||
|
||||
impl<S, B> Future for DefaultHeaderFuture<S, B>
|
||||
where
|
||||
S: Service<Response = ServiceResponse<B>, Error = Error>,
|
||||
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
||||
{
|
||||
type Output = <S::Future as Future>::Output;
|
||||
|
||||
|
|
|
@ -3,8 +3,8 @@ use std::rc::Rc;
|
|||
use std::task::{Context, Poll};
|
||||
|
||||
use actix_service::{Service, Transform};
|
||||
use ahash::AHashMap;
|
||||
use futures_util::future::{ok, FutureExt, LocalBoxFuture, Ready};
|
||||
use fxhash::FxHashMap;
|
||||
|
||||
use crate::dev::{ServiceRequest, ServiceResponse};
|
||||
use crate::error::{Error, Result};
|
||||
|
@ -52,13 +52,13 @@ type ErrorHandler<B> = dyn Fn(ServiceResponse<B>) -> Result<ErrorHandlerResponse
|
|||
/// # }
|
||||
/// ```
|
||||
pub struct ErrorHandlers<B> {
|
||||
handlers: Rc<FxHashMap<StatusCode, Box<ErrorHandler<B>>>>,
|
||||
handlers: Rc<AHashMap<StatusCode, Box<ErrorHandler<B>>>>,
|
||||
}
|
||||
|
||||
impl<B> Default for ErrorHandlers<B> {
|
||||
fn default() -> Self {
|
||||
ErrorHandlers {
|
||||
handlers: Rc::new(FxHashMap::default()),
|
||||
handlers: Rc::new(AHashMap::default()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -81,17 +81,16 @@ impl<B> ErrorHandlers<B> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<S, B> Transform<S> for ErrorHandlers<B>
|
||||
impl<S, B> Transform<S, ServiceRequest> for ErrorHandlers<B>
|
||||
where
|
||||
S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
||||
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
||||
S::Future: 'static,
|
||||
B: 'static,
|
||||
{
|
||||
type Request = ServiceRequest;
|
||||
type Response = ServiceResponse<B>;
|
||||
type Error = Error;
|
||||
type InitError = ();
|
||||
type Transform = ErrorHandlersMiddleware<S, B>;
|
||||
type InitError = ();
|
||||
type Future = Ready<Result<Self::Transform, Self::InitError>>;
|
||||
|
||||
fn new_transform(&self, service: S) -> Self::Future {
|
||||
|
@ -105,16 +104,15 @@ where
|
|||
#[doc(hidden)]
|
||||
pub struct ErrorHandlersMiddleware<S, B> {
|
||||
service: S,
|
||||
handlers: Rc<FxHashMap<StatusCode, Box<ErrorHandler<B>>>>,
|
||||
handlers: Rc<AHashMap<StatusCode, Box<ErrorHandler<B>>>>,
|
||||
}
|
||||
|
||||
impl<S, B> Service for ErrorHandlersMiddleware<S, B>
|
||||
impl<S, B> Service<ServiceRequest> for ErrorHandlersMiddleware<S, B>
|
||||
where
|
||||
S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
||||
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
||||
S::Future: 'static,
|
||||
B: 'static,
|
||||
{
|
||||
type Request = ServiceRequest;
|
||||
type Response = ServiceResponse<B>;
|
||||
type Error = Error;
|
||||
type Future = LocalBoxFuture<'static, Result<Self::Response, Self::Error>>;
|
||||
|
|
|
@ -179,12 +179,11 @@ impl Default for Logger {
|
|||
}
|
||||
}
|
||||
|
||||
impl<S, B> Transform<S> for Logger
|
||||
impl<S, B> Transform<S, ServiceRequest> for Logger
|
||||
where
|
||||
S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
||||
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
||||
B: MessageBody,
|
||||
{
|
||||
type Request = ServiceRequest;
|
||||
type Response = ServiceResponse<StreamLog<B>>;
|
||||
type Error = Error;
|
||||
type InitError = ();
|
||||
|
@ -216,12 +215,11 @@ pub struct LoggerMiddleware<S> {
|
|||
service: S,
|
||||
}
|
||||
|
||||
impl<S, B> Service for LoggerMiddleware<S>
|
||||
impl<S, B> Service<ServiceRequest> for LoggerMiddleware<S>
|
||||
where
|
||||
S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
||||
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
||||
B: MessageBody,
|
||||
{
|
||||
type Request = ServiceRequest;
|
||||
type Response = ServiceResponse<StreamLog<B>>;
|
||||
type Error = Error;
|
||||
type Future = LoggerResponse<S, B>;
|
||||
|
@ -238,7 +236,7 @@ where
|
|||
fut: self.service.call(req),
|
||||
format: None,
|
||||
time: OffsetDateTime::now_utc(),
|
||||
_t: PhantomData,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
} else {
|
||||
let now = OffsetDateTime::now_utc();
|
||||
|
@ -251,7 +249,7 @@ where
|
|||
fut: self.service.call(req),
|
||||
format: Some(format),
|
||||
time: now,
|
||||
_t: PhantomData,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -262,19 +260,19 @@ where
|
|||
pub struct LoggerResponse<S, B>
|
||||
where
|
||||
B: MessageBody,
|
||||
S: Service,
|
||||
S: Service<ServiceRequest>,
|
||||
{
|
||||
#[pin]
|
||||
fut: S::Future,
|
||||
time: OffsetDateTime,
|
||||
format: Option<Format>,
|
||||
_t: PhantomData<(B,)>,
|
||||
_phantom: PhantomData<B>,
|
||||
}
|
||||
|
||||
impl<S, B> Future for LoggerResponse<S, B>
|
||||
where
|
||||
B: MessageBody,
|
||||
S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
||||
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
||||
{
|
||||
type Output = Result<ServiceResponse<StreamLog<B>>, Error>;
|
||||
|
||||
|
@ -524,7 +522,7 @@ impl FormatText {
|
|||
};
|
||||
*self = FormatText::Str(s.to_string())
|
||||
}
|
||||
_ => (),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -589,7 +587,7 @@ impl FormatText {
|
|||
|
||||
*self = s;
|
||||
}
|
||||
_ => (),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -91,16 +91,15 @@ impl NormalizePath {
|
|||
}
|
||||
}
|
||||
|
||||
impl<S, B> Transform<S> for NormalizePath
|
||||
impl<S, B> Transform<S, ServiceRequest> for NormalizePath
|
||||
where
|
||||
S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
||||
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
||||
S::Future: 'static,
|
||||
{
|
||||
type Request = ServiceRequest;
|
||||
type Response = ServiceResponse<B>;
|
||||
type Error = Error;
|
||||
type InitError = ();
|
||||
type Transform = NormalizePathNormalization<S>;
|
||||
type InitError = ();
|
||||
type Future = Ready<Result<Self::Transform, Self::InitError>>;
|
||||
|
||||
fn new_transform(&self, service: S) -> Self::Future {
|
||||
|
@ -119,12 +118,11 @@ pub struct NormalizePathNormalization<S> {
|
|||
trailing_slash_behavior: TrailingSlash,
|
||||
}
|
||||
|
||||
impl<S, B> Service for NormalizePathNormalization<S>
|
||||
impl<S, B> Service<ServiceRequest> for NormalizePathNormalization<S>
|
||||
where
|
||||
S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
||||
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
||||
S::Future: 'static,
|
||||
{
|
||||
type Request = ServiceRequest;
|
||||
type Response = ServiceResponse<B>;
|
||||
type Error = Error;
|
||||
type Future = S::Future;
|
||||
|
|
|
@ -6,7 +6,7 @@ use actix_http::http::{HeaderMap, Method, Uri, Version};
|
|||
use actix_http::{Error, Extensions, HttpMessage, Message, Payload, RequestHead};
|
||||
use actix_router::{Path, Url};
|
||||
use futures_util::future::{ok, Ready};
|
||||
use tinyvec::TinyVec;
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use crate::config::AppConfig;
|
||||
use crate::error::UrlGenerationError;
|
||||
|
@ -16,13 +16,18 @@ use crate::rmap::ResourceMap;
|
|||
|
||||
#[derive(Clone)]
|
||||
/// An HTTP Request
|
||||
pub struct HttpRequest(pub(crate) Rc<HttpRequestInner>);
|
||||
pub struct HttpRequest {
|
||||
// *. Rc<HttpRequestInner> is used exclusively and NO Weak<HttpRequestInner>
|
||||
// is allowed anywhere in the code. Weak pointer is purposely ignored when
|
||||
// doing Rc's ref counter check.
|
||||
pub(crate) inner: Rc<HttpRequestInner>,
|
||||
}
|
||||
|
||||
pub(crate) struct HttpRequestInner {
|
||||
pub(crate) head: Message<RequestHead>,
|
||||
pub(crate) path: Path<Url>,
|
||||
pub(crate) payload: Payload,
|
||||
pub(crate) app_data: TinyVec<[Rc<Extensions>; 4]>,
|
||||
pub(crate) app_data: SmallVec<[Rc<Extensions>; 4]>,
|
||||
rmap: Rc<ResourceMap>,
|
||||
config: AppConfig,
|
||||
pool: &'static HttpRequestPool,
|
||||
|
@ -39,18 +44,20 @@ impl HttpRequest {
|
|||
app_data: Rc<Extensions>,
|
||||
pool: &'static HttpRequestPool,
|
||||
) -> HttpRequest {
|
||||
let mut data = TinyVec::<[Rc<Extensions>; 4]>::new();
|
||||
let mut data = SmallVec::<[Rc<Extensions>; 4]>::new();
|
||||
data.push(app_data);
|
||||
|
||||
HttpRequest(Rc::new(HttpRequestInner {
|
||||
head,
|
||||
path,
|
||||
payload,
|
||||
rmap,
|
||||
config,
|
||||
app_data: data,
|
||||
pool,
|
||||
}))
|
||||
HttpRequest {
|
||||
inner: Rc::new(HttpRequestInner {
|
||||
head,
|
||||
path,
|
||||
payload,
|
||||
rmap,
|
||||
config,
|
||||
app_data: data,
|
||||
pool,
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -58,14 +65,14 @@ impl HttpRequest {
|
|||
/// This method returns reference to the request head
|
||||
#[inline]
|
||||
pub fn head(&self) -> &RequestHead {
|
||||
&self.0.head
|
||||
&self.inner.head
|
||||
}
|
||||
|
||||
/// This method returns mutable reference to the request head.
|
||||
/// panics if multiple references of http request exists.
|
||||
#[inline]
|
||||
pub(crate) fn head_mut(&mut self) -> &mut RequestHead {
|
||||
&mut Rc::get_mut(&mut self.0).unwrap().head
|
||||
&mut Rc::get_mut(&mut self.inner).unwrap().head
|
||||
}
|
||||
|
||||
/// Request's uri.
|
||||
|
@ -118,12 +125,12 @@ impl HttpRequest {
|
|||
/// access the matched value for that segment.
|
||||
#[inline]
|
||||
pub fn match_info(&self) -> &Path<Url> {
|
||||
&self.0.path
|
||||
&self.inner.path
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn match_info_mut(&mut self) -> &mut Path<Url> {
|
||||
&mut Rc::get_mut(&mut self.0).unwrap().path
|
||||
&mut Rc::get_mut(&mut self.inner).unwrap().path
|
||||
}
|
||||
|
||||
/// The resource definition pattern that matched the path. Useful for logging and metrics.
|
||||
|
@ -134,7 +141,7 @@ impl HttpRequest {
|
|||
/// Returns a None when no resource is fully matched, including default services.
|
||||
#[inline]
|
||||
pub fn match_pattern(&self) -> Option<String> {
|
||||
self.0.rmap.match_pattern(self.path())
|
||||
self.inner.rmap.match_pattern(self.path())
|
||||
}
|
||||
|
||||
/// The resource name that matched the path. Useful for logging and metrics.
|
||||
|
@ -142,7 +149,7 @@ impl HttpRequest {
|
|||
/// Returns a None when no resource is fully matched, including default services.
|
||||
#[inline]
|
||||
pub fn match_name(&self) -> Option<&str> {
|
||||
self.0.rmap.match_name(self.path())
|
||||
self.inner.rmap.match_name(self.path())
|
||||
}
|
||||
|
||||
/// Request extensions
|
||||
|
@ -184,7 +191,7 @@ impl HttpRequest {
|
|||
U: IntoIterator<Item = I>,
|
||||
I: AsRef<str>,
|
||||
{
|
||||
self.0.rmap.url_for(&self, name, elements)
|
||||
self.inner.rmap.url_for(&self, name, elements)
|
||||
}
|
||||
|
||||
/// Generate url for named resource
|
||||
|
@ -199,7 +206,7 @@ impl HttpRequest {
|
|||
#[inline]
|
||||
/// Get a reference to a `ResourceMap` of current application.
|
||||
pub fn resource_map(&self) -> &ResourceMap {
|
||||
&self.0.rmap
|
||||
&self.inner.rmap
|
||||
}
|
||||
|
||||
/// Peer socket address
|
||||
|
@ -225,7 +232,7 @@ impl HttpRequest {
|
|||
/// App config
|
||||
#[inline]
|
||||
pub fn app_config(&self) -> &AppConfig {
|
||||
&self.0.config
|
||||
&self.inner.config
|
||||
}
|
||||
|
||||
/// Get an application data object stored with `App::data` or `App::app_data`
|
||||
|
@ -237,7 +244,7 @@ impl HttpRequest {
|
|||
/// let opt_t = req.app_data::<Data<T>>();
|
||||
/// ```
|
||||
pub fn app_data<T: 'static>(&self) -> Option<&T> {
|
||||
for container in self.0.app_data.iter().rev() {
|
||||
for container in self.inner.app_data.iter().rev() {
|
||||
if let Some(data) = container.get::<T>() {
|
||||
return Some(data);
|
||||
}
|
||||
|
@ -259,13 +266,13 @@ impl HttpMessage for HttpRequest {
|
|||
/// Request extensions
|
||||
#[inline]
|
||||
fn extensions(&self) -> Ref<'_, Extensions> {
|
||||
self.0.head.extensions()
|
||||
self.inner.head.extensions()
|
||||
}
|
||||
|
||||
/// Mutable reference to a the request's extensions
|
||||
#[inline]
|
||||
fn extensions_mut(&self) -> RefMut<'_, Extensions> {
|
||||
self.0.head.extensions_mut()
|
||||
self.inner.head.extensions_mut()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -277,11 +284,17 @@ impl HttpMessage for HttpRequest {
|
|||
impl Drop for HttpRequest {
|
||||
fn drop(&mut self) {
|
||||
// if possible, contribute to current worker's HttpRequest allocation pool
|
||||
if Rc::strong_count(&self.0) == 1 {
|
||||
let v = &mut self.0.pool.0.borrow_mut();
|
||||
|
||||
// This relies on no Weak<HttpRequestInner> exists anywhere.(There is none)
|
||||
if let Some(inner) = Rc::get_mut(&mut self.inner) {
|
||||
let v = &mut inner.pool.0.borrow_mut();
|
||||
if v.len() < 128 {
|
||||
self.extensions_mut().clear();
|
||||
v.push(self.0.clone());
|
||||
// clear additional app_data and keep the root one for reuse.
|
||||
inner.app_data.truncate(1);
|
||||
// inner is borrowed mut here. get head's Extension mutably
|
||||
// to reduce borrow check
|
||||
inner.head.extensions.get_mut().clear();
|
||||
v.push(self.inner.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -323,8 +336,8 @@ impl fmt::Debug for HttpRequest {
|
|||
writeln!(
|
||||
f,
|
||||
"\nHttpRequest {:?} {}:{}",
|
||||
self.0.head.version,
|
||||
self.0.head.method,
|
||||
self.inner.head.version,
|
||||
self.inner.head.method,
|
||||
self.path()
|
||||
)?;
|
||||
if !self.query_string().is_empty() {
|
||||
|
@ -363,7 +376,7 @@ impl HttpRequestPool {
|
|||
/// Re-use a previously allocated (but now completed/discarded) HttpRequest object.
|
||||
#[inline]
|
||||
pub(crate) fn get_request(&self) -> Option<HttpRequest> {
|
||||
self.0.borrow_mut().pop().map(HttpRequest)
|
||||
self.0.borrow_mut().pop().map(|inner| HttpRequest { inner })
|
||||
}
|
||||
|
||||
/// Clears all allocated HttpRequest objects.
|
||||
|
|
|
@ -9,9 +9,10 @@ use actix_http::{Error, Extensions, Response};
|
|||
use actix_router::IntoPattern;
|
||||
use actix_service::boxed::{self, BoxService, BoxServiceFactory};
|
||||
use actix_service::{
|
||||
apply, apply_fn_factory, IntoServiceFactory, Service, ServiceFactory, Transform,
|
||||
apply, apply_fn_factory, IntoServiceFactory, Service, ServiceFactory,
|
||||
ServiceFactoryExt, Transform,
|
||||
};
|
||||
use futures_util::future::{ok, Either, LocalBoxFuture, Ready};
|
||||
use futures_core::future::LocalBoxFuture;
|
||||
|
||||
use crate::data::Data;
|
||||
use crate::dev::{insert_slash, AppService, HttpServiceFactory, ResourceDef};
|
||||
|
@ -78,8 +79,8 @@ impl Resource {
|
|||
impl<T> Resource<T>
|
||||
where
|
||||
T: ServiceFactory<
|
||||
ServiceRequest,
|
||||
Config = (),
|
||||
Request = ServiceRequest,
|
||||
Response = ServiceResponse,
|
||||
Error = Error,
|
||||
InitError = (),
|
||||
|
@ -250,8 +251,8 @@ where
|
|||
mw: M,
|
||||
) -> Resource<
|
||||
impl ServiceFactory<
|
||||
ServiceRequest,
|
||||
Config = (),
|
||||
Request = ServiceRequest,
|
||||
Response = ServiceResponse,
|
||||
Error = Error,
|
||||
InitError = (),
|
||||
|
@ -260,7 +261,7 @@ where
|
|||
where
|
||||
M: Transform<
|
||||
T::Service,
|
||||
Request = ServiceRequest,
|
||||
ServiceRequest,
|
||||
Response = ServiceResponse,
|
||||
Error = Error,
|
||||
InitError = (),
|
||||
|
@ -317,8 +318,8 @@ where
|
|||
mw: F,
|
||||
) -> Resource<
|
||||
impl ServiceFactory<
|
||||
ServiceRequest,
|
||||
Config = (),
|
||||
Request = ServiceRequest,
|
||||
Response = ServiceResponse,
|
||||
Error = Error,
|
||||
InitError = (),
|
||||
|
@ -345,10 +346,10 @@ where
|
|||
/// default handler from `App` or `Scope`.
|
||||
pub fn default_service<F, U>(mut self, f: F) -> Self
|
||||
where
|
||||
F: IntoServiceFactory<U>,
|
||||
F: IntoServiceFactory<U, ServiceRequest>,
|
||||
U: ServiceFactory<
|
||||
ServiceRequest,
|
||||
Config = (),
|
||||
Request = ServiceRequest,
|
||||
Response = ServiceResponse,
|
||||
Error = Error,
|
||||
> + 'static,
|
||||
|
@ -368,8 +369,8 @@ where
|
|||
impl<T> HttpServiceFactory for Resource<T>
|
||||
where
|
||||
T: ServiceFactory<
|
||||
ServiceRequest,
|
||||
Config = (),
|
||||
Request = ServiceRequest,
|
||||
Response = ServiceResponse,
|
||||
Error = Error,
|
||||
InitError = (),
|
||||
|
@ -398,11 +399,11 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<T> IntoServiceFactory<T> for Resource<T>
|
||||
impl<T> IntoServiceFactory<T, ServiceRequest> for Resource<T>
|
||||
where
|
||||
T: ServiceFactory<
|
||||
ServiceRequest,
|
||||
Config = (),
|
||||
Request = ServiceRequest,
|
||||
Response = ServiceResponse,
|
||||
Error = Error,
|
||||
InitError = (),
|
||||
|
@ -425,13 +426,12 @@ pub struct ResourceFactory {
|
|||
default: Rc<RefCell<Option<Rc<HttpNewService>>>>,
|
||||
}
|
||||
|
||||
impl ServiceFactory for ResourceFactory {
|
||||
type Config = ();
|
||||
type Request = ServiceRequest;
|
||||
impl ServiceFactory<ServiceRequest> for ResourceFactory {
|
||||
type Response = ServiceResponse;
|
||||
type Error = Error;
|
||||
type InitError = ();
|
||||
type Config = ();
|
||||
type Service = ResourceService;
|
||||
type InitError = ();
|
||||
type Future = CreateResourceService;
|
||||
|
||||
fn new_service(&self, _: ()) -> Self::Future {
|
||||
|
@ -520,14 +520,10 @@ pub struct ResourceService {
|
|||
default: Option<HttpService>,
|
||||
}
|
||||
|
||||
impl Service for ResourceService {
|
||||
type Request = ServiceRequest;
|
||||
impl Service<ServiceRequest> for ResourceService {
|
||||
type Response = ServiceResponse;
|
||||
type Error = Error;
|
||||
type Future = Either<
|
||||
Ready<Result<ServiceResponse, Error>>,
|
||||
LocalBoxFuture<'static, Result<ServiceResponse, Error>>,
|
||||
>;
|
||||
type Future = LocalBoxFuture<'static, Result<ServiceResponse, Error>>;
|
||||
|
||||
fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||
Poll::Ready(Ok(()))
|
||||
|
@ -539,20 +535,22 @@ impl Service for ResourceService {
|
|||
if let Some(ref data) = self.data {
|
||||
req.add_data_container(data.clone());
|
||||
}
|
||||
return Either::Right(route.call(req));
|
||||
return route.call(req);
|
||||
}
|
||||
}
|
||||
if let Some(ref mut default) = self.default {
|
||||
if let Some(ref data) = self.data {
|
||||
req.add_data_container(data.clone());
|
||||
}
|
||||
Either::Right(default.call(req))
|
||||
default.call(req)
|
||||
} else {
|
||||
let req = req.into_parts().0;
|
||||
Either::Left(ok(ServiceResponse::new(
|
||||
req,
|
||||
Response::MethodNotAllowed().finish(),
|
||||
)))
|
||||
Box::pin(async {
|
||||
Ok(ServiceResponse::new(
|
||||
req,
|
||||
Response::MethodNotAllowed().finish(),
|
||||
))
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -568,9 +566,8 @@ impl ResourceEndpoint {
|
|||
}
|
||||
}
|
||||
|
||||
impl ServiceFactory for ResourceEndpoint {
|
||||
impl ServiceFactory<ServiceRequest> for ResourceEndpoint {
|
||||
type Config = ();
|
||||
type Request = ServiceRequest;
|
||||
type Response = ServiceResponse;
|
||||
type Error = Error;
|
||||
type InitError = ();
|
||||
|
@ -586,7 +583,7 @@ impl ServiceFactory for ResourceEndpoint {
|
|||
mod tests {
|
||||
use std::time::Duration;
|
||||
|
||||
use actix_rt::time::delay_for;
|
||||
use actix_rt::time::sleep;
|
||||
use actix_service::Service;
|
||||
use futures_util::future::ok;
|
||||
|
||||
|
@ -654,7 +651,7 @@ mod tests {
|
|||
async fn test_to() {
|
||||
let mut srv =
|
||||
init_service(App::new().service(web::resource("/test").to(|| async {
|
||||
delay_for(Duration::from_millis(100)).await;
|
||||
sleep(Duration::from_millis(100)).await;
|
||||
Ok::<_, Error>(HttpResponse::Ok())
|
||||
})))
|
||||
.await;
|
||||
|
|
|
@ -349,14 +349,14 @@ where
|
|||
pub struct ResponseFuture<T, E> {
|
||||
#[pin]
|
||||
fut: T,
|
||||
_t: PhantomData<E>,
|
||||
_phantom: PhantomData<E>,
|
||||
}
|
||||
|
||||
impl<T, E> ResponseFuture<T, E> {
|
||||
pub fn new(fut: T) -> Self {
|
||||
ResponseFuture {
|
||||
fut,
|
||||
_t: PhantomData,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ use std::cell::RefCell;
|
|||
use std::rc::{Rc, Weak};
|
||||
|
||||
use actix_router::ResourceDef;
|
||||
use fxhash::FxHashMap;
|
||||
use ahash::AHashMap;
|
||||
use url::Url;
|
||||
|
||||
use crate::error::UrlGenerationError;
|
||||
|
@ -12,7 +12,7 @@ use crate::request::HttpRequest;
|
|||
pub struct ResourceMap {
|
||||
root: ResourceDef,
|
||||
parent: RefCell<Weak<ResourceMap>>,
|
||||
named: FxHashMap<String, ResourceDef>,
|
||||
named: AHashMap<String, ResourceDef>,
|
||||
patterns: Vec<(ResourceDef, Option<Rc<ResourceMap>>)>,
|
||||
}
|
||||
|
||||
|
@ -21,7 +21,7 @@ impl ResourceMap {
|
|||
ResourceMap {
|
||||
root,
|
||||
parent: RefCell::new(Weak::new()),
|
||||
named: FxHashMap::default(),
|
||||
named: AHashMap::default(),
|
||||
patterns: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
|
38
src/route.rs
38
src/route.rs
|
@ -18,7 +18,7 @@ use crate::HttpResponse;
|
|||
|
||||
type BoxedRouteService = Box<
|
||||
dyn Service<
|
||||
Request = ServiceRequest,
|
||||
ServiceRequest,
|
||||
Response = ServiceResponse,
|
||||
Error = Error,
|
||||
Future = LocalBoxFuture<'static, Result<ServiceResponse, Error>>,
|
||||
|
@ -27,8 +27,8 @@ type BoxedRouteService = Box<
|
|||
|
||||
type BoxedRouteNewService = Box<
|
||||
dyn ServiceFactory<
|
||||
ServiceRequest,
|
||||
Config = (),
|
||||
Request = ServiceRequest,
|
||||
Response = ServiceResponse,
|
||||
Error = Error,
|
||||
InitError = (),
|
||||
|
@ -63,9 +63,8 @@ impl Route {
|
|||
}
|
||||
}
|
||||
|
||||
impl ServiceFactory for Route {
|
||||
impl ServiceFactory<ServiceRequest> for Route {
|
||||
type Config = ();
|
||||
type Request = ServiceRequest;
|
||||
type Response = ServiceResponse;
|
||||
type Error = Error;
|
||||
type InitError = ();
|
||||
|
@ -117,8 +116,7 @@ impl RouteService {
|
|||
}
|
||||
}
|
||||
|
||||
impl Service for RouteService {
|
||||
type Request = ServiceRequest;
|
||||
impl Service<ServiceRequest> for RouteService {
|
||||
type Response = ServiceResponse;
|
||||
type Error = Error;
|
||||
type Future = LocalBoxFuture<'static, Result<Self::Response, Self::Error>>;
|
||||
|
@ -233,7 +231,7 @@ impl Route {
|
|||
|
||||
struct RouteNewService<T>
|
||||
where
|
||||
T: ServiceFactory<Request = ServiceRequest, Error = Error>,
|
||||
T: ServiceFactory<ServiceRequest, Error = Error>,
|
||||
{
|
||||
service: T,
|
||||
}
|
||||
|
@ -241,33 +239,32 @@ where
|
|||
impl<T> RouteNewService<T>
|
||||
where
|
||||
T: ServiceFactory<
|
||||
ServiceRequest,
|
||||
Config = (),
|
||||
Request = ServiceRequest,
|
||||
Response = ServiceResponse,
|
||||
Error = Error,
|
||||
>,
|
||||
T::Future: 'static,
|
||||
T::Service: 'static,
|
||||
<T::Service as Service>::Future: 'static,
|
||||
<T::Service as Service<ServiceRequest>>::Future: 'static,
|
||||
{
|
||||
pub fn new(service: T) -> Self {
|
||||
RouteNewService { service }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ServiceFactory for RouteNewService<T>
|
||||
impl<T> ServiceFactory<ServiceRequest> for RouteNewService<T>
|
||||
where
|
||||
T: ServiceFactory<
|
||||
ServiceRequest,
|
||||
Config = (),
|
||||
Request = ServiceRequest,
|
||||
Response = ServiceResponse,
|
||||
Error = Error,
|
||||
>,
|
||||
T::Future: 'static,
|
||||
T::Service: 'static,
|
||||
<T::Service as Service>::Future: 'static,
|
||||
<T::Service as Service<ServiceRequest>>::Future: 'static,
|
||||
{
|
||||
type Request = ServiceRequest;
|
||||
type Response = ServiceResponse;
|
||||
type Error = Error;
|
||||
type Config = ();
|
||||
|
@ -289,16 +286,15 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
struct RouteServiceWrapper<T: Service> {
|
||||
struct RouteServiceWrapper<T: Service<ServiceRequest>> {
|
||||
service: T,
|
||||
}
|
||||
|
||||
impl<T> Service for RouteServiceWrapper<T>
|
||||
impl<T> Service<ServiceRequest> for RouteServiceWrapper<T>
|
||||
where
|
||||
T::Future: 'static,
|
||||
T: Service<Request = ServiceRequest, Response = ServiceResponse, Error = Error>,
|
||||
T: Service<ServiceRequest, Response = ServiceResponse, Error = Error>,
|
||||
{
|
||||
type Request = ServiceRequest;
|
||||
type Response = ServiceResponse;
|
||||
type Error = Error;
|
||||
type Future = LocalBoxFuture<'static, Result<Self::Response, Self::Error>>;
|
||||
|
@ -316,7 +312,7 @@ where
|
|||
mod tests {
|
||||
use std::time::Duration;
|
||||
|
||||
use actix_rt::time::delay_for;
|
||||
use actix_rt::time::sleep;
|
||||
use bytes::Bytes;
|
||||
use serde_derive::Serialize;
|
||||
|
||||
|
@ -340,16 +336,16 @@ mod tests {
|
|||
Err::<HttpResponse, _>(error::ErrorBadRequest("err"))
|
||||
}))
|
||||
.route(web::post().to(|| async {
|
||||
delay_for(Duration::from_millis(100)).await;
|
||||
sleep(Duration::from_millis(100)).await;
|
||||
Ok::<_, ()>(HttpResponse::Created())
|
||||
}))
|
||||
.route(web::delete().to(|| async {
|
||||
delay_for(Duration::from_millis(100)).await;
|
||||
sleep(Duration::from_millis(100)).await;
|
||||
Err::<HttpResponse, _>(error::ErrorBadRequest("err"))
|
||||
})),
|
||||
)
|
||||
.service(web::resource("/json").route(web::get().to(|| async {
|
||||
delay_for(Duration::from_millis(25)).await;
|
||||
sleep(Duration::from_millis(25)).await;
|
||||
web::Json(MyObject {
|
||||
name: "test".to_string(),
|
||||
})
|
||||
|
|
43
src/scope.rs
43
src/scope.rs
|
@ -9,9 +9,10 @@ use actix_http::{Extensions, Response};
|
|||
use actix_router::{ResourceDef, ResourceInfo, Router};
|
||||
use actix_service::boxed::{self, BoxService, BoxServiceFactory};
|
||||
use actix_service::{
|
||||
apply, apply_fn_factory, IntoServiceFactory, Service, ServiceFactory, Transform,
|
||||
apply, apply_fn_factory, IntoServiceFactory, Service, ServiceFactory,
|
||||
ServiceFactoryExt, Transform,
|
||||
};
|
||||
use futures_util::future::{ok, Either, LocalBoxFuture, Ready};
|
||||
use futures_core::future::LocalBoxFuture;
|
||||
|
||||
use crate::config::ServiceConfig;
|
||||
use crate::data::Data;
|
||||
|
@ -28,7 +29,6 @@ use crate::service::{
|
|||
type Guards = Vec<Box<dyn Guard>>;
|
||||
type HttpService = BoxService<ServiceRequest, ServiceResponse, Error>;
|
||||
type HttpNewService = BoxServiceFactory<(), ServiceRequest, ServiceResponse, Error, ()>;
|
||||
type BoxedResponse = LocalBoxFuture<'static, Result<ServiceResponse, Error>>;
|
||||
|
||||
/// Resources scope.
|
||||
///
|
||||
|
@ -89,8 +89,8 @@ impl Scope {
|
|||
impl<T> Scope<T>
|
||||
where
|
||||
T: ServiceFactory<
|
||||
ServiceRequest,
|
||||
Config = (),
|
||||
Request = ServiceRequest,
|
||||
Response = ServiceResponse,
|
||||
Error = Error,
|
||||
InitError = (),
|
||||
|
@ -285,10 +285,10 @@ where
|
|||
/// If default resource is not registered, app's default resource is being used.
|
||||
pub fn default_service<F, U>(mut self, f: F) -> Self
|
||||
where
|
||||
F: IntoServiceFactory<U>,
|
||||
F: IntoServiceFactory<U, ServiceRequest>,
|
||||
U: ServiceFactory<
|
||||
ServiceRequest,
|
||||
Config = (),
|
||||
Request = ServiceRequest,
|
||||
Response = ServiceResponse,
|
||||
Error = Error,
|
||||
> + 'static,
|
||||
|
@ -318,8 +318,8 @@ where
|
|||
mw: M,
|
||||
) -> Scope<
|
||||
impl ServiceFactory<
|
||||
ServiceRequest,
|
||||
Config = (),
|
||||
Request = ServiceRequest,
|
||||
Response = ServiceResponse,
|
||||
Error = Error,
|
||||
InitError = (),
|
||||
|
@ -328,7 +328,7 @@ where
|
|||
where
|
||||
M: Transform<
|
||||
T::Service,
|
||||
Request = ServiceRequest,
|
||||
ServiceRequest,
|
||||
Response = ServiceResponse,
|
||||
Error = Error,
|
||||
InitError = (),
|
||||
|
@ -383,8 +383,8 @@ where
|
|||
mw: F,
|
||||
) -> Scope<
|
||||
impl ServiceFactory<
|
||||
ServiceRequest,
|
||||
Config = (),
|
||||
Request = ServiceRequest,
|
||||
Response = ServiceResponse,
|
||||
Error = Error,
|
||||
InitError = (),
|
||||
|
@ -410,8 +410,8 @@ where
|
|||
impl<T> HttpServiceFactory for Scope<T>
|
||||
where
|
||||
T: ServiceFactory<
|
||||
ServiceRequest,
|
||||
Config = (),
|
||||
Request = ServiceRequest,
|
||||
Response = ServiceResponse,
|
||||
Error = Error,
|
||||
InitError = (),
|
||||
|
@ -481,9 +481,8 @@ pub struct ScopeFactory {
|
|||
default: Rc<RefCell<Option<Rc<HttpNewService>>>>,
|
||||
}
|
||||
|
||||
impl ServiceFactory for ScopeFactory {
|
||||
impl ServiceFactory<ServiceRequest> for ScopeFactory {
|
||||
type Config = ();
|
||||
type Request = ServiceRequest;
|
||||
type Response = ServiceResponse;
|
||||
type Error = Error;
|
||||
type InitError = ();
|
||||
|
@ -602,11 +601,10 @@ pub struct ScopeService {
|
|||
_ready: Option<(ServiceRequest, ResourceInfo)>,
|
||||
}
|
||||
|
||||
impl Service for ScopeService {
|
||||
type Request = ServiceRequest;
|
||||
impl Service<ServiceRequest> for ScopeService {
|
||||
type Response = ServiceResponse;
|
||||
type Error = Error;
|
||||
type Future = Either<BoxedResponse, Ready<Result<Self::Response, Self::Error>>>;
|
||||
type Future = LocalBoxFuture<'static, Result<Self::Response, Self::Error>>;
|
||||
|
||||
fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||
Poll::Ready(Ok(()))
|
||||
|
@ -628,15 +626,17 @@ impl Service for ScopeService {
|
|||
if let Some(ref data) = self.data {
|
||||
req.add_data_container(data.clone());
|
||||
}
|
||||
Either::Left(srv.call(req))
|
||||
srv.call(req)
|
||||
} else if let Some(ref mut default) = self.default {
|
||||
if let Some(ref data) = self.data {
|
||||
req.add_data_container(data.clone());
|
||||
}
|
||||
Either::Left(default.call(req))
|
||||
default.call(req)
|
||||
} else {
|
||||
let req = req.into_parts().0;
|
||||
Either::Right(ok(ServiceResponse::new(req, Response::NotFound().finish())))
|
||||
Box::pin(async {
|
||||
Ok(ServiceResponse::new(req, Response::NotFound().finish()))
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -652,13 +652,12 @@ impl ScopeEndpoint {
|
|||
}
|
||||
}
|
||||
|
||||
impl ServiceFactory for ScopeEndpoint {
|
||||
type Config = ();
|
||||
type Request = ServiceRequest;
|
||||
impl ServiceFactory<ServiceRequest> for ScopeEndpoint {
|
||||
type Response = ServiceResponse;
|
||||
type Error = Error;
|
||||
type InitError = ();
|
||||
type Config = ();
|
||||
type Service = ScopeService;
|
||||
type InitError = ();
|
||||
type Future = ScopeFactoryResponse;
|
||||
|
||||
fn new_service(&self, _: ()) -> Self::Future {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::{
|
||||
any::Any,
|
||||
fmt, io,
|
||||
cmp, fmt, io,
|
||||
marker::PhantomData,
|
||||
net,
|
||||
sync::{Arc, Mutex},
|
||||
|
@ -20,9 +20,9 @@ use actix_service::pipeline_factory;
|
|||
use futures_util::future::ok;
|
||||
|
||||
#[cfg(feature = "openssl")]
|
||||
use actix_tls::openssl::{AlpnError, SslAcceptor, SslAcceptorBuilder};
|
||||
use actix_tls::accept::openssl::{AlpnError, SslAcceptor, SslAcceptorBuilder};
|
||||
#[cfg(feature = "rustls")]
|
||||
use actix_tls::rustls::ServerConfig as RustlsServerConfig;
|
||||
use actix_tls::accept::rustls::ServerConfig as RustlsServerConfig;
|
||||
|
||||
use crate::config::AppConfig;
|
||||
|
||||
|
@ -58,8 +58,8 @@ struct Config {
|
|||
pub struct HttpServer<F, I, S, B>
|
||||
where
|
||||
F: Fn() -> I + Send + Clone + 'static,
|
||||
I: IntoServiceFactory<S>,
|
||||
S: ServiceFactory<Config = AppConfig, Request = Request>,
|
||||
I: IntoServiceFactory<S, Request>,
|
||||
S: ServiceFactory<Request, Config = AppConfig>,
|
||||
S::Error: Into<Error>,
|
||||
S::InitError: fmt::Debug,
|
||||
S::Response: Into<Response<B>>,
|
||||
|
@ -67,22 +67,23 @@ where
|
|||
{
|
||||
pub(super) factory: F,
|
||||
config: Arc<Mutex<Config>>,
|
||||
backlog: i32,
|
||||
backlog: u32,
|
||||
sockets: Vec<Socket>,
|
||||
builder: ServerBuilder,
|
||||
on_connect_fn: Option<Arc<dyn Fn(&dyn Any, &mut Extensions) + Send + Sync>>,
|
||||
_t: PhantomData<(S, B)>,
|
||||
_phantom: PhantomData<(S, B)>,
|
||||
}
|
||||
|
||||
impl<F, I, S, B> HttpServer<F, I, S, B>
|
||||
where
|
||||
F: Fn() -> I + Send + Clone + 'static,
|
||||
I: IntoServiceFactory<S>,
|
||||
S: ServiceFactory<Config = AppConfig, Request = Request>,
|
||||
I: IntoServiceFactory<S, Request>,
|
||||
S: ServiceFactory<Request, Config = AppConfig> + 'static,
|
||||
S::Error: Into<Error> + 'static,
|
||||
S::InitError: fmt::Debug,
|
||||
S::Response: Into<Response<B>> + 'static,
|
||||
<S::Service as Service>::Future: 'static,
|
||||
<S::Service as Service<Request>>::Future: 'static,
|
||||
S::Service: 'static,
|
||||
B: MessageBody + 'static,
|
||||
{
|
||||
/// Create new http server with application factory
|
||||
|
@ -99,7 +100,7 @@ where
|
|||
sockets: Vec::new(),
|
||||
builder: ServerBuilder::default(),
|
||||
on_connect_fn: None,
|
||||
_t: PhantomData,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -124,7 +125,7 @@ where
|
|||
sockets: self.sockets,
|
||||
builder: self.builder,
|
||||
on_connect_fn: Some(Arc::new(f)),
|
||||
_t: PhantomData,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -147,7 +148,7 @@ where
|
|||
/// Generally set in the 64-2048 range. Default value is 2048.
|
||||
///
|
||||
/// This method should be called before `bind()` method call.
|
||||
pub fn backlog(mut self, backlog: i32) -> Self {
|
||||
pub fn backlog(mut self, backlog: u32) -> Self {
|
||||
self.backlog = backlog;
|
||||
self.builder = self.builder.backlog(backlog);
|
||||
self
|
||||
|
@ -170,8 +171,10 @@ where
|
|||
/// limit the global TLS CPU usage.
|
||||
///
|
||||
/// By default max connections is set to a 256.
|
||||
#[allow(unused_variables)]
|
||||
pub fn max_connection_rate(self, num: usize) -> Self {
|
||||
actix_tls::max_concurrent_tls_connect(num);
|
||||
#[cfg(any(feature = "rustls", feature = "openssl"))]
|
||||
actix_tls::accept::max_concurrent_tls_connect(num);
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -603,8 +606,8 @@ where
|
|||
impl<F, I, S, B> HttpServer<F, I, S, B>
|
||||
where
|
||||
F: Fn() -> I + Send + Clone + 'static,
|
||||
I: IntoServiceFactory<S>,
|
||||
S: ServiceFactory<Config = AppConfig, Request = Request>,
|
||||
I: IntoServiceFactory<S, Request>,
|
||||
S: ServiceFactory<Request, Config = AppConfig>,
|
||||
S::Error: Into<Error>,
|
||||
S::InitError: fmt::Debug,
|
||||
S::Response: Into<Response<B>>,
|
||||
|
@ -639,7 +642,7 @@ where
|
|||
|
||||
fn create_tcp_listener(
|
||||
addr: net::SocketAddr,
|
||||
backlog: i32,
|
||||
backlog: u32,
|
||||
) -> io::Result<net::TcpListener> {
|
||||
use socket2::{Domain, Protocol, Socket, Type};
|
||||
let domain = match addr {
|
||||
|
@ -649,6 +652,8 @@ fn create_tcp_listener(
|
|||
let socket = Socket::new(domain, Type::stream(), Some(Protocol::tcp()))?;
|
||||
socket.set_reuse_address(true)?;
|
||||
socket.bind(&addr.into())?;
|
||||
// clamp backlog to max u32 that fits in i32 range
|
||||
let backlog = cmp::min(backlog, i32::MAX as u32) as i32;
|
||||
socket.listen(backlog)?;
|
||||
Ok(socket.into_tcp_listener())
|
||||
}
|
||||
|
|
|
@ -62,7 +62,7 @@ impl ServiceRequest {
|
|||
|
||||
/// Deconstruct request into parts
|
||||
pub fn into_parts(mut self) -> (HttpRequest, Payload) {
|
||||
let pl = Rc::get_mut(&mut (self.0).0).unwrap().payload.take();
|
||||
let pl = Rc::get_mut(&mut (self.0).inner).unwrap().payload.take();
|
||||
(self.0, pl)
|
||||
}
|
||||
|
||||
|
@ -73,11 +73,12 @@ impl ServiceRequest {
|
|||
mut req: HttpRequest,
|
||||
pl: Payload,
|
||||
) -> Result<Self, (HttpRequest, Payload)> {
|
||||
if Rc::strong_count(&req.0) == 1 && Rc::weak_count(&req.0) == 0 {
|
||||
Rc::get_mut(&mut req.0).unwrap().payload = pl;
|
||||
Ok(ServiceRequest(req))
|
||||
} else {
|
||||
Err((req, pl))
|
||||
match Rc::get_mut(&mut req.inner) {
|
||||
Some(p) => {
|
||||
p.payload = pl;
|
||||
Ok(ServiceRequest(req))
|
||||
}
|
||||
None => Err((req, pl)),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -87,7 +88,10 @@ impl ServiceRequest {
|
|||
/// can be re-constructed only if rc's strong pointers count eq 1 and
|
||||
/// weak pointers count is 0.
|
||||
pub fn from_request(req: HttpRequest) -> Result<Self, HttpRequest> {
|
||||
if Rc::strong_count(&req.0) == 1 && Rc::weak_count(&req.0) == 0 {
|
||||
// There is no weak pointer used on HttpRequest so intentionally
|
||||
// ignore the check.
|
||||
if Rc::strong_count(&req.inner) == 1 {
|
||||
debug_assert!(Rc::weak_count(&req.inner) == 0);
|
||||
Ok(ServiceRequest(req))
|
||||
} else {
|
||||
Err(req)
|
||||
|
@ -227,7 +231,7 @@ impl ServiceRequest {
|
|||
|
||||
/// Counterpart to [`HttpRequest::app_data`](super::HttpRequest::app_data()).
|
||||
pub fn app_data<T: 'static>(&self) -> Option<&T> {
|
||||
for container in (self.0).0.app_data.iter().rev() {
|
||||
for container in (self.0).inner.app_data.iter().rev() {
|
||||
if let Some(data) = container.get::<T>() {
|
||||
return Some(data);
|
||||
}
|
||||
|
@ -238,13 +242,13 @@ impl ServiceRequest {
|
|||
|
||||
/// Set request payload.
|
||||
pub fn set_payload(&mut self, payload: Payload) {
|
||||
Rc::get_mut(&mut (self.0).0).unwrap().payload = payload;
|
||||
Rc::get_mut(&mut (self.0).inner).unwrap().payload = payload;
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
/// Add app data container to request's resolution set.
|
||||
pub fn add_data_container(&mut self, extensions: Rc<Extensions>) {
|
||||
Rc::get_mut(&mut (self.0).0)
|
||||
Rc::get_mut(&mut (self.0).inner)
|
||||
.unwrap()
|
||||
.app_data
|
||||
.push(extensions);
|
||||
|
@ -280,7 +284,7 @@ impl HttpMessage for ServiceRequest {
|
|||
|
||||
#[inline]
|
||||
fn take_payload(&mut self) -> Payload<Self::Stream> {
|
||||
Rc::get_mut(&mut (self.0).0).unwrap().payload.take()
|
||||
Rc::get_mut(&mut (self.0).inner).unwrap().payload.take()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -486,10 +490,10 @@ impl WebService {
|
|||
/// Set a service factory implementation and generate web service.
|
||||
pub fn finish<T, F>(self, service: F) -> impl HttpServiceFactory
|
||||
where
|
||||
F: IntoServiceFactory<T>,
|
||||
F: IntoServiceFactory<T, ServiceRequest>,
|
||||
T: ServiceFactory<
|
||||
ServiceRequest,
|
||||
Config = (),
|
||||
Request = ServiceRequest,
|
||||
Response = ServiceResponse,
|
||||
Error = Error,
|
||||
InitError = (),
|
||||
|
@ -514,8 +518,8 @@ struct WebServiceImpl<T> {
|
|||
impl<T> HttpServiceFactory for WebServiceImpl<T>
|
||||
where
|
||||
T: ServiceFactory<
|
||||
ServiceRequest,
|
||||
Config = (),
|
||||
Request = ServiceRequest,
|
||||
Response = ServiceResponse,
|
||||
Error = Error,
|
||||
InitError = (),
|
||||
|
|
54
src/test.rs
54
src/test.rs
|
@ -11,7 +11,7 @@ use actix_http::http::{Error as HttpError, Method, StatusCode, Uri, Version};
|
|||
use actix_http::test::TestRequest as HttpTestRequest;
|
||||
use actix_http::{cookie::Cookie, ws, Extensions, HttpService, Request};
|
||||
use actix_router::{Path, ResourceDef, Url};
|
||||
use actix_rt::{time::delay_for, System};
|
||||
use actix_rt::{time::sleep, System};
|
||||
use actix_service::{
|
||||
map_config, IntoService, IntoServiceFactory, Service, ServiceFactory,
|
||||
};
|
||||
|
@ -37,16 +37,14 @@ use crate::{Error, HttpRequest, HttpResponse};
|
|||
|
||||
/// Create service that always responds with `HttpResponse::Ok()`
|
||||
pub fn ok_service(
|
||||
) -> impl Service<Request = ServiceRequest, Response = ServiceResponse<Body>, Error = Error>
|
||||
{
|
||||
) -> impl Service<ServiceRequest, Response = ServiceResponse<Body>, Error = Error> {
|
||||
default_service(StatusCode::OK)
|
||||
}
|
||||
|
||||
/// Create service that responds with response with specified status code
|
||||
pub fn default_service(
|
||||
status_code: StatusCode,
|
||||
) -> impl Service<Request = ServiceRequest, Response = ServiceResponse<Body>, Error = Error>
|
||||
{
|
||||
) -> impl Service<ServiceRequest, Response = ServiceResponse<Body>, Error = Error> {
|
||||
(move |req: ServiceRequest| {
|
||||
ok(req.into_response(HttpResponse::build(status_code).finish()))
|
||||
})
|
||||
|
@ -77,12 +75,12 @@ pub fn default_service(
|
|||
/// ```
|
||||
pub async fn init_service<R, S, B, E>(
|
||||
app: R,
|
||||
) -> impl Service<Request = Request, Response = ServiceResponse<B>, Error = E>
|
||||
) -> impl Service<Request, Response = ServiceResponse<B>, Error = E>
|
||||
where
|
||||
R: IntoServiceFactory<S>,
|
||||
R: IntoServiceFactory<S, Request>,
|
||||
S: ServiceFactory<
|
||||
Request,
|
||||
Config = AppConfig,
|
||||
Request = Request,
|
||||
Response = ServiceResponse<B>,
|
||||
Error = E,
|
||||
>,
|
||||
|
@ -96,15 +94,12 @@ where
|
|||
/// Fallible version of init_service that allows testing data factory errors.
|
||||
pub(crate) async fn try_init_service<R, S, B, E>(
|
||||
app: R,
|
||||
) -> Result<
|
||||
impl Service<Request = Request, Response = ServiceResponse<B>, Error = E>,
|
||||
S::InitError,
|
||||
>
|
||||
) -> Result<impl Service<Request, Response = ServiceResponse<B>, Error = E>, S::InitError>
|
||||
where
|
||||
R: IntoServiceFactory<S>,
|
||||
R: IntoServiceFactory<S, Request>,
|
||||
S: ServiceFactory<
|
||||
Request,
|
||||
Config = AppConfig,
|
||||
Request = Request,
|
||||
Response = ServiceResponse<B>,
|
||||
Error = E,
|
||||
>,
|
||||
|
@ -138,7 +133,7 @@ where
|
|||
/// ```
|
||||
pub async fn call_service<S, R, B, E>(app: &mut S, req: R) -> S::Response
|
||||
where
|
||||
S: Service<Request = R, Response = ServiceResponse<B>, Error = E>,
|
||||
S: Service<R, Response = ServiceResponse<B>, Error = E>,
|
||||
E: std::fmt::Debug,
|
||||
{
|
||||
app.call(req).await.unwrap()
|
||||
|
@ -171,7 +166,7 @@ where
|
|||
/// ```
|
||||
pub async fn read_response<S, B>(app: &mut S, req: Request) -> Bytes
|
||||
where
|
||||
S: Service<Request = Request, Response = ServiceResponse<B>, Error = Error>,
|
||||
S: Service<Request, Response = ServiceResponse<B>, Error = Error>,
|
||||
B: MessageBody + Unpin,
|
||||
{
|
||||
let mut resp = app
|
||||
|
@ -321,7 +316,7 @@ where
|
|||
/// ```
|
||||
pub async fn read_response_json<S, B, T>(app: &mut S, req: Request) -> T
|
||||
where
|
||||
S: Service<Request = Request, Response = ServiceResponse<B>, Error = Error>,
|
||||
S: Service<Request, Response = ServiceResponse<B>, Error = Error>,
|
||||
B: MessageBody + Unpin,
|
||||
T: DeserializeOwned,
|
||||
{
|
||||
|
@ -602,7 +597,7 @@ impl TestRequest {
|
|||
/// Complete request creation, calls service and waits for response future completion.
|
||||
pub async fn send_request<S, B, E>(self, app: &mut S) -> S::Response
|
||||
where
|
||||
S: Service<Request = Request, Response = ServiceResponse<B>, Error = E>,
|
||||
S: Service<Request, Response = ServiceResponse<B>, Error = E>,
|
||||
E: std::fmt::Debug,
|
||||
{
|
||||
let req = self.to_request();
|
||||
|
@ -639,12 +634,12 @@ impl TestRequest {
|
|||
pub fn start<F, I, S, B>(factory: F) -> TestServer
|
||||
where
|
||||
F: Fn() -> I + Send + Clone + 'static,
|
||||
I: IntoServiceFactory<S>,
|
||||
S: ServiceFactory<Config = AppConfig, Request = Request> + 'static,
|
||||
I: IntoServiceFactory<S, Request>,
|
||||
S: ServiceFactory<Request, Config = AppConfig> + 'static,
|
||||
S::Error: Into<Error> + 'static,
|
||||
S::InitError: fmt::Debug,
|
||||
S::Response: Into<HttpResponse<B>> + 'static,
|
||||
<S::Service as Service>::Future: 'static,
|
||||
<S::Service as Service<Request>>::Future: 'static,
|
||||
B: MessageBody + 'static,
|
||||
{
|
||||
start_with(TestServerConfig::default(), factory)
|
||||
|
@ -678,12 +673,12 @@ where
|
|||
pub fn start_with<F, I, S, B>(cfg: TestServerConfig, factory: F) -> TestServer
|
||||
where
|
||||
F: Fn() -> I + Send + Clone + 'static,
|
||||
I: IntoServiceFactory<S>,
|
||||
S: ServiceFactory<Config = AppConfig, Request = Request> + 'static,
|
||||
I: IntoServiceFactory<S, Request>,
|
||||
S: ServiceFactory<Request, Config = AppConfig> + 'static,
|
||||
S::Error: Into<Error> + 'static,
|
||||
S::InitError: fmt::Debug,
|
||||
S::Response: Into<HttpResponse<B>> + 'static,
|
||||
<S::Service as Service>::Future: 'static,
|
||||
<S::Service as Service<Request>>::Future: 'static,
|
||||
B: MessageBody + 'static,
|
||||
{
|
||||
let (tx, rx) = mpsc::channel();
|
||||
|
@ -788,10 +783,13 @@ where
|
|||
}),
|
||||
},
|
||||
}
|
||||
.unwrap()
|
||||
.start();
|
||||
.unwrap();
|
||||
|
||||
sys.block_on(async {
|
||||
let srv = srv.start();
|
||||
tx.send((System::current(), srv, local_addr)).unwrap();
|
||||
});
|
||||
|
||||
tx.send((System::current(), srv, local_addr)).unwrap();
|
||||
sys.run()
|
||||
});
|
||||
|
||||
|
@ -1022,7 +1020,7 @@ impl TestServer {
|
|||
pub async fn stop(self) {
|
||||
self.server.stop(true).await;
|
||||
self.system.stop();
|
||||
delay_for(time::Duration::from_millis(100)).await;
|
||||
sleep(time::Duration::from_millis(100)).await;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -367,7 +367,7 @@ where
|
|||
let json = if let Ok(Some(mime)) = req.mime_type() {
|
||||
mime.subtype() == mime::JSON
|
||||
|| mime.suffix() == Some(mime::JSON)
|
||||
|| ctype.as_ref().map_or(false, |predicate| predicate(mime))
|
||||
|| ctype.map_or(false, |predicate| predicate(mime))
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
|
|
@ -539,7 +539,7 @@ mod tests {
|
|||
.into_parts();
|
||||
let res = HttpMessageBody::new(&req, &mut pl).await;
|
||||
match res.err().unwrap() {
|
||||
PayloadError::UnknownLength => (),
|
||||
PayloadError::UnknownLength => {}
|
||||
_ => unreachable!("error"),
|
||||
}
|
||||
|
||||
|
@ -548,7 +548,7 @@ mod tests {
|
|||
.into_parts();
|
||||
let res = HttpMessageBody::new(&req, &mut pl).await;
|
||||
match res.err().unwrap() {
|
||||
PayloadError::Overflow => (),
|
||||
PayloadError::Overflow => {}
|
||||
_ => unreachable!("error"),
|
||||
}
|
||||
|
||||
|
@ -563,7 +563,7 @@ mod tests {
|
|||
.to_http_parts();
|
||||
let res = HttpMessageBody::new(&req, &mut pl).limit(5).await;
|
||||
match res.err().unwrap() {
|
||||
PayloadError::Overflow => (),
|
||||
PayloadError::Overflow => {}
|
||||
_ => unreachable!("error"),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@ use std::future::Future;
|
|||
|
||||
pub use actix_http::Response as HttpResponse;
|
||||
pub use bytes::{Buf, BufMut, Bytes, BytesMut};
|
||||
pub use futures_channel::oneshot::Canceled;
|
||||
|
||||
use crate::error::BlockingError;
|
||||
use crate::extract::FromRequest;
|
||||
|
|
|
@ -15,26 +15,30 @@ async fn test_start() {
|
|||
thread::spawn(move || {
|
||||
let sys = actix_rt::System::new("test");
|
||||
|
||||
let srv = HttpServer::new(|| {
|
||||
App::new().service(
|
||||
web::resource("/").route(web::to(|| HttpResponse::Ok().body("test"))),
|
||||
)
|
||||
})
|
||||
.workers(1)
|
||||
.backlog(1)
|
||||
.max_connections(10)
|
||||
.max_connection_rate(10)
|
||||
.keep_alive(10)
|
||||
.client_timeout(5000)
|
||||
.client_shutdown(0)
|
||||
.server_hostname("localhost")
|
||||
.system_exit()
|
||||
.disable_signals()
|
||||
.bind(format!("{}", addr))
|
||||
.unwrap()
|
||||
.run();
|
||||
sys.block_on(async {
|
||||
let srv = HttpServer::new(|| {
|
||||
App::new().service(
|
||||
web::resource("/")
|
||||
.route(web::to(|| HttpResponse::Ok().body("test"))),
|
||||
)
|
||||
})
|
||||
.workers(1)
|
||||
.backlog(1)
|
||||
.max_connections(10)
|
||||
.max_connection_rate(10)
|
||||
.keep_alive(10)
|
||||
.client_timeout(5000)
|
||||
.client_shutdown(0)
|
||||
.server_hostname("localhost")
|
||||
.system_exit()
|
||||
.disable_signals()
|
||||
.bind(format!("{}", addr))
|
||||
.unwrap()
|
||||
.run();
|
||||
|
||||
let _ = tx.send((srv, actix_rt::System::current()));
|
||||
});
|
||||
|
||||
let _ = tx.send((srv, actix_rt::System::current()));
|
||||
let _ = sys.run();
|
||||
});
|
||||
let (srv, sys) = rx.recv().unwrap();
|
||||
|
@ -101,10 +105,13 @@ async fn test_start_ssl() {
|
|||
.system_exit()
|
||||
.disable_signals()
|
||||
.bind_openssl(format!("{}", addr), builder)
|
||||
.unwrap()
|
||||
.run();
|
||||
.unwrap();
|
||||
|
||||
sys.block_on(async {
|
||||
let srv = srv.run();
|
||||
let _ = tx.send((srv, actix_rt::System::current()));
|
||||
});
|
||||
|
||||
let _ = tx.send((srv, actix_rt::System::current()));
|
||||
let _ = sys.run();
|
||||
});
|
||||
let (srv, sys) = rx.recv().unwrap();
|
||||
|
|
|
@ -45,7 +45,7 @@ const STR: &str = "Hello World Hello World Hello World Hello World Hello World \
|
|||
struct TestBody {
|
||||
data: Bytes,
|
||||
chunk_size: usize,
|
||||
delay: actix_rt::time::Delay,
|
||||
delay: Pin<Box<actix_rt::time::Sleep>>,
|
||||
}
|
||||
|
||||
impl TestBody {
|
||||
|
@ -53,7 +53,7 @@ impl TestBody {
|
|||
TestBody {
|
||||
data,
|
||||
chunk_size,
|
||||
delay: actix_rt::time::delay_for(std::time::Duration::from_millis(10)),
|
||||
delay: Box::pin(actix_rt::time::sleep(std::time::Duration::from_millis(10))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -67,7 +67,8 @@ impl futures_core::stream::Stream for TestBody {
|
|||
) -> Poll<Option<Self::Item>> {
|
||||
ready!(Pin::new(&mut self.delay).poll(cx));
|
||||
|
||||
self.delay = actix_rt::time::delay_for(std::time::Duration::from_millis(10));
|
||||
self.delay =
|
||||
Box::pin(actix_rt::time::sleep(std::time::Duration::from_millis(10)));
|
||||
let chunk_size = std::cmp::min(self.chunk_size, self.data.len());
|
||||
let chunk = self.data.split_to(chunk_size);
|
||||
if chunk.is_empty() {
|
||||
|
|
Loading…
Reference in New Issue