WebKit Bugzilla
Attachment 369591 Details for
Bug 197463
: Reuse existing WebPageProxy quota handler for NetworkProcessProxy quota requests
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch
bug-197463-20190510132217.patch (text/plain), 35.59 KB, created by
youenn fablet
on 2019-05-10 13:22:18 PDT
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
youenn fablet
Created:
2019-05-10 13:22:18 PDT
Size:
35.59 KB
patch
obsolete
>Subversion Revision: 245079 >diff --git a/Source/WebKit/ChangeLog b/Source/WebKit/ChangeLog >index 5c629748a00ccdc4fcd82350f0397ae3ff1f16e9..94af53cf045ac62f66b27a8903468b20c0b7f50c 100644 >--- a/Source/WebKit/ChangeLog >+++ b/Source/WebKit/ChangeLog >@@ -1,3 +1,44 @@ >+2019-05-10 Youenn Fablet <youenn@apple.com> >+ >+ Reuse existing WebPageProxy quota handler for NetworkProcessProxy quota requests >+ https://bugs.webkit.org/show_bug.cgi?id=197463 >+ <rdar://problem/47403621> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Add a getter to know whether websitedatastore client implements the quota delegate. >+ If not, find the most visible page that is the same origin as the quota request >+ and reuse the existing exceededDatabasQuota delegate. >+ This approach allows to call the delegate even if the quota request comes from a service worker. >+ If no such page is found, the quota will not be increased. >+ >+ Refactoring to make sure we are calling the delegate once a previous call to that delegate is completed. >+ Covered by API test. >+ >+ * UIProcess/API/Cocoa/WKWebsiteDataStore.mm: >+ * UIProcess/Network/NetworkProcessProxy.cpp: >+ (WebKit::NetworkProcessProxy::requestStorageSpace): >+ * UIProcess/Network/NetworkProcessProxy.cpp.orig: Copied from Source/WebKit/UIProcess/Network/NetworkProcessProxy.cpp. >+ * UIProcess/WebPageProxy.cpp: >+ (WebKit::StorageRequests::add): >+ (WebKit::StorageRequests::processNext): >+ (WebKit::StorageRequests::areBeingProcessed const): >+ (WebKit::StorageRequests::setAreBeingProcessed): >+ (WebKit::StorageRequests::StorageRequests): >+ (WebKit::StorageRequests::~StorageRequests): >+ (WebKit::StorageRequests::singleton): >+ (WebKit::WebPageProxy::forMostVisibleWebPageIfAny): >+ (WebKit::WebPageProxy::didChangeMainDocument): >+ (WebKit::WebPageProxy::exceededDatabaseQuota): >+ (WebKit::WebPageProxy::requestStorageSpace): >+ (WebKit::WebPageProxy::makeStorageSpaceRequest): >+ * UIProcess/WebPageProxy.h: >+ * UIProcess/WebProcessProxy.cpp: >+ (WebKit::WebProcessProxy::forWebPages): >+ * UIProcess/WebProcessProxy.h: >+ * UIProcess/WebsiteData/WebsiteDataStoreClient.h: >+ (WebKit::WebsiteDataStoreClient::implementsRequestStorageSpaceHandler const): >+ > 2019-05-08 Megan Gardner <megan_gardner@apple.com> > > Add quirks to emulate undo and redo in hidden editable areas on some websites >diff --git a/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.mm b/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.mm >index 7dd4119c97b193b2843655e523ed8b7dc7e592b3..a7ce26e73106e26d255fccbc43134fa8b2573995 100644 >--- a/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.mm >+++ b/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.mm >@@ -43,7 +43,7 @@ > #import <wtf/URL.h> > #import <wtf/WeakObjCPtr.h> > >-class WebsiteDataStoreClient : public WebKit::WebsiteDataStoreClient { >+class WebsiteDataStoreClient final : public WebKit::WebsiteDataStoreClient { > public: > explicit WebsiteDataStoreClient(id <_WKWebsiteDataStoreDelegate> delegate) > : m_delegate(delegate) >@@ -52,6 +52,7 @@ public: > } > > private: >+ bool implementsRequestStorageSpaceHandler() const final { return m_hasRequestStorageSpaceSelector && !!m_delegate; } > void requestStorageSpace(const WebCore::SecurityOriginData& topOrigin, const WebCore::SecurityOriginData& frameOrigin, uint64_t quota, uint64_t currentSize, uint64_t spaceRequired, CompletionHandler<void(Optional<uint64_t>)>&& completionHandler) final > { > if (!m_hasRequestStorageSpaceSelector || !m_delegate) { >diff --git a/Source/WebKit/UIProcess/Network/NetworkProcessProxy.cpp b/Source/WebKit/UIProcess/Network/NetworkProcessProxy.cpp >index af859aec0362e91f930b286b8f42fc20fa883043..f7efcbf4e97cedc7b2eabe073c663d59eb562d46 100644 >--- a/Source/WebKit/UIProcess/Network/NetworkProcessProxy.cpp >+++ b/Source/WebKit/UIProcess/Network/NetworkProcessProxy.cpp >@@ -1141,7 +1141,7 @@ void NetworkProcessProxy::establishWorkerContextConnectionToNetworkProcessForExp > } > #endif > >-void NetworkProcessProxy::requestStorageSpace(PAL::SessionID sessionID, const WebCore::ClientOrigin& origin, uint64_t quota, uint64_t currentSize, uint64_t spaceRequired, CompletionHandler<void(Optional<uint64_t> quota)>&& completionHandler) >+void NetworkProcessProxy::requestStorageSpace(PAL::SessionID sessionID, const WebCore::ClientOrigin& origin, uint64_t currentQuota, uint64_t currentSize, uint64_t spaceRequired, CompletionHandler<void(Optional<uint64_t> quota)>&& completionHandler) > { > auto* store = websiteDataStoreFromSessionID(sessionID); > >@@ -1150,7 +1150,26 @@ void NetworkProcessProxy::requestStorageSpace(PAL::SessionID sessionID, const We > return; > } > >- store->client().requestStorageSpace(origin.topOrigin, origin.clientOrigin, quota, currentSize, spaceRequired, WTFMove(completionHandler)); >+ if (store->client().implementsRequestStorageSpaceHandler()) { >+ store->client().requestStorageSpace(origin.topOrigin, origin.clientOrigin, currentQuota, currentSize, spaceRequired, WTFMove(completionHandler)); >+ return; >+ } >+ >+ if (origin.topOrigin != origin.clientOrigin) { >+ completionHandler({ }); >+ return; >+ } >+ >+ WebPageProxy::forMostVisibleWebPageIfAny(sessionID, origin.topOrigin, [completionHandler = WTFMove(completionHandler), origin, currentQuota, currentSize, spaceRequired](auto* page) mutable { >+ if (!page) { >+ completionHandler({ }); >+ return; >+ } >+ String name = makeString(FileSystem::encodeForFileName(origin.topOrigin.host), " content"); >+ page->requestStorageSpace(page->mainFrame()->frameID(), origin.topOrigin.databaseIdentifier(), name, name, currentQuota, currentSize, currentSize, spaceRequired, [completionHandler = WTFMove(completionHandler)](auto quota) mutable { >+ completionHandler(quota); >+ }); >+ }); > } > > void NetworkProcessProxy::takeUploadAssertion() >diff --git a/Source/WebKit/UIProcess/WebPageProxy.cpp b/Source/WebKit/UIProcess/WebPageProxy.cpp >index a8ab15e7550c4eb095b254b16094edd45f32d570..c41cc4efd4e08ba1e1495c77f96444de1832ae05 100644 >--- a/Source/WebKit/UIProcess/WebPageProxy.cpp >+++ b/Source/WebKit/UIProcess/WebPageProxy.cpp >@@ -264,76 +264,43 @@ using namespace WebCore; > > DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, webPageProxyCounter, ("WebPageProxy")); > >-class ExceededDatabaseQuotaRecords { >- WTF_MAKE_NONCOPYABLE(ExceededDatabaseQuotaRecords); WTF_MAKE_FAST_ALLOCATED; >- friend NeverDestroyed<ExceededDatabaseQuotaRecords>; >+class StorageRequests { >+ WTF_MAKE_NONCOPYABLE(StorageRequests); WTF_MAKE_FAST_ALLOCATED; >+ friend NeverDestroyed<StorageRequests>; > public: >- struct Record { >- uint64_t frameID; >- String originIdentifier; >- String databaseName; >- String displayName; >- uint64_t currentQuota; >- uint64_t currentOriginUsage; >- uint64_t currentDatabaseUsage; >- uint64_t expectedUsage; >- Messages::WebPageProxy::ExceededDatabaseQuota::DelayedReply reply; >- }; >- >- static ExceededDatabaseQuotaRecords& singleton(); >+ static StorageRequests& singleton(); > >- std::unique_ptr<Record> createRecord(uint64_t frameID, String originIdentifier, >- String databaseName, String displayName, uint64_t currentQuota, >- uint64_t currentOriginUsage, uint64_t currentDatabaseUsage, uint64_t expectedUsage, >- Messages::WebPageProxy::ExceededDatabaseQuota::DelayedReply&&); >+ void processOrAppend(WTF::CompletionHandler<void()>&& completionHandler) >+ { >+ if (m_areBeingProcessing) { >+ m_requests.append(WTFMove(completionHandler)); >+ return; >+ } >+ m_areBeingProcessing = true; >+ completionHandler(); >+ } > >- void add(std::unique_ptr<Record>); >- bool areBeingProcessed() const { return !!m_currentRecord; } >- Record* next(); >+ void processNextIfAny() >+ { >+ if (m_requests.isEmpty()) { >+ m_areBeingProcessing = false; >+ return; >+ } >+ m_requests.takeFirst()(); >+ } > > private: >- ExceededDatabaseQuotaRecords() { } >- ~ExceededDatabaseQuotaRecords() { } >+ StorageRequests() { } >+ ~StorageRequests() { } > >- Deque<std::unique_ptr<Record>> m_records; >- std::unique_ptr<Record> m_currentRecord; >+ Deque<WTF::CompletionHandler<void()>> m_requests; >+ bool m_areBeingProcessing { false }; > }; > >-ExceededDatabaseQuotaRecords& ExceededDatabaseQuotaRecords::singleton() >+StorageRequests& StorageRequests::singleton() > { >- static NeverDestroyed<ExceededDatabaseQuotaRecords> records; >- return records; >-} >- >-std::unique_ptr<ExceededDatabaseQuotaRecords::Record> ExceededDatabaseQuotaRecords::createRecord( >- uint64_t frameID, String originIdentifier, String databaseName, String displayName, >- uint64_t currentQuota, uint64_t currentOriginUsage, uint64_t currentDatabaseUsage, >- uint64_t expectedUsage, Messages::WebPageProxy::ExceededDatabaseQuota::DelayedReply&& reply) >-{ >- auto record = std::make_unique<Record>(); >- record->frameID = frameID; >- record->originIdentifier = originIdentifier; >- record->databaseName = databaseName; >- record->displayName = displayName; >- record->currentQuota = currentQuota; >- record->currentOriginUsage = currentOriginUsage; >- record->currentDatabaseUsage = currentDatabaseUsage; >- record->expectedUsage = expectedUsage; >- record->reply = WTFMove(reply); >- return record; >-} >- >-void ExceededDatabaseQuotaRecords::add(std::unique_ptr<ExceededDatabaseQuotaRecords::Record> record) >-{ >- m_records.append(WTFMove(record)); >-} >- >-ExceededDatabaseQuotaRecords::Record* ExceededDatabaseQuotaRecords::next() >-{ >- m_currentRecord = nullptr; >- if (!m_records.isEmpty()) >- m_currentRecord = m_records.takeFirst(); >- return m_currentRecord.get(); >+ static NeverDestroyed<StorageRequests> requests; >+ return requests; > } > > #if !LOG_DISABLED >@@ -395,6 +362,25 @@ private: > WeakPtr<PageClient> m_pageClient; > }; > >+void WebPageProxy::forMostVisibleWebPageIfAny(PAL::SessionID sessionID, const SecurityOriginData& origin, CompletionHandler<void(WebPageProxy*)>&& completionHandler) >+{ >+ // FIXME: If not finding right away a visible page, we might want to try again for a given period of time when there is a change of visibility. >+ WebPageProxy* selectedPage = nullptr; >+ WebProcessProxy::forWebPages(sessionID, origin, [&](auto& page) { >+ if (!page.mainFrame()) >+ return; >+ if (page.isViewVisible() && (!selectedPage || !selectedPage->isViewVisible())) { >+ selectedPage = &page; >+ return; >+ } >+ if (page.isViewFocused() && (!selectedPage || !selectedPage->isViewFocused())) { >+ selectedPage = &page; >+ return; >+ } >+ }); >+ completionHandler(selectedPage); >+} >+ > Ref<WebPageProxy> WebPageProxy::create(PageClient& pageClient, WebProcessProxy& process, uint64_t pageID, Ref<API::PageConfiguration>&& configuration) > { > return adoptRef(*new WebPageProxy(pageClient, process, pageID, WTFMove(configuration))); >@@ -4396,6 +4382,7 @@ void WebPageProxy::didChangeMainDocument(uint64_t frameID) > #else > UNUSED_PARAM(frameID); > #endif >+ m_isQuotaIncreaseDenied = false; > } > > void WebPageProxy::viewIsBecomingVisible() >@@ -7241,24 +7228,41 @@ void WebPageProxy::didReceiveAuthenticationChallengeProxy(uint64_t, Ref<Authenti > > void WebPageProxy::exceededDatabaseQuota(uint64_t frameID, const String& originIdentifier, const String& databaseName, const String& displayName, uint64_t currentQuota, uint64_t currentOriginUsage, uint64_t currentDatabaseUsage, uint64_t expectedUsage, Messages::WebPageProxy::ExceededDatabaseQuota::DelayedReply&& reply) > { >- ExceededDatabaseQuotaRecords& records = ExceededDatabaseQuotaRecords::singleton(); >- std::unique_ptr<ExceededDatabaseQuotaRecords::Record> newRecord = records.createRecord(frameID, >- originIdentifier, databaseName, displayName, currentQuota, currentOriginUsage, >- currentDatabaseUsage, expectedUsage, WTFMove(reply)); >- records.add(WTFMove(newRecord)); >+ requestStorageSpace(frameID, originIdentifier, databaseName, displayName, currentQuota, currentOriginUsage, currentDatabaseUsage, expectedUsage, [reply = WTFMove(reply)](auto quota) mutable { >+ reply(quota); >+ }); >+} > >- if (records.areBeingProcessed()) >+void WebPageProxy::requestStorageSpace(uint64_t frameID, const String& originIdentifier, const String& databaseName, const String& displayName, uint64_t currentQuota, uint64_t currentOriginUsage, uint64_t currentDatabaseUsage, uint64_t expectedUsage, CompletionHandler<void(uint64_t)>&& completionHandler) >+{ >+ StorageRequests::singleton().processOrAppend([this, protectedThis = makeRef(*this), pageURL = currentURL(), frameID, originIdentifier, databaseName, displayName, currentQuota, currentOriginUsage, currentDatabaseUsage, expectedUsage, completionHandler = WTFMove(completionHandler)]() mutable { >+ this->makeStorageSpaceRequest(frameID, originIdentifier, databaseName, displayName, currentQuota, currentOriginUsage, currentDatabaseUsage, expectedUsage, [this, protectedThis = WTFMove(protectedThis), pageURL = WTFMove(pageURL), completionHandler = WTFMove(completionHandler), currentQuota](auto quota) mutable { >+ if (quota <= currentQuota && this->currentURL() == pageURL) >+ m_isQuotaIncreaseDenied = true; >+ completionHandler(quota); >+ StorageRequests::singleton().processNextIfAny(); >+ }); >+ }); >+} >+ >+void WebPageProxy::makeStorageSpaceRequest(uint64_t frameID, const String& originIdentifier, const String& databaseName, const String& displayName, uint64_t currentQuota, uint64_t currentOriginUsage, uint64_t currentDatabaseUsage, uint64_t expectedUsage, CompletionHandler<void(uint64_t)>&& completionHandler) >+{ >+ if (m_isQuotaIncreaseDenied) { >+ completionHandler(currentQuota); > return; >+ } > >- ExceededDatabaseQuotaRecords::Record* record = records.next(); >- while (record) { >- WebFrameProxy* frame = m_process->webFrame(record->frameID); >- MESSAGE_CHECK(m_process, frame); >+ WebFrameProxy* frame = m_process->webFrame(frameID); >+ MESSAGE_CHECK(m_process, frame); > >- auto origin = API::SecurityOrigin::create(SecurityOriginData::fromDatabaseIdentifier(record->originIdentifier)->securityOrigin()); >- m_uiClient->exceededDatabaseQuota(this, frame, origin.ptr(), record->databaseName, record->displayName, record->currentQuota, record->currentOriginUsage, record->currentDatabaseUsage, record->expectedUsage, WTFMove(record->reply)); >- record = records.next(); >+ auto originData = SecurityOriginData::fromDatabaseIdentifier(originIdentifier); >+ if (originData != SecurityOriginData::fromURL(URL { { }, currentURL() })) { >+ completionHandler(currentQuota); >+ return; > } >+ >+ auto origin = API::SecurityOrigin::create(originData->securityOrigin()); >+ m_uiClient->exceededDatabaseQuota(this, frame, origin.ptr(), databaseName, displayName, currentQuota, currentOriginUsage, currentDatabaseUsage, expectedUsage, WTFMove(completionHandler)); > } > > void WebPageProxy::reachedApplicationCacheOriginQuota(const String& originIdentifier, uint64_t currentQuota, uint64_t totalBytesNeeded, Messages::WebPageProxy::ReachedApplicationCacheOriginQuota::DelayedReply&& reply) >diff --git a/Source/WebKit/UIProcess/WebPageProxy.h b/Source/WebKit/UIProcess/WebPageProxy.h >index b239a9c73a5fd18a00ffa821c81a5fc03469e01f..f936842a52ba6bbd9c579f6a8154d2167a27ad87 100644 >--- a/Source/WebKit/UIProcess/WebPageProxy.h >+++ b/Source/WebKit/UIProcess/WebPageProxy.h >@@ -385,6 +385,8 @@ public: > static Ref<WebPageProxy> create(PageClient&, WebProcessProxy&, uint64_t pageID, Ref<API::PageConfiguration>&&); > virtual ~WebPageProxy(); > >+ static void forMostVisibleWebPageIfAny(PAL::SessionID, const WebCore::SecurityOriginData&, CompletionHandler<void(WebPageProxy*)>&&); >+ > const API::PageConfiguration& configuration() const; > > uint64_t pageID() const { return m_pageID; } >@@ -1542,6 +1544,8 @@ WEBPAGEPROXY_LOADOPTIMIZER_ADDITIONS_1 > void didReceiveMessage(IPC::Connection&, IPC::Decoder&) override; > void didReceiveSyncMessage(IPC::Connection&, IPC::Decoder&, std::unique_ptr<IPC::Encoder>&) override; > >+ void requestStorageSpace(uint64_t frameID, const String& originIdentifier, const String& databaseName, const String& displayName, uint64_t currentQuota, uint64_t currentOriginUsage, uint64_t currentDatabaseUsage, uint64_t expectedUsage, WTF::CompletionHandler<void(uint64_t)>&&); >+ > private: > WebPageProxy(PageClient&, WebProcessProxy&, uint64_t pageID, Ref<API::PageConfiguration>&&); > void platformInitialize(); >@@ -2078,6 +2082,9 @@ private: > static bool isInHardwareKeyboardMode(); > #endif > >+ void makeStorageSpaceRequest(uint64_t frameID, const String& originIdentifier, const String& databaseName, const String& displayName, uint64_t currentQuota, uint64_t currentOriginUsage, uint64_t currentDatabaseUsage, uint64_t expectedUsage, WTF::CompletionHandler<void(uint64_t)>&&); >+ >+ > WeakPtr<PageClient> m_pageClient; > Ref<API::PageConfiguration> m_configuration; > >@@ -2507,6 +2514,7 @@ WEBPAGEPROXY_LOADOPTIMIZER_ADDITIONS_2 > }; > Optional<SpeechSynthesisData> m_speechSynthesisData; > #endif >+ bool m_isQuotaIncreaseDenied { false }; > }; > > } // namespace WebKit >diff --git a/Source/WebKit/UIProcess/WebProcessProxy.cpp b/Source/WebKit/UIProcess/WebProcessProxy.cpp >index 41d300440c19daa1195aad39dcc23be06cbd6d38..8bd2a04c469f1a8c7a0cdec8b26c0f1f89beee62 100644 >--- a/Source/WebKit/UIProcess/WebProcessProxy.cpp >+++ b/Source/WebKit/UIProcess/WebProcessProxy.cpp >@@ -122,6 +122,15 @@ static WebProcessProxy::WebPageProxyMap& globalPageMap() > return pageMap; > } > >+void WebProcessProxy::forWebPages(PAL::SessionID sessionID, const SecurityOriginData& origin, const WTF::Function<void(WebPageProxy&)>& callback) >+{ >+ for (auto* page : globalPageMap().values()) { >+ if (page->sessionID() != sessionID || SecurityOriginData::fromURL(URL { { }, page->currentURL() }) != origin) >+ continue; >+ callback(*page); >+ } >+} >+ > Ref<WebProcessProxy> WebProcessProxy::create(WebProcessPool& processPool, WebsiteDataStore* websiteDataStore, IsPrewarmed isPrewarmed, ShouldLaunchProcess shouldLaunchProcess) > { > auto proxy = adoptRef(*new WebProcessProxy(processPool, websiteDataStore, isPrewarmed)); >diff --git a/Source/WebKit/UIProcess/WebProcessProxy.h b/Source/WebKit/UIProcess/WebProcessProxy.h >index 1284aea5187c1f884acf255ca030ed93cadeff85..a07195b8bab35eceeec5d62b6b240cad98ab6ad5 100644 >--- a/Source/WebKit/UIProcess/WebProcessProxy.h >+++ b/Source/WebKit/UIProcess/WebProcessProxy.h >@@ -110,6 +110,8 @@ public: > static Ref<WebProcessProxy> create(WebProcessPool&, WebsiteDataStore*, IsPrewarmed, ShouldLaunchProcess = ShouldLaunchProcess::Yes); > ~WebProcessProxy(); > >+ static void forWebPages(PAL::SessionID, const WebCore::SecurityOriginData&, const WTF::Function<void(WebPageProxy&)>&); >+ > WebConnection* webConnection() const { return m_webConnection.get(); } > > unsigned suspendedPageCount() const { return m_suspendedPageCount; } >diff --git a/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStoreClient.h b/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStoreClient.h >index e9fcf00153995dc1cce135f8c092e92e66dbff3a..1d320aa65e0076ed44d8c8e05b1281fc9f94771e 100644 >--- a/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStoreClient.h >+++ b/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStoreClient.h >@@ -37,6 +37,7 @@ class WebsiteDataStoreClient { > public: > virtual ~WebsiteDataStoreClient() { } > >+ virtual bool implementsRequestStorageSpaceHandler() const { return false; } > virtual void requestStorageSpace(const WebCore::SecurityOriginData& topOrigin, const WebCore::SecurityOriginData& frameOrigin, uint64_t quota, uint64_t currentSize, uint64_t spaceRequired, CompletionHandler<void(Optional<uint64_t>)>&& completionHandler) > { > completionHandler({ }); >diff --git a/Tools/ChangeLog b/Tools/ChangeLog >index 4c86eb3b3214186e717062ab30517369cb5c000f..63490a9d98f70cdd7f7da7807faecb8d8432d2d2 100644 >--- a/Tools/ChangeLog >+++ b/Tools/ChangeLog >@@ -1,3 +1,21 @@ >+2019-05-10 Youenn Fablet <youenn@apple.com> >+ >+ Reuse existing WebPageProxy quota handler for NetworkProcessProxy quota requests >+ https://bugs.webkit.org/show_bug.cgi?id=197463 >+ <rdar://problem/47403621> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * TestWebKitAPI/Tests/WebKitCocoa/StorageQuota.mm: Added. >+ (-[QuotaDelegate init]): >+ (-[QuotaDelegate _webView:decideDatabaseQuotaForSecurityOrigin:currentQuota:currentOriginUsage:currentDatabaseUsage:expectedUsage:decisionHandler:]): >+ (-[QuotaDelegate quotaDelegateCalled]): >+ (-[QuotaDelegate grantQuota]): >+ (-[StorageSchemes webView:startURLSchemeTask:]): >+ (-[StorageSchemes webView:stopURLSchemeTask:]): >+ (-[QuotaMessageHandler userContentController:didReceiveScriptMessage:]): >+ (doTest): >+ > 2019-05-08 Jonathan Bedard <jbedard@apple.com> > > Change my status to be a WebKit reviewer. >diff --git a/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj b/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj >index 578b61a1216153d8fa6b1ce6f73787c528618f60..68f218c54125fbfb53bc73ef9ebeae82b080c815 100644 >--- a/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj >+++ b/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj >@@ -180,6 +180,7 @@ > 3FCC4FE81EC4E8CA0076E37C /* PictureInPictureDelegate.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 3FCC4FE61EC4E87E0076E37C /* PictureInPictureDelegate.html */; }; > 4135FB842011FAA700332139 /* InjectInternals_Bundle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4135FB832011FAA300332139 /* InjectInternals_Bundle.cpp */; }; > 4135FB852011FABF00332139 /* libWebCoreTestSupport.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 4135FB862011FABF00332139 /* libWebCoreTestSupport.dylib */; }; >+ 414AD6862285D1C000777F2D /* StorageQuota.mm in Sources */ = {isa = PBXBuildFile; fileRef = 414AD6852285D1B000777F2D /* StorageQuota.mm */; }; > 41882F0321010C0D002FF288 /* ProcessPreWarming.mm in Sources */ = {isa = PBXBuildFile; fileRef = 41882F0221010A70002FF288 /* ProcessPreWarming.mm */; }; > 4433A396208044140091ED57 /* SynchronousTimeoutTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4433A395208044130091ED57 /* SynchronousTimeoutTests.mm */; }; > 44817A2F1F0486BF00003810 /* WKRequestActivatedElementInfo.mm in Sources */ = {isa = PBXBuildFile; fileRef = 44817A2E1F0486BF00003810 /* WKRequestActivatedElementInfo.mm */; }; >@@ -1578,6 +1579,7 @@ > 3FCC4FE61EC4E87E0076E37C /* PictureInPictureDelegate.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = PictureInPictureDelegate.html; sourceTree = "<group>"; }; > 4135FB832011FAA300332139 /* InjectInternals_Bundle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = InjectInternals_Bundle.cpp; path = Tests/InjectInternals_Bundle.cpp; sourceTree = SOURCE_ROOT; }; > 4135FB862011FABF00332139 /* libWebCoreTestSupport.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; path = libWebCoreTestSupport.dylib; sourceTree = BUILT_PRODUCTS_DIR; }; >+ 414AD6852285D1B000777F2D /* StorageQuota.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = StorageQuota.mm; sourceTree = "<group>"; }; > 41882F0221010A70002FF288 /* ProcessPreWarming.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ProcessPreWarming.mm; sourceTree = "<group>"; }; > 41973B5C1AF22875006C7B36 /* SharedBuffer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SharedBuffer.cpp; sourceTree = "<group>"; }; > 442BBF681C91CAD90017087F /* RefLogger.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RefLogger.cpp; sourceTree = "<group>"; }; >@@ -2686,6 +2688,7 @@ > 2D9A53AE1B31FA8D0074D5AA /* ShrinkToFit.mm */, > 2DFF7B6C1DA487AF00814614 /* SnapshotStore.mm */, > CDC0932D21C993440030C4B0 /* StopSuspendResumeAllMedia.mm */, >+ 414AD6852285D1B000777F2D /* StorageQuota.mm */, > 515BE1701D428BD100DD7C68 /* StoreBlobThenDelete.mm */, > 1C734B5220788C4800F430EA /* SystemColors.mm */, > 2D70059521EDA0C6003463CB /* TabOutOfWebView.mm */, >@@ -4365,6 +4368,7 @@ > 7CCE7ECE1A411A7E00447C4C /* StopLoadingFromDidFinishLoading.mm in Sources */, > 7CCE7ECF1A411A7E00447C4C /* StopLoadingFromDidReceiveResponse.mm in Sources */, > CDC0932E21C993440030C4B0 /* StopSuspendResumeAllMedia.mm in Sources */, >+ 414AD6862285D1C000777F2D /* StorageQuota.mm in Sources */, > 515BE1711D428E4B00DD7C68 /* StoreBlobThenDelete.mm in Sources */, > 7CCE7ED01A411A7E00447C4C /* StringByEvaluatingJavaScriptFromString.mm in Sources */, > 7CCE7ED11A411A7E00447C4C /* StringTruncator.mm in Sources */, >diff --git a/Tools/TestWebKitAPI/Tests/WebKitCocoa/StorageQuota.mm b/Tools/TestWebKitAPI/Tests/WebKitCocoa/StorageQuota.mm >new file mode 100644 >index 0000000000000000000000000000000000000000..3e6b4131783579223aa50d0300c8c1a42fed8e37 >--- /dev/null >+++ b/Tools/TestWebKitAPI/Tests/WebKitCocoa/StorageQuota.mm >@@ -0,0 +1,300 @@ >+/* >+ * Copyright (C) 2016 Apple Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' >+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, >+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS >+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR >+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF >+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS >+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN >+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) >+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF >+ * THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#import "config.h" >+#import <WebKit/WebKit.h> >+ >+#import "PlatformUtilities.h" >+#import "Test.h" >+#import "TestWKWebView.h" >+#import <WebKit/WKPreferencesPrivate.h> >+#import <WebKit/WKProcessPoolPrivate.h> >+#import <WebKit/WKURLSchemeHandler.h> >+#import <WebKit/WKURLSchemeTaskPrivate.h> >+#import <WebKit/WKWebViewConfigurationPrivate.h> >+#import <WebKit/WKWebsiteDataStorePrivate.h> >+#import <WebKit/WKWebsiteDataStoreRef.h> >+#import <WebKit/_WKWebsiteDataStoreConfiguration.h> >+#import <wtf/BlockPtr.h> >+#import <wtf/HashMap.h> >+#import <wtf/RetainPtr.h> >+#import <wtf/Vector.h> >+#import <wtf/text/StringHash.h> >+#import <wtf/text/WTFString.h> >+ >+using namespace TestWebKitAPI; >+ >+@interface QuotaDelegate : NSObject <WKUIDelegate> >+-(bool)quotaDelegateCalled; >+-(void)grantQuota; >+-(void)denyQuota; >+@end >+ >+static bool receivedQuotaDelegateCalled; >+ >+@implementation QuotaDelegate { >+ bool _quotaDelegateCalled; >+ unsigned long long _currentQuota; >+ unsigned long long _expectedUsage; >+ BlockPtr<void(unsigned long long newQuota)> _decisionHandler; >+} >+ >+- (instancetype)init >+{ >+ if (!(self = [super init])) >+ return nil; >+ >+ _quotaDelegateCalled = false; >+ _expectedUsage = 0; >+ _currentQuota = 0; >+ >+ return self; >+} >+ >+- (void)_webView:(WKWebView *)webView decideDatabaseQuotaForSecurityOrigin:(WKSecurityOrigin *)securityOrigin currentQuota:(unsigned long long)currentQuota currentOriginUsage:(unsigned long long)currentOriginUsage currentDatabaseUsage:(unsigned long long)currentUsage expectedUsage:(unsigned long long)expectedUsage decisionHandler:(void (^)(unsigned long long newQuota))decisionHandler >+{ >+ receivedQuotaDelegateCalled = true; >+ _quotaDelegateCalled = true; >+ _currentQuota = currentQuota; >+ _expectedUsage = expectedUsage; >+ _decisionHandler = decisionHandler; >+} >+ >+-(bool)quotaDelegateCalled { >+ return _quotaDelegateCalled; >+} >+ >+-(void)grantQuota { >+ if (_quotaDelegateCalled) >+ _decisionHandler(_expectedUsage); >+ _quotaDelegateCalled = false; >+} >+ >+-(void)denyQuota { >+ if (_quotaDelegateCalled) >+ _decisionHandler(_currentQuota); >+ _quotaDelegateCalled = false; >+} >+ >+@end >+ >+struct ResourceInfo { >+ RetainPtr<NSString> mimeType; >+ const char* data; >+}; >+ >+@interface StorageSchemes : NSObject <WKURLSchemeHandler> { >+@public >+ HashMap<String, ResourceInfo> resources; >+} >+@end >+ >+@implementation StorageSchemes { >+} >+ >+- (void)webView:(WKWebView *)webView startURLSchemeTask:(id <WKURLSchemeTask>)task >+{ >+ auto entry = resources.find([task.request.URL absoluteString]); >+ if (entry == resources.end()) { >+ NSLog(@"Did not find resource entry for URL %@", task.request.URL); >+ return; >+ } >+ >+ RetainPtr<NSURLResponse> response = adoptNS([[NSURLResponse alloc] initWithURL:task.request.URL MIMEType:entry->value.mimeType.get() expectedContentLength:1 textEncodingName:nil]); >+ [task didReceiveResponse:response.get()]; >+ >+ [task didReceiveData:[NSData dataWithBytesNoCopy:(void*)entry->value.data length:strlen(entry->value.data) freeWhenDone:NO]]; >+ [task didFinish]; >+} >+ >+- (void)webView:(WKWebView *)webView stopURLSchemeTask:(id <WKURLSchemeTask>)task >+{ >+} >+ >+@end >+ >+static bool receivedMessage; >+ >+@interface QuotaMessageHandler : NSObject <WKScriptMessageHandler> >+-(void)setExpectedMessage:(NSString *)message; >+@end >+ >+@implementation QuotaMessageHandler { >+ NSString *_expectedMessage; >+} >+ >+- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message >+{ >+ if (_expectedMessage) { >+ EXPECT_TRUE([[message body] isEqualToString:_expectedMessage]); >+ _expectedMessage = nil; >+ } >+ receivedMessage = true; >+} >+ >+-(void)setExpectedMessage:(NSString *)message { >+ _expectedMessage = message; >+} >+@end >+ >+static const char* TestBytes = R"SWRESOURCE( >+<script> >+ >+async function doTest() >+{ >+ const cache = await window.caches.open("mycache"); >+ const promise = cache.put("http://example.org/test", new Response(new ArrayBuffer(1024 * 500))); >+ window.webkit.messageHandlers.qt.postMessage("start"); >+ promise.then(() => { >+ window.webkit.messageHandlers.qt.postMessage("pass"); >+ }, () => { >+ window.webkit.messageHandlers.qt.postMessage("fail"); >+ }); >+} >+doTest(); >+ >+</script> >+)SWRESOURCE"; >+ >+static bool done; >+ >+TEST(WebKit, QuotaDelegate) >+{ >+ done = false; >+ [[WKWebsiteDataStore defaultDataStore] removeDataOfTypes:[WKWebsiteDataStore allWebsiteDataTypes] modifiedSince:[NSDate distantPast] completionHandler:^() { >+ done = true; >+ }]; >+ TestWebKitAPI::Util::run(&done); >+ >+ auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]); >+ >+ [[configuration websiteDataStore] _setPerOriginStorageQuota: 1024 * 400]; >+ >+ auto messageHandler = adoptNS([[QuotaMessageHandler alloc] init]); >+ [[configuration userContentController] addScriptMessageHandler:messageHandler.get() name:@"qt"]; >+ >+ auto handler1 = adoptNS([[StorageSchemes alloc] init]); >+ handler1->resources.set("qt1://test1.html", ResourceInfo { @"text/html", TestBytes }); >+ [configuration setURLSchemeHandler:handler1.get() forURLScheme:@"QT1"]; >+ [configuration.get().processPool _registerURLSchemeServiceWorkersCanHandle:@"qt1"]; >+ >+ auto handler2 = adoptNS([[StorageSchemes alloc] init]); >+ handler2->resources.set("qt2://test2.html", ResourceInfo { @"text/html", TestBytes }); >+ [configuration setURLSchemeHandler:handler2.get() forURLScheme:@"QT2"]; >+ [configuration.get().processPool _registerURLSchemeServiceWorkersCanHandle:@"qt2"]; >+ >+ auto webView1 = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get() addToWindow:YES]); >+ auto delegate1 = adoptNS([[QuotaDelegate alloc] init]); >+ [webView1 setUIDelegate:delegate1.get()]; >+#if PLATFORM(MAC) >+ [webView1.get().window setIsVisible:YES]; >+#else >+ webView1.get().window.hidden = NO; >+#endif >+ >+ receivedQuotaDelegateCalled = false; >+ [webView1 loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"qt1://test1.html"]]]; >+ Util::run(&receivedQuotaDelegateCalled); >+ >+ auto webView2 = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get() addToWindow:YES]); >+ auto delegate2 = adoptNS([[QuotaDelegate alloc] init]); >+ [webView2 setUIDelegate:delegate2.get()]; >+#if PLATFORM(MAC) >+ [webView2.get().window setIsVisible:YES]; >+#else >+ webView2.get().window.hidden = NO; >+#endif >+ >+ receivedMessage = false; >+ [webView2 loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"qt2://test2.html"]]]; >+ [messageHandler setExpectedMessage: @"start"]; >+ Util::run(&receivedMessage); >+ >+ EXPECT_FALSE(delegate2.get().quotaDelegateCalled); >+ [delegate1 grantQuota]; >+ >+ [messageHandler setExpectedMessage: @"pass"]; >+ receivedMessage = false; >+ Util::run(&receivedMessage); >+ >+ while (!delegate2.get().quotaDelegateCalled) >+ TestWebKitAPI::Util::sleep(0.1); >+ >+ [delegate2 denyQuota]; >+ >+ [messageHandler setExpectedMessage: @"fail"]; >+ receivedMessage = false; >+ Util::run(&receivedMessage); >+} >+ >+TEST(WebKit, QuotaDelegateReload) >+{ >+ done = false; >+ [[WKWebsiteDataStore defaultDataStore] removeDataOfTypes:[WKWebsiteDataStore allWebsiteDataTypes] modifiedSince:[NSDate distantPast] completionHandler:^() { >+ done = true; >+ }]; >+ TestWebKitAPI::Util::run(&done); >+ >+ auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]); >+ >+ [[configuration websiteDataStore] _setPerOriginStorageQuota: 1024 * 400]; >+ >+ auto messageHandler = adoptNS([[QuotaMessageHandler alloc] init]); >+ [[configuration userContentController] addScriptMessageHandler:messageHandler.get() name:@"qt"]; >+ >+ auto handler = adoptNS([[StorageSchemes alloc] init]); >+ handler->resources.set("qt://test1.html", ResourceInfo { @"text/html", TestBytes }); >+ [configuration setURLSchemeHandler:handler.get() forURLScheme:@"QT"]; >+ [configuration.get().processPool _registerURLSchemeServiceWorkersCanHandle:@"qt"]; >+ >+ auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get() addToWindow:YES]); >+ auto delegate = adoptNS([[QuotaDelegate alloc] init]); >+ [webView setUIDelegate:delegate.get()]; >+#if PLATFORM(MAC) >+ [webView.get().window setIsVisible:YES]; >+#else >+ webView.get().window.hidden = NO; >+#endif >+ >+ receivedQuotaDelegateCalled = false; >+ [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"qt://test1.html"]]]; >+ Util::run(&receivedQuotaDelegateCalled); >+ >+ [delegate denyQuota]; >+ >+ [messageHandler setExpectedMessage: @"fail"]; >+ receivedMessage = false; >+ Util::run(&receivedMessage); >+ >+ receivedQuotaDelegateCalled = false; >+ [webView reload]; >+ Util::run(&receivedQuotaDelegateCalled); >+ >+ [delegate grantQuota]; >+ >+ [messageHandler setExpectedMessage: @"pass"]; >+ receivedMessage = false; >+ Util::run(&receivedMessage); >+}
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 197463
:
368677
|
369439
|
369449
|
369591
|
369883
|
369897
|
369902
|
369916
|
369960