mirror of
https://github.com/CrowCpp/Crow.git
synced 2024-06-07 21:10:44 +00:00
Add configurable exception handler (#637)
* Added exception_handler() * Fixed worker crash if exception thrown in catch-all handler
This commit is contained in:
parent
c95e33ac0a
commit
049490c2c9
@ -252,6 +252,24 @@ namespace crow
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Set the function to call to handle uncaught exceptions generated in routes (Default generates error 500).
|
||||
|
||||
///
|
||||
/// The function must have the following signature: void(crow::response&).
|
||||
/// It must set the response passed in argument to the function, which will be sent back to the client.
|
||||
/// See Router::default_exception_handler() for the default implementation.
|
||||
template<typename Func>
|
||||
self_t& exception_handler(Func&& f)
|
||||
{
|
||||
router_.exception_handler() = std::forward<Func>(f);
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::function<void(crow::response&)>& exception_handler()
|
||||
{
|
||||
return router_.exception_handler();
|
||||
}
|
||||
|
||||
/// Set a custom duration and function to run on every tick
|
||||
template<typename Duration, typename Func>
|
||||
self_t& tick(Duration d, Func f)
|
||||
|
@ -1461,22 +1461,13 @@ namespace crow
|
||||
|
||||
CROW_LOG_DEBUG << "Matched rule (upgrade) '" << rules[rule_index]->rule_ << "' " << static_cast<uint32_t>(req.method) << " / " << rules[rule_index]->get_methods();
|
||||
|
||||
// any uncaught exceptions become 500s
|
||||
try
|
||||
{
|
||||
rules[rule_index]->handle_upgrade(req, res, std::move(adaptor));
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
CROW_LOG_ERROR << "An uncaught exception occurred: " << e.what();
|
||||
res = response(500);
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
CROW_LOG_ERROR << "An uncaught exception occurred. The type was unknown so no information was available.";
|
||||
res = response(500);
|
||||
exception_handler_(res);
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
@ -1534,7 +1525,14 @@ namespace crow
|
||||
std::vector<uint16_t> bpi = found.blueprint_indices;
|
||||
if (bps_found[i]->catchall_rule().has_handler())
|
||||
{
|
||||
bps_found[i]->catchall_rule().handler_(req, res);
|
||||
try
|
||||
{
|
||||
bps_found[i]->catchall_rule().handler_(req, res);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
exception_handler_(res);
|
||||
}
|
||||
#ifdef CROW_ENABLE_DEBUG
|
||||
return std::string("Redirected to Blueprint \"" + bps_found[i]->prefix() + "\" Catchall rule");
|
||||
#else
|
||||
@ -1544,7 +1542,14 @@ namespace crow
|
||||
}
|
||||
if (catchall_rule_.has_handler())
|
||||
{
|
||||
catchall_rule_.handler_(req, res);
|
||||
try
|
||||
{
|
||||
catchall_rule_.handler_(req, res);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
exception_handler_(res);
|
||||
}
|
||||
#ifdef CROW_ENABLE_DEBUG
|
||||
return std::string("Redirected to global Catchall rule");
|
||||
#else
|
||||
@ -1704,23 +1709,14 @@ namespace crow
|
||||
|
||||
CROW_LOG_DEBUG << "Matched rule '" << rules[rule_index]->rule_ << "' " << static_cast<uint32_t>(req.method) << " / " << rules[rule_index]->get_methods();
|
||||
|
||||
// any uncaught exceptions become 500s
|
||||
try
|
||||
{
|
||||
auto& rule = rules[rule_index];
|
||||
handle_rule<App>(rule, req, res, found.r_params);
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
CROW_LOG_ERROR << "An uncaught exception occurred: " << e.what();
|
||||
res = response(500);
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
CROW_LOG_ERROR << "An uncaught exception occurred. The type was unknown so no information was available.";
|
||||
res = response(500);
|
||||
exception_handler_(res);
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
@ -1787,6 +1783,30 @@ namespace crow
|
||||
return blueprints_;
|
||||
}
|
||||
|
||||
std::function<void(crow::response&)>& exception_handler()
|
||||
{
|
||||
return exception_handler_;
|
||||
}
|
||||
|
||||
static void default_exception_handler(response& res)
|
||||
{
|
||||
// any uncaught exceptions become 500s
|
||||
res = response(500);
|
||||
|
||||
try
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
CROW_LOG_ERROR << "An uncaught exception occurred: " << e.what();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
CROW_LOG_ERROR << "An uncaught exception occurred. The type was unknown so no information was available.";
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
CatchallRule catchall_rule_;
|
||||
|
||||
@ -1802,5 +1822,6 @@ namespace crow
|
||||
std::array<PerMethod, static_cast<int>(HTTPMethod::InternalMethodCount)> per_methods_;
|
||||
std::vector<std::unique_ptr<BaseRule>> all_rules_;
|
||||
std::vector<Blueprint*> blueprints_;
|
||||
std::function<void(crow::response&)> exception_handler_ = &default_exception_handler;
|
||||
};
|
||||
} // namespace crow
|
||||
|
@ -3261,6 +3261,79 @@ TEST_CASE("blueprint")
|
||||
}
|
||||
} // blueprint
|
||||
|
||||
TEST_CASE("exception_handler")
|
||||
{
|
||||
SimpleApp app;
|
||||
|
||||
CROW_ROUTE(app, "/get_error")
|
||||
([&]() -> std::string {
|
||||
throw std::runtime_error("some error occurred");
|
||||
});
|
||||
|
||||
CROW_ROUTE(app, "/get_no_error")
|
||||
([&]() {
|
||||
return "Hello world";
|
||||
});
|
||||
|
||||
app.validate();
|
||||
|
||||
{
|
||||
request req;
|
||||
response res;
|
||||
|
||||
req.url = "/get_error";
|
||||
app.handle_full(req, res);
|
||||
|
||||
CHECK(500 == res.code);
|
||||
CHECK(res.body.empty());
|
||||
}
|
||||
|
||||
{
|
||||
request req;
|
||||
response res;
|
||||
|
||||
req.url = "/get_no_error";
|
||||
app.handle_full(req, res);
|
||||
|
||||
CHECK(200 == res.code);
|
||||
CHECK(res.body.find("Hello world") != std::string::npos);
|
||||
}
|
||||
|
||||
app.exception_handler([](crow::response& res) {
|
||||
try
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
res = response(501, e.what());
|
||||
}
|
||||
});
|
||||
|
||||
{
|
||||
request req;
|
||||
response res;
|
||||
|
||||
req.url = "/get_error";
|
||||
app.handle_full(req, res);
|
||||
|
||||
CHECK(501 == res.code);
|
||||
CHECK(res.body.find("some error occurred") != std::string::npos);
|
||||
}
|
||||
|
||||
{
|
||||
request req;
|
||||
response res;
|
||||
|
||||
req.url = "/get_no_error";
|
||||
app.handle_full(req, res);
|
||||
|
||||
CHECK(200 == res.code);
|
||||
CHECK(res.body.find("some error occurred") == std::string::npos);
|
||||
CHECK(res.body.find("Hello world") != std::string::npos);
|
||||
}
|
||||
} // exception_handler
|
||||
|
||||
TEST_CASE("base64")
|
||||
{
|
||||
unsigned char sample_bin[] = {0x14, 0xfb, 0x9c, 0x03, 0xd9, 0x7e};
|
||||
|
Loading…
Reference in New Issue
Block a user