diff --git a/src/pipeline.rs b/src/pipeline.rs index 14b050931..1b621882f 100644 --- a/src/pipeline.rs +++ b/src/pipeline.rs @@ -722,8 +722,11 @@ impl FinishingMiddlewares { return None; } self.fut = None; - info.count -= 1; + if info.count == 0 { + return Some(Completed::init(info)); + } + info.count -= 1; match info.mws[info.count as usize].finish(info.req_mut(), &self.resp) { Finished::Done => { if info.count == 0 { diff --git a/src/route.rs b/src/route.rs index 2558fa687..1623702d4 100644 --- a/src/route.rs +++ b/src/route.rs @@ -555,8 +555,11 @@ impl FinishingMiddlewares { return None; } self.fut = None; - info.count -= 1; + if info.count == 0 { + return Some(Response::init(self.resp.take().unwrap())); + } + info.count -= 1; match info.mws[info.count as usize] .finish(&mut info.req, self.resp.as_ref().unwrap()) { diff --git a/src/scope.rs b/src/scope.rs index bab2ac944..fedc7ceda 100644 --- a/src/scope.rs +++ b/src/scope.rs @@ -661,8 +661,11 @@ impl FinishingMiddlewares { return None; } self.fut = None; - info.count -= 1; + if info.count == 0 { + return Some(Response::init(self.resp.take().unwrap())); + } + info.count -= 1; match info.mws[info.count as usize] .finish(&mut info.req, self.resp.as_ref().unwrap()) { diff --git a/tests/test_middleware.rs b/tests/test_middleware.rs new file mode 100644 index 000000000..189b85332 --- /dev/null +++ b/tests/test_middleware.rs @@ -0,0 +1,375 @@ +extern crate actix; +extern crate actix_web; +extern crate futures; +extern crate tokio_core; + +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::Arc; +use std::thread; +use std::time::Duration; + +use actix::*; +use actix_web::*; +use futures::{future, Future}; +use tokio_core::reactor::Timeout; + +struct MiddlewareTest { + start: Arc, + response: Arc, + finish: Arc, +} + +impl middleware::Middleware for MiddlewareTest { + fn start(&self, _: &mut HttpRequest) -> Result { + self.start.store( + self.start.load(Ordering::Relaxed) + 1, + Ordering::Relaxed, + ); + Ok(middleware::Started::Done) + } + + fn response( + &self, _: &mut HttpRequest, resp: HttpResponse, + ) -> Result { + self.response.store( + self.response.load(Ordering::Relaxed) + 1, + Ordering::Relaxed, + ); + Ok(middleware::Response::Done(resp)) + } + + fn finish(&self, _: &mut HttpRequest, _: &HttpResponse) -> middleware::Finished { + self.finish.store( + self.finish.load(Ordering::Relaxed) + 1, + Ordering::Relaxed, + ); + middleware::Finished::Done + } +} + +#[test] +fn test_middleware() { + let num1 = Arc::new(AtomicUsize::new(0)); + let num2 = Arc::new(AtomicUsize::new(0)); + let num3 = Arc::new(AtomicUsize::new(0)); + + let act_num1 = Arc::clone(&num1); + let act_num2 = Arc::clone(&num2); + let act_num3 = Arc::clone(&num3); + + let mut srv = test::TestServer::new(move |app| { + app.middleware(MiddlewareTest { + start: Arc::clone(&act_num1), + response: Arc::clone(&act_num2), + finish: Arc::clone(&act_num3), + }).handler(|_| HttpResponse::Ok()) + }); + + let request = srv.get().finish().unwrap(); + let response = srv.execute(request.send()).unwrap(); + assert!(response.status().is_success()); + + assert_eq!(num1.load(Ordering::Relaxed), 1); + assert_eq!(num2.load(Ordering::Relaxed), 1); + assert_eq!(num3.load(Ordering::Relaxed), 1); +} + +#[test] +fn test_resource_middleware() { + let num1 = Arc::new(AtomicUsize::new(0)); + let num2 = Arc::new(AtomicUsize::new(0)); + let num3 = Arc::new(AtomicUsize::new(0)); + + let act_num1 = Arc::clone(&num1); + let act_num2 = Arc::clone(&num2); + let act_num3 = Arc::clone(&num3); + + let mut srv = test::TestServer::new(move |app| { + app.middleware(MiddlewareTest { + start: Arc::clone(&act_num1), + response: Arc::clone(&act_num2), + finish: Arc::clone(&act_num3), + }).handler(|_| HttpResponse::Ok()) + }); + + let request = srv.get().finish().unwrap(); + let response = srv.execute(request.send()).unwrap(); + assert!(response.status().is_success()); + + assert_eq!(num1.load(Ordering::Relaxed), 1); + assert_eq!(num2.load(Ordering::Relaxed), 1); + assert_eq!(num3.load(Ordering::Relaxed), 1); +} + +#[test] +fn test_scope_middleware() { + let num1 = Arc::new(AtomicUsize::new(0)); + let num2 = Arc::new(AtomicUsize::new(0)); + let num3 = Arc::new(AtomicUsize::new(0)); + + let act_num1 = Arc::clone(&num1); + let act_num2 = Arc::clone(&num2); + let act_num3 = Arc::clone(&num3); + + let mut srv = test::TestServer::with_factory(move || { + App::new().scope("/scope", |scope| { + scope + .middleware(MiddlewareAsyncTest { + start: Arc::clone(&act_num1), + response: Arc::clone(&act_num2), + finish: Arc::clone(&act_num3), + }) + .resource("/test", |r| r.f(|_| HttpResponse::Ok())) + }) + }); + + let request = srv.get() + .uri(srv.url("/scope/test")) + .finish() + .unwrap(); + let response = srv.execute(request.send()).unwrap(); + assert!(response.status().is_success()); + + assert_eq!(num1.load(Ordering::Relaxed), 1); + assert_eq!(num2.load(Ordering::Relaxed), 1); + assert_eq!(num3.load(Ordering::Relaxed), 1); +} + +fn index_test_middleware_async_error(_: HttpRequest) -> FutureResponse { + future::result(Err(error::ErrorBadRequest("TEST"))).responder() +} + +#[test] +fn test_middleware_async_error() { + let req = Arc::new(AtomicUsize::new(0)); + let resp = Arc::new(AtomicUsize::new(0)); + let fin = Arc::new(AtomicUsize::new(0)); + + let act_req = Arc::clone(&req); + let act_resp = Arc::clone(&resp); + let act_fin = Arc::clone(&fin); + + let mut srv = test::TestServer::new(move |app| { + app.middleware(MiddlewareTest { + start: Arc::clone(&act_req), + response: Arc::clone(&act_resp), + finish: Arc::clone(&act_fin), + }).handler(index_test_middleware_async_error) + }); + + let request = srv.get().finish().unwrap(); + let response = srv.execute(request.send()).unwrap(); + assert_eq!(response.status(), http::StatusCode::BAD_REQUEST); + + assert_eq!(req.load(Ordering::Relaxed), 1); + assert_eq!(resp.load(Ordering::Relaxed), 1); + assert_eq!(fin.load(Ordering::Relaxed), 1); +} + +#[test] +fn test_scope_middleware_async_error() { + let req = Arc::new(AtomicUsize::new(0)); + let resp = Arc::new(AtomicUsize::new(0)); + let fin = Arc::new(AtomicUsize::new(0)); + + let act_req = Arc::clone(&req); + let act_resp = Arc::clone(&resp); + let act_fin = Arc::clone(&fin); + + let mut srv = test::TestServer::with_factory(move || { + App::new().scope("/scope", |scope| { + scope + .middleware(MiddlewareAsyncTest { + start: Arc::clone(&act_req), + response: Arc::clone(&act_resp), + finish: Arc::clone(&act_fin), + }) + .resource("/test", |r| r.f(index_test_middleware_async_error)) + }) + }); + + let request = srv.get() + .uri(srv.url("/scope/test")) + .finish() + .unwrap(); + let response = srv.execute(request.send()).unwrap(); + assert_eq!(response.status(), http::StatusCode::BAD_REQUEST); + + assert_eq!(req.load(Ordering::Relaxed), 1); + assert_eq!(resp.load(Ordering::Relaxed), 1); + assert_eq!(fin.load(Ordering::Relaxed), 1); +} + +#[test] +fn test_resource_middleware_async_error() { + let req = Arc::new(AtomicUsize::new(0)); + let resp = Arc::new(AtomicUsize::new(0)); + let fin = Arc::new(AtomicUsize::new(0)); + + let act_req = Arc::clone(&req); + let act_resp = Arc::clone(&resp); + let act_fin = Arc::clone(&fin); + + let mut srv = test::TestServer::with_factory(move || { + let mw = MiddlewareAsyncTest { + start: Arc::clone(&act_req), + response: Arc::clone(&act_resp), + finish: Arc::clone(&act_fin), + }; + + App::new().resource("/test", move |r| { + r.middleware(mw); + r.h(index_test_middleware_async_error); + }) + }); + + let request = srv.get().uri(srv.url("/test")).finish().unwrap(); + let response = srv.execute(request.send()).unwrap(); + assert_eq!(response.status(), http::StatusCode::BAD_REQUEST); + + assert_eq!(req.load(Ordering::Relaxed), 1); + assert_eq!(resp.load(Ordering::Relaxed), 1); + assert_eq!(fin.load(Ordering::Relaxed), 1); +} + +struct MiddlewareAsyncTest { + start: Arc, + response: Arc, + finish: Arc, +} + +impl middleware::Middleware for MiddlewareAsyncTest { + fn start(&self, _: &mut HttpRequest) -> Result { + let to = Timeout::new(Duration::from_millis(10), &Arbiter::handle()).unwrap(); + + let start = Arc::clone(&self.start); + Ok(middleware::Started::Future(Box::new( + to.from_err().and_then(move |_| { + start.fetch_add(1, Ordering::Relaxed); + Ok(None) + }), + ))) + } + + fn response( + &self, _: &mut HttpRequest, resp: HttpResponse, + ) -> Result { + let to = Timeout::new(Duration::from_millis(10), &Arbiter::handle()).unwrap(); + + let response = Arc::clone(&self.response); + Ok(middleware::Response::Future(Box::new( + to.from_err().and_then(move |_| { + response.fetch_add(1, Ordering::Relaxed); + Ok(resp) + }), + ))) + } + + fn finish(&self, _: &mut HttpRequest, _: &HttpResponse) -> middleware::Finished { + let to = Timeout::new(Duration::from_millis(10), &Arbiter::handle()).unwrap(); + + let finish = Arc::clone(&self.finish); + middleware::Finished::Future(Box::new(to.from_err().and_then(move |_| { + finish.fetch_add(1, Ordering::Relaxed); + Ok(()) + }))) + } +} + +#[test] +fn test_async_middleware() { + let num1 = Arc::new(AtomicUsize::new(0)); + let num2 = Arc::new(AtomicUsize::new(0)); + let num3 = Arc::new(AtomicUsize::new(0)); + + let act_num1 = Arc::clone(&num1); + let act_num2 = Arc::clone(&num2); + let act_num3 = Arc::clone(&num3); + + let mut srv = test::TestServer::new(move |app| { + app.middleware(MiddlewareAsyncTest { + start: Arc::clone(&act_num1), + response: Arc::clone(&act_num2), + finish: Arc::clone(&act_num3), + }).handler(|_| HttpResponse::Ok()) + }); + + let request = srv.get().finish().unwrap(); + let response = srv.execute(request.send()).unwrap(); + assert!(response.status().is_success()); + + assert_eq!(num1.load(Ordering::Relaxed), 1); + assert_eq!(num2.load(Ordering::Relaxed), 1); + + thread::sleep(Duration::from_millis(20)); + assert_eq!(num3.load(Ordering::Relaxed), 1); +} + +#[test] +fn test_async_scope_middleware() { + let num1 = Arc::new(AtomicUsize::new(0)); + let num2 = Arc::new(AtomicUsize::new(0)); + let num3 = Arc::new(AtomicUsize::new(0)); + + let act_num1 = Arc::clone(&num1); + let act_num2 = Arc::clone(&num2); + let act_num3 = Arc::clone(&num3); + + let mut srv = test::TestServer::with_factory(move || { + App::new().scope("/scope", |scope| { + scope + .middleware(MiddlewareAsyncTest { + start: Arc::clone(&act_num1), + response: Arc::clone(&act_num2), + finish: Arc::clone(&act_num3), + }) + .resource("/test", |r| r.f(|_| HttpResponse::Ok())) + }) + }); + + let request = srv.get() + .uri(srv.url("/scope/test")) + .finish() + .unwrap(); + let response = srv.execute(request.send()).unwrap(); + assert!(response.status().is_success()); + + assert_eq!(num1.load(Ordering::Relaxed), 1); + assert_eq!(num2.load(Ordering::Relaxed), 1); + + thread::sleep(Duration::from_millis(20)); + assert_eq!(num3.load(Ordering::Relaxed), 1); +} + +#[test] +fn test_async_resource_middleware() { + let num1 = Arc::new(AtomicUsize::new(0)); + let num2 = Arc::new(AtomicUsize::new(0)); + let num3 = Arc::new(AtomicUsize::new(0)); + + let act_num1 = Arc::clone(&num1); + let act_num2 = Arc::clone(&num2); + let act_num3 = Arc::clone(&num3); + + let mut srv = test::TestServer::with_factory(move || { + let mw = MiddlewareAsyncTest { + start: Arc::clone(&act_num1), + response: Arc::clone(&act_num2), + finish: Arc::clone(&act_num3), + }; + App::new().resource("/test", move |r| { + r.middleware(mw); + r.h(|_| HttpResponse::Ok()); + }) + }); + + let request = srv.get().uri(srv.url("/test")).finish().unwrap(); + let response = srv.execute(request.send()).unwrap(); + assert!(response.status().is_success()); + + assert_eq!(num1.load(Ordering::Relaxed), 1); + assert_eq!(num2.load(Ordering::Relaxed), 1); + + thread::sleep(Duration::from_millis(20)); + assert_eq!(num3.load(Ordering::Relaxed), 1); +} diff --git a/tests/test_server.rs b/tests/test_server.rs index 19b6c9195..e61cedd3b 100644 --- a/tests/test_server.rs +++ b/tests/test_server.rs @@ -18,12 +18,11 @@ use flate2::read::GzDecoder; use flate2::write::{DeflateDecoder, DeflateEncoder, GzEncoder}; use flate2::Compression; use futures::stream::once; -use futures::{future, Future, Stream}; +use futures::{Future, Stream}; use h2::client as h2client; use modhttp::Request; use rand::Rng; use std::io::{Read, Write}; -use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::{mpsc, Arc}; use std::{net, thread, time}; use tokio_core::net::TcpStream; @@ -823,122 +822,3 @@ fn test_application() { let response = srv.execute(request.send()).unwrap(); assert!(response.status().is_success()); } - -struct MiddlewareTest { - start: Arc, - response: Arc, - finish: Arc, -} - -impl middleware::Middleware for MiddlewareTest { - fn start(&self, _: &mut HttpRequest) -> Result { - self.start.store( - self.start.load(Ordering::Relaxed) + 1, - Ordering::Relaxed, - ); - Ok(middleware::Started::Done) - } - - fn response( - &self, _: &mut HttpRequest, resp: HttpResponse, - ) -> Result { - self.response.store( - self.response.load(Ordering::Relaxed) + 1, - Ordering::Relaxed, - ); - Ok(middleware::Response::Done(resp)) - } - - fn finish(&self, _: &mut HttpRequest, _: &HttpResponse) -> middleware::Finished { - self.finish.store( - self.finish.load(Ordering::Relaxed) + 1, - Ordering::Relaxed, - ); - middleware::Finished::Done - } -} - -#[test] -fn test_middlewares() { - let num1 = Arc::new(AtomicUsize::new(0)); - let num2 = Arc::new(AtomicUsize::new(0)); - let num3 = Arc::new(AtomicUsize::new(0)); - - let act_num1 = Arc::clone(&num1); - let act_num2 = Arc::clone(&num2); - let act_num3 = Arc::clone(&num3); - - let mut srv = test::TestServer::new(move |app| { - app.middleware(MiddlewareTest { - start: Arc::clone(&act_num1), - response: Arc::clone(&act_num2), - finish: Arc::clone(&act_num3), - }).handler(|_| HttpResponse::Ok()) - }); - - let request = srv.get().finish().unwrap(); - let response = srv.execute(request.send()).unwrap(); - assert!(response.status().is_success()); - - assert_eq!(num1.load(Ordering::Relaxed), 1); - assert_eq!(num2.load(Ordering::Relaxed), 1); - assert_eq!(num3.load(Ordering::Relaxed), 1); -} - -#[test] -fn test_resource_middlewares() { - let num1 = Arc::new(AtomicUsize::new(0)); - let num2 = Arc::new(AtomicUsize::new(0)); - let num3 = Arc::new(AtomicUsize::new(0)); - - let act_num1 = Arc::clone(&num1); - let act_num2 = Arc::clone(&num2); - let act_num3 = Arc::clone(&num3); - - let mut srv = test::TestServer::new(move |app| { - app.middleware(MiddlewareTest { - start: Arc::clone(&act_num1), - response: Arc::clone(&act_num2), - finish: Arc::clone(&act_num3), - }).handler(|_| HttpResponse::Ok()) - }); - - let request = srv.get().finish().unwrap(); - let response = srv.execute(request.send()).unwrap(); - assert!(response.status().is_success()); - - assert_eq!(num1.load(Ordering::Relaxed), 1); - assert_eq!(num2.load(Ordering::Relaxed), 1); - // assert_eq!(num3.load(Ordering::Relaxed), 1); -} - -fn index_test_middleware_async_error(_: HttpRequest) -> FutureResponse { - future::result(Err(error::ErrorBadRequest("TEST"))).responder() -} - -#[test] -fn test_middleware_async_error() { - let req = Arc::new(AtomicUsize::new(0)); - let resp = Arc::new(AtomicUsize::new(0)); - let fin = Arc::new(AtomicUsize::new(0)); - - let act_req = Arc::clone(&req); - let act_resp = Arc::clone(&resp); - let act_fin = Arc::clone(&fin); - - let mut srv = test::TestServer::new(move |app| { - app.middleware(MiddlewareTest { - start: Arc::clone(&act_req), - response: Arc::clone(&act_resp), - finish: Arc::clone(&act_fin), - }).handler(index_test_middleware_async_error) - }); - - let request = srv.get().finish().unwrap(); - let response = srv.execute(request.send()).unwrap(); - assert_eq!(response.status(), http::StatusCode::BAD_REQUEST); - - assert_eq!(req.load(Ordering::Relaxed), 1); - assert_eq!(resp.load(Ordering::Relaxed), 1); - assert_eq!(fin.load(Ordering::Relaxed), 1); -}