[SCM] WebKit Debian packaging branch, webkit-1.1, updated. upstream/1.1.15.1-1414-gc69ee75

jorlow at chromium.org jorlow at chromium.org
Thu Oct 29 20:38:21 UTC 2009


The following commit has been merged in the webkit-1.1 branch:
commit f9c57a32272a1c16a9e2eee740a22e13219bc854
Author: jorlow at chromium.org <jorlow at chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date:   Fri Oct 2 21:15:41 2009 +0000

    2009-10-02  Jeremy Orlow  <jorlow at chromium.org>
    
            Reviewed by Dimitri Glazkov.
    
            Implement per-storage-area quotas for LocalStorage
            https://bugs.webkit.org/show_bug.cgi?id=29991
    
            I put 90% of the code in StorageMap since the decision to allow an update is
            closely tied to quota tracking.  The quota is set via a page's Settings class.
            Like with the local storage path and whether it's enabled, it's assumed that
            all pages in the same group will have the same settings.  The setting defaults
            to 5mb which is what the spec suggests, but it can easily be changed to
            anything else--including StorageMap::noQuota.  Any values in LocalStorage are
            grandfathered in regarudless of quota, so importItem only tracks (and will
            never block) imports.
    
            I believe this change is a good transition to more complex quota management.
            For example, if we wanted to track quotas in the SQLite DB, then we'd just add
            a function to the StorageMap that sets the quota.  This would be fine since all
            use of LocalStorage is blocked on the import completing, so you'd never hit a
            quota error in the mean time.  Also, if embedders wanted to ask the user
            whether to expand the quota whenever it's hit (before deciding whether or not
            to raise an exception), a callback via the chrome client should be fairly easy.
            That said, I think it's best to add these features in steps rather than one
            huge patch.  (Both of these are on my TODO list, btw.)
    
            Included is a layout test that verifies the behavior.  It assumes the default
            quota is 5mb (since that's what Settings defaults to).
    
            Test: storage/domstorage/localstorage/quota.html
    
            * page/PageGroup.cpp:
            (WebCore::PageGroup::localStorage):
            * page/Settings.cpp:
            (WebCore::Settings::Settings):
            (WebCore::Settings::setLocalStorageQuota):
            * page/Settings.h:
            (WebCore::Settings::localStorageQuota):
            * storage/StorageAreaImpl.cpp:
            (WebCore::StorageAreaImpl::create):
            (WebCore::StorageAreaImpl::StorageAreaImpl):
            (WebCore::StorageAreaImpl::setItem):
            (WebCore::StorageAreaImpl::clear):
            * storage/StorageAreaImpl.h:
            * storage/StorageMap.cpp:
            (WebCore::StorageMap::create):
            (WebCore::StorageMap::StorageMap):
            (WebCore::StorageMap::copy):
            (WebCore::StorageMap::setItem):
            (WebCore::StorageMap::removeItem):
            (WebCore::StorageMap::importItem):
            * storage/StorageMap.h:
            (WebCore::StorageMap::quota):
            * storage/StorageNamespace.cpp:
            (WebCore::StorageNamespace::localStorageNamespace):
            * storage/StorageNamespace.h:
            * storage/StorageNamespaceImpl.cpp:
            (WebCore::StorageNamespaceImpl::localStorageNamespace):
            (WebCore::StorageNamespaceImpl::sessionStorageNamespace):
            (WebCore::StorageNamespaceImpl::StorageNamespaceImpl):
            (WebCore::StorageNamespaceImpl::copy):
            (WebCore::StorageNamespaceImpl::storageArea):
            * storage/StorageNamespaceImpl.h:
    2009-10-02  Jeremy Orlow  <jorlow at chromium.org>
    
            Reviewed by Dimitri Glazkov.
    
            Implement per-storage-area quotas for LocalStorage
            https://bugs.webkit.org/show_bug.cgi?id=29991
    
            I put 90% of the code in StorageMap since the decision to allow an update is
            closely tied to quota tracking.  The quota is set via a page's Settings class.
            Like with the local storage path and whether it's enabled, it's assumed that
            all pages in the same group will have the same settings.  The setting defaults
            to 5mb which is what the spec suggests, but it can easily be changed to
            anything else--including StorageMap::noQuota.  Any values in LocalStorage are
            grandfathered in regarudless of quota, so importItem only tracks (and will
            never block) imports.
    
            I believe this change is a good transition to more complex quota management.
            For example, if we wanted to track quotas in the SQLite DB, then we'd just add
            a function to the StorageMap that sets the quota.  This would be fine since all
            use of LocalStorage is blocked on the import completing, so you'd never hit a
            quota error in the mean time.  Also, if embedders wanted to ask the user
            whether to expand the quota whenever it's hit (before deciding whether or not
            to raise an exception), a callback via the chrome client should be fairly easy.
            That said, I think it's best to add these features in steps rather than one
            huge patch.  (Both of these are on my TODO list, btw.)
    
            Included is a layout test that verifies the behavior.  It assumes the default
            quota is 5mb (since that's what Settings defaults to).
    
            * storage/domstorage/localstorage/quota-expected.txt: Added.
            * storage/domstorage/localstorage/quota.html: Added.
            * storage/domstorage/script-tests/quota.js: Added.
            (runTest):
    
    
    git-svn-id: http://svn.webkit.org/repository/webkit/trunk@49040 268f45cc-cd09-0410-ab3c-d52691b4dbfc

diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index cfbfb8b..a0c1cf2 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,37 @@
+2009-10-02  Jeremy Orlow  <jorlow at chromium.org>
+
+        Reviewed by Dimitri Glazkov.
+
+        Implement per-storage-area quotas for LocalStorage
+        https://bugs.webkit.org/show_bug.cgi?id=29991
+
+        I put 90% of the code in StorageMap since the decision to allow an update is
+        closely tied to quota tracking.  The quota is set via a page's Settings class. 
+        Like with the local storage path and whether it's enabled, it's assumed that
+        all pages in the same group will have the same settings.  The setting defaults
+        to 5mb which is what the spec suggests, but it can easily be changed to
+        anything else--including StorageMap::noQuota.  Any values in LocalStorage are
+        grandfathered in regarudless of quota, so importItem only tracks (and will
+        never block) imports.
+
+        I believe this change is a good transition to more complex quota management. 
+        For example, if we wanted to track quotas in the SQLite DB, then we'd just add
+        a function to the StorageMap that sets the quota.  This would be fine since all
+        use of LocalStorage is blocked on the import completing, so you'd never hit a
+        quota error in the mean time.  Also, if embedders wanted to ask the user
+        whether to expand the quota whenever it's hit (before deciding whether or not
+        to raise an exception), a callback via the chrome client should be fairly easy.
+        That said, I think it's best to add these features in steps rather than one
+        huge patch.  (Both of these are on my TODO list, btw.)
+
+        Included is a layout test that verifies the behavior.  It assumes the default
+        quota is 5mb (since that's what Settings defaults to).
+
+        * storage/domstorage/localstorage/quota-expected.txt: Added.
+        * storage/domstorage/localstorage/quota.html: Added.
+        * storage/domstorage/script-tests/quota.js: Added.
+        (runTest):
+
 2009-10-02  Kenneth Russell  <kbr at google.com>
 
         Reviewed by Oliver Hunt.
diff --git a/LayoutTests/storage/domstorage/localstorage/quota-expected.txt b/LayoutTests/storage/domstorage/localstorage/quota-expected.txt
new file mode 100644
index 0000000..65715ec
--- /dev/null
+++ b/LayoutTests/storage/domstorage/localstorage/quota-expected.txt
@@ -0,0 +1,22 @@
+Test whether the quota is doing its job.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Testing window.localStorage
+storage.clear()
+PASS storage.length is 0
+Creating 'data' which contains 64K of data
+PASS data.length is 65536
+Putting 'data' into 40 window.localStorage buckets.
+Putting 'data' into another bucket.h
+PASS Hit exception as expected
+Verify that data was never inserted.
+PASS storage.getItem(40) is null
+Removing bucket 39.
+Adding 'Hello!' into a new bucket.
+PASS Insertion worked.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/storage/domstorage/localstorage/quota.html b/LayoutTests/storage/domstorage/localstorage/quota.html
new file mode 100644
index 0000000..392b849
--- /dev/null
+++ b/LayoutTests/storage/domstorage/localstorage/quota.html
@@ -0,0 +1,15 @@
+<html>
+<head>
+<link rel="stylesheet" href="../../../fast/js/resources/js-test-style.css">
+<script src="../../../fast/js/resources/js-test-pre.js"></script>
+</head>
+<body>
+<p id="description"></p>
+<div id="console"></div>
+<script src="../script-tests/quota.js"></script>
+<script>
+runTest("window.localStorage");
+</script>
+<script src="../../../fast/js/resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/storage/domstorage/script-tests/quota.js b/LayoutTests/storage/domstorage/script-tests/quota.js
new file mode 100644
index 0000000..b383871
--- /dev/null
+++ b/LayoutTests/storage/domstorage/script-tests/quota.js
@@ -0,0 +1,49 @@
+description("Test whether the quota is doing its job.");
+
+function runTest(storageString)
+{
+    storage = eval(storageString);
+    if (!storage) {
+        testFailed(storageString + " DOES NOT exist");
+        return;
+    }
+
+    debug("Testing " + storageString);
+
+    evalAndLog("storage.clear()");
+    shouldBe("storage.length", "0");
+
+    debug("Creating 'data' which contains 64K of data");
+    data = "X";
+    for (var i=0; i<16; i++)
+        data += data;
+    shouldBe("data.length", "65536");
+
+    debug("Putting 'data' into 40 " + storageString + " buckets.");
+    for (var i=0; i<40; i++)
+        storage[i] = data;
+
+    debug("Putting 'data' into another bucket.h");
+    try {
+        storage[40] = data;
+        testFailed("Did not hit quota error.");
+    } catch (e) {
+        testPassed("Hit exception as expected");
+    }
+
+    debug("Verify that data was never inserted.");
+    shouldBeNull("storage.getItem(40)");
+
+    debug("Removing bucket 39.");
+    storage.removeItem('39');
+
+    debug("Adding 'Hello!' into a new bucket.");
+    try {
+        storage['foo'] = "Hello!";
+        testPassed("Insertion worked.");
+    } catch (e) {
+        testFailed("Exception: " + e);
+    }
+
+    window.successfullyParsed = true;
+}
diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog
index 0ae8823..c235644 100644
--- a/WebCore/ChangeLog
+++ b/WebCore/ChangeLog
@@ -1,3 +1,67 @@
+2009-10-02  Jeremy Orlow  <jorlow at chromium.org>
+
+        Reviewed by Dimitri Glazkov.
+
+        Implement per-storage-area quotas for LocalStorage
+        https://bugs.webkit.org/show_bug.cgi?id=29991
+
+        I put 90% of the code in StorageMap since the decision to allow an update is
+        closely tied to quota tracking.  The quota is set via a page's Settings class.
+        Like with the local storage path and whether it's enabled, it's assumed that
+        all pages in the same group will have the same settings.  The setting defaults
+        to 5mb which is what the spec suggests, but it can easily be changed to
+        anything else--including StorageMap::noQuota.  Any values in LocalStorage are
+        grandfathered in regarudless of quota, so importItem only tracks (and will
+        never block) imports.
+
+        I believe this change is a good transition to more complex quota management.
+        For example, if we wanted to track quotas in the SQLite DB, then we'd just add
+        a function to the StorageMap that sets the quota.  This would be fine since all
+        use of LocalStorage is blocked on the import completing, so you'd never hit a
+        quota error in the mean time.  Also, if embedders wanted to ask the user
+        whether to expand the quota whenever it's hit (before deciding whether or not
+        to raise an exception), a callback via the chrome client should be fairly easy.
+        That said, I think it's best to add these features in steps rather than one
+        huge patch.  (Both of these are on my TODO list, btw.)
+
+        Included is a layout test that verifies the behavior.  It assumes the default
+        quota is 5mb (since that's what Settings defaults to).
+
+        Test: storage/domstorage/localstorage/quota.html
+
+        * page/PageGroup.cpp:
+        (WebCore::PageGroup::localStorage):
+        * page/Settings.cpp:
+        (WebCore::Settings::Settings):
+        (WebCore::Settings::setLocalStorageQuota):
+        * page/Settings.h:
+        (WebCore::Settings::localStorageQuota):
+        * storage/StorageAreaImpl.cpp:
+        (WebCore::StorageAreaImpl::create):
+        (WebCore::StorageAreaImpl::StorageAreaImpl):
+        (WebCore::StorageAreaImpl::setItem):
+        (WebCore::StorageAreaImpl::clear):
+        * storage/StorageAreaImpl.h:
+        * storage/StorageMap.cpp:
+        (WebCore::StorageMap::create):
+        (WebCore::StorageMap::StorageMap):
+        (WebCore::StorageMap::copy):
+        (WebCore::StorageMap::setItem):
+        (WebCore::StorageMap::removeItem):
+        (WebCore::StorageMap::importItem):
+        * storage/StorageMap.h:
+        (WebCore::StorageMap::quota):
+        * storage/StorageNamespace.cpp:
+        (WebCore::StorageNamespace::localStorageNamespace):
+        * storage/StorageNamespace.h:
+        * storage/StorageNamespaceImpl.cpp:
+        (WebCore::StorageNamespaceImpl::localStorageNamespace):
+        (WebCore::StorageNamespaceImpl::sessionStorageNamespace):
+        (WebCore::StorageNamespaceImpl::StorageNamespaceImpl):
+        (WebCore::StorageNamespaceImpl::copy):
+        (WebCore::StorageNamespaceImpl::storageArea):
+        * storage/StorageNamespaceImpl.h:
+
 2009-10-02  Joseph Pecoraro  <joepeck at webkit.org>
 
         Reviewed by Timothy Hatcher.
diff --git a/WebCore/page/PageGroup.cpp b/WebCore/page/PageGroup.cpp
index 6b638f1..cf6ba37 100644
--- a/WebCore/page/PageGroup.cpp
+++ b/WebCore/page/PageGroup.cpp
@@ -191,8 +191,9 @@ StorageNamespace* PageGroup::localStorage()
     if (!m_localStorage) {
         // Need a page in this page group to query the settings for the local storage database path.
         Page* page = *m_pages.begin();
-        ASSERT(page);
-        m_localStorage = StorageNamespace::localStorageNamespace(page->settings()->localStorageDatabasePath());
+        const String& path = page->settings()->localStorageDatabasePath();
+        unsigned quota = page->settings()->localStorageQuota();
+        m_localStorage = StorageNamespace::localStorageNamespace(path, quota);
     }
 
     return m_localStorage.get();
diff --git a/WebCore/page/Settings.cpp b/WebCore/page/Settings.cpp
index 16295d2..672fcab 100644
--- a/WebCore/page/Settings.cpp
+++ b/WebCore/page/Settings.cpp
@@ -61,6 +61,7 @@ Settings::Settings(Page* page)
     , m_defaultFontSize(0)
     , m_defaultFixedFontSize(0)
     , m_maximumDecodedImageSize(numeric_limits<size_t>::max())
+    , m_localStorageQuota(5 * 1024 * 1024)  // Suggested by the HTML5 spec.
     , m_pluginAllowedRunTime(numeric_limits<unsigned>::max())
     , m_isJavaEnabled(false)
     , m_loadsImagesAutomatically(false)
@@ -262,6 +263,11 @@ void Settings::setSessionStorageEnabled(bool sessionStorageEnabled)
     m_sessionStorageEnabled = sessionStorageEnabled;
 }
 
+void Settings::setLocalStorageQuota(unsigned localStorageQuota)
+{
+    m_localStorageQuota = localStorageQuota;
+}
+
 void Settings::setPrivateBrowsingEnabled(bool privateBrowsingEnabled)
 {
     m_privateBrowsingEnabled = privateBrowsingEnabled;
diff --git a/WebCore/page/Settings.h b/WebCore/page/Settings.h
index cb7b1c2..d1de963 100644
--- a/WebCore/page/Settings.h
+++ b/WebCore/page/Settings.h
@@ -128,6 +128,9 @@ namespace WebCore {
         void setSessionStorageEnabled(bool);
         bool sessionStorageEnabled() const { return m_sessionStorageEnabled; }
 
+        void setLocalStorageQuota(unsigned);
+        unsigned localStorageQuota() const { return m_localStorageQuota; }
+
         void setPrivateBrowsingEnabled(bool);
         bool privateBrowsingEnabled() const { return m_privateBrowsingEnabled; }
 
@@ -295,6 +298,7 @@ namespace WebCore {
         int m_defaultFontSize;
         int m_defaultFixedFontSize;
         size_t m_maximumDecodedImageSize;
+        unsigned m_localStorageQuota;
         unsigned m_pluginAllowedRunTime;
         bool m_isJavaEnabled : 1;
         bool m_loadsImagesAutomatically : 1;
diff --git a/WebCore/storage/StorageAreaImpl.cpp b/WebCore/storage/StorageAreaImpl.cpp
index 020e2b8..612cb5f 100644
--- a/WebCore/storage/StorageAreaImpl.cpp
+++ b/WebCore/storage/StorageAreaImpl.cpp
@@ -43,15 +43,15 @@ StorageAreaImpl::~StorageAreaImpl()
     ASSERT(isMainThread());
 }
 
-PassRefPtr<StorageAreaImpl> StorageAreaImpl::create(StorageType storageType, PassRefPtr<SecurityOrigin> origin, PassRefPtr<StorageSyncManager> syncManager)
+PassRefPtr<StorageAreaImpl> StorageAreaImpl::create(StorageType storageType, PassRefPtr<SecurityOrigin> origin, PassRefPtr<StorageSyncManager> syncManager, unsigned quota)
 {
-    return adoptRef(new StorageAreaImpl(storageType, origin, syncManager));
+    return adoptRef(new StorageAreaImpl(storageType, origin, syncManager, quota));
 }
 
-StorageAreaImpl::StorageAreaImpl(StorageType storageType, PassRefPtr<SecurityOrigin> origin, PassRefPtr<StorageSyncManager> syncManager)
+StorageAreaImpl::StorageAreaImpl(StorageType storageType, PassRefPtr<SecurityOrigin> origin, PassRefPtr<StorageSyncManager> syncManager, unsigned quota)
     : m_storageType(storageType)
     , m_securityOrigin(origin)
-    , m_storageMap(StorageMap::create())
+    , m_storageMap(StorageMap::create(quota))
     , m_storageSyncManager(syncManager)
 #ifndef NDEBUG
     , m_isShutdown(false)
@@ -135,15 +135,14 @@ void StorageAreaImpl::setItem(const String& key, const String& value, ExceptionC
         return;
     }
 
-    // FIXME: For LocalStorage where a disk quota will be enforced, here is where we need to do quota checking.
-    //        If we decide to enforce a memory quota for SessionStorage, this is where we'd do that, also.
-    // if (<over quota>) {
-    //     ec = QUOTA_EXCEEDED_ERR;
-    //     return;
-    // }
-
     String oldValue;
-    RefPtr<StorageMap> newMap = m_storageMap->setItem(key, value, oldValue);
+    bool quotaException;
+    RefPtr<StorageMap> newMap = m_storageMap->setItem(key, value, oldValue, quotaException);
+
+    if (quotaException) {
+        ec = QUOTA_EXCEEDED_ERR;
+        return;
+    }
 
     if (newMap)
         m_storageMap = newMap.release();
@@ -185,7 +184,8 @@ void StorageAreaImpl::clear(Frame* frame)
     if (privateBrowsingEnabled(frame))
         return;
 
-    m_storageMap = StorageMap::create();
+    unsigned quota = m_storageMap->quota();
+    m_storageMap = StorageMap::create(quota);
 
     if (m_storageAreaSync)
         m_storageAreaSync->scheduleClear();
diff --git a/WebCore/storage/StorageAreaImpl.h b/WebCore/storage/StorageAreaImpl.h
index 4f0907d..fe21a45 100644
--- a/WebCore/storage/StorageAreaImpl.h
+++ b/WebCore/storage/StorageAreaImpl.h
@@ -41,7 +41,7 @@ namespace WebCore {
 
     class StorageAreaImpl : public StorageArea {
     public:
-        static PassRefPtr<StorageAreaImpl> create(StorageType, PassRefPtr<SecurityOrigin>, PassRefPtr<StorageSyncManager>);
+        static PassRefPtr<StorageAreaImpl> create(StorageType, PassRefPtr<SecurityOrigin>, PassRefPtr<StorageSyncManager>, unsigned quota);
         virtual ~StorageAreaImpl();
 
         // The HTML5 DOM Storage API (and contains)
@@ -61,7 +61,7 @@ namespace WebCore {
         SecurityOrigin* securityOrigin();
 
     private:
-        StorageAreaImpl(StorageType, PassRefPtr<SecurityOrigin>, PassRefPtr<StorageSyncManager>);
+        StorageAreaImpl(StorageType, PassRefPtr<SecurityOrigin>, PassRefPtr<StorageSyncManager>, unsigned quota);
         StorageAreaImpl(StorageAreaImpl*);
 
         void blockUntilImportComplete() const;
diff --git a/WebCore/storage/StorageMap.cpp b/WebCore/storage/StorageMap.cpp
index 85cff16..ed91c8c 100644
--- a/WebCore/storage/StorageMap.cpp
+++ b/WebCore/storage/StorageMap.cpp
@@ -30,20 +30,22 @@
 
 namespace WebCore {
 
-PassRefPtr<StorageMap> StorageMap::create()
+PassRefPtr<StorageMap> StorageMap::create(unsigned quota)
 {
-    return adoptRef(new StorageMap);
+    return adoptRef(new StorageMap(quota));
 }
 
-StorageMap::StorageMap()
+StorageMap::StorageMap(unsigned quota)
     : m_iterator(m_map.end())
     , m_iteratorIndex(UINT_MAX)
+    , m_quotaSize(quota)  // quota measured in bytes
+    , m_currentLength(0)
 {
 }
 
 PassRefPtr<StorageMap> StorageMap::copy()
 {
-    RefPtr<StorageMap> newMap = create();
+    RefPtr<StorageMap> newMap = create(m_quotaSize);
     newMap->m_map = m_map;
     return newMap.release();
 }
@@ -96,27 +98,34 @@ String StorageMap::getItem(const String& key) const
     return m_map.get(key);
 }
 
-PassRefPtr<StorageMap> StorageMap::setItem(const String& key, const String& value, String& oldValue)
+PassRefPtr<StorageMap> StorageMap::setItem(const String& key, const String& value, String& oldValue, bool& quotaException)
 {
     ASSERT(!value.isNull());
+    quotaException = false;
 
     // Implement copy-on-write semantics here.  We're guaranteed that the only refs of StorageMaps belong to Storage objects
     // so if more than one Storage object refs this map, copy it before mutating it.
     if (refCount() > 1) {
         RefPtr<StorageMap> newStorageMap = copy();
-        newStorageMap->setItem(key, value, oldValue);
+        newStorageMap->setItem(key, value, oldValue, quotaException);
         return newStorageMap.release();
     }
 
-    pair<HashMap<String, String>::iterator, bool> addResult = m_map.add(key, value);
+    // Quota tracking.  If the quota is enabled and this would go over it, bail.
+    oldValue = m_map.get(key);
+    unsigned newLength = m_currentLength + value.length() - oldValue.length();
+    bool overQuota = newLength > m_quotaSize / sizeof(UChar);
+    bool overflow = (newLength > m_currentLength) != (value.length() > oldValue.length());
+    ASSERT(!overflow);  // If we're debugging, make a fuss.  But it's still worth checking this in the following if statement.
+    if (m_quotaSize != noQuota && (overflow || overQuota)) {
+        quotaException = true;
+        return 0;
+    }
+    m_currentLength = newLength;
 
-    if (addResult.second) {
-        // There was no "oldValue" so null it out.
-        oldValue = String();
-    } else {
-        oldValue = addResult.first->second;
+    pair<HashMap<String, String>::iterator, bool> addResult = m_map.add(key, value);
+    if (!addResult.second)
         addResult.first->second = value;
-    }
 
     invalidateIterator();
 
@@ -137,6 +146,10 @@ PassRefPtr<StorageMap> StorageMap::removeItem(const String& key, String& oldValu
     if (!oldValue.isNull())
         invalidateIterator();
 
+    // Update quota.
+    ASSERT(m_currentLength - oldValue.length() <= m_currentLength);
+    m_currentLength -= oldValue.length();
+
     return 0;
 }
 
@@ -153,6 +166,10 @@ void StorageMap::importItem(const String& key, const String& value)
 
     if (result.second)
         result.first->second = value.copy();
+
+    // Update quota.
+    ASSERT(m_currentLength + value.length() >= m_currentLength);
+    m_currentLength += value.length();
 }
 
 }
diff --git a/WebCore/storage/StorageMap.h b/WebCore/storage/StorageMap.h
index 5ebb265..fa5f46c 100644
--- a/WebCore/storage/StorageMap.h
+++ b/WebCore/storage/StorageMap.h
@@ -39,20 +39,25 @@ namespace WebCore {
 
     class StorageMap : public RefCounted<StorageMap> {
     public:
-        static PassRefPtr<StorageMap> create();
+        // Quota size mesured in bytes.
+        static PassRefPtr<StorageMap> create(unsigned quotaSize);
 
         unsigned length() const;
         String key(unsigned index);
         String getItem(const String&) const;
-        PassRefPtr<StorageMap> setItem(const String& key, const String& value, String& oldValue);
+        PassRefPtr<StorageMap> setItem(const String& key, const String& value, String& oldValue, bool& quota_exception);
         PassRefPtr<StorageMap> removeItem(const String&, String& oldValue);
 
         bool contains(const String& key) const;
 
         void importItem(const String& key, const String& value);
 
+        unsigned quota() const { return m_quotaSize; }
+
+        static const unsigned noQuota = UINT_MAX;
+
     private:
-        StorageMap();
+        StorageMap(unsigned quota);
         PassRefPtr<StorageMap> copy();
         void invalidateIterator();
         void setIteratorToIndex(unsigned);
@@ -60,6 +65,9 @@ namespace WebCore {
         HashMap<String, String> m_map;
         HashMap<String, String>::iterator m_iterator;
         unsigned m_iteratorIndex;
+
+        unsigned m_quotaSize;  // Measured in bytes.
+        unsigned m_currentLength;  // Measured in UChars.
     };
 
 } // namespace WebCore
diff --git a/WebCore/storage/StorageNamespace.cpp b/WebCore/storage/StorageNamespace.cpp
index 6fcae63..6b8caeb 100644
--- a/WebCore/storage/StorageNamespace.cpp
+++ b/WebCore/storage/StorageNamespace.cpp
@@ -36,9 +36,9 @@
 
 namespace WebCore {
 
-PassRefPtr<StorageNamespace> StorageNamespace::localStorageNamespace(const String& path)
+PassRefPtr<StorageNamespace> StorageNamespace::localStorageNamespace(const String& path, unsigned quota)
 {
-    return StorageNamespaceImpl::localStorageNamespace(path);
+    return StorageNamespaceImpl::localStorageNamespace(path, quota);
 }
 
 PassRefPtr<StorageNamespace> StorageNamespace::sessionStorageNamespace()
diff --git a/WebCore/storage/StorageNamespace.h b/WebCore/storage/StorageNamespace.h
index 6866746..0ac5f86 100644
--- a/WebCore/storage/StorageNamespace.h
+++ b/WebCore/storage/StorageNamespace.h
@@ -41,7 +41,7 @@ namespace WebCore {
     // This interface is required for Chromium since these actions need to be proxied between processes.
     class StorageNamespace : public RefCounted<StorageNamespace> {
     public:
-        static PassRefPtr<StorageNamespace> localStorageNamespace(const String& path);
+        static PassRefPtr<StorageNamespace> localStorageNamespace(const String& path, unsigned quota);
         static PassRefPtr<StorageNamespace> sessionStorageNamespace();
 
         virtual ~StorageNamespace() { }
diff --git a/WebCore/storage/StorageNamespaceImpl.cpp b/WebCore/storage/StorageNamespaceImpl.cpp
index d5af31f..bc9d90c 100644
--- a/WebCore/storage/StorageNamespaceImpl.cpp
+++ b/WebCore/storage/StorageNamespaceImpl.cpp
@@ -31,6 +31,7 @@
 #include "SecurityOriginHash.h"
 #include "StringHash.h"
 #include "StorageAreaImpl.h"
+#include "StorageMap.h"
 #include "StorageSyncManager.h"
 #include <wtf/StdLibExtras.h>
 
@@ -44,12 +45,12 @@ static LocalStorageNamespaceMap& localStorageNamespaceMap()
     return localStorageNamespaceMap;
 }
 
-PassRefPtr<StorageNamespace> StorageNamespaceImpl::localStorageNamespace(const String& path)
+PassRefPtr<StorageNamespace> StorageNamespaceImpl::localStorageNamespace(const String& path, unsigned quota)
 {
     const String lookupPath = path.isNull() ? String("") : path;
     LocalStorageNamespaceMap::iterator it = localStorageNamespaceMap().find(lookupPath);
     if (it == localStorageNamespaceMap().end()) {
-        RefPtr<StorageNamespace> storageNamespace = adoptRef(new StorageNamespaceImpl(LocalStorage, lookupPath));
+        RefPtr<StorageNamespace> storageNamespace = adoptRef(new StorageNamespaceImpl(LocalStorage, lookupPath, quota));
         localStorageNamespaceMap().set(lookupPath, storageNamespace.get());
         return storageNamespace.release();
     }
@@ -59,13 +60,14 @@ PassRefPtr<StorageNamespace> StorageNamespaceImpl::localStorageNamespace(const S
 
 PassRefPtr<StorageNamespace> StorageNamespaceImpl::sessionStorageNamespace()
 {
-    return adoptRef(new StorageNamespaceImpl(SessionStorage, String()));
+    return adoptRef(new StorageNamespaceImpl(SessionStorage, String(), StorageMap::noQuota));
 }
 
-StorageNamespaceImpl::StorageNamespaceImpl(StorageType storageType, const String& path)
+StorageNamespaceImpl::StorageNamespaceImpl(StorageType storageType, const String& path, unsigned quota)
     : m_storageType(storageType)
     , m_path(path.copy())  // Copy makes it safe for our other thread to access the path.
     , m_syncManager(0)
+    , m_quota(quota)
     , m_isShutdown(false)
 {
     if (m_storageType == LocalStorage && !m_path.isEmpty())
@@ -91,7 +93,7 @@ PassRefPtr<StorageNamespace> StorageNamespaceImpl::copy()
     ASSERT(!m_isShutdown);
     ASSERT(m_storageType == SessionStorage);
 
-    StorageNamespaceImpl* newNamespace = new StorageNamespaceImpl(m_storageType, m_path);
+    StorageNamespaceImpl* newNamespace = new StorageNamespaceImpl(m_storageType, m_path, m_quota);
 
     StorageAreaMap::iterator end = m_storageAreaMap.end();
     for (StorageAreaMap::iterator i = m_storageAreaMap.begin(); i != end; ++i)
@@ -109,7 +111,7 @@ PassRefPtr<StorageArea> StorageNamespaceImpl::storageArea(PassRefPtr<SecurityOri
     if (storageArea = m_storageAreaMap.get(origin))
         return storageArea.release();
 
-    storageArea = StorageAreaImpl::create(m_storageType, origin, m_syncManager);
+    storageArea = StorageAreaImpl::create(m_storageType, origin, m_syncManager, m_quota);
     m_storageAreaMap.set(origin.release(), storageArea);
     return storageArea.release();
 }
diff --git a/WebCore/storage/StorageNamespaceImpl.h b/WebCore/storage/StorageNamespaceImpl.h
index 05a12ad..b81b55a 100644
--- a/WebCore/storage/StorageNamespaceImpl.h
+++ b/WebCore/storage/StorageNamespaceImpl.h
@@ -42,7 +42,7 @@ namespace WebCore {
 
     class StorageNamespaceImpl : public StorageNamespace {
     public:
-        static PassRefPtr<StorageNamespace> localStorageNamespace(const String& path);
+        static PassRefPtr<StorageNamespace> localStorageNamespace(const String& path, unsigned quota);
         static PassRefPtr<StorageNamespace> sessionStorageNamespace();
 
         virtual ~StorageNamespaceImpl();
@@ -52,7 +52,7 @@ namespace WebCore {
         virtual void unlock();
 
     private:
-        StorageNamespaceImpl(StorageType, const String& path);
+        StorageNamespaceImpl(StorageType, const String& path, unsigned quota);
 
         typedef HashMap<RefPtr<SecurityOrigin>, RefPtr<StorageAreaImpl>, SecurityOriginHash> StorageAreaMap;
         StorageAreaMap m_storageAreaMap;
@@ -63,6 +63,7 @@ namespace WebCore {
         String m_path;
         RefPtr<StorageSyncManager> m_syncManager;
 
+        unsigned m_quota;  // The default quota for each new storage area.
         bool m_isShutdown;
     };
 

-- 
WebKit Debian packaging



More information about the Pkg-webkit-commits mailing list