1 /*
2  * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
3  * Copyright (C) 2011 Google Inc. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1.  Redistributions of source code must retain the above copyright
10  *     notice, this list of conditions and the following disclaimer.
11  * 2.  Redistributions in binary form must reproduce the above copyright
12  *     notice, this list of conditions and the following disclaimer in the
13  *     documentation and/or other materials provided with the distribution.
14  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15  *     its contributors may be used to endorse or promote products derived
16  *     from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #include "third_party/blink/renderer/core/loader/document_loader.h"
31 
32 #include <memory>
33 #include <utility>
34 
35 #include "base/auto_reset.h"
36 #include "base/metrics/histogram_macros.h"
37 #include "base/time/default_tick_clock.h"
38 #include "build/chromeos_buildflags.h"
39 #include "services/network/public/cpp/web_sandbox_flags.h"
40 #include "services/network/public/mojom/web_sandbox_flags.mojom-blink.h"
41 #include "third_party/blink/public/common/features.h"
42 #include "third_party/blink/public/mojom/commit_result/commit_result.mojom-blink.h"
43 #include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
44 #include "third_party/blink/public/platform/modules/service_worker/web_service_worker_network_provider.h"
45 #include "third_party/blink/public/platform/web_url_request.h"
46 #include "third_party/blink/renderer/core/dom/document.h"
47 #include "third_party/blink/renderer/core/dom/document_init.h"
48 #include "third_party/blink/renderer/core/dom/document_parser.h"
49 #include "third_party/blink/renderer/core/dom/events/event.h"
50 #include "third_party/blink/renderer/core/dom/scriptable_document_parser.h"
51 #include "third_party/blink/renderer/core/dom/weak_identifier_map.h"
52 #include "third_party/blink/renderer/core/execution_context/security_context_init.h"
53 #include "third_party/blink/renderer/core/execution_context/window_agent.h"
54 #include "third_party/blink/renderer/core/execution_context/window_agent_factory.h"
55 #include "third_party/blink/renderer/core/feature_policy/document_policy_parser.h"
56 #include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
57 #include "third_party/blink/renderer/core/frame/deprecation.h"
58 #include "third_party/blink/renderer/core/frame/frame_console.h"
59 #include "third_party/blink/renderer/core/frame/intervention.h"
60 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
61 #include "third_party/blink/renderer/core/frame/local_frame.h"
62 #include "third_party/blink/renderer/core/frame/local_frame_client.h"
63 #include "third_party/blink/renderer/core/frame/settings.h"
64 #include "third_party/blink/renderer/core/html/html_document.h"
65 #include "third_party/blink/renderer/core/html/html_frame_owner_element.h"
66 #include "third_party/blink/renderer/core/html/parser/html_parser_idioms.h"
67 #include "third_party/blink/renderer/core/input/event_handler.h"
68 #include "third_party/blink/renderer/core/inspector/console_message.h"
69 #include "third_party/blink/renderer/core/inspector/inspector_trace_events.h"
70 #include "third_party/blink/renderer/core/inspector/main_thread_debugger.h"
71 #include "third_party/blink/renderer/core/loader/alternate_signed_exchange_resource_info.h"
72 #include "third_party/blink/renderer/core/loader/appcache/application_cache_host_for_frame.h"
73 #include "third_party/blink/renderer/core/loader/frame_fetch_context.h"
74 #include "third_party/blink/renderer/core/loader/frame_loader.h"
75 #include "third_party/blink/renderer/core/loader/idleness_detector.h"
76 #include "third_party/blink/renderer/core/loader/interactive_detector.h"
77 #include "third_party/blink/renderer/core/loader/mixed_content_checker.h"
78 #include "third_party/blink/renderer/core/loader/prefetched_signed_exchange_manager.h"
79 #include "third_party/blink/renderer/core/loader/preload_helper.h"
80 #include "third_party/blink/renderer/core/loader/private/frame_client_hints_preferences_context.h"
81 #include "third_party/blink/renderer/core/loader/progress_tracker.h"
82 #include "third_party/blink/renderer/core/loader/subresource_filter.h"
83 #include "third_party/blink/renderer/core/origin_trials/origin_trial_context.h"
84 #include "third_party/blink/renderer/core/page/frame_tree.h"
85 #include "third_party/blink/renderer/core/page/page.h"
86 #include "third_party/blink/renderer/core/page/scrolling/text_fragment_anchor.h"
87 #include "third_party/blink/renderer/core/probe/core_probes.h"
88 #include "third_party/blink/renderer/core/timing/dom_window_performance.h"
89 #include "third_party/blink/renderer/core/timing/window_performance.h"
90 #include "third_party/blink/renderer/core/xml/document_xslt.h"
91 #include "third_party/blink/renderer/platform/bindings/microtask.h"
92 #include "third_party/blink/renderer/platform/bindings/script_forbidden_scope.h"
93 #include "third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h"
94 #include "third_party/blink/renderer/platform/heap/heap.h"
95 #include "third_party/blink/renderer/platform/loader/cors/cors.h"
96 #include "third_party/blink/renderer/platform/loader/fetch/fetch_initiator_type_names.h"
97 #include "third_party/blink/renderer/platform/loader/fetch/fetch_parameters.h"
98 #include "third_party/blink/renderer/platform/loader/fetch/memory_cache.h"
99 #include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
100 #include "third_party/blink/renderer/platform/loader/fetch/resource_loader_options.h"
101 #include "third_party/blink/renderer/platform/loader/fetch/resource_timing_info.h"
102 #include "third_party/blink/renderer/platform/loader/fetch/source_keyed_cached_metadata_handler.h"
103 #include "third_party/blink/renderer/platform/loader/fetch/unique_identifier.h"
104 #include "third_party/blink/renderer/platform/loader/ftp_directory_listing.h"
105 #include "third_party/blink/renderer/platform/loader/static_data_navigation_body_loader.h"
106 #include "third_party/blink/renderer/platform/mhtml/archive_resource.h"
107 #include "third_party/blink/renderer/platform/mhtml/mhtml_archive.h"
108 #include "third_party/blink/renderer/platform/network/encoded_form_data.h"
109 #include "third_party/blink/renderer/platform/network/http_names.h"
110 #include "third_party/blink/renderer/platform/network/http_parsers.h"
111 #include "third_party/blink/renderer/platform/network/network_utils.h"
112 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
113 #include "third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h"
114 #include "third_party/blink/renderer/platform/web_test_support.h"
115 #include "third_party/blink/renderer/platform/weborigin/scheme_registry.h"
116 #include "third_party/blink/renderer/platform/weborigin/security_policy.h"
117 #include "third_party/blink/renderer/platform/wtf/assertions.h"
118 #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
119 #include "third_party/blink/renderer/platform/wtf/text/string_utf8_adaptor.h"
120 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
121 #include "third_party/blink/renderer/platform/wtf/vector.h"
122 
123 namespace blink {
124 
125 namespace {
CopyInitiatorOriginTrials(const WebVector<int> & initiator_origin_trial_features)126 Vector<OriginTrialFeature> CopyInitiatorOriginTrials(
127     const WebVector<int>& initiator_origin_trial_features) {
128   Vector<OriginTrialFeature> result;
129   for (auto feature : initiator_origin_trial_features) {
130     // Convert from int to OriginTrialFeature. These values are passed between
131     // blink navigations. OriginTrialFeature isn't visible outside of blink (and
132     // doesn't need to be) so the values are transferred outside of blink as
133     // ints and casted to OriginTrialFeature once being processed in blink.
134     result.push_back(static_cast<OriginTrialFeature>(feature));
135   }
136   return result;
137 }
138 
CopyForceEnabledOriginTrials(const WebVector<WebString> & force_enabled_origin_trials)139 Vector<String> CopyForceEnabledOriginTrials(
140     const WebVector<WebString>& force_enabled_origin_trials) {
141   Vector<String> result;
142   result.ReserveInitialCapacity(
143       SafeCast<wtf_size_t>(force_enabled_origin_trials.size()));
144   for (const auto& trial : force_enabled_origin_trials)
145     result.push_back(trial);
146   return result;
147 }
148 
IsPagePopupRunningInWebTest(LocalFrame * frame)149 bool IsPagePopupRunningInWebTest(LocalFrame* frame) {
150   return frame && frame->GetPage()->GetChromeClient().IsPopup() &&
151          WebTestSupport::IsRunningWebTest();
152 }
153 
154 }  // namespace
155 
DocumentLoader(LocalFrame * frame,WebNavigationType navigation_type,ContentSecurityPolicy * content_security_policy,std::unique_ptr<WebNavigationParams> navigation_params)156 DocumentLoader::DocumentLoader(
157     LocalFrame* frame,
158     WebNavigationType navigation_type,
159     ContentSecurityPolicy* content_security_policy,
160     std::unique_ptr<WebNavigationParams> navigation_params)
161     : params_(std::move(navigation_params)),
162       url_(params_->url),
163       http_method_(static_cast<String>(params_->http_method)),
164       referrer_(Referrer(params_->referrer.IsEmpty()
165                              ? Referrer::NoReferrer()
166                              : static_cast<String>(params_->referrer),
167                          params_->referrer_policy)),
168       http_body_(params_->http_body),
169       http_content_type_(static_cast<String>(params_->http_content_type)),
170       origin_policy_(params_->origin_policy),
171       requestor_origin_(params_->requestor_origin),
172       unreachable_url_(params_->unreachable_url),
173       ip_address_space_(params_->ip_address_space),
174       grant_load_local_resources_(params_->grant_load_local_resources),
175       force_fetch_cache_mode_(params_->force_fetch_cache_mode),
176       frame_policy_(params_->frame_policy.value_or(FramePolicy())),
177       frame_(frame),
178       // For back/forward navigations, the browser passed a history item to use
179       // at commit time in |params_|. Set it as the current history item of this
180       // DocumentLoader. For other navigations, |history_item_| will be created
181       // when the FrameLoader calls SetHistoryItemStateForCommit.
182       history_item_(IsBackForwardLoadType(params_->frame_load_type)
183                         ? params_->history_item
184                         : nullptr),
185       original_url_(params_->url),
186       original_referrer_(referrer_),
187       response_(params_->response.ToResourceResponse()),
188       load_type_(params_->frame_load_type),
189       is_client_redirect_(params_->is_client_redirect),
190       // TODO(japhet): This is needed because the browser process DCHECKs if the
191       // first entry we commit in a new frame has replacement set. It's unclear
192       // whether the DCHECK is right, investigate removing this special case.
193       // TODO(dgozman): we should get rid of this boolean field, and make client
194       // responsible for it's own view of "replaces current item", based on the
195       // frame load type.
196       replaces_current_history_item_(
197           load_type_ == WebFrameLoadType::kReplaceCurrentItem &&
198           (!frame_->Loader().Opener() || !url_.IsEmpty())),
199       data_received_(false),
200       // The input CSP is null when the CSP check done in the FrameLoader failed
201       content_security_policy_(
202           content_security_policy
203               ? content_security_policy
204               : MakeGarbageCollected<ContentSecurityPolicy>()),
205       was_blocked_by_csp_(!content_security_policy),
206       // Loading the document was blocked by the CSP check. Pretend that this
207       // was an empty document instead and don't reuse the original URL. More
208       // details in: https://crbug.com/622385.
209       // TODO(https://crbug.com/555418) Remove this once XFO moves to the
210       // browser.
211 
212       // Update |origin_to_commit_| to contain an opaque origin with precursor
213       // information that is consistent with the final request URL.
214       // Note: this doesn't use |url_| for the origin calculation, because
215       // redirects are not yet accounted for (this happens later in
216       // StartLoadingInternal).
217       origin_to_commit_(
218           was_blocked_by_csp_
219               ? blink::SecurityOrigin::Create(response_.CurrentRequestUrl())
220                     ->DeriveNewOpaqueOrigin()
221               : params_->origin_to_commit.IsNull()
222                     ? nullptr
223                     : params_->origin_to_commit.Get()->IsolatedCopy()),
224       navigation_type_(navigation_type),
225       document_load_timing_(*this),
226       service_worker_network_provider_(
227           std::move(params_->service_worker_network_provider)),
228       was_blocked_by_document_policy_(false),
229       state_(kNotStarted),
230       in_commit_data_(false),
231       data_buffer_(SharedBuffer::Create()),
232       devtools_navigation_token_(params_->devtools_navigation_token),
233       had_sticky_activation_(params_->is_user_activated),
234       had_transient_activation_(
235           LocalFrame::HasTransientUserActivation(frame_) ||
236           params_->had_transient_activation),
237       is_browser_initiated_(params_->is_browser_initiated),
238       was_discarded_(params_->was_discarded),
239       loading_srcdoc_(url_.IsAboutSrcdocURL()),
240       loading_url_as_empty_document_(!params_->is_static_data &&
241                                      WillLoadUrlAsEmpty(url_)),
242       web_bundle_physical_url_(params_->web_bundle_physical_url),
243       web_bundle_claimed_url_(params_->web_bundle_claimed_url),
244       ukm_source_id_(params_->document_ukm_source_id),
245       clock_(params_->tick_clock ? params_->tick_clock
246                                  : base::DefaultTickClock::GetInstance()),
247       initiator_origin_trial_features_(
248           CopyInitiatorOriginTrials(params_->initiator_origin_trial_features)),
249       force_enabled_origin_trials_(
250           CopyForceEnabledOriginTrials(params_->force_enabled_origin_trials)),
251       origin_isolated_(params_->origin_isolated),
252       is_cross_browsing_context_group_navigation_(
253           params_->is_cross_browsing_context_group_navigation) {
254   DCHECK(frame_);
255 
256   // See `archive_` attribute documentation.
257   if (!frame_->IsMainFrame()) {
258     if (auto* parent = DynamicTo<LocalFrame>(frame_->Tree().Parent()))
259       archive_ = parent->Loader().GetDocumentLoader()->archive_;
260   }
261 
262   // Determine if this document should have a text fragment permission token.
263   // We can either generate a new one from this navigation, if it's user
264   // activated, or receive one propagated from the prior navigation that didn't
265   // consume its token.
266   has_text_fragment_token_ = TextFragmentAnchor::GenerateNewToken(*this) ||
267                              params_->has_text_fragment_token;
268 
269   if (frame_->IsMainFrame()) {
270     previews_state_ = params_->previews_state;
271   } else {
272     // Subframes inherit previews state from the main frame.
273     if (auto* parent = DynamicTo<LocalFrame>(frame_->Tree().Parent()))
274       previews_state_ = parent->Loader().GetDocumentLoader()->previews_state_;
275   }
276 
277   document_policy_ = CreateDocumentPolicy();
278 
279   WebNavigationTimings& timings = params_->navigation_timings;
280   if (!timings.input_start.is_null())
281     document_load_timing_.SetInputStart(timings.input_start);
282   if (timings.navigation_start.is_null()) {
283     // If we don't have any navigation timings yet, it starts now.
284     document_load_timing_.SetNavigationStart(clock_->NowTicks());
285   } else {
286     document_load_timing_.SetNavigationStart(timings.navigation_start);
287     if (!timings.redirect_start.is_null()) {
288       document_load_timing_.SetRedirectStart(timings.redirect_start);
289       document_load_timing_.SetRedirectEnd(timings.redirect_end);
290     }
291     if (!timings.fetch_start.is_null()) {
292       // If we started fetching, we should have started the navigation.
293       DCHECK(!timings.navigation_start.is_null());
294       document_load_timing_.SetFetchStart(timings.fetch_start);
295     }
296   }
297 
298   // The document URL needs to be added to the head of the list as that is
299   // where the redirects originated.
300   if (is_client_redirect_)
301     redirect_chain_.push_back(frame_->GetDocument()->Url());
302 
303   if (was_blocked_by_csp_ || was_blocked_by_document_policy_)
304     ReplaceWithEmptyDocument();
305 
306   if (commit_reason_ != CommitReason::kInitialization)
307     redirect_chain_.push_back(url_);
308 
309   if (IsBackForwardLoadType(params_->frame_load_type))
310     DCHECK(history_item_);
311 }
312 
GetFrameLoader() const313 FrameLoader& DocumentLoader::GetFrameLoader() const {
314   DCHECK(frame_);
315   return frame_->Loader();
316 }
317 
GetLocalFrameClient() const318 LocalFrameClient& DocumentLoader::GetLocalFrameClient() const {
319   DCHECK(frame_);
320   LocalFrameClient* client = frame_->Client();
321   // LocalFrame clears its |m_client| only after detaching all DocumentLoaders
322   // (i.e. calls detachFromFrame() which clears |frame_|) owned by the
323   // LocalFrame's FrameLoader. So, if |frame_| is non nullptr, |client| is
324   // also non nullptr.
325   DCHECK(client);
326   return *client;
327 }
328 
~DocumentLoader()329 DocumentLoader::~DocumentLoader() {
330   DCHECK(!frame_);
331   DCHECK(!application_cache_host_);
332   DCHECK_EQ(state_, kSentDidFinishLoad);
333 }
334 
Trace(Visitor * visitor) const335 void DocumentLoader::Trace(Visitor* visitor) const {
336   visitor->Trace(archive_);
337   visitor->Trace(frame_);
338   visitor->Trace(history_item_);
339   visitor->Trace(parser_);
340   visitor->Trace(subresource_filter_);
341   visitor->Trace(resource_loading_hints_);
342   visitor->Trace(document_load_timing_);
343   visitor->Trace(application_cache_host_);
344   visitor->Trace(content_security_policy_);
345   visitor->Trace(cached_metadata_handler_);
346   visitor->Trace(prefetched_signed_exchange_manager_);
347   visitor->Trace(use_counter_);
348 }
349 
MainResourceIdentifier() const350 uint64_t DocumentLoader::MainResourceIdentifier() const {
351   return main_resource_identifier_;
352 }
353 
GetNavigationTimingInfo() const354 ResourceTimingInfo* DocumentLoader::GetNavigationTimingInfo() const {
355   return navigation_timing_info_.get();
356 }
357 
OriginalUrl() const358 const KURL& DocumentLoader::OriginalUrl() const {
359   return original_url_;
360 }
361 
OriginalReferrer() const362 const Referrer& DocumentLoader::OriginalReferrer() const {
363   return original_referrer_;
364 }
365 
SetSubresourceFilter(SubresourceFilter * subresource_filter)366 void DocumentLoader::SetSubresourceFilter(
367     SubresourceFilter* subresource_filter) {
368   subresource_filter_ = subresource_filter;
369 }
370 
Url() const371 const KURL& DocumentLoader::Url() const {
372   return url_;
373 }
374 
HttpMethod() const375 const AtomicString& DocumentLoader::HttpMethod() const {
376   return http_method_;
377 }
378 
GetReferrer() const379 const Referrer& DocumentLoader::GetReferrer() const {
380   return referrer_;
381 }
382 
SetServiceWorkerNetworkProvider(std::unique_ptr<WebServiceWorkerNetworkProvider> provider)383 void DocumentLoader::SetServiceWorkerNetworkProvider(
384     std::unique_ptr<WebServiceWorkerNetworkProvider> provider) {
385   service_worker_network_provider_ = std::move(provider);
386 }
387 
DispatchLinkHeaderPreloads(const ViewportDescription * viewport,PreloadHelper::MediaPreloadPolicy media_policy)388 void DocumentLoader::DispatchLinkHeaderPreloads(
389     const ViewportDescription* viewport,
390     PreloadHelper::MediaPreloadPolicy media_policy) {
391   DCHECK_GE(state_, kCommitted);
392   PreloadHelper::LoadLinksFromHeader(
393       GetResponse().HttpHeaderField(http_names::kLink),
394       GetResponse().CurrentRequestUrl(), *frame_, frame_->GetDocument(),
395       PreloadHelper::kOnlyLoadResources, media_policy, viewport,
396       nullptr /* alternate_resource_info */,
397       nullptr /* recursive_prefetch_token */);
398 }
399 
DidChangePerformanceTiming()400 void DocumentLoader::DidChangePerformanceTiming() {
401   if (frame_ && state_ >= kCommitted) {
402     GetLocalFrameClient().DidChangePerformanceTiming();
403   }
404 }
405 
DidObserveInputDelay(base::TimeDelta input_delay)406 void DocumentLoader::DidObserveInputDelay(base::TimeDelta input_delay) {
407   if (frame_ && state_ >= kCommitted) {
408     GetLocalFrameClient().DidObserveInputDelay(input_delay);
409   }
410 }
DidObserveLoadingBehavior(LoadingBehaviorFlag behavior)411 void DocumentLoader::DidObserveLoadingBehavior(LoadingBehaviorFlag behavior) {
412   if (frame_) {
413     DCHECK_GE(state_, kCommitted);
414     GetLocalFrameClient().DidObserveLoadingBehavior(behavior);
415   }
416 }
417 
418 // static
LoadTypeToCommitType(WebFrameLoadType type)419 WebHistoryCommitType LoadTypeToCommitType(WebFrameLoadType type) {
420   switch (type) {
421     case WebFrameLoadType::kStandard:
422       return kWebStandardCommit;
423     case WebFrameLoadType::kBackForward:
424       return kWebBackForwardCommit;
425     case WebFrameLoadType::kReload:
426     case WebFrameLoadType::kReplaceCurrentItem:
427     case WebFrameLoadType::kReloadBypassingCache:
428       return kWebHistoryInertCommit;
429   }
430   NOTREACHED();
431   return kWebHistoryInertCommit;
432 }
433 
CategorizeSinglePageAppNavigation(SameDocumentNavigationSource same_document_navigation_source,WebFrameLoadType frame_load_type)434 static SinglePageAppNavigationType CategorizeSinglePageAppNavigation(
435     SameDocumentNavigationSource same_document_navigation_source,
436     WebFrameLoadType frame_load_type) {
437   // |SinglePageAppNavigationType| falls into this grid according to different
438   // combinations of |WebFrameLoadType| and |SameDocumentNavigationSource|:
439   //
440   //                 HistoryApi           Default
441   //  kBackForward   illegal              otherFragmentNav
442   // !kBackForward   sameDocBack/Forward  historyPushOrReplace
443   switch (same_document_navigation_source) {
444     case kSameDocumentNavigationDefault:
445       if (frame_load_type == WebFrameLoadType::kBackForward) {
446         return kSPANavTypeSameDocumentBackwardOrForward;
447       }
448       return kSPANavTypeOtherFragmentNavigation;
449     case kSameDocumentNavigationHistoryApi:
450       // It's illegal to have both kSameDocumentNavigationHistoryApi and
451       // WebFrameLoadType::kBackForward.
452       DCHECK(frame_load_type != WebFrameLoadType::kBackForward);
453       return kSPANavTypeHistoryPushStateOrReplaceState;
454   }
455   NOTREACHED();
456   return kSPANavTypeSameDocumentBackwardOrForward;
457 }
458 
UpdateForSameDocumentNavigation(const KURL & new_url,SameDocumentNavigationSource same_document_navigation_source,scoped_refptr<SerializedScriptValue> data,mojom::blink::ScrollRestorationType scroll_restoration_type,WebFrameLoadType type,bool is_content_initiated)459 void DocumentLoader::UpdateForSameDocumentNavigation(
460     const KURL& new_url,
461     SameDocumentNavigationSource same_document_navigation_source,
462     scoped_refptr<SerializedScriptValue> data,
463     mojom::blink::ScrollRestorationType scroll_restoration_type,
464     WebFrameLoadType type,
465     bool is_content_initiated) {
466   SinglePageAppNavigationType single_page_app_navigation_type =
467       CategorizeSinglePageAppNavigation(same_document_navigation_source, type);
468   UMA_HISTOGRAM_ENUMERATION(
469       "RendererScheduler.UpdateForSameDocumentNavigationCount",
470       single_page_app_navigation_type, kSPANavTypeCount);
471 
472   TRACE_EVENT1("blink", "FrameLoader::updateForSameDocumentNavigation", "url",
473                new_url.GetString().Ascii());
474 
475   // Generate start and stop notifications only when loader is completed so that
476   // we don't fire them for fragment redirection that happens in window.onload
477   // handler. See https://bugs.webkit.org/show_bug.cgi?id=31838
478   // Do not fire the notifications if the frame is concurrently navigating away
479   // from the document, since a new document is already loading.
480   bool was_loading = frame_->IsLoading();
481   if (!was_loading)
482     GetLocalFrameClient().DidStartLoading();
483 
484   // Update the data source's request with the new URL to fake the URL change
485   frame_->GetDocument()->SetURL(new_url);
486 
487   KURL old_url = url_;
488   original_url_ = new_url;
489   url_ = new_url;
490   replaces_current_history_item_ = type != WebFrameLoadType::kStandard;
491   if (same_document_navigation_source == kSameDocumentNavigationHistoryApi) {
492     http_method_ = http_names::kGET;
493     http_body_ = nullptr;
494   }
495   redirect_chain_.clear();
496   if (is_client_redirect_)
497     redirect_chain_.push_back(old_url);
498   redirect_chain_.push_back(new_url);
499 
500   // We want to allow same-document text fragment navigations if they're coming
501   // from the browser. Do this only on a standard navigation so that we don't
502   // clobber the token when this is called from e.g. history.replaceState.
503   if (type == WebFrameLoadType::kStandard) {
504     has_text_fragment_token_ =
505         TextFragmentAnchor::GenerateNewTokenForSameDocument(
506             new_url.FragmentIdentifier(), type, is_content_initiated,
507             same_document_navigation_source);
508   }
509 
510   SetHistoryItemStateForCommit(
511       history_item_.Get(), type,
512       same_document_navigation_source == kSameDocumentNavigationHistoryApi
513           ? HistoryNavigationType::kHistoryApi
514           : HistoryNavigationType::kFragment);
515   history_item_->SetDocumentState(frame_->GetDocument()->GetDocumentState());
516   if (same_document_navigation_source == kSameDocumentNavigationHistoryApi) {
517     history_item_->SetStateObject(std::move(data));
518     history_item_->SetScrollRestorationType(scroll_restoration_type);
519   }
520   WebHistoryCommitType commit_type = LoadTypeToCommitType(type);
521   frame_->GetFrameScheduler()->DidCommitProvisionalLoad(
522       commit_type == kWebHistoryInertCommit,
523       FrameScheduler::NavigationType::kSameDocument);
524 
525   GetLocalFrameClient().DidFinishSameDocumentNavigation(
526       history_item_.Get(), commit_type, is_content_initiated);
527   probe::DidNavigateWithinDocument(frame_);
528   if (!was_loading) {
529     GetLocalFrameClient().DidStopLoading();
530     frame_->UpdateFaviconURL();
531   }
532 }
533 
UrlForHistory() const534 const KURL& DocumentLoader::UrlForHistory() const {
535   return UnreachableURL().IsEmpty() ? Url() : UnreachableURL();
536 }
537 
SetHistoryItemStateForCommit(HistoryItem * old_item,WebFrameLoadType load_type,HistoryNavigationType navigation_type)538 void DocumentLoader::SetHistoryItemStateForCommit(
539     HistoryItem* old_item,
540     WebFrameLoadType load_type,
541     HistoryNavigationType navigation_type) {
542   if (!history_item_ || !IsBackForwardLoadType(load_type))
543     history_item_ = MakeGarbageCollected<HistoryItem>();
544 
545   history_item_->SetURL(UrlForHistory());
546   history_item_->SetReferrer(SecurityPolicy::GenerateReferrer(
547       referrer_.referrer_policy, history_item_->Url(), referrer_.referrer));
548   if (EqualIgnoringASCIICase(http_method_, "POST")) {
549     // FIXME: Eventually we have to make this smart enough to handle the case
550     // where we have a stream for the body to handle the "data interspersed with
551     // files" feature.
552     history_item_->SetFormData(http_body_);
553     history_item_->SetFormContentType(http_content_type_);
554   } else {
555     history_item_->SetFormData(nullptr);
556     history_item_->SetFormContentType(g_null_atom);
557   }
558 
559   // Don't propagate state from the old item to the new item if there isn't an
560   // old item (obviously), or if this is a back/forward navigation, since we
561   // explicitly want to restore the state we just committed.
562   if (!old_item || IsBackForwardLoadType(load_type))
563     return;
564   // Don't propagate state from the old item if this is a different-document
565   // navigation, unless the before and after pages are logically related. This
566   // means they have the same url (ignoring fragment) and the new item was
567   // loaded via reload or client redirect.
568   WebHistoryCommitType history_commit_type = LoadTypeToCommitType(load_type);
569   if (navigation_type == HistoryNavigationType::kDifferentDocument &&
570       (history_commit_type != kWebHistoryInertCommit ||
571        !EqualIgnoringFragmentIdentifier(old_item->Url(), history_item_->Url())))
572     return;
573   history_item_->SetDocumentSequenceNumber(old_item->DocumentSequenceNumber());
574 
575   history_item_->CopyViewStateFrom(old_item);
576   history_item_->SetScrollRestorationType(old_item->ScrollRestorationType());
577 
578   // The item sequence number determines whether items are "the same", such
579   // back/forward navigation between items with the same item sequence number is
580   // a no-op. Only treat this as identical if the navigation did not create a
581   // back/forward entry and the url is identical or it was loaded via
582   // history.replaceState().
583   if (history_commit_type == kWebHistoryInertCommit &&
584       (navigation_type == HistoryNavigationType::kHistoryApi ||
585        old_item->Url() == history_item_->Url())) {
586     history_item_->SetStateObject(old_item->StateObject());
587     history_item_->SetItemSequenceNumber(old_item->ItemSequenceNumber());
588   }
589 }
590 
591 mojo::PendingReceiver<mojom::blink::WorkerTimingContainer>
TakePendingWorkerTimingReceiver(int request_id)592 DocumentLoader::TakePendingWorkerTimingReceiver(int request_id) {
593   if (!GetServiceWorkerNetworkProvider())
594     return mojo::NullReceiver();
595   return GetServiceWorkerNetworkProvider()->TakePendingWorkerTimingReceiver(
596       request_id);
597 }
598 
BodyCodeCacheReceived(mojo_base::BigBuffer data)599 void DocumentLoader::BodyCodeCacheReceived(mojo_base::BigBuffer data) {
600   if (cached_metadata_handler_) {
601     cached_metadata_handler_->SetSerializedCachedMetadata(std::move(data));
602   }
603 }
604 
BodyDataReceived(base::span<const char> data)605 void DocumentLoader::BodyDataReceived(base::span<const char> data) {
606   TRACE_EVENT0("loading", "DocumentLoader::BodyDataReceived");
607   GetFrameLoader().Progress().IncrementProgress(main_resource_identifier_,
608                                                 data.size());
609   probe::DidReceiveData(probe::ToCoreProbeSink(GetFrame()),
610                         main_resource_identifier_, this, data.data(),
611                         data.size());
612 
613   TRACE_EVENT1("loading", "DocumentLoader::HandleData", "length", data.size());
614 
615   DCHECK(data.data());
616   DCHECK(data.size());
617   DCHECK(!frame_->GetPage()->Paused());
618   time_of_last_data_received_ = clock_->NowTicks();
619 
620   if (listing_ftp_directory_ || loading_main_document_from_mhtml_archive_) {
621     // 1) Ftp directory listings accumulate data buffer and transform it later
622     //    to the actual document content.
623     // 2) Mhtml archives accumulate data buffer and parse it as mhtml later
624     //    to retrieve the actual document content.
625     data_buffer_->Append(data.data(), data.size());
626     return;
627   }
628 
629   ProcessDataBuffer(data.data(), data.size());
630 }
631 
BodyLoadingFinished(base::TimeTicks completion_time,int64_t total_encoded_data_length,int64_t total_encoded_body_length,int64_t total_decoded_body_length,bool should_report_corb_blocking,const base::Optional<WebURLError> & error)632 void DocumentLoader::BodyLoadingFinished(
633     base::TimeTicks completion_time,
634     int64_t total_encoded_data_length,
635     int64_t total_encoded_body_length,
636     int64_t total_decoded_body_length,
637     bool should_report_corb_blocking,
638     const base::Optional<WebURLError>& error) {
639   TRACE_EVENT0("loading", "DocumentLoader::BodyLoadingFinished");
640   response_.SetEncodedDataLength(total_encoded_data_length);
641   response_.SetEncodedBodyLength(total_encoded_body_length);
642   response_.SetDecodedBodyLength(total_decoded_body_length);
643 
644   if (!error) {
645     GetFrameLoader().Progress().CompleteProgress(main_resource_identifier_);
646     probe::DidFinishLoading(
647         probe::ToCoreProbeSink(GetFrame()), main_resource_identifier_, this,
648         completion_time, total_encoded_data_length, total_decoded_body_length,
649         should_report_corb_blocking);
650     if (response_.IsHTTP()) {
651       // The response is being copied here to pass the Encoded and Decoded
652       // sizes.
653       // TODO(yoav): copy the sizes info directly.
654       navigation_timing_info_->SetFinalResponse(response_);
655       navigation_timing_info_->AddFinalTransferSize(
656           total_encoded_data_length == -1 ? 0 : total_encoded_data_length);
657       if (report_timing_info_to_parent_) {
658         navigation_timing_info_->SetLoadResponseEnd(completion_time);
659         if (state_ >= kCommitted) {
660           // Note that we currently lose timing info for empty documents,
661           // which will be fixed with synchronous commit.
662           // Main resource timing information is reported through the owner
663           // to be passed to the parent frame, if appropriate.
664 
665           // TODO(https://crbug.com/900700): Set a Mojo pending receiver for
666           // WorkerTimingContainer in |navigation_timing_info|.
667           frame_->Owner()->AddResourceTiming(*navigation_timing_info_);
668         }
669         frame_->SetShouldSendResourceTimingInfoToParent(false);
670       }
671     }
672     FinishedLoading(completion_time);
673     return;
674   }
675 
676   ResourceError resource_error(*error);
677   if (network_utils::IsCertificateTransparencyRequiredError(
678           resource_error.ErrorCode())) {
679     CountUse(WebFeature::kCertificateTransparencyRequiredErrorOnResourceLoad);
680   }
681   GetFrameLoader().Progress().CompleteProgress(main_resource_identifier_);
682   probe::DidFailLoading(probe::ToCoreProbeSink(GetFrame()),
683                         main_resource_identifier_, this, resource_error,
684                         frame_->GetDevToolsFrameToken());
685   GetFrame()->Console().DidFailLoading(this, main_resource_identifier_,
686                                        resource_error);
687   LoadFailed(resource_error);
688 }
689 
LoadFailed(const ResourceError & error)690 void DocumentLoader::LoadFailed(const ResourceError& error) {
691   TRACE_EVENT1("navigation,rail", "DocumentLoader::LoadFailed", "error",
692                error.ErrorCode());
693   body_loader_.reset();
694   virtual_time_pauser_.UnpauseVirtualTime();
695 
696   if (!error.IsCancellation() && frame_->Owner())
697     frame_->Owner()->RenderFallbackContent(frame_);
698 
699   WebHistoryCommitType history_commit_type = LoadTypeToCommitType(load_type_);
700   DCHECK_EQ(kCommitted, state_);
701   if (frame_->GetDocument()->Parser())
702     frame_->GetDocument()->Parser()->StopParsing();
703   state_ = kSentDidFinishLoad;
704   GetLocalFrameClient().DispatchDidFailLoad(error, history_commit_type);
705   GetFrameLoader().DidFinishNavigation(
706       FrameLoader::NavigationFinishState::kFailure);
707   DCHECK_EQ(kSentDidFinishLoad, state_);
708   params_ = nullptr;
709 }
710 
FinishedLoading(base::TimeTicks finish_time)711 void DocumentLoader::FinishedLoading(base::TimeTicks finish_time) {
712   body_loader_.reset();
713   virtual_time_pauser_.UnpauseVirtualTime();
714 
715   DCHECK(commit_reason_ == CommitReason::kInitialization ||
716          !frame_->GetPage()->Paused() ||
717          MainThreadDebugger::Instance()->IsPaused());
718 
719   if (listing_ftp_directory_) {
720     data_buffer_ = GenerateFtpDirectoryListingHtml(
721         response_.CurrentRequestUrl(), data_buffer_.get());
722     ProcessDataBuffer();
723   }
724 
725   if (loading_main_document_from_mhtml_archive_ && state_ < kCommitted) {
726     // The browser process should block any navigation to an MHTML archive
727     // inside iframes. See NavigationRequest::OnResponseStarted().
728     CHECK(frame_->IsMainFrame());
729 
730     archive_ = MHTMLArchive::Create(url_, std::move(data_buffer_));
731   }
732 
733   // We should not call FinishedLoading before committing navigation,
734   // except for the mhtml case. When loading an MHTML archive, the whole archive
735   // has to be validated before committing the navigation. The validation
736   // process loads the entire body of the archive, which will move the state to
737   // FinishedLoading.
738   if (!loading_main_document_from_mhtml_archive_)
739     DCHECK_GE(state_, kCommitted);
740 
741   base::TimeTicks response_end_time = finish_time;
742   if (response_end_time.is_null())
743     response_end_time = time_of_last_data_received_;
744   if (response_end_time.is_null())
745     response_end_time = clock_->NowTicks();
746   GetTiming().SetResponseEnd(response_end_time);
747 
748   if (!frame_)
749     return;
750 
751   if (parser_) {
752     if (parser_blocked_count_) {
753       finish_loading_when_parser_resumed_ = true;
754     } else {
755       parser_->Finish();
756       parser_.Clear();
757     }
758   }
759 }
760 
HandleRedirect(const KURL & current_request_url)761 void DocumentLoader::HandleRedirect(const KURL& current_request_url) {
762   // Browser process should have already checked that redirecting url is
763   // allowed to display content from the target origin.
764   // When the referrer page is in an unsigned Web Bundle file in local
765   // (eg: file:///tmp/a.wbn), Chrome internally redirects the navigation to the
766   // page (eg: https://example.com/page.html) inside the Web Bundle file
767   // to the file's URL (file:///tmp/a.wbn?https://example.com/page.html). In
768   // this case, CanDisplay() returns false, and web_bundle_claimed_url must not
769   // be null.
770   CHECK(SecurityOrigin::Create(current_request_url)->CanDisplay(url_) ||
771         !params_->web_bundle_claimed_url.IsNull());
772 
773   DCHECK(!GetTiming().FetchStart().is_null());
774   redirect_chain_.push_back(url_);
775   GetTiming().AddRedirect(current_request_url, url_);
776 }
777 
ShouldReportTimingInfoToParent()778 bool DocumentLoader::ShouldReportTimingInfoToParent() {
779   DCHECK(frame_);
780   // <iframe>s should report the initial navigation requested by the parent
781   // document, but not subsequent navigations.
782   if (!frame_->Owner())
783     return false;
784   // Note that this can be racy since this information is forwarded over IPC
785   // when crossing process boundaries.
786   if (!frame_->should_send_resource_timing_info_to_parent())
787     return false;
788   // Do not report iframe navigation that restored from history, since its
789   // location may have been changed after initial navigation,
790   if (load_type_ == WebFrameLoadType::kBackForward) {
791     // ...and do not report subsequent navigations in the iframe too.
792     frame_->SetShouldSendResourceTimingInfoToParent(false);
793     return false;
794   }
795   return true;
796 }
797 
ConsoleError(const String & message)798 void DocumentLoader::ConsoleError(const String& message) {
799   auto* console_message = MakeGarbageCollected<ConsoleMessage>(
800       mojom::ConsoleMessageSource::kSecurity,
801       mojom::ConsoleMessageLevel::kError, message,
802       response_.CurrentRequestUrl(), this, MainResourceIdentifier());
803   frame_->DomWindow()->AddConsoleMessage(console_message);
804 }
805 
ReplaceWithEmptyDocument()806 void DocumentLoader::ReplaceWithEmptyDocument() {
807   DCHECK(params_);
808   KURL blocked_url = SecurityOrigin::UrlWithUniqueOpaqueOrigin();
809   original_url_ = blocked_url;
810   url_ = blocked_url;
811   params_->url = blocked_url;
812   WebNavigationParams::FillStaticResponse(params_.get(), "text/html", "UTF-8",
813                                           "");
814 }
815 
CreateDocumentPolicy()816 DocumentPolicy::ParsedDocumentPolicy DocumentLoader::CreateDocumentPolicy() {
817   // For URLs referring to local content to parent frame, they have no way to
818   // specify the document policy they use. If the parent frame requires a
819   // document policy on them, use the required policy as effective policy.
820   if (url_.IsEmpty() || url_.ProtocolIsAbout() || url_.ProtocolIsData() ||
821       url_.ProtocolIs("blob") || url_.ProtocolIs("filesystem"))
822     return {frame_policy_.required_document_policy, {} /* endpoint_map */};
823 
824   PolicyParserMessageBuffer header_logger("Document-Policy HTTP header: ");
825   PolicyParserMessageBuffer require_header_logger(
826       "Require-Document-Policy HTTP header: ");
827 
828   // Filtering out features that are disabled by origin trial is done
829   // in SecurityContextInit when origin trial context is available.
830   auto parsed_policy =
831       DocumentPolicyParser::Parse(
832           response_.HttpHeaderField(http_names::kDocumentPolicy), header_logger)
833           .value_or(DocumentPolicy::ParsedDocumentPolicy{});
834 
835   // |parsed_policy| can have policies that are disabled by origin trial,
836   // but |frame_policy_.required_document_policy| cannot.
837   // It is safe to call |IsPolicyCompatible| as long as required policy is
838   // checked against origin trial.
839   if (!DocumentPolicy::IsPolicyCompatible(
840           frame_policy_.required_document_policy,
841           parsed_policy.feature_state)) {
842     was_blocked_by_document_policy_ = true;
843     // When header policy is less strict than required policy, use required
844     // policy to initialize document policy for the document.
845     parsed_policy = {frame_policy_.required_document_policy,
846                      {} /* endpoint_map */};
847   }
848 
849   // Initialize required document policy for subtree.
850   //
851   // If the document is blocked by document policy, there won't be content
852   // in the sub-frametree, thus no need to initialize required_policy for
853   // subtree.
854   if (!was_blocked_by_document_policy_) {
855     // Require-Document-Policy header only affects subtree of current document,
856     // but not the current document.
857     const DocumentPolicyFeatureState header_required_policy =
858         DocumentPolicyParser::Parse(
859             response_.HttpHeaderField(http_names::kRequireDocumentPolicy),
860             require_header_logger)
861             .value_or(DocumentPolicy::ParsedDocumentPolicy{})
862             .feature_state;
863     frame_->SetRequiredDocumentPolicy(DocumentPolicy::MergeFeatureState(
864         header_required_policy, frame_policy_.required_document_policy));
865   }
866 
867   document_policy_parsing_messages_.AppendVector(header_logger.GetMessages());
868   document_policy_parsing_messages_.AppendVector(
869       require_header_logger.GetMessages());
870 
871   return parsed_policy;
872 }
873 
HandleResponse()874 void DocumentLoader::HandleResponse() {
875   DCHECK(frame_);
876   application_cache_host_->DidReceiveResponseForMainResource(response_);
877 
878   if (response_.CurrentRequestUrl().ProtocolIs("ftp") &&
879       response_.MimeType() == "text/vnd.chromium.ftp-dir") {
880     if (response_.CurrentRequestUrl().Query() == "raw") {
881       // Interpret the FTP LIST command result as text.
882       response_.SetMimeType("text/plain");
883     } else {
884       // FTP directory listing: Make up an HTML for the entries.
885       listing_ftp_directory_ = true;
886       response_.SetMimeType("text/html");
887     }
888   }
889 
890   if (frame_->Owner() && response_.IsHTTP() &&
891       !cors::IsOkStatus(response_.HttpStatusCode()))
892     frame_->Owner()->RenderFallbackContent(frame_);
893 }
894 
CommitData(const char * bytes,size_t length)895 void DocumentLoader::CommitData(const char* bytes, size_t length) {
896   TRACE_EVENT1("loading", "DocumentLoader::CommitData", "length", length);
897 
898   // This can happen if document.close() is called by an event handler while
899   // there's still pending incoming data.
900   // TODO(dgozman): we should stop body loader when stopping the parser to
901   // avoid unnecessary work. This may happen, for example, when we abort current
902   // committed document which is still loading when initiating a new navigation.
903   if (!frame_ || !frame_->GetDocument()->Parsing())
904     return;
905 
906   base::AutoReset<bool> reentrancy_protector(&in_commit_data_, true);
907   if (length)
908     data_received_ = true;
909   parser_->AppendBytes(bytes, length);
910 }
911 
CommitSameDocumentNavigation(const KURL & url,WebFrameLoadType frame_load_type,HistoryItem * history_item,ClientRedirectPolicy client_redirect_policy,LocalDOMWindow * origin_window,bool has_event,std::unique_ptr<WebDocumentLoader::ExtraData> extra_data)912 mojom::CommitResult DocumentLoader::CommitSameDocumentNavigation(
913     const KURL& url,
914     WebFrameLoadType frame_load_type,
915     HistoryItem* history_item,
916     ClientRedirectPolicy client_redirect_policy,
917     LocalDOMWindow* origin_window,
918     bool has_event,
919     std::unique_ptr<WebDocumentLoader::ExtraData> extra_data) {
920   DCHECK(!IsReloadLoadType(frame_load_type));
921   DCHECK(frame_->GetDocument());
922 
923   if (Page* page = frame_->GetPage())
924     page->HistoryNavigationVirtualTimePauser().UnpauseVirtualTime();
925 
926   if (!frame_->IsNavigationAllowed())
927     return mojom::CommitResult::Aborted;
928 
929   if (!IsBackForwardLoadType(frame_load_type)) {
930     // In the case of non-history navigations, check that this is a
931     // same-document navigation. If not, the navigation should restart as a
932     // cross-document navigation.
933     if (!url.HasFragmentIdentifier() ||
934         !EqualIgnoringFragmentIdentifier(frame_->GetDocument()->Url(), url) ||
935         frame_->GetDocument()->IsFrameSet()) {
936       return mojom::CommitResult::RestartCrossDocument;
937     }
938   }
939 
940   // If the requesting document is cross-origin, perform the navigation
941   // asynchronously to minimize the navigator's ability to execute timing
942   // attacks.
943   if (origin_window && !origin_window->GetSecurityOrigin()->CanAccess(
944                            frame_->DomWindow()->GetSecurityOrigin())) {
945     frame_->GetTaskRunner(TaskType::kInternalLoading)
946         ->PostTask(
947             FROM_HERE,
948             WTF::Bind(&DocumentLoader::CommitSameDocumentNavigationInternal,
949                       WrapWeakPersistent(this), url, frame_load_type,
950                       WrapPersistent(history_item), client_redirect_policy,
951                       !!origin_window, has_event, std::move(extra_data)));
952   } else {
953     CommitSameDocumentNavigationInternal(url, frame_load_type, history_item,
954                                          client_redirect_policy, origin_window,
955                                          has_event, std::move(extra_data));
956   }
957   return mojom::CommitResult::Ok;
958 }
959 
CommitSameDocumentNavigationInternal(const KURL & url,WebFrameLoadType frame_load_type,HistoryItem * history_item,ClientRedirectPolicy client_redirect,bool is_content_initiated,bool has_event,std::unique_ptr<WebDocumentLoader::ExtraData> extra_data)960 void DocumentLoader::CommitSameDocumentNavigationInternal(
961     const KURL& url,
962     WebFrameLoadType frame_load_type,
963     HistoryItem* history_item,
964     ClientRedirectPolicy client_redirect,
965     bool is_content_initiated,
966     bool has_event,
967     std::unique_ptr<WebDocumentLoader::ExtraData> extra_data) {
968   // If this function was scheduled to run asynchronously, this DocumentLoader
969   // might have been detached before the task ran.
970   if (!frame_)
971     return;
972 
973   if (!IsBackForwardLoadType(frame_load_type)) {
974     SetNavigationType(has_event ? kWebNavigationTypeLinkClicked
975                                 : kWebNavigationTypeOther);
976     if (history_item_ && url == history_item_->Url())
977       frame_load_type = WebFrameLoadType::kReplaceCurrentItem;
978   }
979 
980   // If we have a client navigation for a different document, a fragment
981   // scroll should cancel it.
982   // Note: see fragment-change-does-not-cancel-pending-navigation, where
983   // this does not actually happen.
984   GetFrameLoader().DidFinishNavigation(
985       FrameLoader::NavigationFinishState::kSuccess);
986 
987   // GetFrameLoader().DidFinishNavigation can lead to DetachFromFrame so need
988   // to check again if frame_ is null.
989   if (!frame_ || !frame_->GetPage())
990     return;
991   GetFrameLoader().SaveScrollState();
992 
993   KURL old_url = frame_->GetDocument()->Url();
994   bool hash_change = EqualIgnoringFragmentIdentifier(url, old_url) &&
995                      url.FragmentIdentifier() != old_url.FragmentIdentifier();
996   if (hash_change) {
997     // If we were in the autoscroll/middleClickAutoscroll mode we want to stop
998     // it before following the link to the anchor
999     frame_->GetEventHandler().StopAutoscroll();
1000     frame_->DomWindow()->EnqueueHashchangeEvent(old_url, url);
1001   }
1002   is_client_redirect_ =
1003       client_redirect == ClientRedirectPolicy::kClientRedirect;
1004   bool same_item_sequence_number =
1005       history_item_ && history_item &&
1006       history_item_->ItemSequenceNumber() == history_item->ItemSequenceNumber();
1007   if (history_item)
1008     history_item_ = history_item;
1009   if (extra_data)
1010     GetLocalFrameClient().UpdateDocumentLoader(this, std::move(extra_data));
1011   UpdateForSameDocumentNavigation(url, kSameDocumentNavigationDefault, nullptr,
1012                                   mojom::blink::ScrollRestorationType::kAuto,
1013                                   frame_load_type, is_content_initiated);
1014 
1015   initial_scroll_state_.was_scrolled_by_user = false;
1016 
1017   frame_->GetDocument()->CheckCompleted();
1018 
1019   // If the item sequence number didn't change, there's no need to trigger
1020   // popstate, restore scroll positions, or scroll to fragments for this
1021   // same-document navigation.  It's possible to get a same-document navigation
1022   // to a same ISN when a history navigation targets a frame that no longer
1023   // exists (https://crbug.com/705550).
1024   if (!same_item_sequence_number) {
1025     GetFrameLoader().DidFinishSameDocumentNavigation(url, frame_load_type,
1026                                                      history_item);
1027   }
1028 }
1029 
ProcessDataBuffer(const char * bytes,size_t length)1030 void DocumentLoader::ProcessDataBuffer(const char* bytes, size_t length) {
1031   DCHECK_GE(state_, kCommitted);
1032   if (parser_blocked_count_ || in_commit_data_) {
1033     // 1) If parser is blocked, we buffer data and process it upon resume.
1034     // 2) If this function is reentered, we defer processing of the additional
1035     //    data to the top-level invocation. Reentrant calls can occur because
1036     //    of web platform (mis-)features that require running a nested run loop:
1037     //    - alert(), confirm(), prompt()
1038     //    - Detach of plugin elements.
1039     //    - Synchronous XMLHTTPRequest
1040     if (bytes)
1041       data_buffer_->Append(bytes, length);
1042     return;
1043   }
1044 
1045   if (bytes)
1046     CommitData(bytes, length);
1047   // Process data received in reentrant invocations. Note that the invocations
1048   // of CommitData() may queue more data in reentrant invocations, so iterate
1049   // until it's empty.
1050   for (const auto& span : *data_buffer_)
1051     CommitData(span.data(), span.size());
1052   // All data has been consumed, so flush the buffer.
1053   data_buffer_->Clear();
1054 }
1055 
StopLoading()1056 void DocumentLoader::StopLoading() {
1057   if (frame_ && GetFrameLoader().GetDocumentLoader() == this)
1058     frame_->GetDocument()->Fetcher()->StopFetching();
1059   body_loader_.reset();
1060   virtual_time_pauser_.UnpauseVirtualTime();
1061   if (!SentDidFinishLoad())
1062     LoadFailed(ResourceError::CancelledError(Url()));
1063 }
1064 
SetDefersLoading(WebURLLoader::DeferType defers)1065 void DocumentLoader::SetDefersLoading(WebURLLoader::DeferType defers) {
1066   defers_loading_ = defers;
1067   if (body_loader_)
1068     body_loader_->SetDefersLoading(defers);
1069 }
1070 
DetachFromFrame(bool flush_microtask_queue)1071 void DocumentLoader::DetachFromFrame(bool flush_microtask_queue) {
1072   DCHECK(frame_);
1073   StopLoading();
1074   if (flush_microtask_queue) {
1075     // Flush microtask queue so that they all run on pre-navigation context.
1076     // TODO(dcheng): This is a temporary hack that should be removed. This is
1077     // only here because it's currently not possible to drop the microtasks
1078     // queued for a Document when the Document is navigated away; instead, the
1079     // entire microtask queue needs to be flushed. Unfortunately, running the
1080     // microtasks any later results in violating internal invariants, since
1081     // Blink does not expect the DocumentLoader for a not-yet-detached Document
1082     // to be null. It is also not possible to flush microtasks any earlier,
1083     // since flushing microtasks can only be done after any other JS (which can
1084     // queue additional microtasks) has run. Once it is possible to associate
1085     // microtasks with a v8::Context, remove this hack.
1086     Microtask::PerformCheckpoint(V8PerIsolateData::MainThreadIsolate());
1087   }
1088   ScriptForbiddenScope forbid_scripts;
1089 
1090   // If that load cancellation triggered another detach, leave.
1091   // (fast/frames/detach-frame-nested-no-crash.html is an example of this.)
1092   if (!frame_)
1093     return;
1094 
1095   if (application_cache_host_) {
1096     application_cache_host_->Detach();
1097     application_cache_host_.Clear();
1098   }
1099   service_worker_network_provider_ = nullptr;
1100   WeakIdentifierMap<DocumentLoader>::NotifyObjectDestroyed(this);
1101   frame_ = nullptr;
1102 }
1103 
UnreachableURL() const1104 const KURL& DocumentLoader::UnreachableURL() const {
1105   return unreachable_url_;
1106 }
1107 
1108 const base::Optional<blink::mojom::FetchCacheMode>&
ForceFetchCacheMode() const1109 DocumentLoader::ForceFetchCacheMode() const {
1110   return force_fetch_cache_mode_;
1111 }
1112 
WillLoadUrlAsEmpty(const KURL & url)1113 bool DocumentLoader::WillLoadUrlAsEmpty(const KURL& url) {
1114   if (url.IsEmpty())
1115     return true;
1116   // Usually, we load urls with about: scheme as empty.
1117   // However, about:srcdoc is only used as a marker for non-existent
1118   // url of iframes with srcdoc attribute, which have possibly non-empty
1119   // content of the srcdoc attribute used as document's html.
1120   if (url.IsAboutSrcdocURL())
1121     return false;
1122   return SchemeRegistry::ShouldLoadURLSchemeAsEmptyDocument(url.Protocol());
1123 }
1124 
InitializeEmptyResponse()1125 void DocumentLoader::InitializeEmptyResponse() {
1126   response_ = ResourceResponse(url_);
1127   response_.SetMimeType("text/html");
1128   response_.SetTextEncodingName("utf-8");
1129 }
1130 
StartLoading()1131 void DocumentLoader::StartLoading() {
1132   probe::LifecycleEvent(frame_, this, "init",
1133                         base::TimeTicks::Now().since_origin().InSecondsF());
1134   StartLoadingInternal();
1135   params_ = nullptr;
1136 }
1137 
StartLoadingInternal()1138 void DocumentLoader::StartLoadingInternal() {
1139   GetTiming().MarkNavigationStart();
1140   DCHECK_EQ(state_, kNotStarted);
1141   DCHECK(params_);
1142   state_ = kProvisional;
1143   application_cache_host_ = MakeGarbageCollected<ApplicationCacheHostForFrame>(
1144       this, GetFrame()->Client()->GetBrowserInterfaceBroker(),
1145       GetFrame()->GetTaskRunner(TaskType::kNetworking),
1146       params_->appcache_host_id);
1147 
1148   if (url_.IsEmpty() && commit_reason_ != CommitReason::kInitialization)
1149     url_ = BlankURL();
1150 
1151   if (loading_url_as_empty_document_) {
1152     InitializeEmptyResponse();
1153     return;
1154   }
1155 
1156   body_loader_ = std::move(params_->body_loader);
1157   DCHECK(body_loader_);
1158   DCHECK(!GetTiming().NavigationStart().is_null());
1159   // The fetch has already started in the browser,
1160   // so we don't MarkFetchStart here.
1161   main_resource_identifier_ = CreateUniqueIdentifier();
1162 
1163   navigation_timing_info_ = ResourceTimingInfo::Create(
1164       fetch_initiator_type_names::kDocument, GetTiming().NavigationStart(),
1165       mojom::blink::RequestContextType::IFRAME,
1166       network::mojom::RequestDestination::kIframe);
1167   navigation_timing_info_->SetInitialURL(url_);
1168   report_timing_info_to_parent_ = ShouldReportTimingInfoToParent();
1169 
1170   virtual_time_pauser_ =
1171       frame_->GetFrameScheduler()->CreateWebScopedVirtualTimePauser(
1172           url_.GetString(),
1173           WebScopedVirtualTimePauser::VirtualTaskDuration::kNonInstant);
1174   virtual_time_pauser_.PauseVirtualTime();
1175 
1176   if (!archive_) {
1177     application_cache_host_->WillStartLoadingMainResource(this, url_,
1178                                                           http_method_);
1179   }
1180 
1181   // Many parties are interested in resource loading, so we will notify
1182   // them through various DispatchXXX methods on FrameFetchContext.
1183 
1184   GetFrameLoader().Progress().WillStartLoading(main_resource_identifier_,
1185                                                ResourceLoadPriority::kVeryHigh);
1186   probe::WillSendNavigationRequest(probe::ToCoreProbeSink(GetFrame()),
1187                                    main_resource_identifier_, this, url_,
1188                                    http_method_, http_body_.get());
1189 
1190   for (size_t i = 0; i < params_->redirects.size(); ++i) {
1191     WebNavigationParams::RedirectInfo& redirect = params_->redirects[i];
1192     url_ = redirect.new_url;
1193     AtomicString new_http_method = redirect.new_http_method;
1194     if (http_method_ != new_http_method) {
1195       http_body_ = nullptr;
1196       http_content_type_ = g_null_atom;
1197       http_method_ = new_http_method;
1198     }
1199     if (redirect.new_referrer.IsEmpty()) {
1200       referrer_ =
1201           Referrer(Referrer::NoReferrer(), redirect.new_referrer_policy);
1202     } else {
1203       referrer_ = Referrer(redirect.new_referrer, redirect.new_referrer_policy);
1204     }
1205 
1206     // TODO(dgozman): check whether clearing origin policy is intended behavior.
1207     origin_policy_ = base::nullopt;
1208     probe::WillSendNavigationRequest(probe::ToCoreProbeSink(GetFrame()),
1209                                      main_resource_identifier_, this, url_,
1210                                      http_method_, http_body_.get());
1211     ResourceResponse redirect_response =
1212         redirect.redirect_response.ToResourceResponse();
1213     navigation_timing_info_->AddRedirect(redirect_response, url_);
1214     HandleRedirect(redirect_response.CurrentRequestUrl());
1215   }
1216 
1217   if (!frame_->IsMainFrame()) {
1218     // We only care about detecting embedded private subresources.
1219     //
1220     // TODO(crbug.com/1129326): Revisit this when we have a coherent story for
1221     // top-level navigations.
1222     MixedContentChecker::CheckMixedPrivatePublic(frame_, response_);
1223   }
1224 
1225   ApplyClientHintsConfig(params_->enabled_client_hints);
1226   PreloadHelper::LoadLinksFromHeader(
1227       response_.HttpHeaderField(http_names::kLink),
1228       response_.CurrentRequestUrl(), *GetFrame(), nullptr,
1229       PreloadHelper::kDoNotLoadResources, PreloadHelper::kLoadAll,
1230       nullptr /* viewport_description */, nullptr /* alternate_resource_info */,
1231       nullptr /* recursive_prefetch_token */);
1232   if (!frame_->IsMainFrame() && response_.HasMajorCertificateErrors()) {
1233     MixedContentChecker::HandleCertificateError(
1234         response_, mojom::blink::RequestContextType::HYPERLINK,
1235         MixedContentChecker::DecideCheckModeForPlugin(
1236             GetFrame()->GetSettings()),
1237         GetContentSecurityNotifier());
1238   }
1239   GetFrameLoader().Progress().IncrementProgress(main_resource_identifier_,
1240                                                 response_);
1241   probe::DidReceiveResourceResponse(probe::ToCoreProbeSink(GetFrame()),
1242                                     main_resource_identifier_, this, response_,
1243                                     nullptr /* resource */);
1244 
1245   HandleResponse();
1246 
1247   loading_main_document_from_mhtml_archive_ =
1248       EqualIgnoringASCIICase("multipart/related", response_.MimeType()) ||
1249       EqualIgnoringASCIICase("message/rfc822", response_.MimeType());
1250   if (loading_main_document_from_mhtml_archive_) {
1251     // The browser process should block any navigation to an MHTML archive
1252     // inside iframes. See NavigationRequest::OnResponseStarted().
1253     CHECK(frame_->IsMainFrame());
1254 
1255     // To commit an mhtml archive synchronously we have to load the whole body
1256     // synchronously and parse it, and it's already loaded in a buffer usually.
1257     // This means we should not defer, and we'll finish loading synchronously
1258     // from StartLoadingBody().
1259     body_loader_->StartLoadingBody(this, false /* use_isolated_code_cache */);
1260     return;
1261   }
1262 
1263   InitializePrefetchedSignedExchangeManager();
1264 
1265   body_loader_->SetDefersLoading(defers_loading_);
1266 }
1267 
StartLoadingResponse()1268 void DocumentLoader::StartLoadingResponse() {
1269   if (!frame_)
1270     return;
1271 
1272   CHECK_GE(state_, kCommitted);
1273 
1274   // Let the browser process know about all the CSP applied to the document.
1275   // The browser process is enforcing several directives. It needs to know about
1276   // 'frame-src', 'child-src', 'navigate-to', 'upgrade-insecure-request', etc.
1277   //
1278   // It is important to forward all the CSP data before loading the response
1279   // body, otherwise some loaded content might not be blocked.
1280   frame_->DomWindow()->GetContentSecurityPolicy()->ReportAccumulatedHeaders();
1281 
1282   CreateParserPostCommit();
1283 
1284   // The main document from an MHTML archive is not loaded from its HTTP
1285   // response, but from the main resource within the archive (in the response).
1286   if (loading_main_document_from_mhtml_archive_) {
1287     // If the `archive_` contains a main resource, load the main document from
1288     // the archive, else it will remain empty.
1289     if (ArchiveResource* resource = archive_->MainResource()) {
1290       DCHECK_EQ(archive_->LoadResult(),
1291                 mojom::blink::MHTMLLoadResult::kSuccess);
1292 
1293       data_buffer_ = resource->Data();
1294       ProcessDataBuffer();
1295       FinishedLoading(base::TimeTicks::Now());
1296       return;
1297     }
1298 
1299     // Log attempts loading a malformed archive.
1300     DCHECK_NE(archive_->LoadResult(), mojom::blink::MHTMLLoadResult::kSuccess);
1301     frame_->Console().AddMessage(MakeGarbageCollected<ConsoleMessage>(
1302         mojom::blink::ConsoleMessageSource::kJavaScript,
1303         mojom::blink::ConsoleMessageLevel::kError,
1304         "Malformed multipart archive: " + url_.GetString()));
1305     FinishedLoading(base::TimeTicks::Now());
1306     return;
1307   }
1308 
1309   // Empty documents are empty by definition. Nothing to load.
1310   if (loading_url_as_empty_document_) {
1311     FinishedLoading(base::TimeTicks::Now());
1312     return;
1313   }
1314 
1315   // TODO(dgozman): why do we stop loading for media documents?
1316   // This seems like a hack.
1317   if (frame_ && frame_->GetDocument()->IsMediaDocument()) {
1318     parser_->Finish();
1319     StopLoading();
1320     return;
1321   }
1322 
1323   // Committing can run unload handlers, which can detach this frame or
1324   // stop this loader.
1325   if (!frame_ || !body_loader_)
1326     return;
1327 
1328   if (!url_.ProtocolIsInHTTPFamily()) {
1329     // We only support code cache for http family, and browser insists on not
1330     // event asking for code cache with other schemes.
1331     body_loader_->StartLoadingBody(this, false /* use_isolated_code_cache */);
1332     return;
1333   }
1334 
1335   bool use_isolated_code_cache =
1336       RuntimeEnabledFeatures::CacheInlineScriptCodeEnabled() &&
1337       ShouldUseIsolatedCodeCache(mojom::blink::RequestContextType::HYPERLINK,
1338                                  response_);
1339 
1340   // The |cached_metadata_handler_| is created, even when
1341   // |use_isolated_code_cache| is false to support the parts that don't
1342   // go throught the site-isolated-code-cache.
1343   auto cached_metadata_sender = CachedMetadataSender::Create(
1344       response_, blink::mojom::CodeCacheType::kJavascript, requestor_origin_);
1345   cached_metadata_handler_ =
1346       MakeGarbageCollected<SourceKeyedCachedMetadataHandler>(
1347           WTF::TextEncoding(), std::move(cached_metadata_sender));
1348 
1349   body_loader_->StartLoadingBody(this, use_isolated_code_cache);
1350 }
1351 
DidInstallNewDocument(Document * document)1352 void DocumentLoader::DidInstallNewDocument(Document* document) {
1353   frame_->DomWindow()->BindContentSecurityPolicy();
1354 
1355   if (history_item_ && IsBackForwardLoadType(load_type_))
1356     document->SetStateForNewControls(history_item_->GetDocumentState());
1357 
1358   DCHECK(document->GetFrame());
1359   // TODO(dgozman): modify frame's client hints directly once we commit
1360   // synchronously.
1361   document->GetFrame()->GetClientHintsPreferences().UpdateFrom(
1362       client_hints_preferences_);
1363 
1364   const AtomicString& dns_prefetch_control =
1365       response_.HttpHeaderField(http_names::kXDNSPrefetchControl);
1366   if (!dns_prefetch_control.IsEmpty())
1367     document->ParseDNSPrefetchControlHeader(dns_prefetch_control);
1368 
1369   String header_content_language =
1370       response_.HttpHeaderField(http_names::kContentLanguage);
1371   if (!header_content_language.IsEmpty()) {
1372     wtf_size_t comma_index = header_content_language.find(',');
1373     // kNotFound == -1 == don't truncate
1374     header_content_language.Truncate(comma_index);
1375     header_content_language =
1376         header_content_language.StripWhiteSpace(IsHTMLSpace<UChar>);
1377     if (!header_content_language.IsEmpty())
1378       document->SetContentLanguage(AtomicString(header_content_language));
1379   }
1380 
1381   for (const auto& message : document_policy_parsing_messages_) {
1382     document->AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
1383         mojom::blink::ConsoleMessageSource::kOther, message.level,
1384         message.content));
1385   }
1386   document_policy_parsing_messages_.clear();
1387 }
1388 
WillCommitNavigation()1389 void DocumentLoader::WillCommitNavigation() {
1390   if (commit_reason_ != CommitReason::kRegular)
1391     return;
1392   probe::WillCommitLoad(frame_, this);
1393   frame_->GetIdlenessDetector()->WillCommitLoad();
1394 }
1395 
DidCommitNavigation()1396 void DocumentLoader::DidCommitNavigation() {
1397   if (commit_reason_ != CommitReason::kRegular)
1398     return;
1399 
1400   WebHistoryCommitType commit_type = LoadTypeToCommitType(load_type_);
1401   frame_->GetFrameScheduler()->DidCommitProvisionalLoad(
1402       commit_type == kWebHistoryInertCommit,
1403       load_type_ == WebFrameLoadType::kReload
1404           ? FrameScheduler::NavigationType::kReload
1405           : FrameScheduler::NavigationType::kOther);
1406   if (response_.CacheControlContainsNoCache()) {
1407     GetFrame()->GetFrameScheduler()->RegisterStickyFeature(
1408         SchedulingPolicy::Feature::kMainResourceHasCacheControlNoCache,
1409         {SchedulingPolicy::RecordMetricsForBackForwardCache()});
1410   }
1411   if (response_.CacheControlContainsNoStore()) {
1412     GetFrame()->GetFrameScheduler()->RegisterStickyFeature(
1413         SchedulingPolicy::Feature::kMainResourceHasCacheControlNoStore,
1414         {SchedulingPolicy::RecordMetricsForBackForwardCache()});
1415   }
1416 
1417   // When a new navigation commits in the frame, subresource loading should be
1418   // resumed.
1419   frame_->ResumeSubresourceLoading();
1420 
1421   Document* document = frame_->GetDocument();
1422   InteractiveDetector* interactive_detector =
1423       InteractiveDetector::From(*document);
1424   if (interactive_detector)
1425     interactive_detector->SetNavigationStartTime(GetTiming().NavigationStart());
1426 
1427   TRACE_EVENT1("devtools.timeline", "CommitLoad", "data",
1428                inspector_commit_load_event::Data(frame_));
1429 
1430   // Needs to run before dispatching preloads, as it may evict the memory cache.
1431   probe::DidCommitLoad(frame_, this);
1432 
1433   frame_->GetPage()->DidCommitLoad(frame_);
1434 
1435   // Report legacy TLS versions after Page::DidCommitLoad, because the latter
1436   // clears the console.
1437   if (response_.IsLegacyTLSVersion()) {
1438     GetFrameLoader().ReportLegacyTLSVersion(
1439         response_.CurrentRequestUrl(), false /* is_subresource */,
1440         frame_->IsAdSubframe() || frame_->IsAdRoot());
1441   }
1442 }
1443 
CalculateSandboxFlags()1444 network::mojom::blink::WebSandboxFlags DocumentLoader::CalculateSandboxFlags() {
1445   auto sandbox_flags = GetFrameLoader().GetForcedSandboxFlags() |
1446                        content_security_policy_->GetSandboxMask() |
1447                        frame_policy_.sandbox_flags;
1448   if (archive_) {
1449     // The URL of a Document loaded from a MHTML archive is controlled by
1450     // the Content-Location header. This would allow UXSS, since
1451     // Content-Location can be arbitrarily controlled to control the
1452     // Document's URL and origin. Instead, force a Document loaded from a
1453     // MHTML archive to be sandboxed, providing exceptions only for creating
1454     // new windows.
1455     DCHECK(commit_reason_ == CommitReason::kRegular ||
1456            commit_reason_ == CommitReason::kInitialization);
1457     sandbox_flags |= (network::mojom::blink::WebSandboxFlags::kAll &
1458                       ~(network::mojom::blink::WebSandboxFlags::kPopups |
1459                         network::mojom::blink::WebSandboxFlags::
1460                             kPropagatesToAuxiliaryBrowsingContexts));
1461   } else if (commit_reason_ == CommitReason::kXSLT) {
1462     // An XSLT document inherits sandbox flags from the document that create it.
1463     sandbox_flags |= frame_->DomWindow()->GetSandboxFlags();
1464   }
1465   return sandbox_flags;
1466 }
1467 
CalculateOrigin(Document * owner_document,network::mojom::blink::WebSandboxFlags sandbox_flags)1468 scoped_refptr<SecurityOrigin> DocumentLoader::CalculateOrigin(
1469     Document* owner_document,
1470     network::mojom::blink::WebSandboxFlags sandbox_flags) {
1471   scoped_refptr<SecurityOrigin> origin;
1472   if (origin_to_commit_) {
1473     // Origin to commit is specified by the browser process, it must be taken
1474     // and used directly. It is currently supplied only for session history
1475     // navigations, where the origin was already calcuated previously and
1476     // stored on the session history entry.
1477     origin = origin_to_commit_;
1478   } else if (IsPagePopupRunningInWebTest(frame_)) {
1479     // If we are a page popup in LayoutTests ensure we use the popup
1480     // owner's security origin so the tests can possibly access the
1481     // document via internals API.
1482     auto* owner_context = frame_->PagePopupOwner()->GetExecutionContext();
1483     origin = owner_context->GetSecurityOrigin()->IsolatedCopy();
1484   } else if (owner_document && owner_document->domWindow()) {
1485     origin = owner_document->domWindow()->GetMutableSecurityOrigin();
1486   } else {
1487     // Otherwise, create an origin that propagates precursor information
1488     // as needed. For non-opaque origins, this creates a standard tuple
1489     // origin, but for opaque origins, it creates an origin with the
1490     // initiator origin as the precursor.
1491     origin = SecurityOrigin::CreateWithReferenceOrigin(url_,
1492                                                        requestor_origin_.get());
1493   }
1494 
1495   if ((sandbox_flags & network::mojom::blink::WebSandboxFlags::kOrigin) !=
1496       network::mojom::blink::WebSandboxFlags::kNone) {
1497     auto sandbox_origin = origin->DeriveNewOpaqueOrigin();
1498 
1499     // If we're supposed to inherit our security origin from our
1500     // owner, but we're also sandboxed, the only things we inherit are
1501     // the origin's potential trustworthiness and the ability to
1502     // load local resources. The latter lets about:blank iframes in
1503     // file:// URL documents load images and other resources from
1504     // the file system.
1505     //
1506     // Note: Sandboxed about:srcdoc iframe without "allow-same-origin" aren't
1507     // allowed to load user's file, even if its parent can.
1508     if (owner_document) {
1509       if (origin->IsPotentiallyTrustworthy())
1510         sandbox_origin->SetOpaqueOriginIsPotentiallyTrustworthy(true);
1511       if (origin->CanLoadLocalResources() && !loading_srcdoc_)
1512         sandbox_origin->GrantLoadLocalResources();
1513     }
1514     origin = sandbox_origin;
1515   }
1516 
1517   if (!frame_->GetSettings()->GetWebSecurityEnabled()) {
1518     // Web security is turned off. We should let this document access
1519     // every other document. This is used primary by testing harnesses for
1520     // web sites.
1521     origin->GrantUniversalAccess();
1522   } else if (origin->IsLocal()) {
1523     if (frame_->GetSettings()->GetAllowUniversalAccessFromFileURLs()) {
1524       // Some clients want local URLs to have universal access, but that
1525       // setting is dangerous for other clients.
1526       origin->GrantUniversalAccess();
1527     } else if (!frame_->GetSettings()->GetAllowFileAccessFromFileURLs()) {
1528       // Some clients do not want local URLs to have access to other local
1529       // URLs.
1530       origin->BlockLocalAccessFromLocalOrigin();
1531     }
1532   }
1533 
1534   if (grant_load_local_resources_)
1535     origin->GrantLoadLocalResources();
1536 
1537   if (origin->IsOpaque()) {
1538     KURL url = url_.IsEmpty() ? BlankURL() : url_;
1539     if (SecurityOrigin::Create(url)->IsPotentiallyTrustworthy())
1540       origin->SetOpaqueOriginIsPotentiallyTrustworthy(true);
1541   }
1542   return origin;
1543 }
1544 
ShouldReuseDOMWindow(LocalDOMWindow * window,SecurityOrigin * security_origin)1545 bool ShouldReuseDOMWindow(LocalDOMWindow* window,
1546                           SecurityOrigin* security_origin) {
1547   // Secure transitions can only happen when navigating from the initial empty
1548   // document.
1549   return window && window->document()->IsInitialEmptyDocument() &&
1550          window->GetSecurityOrigin()->CanAccess(security_origin);
1551 }
1552 
GetWindowAgentForOrigin(LocalFrame * frame,SecurityOrigin * origin)1553 WindowAgent* GetWindowAgentForOrigin(LocalFrame* frame,
1554                                      SecurityOrigin* origin) {
1555   // TODO(keishi): Also check if AllowUniversalAccessFromFileURLs might
1556   // dynamically change.
1557   bool has_potential_universal_access_privilege =
1558       !frame->GetSettings()->GetWebSecurityEnabled() ||
1559       frame->GetSettings()->GetAllowUniversalAccessFromFileURLs();
1560   return frame->window_agent_factory().GetAgentForOrigin(
1561       has_potential_universal_access_privilege,
1562       V8PerIsolateData::MainThreadIsolate(), origin);
1563 }
1564 
InitializeWindow(Document * owner_document)1565 void DocumentLoader::InitializeWindow(Document* owner_document) {
1566   auto sandbox_flags = CalculateSandboxFlags();
1567   auto security_origin = CalculateOrigin(owner_document, sandbox_flags);
1568 
1569   // In some rare cases, we'll re-use a LocalDOMWindow for a new Document. For
1570   // example, when a script calls window.open("..."), the browser gives
1571   // JavaScript a window synchronously but kicks off the load in the window
1572   // asynchronously. Web sites expect that modifications that they make to the
1573   // window object synchronously won't be blown away when the network load
1574   // commits. To make that happen, we "securely transition" the existing
1575   // LocalDOMWindow to the Document that results from the network load. See also
1576   // Document::IsSecureTransitionTo.
1577   if (!ShouldReuseDOMWindow(frame_->DomWindow(), security_origin.get())) {
1578     auto* agent = GetWindowAgentForOrigin(frame_.Get(), security_origin.get());
1579     frame_->SetDOMWindow(MakeGarbageCollected<LocalDOMWindow>(*frame_, agent));
1580 
1581     if (origin_policy_.has_value()) {
1582       // Convert from WebVector<WebString> to WTF::Vector<WTF::String>
1583       Vector<String> ids;
1584       for (const auto& id : origin_policy_->ids) {
1585         ids.push_back(id);
1586       }
1587 
1588       frame_->DomWindow()->SetOriginPolicyIds(ids);
1589     }
1590 
1591     // Inheriting cases use their agent's origin-isolated value, which is set by
1592     // whatever they're inheriting from.
1593     //
1594     // javascript: URLs use the calling page as their Url() value, so we need to
1595     // exclude them explicitly.
1596     //
1597     // TODO(https://crbug.com/1111897): This call is likely to happen happen
1598     // multiple times per agent, since navigations can happen multiple times per
1599     // agent. This is subpar. Currently a DCHECK guards against it happening
1600     // multiple times *with different values*, but ideally we would use a better
1601     // architecture.
1602     if (!Document::ShouldInheritSecurityOriginFromOwner(Url()) &&
1603         commit_reason_ != CommitReason::kJavascriptUrl) {
1604       agent->SetIsOriginIsolated(origin_isolated_);
1605     }
1606   } else {
1607     if (frame_->GetSettings()->GetShouldReuseGlobalForUnownedMainFrame() &&
1608         frame_->IsMainFrame()) {
1609       // When GetShouldReuseGlobalForUnownedMainFrame() causes a main frame's
1610       // window to be reused, we should not inherit the initial empty document's
1611       // Agent, which was a universal access Agent.
1612       // This happens only in android webview.
1613       frame_->DomWindow()->ResetWindowAgent(
1614           GetWindowAgentForOrigin(frame_.Get(), security_origin.get()));
1615     }
1616     frame_->DomWindow()->ClearForReuse();
1617   }
1618 
1619   // Now that we have the final window and Agent, ensure the security origin has
1620   // the appropriate agent cluster id. This may derive a new security origin.
1621   security_origin = security_origin->GetOriginForAgentCluster(
1622       frame_->DomWindow()->GetAgent()->cluster_id());
1623 
1624   SecurityContext& security_context = frame_->DomWindow()->GetSecurityContext();
1625   security_context.SetContentSecurityPolicy(content_security_policy_.Get());
1626   security_context.ApplySandboxFlags(sandbox_flags);
1627   // Conceptually, SecurityOrigin doesn't have to be initialized after sandbox
1628   // flags are applied, but there's a UseCounter in SetSecurityOrigin() that
1629   // wants to inspect sandbox flags.
1630   security_context.SetSecurityOrigin(std::move(security_origin));
1631   // Requires SecurityOrigin to be initialized.
1632   OriginTrialContext::AddTokensFromHeader(
1633       frame_->DomWindow(), response_.HttpHeaderField(http_names::kOriginTrial));
1634 
1635   if (auto* parent = frame_->Tree().Parent()) {
1636     const SecurityContext* parent_context = parent->GetSecurityContext();
1637     security_context.SetInsecureRequestPolicy(
1638         parent_context->GetInsecureRequestPolicy());
1639     for (auto to_upgrade : parent_context->InsecureNavigationsToUpgrade())
1640       security_context.AddInsecureNavigationUpgrade(to_upgrade);
1641   }
1642   frame_->DomWindow()->SetAddressSpace(ip_address_space_);
1643 
1644   if (base::FeatureList::IsEnabled(blink::features::kPolicyContainer)) {
1645     // SVG image documents go throught this but don't have a PolicyContainer, so
1646     // ignore them.
1647     if (frame_->GetPolicyContainer()) {
1648       frame_->DomWindow()->SetReferrerPolicy(
1649           frame_->GetPolicyContainer()->GetReferrerPolicy(), false);
1650     }
1651   }
1652   String referrer_policy_header =
1653       response_.HttpHeaderField(http_names::kReferrerPolicy);
1654   if (!referrer_policy_header.IsNull()) {
1655     CountUse(WebFeature::kReferrerPolicyHeader);
1656     frame_->DomWindow()->ParseAndSetReferrerPolicy(referrer_policy_header);
1657     if (base::FeatureList::IsEnabled(blink::features::kPolicyContainer)) {
1658       if (frame_->GetPolicyContainer()) {
1659         frame_->GetPolicyContainer()->UpdateReferrerPolicy(
1660             frame_->DomWindow()->GetReferrerPolicy());
1661       }
1662     }
1663   }
1664 }
1665 
CommitNavigation()1666 void DocumentLoader::CommitNavigation() {
1667   DCHECK_LT(state_, kCommitted);
1668   DCHECK(frame_->GetPage());
1669   DCHECK(!frame_->GetDocument() || !frame_->GetDocument()->IsActive());
1670   DCHECK_EQ(frame_->Tree().ChildCount(), 0u);
1671   state_ = kCommitted;
1672 
1673   // Prepare a DocumentInit before clearing the frame, because it may need to
1674   // inherit an aliased security context.
1675   Document* owner_document = nullptr;
1676 
1677   // TODO(dcheng): This differs from the behavior of both IE and Firefox: the
1678   // origin is inherited from the document that loaded the URL.
1679   if (Document::ShouldInheritSecurityOriginFromOwner(Url())) {
1680     Frame* owner_frame = frame_->Tree().Parent();
1681     if (!owner_frame)
1682       owner_frame = frame_->Loader().Opener();
1683     if (auto* owner_local_frame = DynamicTo<LocalFrame>(owner_frame))
1684       owner_document = owner_local_frame->GetDocument();
1685   }
1686 
1687   // Re-validate Document Policy feature before installing the new document.
1688   if (!RuntimeEnabledFeatures::DocumentPolicyEnabled(
1689           owner_document ? owner_document->GetExecutionContext() : nullptr)) {
1690     document_policy_ = DocumentPolicy::ParsedDocumentPolicy{};
1691   }
1692 
1693   if (document_policy_.feature_state.contains(
1694           mojom::blink::DocumentPolicyFeature::kForceLoadAtTop)) {
1695     navigation_scroll_allowed_ = !(
1696         document_policy_
1697             .feature_state[mojom::blink::DocumentPolicyFeature::kForceLoadAtTop]
1698             .BoolValue());
1699   }
1700 
1701   LocalDOMWindow* previous_window = frame_->DomWindow();
1702   InitializeWindow(owner_document);
1703 
1704   SecurityContextInit security_init(frame_->DomWindow());
1705   // FeaturePolicy and DocumentPolicy require SecurityOrigin and origin trials
1706   // to be initialized.
1707   // TODO(iclelland): Add Feature-Policy-Report-Only to Origin Policy.
1708   security_init.ApplyFeaturePolicy(frame_.Get(), response_, origin_policy_,
1709                                    frame_policy_);
1710   // |document_policy_| is parsed in document loader because it is
1711   // compared with |frame_policy.required_document_policy| to decide
1712   // whether to block the document load or not.
1713   // |report_only_document_policy| does not block the page load. Its
1714   // initialization is delayed to
1715   // SecurityContextInit::InitializeDocumentPolicy(), similar to
1716   // |report_only_feature_policy|.
1717   security_init.ApplyDocumentPolicy(
1718       document_policy_,
1719       response_.HttpHeaderField(http_names::kDocumentPolicyReportOnly));
1720 
1721   WillCommitNavigation();
1722 
1723   Document* document = frame_->DomWindow()->InstallNewDocument(
1724       DocumentInit::Create()
1725           .WithWindow(frame_->DomWindow(), owner_document)
1726           .ForInitialEmptyDocument(commit_reason_ ==
1727                                    CommitReason::kInitialization)
1728           .WithURL(Url())
1729           .WithTypeFrom(MimeType())
1730           .WithSrcdocDocument(loading_srcdoc_)
1731           .WithNewRegistrationContext()
1732           .WithWebBundleClaimedUrl(web_bundle_claimed_url_)
1733           .WithUkmSourceId(ukm_source_id_));
1734 
1735   RecordUseCountersForCommit();
1736   RecordConsoleMessagesForCommit();
1737 
1738   // Clear the user activation state.
1739   // TODO(crbug.com/736415): Clear this bit unconditionally for all frames.
1740   if (frame_->IsMainFrame())
1741     frame_->ClearUserActivation();
1742 
1743   // The DocumentLoader was flagged as activated if it needs to notify the frame
1744   // that it was activated before navigation. Update the frame state based on
1745   // the new value.
1746   if (frame_->HadStickyUserActivationBeforeNavigation() !=
1747       had_sticky_activation_) {
1748     frame_->SetHadStickyUserActivationBeforeNavigation(had_sticky_activation_);
1749     frame_->GetLocalFrameHostRemote()
1750         .HadStickyUserActivationBeforeNavigationChanged(had_sticky_activation_);
1751   }
1752 
1753   bool should_clear_window_name =
1754       previous_window && frame_->IsMainFrame() && !frame_->Loader().Opener() &&
1755       !frame_->DomWindow()->GetSecurityOrigin()->IsSameOriginWith(
1756           previous_window->GetSecurityOrigin());
1757   if (should_clear_window_name) {
1758     // TODO(andypaicu): experimentalSetNullName will just record the fact
1759     // that the name would be nulled and if the name is accessed after we will
1760     // fire a UseCounter. If we decide to move forward with this change, we'd
1761     // actually clean the name here.
1762     // frame_->tree().setName(g_null_atom);
1763     frame_->Tree().ExperimentalSetNulledName();
1764   }
1765 
1766   bool should_clear_cross_browsing_context_group_window_name =
1767       previous_window && frame_->IsMainFrame() && !frame_->Loader().Opener() &&
1768       is_cross_browsing_context_group_navigation_;
1769   if (should_clear_cross_browsing_context_group_window_name) {
1770     // TODO(shuuran): CrossBrowsingContextGroupSetNulledName will just
1771     // record the fact that the name would be nulled and if the name is accessed
1772     // after we will fire a UseCounter. If we decide to move forward with
1773     // this change, we'd actually clean the name here.
1774     // frame_->tree().setName(g_null_atom);
1775     frame_->Tree().CrossBrowsingContextGroupSetNulledName();
1776   }
1777 
1778   // MHTML archive's URL is usually a local file. However the main resource
1779   // within the archive has a public URL and must be used to resolve all the
1780   // relative links.
1781   if (loading_main_document_from_mhtml_archive_) {
1782     ArchiveResource* main_resource = archive_->MainResource();
1783     KURL main_resource_url = main_resource ? main_resource->Url() : KURL();
1784     if (!main_resource_url.IsEmpty())
1785       document->SetBaseURLOverride(main_resource_url);
1786   }
1787 
1788   if (commit_reason_ == CommitReason::kXSLT)
1789     DocumentXSLT::SetHasTransformSource(*document);
1790 
1791   DidInstallNewDocument(document);
1792 
1793   // This must be called before the document is opened, otherwise HTML parser
1794   // will use stale values from HTMLParserOption.
1795   DidCommitNavigation();
1796 
1797   if (requestor_origin_) {
1798     const scoped_refptr<const SecurityOrigin> url_origin =
1799         SecurityOrigin::Create(Url());
1800 
1801     is_same_origin_navigation_ =
1802         requestor_origin_->IsSameOriginWith(url_origin.get()) &&
1803         Url().ProtocolIsInHTTPFamily();
1804   }
1805 
1806   // The PaintHolding feature defers compositor commits until content has
1807   // been painted or 500ms have passed, whichever comes first. The additional
1808   // PaintHoldingCrossOrigin feature allows PaintHolding even for cross-origin
1809   // navigations, otherwise only same-origin navigations have deferred commits.
1810   // We also require that this be an html document served via http.
1811   if (base::FeatureList::IsEnabled(blink::features::kPaintHolding) &&
1812       IsA<HTMLDocument>(document) && Url().ProtocolIsInHTTPFamily() &&
1813       (is_same_origin_navigation_ ||
1814        base::FeatureList::IsEnabled(
1815            blink::features::kPaintHoldingCrossOrigin))) {
1816     document->SetDeferredCompositorCommitIsAllowed(true);
1817   } else {
1818     document->SetDeferredCompositorCommitIsAllowed(false);
1819   }
1820 
1821   if (response_.IsHTTP() && navigation_timing_info_) {
1822     // The response is being copied here to pass the ServerTiming info.
1823     // TODO(yoav): copy the ServerTiming info directly.
1824     navigation_timing_info_->SetFinalResponse(response_);
1825   }
1826 
1827   {
1828     // Notify the browser process about the commit.
1829     FrameNavigationDisabler navigation_disabler(*frame_);
1830     if (commit_reason_ == CommitReason::kInitialization) {
1831       GetLocalFrameClient().DidCreateInitialEmptyDocument();
1832     } else if (IsJavaScriptURLOrXSLTCommit()) {
1833       GetLocalFrameClient().DidCommitDocumentReplacementNavigation(this);
1834     } else {
1835       GetLocalFrameClient().DispatchDidCommitLoad(
1836           history_item_.Get(), LoadTypeToCommitType(load_type_),
1837           previous_window != frame_->DomWindow());
1838     }
1839     // TODO(dgozman): make DidCreateScriptContext notification call currently
1840     // triggered by installing new document happen here, after commit.
1841   }
1842   // Note: this must be called after DispatchDidCommitLoad() for
1843   // metrics to be correctly sent to the browser process.
1844   if (commit_reason_ != CommitReason::kInitialization)
1845     use_counter_.DidCommitLoad(frame_);
1846   if (load_type_ == WebFrameLoadType::kBackForward) {
1847     if (Page* page = frame_->GetPage())
1848       page->HistoryNavigationVirtualTimePauser().UnpauseVirtualTime();
1849   }
1850 
1851   // FeaturePolicy is reset in the browser process on commit, so this needs to
1852   // be initialized and replicated to the browser process after commit messages
1853   // are sent.
1854   GetLocalFrameClient().DidSetFramePolicyHeaders(
1855       frame_->DomWindow()->GetSandboxFlags(),
1856       security_init.FeaturePolicyHeader(), document_policy_.feature_state);
1857 
1858   // Load the document if needed.
1859   StartLoadingResponse();
1860 }
1861 
CreateParserPostCommit()1862 void DocumentLoader::CreateParserPostCommit() {
1863   // DidObserveLoadingBehavior() must be called after DispatchDidCommitLoad() is
1864   // called for the metrics tracking logic to handle it properly.
1865   if (service_worker_network_provider_ &&
1866       service_worker_network_provider_->GetControllerServiceWorkerMode() ==
1867           blink::mojom::ControllerServiceWorkerMode::kControlled) {
1868     GetLocalFrameClient().DidObserveLoadingBehavior(
1869         kLoadingBehaviorServiceWorkerControlled);
1870   }
1871 
1872   // Links with media values need more information (like viewport information).
1873   // This happens after the first chunk is parsed in HTMLDocumentParser.
1874   DispatchLinkHeaderPreloads(nullptr /* viewport */,
1875                              PreloadHelper::kOnlyLoadNonMedia);
1876 
1877   // Initializing origin trials might force window proxy initialization,
1878   // which later triggers CHECK when swapping in via WebFrame::Swap().
1879   // We can safely omit installing original trials on initial empty document
1880   // and wait for the real load.
1881   if (commit_reason_ != CommitReason::kInitialization) {
1882     LocalDOMWindow* window = frame_->DomWindow();
1883     if (frame_->GetSettings()
1884             ->GetForceTouchEventFeatureDetectionForInspector()) {
1885       window->GetOriginTrialContext()->AddFeature(
1886           OriginTrialFeature::kTouchEventFeatureDetection);
1887     }
1888 
1889     // Enable any origin trials that have been force enabled for this commit.
1890     window->GetOriginTrialContext()->AddForceEnabledTrials(
1891         force_enabled_origin_trials_);
1892 
1893 #if BUILDFLAG(IS_ASH)
1894     // Enable Auto Picture-in-Picture feature for the built-in Chrome OS Video
1895     // Player app.
1896     const url::Origin origin = window->GetSecurityOrigin()->ToUrlOrigin();
1897     if (origin.scheme() == "chrome-extension" &&
1898         origin.DomainIs("jcgeabjmjgoblfofpppfkcoakmfobdko") &&
1899         origin.port() == 0) {
1900       window->GetOriginTrialContext()->AddFeature(
1901           OriginTrialFeature::kAutoPictureInPicture);
1902     }
1903 #endif
1904 
1905     OriginTrialContext::ActivateNavigationFeaturesFromInitiator(
1906         window, &initiator_origin_trial_features_);
1907   }
1908 
1909   ParserSynchronizationPolicy parsing_policy =
1910       RuntimeEnabledFeatures::ForceSynchronousHTMLParsingEnabled()
1911           ? kAllowDeferredParsing
1912           : kAllowAsynchronousParsing;
1913   if (IsJavaScriptURLOrXSLTCommit() ||
1914       !Document::ThreadedParsingEnabledForTesting()) {
1915     parsing_policy = kForceSynchronousParsing;
1916   }
1917   const AtomicString& encoding = commit_reason_ == CommitReason::kXSLT
1918                                      ? "UTF-8"
1919                                      : response_.TextEncodingName();
1920 
1921   Document* document = frame_->GetDocument();
1922   parser_ = document->OpenForNavigation(parsing_policy, MimeType(), encoding);
1923 
1924   // XSLT processing converts the response into UTF-8 before sending it through
1925   // the DocumentParser, but we should still report the original encoding when
1926   // script queries it via document.characterSet.
1927   if (commit_reason_ == CommitReason::kXSLT) {
1928     DocumentEncodingData data;
1929     data.SetEncoding(WTF::TextEncoding(response_.TextEncodingName()));
1930     document->SetEncodingData(data);
1931   }
1932 
1933   // If this is a scriptable parser and there is a resource, register the
1934   // resource's cache handler with the parser.
1935   ScriptableDocumentParser* scriptable_parser =
1936       parser_->AsScriptableDocumentParser();
1937   if (scriptable_parser && cached_metadata_handler_)
1938     scriptable_parser->SetInlineScriptCacheHandler(cached_metadata_handler_);
1939 
1940   GetFrameLoader().DispatchDidClearDocumentOfWindowObject();
1941 
1942   parser_->SetDocumentWasLoadedAsPartOfNavigation();
1943   if (was_discarded_)
1944     document->SetWasDiscarded(true);
1945   document->MaybeHandleHttpRefresh(
1946       response_.HttpHeaderField(http_names::kRefresh),
1947       Document::kHttpRefreshFromHeader);
1948   ReportPreviewsIntervention();
1949 }
1950 
MimeType() const1951 const AtomicString& DocumentLoader::MimeType() const {
1952   // In the case of mhtml archive, |response_| has an archive mime type,
1953   // while the document has a different mime type.
1954   if (loading_main_document_from_mhtml_archive_) {
1955     if (ArchiveResource* main_resource = archive_->MainResource())
1956       return main_resource->MimeType();
1957   }
1958 
1959   return response_.MimeType();
1960 }
1961 
BlockParser()1962 void DocumentLoader::BlockParser() {
1963   parser_blocked_count_++;
1964 }
1965 
ResumeParser()1966 void DocumentLoader::ResumeParser() {
1967   parser_blocked_count_--;
1968   DCHECK_GE(parser_blocked_count_, 0);
1969 
1970   if (parser_blocked_count_ != 0)
1971     return;
1972 
1973   ProcessDataBuffer();
1974 
1975   if (finish_loading_when_parser_resumed_) {
1976     finish_loading_when_parser_resumed_ = false;
1977     parser_->Finish();
1978     parser_.Clear();
1979   }
1980 }
1981 
CountUse(mojom::WebFeature feature)1982 void DocumentLoader::CountUse(mojom::WebFeature feature) {
1983   return use_counter_.Count(feature, GetFrame());
1984 }
1985 
RecordUseCountersForCommit()1986 void DocumentLoader::RecordUseCountersForCommit() {
1987   // Pre-commit state, count usage the use counter associated with "this"
1988   // (provisional document loader) instead of frame_'s document loader.
1989   if (response_.DidServiceWorkerNavigationPreload())
1990     CountUse(WebFeature::kServiceWorkerNavigationPreload);
1991   if (!frame_->IsMainFrame() && response_.GetCTPolicyCompliance() ==
1992                                     ResourceResponse::kCTPolicyDoesNotComply) {
1993     // Exclude main-frame navigations; those are tracked elsewhere.
1994     CountUse(
1995         WebFeature::kCertificateTransparencyNonCompliantResourceInSubframe);
1996   }
1997   if (RuntimeEnabledFeatures::ForceLoadAtTopEnabled(frame_->DomWindow()))
1998     CountUse(WebFeature::kForceLoadAtTop);
1999 
2000   if (response_.IsSignedExchangeInnerResponse()) {
2001     CountUse(WebFeature::kSignedExchangeInnerResponse);
2002     CountUse(frame_->IsMainFrame()
2003                  ? WebFeature::kSignedExchangeInnerResponseInMainFrame
2004                  : WebFeature::kSignedExchangeInnerResponseInSubFrame);
2005   }
2006 
2007   if (!response_.HttpHeaderField(http_names::kRequireDocumentPolicy).IsNull())
2008     CountUse(WebFeature::kRequireDocumentPolicyHeader);
2009 
2010   if (was_blocked_by_document_policy_)
2011     CountUse(WebFeature::kDocumentPolicyCausedPageUnload);
2012 
2013   // Required document policy can either come from iframe attribute or HTTP
2014   // header 'Require-Document-Policy'.
2015   if (!frame_policy_.required_document_policy.empty())
2016     CountUse(WebFeature::kRequiredDocumentPolicy);
2017 }
2018 
RecordConsoleMessagesForCommit()2019 void DocumentLoader::RecordConsoleMessagesForCommit() {
2020   // Log if the document was blocked by CSP checks now that the new Document has
2021   // been created and console messages will be properly displayed.
2022   if (was_blocked_by_csp_) {
2023     ConsoleError("Refused to display '" +
2024                  response_.CurrentRequestUrl().ElidedString() +
2025                  "' because it has not opted into the following policy "
2026                  "required by its embedder: '" +
2027                  GetFrameLoader().RequiredCSP() + "'.");
2028   }
2029 
2030   if (was_blocked_by_document_policy_) {
2031     // TODO(chenleihu): Add which document policy violated in error string,
2032     // instead of just displaying serialized required document policy.
2033     ConsoleError(
2034         "Refused to display '" + response_.CurrentRequestUrl().ElidedString() +
2035         "' because it violates the following document policy "
2036         "required by its embedder: '" +
2037         DocumentPolicy::Serialize(frame_policy_.required_document_policy)
2038             .value_or("[Serialization Error]")
2039             .c_str() +
2040         "'.");
2041   }
2042 
2043   // Report the ResourceResponse now that the new Document has been created and
2044   // console messages will be properly displayed.
2045   frame_->Console().ReportResourceResponseReceived(
2046       this, main_resource_identifier_, response_);
2047 }
2048 
ReportPreviewsIntervention() const2049 void DocumentLoader::ReportPreviewsIntervention() const {
2050   // Only send reports for main frames.
2051   if (!frame_->IsMainFrame())
2052     return;
2053 
2054   // Verify that certain types are not on main frame requests.
2055   DCHECK_NE(PreviewsTypes::kClientLoFiAutoReload, previews_state_);
2056   DCHECK_NE(PreviewsTypes::kSubresourceRedirectOn, previews_state_);
2057 
2058   static_assert(PreviewsTypes::kPreviewsStateLast ==
2059                     PreviewsTypes::kSubresourceRedirectOn,
2060                 "If a new Preview type is added, verify that the Intervention "
2061                 "Report should be sent (or not sent) for that type.");
2062 
2063   // If the preview type is not unspecified, off, or no transform, it is a
2064   // preview that needs to be reported.
2065   if (previews_state_ == PreviewsTypes::kPreviewsUnspecified ||
2066       previews_state_ & PreviewsTypes::kPreviewsOff ||
2067       previews_state_ & PreviewsTypes::kPreviewsNoTransform) {
2068     return;
2069   }
2070 
2071   Intervention::GenerateReport(
2072       frame_, "LitePageServed",
2073       "Modified page load behavior on the page because the page was expected "
2074       "to take a long amount of time to load. "
2075       "https://www.chromestatus.com/feature/5148050062311424");
2076 }
2077 
ApplyClientHintsConfig(const WebVector<network::mojom::WebClientHintsType> & enabled_client_hints)2078 void DocumentLoader::ApplyClientHintsConfig(
2079     const WebVector<network::mojom::WebClientHintsType>& enabled_client_hints) {
2080   for (auto ch : enabled_client_hints)
2081     client_hints_preferences_.SetShouldSend(ch);
2082 }
2083 
InitializePrefetchedSignedExchangeManager()2084 void DocumentLoader::InitializePrefetchedSignedExchangeManager() {
2085   if (params_->prefetched_signed_exchanges.empty())
2086     return;
2087   // |prefetched_signed_exchanges| is set only when the page is loaded from a
2088   // signed exchange.
2089   DCHECK(GetResponse().IsSignedExchangeInnerResponse());
2090   // When the page is loaded from a signed exchange, |last_redirect| must be the
2091   // synthesized redirect for the signed exchange.
2092   DCHECK(params_->redirects.size());
2093   const WebNavigationParams::RedirectInfo& last_redirect =
2094       params_->redirects[params_->redirects.size() - 1];
2095   prefetched_signed_exchange_manager_ =
2096       PrefetchedSignedExchangeManager::MaybeCreate(
2097           GetFrame(),
2098           last_redirect.redirect_response.HttpHeaderField(http_names::kLink),
2099           GetResponse().HttpHeaderField(http_names::kLink),
2100           std::move(params_->prefetched_signed_exchanges));
2101 }
2102 
2103 PrefetchedSignedExchangeManager*
GetPrefetchedSignedExchangeManager() const2104 DocumentLoader::GetPrefetchedSignedExchangeManager() const {
2105   return prefetched_signed_exchange_manager_;
2106 }
2107 
RemainingTimeToLCPLimit() const2108 base::TimeDelta DocumentLoader::RemainingTimeToLCPLimit() const {
2109   // We shouldn't call this function before navigation start
2110   DCHECK(!document_load_timing_.NavigationStart().is_null());
2111   base::TimeTicks lcp_limit =
2112       document_load_timing_.NavigationStart() +
2113       base::TimeDelta::FromMilliseconds(
2114           features::kAlignFontDisplayAutoTimeoutWithLCPGoalTimeoutParam.Get());
2115   base::TimeTicks now = clock_->NowTicks();
2116   if (now < lcp_limit)
2117     return lcp_limit - now;
2118   return base::TimeDelta();
2119 }
2120 
2121 mojom::blink::ContentSecurityNotifier&
GetContentSecurityNotifier()2122 DocumentLoader::GetContentSecurityNotifier() {
2123   if (!content_security_notifier_.is_bound()) {
2124     GetFrame()->Client()->GetBrowserInterfaceBroker().GetInterface(
2125         content_security_notifier_.BindNewPipeAndPassReceiver());
2126   }
2127   return *content_security_notifier_;
2128 }
2129 
ConsumeTextFragmentToken()2130 bool DocumentLoader::ConsumeTextFragmentToken() {
2131   bool token_value = has_text_fragment_token_;
2132   has_text_fragment_token_ = false;
2133   return token_value;
2134 }
2135 
2136 DEFINE_WEAK_IDENTIFIER_MAP(DocumentLoader)
2137 
2138 }  // namespace blink
2139