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#pragma once
32
33#include "FileReaderLoaderClient.h"
34#include "SocketStreamHandleClient.h"
35#include "ThreadableWebSocketChannel.h"
36#include "Timer.h"
37#include "WebSocketDeflateFramer.h"
38#include "WebSocketFrame.h"
39#include "WebSocketHandshake.h"
40#include <wtf/Deque.h>
41#include <wtf/Forward.h>
42#include <wtf/RefCounted.h>
43#include <wtf/TypeCasts.h>
44#include <wtf/Vector.h>
45#include <wtf/text/CString.h>
46
47namespace WebCore {
48
49class Blob;
50class Document;
51class FileReaderLoader;
52class ResourceRequest;
53class ResourceResponse;
54class SocketProvider;
55class SocketStreamHandle;
56class SocketStreamError;
57class WebSocketChannelClient;
58
59class WebSocketChannel final : public RefCounted<WebSocketChannel>, public SocketStreamHandleClient, public ThreadableWebSocketChannel, public FileReaderLoaderClient
60{
61 WTF_MAKE_FAST_ALLOCATED;
62public:
63 static Ref<WebSocketChannel> create(Document& document, WebSocketChannelClient& client, SocketProvider& provider) { return adoptRef(*new WebSocketChannel(document, client, provider)); }
64 virtual ~WebSocketChannel();
65
66 bool isWebSocketChannel() const final { return true; }
67
68 bool send(const char* data, int length);
69
70 // ThreadableWebSocketChannel functions.
71 ConnectStatus connect(const URL&, const String& protocol) final;
72 String subprotocol() final;
73 String extensions() final;
74 ThreadableWebSocketChannel::SendResult send(const String& message) final;
75 ThreadableWebSocketChannel::SendResult send(const JSC::ArrayBuffer&, unsigned byteOffset, unsigned byteLength) final;
76 ThreadableWebSocketChannel::SendResult send(Blob&) final;
77 unsigned bufferedAmount() const final;
78 void close(int code, const String& reason) final; // Start closing handshake.
79 void fail(const String& reason) final;
80 void disconnect() final;
81
82 void suspend() final;
83 void resume() final;
84
85 // SocketStreamHandleClient functions.
86 void didOpenSocketStream(SocketStreamHandle&) final;
87 void didCloseSocketStream(SocketStreamHandle&) final;
88 void didReceiveSocketStreamData(SocketStreamHandle&, const char*, size_t) final;
89 void didFailToReceiveSocketStreamData(SocketStreamHandle&) final;
90 void didUpdateBufferedAmount(SocketStreamHandle&, size_t bufferedAmount) final;
91 void didFailSocketStream(SocketStreamHandle&, const SocketStreamError&) final;
92
93 enum CloseEventCode {
94 CloseEventCodeNotSpecified = -1,
95 CloseEventCodeNormalClosure = 1000,
96 CloseEventCodeGoingAway = 1001,
97 CloseEventCodeProtocolError = 1002,
98 CloseEventCodeUnsupportedData = 1003,
99 CloseEventCodeFrameTooLarge = 1004,
100 CloseEventCodeNoStatusRcvd = 1005,
101 CloseEventCodeAbnormalClosure = 1006,
102 CloseEventCodeInvalidFramePayloadData = 1007,
103 CloseEventCodePolicyViolation = 1008,
104 CloseEventCodeMessageTooBig = 1009,
105 CloseEventCodeMandatoryExt = 1010,
106 CloseEventCodeInternalError = 1011,
107 CloseEventCodeTLSHandshake = 1015,
108 CloseEventCodeMinimumUserDefined = 3000,
109 CloseEventCodeMaximumUserDefined = 4999
110 };
111
112 // FileReaderLoaderClient functions.
113 void didStartLoading() override;
114 void didReceiveData() override;
115 void didFinishLoading() override;
116 void didFail(int errorCode) override;
117
118 unsigned identifier() const { return m_identifier; }
119 bool hasCreatedHandshake() { return !!m_handshake; }
120 ResourceRequest clientHandshakeRequest(Function<String(const URL&)>&& cookieRequestHeaderFieldValue);
121 const ResourceResponse& serverHandshakeResponse() const;
122 WebSocketHandshake::Mode handshakeMode() const;
123
124 using RefCounted<WebSocketChannel>::ref;
125 using RefCounted<WebSocketChannel>::deref;
126
127 Document* document();
128
129protected:
130 void refThreadableWebSocketChannel() override { ref(); }
131 void derefThreadableWebSocketChannel() override { deref(); }
132
133private:
134 WEBCORE_EXPORT WebSocketChannel(Document&, WebSocketChannelClient&, SocketProvider&);
135
136 bool appendToBuffer(const char* data, size_t len);
137 void skipBuffer(size_t len);
138 bool processBuffer();
139 void resumeTimerFired();
140 void startClosingHandshake(int code, const String& reason);
141 void closingTimerFired();
142
143 bool processFrame();
144
145 // It is allowed to send a Blob as a binary frame if hybi-10 protocol is in use. Sending a Blob
146 // can be delayed because it must be read asynchronously. Other types of data (String or
147 // ArrayBuffer) may also be blocked by preceding sending request of a Blob.
148 //
149 // To address this situation, messages to be sent need to be stored in a queue. Whenever a new
150 // data frame is going to be sent, it first must go to the queue. Items in the queue are processed
151 // in the order they were put into the queue. Sending request of a Blob blocks further processing
152 // until the Blob is completely read and sent to the socket stream.
153 enum QueuedFrameType {
154 QueuedFrameTypeString,
155 QueuedFrameTypeVector,
156 QueuedFrameTypeBlob
157 };
158 struct QueuedFrame {
159 WTF_MAKE_STRUCT_FAST_ALLOCATED;
160
161 WebSocketFrame::OpCode opCode;
162 QueuedFrameType frameType;
163 // Only one of the following items is used, according to the value of frameType.
164 CString stringData;
165 Vector<char> vectorData;
166 RefPtr<Blob> blobData;
167 };
168 void enqueueTextFrame(const CString&);
169 void enqueueRawFrame(WebSocketFrame::OpCode, const char* data, size_t dataLength);
170 void enqueueBlobFrame(WebSocketFrame::OpCode, Blob&);
171
172 void processOutgoingFrameQueue();
173 void abortOutgoingFrameQueue();
174
175 enum OutgoingFrameQueueStatus {
176 // It is allowed to put a new item into the queue.
177 OutgoingFrameQueueOpen,
178 // Close frame has already been put into the queue but may not have been sent yet;
179 // m_handle->close() will be called as soon as the queue is cleared. It is not
180 // allowed to put a new item into the queue.
181 OutgoingFrameQueueClosing,
182 // Close frame has been sent or the queue was aborted. It is not allowed to put
183 // a new item to the queue.
184 OutgoingFrameQueueClosed
185 };
186
187 // If you are going to send a hybi-10 frame, you need to use the outgoing frame queue
188 // instead of call sendFrame() directly.
189 void sendFrame(WebSocketFrame::OpCode, const char* data, size_t dataLength, WTF::Function<void(bool)> completionHandler);
190
191 enum BlobLoaderStatus {
192 BlobLoaderNotStarted,
193 BlobLoaderStarted,
194 BlobLoaderFinished,
195 BlobLoaderFailed
196 };
197
198 WeakPtr<Document> m_document;
199 WeakPtr<WebSocketChannelClient> m_client;
200 std::unique_ptr<WebSocketHandshake> m_handshake;
201 RefPtr<SocketStreamHandle> m_handle;
202 Vector<char> m_buffer;
203
204 Timer m_resumeTimer;
205 bool m_suspended { false };
206 bool m_closing { false };
207 bool m_receivedClosingHandshake { false };
208 bool m_allowCookies { true };
209 Timer m_closingTimer;
210 bool m_closed { false };
211 bool m_shouldDiscardReceivedData { false };
212 unsigned m_unhandledBufferedAmount { 0 };
213
214 unsigned m_identifier { 0 }; // m_identifier == 0 means that we could not obtain a valid identifier.
215
216 // Private members only for hybi-10 protocol.
217 bool m_hasContinuousFrame { false };
218 WebSocketFrame::OpCode m_continuousFrameOpCode;
219 Vector<uint8_t> m_continuousFrameData;
220 unsigned short m_closeEventCode { CloseEventCodeAbnormalClosure };
221 String m_closeEventReason;
222
223 Deque<std::unique_ptr<QueuedFrame>> m_outgoingFrameQueue;
224 OutgoingFrameQueueStatus m_outgoingFrameQueueStatus { OutgoingFrameQueueOpen };
225
226 // FIXME: Load two or more Blobs simultaneously for better performance.
227 std::unique_ptr<FileReaderLoader> m_blobLoader;
228 BlobLoaderStatus m_blobLoaderStatus { BlobLoaderNotStarted };
229
230 WebSocketDeflateFramer m_deflateFramer;
231 Ref<SocketProvider> m_socketProvider;
232};
233
234} // namespace WebCore
235
236SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::WebSocketChannel)
237 static bool isType(const WebCore::ThreadableWebSocketChannel& threadableWebSocketChannel) { return threadableWebSocketChannel.isWebSocketChannel(); }
238SPECIALIZE_TYPE_TRAITS_END()
239