Title: [246964] trunk/Source
Revision
246964
Author
[email protected]
Date
2019-07-01 01:09:46 -0700 (Mon, 01 Jul 2019)

Log Message

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.

Source/WebCore:

* Headers.cmake: Add missing headers.

Source/WebKit:

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:

Modified Paths

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
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to