Web Inspector: Audit: provide a way to get the contents of resources
authordrousso@apple.com <drousso@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 14 Mar 2019 10:13:57 +0000 (10:13 +0000)
committerdrousso@apple.com <drousso@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 14 Mar 2019 10:13:57 +0000 (10:13 +0000)
https://bugs.webkit.org/show_bug.cgi?id=195266
<rdar://problem/48550911>

Reviewed by Joseph Pecoraro.

Source/JavaScriptCore:

* inspector/InjectedScriptBase.cpp:
(Inspector::InjectedScriptBase::makeAsyncCall):
Drive-by: fix missing `else`.
Source/WebCore:

Test: inspector/audit/run-resources.html

* inspector/InspectorAuditResourcesObject.idl: Added.
* inspector/InspectorAuditResourcesObject.h: Added.
(WebCore::InspectorAuditResourcesObject::create):
(WebCore::InspectorAuditResourcesObject::Resource):
(WebCore::InspectorAuditResourcesObject::ResourceContent):
(WebCore::InspectorAuditResourcesObject::InspectorAuditCachedResourceClient):
(WebCore::InspectorAuditResourcesObject::InspectorAuditCachedFontClient):
(WebCore::InspectorAuditResourcesObject::InspectorAuditCachedImageClient):
(WebCore::InspectorAuditResourcesObject::InspectorAuditCachedRawResourceClient):
(WebCore::InspectorAuditResourcesObject::InspectorAuditCachedStyleSheetClient):
(WebCore::InspectorAuditResourcesObject::InspectorAuditCachedSVGDocumentClient):
* inspector/InspectorAuditResourcesObject.cpp: Added.
(WebCore::InspectorAuditResourcesObject::InspectorAuditResourcesObject):
(WebCore::InspectorAuditResourcesObject::getResources):
(WebCore::InspectorAuditResourcesObject::getResourceContent):
(WebCore::InspectorAuditResourcesObject::clientForResource):

* inspector/agents/InspectorPageAgent.h:
* inspector/agents/InspectorPageAgent.cpp:
(WebCore::InspectorPageAgent::cachedResourcesForFrame): Added.
(WebCore::allResourcesURLsForFrame):
Moved a file static function to be a class static function so it can be used elsewhere.

* CMakeLists.txt:
* DerivedSources-input.xcfilelist:
* DerivedSources-output.xcfilelist:
* DerivedSources.make:
* Sources.txt:
* WebCore.xcodeproj/project.pbxproj:

LayoutTests:

* inspector/audit/resources/sample-resource.css: Added.
* inspector/audit/resources/sample-resource.js: Added.
* inspector/audit/run-resources.html: Added.
* inspector/audit/run-resources-expected.txt: Added.

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

20 files changed:
LayoutTests/ChangeLog
LayoutTests/inspector/audit/resources/sample-resource.css [new file with mode: 0644]
LayoutTests/inspector/audit/resources/sample-resource.js [new file with mode: 0644]
LayoutTests/inspector/audit/run-resources-expected.txt [new file with mode: 0644]
LayoutTests/inspector/audit/run-resources.html [new file with mode: 0644]
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/inspector/InjectedScriptBase.cpp
Source/WebCore/CMakeLists.txt
Source/WebCore/ChangeLog
Source/WebCore/DerivedSources-input.xcfilelist
Source/WebCore/DerivedSources-output.xcfilelist
Source/WebCore/DerivedSources.make
Source/WebCore/Sources.txt
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/inspector/InspectorAuditResourcesObject.cpp [new file with mode: 0644]
Source/WebCore/inspector/InspectorAuditResourcesObject.h [new file with mode: 0644]
Source/WebCore/inspector/InspectorAuditResourcesObject.idl [new file with mode: 0644]
Source/WebCore/inspector/agents/InspectorPageAgent.cpp
Source/WebCore/inspector/agents/InspectorPageAgent.h
Source/WebCore/inspector/agents/page/PageAuditAgent.cpp

index 1add711..badc589 100644 (file)
@@ -1,5 +1,18 @@
 2019-03-14  Devin Rousso  <drousso@apple.com>
 
+        Web Inspector: Audit: provide a way to get the contents of resources
+        https://bugs.webkit.org/show_bug.cgi?id=195266
+        <rdar://problem/48550911>
+
+        Reviewed by Joseph Pecoraro.
+
+        * inspector/audit/resources/sample-resource.css: Added.
+        * inspector/audit/resources/sample-resource.js: Added.
+        * inspector/audit/run-resources.html: Added.
+        * inspector/audit/run-resources-expected.txt: Added.
+
+2019-03-14  Devin Rousso  <drousso@apple.com>
+
         Web Inspector: Console: getEventListeners should work for any EventTarget
         https://bugs.webkit.org/show_bug.cgi?id=195713
 
diff --git a/LayoutTests/inspector/audit/resources/sample-resource.css b/LayoutTests/inspector/audit/resources/sample-resource.css
new file mode 100644 (file)
index 0000000..f84bc79
--- /dev/null
@@ -0,0 +1 @@
+/* TEST CSS */
\ No newline at end of file
diff --git a/LayoutTests/inspector/audit/resources/sample-resource.js b/LayoutTests/inspector/audit/resources/sample-resource.js
new file mode 100644 (file)
index 0000000..79fea92
--- /dev/null
@@ -0,0 +1 @@
+/* TEST JS */
\ No newline at end of file
diff --git a/LayoutTests/inspector/audit/run-resources-expected.txt b/LayoutTests/inspector/audit/run-resources-expected.txt
new file mode 100644 (file)
index 0000000..e8397ae
--- /dev/null
@@ -0,0 +1,37 @@
+
+Tests for the injected WebInspectorAudit.Resources functions.
+
+
+== Running test suite: Audit.run.Resources
+-- Running test case: Audit.run.Resources.getResources
+Audit setup...
+Audit run `WebInspectorAudit.Resources.getResources()`...
+Found dataURL image.
+PASS: dataURL image should have the expected content.
+PASS: dataURL image should be base64 encoded.
+Found sample-resource.css.
+PASS: sample-resource.css should have the expected content.
+PASS: sample-resource.css should not be base64 encoded.
+Found sample-resource.js.
+PASS: sample-resource.js should have the expected content.
+PASS: sample-resource.js should not be base64 encoded.
+Audit teardown...
+
+-- Running test case: Audit.run.Resources.getResourceContent.InvalidId
+Audit setup...
+Audit run `WebInspectorAudit.Resources.getResourceContent(-1)`...
+PASS: Should throw an exception.
+NotFoundError: Unknown identifier -1
+Audit teardown...
+
+-- Running test case: Audit.run.Resources.InvalidCopiedFunctionCall
+Audit setup...
+Copying WebInspectorAudit to window...
+Audit teardown...
+Testing copied getResources...
+PASS: Should produce an exception.
+Error: NotAllowedError: Cannot be called outside of a Web Inspector Audit
+Testing copied getResourceContent...
+PASS: Should produce an exception.
+Error: NotAllowedError: Cannot be called outside of a Web Inspector Audit
+
diff --git a/LayoutTests/inspector/audit/run-resources.html b/LayoutTests/inspector/audit/run-resources.html
new file mode 100644 (file)
index 0000000..92a552d
--- /dev/null
@@ -0,0 +1,122 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../http/tests/inspector/resources/inspector-test.js"></script>
+<script src="resources/audit-utilities.js"></script>
+<script src="resources/sample-resource.js"></script>
+<link rel="stylesheet" href="resources/sample-resource.css">
+<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAAXNSR0IArs4c6QAAABNJREFUCB1j/M/AAEQMDEwgAgQAHxcCAmtAm/sAAAAASUVORK5CYII=">
+<script>
+function test()
+{
+    InspectorTest.debug();
+
+    let suite = InspectorTest.Audit.createSuite("Audit.run.Resources");
+
+    function evaluateStringForTest(func, args) {
+        return `WebInspectorAudit.Resources.${func}(${Array.isArray(args) ? args.map(JSON.stringify).join(", ") : ""})`;
+    }
+
+    const tests = [
+        { name: "Audit.run.Resources.getResources", func: "getResources" },
+        { name: "Audit.run.Resources.getResourceContent.InvalidId", func: "getResourceContent", args: [-1], shouldError: true, },
+    ];
+
+    for (let {name, func, args, shouldError} of tests) {
+        suite.addTestCase({
+            name,
+            async test() {
+                async function getContentForResource(resource) {
+                    let {result, wasThrown} = await AuditAgent.run(`function() { return JSON.stringify(${evaluateStringForTest("getResourceContent", [resource.id])}); }`);
+                    InspectorTest.assert(!wasThrown, "Should not throw an exception");
+                    return JSON.parse(result.value);
+                }
+
+                let functionString = evaluateStringForTest(func, args);
+
+                await InspectorTest.Audit.setupAudit();
+
+                InspectorTest.log(`Audit run \`${functionString}\`...`);
+                let {result, wasThrown} = await AuditAgent.run(`function() { return JSON.stringify(${functionString}); }`);
+
+                if (shouldError)
+                    InspectorTest.expectThat(wasThrown, "Should throw an exception.");
+                else
+                    InspectorTest.assert(!wasThrown, "Should not throw an exception.");
+
+                if (!wasThrown) {
+                    let resources = JSON.parse(result.value);
+
+                    resources.sort((a, b) => a.url.extendedLocaleCompare(b.url));
+
+                    for (let resource of resources) {
+                        InspectorTest.assert(resource.id, `All resources should have "id".`);
+                        InspectorTest.assert(resource.url, `All resources should have "url".`);
+                        InspectorTest.assert(resource.mimeType, `All resources should have "mimeType".`);
+
+                        if (resource.url.endsWith("sample-resource.js")) {
+                            InspectorTest.log("Found sample-resource.js.");
+                            InspectorTest.assert(resource.mimeType === "text/javascript", "sample-resource.js should have a text/javascript MIME type.");
+
+                            let content = await getContentForResource(resource);
+                            InspectorTest.expectEqual(content.data, "/* TEST JS */", "sample-resource.js should have the expected content.");
+                            InspectorTest.expectFalse(content.base64Encoded, "sample-resource.js should not be base64 encoded.");
+                        }
+
+                        if (resource.url.endsWith("sample-resource.css")) {
+                            InspectorTest.log("Found sample-resource.css.");
+                            InspectorTest.assert(resource.mimeType === "text/css", "sample-resource.css should have a text/css MIME type.");
+
+                            let content = await getContentForResource(resource);
+                            InspectorTest.expectEqual(content.data, "/* TEST CSS */", "sample-resource.css should have the expected content.");
+                            InspectorTest.expectFalse(content.base64Encoded, "sample-resource.css should not be base64 encoded.");
+                        }
+
+                        if (resource.url.startsWith("data:image/png;base64")) {
+                            InspectorTest.log("Found dataURL image.");
+                            InspectorTest.assert(resource.mimeType === "image/png", "dataURL image should have a image/png MIME type.");
+
+                            let content = await getContentForResource(resource);
+                            InspectorTest.expectEqual(content.data, "iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAAXNSR0IArs4c6QAAABNJREFUCB1j/M/AAEQMDEwgAgQAHxcCAmtAm/sAAAAASUVORK5CYII=", "dataURL image should have the expected content.");
+                            InspectorTest.expectThat(content.base64Encoded, "dataURL image should be base64 encoded.");
+                        }
+                    }
+                } else
+                    InspectorTest.log(result.description);
+
+                await InspectorTest.Audit.teardownAudit();
+            },
+        });
+    }
+
+    suite.addTestCase({
+        name: "Audit.run.Resources.InvalidCopiedFunctionCall",
+        description: "Check that WebInspectorAudit.Resources functions throw an error when called outside of an audit.",
+        async test() {
+            let functions = new Map;
+            for (let test of tests)
+                functions.set(test.func, test);
+
+            await InspectorTest.Audit.setupAudit();
+            InspectorTest.log(`Copying WebInspectorAudit to window...`);
+            let {wasThrown} = await AuditAgent.run(`function() { window.CopiedWebInspectorAudit = WebInspectorAudit; }`);
+            InspectorTest.assert(!wasThrown, "Should not throw an exception.");
+            await InspectorTest.Audit.teardownAudit();
+
+            for (let {func, args} of functions.values()) {
+                InspectorTest.log(`Testing copied ${func}...`);
+                await InspectorTest.expectException(async function() {
+                    await InspectorTest.evaluateInPage("window.Copied" + evaluateStringForTest(func, args));
+                });
+            }
+        },
+    });
+
+    suite.runTestCasesAndFinish();
+}
+</script>
+</head>
+<body onload="runTest()">
+    <p>Tests for the injected WebInspectorAudit.Resources functions.</p>
+</body>
+</html>
index a5e23d0..3c70c37 100644 (file)
@@ -1,5 +1,17 @@
 2019-03-14  Devin Rousso  <drousso@apple.com>
 
+        Web Inspector: Audit: provide a way to get the contents of resources
+        https://bugs.webkit.org/show_bug.cgi?id=195266
+        <rdar://problem/48550911>
+
+        Reviewed by Joseph Pecoraro.
+
+        * inspector/InjectedScriptBase.cpp:
+        (Inspector::InjectedScriptBase::makeAsyncCall):
+        Drive-by: fix missing `else`.
+
+2019-03-14  Devin Rousso  <drousso@apple.com>
+
         Web Inspector: Styles: `::-webkit-scrollbar*` rules aren't shown
         https://bugs.webkit.org/show_bug.cgi?id=195123
         <rdar://problem/48450148>
index fd8bbcf..3d2dcae 100644 (file)
@@ -119,7 +119,7 @@ void InjectedScriptBase::makeAsyncCall(Deprecated::ScriptFunctionCall& function,
         jsFunction = JSC::JSNativeStdFunction::create(vm, scriptState->lexicalGlobalObject(), 1, String(), [&, callback = WTFMove(callback)] (JSC::ExecState* exec) {
             if (!exec)
                 checkAsyncCallResult(JSON::Value::create("Exception while making a call."), callback);
-            if (auto resultJSONValue = toInspectorValue(*exec, exec->argument(0)))
+            else if (auto resultJSONValue = toInspectorValue(*exec, exec->argument(0)))
                 checkAsyncCallResult(resultJSONValue, callback);
             else
                 checkAsyncCallResult(JSON::Value::create(makeString("Object has too long reference chain (must not be longer than ", JSON::Value::maxDepth, ')')), callback);
index 5c67049..6d1f108 100644 (file)
@@ -902,6 +902,7 @@ set(WebCore_NON_SVG_IDL_FILES
     inspector/CommandLineAPIHost.idl
     inspector/InspectorAuditAccessibilityObject.idl
     inspector/InspectorAuditDOMObject.idl
+    inspector/InspectorAuditResourcesObject.idl
     inspector/InspectorFrontendHost.idl
 
     loader/appcache/DOMApplicationCache.idl
index 7e39053..2d215e6 100644 (file)
@@ -1,5 +1,45 @@
 2019-03-14  Devin Rousso  <drousso@apple.com>
 
+        Web Inspector: Audit: provide a way to get the contents of resources
+        https://bugs.webkit.org/show_bug.cgi?id=195266
+        <rdar://problem/48550911>
+
+        Reviewed by Joseph Pecoraro.
+
+        Test: inspector/audit/run-resources.html
+
+        * inspector/InspectorAuditResourcesObject.idl: Added.
+        * inspector/InspectorAuditResourcesObject.h: Added.
+        (WebCore::InspectorAuditResourcesObject::create):
+        (WebCore::InspectorAuditResourcesObject::Resource):
+        (WebCore::InspectorAuditResourcesObject::ResourceContent):
+        (WebCore::InspectorAuditResourcesObject::InspectorAuditCachedResourceClient):
+        (WebCore::InspectorAuditResourcesObject::InspectorAuditCachedFontClient):
+        (WebCore::InspectorAuditResourcesObject::InspectorAuditCachedImageClient):
+        (WebCore::InspectorAuditResourcesObject::InspectorAuditCachedRawResourceClient):
+        (WebCore::InspectorAuditResourcesObject::InspectorAuditCachedStyleSheetClient):
+        (WebCore::InspectorAuditResourcesObject::InspectorAuditCachedSVGDocumentClient):
+        * inspector/InspectorAuditResourcesObject.cpp: Added.
+        (WebCore::InspectorAuditResourcesObject::InspectorAuditResourcesObject):
+        (WebCore::InspectorAuditResourcesObject::getResources):
+        (WebCore::InspectorAuditResourcesObject::getResourceContent):
+        (WebCore::InspectorAuditResourcesObject::clientForResource):
+
+        * inspector/agents/InspectorPageAgent.h:
+        * inspector/agents/InspectorPageAgent.cpp:
+        (WebCore::InspectorPageAgent::cachedResourcesForFrame): Added.
+        (WebCore::allResourcesURLsForFrame):
+        Moved a file static function to be a class static function so it can be used elsewhere.
+
+        * CMakeLists.txt:
+        * DerivedSources-input.xcfilelist:
+        * DerivedSources-output.xcfilelist:
+        * DerivedSources.make:
+        * Sources.txt:
+        * WebCore.xcodeproj/project.pbxproj:
+
+2019-03-14  Devin Rousso  <drousso@apple.com>
+
         Web Inspector: Console: getEventListeners should work for any EventTarget
         https://bugs.webkit.org/show_bug.cgi?id=195713
 
index 3f7b946..1e844d1 100644 (file)
@@ -872,6 +872,7 @@ $(PROJECT_DIR)/inspector/CommandLineAPIHost.idl
 $(PROJECT_DIR)/inspector/CommandLineAPIModuleSource.js
 $(PROJECT_DIR)/inspector/InspectorAuditAccessibilityObject.idl
 $(PROJECT_DIR)/inspector/InspectorAuditDOMObject.idl
+$(PROJECT_DIR)/inspector/InspectorAuditResourcesObject.idl
 $(PROJECT_DIR)/inspector/InspectorFrontendHost.idl
 $(PROJECT_DIR)/loader/appcache/DOMApplicationCache.idl
 $(PROJECT_DIR)/make-hash-tools.pl
index 59b5734..33c55ae 100644 (file)
@@ -867,6 +867,8 @@ $(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSInspectorAuditAccessibilityObject
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSInspectorAuditAccessibilityObject.h
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSInspectorAuditDOMObject.cpp
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSInspectorAuditDOMObject.h
+$(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSInspectorAuditResourcesObject.cpp
+$(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSInspectorAuditResourcesObject.h
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSInspectorFrontendHost.cpp
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSInspectorFrontendHost.h
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSInternalSettings.cpp
index 711dd3d..d41f607 100644 (file)
@@ -852,6 +852,7 @@ JS_BINDING_IDLS = \
     $(WebCore)/inspector/CommandLineAPIHost.idl \
     $(WebCore)/inspector/InspectorAuditAccessibilityObject.idl \
     $(WebCore)/inspector/InspectorAuditDOMObject.idl \
+    $(WebCore)/inspector/InspectorAuditResourcesObject.idl \
     $(WebCore)/inspector/InspectorFrontendHost.idl \
     $(WebCore)/loader/appcache/DOMApplicationCache.idl \
     $(WebCore)/page/BarProp.idl \
index 9df9f14..66345c6 100644 (file)
@@ -1276,6 +1276,7 @@ inspector/DOMEditor.cpp
 inspector/DOMPatchSupport.cpp
 inspector/InspectorAuditAccessibilityObject.cpp
 inspector/InspectorAuditDOMObject.cpp
+inspector/InspectorAuditResourcesObject.cpp
 inspector/InspectorCanvas.cpp
 inspector/InspectorClient.cpp
 inspector/InspectorController.cpp
@@ -2915,6 +2916,7 @@ JSImageSmoothingQuality.cpp
 JSInputEvent.cpp
 JSInspectorAuditAccessibilityObject.cpp
 JSInspectorAuditDOMObject.cpp
+JSInspectorAuditResourcesObject.cpp
 JSInspectorFrontendHost.cpp
 JSIntersectionObserver.cpp
 JSIntersectionObserverCallback.cpp
index 84bb7f4..343467c 100644 (file)
                9001774012E0347800648462 /* OESStandardDerivatives.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9001773D12E0347800648462 /* OESStandardDerivatives.cpp */; };
                9001774112E0347800648462 /* OESStandardDerivatives.h in Headers */ = {isa = PBXBuildFile; fileRef = 9001773E12E0347800648462 /* OESStandardDerivatives.h */; };
                9001788112E0370700648462 /* JSOESStandardDerivatives.h in Headers */ = {isa = PBXBuildFile; fileRef = 9001787F12E0370700648462 /* JSOESStandardDerivatives.h */; };
+               9109E9C8222CABCA00BB6264 /* InspectorAuditResourcesObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 9109E9C5222CABC800BB6264 /* InspectorAuditResourcesObject.h */; };
+               9109E9C8222CABCA00BB6265 /* JSInspectorAuditResourcesObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 9109E9C5222CABC800BB6265 /* JSInspectorAuditResourcesObject.h */; };
                91278D5E21DEDAD600B57184 /* PageAuditAgent.h in Headers */ = {isa = PBXBuildFile; fileRef = 91278D5C21DEDAD500B57184 /* PageAuditAgent.h */; };
                91278D6221DEDAF000B57184 /* WorkerAuditAgent.h in Headers */ = {isa = PBXBuildFile; fileRef = 91278D6021DEDAF000B57184 /* WorkerAuditAgent.h */; };
                9175CE5C21E281ED00DF2C27 /* InspectorAuditDOMObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 9175CE5821E281EC00DF2C27 /* InspectorAuditDOMObject.h */; };
                9001773F12E0347800648462 /* OESStandardDerivatives.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = OESStandardDerivatives.idl; sourceTree = "<group>"; };
                9001787E12E0370700648462 /* JSOESStandardDerivatives.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSOESStandardDerivatives.cpp; sourceTree = "<group>"; };
                9001787F12E0370700648462 /* JSOESStandardDerivatives.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSOESStandardDerivatives.h; sourceTree = "<group>"; };
+               9109E9C5222CABC800BB6264 /* InspectorAuditResourcesObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InspectorAuditResourcesObject.h; sourceTree = "<group>"; };
+               9109E9C5222CABC800BB6265 /* JSInspectorAuditResourcesObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSInspectorAuditResourcesObject.h; sourceTree = "<group>"; };
+               9109E9C7222CABC900BB6264 /* InspectorAuditResourcesObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InspectorAuditResourcesObject.cpp; sourceTree = "<group>"; };
+               9109E9C7222CABC900BB6265 /* JSInspectorAuditResourcesObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSInspectorAuditResourcesObject.cpp; sourceTree = "<group>"; };
                91278D5A21DEDAD500B57184 /* PageAuditAgent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PageAuditAgent.cpp; sourceTree = "<group>"; };
                91278D5C21DEDAD500B57184 /* PageAuditAgent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PageAuditAgent.h; sourceTree = "<group>"; };
                91278D5F21DEDAEF00B57184 /* WorkerAuditAgent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WorkerAuditAgent.cpp; sourceTree = "<group>"; };
                                9175CE5A21E281ED00DF2C28 /* JSInspectorAuditAccessibilityObject.h */,
                                9175CE5721E281EB00DF2C28 /* JSInspectorAuditDOMObject.cpp */,
                                9175CE5821E281EC00DF2C28 /* JSInspectorAuditDOMObject.h */,
+                               9109E9C7222CABC900BB6265 /* JSInspectorAuditResourcesObject.cpp */,
+                               9109E9C5222CABC800BB6265 /* JSInspectorAuditResourcesObject.h */,
                                7A0E771C10C00DB100A0276E /* JSInspectorFrontendHost.cpp */,
                                7A0E771D10C00DB100A0276E /* JSInspectorFrontendHost.h */,
                        );
                                9175CE5A21E281ED00DF2C27 /* InspectorAuditAccessibilityObject.h */,
                                9175CE5721E281EB00DF2C27 /* InspectorAuditDOMObject.cpp */,
                                9175CE5821E281EC00DF2C27 /* InspectorAuditDOMObject.h */,
+                               9109E9C7222CABC900BB6264 /* InspectorAuditResourcesObject.cpp */,
+                               9109E9C5222CABC800BB6264 /* InspectorAuditResourcesObject.h */,
                                6A22E8721F1042C400F546C3 /* InspectorCanvas.cpp */,
                                6A22E86F1F10418600F546C3 /* InspectorCanvas.h */,
                                7A1F2B51126C61B20006A7E6 /* InspectorClient.cpp */,
                                A5B81CA71FAA44620037D1E6 /* InspectorApplicationCacheAgent.h in Headers */,
                                9175CE5E21E281ED00DF2C27 /* InspectorAuditAccessibilityObject.h in Headers */,
                                9175CE5C21E281ED00DF2C27 /* InspectorAuditDOMObject.h in Headers */,
+                               9109E9C8222CABCA00BB6264 /* InspectorAuditResourcesObject.h in Headers */,
                                6A22E8701F10418600F546C3 /* InspectorCanvas.h in Headers */,
                                A5B81CA81FAA44620037D1E6 /* InspectorCanvasAgent.h in Headers */,
                                1C81B95C0E97330800266E07 /* InspectorClient.h in Headers */,
                                A86629D309DA2B48009633A6 /* JSInputEvent.h in Headers */,
                                9175CE5E21E281ED00DF2C28 /* JSInspectorAuditAccessibilityObject.h in Headers */,
                                9175CE5C21E281ED00DF2C28 /* JSInspectorAuditDOMObject.h in Headers */,
+                               9109E9C8222CABCA00BB6265 /* JSInspectorAuditResourcesObject.h in Headers */,
                                7A0E771F10C00DB100A0276E /* JSInspectorFrontendHost.h in Headers */,
                                0F4710E61DB700C7002DCEC3 /* JSIntersectionObserver.h in Headers */,
                                0F8B45761DC41DBA00443C3F /* JSIntersectionObserverCallback.h in Headers */,
diff --git a/Source/WebCore/inspector/InspectorAuditResourcesObject.cpp b/Source/WebCore/inspector/InspectorAuditResourcesObject.cpp
new file mode 100644 (file)
index 0000000..1b3b4bd
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#include "config.h"
+#include "InspectorAuditResourcesObject.h"
+
+#include "CachedCSSStyleSheet.h"
+#include "CachedFont.h"
+#include "CachedImage.h"
+#include "CachedRawResource.h"
+#include "CachedResource.h"
+#include "CachedSVGDocument.h"
+#include "Document.h"
+#include "InspectorPageAgent.h"
+#include <wtf/HashMap.h>
+#include <wtf/Vector.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+using namespace Inspector;
+
+#define ERROR_IF_NO_ACTIVE_AUDIT() \
+    if (!m_auditAgent.hasActiveAudit()) \
+        return Exception { NotAllowedError, "Cannot be called outside of a Web Inspector Audit"_s };
+
+InspectorAuditResourcesObject::InspectorAuditResourcesObject(InspectorAuditAgent& auditAgent)
+    : m_auditAgent(auditAgent)
+{
+}
+
+InspectorAuditResourcesObject::~InspectorAuditResourcesObject()
+{
+    for (auto* cachedResource : m_resources.values())
+        cachedResource->removeClient(clientForResource(*cachedResource));
+}
+
+ExceptionOr<Vector<InspectorAuditResourcesObject::Resource>> InspectorAuditResourcesObject::getResources(Document& document)
+{
+    ERROR_IF_NO_ACTIVE_AUDIT();
+
+    Vector<Resource> resources;
+
+    auto* frame = document.frame();
+    if (!frame)
+        return Exception { NotAllowedError, "Cannot be called with a detached document"_s };
+
+    for (auto* cachedResource : InspectorPageAgent::cachedResourcesForFrame(frame)) {
+        Resource resource;
+        resource.url = cachedResource->url();
+        resource.mimeType = cachedResource->mimeType();
+
+        bool exists = false;
+        for (const auto& entry : m_resources) {
+            if (entry.value == cachedResource) {
+                resource.id = entry.key;
+                exists = true;
+                break;
+            }
+        }
+        if (!exists) {
+            cachedResource->addClient(clientForResource(*cachedResource));
+
+            resource.id = String::number(m_resources.size() + 1);
+            m_resources.add(resource.id, cachedResource);
+        }
+
+        resources.append(WTFMove(resource));
+    }
+
+    return resources;
+}
+
+ExceptionOr<InspectorAuditResourcesObject::ResourceContent> InspectorAuditResourcesObject::getResourceContent(Document& document, const String& id)
+{
+    ERROR_IF_NO_ACTIVE_AUDIT();
+
+    auto* frame = document.frame();
+    if (!frame)
+        return Exception { NotAllowedError, "Cannot be called with a detached document"_s };
+
+    auto* cachedResource = m_resources.get(id);
+    if (!cachedResource)
+        return Exception { NotFoundError, makeString("Unknown identifier "_s, id) };
+
+    ErrorString errorString;
+    ResourceContent resourceContent;
+    InspectorPageAgent::resourceContent(errorString, frame, cachedResource->url(), &resourceContent.data, &resourceContent.base64Encoded);
+    if (!errorString.isEmpty())
+        return Exception { NotFoundError, errorString };
+
+    return resourceContent;
+}
+
+CachedResourceClient& InspectorAuditResourcesObject::clientForResource(const CachedResource& cachedResource)
+{
+    if (is<CachedCSSStyleSheet>(cachedResource))
+        return m_cachedStyleSheetClient;
+
+    if (is<CachedFont>(cachedResource))
+        return m_cachedFontClient;
+
+    if (is<CachedImage>(cachedResource))
+        return m_cachedImageClient;
+
+    if (is<CachedRawResource>(cachedResource))
+        return m_cachedRawResourceClient;
+
+    if (is<CachedSVGDocument>(cachedResource))
+        return m_cachedSVGDocumentClient;
+
+    return m_cachedResourceClient;
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/inspector/InspectorAuditResourcesObject.h b/Source/WebCore/inspector/InspectorAuditResourcesObject.h
new file mode 100644 (file)
index 0000000..8a31ea8
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#pragma once
+
+#include "CachedFontClient.h"
+#include "CachedImageClient.h"
+#include "CachedRawResourceClient.h"
+#include "CachedResourceClient.h"
+#include "CachedSVGDocumentClient.h"
+#include "CachedStyleSheetClient.h"
+#include "ExceptionOr.h"
+#include <JavaScriptCore/InspectorAuditAgent.h>
+#include <wtf/Forward.h>
+#include <wtf/Ref.h>
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+class CachedResource;
+class Document;
+
+class InspectorAuditResourcesObject : public RefCounted<InspectorAuditResourcesObject> {
+public:
+    static Ref<InspectorAuditResourcesObject> create(Inspector::InspectorAuditAgent& auditAgent)
+    {
+        return adoptRef(*new InspectorAuditResourcesObject(auditAgent));
+    }
+
+    ~InspectorAuditResourcesObject();
+
+    struct Resource {
+        String id;
+        String url;
+        String mimeType;
+    };
+
+    struct ResourceContent {
+        String data;
+        bool base64Encoded;
+    };
+
+    ExceptionOr<Vector<Resource>> getResources(Document&);
+    ExceptionOr<ResourceContent> getResourceContent(Document&, const String& id);
+
+private:
+    explicit InspectorAuditResourcesObject(Inspector::InspectorAuditAgent&);
+
+    CachedResourceClient& clientForResource(const CachedResource&);
+
+    Inspector::InspectorAuditAgent& m_auditAgent;
+
+    class InspectorAuditCachedResourceClient : public CachedResourceClient { };
+    InspectorAuditCachedResourceClient m_cachedResourceClient;
+
+    class InspectorAuditCachedFontClient : public CachedFontClient { };
+    InspectorAuditCachedFontClient m_cachedFontClient;
+
+    class InspectorAuditCachedImageClient : public CachedImageClient { };
+    InspectorAuditCachedImageClient m_cachedImageClient;
+
+    class InspectorAuditCachedRawResourceClient : public CachedRawResourceClient { };
+    InspectorAuditCachedRawResourceClient m_cachedRawResourceClient;
+
+    class InspectorAuditCachedSVGDocumentClient : public CachedSVGDocumentClient { };
+    InspectorAuditCachedSVGDocumentClient m_cachedSVGDocumentClient;
+
+    class InspectorAuditCachedStyleSheetClient : public CachedStyleSheetClient { };
+    InspectorAuditCachedStyleSheetClient m_cachedStyleSheetClient;
+
+    HashMap<String, CachedResource*> m_resources;
+};
+
+} // namespace WebCore
diff --git a/Source/WebCore/inspector/InspectorAuditResourcesObject.idl b/Source/WebCore/inspector/InspectorAuditResourcesObject.idl
new file mode 100644 (file)
index 0000000..8bbd8c3
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+[
+    ImplementationLacksVTable,
+    JSGenerateToJSObject,
+    NoInterfaceObject,
+] interface InspectorAuditResourcesObject {
+    [CallWith=Document, MayThrowException] sequence<Resource> getResources();
+    [CallWith=Document, MayThrowException] ResourceContent getResourceContent(DOMString id);
+};
+
+[
+    JSGenerateToJSObject,
+] dictionary Resource {
+    DOMString id;
+    DOMString url;
+    DOMString mimeType;
+};
+
+[
+    JSGenerateToJSObject,
+] dictionary ResourceContent {
+    DOMString data;
+    boolean base64Encoded;
+};
index a1aeffc..005b98c 100644 (file)
@@ -129,6 +129,37 @@ bool InspectorPageAgent::dataContent(const char* data, unsigned size, const Stri
     return decodeBuffer(data, size, textEncodingName, result);
 }
 
+Vector<CachedResource*> InspectorPageAgent::cachedResourcesForFrame(Frame* frame)
+{
+    Vector<CachedResource*> result;
+
+    for (auto& cachedResourceHandle : frame->document()->cachedResourceLoader().allCachedResources().values()) {
+        auto* cachedResource = cachedResourceHandle.get();
+        if (cachedResource->resourceRequest().hiddenFromInspector())
+            continue;
+
+        switch (cachedResource->type()) {
+        case CachedResource::Type::ImageResource:
+            // Skip images that were not auto loaded (images disabled in the user agent).
+#if ENABLE(SVG_FONTS)
+        case CachedResource::Type::SVGFontResource:
+#endif
+        case CachedResource::Type::FontResource:
+            // Skip fonts that were referenced in CSS but never used/downloaded.
+            if (cachedResource->stillNeedsLoad())
+                continue;
+            break;
+        default:
+            // All other CachedResource types download immediately.
+            break;
+        }
+
+        result.append(cachedResource);
+    }
+
+    return result;
+}
+
 void InspectorPageAgent::resourceContent(ErrorString& errorString, Frame* frame, const URL& url, String* result, bool* base64Encoded)
 {
     DocumentLoader* loader = assertDocumentLoader(errorString, frame);
@@ -437,44 +468,13 @@ static Ref<JSON::ArrayOf<Inspector::Protocol::Page::Cookie>> buildArrayForCookie
     return cookies;
 }
 
-static Vector<CachedResource*> cachedResourcesForFrame(Frame* frame)
-{
-    Vector<CachedResource*> result;
-
-    for (auto& cachedResourceHandle : frame->document()->cachedResourceLoader().allCachedResources().values()) {
-        auto* cachedResource = cachedResourceHandle.get();
-        if (cachedResource->resourceRequest().hiddenFromInspector())
-            continue;
-
-        switch (cachedResource->type()) {
-        case CachedResource::Type::ImageResource:
-            // Skip images that were not auto loaded (images disabled in the user agent).
-#if ENABLE(SVG_FONTS)
-        case CachedResource::Type::SVGFontResource:
-#endif
-        case CachedResource::Type::FontResource:
-            // Skip fonts that were referenced in CSS but never used/downloaded.
-            if (cachedResource->stillNeedsLoad())
-                continue;
-            break;
-        default:
-            // All other CachedResource types download immediately.
-            break;
-        }
-
-        result.append(cachedResource);
-    }
-
-    return result;
-}
-
 static Vector<URL> allResourcesURLsForFrame(Frame* frame)
 {
     Vector<URL> result;
 
     result.append(frame->loader().documentLoader()->url());
 
-    for (auto* cachedResource : cachedResourcesForFrame(frame))
+    for (auto* cachedResource : InspectorPageAgent::cachedResourcesForFrame(frame))
         result.append(cachedResource->url());
 
     return result;
index 9bfa2bb..c37b4dd 100644 (file)
@@ -76,6 +76,7 @@ public:
     };
 
     static bool sharedBufferContent(RefPtr<SharedBuffer>&&, const String& textEncodingName, bool withBase64Encode, String* result);
+    static Vector<CachedResource*> cachedResourcesForFrame(Frame*);
     static void resourceContent(ErrorString&, Frame*, const URL&, String* result, bool* base64Encoded);
     static String sourceMapURLForResource(CachedResource*);
 
index 141ec08..3622c29 100644 (file)
 
 #include "InspectorAuditAccessibilityObject.h"
 #include "InspectorAuditDOMObject.h"
+#include "InspectorAuditResourcesObject.h"
 #include "JSInspectorAuditAccessibilityObject.h"
 #include "JSInspectorAuditDOMObject.h"
+#include "JSInspectorAuditResourcesObject.h"
 #include "Page.h"
 #include "PageConsoleClient.h"
 #include <JavaScriptCore/CallFrame.h>
@@ -83,11 +85,14 @@ void PageAuditAgent::populateAuditObject(JSC::ExecState* execState, JSC::Strong<
     if (auto* globalObject = JSC::jsCast<JSDOMGlobalObject*>(execState->lexicalGlobalObject())) {
         JSC::JSLockHolder lock(execState);
 
-        if (JSC::JSValue jsInspectorAuditAccessibilityObject = toJSNewlyCreated(execState, globalObject, InspectorAuditAccessibilityObject::create(*this))) \
+        if (JSC::JSValue jsInspectorAuditAccessibilityObject = toJSNewlyCreated(execState, globalObject, InspectorAuditAccessibilityObject::create(*this)))
             auditObject->putDirect(execState->vm(), JSC::Identifier::fromString(execState, "Accessibility"), jsInspectorAuditAccessibilityObject);
 
-        if (JSC::JSValue jsInspectorAuditDOMObject = toJSNewlyCreated(execState, globalObject, InspectorAuditDOMObject::create(*this))) \
+        if (JSC::JSValue jsInspectorAuditDOMObject = toJSNewlyCreated(execState, globalObject, InspectorAuditDOMObject::create(*this)))
             auditObject->putDirect(execState->vm(), JSC::Identifier::fromString(execState, "DOM"), jsInspectorAuditDOMObject);
+
+        if (JSC::JSValue jsInspectorAuditResourcesObject = toJSNewlyCreated(execState, globalObject, InspectorAuditResourcesObject::create(*this)))
+            auditObject->putDirect(execState->vm(), JSC::Identifier::fromString(execState, "Resources"), jsInspectorAuditResourcesObject);
     }
 }