Add the GlobalFilters plugin (#1555)

This commit is contained in:
An Tao 2023-04-16 11:55:00 +08:00 committed by GitHub
parent d133b21804
commit c7912f246b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 192 additions and 15 deletions

View File

@ -287,6 +287,7 @@ set(DROGON_SOURCES
lib/src/PluginsManager.cc lib/src/PluginsManager.cc
lib/src/RangeParser.cc lib/src/RangeParser.cc
lib/src/SecureSSLRedirector.cc lib/src/SecureSSLRedirector.cc
lib/src/GlobalFilters.cc
lib/src/AccessLogger.cc lib/src/AccessLogger.cc
lib/src/RealIpResolver.cc lib/src/RealIpResolver.cc
lib/src/SessionManager.cc lib/src/SessionManager.cc
@ -729,7 +730,9 @@ set(DROGON_PLUGIN_HEADERS
lib/inc/drogon/plugins/SecureSSLRedirector.h lib/inc/drogon/plugins/SecureSSLRedirector.h
lib/inc/drogon/plugins/AccessLogger.h lib/inc/drogon/plugins/AccessLogger.h
lib/inc/drogon/plugins/RealIpResolver.h lib/inc/drogon/plugins/RealIpResolver.h
lib/inc/drogon/plugins/Hodor.h) lib/inc/drogon/plugins/Hodor.h
lib/inc/drogon/plugins/GlobalFilters.h)
install(FILES ${DROGON_PLUGIN_HEADERS} install(FILES ${DROGON_PLUGIN_HEADERS}
DESTINATION ${INSTALL_INCLUDE_DIR}/drogon/plugins) DESTINATION ${INSTALL_INCLUDE_DIR}/drogon/plugins)

View File

@ -0,0 +1,51 @@
#pragma once
#include <drogon/plugins/Plugin.h>
#include <regex>
#include <vector>
#include <memory>
#include <drogon/HttpFilter.h>
namespace drogon
{
namespace plugin
{
/**
* @brif This plugin is used to add global filters to all HTTP requests.
* The json configuration is as follows:
*
* @code
{
"name": "drogon::plugin::GlobalFilters",
"dependencies": [],
"config": {
// filters: the list of global filter names.
"filters": [
"FilterName1", "FilterName2",...
],
// exempt: exempt must be a string or string array, regular
expressions for
// URLs that don't have to be filtered.
"exempt": [
"^/static/.*\\.css", "^/images/.*",...
]
}
}
@endcode
*
*/
class GlobalFilters : public drogon::Plugin<GlobalFilters>,
public std::enable_shared_from_this<GlobalFilters>
{
public:
GlobalFilters() = default;
void initAndStart(const Json::Value &config) override;
void shutdown() override;
private:
std::vector<std::shared_ptr<drogon::HttpFilterBase>> filters_;
std::regex exemptPegex_;
bool regexFlag_{false};
};
} // namespace plugin
} // namespace drogon

View File

@ -9,6 +9,7 @@
#include <drogon/drogon_callbacks.h> #include <drogon/drogon_callbacks.h>
#include <drogon/plugins/Plugin.h> #include <drogon/plugins/Plugin.h>
#include <regex> #include <regex>
#include <memory>
namespace drogon namespace drogon
{ {
@ -32,8 +33,12 @@ namespace plugin
} }
@endcode @endcode
* *
* ssl_redirect_exempt: a regular expression (for matching the path of a * ssl_redirect_exempt: must be a string or a string array, present a regular
* request) list for URLs that don't have to be redirected. expression
* (for matching the path of a request) or a regular expression list for URLs
that don't
* have to be redirected.
*
* secure_ssl_host: If this string is not empty, all SSL redirects * secure_ssl_host: If this string is not empty, all SSL redirects
* will be directed to this host rather than the originally-requested host. * will be directed to this host rather than the originally-requested host.
* *
@ -42,7 +47,8 @@ namespace plugin
* *
*/ */
class DROGON_EXPORT SecureSSLRedirector class DROGON_EXPORT SecureSSLRedirector
: public drogon::Plugin<SecureSSLRedirector> : public drogon::Plugin<SecureSSLRedirector>,
public std::enable_shared_from_this<SecureSSLRedirector>
{ {
public: public:
SecureSSLRedirector() SecureSSLRedirector()

99
lib/src/GlobalFilters.cc Normal file
View File

@ -0,0 +1,99 @@
#include <drogon/plugins/GlobalFilters.h>
#include <drogon/DrClassMap.h>
#include <drogon/HttpAppFramework.h>
#include "FiltersFunction.h"
#include "HttpRequestImpl.h"
using namespace drogon::plugin;
void GlobalFilters::initAndStart(const Json::Value &config)
{
if (config.isMember("filters") && config["filters"].isArray())
{
auto &filters = config["filters"];
for (auto const &filter : filters)
{
if (filter.isString())
{
auto filterPtr = std::dynamic_pointer_cast<HttpFilterBase>(
drogon::DrClassMap::getSingleInstance(filter.asString()));
if (filterPtr)
{
filters_.push_back(filterPtr);
}
else
{
LOG_ERROR << "Filter " << filter.asString()
<< " not found!";
}
}
}
}
if (config.isMember("exempt"))
{
auto exempt = config["exempt"];
if (exempt.isArray())
{
std::string regexStr;
for (auto const &ex : exempt)
{
if (ex.isString())
{
regexStr.append("(").append(exempt.asString()).append(")|");
}
else
{
LOG_ERROR << "exempt must be a string array!";
}
}
if (!regexStr.empty())
{
regexStr.pop_back();
exemptPegex_ = std::regex(regexStr);
regexFlag_ = true;
}
}
else if (exempt.isString())
{
exemptPegex_ = std::regex(exempt.asString());
regexFlag_ = true;
}
else
{
LOG_ERROR << "exempt must be a string or string array!";
}
}
std::weak_ptr<GlobalFilters> weakPtr = shared_from_this();
drogon::app().registerPreRoutingAdvice(
[weakPtr](const drogon::HttpRequestPtr &req,
drogon::AdviceCallback &&acb,
drogon::AdviceChainCallback &&accb) {
auto thisPtr = weakPtr.lock();
if (!thisPtr)
{
accb();
return;
}
if (thisPtr->regexFlag_)
{
if (std::regex_match(req->path(), thisPtr->exemptPegex_))
{
accb();
return;
}
}
auto callbackPtr =
std::make_shared<std::function<void(const HttpResponsePtr &)>>(
std::move(acb));
drogon::filters_function::doFilters(
thisPtr->filters_,
std::static_pointer_cast<HttpRequestImpl>(req),
callbackPtr,
std::move(accb));
});
}
void GlobalFilters::shutdown()
{
filters_.clear();
}

View File

@ -12,8 +12,9 @@ using namespace drogon::plugin;
void SecureSSLRedirector::initAndStart(const Json::Value &config) void SecureSSLRedirector::initAndStart(const Json::Value &config)
{ {
if (config.isMember("ssl_redirect_exempt") && if (config.isMember("ssl_redirect_exempt"))
config["ssl_redirect_exempt"].isArray()) {
if (config["ssl_redirect_exempt"].isArray())
{ {
std::string regexString; std::string regexString;
for (auto &exempt : config["ssl_redirect_exempt"]) for (auto &exempt : config["ssl_redirect_exempt"])
@ -28,9 +29,26 @@ void SecureSSLRedirector::initAndStart(const Json::Value &config)
regexFlag_ = true; regexFlag_ = true;
} }
} }
else if (config["ssl_redirect_exempt"].isString())
{
exemptPegex_ = std::regex(config["ssl_redirect_exempt"].asString());
regexFlag_ = true;
}
else
{
LOG_ERROR
<< "ssl_redirect_exempt must be a string or string array!";
}
}
secureHost_ = config.get("secure_ssl_host", "").asString(); secureHost_ = config.get("secure_ssl_host", "").asString();
app().registerSyncAdvice([this](const HttpRequestPtr &req) { std::weak_ptr<SecureSSLRedirector> weakPtr = shared_from_this();
return this->redirectingAdvice(req); app().registerSyncAdvice([weakPtr](const HttpRequestPtr &req) {
auto thisPtr = weakPtr.lock();
if (!thisPtr)
{
return HttpResponsePtr{};
}
return thisPtr->redirectingAdvice(req);
}); });
} }