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/Vector.h" 48 #include "wtf/text/CString.h" 49 50 namespace blink { 51 52 class BlobDataHandle; 53 class Document; 54 class FileReaderLoader; 55 class SocketStreamHandle; 56 class SocketStreamError; 57 class WebSocketChannelClient; 58 59 class MainThreadWebSocketChannel FINAL : public WebSocketChannel, public SocketStreamHandleClient, public FileReaderLoaderClient { 60 USING_GARBAGE_COLLECTED_MIXIN(MainThreadWebSocketChannel); 61 public: 62 // You can specify the source file and the line number information 63 // explicitly by passing the last parameter. 64 // In the usual case, they are set automatically and you don't have to 65 // pass it. 66 static MainThreadWebSocketChannel* create(Document* document, WebSocketChannelClient* client, const String& sourceURL = String(), unsigned lineNumber = 0) 67 { 68 return adoptRefCountedGarbageCollected(new MainThreadWebSocketChannel(document, client, sourceURL, lineNumber)); 69 } 70 virtual ~MainThreadWebSocketChannel(); 71 72 // WebSocketChannel functions. 73 virtual bool connect(const KURL&, const String& protocol) OVERRIDE; 74 virtual void send(const String& message) OVERRIDE; 75 virtual void send(const ArrayBuffer&, unsigned byteOffset, unsigned byteLength) OVERRIDE; 76 virtual void send(PassRefPtr<BlobDataHandle>) OVERRIDE; 77 virtual void send(PassOwnPtr<Vector<char> > data) OVERRIDE; 78 // Start closing handshake. Use the CloseEventCodeNotSpecified for the code 79 // argument to omit payload. 80 virtual void close(int code, const String& reason) OVERRIDE; 81 virtual void fail(const String& reason, MessageLevel, const String&, unsigned lineNumber) OVERRIDE; 82 virtual void disconnect() OVERRIDE; 83 84 virtual void suspend() OVERRIDE; 85 virtual void resume() OVERRIDE; 86 87 // SocketStreamHandleClient functions. 88 virtual void didOpenSocketStream(SocketStreamHandle*) OVERRIDE; 89 virtual void didCloseSocketStream(SocketStreamHandle*) OVERRIDE; 90 virtual void didReceiveSocketStreamData(SocketStreamHandle*, const char*, int) OVERRIDE; 91 virtual void didConsumeBufferedAmount(SocketStreamHandle*, size_t consumed) OVERRIDE; 92 virtual void didFailSocketStream(SocketStreamHandle*, const SocketStreamError&) OVERRIDE; 93 94 // FileReaderLoaderClient functions. 95 virtual void didStartLoading() OVERRIDE; 96 virtual void didReceiveData() OVERRIDE; 97 virtual void didFinishLoading() OVERRIDE; 98 virtual void didFail(FileError::ErrorCode) OVERRIDE; 99 100 virtual void trace(Visitor*) OVERRIDE; 101 102 private: 103 MainThreadWebSocketChannel(Document*, WebSocketChannelClient*, const String&, unsigned); 104 105 class FramingOverhead { 106 public: 107 FramingOverhead(WebSocketFrame::OpCode opcode, size_t frameDataSize, size_t originalPayloadLength) 108 : m_opcode(opcode) 109 , m_frameDataSize(frameDataSize) 110 , m_originalPayloadLength(originalPayloadLength) 111 { 112 } 113 114 WebSocketFrame::OpCode opcode() const { return m_opcode; } 115 size_t frameDataSize() const { return m_frameDataSize; } 116 size_t originalPayloadLength() const { return m_originalPayloadLength; } 117 118 private: 119 WebSocketFrame::OpCode m_opcode; 120 size_t m_frameDataSize; 121 size_t m_originalPayloadLength; 122 }; 123 124 void clearDocument(); 125 126 void disconnectHandle(); 127 128 // Calls didReceiveMessageError() on m_client if we haven't yet. 129 void callDidReceiveMessageError(); 130 131 bool appendToBuffer(const char* data, size_t len); 132 void skipBuffer(size_t len); 133 // Repeats parsing data from m_buffer until instructed to stop. 134 void processBuffer(); 135 // Parses a handshake response or one frame from m_buffer and processes it. 136 bool processOneItemFromBuffer(); 137 void resumeTimerFired(Timer<MainThreadWebSocketChannel>*); 138 void startClosingHandshake(int code, const String& reason); 139 void closingTimerFired(Timer<MainThreadWebSocketChannel>*); 140 141 // Parses one frame from m_buffer and processes it. 142 bool processFrame(); 143 144 // It is allowed to send a Blob as a binary frame if hybi-10 protocol is in use. Sending a Blob 145 // can be delayed because it must be read asynchronously. Other types of data (String or 146 // ArrayBuffer) may also be blocked by preceding sending request of a Blob. 147 // 148 // To address this situation, messages to be sent need to be stored in a queue. Whenever a new 149 // data frame is going to be sent, it first must go to the queue. Items in the queue are processed 150 // in the order they were put into the queue. Sending request of a Blob blocks further processing 151 // until the Blob is completely read and sent to the socket stream. 152 enum QueuedFrameType { 153 QueuedFrameTypeString, 154 QueuedFrameTypeVector, 155 QueuedFrameTypeBlob 156 }; 157 struct QueuedFrame { 158 WebSocketFrame::OpCode opCode; 159 QueuedFrameType frameType; 160 // Only one of the following items is used, according to the value of frameType. 161 CString stringData; 162 Vector<char> vectorData; 163 RefPtr<BlobDataHandle> blobData; 164 }; 165 void enqueueTextFrame(const CString&); 166 void enqueueRawFrame(WebSocketFrame::OpCode, const char* data, size_t dataLength); 167 void enqueueVector(WebSocketFrame::OpCode, PassOwnPtr<Vector<char> >); 168 void enqueueBlobFrame(WebSocketFrame::OpCode, PassRefPtr<BlobDataHandle>); 169 170 void failAsError(const String& reason) { fail(reason, ErrorMessageLevel, m_sourceURLAtConstruction, m_lineNumberAtConstruction); } 171 void processOutgoingFrameQueue(); 172 void abortOutgoingFrameQueue(); 173 174 enum OutgoingFrameQueueStatus { 175 // It is allowed to put a new item into the queue. 176 OutgoingFrameQueueOpen, 177 // Close frame has already been put into the queue but may not have been sent yet; 178 // m_handle->close() will be called as soon as the queue is cleared. It is not 179 // allowed to put a new item into the queue. 180 OutgoingFrameQueueClosing, 181 // Close frame has been sent or the queue was aborted. It is not allowed to put 182 // a new item to the queue. 183 OutgoingFrameQueueClosed 184 }; 185 186 // In principle, this method is called only by processOutgoingFrameQueue(). 187 // It does work necessary to build frames including Blob loading for queued 188 // data in order. Calling this method directly jumps in the process. 189 bool sendFrame(WebSocketFrame::OpCode, const char* data, size_t dataLength); 190 191 enum BlobLoaderStatus { 192 BlobLoaderNotStarted, 193 BlobLoaderStarted, 194 BlobLoaderFinished, 195 BlobLoaderFailed 196 }; 197 198 enum ChannelState { 199 ChannelIdle, 200 ChannelClosing, 201 ChannelClosed 202 }; 203 204 RawPtrWillBeMember<Document> m_document; 205 Member<WebSocketChannelClient> m_client; 206 Member<WebSocketHandshake> m_handshake; 207 Member<SocketStreamHandle> m_handle; 208 Vector<char> m_buffer; 209 210 Timer<MainThreadWebSocketChannel> m_resumeTimer; 211 bool m_suspended; 212 bool m_didFailOfClientAlreadyRun; 213 // Set to true iff this instance called disconnect() on m_handle. 214 bool m_hasCalledDisconnectOnHandle; 215 bool m_receivedClosingHandshake; 216 Timer<MainThreadWebSocketChannel> m_closingTimer; 217 ChannelState m_state; 218 bool m_shouldDiscardReceivedData; 219 220 unsigned long m_identifier; // m_identifier == 0 means that we could not obtain a valid identifier. 221 222 // Private members only for hybi-10 protocol. 223 bool m_hasContinuousFrame; 224 WebSocketFrame::OpCode m_continuousFrameOpCode; 225 Vector<char> m_continuousFrameData; 226 unsigned short m_closeEventCode; 227 String m_closeEventReason; 228 229 Deque<OwnPtr<QueuedFrame> > m_outgoingFrameQueue; 230 OutgoingFrameQueueStatus m_outgoingFrameQueueStatus; 231 Deque<FramingOverhead> m_framingOverheadQueue; 232 // The number of bytes that are already consumed (i.e. sent) in the 233 // current frame. 234 size_t m_numConsumedBytesInCurrentFrame; 235 236 // FIXME: Load two or more Blobs simultaneously for better performance. 237 OwnPtr<FileReaderLoader> m_blobLoader; 238 BlobLoaderStatus m_blobLoaderStatus; 239 240 // Source code position where construction happened. To be used to show a 241 // console message where no JS callstack info available. 242 String m_sourceURLAtConstruction; 243 unsigned m_lineNumberAtConstruction; 244 245 WebSocketPerMessageDeflate m_perMessageDeflate; 246 247 WebSocketDeflateFramer m_deflateFramer; 248 }; 249 250 } // namespace blink 251 252 #endif // MainThreadWebSocketChannel_h 253