Title: [248179] trunk/Source
Revision
248179
Author
[email protected]
Date
2019-08-02 14:05:39 -0700 (Fri, 02 Aug 2019)

Log Message

Web Inspector: Storage: disable related agents when the tab is closed
https://bugs.webkit.org/show_bug.cgi?id=200117

Reviewed by Joseph Pecoraro.

Rework how `enable`/`disable` is used for storage-related agents so that events are not sent
and data isn't kept alive when the Storage tab isn't enabled.

Source/_javascript_Core:

* inspector/protocol/ApplicationCache.json:
Add `disable` command.

Source/WebCore:

Covered by existing tests.

* inspector/agents/InspectorApplicationCacheAgent.h:
* inspector/agents/InspectorApplicationCacheAgent.cpp:
(WebCore::InspectorApplicationCacheAgent::willDestroyFrontendAndBackend):
(WebCore::InspectorApplicationCacheAgent::enable):
(WebCore::InspectorApplicationCacheAgent::disable): Added.

* inspector/agents/InspectorDOMStorageAgent.cpp:
(WebCore::InspectorDOMStorageAgent::enable):
(WebCore::InspectorDOMStorageAgent::disable):

* inspector/agents/InspectorDatabaseAgent.cpp:
(WebCore::InspectorDatabaseAgent::enable):
(WebCore::InspectorDatabaseAgent::disable):

Source/WebInspectorUI:

* UserInterface/Controllers/ApplicationCacheManager.js:
(WI.ApplicationCacheManager):
(WI.ApplicationCacheManage.prototype.get domains): Added.
(WI.ApplicationCacheManage.prototype.activateExtraDomain): Added.
(WI.ApplicationCacheManager.prototype.initializeTarget):
(WI.ApplicationCacheManager.prototype.enable): Added.
(WI.ApplicationCacheManager.prototype.disable): Added.
(WI.ApplicationCacheManager.prototype.networkStateUpdated):
(WI.ApplicationCacheManager.prototype.applicationCacheStatusUpdated):
(WI.ApplicationCacheManager.prototype._reset): Added.
(WI.ApplicationCacheManager.prototype._mainResourceDidChange):
(WI.ApplicationCacheManager.prototype._manifestForFrameLoaded):
(WI.ApplicationCacheManager.prototype._framesWithManifestsLoaded):
(WI.ApplicationCacheManager.prototype.initialize): Deleted.

* UserInterface/Controllers/DOMStorageManager.js:
(WI.DOMStorageManager):
(WI.DOMStorageManager.prototype.get domains): Added.
(WI.DOMStorageManager.prototype.activateExtraDomain): Added.
(WI.DOMStorageManager.prototype.initializeTarget):
(WI.DOMStorageManager.prototype.enable): Added.
(WI.DOMStorageManager.prototype.disable): Added.
(WI.DOMStorageManager.prototype.itemsCleared):
(WI.DOMStorageManager.prototype.itemRemoved):
(WI.DOMStorageManager.prototype.itemAdded):
(WI.DOMStorageManager.prototype.itemUpdated):
(WI.DOMStorageManager.prototype.inspectDOMStorage):
(WI.DOMStorageManager.prototype._reset): Added.
(WI.DOMStorageManager.prototype._addDOMStorageIfNeeded):
(WI.DOMStorageManager.prototype._addCookieStorageIfNeeded):
(WI.DOMStorageManager.prototype._mainResourceDidChange):
(WI.DOMStorageManager.prototype.initialize): Deleted.
(WI.DOMStorageManager.prototype.domStorageWasAdded): Deleted.

* UserInterface/Controllers/DatabaseManager.js:
(WI.DatabaseManager):
(WI.DatabaseManager.prototype.get domains): Added.
(WI.DatabaseManager.prototype.activateExtraDomain): Added.
(WI.DatabaseManager.prototype.initializeTarget):
(WI.DatabaseManager.prototype.enable): Added.
(WI.DatabaseManager.prototype.disable): Added.
(WI.DatabaseManager.prototype.databaseWasAdded):
(WI.DatabaseManager.prototype.inspectDatabase):
(WI.DatabaseManager.prototype._reset): Added.
(WI.DatabaseManager.prototype._mainResourceDidChange):
(WI.DatabaseManager.prototype.initialize): Deleted.

* UserInterface/Controllers/IndexedDBManager.js:
(WI.IndexedDBManager):
(WI.IndexedDBManager.prototype.get domains): Added.
(WI.IndexedDBManager.prototype.activateExtraDomain): Added.
(WI.IndexedDBManager.prototype.initializeTarget):
(WI.IndexedDBManager.prototype.enable): Added.
(WI.IndexedDBManager.prototype.disable): Added.
(WI.IndexedDBManager.prototype.clearObjectStore):
(WI.IndexedDBManager.prototype._reset): Added.
(WI.IndexedDBManager.prototype._mainResourceDidChange):
(WI.IndexedDBManager.prototype.initialize): Deleted.

* UserInterface/Controllers/AppController.js:
(WI.AppController.prototype.activateExtraDomains):
* UserInterface/Controllers/CanvasManager.js:
(WI.CanvasManager.prototype.get domains): Added.
(WI.CanvasManager.prototype.activateExtraDomain): Added.
Only call `enable` on any extra agents if the domain is not controlled by a manager.

* UserInterface/Views/StorageTabContentView.js:
(WI.StorageTabContentView):
(WI.StorageTabContentView.static isTabAllowed):
(WI.StorageTabContentView.prototype.canShowRepresentedObject):
(WI.StorageTabContentView.prototype.closed): Added.

* UserInterface/Test.html:
* UserInterface/Test/Test.js:
(WI.loaded):
(WI.contentLoaded):

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (248178 => 248179)


--- trunk/Source/_javascript_Core/ChangeLog	2019-08-02 21:02:05 UTC (rev 248178)
+++ trunk/Source/_javascript_Core/ChangeLog	2019-08-02 21:05:39 UTC (rev 248179)
@@ -1,3 +1,16 @@
+2019-08-02  Devin Rousso  <[email protected]>
+
+        Web Inspector: Storage: disable related agents when the tab is closed
+        https://bugs.webkit.org/show_bug.cgi?id=200117
+
+        Reviewed by Joseph Pecoraro.
+
+        Rework how `enable`/`disable` is used for storage-related agents so that events are not sent
+        and data isn't kept alive when the Storage tab isn't enabled.
+
+        * inspector/protocol/ApplicationCache.json:
+        Add `disable` command.
+
 2019-08-01  Keith Miller  <[email protected]>
 
         B3 should support tuple types

Modified: trunk/Source/_javascript_Core/inspector/protocol/ApplicationCache.json (248178 => 248179)


--- trunk/Source/_javascript_Core/inspector/protocol/ApplicationCache.json	2019-08-02 21:02:05 UTC (rev 248178)
+++ trunk/Source/_javascript_Core/inspector/protocol/ApplicationCache.json	2019-08-02 21:05:39 UTC (rev 248179)
@@ -48,6 +48,10 @@
             "description": "Enables application cache domain notifications."
         },
         {
+            "name": "disable",
+            "description": "Disable application cache domain notifications."
+        },
+        {
             "name": "getManifestForFrame",
             "description": "Returns manifest URL for document in the given frame.",
             "parameters": [

Modified: trunk/Source/WebCore/ChangeLog (248178 => 248179)


--- trunk/Source/WebCore/ChangeLog	2019-08-02 21:02:05 UTC (rev 248178)
+++ trunk/Source/WebCore/ChangeLog	2019-08-02 21:05:39 UTC (rev 248179)
@@ -1,5 +1,31 @@
 2019-08-02  Devin Rousso  <[email protected]>
 
+        Web Inspector: Storage: disable related agents when the tab is closed
+        https://bugs.webkit.org/show_bug.cgi?id=200117
+
+        Reviewed by Joseph Pecoraro.
+
+        Rework how `enable`/`disable` is used for storage-related agents so that events are not sent
+        and data isn't kept alive when the Storage tab isn't enabled.
+
+        Covered by existing tests.
+
+        * inspector/agents/InspectorApplicationCacheAgent.h:
+        * inspector/agents/InspectorApplicationCacheAgent.cpp:
+        (WebCore::InspectorApplicationCacheAgent::willDestroyFrontendAndBackend):
+        (WebCore::InspectorApplicationCacheAgent::enable):
+        (WebCore::InspectorApplicationCacheAgent::disable): Added.
+
+        * inspector/agents/InspectorDOMStorageAgent.cpp:
+        (WebCore::InspectorDOMStorageAgent::enable):
+        (WebCore::InspectorDOMStorageAgent::disable):
+
+        * inspector/agents/InspectorDatabaseAgent.cpp:
+        (WebCore::InspectorDatabaseAgent::enable):
+        (WebCore::InspectorDatabaseAgent::disable):
+
+2019-08-02  Devin Rousso  <[email protected]>
+
         Web Inspector: Timelines: Develop > Start Timeline Recording doesn't work when focused on a detached inspector window
         https://bugs.webkit.org/show_bug.cgi?id=200125
         <rdar://problem/53543008>

Modified: trunk/Source/WebCore/inspector/agents/InspectorApplicationCacheAgent.cpp (248178 => 248179)


--- trunk/Source/WebCore/inspector/agents/InspectorApplicationCacheAgent.cpp	2019-08-02 21:02:05 UTC (rev 248178)
+++ trunk/Source/WebCore/inspector/agents/InspectorApplicationCacheAgent.cpp	2019-08-02 21:05:39 UTC (rev 248179)
@@ -56,11 +56,17 @@
 
 void InspectorApplicationCacheAgent::willDestroyFrontendAndBackend(Inspector::DisconnectReason)
 {
-    m_instrumentingAgents.setInspectorApplicationCacheAgent(nullptr);
+    ErrorString unused;
+    disable(unused);
 }
 
-void InspectorApplicationCacheAgent::enable(ErrorString&)
+void InspectorApplicationCacheAgent::enable(ErrorString& errorString)
 {
+    if (m_instrumentingAgents.inspectorApplicationCacheAgent() == this) {
+        errorString = "ApplicationCacheAgent already enabled"_s;
+        return;
+    }
+
     m_instrumentingAgents.setInspectorApplicationCacheAgent(this);
 
     // We need to pass initial navigator.onOnline.
@@ -67,6 +73,16 @@
     networkStateChanged();
 }
 
+void InspectorApplicationCacheAgent::disable(ErrorString& errorString)
+{
+    if (m_instrumentingAgents.inspectorApplicationCacheAgent() != this) {
+        errorString = "ApplicationCacheAgent already disabled"_s;
+        return;
+    }
+
+    m_instrumentingAgents.setInspectorApplicationCacheAgent(nullptr);
+}
+
 void InspectorApplicationCacheAgent::updateApplicationCacheStatus(Frame* frame)
 {
     auto* pageAgent = m_instrumentingAgents.inspectorPageAgent();

Modified: trunk/Source/WebCore/inspector/agents/InspectorApplicationCacheAgent.h (248178 => 248179)


--- trunk/Source/WebCore/inspector/agents/InspectorApplicationCacheAgent.h	2019-08-02 21:02:05 UTC (rev 248178)
+++ trunk/Source/WebCore/inspector/agents/InspectorApplicationCacheAgent.h	2019-08-02 21:05:39 UTC (rev 248179)
@@ -57,6 +57,7 @@
 
     // ApplicationCacheBackendDispatcherHandler
     void enable(ErrorString&) override;
+    void disable(ErrorString&) override;
     void getFramesWithManifests(ErrorString&, RefPtr<JSON::ArrayOf<Inspector::Protocol::ApplicationCache::FrameWithManifest>>& result) override;
     void getManifestForFrame(ErrorString&, const String& frameId, String* manifestURL) override;
     void getApplicationCacheForFrame(ErrorString&, const String& frameId, RefPtr<Inspector::Protocol::ApplicationCache::ApplicationCache>&) override;

Modified: trunk/Source/WebCore/inspector/agents/InspectorDOMStorageAgent.cpp (248178 => 248179)


--- trunk/Source/WebCore/inspector/agents/InspectorDOMStorageAgent.cpp	2019-08-02 21:02:05 UTC (rev 248178)
+++ trunk/Source/WebCore/inspector/agents/InspectorDOMStorageAgent.cpp	2019-08-02 21:05:39 UTC (rev 248179)
@@ -72,13 +72,23 @@
     disable(unused);
 }
 
-void InspectorDOMStorageAgent::enable(ErrorString&)
+void InspectorDOMStorageAgent::enable(ErrorString& errorString)
 {
+    if (m_instrumentingAgents.inspectorDOMStorageAgent() != this) {
+        errorString = "DOMStorageAgent already disabled"_s;
+        return;
+    }
+
     m_instrumentingAgents.setInspectorDOMStorageAgent(this);
 }
 
-void InspectorDOMStorageAgent::disable(ErrorString&)
+void InspectorDOMStorageAgent::disable(ErrorString& errorString)
 {
+    if (m_instrumentingAgents.inspectorDOMStorageAgent() != this) {
+        errorString = "DOMStorageAgent already disabled"_s;
+        return;
+    }
+
     m_instrumentingAgents.setInspectorDOMStorageAgent(nullptr);
 }
 

Modified: trunk/Source/WebCore/inspector/agents/InspectorDatabaseAgent.cpp (248178 => 248179)


--- trunk/Source/WebCore/inspector/agents/InspectorDatabaseAgent.cpp	2019-08-02 21:02:05 UTC (rev 248178)
+++ trunk/Source/WebCore/inspector/agents/InspectorDatabaseAgent.cpp	2019-08-02 21:05:39 UTC (rev 248179)
@@ -232,10 +232,12 @@
     disable(unused);
 }
 
-void InspectorDatabaseAgent::enable(ErrorString&)
+void InspectorDatabaseAgent::enable(ErrorString& errorString)
 {
-    if (m_instrumentingAgents.inspectorDatabaseAgent() == this)
+    if (m_instrumentingAgents.inspectorDatabaseAgent() == this) {
+        errorString = "DatabaseAgent already enabled"_s;
         return;
+    }
 
     m_instrumentingAgents.setInspectorDatabaseAgent(this);
 
@@ -243,8 +245,13 @@
         didOpenDatabase(database.get());
 }
 
-void InspectorDatabaseAgent::disable(ErrorString&)
+void InspectorDatabaseAgent::disable(ErrorString& errorString)
 {
+    if (m_instrumentingAgents.inspectorDatabaseAgent() != this) {
+        errorString = "DatabaseAgent already disabled"_s;
+        return;
+    }
+
     m_instrumentingAgents.setInspectorDatabaseAgent(nullptr);
 
     m_resources.clear();

Modified: trunk/Source/WebInspectorUI/ChangeLog (248178 => 248179)


--- trunk/Source/WebInspectorUI/ChangeLog	2019-08-02 21:02:05 UTC (rev 248178)
+++ trunk/Source/WebInspectorUI/ChangeLog	2019-08-02 21:05:39 UTC (rev 248179)
@@ -1,5 +1,92 @@
 2019-08-02  Devin Rousso  <[email protected]>
 
+        Web Inspector: Storage: disable related agents when the tab is closed
+        https://bugs.webkit.org/show_bug.cgi?id=200117
+
+        Reviewed by Joseph Pecoraro.
+
+        Rework how `enable`/`disable` is used for storage-related agents so that events are not sent
+        and data isn't kept alive when the Storage tab isn't enabled.
+
+        * UserInterface/Controllers/ApplicationCacheManager.js:
+        (WI.ApplicationCacheManager):
+        (WI.ApplicationCacheManage.prototype.get domains): Added.
+        (WI.ApplicationCacheManage.prototype.activateExtraDomain): Added.
+        (WI.ApplicationCacheManager.prototype.initializeTarget):
+        (WI.ApplicationCacheManager.prototype.enable): Added.
+        (WI.ApplicationCacheManager.prototype.disable): Added.
+        (WI.ApplicationCacheManager.prototype.networkStateUpdated):
+        (WI.ApplicationCacheManager.prototype.applicationCacheStatusUpdated):
+        (WI.ApplicationCacheManager.prototype._reset): Added.
+        (WI.ApplicationCacheManager.prototype._mainResourceDidChange):
+        (WI.ApplicationCacheManager.prototype._manifestForFrameLoaded):
+        (WI.ApplicationCacheManager.prototype._framesWithManifestsLoaded):
+        (WI.ApplicationCacheManager.prototype.initialize): Deleted.
+
+        * UserInterface/Controllers/DOMStorageManager.js:
+        (WI.DOMStorageManager):
+        (WI.DOMStorageManager.prototype.get domains): Added.
+        (WI.DOMStorageManager.prototype.activateExtraDomain): Added.
+        (WI.DOMStorageManager.prototype.initializeTarget):
+        (WI.DOMStorageManager.prototype.enable): Added.
+        (WI.DOMStorageManager.prototype.disable): Added.
+        (WI.DOMStorageManager.prototype.itemsCleared):
+        (WI.DOMStorageManager.prototype.itemRemoved):
+        (WI.DOMStorageManager.prototype.itemAdded):
+        (WI.DOMStorageManager.prototype.itemUpdated):
+        (WI.DOMStorageManager.prototype.inspectDOMStorage):
+        (WI.DOMStorageManager.prototype._reset): Added.
+        (WI.DOMStorageManager.prototype._addDOMStorageIfNeeded):
+        (WI.DOMStorageManager.prototype._addCookieStorageIfNeeded):
+        (WI.DOMStorageManager.prototype._mainResourceDidChange):
+        (WI.DOMStorageManager.prototype.initialize): Deleted.
+        (WI.DOMStorageManager.prototype.domStorageWasAdded): Deleted.
+
+        * UserInterface/Controllers/DatabaseManager.js:
+        (WI.DatabaseManager):
+        (WI.DatabaseManager.prototype.get domains): Added.
+        (WI.DatabaseManager.prototype.activateExtraDomain): Added.
+        (WI.DatabaseManager.prototype.initializeTarget):
+        (WI.DatabaseManager.prototype.enable): Added.
+        (WI.DatabaseManager.prototype.disable): Added.
+        (WI.DatabaseManager.prototype.databaseWasAdded):
+        (WI.DatabaseManager.prototype.inspectDatabase):
+        (WI.DatabaseManager.prototype._reset): Added.
+        (WI.DatabaseManager.prototype._mainResourceDidChange):
+        (WI.DatabaseManager.prototype.initialize): Deleted.
+
+        * UserInterface/Controllers/IndexedDBManager.js:
+        (WI.IndexedDBManager):
+        (WI.IndexedDBManager.prototype.get domains): Added.
+        (WI.IndexedDBManager.prototype.activateExtraDomain): Added.
+        (WI.IndexedDBManager.prototype.initializeTarget):
+        (WI.IndexedDBManager.prototype.enable): Added.
+        (WI.IndexedDBManager.prototype.disable): Added.
+        (WI.IndexedDBManager.prototype.clearObjectStore):
+        (WI.IndexedDBManager.prototype._reset): Added.
+        (WI.IndexedDBManager.prototype._mainResourceDidChange):
+        (WI.IndexedDBManager.prototype.initialize): Deleted.
+
+        * UserInterface/Controllers/AppController.js:
+        (WI.AppController.prototype.activateExtraDomains):
+        * UserInterface/Controllers/CanvasManager.js:
+        (WI.CanvasManager.prototype.get domains): Added.
+        (WI.CanvasManager.prototype.activateExtraDomain): Added.
+        Only call `enable` on any extra agents if the domain is not controlled by a manager.
+
+        * UserInterface/Views/StorageTabContentView.js:
+        (WI.StorageTabContentView):
+        (WI.StorageTabContentView.static isTabAllowed):
+        (WI.StorageTabContentView.prototype.canShowRepresentedObject):
+        (WI.StorageTabContentView.prototype.closed): Added.
+
+        * UserInterface/Test.html:
+        * UserInterface/Test/Test.js:
+        (WI.loaded):
+        (WI.contentLoaded):
+
+2019-08-02  Devin Rousso  <[email protected]>
+
         Web Inspector: Timelines: Develop > Start Timeline Recording doesn't work when focused on a detached inspector window
         https://bugs.webkit.org/show_bug.cgi?id=200125
         <rdar://problem/53543008>

Modified: trunk/Source/WebInspectorUI/UserInterface/Controllers/AppController.js (248178 => 248179)


--- trunk/Source/WebInspectorUI/UserInterface/Controllers/AppController.js	2019-08-02 21:02:05 UTC (rev 248178)
+++ trunk/Source/WebInspectorUI/UserInterface/Controllers/AppController.js	2019-08-02 21:05:39 UTC (rev 248179)
@@ -72,10 +72,15 @@
 
         for (let domain of domains) {
             let agent = InspectorBackend.activateDomain(domain);
-            if (agent.enable)
-                agent.enable();
+
             for (let target of WI.targets)
                 target.activateExtraDomain(domain);
+
+            let manager = WI.managers.find((manager) => manager.domains && manager.domains.includes(domain));
+            if (manager)
+                manager.activateExtraDomain(domain);
+            else if (agent.enable)
+                agent.enable();
         }
 
         // FIXME: all code within WI.activateExtraDomains should be distributed elsewhere.

Modified: trunk/Source/WebInspectorUI/UserInterface/Controllers/ApplicationCacheManager.js (248178 => 248179)


--- trunk/Source/WebInspectorUI/UserInterface/Controllers/ApplicationCacheManager.js	2019-08-02 21:02:05 UTC (rev 248178)
+++ trunk/Source/WebInspectorUI/UserInterface/Controllers/ApplicationCacheManager.js	2019-08-02 21:05:39 UTC (rev 248179)
@@ -31,12 +31,20 @@
     {
         super();
 
-        WI.Frame.addEventListener(WI.Frame.Event.MainResourceDidChange, this._mainResourceDidChange, this);
-        WI.Frame.addEventListener(WI.Frame.Event.ChildFrameWasRemoved, this._childFrameWasRemoved, this);
+        this._enabled = false;
+        this._reset();
+    }
 
-        this._online = true;
+    // Agent
 
-        this.initialize();
+    get domains() { return ["ApplicationCache"]; }
+
+    activateExtraDomain(domain)
+    {
+        console.assert(domain === "ApplicationCache");
+
+        for (let target of WI.targets)
+            this.initializeTarget(target);
     }
 
     // Target
@@ -43,6 +51,9 @@
 
     initializeTarget(target)
     {
+        if (!this._enabled)
+            return;
+
         if (target.ApplicationCacheAgent) {
             target.ApplicationCacheAgent.enable();
             target.ApplicationCacheAgent.getFramesWithManifests(this._framesWithManifestsLoaded.bind(this));
@@ -51,10 +62,7 @@
 
     // Public
 
-    initialize()
-    {
-        this._applicationCacheObjects = {};
-    }
+    get online() { return this._online; }
 
     get applicationCacheObjects()
     {
@@ -64,29 +72,42 @@
         return applicationCacheObjects;
     }
 
-    networkStateUpdated(isNowOnline)
+    enable()
     {
-        this._online = isNowOnline;
+        console.assert(!this._enabled);
 
-        this.dispatchEventToListeners(WI.ApplicationCacheManager.Event.NetworkStateUpdated, {online: this._online});
-    }
+        this._enabled = true;
 
-    get online()
-    {
-        return this._online;
+        this._reset();
+
+        for (let target of WI.targets)
+            this.initializeTarget(target);
+
+        WI.Frame.addEventListener(WI.Frame.Event.MainResourceDidChange, this._mainResourceDidChange, this);
+        WI.Frame.addEventListener(WI.Frame.Event.ChildFrameWasRemoved, this._childFrameWasRemoved, this);
     }
 
-    applicationCacheStatusUpdated(frameId, manifestURL, status)
+    disable()
     {
-        var frame = WI.networkManager.frameForIdentifier(frameId);
-        if (!frame)
-            return;
+        console.assert(this._enabled);
 
-        this._frameManifestUpdated(frame, manifestURL, status);
+        this._enabled = false;
+
+        for (let target of WI.targets) {
+            // COMPATIBILITY (iOS 13): ApplicationCache.disable did not exist yet.
+            if (target.ApplicationCacheAgent && target.ApplicationCacheAgent.disable)
+                target.ApplicationCacheAgent.disable();
+        }
+
+        WI.Frame.removeEventListener(null, null, this);
+
+        this._reset();
     }
 
     requestApplicationCache(frame, callback)
     {
+        console.assert(this._enabled);
+
         function callbackWrapper(error, applicationCache)
         {
             if (error) {
@@ -100,18 +121,44 @@
         ApplicationCacheAgent.getApplicationCacheForFrame(frame.id, callbackWrapper);
     }
 
+    // ApplicationCacheObserver
+
+    networkStateUpdated(isNowOnline)
+    {
+        console.assert(this._enabled);
+
+        this._online = isNowOnline;
+
+        this.dispatchEventToListeners(WI.ApplicationCacheManager.Event.NetworkStateUpdated, {online: this._online});
+    }
+
+    applicationCacheStatusUpdated(frameId, manifestURL, status)
+    {
+        console.assert(this._enabled);
+
+        let frame = WI.networkManager.frameForIdentifier(frameId);
+        if (!frame)
+            return;
+
+        this._frameManifestUpdated(frame, manifestURL, status);
+    }
+
     // Private
 
+    _reset()
+    {
+        this._online = true;
+        this._applicationCacheObjects = {};
+
+        this.dispatchEventToListeners(WI.ApplicationCacheManager.Event.Cleared);
+    }
+
     _mainResourceDidChange(event)
     {
         console.assert(event.target instanceof WI.Frame);
 
         if (event.target.isMainFrame()) {
-            // If we are dealing with the main frame, we want to clear our list of objects, because we are navigating to a new page.
-            this.initialize();
-
-            this.dispatchEventToListeners(WI.ApplicationCacheManager.Event.Cleared);
-
+            this._reset();
             return;
         }
 
@@ -126,9 +173,14 @@
 
     _manifestForFrameLoaded(frameId, error, manifestURL)
     {
-        if (error)
+        if (error) {
+            WI.reportInternalError(error);
             return;
+        }
 
+        if (!this._enabled)
+            return;
+
         var frame = WI.networkManager.frameForIdentifier(frameId);
         if (!frame)
             return;
@@ -139,9 +191,14 @@
 
     _framesWithManifestsLoaded(error, framesWithManifests)
     {
-        if (error)
+        if (error) {
+            WI.reportInternalError(error);
             return;
+        }
 
+        if (!this._enabled)
+            return;
+
         for (var i = 0; i < framesWithManifests.length; ++i) {
             var frame = WI.networkManager.frameForIdentifier(framesWithManifests[i].frameId);
             if (!frame)

Modified: trunk/Source/WebInspectorUI/UserInterface/Controllers/CanvasManager.js (248178 => 248179)


--- trunk/Source/WebInspectorUI/UserInterface/Controllers/CanvasManager.js	2019-08-02 21:02:05 UTC (rev 248178)
+++ trunk/Source/WebInspectorUI/UserInterface/Controllers/CanvasManager.js	2019-08-02 21:05:39 UTC (rev 248179)
@@ -39,6 +39,18 @@
         WI.Frame.addEventListener(WI.Frame.Event.MainResourceDidChange, this._mainResourceDidChange, this);
     }
 
+    // Agent
+
+    get domains() { return ["Canvas"]; }
+
+    activateExtraDomain(domain)
+    {
+        console.assert(domain === "Canvas");
+
+        for (let target of WI.targets)
+            this.initializeTarget(target);
+    }
+
     // Target
 
     initializeTarget(target)

Modified: trunk/Source/WebInspectorUI/UserInterface/Controllers/DOMStorageManager.js (248178 => 248179)


--- trunk/Source/WebInspectorUI/UserInterface/Controllers/DOMStorageManager.js	2019-08-02 21:02:05 UTC (rev 248178)
+++ trunk/Source/WebInspectorUI/UserInterface/Controllers/DOMStorageManager.js	2019-08-02 21:05:39 UTC (rev 248179)
@@ -32,10 +32,20 @@
     {
         super();
 
-        WI.Frame.addEventListener(WI.Frame.Event.MainResourceDidChange, this._mainResourceDidChange, this);
-        WI.Frame.addEventListener(WI.Frame.Event.SecurityOriginDidChange, this._securityOriginDidChange, this);
+        this._enabled = false;
+        this._reset();
+    }
 
-        this.initialize();
+    // Agent
+
+    get domains() { return ["DOMStorage"]; }
+
+    activateExtraDomain(domain)
+    {
+        console.assert(domain === "DOMStorage");
+
+        for (let target of WI.targets)
+            this.initializeTarget(target);
     }
 
     // Target
@@ -42,6 +52,9 @@
 
     initializeTarget(target)
     {
+        if (!this._enabled)
+            return;
+
         if (target.DOMStorageAgent)
             target.DOMStorageAgent.enable();
     }
@@ -48,17 +61,8 @@
 
     // Public
 
-    initialize()
-    {
-        this._domStorageObjects = [];
-        this._cookieStorageObjects = {};
-    }
+    get domStorageObjects() { return this._domStorageObjects; }
 
-    get domStorageObjects()
-    {
-        return this._domStorageObjects;
-    }
-
     get cookieStorageObjects()
     {
         var cookieStorageObjects = [];
@@ -67,17 +71,42 @@
         return cookieStorageObjects;
     }
 
-    domStorageWasAdded(id, host, isLocalStorage)
+    enable()
     {
-        var domStorage = new WI.DOMStorageObject(id, host, isLocalStorage);
+        console.assert(!this._enabled);
 
-        this._domStorageObjects.push(domStorage);
-        this.dispatchEventToListeners(WI.DOMStorageManager.Event.DOMStorageObjectWasAdded, {domStorage});
+        this._enabled = true;
+
+        this._reset();
+
+        for (let target of WI.targets)
+            this.initializeTarget(target);
+
+        WI.Frame.addEventListener(WI.Frame.Event.MainResourceDidChange, this._mainResourceDidChange, this);
+        WI.Frame.addEventListener(WI.Frame.Event.SecurityOriginDidChange, this._securityOriginDidChange, this);
     }
 
+    disable()
+    {
+        console.assert(this._enabled);
+
+        this._enabled = false;
+
+        for (let target of WI.targets) {
+            if (target.DOMStorageAgent)
+                target.DOMStorageAgent.disable();
+        }
+
+        WI.Frame.removeEventListener(null, null, this);
+
+        this._reset();
+    }
+
+    // DOMStorageObserver
+
     itemsCleared(storageId)
     {
-        // Called from WI.DOMStorageObserver.
+        console.assert(this._enabled);
 
         let domStorage = this._domStorageForIdentifier(storageId);
         if (domStorage)
@@ -86,7 +115,7 @@
 
     itemRemoved(storageId, key)
     {
-        // Called from WI.DOMStorageObserver.
+        console.assert(this._enabled);
 
         let domStorage = this._domStorageForIdentifier(storageId);
         if (domStorage)
@@ -95,7 +124,7 @@
 
     itemAdded(storageId, key, value)
     {
-        // Called from WI.DOMStorageObserver.
+        console.assert(this._enabled);
 
         let domStorage = this._domStorageForIdentifier(storageId);
         if (domStorage)
@@ -104,7 +133,7 @@
 
     itemUpdated(storageId, key, oldValue, value)
     {
-        // Called from WI.DOMStorageObserver.
+        console.assert(this._enabled);
 
         let domStorage = this._domStorageForIdentifier(storageId);
         if (domStorage)
@@ -113,6 +142,10 @@
 
     inspectDOMStorage(id)
     {
+        // Called from WI.InspectorObserver.
+
+        console.assert(this._enabled);
+
         var domStorage = this._domStorageForIdentifier(id);
         console.assert(domStorage);
         if (!domStorage)
@@ -122,6 +155,20 @@
 
     // Private
 
+    _reset()
+    {
+        this._domStorageObjects = [];
+        this._cookieStorageObjects = {};
+
+        this.dispatchEventToListeners(DOMStorageManager.Event.Cleared);
+
+        let mainFrame = WI.networkManager.mainFrame;
+        if (mainFrame) {
+            this._addDOMStorageIfNeeded(mainFrame);
+            this._addCookieStorageIfNeeded(mainFrame);
+        }
+    }
+
     _domStorageForIdentifier(id)
     {
         for (var storageObject of this._domStorageObjects) {
@@ -133,20 +180,43 @@
         return null;
     }
 
-    _mainResourceDidChange(event)
+    _addDOMStorageIfNeeded(frame)
     {
-        console.assert(event.target instanceof WI.Frame);
+        if (!this._enabled)
+            return;
 
-        if (event.target.isMainFrame()) {
-            // If we are dealing with the main frame, we want to clear our list of objects, because we are navigating to a new page.
-            this.initialize();
-            this.dispatchEventToListeners(WI.DOMStorageManager.Event.Cleared);
+        if (!window.DOMStorageAgent)
+            return;
 
-            this._addDOMStorageIfNeeded(event.target);
-        }
+        // Don't show storage if we don't have a security origin (about:blank).
+        if (!frame.securityOrigin || frame.securityOrigin === "://")
+            return;
 
+        // FIXME: Consider passing the other parts of the origin along.
+
+        let addDOMStorage = (isLocalStorage) => {
+            let identifier = {securityOrigin: frame.securityOrigin, isLocalStorage};
+            if (this._domStorageForIdentifier(identifier))
+                return;
+
+            let domStorage = new WI.DOMStorageObject(identifier, frame.mainResource.urlComponents.host, identifier.isLocalStorage);
+            this._domStorageObjects.push(domStorage);
+            this.dispatchEventToListeners(DOMStorageManager.Event.DOMStorageObjectWasAdded, {domStorage});
+        };
+        addDOMStorage(true);
+        addDOMStorage(false);
+    }
+
+    _addCookieStorageIfNeeded(frame)
+    {
+        if (!this._enabled)
+            return;
+
+        if (!window.DOMStorageAgent)
+            return;
+
         // Add the host of the frame that changed the main resource to the list of hosts there could be cookies for.
-        var host = parseURL(event.target.url).host;
+        let host = parseURL(frame.url).host;
         if (!host)
             return;
 
@@ -157,24 +227,16 @@
         this.dispatchEventToListeners(WI.DOMStorageManager.Event.CookieStorageObjectWasAdded, {cookieStorage: this._cookieStorageObjects[host]});
     }
 
-    _addDOMStorageIfNeeded(frame)
+    _mainResourceDidChange(event)
     {
-        if (!window.DOMStorageAgent)
-            return;
+        console.assert(event.target instanceof WI.Frame);
 
-        // Don't show storage if we don't have a security origin (about:blank).
-        if (!frame.securityOrigin || frame.securityOrigin === "://")
+        if (event.target.isMainFrame()) {
+            this._reset();
             return;
+        }
 
-        // FIXME: Consider passing the other parts of the origin along to domStorageWasAdded.
-
-        var localStorageIdentifier = {securityOrigin: frame.securityOrigin, isLocalStorage: true};
-        if (!this._domStorageForIdentifier(localStorageIdentifier))
-            this.domStorageWasAdded(localStorageIdentifier, frame.mainResource.urlComponents.host, true);
-
-        var sessionStorageIdentifier = {securityOrigin: frame.securityOrigin, isLocalStorage: false};
-        if (!this._domStorageForIdentifier(sessionStorageIdentifier))
-            this.domStorageWasAdded(sessionStorageIdentifier, frame.mainResource.urlComponents.host, false);
+        this._addCookieStorageIfNeeded(event.target);
     }
 
     _securityOriginDidChange(event)

Modified: trunk/Source/WebInspectorUI/UserInterface/Controllers/DatabaseManager.js (248178 => 248179)


--- trunk/Source/WebInspectorUI/UserInterface/Controllers/DatabaseManager.js	2019-08-02 21:02:05 UTC (rev 248178)
+++ trunk/Source/WebInspectorUI/UserInterface/Controllers/DatabaseManager.js	2019-08-02 21:05:39 UTC (rev 248179)
@@ -32,9 +32,20 @@
     {
         super();
 
-        WI.Frame.addEventListener(WI.Frame.Event.MainResourceDidChange, this._mainResourceDidChange, this);
+        this._enabled = false;
+        this._reset();
+    }
 
-        this.initialize();
+    // Agent
+
+    get domains() { return ["Database"]; }
+
+    activateExtraDomain(domain)
+    {
+        console.assert(domain === "Database");
+
+        for (let target of WI.targets)
+            this.initializeTarget(target);
     }
 
     // Target
@@ -41,6 +52,9 @@
 
     initializeTarget(target)
     {
+        if (!this._enabled)
+            return;
+
         if (target.DatabaseAgent)
             target.DatabaseAgent.enable();
     }
@@ -47,19 +61,43 @@
 
     // Public
 
-    initialize()
+    get databases() { return this._databaseObjects; }
+
+    enable()
     {
-        this._databaseObjects = [];
+        console.assert(!this._enabled);
+
+        this._enabled = true;
+
+        this._reset();
+
+        for (let target of WI.targets)
+            this.initializeTarget(target);
+
+        WI.Frame.addEventListener(WI.Frame.Event.MainResourceDidChange, this._mainResourceDidChange, this);
     }
 
-    get databases()
+    disable()
     {
-        return this._databaseObjects;
+        console.assert(this._enabled);
+
+        this._enabled = false;
+
+        for (let target of WI.targets) {
+            if (target.DatabaseAgent)
+                target.DatabaseAgent.disable();
+        }
+
+        WI.Frame.removeEventListener(null, null, this);
+
+        this._reset();
     }
 
+    // DatabaseObserver
+
     databaseWasAdded(id, host, name, version)
     {
-        // Called from WI.DatabaseObserver.
+        console.assert(this._enabled);
 
         var database = new WI.DatabaseObject(id, host, name, version);
 
@@ -67,8 +105,12 @@
         this.dispatchEventToListeners(WI.DatabaseManager.Event.DatabaseWasAdded, {database});
     }
 
+    // InspectorObserver
+
     inspectDatabase(id)
     {
+        console.assert(this._enabled);
+
         var database = this._databaseForIdentifier(id);
         console.assert(database);
         if (!database)
@@ -78,15 +120,19 @@
 
     // Private
 
+    _reset()
+    {
+        this._databaseObjects = [];
+
+        this.dispatchEventToListeners(WI.DatabaseManager.Event.Cleared);
+    }
+
     _mainResourceDidChange(event)
     {
         console.assert(event.target instanceof WI.Frame);
 
-        if (event.target.isMainFrame()) {
-            // If we are dealing with the main frame, we want to clear our list of objects, because we are navigating to a new page.
-            this.initialize();
-            this.dispatchEventToListeners(WI.DatabaseManager.Event.Cleared);
-        }
+        if (event.target.isMainFrame())
+            this._reset();
     }
 
     _databaseForIdentifier(id)

Modified: trunk/Source/WebInspectorUI/UserInterface/Controllers/IndexedDBManager.js (248178 => 248179)


--- trunk/Source/WebInspectorUI/UserInterface/Controllers/IndexedDBManager.js	2019-08-02 21:02:05 UTC (rev 248178)
+++ trunk/Source/WebInspectorUI/UserInterface/Controllers/IndexedDBManager.js	2019-08-02 21:05:39 UTC (rev 248179)
@@ -32,10 +32,20 @@
     {
         super();
 
-        WI.Frame.addEventListener(WI.Frame.Event.MainResourceDidChange, this._mainResourceDidChange, this);
-        WI.Frame.addEventListener(WI.Frame.Event.SecurityOriginDidChange, this._securityOriginDidChange, this);
+        this._enabled = false;
+        this._reset();
+    }
 
-        this.initialize();
+    // Agent
+
+    get domains() { return ["IndexedDB"]; }
+
+    activateExtraDomain(domain)
+    {
+        console.assert(domain === "IndexedDB");
+
+        for (let target of WI.targets)
+            this.initializeTarget(target);
     }
 
     // Target
@@ -42,6 +52,9 @@
 
     initializeTarget(target)
     {
+        if (!this._enabled)
+            return;
+
         if (target.IndexedDBAgent)
             target.IndexedDBAgent.enable();
     }
@@ -48,18 +61,42 @@
 
     // Public
 
-    initialize()
+    get indexedDatabases() { return this._indexedDatabases; }
+
+    enable()
     {
-        this._indexedDatabases = [];
+        console.assert(!this._enabled);
+
+        this._enabled = true;
+
+        this._reset();
+
+        for (let target of WI.targets)
+            this.initializeTarget(target);
+
+        WI.Frame.addEventListener(WI.Frame.Event.MainResourceDidChange, this._mainResourceDidChange, this);
+        WI.Frame.addEventListener(WI.Frame.Event.SecurityOriginDidChange, this._securityOriginDidChange, this);
     }
 
-    get indexedDatabases()
+    disable()
     {
-        return this._indexedDatabases;
+        console.assert(this._enabled);
+
+        this._enabled = false;
+
+        for (let target of WI.targets) {
+            if (target.IndexedDBAgent)
+                target.IndexedDBAgent.disable();
+        }
+
+        WI.Frame.removeEventListener(null, null, this);
+
+        this._reset();
     }
 
     requestIndexedDatabaseData(objectStore, objectStoreIndex, startEntryIndex, maximumEntryCount, callback)
     {
+        console.assert(this._enabled);
         console.assert(window.IndexedDBAgent);
         console.assert(objectStore);
         console.assert(callback);
@@ -98,6 +135,8 @@
 
     clearObjectStore(objectStore)
     {
+        console.assert(this._enabled);
+
         let securityOrigin = objectStore.parentDatabase.securityOrigin;
         let databaseName = objectStore.parentDatabase.name;
         let objectStoreName = objectStore.name;
@@ -107,21 +146,21 @@
 
     // Private
 
-    _mainResourceDidChange(event)
+    _reset()
     {
-        console.assert(event.target instanceof WI.Frame);
+        this._indexedDatabases = [];
+        this.dispatchEventToListeners(WI.IndexedDBManager.Event.Cleared);
 
-        if (event.target.isMainFrame()) {
-            // If we are dealing with the main frame, we want to clear our list of objects, because we are navigating to a new page.
-            this.initialize();
-            this.dispatchEventToListeners(WI.IndexedDBManager.Event.Cleared);
-
-            this._addIndexedDBDatabasesIfNeeded(event.target);
-        }
+        let mainFrame = WI.networkManager.mainFrame;
+        if (mainFrame)
+            this._addIndexedDBDatabasesIfNeeded(mainFrame);
     }
 
     _addIndexedDBDatabasesIfNeeded(frame)
     {
+        if (!this._enabled)
+            return;
+
         if (!window.IndexedDBAgent)
             return;
 
@@ -183,6 +222,14 @@
         IndexedDBAgent.requestDatabaseNames(securityOrigin, processDatabaseNames.bind(this));
     }
 
+    _mainResourceDidChange(event)
+    {
+        console.assert(event.target instanceof WI.Frame);
+
+        if (event.target.isMainFrame())
+            this._reset();
+    }
+
     _securityOriginDidChange(event)
     {
         console.assert(event.target instanceof WI.Frame);

Modified: trunk/Source/WebInspectorUI/UserInterface/Test/Test.js (248178 => 248179)


--- trunk/Source/WebInspectorUI/UserInterface/Test/Test.js	2019-08-02 21:02:05 UTC (rev 248178)
+++ trunk/Source/WebInspectorUI/UserInterface/Test/Test.js	2019-08-02 21:05:39 UTC (rev 248179)
@@ -36,9 +36,11 @@
     InspectorBackend.registerDebuggerDispatcher(new WI.DebuggerObserver);
     InspectorBackend.registerHeapDispatcher(new WI.HeapObserver);
     InspectorBackend.registerMemoryDispatcher(new WI.MemoryObserver);
+    InspectorBackend.registerDatabaseDispatcher(new WI.DatabaseObserver);
     InspectorBackend.registerDOMStorageDispatcher(new WI.DOMStorageObserver);
+    InspectorBackend.registerApplicationCacheDispatcher(new WI.ApplicationCacheObserver);
+    InspectorBackend.registerCPUProfilerDispatcher(new WI.CPUProfilerObserver);
     InspectorBackend.registerScriptProfilerDispatcher(new WI.ScriptProfilerObserver);
-    InspectorBackend.registerCPUProfilerDispatcher(new WI.CPUProfilerObserver);
     InspectorBackend.registerTimelineDispatcher(new WI.TimelineObserver);
     InspectorBackend.registerCSSDispatcher(new WI.CSSObserver);
     InspectorBackend.registerLayerTreeDispatcher(new WI.LayerTreeObserver);
@@ -51,6 +53,8 @@
         WI.targetManager = new WI.TargetManager,
         WI.networkManager = new WI.NetworkManager,
         WI.domStorageManager = new WI.DOMStorageManager,
+        WI.databaseManager = new WI.DatabaseManager,
+        WI.indexedDBManager = new WI.IndexedDBManager,
         WI.domManager = new WI.DOMManager,
         WI.cssManager = new WI.CSSManager,
         WI.consoleManager = new WI.ConsoleManager,
@@ -57,6 +61,7 @@
         WI.runtimeManager = new WI.RuntimeManager,
         WI.heapManager = new WI.HeapManager,
         WI.memoryManager = new WI.MemoryManager,
+        WI.applicationCacheManager = new WI.ApplicationCacheManager,
         WI.timelineManager = new WI.TimelineManager,
         WI.auditManager = new WI.AuditManager,
         WI.debuggerManager = new WI.DebuggerManager,
@@ -127,7 +132,11 @@
 WI.contentLoaded = function()
 {
     // Things that would normally get called by the UI, that we still want to do in tests.
+    WI.applicationCacheManager.enable();
     WI.canvasManager.enable();
+    WI.domStorageManager.enable();
+    WI.databaseManager.enable();
+    WI.indexedDBManager.enable();
 
     // Signal that the frontend is now ready to receive messages.
     InspectorFrontendAPI.loadCompleted();

Modified: trunk/Source/WebInspectorUI/UserInterface/Test.html (248178 => 248179)


--- trunk/Source/WebInspectorUI/UserInterface/Test.html	2019-08-02 21:02:05 UTC (rev 248178)
+++ trunk/Source/WebInspectorUI/UserInterface/Test.html	2019-08-02 21:05:39 UTC (rev 248179)
@@ -83,6 +83,7 @@
     <script src=""
 
     <script src=""
+    <script src=""
     <script src=""
     <script src=""
     <script src=""
@@ -89,8 +90,10 @@
     <script src=""
     <script src=""
     <script src=""
+    <script src=""
     <script src=""
     <script src=""
+    <script src=""
     <script src=""
     <script src=""
     <script src=""
@@ -232,6 +235,7 @@
     <script src=""
 
     <script src=""
+    <script src=""
     <script src=""
     <script src=""
     <script src=""
@@ -239,9 +243,11 @@
     <script src=""
     <script src=""
     <script src=""
+    <script src=""
     <script src=""
     <script src=""
     <script src=""
+    <script src=""
     <script src=""
     <script src=""
     <script src=""

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/StorageTabContentView.js (248178 => 248179)


--- trunk/Source/WebInspectorUI/UserInterface/Views/StorageTabContentView.js	2019-08-02 21:02:05 UTC (rev 248178)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/StorageTabContentView.js	2019-08-02 21:05:39 UTC (rev 248179)
@@ -31,6 +31,11 @@
         let detailsSidebarPanelConstructors = [WI.ApplicationCacheDetailsSidebarPanel, WI.IndexedDatabaseDetailsSidebarPanel];
 
         super(identifier || "storage", "storage", tabBarItem, WI.StorageSidebarPanel, detailsSidebarPanelConstructors);
+
+        WI.applicationCacheManager.enable();
+        WI.databaseManager.enable();
+        WI.domStorageManager.enable();
+        WI.indexedDBManager.enable();
     }
 
     static tabInfo()
@@ -43,7 +48,7 @@
 
     static isTabAllowed()
     {
-        return !!window.DOMStorageAgent || !!window.DatabaseAgent || !!window.IndexedDBAgent;
+        return !!(window.ApplicationCacheAgent || window.DOMStorageAgent || window.DatabaseAgent || window.IndexedDBAgent);
     }
 
     // Public
@@ -60,11 +65,25 @@
 
     canShowRepresentedObject(representedObject)
     {
-        return representedObject instanceof WI.DOMStorageObject || representedObject instanceof WI.CookieStorageObject ||
-            representedObject instanceof WI.DatabaseTableObject || representedObject instanceof WI.DatabaseObject ||
-            representedObject instanceof WI.ApplicationCacheFrame || representedObject instanceof WI.IndexedDatabaseObjectStore ||
-            representedObject instanceof WI.IndexedDatabase || representedObject instanceof WI.IndexedDatabaseObjectStoreIndex;
+        return representedObject instanceof WI.ApplicationCacheFrame
+            || representedObject instanceof WI.CookieStorageObject
+            || representedObject instanceof WI.DOMStorageObject
+            || representedObject instanceof WI.DatabaseObject
+            || representedObject instanceof WI.DatabaseTableObject
+            || representedObject instanceof WI.IndexedDatabase
+            || representedObject instanceof WI.IndexedDatabaseObjectStore
+            || representedObject instanceof WI.IndexedDatabaseObjectStoreIndex;
     }
+
+    closed()
+    {
+        WI.applicationCacheManager.disable();
+        WI.databaseManager.disable();
+        WI.domStorageManager.disable();
+        WI.indexedDBManager.disable();
+
+        super.closed();
+    }
 };
 
 WI.StorageTabContentView.Type = "storage";
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to