Diff
Modified: trunk/Source/WebCore/ChangeLog (246963 => 246964)
--- trunk/Source/WebCore/ChangeLog 2019-07-01 08:01:19 UTC (rev 246963)
+++ trunk/Source/WebCore/ChangeLog 2019-07-01 08:09:46 UTC (rev 246964)
@@ -1,3 +1,12 @@
+2019-07-01 Carlos Garcia Campos <[email protected]>
+
+ WebSockets: add support for sending blob messages when using web sockets platform APIs
+ https://bugs.webkit.org/show_bug.cgi?id=199189
+
+ Reviewed by Youenn Fablet.
+
+ * Headers.cmake: Add missing headers.
+
2019-07-01 Miguel Gomez <[email protected]>
[WPE][GTK] Content disappearing when using CSS transforms
Modified: trunk/Source/WebCore/Headers.cmake (246963 => 246964)
--- trunk/Source/WebCore/Headers.cmake 2019-07-01 08:01:19 UTC (rev 246963)
+++ trunk/Source/WebCore/Headers.cmake 2019-07-01 08:09:46 UTC (rev 246964)
@@ -515,7 +515,9 @@
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 @@
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
Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (246963 => 246964)
--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj 2019-07-01 08:01:19 UTC (rev 246963)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj 2019-07-01 08:09:46 UTC (rev 246964)
@@ -857,12 +857,12 @@
2E4346510F546A8200B0F1BA /* WorkerObjectProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E43463F0F546A8200B0F1BA /* WorkerObjectProxy.h */; };
2E4346530F546A8200B0F1BA /* WorkerRunLoop.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E4346410F546A8200B0F1BA /* WorkerRunLoop.h */; settings = {ATTRIBUTES = (Private, ); }; };
2E4346550F546A8200B0F1BA /* WorkerThread.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E4346430F546A8200B0F1BA /* WorkerThread.h */; settings = {ATTRIBUTES = (Private, ); }; };
- 2E75841E12779ADA0062628B /* FileReaderLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E75841B12779ADA0062628B /* FileReaderLoader.h */; };
+ 2E75841E12779ADA0062628B /* FileReaderLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E75841B12779ADA0062628B /* FileReaderLoader.h */; settings = {ATTRIBUTES = (Private, ); };};
2E75841F12779ADA0062628B /* FileReaderLoaderClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E75841C12779ADA0062628B /* FileReaderLoaderClient.h */; settings = {ATTRIBUTES = (Private, ); }; };
2E94F43C119207DA00B7F75D /* JSFileReader.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E94F43A119207DA00B7F75D /* JSFileReader.h */; };
2E9B5D8F1B66A94E008C6A24 /* WheelEventDeltaFilterMac.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E9B5D8E1B66A94E008C6A24 /* WheelEventDeltaFilterMac.h */; settings = {ATTRIBUTES = (Private, ); }; };
2EA768040FE7126400AB9C8A /* WorkerScriptLoaderClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 2EA768030FE7126400AB9C8A /* WorkerScriptLoaderClient.h */; settings = {ATTRIBUTES = (Private, ); }; };
- 2EB4BCD3121F03E300EC4885 /* BlobResourceHandle.h in Headers */ = {isa = PBXBuildFile; fileRef = 2EB4BCD1121F03E300EC4885 /* BlobResourceHandle.h */; };
+ 2EB4BCD3121F03E300EC4885 /* BlobResourceHandle.h in Headers */ = {isa = PBXBuildFile; fileRef = 2EB4BCD1121F03E300EC4885 /* BlobResourceHandle.h */; settings = {ATTRIBUTES = (Private, ); }; };
2EB767571DA19BDF003E23B5 /* InputEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 2EB767541DA19B67003E23B5 /* InputEvent.h */; settings = {ATTRIBUTES = (Private, ); }; };
2EBBC3D81B65988300F5253D /* WheelEventDeltaFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 2EBBC3D71B65988300F5253D /* WheelEventDeltaFilter.h */; settings = {ATTRIBUTES = (Private, ); }; };
2ECDBAD121D8903400F00ECD /* UndoManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ECDBACE21D8903400F00ECD /* UndoManager.h */; };
@@ -2804,7 +2804,7 @@
976D6C7C122B8A3D001FD1F7 /* BlobBuilder.h in Headers */ = {isa = PBXBuildFile; fileRef = 976D6C5D122B8A3D001FD1F7 /* BlobBuilder.h */; };
976D6C7F122B8A3D001FD1F7 /* BlobURL.h in Headers */ = {isa = PBXBuildFile; fileRef = 976D6C60122B8A3D001FD1F7 /* BlobURL.h */; };
976D6C81122B8A3D001FD1F7 /* File.h in Headers */ = {isa = PBXBuildFile; fileRef = 976D6C62122B8A3D001FD1F7 /* File.h */; settings = {ATTRIBUTES = (Private, ); }; };
- 976D6C83122B8A3D001FD1F7 /* FileError.h in Headers */ = {isa = PBXBuildFile; fileRef = 976D6C64122B8A3D001FD1F7 /* FileError.h */; };
+ 976D6C83122B8A3D001FD1F7 /* FileError.h in Headers */ = {isa = PBXBuildFile; fileRef = 976D6C64122B8A3D001FD1F7 /* FileError.h */; settings = {ATTRIBUTES = (Private, ); }; };
976D6C86122B8A3D001FD1F7 /* FileList.h in Headers */ = {isa = PBXBuildFile; fileRef = 976D6C67122B8A3D001FD1F7 /* FileList.h */; settings = {ATTRIBUTES = (Private, ); }; };
976D6C89122B8A3D001FD1F7 /* FileReader.h in Headers */ = {isa = PBXBuildFile; fileRef = 976D6C6A122B8A3D001FD1F7 /* FileReader.h */; };
976D6C95122B8A3D001FD1F7 /* ThreadableBlobRegistry.h in Headers */ = {isa = PBXBuildFile; fileRef = 976D6C76122B8A3D001FD1F7 /* ThreadableBlobRegistry.h */; };
Modified: trunk/Source/WebCore/fileapi/FileReaderLoader.h (246963 => 246964)
--- trunk/Source/WebCore/fileapi/FileReaderLoader.h 2019-07-01 08:01:19 UTC (rev 246963)
+++ trunk/Source/WebCore/fileapi/FileReaderLoader.h 2019-07-01 08:09:46 UTC (rev 246964)
@@ -61,11 +61,11 @@
};
// If client is given, do the loading asynchronously. Otherwise, load synchronously.
- FileReaderLoader(ReadType, FileReaderLoaderClient*);
+ WEBCORE_EXPORT FileReaderLoader(ReadType, FileReaderLoaderClient*);
~FileReaderLoader();
- void start(ScriptExecutionContext*, Blob&);
- void cancel();
+ WEBCORE_EXPORT void start(ScriptExecutionContext*, Blob&);
+ WEBCORE_EXPORT void cancel();
// ThreadableLoaderClient
void didReceiveResponse(unsigned long, const ResourceResponse&) override;
@@ -74,7 +74,7 @@
void didFail(const ResourceError&) override;
String stringResult();
- RefPtr<JSC::ArrayBuffer> arrayBufferResult() const;
+ WEBCORE_EXPORT RefPtr<JSC::ArrayBuffer> arrayBufferResult() const;
unsigned bytesLoaded() const { return m_bytesLoaded; }
unsigned totalBytes() const { return m_totalBytes; }
FileError::ErrorCode errorCode() const { return m_errorCode; }
Modified: trunk/Source/WebKit/ChangeLog (246963 => 246964)
--- trunk/Source/WebKit/ChangeLog 2019-07-01 08:01:19 UTC (rev 246963)
+++ trunk/Source/WebKit/ChangeLog 2019-07-01 08:09:46 UTC (rev 246964)
@@ -1,3 +1,30 @@
+2019-07-01 Carlos Garcia Campos <[email protected]>
+
+ WebSockets: add support for sending blob messages when using web sockets platform APIs
+ https://bugs.webkit.org/show_bug.cgi?id=199189
+
+ Reviewed by Youenn Fablet.
+
+ 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-07-01 Miguel Gomez <[email protected]>
[WPE][GTK] Content disappearing when using CSS transforms
Modified: trunk/Source/WebKit/WebProcess/Network/WebSocketChannel.cpp (246963 => 246964)
--- trunk/Source/WebKit/WebProcess/Network/WebSocketChannel.cpp 2019-07-01 08:01:19 UTC (rev 246963)
+++ trunk/Source/WebKit/WebProcess/Network/WebSocketChannel.cpp 2019-07-01 08:09:46 UTC (rev 246964)
@@ -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 @@
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;
- 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));
+ 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));
+
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::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 @@
m_client = nullptr;
m_document = nullptr;
m_pendingTasks.clear();
+ m_pendingMessages.clear();
MessageSender::send(Messages::NetworkSocketChannel::Close { 0, { } });
}
Modified: trunk/Source/WebKit/WebProcess/Network/WebSocketChannel.h (246963 => 246964)
--- trunk/Source/WebKit/WebProcess/Network/WebSocketChannel.h 2019-07-01 08:01:19 UTC (rev 246963)
+++ trunk/Source/WebKit/WebProcess/Network/WebSocketChannel.h 2019-07-01 08:09:46 UTC (rev 246964)
@@ -41,6 +41,8 @@
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 @@
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 @@
bool m_isClosing { false };
bool m_isSuspended { false };
Deque<Function<void()>> m_pendingTasks;
+ Deque<std::unique_ptr<PendingMessage>> m_pendingMessages;
};
} // namespace WebKit