Home | History | Annotate | Download | only in native
      1 // Copyright (c) 2012 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 "android_webview/native/state_serializer.h"
      6 
      7 #include <string>
      8 
      9 #include "base/memory/scoped_vector.h"
     10 #include "base/pickle.h"
     11 #include "base/time/time.h"
     12 #include "content/public/browser/child_process_security_policy.h"
     13 #include "content/public/browser/navigation_controller.h"
     14 #include "content/public/browser/navigation_entry.h"
     15 #include "content/public/browser/render_process_host.h"
     16 #include "content/public/browser/web_contents.h"
     17 #include "content/public/common/page_state.h"
     18 
     19 // Reasons for not re-using TabNavigation under chrome/ as of 20121116:
     20 // * Android WebView has different requirements for fields to store since
     21 //   we are the only ones using values like BaseURLForDataURL.
     22 // * TabNavigation does unnecessary copying of data, which in Android
     23 //   WebView case, is undesired since save/restore is called in Android
     24 //   very frequently.
     25 // * TabNavigation is tightly integrated with the rest of chrome session
     26 //   restore and sync code, and has other purpose in addition to serializing
     27 //   NavigationEntry.
     28 
     29 using std::string;
     30 
     31 namespace android_webview {
     32 
     33 namespace {
     34 
     35 // Sanity check value that we are restoring from a valid pickle.
     36 // This can potentially used as an actual serialization version number in the
     37 // future if we ever decide to support restoring from older versions.
     38 const uint32 AW_STATE_VERSION = 20121126;
     39 
     40 }  // namespace
     41 
     42 bool WriteToPickle(const content::WebContents& web_contents,
     43                    Pickle* pickle) {
     44   DCHECK(pickle);
     45 
     46   if (!internal::WriteHeaderToPickle(pickle))
     47     return false;
     48 
     49   const content::NavigationController& controller =
     50       web_contents.GetController();
     51   const int entry_count = controller.GetEntryCount();
     52   const int selected_entry = controller.GetCurrentEntryIndex();
     53   DCHECK(entry_count >= 0);
     54   DCHECK(selected_entry >= -1);  // -1 is valid
     55   DCHECK(selected_entry < entry_count);
     56 
     57   if (!pickle->WriteInt(entry_count))
     58     return false;
     59 
     60   if (!pickle->WriteInt(selected_entry))
     61     return false;
     62 
     63   for (int i = 0; i < entry_count; ++i) {
     64     if (!internal::WriteNavigationEntryToPickle(*controller.GetEntryAtIndex(i),
     65                                                 pickle))
     66       return false;
     67   }
     68 
     69   // Please update AW_STATE_VERSION if serialization format is changed.
     70 
     71   return true;
     72 }
     73 
     74 bool RestoreFromPickle(PickleIterator* iterator,
     75                        content::WebContents* web_contents) {
     76   DCHECK(iterator);
     77   DCHECK(web_contents);
     78 
     79   if (!internal::RestoreHeaderFromPickle(iterator))
     80     return false;
     81 
     82   int entry_count = -1;
     83   int selected_entry = -2;  // -1 is a valid value
     84 
     85   if (!iterator->ReadInt(&entry_count))
     86     return false;
     87 
     88   if (!iterator->ReadInt(&selected_entry))
     89     return false;
     90 
     91   if (entry_count < 0)
     92     return false;
     93   if (selected_entry < -1)
     94     return false;
     95   if (selected_entry >= entry_count)
     96     return false;
     97 
     98   ScopedVector<content::NavigationEntry> restored_entries;
     99   for (int i = 0; i < entry_count; ++i) {
    100     restored_entries.push_back(content::NavigationEntry::Create());
    101     if (!internal::RestoreNavigationEntryFromPickle(iterator,
    102                                                     restored_entries[i]))
    103       return false;
    104 
    105     restored_entries[i]->SetPageID(i);
    106   }
    107 
    108   // |web_contents| takes ownership of these entries after this call.
    109   content::NavigationController& controller = web_contents->GetController();
    110   controller.Restore(
    111       selected_entry,
    112       content::NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY,
    113       &restored_entries.get());
    114   DCHECK_EQ(0u, restored_entries.size());
    115 
    116   if (controller.GetActiveEntry()) {
    117     // Set up the file access rights for the selected navigation entry.
    118     // TODO(joth): This is duplicated from chrome/.../session_restore.cc and
    119     // should be shared e.g. in  NavigationController. http://crbug.com/68222
    120     const int id = web_contents->GetRenderProcessHost()->GetID();
    121     const content::PageState& page_state =
    122         controller.GetActiveEntry()->GetPageState();
    123     const std::vector<base::FilePath>& file_paths =
    124         page_state.GetReferencedFiles();
    125     for (std::vector<base::FilePath>::const_iterator file = file_paths.begin();
    126          file != file_paths.end(); ++file) {
    127       content::ChildProcessSecurityPolicy::GetInstance()->GrantReadFile(id,
    128                                                                         *file);
    129     }
    130   }
    131 
    132   controller.LoadIfNecessary();
    133 
    134   return true;
    135 }
    136 
    137 namespace internal {
    138 
    139 bool WriteHeaderToPickle(Pickle* pickle) {
    140   return pickle->WriteUInt32(AW_STATE_VERSION);
    141 }
    142 
    143 bool RestoreHeaderFromPickle(PickleIterator* iterator) {
    144   uint32 state_version = -1;
    145   if (!iterator->ReadUInt32(&state_version))
    146     return false;
    147 
    148   if (AW_STATE_VERSION != state_version)
    149     return false;
    150 
    151   return true;
    152 }
    153 
    154 bool WriteNavigationEntryToPickle(const content::NavigationEntry& entry,
    155                                   Pickle* pickle) {
    156   if (!pickle->WriteString(entry.GetURL().spec()))
    157     return false;
    158 
    159   if (!pickle->WriteString(entry.GetVirtualURL().spec()))
    160     return false;
    161 
    162   const content::Referrer& referrer = entry.GetReferrer();
    163   if (!pickle->WriteString(referrer.url.spec()))
    164     return false;
    165   if (!pickle->WriteInt(static_cast<int>(referrer.policy)))
    166     return false;
    167 
    168   if (!pickle->WriteString16(entry.GetTitle()))
    169     return false;
    170 
    171   if (!pickle->WriteString(entry.GetPageState().ToEncodedData()))
    172     return false;
    173 
    174   if (!pickle->WriteBool(static_cast<int>(entry.GetHasPostData())))
    175     return false;
    176 
    177   if (!pickle->WriteString(entry.GetOriginalRequestURL().spec()))
    178     return false;
    179 
    180   if (!pickle->WriteString(entry.GetBaseURLForDataURL().spec()))
    181     return false;
    182 
    183   if (!pickle->WriteBool(static_cast<int>(entry.GetIsOverridingUserAgent())))
    184     return false;
    185 
    186   if (!pickle->WriteInt64(entry.GetTimestamp().ToInternalValue()))
    187     return false;
    188 
    189   // Please update AW_STATE_VERSION if serialization format is changed.
    190 
    191   return true;
    192 }
    193 
    194 bool RestoreNavigationEntryFromPickle(PickleIterator* iterator,
    195                                       content::NavigationEntry* entry) {
    196   {
    197     string url;
    198     if (!iterator->ReadString(&url))
    199       return false;
    200     entry->SetURL(GURL(url));
    201   }
    202 
    203   {
    204     string virtual_url;
    205     if (!iterator->ReadString(&virtual_url))
    206       return false;
    207     entry->SetVirtualURL(GURL(virtual_url));
    208   }
    209 
    210   {
    211     content::Referrer referrer;
    212     string referrer_url;
    213     int policy;
    214 
    215     if (!iterator->ReadString(&referrer_url))
    216       return false;
    217     if (!iterator->ReadInt(&policy))
    218       return false;
    219 
    220     referrer.url = GURL(referrer_url);
    221     referrer.policy = static_cast<WebKit::WebReferrerPolicy>(policy);
    222     entry->SetReferrer(referrer);
    223   }
    224 
    225   {
    226     string16 title;
    227     if (!iterator->ReadString16(&title))
    228       return false;
    229     entry->SetTitle(title);
    230   }
    231 
    232   {
    233     string content_state;
    234     if (!iterator->ReadString(&content_state))
    235       return false;
    236     entry->SetPageState(
    237         content::PageState::CreateFromEncodedData(content_state));
    238   }
    239 
    240   {
    241     bool has_post_data;
    242     if (!iterator->ReadBool(&has_post_data))
    243       return false;
    244     entry->SetHasPostData(has_post_data);
    245   }
    246 
    247   {
    248     string original_request_url;
    249     if (!iterator->ReadString(&original_request_url))
    250       return false;
    251     entry->SetOriginalRequestURL(GURL(original_request_url));
    252   }
    253 
    254   {
    255     string base_url_for_data_url;
    256     if (!iterator->ReadString(&base_url_for_data_url))
    257       return false;
    258     entry->SetBaseURLForDataURL(GURL(base_url_for_data_url));
    259   }
    260 
    261   {
    262     bool is_overriding_user_agent;
    263     if (!iterator->ReadBool(&is_overriding_user_agent))
    264       return false;
    265     entry->SetIsOverridingUserAgent(is_overriding_user_agent);
    266   }
    267 
    268   {
    269     int64 timestamp;
    270     if (!iterator->ReadInt64(&timestamp))
    271       return false;
    272     entry->SetTimestamp(base::Time::FromInternalValue(timestamp));
    273   }
    274 
    275   return true;
    276 }
    277 
    278 }  // namespace internal
    279 
    280 }  // namespace android_webview
    281