2022-02-20 19:42:31 +00:00
|
|
|
#pragma once
|
|
|
|
#include "crow/http_request.h"
|
|
|
|
#include "crow/http_response.h"
|
|
|
|
|
|
|
|
namespace crow
|
|
|
|
{
|
|
|
|
struct CORSHandler;
|
|
|
|
|
|
|
|
// CORSRules is used for tuning cors policies
|
|
|
|
struct CORSRules
|
|
|
|
{
|
|
|
|
friend struct crow::CORSHandler;
|
|
|
|
|
2022-02-22 14:38:51 +00:00
|
|
|
// Set Access-Control-Allow-Origin. Default is "*"
|
2022-02-20 19:42:31 +00:00
|
|
|
CORSRules& origin(const std::string& origin)
|
|
|
|
{
|
|
|
|
origin_ = origin;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set Access-Control-Allow-Methods. Default is "*"
|
|
|
|
CORSRules& methods(crow::HTTPMethod method)
|
|
|
|
{
|
|
|
|
add_list_item(methods_, crow::method_name(method));
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set Access-Control-Allow-Methods. Default is "*"
|
|
|
|
template<typename... Methods>
|
|
|
|
CORSRules& methods(crow::HTTPMethod method, Methods... method_list)
|
|
|
|
{
|
|
|
|
add_list_item(methods_, crow::method_name(method));
|
|
|
|
methods(method_list...);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set Access-Control-Allow-Headers. Default is "*"
|
|
|
|
CORSRules& headers(const std::string& header)
|
|
|
|
{
|
|
|
|
add_list_item(headers_, header);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set Access-Control-Allow-Headers. Default is "*"
|
|
|
|
template<typename... Headers>
|
|
|
|
CORSRules& headers(const std::string& header, Headers... header_list)
|
|
|
|
{
|
|
|
|
add_list_item(headers_, header);
|
|
|
|
headers(header_list...);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set Access-Control-Max-Age. Default is none
|
|
|
|
CORSRules& max_age(int max_age)
|
|
|
|
{
|
|
|
|
max_age_ = std::to_string(max_age);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Enable Access-Control-Allow-Credentials
|
|
|
|
CORSRules& allow_credentials()
|
|
|
|
{
|
|
|
|
allow_credentials_ = true;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2022-02-22 14:38:51 +00:00
|
|
|
// Ignore CORS and don't send any headers
|
2022-02-20 19:42:31 +00:00
|
|
|
void ignore()
|
|
|
|
{
|
|
|
|
ignore_ = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2022-02-22 14:38:51 +00:00
|
|
|
// build comma separated list
|
2022-02-20 19:42:31 +00:00
|
|
|
void add_list_item(std::string& list, const std::string& val)
|
|
|
|
{
|
|
|
|
if (list == "*") list = "";
|
|
|
|
if (list.size() > 0) list += ", ";
|
|
|
|
list += val;
|
|
|
|
}
|
|
|
|
|
2022-02-22 14:38:51 +00:00
|
|
|
// Set header `key` to `value` if it is not set
|
2022-02-20 19:42:31 +00:00
|
|
|
void set_header(const std::string& key, const std::string& value, crow::response& res)
|
|
|
|
{
|
|
|
|
if (value.size() == 0) return;
|
|
|
|
if (!get_header_value(res.headers, key).empty()) return;
|
|
|
|
res.add_header(key, value);
|
|
|
|
}
|
|
|
|
|
2022-02-22 14:38:51 +00:00
|
|
|
// Set response headers
|
2022-02-20 19:42:31 +00:00
|
|
|
void apply(crow::response& res)
|
|
|
|
{
|
|
|
|
if (ignore_) return;
|
|
|
|
set_header("Access-Control-Allow-Origin", origin_, res);
|
|
|
|
set_header("Access-Control-Allow-Methods", methods_, res);
|
|
|
|
set_header("Access-Control-Allow-Headers", headers_, res);
|
|
|
|
set_header("Access-Control-Max-Age", max_age_, res);
|
|
|
|
if (allow_credentials_) set_header("Access-Control-Allow-Credentials", "true", res);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ignore_ = false;
|
2022-02-22 14:38:51 +00:00
|
|
|
// TODO: support multiple origins that are dynamically selected
|
2022-02-20 19:42:31 +00:00
|
|
|
std::string origin_ = "*";
|
|
|
|
std::string methods_ = "*";
|
|
|
|
std::string headers_ = "*";
|
|
|
|
std::string max_age_;
|
|
|
|
bool allow_credentials_ = false;
|
|
|
|
};
|
|
|
|
|
2022-02-22 14:38:51 +00:00
|
|
|
/// CORSHandler is a global middleware for setting CORS headers.
|
|
|
|
///
|
|
|
|
/// By default, it sets Access-Control-Allow-Origin/Methods/Headers to "*".
|
|
|
|
/// The default behaviour can be changed with the `global()` cors rule.
|
|
|
|
/// Additional rules for prexies can be added with `prefix()`.
|
2022-02-20 19:42:31 +00:00
|
|
|
struct CORSHandler
|
|
|
|
{
|
|
|
|
struct context
|
|
|
|
{};
|
|
|
|
|
|
|
|
void before_handle(crow::request& /*req*/, crow::response& /*res*/, context& /*ctx*/)
|
|
|
|
{}
|
|
|
|
|
|
|
|
void after_handle(crow::request& req, crow::response& res, context& /*ctx*/)
|
|
|
|
{
|
|
|
|
auto& rule = find_rule(req.url);
|
|
|
|
rule.apply(res);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Handle CORS on specific prefix path
|
|
|
|
CORSRules& prefix(const std::string& prefix)
|
|
|
|
{
|
|
|
|
rules.emplace_back(prefix, CORSRules{});
|
|
|
|
return rules.back().second;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Global CORS policy
|
|
|
|
CORSRules& global()
|
|
|
|
{
|
|
|
|
return default_;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
CORSRules& find_rule(const std::string& path)
|
|
|
|
{
|
|
|
|
for (auto& rule : rules)
|
|
|
|
{
|
|
|
|
if (path.rfind(rule.first, 0) == 0)
|
|
|
|
{
|
|
|
|
return rule.second;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return default_;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<std::pair<std::string, CORSRules>> rules;
|
|
|
|
CORSRules default_;
|
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace crow
|