File: content_serialized_navigation_builder.cc

package info (click to toggle)
chromium 139.0.7258.127-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 6,122,156 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (202 lines) | stat: -rw-r--r-- 9,264 bytes parent folder | download | duplicates (7)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "components/sessions/content/content_serialized_navigation_builder.h"

#include <string>

#include "base/check_op.h"
#include "components/sessions/content/content_record_password_state.h"
#include "components/sessions/content/content_serialized_navigation_driver.h"
#include "components/sessions/content/extended_info_handler.h"
#include "components/sessions/content/navigation_task_id.h"
#include "components/sessions/core/serialized_navigation_entry.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/favicon_status.h"
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/navigation_entry_restore_context.h"
#include "content/public/common/referrer.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "third_party/blink/public/common/page_state/page_state.h"

namespace sessions {

// static
SerializedNavigationEntry
ContentSerializedNavigationBuilder::FromNavigationEntry(
    int index,
    content::NavigationEntry* entry,
    SerializationOptions serialization_options) {
  SerializedNavigationEntry navigation;
  navigation.index_ = index;
  navigation.unique_id_ = entry->GetUniqueID();
  navigation.referrer_url_ = entry->GetReferrer().url;
  navigation.referrer_policy_ = static_cast<int>(entry->GetReferrer().policy);
  navigation.virtual_url_ = entry->GetVirtualURL();
  navigation.title_ = entry->GetTitle();
  if (!(serialization_options & SerializationOptions::EXCLUDE_PAGE_STATE))
    navigation.encoded_page_state_ = entry->GetPageState().ToEncodedData();
  navigation.transition_type_ = entry->GetTransitionType();
  navigation.has_post_data_ = entry->GetHasPostData();
  navigation.post_id_ = entry->GetPostID();
  navigation.original_request_url_ = entry->GetOriginalRequestURL();
  navigation.is_overriding_user_agent_ = entry->GetIsOverridingUserAgent();
  navigation.timestamp_ = entry->GetTimestamp();
  navigation.is_restored_ = entry->IsRestored();
  if (entry->GetFavicon().valid)
    navigation.favicon_url_ = entry->GetFavicon().url;
  navigation.http_status_code_ = entry->GetHttpStatusCode();
  navigation.redirect_chain_ = entry->GetRedirectChain();
  navigation.password_state_ = GetPasswordStateFromNavigation(entry);
  navigation.task_id_ = NavigationTaskId::Get(entry)->id();
  navigation.parent_task_id_ = NavigationTaskId::Get(entry)->parent_id();
  navigation.root_task_id_ = NavigationTaskId::Get(entry)->root_id();

  for (const auto& handler_entry :
       ContentSerializedNavigationDriver::GetInstance()
           ->GetAllExtendedInfoHandlers()) {
    ExtendedInfoHandler* handler = handler_entry.second.get();
    DCHECK(handler);
    std::string value = handler->GetExtendedInfo(entry);
    if (!value.empty())
      navigation.extended_info_map_[handler_entry.first] = value;
  }

  return navigation;
}

// static
std::unique_ptr<content::NavigationEntry>
ContentSerializedNavigationBuilder::ToNavigationEntry(
    const SerializedNavigationEntry* navigation,
    content::BrowserContext* browser_context,
    content::NavigationEntryRestoreContext* restore_context) {
  DCHECK(navigation);
  DCHECK(browser_context);
  DCHECK(restore_context);

  // The initial values of the NavigationEntry are usually temporary - they will
  // normally get clobbered by one of the SetPageState calls below.
  //
  // This means that things like |navigation->referrer_url| are ignored
  // in favor of using the data stored in |navigation->encoded_page_state|.
  //
  // We still use the URL and referrer from |navigation| here for the temporary
  // values, though, in case the PageState fails to decode and clobber them.
  // This allows us to load the original URL and referrer even if other state is
  // lost.
  GURL temporary_url = navigation->virtual_url_;
  content::Referrer temporary_referrer(
      navigation->referrer_url(),
      content::Referrer::ConvertToPolicy(navigation->referrer_policy()));
  std::optional<url::Origin> temporary_initiator_origin;
  std::optional<GURL> temporary_initiator_base_url;

  std::unique_ptr<content::NavigationEntry> entry(
      content::NavigationController::CreateNavigationEntry(
          temporary_url, temporary_referrer, temporary_initiator_origin,
          temporary_initiator_base_url,
          // Use a transition type of reload so that we don't incorrectly
          // increase the typed count.
          ui::PAGE_TRANSITION_RELOAD, false,
          // The extra headers are not sync'ed across sessions.
          std::string(), browser_context,
          nullptr /* blob_url_loader_factory */));

  // In some cases the |encoded_page_state| might be empty - we
  // need to gracefully handle such data when it is deserialized.
  //
  // One case is tests for "foreign" session restore entries, such as
  // SessionRestoreTest.RestoreForeignTab.  We hypothesise that old session
  // restore entries might also contain an empty |encoded_page_state|.
  if (navigation->encoded_page_state_.empty()) {
    // Ensure that the deserialized/restored content::NavigationEntry (and
    // the content::FrameNavigationEntry underneath) has a valid PageState.
    entry->SetPageState(
        blink::PageState::CreateFromURL(navigation->virtual_url_),
        restore_context);

    // The |navigation|-based referrer set below might be inconsistent with the
    // referrer embedded inside the PageState set above.  Nevertheless, to
    // minimize changes to behavior of old session restore entries, we restore
    // the deserialized referrer here.
    //
    // TODO(lukasza): Consider including the |deserialized_referrer| in the
    // PageState set above + drop the SetReferrer call below.  This will
    // slightly change the legacy behavior, but will make PageState and
    // Referrer consistent.
    entry->SetReferrer(temporary_referrer);
  } else {
    // Note that PageState covers some of the values inside |navigation| (e.g.
    // URL, Referrer).  Calling SetPageState will clobber these values in
    // content::NavigationEntry (and FrameNavigationEntry(s) below), as long as
    // the PageState successfully decodes.
    entry->SetPageState(blink::PageState::CreateFromEncodedData(
                            navigation->encoded_page_state_),
                        restore_context);

    // In theory the referrer information in the PageState should exactly match
    // the `navigation`-level data, but there are sometimes discrepancies in
    // practice (e.g. see https://crbug.com/1362322).
    //
    // TODO(crbug.com/40871594): Reintroduce DCHECKs that verify
    // consistency between `navigation->referrer_url()` and
    // `entry->GetReferrer().url` (and between referrer policies restored in
    // `entry` and remembered in `navigation`).
  }

  entry->SetTitle(navigation->title_);
  entry->SetHasPostData(navigation->has_post_data_);
  entry->SetPostID(navigation->post_id_);
  entry->SetOriginalRequestURL(navigation->original_request_url_);
  entry->SetIsOverridingUserAgent(navigation->is_overriding_user_agent_);
  entry->SetTimestamp(navigation->timestamp_);
  entry->SetHttpStatusCode(navigation->http_status_code_);
  entry->SetRedirectChain(navigation->redirect_chain_);
  entry->SetVirtualURL(navigation->virtual_url_);
  sessions::NavigationTaskId* navigation_task_id =
      sessions::NavigationTaskId::Get(entry.get());
  navigation_task_id->set_id(navigation->task_id());
  navigation_task_id->set_parent_id(navigation->parent_task_id());
  navigation_task_id->set_root_id(navigation->root_task_id());

  const ContentSerializedNavigationDriver::ExtendedInfoHandlerMap&
      extended_info_handlers = ContentSerializedNavigationDriver::GetInstance()
                                   ->GetAllExtendedInfoHandlers();
  for (const auto& extended_info_entry : navigation->extended_info_map_) {
    const std::string& key = extended_info_entry.first;
    if (!extended_info_handlers.count(key))
      continue;
    ExtendedInfoHandler* extended_info_handler =
        extended_info_handlers.at(key).get();
    DCHECK(extended_info_handler);
    extended_info_handler->RestoreExtendedInfo(extended_info_entry.second,
                                               entry.get());
  }

  // This field should have the default value.
  DCHECK_EQ(SerializedNavigationEntry::STATE_INVALID,
            navigation->blocked_state_);

  return entry;
}

// static
std::vector<std::unique_ptr<content::NavigationEntry>>
ContentSerializedNavigationBuilder::ToNavigationEntries(
    const std::vector<SerializedNavigationEntry>& navigations,
    content::BrowserContext* browser_context) {
  std::unique_ptr<content::NavigationEntryRestoreContext> restore_context =
      content::NavigationEntryRestoreContext::Create();
  std::vector<std::unique_ptr<content::NavigationEntry>> entries;
  entries.reserve(navigations.size());
  for (const auto& navigation : navigations) {
    entries.push_back(
        ToNavigationEntry(&navigation, browser_context, restore_context.get()));
  }
  return entries;
}

}  // namespace sessions