Title: [264790] trunk
Revision
264790
Author
[email protected]
Date
2020-07-23 14:21:21 -0700 (Thu, 23 Jul 2020)

Log Message

Allow IndexedDB in third-party frames
https://bugs.webkit.org/show_bug.cgi?id=214583
<rdar://problem/61278487>

Patch by Sihui Liu <[email protected]> on 2020-07-23
Reviewed by Geoffrey Garen.

Source/WebCore:

Match IndexedDB's behavior with localStorage. Third-party iframes now have access to IndexedDB with partitioned
in-memory storage. The partitioning key is ClientOrigin, which consists of opening origin and top origin.

API Test: IndexedDB.IndexedDBThirdPartyFrameHasAccess
          IndexedDB.IndexedDBThirdPartyDataRemoval
          IndexedDB.IndexedDBThirdPartyWorkerHasAccess

* Modules/indexeddb/IDBDatabaseIdentifier.cpp:
(WebCore::IDBDatabaseIdentifier::IDBDatabaseIdentifier):
(WebCore::m_isTransient):
(WebCore::IDBDatabaseIdentifier::isolatedCopy const):
(WebCore::IDBDatabaseIdentifier::loggingString const):
* Modules/indexeddb/IDBDatabaseIdentifier.h:
(WebCore::IDBDatabaseIdentifier::hash const):
(WebCore::IDBDatabaseIdentifier::operator== const):
(WebCore::IDBDatabaseIdentifier::isTransient const):
(WebCore::IDBDatabaseIdentifier::encode const):
(WebCore::IDBDatabaseIdentifier::decode):
* Modules/indexeddb/IDBFactory.cpp:
(WebCore::shouldThrowSecurityException):
(WebCore::IDBFactory::openInternal):
(WebCore::IDBFactory::deleteDatabase):
* Modules/indexeddb/server/IDBServer.cpp:
(WebCore::IDBServer::IDBServer::createBackingStore):
* Modules/webdatabase/DOMWindowWebDatabase.cpp:
(WebCore::DOMWindowWebDatabase::openDatabase):
* page/SecurityOrigin.h:
(WebCore::SecurityOrigin::canAccessDatabase const):

Source/WebKit:

Do no append extra space to displayName if host is empty.

* UIProcess/WebsiteData/WebsiteDataStore.cpp:
(WebKit::WebsiteDataStore::fetchDataAndApply):

Tools:

* TestWebKitAPI/Tests/WebKitCocoa/IndexedDBPersistence.mm:
(postResult):
(catch):

LayoutTests:

Update test expectation for new behavior.

* http/tests/security/cross-origin-indexeddb-expected.txt:
* http/tests/security/cross-origin-indexeddb.html:
* http/tests/security/cross-origin-worker-indexeddb-expected.txt:
* http/tests/security/resources/document-for-cross-origin-worker-indexeddb.html:

Modified Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (264789 => 264790)


--- trunk/LayoutTests/ChangeLog	2020-07-23 21:05:27 UTC (rev 264789)
+++ trunk/LayoutTests/ChangeLog	2020-07-23 21:21:21 UTC (rev 264790)
@@ -1,3 +1,18 @@
+2020-07-23  Sihui Liu  <[email protected]>
+
+        Allow IndexedDB in third-party frames
+        https://bugs.webkit.org/show_bug.cgi?id=214583
+        <rdar://problem/61278487>
+
+        Reviewed by Geoffrey Garen.
+
+        Update test expectation for new behavior.
+
+        * http/tests/security/cross-origin-indexeddb-expected.txt:
+        * http/tests/security/cross-origin-indexeddb.html:
+        * http/tests/security/cross-origin-worker-indexeddb-expected.txt:
+        * http/tests/security/resources/document-for-cross-origin-worker-indexeddb.html:
+
 2020-07-23  Yusuke Suzuki  <[email protected]>
 
         Add exception check for WebCore createRejectedPromiseWithTypeError

Modified: trunk/LayoutTests/http/tests/security/cross-origin-indexeddb-expected.txt (264789 => 264790)


--- trunk/LayoutTests/http/tests/security/cross-origin-indexeddb-expected.txt	2020-07-23 21:05:27 UTC (rev 264789)
+++ trunk/LayoutTests/http/tests/security/cross-origin-indexeddb-expected.txt	2020-07-23 21:21:21 UTC (rev 264790)
@@ -1,4 +1,4 @@
-The first iframe below should return a security error, and the second should successfully open the database.
+Both frames can successfully open the database.
 
   
 
@@ -5,8 +5,8 @@
 --------
 Frame: '<!--frame1-->'
 --------
-window.indexedDB.deleteDatabase() threw an exception: SecurityError
-window.indexedDB.open() threw an exception: SecurityError
+Successfully called window.indexedDB.deleteDatabase().
+Successfully called window.indexedDB.open().
 
 
 --------

Modified: trunk/LayoutTests/http/tests/security/cross-origin-indexeddb.html (264789 => 264790)


--- trunk/LayoutTests/http/tests/security/cross-origin-indexeddb.html	2020-07-23 21:05:27 UTC (rev 264789)
+++ trunk/LayoutTests/http/tests/security/cross-origin-indexeddb.html	2020-07-23 21:21:21 UTC (rev 264790)
@@ -17,7 +17,7 @@
     </script>
 </head>
 <body>
-    <p>The first iframe below should return a security error, and the second should successfully open the database.</p>
+    <p>Both frames can successfully open the database.</p>
     <iframe src="" _onload_="decrement()"></iframe>
     <iframe src="" _onload_="decrement()"></iframe>
 </body>

Modified: trunk/LayoutTests/http/tests/security/cross-origin-worker-indexeddb-expected.txt (264789 => 264790)


--- trunk/LayoutTests/http/tests/security/cross-origin-worker-indexeddb-expected.txt	2020-07-23 21:05:27 UTC (rev 264789)
+++ trunk/LayoutTests/http/tests/security/cross-origin-worker-indexeddb-expected.txt	2020-07-23 21:21:21 UTC (rev 264790)
@@ -1,4 +1,4 @@
-The first iframe below should return a security error, and the second should successfully open the database.
+Both frames can successfully open the database.
 
   
 
@@ -5,8 +5,8 @@
 --------
 Frame: '<!--frame1-->'
 --------
-self.indexedDB.deleteDatabase() threw an exception: SecurityError
-self.indexedDB.open() threw an exception: SecurityError
+Successfully called self.indexedDB.deleteDatabase().
+Successfully called self.indexedDB.open().
 
 
 --------

Modified: trunk/LayoutTests/http/tests/security/resources/document-for-cross-origin-worker-indexeddb.html (264789 => 264790)


--- trunk/LayoutTests/http/tests/security/resources/document-for-cross-origin-worker-indexeddb.html	2020-07-23 21:05:27 UTC (rev 264789)
+++ trunk/LayoutTests/http/tests/security/resources/document-for-cross-origin-worker-indexeddb.html	2020-07-23 21:21:21 UTC (rev 264790)
@@ -19,7 +19,7 @@
 </script>
 </head>
 <body>
-    <p>The first iframe below should return a security error, and the second should successfully open the database.</p>
+    <p>Both frames can successfully open the database.</p>
     <iframe src=""
     <iframe src=""
 </body>

Modified: trunk/Source/WebCore/ChangeLog (264789 => 264790)


--- trunk/Source/WebCore/ChangeLog	2020-07-23 21:05:27 UTC (rev 264789)
+++ trunk/Source/WebCore/ChangeLog	2020-07-23 21:21:21 UTC (rev 264790)
@@ -1,3 +1,40 @@
+2020-07-23  Sihui Liu  <[email protected]>
+
+        Allow IndexedDB in third-party frames
+        https://bugs.webkit.org/show_bug.cgi?id=214583
+        <rdar://problem/61278487>
+
+        Reviewed by Geoffrey Garen.
+
+        Match IndexedDB's behavior with localStorage. Third-party iframes now have access to IndexedDB with partitioned
+        in-memory storage. The partitioning key is ClientOrigin, which consists of opening origin and top origin.
+
+        API Test: IndexedDB.IndexedDBThirdPartyFrameHasAccess
+                  IndexedDB.IndexedDBThirdPartyDataRemoval
+                  IndexedDB.IndexedDBThirdPartyWorkerHasAccess
+
+        * Modules/indexeddb/IDBDatabaseIdentifier.cpp:
+        (WebCore::IDBDatabaseIdentifier::IDBDatabaseIdentifier):
+        (WebCore::m_isTransient):
+        (WebCore::IDBDatabaseIdentifier::isolatedCopy const):
+        (WebCore::IDBDatabaseIdentifier::loggingString const):
+        * Modules/indexeddb/IDBDatabaseIdentifier.h:
+        (WebCore::IDBDatabaseIdentifier::hash const):
+        (WebCore::IDBDatabaseIdentifier::operator== const):
+        (WebCore::IDBDatabaseIdentifier::isTransient const):
+        (WebCore::IDBDatabaseIdentifier::encode const):
+        (WebCore::IDBDatabaseIdentifier::decode):
+        * Modules/indexeddb/IDBFactory.cpp:
+        (WebCore::shouldThrowSecurityException):
+        (WebCore::IDBFactory::openInternal):
+        (WebCore::IDBFactory::deleteDatabase):
+        * Modules/indexeddb/server/IDBServer.cpp:
+        (WebCore::IDBServer::IDBServer::createBackingStore):
+        * Modules/webdatabase/DOMWindowWebDatabase.cpp:
+        (WebCore::DOMWindowWebDatabase::openDatabase):
+        * page/SecurityOrigin.h:
+        (WebCore::SecurityOrigin::canAccessDatabase const):
+
 2020-07-23  Chris Dumez  <[email protected]>
 
         Add support for SVGAElement's rel / relList attributes

Modified: trunk/Source/WebCore/Modules/indexeddb/IDBDatabaseIdentifier.cpp (264789 => 264790)


--- trunk/Source/WebCore/Modules/indexeddb/IDBDatabaseIdentifier.cpp	2020-07-23 21:05:27 UTC (rev 264789)
+++ trunk/Source/WebCore/Modules/indexeddb/IDBDatabaseIdentifier.cpp	2020-07-23 21:21:21 UTC (rev 264790)
@@ -35,9 +35,10 @@
 
 namespace WebCore {
 
-IDBDatabaseIdentifier::IDBDatabaseIdentifier(const String& databaseName, SecurityOriginData&& openingOrigin, SecurityOriginData&& mainFrameOrigin)
+IDBDatabaseIdentifier::IDBDatabaseIdentifier(const String& databaseName, SecurityOriginData&& openingOrigin, SecurityOriginData&& mainFrameOrigin, bool isTransient)
     : m_databaseName(databaseName)
     , m_origin { WTFMove(openingOrigin), WTFMove(mainFrameOrigin) }
+    , m_isTransient(isTransient)
 {
     // The empty string is a valid database name, but a null string is not.
     ASSERT(!databaseName.isNull());
@@ -49,6 +50,7 @@
 
     identifier.m_databaseName = m_databaseName.isolatedCopy();
     identifier.m_origin = m_origin.isolatedCopy();
+    identifier.m_isTransient = m_isTransient;
 
     return identifier;
 }
@@ -73,7 +75,7 @@
 #if !LOG_DISABLED
 String IDBDatabaseIdentifier::loggingString() const
 {
-    return makeString(m_databaseName, "@", m_origin.topOrigin.debugString(), ":", m_origin.clientOrigin.debugString());
+    return makeString(m_databaseName, "@", m_origin.topOrigin.debugString(), ":", m_origin.clientOrigin.debugString(), m_isTransient ? ", transient" : "");
 }
 #endif
 

Modified: trunk/Source/WebCore/Modules/indexeddb/IDBDatabaseIdentifier.h (264789 => 264790)


--- trunk/Source/WebCore/Modules/indexeddb/IDBDatabaseIdentifier.h	2020-07-23 21:05:27 UTC (rev 264789)
+++ trunk/Source/WebCore/Modules/indexeddb/IDBDatabaseIdentifier.h	2020-07-23 21:21:21 UTC (rev 264790)
@@ -44,7 +44,7 @@
     {
     }
 
-    WEBCORE_EXPORT IDBDatabaseIdentifier(const String& databaseName, SecurityOriginData&& openingOrigin, SecurityOriginData&& mainFrameOrigin);
+    WEBCORE_EXPORT IDBDatabaseIdentifier(const String& databaseName, SecurityOriginData&& openingOrigin, SecurityOriginData&& mainFrameOrigin, bool isTransient = false);
 
     IDBDatabaseIdentifier isolatedCopy() const;
 
@@ -57,8 +57,9 @@
     {
         unsigned nameHash = StringHash::hash(m_databaseName);
         unsigned originHash = m_origin.hash();
+        unsigned transientHash = m_isTransient;
 
-        unsigned hashCodes[2] = { nameHash, originHash };
+        unsigned hashCodes[3] = { nameHash, originHash, transientHash };
         return StringHasher::hashMemory<sizeof(hashCodes)>(hashCodes);
     }
 
@@ -75,11 +76,12 @@
 
     bool operator==(const IDBDatabaseIdentifier& other) const
     {
-        return other.m_databaseName == m_databaseName && other.m_origin == m_origin;
+        return other.m_databaseName == m_databaseName && other.m_origin == m_origin && other.m_isTransient == m_isTransient;
     }
 
     const String& databaseName() const { return m_databaseName; }
     const ClientOrigin& origin() const { return m_origin; }
+    bool isTransient() const { return m_isTransient; }
 
     String databaseDirectoryRelativeToRoot(const String& rootDirectory, const String& versionString="v1") const;
     static String databaseDirectoryRelativeToRoot(const SecurityOriginData& topLevelOrigin, const SecurityOriginData& openingOrigin, const String& rootDirectory, const String& versionString);
@@ -96,6 +98,7 @@
 private:
     String m_databaseName;
     ClientOrigin m_origin;
+    bool m_isTransient { false };
 };
 
 struct IDBDatabaseIdentifierHash {
@@ -113,7 +116,7 @@
 template<class Encoder>
 void IDBDatabaseIdentifier::encode(Encoder& encoder) const
 {
-    encoder << m_databaseName << m_origin;
+    encoder << m_databaseName << m_origin << m_isTransient;
 }
 
 template<class Decoder>
@@ -129,9 +132,15 @@
     if (!origin)
         return WTF::nullopt;
 
+    Optional<bool> isTransient;
+    decoder >> isTransient;
+    if (!isTransient)
+        return WTF::nullopt;
+
     IDBDatabaseIdentifier identifier;
     identifier.m_databaseName = WTFMove(*databaseName); // FIXME: When decoding from IPC, databaseName can be null, and the non-empty constructor asserts that this is not the case.
     identifier.m_origin = WTFMove(*origin);
+    identifier.m_isTransient = *isTransient;
     return identifier;
 }
 

Modified: trunk/Source/WebCore/Modules/indexeddb/IDBFactory.cpp (264789 => 264790)


--- trunk/Source/WebCore/Modules/indexeddb/IDBFactory.cpp	2020-07-23 21:05:27 UTC (rev 264789)
+++ trunk/Source/WebCore/Modules/indexeddb/IDBFactory.cpp	2020-07-23 21:21:21 UTC (rev 264790)
@@ -54,7 +54,7 @@
             return true;
     }
 
-    if (!context.securityOrigin()->canAccessDatabase(context.topOrigin()))
+    if (!context.securityOrigin()->canAccessDatabase(nullptr))
         return true;
 
     return false;
@@ -91,7 +91,8 @@
         return Exception { SecurityError, "IDBFactory.open() called in an invalid security context"_s };
 
     ASSERT(context.securityOrigin());
-    IDBDatabaseIdentifier databaseIdentifier(name, SecurityOriginData { context.securityOrigin()->data() }, SecurityOriginData { context.topOrigin().data() });
+    bool isTransient = !context.securityOrigin()->canAccessDatabase(&context.topOrigin());
+    IDBDatabaseIdentifier databaseIdentifier(name, SecurityOriginData { context.securityOrigin()->data() }, SecurityOriginData { context.topOrigin().data() }, isTransient);
     if (!databaseIdentifier.isValid())
         return Exception { TypeError, "IDBFactory.open() called with an invalid security origin"_s };
 
@@ -111,7 +112,8 @@
         return Exception { SecurityError, "IDBFactory.deleteDatabase() called in an invalid security context"_s };
 
     ASSERT(context.securityOrigin());
-    IDBDatabaseIdentifier databaseIdentifier(name, SecurityOriginData { context.securityOrigin()->data() }, SecurityOriginData { context.topOrigin().data() });
+    bool isTransient = !context.securityOrigin()->canAccessDatabase(&context.topOrigin());
+    IDBDatabaseIdentifier databaseIdentifier(name, SecurityOriginData { context.securityOrigin()->data() }, SecurityOriginData { context.topOrigin().data() }, isTransient);
     if (!databaseIdentifier.isValid())
         return Exception { TypeError, "IDBFactory.deleteDatabase() called with an invalid security origin"_s };
 

Modified: trunk/Source/WebCore/Modules/indexeddb/server/IDBServer.cpp (264789 => 264790)


--- trunk/Source/WebCore/Modules/indexeddb/server/IDBServer.cpp	2020-07-23 21:05:27 UTC (rev 264789)
+++ trunk/Source/WebCore/Modules/indexeddb/server/IDBServer.cpp	2020-07-23 21:21:21 UTC (rev 264790)
@@ -133,6 +133,10 @@
     if (databaseDirectoryPath.isEmpty())
         return makeUnique<MemoryIDBBackingStore>(m_sessionID, identifier);
 
+    ASSERT(!m_sessionID.isEphemeral());
+    if (identifier.isTransient())
+        return makeUnique<MemoryIDBBackingStore>(m_sessionID, identifier);
+
     return makeUnique<SQLiteIDBBackingStore>(m_sessionID, identifier, databaseDirectoryPath);
 }
 

Modified: trunk/Source/WebCore/Modules/webdatabase/DOMWindowWebDatabase.cpp (264789 => 264790)


--- trunk/Source/WebCore/Modules/webdatabase/DOMWindowWebDatabase.cpp	2020-07-23 21:05:27 UTC (rev 264789)
+++ trunk/Source/WebCore/Modules/webdatabase/DOMWindowWebDatabase.cpp	2020-07-23 21:21:21 UTC (rev 264790)
@@ -48,7 +48,7 @@
     document->addConsoleMessage(MessageSource::Storage, MessageLevel::Warning, "Web SQL is deprecated. Please use IndexedDB instead.");
 
     auto& securityOrigin = document->securityOrigin();
-    if (!securityOrigin.canAccessDatabase(document->topOrigin()))
+    if (!securityOrigin.canAccessDatabase(&document->topOrigin()))
         return Exception { SecurityError };
     auto result = manager.openDatabase(*window.document(), name, version, displayName, estimatedSize, WTFMove(creationCallback));
     if (result.hasException()) {

Modified: trunk/Source/WebCore/page/SecurityOrigin.h (264789 => 264790)


--- trunk/Source/WebCore/page/SecurityOrigin.h	2020-07-23 21:05:27 UTC (rev 264789)
+++ trunk/Source/WebCore/page/SecurityOrigin.h	2020-07-23 21:21:21 UTC (rev 264790)
@@ -148,7 +148,7 @@
 
     WEBCORE_EXPORT String domainForCachePartition() const;
 
-    bool canAccessDatabase(const SecurityOrigin& topOrigin) const { return canAccessStorage(&topOrigin); };
+    bool canAccessDatabase(const SecurityOrigin* topOrigin) const { return canAccessStorage(topOrigin); };
     bool canAccessSessionStorage(const SecurityOrigin& topOrigin) const { return canAccessStorage(&topOrigin, AlwaysAllowFromThirdParty); }
     bool canAccessLocalStorage(const SecurityOrigin* topOrigin) const { return canAccessStorage(topOrigin); };
     bool canAccessPluginStorage(const SecurityOrigin& topOrigin) const { return canAccessStorage(&topOrigin); }

Modified: trunk/Source/WebKit/ChangeLog (264789 => 264790)


--- trunk/Source/WebKit/ChangeLog	2020-07-23 21:05:27 UTC (rev 264789)
+++ trunk/Source/WebKit/ChangeLog	2020-07-23 21:21:21 UTC (rev 264790)
@@ -1,3 +1,16 @@
+2020-07-23  Sihui Liu  <[email protected]>
+
+        Allow IndexedDB in third-party frames
+        https://bugs.webkit.org/show_bug.cgi?id=214583
+        <rdar://problem/61278487>
+
+        Reviewed by Geoffrey Garen.
+
+        Do no append extra space to displayName if host is empty.
+
+        * UIProcess/WebsiteData/WebsiteDataStore.cpp:
+        (WebKit::WebsiteDataStore::fetchDataAndApply):
+
 2020-07-23  David Quesada  <[email protected]>
 
         Unable to present file upload picker after interactively dismissing a previously opened picker

Modified: trunk/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.cpp (264789 => 264790)


--- trunk/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.cpp	2020-07-23 21:05:27 UTC (rev 264789)
+++ trunk/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.cpp	2020-07-23 21:21:21 UTC (rev 264790)
@@ -311,7 +311,8 @@
                     if (!allowsWebsiteDataRecordsForAllOrigins)
                         continue;
 
-                    displayName = makeString(entry.origin.protocol, " ", entry.origin.host);
+                    String hostString = entry.origin.host.isEmpty() ? "" : makeString(" ", entry.origin.host);
+                    displayName = makeString(entry.origin.protocol, hostString);
                 }
 
                 auto& record = m_websiteDataRecords.add(displayName, WebsiteDataRecord { }).iterator->value;

Modified: trunk/Tools/ChangeLog (264789 => 264790)


--- trunk/Tools/ChangeLog	2020-07-23 21:05:27 UTC (rev 264789)
+++ trunk/Tools/ChangeLog	2020-07-23 21:21:21 UTC (rev 264790)
@@ -1,3 +1,15 @@
+2020-07-23  Sihui Liu  <[email protected]>
+
+        Allow IndexedDB in third-party frames
+        https://bugs.webkit.org/show_bug.cgi?id=214583
+        <rdar://problem/61278487>
+
+        Reviewed by Geoffrey Garen.
+
+        * TestWebKitAPI/Tests/WebKitCocoa/IndexedDBPersistence.mm:
+        (postResult):
+        (catch):
+
 2020-07-23  Ryan Haddad  <[email protected]>
 
         [ews] Update bot watcher email address

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/IndexedDBPersistence.mm (264789 => 264790)


--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/IndexedDBPersistence.mm	2020-07-23 21:05:27 UTC (rev 264789)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/IndexedDBPersistence.mm	2020-07-23 21:21:21 UTC (rev 264790)
@@ -27,11 +27,13 @@
 
 #import "PlatformUtilities.h"
 #import "Test.h"
+#import "TestURLSchemeHandler.h"
 #import <WebKit/WebKit.h>
 #import <WebKit/WKProcessPoolPrivate.h>
 #import <WebKit/WKUserContentControllerPrivate.h>
 #import <WebKit/WKWebViewConfigurationPrivate.h>
 #import <WebKit/WKWebViewPrivate.h>
+#import <WebKit/WKWebsiteDataStorePrivate.h>
 #import <WebKit/_WKProcessPoolConfiguration.h>
 #import <WebKit/_WKUserStyleSheet.h>
 #import <wtf/RetainPtr.h>
@@ -179,3 +181,213 @@
     }];
     TestWebKitAPI::Util::run(&readyToContinue);
 }
+
+static NSString *mainFrameString = @"<script> \
+    function postResult(event) { \
+        window.webkit.messageHandlers.testHandler.postMessage(event.data); \
+    } \
+    addEventListener('message', postResult, false); \
+    </script> \
+    <iframe src=''>";
+
+static const char* iframeBytes = R"TESTRESOURCE(
+<script>
+function postResult(result) {
+    if (window.parent != window.top) {
+        parent.postMessage(result, '*');
+    } else {
+        window.webkit.messageHandlers.testHandler.postMessage(result);
+    }
+}
+
+try {
+    var request = window.indexedDB.open('IndexedDBThirdPartyFrameHasAccess');
+    var db = null;
+    request._onupgradeneeded_ = function(event) {
+        db = event.target.result;
+        var objectStore = db.createObjectStore('TestObjectStore');
+        var putRequest = objectStore.put('TestValue', 'TestKey');
+        putRequest._onsuccess_ = function(event) {
+            postResult('database is created - put item success');
+        }
+        putRequest._onerror_ = function(event) {
+            postResult('database is created - put item error: ' + event.target.error.name + ' - ' + event.target.error.message);
+        }
+    }
+    request._onsuccess_ = function(event) {
+        if (db)
+            return;
+        db = event.target.result;
+        var objectStore = db.transaction(['TestObjectStore']).objectStore('TestObjectStore');
+        var getRequest = objectStore.get('TestKey');
+        getRequest._onsuccess_ = function(event) {
+            postResult('database exists - get item success: ' + event.target.result);
+        }
+        getRequest._onerror_ = function(event) {
+            postResult('database exists - get item error: ' + event.target.error.name + ' - ' + event.target.error.message);
+        }
+    }
+    request._onerror_ = function(event) {
+        if (!db) {
+            postResult('database error: ' + event.target.error.name + ' - ' + event.target.error.message);
+        }
+    }
+} catch(err) {
+    postResult('database error: ' + err.name + ' - ' + err.message);
+}
+</script>
+)TESTRESOURCE";
+
+static void loadTestPageInWebView(WKWebView *webView, NSString *expectedResult)
+{
+    [webView loadHTMLString:mainFrameString baseURL:[NSURL URLWithString:@"http://webkit.org"]];
+    TestWebKitAPI::Util::run(&receivedScriptMessage);
+    receivedScriptMessage = false;
+    EXPECT_WK_STREQ(expectedResult, (NSString *)[lastScriptMessage body]);
+}
+
+TEST(IndexedDB, IndexedDBThirdPartyFrameHasAccess)
+{
+    auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
+    auto handler = adoptNS([[IndexedDBMessageHandler alloc] init]);
+    [[configuration userContentController] addScriptMessageHandler:handler.get() name:@"testHandler"];
+    auto schemeHandler = adoptNS([[TestURLSchemeHandler alloc] init]);
+    [schemeHandler setStartURLSchemeTaskHandler:^(WKWebView *, id<WKURLSchemeTask> task) {
+        auto response = adoptNS([[NSURLResponse alloc] initWithURL:task.request.URL MIMEType:@"text/html" expectedContentLength:0 textEncodingName:nil]);
+        [task didReceiveResponse:response.get()];
+        [task didReceiveData:[NSData dataWithBytes:iframeBytes length:strlen(iframeBytes)]];
+        [task didFinish];
+    }];
+    [configuration setURLSchemeHandler:schemeHandler.get() forURLScheme:@"iframe"];
+
+    auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
+    loadTestPageInWebView(webView.get(), @"database is created - put item success");
+
+    auto secondWebView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
+    loadTestPageInWebView(secondWebView.get(), @"database exists - get item success: TestValue");
+
+    webView = nil;
+    secondWebView = nil;
+    [configuration.get().processPool _terminateNetworkProcess];
+
+    // Third-party IDB storage is stored in the memory of network process.
+    auto thirdWebView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
+    loadTestPageInWebView(thirdWebView.get(), @"database is created - put item success");
+}
+
+TEST(IndexedDB, IndexedDBThirdPartyDataRemoval)
+{
+    auto websiteDataTypes = adoptNS([[NSSet alloc] initWithArray:@[WKWebsiteDataTypeIndexedDBDatabases]]);
+    readyToContinue = false;
+    [[WKWebsiteDataStore defaultDataStore] removeDataOfTypes:websiteDataTypes.get() modifiedSince:[NSDate distantPast] completionHandler:^() {
+        readyToContinue = true;
+    }];
+    TestWebKitAPI::Util::run(&readyToContinue);
+
+    [WKWebsiteDataStore _allowWebsiteDataRecordsForAllOrigins];
+
+    auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
+    auto handler = adoptNS([[IndexedDBMessageHandler alloc] init]);
+    [[configuration userContentController] addScriptMessageHandler:handler.get() name:@"testHandler"];
+    auto schemeHandler = adoptNS([[TestURLSchemeHandler alloc] init]);
+    [schemeHandler setStartURLSchemeTaskHandler:^(WKWebView *, id<WKURLSchemeTask> task) {
+        auto response = adoptNS([[NSURLResponse alloc] initWithURL:task.request.URL MIMEType:@"text/html" expectedContentLength:0 textEncodingName:nil]);
+        [task didReceiveResponse:response.get()];
+        [task didReceiveData:[NSData dataWithBytes:iframeBytes length:strlen(iframeBytes)]];
+        [task didFinish];
+    }];
+    [configuration setURLSchemeHandler:schemeHandler.get() forURLScheme:@"iframe"];
+
+    auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
+    loadTestPageInWebView(webView.get(), @"database is created - put item success");
+
+    auto secondWebView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
+    [secondWebView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"iframe://"]]];
+    TestWebKitAPI::Util::run(&receivedScriptMessage);
+    receivedScriptMessage = false;
+    EXPECT_WK_STREQ( @"database is created - put item success", (NSString *)[lastScriptMessage body]);
+
+    readyToContinue = false;
+    [[WKWebsiteDataStore defaultDataStore] fetchDataRecordsOfTypes:websiteDataTypes.get() completionHandler:^(NSArray<WKWebsiteDataRecord *> *dataRecords) {
+        EXPECT_EQ(1u, dataRecords.count);
+        EXPECT_WK_STREQ("iframe", [[dataRecords firstObject] displayName]);
+        [[WKWebsiteDataStore defaultDataStore] removeDataOfTypes:websiteDataTypes.get() forDataRecords:dataRecords completionHandler:^() {
+            readyToContinue = true;
+        }];
+    }];
+    TestWebKitAPI::Util::run(&readyToContinue);
+
+    auto thirdWebView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
+    loadTestPageInWebView(thirdWebView.get(), @"database is created - put item success");
+}
+
+static const char* workerBytes = R"TESTRESOURCE(
+try {
+    var request = indexedDB.open('IndexedDBThirdPartyWorkerHasAccess');
+    var db = null;
+    request._onupgradeneeded_ = function(event) {
+        db = event.target.result;
+        self.postMessage('database is created');
+    }
+    request._onsuccess_ = function(event) {
+        if (db)
+            return;
+        self.postMessage('database exists');
+    }
+    request._onerror_ = function(event) {
+        if (!db) {
+            self.postMessage('database error: ' + event.target.error.name + ' - ' + event.target.error.message);
+        }
+    }
+} catch(err) {
+    self.postMessage('database error: ' + err.name + ' - ' + err.message);
+}
+)TESTRESOURCE";
+
+static const char* workerFrameBytes = R"TESTRESOURCE(
+<script>
+    var worker = new Worker('worker.js');
+    worker._onmessage_ = function(event) {
+        parent.postMessage(event.data, '*');
+    };
+</script>
+)TESTRESOURCE";
+
+TEST(IndexedDB, IndexedDBThirdPartyWorkerHasAccess)
+{
+    auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
+    auto handler = adoptNS([[IndexedDBMessageHandler alloc] init]);
+    [[configuration userContentController] addScriptMessageHandler:handler.get() name:@"testHandler"];
+    auto schemeHandler = adoptNS([[TestURLSchemeHandler alloc] init]);
+    [schemeHandler setStartURLSchemeTaskHandler:^(WKWebView *, id<WKURLSchemeTask> task) {
+        RetainPtr<NSURLResponse> response;
+        RetainPtr<NSData> data;
+        NSURL *requestURL = task.request.URL;
+        if ([requestURL.absoluteString isEqualToString:@"iframe://"]) {
+            response = adoptNS([[NSURLResponse alloc] initWithURL:requestURL MIMEType:@"text/html" expectedContentLength:0 textEncodingName:nil]);
+            data = "" dataWithBytes:workerFrameBytes length:strlen(workerFrameBytes)];
+        } else {
+            EXPECT_WK_STREQ("iframe://worker.js", requestURL.absoluteString);
+            response = adoptNS([[NSURLResponse alloc] initWithURL:requestURL MIMEType:@"text/_javascript_" expectedContentLength:0 textEncodingName:nil]);
+            data = "" dataWithBytes:workerBytes length:strlen(workerBytes)];
+        }
+        [task didReceiveResponse:response.get()];
+        [task didReceiveData:data.get()];
+        [task didFinish];
+    }];
+    [configuration setURLSchemeHandler:schemeHandler.get() forURLScheme:@"iframe"];
+
+    auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
+    loadTestPageInWebView(webView.get(), @"database is created");
+
+    auto secondWebView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
+    loadTestPageInWebView(webView.get(), @"database exists");
+
+    webView = nil;
+    secondWebView = nil;
+    [configuration.get().processPool _terminateNetworkProcess];
+
+    auto thirdWebView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
+    loadTestPageInWebView(thirdWebView.get(), @"database is created");
+}
+
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to