1 // Copyright (c) 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"
10 #include "base/basictypes.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/pickle.h"
13 #include "base/strings/string16.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "base/time/time.h"
17 #include "content/public/browser/favicon_status.h"
18 #include "content/public/browser/navigation_entry.h"
19 #include "content/public/common/page_transition_types.h"
20 #include "content/public/common/referrer.h"
21 #include "sync/protocol/session_specifics.pb.h"
22 #include "sync/util/time.h"
23 #include "testing/gtest/include/gtest/gtest.h"
24 #include "third_party/WebKit/public/platform/WebReferrerPolicy.h"
31 const int kUniqueID
= 50;
32 const content::Referrer kReferrer
=
33 content::Referrer(GURL("http://www.referrer.com"),
34 blink::WebReferrerPolicyAlways
);
35 const GURL
kVirtualURL("http://www.virtual-url.com");
36 const base::string16 kTitle
= base::ASCIIToUTF16("title");
37 const content::PageState kPageState
=
38 content::PageState::CreateFromEncodedData("page state");
39 const content::PageTransition kTransitionType
=
40 static_cast<content::PageTransition
>(
41 content::PAGE_TRANSITION_AUTO_SUBFRAME
|
42 content::PAGE_TRANSITION_HOME_PAGE
|
43 content::PAGE_TRANSITION_CLIENT_REDIRECT
);
44 const bool kHasPostData
= true;
45 const int64 kPostID
= 100;
46 const GURL
kOriginalRequestURL("http://www.original-request.com");
47 const bool kIsOverridingUserAgent
= true;
48 const base::Time kTimestamp
= syncer::ProtoTimeToTime(100);
49 const base::string16 kSearchTerms
= base::ASCIIToUTF16("my search terms");
50 const GURL
kFaviconURL("http://virtual-url.com/favicon.ico");
51 const int kHttpStatusCode
= 404;
52 const GURL
kRedirectURL0("http://go/redirect0");
53 const GURL
kRedirectURL1("http://go/redirect1");
54 const GURL
kOtherURL("http://other.com");
56 const int kPageID
= 10;
58 // Create a NavigationEntry from the constants above.
59 scoped_ptr
<content::NavigationEntry
> MakeNavigationEntryForTest() {
60 scoped_ptr
<content::NavigationEntry
> navigation_entry(
61 content::NavigationEntry::Create());
62 navigation_entry
->SetReferrer(kReferrer
);
63 navigation_entry
->SetVirtualURL(kVirtualURL
);
64 navigation_entry
->SetTitle(kTitle
);
65 navigation_entry
->SetPageState(kPageState
);
66 navigation_entry
->SetTransitionType(kTransitionType
);
67 navigation_entry
->SetHasPostData(kHasPostData
);
68 navigation_entry
->SetPostID(kPostID
);
69 navigation_entry
->SetOriginalRequestURL(kOriginalRequestURL
);
70 navigation_entry
->SetIsOverridingUserAgent(kIsOverridingUserAgent
);
71 navigation_entry
->SetTimestamp(kTimestamp
);
72 navigation_entry
->SetExtraData(kSearchTermsKey
, kSearchTerms
);
73 navigation_entry
->GetFavicon().valid
= true;
74 navigation_entry
->GetFavicon().url
= kFaviconURL
;
75 navigation_entry
->SetHttpStatusCode(kHttpStatusCode
);
76 std::vector
<GURL
> redirect_chain
;
77 redirect_chain
.push_back(kRedirectURL0
);
78 redirect_chain
.push_back(kRedirectURL1
);
79 redirect_chain
.push_back(kVirtualURL
);
80 navigation_entry
->SetRedirectChain(redirect_chain
);
81 return navigation_entry
.Pass();
84 // Create a sync_pb::TabNavigation from the constants above.
85 sync_pb::TabNavigation
MakeSyncDataForTest() {
86 sync_pb::TabNavigation sync_data
;
87 sync_data
.set_virtual_url(kVirtualURL
.spec());
88 sync_data
.set_referrer(kReferrer
.url
.spec());
89 sync_data
.set_referrer_policy(blink::WebReferrerPolicyOrigin
);
90 sync_data
.set_title(base::UTF16ToUTF8(kTitle
));
91 sync_data
.set_state(kPageState
.ToEncodedData());
92 sync_data
.set_page_transition(
93 sync_pb::SyncEnums_PageTransition_AUTO_SUBFRAME
);
94 sync_data
.set_unique_id(kUniqueID
);
95 sync_data
.set_timestamp_msec(syncer::TimeToProtoTime(kTimestamp
));
96 sync_data
.set_redirect_type(sync_pb::SyncEnums::CLIENT_REDIRECT
);
97 sync_data
.set_navigation_home_page(true);
98 sync_data
.set_search_terms(base::UTF16ToUTF8(kSearchTerms
));
99 sync_data
.set_favicon_url(kFaviconURL
.spec());
100 sync_data
.set_http_status_code(kHttpStatusCode
);
101 // The redirect chain only syncs one way.
105 // Create a default SerializedNavigationEntry. All its fields should be
106 // initialized to their respective default values.
107 TEST(SerializedNavigationEntryTest
, DefaultInitializer
) {
108 const SerializedNavigationEntry navigation
;
109 EXPECT_EQ(-1, navigation
.index());
110 EXPECT_EQ(0, navigation
.unique_id());
111 EXPECT_EQ(GURL(), navigation
.referrer().url
);
112 EXPECT_EQ(blink::WebReferrerPolicyDefault
, navigation
.referrer().policy
);
113 EXPECT_EQ(GURL(), navigation
.virtual_url());
114 EXPECT_TRUE(navigation
.title().empty());
115 EXPECT_FALSE(navigation
.page_state().IsValid());
116 EXPECT_EQ(content::PAGE_TRANSITION_TYPED
, navigation
.transition_type());
117 EXPECT_FALSE(navigation
.has_post_data());
118 EXPECT_EQ(-1, navigation
.post_id());
119 EXPECT_EQ(GURL(), navigation
.original_request_url());
120 EXPECT_FALSE(navigation
.is_overriding_user_agent());
121 EXPECT_TRUE(navigation
.timestamp().is_null());
122 EXPECT_TRUE(navigation
.search_terms().empty());
123 EXPECT_FALSE(navigation
.favicon_url().is_valid());
124 EXPECT_EQ(0, navigation
.http_status_code());
125 EXPECT_EQ(0U, navigation
.redirect_chain().size());
128 // Create a SerializedNavigationEntry from a NavigationEntry. All its fields
129 // should match the NavigationEntry's.
130 TEST(SerializedNavigationEntryTest
, FromNavigationEntry
) {
131 const scoped_ptr
<content::NavigationEntry
> navigation_entry(
132 MakeNavigationEntryForTest());
134 const SerializedNavigationEntry
& navigation
=
135 SerializedNavigationEntry::FromNavigationEntry(kIndex
, *navigation_entry
);
137 EXPECT_EQ(kIndex
, navigation
.index());
139 EXPECT_EQ(navigation_entry
->GetUniqueID(), navigation
.unique_id());
140 EXPECT_EQ(kReferrer
.url
, navigation
.referrer().url
);
141 EXPECT_EQ(kReferrer
.policy
, navigation
.referrer().policy
);
142 EXPECT_EQ(kVirtualURL
, navigation
.virtual_url());
143 EXPECT_EQ(kTitle
, navigation
.title());
144 EXPECT_EQ(kPageState
, navigation
.page_state());
145 EXPECT_EQ(kTransitionType
, navigation
.transition_type());
146 EXPECT_EQ(kHasPostData
, navigation
.has_post_data());
147 EXPECT_EQ(kPostID
, navigation
.post_id());
148 EXPECT_EQ(kOriginalRequestURL
, navigation
.original_request_url());
149 EXPECT_EQ(kIsOverridingUserAgent
, navigation
.is_overriding_user_agent());
150 EXPECT_EQ(kTimestamp
, navigation
.timestamp());
151 EXPECT_EQ(kFaviconURL
, navigation
.favicon_url());
152 EXPECT_EQ(kHttpStatusCode
, navigation
.http_status_code());
153 ASSERT_EQ(3U, navigation
.redirect_chain().size());
154 EXPECT_EQ(kRedirectURL0
, navigation
.redirect_chain()[0]);
155 EXPECT_EQ(kRedirectURL1
, navigation
.redirect_chain()[1]);
156 EXPECT_EQ(kVirtualURL
, navigation
.redirect_chain()[2]);
159 // Create a SerializedNavigationEntry from a sync_pb::TabNavigation. All its
160 // fields should match the protocol buffer's if it exists there, and
161 // sbould be set to the default value otherwise.
162 TEST(SerializedNavigationEntryTest
, FromSyncData
) {
163 const sync_pb::TabNavigation sync_data
= MakeSyncDataForTest();
165 const SerializedNavigationEntry
& navigation
=
166 SerializedNavigationEntry::FromSyncData(kIndex
, sync_data
);
168 EXPECT_EQ(kIndex
, navigation
.index());
169 EXPECT_EQ(kUniqueID
, navigation
.unique_id());
170 EXPECT_EQ(kReferrer
.url
, navigation
.referrer().url
);
171 EXPECT_EQ(blink::WebReferrerPolicyOrigin
, navigation
.referrer().policy
);
172 EXPECT_EQ(kVirtualURL
, navigation
.virtual_url());
173 EXPECT_EQ(kTitle
, navigation
.title());
174 EXPECT_EQ(kPageState
, navigation
.page_state());
175 EXPECT_EQ(kTransitionType
, navigation
.transition_type());
176 EXPECT_FALSE(navigation
.has_post_data());
177 EXPECT_EQ(-1, navigation
.post_id());
178 EXPECT_EQ(GURL(), navigation
.original_request_url());
179 EXPECT_FALSE(navigation
.is_overriding_user_agent());
180 EXPECT_TRUE(navigation
.timestamp().is_null());
181 EXPECT_EQ(kSearchTerms
, navigation
.search_terms());
182 EXPECT_EQ(kFaviconURL
, navigation
.favicon_url());
183 EXPECT_EQ(kHttpStatusCode
, navigation
.http_status_code());
184 // The redirect chain only syncs one way.
187 // Create a SerializedNavigationEntry, pickle it, then create another one by
188 // unpickling. The new one should match the old one except for fields
189 // that aren't pickled, which should be set to default values.
190 TEST(SerializedNavigationEntryTest
, Pickle
) {
191 const SerializedNavigationEntry
& old_navigation
=
192 SerializedNavigationEntry::FromNavigationEntry(
193 kIndex
, *MakeNavigationEntryForTest());
196 old_navigation
.WriteToPickle(30000, &pickle
);
198 SerializedNavigationEntry new_navigation
;
199 PickleIterator
pickle_iterator(pickle
);
200 EXPECT_TRUE(new_navigation
.ReadFromPickle(&pickle_iterator
));
202 EXPECT_EQ(kIndex
, new_navigation
.index());
204 EXPECT_EQ(0, new_navigation
.unique_id());
205 EXPECT_EQ(kReferrer
.url
, new_navigation
.referrer().url
);
206 EXPECT_EQ(kReferrer
.policy
, new_navigation
.referrer().policy
);
207 EXPECT_EQ(kVirtualURL
, new_navigation
.virtual_url());
208 EXPECT_EQ(kTitle
, new_navigation
.title());
209 EXPECT_FALSE(new_navigation
.page_state().IsValid());
210 EXPECT_EQ(kTransitionType
, new_navigation
.transition_type());
211 EXPECT_EQ(kHasPostData
, new_navigation
.has_post_data());
212 EXPECT_EQ(-1, new_navigation
.post_id());
213 EXPECT_EQ(kOriginalRequestURL
, new_navigation
.original_request_url());
214 EXPECT_EQ(kIsOverridingUserAgent
, new_navigation
.is_overriding_user_agent());
215 EXPECT_EQ(kTimestamp
, new_navigation
.timestamp());
216 EXPECT_EQ(kSearchTerms
, new_navigation
.search_terms());
217 EXPECT_EQ(kHttpStatusCode
, new_navigation
.http_status_code());
218 EXPECT_EQ(0U, new_navigation
.redirect_chain().size());
221 // Create a NavigationEntry, then create another one by converting to
222 // a SerializedNavigationEntry and back. The new one should match the old one
223 // except for fields that aren't preserved, which should be set to
225 TEST(SerializedNavigationEntryTest
, ToNavigationEntry
) {
226 const scoped_ptr
<content::NavigationEntry
> old_navigation_entry(
227 MakeNavigationEntryForTest());
229 const SerializedNavigationEntry
& navigation
=
230 SerializedNavigationEntry::FromNavigationEntry(kIndex
,
231 *old_navigation_entry
);
233 const scoped_ptr
<content::NavigationEntry
> new_navigation_entry(
234 navigation
.ToNavigationEntry(kPageID
, NULL
));
236 EXPECT_EQ(kReferrer
.url
, new_navigation_entry
->GetReferrer().url
);
237 EXPECT_EQ(kReferrer
.policy
, new_navigation_entry
->GetReferrer().policy
);
238 EXPECT_EQ(kVirtualURL
, new_navigation_entry
->GetVirtualURL());
239 EXPECT_EQ(kTitle
, new_navigation_entry
->GetTitle());
240 EXPECT_EQ(kPageState
, new_navigation_entry
->GetPageState());
241 EXPECT_EQ(kPageID
, new_navigation_entry
->GetPageID());
242 EXPECT_EQ(content::PAGE_TRANSITION_RELOAD
,
243 new_navigation_entry
->GetTransitionType());
244 EXPECT_EQ(kHasPostData
, new_navigation_entry
->GetHasPostData());
245 EXPECT_EQ(kPostID
, new_navigation_entry
->GetPostID());
246 EXPECT_EQ(kOriginalRequestURL
,
247 new_navigation_entry
->GetOriginalRequestURL());
248 EXPECT_EQ(kIsOverridingUserAgent
,
249 new_navigation_entry
->GetIsOverridingUserAgent());
250 base::string16 search_terms
;
251 new_navigation_entry
->GetExtraData(kSearchTermsKey
, &search_terms
);
252 EXPECT_EQ(kSearchTerms
, search_terms
);
253 EXPECT_EQ(kHttpStatusCode
, new_navigation_entry
->GetHttpStatusCode());
254 ASSERT_EQ(3U, new_navigation_entry
->GetRedirectChain().size());
255 EXPECT_EQ(kRedirectURL0
, new_navigation_entry
->GetRedirectChain()[0]);
256 EXPECT_EQ(kRedirectURL1
, new_navigation_entry
->GetRedirectChain()[1]);
257 EXPECT_EQ(kVirtualURL
, new_navigation_entry
->GetRedirectChain()[2]);
260 // Create a NavigationEntry, convert it to a SerializedNavigationEntry, then
261 // create a sync protocol buffer from it. The protocol buffer should
262 // have matching fields to the NavigationEntry (when applicable).
263 TEST(SerializedNavigationEntryTest
, ToSyncData
) {
264 const scoped_ptr
<content::NavigationEntry
> navigation_entry(
265 MakeNavigationEntryForTest());
267 const SerializedNavigationEntry
& navigation
=
268 SerializedNavigationEntry::FromNavigationEntry(kIndex
, *navigation_entry
);
270 const sync_pb::TabNavigation sync_data
= navigation
.ToSyncData();
272 EXPECT_EQ(kVirtualURL
.spec(), sync_data
.virtual_url());
273 EXPECT_EQ(kReferrer
.url
.spec(), sync_data
.referrer());
274 EXPECT_EQ(kTitle
, base::ASCIIToUTF16(sync_data
.title()));
275 EXPECT_TRUE(sync_data
.state().empty());
276 EXPECT_EQ(sync_pb::SyncEnums_PageTransition_AUTO_SUBFRAME
,
277 sync_data
.page_transition());
278 EXPECT_TRUE(sync_data
.has_redirect_type());
279 EXPECT_EQ(navigation_entry
->GetUniqueID(), sync_data
.unique_id());
280 EXPECT_EQ(syncer::TimeToProtoTime(kTimestamp
), sync_data
.timestamp_msec());
281 EXPECT_EQ(kTimestamp
.ToInternalValue(), sync_data
.global_id());
282 EXPECT_EQ(kFaviconURL
.spec(), sync_data
.favicon_url());
283 EXPECT_EQ(kHttpStatusCode
, sync_data
.http_status_code());
284 // The proto navigation redirects don't include the final chain entry
285 // (because it didn't redirect) so the lengths should differ by 1.
286 ASSERT_EQ(3, sync_data
.navigation_redirect_size() + 1);
287 EXPECT_EQ(navigation_entry
->GetRedirectChain()[0].spec(),
288 sync_data
.navigation_redirect(0).url());
289 EXPECT_EQ(navigation_entry
->GetRedirectChain()[1].spec(),
290 sync_data
.navigation_redirect(1).url());
291 EXPECT_FALSE(sync_data
.has_last_navigation_redirect_url());
294 // Test that the last_navigation_redirect_url is set when needed.
295 // This test is just like the above, but with a different virtual_url.
296 // Create a NavigationEntry, convert it to a SerializedNavigationEntry, then
297 // create a sync protocol buffer from it. The protocol buffer should
298 // have a last_navigation_redirect_url.
299 TEST(SerializedNavigationEntryTest
, LastNavigationRedirectUrl
) {
300 const scoped_ptr
<content::NavigationEntry
> navigation_entry(
301 MakeNavigationEntryForTest());
303 navigation_entry
->SetVirtualURL(kOtherURL
);
305 const SerializedNavigationEntry
& navigation
=
306 SerializedNavigationEntry::FromNavigationEntry(kIndex
, *navigation_entry
);
308 const sync_pb::TabNavigation sync_data
= navigation
.ToSyncData();
310 EXPECT_TRUE(sync_data
.has_last_navigation_redirect_url());
311 EXPECT_EQ(kVirtualURL
.spec(), sync_data
.last_navigation_redirect_url());
313 // The redirect chain should be the same as in the above test.
314 ASSERT_EQ(3, sync_data
.navigation_redirect_size() + 1);
315 EXPECT_EQ(navigation_entry
->GetRedirectChain()[0].spec(),
316 sync_data
.navigation_redirect(0).url());
317 EXPECT_EQ(navigation_entry
->GetRedirectChain()[1].spec(),
318 sync_data
.navigation_redirect(1).url());
321 // Ensure all transition types and qualifiers are converted to/from the sync
322 // SerializedNavigationEntry representation properly.
323 TEST(SerializedNavigationEntryTest
, TransitionTypes
) {
324 scoped_ptr
<content::NavigationEntry
> navigation_entry(
325 MakeNavigationEntryForTest());
326 for (uint32 core_type
= content::PAGE_TRANSITION_LINK
;
327 core_type
!= content::PAGE_TRANSITION_LAST_CORE
; ++core_type
) {
328 // Because qualifier is a uint32, left shifting will eventually overflow
329 // and hit zero again. SERVER_REDIRECT, as the last qualifier and also
330 // in place of the sign bit, is therefore the last transition before
332 for (uint32 qualifier
= content::PAGE_TRANSITION_FORWARD_BACK
;
333 qualifier
!= 0; qualifier
<<= 1) {
334 if (qualifier
== 0x08000000)
335 continue; // 0x08000000 is not a valid qualifier.
336 content::PageTransition transition
=
337 static_cast<content::PageTransition
>(core_type
| qualifier
);
339 navigation_entry
->SetTransitionType(transition
);
340 const SerializedNavigationEntry
& navigation
=
341 SerializedNavigationEntry::FromNavigationEntry(kIndex
,
343 const sync_pb::TabNavigation
& sync_data
= navigation
.ToSyncData();
344 const SerializedNavigationEntry
& constructed_nav
=
345 SerializedNavigationEntry::FromSyncData(kIndex
, sync_data
);
346 const content::PageTransition constructed_transition
=
347 constructed_nav
.transition_type();
349 EXPECT_EQ(transition
, constructed_transition
);
354 // Tests that the input data is sanitized when a SerializedNavigationEntry
355 // is created from a pickle format.
356 TEST(SerializedNavigationEntryTest
, Sanitize
) {
357 sync_pb::TabNavigation sync_data
= MakeSyncDataForTest();
359 sync_data
.set_referrer_policy(blink::WebReferrerPolicyNever
);
360 content::PageState page_state
=
361 content::PageState::CreateFromURL(kVirtualURL
);
362 sync_data
.set_state(page_state
.ToEncodedData());
364 const SerializedNavigationEntry
& navigation
=
365 SerializedNavigationEntry::FromSyncData(kIndex
, sync_data
);
367 EXPECT_EQ(kIndex
, navigation
.index());
368 EXPECT_EQ(kUniqueID
, navigation
.unique_id());
369 EXPECT_EQ(GURL(), navigation
.referrer().url
);
370 EXPECT_EQ(blink::WebReferrerPolicyDefault
, navigation
.referrer().policy
);
371 EXPECT_EQ(kVirtualURL
, navigation
.virtual_url());
372 EXPECT_EQ(kTitle
, navigation
.title());
373 EXPECT_EQ(page_state
, navigation
.page_state());
374 EXPECT_EQ(kTransitionType
, navigation
.transition_type());
375 EXPECT_FALSE(navigation
.has_post_data());
376 EXPECT_EQ(-1, navigation
.post_id());
377 EXPECT_EQ(GURL(), navigation
.original_request_url());
378 EXPECT_FALSE(navigation
.is_overriding_user_agent());
379 EXPECT_TRUE(navigation
.timestamp().is_null());
380 EXPECT_EQ(kSearchTerms
, navigation
.search_terms());
381 EXPECT_EQ(kFaviconURL
, navigation
.favicon_url());
382 EXPECT_EQ(kHttpStatusCode
, navigation
.http_status_code());
384 content::PageState empty_state
;
385 EXPECT_TRUE(empty_state
.Equals(empty_state
.RemoveReferrer()));
389 } // namespace sessions