blob: 48ea63f3b44ae73c684716da5117341b8de31997 [file] [log] [blame]
Kinuko Yasudadb67b532018-02-19 09:11:521// Copyright 2018 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "content/browser/loader/prefetch_url_loader.h"
6
Sebastien Marchandf8cbfab2019-01-25 16:02:307#include "base/bind.h"
Kinuko Yasuda8edb92462018-02-21 15:46:578#include "base/feature_list.h"
Tsuyoshi Horo242ee8f2019-04-26 06:37:079#include "content/browser/loader/prefetched_signed_exchange_cache.h"
10#include "content/browser/loader/prefetched_signed_exchange_cache_adapter.h"
Kunihiko Sakamoto66b91d42018-06-15 08:29:2211#include "content/browser/web_package/signed_exchange_prefetch_handler.h"
Kouhei Ueno8a58a982018-10-11 03:37:3112#include "content/browser/web_package/signed_exchange_prefetch_metric_recorder.h"
Tsuyoshi Horo46f5fff2018-05-10 12:33:3513#include "content/browser/web_package/signed_exchange_utils.h"
Kinuko Yasuda8edb92462018-02-21 15:46:5714#include "content/public/common/content_features.h"
Kinuko Yasudaeeae6972018-02-20 08:38:1115#include "net/url_request/url_request_context_getter.h"
Tsuyoshi Horo60be6b12018-09-29 04:28:1816#include "services/network/loader_util.h"
Kinuko Yasuda8edb92462018-02-21 15:46:5717#include "services/network/public/cpp/features.h"
Chong Zhangb7c8d1ce2018-03-13 19:14:1118#include "services/network/public/cpp/shared_url_loader_factory.h"
Kinuko Yasudaeeae6972018-02-20 08:38:1119
Kinuko Yasudadb67b532018-02-19 09:11:5220namespace content {
21
Tsuyoshi Horo60be6b12018-09-29 04:28:1822namespace {
23
24constexpr char kSignedExchangeEnabledAcceptHeaderForPrefetch[] =
Kunihiko Sakamotod6373b2d2019-01-23 04:09:4325 "application/signed-exchange;v=b3;q=0.9,*/*;q=0.8";
Tsuyoshi Horo60be6b12018-09-29 04:28:1826
27} // namespace
28
Kinuko Yasudadb67b532018-02-19 09:11:5229PrefetchURLLoader::PrefetchURLLoader(
30 int32_t routing_id,
31 int32_t request_id,
32 uint32_t options,
Tsuyoshi Horo4801e762018-04-25 07:36:5733 base::RepeatingCallback<int(void)> frame_tree_node_id_getter,
Kinuko Yasudadb67b532018-02-19 09:11:5234 const network::ResourceRequest& resource_request,
35 network::mojom::URLLoaderClientPtr client,
36 const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
Chong Zhangb7c8d1ce2018-03-13 19:14:1137 scoped_refptr<network::SharedURLLoaderFactory> network_loader_factory,
Kinuko Yasudaeeae6972018-02-20 08:38:1138 URLLoaderThrottlesGetter url_loader_throttles_getter,
39 ResourceContext* resource_context,
Kouhei Ueno8a58a982018-10-11 03:37:3140 scoped_refptr<net::URLRequestContextGetter> request_context_getter,
41 scoped_refptr<SignedExchangePrefetchMetricRecorder>
Kunihiko Sakamoto7d0f5bd62019-02-28 05:43:2142 signed_exchange_prefetch_metric_recorder,
Tsuyoshi Horo242ee8f2019-04-26 06:37:0743 scoped_refptr<PrefetchedSignedExchangeCache>
44 prefetched_signed_exchange_cache,
45 base::WeakPtr<storage::BlobStorageContext> blob_storage_context,
Kunihiko Sakamoto7d0f5bd62019-02-28 05:43:2146 const std::string& accept_langs)
Tsuyoshi Horo4801e762018-04-25 07:36:5747 : frame_tree_node_id_getter_(frame_tree_node_id_getter),
Tsuyoshi Horod0a953d2019-01-23 04:38:1448 resource_request_(resource_request),
Tsuyoshi Horocdbb4902018-04-12 06:09:1449 network_loader_factory_(std::move(network_loader_factory)),
Kinuko Yasuda8edb92462018-02-21 15:46:5750 client_binding_(this),
Kinuko Yasudaeeae6972018-02-20 08:38:1151 forwarding_client_(std::move(client)),
52 url_loader_throttles_getter_(url_loader_throttles_getter),
53 resource_context_(resource_context),
Kouhei Ueno8a58a982018-10-11 03:37:3154 request_context_getter_(std::move(request_context_getter)),
55 signed_exchange_prefetch_metric_recorder_(
Kunihiko Sakamoto7d0f5bd62019-02-28 05:43:2156 std::move(signed_exchange_prefetch_metric_recorder)),
57 accept_langs_(accept_langs) {
Kinuko Yasuda8edb92462018-02-21 15:46:5758 DCHECK(network_loader_factory_);
Kinuko Yasudadb67b532018-02-19 09:11:5259
Kunihiko Sakamotof586da62019-03-28 03:03:0460 if (signed_exchange_utils::IsSignedExchangeHandlingEnabled(
61 resource_context_)) {
Kunihiko Sakamoto50ed8305b2019-02-22 04:02:3162 // Set the SignedExchange accept header.
Tsuyoshi Horo60be6b12018-09-29 04:28:1863 // (https://wicg.github.io/webpackage/draft-yasskin-http-origin-signed-responses.html#internet-media-type-applicationsigned-exchange).
Tsuyoshi Horod0a953d2019-01-23 04:38:1464 resource_request_.headers.SetHeader(
Tsuyoshi Horo60be6b12018-09-29 04:28:1865 network::kAcceptHeader, kSignedExchangeEnabledAcceptHeaderForPrefetch);
Tsuyoshi Horo242ee8f2019-04-26 06:37:0766
67 if (prefetched_signed_exchange_cache) {
68 DCHECK(base::FeatureList::IsEnabled(
69 features::kSignedExchangeSubresourcePrefetch));
70 prefetched_signed_exchange_cache_adapter_ =
71 std::make_unique<PrefetchedSignedExchangeCacheAdapter>(
72 std::move(prefetched_signed_exchange_cache),
73 std::move(blob_storage_context), resource_request.url, this);
74 }
Tsuyoshi Horo60be6b12018-09-29 04:28:1875 }
76
Kinuko Yasudadb67b532018-02-19 09:11:5277 network::mojom::URLLoaderClientPtr network_client;
Kinuko Yasuda8edb92462018-02-21 15:46:5778 client_binding_.Bind(mojo::MakeRequest(&network_client));
79 client_binding_.set_connection_error_handler(base::BindOnce(
Kinuko Yasudadb67b532018-02-19 09:11:5280 &PrefetchURLLoader::OnNetworkConnectionError, base::Unretained(this)));
Kinuko Yasuda8edb92462018-02-21 15:46:5781 network_loader_factory_->CreateLoaderAndStart(
82 mojo::MakeRequest(&loader_), routing_id, request_id, options,
Tsuyoshi Horod0a953d2019-01-23 04:38:1483 resource_request_, std::move(network_client), traffic_annotation);
Kinuko Yasudadb67b532018-02-19 09:11:5284}
85
86PrefetchURLLoader::~PrefetchURLLoader() = default;
87
Chong Zhangf19dde92018-05-23 04:33:5988void PrefetchURLLoader::FollowRedirect(
Arthur Sonzogni62a4f4352019-01-07 16:37:2589 const std::vector<std::string>& removed_headers,
90 const net::HttpRequestHeaders& modified_headers,
John Abd-El-Malekc16f6732018-11-22 05:06:4991 const base::Optional<GURL>& new_url) {
Jun Cai23627f042019-01-17 05:09:1092 DCHECK(modified_headers.IsEmpty())
Arthur Sonzogni62a4f4352019-01-07 16:37:2593 << "Redirect with modified headers was not supported yet. "
94 "crbug.com/845683";
95 DCHECK(!new_url) << "Redirect with modified URL was not "
96 "supported yet. crbug.com/845683";
Kunihiko Sakamoto66b91d42018-06-15 08:29:2297 if (signed_exchange_prefetch_handler_) {
Kinuko Yasuda8edb92462018-02-21 15:46:5798 // Rebind |client_binding_| and |loader_|.
Kunihiko Sakamoto66b91d42018-06-15 08:29:2299 client_binding_.Bind(signed_exchange_prefetch_handler_->FollowRedirect(
Kinuko Yasuda8edb92462018-02-21 15:46:57100 mojo::MakeRequest(&loader_)));
101 return;
102 }
103
Kinuko Yasuda39fcea92019-02-04 09:52:28104 DCHECK(loader_);
Kunihiko Sakamoto50ed8305b2019-02-22 04:02:31105 loader_->FollowRedirect(removed_headers,
106 net::HttpRequestHeaders() /* modified_headers */,
Jun Cai23627f042019-01-17 05:09:10107 base::nullopt);
Kinuko Yasudadb67b532018-02-19 09:11:52108}
109
110void PrefetchURLLoader::ProceedWithResponse() {
Kinuko Yasuda39fcea92019-02-04 09:52:28111 if (loader_)
112 loader_->ProceedWithResponse();
Kinuko Yasudadb67b532018-02-19 09:11:52113}
114
115void PrefetchURLLoader::SetPriority(net::RequestPriority priority,
116 int intra_priority_value) {
Kinuko Yasuda39fcea92019-02-04 09:52:28117 if (loader_)
118 loader_->SetPriority(priority, intra_priority_value);
Kinuko Yasudadb67b532018-02-19 09:11:52119}
120
121void PrefetchURLLoader::PauseReadingBodyFromNet() {
Kinuko Yasuda39fcea92019-02-04 09:52:28122 // TODO(kinuko): Propagate or handle the case where |loader_| is
123 // detached (for SignedExchanges), see OnReceiveResponse.
124 if (loader_)
125 loader_->PauseReadingBodyFromNet();
Kinuko Yasudadb67b532018-02-19 09:11:52126}
127
128void PrefetchURLLoader::ResumeReadingBodyFromNet() {
Kinuko Yasuda39fcea92019-02-04 09:52:28129 // TODO(kinuko): Propagate or handle the case where |loader_| is
130 // detached (for SignedExchanges), see OnReceiveResponse.
131 if (loader_)
132 loader_->ResumeReadingBodyFromNet();
Kinuko Yasudadb67b532018-02-19 09:11:52133}
134
135void PrefetchURLLoader::OnReceiveResponse(
Marijn Kruisselbrink9ebd7ba2018-06-11 23:18:04136 const network::ResourceResponseHead& response) {
Kunihiko Sakamotof586da62019-03-28 03:03:04137 if (signed_exchange_utils::IsSignedExchangeHandlingEnabled(
138 resource_context_) &&
139 signed_exchange_utils::ShouldHandleAsSignedHTTPExchange(
Tsuyoshi Horod0a953d2019-01-23 04:38:14140 resource_request_.url, response)) {
Kunihiko Sakamoto66b91d42018-06-15 08:29:22141 DCHECK(!signed_exchange_prefetch_handler_);
Tsuyoshi Horo242ee8f2019-04-26 06:37:07142 if (prefetched_signed_exchange_cache_adapter_) {
143 prefetched_signed_exchange_cache_adapter_->OnReceiveOuterResponse(
144 response);
145 }
Kinuko Yasuda8edb92462018-02-21 15:46:57146 // Note that after this point this doesn't directly get upcalls from the
147 // network. (Until |this| calls the handler's FollowRedirect.)
Kunihiko Sakamoto66b91d42018-06-15 08:29:22148 signed_exchange_prefetch_handler_ =
149 std::make_unique<SignedExchangePrefetchHandler>(
Tsuyoshi Horod0a953d2019-01-23 04:38:14150 frame_tree_node_id_getter_, resource_request_, response,
151 std::move(loader_), client_binding_.Unbind(),
152 network_loader_factory_, url_loader_throttles_getter_,
Kouhei Ueno8a58a982018-10-11 03:37:31153 resource_context_, request_context_getter_, this,
Kunihiko Sakamoto7d0f5bd62019-02-28 05:43:21154 signed_exchange_prefetch_metric_recorder_, accept_langs_);
Kinuko Yasuda8edb92462018-02-21 15:46:57155 return;
156 }
Tsuyoshi Horo242ee8f2019-04-26 06:37:07157 if (prefetched_signed_exchange_cache_adapter_ &&
158 signed_exchange_prefetch_handler_) {
159 prefetched_signed_exchange_cache_adapter_->OnReceiveInnerResponse(response);
160 }
161
Marijn Kruisselbrink9ebd7ba2018-06-11 23:18:04162 forwarding_client_->OnReceiveResponse(response);
Kinuko Yasudadb67b532018-02-19 09:11:52163}
164
165void PrefetchURLLoader::OnReceiveRedirect(
166 const net::RedirectInfo& redirect_info,
167 const network::ResourceResponseHead& head) {
Tsuyoshi Horo242ee8f2019-04-26 06:37:07168 if (prefetched_signed_exchange_cache_adapter_ &&
169 signed_exchange_prefetch_handler_) {
170 prefetched_signed_exchange_cache_adapter_->OnReceiveRedirect(
171 redirect_info.new_url,
172 signed_exchange_prefetch_handler_->ComputeHeaderIntegrity());
173 }
174
Tsuyoshi Horod0a953d2019-01-23 04:38:14175 resource_request_.url = redirect_info.new_url;
176 resource_request_.site_for_cookies = redirect_info.new_site_for_cookies;
177 resource_request_.top_frame_origin = redirect_info.new_top_frame_origin;
178 resource_request_.referrer = GURL(redirect_info.new_referrer);
179 resource_request_.referrer_policy = redirect_info.new_referrer_policy;
Kinuko Yasudadb67b532018-02-19 09:11:52180 forwarding_client_->OnReceiveRedirect(redirect_info, head);
181}
182
Kinuko Yasudadb67b532018-02-19 09:11:52183void PrefetchURLLoader::OnUploadProgress(int64_t current_position,
184 int64_t total_size,
185 base::OnceCallback<void()> callback) {
186 forwarding_client_->OnUploadProgress(current_position, total_size,
187 std::move(callback));
188}
189
190void PrefetchURLLoader::OnReceiveCachedMetadata(
191 const std::vector<uint8_t>& data) {
192 // Just drop this; we don't need to forward this to the renderer
193 // for prefetch.
194}
195
196void PrefetchURLLoader::OnTransferSizeUpdated(int32_t transfer_size_diff) {
197 forwarding_client_->OnTransferSizeUpdated(transfer_size_diff);
198}
199
200void PrefetchURLLoader::OnStartLoadingResponseBody(
201 mojo::ScopedDataPipeConsumerHandle body) {
Tsuyoshi Horo242ee8f2019-04-26 06:37:07202 if (prefetched_signed_exchange_cache_adapter_ &&
203 signed_exchange_prefetch_handler_) {
204 prefetched_signed_exchange_cache_adapter_->OnStartLoadingResponseBody(
205 std::move(body));
206 return;
207 }
208
Arthur Sonzogni63f924d2018-12-05 08:45:26209 // Just drain the original response's body here.
Kinuko Yasudadb67b532018-02-19 09:11:52210 DCHECK(!pipe_drainer_);
211 pipe_drainer_ =
Oksana Zhuravlova10e89832018-03-30 21:49:14212 std::make_unique<mojo::DataPipeDrainer>(this, std::move(body));
Arthur Sonzogni63f924d2018-12-05 08:45:26213
Tsuyoshi Horo242ee8f2019-04-26 06:37:07214 SendEmptyBody();
Kinuko Yasudadb67b532018-02-19 09:11:52215}
216
217void PrefetchURLLoader::OnComplete(
218 const network::URLLoaderCompletionStatus& status) {
Tsuyoshi Horo242ee8f2019-04-26 06:37:07219 if (prefetched_signed_exchange_cache_adapter_ &&
220 signed_exchange_prefetch_handler_) {
221 prefetched_signed_exchange_cache_adapter_->OnComplete(status);
222 return;
223 }
224
225 SendOnComplete(status);
226}
227
228bool PrefetchURLLoader::SendEmptyBody() {
229 // Send an empty response's body.
230 mojo::ScopedDataPipeProducerHandle producer;
231 mojo::ScopedDataPipeConsumerHandle consumer;
232 if (CreateDataPipe(nullptr, &producer, &consumer) != MOJO_RESULT_OK) {
233 // No more resources available for creating a data pipe. Close the
234 // connection, which will in turn make this loader destroyed.
235 forwarding_client_->OnComplete(
236 network::URLLoaderCompletionStatus(net::ERR_INSUFFICIENT_RESOURCES));
237 forwarding_client_.reset();
238 client_binding_.Close();
239 return false;
240 }
241 forwarding_client_->OnStartLoadingResponseBody(std::move(consumer));
242 return true;
243}
244
245void PrefetchURLLoader::SendOnComplete(
246 const network::URLLoaderCompletionStatus& completion_status) {
247 forwarding_client_->OnComplete(completion_status);
Kinuko Yasudadb67b532018-02-19 09:11:52248}
249
250void PrefetchURLLoader::OnNetworkConnectionError() {
251 // The network loader has an error; we should let the client know it's closed
252 // by dropping this, which will in turn make this loader destroyed.
253 forwarding_client_.reset();
254}
255
256} // namespace content