| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "components/sync_sessions/synced_session.h" |
| |
| #include <vector> |
| |
| #include "base/strings/utf_string_conversions.h" |
| #include "components/sessions/core/serialized_navigation_driver.h" |
| #include "components/sync/base/time.h" |
| #include "ui/base/page_transition_types.h" |
| |
| namespace sync_sessions { |
| namespace { |
| |
| using sessions::SerializedNavigationEntry; |
| |
| // The previous referrer policy value corresponding to |Never|. |
| // See original constant in serialized_navigation_entry.cc. |
| const int kObsoleteReferrerPolicyNever = 2; |
| |
| sync_pb::SyncEnums_PageTransition ToSyncPageTransition( |
| ui::PageTransition transition_type) { |
| switch (ui::PageTransitionStripQualifier(transition_type)) { |
| case ui::PAGE_TRANSITION_LINK: |
| return sync_pb::SyncEnums_PageTransition_LINK; |
| |
| case ui::PAGE_TRANSITION_TYPED: |
| return sync_pb::SyncEnums_PageTransition_TYPED; |
| |
| case ui::PAGE_TRANSITION_AUTO_BOOKMARK: |
| return sync_pb::SyncEnums_PageTransition_AUTO_BOOKMARK; |
| |
| case ui::PAGE_TRANSITION_AUTO_SUBFRAME: |
| return sync_pb::SyncEnums_PageTransition_AUTO_SUBFRAME; |
| |
| case ui::PAGE_TRANSITION_MANUAL_SUBFRAME: |
| return sync_pb::SyncEnums_PageTransition_MANUAL_SUBFRAME; |
| |
| case ui::PAGE_TRANSITION_GENERATED: |
| return sync_pb::SyncEnums_PageTransition_GENERATED; |
| |
| case ui::PAGE_TRANSITION_AUTO_TOPLEVEL: |
| return sync_pb::SyncEnums_PageTransition_AUTO_TOPLEVEL; |
| |
| case ui::PAGE_TRANSITION_FORM_SUBMIT: |
| return sync_pb::SyncEnums_PageTransition_FORM_SUBMIT; |
| |
| case ui::PAGE_TRANSITION_RELOAD: |
| return sync_pb::SyncEnums_PageTransition_RELOAD; |
| |
| case ui::PAGE_TRANSITION_KEYWORD: |
| return sync_pb::SyncEnums_PageTransition_KEYWORD; |
| |
| case ui::PAGE_TRANSITION_KEYWORD_GENERATED: |
| return sync_pb::SyncEnums_PageTransition_KEYWORD_GENERATED; |
| |
| // Non-core values listed here although unreachable: |
| case ui::PAGE_TRANSITION_CORE_MASK: |
| case ui::PAGE_TRANSITION_BLOCKED: |
| case ui::PAGE_TRANSITION_FORWARD_BACK: |
| case ui::PAGE_TRANSITION_FROM_ADDRESS_BAR: |
| case ui::PAGE_TRANSITION_HOME_PAGE: |
| case ui::PAGE_TRANSITION_FROM_API: |
| case ui::PAGE_TRANSITION_CHAIN_START: |
| case ui::PAGE_TRANSITION_CHAIN_END: |
| case ui::PAGE_TRANSITION_CLIENT_REDIRECT: |
| case ui::PAGE_TRANSITION_SERVER_REDIRECT: |
| case ui::PAGE_TRANSITION_IS_REDIRECT_MASK: |
| case ui::PAGE_TRANSITION_QUALIFIER_MASK: |
| break; |
| } |
| NOTREACHED(); |
| return sync_pb::SyncEnums_PageTransition_LINK; |
| } |
| |
| ui::PageTransition FromSyncPageTransition( |
| sync_pb::SyncEnums_PageTransition transition_type) { |
| switch (transition_type) { |
| case sync_pb::SyncEnums_PageTransition_LINK: |
| return ui::PAGE_TRANSITION_LINK; |
| |
| case sync_pb::SyncEnums_PageTransition_TYPED: |
| return ui::PAGE_TRANSITION_TYPED; |
| |
| case sync_pb::SyncEnums_PageTransition_AUTO_BOOKMARK: |
| return ui::PAGE_TRANSITION_AUTO_BOOKMARK; |
| |
| case sync_pb::SyncEnums_PageTransition_AUTO_SUBFRAME: |
| return ui::PAGE_TRANSITION_AUTO_SUBFRAME; |
| |
| case sync_pb::SyncEnums_PageTransition_MANUAL_SUBFRAME: |
| return ui::PAGE_TRANSITION_MANUAL_SUBFRAME; |
| |
| case sync_pb::SyncEnums_PageTransition_GENERATED: |
| return ui::PAGE_TRANSITION_GENERATED; |
| |
| case sync_pb::SyncEnums_PageTransition_AUTO_TOPLEVEL: |
| return ui::PAGE_TRANSITION_AUTO_TOPLEVEL; |
| |
| case sync_pb::SyncEnums_PageTransition_FORM_SUBMIT: |
| return ui::PAGE_TRANSITION_FORM_SUBMIT; |
| |
| case sync_pb::SyncEnums_PageTransition_RELOAD: |
| return ui::PAGE_TRANSITION_RELOAD; |
| |
| case sync_pb::SyncEnums_PageTransition_KEYWORD: |
| return ui::PAGE_TRANSITION_KEYWORD; |
| |
| case sync_pb::SyncEnums_PageTransition_KEYWORD_GENERATED: |
| return ui::PAGE_TRANSITION_KEYWORD_GENERATED; |
| } |
| return ui::PAGE_TRANSITION_LINK; |
| } |
| |
| } // namespace |
| |
| SerializedNavigationEntry SessionNavigationFromSyncData( |
| int index, |
| const sync_pb::TabNavigation& sync_data) { |
| SerializedNavigationEntry navigation; |
| navigation.set_index(index); |
| navigation.set_unique_id(sync_data.unique_id()); |
| if (sync_data.has_correct_referrer_policy()) { |
| navigation.set_referrer_url(GURL(sync_data.referrer())); |
| navigation.set_referrer_policy(sync_data.correct_referrer_policy()); |
| } else { |
| navigation.set_referrer_url(GURL()); |
| navigation.set_referrer_policy(kObsoleteReferrerPolicyNever); |
| } |
| navigation.set_virtual_url(GURL(sync_data.virtual_url())); |
| navigation.set_title(base::UTF8ToUTF16(sync_data.title())); |
| |
| uint32_t transition = FromSyncPageTransition(sync_data.page_transition()); |
| |
| if (sync_data.has_redirect_type()) { |
| switch (sync_data.redirect_type()) { |
| case sync_pb::SyncEnums_PageTransitionRedirectType_CLIENT_REDIRECT: |
| transition |= ui::PAGE_TRANSITION_CLIENT_REDIRECT; |
| break; |
| case sync_pb::SyncEnums_PageTransitionRedirectType_SERVER_REDIRECT: |
| transition |= ui::PAGE_TRANSITION_SERVER_REDIRECT; |
| break; |
| } |
| } |
| if (sync_data.navigation_forward_back()) |
| transition |= ui::PAGE_TRANSITION_FORWARD_BACK; |
| if (sync_data.navigation_from_address_bar()) |
| transition |= ui::PAGE_TRANSITION_FROM_ADDRESS_BAR; |
| if (sync_data.navigation_home_page()) |
| transition |= ui::PAGE_TRANSITION_HOME_PAGE; |
| if (sync_data.navigation_chain_start()) |
| transition |= ui::PAGE_TRANSITION_CHAIN_START; |
| if (sync_data.navigation_chain_end()) |
| transition |= ui::PAGE_TRANSITION_CHAIN_END; |
| |
| navigation.set_transition_type(static_cast<ui::PageTransition>(transition)); |
| |
| navigation.set_timestamp(syncer::ProtoTimeToTime(sync_data.timestamp_msec())); |
| if (sync_data.has_favicon_url()) |
| navigation.set_favicon_url(GURL(sync_data.favicon_url())); |
| |
| if (sync_data.has_password_state()) { |
| navigation.set_password_state( |
| static_cast<SerializedNavigationEntry::PasswordState>( |
| sync_data.password_state())); |
| } |
| |
| navigation.set_http_status_code(sync_data.http_status_code()); |
| |
| if (sync_data.has_replaced_navigation()) { |
| SerializedNavigationEntry::ReplacedNavigationEntryData replaced_entry_data; |
| replaced_entry_data.first_committed_url = |
| GURL(sync_data.replaced_navigation().first_committed_url()); |
| replaced_entry_data.first_timestamp = syncer::ProtoTimeToTime( |
| sync_data.replaced_navigation().first_timestamp_msec()); |
| replaced_entry_data.first_transition_type = FromSyncPageTransition( |
| sync_data.replaced_navigation().first_page_transition()); |
| navigation.set_replaced_entry_data(replaced_entry_data); |
| } |
| |
| sessions::SerializedNavigationDriver::Get()->Sanitize(&navigation); |
| |
| navigation.set_is_restored(true); |
| |
| return navigation; |
| } |
| |
| // TODO(zea): perhaps sync state (scroll position, form entries, etc.) as well? |
| // See http://crbug.com/67068. |
| sync_pb::TabNavigation SessionNavigationToSyncData( |
| const SerializedNavigationEntry& navigation) { |
| sync_pb::TabNavigation sync_data; |
| sync_data.set_virtual_url(navigation.virtual_url().spec()); |
| sync_data.set_referrer(navigation.referrer_url().spec()); |
| sync_data.set_correct_referrer_policy(navigation.referrer_policy()); |
| sync_data.set_title(base::UTF16ToUTF8(navigation.title())); |
| |
| // Page transition core. |
| static_assert(static_cast<int32_t>(ui::PAGE_TRANSITION_LAST_CORE) == |
| static_cast<int32_t>(ui::PAGE_TRANSITION_KEYWORD_GENERATED), |
| "PAGE_TRANSITION_LAST_CORE must equal " |
| "PAGE_TRANSITION_KEYWORD_GENERATED"); |
| const ui::PageTransition transition_type = navigation.transition_type(); |
| sync_data.set_page_transition(ToSyncPageTransition(transition_type)); |
| |
| // Page transition qualifiers. |
| if (ui::PageTransitionIsRedirect(transition_type)) { |
| if (transition_type & ui::PAGE_TRANSITION_CLIENT_REDIRECT) { |
| sync_data.set_redirect_type( |
| sync_pb::SyncEnums_PageTransitionRedirectType_CLIENT_REDIRECT); |
| } else if (transition_type & ui::PAGE_TRANSITION_SERVER_REDIRECT) { |
| sync_data.set_redirect_type( |
| sync_pb::SyncEnums_PageTransitionRedirectType_SERVER_REDIRECT); |
| } |
| } |
| sync_data.set_navigation_forward_back( |
| (transition_type & ui::PAGE_TRANSITION_FORWARD_BACK) != 0); |
| sync_data.set_navigation_from_address_bar( |
| (transition_type & ui::PAGE_TRANSITION_FROM_ADDRESS_BAR) != 0); |
| sync_data.set_navigation_home_page( |
| (transition_type & ui::PAGE_TRANSITION_HOME_PAGE) != 0); |
| sync_data.set_navigation_chain_start( |
| (transition_type & ui::PAGE_TRANSITION_CHAIN_START) != 0); |
| sync_data.set_navigation_chain_end( |
| (transition_type & ui::PAGE_TRANSITION_CHAIN_END) != 0); |
| |
| sync_data.set_unique_id(navigation.unique_id()); |
| sync_data.set_timestamp_msec(syncer::TimeToProtoTime(navigation.timestamp())); |
| // The full-resolution timestamp works as a global ID. |
| sync_data.set_global_id(navigation.timestamp().ToInternalValue()); |
| |
| sync_data.set_http_status_code(navigation.http_status_code()); |
| |
| if (navigation.favicon_url().is_valid()) |
| sync_data.set_favicon_url(navigation.favicon_url().spec()); |
| |
| if (navigation.blocked_state() != SerializedNavigationEntry::STATE_INVALID) { |
| sync_data.set_blocked_state( |
| static_cast<sync_pb::TabNavigation_BlockedState>( |
| navigation.blocked_state())); |
| } |
| |
| sync_data.set_password_state( |
| static_cast<sync_pb::TabNavigation_PasswordState>( |
| navigation.password_state())); |
| |
| for (const std::string& content_pack_category : |
| navigation.content_pack_categories()) { |
| sync_data.add_content_pack_categories(content_pack_category); |
| } |
| |
| // Copy all redirect chain entries except the last URL (which should match |
| // the virtual_url). |
| const std::vector<GURL>& redirect_chain = navigation.redirect_chain(); |
| if (redirect_chain.size() > 1) { // Single entry chains have no redirection. |
| size_t last_entry = redirect_chain.size() - 1; |
| for (size_t i = 0; i < last_entry; i++) { |
| sync_pb::NavigationRedirect* navigation_redirect = |
| sync_data.add_navigation_redirect(); |
| navigation_redirect->set_url(redirect_chain[i].spec()); |
| } |
| // If the last URL didn't match the virtual_url, record it separately. |
| if (sync_data.virtual_url() != redirect_chain[last_entry].spec()) { |
| sync_data.set_last_navigation_redirect_url( |
| redirect_chain[last_entry].spec()); |
| } |
| } |
| |
| const base::Optional<SerializedNavigationEntry::ReplacedNavigationEntryData>& |
| replaced_entry_data = navigation.replaced_entry_data(); |
| if (replaced_entry_data.has_value()) { |
| sync_pb::ReplacedNavigation* replaced_navigation = |
| sync_data.mutable_replaced_navigation(); |
| replaced_navigation->set_first_committed_url( |
| replaced_entry_data->first_committed_url.spec()); |
| replaced_navigation->set_first_timestamp_msec( |
| syncer::TimeToProtoTime(replaced_entry_data->first_timestamp)); |
| replaced_navigation->set_first_page_transition( |
| ToSyncPageTransition(replaced_entry_data->first_transition_type)); |
| } |
| |
| sync_data.set_is_restored(navigation.is_restored()); |
| |
| return sync_data; |
| } |
| |
| void SetSessionTabFromSyncData(const sync_pb::SessionTab& sync_data, |
| base::Time timestamp, |
| sessions::SessionTab* tab) { |
| DCHECK(tab); |
| tab->window_id = SessionID::FromSerializedValue(sync_data.window_id()); |
| tab->tab_id = SessionID::FromSerializedValue(sync_data.tab_id()); |
| tab->tab_visual_index = sync_data.tab_visual_index(); |
| tab->current_navigation_index = sync_data.current_navigation_index(); |
| tab->pinned = sync_data.pinned(); |
| tab->extension_app_id = sync_data.extension_app_id(); |
| tab->user_agent_override.clear(); |
| tab->timestamp = timestamp; |
| tab->navigations.clear(); |
| for (int i = 0; i < sync_data.navigation_size(); ++i) { |
| tab->navigations.push_back( |
| SessionNavigationFromSyncData(i, sync_data.navigation(i))); |
| } |
| tab->session_storage_persistent_id.clear(); |
| } |
| |
| sync_pb::SessionTab SessionTabToSyncData(const sessions::SessionTab& tab) { |
| sync_pb::SessionTab sync_data; |
| sync_data.set_tab_id(tab.tab_id.id()); |
| sync_data.set_window_id(tab.window_id.id()); |
| sync_data.set_tab_visual_index(tab.tab_visual_index); |
| sync_data.set_current_navigation_index(tab.current_navigation_index); |
| sync_data.set_pinned(tab.pinned); |
| sync_data.set_extension_app_id(tab.extension_app_id); |
| for (const SerializedNavigationEntry& navigation : tab.navigations) { |
| SessionNavigationToSyncData(navigation).Swap(sync_data.add_navigation()); |
| } |
| return sync_data; |
| } |
| |
| SyncedSessionWindow::SyncedSessionWindow() {} |
| |
| SyncedSessionWindow::~SyncedSessionWindow() {} |
| |
| sync_pb::SessionWindow SyncedSessionWindow::ToSessionWindowProto() const { |
| sync_pb::SessionWindow sync_data; |
| sync_data.set_browser_type(window_type); |
| sync_data.set_window_id(wrapped_window.window_id.id()); |
| sync_data.set_selected_tab_index(wrapped_window.selected_tab_index); |
| |
| for (const auto& tab : wrapped_window.tabs) |
| sync_data.add_tab(tab->tab_id.id()); |
| |
| return sync_data; |
| } |
| |
| SyncedSession::SyncedSession() |
| : session_tag("invalid"), device_type(sync_pb::SyncEnums::TYPE_UNSET) {} |
| |
| SyncedSession::~SyncedSession() {} |
| |
| sync_pb::SessionHeader SyncedSession::ToSessionHeaderProto() const { |
| sync_pb::SessionHeader header; |
| for (const auto& window_pair : windows) { |
| sync_pb::SessionWindow* w = header.add_window(); |
| w->CopyFrom(window_pair.second->ToSessionWindowProto()); |
| } |
| header.set_client_name(session_name); |
| header.set_device_type(device_type); |
| return header; |
| } |
| |
| } // namespace sync_sessions |