1 // Copyright 2013 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.
5 #include "components/sessions/serialized_navigation_entry.h"
7 #include "base/pickle.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "components/sessions/core/serialized_navigation_driver.h"
10 #include "sync/protocol/session_specifics.pb.h"
11 #include "sync/util/time.h"
15 const char kSearchTermsKey
[] = "search_terms";
17 SerializedNavigationEntry::SerializedNavigationEntry()
20 transition_type_(ui::PAGE_TRANSITION_TYPED
),
21 has_post_data_(false),
23 is_overriding_user_agent_(false),
26 blocked_state_(STATE_INVALID
) {
28 SerializedNavigationDriver::Get()->GetDefaultReferrerPolicy();
31 SerializedNavigationEntry::~SerializedNavigationEntry() {}
33 SerializedNavigationEntry
SerializedNavigationEntry::FromSyncData(
35 const sync_pb::TabNavigation
& sync_data
) {
36 SerializedNavigationEntry navigation
;
37 navigation
.index_
= index
;
38 navigation
.unique_id_
= sync_data
.unique_id();
39 navigation
.encoded_page_state_
= sync_data
.state();
40 if (sync_data
.has_correct_referrer_policy()) {
41 navigation
.referrer_url_
= GURL(sync_data
.referrer());
42 navigation
.referrer_policy_
= sync_data
.correct_referrer_policy();
44 int mapped_referrer_policy
;
45 if (SerializedNavigationDriver::Get()->MapReferrerPolicyToNewValues(
46 sync_data
.obsolete_referrer_policy(), &mapped_referrer_policy
)) {
47 navigation
.referrer_url_
= GURL(sync_data
.referrer());
49 navigation
.referrer_url_
= GURL();
51 navigation
.referrer_policy_
= mapped_referrer_policy
;
52 navigation
.encoded_page_state_
=
53 SerializedNavigationDriver::Get()->StripReferrerFromPageState(
54 navigation
.encoded_page_state_
);
56 navigation
.virtual_url_
= GURL(sync_data
.virtual_url());
57 navigation
.title_
= base::UTF8ToUTF16(sync_data
.title());
59 uint32 transition
= 0;
60 if (sync_data
.has_page_transition()) {
61 switch (sync_data
.page_transition()) {
62 case sync_pb::SyncEnums_PageTransition_LINK
:
63 transition
= ui::PAGE_TRANSITION_LINK
;
65 case sync_pb::SyncEnums_PageTransition_TYPED
:
66 transition
= ui::PAGE_TRANSITION_TYPED
;
68 case sync_pb::SyncEnums_PageTransition_AUTO_BOOKMARK
:
69 transition
= ui::PAGE_TRANSITION_AUTO_BOOKMARK
;
71 case sync_pb::SyncEnums_PageTransition_AUTO_SUBFRAME
:
72 transition
= ui::PAGE_TRANSITION_AUTO_SUBFRAME
;
74 case sync_pb::SyncEnums_PageTransition_MANUAL_SUBFRAME
:
75 transition
= ui::PAGE_TRANSITION_MANUAL_SUBFRAME
;
77 case sync_pb::SyncEnums_PageTransition_GENERATED
:
78 transition
= ui::PAGE_TRANSITION_GENERATED
;
80 case sync_pb::SyncEnums_PageTransition_AUTO_TOPLEVEL
:
81 transition
= ui::PAGE_TRANSITION_AUTO_TOPLEVEL
;
83 case sync_pb::SyncEnums_PageTransition_FORM_SUBMIT
:
84 transition
= ui::PAGE_TRANSITION_FORM_SUBMIT
;
86 case sync_pb::SyncEnums_PageTransition_RELOAD
:
87 transition
= ui::PAGE_TRANSITION_RELOAD
;
89 case sync_pb::SyncEnums_PageTransition_KEYWORD
:
90 transition
= ui::PAGE_TRANSITION_KEYWORD
;
92 case sync_pb::SyncEnums_PageTransition_KEYWORD_GENERATED
:
93 transition
= ui::PAGE_TRANSITION_KEYWORD_GENERATED
;
96 transition
= ui::PAGE_TRANSITION_LINK
;
101 if (sync_data
.has_redirect_type()) {
102 switch (sync_data
.redirect_type()) {
103 case sync_pb::SyncEnums_PageTransitionRedirectType_CLIENT_REDIRECT
:
104 transition
|= ui::PAGE_TRANSITION_CLIENT_REDIRECT
;
106 case sync_pb::SyncEnums_PageTransitionRedirectType_SERVER_REDIRECT
:
107 transition
|= ui::PAGE_TRANSITION_SERVER_REDIRECT
;
111 if (sync_data
.navigation_forward_back())
112 transition
|= ui::PAGE_TRANSITION_FORWARD_BACK
;
113 if (sync_data
.navigation_from_address_bar())
114 transition
|= ui::PAGE_TRANSITION_FROM_ADDRESS_BAR
;
115 if (sync_data
.navigation_home_page())
116 transition
|= ui::PAGE_TRANSITION_HOME_PAGE
;
117 if (sync_data
.navigation_chain_start())
118 transition
|= ui::PAGE_TRANSITION_CHAIN_START
;
119 if (sync_data
.navigation_chain_end())
120 transition
|= ui::PAGE_TRANSITION_CHAIN_END
;
122 navigation
.transition_type_
= static_cast<ui::PageTransition
>(transition
);
124 navigation
.timestamp_
= base::Time();
125 navigation
.search_terms_
= base::UTF8ToUTF16(sync_data
.search_terms());
126 if (sync_data
.has_favicon_url())
127 navigation
.favicon_url_
= GURL(sync_data
.favicon_url());
129 navigation
.http_status_code_
= sync_data
.http_status_code();
131 SerializedNavigationDriver::Get()->Sanitize(&navigation
);
133 navigation
.is_restored_
= true;
140 // Helper used by SerializedNavigationEntry::WriteToPickle(). It writes |str| to
141 // |pickle|, if and only if |str| fits within (|max_bytes| -
142 // |*bytes_written|). |bytes_written| is incremented to reflect the
145 // TODO(akalin): Unify this with the same function in
146 // base_session_service.cc.
147 void WriteStringToPickle(Pickle
* pickle
,
150 const std::string
& str
) {
151 int num_bytes
= str
.size() * sizeof(char);
152 if (*bytes_written
+ num_bytes
< max_bytes
) {
153 *bytes_written
+= num_bytes
;
154 pickle
->WriteString(str
);
156 pickle
->WriteString(std::string());
160 // base::string16 version of WriteStringToPickle.
162 // TODO(akalin): Unify this, too.
163 void WriteString16ToPickle(Pickle
* pickle
,
166 const base::string16
& str
) {
167 int num_bytes
= str
.size() * sizeof(base::char16
);
168 if (*bytes_written
+ num_bytes
< max_bytes
) {
169 *bytes_written
+= num_bytes
;
170 pickle
->WriteString16(str
);
172 pickle
->WriteString16(base::string16());
176 // A mask used for arbitrary boolean values needed to represent a
177 // NavigationEntry. Currently only contains HAS_POST_DATA.
179 // NOTE(akalin): We may want to just serialize |has_post_data_|
180 // directly. Other bools (|is_overriding_user_agent_|) haven't been
181 // added to this mask.
193 // encoded_page_state_
198 // type_mask (has_post_data_)
200 // referrer_policy_ (broken, crbug.com/450589)
201 // original_request_url_
202 // is_overriding_user_agent_
208 void SerializedNavigationEntry::WriteToPickle(int max_size
,
209 Pickle
* pickle
) const {
210 pickle
->WriteInt(index_
);
212 int bytes_written
= 0;
214 WriteStringToPickle(pickle
, &bytes_written
, max_size
,
215 virtual_url_
.spec());
217 WriteString16ToPickle(pickle
, &bytes_written
, max_size
, title_
);
219 const std::string encoded_page_state
=
220 SerializedNavigationDriver::Get()->GetSanitizedPageStateForPickle(this);
221 WriteStringToPickle(pickle
, &bytes_written
, max_size
, encoded_page_state
);
223 pickle
->WriteInt(transition_type_
);
225 const int type_mask
= has_post_data_
? HAS_POST_DATA
: 0;
226 pickle
->WriteInt(type_mask
);
228 int mapped_referrer_policy
;
229 if (SerializedNavigationDriver::Get()->MapReferrerPolicyToOldValues(
230 referrer_policy_
, &mapped_referrer_policy
) &&
231 referrer_url_
.is_valid()) {
232 WriteStringToPickle(pickle
, &bytes_written
, max_size
, referrer_url_
.spec());
234 WriteStringToPickle(pickle
, &bytes_written
, max_size
, std::string());
236 pickle
->WriteInt(mapped_referrer_policy
);
238 // Save info required to override the user agent.
240 pickle
, &bytes_written
, max_size
,
241 original_request_url_
.is_valid() ?
242 original_request_url_
.spec() : std::string());
243 pickle
->WriteBool(is_overriding_user_agent_
);
244 pickle
->WriteInt64(timestamp_
.ToInternalValue());
246 WriteString16ToPickle(pickle
, &bytes_written
, max_size
, search_terms_
);
248 pickle
->WriteInt(http_status_code_
);
250 pickle
->WriteInt(referrer_policy_
);
253 bool SerializedNavigationEntry::ReadFromPickle(PickleIterator
* iterator
) {
254 *this = SerializedNavigationEntry();
255 std::string virtual_url_spec
;
256 int transition_type_int
= 0;
257 if (!iterator
->ReadInt(&index_
) ||
258 !iterator
->ReadString(&virtual_url_spec
) ||
259 !iterator
->ReadString16(&title_
) ||
260 !iterator
->ReadString(&encoded_page_state_
) ||
261 !iterator
->ReadInt(&transition_type_int
))
263 virtual_url_
= GURL(virtual_url_spec
);
264 transition_type_
= ui::PageTransitionFromInt(transition_type_int
);
266 // type_mask did not always exist in the written stream. As such, we
267 // don't fail if it can't be read.
269 bool has_type_mask
= iterator
->ReadInt(&type_mask
);
272 has_post_data_
= type_mask
& HAS_POST_DATA
;
273 // the "referrer" property was added after type_mask to the written
274 // stream. As such, we don't fail if it can't be read.
275 std::string referrer_spec
;
276 if (!iterator
->ReadString(&referrer_spec
))
277 referrer_spec
= std::string();
278 referrer_url_
= GURL(referrer_spec
);
280 // The "referrer policy" property was added even later, so we fall back to
281 // the default policy if the property is not present.
283 // Note: due to crbug.com/450589 this value might be incorrect, and a
284 // corrected version is stored later in the pickle.
285 if (!iterator
->ReadInt(&referrer_policy_
)) {
287 SerializedNavigationDriver::Get()->GetDefaultReferrerPolicy();
290 // If the original URL can't be found, leave it empty.
291 std::string original_request_url_spec
;
292 if (!iterator
->ReadString(&original_request_url_spec
))
293 original_request_url_spec
= std::string();
294 original_request_url_
= GURL(original_request_url_spec
);
296 // Default to not overriding the user agent if we don't have info.
297 if (!iterator
->ReadBool(&is_overriding_user_agent_
))
298 is_overriding_user_agent_
= false;
300 int64 timestamp_internal_value
= 0;
301 if (iterator
->ReadInt64(×tamp_internal_value
)) {
302 timestamp_
= base::Time::FromInternalValue(timestamp_internal_value
);
304 timestamp_
= base::Time();
307 // If the search terms field can't be found, leave it empty.
308 if (!iterator
->ReadString16(&search_terms_
))
309 search_terms_
.clear();
311 if (!iterator
->ReadInt(&http_status_code_
))
312 http_status_code_
= 0;
314 // Correct referrer policy (if present).
315 int correct_referrer_policy
;
316 if (iterator
->ReadInt(&correct_referrer_policy
)) {
317 referrer_policy_
= correct_referrer_policy
;
319 int mapped_referrer_policy
;
320 if (!SerializedNavigationDriver::Get()->MapReferrerPolicyToNewValues(
321 referrer_policy_
, &mapped_referrer_policy
)) {
322 referrer_url_
= GURL();
324 referrer_policy_
= mapped_referrer_policy
;
325 encoded_page_state_
=
326 SerializedNavigationDriver::Get()->StripReferrerFromPageState(
327 encoded_page_state_
);
331 SerializedNavigationDriver::Get()->Sanitize(this);
338 // TODO(zea): perhaps sync state (scroll position, form entries, etc.) as well?
339 // See http://crbug.com/67068.
340 sync_pb::TabNavigation
SerializedNavigationEntry::ToSyncData() const {
341 sync_pb::TabNavigation sync_data
;
342 sync_data
.set_virtual_url(virtual_url_
.spec());
343 int mapped_referrer_policy
;
344 if (SerializedNavigationDriver::Get()->MapReferrerPolicyToOldValues(
345 referrer_policy_
, &mapped_referrer_policy
)) {
346 sync_data
.set_referrer(referrer_url_
.spec());
348 sync_data
.set_referrer(std::string());
350 sync_data
.set_obsolete_referrer_policy(mapped_referrer_policy
);
351 sync_data
.set_correct_referrer_policy(referrer_policy_
);
352 sync_data
.set_title(base::UTF16ToUTF8(title_
));
354 // Page transition core.
355 static_assert(ui::PAGE_TRANSITION_LAST_CORE
==
356 ui::PAGE_TRANSITION_KEYWORD_GENERATED
,
357 "PAGE_TRANSITION_LAST_CORE must equal "
358 "PAGE_TRANSITION_KEYWORD_GENERATED");
359 switch (ui::PageTransitionStripQualifier(transition_type_
)) {
360 case ui::PAGE_TRANSITION_LINK
:
361 sync_data
.set_page_transition(
362 sync_pb::SyncEnums_PageTransition_LINK
);
364 case ui::PAGE_TRANSITION_TYPED
:
365 sync_data
.set_page_transition(
366 sync_pb::SyncEnums_PageTransition_TYPED
);
368 case ui::PAGE_TRANSITION_AUTO_BOOKMARK
:
369 sync_data
.set_page_transition(
370 sync_pb::SyncEnums_PageTransition_AUTO_BOOKMARK
);
372 case ui::PAGE_TRANSITION_AUTO_SUBFRAME
:
373 sync_data
.set_page_transition(
374 sync_pb::SyncEnums_PageTransition_AUTO_SUBFRAME
);
376 case ui::PAGE_TRANSITION_MANUAL_SUBFRAME
:
377 sync_data
.set_page_transition(
378 sync_pb::SyncEnums_PageTransition_MANUAL_SUBFRAME
);
380 case ui::PAGE_TRANSITION_GENERATED
:
381 sync_data
.set_page_transition(
382 sync_pb::SyncEnums_PageTransition_GENERATED
);
384 case ui::PAGE_TRANSITION_AUTO_TOPLEVEL
:
385 sync_data
.set_page_transition(
386 sync_pb::SyncEnums_PageTransition_AUTO_TOPLEVEL
);
388 case ui::PAGE_TRANSITION_FORM_SUBMIT
:
389 sync_data
.set_page_transition(
390 sync_pb::SyncEnums_PageTransition_FORM_SUBMIT
);
392 case ui::PAGE_TRANSITION_RELOAD
:
393 sync_data
.set_page_transition(
394 sync_pb::SyncEnums_PageTransition_RELOAD
);
396 case ui::PAGE_TRANSITION_KEYWORD
:
397 sync_data
.set_page_transition(
398 sync_pb::SyncEnums_PageTransition_KEYWORD
);
400 case ui::PAGE_TRANSITION_KEYWORD_GENERATED
:
401 sync_data
.set_page_transition(
402 sync_pb::SyncEnums_PageTransition_KEYWORD_GENERATED
);
408 // Page transition qualifiers.
409 if (ui::PageTransitionIsRedirect(transition_type_
)) {
410 if (transition_type_
& ui::PAGE_TRANSITION_CLIENT_REDIRECT
) {
411 sync_data
.set_redirect_type(
412 sync_pb::SyncEnums_PageTransitionRedirectType_CLIENT_REDIRECT
);
413 } else if (transition_type_
& ui::PAGE_TRANSITION_SERVER_REDIRECT
) {
414 sync_data
.set_redirect_type(
415 sync_pb::SyncEnums_PageTransitionRedirectType_SERVER_REDIRECT
);
418 sync_data
.set_navigation_forward_back(
419 (transition_type_
& ui::PAGE_TRANSITION_FORWARD_BACK
) != 0);
420 sync_data
.set_navigation_from_address_bar(
421 (transition_type_
& ui::PAGE_TRANSITION_FROM_ADDRESS_BAR
) != 0);
422 sync_data
.set_navigation_home_page(
423 (transition_type_
& ui::PAGE_TRANSITION_HOME_PAGE
) != 0);
424 sync_data
.set_navigation_chain_start(
425 (transition_type_
& ui::PAGE_TRANSITION_CHAIN_START
) != 0);
426 sync_data
.set_navigation_chain_end(
427 (transition_type_
& ui::PAGE_TRANSITION_CHAIN_END
) != 0);
429 sync_data
.set_unique_id(unique_id_
);
430 sync_data
.set_timestamp_msec(syncer::TimeToProtoTime(timestamp_
));
431 // The full-resolution timestamp works as a global ID.
432 sync_data
.set_global_id(timestamp_
.ToInternalValue());
434 sync_data
.set_search_terms(base::UTF16ToUTF8(search_terms_
));
436 sync_data
.set_http_status_code(http_status_code_
);
438 if (favicon_url_
.is_valid())
439 sync_data
.set_favicon_url(favicon_url_
.spec());
441 if (blocked_state_
!= STATE_INVALID
) {
442 sync_data
.set_blocked_state(
443 static_cast<sync_pb::TabNavigation_BlockedState
>(blocked_state_
));
446 for (std::set
<std::string
>::const_iterator it
=
447 content_pack_categories_
.begin();
448 it
!= content_pack_categories_
.end(); ++it
) {
449 sync_data
.add_content_pack_categories(*it
);
452 // Copy all redirect chain entries except the last URL (which should match
454 if (redirect_chain_
.size() > 1) { // Single entry chains have no redirection.
455 size_t last_entry
= redirect_chain_
.size() - 1;
456 for (size_t i
= 0; i
< last_entry
; i
++) {
457 sync_pb::NavigationRedirect
* navigation_redirect
=
458 sync_data
.add_navigation_redirect();
459 navigation_redirect
->set_url(redirect_chain_
[i
].spec());
461 // If the last URL didn't match the virtual_url, record it separately.
462 if (sync_data
.virtual_url() != redirect_chain_
[last_entry
].spec()) {
463 sync_data
.set_last_navigation_redirect_url(
464 redirect_chain_
[last_entry
].spec());
468 sync_data
.set_is_restored(is_restored_
);
473 } // namespace sessions