Changeset 287612 in webkit


Ignore:
Timestamp:
Jan 5, 2022 2:46:30 AM (7 months ago)
Author:
youenn@apple.com
Message:

Fetch using FormData with file doesn't go through Service Worker
https://bugs.webkit.org/show_bug.cgi?id=187461
<rdar://problem/41975544>

Reviewed by Chris Dumez.

LayoutTests/imported/w3c:

  • web-platform-tests/fetch/api/response/response-consume-expected.txt:
  • web-platform-tests/fetch/api/response/response-consume-stream.any-expected.txt:
  • web-platform-tests/fetch/api/response/response-consume-stream.any.worker-expected.txt:

Source/WebCore:

Add support for reading formData based bodies through streams or regular methods like text.
For that purpose, we add FormDataConsumer which allows serializing form datas that may contain files or blobs.
Add the ability to load blobs from BlobLoader using the internal URL (stored in FormData) in lieu of passing a blob object.
Enable fetch events for form data based fetch events.

Test: http/wpt/service-workers/form-data-upload.html

  • Modules/fetch/FetchBody.cpp:
  • Modules/fetch/FetchBody.h:
  • Modules/fetch/FetchBodyConsumer.cpp:
  • Modules/fetch/FetchBodyConsumer.h:
  • Modules/fetch/FormDataConsumer.cpp: Added.
  • Modules/fetch/FormDataConsumer.h: Added.
  • Sources.txt:
  • WebCore.xcodeproj/project.pbxproj:
  • fileapi/BlobLoader.h:
  • fileapi/FileReaderLoader.cpp:
  • fileapi/FileReaderLoader.h:
  • workers/service/context/ServiceWorkerFetch.cpp:

LayoutTests:

In addition to adding a test to http/wpt/fetch/request-consume-stream.html, we fix the other tests that should all be passing.
Add http/wpt/service-workers/form-data-upload.html and translate exiting http/tests scripts for the WPT server.

  • http/wpt/fetch/request-consume-stream-expected.txt:
  • http/wpt/fetch/request-consume-stream.html:
  • http/wpt/service-workers/form-data-upload-expected.txt: Added.
  • http/wpt/service-workers/form-data-upload-worker.js: Added.
  • http/wpt/service-workers/form-data-upload.html: Added.
  • http/wpt/service-workers/resources/create-temp-file-iframe.html: Added.
  • http/wpt/service-workers/resources/reset-temp-file.py: Added.
  • http/wpt/service-workers/resources/temp-file-utils.js: Added.
  • http/wpt/service-workers/resources/touch-temp-file.py: Added.
  • http/wpt/service-workers/resources/write-temp-file.py: Added.
Location:
trunk
Files:
10 added
19 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r287611 r287612  
     12022-01-05  Youenn Fablet  <youenn@apple.com>
     2
     3        Fetch using FormData with file doesn't go through Service Worker
     4        https://bugs.webkit.org/show_bug.cgi?id=187461
     5        <rdar://problem/41975544>
     6
     7        Reviewed by Chris Dumez.
     8
     9        In addition to adding a test to http/wpt/fetch/request-consume-stream.html, we fix the other tests that should all be passing.
     10        Add http/wpt/service-workers/form-data-upload.html and translate exiting http/tests scripts for the WPT server.
     11
     12        * http/wpt/fetch/request-consume-stream-expected.txt:
     13        * http/wpt/fetch/request-consume-stream.html:
     14        * http/wpt/service-workers/form-data-upload-expected.txt: Added.
     15        * http/wpt/service-workers/form-data-upload-worker.js: Added.
     16        * http/wpt/service-workers/form-data-upload.html: Added.
     17        * http/wpt/service-workers/resources/create-temp-file-iframe.html: Added.
     18        * http/wpt/service-workers/resources/reset-temp-file.py: Added.
     19        * http/wpt/service-workers/resources/temp-file-utils.js: Added.
     20        * http/wpt/service-workers/resources/touch-temp-file.py: Added.
     21        * http/wpt/service-workers/resources/write-temp-file.py: Added.
     22
    1232022-01-05  Youenn Fablet  <youenn@apple.com>
    224
  • trunk/LayoutTests/http/wpt/fetch/request-consume-stream-expected.txt

    r262254 r287612  
    11
    2 FAIL Read empty text request's body as readableStream assert_array_equals: Retrieve and verify stream lengths differ, expected array object "" length 0, got object "123,34,107,101,121,34,58,32,34,118,97,108,117,101,34,125" length 16
    3 FAIL Read empty blob request's body as readableStream assert_array_equals: Retrieve and verify stream lengths differ, expected array object "" length 0, got object "123,34,107,101,121,34,58,32,34,118,97,108,117,101,34,125" length 16
    4 FAIL Read blob request's body as readableStream assert_array_equals: Retrieve and verify stream lengths differ, expected array object "115,32,105,115,32,114,101,113,117,101,115,116,39,115,32,98,111,100,121,34" length 24, got object "123,34,107,101,121,34,58,32,34,118,97,108,117,101,34,125" length 16
    5 FAIL Read text request's body as readableStream assert_array_equals: Retrieve and verify stream lengths differ, expected array object "115,32,105,115,32,114,101,113,117,101,115,116,39,115,32,98,111,100,121,34" length 24, got object "123,34,107,101,121,34,58,32,34,118,97,108,117,101,34,125" length 16
    6 FAIL Read URLSearchParams request's body as readableStream assert_array_equals: Retrieve and verify stream lengths differ, expected array object "110,97,109,101,61,118,97,108,117,101" length 10, got object "123,34,107,101,121,34,58,32,34,118,97,108,117,101,34,125" length 16
    7 FAIL Read array buffer request's body as readableStream assert_array_equals: Retrieve and verify stream lengths differ, expected array object "115,32,105,115,32,114,101,113,117,101,115,116,39,115,32,98,111,100,121,34" length 24, got object "123,34,107,101,121,34,58,32,34,118,97,108,117,101,34,125" length 16
    8 FAIL Read form data request's body as readableStream assert_array_equals: Retrieve and verify stream lengths differ, expected array object "110,97,109,101,61,118,97,108,117,101" length 10, got object "123,34,107,101,121,34,58,32,34,118,97,108,117,101,34,125" length 16
     2PASS Read empty text request's body as readableStream
     3PASS Read empty blob request's body as readableStream
     4PASS Read blob request's body as readableStream
     5PASS Read text request's body as readableStream
     6PASS Read URLSearchParams request's body as readableStream
     7PASS Read array buffer request's body as readableStream
     8PASS Read form data request's body as readableStream
     9PASS Read form data with blob request's body as readableStream
    910
  • trunk/LayoutTests/http/wpt/fetch/request-consume-stream.html

    r221437 r287612  
    1212  <body>
    1313    <script>
     14async function getStringFromStream(reader, currentValue) {
     15    const data = await reader.read();
     16    if (!data.done) {
     17        let buffer;
     18        if (currentValue) {
     19            const newBuffer = new ArrayBuffer(data.value.length + currentValue.length);
     20            buffer = new Uint8Array(newBuffer);
     21            buffer.set(currentValue, 0);
     22            buffer.set(data.value, currentValue.length);
     23        } else
     24            buffer = data.value;
     25        return getStringFromStream(reader, buffer);
     26    }
     27    return (new TextDecoder).decode(currentValue);
     28}
     29
    1430function createRequestWithBody(body)
    1531{
    16     return new Request("", {body: "{\"key\": \"value\"}", method: "POST"});
     32    return new Request("", {body: body, method: "POST"});
    1733}
    1834
     
    5975}, "Read array buffer request's body as readableStream");
    6076
    61 promise_test(function(test) {
     77promise_test(async (test) => {
    6278    var request = createRequestWithBody(formData);
    63     return validateStreamFromString(request.body.getReader(), "name=value");
     79    const value = await getStringFromStream(request.body.getReader());
     80
     81    assert_true(value.includes('name="name"'), "name");
     82    assert_true(value.includes('value'), "name");
    6483}, "Read form data request's body as readableStream");
     84
     85promise_test(async (test) => {
     86    const formData = new FormData();
     87    const blob = new Blob(["'Hello'"], { "type" : "text/plain" });
     88    formData.append("blob", blob, "blob.file");
     89    formData.append("name", "value");
     90
     91    const request = createRequestWithBody(formData);
     92    const value = await getStringFromStream(request.body.getReader());
     93
     94    assert_true(value.includes('name="name"'), "name");
     95    assert_true(value.includes('value'), "name");
     96
     97    assert_true(value.includes('name="blob"'), "blob");
     98    assert_true(value.includes('Hello'), "Hello");
     99}, "Read form data with blob request's body as readableStream");
    65100    </script>
    66101  </body>
  • trunk/LayoutTests/imported/w3c/ChangeLog

    r287610 r287612  
     12022-01-05  Youenn Fablet  <youenn@apple.com>
     2
     3        Fetch using FormData with file doesn't go through Service Worker
     4        https://bugs.webkit.org/show_bug.cgi?id=187461
     5        <rdar://problem/41975544>
     6
     7        Reviewed by Chris Dumez.
     8
     9        * web-platform-tests/fetch/api/response/response-consume-expected.txt:
     10        * web-platform-tests/fetch/api/response/response-consume-stream.any-expected.txt:
     11        * web-platform-tests/fetch/api/response/response-consume-stream.any.worker-expected.txt:
     12
    1132022-01-05  Martin Robinson  <mrobinson@webkit.org>
    214
  • trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/response/response-consume-expected.txt

    r267651 r287612  
    3939PASS Consume response's body: from fetch to arrayBuffer
    4040PASS Consume response's body: from fetch without correct type to formData (error case)
    41 FAIL Consume response's body: from multipart form data blob to formData promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
     41PASS Consume response's body: from multipart form data blob to formData
    4242
  • trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/response/response-consume-stream.any-expected.txt

    r279344 r287612  
    66PASS Read URLSearchParams response's body as readableStream
    77PASS Read array buffer response's body as readableStream
    8 FAIL Read form data response's body as readableStream promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
     8PASS Read form data response's body as readableStream
    99PASS Getting an error Response stream
    1010PASS Getting a redirect Response stream
  • trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/response/response-consume-stream.any.worker-expected.txt

    r279344 r287612  
    66PASS Read URLSearchParams response's body as readableStream
    77PASS Read array buffer response's body as readableStream
    8 FAIL Read form data response's body as readableStream promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
     8PASS Read form data response's body as readableStream
    99PASS Getting an error Response stream
    1010PASS Getting a redirect Response stream
  • trunk/Source/WebCore/ChangeLog

    r287611 r287612  
     12022-01-05  Youenn Fablet  <youenn@apple.com>
     2
     3        Fetch using FormData with file doesn't go through Service Worker
     4        https://bugs.webkit.org/show_bug.cgi?id=187461
     5        <rdar://problem/41975544>
     6
     7        Reviewed by Chris Dumez.
     8
     9        Add support for reading formData based bodies through streams or regular methods like text.
     10        For that purpose, we add FormDataConsumer which allows serializing form datas that may contain files or blobs.
     11        Add the ability to load blobs from BlobLoader using the internal URL (stored in FormData) in lieu of passing a blob object.
     12        Enable fetch events for form data based fetch events.
     13
     14        Test: http/wpt/service-workers/form-data-upload.html
     15
     16        * Modules/fetch/FetchBody.cpp:
     17        * Modules/fetch/FetchBody.h:
     18        * Modules/fetch/FetchBodyConsumer.cpp:
     19        * Modules/fetch/FetchBodyConsumer.h:
     20        * Modules/fetch/FormDataConsumer.cpp: Added.
     21        * Modules/fetch/FormDataConsumer.h: Added.
     22        * Sources.txt:
     23        * WebCore.xcodeproj/project.pbxproj:
     24        * fileapi/BlobLoader.h:
     25        * fileapi/FileReaderLoader.cpp:
     26        * fileapi/FileReaderLoader.h:
     27        * workers/service/context/ServiceWorkerFetch.cpp:
     28
    1292022-01-05  Youenn Fablet  <youenn@apple.com>
    230
  • trunk/Source/WebCore/Modules/fetch/FetchBody.cpp

    r287021 r287612  
    9595    }
    9696
    97     // FIXME: Support form data bodies.
    98     return std::nullopt;
     97    return FetchBody { Ref { formData } };
    9998}
    10099
     
    197196        m_data = nullptr;
    198197    } else if (isFormData())
    199         source.error(Exception { NotSupportedError, "Not implemented"_s });
     198        m_consumer.consumeFormDataAsStream(formDataBody(), source, owner.scriptExecutionContext());
    200199    else if (m_consumer.hasData())
    201200        closeStream = source.enqueue(m_consumer.takeAsArrayBuffer());
     
    235234void FetchBody::consumeFormData(FetchBodyOwner& owner, Ref<DeferredPromise>&& promise)
    236235{
    237     if (auto sharedBuffer = formDataBody().asSharedBuffer()) {
    238         m_consumer.resolveWithData(WTFMove(promise), owner.contentType(), sharedBuffer->makeContiguous()->data(), sharedBuffer->size());
    239         m_data = nullptr;
    240     } else {
    241         // FIXME: If the form data contains blobs, load them like we do other blobs.
    242         // That will fix the last WPT test in response-consume.html.
    243         promise->reject(NotSupportedError);
    244     }
     236    m_consumer.resolveWithFormData(WTFMove(promise), owner.contentType(), formDataBody(), owner.scriptExecutionContext());
     237    m_data = nullptr;
    245238}
    246239
     
    312305FetchBody FetchBody::clone()
    313306{
    314     FetchBody clone(m_consumer);
     307    FetchBody clone(m_consumer.clone());
    315308
    316309    if (isArrayBuffer())
  • trunk/Source/WebCore/Modules/fetch/FetchBody.h

    r287021 r287612  
    9595    explicit FetchBody(String&& data) : m_data(WTFMove(data)) { }
    9696    explicit FetchBody(Ref<const URLSearchParams>&& data) : m_data(WTFMove(data)) { }
    97     explicit FetchBody(const FetchBodyConsumer& consumer) : m_consumer(consumer) { }
     97    explicit FetchBody(FetchBodyConsumer&& consumer) : m_consumer(WTFMove(consumer)) { }
    9898    explicit FetchBody(Ref<ReadableStream>&& stream) : m_readableStream(WTFMove(stream)) { }
    9999
  • trunk/Source/WebCore/Modules/fetch/FetchBodyConsumer.cpp

    r287021 r287612  
    3131
    3232#include "DOMFormData.h"
     33#include "FormDataConsumer.h"
    3334#include "HTTPHeaderField.h"
    3435#include "HTTPParsers.h"
     
    244245{
    245246    m_buffer.reset();
     247    if (m_formDataConsumer)
     248        m_formDataConsumer->cancel();
    246249    resetConsumePromise();
    247250    if (m_sink) {
     
    254257{
    255258    resolveWithTypeAndData(WTFMove(promise), m_type, contentType, data, length);
     259}
     260
     261void FetchBodyConsumer::resolveWithFormData(Ref<DeferredPromise>&& promise, const String& contentType, const FormData& formData, ScriptExecutionContext* context)
     262{
     263    if (auto sharedBuffer = formData.asSharedBuffer()) {
     264        resolveWithData(WTFMove(promise), contentType, sharedBuffer->makeContiguous()->data(), sharedBuffer->size());
     265        return;
     266    }
     267
     268    if (!context)
     269        return;
     270
     271    m_formDataConsumer = makeUnique<FormDataConsumer>(formData, *context, [this, promise = WTFMove(promise), contentType, builder = SharedBufferBuilder { }](auto&& result) mutable {
     272        if (result.hasException()) {
     273            promise->reject(result.releaseException());
     274            return;
     275        }
     276
     277        auto& value = result.returnValue();
     278        if (value.empty()) {
     279            auto buffer = builder.takeAsContiguous();
     280            resolveWithData(WTFMove(promise), contentType, buffer->data(), buffer->size());
     281            return;
     282        }
     283
     284        builder.append(value);
     285    });
     286}
     287
     288void FetchBodyConsumer::consumeFormDataAsStream(const FormData& formData, FetchBodySource& source, ScriptExecutionContext* context)
     289{
     290    if (auto sharedBuffer = formData.asSharedBuffer()) {
     291        if (source.enqueue(ArrayBuffer::tryCreate(sharedBuffer->makeContiguous()->data(), sharedBuffer->size())))
     292            source.close();
     293        return;
     294    }
     295
     296    if (!context)
     297        return;
     298
     299    m_formDataConsumer = makeUnique<FormDataConsumer>(formData, *context, [this, source = Ref { source }](auto&& result) {
     300        if (result.hasException()) {
     301            source->error(result.releaseException());
     302            return;
     303        }
     304
     305        auto& value = result.returnValue();
     306        if (value.empty()) {
     307            source->close();
     308            return;
     309        }
     310
     311        if (!source->enqueue(ArrayBuffer::tryCreate(value.data(), value.size())))
     312            m_formDataConsumer->cancel();
     313    });
    256314}
    257315
     
    417475}
    418476
     477FetchBodyConsumer FetchBodyConsumer::clone()
     478{
     479    FetchBodyConsumer clone { m_type };
     480    clone.m_contentType = m_contentType;
     481    clone.m_buffer = m_buffer;
     482    return clone;
     483}
     484
    419485} // namespace WebCore
  • trunk/Source/WebCore/Modules/fetch/FetchBodyConsumer.h

    r287021 r287612  
    3030
    3131#include "FetchBodySource.h"
     32#include "FormDataConsumer.h"
    3233#include "JSDOMPromiseDeferred.h"
    3334#include "ReadableStreamSink.h"
     35#include "ScriptExecutionContextIdentifier.h"
    3436#include "SharedBuffer.h"
    3537#include "UserGestureIndicator.h"
     
    4042class DOMFormData;
    4143class FetchBodySource;
     44class FormData;
    4245class ReadableStream;
    4346
     
    4750
    4851    explicit FetchBodyConsumer(Type type) : m_type(type) { }
     52
     53    FetchBodyConsumer clone();
    4954
    5055    void append(const uint8_t* data, unsigned);
     
    6671    void resolve(Ref<DeferredPromise>&&, const String& contentType, ReadableStream*);
    6772    void resolveWithData(Ref<DeferredPromise>&&, const String& contentType, const unsigned char*, unsigned);
     73    void resolveWithFormData(Ref<DeferredPromise>&&, const String& contentType, const FormData&, ScriptExecutionContext*);
     74    void consumeFormDataAsStream(const FormData&, FetchBodySource&, ScriptExecutionContext*);
    6875
    6976    void loadingFailed(const Exception&);
     
    8996    bool m_isLoading { false };
    9097    RefPtr<UserGestureToken> m_userGestureToken;
     98    std::unique_ptr<FormDataConsumer> m_formDataConsumer;
    9199};
    92100
  • trunk/Source/WebCore/Sources.txt

    r287538 r287612  
    8989Modules/fetch/FetchRequest.cpp
    9090Modules/fetch/FetchResponse.cpp
     91Modules/fetch/FormDataConsumer.cpp
    9192Modules/fetch/WindowOrWorkerGlobalScopeFetch.cpp
    9293Modules/filesystemaccess/FileSystemDirectoryHandle.cpp
  • trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj

    r287574 r287612  
    84868486                3FBC4AF2189881560046EE38 /* VideoFullscreenInterfaceAVKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VideoFullscreenInterfaceAVKit.h; sourceTree = "<group>"; };
    84878487                41024FC823CF254F00FDF98E /* SampleBufferDisplayLayer.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = SampleBufferDisplayLayer.cpp; sourceTree = "<group>"; };
     8488                4102EE0E27830E6300D6BE74 /* FormDataConsumer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FormDataConsumer.h; sourceTree = "<group>"; };
     8489                4102EE1027830E6300D6BE74 /* FormDataConsumer.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = FormDataConsumer.cpp; sourceTree = "<group>"; };
    84888490                4107908A1FC3E4F20061B27A /* ClientOrigin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ClientOrigin.h; sourceTree = "<group>"; };
    84898491                4109382C2347850E009428BA /* JSAbortSignalCustom.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = JSAbortSignalCustom.cpp; sourceTree = "<group>"; };
     
    2128221284                                413015D61C7B570400091C6E /* FetchResponse.h */,
    2128321285                                413015D71C7B570400091C6E /* FetchResponse.idl */,
     21286                                4102EE1027830E6300D6BE74 /* FormDataConsumer.cpp */,
     21287                                4102EE0E27830E6300D6BE74 /* FormDataConsumer.h */,
    2128421288                                7C2E0BD125106AC4005F3C87 /* WindowOrWorkerGlobalScope+Fetch.idl */,
    2128521289                                7C2E0BD025106AC4005F3C87 /* WindowOrWorkerGlobalScopeFetch.cpp */,
  • trunk/Source/WebCore/fileapi/BlobLoader.h

    r278340 r287612  
    4444
    4545    void start(Blob&, ScriptExecutionContext*, FileReaderLoader::ReadType);
     46    void start(const URL&, ScriptExecutionContext*, FileReaderLoader::ReadType);
    4647
    4748    void cancel();
     
    9091}
    9192
     93inline void BlobLoader::start(const URL& blobURL, ScriptExecutionContext* context, FileReaderLoader::ReadType readType)
     94{
     95    ASSERT(!m_loader);
     96    m_loader = makeUnique<FileReaderLoader>(readType, this);
     97    m_loader->start(context, blobURL);
     98}
     99
    92100inline void BlobLoader::didFinishLoading()
    93101{
  • trunk/Source/WebCore/fileapi/FileReaderLoader.cpp

    r286772 r287612  
    7575void FileReaderLoader::start(ScriptExecutionContext* scriptExecutionContext, Blob& blob)
    7676{
     77    start(scriptExecutionContext, blob.url());
     78}
     79
     80void FileReaderLoader::start(ScriptExecutionContext* scriptExecutionContext, const URL& blobURL)
     81{
    7782    ASSERT(scriptExecutionContext);
    7883
     
    8388        return;
    8489    }
    85     ThreadableBlobRegistry::registerBlobURL(scriptExecutionContext->securityOrigin(), scriptExecutionContext->policyContainer(), m_urlForReading, blob.url());
     90    ThreadableBlobRegistry::registerBlobURL(scriptExecutionContext->securityOrigin(), scriptExecutionContext->policyContainer(), m_urlForReading, blobURL);
    8691
    8792    // Construct and load the request.
  • trunk/Source/WebCore/fileapi/FileReaderLoader.h

    r286772 r287612  
    6767
    6868    WEBCORE_EXPORT void start(ScriptExecutionContext*, Blob&);
     69    void start(ScriptExecutionContext*, const URL&);
    6970    WEBCORE_EXPORT void cancel();
    7071
  • trunk/Source/WebCore/platform/SharedBuffer.h

    r287021 r287612  
    231231    WEBCORE_EXPORT void append(const FragmentedSharedBuffer&);
    232232    WEBCORE_EXPORT void append(const uint8_t*, size_t);
     233    void append(Span<const uint8_t> value) { append(value.data(), value.size()); }
    233234    void append(const char* data, size_t length) { append(reinterpret_cast<const uint8_t*>(data), length); }
    234235    WEBCORE_EXPORT void append(Vector<uint8_t>&&);
  • trunk/Source/WebCore/workers/service/context/ServiceWorkerFetch.cpp

    r287021 r287612  
    4747
    4848// https://fetch.spec.whatwg.org/#http-fetch step 3.3
    49 static inline std::optional<ResourceError> validateResponse(const ResourceResponse& response, FetchOptions::Mode mode, FetchOptions::Redirect redirect)
     49static inline ResourceError validateResponse(const ResourceResponse& response, FetchOptions::Mode mode, FetchOptions::Redirect redirect)
    5050{
    5151    if (response.type() == ResourceResponse::Type::Error)
     
    8585
    8686    auto resourceResponse = response->resourceResponse();
    87     if (auto error = validateResponse(resourceResponse, mode, redirect)) {
    88         client->didFail(error.value());
     87    if (auto error = validateResponse(resourceResponse, mode, redirect); !error.isNull()) {
     88        client->didFail(error);
    8989        return;
    9090    }
Note: See TracChangeset for help on using the changeset viewer.