Skip to content

Commit

Permalink
Pass prefetched signed exchanges to renderer process
Browse files Browse the repository at this point in the history
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/+/1600438
Reviewed-by: Kinuko Yasuda <kinuko@chromium.org>
Reviewed-by: Kunihiko Sakamoto <ksakamoto@chromium.org>
Commit-Queue: Tsuyoshi Horo <horo@chromium.org>
Cr-Commit-Position: refs/heads/master@{#659318}
  • Loading branch information
horo-t authored and Commit Bot committed May 14, 2019
1 parent bb9ce98 commit eaf3b29
Show file tree
Hide file tree
Showing 14 changed files with 241 additions and 12 deletions.
7 changes: 7 additions & 0 deletions content/browser/frame_host/navigation_request.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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_,
Expand Down
3 changes: 2 additions & 1 deletion content/browser/frame_host/navigation_request.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
106 changes: 95 additions & 11 deletions content/browser/loader/prefetched_signed_exchange_cache.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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 {}

Expand All @@ -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()));
Expand All @@ -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.
return base::nullopt;
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) {
Expand All @@ -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) {
Expand All @@ -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_;

Expand Down Expand Up @@ -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
2 changes: 2 additions & 0 deletions content/browser/loader/prefetched_signed_exchange_cache.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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_;

Expand Down
1 change: 1 addition & 0 deletions content/browser/navigation_subresource_loader_params.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
9 changes: 9 additions & 0 deletions content/browser/navigation_subresource_loader_params.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions content/common/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
27 changes: 27 additions & 0 deletions content/common/content_param_traits.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
11 changes: 11 additions & 0 deletions content/common/content_param_traits.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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_
9 changes: 9 additions & 0 deletions content/common/frame_messages.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down
5 changes: 5 additions & 0 deletions content/common/navigation_params.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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
Expand Down
25 changes: 25 additions & 0 deletions content/common/prefetched_signed_exchange_info.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// 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
Loading

0 comments on commit eaf3b29

Please sign in to comment.