Commit eaf3b29f authored by Tsuyoshi Horo's avatar Tsuyoshi Horo Committed by Commit Bot

Pass prefetched signed exchanges to renderer process

This CL introduces PrefetchedSignedExchangeInfo struct, which keeps the
information about a prefetched signed exchange. It is created in
PrefetchedSignedExchangeCache and passed to SubresourceLoaderParams and will be
passed to the renderer process in CommitNavigation IPC's CommitNavigationParams.

Bug: 935267
Change-Id: Id67c2ce99801f6c89d679cf9efaf65617d68cdfa
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1600438Reviewed-by: default avatarKinuko Yasuda <kinuko@chromium.org>
Reviewed-by: default avatarKunihiko Sakamoto <ksakamoto@chromium.org>
Commit-Queue: Tsuyoshi Horo <horo@chromium.org>
Cr-Commit-Position: refs/heads/master@{#659318}
parent bb9ce980
......@@ -2037,6 +2037,13 @@ void NavigationRequest::CommitNavigation() {
render_frame_host_->GetProcess()->GetID(),
render_frame_host_->GetRoutingID(), &service_worker_provider_info);
}
if (subresource_loader_params_ &&
!subresource_loader_params_->prefetched_signed_exchanges.empty()) {
DCHECK(base::FeatureList::IsEnabled(
features::kSignedExchangeSubresourcePrefetch));
commit_params_.prefetched_signed_exchanges =
std::move(subresource_loader_params_->prefetched_signed_exchanges);
}
render_frame_host_->CommitNavigation(
this, response_.get(), std::move(url_loader_client_endpoints_),
common_params_, commit_params_, is_view_source_,
......
......@@ -753,7 +753,8 @@ class CONTENT_EXPORT NavigationRequest : public NavigationURLLoaderDelegate,
base::Closure on_start_checks_complete_closure_;
// Used in the network service world to pass the subressource loader params
// to the renderer. Used by AppCache and ServiceWorker.
// to the renderer. Used by AppCache and ServiceWorker, and
// SignedExchangeSubresourcePrefetch.
base::Optional<SubresourceLoaderParams> subresource_loader_params_;
// See comment on accessor.
......
......@@ -208,15 +208,70 @@ class InnerResponseURLLoader : public network::mojom::URLLoader {
DISALLOW_COPY_AND_ASSIGN(InnerResponseURLLoader);
};
// A URLLoaderFactory which handles a signed exchange subresource request from
// renderer process.
class SubresourceSignedExchangeURLLoaderFactory
: public network::mojom::URLLoaderFactory {
public:
SubresourceSignedExchangeURLLoaderFactory(
network::mojom::URLLoaderFactoryRequest request,
std::unique_ptr<const PrefetchedSignedExchangeCache::Entry> entry)
: entry_(std::move(entry)) {
bindings_.AddBinding(this, std::move(request));
bindings_.set_connection_error_handler(base::BindRepeating(
&SubresourceSignedExchangeURLLoaderFactory::OnConnectionError,
base::Unretained(this)));
}
~SubresourceSignedExchangeURLLoaderFactory() override {}
// network::mojom::URLLoaderFactory implementation.
void CreateLoaderAndStart(network::mojom::URLLoaderRequest loader,
int32_t routing_id,
int32_t request_id,
uint32_t options,
const network::ResourceRequest& request,
network::mojom::URLLoaderClientPtr client,
const net::MutableNetworkTrafficAnnotationTag&
traffic_annotation) override {
// TODO(crbug.com/935267): Implement CORS check.
DCHECK_EQ(request.url, entry_->inner_url());
mojo::MakeStrongBinding(
std::make_unique<InnerResponseURLLoader>(
*entry_->inner_response(),
std::make_unique<const storage::BlobDataHandle>(
*entry_->blob_data_handle()),
*entry_->completion_status(), std::move(client)),
std::move(loader));
}
void Clone(network::mojom::URLLoaderFactoryRequest request) override {
bindings_.AddBinding(this, std::move(request));
}
private:
void OnConnectionError() {
if (!bindings_.empty())
return;
delete this;
}
std::unique_ptr<const PrefetchedSignedExchangeCache::Entry> entry_;
mojo::BindingSet<network::mojom::URLLoaderFactory> bindings_;
DISALLOW_COPY_AND_ASSIGN(SubresourceSignedExchangeURLLoaderFactory);
};
// A NavigationLoaderInterceptor which handles a request which matches the
// prefetched signed exchange that has been stored to a
// PrefetchedSignedExchangeCache.
class PrefetchedNavigationLoaderInterceptor
: public NavigationLoaderInterceptor {
public:
explicit PrefetchedNavigationLoaderInterceptor(
std::unique_ptr<const PrefetchedSignedExchangeCache::Entry> exchange)
: exchange_(std::move(exchange)), weak_factory_(this) {}
PrefetchedNavigationLoaderInterceptor(
std::unique_ptr<const PrefetchedSignedExchangeCache::Entry> exchange,
std::vector<PrefetchedSignedExchangeInfo> info_list)
: exchange_(std::move(exchange)),
info_list_(std::move(info_list)),
weak_factory_(this) {}
~PrefetchedNavigationLoaderInterceptor() override {}
......@@ -229,15 +284,17 @@ class PrefetchedNavigationLoaderInterceptor
// header (eg: HttpVaryData::MatchesRequest()) and Cache-Control header.
// And also we shuold check the expires parameter of the signed exchange's
// signature. TODO(crbug.com/935267): Implement these checking logic.
if (!outer_request_handled_ &&
if (state_ == State::kInitial &&
tentative_resource_request.url == exchange_->outer_url()) {
outer_request_handled_ = true;
state_ = State::kOuterRequestRequested;
std::move(callback).Run(base::BindOnce(
&PrefetchedNavigationLoaderInterceptor::StartRedirectResponse,
weak_factory_.GetWeakPtr()));
return;
}
if (tentative_resource_request.url == exchange_->inner_url()) {
DCHECK_EQ(State::kOuterRequestRequested, state_);
state_ = State::kInnerResponseRequested;
std::move(callback).Run(base::BindOnce(
&PrefetchedNavigationLoaderInterceptor::StartInnerResponse,
weak_factory_.GetWeakPtr()));
......@@ -248,12 +305,21 @@ class PrefetchedNavigationLoaderInterceptor
base::Optional<SubresourceLoaderParams> MaybeCreateSubresourceLoaderParams()
override {
// TODO(crbug.com/935267): Implement this to pass the prefetched signed
// exchanges of subresources to the renderer process.
if (state_ != State::kInnerResponseRequested)
return base::nullopt;
SubresourceLoaderParams params;
params.prefetched_signed_exchanges = std::move(info_list_);
return base::make_optional(std::move(params));
}
private:
enum class State {
kInitial,
kOuterRequestRequested,
kInnerResponseRequested
};
void StartRedirectResponse(const network::ResourceRequest& resource_request,
network::mojom::URLLoaderRequest request,
network::mojom::URLLoaderClientPtr client) {
......@@ -263,6 +329,7 @@ class PrefetchedNavigationLoaderInterceptor
*exchange_->outer_response(), std::move(client)),
std::move(request));
}
void StartInnerResponse(const network::ResourceRequest& resource_request,
network::mojom::URLLoaderRequest request,
network::mojom::URLLoaderClientPtr client) {
......@@ -275,9 +342,9 @@ class PrefetchedNavigationLoaderInterceptor
std::move(request));
}
State state_ = State::kInitial;
std::unique_ptr<const PrefetchedSignedExchangeCache::Entry> exchange_;
bool outer_request_handled_ = false;
std::vector<PrefetchedSignedExchangeInfo> info_list_;
base::WeakPtrFactory<PrefetchedNavigationLoaderInterceptor> weak_factory_;
......@@ -374,7 +441,24 @@ PrefetchedSignedExchangeCache::MaybeCreateInterceptor(const GURL& outer_url) {
if (it == exchanges_.end())
return nullptr;
return std::make_unique<PrefetchedNavigationLoaderInterceptor>(
it->second->Clone());
it->second->Clone(), GetInfoList());
}
std::vector<PrefetchedSignedExchangeInfo>
PrefetchedSignedExchangeCache::GetInfoList() const {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
std::vector<PrefetchedSignedExchangeInfo> info_list;
for (const auto& exchange : exchanges_) {
network::mojom::URLLoaderFactoryPtrInfo loader_factory_info;
new SubresourceSignedExchangeURLLoaderFactory(
mojo::MakeRequest(&loader_factory_info), exchange.second->Clone());
info_list.emplace_back(
exchange.second->outer_url(), *exchange.second->header_integrity(),
exchange.second->inner_url(), *exchange.second->inner_response(),
std::move(loader_factory_info).PassHandle().release());
}
return info_list;
}
} // namespace content
......@@ -9,6 +9,7 @@
#include "base/memory/ref_counted.h"
#include "content/common/content_export.h"
#include "content/common/prefetched_signed_exchange_info.h"
#include "net/base/hash_value.h"
#include "services/network/public/cpp/resource_response.h"
#include "services/network/public/cpp/url_loader_completion_status.h"
......@@ -108,6 +109,7 @@ class CONTENT_EXPORT PrefetchedSignedExchangeCache
using EntryMap = std::map<GURL /* outer_url */, std::unique_ptr<const Entry>>;
~PrefetchedSignedExchangeCache();
std::vector<PrefetchedSignedExchangeInfo> GetInfoList() const;
EntryMap exchanges_;
......
......@@ -21,6 +21,7 @@ SubresourceLoaderParams& SubresourceLoaderParams::operator=(
std::move(other.controller_service_worker_info);
controller_service_worker_object_host =
other.controller_service_worker_object_host;
prefetched_signed_exchanges = std::move(other.prefetched_signed_exchanges);
return *this;
}
......
......@@ -7,6 +7,7 @@
#include "base/memory/weak_ptr.h"
#include "content/common/content_export.h"
#include "content/common/prefetched_signed_exchange_info.h"
#include "services/network/public/mojom/url_loader_factory.mojom.h"
#include "third_party/blink/public/mojom/service_worker/controller_service_worker.mojom.h"
......@@ -41,6 +42,14 @@ struct CONTENT_EXPORT SubresourceLoaderParams {
// ServiceWorkerObjectHost::CreateIncompleteObjectInfo() for details.
blink::mojom::ControllerServiceWorkerInfoPtr controller_service_worker_info;
base::WeakPtr<ServiceWorkerObjectHost> controller_service_worker_object_host;
// For SignedExchangeSubresourcePrefetch.
// When signed exchanges were prefetched in the previous page and were stored
// to the PrefetchedSignedExchangeCache, and the main resource for the
// navigation was served from the cache, |prefetched_signed_exchanges|
// contains the all prefetched signed exchanges and they will be passed to the
// renderer.
std::vector<PrefetchedSignedExchangeInfo> prefetched_signed_exchanges;
};
} // namespace content
......
......@@ -209,6 +209,8 @@ source_set("common") {
"possibly_associated_interface_ptr.h",
"possibly_associated_interface_ptr_info.h",
"possibly_associated_wrapper_shared_url_loader_factory.h",
"prefetched_signed_exchange_info.cc",
"prefetched_signed_exchange_info.h",
"process_type.cc",
"render_widget_surface_properties.cc",
"render_widget_surface_properties.h",
......
......@@ -512,6 +512,33 @@ void ParamTraits<viz::SurfaceInfo>::Log(const param_type& p, std::string* l) {
l->append(")");
}
void ParamTraits<net::SHA256HashValue>::Write(base::Pickle* m,
const param_type& p) {
m->WriteData(reinterpret_cast<const char*>(p.data), sizeof(p.data));
}
bool ParamTraits<net::SHA256HashValue>::Read(const base::Pickle* m,
base::PickleIterator* iter,
param_type* r) {
const char* data;
int data_length;
if (!iter->ReadData(&data, &data_length)) {
NOTREACHED();
return false;
}
if (data_length != sizeof(r->data)) {
NOTREACHED();
return false;
}
memcpy(r->data, data, sizeof(r->data));
return true;
}
void ParamTraits<net::SHA256HashValue>::Log(const param_type& p,
std::string* l) {
l->append("<SHA256HashValue>");
}
} // namespace IPC
// Generate param traits write methods.
......
......@@ -17,6 +17,7 @@
#include "content/common/content_param_traits_macros.h"
#include "content/common/cursors/webcursor.h"
#include "ipc/ipc_mojo_param_traits.h"
#include "net/base/hash_value.h"
#include "storage/common/blob_storage/blob_handle.h"
#include "third_party/blink/public/platform/web_input_event.h"
#include "ui/accessibility/ax_mode.h"
......@@ -175,6 +176,16 @@ struct CONTENT_EXPORT ParamTraits<viz::SurfaceInfo> {
static void Log(const param_type& p, std::string* l);
};
template <>
struct CONTENT_EXPORT ParamTraits<net::SHA256HashValue> {
typedef net::SHA256HashValue param_type;
static void Write(base::Pickle* m, const param_type& p);
static bool Read(const base::Pickle* m,
base::PickleIterator* iter,
param_type* r);
static void Log(const param_type& p, std::string* l);
};
} // namespace IPC
#endif // CONTENT_COMMON_CONTENT_PARAM_TRAITS_H_
......@@ -477,6 +477,14 @@ IPC_STRUCT_TRAITS_BEGIN(content::InitiatorCSPInfo)
IPC_STRUCT_TRAITS_MEMBER(initiator_self_source)
IPC_STRUCT_TRAITS_END()
IPC_STRUCT_TRAITS_BEGIN(content::PrefetchedSignedExchangeInfo)
IPC_STRUCT_TRAITS_MEMBER(outer_url)
IPC_STRUCT_TRAITS_MEMBER(header_integrity)
IPC_STRUCT_TRAITS_MEMBER(inner_url)
IPC_STRUCT_TRAITS_MEMBER(inner_response)
IPC_STRUCT_TRAITS_MEMBER(loader_factory_handle)
IPC_STRUCT_TRAITS_END()
IPC_STRUCT_TRAITS_BEGIN(content::CommonNavigationParams)
IPC_STRUCT_TRAITS_MEMBER(url)
IPC_STRUCT_TRAITS_MEMBER(initiator_origin)
......@@ -531,6 +539,7 @@ IPC_STRUCT_TRAITS_BEGIN(content::CommitNavigationParams)
IPC_STRUCT_TRAITS_MEMBER(appcache_host_id)
IPC_STRUCT_TRAITS_MEMBER(was_activated)
IPC_STRUCT_TRAITS_MEMBER(navigation_token)
IPC_STRUCT_TRAITS_MEMBER(prefetched_signed_exchanges)
#if defined(OS_ANDROID)
IPC_STRUCT_TRAITS_MEMBER(data_url_as_string)
#endif
......
......@@ -19,6 +19,7 @@
#include "content/common/content_security_policy/content_security_policy.h"
#include "content/common/content_security_policy/csp_disposition_enum.h"
#include "content/common/frame_message_enums.h"
#include "content/common/prefetched_signed_exchange_info.h"
#include "content/common/service_worker/service_worker_types.h"
#include "content/public/common/navigation_policy.h"
#include "content/public/common/page_state.h"
......@@ -332,6 +333,10 @@ struct CONTENT_EXPORT CommitNavigationParams {
// same-document browser-initiated navigations are properly handled as well.
base::UnguessableToken navigation_token;
// Prefetched signed exchanges. Used when SignedExchangeSubresourcePrefetch
// feature is enabled.
std::vector<PrefetchedSignedExchangeInfo> prefetched_signed_exchanges;
#if defined(OS_ANDROID)
// The real content of the data: URL. Only used in Android WebView for
// implementing LoadDataWithBaseUrl API method to circumvent the restriction
......
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/common/prefetched_signed_exchange_info.h"
namespace content {
PrefetchedSignedExchangeInfo::PrefetchedSignedExchangeInfo() = default;
PrefetchedSignedExchangeInfo::PrefetchedSignedExchangeInfo(
const PrefetchedSignedExchangeInfo&) = default;
PrefetchedSignedExchangeInfo::PrefetchedSignedExchangeInfo(
const GURL& outer_url,
const net::SHA256HashValue& header_integrity,
const GURL& inner_url,
const network::ResourceResponseHead& inner_response,
mojo::MessagePipeHandle loader_factory_handle)
: outer_url(outer_url),
header_integrity(header_integrity),
inner_url(inner_url),
inner_response(inner_response),
loader_factory_handle(loader_factory_handle) {}
PrefetchedSignedExchangeInfo::~PrefetchedSignedExchangeInfo() = default;
} // namespace content
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_COMMON_PREFETCHED_SIGNED_EXCHANGE_INFO_H_
#define CONTENT_COMMON_PREFETCHED_SIGNED_EXCHANGE_INFO_H_
#include "content/common/content_export.h"
#include "mojo/public/cpp/system/message_pipe.h"
#include "net/base/hash_value.h"
#include "services/network/public/cpp/resource_response.h"
#include "url/gurl.h"
namespace content {
// Used for SignedExchangeSubresourcePrefetch.
// This struct keeps the information about a prefetched signed exchange. It is
// used in CommitNavigationParams to be passed from the browser process to the
// renderer process in CommitNavigation IPC.
struct CONTENT_EXPORT PrefetchedSignedExchangeInfo {
PrefetchedSignedExchangeInfo();
PrefetchedSignedExchangeInfo(const PrefetchedSignedExchangeInfo&);
PrefetchedSignedExchangeInfo(
const GURL& outer_url,
const net::SHA256HashValue& header_integrity,
const GURL& inner_url,
const network::ResourceResponseHead& inner_response,
mojo::MessagePipeHandle loader_factory_handle);
~PrefetchedSignedExchangeInfo();
GURL outer_url;
net::SHA256HashValue header_integrity;
GURL inner_url;
network::ResourceResponseHead inner_response;
mojo::MessagePipeHandle loader_factory_handle;
};
} // namespace content
#endif // CONTENT_COMMON_PREFETCHED_SIGNED_EXCHANGE_INFO_H_
......@@ -489,6 +489,12 @@ void FillNavigationParamsRequest(
}
navigation_params->was_discarded = commit_params.was_discarded;
if (!commit_params.prefetched_signed_exchanges.empty()) {
DCHECK(base::FeatureList::IsEnabled(
features::kSignedExchangeSubresourcePrefetch));
// TODO(crbug.com/935267): Pass the prefetched signed exchanges to Blink.
}
#if defined(OS_ANDROID)
navigation_params->had_transient_activation = common_params.has_user_gesture;
#endif
......
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