<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[225546] trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/225546">225546</a></dd>
<dt>Author</dt> <dd>commit-queue@webkit.org</dd>
<dt>Date</dt> <dd>2017-12-05 14:09:36 -0800 (Tue, 05 Dec 2017)</dd>
</dl>

<h3>Log Message</h3>
<pre>Web Inspector: content views for resources loaded through XHR do not reflect declared mime-type
https://bugs.webkit.org/show_bug.cgi?id=141389
<rdar://problem/19767070>

Patch by Joseph Pecoraro <pecoraro@apple.com> on 2017-12-05
Reviewed by Brian Burg.

Source/WebCore:

Updated: http/tests/inspector/network/xhr-response-body.html:
         http/tests/inspector/network/fetch-response-body.html:

* xml/XMLHttpRequest.cpp:
(WebCore::XMLHttpRequest::didFinishLoading):
* inspector/InspectorInstrumentation.cpp:
(WebCore::InspectorInstrumentation::didFinishXHRLoadingImpl): Deleted.
* inspector/InspectorInstrumentation.h:
(WebCore::InspectorInstrumentation::didFinishXHRLoading): Deleted.
Remove special handling of XHR content that decoded output as text.

* inspector/NetworkResourcesData.h:
(WebCore::NetworkResourcesData::ResourceData::requestId const):
(WebCore::NetworkResourcesData::ResourceData::loaderId const):
(WebCore::NetworkResourcesData::ResourceData::frameId const):
(WebCore::NetworkResourcesData::ResourceData::url const):
(WebCore::NetworkResourcesData::ResourceData::content const):
(WebCore::NetworkResourcesData::ResourceData::isContentEvicted const):
(WebCore::NetworkResourcesData::ResourceData::textEncodingName const):
* inspector/NetworkResourcesData.cpp:
(WebCore::NetworkResourcesData::ResourceData::ResourceData):
(WebCore::NetworkResourcesData::ResourceData::decodeDataToContent):
(WebCore::NetworkResourcesData::responseReceived):
(WebCore::NetworkResourcesData::setResourceContent):
(WebCore::shouldBufferResourceData):
(WebCore::NetworkResourcesData::maybeAddResourceData):
(WebCore::NetworkResourcesData::maybeDecodeDataToContent):

Make NetworkResourcesData only create a text decoder for resources we
really think are text, and buffer resource data if it is text data
or if it is a resource that would otherwise not be buffered by WebCore
(such as XHRs with a DoNotBufferData policy). This ensures that the
Inspector will have data to show for resources that won't be cached.

* inspector/agents/InspectorPageAgent.cpp:
(WebCore::InspectorPageAgent::resourceContent):
(WebCore::InspectorPageAgent::sourceMapURLForResource):
(WebCore::InspectorPageAgent::searchInResource):
(WebCore::InspectorPageAgent::searchInResources):
(WebCore::hasTextContent): Deleted.
(WebCore::InspectorPageAgent::cachedResourceContent): Deleted.
(WebCore::InspectorPageAgent::createTextDecoder): Deleted.
(WebCore::textContentForCachedResource): Deleted.
* inspector/agents/InspectorPageAgent.h:
* inspector/agents/InspectorNetworkAgent.cpp:
(WebCore::InspectorNetworkAgent::didReceiveData):
(WebCore::InspectorNetworkAgent::willDestroyCachedResource):
(WebCore::InspectorNetworkAgent::getResponseBody):
(WebCore::InspectorNetworkAgent::shouldTreatAsText):
(WebCore::InspectorNetworkAgent::createTextDecoder):
(WebCore::InspectorNetworkAgent::textContentForCachedResource):
(WebCore::InspectorNetworkAgent::cachedResourceContent):
(WebCore::textContentForResourceData):
(WebCore::InspectorNetworkAgent::searchOtherRequests):
(WebCore::isErrorStatusCode): Deleted.
(WebCore::InspectorNetworkAgent::didFinishXHRLoading): Deleted.
* inspector/agents/InspectorNetworkAgent.h:
Move static PageAgent functions related to the generic data tuple
(content, base64Encoded) to NetworkAgent. Also generalize it to
not rely on the CachedResourceType, but instead rely on the MIME type.
This has a few changes in behavior:

    - Images, may now be text if they have a text mime type (image/svg+xml).
    - XHR / Fetch / Other may be sent as text if they have a text mime type.
    - XHR / Fetch / Other are not assumed to be text, and may be sent as base64 encoded.

For this to be useful the frontend should also check the mime type and
display an appropriate ContentView.

Source/WebInspectorUI:

* UserInterface/Base/Utilities.js:
Blob <-> Text conversion helpers.

* UserInterface/Models/Resource.js:
(WI.Resource.prototype.createObjectURL):
Previously all Image resources were assumed to have base64Encoded data
which we automatically convert to a Blob. Now that some image data
can be transfered as text, convert that to a Blob here since the output
is expected to be a Blob.

* UserInterface/Views/ResourceContentView.js:
(WI.ResourceContentView.prototype.showGenericNoContentMessage):
* UserInterface/Views/TextResourceContentView.js:
(WI.TextResourceContentView.prototype.contentAvailable):
(WI.TextResourceContentView.prototype._contentDidPopulate):
* UserInterface/Views/ImageResourceContentView.js:
(WI.ImageResourceContentView.prototype.contentAvailable):
Better handle no content cases.

* UserInterface/Views/ResourceClusterContentView.js:
(WI.ResourceClusterContentView.prototype.get responseContentView):
(WI.ResourceClusterContentView.prototype._contentViewForResourceType):
Make a best effort to find a good ContentView to show the resource data.
This is done by looking at the ResourceType and MIME Type.

* UserInterface/Views/SVGImageResourceClusterContentView.js:
(WI.SVGImageResourceClusterContentView.prototype._showContentViewForIdentifier):
Handle if image data is now text (the image/svg+xml case).

LayoutTests:

* http/tests/inspector/network/fetch-response-body-expected.txt:
* http/tests/inspector/network/fetch-response-body.html:
* http/tests/inspector/network/xhr-response-body-expected.txt:
* http/tests/inspector/network/xhr-response-body.html:
Update tests for new expectations now that binary data shows as binary.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkLayoutTestshttptestsinspectornetworkfetchresponsebodyexpectedtxt">trunk/LayoutTests/http/tests/inspector/network/fetch-response-body-expected.txt</a></li>
<li><a href="#trunkLayoutTestshttptestsinspectornetworkfetchresponsebodyhtml">trunk/LayoutTests/http/tests/inspector/network/fetch-response-body.html</a></li>
<li><a href="#trunkLayoutTestshttptestsinspectornetworkxhrresponsebodyexpectedtxt">trunk/LayoutTests/http/tests/inspector/network/xhr-response-body-expected.txt</a></li>
<li><a href="#trunkLayoutTestshttptestsinspectornetworkxhrresponsebodyhtml">trunk/LayoutTests/http/tests/inspector/network/xhr-response-body.html</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreinspectorInspectorInstrumentationcpp">trunk/Source/WebCore/inspector/InspectorInstrumentation.cpp</a></li>
<li><a href="#trunkSourceWebCoreinspectorInspectorInstrumentationh">trunk/Source/WebCore/inspector/InspectorInstrumentation.h</a></li>
<li><a href="#trunkSourceWebCoreinspectorNetworkResourcesDatacpp">trunk/Source/WebCore/inspector/NetworkResourcesData.cpp</a></li>
<li><a href="#trunkSourceWebCoreinspectorNetworkResourcesDatah">trunk/Source/WebCore/inspector/NetworkResourcesData.h</a></li>
<li><a href="#trunkSourceWebCoreinspectoragentsInspectorNetworkAgentcpp">trunk/Source/WebCore/inspector/agents/InspectorNetworkAgent.cpp</a></li>
<li><a href="#trunkSourceWebCoreinspectoragentsInspectorNetworkAgenth">trunk/Source/WebCore/inspector/agents/InspectorNetworkAgent.h</a></li>
<li><a href="#trunkSourceWebCoreinspectoragentsInspectorPageAgentcpp">trunk/Source/WebCore/inspector/agents/InspectorPageAgent.cpp</a></li>
<li><a href="#trunkSourceWebCoreinspectoragentsInspectorPageAgenth">trunk/Source/WebCore/inspector/agents/InspectorPageAgent.h</a></li>
<li><a href="#trunkSourceWebCorexmlXMLHttpRequestcpp">trunk/Source/WebCore/xml/XMLHttpRequest.cpp</a></li>
<li><a href="#trunkSourceWebInspectorUIChangeLog">trunk/Source/WebInspectorUI/ChangeLog</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceBaseUtilitiesjs">trunk/Source/WebInspectorUI/UserInterface/Base/Utilities.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceModelsResourcejs">trunk/Source/WebInspectorUI/UserInterface/Models/Resource.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsImageResourceContentViewjs">trunk/Source/WebInspectorUI/UserInterface/Views/ImageResourceContentView.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsResourceClusterContentViewjs">trunk/Source/WebInspectorUI/UserInterface/Views/ResourceClusterContentView.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsResourceContentViewjs">trunk/Source/WebInspectorUI/UserInterface/Views/ResourceContentView.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsSVGImageResourceClusterContentViewjs">trunk/Source/WebInspectorUI/UserInterface/Views/SVGImageResourceClusterContentView.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsTextResourceContentViewjs">trunk/Source/WebInspectorUI/UserInterface/Views/TextResourceContentView.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (225545 => 225546)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog      2017-12-05 22:09:04 UTC (rev 225545)
+++ trunk/LayoutTests/ChangeLog 2017-12-05 22:09:36 UTC (rev 225546)
</span><span class="lines">@@ -1,3 +1,17 @@
</span><ins>+2017-12-05  Joseph Pecoraro  <pecoraro@apple.com>
+
+        Web Inspector: content views for resources loaded through XHR do not reflect declared mime-type
+        https://bugs.webkit.org/show_bug.cgi?id=141389
+        <rdar://problem/19767070>
+
+        Reviewed by Brian Burg.
+
+        * http/tests/inspector/network/fetch-response-body-expected.txt:
+        * http/tests/inspector/network/fetch-response-body.html:
+        * http/tests/inspector/network/xhr-response-body-expected.txt:
+        * http/tests/inspector/network/xhr-response-body.html:
+        Update tests for new expectations now that binary data shows as binary.        
+
</ins><span class="cx"> 2017-12-05  Youenn Fablet  <youenn@apple.com>
</span><span class="cx"> 
</span><span class="cx">         Implement https://w3c.github.io/ServiceWorker/#clients-claim
</span></span></pre></div>
<a id="trunkLayoutTestshttptestsinspectornetworkfetchresponsebodyexpectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/http/tests/inspector/network/fetch-response-body-expected.txt (225545 => 225546)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/http/tests/inspector/network/fetch-response-body-expected.txt  2017-12-05 22:09:04 UTC (rev 225545)
+++ trunk/LayoutTests/http/tests/inspector/network/fetch-response-body-expected.txt     2017-12-05 22:09:36 UTC (rev 225546)
</span><span class="lines">@@ -5,35 +5,42 @@
</span><span class="cx"> -- Running test case: Network.getResponseBody.Fetch.Text
</span><span class="cx"> PASS: Resource should be Fetch type.
</span><span class="cx"> PASS: MIMEType should be 'text/plain'.
</span><ins>+PASS: Content should not be base64Encoded.
</ins><span class="cx"> PASS: Text content should match data.txt.
</span><span class="cx"> 
</span><span class="cx"> -- Running test case: Network.getResponseBody.Fetch.HTML
</span><span class="cx"> PASS: Resource should be Fetch type.
</span><span class="cx"> PASS: MIMEType should be 'text/html'.
</span><ins>+PASS: Content should not be base64Encoded.
</ins><span class="cx"> PASS: Text content should match data.html.
</span><span class="cx"> 
</span><span class="cx"> -- Running test case: Network.getResponseBody.Fetch.JSON
</span><span class="cx"> PASS: Resource should be Fetch type.
</span><span class="cx"> PASS: MIMEType should be 'application/octet-stream'.
</span><ins>+PASS: Content should be base64Encoded.
</ins><span class="cx"> PASS: JSON content should match data.json.
</span><span class="cx"> 
</span><span class="cx"> -- Running test case: Network.getResponseBody.Fetch.JSON2
</span><span class="cx"> PASS: Resource should be Fetch type.
</span><span class="cx"> PASS: MIMEType should be 'application/json'.
</span><ins>+PASS: Content should not be base64Encoded.
</ins><span class="cx"> PASS: JSON content should match specified content.
</span><span class="cx"> 
</span><span class="cx"> -- Running test case: Network.getResponseBody.Fetch.JSON3
</span><span class="cx"> PASS: Resource should be Fetch type.
</span><span class="cx"> PASS: MIMEType should be 'application/vnd.api+json'.
</span><ins>+PASS: Content should not be base64Encoded.
</ins><span class="cx"> PASS: JSON content should match specified content.
</span><span class="cx"> 
</span><span class="cx"> -- Running test case: Network.getResponseBody.Fetch.SVG
</span><span class="cx"> PASS: Resource should be Fetch type.
</span><span class="cx"> PASS: MIMEType should be 'image/svg+xml'.
</span><ins>+PASS: Content should not be base64Encoded.
</ins><span class="cx"> PASS: SVG content should be text.
</span><span class="cx"> 
</span><span class="cx"> -- Running test case: Network.getResponseBody.Fetch.PNG
</span><span class="cx"> PASS: Resource should be Fetch type.
</span><span class="cx"> PASS: MIMEType should be 'image/png'.
</span><del>-PASS: Image content should be text.
</del><ins>+PASS: Content should be base64Encoded.
+PASS: Image content should be a Blob.
</ins><span class="cx"> 
</span></span></pre></div>
<a id="trunkLayoutTestshttptestsinspectornetworkfetchresponsebodyhtml"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/http/tests/inspector/network/fetch-response-body.html (225545 => 225546)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/http/tests/inspector/network/fetch-response-body.html  2017-12-05 22:09:04 UTC (rev 225545)
+++ trunk/LayoutTests/http/tests/inspector/network/fetch-response-body.html     2017-12-05 22:09:36 UTC (rev 225546)
</span><span class="lines">@@ -36,6 +36,18 @@
</span><span class="cx"> {
</span><span class="cx">     let suite = InspectorTest.createAsyncSuite("Network.getResponseBody.Fetch");
</span><span class="cx"> 
</span><ins>+    function contentAsText(content) {
+        return new Promise((resolve) => {
+            if (typeof content === "string") {
+                resolve(content)
+                return;
+            }
+            blobAsText(content, (text) => {
+                resolve(text);
+            });
+        });
+    }
+
</ins><span class="cx">     function addTestCase({name, description, expression, contentHandler}) {
</span><span class="cx">         suite.addTestCase({
</span><span class="cx">             name, description,
</span><span class="lines">@@ -57,8 +69,9 @@
</span><span class="cx">         name: "Network.getResponseBody.Fetch.Text",
</span><span class="cx">         description: "Get text/plain content as text.",
</span><span class="cx">         expression: "createFetchForText()",
</span><del>-        contentHandler({error, sourceCode, content}) {
</del><ins>+        contentHandler({error, sourceCode, content, rawBase64Encoded}) {
</ins><span class="cx">             InspectorTest.expectEqual(sourceCode.mimeType, "text/plain", "MIMEType should be 'text/plain'.");
</span><ins>+            InspectorTest.expectEqual(rawBase64Encoded, false, "Content should not be base64Encoded.");
</ins><span class="cx">             InspectorTest.expectEqual(content, "Plain text resource.\n", "Text content should match data.txt.");
</span><span class="cx">         }
</span><span class="cx">     });
</span><span class="lines">@@ -67,8 +80,9 @@
</span><span class="cx">         name: "Network.getResponseBody.Fetch.HTML",
</span><span class="cx">         description: "Get text/html content as text.",
</span><span class="cx">         expression: "createFetchForHTML()",
</span><del>-        contentHandler({error, sourceCode, content}) {
</del><ins>+        contentHandler({error, sourceCode, content, rawBase64Encoded}) {
</ins><span class="cx">             InspectorTest.expectEqual(sourceCode.mimeType, "text/html", "MIMEType should be 'text/html'.");
</span><ins>+            InspectorTest.expectEqual(rawBase64Encoded, false, "Content should not be base64Encoded.");
</ins><span class="cx">             InspectorTest.expectEqual(content, "<span>Hello World</span>\n", "Text content should match data.html.");
</span><span class="cx">         }
</span><span class="cx">     });
</span><span class="lines">@@ -75,11 +89,14 @@
</span><span class="cx"> 
</span><span class="cx">     addTestCase({
</span><span class="cx">         name: "Network.getResponseBody.Fetch.JSON",
</span><del>-        description: "Get application/octet-stream content as text.",
</del><ins>+        description: "Get application/octet-stream content as base64Encoded text.",
</ins><span class="cx">         expression: "createFetchForJSON()",
</span><del>-        contentHandler({error, sourceCode, content}) {
</del><ins>+        contentHandler({error, sourceCode, content, rawBase64Encoded}) {
</ins><span class="cx">             InspectorTest.expectEqual(sourceCode.mimeType, "application/octet-stream", "MIMEType should be 'application/octet-stream'.");
</span><del>-            InspectorTest.expectEqual(content, `{"json": true, "value": 42}\n`, "JSON content should match data.json.");
</del><ins>+            InspectorTest.expectEqual(rawBase64Encoded, true, "Content should be base64Encoded.");
+            return contentAsText(content).then((text) => {
+                InspectorTest.expectEqual(text, `{"json": true, "value": 42}\n`, "JSON content should match data.json.");
+            });
</ins><span class="cx">         }
</span><span class="cx">     });
</span><span class="cx"> 
</span><span class="lines">@@ -87,8 +104,9 @@
</span><span class="cx">         name: "Network.getResponseBody.Fetch.JSON2",
</span><span class="cx">         description: "Get application/json content as text.",
</span><span class="cx">         expression: "createFetchForJSON2()",
</span><del>-        contentHandler({error, sourceCode, content}) {
</del><ins>+        contentHandler({error, sourceCode, content, rawBase64Encoded}) {
</ins><span class="cx">             InspectorTest.expectEqual(sourceCode.mimeType, "application/json", "MIMEType should be 'application/json'.");
</span><ins>+            InspectorTest.expectEqual(rawBase64Encoded, false, "Content should not be base64Encoded.");
</ins><span class="cx">             InspectorTest.expectEqual(content, `{"json":true,"value":42}`, "JSON content should match specified content.");
</span><span class="cx">         }
</span><span class="cx">     });
</span><span class="lines">@@ -97,8 +115,9 @@
</span><span class="cx">         name: "Network.getResponseBody.Fetch.JSON3",
</span><span class="cx">         description: "Get arbitrary +json content as text.",
</span><span class="cx">         expression: "createFetchForJSON3()",
</span><del>-        contentHandler({error, sourceCode, content}) {
</del><ins>+        contentHandler({error, sourceCode, content, rawBase64Encoded}) {
</ins><span class="cx">             InspectorTest.expectEqual(sourceCode.mimeType, "application/vnd.api+json", "MIMEType should be 'application/vnd.api+json'.");
</span><ins>+            InspectorTest.expectEqual(rawBase64Encoded, false, "Content should not be base64Encoded.");
</ins><span class="cx">             InspectorTest.expectEqual(content, `{"json":true,"value":999}`, "JSON content should match specified content.");
</span><span class="cx">         }
</span><span class="cx">     });
</span><span class="lines">@@ -107,8 +126,9 @@
</span><span class="cx">         name: "Network.getResponseBody.Fetch.SVG",
</span><span class="cx">         description: "Get image/svg+xml content as text.",
</span><span class="cx">         expression: "createFetchForSVG()",
</span><del>-        contentHandler({error, sourceCode, content}) {
</del><ins>+        contentHandler({error, sourceCode, content, rawBase64Encoded}) {
</ins><span class="cx">             InspectorTest.expectEqual(sourceCode.mimeType, "image/svg+xml", "MIMEType should be 'image/svg+xml'.");
</span><ins>+            InspectorTest.expectEqual(rawBase64Encoded, false, "Content should not be base64Encoded.");
</ins><span class="cx">             InspectorTest.expectEqual(content,
</span><span class="cx"> `<?xml version="1.0" encoding="UTF-8"?>
</span><span class="cx"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 200">
</span><span class="lines">@@ -122,10 +142,10 @@
</span><span class="cx">         name: "Network.getResponseBody.Fetch.PNG",
</span><span class="cx">         description: "Get image/png content.",
</span><span class="cx">         expression: "createFetchForPNG()",
</span><del>-        contentHandler({error, sourceCode, content}) {
-            // FIXME: <https://webkit.org/b/165495> Web Inspector: XHR / Fetch for non-text content should not show garbled text
</del><ins>+        contentHandler({error, sourceCode, content, rawBase64Encoded}) {
</ins><span class="cx">             InspectorTest.expectEqual(sourceCode.mimeType, "image/png", "MIMEType should be 'image/png'.");
</span><del>-            InspectorTest.expectEqual(typeof content, "string", "Image content should be text.");
</del><ins>+            InspectorTest.expectEqual(rawBase64Encoded, true, "Content should be base64Encoded.");
+            InspectorTest.expectThat(content instanceof Blob, "Image content should be a Blob.");
</ins><span class="cx">         }
</span><span class="cx">     });
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkLayoutTestshttptestsinspectornetworkxhrresponsebodyexpectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/http/tests/inspector/network/xhr-response-body-expected.txt (225545 => 225546)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/http/tests/inspector/network/xhr-response-body-expected.txt    2017-12-05 22:09:04 UTC (rev 225545)
+++ trunk/LayoutTests/http/tests/inspector/network/xhr-response-body-expected.txt       2017-12-05 22:09:36 UTC (rev 225546)
</span><span class="lines">@@ -5,35 +5,42 @@
</span><span class="cx"> -- Running test case: Network.getResponseBody.XHR.Text
</span><span class="cx"> PASS: Resource should be XHR type.
</span><span class="cx"> PASS: MIMEType should be 'text/plain'.
</span><ins>+PASS: Content should not be base64Encoded.
</ins><span class="cx"> PASS: Text content should match data.txt.
</span><span class="cx"> 
</span><span class="cx"> -- Running test case: Network.getResponseBody.XHR.HTML
</span><span class="cx"> PASS: Resource should be XHR type.
</span><span class="cx"> PASS: MIMEType should be 'text/html'.
</span><ins>+PASS: Content should not be base64Encoded.
</ins><span class="cx"> PASS: Text content should match data.html.
</span><span class="cx"> 
</span><span class="cx"> -- Running test case: Network.getResponseBody.XHR.JSON
</span><span class="cx"> PASS: Resource should be XHR type.
</span><span class="cx"> PASS: MIMEType should be 'application/octet-stream'.
</span><ins>+PASS: Content should be base64Encoded.
</ins><span class="cx"> PASS: JSON content should match data.json.
</span><span class="cx"> 
</span><span class="cx"> -- Running test case: Network.getResponseBody.XHR.JSON2
</span><span class="cx"> PASS: Resource should be XHR type.
</span><span class="cx"> PASS: MIMEType should be 'application/json'.
</span><ins>+PASS: Content should not be base64Encoded.
</ins><span class="cx"> PASS: JSON content should match specified content.
</span><span class="cx"> 
</span><span class="cx"> -- Running test case: Network.getResponseBody.XHR.JSON3
</span><span class="cx"> PASS: Resource should be XHR type.
</span><span class="cx"> PASS: MIMEType should be 'application/vnd.api+json'.
</span><ins>+PASS: Content should not be base64Encoded.
</ins><span class="cx"> PASS: JSON content should match specified content.
</span><span class="cx"> 
</span><span class="cx"> -- Running test case: Network.getResponseBody.XHR.SVG
</span><span class="cx"> PASS: Resource should be XHR type.
</span><span class="cx"> PASS: MIMEType should be 'image/svg+xml'.
</span><ins>+PASS: Content should not be base64Encoded.
</ins><span class="cx"> PASS: SVG content should be text.
</span><span class="cx"> 
</span><span class="cx"> -- Running test case: Network.getResponseBody.XHR.PNG
</span><span class="cx"> PASS: Resource should be XHR type.
</span><span class="cx"> PASS: MIMEType should be 'image/png'.
</span><del>-PASS: Image content should be text.
</del><ins>+PASS: Content should be base64Encoded.
+PASS: Image content should be a Blob.
</ins><span class="cx"> 
</span></span></pre></div>
<a id="trunkLayoutTestshttptestsinspectornetworkxhrresponsebodyhtml"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/http/tests/inspector/network/xhr-response-body.html (225545 => 225546)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/http/tests/inspector/network/xhr-response-body.html    2017-12-05 22:09:04 UTC (rev 225545)
+++ trunk/LayoutTests/http/tests/inspector/network/xhr-response-body.html       2017-12-05 22:09:36 UTC (rev 225546)
</span><span class="lines">@@ -42,6 +42,18 @@
</span><span class="cx"> {
</span><span class="cx">     let suite = InspectorTest.createAsyncSuite("Network.getResponseBody.XHR");
</span><span class="cx"> 
</span><ins>+    function contentAsText(content) {
+        return new Promise((resolve) => {
+            if (typeof content === "string") {
+                resolve(content)
+                return;
+            }
+            blobAsText(content, (text) => {
+                resolve(text);
+            });
+        });
+    }
+
</ins><span class="cx">     function addTestCase({name, description, expression, contentHandler}) {
</span><span class="cx">         suite.addTestCase({
</span><span class="cx">             name, description,
</span><span class="lines">@@ -63,8 +75,9 @@
</span><span class="cx">         name: "Network.getResponseBody.XHR.Text",
</span><span class="cx">         description: "Get text/plain content as text.",
</span><span class="cx">         expression: "createXHRForText()",
</span><del>-        contentHandler({error, sourceCode, content}) {
</del><ins>+        contentHandler({error, sourceCode, content, rawBase64Encoded}) {
</ins><span class="cx">             InspectorTest.expectEqual(sourceCode.mimeType, "text/plain", "MIMEType should be 'text/plain'.");
</span><ins>+            InspectorTest.expectEqual(rawBase64Encoded, false, "Content should not be base64Encoded.");
</ins><span class="cx">             InspectorTest.expectEqual(content, "Plain text resource.\n", "Text content should match data.txt.");
</span><span class="cx">         }
</span><span class="cx">     });
</span><span class="lines">@@ -73,8 +86,9 @@
</span><span class="cx">         name: "Network.getResponseBody.XHR.HTML",
</span><span class="cx">         description: "Get text/html content as text.",
</span><span class="cx">         expression: "createXHRForHTML()",
</span><del>-        contentHandler({error, sourceCode, content}) {
</del><ins>+        contentHandler({error, sourceCode, content, rawBase64Encoded}) {
</ins><span class="cx">             InspectorTest.expectEqual(sourceCode.mimeType, "text/html", "MIMEType should be 'text/html'.");
</span><ins>+            InspectorTest.expectEqual(rawBase64Encoded, false, "Content should not be base64Encoded.");
</ins><span class="cx">             InspectorTest.expectEqual(content, "<span>Hello World</span>\n", "Text content should match data.html.");
</span><span class="cx">         }
</span><span class="cx">     });
</span><span class="lines">@@ -81,11 +95,14 @@
</span><span class="cx"> 
</span><span class="cx">     addTestCase({
</span><span class="cx">         name: "Network.getResponseBody.XHR.JSON",
</span><del>-        description: "Get application/octet-stream content as text.",
</del><ins>+        description: "Get application/octet-stream content as base64Encoded text.",
</ins><span class="cx">         expression: "createXHRForJSON()",
</span><del>-        contentHandler({error, sourceCode, content}) {
</del><ins>+        contentHandler({error, sourceCode, content, rawBase64Encoded}) {
</ins><span class="cx">             InspectorTest.expectEqual(sourceCode.mimeType, "application/octet-stream", "MIMEType should be 'application/octet-stream'.");
</span><del>-            InspectorTest.expectEqual(content, `{"json": true, "value": 42}\n`, "JSON content should match data.json.");
</del><ins>+            InspectorTest.expectEqual(rawBase64Encoded, true, "Content should be base64Encoded.");
+            return contentAsText(content).then((text) => {
+                InspectorTest.expectEqual(text, `{"json": true, "value": 42}\n`, "JSON content should match data.json.");
+            });
</ins><span class="cx">         }
</span><span class="cx">     });
</span><span class="cx"> 
</span><span class="lines">@@ -93,8 +110,9 @@
</span><span class="cx">         name: "Network.getResponseBody.XHR.JSON2",
</span><span class="cx">         description: "Get application/json content as text.",
</span><span class="cx">         expression: "createXHRForJSON2()",
</span><del>-        contentHandler({error, sourceCode, content}) {
</del><ins>+        contentHandler({error, sourceCode, content, rawBase64Encoded}) {
</ins><span class="cx">             InspectorTest.expectEqual(sourceCode.mimeType, "application/json", "MIMEType should be 'application/json'.");
</span><ins>+            InspectorTest.expectEqual(rawBase64Encoded, false, "Content should not be base64Encoded.");
</ins><span class="cx">             InspectorTest.expectEqual(content, `{"json":true,"value":42}`, "JSON content should match specified content.");
</span><span class="cx">         }
</span><span class="cx">     });
</span><span class="lines">@@ -103,8 +121,9 @@
</span><span class="cx">         name: "Network.getResponseBody.XHR.JSON3",
</span><span class="cx">         description: "Get arbitrary +json content as text.",
</span><span class="cx">         expression: "createXHRForJSON3()",
</span><del>-        contentHandler({error, sourceCode, content}) {
</del><ins>+        contentHandler({error, sourceCode, content, rawBase64Encoded}) {
</ins><span class="cx">             InspectorTest.expectEqual(sourceCode.mimeType, "application/vnd.api+json", "MIMEType should be 'application/vnd.api+json'.");
</span><ins>+            InspectorTest.expectEqual(rawBase64Encoded, false, "Content should not be base64Encoded.");
</ins><span class="cx">             InspectorTest.expectEqual(content, `{"json":true,"value":999}`, "JSON content should match specified content.");
</span><span class="cx">         }
</span><span class="cx">     });
</span><span class="lines">@@ -113,8 +132,9 @@
</span><span class="cx">         name: "Network.getResponseBody.XHR.SVG",
</span><span class="cx">         description: "Get image/svg+xml content as text.",
</span><span class="cx">         expression: "createXHRForSVG()",
</span><del>-        contentHandler({error, sourceCode, content}) {
</del><ins>+        contentHandler({error, sourceCode, content, rawBase64Encoded}) {
</ins><span class="cx">             InspectorTest.expectEqual(sourceCode.mimeType, "image/svg+xml", "MIMEType should be 'image/svg+xml'.");
</span><ins>+            InspectorTest.expectEqual(rawBase64Encoded, false, "Content should not be base64Encoded.");
</ins><span class="cx">             InspectorTest.expectEqual(content,
</span><span class="cx"> `<?xml version="1.0" encoding="UTF-8"?>
</span><span class="cx"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 200">
</span><span class="lines">@@ -128,10 +148,10 @@
</span><span class="cx">         name: "Network.getResponseBody.XHR.PNG",
</span><span class="cx">         description: "Get image/png content.",
</span><span class="cx">         expression: "createXHRForPNG()",
</span><del>-        contentHandler({error, sourceCode, content}) {
-            // FIXME: <https://webkit.org/b/165495> Web Inspector: XHR / Fetch for non-text content should not show garbled text
</del><ins>+        contentHandler({error, sourceCode, content, rawBase64Encoded}) {
</ins><span class="cx">             InspectorTest.expectEqual(sourceCode.mimeType, "image/png", "MIMEType should be 'image/png'.");
</span><del>-            InspectorTest.expectEqual(typeof content, "string", "Image content should be text.");
</del><ins>+            InspectorTest.expectEqual(rawBase64Encoded, true, "Content should be base64Encoded.");
+            InspectorTest.expectThat(content instanceof Blob, "Image content should be a Blob.");
</ins><span class="cx">         }
</span><span class="cx">     });
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (225545 => 225546)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog   2017-12-05 22:09:04 UTC (rev 225545)
+++ trunk/Source/WebCore/ChangeLog      2017-12-05 22:09:36 UTC (rev 225546)
</span><span class="lines">@@ -1,3 +1,80 @@
</span><ins>+2017-12-05  Joseph Pecoraro  <pecoraro@apple.com>
+
+        Web Inspector: content views for resources loaded through XHR do not reflect declared mime-type
+        https://bugs.webkit.org/show_bug.cgi?id=141389
+        <rdar://problem/19767070>
+
+        Reviewed by Brian Burg.
+
+        Updated: http/tests/inspector/network/xhr-response-body.html:
+                 http/tests/inspector/network/fetch-response-body.html:
+
+        * xml/XMLHttpRequest.cpp:
+        (WebCore::XMLHttpRequest::didFinishLoading):
+        * inspector/InspectorInstrumentation.cpp:
+        (WebCore::InspectorInstrumentation::didFinishXHRLoadingImpl): Deleted.
+        * inspector/InspectorInstrumentation.h:
+        (WebCore::InspectorInstrumentation::didFinishXHRLoading): Deleted.
+        Remove special handling of XHR content that decoded output as text.
+
+        * inspector/NetworkResourcesData.h:
+        (WebCore::NetworkResourcesData::ResourceData::requestId const):
+        (WebCore::NetworkResourcesData::ResourceData::loaderId const):
+        (WebCore::NetworkResourcesData::ResourceData::frameId const):
+        (WebCore::NetworkResourcesData::ResourceData::url const):
+        (WebCore::NetworkResourcesData::ResourceData::content const):
+        (WebCore::NetworkResourcesData::ResourceData::isContentEvicted const):
+        (WebCore::NetworkResourcesData::ResourceData::textEncodingName const):
+        * inspector/NetworkResourcesData.cpp:
+        (WebCore::NetworkResourcesData::ResourceData::ResourceData):
+        (WebCore::NetworkResourcesData::ResourceData::decodeDataToContent):
+        (WebCore::NetworkResourcesData::responseReceived):
+        (WebCore::NetworkResourcesData::setResourceContent):
+        (WebCore::shouldBufferResourceData):
+        (WebCore::NetworkResourcesData::maybeAddResourceData):
+        (WebCore::NetworkResourcesData::maybeDecodeDataToContent):
+
+        Make NetworkResourcesData only create a text decoder for resources we
+        really think are text, and buffer resource data if it is text data
+        or if it is a resource that would otherwise not be buffered by WebCore
+        (such as XHRs with a DoNotBufferData policy). This ensures that the
+        Inspector will have data to show for resources that won't be cached.
+
+        * inspector/agents/InspectorPageAgent.cpp:
+        (WebCore::InspectorPageAgent::resourceContent):
+        (WebCore::InspectorPageAgent::sourceMapURLForResource):
+        (WebCore::InspectorPageAgent::searchInResource):
+        (WebCore::InspectorPageAgent::searchInResources):
+        (WebCore::hasTextContent): Deleted.
+        (WebCore::InspectorPageAgent::cachedResourceContent): Deleted.
+        (WebCore::InspectorPageAgent::createTextDecoder): Deleted.
+        (WebCore::textContentForCachedResource): Deleted.
+        * inspector/agents/InspectorPageAgent.h:
+        * inspector/agents/InspectorNetworkAgent.cpp:
+        (WebCore::InspectorNetworkAgent::didReceiveData):
+        (WebCore::InspectorNetworkAgent::willDestroyCachedResource):
+        (WebCore::InspectorNetworkAgent::getResponseBody):
+        (WebCore::InspectorNetworkAgent::shouldTreatAsText):
+        (WebCore::InspectorNetworkAgent::createTextDecoder):
+        (WebCore::InspectorNetworkAgent::textContentForCachedResource):
+        (WebCore::InspectorNetworkAgent::cachedResourceContent):
+        (WebCore::textContentForResourceData):
+        (WebCore::InspectorNetworkAgent::searchOtherRequests):
+        (WebCore::isErrorStatusCode): Deleted.
+        (WebCore::InspectorNetworkAgent::didFinishXHRLoading): Deleted.
+        * inspector/agents/InspectorNetworkAgent.h:
+        Move static PageAgent functions related to the generic data tuple
+        (content, base64Encoded) to NetworkAgent. Also generalize it to
+        not rely on the CachedResourceType, but instead rely on the MIME type.
+        This has a few changes in behavior:
+
+            - Images, may now be text if they have a text mime type (image/svg+xml).
+            - XHR / Fetch / Other may be sent as text if they have a text mime type.
+            - XHR / Fetch / Other are not assumed to be text, and may be sent as base64 encoded.
+        
+        For this to be useful the frontend should also check the mime type and
+        display an appropriate ContentView.
+
</ins><span class="cx"> 2017-12-05  Youenn Fablet  <youenn@apple.com>
</span><span class="cx"> 
</span><span class="cx">         Implement https://w3c.github.io/ServiceWorker/#clients-claim
</span></span></pre></div>
<a id="trunkSourceWebCoreinspectorInspectorInstrumentationcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/inspector/InspectorInstrumentation.cpp (225545 => 225546)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/inspector/InspectorInstrumentation.cpp      2017-12-05 22:09:04 UTC (rev 225545)
+++ trunk/Source/WebCore/inspector/InspectorInstrumentation.cpp 2017-12-05 22:09:36 UTC (rev 225546)
</span><span class="lines">@@ -617,14 +617,6 @@
</span><span class="cx">         consoleAgent->didFailLoading(identifier, error); // This should come AFTER resource notification, front-end relies on this.
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void InspectorInstrumentation::didFinishXHRLoadingImpl(InstrumentingAgents& instrumentingAgents, unsigned long identifier, std::optional<String> decodedText)
-{
-    if (InspectorNetworkAgent* networkAgent = instrumentingAgents.inspectorNetworkAgent()) {
-        if (decodedText)
-            networkAgent->didFinishXHRLoading(identifier, *decodedText);
-    }
-}
-
</del><span class="cx"> void InspectorInstrumentation::willLoadXHRSynchronouslyImpl(InstrumentingAgents& instrumentingAgents)
</span><span class="cx"> {
</span><span class="cx">     if (InspectorNetworkAgent* networkAgent = instrumentingAgents.inspectorNetworkAgent())
</span></span></pre></div>
<a id="trunkSourceWebCoreinspectorInspectorInstrumentationh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/inspector/InspectorInstrumentation.h (225545 => 225546)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/inspector/InspectorInstrumentation.h        2017-12-05 22:09:04 UTC (rev 225545)
+++ trunk/Source/WebCore/inspector/InspectorInstrumentation.h   2017-12-05 22:09:36 UTC (rev 225546)
</span><span class="lines">@@ -195,7 +195,6 @@
</span><span class="cx">     static void continueAfterXFrameOptionsDenied(Frame&, unsigned long identifier, DocumentLoader&, const ResourceResponse&);
</span><span class="cx">     static void continueWithPolicyDownload(Frame&, unsigned long identifier, DocumentLoader&, const ResourceResponse&);
</span><span class="cx">     static void continueWithPolicyIgnore(Frame&, unsigned long identifier, DocumentLoader&, const ResourceResponse&);
</span><del>-    static void didFinishXHRLoading(ScriptExecutionContext*, unsigned long identifier, std::optional<String> decodedText);
</del><span class="cx">     static void willLoadXHRSynchronously(ScriptExecutionContext*);
</span><span class="cx">     static void didLoadXHRSynchronously(ScriptExecutionContext*);
</span><span class="cx">     static void scriptImported(ScriptExecutionContext&, unsigned long identifier, const String& sourceString);
</span><span class="lines">@@ -366,7 +365,6 @@
</span><span class="cx">     static void didReceiveDataImpl(InstrumentingAgents&, unsigned long identifier, const char* data, int dataLength, int encodedDataLength);
</span><span class="cx">     static void didFinishLoadingImpl(InstrumentingAgents&, unsigned long identifier, DocumentLoader*, const NetworkLoadMetrics&, ResourceLoader*);
</span><span class="cx">     static void didFailLoadingImpl(InstrumentingAgents&, unsigned long identifier, DocumentLoader*, const ResourceError&);
</span><del>-    static void didFinishXHRLoadingImpl(InstrumentingAgents&, unsigned long identifier, std::optional<String> decodedText);
</del><span class="cx">     static void willLoadXHRSynchronouslyImpl(InstrumentingAgents&);
</span><span class="cx">     static void didLoadXHRSynchronouslyImpl(InstrumentingAgents&);
</span><span class="cx">     static void scriptImportedImpl(InstrumentingAgents&, unsigned long identifier, const String& sourceString);
</span><span class="lines">@@ -1011,13 +1009,6 @@
</span><span class="cx">         didReceiveResourceResponseImpl(*instrumentingAgents, identifier, &loader, response, nullptr);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-inline void InspectorInstrumentation::didFinishXHRLoading(ScriptExecutionContext* context, unsigned long identifier, std::optional<String> decodedText)
-{
-    FAST_RETURN_IF_NO_FRONTENDS(void());
-    if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForContext(context))
-        didFinishXHRLoadingImpl(*instrumentingAgents, identifier, decodedText);
-}
-
</del><span class="cx"> inline void InspectorInstrumentation::willLoadXHRSynchronously(ScriptExecutionContext* context)
</span><span class="cx"> {
</span><span class="cx">     FAST_RETURN_IF_NO_FRONTENDS(void());
</span></span></pre></div>
<a id="trunkSourceWebCoreinspectorNetworkResourcesDatacpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/inspector/NetworkResourcesData.cpp (225545 => 225546)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/inspector/NetworkResourcesData.cpp  2017-12-05 22:09:04 UTC (rev 225545)
+++ trunk/Source/WebCore/inspector/NetworkResourcesData.cpp     2017-12-05 22:09:36 UTC (rev 225546)
</span><span class="lines">@@ -1,5 +1,6 @@
</span><span class="cx"> /*
</span><span class="cx">  * Copyright (C) 2011 Google Inc. All rights reserved.
</span><ins>+ * Copyright (C) 2017 Apple Inc.  All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions are
</span><span class="lines">@@ -30,9 +31,11 @@
</span><span class="cx"> #include "NetworkResourcesData.h"
</span><span class="cx"> 
</span><span class="cx"> #include "CachedResource.h"
</span><ins>+#include "InspectorNetworkAgent.h"
</ins><span class="cx"> #include "ResourceResponse.h"
</span><span class="cx"> #include "SharedBuffer.h"
</span><span class="cx"> #include "TextResourceDecoder.h"
</span><ins>+#include <wtf/text/Base64.h>
</ins><span class="cx"> 
</span><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><span class="lines">@@ -44,10 +47,6 @@
</span><span class="cx"> NetworkResourcesData::ResourceData::ResourceData(const String& requestId, const String& loaderId)
</span><span class="cx">     : m_requestId(requestId)
</span><span class="cx">     , m_loaderId(loaderId)
</span><del>-    , m_base64Encoded(false)
-    , m_isContentEvicted(false)
-    , m_type(InspectorPageAgent::OtherResource)
-    , m_cachedResource(nullptr)
</del><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -104,10 +103,22 @@
</span><span class="cx"> size_t NetworkResourcesData::ResourceData::decodeDataToContent()
</span><span class="cx"> {
</span><span class="cx">     ASSERT(!hasContent());
</span><ins>+
</ins><span class="cx">     size_t dataLength = m_dataBuffer->size();
</span><del>-    m_content = m_decoder->decodeAndFlush(m_dataBuffer->data(), m_dataBuffer->size());
</del><ins>+
+    if (m_decoder) {
+        m_base64Encoded = false;
+        m_content = m_decoder->decodeAndFlush(m_dataBuffer->data(), dataLength);
+    } else {
+        m_base64Encoded = true;
+        m_content = base64Encode(m_dataBuffer->data(), dataLength);
+    }
+
</ins><span class="cx">     m_dataBuffer = nullptr;
</span><del>-    return contentSizeInBytes(m_content) - dataLength;
</del><ins>+
+    size_t decodedLength = contentSizeInBytes(m_content);
+    ASSERT(decodedLength >= dataLength);
+    return decodedLength - dataLength;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> NetworkResourcesData::NetworkResourcesData()
</span><span class="lines">@@ -144,11 +155,14 @@
</span><span class="cx">     ResourceData* resourceData = resourceDataForRequestId(requestId);
</span><span class="cx">     if (!resourceData)
</span><span class="cx">         return;
</span><ins>+
</ins><span class="cx">     resourceData->setFrameId(frameId);
</span><span class="cx">     resourceData->setURL(response.url());
</span><del>-    resourceData->setDecoder(InspectorPageAgent::createTextDecoder(response.mimeType(), response.textEncodingName()));
</del><span class="cx">     resourceData->setHTTPStatusCode(response.httpStatusCode());
</span><span class="cx">     resourceData->setType(type);
</span><ins>+
+    if (InspectorNetworkAgent::shouldTreatAsText(response.mimeType()))
+        resourceData->setDecoder(InspectorNetworkAgent::createTextDecoder(response.mimeType(), response.textEncodingName()));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void NetworkResourcesData::setResourceType(const String& requestId, InspectorPageAgent::ResourceType type)
</span><span class="lines">@@ -172,11 +186,13 @@
</span><span class="cx">     ResourceData* resourceData = resourceDataForRequestId(requestId);
</span><span class="cx">     if (!resourceData)
</span><span class="cx">         return;
</span><ins>+
</ins><span class="cx">     size_t dataLength = contentSizeInBytes(content);
</span><span class="cx">     if (dataLength > m_maximumSingleResourceContentSize)
</span><span class="cx">         return;
</span><span class="cx">     if (resourceData->isContentEvicted())
</span><span class="cx">         return;
</span><ins>+
</ins><span class="cx">     if (ensureFreeSpace(dataLength) && !resourceData->isContentEvicted()) {
</span><span class="cx">         // We can not be sure that we didn't try to save this request data while it was loading, so remove it, if any.
</span><span class="cx">         if (resourceData->hasContent() || resourceData->hasData())
</span><span class="lines">@@ -187,17 +203,32 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+static bool shouldBufferResourceData(const NetworkResourcesData::ResourceData& resourceData)
+{
+    if (resourceData.decoder())
+        return true;
+
+    // Buffer data for Web Inspector when the rest of the system would not normally buffer.
+    if (resourceData.cachedResource() && resourceData.cachedResource()->dataBufferingPolicy() == DoNotBufferData)
+        return true;
+
+    return false;
+}
+
</ins><span class="cx"> void NetworkResourcesData::maybeAddResourceData(const String& requestId, const char* data, size_t dataLength)
</span><span class="cx"> {
</span><span class="cx">     ResourceData* resourceData = resourceDataForRequestId(requestId);
</span><span class="cx">     if (!resourceData)
</span><span class="cx">         return;
</span><del>-    if (!resourceData->decoder())
</del><ins>+
+    if (!shouldBufferResourceData(*resourceData))
</ins><span class="cx">         return;
</span><ins>+
</ins><span class="cx">     if (resourceData->dataLength() + dataLength > m_maximumSingleResourceContentSize)
</span><span class="cx">         m_contentSize -= resourceData->evictContent();
</span><span class="cx">     if (resourceData->isContentEvicted())
</span><span class="cx">         return;
</span><ins>+
</ins><span class="cx">     if (ensureFreeSpace(dataLength) && !resourceData->isContentEvicted()) {
</span><span class="cx">         m_requestIdsDeque.append(requestId);
</span><span class="cx">         resourceData->appendData(data, dataLength);
</span><span class="lines">@@ -210,8 +241,10 @@
</span><span class="cx">     ResourceData* resourceData = resourceDataForRequestId(requestId);
</span><span class="cx">     if (!resourceData)
</span><span class="cx">         return;
</span><ins>+
</ins><span class="cx">     if (!resourceData->hasData())
</span><span class="cx">         return;
</span><ins>+
</ins><span class="cx">     m_contentSize += resourceData->decodeDataToContent();
</span><span class="cx">     size_t dataLength = contentSizeInBytes(resourceData->content());
</span><span class="cx">     if (dataLength > m_maximumSingleResourceContentSize)
</span></span></pre></div>
<a id="trunkSourceWebCoreinspectorNetworkResourcesDatah"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/inspector/NetworkResourcesData.h (225545 => 225546)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/inspector/NetworkResourcesData.h    2017-12-05 22:09:04 UTC (rev 225545)
+++ trunk/Source/WebCore/inspector/NetworkResourcesData.h       2017-12-05 22:09:36 UTC (rev 225546)
</span><span class="lines">@@ -1,5 +1,6 @@
</span><span class="cx"> /*
</span><span class="cx">  * Copyright (C) 2011 Google Inc. All rights reserved.
</span><ins>+ * Copyright (C) 2017 Apple Inc.  All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions are
</span><span class="lines">@@ -29,7 +30,6 @@
</span><span class="cx"> #pragma once
</span><span class="cx"> 
</span><span class="cx"> #include "InspectorPageAgent.h"
</span><del>-#include "TextResourceDecoder.h"
</del><span class="cx"> #include <wtf/Deque.h>
</span><span class="cx"> #include <wtf/HashMap.h>
</span><span class="cx"> #include <wtf/text/WTFString.h>
</span><span class="lines">@@ -38,6 +38,7 @@
</span><span class="cx"> 
</span><span class="cx"> class CachedResource;
</span><span class="cx"> class ResourceResponse;
</span><ins>+class TextResourceDecoder;
</ins><span class="cx"> class SharedBuffer;
</span><span class="cx"> 
</span><span class="cx"> class NetworkResourcesData {
</span><span class="lines">@@ -49,24 +50,24 @@
</span><span class="cx">     public:
</span><span class="cx">         ResourceData(const String& requestId, const String& loaderId);
</span><span class="cx"> 
</span><del>-        String requestId() const { return m_requestId; }
-        String loaderId() const { return m_loaderId; }
</del><ins>+        const String& requestId() const { return m_requestId; }
+        const String& loaderId() const { return m_loaderId; }
</ins><span class="cx"> 
</span><del>-        String frameId() const { return m_frameId; }
</del><ins>+        const String& frameId() const { return m_frameId; }
</ins><span class="cx">         void setFrameId(const String& frameId) { m_frameId = frameId; }
</span><span class="cx"> 
</span><del>-        String url() const { return m_url; }
</del><ins>+        const String& url() const { return m_url; }
</ins><span class="cx">         void setURL(const String& url) { m_url = url; }
</span><span class="cx"> 
</span><span class="cx">         bool hasContent() const { return !m_content.isNull(); }
</span><del>-        String content() const { return m_content; }
</del><ins>+        const String& content() const { return m_content; }
</ins><span class="cx">         void setContent(const String&, bool base64Encoded);
</span><span class="cx"> 
</span><span class="cx">         bool base64Encoded() const { return m_base64Encoded; }
</span><span class="cx"> 
</span><span class="cx">         unsigned removeContent();
</span><ins>+        unsigned evictContent();
</ins><span class="cx">         bool isContentEvicted() const { return m_isContentEvicted; }
</span><del>-        unsigned evictContent();
</del><span class="cx"> 
</span><span class="cx">         InspectorPageAgent::ResourceType type() const { return m_type; }
</span><span class="cx">         void setType(InspectorPageAgent::ResourceType type) { m_type = type; }
</span><span class="lines">@@ -74,7 +75,7 @@
</span><span class="cx">         int httpStatusCode() const { return m_httpStatusCode; }
</span><span class="cx">         void setHTTPStatusCode(int httpStatusCode) { m_httpStatusCode = httpStatusCode; }
</span><span class="cx"> 
</span><del>-        String textEncodingName() const { return m_textEncodingName; }
</del><ins>+        const String& textEncodingName() const { return m_textEncodingName; }
</ins><span class="cx">         void setTextEncodingName(const String& textEncodingName) { m_textEncodingName = textEncodingName; }
</span><span class="cx"> 
</span><span class="cx">         RefPtr<TextResourceDecoder> decoder() const { return m_decoder.copyRef(); }
</span><span class="lines">@@ -97,17 +98,15 @@
</span><span class="cx">         String m_frameId;
</span><span class="cx">         String m_url;
</span><span class="cx">         String m_content;
</span><del>-        bool m_base64Encoded;
-        RefPtr<SharedBuffer> m_dataBuffer;
-        bool m_isContentEvicted;
-        InspectorPageAgent::ResourceType m_type;
-        int m_httpStatusCode;
-
</del><span class="cx">         String m_textEncodingName;
</span><span class="cx">         RefPtr<TextResourceDecoder> m_decoder;
</span><del>-
</del><ins>+        RefPtr<SharedBuffer> m_dataBuffer;
</ins><span class="cx">         RefPtr<SharedBuffer> m_buffer;
</span><del>-        CachedResource* m_cachedResource;
</del><ins>+        CachedResource* m_cachedResource { nullptr };
+        InspectorPageAgent::ResourceType m_type { InspectorPageAgent::OtherResource };
+        int m_httpStatusCode { 0 };
+        bool m_isContentEvicted { false };
+        bool m_base64Encoded { false };
</ins><span class="cx">     };
</span><span class="cx"> 
</span><span class="cx">     NetworkResourcesData();
</span></span></pre></div>
<a id="trunkSourceWebCoreinspectoragentsInspectorNetworkAgentcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/inspector/agents/InspectorNetworkAgent.cpp (225545 => 225546)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/inspector/agents/InspectorNetworkAgent.cpp  2017-12-05 22:09:04 UTC (rev 225545)
+++ trunk/Source/WebCore/inspector/agents/InspectorNetworkAgent.cpp     2017-12-05 22:09:36 UTC (rev 225546)
</span><span class="lines">@@ -32,10 +32,12 @@
</span><span class="cx"> #include "config.h"
</span><span class="cx"> #include "InspectorNetworkAgent.h"
</span><span class="cx"> 
</span><ins>+#include "CachedCSSStyleSheet.h"
</ins><span class="cx"> #include "CachedRawResource.h"
</span><span class="cx"> #include "CachedResource.h"
</span><span class="cx"> #include "CachedResourceLoader.h"
</span><span class="cx"> #include "CachedResourceRequestInitiators.h"
</span><ins>+#include "CachedScript.h"
</ins><span class="cx"> #include "Document.h"
</span><span class="cx"> #include "DocumentLoader.h"
</span><span class="cx"> #include "DocumentThreadableLoader.h"
</span><span class="lines">@@ -47,6 +49,7 @@
</span><span class="cx"> #include "InstrumentingAgents.h"
</span><span class="cx"> #include "JSMainThreadExecState.h"
</span><span class="cx"> #include "JSWebSocket.h"
</span><ins>+#include "MIMETypeRegistry.h"
</ins><span class="cx"> #include "MemoryCache.h"
</span><span class="cx"> #include "NetworkResourcesData.h"
</span><span class="cx"> #include "Page.h"
</span><span class="lines">@@ -58,6 +61,7 @@
</span><span class="cx"> #include "ScriptState.h"
</span><span class="cx"> #include "ScriptableDocumentParser.h"
</span><span class="cx"> #include "SubresourceLoader.h"
</span><ins>+#include "TextResourceDecoder.h"
</ins><span class="cx"> #include "ThreadableLoaderClient.h"
</span><span class="cx"> #include "URL.h"
</span><span class="cx"> #include "WebSocket.h"
</span><span class="lines">@@ -67,7 +71,6 @@
</span><span class="cx"> #include <inspector/IdentifiersFactory.h>
</span><span class="cx"> #include <inspector/InjectedScript.h>
</span><span class="cx"> #include <inspector/InjectedScriptManager.h>
</span><del>-#include <inspector/InspectorFrontendRouter.h>
</del><span class="cx"> #include <inspector/ScriptCallStack.h>
</span><span class="cx"> #include <inspector/ScriptCallStackFactory.h>
</span><span class="cx"> #include <runtime/JSCInlines.h>
</span><span class="lines">@@ -75,6 +78,7 @@
</span><span class="cx"> #include <wtf/Lock.h>
</span><span class="cx"> #include <wtf/RefPtr.h>
</span><span class="cx"> #include <wtf/Stopwatch.h>
</span><ins>+#include <wtf/text/Base64.h>
</ins><span class="cx"> #include <wtf/text/StringBuilder.h>
</span><span class="cx"> 
</span><span class="cx"> typedef Inspector::NetworkBackendDispatcherHandler::LoadResourceCallback LoadResourceCallback;
</span><span class="lines">@@ -456,11 +460,6 @@
</span><span class="cx">         didReceiveData(identifier, nullptr, cachedResource->encodedSize(), 0);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-static bool isErrorStatusCode(int statusCode)
-{
-    return statusCode >= 400;
-}
-
</del><span class="cx"> void InspectorNetworkAgent::didReceiveData(unsigned long identifier, const char* data, int dataLength, int encodedDataLength)
</span><span class="cx"> {
</span><span class="cx">     if (m_hiddenRequestIdentifiers.contains(identifier))
</span><span class="lines">@@ -470,7 +469,7 @@
</span><span class="cx"> 
</span><span class="cx">     if (data) {
</span><span class="cx">         NetworkResourcesData::ResourceData const* resourceData = m_resourcesData->data(requestId);
</span><del>-        if (resourceData && !m_loadingXHRSynchronously && (!resourceData->cachedResource() || resourceData->cachedResource()->dataBufferingPolicy() == DoNotBufferData || isErrorStatusCode(resourceData->httpStatusCode())))
</del><ins>+        if (resourceData && !m_loadingXHRSynchronously)
</ins><span class="cx">             m_resourcesData->maybeAddResourceData(requestId, data, dataLength);
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -567,11 +566,6 @@
</span><span class="cx">         m_resourcesData->setResourceType(IdentifiersFactory::requestId(identifier), InspectorPageAgent::XHRResource);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void InspectorNetworkAgent::didFinishXHRLoading(unsigned long identifier, const String& decodedText)
-{
-    m_resourcesData->setResourceContent(IdentifiersFactory::requestId(identifier), decodedText);
-}
-
</del><span class="cx"> void InspectorNetworkAgent::willLoadXHRSynchronously()
</span><span class="cx"> {
</span><span class="cx">     m_loadingXHRSynchronously = true;
</span><span class="lines">@@ -590,8 +584,9 @@
</span><span class="cx"> 
</span><span class="cx">     String content;
</span><span class="cx">     bool base64Encoded;
</span><del>-    if (!InspectorPageAgent::cachedResourceContent(&cachedResource, &content, &base64Encoded))
</del><ins>+    if (!InspectorNetworkAgent::cachedResourceContent(cachedResource, &content, &base64Encoded))
</ins><span class="cx">         return;
</span><ins>+
</ins><span class="cx">     for (auto& id : requestIds)
</span><span class="cx">         m_resourcesData->setResourceContent(id, content, base64Encoded);
</span><span class="cx"> }
</span><span class="lines">@@ -778,7 +773,7 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     if (resourceData->cachedResource()) {
</span><del>-        if (InspectorPageAgent::cachedResourceContent(resourceData->cachedResource(), content, base64Encoded))
</del><ins>+        if (InspectorNetworkAgent::cachedResourceContent(*resourceData->cachedResource(), content, base64Encoded))
</ins><span class="cx">             return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -868,6 +863,84 @@
</span><span class="cx">     result = injectedScript.wrapObject(webSocketAsScriptValue(state, webSocket), objectGroupName);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool InspectorNetworkAgent::shouldTreatAsText(const String& mimeType)
+{
+    return startsWithLettersIgnoringASCIICase(mimeType, "text/")
+        || MIMETypeRegistry::isSupportedJavaScriptMIMEType(mimeType)
+        || MIMETypeRegistry::isSupportedJSONMIMEType(mimeType)
+        || MIMETypeRegistry::isXMLMIMEType(mimeType);
+}
+
+Ref<TextResourceDecoder> InspectorNetworkAgent::createTextDecoder(const String& mimeType, const String& textEncodingName)
+{
+    if (!textEncodingName.isEmpty())
+        return TextResourceDecoder::create(ASCIILiteral("text/plain"), textEncodingName);
+
+    if (MIMETypeRegistry::isTextMIMEType(mimeType))
+        return TextResourceDecoder::create(mimeType, "UTF-8");
+    if (MIMETypeRegistry::isXMLMIMEType(mimeType)) {
+        auto decoder = TextResourceDecoder::create(ASCIILiteral("application/xml"));
+        decoder->useLenientXMLDecoding();
+        return decoder;
+    }
+
+    return TextResourceDecoder::create(ASCIILiteral("text/plain"), "UTF-8");
+}
+
+std::optional<String> InspectorNetworkAgent::textContentForCachedResource(CachedResource& cachedResource)
+{
+    if (!InspectorNetworkAgent::shouldTreatAsText(cachedResource.mimeType()))
+        return std::nullopt;
+
+    String result;
+    bool base64Encoded;
+    if (InspectorNetworkAgent::cachedResourceContent(cachedResource, &result, &base64Encoded)) {
+        ASSERT(!base64Encoded);
+        return result;
+    }
+
+    return std::nullopt;
+}
+
+bool InspectorNetworkAgent::cachedResourceContent(CachedResource& resource, String* result, bool* base64Encoded)
+{
+    ASSERT(result);
+    ASSERT(base64Encoded);
+
+    if (!resource.encodedSize()) {
+        *base64Encoded = false;
+        *result = String();
+        return true;
+    }
+
+    switch (resource.type()) {
+    case CachedResource::CSSStyleSheet:
+        *base64Encoded = false;
+        *result = downcast<CachedCSSStyleSheet>(resource).sheetText();
+        // The above can return a null String if the MIME type is invalid.
+        return !result->isNull();
+    case CachedResource::Script:
+        *base64Encoded = false;
+        *result = downcast<CachedScript>(resource).script().toString();
+        return true;
+    default:
+        auto* buffer = resource.resourceBuffer();
+        if (!buffer)
+            return false;
+
+        if (InspectorNetworkAgent::shouldTreatAsText(resource.mimeType())) {
+            auto decoder = InspectorNetworkAgent::createTextDecoder(resource.mimeType(), resource.response().textEncodingName());
+            *base64Encoded = false;
+            *result = decoder->decodeAndFlush(buffer->data(), buffer->size());
+            return true;
+        }
+
+        *base64Encoded = true;
+        *result = base64Encode(buffer->data(), buffer->size());
+        return true;
+    }
+}
+
</ins><span class="cx"> static Ref<Inspector::Protocol::Page::SearchResult> buildObjectForSearchResult(const String& requestId, const String& frameId, const String& url, int matchesCount)
</span><span class="cx"> {
</span><span class="cx">     auto searchResult = Inspector::Protocol::Page::SearchResult::create()
</span><span class="lines">@@ -879,11 +952,22 @@
</span><span class="cx">     return searchResult;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+static std::optional<String> textContentForResourceData(const NetworkResourcesData::ResourceData& resourceData)
+{
+    if (resourceData.hasContent() && !resourceData.base64Encoded())
+        return resourceData.content();
+
+    if (resourceData.cachedResource())
+        return InspectorNetworkAgent::textContentForCachedResource(*resourceData.cachedResource());
+
+    return std::nullopt;
+}
+
</ins><span class="cx"> void InspectorNetworkAgent::searchOtherRequests(const JSC::Yarr::RegularExpression& regex, RefPtr<JSON::ArrayOf<Inspector::Protocol::Page::SearchResult>>& result)
</span><span class="cx"> {
</span><span class="cx">     Vector<NetworkResourcesData::ResourceData*> resources = m_resourcesData->resources();
</span><span class="cx">     for (auto* resourceData : resources) {
</span><del>-        if (resourceData->hasContent()) {
</del><ins>+        if (auto textContent = textContentForResourceData(*resourceData)) {
</ins><span class="cx">             int matchesCount = ContentSearchUtilities::countRegularExpressionMatches(regex, resourceData->content());
</span><span class="cx">             if (matchesCount)
</span><span class="cx">                 result->addItem(buildObjectForSearchResult(resourceData->requestId(), resourceData->frameId(), resourceData->url(), matchesCount));
</span></span></pre></div>
<a id="trunkSourceWebCoreinspectoragentsInspectorNetworkAgenth"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/inspector/agents/InspectorNetworkAgent.h (225545 => 225546)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/inspector/agents/InspectorNetworkAgent.h    2017-12-05 22:09:04 UTC (rev 225545)
+++ trunk/Source/WebCore/inspector/agents/InspectorNetworkAgent.h       2017-12-05 22:09:36 UTC (rev 225546)
</span><span class="lines">@@ -57,6 +57,7 @@
</span><span class="cx"> class ResourceLoader;
</span><span class="cx"> class ResourceRequest;
</span><span class="cx"> class ResourceResponse;
</span><ins>+class TextResourceDecoder;
</ins><span class="cx"> class URL;
</span><span class="cx"> class WebSocket;
</span><span class="cx"> 
</span><span class="lines">@@ -71,6 +72,11 @@
</span><span class="cx">     explicit InspectorNetworkAgent(WebAgentContext&);
</span><span class="cx">     virtual ~InspectorNetworkAgent();
</span><span class="cx"> 
</span><ins>+    static bool shouldTreatAsText(const String& mimeType);
+    static Ref<TextResourceDecoder> createTextDecoder(const String& mimeType, const String& textEncodingName);
+    static std::optional<String> textContentForCachedResource(CachedResource&);
+    static bool cachedResourceContent(CachedResource&, String* result, bool* base64Encoded);
+
</ins><span class="cx">     void didCreateFrontendAndBackend(Inspector::FrontendRouter*, Inspector::BackendDispatcher*) override;
</span><span class="cx">     void willDestroyFrontendAndBackend(Inspector::DisconnectReason) override;
</span><span class="cx"> 
</span><span class="lines">@@ -85,7 +91,6 @@
</span><span class="cx">     void didFailLoading(unsigned long identifier, DocumentLoader*, const ResourceError&);
</span><span class="cx">     void didLoadResourceFromMemoryCache(DocumentLoader*, CachedResource&);
</span><span class="cx">     void didReceiveThreadableLoaderResponse(unsigned long identifier, DocumentThreadableLoader&);
</span><del>-    void didFinishXHRLoading(unsigned long identifier, const String& decodedText);
</del><span class="cx">     void willLoadXHRSynchronously();
</span><span class="cx">     void didLoadXHRSynchronously();
</span><span class="cx">     void didReceiveScriptResponse(unsigned long identifier);
</span><span class="lines">@@ -104,8 +109,6 @@
</span><span class="cx">     void searchOtherRequests(const JSC::Yarr::RegularExpression&, RefPtr<JSON::ArrayOf<Inspector::Protocol::Page::SearchResult>>&);
</span><span class="cx">     void searchInRequest(ErrorString&, const String& requestId, const String& query, bool caseSensitive, bool isRegex, RefPtr<JSON::ArrayOf<Inspector::Protocol::GenericTypes::SearchMatch>>&);
</span><span class="cx"> 
</span><del>-    RefPtr<Inspector::Protocol::Network::Initiator> buildInitiatorObject(Document*);
-
</del><span class="cx">     // Called from frontend.
</span><span class="cx">     void enable(ErrorString&) final;
</span><span class="cx">     void disable(ErrorString&) final;
</span><span class="lines">@@ -128,6 +131,7 @@
</span><span class="cx"> 
</span><span class="cx">     WebSocket* webSocketForRequestId(const String& requestId);
</span><span class="cx"> 
</span><ins>+    RefPtr<Inspector::Protocol::Network::Initiator> buildInitiatorObject(Document*);
</ins><span class="cx">     Ref<Inspector::Protocol::Network::ResourceTiming> buildObjectForTiming(const NetworkLoadMetrics&, ResourceLoader&);
</span><span class="cx">     Ref<Inspector::Protocol::Network::Metrics> buildObjectForMetrics(const NetworkLoadMetrics&);
</span><span class="cx">     RefPtr<Inspector::Protocol::Network::Response> buildObjectForResourceResponse(const ResourceResponse&, ResourceLoader*);
</span></span></pre></div>
<a id="trunkSourceWebCoreinspectoragentsInspectorPageAgentcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/inspector/agents/InspectorPageAgent.cpp (225545 => 225546)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/inspector/agents/InspectorPageAgent.cpp     2017-12-05 22:09:04 UTC (rev 225545)
+++ trunk/Source/WebCore/inspector/agents/InspectorPageAgent.cpp        2017-12-05 22:09:36 UTC (rev 225546)
</span><span class="lines">@@ -32,12 +32,8 @@
</span><span class="cx"> #include "config.h"
</span><span class="cx"> #include "InspectorPageAgent.h"
</span><span class="cx"> 
</span><del>-#include "CachedCSSStyleSheet.h"
-#include "CachedFont.h"
-#include "CachedImage.h"
</del><span class="cx"> #include "CachedResource.h"
</span><span class="cx"> #include "CachedResourceLoader.h"
</span><del>-#include "CachedScript.h"
</del><span class="cx"> #include "Cookie.h"
</span><span class="cx"> #include "CookieJar.h"
</span><span class="cx"> #include "Document.h"
</span><span class="lines">@@ -65,7 +61,6 @@
</span><span class="cx"> #include "Settings.h"
</span><span class="cx"> #include "StyleScope.h"
</span><span class="cx"> #include "TextEncoding.h"
</span><del>-#include "TextResourceDecoder.h"
</del><span class="cx"> #include "UserGestureIndicator.h"
</span><span class="cx"> #include <inspector/ContentSearchUtilities.h>
</span><span class="cx"> #include <inspector/IdentifiersFactory.h>
</span><span class="lines">@@ -96,69 +91,6 @@
</span><span class="cx">     return false;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-static bool hasTextContent(CachedResource* cachedResource)
-{
-    // FIXME: <https://webkit.org/b/165495> Web Inspector: XHR / Fetch for non-text content should not show garbled text
-    // We should not assume XHR / Fetch have text content.
-
-    InspectorPageAgent::ResourceType type = InspectorPageAgent::inspectorResourceType(*cachedResource);
-    return type == InspectorPageAgent::DocumentResource
-        || type == InspectorPageAgent::StylesheetResource
-        || type == InspectorPageAgent::ScriptResource
-        || type == InspectorPageAgent::XHRResource
-        || type == InspectorPageAgent::FetchResource;
-}
-
-bool InspectorPageAgent::cachedResourceContent(CachedResource* cachedResource, String* result, bool* base64Encoded)
-{
-    if (!cachedResource)
-        return false;
-
-    *base64Encoded = !hasTextContent(cachedResource);
-
-    if (!cachedResource->encodedSize()) {
-        *result = emptyString();
-        return true;
-    }
-
-    if (*base64Encoded) {
-        if (auto* buffer = cachedResource->resourceBuffer()) {
-            *result = base64Encode(buffer->data(), buffer->size());
-            return true;
-        }
-        return false;
-    }
-
-    if (cachedResource) {
-        switch (cachedResource->type()) {
-        case CachedResource::CSSStyleSheet:
-            // This can return a null String if the MIME type is invalid.
-            *result = downcast<CachedCSSStyleSheet>(*cachedResource).sheetText();
-            return !result->isNull();
-        case CachedResource::Script:
-            *result = downcast<CachedScript>(*cachedResource).script().toString();
-            return true;
-        case CachedResource::MediaResource:
-        case CachedResource::Icon:
-        case CachedResource::RawResource: {
-            auto* buffer = cachedResource->resourceBuffer();
-            if (!buffer)
-                return false;
-            RefPtr<TextResourceDecoder> decoder = InspectorPageAgent::createTextDecoder(cachedResource->response().mimeType(), cachedResource->response().textEncodingName());
-            // We show content for raw resources only for certain mime types (text, html and xml). Otherwise decoder will be null.
-            if (!decoder)
-                return false;
-            *result = decoder->decodeAndFlush(buffer->data(), buffer->size());
-            return true;
-        }
-        default:
-            auto* buffer = cachedResource->resourceBuffer();
-            return decodeBuffer(buffer ? buffer->data() : nullptr, buffer ? buffer->size() : 0, cachedResource->encoding(), result);
-        }
-    }
-    return false;
-}
-
</del><span class="cx"> bool InspectorPageAgent::mainResourceContent(Frame* frame, bool withBase64Encode, String* result)
</span><span class="cx"> {
</span><span class="cx">     RefPtr<SharedBuffer> buffer = frame->loader().documentLoader()->mainResourceData();
</span><span class="lines">@@ -195,14 +127,15 @@
</span><span class="cx">         success = mainResourceContent(frame, *base64Encoded, result);
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    if (!success)
-        success = cachedResourceContent(cachedResource(frame, url), result, base64Encoded);
</del><ins>+    if (!success) {
+        if (auto* resource = cachedResource(frame, url))
+            success = InspectorNetworkAgent::cachedResourceContent(*resource, result, base64Encoded);
+    }
</ins><span class="cx"> 
</span><span class="cx">     if (!success)
</span><span class="cx">         errorString = ASCIILiteral("No resource with given URL found");
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-//static
</del><span class="cx"> String InspectorPageAgent::sourceMapURLForResource(CachedResource* cachedResource)
</span><span class="cx"> {
</span><span class="cx">     static NeverDestroyed<String> sourceMapHTTPHeader(MAKE_STATIC_STRING_IMPL("SourceMap"));
</span><span class="lines">@@ -225,7 +158,7 @@
</span><span class="cx"> 
</span><span class="cx">     String content;
</span><span class="cx">     bool base64Encoded;
</span><del>-    if (InspectorPageAgent::cachedResourceContent(cachedResource, &content, &base64Encoded) && !base64Encoded)
</del><ins>+    if (InspectorNetworkAgent::cachedResourceContent(*cachedResource, &content, &base64Encoded) && !base64Encoded)
</ins><span class="cx">         return ContentSearchUtilities::findStylesheetSourceMapURL(content);
</span><span class="cx"> 
</span><span class="cx">     return String();
</span><span class="lines">@@ -325,23 +258,6 @@
</span><span class="cx">     return resourceTypeJSON(inspectorResourceType(cachedResource));
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-RefPtr<TextResourceDecoder> InspectorPageAgent::createTextDecoder(const String& mimeType, const String& textEncodingName)
-{
-    if (!textEncodingName.isEmpty())
-        return TextResourceDecoder::create(ASCIILiteral("text/plain"), textEncodingName);
-
-    if (MIMETypeRegistry::isTextMIMEType(mimeType))
-        return TextResourceDecoder::create(mimeType, "UTF-8");
-
-    if (MIMETypeRegistry::isXMLMIMEType(mimeType)) {
-        RefPtr<TextResourceDecoder> decoder = TextResourceDecoder::create(ASCIILiteral("application/xml"));
-        decoder->useLenientXMLDecoding();
-        return decoder;
-    }
-
-    return TextResourceDecoder::create(ASCIILiteral("text/plain"), "UTF-8");
-}
-
</del><span class="cx"> InspectorPageAgent::InspectorPageAgent(PageAgentContext& context, InspectorClient* client, InspectorOverlay* overlay)
</span><span class="cx">     : InspectorAgentBase(ASCIILiteral("Page"), context)
</span><span class="cx">     , m_frontendDispatcher(std::make_unique<Inspector::PageFrontendDispatcher>(context.frontendRouter))
</span><span class="lines">@@ -543,18 +459,6 @@
</span><span class="cx">     resourceContent(errorString, frame, URL(ParsedURLString, url), content, base64Encoded);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-static bool textContentForCachedResource(CachedResource* cachedResource, String* result)
-{
-    if (hasTextContent(cachedResource)) {
-        bool base64Encoded;
-        if (InspectorPageAgent::cachedResourceContent(cachedResource, result, &base64Encoded)) {
-            ASSERT(!base64Encoded);
-            return true;
-        }
-    }
-    return false;
-}
-
</del><span class="cx"> void InspectorPageAgent::searchInResource(ErrorString& errorString, const String& frameId, const String& url, const String& query, const bool* const optionalCaseSensitive, const bool* const optionalIsRegex, const String* optionalRequestId, RefPtr<JSON::ArrayOf<Inspector::Protocol::GenericTypes::SearchMatch>>& results)
</span><span class="cx"> {
</span><span class="cx">     results = JSON::ArrayOf<Inspector::Protocol::GenericTypes::SearchMatch>::create();
</span><span class="lines">@@ -585,9 +489,12 @@
</span><span class="cx">         success = mainResourceContent(frame, false, &content);
</span><span class="cx"> 
</span><span class="cx">     if (!success) {
</span><del>-        CachedResource* resource = cachedResource(frame, kurl);
-        if (resource)
-            success = textContentForCachedResource(resource, &content);
</del><ins>+        if (auto* resource = cachedResource(frame, kurl)) {
+            if (auto textContent = InspectorNetworkAgent::textContentForCachedResource(*resource)) {
+                content = *textContent;
+                success = true;
+            }
+        }
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     if (!success)
</span><span class="lines">@@ -614,21 +521,13 @@
</span><span class="cx">     JSC::Yarr::RegularExpression regex = ContentSearchUtilities::createSearchRegex(text, caseSensitive, isRegex);
</span><span class="cx"> 
</span><span class="cx">     for (Frame* frame = &m_page.mainFrame(); frame; frame = frame->tree().traverseNext()) {
</span><del>-        String content;
-
</del><span class="cx">         for (auto* cachedResource : cachedResourcesForFrame(frame)) {
</span><del>-            if (textContentForCachedResource(cachedResource, &content)) {
-                int matchesCount = ContentSearchUtilities::countRegularExpressionMatches(regex, content);
</del><ins>+            if (auto textContent = InspectorNetworkAgent::textContentForCachedResource(*cachedResource)) {
+                int matchesCount = ContentSearchUtilities::countRegularExpressionMatches(regex, *textContent);
</ins><span class="cx">                 if (matchesCount)
</span><span class="cx">                     result->addItem(buildObjectForSearchResult(frameId(frame), cachedResource->url(), matchesCount));
</span><span class="cx">             }
</span><span class="cx">         }
</span><del>-
-        if (mainResourceContent(frame, false, &content)) {
-            int matchesCount = ContentSearchUtilities::countRegularExpressionMatches(regex, content);
-            if (matchesCount)
-                result->addItem(buildObjectForSearchResult(frameId(frame), frame->document()->url(), matchesCount));
-        }
</del><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     if (InspectorNetworkAgent* networkAgent = m_instrumentingAgents.inspectorNetworkAgent())
</span></span></pre></div>
<a id="trunkSourceWebCoreinspectoragentsInspectorPageAgenth"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/inspector/agents/InspectorPageAgent.h (225545 => 225546)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/inspector/agents/InspectorPageAgent.h       2017-12-05 22:09:04 UTC (rev 225545)
+++ trunk/Source/WebCore/inspector/agents/InspectorPageAgent.h  2017-12-05 22:09:36 UTC (rev 225546)
</span><span class="lines">@@ -50,7 +50,6 @@
</span><span class="cx"> class Page;
</span><span class="cx"> class RenderObject;
</span><span class="cx"> class SharedBuffer;
</span><del>-class TextResourceDecoder;
</del><span class="cx"> class URL;
</span><span class="cx"> 
</span><span class="cx"> typedef String ErrorString;
</span><span class="lines">@@ -75,7 +74,6 @@
</span><span class="cx">         OtherResource,
</span><span class="cx">     };
</span><span class="cx"> 
</span><del>-    static bool cachedResourceContent(CachedResource*, String* result, bool* base64Encoded);
</del><span class="cx">     static bool sharedBufferContent(RefPtr<SharedBuffer>&&, const String& textEncodingName, bool withBase64Encode, String* result);
</span><span class="cx">     static void resourceContent(ErrorString&, Frame*, const URL&, String* result, bool* base64Encoded);
</span><span class="cx">     static String sourceMapURLForResource(CachedResource*);
</span><span class="lines">@@ -85,7 +83,6 @@
</span><span class="cx">     static ResourceType inspectorResourceType(CachedResource::Type);
</span><span class="cx">     static ResourceType inspectorResourceType(const CachedResource&);
</span><span class="cx">     static Inspector::Protocol::Page::ResourceType cachedResourceTypeJSON(const CachedResource&);
</span><del>-    static RefPtr<TextResourceDecoder> createTextDecoder(const String& mimeType, const String& textEncodingName);
</del><span class="cx"> 
</span><span class="cx">     // Page API for InspectorFrontend
</span><span class="cx">     void enable(ErrorString&) override;
</span></span></pre></div>
<a id="trunkSourceWebCorexmlXMLHttpRequestcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/xml/XMLHttpRequest.cpp (225545 => 225546)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/xml/XMLHttpRequest.cpp      2017-12-05 22:09:04 UTC (rev 225545)
+++ trunk/Source/WebCore/xml/XMLHttpRequest.cpp 2017-12-05 22:09:36 UTC (rev 225546)
</span><span class="lines">@@ -925,7 +925,7 @@
</span><span class="cx">     networkError();
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void XMLHttpRequest::didFinishLoading(unsigned long identifier)
</del><ins>+void XMLHttpRequest::didFinishLoading(unsigned long)
</ins><span class="cx"> {
</span><span class="cx">     if (m_error)
</span><span class="cx">         return;
</span><span class="lines">@@ -938,11 +938,6 @@
</span><span class="cx"> 
</span><span class="cx">     m_responseBuilder.shrinkToFit();
</span><span class="cx"> 
</span><del>-    std::optional<String> decodedText;
-    if (!m_binaryResponseBuilder)
-        decodedText = m_responseBuilder.toStringPreserveCapacity();
-    InspectorInstrumentation::didFinishXHRLoading(scriptExecutionContext(), identifier, decodedText);
-
</del><span class="cx">     bool hadLoader = m_loader;
</span><span class="cx">     m_loader = nullptr;
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/ChangeLog (225545 => 225546)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/ChangeLog    2017-12-05 22:09:04 UTC (rev 225545)
+++ trunk/Source/WebInspectorUI/ChangeLog       2017-12-05 22:09:36 UTC (rev 225546)
</span><span class="lines">@@ -1,3 +1,40 @@
</span><ins>+2017-12-05  Joseph Pecoraro  <pecoraro@apple.com>
+
+        Web Inspector: content views for resources loaded through XHR do not reflect declared mime-type
+        https://bugs.webkit.org/show_bug.cgi?id=141389
+        <rdar://problem/19767070>
+
+        Reviewed by Brian Burg.
+
+        * UserInterface/Base/Utilities.js:
+        Blob <-> Text conversion helpers.
+
+        * UserInterface/Models/Resource.js:
+        (WI.Resource.prototype.createObjectURL):
+        Previously all Image resources were assumed to have base64Encoded data
+        which we automatically convert to a Blob. Now that some image data
+        can be transfered as text, convert that to a Blob here since the output
+        is expected to be a Blob.
+
+        * UserInterface/Views/ResourceContentView.js:
+        (WI.ResourceContentView.prototype.showGenericNoContentMessage):
+        * UserInterface/Views/TextResourceContentView.js:
+        (WI.TextResourceContentView.prototype.contentAvailable):
+        (WI.TextResourceContentView.prototype._contentDidPopulate):
+        * UserInterface/Views/ImageResourceContentView.js:
+        (WI.ImageResourceContentView.prototype.contentAvailable):
+        Better handle no content cases.
+
+        * UserInterface/Views/ResourceClusterContentView.js:
+        (WI.ResourceClusterContentView.prototype.get responseContentView):
+        (WI.ResourceClusterContentView.prototype._contentViewForResourceType):
+        Make a best effort to find a good ContentView to show the resource data.
+        This is done by looking at the ResourceType and MIME Type.
+
+        * UserInterface/Views/SVGImageResourceClusterContentView.js:
+        (WI.SVGImageResourceClusterContentView.prototype._showContentViewForIdentifier):
+        Handle if image data is now text (the image/svg+xml case).
+
</ins><span class="cx"> 2017-12-05  Simon Fraser  <simon.fraser@apple.com>
</span><span class="cx"> 
</span><span class="cx">         Remove webkitGetImageDataHD and webkitPutImageDataHD from canvas API
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceBaseUtilitiesjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Base/Utilities.js (225545 => 225546)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Base/Utilities.js      2017-12-05 22:09:04 UTC (rev 225545)
+++ trunk/Source/WebInspectorUI/UserInterface/Base/Utilities.js 2017-12-05 22:09:36 UTC (rev 225546)
</span><span class="lines">@@ -1594,6 +1594,19 @@
</span><span class="cx">     return new Blob(byteArrays, {type: mimeType});
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+function textToBlob(text, mimeType)
+{
+    return new Blob([text], {type: mimeType});
+}
+
+function blobAsText(blob, callback)
+{
+    console.assert(blob instanceof Blob);
+    let fileReader = new FileReader;
+    fileReader.addEventListener("loadend", () => { callback(fileReader.result); });
+    fileReader.readAsText(blob);
+}
+
</ins><span class="cx"> if (!window.handlePromiseException) {
</span><span class="cx">     window.handlePromiseException = function handlePromiseException(error)
</span><span class="cx">     {
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceModelsResourcejs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Models/Resource.js (225545 => 225546)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Models/Resource.js     2017-12-05 22:09:04 UTC (rev 225545)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/Resource.js        2017-12-05 22:09:36 UTC (rev 225546)
</span><span class="lines">@@ -380,6 +380,11 @@
</span><span class="cx">         if (content instanceof Blob)
</span><span class="cx">             return URL.createObjectURL(content);
</span><span class="cx"> 
</span><ins>+        if (typeof content === "string") {
+            let blob = textToBlob(content, this._mimeType);
+            return URL.createObjectURL(blob);
+        }
+
</ins><span class="cx">         return null;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -1129,7 +1134,6 @@
</span><span class="cx">     "text/xml": WI.Resource.Type.Document,
</span><span class="cx">     "text/plain": WI.Resource.Type.Document,
</span><span class="cx">     "application/xhtml+xml": WI.Resource.Type.Document,
</span><del>-    "image/svg+xml": WI.Resource.Type.Document,
</del><span class="cx"> 
</span><span class="cx">     "text/css": WI.Resource.Type.Stylesheet,
</span><span class="cx">     "text/xsl": WI.Resource.Type.Stylesheet,
</span><span class="lines">@@ -1138,6 +1142,7 @@
</span><span class="cx">     "text/x-scss": WI.Resource.Type.Stylesheet,
</span><span class="cx"> 
</span><span class="cx">     "application/pdf": WI.Resource.Type.Image,
</span><ins>+    "image/svg+xml": WI.Resource.Type.Image,
</ins><span class="cx"> 
</span><span class="cx">     "application/x-font-type1": WI.Resource.Type.Font,
</span><span class="cx">     "application/x-font-ttf": WI.Resource.Type.Font,
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsImageResourceContentViewjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Views/ImageResourceContentView.js (225545 => 225546)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/ImageResourceContentView.js      2017-12-05 22:09:04 UTC (rev 225545)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/ImageResourceContentView.js 2017-12-05 22:09:36 UTC (rev 225546)
</span><span class="lines">@@ -48,6 +48,13 @@
</span><span class="cx"> 
</span><span class="cx">     contentAvailable(content, base64Encoded)
</span><span class="cx">     {
</span><ins>+        this.removeLoadingIndicator();
+
+        if (!content) {
+            this.showGenericNoContentMessage();
+            return;
+        }
+
</ins><span class="cx">         let objectURL = this.resource.createObjectURL();
</span><span class="cx">         if (!objectURL) {
</span><span class="cx">             this.showGenericErrorMessage();
</span><span class="lines">@@ -54,8 +61,6 @@
</span><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        this.removeLoadingIndicator();
-
</del><span class="cx">         this._imageElement = document.createElement("img");
</span><span class="cx">         this._imageElement.addEventListener("load", function() { URL.revokeObjectURL(objectURL); });
</span><span class="cx">         this._imageElement.src = objectURL;
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsResourceClusterContentViewjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Views/ResourceClusterContentView.js (225545 => 225546)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/ResourceClusterContentView.js    2017-12-05 22:09:04 UTC (rev 225545)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/ResourceClusterContentView.js       2017-12-05 22:09:36 UTC (rev 225546)
</span><span class="lines">@@ -76,42 +76,21 @@
</span><span class="cx">         if (this._responseContentView)
</span><span class="cx">             return this._responseContentView;
</span><span class="cx"> 
</span><del>-        switch (this._resource.type) {
-        case WI.Resource.Type.Document:
-        case WI.Resource.Type.Script:
-        case WI.Resource.Type.Stylesheet:
-            this._responseContentView = new WI.TextResourceContentView(this._resource);
-            break;
</del><ins>+        this._responseContentView = this._contentViewForResourceType(this._resource.type);
+        if (this._responseContentView)
+            return this._responseContentView;
</ins><span class="cx"> 
</span><del>-        case WI.Resource.Type.XHR:
-        case WI.Resource.Type.Fetch:
-        case WI.Resource.Type.Ping:
-        case WI.Resource.Type.Beacon:
-            // FIXME: <https://webkit.org/b/165495> Web Inspector: XHR / Fetch for non-text content should not show garbled text
-            // The response content for these requests may not always be text.
</del><ins>+        let typeFromMIMEType = WI.Resource.typeFromMIMEType(this._resource.mimeType);
+        this._responseContentView = this._contentViewForResourceType(typeFromMIMEType);
+        if (this._responseContentView)
+            return this._responseContentView;
+
+        if (WI.shouldTreatMIMETypeAsText(this._resource.mimeType)) {
</ins><span class="cx">             this._responseContentView = new WI.TextResourceContentView(this._resource);
</span><del>-            break;
-
-        case WI.Resource.Type.Image:
-            if (this._resource.mimeTypeComponents.type === "image/svg+xml")
-                this._responseContentView = new WI.SVGImageResourceClusterContentView(this._resource);
-            else
-                this._responseContentView = new WI.ImageResourceContentView(this._resource);
-            break;
-
-        case WI.Resource.Type.Font:
-            this._responseContentView = new WI.FontResourceContentView(this._resource);
-            break;
-
-        case WI.Resource.Type.WebSocket:
-            this._responseContentView = new WI.WebSocketContentView(this._resource);
-            break;
-
-        default:
-            this._responseContentView = new WI.GenericResourceContentView(this._resource);
-            break;
</del><ins>+            return this._responseContentView;
</ins><span class="cx">         }
</span><span class="cx"> 
</span><ins>+        this._responseContentView = new WI.GenericResourceContentView(this._resource);
</ins><span class="cx">         return this._responseContentView;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -224,6 +203,30 @@
</span><span class="cx">         return !!this._customResponseContentViewConstructor;
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    _contentViewForResourceType(type)
+    {
+        switch (type) {
+        case WI.Resource.Type.Document:
+        case WI.Resource.Type.Script:
+        case WI.Resource.Type.Stylesheet:
+            return new WI.TextResourceContentView(this._resource);
+
+        case WI.Resource.Type.Image:
+            if (this._resource.mimeTypeComponents.type === "image/svg+xml")
+                return new WI.SVGImageResourceClusterContentView(this._resource);
+            return new WI.ImageResourceContentView(this._resource);
+
+        case WI.Resource.Type.Font:
+            return new WI.FontResourceContentView(this._resource);
+
+        case WI.Resource.Type.WebSocket:
+            return new WI.WebSocketContentView(this._resource);
+
+        default:
+            return null;
+        }
+    }
+
</ins><span class="cx">     _pathComponentForContentView(contentView)
</span><span class="cx">     {
</span><span class="cx">         console.assert(contentView);
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsResourceContentViewjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Views/ResourceContentView.js (225545 => 225546)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/ResourceContentView.js   2017-12-05 22:09:04 UTC (rev 225545)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/ResourceContentView.js      2017-12-05 22:09:36 UTC (rev 225546)
</span><span class="lines">@@ -81,6 +81,11 @@
</span><span class="cx">         throw WI.NotImplementedError.subclassMustOverride();
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    showGenericNoContentMessage()
+    {
+        this.showMessage(WI.UIString("Resource has no content"));
+    }
+
</ins><span class="cx">     showGenericErrorMessage()
</span><span class="cx">     {
</span><span class="cx">         this._contentError(WI.UIString("An error occurred trying to load the resource."));
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsSVGImageResourceClusterContentViewjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Views/SVGImageResourceClusterContentView.js (225545 => 225546)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/SVGImageResourceClusterContentView.js    2017-12-05 22:09:04 UTC (rev 225545)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/SVGImageResourceClusterContentView.js       2017-12-05 22:09:36 UTC (rev 225546)
</span><span class="lines">@@ -136,11 +136,14 @@
</span><span class="cx">             contentViewToShow = new WI.TextContentView("", this._resource.mimeType);
</span><span class="cx"> 
</span><span class="cx">             this._resource.requestContent().then((result) => {
</span><del>-                let fileReader = new FileReader;
-                fileReader.addEventListener("loadend", () => {
-                    contentViewToShow.textEditor.string = fileReader.result;
</del><ins>+                if (typeof result.content === "string") {
+                    contentViewToShow.textEditor.string = result.content;
+                    return;
+                }
+
+                blobAsText(result.content, (text) => {
+                    contentViewToShow.textEditor.string = text;
</ins><span class="cx">                 });
</span><del>-                fileReader.readAsText(result.content);
</del><span class="cx">             });
</span><span class="cx">             break;
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsTextResourceContentViewjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Views/TextResourceContentView.js (225545 => 225546)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/TextResourceContentView.js       2017-12-05 22:09:04 UTC (rev 225545)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/TextResourceContentView.js  2017-12-05 22:09:36 UTC (rev 225546)
</span><span class="lines">@@ -130,6 +130,11 @@
</span><span class="cx">         this._textEditor.close();
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    contentAvailable(content, base64Encoded)
+    {
+        // Do nothing.
+    }
+
</ins><span class="cx">     get supportsSave()
</span><span class="cx">     {
</span><span class="cx">         return super.supportsSave || this.resource instanceof WI.CSSStyleSheet;
</span><span class="lines">@@ -210,7 +215,7 @@
</span><span class="cx">         this._codeCoverageButtonNavigationItem.activated = WI.enableControlFlowProfilerSetting.value;
</span><span class="cx"> 
</span><span class="cx">         if (!this._textEditor.string)
</span><del>-            this.showMessage(WI.UIString("Resource has no content"));
</del><ins>+            this.showGenericNoContentMessage();
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     _togglePrettyPrint(event)
</span></span></pre>
</div>
</div>

</body>
</html>