// Copyright 2022 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "services/network/cors/cors_url_loader.h" #include "base/test/bind.h" #include "base/test/metrics/histogram_tester.h" #include "base/test/scoped_feature_list.h" #include "net/base/net_errors.h" #include "services/network/cors/cors_url_loader_test_util.h" #include "services/network/public/cpp/cors/cors_error_status.h" #include "services/network/public/cpp/features.h" #include "services/network/public/cpp/resource_request.h" #include "services/network/public/mojom/cors.mojom.h" #include "services/network/public/mojom/fetch_api.mojom.h" #include "services/network/public/mojom/ip_address_space.mojom.h" #include "services/network/test/client_security_state_builder.h" #include "services/network/test/mock_devtools_observer.h" #include "services/network/test/test_url_loader_client.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "url/origin.h" namespace network::cors { namespace { ElementsAre; IsEmpty; IsSupersetOf; Optional; Pair; constexpr char kPreflightErrorHistogramName[] = …; constexpr char kPreflightWarningHistogramName[] = …; base::Bucket MakeBucket(mojom::CorsError error, base::HistogramBase::Count count) { … } std::vector<std::pair<std::string, std::string>> MakeHeaderPairs( const net::HttpRequestHeaders& headers) { … } class RequestTrustedParamsBuilder { … }; class CorsURLLoaderPrivateNetworkAccessTest : public CorsURLLoaderTestBase { … }; TEST_F(CorsURLLoaderPrivateNetworkAccessTest, TargetIpAddressSpaceSimple) { … } TEST_F(CorsURLLoaderPrivateNetworkAccessTest, TargetIpAddressSpacePreflight) { … } TEST_F(CorsURLLoaderPrivateNetworkAccessTest, RequestHeadersSimple) { … } TEST_F(CorsURLLoaderPrivateNetworkAccessTest, RequestHeadersPreflight) { … } TEST_F(CorsURLLoaderPrivateNetworkAccessTest, MissingResponseHeaderSimple) { … } TEST_F(CorsURLLoaderPrivateNetworkAccessTest, MissingResponseHeaderPreflight) { … } TEST_F(CorsURLLoaderPrivateNetworkAccessTest, InvalidResponseHeaderSimple) { … } TEST_F(CorsURLLoaderPrivateNetworkAccessTest, InvalidResponseHeaderPreflight) { … } TEST_F(CorsURLLoaderPrivateNetworkAccessTest, ErrorAfterPreflight) { … } TEST_F(CorsURLLoaderPrivateNetworkAccessTest, SuccessSimple) { … } TEST_F(CorsURLLoaderPrivateNetworkAccessTest, SuccessPreflight) { … } TEST_F(CorsURLLoaderPrivateNetworkAccessTest, SuccessNoCors) { … } TEST_F(CorsURLLoaderPrivateNetworkAccessTest, RedirectBeforePreflight) { … } TEST_F(CorsURLLoaderPrivateNetworkAccessTest, RedirectAfterPreflight) { … } // Regression test for https://crbug.com/1432684. TEST_F(CorsURLLoaderPrivateNetworkAccessTest, RedirectAfterPnaOnlyWarningPreflight) { … } // This test verifies that PNA preflight results are cached per target IP // address space. TEST_F(CorsURLLoaderPrivateNetworkAccessTest, CachesPreflightResult) { … } // This test verifies that successful PNA preflights do not place entries in the // preflight cache that are shared with non-PNA preflights. In other words, a // non-PNA preflight cannot be skipped because a PNA preflght previously // succeeded. TEST_F(CorsURLLoaderPrivateNetworkAccessTest, DoesNotShareCache) { … } // The following `PrivateNetworkAccessPolicyWarn*` tests verify the correct // functioning of the `kPreflightWarn` private network request policy. That is, // preflight errors caused exclusively by Private Network Access logic should // be ignored. // // The `*PolicyWarnSimple*` variants test what happens in the "simple request" // case, when a preflight would not have been sent were it not for Private // Network Access. The `*PolicyWarnPreflight*` variants test what happens when // a preflight was attempted before noticing the private network access. // // TODO(crbug.com/40204695): Remove these tests once the policy is never // set to `kPreflightWarn` anymore. // This test verifies that when: // // - the private network request policy is set to `kPreflightWarn` // - a simple request detects a private network request // - the following PNA preflight fails due to a network error // // ... the error is ignored and the request proceeds. TEST_F(CorsURLLoaderPrivateNetworkAccessTest, PolicyWarnSimpleNetError) { … } // This test verifies that when: // // - the private network request policy is set to `kPreflightWarn` // - a simple request detects a private network request // - the following PNA preflight response takes forever to arrive // // ... a short timeout is applied, the error ignored and the request proceeds. TEST_F(CorsURLLoaderPrivateNetworkAccessTest, PolicyWarnSimpleTimeout) { … } // This test verifies that when: // // - the private network request policy is set to `kPreflightWarn` // - a CORS preflight request detects a private network request // - the following PNA preflight response takes forever to arrive // // ... we wait as long as it takes for the response to arrive. TEST_F(CorsURLLoaderPrivateNetworkAccessTest, PolicyWarnPreflightNoTimeout) { … } // This test verifies that when: // // - the private network request policy is set to `kPreflightBlock` // - a simple request detects a private network request // - the following PNA preflight response takes forever to arrive // // ... we wait as long as it takes for the response to arrive. TEST_F(CorsURLLoaderPrivateNetworkAccessTest, PolicyBlockPreflightNoTimeout) { … } // This test verifies that when: // // - the private network request policy is set to `kPreflightWarn` // - a simple request detects a private network request // - the following PNA preflight fails due to a non-PNA CORS error // // ... the error is ignored and the request proceeds. TEST_F(CorsURLLoaderPrivateNetworkAccessTest, PolicyWarnSimpleCorsError) { … } // This test verifies that when: // // - the private network request policy is set to `kPreflightWarn` // - a simple request detects a private network request // - the following PNA preflight fails due to a missing PNA header // // ... the error is ignored and the request proceeds. TEST_F(CorsURLLoaderPrivateNetworkAccessTest, PolicyWarnSimpleMissingAllowPrivateNetwork) { … } // This test verifies that when: // // - the private network request policy is set to `kPreflightWarn` // - a simple request detects a private network request // - the following PNA preflight fails due to an invalid PNA header // // ... the error is ignored and the request proceeds. TEST_F(CorsURLLoaderPrivateNetworkAccessTest, PolicyWarnSimpleInvalidAllowPrivateNetwork) { … } // This test verifies that when: // // - the private network request policy is set to `kPreflightWarn` // - a CORS preflight request detects a private network request // - the following PNA preflight fails due to a network error // // ... the error is not ignored and the request is failed. TEST_F(CorsURLLoaderPrivateNetworkAccessTest, PolicyWarnPreflightNetError) { … } // This test verifies that when: // // - the private network request policy is set to `kPreflightWarn` // - a CORS preflight request detects a private network request // - the following PNA preflight fails due to a non-PNA CORS error // // ... the error is not ignored and the request is failed. TEST_F(CorsURLLoaderPrivateNetworkAccessTest, PolicyWarnPreflightCorsError) { … } // This test verifies that when: // // - the private network request policy is set to `kPreflightWarn` // - a CORS preflight request detects a private network request // - the following PNA preflight fails due to a missing PNA header // // ... the error is ignored and the request proceeds. TEST_F(CorsURLLoaderPrivateNetworkAccessTest, PolicyWarnPreflightMissingAllowPrivateNetwork) { … } // Returns a PUT request for a resource from `initiator_origin`. // // `devtools_observer` will receive mojo messages about events concerning the // request. ResourceRequest MakeSameOriginPutRequest( const url::Origin& initiator_origin, MockDevToolsObserver& devtools_observer) { … } // This test verifies that when: // // - the private network request policy is set to `kPreflightWarn` // - the request mode is set to `kCors` // - the request is not "simple" // - the request is same-origin with the initiator (so no CORS preflight) // - the initial request detects a private network request // - the following PNA preflight fails due to a net error // // ... the error is ignored and the request proceeds. TEST_F(CorsURLLoaderPrivateNetworkAccessTest, PolicyWarnSameOriginNetError) { … } // This test verifies that when: // // - the private network request policy is set to `kPreflightWarn` // - the request mode is set to `kCors` // - the request is not "simple" // - the request is same-origin with the initiator (so no CORS preflight) // - the initial request detects a private network request // - the following PNA preflight fails due to a non-PNA CORS error // // ... the error is ignored and the request proceeds. TEST_F(CorsURLLoaderPrivateNetworkAccessTest, PolicyWarnSameOriginCorsError) { … } // This test verifies that when: // // - the private network request policy is set to `kPreflightWarn` // - the request mode is set to `kCors` // - the request is not "simple" // - the request is same-origin with the initiator (so no CORS preflight) // - the initial request detects a private network request // - the following PNA preflight fails due to missing PNA header // // ... the error is ignored and the request proceeds. TEST_F(CorsURLLoaderPrivateNetworkAccessTest, PolicyWarnSameOriginMissingAllowPrivateNetwork) { … } // The following `PrivateNetworkAccessPolicyBlock*` tests verify that PNA // preflights must succeed for the overall request to succeed when the private // network request policy is set to `kPreflightBlock`. // This test verifies that when: // // - the private network request policy is set to `kPreflightBlock` // - a private network request is detected // - the following PNA preflight fails due to a network error // // ... the error is not ignored and the request is failed. TEST_F(CorsURLLoaderPrivateNetworkAccessTest, PolicyBlockNetError) { … } // This test verifies that when: // // - the private network request policy is set to `kPreflightBlock` // - a simple request detects a private network request // - the following PNA preflight fails due to a non-PNA CORS error // // ... the error is not ignored and the request is failed. TEST_F(CorsURLLoaderPrivateNetworkAccessTest, PolicyBlockCorsError) { … } // This test verifies that when: // // - the private network request policy is set to `kPreflightBlock` // - a simple request detects a private network request // - the following PNA preflight fails due to a missing PNA header // // ... the error is ignored and the request proceeds. TEST_F(CorsURLLoaderPrivateNetworkAccessTest, PolicyBlockMissingAllowPrivateNetwork) { … } // This test verifies that when: // // - the private network request policy is set to `kPreflightWarn` // - a simple request detects a private network request // - the following PNA preflight fails due to an invalid PNA header // // ... the error is ignored and the request proceeds. TEST_F(CorsURLLoaderPrivateNetworkAccessTest, PolicyBlockInvalidAllowPrivateNetwork) { … } // The following `PrivateNetworkAccessPolicyOn*` tests verify that the private // network request policy can be set on the loader factory params or the request // itself, with preference given to the factory params. // This test verifies that when the `ResourceRequest` carries a client security // state and the loader factory params do not, the private network request // policy is taken from the request. // // This is achieved by setting the request policy to `kPreflightBlock` and // checking that preflight results are respected. TEST_F(CorsURLLoaderPrivateNetworkAccessTest, PolicyOnRequestOnly) { … } // This test verifies that when the loader factory params carry a client // security state and the `ResourceRequest` does not, the private network // request policy is taken from the factory params. // // This is achieved by setting the factory policy to `kPreflightBlock` and // checking that preflight results are respected. TEST_F(CorsURLLoaderPrivateNetworkAccessTest, PolicyOnFactoryOnly) { … } // This test verifies that when both the `ResourceRequest` and the loader // factory params carry a client security state, the private network request // policy is taken from the factory. // // This is achieved by setting the factory policy to `kPreflightBlock`, // the request policy to `kPreflightWarn, and checking that preflight results // are respected. TEST_F(CorsURLLoaderPrivateNetworkAccessTest, PolicyOnFactoryAndRequest) { … } TEST_F(CorsURLLoaderPrivateNetworkAccessTest, NoPermissionPromptForNonPnaPreflights) { … } } // namespace } // namespace network::cors