Web Inspector: Should be able to see where Resources came from (Memory Cache, Disk...
authorjoepeck@webkit.org <joepeck@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 9 Mar 2017 03:35:13 +0000 (03:35 +0000)
committerjoepeck@webkit.org <joepeck@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 9 Mar 2017 03:35:13 +0000 (03:35 +0000)
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: https://svn.webkit.org/repository/webkit/trunk@213621 268f45cc-cd09-0410-ab3c-d52691b4dbfc

39 files changed:
LayoutTests/ChangeLog
LayoutTests/http/tests/cache/disk-cache/resources/cache-test.js
LayoutTests/http/tests/inspector/network/resource-response-source-disk-cache-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/inspector/network/resource-response-source-disk-cache.html [new file with mode: 0644]
LayoutTests/http/tests/inspector/network/resource-response-source-memory-cache-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/inspector/network/resource-response-source-memory-cache.html [new file with mode: 0644]
LayoutTests/http/tests/inspector/network/resource-response-source-network-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/inspector/network/resource-response-source-network.html [new file with mode: 0644]
LayoutTests/http/tests/inspector/network/resource-timing-expected.txt
LayoutTests/http/tests/inspector/network/resource-timing.html
LayoutTests/http/tests/inspector/network/resources/cached-script.js [new file with mode: 0644]
LayoutTests/platform/mac-wk1/TestExpectations
LayoutTests/platform/win/TestExpectations
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/inspector/protocol/Network.json
Source/JavaScriptCore/inspector/scripts/codegen/generate_cpp_protocol_types_header.py
Source/JavaScriptCore/inspector/scripts/codegen/generate_cpp_protocol_types_implementation.py
Source/JavaScriptCore/inspector/scripts/codegen/generator.py
Source/JavaScriptCore/inspector/scripts/tests/generic/expected/type-with-open-parameters.json-result [new file with mode: 0644]
Source/JavaScriptCore/inspector/scripts/tests/generic/type-with-open-parameters.json [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/inspector/InspectorInstrumentation.cpp
Source/WebCore/inspector/InspectorInstrumentation.h
Source/WebCore/inspector/InspectorNetworkAgent.cpp
Source/WebCore/inspector/InspectorNetworkAgent.h
Source/WebCore/loader/FrameLoader.cpp
Source/WebCore/loader/SubresourceLoader.cpp
Source/WebCore/loader/cache/MemoryCache.cpp
Source/WebCore/platform/network/ResourceResponseBase.cpp
Source/WebCore/platform/network/ResourceResponseBase.h
Source/WebInspectorUI/ChangeLog
Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js
Source/WebInspectorUI/UserInterface/Controllers/FrameResourceManager.js
Source/WebInspectorUI/UserInterface/Models/Resource.js
Source/WebInspectorUI/UserInterface/Protocol/NetworkObserver.js
Source/WebInspectorUI/UserInterface/Views/NetworkGridContentView.css
Source/WebInspectorUI/UserInterface/Views/NetworkGridContentView.js
Source/WebInspectorUI/UserInterface/Views/NetworkTimelineView.js
Source/WebInspectorUI/UserInterface/Views/ResourceTimelineDataGridNode.js

index 907b794..99cd929 100644 (file)
@@ -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()
index 4662dfe..0794346 100644 (file)
@@ -75,7 +75,7 @@ function loadResource(test, onload)
     test.xhr.send();
 }
 
-function loadResourcesWithOptions(tests, options, completetion)
+function loadResourcesWithOptions(tests, options, completion)
 {
     if (options["ClearMemoryCache"])
         internals.clearMemoryCache();
@@ -86,14 +86,14 @@ function loadResourcesWithOptions(tests, options, completetion)
         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 (file)
index 0000000..0e54452
--- /dev/null
@@ -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 (file)
index 0000000..a1e459a
--- /dev/null
@@ -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 (file)
index 0000000..0056975
--- /dev/null
@@ -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 (file)
index 0000000..1914f7b
--- /dev/null
@@ -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 (file)
index 0000000..f8a645e
--- /dev/null
@@ -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 (file)
index 0000000..4941d21
--- /dev/null
@@ -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>
index 94381f3..c2cf7b4 100644 (file)
@@ -3,7 +3,7 @@ Tests that a resource has timing information.
 
 == 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.
index 10bef54..9c503ca 100644 (file)
@@ -26,7 +26,7 @@ function test()
             .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 (file)
index 0000000..5731a26
--- /dev/null
@@ -0,0 +1 @@
+function cachedScript() {}
index ac02ea0..210f55f 100644 (file)
@@ -146,6 +146,7 @@ compositing/iframes/overlapped-nested-iframes.html [ Pass Failure ]
 
 # 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 ]
 
index 1469941..a0e447e 100644 (file)
@@ -2281,6 +2281,7 @@ webkit.org/b/60206 http/tests/navigation/response204.html [ Failure ]
 
 # 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 ]
index 2b12b1f..1e9b5c2 100644 (file)
@@ -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.
+
+        * 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.
+
 2017-03-08  Keith Miller  <keith_miller@apple.com>
 
         WebAssembly: Make OOB for fast memory do an extra safety check by ensuring the faulting address is in the range we allocated for fast memory
index 5b159ab..556ae17 100644 (file)
@@ -65,9 +65,9 @@
                 { "name": "headers", "$ref": "Headers", "description": "HTTP response headers." },
                 { "name": "headersText", "type": "string", "optional": true, "description": "HTTP response headers text." },
                 { "name": "mimeType", "type": "string", "description": "Resource mimeType as determined by the browser." },
+                { "name": "source", "type": "string", "enum": ["unknown", "network", "memory-cache", "disk-cache"], "description": "Specifies where the response came from." },
                 { "name": "requestHeaders", "$ref": "Headers", "optional": true, "description": "Refined HTTP request headers that were actually transmitted over the network." },
                 { "name": "requestHeadersText", "type": "string", "optional": true, "description": "HTTP request headers text." },
-                { "name": "fromDiskCache", "type": "boolean", "optional": true, "description": "Specifies that the request was served from the disk cache." },
                 { "name": "timing", "$ref": "ResourceTiming", "optional": true, "description": "Timing information for the given request." }
             ]
         },
index 1f91cdd..4d65331 100755 (executable)
@@ -236,7 +236,8 @@ class CppProtocolTypesHeaderGenerator(CppGenerator):
         if Generator.type_has_open_fields(type_declaration.type):
             lines.append('')
             lines.append('    // Property names for type generated as open.')
-            for type_member in type_declaration.type_members:
+            open_members = Generator.open_fields(type_declaration)
+            for type_member in open_members:
                 export_macro = self.model().framework.setting('export_macro', None)
                 lines.append('    %s static const char* %s;' % (export_macro, ucfirst(type_member.member_name)))
 
index f302a73..c71c39a 100755 (executable)
@@ -161,7 +161,8 @@ class CppProtocolTypesImplementationGenerator(CppGenerator):
         for domain in self.domains_to_generate():
             type_declarations = self.type_declarations_for_domain(domain)
             for type_declaration in filter(lambda decl: Generator.type_has_open_fields(decl.type), type_declarations):
-                for type_member in sorted(type_declaration.type_members, key=lambda member: member.member_name):
+                open_members = Generator.open_fields(type_declaration)
+                for type_member in sorted(open_members, key=lambda member: member.member_name):
                     field_name = '::'.join(['Inspector', 'Protocol', domain.domain_name, ucfirst(type_declaration.type_name), ucfirst(type_member.member_name)])
                     lines.append('const char* %s = "%s";' % (field_name, type_member.member_name))
 
index 2d33b94..6e609a6 100755 (executable)
@@ -65,16 +65,15 @@ _TYPES_NEEDING_RUNTIME_CASTS = set([
 ])
 
 # FIXME: This should be converted into a property in JSON.
-_TYPES_WITH_OPEN_FIELDS = set([
-    "Timeline.TimelineEvent",
+_TYPES_WITH_OPEN_FIELDS = {
+    "Timeline.TimelineEvent": [],
     # InspectorStyleSheet not only creates this property but wants to read it and modify it.
-    "CSS.CSSProperty",
+    "CSS.CSSProperty": [],
     # InspectorNetworkAgent needs to update mime-type.
-    "Network.Response",
+    "Network.Response": ["mimeType"],
     # For testing purposes only.
-    "Test.OpenParameterBundle"
-])
-
+    "Test.OpenParameters": ["alpha"],
+}
 
 class Generator:
     def __init__(self, model, platform, input_filepath):
@@ -144,6 +143,13 @@ class Generator:
     def type_has_open_fields(_type):
         return _type.qualified_name() in _TYPES_WITH_OPEN_FIELDS
 
+    @staticmethod
+    def open_fields(type_declaration):
+        fields = set(_TYPES_WITH_OPEN_FIELDS.get(type_declaration.type.qualified_name(), []))
+        if not fields:
+            return type_declaration.type_members
+        return filter(lambda member: member.member_name in fields, type_declaration.type_members)
+
     def type_needs_shape_assertions(self, _type):
         if not hasattr(self, "_types_needing_shape_assertions"):
             self.calculate_types_requiring_shape_assertions(self.model().domains)
diff --git a/Source/JavaScriptCore/inspector/scripts/tests/generic/expected/type-with-open-parameters.json-result b/Source/JavaScriptCore/inspector/scripts/tests/generic/expected/type-with-open-parameters.json-result
new file mode 100644 (file)
index 0000000..8c8f634
--- /dev/null
@@ -0,0 +1,1158 @@
+### Begin File: InspectorBackendCommands.js
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ * Copyright (C) 2013-2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2014 University of Washington. 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.
+ */
+
+// DO NOT EDIT THIS FILE. It is automatically generated from type-with-open-parameters.json
+// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py
+### End File: InspectorBackendCommands.js
+
+### Begin File: TestAlternateBackendDispatchers.h
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ * Copyright (C) 2013-2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2014 University of Washington. 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.
+ */
+
+// DO NOT EDIT THIS FILE. It is automatically generated from type-with-open-parameters.json
+// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py
+
+#pragma once
+
+#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
+
+#include "TestProtocolTypes.h"
+#include <inspector/InspectorFrontendRouter.h>
+#include <JavaScriptCore/InspectorBackendDispatcher.h>
+
+namespace Inspector {
+
+class AlternateBackendDispatcher {
+public:
+    void setBackendDispatcher(RefPtr<BackendDispatcher>&& dispatcher) { m_backendDispatcher = WTFMove(dispatcher); }
+    BackendDispatcher* backendDispatcher() const { return m_backendDispatcher.get(); }
+private:
+    RefPtr<BackendDispatcher> m_backendDispatcher;
+};
+
+
+
+
+} // namespace Inspector
+
+#endif // ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
+### End File: TestAlternateBackendDispatchers.h
+
+### Begin File: TestBackendDispatchers.h
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ * Copyright (C) 2013-2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2014 University of Washington. 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.
+ */
+
+// DO NOT EDIT THIS FILE. It is automatically generated from type-with-open-parameters.json
+// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py
+
+#pragma once
+
+#include "TestProtocolObjects.h"
+#include <inspector/InspectorBackendDispatcher.h>
+#include <wtf/text/WTFString.h>
+
+namespace Inspector {
+
+typedef String ErrorString;
+
+
+
+} // namespace Inspector
+### End File: TestBackendDispatchers.h
+
+### Begin File: TestBackendDispatchers.cpp
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ * Copyright (C) 2013-2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2014 University of Washington. 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.
+ */
+
+// DO NOT EDIT THIS FILE. It is automatically generated from type-with-open-parameters.json
+// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py
+
+#include "config.h"
+#include "TestBackendDispatchers.h"
+
+#include <inspector/InspectorFrontendRouter.h>
+#include <inspector/InspectorValues.h>
+#include <wtf/NeverDestroyed.h>
+#include <wtf/text/CString.h>
+
+#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
+#include "TestAlternateBackendDispatchers.h"
+#endif
+
+namespace Inspector {
+
+
+
+} // namespace Inspector
+
+### End File: TestBackendDispatchers.cpp
+
+### Begin File: TestFrontendDispatchers.h
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ * Copyright (C) 2013-2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2014 University of Washington. 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.
+ */
+
+// DO NOT EDIT THIS FILE. It is automatically generated from type-with-open-parameters.json
+// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py
+
+#pragma once
+
+#include "TestProtocolObjects.h"
+#include <inspector/InspectorValues.h>
+#include <wtf/text/WTFString.h>
+
+namespace Inspector {
+
+class FrontendRouter;
+
+} // namespace Inspector
+### End File: TestFrontendDispatchers.h
+
+### Begin File: TestFrontendDispatchers.cpp
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ * Copyright (C) 2013-2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2014 University of Washington. 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.
+ */
+
+// DO NOT EDIT THIS FILE. It is automatically generated from type-with-open-parameters.json
+// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py
+
+#include "config.h"
+#include "TestFrontendDispatchers.h"
+
+#include "InspectorFrontendRouter.h"
+#include <wtf/text/CString.h>
+
+namespace Inspector {
+
+} // namespace Inspector
+
+### End File: TestFrontendDispatchers.cpp
+
+### Begin File: TestProtocolObjects.h
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ * Copyright (C) 2013-2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2014 University of Washington. 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.
+ */
+
+// DO NOT EDIT THIS FILE. It is automatically generated from type-with-open-parameters.json
+// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py
+
+#pragma once
+
+#include <inspector/InspectorProtocolTypes.h>
+#include <wtf/Assertions.h>
+
+namespace Inspector {
+
+
+
+namespace Protocol {
+
+// Forward declarations.
+namespace Test {
+class NoOpenParameters;
+class OpenParameters;
+} // Test
+// End of forward declarations.
+
+
+
+
+namespace Test {
+class NoOpenParameters : public Inspector::InspectorObjectBase {
+public:
+    enum {
+        NoFieldsSet = 0,
+        OneSet = 1 << 0,
+        TwoSet = 1 << 1,
+        AllFieldsSet = (OneSet | TwoSet)
+    };
+
+    template<int STATE>
+    class Builder {
+    private:
+        RefPtr<InspectorObject> m_result;
+
+        template<int STEP> Builder<STATE | STEP>& castState()
+        {
+            return *reinterpret_cast<Builder<STATE | STEP>*>(this);
+        }
+
+        Builder(Ref</*NoOpenParameters*/InspectorObject>&& object)
+            : m_result(WTFMove(object))
+        {
+            COMPILE_ASSERT(STATE == NoFieldsSet, builder_created_in_non_init_state);
+        }
+        friend class NoOpenParameters;
+    public:
+
+        Builder<STATE | OneSet>& setOne(double value)
+        {
+            COMPILE_ASSERT(!(STATE & OneSet), property_one_already_set);
+            m_result->setDouble(ASCIILiteral("one"), value);
+            return castState<OneSet>();
+        }
+
+        Builder<STATE | TwoSet>& setTwo(double value)
+        {
+            COMPILE_ASSERT(!(STATE & TwoSet), property_two_already_set);
+            m_result->setDouble(ASCIILiteral("two"), value);
+            return castState<TwoSet>();
+        }
+
+        Ref<NoOpenParameters> release()
+        {
+            COMPILE_ASSERT(STATE == AllFieldsSet, result_is_not_ready);
+            COMPILE_ASSERT(sizeof(NoOpenParameters) == sizeof(InspectorObject), cannot_cast);
+
+            Ref<InspectorObject> result = m_result.releaseNonNull();
+            return WTFMove(*reinterpret_cast<Ref<NoOpenParameters>*>(&result));
+        }
+    };
+
+    /*
+     * Synthetic constructor:
+     * Ref<NoOpenParameters> result = NoOpenParameters::create()
+     *     .setOne(...)
+     *     .setTwo(...)
+     *     .release();
+     */
+    static Builder<NoFieldsSet> create()
+    {
+        return Builder<NoFieldsSet>(InspectorObject::create());
+    }
+};
+
+class OpenParameters : public Inspector::InspectorObject {
+public:
+    enum {
+        NoFieldsSet = 0,
+        AlphaSet = 1 << 0,
+        BetaSet = 1 << 1,
+        AllFieldsSet = (AlphaSet | BetaSet)
+    };
+
+    template<int STATE>
+    class Builder {
+    private:
+        RefPtr<InspectorObject> m_result;
+
+        template<int STEP> Builder<STATE | STEP>& castState()
+        {
+            return *reinterpret_cast<Builder<STATE | STEP>*>(this);
+        }
+
+        Builder(Ref</*OpenParameters*/InspectorObject>&& object)
+            : m_result(WTFMove(object))
+        {
+            COMPILE_ASSERT(STATE == NoFieldsSet, builder_created_in_non_init_state);
+        }
+        friend class OpenParameters;
+    public:
+
+        Builder<STATE | AlphaSet>& setAlpha(double value)
+        {
+            COMPILE_ASSERT(!(STATE & AlphaSet), property_alpha_already_set);
+            m_result->setDouble(ASCIILiteral("alpha"), value);
+            return castState<AlphaSet>();
+        }
+
+        Builder<STATE | BetaSet>& setBeta(double value)
+        {
+            COMPILE_ASSERT(!(STATE & BetaSet), property_beta_already_set);
+            m_result->setDouble(ASCIILiteral("beta"), value);
+            return castState<BetaSet>();
+        }
+
+        Ref<OpenParameters> release()
+        {
+            COMPILE_ASSERT(STATE == AllFieldsSet, result_is_not_ready);
+            COMPILE_ASSERT(sizeof(OpenParameters) == sizeof(InspectorObject), cannot_cast);
+
+            Ref<InspectorObject> result = m_result.releaseNonNull();
+            return WTFMove(*reinterpret_cast<Ref<OpenParameters>*>(&result));
+        }
+    };
+
+    /*
+     * Synthetic constructor:
+     * Ref<OpenParameters> result = OpenParameters::create()
+     *     .setAlpha(...)
+     *     .setBeta(...)
+     *     .release();
+     */
+    static Builder<NoFieldsSet> create()
+    {
+        return Builder<NoFieldsSet>(InspectorObject::create());
+    }
+
+    // Property names for type generated as open.
+    None static const char* Alpha;
+};
+
+} // Test
+
+
+
+} // namespace Protocol
+
+} // namespace Inspector
+### End File: TestProtocolObjects.h
+
+### Begin File: TestProtocolObjects.cpp
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ * Copyright (C) 2013-2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2014 University of Washington. 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.
+ */
+
+// DO NOT EDIT THIS FILE. It is automatically generated from type-with-open-parameters.json
+// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py
+
+#include "config.h"
+#include "TestProtocolObjects.h"
+
+#include <wtf/Optional.h>
+#include <wtf/text/CString.h>
+
+namespace Inspector {
+
+namespace Protocol {
+
+const char* Inspector::Protocol::Test::OpenParameters::Alpha = "alpha";
+
+} // namespace Protocol
+
+} // namespace Inspector
+
+### End File: TestProtocolObjects.cpp
+
+### Begin File: TestProtocolBackendDispatchers.h
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ * Copyright (C) 2013-2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2014 University of Washington. 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.
+ */
+
+// DO NOT EDIT THIS FILE. It is automatically generated from type-with-open-parameters.json
+// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py
+
+#include <JavaScriptCore/InspectorAlternateBackendDispatchers.h>
+#include <wtf/RetainPtr.h>
+
+
+
+namespace Inspector {
+
+
+} // namespace Inspector
+
+### End File: TestProtocolBackendDispatchers.h
+
+### Begin File: TestProtocolBackendDispatchers.mm
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ * Copyright (C) 2013-2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2014 University of Washington. 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.
+ */
+
+// DO NOT EDIT THIS FILE. It is automatically generated from type-with-open-parameters.json
+// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py
+
+#import "config.h"
+#import "TestProtocolBackendDispatchers.h"
+
+#include "TestProtocolInternal.h"
+#include "TestProtocolTypeConversions.h"
+#include <JavaScriptCore/InspectorValues.h>
+
+namespace Inspector {
+
+} // namespace Inspector
+
+### End File: TestProtocolBackendDispatchers.mm
+
+### Begin File: TestProtocolConfiguration.h
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ * Copyright (C) 2013-2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2014 University of Washington. 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.
+ */
+
+// DO NOT EDIT THIS FILE. It is automatically generated from type-with-open-parameters.json
+// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py
+
+#import <WebInspector/TestProtocol.h>
+
+__attribute__((visibility ("default")))
+@interface TestProtocolConfiguration : NSObject
+@end
+
+
+### End File: TestProtocolConfiguration.h
+
+### Begin File: TestProtocolConfiguration.mm
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ * Copyright (C) 2013-2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2014 University of Washington. 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.
+ */
+
+// DO NOT EDIT THIS FILE. It is automatically generated from type-with-open-parameters.json
+// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py
+
+#import "TestProtocolConfiguration.h"
+
+#import "TestProtocolInternal.h"
+#import "TestProtocolBackendDispatchers.h"
+#import <JavaScriptCore/AlternateDispatchableAgent.h>
+#import <JavaScriptCore/AugmentableInspectorController.h>
+#import <JavaScriptCore/InspectorAlternateBackendDispatchers.h>
+#import <JavaScriptCore/InspectorBackendDispatchers.h>
+
+using namespace Inspector;
+
+@implementation TestProtocolConfiguration
+{
+    AugmentableInspectorController* _controller;
+}
+
+- (instancetype)initWithController:(AugmentableInspectorController*)controller
+{
+    self = [super init];
+    if (!self)
+        return nil;
+    ASSERT(controller);
+    _controller = controller;
+    return self;
+}
+
+- (void)dealloc
+{
+    [super dealloc];
+}
+
+@end
+
+
+### End File: TestProtocolConfiguration.mm
+
+### Begin File: TestProtocolEventDispatchers.mm
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ * Copyright (C) 2013-2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2014 University of Washington. 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.
+ */
+
+// DO NOT EDIT THIS FILE. It is automatically generated from type-with-open-parameters.json
+// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py
+
+#import "TestProtocolInternal.h"
+
+#import "TestProtocolTypeConversions.h"
+#import <JavaScriptCore/InspectorValues.h>
+
+using namespace Inspector;
+
+
+### End File: TestProtocolEventDispatchers.mm
+
+### Begin File: TestProtocol.h
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ * Copyright (C) 2013-2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2014 University of Washington. 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.
+ */
+
+// DO NOT EDIT THIS FILE. It is automatically generated from type-with-open-parameters.json
+// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py
+
+#import <Foundation/Foundation.h>
+
+#import <WebInspector/RWIProtocolJSONObject.h>
+
+
+@class TestProtocolTestNoOpenParameters;
+@class TestProtocolTestOpenParameters;
+
+typedef NS_ENUM(NSInteger, TestProtocolPlatform) {
+    TestProtocolPlatformAll,
+    TestProtocolPlatformGeneric,
+    TestProtocolPlatformIOS,
+    TestProtocolPlatformMacOS,
+};
+
+
+
+
+__attribute__((visibility ("default")))
+@interface TestProtocolTestNoOpenParameters : RWIProtocolJSONObject
+- (instancetype)initWithPayload:(NSDictionary<NSString *, id> *)payload;
+- (instancetype)initWithJSONObject:(RWIProtocolJSONObject *)jsonObject;
+- (instancetype)initWithOne:(double)one two:(double)two;
+/* required */ @property (nonatomic, assign) double one;
+/* required */ @property (nonatomic, assign) double two;
+@end
+
+__attribute__((visibility ("default")))
+@interface TestProtocolTestOpenParameters : RWIProtocolJSONObject
+- (instancetype)initWithPayload:(NSDictionary<NSString *, id> *)payload;
+- (instancetype)initWithJSONObject:(RWIProtocolJSONObject *)jsonObject;
+- (instancetype)initWithAlpha:(double)alpha beta:(double)beta;
+/* required */ @property (nonatomic, assign) double alpha;
+/* required */ @property (nonatomic, assign) double beta;
+@end
+
+
+
+
+
+
+### End File: TestProtocol.h
+
+### Begin File: TestProtocolInternal.h
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ * Copyright (C) 2013-2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2014 University of Washington. 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.
+ */
+
+// DO NOT EDIT THIS FILE. It is automatically generated from type-with-open-parameters.json
+// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py
+
+#import "TestProtocol.h"
+#import "TestProtocolJSONObjectPrivate.h"
+#import <JavaScriptCore/AugmentableInspectorController.h>
+#import <JavaScriptCore/InspectorValues.h>
+
+
+
+
+### End File: TestProtocolInternal.h
+
+### Begin File: TestProtocolTypeConversions.h
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ * Copyright (C) 2013-2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2014 University of Washington. 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.
+ */
+
+// DO NOT EDIT THIS FILE. It is automatically generated from type-with-open-parameters.json
+// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py
+
+#import "TestProtocol.h"
+#import <WebInspector/RWIProtocolArrayConversions.h>
+
+namespace Inspector {
+
+template<typename ObjCEnumType>
+std::optional<ObjCEnumType> fromProtocolString(const String& value);
+
+inline String toProtocolString(TestProtocolPlatform value)
+{
+    switch(value) {
+    case TestProtocolPlatformAll:
+        return ASCIILiteral("all");
+    case TestProtocolPlatformGeneric:
+        return ASCIILiteral("generic");
+    case TestProtocolPlatformIOS:
+        return ASCIILiteral("ios");
+    case TestProtocolPlatformMacOS:
+        return ASCIILiteral("macos");
+    }
+}
+
+template<>
+inline std::optional<TestProtocolPlatform> fromProtocolString(const String& value)
+{
+    if (value == "all")
+        return TestProtocolPlatformAll;
+    if (value == "generic")
+        return TestProtocolPlatformGeneric;
+    if (value == "ios")
+        return TestProtocolPlatformIOS;
+    if (value == "macos")
+        return TestProtocolPlatformMacOS;
+    return std::nullopt;
+}
+
+
+
+} // namespace Inspector
+
+### End File: TestProtocolTypeConversions.h
+
+### Begin File: TestProtocolTypeConversions.mm
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ * Copyright (C) 2013-2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2014 University of Washington. 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.
+ */
+
+// DO NOT EDIT THIS FILE. It is automatically generated from type-with-open-parameters.json
+// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py
+
+#import "TestProtocolTypeConversions.h"
+
+#import "TestProtocol.h"
+#import "TestProtocolTypeParser.h"
+#import <WebInspector/RWIProtocolJSONObjectPrivate.h>
+
+using namespace Inspector;
+
+@interface TestProtocolTypeConversions (TestDomain)
+
++ (void)_parseNoOpenParameters:(TestProtocolTestNoOpenParameters **)outValue fromPayload:(id)payload;
++ (void)_parseOpenParameters:(TestProtocolTestOpenParameters **)outValue fromPayload:(id)payload;
+
+@end
+
+@implementation TestProtocolTypeConversions (TestDomain)
+
++ (void)_parseNoOpenParameters:(TestProtocolTestNoOpenParameters **)outValue fromPayload:(id)payload
+{
+    THROW_EXCEPTION_FOR_BAD_TYPE(payload, [NSDictionary class]);
+    *outValue = [[TestProtocolTestNoOpenParameters alloc] initWithPayload:payload];
+}
+
++ (void)_parseOpenParameters:(TestProtocolTestOpenParameters **)outValue fromPayload:(id)payload
+{
+    THROW_EXCEPTION_FOR_BAD_TYPE(payload, [NSDictionary class]);
+    *outValue = [[TestProtocolTestOpenParameters alloc] initWithPayload:payload];
+}
+
+@end
+
+
+### End File: TestProtocolTypeConversions.mm
+
+### Begin File: TestProtocolTypes.mm
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ * Copyright (C) 2013-2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2014 University of Washington. 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.
+ */
+
+// DO NOT EDIT THIS FILE. It is automatically generated from type-with-open-parameters.json
+// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py
+
+#import "TestProtocolInternal.h"
+
+#import "TestProtocolTypeConversions.h"
+#import <WebInspector/RWIProtocolJSONObjectPrivate.h>
+#import <JavaScriptCore/InspectorValues.h>
+#import <wtf/Assertions.h>
+
+using namespace Inspector;
+
+
+@implementation TestProtocolTestNoOpenParameters
+
+- (instancetype)initWithPayload:(nonnull NSDictionary<NSString *, id> *)payload
+{
+    if (!(self = [super init]))
+        return nil;
+
+    THROW_EXCEPTION_FOR_REQUIRED_PROPERTY(payload[@"one"], @"one");
+    self.one = [payload[@"one"] doubleValue];
+
+    THROW_EXCEPTION_FOR_REQUIRED_PROPERTY(payload[@"two"], @"two");
+    self.two = [payload[@"two"] doubleValue];
+
+    return self;
+}
+- (instancetype)initWithJSONObject:(RWIProtocolJSONObject *)jsonObject
+{
+    if (!(self = [super initWithInspectorObject:[jsonObject toInspectorObject].get()]))
+        return nil;
+
+    return self;
+}
+
+- (instancetype)initWithOne:(double)one two:(double)two
+{
+    if (!(self = [super init]))
+        return nil;
+
+    self.one = one;
+    self.two = two;
+
+    return self;
+}
+
+- (void)setOne:(double)one
+{
+    [super setDouble:one forKey:@"one"];
+}
+
+- (double)one
+{
+    return [super doubleForKey:@"one"];
+}
+
+- (void)setTwo:(double)two
+{
+    [super setDouble:two forKey:@"two"];
+}
+
+- (double)two
+{
+    return [super doubleForKey:@"two"];
+}
+
+@end
+
+@implementation TestProtocolTestOpenParameters
+
+- (instancetype)initWithPayload:(nonnull NSDictionary<NSString *, id> *)payload
+{
+    if (!(self = [super init]))
+        return nil;
+
+    THROW_EXCEPTION_FOR_REQUIRED_PROPERTY(payload[@"alpha"], @"alpha");
+    self.alpha = [payload[@"alpha"] doubleValue];
+
+    THROW_EXCEPTION_FOR_REQUIRED_PROPERTY(payload[@"beta"], @"beta");
+    self.beta = [payload[@"beta"] doubleValue];
+
+    return self;
+}
+- (instancetype)initWithJSONObject:(RWIProtocolJSONObject *)jsonObject
+{
+    if (!(self = [super initWithInspectorObject:[jsonObject toInspectorObject].get()]))
+        return nil;
+
+    return self;
+}
+
+- (instancetype)initWithAlpha:(double)alpha beta:(double)beta
+{
+    if (!(self = [super init]))
+        return nil;
+
+    self.alpha = alpha;
+    self.beta = beta;
+
+    return self;
+}
+
+- (void)setAlpha:(double)alpha
+{
+    [super setDouble:alpha forKey:@"alpha"];
+}
+
+- (double)alpha
+{
+    return [super doubleForKey:@"alpha"];
+}
+
+- (void)setBeta:(double)beta
+{
+    [super setDouble:beta forKey:@"beta"];
+}
+
+- (double)beta
+{
+    return [super doubleForKey:@"beta"];
+}
+
+@end
+
+
+### End File: TestProtocolTypes.mm
diff --git a/Source/JavaScriptCore/inspector/scripts/tests/generic/type-with-open-parameters.json b/Source/JavaScriptCore/inspector/scripts/tests/generic/type-with-open-parameters.json
new file mode 100644 (file)
index 0000000..99b0220
--- /dev/null
@@ -0,0 +1,21 @@
+{
+    "domain": "Test",
+    "types": [
+        {
+            "id": "NoOpenParameters",
+            "type": "object",
+            "properties": [
+                { "name": "one", "type": "number" },
+                { "name": "two", "type": "number" }
+            ]
+        },
+        {
+            "id": "OpenParameters",
+            "type": "object",
+            "properties": [
+                { "name": "alpha", "type": "number" },
+                { "name": "beta", "type": "number" }
+            ]
+        }
+    ]
+}
index 5a96b39..d7275d6 100644 (file)
@@ -1,3 +1,45 @@
+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.
+
+        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.
+
 2017-03-08  Chris Dumez  <cdumez@apple.com>
 
         Drop support for non-standard document.all.tags()
index 580a828..caad76b 100644 (file)
@@ -564,12 +564,6 @@ void InspectorInstrumentation::continueAfterPingLoaderImpl(InstrumentingAgents&
     willSendRequestImpl(instrumentingAgents, identifier, loader, request, response);
 }
 
-void InspectorInstrumentation::markResourceAsCachedImpl(InstrumentingAgents& instrumentingAgents, unsigned long identifier)
-{
-    if (InspectorNetworkAgent* networkAgent = instrumentingAgents.inspectorNetworkAgent())
-        networkAgent->markResourceAsCached(identifier);
-}
-
 void InspectorInstrumentation::didLoadResourceFromMemoryCacheImpl(InstrumentingAgents& instrumentingAgents, DocumentLoader* loader, CachedResource* cachedResource)
 {
     if (!instrumentingAgents.inspectorEnvironment().developerExtrasEnabled())
index c9db4ff..8e00a8c 100644 (file)
@@ -152,7 +152,6 @@ public:
     static void applyEmulatedMedia(Frame&, String&);
     static void willSendRequest(Frame*, unsigned long identifier, DocumentLoader*, ResourceRequest&, const ResourceResponse& redirectResponse);
     static void continueAfterPingLoader(Frame&, unsigned long identifier, DocumentLoader*, ResourceRequest&, const ResourceResponse&);
-    static void markResourceAsCached(Page&, unsigned long identifier);
     static void didLoadResourceFromMemoryCache(Page&, DocumentLoader*, CachedResource*);
     static void didReceiveResourceResponse(Frame&, unsigned long identifier, DocumentLoader*, const ResourceResponse&, ResourceLoader*);
     static void didReceiveThreadableLoaderResponse(DocumentThreadableLoader&, unsigned long identifier);
@@ -835,11 +834,6 @@ inline void InspectorInstrumentation::continueAfterPingLoader(Frame& frame, unsi
         InspectorInstrumentation::continueAfterPingLoaderImpl(*instrumentingAgents, identifier, loader, request, response);
 }
 
-inline void InspectorInstrumentation::markResourceAsCached(Page& page, unsigned long identifier)
-{
-    markResourceAsCachedImpl(instrumentingAgentsForPage(page), identifier);
-}
-
 inline void InspectorInstrumentation::didLoadResourceFromMemoryCache(Page& page, DocumentLoader* loader, CachedResource* resource)
 {
     didLoadResourceFromMemoryCacheImpl(instrumentingAgentsForPage(page), loader, resource);
index ee34ccf..f15feb3 100644 (file)
@@ -211,6 +211,25 @@ static Ref<Inspector::Protocol::Network::Request> buildObjectForResourceRequest(
     return requestObject;
 }
 
+static Inspector::Protocol::Network::Response::Source responseSource(ResourceResponse::Source source)
+{
+    switch (source) {
+    case ResourceResponse::Source::Unknown:
+        return Inspector::Protocol::Network::Response::Source::Unknown;
+    case ResourceResponse::Source::Network:
+        return Inspector::Protocol::Network::Response::Source::Network;
+    case ResourceResponse::Source::MemoryCache:
+    case ResourceResponse::Source::MemoryCacheAfterValidation:
+        return Inspector::Protocol::Network::Response::Source::MemoryCache;
+    case ResourceResponse::Source::DiskCache:
+    case ResourceResponse::Source::DiskCacheAfterValidation:
+        return Inspector::Protocol::Network::Response::Source::DiskCache;
+    }
+
+    ASSERT_NOT_REACHED();
+    return Inspector::Protocol::Network::Response::Source::Unknown;
+}
+
 RefPtr<Inspector::Protocol::Network::Response> InspectorNetworkAgent::buildObjectForResourceResponse(const ResourceResponse& response, ResourceLoader* resourceLoader)
 {
     if (response.isNull())
@@ -225,9 +244,9 @@ RefPtr<Inspector::Protocol::Network::Response> InspectorNetworkAgent::buildObjec
         .setStatusText(response.httpStatusText())
         .setHeaders(WTFMove(headers))
         .setMimeType(response.mimeType())
+        .setSource(responseSource(response.source()))
         .release();
 
-    responseObject->setFromDiskCache(response.source() == ResourceResponse::Source::DiskCache || response.source() == ResourceResponse::Source::DiskCacheAfterValidation);
     if (resourceLoader)
         responseObject->setTiming(buildObjectForTiming(response.deprecatedNetworkLoadMetrics(), *resourceLoader));
 
@@ -309,14 +328,6 @@ void InspectorNetworkAgent::willSendRequest(unsigned long identifier, DocumentLo
     m_frontendDispatcher->requestWillBeSent(requestId, m_pageAgent->frameId(loader.frame()), m_pageAgent->loaderId(&loader), loader.url().string(), buildObjectForResourceRequest(request), timestamp(), initiatorObject, buildObjectForResourceResponse(redirectResponse, nullptr), type != InspectorPageAgent::OtherResource ? &resourceType : nullptr, targetId.isEmpty() ? nullptr : &targetId);
 }
 
-void InspectorNetworkAgent::markResourceAsCached(unsigned long identifier)
-{
-    if (m_hiddenRequestIdentifiers.contains(identifier))
-        return;
-
-    m_frontendDispatcher->requestServedFromCache(IdentifiersFactory::requestId(identifier));
-}
-
 void InspectorNetworkAgent::didReceiveResponse(unsigned long identifier, DocumentLoader& loader, const ResourceResponse& response, ResourceLoader* resourceLoader)
 {
     if (m_hiddenRequestIdentifiers.contains(identifier))
@@ -428,11 +439,16 @@ void InspectorNetworkAgent::didLoadResourceFromMemoryCache(DocumentLoader& loade
     String frameId = m_pageAgent->frameId(loader.frame());
     unsigned long identifier = loader.frame()->page()->progress().createUniqueIdentifier();
     String requestId = IdentifiersFactory::requestId(identifier);
+
     m_resourcesData->resourceCreated(requestId, loaderId);
     m_resourcesData->addCachedResource(requestId, &resource);
 
     RefPtr<Inspector::Protocol::Network::Initiator> initiatorObject = buildInitiatorObject(loader.frame() ? loader.frame()->document() : nullptr);
 
+    // FIXME: It would be ideal to generate the Network.Response with the MemoryCache source
+    // instead of whatever ResourceResponse::Source the CachedResources's response has.
+    // The frontend already knows for certain that this was served from the memory cache.
+
     m_frontendDispatcher->requestServedFromMemoryCache(requestId, frameId, loaderId, loader.url().string(), timestamp(), initiatorObject, buildObjectForCachedResource(&resource));
 }
 
index 5c29246..449fef5 100644 (file)
@@ -76,7 +76,6 @@ public:
     void willRecalculateStyle();
     void didRecalculateStyle();
     void willSendRequest(unsigned long identifier, DocumentLoader&, ResourceRequest&, const ResourceResponse& redirectResponse);
-    void markResourceAsCached(unsigned long identifier);
     void didReceiveResponse(unsigned long identifier, DocumentLoader&, const ResourceResponse&, ResourceLoader*);
     void didReceiveData(unsigned long identifier, const char* data, int dataLength, int encodedDataLength);
     void didFinishLoading(unsigned long identifier, DocumentLoader&);
index 6851b8b..2345c55 100644 (file)
@@ -3218,8 +3218,10 @@ void FrameLoader::loadedResourceFromMemoryCache(CachedResource* resource, Resour
     unsigned long identifier;
     ResourceError error;
     requestFromDelegate(newRequest, identifier, error);
-    InspectorInstrumentation::markResourceAsCached(*page, identifier);
-    notifier().sendRemainingDelegateMessages(m_documentLoader.get(), identifier, newRequest, resource->response(), 0, resource->encodedSize(), 0, error);
+
+    ResourceResponse response = resource->response();
+    response.setSource(ResourceResponse::Source::MemoryCache);
+    notifier().sendRemainingDelegateMessages(m_documentLoader.get(), identifier, newRequest, response, 0, resource->encodedSize(), 0, error);
 }
 
 void FrameLoader::applyUserAgent(ResourceRequest& request)
index da8b0ae..a80fc00 100644 (file)
@@ -301,12 +301,14 @@ void SubresourceLoader::didReceiveResponse(const ResourceResponse& response)
         if (response.httpStatusCode() == 304) {
             // 304 Not modified / Use local copy
             // Existing resource is ok, just use it updating the expiration time.
-            m_resource->setResponse(response);
-            MemoryCache::singleton().revalidationSucceeded(*m_resource, response);
+            ResourceResponse revalidationResponse = response;
+            revalidationResponse.setSource(ResourceResponse::Source::MemoryCacheAfterValidation);
+            m_resource->setResponse(revalidationResponse);
+            MemoryCache::singleton().revalidationSucceeded(*m_resource, revalidationResponse);
             if (m_frame && m_frame->page())
                 m_frame->page()->diagnosticLoggingClient().logDiagnosticMessageWithResult(DiagnosticLoggingKeys::cachedResourceRevalidationKey(), emptyString(), DiagnosticLoggingResultPass, ShouldSample::Yes);
             if (!reachedTerminalState())
-                ResourceLoader::didReceiveResponse(response);
+                ResourceLoader::didReceiveResponse(revalidationResponse);
             return;
         }
         // Did not get 304 response, continue as a regular resource load.
index 75ee84b..d413fb8 100644 (file)
@@ -128,6 +128,7 @@ bool MemoryCache::add(CachedResource& resource)
 
 void MemoryCache::revalidationSucceeded(CachedResource& revalidatingResource, const ResourceResponse& response)
 {
+    ASSERT(response.source() == ResourceResponse::Source::MemoryCacheAfterValidation);
     ASSERT(revalidatingResource.resourceToRevalidate());
     CachedResource& resource = *revalidatingResource.resourceToRevalidate();
     ASSERT(!resource.inCache());
index eb6bdf7..78c269b 100644 (file)
@@ -565,11 +565,6 @@ ResourceResponseBase::Source ResourceResponseBase::source() const
     return m_source;
 }
 
-void ResourceResponseBase::setSource(Source source)
-{
-    m_source = source;
-}
-
 void ResourceResponseBase::lazyInit(InitLevel initLevel) const
 {
     const_cast<ResourceResponse*>(static_cast<const ResourceResponse*>(this))->platformLazyInit(initLevel);
index 1effe1f..3e32f03 100644 (file)
@@ -132,10 +132,9 @@ public:
     WEBCORE_EXPORT std::optional<std::chrono::system_clock::time_point> lastModified() const;
     ParsedContentRange& contentRange() const;
 
-    // This is primarily for testing support. It is not necessarily accurate in all scenarios.
     enum class Source { Unknown, Network, DiskCache, DiskCacheAfterValidation, MemoryCache, MemoryCacheAfterValidation };
     WEBCORE_EXPORT Source source() const;
-    WEBCORE_EXPORT void setSource(Source);
+    void setSource(Source source) { m_source = source; }
 
     const std::optional<SHA1::Digest>& cacheBodyKey() const { return m_cacheBodyKey; }
     void setCacheBodyKey(const SHA1::Digest& key) { m_cacheBodyKey = key; }
index 62b721d..90793ec 100644 (file)
@@ -1,3 +1,56 @@
+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.
+
+        * 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.
+
 2017-03-08  Devin Rousso  <dcrousso+webkit@gmail.com>
 
         Web Inspector: add a "create breakpoint" context menu item for linkified source locations
index dcc6f01..15c8ebf 100644 (file)
@@ -41,7 +41,9 @@ localizedStrings["%s \u2014 %s"] = "%s \u2014 %s";
 localizedStrings["%s cannot be modified"] = "%s cannot be modified";
 localizedStrings["%s delay"] = "%s delay";
 localizedStrings["%s interval"] = "%s interval";
+localizedStrings["(Disk)"] = "(Disk)";
 localizedStrings["(Index)"] = "(Index)";
+localizedStrings["(Memory)"] = "(Memory)";
 localizedStrings["(Tail Call)"] = "(Tail Call)";
 localizedStrings["(anonymous function)"] = "(anonymous function)";
 localizedStrings["(async)"] = "(async)";
index 0c6f80f..398b00f 100644 (file)
@@ -305,7 +305,7 @@ WebInspector.FrameResourceManager = class FrameResourceManager extends WebInspec
         if (!resource)
             return;
 
-        resource.markAsCached();
+        resource.legacyMarkServedFromMemoryCache();
     }
 
     resourceRequestWasServedFromMemoryCache(requestIdentifier, frameIdentifier, loaderIdentifier, cachedResourcePayload, timestamp, initiator)
@@ -318,16 +318,19 @@ WebInspector.FrameResourceManager = class FrameResourceManager extends WebInspec
 
         console.assert(!this._resourceRequestIdentifierMap.has(requestIdentifier));
 
-        var elapsedTime = WebInspector.timelineManager.computeElapsedTime(timestamp);
-        var initiatorSourceCodeLocation = this._initiatorSourceCodeLocationFromPayload(initiator);
-        var response = cachedResourcePayload.response;
-        var resource = this._addNewResourceToFrameOrTarget(requestIdentifier, frameIdentifier, loaderIdentifier, cachedResourcePayload.url, cachedResourcePayload.type, "GET", null, null, elapsedTime, null, null, initiatorSourceCodeLocation);
-        resource.markAsCached();
-        resource.updateForResponse(cachedResourcePayload.url, response.mimeType, cachedResourcePayload.type, response.headers, response.status, response.statusText, elapsedTime, response.timing);
+        let elapsedTime = WebInspector.timelineManager.computeElapsedTime(timestamp);
+        let initiatorSourceCodeLocation = this._initiatorSourceCodeLocationFromPayload(initiator);
+        let response = cachedResourcePayload.response;
+        const responseSource = NetworkAgent.ResponseSource.MemoryCache;
+
+        let resource = this._addNewResourceToFrameOrTarget(requestIdentifier, frameIdentifier, loaderIdentifier, cachedResourcePayload.url, cachedResourcePayload.type, "GET", null, null, elapsedTime, null, null, initiatorSourceCodeLocation);
+        resource.updateForResponse(cachedResourcePayload.url, response.mimeType, cachedResourcePayload.type, response.headers, response.status, response.statusText, elapsedTime, response.timing, responseSource);
         resource.increaseSize(cachedResourcePayload.bodySize, elapsedTime);
         resource.increaseTransferSize(cachedResourcePayload.bodySize);
         resource.markAsFinished(elapsedTime);
 
+        console.assert(resource.cached, "This resource should be classified as cached since it was served from the MemoryCache", resource);
+
         if (cachedResourcePayload.sourceMapURL)
             WebInspector.sourceMapManager.downloadSourceMap(cachedResourcePayload.sourceMapURL, resource.url, resource);
 
@@ -372,10 +375,11 @@ WebInspector.FrameResourceManager = class FrameResourceManager extends WebInspec
             this._resourceRequestIdentifierMap.set(requestIdentifier, resource);
         }
 
+        // COMPATIBILITY (iOS 10.3): `fromDiskCache` is legacy, replaced by `source`.
         if (response.fromDiskCache)
-            resource.markAsCached();
+            resource.legacyMarkServedFromDiskCache();
 
-        resource.updateForResponse(response.url, response.mimeType, type, response.headers, response.status, response.statusText, elapsedTime, response.timing);
+        resource.updateForResponse(response.url, response.mimeType, type, response.headers, response.status, response.statusText, elapsedTime, response.timing, response.source);
     }
 
     resourceRequestDidReceiveData(requestIdentifier, dataLength, encodedDataLength, timestamp)
index 29e5a7d..f4c7439 100644 (file)
@@ -56,9 +56,12 @@ WebInspector.Resource = class Resource extends WebInspector.SourceCode
         this._lastDataReceivedTimestamp = NaN;
         this._finishedOrFailedTimestamp = NaN;
         this._finishThenRequestContentPromise = null;
+        this._statusCode = NaN;
+        this._statusText = null;
         this._size = NaN;
         this._transferSize = NaN;
         this._cached = false;
+        this._responseSource = WebInspector.Resource.ResponseSource.Unknown;
         this._timingData = new WebInspector.ResourceTimingData(this);
         this._target = targetId ? WebInspector.targetManager.targetForIdentifier(targetId) : WebInspector.mainTarget;
 
@@ -130,10 +133,37 @@ WebInspector.Resource = class Resource extends WebInspector.SourceCode
         }
     }
 
+    static responseSourceFromPayload(source)
+    {
+        if (!source)
+            return WebInspector.Resource.ResponseSource.Unknown;
+
+        switch (source) {
+        case NetworkAgent.ResponseSource.Unknown:
+            return WebInspector.Resource.ResponseSource.Unknown;
+        case NetworkAgent.ResponseSource.Network:
+            return WebInspector.Resource.ResponseSource.Network;
+        case NetworkAgent.ResponseSource.MemoryCache:
+            return WebInspector.Resource.ResponseSource.MemoryCache;
+        case NetworkAgent.ResponseSource.DiskCache:
+            return WebInspector.Resource.ResponseSource.DiskCache;
+        default:
+            console.error("Unknown response source type: ", source);
+            return WebInspector.Resource.ResponseSource.Unknown;
+        }
+    }
+
     // Public
 
     get target() { return this._target; }
     get type() { return this._type; }
+    get loaderIdentifier() { return this._loaderIdentifier; }
+    get requestIdentifier() { return this._requestIdentifier; }
+    get requestMethod() { return this._requestMethod; }
+    get requestData() { return this._requestData; }
+    get statusCode() { return this._statusCode; }
+    get statusText() { return this._statusText; }
+    get responseSource() { return this._responseSource; }
     get timingData() { return this._timingData; }
 
     get url()
@@ -245,16 +275,6 @@ WebInspector.Resource = class Resource extends WebInspector.SourceCode
         return this._parentFrame;
     }
 
-    get loaderIdentifier()
-    {
-        return this._loaderIdentifier;
-    }
-
-    get requestIdentifier()
-    {
-        return this._requestIdentifier;
-    }
-
     get finished()
     {
         return this._finished;
@@ -270,16 +290,6 @@ WebInspector.Resource = class Resource extends WebInspector.SourceCode
         return this._canceled;
     }
 
-    get requestMethod()
-    {
-        return this._requestMethod;
-    }
-
-    get requestData()
-    {
-        return this._requestData;
-    }
-
     get requestDataContentType()
     {
         return this._requestHeaders.valueForCaseInsensitiveKey("Content-Type") || null;
@@ -350,16 +360,6 @@ WebInspector.Resource = class Resource extends WebInspector.SourceCode
         return this._cached;
     }
 
-    get statusCode()
-    {
-        return this._statusCode;
-    }
-
-    get statusText()
-    {
-        return this._statusText;
-    }
-
     get size()
     {
         return this._size;
@@ -452,15 +452,20 @@ WebInspector.Resource = class Resource extends WebInspector.SourceCode
         this.dispatchEventToListeners(WebInspector.Resource.Event.TimestampsDidChange);
     }
 
-    updateForResponse(url, mimeType, type, responseHeaders, statusCode, statusText, elapsedTime, timingData)
+    hasResponse()
+    {
+        return !isNaN(this._statusCode);
+    }
+
+    updateForResponse(url, mimeType, type, responseHeaders, statusCode, statusText, elapsedTime, timingData, source)
     {
         console.assert(!this._finished);
         console.assert(!this._failed);
         console.assert(!this._canceled);
 
-        var oldURL = this._url;
-        var oldMIMEType = this._mimeType;
-        var oldType = this._type;
+        let oldURL = this._url;
+        let oldMIMEType = this._mimeType;
+        let oldType = this._type;
 
         if (type in WebInspector.Resource.Type)
             type = WebInspector.Resource.Type[type];
@@ -474,12 +479,17 @@ WebInspector.Resource = class Resource extends WebInspector.SourceCode
         this._responseReceivedTimestamp = elapsedTime || NaN;
         this._timingData = WebInspector.ResourceTimingData.fromPayload(timingData, this);
 
+        if (source)
+            this._responseSource = WebInspector.Resource.responseSourceFromPayload(source);
+
         this._responseHeadersSize = String(this._statusCode).length + this._statusText.length + 12; // Extra length is for "HTTP/1.1 ", " ", and "\r\n".
-        for (var name in this._responseHeaders)
+        for (let name in this._responseHeaders)
             this._responseHeadersSize += name.length + this._responseHeaders[name].length + 4; // Extra length is for ": ", and "\r\n".
 
-        if (statusCode === 304 && !this._cached)
-            this.markAsCached();
+        if (!this._cached) {
+            if (statusCode === 304 || (this._responseSource === WebInspector.Resource.ResponseSource.MemoryCache || this._responseSource === WebInspector.Resource.ResponseSource.DiskCache))
+                this.markAsCached();
+        }
 
         if (oldURL !== url) {
             // Delete the URL components so the URL is re-parsed the next time it is requested.
@@ -566,7 +576,7 @@ WebInspector.Resource = class Resource extends WebInspector.SourceCode
 
         this.dispatchEventToListeners(WebInspector.Resource.Event.CacheStatusDidChange);
 
-        // The transferSize is starts returning 0 when cached is true, unless status is 304.
+        // The transferSize starts returning 0 when cached is true, unless status is 304.
         if (this._statusCode !== 304)
             this.dispatchEventToListeners(WebInspector.Resource.Event.TransferSizeDidChange);
     }
@@ -609,6 +619,26 @@ WebInspector.Resource = class Resource extends WebInspector.SourceCode
         this._finishedOrFailedTimestamp = NaN;
     }
 
+    legacyMarkServedFromMemoryCache()
+    {
+        // COMPATIBILITY (iOS 10.3): This is a legacy code path where we know the resource came from the MemoryCache.
+        console.assert(this._responseSource === WebInspector.Resource.ResponseSource.Unknown);
+
+        this._responseSource = WebInspector.Resource.ResponseSource.MemoryCache;
+
+        this.markAsCached();
+    }
+
+    legacyMarkServedFromDiskCache()
+    {
+        // COMPATIBILITY (iOS 10.3): This is a legacy code path where we know the resource came from the DiskCache.
+        console.assert(this._responseSource === WebInspector.Resource.ResponseSource.Unknown);
+
+        this._responseSource = WebInspector.Resource.ResponseSource.DiskCache;
+
+        this.markAsCached();
+    }
+
     getImageSize(callback)
     {
         // Throw an error in the case this resource is not an image.
@@ -762,6 +792,13 @@ WebInspector.Resource.Type = {
     Other: "resource-type-other"
 };
 
+WebInspector.Resource.ResponseSource = {
+    Unknown: Symbol("unknown"),
+    Network: Symbol("network"),
+    MemoryCache: Symbol("memory-cache"),
+    DiskCache: Symbol("disk-cache"),
+};
+
 // This MIME Type map is private, use WebInspector.Resource.typeFromMIMEType().
 WebInspector.Resource._mimeTypeMap = {
     "text/html": WebInspector.Resource.Type.Document,
index f2e4c0d..3c1b1a2 100644 (file)
@@ -34,6 +34,7 @@ WebInspector.NetworkObserver = class NetworkObserver
 
     requestServedFromCache(requestId)
     {
+        // COMPATIBILITY (iOS 10.3): The backend no longer sends this.
         WebInspector.frameResourceManager.markResourceRequestAsServedFromMemoryCache(requestId);
     }
 
index c056c65..5c654e8 100644 (file)
 .content-view.network-grid > .data-grid .preserved:not(.selected) .cell-content .timeline-record-bar > .segment {
     filter: grayscale();
 }
+
+.content-view.network-grid > .data-grid .cache-type {
+    color: gray;
+}
+
+.content-view.network-grid > .data-grid:matches(:focus, .force-focus) tr.selected .cache-type {
+    color: var(--selected-foreground-color) !important;
+}
index e55a943..690969e 100644 (file)
@@ -45,22 +45,22 @@ WebInspector.NetworkGridContentView = class NetworkGridContentView extends WebIn
         columns.domain.width = "10%";
 
         columns.type.title = WebInspector.UIString("Type");
-        columns.type.width = "8%";
+        columns.type.width = "6%";
 
         columns.method.title = WebInspector.UIString("Method");
-        columns.method.width = "6%";
+        columns.method.width = "5%";
 
         columns.scheme.title = WebInspector.UIString("Scheme");
-        columns.scheme.width = "6%";
+        columns.scheme.width = "5%";
 
         columns.statusCode.title = WebInspector.UIString("Status");
-        columns.statusCode.width = "6%";
+        columns.statusCode.width = "5%";
 
         columns.cached.title = WebInspector.UIString("Cached");
-        columns.cached.width = "6%";
+        columns.cached.width = "8%";
 
         columns.size.title = WebInspector.UIString("Size");
-        columns.size.width = "8%";
+        columns.size.width = "6%";
         columns.size.aligned = "right";
 
         columns.transferSize.title = WebInspector.UIString("Transferred");
@@ -86,7 +86,7 @@ WebInspector.NetworkGridContentView = class NetworkGridContentView extends WebIn
         this._timelineRuler.allowsClippedLabels = true;
 
         columns.graph.title = WebInspector.UIString("Timeline");
-        columns.graph.width = "15%";
+        columns.graph.width = "20%";
         columns.graph.headerView = this._timelineRuler;
         columns.graph.sortable = false;
 
index 2414d95..3a284d2 100644 (file)
@@ -63,10 +63,10 @@ WebInspector.NetworkTimelineView = class NetworkTimelineView extends WebInspecto
         columns.statusCode.width = "4%";
 
         columns.cached.title = WebInspector.UIString("Cached");
-        columns.cached.width = "4%";
+        columns.cached.width = "6%";
 
         columns.size.title = WebInspector.UIString("Size");
-        columns.size.width = "8%";
+        columns.size.width = "6%";
         columns.size.aligned = "right";
 
         columns.transferSize.title = WebInspector.UIString("Transferred");
index e4db013..81286b2 100644 (file)
@@ -90,12 +90,12 @@ WebInspector.ResourceTimelineDataGridNode = class ResourceTimelineDataGridNode e
 
     createCellContent(columnIdentifier, cell)
     {
-        var resource = this._resource;
+        let resource = this._resource;
 
         if (resource.failed || resource.canceled || resource.statusCode >= 400)
             cell.classList.add("error");
 
-        var value = this.data[columnIdentifier];
+        let value = this.data[columnIdentifier];
 
         switch (columnIdentifier) {
         case "name":
@@ -112,7 +112,7 @@ WebInspector.ResourceTimelineDataGridNode = class ResourceTimelineDataGridNode e
             return value || emDash;
 
         case "cached":
-            return value ? WebInspector.UIString("Yes") : WebInspector.UIString("No");
+            return this._cachedCellContent();
 
         case "domain":
             return value || emDash;
@@ -219,6 +219,25 @@ WebInspector.ResourceTimelineDataGridNode = class ResourceTimelineDataGridNode e
         return fragment;
     }
 
+    _cachedCellContent()
+    {
+        if (!this._resource.hasResponse())
+            return emDash;
+
+        let responseSource = this._resource.responseSource;
+        if (responseSource === WebInspector.Resource.ResponseSource.MemoryCache || responseSource === WebInspector.Resource.ResponseSource.DiskCache) {
+            console.assert(this._resource.cached, "This resource has a cache responseSource it should also be marked as cached", resource);
+            let span = document.createElement("span");
+            let cacheType = document.createElement("span");
+            cacheType.classList = "cache-type";
+            cacheType.textContent = responseSource === WebInspector.Resource.ResponseSource.MemoryCache ? WebInspector.UIString("(Memory)") : WebInspector.UIString("(Disk)");
+            span.append(WebInspector.UIString("Yes"), " ", cacheType);
+            return span;
+        }
+
+        return this._resource.cached ? WebInspector.UIString("Yes") : WebInspector.UIString("No");
+    }
+
     _needsRefresh()
     {
         if (this.dataGrid instanceof WebInspector.TimelineDataGrid) {