blob: 67380a495d40ad6e3bcbdc1592f21ab29eed330c [file] [log] [blame]
// 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.
#ifndef CHROME_BROWSER_SSL_HTTPS_UPGRADES_INTERCEPTOR_H_
#define CHROME_BROWSER_SSL_HTTPS_UPGRADES_INTERCEPTOR_H_
#include <memory>
#include <optional>
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/sequence_checker.h"
#include "chrome/browser/ssl/https_only_mode_tab_helper.h"
#include "components/security_interstitials/core/https_only_mode_metrics.h"
#include "content/public/browser/url_loader_request_interceptor.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "mojo/public/cpp/system/data_pipe.h"
#include "net/base/request_priority.h"
#include "net/http/http_request_headers.h"
#include "services/network/public/cpp/resource_request.h"
#include "services/network/public/cpp/url_loader_completion_status.h"
#include "services/network/public/mojom/url_loader.mojom.h"
#include "url/gurl.h"
namespace blink {
class ThrottlingURLLoader;
} // namespace blink
namespace content {
class BrowserContext;
class NavigationUIData;
class WebContents;
} // namespace content
// A class that attempts to intercept HTTP navigation requests and redirect them
// to HTTPS, and then if the upgraded requests fail redirect them back to HTTP.
// Its lifetime matches that of the content/ navigation loader code.
//
// (Aside: An alternate implementation of this class would be as a
// NavigationLoaderInterceptor in content/, which could have a slightly simpler
// implementation, but by having this in chrome/ we don't need a Delegate
// interface for the embedder logic. If we move this into content/ in the future
// -- for example, in order to have a default HTTPS Upgrades implementation in
// the content/ platform -- then we can make that switch.)
class HttpsUpgradesInterceptor : public content::URLLoaderRequestInterceptor,
public network::mojom::URLLoader {
public:
static std::unique_ptr<HttpsUpgradesInterceptor> MaybeCreateInterceptor(
content::FrameTreeNodeId frame_tree_node_id,
content::NavigationUIData* navigation_ui_data_);
HttpsUpgradesInterceptor(content::FrameTreeNodeId frame_tree_node_id,
bool http_interstitial_enabled,
content::NavigationUIData* navigation_ui_data_);
~HttpsUpgradesInterceptor() override;
HttpsUpgradesInterceptor(const HttpsUpgradesInterceptor&) = delete;
HttpsUpgradesInterceptor& operator=(const HttpsUpgradesInterceptor&) = delete;
// content::URLLoaderRequestInterceptor:
void MaybeCreateLoader(
const network::ResourceRequest& tentative_resource_request,
content::BrowserContext* browser_context,
content::URLLoaderRequestInterceptor::LoaderCallback callback) override;
bool MaybeCreateLoaderForResponse(
const network::URLLoaderCompletionStatus& status,
const network::ResourceRequest& request,
network::mojom::URLResponseHeadPtr* response_head,
mojo::ScopedDataPipeConsumerHandle* response_body,
mojo::PendingRemote<network::mojom::URLLoader>* loader,
mojo::PendingReceiver<network::mojom::URLLoaderClient>* client_receiver,
blink::ThrottlingURLLoader* url_loader) override;
// Continuation of MaybeCreateLoader() after querying the network service for
// the HSTS status for the hostname in the request.
void MaybeCreateLoaderOnHstsQueryCompleted(
const network::ResourceRequest& tentative_resource_request,
content::URLLoaderRequestInterceptor::LoaderCallback callback,
bool is_hsts_active_for_host);
// Sets the ports used by the EmbeddedTestServer (which uses random ports)
// to determine the correct port to upgrade/fallback to in tests.
static void SetHttpsPortForTesting(int port);
static void SetHttpPortForTesting(int port);
static int GetHttpsPortForTesting();
static int GetHttpPortForTesting();
private:
// network::mojom::URLLoader:
void FollowRedirect(
const std::vector<std::string>& removed_headers,
const net::HttpRequestHeaders& modified_headers,
const net::HttpRequestHeaders& modified_cors_exempt_headers,
const std::optional<GURL>& new_url) override {}
void SetPriority(net::RequestPriority priority,
int intra_priority_value) override {}
// Returns a RequestHandler callback that can be passed to the underlying
// LoaderCallback to serve an artificial redirect to `new_url`.
RequestHandler CreateRedirectHandler(const GURL& new_url);
// Passed to the LoaderCallback as the ResponseHandler with `new_url` bound,
// this method receives the receiver and client_remote from the
// NavigationLoader, to bind against. Triggers a redirect to `new_url` using
// `client`.
void RedirectHandler(
const GURL& new_url,
const network::ResourceRequest& request,
mojo::PendingReceiver<network::mojom::URLLoader> receiver,
mojo::PendingRemote<network::mojom::URLLoaderClient> client);
// Mojo error handling. Resets `receiver_` and `client_`.
void OnConnectionClosed();
// Used to access the WebContents for the navigation.
content::FrameTreeNodeId frame_tree_node_id_;
// Controls whether we are upgrading and falling back with an interstitial
// before proceeding with the HTTP navigation. This reflects the general
// UI setting. Only used to set the values of interstitial_state_.
bool http_interstitial_enabled_by_pref_ = false;
// Parameters about whether the throttle should trigger the interstitial
// warning before navigating to the HTTP fallback URL. Can be null if the
// current load isn't eligible for an upgrade.
std::unique_ptr<
security_interstitials::https_only_mode::HttpInterstitialState>
interstitial_state_;
// URLs seen by the interceptor, used to detect a redirect loop.
std::set<GURL> urls_seen_;
// Receiver for the URLLoader interface.
mojo::Receiver<network::mojom::URLLoader> receiver_{this};
// The owning client. Used for serving redirects.
mojo::Remote<network::mojom::URLLoaderClient> client_;
// Owned by NavigationURLLoaderImpl, which should outlive the interceptor.
raw_ptr<content::NavigationUIData> navigation_ui_data_;
SEQUENCE_CHECKER(sequence_checker_);
base::WeakPtrFactory<HttpsUpgradesInterceptor> weak_factory_{this};
};
#endif // CHROME_BROWSER_SSL_HTTPS_UPGRADES_INTERCEPTOR_H_