Recover on panic from handler

This commit is contained in:
Mohd Tarmizi 2016-06-19 15:24:48 +08:00
parent e2e7fb4a02
commit 096cc4a7c6
1 changed files with 14 additions and 7 deletions

View File

@ -44,6 +44,7 @@ use std::collections::{HashMap, HashSet};
use std::io::{self, Read, Write, Cursor, BufRead}; use std::io::{self, Read, Write, Cursor, BufRead};
use std::mem; use std::mem;
use std::net::TcpListener; use std::net::TcpListener;
use std::panic::{AssertUnwindSafe, RefUnwindSafe, catch_unwind};
use std::rc::Rc; use std::rc::Rc;
#[cfg(unix)] use unix::{Transport, Socket}; #[cfg(unix)] use unix::{Transport, Socket};
@ -561,7 +562,8 @@ impl Drop for Request {
} }
} }
fn run_transport<F>(mut handler: F, transport: &mut Transport) where F: FnMut(Request) { fn run_transport<F>(handler: F, transport: &mut Transport) where
F: Fn(Request) + RefUnwindSafe {
let addrs: Option<HashSet<String>> = match std::env::var("FCGI_WEB_SERVER_ADDRS") { let addrs: Option<HashSet<String>> = match std::env::var("FCGI_WEB_SERVER_ADDRS") {
Ok(value) => Some(value.split(',').map(|s| s.to_owned()).collect()), Ok(value) => Some(value.split(',').map(|s| s.to_owned()).collect()),
Err(std::env::VarError::NotPresent) => None, Err(std::env::VarError::NotPresent) => None,
@ -580,10 +582,12 @@ fn run_transport<F>(mut handler: F, transport: &mut Transport) where F: FnMut(Re
None => true, None => true,
}; };
if allow { if allow {
let sock = Rc::new(sock); let sock = AssertUnwindSafe(Rc::new(sock));
loop { loop {
let (request_id, role, keep_conn) = Request::begin(&sock).unwrap(); let (request_id, role, keep_conn) = Request::begin(&sock).unwrap();
handler(Request::new(sock.clone(), request_id, role).unwrap()); catch_unwind(|| {
handler(Request::new(sock.clone(), request_id, role).unwrap());
}).unwrap_or(());
if !keep_conn { break; } if !keep_conn { break; }
} }
} }
@ -594,7 +598,7 @@ fn run_transport<F>(mut handler: F, transport: &mut Transport) where F: FnMut(Re
/// Runs as a FastCGI process with the given handler. /// Runs as a FastCGI process with the given handler.
/// ///
/// Available under Unix only. If you are using Windows, use `run_tcp` instead. /// Available under Unix only. If you are using Windows, use `run_tcp` instead.
pub fn run<F>(handler: F) where F: FnMut(Request) { pub fn run<F>(handler: F) where F: Fn(Request) + RefUnwindSafe {
run_transport(handler, &mut Transport::new()) run_transport(handler, &mut Transport::new())
} }
@ -603,19 +607,22 @@ pub fn run<F>(handler: F) where F: FnMut(Request) {
/// Unix domain sockets are supported. /// Unix domain sockets are supported.
/// ///
/// Available under Unix only. /// Available under Unix only.
pub fn run_raw<F>(handler: F, raw_fd: std::os::unix::io::RawFd) where F: FnMut(Request) { pub fn run_raw<F>(handler: F, raw_fd: std::os::unix::io::RawFd) where
F: Fn(Request) + RefUnwindSafe {
run_transport(handler, &mut Transport::from_raw_fd(raw_fd)) run_transport(handler, &mut Transport::from_raw_fd(raw_fd))
} }
#[cfg(unix)] #[cfg(unix)]
/// Accepts requests from a user-supplied TCP listener. /// Accepts requests from a user-supplied TCP listener.
pub fn run_tcp<F>(handler: F, listener: &TcpListener) where F: FnMut(Request) { pub fn run_tcp<F>(handler: F, listener: &TcpListener) where
F: Fn(Request) + RefUnwindSafe {
use std::os::unix::io::AsRawFd; use std::os::unix::io::AsRawFd;
run_transport(handler, &mut Transport::from_raw_fd(listener.as_raw_fd())) run_transport(handler, &mut Transport::from_raw_fd(listener.as_raw_fd()))
} }
#[cfg(windows)] #[cfg(windows)]
/// Accepts requests from a user-supplied TCP listener. /// Accepts requests from a user-supplied TCP listener.
pub fn run_tcp<F>(handler: F, listener: &TcpListener) where F: FnMut(Request) { pub fn run_tcp<F>(handler: F, listener: &TcpListener) where
F: Fn(Request) + RefUnwindSafe {
run_transport(handler, &mut Transport::from_tcp(&listener)) run_transport(handler, &mut Transport::from_tcp(&listener))
} }