⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 203494 in webkit


Ignore:
Timestamp:
Jul 20, 2016, 11:51:05 PM (10 years ago)
Author:
commit-queue@webkit.org
Message:

[XHR] Cache response JS object in case of arraybuffer and blob response types
​https://bugs.webkit.org/show_bug.cgi?id=128903

Patch by Youenn Fablet <​youenn@apple.com> on 2016-07-20
Reviewed by Alex Christensen.

Source/WebCore:

Covered by existing and modified tests.

Making response getter a JS builtin that caches response in @response private slot.
Handling invalidation of cached response with @responseCacheIsValid new private method.
Handling creation of cached response with @retrieveResponse new private method which reuses most of
JSXMLHttpRequest::response previous code.

Caching of responses is activated whenever load ended without any error for blob and arraybuffer response types.

Caching of response for document is also activated in case the response getter is used but not if responseXML getter is used.

  • CMakeLists.txt: Adding XMLHttpRequest.js.
  • DerivedSources.make: Ditto.
  • bindings/js/JSXMLHttpRequestCustom.cpp:

(WebCore::JSXMLHttpRequest::retrieveResponse): Implements creation of to-be-cached response.
(WebCore::JSXMLHttpRequest::response): Deleted.

  • bindings/js/WebCoreBuiltinNames.h: Adding new private names.
  • xml/XMLHttpRequest.cpp:

(WebCore::XMLHttpRequest::didCacheResponse): Renamed from didCacheResponseJSON as all response types are now cached.
(WebCore::XMLHttpRequest::didCacheResponseJSON): Deleted.

  • xml/XMLHttpRequest.h:
  • xml/XMLHttpRequest.idl:

LayoutTests:

  • http/tests/xmlhttprequest/onabort-response-getters-expected.txt:
  • http/tests/xmlhttprequest/onabort-response-getters.html:
Location:
trunk
Files:
1 added
11 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r203491 r203494  
     12016-07-20  Youenn Fablet  <youenn@apple.com>
     2
     3        [XHR] Cache response JS object in case of arraybuffer and blob response types
     4        https://bugs.webkit.org/show_bug.cgi?id=128903
     5
     6        Reviewed by Alex Christensen.
     7
     8        * http/tests/xmlhttprequest/onabort-response-getters-expected.txt:
     9        * http/tests/xmlhttprequest/onabort-response-getters.html:
     10
    1112016-07-19  Filip Pizlo  <fpizlo@apple.com>
    212
  • trunk/LayoutTests/http/tests/xmlhttprequest/onabort-response-getters-expected.txt

    r163527 r203494  
    11
    22PASS getting arraybuffer response within abort event callback
     3PASS getting arraybuffer response within abort event callback (aborting in loadend)
    34PASS getting blob response within abort event callback
     5PASS getting blob response within abort event callback (aborting in loadend)
    46PASS getting json response within abort event callback
     7PASS getting json response within abort event callback (aborting in loadend)
    58PASS getting document response within abort event callback
     9PASS getting document response within abort event callback (aborting in loadend)
     10PASS getting text response within abort event callback
     11PASS getting text response within abort event callback (aborting in loadend)
    612
  • trunk/LayoutTests/http/tests/xmlhttprequest/onabort-response-getters.html

    r163527 r203494  
    88    <div id="log"></div>
    99    <script>
     10    function checkCachedResponse(client) {
     11        assert_true(client.response === client.response);
     12        if (client.responseType == "text")
     13            assert_true(client.responseText === client.response);
     14        if (client.responseType == "document")
     15            assert_true(client.responseXML === client.response);
     16    }
     17
    1018    function runTest(name, fileName, mimeType, setupClient, checkResponse) {
    1119      var test = async_test(name)
    … …  
    2937                checkResponse(test, client)
    3038                client.isResponseChecked = true
     39                checkCachedResponse(client);
    3140            }
    3241        })
    … …  
    3948            assert_true(client.hasAborted, "xhr should have aborted")
    4049            assert_true(client.isResponseChecked, "xhr response should have been checked")
     50            checkCachedResponse(client);
    4151            test.done()
     52        })
     53        client.send(null)
     54      })
     55
     56      var test2 = async_test(name + " (aborting in loadend)")
     57      test2.step(function() {
     58        var client = new XMLHttpRequest()
     59        var url = "/resources/load-then-wait.cgi?name=../xmlhttprequest/" + fileName + "&waitFor=1&mimeType=" + mimeType
     60        client.open("GET", url, true)
     61        setupClient(test2, client)
     62
     63        client.onloadend = test2.step_func(function () {
     64            assert_true(client.response != null);
     65            checkCachedResponse(client);
     66            client.abort();
     67            checkResponse(test2, client);
     68            checkCachedResponse(client);
     69            test2.done();
    4270        })
    4371        client.send(null)
    … …  
    6997    )
    7098
     99    runTest("getting text response within abort event callback",
     100        "resources/test.json","text/plain",
     101        function(test, client) {client.responseType = "text"},
     102        function(test, client) {assert_true(client.response == "", "text response must be an empty string")}
     103    )
     104
    71105    </script>
    72106  </body>
  • trunk/Source/WebCore/CMakeLists.txt

    r203445 r203494  
    37273727    ${WEBCORE_DIR}/Modules/streams/WritableStream.js
    37283728    ${WEBCORE_DIR}/Modules/streams/WritableStreamInternals.js
     3729    ${WEBCORE_DIR}/xml/XMLHttpRequest.js
    37293730)
    37303731
  • trunk/Source/WebCore/ChangeLog

    r203490 r203494  
     12016-07-20  Youenn Fablet  <youenn@apple.com>
     2
     3        [XHR] Cache response JS object in case of arraybuffer and blob response types
     4        https://bugs.webkit.org/show_bug.cgi?id=128903
     5
     6        Reviewed by Alex Christensen.
     7
     8        Covered by existing and modified tests.
     9
     10        Making response getter a JS builtin that caches response in @response private slot.
     11        Handling invalidation of cached response with @responseCacheIsValid new private method.
     12        Handling creation of cached response with @retrieveResponse new private method which reuses most of
     13        JSXMLHttpRequest::response previous code.
     14
     15        Caching of responses is activated whenever load ended without any error for blob and arraybuffer response types.
     16
     17        Caching of response for document is also activated in case the response getter is used but not if responseXML getter is used.
     18
     19        * CMakeLists.txt: Adding XMLHttpRequest.js.
     20        * DerivedSources.make: Ditto.
     21        * bindings/js/JSXMLHttpRequestCustom.cpp:
     22        (WebCore::JSXMLHttpRequest::retrieveResponse): Implements creation of to-be-cached response.
     23        (WebCore::JSXMLHttpRequest::response): Deleted.
     24        * bindings/js/WebCoreBuiltinNames.h: Adding new private names.
     25        * xml/XMLHttpRequest.cpp:
     26        (WebCore::XMLHttpRequest::didCacheResponse): Renamed from didCacheResponseJSON as all response types are now cached.
     27        (WebCore::XMLHttpRequest::didCacheResponseJSON): Deleted.
     28        * xml/XMLHttpRequest.h:
     29        * xml/XMLHttpRequest.idl:
     30
    1312016-07-20  Youenn Fablet  <youenn@apple.com>
    232
  • trunk/Source/WebCore/DerivedSources.make

    r203445 r203494  
    13001300    $(WebCore)/Modules/streams/WritableStream.js \
    13011301    $(WebCore)/Modules/streams/WritableStreamInternals.js \
     1302    $(WebCore)/xml/XMLHttpRequest.js \
    13021303#
    13031304
  • trunk/Source/WebCore/bindings/js/JSXMLHttpRequestCustom.cpp

    r203470 r203494  
    6464    if (Document* responseDocument = wrapped().optionalResponseXML())
    6565        visitor.addOpaqueRoot(responseDocument);
    66 
    67     if (ArrayBuffer* responseArrayBuffer = wrapped().optionalResponseArrayBuffer())
    68         visitor.addOpaqueRoot(responseArrayBuffer);
    69 
    70     if (Blob* responseBlob = wrapped().optionalResponseBlob())
    71         visitor.addOpaqueRoot(responseBlob);
    7266}
    7367
    … …  
    152146}
    153147
    154 JSValue JSXMLHttpRequest::response(ExecState& state) const
     148JSValue JSXMLHttpRequest::retrieveResponse(ExecState& state)
    155149{
    156     // FIXME: Use CachedAttribute for other types than JSON as well.
    157     if (m_response && wrapped().responseCacheIsValid())
    158         return m_response.get();
    159 
    160150    auto type = wrapped().responseType();
    161151
    … …  
    171161        return jsNull();
    172162
     163    JSValue value;
    173164    switch (type) {
    174165    case XMLHttpRequest::ResponseType::EmptyString:
    175166    case XMLHttpRequest::ResponseType::Text:
    176167        ASSERT_NOT_REACHED();
     168        return jsUndefined();
     169
     170    case XMLHttpRequest::ResponseType::Json:
     171        value = JSONParse(&state, wrapped().responseTextIgnoringResponseType());
     172        if (!value)
     173            value = jsNull();
    177174        break;
    178175
    179     case XMLHttpRequest::ResponseType::Json:
    180         {
    181             JSValue value = JSONParse(&state, wrapped().responseTextIgnoringResponseType());
    182             if (!value)
    183                 value = jsNull();
    184             m_response.set(state.vm(), this, value);
    185             wrapped().didCacheResponseJSON();
    186             return value;
    187         }
    188 
    189     case XMLHttpRequest::ResponseType::Document:
    190         {
    191             ExceptionCode ec = 0;
    192             Document* document = wrapped().responseXML(ec);
    193             if (ec) {
    194                 setDOMException(&state, ec);
    195                 return jsUndefined();
    196             }
    197             return toJS(&state, globalObject(), document);
    198         }
    199 
     176    case XMLHttpRequest::ResponseType::Document: {
     177        ExceptionCode ec = 0;
     178        auto document = wrapped().responseXML(ec);
     179        ASSERT(!ec);
     180        value = toJS(&state, globalObject(), document);
     181        break;
     182    }
    200183    case XMLHttpRequest::ResponseType::Blob:
    201         return toJS(&state, globalObject(), wrapped().responseBlob());
     184        value = toJSNewlyCreated(&state, globalObject(), wrapped().createResponseBlob());
     185        break;
    202186
    203187    case XMLHttpRequest::ResponseType::Arraybuffer:
    204         return toJS(&state, globalObject(), wrapped().responseArrayBuffer());
     188        value = toJS(&state, globalObject(), wrapped().createResponseArrayBuffer());
     189        break;
    205190    }
    206 
    207     ASSERT_NOT_REACHED();
    208     return jsUndefined();
     191    wrapped().didCacheResponse();
     192    return value;
    209193}
    210194
  • trunk/Source/WebCore/bindings/js/WebCoreBuiltinNames.h

    r203445 r203494  
    6363    macro(readyPromiseCapability) \
    6464    macro(removeTrack) \
     65    macro(responseCacheIsValid) \
     66    macro(retrieveResponse) \
     67    macro(response) \
    6568    macro(setStatus) \
    6669    macro(state) \
    … …  
    8689    macro(RTCIceCandidate) \
    8790    macro(RTCSessionDescription) \
     91    macro(XMLHttpRequest)
    8892
    8993class WebCoreBuiltinNames {
  • trunk/Source/WebCore/xml/XMLHttpRequest.cpp

    r203490 r203494  
    172172}
    173173
    174 void XMLHttpRequest::didCacheResponseJSON()
    175 {
    176     ASSERT(m_responseType == ResponseType::Json);
     174void XMLHttpRequest::didCacheResponse()
     175{
    177176    ASSERT(doneWithoutErrors());
    178177    m_responseCacheIsValid = true;
    … …  
    219218}
    220219
    221 Blob* XMLHttpRequest::responseBlob()
     220Ref<Blob> XMLHttpRequest::createResponseBlob()
    222221{
    223222    ASSERT(m_responseType == ResponseType::Blob);
    224223    ASSERT(doneWithoutErrors());
    225224
    226     if (!m_responseBlob) {
    227         if (m_binaryResponseBuilder) {
    228             // FIXME: We just received the data from NetworkProcess, and are sending it back. This is inefficient.
    229             Vector<uint8_t> data;
    230             data.append(m_binaryResponseBuilder->data(), m_binaryResponseBuilder->size());
    231             String normalizedContentType = Blob::normalizedContentType(responseMIMEType()); // responseMIMEType defaults to text/xml which may be incorrect.
    232             m_responseBlob = Blob::create(WTFMove(data), normalizedContentType);
    233             m_binaryResponseBuilder = nullptr;
    234         } else {
    235             // If we errored out or got no data, we still return a blob, just an empty one.
    236             m_responseBlob = Blob::create();
    237         }
    238     }
    239 
    240     return m_responseBlob.get();
    241 }
    242 
    243 ArrayBuffer* XMLHttpRequest::responseArrayBuffer()
     225    if (!m_binaryResponseBuilder)
     226        return Blob::create();
     227
     228    // FIXME: We just received the data from NetworkProcess, and are sending it back. This is inefficient.
     229    Vector<uint8_t> data;
     230    data.append(m_binaryResponseBuilder->data(), m_binaryResponseBuilder->size());
     231    m_binaryResponseBuilder = nullptr;
     232    String normalizedContentType = Blob::normalizedContentType(responseMIMEType()); // responseMIMEType defaults to text/xml which may be incorrect.
     233    return Blob::create(WTFMove(data), normalizedContentType);
     234}
     235
     236RefPtr<ArrayBuffer> XMLHttpRequest::createResponseArrayBuffer()
    244237{
    245238    ASSERT(m_responseType == ResponseType::Arraybuffer);
    246239    ASSERT(doneWithoutErrors());
    247240
    248     if (!m_responseArrayBuffer) {
    249         if (m_binaryResponseBuilder)
    250             m_responseArrayBuffer = m_binaryResponseBuilder->createArrayBuffer();
    251         else
    252             m_responseArrayBuffer = ArrayBuffer::create(nullptr, 0);
    253         m_binaryResponseBuilder = nullptr;
    254     }
    255 
    256     return m_responseArrayBuffer.get();
     241    auto result = m_binaryResponseBuilder ? m_binaryResponseBuilder->createArrayBuffer() : ArrayBuffer::create(nullptr, 0);
     242    m_binaryResponseBuilder = nullptr;
     243    return result;
    257244}
    258245
    … …  
    820807    m_createdDocument = false;
    821808    m_responseDocument = nullptr;
    822     m_responseBlob = nullptr;
    823809    m_binaryResponseBuilder = nullptr;
    824     m_responseArrayBuffer = nullptr;
    825810    m_responseCacheIsValid = false;
    826811}
  • trunk/Source/WebCore/xml/XMLHttpRequest.h

    r203470 r203494  
    8989    String responseTextIgnoringResponseType() const { return m_responseBuilder.toStringPreserveCapacity(); }
    9090    String responseMIMEType() const;
     91
     92    Document* optionalResponseXML() const { return m_responseDocument.get(); }
    9193    Document* responseXML(ExceptionCode&);
    92     Document* optionalResponseXML() const { return m_responseDocument.get(); }
    93     Blob* responseBlob();
    94     Blob* optionalResponseBlob() const { return m_responseBlob.get(); }
     94
     95    Ref<Blob> createResponseBlob();
     96    RefPtr<JSC::ArrayBuffer> createResponseArrayBuffer();
     97
    9598    unsigned timeout() const { return m_timeoutMilliseconds; }
    9699    void setTimeout(unsigned timeout, ExceptionCode&);
    97100
    98101    bool responseCacheIsValid() const { return m_responseCacheIsValid; }
    99     void didCacheResponseJSON();
     102    void didCacheResponse();
    100103
    101104    // Expose HTTP validation methods for other untrusted requests.
    … …  
    109112
    110113    String responseURL() const;
    111 
    112     // response attribute has custom getter.
    113     JSC::ArrayBuffer* responseArrayBuffer();
    114     JSC::ArrayBuffer* optionalResponseArrayBuffer() const { return m_responseArrayBuffer.get(); }
    115114
    116115    void setLastSendLineAndColumnNumber(unsigned lineNumber, unsigned columnNumber);
    … …  
    188187    bool m_async { true };
    189188    bool m_includeCredentials { false };
    190     RefPtr<Blob> m_responseBlob;
    191189
    192190    RefPtr<ThreadableLoader> m_loader;
    … …  
    202200    bool m_createdDocument { false };
    203201    RefPtr<Document> m_responseDocument;
    204    
     202
    205203    RefPtr<SharedBuffer> m_binaryResponseBuilder;
    206     RefPtr<JSC::ArrayBuffer> m_responseArrayBuffer;
    207204
    208205    bool m_error { false };
  • trunk/Source/WebCore/xml/XMLHttpRequest.idl

    r203470 r203494  
    4545    JSGenerateToJSObject,
    4646    ExportMacro=WEBCORE_EXPORT,
     47    PublicIdentifier,
     48    PrivateIdentifier,
    4749] interface XMLHttpRequest : XMLHttpRequestEventTarget {
    4850    attribute EventHandler onreadystatechange;
    … …  
    7981
    8082    [SetterRaisesException] attribute XMLHttpRequestResponseType responseType;
    81     [GetterRaisesException, CachedAttribute, CustomGetter] readonly attribute Object response;
     83    [JSBuiltin] readonly attribute Object response;
    8284
    8385    readonly attribute unsigned short status;
    … …  
    8587    readonly attribute DOMString responseURL;
    8688
     89    [PrivateIdentifier] boolean responseCacheIsValid();
     90    [PrivateIdentifier, Custom] any retrieveResponse();
     91
    8792    // Extension
    8893    [RaisesException] void overrideMimeType(DOMString override);
Note: See TracChangeset for help on using the changeset viewer.