diff options
Diffstat (limited to 'chromium/components/sessions/serialized_navigation_entry.cc')
| -rw-r--r-- | chromium/components/sessions/serialized_navigation_entry.cc | 475 |
1 files changed, 475 insertions, 0 deletions
diff --git a/chromium/components/sessions/serialized_navigation_entry.cc b/chromium/components/sessions/serialized_navigation_entry.cc new file mode 100644 index 00000000000..5e4183cf5d2 --- /dev/null +++ b/chromium/components/sessions/serialized_navigation_entry.cc @@ -0,0 +1,475 @@ +// Copyright 2013 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/sessions/serialized_navigation_entry.h" + +#include "base/pickle.h" +#include "base/strings/utf_string_conversions.h" +#include "content/public/browser/favicon_status.h" +#include "content/public/browser/navigation_controller.h" +#include "content/public/browser/navigation_entry.h" +#include "sync/protocol/session_specifics.pb.h" +#include "sync/util/time.h" +#include "third_party/WebKit/public/platform/WebReferrerPolicy.h" + +using content::NavigationEntry; + +namespace sessions { + +const char kSearchTermsKey[] = "search_terms"; + +SerializedNavigationEntry::SerializedNavigationEntry() + : index_(-1), + unique_id_(0), + transition_type_(content::PAGE_TRANSITION_TYPED), + has_post_data_(false), + post_id_(-1), + is_overriding_user_agent_(false), + blocked_state_(STATE_INVALID) {} + +SerializedNavigationEntry::~SerializedNavigationEntry() {} + +// static +SerializedNavigationEntry SerializedNavigationEntry::FromNavigationEntry( + int index, + const NavigationEntry& entry) { + SerializedNavigationEntry navigation; + navigation.index_ = index; + navigation.unique_id_ = entry.GetUniqueID(); + navigation.referrer_ = entry.GetReferrer(); + navigation.virtual_url_ = entry.GetVirtualURL(); + navigation.title_ = entry.GetTitle(); + navigation.page_state_ = entry.GetPageState(); + 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(); + // If you want to navigate a named frame in Chrome, you will first need to + // add support for persisting it. It is currently only used for layout tests. + CHECK(entry.GetFrameToNavigate().empty()); + entry.GetExtraData(kSearchTermsKey, &navigation.search_terms_); + if (entry.GetFavicon().valid) + navigation.favicon_url_ = entry.GetFavicon().url; + + return navigation; +} + +SerializedNavigationEntry SerializedNavigationEntry::FromSyncData( + int index, + const sync_pb::TabNavigation& sync_data) { + SerializedNavigationEntry navigation; + navigation.index_ = index; + navigation.unique_id_ = sync_data.unique_id(); + navigation.referrer_ = + content::Referrer(GURL(sync_data.referrer()), + WebKit::WebReferrerPolicyDefault); + navigation.virtual_url_ = GURL(sync_data.virtual_url()); + navigation.title_ = UTF8ToUTF16(sync_data.title()); + navigation.page_state_ = + content::PageState::CreateFromEncodedData(sync_data.state()); + + uint32 transition = 0; + if (sync_data.has_page_transition()) { + switch (sync_data.page_transition()) { + case sync_pb::SyncEnums_PageTransition_LINK: + transition = content::PAGE_TRANSITION_LINK; + break; + case sync_pb::SyncEnums_PageTransition_TYPED: + transition = content::PAGE_TRANSITION_TYPED; + break; + case sync_pb::SyncEnums_PageTransition_AUTO_BOOKMARK: + transition = content::PAGE_TRANSITION_AUTO_BOOKMARK; + break; + case sync_pb::SyncEnums_PageTransition_AUTO_SUBFRAME: + transition = content::PAGE_TRANSITION_AUTO_SUBFRAME; + break; + case sync_pb::SyncEnums_PageTransition_MANUAL_SUBFRAME: + transition = content::PAGE_TRANSITION_MANUAL_SUBFRAME; + break; + case sync_pb::SyncEnums_PageTransition_GENERATED: + transition = content::PAGE_TRANSITION_GENERATED; + break; + case sync_pb::SyncEnums_PageTransition_AUTO_TOPLEVEL: + transition = content::PAGE_TRANSITION_AUTO_TOPLEVEL; + break; + case sync_pb::SyncEnums_PageTransition_FORM_SUBMIT: + transition = content::PAGE_TRANSITION_FORM_SUBMIT; + break; + case sync_pb::SyncEnums_PageTransition_RELOAD: + transition = content::PAGE_TRANSITION_RELOAD; + break; + case sync_pb::SyncEnums_PageTransition_KEYWORD: + transition = content::PAGE_TRANSITION_KEYWORD; + break; + case sync_pb::SyncEnums_PageTransition_KEYWORD_GENERATED: + transition = + content::PAGE_TRANSITION_KEYWORD_GENERATED; + break; + default: + transition = content::PAGE_TRANSITION_LINK; + break; + } + } + + if (sync_data.has_redirect_type()) { + switch (sync_data.redirect_type()) { + case sync_pb::SyncEnums_PageTransitionRedirectType_CLIENT_REDIRECT: + transition |= content::PAGE_TRANSITION_CLIENT_REDIRECT; + break; + case sync_pb::SyncEnums_PageTransitionRedirectType_SERVER_REDIRECT: + transition |= content::PAGE_TRANSITION_SERVER_REDIRECT; + break; + } + } + if (sync_data.navigation_forward_back()) + transition |= content::PAGE_TRANSITION_FORWARD_BACK; + if (sync_data.navigation_from_address_bar()) + transition |= content::PAGE_TRANSITION_FROM_ADDRESS_BAR; + if (sync_data.navigation_home_page()) + transition |= content::PAGE_TRANSITION_HOME_PAGE; + if (sync_data.navigation_chain_start()) + transition |= content::PAGE_TRANSITION_CHAIN_START; + if (sync_data.navigation_chain_end()) + transition |= content::PAGE_TRANSITION_CHAIN_END; + + navigation.transition_type_ = + static_cast<content::PageTransition>(transition); + + navigation.timestamp_ = base::Time(); + navigation.search_terms_ = UTF8ToUTF16(sync_data.search_terms()); + if (sync_data.has_favicon_url()) + navigation.favicon_url_ = GURL(sync_data.favicon_url()); + + // We shouldn't sync session data for managed users down at the moment. + DCHECK(!sync_data.has_blocked_state()); + DCHECK_EQ(0, sync_data.content_pack_categories_size()); + + return navigation; +} + +namespace { + +// Helper used by SerializedNavigationEntry::WriteToPickle(). It writes |str| to +// |pickle|, if and only if |str| fits within (|max_bytes| - +// |*bytes_written|). |bytes_written| is incremented to reflect the +// data written. +// +// TODO(akalin): Unify this with the same function in +// base_session_service.cc. +void WriteStringToPickle(Pickle* pickle, + int* bytes_written, + int max_bytes, + const std::string& str) { + int num_bytes = str.size() * sizeof(char); + if (*bytes_written + num_bytes < max_bytes) { + *bytes_written += num_bytes; + pickle->WriteString(str); + } else { + pickle->WriteString(std::string()); + } +} + +// string16 version of WriteStringToPickle. +// +// TODO(akalin): Unify this, too. +void WriteString16ToPickle(Pickle* pickle, + int* bytes_written, + int max_bytes, + const string16& str) { + int num_bytes = str.size() * sizeof(char16); + if (*bytes_written + num_bytes < max_bytes) { + *bytes_written += num_bytes; + pickle->WriteString16(str); + } else { + pickle->WriteString16(string16()); + } +} + +// A mask used for arbitrary boolean values needed to represent a +// NavigationEntry. Currently only contains HAS_POST_DATA. +// +// NOTE(akalin): We may want to just serialize |has_post_data_| +// directly. Other bools (|is_overriding_user_agent_|) haven't been +// added to this mask. +enum TypeMask { + HAS_POST_DATA = 1 +}; + +} // namespace + +// Pickle order: +// +// index_ +// virtual_url_ +// title_ +// page_state_ +// transition_type_ +// +// Added on later: +// +// type_mask (has_post_data_) +// referrer_ +// original_request_url_ +// is_overriding_user_agent_ +// timestamp_ +// search_terms_ + +void SerializedNavigationEntry::WriteToPickle(int max_size, + Pickle* pickle) const { + pickle->WriteInt(index_); + + int bytes_written = 0; + + WriteStringToPickle(pickle, &bytes_written, max_size, + virtual_url_.spec()); + + WriteString16ToPickle(pickle, &bytes_written, max_size, title_); + + content::PageState page_state = page_state_; + if (has_post_data_) + page_state = page_state.RemovePasswordData(); + + WriteStringToPickle(pickle, &bytes_written, max_size, + page_state.ToEncodedData()); + + pickle->WriteInt(transition_type_); + + const int type_mask = has_post_data_ ? HAS_POST_DATA : 0; + pickle->WriteInt(type_mask); + + WriteStringToPickle( + pickle, &bytes_written, max_size, + referrer_.url.is_valid() ? referrer_.url.spec() : std::string()); + + pickle->WriteInt(referrer_.policy); + + // Save info required to override the user agent. + WriteStringToPickle( + pickle, &bytes_written, max_size, + original_request_url_.is_valid() ? + original_request_url_.spec() : std::string()); + pickle->WriteBool(is_overriding_user_agent_); + pickle->WriteInt64(timestamp_.ToInternalValue()); + + WriteString16ToPickle(pickle, &bytes_written, max_size, search_terms_); +} + +bool SerializedNavigationEntry::ReadFromPickle(PickleIterator* iterator) { + *this = SerializedNavigationEntry(); + std::string virtual_url_spec, page_state_data; + int transition_type_int = 0; + if (!iterator->ReadInt(&index_) || + !iterator->ReadString(&virtual_url_spec) || + !iterator->ReadString16(&title_) || + !iterator->ReadString(&page_state_data) || + !iterator->ReadInt(&transition_type_int)) + return false; + virtual_url_ = GURL(virtual_url_spec); + page_state_ = content::PageState::CreateFromEncodedData(page_state_data); + transition_type_ = static_cast<content::PageTransition>(transition_type_int); + + // type_mask did not always exist in the written stream. As such, we + // don't fail if it can't be read. + int type_mask = 0; + bool has_type_mask = iterator->ReadInt(&type_mask); + + if (has_type_mask) { + has_post_data_ = type_mask & HAS_POST_DATA; + // the "referrer" property was added after type_mask to the written + // stream. As such, we don't fail if it can't be read. + std::string referrer_spec; + if (!iterator->ReadString(&referrer_spec)) + referrer_spec = std::string(); + // The "referrer policy" property was added even later, so we fall back to + // the default policy if the property is not present. + int policy_int; + WebKit::WebReferrerPolicy policy; + if (iterator->ReadInt(&policy_int)) + policy = static_cast<WebKit::WebReferrerPolicy>(policy_int); + else + policy = WebKit::WebReferrerPolicyDefault; + referrer_ = content::Referrer(GURL(referrer_spec), policy); + + // If the original URL can't be found, leave it empty. + std::string original_request_url_spec; + if (!iterator->ReadString(&original_request_url_spec)) + original_request_url_spec = std::string(); + original_request_url_ = GURL(original_request_url_spec); + + // Default to not overriding the user agent if we don't have info. + if (!iterator->ReadBool(&is_overriding_user_agent_)) + is_overriding_user_agent_ = false; + + int64 timestamp_internal_value = 0; + if (iterator->ReadInt64(×tamp_internal_value)) { + timestamp_ = base::Time::FromInternalValue(timestamp_internal_value); + } else { + timestamp_ = base::Time(); + } + + // If the search terms field can't be found, leave it empty. + if (!iterator->ReadString16(&search_terms_)) + search_terms_.clear(); + } + + return true; +} + +scoped_ptr<NavigationEntry> SerializedNavigationEntry::ToNavigationEntry( + int page_id, + content::BrowserContext* browser_context) const { + scoped_ptr<NavigationEntry> entry( + content::NavigationController::CreateNavigationEntry( + virtual_url_, + referrer_, + // Use a transition type of reload so that we don't incorrectly + // increase the typed count. + content::PAGE_TRANSITION_RELOAD, + false, + // The extra headers are not sync'ed across sessions. + std::string(), + browser_context)); + + entry->SetTitle(title_); + entry->SetPageState(page_state_); + entry->SetPageID(page_id); + entry->SetHasPostData(has_post_data_); + entry->SetPostID(post_id_); + entry->SetOriginalRequestURL(original_request_url_); + entry->SetIsOverridingUserAgent(is_overriding_user_agent_); + entry->SetTimestamp(timestamp_); + entry->SetExtraData(kSearchTermsKey, search_terms_); + + // These fields should have default values. + DCHECK_EQ(STATE_INVALID, blocked_state_); + DCHECK_EQ(0u, content_pack_categories_.size()); + + return entry.Pass(); +} + +// TODO(zea): perhaps sync state (scroll position, form entries, etc.) as well? +// See http://crbug.com/67068. +sync_pb::TabNavigation SerializedNavigationEntry::ToSyncData() const { + sync_pb::TabNavigation sync_data; + sync_data.set_virtual_url(virtual_url_.spec()); + // FIXME(zea): Support referrer policy? + sync_data.set_referrer(referrer_.url.spec()); + sync_data.set_title(UTF16ToUTF8(title_)); + + // Page transition core. + COMPILE_ASSERT(content::PAGE_TRANSITION_LAST_CORE == + content::PAGE_TRANSITION_KEYWORD_GENERATED, + PageTransitionCoreBounds); + switch (PageTransitionStripQualifier(transition_type_)) { + case content::PAGE_TRANSITION_LINK: + sync_data.set_page_transition( + sync_pb::SyncEnums_PageTransition_LINK); + break; + case content::PAGE_TRANSITION_TYPED: + sync_data.set_page_transition( + sync_pb::SyncEnums_PageTransition_TYPED); + break; + case content::PAGE_TRANSITION_AUTO_BOOKMARK: + sync_data.set_page_transition( + sync_pb::SyncEnums_PageTransition_AUTO_BOOKMARK); + break; + case content::PAGE_TRANSITION_AUTO_SUBFRAME: + sync_data.set_page_transition( + sync_pb::SyncEnums_PageTransition_AUTO_SUBFRAME); + break; + case content::PAGE_TRANSITION_MANUAL_SUBFRAME: + sync_data.set_page_transition( + sync_pb::SyncEnums_PageTransition_MANUAL_SUBFRAME); + break; + case content::PAGE_TRANSITION_GENERATED: + sync_data.set_page_transition( + sync_pb::SyncEnums_PageTransition_GENERATED); + break; + case content::PAGE_TRANSITION_AUTO_TOPLEVEL: + sync_data.set_page_transition( + sync_pb::SyncEnums_PageTransition_AUTO_TOPLEVEL); + break; + case content::PAGE_TRANSITION_FORM_SUBMIT: + sync_data.set_page_transition( + sync_pb::SyncEnums_PageTransition_FORM_SUBMIT); + break; + case content::PAGE_TRANSITION_RELOAD: + sync_data.set_page_transition( + sync_pb::SyncEnums_PageTransition_RELOAD); + break; + case content::PAGE_TRANSITION_KEYWORD: + sync_data.set_page_transition( + sync_pb::SyncEnums_PageTransition_KEYWORD); + break; + case content::PAGE_TRANSITION_KEYWORD_GENERATED: + sync_data.set_page_transition( + sync_pb::SyncEnums_PageTransition_KEYWORD_GENERATED); + break; + default: + NOTREACHED(); + } + + // Page transition qualifiers. + if (PageTransitionIsRedirect(transition_type_)) { + if (transition_type_ & content::PAGE_TRANSITION_CLIENT_REDIRECT) { + sync_data.set_redirect_type( + sync_pb::SyncEnums_PageTransitionRedirectType_CLIENT_REDIRECT); + } else if (transition_type_ & content::PAGE_TRANSITION_SERVER_REDIRECT) { + sync_data.set_redirect_type( + sync_pb::SyncEnums_PageTransitionRedirectType_SERVER_REDIRECT); + } + } + sync_data.set_navigation_forward_back( + (transition_type_ & content::PAGE_TRANSITION_FORWARD_BACK) != 0); + sync_data.set_navigation_from_address_bar( + (transition_type_ & content::PAGE_TRANSITION_FROM_ADDRESS_BAR) != 0); + sync_data.set_navigation_home_page( + (transition_type_ & content::PAGE_TRANSITION_HOME_PAGE) != 0); + sync_data.set_navigation_chain_start( + (transition_type_ & content::PAGE_TRANSITION_CHAIN_START) != 0); + sync_data.set_navigation_chain_end( + (transition_type_ & content::PAGE_TRANSITION_CHAIN_END) != 0); + + sync_data.set_unique_id(unique_id_); + sync_data.set_timestamp_msec(syncer::TimeToProtoTime(timestamp_)); + // The full-resolution timestamp works as a global ID. + sync_data.set_global_id(timestamp_.ToInternalValue()); + + sync_data.set_search_terms(UTF16ToUTF8(search_terms_)); + + if (favicon_url_.is_valid()) + sync_data.set_favicon_url(favicon_url_.spec()); + + if (blocked_state_ != STATE_INVALID) { + sync_data.set_blocked_state( + static_cast<sync_pb::TabNavigation_BlockedState>(blocked_state_)); + } + + for (std::set<std::string>::const_iterator it = + content_pack_categories_.begin(); + it != content_pack_categories_.end(); ++it) { + sync_data.add_content_pack_categories(*it); + } + + return sync_data; +} + +// static +std::vector<NavigationEntry*> SerializedNavigationEntry::ToNavigationEntries( + const std::vector<SerializedNavigationEntry>& navigations, + content::BrowserContext* browser_context) { + int page_id = 0; + std::vector<NavigationEntry*> entries; + for (std::vector<SerializedNavigationEntry>::const_iterator + it = navigations.begin(); it != navigations.end(); ++it) { + entries.push_back( + it->ToNavigationEntry(page_id, browser_context).release()); + ++page_id; + } + return entries; +} + +} // namespace sessions |
