Kinuko Yasuda | db67b53 | 2018-02-19 09:11:52 | [diff] [blame] | 1 | // 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 Marchand | f8cbfab | 2019-01-25 16:02:30 | [diff] [blame] | 7 | #include "base/bind.h" |
Kinuko Yasuda | 8edb9246 | 2018-02-21 15:46:57 | [diff] [blame] | 8 | #include "base/feature_list.h" |
Tsuyoshi Horo | 242ee8f | 2019-04-26 06:37:07 | [diff] [blame^] | 9 | #include "content/browser/loader/prefetched_signed_exchange_cache.h" |
| 10 | #include "content/browser/loader/prefetched_signed_exchange_cache_adapter.h" |
Kunihiko Sakamoto | 66b91d4 | 2018-06-15 08:29:22 | [diff] [blame] | 11 | #include "content/browser/web_package/signed_exchange_prefetch_handler.h" |
Kouhei Ueno | 8a58a98 | 2018-10-11 03:37:31 | [diff] [blame] | 12 | #include "content/browser/web_package/signed_exchange_prefetch_metric_recorder.h" |
Tsuyoshi Horo | 46f5fff | 2018-05-10 12:33:35 | [diff] [blame] | 13 | #include "content/browser/web_package/signed_exchange_utils.h" |
Kinuko Yasuda | 8edb9246 | 2018-02-21 15:46:57 | [diff] [blame] | 14 | #include "content/public/common/content_features.h" |
Kinuko Yasuda | eeae697 | 2018-02-20 08:38:11 | [diff] [blame] | 15 | #include "net/url_request/url_request_context_getter.h" |
Tsuyoshi Horo | 60be6b1 | 2018-09-29 04:28:18 | [diff] [blame] | 16 | #include "services/network/loader_util.h" |
Kinuko Yasuda | 8edb9246 | 2018-02-21 15:46:57 | [diff] [blame] | 17 | #include "services/network/public/cpp/features.h" |
Chong Zhang | b7c8d1ce | 2018-03-13 19:14:11 | [diff] [blame] | 18 | #include "services/network/public/cpp/shared_url_loader_factory.h" |
Kinuko Yasuda | eeae697 | 2018-02-20 08:38:11 | [diff] [blame] | 19 | |
Kinuko Yasuda | db67b53 | 2018-02-19 09:11:52 | [diff] [blame] | 20 | namespace content { |
| 21 | |
Tsuyoshi Horo | 60be6b1 | 2018-09-29 04:28:18 | [diff] [blame] | 22 | namespace { |
| 23 | |
| 24 | constexpr char kSignedExchangeEnabledAcceptHeaderForPrefetch[] = |
Kunihiko Sakamoto | d6373b2d | 2019-01-23 04:09:43 | [diff] [blame] | 25 | "application/signed-exchange;v=b3;q=0.9,*/*;q=0.8"; |
Tsuyoshi Horo | 60be6b1 | 2018-09-29 04:28:18 | [diff] [blame] | 26 | |
| 27 | } // namespace |
| 28 | |
Kinuko Yasuda | db67b53 | 2018-02-19 09:11:52 | [diff] [blame] | 29 | PrefetchURLLoader::PrefetchURLLoader( |
| 30 | int32_t routing_id, |
| 31 | int32_t request_id, |
| 32 | uint32_t options, |
Tsuyoshi Horo | 4801e76 | 2018-04-25 07:36:57 | [diff] [blame] | 33 | base::RepeatingCallback<int(void)> frame_tree_node_id_getter, |
Kinuko Yasuda | db67b53 | 2018-02-19 09:11:52 | [diff] [blame] | 34 | const network::ResourceRequest& resource_request, |
| 35 | network::mojom::URLLoaderClientPtr client, |
| 36 | const net::MutableNetworkTrafficAnnotationTag& traffic_annotation, |
Chong Zhang | b7c8d1ce | 2018-03-13 19:14:11 | [diff] [blame] | 37 | scoped_refptr<network::SharedURLLoaderFactory> network_loader_factory, |
Kinuko Yasuda | eeae697 | 2018-02-20 08:38:11 | [diff] [blame] | 38 | URLLoaderThrottlesGetter url_loader_throttles_getter, |
| 39 | ResourceContext* resource_context, |
Kouhei Ueno | 8a58a98 | 2018-10-11 03:37:31 | [diff] [blame] | 40 | scoped_refptr<net::URLRequestContextGetter> request_context_getter, |
| 41 | scoped_refptr<SignedExchangePrefetchMetricRecorder> |
Kunihiko Sakamoto | 7d0f5bd6 | 2019-02-28 05:43:21 | [diff] [blame] | 42 | signed_exchange_prefetch_metric_recorder, |
Tsuyoshi Horo | 242ee8f | 2019-04-26 06:37:07 | [diff] [blame^] | 43 | scoped_refptr<PrefetchedSignedExchangeCache> |
| 44 | prefetched_signed_exchange_cache, |
| 45 | base::WeakPtr<storage::BlobStorageContext> blob_storage_context, |
Kunihiko Sakamoto | 7d0f5bd6 | 2019-02-28 05:43:21 | [diff] [blame] | 46 | const std::string& accept_langs) |
Tsuyoshi Horo | 4801e76 | 2018-04-25 07:36:57 | [diff] [blame] | 47 | : frame_tree_node_id_getter_(frame_tree_node_id_getter), |
Tsuyoshi Horo | d0a953d | 2019-01-23 04:38:14 | [diff] [blame] | 48 | resource_request_(resource_request), |
Tsuyoshi Horo | cdbb490 | 2018-04-12 06:09:14 | [diff] [blame] | 49 | network_loader_factory_(std::move(network_loader_factory)), |
Kinuko Yasuda | 8edb9246 | 2018-02-21 15:46:57 | [diff] [blame] | 50 | client_binding_(this), |
Kinuko Yasuda | eeae697 | 2018-02-20 08:38:11 | [diff] [blame] | 51 | forwarding_client_(std::move(client)), |
| 52 | url_loader_throttles_getter_(url_loader_throttles_getter), |
| 53 | resource_context_(resource_context), |
Kouhei Ueno | 8a58a98 | 2018-10-11 03:37:31 | [diff] [blame] | 54 | request_context_getter_(std::move(request_context_getter)), |
| 55 | signed_exchange_prefetch_metric_recorder_( |
Kunihiko Sakamoto | 7d0f5bd6 | 2019-02-28 05:43:21 | [diff] [blame] | 56 | std::move(signed_exchange_prefetch_metric_recorder)), |
| 57 | accept_langs_(accept_langs) { |
Kinuko Yasuda | 8edb9246 | 2018-02-21 15:46:57 | [diff] [blame] | 58 | DCHECK(network_loader_factory_); |
Kinuko Yasuda | db67b53 | 2018-02-19 09:11:52 | [diff] [blame] | 59 | |
Kunihiko Sakamoto | f586da6 | 2019-03-28 03:03:04 | [diff] [blame] | 60 | if (signed_exchange_utils::IsSignedExchangeHandlingEnabled( |
| 61 | resource_context_)) { |
Kunihiko Sakamoto | 50ed8305b | 2019-02-22 04:02:31 | [diff] [blame] | 62 | // Set the SignedExchange accept header. |
Tsuyoshi Horo | 60be6b1 | 2018-09-29 04:28:18 | [diff] [blame] | 63 | // (https://wicg.github.io/webpackage/draft-yasskin-http-origin-signed-responses.html#internet-media-type-applicationsigned-exchange). |
Tsuyoshi Horo | d0a953d | 2019-01-23 04:38:14 | [diff] [blame] | 64 | resource_request_.headers.SetHeader( |
Tsuyoshi Horo | 60be6b1 | 2018-09-29 04:28:18 | [diff] [blame] | 65 | network::kAcceptHeader, kSignedExchangeEnabledAcceptHeaderForPrefetch); |
Tsuyoshi Horo | 242ee8f | 2019-04-26 06:37:07 | [diff] [blame^] | 66 | |
| 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 Horo | 60be6b1 | 2018-09-29 04:28:18 | [diff] [blame] | 75 | } |
| 76 | |
Kinuko Yasuda | db67b53 | 2018-02-19 09:11:52 | [diff] [blame] | 77 | network::mojom::URLLoaderClientPtr network_client; |
Kinuko Yasuda | 8edb9246 | 2018-02-21 15:46:57 | [diff] [blame] | 78 | client_binding_.Bind(mojo::MakeRequest(&network_client)); |
| 79 | client_binding_.set_connection_error_handler(base::BindOnce( |
Kinuko Yasuda | db67b53 | 2018-02-19 09:11:52 | [diff] [blame] | 80 | &PrefetchURLLoader::OnNetworkConnectionError, base::Unretained(this))); |
Kinuko Yasuda | 8edb9246 | 2018-02-21 15:46:57 | [diff] [blame] | 81 | network_loader_factory_->CreateLoaderAndStart( |
| 82 | mojo::MakeRequest(&loader_), routing_id, request_id, options, |
Tsuyoshi Horo | d0a953d | 2019-01-23 04:38:14 | [diff] [blame] | 83 | resource_request_, std::move(network_client), traffic_annotation); |
Kinuko Yasuda | db67b53 | 2018-02-19 09:11:52 | [diff] [blame] | 84 | } |
| 85 | |
| 86 | PrefetchURLLoader::~PrefetchURLLoader() = default; |
| 87 | |
Chong Zhang | f19dde9 | 2018-05-23 04:33:59 | [diff] [blame] | 88 | void PrefetchURLLoader::FollowRedirect( |
Arthur Sonzogni | 62a4f435 | 2019-01-07 16:37:25 | [diff] [blame] | 89 | const std::vector<std::string>& removed_headers, |
| 90 | const net::HttpRequestHeaders& modified_headers, |
John Abd-El-Malek | c16f673 | 2018-11-22 05:06:49 | [diff] [blame] | 91 | const base::Optional<GURL>& new_url) { |
Jun Cai | 23627f04 | 2019-01-17 05:09:10 | [diff] [blame] | 92 | DCHECK(modified_headers.IsEmpty()) |
Arthur Sonzogni | 62a4f435 | 2019-01-07 16:37:25 | [diff] [blame] | 93 | << "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 Sakamoto | 66b91d4 | 2018-06-15 08:29:22 | [diff] [blame] | 97 | if (signed_exchange_prefetch_handler_) { |
Kinuko Yasuda | 8edb9246 | 2018-02-21 15:46:57 | [diff] [blame] | 98 | // Rebind |client_binding_| and |loader_|. |
Kunihiko Sakamoto | 66b91d4 | 2018-06-15 08:29:22 | [diff] [blame] | 99 | client_binding_.Bind(signed_exchange_prefetch_handler_->FollowRedirect( |
Kinuko Yasuda | 8edb9246 | 2018-02-21 15:46:57 | [diff] [blame] | 100 | mojo::MakeRequest(&loader_))); |
| 101 | return; |
| 102 | } |
| 103 | |
Kinuko Yasuda | 39fcea9 | 2019-02-04 09:52:28 | [diff] [blame] | 104 | DCHECK(loader_); |
Kunihiko Sakamoto | 50ed8305b | 2019-02-22 04:02:31 | [diff] [blame] | 105 | loader_->FollowRedirect(removed_headers, |
| 106 | net::HttpRequestHeaders() /* modified_headers */, |
Jun Cai | 23627f04 | 2019-01-17 05:09:10 | [diff] [blame] | 107 | base::nullopt); |
Kinuko Yasuda | db67b53 | 2018-02-19 09:11:52 | [diff] [blame] | 108 | } |
| 109 | |
| 110 | void PrefetchURLLoader::ProceedWithResponse() { |
Kinuko Yasuda | 39fcea9 | 2019-02-04 09:52:28 | [diff] [blame] | 111 | if (loader_) |
| 112 | loader_->ProceedWithResponse(); |
Kinuko Yasuda | db67b53 | 2018-02-19 09:11:52 | [diff] [blame] | 113 | } |
| 114 | |
| 115 | void PrefetchURLLoader::SetPriority(net::RequestPriority priority, |
| 116 | int intra_priority_value) { |
Kinuko Yasuda | 39fcea9 | 2019-02-04 09:52:28 | [diff] [blame] | 117 | if (loader_) |
| 118 | loader_->SetPriority(priority, intra_priority_value); |
Kinuko Yasuda | db67b53 | 2018-02-19 09:11:52 | [diff] [blame] | 119 | } |
| 120 | |
| 121 | void PrefetchURLLoader::PauseReadingBodyFromNet() { |
Kinuko Yasuda | 39fcea9 | 2019-02-04 09:52:28 | [diff] [blame] | 122 | // TODO(kinuko): Propagate or handle the case where |loader_| is |
| 123 | // detached (for SignedExchanges), see OnReceiveResponse. |
| 124 | if (loader_) |
| 125 | loader_->PauseReadingBodyFromNet(); |
Kinuko Yasuda | db67b53 | 2018-02-19 09:11:52 | [diff] [blame] | 126 | } |
| 127 | |
| 128 | void PrefetchURLLoader::ResumeReadingBodyFromNet() { |
Kinuko Yasuda | 39fcea9 | 2019-02-04 09:52:28 | [diff] [blame] | 129 | // TODO(kinuko): Propagate or handle the case where |loader_| is |
| 130 | // detached (for SignedExchanges), see OnReceiveResponse. |
| 131 | if (loader_) |
| 132 | loader_->ResumeReadingBodyFromNet(); |
Kinuko Yasuda | db67b53 | 2018-02-19 09:11:52 | [diff] [blame] | 133 | } |
| 134 | |
| 135 | void PrefetchURLLoader::OnReceiveResponse( |
Marijn Kruisselbrink | 9ebd7ba | 2018-06-11 23:18:04 | [diff] [blame] | 136 | const network::ResourceResponseHead& response) { |
Kunihiko Sakamoto | f586da6 | 2019-03-28 03:03:04 | [diff] [blame] | 137 | if (signed_exchange_utils::IsSignedExchangeHandlingEnabled( |
| 138 | resource_context_) && |
| 139 | signed_exchange_utils::ShouldHandleAsSignedHTTPExchange( |
Tsuyoshi Horo | d0a953d | 2019-01-23 04:38:14 | [diff] [blame] | 140 | resource_request_.url, response)) { |
Kunihiko Sakamoto | 66b91d4 | 2018-06-15 08:29:22 | [diff] [blame] | 141 | DCHECK(!signed_exchange_prefetch_handler_); |
Tsuyoshi Horo | 242ee8f | 2019-04-26 06:37:07 | [diff] [blame^] | 142 | if (prefetched_signed_exchange_cache_adapter_) { |
| 143 | prefetched_signed_exchange_cache_adapter_->OnReceiveOuterResponse( |
| 144 | response); |
| 145 | } |
Kinuko Yasuda | 8edb9246 | 2018-02-21 15:46:57 | [diff] [blame] | 146 | // Note that after this point this doesn't directly get upcalls from the |
| 147 | // network. (Until |this| calls the handler's FollowRedirect.) |
Kunihiko Sakamoto | 66b91d4 | 2018-06-15 08:29:22 | [diff] [blame] | 148 | signed_exchange_prefetch_handler_ = |
| 149 | std::make_unique<SignedExchangePrefetchHandler>( |
Tsuyoshi Horo | d0a953d | 2019-01-23 04:38:14 | [diff] [blame] | 150 | frame_tree_node_id_getter_, resource_request_, response, |
| 151 | std::move(loader_), client_binding_.Unbind(), |
| 152 | network_loader_factory_, url_loader_throttles_getter_, |
Kouhei Ueno | 8a58a98 | 2018-10-11 03:37:31 | [diff] [blame] | 153 | resource_context_, request_context_getter_, this, |
Kunihiko Sakamoto | 7d0f5bd6 | 2019-02-28 05:43:21 | [diff] [blame] | 154 | signed_exchange_prefetch_metric_recorder_, accept_langs_); |
Kinuko Yasuda | 8edb9246 | 2018-02-21 15:46:57 | [diff] [blame] | 155 | return; |
| 156 | } |
Tsuyoshi Horo | 242ee8f | 2019-04-26 06:37:07 | [diff] [blame^] | 157 | if (prefetched_signed_exchange_cache_adapter_ && |
| 158 | signed_exchange_prefetch_handler_) { |
| 159 | prefetched_signed_exchange_cache_adapter_->OnReceiveInnerResponse(response); |
| 160 | } |
| 161 | |
Marijn Kruisselbrink | 9ebd7ba | 2018-06-11 23:18:04 | [diff] [blame] | 162 | forwarding_client_->OnReceiveResponse(response); |
Kinuko Yasuda | db67b53 | 2018-02-19 09:11:52 | [diff] [blame] | 163 | } |
| 164 | |
| 165 | void PrefetchURLLoader::OnReceiveRedirect( |
| 166 | const net::RedirectInfo& redirect_info, |
| 167 | const network::ResourceResponseHead& head) { |
Tsuyoshi Horo | 242ee8f | 2019-04-26 06:37:07 | [diff] [blame^] | 168 | 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 Horo | d0a953d | 2019-01-23 04:38:14 | [diff] [blame] | 175 | 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 Yasuda | db67b53 | 2018-02-19 09:11:52 | [diff] [blame] | 180 | forwarding_client_->OnReceiveRedirect(redirect_info, head); |
| 181 | } |
| 182 | |
Kinuko Yasuda | db67b53 | 2018-02-19 09:11:52 | [diff] [blame] | 183 | void 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 | |
| 190 | void 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 | |
| 196 | void PrefetchURLLoader::OnTransferSizeUpdated(int32_t transfer_size_diff) { |
| 197 | forwarding_client_->OnTransferSizeUpdated(transfer_size_diff); |
| 198 | } |
| 199 | |
| 200 | void PrefetchURLLoader::OnStartLoadingResponseBody( |
| 201 | mojo::ScopedDataPipeConsumerHandle body) { |
Tsuyoshi Horo | 242ee8f | 2019-04-26 06:37:07 | [diff] [blame^] | 202 | 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 Sonzogni | 63f924d | 2018-12-05 08:45:26 | [diff] [blame] | 209 | // Just drain the original response's body here. |
Kinuko Yasuda | db67b53 | 2018-02-19 09:11:52 | [diff] [blame] | 210 | DCHECK(!pipe_drainer_); |
| 211 | pipe_drainer_ = |
Oksana Zhuravlova | 10e8983 | 2018-03-30 21:49:14 | [diff] [blame] | 212 | std::make_unique<mojo::DataPipeDrainer>(this, std::move(body)); |
Arthur Sonzogni | 63f924d | 2018-12-05 08:45:26 | [diff] [blame] | 213 | |
Tsuyoshi Horo | 242ee8f | 2019-04-26 06:37:07 | [diff] [blame^] | 214 | SendEmptyBody(); |
Kinuko Yasuda | db67b53 | 2018-02-19 09:11:52 | [diff] [blame] | 215 | } |
| 216 | |
| 217 | void PrefetchURLLoader::OnComplete( |
| 218 | const network::URLLoaderCompletionStatus& status) { |
Tsuyoshi Horo | 242ee8f | 2019-04-26 06:37:07 | [diff] [blame^] | 219 | 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 | |
| 228 | bool 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 | |
| 245 | void PrefetchURLLoader::SendOnComplete( |
| 246 | const network::URLLoaderCompletionStatus& completion_status) { |
| 247 | forwarding_client_->OnComplete(completion_status); |
Kinuko Yasuda | db67b53 | 2018-02-19 09:11:52 | [diff] [blame] | 248 | } |
| 249 | |
| 250 | void 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 |