mirror of
https://gitee.com/an-tao/drogon.git
synced 2024-12-03 12:18:11 +08:00
Add additional HttpStatusCodes and implement a custom error handler (#439)
This adds: Various lesser-used HTTP status codes to the HttpStatusCode enumeration. Getter and setter for customErrorHandler, which is a function that generates a HttpResponsePtr given an HttpStatusCode. This is intended to be similar to the custom404 functionality, allowing a user to override the layout of the error page. The custom404 functions were kept even though this supersedes that to avoid breaking current code. Finally, all of the Routers were updated to use the error handler for their 405/403 responses. If no custom error handler is set, a default is used. The default behavior is identical to what exists now, an empty body with the status code set.
This commit is contained in:
parent
4423d836f4
commit
c754d65cf0
@ -124,6 +124,23 @@ class HttpAppFramework : public trantor::NonCopyable
|
||||
virtual HttpAppFramework &setCustom404Page(const HttpResponsePtr &resp,
|
||||
bool set404 = true) = 0;
|
||||
|
||||
/// Set custom error handler
|
||||
/**
|
||||
* @param resp_generator is invoked when an error in the framework needs to
|
||||
* be sent to the client to provide a custom layout.
|
||||
*/
|
||||
virtual HttpAppFramework &setCustomErrorHandler(
|
||||
std::function<HttpResponsePtr(HttpStatusCode)> &&resp_generator) = 0;
|
||||
|
||||
/// Get custom error handler
|
||||
/**
|
||||
* @return A const-reference to the error handler set using
|
||||
* setCustomErrorHandler. If none was provided, the default error handler is
|
||||
* returned.
|
||||
*/
|
||||
virtual const std::function<HttpResponsePtr(HttpStatusCode)>
|
||||
&getCustomErrorHandler() const = 0;
|
||||
|
||||
/// Get the plugin object registered in the framework
|
||||
/**
|
||||
* @note
|
||||
|
@ -37,6 +37,7 @@ enum HttpStatusCode
|
||||
k304NotModified = 304,
|
||||
k305UseProxy = 305,
|
||||
k307TemporaryRedirect = 307,
|
||||
k308PermanentRedirect = 308,
|
||||
k400BadRequest = 400,
|
||||
k401Unauthorized = 401,
|
||||
k402PaymentRequired = 402,
|
||||
@ -53,14 +54,22 @@ enum HttpStatusCode
|
||||
k413RequestEntityTooLarge = 413,
|
||||
k414RequestURITooLarge = 414,
|
||||
k415UnsupportedMediaType = 415,
|
||||
k416Requestedrangenotsatisfiable = 416,
|
||||
k416RequestedRangeNotSatisfiable = 416,
|
||||
k417ExpectationFailed = 417,
|
||||
k421MisdirectedRequest = 421,
|
||||
k425TooEarly = 425,
|
||||
k426UpgradeRequired = 426,
|
||||
k428PreconditionRequired = 428,
|
||||
k429TooManyRequests = 429,
|
||||
k431RequestHeaderFieldsTooLarge = 431,
|
||||
k451UnavailableForLegalReasons = 451,
|
||||
k500InternalServerError = 500,
|
||||
k501NotImplemented = 501,
|
||||
k502BadGateway = 502,
|
||||
k503ServiceUnavailable = 503,
|
||||
k504GatewayTimeout = 504,
|
||||
k505HTTPVersionnotsupported = 505,
|
||||
k505HTTPVersionNotSupported = 505,
|
||||
k510NotExtended = 510,
|
||||
};
|
||||
|
||||
enum class Version
|
||||
|
@ -109,6 +109,10 @@ std::string getGitCommit()
|
||||
{
|
||||
return DROGON_VERSION_SHA1;
|
||||
}
|
||||
HttpResponsePtr defaultErrorHandler(HttpStatusCode code)
|
||||
{
|
||||
return std::make_shared<HttpResponseImpl>(code, CT_TEXT_HTML);
|
||||
}
|
||||
} // namespace drogon
|
||||
static void godaemon(void)
|
||||
{
|
||||
@ -947,4 +951,17 @@ HttpAppFramework &HttpAppFrameworkImpl::addALocation(
|
||||
bool HttpAppFrameworkImpl::areAllDbClientsAvailable() const noexcept
|
||||
{
|
||||
return dbClientManagerPtr_->areAllDbClientsAvailable();
|
||||
}
|
||||
}
|
||||
|
||||
HttpAppFramework &HttpAppFrameworkImpl::setCustomErrorHandler(
|
||||
std::function<HttpResponsePtr(HttpStatusCode)> &&resp_generator)
|
||||
{
|
||||
customErrorHandler_ = std::move(resp_generator);
|
||||
return *this;
|
||||
}
|
||||
|
||||
const std::function<HttpResponsePtr(HttpStatusCode)>
|
||||
&HttpAppFrameworkImpl::getCustomErrorHandler() const
|
||||
{
|
||||
return customErrorHandler_;
|
||||
}
|
||||
|
@ -27,6 +27,8 @@
|
||||
|
||||
namespace drogon
|
||||
{
|
||||
HttpResponsePtr defaultErrorHandler(HttpStatusCode code);
|
||||
|
||||
struct InitBeforeMainFunction
|
||||
{
|
||||
explicit InitBeforeMainFunction(const std::function<void()> &func)
|
||||
@ -34,6 +36,7 @@ struct InitBeforeMainFunction
|
||||
func();
|
||||
}
|
||||
};
|
||||
|
||||
class HttpAppFrameworkImpl : public HttpAppFramework
|
||||
{
|
||||
public:
|
||||
@ -81,6 +84,10 @@ class HttpAppFrameworkImpl : public HttpAppFramework
|
||||
return *this;
|
||||
}
|
||||
|
||||
HttpAppFramework &setCustomErrorHandler(
|
||||
std::function<HttpResponsePtr(HttpStatusCode)> &&resp_generator)
|
||||
override;
|
||||
|
||||
const HttpResponsePtr &getCustom404Page();
|
||||
|
||||
virtual void forward(
|
||||
@ -433,6 +440,8 @@ class HttpAppFrameworkImpl : public HttpAppFramework
|
||||
}
|
||||
|
||||
virtual bool areAllDbClientsAvailable() const noexcept override;
|
||||
const std::function<HttpResponsePtr(HttpStatusCode)>
|
||||
&getCustomErrorHandler() const override;
|
||||
|
||||
private:
|
||||
virtual void registerHttpController(
|
||||
@ -516,6 +525,8 @@ class HttpAppFrameworkImpl : public HttpAppFramework
|
||||
std::unique_ptr<SessionManager> sessionManagerPtr_;
|
||||
Json::Value jsonConfig_;
|
||||
HttpResponsePtr custom404_;
|
||||
std::function<HttpResponsePtr(HttpStatusCode)> customErrorHandler_ =
|
||||
&defaultErrorHandler;
|
||||
static InitBeforeMainFunction initFirst_;
|
||||
bool enableServerHeader_{true};
|
||||
bool enableDateHeader_{true};
|
||||
|
@ -427,16 +427,15 @@ void HttpControllersRouter::route(
|
||||
if (!binder)
|
||||
{
|
||||
// Invalid Http Method
|
||||
auto res = drogon::HttpResponse::newHttpResponse();
|
||||
if (req->method() != Options)
|
||||
{
|
||||
res->setStatusCode(k405MethodNotAllowed);
|
||||
callback(
|
||||
app().getCustomErrorHandler()(k405MethodNotAllowed));
|
||||
}
|
||||
else
|
||||
{
|
||||
res->setStatusCode(k403Forbidden);
|
||||
callback(app().getCustomErrorHandler()(k403Forbidden));
|
||||
}
|
||||
callback(res);
|
||||
return;
|
||||
}
|
||||
if (!postRoutingObservers_.empty())
|
||||
|
@ -105,16 +105,14 @@ void HttpSimpleControllersRouter::route(
|
||||
if (!binder)
|
||||
{
|
||||
// Invalid Http Method
|
||||
auto res = drogon::HttpResponse::newHttpResponse();
|
||||
if (req->method() != Options)
|
||||
{
|
||||
res->setStatusCode(k405MethodNotAllowed);
|
||||
callback(app().getCustomErrorHandler()(k405MethodNotAllowed));
|
||||
}
|
||||
else
|
||||
{
|
||||
res->setStatusCode(k403Forbidden);
|
||||
callback(app().getCustomErrorHandler()(k403Forbidden));
|
||||
}
|
||||
callback(res);
|
||||
return;
|
||||
}
|
||||
// Do post routing advices.
|
||||
|
@ -241,6 +241,11 @@ const string_view &statusCodeToString(int code)
|
||||
static string_view sv = "Temporary Redirect";
|
||||
return sv;
|
||||
}
|
||||
case 308:
|
||||
{
|
||||
static string_view sv = "Permanent Redirect";
|
||||
return sv;
|
||||
}
|
||||
case 400:
|
||||
{
|
||||
static string_view sv = "Bad Request";
|
||||
@ -323,7 +328,7 @@ const string_view &statusCodeToString(int code)
|
||||
}
|
||||
case 416:
|
||||
{
|
||||
static string_view sv = "Requested range not satisfiable";
|
||||
static string_view sv = "Requested Range Not Satisfiable";
|
||||
return sv;
|
||||
}
|
||||
case 417:
|
||||
@ -331,6 +336,41 @@ const string_view &statusCodeToString(int code)
|
||||
static string_view sv = "Expectation Failed";
|
||||
return sv;
|
||||
}
|
||||
case 421:
|
||||
{
|
||||
static string_view sv = "Misdirected Request";
|
||||
return sv;
|
||||
}
|
||||
case 425:
|
||||
{
|
||||
static string_view sv = "Too Early";
|
||||
return sv;
|
||||
}
|
||||
case 426:
|
||||
{
|
||||
static string_view sv = "Upgrade Required";
|
||||
return sv;
|
||||
}
|
||||
case 428:
|
||||
{
|
||||
static string_view sv = "Precondition Required";
|
||||
return sv;
|
||||
}
|
||||
case 429:
|
||||
{
|
||||
static string_view sv = "Too Many Requests";
|
||||
return sv;
|
||||
}
|
||||
case 431:
|
||||
{
|
||||
static string_view sv = "Request Header Fields Too Large";
|
||||
return sv;
|
||||
}
|
||||
case 451:
|
||||
{
|
||||
static string_view sv = "Unavailable For Legal Reasons";
|
||||
return sv;
|
||||
}
|
||||
case 500:
|
||||
{
|
||||
static string_view sv = "Internal Server Error";
|
||||
@ -358,7 +398,12 @@ const string_view &statusCodeToString(int code)
|
||||
}
|
||||
case 505:
|
||||
{
|
||||
static string_view sv = "HTTP Version not supported";
|
||||
static string_view sv = "HTTP Version Not Supported";
|
||||
return sv;
|
||||
}
|
||||
case 510:
|
||||
{
|
||||
static string_view sv = "Not Extended";
|
||||
return sv;
|
||||
}
|
||||
default:
|
||||
|
@ -61,9 +61,7 @@ void StaticFileRouter::route(
|
||||
if (path.find("/../") != std::string::npos)
|
||||
{
|
||||
// Downloading files from the parent folder is forbidden.
|
||||
auto resp = HttpResponse::newHttpResponse();
|
||||
resp->setStatusCode(k403Forbidden);
|
||||
callback(resp);
|
||||
callback(app().getCustomErrorHandler()(k403Forbidden));
|
||||
return;
|
||||
}
|
||||
auto lPath = path;
|
||||
@ -114,9 +112,7 @@ void StaticFileRouter::route(
|
||||
auto pos = restOfThePath.rfind('/');
|
||||
if (pos != 0 && pos != string_view::npos && !location.isRecursive_)
|
||||
{
|
||||
auto resp = HttpResponse::newHttpResponse();
|
||||
resp->setStatusCode(k403Forbidden);
|
||||
callback(resp);
|
||||
callback(app().getCustomErrorHandler()(k403Forbidden));
|
||||
return;
|
||||
}
|
||||
if (!location.allowAll_)
|
||||
@ -124,9 +120,7 @@ void StaticFileRouter::route(
|
||||
pos = restOfThePath.rfind('.');
|
||||
if (pos == string_view::npos)
|
||||
{
|
||||
auto resp = HttpResponse::newHttpResponse();
|
||||
resp->setStatusCode(k403Forbidden);
|
||||
callback(resp);
|
||||
callback(app().getCustomErrorHandler()(k403Forbidden));
|
||||
return;
|
||||
}
|
||||
std::string extension{restOfThePath.data() + pos + 1,
|
||||
@ -137,9 +131,7 @@ void StaticFileRouter::route(
|
||||
tolower);
|
||||
if (fileTypeSet_.find(extension) == fileTypeSet_.end())
|
||||
{
|
||||
auto resp = HttpResponse::newHttpResponse();
|
||||
resp->setStatusCode(k403Forbidden);
|
||||
callback(resp);
|
||||
callback(app().getCustomErrorHandler()(k403Forbidden));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -110,16 +110,15 @@ void WebsocketControllersRouter::route(
|
||||
if (!binder)
|
||||
{
|
||||
// Invalid Http Method
|
||||
auto res = drogon::HttpResponse::newHttpResponse();
|
||||
if (req->method() != Options)
|
||||
{
|
||||
res->setStatusCode(k405MethodNotAllowed);
|
||||
callback(
|
||||
app().getCustomErrorHandler()(k405MethodNotAllowed));
|
||||
}
|
||||
else
|
||||
{
|
||||
res->setStatusCode(k403Forbidden);
|
||||
callback(app().getCustomErrorHandler()(k403Forbidden));
|
||||
}
|
||||
callback(res);
|
||||
return;
|
||||
}
|
||||
// Do post routing advices.
|
||||
|
Loading…
Reference in New Issue
Block a user