WebKit Bugzilla
Attachment 373016 Details for
Bug 199189
: WebSockets: add support for sending blob messages when using web sockets platform APIs
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch
wk2-websockets-blobs.diff (text/plain), 13.99 KB, created by
Carlos Garcia Campos
on 2019-06-27 04:19:54 PDT
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Carlos Garcia Campos
Created:
2019-06-27 04:19:54 PDT
Size:
13.99 KB
patch
obsolete
>diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog >index cf04002c3a3..1c90d1341bb 100644 >--- a/Source/WebCore/ChangeLog >+++ b/Source/WebCore/ChangeLog >@@ -1,3 +1,12 @@ >+2019-06-27 Carlos Garcia Campos <cgarcia@igalia.com> >+ >+ WebSockets: add support for sending blob messages when using web sockets platform APIs >+ https://bugs.webkit.org/show_bug.cgi?id=199189 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * Headers.cmake: Add missing headers. >+ > 2019-06-27 Carlos Garcia Campos <cgarcia@igalia.com> > > [SOUP] Use libsoup WebSockets API >diff --git a/Source/WebCore/Headers.cmake b/Source/WebCore/Headers.cmake >index a81d82ab8df..017c9129ef0 100644 >--- a/Source/WebCore/Headers.cmake >+++ b/Source/WebCore/Headers.cmake >@@ -515,7 +515,9 @@ set(WebCore_PRIVATE_FRAMEWORK_HEADERS > fileapi/BlobLineEndings.h > fileapi/BlobPropertyBag.h > fileapi/File.h >+ fileapi/FileError.h > fileapi/FileList.h >+ fileapi/FileReaderLoader.h > fileapi/FileReaderLoaderClient.h > > history/BackForwardClient.h >@@ -1168,6 +1170,7 @@ set(WebCore_PRIVATE_FRAMEWORK_HEADERS > platform/network/BlobPart.h > platform/network/BlobRegistry.h > platform/network/BlobRegistryImpl.h >+ platform/network/BlobResourceHandle.h > platform/network/CacheValidation.h > platform/network/CertificateInfoBase.h > platform/network/CookieRequestHeaderFieldProxy.h >diff --git a/Source/WebKit/ChangeLog b/Source/WebKit/ChangeLog >index 3c315d4d081..b1a5ad2d43e 100644 >--- a/Source/WebKit/ChangeLog >+++ b/Source/WebKit/ChangeLog >@@ -1,3 +1,30 @@ >+2019-06-27 Carlos Garcia Campos <cgarcia@igalia.com> >+ >+ WebSockets: add support for sending blob messages when using web sockets platform APIs >+ https://bugs.webkit.org/show_bug.cgi?id=199189 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Add helper private class BlobLoader that uses FileReaderLoader to load the blobs. Since blob loads are >+ asynchronous, the messages are queued using another helper internal class PendingMessage. >+ >+ * WebProcess/Network/WebSocketChannel.cpp: >+ (WebKit::WebSocketChannel::increaseBufferedAmount): Increase the buffered amount checking we don't overlofw. >+ (WebKit::WebSocketChannel::decreaseBufferedAmount): Decrease the buffered amount. >+ (WebKit::WebSocketChannel::sendMessage): Helper class to send message to the network process and decrease the >+ buffered amount when done. >+ (WebKit::WebSocketChannel::send): Queue the message in pending queue if there are pending messages in the queue >+ for text and binary messages. For blobs, always queue the message unless it's an empty blob that we can handle >+ as empty binary data directly. >+ (WebKit::PendingMessage::PendingMessage): Helper class to queue message requests. >+ (WebKit::PendingMessage::type const): Type of message: Text, Binary, Blob. >+ (WebKit::PendingMessage::textMessage const): The text message. >+ (WebKit::PendingMessage::binaryData const): The binary data. >+ (WebKit::PendingMessage::blobLoader const): The blob loader. >+ (WebKit::WebSocketChannel::fail): Notify the client about the error to ensure onclose is emitted. >+ (WebKit::WebSocketChannel::disconnect): Clear the pending messages queue. >+ * WebProcess/Network/WebSocketChannel.h: >+ > 2019-06-27 Carlos Garcia Campos <cgarcia@igalia.com> > > [SOUP] WebSockets: handle TLS certificate and errors >diff --git a/Source/WebKit/WebProcess/Network/WebSocketChannel.cpp b/Source/WebKit/WebProcess/Network/WebSocketChannel.cpp >index 72f7d9c60f2..0fbfb9e395c 100644 >--- a/Source/WebKit/WebProcess/Network/WebSocketChannel.cpp >+++ b/Source/WebKit/WebProcess/Network/WebSocketChannel.cpp >@@ -32,11 +32,15 @@ > #include "NetworkSocketChannelMessages.h" > #include "WebCoreArgumentCoders.h" > #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> > > namespace WebKit { > >@@ -92,43 +96,195 @@ WebSocketChannel::ConnectStatus WebSocketChannel::connect(const URL& url, const > return ConnectStatus::OK; > } > >-WebSocketChannel::SendResult WebSocketChannel::send(const String& message) >+bool WebSocketChannel::increaseBufferedAmount(size_t byteLength) > { >- auto byteLength = message.sizeInBytes(); >- m_bufferedAmount += byteLength; >+ if (!byteLength) >+ return true; >+ >+ Checked<size_t, RecordOverflow> checkedNewBufferedAmount = m_bufferedAmount; >+ checkedNewBufferedAmount += byteLength; >+ if (UNLIKELY(checkedNewBufferedAmount.hasOverflowed())) { >+ fail("Failed to send WebSocket frame: buffer has no more space"); >+ return false; >+ } >+ >+ m_bufferedAmount = checkedNewBufferedAmount.unsafeGet(); > if (m_client) > m_client->didUpdateBufferedAmount(m_bufferedAmount); >+ return true; >+} > >+void WebSocketChannel::decreaseBufferedAmount(size_t byteLength) >+{ >+ if (!byteLength) >+ return; >+ >+ ASSERT(m_bufferedAmount >= byteLength); >+ m_bufferedAmount -= byteLength; >+ if (m_client) >+ m_client->didUpdateBufferedAmount(m_bufferedAmount); >+} >+ >+template<typename T> void WebSocketChannel::sendMessage(T&& message, size_t byteLength) >+{ > CompletionHandler<void()> completionHandler = [this, protectedThis = makeRef(*this), byteLength] { >- ASSERT(m_bufferedAmount >= byteLength); >- m_bufferedAmount -= byteLength; >- if (m_client) >- m_client->didUpdateBufferedAmount(m_bufferedAmount); >+ decreaseBufferedAmount(byteLength); > }; >- sendWithAsyncReply(Messages::NetworkSocketChannel::SendString { message }, WTFMove(completionHandler)); >+ sendWithAsyncReply(WTFMove(message), WTFMove(completionHandler)); >+} >+ >+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(std::make_unique<PendingMessage>(message)); >+ > return SendSuccess; > } > > WebSocketChannel::SendResult WebSocketChannel::send(const JSC::ArrayBuffer& binaryData, unsigned byteOffset, unsigned byteLength) > { >- m_bufferedAmount += byteLength; >- if (m_client) >- m_client->didUpdateBufferedAmount(m_bufferedAmount); >+ 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(std::make_unique<PendingMessage>(binaryData, byteOffset, byteLength)); > >- CompletionHandler<void()> completionHandler = [this, protectedThis = makeRef(*this), byteLength] { >- ASSERT(m_bufferedAmount >= byteLength); >- m_bufferedAmount -= byteLength; >- if (m_client) >- m_client->didUpdateBufferedAmount(m_bufferedAmount); >- }; >- sendWithAsyncReply(Messages::NetworkSocketChannel::SendData { IPC::DataReference { static_cast<const uint8_t*>(binaryData.data()) + byteOffset, byteLength } }, WTFMove(completionHandler)); > return SendSuccess; > } > >-WebSocketChannel::SendResult WebSocketChannel::send(WebCore::Blob&) >+class BlobLoader final : public WebCore::FileReaderLoaderClient { >+ WTF_MAKE_FAST_ALLOCATED; >+public: >+ BlobLoader(WebCore::Document* document, Blob& blob, CompletionHandler<void()>&& completionHandler) >+ : m_loader(std::make_unique<FileReaderLoader>(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, Blob& blob, CompletionHandler<void()>&& completionHandler) >+ : m_type(Type::Blob) >+ , m_blobLoader(std::make_unique<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(WebCore::Blob& blob) > { >- notImplemented(); >- return SendFail; >+ // Avoid the Blob queue and loading for empty blobs. >+ if (!blob.size()) >+ return send(JSC::ArrayBuffer::create(blob.size(), 1), 0, 0); >+ >+ m_pendingMessages.append(std::make_unique<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 SendSuccess; > } > > unsigned WebSocketChannel::bufferedAmount() const >@@ -149,7 +305,11 @@ void WebSocketChannel::close(int code, const String& reason) > > void WebSocketChannel::fail(const String& reason) > { >- MessageSender::send(Messages::NetworkSocketChannel::Close { 0, reason }); >+ if (m_client) >+ m_client->didReceiveMessageError(); >+ >+ if (!m_isClosing) >+ MessageSender::send(Messages::NetworkSocketChannel::Close { 0, reason }); > } > > void WebSocketChannel::disconnect() >@@ -157,6 +317,7 @@ void WebSocketChannel::disconnect() > m_client = nullptr; > m_document = nullptr; > m_pendingTasks.clear(); >+ m_pendingMessages.clear(); > > MessageSender::send(Messages::NetworkSocketChannel::Close { 0, { } }); > } >diff --git a/Source/WebKit/WebProcess/Network/WebSocketChannel.h b/Source/WebKit/WebProcess/Network/WebSocketChannel.h >index 1b4a552835a..ea95b73db91 100644 >--- a/Source/WebKit/WebProcess/Network/WebSocketChannel.h >+++ b/Source/WebKit/WebProcess/Network/WebSocketChannel.h >@@ -41,6 +41,8 @@ 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&); >@@ -83,6 +85,9 @@ private: > IPC::Connection* messageSenderConnection() const final; > uint64_t messageSenderDestinationID() const final; > >+ bool increaseBufferedAmount(size_t); >+ void decreaseBufferedAmount(size_t); >+ template<typename T> void sendMessage(T&&, size_t byteLength); > void enqueueTask(Function<void()>&&); > > WeakPtr<WebCore::Document> m_document; >@@ -92,6 +97,7 @@ private: > bool m_isClosing { false }; > bool m_isSuspended { false }; > Deque<Function<void()>> m_pendingTasks; >+ Deque<std::unique_ptr<PendingMessage>> m_pendingMessages; > }; > > } // namespace WebKit
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 199189
:
372834
|
372915
|
373016
|
373019
|
373029
|
373031
|
373095