1 /* 2 * Copyright (C) 2011, 2012 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #ifndef MainThreadWebSocketChannel_h 32 #define MainThreadWebSocketChannel_h 33 34 #include "core/fileapi/FileError.h" 35 #include "core/fileapi/FileReaderLoaderClient.h" 36 #include "core/frame/ConsoleTypes.h" 37 #include "modules/websockets/WebSocketChannel.h" 38 #include "modules/websockets/WebSocketDeflateFramer.h" 39 #include "modules/websockets/WebSocketFrame.h" 40 #include "modules/websockets/WebSocketHandshake.h" 41 #include "modules/websockets/WebSocketPerMessageDeflate.h" 42 #include "platform/Timer.h" 43 #include "platform/network/SocketStreamHandleClient.h" 44 #include "wtf/Deque.h" 45 #include "wtf/Forward.h" 46 #include "wtf/PassOwnPtr.h" 47 #include "wtf/RefCounted.h" 48 #include "wtf/Vector.h" 49 #include "wtf/text/CString.h" 50 51 namespace WebCore { 52 53 class BlobDataHandle; 54 class Document; 55 class FileReaderLoader; 56 class SocketStreamHandle; 57 class SocketStreamError; 58 class WebSocketChannelClient; 59 60 class MainThreadWebSocketChannel : public RefCounted<MainThreadWebSocketChannel>, public SocketStreamHandleClient, public WebSocketChannel, public FileReaderLoaderClient { 61 WTF_MAKE_FAST_ALLOCATED; 62 public: 63 // You can specify the source file and the line number information 64 // explicitly by passing the last parameter. 65 // In the usual case, they are set automatically and you don't have to 66 // pass it. 67 static PassRefPtr<MainThreadWebSocketChannel> create(Document* document, WebSocketChannelClient* client, const String& sourceURL = String(), unsigned lineNumber = 0) { return adoptRef(new MainThreadWebSocketChannel(document, client, sourceURL, lineNumber)); } 68 virtual ~MainThreadWebSocketChannel(); 69 70 bool send(const char* data, int length); 71 72 // WebSocketChannel functions. 73 virtual void connect(const KURL&, const String& protocol) OVERRIDE; 74 virtual String subprotocol() OVERRIDE; 75 virtual String extensions() OVERRIDE; 76 virtual WebSocketChannel::SendResult send(const String& message) OVERRIDE; 77 virtual WebSocketChannel::SendResult send(const ArrayBuffer&, unsigned byteOffset, unsigned byteLength) OVERRIDE; 78 virtual WebSocketChannel::SendResult send(PassRefPtr<BlobDataHandle>) OVERRIDE; 79 virtual unsigned long bufferedAmount() const OVERRIDE; 80 // Start closing handshake. Use the CloseEventCodeNotSpecified for the code 81 // argument to omit payload. 82 virtual void close(int code, const String& reason) OVERRIDE; 83 virtual void fail(const String& reason, MessageLevel, const String&, unsigned lineNumber) OVERRIDE; 84 using WebSocketChannel::fail; 85 virtual void disconnect() OVERRIDE; 86 87 virtual void suspend() OVERRIDE; 88 virtual void resume() OVERRIDE; 89 90 // SocketStreamHandleClient functions. 91 virtual void willOpenSocketStream(SocketStreamHandle*) OVERRIDE; 92 virtual void didOpenSocketStream(SocketStreamHandle*) OVERRIDE; 93 virtual void didCloseSocketStream(SocketStreamHandle*) OVERRIDE; 94 virtual void didReceiveSocketStreamData(SocketStreamHandle*, const char*, int) OVERRIDE; 95 virtual void didUpdateBufferedAmount(SocketStreamHandle*, size_t bufferedAmount) OVERRIDE; 96 virtual void didFailSocketStream(SocketStreamHandle*, const SocketStreamError&) OVERRIDE; 97 98 // FileReaderLoaderClient functions. 99 virtual void didStartLoading(); 100 virtual void didReceiveData(); 101 virtual void didFinishLoading(); 102 virtual void didFail(FileError::ErrorCode); 103 104 using RefCounted<MainThreadWebSocketChannel>::ref; 105 using RefCounted<MainThreadWebSocketChannel>::deref; 106 107 protected: 108 // WebSocketChannel functions. 109 virtual void refWebSocketChannel() OVERRIDE { ref(); } 110 virtual void derefWebSocketChannel() OVERRIDE { deref(); } 111 112 private: 113 MainThreadWebSocketChannel(Document*, WebSocketChannelClient*, const String&, unsigned); 114 115 void disconnectHandle(); 116 117 bool appendToBuffer(const char* data, size_t len); 118 void skipBuffer(size_t len); 119 // Repeats parsing data from m_buffer until instructed to stop. 120 void processBuffer(); 121 // Parses a handshake response or one frame from m_buffer and processes it. 122 bool processOneItemFromBuffer(); 123 void resumeTimerFired(Timer<MainThreadWebSocketChannel>*); 124 void startClosingHandshake(int code, const String& reason); 125 void closingTimerFired(Timer<MainThreadWebSocketChannel>*); 126 127 // Parses one frame from m_buffer and processes it. 128 bool processFrame(); 129 130 // It is allowed to send a Blob as a binary frame if hybi-10 protocol is in use. Sending a Blob 131 // can be delayed because it must be read asynchronously. Other types of data (String or 132 // ArrayBuffer) may also be blocked by preceding sending request of a Blob. 133 // 134 // To address this situation, messages to be sent need to be stored in a queue. Whenever a new 135 // data frame is going to be sent, it first must go to the queue. Items in the queue are processed 136 // in the order they were put into the queue. Sending request of a Blob blocks further processing 137 // until the Blob is completely read and sent to the socket stream. 138 enum QueuedFrameType { 139 QueuedFrameTypeString, 140 QueuedFrameTypeVector, 141 QueuedFrameTypeBlob 142 }; 143 struct QueuedFrame { 144 WebSocketFrame::OpCode opCode; 145 QueuedFrameType frameType; 146 // Only one of the following items is used, according to the value of frameType. 147 CString stringData; 148 Vector<char> vectorData; 149 RefPtr<BlobDataHandle> blobData; 150 }; 151 void enqueueTextFrame(const CString&); 152 void enqueueRawFrame(WebSocketFrame::OpCode, const char* data, size_t dataLength); 153 void enqueueBlobFrame(WebSocketFrame::OpCode, PassRefPtr<BlobDataHandle>); 154 155 void failAsError(const String& reason) { fail(reason, ErrorMessageLevel, m_sourceURLAtConstruction, m_lineNumberAtConstruction); } 156 void processOutgoingFrameQueue(); 157 void abortOutgoingFrameQueue(); 158 159 enum OutgoingFrameQueueStatus { 160 // It is allowed to put a new item into the queue. 161 OutgoingFrameQueueOpen, 162 // Close frame has already been put into the queue but may not have been sent yet; 163 // m_handle->close() will be called as soon as the queue is cleared. It is not 164 // allowed to put a new item into the queue. 165 OutgoingFrameQueueClosing, 166 // Close frame has been sent or the queue was aborted. It is not allowed to put 167 // a new item to the queue. 168 OutgoingFrameQueueClosed 169 }; 170 171 // In principle, this method is called only by processOutgoingFrameQueue(). 172 // It does work necessary to build frames including Blob loading for queued 173 // data in order. Calling this method directly jumps in the process. 174 bool sendFrame(WebSocketFrame::OpCode, const char* data, size_t dataLength); 175 176 enum BlobLoaderStatus { 177 BlobLoaderNotStarted, 178 BlobLoaderStarted, 179 BlobLoaderFinished, 180 BlobLoaderFailed 181 }; 182 183 enum ChannelState { 184 ChannelIdle, 185 ChannelClosing, 186 ChannelClosed 187 }; 188 189 Document* m_document; 190 WebSocketChannelClient* m_client; 191 OwnPtr<WebSocketHandshake> m_handshake; 192 RefPtr<SocketStreamHandle> m_handle; 193 Vector<char> m_buffer; 194 195 Timer<MainThreadWebSocketChannel> m_resumeTimer; 196 bool m_suspended; 197 bool m_didFailOfClientAlreadyRun; 198 // Set to true iff this instance called disconnect() on m_handle. 199 bool m_hasCalledDisconnectOnHandle; 200 bool m_receivedClosingHandshake; 201 Timer<MainThreadWebSocketChannel> m_closingTimer; 202 ChannelState m_state; 203 bool m_shouldDiscardReceivedData; 204 unsigned long m_unhandledBufferedAmount; 205 206 unsigned long m_identifier; // m_identifier == 0 means that we could not obtain a valid identifier. 207 208 // Private members only for hybi-10 protocol. 209 bool m_hasContinuousFrame; 210 WebSocketFrame::OpCode m_continuousFrameOpCode; 211 Vector<char> m_continuousFrameData; 212 unsigned short m_closeEventCode; 213 String m_closeEventReason; 214 215 Deque<OwnPtr<QueuedFrame> > m_outgoingFrameQueue; 216 OutgoingFrameQueueStatus m_outgoingFrameQueueStatus; 217 218 // FIXME: Load two or more Blobs simultaneously for better performance. 219 OwnPtr<FileReaderLoader> m_blobLoader; 220 BlobLoaderStatus m_blobLoaderStatus; 221 222 // Source code position where construction happened. To be used to show a 223 // console message where no JS callstack info available. 224 String m_sourceURLAtConstruction; 225 unsigned m_lineNumberAtConstruction; 226 227 WebSocketPerMessageDeflate m_perMessageDeflate; 228 229 WebSocketDeflateFramer m_deflateFramer; 230 }; 231 232 } // namespace WebCore 233 234 #endif // MainThreadWebSocketChannel_h 235