- Revision
- 94162
- Author
- yu...@chromium.org
- Date
- 2011-08-31 01:35:54 -0700 (Wed, 31 Aug 2011)
Log Message
WebSocket: Load Blob in WebSocketChannel
https://bugs.webkit.org/show_bug.cgi?id=67013
Reviewed by Kent Tamura.
Add WebSocketChannel::enqueueBlobFrame(). It makes WebSocketChannel start loading a Blob
and send a WebSocket frame after the Blob is loaded.
While a Blob is being loaded, subsequent send() requests cannot be processed and are blocked.
Pending requests are stored in m_outgoingFrameQueue. When we have finished loading a Blob,
requests in the queue are allowed to get processed.
No new tests are added, because nobody uses enqueueBlobFrame() yet. New tests will be added
when WebSocket.send(Blob) is implemented, and they will cover this code change.
* websockets/WebSocketChannel.cpp:
ref() is called when m_blobLoader is allocated, and deref() is called in didFinishLoading()
or didFail(). This is necessary because WebSocketChannel must be able to receive callbacks
from FileReaderLoader even if the channel is referred from no other objects.
(WebCore::WebSocketChannel::WebSocketChannel):
(WebCore::WebSocketChannel::didStartLoading):
(WebCore::WebSocketChannel::didReceiveData):
(WebCore::WebSocketChannel::didFinishLoading):
(WebCore::WebSocketChannel::didFail):
When we have failed to load a Blob, fail() is called, and eventually didCloseSocketStream()
will be called. It will clean up the pending requests in the queue.
(WebCore::WebSocketChannel::enqueueBlobFrame):
(WebCore::WebSocketChannel::processOutgoingFrameQueue):
(WebCore::WebSocketChannel::abortOutgoingFrameQueue):
Cancel the Blob loader when the outgoing request queue is about to be aborted. The loader
will not invoke didFail() callback once it is canceled, thus we need to call didFail()
manually so that we can free up the loader and decrement the reference count.
Modified Paths
Diff
Modified: trunk/Source/WebCore/ChangeLog (94161 => 94162)
--- trunk/Source/WebCore/ChangeLog 2011-08-31 08:33:38 UTC (rev 94161)
+++ trunk/Source/WebCore/ChangeLog 2011-08-31 08:35:54 UTC (rev 94162)
@@ -1,5 +1,40 @@
2011-08-31 Yuta Kitamura <yu...@chromium.org>
+ WebSocket: Load Blob in WebSocketChannel
+ https://bugs.webkit.org/show_bug.cgi?id=67013
+
+ Reviewed by Kent Tamura.
+
+ Add WebSocketChannel::enqueueBlobFrame(). It makes WebSocketChannel start loading a Blob
+ and send a WebSocket frame after the Blob is loaded.
+
+ While a Blob is being loaded, subsequent send() requests cannot be processed and are blocked.
+ Pending requests are stored in m_outgoingFrameQueue. When we have finished loading a Blob,
+ requests in the queue are allowed to get processed.
+
+ No new tests are added, because nobody uses enqueueBlobFrame() yet. New tests will be added
+ when WebSocket.send(Blob) is implemented, and they will cover this code change.
+
+ * websockets/WebSocketChannel.cpp:
+ ref() is called when m_blobLoader is allocated, and deref() is called in didFinishLoading()
+ or didFail(). This is necessary because WebSocketChannel must be able to receive callbacks
+ from FileReaderLoader even if the channel is referred from no other objects.
+ (WebCore::WebSocketChannel::WebSocketChannel):
+ (WebCore::WebSocketChannel::didStartLoading):
+ (WebCore::WebSocketChannel::didReceiveData):
+ (WebCore::WebSocketChannel::didFinishLoading):
+ (WebCore::WebSocketChannel::didFail):
+ When we have failed to load a Blob, fail() is called, and eventually didCloseSocketStream()
+ will be called. It will clean up the pending requests in the queue.
+ (WebCore::WebSocketChannel::enqueueBlobFrame):
+ (WebCore::WebSocketChannel::processOutgoingFrameQueue):
+ (WebCore::WebSocketChannel::abortOutgoingFrameQueue):
+ Cancel the Blob loader when the outgoing request queue is about to be aborted. The loader
+ will not invoke didFail() callback once it is canceled, thus we need to call didFail()
+ manually so that we can free up the loader and decrement the reference count.
+
+2011-08-31 Yuta Kitamura <yu...@chromium.org>
+
WebSocket: Receive binary message as ArrayBuffer
https://bugs.webkit.org/show_bug.cgi?id=67180
Modified: trunk/Source/WebCore/websockets/WebSocketChannel.cpp (94161 => 94162)
--- trunk/Source/WebCore/websockets/WebSocketChannel.cpp 2011-08-31 08:33:38 UTC (rev 94161)
+++ trunk/Source/WebCore/websockets/WebSocketChannel.cpp 2011-08-31 08:35:54 UTC (rev 94162)
@@ -34,8 +34,12 @@
#include "WebSocketChannel.h"
+#include "ArrayBuffer.h"
+#include "Blob.h"
#include "CookieJar.h"
#include "Document.h"
+#include "FileError.h"
+#include "FileReaderLoader.h"
#include "InspectorInstrumentation.h"
#include "Logging.h"
#include "Page.h"
@@ -102,6 +106,9 @@
, m_hasContinuousFrame(false)
, m_closeEventCode(CloseEventCodeAbnormalClosure)
, m_outgoingFrameQueueStatus(OutgoingFrameQueueOpen)
+#if ENABLE(BLOB)
+ , m_blobLoaderStatus(BlobLoaderNotStarted)
+#endif
{
ASSERT(m_context->isDocument());
Document* document = static_cast<Document*>(m_context);
@@ -324,6 +331,43 @@
{
}
+#if ENABLE(BLOB)
+void WebSocketChannel::didStartLoading()
+{
+ LOG(Network, "WebSocketChannel %p didStartLoading", this);
+ ASSERT(m_blobLoader);
+ ASSERT(m_blobLoaderStatus == BlobLoaderStarted);
+}
+
+void WebSocketChannel::didReceiveData()
+{
+ LOG(Network, "WebSocketChannel %p didReceiveData", this);
+ ASSERT(m_blobLoader);
+ ASSERT(m_blobLoaderStatus == BlobLoaderStarted);
+}
+
+void WebSocketChannel::didFinishLoading()
+{
+ LOG(Network, "WebSocketChannel %p didFinishLoading", this);
+ ASSERT(m_blobLoader);
+ ASSERT(m_blobLoaderStatus == BlobLoaderStarted);
+ m_blobLoaderStatus = BlobLoaderFinished;
+ processOutgoingFrameQueue();
+ deref();
+}
+
+void WebSocketChannel::didFail(int errorCode)
+{
+ LOG(Network, "WebSocketChannel %p didFail %d", this, errorCode);
+ ASSERT(m_blobLoader);
+ ASSERT(m_blobLoaderStatus == BlobLoaderStarted);
+ m_blobLoader.clear();
+ m_blobLoaderStatus = BlobLoaderFailed;
+ fail("Failed to load Blob: error code = " + String::number(errorCode)); // FIXME: Generate human-friendly reason message.
+ deref();
+}
+#endif
+
bool WebSocketChannel::appendToBuffer(const char* data, size_t len)
{
size_t newBufferSize = m_bufferSize + len;
@@ -783,6 +827,18 @@
processOutgoingFrameQueue();
}
+void WebSocketChannel::enqueueBlobFrame(OpCode opCode, const Blob& blob)
+{
+ ASSERT(!m_useHixie76Protocol);
+ ASSERT(m_outgoingFrameQueueStatus == OutgoingFrameQueueOpen);
+ OwnPtr<QueuedFrame> frame = adoptPtr(new QueuedFrame);
+ frame->opCode = opCode;
+ frame->frameType = QueuedFrameTypeBlob;
+ frame->blobData = Blob::create(blob.url(), blob.type(), blob.size());
+ m_outgoingFrameQueue.append(frame.release());
+ processOutgoingFrameQueue();
+}
+
void WebSocketChannel::processOutgoingFrameQueue()
{
ASSERT(!m_useHixie76Protocol);
@@ -804,6 +860,38 @@
fail("Failed to send WebSocket frame.");
break;
+ case QueuedFrameTypeBlob: {
+#if ENABLE(BLOB)
+ switch (m_blobLoaderStatus) {
+ case BlobLoaderNotStarted:
+ ref(); // Will be derefed after didFinishLoading() or didFail().
+ ASSERT(!m_blobLoader);
+ m_blobLoader = adoptPtr(new FileReaderLoader(FileReaderLoader::ReadAsArrayBuffer, this));
+ m_blobLoaderStatus = BlobLoaderStarted;
+ m_blobLoader->start(m_context, frame->blobData.get());
+ m_outgoingFrameQueue.prepend(frame.release());
+ return;
+
+ case BlobLoaderStarted:
+ case BlobLoaderFailed:
+ m_outgoingFrameQueue.prepend(frame.release());
+ return;
+
+ case BlobLoaderFinished: {
+ RefPtr<ArrayBuffer> result = m_blobLoader->arrayBufferResult();
+ m_blobLoader.clear();
+ m_blobLoaderStatus = BlobLoaderNotStarted;
+ if (!sendFrame(frame->opCode, static_cast<const char*>(result->data()), result->byteLength()))
+ fail("Failed to send WebSocket frame.");
+ break;
+ }
+ }
+#else
+ fail("FileReader is not available. Could not send a Blob as WebSocket binary message.");
+#endif
+ break;
+ }
+
default:
ASSERT_NOT_REACHED();
break;
@@ -822,6 +910,12 @@
ASSERT(!m_useHixie76Protocol);
m_outgoingFrameQueue.clear();
m_outgoingFrameQueueStatus = OutgoingFrameQueueClosed;
+#if ENABLE(BLOB)
+ if (m_blobLoaderStatus == BlobLoaderStarted) {
+ m_blobLoader->cancel();
+ didFail(FileError::ABORT_ERR);
+ }
+#endif
}
bool WebSocketChannel::sendFrame(OpCode opCode, const char* data, size_t dataLength)
Modified: trunk/Source/WebCore/websockets/WebSocketChannel.h (94161 => 94162)
--- trunk/Source/WebCore/websockets/WebSocketChannel.h 2011-08-31 08:33:38 UTC (rev 94161)
+++ trunk/Source/WebCore/websockets/WebSocketChannel.h 2011-08-31 08:35:54 UTC (rev 94162)
@@ -33,6 +33,7 @@
#if ENABLE(WEB_SOCKETS)
+#include "FileReaderLoaderClient.h"
#include "SocketStreamHandleClient.h"
#include "ThreadableWebSocketChannel.h"
#include "Timer.h"
@@ -44,12 +45,18 @@
namespace WebCore {
+class Blob;
+class FileReaderLoader;
class ScriptExecutionContext;
class SocketStreamHandle;
class SocketStreamError;
class WebSocketChannelClient;
-class WebSocketChannel : public RefCounted<WebSocketChannel>, public SocketStreamHandleClient, public ThreadableWebSocketChannel {
+class WebSocketChannel : public RefCounted<WebSocketChannel>, public SocketStreamHandleClient, public ThreadableWebSocketChannel
+#if ENABLE(BLOB)
+ , public FileReaderLoaderClient
+#endif
+{
WTF_MAKE_FAST_ALLOCATED;
public:
static PassRefPtr<WebSocketChannel> create(ScriptExecutionContext* context, WebSocketChannelClient* client) { return adoptRef(new WebSocketChannel(context, client)); }
@@ -86,6 +93,14 @@
CloseEventCodeInvalidUTF8 = 1007
};
+#if ENABLE(BLOB)
+ // FileReaderLoaderClient functions.
+ virtual void didStartLoading();
+ virtual void didReceiveData();
+ virtual void didFinishLoading();
+ virtual void didFail(int errorCode);
+#endif
+
using RefCounted<WebSocketChannel>::ref;
using RefCounted<WebSocketChannel>::deref;
@@ -151,8 +166,8 @@
// When hixie-76 protocol is chosen, the queue is not used and messages are sent directly.
enum QueuedFrameType {
QueuedFrameTypeString,
- QueuedFrameTypeVector
- // FIXME: Add QueuedFrameTypeBlob.
+ QueuedFrameTypeVector,
+ QueuedFrameTypeBlob
};
struct QueuedFrame {
OpCode opCode;
@@ -160,11 +175,11 @@
// Only one of the following items is used, according to the value of frameType.
String stringData;
Vector<char> vectorData;
- // FIXME: Add blobData.
+ RefPtr<Blob> blobData;
};
void enqueueTextFrame(const String&);
void enqueueRawFrame(OpCode, const char* data, size_t dataLength);
- // FIXME: Add enqueueBlobFrame().
+ void enqueueBlobFrame(OpCode, const Blob&);
void processOutgoingFrameQueue();
void abortOutgoingFrameQueue();
@@ -186,6 +201,15 @@
bool sendFrame(OpCode, const char* data, size_t dataLength);
bool sendFrameHixie76(const char* data, size_t dataLength);
+#if ENABLE(BLOB)
+ enum BlobLoaderStatus {
+ BlobLoaderNotStarted,
+ BlobLoaderStarted,
+ BlobLoaderFinished,
+ BlobLoaderFailed
+ };
+#endif
+
ScriptExecutionContext* m_context;
WebSocketChannelClient* m_client;
OwnPtr<WebSocketHandshake> m_handshake;
@@ -215,6 +239,12 @@
Deque<OwnPtr<QueuedFrame> > m_outgoingFrameQueue;
OutgoingFrameQueueStatus m_outgoingFrameQueueStatus;
+
+#if ENABLE(BLOB)
+ // FIXME: Load two or more Blobs simultaneously for better performance.
+ OwnPtr<FileReaderLoader> m_blobLoader;
+ BlobLoaderStatus m_blobLoaderStatus;
+#endif
};
} // namespace WebCore