OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "components/sessions/serialized_navigation_entry.h" | |
6 | |
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" | |
12 | |
13 namespace sessions { | |
14 | |
15 const char kSearchTermsKey[] = "search_terms"; | |
16 | |
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(); | |
29 } | |
30 | |
31 SerializedNavigationEntry::~SerializedNavigationEntry() {} | |
32 | |
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(); | |
50 } | |
51 navigation.referrer_policy_ = mapped_referrer_policy; | |
52 navigation.encoded_page_state_ = | |
53 SerializedNavigationDriver::Get()->StripReferrerFromPageState( | |
54 navigation.encoded_page_state_); | |
55 } | |
56 navigation.virtual_url_ = GURL(sync_data.virtual_url()); | |
57 navigation.title_ = base::UTF8ToUTF16(sync_data.title()); | |
58 | |
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; | |
98 } | |
99 } | |
100 | |
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; | |
109 } | |
110 } | |
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; | |
121 | |
122 navigation.transition_type_ = static_cast<ui::PageTransition>(transition); | |
123 | |
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()); | |
128 | |
129 navigation.http_status_code_ = sync_data.http_status_code(); | |
130 | |
131 SerializedNavigationDriver::Get()->Sanitize(&navigation); | |
132 | |
133 navigation.is_restored_ = true; | |
134 | |
135 return navigation; | |
136 } | |
137 | |
138 namespace { | |
139 | |
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. | |
144 // | |
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()); | |
157 } | |
158 } | |
159 | |
160 // base::string16 version of WriteStringToPickle. | |
161 // | |
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()); | |
173 } | |
174 } | |
175 | |
176 // A mask used for arbitrary boolean values needed to represent a | |
177 // NavigationEntry. Currently only contains HAS_POST_DATA. | |
178 // | |
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 | |
184 }; | |
185 | |
186 } // namespace | |
187 | |
188 // Pickle order: | |
189 // | |
190 // index_ | |
191 // virtual_url_ | |
192 // title_ | |
193 // encoded_page_state_ | |
194 // transition_type_ | |
195 // | |
196 // Added on later: | |
197 // | |
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_ | |
207 | |
208 void SerializedNavigationEntry::WriteToPickle(int max_size, | |
209 base::Pickle* pickle) const { | |
210 pickle->WriteInt(index_); | |
211 | |
212 int bytes_written = 0; | |
213 | |
214 WriteStringToPickle(pickle, &bytes_written, max_size, | |
215 virtual_url_.spec()); | |
216 | |
217 WriteString16ToPickle(pickle, &bytes_written, max_size, title_); | |
218 | |
219 const std::string encoded_page_state = | |
220 SerializedNavigationDriver::Get()->GetSanitizedPageStateForPickle(this); | |
221 WriteStringToPickle(pickle, &bytes_written, max_size, encoded_page_state); | |
222 | |
223 pickle->WriteInt(transition_type_); | |
224 | |
225 const int type_mask = has_post_data_ ? HAS_POST_DATA : 0; | |
226 pickle->WriteInt(type_mask); | |
227 | |
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()); | |
235 } | |
236 pickle->WriteInt(mapped_referrer_policy); | |
237 | |
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()); | |
245 | |
246 WriteString16ToPickle(pickle, &bytes_written, max_size, search_terms_); | |
247 | |
248 pickle->WriteInt(http_status_code_); | |
249 | |
250 pickle->WriteInt(referrer_policy_); | |
251 } | |
252 | |
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); | |
265 | |
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); | |
270 | |
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); | |
279 | |
280 // The "referrer policy" property was added even later, so we fall back to | |
281 // the default policy if the property is not present. | |
282 // | |
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(); | |
288 } | |
289 | |
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); | |
295 | |
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; | |
299 | |
300 int64 timestamp_internal_value = 0; | |
301 if (iterator->ReadInt64(×tamp_internal_value)) { | |
302 timestamp_ = base::Time::FromInternalValue(timestamp_internal_value); | |
303 } else { | |
304 timestamp_ = base::Time(); | |
305 } | |
306 | |
307 // If the search terms field can't be found, leave it empty. | |
308 if (!iterator->ReadString16(&search_terms_)) | |
309 search_terms_.clear(); | |
310 | |
311 if (!iterator->ReadInt(&http_status_code_)) | |
312 http_status_code_ = 0; | |
313 | |
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(); | |
323 } | |
324 referrer_policy_ = mapped_referrer_policy; | |
325 encoded_page_state_ = | |
326 SerializedNavigationDriver::Get()->StripReferrerFromPageState( | |
327 encoded_page_state_); | |
328 } | |
329 } | |
330 | |
331 SerializedNavigationDriver::Get()->Sanitize(this); | |
332 | |
333 is_restored_ = true; | |
334 | |
335 return true; | |
336 } | |
337 | |
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()); | |
349 } | |
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_)); | |
353 | |
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(); | |
406 } | |
407 | |
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); | |
416 } | |
417 } | |
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); | |
428 | |
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()); | |
433 | |
434 sync_data.set_search_terms(base::UTF16ToUTF8(search_terms_)); | |
435 | |
436 sync_data.set_http_status_code(http_status_code_); | |
437 | |
438 if (favicon_url_.is_valid()) | |
439 sync_data.set_favicon_url(favicon_url_.spec()); | |
440 | |
441 if (blocked_state_ != STATE_INVALID) { | |
442 sync_data.set_blocked_state( | |
443 static_cast<sync_pb::TabNavigation_BlockedState>(blocked_state_)); | |
444 } | |
445 | |
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); | |
450 } | |
451 | |
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()); | |
460 } | |
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()); | |
465 } | |
466 } | |
467 | |
468 sync_data.set_is_restored(is_restored_); | |
469 | |
470 return sync_data; | |
471 } | |
472 | |
473 } // namespace sessions | |
OLD | NEW |