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