Title: [121354] trunk/Source/WebKit2
Revision
121354
Author
beid...@apple.com
Date
2012-06-27 11:28:52 -0700 (Wed, 27 Jun 2012)

Log Message

https://bugs.webkit.org/show_bug.cgi?id=87513
WebBackForwardList needs an overhaul to consistently and clearly handle error conditions.

Reviewed by Darin Adler.

- We think a null entry might somehow be getting in the list so we now try to prevent that.
- We think a null entry might somehow be in the list so we now null check when indexing into m_entries.
- A lot of index math - especially tracking "no current index" - was implicit or wrong.
- Operating on a WebBackForwardList whose page has been closed is now an explicit no-op.
- The session state data reading and writing code was fragile and needed an overhaul.
- This includes adding a new V1 format of the session data that is easier to validate when reading back in.

* UIProcess/WebBackForwardList.cpp:
(WebKit::WebBackForwardList::~WebBackForwardList):
(WebKit::WebBackForwardList::pageClosed):
(WebKit::WebBackForwardList::addItem):
(WebKit::WebBackForwardList::goToItem):
(WebKit::WebBackForwardList::backListCount):
(WebKit::WebBackForwardList::forwardListCount):
(WebKit::WebBackForwardList::backListAsImmutableArrayWithLimit):
(WebKit::WebBackForwardList::forwardListAsImmutableArrayWithLimit):
(WebKit::WebBackForwardList::clear):

* UIProcess/WebBackForwardList.h:
(WebBackForwardList):

* UIProcess/cf/WebBackForwardListCF.cpp:
(WebKit::createEmptySessionHistoryDictionary):
(WebKit::WebBackForwardList::createCFDictionaryRepresentation):
(WebKit::WebBackForwardList::restoreFromCFDictionaryRepresentation):
(WebKit::WebBackForwardList::restoreFromV0CFDictionaryRepresentation):
(WebKit::WebBackForwardList::restoreFromV1CFDictionaryRepresentation):
(WebKit::extractBackForwardListEntriesFromArray):

Modified Paths

Diff

Modified: trunk/Source/WebKit2/ChangeLog (121353 => 121354)


--- trunk/Source/WebKit2/ChangeLog	2012-06-27 18:28:20 UTC (rev 121353)
+++ trunk/Source/WebKit2/ChangeLog	2012-06-27 18:28:52 UTC (rev 121354)
@@ -1,3 +1,39 @@
+2012-06-27  Brady Eidson  <beid...@apple.com>
+
+        https://bugs.webkit.org/show_bug.cgi?id=87513
+        WebBackForwardList needs an overhaul to consistently and clearly handle error conditions.
+
+        Reviewed by Darin Adler.
+
+        - We think a null entry might somehow be getting in the list so we now try to prevent that.
+        - We think a null entry might somehow be in the list so we now null check when indexing into m_entries.
+        - A lot of index math - especially tracking "no current index" - was implicit or wrong.
+        - Operating on a WebBackForwardList whose page has been closed is now an explicit no-op.
+        - The session state data reading and writing code was fragile and needed an overhaul.
+        - This includes adding a new V1 format of the session data that is easier to validate when reading back in.
+
+        * UIProcess/WebBackForwardList.cpp:
+        (WebKit::WebBackForwardList::~WebBackForwardList):
+        (WebKit::WebBackForwardList::pageClosed):
+        (WebKit::WebBackForwardList::addItem):
+        (WebKit::WebBackForwardList::goToItem):
+        (WebKit::WebBackForwardList::backListCount):
+        (WebKit::WebBackForwardList::forwardListCount):
+        (WebKit::WebBackForwardList::backListAsImmutableArrayWithLimit):
+        (WebKit::WebBackForwardList::forwardListAsImmutableArrayWithLimit):
+        (WebKit::WebBackForwardList::clear):
+
+        * UIProcess/WebBackForwardList.h:
+        (WebBackForwardList):
+
+        * UIProcess/cf/WebBackForwardListCF.cpp:
+        (WebKit::createEmptySessionHistoryDictionary):
+        (WebKit::WebBackForwardList::createCFDictionaryRepresentation):
+        (WebKit::WebBackForwardList::restoreFromCFDictionaryRepresentation):
+        (WebKit::WebBackForwardList::restoreFromV0CFDictionaryRepresentation):
+        (WebKit::WebBackForwardList::restoreFromV1CFDictionaryRepresentation):
+        (WebKit::extractBackForwardListEntriesFromArray):
+
 2012-06-27  Zan Dobersek  <zandober...@gmail.com>
 
         [Gtk] Add support for the Gamepad API

Modified: trunk/Source/WebKit2/UIProcess/WebBackForwardList.cpp (121353 => 121354)


--- trunk/Source/WebKit2/UIProcess/WebBackForwardList.cpp	2012-06-27 18:28:20 UTC (rev 121353)
+++ trunk/Source/WebKit2/UIProcess/WebBackForwardList.cpp	2012-06-27 18:28:52 UTC (rev 121354)
@@ -43,17 +43,28 @@
 
 WebBackForwardList::~WebBackForwardList()
 {
+    // A WebBackForwardList should never be destroyed unless it's associated page has been closed or is invalid.
+    ASSERT((!m_page && !m_hasCurrentIndex) || !m_page->isValid());
 }
 
 void WebBackForwardList::pageClosed()
 {
+    // We should have always started out with an m_page and we should never close the page twice.
+    ASSERT(m_page);
+
     if (m_page) {
         size_t size = m_entries.size();
-        for (size_t i = 0; i < size; ++i)
+        for (size_t i = 0; i < size; ++i) {
+            ASSERT(m_entries[i]);
+            if (!m_entries[i])
+                continue;
             m_page->backForwardRemovedItem(m_entries[i]->itemID());
+        }
     }
 
     m_page = 0;
+    m_entries.clear();
+    m_hasCurrentIndex = false;
 }
 
 void WebBackForwardList::addItem(WebBackForwardListItem* newItem)
@@ -81,15 +92,22 @@
             m_page->backForwardRemovedItem(m_entries[0]->itemID());
             removedItems.append(m_entries[0].release());
             m_entries.remove(0);
+
             if (m_entries.isEmpty())
                 m_hasCurrentIndex = false;
             else
                 m_currentIndex--;
         }
     } else {
-        // If we have no current item index, we should have no other entries before adding this new item.
+        // If we have no current item index we should also not have any entries.
+        ASSERT(m_entries.isEmpty());
+
+        // But just in case it does happen in practice we'll get back in to a consistent state now before adding the new item.
         size_t size = m_entries.size();
         for (size_t i = 0; i < size; ++i) {
+            ASSERT(m_entries[i]);
+            if (!m_entries[i])
+                continue;
             m_page->backForwardRemovedItem(m_entries[i]->itemID());
             removedItems.append(m_entries[i].release());
         }
@@ -97,6 +115,7 @@
     }
     
     if (!m_hasCurrentIndex) {
+        ASSERT(m_entries.isEmpty());
         m_currentIndex = 0;
         m_hasCurrentIndex = true;
     } else
@@ -115,7 +134,7 @@
 {
     ASSERT(!m_hasCurrentIndex || m_currentIndex < m_entries.size());
 
-    if (!m_entries.size() || !item)
+    if (!m_entries.size() || !item || !m_page || !m_hasCurrentIndex)
         return;
         
     unsigned index = 0;
@@ -125,8 +144,7 @@
     }
     if (index < m_entries.size()) {
         m_currentIndex = index;
-        if (m_page)
-            m_page->didChangeBackForwardList(0, 0);
+        m_page->didChangeBackForwardList(0, 0);
     }
 }
 
@@ -134,28 +152,28 @@
 {
     ASSERT(!m_hasCurrentIndex || m_currentIndex < m_entries.size());
 
-    return m_hasCurrentIndex ? m_entries[m_currentIndex].get() : 0;
+    return m_page && m_hasCurrentIndex ? m_entries[m_currentIndex].get() : 0;
 }
 
 WebBackForwardListItem* WebBackForwardList::backItem()
 {
     ASSERT(!m_hasCurrentIndex || m_currentIndex < m_entries.size());
 
-    return m_hasCurrentIndex && m_currentIndex ? m_entries[m_currentIndex - 1].get() : 0;
+    return m_page && m_hasCurrentIndex && m_currentIndex ? m_entries[m_currentIndex - 1].get() : 0;
 }
 
 WebBackForwardListItem* WebBackForwardList::forwardItem()
 {
     ASSERT(!m_hasCurrentIndex || m_currentIndex < m_entries.size());
 
-    return m_hasCurrentIndex && m_entries.size() && m_currentIndex < m_entries.size() - 1 ? m_entries[m_currentIndex + 1].get() : 0;
+    return m_page && m_hasCurrentIndex && m_entries.size() && m_currentIndex < m_entries.size() - 1 ? m_entries[m_currentIndex + 1].get() : 0;
 }
 
 WebBackForwardListItem* WebBackForwardList::itemAtIndex(int index)
 {
     ASSERT(!m_hasCurrentIndex || m_currentIndex < m_entries.size());
 
-    if (!m_hasCurrentIndex)
+    if (!m_hasCurrentIndex || !m_page)
         return 0;
     
     // Do range checks without doing math on index to avoid overflow.
@@ -172,20 +190,23 @@
 {
     ASSERT(!m_hasCurrentIndex || m_currentIndex < m_entries.size());
 
-    return !m_hasCurrentIndex ? 0 : m_currentIndex;
+    return m_page && m_hasCurrentIndex ? m_currentIndex : 0;
 }
 
 int WebBackForwardList::forwardListCount()
 {
     ASSERT(!m_hasCurrentIndex || m_currentIndex < m_entries.size());
 
-    return !m_hasCurrentIndex ? 0 : static_cast<int>(m_entries.size()) - (m_currentIndex + 1);
+    return m_page && m_hasCurrentIndex ? m_entries.size() - (m_currentIndex + 1) : 0;
 }
 
 PassRefPtr<ImmutableArray> WebBackForwardList::backListAsImmutableArrayWithLimit(unsigned limit)
 {
     ASSERT(!m_hasCurrentIndex || m_currentIndex < m_entries.size());
 
+    if (!m_page || !m_hasCurrentIndex)
+        return ImmutableArray::create();
+
     unsigned backListSize = static_cast<unsigned>(backListCount());
     unsigned size = std::min(backListSize, limit);
     if (!size)
@@ -195,8 +216,10 @@
     vector.reserveInitialCapacity(size);
 
     ASSERT(backListSize >= size);
-    for (unsigned i = backListSize - size; i < backListSize; ++i)
+    for (unsigned i = backListSize - size; i < backListSize; ++i) {
+        ASSERT(m_entries[i]);
         vector.uncheckedAppend(m_entries[i].get());
+    }
 
     return ImmutableArray::adopt(vector);
 }
@@ -205,6 +228,9 @@
 {
     ASSERT(!m_hasCurrentIndex || m_currentIndex < m_entries.size());
 
+    if (!m_page || !m_hasCurrentIndex)
+        return ImmutableArray::create();
+
     unsigned size = std::min(static_cast<unsigned>(forwardListCount()), limit);
     if (!size)
         return ImmutableArray::create();
@@ -214,8 +240,10 @@
 
     unsigned last = m_currentIndex + size;
     ASSERT(last < m_entries.size());
-    for (unsigned i = m_currentIndex + 1; i <= last; ++i)
+    for (unsigned i = m_currentIndex + 1; i <= last; ++i) {
+        ASSERT(m_entries[i]);
         vector.uncheckedAppend(m_entries[i].get());
+    }
 
     return ImmutableArray::adopt(vector);
 }
@@ -225,22 +253,42 @@
     ASSERT(!m_hasCurrentIndex || m_currentIndex < m_entries.size());
 
     size_t size = m_entries.size();
-    if (size <= 1)
+    if (!m_page || size <= 1)
         return;
 
     RefPtr<WebBackForwardListItem> currentItem = this->currentItem();
+    Vector<RefPtr<APIObject> > removedItems;
 
-    if (m_page) {
+    if (!currentItem) {
+        // We should only ever have no current item if we also have no current item index.
+        ASSERT(!m_hasCurrentIndex);
+
+        // But just in case it does happen in practice we should get back into a consistent state now.
         for (size_t i = 0; i < size; ++i) {
-            if (m_entries[i] != currentItem)
-                m_page->backForwardRemovedItem(m_entries[i]->itemID());
+            ASSERT(m_entries[i]);
+            if (!m_entries[i])
+                continue;
+
+            m_page->backForwardRemovedItem(m_entries[i]->itemID());
+            removedItems.append(m_entries[i].release());
         }
+
+        m_entries.clear();
+        m_hasCurrentIndex = false;
+        m_page->didChangeBackForwardList(0, &removedItems);
+
+        return;
     }
 
-    Vector<RefPtr<APIObject> > removedItems;
-    removedItems.reserveCapacity(m_entries.size() - 1);
-    for (size_t i = 0; i < m_entries.size(); ++i) {
-        if (i != m_currentIndex)
+    for (size_t i = 0; i < size; ++i) {
+        ASSERT(m_entries[i]);
+        if (m_entries[i] && m_entries[i] != currentItem)
+            m_page->backForwardRemovedItem(m_entries[i]->itemID());
+    }
+
+    removedItems.reserveCapacity(size - 1);
+    for (size_t i = 0; i < size; ++i) {
+        if (i != m_currentIndex && m_hasCurrentIndex && m_entries[i])
             removedItems.append(m_entries[i].release());
     }
 
@@ -254,8 +302,7 @@
         m_hasCurrentIndex = false;
     }
 
-    if (m_page)
-        m_page->didChangeBackForwardList(0, &removedItems);
+    m_page->didChangeBackForwardList(0, &removedItems);
 }
 
 } // namespace WebKit

Modified: trunk/Source/WebKit2/UIProcess/WebBackForwardList.h (121353 => 121354)


--- trunk/Source/WebKit2/UIProcess/WebBackForwardList.h	2012-06-27 18:28:20 UTC (rev 121353)
+++ trunk/Source/WebKit2/UIProcess/WebBackForwardList.h	2012-06-27 18:28:52 UTC (rev 121354)
@@ -80,6 +80,8 @@
 #if USE(CF)
     CFDictionaryRef createCFDictionaryRepresentation(WebPageProxy::WebPageProxySessionStateFilterCallback, void* context) const;
     bool restoreFromCFDictionaryRepresentation(CFDictionaryRef);
+    bool restoreFromV0CFDictionaryRepresentation(CFDictionaryRef);
+    bool restoreFromV1CFDictionaryRepresentation(CFDictionaryRef);
 #endif
 
 private:

Modified: trunk/Source/WebKit2/UIProcess/cf/WebBackForwardListCF.cpp (121353 => 121354)


--- trunk/Source/WebKit2/UIProcess/cf/WebBackForwardListCF.cpp	2012-06-27 18:28:20 UTC (rev 121353)
+++ trunk/Source/WebKit2/UIProcess/cf/WebBackForwardListCF.cpp	2012-06-27 18:28:52 UTC (rev 121354)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010, 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2010, 2011, 2012 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -44,6 +44,10 @@
     return uniqueHistoryItemID;
 }
 
+static CFIndex currentVersion = 1;
+DEFINE_STATIC_GETTER(CFNumberRef, SessionHistoryCurrentVersion, (CFNumberCreate(0, kCFNumberCFIndexType, &currentVersion)));
+
+DEFINE_STATIC_GETTER(CFStringRef, SessionHistoryVersionKey, (CFSTR("SessionHistoryVersion")));
 DEFINE_STATIC_GETTER(CFStringRef, SessionHistoryCurrentIndexKey, (CFSTR("SessionHistoryCurrentIndex")));
 DEFINE_STATIC_GETTER(CFStringRef, SessionHistoryEntriesKey, (CFSTR("SessionHistoryEntries")));
 DEFINE_STATIC_GETTER(CFStringRef, SessionHistoryEntryTitleKey, (CFSTR("SessionHistoryEntryTitle")));
@@ -51,23 +55,41 @@
 DEFINE_STATIC_GETTER(CFStringRef, SessionHistoryEntryOriginalURLKey, (CFSTR("SessionHistoryEntryOriginalURL")));
 DEFINE_STATIC_GETTER(CFStringRef, SessionHistoryEntryDataKey, (CFSTR("SessionHistoryEntryData")));
 
+static bool extractBackForwardListEntriesFromArray(CFArrayRef, BackForwardListItemVector&);
+
+static CFDictionaryRef createEmptySessionHistoryDictionary()
+{
+    static const void* keys[1] = { SessionHistoryVersionKey() };
+    static const void* values[1] = { SessionHistoryCurrentVersion() };
+
+    return CFDictionaryCreate(0, keys, values, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+}
+
 CFDictionaryRef WebBackForwardList::createCFDictionaryRepresentation(WebPageProxy::WebPageProxySessionStateFilterCallback filter, void* context) const
 {
     ASSERT(!m_hasCurrentIndex || m_currentIndex < m_entries.size());
 
+    if (!m_hasCurrentIndex) {
+        // We represent having no current index by writing out an empty dictionary (besides the version).
+        return createEmptySessionHistoryDictionary();
+    }
+
     RetainPtr<CFMutableArrayRef> entries(AdoptCF, CFArrayCreateMutable(0, m_entries.size(), &kCFTypeArrayCallBacks));
 
     // We may need to update the current index to account for entries that are filtered by the callback.
     CFIndex currentIndex = m_currentIndex;
+    bool hasCurrentIndex = true;
 
     for (size_t i = 0; i < m_entries.size(); ++i) {
         // If we somehow ended up with a null entry then we should consider the data invalid and not save session history at all.
         ASSERT(m_entries[i]);
-        if (!m_entries[i])
+        if (!m_entries[i]) {
+            LOG(SessionState, "WebBackForwardList contained a null entry at index %lu", i);
             return 0;
+        }
 
         if (filter && !filter(toAPI(m_page), WKPageGetSessionHistoryURLValueType(), toURLRef(m_entries[i]->originalURL().impl()), context)) {
-            if (i <= static_cast<size_t>(m_currentIndex))
+            if (i <= m_currentIndex)
                 currentIndex--;
             continue;
         }
@@ -87,26 +109,62 @@
         CFArrayAppendValue(entries.get(), entryDictionary.get());
     }
         
-    // If all items before and including the current item were filtered then currentIndex will be -1.
-    // Assuming we didn't start out with NoCurrentItemIndex, we should store "current" to point at the first item.
-    if (currentIndex == -1 && m_hasCurrentIndex && CFArrayGetCount(entries.get()))
-        currentIndex = 0;
+    ASSERT(currentIndex == -1 || (currentIndex > -1 && currentIndex < CFArrayGetCount(entries.get())));
+    if (currentIndex < -1 || currentIndex >= CFArrayGetCount(entries.get())) {
+        LOG(SessionState, "Filtering entries to be saved resulted in an inconsistent state that we cannot represent");
+        return 0;
+    }
 
-    // FIXME: We're relying on currentIndex == -1 to mean the exact same thing as NoCurrentItemIndex (UINT_MAX) in unsigned form.
-    // That seems implicit and fragile and we should find a better way of representing the NoCurrentItemIndex case.
-    if (!m_hasCurrentIndex || !CFArrayGetCount(entries.get()))
-        currentIndex = -1;
+    // If we have an index and all items before and including the current item were filtered then currentIndex will be -1.
+    // In this case the new current index should point at the first item.
+    // It's also possible that all items were filtered so we should represent not having a current index.
+    if (currentIndex == -1) {
+        if (CFArrayGetCount(entries.get()))
+            currentIndex = 0;
+        else
+            hasCurrentIndex = false;
+    }
 
-    RetainPtr<CFNumberRef> currentIndexNumber(AdoptCF, CFNumberCreate(0, kCFNumberCFIndexType, &currentIndex));
+    if (hasCurrentIndex) {
+        RetainPtr<CFNumberRef> currentIndexNumber(AdoptCF, CFNumberCreate(0, kCFNumberCFIndexType, &currentIndex));
+        const void* keys[3] = { SessionHistoryVersionKey(), SessionHistoryCurrentIndexKey(), SessionHistoryEntriesKey() };
+        const void* values[3] = { SessionHistoryCurrentVersion(), currentIndexNumber.get(), entries.get() };
+ 
+        return CFDictionaryCreate(0, keys, values, 3, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+    }
 
-    const void* keys[2] = { SessionHistoryCurrentIndexKey(), SessionHistoryEntriesKey() };
-    const void* values[2] = { currentIndexNumber.get(), entries.get() };
-
-    return CFDictionaryCreate(0, keys, values, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+    // We represent having no current index by writing out an empty dictionary (besides the version).
+    return createEmptySessionHistoryDictionary();
 }
 
 bool WebBackForwardList::restoreFromCFDictionaryRepresentation(CFDictionaryRef dictionary)
 {
+    CFNumberRef cfVersion = (CFNumberRef)CFDictionaryGetValue(dictionary, SessionHistoryVersionKey());
+    if (!cfVersion) {
+        // v0 session history dictionaries did not contain versioning
+        return restoreFromV0CFDictionaryRepresentation(dictionary);
+    }
+    
+    if (CFGetTypeID(cfVersion) != CFNumberGetTypeID()) {
+        LOG(SessionState, "WebBackForwardList dictionary representation contains a version that is not a number");
+        return false;
+    }
+
+    CFIndex version;
+    if (!CFNumberGetValue(cfVersion, kCFNumberCFIndexType, &version)) {
+        LOG(SessionState, "WebBackForwardList dictionary representation does not have a correctly typed current version");
+        return false;
+    }
+    
+    if (version == 1)
+        return restoreFromV1CFDictionaryRepresentation(dictionary);
+    
+    LOG(SessionState, "WebBackForwardList dictionary representation has an invalid current version (%ld)", version);
+    return false;
+}
+
+bool WebBackForwardList::restoreFromV0CFDictionaryRepresentation(CFDictionaryRef dictionary)
+{
     CFNumberRef cfIndex = (CFNumberRef)CFDictionaryGetValue(dictionary, SessionHistoryCurrentIndexKey());
     if (!cfIndex || CFGetTypeID(cfIndex) != CFNumberGetTypeID()) {
         LOG(SessionState, "WebBackForwardList dictionary representation does not have a valid current index");
@@ -115,12 +173,12 @@
 
     CFIndex currentCFIndex;
     if (!CFNumberGetValue(cfIndex, kCFNumberCFIndexType, &currentCFIndex)) {
-        LOG(SessionState, "WebBackForwardList dictionary representation does not have a valid integer current index");
+        LOG(SessionState, "WebBackForwardList dictionary representation does not have a correctly typed current index");
         return false;
     }
     
     if (currentCFIndex < -1) {
-        LOG(SessionState, "WebBackForwardList dictionary representation contains a negative current index that is bogus (%ld)", currentCFIndex);
+        LOG(SessionState, "WebBackForwardList dictionary representation contains an unexpected negative current index (%ld)", currentCFIndex);
         return false;
     }
 
@@ -131,23 +189,94 @@
     }
 
     CFIndex size = CFArrayGetCount(cfEntries);
-    if (currentCFIndex < -1 || currentCFIndex >= size ) {
+    if (size < 0 || currentCFIndex >= size) {
         LOG(SessionState, "WebBackForwardList dictionary representation contains an invalid current index (%ld) for the number of entries (%ld)", currentCFIndex, size);
         return false;
     }
 
-    // FIXME: We're relying on currentIndex == -1 to mean the exact same thing as NoCurrentItemIndex (UINT_MAX) in unsigned form.
-    // That seems implicit and fragile and we should find a better way of representing the NoCurrentItemIndex case.
-    bool hasCurrentIndex = currentCFIndex > -1;
-    unsigned currentIndex = hasCurrentIndex ? static_cast<unsigned>(currentCFIndex) : 0;
+    // Version 0 session history relied on currentIndex == -1 to represent the same thing as not having a current index.
+    bool hasCurrentIndex = currentCFIndex != -1;
 
     if (!hasCurrentIndex && size) {
-        LOG(SessionState, "WebBackForwardList dictionary representation says there is no current item index, but there is a list of %ld entries - this is bogus", size);
+        LOG(SessionState, "WebBackForwardList dictionary representation says there is no current index, but there is a list of %ld entries", size);
         return false;
     }
     
-    BackForwardListItemVector newEntries;
-    newEntries.reserveCapacity(size);
+    BackForwardListItemVector entries;
+    if (!extractBackForwardListEntriesFromArray(cfEntries, entries)) {
+        // extractBackForwardListEntriesFromArray has already logged the appropriate error message.
+        return false;
+    }
+
+    ASSERT(entries.size() == static_cast<unsigned>(size));
+    
+    m_hasCurrentIndex = hasCurrentIndex;
+    m_currentIndex = m_hasCurrentIndex ? static_cast<uint32_t>(currentCFIndex) : 0;
+    m_entries = entries;
+
+    return true;
+}
+
+bool WebBackForwardList::restoreFromV1CFDictionaryRepresentation(CFDictionaryRef dictionary)
+{
+    CFNumberRef cfIndex = (CFNumberRef)CFDictionaryGetValue(dictionary, SessionHistoryCurrentIndexKey());
+    if (!cfIndex) {
+        // No current index means the dictionary represents an empty session.
+        m_hasCurrentIndex = false;
+        m_currentIndex = 0;
+        m_entries.clear();
+
+        return true;
+    }
+
+    if (CFGetTypeID(cfIndex) != CFNumberGetTypeID()) {
+        LOG(SessionState, "WebBackForwardList dictionary representation does not have a valid current index");
+        return false;
+    }
+
+    CFIndex currentCFIndex;
+    if (!CFNumberGetValue(cfIndex, kCFNumberCFIndexType, &currentCFIndex)) {
+        LOG(SessionState, "WebBackForwardList dictionary representation does not have a correctly typed current index");
+        return false;
+    }
+    
+    if (currentCFIndex < 0) {
+        LOG(SessionState, "WebBackForwardList dictionary representation contains an unexpected negative current index (%ld)", currentCFIndex);
+        return false;
+    }
+
+    CFArrayRef cfEntries = (CFArrayRef)CFDictionaryGetValue(dictionary, SessionHistoryEntriesKey());
+    if (!cfEntries || CFGetTypeID(cfEntries) != CFArrayGetTypeID()) {
+        LOG(SessionState, "WebBackForwardList dictionary representation does not have a valid list of entries");
+        return false;
+    }
+
+    CFIndex size = CFArrayGetCount(cfEntries);
+    if (currentCFIndex >= size) {
+        LOG(SessionState, "WebBackForwardList dictionary representation contains an invalid current index (%ld) for the number of entries (%ld)", currentCFIndex, size);
+        return false;
+    }
+    
+    BackForwardListItemVector entries;
+    if (!extractBackForwardListEntriesFromArray(cfEntries, entries)) {
+        // extractBackForwardListEntriesFromArray has already logged the appropriate error message.
+        return false;
+    }
+    
+    ASSERT(entries.size() == static_cast<unsigned>(size));
+    
+    m_hasCurrentIndex = true;
+    m_currentIndex = static_cast<uint32_t>(currentCFIndex);
+    m_entries = entries;
+
+    return true;
+}
+
+static bool extractBackForwardListEntriesFromArray(CFArrayRef cfEntries, BackForwardListItemVector& entries)
+{
+    CFIndex size = CFArrayGetCount(cfEntries);
+
+    entries.reserveCapacity(size);
     for (CFIndex i = 0; i < size; ++i) {
         CFDictionaryRef entryDictionary = (CFDictionaryRef)CFArrayGetValueAtIndex(cfEntries, i);
         if (!entryDictionary || CFGetTypeID(entryDictionary) != CFDictionaryGetTypeID()) {
@@ -179,12 +308,8 @@
             return false;
         }
         
-        newEntries.append(WebBackForwardListItem::create(originalURL, entryURL, entryTitle, CFDataGetBytePtr(backForwardData), CFDataGetLength(backForwardData), generateWebBackForwardItemID()));
+        entries.append(WebBackForwardListItem::create(originalURL, entryURL, entryTitle, CFDataGetBytePtr(backForwardData), CFDataGetLength(backForwardData), generateWebBackForwardItemID()));
     }
-    
-    m_entries = newEntries;
-    m_hasCurrentIndex = hasCurrentIndex;
-    m_currentIndex = currentIndex;
 
     return true;
 }
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to