From 53780b7dee6a8192e7c4e9165c4d2f2d645c12fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julio=20C=C3=A9sar=20Rocha?= Date: Tue, 12 Mar 2024 17:33:33 -0700 Subject: [PATCH 1/8] Make HTTP origin value an instance member (#12821) * Make origin an instance member * Change files * Remove s_origin * Remove redundant namespace --- ...-bc10ca83-c1a9-4f4a-ac53-6d54378c3aca.json | 7 +++ .../OriginPolicyHttpFilterTest.cpp | 47 +++++++++++++++++-- .../Networking/OriginPolicyHttpFilter.cpp | 42 ++++++++--------- .../Networking/OriginPolicyHttpFilter.h | 11 ++--- vnext/Shared/Networking/WinRTHttpResource.cpp | 6 +-- 5 files changed, 75 insertions(+), 38 deletions(-) create mode 100644 change/react-native-windows-bc10ca83-c1a9-4f4a-ac53-6d54378c3aca.json diff --git a/change/react-native-windows-bc10ca83-c1a9-4f4a-ac53-6d54378c3aca.json b/change/react-native-windows-bc10ca83-c1a9-4f4a-ac53-6d54378c3aca.json new file mode 100644 index 00000000000..f36a7791478 --- /dev/null +++ b/change/react-native-windows-bc10ca83-c1a9-4f4a-ac53-6d54378c3aca.json @@ -0,0 +1,7 @@ +{ + "type": "prerelease", + "comment": "Make HTTP origin value an instance member", + "packageName": "react-native-windows", + "email": "julio.rocha@microsoft.com", + "dependentChangeType": "patch" +} diff --git a/vnext/Desktop.UnitTests/OriginPolicyHttpFilterTest.cpp b/vnext/Desktop.UnitTests/OriginPolicyHttpFilterTest.cpp index 1815236eab1..fefd87fa9e5 100644 --- a/vnext/Desktop.UnitTests/OriginPolicyHttpFilterTest.cpp +++ b/vnext/Desktop.UnitTests/OriginPolicyHttpFilterTest.cpp @@ -252,6 +252,48 @@ TEST_CLASS (OriginPolicyHttpFilterTest) { } } + TEST_METHOD(ValidatePreflightResponseHeadersCaseMismatchSucceeds) { + auto mockFilter = winrt::make(); + mockFilter.as()->Mocks.SendRequestAsync = + [](HttpRequestMessage const &request) -> ResponseOperation { + HttpResponseMessage response{}; + + response.StatusCode(HttpStatusCode::Ok); + response.Headers().Insert(L"Access-Control-Allow-Origin", L"*"); + + // Return allowed headers as requested by client, in lower case. + // This tests case-insensitive preflight validation. + auto allowHeaders = boost::to_lower_copy(wstring{request.Headers().Lookup(L"Access-Control-Request-Headers")}); + response.Headers().Insert(L"Access-Control-Allow-Headers", std::move(allowHeaders)); + + co_return response; + }; + + auto reqArgs = winrt::make(); + auto request = HttpRequestMessage(HttpMethod::Get(), Uri{L"http://somehost"}); + request.Properties().Insert(L"RequestArgs", reqArgs); + request.Headers().TryAppendWithoutValidation(L"ChangeMyCase", L"Value"); + // Should implicitly set Content-Length and Content-Type + request.Content(HttpStringContent{L"PreflightContent"}); + + auto filter = winrt::make("http://somehost", mockFilter); + auto opFilter = filter.as(); + + try { + auto sendOp = opFilter->SendPreflightAsync(request); + sendOp.get(); + + auto response = sendOp.GetResults(); + opFilter->ValidatePreflightResponse(request, response); + + Assert::IsTrue(boost::iequals( + response.Headers().Lookup(L"Access-Control-Allow-Headers").c_str(), + L"ChangeMyCase, Content-Length, Content-Type")); + } catch (const winrt::hresult_error &e) { + Assert::Fail(e.message().c_str()); + } + } + TEST_METHOD(ValidatePreflightResponseMainAndContentHeadersSucceeds) { auto mockFilter = winrt::make(); mockFilter.as()->Mocks.SendRequestAsync = @@ -274,10 +316,9 @@ TEST_CLASS (OriginPolicyHttpFilterTest) { // Should implicitly set Conent-Length and Content-Type request.Content(HttpStringContent{L"PreflightContent"}); - auto filter = winrt::make(mockFilter); + auto filter = winrt::make("http://somehost", mockFilter); auto opFilter = filter.as(); - OriginPolicyHttpFilter::SetStaticOrigin("http://somehost"); try { auto sendOp = opFilter->SendPreflightAsync(request); sendOp.get(); @@ -285,12 +326,10 @@ TEST_CLASS (OriginPolicyHttpFilterTest) { auto response = sendOp.GetResults(); opFilter->ValidatePreflightResponse(request, response); - OriginPolicyHttpFilter::SetStaticOrigin({}); Assert::AreEqual( L"Authorization, Content-Length, Content-Type", response.Headers().Lookup(L"Access-Control-Allow-Headers").c_str()); } catch (const winrt::hresult_error &e) { - OriginPolicyHttpFilter::SetStaticOrigin({}); Assert::Fail(e.message().c_str()); } } diff --git a/vnext/Shared/Networking/OriginPolicyHttpFilter.cpp b/vnext/Shared/Networking/OriginPolicyHttpFilter.cpp index 5cd1b05bc30..8855c381ee3 100644 --- a/vnext/Shared/Networking/OriginPolicyHttpFilter.cpp +++ b/vnext/Shared/Networking/OriginPolicyHttpFilter.cpp @@ -16,6 +16,7 @@ #include using std::set; +using std::string; using std::wstring; using winrt::hresult_error; @@ -108,15 +109,6 @@ bool OriginPolicyHttpFilter::ConstWcharComparer::operator()(const wchar_t *a, co /*static*/ set OriginPolicyHttpFilter::s_corsForbiddenRequestHeaderNamePrefixes = {L"Proxy-", L"Sec-"}; -/*static*/ Uri OriginPolicyHttpFilter::s_origin{nullptr}; - -/*static*/ void OriginPolicyHttpFilter::SetStaticOrigin(std::string &&url) { - if (!url.empty()) - s_origin = Uri{to_hstring(url)}; - else - s_origin = nullptr; -} - /*static*/ bool OriginPolicyHttpFilter::IsSameOrigin(Uri const &u1, Uri const &u2) noexcept { return (u1 && u2) && u1.SchemeName() == u2.SchemeName() && u1.Host() == u2.Host() && u1.Port() == u2.Port(); } @@ -381,10 +373,14 @@ bool OriginPolicyHttpFilter::ConstWcharComparer::operator()(const wchar_t *a, co } } -OriginPolicyHttpFilter::OriginPolicyHttpFilter(IHttpFilter const &innerFilter) : m_innerFilter{innerFilter} {} +OriginPolicyHttpFilter::OriginPolicyHttpFilter(string &&origin, IHttpFilter const &innerFilter) + : m_origin{nullptr}, m_innerFilter{innerFilter} { + if (!origin.empty()) + m_origin = Uri{to_hstring(origin)}; +} -OriginPolicyHttpFilter::OriginPolicyHttpFilter() - : OriginPolicyHttpFilter(winrt::Windows::Web::Http::Filters::HttpBaseProtocolFilter{}) {} +OriginPolicyHttpFilter::OriginPolicyHttpFilter(string &&origin) + : OriginPolicyHttpFilter(std::move(origin), winrt::Windows::Web::Http::Filters::HttpBaseProtocolFilter{}) {} OriginPolicy OriginPolicyHttpFilter::ValidateRequest(HttpRequestMessage const &request) { auto effectiveOriginPolicy = @@ -394,17 +390,17 @@ OriginPolicy OriginPolicyHttpFilter::ValidateRequest(HttpRequestMessage const &r return effectiveOriginPolicy; case OriginPolicy::SameOrigin: - if (!IsSameOrigin(s_origin, request.RequestUri())) + if (!IsSameOrigin(m_origin, request.RequestUri())) throw hresult_error{E_INVALIDARG, L"SOP (same-origin policy) is enforced"}; break; case OriginPolicy::SimpleCrossOriginResourceSharing: // Check for disallowed mixed content if (GetRuntimeOptionBool("Http.BlockMixedContentSimpleCors") && - s_origin.SchemeName() != request.RequestUri().SchemeName()) + m_origin.SchemeName() != request.RequestUri().SchemeName()) throw hresult_error{E_INVALIDARG, L"The origin and request URLs must have the same scheme"}; - if (IsSameOrigin(s_origin, request.RequestUri())) + if (IsSameOrigin(m_origin, request.RequestUri())) // Same origin. Therefore, skip Cross-Origin handling. effectiveOriginPolicy = OriginPolicy::SameOrigin; else if (!IsSimpleCorsRequest(request)) @@ -420,7 +416,7 @@ OriginPolicy OriginPolicyHttpFilter::ValidateRequest(HttpRequestMessage const &r // Example: On the Edge browser, an XHR request with the "Host" header set gets rejected as unsafe. // https://fetch.spec.whatwg.org/#forbidden-header-name - if (s_origin.SchemeName() != request.RequestUri().SchemeName()) + if (m_origin.SchemeName() != request.RequestUri().SchemeName()) throw hresult_error{E_INVALIDARG, L"The origin and request URLs must have the same scheme"}; if (!AreSafeRequestHeaders(request.Headers())) @@ -429,7 +425,7 @@ OriginPolicy OriginPolicyHttpFilter::ValidateRequest(HttpRequestMessage const &r if (s_forbiddenMethods.find(request.Method().ToString().c_str()) != s_forbiddenMethods.cend()) throw hresult_error{E_INVALIDARG, L"Request method not allowed in cross-origin resource sharing"}; - if (IsSameOrigin(s_origin, request.RequestUri())) + if (IsSameOrigin(m_origin, request.RequestUri())) effectiveOriginPolicy = OriginPolicy::SameOrigin; else if (IsSimpleCorsRequest(request)) effectiveOriginPolicy = OriginPolicy::SimpleCrossOriginResourceSharing; @@ -466,7 +462,7 @@ void OriginPolicyHttpFilter::ValidateAllowOrigin( // 4.10.4 - Mismatched allow origin auto taintedOriginProp = props.TryLookup(L"TaintedOrigin"); auto taintedOrigin = taintedOriginProp && winrt::unbox_value(taintedOriginProp); - auto origin = taintedOrigin ? nullptr : s_origin; + auto origin = taintedOrigin ? nullptr : m_origin; if (allowedOrigin.empty() || !IsSameOrigin(origin, Uri{allowedOrigin})) { hstring errorMessage; if (allowedOrigin.empty()) @@ -597,7 +593,7 @@ void OriginPolicyHttpFilter::ValidateResponse(HttpResponseMessage const &respons bool originAllowed = false; for (const auto &header : response.Headers()) { if (boost::iequals(header.Key(), L"Access-Control-Allow-Origin")) { - originAllowed |= L"*" == header.Value() || s_origin == Uri{header.Value()}; + originAllowed |= L"*" == header.Value() || m_origin == Uri{header.Value()}; } } @@ -685,7 +681,7 @@ ResponseOperation OriginPolicyHttpFilter::SendPreflightAsync(HttpRequestMessage } preflightRequest.Headers().Insert(L"Access-Control-Request-Headers", headerNames); - preflightRequest.Headers().Insert(L"Origin", GetOrigin(s_origin)); + preflightRequest.Headers().Insert(L"Origin", GetOrigin(m_origin)); preflightRequest.Headers().Insert(L"Sec-Fetch-Mode", L"CORS"); co_return {co_await m_innerFilter.SendRequestAsync(preflightRequest)}; @@ -702,7 +698,7 @@ bool OriginPolicyHttpFilter::OnRedirecting( // origin=http://a.com. Since the origin matches the URL, the request is authorized at http://a.com, but it actually // allows http://b.com to bypass the CORS check at http://a.com since the redirected URL is from http://b.com. if (!IsSameOrigin(response.Headers().Location(), request.RequestUri()) && - !IsSameOrigin(s_origin, request.RequestUri())) { + !IsSameOrigin(m_origin, request.RequestUri())) { // By masking the origin field in the request header, we make it impossible for the server to set a single value for // the access-control-allow-origin header. It means, the only way to support redirect is that server allows access // from all sites through wildcard. @@ -734,7 +730,7 @@ ResponseOperation OriginPolicyHttpFilter::SendRequestAsync(HttpRequestMessage co // Allow only HTTP or HTTPS schemes if (GetRuntimeOptionBool("Http.StrictScheme") && coRequest.RequestUri().SchemeName() != L"https" && coRequest.RequestUri().SchemeName() != L"http") - throw hresult_error{E_INVALIDARG, L"Invalid URL scheme: [" + s_origin.SchemeName() + L"]"}; + throw hresult_error{E_INVALIDARG, L"Invalid URL scheme: [" + m_origin.SchemeName() + L"]"}; if (!GetRuntimeOptionBool("Http.OmitCredentials")) { coRequest.Properties().Lookup(L"RequestArgs").as()->WithCredentials = false; @@ -771,7 +767,7 @@ ResponseOperation OriginPolicyHttpFilter::SendRequestAsync(HttpRequestMessage co if (originPolicy == OriginPolicy::SimpleCrossOriginResourceSharing || originPolicy == OriginPolicy::CrossOriginResourceSharing) { - coRequest.Headers().Insert(L"Origin", GetOrigin(s_origin)); + coRequest.Headers().Insert(L"Origin", GetOrigin(m_origin)); } auto response = co_await m_innerFilter.SendRequestAsync(coRequest); diff --git a/vnext/Shared/Networking/OriginPolicyHttpFilter.h b/vnext/Shared/Networking/OriginPolicyHttpFilter.h index e2c322ff787..88108e86646 100644 --- a/vnext/Shared/Networking/OriginPolicyHttpFilter.h +++ b/vnext/Shared/Networking/OriginPolicyHttpFilter.h @@ -36,9 +36,6 @@ class OriginPolicyHttpFilter static std::set s_corsForbiddenRequestHeaderNamePrefixes; static std::set s_cookieSettingResponseHeaders; - // NOTE: Assumes static origin through owning client/resource/module/(React) instance's lifetime. - static winrt::Windows::Foundation::Uri s_origin; - struct AccessControlValues { winrt::hstring AllowedOrigin; winrt::hstring AllowedCredentials; @@ -48,11 +45,11 @@ class OriginPolicyHttpFilter size_t MaxAge; }; + winrt::Windows::Foundation::Uri m_origin; + winrt::Windows::Web::Http::Filters::IHttpFilter m_innerFilter; public: - static void SetStaticOrigin(std::string &&url); - static bool IsSameOrigin( winrt::Windows::Foundation::Uri const &u1, winrt::Windows::Foundation::Uri const &u2) noexcept; @@ -79,9 +76,9 @@ class OriginPolicyHttpFilter winrt::Windows::Web::Http::HttpResponseMessage const &response, bool removeAll); - OriginPolicyHttpFilter(winrt::Windows::Web::Http::Filters::IHttpFilter const &innerFilter); + OriginPolicyHttpFilter(std::string &&origin, winrt::Windows::Web::Http::Filters::IHttpFilter const &innerFilter); - OriginPolicyHttpFilter(); + OriginPolicyHttpFilter(std::string &&origin); OriginPolicy ValidateRequest(winrt::Windows::Web::Http::HttpRequestMessage const &request); diff --git a/vnext/Shared/Networking/WinRTHttpResource.cpp b/vnext/Shared/Networking/WinRTHttpResource.cpp index 899fb157b86..7c81783b2e7 100644 --- a/vnext/Shared/Networking/WinRTHttpResource.cpp +++ b/vnext/Shared/Networking/WinRTHttpResource.cpp @@ -641,8 +641,7 @@ void WinRTHttpResource::AddResponseHandler(shared_ptr response #pragma region IHttpResource -/*static*/ shared_ptr IHttpResource::Make( - winrt::Windows::Foundation::IInspectable const &inspectableProperties) noexcept { +/*static*/ shared_ptr IHttpResource::Make(IInspectable const &inspectableProperties) noexcept { using namespace winrt::Microsoft::ReactNative; using winrt::Windows::Web::Http::HttpClient; @@ -653,8 +652,7 @@ void WinRTHttpResource::AddResponseHandler(shared_ptr response client = HttpClient{redirFilter}; } else { auto globalOrigin = GetRuntimeOptionString("Http.GlobalOrigin"); - OriginPolicyHttpFilter::SetStaticOrigin(std::move(globalOrigin)); - auto opFilter = winrt::make(redirFilter); + auto opFilter = winrt::make(std::move(globalOrigin), redirFilter); redirFilter.as()->SetRedirectSource(opFilter.as()); client = HttpClient{opFilter}; From 569fd4b905d6c112404d3e224ea53bc3b6384e2a Mon Sep 17 00:00:00 2001 From: "Julio C. Rocha" Date: Tue, 12 Mar 2024 17:46:40 -0700 Subject: [PATCH 2/8] Remove change file --- ...ative-windows-bc10ca83-c1a9-4f4a-ac53-6d54378c3aca.json | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 change/react-native-windows-bc10ca83-c1a9-4f4a-ac53-6d54378c3aca.json diff --git a/change/react-native-windows-bc10ca83-c1a9-4f4a-ac53-6d54378c3aca.json b/change/react-native-windows-bc10ca83-c1a9-4f4a-ac53-6d54378c3aca.json deleted file mode 100644 index f36a7791478..00000000000 --- a/change/react-native-windows-bc10ca83-c1a9-4f4a-ac53-6d54378c3aca.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "type": "prerelease", - "comment": "Make HTTP origin value an instance member", - "packageName": "react-native-windows", - "email": "julio.rocha@microsoft.com", - "dependentChangeType": "patch" -} From 509c99ef4331178d28f14bb5ed3a287b799e0fcf Mon Sep 17 00:00:00 2001 From: "Julio C. Rocha" Date: Tue, 12 Mar 2024 17:51:28 -0700 Subject: [PATCH 3/8] Change files --- ...ative-windows-79195159-2c00-460f-966c-7d600e37bc60.json | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 change/react-native-windows-79195159-2c00-460f-966c-7d600e37bc60.json diff --git a/change/react-native-windows-79195159-2c00-460f-966c-7d600e37bc60.json b/change/react-native-windows-79195159-2c00-460f-966c-7d600e37bc60.json new file mode 100644 index 00000000000..d77419c7093 --- /dev/null +++ b/change/react-native-windows-79195159-2c00-460f-966c-7d600e37bc60.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "Make HTTP origin value an instance member (#12821)", + "packageName": "react-native-windows", + "email": "julio.rocha@microsoft.com", + "dependentChangeType": "patch" +} From 4a3006b14cdf02ae658ed14e940ad450de36fee5 Mon Sep 17 00:00:00 2001 From: "Julio C. Rocha" Date: Tue, 12 Mar 2024 18:03:47 -0700 Subject: [PATCH 4/8] Add missing backports --- vnext/Desktop.UnitTests/OriginPolicyHttpFilterTest.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/vnext/Desktop.UnitTests/OriginPolicyHttpFilterTest.cpp b/vnext/Desktop.UnitTests/OriginPolicyHttpFilterTest.cpp index fefd87fa9e5..dc0f7ee2964 100644 --- a/vnext/Desktop.UnitTests/OriginPolicyHttpFilterTest.cpp +++ b/vnext/Desktop.UnitTests/OriginPolicyHttpFilterTest.cpp @@ -7,6 +7,9 @@ #include #include "WinRTNetworkingMocks.h" +// Boost Library +#include + // Windows API #include #include @@ -17,6 +20,7 @@ using namespace winrt::Windows::Web::Http; using Microsoft::React::Networking::OriginPolicyHttpFilter; using Microsoft::React::Networking::RequestArgs; using Microsoft::React::Networking::ResponseOperation; +using std::wstring; using winrt::Windows::Foundation::Uri; namespace Microsoft::React::Test { @@ -313,7 +317,7 @@ TEST_CLASS (OriginPolicyHttpFilterTest) { auto request = HttpRequestMessage(HttpMethod::Get(), Uri{L"http://somehost"}); request.Properties().Insert(L"RequestArgs", reqArgs); request.Headers().TryAppendWithoutValidation(L"Authorization", L"Bearer abc"); - // Should implicitly set Conent-Length and Content-Type + // Should implicitly set Content-Length and Content-Type request.Content(HttpStringContent{L"PreflightContent"}); auto filter = winrt::make("http://somehost", mockFilter); From de6ffd703d0f4b854a34cea40b1123b82e683fdb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julio=20C=C3=A9sar=20Rocha?= Date: Fri, 21 Apr 2023 16:29:27 -0700 Subject: [PATCH 5/8] Use case-insensitive comparison for CORS preflight responses (#11511) * Remove usage of RestoreUseStaticGraphEvaluation * Add test ValidatePreflightResponseHeadersCaseMismatchSucceeds * Use case-insensitive comparer for AllowedHeaders * Change files * Revert "Remove usage of RestoreUseStaticGraphEvaluation" This reverts commit 735b168892dc2d1643f49711df16afc20a07f689. * Rename ConstWcharComparer to CaseInsensitiveComparer * Update vnext/Desktop.UnitTests/OriginPolicyHttpFilterTest.cpp Co-authored-by: Danny van Velzen * Remove unused code * Make ExposedHeaders case-insensitive --------- Co-authored-by: Danny van Velzen --- ...-7cf2e2b2-8bb7-40e6-8859-f584c4033f3a.json | 7 +++++ .../OriginPolicyHttpFilterTest.cpp | 4 +++ .../Networking/OriginPolicyHttpFilter.cpp | 30 +++++++++++-------- .../Networking/OriginPolicyHttpFilter.h | 23 +++++++------- 4 files changed, 40 insertions(+), 24 deletions(-) create mode 100644 change/react-native-windows-7cf2e2b2-8bb7-40e6-8859-f584c4033f3a.json diff --git a/change/react-native-windows-7cf2e2b2-8bb7-40e6-8859-f584c4033f3a.json b/change/react-native-windows-7cf2e2b2-8bb7-40e6-8859-f584c4033f3a.json new file mode 100644 index 00000000000..74aaa2f1646 --- /dev/null +++ b/change/react-native-windows-7cf2e2b2-8bb7-40e6-8859-f584c4033f3a.json @@ -0,0 +1,7 @@ +{ + "type": "prerelease", + "comment": "Use case-insensitive comparer for AllowedHeaders", + "packageName": "react-native-windows", + "email": "julio.rocha@microsoft.com", + "dependentChangeType": "patch" +} diff --git a/vnext/Desktop.UnitTests/OriginPolicyHttpFilterTest.cpp b/vnext/Desktop.UnitTests/OriginPolicyHttpFilterTest.cpp index dc0f7ee2964..b2dd320ad4f 100644 --- a/vnext/Desktop.UnitTests/OriginPolicyHttpFilterTest.cpp +++ b/vnext/Desktop.UnitTests/OriginPolicyHttpFilterTest.cpp @@ -10,6 +10,9 @@ // Boost Library #include +// Boost Library +#include + // Windows API #include #include @@ -21,6 +24,7 @@ using Microsoft::React::Networking::OriginPolicyHttpFilter; using Microsoft::React::Networking::RequestArgs; using Microsoft::React::Networking::ResponseOperation; using std::wstring; +using std::wstring; using winrt::Windows::Foundation::Uri; namespace Microsoft::React::Test { diff --git a/vnext/Shared/Networking/OriginPolicyHttpFilter.cpp b/vnext/Shared/Networking/OriginPolicyHttpFilter.cpp index 8855c381ee3..2be5702837a 100644 --- a/vnext/Shared/Networking/OriginPolicyHttpFilter.cpp +++ b/vnext/Shared/Networking/OriginPolicyHttpFilter.cpp @@ -38,22 +38,26 @@ namespace Microsoft::React::Networking { #pragma region OriginPolicyHttpFilter -#pragma region ConstWcharComparer +#pragma region CaseInsensitiveComparer -bool OriginPolicyHttpFilter::ConstWcharComparer::operator()(const wchar_t *a, const wchar_t *b) const { +bool OriginPolicyHttpFilter::CaseInsensitiveComparer::operator()(const wchar_t *a, const wchar_t *b) const { return _wcsicmp(a, b) < 0; } -#pragma endregion ConstWcharComparer +bool OriginPolicyHttpFilter::CaseInsensitiveComparer::operator()(const wstring &a, const wstring &b) const { + return _wcsicmp(a.c_str(), b.c_str()) < 0; +} + +#pragma endregion CaseInsensitiveComparer // https://fetch.spec.whatwg.org/#forbidden-method -/*static*/ set OriginPolicyHttpFilter::s_forbiddenMethods = - {L"CONNECT", L"TRACE", L"TRACK"}; +/*static*/ set + OriginPolicyHttpFilter::s_forbiddenMethods = {L"CONNECT", L"TRACE", L"TRACK"}; -/*static*/ set +/*static*/ set OriginPolicyHttpFilter::s_simpleCorsMethods = {L"GET", L"HEAD", L"POST"}; -/*static*/ set +/*static*/ set OriginPolicyHttpFilter::s_simpleCorsRequestHeaderNames = { L"Accept", L"Accept-Language", @@ -65,11 +69,11 @@ bool OriginPolicyHttpFilter::ConstWcharComparer::operator()(const wchar_t *a, co L"Viewport-Width", L"Width"}; -/*static*/ set +/*static*/ set OriginPolicyHttpFilter::s_simpleCorsResponseHeaderNames = {L"Cache-Control", L"Content-Language", L"Content-Type", L"Expires", L"Last-Modified", L"Pragma"}; -/*static*/ set +/*static*/ set OriginPolicyHttpFilter::s_simpleCorsContentTypeValues = { L"application/x-www-form-urlencoded", L"multipart/form-data", @@ -77,7 +81,7 @@ bool OriginPolicyHttpFilter::ConstWcharComparer::operator()(const wchar_t *a, co // https://fetch.spec.whatwg.org/#forbidden-header-name // Chromium still bans "User-Agent" due to https://crbug.com/571722 -/*static*/ set +/*static*/ set OriginPolicyHttpFilter::s_corsForbiddenRequestHeaderNames = { L"Accept-Charset", L"Accept-Encoding", @@ -100,13 +104,13 @@ bool OriginPolicyHttpFilter::ConstWcharComparer::operator()(const wchar_t *a, co L"Upgrade", L"Via"}; -/*static*/ set +/*static*/ set OriginPolicyHttpFilter::s_cookieSettingResponseHeaders = { L"Set-Cookie", L"Set-Cookie2", // Deprecated by the spec, but probably still used }; -/*static*/ set +/*static*/ set OriginPolicyHttpFilter::s_corsForbiddenRequestHeaderNamePrefixes = {L"Proxy-", L"Sec-"}; /*static*/ bool OriginPolicyHttpFilter::IsSameOrigin(Uri const &u1, Uri const &u2) noexcept { @@ -293,7 +297,7 @@ bool OriginPolicyHttpFilter::ConstWcharComparer::operator()(const wchar_t *a, co } /*static*/ OriginPolicyHttpFilter::AccessControlValues OriginPolicyHttpFilter::ExtractAccessControlValues( - winrt::Windows::Foundation::Collections::IMap const &headers) { + IMap const &headers) { using std::wregex; using std::wsregex_token_iterator; diff --git a/vnext/Shared/Networking/OriginPolicyHttpFilter.h b/vnext/Shared/Networking/OriginPolicyHttpFilter.h index 88108e86646..ba8738d5636 100644 --- a/vnext/Shared/Networking/OriginPolicyHttpFilter.h +++ b/vnext/Shared/Networking/OriginPolicyHttpFilter.h @@ -22,26 +22,27 @@ class OriginPolicyHttpFilter : public winrt:: implements { public: - struct ConstWcharComparer { + struct CaseInsensitiveComparer { bool operator()(const wchar_t *, const wchar_t *) const; + bool operator()(const std::wstring &, const std::wstring &) const; }; private: - static std::set s_forbiddenMethods; - static std::set s_simpleCorsMethods; - static std::set s_simpleCorsRequestHeaderNames; - static std::set s_simpleCorsResponseHeaderNames; - static std::set s_simpleCorsContentTypeValues; - static std::set s_corsForbiddenRequestHeaderNames; - static std::set s_corsForbiddenRequestHeaderNamePrefixes; - static std::set s_cookieSettingResponseHeaders; + static std::set s_forbiddenMethods; + static std::set s_simpleCorsMethods; + static std::set s_simpleCorsRequestHeaderNames; + static std::set s_simpleCorsResponseHeaderNames; + static std::set s_simpleCorsContentTypeValues; + static std::set s_corsForbiddenRequestHeaderNames; + static std::set s_corsForbiddenRequestHeaderNamePrefixes; + static std::set s_cookieSettingResponseHeaders; struct AccessControlValues { winrt::hstring AllowedOrigin; winrt::hstring AllowedCredentials; - std::set AllowedHeaders; + std::set AllowedHeaders; std::set AllowedMethods; - std::set ExposedHeaders; + std::set ExposedHeaders; size_t MaxAge; }; From 21d3ff8e83611f1d8f18c4f1f3d2ab6caa85487d Mon Sep 17 00:00:00 2001 From: "Julio C. Rocha" Date: Tue, 12 Mar 2024 18:18:12 -0700 Subject: [PATCH 6/8] Remove change file --- ...ative-windows-7cf2e2b2-8bb7-40e6-8859-f584c4033f3a.json | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 change/react-native-windows-7cf2e2b2-8bb7-40e6-8859-f584c4033f3a.json diff --git a/change/react-native-windows-7cf2e2b2-8bb7-40e6-8859-f584c4033f3a.json b/change/react-native-windows-7cf2e2b2-8bb7-40e6-8859-f584c4033f3a.json deleted file mode 100644 index 74aaa2f1646..00000000000 --- a/change/react-native-windows-7cf2e2b2-8bb7-40e6-8859-f584c4033f3a.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "type": "prerelease", - "comment": "Use case-insensitive comparer for AllowedHeaders", - "packageName": "react-native-windows", - "email": "julio.rocha@microsoft.com", - "dependentChangeType": "patch" -} From 7bb8fce54a84c654dc091d2ef0bc232e29993023 Mon Sep 17 00:00:00 2001 From: "Julio C. Rocha" Date: Tue, 12 Mar 2024 18:51:13 -0700 Subject: [PATCH 7/8] clang format --- vnext/Desktop.UnitTests/OriginPolicyHttpFilterTest.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/vnext/Desktop.UnitTests/OriginPolicyHttpFilterTest.cpp b/vnext/Desktop.UnitTests/OriginPolicyHttpFilterTest.cpp index b2dd320ad4f..30feea4c14a 100644 --- a/vnext/Desktop.UnitTests/OriginPolicyHttpFilterTest.cpp +++ b/vnext/Desktop.UnitTests/OriginPolicyHttpFilterTest.cpp @@ -24,7 +24,6 @@ using Microsoft::React::Networking::OriginPolicyHttpFilter; using Microsoft::React::Networking::RequestArgs; using Microsoft::React::Networking::ResponseOperation; using std::wstring; -using std::wstring; using winrt::Windows::Foundation::Uri; namespace Microsoft::React::Test { From a31ba08ade6ecfbae06a0dc04d5a8370540b387d Mon Sep 17 00:00:00 2001 From: "Julio C. Rocha" Date: Tue, 12 Mar 2024 18:54:36 -0700 Subject: [PATCH 8/8] Remove redundant include --- vnext/Desktop.UnitTests/OriginPolicyHttpFilterTest.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/vnext/Desktop.UnitTests/OriginPolicyHttpFilterTest.cpp b/vnext/Desktop.UnitTests/OriginPolicyHttpFilterTest.cpp index 30feea4c14a..dc0f7ee2964 100644 --- a/vnext/Desktop.UnitTests/OriginPolicyHttpFilterTest.cpp +++ b/vnext/Desktop.UnitTests/OriginPolicyHttpFilterTest.cpp @@ -10,9 +10,6 @@ // Boost Library #include -// Boost Library -#include - // Windows API #include #include