ServiceWorker Inspector: Various issues inspecting service worker on mobile.twitter.com
authorjoepeck@webkit.org <joepeck@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 8 Dec 2017 23:03:58 +0000 (23:03 +0000)
committerjoepeck@webkit.org <joepeck@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 8 Dec 2017 23:03:58 +0000 (23:03 +0000)
https://bugs.webkit.org/show_bug.cgi?id=180520
<rdar://problem/35900764>

Reviewed by Brian Burg.

Source/JavaScriptCore:

* inspector/protocol/ServiceWorker.json:
Include content script content in the initialization info.

Source/WebCore:

* inspector/agents/worker/ServiceWorkerAgent.cpp:
(WebCore::ServiceWorkerAgent::getInitializationInfo):
* inspector/agents/worker/ServiceWorkerAgent.h:
Add initial script content to initialization so we always at least have main resource content.

Source/WebInspectorUI:

* UserInterface/Main.html:
* UserInterface/Test.html:
New files.

* UserInterface/Controllers/SourceMapManager.js:
(WI.SourceMapManager.prototype._loadAndParseSourceMap):
* UserInterface/Models/SourceMapResource.js:
(WI.SourceMapResource.prototype.requestContentFromBackend):
A ServiceWorker inspector doesn't have a main frame, fall back to an
empty frameIdentifier, it is ignored by the Service Worker network agent.

* UserInterface/Base/Main.js:
Handle a Service Worker inspector where there is no frame. This can
search the main resource's resource collection.

* UserInterface/Controllers/DebuggerManager.js:
(WI.DebuggerManager.prototype.scriptDidParse):

* UserInterface/Controllers/FrameResourceManager.js:
(WI.FrameResourceManager.prototype.resourceRequestDidFailLoading):
In Service Workers the resources won't have a parent frame.

(WI.FrameResourceManager.prototype._addNewResourceToFrameOrTarget):
(WI.FrameResourceManager.prototype._processServiceWorkerInitializationInfo):
In service worker initialization fallback to using the script content
as the main resource if we didn't get a Script that actually includes it.

* UserInterface/Models/LocalScript.js:
(WI.LocalScript):
(WI.LocalScript.prototype.requestContentFromBackend):
A way to create a local Script with content.

* UserInterface/Views/SourceCodeTextEditor.js:
(WI.SourceCodeTextEditor.prototype.get _supportsDebugging):
Disallow breakpoints in a LocalScript since we have no way to tell the
backend where to set breakpoints.

* UserInterface/Models/TextRange.js:
(WI.TextRange.fromText):
Add a way to get a TextRange from static text.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@225709 268f45cc-cd09-0410-ab3c-d52691b4dbfc

16 files changed:
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/inspector/protocol/ServiceWorker.json
Source/WebCore/ChangeLog
Source/WebCore/inspector/agents/worker/ServiceWorkerAgent.cpp
Source/WebCore/inspector/agents/worker/ServiceWorkerAgent.h
Source/WebInspectorUI/ChangeLog
Source/WebInspectorUI/UserInterface/Base/Main.js
Source/WebInspectorUI/UserInterface/Controllers/DebuggerManager.js
Source/WebInspectorUI/UserInterface/Controllers/FrameResourceManager.js
Source/WebInspectorUI/UserInterface/Controllers/SourceMapManager.js
Source/WebInspectorUI/UserInterface/Main.html
Source/WebInspectorUI/UserInterface/Models/LocalScript.js [new file with mode: 0644]
Source/WebInspectorUI/UserInterface/Models/SourceMapResource.js
Source/WebInspectorUI/UserInterface/Models/TextRange.js
Source/WebInspectorUI/UserInterface/Test.html
Source/WebInspectorUI/UserInterface/Views/SourceCodeTextEditor.js

index baf7031..503848b 100644 (file)
@@ -1,3 +1,14 @@
+2017-12-08  Joseph Pecoraro  <pecoraro@apple.com>
+
+        ServiceWorker Inspector: Various issues inspecting service worker on mobile.twitter.com
+        https://bugs.webkit.org/show_bug.cgi?id=180520
+        <rdar://problem/35900764>
+
+        Reviewed by Brian Burg.
+
+        * inspector/protocol/ServiceWorker.json:
+        Include content script content in the initialization info.
+
 2017-12-08  Konstantin Tokarev  <annulen@yandex.ru>
 
         [python] Replace print operator with print() function for python3 compatibility
index 71d4afc..8113068 100644 (file)
@@ -4,13 +4,14 @@
     "availability": ["service-worker"],
     "types": [
         {
-            "id": "InitializationInfo",
+            "id": "Configuration",
             "type": "object",
             "description": "ServiceWorker metadata and initial state.",
             "properties": [
                 { "name": "targetId", "type": "string" },
                 { "name": "securityOrigin", "type": "string" },
-                { "name": "url", "type": "string", "description": "ServiceWorker main script URL." }
+                { "name": "url", "type": "string", "description": "ServiceWorker main script URL." },
+                { "name": "content", "type": "string", "description": "ServiceWorker main script content." }
             ]
         }
     ],
@@ -19,7 +20,7 @@
             "name": "getInitializationInfo",
             "description": "Returns the initialization information for this target.",
             "returns": [
-                { "name": "info", "$ref": "InitializationInfo" }
+                { "name": "info", "$ref": "Configuration" }
             ]
         }
     ]
index 2682c40..b0f6365 100644 (file)
@@ -1,5 +1,18 @@
 2017-12-08  Joseph Pecoraro  <pecoraro@apple.com>
 
+        ServiceWorker Inspector: Various issues inspecting service worker on mobile.twitter.com
+        https://bugs.webkit.org/show_bug.cgi?id=180520
+        <rdar://problem/35900764>
+
+        Reviewed by Brian Burg.
+
+        * inspector/agents/worker/ServiceWorkerAgent.cpp:
+        (WebCore::ServiceWorkerAgent::getInitializationInfo):
+        * inspector/agents/worker/ServiceWorkerAgent.h:
+        Add initial script content to initialization so we always at least have main resource content.
+
+2017-12-08  Joseph Pecoraro  <pecoraro@apple.com>
+
         ServiceWorker Inspector: Should be able to see image content from CacheStorage.add(url) network request
         https://bugs.webkit.org/show_bug.cgi?id=180506
 
index fee473e..0f79fb7 100644 (file)
@@ -52,12 +52,13 @@ void ServiceWorkerAgent::willDestroyFrontendAndBackend(Inspector::DisconnectReas
 {
 }
 
-void ServiceWorkerAgent::getInitializationInfo(ErrorString&, RefPtr<Inspector::Protocol::ServiceWorker::InitializationInfo>& info)
+void ServiceWorkerAgent::getInitializationInfo(ErrorString&, RefPtr<Inspector::Protocol::ServiceWorker::Configuration>& info)
 {
-    info = Inspector::Protocol::ServiceWorker::InitializationInfo::create()
+    info = Inspector::Protocol::ServiceWorker::Configuration::create()
         .setTargetId(m_serviceWorkerGlobalScope.identifier())
         .setSecurityOrigin(m_serviceWorkerGlobalScope.securityOrigin()->toRawString())
         .setUrl(m_serviceWorkerGlobalScope.thread().contextData().scriptURL)
+        .setContent(m_serviceWorkerGlobalScope.thread().contextData().script)
         .release();
 }
 
index 19cbf9a..a4ad944 100644 (file)
@@ -47,7 +47,7 @@ public:
     void willDestroyFrontendAndBackend(Inspector::DisconnectReason) final;
 
     // ServiceWorkerBackendDispatcherHandler
-    void getInitializationInfo(ErrorString&, RefPtr<Inspector::Protocol::ServiceWorker::InitializationInfo>&) final;
+    void getInitializationInfo(ErrorString&, RefPtr<Inspector::Protocol::ServiceWorker::Configuration>&) final;
 
 private:
     ServiceWorkerGlobalScope& m_serviceWorkerGlobalScope;
index 5b4440b..0f5f223 100644 (file)
@@ -1,3 +1,52 @@
+2017-12-08  Joseph Pecoraro  <pecoraro@apple.com>
+
+        ServiceWorker Inspector: Various issues inspecting service worker on mobile.twitter.com
+        https://bugs.webkit.org/show_bug.cgi?id=180520
+        <rdar://problem/35900764>
+
+        Reviewed by Brian Burg.
+
+        * UserInterface/Main.html:
+        * UserInterface/Test.html:
+        New files.
+
+        * UserInterface/Controllers/SourceMapManager.js:
+        (WI.SourceMapManager.prototype._loadAndParseSourceMap):
+        * UserInterface/Models/SourceMapResource.js:
+        (WI.SourceMapResource.prototype.requestContentFromBackend):
+        A ServiceWorker inspector doesn't have a main frame, fall back to an
+        empty frameIdentifier, it is ignored by the Service Worker network agent.
+
+        * UserInterface/Base/Main.js:
+        Handle a Service Worker inspector where there is no frame. This can
+        search the main resource's resource collection.
+
+        * UserInterface/Controllers/DebuggerManager.js:
+        (WI.DebuggerManager.prototype.scriptDidParse):
+
+        * UserInterface/Controllers/FrameResourceManager.js:
+        (WI.FrameResourceManager.prototype.resourceRequestDidFailLoading):
+        In Service Workers the resources won't have a parent frame.
+
+        (WI.FrameResourceManager.prototype._addNewResourceToFrameOrTarget):
+        (WI.FrameResourceManager.prototype._processServiceWorkerInitializationInfo):
+        In service worker initialization fallback to using the script content
+        as the main resource if we didn't get a Script that actually includes it.
+
+        * UserInterface/Models/LocalScript.js:
+        (WI.LocalScript):
+        (WI.LocalScript.prototype.requestContentFromBackend):
+        A way to create a local Script with content.
+
+        * UserInterface/Views/SourceCodeTextEditor.js:
+        (WI.SourceCodeTextEditor.prototype.get _supportsDebugging):
+        Disallow breakpoints in a LocalScript since we have no way to tell the
+        backend where to set breakpoints.
+
+        * UserInterface/Models/TextRange.js:
+        (WI.TextRange.fromText):
+        Add a way to get a TextRange from static text.
+
 2017-12-08  Michael Catanzaro  <mcatanzaro@igalia.com>
 
         Don't require perl(File::Copy::Recursive)
index f06e964..8b3e9dc 100644 (file)
@@ -810,17 +810,20 @@ WI.openURL = function(url, frame, options = {})
         return;
     }
 
-    var searchChildFrames = false;
+    let searchChildFrames = false;
     if (!frame) {
         frame = this.frameResourceManager.mainFrame;
         searchChildFrames = true;
     }
 
-    console.assert(frame);
-
-    // WI.Frame.resourceForURL does not check the main resource, only sub-resources. So check both.
+    let resource;
     let simplifiedURL = removeURLFragment(url);
-    var resource = frame.url === simplifiedURL ? frame.mainResource : frame.resourceForURL(simplifiedURL, searchChildFrames);
+    if (frame) {
+        // WI.Frame.resourceForURL does not check the main resource, only sub-resources. So check both.
+        resource = frame.url === simplifiedURL ? frame.mainResource : frame.resourceForURL(simplifiedURL, searchChildFrames);
+    } else if (WI.sharedApp.debuggableType === WI.DebuggableType.ServiceWorker)
+        resource = WI.mainTarget.resourceCollection.resourceForURL(removeURLFragment(url));
+
     if (resource) {
         let positionToReveal = new WI.SourceCodePosition(options.lineNumber, 0);
         this.showSourceCode(resource, Object.shallowMerge(options, {positionToReveal}));
index 5ccfac8..d368512 100644 (file)
@@ -710,11 +710,18 @@ WI.DebuggerManager = class DebuggerManager extends WI.Object
 
         targetData.addScript(script);
 
-        if (!target.mainResource && (target !== WI.mainResource || WI.sharedApp.debuggableType === WI.DebuggableType.ServiceWorker)) {
-            // FIXME: <https://webkit.org/b/164427> Web Inspector: WorkerTarget's mainResource should be a Resource not a Script
-            // We make the main resource of a WorkerTarget the Script instead of the Resource
-            // because the frontend may not be informed of the Resource. We should guarantee
-            // the frontend is informed of the Resource.
+        // FIXME: <https://webkit.org/b/164427> Web Inspector: WorkerTarget's mainResource should be a Resource not a Script
+        // We make the main resource of a WorkerTarget the Script instead of the Resource
+        // because the frontend may not be informed of the Resource. We should guarantee
+        // the frontend is informed of the Resource.
+        if (WI.sharedApp.debuggableType === WI.DebuggableType.ServiceWorker) {
+            // A ServiceWorker starts with a LocalScript for the main resource but we can replace it during initialization.
+            if (target.mainResource instanceof WI.LocalScript) {
+                if (script.url === target.name)
+                    target.mainResource = script;
+            }
+        } else if (!target.mainResource && target !== WI.mainTarget) {
+            // A Worker starts without a main resource and we insert one.
             if (script.url === target.name) {
                 target.mainResource = script;
                 if (script.resource)
@@ -734,7 +741,7 @@ WI.DebuggerManager = class DebuggerManager extends WI.Object
 
         this.dispatchEventToListeners(WI.DebuggerManager.Event.ScriptAdded, {script});
 
-        if (target !== WI.mainTarget && !script.isMainResource() && !script.resource)
+        if ((target !== WI.mainTarget || WI.sharedApp.debuggableType === WI.DebuggableType.ServiceWorker) && !script.isMainResource() && !script.resource)
             target.addScript(script);
     }
 
index 318bd27..75224c8 100644 (file)
@@ -43,7 +43,7 @@ WI.FrameResourceManager = class FrameResourceManager extends WI.Object
         }
 
         if (window.ServiceWorkerAgent)
-            ServiceWorkerAgent.getInitializationInfo(this._processServiceWorkerInitializationInfo.bind(this));
+            ServiceWorkerAgent.getInitializationInfo(this._processServiceWorkerConfiguration.bind(this));
 
         if (window.NetworkAgent)
             NetworkAgent.enable();
@@ -458,7 +458,7 @@ WI.FrameResourceManager = class FrameResourceManager extends WI.Object
         let elapsedTime = WI.timelineManager.computeElapsedTime(timestamp);
         resource.markAsFailed(canceled, elapsedTime, errorText);
 
-        if (resource === resource.parentFrame.provisionalMainResource)
+        if (resource.parentFrame && resource === resource.parentFrame.provisionalMainResource)
             resource.parentFrame.clearProvisionalLoad();
 
         this._resourceRequestIdentifierMap.delete(requestIdentifier);
@@ -534,6 +534,7 @@ WI.FrameResourceManager = class FrameResourceManager extends WI.Object
             }
         } else {
             // This is a new request for a new frame, which is always the main resource.
+            console.assert(WI.sharedApp.debuggableType !== WI.DebuggableType.ServiceWorker);
             console.assert(!targetId);
             resource = new WI.Resource(url, null, type, loaderIdentifier, targetId, requestIdentifier, requestMethod, requestHeaders, requestData, elapsedTime, walltime, initiatorSourceCodeLocation, originalRequestWillBeSentTimestamp);
             frame = new WI.Frame(frameIdentifier, frameName, frameSecurityOrigin, loaderIdentifier, resource);
@@ -628,7 +629,7 @@ WI.FrameResourceManager = class FrameResourceManager extends WI.Object
         return sourceCode.createSourceCodeLocation(lineNumber, columnNumber);
     }
 
-    _processServiceWorkerInitializationInfo(error, initializationPayload)
+    _processServiceWorkerConfiguration(error, initializationPayload)
     {
         console.assert(this._waitingForMainFrameResourceTreePayload);
         this._waitingForMainFrameResourceTreePayload = false;
@@ -642,6 +643,19 @@ WI.FrameResourceManager = class FrameResourceManager extends WI.Object
 
         WI.mainTarget.identifier = initializationPayload.targetId;
         WI.mainTarget.name = initializationPayload.url;
+
+        // Create a main resource with this content in case the content never shows up as a WI.Script.
+        const type = WI.Script.SourceType.Program;
+        let script = new WI.LocalScript(WI.mainTarget, initializationPayload.url, type, initializationPayload.content);
+        WI.mainTarget.mainResource = script;
+
+        InspectorBackend.runAfterPendingDispatches(() => {
+            if (WI.mainTarget.mainResource === script) {
+                // We've now received all the scripts, if we don't have a better main resource use this LocalScript.
+                WI.debuggerManager.dataForTarget(WI.mainTarget).addScript(script);
+                WI.debuggerManager.dispatchEventToListeners(WI.DebuggerManager.Event.ScriptAdded, {script});
+            }
+        });
     }
 
     _processMainFrameResourceTreePayload(error, mainFramePayload)
index b0a9e39..a5124be 100644 (file)
@@ -136,8 +136,10 @@ WI.SourceMapManager = class SourceMapManager extends WI.Object
         if (originalSourceCode instanceof WI.Resource && originalSourceCode.parentFrame)
             frameIdentifier = originalSourceCode.parentFrame.id;
 
-        if (!frameIdentifier)
+        if (!frameIdentifier && WI.frameResourceManager.mainFrame)
             frameIdentifier = WI.frameResourceManager.mainFrame.id;
+        else
+            frameIdentifier = "";
 
         NetworkAgent.loadResource(frameIdentifier, sourceMapURL, sourceMapLoaded.bind(this));
     }
index 4750c5e..3cd6a60 100644 (file)
     <script src="Models/TimelineRange.js"></script>
     <script src="Models/TimelineRecord.js"></script>
 
+    <script src="Models/Resource.js"></script>
+    <script src="Models/Script.js"></script>
+    <script src="Models/LocalScript.js"></script>
+
     <script src="Models/AnalyzerMessage.js"></script>
     <script src="Models/ApplicationCacheFrame.js"></script>
     <script src="Models/ApplicationCacheManifest.js"></script>
     <script src="Models/RecordingFrame.js"></script>
     <script src="Models/RecordingInitialStateAction.js"></script>
     <script src="Models/RenderingFrameTimelineRecord.js"></script>
-    <script src="Models/Resource.js"></script>
     <script src="Models/ResourceCollection.js"></script>
     <script src="Models/ResourceQueryMatch.js"></script>
     <script src="Models/ResourceQueryResult.js"></script>
     <script src="Models/ResourceTimingData.js"></script>
     <script src="Models/Revision.js"></script>
     <script src="Models/ScopeChainNode.js"></script>
-    <script src="Models/Script.js"></script>
     <script src="Models/ScriptInstrument.js"></script>
     <script src="Models/ScriptSyntaxTree.js"></script>
     <script src="Models/ScriptTimelineRecord.js"></script>
diff --git a/Source/WebInspectorUI/UserInterface/Models/LocalScript.js b/Source/WebInspectorUI/UserInterface/Models/LocalScript.js
new file mode 100644 (file)
index 0000000..3790110
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+WI.LocalScript = class LocalScript extends WI.Script
+{
+    constructor(target, url, sourceType, text)
+    {
+        super(target, null, WI.TextRange.fromText(text), url, sourceType);
+
+        this._text = text;
+    }
+
+    // Public
+
+    requestContentFromBackend()
+    {
+        return Promise.resolve({scriptSource: this._text});
+    }
+};
index e5a3450..30d0032 100644 (file)
@@ -140,8 +140,10 @@ WI.SourceMapResource = class SourceMapResource extends WI.Resource
         if (this._sourceMap.originalSourceCode instanceof WI.Resource && this._sourceMap.originalSourceCode.parentFrame)
             frameIdentifier = this._sourceMap.originalSourceCode.parentFrame.id;
 
-        if (!frameIdentifier)
+        if (!frameIdentifier && WI.frameResourceManager.mainFrame)
             frameIdentifier = WI.frameResourceManager.mainFrame.id;
+        else
+            frameIdentifier = "";
 
         return NetworkAgent.loadResource(frameIdentifier, this.url).then(sourceMapResourceLoaded.bind(this)).catch(sourceMapResourceLoadError.bind(this));
     }
index 73d75d7..6a6e7a0 100644 (file)
@@ -51,6 +51,14 @@ WI.TextRange = class TextRange
         }
     }
 
+    // Static
+
+    static fromText(text)
+    {
+        let lines = text.split("\n");
+        return new WI.TextRange(0, 0, lines.length - 1, lines.lastValue.length);
+    }
+
     // Public
 
     get startLine() { return this._startLine; }
@@ -152,5 +160,4 @@ WI.TextRange = class TextRange
 
         return this.cloneAndModify(-line, deltaStartColumn, -line, deltaEndColumn);
     }
-
 };
index 7f48279..6dbaa85 100644 (file)
     <script src="Models/TimelineRange.js"></script>
     <script src="Models/TimelineRecord.js"></script>
 
+    <script src="Models/Resource.js"></script>
+    <script src="Models/Script.js"></script>
+    <script src="Models/LocalScript.js"></script>
+
     <script src="Models/Breakpoint.js"></script>
     <script src="Models/CSSCompletions.js"></script>
     <script src="Models/CSSKeywordCompletions.js"></script>
     <script src="Models/RecordingFrame.js"></script>
     <script src="Models/RecordingInitialStateAction.js"></script>
     <script src="Models/RenderingFrameTimelineRecord.js"></script>
-    <script src="Models/Resource.js"></script>
     <script src="Models/ResourceCollection.js"></script>
     <script src="Models/ResourceQueryMatch.js"></script>
     <script src="Models/ResourceQueryResult.js"></script>
     <script src="Models/ResourceTimingData.js"></script>
     <script src="Models/Revision.js"></script>
     <script src="Models/ScopeChainNode.js"></script>
-    <script src="Models/Script.js"></script>
     <script src="Models/ScriptInstrument.js"></script>
     <script src="Models/ScriptSyntaxTree.js"></script>
     <script src="Models/ScriptTimelineRecord.js"></script>
index 039fe37..f8dd84a 100644 (file)
@@ -1174,7 +1174,7 @@ WI.SourceCodeTextEditor = class SourceCodeTextEditor extends WI.TextEditor
         if (this._sourceCode instanceof WI.Resource)
             return this._sourceCode.type === WI.Resource.Type.Document || this._sourceCode.type === WI.Resource.Type.Script;
         if (this._sourceCode instanceof WI.Script)
-            return true;
+            return !(this._sourceCode instanceof WI.LocalScript);
         return false;
     }