Title: [91060] trunk/Source/WebCore
Revision
91060
Author
[email protected]
Date
2011-07-15 01:35:16 -0700 (Fri, 15 Jul 2011)

Log Message

LocalStorage: Changed the value type of ItemTable from TEXT to BLOB
to avoid string truncation.
This patch will also convert the exsisting ItemTable and perform
the DATA MIGRATION job.
https://bugs.webkit.org/show_bug.cgi?id=58762

Patch by Jonathan Dong <[email protected]> on 2011-07-15
Reviewed by Jeremy Orlow.

Tests: manual-tests/localstorage-value-truncation.html

* manual-tests/localstorage-value-truncation.html: Added.
Demostrate the testcase shown in bug 58762.
* platform/sql/SQLiteStatement.cpp:
(WebCore::SQLiteStatement::isColumnDeclearedAsBlob):
Test if the pre-defined type of column is BLOB.
* platform/sql/SQLiteStatement.h:
* storage/StorageAreaSync.cpp:
Change the localStorage value type from Text to BLOB to avoid the
value string truncation at \x00.
(WebCore::StorageAreaSync::openDatabase):
Change the database structure, use BLOB to replace the TEXT type of
value segment in ItemTable.
(WebCore::StorageAreaSync::migrateItemTableIfNeeded):
Migrate the ItemTable if the pre-defined type of value is TEXT.
(WebCore::StorageAreaSync::performImport):
Use getColumnBlobAsString() to import the BLOB value.
(WebCore::StorageAreaSync::sync):
Use bindBlob() to bind value string to the SQLiteStatement for the
database execution.
* storage/StorageAreaSync.h:

Modified Paths

Added Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (91059 => 91060)


--- trunk/Source/WebCore/ChangeLog	2011-07-15 08:22:23 UTC (rev 91059)
+++ trunk/Source/WebCore/ChangeLog	2011-07-15 08:35:16 UTC (rev 91060)
@@ -1,3 +1,36 @@
+2011-07-15  Jonathan Dong  <[email protected]>
+
+        LocalStorage: Changed the value type of ItemTable from TEXT to BLOB
+        to avoid string truncation.
+        This patch will also convert the exsisting ItemTable and perform
+        the DATA MIGRATION job.
+        https://bugs.webkit.org/show_bug.cgi?id=58762
+
+        Reviewed by Jeremy Orlow.
+
+        Tests: manual-tests/localstorage-value-truncation.html
+
+        * manual-tests/localstorage-value-truncation.html: Added.
+        Demostrate the testcase shown in bug 58762.
+        * platform/sql/SQLiteStatement.cpp:
+        (WebCore::SQLiteStatement::isColumnDeclearedAsBlob):
+        Test if the pre-defined type of column is BLOB.
+        * platform/sql/SQLiteStatement.h:
+        * storage/StorageAreaSync.cpp:
+        Change the localStorage value type from Text to BLOB to avoid the
+        value string truncation at \x00.
+        (WebCore::StorageAreaSync::openDatabase):
+        Change the database structure, use BLOB to replace the TEXT type of
+        value segment in ItemTable.
+        (WebCore::StorageAreaSync::migrateItemTableIfNeeded):
+        Migrate the ItemTable if the pre-defined type of value is TEXT.
+        (WebCore::StorageAreaSync::performImport):
+        Use getColumnBlobAsString() to import the BLOB value.
+        (WebCore::StorageAreaSync::sync):
+        Use bindBlob() to bind value string to the SQLiteStatement for the
+        database execution.
+        * storage/StorageAreaSync.h:
+
 2011-07-15  Kentaro Hara  <[email protected]>
 
         Clear the content of a search input form when 'Escape' is pressed.

Added: trunk/Source/WebCore/manual-tests/localstorage-value-truncation.html (0 => 91060)


--- trunk/Source/WebCore/manual-tests/localstorage-value-truncation.html	                        (rev 0)
+++ trunk/Source/WebCore/manual-tests/localstorage-value-truncation.html	2011-07-15 08:35:16 UTC (rev 91060)
@@ -0,0 +1,31 @@
+<html>
+<body>
+    <p>In this test we need to find out if the browser can save the localStorage item correctly without truncated by the \x00 in the middle of the string.</p>
+<script type="text/_javascript_">
+    var key = 'TruncVal';
+    var value = '123\x00567';
+
+    var x = localStorage.getItem(key);
+    if (!x) {
+        localStorage.setItem(key, value);
+        document.write("<p>It hasn't got the '" + key + "' in the localStorage database, will create it using:<br>");
+        document.write("<code>localStorage.setItem('" + key + "', '" + value + "');</code><br>");
+        document.write("Now close your browser and start it again to see the results.</p>");
+    }
+    else {
+        document.write("<p>The value of " + key + " is: '" + x + "', the length is: " + x.length + "<br>");
+
+        if (x == value) {
+            document.write("PASS.");
+        }
+        else {
+            document.write("FAIL: The expected value is: '" + value + "', the expected length is: " + value.length);
+        }
+        document.write("</p><a href="" + key + "');\">remove '" + key + "' from localStorage</a>");
+    }
+</script>
+
+<p>This is for <a href=""
+</p>
+</body>
+</html>

Modified: trunk/Source/WebCore/platform/sql/SQLiteStatement.cpp (91059 => 91060)


--- trunk/Source/WebCore/platform/sql/SQLiteStatement.cpp	2011-07-15 08:22:23 UTC (rev 91059)
+++ trunk/Source/WebCore/platform/sql/SQLiteStatement.cpp	2011-07-15 08:35:16 UTC (rev 91060)
@@ -287,6 +287,17 @@
     return sqlite3_column_type(m_statement, col) == SQLITE_NULL;
 }
 
+bool SQLiteStatement::isColumnDeclaredAsBlob(int col)
+{
+    ASSERT(col >= 0);
+    if (!m_statement) {
+        if (prepare() != SQLITE_OK)
+            return false;
+    }
+
+    return equalIgnoringCase(String("BLOB"), String(reinterpret_cast<const UChar*>(sqlite3_column_decltype16(m_statement, col))));
+}
+
 String SQLiteStatement::getColumnName(int col)
 {
     ASSERT(col >= 0);

Modified: trunk/Source/WebCore/platform/sql/SQLiteStatement.h (91059 => 91060)


--- trunk/Source/WebCore/platform/sql/SQLiteStatement.h	2011-07-15 08:22:23 UTC (rev 91059)
+++ trunk/Source/WebCore/platform/sql/SQLiteStatement.h	2011-07-15 08:35:16 UTC (rev 91060)
@@ -74,6 +74,7 @@
     int columnCount();
     
     bool isColumnNull(int col);
+    bool isColumnDeclaredAsBlob(int col);
     String getColumnName(int col);
     SQLValue getColumnValue(int col);
     String getColumnText(int col);

Modified: trunk/Source/WebCore/storage/StorageAreaSync.cpp (91059 => 91060)


--- trunk/Source/WebCore/storage/StorageAreaSync.cpp	2011-07-15 08:22:23 UTC (rev 91059)
+++ trunk/Source/WebCore/storage/StorageAreaSync.cpp	2011-07-15 08:35:16 UTC (rev 91060)
@@ -33,6 +33,7 @@
 #include "HTMLElement.h"
 #include "SQLiteFileSystem.h"
 #include "SQLiteStatement.h"
+#include "SQLiteTransaction.h"
 #include "SecurityOrigin.h"
 #include "StorageAreaImpl.h"
 #include "StorageSyncManager.h"
@@ -254,7 +255,9 @@
         return;
     }
 
-    if (!m_database.executeCommand("CREATE TABLE IF NOT EXISTS ItemTable (key TEXT UNIQUE ON CONFLICT REPLACE, value TEXT NOT NULL ON CONFLICT FAIL)")) {
+    migrateItemTableIfNeeded();
+
+    if (!m_database.executeCommand("CREATE TABLE IF NOT EXISTS ItemTable (key TEXT UNIQUE ON CONFLICT REPLACE, value BLOB NOT NULL ON CONFLICT FAIL)")) {
         LOG_ERROR("Failed to create table ItemTable for local storage");
         markImported();
         m_databaseOpenFailed = true;
@@ -264,6 +267,49 @@
     StorageTracker::tracker().setOriginDetails(m_databaseIdentifier, databaseFilename);
 }
 
+void StorageAreaSync::migrateItemTableIfNeeded()
+{
+    if (!m_database.tableExists("ItemTable"))
+        return;
+
+    {
+        SQLiteStatement query(m_database, "SELECT value FROM ItemTable LIMIT 1");
+        // this query isn't ever executed.
+        if (query.isColumnDeclaredAsBlob(0))
+            return;
+    }
+
+    // alter table for backward compliance, change the value type from TEXT to BLOB.
+    static const char* commands[] = {
+        "DROP TABLE IF EXISTS ItemTable2",
+        "CREATE TABLE ItemTable2 (key TEXT UNIQUE ON CONFLICT REPLACE, value BLOB NOT NULL ON CONFLICT FAIL)",
+        "INSERT INTO ItemTable2 SELECT * from ItemTable",
+        "DROP TABLE ItemTable",
+        "ALTER TABLE ItemTable2 RENAME TO ItemTable",
+        0,
+    };
+
+    SQLiteTransaction transaction(m_database, false);
+    transaction.begin();
+    for (size_t i = 0; commands[i]; ++i) {
+        if (!m_database.executeCommand(commands[i])) {
+            LOG_ERROR("Failed to migrate table ItemTable for local storage when executing: %s", commands[i]);
+            transaction.rollback();
+
+            // finally it will try to keep a backup of ItemTable for the future restoration.
+            // NOTICE: this will essentially DELETE the current database, but that's better
+            // than continually hitting this case and never being able to use the local storage.
+            // if this is ever hit, it's definitely a bug.
+            ASSERT_NOT_REACHED();
+            if (!m_database.executeCommand("ALTER TABLE ItemTable RENAME TO Backup_ItemTable"))
+                LOG_ERROR("Failed to save ItemTable after migration job failed.");
+
+            return;
+        }
+    }
+    transaction.commit();
+}
+
 void StorageAreaSync::performImport()
 {
     ASSERT(!isMainThread());
@@ -286,7 +332,7 @@
 
     int result = query.step();
     while (result == SQLResultRow) {
-        itemMap.set(query.getColumnText(0), query.getColumnText(1));
+        itemMap.set(query.getColumnText(0), query.getColumnBlobAsString(1));
         result = query.step();
     }
 
@@ -392,7 +438,7 @@
 
         // If the second argument is non-null, we're doing an insert, so bind it as the value.
         if (!it->second.isNull())
-            query.bindText(2, it->second);
+            query.bindBlob(2, it->second);
 
         int result = query.step();
         if (result != SQLResultDone) {

Modified: trunk/Source/WebCore/storage/StorageAreaSync.h (91059 => 91060)


--- trunk/Source/WebCore/storage/StorageAreaSync.h	2011-07-15 08:22:23 UTC (rev 91059)
+++ trunk/Source/WebCore/storage/StorageAreaSync.h	2011-07-15 08:35:16 UTC (rev 91060)
@@ -102,6 +102,7 @@
         mutable ThreadCondition m_importCondition;
         mutable bool m_importComplete;
         void markImported();
+        void migrateItemTableIfNeeded();
     };
 
 } // namespace WebCore
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to