use std::panic::{catch_unwind, AssertUnwindSafe, UnwindSafe};
use futures_util::future::FutureExt;
use hyper::{Body, Response, StatusCode};
use log::error;
use crate::handler::{Handler, HandlerError, IntoResponse, NewHandler};
use crate::state::{request_id, State};
async fn handle<H>(
handler: H,
state: AssertUnwindSafe<State>,
) -> Result<(State, Response<Body>), (State, HandlerError)>
where
H: Handler,
{
let AssertUnwindSafe(state) = state;
handler.handle(state).await
}
pub async fn call_handler<T>(t: T, state: AssertUnwindSafe<State>) -> anyhow::Result<Response<Body>>
where
T: NewHandler + Send + UnwindSafe,
{
match catch_unwind(move || t.new_handler()) {
Ok(handler) => {
let unwind_result = AssertUnwindSafe(handle(handler?, state))
.catch_unwind()
.await;
let result = match unwind_result {
Ok(result) => result.map(|(_, res)| res),
Err(_) => Ok(finalize_panic_response()),
};
Ok(match result {
Ok(res) => res,
Err((state, err)) => finalize_error_response(state, err),
})
}
Err(_) => Ok(finalize_panic_response()),
}
}
fn finalize_error_response(state: State, err: HandlerError) -> Response<Body> {
error!("[ERROR][{}][Error: {:?}]", request_id(&state), err);
err.into_response(&state)
}
fn finalize_panic_response() -> Response<Body> {
error!("[PANIC][A panic occurred while invoking the handler]");
Response::builder()
.status(StatusCode::INTERNAL_SERVER_ERROR)
.body(Body::default())
.unwrap()
}
#[cfg(test)]
mod tests {
use super::*;
use futures_util::future;
use hyper::{HeaderMap, Method, StatusCode};
use std::io;
use std::pin::Pin;
use crate::handler::HandlerFuture;
use crate::helpers::http::response::create_empty_response;
use crate::state::set_request_id;
#[test]
fn success() {
let new_handler = || {
Ok(|state| {
let res = create_empty_response(&state, StatusCode::ACCEPTED);
(state, res)
})
};
let mut state = State::new();
state.put(HeaderMap::new());
state.put(Method::GET);
set_request_id(&mut state);
let r = call_handler(&new_handler, AssertUnwindSafe(state));
let response = futures_executor::block_on(r).unwrap();
assert_eq!(response.status(), StatusCode::ACCEPTED);
}
#[test]
fn async_success_repeat_poll() {
let new_handler = || {
Ok(|state| {
let f = future::lazy(move |_| {
let res = create_empty_response(&state, StatusCode::ACCEPTED);
Ok((state, res))
});
let f = f.map(|v| v);
let f = f.map(|v| v);
let f = f.map(|v| v);
f.boxed()
})
};
let mut state = State::new();
state.put(HeaderMap::new());
state.put(Method::GET);
set_request_id(&mut state);
let r = call_handler(&new_handler, AssertUnwindSafe(state));
let response = futures_executor::block_on(r).unwrap();
assert_eq!(response.status(), StatusCode::ACCEPTED);
}
#[test]
fn error() {
let new_handler =
|| Ok(|state| future::err((state, io::Error::last_os_error().into())).boxed());
let mut state = State::new();
state.put(HeaderMap::new());
state.put(Method::GET);
set_request_id(&mut state);
let r = call_handler(&new_handler, AssertUnwindSafe(state));
let response = futures_executor::block_on(r).unwrap();
assert_eq!(response.status(), StatusCode::INTERNAL_SERVER_ERROR);
}
#[test]
fn panic() {
#[allow(clippy::unnecessary_literal_unwrap)] let new_handler = || {
Ok(|_| {
let val: Option<Pin<Box<HandlerFuture>>> = None;
val.expect("test panic")
})
};
let mut state = State::new();
state.put(HeaderMap::new());
state.put(Method::GET);
set_request_id(&mut state);
let r = call_handler(&new_handler, AssertUnwindSafe(state));
let response = futures_executor::block_on(r).unwrap();
assert_eq!(response.status(), StatusCode::INTERNAL_SERVER_ERROR);
}
#[test]
fn async_panic() {
let new_handler = || Ok(|_| future::lazy(move |_| panic!("test panic")).boxed());
let mut state = State::new();
state.put(HeaderMap::new());
state.put(Method::GET);
set_request_id(&mut state);
let r = call_handler(&new_handler, AssertUnwindSafe(state));
let response = futures_executor::block_on(r).unwrap();
assert_eq!(response.status(), StatusCode::INTERNAL_SERVER_ERROR);
}
#[test]
fn async_panic_repeat_poll() {
let new_handler = || {
Ok(|_| {
let f = future::lazy(move |_| panic!("test panic"));
let f = f.map(|v| v);
let f = f.map(|v| v);
let f = f.map(|v| v);
f.boxed()
})
};
let mut state = State::new();
state.put(HeaderMap::new());
state.put(Method::GET);
set_request_id(&mut state);
let r = call_handler(&new_handler, AssertUnwindSafe(state));
let response = futures_executor::block_on(r).unwrap();
assert_eq!(response.status(), StatusCode::INTERNAL_SERVER_ERROR);
}
#[test]
fn new_handler_panic() {
struct PanicNewHandler;
impl NewHandler for PanicNewHandler {
type Instance = Self;
fn new_handler(&self) -> anyhow::Result<Self::Instance> {
panic!("Pannicked creating a new handler");
}
}
impl Handler for PanicNewHandler {
fn handle(self, _state: State) -> Pin<Box<HandlerFuture>> {
unreachable!();
}
}
let mut state = State::new();
state.put(HeaderMap::new());
state.put(Method::GET);
set_request_id(&mut state);
let new_handler = PanicNewHandler {};
let r = call_handler(new_handler, AssertUnwindSafe(state));
let response = futures_executor::block_on(r).unwrap();
assert_eq!(response.status(), StatusCode::INTERNAL_SERVER_ERROR);
}
}