cc: Added inline to Tile::IsReadyToDraw
[chromium-blink-merge.git] / components / sessions / serialized_navigation_entry.cc
blob0fc6ff184b3ab5dfc9fc154408ca609ca4fd7210
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 "content/public/browser/favicon_status.h"
10 #include "content/public/browser/navigation_controller.h"
11 #include "content/public/browser/navigation_entry.h"
12 #include "sync/protocol/session_specifics.pb.h"
13 #include "sync/util/time.h"
14 #include "third_party/WebKit/public/platform/WebReferrerPolicy.h"
16 using content::NavigationEntry;
18 namespace sessions {
20 const char kSearchTermsKey[] = "search_terms";
22 SerializedNavigationEntry::SerializedNavigationEntry()
23 : index_(-1),
24 unique_id_(0),
25 transition_type_(content::PAGE_TRANSITION_TYPED),
26 has_post_data_(false),
27 post_id_(-1),
28 is_overriding_user_agent_(false),
29 http_status_code_(0),
30 blocked_state_(STATE_INVALID) {}
32 SerializedNavigationEntry::~SerializedNavigationEntry() {}
34 // static
35 SerializedNavigationEntry SerializedNavigationEntry::FromNavigationEntry(
36 int index,
37 const NavigationEntry& entry) {
38 SerializedNavigationEntry navigation;
39 navigation.index_ = index;
40 navigation.unique_id_ = entry.GetUniqueID();
41 navigation.referrer_ = entry.GetReferrer();
42 navigation.virtual_url_ = entry.GetVirtualURL();
43 navigation.title_ = entry.GetTitle();
44 navigation.page_state_ = entry.GetPageState();
45 navigation.transition_type_ = entry.GetTransitionType();
46 navigation.has_post_data_ = entry.GetHasPostData();
47 navigation.post_id_ = entry.GetPostID();
48 navigation.original_request_url_ = entry.GetOriginalRequestURL();
49 navigation.is_overriding_user_agent_ = entry.GetIsOverridingUserAgent();
50 navigation.timestamp_ = entry.GetTimestamp();
51 // If you want to navigate a named frame in Chrome, you will first need to
52 // add support for persisting it. It is currently only used for layout tests.
53 CHECK(entry.GetFrameToNavigate().empty());
54 entry.GetExtraData(kSearchTermsKey, &navigation.search_terms_);
55 if (entry.GetFavicon().valid)
56 navigation.favicon_url_ = entry.GetFavicon().url;
57 navigation.http_status_code_ = entry.GetHttpStatusCode();
59 return navigation;
62 SerializedNavigationEntry SerializedNavigationEntry::FromSyncData(
63 int index,
64 const sync_pb::TabNavigation& sync_data) {
65 SerializedNavigationEntry navigation;
66 navigation.index_ = index;
67 navigation.unique_id_ = sync_data.unique_id();
68 navigation.referrer_ =
69 content::Referrer(GURL(sync_data.referrer()),
70 WebKit::WebReferrerPolicyDefault);
71 navigation.virtual_url_ = GURL(sync_data.virtual_url());
72 navigation.title_ = UTF8ToUTF16(sync_data.title());
73 navigation.page_state_ =
74 content::PageState::CreateFromEncodedData(sync_data.state());
76 uint32 transition = 0;
77 if (sync_data.has_page_transition()) {
78 switch (sync_data.page_transition()) {
79 case sync_pb::SyncEnums_PageTransition_LINK:
80 transition = content::PAGE_TRANSITION_LINK;
81 break;
82 case sync_pb::SyncEnums_PageTransition_TYPED:
83 transition = content::PAGE_TRANSITION_TYPED;
84 break;
85 case sync_pb::SyncEnums_PageTransition_AUTO_BOOKMARK:
86 transition = content::PAGE_TRANSITION_AUTO_BOOKMARK;
87 break;
88 case sync_pb::SyncEnums_PageTransition_AUTO_SUBFRAME:
89 transition = content::PAGE_TRANSITION_AUTO_SUBFRAME;
90 break;
91 case sync_pb::SyncEnums_PageTransition_MANUAL_SUBFRAME:
92 transition = content::PAGE_TRANSITION_MANUAL_SUBFRAME;
93 break;
94 case sync_pb::SyncEnums_PageTransition_GENERATED:
95 transition = content::PAGE_TRANSITION_GENERATED;
96 break;
97 case sync_pb::SyncEnums_PageTransition_AUTO_TOPLEVEL:
98 transition = content::PAGE_TRANSITION_AUTO_TOPLEVEL;
99 break;
100 case sync_pb::SyncEnums_PageTransition_FORM_SUBMIT:
101 transition = content::PAGE_TRANSITION_FORM_SUBMIT;
102 break;
103 case sync_pb::SyncEnums_PageTransition_RELOAD:
104 transition = content::PAGE_TRANSITION_RELOAD;
105 break;
106 case sync_pb::SyncEnums_PageTransition_KEYWORD:
107 transition = content::PAGE_TRANSITION_KEYWORD;
108 break;
109 case sync_pb::SyncEnums_PageTransition_KEYWORD_GENERATED:
110 transition =
111 content::PAGE_TRANSITION_KEYWORD_GENERATED;
112 break;
113 default:
114 transition = content::PAGE_TRANSITION_LINK;
115 break;
119 if (sync_data.has_redirect_type()) {
120 switch (sync_data.redirect_type()) {
121 case sync_pb::SyncEnums_PageTransitionRedirectType_CLIENT_REDIRECT:
122 transition |= content::PAGE_TRANSITION_CLIENT_REDIRECT;
123 break;
124 case sync_pb::SyncEnums_PageTransitionRedirectType_SERVER_REDIRECT:
125 transition |= content::PAGE_TRANSITION_SERVER_REDIRECT;
126 break;
129 if (sync_data.navigation_forward_back())
130 transition |= content::PAGE_TRANSITION_FORWARD_BACK;
131 if (sync_data.navigation_from_address_bar())
132 transition |= content::PAGE_TRANSITION_FROM_ADDRESS_BAR;
133 if (sync_data.navigation_home_page())
134 transition |= content::PAGE_TRANSITION_HOME_PAGE;
135 if (sync_data.navigation_chain_start())
136 transition |= content::PAGE_TRANSITION_CHAIN_START;
137 if (sync_data.navigation_chain_end())
138 transition |= content::PAGE_TRANSITION_CHAIN_END;
140 navigation.transition_type_ =
141 static_cast<content::PageTransition>(transition);
143 navigation.timestamp_ = base::Time();
144 navigation.search_terms_ = UTF8ToUTF16(sync_data.search_terms());
145 if (sync_data.has_favicon_url())
146 navigation.favicon_url_ = GURL(sync_data.favicon_url());
148 navigation.http_status_code_ = sync_data.http_status_code();
150 // We shouldn't sync session data for managed users down at the moment.
151 DCHECK(!sync_data.has_blocked_state());
152 DCHECK_EQ(0, sync_data.content_pack_categories_size());
154 return navigation;
157 namespace {
159 // Helper used by SerializedNavigationEntry::WriteToPickle(). It writes |str| to
160 // |pickle|, if and only if |str| fits within (|max_bytes| -
161 // |*bytes_written|). |bytes_written| is incremented to reflect the
162 // data written.
164 // TODO(akalin): Unify this with the same function in
165 // base_session_service.cc.
166 void WriteStringToPickle(Pickle* pickle,
167 int* bytes_written,
168 int max_bytes,
169 const std::string& str) {
170 int num_bytes = str.size() * sizeof(char);
171 if (*bytes_written + num_bytes < max_bytes) {
172 *bytes_written += num_bytes;
173 pickle->WriteString(str);
174 } else {
175 pickle->WriteString(std::string());
179 // string16 version of WriteStringToPickle.
181 // TODO(akalin): Unify this, too.
182 void WriteString16ToPickle(Pickle* pickle,
183 int* bytes_written,
184 int max_bytes,
185 const string16& str) {
186 int num_bytes = str.size() * sizeof(char16);
187 if (*bytes_written + num_bytes < max_bytes) {
188 *bytes_written += num_bytes;
189 pickle->WriteString16(str);
190 } else {
191 pickle->WriteString16(string16());
195 // A mask used for arbitrary boolean values needed to represent a
196 // NavigationEntry. Currently only contains HAS_POST_DATA.
198 // NOTE(akalin): We may want to just serialize |has_post_data_|
199 // directly. Other bools (|is_overriding_user_agent_|) haven't been
200 // added to this mask.
201 enum TypeMask {
202 HAS_POST_DATA = 1
205 } // namespace
207 // Pickle order:
209 // index_
210 // virtual_url_
211 // title_
212 // page_state_
213 // transition_type_
215 // Added on later:
217 // type_mask (has_post_data_)
218 // referrer_
219 // original_request_url_
220 // is_overriding_user_agent_
221 // timestamp_
222 // search_terms_
223 // http_status_code_
225 void SerializedNavigationEntry::WriteToPickle(int max_size,
226 Pickle* pickle) const {
227 pickle->WriteInt(index_);
229 int bytes_written = 0;
231 WriteStringToPickle(pickle, &bytes_written, max_size,
232 virtual_url_.spec());
234 WriteString16ToPickle(pickle, &bytes_written, max_size, title_);
236 content::PageState page_state = page_state_;
237 if (has_post_data_)
238 page_state = page_state.RemovePasswordData();
240 WriteStringToPickle(pickle, &bytes_written, max_size,
241 page_state.ToEncodedData());
243 pickle->WriteInt(transition_type_);
245 const int type_mask = has_post_data_ ? HAS_POST_DATA : 0;
246 pickle->WriteInt(type_mask);
248 WriteStringToPickle(
249 pickle, &bytes_written, max_size,
250 referrer_.url.is_valid() ? referrer_.url.spec() : std::string());
252 pickle->WriteInt(referrer_.policy);
254 // Save info required to override the user agent.
255 WriteStringToPickle(
256 pickle, &bytes_written, max_size,
257 original_request_url_.is_valid() ?
258 original_request_url_.spec() : std::string());
259 pickle->WriteBool(is_overriding_user_agent_);
260 pickle->WriteInt64(timestamp_.ToInternalValue());
262 WriteString16ToPickle(pickle, &bytes_written, max_size, search_terms_);
264 pickle->WriteInt(http_status_code_);
267 bool SerializedNavigationEntry::ReadFromPickle(PickleIterator* iterator) {
268 *this = SerializedNavigationEntry();
269 std::string virtual_url_spec, page_state_data;
270 int transition_type_int = 0;
271 if (!iterator->ReadInt(&index_) ||
272 !iterator->ReadString(&virtual_url_spec) ||
273 !iterator->ReadString16(&title_) ||
274 !iterator->ReadString(&page_state_data) ||
275 !iterator->ReadInt(&transition_type_int))
276 return false;
277 virtual_url_ = GURL(virtual_url_spec);
278 page_state_ = content::PageState::CreateFromEncodedData(page_state_data);
279 transition_type_ = static_cast<content::PageTransition>(transition_type_int);
281 // type_mask did not always exist in the written stream. As such, we
282 // don't fail if it can't be read.
283 int type_mask = 0;
284 bool has_type_mask = iterator->ReadInt(&type_mask);
286 if (has_type_mask) {
287 has_post_data_ = type_mask & HAS_POST_DATA;
288 // the "referrer" property was added after type_mask to the written
289 // stream. As such, we don't fail if it can't be read.
290 std::string referrer_spec;
291 if (!iterator->ReadString(&referrer_spec))
292 referrer_spec = std::string();
293 // The "referrer policy" property was added even later, so we fall back to
294 // the default policy if the property is not present.
295 int policy_int;
296 WebKit::WebReferrerPolicy policy;
297 if (iterator->ReadInt(&policy_int))
298 policy = static_cast<WebKit::WebReferrerPolicy>(policy_int);
299 else
300 policy = WebKit::WebReferrerPolicyDefault;
301 referrer_ = content::Referrer(GURL(referrer_spec), policy);
303 // If the original URL can't be found, leave it empty.
304 std::string original_request_url_spec;
305 if (!iterator->ReadString(&original_request_url_spec))
306 original_request_url_spec = std::string();
307 original_request_url_ = GURL(original_request_url_spec);
309 // Default to not overriding the user agent if we don't have info.
310 if (!iterator->ReadBool(&is_overriding_user_agent_))
311 is_overriding_user_agent_ = false;
313 int64 timestamp_internal_value = 0;
314 if (iterator->ReadInt64(&timestamp_internal_value)) {
315 timestamp_ = base::Time::FromInternalValue(timestamp_internal_value);
316 } else {
317 timestamp_ = base::Time();
320 // If the search terms field can't be found, leave it empty.
321 if (!iterator->ReadString16(&search_terms_))
322 search_terms_.clear();
324 if (!iterator->ReadInt(&http_status_code_))
325 http_status_code_ = 0;
328 return true;
331 scoped_ptr<NavigationEntry> SerializedNavigationEntry::ToNavigationEntry(
332 int page_id,
333 content::BrowserContext* browser_context) const {
334 scoped_ptr<NavigationEntry> entry(
335 content::NavigationController::CreateNavigationEntry(
336 virtual_url_,
337 referrer_,
338 // Use a transition type of reload so that we don't incorrectly
339 // increase the typed count.
340 content::PAGE_TRANSITION_RELOAD,
341 false,
342 // The extra headers are not sync'ed across sessions.
343 std::string(),
344 browser_context));
346 entry->SetTitle(title_);
347 entry->SetPageState(page_state_);
348 entry->SetPageID(page_id);
349 entry->SetHasPostData(has_post_data_);
350 entry->SetPostID(post_id_);
351 entry->SetOriginalRequestURL(original_request_url_);
352 entry->SetIsOverridingUserAgent(is_overriding_user_agent_);
353 entry->SetTimestamp(timestamp_);
354 entry->SetExtraData(kSearchTermsKey, search_terms_);
355 entry->SetHttpStatusCode(http_status_code_);
357 // These fields should have default values.
358 DCHECK_EQ(STATE_INVALID, blocked_state_);
359 DCHECK_EQ(0u, content_pack_categories_.size());
361 return entry.Pass();
364 // TODO(zea): perhaps sync state (scroll position, form entries, etc.) as well?
365 // See http://crbug.com/67068.
366 sync_pb::TabNavigation SerializedNavigationEntry::ToSyncData() const {
367 sync_pb::TabNavigation sync_data;
368 sync_data.set_virtual_url(virtual_url_.spec());
369 // FIXME(zea): Support referrer policy?
370 sync_data.set_referrer(referrer_.url.spec());
371 sync_data.set_title(UTF16ToUTF8(title_));
373 // Page transition core.
374 COMPILE_ASSERT(content::PAGE_TRANSITION_LAST_CORE ==
375 content::PAGE_TRANSITION_KEYWORD_GENERATED,
376 PageTransitionCoreBounds);
377 switch (PageTransitionStripQualifier(transition_type_)) {
378 case content::PAGE_TRANSITION_LINK:
379 sync_data.set_page_transition(
380 sync_pb::SyncEnums_PageTransition_LINK);
381 break;
382 case content::PAGE_TRANSITION_TYPED:
383 sync_data.set_page_transition(
384 sync_pb::SyncEnums_PageTransition_TYPED);
385 break;
386 case content::PAGE_TRANSITION_AUTO_BOOKMARK:
387 sync_data.set_page_transition(
388 sync_pb::SyncEnums_PageTransition_AUTO_BOOKMARK);
389 break;
390 case content::PAGE_TRANSITION_AUTO_SUBFRAME:
391 sync_data.set_page_transition(
392 sync_pb::SyncEnums_PageTransition_AUTO_SUBFRAME);
393 break;
394 case content::PAGE_TRANSITION_MANUAL_SUBFRAME:
395 sync_data.set_page_transition(
396 sync_pb::SyncEnums_PageTransition_MANUAL_SUBFRAME);
397 break;
398 case content::PAGE_TRANSITION_GENERATED:
399 sync_data.set_page_transition(
400 sync_pb::SyncEnums_PageTransition_GENERATED);
401 break;
402 case content::PAGE_TRANSITION_AUTO_TOPLEVEL:
403 sync_data.set_page_transition(
404 sync_pb::SyncEnums_PageTransition_AUTO_TOPLEVEL);
405 break;
406 case content::PAGE_TRANSITION_FORM_SUBMIT:
407 sync_data.set_page_transition(
408 sync_pb::SyncEnums_PageTransition_FORM_SUBMIT);
409 break;
410 case content::PAGE_TRANSITION_RELOAD:
411 sync_data.set_page_transition(
412 sync_pb::SyncEnums_PageTransition_RELOAD);
413 break;
414 case content::PAGE_TRANSITION_KEYWORD:
415 sync_data.set_page_transition(
416 sync_pb::SyncEnums_PageTransition_KEYWORD);
417 break;
418 case content::PAGE_TRANSITION_KEYWORD_GENERATED:
419 sync_data.set_page_transition(
420 sync_pb::SyncEnums_PageTransition_KEYWORD_GENERATED);
421 break;
422 default:
423 NOTREACHED();
426 // Page transition qualifiers.
427 if (PageTransitionIsRedirect(transition_type_)) {
428 if (transition_type_ & content::PAGE_TRANSITION_CLIENT_REDIRECT) {
429 sync_data.set_redirect_type(
430 sync_pb::SyncEnums_PageTransitionRedirectType_CLIENT_REDIRECT);
431 } else if (transition_type_ & content::PAGE_TRANSITION_SERVER_REDIRECT) {
432 sync_data.set_redirect_type(
433 sync_pb::SyncEnums_PageTransitionRedirectType_SERVER_REDIRECT);
436 sync_data.set_navigation_forward_back(
437 (transition_type_ & content::PAGE_TRANSITION_FORWARD_BACK) != 0);
438 sync_data.set_navigation_from_address_bar(
439 (transition_type_ & content::PAGE_TRANSITION_FROM_ADDRESS_BAR) != 0);
440 sync_data.set_navigation_home_page(
441 (transition_type_ & content::PAGE_TRANSITION_HOME_PAGE) != 0);
442 sync_data.set_navigation_chain_start(
443 (transition_type_ & content::PAGE_TRANSITION_CHAIN_START) != 0);
444 sync_data.set_navigation_chain_end(
445 (transition_type_ & content::PAGE_TRANSITION_CHAIN_END) != 0);
447 sync_data.set_unique_id(unique_id_);
448 sync_data.set_timestamp_msec(syncer::TimeToProtoTime(timestamp_));
449 // The full-resolution timestamp works as a global ID.
450 sync_data.set_global_id(timestamp_.ToInternalValue());
452 sync_data.set_search_terms(UTF16ToUTF8(search_terms_));
454 sync_data.set_http_status_code(http_status_code_);
456 if (favicon_url_.is_valid())
457 sync_data.set_favicon_url(favicon_url_.spec());
459 if (blocked_state_ != STATE_INVALID) {
460 sync_data.set_blocked_state(
461 static_cast<sync_pb::TabNavigation_BlockedState>(blocked_state_));
464 for (std::set<std::string>::const_iterator it =
465 content_pack_categories_.begin();
466 it != content_pack_categories_.end(); ++it) {
467 sync_data.add_content_pack_categories(*it);
470 return sync_data;
473 // static
474 std::vector<NavigationEntry*> SerializedNavigationEntry::ToNavigationEntries(
475 const std::vector<SerializedNavigationEntry>& navigations,
476 content::BrowserContext* browser_context) {
477 int page_id = 0;
478 std::vector<NavigationEntry*> entries;
479 for (std::vector<SerializedNavigationEntry>::const_iterator
480 it = navigations.begin(); it != navigations.end(); ++it) {
481 entries.push_back(
482 it->ToNavigationEntry(page_id, browser_context).release());
483 ++page_id;
485 return entries;
488 } // namespace sessions