blob: c86505ea6ba6487a5be94da38e339efc21d4ad9b [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"
Matt Menked9cad562018-08-10 21:47:0913#include "base/optional.h"
qufehdquf9c8433abd2018-07-10 16:57:2714#include "base/stl_util.h"
Gabriel Charette44db1422018-08-06 11:19:3315#include "base/task/post_task.h"
yzshen0f278522017-05-01 17:10:2216#include "base/trace_event/trace_event.h"
Min Qinda0ed2062018-02-23 22:00:5317#include "components/download/public/common/download_stats.h"
anantae3f159a2017-05-11 23:40:0718#include "content/browser/appcache/appcache_navigation_handle.h"
Hiroki Nakagawaff43e4472018-07-26 07:06:4619#include "content/browser/appcache/appcache_navigation_handle_core.h"
anantaa2c8ec62017-06-09 23:44:0520#include "content/browser/appcache/appcache_request_handler.h"
ananta5149d8e2017-04-21 00:01:3721#include "content/browser/blob_storage/chrome_blob_storage_context.h"
Andrey Kosyakov8d49c5062018-03-15 19:50:4922#include "content/browser/devtools/render_frame_devtools_agent_host.h"
Ken Rockot314714c2017-11-05 23:36:2423#include "content/browser/file_url_loader_factory.h"
Chris Mumford942075ad2018-05-19 00:22:0424#include "content/browser/fileapi/file_system_url_loader_factory.h"
jam8c4edd02017-05-06 18:50:3325#include "content/browser/frame_host/frame_tree_node.h"
scottmg69985212017-04-12 16:47:2826#include "content/browser/frame_host/navigation_request_info.h"
Kinuko Yasuda7f3e1722018-03-26 08:58:5827#include "content/browser/loader/navigation_loader_interceptor.h"
scottmg95feea52017-04-12 17:51:3328#include "content/browser/loader/navigation_url_loader_delegate.h"
arthursonzogni2695d04d2017-12-12 08:39:0129#include "content/browser/loader/resource_dispatcher_host_impl.h"
arthursonzogni40db5f52018-01-08 16:38:4930#include "content/browser/loader/resource_request_info_impl.h"
scottmgd2021c92017-05-15 16:58:0531#include "content/browser/resource_context_impl.h"
32#include "content/browser/service_worker/service_worker_navigation_handle.h"
33#include "content/browser/service_worker/service_worker_navigation_handle_core.h"
34#include "content/browser/service_worker/service_worker_request_handler.h"
jamc1905862017-05-16 14:45:3035#include "content/browser/storage_partition_impl.h"
36#include "content/browser/url_loader_factory_getter.h"
scottmgd2021c92017-05-15 16:58:0537#include "content/browser/web_contents/web_contents_impl.h"
Kouhei Ueno958c5f482018-03-19 08:20:3838#include "content/browser/web_package/signed_exchange_consts.h"
Kunihiko Sakamotoe6aa22e2018-06-15 03:26:5539#include "content/browser/web_package/signed_exchange_request_handler.h"
Tsuyoshi Horob85801592018-02-19 22:18:0740#include "content/browser/web_package/signed_exchange_url_loader_factory_for_non_network_service.h"
Tsuyoshi Horo46f5fff2018-05-10 12:33:3541#include "content/browser/web_package/signed_exchange_utils.h"
jam1a97290b2017-05-09 04:30:5042#include "content/browser/webui/url_data_manager_backend.h"
Chris Mumfordbae8a742018-03-01 23:02:2343#include "content/browser/webui/web_ui_url_loader_factory_internal.h"
Makoto Shimazu21950e82018-08-02 12:37:1444#include "content/common/mime_sniffing_throttle.h"
Kinuko Yasuda250577c2017-10-29 02:51:2445#include "content/common/navigation_subresource_loader_params.h"
Matt Menkea294b092018-07-06 17:53:3246#include "content/common/net/record_load_histograms.h"
yzshenefcb7c72017-06-16 23:12:3047#include "content/common/throttling_url_loader.h"
jamc1905862017-05-16 14:45:3048#include "content/public/browser/browser_context.h"
scottmg95feea52017-04-12 17:51:3349#include "content/public/browser/browser_thread.h"
yzshenefcb7c72017-06-16 23:12:3050#include "content/public/browser/content_browser_client.h"
Robbie McElratha5adc4e2018-07-03 23:53:0951#include "content/public/browser/download_utils.h"
scottmgefb697302017-04-12 22:37:3052#include "content/public/browser/global_request_id.h"
Dmitry Skiba7e8c7e22018-01-04 21:04:1853#include "content/public/browser/navigation_data.h"
scottmg69985212017-04-12 16:47:2854#include "content/public/browser/navigation_ui_data.h"
John Abd-El-Malek3ebdff862018-04-23 18:57:2155#include "content/public/browser/plugin_service.h"
arthursonzogni40db5f52018-01-08 16:38:4956#include "content/public/browser/resource_dispatcher_host_delegate.h"
scottmgefb697302017-04-12 22:37:3057#include "content/public/browser/ssl_status.h"
Jian Li18e29242018-05-10 22:25:1258#include "content/public/browser/url_loader_request_interceptor.h"
arthursonzogni2695d04d2017-12-12 08:39:0159#include "content/public/common/content_features.h"
ananta5149d8e2017-04-21 00:01:3760#include "content/public/common/referrer.h"
jam8c4edd02017-05-06 18:50:3361#include "content/public/common/url_constants.h"
Ken Rockot314714c2017-11-05 23:36:2462#include "content/public/common/url_utils.h"
John Abd-El-Malek3ebdff862018-04-23 18:57:2163#include "content/public/common/webplugininfo.h"
ananta5149d8e2017-04-21 00:01:3764#include "net/base/load_flags.h"
Matt Menked9cad562018-08-10 21:47:0965#include "net/cert/sct_status_flags.h"
66#include "net/cert/signed_certificate_timestamp_and_status.h"
Min Qin37db5102017-09-13 21:21:2567#include "net/http/http_content_disposition.h"
Chong Zhang7607f1f2018-06-01 20:52:2068#include "net/http/http_request_headers.h"
Matt Menked9cad562018-08-10 21:47:0969#include "net/ssl/ssl_info.h"
rhalavati4cda417b2017-06-12 11:00:2470#include "net/traffic_annotation/network_traffic_annotation.h"
Tsuyoshi Horo9e2ec4df2017-10-16 15:15:5571#include "net/url_request/redirect_util.h"
Daniel Bratell0dfa6282017-11-08 10:12:2372#include "net/url_request/url_request.h"
scottmg69985212017-04-12 16:47:2873#include "net/url_request/url_request_context.h"
Tsuyoshi Horo70014ad2018-02-14 11:20:1474#include "net/url_request/url_request_context_getter.h"
John Abd-El-Malek3ebdff862018-04-23 18:57:2175#include "ppapi/buildflags/buildflags.h"
John Abd-El-Malek89c02ae2018-02-01 01:56:1976#include "services/network/loader_util.h"
Yutaka Hiranod8789f92018-01-30 09:59:5177#include "services/network/public/cpp/features.h"
Antonio Gomes9cdc09a2018-05-07 23:24:2678#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
79#include "services/network/public/cpp/wrapper_shared_url_loader_factory.h"
Ken Rockot54311e62018-02-10 19:01:5280#include "services/network/public/mojom/request_context_frame_type.mojom.h"
81#include "services/network/public/mojom/url_loader_factory.mojom.h"
yzshenefcb7c72017-06-16 23:12:3082#include "services/service_manager/public/cpp/connector.h"
John Abd-El-Malek3ebdff862018-04-23 18:57:2183#include "third_party/blink/public/common/mime_util/mime_util.h"
Han Leonf1525df2018-07-11 03:47:5984#include "third_party/blink/public/common/service_worker/service_worker_utils.h"
scottmg69985212017-04-12 16:47:2885
86namespace content {
87
jambcc67882017-04-28 18:20:0988namespace {
yzshenfa5e57202017-05-02 21:24:1389
Jian Li18e29242018-05-10 22:25:1290class NavigationLoaderInterceptorBrowserContainer
91 : public NavigationLoaderInterceptor {
92 public:
93 explicit NavigationLoaderInterceptorBrowserContainer(
94 std::unique_ptr<URLLoaderRequestInterceptor> browser_interceptor)
95 : browser_interceptor_(std::move(browser_interceptor)) {}
96
97 ~NavigationLoaderInterceptorBrowserContainer() override = default;
98
Matt Falkenhagen43765122018-08-22 19:37:2299 void MaybeCreateLoader(
100 const network::ResourceRequest& tentative_resource_request,
101 ResourceContext* resource_context,
102 LoaderCallback callback,
103 FallbackCallback fallback_callback) override {
104 browser_interceptor_->MaybeCreateLoader(
105 tentative_resource_request, resource_context, std::move(callback));
Jian Li18e29242018-05-10 22:25:12106 }
107
108 private:
109 std::unique_ptr<URLLoaderRequestInterceptor> browser_interceptor_;
110};
111
John Abd-El-Malekdb3a13b2018-05-01 17:52:02112// Only used on the IO thread.
arthursonzogni1fd60e62018-05-09 15:57:32113base::LazyInstance<NavigationURLLoaderImpl::BeginNavigationInterceptor>::Leaky
John Abd-El-Malekdb3a13b2018-05-01 17:52:02114 g_interceptor = LAZY_INSTANCE_INITIALIZER;
115
Kinuko Yasuda7f3e1722018-03-26 08:58:58116// Returns true if interception by NavigationLoaderInterceptors is enabled.
Tsuyoshi Horo46f5fff2018-05-10 12:33:35117// Both ServiceWorkerServicification and SignedExchange require the loader
118// interception. So even if NetworkService is not enabled, returns true when one
119// of them is enabled.
Kinuko Yasuda7f3e1722018-03-26 08:58:58120bool IsLoaderInterceptionEnabled() {
Yutaka Hiranod8789f92018-01-30 09:59:51121 return base::FeatureList::IsEnabled(network::features::kNetworkService) ||
Han Leonf1525df2018-07-11 03:47:59122 blink::ServiceWorkerUtils::IsServicificationEnabled() ||
Tsuyoshi Horo46f5fff2018-05-10 12:33:35123 signed_exchange_utils::IsSignedExchangeHandlingEnabled();
Tsuyoshi Horob8d512a2018-01-25 17:01:59124}
125
ananta2e65213d2017-05-19 04:08:24126// Request ID for browser initiated requests. We start at -2 on the same lines
127// as ResourceDispatcherHostImpl.
128int g_next_request_id = -2;
arthursonzogni40db5f52018-01-08 16:38:49129GlobalRequestID MakeGlobalRequestID() {
130 return GlobalRequestID(-1, g_next_request_id--);
131}
ananta2e65213d2017-05-19 04:08:24132
Emily Starkb09f19a2017-11-22 22:41:47133size_t GetCertificateChainsSizeInKB(const net::SSLInfo& ssl_info) {
134 base::Pickle cert_pickle;
135 ssl_info.cert->Persist(&cert_pickle);
136 base::Pickle unverified_cert_pickle;
137 ssl_info.unverified_cert->Persist(&unverified_cert_pickle);
138 return (cert_pickle.size() + unverified_cert_pickle.size()) / 1000;
139}
140
scottmgd2021c92017-05-15 16:58:05141WebContents* GetWebContentsFromFrameTreeNodeID(int frame_tree_node_id) {
142 DCHECK_CURRENTLY_ON(BrowserThread::UI);
143 FrameTreeNode* frame_tree_node =
144 FrameTreeNode::GloballyFindByID(frame_tree_node_id);
145 if (!frame_tree_node)
146 return nullptr;
ananta5149d8e2017-04-21 00:01:37147
scottmgd2021c92017-05-15 16:58:05148 return WebContentsImpl::FromFrameTreeNode(frame_tree_node);
149}
150
Daniel Bratellcf0b485c2017-11-09 22:42:50151const net::NetworkTrafficAnnotationTag kNavigationUrlLoaderTrafficAnnotation =
Ramin Halavatie99206e92017-06-23 05:02:50152 net::DefineNetworkTrafficAnnotation("navigation_url_loader", R"(
Ramin Halavati7b5ce1c2017-07-03 09:13:09153 semantics {
154 sender: "Navigation URL Loader"
155 description:
156 "This request is issued by a main frame navigation to fetch the "
157 "content of the page that is being navigated to."
158 trigger:
159 "Navigating Chrome (by clicking on a link, bookmark, history item, "
160 "using session restore, etc)."
161 data:
162 "Arbitrary site-controlled data can be included in the URL, HTTP "
163 "headers, and request body. Requests may include cookies and "
164 "site-specific credentials."
165 destination: WEBSITE
166 }
167 policy {
Ramin Halavati3b979782017-07-21 11:40:26168 cookies_allowed: YES
Ramin Halavati7b5ce1c2017-07-03 09:13:09169 cookies_store: "user"
170 setting: "This feature cannot be disabled."
Ramin Halavati386daa62017-08-17 10:41:59171 chrome_policy {
172 URLBlacklist {
173 URLBlacklist: { entries: '*' }
174 }
175 }
176 chrome_policy {
177 URLWhitelist {
178 URLWhitelist { }
179 }
180 }
181 }
182 comments:
183 "Chrome would be unable to navigate to websites without this type of "
184 "request. Using either URLBlacklist or URLWhitelist policies (or a "
185 "combination of both) limits the scope of these requests."
186 )");
Ramin Halavatie99206e92017-06-23 05:02:50187
Tsuyoshi Horob8d512a2018-01-25 17:01:59188std::unique_ptr<network::ResourceRequest> CreateResourceRequest(
189 NavigationRequestInfo* request_info,
190 int frame_tree_node_id,
191 bool allow_download) {
192 // TODO(scottmg): Port over stuff from RDHI::BeginNavigationRequest() here.
193 auto new_request = std::make_unique<network::ResourceRequest>();
194
195 new_request->method = request_info->common_params.method;
196 new_request->url = request_info->common_params.url;
197 new_request->site_for_cookies = request_info->site_for_cookies;
Tarun Bansal98260cd2018-02-17 07:52:23198
199 net::RequestPriority net_priority = net::HIGHEST;
200 if (!request_info->is_main_frame &&
201 base::FeatureList::IsEnabled(features::kLowPriorityIframes)) {
202 net_priority = net::LOWEST;
203 }
204 new_request->priority = net_priority;
205
Tsuyoshi Horob8d512a2018-01-25 17:01:59206 new_request->render_frame_id = frame_tree_node_id;
207
208 // The code below to set fields like request_initiator, referrer, etc has
209 // been copied from ResourceDispatcherHostImpl. We did not refactor the
210 // common code into a function, because RDHI uses accessor functions on the
211 // URLRequest class to set these fields. whereas we use ResourceRequest here.
212 new_request->request_initiator = request_info->begin_params->initiator_origin;
213 new_request->referrer = request_info->common_params.referrer.url;
214 new_request->referrer_policy = Referrer::ReferrerPolicyForUrlRequest(
215 request_info->common_params.referrer.policy);
216 new_request->headers.AddHeadersFromString(
217 request_info->begin_params->headers);
Kouhei Ueno958c5f482018-03-19 08:20:38218
219 std::string accept_value = network::kFrameAcceptHeader;
Tsuyoshi Horo46f5fff2018-05-10 12:33:35220 // TODO(https://crbug.com/840704): Decide whether the Accept header should
221 // advertise the state of kSignedHTTPExchangeOriginTrial before starting the
222 // Origin-Trial.
223 if (signed_exchange_utils::IsSignedExchangeHandlingEnabled()) {
Kouhei Ueno958c5f482018-03-19 08:20:38224 DCHECK(!accept_value.empty());
225 accept_value.append(kAcceptHeaderSignedExchangeSuffix);
226 }
227
228 new_request->headers.SetHeader(network::kAcceptHeader, accept_value);
Tsuyoshi Horob8d512a2018-01-25 17:01:59229
230 new_request->resource_type = request_info->is_main_frame
231 ? RESOURCE_TYPE_MAIN_FRAME
232 : RESOURCE_TYPE_SUB_FRAME;
233 if (request_info->is_main_frame)
234 new_request->update_first_party_url_on_redirect = true;
235
236 int load_flags = request_info->begin_params->load_flags;
Tsuyoshi Horob8d512a2018-01-25 17:01:59237 if (request_info->is_main_frame)
238 load_flags |= net::LOAD_MAIN_FRAME_DEPRECATED;
239
240 // Sync loads should have maximum priority and should be the only
241 // requests that have the ignore limits flag set.
242 DCHECK(!(load_flags & net::LOAD_IGNORE_LIMITS));
243
244 new_request->load_flags = load_flags;
245
246 new_request->request_body = request_info->common_params.post_data.get();
247 new_request->report_raw_headers = request_info->report_raw_headers;
248 new_request->allow_download = allow_download;
249 new_request->enable_load_timing = true;
250
251 new_request->fetch_request_mode = network::mojom::FetchRequestMode::kNavigate;
252 new_request->fetch_credentials_mode =
253 network::mojom::FetchCredentialsMode::kInclude;
254 new_request->fetch_redirect_mode = network::mojom::FetchRedirectMode::kManual;
Yutaka Hirano4b9b7a7f2018-03-07 14:35:15255 new_request->fetch_request_context_type =
Richard Li01f04032018-09-19 07:45:59256 static_cast<int>(request_info->begin_params->request_context_type);
Carlos ILa54c59a2018-06-11 19:43:03257 new_request->upgrade_if_insecure = request_info->upgrade_if_insecure;
Tsuyoshi Horoc1ab7122018-06-19 05:48:13258 new_request->throttling_profile_id = request_info->devtools_frame_token;
Tsuyoshi Horob8d512a2018-01-25 17:01:59259 return new_request;
260}
261
Makoto Shimazu44c2c3232018-03-30 01:10:20262// Used only when NetworkService is disabled but IsLoaderInterceptionEnabled()
263// is true.
264std::unique_ptr<NavigationRequestInfo> CreateNavigationRequestInfoForRedirect(
265 const NavigationRequestInfo& previous_request_info,
266 const network::ResourceRequest& updated_resource_request) {
267 DCHECK(!base::FeatureList::IsEnabled(network::features::kNetworkService));
268 DCHECK(IsLoaderInterceptionEnabled());
269
270 CommonNavigationParams new_common_params =
271 previous_request_info.common_params;
272 new_common_params.url = updated_resource_request.url;
273 new_common_params.referrer =
Makoto Shimazue8019fb2018-06-26 03:54:31274 Referrer(updated_resource_request.referrer,
Makoto Shimazu44c2c3232018-03-30 01:10:20275 Referrer::NetReferrerPolicyToBlinkReferrerPolicy(
276 updated_resource_request.referrer_policy));
277 new_common_params.method = updated_resource_request.method;
278 new_common_params.post_data = updated_resource_request.request_body;
Makoto Shimazu44c2c3232018-03-30 01:10:20279
280 mojom::BeginNavigationParamsPtr new_begin_params =
281 previous_request_info.begin_params.Clone();
282 new_begin_params->headers = updated_resource_request.headers.ToString();
283
284 return std::make_unique<NavigationRequestInfo>(
285 std::move(new_common_params), std::move(new_begin_params),
286 updated_resource_request.site_for_cookies,
287 previous_request_info.is_main_frame,
288 previous_request_info.parent_is_main_frame,
289 previous_request_info.are_ancestors_secure,
290 previous_request_info.frame_tree_node_id,
291 previous_request_info.is_for_guests_only,
292 previous_request_info.report_raw_headers,
Marijn Kruisselbrink07bf59d52018-04-03 21:50:25293 previous_request_info.is_prerendering,
Carlos ILa54c59a2018-06-11 19:43:03294 previous_request_info.upgrade_if_insecure,
Tsuyoshi Horo32b51f12018-05-09 17:58:46295 nullptr /* blob_url_loader_factory */,
Tsuyoshi Horoc1ab7122018-06-19 05:48:13296 previous_request_info.devtools_navigation_token,
297 previous_request_info.devtools_frame_token);
Makoto Shimazu44c2c3232018-03-30 01:10:20298}
299
John Abd-El-Maleka67add82018-03-09 18:22:01300// Called for requests that we don't have a URLLoaderFactory for.
Matt Falkenhagen43765122018-08-22 19:37:22301void UnknownSchemeCallback(
302 bool handled_externally,
303 const network::ResourceRequest& /* resource_request */,
304 network::mojom::URLLoaderRequest request,
305 network::mojom::URLLoaderClientPtr client) {
John Abd-El-Maleka67add82018-03-09 18:22:01306 client->OnComplete(network::URLLoaderCompletionStatus(
307 handled_externally ? net::ERR_ABORTED : net::ERR_UNKNOWN_URL_SCHEME));
308}
309
Clark DuVallbf7722f2018-08-03 18:03:33310// Returns whether this URL can be handled by the default network service
311// URLLoader.
312bool IsURLHandledByDefaultLoader(const GURL& url) {
313 // Data URLs are only handled by the network service if
314 // |enable_data_url_support| is set in NetworkContextParams. This is set to
315 // true for the context used by NavigationURLLoaderImpl, so in addition to
316 // checking whether the URL is handled by the network service, we also need to
317 // check for the data scheme.
318 return IsURLHandledByNetworkService(url) || url.SchemeIs(url::kDataScheme);
319}
320
321// Determines whether it is safe to redirect to |url|.
Clark DuVallb2680c22018-08-10 15:27:27322bool IsRedirectSafe(const GURL& url, ResourceContext* resource_context) {
323 return IsSafeRedirectTarget(url) &&
Clark DuVallbf7722f2018-08-03 18:03:33324 GetContentClient()->browser()->IsSafeRedirectTarget(url,
325 resource_context);
326}
327
yzshenfa5e57202017-05-02 21:24:13328} // namespace
329
kinuko69732972017-05-29 08:50:07330// Kept around during the lifetime of the navigation request, and is
331// responsible for dispatching a ResourceRequest to the appropriate
kinukod8b13e212017-06-07 06:59:26332// URLLoader. In order to get the right URLLoader it builds a vector
Kinuko Yasuda7f3e1722018-03-26 08:58:58333// of NavigationLoaderInterceptors and successively calls MaybeCreateLoader
kinukod8b13e212017-06-07 06:59:26334// on each until the request is successfully handled. The same sequence
335// may be performed multiple times when redirects happen.
Alex Clarke1e08882b32017-10-06 14:22:40336// TODO(michaeln): Expose this class and add more unittests.
arthursonzogni1fd60e62018-05-09 15:57:32337class NavigationURLLoaderImpl::URLLoaderRequestController
John Abd-El-Malekb165dc52018-01-18 17:12:18338 : public network::mojom::URLLoaderClient {
kinuko69732972017-05-29 08:50:07339 public:
jam9354af82017-06-03 21:59:41340 URLLoaderRequestController(
Kinuko Yasuda7f3e1722018-03-26 08:58:58341 std::vector<std::unique_ptr<NavigationLoaderInterceptor>>
342 initial_interceptors,
John Abd-El-Malek1df61792018-01-12 20:40:45343 std::unique_ptr<network::ResourceRequest> resource_request,
jam9354af82017-06-03 21:59:41344 ResourceContext* resource_context,
arthursonzogni40db5f52018-01-08 16:38:49345 const GURL& url,
Matt Menked9cad562018-08-10 21:47:09346 bool is_main_frame,
Ken Rockota0dfaca12018-02-15 07:26:25347 network::mojom::URLLoaderFactoryRequest proxied_factory_request,
348 network::mojom::URLLoaderFactoryPtrInfo proxied_factory_info,
John Abd-El-Maleka67add82018-03-09 18:22:01349 std::set<std::string> known_schemes,
Clark DuVallb2680c22018-08-10 15:27:27350 bool bypass_redirect_checks,
arthursonzogni1fd60e62018-05-09 15:57:32351 const base::WeakPtr<NavigationURLLoaderImpl>& owner)
Kinuko Yasuda7f3e1722018-03-26 08:58:58352 : interceptors_(std::move(initial_interceptors)),
Alex Clarke1e08882b32017-10-06 14:22:40353 resource_request_(std::move(resource_request)),
kinuko69732972017-05-29 08:50:07354 resource_context_(resource_context),
arthursonzogni40db5f52018-01-08 16:38:49355 url_(url),
Matt Menked9cad562018-08-10 21:47:09356 is_main_frame_(is_main_frame),
anantab9800e52017-07-29 18:04:13357 owner_(owner),
arthursonzogni2695d04d2017-12-12 08:39:01358 response_loader_binding_(this),
Ken Rockota0dfaca12018-02-15 07:26:25359 proxied_factory_request_(std::move(proxied_factory_request)),
360 proxied_factory_info_(std::move(proxied_factory_info)),
John Abd-El-Maleka67add82018-03-09 18:22:01361 known_schemes_(std::move(known_schemes)),
Clark DuVallb2680c22018-08-10 15:27:27362 bypass_redirect_checks_(bypass_redirect_checks),
arthursonzogni2695d04d2017-12-12 08:39:01363 weak_factory_(this) {}
kinuko69732972017-05-29 08:50:07364
yzshenefcb7c72017-06-16 23:12:30365 ~URLLoaderRequestController() override {
kinuko69732972017-05-29 08:50:07366 DCHECK_CURRENTLY_ON(BrowserThread::IO);
Matt Menkea294b092018-07-06 17:53:32367
368 // If neither OnCompleted nor OnReceivedResponse has been invoked, the
369 // request was canceled before receiving a response, so log a cancellation.
370 // Results after receiving a non-error response are logged in the renderer,
371 // if the request is passed to one. If it's a download, or not passed to a
372 // renderer for some other reason, results will not be logged for the
373 // request. The net::OK check may not be necessary - the case where OK is
374 // received without receiving any headers looks broken, anyways.
375 if (!received_response_ && (!status_ || status_->error_code != net::OK)) {
376 RecordLoadHistograms(url_, resource_request_->resource_type,
377 status_ ? status_->error_code : net::ERR_ABORTED);
378 }
kinuko69732972017-05-29 08:50:07379 }
380
arthursonzognib521c6a2018-01-08 12:23:40381 static uint32_t GetURLLoaderOptions(bool is_main_frame) {
Livvie Lin139bf442018-08-10 00:18:54382 uint32_t options = network::mojom::kURLLoadOptionNone;
Makoto Shimazu34ab40c2018-08-23 04:32:03383
384 // Ensure that Mime sniffing works.
385 options |= network::mojom::kURLLoadOptionSniffMimeType;
386
Livvie Lin139bf442018-08-10 00:18:54387 if (is_main_frame) {
388 // SSLInfo is not needed on subframe responses because users can inspect
389 // only the certificate for the main frame when using the info bubble.
390 options |= network::mojom::kURLLoadOptionSendSSLInfoWithResponse;
John Abd-El-Malekb165dc52018-01-18 17:12:18391 options |= network::mojom::kURLLoadOptionSendSSLInfoForCertificateError;
Livvie Lin139bf442018-08-10 00:18:54392 }
arthursonzognib521c6a2018-01-08 12:23:40393
Makoto Shimazu34ab40c2018-08-23 04:32:03394 if (!base::FeatureList::IsEnabled(network::features::kNetworkService)) {
arthursonzognib521c6a2018-01-08 12:23:40395 // TODO(arthursonzogni): This is a temporary option. Remove this as soon
396 // as the InterceptingResourceHandler is removed.
397 // See https://crbug.com/791049.
John Abd-El-Malekb165dc52018-01-18 17:12:18398 options |= network::mojom::kURLLoadOptionPauseOnResponseStarted;
arthursonzognib521c6a2018-01-08 12:23:40399 }
400
401 return options;
402 }
403
Makoto Shimazu44c2c3232018-03-30 01:10:20404 SingleRequestURLLoaderFactory::RequestHandler
405 CreateDefaultRequestHandlerForNonNetworkService(
406 net::URLRequestContextGetter* url_request_context_getter,
407 storage::FileSystemContext* upload_file_system_context,
408 ServiceWorkerNavigationHandleCore* service_worker_navigation_handle_core,
Makoto Shimazu684a5ad2018-05-29 08:20:50409 AppCacheNavigationHandleCore* appcache_handle_core,
410 bool was_request_intercepted) const {
Matt Falkenhagen34739112018-07-17 20:36:33411 DCHECK_CURRENTLY_ON(BrowserThread::IO);
412 DCHECK(!base::FeatureList::IsEnabled(network::features::kNetworkService));
413 DCHECK(started_);
414
Makoto Shimazu44c2c3232018-03-30 01:10:20415 return base::BindOnce(
416 &URLLoaderRequestController::CreateNonNetworkServiceURLLoader,
417 weak_factory_.GetWeakPtr(),
418 base::Unretained(url_request_context_getter),
419 base::Unretained(upload_file_system_context),
420 std::make_unique<NavigationRequestInfo>(*request_info_),
Makoto Shimazu684a5ad2018-05-29 08:20:50421 // If the request has already been intercepted, the request should not
422 // be intercepted again.
423 // S13nServiceWorker: Requests are intercepted by S13nServiceWorker
424 // before the default request handler when needed, so we never need to
425 // pass |service_worker_navigation_handle_core| here.
Han Leonf1525df2018-07-11 03:47:59426 base::Unretained(
427 blink::ServiceWorkerUtils::IsServicificationEnabled() ||
428 was_request_intercepted
429 ? nullptr
430 : service_worker_navigation_handle_core),
Makoto Shimazu684a5ad2018-05-29 08:20:50431 base::Unretained(was_request_intercepted ? nullptr
432 : appcache_handle_core));
Makoto Shimazu44c2c3232018-03-30 01:10:20433 }
434
arthursonzogni2695d04d2017-12-12 08:39:01435 void CreateNonNetworkServiceURLLoader(
436 net::URLRequestContextGetter* url_request_context_getter,
437 storage::FileSystemContext* upload_file_system_context,
438 std::unique_ptr<NavigationRequestInfo> request_info,
arthursonzogni2695d04d2017-12-12 08:39:01439 ServiceWorkerNavigationHandleCore* service_worker_navigation_handle_core,
440 AppCacheNavigationHandleCore* appcache_handle_core,
Matt Falkenhagen43765122018-08-22 19:37:22441 const network::ResourceRequest& /* resource_request */,
John Abd-El-Malekb165dc52018-01-18 17:12:18442 network::mojom::URLLoaderRequest url_loader,
443 network::mojom::URLLoaderClientPtr url_loader_client) {
Matt Falkenhagen43765122018-08-22 19:37:22444 // |resource_request| is unused here. Its info may not be the same as
445 // |request_info|, because URLLoaderThrottles may have rewritten it. We
446 // don't propagate the fields to |request_info| here because the request
447 // will usually go to ResourceDispatcherHost which does its own request
448 // modification independent of URLLoaderThrottles.
Matt Falkenhagen34739112018-07-17 20:36:33449 DCHECK_CURRENTLY_ON(BrowserThread::IO);
450 DCHECK(!base::FeatureList::IsEnabled(network::features::kNetworkService));
451 DCHECK(started_);
Matt Falkenhagend2867e82018-07-04 08:26:38452
Tsuyoshi Horob8d512a2018-01-25 17:01:59453 default_loader_used_ = true;
Tsuyoshi Horo46f5fff2018-05-10 12:33:35454 if (signed_exchange_utils::IsSignedExchangeHandlingEnabled()) {
Matt Falkenhagen43765122018-08-22 19:37:22455 // TODO(falken): Understand and add a comment about why
456 // SignedExchangeRequestHandler is the only interceptor being added here.
Kinuko Yasudabe4ad292018-07-06 01:33:39457 DCHECK(!network_loader_factory_);
Tsuyoshi Horo561163b2018-03-27 03:11:23458 // It is safe to pass the callback of CreateURLLoaderThrottles with the
Tsuyoshi Horo70014ad2018-02-14 11:20:14459 // unretained |this|, because the passed callback will be used by a
460 // SignedExchangeHandler which is indirectly owned by |this| until its
461 // header is verified and parsed, that's where the getter is used.
Kunihiko Sakamotoe6aa22e2018-06-15 03:26:55462 interceptors_.push_back(std::make_unique<SignedExchangeRequestHandler>(
Tsuyoshi Horo70014ad2018-02-14 11:20:14463 url::Origin::Create(request_info->common_params.url),
Tsuyoshi Horo32b51f12018-05-09 17:58:46464 request_info->common_params.url,
Kinuko Yasuda32a25652018-02-19 08:14:25465 GetURLLoaderOptions(request_info->is_main_frame),
Tsuyoshi Horocdbb4902018-04-12 06:09:14466 request_info->frame_tree_node_id,
Tsuyoshi Horo32b51f12018-05-09 17:58:46467 request_info->devtools_navigation_token,
Tsuyoshi Horob8d381182018-06-19 10:07:29468 request_info->devtools_frame_token, request_info->report_raw_headers,
Tsuyoshi Horo6e6782d2018-06-07 02:32:47469 request_info->begin_params->load_flags,
Tsuyoshi Horo70014ad2018-02-14 11:20:14470 base::MakeRefCounted<
471 SignedExchangeURLLoaderFactoryForNonNetworkService>(
472 resource_context_, url_request_context_getter),
473 base::BindRepeating(
474 &URLLoaderRequestController::CreateURLLoaderThrottles,
John Abd-El-Malek9ee2a712018-08-24 19:50:45475 base::Unretained(this))));
Tsuyoshi Horob8d512a2018-01-25 17:01:59476 }
477
John Abd-El-Malekdb3a13b2018-05-01 17:52:02478 uint32_t options = GetURLLoaderOptions(request_info->is_main_frame);
479
480 bool intercepted = false;
481 if (g_interceptor.Get()) {
482 intercepted = g_interceptor.Get().Run(
483 &url_loader, frame_tree_node_id_, 0 /* request_id */, options,
484 *resource_request_.get(), &url_loader_client,
485 net::MutableNetworkTrafficAnnotationTag(
486 kNavigationUrlLoaderTrafficAnnotation));
487 }
488
arthursonzogni2695d04d2017-12-12 08:39:01489 // The ResourceDispatcherHostImpl can be null in unit tests.
John Abd-El-Malekdb3a13b2018-05-01 17:52:02490 if (!intercepted && ResourceDispatcherHostImpl::Get()) {
arthursonzogni2695d04d2017-12-12 08:39:01491 ResourceDispatcherHostImpl::Get()->BeginNavigationRequest(
492 resource_context_, url_request_context_getter->GetURLRequestContext(),
493 upload_file_system_context, *request_info,
arthursonzogni662d723c2018-04-24 16:13:22494 std::move(navigation_ui_data_), std::move(url_loader_client),
arthursonzogni2695d04d2017-12-12 08:39:01495 std::move(url_loader), service_worker_navigation_handle_core,
Makoto Shimazuff60c1412018-06-19 06:17:33496 appcache_handle_core, options, global_request_id_);
arthursonzogni2695d04d2017-12-12 08:39:01497 }
498
499 // TODO(arthursonzogni): Detect when the ResourceDispatcherHost didn't
500 // create a URLLoader. When it doesn't, do not send OnRequestStarted().
501 BrowserThread::PostTask(
502 BrowserThread::UI, FROM_HERE,
arthursonzogni1fd60e62018-05-09 15:57:32503 base::BindOnce(&NavigationURLLoaderImpl::OnRequestStarted, owner_,
504 base::TimeTicks::Now()));
arthursonzogni2695d04d2017-12-12 08:39:01505 }
506
507 // TODO(arthursonzogni): See if this could eventually be unified with Start().
508 void StartWithoutNetworkService(
509 net::URLRequestContextGetter* url_request_context_getter,
510 storage::FileSystemContext* upload_file_system_context,
511 ServiceWorkerNavigationHandleCore* service_worker_navigation_handle_core,
512 AppCacheNavigationHandleCore* appcache_handle_core,
513 std::unique_ptr<NavigationRequestInfo> request_info,
514 std::unique_ptr<NavigationUIData> navigation_ui_data) {
Matt Falkenhagen34739112018-07-17 20:36:33515 DCHECK_CURRENTLY_ON(BrowserThread::IO);
516 DCHECK(!base::FeatureList::IsEnabled(network::features::kNetworkService));
517 DCHECK(!started_);
arthursonzogni2695d04d2017-12-12 08:39:01518 started_ = true;
Makoto Shimazu44c2c3232018-03-30 01:10:20519 request_info_ = std::move(request_info);
520 frame_tree_node_id_ = request_info_->frame_tree_node_id;
Yuzhu Shencb3011f62018-02-08 02:51:50521 web_contents_getter_ = base::BindRepeating(
Yuzhu Shen9508fc72018-02-08 23:18:59522 &GetWebContentsFromFrameTreeNodeID, frame_tree_node_id_);
Makoto Shimazu44c2c3232018-03-30 01:10:20523 navigation_ui_data_ = std::move(navigation_ui_data);
Makoto Shimazuff60c1412018-06-19 06:17:33524 // The ResourceDispatcherHostImpl can be null in unit tests.
525 ResourceDispatcherHostImpl* rph = ResourceDispatcherHostImpl::Get();
526 if (rph)
527 global_request_id_ = rph->MakeGlobalRequestID();
528
Makoto Shimazu44c2c3232018-03-30 01:10:20529 default_request_handler_factory_ = base::BindRepeating(
530 &URLLoaderRequestController::
531 CreateDefaultRequestHandlerForNonNetworkService,
532 // base::Unretained(this) is safe since
533 // |default_request_handler_factory_| could be called only from |this|.
534 base::Unretained(this), base::Unretained(url_request_context_getter),
535 base::Unretained(upload_file_system_context),
arthursonzogni2695d04d2017-12-12 08:39:01536 base::Unretained(service_worker_navigation_handle_core),
537 base::Unretained(appcache_handle_core));
538
Marijn Kruisselbrink8a7fd102018-06-05 17:30:39539 // Requests to Blob scheme won't get redirected to/from other schemes
540 // or be intercepted, so we just let it go here.
541 if (request_info_->common_params.url.SchemeIsBlob() &&
542 request_info_->blob_url_loader_factory) {
543 url_loader_ = ThrottlingURLLoader::CreateLoaderAndStart(
544 network::SharedURLLoaderFactory::Create(
545 std::move(request_info_->blob_url_loader_factory)),
546 CreateURLLoaderThrottles(), -1 /* routing_id */, 0 /* request_id? */,
547 network::mojom::kURLLoadOptionNone, resource_request_.get(), this,
548 kNavigationUrlLoaderTrafficAnnotation,
549 base::ThreadTaskRunnerHandle::Get());
550 return;
551 }
552
Makoto Shimazu44c2c3232018-03-30 01:10:20553 // If S13nServiceWorker is disabled, just use
554 // |default_request_handler_factory_| and return. The non network service
555 // request handling goes through ResourceDispatcherHost which has legacy
556 // hooks for service worker (ServiceWorkerRequestInterceptor), so no service
557 // worker interception is needed here.
Han Leonf1525df2018-07-11 03:47:59558 if (!blink::ServiceWorkerUtils::IsServicificationEnabled() ||
Makoto Shimazu44c2c3232018-03-30 01:10:20559 !service_worker_navigation_handle_core) {
560 url_loader_ = ThrottlingURLLoader::CreateLoaderAndStart(
561 base::MakeRefCounted<SingleRequestURLLoaderFactory>(
Makoto Shimazu684a5ad2018-05-29 08:20:50562 default_request_handler_factory_.Run(
563 false /* was_request_intercepted */)),
Makoto Shimazu44c2c3232018-03-30 01:10:20564 CreateURLLoaderThrottles(), -1 /* routing_id */, 0 /* request_id */,
565 network::mojom::kURLLoadOptionNone, resource_request_.get(),
566 this /* client */, kNavigationUrlLoaderTrafficAnnotation,
567 base::ThreadTaskRunnerHandle::Get());
568 return;
569 }
570
571 // Otherwise, if S13nServiceWorker is enabled, create an interceptor so
572 // S13nServiceWorker has a chance to intercept the request.
573 std::unique_ptr<NavigationLoaderInterceptor> service_worker_interceptor =
574 CreateServiceWorkerInterceptor(*request_info_,
575 service_worker_navigation_handle_core);
576 // If an interceptor is not created for some reasons (e.g. the origin is not
577 // secure), we no longer have to go through the rest of the network service
578 // code.
579 if (!service_worker_interceptor) {
580 url_loader_ = ThrottlingURLLoader::CreateLoaderAndStart(
581 base::MakeRefCounted<SingleRequestURLLoaderFactory>(
Makoto Shimazu684a5ad2018-05-29 08:20:50582 default_request_handler_factory_.Run(
583 false /* was_request_intercepted */)),
Makoto Shimazu44c2c3232018-03-30 01:10:20584 CreateURLLoaderThrottles(), -1 /* routing_id */, 0 /* request_id */,
585 network::mojom::kURLLoadOptionNone, resource_request_.get(),
586 this /* client */, kNavigationUrlLoaderTrafficAnnotation,
587 base::ThreadTaskRunnerHandle::Get());
588 return;
589 }
590
591 interceptors_.push_back(std::move(service_worker_interceptor));
592
Makoto Shimazu44c2c3232018-03-30 01:10:20593 Restart();
arthursonzogni2695d04d2017-12-12 08:39:01594 }
595
kinuko69732972017-05-29 08:50:07596 void Start(
Kinuko Yasudabe4ad292018-07-06 01:33:39597 std::unique_ptr<network::SharedURLLoaderFactoryInfo>
598 network_loader_factory_info,
kinuko69732972017-05-29 08:50:07599 ServiceWorkerNavigationHandleCore* service_worker_navigation_handle_core,
600 AppCacheNavigationHandleCore* appcache_handle_core,
601 std::unique_ptr<NavigationRequestInfo> request_info,
John Abd-El-Malekeb1a5382018-01-05 16:58:00602 std::unique_ptr<NavigationUIData> navigation_ui_data,
John Abd-El-Malekb165dc52018-01-18 17:12:18603 network::mojom::URLLoaderFactoryPtrInfo factory_for_webui,
John Abd-El-Malek576c6132017-11-04 00:33:58604 int frame_tree_node_id,
kinuko69732972017-05-29 08:50:07605 std::unique_ptr<service_manager::Connector> connector) {
Matt Falkenhagen34739112018-07-17 20:36:33606 DCHECK_CURRENTLY_ON(BrowserThread::IO);
607 DCHECK(base::FeatureList::IsEnabled(network::features::kNetworkService));
608 DCHECK(!started_);
arthursonzogni40db5f52018-01-08 16:38:49609 global_request_id_ = MakeGlobalRequestID();
John Abd-El-Malek576c6132017-11-04 00:33:58610 frame_tree_node_id_ = frame_tree_node_id;
Alex Clarke1e08882b32017-10-06 14:22:40611 started_ = true;
John Abd-El-Malek576c6132017-11-04 00:33:58612 web_contents_getter_ =
613 base::Bind(&GetWebContentsFromFrameTreeNodeID, frame_tree_node_id);
John Abd-El-Malekeb1a5382018-01-05 16:58:00614 navigation_ui_data_ = std::move(navigation_ui_data);
kinuko69732972017-05-29 08:50:07615
Kinuko Yasudabe4ad292018-07-06 01:33:39616 DCHECK(network_loader_factory_info);
617 network_loader_factory_ = network::SharedURLLoaderFactory::Create(
618 std::move(network_loader_factory_info));
619
kinuko69732972017-05-29 08:50:07620 if (resource_request_->request_body) {
mmenkeed44e6c2017-06-28 21:13:32621 GetBodyBlobDataHandles(resource_request_->request_body.get(),
622 resource_context_, &blob_handles_);
kinuko69732972017-05-29 08:50:07623 }
624
625 // Requests to WebUI scheme won't get redirected to/from other schemes
626 // or be intercepted, so we just let it go here.
627 if (factory_for_webui.is_valid()) {
yzshenefcb7c72017-06-16 23:12:30628 url_loader_ = ThrottlingURLLoader::CreateLoaderAndStart(
Antonio Gomes9cdc09a2018-05-07 23:24:26629 base::MakeRefCounted<network::WrapperSharedURLLoaderFactory>(
Yuzhu Shend87986f2018-01-17 22:16:37630 std::move(factory_for_webui)),
Ken Rockot5f734e32018-06-13 01:41:03631 CreateURLLoaderThrottles(), 0 /* routing_id */,
632 global_request_id_.request_id, network::mojom::kURLLoadOptionNone,
633 resource_request_.get(), this, kNavigationUrlLoaderTrafficAnnotation,
Hajime Hoshif5ef35262017-11-28 19:13:00634 base::ThreadTaskRunnerHandle::Get());
kinuko69732972017-05-29 08:50:07635 return;
636 }
637
Marijn Kruisselbrink07bf59d52018-04-03 21:50:25638 // Requests to Blob scheme won't get redirected to/from other schemes
639 // or be intercepted, so we just let it go here.
640 if (request_info->common_params.url.SchemeIsBlob() &&
641 request_info->blob_url_loader_factory) {
642 url_loader_ = ThrottlingURLLoader::CreateLoaderAndStart(
643 network::SharedURLLoaderFactory::Create(
644 std::move(request_info->blob_url_loader_factory)),
Ken Rockot5f734e32018-06-13 01:41:03645 CreateURLLoaderThrottles(), 0 /* routing_id */,
646 global_request_id_.request_id, network::mojom::kURLLoadOptionNone,
647 resource_request_.get(), this, kNavigationUrlLoaderTrafficAnnotation,
Marijn Kruisselbrink07bf59d52018-04-03 21:50:25648 base::ThreadTaskRunnerHandle::Get());
649 return;
650 }
651
kinuko69732972017-05-29 08:50:07652 if (service_worker_navigation_handle_core) {
Kinuko Yasuda7f3e1722018-03-26 08:58:58653 std::unique_ptr<NavigationLoaderInterceptor> service_worker_interceptor =
Makoto Shimazu44c2c3232018-03-30 01:10:20654 CreateServiceWorkerInterceptor(*request_info,
655 service_worker_navigation_handle_core);
Kinuko Yasuda7f3e1722018-03-26 08:58:58656 if (service_worker_interceptor)
657 interceptors_.push_back(std::move(service_worker_interceptor));
kinuko69732972017-05-29 08:50:07658 }
659
660 if (appcache_handle_core) {
Kinuko Yasuda7f3e1722018-03-26 08:58:58661 std::unique_ptr<NavigationLoaderInterceptor> appcache_interceptor =
Hiroki Nakagawaff43e4472018-07-26 07:06:46662 AppCacheRequestHandler::InitializeForMainResourceNetworkService(
663 *resource_request_, appcache_handle_core->host()->GetWeakPtr(),
Kinuko Yasudabe4ad292018-07-06 01:33:39664 network_loader_factory_);
Kinuko Yasuda7f3e1722018-03-26 08:58:58665 if (appcache_interceptor)
666 interceptors_.push_back(std::move(appcache_interceptor));
kinuko69732972017-05-29 08:50:07667 }
668
Tsuyoshi Horo46f5fff2018-05-10 12:33:35669 if (signed_exchange_utils::IsSignedExchangeHandlingEnabled()) {
Kunihiko Sakamotoe9a0502c2018-06-06 09:29:51670 // Signed Exchange is currently disabled when Network Service is enabled
Kunihiko Sakamotoe6aa22e2018-06-15 03:26:55671 // (https://crbug.com/849935), but still create
672 // SignedExchangeRequestHandler in order to show error message (and
673 // devtools warning) to users.
Kunihiko Sakamotoe9a0502c2018-06-06 09:29:51674
Tsuyoshi Horo561163b2018-03-27 03:11:23675 // It is safe to pass the callback of CreateURLLoaderThrottles with the
Tsuyoshi Horo70014ad2018-02-14 11:20:14676 // unretained |this|, because the passed callback will be used by a
677 // SignedExchangeHandler which is indirectly owned by |this| until its
678 // header is verified and parsed, that's where the getter is used.
Kunihiko Sakamotoe6aa22e2018-06-15 03:26:55679 interceptors_.push_back(std::make_unique<SignedExchangeRequestHandler>(
Tsuyoshi Horo70014ad2018-02-14 11:20:14680 url::Origin::Create(request_info->common_params.url),
Tsuyoshi Horo32b51f12018-05-09 17:58:46681 request_info->common_params.url,
Kinuko Yasuda32a25652018-02-19 08:14:25682 GetURLLoaderOptions(request_info->is_main_frame),
Tsuyoshi Horocdbb4902018-04-12 06:09:14683 request_info->frame_tree_node_id,
Tsuyoshi Horo32b51f12018-05-09 17:58:46684 request_info->devtools_navigation_token,
Tsuyoshi Horob8d381182018-06-19 10:07:29685 request_info->devtools_frame_token, request_info->report_raw_headers,
Kinuko Yasudabe4ad292018-07-06 01:33:39686 request_info->begin_params->load_flags, network_loader_factory_,
Tsuyoshi Horo70014ad2018-02-14 11:20:14687 base::BindRepeating(
688 &URLLoaderRequestController::CreateURLLoaderThrottles,
John Abd-El-Malek9ee2a712018-08-24 19:50:45689 base::Unretained(this))));
Tsuyoshi Horob8d512a2018-01-25 17:01:59690 }
691
Jian Li18e29242018-05-10 22:25:12692 std::vector<std::unique_ptr<URLLoaderRequestInterceptor>>
693 browser_interceptors = GetContentClient()
694 ->browser()
695 ->WillCreateURLLoaderRequestInterceptors(
696 navigation_ui_data_.get(),
697 request_info->frame_tree_node_id);
698 if (!browser_interceptors.empty()) {
699 for (auto& browser_interceptor : browser_interceptors) {
700 interceptors_.push_back(
701 std::make_unique<NavigationLoaderInterceptorBrowserContainer>(
702 std::move(browser_interceptor)));
703 }
704 }
705
yzshenefcb7c72017-06-16 23:12:30706 Restart();
kinuko69732972017-05-29 08:50:07707 }
708
Michael Nordman2431f5f2017-09-13 04:58:15709 // This could be called multiple times to follow a chain of redirects.
yzshenefcb7c72017-06-16 23:12:30710 void Restart() {
Kinuko Yasuda7f3e1722018-03-26 08:58:58711 DCHECK(IsLoaderInterceptionEnabled());
Tsuyoshi Horo5204c872017-09-21 16:28:17712 // Clear |url_loader_| if it's not the default one (network). This allows
713 // the restarted request to use a new loader, instead of, e.g., reusing the
714 // AppCache or service worker loader. For an optimization, we keep and reuse
Kinuko Yasuda7f3e1722018-03-26 08:58:58715 // the default url loader if the all |interceptors_| doesn't handle the
Clark DuVallbf7722f2018-08-03 18:03:33716 // redirected request. If the network service is enabled, only certain
717 // schemes are handled by the default URL loader. We need to make sure the
718 // redirected URL is a handled scheme, otherwise reset the loader so the
719 // correct non-network service loader can be used.
720 if (!default_loader_used_ ||
721 (base::FeatureList::IsEnabled(network::features::kNetworkService) &&
722 !IsURLHandledByDefaultLoader(resource_request_->url))) {
Tsuyoshi Horo5204c872017-09-21 16:28:17723 url_loader_.reset();
Clark DuVallbf7722f2018-08-03 18:03:33724 }
Kinuko Yasuda7f3e1722018-03-26 08:58:58725 interceptor_index_ = 0;
anantab9800e52017-07-29 18:04:13726 received_response_ = false;
Kinuko Yasuda7f3e1722018-03-26 08:58:58727 MaybeStartLoader(nullptr /* interceptor */,
728 {} /* single_request_handler */);
kinuko69732972017-05-29 08:50:07729 }
730
Kinuko Yasuda7f3e1722018-03-26 08:58:58731 // |interceptor| is non-null if this is called by one of the interceptors
732 // (via a LoaderCallback).
733 // |single_request_handler| is the RequestHandler given by the |interceptor|,
734 // non-null if the interceptor wants to handle the request.
Ken Rockot387ddd5a2018-01-30 19:18:40735 void MaybeStartLoader(
Kinuko Yasuda7f3e1722018-03-26 08:58:58736 NavigationLoaderInterceptor* interceptor,
Ken Rockot387ddd5a2018-01-30 19:18:40737 SingleRequestURLLoaderFactory::RequestHandler single_request_handler) {
Matt Falkenhagen34739112018-07-17 20:36:33738 DCHECK_CURRENTLY_ON(BrowserThread::IO);
739 DCHECK(IsLoaderInterceptionEnabled());
740 DCHECK(started_);
741
Ken Rockot387ddd5a2018-01-30 19:18:40742 if (single_request_handler) {
Kinuko Yasuda7f3e1722018-03-26 08:58:58743 // |interceptor| wants to handle the request with
744 // |single_request_handler|.
745 DCHECK(interceptor);
Matt Falkenhagen43765122018-08-22 19:37:22746
747 std::vector<std::unique_ptr<URLLoaderThrottle>> throttles =
Makoto Shimazu21950e82018-08-02 12:37:14748 CreateURLLoaderThrottles();
Matt Falkenhagen43765122018-08-22 19:37:22749 // Intercepted requests need MimeSniffingThrottle to do mime sniffing.
750 // Non-intercepted requests usually go through the regular network
751 // URLLoader, which does mime sniffing.
Makoto Shimazu21950e82018-08-02 12:37:14752 throttles.push_back(std::make_unique<MimeSniffingThrottle>());
Matt Falkenhagen43765122018-08-22 19:37:22753
Michael Nordman2431f5f2017-09-13 04:58:15754 default_loader_used_ = false;
yzshenefcb7c72017-06-16 23:12:30755 url_loader_ = ThrottlingURLLoader::CreateLoaderAndStart(
Ken Rockot387ddd5a2018-01-30 19:18:40756 base::MakeRefCounted<SingleRequestURLLoaderFactory>(
757 std::move(single_request_handler)),
Makoto Shimazu21950e82018-08-02 12:37:14758 std::move(throttles), frame_tree_node_id_,
Ken Rockot5f734e32018-06-13 01:41:03759 global_request_id_.request_id, network::mojom::kURLLoadOptionNone,
760 resource_request_.get(), this, kNavigationUrlLoaderTrafficAnnotation,
Hajime Hoshif5ef35262017-11-28 19:13:00761 base::ThreadTaskRunnerHandle::Get());
anantae60d1d42017-06-20 04:16:27762
Kinuko Yasuda250577c2017-10-29 02:51:24763 subresource_loader_params_ =
Kinuko Yasuda7f3e1722018-03-26 08:58:58764 interceptor->MaybeCreateSubresourceLoaderParams();
Kinuko Yasuda8757204a2017-11-04 07:50:13765
kinuko69732972017-05-29 08:50:07766 return;
767 }
768
Kinuko Yasuda7f3e1722018-03-26 08:58:58769 // Before falling back to the next interceptor, see if |interceptor| still
770 // wants to give additional info to the frame for subresource loading. In
771 // that case we will just fall back to the default loader (i.e. won't go on
772 // to the next interceptors) but send the subresource_loader_params to the
773 // child process. This is necessary for correctness in the cases where, e.g.
Matt Falkenhagen43765122018-08-22 19:37:22774 // there's a controlling service worker that doesn't have a fetch event
775 // handler so it doesn't intercept requests. In that case we still want to
776 // skip AppCache.
Kinuko Yasuda7f3e1722018-03-26 08:58:58777 if (interceptor) {
Kinuko Yasuda8757204a2017-11-04 07:50:13778 subresource_loader_params_ =
Kinuko Yasuda7f3e1722018-03-26 08:58:58779 interceptor->MaybeCreateSubresourceLoaderParams();
Kinuko Yasuda8757204a2017-11-04 07:50:13780
781 // If non-null |subresource_loader_params_| is returned, make sure
Kinuko Yasuda7f3e1722018-03-26 08:58:58782 // we skip the next interceptors.
Kinuko Yasuda8757204a2017-11-04 07:50:13783 if (subresource_loader_params_)
Kinuko Yasuda7f3e1722018-03-26 08:58:58784 interceptor_index_ = interceptors_.size();
Kinuko Yasuda8757204a2017-11-04 07:50:13785 }
786
Kinuko Yasuda7f3e1722018-03-26 08:58:58787 // See if the next interceptor wants to handle the request.
788 if (interceptor_index_ < interceptors_.size()) {
789 auto* next_interceptor = interceptors_[interceptor_index_++].get();
790 next_interceptor->MaybeCreateLoader(
kinuko69732972017-05-29 08:50:07791 *resource_request_, resource_context_,
792 base::BindOnce(&URLLoaderRequestController::MaybeStartLoader,
Matt Falkenhagen43765122018-08-22 19:37:22793 base::Unretained(this), next_interceptor),
794 base::BindOnce(
795 &URLLoaderRequestController::FallbackToNonInterceptedRequest,
796 base::Unretained(this)));
kinuko69732972017-05-29 08:50:07797 return;
798 }
799
Matt Falkenhagen43765122018-08-22 19:37:22800 // If we already have the default |url_loader_| we must come here after a
Matt Falkenhagencc3e7e52018-08-28 06:23:48801 // redirect. No interceptors wanted to intercept the redirected request, so
Matt Falkenhagen43765122018-08-22 19:37:22802 // let the loader just follow the redirect.
Michael Nordman2431f5f2017-09-13 04:58:15803 if (url_loader_) {
804 DCHECK(!redirect_info_.new_url.is_empty());
Chong Zhang7607f1f2018-06-01 20:52:20805 url_loader_->FollowRedirect(
806 std::move(url_loader_modified_request_headers_));
Michael Nordman2431f5f2017-09-13 04:58:15807 return;
808 }
809
Matt Falkenhagen43765122018-08-22 19:37:22810 // No interceptors wanted to handle this request.
Matt Falkenhagencc3e7e52018-08-28 06:23:48811 uint32_t options = network::mojom::kURLLoadOptionNone;
812 scoped_refptr<network::SharedURLLoaderFactory> factory =
813 PrepareForNonInterceptedRequest(&options);
814 url_loader_ = ThrottlingURLLoader::CreateLoaderAndStart(
815 std::move(factory), CreateURLLoaderThrottles(), frame_tree_node_id_,
816 global_request_id_.request_id, options, resource_request_.get(),
817 this /* client */, kNavigationUrlLoaderTrafficAnnotation,
818 base::ThreadTaskRunnerHandle::Get());
Matt Falkenhagen43765122018-08-22 19:37:22819 }
Makoto Shimazu44c2c3232018-03-30 01:10:20820
Matt Falkenhagen43765122018-08-22 19:37:22821 // This is the |fallback_callback| passed to
822 // NavigationLoaderInterceptor::MaybeCreateLoader. It allows an interceptor
823 // to initially elect to handle a request, and later decide to fallback to
824 // the default behavior. This is needed for service worker network fallback.
825 void FallbackToNonInterceptedRequest(bool reset_subresource_loader_params) {
826 if (reset_subresource_loader_params)
827 subresource_loader_params_.reset();
828
Matt Falkenhagencc3e7e52018-08-28 06:23:48829 // Non-NetworkService:
830 // Cancel state on ResourceDispatcherHostImpl so it doesn't complain about
831 // reusing the request_id after redirects. Otherwise the following sequence
832 // can happen:
833 // RDHI Start(request_id) -> Redirect -> SW interception -> SW fallback to
834 // network -> RDHI Start(request_id).
835 if (!base::FeatureList::IsEnabled(network::features::kNetworkService)) {
836 DCHECK(ResourceDispatcherHostImpl::Get());
837 ResourceDispatcherHostImpl::Get()->CancelRequest(
838 global_request_id_.child_id, global_request_id_.request_id);
Matt Falkenhagen43765122018-08-22 19:37:22839 }
840
Matt Falkenhagencc3e7e52018-08-28 06:23:48841 // |url_loader_| is using the factory for the interceptor that decided to
842 // fallback, so restart it with the non-interceptor factory.
843 DCHECK(url_loader_);
844 uint32_t options = network::mojom::kURLLoadOptionNone;
845 scoped_refptr<network::SharedURLLoaderFactory> factory =
846 PrepareForNonInterceptedRequest(&options);
847 url_loader_->RestartWithFactory(std::move(factory), options);
Matt Falkenhagen43765122018-08-22 19:37:22848 }
849
Matt Falkenhagencc3e7e52018-08-28 06:23:48850 scoped_refptr<network::SharedURLLoaderFactory>
851 PrepareForNonInterceptedRequest(uint32_t* out_options) {
Makoto Shimazu44c2c3232018-03-30 01:10:20852 // If NetworkService is not enabled (which means we come here because one of
853 // the loader interceptors is enabled), use the default request handler
854 // instead of going through the NetworkService path.
855 if (!base::FeatureList::IsEnabled(network::features::kNetworkService)) {
856 DCHECK(!interceptors_.empty());
857 DCHECK(default_request_handler_factory_);
Kunihiko Sakamoto21ab4ad262018-08-21 10:26:21858 // The only way to come here is to enable ServiceWorkerServicification or
859 // SignedExchange without NetworkService. We know that their request
860 // interceptors have already intercepted and decided not to handle the
Makoto Shimazu684a5ad2018-05-29 08:20:50861 // request.
Kunihiko Sakamoto21ab4ad262018-08-21 10:26:21862 DCHECK(blink::ServiceWorkerUtils::IsServicificationEnabled() ||
863 signed_exchange_utils::IsSignedExchangeHandlingEnabled());
Makoto Shimazu44c2c3232018-03-30 01:10:20864 default_loader_used_ = true;
865 // Update |request_info_| when following a redirect.
866 if (url_chain_.size() > 0) {
867 request_info_ = CreateNavigationRequestInfoForRedirect(
868 *request_info_, *resource_request_);
869 }
Matt Falkenhagen43765122018-08-22 19:37:22870
Makoto Shimazu684a5ad2018-05-29 08:20:50871 // When |subresource_loader_params_| has its value, the request should not
872 // be intercepted by any other interceptors since it means that a request
873 // interceptor already intercepted the request and it attached its info to
874 // the request.
Matt Falkenhagen43765122018-08-22 19:37:22875 bool was_request_intercepted = subresource_loader_params_.has_value();
876
Matt Falkenhagencc3e7e52018-08-28 06:23:48877 // TODO(falken): Determine whether GetURLLoaderOptions() can be called
878 // here like below. It looks like |default_request_handler_factory_| just
879 // calls that.
880 *out_options = network::mojom::kURLLoadOptionNone;
881 return base::MakeRefCounted<SingleRequestURLLoaderFactory>(
882 default_request_handler_factory_.Run(was_request_intercepted));
Makoto Shimazu44c2c3232018-03-30 01:10:20883 }
884
Matt Falkenhagen43765122018-08-22 19:37:22885 // TODO(https://crbug.com/796425): We temporarily wrap raw
886 // mojom::URLLoaderFactory pointers into SharedURLLoaderFactory. Need to
887 // further refactor the factory getters to avoid this.
888 scoped_refptr<network::SharedURLLoaderFactory> factory;
889
Clark DuVallbf7722f2018-08-03 18:03:33890 if (!IsURLHandledByDefaultLoader(resource_request_->url)) {
John Abd-El-Maleka67add82018-03-09 18:22:01891 if (known_schemes_.find(resource_request_->url.scheme()) ==
892 known_schemes_.end()) {
893 bool handled = GetContentClient()->browser()->HandleExternalProtocol(
894 resource_request_->url, web_contents_getter_,
895 ChildProcessHost::kInvalidUniqueID, navigation_ui_data_.get(),
896 resource_request_->resource_type == RESOURCE_TYPE_MAIN_FRAME,
897 static_cast<ui::PageTransition>(resource_request_->transition_type),
898 resource_request_->has_user_gesture);
899 factory = base::MakeRefCounted<SingleRequestURLLoaderFactory>(
900 base::BindOnce(UnknownSchemeCallback, handled));
901 } else {
902 network::mojom::URLLoaderFactoryPtr& non_network_factory =
903 non_network_url_loader_factories_[resource_request_->url.scheme()];
904 if (!non_network_factory.is_bound()) {
905 BrowserThread::PostTask(
906 BrowserThread::UI, FROM_HERE,
arthursonzogni1fd60e62018-05-09 15:57:32907 base::BindOnce(&NavigationURLLoaderImpl ::
John Abd-El-Maleka67add82018-03-09 18:22:01908 BindNonNetworkURLLoaderFactoryRequest,
909 owner_, frame_tree_node_id_,
910 resource_request_->url,
911 mojo::MakeRequest(&non_network_factory)));
912 }
Antonio Gomes9cdc09a2018-05-07 23:24:26913 factory =
914 base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
915 non_network_factory.get());
Ken Rockot314714c2017-11-05 23:36:24916 }
jam9354af82017-06-03 21:59:41917 } else {
anantab9800e52017-07-29 18:04:13918 default_loader_used_ = true;
Ken Rockota0dfaca12018-02-15 07:26:25919
920 // NOTE: We only support embedders proxying network-service-bound requests
Kinuko Yasuda7f3e1722018-03-26 08:58:58921 // not handled by NavigationLoaderInterceptors above (e.g. Service Worker
922 // or AppCache). Hence this code is only reachable when one of the above
923 // interceptors isn't used and the URL is either a data URL or has a
924 // scheme which is handled by the network service. We explicitly avoid
925 // proxying the data URL case here.
Ken Rockota0dfaca12018-02-15 07:26:25926 if (proxied_factory_request_.is_pending() &&
927 !resource_request_->url.SchemeIs(url::kDataScheme)) {
928 DCHECK(proxied_factory_info_.is_valid());
Chong Zhang70432e32018-03-07 04:43:52929 // We don't worry about reconnection since it's a single navigation.
Kinuko Yasudabe4ad292018-07-06 01:33:39930 network_loader_factory_->Clone(std::move(proxied_factory_request_));
Antonio Gomes9cdc09a2018-05-07 23:24:26931 factory = base::MakeRefCounted<network::WrapperSharedURLLoaderFactory>(
Ken Rockota0dfaca12018-02-15 07:26:25932 std::move(proxied_factory_info_));
933 } else {
Kinuko Yasudabe4ad292018-07-06 01:33:39934 factory = network_loader_factory_;
Ken Rockota0dfaca12018-02-15 07:26:25935 }
jam9354af82017-06-03 21:59:41936 }
Min Qin83d07872017-10-26 23:22:41937 url_chain_.push_back(resource_request_->url);
Matt Falkenhagencc3e7e52018-08-28 06:23:48938 *out_options = GetURLLoaderOptions(resource_request_->resource_type ==
939 RESOURCE_TYPE_MAIN_FRAME);
940 return factory;
kinuko69732972017-05-29 08:50:07941 }
942
Chong Zhang7607f1f2018-06-01 20:52:20943 void FollowRedirect(
944 const base::Optional<net::HttpRequestHeaders>& modified_request_headers) {
yzshenefcb7c72017-06-16 23:12:30945 DCHECK_CURRENTLY_ON(BrowserThread::IO);
Michael Nordman2431f5f2017-09-13 04:58:15946 DCHECK(!redirect_info_.new_url.is_empty());
arthursonzogni2695d04d2017-12-12 08:39:01947
Kinuko Yasuda7f3e1722018-03-26 08:58:58948 if (!IsLoaderInterceptionEnabled()) {
Chong Zhang7607f1f2018-06-01 20:52:20949 url_loader_->FollowRedirect(modified_request_headers);
arthursonzogni2695d04d2017-12-12 08:39:01950 return;
951 }
anantab9800e52017-07-29 18:04:13952
Kinuko Yasuda7f3e1722018-03-26 08:58:58953 // Update |resource_request_| and call Restart to give our |interceptors_| a
954 // chance at handling the new location. If no interceptor wants to take
955 // over, we'll use the existing url_loader to follow the redirect, see
956 // MaybeStartLoader.
Michael Nordman2431f5f2017-09-13 04:58:15957 // TODO(michaeln): This is still WIP and is based on URLRequest::Redirect,
958 // there likely remains more to be done.
959 // a. For subframe navigations, the Origin header may need to be modified
960 // differently?
961 // b. How should redirect_info_.referred_token_binding_host be handled?
Michael Nordman2431f5f2017-09-13 04:58:15962
Tsuyoshi Horo9e2ec4df2017-10-16 15:15:55963 bool should_clear_upload = false;
964 net::RedirectUtil::UpdateHttpRequest(
965 resource_request_->url, resource_request_->method, redirect_info_,
Chong Zhang7607f1f2018-06-01 20:52:20966 modified_request_headers, &resource_request_->headers,
967 &should_clear_upload);
Tsuyoshi Horo9e2ec4df2017-10-16 15:15:55968 if (should_clear_upload) {
Michael Nordman2431f5f2017-09-13 04:58:15969 // The request body is no longer applicable.
970 resource_request_->request_body = nullptr;
971 blob_handles_.clear();
972 }
973
Michael Nordman2431f5f2017-09-13 04:58:15974 resource_request_->url = redirect_info_.new_url;
Tsuyoshi Horo9e2ec4df2017-10-16 15:15:55975 resource_request_->method = redirect_info_.new_method;
Michael Nordman2431f5f2017-09-13 04:58:15976 resource_request_->site_for_cookies = redirect_info_.new_site_for_cookies;
977 resource_request_->referrer = GURL(redirect_info_.new_referrer);
John Abd-El-Malekb77d22fb72017-12-22 17:34:48978 resource_request_->referrer_policy = redirect_info_.new_referrer_policy;
Min Qin83d07872017-10-26 23:22:41979 url_chain_.push_back(redirect_info_.new_url);
Michael Nordman2431f5f2017-09-13 04:58:15980
Chong Zhang7607f1f2018-06-01 20:52:20981 // Need to cache modified headers for |url_loader_| since it doesn't use
982 // |resource_request_| during redirect.
983 url_loader_modified_request_headers_ = modified_request_headers;
984
Michael Nordman2431f5f2017-09-13 04:58:15985 Restart();
yzshenefcb7c72017-06-16 23:12:30986 }
987
Kinuko Yasuda250577c2017-10-29 02:51:24988 base::Optional<SubresourceLoaderParams> TakeSubresourceLoaderParams() {
989 return std::move(subresource_loader_params_);
anantae60d1d42017-06-20 04:16:27990 }
991
kinuko69732972017-05-29 08:50:07992 private:
John Abd-El-Malekb165dc52018-01-18 17:12:18993 // network::mojom::URLLoaderClient implementation:
Marijn Kruisselbrink9ebd7ba2018-06-11 23:18:04994 void OnReceiveResponse(const network::ResourceResponseHead& head) override {
Matt Menked9cad562018-08-10 21:47:09995 // Record the SCT histogram before checking if anything wants to intercept
996 // the response, so interceptors like AppCache and extensions can't hide
997 // values from the histograms.
998 RecordSCTHistogramIfNeeded(head.ssl_info);
999
anantab9800e52017-07-29 18:04:131000 received_response_ = true;
arthursonzogni2695d04d2017-12-12 08:39:011001
anantab9800e52017-07-29 18:04:131002 // If the default loader (network) was used to handle the URL load request
Kinuko Yasuda7f3e1722018-03-26 08:58:581003 // we need to see if the interceptors want to potentially create a new
1004 // loader for the response. e.g. AppCache.
anantab9800e52017-07-29 18:04:131005 if (MaybeCreateLoaderForResponse(head))
1006 return;
arthursonzogni3a4ca9f2017-12-07 17:58:341007
John Abd-El-Malekb165dc52018-01-18 17:12:181008 network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints;
John Abd-El-Malekecc6f5f2018-03-02 18:47:391009
1010 // Currently only plugin handlers may intercept the response. Don't treat
1011 // the response as download if it has been handled by plugins.
1012 bool response_intercepted = false;
arthursonzogni3a4ca9f2017-12-07 17:58:341013 if (url_loader_) {
1014 url_loader_client_endpoints = url_loader_->Unbind();
John Abd-El-Malekecc6f5f2018-03-02 18:47:391015 response_intercepted = url_loader_->response_intercepted();
arthursonzogni3a4ca9f2017-12-07 17:58:341016 } else {
John Abd-El-Malekb165dc52018-01-18 17:12:181017 url_loader_client_endpoints =
1018 network::mojom::URLLoaderClientEndpoints::New(
1019 response_url_loader_.PassInterface(),
1020 response_loader_binding_.Unbind());
arthursonzogni3a4ca9f2017-12-07 17:58:341021 }
1022
arthursonzogni40db5f52018-01-08 16:38:491023 bool is_download;
1024 bool is_stream;
Ryan Sturm64315a92018-07-20 06:25:281025 // If there is not an explicit PreviewsState set on the request, turn
1026 // Previews off.
1027 PreviewsState previews_state = PREVIEWS_OFF;
arthursonzogni40db5f52018-01-08 16:38:491028 std::unique_ptr<NavigationData> cloned_navigation_data;
Kenichi Ishibashia7175632018-07-30 02:08:351029
Kinuko Yasuda7f3e1722018-03-26 08:58:581030 if (IsLoaderInterceptionEnabled()) {
Robbie McElratha5adc4e2018-07-03 23:53:091031 bool must_download = download_utils::MustDownload(
Jochen Eisinger7678c8ac2018-05-07 15:47:341032 url_, head.headers.get(), head.mime_type);
John Abd-El-Malek3ebdff862018-04-23 18:57:211033 bool known_mime_type = blink::IsSupportedMimeType(head.mime_type);
1034
Matt Menke2bd72d82018-08-03 15:17:181035 bool is_download_if_not_handled_by_plugin =
1036 !response_intercepted && (must_download || !known_mime_type);
1037
John Abd-El-Malek3ebdff862018-04-23 18:57:211038#if BUILDFLAG(ENABLE_PLUGINS)
1039 if (!response_intercepted && !must_download && !known_mime_type) {
1040 CheckPluginAndContinueOnReceiveResponse(
Marijn Kruisselbrink9ebd7ba2018-06-11 23:18:041041 head, std::move(url_loader_client_endpoints),
Matt Menke2bd72d82018-08-03 15:17:181042 is_download_if_not_handled_by_plugin, std::vector<WebPluginInfo>());
John Abd-El-Malek3ebdff862018-04-23 18:57:211043 return;
1044 }
1045#endif
1046
Matt Menke2bd72d82018-08-03 15:17:181047 is_download = is_download_if_not_handled_by_plugin;
arthursonzogni40db5f52018-01-08 16:38:491048 is_stream = false;
arthursonzognib1de19fa2018-04-03 19:55:101049
Kenichi Ishibashia7175632018-07-30 02:08:351050 // If NetworkService is on, or an interceptor handled the request, the
1051 // request doesn't use ResourceDispatcherHost so
1052 // CallOnReceivedResponse and return here.
1053 if (base::FeatureList::IsEnabled(network::features::kNetworkService) ||
1054 !default_loader_used_) {
1055 CallOnReceivedResponse(head, std::move(url_loader_client_endpoints),
1056 std::move(cloned_navigation_data), is_download,
1057 is_stream, previews_state);
1058 return;
arthursonzognib950d902018-02-08 09:27:131059 }
arthursonzogni40db5f52018-01-08 16:38:491060 }
1061
Kenichi Ishibashia7175632018-07-30 02:08:351062 // NetworkService is off and an interceptor didn't handle the request,
1063 // so it went to ResourceDispatcherHost.
1064 ResourceDispatcherHostImpl* rdh = ResourceDispatcherHostImpl::Get();
1065 net::URLRequest* url_request = rdh->GetURLRequest(global_request_id_);
1066
1067 // The |url_request| maybe have been removed from the resource dispatcher
1068 // host during the time it took for OnReceiveResponse() to be received.
1069 if (url_request) {
1070 ResourceRequestInfoImpl* info =
1071 ResourceRequestInfoImpl::ForRequest(url_request);
1072 is_download = !response_intercepted && info->IsDownload();
1073 is_stream = info->is_stream();
1074 previews_state = info->GetPreviewsState();
1075 if (rdh->delegate()) {
1076 NavigationData* navigation_data =
1077 rdh->delegate()->GetNavigationData(url_request);
1078
1079 // Clone the embedder's NavigationData before moving it to the UI
1080 // thread.
1081 if (navigation_data)
1082 cloned_navigation_data = navigation_data->Clone();
1083 }
1084
1085 // non-S13nServiceWorker:
1086 // This is similar to what is done in
1087 // ServiceWorkerControlleeHandler::MaybeCreateSubresourceLoaderParams()
1088 // (which is used when S13nServiceWorker is on). It takes the matching
1089 // ControllerServiceWorkerInfo (if any) associated with the request. It
1090 // will be sent to the renderer process and used to intercept requests.
1091 ServiceWorkerProviderHost* sw_provider_host =
1092 ServiceWorkerRequestHandler::GetProviderHost(url_request);
1093 if (sw_provider_host && sw_provider_host->controller()) {
1094 DCHECK(!blink::ServiceWorkerUtils::IsServicificationEnabled());
1095 subresource_loader_params_ = SubresourceLoaderParams();
1096 subresource_loader_params_->controller_service_worker_info =
1097 mojom::ControllerServiceWorkerInfo::New();
1098 subresource_loader_params_->controller_service_worker_info->mode =
1099 sw_provider_host->GetControllerMode();
1100 base::WeakPtr<ServiceWorkerObjectHost> sw_object_host =
1101 sw_provider_host->GetOrCreateServiceWorkerObjectHost(
1102 sw_provider_host->controller());
1103 if (sw_object_host) {
1104 subresource_loader_params_->controller_service_worker_object_host =
1105 sw_object_host;
1106 subresource_loader_params_->controller_service_worker_info
1107 ->object_info = sw_object_host->CreateIncompleteObjectInfo();
1108 }
1109 }
1110 } else {
1111 is_download = is_stream = false;
1112 }
1113
Marijn Kruisselbrink9ebd7ba2018-06-11 23:18:041114 CallOnReceivedResponse(head, std::move(url_loader_client_endpoints),
John Abd-El-Malek3ebdff862018-04-23 18:57:211115 std::move(cloned_navigation_data), is_download,
Ryan Sturm64315a92018-07-20 06:25:281116 is_stream, previews_state);
John Abd-El-Malek3ebdff862018-04-23 18:57:211117 }
1118
1119#if BUILDFLAG(ENABLE_PLUGINS)
1120 void CheckPluginAndContinueOnReceiveResponse(
1121 const network::ResourceResponseHead& head,
John Abd-El-Malek3ebdff862018-04-23 18:57:211122 network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
Matt Menke2bd72d82018-08-03 15:17:181123 bool is_download_if_not_handled_by_plugin,
John Abd-El-Malek3ebdff862018-04-23 18:57:211124 const std::vector<WebPluginInfo>& plugins) {
1125 bool stale;
1126 WebPluginInfo plugin;
1127 // It's ok to pass -1 for the render process and frame ID since that's
1128 // only used for plugin overridding. We don't actually care if we get an
1129 // overridden plugin or not, since all we care about is the presence of a
1130 // plugin. Note that this is what the MimeSniffingResourceHandler code
1131 // path does as well for navigations.
1132 bool has_plugin = PluginService::GetInstance()->GetPluginInfo(
1133 -1 /* render_process_id */, -1 /* render_frame_id */, resource_context_,
1134 resource_request_->url, url::Origin(), head.mime_type,
1135 false /* allow_wildcard */, &stale, &plugin, nullptr);
1136
1137 if (stale) {
1138 // Refresh the plugins asynchronously.
1139 PluginService::GetInstance()->GetPlugins(base::BindOnce(
1140 &URLLoaderRequestController::CheckPluginAndContinueOnReceiveResponse,
Marijn Kruisselbrink9ebd7ba2018-06-11 23:18:041141 weak_factory_.GetWeakPtr(), head,
Matt Menke2bd72d82018-08-03 15:17:181142 std::move(url_loader_client_endpoints),
1143 is_download_if_not_handled_by_plugin));
John Abd-El-Malek3ebdff862018-04-23 18:57:211144 return;
1145 }
1146
Matt Menke2bd72d82018-08-03 15:17:181147 bool is_download = !has_plugin && is_download_if_not_handled_by_plugin;
John Abd-El-Malek3ebdff862018-04-23 18:57:211148
Marijn Kruisselbrink9ebd7ba2018-06-11 23:18:041149 CallOnReceivedResponse(head, std::move(url_loader_client_endpoints),
Ryan Sturm64315a92018-07-20 06:25:281150 nullptr, is_download, false /* is_stream */,
1151 PREVIEWS_OFF /* previews_state */);
John Abd-El-Malek3ebdff862018-04-23 18:57:211152 }
1153#endif
1154
1155 void CallOnReceivedResponse(
1156 const network::ResourceResponseHead& head,
John Abd-El-Malek3ebdff862018-04-23 18:57:211157 network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
1158 std::unique_ptr<NavigationData> cloned_navigation_data,
1159 bool is_download,
Ryan Sturm64315a92018-07-20 06:25:281160 bool is_stream,
1161 PreviewsState previews_state) {
John Abd-El-Malek3ebdff862018-04-23 18:57:211162 scoped_refptr<network::ResourceResponse> response(
1163 new network::ResourceResponse());
1164 response->head = head;
1165
Andrey Kosyakova924c8b2017-08-18 17:37:231166 // Make a copy of the ResourceResponse before it is passed to another
1167 // thread.
1168 //
1169 // TODO(davidben): This copy could be avoided if ResourceResponse weren't
1170 // reference counted and the loader stack passed unique ownership of the
1171 // response. https://crbug.com/416050
yzshenefcb7c72017-06-16 23:12:301172 BrowserThread::PostTask(
1173 BrowserThread::UI, FROM_HERE,
Philip Rogers7178f5c2018-07-09 18:52:591174 base::BindOnce(&NavigationURLLoaderImpl::OnReceiveResponse, owner_,
1175 response->DeepCopy(),
1176 std::move(url_loader_client_endpoints),
1177 std::move(cloned_navigation_data), global_request_id_,
Ryan Sturm64315a92018-07-20 06:25:281178 is_download, is_stream, previews_state));
yzshenefcb7c72017-06-16 23:12:301179 }
1180
1181 void OnReceiveRedirect(const net::RedirectInfo& redirect_info,
John Abd-El-Malek46248032018-01-17 19:11:231182 const network::ResourceResponseHead& head) override {
Clark DuVallb2680c22018-08-10 15:27:271183 if (base::FeatureList::IsEnabled(network::features::kNetworkService) &&
1184 !bypass_redirect_checks_ &&
1185 !IsRedirectSafe(redirect_info.new_url, resource_context_)) {
1186 OnComplete(network::URLLoaderCompletionStatus(net::ERR_UNSAFE_REDIRECT));
1187 return;
Clark DuVallbf7722f2018-08-03 18:03:331188 }
1189
Michael Nordman2431f5f2017-09-13 04:58:151190 if (--redirect_limit_ == 0) {
Takashi Toyoshimaaa278662017-11-20 11:11:261191 OnComplete(
1192 network::URLLoaderCompletionStatus(net::ERR_TOO_MANY_REDIRECTS));
Michael Nordman2431f5f2017-09-13 04:58:151193 return;
1194 }
1195
1196 // Store the redirect_info for later use in FollowRedirect where we give
Kinuko Yasuda7f3e1722018-03-26 08:58:581197 // our interceptors_ a chance to intercept the request for the new location.
Michael Nordman2431f5f2017-09-13 04:58:151198 redirect_info_ = redirect_info;
1199
John Abd-El-Malek46248032018-01-17 19:11:231200 scoped_refptr<network::ResourceResponse> response(
1201 new network::ResourceResponse());
Andrey Kosyakova924c8b2017-08-18 17:37:231202 response->head = head;
arthursonzogni40db5f52018-01-08 16:38:491203 url_ = redirect_info.new_url;
Andrey Kosyakova924c8b2017-08-18 17:37:231204
1205 // Make a copy of the ResourceResponse before it is passed to another
1206 // thread.
1207 //
1208 // TODO(davidben): This copy could be avoided if ResourceResponse weren't
1209 // reference counted and the loader stack passed unique ownership of the
1210 // response. https://crbug.com/416050
yzshenefcb7c72017-06-16 23:12:301211 BrowserThread::PostTask(
1212 BrowserThread::UI, FROM_HERE,
arthursonzogni1fd60e62018-05-09 15:57:321213 base::BindOnce(&NavigationURLLoaderImpl::OnReceiveRedirect, owner_,
1214 redirect_info, response->DeepCopy()));
yzshenefcb7c72017-06-16 23:12:301215 }
1216
yzshenefcb7c72017-06-16 23:12:301217 void OnUploadProgress(int64_t current_position,
1218 int64_t total_size,
1219 OnUploadProgressCallback callback) override {}
yzshenefcb7c72017-06-16 23:12:301220 void OnReceiveCachedMetadata(const std::vector<uint8_t>& data) override {}
yzshenefcb7c72017-06-16 23:12:301221 void OnTransferSizeUpdated(int32_t transfer_size_diff) override {}
1222
Philip Rogers7178f5c2018-07-09 18:52:591223 void OnStartLoadingResponseBody(mojo::ScopedDataPipeConsumerHandle) override {
1224 // Not reached. At this point, the loader and client endpoints must have
1225 // been unbound and forwarded to the renderer.
1226 CHECK(false);
yzshenefcb7c72017-06-16 23:12:301227 }
1228
Takashi Toyoshimaaa278662017-11-20 11:11:261229 void OnComplete(const network::URLLoaderCompletionStatus& status) override {
Matt Menked9cad562018-08-10 21:47:091230 RecordSCTHistogramIfNeeded(status.ssl_info);
1231
Emily Starkb09f19a2017-11-22 22:41:471232 UMA_HISTOGRAM_BOOLEAN(
arthursonzognie70c4a042018-05-02 15:49:101233 "Navigation.URLLoaderNetworkService.OnCompleteHasSSLInfo",
Emily Starkb09f19a2017-11-22 22:41:471234 status.ssl_info.has_value());
1235 if (status.ssl_info.has_value()) {
1236 UMA_HISTOGRAM_MEMORY_KB(
1237 "Navigation.URLLoaderNetworkService.OnCompleteCertificateChainsSize",
1238 GetCertificateChainsSizeInKB(status.ssl_info.value()));
1239 }
1240
Takashi Toyoshima8f988532017-11-13 07:32:371241 if (status.error_code != net::OK && !received_response_) {
anantab9800e52017-07-29 18:04:131242 // If the default loader (network) was used to handle the URL load
Kinuko Yasuda7f3e1722018-03-26 08:58:581243 // request we need to see if the interceptors want to potentially create a
anantab9800e52017-07-29 18:04:131244 // new loader for the response. e.g. AppCache.
John Abd-El-Malek46248032018-01-17 19:11:231245 if (MaybeCreateLoaderForResponse(network::ResourceResponseHead()))
anantab9800e52017-07-29 18:04:131246 return;
1247 }
Takashi Toyoshima8f988532017-11-13 07:32:371248 status_ = status;
arthursonzogni2695d04d2017-12-12 08:39:011249
yzshenefcb7c72017-06-16 23:12:301250 BrowserThread::PostTask(
1251 BrowserThread::UI, FROM_HERE,
arthursonzogni1fd60e62018-05-09 15:57:321252 base::BindOnce(&NavigationURLLoaderImpl::OnComplete, owner_, status));
yzshenefcb7c72017-06-16 23:12:301253 }
1254
Kinuko Yasuda7f3e1722018-03-26 08:58:581255 // Returns true if an interceptor wants to handle the response, i.e. return a
Michael Nordman2431f5f2017-09-13 04:58:151256 // different response. For e.g. AppCache may have fallback content.
John Abd-El-Malek46248032018-01-17 19:11:231257 bool MaybeCreateLoaderForResponse(
1258 const network::ResourceResponseHead& response) {
Kinuko Yasuda7f3e1722018-03-26 08:58:581259 if (!IsLoaderInterceptionEnabled())
arthursonzogni2695d04d2017-12-12 08:39:011260 return false;
1261
anantab9800e52017-07-29 18:04:131262 if (!default_loader_used_)
1263 return false;
1264
Kinuko Yasuda7f3e1722018-03-26 08:58:581265 for (auto& interceptor : interceptors_) {
John Abd-El-Malekb165dc52018-01-18 17:12:181266 network::mojom::URLLoaderClientRequest response_client_request;
Kinuko Yasuda7f3e1722018-03-26 08:58:581267 if (interceptor->MaybeCreateLoaderForResponse(
1268 response, &response_url_loader_, &response_client_request,
1269 url_loader_.get())) {
Kunihiko Sakamoto21ab4ad262018-08-21 10:26:211270 if (response_loader_binding_.is_bound())
1271 response_loader_binding_.Close();
Michael Nordman2431f5f2017-09-13 04:58:151272 response_loader_binding_.Bind(std::move(response_client_request));
1273 default_loader_used_ = false;
1274 url_loader_.reset();
anantab9800e52017-07-29 18:04:131275 return true;
1276 }
1277 }
1278 return false;
1279 }
1280
Matt Falkenhagen43765122018-08-22 19:37:221281 std::vector<std::unique_ptr<URLLoaderThrottle>> CreateURLLoaderThrottles() {
Tsuyoshi Horo70014ad2018-02-14 11:20:141282 return GetContentClient()->browser()->CreateURLLoaderThrottles(
1283 *resource_request_, resource_context_, web_contents_getter_,
1284 navigation_ui_data_.get(), frame_tree_node_id_);
1285 }
1286
Makoto Shimazu44c2c3232018-03-30 01:10:201287 std::unique_ptr<NavigationLoaderInterceptor> CreateServiceWorkerInterceptor(
1288 const NavigationRequestInfo& request_info,
1289 ServiceWorkerNavigationHandleCore* service_worker_navigation_handle_core)
1290 const {
1291 const ResourceType resource_type = request_info.is_main_frame
1292 ? RESOURCE_TYPE_MAIN_FRAME
1293 : RESOURCE_TYPE_SUB_FRAME;
1294 network::mojom::RequestContextFrameType frame_type =
1295 request_info.is_main_frame
1296 ? network::mojom::RequestContextFrameType::kTopLevel
1297 : network::mojom::RequestContextFrameType::kNested;
1298 storage::BlobStorageContext* blob_storage_context = GetBlobStorageContext(
1299 GetChromeBlobStorageContextForResourceContext(resource_context_));
1300 return ServiceWorkerRequestHandler::InitializeForNavigationNetworkService(
Matt Falkenhagen43765122018-08-22 19:37:221301 resource_request_->url, resource_context_,
Makoto Shimazu44c2c3232018-03-30 01:10:201302 service_worker_navigation_handle_core, blob_storage_context,
1303 request_info.begin_params->skip_service_worker, resource_type,
1304 request_info.begin_params->request_context_type, frame_type,
1305 request_info.are_ancestors_secure, request_info.common_params.post_data,
1306 web_contents_getter_);
1307 }
1308
Matt Menked9cad562018-08-10 21:47:091309 void RecordSCTHistogramIfNeeded(
1310 const base::Optional<net::SSLInfo>& ssl_info) {
1311 if (is_main_frame_ && url_.SchemeIsCryptographic() &&
1312 ssl_info.has_value()) {
1313 int num_valid_scts = 0;
1314 for (const auto& signed_certificate_timestamps :
1315 ssl_info->signed_certificate_timestamps) {
1316 if (signed_certificate_timestamps.status == net::ct::SCT_STATUS_OK)
1317 ++num_valid_scts;
1318 }
1319 UMA_HISTOGRAM_COUNTS_100(
1320 "Net.CertificateTransparency.MainFrameValidSCTCount", num_valid_scts);
1321 }
1322 }
1323
Kinuko Yasuda7f3e1722018-03-26 08:58:581324 std::vector<std::unique_ptr<NavigationLoaderInterceptor>> interceptors_;
1325 size_t interceptor_index_ = 0;
kinuko69732972017-05-29 08:50:071326
John Abd-El-Malek1df61792018-01-12 20:40:451327 std::unique_ptr<network::ResourceRequest> resource_request_;
Makoto Shimazu44c2c3232018-03-30 01:10:201328 // Non-NetworkService: |request_info_| is updated along with
1329 // |resource_request_| on redirects.
1330 std::unique_ptr<NavigationRequestInfo> request_info_;
John Abd-El-Malek576c6132017-11-04 00:33:581331 int frame_tree_node_id_ = 0;
arthursonzogni40db5f52018-01-08 16:38:491332 GlobalRequestID global_request_id_;
Michael Nordman2431f5f2017-09-13 04:58:151333 net::RedirectInfo redirect_info_;
Daniel Bratell0dfa6282017-11-08 10:12:231334 int redirect_limit_ = net::URLRequest::kMaxRedirects;
kinuko69732972017-05-29 08:50:071335 ResourceContext* resource_context_;
yzshenefcb7c72017-06-16 23:12:301336 base::Callback<WebContents*()> web_contents_getter_;
John Abd-El-Malekeb1a5382018-01-05 16:58:001337 std::unique_ptr<NavigationUIData> navigation_ui_data_;
Kinuko Yasudabe4ad292018-07-06 01:33:391338 scoped_refptr<network::SharedURLLoaderFactory> network_loader_factory_;
arthursonzogni2695d04d2017-12-12 08:39:011339
yzshenefcb7c72017-06-16 23:12:301340 std::unique_ptr<ThrottlingURLLoader> url_loader_;
arthursonzogni2695d04d2017-12-12 08:39:011341
Chong Zhang7607f1f2018-06-01 20:52:201342 // Caches the modified request headers provided by clients during redirect,
1343 // will be consumed by next |url_loader_->FollowRedirect()|.
1344 base::Optional<net::HttpRequestHeaders> url_loader_modified_request_headers_;
1345
mmenkeed44e6c2017-06-28 21:13:321346 BlobHandles blob_handles_;
Min Qin83d07872017-10-26 23:22:411347 std::vector<GURL> url_chain_;
kinuko69732972017-05-29 08:50:071348
arthursonzogni40db5f52018-01-08 16:38:491349 // Current URL that is being navigated, updated after redirection.
1350 GURL url_;
1351
Matt Menked9cad562018-08-10 21:47:091352 const bool is_main_frame_;
1353
anantae60d1d42017-06-20 04:16:271354 // Currently used by the AppCache loader to pass its factory to the
1355 // renderer which enables it to handle subresources.
Kinuko Yasuda250577c2017-10-29 02:51:241356 base::Optional<SubresourceLoaderParams> subresource_loader_params_;
anantae60d1d42017-06-20 04:16:271357
mmenkeed44e6c2017-06-28 21:13:321358 // This is referenced only on the UI thread.
arthursonzogni1fd60e62018-05-09 15:57:321359 base::WeakPtr<NavigationURLLoaderImpl> owner_;
mmenkeed44e6c2017-06-28 21:13:321360
anantab9800e52017-07-29 18:04:131361 // Set to true if the default URLLoader (network service) was used for the
1362 // current navigation.
1363 bool default_loader_used_ = false;
1364
1365 // URLLoaderClient binding for loaders created for responses received from the
1366 // network loader.
John Abd-El-Malekb165dc52018-01-18 17:12:181367 mojo::Binding<network::mojom::URLLoaderClient> response_loader_binding_;
anantab9800e52017-07-29 18:04:131368
1369 // URLLoader instance for response loaders, i.e loaders created for handing
1370 // responses received from the network URLLoader.
John Abd-El-Malekb165dc52018-01-18 17:12:181371 network::mojom::URLLoaderPtr response_url_loader_;
anantab9800e52017-07-29 18:04:131372
1373 // Set to true if we receive a valid response from a URLLoader, i.e.
1374 // URLLoaderClient::OnReceivedResponse() is called.
1375 bool received_response_ = false;
1376
Alex Clarke1e08882b32017-10-06 14:22:401377 bool started_ = false;
1378
Ken Rockot314714c2017-11-05 23:36:241379 // Lazily initialized and used in the case of non-network resource
1380 // navigations. Keyed by URL scheme.
John Abd-El-Malekb165dc52018-01-18 17:12:181381 std::map<std::string, network::mojom::URLLoaderFactoryPtr>
Ken Rockot314714c2017-11-05 23:36:241382 non_network_url_loader_factories_;
1383
Makoto Shimazu44c2c3232018-03-30 01:10:201384 // Non-NetworkService:
1385 // Generator of a request handler for sending request to the network. This
1386 // captures all of parameters to create a
1387 // SingleRequestURLLoaderFactory::RequestHandler. Used only when
1388 // NetworkService is disabled but IsLoaderInterceptionEnabled() is true.
Makoto Shimazu684a5ad2018-05-29 08:20:501389 // Set |was_request_intercepted| to true if the request was intercepted by an
1390 // interceptor and the request is falling back to the network. In that case,
1391 // any interceptors won't intercept the request.
1392 base::RepeatingCallback<SingleRequestURLLoaderFactory::RequestHandler(
1393 bool /* was_request_intercepted */)>
Makoto Shimazu44c2c3232018-03-30 01:10:201394 default_request_handler_factory_;
1395
Min Qin40b72172017-09-27 00:19:171396 // The completion status if it has been received. This is needed to handle
1397 // the case that the response is intercepted by download, and OnComplete() is
1398 // already called while we are transferring the |url_loader_| and response
1399 // body to download code.
Takashi Toyoshimaaa278662017-11-20 11:11:261400 base::Optional<network::URLLoaderCompletionStatus> status_;
Min Qin40b72172017-09-27 00:19:171401
Ken Rockota0dfaca12018-02-15 07:26:251402 // Before creating this URLLoaderRequestController on UI thread, the embedder
1403 // may have elected to proxy the URLLoaderFactory request, in which case these
1404 // fields will contain input (info) and output (request) endpoints for the
1405 // proxy. If this controller is handling a request for which proxying is
1406 // supported, requests will be plumbed through these endpoints.
1407 //
1408 // Note that these are only used for requests that go to the Network Service.
1409 network::mojom::URLLoaderFactoryRequest proxied_factory_request_;
1410 network::mojom::URLLoaderFactoryPtrInfo proxied_factory_info_;
1411
John Abd-El-Maleka67add82018-03-09 18:22:011412 // The schemes that this loader can use. For anything else we'll try external
1413 // protocol handlers.
1414 std::set<std::string> known_schemes_;
1415
Clark DuVallb2680c22018-08-10 15:27:271416 // If true, redirect checks will be handled in a proxy, and not here.
1417 bool bypass_redirect_checks_;
Clark DuVallbf7722f2018-08-03 18:03:331418
Makoto Shimazu44c2c3232018-03-30 01:10:201419 mutable base::WeakPtrFactory<URLLoaderRequestController> weak_factory_;
arthursonzogni2695d04d2017-12-12 08:39:011420
kinuko69732972017-05-29 08:50:071421 DISALLOW_COPY_AND_ASSIGN(URLLoaderRequestController);
1422};
1423
Min Qin75ed6df2017-12-01 20:39:151424// TODO(https://crbug.com/790734): pass |navigation_ui_data| along with the
1425// request so that it could be modified.
arthursonzogni1fd60e62018-05-09 15:57:321426NavigationURLLoaderImpl::NavigationURLLoaderImpl(
scottmg69985212017-04-12 16:47:281427 ResourceContext* resource_context,
1428 StoragePartition* storage_partition,
1429 std::unique_ptr<NavigationRequestInfo> request_info,
1430 std::unique_ptr<NavigationUIData> navigation_ui_data,
scottmgd2021c92017-05-15 16:58:051431 ServiceWorkerNavigationHandle* service_worker_navigation_handle,
scottmg69985212017-04-12 16:47:281432 AppCacheNavigationHandle* appcache_handle,
Alex Clarke1e08882b32017-10-06 14:22:401433 NavigationURLLoaderDelegate* delegate,
Kinuko Yasuda7f3e1722018-03-26 08:58:581434 std::vector<std::unique_ptr<NavigationLoaderInterceptor>>
1435 initial_interceptors)
Min Qin37db5102017-09-13 21:21:251436 : delegate_(delegate),
1437 allow_download_(request_info->common_params.allow_download),
1438 weak_factory_(this) {
scottmg95feea52017-04-12 17:51:331439 DCHECK_CURRENTLY_ON(BrowserThread::UI);
John Abd-El-Malekfcb2ecf2017-11-15 23:15:301440 int frame_tree_node_id = request_info->frame_tree_node_id;
ananta5149d8e2017-04-21 00:01:371441
yzshen0f278522017-05-01 17:10:221442 TRACE_EVENT_ASYNC_BEGIN_WITH_TIMESTAMP1(
1443 "navigation", "Navigation timeToResponseStarted", this,
kinuko69732972017-05-29 08:50:071444 request_info->common_params.navigation_start, "FrameTreeNode id",
John Abd-El-Malekfcb2ecf2017-11-15 23:15:301445 frame_tree_node_id);
yzshen0f278522017-05-01 17:10:221446
arthursonzogni2695d04d2017-12-12 08:39:011447 ServiceWorkerNavigationHandleCore* service_worker_navigation_handle_core =
1448 service_worker_navigation_handle
1449 ? service_worker_navigation_handle->core()
1450 : nullptr;
1451
1452 AppCacheNavigationHandleCore* appcache_handle_core =
1453 appcache_handle ? appcache_handle->core() : nullptr;
1454
Yuzhu Shencb3011f62018-02-08 02:51:501455 std::unique_ptr<network::ResourceRequest> new_request = CreateResourceRequest(
1456 request_info.get(), frame_tree_node_id, allow_download_);
Yutaka Hirano61e41b3c2018-05-31 05:31:061457 new_request->transition_type = request_info->common_params.transition;
Tsuyoshi Horob8d512a2018-01-25 17:01:591458
Yutaka Hiranod8789f92018-01-30 09:59:511459 if (!base::FeatureList::IsEnabled(network::features::kNetworkService)) {
arthursonzogni2695d04d2017-12-12 08:39:011460 DCHECK(!request_controller_);
1461 request_controller_ = std::make_unique<URLLoaderRequestController>(
Kinuko Yasuda7f3e1722018-03-26 08:58:581462 /* initial_interceptors = */
1463 std::vector<std::unique_ptr<NavigationLoaderInterceptor>>(),
Tsuyoshi Horob8d512a2018-01-25 17:01:591464 std::move(new_request), resource_context,
Matt Menked9cad562018-08-10 21:47:091465 request_info->common_params.url, request_info->is_main_frame,
Ken Rockota0dfaca12018-02-15 07:26:251466 /* proxied_url_loader_factory_request */ nullptr,
John Abd-El-Maleka67add82018-03-09 18:22:011467 /* proxied_url_loader_factory_info */ nullptr, std::set<std::string>(),
Clark DuVallb2680c22018-08-10 15:27:271468 /* bypass_redirect_checks */ false, weak_factory_.GetWeakPtr());
arthursonzogni2695d04d2017-12-12 08:39:011469
1470 BrowserThread::PostTask(
1471 BrowserThread::IO, FROM_HERE,
1472 base::BindOnce(
1473 &URLLoaderRequestController::StartWithoutNetworkService,
1474 base::Unretained(request_controller_.get()),
Tsuyoshi Horo70014ad2018-02-14 11:20:141475 base::RetainedRef(storage_partition->GetURLRequestContext()),
arthursonzogni2695d04d2017-12-12 08:39:011476 base::Unretained(storage_partition->GetFileSystemContext()),
1477 base::Unretained(service_worker_navigation_handle_core),
tzikccf160c2018-02-20 12:43:131478 base::Unretained(appcache_handle_core), std::move(request_info),
1479 std::move(navigation_ui_data)));
arthursonzogni2695d04d2017-12-12 08:39:011480 return;
1481 }
1482
scottmgd2021c92017-05-15 16:58:051483 // Check if a web UI scheme wants to handle this request.
Ken Rockot6414c4d92017-11-08 19:58:321484 FrameTreeNode* frame_tree_node =
1485 FrameTreeNode::GloballyFindByID(frame_tree_node_id);
John Abd-El-Malekb165dc52018-01-18 17:12:181486 network::mojom::URLLoaderFactoryPtrInfo factory_for_webui;
scottmgd2021c92017-05-15 16:58:051487 const auto& schemes = URLDataManagerBackend::GetWebUISchemes();
John Abd-El-Malekbb0bc8e2017-11-11 01:08:151488 std::string scheme = new_request->url.scheme();
qufehdquf9c8433abd2018-07-10 16:57:271489 if (base::ContainsValue(schemes, scheme)) {
Chris Mumfordbae8a742018-03-01 23:02:231490 factory_for_webui = CreateWebUIURLLoaderBinding(
1491 frame_tree_node->current_frame_host(), scheme)
1492 .PassInterface();
ananta5149d8e2017-04-21 00:01:371493 }
scottmgd2021c92017-05-15 16:58:051494
Ken Rockota0dfaca12018-02-15 07:26:251495 network::mojom::URLLoaderFactoryPtrInfo proxied_factory_info;
1496 network::mojom::URLLoaderFactoryRequest proxied_factory_request;
Clark DuVallb2680c22018-08-10 15:27:271497 bool bypass_redirect_checks = false;
Chris Mumford942075ad2018-05-19 00:22:041498 auto* partition = static_cast<StoragePartitionImpl*>(storage_partition);
Ken Rockota0dfaca12018-02-15 07:26:251499 if (frame_tree_node) {
1500 // |frame_tree_node| may be null in some unit test environments.
1501 GetContentClient()
1502 ->browser()
1503 ->RegisterNonNetworkNavigationURLLoaderFactories(
John Abd-El-Malekea006302018-05-10 05:50:461504 frame_tree_node_id, &non_network_url_loader_factories_);
Ken Rockota0dfaca12018-02-15 07:26:251505
1506 // The embedder may want to proxy all network-bound URLLoaderFactory
1507 // requests that it can. If it elects to do so, we'll pass its proxy
1508 // endpoints off to the URLLoaderRequestController where wthey will be
1509 // connected if the request type supports proxying.
1510 network::mojom::URLLoaderFactoryPtrInfo factory_info;
1511 auto factory_request = mojo::MakeRequest(&factory_info);
Andrey Kosyakov8d49c5062018-03-15 19:50:491512 bool use_proxy = GetContentClient()->browser()->WillCreateURLLoaderFactory(
Ken Rockot428b1d62018-06-06 17:12:211513 partition->browser_context(), frame_tree_node->current_frame_host(),
Clark DuVall8dc4e502018-09-07 01:51:121514 true /* is_navigation */, new_request->url, &factory_request,
1515 &bypass_redirect_checks);
Andrey Kosyakov8d49c5062018-03-15 19:50:491516 if (RenderFrameDevToolsAgentHost::WillCreateURLLoaderFactory(
Jochen Eisingercdc12d12018-05-08 15:07:471517 frame_tree_node->current_frame_host(), true, false,
1518 &factory_request)) {
Andrey Kosyakov8d49c5062018-03-15 19:50:491519 use_proxy = true;
1520 }
1521 if (use_proxy) {
Ken Rockota0dfaca12018-02-15 07:26:251522 proxied_factory_request = std::move(factory_request);
1523 proxied_factory_info = std::move(factory_info);
1524 }
Chris Mumford942075ad2018-05-19 00:22:041525
1526 const std::string storage_domain;
1527 non_network_url_loader_factories_[url::kFileSystemScheme] =
1528 CreateFileSystemURLLoaderFactory(frame_tree_node->current_frame_host(),
1529 /*is_navigation=*/true,
1530 partition->GetFileSystemContext(),
1531 storage_domain);
Ken Rockota0dfaca12018-02-15 07:26:251532 }
1533
John Abd-El-Maleka67add82018-03-09 18:22:011534 non_network_url_loader_factories_[url::kFileScheme] =
1535 std::make_unique<FileURLLoaderFactory>(
1536 partition->browser_context()->GetPath(),
1537 base::CreateSequencedTaskRunnerWithTraits(
Gabriel Charetteb10aeebc2018-07-26 20:15:001538 {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
John Abd-El-Maleka67add82018-03-09 18:22:011539 base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}));
1540 std::set<std::string> known_schemes;
1541 for (auto& iter : non_network_url_loader_factories_)
1542 known_schemes.insert(iter.first);
1543
kinuko69732972017-05-29 08:50:071544 DCHECK(!request_controller_);
Jeremy Roman04f27c372017-10-27 15:20:551545 request_controller_ = std::make_unique<URLLoaderRequestController>(
Kinuko Yasuda7f3e1722018-03-26 08:58:581546 std::move(initial_interceptors), std::move(new_request), resource_context,
Matt Menked9cad562018-08-10 21:47:091547 request_info->common_params.url, request_info->is_main_frame,
1548 std::move(proxied_factory_request), std::move(proxied_factory_info),
1549 std::move(known_schemes), bypass_redirect_checks,
1550 weak_factory_.GetWeakPtr());
scottmgd2021c92017-05-15 16:58:051551 BrowserThread::PostTask(
1552 BrowserThread::IO, FROM_HERE,
Ken Rockot387ddd5a2018-01-30 19:18:401553 base::BindOnce(
1554 &URLLoaderRequestController::Start,
1555 base::Unretained(request_controller_.get()),
Kinuko Yasudabe4ad292018-07-06 01:33:391556 partition->url_loader_factory_getter()->GetNetworkFactoryInfo(),
Ken Rockot387ddd5a2018-01-30 19:18:401557 service_worker_navigation_handle_core, appcache_handle_core,
1558 std::move(request_info), std::move(navigation_ui_data),
1559 std::move(factory_for_webui), frame_tree_node_id,
1560 ServiceManagerConnection::GetForProcess()->GetConnector()->Clone()));
scottmg69985212017-04-12 16:47:281561}
1562
arthursonzogni1fd60e62018-05-09 15:57:321563NavigationURLLoaderImpl::~NavigationURLLoaderImpl() {
kinuko69732972017-05-29 08:50:071564 BrowserThread::DeleteSoon(BrowserThread::IO, FROM_HERE,
1565 request_controller_.release());
1566}
scottmg69985212017-04-12 16:47:281567
Chong Zhang7607f1f2018-06-01 20:52:201568void NavigationURLLoaderImpl::FollowRedirect(
Jun Cai605ff0e72018-06-12 22:29:201569 const base::Optional<std::vector<std::string>>&
1570 to_be_removed_request_headers,
Chong Zhang7607f1f2018-06-01 20:52:201571 const base::Optional<net::HttpRequestHeaders>& modified_request_headers) {
yzshenefcb7c72017-06-16 23:12:301572 BrowserThread::PostTask(
1573 BrowserThread::IO, FROM_HERE,
tzik0f14f192017-08-15 02:43:331574 base::BindOnce(&URLLoaderRequestController::FollowRedirect,
Chong Zhang7607f1f2018-06-01 20:52:201575 base::Unretained(request_controller_.get()),
1576 modified_request_headers));
scottmg95feea52017-04-12 17:51:331577}
scottmg69985212017-04-12 16:47:281578
arthursonzogni1fd60e62018-05-09 15:57:321579void NavigationURLLoaderImpl::ProceedWithResponse() {}
scottmg69985212017-04-12 16:47:281580
arthursonzogni1fd60e62018-05-09 15:57:321581void NavigationURLLoaderImpl::OnReceiveResponse(
John Abd-El-Malek46248032018-01-17 19:11:231582 scoped_refptr<network::ResourceResponse> response,
John Abd-El-Malekb165dc52018-01-18 17:12:181583 network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
arthursonzogni40db5f52018-01-08 16:38:491584 std::unique_ptr<NavigationData> navigation_data,
1585 const GlobalRequestID& global_request_id,
1586 bool is_download,
Ryan Sturm64315a92018-07-20 06:25:281587 bool is_stream,
1588 PreviewsState previews_state) {
arthursonzogni3a4ca9f2017-12-07 17:58:341589 TRACE_EVENT_ASYNC_END2("navigation", "Navigation timeToResponseStarted", this,
arthursonzogni1fd60e62018-05-09 15:57:321590 "&NavigationURLLoaderImpl", this, "success", true);
arthursonzogni3a4ca9f2017-12-07 17:58:341591
scottmgefb697302017-04-12 22:37:301592 // TODO(scottmg): This needs to do more of what
arthursonzogni3a4ca9f2017-12-07 17:58:341593 // NavigationResourceHandler::OnResponseStarted() does.
arthursonzogni3a4ca9f2017-12-07 17:58:341594
arthursonzogni3a4ca9f2017-12-07 17:58:341595 delegate_->OnResponseStarted(
arthursonzognif34adf092018-04-24 17:06:131596 std::move(response), std::move(url_loader_client_endpoints),
Philip Rogers7178f5c2018-07-09 18:52:591597 std::move(navigation_data), global_request_id,
Ryan Sturm64315a92018-07-20 06:25:281598 allow_download_ && is_download, is_stream, previews_state,
arthursonzogni3a4ca9f2017-12-07 17:58:341599 request_controller_->TakeSubresourceLoaderParams());
scottmg95feea52017-04-12 17:51:331600}
scottmg69985212017-04-12 16:47:281601
arthursonzogni1fd60e62018-05-09 15:57:321602void NavigationURLLoaderImpl::OnReceiveRedirect(
scottmg69985212017-04-12 16:47:281603 const net::RedirectInfo& redirect_info,
John Abd-El-Malek46248032018-01-17 19:11:231604 scoped_refptr<network::ResourceResponse> response) {
scottmg95feea52017-04-12 17:51:331605 DCHECK_CURRENTLY_ON(BrowserThread::UI);
Andrey Kosyakova924c8b2017-08-18 17:37:231606 delegate_->OnRequestRedirected(redirect_info, std::move(response));
scottmg95feea52017-04-12 17:51:331607}
scottmg69985212017-04-12 16:47:281608
arthursonzogni1fd60e62018-05-09 15:57:321609void NavigationURLLoaderImpl::OnComplete(
Takashi Toyoshimaaa278662017-11-20 11:11:261610 const network::URLLoaderCompletionStatus& status) {
Takashi Toyoshima8f988532017-11-13 07:32:371611 if (status.error_code == net::OK)
John Abd-El-Malekb906d282017-08-31 19:36:431612 return;
1613
1614 TRACE_EVENT_ASYNC_END2("navigation", "Navigation timeToResponseStarted", this,
arthursonzogni1fd60e62018-05-09 15:57:321615 "&NavigationURLLoaderImpl", this, "success", false);
Lucas Garron0efab6d2017-08-30 22:28:511616
Johannes Henkel6a43fef2018-05-17 18:41:521617 delegate_->OnRequestFailed(status);
yzshen384441de2017-04-19 23:26:141618}
scottmg69985212017-04-12 16:47:281619
arthursonzogni1fd60e62018-05-09 15:57:321620void NavigationURLLoaderImpl::SetBeginNavigationInterceptorForTesting(
John Abd-El-Malekdb3a13b2018-05-01 17:52:021621 const BeginNavigationInterceptor& interceptor) {
1622 DCHECK(!BrowserThread::IsThreadInitialized(BrowserThread::IO) ||
1623 BrowserThread::CurrentlyOn(BrowserThread::IO));
1624 DCHECK(!base::FeatureList::IsEnabled(network::features::kNetworkService));
1625 g_interceptor.Get() = interceptor;
1626}
1627
arthursonzogni1fd60e62018-05-09 15:57:321628void NavigationURLLoaderImpl::OnRequestStarted(base::TimeTicks timestamp) {
arthursonzogni2695d04d2017-12-12 08:39:011629 DCHECK_CURRENTLY_ON(BrowserThread::UI);
1630 delegate_->OnRequestStarted(timestamp);
1631}
1632
arthursonzogni1fd60e62018-05-09 15:57:321633void NavigationURLLoaderImpl::BindNonNetworkURLLoaderFactoryRequest(
Ken Rockota0dfaca12018-02-15 07:26:251634 int frame_tree_node_id,
Ken Rockot314714c2017-11-05 23:36:241635 const GURL& url,
John Abd-El-Malekb165dc52018-01-18 17:12:181636 network::mojom::URLLoaderFactoryRequest factory) {
Ken Rockot314714c2017-11-05 23:36:241637 auto it = non_network_url_loader_factories_.find(url.scheme());
1638 if (it == non_network_url_loader_factories_.end()) {
1639 DVLOG(1) << "Ignoring request with unknown scheme: " << url.spec();
1640 return;
1641 }
Ken Rockota0dfaca12018-02-15 07:26:251642 FrameTreeNode* frame_tree_node =
1643 FrameTreeNode::GloballyFindByID(frame_tree_node_id);
Ken Rockot428b1d62018-06-06 17:12:211644 auto* frame = frame_tree_node->current_frame_host();
Ken Rockota0dfaca12018-02-15 07:26:251645 GetContentClient()->browser()->WillCreateURLLoaderFactory(
Ken Rockot428b1d62018-06-06 17:12:211646 frame->GetSiteInstance()->GetBrowserContext(), frame,
Clark DuVall8dc4e502018-09-07 01:51:121647 true /* is_navigation */, url, &factory,
1648 nullptr /* bypass_redirect_checks */);
Ken Rockot314714c2017-11-05 23:36:241649 it->second->Clone(std::move(factory));
1650}
1651
scottmg69985212017-04-12 16:47:281652} // namespace content