content_serialized_navigation_builder.cc 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. // Copyright 2014 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. #include "components/sessions/content/content_serialized_navigation_builder.h"
  5. #include <string>
  6. #include "base/check_op.h"
  7. #include "components/sessions/content/content_record_password_state.h"
  8. #include "components/sessions/content/content_serialized_navigation_driver.h"
  9. #include "components/sessions/content/extended_info_handler.h"
  10. #include "components/sessions/content/navigation_task_id.h"
  11. #include "components/sessions/core/serialized_navigation_entry.h"
  12. #include "content/public/browser/browser_context.h"
  13. #include "content/public/browser/favicon_status.h"
  14. #include "content/public/browser/navigation_controller.h"
  15. #include "content/public/browser/navigation_entry.h"
  16. #include "content/public/browser/navigation_entry_restore_context.h"
  17. #include "content/public/browser/replaced_navigation_entry_data.h"
  18. #include "content/public/common/referrer.h"
  19. #include "services/network/public/cpp/shared_url_loader_factory.h"
  20. #include "third_party/blink/public/common/page_state/page_state.h"
  21. namespace sessions {
  22. namespace {
  23. absl::optional<SerializedNavigationEntry::ReplacedNavigationEntryData>
  24. ConvertReplacedEntryData(
  25. const absl::optional<content::ReplacedNavigationEntryData>& input_data) {
  26. if (!input_data.has_value())
  27. return absl::nullopt;
  28. SerializedNavigationEntry::ReplacedNavigationEntryData output_data;
  29. output_data.first_committed_url = input_data->first_committed_url;
  30. output_data.first_timestamp = input_data->first_timestamp;
  31. output_data.first_transition_type = input_data->first_transition_type;
  32. return output_data;
  33. }
  34. } // namespace
  35. // static
  36. SerializedNavigationEntry
  37. ContentSerializedNavigationBuilder::FromNavigationEntry(
  38. int index,
  39. content::NavigationEntry* entry,
  40. SerializationOptions serialization_options) {
  41. SerializedNavigationEntry navigation;
  42. navigation.index_ = index;
  43. navigation.unique_id_ = entry->GetUniqueID();
  44. navigation.referrer_url_ = entry->GetReferrer().url;
  45. navigation.referrer_policy_ = static_cast<int>(entry->GetReferrer().policy);
  46. navigation.virtual_url_ = entry->GetVirtualURL();
  47. navigation.title_ = entry->GetTitle();
  48. if (!(serialization_options & SerializationOptions::EXCLUDE_PAGE_STATE))
  49. navigation.encoded_page_state_ = entry->GetPageState().ToEncodedData();
  50. navigation.transition_type_ = entry->GetTransitionType();
  51. navigation.has_post_data_ = entry->GetHasPostData();
  52. navigation.post_id_ = entry->GetPostID();
  53. navigation.original_request_url_ = entry->GetOriginalRequestURL();
  54. navigation.is_overriding_user_agent_ = entry->GetIsOverridingUserAgent();
  55. navigation.timestamp_ = entry->GetTimestamp();
  56. navigation.is_restored_ = entry->IsRestored();
  57. if (entry->GetFavicon().valid)
  58. navigation.favicon_url_ = entry->GetFavicon().url;
  59. navigation.http_status_code_ = entry->GetHttpStatusCode();
  60. navigation.redirect_chain_ = entry->GetRedirectChain();
  61. navigation.replaced_entry_data_ =
  62. ConvertReplacedEntryData(entry->GetReplacedEntryData());
  63. navigation.password_state_ = GetPasswordStateFromNavigation(entry);
  64. navigation.task_id_ = NavigationTaskId::Get(entry)->id();
  65. navigation.parent_task_id_ = NavigationTaskId::Get(entry)->parent_id();
  66. navigation.root_task_id_ = NavigationTaskId::Get(entry)->root_id();
  67. for (const auto& handler_entry :
  68. ContentSerializedNavigationDriver::GetInstance()
  69. ->GetAllExtendedInfoHandlers()) {
  70. ExtendedInfoHandler* handler = handler_entry.second.get();
  71. DCHECK(handler);
  72. std::string value = handler->GetExtendedInfo(entry);
  73. if (!value.empty())
  74. navigation.extended_info_map_[handler_entry.first] = value;
  75. }
  76. return navigation;
  77. }
  78. // static
  79. std::unique_ptr<content::NavigationEntry>
  80. ContentSerializedNavigationBuilder::ToNavigationEntry(
  81. const SerializedNavigationEntry* navigation,
  82. content::BrowserContext* browser_context,
  83. content::NavigationEntryRestoreContext* restore_context) {
  84. DCHECK(navigation);
  85. DCHECK(browser_context);
  86. DCHECK(restore_context);
  87. // The initial values of the NavigationEntry are only temporary - they
  88. // will get cloberred by one of the SetPageState calls below.
  89. //
  90. // This means that things like |navigation->referrer_url| are ignored
  91. // in favor of using the data stored in |navigation->encoded_page_state|.
  92. GURL temporary_url;
  93. content::Referrer temporary_referrer;
  94. absl::optional<url::Origin> temporary_initiator_origin;
  95. std::unique_ptr<content::NavigationEntry> entry(
  96. content::NavigationController::CreateNavigationEntry(
  97. temporary_url, temporary_referrer, temporary_initiator_origin,
  98. // Use a transition type of reload so that we don't incorrectly
  99. // increase the typed count.
  100. ui::PAGE_TRANSITION_RELOAD, false,
  101. // The extra headers are not sync'ed across sessions.
  102. std::string(), browser_context,
  103. nullptr /* blob_url_loader_factory */));
  104. // In some cases the |encoded_page_state| might be empty - we
  105. // need to gracefully handle such data when it is deserialized.
  106. //
  107. // One case is tests for "foreign" session restore entries, such as
  108. // SessionRestoreTest.RestoreForeignTab. We hypothesise that old session
  109. // restore entries might also contain an empty |encoded_page_state|.
  110. if (navigation->encoded_page_state_.empty()) {
  111. // Ensure that the deserialized/restored content::NavigationEntry (and
  112. // the content::FrameNavigationEntry underneath) has a valid PageState.
  113. entry->SetPageState(
  114. blink::PageState::CreateFromURL(navigation->virtual_url_),
  115. restore_context);
  116. // The |navigation|-based referrer set below might be inconsistent with the
  117. // referrer embedded inside the PageState set above. Nevertheless, to
  118. // minimize changes to behavior of old session restore entries, we restore
  119. // the deserialized referrer here.
  120. //
  121. // TODO(lukasza): Consider including the |deserialized_referrer| in the
  122. // PageState set above + drop the SetReferrer call below. This will
  123. // slightly change the legacy behavior, but will make PageState and
  124. // Referrer consistent.
  125. content::Referrer referrer(
  126. navigation->referrer_url(),
  127. content::Referrer::ConvertToPolicy(navigation->referrer_policy()));
  128. entry->SetReferrer(referrer);
  129. } else {
  130. // Note that PageState covers some of the values inside |navigation| (e.g.
  131. // URL, Referrer). Calling SetPageState will clobber these values in
  132. // content::NavigationEntry (and FrameNavigationEntry(s) below).
  133. entry->SetPageState(blink::PageState::CreateFromEncodedData(
  134. navigation->encoded_page_state_),
  135. restore_context);
  136. // |navigation|-level referrer information is redundant wrt PageState, but
  137. // they should be consistent / in-sync.
  138. DCHECK_EQ(navigation->referrer_url(), entry->GetReferrer().url);
  139. DCHECK_EQ(navigation->referrer_policy(),
  140. static_cast<int>(entry->GetReferrer().policy));
  141. }
  142. entry->SetTitle(navigation->title_);
  143. entry->SetHasPostData(navigation->has_post_data_);
  144. entry->SetPostID(navigation->post_id_);
  145. entry->SetOriginalRequestURL(navigation->original_request_url_);
  146. entry->SetIsOverridingUserAgent(navigation->is_overriding_user_agent_);
  147. entry->SetTimestamp(navigation->timestamp_);
  148. entry->SetHttpStatusCode(navigation->http_status_code_);
  149. entry->SetRedirectChain(navigation->redirect_chain_);
  150. entry->SetVirtualURL(navigation->virtual_url_);
  151. sessions::NavigationTaskId* navigation_task_id =
  152. sessions::NavigationTaskId::Get(entry.get());
  153. navigation_task_id->set_id(navigation->task_id());
  154. navigation_task_id->set_parent_id(navigation->parent_task_id());
  155. navigation_task_id->set_root_id(navigation->root_task_id());
  156. const ContentSerializedNavigationDriver::ExtendedInfoHandlerMap&
  157. extended_info_handlers = ContentSerializedNavigationDriver::GetInstance()
  158. ->GetAllExtendedInfoHandlers();
  159. for (const auto& extended_info_entry : navigation->extended_info_map_) {
  160. const std::string& key = extended_info_entry.first;
  161. if (!extended_info_handlers.count(key))
  162. continue;
  163. ExtendedInfoHandler* extended_info_handler =
  164. extended_info_handlers.at(key).get();
  165. DCHECK(extended_info_handler);
  166. extended_info_handler->RestoreExtendedInfo(extended_info_entry.second,
  167. entry.get());
  168. }
  169. // This field should have the default value.
  170. DCHECK_EQ(SerializedNavigationEntry::STATE_INVALID,
  171. navigation->blocked_state_);
  172. return entry;
  173. }
  174. // static
  175. std::vector<std::unique_ptr<content::NavigationEntry>>
  176. ContentSerializedNavigationBuilder::ToNavigationEntries(
  177. const std::vector<SerializedNavigationEntry>& navigations,
  178. content::BrowserContext* browser_context) {
  179. std::unique_ptr<content::NavigationEntryRestoreContext> restore_context =
  180. content::NavigationEntryRestoreContext::Create();
  181. std::vector<std::unique_ptr<content::NavigationEntry>> entries;
  182. entries.reserve(navigations.size());
  183. for (const auto& navigation : navigations) {
  184. entries.push_back(
  185. ToNavigationEntry(&navigation, browser_context, restore_context.get()));
  186. }
  187. return entries;
  188. }
  189. } // namespace sessions