From 891e880ad12c7b480d11169b3076a674c09b12c5 Mon Sep 17 00:00:00 2001 From: Eric Frias Date: Fri, 17 Oct 2014 16:18:55 -0400 Subject: [PATCH] When the HTTP server asyncs a handler for a request, keep a future for that async and cancel any running asyncs when the HTTP server destructs --- src/network/http/http_server.cpp | 96 +++++++++++++++++++++++--------- 1 file changed, 70 insertions(+), 26 deletions(-) diff --git a/src/network/http/http_server.cpp b/src/network/http/http_server.cpp index 7ccfe8c..e0dd9b6 100644 --- a/src/network/http/http_server.cpp +++ b/src/network/http/http_server.cpp @@ -48,42 +48,86 @@ namespace fc { namespace http { { public: impl(){} - impl(const fc::ip::endpoint& p ) { + + impl(const fc::ip::endpoint& p ) + { tcp_serv.set_reuse_address(); tcp_serv.listen(p); accept_complete = fc::async([this](){ this->accept_loop(); }, "http_server accept_loop"); } - fc::future accept_complete; - ~impl() { - try { + + ~impl() + { + try + { tcp_serv.close(); - if( accept_complete.valid() ) - accept_complete.wait(); - }catch(...){} + if (accept_complete.valid()) + accept_complete.wait(); + } + catch (...) + { + } + + for (fc::future& request_in_progress : requests_in_progress) + { + try + { + request_in_progress.cancel_and_wait(); + } + catch (const fc::exception& e) + { + wlog("Caught exception while canceling http request task: ${error}", ("error", e)); + } + catch (const std::exception& e) + { + wlog("Caught exception while canceling http request task: ${error}", ("error", e.what())); + } + catch (...) + { + wlog("Caught unknown exception while canceling http request task"); + } + } + requests_in_progress.clear(); } - void accept_loop() { - while( !accept_complete.canceled() ) - { - http::connection_ptr con = std::make_shared(); - tcp_serv.accept( con->get_socket() ); - //ilog( "Accept Connection" ); - fc::async( [=](){ handle_connection( con, on_req ); }, "http_server handle_connection" ); - } + + void accept_loop() + { + while( !accept_complete.canceled() ) + { + http::connection_ptr con = std::make_shared(); + tcp_serv.accept( con->get_socket() ); + //ilog( "Accept Connection" ); + // clean up futures for any completed requests + for (auto iter = requests_in_progress.begin(); iter != requests_in_progress.end();) + if (!iter->valid() || iter->ready()) + iter = requests_in_progress.erase(iter); + else + ++iter; + requests_in_progress.emplace_back(fc::async([=](){ handle_connection(con, on_req); }, "http_server handle_connection")); + } } void handle_connection( const http::connection_ptr& c, - std::function do_on_req ) { - try { - http::server::response rep( fc::shared_ptr( new response::impl(c) ) ); - auto req = c->read_request(); - if( do_on_req ) do_on_req( req, rep ); - c->get_socket().close(); - } catch ( fc::exception& e ) { - wlog( "unable to read request ${1}", ("1", e.to_detail_string() ) );//fc::except_str().c_str()); - } - //wlog( "done handle connection" ); + std::function do_on_req ) + { + try + { + http::server::response rep( fc::shared_ptr( new response::impl(c) ) ); + request req = c->read_request(); + if( do_on_req ) + do_on_req( req, rep ); + c->get_socket().close(); + } + catch ( fc::exception& e ) + { + wlog( "unable to read request ${1}", ("1", e.to_detail_string() ) );//fc::except_str().c_str()); + } + //wlog( "done handle connection" ); } - std::function on_req; + + fc::future accept_complete; + std::function on_req; + std::vector > requests_in_progress; fc::tcp_server tcp_serv; };