Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Host Redirector plugin #1796

Open
wants to merge 22 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,7 @@ set(DROGON_SOURCES
lib/src/Redirector.cc
lib/src/SessionManager.cc
lib/src/SlashRemover.cc
lib/src/HostRedirector.cc
lib/src/SlidingWindowRateLimiter.cc
lib/src/StaticFileRouter.cc
lib/src/TaskTimeoutFlag.cc
Expand Down Expand Up @@ -734,6 +735,7 @@ set(DROGON_PLUGIN_HEADERS
lib/inc/drogon/plugins/RealIpResolver.h
lib/inc/drogon/plugins/Hodor.h
lib/inc/drogon/plugins/SlashRemover.h
lib/inc/drogon/plugins/HostRedirector.h
lib/inc/drogon/plugins/GlobalFilters.h
lib/inc/drogon/plugins/PromExporter.h)

Expand Down
110 changes: 110 additions & 0 deletions lib/inc/drogon/plugins/HostRedirector.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/**
* @file HostRedirector.h
* @author Mis1eader
*
* Copyright 2023, Mis1eader. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
* that can be found in the License file.
*
* Drogon
*
*/

#pragma once

#include "drogon/plugins/Plugin.h"
#include "drogon/utils/FunctionTraits.h"
#include <json/value.h>
#include <cstddef>
#include <memory>
#include <string_view>
#include <unordered_map>
#include <vector>

namespace drogon::plugin
{
/**
* @brief The HostRedirector plugin redirects requests with respect to rules.
* The json configuration is as follows:
*
* @code
{
"name": "drogon::plugin::HostRedirector",
"dependencies": ["drogon::plugin::Redirector"],
"config": {
"rules": {
"www.example.com": [
"10.10.10.1/*",
"example.com/*",
"search.example.com/*",
"ww.example.com/*"
],
"images.example.com": [
"image.example.com/*",
"www.example.com/images",
"www.example.com/image"
],
"www.example.com/maps": [
"www.example.com/map/*",
"map.example.com",
"maps.example.com"
],
"/": [
"/home/*"
]
}
}
}
@endcode
*
* Enable the plugin by adding the configuration to the list of plugins in the
* configuration file.
* */
class DROGON_EXPORT HostRedirector
: public drogon::Plugin<HostRedirector>,
public std::enable_shared_from_this<HostRedirector>
{
private:
struct RedirectLocation
{
std::string host, path;
};

struct RedirectFrom
{
std::string host, path;
bool isWildcard = false;
size_t toIdx;
};

struct RedirectGroup
{
std::unordered_map<std::string_view, RedirectGroup *> groups;
size_t maxPathLen = std::string_view::npos;
RedirectLocation *to = nullptr, *wildcard = nullptr;
};

public:
HostRedirector()
{
}

void initAndStart(const Json::Value &config) override;
void shutdown() override;

private:
bool redirectingAdvice(const drogon::HttpRequestPtr &,
std::string &,
bool &) const;

void lookup(std::string &host, std::string &path) const;

void recursiveDelete(const RedirectGroup *group);

bool doHostLookup_{false};
std::unordered_map<std::string_view, RedirectGroup> rulesFrom_;
std::vector<RedirectLocation> rulesTo_;
std::vector<RedirectFrom> rulesFromData_;
};
} // namespace drogon::plugin
91 changes: 58 additions & 33 deletions lib/inc/drogon/plugins/Redirector.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,34 +22,48 @@ namespace drogon
namespace plugin
{
/**
* @brief The RedirectorHandler is a function object that can be registered to
* the Redirector plugin. It is used to redirect requests to proper URLs. Users
* can modify the protocol, host and path of the request. If a false value is
* returned, the request will be considered as invalid and a 404 response will
* be sent to the client.
* @brief The PreRedirectorHandler is a function object that can be registered
* to the Redirector plugin. It is used to redirect requests to proper URLs.
* Users can modify the protocol, host and path of the request. If a false value
* is returned, the request will be considered as invalid and a 404 response
* will be sent to the client.
*/
using RedirectorHandler =
using PreRedirectorHandler =
std::function<bool(const drogon::HttpRequestPtr &,
std::string &, //"http://" or "https://"
std::string &, // host
bool &)>; // path changed or not
/**
* @brief The PathRewriteHandler is a function object that can be registered to
* the Redirector plugin. It is used to rewrite the path of the request. The
* Redirector plugin will call all registered PathRewriteHandlers in the order
* of registration. If one or more handlers return true, the request will be
* redirected to the new path.
* @brief The PathRedirectorHandler is a function object that can be registered
* to the Redirector plugin. It is used to rewrite the path of the request. The
* Redirector plugin will call all registered PathRedirectorHandlers in the
* order of registration. If one or more handlers return true, the request will
* be redirected to the new path.
*/
using PathRedirectorHandler =
std::function<bool(const drogon::HttpRequestPtr &)>;

/**
* @brief The PostRedirectorHandler is a function object that can be registered
* to the Redirector plugin. It is used to redirect requests to proper URLs.
* Users can modify the host or path of the request. If a false value is
* returned, the request will be considered as invalid and a 404 response will
* be sent to the client.
*/
using PathRewriteHandler = std::function<bool(const drogon::HttpRequestPtr &)>;
using PostRedirectorHandler =
std::function<bool(const drogon::HttpRequestPtr &,
std::string &, // host
bool &)>; // path changed or not

/**
* @brief The ForwardHandler is a function object that can be registered to the
* Redirector plugin. It is used to forward the request to next processing steps
* in the framework. The Redirector plugin will call all registered
* ForwardHandlers in the order of registration. Users can use this handler to
* change the request path or any other part of the request.
* @brief The PathForwarderHandler is a function object that can be registered
* to the Redirector plugin. It is used to forward the request to next
* processing steps in the framework. The Redirector plugin will call all
* registered PathForwarderHandlers in the order of registration. Users can use
* this handler to change the request path or any other part of the request.
*/
using ForwardHandler = std::function<void(const drogon::HttpRequestPtr &)>;
using PathForwarderHandler =
std::function<void(const drogon::HttpRequestPtr &)>;

/**
* @brief This plugin is used to redirect requests to proper URLs. It is a
Expand Down Expand Up @@ -79,40 +93,51 @@ class DROGON_EXPORT Redirector : public drogon::Plugin<Redirector>,
void initAndStart(const Json::Value &config) override;
void shutdown() override;

void registerRedirectHandler(RedirectorHandler &&handler)
void registerPreRedirectorHandler(PreRedirectorHandler &&handler)
{
preRedirectorHandlers_.emplace_back(std::move(handler));
}

void registerPreRedirectorHandler(const PreRedirectorHandler &handler)
{
preRedirectorHandlers_.emplace_back(handler);
}

void registerPathRedirectorHandler(PathRedirectorHandler &&handler)
{
handlers_.emplace_back(std::move(handler));
pathRedirectorHandlers_.emplace_back(std::move(handler));
}

void registerRedirectHandler(const RedirectorHandler &handler)
void registerPathRedirectorHandler(const PathRedirectorHandler &handler)
{
handlers_.emplace_back(handler);
pathRedirectorHandlers_.emplace_back(handler);
}

void registerPathRewriteHandler(PathRewriteHandler &&handler)
void registerPostRedirectorHandler(PostRedirectorHandler &&handler)
{
pathRewriteHandlers_.emplace_back(std::move(handler));
postRedirectorHandlers_.emplace_back(std::move(handler));
}

void registerPathRewriteHandler(const PathRewriteHandler &handler)
void registerPostRedirectorHandler(const PostRedirectorHandler &handler)
{
pathRewriteHandlers_.emplace_back(handler);
postRedirectorHandlers_.emplace_back(handler);
}

void registerForwardHandler(ForwardHandler &&handler)
void registerPathForwarderHandler(PathForwarderHandler &&handler)
{
forwardHandlers_.emplace_back(std::move(handler));
pathForwarderHandlers_.emplace_back(std::move(handler));
}

void registerForwardHandler(const ForwardHandler &handler)
void registerPathForwarderHandler(const PathForwarderHandler &handler)
{
forwardHandlers_.emplace_back(handler);
pathForwarderHandlers_.emplace_back(handler);
}

private:
std::vector<RedirectorHandler> handlers_;
std::vector<PathRewriteHandler> pathRewriteHandlers_;
std::vector<ForwardHandler> forwardHandlers_;
std::vector<PreRedirectorHandler> preRedirectorHandlers_;
std::vector<PathRedirectorHandler> pathRedirectorHandlers_;
std::vector<PostRedirectorHandler> postRedirectorHandlers_;
std::vector<PathForwarderHandler> pathForwarderHandlers_;
};

} // namespace plugin
Expand Down
Loading
Loading