Abstract out WebSocketChannel message queue
authoryouenn@apple.com <youenn@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 4 Sep 2019 16:46:55 +0000 (16:46 +0000)
committeryouenn@apple.com <youenn@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 4 Sep 2019 16:46:55 +0000 (16:46 +0000)
https://bugs.webkit.org/show_bug.cgi?id=201359

Reviewed by Alex Christensen.

Source/WebCore:

Move BlobLoader in its own file.
Introduce NetworkSendQueue class to handle the sending of messages, some of them being blobs.
This class ensures that messages will be sent in order, even though blob data is resolved asynchronously.

Covered by existing tests.

* Headers.cmake:
* Sources.txt:
* WebCore.xcodeproj/project.pbxproj:
* fileapi/BlobLoader.h: Added.
(WebCore::BlobLoader::BlobLoader):
(WebCore::BlobLoader::~BlobLoader):
(WebCore::BlobLoader::didFinishLoading):
(WebCore::BlobLoader::didFail):
(WebCore::BlobLoader::complete):
* fileapi/NetworkSendQueue.cpp: Added.
(WebCore::NetworkSendQueue::NetworkSendQueue):
(WebCore::NetworkSendQueue::enqueue):
(WebCore::NetworkSendQueue::clear):
(WebCore::NetworkSendQueue::processMessages):
* fileapi/NetworkSendQueue.h: Added.

Source/WebKit:

Make use of newly added NetworkSendQueue.

* WebProcess/Network/WebSocketChannel.cpp:
(WebKit::WebSocketChannel::createMessageQueue):
(WebKit::WebSocketChannel::WebSocketChannel):
(WebKit::WebSocketChannel::send):
(WebKit::WebSocketChannel::disconnect):
* WebProcess/Network/WebSocketChannel.h:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@249481 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebCore/ChangeLog
Source/WebCore/Headers.cmake
Source/WebCore/Sources.txt
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/fileapi/BlobLoader.h [new file with mode: 0644]
Source/WebCore/fileapi/NetworkSendQueue.cpp [new file with mode: 0644]
Source/WebCore/fileapi/NetworkSendQueue.h [new file with mode: 0644]
Source/WebKit/ChangeLog
Source/WebKit/WebProcess/Network/WebSocketChannel.cpp
Source/WebKit/WebProcess/Network/WebSocketChannel.h

index f5400d5..fe04eac 100644 (file)
@@ -1,3 +1,32 @@
+2019-09-04  Youenn Fablet  <youenn@apple.com>
+
+        Abstract out WebSocketChannel message queue
+        https://bugs.webkit.org/show_bug.cgi?id=201359
+
+        Reviewed by Alex Christensen.
+
+        Move BlobLoader in its own file.
+        Introduce NetworkSendQueue class to handle the sending of messages, some of them being blobs.
+        This class ensures that messages will be sent in order, even though blob data is resolved asynchronously.
+
+        Covered by existing tests.
+
+        * Headers.cmake:
+        * Sources.txt:
+        * WebCore.xcodeproj/project.pbxproj:
+        * fileapi/BlobLoader.h: Added.
+        (WebCore::BlobLoader::BlobLoader):
+        (WebCore::BlobLoader::~BlobLoader):
+        (WebCore::BlobLoader::didFinishLoading):
+        (WebCore::BlobLoader::didFail):
+        (WebCore::BlobLoader::complete):
+        * fileapi/NetworkSendQueue.cpp: Added.
+        (WebCore::NetworkSendQueue::NetworkSendQueue):
+        (WebCore::NetworkSendQueue::enqueue):
+        (WebCore::NetworkSendQueue::clear):
+        (WebCore::NetworkSendQueue::processMessages):
+        * fileapi/NetworkSendQueue.h: Added.
+
 2019-09-04  Rob Buis  <rbuis@igalia.com>
 
         Allow checking whether image was created from JavaScript
index be8564e..98604cf 100644 (file)
@@ -519,6 +519,7 @@ set(WebCore_PRIVATE_FRAMEWORK_HEADERS
     fileapi/FileList.h
     fileapi/FileReaderLoader.h
     fileapi/FileReaderLoaderClient.h
+    fileapi/NetworkSendQueue.h
 
     history/BackForwardClient.h
     history/BackForwardController.h
index d405817..c9b113c 100644 (file)
@@ -1056,6 +1056,7 @@ fileapi/FileList.cpp
 fileapi/FileReader.cpp
 fileapi/FileReaderLoader.cpp
 fileapi/FileReaderSync.cpp
+fileapi/NetworkSendQueue.cpp
 fileapi/ThreadableBlobRegistry.cpp
 
 history/BackForwardController.cpp
index 0b6f464..394155a 100644 (file)
                41DE7C7D222DA14800532B65 /* StorageQuotaUser.h in Headers */ = {isa = PBXBuildFile; fileRef = 41DE7C78222DA13C00532B65 /* StorageQuotaUser.h */; settings = {ATTRIBUTES = (Private, ); }; };
                41DEFCB61E56C1BD000D9E5F /* JSDOMMapLike.h in Headers */ = {isa = PBXBuildFile; fileRef = 41DEFCB41E56C1B9000D9E5F /* JSDOMMapLike.h */; };
                41E1B1D10FF5986900576B3B /* AbstractWorker.h in Headers */ = {isa = PBXBuildFile; fileRef = 41E1B1CB0FF5986900576B3B /* AbstractWorker.h */; };
+               41E9DCE7231974BF00F35949 /* BlobLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = 41E9DCE4231973FE00F35949 /* BlobLoader.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               41E9DCE92319CA7600F35949 /* NetworkSendQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 41E9DCE82319CA7500F35949 /* NetworkSendQueue.h */; settings = {ATTRIBUTES = (Private, ); }; };
                41F062140F5F192600A07EAC /* InspectorDatabaseResource.h in Headers */ = {isa = PBXBuildFile; fileRef = 41F062120F5F192600A07EAC /* InspectorDatabaseResource.h */; };
                41F1D21F0EF35C2A00DA8753 /* ScriptCachedFrameData.h in Headers */ = {isa = PBXBuildFile; fileRef = 41F1D21D0EF35C2A00DA8753 /* ScriptCachedFrameData.h */; settings = {ATTRIBUTES = (Private, ); }; };
                41FABD2D1F4DFE4A006A6C97 /* DOMCacheEngine.h in Headers */ = {isa = PBXBuildFile; fileRef = 41FABD2B1F4DFE42006A6C97 /* DOMCacheEngine.h */; settings = {ATTRIBUTES = (Private, ); }; };
                41E593FF214865AA00D3CB61 /* RTCRtpEncodingParameters.idl */ = {isa = PBXFileReference; lastKnownFileType = text; path = RTCRtpEncodingParameters.idl; sourceTree = "<group>"; };
                41E59400214865AA00D3CB61 /* RTCRtpHeaderExtensionParameters.idl */ = {isa = PBXFileReference; lastKnownFileType = text; path = RTCRtpHeaderExtensionParameters.idl; sourceTree = "<group>"; };
                41E59401214865AB00D3CB61 /* RTCRtpFecParameters.idl */ = {isa = PBXFileReference; lastKnownFileType = text; path = RTCRtpFecParameters.idl; sourceTree = "<group>"; };
+               41E9DCE4231973FE00F35949 /* BlobLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BlobLoader.h; sourceTree = "<group>"; };
+               41E9DCE62319742300F35949 /* BlobLineEndings.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = BlobLineEndings.idl; sourceTree = "<group>"; };
+               41E9DCE82319CA7500F35949 /* NetworkSendQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NetworkSendQueue.h; sourceTree = "<group>"; };
+               41E9DCEA2319CAE800F35949 /* NetworkSendQueue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NetworkSendQueue.cpp; sourceTree = "<group>"; };
                41F062120F5F192600A07EAC /* InspectorDatabaseResource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InspectorDatabaseResource.h; sourceTree = "<group>"; };
                41F062130F5F192600A07EAC /* InspectorDatabaseResource.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InspectorDatabaseResource.cpp; sourceTree = "<group>"; };
                41F1D21D0EF35C2A00DA8753 /* ScriptCachedFrameData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScriptCachedFrameData.h; sourceTree = "<group>"; };
                7C77C3D21DEF178E00A50BFA /* JSBlobPropertyBag.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSBlobPropertyBag.cpp; sourceTree = "<group>"; };
                7C77C3D31DEF178E00A50BFA /* JSBlobPropertyBag.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSBlobPropertyBag.h; sourceTree = "<group>"; };
                7C77C3D61DEF850A00A50BFA /* BlobLineEndings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BlobLineEndings.h; sourceTree = "<group>"; };
-               7C77C3D81DEF854000A50BFA /* BlobLineEndings.idl */ = {isa = PBXFileReference; lastKnownFileType = text; path = BlobLineEndings.idl; sourceTree = "<group>"; };
                7C77C3D91DEF86D700A50BFA /* JSBlobLineEndings.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSBlobLineEndings.cpp; sourceTree = "<group>"; };
                7C77C3DA1DEF86D700A50BFA /* JSBlobLineEndings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSBlobLineEndings.h; sourceTree = "<group>"; };
                7C7903B01F86F95C00463A70 /* ImageBitmapRenderingContext.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ImageBitmapRenderingContext.h; sourceTree = "<group>"; };
                                A15D75131E68F7B100A35FBC /* BlobCallback.h */,
                                A15D75141E68F7B100A35FBC /* BlobCallback.idl */,
                                7C77C3D61DEF850A00A50BFA /* BlobLineEndings.h */,
-                               7C77C3D81DEF854000A50BFA /* BlobLineEndings.idl */,
+                               41E9DCE62319742300F35949 /* BlobLineEndings.idl */,
+                               41E9DCE4231973FE00F35949 /* BlobLoader.h */,
                                7C77C3D01DEE472400A50BFA /* BlobPropertyBag.h */,
                                7C77C3CF1DEE471800A50BFA /* BlobPropertyBag.idl */,
                                976D6C5F122B8A3D001FD1F7 /* BlobURL.cpp */,
                                2EDF369A122C94B4002F7D4E /* FileReaderSync.cpp */,
                                2EDF369B122C94B4002F7D4E /* FileReaderSync.h */,
                                E1AB1EBD14E9E3A800449E13 /* FileReaderSync.idl */,
+                               41E9DCEA2319CAE800F35949 /* NetworkSendQueue.cpp */,
+                               41E9DCE82319CA7500F35949 /* NetworkSendQueue.h */,
                                976D6C75122B8A3D001FD1F7 /* ThreadableBlobRegistry.cpp */,
                                976D6C76122B8A3D001FD1F7 /* ThreadableBlobRegistry.h */,
                        );
                                E1D31CDD19196020001005A3 /* BlobDataFileReference.h in Headers */,
                                4D3B00AF215D6A690076B983 /* BlobEvent.h in Headers */,
                                7C77C3D71DEF850A00A50BFA /* BlobLineEndings.h in Headers */,
+                               41E9DCE7231974BF00F35949 /* BlobLoader.h in Headers */,
                                E1C94AF9191303F000D5A893 /* BlobPart.h in Headers */,
                                7C77C3D11DEE472400A50BFA /* BlobPropertyBag.h in Headers */,
                                2EDEF1F5121B0EFC00726DB2 /* BlobRegistry.h in Headers */,
                                416D75A220C651A500D02D2C /* NetworkLoadInformation.h in Headers */,
                                8A81BF8511DCFD9000DA2B98 /* NetworkLoadMetrics.h in Headers */,
                                59C27F07138D28CF0079B7E2 /* NetworkResourcesData.h in Headers */,
+                               41E9DCE92319CA7600F35949 /* NetworkSendQueue.h in Headers */,
                                1A7FA6190DDA3B3A0028F8A5 /* NetworkStateNotifier.h in Headers */,
                                E13EF3441684ECF40034C83F /* NetworkStorageSession.h in Headers */,
                                269397241A4A5B6400E8349D /* NFA.h in Headers */,
diff --git a/Source/WebCore/fileapi/BlobLoader.h b/Source/WebCore/fileapi/BlobLoader.h
new file mode 100644 (file)
index 0000000..00b32df
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2019 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "Blob.h"
+#include "Document.h"
+#include "FileReaderLoader.h"
+#include "FileReaderLoaderClient.h"
+#include "SharedBuffer.h"
+#include <JavaScriptCore/ArrayBuffer.h>
+#include <wtf/CompletionHandler.h>
+
+namespace WebCore {
+
+class BlobLoader final : public FileReaderLoaderClient {
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    BlobLoader(Document*, Blob&, CompletionHandler<void()>&&);
+    ~BlobLoader();
+
+    bool isLoading() const { return !!m_loader; }
+    const RefPtr<JSC::ArrayBuffer>& result() const { return m_buffer; }
+    int errorCode() const { return m_errorCode; }
+
+private:
+    void didStartLoading() final { }
+    void didReceiveData() final { }
+
+    void didFinishLoading() final;
+    void didFail(int errorCode) final;
+    void complete();
+
+    std::unique_ptr<FileReaderLoader> m_loader;
+    RefPtr<JSC::ArrayBuffer> m_buffer;
+    int m_errorCode { 0 };
+    CompletionHandler<void()> m_completionHandler;
+};
+
+inline BlobLoader::BlobLoader(WebCore::Document* document, Blob& blob, CompletionHandler<void()>&& completionHandler)
+    : m_loader(makeUnique<FileReaderLoader>(FileReaderLoader::ReadAsArrayBuffer, this))
+    , m_completionHandler(WTFMove(completionHandler))
+{
+    m_loader->start(document, blob);
+}
+
+inline BlobLoader::~BlobLoader()
+{
+    if (m_loader)
+        m_loader->cancel();
+}
+
+inline void BlobLoader::didFinishLoading()
+{
+    m_buffer = m_loader->arrayBufferResult();
+    complete();
+}
+
+inline void BlobLoader::didFail(int errorCode)
+{
+    m_errorCode = errorCode;
+    complete();
+}
+
+inline void BlobLoader::complete()
+{
+    m_loader = nullptr;
+    m_completionHandler();
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/fileapi/NetworkSendQueue.cpp b/Source/WebCore/fileapi/NetworkSendQueue.cpp
new file mode 100644 (file)
index 0000000..79bec58
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2019 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "NetworkSendQueue.h"
+
+#include "BlobLoader.h"
+
+namespace WebCore {
+
+NetworkSendQueue::NetworkSendQueue(Document& document, WriteString&& writeString, WriteRawData&& writeRawData, ProcessError&& processError)
+    : m_document(makeWeakPtr(document))
+    , m_writeString(WTFMove(writeString))
+    , m_writeRawData(WTFMove(writeRawData))
+    , m_processError(WTFMove(processError))
+{
+}
+
+NetworkSendQueue::~NetworkSendQueue() = default;
+
+void NetworkSendQueue::enqueue(const String& data)
+{
+    if (m_queue.isEmpty()) {
+        m_writeString(data);
+        return;
+    }
+    m_queue.append(data);
+}
+
+void NetworkSendQueue::enqueue(const JSC::ArrayBuffer& binaryData, unsigned byteOffset, unsigned byteLength)
+{
+    if (m_queue.isEmpty()) {
+        auto* data = static_cast<const char*>(binaryData.data());
+        m_writeRawData(data + byteOffset, byteLength);
+        return;
+    }
+    m_queue.append(SharedBuffer::create(static_cast<const uint8_t*>(binaryData.data()) + byteOffset, byteLength));
+}
+
+void NetworkSendQueue::enqueue(WebCore::Blob& blob)
+{
+    auto byteLength = blob.size();
+    if (!byteLength) {
+        enqueue(JSC::ArrayBuffer::create(byteLength, 1), 0, 0);
+        return;
+    }
+    m_queue.append(makeUniqueRef<BlobLoader>(m_document.get(), blob, [this] {
+        processMessages();
+    }));
+}
+
+void NetworkSendQueue::clear()
+{
+    m_queue.clear();
+}
+
+void NetworkSendQueue::processMessages()
+{
+    while (!m_queue.isEmpty()) {
+        bool shouldStopProcessing = false;
+        switchOn(m_queue.first(), [this](const String& message) {
+            m_writeString(message);
+        }, [this](Ref<SharedBuffer>& data) {
+            m_writeRawData(data->data(), data->size());
+        }, [this, &shouldStopProcessing](UniqueRef<BlobLoader>& loader) {
+            if (loader->isLoading() || loader->errorCode() == FileError::ABORT_ERR) {
+                shouldStopProcessing = true;
+                return;
+            }
+
+            if (const auto& result = loader->result()) {
+                m_writeRawData(static_cast<const char*>(result->data()), result->byteLength());
+                return;
+            }
+            ASSERT(loader->errorCode());
+            shouldStopProcessing = m_processError(loader->errorCode()) == Continue::No;
+        });
+        if (shouldStopProcessing)
+            return;
+        m_queue.removeFirst();
+    }
+
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/fileapi/NetworkSendQueue.h b/Source/WebCore/fileapi/NetworkSendQueue.h
new file mode 100644 (file)
index 0000000..8d4089c
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2019 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <wtf/Deque.h>
+#include <wtf/Function.h>
+#include <wtf/UniqueRef.h>
+#include <wtf/Variant.h>
+
+namespace JSC {
+class ArrayBuffer;
+}
+
+namespace WebCore {
+
+class Blob;
+class BlobLoader;
+class Document;
+class SharedBuffer;
+
+class WEBCORE_EXPORT NetworkSendQueue {
+public:
+    using WriteString = Function<void(const String&)>;
+    using WriteRawData = Function<void(const char*, size_t)>;
+    enum class Continue { No, Yes };
+    using ProcessError = Function<Continue(int)>;
+    NetworkSendQueue(Document&, WriteString&&, WriteRawData&&, ProcessError&&);
+    ~NetworkSendQueue();
+
+    void enqueue(const String&);
+    void enqueue(const JSC::ArrayBuffer&, unsigned byteOffset, unsigned byteLength);
+    void enqueue(Blob&);
+
+    void clear();
+
+private:
+    void processMessages();
+
+    using Message = Variant<String, Ref<SharedBuffer>, UniqueRef<BlobLoader>>;
+    Deque<Message> m_queue;
+
+    WeakPtr<Document> m_document;
+
+    WriteString m_writeString;
+    WriteRawData m_writeRawData;
+    ProcessError m_processError;
+};
+
+} // namespace WebCore
index 5015730..b5b2168 100644 (file)
@@ -1,5 +1,21 @@
 2019-09-04  Youenn Fablet  <youenn@apple.com>
 
+        Abstract out WebSocketChannel message queue
+        https://bugs.webkit.org/show_bug.cgi?id=201359
+
+        Reviewed by Alex Christensen.
+
+        Make use of newly added NetworkSendQueue.
+
+        * WebProcess/Network/WebSocketChannel.cpp:
+        (WebKit::WebSocketChannel::createMessageQueue):
+        (WebKit::WebSocketChannel::WebSocketChannel):
+        (WebKit::WebSocketChannel::send):
+        (WebKit::WebSocketChannel::disconnect):
+        * WebProcess/Network/WebSocketChannel.h:
+
+2019-09-04  Youenn Fablet  <youenn@apple.com>
+
         Move MessageRegistry to NetworkProcess
         https://bugs.webkit.org/show_bug.cgi?id=201299
 
index 2e57af2..3e79f9a 100644 (file)
 #include "WebProcess.h"
 #include <WebCore/Blob.h>
 #include <WebCore/Document.h>
-#include <WebCore/FileReaderLoader.h>
-#include <WebCore/FileReaderLoaderClient.h>
-#include <WebCore/NotImplemented.h>
 #include <WebCore/WebSocketChannel.h>
 #include <WebCore/WebSocketChannelClient.h>
-#include <pal/SessionID.h>
 #include <wtf/CheckedArithmetic.h>
 
+using namespace WebCore;
+
 namespace WebKit {
 
-Ref<WebSocketChannel> WebSocketChannel::create(WebCore::Document& document, WebCore::WebSocketChannelClient& client)
+Ref<WebSocketChannel> WebSocketChannel::create(Document& document, WebSocketChannelClient& client)
 {
     return adoptRef(*new WebSocketChannel(document, client));
 }
 
-WebSocketChannel::WebSocketChannel(WebCore::Document& document, WebCore::WebSocketChannelClient& client)
+NetworkSendQueue WebSocketChannel::createMessageQueue(Document& document, WebSocketChannel& channel)
+{
+    return { document, [&channel](auto& string) {
+        auto byteLength = string.sizeInBytes();
+        channel.sendMessage(Messages::NetworkSocketChannel::SendString { string }, byteLength);
+    }, [&channel](const char* data, size_t byteLength) {
+        channel.sendMessage(Messages::NetworkSocketChannel::SendData { IPC::DataReference { reinterpret_cast<const uint8_t*>(data), byteLength } }, byteLength);
+    }, [&channel](auto errorCode) {
+        channel.fail(makeString("Failed to load Blob: error code = ", errorCode));
+        return NetworkSendQueue::Continue::No;
+    } };
+}
+
+WebSocketChannel::WebSocketChannel(Document& document, WebSocketChannelClient& client)
     : m_document(makeWeakPtr(document))
     , m_client(makeWeakPtr(client))
+    , m_messageQueue(createMessageQueue(document, *this))
 {
 }
 
@@ -132,102 +144,13 @@ template<typename T> void WebSocketChannel::sendMessage(T&& message, size_t byte
     sendWithAsyncReply(WTFMove(message), WTFMove(completionHandler));
 }
 
-class BlobLoader final : public WebCore::FileReaderLoaderClient {
-    WTF_MAKE_FAST_ALLOCATED;
-public:
-    BlobLoader(WebCore::Document* document, WebCore::Blob& blob, CompletionHandler<void()>&& completionHandler)
-        : m_loader(makeUnique<WebCore::FileReaderLoader>(WebCore::FileReaderLoader::ReadAsArrayBuffer, this))
-        , m_completionHandler(WTFMove(completionHandler))
-    {
-        m_loader->start(document, blob);
-    }
-
-    ~BlobLoader()
-    {
-        if (m_loader)
-            m_loader->cancel();
-    }
-
-    bool isLoading() const { return !!m_loader; }
-    const RefPtr<JSC::ArrayBuffer>& result() const { return m_buffer; }
-    Optional<int> errorCode() const { return m_errorCode; }
-
-private:
-    void didStartLoading() final { }
-    void didReceiveData() final { }
-
-    void didFinishLoading() final
-    {
-        m_buffer = m_loader->arrayBufferResult();
-        complete();
-    }
-
-    void didFail(int errorCode) final
-    {
-        m_errorCode = errorCode;
-        complete();
-    }
-
-    void complete()
-    {
-        m_loader = nullptr;
-        m_completionHandler();
-    }
-
-    std::unique_ptr<WebCore::FileReaderLoader> m_loader;
-    RefPtr<JSC::ArrayBuffer> m_buffer;
-    Optional<int> m_errorCode;
-    CompletionHandler<void()> m_completionHandler;
-};
-
-class PendingMessage {
-    WTF_MAKE_FAST_ALLOCATED;
-public:
-    enum class Type { Text, Binary, Blob };
-
-    explicit PendingMessage(const String& message)
-        : m_type(Type::Text)
-        , m_textMessage(message)
-    {
-    }
-
-    PendingMessage(const JSC::ArrayBuffer& binaryData, unsigned byteOffset, unsigned byteLength)
-        : m_type(Type::Binary)
-        , m_binaryData(WebCore::SharedBuffer::create(static_cast<const uint8_t*>(binaryData.data()) + byteOffset, byteLength))
-    {
-    }
-
-    PendingMessage(WebCore::Document* document, WebCore::Blob& blob, CompletionHandler<void()>&& completionHandler)
-        : m_type(Type::Blob)
-        , m_blobLoader(makeUnique<BlobLoader>(document, blob, WTFMove(completionHandler)))
-    {
-    }
-
-    ~PendingMessage() = default;
-
-    Type type() const { return m_type; }
-    const String& textMessage() const { ASSERT(m_type == Type::Text); return m_textMessage; }
-    const WebCore::SharedBuffer& binaryData() const { ASSERT(m_type == Type::Binary); return *m_binaryData; }
-    const BlobLoader& blobLoader() const { ASSERT(m_type == Type::Blob); return *m_blobLoader; }
-
-private:
-    Type m_type;
-    String m_textMessage;
-    RefPtr<WebCore::SharedBuffer> m_binaryData;
-    std::unique_ptr<BlobLoader> m_blobLoader;
-};
-
 WebSocketChannel::SendResult WebSocketChannel::send(const String& message)
 {
     auto byteLength = message.sizeInBytes();
     if (!increaseBufferedAmount(byteLength))
         return SendFail;
 
-    if (m_pendingMessages.isEmpty())
-        sendMessage(Messages::NetworkSocketChannel::SendString { message }, byteLength);
-    else
-        m_pendingMessages.append(makeUnique<PendingMessage>(message));
-
+    m_messageQueue.enqueue(message);
     return SendSuccess;
 }
 
@@ -236,53 +159,20 @@ WebSocketChannel::SendResult WebSocketChannel::send(const JSC::ArrayBuffer& bina
     if (!increaseBufferedAmount(byteLength))
         return SendFail;
 
-    if (m_pendingMessages.isEmpty())
-        sendMessage(Messages::NetworkSocketChannel::SendData { IPC::DataReference { static_cast<const uint8_t*>(binaryData.data()) + byteOffset, byteLength } }, byteLength);
-    else
-        m_pendingMessages.append(makeUnique<PendingMessage>(binaryData, byteOffset, byteLength));
-
+    m_messageQueue.enqueue(binaryData, byteOffset, byteLength);
     return SendSuccess;
 }
 
-WebSocketChannel::SendResult WebSocketChannel::send(WebCore::Blob& blob)
+WebSocketChannel::SendResult WebSocketChannel::send(Blob& blob)
 {
-    // Avoid the Blob queue and loading for empty blobs.
+    auto byteLength = blob.size();
     if (!blob.size())
-        return send(JSC::ArrayBuffer::create(blob.size(), 1), 0, 0);
-
-    m_pendingMessages.append(makeUnique<PendingMessage>(m_document.get(), blob, [this] {
-        while (!m_pendingMessages.isEmpty()) {
-            auto& message = m_pendingMessages.first();
-
-            switch (message->type()) {
-            case PendingMessage::Type::Text:
-                sendMessage(Messages::NetworkSocketChannel::SendString { message->textMessage() }, message->textMessage().sizeInBytes());
-                break;
-            case PendingMessage::Type::Binary: {
-                const auto& binaryData = message->binaryData();
-                sendMessage(Messages::NetworkSocketChannel::SendData { IPC::DataReference { reinterpret_cast<const uint8_t*>(binaryData.data()), binaryData.size() } }, binaryData.size());
-                break;
-            }
-            case PendingMessage::Type::Blob: {
-                auto& loader = message->blobLoader();
-                if (loader.isLoading())
-                    return;
-
-                if (const auto& result = loader.result()) {
-                    auto byteLength = result->byteLength();
-                    if (increaseBufferedAmount(byteLength))
-                        sendMessage(Messages::NetworkSocketChannel::SendData { IPC::DataReference { reinterpret_cast<const uint8_t*>(result->data()), byteLength } }, byteLength);
-                } else if (auto errorCode = loader.errorCode())
-                    fail(makeString("Failed to load Blob: error code = ", errorCode.value()));
-                else
-                    ASSERT_NOT_REACHED();
-                break;
-            }
-            }
-
-            m_pendingMessages.removeFirst();
-        }
-    }));
+        return send(JSC::ArrayBuffer::create(byteLength, 1), 0, 0);
+
+    if (!increaseBufferedAmount(byteLength))
+        return SendFail;
+
+    m_messageQueue.enqueue(blob);
     return SendSuccess;
 }
 
@@ -316,7 +206,7 @@ void WebSocketChannel::disconnect()
     m_client = nullptr;
     m_document = nullptr;
     m_pendingTasks.clear();
-    m_pendingMessages.clear();
+    m_messageQueue.clear();
 
     MessageSender::send(Messages::NetworkSocketChannel::Close { 0, { } });
 }
index 6cc7134..a49d7b8 100644 (file)
@@ -27,9 +27,9 @@
 
 #include "MessageReceiver.h"
 #include "MessageSender.h"
+#include <WebCore/NetworkSendQueue.h>
 #include <WebCore/ThreadableWebSocketChannel.h>
 #include <pal/SessionID.h>
-#include <wtf/Deque.h>
 #include <wtf/Identified.h>
 #include <wtf/WeakPtr.h>
 
@@ -41,8 +41,6 @@ class DataReference;
 
 namespace WebKit {
 
-class PendingMessage;
-
 class WebSocketChannel : public IPC::MessageSender, public IPC::MessageReceiver, public WebCore::ThreadableWebSocketChannel, public RefCounted<WebSocketChannel>, public Identified<WebSocketChannel> {
 public:
     static Ref<WebSocketChannel> create(WebCore::Document&, WebCore::WebSocketChannelClient&);
@@ -58,6 +56,8 @@ public:
 private:
     WebSocketChannel(WebCore::Document&, WebCore::WebSocketChannelClient&);
 
+    static WebCore::NetworkSendQueue createMessageQueue(WebCore::Document&, WebSocketChannel&);
+
     // ThreadableWebSocketChannel
     ConnectStatus connect(const URL&, const String& protocol) final;
     String subprotocol() final;
@@ -98,7 +98,7 @@ private:
     bool m_isClosing { false };
     bool m_isSuspended { false };
     Deque<Function<void()>> m_pendingTasks;
-    Deque<std::unique_ptr<PendingMessage>> m_pendingMessages;
+    WebCore::NetworkSendQueue m_messageQueue;
 };
 
 } // namespace WebKit