blob: 838bef6ca9b539846f83b8d5566ffa1fddab50de [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"
Matt Falkenhagen2ba894152018-09-21 08:29:4411#include "base/debug/alias.h"
Tarun Bansal98260cd2018-02-17 07:52:2312#include "base/feature_list.h"
Emily Starkb09f19a2017-11-22 22:41:4713#include "base/metrics/histogram_macros.h"
Matt Menked9cad562018-08-10 21:47:0914#include "base/optional.h"
Matt Falkenhagen2ba894152018-09-21 08:29:4415#include "base/rand_util.h"
qufehdquf9c8433abd2018-07-10 16:57:2716#include "base/stl_util.h"
Gabriel Charette44db1422018-08-06 11:19:3317#include "base/task/post_task.h"
yzshen0f278522017-05-01 17:10:2218#include "base/trace_event/trace_event.h"
Min Qinda0ed2062018-02-23 22:00:5319#include "components/download/public/common/download_stats.h"
anantae3f159a2017-05-11 23:40:0720#include "content/browser/appcache/appcache_navigation_handle.h"
Hiroki Nakagawaff43e4472018-07-26 07:06:4621#include "content/browser/appcache/appcache_navigation_handle_core.h"
anantaa2c8ec62017-06-09 23:44:0522#include "content/browser/appcache/appcache_request_handler.h"
ananta5149d8e2017-04-21 00:01:3723#include "content/browser/blob_storage/chrome_blob_storage_context.h"
Andrey Kosyakov8d49c5062018-03-15 19:50:4924#include "content/browser/devtools/render_frame_devtools_agent_host.h"
Ken Rockot314714c2017-11-05 23:36:2425#include "content/browser/file_url_loader_factory.h"
Chris Mumford942075ad2018-05-19 00:22:0426#include "content/browser/fileapi/file_system_url_loader_factory.h"
jam8c4edd02017-05-06 18:50:3327#include "content/browser/frame_host/frame_tree_node.h"
scottmg69985212017-04-12 16:47:2828#include "content/browser/frame_host/navigation_request_info.h"
Kinuko Yasuda7f3e1722018-03-26 08:58:5829#include "content/browser/loader/navigation_loader_interceptor.h"
scottmg95feea52017-04-12 17:51:3330#include "content/browser/loader/navigation_url_loader_delegate.h"
arthursonzogni2695d04d2017-12-12 08:39:0131#include "content/browser/loader/resource_dispatcher_host_impl.h"
arthursonzogni40db5f52018-01-08 16:38:4932#include "content/browser/loader/resource_request_info_impl.h"
scottmgd2021c92017-05-15 16:58:0533#include "content/browser/resource_context_impl.h"
34#include "content/browser/service_worker/service_worker_navigation_handle.h"
35#include "content/browser/service_worker/service_worker_navigation_handle_core.h"
36#include "content/browser/service_worker/service_worker_request_handler.h"
jamc1905862017-05-16 14:45:3037#include "content/browser/storage_partition_impl.h"
38#include "content/browser/url_loader_factory_getter.h"
scottmgd2021c92017-05-15 16:58:0539#include "content/browser/web_contents/web_contents_impl.h"
Kouhei Ueno958c5f482018-03-19 08:20:3840#include "content/browser/web_package/signed_exchange_consts.h"
Kunihiko Sakamotoe6aa22e2018-06-15 03:26:5541#include "content/browser/web_package/signed_exchange_request_handler.h"
Tsuyoshi Horob85801592018-02-19 22:18:0742#include "content/browser/web_package/signed_exchange_url_loader_factory_for_non_network_service.h"
Tsuyoshi Horo46f5fff2018-05-10 12:33:3543#include "content/browser/web_package/signed_exchange_utils.h"
jam1a97290b2017-05-09 04:30:5044#include "content/browser/webui/url_data_manager_backend.h"
Chris Mumfordbae8a742018-03-01 23:02:2345#include "content/browser/webui/web_ui_url_loader_factory_internal.h"
Makoto Shimazu21950e82018-08-02 12:37:1446#include "content/common/mime_sniffing_throttle.h"
Kinuko Yasuda250577c2017-10-29 02:51:2447#include "content/common/navigation_subresource_loader_params.h"
Matt Menkea294b092018-07-06 17:53:3248#include "content/common/net/record_load_histograms.h"
yzshenefcb7c72017-06-16 23:12:3049#include "content/common/throttling_url_loader.h"
jamc1905862017-05-16 14:45:3050#include "content/public/browser/browser_context.h"
Eric Seckler8652dcd52018-09-20 10:42:2851#include "content/public/browser/browser_task_traits.h"
scottmg95feea52017-04-12 17:51:3352#include "content/public/browser/browser_thread.h"
yzshenefcb7c72017-06-16 23:12:3053#include "content/public/browser/content_browser_client.h"
Robbie McElratha5adc4e2018-07-03 23:53:0954#include "content/public/browser/download_utils.h"
scottmgefb697302017-04-12 22:37:3055#include "content/public/browser/global_request_id.h"
Dmitry Skiba7e8c7e22018-01-04 21:04:1856#include "content/public/browser/navigation_data.h"
scottmg69985212017-04-12 16:47:2857#include "content/public/browser/navigation_ui_data.h"
John Abd-El-Malek3ebdff862018-04-23 18:57:2158#include "content/public/browser/plugin_service.h"
arthursonzogni40db5f52018-01-08 16:38:4959#include "content/public/browser/resource_dispatcher_host_delegate.h"
scottmgefb697302017-04-12 22:37:3060#include "content/public/browser/ssl_status.h"
Jian Li18e29242018-05-10 22:25:1261#include "content/public/browser/url_loader_request_interceptor.h"
arthursonzogni2695d04d2017-12-12 08:39:0162#include "content/public/common/content_features.h"
ananta5149d8e2017-04-21 00:01:3763#include "content/public/common/referrer.h"
jam8c4edd02017-05-06 18:50:3364#include "content/public/common/url_constants.h"
Ken Rockot314714c2017-11-05 23:36:2465#include "content/public/common/url_utils.h"
John Abd-El-Malek3ebdff862018-04-23 18:57:2166#include "content/public/common/webplugininfo.h"
ananta5149d8e2017-04-21 00:01:3767#include "net/base/load_flags.h"
Matt Menked9cad562018-08-10 21:47:0968#include "net/cert/sct_status_flags.h"
69#include "net/cert/signed_certificate_timestamp_and_status.h"
Min Qin37db5102017-09-13 21:21:2570#include "net/http/http_content_disposition.h"
Chong Zhang7607f1f2018-06-01 20:52:2071#include "net/http/http_request_headers.h"
Matt Menked9cad562018-08-10 21:47:0972#include "net/ssl/ssl_info.h"
rhalavati4cda417b2017-06-12 11:00:2473#include "net/traffic_annotation/network_traffic_annotation.h"
Tsuyoshi Horo9e2ec4df2017-10-16 15:15:5574#include "net/url_request/redirect_util.h"
Daniel Bratell0dfa6282017-11-08 10:12:2375#include "net/url_request/url_request.h"
scottmg69985212017-04-12 16:47:2876#include "net/url_request/url_request_context.h"
Tsuyoshi Horo70014ad2018-02-14 11:20:1477#include "net/url_request/url_request_context_getter.h"
John Abd-El-Malek3ebdff862018-04-23 18:57:2178#include "ppapi/buildflags/buildflags.h"
John Abd-El-Malek89c02ae2018-02-01 01:56:1979#include "services/network/loader_util.h"
Yutaka Hiranod8789f92018-01-30 09:59:5180#include "services/network/public/cpp/features.h"
Antonio Gomes9cdc09a2018-05-07 23:24:2681#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
82#include "services/network/public/cpp/wrapper_shared_url_loader_factory.h"
Ken Rockot54311e62018-02-10 19:01:5283#include "services/network/public/mojom/request_context_frame_type.mojom.h"
84#include "services/network/public/mojom/url_loader_factory.mojom.h"
yzshenefcb7c72017-06-16 23:12:3085#include "services/service_manager/public/cpp/connector.h"
John Abd-El-Malek3ebdff862018-04-23 18:57:2186#include "third_party/blink/public/common/mime_util/mime_util.h"
Han Leonf1525df2018-07-11 03:47:5987#include "third_party/blink/public/common/service_worker/service_worker_utils.h"
Matt Falkenhagen2ba894152018-09-21 08:29:4488#include "url/gurl.h"
scottmg69985212017-04-12 16:47:2889
90namespace content {
91
jambcc67882017-04-28 18:20:0992namespace {
yzshenfa5e57202017-05-02 21:24:1393
Jian Li18e29242018-05-10 22:25:1294class NavigationLoaderInterceptorBrowserContainer
95 : public NavigationLoaderInterceptor {
96 public:
97 explicit NavigationLoaderInterceptorBrowserContainer(
98 std::unique_ptr<URLLoaderRequestInterceptor> browser_interceptor)
99 : browser_interceptor_(std::move(browser_interceptor)) {}
100
101 ~NavigationLoaderInterceptorBrowserContainer() override = default;
102
Matt Falkenhagen43765122018-08-22 19:37:22103 void MaybeCreateLoader(
104 const network::ResourceRequest& tentative_resource_request,
105 ResourceContext* resource_context,
106 LoaderCallback callback,
107 FallbackCallback fallback_callback) override {
108 browser_interceptor_->MaybeCreateLoader(
109 tentative_resource_request, resource_context, std::move(callback));
Jian Li18e29242018-05-10 22:25:12110 }
111
112 private:
113 std::unique_ptr<URLLoaderRequestInterceptor> browser_interceptor_;
114};
115
John Abd-El-Malekdb3a13b2018-05-01 17:52:02116// Only used on the IO thread.
arthursonzogni1fd60e62018-05-09 15:57:32117base::LazyInstance<NavigationURLLoaderImpl::BeginNavigationInterceptor>::Leaky
John Abd-El-Malekdb3a13b2018-05-01 17:52:02118 g_interceptor = LAZY_INSTANCE_INITIALIZER;
119
Kinuko Yasuda7f3e1722018-03-26 08:58:58120// Returns true if interception by NavigationLoaderInterceptors is enabled.
Tsuyoshi Horo46f5fff2018-05-10 12:33:35121// Both ServiceWorkerServicification and SignedExchange require the loader
122// interception. So even if NetworkService is not enabled, returns true when one
123// of them is enabled.
Kinuko Yasuda7f3e1722018-03-26 08:58:58124bool IsLoaderInterceptionEnabled() {
Yutaka Hiranod8789f92018-01-30 09:59:51125 return base::FeatureList::IsEnabled(network::features::kNetworkService) ||
Han Leonf1525df2018-07-11 03:47:59126 blink::ServiceWorkerUtils::IsServicificationEnabled() ||
Tsuyoshi Horo46f5fff2018-05-10 12:33:35127 signed_exchange_utils::IsSignedExchangeHandlingEnabled();
Tsuyoshi Horob8d512a2018-01-25 17:01:59128}
129
ananta2e65213d2017-05-19 04:08:24130// Request ID for browser initiated requests. We start at -2 on the same lines
131// as ResourceDispatcherHostImpl.
132int g_next_request_id = -2;
arthursonzogni40db5f52018-01-08 16:38:49133GlobalRequestID MakeGlobalRequestID() {
134 return GlobalRequestID(-1, g_next_request_id--);
135}
ananta2e65213d2017-05-19 04:08:24136
Emily Starkb09f19a2017-11-22 22:41:47137size_t GetCertificateChainsSizeInKB(const net::SSLInfo& ssl_info) {
138 base::Pickle cert_pickle;
139 ssl_info.cert->Persist(&cert_pickle);
140 base::Pickle unverified_cert_pickle;
141 ssl_info.unverified_cert->Persist(&unverified_cert_pickle);
142 return (cert_pickle.size() + unverified_cert_pickle.size()) / 1000;
143}
144
scottmgd2021c92017-05-15 16:58:05145WebContents* GetWebContentsFromFrameTreeNodeID(int frame_tree_node_id) {
146 DCHECK_CURRENTLY_ON(BrowserThread::UI);
147 FrameTreeNode* frame_tree_node =
148 FrameTreeNode::GloballyFindByID(frame_tree_node_id);
149 if (!frame_tree_node)
150 return nullptr;
ananta5149d8e2017-04-21 00:01:37151
scottmgd2021c92017-05-15 16:58:05152 return WebContentsImpl::FromFrameTreeNode(frame_tree_node);
153}
154
Daniel Bratellcf0b485c2017-11-09 22:42:50155const net::NetworkTrafficAnnotationTag kNavigationUrlLoaderTrafficAnnotation =
Ramin Halavatie99206e92017-06-23 05:02:50156 net::DefineNetworkTrafficAnnotation("navigation_url_loader", R"(
Ramin Halavati7b5ce1c2017-07-03 09:13:09157 semantics {
158 sender: "Navigation URL Loader"
159 description:
160 "This request is issued by a main frame navigation to fetch the "
161 "content of the page that is being navigated to."
162 trigger:
163 "Navigating Chrome (by clicking on a link, bookmark, history item, "
164 "using session restore, etc)."
165 data:
166 "Arbitrary site-controlled data can be included in the URL, HTTP "
167 "headers, and request body. Requests may include cookies and "
168 "site-specific credentials."
169 destination: WEBSITE
170 }
171 policy {
Ramin Halavati3b979782017-07-21 11:40:26172 cookies_allowed: YES
Ramin Halavati7b5ce1c2017-07-03 09:13:09173 cookies_store: "user"
174 setting: "This feature cannot be disabled."
Ramin Halavati386daa62017-08-17 10:41:59175 chrome_policy {
176 URLBlacklist {
177 URLBlacklist: { entries: '*' }
178 }
179 }
180 chrome_policy {
181 URLWhitelist {
182 URLWhitelist { }
183 }
184 }
185 }
186 comments:
187 "Chrome would be unable to navigate to websites without this type of "
188 "request. Using either URLBlacklist or URLWhitelist policies (or a "
189 "combination of both) limits the scope of these requests."
190 )");
Ramin Halavatie99206e92017-06-23 05:02:50191
Tsuyoshi Horob8d512a2018-01-25 17:01:59192std::unique_ptr<network::ResourceRequest> CreateResourceRequest(
193 NavigationRequestInfo* request_info,
194 int frame_tree_node_id,
195 bool allow_download) {
196 // TODO(scottmg): Port over stuff from RDHI::BeginNavigationRequest() here.
197 auto new_request = std::make_unique<network::ResourceRequest>();
198
199 new_request->method = request_info->common_params.method;
200 new_request->url = request_info->common_params.url;
201 new_request->site_for_cookies = request_info->site_for_cookies;
Tarun Bansal98260cd2018-02-17 07:52:23202
203 net::RequestPriority net_priority = net::HIGHEST;
204 if (!request_info->is_main_frame &&
205 base::FeatureList::IsEnabled(features::kLowPriorityIframes)) {
206 net_priority = net::LOWEST;
207 }
208 new_request->priority = net_priority;
209
Tsuyoshi Horob8d512a2018-01-25 17:01:59210 new_request->render_frame_id = frame_tree_node_id;
211
212 // The code below to set fields like request_initiator, referrer, etc has
213 // been copied from ResourceDispatcherHostImpl. We did not refactor the
214 // common code into a function, because RDHI uses accessor functions on the
215 // URLRequest class to set these fields. whereas we use ResourceRequest here.
216 new_request->request_initiator = request_info->begin_params->initiator_origin;
217 new_request->referrer = request_info->common_params.referrer.url;
218 new_request->referrer_policy = Referrer::ReferrerPolicyForUrlRequest(
219 request_info->common_params.referrer.policy);
220 new_request->headers.AddHeadersFromString(
221 request_info->begin_params->headers);
Kouhei Ueno958c5f482018-03-19 08:20:38222
223 std::string accept_value = network::kFrameAcceptHeader;
Tsuyoshi Horo46f5fff2018-05-10 12:33:35224 // TODO(https://crbug.com/840704): Decide whether the Accept header should
225 // advertise the state of kSignedHTTPExchangeOriginTrial before starting the
226 // Origin-Trial.
227 if (signed_exchange_utils::IsSignedExchangeHandlingEnabled()) {
Kouhei Ueno958c5f482018-03-19 08:20:38228 DCHECK(!accept_value.empty());
229 accept_value.append(kAcceptHeaderSignedExchangeSuffix);
230 }
231
232 new_request->headers.SetHeader(network::kAcceptHeader, accept_value);
Tsuyoshi Horob8d512a2018-01-25 17:01:59233
234 new_request->resource_type = request_info->is_main_frame
235 ? RESOURCE_TYPE_MAIN_FRAME
236 : RESOURCE_TYPE_SUB_FRAME;
237 if (request_info->is_main_frame)
238 new_request->update_first_party_url_on_redirect = true;
239
240 int load_flags = request_info->begin_params->load_flags;
Tsuyoshi Horob8d512a2018-01-25 17:01:59241 if (request_info->is_main_frame)
242 load_flags |= net::LOAD_MAIN_FRAME_DEPRECATED;
243
244 // Sync loads should have maximum priority and should be the only
245 // requests that have the ignore limits flag set.
246 DCHECK(!(load_flags & net::LOAD_IGNORE_LIMITS));
247
248 new_request->load_flags = load_flags;
249
250 new_request->request_body = request_info->common_params.post_data.get();
251 new_request->report_raw_headers = request_info->report_raw_headers;
252 new_request->allow_download = allow_download;
253 new_request->enable_load_timing = true;
254
255 new_request->fetch_request_mode = network::mojom::FetchRequestMode::kNavigate;
256 new_request->fetch_credentials_mode =
257 network::mojom::FetchCredentialsMode::kInclude;
258 new_request->fetch_redirect_mode = network::mojom::FetchRedirectMode::kManual;
Yutaka Hirano4b9b7a7f2018-03-07 14:35:15259 new_request->fetch_request_context_type =
Richard Li01f04032018-09-19 07:45:59260 static_cast<int>(request_info->begin_params->request_context_type);
Carlos ILa54c59a2018-06-11 19:43:03261 new_request->upgrade_if_insecure = request_info->upgrade_if_insecure;
Tsuyoshi Horoc1ab7122018-06-19 05:48:13262 new_request->throttling_profile_id = request_info->devtools_frame_token;
Tsuyoshi Horob8d512a2018-01-25 17:01:59263 return new_request;
264}
265
Makoto Shimazu44c2c3232018-03-30 01:10:20266// Used only when NetworkService is disabled but IsLoaderInterceptionEnabled()
267// is true.
268std::unique_ptr<NavigationRequestInfo> CreateNavigationRequestInfoForRedirect(
269 const NavigationRequestInfo& previous_request_info,
270 const network::ResourceRequest& updated_resource_request) {
271 DCHECK(!base::FeatureList::IsEnabled(network::features::kNetworkService));
272 DCHECK(IsLoaderInterceptionEnabled());
273
274 CommonNavigationParams new_common_params =
275 previous_request_info.common_params;
276 new_common_params.url = updated_resource_request.url;
277 new_common_params.referrer =
Makoto Shimazue8019fb2018-06-26 03:54:31278 Referrer(updated_resource_request.referrer,
Makoto Shimazu44c2c3232018-03-30 01:10:20279 Referrer::NetReferrerPolicyToBlinkReferrerPolicy(
280 updated_resource_request.referrer_policy));
281 new_common_params.method = updated_resource_request.method;
282 new_common_params.post_data = updated_resource_request.request_body;
Makoto Shimazu44c2c3232018-03-30 01:10:20283
284 mojom::BeginNavigationParamsPtr new_begin_params =
285 previous_request_info.begin_params.Clone();
286 new_begin_params->headers = updated_resource_request.headers.ToString();
287
288 return std::make_unique<NavigationRequestInfo>(
289 std::move(new_common_params), std::move(new_begin_params),
290 updated_resource_request.site_for_cookies,
291 previous_request_info.is_main_frame,
292 previous_request_info.parent_is_main_frame,
293 previous_request_info.are_ancestors_secure,
294 previous_request_info.frame_tree_node_id,
295 previous_request_info.is_for_guests_only,
296 previous_request_info.report_raw_headers,
Marijn Kruisselbrink07bf59d52018-04-03 21:50:25297 previous_request_info.is_prerendering,
Carlos ILa54c59a2018-06-11 19:43:03298 previous_request_info.upgrade_if_insecure,
Tsuyoshi Horo32b51f12018-05-09 17:58:46299 nullptr /* blob_url_loader_factory */,
Tsuyoshi Horoc1ab7122018-06-19 05:48:13300 previous_request_info.devtools_navigation_token,
301 previous_request_info.devtools_frame_token);
Makoto Shimazu44c2c3232018-03-30 01:10:20302}
303
John Abd-El-Maleka67add82018-03-09 18:22:01304// Called for requests that we don't have a URLLoaderFactory for.
Matt Falkenhagen43765122018-08-22 19:37:22305void UnknownSchemeCallback(
306 bool handled_externally,
307 const network::ResourceRequest& /* resource_request */,
308 network::mojom::URLLoaderRequest request,
309 network::mojom::URLLoaderClientPtr client) {
John Abd-El-Maleka67add82018-03-09 18:22:01310 client->OnComplete(network::URLLoaderCompletionStatus(
311 handled_externally ? net::ERR_ABORTED : net::ERR_UNKNOWN_URL_SCHEME));
312}
313
Clark DuVallbf7722f2018-08-03 18:03:33314// Returns whether this URL can be handled by the default network service
315// URLLoader.
316bool IsURLHandledByDefaultLoader(const GURL& url) {
317 // Data URLs are only handled by the network service if
318 // |enable_data_url_support| is set in NetworkContextParams. This is set to
319 // true for the context used by NavigationURLLoaderImpl, so in addition to
320 // checking whether the URL is handled by the network service, we also need to
321 // check for the data scheme.
322 return IsURLHandledByNetworkService(url) || url.SchemeIs(url::kDataScheme);
323}
324
Chris Mumford90b1a0d2018-09-26 20:10:43325// Determines whether it is safe to redirect from |from_url| to |to_url|.
326bool IsRedirectSafe(const GURL& from_url,
327 const GURL& to_url,
328 ResourceContext* resource_context) {
329 return IsSafeRedirectTarget(from_url, to_url) &&
330 GetContentClient()->browser()->IsSafeRedirectTarget(to_url,
Clark DuVallbf7722f2018-08-03 18:03:33331 resource_context);
332}
333
yzshenfa5e57202017-05-02 21:24:13334} // namespace
335
kinuko69732972017-05-29 08:50:07336// Kept around during the lifetime of the navigation request, and is
337// responsible for dispatching a ResourceRequest to the appropriate
kinukod8b13e212017-06-07 06:59:26338// URLLoader. In order to get the right URLLoader it builds a vector
Kinuko Yasuda7f3e1722018-03-26 08:58:58339// of NavigationLoaderInterceptors and successively calls MaybeCreateLoader
kinukod8b13e212017-06-07 06:59:26340// on each until the request is successfully handled. The same sequence
341// may be performed multiple times when redirects happen.
Alex Clarke1e08882b32017-10-06 14:22:40342// TODO(michaeln): Expose this class and add more unittests.
arthursonzogni1fd60e62018-05-09 15:57:32343class NavigationURLLoaderImpl::URLLoaderRequestController
John Abd-El-Malekb165dc52018-01-18 17:12:18344 : public network::mojom::URLLoaderClient {
kinuko69732972017-05-29 08:50:07345 public:
jam9354af82017-06-03 21:59:41346 URLLoaderRequestController(
Kinuko Yasuda7f3e1722018-03-26 08:58:58347 std::vector<std::unique_ptr<NavigationLoaderInterceptor>>
348 initial_interceptors,
John Abd-El-Malek1df61792018-01-12 20:40:45349 std::unique_ptr<network::ResourceRequest> resource_request,
jam9354af82017-06-03 21:59:41350 ResourceContext* resource_context,
arthursonzogni40db5f52018-01-08 16:38:49351 const GURL& url,
Matt Menked9cad562018-08-10 21:47:09352 bool is_main_frame,
Ken Rockota0dfaca12018-02-15 07:26:25353 network::mojom::URLLoaderFactoryRequest proxied_factory_request,
354 network::mojom::URLLoaderFactoryPtrInfo proxied_factory_info,
John Abd-El-Maleka67add82018-03-09 18:22:01355 std::set<std::string> known_schemes,
Clark DuVallb2680c22018-08-10 15:27:27356 bool bypass_redirect_checks,
arthursonzogni1fd60e62018-05-09 15:57:32357 const base::WeakPtr<NavigationURLLoaderImpl>& owner)
Kinuko Yasuda7f3e1722018-03-26 08:58:58358 : interceptors_(std::move(initial_interceptors)),
Alex Clarke1e08882b32017-10-06 14:22:40359 resource_request_(std::move(resource_request)),
kinuko69732972017-05-29 08:50:07360 resource_context_(resource_context),
arthursonzogni40db5f52018-01-08 16:38:49361 url_(url),
Matt Menked9cad562018-08-10 21:47:09362 is_main_frame_(is_main_frame),
anantab9800e52017-07-29 18:04:13363 owner_(owner),
arthursonzogni2695d04d2017-12-12 08:39:01364 response_loader_binding_(this),
Ken Rockota0dfaca12018-02-15 07:26:25365 proxied_factory_request_(std::move(proxied_factory_request)),
366 proxied_factory_info_(std::move(proxied_factory_info)),
John Abd-El-Maleka67add82018-03-09 18:22:01367 known_schemes_(std::move(known_schemes)),
Clark DuVallb2680c22018-08-10 15:27:27368 bypass_redirect_checks_(bypass_redirect_checks),
arthursonzogni2695d04d2017-12-12 08:39:01369 weak_factory_(this) {}
kinuko69732972017-05-29 08:50:07370
yzshenefcb7c72017-06-16 23:12:30371 ~URLLoaderRequestController() override {
kinuko69732972017-05-29 08:50:07372 DCHECK_CURRENTLY_ON(BrowserThread::IO);
Matt Menkea294b092018-07-06 17:53:32373
374 // If neither OnCompleted nor OnReceivedResponse has been invoked, the
375 // request was canceled before receiving a response, so log a cancellation.
376 // Results after receiving a non-error response are logged in the renderer,
377 // if the request is passed to one. If it's a download, or not passed to a
378 // renderer for some other reason, results will not be logged for the
379 // request. The net::OK check may not be necessary - the case where OK is
380 // received without receiving any headers looks broken, anyways.
381 if (!received_response_ && (!status_ || status_->error_code != net::OK)) {
382 RecordLoadHistograms(url_, resource_request_->resource_type,
383 status_ ? status_->error_code : net::ERR_ABORTED);
384 }
kinuko69732972017-05-29 08:50:07385 }
386
arthursonzognib521c6a2018-01-08 12:23:40387 static uint32_t GetURLLoaderOptions(bool is_main_frame) {
Livvie Lin139bf442018-08-10 00:18:54388 uint32_t options = network::mojom::kURLLoadOptionNone;
Makoto Shimazu34ab40c2018-08-23 04:32:03389
390 // Ensure that Mime sniffing works.
391 options |= network::mojom::kURLLoadOptionSniffMimeType;
392
Livvie Lin139bf442018-08-10 00:18:54393 if (is_main_frame) {
394 // SSLInfo is not needed on subframe responses because users can inspect
395 // only the certificate for the main frame when using the info bubble.
396 options |= network::mojom::kURLLoadOptionSendSSLInfoWithResponse;
John Abd-El-Malekb165dc52018-01-18 17:12:18397 options |= network::mojom::kURLLoadOptionSendSSLInfoForCertificateError;
Livvie Lin139bf442018-08-10 00:18:54398 }
arthursonzognib521c6a2018-01-08 12:23:40399
Makoto Shimazu34ab40c2018-08-23 04:32:03400 if (!base::FeatureList::IsEnabled(network::features::kNetworkService)) {
arthursonzognib521c6a2018-01-08 12:23:40401 // TODO(arthursonzogni): This is a temporary option. Remove this as soon
402 // as the InterceptingResourceHandler is removed.
403 // See https://crbug.com/791049.
John Abd-El-Malekb165dc52018-01-18 17:12:18404 options |= network::mojom::kURLLoadOptionPauseOnResponseStarted;
arthursonzognib521c6a2018-01-08 12:23:40405 }
406
407 return options;
408 }
409
Makoto Shimazu44c2c3232018-03-30 01:10:20410 SingleRequestURLLoaderFactory::RequestHandler
411 CreateDefaultRequestHandlerForNonNetworkService(
412 net::URLRequestContextGetter* url_request_context_getter,
413 storage::FileSystemContext* upload_file_system_context,
414 ServiceWorkerNavigationHandleCore* service_worker_navigation_handle_core,
Makoto Shimazu684a5ad2018-05-29 08:20:50415 AppCacheNavigationHandleCore* appcache_handle_core,
416 bool was_request_intercepted) const {
Matt Falkenhagen34739112018-07-17 20:36:33417 DCHECK_CURRENTLY_ON(BrowserThread::IO);
418 DCHECK(!base::FeatureList::IsEnabled(network::features::kNetworkService));
419 DCHECK(started_);
420
Makoto Shimazu44c2c3232018-03-30 01:10:20421 return base::BindOnce(
422 &URLLoaderRequestController::CreateNonNetworkServiceURLLoader,
423 weak_factory_.GetWeakPtr(),
424 base::Unretained(url_request_context_getter),
425 base::Unretained(upload_file_system_context),
426 std::make_unique<NavigationRequestInfo>(*request_info_),
Makoto Shimazu684a5ad2018-05-29 08:20:50427 // If the request has already been intercepted, the request should not
428 // be intercepted again.
429 // S13nServiceWorker: Requests are intercepted by S13nServiceWorker
430 // before the default request handler when needed, so we never need to
431 // pass |service_worker_navigation_handle_core| here.
Han Leonf1525df2018-07-11 03:47:59432 base::Unretained(
433 blink::ServiceWorkerUtils::IsServicificationEnabled() ||
434 was_request_intercepted
435 ? nullptr
436 : service_worker_navigation_handle_core),
Makoto Shimazu684a5ad2018-05-29 08:20:50437 base::Unretained(was_request_intercepted ? nullptr
438 : appcache_handle_core));
Makoto Shimazu44c2c3232018-03-30 01:10:20439 }
440
arthursonzogni2695d04d2017-12-12 08:39:01441 void CreateNonNetworkServiceURLLoader(
442 net::URLRequestContextGetter* url_request_context_getter,
443 storage::FileSystemContext* upload_file_system_context,
444 std::unique_ptr<NavigationRequestInfo> request_info,
arthursonzogni2695d04d2017-12-12 08:39:01445 ServiceWorkerNavigationHandleCore* service_worker_navigation_handle_core,
446 AppCacheNavigationHandleCore* appcache_handle_core,
Matt Falkenhagen43765122018-08-22 19:37:22447 const network::ResourceRequest& /* resource_request */,
John Abd-El-Malekb165dc52018-01-18 17:12:18448 network::mojom::URLLoaderRequest url_loader,
449 network::mojom::URLLoaderClientPtr url_loader_client) {
Matt Falkenhagen43765122018-08-22 19:37:22450 // |resource_request| is unused here. Its info may not be the same as
451 // |request_info|, because URLLoaderThrottles may have rewritten it. We
452 // don't propagate the fields to |request_info| here because the request
453 // will usually go to ResourceDispatcherHost which does its own request
454 // modification independent of URLLoaderThrottles.
Matt Falkenhagen34739112018-07-17 20:36:33455 DCHECK_CURRENTLY_ON(BrowserThread::IO);
456 DCHECK(!base::FeatureList::IsEnabled(network::features::kNetworkService));
457 DCHECK(started_);
Matt Falkenhagend2867e82018-07-04 08:26:38458
Tsuyoshi Horob8d512a2018-01-25 17:01:59459 default_loader_used_ = true;
Tsuyoshi Horo46f5fff2018-05-10 12:33:35460 if (signed_exchange_utils::IsSignedExchangeHandlingEnabled()) {
Matt Falkenhagen43765122018-08-22 19:37:22461 // TODO(falken): Understand and add a comment about why
462 // SignedExchangeRequestHandler is the only interceptor being added here.
Kinuko Yasudabe4ad292018-07-06 01:33:39463 DCHECK(!network_loader_factory_);
Tsuyoshi Horo561163b2018-03-27 03:11:23464 // It is safe to pass the callback of CreateURLLoaderThrottles with the
Tsuyoshi Horo70014ad2018-02-14 11:20:14465 // unretained |this|, because the passed callback will be used by a
466 // SignedExchangeHandler which is indirectly owned by |this| until its
467 // header is verified and parsed, that's where the getter is used.
Kunihiko Sakamotoe6aa22e2018-06-15 03:26:55468 interceptors_.push_back(std::make_unique<SignedExchangeRequestHandler>(
Tsuyoshi Horo70014ad2018-02-14 11:20:14469 url::Origin::Create(request_info->common_params.url),
Tsuyoshi Horo32b51f12018-05-09 17:58:46470 request_info->common_params.url,
Kinuko Yasuda32a25652018-02-19 08:14:25471 GetURLLoaderOptions(request_info->is_main_frame),
Tsuyoshi Horocdbb4902018-04-12 06:09:14472 request_info->frame_tree_node_id,
Tsuyoshi Horo32b51f12018-05-09 17:58:46473 request_info->devtools_navigation_token,
Tsuyoshi Horob8d381182018-06-19 10:07:29474 request_info->devtools_frame_token, request_info->report_raw_headers,
Tsuyoshi Horo6e6782d2018-06-07 02:32:47475 request_info->begin_params->load_flags,
Tsuyoshi Horo70014ad2018-02-14 11:20:14476 base::MakeRefCounted<
477 SignedExchangeURLLoaderFactoryForNonNetworkService>(
478 resource_context_, url_request_context_getter),
479 base::BindRepeating(
480 &URLLoaderRequestController::CreateURLLoaderThrottles,
John Abd-El-Malek9ee2a712018-08-24 19:50:45481 base::Unretained(this))));
Tsuyoshi Horob8d512a2018-01-25 17:01:59482 }
483
John Abd-El-Malekdb3a13b2018-05-01 17:52:02484 uint32_t options = GetURLLoaderOptions(request_info->is_main_frame);
485
486 bool intercepted = false;
487 if (g_interceptor.Get()) {
488 intercepted = g_interceptor.Get().Run(
489 &url_loader, frame_tree_node_id_, 0 /* request_id */, options,
490 *resource_request_.get(), &url_loader_client,
491 net::MutableNetworkTrafficAnnotationTag(
492 kNavigationUrlLoaderTrafficAnnotation));
493 }
494
arthursonzogni2695d04d2017-12-12 08:39:01495 // The ResourceDispatcherHostImpl can be null in unit tests.
John Abd-El-Malekdb3a13b2018-05-01 17:52:02496 if (!intercepted && ResourceDispatcherHostImpl::Get()) {
arthursonzogni2695d04d2017-12-12 08:39:01497 ResourceDispatcherHostImpl::Get()->BeginNavigationRequest(
498 resource_context_, url_request_context_getter->GetURLRequestContext(),
499 upload_file_system_context, *request_info,
arthursonzogni662d723c2018-04-24 16:13:22500 std::move(navigation_ui_data_), std::move(url_loader_client),
arthursonzogni2695d04d2017-12-12 08:39:01501 std::move(url_loader), service_worker_navigation_handle_core,
Makoto Shimazuff60c1412018-06-19 06:17:33502 appcache_handle_core, options, global_request_id_);
arthursonzogni2695d04d2017-12-12 08:39:01503 }
504
505 // TODO(arthursonzogni): Detect when the ResourceDispatcherHost didn't
506 // create a URLLoader. When it doesn't, do not send OnRequestStarted().
Eric Seckler8652dcd52018-09-20 10:42:28507 base::PostTaskWithTraits(
508 FROM_HERE, {BrowserThread::UI},
arthursonzogni1fd60e62018-05-09 15:57:32509 base::BindOnce(&NavigationURLLoaderImpl::OnRequestStarted, owner_,
510 base::TimeTicks::Now()));
arthursonzogni2695d04d2017-12-12 08:39:01511 }
512
513 // TODO(arthursonzogni): See if this could eventually be unified with Start().
514 void StartWithoutNetworkService(
515 net::URLRequestContextGetter* url_request_context_getter,
516 storage::FileSystemContext* upload_file_system_context,
517 ServiceWorkerNavigationHandleCore* service_worker_navigation_handle_core,
518 AppCacheNavigationHandleCore* appcache_handle_core,
519 std::unique_ptr<NavigationRequestInfo> request_info,
520 std::unique_ptr<NavigationUIData> navigation_ui_data) {
Matt Falkenhagen34739112018-07-17 20:36:33521 DCHECK_CURRENTLY_ON(BrowserThread::IO);
522 DCHECK(!base::FeatureList::IsEnabled(network::features::kNetworkService));
523 DCHECK(!started_);
arthursonzogni2695d04d2017-12-12 08:39:01524 started_ = true;
Makoto Shimazu44c2c3232018-03-30 01:10:20525 request_info_ = std::move(request_info);
526 frame_tree_node_id_ = request_info_->frame_tree_node_id;
Yuzhu Shencb3011f62018-02-08 02:51:50527 web_contents_getter_ = base::BindRepeating(
Yuzhu Shen9508fc72018-02-08 23:18:59528 &GetWebContentsFromFrameTreeNodeID, frame_tree_node_id_);
Makoto Shimazu44c2c3232018-03-30 01:10:20529 navigation_ui_data_ = std::move(navigation_ui_data);
Makoto Shimazuff60c1412018-06-19 06:17:33530 // The ResourceDispatcherHostImpl can be null in unit tests.
531 ResourceDispatcherHostImpl* rph = ResourceDispatcherHostImpl::Get();
532 if (rph)
533 global_request_id_ = rph->MakeGlobalRequestID();
534
Makoto Shimazu44c2c3232018-03-30 01:10:20535 default_request_handler_factory_ = base::BindRepeating(
536 &URLLoaderRequestController::
537 CreateDefaultRequestHandlerForNonNetworkService,
538 // base::Unretained(this) is safe since
539 // |default_request_handler_factory_| could be called only from |this|.
540 base::Unretained(this), base::Unretained(url_request_context_getter),
541 base::Unretained(upload_file_system_context),
arthursonzogni2695d04d2017-12-12 08:39:01542 base::Unretained(service_worker_navigation_handle_core),
543 base::Unretained(appcache_handle_core));
544
Marijn Kruisselbrink8a7fd102018-06-05 17:30:39545 // Requests to Blob scheme won't get redirected to/from other schemes
546 // or be intercepted, so we just let it go here.
547 if (request_info_->common_params.url.SchemeIsBlob() &&
548 request_info_->blob_url_loader_factory) {
549 url_loader_ = ThrottlingURLLoader::CreateLoaderAndStart(
550 network::SharedURLLoaderFactory::Create(
551 std::move(request_info_->blob_url_loader_factory)),
552 CreateURLLoaderThrottles(), -1 /* routing_id */, 0 /* request_id? */,
553 network::mojom::kURLLoadOptionNone, resource_request_.get(), this,
554 kNavigationUrlLoaderTrafficAnnotation,
555 base::ThreadTaskRunnerHandle::Get());
556 return;
557 }
558
Makoto Shimazu44c2c3232018-03-30 01:10:20559 // If S13nServiceWorker is disabled, just use
560 // |default_request_handler_factory_| and return. The non network service
561 // request handling goes through ResourceDispatcherHost which has legacy
562 // hooks for service worker (ServiceWorkerRequestInterceptor), so no service
563 // worker interception is needed here.
Han Leonf1525df2018-07-11 03:47:59564 if (!blink::ServiceWorkerUtils::IsServicificationEnabled() ||
Makoto Shimazu44c2c3232018-03-30 01:10:20565 !service_worker_navigation_handle_core) {
566 url_loader_ = ThrottlingURLLoader::CreateLoaderAndStart(
567 base::MakeRefCounted<SingleRequestURLLoaderFactory>(
Makoto Shimazu684a5ad2018-05-29 08:20:50568 default_request_handler_factory_.Run(
569 false /* was_request_intercepted */)),
Makoto Shimazu44c2c3232018-03-30 01:10:20570 CreateURLLoaderThrottles(), -1 /* routing_id */, 0 /* request_id */,
571 network::mojom::kURLLoadOptionNone, resource_request_.get(),
572 this /* client */, kNavigationUrlLoaderTrafficAnnotation,
573 base::ThreadTaskRunnerHandle::Get());
574 return;
575 }
576
577 // Otherwise, if S13nServiceWorker is enabled, create an interceptor so
578 // S13nServiceWorker has a chance to intercept the request.
579 std::unique_ptr<NavigationLoaderInterceptor> service_worker_interceptor =
580 CreateServiceWorkerInterceptor(*request_info_,
581 service_worker_navigation_handle_core);
582 // If an interceptor is not created for some reasons (e.g. the origin is not
583 // secure), we no longer have to go through the rest of the network service
584 // code.
585 if (!service_worker_interceptor) {
586 url_loader_ = ThrottlingURLLoader::CreateLoaderAndStart(
587 base::MakeRefCounted<SingleRequestURLLoaderFactory>(
Makoto Shimazu684a5ad2018-05-29 08:20:50588 default_request_handler_factory_.Run(
589 false /* was_request_intercepted */)),
Makoto Shimazu44c2c3232018-03-30 01:10:20590 CreateURLLoaderThrottles(), -1 /* routing_id */, 0 /* request_id */,
591 network::mojom::kURLLoadOptionNone, resource_request_.get(),
592 this /* client */, kNavigationUrlLoaderTrafficAnnotation,
593 base::ThreadTaskRunnerHandle::Get());
594 return;
595 }
596
597 interceptors_.push_back(std::move(service_worker_interceptor));
598
Makoto Shimazu44c2c3232018-03-30 01:10:20599 Restart();
arthursonzogni2695d04d2017-12-12 08:39:01600 }
601
kinuko69732972017-05-29 08:50:07602 void Start(
Kinuko Yasudabe4ad292018-07-06 01:33:39603 std::unique_ptr<network::SharedURLLoaderFactoryInfo>
604 network_loader_factory_info,
kinuko69732972017-05-29 08:50:07605 ServiceWorkerNavigationHandleCore* service_worker_navigation_handle_core,
606 AppCacheNavigationHandleCore* appcache_handle_core,
607 std::unique_ptr<NavigationRequestInfo> request_info,
John Abd-El-Malekeb1a5382018-01-05 16:58:00608 std::unique_ptr<NavigationUIData> navigation_ui_data,
John Abd-El-Malekb165dc52018-01-18 17:12:18609 network::mojom::URLLoaderFactoryPtrInfo factory_for_webui,
John Abd-El-Malek576c6132017-11-04 00:33:58610 int frame_tree_node_id,
kinuko69732972017-05-29 08:50:07611 std::unique_ptr<service_manager::Connector> connector) {
Matt Falkenhagen34739112018-07-17 20:36:33612 DCHECK_CURRENTLY_ON(BrowserThread::IO);
613 DCHECK(base::FeatureList::IsEnabled(network::features::kNetworkService));
614 DCHECK(!started_);
arthursonzogni40db5f52018-01-08 16:38:49615 global_request_id_ = MakeGlobalRequestID();
John Abd-El-Malek576c6132017-11-04 00:33:58616 frame_tree_node_id_ = frame_tree_node_id;
Alex Clarke1e08882b32017-10-06 14:22:40617 started_ = true;
John Abd-El-Malek576c6132017-11-04 00:33:58618 web_contents_getter_ =
619 base::Bind(&GetWebContentsFromFrameTreeNodeID, frame_tree_node_id);
John Abd-El-Malekeb1a5382018-01-05 16:58:00620 navigation_ui_data_ = std::move(navigation_ui_data);
kinuko69732972017-05-29 08:50:07621
Kinuko Yasudabe4ad292018-07-06 01:33:39622 DCHECK(network_loader_factory_info);
623 network_loader_factory_ = network::SharedURLLoaderFactory::Create(
624 std::move(network_loader_factory_info));
625
kinuko69732972017-05-29 08:50:07626 if (resource_request_->request_body) {
mmenkeed44e6c2017-06-28 21:13:32627 GetBodyBlobDataHandles(resource_request_->request_body.get(),
628 resource_context_, &blob_handles_);
kinuko69732972017-05-29 08:50:07629 }
630
631 // Requests to WebUI scheme won't get redirected to/from other schemes
632 // or be intercepted, so we just let it go here.
633 if (factory_for_webui.is_valid()) {
yzshenefcb7c72017-06-16 23:12:30634 url_loader_ = ThrottlingURLLoader::CreateLoaderAndStart(
Antonio Gomes9cdc09a2018-05-07 23:24:26635 base::MakeRefCounted<network::WrapperSharedURLLoaderFactory>(
Yuzhu Shend87986f2018-01-17 22:16:37636 std::move(factory_for_webui)),
Ken Rockot5f734e32018-06-13 01:41:03637 CreateURLLoaderThrottles(), 0 /* routing_id */,
638 global_request_id_.request_id, network::mojom::kURLLoadOptionNone,
639 resource_request_.get(), this, kNavigationUrlLoaderTrafficAnnotation,
Hajime Hoshif5ef35262017-11-28 19:13:00640 base::ThreadTaskRunnerHandle::Get());
kinuko69732972017-05-29 08:50:07641 return;
642 }
643
Marijn Kruisselbrink07bf59d52018-04-03 21:50:25644 // Requests to Blob scheme won't get redirected to/from other schemes
645 // or be intercepted, so we just let it go here.
646 if (request_info->common_params.url.SchemeIsBlob() &&
647 request_info->blob_url_loader_factory) {
648 url_loader_ = ThrottlingURLLoader::CreateLoaderAndStart(
649 network::SharedURLLoaderFactory::Create(
650 std::move(request_info->blob_url_loader_factory)),
Ken Rockot5f734e32018-06-13 01:41:03651 CreateURLLoaderThrottles(), 0 /* routing_id */,
652 global_request_id_.request_id, network::mojom::kURLLoadOptionNone,
653 resource_request_.get(), this, kNavigationUrlLoaderTrafficAnnotation,
Marijn Kruisselbrink07bf59d52018-04-03 21:50:25654 base::ThreadTaskRunnerHandle::Get());
655 return;
656 }
657
kinuko69732972017-05-29 08:50:07658 if (service_worker_navigation_handle_core) {
Kinuko Yasuda7f3e1722018-03-26 08:58:58659 std::unique_ptr<NavigationLoaderInterceptor> service_worker_interceptor =
Makoto Shimazu44c2c3232018-03-30 01:10:20660 CreateServiceWorkerInterceptor(*request_info,
661 service_worker_navigation_handle_core);
Kinuko Yasuda7f3e1722018-03-26 08:58:58662 if (service_worker_interceptor)
663 interceptors_.push_back(std::move(service_worker_interceptor));
kinuko69732972017-05-29 08:50:07664 }
665
666 if (appcache_handle_core) {
Kinuko Yasuda7f3e1722018-03-26 08:58:58667 std::unique_ptr<NavigationLoaderInterceptor> appcache_interceptor =
Hiroki Nakagawaff43e4472018-07-26 07:06:46668 AppCacheRequestHandler::InitializeForMainResourceNetworkService(
669 *resource_request_, appcache_handle_core->host()->GetWeakPtr(),
Kinuko Yasudabe4ad292018-07-06 01:33:39670 network_loader_factory_);
Kinuko Yasuda7f3e1722018-03-26 08:58:58671 if (appcache_interceptor)
672 interceptors_.push_back(std::move(appcache_interceptor));
kinuko69732972017-05-29 08:50:07673 }
674
Tsuyoshi Horo46f5fff2018-05-10 12:33:35675 if (signed_exchange_utils::IsSignedExchangeHandlingEnabled()) {
Kunihiko Sakamotoe9a0502c2018-06-06 09:29:51676 // Signed Exchange is currently disabled when Network Service is enabled
Kunihiko Sakamotoe6aa22e2018-06-15 03:26:55677 // (https://crbug.com/849935), but still create
678 // SignedExchangeRequestHandler in order to show error message (and
679 // devtools warning) to users.
Kunihiko Sakamotoe9a0502c2018-06-06 09:29:51680
Tsuyoshi Horo561163b2018-03-27 03:11:23681 // It is safe to pass the callback of CreateURLLoaderThrottles with the
Tsuyoshi Horo70014ad2018-02-14 11:20:14682 // unretained |this|, because the passed callback will be used by a
683 // SignedExchangeHandler which is indirectly owned by |this| until its
684 // header is verified and parsed, that's where the getter is used.
Kunihiko Sakamotoe6aa22e2018-06-15 03:26:55685 interceptors_.push_back(std::make_unique<SignedExchangeRequestHandler>(
Tsuyoshi Horo70014ad2018-02-14 11:20:14686 url::Origin::Create(request_info->common_params.url),
Tsuyoshi Horo32b51f12018-05-09 17:58:46687 request_info->common_params.url,
Kinuko Yasuda32a25652018-02-19 08:14:25688 GetURLLoaderOptions(request_info->is_main_frame),
Tsuyoshi Horocdbb4902018-04-12 06:09:14689 request_info->frame_tree_node_id,
Tsuyoshi Horo32b51f12018-05-09 17:58:46690 request_info->devtools_navigation_token,
Tsuyoshi Horob8d381182018-06-19 10:07:29691 request_info->devtools_frame_token, request_info->report_raw_headers,
Kinuko Yasudabe4ad292018-07-06 01:33:39692 request_info->begin_params->load_flags, network_loader_factory_,
Tsuyoshi Horo70014ad2018-02-14 11:20:14693 base::BindRepeating(
694 &URLLoaderRequestController::CreateURLLoaderThrottles,
John Abd-El-Malek9ee2a712018-08-24 19:50:45695 base::Unretained(this))));
Tsuyoshi Horob8d512a2018-01-25 17:01:59696 }
697
Jian Li18e29242018-05-10 22:25:12698 std::vector<std::unique_ptr<URLLoaderRequestInterceptor>>
699 browser_interceptors = GetContentClient()
700 ->browser()
701 ->WillCreateURLLoaderRequestInterceptors(
702 navigation_ui_data_.get(),
703 request_info->frame_tree_node_id);
704 if (!browser_interceptors.empty()) {
705 for (auto& browser_interceptor : browser_interceptors) {
706 interceptors_.push_back(
707 std::make_unique<NavigationLoaderInterceptorBrowserContainer>(
708 std::move(browser_interceptor)));
709 }
710 }
711
yzshenefcb7c72017-06-16 23:12:30712 Restart();
kinuko69732972017-05-29 08:50:07713 }
714
Michael Nordman2431f5f2017-09-13 04:58:15715 // This could be called multiple times to follow a chain of redirects.
yzshenefcb7c72017-06-16 23:12:30716 void Restart() {
Kinuko Yasuda7f3e1722018-03-26 08:58:58717 DCHECK(IsLoaderInterceptionEnabled());
Tsuyoshi Horo5204c872017-09-21 16:28:17718 // Clear |url_loader_| if it's not the default one (network). This allows
719 // the restarted request to use a new loader, instead of, e.g., reusing the
720 // AppCache or service worker loader. For an optimization, we keep and reuse
Kinuko Yasuda7f3e1722018-03-26 08:58:58721 // the default url loader if the all |interceptors_| doesn't handle the
Clark DuVallbf7722f2018-08-03 18:03:33722 // redirected request. If the network service is enabled, only certain
723 // schemes are handled by the default URL loader. We need to make sure the
724 // redirected URL is a handled scheme, otherwise reset the loader so the
725 // correct non-network service loader can be used.
726 if (!default_loader_used_ ||
727 (base::FeatureList::IsEnabled(network::features::kNetworkService) &&
728 !IsURLHandledByDefaultLoader(resource_request_->url))) {
Tsuyoshi Horo5204c872017-09-21 16:28:17729 url_loader_.reset();
Clark DuVallbf7722f2018-08-03 18:03:33730 }
Kinuko Yasuda7f3e1722018-03-26 08:58:58731 interceptor_index_ = 0;
anantab9800e52017-07-29 18:04:13732 received_response_ = false;
Kinuko Yasuda7f3e1722018-03-26 08:58:58733 MaybeStartLoader(nullptr /* interceptor */,
734 {} /* single_request_handler */);
kinuko69732972017-05-29 08:50:07735 }
736
Kinuko Yasuda7f3e1722018-03-26 08:58:58737 // |interceptor| is non-null if this is called by one of the interceptors
738 // (via a LoaderCallback).
739 // |single_request_handler| is the RequestHandler given by the |interceptor|,
740 // non-null if the interceptor wants to handle the request.
Ken Rockot387ddd5a2018-01-30 19:18:40741 void MaybeStartLoader(
Kinuko Yasuda7f3e1722018-03-26 08:58:58742 NavigationLoaderInterceptor* interceptor,
Ken Rockot387ddd5a2018-01-30 19:18:40743 SingleRequestURLLoaderFactory::RequestHandler single_request_handler) {
Matt Falkenhagen34739112018-07-17 20:36:33744 DCHECK_CURRENTLY_ON(BrowserThread::IO);
745 DCHECK(IsLoaderInterceptionEnabled());
746 DCHECK(started_);
747
Ken Rockot387ddd5a2018-01-30 19:18:40748 if (single_request_handler) {
Kinuko Yasuda7f3e1722018-03-26 08:58:58749 // |interceptor| wants to handle the request with
750 // |single_request_handler|.
751 DCHECK(interceptor);
Matt Falkenhagen43765122018-08-22 19:37:22752
753 std::vector<std::unique_ptr<URLLoaderThrottle>> throttles =
Makoto Shimazu21950e82018-08-02 12:37:14754 CreateURLLoaderThrottles();
Matt Falkenhagen43765122018-08-22 19:37:22755 // Intercepted requests need MimeSniffingThrottle to do mime sniffing.
756 // Non-intercepted requests usually go through the regular network
757 // URLLoader, which does mime sniffing.
Makoto Shimazu21950e82018-08-02 12:37:14758 throttles.push_back(std::make_unique<MimeSniffingThrottle>());
Matt Falkenhagen43765122018-08-22 19:37:22759
Michael Nordman2431f5f2017-09-13 04:58:15760 default_loader_used_ = false;
yzshenefcb7c72017-06-16 23:12:30761 url_loader_ = ThrottlingURLLoader::CreateLoaderAndStart(
Ken Rockot387ddd5a2018-01-30 19:18:40762 base::MakeRefCounted<SingleRequestURLLoaderFactory>(
763 std::move(single_request_handler)),
Makoto Shimazu21950e82018-08-02 12:37:14764 std::move(throttles), frame_tree_node_id_,
Ken Rockot5f734e32018-06-13 01:41:03765 global_request_id_.request_id, network::mojom::kURLLoadOptionNone,
766 resource_request_.get(), this, kNavigationUrlLoaderTrafficAnnotation,
Hajime Hoshif5ef35262017-11-28 19:13:00767 base::ThreadTaskRunnerHandle::Get());
anantae60d1d42017-06-20 04:16:27768
Kinuko Yasuda250577c2017-10-29 02:51:24769 subresource_loader_params_ =
Kinuko Yasuda7f3e1722018-03-26 08:58:58770 interceptor->MaybeCreateSubresourceLoaderParams();
Kinuko Yasuda8757204a2017-11-04 07:50:13771
kinuko69732972017-05-29 08:50:07772 return;
773 }
774
Kinuko Yasuda7f3e1722018-03-26 08:58:58775 // Before falling back to the next interceptor, see if |interceptor| still
776 // wants to give additional info to the frame for subresource loading. In
777 // that case we will just fall back to the default loader (i.e. won't go on
778 // to the next interceptors) but send the subresource_loader_params to the
779 // child process. This is necessary for correctness in the cases where, e.g.
Matt Falkenhagen43765122018-08-22 19:37:22780 // there's a controlling service worker that doesn't have a fetch event
781 // handler so it doesn't intercept requests. In that case we still want to
782 // skip AppCache.
Kinuko Yasuda7f3e1722018-03-26 08:58:58783 if (interceptor) {
Kinuko Yasuda8757204a2017-11-04 07:50:13784 subresource_loader_params_ =
Kinuko Yasuda7f3e1722018-03-26 08:58:58785 interceptor->MaybeCreateSubresourceLoaderParams();
Kinuko Yasuda8757204a2017-11-04 07:50:13786
787 // If non-null |subresource_loader_params_| is returned, make sure
Kinuko Yasuda7f3e1722018-03-26 08:58:58788 // we skip the next interceptors.
Kinuko Yasuda8757204a2017-11-04 07:50:13789 if (subresource_loader_params_)
Kinuko Yasuda7f3e1722018-03-26 08:58:58790 interceptor_index_ = interceptors_.size();
Kinuko Yasuda8757204a2017-11-04 07:50:13791 }
792
Kinuko Yasuda7f3e1722018-03-26 08:58:58793 // See if the next interceptor wants to handle the request.
794 if (interceptor_index_ < interceptors_.size()) {
795 auto* next_interceptor = interceptors_[interceptor_index_++].get();
796 next_interceptor->MaybeCreateLoader(
kinuko69732972017-05-29 08:50:07797 *resource_request_, resource_context_,
798 base::BindOnce(&URLLoaderRequestController::MaybeStartLoader,
Matt Falkenhagen43765122018-08-22 19:37:22799 base::Unretained(this), next_interceptor),
800 base::BindOnce(
801 &URLLoaderRequestController::FallbackToNonInterceptedRequest,
802 base::Unretained(this)));
kinuko69732972017-05-29 08:50:07803 return;
804 }
805
Matt Falkenhagen43765122018-08-22 19:37:22806 // If we already have the default |url_loader_| we must come here after a
Matt Falkenhagencc3e7e52018-08-28 06:23:48807 // redirect. No interceptors wanted to intercept the redirected request, so
Matt Falkenhagen43765122018-08-22 19:37:22808 // let the loader just follow the redirect.
Michael Nordman2431f5f2017-09-13 04:58:15809 if (url_loader_) {
810 DCHECK(!redirect_info_.new_url.is_empty());
Chong Zhang7607f1f2018-06-01 20:52:20811 url_loader_->FollowRedirect(
812 std::move(url_loader_modified_request_headers_));
Michael Nordman2431f5f2017-09-13 04:58:15813 return;
814 }
815
Matt Falkenhagen43765122018-08-22 19:37:22816 // No interceptors wanted to handle this request.
Matt Falkenhagencc3e7e52018-08-28 06:23:48817 uint32_t options = network::mojom::kURLLoadOptionNone;
818 scoped_refptr<network::SharedURLLoaderFactory> factory =
819 PrepareForNonInterceptedRequest(&options);
820 url_loader_ = ThrottlingURLLoader::CreateLoaderAndStart(
821 std::move(factory), CreateURLLoaderThrottles(), frame_tree_node_id_,
822 global_request_id_.request_id, options, resource_request_.get(),
823 this /* client */, kNavigationUrlLoaderTrafficAnnotation,
824 base::ThreadTaskRunnerHandle::Get());
Matt Falkenhagen43765122018-08-22 19:37:22825 }
Makoto Shimazu44c2c3232018-03-30 01:10:20826
Matt Falkenhagen43765122018-08-22 19:37:22827 // This is the |fallback_callback| passed to
828 // NavigationLoaderInterceptor::MaybeCreateLoader. It allows an interceptor
829 // to initially elect to handle a request, and later decide to fallback to
830 // the default behavior. This is needed for service worker network fallback.
831 void FallbackToNonInterceptedRequest(bool reset_subresource_loader_params) {
832 if (reset_subresource_loader_params)
833 subresource_loader_params_.reset();
834
Matt Falkenhagencc3e7e52018-08-28 06:23:48835 // Non-NetworkService:
836 // Cancel state on ResourceDispatcherHostImpl so it doesn't complain about
837 // reusing the request_id after redirects. Otherwise the following sequence
838 // can happen:
839 // RDHI Start(request_id) -> Redirect -> SW interception -> SW fallback to
840 // network -> RDHI Start(request_id).
841 if (!base::FeatureList::IsEnabled(network::features::kNetworkService)) {
842 DCHECK(ResourceDispatcherHostImpl::Get());
843 ResourceDispatcherHostImpl::Get()->CancelRequest(
844 global_request_id_.child_id, global_request_id_.request_id);
Matt Falkenhagen43765122018-08-22 19:37:22845 }
846
Matt Falkenhagencc3e7e52018-08-28 06:23:48847 // |url_loader_| is using the factory for the interceptor that decided to
848 // fallback, so restart it with the non-interceptor factory.
849 DCHECK(url_loader_);
850 uint32_t options = network::mojom::kURLLoadOptionNone;
851 scoped_refptr<network::SharedURLLoaderFactory> factory =
852 PrepareForNonInterceptedRequest(&options);
853 url_loader_->RestartWithFactory(std::move(factory), options);
Matt Falkenhagen43765122018-08-22 19:37:22854 }
855
Matt Falkenhagencc3e7e52018-08-28 06:23:48856 scoped_refptr<network::SharedURLLoaderFactory>
857 PrepareForNonInterceptedRequest(uint32_t* out_options) {
Makoto Shimazu44c2c3232018-03-30 01:10:20858 // If NetworkService is not enabled (which means we come here because one of
859 // the loader interceptors is enabled), use the default request handler
860 // instead of going through the NetworkService path.
861 if (!base::FeatureList::IsEnabled(network::features::kNetworkService)) {
862 DCHECK(!interceptors_.empty());
863 DCHECK(default_request_handler_factory_);
Kunihiko Sakamoto21ab4ad262018-08-21 10:26:21864 // The only way to come here is to enable ServiceWorkerServicification or
865 // SignedExchange without NetworkService. We know that their request
866 // interceptors have already intercepted and decided not to handle the
Makoto Shimazu684a5ad2018-05-29 08:20:50867 // request.
Kunihiko Sakamoto21ab4ad262018-08-21 10:26:21868 DCHECK(blink::ServiceWorkerUtils::IsServicificationEnabled() ||
869 signed_exchange_utils::IsSignedExchangeHandlingEnabled());
Makoto Shimazu44c2c3232018-03-30 01:10:20870 default_loader_used_ = true;
871 // Update |request_info_| when following a redirect.
872 if (url_chain_.size() > 0) {
873 request_info_ = CreateNavigationRequestInfoForRedirect(
874 *request_info_, *resource_request_);
875 }
Matt Falkenhagen43765122018-08-22 19:37:22876
Makoto Shimazu684a5ad2018-05-29 08:20:50877 // When |subresource_loader_params_| has its value, the request should not
878 // be intercepted by any other interceptors since it means that a request
879 // interceptor already intercepted the request and it attached its info to
880 // the request.
Matt Falkenhagen43765122018-08-22 19:37:22881 bool was_request_intercepted = subresource_loader_params_.has_value();
882
Matt Falkenhagencc3e7e52018-08-28 06:23:48883 // TODO(falken): Determine whether GetURLLoaderOptions() can be called
884 // here like below. It looks like |default_request_handler_factory_| just
885 // calls that.
886 *out_options = network::mojom::kURLLoadOptionNone;
887 return base::MakeRefCounted<SingleRequestURLLoaderFactory>(
888 default_request_handler_factory_.Run(was_request_intercepted));
Makoto Shimazu44c2c3232018-03-30 01:10:20889 }
890
Matt Falkenhagen43765122018-08-22 19:37:22891 // TODO(https://crbug.com/796425): We temporarily wrap raw
892 // mojom::URLLoaderFactory pointers into SharedURLLoaderFactory. Need to
893 // further refactor the factory getters to avoid this.
894 scoped_refptr<network::SharedURLLoaderFactory> factory;
895
Clark DuVallbf7722f2018-08-03 18:03:33896 if (!IsURLHandledByDefaultLoader(resource_request_->url)) {
John Abd-El-Maleka67add82018-03-09 18:22:01897 if (known_schemes_.find(resource_request_->url.scheme()) ==
898 known_schemes_.end()) {
899 bool handled = GetContentClient()->browser()->HandleExternalProtocol(
900 resource_request_->url, web_contents_getter_,
901 ChildProcessHost::kInvalidUniqueID, navigation_ui_data_.get(),
902 resource_request_->resource_type == RESOURCE_TYPE_MAIN_FRAME,
903 static_cast<ui::PageTransition>(resource_request_->transition_type),
904 resource_request_->has_user_gesture);
905 factory = base::MakeRefCounted<SingleRequestURLLoaderFactory>(
906 base::BindOnce(UnknownSchemeCallback, handled));
907 } else {
908 network::mojom::URLLoaderFactoryPtr& non_network_factory =
909 non_network_url_loader_factories_[resource_request_->url.scheme()];
910 if (!non_network_factory.is_bound()) {
Eric Seckler8652dcd52018-09-20 10:42:28911 base::PostTaskWithTraits(
912 FROM_HERE, {BrowserThread::UI},
arthursonzogni1fd60e62018-05-09 15:57:32913 base::BindOnce(&NavigationURLLoaderImpl ::
John Abd-El-Maleka67add82018-03-09 18:22:01914 BindNonNetworkURLLoaderFactoryRequest,
915 owner_, frame_tree_node_id_,
916 resource_request_->url,
917 mojo::MakeRequest(&non_network_factory)));
918 }
Antonio Gomes9cdc09a2018-05-07 23:24:26919 factory =
920 base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
921 non_network_factory.get());
Ken Rockot314714c2017-11-05 23:36:24922 }
jam9354af82017-06-03 21:59:41923 } else {
anantab9800e52017-07-29 18:04:13924 default_loader_used_ = true;
Ken Rockota0dfaca12018-02-15 07:26:25925
926 // NOTE: We only support embedders proxying network-service-bound requests
Kinuko Yasuda7f3e1722018-03-26 08:58:58927 // not handled by NavigationLoaderInterceptors above (e.g. Service Worker
928 // or AppCache). Hence this code is only reachable when one of the above
929 // interceptors isn't used and the URL is either a data URL or has a
930 // scheme which is handled by the network service. We explicitly avoid
931 // proxying the data URL case here.
Ken Rockota0dfaca12018-02-15 07:26:25932 if (proxied_factory_request_.is_pending() &&
933 !resource_request_->url.SchemeIs(url::kDataScheme)) {
934 DCHECK(proxied_factory_info_.is_valid());
Chong Zhang70432e32018-03-07 04:43:52935 // We don't worry about reconnection since it's a single navigation.
Kinuko Yasudabe4ad292018-07-06 01:33:39936 network_loader_factory_->Clone(std::move(proxied_factory_request_));
Antonio Gomes9cdc09a2018-05-07 23:24:26937 factory = base::MakeRefCounted<network::WrapperSharedURLLoaderFactory>(
Ken Rockota0dfaca12018-02-15 07:26:25938 std::move(proxied_factory_info_));
939 } else {
Kinuko Yasudabe4ad292018-07-06 01:33:39940 factory = network_loader_factory_;
Ken Rockota0dfaca12018-02-15 07:26:25941 }
jam9354af82017-06-03 21:59:41942 }
Min Qin83d07872017-10-26 23:22:41943 url_chain_.push_back(resource_request_->url);
Matt Falkenhagencc3e7e52018-08-28 06:23:48944 *out_options = GetURLLoaderOptions(resource_request_->resource_type ==
945 RESOURCE_TYPE_MAIN_FRAME);
946 return factory;
kinuko69732972017-05-29 08:50:07947 }
948
Chong Zhang7607f1f2018-06-01 20:52:20949 void FollowRedirect(
950 const base::Optional<net::HttpRequestHeaders>& modified_request_headers) {
yzshenefcb7c72017-06-16 23:12:30951 DCHECK_CURRENTLY_ON(BrowserThread::IO);
Michael Nordman2431f5f2017-09-13 04:58:15952 DCHECK(!redirect_info_.new_url.is_empty());
arthursonzogni2695d04d2017-12-12 08:39:01953
Kinuko Yasuda7f3e1722018-03-26 08:58:58954 if (!IsLoaderInterceptionEnabled()) {
Chong Zhang7607f1f2018-06-01 20:52:20955 url_loader_->FollowRedirect(modified_request_headers);
arthursonzogni2695d04d2017-12-12 08:39:01956 return;
957 }
anantab9800e52017-07-29 18:04:13958
Kinuko Yasuda7f3e1722018-03-26 08:58:58959 // Update |resource_request_| and call Restart to give our |interceptors_| a
960 // chance at handling the new location. If no interceptor wants to take
961 // over, we'll use the existing url_loader to follow the redirect, see
962 // MaybeStartLoader.
Michael Nordman2431f5f2017-09-13 04:58:15963 // TODO(michaeln): This is still WIP and is based on URLRequest::Redirect,
964 // there likely remains more to be done.
965 // a. For subframe navigations, the Origin header may need to be modified
966 // differently?
967 // b. How should redirect_info_.referred_token_binding_host be handled?
Michael Nordman2431f5f2017-09-13 04:58:15968
Tsuyoshi Horo9e2ec4df2017-10-16 15:15:55969 bool should_clear_upload = false;
970 net::RedirectUtil::UpdateHttpRequest(
971 resource_request_->url, resource_request_->method, redirect_info_,
Chong Zhang7607f1f2018-06-01 20:52:20972 modified_request_headers, &resource_request_->headers,
973 &should_clear_upload);
Tsuyoshi Horo9e2ec4df2017-10-16 15:15:55974 if (should_clear_upload) {
Michael Nordman2431f5f2017-09-13 04:58:15975 // The request body is no longer applicable.
976 resource_request_->request_body = nullptr;
977 blob_handles_.clear();
978 }
979
Michael Nordman2431f5f2017-09-13 04:58:15980 resource_request_->url = redirect_info_.new_url;
Tsuyoshi Horo9e2ec4df2017-10-16 15:15:55981 resource_request_->method = redirect_info_.new_method;
Michael Nordman2431f5f2017-09-13 04:58:15982 resource_request_->site_for_cookies = redirect_info_.new_site_for_cookies;
983 resource_request_->referrer = GURL(redirect_info_.new_referrer);
John Abd-El-Malekb77d22fb72017-12-22 17:34:48984 resource_request_->referrer_policy = redirect_info_.new_referrer_policy;
Min Qin83d07872017-10-26 23:22:41985 url_chain_.push_back(redirect_info_.new_url);
Michael Nordman2431f5f2017-09-13 04:58:15986
Chong Zhang7607f1f2018-06-01 20:52:20987 // Need to cache modified headers for |url_loader_| since it doesn't use
988 // |resource_request_| during redirect.
989 url_loader_modified_request_headers_ = modified_request_headers;
990
Michael Nordman2431f5f2017-09-13 04:58:15991 Restart();
yzshenefcb7c72017-06-16 23:12:30992 }
993
Kinuko Yasuda250577c2017-10-29 02:51:24994 base::Optional<SubresourceLoaderParams> TakeSubresourceLoaderParams() {
995 return std::move(subresource_loader_params_);
anantae60d1d42017-06-20 04:16:27996 }
997
kinuko69732972017-05-29 08:50:07998 private:
John Abd-El-Malekb165dc52018-01-18 17:12:18999 // network::mojom::URLLoaderClient implementation:
Marijn Kruisselbrink9ebd7ba2018-06-11 23:18:041000 void OnReceiveResponse(const network::ResourceResponseHead& head) override {
Matt Menked9cad562018-08-10 21:47:091001 // Record the SCT histogram before checking if anything wants to intercept
1002 // the response, so interceptors like AppCache and extensions can't hide
1003 // values from the histograms.
1004 RecordSCTHistogramIfNeeded(head.ssl_info);
1005
anantab9800e52017-07-29 18:04:131006 received_response_ = true;
arthursonzogni2695d04d2017-12-12 08:39:011007
anantab9800e52017-07-29 18:04:131008 // If the default loader (network) was used to handle the URL load request
Kinuko Yasuda7f3e1722018-03-26 08:58:581009 // we need to see if the interceptors want to potentially create a new
1010 // loader for the response. e.g. AppCache.
anantab9800e52017-07-29 18:04:131011 if (MaybeCreateLoaderForResponse(head))
1012 return;
arthursonzogni3a4ca9f2017-12-07 17:58:341013
John Abd-El-Malekb165dc52018-01-18 17:12:181014 network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints;
John Abd-El-Malekecc6f5f2018-03-02 18:47:391015
1016 // Currently only plugin handlers may intercept the response. Don't treat
1017 // the response as download if it has been handled by plugins.
1018 bool response_intercepted = false;
arthursonzogni3a4ca9f2017-12-07 17:58:341019 if (url_loader_) {
1020 url_loader_client_endpoints = url_loader_->Unbind();
John Abd-El-Malekecc6f5f2018-03-02 18:47:391021 response_intercepted = url_loader_->response_intercepted();
arthursonzogni3a4ca9f2017-12-07 17:58:341022 } else {
John Abd-El-Malekb165dc52018-01-18 17:12:181023 url_loader_client_endpoints =
1024 network::mojom::URLLoaderClientEndpoints::New(
1025 response_url_loader_.PassInterface(),
1026 response_loader_binding_.Unbind());
arthursonzogni3a4ca9f2017-12-07 17:58:341027 }
1028
arthursonzogni40db5f52018-01-08 16:38:491029 bool is_download;
1030 bool is_stream;
Ryan Sturm64315a92018-07-20 06:25:281031 // If there is not an explicit PreviewsState set on the request, turn
1032 // Previews off.
1033 PreviewsState previews_state = PREVIEWS_OFF;
arthursonzogni40db5f52018-01-08 16:38:491034 std::unique_ptr<NavigationData> cloned_navigation_data;
Kenichi Ishibashia7175632018-07-30 02:08:351035
Kinuko Yasuda7f3e1722018-03-26 08:58:581036 if (IsLoaderInterceptionEnabled()) {
Robbie McElratha5adc4e2018-07-03 23:53:091037 bool must_download = download_utils::MustDownload(
Jochen Eisinger7678c8ac2018-05-07 15:47:341038 url_, head.headers.get(), head.mime_type);
John Abd-El-Malek3ebdff862018-04-23 18:57:211039 bool known_mime_type = blink::IsSupportedMimeType(head.mime_type);
1040
Matt Menke2bd72d82018-08-03 15:17:181041 bool is_download_if_not_handled_by_plugin =
1042 !response_intercepted && (must_download || !known_mime_type);
1043
John Abd-El-Malek3ebdff862018-04-23 18:57:211044#if BUILDFLAG(ENABLE_PLUGINS)
1045 if (!response_intercepted && !must_download && !known_mime_type) {
1046 CheckPluginAndContinueOnReceiveResponse(
Marijn Kruisselbrink9ebd7ba2018-06-11 23:18:041047 head, std::move(url_loader_client_endpoints),
Matt Menke2bd72d82018-08-03 15:17:181048 is_download_if_not_handled_by_plugin, std::vector<WebPluginInfo>());
John Abd-El-Malek3ebdff862018-04-23 18:57:211049 return;
1050 }
1051#endif
1052
Matt Menke2bd72d82018-08-03 15:17:181053 is_download = is_download_if_not_handled_by_plugin;
arthursonzogni40db5f52018-01-08 16:38:491054 is_stream = false;
arthursonzognib1de19fa2018-04-03 19:55:101055
Kenichi Ishibashia7175632018-07-30 02:08:351056 // If NetworkService is on, or an interceptor handled the request, the
1057 // request doesn't use ResourceDispatcherHost so
1058 // CallOnReceivedResponse and return here.
1059 if (base::FeatureList::IsEnabled(network::features::kNetworkService) ||
1060 !default_loader_used_) {
1061 CallOnReceivedResponse(head, std::move(url_loader_client_endpoints),
1062 std::move(cloned_navigation_data), is_download,
1063 is_stream, previews_state);
1064 return;
arthursonzognib950d902018-02-08 09:27:131065 }
arthursonzogni40db5f52018-01-08 16:38:491066 }
1067
Kenichi Ishibashia7175632018-07-30 02:08:351068 // NetworkService is off and an interceptor didn't handle the request,
1069 // so it went to ResourceDispatcherHost.
1070 ResourceDispatcherHostImpl* rdh = ResourceDispatcherHostImpl::Get();
1071 net::URLRequest* url_request = rdh->GetURLRequest(global_request_id_);
1072
1073 // The |url_request| maybe have been removed from the resource dispatcher
1074 // host during the time it took for OnReceiveResponse() to be received.
1075 if (url_request) {
1076 ResourceRequestInfoImpl* info =
1077 ResourceRequestInfoImpl::ForRequest(url_request);
1078 is_download = !response_intercepted && info->IsDownload();
1079 is_stream = info->is_stream();
1080 previews_state = info->GetPreviewsState();
1081 if (rdh->delegate()) {
1082 NavigationData* navigation_data =
1083 rdh->delegate()->GetNavigationData(url_request);
1084
1085 // Clone the embedder's NavigationData before moving it to the UI
1086 // thread.
1087 if (navigation_data)
1088 cloned_navigation_data = navigation_data->Clone();
1089 }
1090
1091 // non-S13nServiceWorker:
1092 // This is similar to what is done in
1093 // ServiceWorkerControlleeHandler::MaybeCreateSubresourceLoaderParams()
1094 // (which is used when S13nServiceWorker is on). It takes the matching
1095 // ControllerServiceWorkerInfo (if any) associated with the request. It
1096 // will be sent to the renderer process and used to intercept requests.
1097 ServiceWorkerProviderHost* sw_provider_host =
1098 ServiceWorkerRequestHandler::GetProviderHost(url_request);
1099 if (sw_provider_host && sw_provider_host->controller()) {
1100 DCHECK(!blink::ServiceWorkerUtils::IsServicificationEnabled());
1101 subresource_loader_params_ = SubresourceLoaderParams();
1102 subresource_loader_params_->controller_service_worker_info =
1103 mojom::ControllerServiceWorkerInfo::New();
1104 subresource_loader_params_->controller_service_worker_info->mode =
1105 sw_provider_host->GetControllerMode();
1106 base::WeakPtr<ServiceWorkerObjectHost> sw_object_host =
1107 sw_provider_host->GetOrCreateServiceWorkerObjectHost(
1108 sw_provider_host->controller());
1109 if (sw_object_host) {
1110 subresource_loader_params_->controller_service_worker_object_host =
1111 sw_object_host;
1112 subresource_loader_params_->controller_service_worker_info
1113 ->object_info = sw_object_host->CreateIncompleteObjectInfo();
1114 }
1115 }
1116 } else {
1117 is_download = is_stream = false;
1118 }
1119
Marijn Kruisselbrink9ebd7ba2018-06-11 23:18:041120 CallOnReceivedResponse(head, std::move(url_loader_client_endpoints),
John Abd-El-Malek3ebdff862018-04-23 18:57:211121 std::move(cloned_navigation_data), is_download,
Ryan Sturm64315a92018-07-20 06:25:281122 is_stream, previews_state);
John Abd-El-Malek3ebdff862018-04-23 18:57:211123 }
1124
1125#if BUILDFLAG(ENABLE_PLUGINS)
1126 void CheckPluginAndContinueOnReceiveResponse(
1127 const network::ResourceResponseHead& head,
John Abd-El-Malek3ebdff862018-04-23 18:57:211128 network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
Matt Menke2bd72d82018-08-03 15:17:181129 bool is_download_if_not_handled_by_plugin,
John Abd-El-Malek3ebdff862018-04-23 18:57:211130 const std::vector<WebPluginInfo>& plugins) {
1131 bool stale;
1132 WebPluginInfo plugin;
1133 // It's ok to pass -1 for the render process and frame ID since that's
1134 // only used for plugin overridding. We don't actually care if we get an
1135 // overridden plugin or not, since all we care about is the presence of a
1136 // plugin. Note that this is what the MimeSniffingResourceHandler code
1137 // path does as well for navigations.
1138 bool has_plugin = PluginService::GetInstance()->GetPluginInfo(
1139 -1 /* render_process_id */, -1 /* render_frame_id */, resource_context_,
1140 resource_request_->url, url::Origin(), head.mime_type,
1141 false /* allow_wildcard */, &stale, &plugin, nullptr);
1142
1143 if (stale) {
1144 // Refresh the plugins asynchronously.
1145 PluginService::GetInstance()->GetPlugins(base::BindOnce(
1146 &URLLoaderRequestController::CheckPluginAndContinueOnReceiveResponse,
Marijn Kruisselbrink9ebd7ba2018-06-11 23:18:041147 weak_factory_.GetWeakPtr(), head,
Matt Menke2bd72d82018-08-03 15:17:181148 std::move(url_loader_client_endpoints),
1149 is_download_if_not_handled_by_plugin));
John Abd-El-Malek3ebdff862018-04-23 18:57:211150 return;
1151 }
1152
Matt Menke2bd72d82018-08-03 15:17:181153 bool is_download = !has_plugin && is_download_if_not_handled_by_plugin;
John Abd-El-Malek3ebdff862018-04-23 18:57:211154
Marijn Kruisselbrink9ebd7ba2018-06-11 23:18:041155 CallOnReceivedResponse(head, std::move(url_loader_client_endpoints),
Ryan Sturm64315a92018-07-20 06:25:281156 nullptr, is_download, false /* is_stream */,
1157 PREVIEWS_OFF /* previews_state */);
John Abd-El-Malek3ebdff862018-04-23 18:57:211158 }
1159#endif
1160
1161 void CallOnReceivedResponse(
1162 const network::ResourceResponseHead& head,
John Abd-El-Malek3ebdff862018-04-23 18:57:211163 network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
1164 std::unique_ptr<NavigationData> cloned_navigation_data,
1165 bool is_download,
Ryan Sturm64315a92018-07-20 06:25:281166 bool is_stream,
1167 PreviewsState previews_state) {
John Abd-El-Malek3ebdff862018-04-23 18:57:211168 scoped_refptr<network::ResourceResponse> response(
1169 new network::ResourceResponse());
1170 response->head = head;
1171
Andrey Kosyakova924c8b2017-08-18 17:37:231172 // Make a copy of the ResourceResponse before it is passed to another
1173 // thread.
1174 //
1175 // TODO(davidben): This copy could be avoided if ResourceResponse weren't
1176 // reference counted and the loader stack passed unique ownership of the
1177 // response. https://crbug.com/416050
Eric Seckler8652dcd52018-09-20 10:42:281178 base::PostTaskWithTraits(
1179 FROM_HERE, {BrowserThread::UI},
Philip Rogers7178f5c2018-07-09 18:52:591180 base::BindOnce(&NavigationURLLoaderImpl::OnReceiveResponse, owner_,
1181 response->DeepCopy(),
1182 std::move(url_loader_client_endpoints),
1183 std::move(cloned_navigation_data), global_request_id_,
Ryan Sturm64315a92018-07-20 06:25:281184 is_download, is_stream, previews_state));
yzshenefcb7c72017-06-16 23:12:301185 }
1186
1187 void OnReceiveRedirect(const net::RedirectInfo& redirect_info,
John Abd-El-Malek46248032018-01-17 19:11:231188 const network::ResourceResponseHead& head) override {
Clark DuVallb2680c22018-08-10 15:27:271189 if (base::FeatureList::IsEnabled(network::features::kNetworkService) &&
1190 !bypass_redirect_checks_ &&
Chris Mumford90b1a0d2018-09-26 20:10:431191 !IsRedirectSafe(url_, redirect_info.new_url, resource_context_)) {
Clark DuVallb2680c22018-08-10 15:27:271192 OnComplete(network::URLLoaderCompletionStatus(net::ERR_UNSAFE_REDIRECT));
1193 return;
Clark DuVallbf7722f2018-08-03 18:03:331194 }
1195
Michael Nordman2431f5f2017-09-13 04:58:151196 if (--redirect_limit_ == 0) {
Takashi Toyoshimaaa278662017-11-20 11:11:261197 OnComplete(
1198 network::URLLoaderCompletionStatus(net::ERR_TOO_MANY_REDIRECTS));
Michael Nordman2431f5f2017-09-13 04:58:151199 return;
1200 }
1201
1202 // Store the redirect_info for later use in FollowRedirect where we give
Kinuko Yasuda7f3e1722018-03-26 08:58:581203 // our interceptors_ a chance to intercept the request for the new location.
Michael Nordman2431f5f2017-09-13 04:58:151204 redirect_info_ = redirect_info;
1205
John Abd-El-Malek46248032018-01-17 19:11:231206 scoped_refptr<network::ResourceResponse> response(
1207 new network::ResourceResponse());
Andrey Kosyakova924c8b2017-08-18 17:37:231208 response->head = head;
arthursonzogni40db5f52018-01-08 16:38:491209 url_ = redirect_info.new_url;
Andrey Kosyakova924c8b2017-08-18 17:37:231210
1211 // Make a copy of the ResourceResponse before it is passed to another
1212 // thread.
1213 //
1214 // TODO(davidben): This copy could be avoided if ResourceResponse weren't
1215 // reference counted and the loader stack passed unique ownership of the
1216 // response. https://crbug.com/416050
Eric Seckler8652dcd52018-09-20 10:42:281217 base::PostTaskWithTraits(
1218 FROM_HERE, {BrowserThread::UI},
arthursonzogni1fd60e62018-05-09 15:57:321219 base::BindOnce(&NavigationURLLoaderImpl::OnReceiveRedirect, owner_,
1220 redirect_info, response->DeepCopy()));
yzshenefcb7c72017-06-16 23:12:301221 }
1222
yzshenefcb7c72017-06-16 23:12:301223 void OnUploadProgress(int64_t current_position,
1224 int64_t total_size,
1225 OnUploadProgressCallback callback) override {}
yzshenefcb7c72017-06-16 23:12:301226 void OnReceiveCachedMetadata(const std::vector<uint8_t>& data) override {}
yzshenefcb7c72017-06-16 23:12:301227 void OnTransferSizeUpdated(int32_t transfer_size_diff) override {}
1228
Philip Rogers7178f5c2018-07-09 18:52:591229 void OnStartLoadingResponseBody(mojo::ScopedDataPipeConsumerHandle) override {
1230 // Not reached. At this point, the loader and client endpoints must have
1231 // been unbound and forwarded to the renderer.
Matt Falkenhagen2ba894152018-09-21 08:29:441232
1233 // TODO(crbug.com/882661): Remove these aliases when the linked bug is
1234 // fixed.
1235 bool received_response = received_response_;
1236 base::debug::Alias(&received_response);
1237 bool default_loader_used = default_loader_used_;
1238 base::debug::Alias(&default_loader_used);
1239 DEBUG_ALIAS_FOR_GURL(url, url_);
1240 size_t chain_size = url_chain_.size();
1241 base::debug::Alias(&chain_size);
1242 GURL url0;
1243 GURL url1;
1244 GURL url2;
1245 GURL url3;
1246 GURL url4;
1247 GURL url5;
1248 if (url_chain_.size() > 0)
1249 url0 = url_chain_[0];
1250 if (url_chain_.size() > 1)
1251 url1 = url_chain_[1];
1252 if (url_chain_.size() > 2)
1253 url2 = url_chain_[2];
1254 if (url_chain_.size() > 3)
1255 url3 = url_chain_[3];
1256 if (url_chain_.size() > 4)
1257 url4 = url_chain_[4];
1258 if (url_chain_.size() > 5)
1259 url5 = url_chain_[5];
1260 DEBUG_ALIAS_FOR_GURL(url0_buf, url0);
1261 DEBUG_ALIAS_FOR_GURL(url1_buf, url1);
1262 DEBUG_ALIAS_FOR_GURL(url2_buf, url2);
1263 DEBUG_ALIAS_FOR_GURL(url3_buf, url3);
1264 DEBUG_ALIAS_FOR_GURL(url4_buf, url4);
1265 DEBUG_ALIAS_FOR_GURL(url5_buf, url5);
Philip Rogers7178f5c2018-07-09 18:52:591266 CHECK(false);
yzshenefcb7c72017-06-16 23:12:301267 }
1268
Takashi Toyoshimaaa278662017-11-20 11:11:261269 void OnComplete(const network::URLLoaderCompletionStatus& status) override {
Matt Menked9cad562018-08-10 21:47:091270 RecordSCTHistogramIfNeeded(status.ssl_info);
1271
Emily Starkb09f19a2017-11-22 22:41:471272 UMA_HISTOGRAM_BOOLEAN(
arthursonzognie70c4a042018-05-02 15:49:101273 "Navigation.URLLoaderNetworkService.OnCompleteHasSSLInfo",
Emily Starkb09f19a2017-11-22 22:41:471274 status.ssl_info.has_value());
1275 if (status.ssl_info.has_value()) {
1276 UMA_HISTOGRAM_MEMORY_KB(
1277 "Navigation.URLLoaderNetworkService.OnCompleteCertificateChainsSize",
1278 GetCertificateChainsSizeInKB(status.ssl_info.value()));
1279 }
1280
Takashi Toyoshima8f988532017-11-13 07:32:371281 if (status.error_code != net::OK && !received_response_) {
anantab9800e52017-07-29 18:04:131282 // If the default loader (network) was used to handle the URL load
Kinuko Yasuda7f3e1722018-03-26 08:58:581283 // request we need to see if the interceptors want to potentially create a
anantab9800e52017-07-29 18:04:131284 // new loader for the response. e.g. AppCache.
John Abd-El-Malek46248032018-01-17 19:11:231285 if (MaybeCreateLoaderForResponse(network::ResourceResponseHead()))
anantab9800e52017-07-29 18:04:131286 return;
1287 }
Takashi Toyoshima8f988532017-11-13 07:32:371288 status_ = status;
arthursonzogni2695d04d2017-12-12 08:39:011289
Eric Seckler8652dcd52018-09-20 10:42:281290 base::PostTaskWithTraits(
1291 FROM_HERE, {BrowserThread::UI},
arthursonzogni1fd60e62018-05-09 15:57:321292 base::BindOnce(&NavigationURLLoaderImpl::OnComplete, owner_, status));
yzshenefcb7c72017-06-16 23:12:301293 }
1294
Kinuko Yasuda7f3e1722018-03-26 08:58:581295 // Returns true if an interceptor wants to handle the response, i.e. return a
Michael Nordman2431f5f2017-09-13 04:58:151296 // different response. For e.g. AppCache may have fallback content.
John Abd-El-Malek46248032018-01-17 19:11:231297 bool MaybeCreateLoaderForResponse(
1298 const network::ResourceResponseHead& response) {
Kinuko Yasuda7f3e1722018-03-26 08:58:581299 if (!IsLoaderInterceptionEnabled())
arthursonzogni2695d04d2017-12-12 08:39:011300 return false;
1301
anantab9800e52017-07-29 18:04:131302 if (!default_loader_used_)
1303 return false;
1304
Kinuko Yasuda7f3e1722018-03-26 08:58:581305 for (auto& interceptor : interceptors_) {
John Abd-El-Malekb165dc52018-01-18 17:12:181306 network::mojom::URLLoaderClientRequest response_client_request;
Kinuko Yasuda7f3e1722018-03-26 08:58:581307 if (interceptor->MaybeCreateLoaderForResponse(
1308 response, &response_url_loader_, &response_client_request,
1309 url_loader_.get())) {
Kunihiko Sakamoto21ab4ad262018-08-21 10:26:211310 if (response_loader_binding_.is_bound())
1311 response_loader_binding_.Close();
Michael Nordman2431f5f2017-09-13 04:58:151312 response_loader_binding_.Bind(std::move(response_client_request));
1313 default_loader_used_ = false;
1314 url_loader_.reset();
anantab9800e52017-07-29 18:04:131315 return true;
1316 }
1317 }
1318 return false;
1319 }
1320
Matt Falkenhagen43765122018-08-22 19:37:221321 std::vector<std::unique_ptr<URLLoaderThrottle>> CreateURLLoaderThrottles() {
Tsuyoshi Horo70014ad2018-02-14 11:20:141322 return GetContentClient()->browser()->CreateURLLoaderThrottles(
1323 *resource_request_, resource_context_, web_contents_getter_,
1324 navigation_ui_data_.get(), frame_tree_node_id_);
1325 }
1326
Makoto Shimazu44c2c3232018-03-30 01:10:201327 std::unique_ptr<NavigationLoaderInterceptor> CreateServiceWorkerInterceptor(
1328 const NavigationRequestInfo& request_info,
1329 ServiceWorkerNavigationHandleCore* service_worker_navigation_handle_core)
1330 const {
1331 const ResourceType resource_type = request_info.is_main_frame
1332 ? RESOURCE_TYPE_MAIN_FRAME
1333 : RESOURCE_TYPE_SUB_FRAME;
1334 network::mojom::RequestContextFrameType frame_type =
1335 request_info.is_main_frame
1336 ? network::mojom::RequestContextFrameType::kTopLevel
1337 : network::mojom::RequestContextFrameType::kNested;
1338 storage::BlobStorageContext* blob_storage_context = GetBlobStorageContext(
1339 GetChromeBlobStorageContextForResourceContext(resource_context_));
1340 return ServiceWorkerRequestHandler::InitializeForNavigationNetworkService(
Matt Falkenhagen43765122018-08-22 19:37:221341 resource_request_->url, resource_context_,
Makoto Shimazu44c2c3232018-03-30 01:10:201342 service_worker_navigation_handle_core, blob_storage_context,
1343 request_info.begin_params->skip_service_worker, resource_type,
1344 request_info.begin_params->request_context_type, frame_type,
1345 request_info.are_ancestors_secure, request_info.common_params.post_data,
1346 web_contents_getter_);
1347 }
1348
Matt Menked9cad562018-08-10 21:47:091349 void RecordSCTHistogramIfNeeded(
1350 const base::Optional<net::SSLInfo>& ssl_info) {
1351 if (is_main_frame_ && url_.SchemeIsCryptographic() &&
1352 ssl_info.has_value()) {
1353 int num_valid_scts = 0;
1354 for (const auto& signed_certificate_timestamps :
1355 ssl_info->signed_certificate_timestamps) {
1356 if (signed_certificate_timestamps.status == net::ct::SCT_STATUS_OK)
1357 ++num_valid_scts;
1358 }
1359 UMA_HISTOGRAM_COUNTS_100(
1360 "Net.CertificateTransparency.MainFrameValidSCTCount", num_valid_scts);
1361 }
1362 }
1363
Kinuko Yasuda7f3e1722018-03-26 08:58:581364 std::vector<std::unique_ptr<NavigationLoaderInterceptor>> interceptors_;
1365 size_t interceptor_index_ = 0;
kinuko69732972017-05-29 08:50:071366
John Abd-El-Malek1df61792018-01-12 20:40:451367 std::unique_ptr<network::ResourceRequest> resource_request_;
Makoto Shimazu44c2c3232018-03-30 01:10:201368 // Non-NetworkService: |request_info_| is updated along with
1369 // |resource_request_| on redirects.
1370 std::unique_ptr<NavigationRequestInfo> request_info_;
John Abd-El-Malek576c6132017-11-04 00:33:581371 int frame_tree_node_id_ = 0;
arthursonzogni40db5f52018-01-08 16:38:491372 GlobalRequestID global_request_id_;
Michael Nordman2431f5f2017-09-13 04:58:151373 net::RedirectInfo redirect_info_;
Daniel Bratell0dfa6282017-11-08 10:12:231374 int redirect_limit_ = net::URLRequest::kMaxRedirects;
kinuko69732972017-05-29 08:50:071375 ResourceContext* resource_context_;
yzshenefcb7c72017-06-16 23:12:301376 base::Callback<WebContents*()> web_contents_getter_;
John Abd-El-Malekeb1a5382018-01-05 16:58:001377 std::unique_ptr<NavigationUIData> navigation_ui_data_;
Kinuko Yasudabe4ad292018-07-06 01:33:391378 scoped_refptr<network::SharedURLLoaderFactory> network_loader_factory_;
arthursonzogni2695d04d2017-12-12 08:39:011379
yzshenefcb7c72017-06-16 23:12:301380 std::unique_ptr<ThrottlingURLLoader> url_loader_;
arthursonzogni2695d04d2017-12-12 08:39:011381
Chong Zhang7607f1f2018-06-01 20:52:201382 // Caches the modified request headers provided by clients during redirect,
1383 // will be consumed by next |url_loader_->FollowRedirect()|.
1384 base::Optional<net::HttpRequestHeaders> url_loader_modified_request_headers_;
1385
mmenkeed44e6c2017-06-28 21:13:321386 BlobHandles blob_handles_;
Min Qin83d07872017-10-26 23:22:411387 std::vector<GURL> url_chain_;
kinuko69732972017-05-29 08:50:071388
arthursonzogni40db5f52018-01-08 16:38:491389 // Current URL that is being navigated, updated after redirection.
1390 GURL url_;
1391
Matt Menked9cad562018-08-10 21:47:091392 const bool is_main_frame_;
1393
anantae60d1d42017-06-20 04:16:271394 // Currently used by the AppCache loader to pass its factory to the
1395 // renderer which enables it to handle subresources.
Kinuko Yasuda250577c2017-10-29 02:51:241396 base::Optional<SubresourceLoaderParams> subresource_loader_params_;
anantae60d1d42017-06-20 04:16:271397
mmenkeed44e6c2017-06-28 21:13:321398 // This is referenced only on the UI thread.
arthursonzogni1fd60e62018-05-09 15:57:321399 base::WeakPtr<NavigationURLLoaderImpl> owner_;
mmenkeed44e6c2017-06-28 21:13:321400
anantab9800e52017-07-29 18:04:131401 // Set to true if the default URLLoader (network service) was used for the
1402 // current navigation.
1403 bool default_loader_used_ = false;
1404
1405 // URLLoaderClient binding for loaders created for responses received from the
1406 // network loader.
John Abd-El-Malekb165dc52018-01-18 17:12:181407 mojo::Binding<network::mojom::URLLoaderClient> response_loader_binding_;
anantab9800e52017-07-29 18:04:131408
1409 // URLLoader instance for response loaders, i.e loaders created for handing
1410 // responses received from the network URLLoader.
John Abd-El-Malekb165dc52018-01-18 17:12:181411 network::mojom::URLLoaderPtr response_url_loader_;
anantab9800e52017-07-29 18:04:131412
1413 // Set to true if we receive a valid response from a URLLoader, i.e.
1414 // URLLoaderClient::OnReceivedResponse() is called.
1415 bool received_response_ = false;
1416
Alex Clarke1e08882b32017-10-06 14:22:401417 bool started_ = false;
1418
Ken Rockot314714c2017-11-05 23:36:241419 // Lazily initialized and used in the case of non-network resource
1420 // navigations. Keyed by URL scheme.
John Abd-El-Malekb165dc52018-01-18 17:12:181421 std::map<std::string, network::mojom::URLLoaderFactoryPtr>
Ken Rockot314714c2017-11-05 23:36:241422 non_network_url_loader_factories_;
1423
Makoto Shimazu44c2c3232018-03-30 01:10:201424 // Non-NetworkService:
1425 // Generator of a request handler for sending request to the network. This
1426 // captures all of parameters to create a
1427 // SingleRequestURLLoaderFactory::RequestHandler. Used only when
1428 // NetworkService is disabled but IsLoaderInterceptionEnabled() is true.
Makoto Shimazu684a5ad2018-05-29 08:20:501429 // Set |was_request_intercepted| to true if the request was intercepted by an
1430 // interceptor and the request is falling back to the network. In that case,
1431 // any interceptors won't intercept the request.
1432 base::RepeatingCallback<SingleRequestURLLoaderFactory::RequestHandler(
1433 bool /* was_request_intercepted */)>
Makoto Shimazu44c2c3232018-03-30 01:10:201434 default_request_handler_factory_;
1435
Min Qin40b72172017-09-27 00:19:171436 // The completion status if it has been received. This is needed to handle
1437 // the case that the response is intercepted by download, and OnComplete() is
1438 // already called while we are transferring the |url_loader_| and response
1439 // body to download code.
Takashi Toyoshimaaa278662017-11-20 11:11:261440 base::Optional<network::URLLoaderCompletionStatus> status_;
Min Qin40b72172017-09-27 00:19:171441
Ken Rockota0dfaca12018-02-15 07:26:251442 // Before creating this URLLoaderRequestController on UI thread, the embedder
1443 // may have elected to proxy the URLLoaderFactory request, in which case these
1444 // fields will contain input (info) and output (request) endpoints for the
1445 // proxy. If this controller is handling a request for which proxying is
1446 // supported, requests will be plumbed through these endpoints.
1447 //
1448 // Note that these are only used for requests that go to the Network Service.
1449 network::mojom::URLLoaderFactoryRequest proxied_factory_request_;
1450 network::mojom::URLLoaderFactoryPtrInfo proxied_factory_info_;
1451
John Abd-El-Maleka67add82018-03-09 18:22:011452 // The schemes that this loader can use. For anything else we'll try external
1453 // protocol handlers.
1454 std::set<std::string> known_schemes_;
1455
Clark DuVallb2680c22018-08-10 15:27:271456 // If true, redirect checks will be handled in a proxy, and not here.
1457 bool bypass_redirect_checks_;
Clark DuVallbf7722f2018-08-03 18:03:331458
Makoto Shimazu44c2c3232018-03-30 01:10:201459 mutable base::WeakPtrFactory<URLLoaderRequestController> weak_factory_;
arthursonzogni2695d04d2017-12-12 08:39:011460
kinuko69732972017-05-29 08:50:071461 DISALLOW_COPY_AND_ASSIGN(URLLoaderRequestController);
1462};
1463
Min Qin75ed6df2017-12-01 20:39:151464// TODO(https://crbug.com/790734): pass |navigation_ui_data| along with the
1465// request so that it could be modified.
arthursonzogni1fd60e62018-05-09 15:57:321466NavigationURLLoaderImpl::NavigationURLLoaderImpl(
scottmg69985212017-04-12 16:47:281467 ResourceContext* resource_context,
1468 StoragePartition* storage_partition,
1469 std::unique_ptr<NavigationRequestInfo> request_info,
1470 std::unique_ptr<NavigationUIData> navigation_ui_data,
scottmgd2021c92017-05-15 16:58:051471 ServiceWorkerNavigationHandle* service_worker_navigation_handle,
scottmg69985212017-04-12 16:47:281472 AppCacheNavigationHandle* appcache_handle,
Alex Clarke1e08882b32017-10-06 14:22:401473 NavigationURLLoaderDelegate* delegate,
Kinuko Yasuda7f3e1722018-03-26 08:58:581474 std::vector<std::unique_ptr<NavigationLoaderInterceptor>>
1475 initial_interceptors)
Min Qin37db5102017-09-13 21:21:251476 : delegate_(delegate),
1477 allow_download_(request_info->common_params.allow_download),
1478 weak_factory_(this) {
scottmg95feea52017-04-12 17:51:331479 DCHECK_CURRENTLY_ON(BrowserThread::UI);
John Abd-El-Malekfcb2ecf2017-11-15 23:15:301480 int frame_tree_node_id = request_info->frame_tree_node_id;
ananta5149d8e2017-04-21 00:01:371481
yzshen0f278522017-05-01 17:10:221482 TRACE_EVENT_ASYNC_BEGIN_WITH_TIMESTAMP1(
1483 "navigation", "Navigation timeToResponseStarted", this,
kinuko69732972017-05-29 08:50:071484 request_info->common_params.navigation_start, "FrameTreeNode id",
John Abd-El-Malekfcb2ecf2017-11-15 23:15:301485 frame_tree_node_id);
yzshen0f278522017-05-01 17:10:221486
arthursonzogni2695d04d2017-12-12 08:39:011487 ServiceWorkerNavigationHandleCore* service_worker_navigation_handle_core =
1488 service_worker_navigation_handle
1489 ? service_worker_navigation_handle->core()
1490 : nullptr;
1491
1492 AppCacheNavigationHandleCore* appcache_handle_core =
1493 appcache_handle ? appcache_handle->core() : nullptr;
1494
Yuzhu Shencb3011f62018-02-08 02:51:501495 std::unique_ptr<network::ResourceRequest> new_request = CreateResourceRequest(
1496 request_info.get(), frame_tree_node_id, allow_download_);
Yutaka Hirano61e41b3c2018-05-31 05:31:061497 new_request->transition_type = request_info->common_params.transition;
Tsuyoshi Horob8d512a2018-01-25 17:01:591498
Yutaka Hiranod8789f92018-01-30 09:59:511499 if (!base::FeatureList::IsEnabled(network::features::kNetworkService)) {
arthursonzogni2695d04d2017-12-12 08:39:011500 DCHECK(!request_controller_);
1501 request_controller_ = std::make_unique<URLLoaderRequestController>(
Kinuko Yasuda7f3e1722018-03-26 08:58:581502 /* initial_interceptors = */
1503 std::vector<std::unique_ptr<NavigationLoaderInterceptor>>(),
Tsuyoshi Horob8d512a2018-01-25 17:01:591504 std::move(new_request), resource_context,
Matt Menked9cad562018-08-10 21:47:091505 request_info->common_params.url, request_info->is_main_frame,
Ken Rockota0dfaca12018-02-15 07:26:251506 /* proxied_url_loader_factory_request */ nullptr,
John Abd-El-Maleka67add82018-03-09 18:22:011507 /* proxied_url_loader_factory_info */ nullptr, std::set<std::string>(),
Clark DuVallb2680c22018-08-10 15:27:271508 /* bypass_redirect_checks */ false, weak_factory_.GetWeakPtr());
arthursonzogni2695d04d2017-12-12 08:39:011509
Eric Seckler8652dcd52018-09-20 10:42:281510 base::PostTaskWithTraits(
1511 FROM_HERE, {BrowserThread::IO},
arthursonzogni2695d04d2017-12-12 08:39:011512 base::BindOnce(
1513 &URLLoaderRequestController::StartWithoutNetworkService,
1514 base::Unretained(request_controller_.get()),
Tsuyoshi Horo70014ad2018-02-14 11:20:141515 base::RetainedRef(storage_partition->GetURLRequestContext()),
arthursonzogni2695d04d2017-12-12 08:39:011516 base::Unretained(storage_partition->GetFileSystemContext()),
1517 base::Unretained(service_worker_navigation_handle_core),
tzikccf160c2018-02-20 12:43:131518 base::Unretained(appcache_handle_core), std::move(request_info),
1519 std::move(navigation_ui_data)));
arthursonzogni2695d04d2017-12-12 08:39:011520 return;
1521 }
1522
scottmgd2021c92017-05-15 16:58:051523 // Check if a web UI scheme wants to handle this request.
Ken Rockot6414c4d92017-11-08 19:58:321524 FrameTreeNode* frame_tree_node =
1525 FrameTreeNode::GloballyFindByID(frame_tree_node_id);
John Abd-El-Malekb165dc52018-01-18 17:12:181526 network::mojom::URLLoaderFactoryPtrInfo factory_for_webui;
scottmgd2021c92017-05-15 16:58:051527 const auto& schemes = URLDataManagerBackend::GetWebUISchemes();
John Abd-El-Malekbb0bc8e2017-11-11 01:08:151528 std::string scheme = new_request->url.scheme();
qufehdquf9c8433abd2018-07-10 16:57:271529 if (base::ContainsValue(schemes, scheme)) {
Chris Mumfordbae8a742018-03-01 23:02:231530 factory_for_webui = CreateWebUIURLLoaderBinding(
1531 frame_tree_node->current_frame_host(), scheme)
1532 .PassInterface();
ananta5149d8e2017-04-21 00:01:371533 }
scottmgd2021c92017-05-15 16:58:051534
Ken Rockota0dfaca12018-02-15 07:26:251535 network::mojom::URLLoaderFactoryPtrInfo proxied_factory_info;
1536 network::mojom::URLLoaderFactoryRequest proxied_factory_request;
Clark DuVallb2680c22018-08-10 15:27:271537 bool bypass_redirect_checks = false;
Chris Mumford942075ad2018-05-19 00:22:041538 auto* partition = static_cast<StoragePartitionImpl*>(storage_partition);
Ken Rockota0dfaca12018-02-15 07:26:251539 if (frame_tree_node) {
1540 // |frame_tree_node| may be null in some unit test environments.
1541 GetContentClient()
1542 ->browser()
1543 ->RegisterNonNetworkNavigationURLLoaderFactories(
John Abd-El-Malekea006302018-05-10 05:50:461544 frame_tree_node_id, &non_network_url_loader_factories_);
Ken Rockota0dfaca12018-02-15 07:26:251545
1546 // The embedder may want to proxy all network-bound URLLoaderFactory
1547 // requests that it can. If it elects to do so, we'll pass its proxy
1548 // endpoints off to the URLLoaderRequestController where wthey will be
1549 // connected if the request type supports proxying.
1550 network::mojom::URLLoaderFactoryPtrInfo factory_info;
1551 auto factory_request = mojo::MakeRequest(&factory_info);
Andrey Kosyakov8d49c5062018-03-15 19:50:491552 bool use_proxy = GetContentClient()->browser()->WillCreateURLLoaderFactory(
Ken Rockot428b1d62018-06-06 17:12:211553 partition->browser_context(), frame_tree_node->current_frame_host(),
Clark DuVall8dc4e502018-09-07 01:51:121554 true /* is_navigation */, new_request->url, &factory_request,
1555 &bypass_redirect_checks);
Andrey Kosyakov8d49c5062018-03-15 19:50:491556 if (RenderFrameDevToolsAgentHost::WillCreateURLLoaderFactory(
Jochen Eisingercdc12d12018-05-08 15:07:471557 frame_tree_node->current_frame_host(), true, false,
1558 &factory_request)) {
Andrey Kosyakov8d49c5062018-03-15 19:50:491559 use_proxy = true;
1560 }
1561 if (use_proxy) {
Ken Rockota0dfaca12018-02-15 07:26:251562 proxied_factory_request = std::move(factory_request);
1563 proxied_factory_info = std::move(factory_info);
1564 }
Chris Mumford942075ad2018-05-19 00:22:041565
1566 const std::string storage_domain;
1567 non_network_url_loader_factories_[url::kFileSystemScheme] =
1568 CreateFileSystemURLLoaderFactory(frame_tree_node->current_frame_host(),
1569 /*is_navigation=*/true,
1570 partition->GetFileSystemContext(),
1571 storage_domain);
Ken Rockota0dfaca12018-02-15 07:26:251572 }
1573
John Abd-El-Maleka67add82018-03-09 18:22:011574 non_network_url_loader_factories_[url::kFileScheme] =
1575 std::make_unique<FileURLLoaderFactory>(
1576 partition->browser_context()->GetPath(),
1577 base::CreateSequencedTaskRunnerWithTraits(
Gabriel Charetteb10aeeb2018-07-26 20:15:001578 {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
John Abd-El-Maleka67add82018-03-09 18:22:011579 base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}));
1580 std::set<std::string> known_schemes;
1581 for (auto& iter : non_network_url_loader_factories_)
1582 known_schemes.insert(iter.first);
1583
kinuko69732972017-05-29 08:50:071584 DCHECK(!request_controller_);
Jeremy Roman04f27c372017-10-27 15:20:551585 request_controller_ = std::make_unique<URLLoaderRequestController>(
Kinuko Yasuda7f3e1722018-03-26 08:58:581586 std::move(initial_interceptors), std::move(new_request), resource_context,
Matt Menked9cad562018-08-10 21:47:091587 request_info->common_params.url, request_info->is_main_frame,
1588 std::move(proxied_factory_request), std::move(proxied_factory_info),
1589 std::move(known_schemes), bypass_redirect_checks,
1590 weak_factory_.GetWeakPtr());
Eric Seckler8652dcd52018-09-20 10:42:281591 base::PostTaskWithTraits(
1592 FROM_HERE, {BrowserThread::IO},
Ken Rockot387ddd5a2018-01-30 19:18:401593 base::BindOnce(
1594 &URLLoaderRequestController::Start,
1595 base::Unretained(request_controller_.get()),
Kinuko Yasudabe4ad292018-07-06 01:33:391596 partition->url_loader_factory_getter()->GetNetworkFactoryInfo(),
Ken Rockot387ddd5a2018-01-30 19:18:401597 service_worker_navigation_handle_core, appcache_handle_core,
1598 std::move(request_info), std::move(navigation_ui_data),
1599 std::move(factory_for_webui), frame_tree_node_id,
1600 ServiceManagerConnection::GetForProcess()->GetConnector()->Clone()));
scottmg69985212017-04-12 16:47:281601}
1602
arthursonzogni1fd60e62018-05-09 15:57:321603NavigationURLLoaderImpl::~NavigationURLLoaderImpl() {
kinuko69732972017-05-29 08:50:071604 BrowserThread::DeleteSoon(BrowserThread::IO, FROM_HERE,
1605 request_controller_.release());
1606}
scottmg69985212017-04-12 16:47:281607
Chong Zhang7607f1f2018-06-01 20:52:201608void NavigationURLLoaderImpl::FollowRedirect(
Jun Cai605ff0e72018-06-12 22:29:201609 const base::Optional<std::vector<std::string>>&
1610 to_be_removed_request_headers,
Chong Zhang7607f1f2018-06-01 20:52:201611 const base::Optional<net::HttpRequestHeaders>& modified_request_headers) {
Eric Seckler8652dcd52018-09-20 10:42:281612 base::PostTaskWithTraits(
1613 FROM_HERE, {BrowserThread::IO},
tzik0f14f192017-08-15 02:43:331614 base::BindOnce(&URLLoaderRequestController::FollowRedirect,
Chong Zhang7607f1f2018-06-01 20:52:201615 base::Unretained(request_controller_.get()),
1616 modified_request_headers));
scottmg95feea52017-04-12 17:51:331617}
scottmg69985212017-04-12 16:47:281618
arthursonzogni1fd60e62018-05-09 15:57:321619void NavigationURLLoaderImpl::ProceedWithResponse() {}
scottmg69985212017-04-12 16:47:281620
arthursonzogni1fd60e62018-05-09 15:57:321621void NavigationURLLoaderImpl::OnReceiveResponse(
John Abd-El-Malek46248032018-01-17 19:11:231622 scoped_refptr<network::ResourceResponse> response,
John Abd-El-Malekb165dc52018-01-18 17:12:181623 network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
arthursonzogni40db5f52018-01-08 16:38:491624 std::unique_ptr<NavigationData> navigation_data,
1625 const GlobalRequestID& global_request_id,
1626 bool is_download,
Ryan Sturm64315a92018-07-20 06:25:281627 bool is_stream,
1628 PreviewsState previews_state) {
arthursonzogni3a4ca9f2017-12-07 17:58:341629 TRACE_EVENT_ASYNC_END2("navigation", "Navigation timeToResponseStarted", this,
arthursonzogni1fd60e62018-05-09 15:57:321630 "&NavigationURLLoaderImpl", this, "success", true);
arthursonzogni3a4ca9f2017-12-07 17:58:341631
scottmgefb697302017-04-12 22:37:301632 // TODO(scottmg): This needs to do more of what
arthursonzogni3a4ca9f2017-12-07 17:58:341633 // NavigationResourceHandler::OnResponseStarted() does.
arthursonzogni3a4ca9f2017-12-07 17:58:341634
arthursonzogni3a4ca9f2017-12-07 17:58:341635 delegate_->OnResponseStarted(
arthursonzognif34adf092018-04-24 17:06:131636 std::move(response), std::move(url_loader_client_endpoints),
Philip Rogers7178f5c2018-07-09 18:52:591637 std::move(navigation_data), global_request_id,
Ryan Sturm64315a92018-07-20 06:25:281638 allow_download_ && is_download, is_stream, previews_state,
arthursonzogni3a4ca9f2017-12-07 17:58:341639 request_controller_->TakeSubresourceLoaderParams());
scottmg95feea52017-04-12 17:51:331640}
scottmg69985212017-04-12 16:47:281641
arthursonzogni1fd60e62018-05-09 15:57:321642void NavigationURLLoaderImpl::OnReceiveRedirect(
scottmg69985212017-04-12 16:47:281643 const net::RedirectInfo& redirect_info,
John Abd-El-Malek46248032018-01-17 19:11:231644 scoped_refptr<network::ResourceResponse> response) {
scottmg95feea52017-04-12 17:51:331645 DCHECK_CURRENTLY_ON(BrowserThread::UI);
Andrey Kosyakova924c8b2017-08-18 17:37:231646 delegate_->OnRequestRedirected(redirect_info, std::move(response));
scottmg95feea52017-04-12 17:51:331647}
scottmg69985212017-04-12 16:47:281648
arthursonzogni1fd60e62018-05-09 15:57:321649void NavigationURLLoaderImpl::OnComplete(
Takashi Toyoshimaaa278662017-11-20 11:11:261650 const network::URLLoaderCompletionStatus& status) {
Takashi Toyoshima8f988532017-11-13 07:32:371651 if (status.error_code == net::OK)
John Abd-El-Malekb906d282017-08-31 19:36:431652 return;
1653
1654 TRACE_EVENT_ASYNC_END2("navigation", "Navigation timeToResponseStarted", this,
arthursonzogni1fd60e62018-05-09 15:57:321655 "&NavigationURLLoaderImpl", this, "success", false);
Lucas Garron0efab6d2017-08-30 22:28:511656
Johannes Henkel6a43fef2018-05-17 18:41:521657 delegate_->OnRequestFailed(status);
yzshen384441de2017-04-19 23:26:141658}
scottmg69985212017-04-12 16:47:281659
arthursonzogni1fd60e62018-05-09 15:57:321660void NavigationURLLoaderImpl::SetBeginNavigationInterceptorForTesting(
John Abd-El-Malekdb3a13b2018-05-01 17:52:021661 const BeginNavigationInterceptor& interceptor) {
1662 DCHECK(!BrowserThread::IsThreadInitialized(BrowserThread::IO) ||
1663 BrowserThread::CurrentlyOn(BrowserThread::IO));
1664 DCHECK(!base::FeatureList::IsEnabled(network::features::kNetworkService));
1665 g_interceptor.Get() = interceptor;
1666}
1667
arthursonzogni1fd60e62018-05-09 15:57:321668void NavigationURLLoaderImpl::OnRequestStarted(base::TimeTicks timestamp) {
arthursonzogni2695d04d2017-12-12 08:39:011669 DCHECK_CURRENTLY_ON(BrowserThread::UI);
1670 delegate_->OnRequestStarted(timestamp);
1671}
1672
arthursonzogni1fd60e62018-05-09 15:57:321673void NavigationURLLoaderImpl::BindNonNetworkURLLoaderFactoryRequest(
Ken Rockota0dfaca12018-02-15 07:26:251674 int frame_tree_node_id,
Ken Rockot314714c2017-11-05 23:36:241675 const GURL& url,
John Abd-El-Malekb165dc52018-01-18 17:12:181676 network::mojom::URLLoaderFactoryRequest factory) {
Ken Rockot314714c2017-11-05 23:36:241677 auto it = non_network_url_loader_factories_.find(url.scheme());
1678 if (it == non_network_url_loader_factories_.end()) {
1679 DVLOG(1) << "Ignoring request with unknown scheme: " << url.spec();
1680 return;
1681 }
Ken Rockota0dfaca12018-02-15 07:26:251682 FrameTreeNode* frame_tree_node =
1683 FrameTreeNode::GloballyFindByID(frame_tree_node_id);
Ken Rockot428b1d62018-06-06 17:12:211684 auto* frame = frame_tree_node->current_frame_host();
Ken Rockota0dfaca12018-02-15 07:26:251685 GetContentClient()->browser()->WillCreateURLLoaderFactory(
Ken Rockot428b1d62018-06-06 17:12:211686 frame->GetSiteInstance()->GetBrowserContext(), frame,
Clark DuVall8dc4e502018-09-07 01:51:121687 true /* is_navigation */, url, &factory,
1688 nullptr /* bypass_redirect_checks */);
Ken Rockot314714c2017-11-05 23:36:241689 it->second->Clone(std::move(factory));
1690}
1691
scottmg69985212017-04-12 16:47:281692} // namespace content