Skip to content

Commit

Permalink
Added CrossDomain settings for API Server & modified to apply CORS wi…
Browse files Browse the repository at this point in the history
…thout specifying protocol (#621)
  • Loading branch information
dimiden committed Jan 24, 2022
1 parent ae14b73 commit f82a315
Show file tree
Hide file tree
Showing 13 changed files with 127 additions and 57 deletions.
37 changes: 37 additions & 0 deletions src/projects/api_server/api_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,19 @@ namespace api
return true;
}

// CORS
{
bool is_cors_parsed;
auto cross_domains = api_config.GetCrossDomainList(&is_cors_parsed);

if (is_cors_parsed)
{
// API server doesn't have VHost, so use dummy VHost
auto vhost_app_name = info::VHostAppName::InvalidVHostAppName();

This comment has been minimized.

Copy link
@akash-okobiz

akash-okobiz Aug 27, 2024

wordpress

_cors_manager.SetCrossDomains(vhost_app_name, cross_domains);
}
}

_access_token = api_config.GetAccessToken();

if (_access_token.IsEmpty())
Expand Down Expand Up @@ -270,8 +283,30 @@ namespace api
{
auto http_interceptor = std::make_shared<http::svr::DefaultInterceptor>();

// CORS header processor
http_interceptor->Register(http::Method::All, R"(.+)", [=](const std::shared_ptr<http::svr::HttpConnection> &client) -> http::svr::NextHandler {
auto response = client->GetResponse();
auto request = client->GetRequest();

do
{
// Set default headers
response->SetHeader("Server", "OvenMediaEngine");
response->SetHeader("Content-Type", "text/html");

auto vhost_app_name = info::VHostAppName::InvalidVHostAppName();

_cors_manager.SetupHttpCorsHeader(vhost_app_name, request, response);

return http::svr::NextHandler::Call;
} while (false);

return http::svr::NextHandler::DoNotCall;
});

// Request Handlers will be added to http_interceptor
_root_controller = std::make_shared<RootController>(_access_token);
_root_controller->SetServer(GetSharedPtr());
_root_controller->SetInterceptor(http_interceptor);
_root_controller->PrepareHandlers();

Expand All @@ -291,6 +326,8 @@ namespace api
_is_storage_path_initialized = false;
_storage_path = "";

_root_controller = nullptr;

return http_result && https_result;
}

Expand Down
7 changes: 5 additions & 2 deletions src/projects/api_server/api_server.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,14 @@
#include <base/ovlibrary/ovlibrary.h>
#include <base/ovsocket/ovsocket.h>
#include <config/config.h>
#include <modules/http/cors/cors_manager.h>
#include <modules/http/server/http_server_manager.h>

#include "controllers/root_controller.h"

namespace api
{
class Server : public ov::Singleton<Server>
class Server : public ov::EnableSharedFromThis<Server>
{
public:
bool Start(const std::shared_ptr<const cfg::Server> &server_config);
Expand Down Expand Up @@ -49,5 +50,7 @@ namespace api

bool _is_storage_path_initialized = false;
ov::String _storage_path;

http::CorsManager _cors_manager;
};
} // namespace api
} // namespace api
10 changes: 10 additions & 0 deletions src/projects/api_server/controllers/controller.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@

namespace api
{
class Server;

class ApiResponse
{
public:
Expand Down Expand Up @@ -79,6 +81,11 @@ namespace api
class Controller
{
public:
void SetServer(const std::shared_ptr<Server> &server)
{
_server = server;
}

void SetPrefix(const ov::String &prefix)
{
_prefix = prefix;
Expand All @@ -94,6 +101,7 @@ namespace api
{
auto instance = std::make_shared<Tcontroller>();

instance->SetServer(_server);
instance->SetPrefix(_prefix + prefix_of_sub_controller);
instance->SetInterceptor(_interceptor);

Expand Down Expand Up @@ -314,5 +322,7 @@ namespace api
// For all Handler registrations, prefix before pattern
ov::String _prefix;
std::shared_ptr<http::svr::DefaultInterceptor> _interceptor;

std::shared_ptr<Server> _server;
};
} // namespace api
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,9 @@ namespace api
ApiResponse VHostsController::OnDeleteVhost(const std::shared_ptr<http::svr::HttpConnection> &client,
const std::shared_ptr<mon::HostMetrics> &vhost)
{
auto api_server = Server::GetInstance();

try
{
api_server->DeleteVHost(*(vhost.get()));
_server->DeleteVHost(*(vhost.get()));
}
catch (std::shared_ptr<cfg::ConfigError> &error)
{
Expand Down
14 changes: 10 additions & 4 deletions src/projects/config/config_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ namespace cfg
{
// Modify if supported xml version is added or changed

// Current OME compatible with v8 & v9
_supported_versions_map["Server"] = {8, 9};
// Current OME compatible with v8 & v9 & v10
_supported_versions_map["Server"] = {8, 9, 10};
_supported_versions_map["Logger"] = {2};
}

Expand Down Expand Up @@ -325,8 +325,8 @@ namespace cfg
ov::String description;

description.Format(
"The version of %s.xml is outdated (Your XML version: %d, Latest version: %d).\n",
name.CStr(), version, supported_versions);
"The version of %s.xml is outdated (Your XML version: %d).\n",
name.CStr(), version);

description.AppendFormat(
"If you have upgraded OME, see misc/conf_examples/%s.xml\n",
Expand All @@ -350,6 +350,12 @@ namespace cfg
description.AppendFormat(" - Added <Server>.<Bind>.<Managers>.<API>.<Storage> to store configs created using API\n");
}

if (version <= 9)
{
description.AppendFormat("Major Changes (v9 -> v10):\n");
description.AppendFormat(" - Added <Server>.<Bind>.<Managers>.<API>.<CrossDomains>\n");
}

throw CreateConfigError("%s", description.CStr());
}
}
Expand Down
5 changes: 4 additions & 1 deletion src/projects/config/items/managers/api/api.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
//==============================================================================
#pragma once

#include "../../common/cross_domain_support.h"
#include "storage/storage.h"

namespace cfg
Expand All @@ -16,7 +17,7 @@ namespace cfg
{
namespace api
{
struct API : public Item
struct API : public Item, public cmn::CrossDomainSupport
{
protected:
ov::String _access_token;
Expand All @@ -34,6 +35,8 @@ namespace cfg
Register("AccessToken", &_access_token);

Register<Optional>("Storage", &_storage);

Register<Optional>({"CrossDomains", OmitRule::Omit}, &_cross_domains);
}
};
} // namespace api
Expand Down
2 changes: 1 addition & 1 deletion src/projects/main/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ int main(int argc, char *argv[])
INIT_MODULE(rtspc_provider, "RTSPC Provider", pvd::RtspcProvider::Create(*server_config, media_router));
// PENDING : INIT_MODULE(rtsp_provider, "RTSP Provider", pvd::RtspProvider::Create(*server_config, media_router));

auto api_server = api::Server::GetInstance();
auto api_server = std::make_shared<api::Server>();

if (succeeded)
{
Expand Down
56 changes: 30 additions & 26 deletions src/projects/modules/http/cors/cors_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,19 @@

#include "../http_private.h"

static constexpr char CORS_HTTP_PREFIX[] = "http://";
static constexpr auto CORS_HTTP_PREFIX_LENGTH = OV_COUNTOF(CORS_HTTP_PREFIX) - 1;
static constexpr char CORS_HTTPS_PREFIX[] = "https://";
static constexpr auto CORS_HTTPS_PREFIX_LENGTH = OV_COUNTOF(CORS_HTTPS_PREFIX) - 1;

namespace http
{
void CorsManager::SetCrossDomains(const info::VHostAppName &vhost_app_name, const std::vector<ov::String> &url_list)
{
std::lock_guard lock_guard(_cors_mutex);

auto &cors_policy = _cors_policy_map[vhost_app_name];
auto &cors_regex_list = _cors_regex_list_map[vhost_app_name];
auto &cors_regex_list = _cors_item_list_map[vhost_app_name];
ov::String cors_rtmp;

auto cors_domains_for_rtmp = std::vector<ov::String>();
Expand All @@ -33,17 +38,12 @@ namespace http

cors_policy = CorsPolicy::Origin;

constexpr char HTTP_PREFIX[] = "http://";
constexpr auto HTTP_PREFIX_LENGTH = OV_COUNTOF(HTTP_PREFIX) - 1;
constexpr char HTTPS_PREFIX[] = "https://";
constexpr auto HTTPS_PREFIX_LENGTH = OV_COUNTOF(HTTPS_PREFIX) - 1;

for (auto url : url_list)
{
if (url == "*")
{
cors_regex_list.clear();
cors_regex_list.push_back(ov::Regex::CompiledRegex(ov::Regex::WildCardRegex("*")));
cors_regex_list.emplace_back(false, ov::Regex::CompiledRegex(ov::Regex::WildCardRegex("*")));
cors_policy = CorsPolicy::All;

if (url_list.size() > 1)
Expand All @@ -68,16 +68,9 @@ namespace http
continue;
}

cors_regex_list.push_back(ov::Regex::CompiledRegex(ov::Regex::WildCardRegex(url)));
bool has_protocol = url.HasPrefix(CORS_HTTP_PREFIX) || url.HasPrefix(CORS_HTTPS_PREFIX);

if (url.HasPrefix(HTTP_PREFIX))
{
url = url.Substring(HTTP_PREFIX_LENGTH);
}
else if (url.HasPrefix(HTTPS_PREFIX))
{
url = url.Substring(HTTPS_PREFIX_LENGTH);
}
cors_regex_list.emplace_back(has_protocol, ov::Regex::CompiledRegex(ov::Regex::WildCardRegex(url)));

cors_domains_for_rtmp.push_back(url);
}
Expand Down Expand Up @@ -147,11 +140,11 @@ namespace http
std::lock_guard lock_guard(_cors_mutex);

auto cors_policy_iterator = _cors_policy_map.find(vhost_app_name);
auto cors_regex_list_iterator = _cors_regex_list_map.find(vhost_app_name);
auto cors_regex_list_iterator = _cors_item_list_map.find(vhost_app_name);

if (
(cors_policy_iterator == _cors_policy_map.end()) ||
(cors_regex_list_iterator == _cors_regex_list_map.end()))
(cors_regex_list_iterator == _cors_item_list_map.end()))
{
// This happens in the following situations:
//
Expand All @@ -177,14 +170,25 @@ namespace http
break;

case CorsPolicy::Origin: {
const auto &cors_regex_list = cors_regex_list_iterator->second;
auto item = std::find_if(cors_regex_list.begin(), cors_regex_list.end(),
[&origin_header](auto &cors_regex) -> bool {
ov::MatchResult match_result = cors_regex.Matches(origin_header);
return match_result.IsMatched();
});

if (item == cors_regex_list.end())
const auto &cors_item_list = cors_regex_list_iterator->second;
auto origin_header_without_protocol = origin_header;

if (origin_header.HasPrefix(CORS_HTTP_PREFIX))
{
origin_header_without_protocol = origin_header.Substring(CORS_HTTP_PREFIX_LENGTH);
}
else if (origin_header.HasPrefix(CORS_HTTPS_PREFIX))
{
origin_header_without_protocol = origin_header.Substring(CORS_HTTPS_PREFIX_LENGTH);
}

auto item = std::find_if(
cors_item_list.begin(), cors_item_list.end(),
[&origin_header, &origin_header_without_protocol](auto &cors_item) -> bool {
return cors_item.regex.Matches(cors_item.has_protocol ? origin_header : origin_header_without_protocol).IsMatched();
});

if (item == cors_item_list.end())
{
// Could not find the domain
return false;
Expand Down
14 changes: 13 additions & 1 deletion src/projects/modules/http/cors/cors_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,26 @@ namespace http
Origin
};

struct CorsItem
{
CorsItem(bool has_protocol, const ov::Regex &regex)
: has_protocol(has_protocol),
regex(regex)
{
}

bool has_protocol;
ov::Regex regex;
};

protected:
mutable std::mutex _cors_mutex;

std::unordered_map<info::VHostAppName, CorsPolicy> _cors_policy_map;

// CORS for HTTP
// key: VHostAppName, value: regex
std::unordered_map<info::VHostAppName, std::vector<ov::Regex>> _cors_regex_list_map;
std::unordered_map<info::VHostAppName, std::vector<CorsItem>> _cors_item_list_map;

// CORS for RTMP
//
Expand Down
9 changes: 3 additions & 6 deletions src/projects/publishers/segment/cmaf/cmaf_publisher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,15 +71,12 @@ std::shared_ptr<pub::Application> CmafPublisher::OnCreatePublisherApplication(co
if (stream_server != nullptr)
{
bool is_parsed;
auto cross_domains = lldash_publisher_config.GetCrossDomainList(&is_parsed);
const auto &cross_domains = lldash_publisher_config.GetCrossDomainList(&is_parsed);

if (is_parsed == false)
if (is_parsed)
{
OV_ASSERT2(cross_domains.empty());
cross_domains.push_back("*");
stream_server->SetCrossDomains(name, cross_domains);
}

stream_server->SetCrossDomains(name, cross_domains);
}
}

Expand Down
9 changes: 3 additions & 6 deletions src/projects/publishers/segment/dash/dash_publisher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,15 +70,12 @@ std::shared_ptr<pub::Application> DashPublisher::OnCreatePublisherApplication(co
if (stream_server != nullptr)
{
bool is_parsed;
auto cross_domains = dash_publisher_config.GetCrossDomainList(&is_parsed);
const auto &cross_domains = dash_publisher_config.GetCrossDomainList(&is_parsed);

if (is_parsed == false)
if (is_parsed)
{
OV_ASSERT2(cross_domains.empty());
cross_domains.push_back("*");
stream_server->SetCrossDomains(name, cross_domains);
}

stream_server->SetCrossDomains(name, cross_domains);
}
}

Expand Down
9 changes: 3 additions & 6 deletions src/projects/publishers/segment/hls/hls_publisher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,15 +72,12 @@ std::shared_ptr<pub::Application> HlsPublisher::OnCreatePublisherApplication(con
if (stream_server != nullptr)
{
bool is_parsed;
auto cross_domains = hls_publisher_config.GetCrossDomainList(&is_parsed);
const auto &cross_domains = hls_publisher_config.GetCrossDomainList(&is_parsed);

if (is_parsed == false)
if (is_parsed)
{
OV_ASSERT2(cross_domains.empty());
cross_domains.push_back("*");
stream_server->SetCrossDomains(name, cross_domains);
}

stream_server->SetCrossDomains(name, cross_domains);
}
}

Expand Down
Loading

0 comments on commit f82a315

Please sign in to comment.