add support for preflight requ (cors)

This commit is contained in:
Tomasz Sowa 2022-08-30 01:52:02 +02:00
parent a34db6505d
commit 217f42b7c6
5 changed files with 125 additions and 1 deletions

View File

@ -54,6 +54,10 @@ public:
static constexpr const wchar_t * accept_language = L"Accept-Language";
static constexpr const wchar_t * authorization = L"Authorization";
static constexpr const wchar_t * allow = L"Allow";
static constexpr const wchar_t * access_control_allow_methods = L"Access-Control-Allow-Methods";
static constexpr const wchar_t * access_control_allow_origin = L"Access-Control-Allow-Origin";
static constexpr const wchar_t * access_control_allow_headers = L"Access-Control-Allow-Headers";
static constexpr const wchar_t * access_control_max_age = L"Access-Control-Max-Age";
/*
* headers' names lower case

View File

@ -1597,6 +1597,19 @@ return false;
}
bool Request::AddHeader(const wchar_t * name, long value)
{
if( !out_headers.has_key(name) )
{
out_headers.add(name, value);
return true;
}
return false;
}
bool Request::AddHeader(const std::wstring & name, const std::wstring & value)
{
if( !out_headers.has_key(name) )

View File

@ -513,6 +513,7 @@ public:
// RENAMEME to add_header_if_not_exists
bool AddHeader(const wchar_t * name, const wchar_t * value);
bool AddHeader(const wchar_t * name, long value);
bool AddHeader(const std::wstring & name, const std::wstring & value);
bool AddHeader(const wchar_t * name, const pt::WTextStream & value);
bool AddHeader(const std::wstring & name, const pt::WTextStream & value);

View File

@ -142,6 +142,61 @@ bool FunctionBase::HasAccess()
}
bool FunctionBase::IsCorsMethodAvailable(Request::Method method)
{
return method == Request::get || method == Request::head || method == Request::post || method == Request::put ||
method == Request::delete_ ||method == Request::patch;
}
bool FunctionBase::IsCorsOriginAvailable(const std::wstring & origin_url)
{
// true by default for all urles
return true;
}
bool FunctionBase::AreCorsHeadersAvailable(const std::wstring & headers)
{
// true by default for all headers
// headers are comma separated
return true;
}
/*
* method is the value of Access-Control-Request-Method header sent by the client
*/
void FunctionBase::AddAccessControlAllowMethodsHeader(Request::Method method)
{
cur->request->AddHeader(Header::access_control_allow_methods, L"GET, HEAD, POST, PUT, DELETE, OPTIONS, PATCH");
}
/*
* origin_url is the value of Origin header sent by the client
*/
void FunctionBase::AddAccessControlAllowOriginHeader(const std::wstring & origin_url)
{
cur->request->AddHeader(Header::access_control_allow_origin, origin_url);
}
/*
* headers is the value of Access-Control-Request-Headers header sent by the client
*/
void FunctionBase::AddAccessControlAllowHeadersHeader(const std::wstring & headers)
{
cur->request->AddHeader(Header::access_control_allow_headers, headers);
}
void FunctionBase::AddAccessControlMaxAgeHeader()
{
// default 24 hours
cur->request->AddHeader(Header::access_control_max_age, 86400);
}
void FunctionBase::MakeGet()
{
@ -174,12 +229,53 @@ void FunctionBase::MakeConnect()
// do nothing by default
}
void FunctionBase::MakeOptions()
{
cur->request->http_status = Header::status_204_no_content;
cur->request->out_headers.add(Header::allow, L"OPTIONS, GET, HEAD, POST, DELETE");
pt::Space * cors_method = cur->request->headers_in.get_space_nc(L"Access_Control_Request_Method"); // FastCGI changes '-' to '_'
pt::Space * cors_headers = cur->request->headers_in.get_space_nc(L"Access_Control_Request_Headers");
pt::Space * cors_origin = cur->request->headers_in.get_space_nc(L"Origin");
if( cors_method && cors_origin && cors_method->is_wstr() && cors_origin->is_wstr() )
{
/*
* this is a preflight request
* https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request
* (we allow Access-Control-Request-Headers not to be present)
*/
Request::Method method = Request::CheckRequestMethod(cors_method->get_wstr()->c_str());
if( IsCorsMethodAvailable(method) && IsCorsOriginAvailable(*cors_origin->get_wstr()) )
{
bool cors_available = true;
if( cors_headers && cors_headers->is_wstr() )
{
cors_available = AreCorsHeadersAvailable(*cors_headers->get_wstr());
}
if( cors_available )
{
AddAccessControlAllowMethodsHeader(method);
AddAccessControlAllowOriginHeader(*cors_origin->get_wstr());
AddAccessControlMaxAgeHeader();
if( cors_headers && cors_headers->is_wstr() )
{
AddAccessControlAllowHeadersHeader(*cors_headers->get_wstr());
}
}
}
}
else
{
cur->request->out_headers.add(Header::allow, L"GET, HEAD, POST, PUT, DELETE, OPTIONS, PATCH");
}
}
void FunctionBase::MakeTrace()
{
// do nothing by default

View File

@ -111,6 +111,16 @@ public:
virtual bool HasAccess();
virtual bool IsCorsMethodAvailable(Request::Method method);
virtual bool IsCorsOriginAvailable(const std::wstring & origin_url);
virtual bool AreCorsHeadersAvailable(const std::wstring & headers);
virtual void AddAccessControlAllowMethodsHeader(Request::Method method);
virtual void AddAccessControlAllowOriginHeader(const std::wstring & origin_url);
virtual void AddAccessControlAllowHeadersHeader(const std::wstring & headers);
virtual void AddAccessControlMaxAgeHeader();
virtual void MakeGet();
virtual void MakeHead();
virtual void MakePost();