Add the GlobalFilters plugin (#1555)
This commit is contained in:
parent
d133b21804
commit
c7912f246b
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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
|
|
@ -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()
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
|
@ -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);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue