| // Copyright 2018 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef SERVICES_NETWORK_CORS_PREFLIGHT_CONTROLLER_H_ |
| #define SERVICES_NETWORK_CORS_PREFLIGHT_CONTROLLER_H_ |
| |
| #include <memory> |
| #include <optional> |
| #include <string> |
| |
| #include "base/component_export.h" |
| #include "base/containers/unique_ptr_adapters.h" |
| #include "base/functional/callback.h" |
| #include "base/memory/raw_ptr.h" |
| #include "base/memory/weak_ptr.h" |
| #include "base/types/expected.h" |
| #include "base/types/strong_alias.h" |
| #include "mojo/public/cpp/bindings/remote.h" |
| #include "net/traffic_annotation/network_traffic_annotation.h" |
| #include "services/network/cors/preflight_cache.h" |
| #include "services/network/cors/preflight_result.h" |
| #include "services/network/public/cpp/cors/cors_error_status.h" |
| #include "services/network/public/cpp/resource_request.h" |
| #include "services/network/public/mojom/clear_data_filter.mojom-forward.h" |
| #include "services/network/public/mojom/fetch_api.mojom.h" |
| #include "services/network/public/mojom/url_loader_factory.mojom.h" |
| #include "services/network/public/mojom/url_response_head.mojom-forward.h" |
| #include "url/gurl.h" |
| |
| namespace net { |
| class NetLogWithSource; |
| } // namespace net |
| |
| namespace network { |
| |
| class NetworkService; |
| |
| namespace cors { |
| |
| // A class to manage CORS-preflight, making a CORS-preflight request, checking |
| // its result, and owning a CORS-preflight cache. |
| class COMPONENT_EXPORT(NETWORK_SERVICE) PreflightController final { |
| public: |
| // Called with the result of `PerformPreflightCheck()`. |
| // |
| // `net_error` is the overall result of the operation. |
| // |
| // `cors_error_status` contains additional details about CORS-specific errors. |
| // Invariant: `cors_error_status` is nullopt if `net_error` is neither |
| // `net::ERR_FAILED` nor `net::OK`. |
| // If `net_error` is `net::OK`, then `cors_error_status` may be non-nullopt to |
| // indicate a warning-only error arose due to Private Network Access. |
| // TODO(crbug.com/40204695): Once PNA preflights are always enforced, |
| // stop populating `cors_error_status` when `net_error` is `net::OK`. |
| // |
| // `has_autorization_covered_by_wildcard` is true iff the request carries an |
| // "authorization" header and that header is covered by the wildcard in the |
| // preflight response. |
| // TODO(crbug.com/40168475): Remove |
| // `has_authorization_covered_by_wildcard` once the investigation is done. |
| using CompletionCallback = |
| base::OnceCallback<void(int net_error, |
| std::optional<CorsErrorStatus> cors_error_status, |
| bool has_authorization_covered_by_wildcard)>; |
| |
| using WithTrustedHeaderClient = |
| base::StrongAlias<class WithTrustedHeaderClientTag, bool>; |
| |
| // Creates a CORS-preflight ResourceRequest for a specified `request` for a |
| // URL that is originally requested. |
| static std::unique_ptr<ResourceRequest> CreatePreflightRequestForTesting( |
| const ResourceRequest& request, |
| bool tainted = false); |
| |
| // Creates a PreflightResult for a specified response parameters for testing. |
| static std::unique_ptr<PreflightResult> CreatePreflightResultForTesting( |
| const GURL& final_url, |
| const mojom::URLResponseHead& head, |
| const ResourceRequest& original_request, |
| bool tainted, |
| std::optional<CorsErrorStatus>* detected_error_status); |
| |
| // Checks CORS aceess on the CORS-preflight response parameters for testing. |
| static base::expected<void, CorsErrorStatus> CheckPreflightAccessForTesting( |
| const GURL& response_url, |
| const int response_status_code, |
| const std::optional<std::string>& allow_origin_header, |
| const std::optional<std::string>& allow_credentials_header, |
| mojom::CredentialsMode actual_credentials_mode, |
| const url::Origin& origin); |
| |
| explicit PreflightController(NetworkService* network_service); |
| |
| PreflightController(const PreflightController&) = delete; |
| PreflightController& operator=(const PreflightController&) = delete; |
| |
| ~PreflightController(); |
| |
| // Determines if a CORS-preflight request is needed, and checks the cache, or |
| // makes a preflight request if it is needed. A result will be notified |
| // synchronously or asynchronously. |
| void PerformPreflightCheck( |
| CompletionCallback callback, |
| int32_t request_id, |
| const ResourceRequest& resource_request, |
| WithTrustedHeaderClient with_trusted_header_client, |
| NonWildcardRequestHeadersSupport non_wildcard_request_headers_support, |
| bool tainted, |
| const net::NetworkTrafficAnnotationTag& traffic_annotation, |
| mojom::URLLoaderFactory* loader_factory, |
| const net::IsolationInfo& isolation_info, |
| mojom::ClientSecurityStatePtr client_security_state, |
| base::WeakPtr<mojo::Remote<mojom::DevToolsObserver>> devtools_observer, |
| const net::NetLogWithSource& net_log, |
| bool acam_preflight_spec_conformant, |
| mojo::PendingRemote<mojom::URLLoaderNetworkServiceObserver> |
| url_loader_network_service_observer); |
| |
| // Clears the CORS preflight cache. The time range is always "all time" as |
| // the preflight cache max age is capped to 2hrs. in Chrome. |
| // It clears origins selectively when the url filter is not null, otherwise |
| // clears all its contents. |
| void ClearCorsPreflightCache(mojom::ClearDataFilterPtr url_filter); |
| |
| PreflightCache& GetPreflightCacheForTesting() { return cache_; } |
| |
| private: |
| class PreflightLoader; |
| |
| void RemoveLoader(PreflightLoader* loader); |
| void AppendToCache(const url::Origin& origin, |
| const GURL& url, |
| const net::NetworkIsolationKey& network_isolation_key, |
| std::unique_ptr<PreflightResult> result); |
| |
| NetworkService* network_service() { return network_service_; } |
| |
| PreflightCache cache_; |
| std::set<std::unique_ptr<PreflightLoader>, base::UniquePtrComparator> |
| loaders_; |
| |
| const raw_ptr<NetworkService> network_service_; |
| }; |
| |
| } // namespace cors |
| |
| } // namespace network |
| |
| #endif // SERVICES_NETWORK_CORS_PREFLIGHT_CONTROLLER_H_ |