Web Inspector: Should be able to see where Resources came from (Memory Cache, Disk Cache)
https://bugs.webkit.org/show_bug.cgi?id=164892
<rdar://problem/29320562>

Reviewed by Brian Burg.

Source/JavaScriptCore:

* inspector/protocol/Network.json:
Replace "fromDiskCache" property with "source" property which includes
more complete information about the source of this response (network,
memory cache, disk cache, or unknown).

* inspector/scripts/codegen/generate_cpp_protocol_types_header.py:
(_generate_class_for_object_declaration):
* inspector/scripts/codegen/generate_cpp_protocol_types_implementation.py:
(CppProtocolTypesImplementationGenerator._generate_open_field_names):
* inspector/scripts/codegen/generator.py:
(Generator):
(Generator.open_fields):
To avoid conflicts between the Inspector::Protocol::Network::Response::Source
enum and open accessor string symbol that would have the same name, only generate
a specific list of open accessor strings. This reduces the list of exported
symbols from all properties to just the ones that are needed. This can be
cleaned up later if needed.

* inspector/scripts/tests/generic/expected/type-with-open-parameters.json-result: Added.
* inspector/scripts/tests/generic/type-with-open-parameters.json: Added.
Test for open accessors generation.

Source/WebCore:

Test: http/tests/inspector/network/resource-response-source-disk-cache.html
      http/tests/inspector/network/resource-response-source-memory-cache.html
      http/tests/inspector/network/resource-response-source-network.html

* platform/network/ResourceResponseBase.cpp:
(WebCore::ResourceResponseBase::setSource): Deleted.
* platform/network/ResourceResponseBase.h:
(WebCore::ResourceResponseBase::setSource):
Make Source mutable to allow it to be set in const methods.

* loader/SubresourceLoader.cpp:
(WebCore::SubresourceLoader::didReceiveResponse):
Set the Response source after a successful memory cache validation
as early as possible so that future copies have up to date info.

* inspector/InspectorNetworkAgent.cpp:
(WebCore::responseSource):
(WebCore::InspectorNetworkAgent::buildObjectForResourceResponse):
(WebCore::InspectorNetworkAgent::didLoadResourceFromMemoryCache):
(WebCore::InspectorNetworkAgent::markResourceAsCached): Deleted.
Eliminate this "markResourceAsCached" path.
Update Response to include required source parameter instead of
optional fromDiskCache parameter.

* inspector/InspectorInstrumentation.cpp:
(WebCore::InspectorInstrumentation::markResourceAsCachedImpl): Deleted.
* inspector/InspectorInstrumentation.h:
(WebCore::InspectorInstrumentation::markResourceAsCached): Deleted.
* inspector/InspectorNetworkAgent.h:
* loader/FrameLoader.cpp:
(WebCore::FrameLoader::loadedResourceFromMemoryCache):
Eliminate this "markResourceAsCached" call because the later delegate
messages will include this information.

Source/WebInspectorUI:

* Localizations/en.lproj/localizedStrings.js:
New localized strings for memory/disk cache information.

* UserInterface/Controllers/FrameResourceManager.js:
(WebInspector.FrameResourceManager.prototype.markResourceRequestAsServedFromMemoryCache):
Make this legacy path more explicit.

(WebInspector.FrameResourceManager.prototype.resourceRequestWasServedFromMemoryCache):
Make this memory cache path more explicit.

(WebInspector.FrameResourceManager.prototype.resourceRequestDidReceiveResponse):
Pass the resource's response source onward.

* UserInterface/Models/Resource.js:
(WebInspector.Resource):
(WebInspector.Resource.responseSourceFromPayload):
(WebInspector.Resource.prototype.get responseSource):
(WebInspector.Resource.prototype.hasResponse):
(WebInspector.Resource.prototype.updateForResponse):
(WebInspector.Resource.prototype.markAsCached):
(WebInspector.Resource.prototype.legacyMarkServedFromMemoryCache):
(WebInspector.Resource.prototype.legacyMarkServedFromDiskCache):
Include a WebInspector.ResponseSource enum.
Update a Resource's responseSource state where appropriate.

* UserInterface/Protocol/NetworkObserver.js:
(WebInspector.NetworkObserver.prototype.requestServedFromCache):
Mark legacy path.

* UserInterface/Views/NetworkGridContentView.js:
(WebInspector.NetworkGridContentView):
* UserInterface/Views/NetworkTimelineView.js:
(WebInspector.NetworkTimelineView):
Tweak default column sizes to make Cached and graph columns a little larger.

* UserInterface/Views/ResourceTimelineDataGridNode.js:
(WebInspector.ResourceTimelineDataGridNode.prototype.createCellContent):
(WebInspector.ResourceTimelineDataGridNode.prototype._cachedCellContent):
Update "Cached" column data with more information if available.

* UserInterface/Views/NetworkGridContentView.css:
(.content-view.network-grid > .data-grid .cache-type):
(.content-view.network-grid > .data-grid:matches(:focus, .force-focus) tr.selected .cache-type):
Style the cache type a secondary color.

LayoutTests:

* http/tests/inspector/network/resource-response-source-disk-cache-expected.txt: Added.
* http/tests/inspector/network/resource-response-source-disk-cache.html: Added.
* http/tests/inspector/network/resource-response-source-memory-cache-expected.txt: Added.
* http/tests/inspector/network/resource-response-source-memory-cache.html: Added.
* http/tests/inspector/network/resource-response-source-network-expected.txt: Added.
* http/tests/inspector/network/resource-response-source-network.html: Added.
* http/tests/inspector/network/resources/cached-script.js: Added.
Test for Network, MemoryCache, and DiskCache loads.

* http/tests/inspector/network/resource-timing-expected.txt:
* http/tests/inspector/network/resource-timing.html:
Fix a typo.

* http/tests/cache/disk-cache/resources/cache-test.js:
(loadResourcesWithOptions):
(loadResources):
Fix typos and style.

* platform/mac-wk1/TestExpectations:
* platform/win/TestExpectations:
Skip disk cache tests where the disk cache is not enabled.

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@213621 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index 907b794..99cd929 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,33 @@
+2017-03-08  Joseph Pecoraro  <pecoraro@apple.com>
+
+        Web Inspector: Should be able to see where Resources came from (Memory Cache, Disk Cache)
+        https://bugs.webkit.org/show_bug.cgi?id=164892
+        <rdar://problem/29320562>
+
+        Reviewed by Brian Burg.
+
+        * http/tests/inspector/network/resource-response-source-disk-cache-expected.txt: Added.
+        * http/tests/inspector/network/resource-response-source-disk-cache.html: Added.
+        * http/tests/inspector/network/resource-response-source-memory-cache-expected.txt: Added.
+        * http/tests/inspector/network/resource-response-source-memory-cache.html: Added.
+        * http/tests/inspector/network/resource-response-source-network-expected.txt: Added.
+        * http/tests/inspector/network/resource-response-source-network.html: Added.
+        * http/tests/inspector/network/resources/cached-script.js: Added.
+        Test for Network, MemoryCache, and DiskCache loads.
+
+        * http/tests/inspector/network/resource-timing-expected.txt:
+        * http/tests/inspector/network/resource-timing.html:
+        Fix a typo.
+
+        * http/tests/cache/disk-cache/resources/cache-test.js:
+        (loadResourcesWithOptions):
+        (loadResources):
+        Fix typos and style.
+
+        * platform/mac-wk1/TestExpectations:
+        * platform/win/TestExpectations:
+        Skip disk cache tests where the disk cache is not enabled.
+
 2017-03-08  Chris Dumez  <cdumez@apple.com>
 
         Drop support for non-standard document.all.tags()
diff --git a/LayoutTests/http/tests/cache/disk-cache/resources/cache-test.js b/LayoutTests/http/tests/cache/disk-cache/resources/cache-test.js
index 4662dfe..0794346 100644
--- a/LayoutTests/http/tests/cache/disk-cache/resources/cache-test.js
+++ b/LayoutTests/http/tests/cache/disk-cache/resources/cache-test.js
@@ -75,7 +75,7 @@
     test.xhr.send();
 }
 
-function loadResourcesWithOptions(tests, options, completetion)
+function loadResourcesWithOptions(tests, options, completion)
 {
     if (options["ClearMemoryCache"])
         internals.clearMemoryCache();
@@ -86,14 +86,14 @@
         loadResource(tests[i], function (ev) {
             --pendingCount;
             if (!pendingCount)
-                completetion(ev);
-         });
+                completion(ev);
+        });
     }
 }
 
-function loadResources(tests, completetion)
+function loadResources(tests, completion)
 {
-    loadResourcesWithOptions(tests, { "ClearMemoryCache" : true }, completetion);
+    loadResourcesWithOptions(tests, { "ClearMemoryCache" : true }, completion);
 }
 
 function printResults(tests)
diff --git a/LayoutTests/http/tests/inspector/network/resource-response-source-disk-cache-expected.txt b/LayoutTests/http/tests/inspector/network/resource-response-source-disk-cache-expected.txt
new file mode 100644
index 0000000..0e54452
--- /dev/null
+++ b/LayoutTests/http/tests/inspector/network/resource-response-source-disk-cache-expected.txt
@@ -0,0 +1,15 @@
+Test for `Resource.ResponseSource.DiskCache`.
+
+
+== Running test suite: Resource.ResponseSource.DiskCache
+-- Running test setup.
+-- Running test case: PossibleNetworkLoad
+PASS: Resource should be created.
+PASS: Resource should receive a Response.
+
+-- Running test case: Resource.ResponseSource.DiskCache
+PASS: Resource should be created.
+PASS: Resource should receive a Response.
+PASS: statusCode should be 200
+PASS: responseSource should be Symbol(disk-cache)
+
diff --git a/LayoutTests/http/tests/inspector/network/resource-response-source-disk-cache.html b/LayoutTests/http/tests/inspector/network/resource-response-source-disk-cache.html
new file mode 100644
index 0000000..a1e459a
--- /dev/null
+++ b/LayoutTests/http/tests/inspector/network/resource-response-source-disk-cache.html
@@ -0,0 +1,70 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<script src="../resources/inspector-test.js"></script>
+<script src="../../cache/disk-cache/resources/cache-test.js"></script>
+<script>
+function loadAndTriggerInspector(url) {
+    fetch(url).then(() => {
+        TestPage.dispatchEventToFrontend("LoadComplete");
+    });
+}
+
+function triggerNetworkLoad() {
+    loadAndTriggerInspector("/resources/square100.png");
+}
+
+function triggerDiskCacheLoad() {
+    loadAndTriggerInspector("/resources/square100.png");
+}
+
+function test()
+{
+    let suite = InspectorTest.createAsyncSuite("Resource.ResponseSource.DiskCache");
+
+    function addTestCase({name, description, setup, expression, statusCode, responseSource}) {
+        suite.addTestCase({
+            name, description, setup,
+            test(resolve, reject) {
+                InspectorTest.evaluateInPage(expression);
+                Promise.all([
+                    WebInspector.Frame.awaitEvent(WebInspector.Frame.Event.ResourceWasAdded),
+                    WebInspector.Resource.awaitEvent(WebInspector.Resource.Event.ResponseReceived),
+                    InspectorTest.awaitEvent("LoadComplete"),
+                ]).then(([resourceWasAddedEvent, responseReceivedEvent, loadCompleteEvent]) => {
+                    let resource = resourceWasAddedEvent.data.resource;
+                    InspectorTest.expectThat(resource instanceof WebInspector.Resource, "Resource should be created.");
+                    InspectorTest.expectEqual(resource, responseReceivedEvent.target, "Resource should receive a Response.");
+                    if (statusCode)
+                        InspectorTest.expectEqual(resource.statusCode, statusCode, `statusCode should be ${statusCode}`);
+                    if (responseSource)
+                        InspectorTest.expectEqual(resource.responseSource, responseSource, `responseSource should be ${String(responseSource)}`);
+                }).then(resolve, reject);
+            }
+        });
+    }
+
+    addTestCase({
+        name: "PossibleNetworkLoad",
+        description: "Load a resource from the network, it might be in an earlier disk cache",
+        setup(resolve) { InspectorTest.evaluateInPage(`internals.clearMemoryCache()`, resolve); },
+        expression: `triggerNetworkLoad()`,
+    });
+
+    addTestCase({
+        name: "Resource.ResponseSource.DiskCache",
+        description: "Load a resource from the disk cache",
+        expression: `triggerDiskCacheLoad()`,
+        responseSource: WebInspector.Resource.ResponseSource.DiskCache,
+        statusCode: 200,
+    });
+
+    suite.runTestCasesAndFinish();
+}
+</script>
+</head>
+<body onload="runTest()">
+<p>Test for `Resource.ResponseSource.DiskCache`.</p>
+</body>
+</html>
diff --git a/LayoutTests/http/tests/inspector/network/resource-response-source-memory-cache-expected.txt b/LayoutTests/http/tests/inspector/network/resource-response-source-memory-cache-expected.txt
new file mode 100644
index 0000000..0056975
--- /dev/null
+++ b/LayoutTests/http/tests/inspector/network/resource-response-source-memory-cache-expected.txt
@@ -0,0 +1,9 @@
+Test for `Resource.ResponseSource.MemoryCache`.
+
+
+== Running test suite: Resource.ResponseSource.MemoryCache
+-- Running test case: Resource.ResponseSource.MemoryCache
+PASS: Resource should be exist.
+PASS: statusCode should be 304
+PASS: responseSource should be Symbol(memory-cache)
+
diff --git a/LayoutTests/http/tests/inspector/network/resource-response-source-memory-cache.html b/LayoutTests/http/tests/inspector/network/resource-response-source-memory-cache.html
new file mode 100644
index 0000000..1914f7b
--- /dev/null
+++ b/LayoutTests/http/tests/inspector/network/resource-response-source-memory-cache.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<script src="resources/cached-script.js"></script>
+<script src="../resources/inspector-test.js"></script>
+<script>
+TestPage.dispatchEventToFrontend("LoadComplete");
+
+function test()
+{
+    let suite = InspectorTest.createAsyncSuite("Resource.ResponseSource.MemoryCache");
+
+    function addReloadTestCase({name, description, expression, pattern, ignoreCache, statusCode, responseSource}) {
+        suite.addTestCase({
+            name, description,
+            test(resolve, reject) {
+                InspectorTest.reloadPage(ignoreCache);
+                InspectorTest.awaitEvent("LoadComplete").then((event) => {
+                    let resource = null;
+                    for (let item of WebInspector.frameResourceManager.mainFrame.resourceCollection.items) {
+                        if (pattern.test(item.url)) {
+                            resource = item;
+                            break;
+                        }
+                    }
+                    if (!resource) {
+                        InspectorTest.fail("Failed to find specific resource.");
+                        reject();
+                        return;
+                    }
+                    InspectorTest.expectThat(resource instanceof WebInspector.Resource, "Resource should be exist.");
+                    InspectorTest.expectEqual(resource.statusCode, statusCode, `statusCode should be ${statusCode}`);
+                    InspectorTest.expectEqual(resource.responseSource, responseSource, `responseSource should be ${String(responseSource)}`);                    
+                }).then(resolve, reject);
+            }
+        });
+    }
+
+    addReloadTestCase({
+        name: "Resource.ResponseSource.MemoryCache",
+        description: "Load a resource from the memory cache by reloading this page.",
+        pattern: /cached-script\.js$/,
+        ignoreCache: false,
+        responseSource: WebInspector.Resource.ResponseSource.MemoryCache,
+        statusCode: 304,
+    });
+
+    suite.runTestCasesAndFinish();
+}
+</script>
+</head>
+<body onload="runTest()">
+<p>Test for `Resource.ResponseSource.MemoryCache`.</p>
+</body>
+</html>
diff --git a/LayoutTests/http/tests/inspector/network/resource-response-source-network-expected.txt b/LayoutTests/http/tests/inspector/network/resource-response-source-network-expected.txt
new file mode 100644
index 0000000..f8a645e
--- /dev/null
+++ b/LayoutTests/http/tests/inspector/network/resource-response-source-network-expected.txt
@@ -0,0 +1,10 @@
+Test for `Resource.ResponseSource.Network`.
+
+
+== Running test suite: Resource.ResponseSource.Network
+-- Running test case: Resource.ResponseSource.Network
+PASS: Resource should be created.
+PASS: Resource should receive a Response.
+PASS: statusCode should be 200
+PASS: responseSource should be Symbol(network)
+
diff --git a/LayoutTests/http/tests/inspector/network/resource-response-source-network.html b/LayoutTests/http/tests/inspector/network/resource-response-source-network.html
new file mode 100644
index 0000000..4941d21
--- /dev/null
+++ b/LayoutTests/http/tests/inspector/network/resource-response-source-network.html
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<script src="../resources/inspector-test.js"></script>
+<script>
+function triggerNetworkLoad() {
+    let url = "resources/data.json?" + Math.random();
+    fetch(url).then(() => {
+        TestPage.dispatchEventToFrontend("LoadComplete");
+    });
+}
+
+function test()
+{
+    let suite = InspectorTest.createAsyncSuite("Resource.ResponseSource.Network");
+
+    function addTestCase({name, description, expression, statusCode, responseSource}) {
+        suite.addTestCase({
+            name, description,
+            test(resolve, reject) {
+                InspectorTest.evaluateInPage(expression);
+                Promise.all([
+                    WebInspector.Frame.awaitEvent(WebInspector.Frame.Event.ResourceWasAdded),
+                    WebInspector.Resource.awaitEvent(WebInspector.Resource.Event.ResponseReceived),
+                    InspectorTest.awaitEvent("LoadComplete"),
+                ]).then(([resourceWasAddedEvent, responseReceivedEvent, loadCompleteEvent]) => {
+                    let resource = resourceWasAddedEvent.data.resource;
+                    InspectorTest.expectThat(resource instanceof WebInspector.Resource, "Resource should be created.");
+                    InspectorTest.expectEqual(resource, responseReceivedEvent.target, "Resource should receive a Response.");
+                    InspectorTest.expectEqual(resource.statusCode, statusCode, `statusCode should be ${statusCode}`);
+                    InspectorTest.expectEqual(resource.responseSource, responseSource, `responseSource should be ${String(responseSource)}`);
+                }).then(resolve, reject);
+            }
+        });
+    }
+
+    addTestCase({
+        name: "Resource.ResponseSource.Network",
+        description: "Load a resource from the network by giving a random URL.",
+        expression: `triggerNetworkLoad()`,
+        responseSource: WebInspector.Resource.ResponseSource.Network,
+        statusCode: 200,
+    });
+
+    suite.runTestCasesAndFinish();
+}
+</script>
+</head>
+<body onload="runTest()">
+<p>Test for `Resource.ResponseSource.Network`.</p>
+</body>
+</html>
diff --git a/LayoutTests/http/tests/inspector/network/resource-timing-expected.txt b/LayoutTests/http/tests/inspector/network/resource-timing-expected.txt
index 94381f3..c2cf7b4 100644
--- a/LayoutTests/http/tests/inspector/network/resource-timing-expected.txt
+++ b/LayoutTests/http/tests/inspector/network/resource-timing-expected.txt
@@ -3,7 +3,7 @@
 
 == Running test suite: ResourceTimingData
 -- Running test case: CheckResourceTimingInformationForResource
-PASS: Resource should be createad.
+PASS: Resource should be created.
 PASS: Added Resource received a response.
 PASS: Added Resource did finish loading.
 PASS: Newly added resource should have a resource timing model.
diff --git a/LayoutTests/http/tests/inspector/network/resource-timing.html b/LayoutTests/http/tests/inspector/network/resource-timing.html
index 10bef54..9c503ca 100644
--- a/LayoutTests/http/tests/inspector/network/resource-timing.html
+++ b/LayoutTests/http/tests/inspector/network/resource-timing.html
@@ -26,7 +26,7 @@
             .then(([resourceWasAddedEvent, responseReceivedEvent, loadingDidFinishEvent]) => {
                 let resource = resourceWasAddedEvent.data.resource;
 
-                InspectorTest.expectThat(resource instanceof WebInspector.Resource, "Resource should be createad.");
+                InspectorTest.expectThat(resource instanceof WebInspector.Resource, "Resource should be created.");
                 InspectorTest.expectThat(resource === responseReceivedEvent.target, "Added Resource received a response.");
                 InspectorTest.expectThat(resource === loadingDidFinishEvent.target, "Added Resource did finish loading.");
 
diff --git a/LayoutTests/http/tests/inspector/network/resources/cached-script.js b/LayoutTests/http/tests/inspector/network/resources/cached-script.js
new file mode 100644
index 0000000..5731a26
--- /dev/null
+++ b/LayoutTests/http/tests/inspector/network/resources/cached-script.js
@@ -0,0 +1 @@
+function cachedScript() {}
diff --git a/LayoutTests/platform/mac-wk1/TestExpectations b/LayoutTests/platform/mac-wk1/TestExpectations
index ac02ea0..210f55f 100644
--- a/LayoutTests/platform/mac-wk1/TestExpectations
+++ b/LayoutTests/platform/mac-wk1/TestExpectations
@@ -146,6 +146,7 @@
 
 # Disk cache is WK2 only
 http/tests/cache/disk-cache
+http/tests/inspector/network/resource-response-source-disk-cache.html
 
 [ Yosemite+ ] fast/ruby/ruby-expansion-cjk-2.html [ ImageOnlyFailure ]
 
diff --git a/LayoutTests/platform/win/TestExpectations b/LayoutTests/platform/win/TestExpectations
index 1469941..a0e447e 100644
--- a/LayoutTests/platform/win/TestExpectations
+++ b/LayoutTests/platform/win/TestExpectations
@@ -2281,6 +2281,7 @@
 
 # Disk cache is WK2 only
 http/tests/cache/disk-cache
+http/tests/inspector/network/resource-response-source-disk-cache.html
 
 # The following are unreviewed:
 http/tests/cache/content-type-ignored-during-revalidation.html [ Failure ]