blob: 4e74c769ba2b83690e5a2222472aa3380b99af74 [file] [log] [blame]
danakjc492bf82020-09-09 20:02:441// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef CONTENT_BROWSER_RENDERER_HOST_NAVIGATION_ENTRY_IMPL_H_
6#define CONTENT_BROWSER_RENDERER_HOST_NAVIGATION_ENTRY_IMPL_H_
7
8#include <stdint.h>
9
10#include <memory>
11#include <string>
12#include <vector>
13
14#include "base/containers/flat_map.h"
15#include "base/macros.h"
16#include "base/memory/ref_counted.h"
17#include "base/optional.h"
18#include "base/time/time.h"
19#include "build/build_config.h"
20#include "content/browser/renderer_host/back_forward_cache_metrics.h"
21#include "content/browser/renderer_host/frame_navigation_entry.h"
22#include "content/browser/renderer_host/frame_tree_node.h"
23#include "content/browser/site_instance_impl.h"
24#include "content/common/navigation_params.mojom.h"
25#include "content/public/browser/favicon_status.h"
26#include "content/public/browser/global_request_id.h"
27#include "content/public/browser/navigation_entry.h"
28#include "content/public/browser/reload_type.h"
29#include "content/public/browser/replaced_navigation_entry_data.h"
30#include "content/public/browser/restore_type.h"
31#include "content/public/browser/ssl_status.h"
32#include "content/public/common/page_state.h"
33#include "net/base/isolation_info.h"
34#include "third_party/blink/public/common/loader/previews_state.h"
35#include "url/origin.h"
36
37namespace content {
38
39class WebBundleNavigationInfo;
40
41class CONTENT_EXPORT NavigationEntryImpl : public NavigationEntry {
42 public:
43 // Represents a tree of FrameNavigationEntries that make up this joint session
44 // history item.
45 struct TreeNode {
46 TreeNode(TreeNode* parent, scoped_refptr<FrameNavigationEntry> frame_entry);
47 ~TreeNode();
48
49 // Returns whether this TreeNode corresponds to |frame_tree_node|. If this
50 // is called on the root TreeNode, we only check if |frame_tree_node| is the
51 // main frame. Otherwise, we check if the unique name matches.
52 bool MatchesFrame(FrameTreeNode* frame_tree_node) const;
53
54 // Recursively makes a deep copy of TreeNode with copies of each of the
55 // FrameNavigationEntries in the subtree. Replaces the TreeNode
56 // corresponding to |target_frame_tree_node|, clearing all of its children
57 // unless |clone_children_of_target| is true. This function omits any
58 // subframe history items that do not correspond to frames actually in the
59 // current page, using |current_frame_tree_node| (if present).
60 // TODO(creis): For --site-per-process, share FrameNavigationEntries between
61 // NavigationEntries of the same tab.
62 std::unique_ptr<TreeNode> CloneAndReplace(
63 scoped_refptr<FrameNavigationEntry> frame_navigation_entry,
64 bool clone_children_of_target,
65 FrameTreeNode* target_frame_tree_node,
66 FrameTreeNode* current_frame_tree_node,
67 TreeNode* parent_node) const;
68
69 // The parent of this node.
70 TreeNode* parent;
71
72 // Ref counted pointer that keeps the FrameNavigationEntry alive as long as
73 // it is needed by this node's NavigationEntry.
74 scoped_refptr<FrameNavigationEntry> frame_entry;
75
76 // List of child TreeNodes, which will be deleted when this node is.
77 std::vector<std::unique_ptr<TreeNode>> children;
78 };
79
80 static NavigationEntryImpl* FromNavigationEntry(NavigationEntry* entry);
81 static const NavigationEntryImpl* FromNavigationEntry(
82 const NavigationEntry* entry);
83 static std::unique_ptr<NavigationEntryImpl> FromNavigationEntry(
84 std::unique_ptr<NavigationEntry> entry);
85
86 NavigationEntryImpl();
87 NavigationEntryImpl(
88 scoped_refptr<SiteInstanceImpl> instance,
89 const GURL& url,
90 const Referrer& referrer,
91 const base::Optional<url::Origin>& initiator_origin,
92 const base::string16& title,
93 ui::PageTransition transition_type,
94 bool is_renderer_initiated,
95 scoped_refptr<network::SharedURLLoaderFactory> blob_url_loader_factory);
96 ~NavigationEntryImpl() override;
97
98 // NavigationEntry implementation:
99 int GetUniqueID() override;
100 PageType GetPageType() override;
101 void SetURL(const GURL& url) override;
102 const GURL& GetURL() override;
103 void SetBaseURLForDataURL(const GURL& url) override;
104 const GURL& GetBaseURLForDataURL() override;
105#if defined(OS_ANDROID)
106 void SetDataURLAsString(
107 scoped_refptr<base::RefCountedString> data_url) override;
108 const scoped_refptr<const base::RefCountedString>& GetDataURLAsString()
109 override;
110#endif
111 void SetReferrer(const Referrer& referrer) override;
112 const Referrer& GetReferrer() override;
113 void SetVirtualURL(const GURL& url) override;
114 const GURL& GetVirtualURL() override;
115 void SetTitle(const base::string16& title) override;
116 const base::string16& GetTitle() override;
117 void SetPageState(const PageState& state) override;
118 PageState GetPageState() override;
119 const base::string16& GetTitleForDisplay() override;
120 bool IsViewSourceMode() override;
121 void SetTransitionType(ui::PageTransition transition_type) override;
122 ui::PageTransition GetTransitionType() override;
123 const GURL& GetUserTypedURL() override;
124 void SetHasPostData(bool has_post_data) override;
125 bool GetHasPostData() override;
126 void SetPostID(int64_t post_id) override;
127 int64_t GetPostID() override;
128 void SetPostData(
129 const scoped_refptr<network::ResourceRequestBody>& data) override;
130 scoped_refptr<network::ResourceRequestBody> GetPostData() override;
131 FaviconStatus& GetFavicon() override;
132 SSLStatus& GetSSL() override;
133 void SetOriginalRequestURL(const GURL& original_url) override;
134 const GURL& GetOriginalRequestURL() override;
135 void SetIsOverridingUserAgent(bool override_ua) override;
136 bool GetIsOverridingUserAgent() override;
137 void SetTimestamp(base::Time timestamp) override;
138 base::Time GetTimestamp() override;
139 void SetCanLoadLocalResources(bool allow) override;
140 bool GetCanLoadLocalResources() override;
141 void SetHttpStatusCode(int http_status_code) override;
142 int GetHttpStatusCode() override;
143 void SetRedirectChain(const std::vector<GURL>& redirects) override;
144 const std::vector<GURL>& GetRedirectChain() override;
145 const base::Optional<ReplacedNavigationEntryData>& GetReplacedEntryData()
146 override;
147 bool IsRestored() override;
148 std::string GetExtraHeaders() override;
149 void AddExtraHeaders(const std::string& extra_headers) override;
150 int64_t GetMainFrameDocumentSequenceNumber() override;
151
152 // Creates a copy of this NavigationEntryImpl that can be modified
153 // independently from the original. Does not copy any value that would be
154 // cleared in ResetForCommit. Unlike |CloneAndReplace|, this does not check
155 // whether the subframe history items are for frames that are still in the
156 // current page.
157 std::unique_ptr<NavigationEntryImpl> Clone() const;
158
159 // Like |Clone|, but replaces the FrameNavigationEntry corresponding to
160 // |target_frame_tree_node| with |frame_entry|, clearing all of its children
161 // unless |clone_children_of_target| is true. This function omits any
162 // subframe history items that do not correspond to frames actually in the
163 // current page, using |root_frame_tree_node| (if present).
164 //
165 // TODO(creis): Once we start sharing FrameNavigationEntries between
166 // NavigationEntryImpls, we will need to support two versions of Clone: one
167 // that shares the existing FrameNavigationEntries (for use within the same
168 // tab) and one that draws them from a different pool (for use in a new tab).
169 std::unique_ptr<NavigationEntryImpl> CloneAndReplace(
170 scoped_refptr<FrameNavigationEntry> frame_entry,
171 bool clone_children_of_target,
172 FrameTreeNode* target_frame_tree_node,
173 FrameTreeNode* root_frame_tree_node) const;
174
175 // Helper functions to construct NavigationParameters for a navigation to this
176 // NavigationEntry.
177 mojom::CommonNavigationParamsPtr ConstructCommonNavigationParams(
178 const FrameNavigationEntry& frame_entry,
179 const scoped_refptr<network::ResourceRequestBody>& post_body,
180 const GURL& dest_url,
181 blink::mojom::ReferrerPtr dest_referrer,
182 mojom::NavigationType navigation_type,
183 blink::PreviewsState previews_state,
184 base::TimeTicks navigation_start,
185 base::TimeTicks input_start);
186 mojom::CommitNavigationParamsPtr ConstructCommitNavigationParams(
187 const FrameNavigationEntry& frame_entry,
188 const GURL& original_url,
189 const base::Optional<url::Origin>& origin_to_commit,
190 const std::string& original_method,
191 const base::flat_map<std::string, bool>& subframe_unique_names,
192 bool intended_as_new_entry,
193 int pending_offset_to_send,
194 int current_offset_to_send,
195 int current_length_to_send,
196 const blink::FramePolicy& frame_policy);
197
198 // Once a navigation entry is committed, we should no longer track several
199 // pieces of non-persisted state, as documented on the members below.
200 // |frame_entry| is the FrameNavigationEntry for the frame that committed
201 // the navigation. It can be null.
202 void ResetForCommit(FrameNavigationEntry* frame_entry);
203
204 // Exposes the tree of FrameNavigationEntries that make up this joint session
205 // history item.
206 // In default Chrome, this tree only has a root node with an unshared
207 // FrameNavigationEntry. Subframes are only added to the tree if the
208 // --site-per-process flag is passed.
209 TreeNode* root_node() const { return frame_tree_.get(); }
210
211 // Finds the TreeNode associated with |frame_tree_node|, if any.
212 NavigationEntryImpl::TreeNode* GetTreeNode(
213 FrameTreeNode* frame_tree_node) const;
214
215 // Finds the TreeNode associated with |frame_tree_node_id| to add or update
216 // its FrameNavigationEntry. A new FrameNavigationEntry is added if none
217 // exists, or else the existing one (which might be shared with other
218 // NavigationEntries) is updated with the given parameters.
219 // Does nothing if there is no entry already and |url| is about:blank, since
220 // that does not count as a real commit.
221 void AddOrUpdateFrameEntry(
222 FrameTreeNode* frame_tree_node,
223 int64_t item_sequence_number,
224 int64_t document_sequence_number,
225 SiteInstanceImpl* site_instance,
226 scoped_refptr<SiteInstanceImpl> source_site_instance,
227 const GURL& url,
228 const base::Optional<url::Origin>& origin,
229 const Referrer& referrer,
230 const base::Optional<url::Origin>& initiator_origin,
231 const std::vector<GURL>& redirect_chain,
232 const PageState& page_state,
233 const std::string& method,
234 int64_t post_id,
235 scoped_refptr<network::SharedURLLoaderFactory> blob_url_loader_factory,
236 std::unique_ptr<WebBundleNavigationInfo> web_bundle_navigation_info);
237
238 // Returns the FrameNavigationEntry corresponding to |frame_tree_node|, if
239 // there is one in this NavigationEntry.
240 FrameNavigationEntry* GetFrameEntry(FrameTreeNode* frame_tree_node) const;
241
242 // Returns a map of frame unique names to |is_about_blank| for immediate
243 // children of the TreeNode associated with |frame_tree_node|. The renderer
244 // process will use this list of names to know whether to ask the browser
245 // process for a history item when new subframes are created during a
246 // back/forward navigation. (|is_about_blank| can be used to skip the request
247 // if the frame's default URL is about:blank and the history item would be a
248 // no-op. See https://crbug.com/657896.)
249 // TODO(creis): Send a data structure that also contains all corresponding
250 // same-process PageStates for the whole subtree, so that the renderer process
251 // only needs to ask the browser process to handle the cross-process cases.
252 // See https://crbug.com/639842.
253 base::flat_map<std::string, bool> GetSubframeUniqueNames(
254 FrameTreeNode* frame_tree_node) const;
255
256 // Walks the tree of FrameNavigationEntries to find entries with |origin| so
257 // their isolation status can be registered.
258 void RegisterExistingOriginToPreventOptInIsolation(const url::Origin& origin);
259
260 // Removes any subframe FrameNavigationEntries that match the unique name of
261 // |frame_tree_node|, and all of their children. There should be at most one,
262 // since collisions are avoided but leave old FrameNavigationEntries in the
263 // tree after their frame has been detached.
264 //
265 // If |only_if_different_position| is specified, then the removal is only
266 // done if the found FNE is in a different tree position than the
267 // |frame_tree_node|.
268 void RemoveEntryForFrame(FrameTreeNode* frame_tree_node,
269 bool only_if_different_position);
270
271 void set_unique_id(int unique_id) { unique_id_ = unique_id; }
272
273 void set_started_from_context_menu(bool started_from_context_menu) {
274 started_from_context_menu_ = started_from_context_menu;
275 }
276
277 bool has_started_from_context_menu() const {
278 return started_from_context_menu_;
279 }
280
281 // The SiteInstance represents which pages must share processes. This is a
282 // reference counted pointer to a shared SiteInstance.
283 //
284 // Note that the SiteInstance should usually not be changed after it is set,
285 // but this may happen if the NavigationEntry was cloned and needs to use a
286 // different SiteInstance.
287 void set_site_instance(scoped_refptr<SiteInstanceImpl> site_instance);
288 SiteInstanceImpl* site_instance() const {
289 return frame_tree_->frame_entry->site_instance();
290 }
291
292 // The |source_site_instance| is used to identify the SiteInstance of the
293 // frame that initiated the navigation. It is set on the
294 // FrameNavigationEntry for the main frame.
295 void set_source_site_instance(
296 scoped_refptr<SiteInstanceImpl> source_site_instance) {
297 root_node()->frame_entry->set_source_site_instance(
298 source_site_instance.get());
299 }
300
301 void set_page_type(PageType page_type) { page_type_ = page_type; }
302
303 bool has_virtual_url() const { return !virtual_url_.is_empty(); }
304
305 bool update_virtual_url_with_url() const {
306 return update_virtual_url_with_url_;
307 }
308 void set_update_virtual_url_with_url(bool update) {
309 update_virtual_url_with_url_ = update;
310 }
311
312 // Extra headers (separated by \r\n) to send during the request.
313 void set_extra_headers(const std::string& extra_headers) {
314 extra_headers_ = extra_headers;
315 }
316 const std::string& extra_headers() const { return extra_headers_; }
317
318 // Whether this (pending) navigation is renderer-initiated. Resets to false
319 // for all types of navigations after commit.
320 void set_is_renderer_initiated(bool is_renderer_initiated) {
321 is_renderer_initiated_ = is_renderer_initiated;
322 }
323 bool is_renderer_initiated() const { return is_renderer_initiated_; }
324
325 void set_user_typed_url(const GURL& user_typed_url) {
326 user_typed_url_ = user_typed_url;
327 }
328
329 // The RestoreType for this entry. This is set if the entry was retored. This
330 // is set to RestoreType::NONE once the entry is loaded.
331 void set_restore_type(RestoreType type) { restore_type_ = type; }
332 RestoreType restore_type() const { return restore_type_; }
333
334 // The ReloadType for this entry. This is set when a reload is requested.
335 // This is set to ReloadType::NONE if the entry isn't for a reload, or once
336 // the entry is loaded.
337 void set_reload_type(ReloadType type) { reload_type_ = type; }
338 ReloadType reload_type() const { return reload_type_; }
339
340 // Whether this (pending) navigation needs to replace current entry.
341 // Resets to false after commit.
342 bool should_replace_entry() const { return should_replace_entry_; }
343
344 void set_should_replace_entry(bool should_replace_entry) {
345 should_replace_entry_ = should_replace_entry;
346 }
347
348 // Whether this (pending) navigation should clear the session history. Resets
349 // to false after commit.
350 bool should_clear_history_list() const { return should_clear_history_list_; }
351 void set_should_clear_history_list(bool should_clear_history_list) {
352 should_clear_history_list_ = should_clear_history_list;
353 }
354
355 // Indicates which FrameTreeNode to navigate. Currently only used if the
356 // --site-per-process flag is passed.
357 int frame_tree_node_id() const { return frame_tree_node_id_; }
358 void set_frame_tree_node_id(int frame_tree_node_id) {
359 frame_tree_node_id_ = frame_tree_node_id;
360 }
361
362 // Returns the history URL for a data URL to use in Blink.
363 GURL GetHistoryURLForDataURL();
364
365 // These flags are set when the navigation controller gets notified of an SSL
366 // error while a navigation is pending.
367 void set_ssl_error(bool error) { ssl_error_ = error; }
368 bool ssl_error() const { return ssl_error_; }
369
370 bool has_user_gesture() const { return has_user_gesture_; }
371
372 void set_has_user_gesture(bool has_user_gesture) {
373 has_user_gesture_ = has_user_gesture;
374 }
375
376 void set_isolation_info(const net::IsolationInfo& isolation_info) {
377 isolation_info_ = isolation_info;
378 }
379
380 const base::Optional<net::IsolationInfo>& isolation_info() const {
381 return isolation_info_;
382 }
383
384 // Stores a record of the what was committed in this NavigationEntry's main
385 // frame before it was replaced (e.g. by history.replaceState()).
386 void set_replaced_entry_data(const ReplacedNavigationEntryData& data) {
387 replaced_entry_data_ = data;
388 }
389
390 // See comment for should_skip_on_back_forward_ui_.
391 bool should_skip_on_back_forward_ui() const {
392 return should_skip_on_back_forward_ui_;
393 }
394
395 void set_should_skip_on_back_forward_ui(bool should_skip) {
396 should_skip_on_back_forward_ui_ = should_skip;
397 }
398
399 BackForwardCacheMetrics* back_forward_cache_metrics() {
400 return back_forward_cache_metrics_.get();
401 }
402
403 void set_back_forward_cache_metrics(
404 scoped_refptr<BackForwardCacheMetrics> metrics) {
405 DCHECK(metrics);
406 DCHECK(!back_forward_cache_metrics_);
407 back_forward_cache_metrics_ = metrics;
408 }
409
410 private:
411 // WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
412 // Session/Tab restore save portions of this class so that it can be recreated
413 // later. If you add a new field that needs to be persisted you'll have to
414 // update SessionService/TabRestoreService and Android WebView
415 // state_serializer.cc appropriately.
416 // For all new fields, update |Clone| and possibly |ResetForCommit|.
417 // WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
418
419 // Tree of FrameNavigationEntries, one for each frame on the page.
420 // TODO(creis): Once FrameNavigationEntries can be shared across multiple
421 // NavigationEntries, we will need to update Session/Tab restore. For now,
422 // each NavigationEntry's tree has its own unshared FrameNavigationEntries.
423 std::unique_ptr<TreeNode> frame_tree_;
424
425 // See the accessors above for descriptions.
426 int unique_id_;
427 PageType page_type_;
428 GURL virtual_url_;
429 bool update_virtual_url_with_url_;
430 base::string16 title_;
431 FaviconStatus favicon_;
432 SSLStatus ssl_;
433 ui::PageTransition transition_type_;
434 GURL user_typed_url_;
435 RestoreType restore_type_;
436 GURL original_request_url_;
437 bool is_overriding_user_agent_;
438 base::Time timestamp_;
439 int http_status_code_;
440
441 // This member is not persisted with session restore because it is transient.
442 // If the post request succeeds, this field is cleared since the same
443 // information is stored in PageState. It is also only shallow copied with
444 // compiler provided copy constructor. Cleared in |ResetForCommit|.
445 scoped_refptr<network::ResourceRequestBody> post_data_;
446
447 // This member is not persisted with session restore.
448 std::string extra_headers_;
449
450 // Used for specifying base URL for pages loaded via data URLs. Only used and
451 // persisted by Android WebView.
452 GURL base_url_for_data_url_;
453
454#if defined(OS_ANDROID)
455 // Used for passing really big data URLs from browser to renderers. Only used
456 // and persisted by Android WebView.
457 scoped_refptr<const base::RefCountedString> data_url_as_string_;
458#endif
459
460 // Whether the entry, while loading, was created for a renderer-initiated
461 // navigation. This dictates whether the URL should be displayed before the
462 // navigation commits. It is cleared in |ResetForCommit| and not persisted.
463 bool is_renderer_initiated_;
464
465 // This is a cached version of the result of GetTitleForDisplay. It prevents
466 // us from having to do URL formatting on the URL every time the title is
467 // displayed. When the URL, virtual URL, or title is set, this should be
468 // cleared to force a refresh.
469 mutable base::string16 cached_display_title_;
470
471 // This is set to true when this entry is being reloaded and due to changes in
472 // the state of the URL, it has to be reloaded in a different site instance.
473 // In such case, we must treat it as an existing navigation in the new site
474 // instance, instead of a new navigation. This value should not be persisted
475 // and is cleared in |ResetForCommit|.
476 //
477 // We also use this flag for cross-process redirect navigations, so that the
478 // browser will replace the current navigation entry (which is the page
479 // doing the redirect).
480 bool should_replace_entry_;
481
482 // This is set to true when this entry's navigation should clear the session
483 // history both on the renderer and browser side. The browser side history
484 // won't be cleared until the renderer has committed this navigation. This
485 // entry is not persisted by the session restore system, as it is always
486 // cleared in |ResetForCommit|.
487 bool should_clear_history_list_;
488
489 // Set when this entry should be able to access local file:// resources. This
490 // value is not needed after the entry commits and is not persisted.
491 bool can_load_local_resources_;
492
493 // If not -1, this indicates which FrameTreeNode to navigate. This field is
494 // not persisted because it is experimental and only used when the
495 // --site-per-process flag is passed. It is cleared in |ResetForCommit|
496 // because we only use it while the navigation is pending.
497 // TODO(creis): Move this to FrameNavigationEntry.
498 int frame_tree_node_id_;
499
500 // Whether the URL load carries a user gesture.
501 bool has_user_gesture_;
502
503 // Used to store ReloadType for the entry. This is ReloadType::NONE for
504 // non-reload navigations. Reset at commit and not persisted.
505 ReloadType reload_type_;
506
507 // Determine if the navigation was started within a context menu.
508 bool started_from_context_menu_;
509
510 // Set to true if the navigation controller gets notified about a SSL error
511 // for a pending navigation. Defaults to false.
512 bool ssl_error_;
513
514 // The net::IsolationInfo for this NavigationEntry. If provided, this
515 // determines the IsolationInfo to be used when navigating to this
516 // NavigationEntry; otherwise, it is determined based on the navigating frame
517 // and top frame origins. For example, this is used for view-source.
518 base::Optional<net::IsolationInfo> isolation_info_;
519
520 // Stores information about the entry prior to being replaced (e.g.
521 // history.replaceState()). It is preserved after commit (session sync for
522 // offline analysis) but should not be persisted. The concept is valid for
523 // subframe navigations but we only need to track it for main frames, that's
524 // why the field is listed here.
525 base::Optional<ReplacedNavigationEntryData> replaced_entry_data_;
526
527 // Set to true if this page does a navigation without ever receiving a user
528 // gesture. If true, it will be skipped on subsequent back/forward button
529 // clicks. This is to intervene against pages that manipulate the history such
530 // that the user is not able to go back to the last site they interacted with.
531 // Navigation here implies both client side redirects and history.pushState
532 // calls.
533 // It is always false the first time an entry's navigation is committed and
534 // is also reset to false if an entry is reused for any subsequent
535 // navigations.
536 // TODO(shivanisha): Persist this field once the intervention is stable.
537 bool should_skip_on_back_forward_ui_;
538
539 // TODO(altimin, crbug.com/933147): Remove this logic after we are done
540 // with implement back-forward cache.
541 // It is preserved at commit but not persisted.
542 scoped_refptr<BackForwardCacheMetrics> back_forward_cache_metrics_;
543
544 DISALLOW_COPY_AND_ASSIGN(NavigationEntryImpl);
545};
546
547} // namespace content
548
549#endif // CONTENT_BROWSER_RENDERER_HOST_NAVIGATION_ENTRY_IMPL_H_