#ifndef MainThreadWebSocketChannel_h
#define MainThreadWebSocketChannel_h
#include "core/fileapi/FileError.h"
#include "core/fileapi/FileReaderLoaderClient.h"
#include "core/frame/ConsoleTypes.h"
#include "modules/websockets/WebSocketChannel.h"
#include "modules/websockets/WebSocketDeflateFramer.h"
#include "modules/websockets/WebSocketFrame.h"
#include "modules/websockets/WebSocketHandshake.h"
#include "modules/websockets/WebSocketPerMessageDeflate.h"
#include "platform/Timer.h"
#include "platform/network/SocketStreamHandleClient.h"
#include "wtf/Deque.h"
#include "wtf/Forward.h"
#include "wtf/PassOwnPtr.h"
#include "wtf/RefCounted.h"
#include "wtf/Vector.h"
#include "wtf/text/CString.h"
namespace WebCore {
class BlobDataHandle;
class Document;
class FileReaderLoader;
class SocketStreamHandle;
class SocketStreamError;
class WebSocketChannelClient;
class MainThreadWebSocketChannel FINAL : public RefCounted<MainThreadWebSocketChannel>, public SocketStreamHandleClient, public WebSocketChannel, public FileReaderLoaderClient {
WTF_MAKE_FAST_ALLOCATED;
public:
static PassRefPtr<MainThreadWebSocketChannel> create(Document* document, WebSocketChannelClient* client, const String& sourceURL = String(), unsigned lineNumber = 0) { return adoptRef(new MainThreadWebSocketChannel(document, client, sourceURL, lineNumber)); }
virtual ~MainThreadWebSocketChannel();
bool send(const char* data, int length);
virtual void connect(const KURL&, const String& protocol) OVERRIDE;
virtual String subprotocol() OVERRIDE;
virtual String extensions() OVERRIDE;
virtual WebSocketChannel::SendResult send(const String& message) OVERRIDE;
virtual WebSocketChannel::SendResult send(const ArrayBuffer&, unsigned byteOffset, unsigned byteLength) OVERRIDE;
virtual WebSocketChannel::SendResult send(PassRefPtr<BlobDataHandle>) OVERRIDE;
virtual unsigned long bufferedAmount() const OVERRIDE;
virtual void close(int code, const String& reason) OVERRIDE;
virtual void fail(const String& reason, MessageLevel, const String&, unsigned lineNumber) OVERRIDE;
using WebSocketChannel::fail;
virtual void disconnect() OVERRIDE;
virtual void suspend() OVERRIDE;
virtual void resume() OVERRIDE;
virtual void willOpenSocketStream(SocketStreamHandle*) OVERRIDE;
virtual void didOpenSocketStream(SocketStreamHandle*) OVERRIDE;
virtual void didCloseSocketStream(SocketStreamHandle*) OVERRIDE;
virtual void didReceiveSocketStreamData(SocketStreamHandle*, const char*, int) OVERRIDE;
virtual void didUpdateBufferedAmount(SocketStreamHandle*, size_t bufferedAmount) OVERRIDE;
virtual void didFailSocketStream(SocketStreamHandle*, const SocketStreamError&) OVERRIDE;
virtual void didStartLoading() OVERRIDE;
virtual void didReceiveData() OVERRIDE;
virtual void didFinishLoading() OVERRIDE;
virtual void didFail(FileError::ErrorCode) OVERRIDE;
using RefCounted<MainThreadWebSocketChannel>::ref;
using RefCounted<MainThreadWebSocketChannel>::deref;
protected:
virtual void refWebSocketChannel() OVERRIDE { ref(); }
virtual void derefWebSocketChannel() OVERRIDE { deref(); }
private:
MainThreadWebSocketChannel(Document*, WebSocketChannelClient*, const String&, unsigned);
void clearDocument();
void disconnectHandle();
void callDidReceiveMessageError();
bool appendToBuffer(const char* data, size_t len);
void skipBuffer(size_t len);
void processBuffer();
bool processOneItemFromBuffer();
void resumeTimerFired(Timer<MainThreadWebSocketChannel>*);
void startClosingHandshake(int code, const String& reason);
void closingTimerFired(Timer<MainThreadWebSocketChannel>*);
bool processFrame();
enum QueuedFrameType {
QueuedFrameTypeString,
QueuedFrameTypeVector,
QueuedFrameTypeBlob
};
struct QueuedFrame {
WebSocketFrame::OpCode opCode;
QueuedFrameType frameType;
CString stringData;
Vector<char> vectorData;
RefPtr<BlobDataHandle> blobData;
};
void enqueueTextFrame(const CString&);
void enqueueRawFrame(WebSocketFrame::OpCode, const char* data, size_t dataLength);
void enqueueBlobFrame(WebSocketFrame::OpCode, PassRefPtr<BlobDataHandle>);
void failAsError(const String& reason) { fail(reason, ErrorMessageLevel, m_sourceURLAtConstruction, m_lineNumberAtConstruction); }
void processOutgoingFrameQueue();
void abortOutgoingFrameQueue();
enum OutgoingFrameQueueStatus {
OutgoingFrameQueueOpen,
OutgoingFrameQueueClosing,
OutgoingFrameQueueClosed
};
bool sendFrame(WebSocketFrame::OpCode, const char* data, size_t dataLength);
enum BlobLoaderStatus {
BlobLoaderNotStarted,
BlobLoaderStarted,
BlobLoaderFinished,
BlobLoaderFailed
};
enum ChannelState {
ChannelIdle,
ChannelClosing,
ChannelClosed
};
Document* m_document;
WebSocketChannelClient* m_client;
OwnPtr<WebSocketHandshake> m_handshake;
RefPtr<SocketStreamHandle> m_handle;
Vector<char> m_buffer;
Timer<MainThreadWebSocketChannel> m_resumeTimer;
bool m_suspended;
bool m_didFailOfClientAlreadyRun;
bool m_hasCalledDisconnectOnHandle;
bool m_receivedClosingHandshake;
Timer<MainThreadWebSocketChannel> m_closingTimer;
ChannelState m_state;
bool m_shouldDiscardReceivedData;
unsigned long m_unhandledBufferedAmount;
unsigned long m_identifier;
bool m_hasContinuousFrame;
WebSocketFrame::OpCode m_continuousFrameOpCode;
Vector<char> m_continuousFrameData;
unsigned short m_closeEventCode;
String m_closeEventReason;
Deque<OwnPtr<QueuedFrame> > m_outgoingFrameQueue;
OutgoingFrameQueueStatus m_outgoingFrameQueueStatus;
OwnPtr<FileReaderLoader> m_blobLoader;
BlobLoaderStatus m_blobLoaderStatus;
String m_sourceURLAtConstruction;
unsigned m_lineNumberAtConstruction;
WebSocketPerMessageDeflate m_perMessageDeflate;
WebSocketDeflateFramer m_deflateFramer;
};
}
#endif