add config options for testing the Origin header in cors requests
- allow_all_cors_origins - whether or not to allow all origins - allowed_cors_origins - a list of allowed origins (used if allow_all_cors_origins is false)
This commit is contained in:
parent
778ed01a55
commit
a19158cb62
|
@ -350,6 +350,9 @@ void Config::AssignValues()
|
|||
add_header_cache_no_store_in_htmx_request = Bool(L"add_header_cache_no_store_in_htmx_request", true);
|
||||
|
||||
request_queue_job_limit = Size(L"request_queue_job_limit", 1024);
|
||||
|
||||
allow_all_cors_origins = Bool(L"allow_all_cors_origins", false);
|
||||
ListText(L"allowed_cors_origins", allowed_cors_origins);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -976,7 +976,17 @@ public:
|
|||
// if the limit is reached then the http status 503 Service Unavailable is returned
|
||||
size_t request_queue_job_limit;
|
||||
|
||||
// whether or not all origins are allowed in cors requests
|
||||
// default: false;
|
||||
// if false then we check allowed_cors_origins table to check whether the origin is available (origin is sent in Origin header),
|
||||
// if allow_all_cors_origins is false and allowed_cors_origins is empty then by default we do not allow cors requests
|
||||
// (but you can still allow it in your function/controller by overriding IsCorsOriginAvailable(...) method)
|
||||
bool allow_all_cors_origins;
|
||||
|
||||
// list of allowed origins in cors requests
|
||||
// used only if allow_all_cors_origins is false
|
||||
// default: empty
|
||||
std::vector<std::wstring> allowed_cors_origins;
|
||||
|
||||
|
||||
Config();
|
||||
|
|
|
@ -1628,8 +1628,23 @@ void slice_by(const std::wstring & str, wchar_t c, std::vector<std::wstring> & o
|
|||
}
|
||||
|
||||
|
||||
bool is_in_list(const std::wstring & item, const std::vector<std::wstring> & list)
|
||||
{
|
||||
return is_in_list_generic(item, list);
|
||||
}
|
||||
|
||||
|
||||
bool is_in_list(const std::wstring & item, const std::list<std::wstring> & list)
|
||||
{
|
||||
return is_in_list_generic(item, list);
|
||||
}
|
||||
|
||||
|
||||
bool is_in_list(const std::wstring & item, const std::set<std::wstring> & list)
|
||||
{
|
||||
return is_in_list_generic(item, list);
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace Winix
|
||||
|
|
|
@ -36,6 +36,8 @@
|
|||
#define headerfile_winix_core_misc
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <ctime>
|
||||
#include <cstdio>
|
||||
|
@ -1032,6 +1034,28 @@ void timespec_to_stream_with_unit(timespec & val, pt::Stream & stream);
|
|||
void slice_by(const std::wstring & str, wchar_t c, std::vector<std::wstring> & out);
|
||||
|
||||
|
||||
bool is_in_list(const std::wstring & item, const std::vector<std::wstring> & list);
|
||||
bool is_in_list(const std::wstring & item, const std::list<std::wstring> & list);
|
||||
bool is_in_list(const std::wstring & item, const std::set<std::wstring> & list);
|
||||
|
||||
|
||||
|
||||
template<typename ContainerType>
|
||||
bool is_in_list_generic(const std::wstring & item, const ContainerType & list)
|
||||
{
|
||||
for(const std::wstring & str : list)
|
||||
{
|
||||
if( str == item )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace Winix
|
||||
|
||||
|
||||
|
|
|
@ -1536,10 +1536,25 @@ void Request::PrepareSessionCookie()
|
|||
}
|
||||
|
||||
|
||||
void Request::CheckOriginHeader()
|
||||
{
|
||||
pt::Space * origin = headers_in.get_space_nc(L"Origin");
|
||||
|
||||
if( origin && origin->is_wstr() && !out_headers.has_key(Header::access_control_allow_origin) )
|
||||
{
|
||||
if( function && function->IsCorsOriginAvailable(*origin->get_wstr()) )
|
||||
{
|
||||
function->AddAccessControlAllowOriginHeader(*origin->get_wstr());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Request::PrepareHeaders(bool compressing, int compress_encoding, size_t output_size)
|
||||
{
|
||||
PrepareSessionCookie();
|
||||
CheckOriginHeader();
|
||||
|
||||
if( send_as_attachment )
|
||||
{
|
||||
|
|
|
@ -595,6 +595,7 @@ private:
|
|||
int SelectDeflateVersion();
|
||||
void SelectCompression(size_t source_len, bool & compression_allowed, int & compression_encoding);
|
||||
void PrepareSessionCookie();
|
||||
void CheckOriginHeader();
|
||||
void PrepareHeaders(bool compressing, int compress_encoding, size_t output_size);
|
||||
void ModifyStatusForRedirect();
|
||||
void PrepareSendFileHeaderForStaticMountpoint();
|
||||
|
|
|
@ -151,8 +151,22 @@ bool FunctionBase::IsCorsMethodAvailable(Request::Method method)
|
|||
|
||||
bool FunctionBase::IsCorsOriginAvailable(const std::wstring & origin_url)
|
||||
{
|
||||
// true by default for all urles
|
||||
return true;
|
||||
if( config )
|
||||
{
|
||||
if( config->allow_all_cors_origins )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// origin_url can be a "null" string
|
||||
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Origin
|
||||
// but in such a case the "null" should be put to the config as well
|
||||
return is_in_list(origin_url, config->allowed_cors_origins);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
@ -175,10 +189,25 @@ void FunctionBase::AddAccessControlAllowMethodsHeader(Request::Method method)
|
|||
|
||||
/*
|
||||
* origin_url is the value of Origin header sent by the client
|
||||
* origin_url can be: "null"
|
||||
* https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Origin
|
||||
*
|
||||
*/
|
||||
void FunctionBase::AddAccessControlAllowOriginHeader(const std::wstring & origin_url)
|
||||
{
|
||||
cur->request->AddHeader(Header::access_control_allow_origin, origin_url);
|
||||
if( config )
|
||||
{
|
||||
if( config->allow_all_cors_origins )
|
||||
{
|
||||
cur->request->AddHeader(Header::access_control_allow_origin, L"*");
|
||||
}
|
||||
else
|
||||
{
|
||||
// method IsCorsOriginAvailable(..) was called beforehand so now we assume
|
||||
// that the origin_url is permitted
|
||||
cur->request->AddHeader(Header::access_control_allow_origin, origin_url);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -246,27 +275,34 @@ void FunctionBase::MakeOptions()
|
|||
* (we allow Access-Control-Request-Headers not to be present)
|
||||
*/
|
||||
Request::Method method = Request::CheckRequestMethod(cors_method->get_wstr()->c_str());
|
||||
bool cors_available = false;
|
||||
|
||||
if( IsCorsMethodAvailable(method) && IsCorsOriginAvailable(*cors_origin->get_wstr()) )
|
||||
{
|
||||
bool cors_available = true;
|
||||
cors_available = true;
|
||||
|
||||
if( cors_headers && cors_headers->is_wstr() )
|
||||
{
|
||||
cors_available = AreCorsHeadersAvailable(*cors_headers->get_wstr());
|
||||
}
|
||||
}
|
||||
|
||||
if( cors_available )
|
||||
if( cors_available )
|
||||
{
|
||||
AddAccessControlAllowMethodsHeader(method);
|
||||
AddAccessControlAllowOriginHeader(*cors_origin->get_wstr());
|
||||
AddAccessControlMaxAgeHeader();
|
||||
|
||||
if( cors_headers && cors_headers->is_wstr() )
|
||||
{
|
||||
AddAccessControlAllowMethodsHeader(method);
|
||||
AddAccessControlAllowOriginHeader(*cors_origin->get_wstr());
|
||||
AddAccessControlMaxAgeHeader();
|
||||
|
||||
if( cors_headers && cors_headers->is_wstr() )
|
||||
{
|
||||
AddAccessControlAllowHeadersHeader(*cors_headers->get_wstr());
|
||||
}
|
||||
AddAccessControlAllowHeadersHeader(*cors_headers->get_wstr());
|
||||
}
|
||||
|
||||
log << log3 << "FunctionBase: cors requests are permitted" << logend;
|
||||
}
|
||||
else
|
||||
{
|
||||
log << log2 << "FunctionBase: cors requests are not permitted" << logend;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
Loading…
Reference in New Issue