Make the offline login page switch back to the online one after going online.
[chromium-blink-merge.git] / components / sessions / serialized_navigation_entry.cc
blobe630c19959b349acd08287d9fbbc81fddc6d0994
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"
13 namespace sessions {
15 const char kSearchTermsKey[] = "search_terms";
17 SerializedNavigationEntry::SerializedNavigationEntry()
18 : index_(-1),
19 unique_id_(0),
20 transition_type_(ui::PAGE_TRANSITION_TYPED),
21 has_post_data_(false),
22 post_id_(-1),
23 is_overriding_user_agent_(false),
24 http_status_code_(0),
25 is_restored_(false),
26 blocked_state_(STATE_INVALID) {
27 referrer_policy_ =
28 SerializedNavigationDriver::Get()->GetDefaultReferrerPolicy();
31 SerializedNavigationEntry::~SerializedNavigationEntry() {}
33 SerializedNavigationEntry SerializedNavigationEntry::FromSyncData(
34 int index,
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();
43 } else {
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());
48 } else {
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;
64 break;
65 case sync_pb::SyncEnums_PageTransition_TYPED:
66 transition = ui::PAGE_TRANSITION_TYPED;
67 break;
68 case sync_pb::SyncEnums_PageTransition_AUTO_BOOKMARK:
69 transition = ui::PAGE_TRANSITION_AUTO_BOOKMARK;
70 break;
71 case sync_pb::SyncEnums_PageTransition_AUTO_SUBFRAME:
72 transition = ui::PAGE_TRANSITION_AUTO_SUBFRAME;
73 break;
74 case sync_pb::SyncEnums_PageTransition_MANUAL_SUBFRAME:
75 transition = ui::PAGE_TRANSITION_MANUAL_SUBFRAME;
76 break;
77 case sync_pb::SyncEnums_PageTransition_GENERATED:
78 transition = ui::PAGE_TRANSITION_GENERATED;
79 break;
80 case sync_pb::SyncEnums_PageTransition_AUTO_TOPLEVEL:
81 transition = ui::PAGE_TRANSITION_AUTO_TOPLEVEL;
82 break;
83 case sync_pb::SyncEnums_PageTransition_FORM_SUBMIT:
84 transition = ui::PAGE_TRANSITION_FORM_SUBMIT;
85 break;
86 case sync_pb::SyncEnums_PageTransition_RELOAD:
87 transition = ui::PAGE_TRANSITION_RELOAD;
88 break;
89 case sync_pb::SyncEnums_PageTransition_KEYWORD:
90 transition = ui::PAGE_TRANSITION_KEYWORD;
91 break;
92 case sync_pb::SyncEnums_PageTransition_KEYWORD_GENERATED:
93 transition = ui::PAGE_TRANSITION_KEYWORD_GENERATED;
94 break;
95 default:
96 transition = ui::PAGE_TRANSITION_LINK;
97 break;
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;
105 break;
106 case sync_pb::SyncEnums_PageTransitionRedirectType_SERVER_REDIRECT:
107 transition |= ui::PAGE_TRANSITION_SERVER_REDIRECT;
108 break;
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;
135 return navigation;
138 namespace {
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
143 // data written.
145 // TODO(akalin): Unify this with the same function in
146 // base_session_service.cc.
147 void WriteStringToPickle(base::Pickle* pickle,
148 int* bytes_written,
149 int max_bytes,
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);
155 } else {
156 pickle->WriteString(std::string());
160 // base::string16 version of WriteStringToPickle.
162 // TODO(akalin): Unify this, too.
163 void WriteString16ToPickle(base::Pickle* pickle,
164 int* bytes_written,
165 int max_bytes,
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);
171 } else {
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.
182 enum TypeMask {
183 HAS_POST_DATA = 1
186 } // namespace
188 // Pickle order:
190 // index_
191 // virtual_url_
192 // title_
193 // encoded_page_state_
194 // transition_type_
196 // Added on later:
198 // type_mask (has_post_data_)
199 // referrer_url_
200 // referrer_policy_ (broken, crbug.com/450589)
201 // original_request_url_
202 // is_overriding_user_agent_
203 // timestamp_
204 // search_terms_
205 // http_status_code_
206 // referrer_policy_
208 void SerializedNavigationEntry::WriteToPickle(int max_size,
209 base::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());
233 } else {
234 WriteStringToPickle(pickle, &bytes_written, max_size, std::string());
236 pickle->WriteInt(mapped_referrer_policy);
238 // Save info required to override the user agent.
239 WriteStringToPickle(
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(base::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))
262 return false;
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.
268 int type_mask = 0;
269 bool has_type_mask = iterator->ReadInt(&type_mask);
271 if (has_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_)) {
286 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(&timestamp_internal_value)) {
302 timestamp_ = base::Time::FromInternalValue(timestamp_internal_value);
303 } else {
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;
318 } else {
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);
333 is_restored_ = true;
335 return true;
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());
347 } else {
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);
363 break;
364 case ui::PAGE_TRANSITION_TYPED:
365 sync_data.set_page_transition(
366 sync_pb::SyncEnums_PageTransition_TYPED);
367 break;
368 case ui::PAGE_TRANSITION_AUTO_BOOKMARK:
369 sync_data.set_page_transition(
370 sync_pb::SyncEnums_PageTransition_AUTO_BOOKMARK);
371 break;
372 case ui::PAGE_TRANSITION_AUTO_SUBFRAME:
373 sync_data.set_page_transition(
374 sync_pb::SyncEnums_PageTransition_AUTO_SUBFRAME);
375 break;
376 case ui::PAGE_TRANSITION_MANUAL_SUBFRAME:
377 sync_data.set_page_transition(
378 sync_pb::SyncEnums_PageTransition_MANUAL_SUBFRAME);
379 break;
380 case ui::PAGE_TRANSITION_GENERATED:
381 sync_data.set_page_transition(
382 sync_pb::SyncEnums_PageTransition_GENERATED);
383 break;
384 case ui::PAGE_TRANSITION_AUTO_TOPLEVEL:
385 sync_data.set_page_transition(
386 sync_pb::SyncEnums_PageTransition_AUTO_TOPLEVEL);
387 break;
388 case ui::PAGE_TRANSITION_FORM_SUBMIT:
389 sync_data.set_page_transition(
390 sync_pb::SyncEnums_PageTransition_FORM_SUBMIT);
391 break;
392 case ui::PAGE_TRANSITION_RELOAD:
393 sync_data.set_page_transition(
394 sync_pb::SyncEnums_PageTransition_RELOAD);
395 break;
396 case ui::PAGE_TRANSITION_KEYWORD:
397 sync_data.set_page_transition(
398 sync_pb::SyncEnums_PageTransition_KEYWORD);
399 break;
400 case ui::PAGE_TRANSITION_KEYWORD_GENERATED:
401 sync_data.set_page_transition(
402 sync_pb::SyncEnums_PageTransition_KEYWORD_GENERATED);
403 break;
404 default:
405 NOTREACHED();
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
453 // the virtual_url).
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_);
470 return sync_data;
473 } // namespace sessions