Home | History | Annotate | Download | only in sessions
      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.
      4 
      5 #include "components/sessions/serialized_navigation_entry.h"
      6 
      7 #include <cstddef>
      8 #include <string>
      9 
     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/referrer.h"
     20 #include "sync/protocol/session_specifics.pb.h"
     21 #include "sync/util/time.h"
     22 #include "testing/gtest/include/gtest/gtest.h"
     23 #include "third_party/WebKit/public/platform/WebReferrerPolicy.h"
     24 #include "ui/base/page_transition_types.h"
     25 #include "url/gurl.h"
     26 
     27 namespace sessions {
     28 namespace {
     29 
     30 const int kIndex = 3;
     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 ui::PageTransition kTransitionType =
     40     ui::PageTransitionFromInt(
     41         ui::PAGE_TRANSITION_AUTO_SUBFRAME |
     42         ui::PAGE_TRANSITION_HOME_PAGE |
     43         ui::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");
     55 
     56 const int kPageID = 10;
     57 
     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();
     82 }
     83 
     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.
    102   return sync_data;
    103 }
    104 
    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(ui::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());
    126 }
    127 
    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());
    133 
    134   const SerializedNavigationEntry& navigation =
    135       SerializedNavigationEntry::FromNavigationEntry(kIndex, *navigation_entry);
    136 
    137   EXPECT_EQ(kIndex, navigation.index());
    138 
    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]);
    157 }
    158 
    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();
    164 
    165   const SerializedNavigationEntry& navigation =
    166       SerializedNavigationEntry::FromSyncData(kIndex, sync_data);
    167 
    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.
    185 }
    186 
    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());
    194 
    195   Pickle pickle;
    196   old_navigation.WriteToPickle(30000, &pickle);
    197 
    198   SerializedNavigationEntry new_navigation;
    199   PickleIterator pickle_iterator(pickle);
    200   EXPECT_TRUE(new_navigation.ReadFromPickle(&pickle_iterator));
    201 
    202   EXPECT_EQ(kIndex, new_navigation.index());
    203 
    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());
    219 }
    220 
    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
    224 // expected values.
    225 TEST(SerializedNavigationEntryTest, ToNavigationEntry) {
    226   const scoped_ptr<content::NavigationEntry> old_navigation_entry(
    227       MakeNavigationEntryForTest());
    228 
    229   const SerializedNavigationEntry& navigation =
    230       SerializedNavigationEntry::FromNavigationEntry(kIndex,
    231                                                      *old_navigation_entry);
    232 
    233   const scoped_ptr<content::NavigationEntry> new_navigation_entry(
    234       navigation.ToNavigationEntry(kPageID, NULL));
    235 
    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(ui::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]);
    258 }
    259 
    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());
    266 
    267   const SerializedNavigationEntry& navigation =
    268       SerializedNavigationEntry::FromNavigationEntry(kIndex, *navigation_entry);
    269 
    270   const sync_pb::TabNavigation sync_data = navigation.ToSyncData();
    271 
    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());
    292 }
    293 
    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());
    302 
    303   navigation_entry->SetVirtualURL(kOtherURL);
    304 
    305   const SerializedNavigationEntry& navigation =
    306       SerializedNavigationEntry::FromNavigationEntry(kIndex, *navigation_entry);
    307 
    308   const sync_pb::TabNavigation sync_data = navigation.ToSyncData();
    309 
    310   EXPECT_TRUE(sync_data.has_last_navigation_redirect_url());
    311   EXPECT_EQ(kVirtualURL.spec(), sync_data.last_navigation_redirect_url());
    312 
    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());
    319 }
    320 
    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 = ui::PAGE_TRANSITION_LINK;
    327        core_type != ui::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
    331     // breaking.
    332     for (uint32 qualifier = ui::PAGE_TRANSITION_FORWARD_BACK;
    333          qualifier != 0; qualifier <<= 1) {
    334       if (qualifier == 0x08000000)
    335         continue;  // 0x08000000 is not a valid qualifier.
    336       ui::PageTransition transition =
    337           ui::PageTransitionFromInt(core_type | qualifier);
    338 
    339       navigation_entry->SetTransitionType(transition);
    340       const SerializedNavigationEntry& navigation =
    341           SerializedNavigationEntry::FromNavigationEntry(kIndex,
    342                                                          *navigation_entry);
    343       const sync_pb::TabNavigation& sync_data = navigation.ToSyncData();
    344       const SerializedNavigationEntry& constructed_nav =
    345           SerializedNavigationEntry::FromSyncData(kIndex, sync_data);
    346       const ui::PageTransition constructed_transition =
    347           constructed_nav.transition_type();
    348 
    349       EXPECT_EQ(transition, constructed_transition);
    350     }
    351   }
    352 }
    353 
    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();
    358 
    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());
    363 
    364   const SerializedNavigationEntry& navigation =
    365       SerializedNavigationEntry::FromSyncData(kIndex, sync_data);
    366 
    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());
    383 
    384   content::PageState empty_state;
    385   EXPECT_TRUE(empty_state.Equals(empty_state.RemoveReferrer()));
    386 }
    387 
    388 }  // namespace
    389 }  // namespace sessions
    390