blob: 95995d5962e6368cd0944faf080d353416153ad9 [file] [log] [blame]
// 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