update to latest master branch of actix-net

This commit is contained in:
fakeshadow 2021-02-05 00:22:36 +08:00
commit 78a8b4173d
66 changed files with 698 additions and 718 deletions

View File

@ -11,7 +11,11 @@
* `ServiceRequest::into_parts` and `ServiceRequest::from_parts` would not fail.
`ServiceRequest::from_request` would not fail and no payload would be generated [#1893]
* Our `Either` type now uses `Left`/`Right` variants (instead of `A`/`B`) [#1894]
* `test::{call_service, read_response, read_response_json, send_request}` take `&Service`
in argument [#1905]
* `App::wrap_fn`, `Resource::wrap_fn` and `Scope::wrap_fn` would give `&Service` in closure
argument [#1905]
### Fixed
* Multiple calls `App::data` with the same type now keeps the latest call's data. [#1906]
@ -27,6 +31,7 @@
[#1893]: https://github.com/actix/actix-web/pull/1893
[#1894]: https://github.com/actix/actix-web/pull/1894
[#1869]: https://github.com/actix/actix-web/pull/1869
[#1905]: https://github.com/actix/actix-web/pull/1905
[#1906]: https://github.com/actix/actix-web/pull/1906

View File

@ -74,9 +74,9 @@ required-features = ["rustls"]
[dependencies]
actix-codec = "0.4.0-beta.1"
actix-macros = "0.1.0"
actix-router = "0.2.4"
actix-rt = "2.0.0-beta.2"
actix-macros = "0.2.0"
actix-router = "0.2.6"
actix-rt = "2"
actix-server = "2.0.0-beta.2"
actix-service = "2.0.0-beta.3"
actix-utils = "3.0.0-beta.1"
@ -132,7 +132,12 @@ actix-multipart = { path = "actix-multipart" }
actix-files = { path = "actix-files" }
awc = { path = "awc" }
actix-tls = { git = "https://github.com/actix/actix-net", branch = "refactor/resolver" }
actix-service = { git = "https://github.com/actix/actix-net.git" }
actix-server = { git = "https://github.com/actix/actix-net.git" }
actix-tls = { git = "https://github.com/actix/actix-net.git" }
actix-utils = { git = "https://github.com/actix/actix-net.git" }
actix-router = { git = "https://github.com/actix/actix-net.git" }
actix = { git = "https://github.com/actix/actix.git", branch = "feat/actix-rt-2" }
[[bench]]
name = "server"

View File

@ -31,5 +31,5 @@ percent-encoding = "2.1"
v_htmlescape = "0.12"
[dev-dependencies]
actix-rt = "2.0.0-beta.2"
actix-rt = "2"
actix-web = "4.0.0-beta.1"

View File

@ -73,7 +73,8 @@ mod tests {
},
middleware::Compress,
test::{self, TestRequest},
web, App, HttpResponse, Responder,
web::{self, Bytes},
App, HttpResponse, Responder,
};
use futures_util::future::ok;
@ -365,7 +366,7 @@ mod tests {
DispositionType::Attachment
}
let mut srv = test::init_service(
let srv = test::init_service(
App::new().service(
Files::new("/", ".")
.mime_override(all_attachment)
@ -375,7 +376,7 @@ mod tests {
.await;
let request = TestRequest::get().uri("/").to_request();
let response = test::call_service(&mut srv, request).await;
let response = test::call_service(&srv, request).await;
assert_eq!(response.status(), StatusCode::OK);
let content_disposition = response
@ -390,7 +391,7 @@ mod tests {
#[actix_rt::test]
async fn test_named_file_ranges_status_code() {
let mut srv = test::init_service(
let srv = test::init_service(
App::new().service(Files::new("/test", ".").index_file("Cargo.toml")),
)
.await;
@ -400,7 +401,7 @@ mod tests {
.uri("/t%65st/Cargo.toml")
.insert_header((header::RANGE, "bytes=10-20"))
.to_request();
let response = test::call_service(&mut srv, request).await;
let response = test::call_service(&srv, request).await;
assert_eq!(response.status(), StatusCode::PARTIAL_CONTENT);
// Invalid range header
@ -408,7 +409,7 @@ mod tests {
.uri("/t%65st/Cargo.toml")
.insert_header((header::RANGE, "bytes=1-0"))
.to_request();
let response = test::call_service(&mut srv, request).await;
let response = test::call_service(&srv, request).await;
assert_eq!(response.status(), StatusCode::RANGE_NOT_SATISFIABLE);
}
@ -495,14 +496,14 @@ mod tests {
#[actix_rt::test]
async fn test_static_files_with_spaces() {
let mut srv = test::init_service(
let srv = test::init_service(
App::new().service(Files::new("/", ".").index_file("Cargo.toml")),
)
.await;
let request = TestRequest::get()
.uri("/tests/test%20space.binary")
.to_request();
let response = test::call_service(&mut srv, request).await;
let response = test::call_service(&srv, request).await;
assert_eq!(response.status(), StatusCode::OK);
let bytes = test::read_body(response).await;
@ -512,28 +513,28 @@ mod tests {
#[actix_rt::test]
async fn test_files_not_allowed() {
let mut srv = test::init_service(App::new().service(Files::new("/", "."))).await;
let srv = test::init_service(App::new().service(Files::new("/", "."))).await;
let req = TestRequest::default()
.uri("/Cargo.toml")
.method(Method::POST)
.to_request();
let resp = test::call_service(&mut srv, req).await;
let resp = test::call_service(&srv, req).await;
assert_eq!(resp.status(), StatusCode::METHOD_NOT_ALLOWED);
let mut srv = test::init_service(App::new().service(Files::new("/", "."))).await;
let srv = test::init_service(App::new().service(Files::new("/", "."))).await;
let req = TestRequest::default()
.method(Method::PUT)
.uri("/Cargo.toml")
.to_request();
let resp = test::call_service(&mut srv, req).await;
let resp = test::call_service(&srv, req).await;
assert_eq!(resp.status(), StatusCode::METHOD_NOT_ALLOWED);
}
#[actix_rt::test]
async fn test_files_guards() {
let mut srv = test::init_service(
let srv = test::init_service(
App::new().service(Files::new("/", ".").use_guards(guard::Post())),
)
.await;
@ -543,13 +544,13 @@ mod tests {
.method(Method::POST)
.to_request();
let resp = test::call_service(&mut srv, req).await;
let resp = test::call_service(&srv, req).await;
assert_eq!(resp.status(), StatusCode::OK);
}
#[actix_rt::test]
async fn test_named_file_content_encoding() {
let mut srv = test::init_service(App::new().wrap(Compress::default()).service(
let srv = test::init_service(App::new().wrap(Compress::default()).service(
web::resource("/").to(|| async {
NamedFile::open("Cargo.toml")
.unwrap()
@ -562,14 +563,14 @@ mod tests {
.uri("/")
.insert_header((header::ACCEPT_ENCODING, "gzip"))
.to_request();
let res = test::call_service(&mut srv, request).await;
let res = test::call_service(&srv, request).await;
assert_eq!(res.status(), StatusCode::OK);
assert!(!res.headers().contains_key(header::CONTENT_ENCODING));
}
#[actix_rt::test]
async fn test_named_file_content_encoding_gzip() {
let mut srv = test::init_service(App::new().wrap(Compress::default()).service(
let srv = test::init_service(App::new().wrap(Compress::default()).service(
web::resource("/").to(|| async {
NamedFile::open("Cargo.toml")
.unwrap()
@ -582,7 +583,7 @@ mod tests {
.uri("/")
.insert_header((header::ACCEPT_ENCODING, "gzip"))
.to_request();
let res = test::call_service(&mut srv, request).await;
let res = test::call_service(&srv, request).await;
assert_eq!(res.status(), StatusCode::OK);
assert_eq!(
res.headers()
@ -604,27 +605,27 @@ mod tests {
#[actix_rt::test]
async fn test_static_files() {
let mut srv = test::init_service(
let srv = test::init_service(
App::new().service(Files::new("/", ".").show_files_listing()),
)
.await;
let req = TestRequest::with_uri("/missing").to_request();
let resp = test::call_service(&mut srv, req).await;
let resp = test::call_service(&srv, req).await;
assert_eq!(resp.status(), StatusCode::NOT_FOUND);
let mut srv = test::init_service(App::new().service(Files::new("/", "."))).await;
let srv = test::init_service(App::new().service(Files::new("/", "."))).await;
let req = TestRequest::default().to_request();
let resp = test::call_service(&mut srv, req).await;
let resp = test::call_service(&srv, req).await;
assert_eq!(resp.status(), StatusCode::NOT_FOUND);
let mut srv = test::init_service(
let srv = test::init_service(
App::new().service(Files::new("/", ".").show_files_listing()),
)
.await;
let req = TestRequest::with_uri("/tests").to_request();
let resp = test::call_service(&mut srv, req).await;
let resp = test::call_service(&srv, req).await;
assert_eq!(
resp.headers().get(header::CONTENT_TYPE).unwrap(),
"text/html; charset=utf-8"
@ -637,16 +638,16 @@ mod tests {
#[actix_rt::test]
async fn test_redirect_to_slash_directory() {
// should not redirect if no index
let mut srv = test::init_service(
let srv = test::init_service(
App::new().service(Files::new("/", ".").redirect_to_slash_directory()),
)
.await;
let req = TestRequest::with_uri("/tests").to_request();
let resp = test::call_service(&mut srv, req).await;
let resp = test::call_service(&srv, req).await;
assert_eq!(resp.status(), StatusCode::NOT_FOUND);
// should redirect if index present
let mut srv = test::init_service(
let srv = test::init_service(
App::new().service(
Files::new("/", ".")
.index_file("test.png")
@ -655,12 +656,12 @@ mod tests {
)
.await;
let req = TestRequest::with_uri("/tests").to_request();
let resp = test::call_service(&mut srv, req).await;
let resp = test::call_service(&srv, req).await;
assert_eq!(resp.status(), StatusCode::FOUND);
// should not redirect if the path is wrong
let req = TestRequest::with_uri("/not_existing").to_request();
let resp = test::call_service(&mut srv, req).await;
let resp = test::call_service(&srv, req).await;
assert_eq!(resp.status(), StatusCode::NOT_FOUND);
}
@ -672,7 +673,7 @@ mod tests {
#[actix_rt::test]
async fn test_default_handler_file_missing() {
let mut st = Files::new("/", ".")
let st = Files::new("/", ".")
.default_handler(|req: ServiceRequest| {
ok(req.into_response(HttpResponse::Ok().body("default content")))
})
@ -681,7 +682,7 @@ mod tests {
.unwrap();
let req = TestRequest::with_uri("/missing").to_srv_request();
let resp = test::call_service(&mut st, req).await;
let resp = test::call_service(&st, req).await;
assert_eq!(resp.status(), StatusCode::OK);
let bytes = test::read_body(resp).await;
assert_eq!(bytes, web::Bytes::from_static(b"default content"));
@ -750,54 +751,49 @@ mod tests {
// );
// }
// #[actix_rt::test]
// fn integration_serve_index() {
// let mut srv = test::TestServer::with_factory(|| {
// App::new().handler(
// "test",
// Files::new(".").index_file("Cargo.toml"),
// )
// });
#[actix_rt::test]
async fn integration_serve_index() {
let srv = test::init_service(
App::new().service(Files::new("test", ".").index_file("Cargo.toml")),
)
.await;
// let request = srv.get().uri(srv.url("/test")).finish().unwrap();
// let response = srv.execute(request.send()).unwrap();
// assert_eq!(response.status(), StatusCode::OK);
// let bytes = srv.execute(response.body()).unwrap();
// let data = Bytes::from(fs::read("Cargo.toml").unwrap());
// assert_eq!(bytes, data);
let req = TestRequest::get().uri("/test").to_request();
let res = test::call_service(&srv, req).await;
assert_eq!(res.status(), StatusCode::OK);
// let request = srv.get().uri(srv.url("/test/")).finish().unwrap();
// let response = srv.execute(request.send()).unwrap();
// assert_eq!(response.status(), StatusCode::OK);
// let bytes = srv.execute(response.body()).unwrap();
// let data = Bytes::from(fs::read("Cargo.toml").unwrap());
// assert_eq!(bytes, data);
let bytes = test::read_body(res).await;
// // nonexistent index file
// let request = srv.get().uri(srv.url("/test/unknown")).finish().unwrap();
// let response = srv.execute(request.send()).unwrap();
// assert_eq!(response.status(), StatusCode::NOT_FOUND);
let data = Bytes::from(fs::read("Cargo.toml").unwrap());
assert_eq!(bytes, data);
// let request = srv.get().uri(srv.url("/test/unknown/")).finish().unwrap();
// let response = srv.execute(request.send()).unwrap();
// assert_eq!(response.status(), StatusCode::NOT_FOUND);
// }
let req = TestRequest::get().uri("/test/").to_request();
let res = test::call_service(&srv, req).await;
assert_eq!(res.status(), StatusCode::OK);
// #[actix_rt::test]
// fn integration_percent_encoded() {
// let mut srv = test::TestServer::with_factory(|| {
// App::new().handler(
// "test",
// Files::new(".").index_file("Cargo.toml"),
// )
// });
let bytes = test::read_body(res).await;
let data = Bytes::from(fs::read("Cargo.toml").unwrap());
assert_eq!(bytes, data);
// let request = srv
// .get()
// .uri(srv.url("/test/%43argo.toml"))
// .finish()
// .unwrap();
// let response = srv.execute(request.send()).unwrap();
// assert_eq!(response.status(), StatusCode::OK);
// }
// nonexistent index file
let req = TestRequest::get().uri("/test/unknown").to_request();
let res = test::call_service(&srv, req).await;
assert_eq!(res.status(), StatusCode::NOT_FOUND);
let req = TestRequest::get().uri("/test/unknown/").to_request();
let res = test::call_service(&srv, req).await;
assert_eq!(res.status(), StatusCode::NOT_FOUND);
}
#[actix_rt::test]
async fn integration_percent_encoded() {
let srv = test::init_service(
App::new().service(Files::new("test", ".").index_file("Cargo.toml")),
)
.await;
let req = TestRequest::get().uri("/test/%43argo.toml").to_request();
let res = test::call_service(&srv, req).await;
assert_eq!(res.status(), StatusCode::OK);
}
}

View File

@ -1,9 +1,4 @@
use std::{
fmt, io,
path::PathBuf,
rc::Rc,
task::{Context, Poll},
};
use std::{fmt, io, path::PathBuf, rc::Rc, task::Poll};
use actix_service::Service;
use actix_web::{
@ -40,10 +35,10 @@ type FilesServiceFuture = Either<
>;
impl FilesService {
fn handle_err(&mut self, e: io::Error, req: ServiceRequest) -> FilesServiceFuture {
fn handle_err(&self, e: io::Error, req: ServiceRequest) -> FilesServiceFuture {
log::debug!("Failed to handle {}: {}", req.path(), e);
if let Some(ref mut default) = self.default {
if let Some(ref default) = self.default {
Either::Right(default.call(req))
} else {
Either::Left(ok(req.error_response(e)))
@ -62,11 +57,9 @@ impl Service<ServiceRequest> for FilesService {
type Error = Error;
type Future = FilesServiceFuture;
fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
actix_service::always_ready!();
fn call(&mut self, req: ServiceRequest) -> Self::Future {
fn call(&self, req: ServiceRequest) -> Self::Future {
let is_method_valid = if let Some(guard) = &self.guards {
// execute user defined guards
(**guard).check(req.head())

View File

@ -11,11 +11,10 @@ use actix_web::{
#[actix_rt::test]
async fn test_utf8_file_contents() {
// use default ISO-8859-1 encoding
let mut srv =
test::init_service(App::new().service(Files::new("/", "./tests"))).await;
let srv = test::init_service(App::new().service(Files::new("/", "./tests"))).await;
let req = TestRequest::with_uri("/utf8.txt").to_request();
let res = test::call_service(&mut srv, req).await;
let res = test::call_service(&srv, req).await;
assert_eq!(res.status(), StatusCode::OK);
assert_eq!(
@ -24,13 +23,13 @@ async fn test_utf8_file_contents() {
);
// prefer UTF-8 encoding
let mut srv = test::init_service(
let srv = test::init_service(
App::new().service(Files::new("/", "./tests").prefer_utf8(true)),
)
.await;
let req = TestRequest::with_uri("/utf8.txt").to_request();
let res = test::call_service(&mut srv, req).await;
let res = test::call_service(&srv, req).await;
assert_eq!(res.status(), StatusCode::OK);
assert_eq!(

View File

@ -33,7 +33,7 @@ actix-service = "2.0.0-beta.3"
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.2"
actix-rt = "2"
actix-server = "2.0.0-beta.2"
awc = "3.0.0-beta.1"

View File

@ -60,7 +60,7 @@ pub async fn test_server_with_addr<F: ServiceFactory<TcpStream>>(
// run server in separate thread
thread::spawn(move || {
let sys = System::new("actix-test-server");
let sys = System::new();
let local_addr = tcp.local_addr().unwrap();
let srv = Server::build()
@ -69,7 +69,7 @@ pub async fn test_server_with_addr<F: ServiceFactory<TcpStream>>(
.disable_signals();
sys.block_on(async {
srv.start();
srv.run();
tx.send((System::current(), local_addr)).unwrap();
});

View File

@ -16,6 +16,8 @@
* `Extensions::insert` returns Option of replaced item. [#1904]
* Remove `HttpResponseBuilder::json2()` and make `HttpResponseBuilder::json()` take a value by
reference. [#1903]
* `client::error::ConnectError` Resolver variant contains `Box<dyn std::error::Error>` type [#1905]
* `client::ConnectorConfig` default timeout changed to 5 seconds. [#1905]
### Removed
* `ResponseBuilder::set`; use `ResponseBuilder::insert_header`. [#1869]
@ -28,6 +30,7 @@
[#1894]: https://github.com/actix/actix-web/pull/1894
[#1903]: https://github.com/actix/actix-web/pull/1903
[#1904]: https://github.com/actix/actix-web/pull/1904
[#1905]: https://github.com/actix/actix-web/pull/1905
[#1912]: https://github.com/actix/actix-web/pull/1912

View File

@ -43,7 +43,7 @@ actors = ["actix"]
actix-service = "2.0.0-beta.3"
actix-codec = "0.4.0-beta.1"
actix-utils = "3.0.0-beta.1"
actix-rt = "2.0.0-beta.2"
actix-rt = "2.0.0"
actix-tls = { version = "3.0.0-beta.2", default-features = false, features = ["accept", "uri"] }
actix = { version = "0.11.0-beta.1", optional = true }
@ -70,6 +70,7 @@ log = "0.4"
mime = "0.3"
percent-encoding = "2.1"
pin-project = "1.0.0"
pin-project-lite = "0.2"
rand = "0.8"
regex = "1.3"
serde = "1.0"

View File

@ -14,7 +14,7 @@ use crate::header::HeaderMap;
use crate::message::{ConnectionType, ResponseHead};
use crate::request::Request;
const MAX_BUFFER_SIZE: usize = 131_072;
pub(crate) const MAX_BUFFER_SIZE: usize = 131_072;
const MAX_HEADERS: usize = 96;
/// Incoming message decoder

View File

@ -1,5 +1,4 @@
use std::{
cell::RefCell,
collections::VecDeque,
fmt,
future::Future,
@ -46,7 +45,7 @@ bitflags! {
}
}
#[pin_project::pin_project]
#[pin_project]
/// Dispatcher for HTTP/1.1 protocol
pub struct Dispatcher<T, S, B, X, U>
where
@ -91,7 +90,7 @@ where
U: Service<(Request, Framed<T, Codec>), Response = ()>,
U::Error: fmt::Display,
{
flow: Rc<RefCell<HttpFlow<S, X, U>>>,
flow: Rc<HttpFlow<S, X, U>>,
on_connect_data: OnConnectData,
flags: Flags,
peer_addr: Option<net::SocketAddr>,
@ -140,27 +139,14 @@ where
fn is_empty(&self) -> bool {
matches!(self, State::None)
}
fn is_call(&self) -> bool {
matches!(self, State::ServiceCall(_))
}
}
enum PollResponse {
Upgrade(Request),
DoNothing,
DrainWriteBuf,
}
impl PartialEq for PollResponse {
fn eq(&self, other: &PollResponse) -> bool {
match self {
PollResponse::DrainWriteBuf => matches!(other, PollResponse::DrainWriteBuf),
PollResponse::DoNothing => matches!(other, PollResponse::DoNothing),
_ => false,
}
}
}
impl<T, S, B, X, U> Dispatcher<T, S, B, X, U>
where
T: AsyncRead + AsyncWrite + Unpin,
@ -177,7 +163,7 @@ where
pub(crate) fn new(
stream: T,
config: ServiceConfig,
services: Rc<RefCell<HttpFlow<S, X, U>>>,
flow: Rc<HttpFlow<S, X, U>>,
on_connect_data: OnConnectData,
peer_addr: Option<net::SocketAddr>,
) -> Self {
@ -187,7 +173,7 @@ where
config,
BytesMut::with_capacity(HW_BUFFER_SIZE),
None,
services,
flow,
on_connect_data,
peer_addr,
)
@ -200,7 +186,7 @@ where
config: ServiceConfig,
read_buf: BytesMut,
timeout: Option<Sleep>,
services: Rc<RefCell<HttpFlow<S, X, U>>>,
flow: Rc<HttpFlow<S, X, U>>,
on_connect_data: OnConnectData,
peer_addr: Option<net::SocketAddr>,
) -> Self {
@ -230,7 +216,7 @@ where
io: Some(io),
codec,
read_buf,
flow: services,
flow,
on_connect_data,
flags,
peer_addr,
@ -325,9 +311,10 @@ where
message: Response<()>,
body: ResponseBody<B>,
) -> Result<(), DispatchError> {
let size = body.size();
let mut this = self.project();
this.codec
.encode(Message::Item((message, body.size())), &mut this.write_buf)
.encode(Message::Item((message, size)), &mut this.write_buf)
.map_err(|err| {
if let Some(mut payload) = this.payload.take() {
payload.set_error(PayloadError::Incomplete(None));
@ -336,74 +323,94 @@ where
})?;
this.flags.set(Flags::KEEPALIVE, this.codec.keepalive());
match body.size() {
match size {
BodySize::None | BodySize::Empty => this.state.set(State::None),
_ => this.state.set(State::SendPayload(body)),
};
Ok(())
}
fn send_continue(self: Pin<&mut Self>) {
self.project()
.write_buf
.extend_from_slice(b"HTTP/1.1 100 Continue\r\n\r\n");
}
fn poll_response(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Result<PollResponse, DispatchError> {
loop {
let mut this = self.as_mut().project();
// state is not changed on Poll::Pending.
// other variant and conditions always trigger a state change(or an error).
let state_change = match this.state.project() {
match this.state.as_mut().project() {
// no future is in InnerDispatcher state. pop next message.
StateProj::None => match this.messages.pop_front() {
// handle request message.
Some(DispatcherMessage::Item(req)) => {
self.as_mut().handle_request(req, cx)?;
true
// Handle `EXPECT: 100-Continue` header
if req.head().expect() {
// set InnerDispatcher state and continue loop to poll it.
let task = this.flow.expect.call(req);
this.state.set(State::ExpectCall(task));
} else {
// the same as expect call.
let task = this.flow.service.call(req);
this.state.set(State::ServiceCall(task));
};
}
// handle error message.
Some(DispatcherMessage::Error(res)) => {
// send_response would update InnerDispatcher state to SendPayload or
// None(If response body is empty).
// continue loop to poll it.
self.as_mut()
.send_response(res, ResponseBody::Other(Body::Empty))?;
true
}
// return with upgrade request and poll it exclusively.
Some(DispatcherMessage::Upgrade(req)) => {
return Ok(PollResponse::Upgrade(req));
}
None => false,
// all messages are dealt with.
None => return Ok(PollResponse::DoNothing),
},
StateProj::ExpectCall(fut) => match fut.poll(cx) {
// expect resolved. write continue to buffer and set InnerDispatcher state
// to service call.
Poll::Ready(Ok(req)) => {
self.as_mut().send_continue();
this = self.as_mut().project();
let fut = this.flow.borrow_mut().service.call(req);
this.write_buf
.extend_from_slice(b"HTTP/1.1 100 Continue\r\n\r\n");
let fut = this.flow.service.call(req);
this.state.set(State::ServiceCall(fut));
continue;
}
// send expect error as response
Poll::Ready(Err(e)) => {
let res: Response = e.into().into();
let (res, body) = res.replace_body(());
self.as_mut().send_response(res, body.into_body())?;
true
}
Poll::Pending => false,
// expect must be solved before progress can be made.
Poll::Pending => return Ok(PollResponse::DoNothing),
},
StateProj::ServiceCall(fut) => match fut.poll(cx) {
// service call resolved. send response.
Poll::Ready(Ok(res)) => {
let (res, body) = res.into().replace_body(());
self.as_mut().send_response(res, body)?;
continue;
}
// send service call error as response
Poll::Ready(Err(e)) => {
let res: Response = e.into().into();
let (res, body) = res.replace_body(());
self.as_mut().send_response(res, body.into_body())?;
true
}
Poll::Pending => false,
// service call pending and could be waiting for more chunk messages.
// (pipeline message limit and/or payload can_read limit)
Poll::Pending => {
// no new message is decoded and no new payload is feed.
// nothing to do except waiting for new incoming data from client.
if !self.as_mut().poll_request(cx)? {
return Ok(PollResponse::DoNothing);
}
// otherwise keep loop.
}
},
StateProj::SendPayload(mut stream) => {
// keep populate writer buffer until buffer size limit hit,
// get blocked or finished.
loop {
if this.write_buf.len() < HW_BUFFER_SIZE {
match stream.as_mut().poll_next(cx) {
@ -412,50 +419,42 @@ where
Message::Chunk(Some(item)),
&mut this.write_buf,
)?;
continue;
}
Poll::Ready(None) => {
this.codec.encode(
Message::Chunk(None),
&mut this.write_buf,
)?;
this = self.as_mut().project();
this.state.set(State::None);
// payload stream finished.
// break and goes out of scope of borrowed stream.
break;
}
Poll::Ready(Some(Err(_))) => {
return Err(DispatchError::Unknown)
Poll::Ready(Some(Err(e))) => {
return Err(DispatchError::Service(e))
}
// Payload Stream Pending should only be given when the caller
// promise to wake it up properly.
//
// TODO: Think if it's an good idea to mix in a self wake up.
// It would turn dispatcher into a busy polling style of stream
// handling. (Or another timer as source of scheduled wake up)
// As There is no way to know when or how the caller would wake
// up the stream so a self wake up is an overhead that would
// result in a double polling(or an extra timer)
Poll::Pending => return Ok(PollResponse::DoNothing),
}
} else {
// buffer is beyond max size.
// return and write the whole buffer to io stream.
return Ok(PollResponse::DrainWriteBuf);
}
break;
}
continue;
}
};
// state is changed and continue when the state is not Empty
if state_change {
if !self.state.is_empty() {
continue;
}
} else {
// if read-backpressure is enabled and we consumed some data.
// we may read more data and retry
if self.state.is_call() {
if self.as_mut().poll_request(cx)? {
continue;
}
} else if !self.messages.is_empty() {
continue;
// break from Poll::Ready(None) on stream finished.
// this is for re borrow InnerDispatcher state and set it to None.
this.state.set(State::None);
}
}
break;
}
Ok(PollResponse::DoNothing)
}
fn handle_request(
@ -463,41 +462,39 @@ where
req: Request,
cx: &mut Context<'_>,
) -> Result<(), DispatchError> {
let mut this = self.as_mut().project();
// Handle `EXPECT: 100-Continue` header
if req.head().expect() {
// set dispatcher state so the future is pinned.
let mut this = self.as_mut().project();
let task = this.flow.borrow_mut().expect.call(req);
// set InnerDispatcher state so the future is pinned.
let task = this.flow.expect.call(req);
this.state.set(State::ExpectCall(task));
} else {
// the same as above.
let mut this = self.as_mut().project();
let task = this.flow.borrow_mut().service.call(req);
let task = this.flow.service.call(req);
this.state.set(State::ServiceCall(task));
};
// eagerly poll the future for once(or twice if expect is resolved immediately).
loop {
match self.as_mut().project().state.project() {
match this.state.as_mut().project() {
StateProj::ExpectCall(fut) => {
match fut.poll(cx) {
// expect is resolved. continue loop and poll the service call branch.
Poll::Ready(Ok(req)) => {
self.as_mut().send_continue();
let mut this = self.as_mut().project();
let task = this.flow.borrow_mut().service.call(req);
this.state.set(State::ServiceCall(task));
continue;
this.write_buf
.extend_from_slice(b"HTTP/1.1 100 Continue\r\n\r\n");
let task = this.flow.service.call(req);
this.state.as_mut().set(State::ServiceCall(task));
}
// future is pending. return Ok(()) to notify that a new state is
// set and the outer loop should be continue.
// future is pending. return Ok(()) to notify that a new InnerDispatcher
// state is set and the outer loop should be continue.
Poll::Pending => return Ok(()),
// future is error. send response and return a result. On success
// to notify the dispatcher a new state is set and the outer loop
// should be continue.
// to notify the dispatcher a new InnerDispatcher state is set and
// the outer loop should be continue.
Poll::Ready(Err(e)) => {
let e = e.into();
let res: Response = e.into();
let res: Response = e.into().into();
let (res, body) = res.replace_body(());
return self.send_response(res, body.into_body());
}
@ -507,8 +504,8 @@ where
// return no matter the service call future's result.
return match fut.poll(cx) {
// future is resolved. send response and return a result. On success
// to notify the dispatcher a new state is set and the outer loop
// should be continue.
// to notify the dispatcher a new InnerDispatcher state is set and the
// outer loop should be continue.
Poll::Ready(Ok(res)) => {
let (res, body) = res.into().replace_body(());
self.send_response(res, body)
@ -550,27 +547,28 @@ where
match msg {
Message::Item(mut req) => {
let pl = this.codec.message_type();
req.head_mut().peer_addr = *this.peer_addr;
// merge on_connect_ext data into request extensions
this.on_connect_data.merge_into(&mut req);
if pl == MessageType::Stream
&& this.flow.borrow().upgrade.is_some()
{
this.messages.push_back(DispatcherMessage::Upgrade(req));
break;
}
if pl == MessageType::Payload || pl == MessageType::Stream {
let (ps, pl) = Payload::create(false);
let (req1, _) =
req.replace_payload(crate::Payload::H1(pl));
req = req1;
*this.payload = Some(ps);
match this.codec.message_type() {
MessageType::Stream if this.flow.upgrade.is_some() => {
this.messages
.push_back(DispatcherMessage::Upgrade(req));
break;
}
MessageType::Payload | MessageType::Stream => {
let (ps, pl) = Payload::create(false);
let (req1, _) =
req.replace_payload(crate::Payload::H1(pl));
req = req1;
*this.payload = Some(ps);
}
MessageType::None => {}
}
// handle request early
// handle request early if no future lives in InnerDispatcher state.
if this.state.is_empty() {
self.as_mut().handle_request(req, cx)?;
this = self.as_mut().project();
@ -636,6 +634,7 @@ where
*this.ka_expire = expire;
}
}
Ok(updated)
}
@ -723,6 +722,75 @@ where
}
Ok(())
}
/// Returns true when io stream can be disconnected after write to it.
///
/// It covers these conditions:
///
/// - `Flags::READ_DISCONNECT` flag active.
/// - `std::io::ErrorKind::ConnectionReset` after partial read.
/// - all data read done.
#[inline(always)]
fn read_available(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Result<bool, DispatchError> {
let this = self.project();
if this.flags.contains(Flags::READ_DISCONNECT) {
return Ok(true);
};
let buf = this.read_buf;
let mut io = Pin::new(this.io.as_mut().unwrap());
let mut read_some = false;
loop {
// grow buffer if necessary.
let remaining = buf.capacity() - buf.len();
if remaining < LW_BUFFER_SIZE {
buf.reserve(HW_BUFFER_SIZE - remaining);
}
match actix_codec::poll_read_buf(io.as_mut(), cx, buf) {
Poll::Pending => return Ok(false),
Poll::Ready(Ok(n)) => {
if n == 0 {
return Ok(true);
} else {
// Return early when read buf exceed decoder's max buffer size.
if buf.len() >= super::decoder::MAX_BUFFER_SIZE {
return Ok(false);
}
read_some = true;
}
}
Poll::Ready(Err(err)) => {
return if err.kind() == io::ErrorKind::WouldBlock {
Ok(false)
} else if err.kind() == io::ErrorKind::ConnectionReset && read_some {
Ok(true)
} else {
Err(DispatchError::Io(err))
}
}
}
}
}
/// call upgrade service with request.
fn upgrade(self: Pin<&mut Self>, req: Request) -> U::Future {
let this = self.project();
let mut parts = FramedParts::with_read_buf(
this.io.take().unwrap(),
mem::take(this.codec),
mem::take(this.read_buf),
);
parts.write_buf = mem::take(this.write_buf);
let framed = Framed::from_parts(parts);
this.flow.upgrade.as_ref().unwrap().call((req, framed))
}
}
impl<T, S, B, X, U> Future for Dispatcher<T, S, B, X, U>
@ -756,9 +824,10 @@ where
if inner.flags.contains(Flags::WRITE_DISCONNECT) {
Poll::Ready(Ok(()))
} else {
// flush buffer
// flush buffer.
inner.as_mut().poll_flush(cx)?;
if !inner.write_buf.is_empty() {
// still have unfinished data. wait.
Poll::Pending
} else {
Pin::new(inner.project().io.as_mut().unwrap())
@ -767,21 +836,14 @@ where
}
}
} else {
// read socket into a buf
let should_disconnect =
if !inner.flags.contains(Flags::READ_DISCONNECT) {
let mut inner_p = inner.as_mut().project();
read_available(
cx,
inner_p.io.as_mut().unwrap(),
&mut inner_p.read_buf,
)?
} else {
None
};
// read from io stream and fill read buffer.
let should_disconnect = inner.as_mut().read_available(cx)?;
// parse read buffer into http requests and payloads.
inner.as_mut().poll_request(cx)?;
if let Some(true) = should_disconnect {
// io stream should to be closed.
if should_disconnect {
let inner_p = inner.as_mut().project();
inner_p.flags.insert(Flags::READ_DISCONNECT);
if let Some(mut payload) = inner_p.payload.take() {
@ -790,38 +852,29 @@ where
};
loop {
// grow buffer if necessary.
let inner_p = inner.as_mut().project();
let remaining =
inner_p.write_buf.capacity() - inner_p.write_buf.len();
if remaining < LW_BUFFER_SIZE {
inner_p.write_buf.reserve(HW_BUFFER_SIZE - remaining);
}
let result = inner.as_mut().poll_response(cx)?;
let drain = result == PollResponse::DrainWriteBuf;
// switch to upgrade handler
if let PollResponse::Upgrade(req) = result {
let inner_p = inner.as_mut().project();
let mut parts = FramedParts::with_read_buf(
inner_p.io.take().unwrap(),
mem::take(inner_p.codec),
mem::take(inner_p.read_buf),
);
parts.write_buf = mem::take(inner_p.write_buf);
let framed = Framed::from_parts(parts);
let upgrade = inner_p
.flow
.borrow_mut()
.upgrade
.take()
.unwrap()
.call((req, framed));
self.as_mut()
.project()
.inner
.set(DispatcherState::Upgrade(upgrade));
return self.poll(cx);
}
// poll_response and populate write buffer.
// drain indicate if write buffer should be emptied before next run.
let drain = match inner.as_mut().poll_response(cx)? {
PollResponse::DrainWriteBuf => true,
PollResponse::DoNothing => false,
// upgrade request and goes Upgrade variant of DispatcherState.
PollResponse::Upgrade(req) => {
let upgrade = inner.upgrade(req);
self.as_mut()
.project()
.inner
.set(DispatcherState::Upgrade(upgrade));
return self.poll(cx);
}
};
// we didn't get WouldBlock from write operation,
// so data get written to kernel completely (macOS)
@ -839,6 +892,7 @@ where
return Poll::Ready(Ok(()));
}
// check if still have unsolved future in InnerDispatcher state.
let is_empty = inner.state.is_empty();
let inner_p = inner.as_mut().project();
@ -878,61 +932,6 @@ where
}
}
/// Returns either:
/// - `Ok(Some(true))` - data was read and done reading all data.
/// - `Ok(Some(false))` - data was read but there should be more to read.
/// - `Ok(None)` - no data was read but there should be more to read later.
/// - Unhandled Errors
fn read_available<T>(
cx: &mut Context<'_>,
io: &mut T,
buf: &mut BytesMut,
) -> Result<Option<bool>, io::Error>
where
T: AsyncRead + Unpin,
{
let mut read_some = false;
loop {
// If buf is full return but do not disconnect since
// there is more reading to be done
if buf.len() >= HW_BUFFER_SIZE {
return Ok(Some(false));
}
let remaining = buf.capacity() - buf.len();
if remaining < LW_BUFFER_SIZE {
buf.reserve(HW_BUFFER_SIZE - remaining);
}
match actix_codec::poll_read_buf(Pin::new(io), cx, buf) {
Poll::Pending => {
return if read_some { Ok(Some(false)) } else { Ok(None) };
}
Poll::Ready(Ok(n)) => {
if n == 0 {
return Ok(Some(true));
} else {
read_some = true;
}
}
Poll::Ready(Err(err)) => {
return if err.kind() == io::ErrorKind::WouldBlock {
if read_some {
Ok(Some(false))
} else {
Ok(None)
}
} else if err.kind() == io::ErrorKind::ConnectionReset && read_some {
Ok(Some(true))
} else {
Err(err)
}
}
}
}
}
#[cfg(test)]
mod tests {
use std::str;

View File

@ -1,4 +1,4 @@
use std::task::{Context, Poll};
use std::task::Poll;
use actix_service::{Service, ServiceFactory};
use futures_util::future::{ready, Ready};
@ -26,11 +26,9 @@ impl Service<Request> for ExpectHandler {
type Error = Error;
type Future = Ready<Result<Self::Response, Self::Error>>;
fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
actix_service::always_ready!();
fn call(&mut self, req: Request) -> Self::Future {
fn call(&self, req: Request) -> Self::Future {
ready(Ok(req))
// TODO: add some way to trigger error
// Err(error::ErrorExpectationFailed("test"))

View File

@ -1,4 +1,3 @@
use std::cell::RefCell;
use std::future::Future;
use std::marker::PhantomData;
use std::pin::Pin;
@ -367,7 +366,7 @@ where
X: Service<Request>,
U: Service<(Request, Framed<T, Codec>)>,
{
flow: Rc<RefCell<HttpFlow<S, X, U>>>,
flow: Rc<HttpFlow<S, X, U>>,
on_connect_ext: Option<Rc<ConnectCallback<T>>>,
cfg: ServiceConfig,
_phantom: PhantomData<B>,
@ -417,9 +416,9 @@ where
type Error = DispatchError;
type Future = Dispatcher<T, S, B, X, U>;
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
let mut flow = self.flow.borrow_mut();
let ready = flow
fn poll_ready(&self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
let ready = self
.flow
.expect
.poll_ready(cx)
.map_err(|e| {
@ -429,7 +428,8 @@ where
})?
.is_ready();
let ready = flow
let ready = self
.flow
.service
.poll_ready(cx)
.map_err(|e| {
@ -440,7 +440,7 @@ where
.is_ready()
&& ready;
let ready = if let Some(ref mut upg) = flow.upgrade {
let ready = if let Some(ref upg) = self.flow.upgrade {
upg.poll_ready(cx)
.map_err(|e| {
let e = e.into();
@ -460,7 +460,7 @@ where
}
}
fn call(&mut self, (io, addr): (T, Option<net::SocketAddr>)) -> Self::Future {
fn call(&self, (io, addr): (T, Option<net::SocketAddr>)) -> Self::Future {
let on_connect_data =
OnConnectData::from_io(&io, self.on_connect_ext.as_deref());

View File

@ -1,4 +1,4 @@
use std::task::{Context, Poll};
use std::task::Poll;
use actix_codec::Framed;
use actix_service::{Service, ServiceFactory};
@ -28,11 +28,9 @@ impl<T> Service<(Request, Framed<T, Codec>)> for UpgradeHandler {
type Error = Error;
type Future = Ready<Result<Self::Response, Self::Error>>;
fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
actix_service::always_ready!();
fn call(&mut self, _: (Request, Framed<T, Codec>)) -> Self::Future {
fn call(&self, _: (Request, Framed<T, Codec>)) -> Self::Future {
ready(Ok(()))
}
}

View File

@ -1,4 +1,3 @@
use std::cell::RefCell;
use std::future::Future;
use std::marker::PhantomData;
use std::net;
@ -37,7 +36,7 @@ where
S: Service<Request>,
B: MessageBody,
{
flow: Rc<RefCell<HttpFlow<S, X, U>>>,
flow: Rc<HttpFlow<S, X, U>>,
connection: Connection<T, Bytes>,
on_connect_data: OnConnectData,
config: ServiceConfig,
@ -56,7 +55,7 @@ where
B: MessageBody,
{
pub(crate) fn new(
services: Rc<RefCell<HttpFlow<S, X, U>>>,
flow: Rc<HttpFlow<S, X, U>>,
connection: Connection<T, Bytes>,
on_connect_data: OnConnectData,
config: ServiceConfig,
@ -80,7 +79,7 @@ where
};
Dispatcher {
flow: services,
flow,
config,
peer_addr,
connection,
@ -138,7 +137,7 @@ where
let svc = ServiceResponse::<S::Future, S::Response, S::Error, B> {
state: ServiceResponseState::ServiceCall(
this.flow.borrow_mut().service.call(req),
this.flow.service.call(req),
Some(res),
),
config: this.config.clone(),

View File

@ -1,4 +1,3 @@
use std::cell::RefCell;
use std::future::Future;
use std::marker::PhantomData;
use std::pin::Pin;
@ -249,7 +248,7 @@ pub struct H2ServiceHandler<T, S, B>
where
S: Service<Request>,
{
flow: Rc<RefCell<HttpFlow<S, (), ()>>>,
flow: Rc<HttpFlow<S, (), ()>>,
cfg: ServiceConfig,
on_connect_ext: Option<Rc<ConnectCallback<T>>>,
_phantom: PhantomData<B>,
@ -290,15 +289,15 @@ where
type Error = DispatchError;
type Future = H2ServiceHandlerResponse<T, S, B>;
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
self.flow.borrow_mut().service.poll_ready(cx).map_err(|e| {
fn poll_ready(&self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
self.flow.service.poll_ready(cx).map_err(|e| {
let e = e.into();
error!("Service readiness error: {:?}", e);
DispatchError::Service(e)
})
}
fn call(&mut self, (io, addr): (T, Option<net::SocketAddr>)) -> Self::Future {
fn call(&self, (io, addr): (T, Option<net::SocketAddr>)) -> Self::Future {
let on_connect_data =
OnConnectData::from_io(&io, self.on_connect_ext.as_deref());
@ -321,7 +320,7 @@ where
{
Incoming(Dispatcher<T, S, B, (), ()>),
Handshake(
Option<Rc<RefCell<HttpFlow<S, (), ()>>>>,
Option<Rc<HttpFlow<S, (), ()>>>,
Option<ServiceConfig>,
Option<net::SocketAddr>,
OnConnectData,

View File

@ -126,6 +126,6 @@ impl IntoHeaderValue for Mime {
#[inline]
fn try_into_value(self) -> Result<HeaderValue, Self::Error> {
HeaderValue::try_from(format!("{}", self))
HeaderValue::from_str(self.as_ref())
}
}

View File

@ -1,4 +1,3 @@
use std::cell::RefCell;
use std::marker::PhantomData;
use std::pin::Pin;
use std::task::{Context, Poll};
@ -440,7 +439,7 @@ where
X: Service<Request>,
U: Service<(Request, Framed<T, h1::Codec>)>,
{
flow: Rc<RefCell<HttpFlow<S, X, U>>>,
flow: Rc<HttpFlow<S, X, U>>,
cfg: ServiceConfig,
on_connect_ext: Option<Rc<ConnectCallback<T>>>,
_phantom: PhantomData<B>,
@ -454,12 +453,12 @@ pub(super) struct HttpFlow<S, X, U> {
}
impl<S, X, U> HttpFlow<S, X, U> {
pub(super) fn new(service: S, expect: X, upgrade: Option<U>) -> Rc<RefCell<Self>> {
Rc::new(RefCell::new(Self {
pub(super) fn new(service: S, expect: X, upgrade: Option<U>) -> Rc<Self> {
Rc::new(Self {
service,
expect,
upgrade,
}))
})
}
}
@ -509,9 +508,9 @@ where
type Error = DispatchError;
type Future = HttpServiceHandlerResponse<T, S, B, X, U>;
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
let mut flow = self.flow.borrow_mut();
let ready = flow
fn poll_ready(&self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
let ready = self
.flow
.expect
.poll_ready(cx)
.map_err(|e| {
@ -521,7 +520,8 @@ where
})?
.is_ready();
let ready = flow
let ready = self
.flow
.service
.poll_ready(cx)
.map_err(|e| {
@ -532,7 +532,7 @@ where
.is_ready()
&& ready;
let ready = if let Some(ref mut upg) = flow.upgrade {
let ready = if let Some(ref upg) = self.flow.upgrade {
upg.poll_ready(cx)
.map_err(|e| {
let e = e.into();
@ -553,7 +553,7 @@ where
}
fn call(
&mut self,
&self,
(io, proto, peer_addr): (T, Protocol, Option<net::SocketAddr>),
) -> Self::Future {
let on_connect_data =
@ -604,7 +604,7 @@ where
Option<(
Handshake<T, Bytes>,
ServiceConfig,
Rc<RefCell<HttpFlow<S, X, U>>>,
Rc<HttpFlow<S, X, U>>,
OnConnectData,
Option<net::SocketAddr>,
)>,

View File

@ -21,7 +21,7 @@ impl<T> WsService<T> {
WsService(Arc::new(Mutex::new((PhantomData, Cell::new(false)))))
}
fn set_polled(&mut self) {
fn set_polled(&self) {
*self.0.lock().unwrap().1.get_mut() = true;
}
@ -44,15 +44,12 @@ where
type Error = Error;
type Future = Pin<Box<dyn Future<Output = Result<(), Error>>>>;
fn poll_ready(&mut self, _ctx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
fn poll_ready(&self, _ctx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
self.set_polled();
Poll::Ready(Ok(()))
}
fn call(
&mut self,
(req, mut framed): (Request, Framed<T, h1::Codec>),
) -> Self::Future {
fn call(&self, (req, mut framed): (Request, Framed<T, h1::Codec>)) -> Self::Future {
let fut = async move {
let res = ws::handshake(req.head()).unwrap().message_body(());

View File

@ -28,5 +28,5 @@ mime = "0.3"
twoway = "0.2"
[dev-dependencies]
actix-rt = "2.0.0-beta.2"
actix-rt = "2"
actix-http = "3.0.0-beta.1"

View File

@ -28,6 +28,6 @@ pin-project = "1.0.0"
tokio = { version = "1", features = ["sync"] }
[dev-dependencies]
actix-rt = "2.0.0-beta.2"
actix-rt = "2"
env_logger = "0.7"
futures-util = { version = "0.3.7", default-features = false }

View File

@ -233,14 +233,13 @@ mod tests {
#[actix_rt::test]
async fn test_default_resource() {
let mut srv =
init_service(App::new().service(web::resource("/test").to(|| {
HttpResponse::Ok().streaming(HttpContext::create(MyActor { count: 0 }))
})))
.await;
let srv = init_service(App::new().service(web::resource("/test").to(|| {
HttpResponse::Ok().streaming(HttpContext::create(MyActor { count: 0 }))
})))
.await;
let req = TestRequest::with_uri("/test").to_request();
let resp = call_service(&mut srv, req).await;
let resp = call_service(&srv, req).await;
assert_eq!(resp.status(), StatusCode::OK);
let body = read_body(resp).await;

View File

@ -19,7 +19,7 @@ syn = { version = "1", features = ["full", "parsing"] }
proc-macro2 = "1"
[dev-dependencies]
actix-rt = "2.0.0-beta.2"
actix-rt = "2"
actix-web = "4.0.0-beta.1"
futures-util = { version = "0.3.7", default-features = false }
trybuild = "1"

View File

@ -175,7 +175,6 @@ pub fn main(_: TokenStream, item: TokenStream) -> TokenStream {
let vis = &input.vis;
let sig = &mut input.sig;
let body = &input.block;
let name = &sig.ident;
if sig.asyncness.is_none() {
return syn::Error::new_spanned(sig.fn_token, "only async fn is supported")
@ -188,7 +187,7 @@ pub fn main(_: TokenStream, item: TokenStream) -> TokenStream {
(quote! {
#(#attrs)*
#vis #sig {
actix_web::rt::System::new(stringify!(#name))
actix_web::rt::System::new()
.block_on(async move { #body })
}
})

View File

@ -1,5 +1,4 @@
use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};
use actix_web::dev::{Service, ServiceRequest, ServiceResponse, Transform};
@ -8,7 +7,7 @@ use actix_web::{http, test, web::Path, App, Error, HttpResponse, Responder};
use actix_web_codegen::{
connect, delete, get, head, options, patch, post, put, route, trace,
};
use futures_util::future;
use futures_util::future::{self, LocalBoxFuture};
// Make sure that we can name function as 'config'
#[get("/config")]
@ -117,14 +116,13 @@ where
{
type Response = ServiceResponse<B>;
type Error = Error;
#[allow(clippy::type_complexity)]
type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>>>>;
type Future = LocalBoxFuture<'static, Result<Self::Response, Self::Error>>;
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
fn poll_ready(&self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
self.service.poll_ready(cx)
}
fn call(&mut self, req: ServiceRequest) -> Self::Future {
fn call(&self, req: ServiceRequest) -> Self::Future {
let fut = self.service.call(req);
Box::pin(async move {

View File

@ -8,6 +8,9 @@
* `connector::default_connector` function to get a default connector type
that uses current dns resolver feature.
### Changed
* Relax default timeout for `Connector` to 5 seconds(original 1 second). [#1905]
### Removed
* `trust-dns` removed from default dns resolver
* `ClientRequest::set`; use `ClientRequest::insert_header`. [#1869]
@ -16,6 +19,7 @@
* `ClientRequest::header`; use `ClientRequest::append_header`. [#1869]
[#1869]: https://github.com/actix/actix-web/pull/1869
[#1905]: https://github.com/actix/actix-web/pull/1905
## 3.0.0-beta.1 - 2021-01-07

View File

@ -43,7 +43,7 @@ trust-dns = ["trust-dns-resolver/tokio-runtime", "trust-dns-resolver/system-conf
actix-codec = "0.4.0-beta.1"
actix-service = "2.0.0-beta.3"
actix-http = "3.0.0-beta.1"
actix-rt = "2.0.0-beta.2"
actix-rt = "2"
actix-tls = { version = "3.0.0-beta.2", default-features = false, features = ["connect", "uri"] }
actix-utils = "3.0.0-beta.1"
@ -72,9 +72,6 @@ tokio = { version = "1", features = ["sync"] }
trust-dns-resolver = { version = "0.20.0", default-features = false, optional = true }
[dev-dependencies]
# 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 = "4.0.0-beta.1", features = ["openssl"] }
actix-http = { version = "3.0.0-beta.1", features = ["openssl"] }
actix-http-test = { version = "3.0.0-beta.1", features = ["openssl"] }

View File

@ -21,7 +21,7 @@ use actix_rt::System;
use awc::Client;
fn main() {
System::new("test").block_on(async {
System::new().block_on(async {
let client = Client::default();
let res = client

View File

@ -1,4 +1,3 @@
use std::cell::RefCell;
use std::convert::TryFrom;
use std::fmt;
use std::rc::Rc;
@ -24,7 +23,7 @@ pub struct ClientBuilder {
conn_window_size: Option<u32>,
headers: HeaderMap,
timeout: Option<Duration>,
connector: Option<RefCell<Box<dyn Connect>>>,
connector: Option<Box<dyn Connect>>,
}
impl Default for ClientBuilder {
@ -56,7 +55,7 @@ impl ClientBuilder {
<T::Response as Connection>::Future: 'static,
T::Future: 'static,
{
self.connector = Some(RefCell::new(Box::new(ConnectorWrapper(connector))));
self.connector = Some(Box::new(ConnectorWrapper(connector)));
self
}
@ -182,9 +181,7 @@ impl ClientBuilder {
if let Some(val) = self.stream_window_size {
connector = connector.initial_window_size(val)
};
RefCell::new(
Box::new(ConnectorWrapper(connector.finish())) as Box<dyn Connect>
)
Box::new(ConnectorWrapper(connector.finish())) as _
};
let config = ClientConfig {
headers: self.headers,

View File

@ -18,7 +18,7 @@ pub(crate) struct ConnectorConfig {
impl Default for ConnectorConfig {
fn default() -> Self {
Self {
timeout: Duration::from_secs(1),
timeout: Duration::from_secs(5),
conn_lifetime: Duration::from_secs(75),
conn_keep_alive: Duration::from_secs(15),
disconnect_timeout: Some(Duration::from_millis(3000)),

View File

@ -5,7 +5,8 @@ use std::{fmt, io, time};
use actix_codec::{AsyncRead, AsyncWrite, Framed, ReadBuf};
use bytes::Bytes;
use futures_util::future::{err, Either, FutureExt, LocalBoxFuture, Ready};
use futures_core::future::LocalBoxFuture;
use futures_util::future::{err, Either, FutureExt, Ready};
use h2::client::SendRequest;
use pin_project::pin_project;

View File

@ -94,9 +94,9 @@ impl Connector<(), ()> {
fn build_ssl(protocols: Vec<Vec<u8>>) -> SslConnector {
let mut config = ClientConfig::new();
config.set_protocols(&protocols);
config
.root_store
.add_server_trust_anchors(&actix_tls::accept::rustls::TLS_SERVER_ROOTS);
config.root_store.add_server_trust_anchors(
&actix_tls::connect::ssl::rustls::TLS_SERVER_ROOTS,
);
SslConnector::Rustls(std::sync::Arc::new(config))
}
@ -386,11 +386,11 @@ mod connect_impl {
Ready<Result<IoConnection<Io>, ConnectError>>,
>;
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
fn poll_ready(&self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
self.tcp_pool.poll_ready(cx)
}
fn call(&mut self, req: Connect) -> Self::Future {
fn call(&self, req: Connect) -> Self::Future {
match req.uri.scheme_str() {
Some("https") | Some("wss") => {
Either::Right(err(ConnectError::SslIsNotSupported))
@ -454,11 +454,11 @@ mod connect_impl {
InnerConnectorResponseB<T2, Io1, Io2>,
>;
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
fn poll_ready(&self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
self.tcp_pool.poll_ready(cx)
}
fn call(&mut self, req: Connect) -> Self::Future {
fn call(&self, req: Connect) -> Self::Future {
match req.uri.scheme_str() {
Some("https") | Some("wss") => Either::Right(InnerConnectorResponseB {
fut: self.ssl_pool.call(req),
@ -535,9 +535,9 @@ mod connector_impl {
// resolver implementation using trust-dns crate.
#[cfg(feature = "trust-dns")]
mod connector_impl {
use std::net::SocketAddr;
use std::{cell::RefCell, net::SocketAddr};
use actix_rt::{net::TcpStream, Arbiter};
use actix_rt::net::TcpStream;
use actix_service::Service;
use actix_tls::connect::{
Address, Connect, ConnectError, Connection, Resolve, Resolver,
@ -549,32 +549,42 @@ mod connector_impl {
TokioAsyncResolver,
};
#[derive(Clone)]
pub struct TrustDnsResolver {
resolver: TokioAsyncResolver,
}
impl TrustDnsResolver {
fn new() -> Self {
// dns struct is cached in Arbiter thread local map.
// so new client constructor can reuse the dns resolver on local thread.
if Arbiter::contains_item::<TokioAsyncResolver>() {
Arbiter::get_item(|item: &TokioAsyncResolver| TrustDnsResolver {
resolver: item.clone(),
})
} else {
let (cfg, opts) = match read_system_conf() {
Ok((cfg, opts)) => (cfg, opts),
Err(e) => {
log::error!("TRust-DNS can not load system config: {}", e);
(ResolverConfig::default(), ResolverOpts::default())
}
};
let resolver = TokioAsyncResolver::tokio(cfg, opts).unwrap();
Arbiter::set_item(resolver.clone());
TrustDnsResolver { resolver }
// dns struct is cached in thread local.
// so new client constructor can reuse the existing dns resolver.
thread_local! {
static TRUST_DNS_RESOLVER: RefCell<Option<TrustDnsResolver>> = RefCell::new(None)
}
TRUST_DNS_RESOLVER.with(|local| {
let resolver = local.borrow().as_ref().map(Clone::clone);
match resolver {
Some(resolver) => resolver,
None => {
let (cfg, opts) = match read_system_conf() {
Ok((cfg, opts)) => (cfg, opts),
Err(e) => {
log::error!(
"TRust-DNS can not load system config: {}",
e
);
(ResolverConfig::default(), ResolverOpts::default())
}
};
let resolver = TokioAsyncResolver::tokio(cfg, opts).unwrap();
let resolver = TrustDnsResolver { resolver };
*local.borrow_mut() = Some(resolver.clone());
resolver
}
}
})
}
}

View File

@ -46,7 +46,7 @@ impl From<Authority> for Key {
}
/// Connections pool
pub(crate) struct ConnectionPool<T, Io: 'static>(Rc<RefCell<T>>, Rc<RefCell<Inner<Io>>>);
pub(crate) struct ConnectionPool<T, Io: 'static>(Rc<T>, Rc<RefCell<Inner<Io>>>);
impl<T, Io> ConnectionPool<T, Io>
where
@ -54,7 +54,7 @@ where
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));
let connector_rc = Rc::new(connector);
let inner_rc = Rc::new(RefCell::new(Inner {
config,
acquired: 0,
@ -99,12 +99,12 @@ where
type Error = ConnectError;
type Future = LocalBoxFuture<'static, Result<IoConnection<Io>, ConnectError>>;
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
fn poll_ready(&self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
self.0.poll_ready(cx)
}
fn call(&mut self, req: Connect) -> Self::Future {
let mut connector = self.0.clone();
fn call(&self, req: Connect) -> Self::Future {
let connector = self.0.clone();
let inner = self.1.clone();
let fut = async move {
@ -326,7 +326,7 @@ where
{
if let Some(timeout) = self.config.disconnect_timeout {
if let ConnectionType::H1(io) = conn.io {
actix_rt::spawn(CloseConnection::new(io, timeout))
actix_rt::spawn(CloseConnection::new(io, timeout));
}
}
} else {
@ -341,7 +341,7 @@ where
if let ConnectionType::H1(io) = io {
actix_rt::spawn(CloseConnection::new(
io, timeout,
))
));
}
}
continue;
@ -373,7 +373,7 @@ where
self.acquired -= 1;
if let Some(timeout) = self.config.disconnect_timeout {
if let ConnectionType::H1(io) = io {
actix_rt::spawn(CloseConnection::new(io, timeout))
actix_rt::spawn(CloseConnection::new(io, timeout));
}
}
self.check_availability();
@ -429,7 +429,7 @@ struct ConnectorPoolSupport<T, Io>
where
Io: AsyncRead + AsyncWrite + Unpin + 'static,
{
connector: T,
connector: Rc<T>,
inner: Rc<RefCell<Inner<Io>>>,
}
@ -536,7 +536,7 @@ where
rx: Some(rx),
inner: Some(inner),
config,
})
});
}
}

View File

@ -20,14 +20,14 @@ pub(crate) struct ConnectorWrapper<T>(pub T);
pub(crate) trait Connect {
fn send_request(
&mut self,
&self,
head: RequestHead,
body: Body,
addr: Option<net::SocketAddr>,
) -> Pin<Box<dyn Future<Output = Result<ClientResponse, SendRequestError>>>>;
fn send_request_extra(
&mut self,
&self,
head: Rc<RequestHead>,
extra_headers: Option<HeaderMap>,
body: Body,
@ -36,7 +36,7 @@ pub(crate) trait Connect {
/// Send request, returns Response and Framed
fn open_tunnel(
&mut self,
&self,
head: RequestHead,
addr: Option<net::SocketAddr>,
) -> Pin<
@ -52,7 +52,7 @@ pub(crate) trait Connect {
/// Send request and extra headers, returns Response and Framed
fn open_tunnel_extra(
&mut self,
&self,
head: Rc<RequestHead>,
extra_headers: Option<HeaderMap>,
addr: Option<net::SocketAddr>,
@ -78,7 +78,7 @@ where
T::Future: 'static,
{
fn send_request(
&mut self,
&self,
head: RequestHead,
body: Body,
addr: Option<net::SocketAddr>,
@ -101,7 +101,7 @@ where
}
fn send_request_extra(
&mut self,
&self,
head: Rc<RequestHead>,
extra_headers: Option<HeaderMap>,
body: Body,
@ -126,7 +126,7 @@ where
}
fn open_tunnel(
&mut self,
&self,
head: RequestHead,
addr: Option<net::SocketAddr>,
) -> Pin<
@ -158,7 +158,7 @@ where
}
fn open_tunnel_extra(
&mut self,
&self,
head: Rc<RequestHead>,
extra_headers: Option<HeaderMap>,
addr: Option<net::SocketAddr>,

View File

@ -93,7 +93,6 @@
#![doc(html_logo_url = "https://actix.rs/img/logo.png")]
#![doc(html_favicon_url = "https://actix.rs/favicon.ico")]
use std::cell::RefCell;
use std::convert::TryFrom;
use std::rc::Rc;
use std::time::Duration;
@ -147,7 +146,7 @@ use self::connect::{Connect, ConnectorWrapper};
pub struct Client(Rc<ClientConfig>);
pub(crate) struct ClientConfig {
pub(crate) connector: RefCell<Box<dyn Connect>>,
pub(crate) connector: Box<dyn Connect>,
pub(crate) headers: HeaderMap,
pub(crate) timeout: Option<Duration>,
}
@ -155,9 +154,7 @@ pub(crate) struct ClientConfig {
impl Default for Client {
fn default() -> Self {
Client(Rc::new(ClientConfig {
connector: RefCell::new(Box::new(ConnectorWrapper(
Connector::new().finish(),
))),
connector: Box::new(ConnectorWrapper(Connector::new().finish())),
headers: HeaderMap::new(),
timeout: Some(Duration::from_secs(5)),
}))

View File

@ -183,15 +183,13 @@ impl RequestSender {
where
B: Into<Body>,
{
let mut connector = config.connector.borrow_mut();
let fut = match self {
RequestSender::Owned(head) => {
connector.send_request(head, body.into(), addr)
}
RequestSender::Rc(head, extra_headers) => {
connector.send_request_extra(head, extra_headers, body.into(), addr)
config.connector.send_request(head, body.into(), addr)
}
RequestSender::Rc(head, extra_headers) => config
.connector
.send_request_extra(head, extra_headers, body.into(), addr),
};
SendClientRequest::new(fut, response_decompress, timeout.or(config.timeout))

View File

@ -325,11 +325,7 @@ impl WebsocketsRequest {
let max_size = self.max_size;
let server_mode = self.server_mode;
let fut = self
.config
.connector
.borrow_mut()
.open_tunnel(head, self.addr);
let fut = self.config.connector.open_tunnel(head, self.addr);
// set request timeout
let (head, framed) = if let Some(to) = self.config.timeout {

View File

@ -719,7 +719,6 @@ async fn test_client_cookie_handling() {
async fn client_unread_response() {
let addr = test::unused_addr();
let lst = std::net::TcpListener::bind(addr).unwrap();
std::thread::spawn(move || {
for stream in lst.incoming() {
let mut stream = stream.unwrap();

View File

@ -68,7 +68,7 @@ impl<T: Responder> Responder for OptionResponder<T> {
}
fn future_responder(c: &mut Criterion) {
let rt = actix_rt::System::new("test");
let rt = actix_rt::System::new();
let req = TestRequest::default().to_http_request();
c.bench_function("future_responder", move |b| {
@ -91,7 +91,7 @@ fn future_responder(c: &mut Criterion) {
}
fn responder(c: &mut Criterion) {
let rt = actix_rt::System::new("test");
let rt = actix_rt::System::new();
let req = TestRequest::default().to_http_request();
c.bench_function("responder", move |b| {
b.iter_custom(|_| {

View File

@ -29,7 +29,7 @@ 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 rt = actix_rt::System::new("test");
let rt = actix_rt::System::new();
let srv = rt.block_on(async {
test::start(|| {

View File

@ -25,7 +25,7 @@ pub fn bench_async_service<S>(c: &mut Criterion, srv: S, name: &str)
where
S: Service<ServiceRequest, Response = ServiceResponse, Error = Error> + 'static,
{
let rt = actix_rt::System::new("test");
let rt = actix_rt::System::new();
let srv = Rc::new(RefCell::new(srv));
let req = TestRequest::default().to_srv_request();
@ -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 rt = actix_rt::System::new("test");
let rt = actix_rt::System::new();
let srv = Rc::new(RefCell::new(rt.block_on(init_service(
App::new().service(web::service("/").finish(index)),
))));

View File

@ -422,7 +422,7 @@ where
>
where
B1: MessageBody,
F: FnMut(ServiceRequest, &mut T::Service) -> R + Clone,
F: Fn(ServiceRequest, &T::Service) -> R + Clone,
R: Future<Output = Result<ServiceResponse<B1>, Error>>,
{
App {
@ -480,7 +480,7 @@ mod tests {
#[actix_rt::test]
async fn test_default_resource() {
let mut srv = init_service(
let srv = init_service(
App::new().service(web::resource("/test").to(HttpResponse::Ok)),
)
.await;
@ -492,7 +492,7 @@ mod tests {
let resp = srv.call(req).await.unwrap();
assert_eq!(resp.status(), StatusCode::NOT_FOUND);
let mut srv = init_service(
let srv = init_service(
App::new()
.service(web::resource("/test").to(HttpResponse::Ok))
.service(
@ -525,7 +525,7 @@ mod tests {
#[actix_rt::test]
async fn test_data_factory() {
let mut srv =
let srv =
init_service(App::new().data_factory(|| ok::<_, ()>(10usize)).service(
web::resource("/").to(|_: web::Data<usize>| HttpResponse::Ok()),
))
@ -534,7 +534,7 @@ mod tests {
let resp = srv.call(req).await.unwrap();
assert_eq!(resp.status(), StatusCode::OK);
let mut srv =
let srv =
init_service(App::new().data_factory(|| ok::<_, ()>(10u32)).service(
web::resource("/").to(|_: web::Data<usize>| HttpResponse::Ok()),
))
@ -557,7 +557,7 @@ mod tests {
#[actix_rt::test]
async fn test_extension() {
let mut srv = init_service(App::new().app_data(10usize).service(
let srv = init_service(App::new().app_data(10usize).service(
web::resource("/").to(|req: HttpRequest| {
assert_eq!(*req.app_data::<usize>().unwrap(), 10);
HttpResponse::Ok()
@ -571,7 +571,7 @@ mod tests {
#[actix_rt::test]
async fn test_wrap() {
let mut srv = init_service(
let srv = init_service(
App::new()
.wrap(
DefaultHeaders::new()
@ -581,7 +581,7 @@ mod tests {
)
.await;
let req = TestRequest::with_uri("/test").to_request();
let resp = call_service(&mut srv, req).await;
let resp = call_service(&srv, req).await;
assert_eq!(resp.status(), StatusCode::OK);
assert_eq!(
resp.headers().get(header::CONTENT_TYPE).unwrap(),
@ -591,7 +591,7 @@ mod tests {
#[actix_rt::test]
async fn test_router_wrap() {
let mut srv = init_service(
let srv = init_service(
App::new()
.route("/test", web::get().to(HttpResponse::Ok))
.wrap(
@ -601,7 +601,7 @@ mod tests {
)
.await;
let req = TestRequest::with_uri("/test").to_request();
let resp = call_service(&mut srv, req).await;
let resp = call_service(&srv, req).await;
assert_eq!(resp.status(), StatusCode::OK);
assert_eq!(
resp.headers().get(header::CONTENT_TYPE).unwrap(),
@ -611,7 +611,7 @@ mod tests {
#[actix_rt::test]
async fn test_wrap_fn() {
let mut srv = init_service(
let srv = init_service(
App::new()
.wrap_fn(|req, srv| {
let fut = srv.call(req);
@ -628,7 +628,7 @@ mod tests {
)
.await;
let req = TestRequest::with_uri("/test").to_request();
let resp = call_service(&mut srv, req).await;
let resp = call_service(&srv, req).await;
assert_eq!(resp.status(), StatusCode::OK);
assert_eq!(
resp.headers().get(header::CONTENT_TYPE).unwrap(),
@ -638,7 +638,7 @@ mod tests {
#[actix_rt::test]
async fn test_router_wrap_fn() {
let mut srv = init_service(
let srv = init_service(
App::new()
.route("/test", web::get().to(HttpResponse::Ok))
.wrap_fn(|req, srv| {
@ -655,7 +655,7 @@ mod tests {
)
.await;
let req = TestRequest::with_uri("/test").to_request();
let resp = call_service(&mut srv, req).await;
let resp = call_service(&srv, req).await;
assert_eq!(resp.status(), StatusCode::OK);
assert_eq!(
resp.headers().get(header::CONTENT_TYPE).unwrap(),
@ -665,7 +665,7 @@ mod tests {
#[actix_rt::test]
async fn test_external_resource() {
let mut srv = init_service(
let srv = init_service(
App::new()
.external_resource("youtube", "https://youtube.com/watch/{video_id}")
.route(
@ -679,7 +679,7 @@ mod tests {
)
.await;
let req = TestRequest::with_uri("/test").to_request();
let resp = call_service(&mut srv, req).await;
let resp = call_service(&srv, req).await;
assert_eq!(resp.status(), StatusCode::OK);
let body = read_body(resp).await;
assert_eq!(body, Bytes::from_static(b"https://youtube.com/watch/12345"));

View File

@ -196,7 +196,7 @@ where
actix_service::forward_ready!(service);
fn call(&mut self, req: Request) -> Self::Future {
fn call(&self, req: Request) -> Self::Future {
let (head, payload) = req.into_parts();
let req = if let Some(mut req) = self.app_state.pool().pop() {
@ -287,8 +287,8 @@ impl Service<ServiceRequest> for AppRouting {
actix_service::always_ready!();
fn call(&mut self, mut req: ServiceRequest) -> Self::Future {
let res = self.router.recognize_mut_checked(&mut req, |req, guards| {
fn call(&self, mut req: ServiceRequest) -> Self::Future {
let res = self.router.recognize_checked(&mut req, |req, guards| {
if let Some(ref guards) = guards {
for f in guards {
if !f.check(req.head()) {
@ -354,7 +354,7 @@ mod tests {
let data = Arc::new(AtomicBool::new(false));
{
let mut app = init_service(
let app = init_service(
App::new()
.data(DropData(data.clone()))
.service(web::resource("/test").to(HttpResponse::Ok)),

View File

@ -263,7 +263,7 @@ mod tests {
cfg.app_data(15u8);
};
let mut srv = init_service(App::new().configure(cfg).service(
let srv = init_service(App::new().configure(cfg).service(
web::resource("/").to(|_: web::Data<usize>, req: HttpRequest| {
assert_eq!(*req.app_data::<u8>().unwrap(), 15u8);
HttpResponse::Ok()
@ -286,7 +286,7 @@ mod tests {
// });
// };
// let mut srv =
// let srv =
// init_service(App::new().configure(cfg).service(
// web::resource("/").to(|_: web::Data<usize>| HttpResponse::Ok()),
// ));
@ -297,7 +297,7 @@ mod tests {
// let cfg2 = |cfg: &mut ServiceConfig| {
// cfg.data_factory(|| Ok::<_, ()>(10u32));
// };
// let mut srv = init_service(
// let srv = init_service(
// App::new()
// .service(web::resource("/").to(|_: web::Data<usize>| HttpResponse::Ok()))
// .configure(cfg2),
@ -309,7 +309,7 @@ mod tests {
#[actix_rt::test]
async fn test_external_resource() {
let mut srv = init_service(
let srv = init_service(
App::new()
.configure(|cfg| {
cfg.external_resource(
@ -328,7 +328,7 @@ mod tests {
)
.await;
let req = TestRequest::with_uri("/test").to_request();
let resp = call_service(&mut srv, req).await;
let resp = call_service(&srv, req).await;
assert_eq!(resp.status(), StatusCode::OK);
let body = read_body(resp).await;
assert_eq!(body, Bytes::from_static(b"https://youtube.com/watch/12345"));
@ -336,7 +336,7 @@ mod tests {
#[actix_rt::test]
async fn test_service() {
let mut srv = init_service(App::new().configure(|cfg| {
let srv = init_service(App::new().configure(|cfg| {
cfg.service(
web::resource("/test").route(web::get().to(HttpResponse::Created)),
)
@ -347,13 +347,13 @@ mod tests {
let req = TestRequest::with_uri("/test")
.method(Method::GET)
.to_request();
let resp = call_service(&mut srv, req).await;
let resp = call_service(&srv, req).await;
assert_eq!(resp.status(), StatusCode::CREATED);
let req = TestRequest::with_uri("/index.html")
.method(Method::GET)
.to_request();
let resp = call_service(&mut srv, req).await;
let resp = call_service(&srv, req).await;
assert_eq!(resp.status(), StatusCode::OK);
}
}

View File

@ -144,7 +144,7 @@ mod tests {
#[actix_rt::test]
async fn test_data_extractor() {
let mut srv = init_service(App::new().data("TEST".to_string()).service(
let srv = init_service(App::new().data("TEST".to_string()).service(
web::resource("/").to(|data: web::Data<String>| {
assert_eq!(data.to_lowercase(), "test");
HttpResponse::Ok()
@ -156,7 +156,7 @@ mod tests {
let resp = srv.call(req).await.unwrap();
assert_eq!(resp.status(), StatusCode::OK);
let mut srv =
let srv =
init_service(App::new().data(10u32).service(
web::resource("/").to(|_: web::Data<usize>| HttpResponse::Ok()),
))
@ -165,7 +165,7 @@ mod tests {
let resp = srv.call(req).await.unwrap();
assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR);
let mut srv = init_service(
let srv = init_service(
App::new()
.data(10u32)
.data(13u32)
@ -186,7 +186,7 @@ mod tests {
#[actix_rt::test]
async fn test_app_data_extractor() {
let mut srv =
let srv =
init_service(App::new().app_data(Data::new(10usize)).service(
web::resource("/").to(|_: web::Data<usize>| HttpResponse::Ok()),
))
@ -196,7 +196,7 @@ mod tests {
let resp = srv.call(req).await.unwrap();
assert_eq!(resp.status(), StatusCode::OK);
let mut srv =
let srv =
init_service(App::new().app_data(Data::new(10u32)).service(
web::resource("/").to(|_: web::Data<usize>| HttpResponse::Ok()),
))
@ -208,7 +208,7 @@ mod tests {
#[actix_rt::test]
async fn test_route_data_extractor() {
let mut srv = init_service(
let srv = init_service(
App::new().service(
web::resource("/")
.data(10usize)
@ -222,7 +222,7 @@ mod tests {
assert_eq!(resp.status(), StatusCode::OK);
// different type
let mut srv = init_service(
let srv = init_service(
App::new().service(
web::resource("/")
.data(10u32)
@ -237,7 +237,7 @@ mod tests {
#[actix_rt::test]
async fn test_override_data() {
let mut srv = init_service(App::new().data(1usize).service(
let srv = init_service(App::new().data(1usize).service(
web::resource("/").data(10usize).route(web::get().to(
|data: web::Data<usize>| {
assert_eq!(**data, 10);

View File

@ -113,11 +113,11 @@ where
type Error = Error;
type Future = HandlerServiceFuture<F, T, R>;
fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
fn poll_ready(&self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
fn call(&mut self, req: ServiceRequest) -> Self::Future {
fn call(&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())

View File

@ -80,11 +80,11 @@ where
type Error = Error;
type Future = CompatMiddlewareFuture<S::Future>;
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
fn poll_ready(&self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
self.service.poll_ready(cx).map_err(From::from)
}
fn call(&mut self, req: Req) -> Self::Future {
fn call(&self, req: Req) -> Self::Future {
let fut = self.service.call(req);
CompatMiddlewareFuture { fut }
}
@ -138,7 +138,7 @@ mod tests {
let logger = Logger::default();
let compress = Compress::default();
let mut srv = init_service(
let srv = init_service(
App::new().service(
web::scope("app")
.wrap(Compat::new(logger))
@ -151,7 +151,7 @@ mod tests {
.await;
let req = TestRequest::with_uri("/app/test").to_request();
let resp = call_service(&mut srv, req).await;
let resp = call_service(&srv, req).await;
assert_eq!(resp.status(), StatusCode::OK);
}
@ -160,7 +160,7 @@ mod tests {
let logger = Logger::default();
let compress = Compress::default();
let mut srv = init_service(
let srv = init_service(
App::new().service(
web::resource("app/test")
.wrap(Compat::new(logger))
@ -171,7 +171,7 @@ mod tests {
.await;
let req = TestRequest::with_uri("/app/test").to_request();
let resp = call_service(&mut srv, req).await;
let resp = call_service(&srv, req).await;
assert_eq!(resp.status(), StatusCode::OK);
}
@ -185,11 +185,11 @@ mod tests {
let logger = Logger::default();
let mut mw = Condition::new(true, Compat::new(logger))
let mw = Condition::new(true, Compat::new(logger))
.new_transform(srv.into_service())
.await
.unwrap();
let resp = call_service(&mut mw, TestRequest::default().to_srv_request()).await;
let resp = call_service(&mw, TestRequest::default().to_srv_request()).await;
assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR);
}
}

View File

@ -90,7 +90,7 @@ where
actix_service::forward_ready!(service);
#[allow(clippy::borrow_interior_mutable_const)]
fn call(&mut self, req: ServiceRequest) -> Self::Future {
fn call(&self, req: ServiceRequest) -> Self::Future {
// negotiate content-encoding
let encoding = if let Some(val) = req.headers().get(&ACCEPT_ENCODING) {
if let Ok(enc) = val.to_str() {

View File

@ -76,14 +76,14 @@ where
type Error = E::Error;
type Future = Either<E::Future, D::Future>;
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
fn poll_ready(&self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
match self {
ConditionMiddleware::Enable(service) => service.poll_ready(cx),
ConditionMiddleware::Disable(service) => service.poll_ready(cx),
}
}
fn call(&mut self, req: Req) -> Self::Future {
fn call(&self, req: Req) -> Self::Future {
match self {
ConditionMiddleware::Enable(service) => Either::Left(service.call(req)),
ConditionMiddleware::Disable(service) => Either::Right(service.call(req)),
@ -123,12 +123,12 @@ mod tests {
let mw =
ErrorHandlers::new().handler(StatusCode::INTERNAL_SERVER_ERROR, render_500);
let mut mw = Condition::new(true, mw)
let mw = Condition::new(true, mw)
.new_transform(srv.into_service())
.await
.unwrap();
let resp =
test::call_service(&mut mw, TestRequest::default().to_srv_request()).await;
test::call_service(&mw, TestRequest::default().to_srv_request()).await;
assert_eq!(resp.headers().get(CONTENT_TYPE).unwrap(), "0001");
}
@ -141,13 +141,13 @@ mod tests {
let mw =
ErrorHandlers::new().handler(StatusCode::INTERNAL_SERVER_ERROR, render_500);
let mut mw = Condition::new(false, mw)
let mw = Condition::new(false, mw)
.new_transform(srv.into_service())
.await
.unwrap();
let resp =
test::call_service(&mut mw, TestRequest::default().to_srv_request()).await;
test::call_service(&mw, TestRequest::default().to_srv_request()).await;
assert_eq!(resp.headers().get(CONTENT_TYPE), None);
}
}

View File

@ -143,7 +143,7 @@ where
actix_service::forward_ready!(service);
fn call(&mut self, req: ServiceRequest) -> Self::Future {
fn call(&self, req: ServiceRequest) -> Self::Future {
let inner = self.inner.clone();
let fut = self.service.call(req);
@ -200,7 +200,7 @@ mod tests {
#[actix_rt::test]
async fn test_default_headers() {
let mut mw = DefaultHeaders::new()
let mw = DefaultHeaders::new()
.header(CONTENT_TYPE, "0001")
.new_transform(ok_service())
.await
@ -218,7 +218,7 @@ mod tests {
.finish(),
))
};
let mut mw = DefaultHeaders::new()
let mw = DefaultHeaders::new()
.header(CONTENT_TYPE, "0001")
.new_transform(srv.into_service())
.await
@ -231,7 +231,7 @@ mod tests {
async fn test_content_type() {
let srv =
|req: ServiceRequest| ok(req.into_response(HttpResponse::Ok().finish()));
let mut mw = DefaultHeaders::new()
let mw = DefaultHeaders::new()
.add_content_type()
.new_transform(srv.into_service())
.await

View File

@ -123,7 +123,7 @@ where
actix_service::forward_ready!(service);
fn call(&mut self, req: ServiceRequest) -> Self::Future {
fn call(&self, req: ServiceRequest) -> Self::Future {
let handlers = self.handlers.clone();
let fut = self.service.call(req);
ErrorHandlersFuture::ServiceFuture { fut, handlers }
@ -196,14 +196,14 @@ mod tests {
ok(req.into_response(HttpResponse::InternalServerError().finish()))
};
let mut mw = ErrorHandlers::new()
let mw = ErrorHandlers::new()
.handler(StatusCode::INTERNAL_SERVER_ERROR, render_500)
.new_transform(srv.into_service())
.await
.unwrap();
let resp =
test::call_service(&mut mw, TestRequest::default().to_srv_request()).await;
test::call_service(&mw, TestRequest::default().to_srv_request()).await;
assert_eq!(resp.headers().get(CONTENT_TYPE).unwrap(), "0001");
}
@ -223,14 +223,14 @@ mod tests {
ok(req.into_response(HttpResponse::InternalServerError().finish()))
};
let mut mw = ErrorHandlers::new()
let mw = ErrorHandlers::new()
.handler(StatusCode::INTERNAL_SERVER_ERROR, render_500_async)
.new_transform(srv.into_service())
.await
.unwrap();
let resp =
test::call_service(&mut mw, TestRequest::default().to_srv_request()).await;
test::call_service(&mw, TestRequest::default().to_srv_request()).await;
assert_eq!(resp.headers().get(CONTENT_TYPE).unwrap(), "0001");
}
}

View File

@ -219,7 +219,7 @@ where
actix_service::forward_ready!(service);
fn call(&mut self, req: ServiceRequest) -> Self::Future {
fn call(&self, req: ServiceRequest) -> Self::Future {
if self.inner.exclude.contains(req.path())
|| self.inner.exclude_regex.is_match(req.path())
{
@ -609,7 +609,7 @@ mod tests {
};
let logger = Logger::new("%% %{User-Agent}i %{X-Test}o %{HOME}e %D test");
let mut srv = logger.new_transform(srv.into_service()).await.unwrap();
let srv = logger.new_transform(srv.into_service()).await.unwrap();
let req = TestRequest::default()
.insert_header((
@ -632,7 +632,7 @@ mod tests {
let logger = Logger::new("%% %{User-Agent}i %{X-Test}o %{HOME}e %D test")
.exclude_regex("\\w");
let mut srv = logger.new_transform(srv.into_service()).await.unwrap();
let srv = logger.new_transform(srv.into_service()).await.unwrap();
let req = TestRequest::default()
.insert_header((
@ -806,7 +806,7 @@ mod tests {
captured.to_owned()
});
let mut srv = logger.new_transform(test::ok_service()).await.unwrap();
let srv = logger.new_transform(test::ok_service()).await.unwrap();
let req = TestRequest::default().to_srv_request();
srv.call(req).await.unwrap();

View File

@ -57,7 +57,7 @@ impl Default for TrailingSlash {
/// ```rust
/// use actix_web::{web, middleware, App};
///
/// # actix_web::rt::System::new("doctest").block_on(async {
/// # actix_web::rt::System::new().block_on(async {
/// let app = App::new()
/// .wrap(middleware::NormalizePath::default())
/// .route("/test", web::get().to(|| async { "test" }))
@ -66,22 +66,22 @@ impl Default for TrailingSlash {
/// use actix_web::http::StatusCode;
/// use actix_web::test::{call_service, init_service, TestRequest};
///
/// let mut app = init_service(app).await;
/// let app = init_service(app).await;
///
/// let req = TestRequest::with_uri("/test").to_request();
/// let res = call_service(&mut app, req).await;
/// let res = call_service(&app, req).await;
/// assert_eq!(res.status(), StatusCode::OK);
///
/// let req = TestRequest::with_uri("/test/").to_request();
/// let res = call_service(&mut app, req).await;
/// let res = call_service(&app, req).await;
/// assert_eq!(res.status(), StatusCode::OK);
///
/// let req = TestRequest::with_uri("/unmatchable").to_request();
/// let res = call_service(&mut app, req).await;
/// let res = call_service(&app, req).await;
/// assert_eq!(res.status(), StatusCode::NOT_FOUND);
///
/// let req = TestRequest::with_uri("/unmatchable/").to_request();
/// let res = call_service(&mut app, req).await;
/// let res = call_service(&app, req).await;
/// assert_eq!(res.status(), StatusCode::NOT_FOUND);
/// # })
/// ```
@ -132,7 +132,7 @@ where
actix_service::forward_ready!(service);
fn call(&mut self, mut req: ServiceRequest) -> Self::Future {
fn call(&self, mut req: ServiceRequest) -> Self::Future {
let head = req.head_mut();
let original_path = head.uri.path();
@ -195,7 +195,7 @@ mod tests {
#[actix_rt::test]
async fn test_wrap() {
let mut app = init_service(
let app = init_service(
App::new()
.wrap(NormalizePath::default())
.service(web::resource("/").to(HttpResponse::Ok))
@ -204,37 +204,37 @@ mod tests {
.await;
let req = TestRequest::with_uri("/").to_request();
let res = call_service(&mut app, req).await;
let res = call_service(&app, req).await;
assert!(res.status().is_success());
let req = TestRequest::with_uri("/?query=test").to_request();
let res = call_service(&mut app, req).await;
let res = call_service(&app, req).await;
assert!(res.status().is_success());
let req = TestRequest::with_uri("///").to_request();
let res = call_service(&mut app, req).await;
let res = call_service(&app, req).await;
assert!(res.status().is_success());
let req = TestRequest::with_uri("/v1//something////").to_request();
let res = call_service(&mut app, req).await;
let res = call_service(&app, req).await;
assert!(res.status().is_success());
let req2 = TestRequest::with_uri("//v1/something").to_request();
let res2 = call_service(&mut app, req2).await;
let res2 = call_service(&app, req2).await;
assert!(res2.status().is_success());
let req3 = TestRequest::with_uri("//v1//////something").to_request();
let res3 = call_service(&mut app, req3).await;
let res3 = call_service(&app, req3).await;
assert!(res3.status().is_success());
let req4 = TestRequest::with_uri("/v1//something").to_request();
let res4 = call_service(&mut app, req4).await;
let res4 = call_service(&app, req4).await;
assert!(res4.status().is_success());
}
#[actix_rt::test]
async fn trim_trailing_slashes() {
let mut app = init_service(
let app = init_service(
App::new()
.wrap(NormalizePath(TrailingSlash::Trim))
.service(web::resource("/").to(HttpResponse::Ok))
@ -244,37 +244,37 @@ mod tests {
// root paths should still work
let req = TestRequest::with_uri("/").to_request();
let res = call_service(&mut app, req).await;
let res = call_service(&app, req).await;
assert!(res.status().is_success());
let req = TestRequest::with_uri("/?query=test").to_request();
let res = call_service(&mut app, req).await;
let res = call_service(&app, req).await;
assert!(res.status().is_success());
let req = TestRequest::with_uri("///").to_request();
let res = call_service(&mut app, req).await;
let res = call_service(&app, req).await;
assert!(res.status().is_success());
let req = TestRequest::with_uri("/v1/something////").to_request();
let res = call_service(&mut app, req).await;
let res = call_service(&app, req).await;
assert!(res.status().is_success());
let req2 = TestRequest::with_uri("/v1/something/").to_request();
let res2 = call_service(&mut app, req2).await;
let res2 = call_service(&app, req2).await;
assert!(res2.status().is_success());
let req3 = TestRequest::with_uri("//v1//something//").to_request();
let res3 = call_service(&mut app, req3).await;
let res3 = call_service(&app, req3).await;
assert!(res3.status().is_success());
let req4 = TestRequest::with_uri("//v1//something").to_request();
let res4 = call_service(&mut app, req4).await;
let res4 = call_service(&app, req4).await;
assert!(res4.status().is_success());
}
#[actix_rt::test]
async fn keep_trailing_slash_unchanged() {
let mut app = init_service(
let app = init_service(
App::new()
.wrap(NormalizePath(TrailingSlash::MergeOnly))
.service(web::resource("/").to(HttpResponse::Ok))
@ -299,7 +299,7 @@ mod tests {
for (path, success) in tests {
let req = TestRequest::with_uri(path).to_request();
let res = call_service(&mut app, req).await;
let res = call_service(&app, req).await;
assert_eq!(res.status().is_success(), success);
}
}
@ -311,7 +311,7 @@ mod tests {
ready(Ok(req.into_response(HttpResponse::Ok().finish())))
};
let mut normalize = NormalizePath::default()
let normalize = NormalizePath::default()
.new_transform(srv.into_service())
.await
.unwrap();
@ -342,7 +342,7 @@ mod tests {
ready(Ok(req.into_response(HttpResponse::Ok().finish())))
};
let mut normalize = NormalizePath::default()
let normalize = NormalizePath::default()
.new_transform(srv.into_service())
.await
.unwrap();
@ -359,7 +359,7 @@ mod tests {
ready(Ok(req.into_response(HttpResponse::Ok().finish())))
};
let mut normalize = NormalizePath::default()
let normalize = NormalizePath::default()
.new_transform(srv.into_service())
.await
.unwrap();

View File

@ -556,7 +556,7 @@ mod tests {
#[actix_rt::test]
async fn test_drop_http_request_pool() {
let mut srv = init_service(App::new().service(web::resource("/").to(
let srv = init_service(App::new().service(web::resource("/").to(
|req: HttpRequest| {
HttpResponse::Ok()
.insert_header(("pool_cap", req.app_state().pool().cap))
@ -566,7 +566,7 @@ mod tests {
.await;
let req = TestRequest::default().to_request();
let resp = call_service(&mut srv, req).await;
let resp = call_service(&srv, req).await;
drop(srv);
@ -575,7 +575,7 @@ mod tests {
#[actix_rt::test]
async fn test_data() {
let mut srv = init_service(App::new().app_data(10usize).service(
let srv = init_service(App::new().app_data(10usize).service(
web::resource("/").to(|req: HttpRequest| {
if req.app_data::<usize>().is_some() {
HttpResponse::Ok()
@ -587,10 +587,10 @@ mod tests {
.await;
let req = TestRequest::default().to_request();
let resp = call_service(&mut srv, req).await;
let resp = call_service(&srv, req).await;
assert_eq!(resp.status(), StatusCode::OK);
let mut srv = init_service(App::new().app_data(10u32).service(
let srv = init_service(App::new().app_data(10u32).service(
web::resource("/").to(|req: HttpRequest| {
if req.app_data::<usize>().is_some() {
HttpResponse::Ok()
@ -602,7 +602,7 @@ mod tests {
.await;
let req = TestRequest::default().to_request();
let resp = call_service(&mut srv, req).await;
let resp = call_service(&srv, req).await;
assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
}
@ -614,7 +614,7 @@ mod tests {
HttpResponse::Ok().body(num.to_string())
}
let mut srv = init_service(
let srv = init_service(
App::new()
.app_data(88usize)
.service(web::resource("/").route(web::get().to(echo_usize)))
@ -645,7 +645,7 @@ mod tests {
HttpResponse::Ok().body(num.to_string())
}
let mut srv = init_service(
let srv = init_service(
App::new()
.app_data(88usize)
.service(web::resource("/").route(web::get().to(echo_usize)))
@ -685,7 +685,7 @@ mod tests {
let tracker = Rc::new(RefCell::new(Tracker { dropped: false }));
{
let tracker2 = Rc::clone(&tracker);
let mut srv = init_service(App::new().data(10u32).service(
let srv = init_service(App::new().data(10u32).service(
web::resource("/").to(move |req: HttpRequest| {
req.extensions_mut().insert(Foo {
tracker: Rc::clone(&tracker2),
@ -696,7 +696,7 @@ mod tests {
.await;
let req = TestRequest::default().to_request();
let resp = call_service(&mut srv, req).await;
let resp = call_service(&srv, req).await;
assert_eq!(resp.status(), StatusCode::OK);
}
@ -705,7 +705,7 @@ mod tests {
#[actix_rt::test]
async fn extract_path_pattern() {
let mut srv = init_service(
let srv = init_service(
App::new().service(
web::scope("/user/{id}")
.service(web::resource("/profile").route(web::get().to(
@ -727,17 +727,17 @@ mod tests {
.await;
let req = TestRequest::get().uri("/user/22/profile").to_request();
let res = call_service(&mut srv, req).await;
let res = call_service(&srv, req).await;
assert_eq!(res.status(), StatusCode::OK);
let req = TestRequest::get().uri("/user/22/not-exist").to_request();
let res = call_service(&mut srv, req).await;
let res = call_service(&srv, req).await;
assert_eq!(res.status(), StatusCode::OK);
}
#[actix_rt::test]
async fn extract_path_pattern_complex() {
let mut srv = init_service(
let srv = init_service(
App::new()
.service(web::scope("/user").service(web::scope("/{id}").service(
web::resource("").to(move |req: HttpRequest| {
@ -759,15 +759,15 @@ mod tests {
.await;
let req = TestRequest::get().uri("/user/test").to_request();
let res = call_service(&mut srv, req).await;
let res = call_service(&srv, req).await;
assert_eq!(res.status(), StatusCode::OK);
let req = TestRequest::get().uri("/").to_request();
let res = call_service(&mut srv, req).await;
let res = call_service(&srv, req).await;
assert_eq!(res.status(), StatusCode::OK);
let req = TestRequest::get().uri("/not-exist").to_request();
let res = call_service(&mut srv, req).await;
let res = call_service(&srv, req).await;
assert_eq!(res.status(), StatusCode::OK);
}
}

View File

@ -102,7 +102,7 @@ mod tests {
#[actix_rt::test]
async fn req_data_extractor() {
let mut srv = init_service(
let srv = init_service(
App::new()
.wrap_fn(|req, srv| {
if req.method() == Method::POST {
@ -142,7 +142,7 @@ mod tests {
#[actix_rt::test]
async fn req_data_internal_mutability() {
let mut srv = init_service(
let srv = init_service(
App::new()
.wrap_fn(|req, srv| {
let data_before = Rc::new(RefCell::new(42u32));

View File

@ -328,7 +328,7 @@ where
>,
>
where
F: FnMut(ServiceRequest, &mut T::Service) -> R + Clone,
F: Fn(ServiceRequest, &T::Service) -> R + Clone,
R: Future<Output = Result<ServiceResponse, Error>>,
{
Resource {
@ -471,8 +471,8 @@ impl Service<ServiceRequest> for ResourceService {
actix_service::always_ready!();
fn call(&mut self, mut req: ServiceRequest) -> Self::Future {
for route in self.routes.iter_mut() {
fn call(&self, mut req: ServiceRequest) -> Self::Future {
for route in self.routes.iter() {
if route.check(&mut req) {
if let Some(ref app_data) = self.app_data {
req.add_data_container(app_data.clone());
@ -530,7 +530,7 @@ mod tests {
#[actix_rt::test]
async fn test_middleware() {
let mut srv =
let srv =
init_service(
App::new().service(
web::resource("/test")
@ -544,7 +544,7 @@ mod tests {
)
.await;
let req = TestRequest::with_uri("/test").to_request();
let resp = call_service(&mut srv, req).await;
let resp = call_service(&srv, req).await;
assert_eq!(resp.status(), StatusCode::OK);
assert_eq!(
resp.headers().get(header::CONTENT_TYPE).unwrap(),
@ -554,7 +554,7 @@ mod tests {
#[actix_rt::test]
async fn test_middleware_fn() {
let mut srv = init_service(
let srv = init_service(
App::new().service(
web::resource("/test")
.wrap_fn(|req, srv| {
@ -574,7 +574,7 @@ mod tests {
)
.await;
let req = TestRequest::with_uri("/test").to_request();
let resp = call_service(&mut srv, req).await;
let resp = call_service(&srv, req).await;
assert_eq!(resp.status(), StatusCode::OK);
assert_eq!(
resp.headers().get(header::CONTENT_TYPE).unwrap(),
@ -584,20 +584,20 @@ mod tests {
#[actix_rt::test]
async fn test_to() {
let mut srv =
let srv =
init_service(App::new().service(web::resource("/test").to(|| async {
sleep(Duration::from_millis(100)).await;
Ok::<_, Error>(HttpResponse::Ok())
})))
.await;
let req = TestRequest::with_uri("/test").to_request();
let resp = call_service(&mut srv, req).await;
let resp = call_service(&srv, req).await;
assert_eq!(resp.status(), StatusCode::OK);
}
#[actix_rt::test]
async fn test_pattern() {
let mut srv = init_service(
let srv = init_service(
App::new().service(
web::resource(["/test", "/test2"])
.to(|| async { Ok::<_, Error>(HttpResponse::Ok()) }),
@ -605,16 +605,16 @@ mod tests {
)
.await;
let req = TestRequest::with_uri("/test").to_request();
let resp = call_service(&mut srv, req).await;
let resp = call_service(&srv, req).await;
assert_eq!(resp.status(), StatusCode::OK);
let req = TestRequest::with_uri("/test2").to_request();
let resp = call_service(&mut srv, req).await;
let resp = call_service(&srv, req).await;
assert_eq!(resp.status(), StatusCode::OK);
}
#[actix_rt::test]
async fn test_default_resource() {
let mut srv = init_service(
let srv = init_service(
App::new()
.service(web::resource("/test").route(web::get().to(HttpResponse::Ok)))
.default_service(|r: ServiceRequest| {
@ -623,16 +623,16 @@ mod tests {
)
.await;
let req = TestRequest::with_uri("/test").to_request();
let resp = call_service(&mut srv, req).await;
let resp = call_service(&srv, req).await;
assert_eq!(resp.status(), StatusCode::OK);
let req = TestRequest::with_uri("/test")
.method(Method::POST)
.to_request();
let resp = call_service(&mut srv, req).await;
let resp = call_service(&srv, req).await;
assert_eq!(resp.status(), StatusCode::METHOD_NOT_ALLOWED);
let mut srv = init_service(
let srv = init_service(
App::new().service(
web::resource("/test")
.route(web::get().to(HttpResponse::Ok))
@ -644,19 +644,19 @@ mod tests {
.await;
let req = TestRequest::with_uri("/test").to_request();
let resp = call_service(&mut srv, req).await;
let resp = call_service(&srv, req).await;
assert_eq!(resp.status(), StatusCode::OK);
let req = TestRequest::with_uri("/test")
.method(Method::POST)
.to_request();
let resp = call_service(&mut srv, req).await;
let resp = call_service(&srv, req).await;
assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
}
#[actix_rt::test]
async fn test_resource_guards() {
let mut srv = init_service(
let srv = init_service(
App::new()
.service(
web::resource("/test/{p}")
@ -679,25 +679,25 @@ mod tests {
let req = TestRequest::with_uri("/test/it")
.method(Method::GET)
.to_request();
let resp = call_service(&mut srv, req).await;
let resp = call_service(&srv, req).await;
assert_eq!(resp.status(), StatusCode::OK);
let req = TestRequest::with_uri("/test/it")
.method(Method::PUT)
.to_request();
let resp = call_service(&mut srv, req).await;
let resp = call_service(&srv, req).await;
assert_eq!(resp.status(), StatusCode::CREATED);
let req = TestRequest::with_uri("/test/it")
.method(Method::DELETE)
.to_request();
let resp = call_service(&mut srv, req).await;
let resp = call_service(&srv, req).await;
assert_eq!(resp.status(), StatusCode::NO_CONTENT);
}
#[actix_rt::test]
async fn test_data() {
let mut srv = init_service(
let srv = init_service(
App::new()
.data(1.0f64)
.data(1usize)
@ -723,13 +723,13 @@ mod tests {
.await;
let req = TestRequest::get().uri("/test").to_request();
let resp = call_service(&mut srv, req).await;
let resp = call_service(&srv, req).await;
assert_eq!(resp.status(), StatusCode::OK);
}
#[actix_rt::test]
async fn test_data_default_service() {
let mut srv = init_service(
let srv = init_service(
App::new().data(1usize).service(
web::resource("/test")
.data(10usize)
@ -742,7 +742,7 @@ mod tests {
.await;
let req = TestRequest::get().uri("/test").to_request();
let resp = call_service(&mut srv, req).await;
let resp = call_service(&srv, req).await;
assert_eq!(resp.status(), StatusCode::OK);
}
}

View File

@ -260,7 +260,7 @@ pub(crate) mod tests {
#[actix_rt::test]
async fn test_option_responder() {
let mut srv = init_service(
let srv = init_service(
App::new()
.service(
web::resource("/none").to(|| async { Option::<&'static str>::None }),

View File

@ -121,11 +121,11 @@ impl Service<ServiceRequest> for RouteService {
type Error = Error;
type Future = LocalBoxFuture<'static, Result<Self::Response, Self::Error>>;
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
fn poll_ready(&self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
self.service.poll_ready(cx)
}
fn call(&mut self, req: ServiceRequest) -> Self::Future {
fn call(&self, req: ServiceRequest) -> Self::Future {
self.service.call(req)
}
}
@ -299,11 +299,11 @@ where
type Error = Error;
type Future = LocalBoxFuture<'static, Result<Self::Response, Self::Error>>;
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
fn poll_ready(&self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
self.service.poll_ready(cx)
}
fn call(&mut self, req: ServiceRequest) -> Self::Future {
fn call(&self, req: ServiceRequest) -> Self::Future {
Box::pin(self.service.call(req))
}
}
@ -327,7 +327,7 @@ mod tests {
#[actix_rt::test]
async fn test_route() {
let mut srv = init_service(
let srv = init_service(
App::new()
.service(
web::resource("/test")
@ -356,35 +356,35 @@ mod tests {
let req = TestRequest::with_uri("/test")
.method(Method::GET)
.to_request();
let resp = call_service(&mut srv, req).await;
let resp = call_service(&srv, req).await;
assert_eq!(resp.status(), StatusCode::OK);
let req = TestRequest::with_uri("/test")
.method(Method::POST)
.to_request();
let resp = call_service(&mut srv, req).await;
let resp = call_service(&srv, req).await;
assert_eq!(resp.status(), StatusCode::CREATED);
let req = TestRequest::with_uri("/test")
.method(Method::PUT)
.to_request();
let resp = call_service(&mut srv, req).await;
let resp = call_service(&srv, req).await;
assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
let req = TestRequest::with_uri("/test")
.method(Method::DELETE)
.to_request();
let resp = call_service(&mut srv, req).await;
let resp = call_service(&srv, req).await;
assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
let req = TestRequest::with_uri("/test")
.method(Method::HEAD)
.to_request();
let resp = call_service(&mut srv, req).await;
let resp = call_service(&srv, req).await;
assert_eq!(resp.status(), StatusCode::METHOD_NOT_ALLOWED);
let req = TestRequest::with_uri("/json").to_request();
let resp = call_service(&mut srv, req).await;
let resp = call_service(&srv, req).await;
assert_eq!(resp.status(), StatusCode::OK);
let body = read_body(resp).await;

View File

@ -380,7 +380,7 @@ where
>,
>
where
F: FnMut(ServiceRequest, &mut T::Service) -> R + Clone,
F: Fn(ServiceRequest, &T::Service) -> R + Clone,
R: Future<Output = Result<ServiceResponse, Error>>,
{
Scope {
@ -526,8 +526,8 @@ impl Service<ServiceRequest> for ScopeService {
actix_service::always_ready!();
fn call(&mut self, mut req: ServiceRequest) -> Self::Future {
let res = self.router.recognize_mut_checked(&mut req, |req, guards| {
fn call(&self, mut req: ServiceRequest) -> Self::Future {
let res = self.router.recognize_checked(&mut req, |req, guards| {
if let Some(ref guards) = guards {
for f in guards {
if !f.check(req.head()) {
@ -589,7 +589,7 @@ mod tests {
#[actix_rt::test]
async fn test_scope() {
let mut srv = init_service(App::new().service(
let srv = init_service(App::new().service(
web::scope("/app").service(web::resource("/path1").to(HttpResponse::Ok)),
))
.await;
@ -601,7 +601,7 @@ mod tests {
#[actix_rt::test]
async fn test_scope_root() {
let mut srv = init_service(
let srv = init_service(
App::new().service(
web::scope("/app")
.service(web::resource("").to(HttpResponse::Ok))
@ -621,7 +621,7 @@ mod tests {
#[actix_rt::test]
async fn test_scope_root2() {
let mut srv = init_service(App::new().service(
let srv = init_service(App::new().service(
web::scope("/app/").service(web::resource("").to(HttpResponse::Ok)),
))
.await;
@ -637,7 +637,7 @@ mod tests {
#[actix_rt::test]
async fn test_scope_root3() {
let mut srv = init_service(App::new().service(
let srv = init_service(App::new().service(
web::scope("/app/").service(web::resource("/").to(HttpResponse::Ok)),
))
.await;
@ -653,7 +653,7 @@ mod tests {
#[actix_rt::test]
async fn test_scope_route() {
let mut srv = init_service(
let srv = init_service(
App::new().service(
web::scope("app")
.route("/path1", web::get().to(HttpResponse::Ok))
@ -681,7 +681,7 @@ mod tests {
#[actix_rt::test]
async fn test_scope_route_without_leading_slash() {
let mut srv = init_service(
let srv = init_service(
App::new().service(
web::scope("app").service(
web::resource("path1")
@ -711,7 +711,7 @@ mod tests {
#[actix_rt::test]
async fn test_scope_guard() {
let mut srv = init_service(
let srv = init_service(
App::new().service(
web::scope("/app")
.guard(guard::Get())
@ -735,14 +735,13 @@ mod tests {
#[actix_rt::test]
async fn test_scope_variable_segment() {
let mut srv =
init_service(App::new().service(web::scope("/ab-{project}").service(
web::resource("/path1").to(|r: HttpRequest| {
HttpResponse::Ok()
.body(format!("project: {}", &r.match_info()["project"]))
}),
)))
.await;
let srv = init_service(App::new().service(web::scope("/ab-{project}").service(
web::resource("/path1").to(|r: HttpRequest| {
HttpResponse::Ok()
.body(format!("project: {}", &r.match_info()["project"]))
}),
)))
.await;
let req = TestRequest::with_uri("/ab-project1/path1").to_request();
let resp = srv.call(req).await.unwrap();
@ -763,7 +762,7 @@ mod tests {
#[actix_rt::test]
async fn test_nested_scope() {
let mut srv = init_service(App::new().service(web::scope("/app").service(
let srv = init_service(App::new().service(web::scope("/app").service(
web::scope("/t1").service(web::resource("/path1").to(HttpResponse::Created)),
)))
.await;
@ -775,7 +774,7 @@ mod tests {
#[actix_rt::test]
async fn test_nested_scope_no_slash() {
let mut srv = init_service(App::new().service(web::scope("/app").service(
let srv = init_service(App::new().service(web::scope("/app").service(
web::scope("t1").service(web::resource("/path1").to(HttpResponse::Created)),
)))
.await;
@ -787,7 +786,7 @@ mod tests {
#[actix_rt::test]
async fn test_nested_scope_root() {
let mut srv = init_service(
let srv = init_service(
App::new().service(
web::scope("/app").service(
web::scope("/t1")
@ -809,7 +808,7 @@ mod tests {
#[actix_rt::test]
async fn test_nested_scope_filter() {
let mut srv = init_service(
let srv = init_service(
App::new().service(
web::scope("/app").service(
web::scope("/t1")
@ -835,7 +834,7 @@ mod tests {
#[actix_rt::test]
async fn test_nested_scope_with_variable_segment() {
let mut srv = init_service(App::new().service(web::scope("/app").service(
let srv = init_service(App::new().service(web::scope("/app").service(
web::scope("/{project_id}").service(web::resource("/path1").to(
|r: HttpRequest| {
HttpResponse::Created()
@ -860,7 +859,7 @@ mod tests {
#[actix_rt::test]
async fn test_nested2_scope_with_variable_segment() {
let mut srv = init_service(App::new().service(web::scope("/app").service(
let srv = init_service(App::new().service(web::scope("/app").service(
web::scope("/{project}").service(web::scope("/{id}").service(
web::resource("/path1").to(|r: HttpRequest| {
HttpResponse::Created().body(format!(
@ -892,7 +891,7 @@ mod tests {
#[actix_rt::test]
async fn test_default_resource() {
let mut srv = init_service(
let srv = init_service(
App::new().service(
web::scope("/app")
.service(web::resource("/path1").to(HttpResponse::Ok))
@ -914,7 +913,7 @@ mod tests {
#[actix_rt::test]
async fn test_default_resource_propagation() {
let mut srv = init_service(
let srv = init_service(
App::new()
.service(
web::scope("/app1")
@ -942,7 +941,7 @@ mod tests {
#[actix_rt::test]
async fn test_middleware() {
let mut srv = init_service(
let srv = init_service(
App::new().service(
web::scope("app")
.wrap(
@ -959,7 +958,7 @@ mod tests {
.await;
let req = TestRequest::with_uri("/app/test").to_request();
let resp = call_service(&mut srv, req).await;
let resp = call_service(&srv, req).await;
assert_eq!(resp.status(), StatusCode::OK);
assert_eq!(
resp.headers().get(header::CONTENT_TYPE).unwrap(),
@ -969,7 +968,7 @@ mod tests {
#[actix_rt::test]
async fn test_middleware_fn() {
let mut srv = init_service(
let srv = init_service(
App::new().service(
web::scope("app")
.wrap_fn(|req, srv| {
@ -989,7 +988,7 @@ mod tests {
.await;
let req = TestRequest::with_uri("/app/test").to_request();
let resp = call_service(&mut srv, req).await;
let resp = call_service(&srv, req).await;
assert_eq!(resp.status(), StatusCode::OK);
assert_eq!(
resp.headers().get(header::CONTENT_TYPE).unwrap(),
@ -999,7 +998,7 @@ mod tests {
#[actix_rt::test]
async fn test_override_data() {
let mut srv = init_service(App::new().data(1usize).service(
let srv = init_service(App::new().data(1usize).service(
web::scope("app").data(10usize).route(
"/t",
web::get().to(|data: web::Data<usize>| {
@ -1011,13 +1010,13 @@ mod tests {
.await;
let req = TestRequest::with_uri("/app/t").to_request();
let resp = call_service(&mut srv, req).await;
let resp = call_service(&srv, req).await;
assert_eq!(resp.status(), StatusCode::OK);
}
#[actix_rt::test]
async fn test_override_data_default_service() {
let mut srv = init_service(App::new().data(1usize).service(
let srv = init_service(App::new().data(1usize).service(
web::scope("app").data(10usize).default_service(web::to(
|data: web::Data<usize>| {
assert_eq!(**data, 10);
@ -1028,13 +1027,13 @@ mod tests {
.await;
let req = TestRequest::with_uri("/app/t").to_request();
let resp = call_service(&mut srv, req).await;
let resp = call_service(&srv, req).await;
assert_eq!(resp.status(), StatusCode::OK);
}
#[actix_rt::test]
async fn test_override_app_data() {
let mut srv = init_service(App::new().app_data(web::Data::new(1usize)).service(
let srv = init_service(App::new().app_data(web::Data::new(1usize)).service(
web::scope("app").app_data(web::Data::new(10usize)).route(
"/t",
web::get().to(|data: web::Data<usize>| {
@ -1046,17 +1045,16 @@ mod tests {
.await;
let req = TestRequest::with_uri("/app/t").to_request();
let resp = call_service(&mut srv, req).await;
let resp = call_service(&srv, req).await;
assert_eq!(resp.status(), StatusCode::OK);
}
#[actix_rt::test]
async fn test_scope_config() {
let mut srv =
init_service(App::new().service(web::scope("/app").configure(|s| {
s.route("/path1", web::get().to(HttpResponse::Ok));
})))
.await;
let srv = init_service(App::new().service(web::scope("/app").configure(|s| {
s.route("/path1", web::get().to(HttpResponse::Ok));
})))
.await;
let req = TestRequest::with_uri("/app/path1").to_request();
let resp = srv.call(req).await.unwrap();
@ -1065,13 +1063,12 @@ mod tests {
#[actix_rt::test]
async fn test_scope_config_2() {
let mut srv =
init_service(App::new().service(web::scope("/app").configure(|s| {
s.service(web::scope("/v1").configure(|s| {
s.route("/", web::get().to(HttpResponse::Ok));
}));
})))
.await;
let srv = init_service(App::new().service(web::scope("/app").configure(|s| {
s.service(web::scope("/v1").configure(|s| {
s.route("/", web::get().to(HttpResponse::Ok));
}));
})))
.await;
let req = TestRequest::with_uri("/app/v1/").to_request();
let resp = srv.call(req).await.unwrap();
@ -1080,24 +1077,20 @@ mod tests {
#[actix_rt::test]
async fn test_url_for_external() {
let mut srv =
init_service(App::new().service(web::scope("/app").configure(|s| {
s.service(web::scope("/v1").configure(|s| {
s.external_resource(
"youtube",
"https://youtube.com/watch/{video_id}",
);
s.route(
"/",
web::get().to(|req: HttpRequest| {
HttpResponse::Ok().body(
req.url_for("youtube", &["xxxxxx"]).unwrap().to_string(),
)
}),
);
}));
})))
.await;
let srv = init_service(App::new().service(web::scope("/app").configure(|s| {
s.service(web::scope("/v1").configure(|s| {
s.external_resource("youtube", "https://youtube.com/watch/{video_id}");
s.route(
"/",
web::get().to(|req: HttpRequest| {
HttpResponse::Ok().body(
req.url_for("youtube", &["xxxxxx"]).unwrap().to_string(),
)
}),
);
}));
})))
.await;
let req = TestRequest::with_uri("/app/v1/").to_request();
let resp = srv.call(req).await.unwrap();
@ -1108,7 +1101,7 @@ mod tests {
#[actix_rt::test]
async fn test_url_for_nested() {
let mut srv = init_service(App::new().service(web::scope("/a").service(
let srv = init_service(App::new().service(web::scope("/a").service(
web::scope("/b").service(web::resource("/c/{stuff}").name("c").route(
web::get().to(|req: HttpRequest| {
HttpResponse::Ok()
@ -1119,7 +1112,7 @@ mod tests {
.await;
let req = TestRequest::with_uri("/a/b/c/test").to_request();
let resp = call_service(&mut srv, req).await;
let resp = call_service(&srv, req).await;
assert_eq!(resp.status(), StatusCode::OK);
let body = read_body(resp).await;
assert_eq!(

View File

@ -630,7 +630,7 @@ where
/// }
/// ```
pub fn run(self) -> Server {
self.builder.start()
self.builder.run()
}
}

View File

@ -542,7 +542,7 @@ mod tests {
#[actix_rt::test]
async fn test_service() {
let mut srv = init_service(
let srv = init_service(
App::new().service(web::service("/test").name("test").finish(
|req: ServiceRequest| ok(req.into_response(HttpResponse::Ok().finish())),
)),
@ -552,7 +552,7 @@ mod tests {
let resp = srv.call(req).await.unwrap();
assert_eq!(resp.status(), http::StatusCode::OK);
let mut srv = init_service(
let srv = init_service(
App::new().service(web::service("/test").guard(guard::Get()).finish(
|req: ServiceRequest| ok(req.into_response(HttpResponse::Ok().finish())),
)),
@ -567,7 +567,7 @@ mod tests {
#[actix_rt::test]
async fn test_service_data() {
let mut srv = init_service(
let srv = init_service(
App::new()
.data(42u32)
.service(web::service("/test").name("test").finish(

View File

@ -60,7 +60,7 @@ pub fn default_service(
///
/// #[actix_rt::test]
/// async fn test_init_service() {
/// let mut app = test::init_service(
/// let app = test::init_service(
/// App::new()
/// .service(web::resource("/test").to(|| async { HttpResponse::Ok() }))
/// ).await;
@ -116,7 +116,7 @@ where
///
/// #[actix_rt::test]
/// async fn test_response() {
/// let mut app = test::init_service(
/// let app = test::init_service(
/// App::new()
/// .service(web::resource("/test").to(|| async {
/// HttpResponse::Ok()
@ -127,11 +127,11 @@ where
/// let req = test::TestRequest::with_uri("/test").to_request();
///
/// // Call application
/// let resp = test::call_service(&mut app, req).await;
/// let resp = test::call_service(&app, req).await;
/// assert_eq!(resp.status(), StatusCode::OK);
/// }
/// ```
pub async fn call_service<S, R, B, E>(app: &mut S, req: R) -> S::Response
pub async fn call_service<S, R, B, E>(app: &S, req: R) -> S::Response
where
S: Service<R, Response = ServiceResponse<B>, Error = E>,
E: std::fmt::Debug,
@ -147,7 +147,7 @@ where
///
/// #[actix_rt::test]
/// async fn test_index() {
/// let mut app = test::init_service(
/// let app = test::init_service(
/// App::new().service(
/// web::resource("/index.html")
/// .route(web::post().to(|| async {
@ -160,11 +160,11 @@ where
/// .header(header::CONTENT_TYPE, "application/json")
/// .to_request();
///
/// let result = test::read_response(&mut app, req).await;
/// let result = test::read_response(&app, req).await;
/// assert_eq!(result, Bytes::from_static(b"welcome!"));
/// }
/// ```
pub async fn read_response<S, B>(app: &mut S, req: Request) -> Bytes
pub async fn read_response<S, B>(app: &S, req: Request) -> Bytes
where
S: Service<Request, Response = ServiceResponse<B>, Error = Error>,
B: MessageBody + Unpin,
@ -190,7 +190,7 @@ where
///
/// #[actix_rt::test]
/// async fn test_index() {
/// let mut app = test::init_service(
/// let app = test::init_service(
/// App::new().service(
/// web::resource("/index.html")
/// .route(web::post().to(|| async {
@ -203,7 +203,7 @@ where
/// .header(header::CONTENT_TYPE, "application/json")
/// .to_request();
///
/// let resp = test::call_service(&mut app, req).await;
/// let resp = test::call_service(&app, req).await;
/// let result = test::read_body(resp).await;
/// assert_eq!(result, Bytes::from_static(b"welcome!"));
/// }
@ -234,7 +234,7 @@ where
///
/// #[actix_rt::test]
/// async fn test_post_person() {
/// let mut app = test::init_service(
/// let app = test::init_service(
/// App::new().service(
/// web::resource("/people")
/// .route(web::post().to(|person: web::Json<Person>| async {
@ -294,7 +294,7 @@ where
///
/// #[actix_rt::test]
/// async fn test_add_person() {
/// let mut app = test::init_service(
/// let app = test::init_service(
/// App::new().service(
/// web::resource("/people")
/// .route(web::post().to(|person: web::Json<Person>| async {
@ -314,7 +314,7 @@ where
/// let result: Person = test::read_response_json(&mut app, req).await;
/// }
/// ```
pub async fn read_response_json<S, B, T>(app: &mut S, req: Request) -> T
pub async fn read_response_json<S, B, T>(app: &S, req: Request) -> T
where
S: Service<Request, Response = ServiceResponse<B>, Error = Error>,
B: MessageBody + Unpin,
@ -569,7 +569,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
pub async fn send_request<S, B, E>(self, app: &S) -> S::Response
where
S: Service<Request, Response = ServiceResponse<B>, Error = E>,
E: std::fmt::Debug,
@ -595,7 +595,7 @@ impl TestRequest {
///
/// #[actix_rt::test]
/// async fn test_example() {
/// let mut srv = test::start(
/// let srv = test::start(
/// || App::new().service(
/// web::resource("/").to(my_handler))
/// );
@ -635,7 +635,7 @@ where
///
/// #[actix_rt::test]
/// async fn test_example() {
/// let mut srv = test::start_with(test::config().h1(), ||
/// let srv = test::start_with(test::config().h1(), ||
/// App::new().service(web::resource("/").to(my_handler))
/// );
///
@ -667,7 +667,7 @@ where
// run server in separate thread
thread::spawn(move || {
let sys = System::new("actix-test-server");
let sys = System::new();
let tcp = net::TcpListener::bind("127.0.0.1:0").unwrap();
let local_addr = tcp.local_addr().unwrap();
let factory = factory.clone();
@ -760,7 +760,7 @@ where
.unwrap();
sys.block_on(async {
let srv = srv.start();
let srv = srv.run();
tx.send((System::current(), srv, local_addr)).unwrap();
});
@ -1043,7 +1043,7 @@ mod tests {
#[actix_rt::test]
async fn test_request_methods() {
let mut app = init_service(
let app = init_service(
App::new().service(
web::resource("/index.html")
.route(web::put().to(|| HttpResponse::Ok().body("put!")))
@ -1058,7 +1058,7 @@ mod tests {
.insert_header((header::CONTENT_TYPE, "application/json"))
.to_request();
let result = read_response(&mut app, put_req).await;
let result = read_response(&app, put_req).await;
assert_eq!(result, Bytes::from_static(b"put!"));
let patch_req = TestRequest::patch()
@ -1066,17 +1066,17 @@ mod tests {
.insert_header((header::CONTENT_TYPE, "application/json"))
.to_request();
let result = read_response(&mut app, patch_req).await;
let result = read_response(&app, patch_req).await;
assert_eq!(result, Bytes::from_static(b"patch!"));
let delete_req = TestRequest::delete().uri("/index.html").to_request();
let result = read_response(&mut app, delete_req).await;
let result = read_response(&app, delete_req).await;
assert_eq!(result, Bytes::from_static(b"delete!"));
}
#[actix_rt::test]
async fn test_response() {
let mut app = init_service(
let app = init_service(
App::new().service(
web::resource("/index.html")
.route(web::post().to(|| HttpResponse::Ok().body("welcome!"))),
@ -1089,13 +1089,13 @@ mod tests {
.insert_header((header::CONTENT_TYPE, "application/json"))
.to_request();
let result = read_response(&mut app, req).await;
let result = read_response(&app, req).await;
assert_eq!(result, Bytes::from_static(b"welcome!"));
}
#[actix_rt::test]
async fn test_send_request() {
let mut app = init_service(
let app = init_service(
App::new().service(
web::resource("/index.html")
.route(web::get().to(|| HttpResponse::Ok().body("welcome!"))),
@ -1105,7 +1105,7 @@ mod tests {
let resp = TestRequest::get()
.uri("/index.html")
.send_request(&mut app)
.send_request(&app)
.await;
let result = read_body(resp).await;
@ -1120,7 +1120,7 @@ mod tests {
#[actix_rt::test]
async fn test_response_json() {
let mut app = init_service(App::new().service(web::resource("/people").route(
let app = init_service(App::new().service(web::resource("/people").route(
web::post().to(|person: web::Json<Person>| HttpResponse::Ok().json(person)),
)))
.await;
@ -1133,13 +1133,13 @@ mod tests {
.set_payload(payload)
.to_request();
let result: Person = read_response_json(&mut app, req).await;
let result: Person = read_response_json(&app, req).await;
assert_eq!(&result.id, "12345");
}
#[actix_rt::test]
async fn test_body_json() {
let mut app = init_service(App::new().service(web::resource("/people").route(
let app = init_service(App::new().service(web::resource("/people").route(
web::post().to(|person: web::Json<Person>| HttpResponse::Ok().json(person)),
)))
.await;
@ -1150,7 +1150,7 @@ mod tests {
.uri("/people")
.insert_header((header::CONTENT_TYPE, "application/json"))
.set_payload(payload)
.send_request(&mut app)
.send_request(&app)
.await;
let result: Person = read_body_json(resp).await;
@ -1159,7 +1159,7 @@ mod tests {
#[actix_rt::test]
async fn test_request_response_form() {
let mut app = init_service(App::new().service(web::resource("/people").route(
let app = init_service(App::new().service(web::resource("/people").route(
web::post().to(|person: web::Form<Person>| HttpResponse::Ok().json(person)),
)))
.await;
@ -1176,14 +1176,14 @@ mod tests {
assert_eq!(req.content_type(), "application/x-www-form-urlencoded");
let result: Person = read_response_json(&mut app, req).await;
let result: Person = read_response_json(&app, req).await;
assert_eq!(&result.id, "12345");
assert_eq!(&result.name, "User name");
}
#[actix_rt::test]
async fn test_request_response_json() {
let mut app = init_service(App::new().service(web::resource("/people").route(
let app = init_service(App::new().service(web::resource("/people").route(
web::post().to(|person: web::Json<Person>| HttpResponse::Ok().json(person)),
)))
.await;
@ -1200,7 +1200,7 @@ mod tests {
assert_eq!(req.content_type(), "application/json");
let result: Person = read_response_json(&mut app, req).await;
let result: Person = read_response_json(&app, req).await;
assert_eq!(&result.id, "12345");
assert_eq!(&result.name, "User name");
}
@ -1218,7 +1218,7 @@ mod tests {
}
}
let mut app = init_service(
let app = init_service(
App::new().service(web::resource("/index.html").to(async_with_block)),
)
.await;
@ -1235,7 +1235,7 @@ mod tests {
HttpResponse::Ok()
}
let mut app = init_service(
let app = init_service(
App::new()
.data(10usize)
.service(web::resource("/index.html").to(handler)),
@ -1291,7 +1291,7 @@ mod tests {
.data(addr.clone())
.service(web::resource("/").to(actor_handler));
let mut app = init_service(srv).await;
let app = init_service(srv).await;
let req = TestRequest::post().uri("/").to_request();
let res = app.call(req).await.unwrap();

View File

@ -392,7 +392,7 @@ mod tests {
"payload is probably json string"
}
let mut srv = init_service(
let srv = init_service(
App::new()
.service(
web::resource("/bytes-app-data")
@ -422,43 +422,43 @@ mod tests {
.await;
let req = TestRequest::with_uri("/bytes-app-data").to_request();
let resp = call_service(&mut srv, req).await;
let resp = call_service(&srv, req).await;
assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
let req = TestRequest::with_uri("/bytes-data").to_request();
let resp = call_service(&mut srv, req).await;
let resp = call_service(&srv, req).await;
assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
let req = TestRequest::with_uri("/string-app-data").to_request();
let resp = call_service(&mut srv, req).await;
let resp = call_service(&srv, req).await;
assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
let req = TestRequest::with_uri("/string-data").to_request();
let resp = call_service(&mut srv, req).await;
let resp = call_service(&srv, req).await;
assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
let req = TestRequest::with_uri("/bytes-app-data")
.insert_header(header::ContentType(mime::APPLICATION_JSON))
.to_request();
let resp = call_service(&mut srv, req).await;
let resp = call_service(&srv, req).await;
assert_eq!(resp.status(), StatusCode::OK);
let req = TestRequest::with_uri("/bytes-data")
.insert_header(header::ContentType(mime::APPLICATION_JSON))
.to_request();
let resp = call_service(&mut srv, req).await;
let resp = call_service(&srv, req).await;
assert_eq!(resp.status(), StatusCode::OK);
let req = TestRequest::with_uri("/string-app-data")
.insert_header(header::ContentType(mime::APPLICATION_JSON))
.to_request();
let resp = call_service(&mut srv, req).await;
let resp = call_service(&srv, req).await;
assert_eq!(resp.status(), StatusCode::OK);
let req = TestRequest::with_uri("/string-data")
.insert_header(header::ContentType(mime::APPLICATION_JSON))
.to_request();
let resp = call_service(&mut srv, req).await;
let resp = call_service(&srv, req).await;
assert_eq!(resp.status(), StatusCode::OK);
}

View File

@ -13,7 +13,7 @@ async fn test_start() {
let (tx, rx) = mpsc::channel();
thread::spawn(move || {
let sys = actix_rt::System::new("test");
let sys = actix_rt::System::new();
sys.block_on(async {
let srv = HttpServer::new(|| {
@ -91,7 +91,7 @@ async fn test_start_ssl() {
let (tx, rx) = mpsc::channel();
thread::spawn(move || {
let sys = actix_rt::System::new("test");
let sys = actix_rt::System::new();
let builder = ssl_acceptor().unwrap();
let srv = HttpServer::new(|| {