blob: 853a116ec326041c3f5ed66f42095cc9db9199ce [file] [log] [blame]
scottmg69985212017-04-12 16:47:281// Copyright 2017 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
arthursonzogni1fd60e62018-05-09 15:57:325#include "content/browser/loader/navigation_url_loader_impl.h"
scottmg69985212017-04-12 16:47:286
Gyuyoung Kim637cefb2018-02-03 03:03:217#include <memory>
8
ananta5149d8e2017-04-21 00:01:379#include "base/bind.h"
10#include "base/bind_helpers.h"
Tarun Bansal98260cd2018-02-17 07:52:2311#include "base/feature_list.h"
Emily Starkb09f19a2017-11-22 22:41:4712#include "base/metrics/histogram_macros.h"
Ken Rockot314714c2017-11-05 23:36:2413#include "base/task_scheduler/post_task.h"
yzshen0f278522017-05-01 17:10:2214#include "base/trace_event/trace_event.h"
Min Qinda0ed2062018-02-23 22:00:5315#include "components/download/public/common/download_stats.h"
anantae3f159a2017-05-11 23:40:0716#include "content/browser/appcache/appcache_navigation_handle.h"
anantaa2c8ec62017-06-09 23:44:0517#include "content/browser/appcache/appcache_request_handler.h"
ananta5149d8e2017-04-21 00:01:3718#include "content/browser/blob_storage/chrome_blob_storage_context.h"
Andrey Kosyakov8d49c5062018-03-15 19:50:4919#include "content/browser/devtools/render_frame_devtools_agent_host.h"
Ken Rockot314714c2017-11-05 23:36:2420#include "content/browser/file_url_loader_factory.h"
jam8c4edd02017-05-06 18:50:3321#include "content/browser/frame_host/frame_tree_node.h"
scottmg69985212017-04-12 16:47:2822#include "content/browser/frame_host/navigation_request_info.h"
Kinuko Yasuda7f3e1722018-03-26 08:58:5823#include "content/browser/loader/navigation_loader_interceptor.h"
Andrey Kosyakov52a84812018-04-19 05:36:3924#include "content/browser/loader/navigation_loader_util.h"
scottmg95feea52017-04-12 17:51:3325#include "content/browser/loader/navigation_url_loader_delegate.h"
arthursonzogni2695d04d2017-12-12 08:39:0126#include "content/browser/loader/resource_dispatcher_host_impl.h"
arthursonzogni40db5f52018-01-08 16:38:4927#include "content/browser/loader/resource_request_info_impl.h"
scottmgd2021c92017-05-15 16:58:0528#include "content/browser/resource_context_impl.h"
29#include "content/browser/service_worker/service_worker_navigation_handle.h"
30#include "content/browser/service_worker/service_worker_navigation_handle_core.h"
31#include "content/browser/service_worker/service_worker_request_handler.h"
jamc1905862017-05-16 14:45:3032#include "content/browser/storage_partition_impl.h"
33#include "content/browser/url_loader_factory_getter.h"
scottmgd2021c92017-05-15 16:58:0534#include "content/browser/web_contents/web_contents_impl.h"
Kouhei Ueno958c5f482018-03-19 08:20:3835#include "content/browser/web_package/signed_exchange_consts.h"
Tsuyoshi Horob85801592018-02-19 22:18:0736#include "content/browser/web_package/signed_exchange_url_loader_factory_for_non_network_service.h"
37#include "content/browser/web_package/web_package_request_handler.h"
jam1a97290b2017-05-09 04:30:5038#include "content/browser/webui/url_data_manager_backend.h"
Chris Mumfordbae8a742018-03-01 23:02:2339#include "content/browser/webui/web_ui_url_loader_factory_internal.h"
Kinuko Yasuda250577c2017-10-29 02:51:2440#include "content/common/navigation_subresource_loader_params.h"
Makoto Shimazu44c2c3232018-03-30 01:10:2041#include "content/common/service_worker/service_worker_utils.h"
yzshenefcb7c72017-06-16 23:12:3042#include "content/common/throttling_url_loader.h"
jamc1905862017-05-16 14:45:3043#include "content/public/browser/browser_context.h"
scottmg95feea52017-04-12 17:51:3344#include "content/public/browser/browser_thread.h"
yzshenefcb7c72017-06-16 23:12:3045#include "content/public/browser/content_browser_client.h"
scottmgefb697302017-04-12 22:37:3046#include "content/public/browser/global_request_id.h"
Dmitry Skiba7e8c7e22018-01-04 21:04:1847#include "content/public/browser/navigation_data.h"
scottmg69985212017-04-12 16:47:2848#include "content/public/browser/navigation_ui_data.h"
John Abd-El-Malek3ebdff862018-04-23 18:57:2149#include "content/public/browser/plugin_service.h"
arthursonzogni40db5f52018-01-08 16:38:4950#include "content/public/browser/resource_dispatcher_host_delegate.h"
scottmgefb697302017-04-12 22:37:3051#include "content/public/browser/ssl_status.h"
arthursonzogni2695d04d2017-12-12 08:39:0152#include "content/public/common/content_features.h"
ananta5149d8e2017-04-21 00:01:3753#include "content/public/common/referrer.h"
jam8c4edd02017-05-06 18:50:3354#include "content/public/common/url_constants.h"
Ken Rockot314714c2017-11-05 23:36:2455#include "content/public/common/url_utils.h"
John Abd-El-Malek3ebdff862018-04-23 18:57:2156#include "content/public/common/webplugininfo.h"
ananta5149d8e2017-04-21 00:01:3757#include "net/base/load_flags.h"
Min Qin37db5102017-09-13 21:21:2558#include "net/http/http_content_disposition.h"
rhalavati4cda417b2017-06-12 11:00:2459#include "net/traffic_annotation/network_traffic_annotation.h"
Tsuyoshi Horo9e2ec4df2017-10-16 15:15:5560#include "net/url_request/redirect_util.h"
Daniel Bratell0dfa6282017-11-08 10:12:2361#include "net/url_request/url_request.h"
scottmg69985212017-04-12 16:47:2862#include "net/url_request/url_request_context.h"
Tsuyoshi Horo70014ad2018-02-14 11:20:1463#include "net/url_request/url_request_context_getter.h"
John Abd-El-Malek3ebdff862018-04-23 18:57:2164#include "ppapi/buildflags/buildflags.h"
John Abd-El-Malek89c02ae2018-02-01 01:56:1965#include "services/network/loader_util.h"
Yutaka Hiranod8789f92018-01-30 09:59:5166#include "services/network/public/cpp/features.h"
Antonio Gomes9cdc09a2018-05-07 23:24:2667#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
68#include "services/network/public/cpp/wrapper_shared_url_loader_factory.h"
Ken Rockot54311e62018-02-10 19:01:5269#include "services/network/public/mojom/request_context_frame_type.mojom.h"
70#include "services/network/public/mojom/url_loader_factory.mojom.h"
yzshenefcb7c72017-06-16 23:12:3071#include "services/service_manager/public/cpp/connector.h"
John Abd-El-Malek3ebdff862018-04-23 18:57:2172#include "third_party/blink/public/common/mime_util/mime_util.h"
scottmg69985212017-04-12 16:47:2873
74namespace content {
75
jambcc67882017-04-28 18:20:0976namespace {
yzshenfa5e57202017-05-02 21:24:1377
John Abd-El-Malekdb3a13b2018-05-01 17:52:0278// Only used on the IO thread.
arthursonzogni1fd60e62018-05-09 15:57:3279base::LazyInstance<NavigationURLLoaderImpl::BeginNavigationInterceptor>::Leaky
John Abd-El-Malekdb3a13b2018-05-01 17:52:0280 g_interceptor = LAZY_INSTANCE_INITIALIZER;
81
Kinuko Yasuda7f3e1722018-03-26 08:58:5882// Returns true if interception by NavigationLoaderInterceptors is enabled.
83bool IsLoaderInterceptionEnabled() {
Yutaka Hiranod8789f92018-01-30 09:59:5184 return base::FeatureList::IsEnabled(network::features::kNetworkService) ||
Makoto Shimazu44c2c3232018-03-30 01:10:2085 base::FeatureList::IsEnabled(features::kSignedHTTPExchange) ||
86 ServiceWorkerUtils::IsServicificationEnabled();
Tsuyoshi Horob8d512a2018-01-25 17:01:5987}
88
ananta2e65213d2017-05-19 04:08:2489// Request ID for browser initiated requests. We start at -2 on the same lines
90// as ResourceDispatcherHostImpl.
91int g_next_request_id = -2;
arthursonzogni40db5f52018-01-08 16:38:4992GlobalRequestID MakeGlobalRequestID() {
93 return GlobalRequestID(-1, g_next_request_id--);
94}
ananta2e65213d2017-05-19 04:08:2495
Emily Starkb09f19a2017-11-22 22:41:4796size_t GetCertificateChainsSizeInKB(const net::SSLInfo& ssl_info) {
97 base::Pickle cert_pickle;
98 ssl_info.cert->Persist(&cert_pickle);
99 base::Pickle unverified_cert_pickle;
100 ssl_info.unverified_cert->Persist(&unverified_cert_pickle);
101 return (cert_pickle.size() + unverified_cert_pickle.size()) / 1000;
102}
103
scottmgd2021c92017-05-15 16:58:05104WebContents* GetWebContentsFromFrameTreeNodeID(int frame_tree_node_id) {
105 DCHECK_CURRENTLY_ON(BrowserThread::UI);
106 FrameTreeNode* frame_tree_node =
107 FrameTreeNode::GloballyFindByID(frame_tree_node_id);
108 if (!frame_tree_node)
109 return nullptr;
ananta5149d8e2017-04-21 00:01:37110
scottmgd2021c92017-05-15 16:58:05111 return WebContentsImpl::FromFrameTreeNode(frame_tree_node);
112}
113
Daniel Bratellcf0b485c2017-11-09 22:42:50114const net::NetworkTrafficAnnotationTag kNavigationUrlLoaderTrafficAnnotation =
Ramin Halavatie99206e92017-06-23 05:02:50115 net::DefineNetworkTrafficAnnotation("navigation_url_loader", R"(
Ramin Halavati7b5ce1c2017-07-03 09:13:09116 semantics {
117 sender: "Navigation URL Loader"
118 description:
119 "This request is issued by a main frame navigation to fetch the "
120 "content of the page that is being navigated to."
121 trigger:
122 "Navigating Chrome (by clicking on a link, bookmark, history item, "
123 "using session restore, etc)."
124 data:
125 "Arbitrary site-controlled data can be included in the URL, HTTP "
126 "headers, and request body. Requests may include cookies and "
127 "site-specific credentials."
128 destination: WEBSITE
129 }
130 policy {
Ramin Halavati3b979782017-07-21 11:40:26131 cookies_allowed: YES
Ramin Halavati7b5ce1c2017-07-03 09:13:09132 cookies_store: "user"
133 setting: "This feature cannot be disabled."
Ramin Halavati386daa62017-08-17 10:41:59134 chrome_policy {
135 URLBlacklist {
136 URLBlacklist: { entries: '*' }
137 }
138 }
139 chrome_policy {
140 URLWhitelist {
141 URLWhitelist { }
142 }
143 }
144 }
145 comments:
146 "Chrome would be unable to navigate to websites without this type of "
147 "request. Using either URLBlacklist or URLWhitelist policies (or a "
148 "combination of both) limits the scope of these requests."
149 )");
Ramin Halavatie99206e92017-06-23 05:02:50150
Tsuyoshi Horob8d512a2018-01-25 17:01:59151std::unique_ptr<network::ResourceRequest> CreateResourceRequest(
152 NavigationRequestInfo* request_info,
153 int frame_tree_node_id,
154 bool allow_download) {
155 // TODO(scottmg): Port over stuff from RDHI::BeginNavigationRequest() here.
156 auto new_request = std::make_unique<network::ResourceRequest>();
157
158 new_request->method = request_info->common_params.method;
159 new_request->url = request_info->common_params.url;
160 new_request->site_for_cookies = request_info->site_for_cookies;
Tarun Bansal98260cd2018-02-17 07:52:23161
162 net::RequestPriority net_priority = net::HIGHEST;
163 if (!request_info->is_main_frame &&
164 base::FeatureList::IsEnabled(features::kLowPriorityIframes)) {
165 net_priority = net::LOWEST;
166 }
167 new_request->priority = net_priority;
168
Tsuyoshi Horob8d512a2018-01-25 17:01:59169 new_request->render_frame_id = frame_tree_node_id;
170
171 // The code below to set fields like request_initiator, referrer, etc has
172 // been copied from ResourceDispatcherHostImpl. We did not refactor the
173 // common code into a function, because RDHI uses accessor functions on the
174 // URLRequest class to set these fields. whereas we use ResourceRequest here.
175 new_request->request_initiator = request_info->begin_params->initiator_origin;
176 new_request->referrer = request_info->common_params.referrer.url;
177 new_request->referrer_policy = Referrer::ReferrerPolicyForUrlRequest(
178 request_info->common_params.referrer.policy);
179 new_request->headers.AddHeadersFromString(
180 request_info->begin_params->headers);
Kouhei Ueno958c5f482018-03-19 08:20:38181
182 std::string accept_value = network::kFrameAcceptHeader;
183 if (base::FeatureList::IsEnabled(features::kSignedHTTPExchange)) {
184 DCHECK(!accept_value.empty());
185 accept_value.append(kAcceptHeaderSignedExchangeSuffix);
186 }
187
188 new_request->headers.SetHeader(network::kAcceptHeader, accept_value);
Tsuyoshi Horob8d512a2018-01-25 17:01:59189
190 new_request->resource_type = request_info->is_main_frame
191 ? RESOURCE_TYPE_MAIN_FRAME
192 : RESOURCE_TYPE_SUB_FRAME;
193 if (request_info->is_main_frame)
194 new_request->update_first_party_url_on_redirect = true;
195
196 int load_flags = request_info->begin_params->load_flags;
Tsuyoshi Horob8d512a2018-01-25 17:01:59197 if (request_info->is_main_frame)
198 load_flags |= net::LOAD_MAIN_FRAME_DEPRECATED;
199
200 // Sync loads should have maximum priority and should be the only
201 // requests that have the ignore limits flag set.
202 DCHECK(!(load_flags & net::LOAD_IGNORE_LIMITS));
203
204 new_request->load_flags = load_flags;
205
206 new_request->request_body = request_info->common_params.post_data.get();
207 new_request->report_raw_headers = request_info->report_raw_headers;
208 new_request->allow_download = allow_download;
209 new_request->enable_load_timing = true;
210
211 new_request->fetch_request_mode = network::mojom::FetchRequestMode::kNavigate;
212 new_request->fetch_credentials_mode =
213 network::mojom::FetchCredentialsMode::kInclude;
214 new_request->fetch_redirect_mode = network::mojom::FetchRedirectMode::kManual;
Yutaka Hirano4b9b7a7f2018-03-07 14:35:15215 new_request->fetch_request_context_type =
216 request_info->begin_params->request_context_type;
Tsuyoshi Horob8d512a2018-01-25 17:01:59217 return new_request;
218}
219
Makoto Shimazu44c2c3232018-03-30 01:10:20220// Used only when NetworkService is disabled but IsLoaderInterceptionEnabled()
221// is true.
222std::unique_ptr<NavigationRequestInfo> CreateNavigationRequestInfoForRedirect(
223 const NavigationRequestInfo& previous_request_info,
224 const network::ResourceRequest& updated_resource_request) {
225 DCHECK(!base::FeatureList::IsEnabled(network::features::kNetworkService));
226 DCHECK(IsLoaderInterceptionEnabled());
227
228 CommonNavigationParams new_common_params =
229 previous_request_info.common_params;
230 new_common_params.url = updated_resource_request.url;
231 new_common_params.referrer =
232 Referrer(updated_resource_request.url,
233 Referrer::NetReferrerPolicyToBlinkReferrerPolicy(
234 updated_resource_request.referrer_policy));
235 new_common_params.method = updated_resource_request.method;
236 new_common_params.post_data = updated_resource_request.request_body;
237 // TODO(shimazu): Set correct base url and history url for a data URL.
238
239 mojom::BeginNavigationParamsPtr new_begin_params =
240 previous_request_info.begin_params.Clone();
241 new_begin_params->headers = updated_resource_request.headers.ToString();
242
243 return std::make_unique<NavigationRequestInfo>(
244 std::move(new_common_params), std::move(new_begin_params),
245 updated_resource_request.site_for_cookies,
246 previous_request_info.is_main_frame,
247 previous_request_info.parent_is_main_frame,
248 previous_request_info.are_ancestors_secure,
249 previous_request_info.frame_tree_node_id,
250 previous_request_info.is_for_guests_only,
251 previous_request_info.report_raw_headers,
Marijn Kruisselbrink07bf59d52018-04-03 21:50:25252 previous_request_info.is_prerendering,
Tsuyoshi Horo32b51f12018-05-09 17:58:46253 nullptr /* blob_url_loader_factory */,
254 previous_request_info.devtools_navigation_token);
Makoto Shimazu44c2c3232018-03-30 01:10:20255}
256
John Abd-El-Maleka67add82018-03-09 18:22:01257// Called for requests that we don't have a URLLoaderFactory for.
258void UnknownSchemeCallback(bool handled_externally,
259 network::mojom::URLLoaderRequest request,
260 network::mojom::URLLoaderClientPtr client) {
261 client->OnComplete(network::URLLoaderCompletionStatus(
262 handled_externally ? net::ERR_ABORTED : net::ERR_UNKNOWN_URL_SCHEME));
263}
264
yzshenfa5e57202017-05-02 21:24:13265} // namespace
266
kinuko69732972017-05-29 08:50:07267// Kept around during the lifetime of the navigation request, and is
268// responsible for dispatching a ResourceRequest to the appropriate
kinukod8b13e212017-06-07 06:59:26269// URLLoader. In order to get the right URLLoader it builds a vector
Kinuko Yasuda7f3e1722018-03-26 08:58:58270// of NavigationLoaderInterceptors and successively calls MaybeCreateLoader
kinukod8b13e212017-06-07 06:59:26271// on each until the request is successfully handled. The same sequence
272// may be performed multiple times when redirects happen.
Alex Clarke1e08882b32017-10-06 14:22:40273// TODO(michaeln): Expose this class and add more unittests.
arthursonzogni1fd60e62018-05-09 15:57:32274class NavigationURLLoaderImpl::URLLoaderRequestController
John Abd-El-Malekb165dc52018-01-18 17:12:18275 : public network::mojom::URLLoaderClient {
kinuko69732972017-05-29 08:50:07276 public:
jam9354af82017-06-03 21:59:41277 URLLoaderRequestController(
Kinuko Yasuda7f3e1722018-03-26 08:58:58278 std::vector<std::unique_ptr<NavigationLoaderInterceptor>>
279 initial_interceptors,
John Abd-El-Malek1df61792018-01-12 20:40:45280 std::unique_ptr<network::ResourceRequest> resource_request,
jam9354af82017-06-03 21:59:41281 ResourceContext* resource_context,
anantae60d1d42017-06-20 04:16:27282 scoped_refptr<URLLoaderFactoryGetter> default_url_loader_factory_getter,
arthursonzogni40db5f52018-01-08 16:38:49283 const GURL& url,
Ken Rockota0dfaca12018-02-15 07:26:25284 network::mojom::URLLoaderFactoryRequest proxied_factory_request,
285 network::mojom::URLLoaderFactoryPtrInfo proxied_factory_info,
John Abd-El-Maleka67add82018-03-09 18:22:01286 std::set<std::string> known_schemes,
arthursonzogni1fd60e62018-05-09 15:57:32287 const base::WeakPtr<NavigationURLLoaderImpl>& owner)
Kinuko Yasuda7f3e1722018-03-26 08:58:58288 : interceptors_(std::move(initial_interceptors)),
Alex Clarke1e08882b32017-10-06 14:22:40289 resource_request_(std::move(resource_request)),
kinuko69732972017-05-29 08:50:07290 resource_context_(resource_context),
anantae60d1d42017-06-20 04:16:27291 default_url_loader_factory_getter_(default_url_loader_factory_getter),
arthursonzogni40db5f52018-01-08 16:38:49292 url_(url),
anantab9800e52017-07-29 18:04:13293 owner_(owner),
arthursonzogni2695d04d2017-12-12 08:39:01294 response_loader_binding_(this),
Ken Rockota0dfaca12018-02-15 07:26:25295 proxied_factory_request_(std::move(proxied_factory_request)),
296 proxied_factory_info_(std::move(proxied_factory_info)),
John Abd-El-Maleka67add82018-03-09 18:22:01297 known_schemes_(std::move(known_schemes)),
arthursonzogni2695d04d2017-12-12 08:39:01298 weak_factory_(this) {}
kinuko69732972017-05-29 08:50:07299
yzshenefcb7c72017-06-16 23:12:30300 ~URLLoaderRequestController() override {
kinuko69732972017-05-29 08:50:07301 DCHECK_CURRENTLY_ON(BrowserThread::IO);
302 }
303
arthursonzognib521c6a2018-01-08 12:23:40304 static uint32_t GetURLLoaderOptions(bool is_main_frame) {
John Abd-El-Malekb165dc52018-01-18 17:12:18305 uint32_t options = network::mojom::kURLLoadOptionSendSSLInfoWithResponse;
arthursonzognib521c6a2018-01-08 12:23:40306 if (is_main_frame)
John Abd-El-Malekb165dc52018-01-18 17:12:18307 options |= network::mojom::kURLLoadOptionSendSSLInfoForCertificateError;
arthursonzognib521c6a2018-01-08 12:23:40308
Yutaka Hiranod8789f92018-01-30 09:59:51309 if (base::FeatureList::IsEnabled(network::features::kNetworkService)) {
John Abd-El-Malekb165dc52018-01-18 17:12:18310 options |= network::mojom::kURLLoadOptionSniffMimeType;
arthursonzognib521c6a2018-01-08 12:23:40311 } else {
312 // TODO(arthursonzogni): This is a temporary option. Remove this as soon
313 // as the InterceptingResourceHandler is removed.
314 // See https://crbug.com/791049.
John Abd-El-Malekb165dc52018-01-18 17:12:18315 options |= network::mojom::kURLLoadOptionPauseOnResponseStarted;
arthursonzognib521c6a2018-01-08 12:23:40316 }
317
318 return options;
319 }
320
Makoto Shimazu44c2c3232018-03-30 01:10:20321 SingleRequestURLLoaderFactory::RequestHandler
322 CreateDefaultRequestHandlerForNonNetworkService(
323 net::URLRequestContextGetter* url_request_context_getter,
324 storage::FileSystemContext* upload_file_system_context,
325 ServiceWorkerNavigationHandleCore* service_worker_navigation_handle_core,
326 AppCacheNavigationHandleCore* appcache_handle_core) const {
327 return base::BindOnce(
328 &URLLoaderRequestController::CreateNonNetworkServiceURLLoader,
329 weak_factory_.GetWeakPtr(),
330 base::Unretained(url_request_context_getter),
331 base::Unretained(upload_file_system_context),
332 std::make_unique<NavigationRequestInfo>(*request_info_),
333 base::Unretained(service_worker_navigation_handle_core),
334 base::Unretained(appcache_handle_core));
335 }
336
arthursonzogni2695d04d2017-12-12 08:39:01337 void CreateNonNetworkServiceURLLoader(
338 net::URLRequestContextGetter* url_request_context_getter,
339 storage::FileSystemContext* upload_file_system_context,
340 std::unique_ptr<NavigationRequestInfo> request_info,
arthursonzogni2695d04d2017-12-12 08:39:01341 ServiceWorkerNavigationHandleCore* service_worker_navigation_handle_core,
342 AppCacheNavigationHandleCore* appcache_handle_core,
John Abd-El-Malekb165dc52018-01-18 17:12:18343 network::mojom::URLLoaderRequest url_loader,
344 network::mojom::URLLoaderClientPtr url_loader_client) {
Yutaka Hiranod8789f92018-01-30 09:59:51345 DCHECK(!base::FeatureList::IsEnabled(network::features::kNetworkService));
arthursonzogni2695d04d2017-12-12 08:39:01346 DCHECK_CURRENTLY_ON(BrowserThread::IO);
347
Tsuyoshi Horob8d512a2018-01-25 17:01:59348 default_loader_used_ = true;
349 if (base::FeatureList::IsEnabled(features::kSignedHTTPExchange)) {
Tsuyoshi Horo70014ad2018-02-14 11:20:14350 DCHECK(!default_url_loader_factory_getter_);
Tsuyoshi Horo561163b2018-03-27 03:11:23351 // It is safe to pass the callback of CreateURLLoaderThrottles with the
Tsuyoshi Horo70014ad2018-02-14 11:20:14352 // unretained |this|, because the passed callback will be used by a
353 // SignedExchangeHandler which is indirectly owned by |this| until its
354 // header is verified and parsed, that's where the getter is used.
Kinuko Yasuda7f3e1722018-03-26 08:58:58355 interceptors_.push_back(std::make_unique<WebPackageRequestHandler>(
Tsuyoshi Horo70014ad2018-02-14 11:20:14356 url::Origin::Create(request_info->common_params.url),
Tsuyoshi Horo32b51f12018-05-09 17:58:46357 request_info->common_params.url,
Kinuko Yasuda32a25652018-02-19 08:14:25358 GetURLLoaderOptions(request_info->is_main_frame),
Tsuyoshi Horocdbb4902018-04-12 06:09:14359 request_info->frame_tree_node_id,
Tsuyoshi Horo32b51f12018-05-09 17:58:46360 request_info->devtools_navigation_token,
361 request_info->report_raw_headers,
Tsuyoshi Horo70014ad2018-02-14 11:20:14362 base::MakeRefCounted<
363 SignedExchangeURLLoaderFactoryForNonNetworkService>(
364 resource_context_, url_request_context_getter),
365 base::BindRepeating(
366 &URLLoaderRequestController::CreateURLLoaderThrottles,
Tsuyoshi Horof7702192018-03-07 15:00:36367 base::Unretained(this)),
368 url_request_context_getter));
Tsuyoshi Horob8d512a2018-01-25 17:01:59369 }
370
John Abd-El-Malekdb3a13b2018-05-01 17:52:02371 uint32_t options = GetURLLoaderOptions(request_info->is_main_frame);
372
373 bool intercepted = false;
374 if (g_interceptor.Get()) {
375 intercepted = g_interceptor.Get().Run(
376 &url_loader, frame_tree_node_id_, 0 /* request_id */, options,
377 *resource_request_.get(), &url_loader_client,
378 net::MutableNetworkTrafficAnnotationTag(
379 kNavigationUrlLoaderTrafficAnnotation));
380 }
381
arthursonzogni2695d04d2017-12-12 08:39:01382 // The ResourceDispatcherHostImpl can be null in unit tests.
John Abd-El-Malekdb3a13b2018-05-01 17:52:02383 if (!intercepted && ResourceDispatcherHostImpl::Get()) {
arthursonzogni2695d04d2017-12-12 08:39:01384 ResourceDispatcherHostImpl::Get()->BeginNavigationRequest(
385 resource_context_, url_request_context_getter->GetURLRequestContext(),
386 upload_file_system_context, *request_info,
arthursonzogni662d723c2018-04-24 16:13:22387 std::move(navigation_ui_data_), std::move(url_loader_client),
arthursonzogni2695d04d2017-12-12 08:39:01388 std::move(url_loader), service_worker_navigation_handle_core,
John Abd-El-Malekdb3a13b2018-05-01 17:52:02389 appcache_handle_core, options, &global_request_id_);
arthursonzogni2695d04d2017-12-12 08:39:01390 }
391
392 // TODO(arthursonzogni): Detect when the ResourceDispatcherHost didn't
393 // create a URLLoader. When it doesn't, do not send OnRequestStarted().
394 BrowserThread::PostTask(
395 BrowserThread::UI, FROM_HERE,
arthursonzogni1fd60e62018-05-09 15:57:32396 base::BindOnce(&NavigationURLLoaderImpl::OnRequestStarted, owner_,
397 base::TimeTicks::Now()));
arthursonzogni2695d04d2017-12-12 08:39:01398 }
399
400 // TODO(arthursonzogni): See if this could eventually be unified with Start().
401 void StartWithoutNetworkService(
402 net::URLRequestContextGetter* url_request_context_getter,
403 storage::FileSystemContext* upload_file_system_context,
404 ServiceWorkerNavigationHandleCore* service_worker_navigation_handle_core,
405 AppCacheNavigationHandleCore* appcache_handle_core,
406 std::unique_ptr<NavigationRequestInfo> request_info,
407 std::unique_ptr<NavigationUIData> navigation_ui_data) {
Yutaka Hiranod8789f92018-01-30 09:59:51408 DCHECK(!base::FeatureList::IsEnabled(network::features::kNetworkService));
arthursonzogni2695d04d2017-12-12 08:39:01409 DCHECK_CURRENTLY_ON(BrowserThread::IO);
410 DCHECK(!started_);
411 started_ = true;
Makoto Shimazu44c2c3232018-03-30 01:10:20412 request_info_ = std::move(request_info);
413 frame_tree_node_id_ = request_info_->frame_tree_node_id;
Yuzhu Shencb3011f62018-02-08 02:51:50414 web_contents_getter_ = base::BindRepeating(
Yuzhu Shen9508fc72018-02-08 23:18:59415 &GetWebContentsFromFrameTreeNodeID, frame_tree_node_id_);
Makoto Shimazu44c2c3232018-03-30 01:10:20416 navigation_ui_data_ = std::move(navigation_ui_data);
417 default_request_handler_factory_ = base::BindRepeating(
418 &URLLoaderRequestController::
419 CreateDefaultRequestHandlerForNonNetworkService,
420 // base::Unretained(this) is safe since
421 // |default_request_handler_factory_| could be called only from |this|.
422 base::Unretained(this), base::Unretained(url_request_context_getter),
423 base::Unretained(upload_file_system_context),
arthursonzogni2695d04d2017-12-12 08:39:01424 base::Unretained(service_worker_navigation_handle_core),
425 base::Unretained(appcache_handle_core));
426
Makoto Shimazu44c2c3232018-03-30 01:10:20427 // If S13nServiceWorker is disabled, just use
428 // |default_request_handler_factory_| and return. The non network service
429 // request handling goes through ResourceDispatcherHost which has legacy
430 // hooks for service worker (ServiceWorkerRequestInterceptor), so no service
431 // worker interception is needed here.
432 if (!ServiceWorkerUtils::IsServicificationEnabled() ||
433 !service_worker_navigation_handle_core) {
434 url_loader_ = ThrottlingURLLoader::CreateLoaderAndStart(
435 base::MakeRefCounted<SingleRequestURLLoaderFactory>(
436 default_request_handler_factory_.Run()),
437 CreateURLLoaderThrottles(), -1 /* routing_id */, 0 /* request_id */,
438 network::mojom::kURLLoadOptionNone, resource_request_.get(),
439 this /* client */, kNavigationUrlLoaderTrafficAnnotation,
440 base::ThreadTaskRunnerHandle::Get());
441 return;
442 }
443
444 // Otherwise, if S13nServiceWorker is enabled, create an interceptor so
445 // S13nServiceWorker has a chance to intercept the request.
446 std::unique_ptr<NavigationLoaderInterceptor> service_worker_interceptor =
447 CreateServiceWorkerInterceptor(*request_info_,
448 service_worker_navigation_handle_core);
449 // If an interceptor is not created for some reasons (e.g. the origin is not
450 // secure), we no longer have to go through the rest of the network service
451 // code.
452 if (!service_worker_interceptor) {
453 url_loader_ = ThrottlingURLLoader::CreateLoaderAndStart(
454 base::MakeRefCounted<SingleRequestURLLoaderFactory>(
455 default_request_handler_factory_.Run()),
456 CreateURLLoaderThrottles(), -1 /* routing_id */, 0 /* request_id */,
457 network::mojom::kURLLoadOptionNone, resource_request_.get(),
458 this /* client */, kNavigationUrlLoaderTrafficAnnotation,
459 base::ThreadTaskRunnerHandle::Get());
460 return;
461 }
462
463 interceptors_.push_back(std::move(service_worker_interceptor));
464
465 // TODO(shimazu): Make sure we have a consistent global id for the
466 // navigation request.
467 global_request_id_ = MakeGlobalRequestID();
468 Restart();
arthursonzogni2695d04d2017-12-12 08:39:01469 }
470
kinuko69732972017-05-29 08:50:07471 void Start(
Tsuyoshi Horo70014ad2018-02-14 11:20:14472 net::URLRequestContextGetter* url_request_context_getter,
kinuko69732972017-05-29 08:50:07473 ServiceWorkerNavigationHandleCore* service_worker_navigation_handle_core,
474 AppCacheNavigationHandleCore* appcache_handle_core,
475 std::unique_ptr<NavigationRequestInfo> request_info,
John Abd-El-Malekeb1a5382018-01-05 16:58:00476 std::unique_ptr<NavigationUIData> navigation_ui_data,
John Abd-El-Malekb165dc52018-01-18 17:12:18477 network::mojom::URLLoaderFactoryPtrInfo factory_for_webui,
John Abd-El-Malek576c6132017-11-04 00:33:58478 int frame_tree_node_id,
kinuko69732972017-05-29 08:50:07479 std::unique_ptr<service_manager::Connector> connector) {
Yutaka Hiranod8789f92018-01-30 09:59:51480 DCHECK(base::FeatureList::IsEnabled(network::features::kNetworkService));
kinuko69732972017-05-29 08:50:07481 DCHECK_CURRENTLY_ON(BrowserThread::IO);
Alex Clarke1e08882b32017-10-06 14:22:40482 DCHECK(!started_);
arthursonzogni40db5f52018-01-08 16:38:49483 global_request_id_ = MakeGlobalRequestID();
John Abd-El-Malek576c6132017-11-04 00:33:58484 frame_tree_node_id_ = frame_tree_node_id;
Alex Clarke1e08882b32017-10-06 14:22:40485 started_ = true;
John Abd-El-Malek576c6132017-11-04 00:33:58486 web_contents_getter_ =
487 base::Bind(&GetWebContentsFromFrameTreeNodeID, frame_tree_node_id);
John Abd-El-Malekeb1a5382018-01-05 16:58:00488 navigation_ui_data_ = std::move(navigation_ui_data);
kinuko69732972017-05-29 08:50:07489
490 if (resource_request_->request_body) {
mmenkeed44e6c2017-06-28 21:13:32491 GetBodyBlobDataHandles(resource_request_->request_body.get(),
492 resource_context_, &blob_handles_);
kinuko69732972017-05-29 08:50:07493 }
494
495 // Requests to WebUI scheme won't get redirected to/from other schemes
496 // or be intercepted, so we just let it go here.
497 if (factory_for_webui.is_valid()) {
yzshenefcb7c72017-06-16 23:12:30498 url_loader_ = ThrottlingURLLoader::CreateLoaderAndStart(
Antonio Gomes9cdc09a2018-05-07 23:24:26499 base::MakeRefCounted<network::WrapperSharedURLLoaderFactory>(
Yuzhu Shend87986f2018-01-17 22:16:37500 std::move(factory_for_webui)),
Tsuyoshi Horo70014ad2018-02-14 11:20:14501 CreateURLLoaderThrottles(), 0 /* routing_id */, 0 /* request_id? */,
John Abd-El-Malekb165dc52018-01-18 17:12:18502 network::mojom::kURLLoadOptionNone, resource_request_.get(), this,
503 kNavigationUrlLoaderTrafficAnnotation,
Hajime Hoshif5ef35262017-11-28 19:13:00504 base::ThreadTaskRunnerHandle::Get());
kinuko69732972017-05-29 08:50:07505 return;
506 }
507
Marijn Kruisselbrink07bf59d52018-04-03 21:50:25508 // Requests to Blob scheme won't get redirected to/from other schemes
509 // or be intercepted, so we just let it go here.
510 if (request_info->common_params.url.SchemeIsBlob() &&
511 request_info->blob_url_loader_factory) {
512 url_loader_ = ThrottlingURLLoader::CreateLoaderAndStart(
513 network::SharedURLLoaderFactory::Create(
514 std::move(request_info->blob_url_loader_factory)),
515 GetContentClient()->browser()->CreateURLLoaderThrottles(
516 *resource_request_, resource_context_, web_contents_getter_,
517 navigation_ui_data_.get(), frame_tree_node_id_),
518 0 /* routing_id */, 0 /* request_id? */,
519 network::mojom::kURLLoadOptionNone, resource_request_.get(), this,
520 kNavigationUrlLoaderTrafficAnnotation,
521 base::ThreadTaskRunnerHandle::Get());
522 return;
523 }
524
kinuko69732972017-05-29 08:50:07525 if (service_worker_navigation_handle_core) {
Kinuko Yasuda7f3e1722018-03-26 08:58:58526 std::unique_ptr<NavigationLoaderInterceptor> service_worker_interceptor =
Makoto Shimazu44c2c3232018-03-30 01:10:20527 CreateServiceWorkerInterceptor(*request_info,
528 service_worker_navigation_handle_core);
Kinuko Yasuda7f3e1722018-03-26 08:58:58529 if (service_worker_interceptor)
530 interceptors_.push_back(std::move(service_worker_interceptor));
kinuko69732972017-05-29 08:50:07531 }
532
533 if (appcache_handle_core) {
Kinuko Yasuda7f3e1722018-03-26 08:58:58534 std::unique_ptr<NavigationLoaderInterceptor> appcache_interceptor =
anantaa2c8ec62017-06-09 23:44:05535 AppCacheRequestHandler::InitializeForNavigationNetworkService(
anantae60d1d42017-06-20 04:16:27536 *resource_request_, appcache_handle_core,
537 default_url_loader_factory_getter_.get());
Kinuko Yasuda7f3e1722018-03-26 08:58:58538 if (appcache_interceptor)
539 interceptors_.push_back(std::move(appcache_interceptor));
kinuko69732972017-05-29 08:50:07540 }
541
Tsuyoshi Horob8d512a2018-01-25 17:01:59542 if (base::FeatureList::IsEnabled(features::kSignedHTTPExchange)) {
Tsuyoshi Horo561163b2018-03-27 03:11:23543 // It is safe to pass the callback of CreateURLLoaderThrottles with the
Tsuyoshi Horo70014ad2018-02-14 11:20:14544 // unretained |this|, because the passed callback will be used by a
545 // SignedExchangeHandler which is indirectly owned by |this| until its
546 // header is verified and parsed, that's where the getter is used.
Kinuko Yasuda7f3e1722018-03-26 08:58:58547 interceptors_.push_back(std::make_unique<WebPackageRequestHandler>(
Tsuyoshi Horo70014ad2018-02-14 11:20:14548 url::Origin::Create(request_info->common_params.url),
Tsuyoshi Horo32b51f12018-05-09 17:58:46549 request_info->common_params.url,
Kinuko Yasuda32a25652018-02-19 08:14:25550 GetURLLoaderOptions(request_info->is_main_frame),
Tsuyoshi Horocdbb4902018-04-12 06:09:14551 request_info->frame_tree_node_id,
Tsuyoshi Horo32b51f12018-05-09 17:58:46552 request_info->devtools_navigation_token,
553 request_info->report_raw_headers,
Chong Zhang5271432a2018-03-01 23:31:02554 default_url_loader_factory_getter_->GetNetworkFactory(),
Tsuyoshi Horo70014ad2018-02-14 11:20:14555 base::BindRepeating(
556 &URLLoaderRequestController::CreateURLLoaderThrottles,
Tsuyoshi Horof7702192018-03-07 15:00:36557 base::Unretained(this)),
558 url_request_context_getter));
Tsuyoshi Horob8d512a2018-01-25 17:01:59559 }
560
yzshenefcb7c72017-06-16 23:12:30561 Restart();
kinuko69732972017-05-29 08:50:07562 }
563
Michael Nordman2431f5f2017-09-13 04:58:15564 // This could be called multiple times to follow a chain of redirects.
yzshenefcb7c72017-06-16 23:12:30565 void Restart() {
Kinuko Yasuda7f3e1722018-03-26 08:58:58566 DCHECK(IsLoaderInterceptionEnabled());
Tsuyoshi Horo5204c872017-09-21 16:28:17567 // Clear |url_loader_| if it's not the default one (network). This allows
568 // the restarted request to use a new loader, instead of, e.g., reusing the
569 // AppCache or service worker loader. For an optimization, we keep and reuse
Kinuko Yasuda7f3e1722018-03-26 08:58:58570 // the default url loader if the all |interceptors_| doesn't handle the
Tsuyoshi Horo5204c872017-09-21 16:28:17571 // redirected request.
572 if (!default_loader_used_)
573 url_loader_.reset();
Kinuko Yasuda7f3e1722018-03-26 08:58:58574 interceptor_index_ = 0;
anantab9800e52017-07-29 18:04:13575 received_response_ = false;
Kinuko Yasuda7f3e1722018-03-26 08:58:58576 MaybeStartLoader(nullptr /* interceptor */,
577 {} /* single_request_handler */);
kinuko69732972017-05-29 08:50:07578 }
579
Kinuko Yasuda7f3e1722018-03-26 08:58:58580 // |interceptor| is non-null if this is called by one of the interceptors
581 // (via a LoaderCallback).
582 // |single_request_handler| is the RequestHandler given by the |interceptor|,
583 // non-null if the interceptor wants to handle the request.
Ken Rockot387ddd5a2018-01-30 19:18:40584 void MaybeStartLoader(
Kinuko Yasuda7f3e1722018-03-26 08:58:58585 NavigationLoaderInterceptor* interceptor,
Ken Rockot387ddd5a2018-01-30 19:18:40586 SingleRequestURLLoaderFactory::RequestHandler single_request_handler) {
Kinuko Yasuda7f3e1722018-03-26 08:58:58587 DCHECK(IsLoaderInterceptionEnabled());
Ken Rockot387ddd5a2018-01-30 19:18:40588 if (single_request_handler) {
Kinuko Yasuda7f3e1722018-03-26 08:58:58589 // |interceptor| wants to handle the request with
590 // |single_request_handler|.
591 DCHECK(interceptor);
Michael Nordman2431f5f2017-09-13 04:58:15592 default_loader_used_ = false;
yzshenefcb7c72017-06-16 23:12:30593 url_loader_ = ThrottlingURLLoader::CreateLoaderAndStart(
Ken Rockot387ddd5a2018-01-30 19:18:40594 base::MakeRefCounted<SingleRequestURLLoaderFactory>(
595 std::move(single_request_handler)),
Tsuyoshi Horo70014ad2018-02-14 11:20:14596 CreateURLLoaderThrottles(), frame_tree_node_id_, 0 /* request_id? */,
Ken Rockot387ddd5a2018-01-30 19:18:40597 network::mojom::kURLLoadOptionNone, resource_request_.get(), this,
Hajime Hoshif5ef35262017-11-28 19:13:00598 kNavigationUrlLoaderTrafficAnnotation,
599 base::ThreadTaskRunnerHandle::Get());
anantae60d1d42017-06-20 04:16:27600
Kinuko Yasuda250577c2017-10-29 02:51:24601 subresource_loader_params_ =
Kinuko Yasuda7f3e1722018-03-26 08:58:58602 interceptor->MaybeCreateSubresourceLoaderParams();
Kinuko Yasuda8757204a2017-11-04 07:50:13603
kinuko69732972017-05-29 08:50:07604 return;
605 }
606
Kinuko Yasuda7f3e1722018-03-26 08:58:58607 // Before falling back to the next interceptor, see if |interceptor| still
608 // wants to give additional info to the frame for subresource loading. In
609 // that case we will just fall back to the default loader (i.e. won't go on
610 // to the next interceptors) but send the subresource_loader_params to the
611 // child process. This is necessary for correctness in the cases where, e.g.
612 // there's a controlling ServiceWorker that doesn't handle main resource
613 // loading, but may still want to control the page and/or handle subresource
614 // loading. In that case we want to skip AppCache.
615 if (interceptor) {
Kinuko Yasuda8757204a2017-11-04 07:50:13616 subresource_loader_params_ =
Kinuko Yasuda7f3e1722018-03-26 08:58:58617 interceptor->MaybeCreateSubresourceLoaderParams();
Kinuko Yasuda8757204a2017-11-04 07:50:13618
619 // If non-null |subresource_loader_params_| is returned, make sure
Kinuko Yasuda7f3e1722018-03-26 08:58:58620 // we skip the next interceptors.
Kinuko Yasuda8757204a2017-11-04 07:50:13621 if (subresource_loader_params_)
Kinuko Yasuda7f3e1722018-03-26 08:58:58622 interceptor_index_ = interceptors_.size();
Kinuko Yasuda8757204a2017-11-04 07:50:13623 }
624
Kinuko Yasuda7f3e1722018-03-26 08:58:58625 // See if the next interceptor wants to handle the request.
626 if (interceptor_index_ < interceptors_.size()) {
627 auto* next_interceptor = interceptors_[interceptor_index_++].get();
628 next_interceptor->MaybeCreateLoader(
kinuko69732972017-05-29 08:50:07629 *resource_request_, resource_context_,
630 base::BindOnce(&URLLoaderRequestController::MaybeStartLoader,
Kinuko Yasuda7f3e1722018-03-26 08:58:58631 base::Unretained(this), next_interceptor));
kinuko69732972017-05-29 08:50:07632 return;
633 }
634
Kinuko Yasuda7f3e1722018-03-26 08:58:58635 // If we already have the default |url_loader_| we must come here after
636 // a redirect. No interceptors wanted to intercept the redirected request,
637 // so let it just follow the redirect.
Michael Nordman2431f5f2017-09-13 04:58:15638 if (url_loader_) {
639 DCHECK(!redirect_info_.new_url.is_empty());
640 url_loader_->FollowRedirect();
641 return;
642 }
643
Ken Rockota0dfaca12018-02-15 07:26:25644 // TODO(https://crbug.com/796425): We temporarily wrap raw
645 // mojom::URLLoaderFactory pointers into SharedURLLoaderFactory. Need to
646 // further refactor the factory getters to avoid this.
Chong Zhangb7c8d1ce2018-03-13 19:14:11647 scoped_refptr<network::SharedURLLoaderFactory> factory;
Kinuko Yasuda7f3e1722018-03-26 08:58:58648 DCHECK_EQ(interceptors_.size(), interceptor_index_);
Makoto Shimazu44c2c3232018-03-30 01:10:20649
650 // If NetworkService is not enabled (which means we come here because one of
651 // the loader interceptors is enabled), use the default request handler
652 // instead of going through the NetworkService path.
653 if (!base::FeatureList::IsEnabled(network::features::kNetworkService)) {
654 DCHECK(!interceptors_.empty());
655 DCHECK(default_request_handler_factory_);
656 default_loader_used_ = true;
657 // Update |request_info_| when following a redirect.
658 if (url_chain_.size() > 0) {
659 request_info_ = CreateNavigationRequestInfoForRedirect(
660 *request_info_, *resource_request_);
661 }
662 url_loader_ = ThrottlingURLLoader::CreateLoaderAndStart(
663 base::MakeRefCounted<SingleRequestURLLoaderFactory>(
664 default_request_handler_factory_.Run()),
665 CreateURLLoaderThrottles(), frame_tree_node_id_, 0 /* request_id */,
666 network::mojom::kURLLoadOptionNone, resource_request_.get(),
667 this /* client */, kNavigationUrlLoaderTrafficAnnotation,
668 base::ThreadTaskRunnerHandle::Get());
669 return;
670 }
671
jam9354af82017-06-03 21:59:41672 if (resource_request_->url.SchemeIs(url::kBlobScheme)) {
Antonio Gomes9cdc09a2018-05-07 23:24:26673 factory =
674 base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
675 default_url_loader_factory_getter_->GetBlobFactory());
Ken Rockot314714c2017-11-05 23:36:24676 } else if (!IsURLHandledByNetworkService(resource_request_->url) &&
677 !resource_request_->url.SchemeIs(url::kDataScheme)) {
John Abd-El-Maleka67add82018-03-09 18:22:01678 if (known_schemes_.find(resource_request_->url.scheme()) ==
679 known_schemes_.end()) {
680 bool handled = GetContentClient()->browser()->HandleExternalProtocol(
681 resource_request_->url, web_contents_getter_,
682 ChildProcessHost::kInvalidUniqueID, navigation_ui_data_.get(),
683 resource_request_->resource_type == RESOURCE_TYPE_MAIN_FRAME,
684 static_cast<ui::PageTransition>(resource_request_->transition_type),
685 resource_request_->has_user_gesture);
686 factory = base::MakeRefCounted<SingleRequestURLLoaderFactory>(
687 base::BindOnce(UnknownSchemeCallback, handled));
688 } else {
689 network::mojom::URLLoaderFactoryPtr& non_network_factory =
690 non_network_url_loader_factories_[resource_request_->url.scheme()];
691 if (!non_network_factory.is_bound()) {
692 BrowserThread::PostTask(
693 BrowserThread::UI, FROM_HERE,
arthursonzogni1fd60e62018-05-09 15:57:32694 base::BindOnce(&NavigationURLLoaderImpl ::
John Abd-El-Maleka67add82018-03-09 18:22:01695 BindNonNetworkURLLoaderFactoryRequest,
696 owner_, frame_tree_node_id_,
697 resource_request_->url,
698 mojo::MakeRequest(&non_network_factory)));
699 }
Antonio Gomes9cdc09a2018-05-07 23:24:26700 factory =
701 base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
702 non_network_factory.get());
Ken Rockot314714c2017-11-05 23:36:24703 }
jam9354af82017-06-03 21:59:41704 } else {
anantab9800e52017-07-29 18:04:13705 default_loader_used_ = true;
Ken Rockota0dfaca12018-02-15 07:26:25706
707 // NOTE: We only support embedders proxying network-service-bound requests
Kinuko Yasuda7f3e1722018-03-26 08:58:58708 // not handled by NavigationLoaderInterceptors above (e.g. Service Worker
709 // or AppCache). Hence this code is only reachable when one of the above
710 // interceptors isn't used and the URL is either a data URL or has a
711 // scheme which is handled by the network service. We explicitly avoid
712 // proxying the data URL case here.
Ken Rockota0dfaca12018-02-15 07:26:25713 if (proxied_factory_request_.is_pending() &&
714 !resource_request_->url.SchemeIs(url::kDataScheme)) {
715 DCHECK(proxied_factory_info_.is_valid());
Chong Zhang70432e32018-03-07 04:43:52716 // We don't worry about reconnection since it's a single navigation.
Chong Zhang5271432a2018-03-01 23:31:02717 default_url_loader_factory_getter_->CloneNetworkFactory(
718 std::move(proxied_factory_request_));
Antonio Gomes9cdc09a2018-05-07 23:24:26719 factory = base::MakeRefCounted<network::WrapperSharedURLLoaderFactory>(
Ken Rockota0dfaca12018-02-15 07:26:25720 std::move(proxied_factory_info_));
721 } else {
Chong Zhang5271432a2018-03-01 23:31:02722 factory = default_url_loader_factory_getter_->GetNetworkFactory();
Ken Rockota0dfaca12018-02-15 07:26:25723 }
jam9354af82017-06-03 21:59:41724 }
Min Qin83d07872017-10-26 23:22:41725 url_chain_.push_back(resource_request_->url);
arthursonzognib521c6a2018-01-08 12:23:40726 uint32_t options = GetURLLoaderOptions(resource_request_->resource_type ==
727 RESOURCE_TYPE_MAIN_FRAME);
yzshenefcb7c72017-06-16 23:12:30728 url_loader_ = ThrottlingURLLoader::CreateLoaderAndStart(
Ken Rockota0dfaca12018-02-15 07:26:25729 factory, CreateURLLoaderThrottles(), frame_tree_node_id_,
730 0 /* request_id? */, options, resource_request_.get(), this,
Tsuyoshi Horo70014ad2018-02-14 11:20:14731 kNavigationUrlLoaderTrafficAnnotation,
Hajime Hoshif5ef35262017-11-28 19:13:00732 base::ThreadTaskRunnerHandle::Get());
kinuko69732972017-05-29 08:50:07733 }
734
yzshenefcb7c72017-06-16 23:12:30735 void FollowRedirect() {
736 DCHECK_CURRENTLY_ON(BrowserThread::IO);
Michael Nordman2431f5f2017-09-13 04:58:15737 DCHECK(!redirect_info_.new_url.is_empty());
arthursonzogni2695d04d2017-12-12 08:39:01738
Kinuko Yasuda7f3e1722018-03-26 08:58:58739 if (!IsLoaderInterceptionEnabled()) {
arthursonzogni2695d04d2017-12-12 08:39:01740 url_loader_->FollowRedirect();
741 return;
742 }
anantab9800e52017-07-29 18:04:13743
Kinuko Yasuda7f3e1722018-03-26 08:58:58744 // Update |resource_request_| and call Restart to give our |interceptors_| a
745 // chance at handling the new location. If no interceptor wants to take
746 // over, we'll use the existing url_loader to follow the redirect, see
747 // MaybeStartLoader.
Michael Nordman2431f5f2017-09-13 04:58:15748 // TODO(michaeln): This is still WIP and is based on URLRequest::Redirect,
749 // there likely remains more to be done.
750 // a. For subframe navigations, the Origin header may need to be modified
751 // differently?
752 // b. How should redirect_info_.referred_token_binding_host be handled?
Michael Nordman2431f5f2017-09-13 04:58:15753
Tsuyoshi Horo9e2ec4df2017-10-16 15:15:55754 bool should_clear_upload = false;
755 net::RedirectUtil::UpdateHttpRequest(
756 resource_request_->url, resource_request_->method, redirect_info_,
757 &resource_request_->headers, &should_clear_upload);
758 if (should_clear_upload) {
Michael Nordman2431f5f2017-09-13 04:58:15759 // The request body is no longer applicable.
760 resource_request_->request_body = nullptr;
761 blob_handles_.clear();
762 }
763
Michael Nordman2431f5f2017-09-13 04:58:15764 resource_request_->url = redirect_info_.new_url;
Tsuyoshi Horo9e2ec4df2017-10-16 15:15:55765 resource_request_->method = redirect_info_.new_method;
Michael Nordman2431f5f2017-09-13 04:58:15766 resource_request_->site_for_cookies = redirect_info_.new_site_for_cookies;
767 resource_request_->referrer = GURL(redirect_info_.new_referrer);
John Abd-El-Malekb77d22fb72017-12-22 17:34:48768 resource_request_->referrer_policy = redirect_info_.new_referrer_policy;
Min Qin83d07872017-10-26 23:22:41769 url_chain_.push_back(redirect_info_.new_url);
Michael Nordman2431f5f2017-09-13 04:58:15770
771 Restart();
yzshenefcb7c72017-06-16 23:12:30772 }
773
Kinuko Yasuda250577c2017-10-29 02:51:24774 base::Optional<SubresourceLoaderParams> TakeSubresourceLoaderParams() {
775 return std::move(subresource_loader_params_);
anantae60d1d42017-06-20 04:16:27776 }
777
kinuko69732972017-05-29 08:50:07778 private:
John Abd-El-Malekb165dc52018-01-18 17:12:18779 // network::mojom::URLLoaderClient implementation:
yzshenefcb7c72017-06-16 23:12:30780 void OnReceiveResponse(
John Abd-El-Malek46248032018-01-17 19:11:23781 const network::ResourceResponseHead& head,
John Abd-El-Malekb165dc52018-01-18 17:12:18782 network::mojom::DownloadedTempFilePtr downloaded_file) override {
anantab9800e52017-07-29 18:04:13783 received_response_ = true;
arthursonzogni2695d04d2017-12-12 08:39:01784
anantab9800e52017-07-29 18:04:13785 // If the default loader (network) was used to handle the URL load request
Kinuko Yasuda7f3e1722018-03-26 08:58:58786 // we need to see if the interceptors want to potentially create a new
787 // loader for the response. e.g. AppCache.
anantab9800e52017-07-29 18:04:13788 if (MaybeCreateLoaderForResponse(head))
789 return;
arthursonzogni3a4ca9f2017-12-07 17:58:34790
John Abd-El-Malekb165dc52018-01-18 17:12:18791 network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints;
John Abd-El-Malekecc6f5f2018-03-02 18:47:39792
793 // Currently only plugin handlers may intercept the response. Don't treat
794 // the response as download if it has been handled by plugins.
795 bool response_intercepted = false;
arthursonzogni3a4ca9f2017-12-07 17:58:34796 if (url_loader_) {
797 url_loader_client_endpoints = url_loader_->Unbind();
John Abd-El-Malekecc6f5f2018-03-02 18:47:39798 response_intercepted = url_loader_->response_intercepted();
arthursonzogni3a4ca9f2017-12-07 17:58:34799 } else {
John Abd-El-Malekb165dc52018-01-18 17:12:18800 url_loader_client_endpoints =
801 network::mojom::URLLoaderClientEndpoints::New(
802 response_url_loader_.PassInterface(),
803 response_loader_binding_.Unbind());
arthursonzogni3a4ca9f2017-12-07 17:58:34804 }
805
arthursonzogni40db5f52018-01-08 16:38:49806 bool is_download;
807 bool is_stream;
808 std::unique_ptr<NavigationData> cloned_navigation_data;
Kinuko Yasuda7f3e1722018-03-26 08:58:58809 if (IsLoaderInterceptionEnabled()) {
John Abd-El-Malek3ebdff862018-04-23 18:57:21810 bool must_download = navigation_loader_util::MustDownload(
Jochen Eisinger7678c8ac2018-05-07 15:47:34811 url_, head.headers.get(), head.mime_type);
John Abd-El-Malek3ebdff862018-04-23 18:57:21812 bool known_mime_type = blink::IsSupportedMimeType(head.mime_type);
813
814#if BUILDFLAG(ENABLE_PLUGINS)
815 if (!response_intercepted && !must_download && !known_mime_type) {
816 CheckPluginAndContinueOnReceiveResponse(
817 head, std::move(downloaded_file),
818 std::move(url_loader_client_endpoints),
819 std::vector<WebPluginInfo>());
820 return;
821 }
822#endif
823
824 is_download =
825 !response_intercepted && (must_download || !known_mime_type);
arthursonzogni40db5f52018-01-08 16:38:49826 is_stream = false;
827 } else {
828 ResourceDispatcherHostImpl* rdh = ResourceDispatcherHostImpl::Get();
829 net::URLRequest* url_request = rdh->GetURLRequest(global_request_id_);
arthursonzognib1de19fa2018-04-03 19:55:10830
831 // The |url_request| maybe have been removed from the resource dispatcher
John Abd-El-Malek739997242018-05-01 19:48:25832 // host during the time it took for OnReceiveResponse() to be received.
833 if (url_request) {
834 ResourceRequestInfoImpl* info =
835 ResourceRequestInfoImpl::ForRequest(url_request);
836 is_download = !response_intercepted && info->IsDownload();
837 is_stream = info->is_stream();
838 if (rdh->delegate()) {
839 NavigationData* navigation_data =
840 rdh->delegate()->GetNavigationData(url_request);
arthursonzognib1de19fa2018-04-03 19:55:10841
John Abd-El-Malek739997242018-05-01 19:48:25842 // Clone the embedder's NavigationData before moving it to the UI
843 // thread.
844 if (navigation_data)
845 cloned_navigation_data = navigation_data->Clone();
846 }
arthursonzogni40db5f52018-01-08 16:38:49847
John Abd-El-Malek739997242018-05-01 19:48:25848 // This is similar to what is done in
849 // ServiceWorkerControlleeHandler::MaybeCreateSubresourceLoaderParams().
850 // It takes the matching ControllerServiceWorkerInfo (if any) associated
851 // with the request. It will be sent to the renderer process and used to
852 // intercept requests.
853 // TODO(arthursonzogni): This is needed only for the
854 // non-S13nServiceWorker case. The S13nServiceWorker case is still not
855 // supported without the NetworkService. This block needs to be updated
856 // once support for it will be added.
857 ServiceWorkerProviderHost* sw_provider_host =
858 ServiceWorkerRequestHandler::GetProviderHost(url_request);
859 if (sw_provider_host && sw_provider_host->controller()) {
860 subresource_loader_params_ = SubresourceLoaderParams();
861 subresource_loader_params_->controller_service_worker_info =
862 mojom::ControllerServiceWorkerInfo::New();
863 subresource_loader_params_->controller_service_worker_info
864 ->object_info = sw_provider_host->GetOrCreateServiceWorkerHandle(
865 sw_provider_host->controller());
866 }
867 } else {
868 is_download = is_stream = false;
arthursonzognib950d902018-02-08 09:27:13869 }
arthursonzogni40db5f52018-01-08 16:38:49870 }
871
John Abd-El-Malek3ebdff862018-04-23 18:57:21872 CallOnReceivedResponse(head, std::move(downloaded_file),
873 std::move(url_loader_client_endpoints),
874 std::move(cloned_navigation_data), is_download,
875 is_stream);
876 }
877
878#if BUILDFLAG(ENABLE_PLUGINS)
879 void CheckPluginAndContinueOnReceiveResponse(
880 const network::ResourceResponseHead& head,
881 network::mojom::DownloadedTempFilePtr downloaded_file,
882 network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
883 const std::vector<WebPluginInfo>& plugins) {
884 bool stale;
885 WebPluginInfo plugin;
886 // It's ok to pass -1 for the render process and frame ID since that's
887 // only used for plugin overridding. We don't actually care if we get an
888 // overridden plugin or not, since all we care about is the presence of a
889 // plugin. Note that this is what the MimeSniffingResourceHandler code
890 // path does as well for navigations.
891 bool has_plugin = PluginService::GetInstance()->GetPluginInfo(
892 -1 /* render_process_id */, -1 /* render_frame_id */, resource_context_,
893 resource_request_->url, url::Origin(), head.mime_type,
894 false /* allow_wildcard */, &stale, &plugin, nullptr);
895
896 if (stale) {
897 // Refresh the plugins asynchronously.
898 PluginService::GetInstance()->GetPlugins(base::BindOnce(
899 &URLLoaderRequestController::CheckPluginAndContinueOnReceiveResponse,
900 weak_factory_.GetWeakPtr(), head, std::move(downloaded_file),
901 std::move(url_loader_client_endpoints)));
902 return;
903 }
904
905 bool is_download =
906 !has_plugin &&
907 (!head.headers || head.headers->response_code() / 100 == 2);
908
909 CallOnReceivedResponse(head, std::move(downloaded_file),
910 std::move(url_loader_client_endpoints), nullptr,
911 is_download, false /* is_stream */);
912 }
913#endif
914
915 void CallOnReceivedResponse(
916 const network::ResourceResponseHead& head,
917 network::mojom::DownloadedTempFilePtr downloaded_file,
918 network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
919 std::unique_ptr<NavigationData> cloned_navigation_data,
920 bool is_download,
921 bool is_stream) {
922 scoped_refptr<network::ResourceResponse> response(
923 new network::ResourceResponse());
924 response->head = head;
925
Andrey Kosyakova924c8b2017-08-18 17:37:23926 // Make a copy of the ResourceResponse before it is passed to another
927 // thread.
928 //
929 // TODO(davidben): This copy could be avoided if ResourceResponse weren't
930 // reference counted and the loader stack passed unique ownership of the
931 // response. https://crbug.com/416050
yzshenefcb7c72017-06-16 23:12:30932 BrowserThread::PostTask(
933 BrowserThread::UI, FROM_HERE,
arthursonzogni1fd60e62018-05-09 15:57:32934 base::BindOnce(&NavigationURLLoaderImpl::OnReceiveResponse, owner_,
935 response->DeepCopy(),
arthursonzogni40db5f52018-01-08 16:38:49936 std::move(url_loader_client_endpoints),
Andrey Kosyakov87cd9252018-03-27 16:58:27937 std::move(cloned_navigation_data), global_request_id_,
938 is_download, is_stream, std::move(downloaded_file)));
yzshenefcb7c72017-06-16 23:12:30939 }
940
941 void OnReceiveRedirect(const net::RedirectInfo& redirect_info,
John Abd-El-Malek46248032018-01-17 19:11:23942 const network::ResourceResponseHead& head) override {
Michael Nordman2431f5f2017-09-13 04:58:15943 if (--redirect_limit_ == 0) {
Takashi Toyoshimaaa278662017-11-20 11:11:26944 OnComplete(
945 network::URLLoaderCompletionStatus(net::ERR_TOO_MANY_REDIRECTS));
Michael Nordman2431f5f2017-09-13 04:58:15946 return;
947 }
948
949 // Store the redirect_info for later use in FollowRedirect where we give
Kinuko Yasuda7f3e1722018-03-26 08:58:58950 // our interceptors_ a chance to intercept the request for the new location.
Michael Nordman2431f5f2017-09-13 04:58:15951 redirect_info_ = redirect_info;
952
John Abd-El-Malek46248032018-01-17 19:11:23953 scoped_refptr<network::ResourceResponse> response(
954 new network::ResourceResponse());
Andrey Kosyakova924c8b2017-08-18 17:37:23955 response->head = head;
arthursonzogni40db5f52018-01-08 16:38:49956 url_ = redirect_info.new_url;
Andrey Kosyakova924c8b2017-08-18 17:37:23957
958 // Make a copy of the ResourceResponse before it is passed to another
959 // thread.
960 //
961 // TODO(davidben): This copy could be avoided if ResourceResponse weren't
962 // reference counted and the loader stack passed unique ownership of the
963 // response. https://crbug.com/416050
yzshenefcb7c72017-06-16 23:12:30964 BrowserThread::PostTask(
965 BrowserThread::UI, FROM_HERE,
arthursonzogni1fd60e62018-05-09 15:57:32966 base::BindOnce(&NavigationURLLoaderImpl::OnReceiveRedirect, owner_,
967 redirect_info, response->DeepCopy()));
yzshenefcb7c72017-06-16 23:12:30968 }
969
970 void OnDataDownloaded(int64_t data_length, int64_t encoded_length) override {}
yzshenefcb7c72017-06-16 23:12:30971 void OnUploadProgress(int64_t current_position,
972 int64_t total_size,
973 OnUploadProgressCallback callback) override {}
yzshenefcb7c72017-06-16 23:12:30974 void OnReceiveCachedMetadata(const std::vector<uint8_t>& data) override {}
yzshenefcb7c72017-06-16 23:12:30975 void OnTransferSizeUpdated(int32_t transfer_size_diff) override {}
976
arthursonzogni3a4ca9f2017-12-07 17:58:34977 void OnStartLoadingResponseBody(mojo::ScopedDataPipeConsumerHandle) override {
978 // Not reached. At this point, the loader and client endpoints must have
979 // been unbound and forwarded to the renderer.
980 CHECK(false);
yzshenefcb7c72017-06-16 23:12:30981 }
982
Takashi Toyoshimaaa278662017-11-20 11:11:26983 void OnComplete(const network::URLLoaderCompletionStatus& status) override {
Emily Starkb09f19a2017-11-22 22:41:47984 UMA_HISTOGRAM_BOOLEAN(
arthursonzognie70c4a042018-05-02 15:49:10985 "Navigation.URLLoaderNetworkService.OnCompleteHasSSLInfo",
Emily Starkb09f19a2017-11-22 22:41:47986 status.ssl_info.has_value());
987 if (status.ssl_info.has_value()) {
988 UMA_HISTOGRAM_MEMORY_KB(
989 "Navigation.URLLoaderNetworkService.OnCompleteCertificateChainsSize",
990 GetCertificateChainsSizeInKB(status.ssl_info.value()));
991 }
992
Takashi Toyoshima8f988532017-11-13 07:32:37993 if (status.error_code != net::OK && !received_response_) {
anantab9800e52017-07-29 18:04:13994 // If the default loader (network) was used to handle the URL load
Kinuko Yasuda7f3e1722018-03-26 08:58:58995 // request we need to see if the interceptors want to potentially create a
anantab9800e52017-07-29 18:04:13996 // new loader for the response. e.g. AppCache.
John Abd-El-Malek46248032018-01-17 19:11:23997 if (MaybeCreateLoaderForResponse(network::ResourceResponseHead()))
anantab9800e52017-07-29 18:04:13998 return;
999 }
Takashi Toyoshima8f988532017-11-13 07:32:371000 status_ = status;
arthursonzogni2695d04d2017-12-12 08:39:011001
yzshenefcb7c72017-06-16 23:12:301002 BrowserThread::PostTask(
1003 BrowserThread::UI, FROM_HERE,
arthursonzogni1fd60e62018-05-09 15:57:321004 base::BindOnce(&NavigationURLLoaderImpl::OnComplete, owner_, status));
yzshenefcb7c72017-06-16 23:12:301005 }
1006
Kinuko Yasuda7f3e1722018-03-26 08:58:581007 // Returns true if an interceptor wants to handle the response, i.e. return a
Michael Nordman2431f5f2017-09-13 04:58:151008 // different response. For e.g. AppCache may have fallback content.
John Abd-El-Malek46248032018-01-17 19:11:231009 bool MaybeCreateLoaderForResponse(
1010 const network::ResourceResponseHead& response) {
Kinuko Yasuda7f3e1722018-03-26 08:58:581011 if (!IsLoaderInterceptionEnabled())
arthursonzogni2695d04d2017-12-12 08:39:011012 return false;
1013
anantab9800e52017-07-29 18:04:131014 if (!default_loader_used_)
1015 return false;
1016
Kinuko Yasuda7f3e1722018-03-26 08:58:581017 for (auto& interceptor : interceptors_) {
John Abd-El-Malekb165dc52018-01-18 17:12:181018 network::mojom::URLLoaderClientRequest response_client_request;
Kinuko Yasuda7f3e1722018-03-26 08:58:581019 if (interceptor->MaybeCreateLoaderForResponse(
1020 response, &response_url_loader_, &response_client_request,
1021 url_loader_.get())) {
Michael Nordman2431f5f2017-09-13 04:58:151022 response_loader_binding_.Bind(std::move(response_client_request));
1023 default_loader_used_ = false;
1024 url_loader_.reset();
anantab9800e52017-07-29 18:04:131025 return true;
1026 }
1027 }
1028 return false;
1029 }
1030
Tsuyoshi Horo70014ad2018-02-14 11:20:141031 std::vector<std::unique_ptr<content::URLLoaderThrottle>>
1032 CreateURLLoaderThrottles() {
1033 return GetContentClient()->browser()->CreateURLLoaderThrottles(
1034 *resource_request_, resource_context_, web_contents_getter_,
1035 navigation_ui_data_.get(), frame_tree_node_id_);
1036 }
1037
Makoto Shimazu44c2c3232018-03-30 01:10:201038 std::unique_ptr<NavigationLoaderInterceptor> CreateServiceWorkerInterceptor(
1039 const NavigationRequestInfo& request_info,
1040 ServiceWorkerNavigationHandleCore* service_worker_navigation_handle_core)
1041 const {
1042 const ResourceType resource_type = request_info.is_main_frame
1043 ? RESOURCE_TYPE_MAIN_FRAME
1044 : RESOURCE_TYPE_SUB_FRAME;
1045 network::mojom::RequestContextFrameType frame_type =
1046 request_info.is_main_frame
1047 ? network::mojom::RequestContextFrameType::kTopLevel
1048 : network::mojom::RequestContextFrameType::kNested;
1049 storage::BlobStorageContext* blob_storage_context = GetBlobStorageContext(
1050 GetChromeBlobStorageContextForResourceContext(resource_context_));
1051 return ServiceWorkerRequestHandler::InitializeForNavigationNetworkService(
1052 *resource_request_, resource_context_,
1053 service_worker_navigation_handle_core, blob_storage_context,
1054 request_info.begin_params->skip_service_worker, resource_type,
1055 request_info.begin_params->request_context_type, frame_type,
1056 request_info.are_ancestors_secure, request_info.common_params.post_data,
1057 web_contents_getter_);
1058 }
1059
Kinuko Yasuda7f3e1722018-03-26 08:58:581060 std::vector<std::unique_ptr<NavigationLoaderInterceptor>> interceptors_;
1061 size_t interceptor_index_ = 0;
kinuko69732972017-05-29 08:50:071062
John Abd-El-Malek1df61792018-01-12 20:40:451063 std::unique_ptr<network::ResourceRequest> resource_request_;
Makoto Shimazu44c2c3232018-03-30 01:10:201064 // Non-NetworkService: |request_info_| is updated along with
1065 // |resource_request_| on redirects.
1066 std::unique_ptr<NavigationRequestInfo> request_info_;
John Abd-El-Malek576c6132017-11-04 00:33:581067 int frame_tree_node_id_ = 0;
arthursonzogni40db5f52018-01-08 16:38:491068 GlobalRequestID global_request_id_;
Michael Nordman2431f5f2017-09-13 04:58:151069 net::RedirectInfo redirect_info_;
Daniel Bratell0dfa6282017-11-08 10:12:231070 int redirect_limit_ = net::URLRequest::kMaxRedirects;
kinuko69732972017-05-29 08:50:071071 ResourceContext* resource_context_;
yzshenefcb7c72017-06-16 23:12:301072 base::Callback<WebContents*()> web_contents_getter_;
John Abd-El-Malekeb1a5382018-01-05 16:58:001073 std::unique_ptr<NavigationUIData> navigation_ui_data_;
anantae60d1d42017-06-20 04:16:271074 scoped_refptr<URLLoaderFactoryGetter> default_url_loader_factory_getter_;
arthursonzogni2695d04d2017-12-12 08:39:011075
yzshenefcb7c72017-06-16 23:12:301076 std::unique_ptr<ThrottlingURLLoader> url_loader_;
arthursonzogni2695d04d2017-12-12 08:39:011077
mmenkeed44e6c2017-06-28 21:13:321078 BlobHandles blob_handles_;
Min Qin83d07872017-10-26 23:22:411079 std::vector<GURL> url_chain_;
kinuko69732972017-05-29 08:50:071080
arthursonzogni40db5f52018-01-08 16:38:491081 // Current URL that is being navigated, updated after redirection.
1082 GURL url_;
1083
anantae60d1d42017-06-20 04:16:271084 // Currently used by the AppCache loader to pass its factory to the
1085 // renderer which enables it to handle subresources.
Kinuko Yasuda250577c2017-10-29 02:51:241086 base::Optional<SubresourceLoaderParams> subresource_loader_params_;
anantae60d1d42017-06-20 04:16:271087
mmenkeed44e6c2017-06-28 21:13:321088 // This is referenced only on the UI thread.
arthursonzogni1fd60e62018-05-09 15:57:321089 base::WeakPtr<NavigationURLLoaderImpl> owner_;
mmenkeed44e6c2017-06-28 21:13:321090
anantab9800e52017-07-29 18:04:131091 // Set to true if the default URLLoader (network service) was used for the
1092 // current navigation.
1093 bool default_loader_used_ = false;
1094
1095 // URLLoaderClient binding for loaders created for responses received from the
1096 // network loader.
John Abd-El-Malekb165dc52018-01-18 17:12:181097 mojo::Binding<network::mojom::URLLoaderClient> response_loader_binding_;
anantab9800e52017-07-29 18:04:131098
1099 // URLLoader instance for response loaders, i.e loaders created for handing
1100 // responses received from the network URLLoader.
John Abd-El-Malekb165dc52018-01-18 17:12:181101 network::mojom::URLLoaderPtr response_url_loader_;
anantab9800e52017-07-29 18:04:131102
1103 // Set to true if we receive a valid response from a URLLoader, i.e.
1104 // URLLoaderClient::OnReceivedResponse() is called.
1105 bool received_response_ = false;
1106
Alex Clarke1e08882b32017-10-06 14:22:401107 bool started_ = false;
1108
Ken Rockot314714c2017-11-05 23:36:241109 // Lazily initialized and used in the case of non-network resource
1110 // navigations. Keyed by URL scheme.
John Abd-El-Malekb165dc52018-01-18 17:12:181111 std::map<std::string, network::mojom::URLLoaderFactoryPtr>
Ken Rockot314714c2017-11-05 23:36:241112 non_network_url_loader_factories_;
1113
Makoto Shimazu44c2c3232018-03-30 01:10:201114 // Non-NetworkService:
1115 // Generator of a request handler for sending request to the network. This
1116 // captures all of parameters to create a
1117 // SingleRequestURLLoaderFactory::RequestHandler. Used only when
1118 // NetworkService is disabled but IsLoaderInterceptionEnabled() is true.
1119 base::RepeatingCallback<SingleRequestURLLoaderFactory::RequestHandler()>
1120 default_request_handler_factory_;
1121
Min Qin40b72172017-09-27 00:19:171122 // The completion status if it has been received. This is needed to handle
1123 // the case that the response is intercepted by download, and OnComplete() is
1124 // already called while we are transferring the |url_loader_| and response
1125 // body to download code.
Takashi Toyoshimaaa278662017-11-20 11:11:261126 base::Optional<network::URLLoaderCompletionStatus> status_;
Min Qin40b72172017-09-27 00:19:171127
Ken Rockota0dfaca12018-02-15 07:26:251128 // Before creating this URLLoaderRequestController on UI thread, the embedder
1129 // may have elected to proxy the URLLoaderFactory request, in which case these
1130 // fields will contain input (info) and output (request) endpoints for the
1131 // proxy. If this controller is handling a request for which proxying is
1132 // supported, requests will be plumbed through these endpoints.
1133 //
1134 // Note that these are only used for requests that go to the Network Service.
1135 network::mojom::URLLoaderFactoryRequest proxied_factory_request_;
1136 network::mojom::URLLoaderFactoryPtrInfo proxied_factory_info_;
1137
John Abd-El-Maleka67add82018-03-09 18:22:011138 // The schemes that this loader can use. For anything else we'll try external
1139 // protocol handlers.
1140 std::set<std::string> known_schemes_;
1141
Makoto Shimazu44c2c3232018-03-30 01:10:201142 mutable base::WeakPtrFactory<URLLoaderRequestController> weak_factory_;
arthursonzogni2695d04d2017-12-12 08:39:011143
kinuko69732972017-05-29 08:50:071144 DISALLOW_COPY_AND_ASSIGN(URLLoaderRequestController);
1145};
1146
Min Qin75ed6df2017-12-01 20:39:151147// TODO(https://crbug.com/790734): pass |navigation_ui_data| along with the
1148// request so that it could be modified.
arthursonzogni1fd60e62018-05-09 15:57:321149NavigationURLLoaderImpl::NavigationURLLoaderImpl(
scottmg69985212017-04-12 16:47:281150 ResourceContext* resource_context,
1151 StoragePartition* storage_partition,
1152 std::unique_ptr<NavigationRequestInfo> request_info,
1153 std::unique_ptr<NavigationUIData> navigation_ui_data,
scottmgd2021c92017-05-15 16:58:051154 ServiceWorkerNavigationHandle* service_worker_navigation_handle,
scottmg69985212017-04-12 16:47:281155 AppCacheNavigationHandle* appcache_handle,
Alex Clarke1e08882b32017-10-06 14:22:401156 NavigationURLLoaderDelegate* delegate,
Kinuko Yasuda7f3e1722018-03-26 08:58:581157 std::vector<std::unique_ptr<NavigationLoaderInterceptor>>
1158 initial_interceptors)
Min Qin37db5102017-09-13 21:21:251159 : delegate_(delegate),
1160 allow_download_(request_info->common_params.allow_download),
1161 weak_factory_(this) {
scottmg95feea52017-04-12 17:51:331162 DCHECK_CURRENTLY_ON(BrowserThread::UI);
John Abd-El-Malekfcb2ecf2017-11-15 23:15:301163 int frame_tree_node_id = request_info->frame_tree_node_id;
ananta5149d8e2017-04-21 00:01:371164
yzshen0f278522017-05-01 17:10:221165 TRACE_EVENT_ASYNC_BEGIN_WITH_TIMESTAMP1(
1166 "navigation", "Navigation timeToResponseStarted", this,
kinuko69732972017-05-29 08:50:071167 request_info->common_params.navigation_start, "FrameTreeNode id",
John Abd-El-Malekfcb2ecf2017-11-15 23:15:301168 frame_tree_node_id);
yzshen0f278522017-05-01 17:10:221169
arthursonzogni2695d04d2017-12-12 08:39:011170 ServiceWorkerNavigationHandleCore* service_worker_navigation_handle_core =
1171 service_worker_navigation_handle
1172 ? service_worker_navigation_handle->core()
1173 : nullptr;
1174
1175 AppCacheNavigationHandleCore* appcache_handle_core =
1176 appcache_handle ? appcache_handle->core() : nullptr;
1177
Yuzhu Shencb3011f62018-02-08 02:51:501178 std::unique_ptr<network::ResourceRequest> new_request = CreateResourceRequest(
1179 request_info.get(), frame_tree_node_id, allow_download_);
Tsuyoshi Horob8d512a2018-01-25 17:01:591180
Yutaka Hiranod8789f92018-01-30 09:59:511181 if (!base::FeatureList::IsEnabled(network::features::kNetworkService)) {
arthursonzogni2695d04d2017-12-12 08:39:011182 DCHECK(!request_controller_);
1183 request_controller_ = std::make_unique<URLLoaderRequestController>(
Kinuko Yasuda7f3e1722018-03-26 08:58:581184 /* initial_interceptors = */
1185 std::vector<std::unique_ptr<NavigationLoaderInterceptor>>(),
Tsuyoshi Horob8d512a2018-01-25 17:01:591186 std::move(new_request), resource_context,
arthursonzogni40db5f52018-01-08 16:38:491187 /* default_url_factory_getter = */ nullptr,
1188 request_info->common_params.url,
Ken Rockota0dfaca12018-02-15 07:26:251189 /* proxied_url_loader_factory_request */ nullptr,
John Abd-El-Maleka67add82018-03-09 18:22:011190 /* proxied_url_loader_factory_info */ nullptr, std::set<std::string>(),
arthursonzogni40db5f52018-01-08 16:38:491191 weak_factory_.GetWeakPtr());
arthursonzogni2695d04d2017-12-12 08:39:011192
1193 BrowserThread::PostTask(
1194 BrowserThread::IO, FROM_HERE,
1195 base::BindOnce(
1196 &URLLoaderRequestController::StartWithoutNetworkService,
1197 base::Unretained(request_controller_.get()),
Tsuyoshi Horo70014ad2018-02-14 11:20:141198 base::RetainedRef(storage_partition->GetURLRequestContext()),
arthursonzogni2695d04d2017-12-12 08:39:011199 base::Unretained(storage_partition->GetFileSystemContext()),
1200 base::Unretained(service_worker_navigation_handle_core),
tzikccf160c2018-02-20 12:43:131201 base::Unretained(appcache_handle_core), std::move(request_info),
1202 std::move(navigation_ui_data)));
arthursonzogni2695d04d2017-12-12 08:39:011203 return;
1204 }
1205
scottmgd2021c92017-05-15 16:58:051206 // Check if a web UI scheme wants to handle this request.
Ken Rockot6414c4d92017-11-08 19:58:321207 FrameTreeNode* frame_tree_node =
1208 FrameTreeNode::GloballyFindByID(frame_tree_node_id);
John Abd-El-Malekb165dc52018-01-18 17:12:181209 network::mojom::URLLoaderFactoryPtrInfo factory_for_webui;
scottmgd2021c92017-05-15 16:58:051210 const auto& schemes = URLDataManagerBackend::GetWebUISchemes();
John Abd-El-Malekbb0bc8e2017-11-11 01:08:151211 std::string scheme = new_request->url.scheme();
1212 if (std::find(schemes.begin(), schemes.end(), scheme) != schemes.end()) {
Chris Mumfordbae8a742018-03-01 23:02:231213 factory_for_webui = CreateWebUIURLLoaderBinding(
1214 frame_tree_node->current_frame_host(), scheme)
1215 .PassInterface();
ananta5149d8e2017-04-21 00:01:371216 }
scottmgd2021c92017-05-15 16:58:051217
Ken Rockota0dfaca12018-02-15 07:26:251218 network::mojom::URLLoaderFactoryPtrInfo proxied_factory_info;
1219 network::mojom::URLLoaderFactoryRequest proxied_factory_request;
1220 if (frame_tree_node) {
1221 // |frame_tree_node| may be null in some unit test environments.
1222 GetContentClient()
1223 ->browser()
1224 ->RegisterNonNetworkNavigationURLLoaderFactories(
John Abd-El-Malekea006302018-05-10 05:50:461225 frame_tree_node_id, &non_network_url_loader_factories_);
Ken Rockota0dfaca12018-02-15 07:26:251226
1227 // The embedder may want to proxy all network-bound URLLoaderFactory
1228 // requests that it can. If it elects to do so, we'll pass its proxy
1229 // endpoints off to the URLLoaderRequestController where wthey will be
1230 // connected if the request type supports proxying.
1231 network::mojom::URLLoaderFactoryPtrInfo factory_info;
1232 auto factory_request = mojo::MakeRequest(&factory_info);
Andrey Kosyakov8d49c5062018-03-15 19:50:491233 bool use_proxy = GetContentClient()->browser()->WillCreateURLLoaderFactory(
1234 frame_tree_node->current_frame_host(), true /* is_navigation */,
1235 &factory_request);
1236 if (RenderFrameDevToolsAgentHost::WillCreateURLLoaderFactory(
Jochen Eisingercdc12d12018-05-08 15:07:471237 frame_tree_node->current_frame_host(), true, false,
1238 &factory_request)) {
Andrey Kosyakov8d49c5062018-03-15 19:50:491239 use_proxy = true;
1240 }
1241 if (use_proxy) {
Ken Rockota0dfaca12018-02-15 07:26:251242 proxied_factory_request = std::move(factory_request);
1243 proxied_factory_info = std::move(factory_info);
1244 }
1245 }
1246
Ken Rockot314714c2017-11-05 23:36:241247 auto* partition = static_cast<StoragePartitionImpl*>(storage_partition);
John Abd-El-Maleka67add82018-03-09 18:22:011248 non_network_url_loader_factories_[url::kFileScheme] =
1249 std::make_unique<FileURLLoaderFactory>(
1250 partition->browser_context()->GetPath(),
1251 base::CreateSequencedTaskRunnerWithTraits(
1252 {base::MayBlock(), base::TaskPriority::BACKGROUND,
1253 base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}));
1254 std::set<std::string> known_schemes;
1255 for (auto& iter : non_network_url_loader_factories_)
1256 known_schemes.insert(iter.first);
1257
kinuko69732972017-05-29 08:50:071258 DCHECK(!request_controller_);
Jeremy Roman04f27c372017-10-27 15:20:551259 request_controller_ = std::make_unique<URLLoaderRequestController>(
Kinuko Yasuda7f3e1722018-03-26 08:58:581260 std::move(initial_interceptors), std::move(new_request), resource_context,
arthursonzogni40db5f52018-01-08 16:38:491261 partition->url_loader_factory_getter(), request_info->common_params.url,
Ken Rockota0dfaca12018-02-15 07:26:251262 std::move(proxied_factory_request), std::move(proxied_factory_info),
John Abd-El-Maleka67add82018-03-09 18:22:011263 std::move(known_schemes), weak_factory_.GetWeakPtr());
scottmgd2021c92017-05-15 16:58:051264 BrowserThread::PostTask(
1265 BrowserThread::IO, FROM_HERE,
Ken Rockot387ddd5a2018-01-30 19:18:401266 base::BindOnce(
1267 &URLLoaderRequestController::Start,
1268 base::Unretained(request_controller_.get()),
Tsuyoshi Horo70014ad2018-02-14 11:20:141269 base::RetainedRef(storage_partition->GetURLRequestContext()),
Ken Rockot387ddd5a2018-01-30 19:18:401270 service_worker_navigation_handle_core, appcache_handle_core,
1271 std::move(request_info), std::move(navigation_ui_data),
1272 std::move(factory_for_webui), frame_tree_node_id,
1273 ServiceManagerConnection::GetForProcess()->GetConnector()->Clone()));
scottmg69985212017-04-12 16:47:281274}
1275
arthursonzogni1fd60e62018-05-09 15:57:321276NavigationURLLoaderImpl::~NavigationURLLoaderImpl() {
kinuko69732972017-05-29 08:50:071277 BrowserThread::DeleteSoon(BrowserThread::IO, FROM_HERE,
1278 request_controller_.release());
1279}
scottmg69985212017-04-12 16:47:281280
arthursonzogni1fd60e62018-05-09 15:57:321281void NavigationURLLoaderImpl::FollowRedirect() {
yzshenefcb7c72017-06-16 23:12:301282 BrowserThread::PostTask(
1283 BrowserThread::IO, FROM_HERE,
tzik0f14f192017-08-15 02:43:331284 base::BindOnce(&URLLoaderRequestController::FollowRedirect,
1285 base::Unretained(request_controller_.get())));
scottmg95feea52017-04-12 17:51:331286}
scottmg69985212017-04-12 16:47:281287
arthursonzogni1fd60e62018-05-09 15:57:321288void NavigationURLLoaderImpl::ProceedWithResponse() {}
scottmg69985212017-04-12 16:47:281289
arthursonzogni1fd60e62018-05-09 15:57:321290void NavigationURLLoaderImpl::OnReceiveResponse(
John Abd-El-Malek46248032018-01-17 19:11:231291 scoped_refptr<network::ResourceResponse> response,
John Abd-El-Malekb165dc52018-01-18 17:12:181292 network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
arthursonzogni40db5f52018-01-08 16:38:491293 std::unique_ptr<NavigationData> navigation_data,
1294 const GlobalRequestID& global_request_id,
1295 bool is_download,
1296 bool is_stream,
John Abd-El-Malekb165dc52018-01-18 17:12:181297 network::mojom::DownloadedTempFilePtr downloaded_file) {
arthursonzogni3a4ca9f2017-12-07 17:58:341298 TRACE_EVENT_ASYNC_END2("navigation", "Navigation timeToResponseStarted", this,
arthursonzogni1fd60e62018-05-09 15:57:321299 "&NavigationURLLoaderImpl", this, "success", true);
arthursonzogni3a4ca9f2017-12-07 17:58:341300
scottmgefb697302017-04-12 22:37:301301 // TODO(scottmg): This needs to do more of what
arthursonzogni3a4ca9f2017-12-07 17:58:341302 // NavigationResourceHandler::OnResponseStarted() does.
arthursonzogni3a4ca9f2017-12-07 17:58:341303
arthursonzogni3a4ca9f2017-12-07 17:58:341304 delegate_->OnResponseStarted(
arthursonzognif34adf092018-04-24 17:06:131305 std::move(response), std::move(url_loader_client_endpoints),
Andrey Kosyakov87cd9252018-03-27 16:58:271306 std::move(navigation_data), global_request_id,
arthursonzogni40db5f52018-01-08 16:38:491307 allow_download_ && is_download, is_stream,
arthursonzogni3a4ca9f2017-12-07 17:58:341308 request_controller_->TakeSubresourceLoaderParams());
scottmg95feea52017-04-12 17:51:331309}
scottmg69985212017-04-12 16:47:281310
arthursonzogni1fd60e62018-05-09 15:57:321311void NavigationURLLoaderImpl::OnReceiveRedirect(
scottmg69985212017-04-12 16:47:281312 const net::RedirectInfo& redirect_info,
John Abd-El-Malek46248032018-01-17 19:11:231313 scoped_refptr<network::ResourceResponse> response) {
scottmg95feea52017-04-12 17:51:331314 DCHECK_CURRENTLY_ON(BrowserThread::UI);
Andrey Kosyakova924c8b2017-08-18 17:37:231315 delegate_->OnRequestRedirected(redirect_info, std::move(response));
scottmg95feea52017-04-12 17:51:331316}
scottmg69985212017-04-12 16:47:281317
arthursonzogni1fd60e62018-05-09 15:57:321318void NavigationURLLoaderImpl::OnComplete(
Takashi Toyoshimaaa278662017-11-20 11:11:261319 const network::URLLoaderCompletionStatus& status) {
Takashi Toyoshima8f988532017-11-13 07:32:371320 if (status.error_code == net::OK)
John Abd-El-Malekb906d282017-08-31 19:36:431321 return;
1322
1323 TRACE_EVENT_ASYNC_END2("navigation", "Navigation timeToResponseStarted", this,
arthursonzogni1fd60e62018-05-09 15:57:321324 "&NavigationURLLoaderImpl", this, "success", false);
Lucas Garron0efab6d2017-08-30 22:28:511325
Arthur Sonzogni0b2b1a922018-03-15 15:24:151326 delegate_->OnRequestFailed(status.exists_in_cache, status.error_code,
Carlos IL81133382017-12-06 17:18:451327 status.ssl_info);
yzshen384441de2017-04-19 23:26:141328}
scottmg69985212017-04-12 16:47:281329
arthursonzogni1fd60e62018-05-09 15:57:321330void NavigationURLLoaderImpl::SetBeginNavigationInterceptorForTesting(
John Abd-El-Malekdb3a13b2018-05-01 17:52:021331 const BeginNavigationInterceptor& interceptor) {
1332 DCHECK(!BrowserThread::IsThreadInitialized(BrowserThread::IO) ||
1333 BrowserThread::CurrentlyOn(BrowserThread::IO));
1334 DCHECK(!base::FeatureList::IsEnabled(network::features::kNetworkService));
1335 g_interceptor.Get() = interceptor;
1336}
1337
arthursonzogni1fd60e62018-05-09 15:57:321338void NavigationURLLoaderImpl::OnRequestStarted(base::TimeTicks timestamp) {
arthursonzogni2695d04d2017-12-12 08:39:011339 DCHECK_CURRENTLY_ON(BrowserThread::UI);
1340 delegate_->OnRequestStarted(timestamp);
1341}
1342
arthursonzogni1fd60e62018-05-09 15:57:321343void NavigationURLLoaderImpl::BindNonNetworkURLLoaderFactoryRequest(
Ken Rockota0dfaca12018-02-15 07:26:251344 int frame_tree_node_id,
Ken Rockot314714c2017-11-05 23:36:241345 const GURL& url,
John Abd-El-Malekb165dc52018-01-18 17:12:181346 network::mojom::URLLoaderFactoryRequest factory) {
Ken Rockot314714c2017-11-05 23:36:241347 auto it = non_network_url_loader_factories_.find(url.scheme());
1348 if (it == non_network_url_loader_factories_.end()) {
1349 DVLOG(1) << "Ignoring request with unknown scheme: " << url.spec();
1350 return;
1351 }
Ken Rockota0dfaca12018-02-15 07:26:251352 FrameTreeNode* frame_tree_node =
1353 FrameTreeNode::GloballyFindByID(frame_tree_node_id);
1354 GetContentClient()->browser()->WillCreateURLLoaderFactory(
1355 frame_tree_node->current_frame_host(), true /* is_navigation */,
1356 &factory);
Ken Rockot314714c2017-11-05 23:36:241357 it->second->Clone(std::move(factory));
1358}
1359
scottmg69985212017-04-12 16:47:281360} // namespace content