Index: third_party/WebKit/Source/modules/websockets/DocumentWebSocketChannel.cpp |
diff --git a/third_party/WebKit/Source/modules/websockets/DocumentWebSocketChannel.cpp b/third_party/WebKit/Source/modules/websockets/DocumentWebSocketChannel.cpp |
index 797dab0005f0d01223e335dbcce54a896c9580de..e03f57cbcb4f908bc42d09fcff798090c85cdacb 100644 |
--- a/third_party/WebKit/Source/modules/websockets/DocumentWebSocketChannel.cpp |
+++ b/third_party/WebKit/Source/modules/websockets/DocumentWebSocketChannel.cpp |
@@ -34,8 +34,6 @@ |
#include "core/dom/Document.h" |
#include "core/dom/ExecutionContext.h" |
#include "core/fetch/UniqueIdentifier.h" |
-#include "core/fileapi/FileReaderLoader.h" |
-#include "core/fileapi/FileReaderLoaderClient.h" |
#include "core/frame/LocalFrame.h" |
#include "core/inspector/ConsoleMessage.h" |
#include "core/inspector/InspectorInstrumentation.h" |
@@ -60,60 +58,13 @@ using blink::WebSocketHandle; |
namespace blink { |
-class DocumentWebSocketChannel::BlobLoader final : public GarbageCollectedFinalized<DocumentWebSocketChannel::BlobLoader>, public FileReaderLoaderClient { |
-public: |
- BlobLoader(PassRefPtr<BlobDataHandle>, DocumentWebSocketChannel*); |
- ~BlobLoader() override { } |
- |
- void cancel(); |
- |
- // FileReaderLoaderClient functions. |
- void didStartLoading() override { } |
- void didReceiveData() override { } |
- void didFinishLoading() override; |
- void didFail(FileError::ErrorCode) override; |
- |
- DEFINE_INLINE_TRACE() |
- { |
- visitor->trace(m_channel); |
- } |
- |
-private: |
- Member<DocumentWebSocketChannel> m_channel; |
- FileReaderLoader m_loader; |
-}; |
- |
-DocumentWebSocketChannel::BlobLoader::BlobLoader(PassRefPtr<BlobDataHandle> blobDataHandle, DocumentWebSocketChannel* channel) |
- : m_channel(channel) |
- , m_loader(FileReaderLoader::ReadAsArrayBuffer, this) |
-{ |
- m_loader.start(channel->executionContext(), blobDataHandle); |
-} |
- |
-void DocumentWebSocketChannel::BlobLoader::cancel() |
-{ |
- m_loader.cancel(); |
- // didFail will be called immediately. |
- // |this| is deleted here. |
-} |
- |
-void DocumentWebSocketChannel::BlobLoader::didFinishLoading() |
-{ |
- m_channel->didFinishLoadingBlob(m_loader.arrayBufferResult()); |
- // |this| is deleted here. |
-} |
- |
-void DocumentWebSocketChannel::BlobLoader::didFail(FileError::ErrorCode errorCode) |
-{ |
- m_channel->didFailLoadingBlob(errorCode); |
- // |this| is deleted here. |
-} |
- |
DocumentWebSocketChannel::DocumentWebSocketChannel(Document* document, WebSocketChannelClient* client, const String& sourceURL, unsigned lineNumber, WebSocketHandle *handle) |
: ContextLifecycleObserver(document) |
, m_handle(adoptPtr(handle ? handle : Platform::current()->createWebSocketHandle())) |
, m_client(client) |
, m_identifier(createUniqueIdentifier()) |
+ , m_blobLoadingMode(false) |
+ , m_blobDataPending(0) |
, m_sendingQuota(0) |
, m_receivedDataSizeForFlowControl(receivedDataSizeForFlowControlHighWaterMark * 2) // initial quota |
, m_sentSizeOfTopMessage(0) |
@@ -124,7 +75,7 @@ DocumentWebSocketChannel::DocumentWebSocketChannel(Document* document, WebSocket |
DocumentWebSocketChannel::~DocumentWebSocketChannel() |
{ |
- ASSERT(!m_blobLoader); |
+ ASSERT(!m_blobLoadingMode); |
} |
bool DocumentWebSocketChannel::connect(const KURL& url, const String& protocol) |
@@ -255,7 +206,7 @@ void DocumentWebSocketChannel::disconnect() |
TRACE_EVENT_INSTANT1("devtools.timeline", "WebSocketDestroy", TRACE_EVENT_SCOPE_THREAD, "data", InspectorWebSocketEvent::data(document(), m_identifier)); |
InspectorInstrumentation::didCloseWebSocket(document(), m_identifier); |
} |
- abortAsyncOperations(); |
+ m_blobLoadingMode = false; |
m_handle.clear(); |
m_client = nullptr; |
m_identifier = 0; |
@@ -308,11 +259,21 @@ void DocumentWebSocketChannel::sendInternal(WebSocketHandle::MessageType message |
} |
} |
+void DocumentWebSocketChannel::sendBlob(const BlobDataHandle& blob) |
+{ |
+ ASSERT(!m_blobLoadingMode); |
+ m_blobLoadingMode = true; |
+ m_blobDataPending = blob.size(); |
+ m_handle->sendBlob(blob.uuid(), blob.size()); |
+ // The message is still in |m_messages| so that the renderer holds a |
+ // reference to it until it is fully sent. |
+} |
+ |
void DocumentWebSocketChannel::processSendQueue() |
{ |
ASSERT(m_handle); |
uint64_t consumedBufferedAmount = 0; |
- while (!m_messages.isEmpty() && !m_blobLoader) { |
+ while (!m_messages.isEmpty() && !m_blobLoadingMode) { |
Message* message = m_messages.first().get(); |
if (m_sendingQuota == 0 && message->type != MessageTypeClose) |
break; |
@@ -321,8 +282,7 @@ void DocumentWebSocketChannel::processSendQueue() |
sendInternal(WebSocketHandle::MessageTypeText, message->text.data(), message->text.length(), &consumedBufferedAmount); |
break; |
case MessageTypeBlob: |
- ASSERT(!m_blobLoader); |
- m_blobLoader = new BlobLoader(message->blobDataHandle, this); |
+ sendBlob(*message->blobDataHandle); |
break; |
case MessageTypeArrayBuffer: |
sendInternal(WebSocketHandle::MessageTypeBinary, static_cast<const char*>(message->arrayBuffer->data()), message->arrayBuffer->byteLength(), &consumedBufferedAmount); |
@@ -356,18 +316,10 @@ void DocumentWebSocketChannel::flowControlIfNecessary() |
m_receivedDataSizeForFlowControl = 0; |
} |
-void DocumentWebSocketChannel::abortAsyncOperations() |
-{ |
- if (m_blobLoader) { |
- m_blobLoader->cancel(); |
- m_blobLoader.clear(); |
- } |
-} |
- |
void DocumentWebSocketChannel::handleDidClose(bool wasClean, unsigned short code, const String& reason) |
{ |
m_handle.clear(); |
- abortAsyncOperations(); |
+ m_blobLoadingMode = false; |
if (!m_client) { |
return; |
} |
@@ -515,7 +467,21 @@ void DocumentWebSocketChannel::didReceiveFlowControl(WebSocketHandle* handle, in |
ASSERT(quota >= 0); |
m_sendingQuota += quota; |
- processSendQueue(); |
+ if (m_blobLoadingMode) { |
+ uint64_t blobUsedQuota = std::min(static_cast<uint64_t>(quota), m_blobDataPending); |
+ if (blobUsedQuota > 0) { |
+ // Reflect bufferedAmount. If non-Blob messages were sent |
+ // immediately before the Blob, their quota refresh will still be |
+ // counted against bufferedAmount. However, bufferedAmount will |
+ // always be correct when blob loading mode finishes. |
+ m_sendingQuota -= blobUsedQuota; |
+ m_blobDataPending -= blobUsedQuota; |
+ if (m_client) |
+ m_client->didConsumeBufferedAmount(blobUsedQuota); |
+ } |
+ } else { |
+ processSendQueue(); |
+ } |
} |
void DocumentWebSocketChannel::didStartClosingHandshake(WebSocketHandle* handle) |
@@ -529,32 +495,30 @@ void DocumentWebSocketChannel::didStartClosingHandshake(WebSocketHandle* handle) |
m_client->didStartClosingHandshake(); |
} |
-void DocumentWebSocketChannel::didFinishLoadingBlob(PassRefPtr<DOMArrayBuffer> buffer) |
+void DocumentWebSocketChannel::didCompleteSendingBlob(WebSocketHandle* handle) |
{ |
- m_blobLoader.clear(); |
- ASSERT(m_handle); |
- // The loaded blob is always placed on m_messages[0]. |
- ASSERT(m_messages.size() > 0 && m_messages.first()->type == MessageTypeBlob); |
- // We replace it with the loaded blob. |
- m_messages.first() = adoptPtr(new Message(buffer)); |
- processSendQueue(); |
-} |
+ WTF_LOG(Network, "DocumentWebSocketChannel %p didCompleteSendingBlob(%p)", this, handle); |
-void DocumentWebSocketChannel::didFailLoadingBlob(FileError::ErrorCode errorCode) |
-{ |
- m_blobLoader.clear(); |
- if (errorCode == FileError::ABORT_ERR) { |
- // The error is caused by cancel(). |
+ // If the IPC was unexpected, do nothing. |
+ if (!m_blobLoadingMode) |
return; |
- } |
- // FIXME: Generate human-friendly reason message. |
- failAsError("Failed to load Blob: error code = " + String::number(errorCode)); |
- // |this| can be deleted here. |
+ |
+ ASSERT(m_handle); |
+ ASSERT(handle == m_handle); |
+ ASSERT(m_sendingQuota >= m_blobDataPending); |
+ |
+ m_sendingQuota -= m_blobDataPending; |
+ if (m_blobDataPending && m_client) |
+ m_client->didConsumeBufferedAmount(m_blobDataPending); |
+ m_blobDataPending = 0; |
+ m_blobLoadingMode = false; |
+ // Remove the reference to the Blob. |
+ m_messages.removeFirst(); |
+ processSendQueue(); |
} |
DEFINE_TRACE(DocumentWebSocketChannel) |
{ |
- visitor->trace(m_blobLoader); |
visitor->trace(m_client); |
WebSocketChannel::trace(visitor); |
ContextLifecycleObserver::trace(visitor); |