Commit 6b2f6390 authored by Ryan Sturm's avatar Ryan Sturm Committed by Chromium LUCI CQ

Service worker navigation preload can use Search Prefetch requests

The service worker navigation preload is issued as part of a Service
Worker navigation URLLoader interceptor. In a similar vein, Search
Prefetch uses the same type of interceptor, but at lower priority.

Once Service Worker has decided to intercept the navigation (generally,
this means there is a fetch handler), it issues a direct network service request to get
the resource when navigation preload is enabled in the service worker.
This means lower priority interceptors are never consulted (i.e., app
cache is not consulted, which is good; search prefetch is not consulted,
which is not ideal).

This CL adds functionality to handle synchronous interception decisions,
but stops short of copying the interception logic in the navigation
pathway that handles asynchronous decisions with multiple interceptors.


Bug: 1155330

Change-Id: Iae225c0b4926946a4ec9fccc5dc5d240dc53c058
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2570392
Commit-Queue: Ryan Sturm <ryansturm@chromium.org>
Reviewed-by: default avatarMatt Falkenhagen <falken@chromium.org>
Reviewed-by: default avatarMakoto Shimazu <shimazu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#835364}
parent ae365c95
......@@ -103,6 +103,7 @@
#include "chrome/browser/prefetch/search_prefetch/field_trial_settings.h"
#include "chrome/browser/prefetch/search_prefetch/search_prefetch_service.h"
#include "chrome/browser/prefetch/search_prefetch/search_prefetch_service_factory.h"
#include "chrome/browser/prefetch/search_prefetch/search_prefetch_url_loader.h"
#include "chrome/browser/prefetch/search_prefetch/search_prefetch_url_loader_interceptor.h"
#include "chrome/browser/previews/previews_content_util.h"
#include "chrome/browser/previews/previews_service.h"
......@@ -4806,6 +4807,33 @@ ChromeContentBrowserClient::WillCreateURLLoaderRequestInterceptors(
return interceptors;
}
content::ContentBrowserClient::URLLoaderRequestHandler
ChromeContentBrowserClient::
CreateURLLoaderHandlerForServiceWorkerNavigationPreload(
int frame_tree_node_id,
const network::ResourceRequest& resource_request) {
content::ContentBrowserClient::URLLoaderRequestHandler callback;
// If search prefetch is disabled, nothing needs to be handled.
if (!SearchPrefetchServiceIsEnabled()) {
return callback;
}
std::unique_ptr<SearchPrefetchURLLoader> loader =
SearchPrefetchURLLoaderInterceptor::MaybeCreateLoaderForRequest(
resource_request, frame_tree_node_id);
if (!loader) {
return callback;
}
auto* raw_loader = loader.get();
// Hand ownership of the loader to the callback, when it runs, mojo will
// manage it. If the callback is deleted, the loader will be deleted.
callback = raw_loader->ServingResponseHandler(std::move(loader));
return callback;
}
bool ChromeContentBrowserClient::WillInterceptWebSocket(
content::RenderFrameHost* frame) {
#if BUILDFLAG(ENABLE_EXTENSIONS)
......
......@@ -499,6 +499,10 @@ class ChromeContentBrowserClient : public content::ContentBrowserClient {
int frame_tree_node_id,
const scoped_refptr<network::SharedURLLoaderFactory>&
network_loader_factory) override;
content::ContentBrowserClient::URLLoaderRequestHandler
CreateURLLoaderHandlerForServiceWorkerNavigationPreload(
int frame_tree_node_id,
const network::ResourceRequest& resource_request) override;
bool WillInterceptWebSocket(content::RenderFrameHost* frame) override;
void CreateWebSocket(
content::RenderFrameHost* frame,
......
......@@ -78,21 +78,27 @@ void SearchPrefetchFromStringURLLoader::TransferRawData() {
}
SearchPrefetchURLLoader::RequestHandler
SearchPrefetchFromStringURLLoader::ServingResponseHandler() {
SearchPrefetchFromStringURLLoader::ServingResponseHandler(
std::unique_ptr<SearchPrefetchURLLoader> loader) {
return base::BindOnce(&SearchPrefetchFromStringURLLoader::BindAndStart,
weak_ptr_factory_.GetWeakPtr());
weak_ptr_factory_.GetWeakPtr(), std::move(loader));
}
void SearchPrefetchFromStringURLLoader::BindAndStart(
std::unique_ptr<SearchPrefetchURLLoader> loader,
const network::ResourceRequest& request,
mojo::PendingReceiver<network::mojom::URLLoader> receiver,
mojo::PendingRemote<network::mojom::URLLoaderClient> client) {
DCHECK(!receiver_.is_bound());
// At this point, we are bound to the mojo receiver, so we can release
// |loader|, which points to |this|.
receiver_.Bind(std::move(receiver));
receiver_.set_disconnect_handler(
base::BindOnce(&SearchPrefetchFromStringURLLoader::OnMojoDisconnect,
weak_ptr_factory_.GetWeakPtr()));
client_.Bind(std::move(client));
loader.release();
mojo::ScopedDataPipeProducerHandle producer_handle;
mojo::ScopedDataPipeConsumerHandle consumer_handle;
......
......@@ -43,7 +43,8 @@ class SearchPrefetchFromStringURLLoader : public network::mojom::URLLoader,
const SearchPrefetchFromStringURLLoader&) = delete;
// SearchPrefetchURLLoader:
SearchPrefetchURLLoader::RequestHandler ServingResponseHandler() override;
SearchPrefetchURLLoader::RequestHandler ServingResponseHandler(
std::unique_ptr<SearchPrefetchURLLoader> loader) override;
private:
// network::mojom::URLLoader:
......@@ -58,8 +59,11 @@ class SearchPrefetchFromStringURLLoader : public network::mojom::URLLoader,
void ResumeReadingBodyFromNet() override;
// Binds |this| to the mojo handlers and starts the network request using
// |request|. After this method is called, |this| manages its own lifetime.
// |request|. After this method is called, |this| manages its own lifetime;
// |loader| points to |this| and can be released once the mojo connection is
// set up.
void BindAndStart(
std::unique_ptr<SearchPrefetchURLLoader> loader,
const network::ResourceRequest& request,
mojo::PendingReceiver<network::mojom::URLLoader> url_loader_receiver,
mojo::PendingRemote<network::mojom::URLLoaderClient> forwarding_client);
......
......@@ -37,6 +37,8 @@
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browsing_data_filter_builder.h"
#include "content/public/browser/browsing_data_remover.h"
#include "content/public/browser/service_worker_context.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/common/content_client.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
......@@ -49,6 +51,7 @@
#include "net/test/embedded_test_server/http_request.h"
#include "net/test/embedded_test_server/http_response.h"
#include "third_party/blink/public/common/loader/url_loader_throttle.h"
#include "third_party/blink/public/mojom/service_worker/service_worker_registration_options.mojom.h"
#include "url/gurl.h"
namespace {
......@@ -61,6 +64,7 @@ constexpr char kLoadInSubframe[] = "/load_in_subframe";
constexpr char kClientHintsURL[] = "/accept_ch_with_lifetime.html";
constexpr char kThrottleHeader[] = "porgs-header";
constexpr char kThrottleHeaderValue[] = "porgs-header-value";
constexpr char kServiceWorkerUrl[] = "/navigation_preload.js";
} // namespace
// A response that hangs after serving the start of the response.
......@@ -358,6 +362,14 @@ class SearchPrefetchBaseBrowserTest : public InProcessBrowserTest {
DevToolsWindowTesting::CloseDevToolsWindowSync(window_);
}
// Allows the search server to serve |content| with |content_type| when
// |relative_url| is requested.
void RegisterStaticFile(const std::string& relative_url,
const std::string& content,
const std::string& content_type) {
static_files_[relative_url] = std::make_pair(content, content_type);
}
private:
std::unique_ptr<net::test_server::HttpResponse> HandleSearchRequest(
const net::test_server::HttpRequest& request) {
......@@ -384,6 +396,15 @@ class SearchPrefetchBaseBrowserTest : public InProcessBrowserTest {
MonitorSearchResourceRequestOnUIThread,
base::Unretained(this), request, is_prefetch));
if (base::Contains(static_files_, request.relative_url)) {
std::unique_ptr<net::test_server::BasicHttpResponse> resp =
std::make_unique<net::test_server::BasicHttpResponse>();
resp->set_code(net::HTTP_OK);
resp->set_content(static_files_[request.relative_url].first);
resp->set_content_type(static_files_[request.relative_url].second);
return resp;
}
// If this is an embedded search for load in iframe, parse out the iframe
// URL and serve it as an iframe in the returned HTML.
if (request.relative_url.find(kLoadInSubframe) == 0) {
......@@ -509,6 +530,11 @@ class SearchPrefetchBaseBrowserTest : public InProcessBrowserTest {
// When set to true, serves a response that hangs after the start of the body.
bool hang_requests_after_start_ = false;
// Test cases can add path, content, content type tuples to be served.
std::map<std::string /* path */,
std::pair<std::string /* content */, std::string /* content_type */>>
static_files_;
DevToolsWindow* window_ = nullptr;
};
......@@ -1606,6 +1632,77 @@ IN_PROC_BROWSER_TEST_P(SearchPrefetchServiceEnabledBrowserTest,
}));
}
void RunFirstParam(base::RepeatingClosure closure, bool success) {
ASSERT_TRUE(success);
closure.Run();
}
IN_PROC_BROWSER_TEST_P(SearchPrefetchServiceEnabledBrowserTest,
ServiceWorkerServedPrefetchWithPreload) {
const GURL worker_url = GetSearchServerQueryURLWithNoQuery(kServiceWorkerUrl);
const std::string kEnableNavigationPreloadScript = R"(
self.addEventListener('activate', event => {
event.waitUntil(self.registration.navigationPreload.enable());
});
self.addEventListener('fetch', event => {
if (event.preloadResponse !== undefined) {
event.respondWith(async function() {
const response = await event.preloadResponse;
if (response) return response;
return fetch(event.request);
});
}
});)";
std::string search_terms = "prefetch_content";
GURL prefetch_url = GetSearchServerQueryURL(search_terms);
RegisterStaticFile(kServiceWorkerUrl, kEnableNavigationPreloadScript,
"text/javascript");
auto* service_worker_context =
browser()
->profile()
->GetDefaultStoragePartition(browser()->profile())
->GetServiceWorkerContext();
base::RunLoop run_loop;
blink::mojom::ServiceWorkerRegistrationOptions options(
GetSearchServerQueryURLWithNoQuery("/"),
blink::mojom::ScriptType::kClassic,
blink::mojom::ServiceWorkerUpdateViaCache::kImports);
service_worker_context->RegisterServiceWorker(
worker_url, options,
base::BindOnce(&RunFirstParam, run_loop.QuitClosure()));
run_loop.Run();
auto* search_prefetch_service =
SearchPrefetchServiceFactory::GetForProfile(browser()->profile());
EXPECT_NE(nullptr, search_prefetch_service);
EXPECT_TRUE(search_prefetch_service->MaybePrefetchURL(prefetch_url));
auto prefetch_status =
search_prefetch_service->GetSearchPrefetchStatusForTesting(
base::ASCIIToUTF16(search_terms));
WaitUntilStatusChanges(base::ASCIIToUTF16(search_terms));
prefetch_status = search_prefetch_service->GetSearchPrefetchStatusForTesting(
base::ASCIIToUTF16(search_terms));
ASSERT_TRUE(prefetch_status.has_value());
EXPECT_EQ(SearchPrefetchStatus::kCanBeServed, prefetch_status.value());
ui_test_utils::NavigateToURL(browser(), prefetch_url);
auto inner_html = GetDocumentInnerHTML();
EXPECT_FALSE(base::Contains(inner_html, "regular"));
EXPECT_TRUE(base::Contains(inner_html, "prefetch"));
prefetch_status = search_prefetch_service->GetSearchPrefetchStatusForTesting(
base::ASCIIToUTF16(search_terms));
EXPECT_FALSE(prefetch_status.has_value());
}
// True means that responses are streamed, false means full responses must be
// received in order to server the response.
INSTANTIATE_TEST_SUITE_P(All,
......
......@@ -5,6 +5,8 @@
#ifndef CHROME_BROWSER_PREFETCH_SEARCH_PREFETCH_SEARCH_PREFETCH_URL_LOADER_H_
#define CHROME_BROWSER_PREFETCH_SEARCH_PREFETCH_SEARCH_PREFETCH_URL_LOADER_H_
#include <memory>
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "services/network/public/mojom/url_loader.mojom.h"
......@@ -22,7 +24,12 @@ class SearchPrefetchURLLoader {
mojo::PendingRemote<network::mojom::URLLoaderClient> client)>;
// Called when the response should be served to the user. Returns a handler.
virtual RequestHandler ServingResponseHandler() = 0;
// |loader| is the owning pointer to |this|. It needs to be stored within the
// returned |RequestHandler| to allow |this| to be owned by the callback.
// This allows ownership until the callback is run, which then should have
// ownership owned via a mojo connection.
virtual RequestHandler ServingResponseHandler(
std::unique_ptr<SearchPrefetchURLLoader> loader) = 0;
};
#endif // CHROME_BROWSER_PREFETCH_SEARCH_PREFETCH_SEARCH_PREFETCH_URL_LOADER_H_
......@@ -21,18 +21,6 @@
#include "content/public/browser/storage_partition.h"
#include "content/public/browser/web_contents.h"
namespace {
Profile* ProfileFromFrameTreeNodeID(int frame_tree_node_id) {
content::WebContents* web_contents =
content::WebContents::FromFrameTreeNodeId(frame_tree_node_id);
if (!web_contents)
return nullptr;
return Profile::FromBrowserContext(web_contents->GetBrowserContext());
}
} // namespace
SearchPrefetchURLLoaderInterceptor::SearchPrefetchURLLoaderInterceptor(
int frame_tree_node_id)
: frame_tree_node_id_(frame_tree_node_id) {}
......@@ -40,55 +28,26 @@ SearchPrefetchURLLoaderInterceptor::SearchPrefetchURLLoaderInterceptor(
SearchPrefetchURLLoaderInterceptor::~SearchPrefetchURLLoaderInterceptor() =
default;
void SearchPrefetchURLLoaderInterceptor::MaybeCreateLoader(
// static
std::unique_ptr<SearchPrefetchURLLoader>
SearchPrefetchURLLoaderInterceptor::MaybeCreateLoaderForRequest(
const network::ResourceRequest& tentative_resource_request,
content::BrowserContext* browser_context,
content::URLLoaderRequestInterceptor::LoaderCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(!loader_callback_);
loader_callback_ = std::move(callback);
int frame_tree_node_id) {
content::WebContents* web_contents =
content::WebContents::FromFrameTreeNodeId(frame_tree_node_id_);
content::WebContents::FromFrameTreeNodeId(frame_tree_node_id);
// Make sure this is for a navigation.
if (!web_contents) {
DoNotInterceptPrefetchedNavigation();
return;
return nullptr;
}
// Only intercept main frame requests.
content::RenderFrameHost* main_frame = web_contents->GetMainFrame();
if (!main_frame || main_frame->GetFrameTreeNodeId() != frame_tree_node_id_) {
DoNotInterceptPrefetchedNavigation();
return;
}
url_ = tentative_resource_request.url;
std::unique_ptr<SearchPrefetchURLLoader> prefetch =
GetPrefetchedResponse(url_);
if (!prefetch) {
DoNotInterceptPrefetchedNavigation();
return;
if (!main_frame || main_frame->GetFrameTreeNodeId() != frame_tree_node_id) {
return nullptr;
}
InterceptPrefetchedNavigation(std::move(prefetch));
}
void SearchPrefetchURLLoaderInterceptor::InterceptPrefetchedNavigation(
std::unique_ptr<SearchPrefetchURLLoader> prefetch) {
std::move(loader_callback_).Run(prefetch->ServingResponseHandler());
// url_loader manages its own lifetime once bound to the mojo pipes.
prefetch.release();
}
void SearchPrefetchURLLoaderInterceptor::DoNotInterceptPrefetchedNavigation() {
std::move(loader_callback_).Run({});
}
std::unique_ptr<SearchPrefetchURLLoader>
SearchPrefetchURLLoaderInterceptor::GetPrefetchedResponse(const GURL& url) {
auto* profile = ProfileFromFrameTreeNodeID(frame_tree_node_id_);
auto* profile =
Profile::FromBrowserContext(web_contents->GetBrowserContext());
if (!profile)
return nullptr;
......@@ -97,5 +56,28 @@ SearchPrefetchURLLoaderInterceptor::GetPrefetchedResponse(const GURL& url) {
if (!service)
return nullptr;
return service->TakePrefetchResponse(url);
return service->TakePrefetchResponse(tentative_resource_request.url);
}
void SearchPrefetchURLLoaderInterceptor::MaybeCreateLoader(
const network::ResourceRequest& tentative_resource_request,
content::BrowserContext* browser_context,
content::URLLoaderRequestInterceptor::LoaderCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
std::unique_ptr<SearchPrefetchURLLoader> prefetch =
MaybeCreateLoaderForRequest(tentative_resource_request,
frame_tree_node_id_);
if (!prefetch) {
std::move(callback).Run({});
return;
}
auto* raw_prefetch = prefetch.get();
// Hand ownership of the loader to the callback, when the callback runs,
// mojo connection termination will manage it. If the callback is deleted,
// the loader will be deleted.
std::move(callback).Run(
raw_prefetch->ServingResponseHandler(std::move(prefetch)));
}
......@@ -35,34 +35,25 @@ class SearchPrefetchURLLoaderInterceptor
SearchPrefetchURLLoaderInterceptor& operator=(
const SearchPrefetchURLLoaderInterceptor&) = delete;
// Creates a SearchPrefetchURLLoader if there is a prefetched response able to
// be served to |tentative_resource_request|,.
static std::unique_ptr<SearchPrefetchURLLoader> MaybeCreateLoaderForRequest(
const network::ResourceRequest& tentative_resource_request,
int frame_tree_node_id);
// content::URLLaoderRequestInterceptor:
void MaybeCreateLoader(
const network::ResourceRequest& tentative_resource_request,
content::BrowserContext* browser_context,
content::URLLoaderRequestInterceptor::LoaderCallback callback) override;
protected:
// Virtual for testing
virtual std::unique_ptr<SearchPrefetchURLLoader> GetPrefetchedResponse(
const GURL& url);
private:
void InterceptPrefetchedNavigation(
std::unique_ptr<SearchPrefetchURLLoader> prefetch);
void DoNotInterceptPrefetchedNavigation();
bool MaybeInterceptNavigation(
const network::ResourceRequest& tentative_resource_request);
// Used to get the current WebContents/Profile.
const int frame_tree_node_id_;
// The url that |MaybeCreateLoader| is called with.
GURL url_;
// Set in |MaybeCreateLoader| and used in |On[DoNot]InterceptRequest|.
content::URLLoaderRequestInterceptor::LoaderCallback loader_callback_;
SEQUENCE_CHECKER(sequence_checker_);
};
......
......@@ -50,14 +50,16 @@ StreamingSearchPrefetchURLLoader::StreamingSearchPrefetchURLLoader(
StreamingSearchPrefetchURLLoader::~StreamingSearchPrefetchURLLoader() = default;
SearchPrefetchURLLoader::RequestHandler
StreamingSearchPrefetchURLLoader::ServingResponseHandler() {
StreamingSearchPrefetchURLLoader::ServingResponseHandler(
std::unique_ptr<SearchPrefetchURLLoader> loader) {
DCHECK(!streaming_prefetch_request_);
return base::BindOnce(
&StreamingSearchPrefetchURLLoader::SetUpForwardingClient,
weak_factory_.GetWeakPtr());
weak_factory_.GetWeakPtr(), std::move(loader));
}
void StreamingSearchPrefetchURLLoader::SetUpForwardingClient(
std::unique_ptr<SearchPrefetchURLLoader> loader,
const network::ResourceRequest& resource_request,
mojo::PendingReceiver<network::mojom::URLLoader> receiver,
mojo::PendingRemote<network::mojom::URLLoaderClient> forwarding_client) {
......@@ -67,10 +69,14 @@ void StreamingSearchPrefetchURLLoader::SetUpForwardingClient(
network_url_loader_->SetPriority(resource_request.priority, -1);
// At this point, we are bound to the mojo receiver, so we can release
// |loader|, which points to |this|.
receiver_.Bind(std::move(receiver));
receiver_.set_disconnect_handler(
base::BindOnce(&StreamingSearchPrefetchURLLoader::OnMojoDisconnect,
weak_factory_.GetWeakPtr()));
loader.release();
forwarding_client_.Bind(std::move(forwarding_client));
if (!resource_request.report_raw_headers) {
......
......@@ -46,7 +46,8 @@ class StreamingSearchPrefetchURLLoader : public network::mojom::URLLoader,
private:
// SearchPrefetchURLLoader:
SearchPrefetchURLLoader::RequestHandler ServingResponseHandler() override;
SearchPrefetchURLLoader::RequestHandler ServingResponseHandler(
std::unique_ptr<SearchPrefetchURLLoader> loader) override;
// network::mojom::URLLoader:
void FollowRedirect(
......@@ -78,8 +79,11 @@ class StreamingSearchPrefetchURLLoader : public network::mojom::URLLoader,
// Sets up mojo forwarding to the navigation path. Resumes
// |network_url_loader_| calls. Serves the start of the response to the
// navigation path.
// navigation path. After this method is called, |this| manages its own
// lifetime; |loader| points to |this| and can be released once the mojo
// connection is set up.
void SetUpForwardingClient(
std::unique_ptr<SearchPrefetchURLLoader> loader,
const network::ResourceRequest&,
mojo::PendingReceiver<network::mojom::URLLoader> receiver,
mojo::PendingRemote<network::mojom::URLLoaderClient> forwarding_client);
......
......@@ -18,6 +18,7 @@
#include "content/browser/devtools/service_worker_devtools_agent_host.h"
#include "content/browser/devtools/service_worker_devtools_manager.h"
#include "content/browser/loader/navigation_url_loader_impl.h"
#include "content/browser/loader/single_request_url_loader_factory.h"
#include "content/browser/renderer_host/frame_tree_node.h"
#include "content/browser/renderer_host/navigation_request.h"
#include "content/browser/service_worker/embedded_worker_status.h"
......@@ -757,6 +758,21 @@ bool ServiceWorkerFetchDispatcher::MaybeStartNavigationPreload(
url_loader_client->Bind(&url_loader_client_to_pass);
mojo::PendingRemote<network::mojom::URLLoader> url_loader;
// Allow the embedder to intercept the URLLoader request if necessary. This
// must be a synchronous decision by the embedder. In the future, we may wish
// to support asynchronous decisions using |URLLoaderRequestInterceptor| in
// the same fashion that they are used for navigation requests.
ContentBrowserClient::URLLoaderRequestHandler embedder_url_loader_handler =
GetContentClient()
->browser()
->CreateURLLoaderHandlerForServiceWorkerNavigationPreload(
frame_tree_node_id, resource_request);
if (!embedder_url_loader_handler.is_null()) {
factory = base::MakeRefCounted<content::SingleRequestURLLoaderFactory>(
std::move(embedder_url_loader_handler));
}
factory->CreateLoaderAndStart(
url_loader.InitWithNewPipeAndPassReceiver(), -1 /* routing_id? */,
GlobalRequestID::MakeBrowserInitiated().request_id,
......
......@@ -808,6 +808,13 @@ ContentBrowserClient::WillCreateURLLoaderRequestInterceptors(
return std::vector<std::unique_ptr<URLLoaderRequestInterceptor>>();
}
ContentBrowserClient::URLLoaderRequestHandler
ContentBrowserClient::CreateURLLoaderHandlerForServiceWorkerNavigationPreload(
int frame_tree_node_id,
const network::ResourceRequest& resource_request) {
return ContentBrowserClient::URLLoaderRequestHandler();
}
void ContentBrowserClient::OnNetworkServiceCreated(
network::mojom::NetworkService* network_service) {}
......
......@@ -123,6 +123,8 @@ enum class OriginPolicyState;
class SharedURLLoaderFactory;
namespace mojom {
class TrustedHeaderClient;
class URLLoader;
class URLLoaderClient;
} // namespace mojom
} // namespace network
......@@ -250,7 +252,7 @@ class CONTENT_EXPORT ContentBrowserClient {
using IsClipboardPasteAllowedCallback =
base::OnceCallback<void(ClipboardPasteAllowed)>;
virtual ~ContentBrowserClient() {}
virtual ~ContentBrowserClient() = default;
// Allows the embedder to set any number of custom BrowserMainParts
// implementations for the browser startup code. See comments in
......@@ -1453,6 +1455,24 @@ class CONTENT_EXPORT ContentBrowserClient {
const scoped_refptr<network::SharedURLLoaderFactory>&
network_loader_factory);
// Callback to handle a request for a URLLoader.
using URLLoaderRequestHandler = base::OnceCallback<void(
const network::ResourceRequest& resource_request,
mojo::PendingReceiver<network::mojom::URLLoader> url_loader_receiver,
mojo::PendingRemote<network::mojom::URLLoaderClient> client)>;
// Allows the embedder to return a callback that is capable of loading a
// service worker navigation preload request. Similar to
// |WillCreateURLLoaderRequestInterceptors()|, but only allows for synchronous
// decisions of whether to handle the preload request with no fallback. As a
// result of being synchronous, the embedder can decide which, if there are
// multiple, URLLoader handlers is appropriate. If the embedder returns a null
// callback, the default behavior will be used to fetch the request.
virtual URLLoaderRequestHandler
CreateURLLoaderHandlerForServiceWorkerNavigationPreload(
int frame_tree_node_id,
const network::ResourceRequest& resource_request);
// Called when the NetworkService, accessible through
// content::GetNetworkService(), is created. Implementations should avoid
// calling into GetNetworkService() again to avoid re-entrancy if the service
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment