Changeset 225546 in webkit


Ignore:
Timestamp:
Dec 5, 2017 2:09:36 PM (6 years ago)
Author:
commit-queue@webkit.org
Message:

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 <Joseph Pecoraro> 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.

Location:
trunk
Files:
23 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r225537 r225546  
     12017-12-05  Joseph Pecoraro  <pecoraro@apple.com>
     2
     3        Web Inspector: content views for resources loaded through XHR do not reflect declared mime-type
     4        https://bugs.webkit.org/show_bug.cgi?id=141389
     5        <rdar://problem/19767070>
     6
     7        Reviewed by Brian Burg.
     8
     9        * http/tests/inspector/network/fetch-response-body-expected.txt:
     10        * http/tests/inspector/network/fetch-response-body.html:
     11        * http/tests/inspector/network/xhr-response-body-expected.txt:
     12        * http/tests/inspector/network/xhr-response-body.html:
     13        Update tests for new expectations now that binary data shows as binary.       
     14
    1152017-12-05  Youenn Fablet  <youenn@apple.com>
    216
  • trunk/LayoutTests/http/tests/inspector/network/fetch-response-body-expected.txt

    r209629 r225546  
    66PASS: Resource should be Fetch type.
    77PASS: MIMEType should be 'text/plain'.
     8PASS: Content should not be base64Encoded.
    89PASS: Text content should match data.txt.
    910
     
    1112PASS: Resource should be Fetch type.
    1213PASS: MIMEType should be 'text/html'.
     14PASS: Content should not be base64Encoded.
    1315PASS: Text content should match data.html.
    1416
     
    1618PASS: Resource should be Fetch type.
    1719PASS: MIMEType should be 'application/octet-stream'.
     20PASS: Content should be base64Encoded.
    1821PASS: JSON content should match data.json.
    1922
     
    2124PASS: Resource should be Fetch type.
    2225PASS: MIMEType should be 'application/json'.
     26PASS: Content should not be base64Encoded.
    2327PASS: JSON content should match specified content.
    2428
     
    2630PASS: Resource should be Fetch type.
    2731PASS: MIMEType should be 'application/vnd.api+json'.
     32PASS: Content should not be base64Encoded.
    2833PASS: JSON content should match specified content.
    2934
     
    3136PASS: Resource should be Fetch type.
    3237PASS: MIMEType should be 'image/svg+xml'.
     38PASS: Content should not be base64Encoded.
    3339PASS: SVG content should be text.
    3440
     
    3642PASS: Resource should be Fetch type.
    3743PASS: MIMEType should be 'image/png'.
    38 PASS: Image content should be text.
     44PASS: Content should be base64Encoded.
     45PASS: Image content should be a Blob.
    3946
  • trunk/LayoutTests/http/tests/inspector/network/fetch-response-body.html

    r220119 r225546  
    3737    let suite = InspectorTest.createAsyncSuite("Network.getResponseBody.Fetch");
    3838
     39    function contentAsText(content) {
     40        return new Promise((resolve) => {
     41            if (typeof content === "string") {
     42                resolve(content)
     43                return;
     44            }
     45            blobAsText(content, (text) => {
     46                resolve(text);
     47            });
     48        });
     49    }
     50
    3951    function addTestCase({name, description, expression, contentHandler}) {
    4052        suite.addTestCase({
     
    5870        description: "Get text/plain content as text.",
    5971        expression: "createFetchForText()",
    60         contentHandler({error, sourceCode, content}) {
     72        contentHandler({error, sourceCode, content, rawBase64Encoded}) {
    6173            InspectorTest.expectEqual(sourceCode.mimeType, "text/plain", "MIMEType should be 'text/plain'.");
     74            InspectorTest.expectEqual(rawBase64Encoded, false, "Content should not be base64Encoded.");
    6275            InspectorTest.expectEqual(content, "Plain text resource.\n", "Text content should match data.txt.");
    6376        }
     
    6881        description: "Get text/html content as text.",
    6982        expression: "createFetchForHTML()",
    70         contentHandler({error, sourceCode, content}) {
     83        contentHandler({error, sourceCode, content, rawBase64Encoded}) {
    7184            InspectorTest.expectEqual(sourceCode.mimeType, "text/html", "MIMEType should be 'text/html'.");
     85            InspectorTest.expectEqual(rawBase64Encoded, false, "Content should not be base64Encoded.");
    7286            InspectorTest.expectEqual(content, "<span>Hello World</span>\n", "Text content should match data.html.");
    7387        }
     
    7690    addTestCase({
    7791        name: "Network.getResponseBody.Fetch.JSON",
    78         description: "Get application/octet-stream content as text.",
     92        description: "Get application/octet-stream content as base64Encoded text.",
    7993        expression: "createFetchForJSON()",
    80         contentHandler({error, sourceCode, content}) {
     94        contentHandler({error, sourceCode, content, rawBase64Encoded}) {
    8195            InspectorTest.expectEqual(sourceCode.mimeType, "application/octet-stream", "MIMEType should be 'application/octet-stream'.");
    82             InspectorTest.expectEqual(content, `{"json": true, "value": 42}\n`, "JSON content should match data.json.");
     96            InspectorTest.expectEqual(rawBase64Encoded, true, "Content should be base64Encoded.");
     97            return contentAsText(content).then((text) => {
     98                InspectorTest.expectEqual(text, `{"json": true, "value": 42}\n`, "JSON content should match data.json.");
     99            });
    83100        }
    84101    });
     
    88105        description: "Get application/json content as text.",
    89106        expression: "createFetchForJSON2()",
    90         contentHandler({error, sourceCode, content}) {
     107        contentHandler({error, sourceCode, content, rawBase64Encoded}) {
    91108            InspectorTest.expectEqual(sourceCode.mimeType, "application/json", "MIMEType should be 'application/json'.");
     109            InspectorTest.expectEqual(rawBase64Encoded, false, "Content should not be base64Encoded.");
    92110            InspectorTest.expectEqual(content, `{"json":true,"value":42}`, "JSON content should match specified content.");
    93111        }
     
    98116        description: "Get arbitrary +json content as text.",
    99117        expression: "createFetchForJSON3()",
    100         contentHandler({error, sourceCode, content}) {
     118        contentHandler({error, sourceCode, content, rawBase64Encoded}) {
    101119            InspectorTest.expectEqual(sourceCode.mimeType, "application/vnd.api+json", "MIMEType should be 'application/vnd.api+json'.");
     120            InspectorTest.expectEqual(rawBase64Encoded, false, "Content should not be base64Encoded.");
    102121            InspectorTest.expectEqual(content, `{"json":true,"value":999}`, "JSON content should match specified content.");
    103122        }
     
    108127        description: "Get image/svg+xml content as text.",
    109128        expression: "createFetchForSVG()",
    110         contentHandler({error, sourceCode, content}) {
     129        contentHandler({error, sourceCode, content, rawBase64Encoded}) {
    111130            InspectorTest.expectEqual(sourceCode.mimeType, "image/svg+xml", "MIMEType should be 'image/svg+xml'.");
     131            InspectorTest.expectEqual(rawBase64Encoded, false, "Content should not be base64Encoded.");
    112132            InspectorTest.expectEqual(content,
    113133`<?xml version="1.0" encoding="UTF-8"?>
     
    123143        description: "Get image/png content.",
    124144        expression: "createFetchForPNG()",
    125         contentHandler({error, sourceCode, content}) {
    126             // FIXME: <https://webkit.org/b/165495> Web Inspector: XHR / Fetch for non-text content should not show garbled text
     145        contentHandler({error, sourceCode, content, rawBase64Encoded}) {
    127146            InspectorTest.expectEqual(sourceCode.mimeType, "image/png", "MIMEType should be 'image/png'.");
    128             InspectorTest.expectEqual(typeof content, "string", "Image content should be text.");
     147            InspectorTest.expectEqual(rawBase64Encoded, true, "Content should be base64Encoded.");
     148            InspectorTest.expectThat(content instanceof Blob, "Image content should be a Blob.");
    129149        }
    130150    });
  • trunk/LayoutTests/http/tests/inspector/network/xhr-response-body-expected.txt

    r209629 r225546  
    66PASS: Resource should be XHR type.
    77PASS: MIMEType should be 'text/plain'.
     8PASS: Content should not be base64Encoded.
    89PASS: Text content should match data.txt.
    910
     
    1112PASS: Resource should be XHR type.
    1213PASS: MIMEType should be 'text/html'.
     14PASS: Content should not be base64Encoded.
    1315PASS: Text content should match data.html.
    1416
     
    1618PASS: Resource should be XHR type.
    1719PASS: MIMEType should be 'application/octet-stream'.
     20PASS: Content should be base64Encoded.
    1821PASS: JSON content should match data.json.
    1922
     
    2124PASS: Resource should be XHR type.
    2225PASS: MIMEType should be 'application/json'.
     26PASS: Content should not be base64Encoded.
    2327PASS: JSON content should match specified content.
    2428
     
    2630PASS: Resource should be XHR type.
    2731PASS: MIMEType should be 'application/vnd.api+json'.
     32PASS: Content should not be base64Encoded.
    2833PASS: JSON content should match specified content.
    2934
     
    3136PASS: Resource should be XHR type.
    3237PASS: MIMEType should be 'image/svg+xml'.
     38PASS: Content should not be base64Encoded.
    3339PASS: SVG content should be text.
    3440
     
    3642PASS: Resource should be XHR type.
    3743PASS: MIMEType should be 'image/png'.
    38 PASS: Image content should be text.
     44PASS: Content should be base64Encoded.
     45PASS: Image content should be a Blob.
    3946
  • trunk/LayoutTests/http/tests/inspector/network/xhr-response-body.html

    r220119 r225546  
    4343    let suite = InspectorTest.createAsyncSuite("Network.getResponseBody.XHR");
    4444
     45    function contentAsText(content) {
     46        return new Promise((resolve) => {
     47            if (typeof content === "string") {
     48                resolve(content)
     49                return;
     50            }
     51            blobAsText(content, (text) => {
     52                resolve(text);
     53            });
     54        });
     55    }
     56
    4557    function addTestCase({name, description, expression, contentHandler}) {
    4658        suite.addTestCase({
     
    6476        description: "Get text/plain content as text.",
    6577        expression: "createXHRForText()",
    66         contentHandler({error, sourceCode, content}) {
     78        contentHandler({error, sourceCode, content, rawBase64Encoded}) {
    6779            InspectorTest.expectEqual(sourceCode.mimeType, "text/plain", "MIMEType should be 'text/plain'.");
     80            InspectorTest.expectEqual(rawBase64Encoded, false, "Content should not be base64Encoded.");
    6881            InspectorTest.expectEqual(content, "Plain text resource.\n", "Text content should match data.txt.");
    6982        }
     
    7487        description: "Get text/html content as text.",
    7588        expression: "createXHRForHTML()",
    76         contentHandler({error, sourceCode, content}) {
     89        contentHandler({error, sourceCode, content, rawBase64Encoded}) {
    7790            InspectorTest.expectEqual(sourceCode.mimeType, "text/html", "MIMEType should be 'text/html'.");
     91            InspectorTest.expectEqual(rawBase64Encoded, false, "Content should not be base64Encoded.");
    7892            InspectorTest.expectEqual(content, "<span>Hello World</span>\n", "Text content should match data.html.");
    7993        }
     
    8296    addTestCase({
    8397        name: "Network.getResponseBody.XHR.JSON",
    84         description: "Get application/octet-stream content as text.",
     98        description: "Get application/octet-stream content as base64Encoded text.",
    8599        expression: "createXHRForJSON()",
    86         contentHandler({error, sourceCode, content}) {
     100        contentHandler({error, sourceCode, content, rawBase64Encoded}) {
    87101            InspectorTest.expectEqual(sourceCode.mimeType, "application/octet-stream", "MIMEType should be 'application/octet-stream'.");
    88             InspectorTest.expectEqual(content, `{"json": true, "value": 42}\n`, "JSON content should match data.json.");
     102            InspectorTest.expectEqual(rawBase64Encoded, true, "Content should be base64Encoded.");
     103            return contentAsText(content).then((text) => {
     104                InspectorTest.expectEqual(text, `{"json": true, "value": 42}\n`, "JSON content should match data.json.");
     105            });
    89106        }
    90107    });
     
    94111        description: "Get application/json content as text.",
    95112        expression: "createXHRForJSON2()",
    96         contentHandler({error, sourceCode, content}) {
     113        contentHandler({error, sourceCode, content, rawBase64Encoded}) {
    97114            InspectorTest.expectEqual(sourceCode.mimeType, "application/json", "MIMEType should be 'application/json'.");
     115            InspectorTest.expectEqual(rawBase64Encoded, false, "Content should not be base64Encoded.");
    98116            InspectorTest.expectEqual(content, `{"json":true,"value":42}`, "JSON content should match specified content.");
    99117        }
     
    104122        description: "Get arbitrary +json content as text.",
    105123        expression: "createXHRForJSON3()",
    106         contentHandler({error, sourceCode, content}) {
     124        contentHandler({error, sourceCode, content, rawBase64Encoded}) {
    107125            InspectorTest.expectEqual(sourceCode.mimeType, "application/vnd.api+json", "MIMEType should be 'application/vnd.api+json'.");
     126            InspectorTest.expectEqual(rawBase64Encoded, false, "Content should not be base64Encoded.");
    108127            InspectorTest.expectEqual(content, `{"json":true,"value":999}`, "JSON content should match specified content.");
    109128        }
     
    114133        description: "Get image/svg+xml content as text.",
    115134        expression: "createXHRForSVG()",
    116         contentHandler({error, sourceCode, content}) {
     135        contentHandler({error, sourceCode, content, rawBase64Encoded}) {
    117136            InspectorTest.expectEqual(sourceCode.mimeType, "image/svg+xml", "MIMEType should be 'image/svg+xml'.");
     137            InspectorTest.expectEqual(rawBase64Encoded, false, "Content should not be base64Encoded.");
    118138            InspectorTest.expectEqual(content,
    119139`<?xml version="1.0" encoding="UTF-8"?>
     
    129149        description: "Get image/png content.",
    130150        expression: "createXHRForPNG()",
    131         contentHandler({error, sourceCode, content}) {
    132             // FIXME: <https://webkit.org/b/165495> Web Inspector: XHR / Fetch for non-text content should not show garbled text
     151        contentHandler({error, sourceCode, content, rawBase64Encoded}) {
    133152            InspectorTest.expectEqual(sourceCode.mimeType, "image/png", "MIMEType should be 'image/png'.");
    134             InspectorTest.expectEqual(typeof content, "string", "Image content should be text.");
     153            InspectorTest.expectEqual(rawBase64Encoded, true, "Content should be base64Encoded.");
     154            InspectorTest.expectThat(content instanceof Blob, "Image content should be a Blob.");
    135155        }
    136156    });
  • trunk/Source/WebCore/ChangeLog

    r225537 r225546  
     12017-12-05  Joseph Pecoraro  <pecoraro@apple.com>
     2
     3        Web Inspector: content views for resources loaded through XHR do not reflect declared mime-type
     4        https://bugs.webkit.org/show_bug.cgi?id=141389
     5        <rdar://problem/19767070>
     6
     7        Reviewed by Brian Burg.
     8
     9        Updated: http/tests/inspector/network/xhr-response-body.html:
     10                 http/tests/inspector/network/fetch-response-body.html:
     11
     12        * xml/XMLHttpRequest.cpp:
     13        (WebCore::XMLHttpRequest::didFinishLoading):
     14        * inspector/InspectorInstrumentation.cpp:
     15        (WebCore::InspectorInstrumentation::didFinishXHRLoadingImpl): Deleted.
     16        * inspector/InspectorInstrumentation.h:
     17        (WebCore::InspectorInstrumentation::didFinishXHRLoading): Deleted.
     18        Remove special handling of XHR content that decoded output as text.
     19
     20        * inspector/NetworkResourcesData.h:
     21        (WebCore::NetworkResourcesData::ResourceData::requestId const):
     22        (WebCore::NetworkResourcesData::ResourceData::loaderId const):
     23        (WebCore::NetworkResourcesData::ResourceData::frameId const):
     24        (WebCore::NetworkResourcesData::ResourceData::url const):
     25        (WebCore::NetworkResourcesData::ResourceData::content const):
     26        (WebCore::NetworkResourcesData::ResourceData::isContentEvicted const):
     27        (WebCore::NetworkResourcesData::ResourceData::textEncodingName const):
     28        * inspector/NetworkResourcesData.cpp:
     29        (WebCore::NetworkResourcesData::ResourceData::ResourceData):
     30        (WebCore::NetworkResourcesData::ResourceData::decodeDataToContent):
     31        (WebCore::NetworkResourcesData::responseReceived):
     32        (WebCore::NetworkResourcesData::setResourceContent):
     33        (WebCore::shouldBufferResourceData):
     34        (WebCore::NetworkResourcesData::maybeAddResourceData):
     35        (WebCore::NetworkResourcesData::maybeDecodeDataToContent):
     36
     37        Make NetworkResourcesData only create a text decoder for resources we
     38        really think are text, and buffer resource data if it is text data
     39        or if it is a resource that would otherwise not be buffered by WebCore
     40        (such as XHRs with a DoNotBufferData policy). This ensures that the
     41        Inspector will have data to show for resources that won't be cached.
     42
     43        * inspector/agents/InspectorPageAgent.cpp:
     44        (WebCore::InspectorPageAgent::resourceContent):
     45        (WebCore::InspectorPageAgent::sourceMapURLForResource):
     46        (WebCore::InspectorPageAgent::searchInResource):
     47        (WebCore::InspectorPageAgent::searchInResources):
     48        (WebCore::hasTextContent): Deleted.
     49        (WebCore::InspectorPageAgent::cachedResourceContent): Deleted.
     50        (WebCore::InspectorPageAgent::createTextDecoder): Deleted.
     51        (WebCore::textContentForCachedResource): Deleted.
     52        * inspector/agents/InspectorPageAgent.h:
     53        * inspector/agents/InspectorNetworkAgent.cpp:
     54        (WebCore::InspectorNetworkAgent::didReceiveData):
     55        (WebCore::InspectorNetworkAgent::willDestroyCachedResource):
     56        (WebCore::InspectorNetworkAgent::getResponseBody):
     57        (WebCore::InspectorNetworkAgent::shouldTreatAsText):
     58        (WebCore::InspectorNetworkAgent::createTextDecoder):
     59        (WebCore::InspectorNetworkAgent::textContentForCachedResource):
     60        (WebCore::InspectorNetworkAgent::cachedResourceContent):
     61        (WebCore::textContentForResourceData):
     62        (WebCore::InspectorNetworkAgent::searchOtherRequests):
     63        (WebCore::isErrorStatusCode): Deleted.
     64        (WebCore::InspectorNetworkAgent::didFinishXHRLoading): Deleted.
     65        * inspector/agents/InspectorNetworkAgent.h:
     66        Move static PageAgent functions related to the generic data tuple
     67        (content, base64Encoded) to NetworkAgent. Also generalize it to
     68        not rely on the CachedResourceType, but instead rely on the MIME type.
     69        This has a few changes in behavior:
     70
     71            - Images, may now be text if they have a text mime type (image/svg+xml).
     72            - XHR / Fetch / Other may be sent as text if they have a text mime type.
     73            - XHR / Fetch / Other are not assumed to be text, and may be sent as base64 encoded.
     74       
     75        For this to be useful the frontend should also check the mime type and
     76        display an appropriate ContentView.
     77
    1782017-12-05  Youenn Fablet  <youenn@apple.com>
    279
  • trunk/Source/WebCore/inspector/InspectorInstrumentation.cpp

    r225488 r225546  
    618618}
    619619
    620 void InspectorInstrumentation::didFinishXHRLoadingImpl(InstrumentingAgents& instrumentingAgents, unsigned long identifier, std::optional<String> decodedText)
    621 {
    622     if (InspectorNetworkAgent* networkAgent = instrumentingAgents.inspectorNetworkAgent()) {
    623         if (decodedText)
    624             networkAgent->didFinishXHRLoading(identifier, *decodedText);
    625     }
    626 }
    627 
    628620void InspectorInstrumentation::willLoadXHRSynchronouslyImpl(InstrumentingAgents& instrumentingAgents)
    629621{
  • trunk/Source/WebCore/inspector/InspectorInstrumentation.h

    r225488 r225546  
    196196    static void continueWithPolicyDownload(Frame&, unsigned long identifier, DocumentLoader&, const ResourceResponse&);
    197197    static void continueWithPolicyIgnore(Frame&, unsigned long identifier, DocumentLoader&, const ResourceResponse&);
    198     static void didFinishXHRLoading(ScriptExecutionContext*, unsigned long identifier, std::optional<String> decodedText);
    199198    static void willLoadXHRSynchronously(ScriptExecutionContext*);
    200199    static void didLoadXHRSynchronously(ScriptExecutionContext*);
     
    367366    static void didFinishLoadingImpl(InstrumentingAgents&, unsigned long identifier, DocumentLoader*, const NetworkLoadMetrics&, ResourceLoader*);
    368367    static void didFailLoadingImpl(InstrumentingAgents&, unsigned long identifier, DocumentLoader*, const ResourceError&);
    369     static void didFinishXHRLoadingImpl(InstrumentingAgents&, unsigned long identifier, std::optional<String> decodedText);
    370368    static void willLoadXHRSynchronouslyImpl(InstrumentingAgents&);
    371369    static void didLoadXHRSynchronouslyImpl(InstrumentingAgents&);
     
    10121010}
    10131011
    1014 inline void InspectorInstrumentation::didFinishXHRLoading(ScriptExecutionContext* context, unsigned long identifier, std::optional<String> decodedText)
    1015 {
    1016     FAST_RETURN_IF_NO_FRONTENDS(void());
    1017     if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForContext(context))
    1018         didFinishXHRLoadingImpl(*instrumentingAgents, identifier, decodedText);
    1019 }
    1020 
    10211012inline void InspectorInstrumentation::willLoadXHRSynchronously(ScriptExecutionContext* context)
    10221013{
  • trunk/Source/WebCore/inspector/NetworkResourcesData.cpp

    r224596 r225546  
    11/*
    22 * Copyright (C) 2011 Google Inc. All rights reserved.
     3 * Copyright (C) 2017 Apple Inc.  All rights reserved.
    34 *
    45 * Redistribution and use in source and binary forms, with or without
     
    3132
    3233#include "CachedResource.h"
     34#include "InspectorNetworkAgent.h"
    3335#include "ResourceResponse.h"
    3436#include "SharedBuffer.h"
    3537#include "TextResourceDecoder.h"
     38#include <wtf/text/Base64.h>
    3639
    3740namespace WebCore {
     
    4548    : m_requestId(requestId)
    4649    , m_loaderId(loaderId)
    47     , m_base64Encoded(false)
    48     , m_isContentEvicted(false)
    49     , m_type(InspectorPageAgent::OtherResource)
    50     , m_cachedResource(nullptr)
    5150{
    5251}
     
    105104{
    106105    ASSERT(!hasContent());
     106
    107107    size_t dataLength = m_dataBuffer->size();
    108     m_content = m_decoder->decodeAndFlush(m_dataBuffer->data(), m_dataBuffer->size());
     108
     109    if (m_decoder) {
     110        m_base64Encoded = false;
     111        m_content = m_decoder->decodeAndFlush(m_dataBuffer->data(), dataLength);
     112    } else {
     113        m_base64Encoded = true;
     114        m_content = base64Encode(m_dataBuffer->data(), dataLength);
     115    }
     116
    109117    m_dataBuffer = nullptr;
    110     return contentSizeInBytes(m_content) - dataLength;
     118
     119    size_t decodedLength = contentSizeInBytes(m_content);
     120    ASSERT(decodedLength >= dataLength);
     121    return decodedLength - dataLength;
    111122}
    112123
     
    145156    if (!resourceData)
    146157        return;
     158
    147159    resourceData->setFrameId(frameId);
    148160    resourceData->setURL(response.url());
    149     resourceData->setDecoder(InspectorPageAgent::createTextDecoder(response.mimeType(), response.textEncodingName()));
    150161    resourceData->setHTTPStatusCode(response.httpStatusCode());
    151162    resourceData->setType(type);
     163
     164    if (InspectorNetworkAgent::shouldTreatAsText(response.mimeType()))
     165        resourceData->setDecoder(InspectorNetworkAgent::createTextDecoder(response.mimeType(), response.textEncodingName()));
    152166}
    153167
     
    173187    if (!resourceData)
    174188        return;
     189
    175190    size_t dataLength = contentSizeInBytes(content);
    176191    if (dataLength > m_maximumSingleResourceContentSize)
     
    178193    if (resourceData->isContentEvicted())
    179194        return;
     195
    180196    if (ensureFreeSpace(dataLength) && !resourceData->isContentEvicted()) {
    181197        // We can not be sure that we didn't try to save this request data while it was loading, so remove it, if any.
     
    188204}
    189205
     206static bool shouldBufferResourceData(const NetworkResourcesData::ResourceData& resourceData)
     207{
     208    if (resourceData.decoder())
     209        return true;
     210
     211    // Buffer data for Web Inspector when the rest of the system would not normally buffer.
     212    if (resourceData.cachedResource() && resourceData.cachedResource()->dataBufferingPolicy() == DoNotBufferData)
     213        return true;
     214
     215    return false;
     216}
     217
    190218void NetworkResourcesData::maybeAddResourceData(const String& requestId, const char* data, size_t dataLength)
    191219{
     
    193221    if (!resourceData)
    194222        return;
    195     if (!resourceData->decoder())
    196         return;
     223
     224    if (!shouldBufferResourceData(*resourceData))
     225        return;
     226
    197227    if (resourceData->dataLength() + dataLength > m_maximumSingleResourceContentSize)
    198228        m_contentSize -= resourceData->evictContent();
    199229    if (resourceData->isContentEvicted())
    200230        return;
     231
    201232    if (ensureFreeSpace(dataLength) && !resourceData->isContentEvicted()) {
    202233        m_requestIdsDeque.append(requestId);
     
    211242    if (!resourceData)
    212243        return;
     244
    213245    if (!resourceData->hasData())
    214246        return;
     247
    215248    m_contentSize += resourceData->decodeDataToContent();
    216249    size_t dataLength = contentSizeInBytes(resourceData->content());
  • trunk/Source/WebCore/inspector/NetworkResourcesData.h

    r224596 r225546  
    11/*
    22 * Copyright (C) 2011 Google Inc. All rights reserved.
     3 * Copyright (C) 2017 Apple Inc.  All rights reserved.
    34 *
    45 * Redistribution and use in source and binary forms, with or without
     
    3031
    3132#include "InspectorPageAgent.h"
    32 #include "TextResourceDecoder.h"
    3333#include <wtf/Deque.h>
    3434#include <wtf/HashMap.h>
     
    3939class CachedResource;
    4040class ResourceResponse;
     41class TextResourceDecoder;
    4142class SharedBuffer;
    4243
     
    5051        ResourceData(const String& requestId, const String& loaderId);
    5152
    52         String requestId() const { return m_requestId; }
    53         String loaderId() const { return m_loaderId; }
     53        const String& requestId() const { return m_requestId; }
     54        const String& loaderId() const { return m_loaderId; }
    5455
    55         String frameId() const { return m_frameId; }
     56        const String& frameId() const { return m_frameId; }
    5657        void setFrameId(const String& frameId) { m_frameId = frameId; }
    5758
    58         String url() const { return m_url; }
     59        const String& url() const { return m_url; }
    5960        void setURL(const String& url) { m_url = url; }
    6061
    6162        bool hasContent() const { return !m_content.isNull(); }
    62         String content() const { return m_content; }
     63        const String& content() const { return m_content; }
    6364        void setContent(const String&, bool base64Encoded);
    6465
     
    6667
    6768        unsigned removeContent();
     69        unsigned evictContent();
    6870        bool isContentEvicted() const { return m_isContentEvicted; }
    69         unsigned evictContent();
    7071
    7172        InspectorPageAgent::ResourceType type() const { return m_type; }
     
    7576        void setHTTPStatusCode(int httpStatusCode) { m_httpStatusCode = httpStatusCode; }
    7677
    77         String textEncodingName() const { return m_textEncodingName; }
     78        const String& textEncodingName() const { return m_textEncodingName; }
    7879        void setTextEncodingName(const String& textEncodingName) { m_textEncodingName = textEncodingName; }
    7980
     
    9899        String m_url;
    99100        String m_content;
    100         bool m_base64Encoded;
    101         RefPtr<SharedBuffer> m_dataBuffer;
    102         bool m_isContentEvicted;
    103         InspectorPageAgent::ResourceType m_type;
    104         int m_httpStatusCode;
    105 
    106101        String m_textEncodingName;
    107102        RefPtr<TextResourceDecoder> m_decoder;
    108 
     103        RefPtr<SharedBuffer> m_dataBuffer;
    109104        RefPtr<SharedBuffer> m_buffer;
    110         CachedResource* m_cachedResource;
     105        CachedResource* m_cachedResource { nullptr };
     106        InspectorPageAgent::ResourceType m_type { InspectorPageAgent::OtherResource };
     107        int m_httpStatusCode { 0 };
     108        bool m_isContentEvicted { false };
     109        bool m_base64Encoded { false };
    111110    };
    112111
  • trunk/Source/WebCore/inspector/agents/InspectorNetworkAgent.cpp

    r225425 r225546  
    3333#include "InspectorNetworkAgent.h"
    3434
     35#include "CachedCSSStyleSheet.h"
    3536#include "CachedRawResource.h"
    3637#include "CachedResource.h"
    3738#include "CachedResourceLoader.h"
    3839#include "CachedResourceRequestInitiators.h"
     40#include "CachedScript.h"
    3941#include "Document.h"
    4042#include "DocumentLoader.h"
     
    4850#include "JSMainThreadExecState.h"
    4951#include "JSWebSocket.h"
     52#include "MIMETypeRegistry.h"
    5053#include "MemoryCache.h"
    5154#include "NetworkResourcesData.h"
     
    5962#include "ScriptableDocumentParser.h"
    6063#include "SubresourceLoader.h"
     64#include "TextResourceDecoder.h"
    6165#include "ThreadableLoaderClient.h"
    6266#include "URL.h"
     
    6872#include <inspector/InjectedScript.h>
    6973#include <inspector/InjectedScriptManager.h>
    70 #include <inspector/InspectorFrontendRouter.h>
    7174#include <inspector/ScriptCallStack.h>
    7275#include <inspector/ScriptCallStackFactory.h>
     
    7679#include <wtf/RefPtr.h>
    7780#include <wtf/Stopwatch.h>
     81#include <wtf/text/Base64.h>
    7882#include <wtf/text/StringBuilder.h>
    7983
     
    457461}
    458462
    459 static bool isErrorStatusCode(int statusCode)
    460 {
    461     return statusCode >= 400;
    462 }
    463 
    464463void InspectorNetworkAgent::didReceiveData(unsigned long identifier, const char* data, int dataLength, int encodedDataLength)
    465464{
     
    471470    if (data) {
    472471        NetworkResourcesData::ResourceData const* resourceData = m_resourcesData->data(requestId);
    473         if (resourceData && !m_loadingXHRSynchronously && (!resourceData->cachedResource() || resourceData->cachedResource()->dataBufferingPolicy() == DoNotBufferData || isErrorStatusCode(resourceData->httpStatusCode())))
     472        if (resourceData && !m_loadingXHRSynchronously)
    474473            m_resourcesData->maybeAddResourceData(requestId, data, dataLength);
    475474    }
     
    568567}
    569568
    570 void InspectorNetworkAgent::didFinishXHRLoading(unsigned long identifier, const String& decodedText)
    571 {
    572     m_resourcesData->setResourceContent(IdentifiersFactory::requestId(identifier), decodedText);
    573 }
    574 
    575569void InspectorNetworkAgent::willLoadXHRSynchronously()
    576570{
     
    591585    String content;
    592586    bool base64Encoded;
    593     if (!InspectorPageAgent::cachedResourceContent(&cachedResource, &content, &base64Encoded))
    594         return;
     587    if (!InspectorNetworkAgent::cachedResourceContent(cachedResource, &content, &base64Encoded))
     588        return;
     589
    595590    for (auto& id : requestIds)
    596591        m_resourcesData->setResourceContent(id, content, base64Encoded);
     
    779774
    780775    if (resourceData->cachedResource()) {
    781         if (InspectorPageAgent::cachedResourceContent(resourceData->cachedResource(), content, base64Encoded))
     776        if (InspectorNetworkAgent::cachedResourceContent(*resourceData->cachedResource(), content, base64Encoded))
    782777            return;
    783778    }
     
    867862    String objectGroupName = objectGroup ? *objectGroup : String();
    868863    result = injectedScript.wrapObject(webSocketAsScriptValue(state, webSocket), objectGroupName);
     864}
     865
     866bool InspectorNetworkAgent::shouldTreatAsText(const String& mimeType)
     867{
     868    return startsWithLettersIgnoringASCIICase(mimeType, "text/")
     869        || MIMETypeRegistry::isSupportedJavaScriptMIMEType(mimeType)
     870        || MIMETypeRegistry::isSupportedJSONMIMEType(mimeType)
     871        || MIMETypeRegistry::isXMLMIMEType(mimeType);
     872}
     873
     874Ref<TextResourceDecoder> InspectorNetworkAgent::createTextDecoder(const String& mimeType, const String& textEncodingName)
     875{
     876    if (!textEncodingName.isEmpty())
     877        return TextResourceDecoder::create(ASCIILiteral("text/plain"), textEncodingName);
     878
     879    if (MIMETypeRegistry::isTextMIMEType(mimeType))
     880        return TextResourceDecoder::create(mimeType, "UTF-8");
     881    if (MIMETypeRegistry::isXMLMIMEType(mimeType)) {
     882        auto decoder = TextResourceDecoder::create(ASCIILiteral("application/xml"));
     883        decoder->useLenientXMLDecoding();
     884        return decoder;
     885    }
     886
     887    return TextResourceDecoder::create(ASCIILiteral("text/plain"), "UTF-8");
     888}
     889
     890std::optional<String> InspectorNetworkAgent::textContentForCachedResource(CachedResource& cachedResource)
     891{
     892    if (!InspectorNetworkAgent::shouldTreatAsText(cachedResource.mimeType()))
     893        return std::nullopt;
     894
     895    String result;
     896    bool base64Encoded;
     897    if (InspectorNetworkAgent::cachedResourceContent(cachedResource, &result, &base64Encoded)) {
     898        ASSERT(!base64Encoded);
     899        return result;
     900    }
     901
     902    return std::nullopt;
     903}
     904
     905bool InspectorNetworkAgent::cachedResourceContent(CachedResource& resource, String* result, bool* base64Encoded)
     906{
     907    ASSERT(result);
     908    ASSERT(base64Encoded);
     909
     910    if (!resource.encodedSize()) {
     911        *base64Encoded = false;
     912        *result = String();
     913        return true;
     914    }
     915
     916    switch (resource.type()) {
     917    case CachedResource::CSSStyleSheet:
     918        *base64Encoded = false;
     919        *result = downcast<CachedCSSStyleSheet>(resource).sheetText();
     920        // The above can return a null String if the MIME type is invalid.
     921        return !result->isNull();
     922    case CachedResource::Script:
     923        *base64Encoded = false;
     924        *result = downcast<CachedScript>(resource).script().toString();
     925        return true;
     926    default:
     927        auto* buffer = resource.resourceBuffer();
     928        if (!buffer)
     929            return false;
     930
     931        if (InspectorNetworkAgent::shouldTreatAsText(resource.mimeType())) {
     932            auto decoder = InspectorNetworkAgent::createTextDecoder(resource.mimeType(), resource.response().textEncodingName());
     933            *base64Encoded = false;
     934            *result = decoder->decodeAndFlush(buffer->data(), buffer->size());
     935            return true;
     936        }
     937
     938        *base64Encoded = true;
     939        *result = base64Encode(buffer->data(), buffer->size());
     940        return true;
     941    }
    869942}
    870943
     
    880953}
    881954
     955static std::optional<String> textContentForResourceData(const NetworkResourcesData::ResourceData& resourceData)
     956{
     957    if (resourceData.hasContent() && !resourceData.base64Encoded())
     958        return resourceData.content();
     959
     960    if (resourceData.cachedResource())
     961        return InspectorNetworkAgent::textContentForCachedResource(*resourceData.cachedResource());
     962
     963    return std::nullopt;
     964}
     965
    882966void InspectorNetworkAgent::searchOtherRequests(const JSC::Yarr::RegularExpression& regex, RefPtr<JSON::ArrayOf<Inspector::Protocol::Page::SearchResult>>& result)
    883967{
    884968    Vector<NetworkResourcesData::ResourceData*> resources = m_resourcesData->resources();
    885969    for (auto* resourceData : resources) {
    886         if (resourceData->hasContent()) {
     970        if (auto textContent = textContentForResourceData(*resourceData)) {
    887971            int matchesCount = ContentSearchUtilities::countRegularExpressionMatches(regex, resourceData->content());
    888972            if (matchesCount)
  • trunk/Source/WebCore/inspector/agents/InspectorNetworkAgent.h

    r225425 r225546  
    5858class ResourceRequest;
    5959class ResourceResponse;
     60class TextResourceDecoder;
    6061class URL;
    6162class WebSocket;
     
    7172    explicit InspectorNetworkAgent(WebAgentContext&);
    7273    virtual ~InspectorNetworkAgent();
     74
     75    static bool shouldTreatAsText(const String& mimeType);
     76    static Ref<TextResourceDecoder> createTextDecoder(const String& mimeType, const String& textEncodingName);
     77    static std::optional<String> textContentForCachedResource(CachedResource&);
     78    static bool cachedResourceContent(CachedResource&, String* result, bool* base64Encoded);
    7379
    7480    void didCreateFrontendAndBackend(Inspector::FrontendRouter*, Inspector::BackendDispatcher*) override;
     
    8692    void didLoadResourceFromMemoryCache(DocumentLoader*, CachedResource&);
    8793    void didReceiveThreadableLoaderResponse(unsigned long identifier, DocumentThreadableLoader&);
    88     void didFinishXHRLoading(unsigned long identifier, const String& decodedText);
    8994    void willLoadXHRSynchronously();
    9095    void didLoadXHRSynchronously();
     
    104109    void searchOtherRequests(const JSC::Yarr::RegularExpression&, RefPtr<JSON::ArrayOf<Inspector::Protocol::Page::SearchResult>>&);
    105110    void searchInRequest(ErrorString&, const String& requestId, const String& query, bool caseSensitive, bool isRegex, RefPtr<JSON::ArrayOf<Inspector::Protocol::GenericTypes::SearchMatch>>&);
    106 
    107     RefPtr<Inspector::Protocol::Network::Initiator> buildInitiatorObject(Document*);
    108111
    109112    // Called from frontend.
     
    129132    WebSocket* webSocketForRequestId(const String& requestId);
    130133
     134    RefPtr<Inspector::Protocol::Network::Initiator> buildInitiatorObject(Document*);
    131135    Ref<Inspector::Protocol::Network::ResourceTiming> buildObjectForTiming(const NetworkLoadMetrics&, ResourceLoader&);
    132136    Ref<Inspector::Protocol::Network::Metrics> buildObjectForMetrics(const NetworkLoadMetrics&);
  • trunk/Source/WebCore/inspector/agents/InspectorPageAgent.cpp

    r225425 r225546  
    3333#include "InspectorPageAgent.h"
    3434
    35 #include "CachedCSSStyleSheet.h"
    36 #include "CachedFont.h"
    37 #include "CachedImage.h"
    3835#include "CachedResource.h"
    3936#include "CachedResourceLoader.h"
    40 #include "CachedScript.h"
    4137#include "Cookie.h"
    4238#include "CookieJar.h"
     
    6662#include "StyleScope.h"
    6763#include "TextEncoding.h"
    68 #include "TextResourceDecoder.h"
    6964#include "UserGestureIndicator.h"
    7065#include <inspector/ContentSearchUtilities.h>
     
    9792}
    9893
    99 static bool hasTextContent(CachedResource* cachedResource)
    100 {
    101     // FIXME: <https://webkit.org/b/165495> Web Inspector: XHR / Fetch for non-text content should not show garbled text
    102     // We should not assume XHR / Fetch have text content.
    103 
    104     InspectorPageAgent::ResourceType type = InspectorPageAgent::inspectorResourceType(*cachedResource);
    105     return type == InspectorPageAgent::DocumentResource
    106         || type == InspectorPageAgent::StylesheetResource
    107         || type == InspectorPageAgent::ScriptResource
    108         || type == InspectorPageAgent::XHRResource
    109         || type == InspectorPageAgent::FetchResource;
    110 }
    111 
    112 bool InspectorPageAgent::cachedResourceContent(CachedResource* cachedResource, String* result, bool* base64Encoded)
    113 {
    114     if (!cachedResource)
    115         return false;
    116 
    117     *base64Encoded = !hasTextContent(cachedResource);
    118 
    119     if (!cachedResource->encodedSize()) {
    120         *result = emptyString();
    121         return true;
    122     }
    123 
    124     if (*base64Encoded) {
    125         if (auto* buffer = cachedResource->resourceBuffer()) {
    126             *result = base64Encode(buffer->data(), buffer->size());
    127             return true;
    128         }
    129         return false;
    130     }
    131 
    132     if (cachedResource) {
    133         switch (cachedResource->type()) {
    134         case CachedResource::CSSStyleSheet:
    135             // This can return a null String if the MIME type is invalid.
    136             *result = downcast<CachedCSSStyleSheet>(*cachedResource).sheetText();
    137             return !result->isNull();
    138         case CachedResource::Script:
    139             *result = downcast<CachedScript>(*cachedResource).script().toString();
    140             return true;
    141         case CachedResource::MediaResource:
    142         case CachedResource::Icon:
    143         case CachedResource::RawResource: {
    144             auto* buffer = cachedResource->resourceBuffer();
    145             if (!buffer)
    146                 return false;
    147             RefPtr<TextResourceDecoder> decoder = InspectorPageAgent::createTextDecoder(cachedResource->response().mimeType(), cachedResource->response().textEncodingName());
    148             // We show content for raw resources only for certain mime types (text, html and xml). Otherwise decoder will be null.
    149             if (!decoder)
    150                 return false;
    151             *result = decoder->decodeAndFlush(buffer->data(), buffer->size());
    152             return true;
    153         }
    154         default:
    155             auto* buffer = cachedResource->resourceBuffer();
    156             return decodeBuffer(buffer ? buffer->data() : nullptr, buffer ? buffer->size() : 0, cachedResource->encoding(), result);
    157         }
    158     }
    159     return false;
    160 }
    161 
    16294bool InspectorPageAgent::mainResourceContent(Frame* frame, bool withBase64Encode, String* result)
    16395{
     
    196128    }
    197129
    198     if (!success)
    199         success = cachedResourceContent(cachedResource(frame, url), result, base64Encoded);
     130    if (!success) {
     131        if (auto* resource = cachedResource(frame, url))
     132            success = InspectorNetworkAgent::cachedResourceContent(*resource, result, base64Encoded);
     133    }
    200134
    201135    if (!success)
     
    203137}
    204138
    205 //static
    206139String InspectorPageAgent::sourceMapURLForResource(CachedResource* cachedResource)
    207140{
     
    226159    String content;
    227160    bool base64Encoded;
    228     if (InspectorPageAgent::cachedResourceContent(cachedResource, &content, &base64Encoded) && !base64Encoded)
     161    if (InspectorNetworkAgent::cachedResourceContent(*cachedResource, &content, &base64Encoded) && !base64Encoded)
    229162        return ContentSearchUtilities::findStylesheetSourceMapURL(content);
    230163
     
    326259}
    327260
    328 RefPtr<TextResourceDecoder> InspectorPageAgent::createTextDecoder(const String& mimeType, const String& textEncodingName)
    329 {
    330     if (!textEncodingName.isEmpty())
    331         return TextResourceDecoder::create(ASCIILiteral("text/plain"), textEncodingName);
    332 
    333     if (MIMETypeRegistry::isTextMIMEType(mimeType))
    334         return TextResourceDecoder::create(mimeType, "UTF-8");
    335 
    336     if (MIMETypeRegistry::isXMLMIMEType(mimeType)) {
    337         RefPtr<TextResourceDecoder> decoder = TextResourceDecoder::create(ASCIILiteral("application/xml"));
    338         decoder->useLenientXMLDecoding();
    339         return decoder;
    340     }
    341 
    342     return TextResourceDecoder::create(ASCIILiteral("text/plain"), "UTF-8");
    343 }
    344 
    345261InspectorPageAgent::InspectorPageAgent(PageAgentContext& context, InspectorClient* client, InspectorOverlay* overlay)
    346262    : InspectorAgentBase(ASCIILiteral("Page"), context)
     
    544460}
    545461
    546 static bool textContentForCachedResource(CachedResource* cachedResource, String* result)
    547 {
    548     if (hasTextContent(cachedResource)) {
    549         bool base64Encoded;
    550         if (InspectorPageAgent::cachedResourceContent(cachedResource, result, &base64Encoded)) {
    551             ASSERT(!base64Encoded);
    552             return true;
    553         }
    554     }
    555     return false;
    556 }
    557 
    558462void 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)
    559463{
     
    586490
    587491    if (!success) {
    588         CachedResource* resource = cachedResource(frame, kurl);
    589         if (resource)
    590             success = textContentForCachedResource(resource, &content);
     492        if (auto* resource = cachedResource(frame, kurl)) {
     493            if (auto textContent = InspectorNetworkAgent::textContentForCachedResource(*resource)) {
     494                content = *textContent;
     495                success = true;
     496            }
     497        }
    591498    }
    592499
     
    615522
    616523    for (Frame* frame = &m_page.mainFrame(); frame; frame = frame->tree().traverseNext()) {
    617         String content;
    618 
    619524        for (auto* cachedResource : cachedResourcesForFrame(frame)) {
    620             if (textContentForCachedResource(cachedResource, &content)) {
    621                 int matchesCount = ContentSearchUtilities::countRegularExpressionMatches(regex, content);
     525            if (auto textContent = InspectorNetworkAgent::textContentForCachedResource(*cachedResource)) {
     526                int matchesCount = ContentSearchUtilities::countRegularExpressionMatches(regex, *textContent);
    622527                if (matchesCount)
    623528                    result->addItem(buildObjectForSearchResult(frameId(frame), cachedResource->url(), matchesCount));
    624529            }
    625         }
    626 
    627         if (mainResourceContent(frame, false, &content)) {
    628             int matchesCount = ContentSearchUtilities::countRegularExpressionMatches(regex, content);
    629             if (matchesCount)
    630                 result->addItem(buildObjectForSearchResult(frameId(frame), frame->document()->url(), matchesCount));
    631530        }
    632531    }
  • trunk/Source/WebCore/inspector/agents/InspectorPageAgent.h

    r225425 r225546  
    5151class RenderObject;
    5252class SharedBuffer;
    53 class TextResourceDecoder;
    5453class URL;
    5554
     
    7675    };
    7776
    78     static bool cachedResourceContent(CachedResource*, String* result, bool* base64Encoded);
    7977    static bool sharedBufferContent(RefPtr<SharedBuffer>&&, const String& textEncodingName, bool withBase64Encode, String* result);
    8078    static void resourceContent(ErrorString&, Frame*, const URL&, String* result, bool* base64Encoded);
     
    8684    static ResourceType inspectorResourceType(const CachedResource&);
    8785    static Inspector::Protocol::Page::ResourceType cachedResourceTypeJSON(const CachedResource&);
    88     static RefPtr<TextResourceDecoder> createTextDecoder(const String& mimeType, const String& textEncodingName);
    8986
    9087    // Page API for InspectorFrontend
  • trunk/Source/WebCore/xml/XMLHttpRequest.cpp

    r224299 r225546  
    926926}
    927927
    928 void XMLHttpRequest::didFinishLoading(unsigned long identifier)
     928void XMLHttpRequest::didFinishLoading(unsigned long)
    929929{
    930930    if (m_error)
     
    938938
    939939    m_responseBuilder.shrinkToFit();
    940 
    941     std::optional<String> decodedText;
    942     if (!m_binaryResponseBuilder)
    943         decodedText = m_responseBuilder.toStringPreserveCapacity();
    944     InspectorInstrumentation::didFinishXHRLoading(scriptExecutionContext(), identifier, decodedText);
    945940
    946941    bool hadLoader = m_loader;
  • trunk/Source/WebInspectorUI/ChangeLog

    r225527 r225546  
     12017-12-05  Joseph Pecoraro  <pecoraro@apple.com>
     2
     3        Web Inspector: content views for resources loaded through XHR do not reflect declared mime-type
     4        https://bugs.webkit.org/show_bug.cgi?id=141389
     5        <rdar://problem/19767070>
     6
     7        Reviewed by Brian Burg.
     8
     9        * UserInterface/Base/Utilities.js:
     10        Blob <-> Text conversion helpers.
     11
     12        * UserInterface/Models/Resource.js:
     13        (WI.Resource.prototype.createObjectURL):
     14        Previously all Image resources were assumed to have base64Encoded data
     15        which we automatically convert to a Blob. Now that some image data
     16        can be transfered as text, convert that to a Blob here since the output
     17        is expected to be a Blob.
     18
     19        * UserInterface/Views/ResourceContentView.js:
     20        (WI.ResourceContentView.prototype.showGenericNoContentMessage):
     21        * UserInterface/Views/TextResourceContentView.js:
     22        (WI.TextResourceContentView.prototype.contentAvailable):
     23        (WI.TextResourceContentView.prototype._contentDidPopulate):
     24        * UserInterface/Views/ImageResourceContentView.js:
     25        (WI.ImageResourceContentView.prototype.contentAvailable):
     26        Better handle no content cases.
     27
     28        * UserInterface/Views/ResourceClusterContentView.js:
     29        (WI.ResourceClusterContentView.prototype.get responseContentView):
     30        (WI.ResourceClusterContentView.prototype._contentViewForResourceType):
     31        Make a best effort to find a good ContentView to show the resource data.
     32        This is done by looking at the ResourceType and MIME Type.
     33
     34        * UserInterface/Views/SVGImageResourceClusterContentView.js:
     35        (WI.SVGImageResourceClusterContentView.prototype._showContentViewForIdentifier):
     36        Handle if image data is now text (the image/svg+xml case).
     37
    1382017-12-05  Simon Fraser  <simon.fraser@apple.com>
    239
  • trunk/Source/WebInspectorUI/UserInterface/Base/Utilities.js

    r223308 r225546  
    15951595}
    15961596
     1597function textToBlob(text, mimeType)
     1598{
     1599    return new Blob([text], {type: mimeType});
     1600}
     1601
     1602function blobAsText(blob, callback)
     1603{
     1604    console.assert(blob instanceof Blob);
     1605    let fileReader = new FileReader;
     1606    fileReader.addEventListener("loadend", () => { callback(fileReader.result); });
     1607    fileReader.readAsText(blob);
     1608}
     1609
    15971610if (!window.handlePromiseException) {
    15981611    window.handlePromiseException = function handlePromiseException(error)
  • trunk/Source/WebInspectorUI/UserInterface/Models/Resource.js

    r225244 r225546  
    381381            return URL.createObjectURL(content);
    382382
     383        if (typeof content === "string") {
     384            let blob = textToBlob(content, this._mimeType);
     385            return URL.createObjectURL(blob);
     386        }
     387
    383388        return null;
    384389    }
     
    11301135    "text/plain": WI.Resource.Type.Document,
    11311136    "application/xhtml+xml": WI.Resource.Type.Document,
    1132     "image/svg+xml": WI.Resource.Type.Document,
    11331137
    11341138    "text/css": WI.Resource.Type.Stylesheet,
     
    11391143
    11401144    "application/pdf": WI.Resource.Type.Image,
     1145    "image/svg+xml": WI.Resource.Type.Image,
    11411146
    11421147    "application/x-font-type1": WI.Resource.Type.Font,
  • trunk/Source/WebInspectorUI/UserInterface/Views/ImageResourceContentView.js

    r221338 r225546  
    4949    contentAvailable(content, base64Encoded)
    5050    {
     51        this.removeLoadingIndicator();
     52
     53        if (!content) {
     54            this.showGenericNoContentMessage();
     55            return;
     56        }
     57
    5158        let objectURL = this.resource.createObjectURL();
    5259        if (!objectURL) {
     
    5461            return;
    5562        }
    56 
    57         this.removeLoadingIndicator();
    5863
    5964        this._imageElement = document.createElement("img");
  • trunk/Source/WebInspectorUI/UserInterface/Views/ResourceClusterContentView.js

    r224767 r225546  
    7777            return this._responseContentView;
    7878
    79         switch (this._resource.type) {
    80         case WI.Resource.Type.Document:
    81         case WI.Resource.Type.Script:
    82         case WI.Resource.Type.Stylesheet:
     79        this._responseContentView = this._contentViewForResourceType(this._resource.type);
     80        if (this._responseContentView)
     81            return this._responseContentView;
     82
     83        let typeFromMIMEType = WI.Resource.typeFromMIMEType(this._resource.mimeType);
     84        this._responseContentView = this._contentViewForResourceType(typeFromMIMEType);
     85        if (this._responseContentView)
     86            return this._responseContentView;
     87
     88        if (WI.shouldTreatMIMETypeAsText(this._resource.mimeType)) {
    8389            this._responseContentView = new WI.TextResourceContentView(this._resource);
    84             break;
    85 
    86         case WI.Resource.Type.XHR:
    87         case WI.Resource.Type.Fetch:
    88         case WI.Resource.Type.Ping:
    89         case WI.Resource.Type.Beacon:
    90             // FIXME: <https://webkit.org/b/165495> Web Inspector: XHR / Fetch for non-text content should not show garbled text
    91             // The response content for these requests may not always be text.
    92             this._responseContentView = new WI.TextResourceContentView(this._resource);
    93             break;
    94 
    95         case WI.Resource.Type.Image:
    96             if (this._resource.mimeTypeComponents.type === "image/svg+xml")
    97                 this._responseContentView = new WI.SVGImageResourceClusterContentView(this._resource);
    98             else
    99                 this._responseContentView = new WI.ImageResourceContentView(this._resource);
    100             break;
    101 
    102         case WI.Resource.Type.Font:
    103             this._responseContentView = new WI.FontResourceContentView(this._resource);
    104             break;
    105 
    106         case WI.Resource.Type.WebSocket:
    107             this._responseContentView = new WI.WebSocketContentView(this._resource);
    108             break;
    109 
    110         default:
    111             this._responseContentView = new WI.GenericResourceContentView(this._resource);
    112             break;
    113         }
    114 
     90            return this._responseContentView;
     91        }
     92
     93        this._responseContentView = new WI.GenericResourceContentView(this._resource);
    11594        return this._responseContentView;
    11695    }
     
    223202    {
    224203        return !!this._customResponseContentViewConstructor;
     204    }
     205
     206    _contentViewForResourceType(type)
     207    {
     208        switch (type) {
     209        case WI.Resource.Type.Document:
     210        case WI.Resource.Type.Script:
     211        case WI.Resource.Type.Stylesheet:
     212            return new WI.TextResourceContentView(this._resource);
     213
     214        case WI.Resource.Type.Image:
     215            if (this._resource.mimeTypeComponents.type === "image/svg+xml")
     216                return new WI.SVGImageResourceClusterContentView(this._resource);
     217            return new WI.ImageResourceContentView(this._resource);
     218
     219        case WI.Resource.Type.Font:
     220            return new WI.FontResourceContentView(this._resource);
     221
     222        case WI.Resource.Type.WebSocket:
     223            return new WI.WebSocketContentView(this._resource);
     224
     225        default:
     226            return null;
     227        }
    225228    }
    226229
  • trunk/Source/WebInspectorUI/UserInterface/Views/ResourceContentView.js

    r225244 r225546  
    8080    {
    8181        throw WI.NotImplementedError.subclassMustOverride();
     82    }
     83
     84    showGenericNoContentMessage()
     85    {
     86        this.showMessage(WI.UIString("Resource has no content"));
    8287    }
    8388
  • trunk/Source/WebInspectorUI/UserInterface/Views/SVGImageResourceClusterContentView.js

    r220119 r225546  
    137137
    138138            this._resource.requestContent().then((result) => {
    139                 let fileReader = new FileReader;
    140                 fileReader.addEventListener("loadend", () => {
    141                     contentViewToShow.textEditor.string = fileReader.result;
     139                if (typeof result.content === "string") {
     140                    contentViewToShow.textEditor.string = result.content;
     141                    return;
     142                }
     143
     144                blobAsText(result.content, (text) => {
     145                    contentViewToShow.textEditor.string = text;
    142146                });
    143                 fileReader.readAsText(result.content);
    144147            });
    145148            break;
  • trunk/Source/WebInspectorUI/UserInterface/Views/TextResourceContentView.js

    r222739 r225546  
    131131    }
    132132
     133    contentAvailable(content, base64Encoded)
     134    {
     135        // Do nothing.
     136    }
     137
    133138    get supportsSave()
    134139    {
     
    211216
    212217        if (!this._textEditor.string)
    213             this.showMessage(WI.UIString("Resource has no content"));
     218            this.showGenericNoContentMessage();
    214219    }
    215220
Note: See TracChangeset for help on using the changeset viewer.