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 #include "config.h"
32 #include "modules/websockets/MainThreadWebSocketChannel.h"
33
34 #include "bindings/v8/ExceptionStatePlaceholder.h"
35 #include "core/dom/Document.h"
36 #include "core/dom/ExecutionContext.h"
37 #include "core/fileapi/Blob.h"
38 #include "core/fileapi/FileReaderLoader.h"
39 #include "core/frame/LocalFrame.h"
40 #include "core/inspector/InspectorInstrumentation.h"
41 #include "core/inspector/InspectorTraceEvents.h"
42 #include "core/loader/FrameLoader.h"
43 #include "core/loader/FrameLoaderClient.h"
44 #include "core/loader/MixedContentChecker.h"
45 #include "core/loader/UniqueIdentifier.h"
46 #include "core/page/Page.h"
47 #include "modules/websockets/WebSocketChannelClient.h"
48 #include "platform/Logging.h"
49 #include "platform/network/SocketStreamError.h"
50 #include "platform/network/SocketStreamHandle.h"
51 #include "wtf/ArrayBuffer.h"
52 #include "wtf/FastMalloc.h"
53 #include "wtf/HashMap.h"
54 #include "wtf/OwnPtr.h"
55 #include "wtf/text/StringHash.h"
56 #include "wtf/text/WTFString.h"
57
58 using namespace std;
59
60 namespace WebCore {
61
62 const double TCPMaximumSegmentLifetime = 2 * 60.0;
63
MainThreadWebSocketChannel(Document * document,WebSocketChannelClient * client,const String & sourceURL,unsigned lineNumber)64 MainThreadWebSocketChannel::MainThreadWebSocketChannel(Document* document, WebSocketChannelClient* client, const String& sourceURL, unsigned lineNumber)
65 : m_document(document)
66 , m_client(client)
67 , m_resumeTimer(this, &MainThreadWebSocketChannel::resumeTimerFired)
68 , m_suspended(false)
69 , m_didFailOfClientAlreadyRun(false)
70 , m_hasCalledDisconnectOnHandle(false)
71 , m_receivedClosingHandshake(false)
72 , m_closingTimer(this, &MainThreadWebSocketChannel::closingTimerFired)
73 , m_state(ChannelIdle)
74 , m_shouldDiscardReceivedData(false)
75 , m_identifier(0)
76 , m_hasContinuousFrame(false)
77 , m_closeEventCode(CloseEventCodeAbnormalClosure)
78 , m_outgoingFrameQueueStatus(OutgoingFrameQueueOpen)
79 , m_numConsumedBytesInCurrentFrame(0)
80 , m_blobLoaderStatus(BlobLoaderNotStarted)
81 , m_sourceURLAtConstruction(sourceURL)
82 , m_lineNumberAtConstruction(lineNumber)
83 {
84 if (m_document->page())
85 m_identifier = createUniqueIdentifier();
86 }
87
~MainThreadWebSocketChannel()88 MainThreadWebSocketChannel::~MainThreadWebSocketChannel()
89 {
90 }
91
connect(const KURL & url,const String & protocol)92 bool MainThreadWebSocketChannel::connect(const KURL& url, const String& protocol)
93 {
94 WTF_LOG(Network, "MainThreadWebSocketChannel %p connect()", this);
95 ASSERT(!m_handle);
96 ASSERT(!m_suspended);
97
98 if (m_document->frame() && !m_document->frame()->loader().mixedContentChecker()->canConnectInsecureWebSocket(m_document->securityOrigin(), url))
99 return false;
100 if (MixedContentChecker::isMixedContent(m_document->securityOrigin(), url)) {
101 String message = "Connecting to a non-secure WebSocket server from a secure origin is deprecated.";
102 m_document->addConsoleMessage(JSMessageSource, WarningMessageLevel, message);
103 }
104
105 m_handshake = adoptPtr(new WebSocketHandshake(url, protocol, m_document));
106 m_handshake->reset();
107 m_handshake->addExtensionProcessor(m_perMessageDeflate.createExtensionProcessor());
108 m_handshake->addExtensionProcessor(m_deflateFramer.createExtensionProcessor());
109 if (m_identifier) {
110 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "WebSocketCreate", "data", InspectorWebSocketCreateEvent::data(m_document, m_identifier, url, protocol));
111 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline.stack"), "CallStack", "stack", InspectorCallStackEvent::currentCallStack());
112 // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing.
113 InspectorInstrumentation::didCreateWebSocket(m_document, m_identifier, url, protocol);
114 }
115 ref();
116
117 m_handle = SocketStreamHandle::create(this);
118 ASSERT(m_handle);
119 if (m_document->frame()) {
120 m_document->frame()->loader().client()->dispatchWillOpenSocketStream(m_handle.get());
121 }
122 m_handle->connect(m_handshake->url());
123
124 return true;
125 }
126
send(const String & message)127 WebSocketChannel::SendResult MainThreadWebSocketChannel::send(const String& message)
128 {
129 WTF_LOG(Network, "MainThreadWebSocketChannel %p send() Sending String '%s'", this, message.utf8().data());
130 CString utf8 = message.utf8(StrictUTF8ConversionReplacingUnpairedSurrogatesWithFFFD);
131 enqueueTextFrame(utf8);
132 processOutgoingFrameQueue();
133 // m_channel->send() may happen later, thus it's not always possible to know whether
134 // the message has been sent to the socket successfully. In this case, we have no choice
135 // but to return SendSuccess.
136 return WebSocketChannel::SendSuccess;
137 }
138
send(const ArrayBuffer & binaryData,unsigned byteOffset,unsigned byteLength)139 WebSocketChannel::SendResult MainThreadWebSocketChannel::send(const ArrayBuffer& binaryData, unsigned byteOffset, unsigned byteLength)
140 {
141 WTF_LOG(Network, "MainThreadWebSocketChannel %p send() Sending ArrayBuffer %p byteOffset=%u byteLength=%u", this, &binaryData, byteOffset, byteLength);
142 enqueueRawFrame(WebSocketFrame::OpCodeBinary, static_cast<const char*>(binaryData.data()) + byteOffset, byteLength);
143 processOutgoingFrameQueue();
144 return WebSocketChannel::SendSuccess;
145 }
146
send(PassRefPtr<BlobDataHandle> binaryData)147 WebSocketChannel::SendResult MainThreadWebSocketChannel::send(PassRefPtr<BlobDataHandle> binaryData)
148 {
149 WTF_LOG(Network, "MainThreadWebSocketChannel %p send() Sending Blob '%s'", this, binaryData->uuid().utf8().data());
150 enqueueBlobFrame(WebSocketFrame::OpCodeBinary, binaryData);
151 processOutgoingFrameQueue();
152 return WebSocketChannel::SendSuccess;
153 }
154
send(PassOwnPtr<Vector<char>> data)155 WebSocketChannel::SendResult MainThreadWebSocketChannel::send(PassOwnPtr<Vector<char> > data)
156 {
157 WTF_LOG(Network, "MainThreadWebSocketChannel %p send() Sending Vector %p", this, data.get());
158 enqueueVector(WebSocketFrame::OpCodeBinary, data);
159 processOutgoingFrameQueue();
160 return WebSocketChannel::SendSuccess;
161 }
162
close(int code,const String & reason)163 void MainThreadWebSocketChannel::close(int code, const String& reason)
164 {
165 WTF_LOG(Network, "MainThreadWebSocketChannel %p close() code=%d reason='%s'", this, code, reason.utf8().data());
166 ASSERT(!m_suspended);
167 if (!m_handle)
168 return;
169 startClosingHandshake(code, reason);
170 if (!m_closingTimer.isActive())
171 m_closingTimer.startOneShot(2 * TCPMaximumSegmentLifetime, FROM_HERE);
172 }
173
clearDocument()174 void MainThreadWebSocketChannel::clearDocument()
175 {
176 if (m_handshake)
177 m_handshake->clearDocument();
178 m_document = 0;
179 }
180
disconnectHandle()181 void MainThreadWebSocketChannel::disconnectHandle()
182 {
183 if (!m_handle)
184 return;
185 m_hasCalledDisconnectOnHandle = true;
186 m_handle->disconnect();
187 }
188
callDidReceiveMessageError()189 void MainThreadWebSocketChannel::callDidReceiveMessageError()
190 {
191 if (!m_client || m_didFailOfClientAlreadyRun)
192 return;
193 m_didFailOfClientAlreadyRun = true;
194 m_client->didReceiveMessageError();
195 }
196
fail(const String & reason,MessageLevel level,const String & sourceURL,unsigned lineNumber)197 void MainThreadWebSocketChannel::fail(const String& reason, MessageLevel level, const String& sourceURL, unsigned lineNumber)
198 {
199 WTF_LOG(Network, "MainThreadWebSocketChannel %p fail() reason='%s'", this, reason.utf8().data());
200 if (m_document) {
201 InspectorInstrumentation::didReceiveWebSocketFrameError(m_document, m_identifier, reason);
202 const String message = "WebSocket connection to '" + m_handshake->url().elidedString() + "' failed: " + reason;
203 m_document->addConsoleMessage(JSMessageSource, level, message, sourceURL, lineNumber);
204 }
205 // Hybi-10 specification explicitly states we must not continue to handle incoming data
206 // once the WebSocket connection is failed (section 7.1.7).
207 RefPtrWillBeRawPtr<MainThreadWebSocketChannel> protect(this); // The client can close the channel, potentially removing the last reference.
208 m_shouldDiscardReceivedData = true;
209 if (!m_buffer.isEmpty())
210 skipBuffer(m_buffer.size()); // Save memory.
211 m_deflateFramer.didFail();
212 m_perMessageDeflate.didFail();
213 m_hasContinuousFrame = false;
214 m_continuousFrameData.clear();
215
216 callDidReceiveMessageError();
217
218 if (m_state != ChannelClosed)
219 disconnectHandle(); // Will call didCloseSocketStream().
220 }
221
disconnect()222 void MainThreadWebSocketChannel::disconnect()
223 {
224 WTF_LOG(Network, "MainThreadWebSocketChannel %p disconnect()", this);
225 if (m_identifier && m_document) {
226 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "WebSocketDestroy", "data", InspectorWebSocketEvent::data(m_document, m_identifier));
227 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline.stack"), "CallStack", "stack", InspectorCallStackEvent::currentCallStack());
228 // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing.
229 InspectorInstrumentation::didCloseWebSocket(m_document, m_identifier);
230 }
231
232 clearDocument();
233
234 m_client = 0;
235 disconnectHandle();
236 }
237
suspend()238 void MainThreadWebSocketChannel::suspend()
239 {
240 m_suspended = true;
241 }
242
resume()243 void MainThreadWebSocketChannel::resume()
244 {
245 m_suspended = false;
246 if ((!m_buffer.isEmpty() || (m_state == ChannelClosed)) && m_client && !m_resumeTimer.isActive())
247 m_resumeTimer.startOneShot(0, FROM_HERE);
248 }
249
didOpenSocketStream(SocketStreamHandle * handle)250 void MainThreadWebSocketChannel::didOpenSocketStream(SocketStreamHandle* handle)
251 {
252 WTF_LOG(Network, "MainThreadWebSocketChannel %p didOpenSocketStream()", this);
253 ASSERT(handle == m_handle);
254 if (!m_document)
255 return;
256 if (m_identifier) {
257 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "WebSocketSendHandshakeRequest", "data", InspectorWebSocketEvent::data(m_document, m_identifier));
258 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline.stack"), "CallStack", "stack", InspectorCallStackEvent::currentCallStack());
259 // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing.
260 InspectorInstrumentation::willSendWebSocketHandshakeRequest(m_document, m_identifier, m_handshake->clientHandshakeRequest().get());
261 }
262 CString handshakeMessage = m_handshake->clientHandshakeMessage();
263 if (!handle->send(handshakeMessage.data(), handshakeMessage.length()))
264 failAsError("Failed to send WebSocket handshake.");
265 }
266
didCloseSocketStream(SocketStreamHandle * handle)267 void MainThreadWebSocketChannel::didCloseSocketStream(SocketStreamHandle* handle)
268 {
269 WTF_LOG(Network, "MainThreadWebSocketChannel %p didCloseSocketStream()", this);
270 if (m_identifier && m_document) {
271 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "WebSocketDestroy", "data", InspectorWebSocketEvent::data(m_document, m_identifier));
272 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline.stack"), "CallStack", "stack", InspectorCallStackEvent::currentCallStack());
273 // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing.
274 InspectorInstrumentation::didCloseWebSocket(m_document, m_identifier);
275 }
276 ASSERT_UNUSED(handle, handle == m_handle || !m_handle);
277
278 // Show error message on JS console if this is unexpected connection close
279 // during opening handshake.
280 if (!m_hasCalledDisconnectOnHandle && m_handshake->mode() == WebSocketHandshake::Incomplete && m_document) {
281 const String message = "WebSocket connection to '" + m_handshake->url().elidedString() + "' failed: Connection closed before receiving a handshake response";
282 m_document->addConsoleMessage(JSMessageSource, ErrorMessageLevel, message, m_sourceURLAtConstruction, m_lineNumberAtConstruction);
283 }
284
285 m_state = ChannelClosed;
286 if (m_closingTimer.isActive())
287 m_closingTimer.stop();
288 if (m_outgoingFrameQueueStatus != OutgoingFrameQueueClosed)
289 abortOutgoingFrameQueue();
290 if (m_handle) {
291 WebSocketChannelClient* client = m_client;
292 m_client = 0;
293 clearDocument();
294 m_handle = nullptr;
295 if (client)
296 client->didClose(m_receivedClosingHandshake ? WebSocketChannelClient::ClosingHandshakeComplete : WebSocketChannelClient::ClosingHandshakeIncomplete, m_closeEventCode, m_closeEventReason);
297 }
298 deref();
299 }
300
didReceiveSocketStreamData(SocketStreamHandle * handle,const char * data,int len)301 void MainThreadWebSocketChannel::didReceiveSocketStreamData(SocketStreamHandle* handle, const char* data, int len)
302 {
303 WTF_LOG(Network, "MainThreadWebSocketChannel %p didReceiveSocketStreamData() Received %d bytes", this, len);
304 RefPtrWillBeRawPtr<MainThreadWebSocketChannel> protect(this); // The client can close the channel, potentially removing the last reference.
305 ASSERT(handle == m_handle);
306 if (!m_document)
307 return;
308 if (len <= 0) {
309 disconnectHandle();
310 return;
311 }
312 if (!m_client) {
313 m_shouldDiscardReceivedData = true;
314 disconnectHandle();
315 return;
316 }
317 if (m_shouldDiscardReceivedData)
318 return;
319 if (!appendToBuffer(data, len)) {
320 m_shouldDiscardReceivedData = true;
321 failAsError("Ran out of memory while receiving WebSocket data.");
322 return;
323 }
324 processBuffer();
325 }
326
didConsumeBufferedAmount(SocketStreamHandle *,size_t consumed)327 void MainThreadWebSocketChannel::didConsumeBufferedAmount(SocketStreamHandle*, size_t consumed)
328 {
329 if (m_framingOverheadQueue.isEmpty()) {
330 // Ignore the handshake consumption.
331 return;
332 }
333 if (!m_client || m_state == ChannelClosed)
334 return;
335 size_t remain = consumed;
336 while (remain > 0) {
337 ASSERT(!m_framingOverheadQueue.isEmpty());
338 const FramingOverhead& frame = m_framingOverheadQueue.first();
339
340 ASSERT(m_numConsumedBytesInCurrentFrame <= frame.frameDataSize());
341 size_t consumedInThisFrame = std::min(remain, frame.frameDataSize() - m_numConsumedBytesInCurrentFrame);
342 remain -= consumedInThisFrame;
343 m_numConsumedBytesInCurrentFrame += consumedInThisFrame;
344
345 if (m_numConsumedBytesInCurrentFrame == frame.frameDataSize()) {
346 if (m_client && WebSocketFrame::isNonControlOpCode(frame.opcode())) {
347 // FIXME: As |consumed| is the number of possibly compressed
348 // bytes, we can't determine the number of consumed original
349 // bytes in the middle of a frame.
350 m_client->didConsumeBufferedAmount(frame.originalPayloadLength());
351 }
352 m_framingOverheadQueue.takeFirst();
353 m_numConsumedBytesInCurrentFrame = 0;
354 }
355 }
356 }
357
didFailSocketStream(SocketStreamHandle * handle,const SocketStreamError & error)358 void MainThreadWebSocketChannel::didFailSocketStream(SocketStreamHandle* handle, const SocketStreamError& error)
359 {
360 WTF_LOG(Network, "MainThreadWebSocketChannel %p didFailSocketStream()", this);
361 ASSERT_UNUSED(handle, handle == m_handle || !m_handle);
362 m_shouldDiscardReceivedData = true;
363 String message;
364 if (error.isNull())
365 message = "WebSocket network error";
366 else if (error.localizedDescription().isNull())
367 message = "WebSocket network error: error code " + String::number(error.errorCode());
368 else
369 message = "WebSocket network error: error code " + String::number(error.errorCode()) + ", " + error.localizedDescription();
370 String failingURL = error.failingURL();
371 ASSERT(failingURL.isNull() || m_handshake->url().string() == failingURL);
372 if (failingURL.isNull())
373 failingURL = m_handshake->url().string();
374 WTF_LOG(Network, "Error Message: '%s', FailURL: '%s'", message.utf8().data(), failingURL.utf8().data());
375
376 RefPtrWillBeRawPtr<WebSocketChannel> protect(this);
377
378 if (m_state != ChannelClosing && m_state != ChannelClosed)
379 callDidReceiveMessageError();
380
381 if (m_state != ChannelClosed)
382 disconnectHandle();
383 }
384
didStartLoading()385 void MainThreadWebSocketChannel::didStartLoading()
386 {
387 WTF_LOG(Network, "MainThreadWebSocketChannel %p didStartLoading()", this);
388 ASSERT(m_blobLoader);
389 ASSERT(m_blobLoaderStatus == BlobLoaderStarted);
390 }
391
didReceiveData()392 void MainThreadWebSocketChannel::didReceiveData()
393 {
394 WTF_LOG(Network, "MainThreadWebSocketChannel %p didReceiveData()", this);
395 ASSERT(m_blobLoader);
396 ASSERT(m_blobLoaderStatus == BlobLoaderStarted);
397 }
398
didFinishLoading()399 void MainThreadWebSocketChannel::didFinishLoading()
400 {
401 WTF_LOG(Network, "MainThreadWebSocketChannel %p didFinishLoading()", this);
402 ASSERT(m_blobLoader);
403 ASSERT(m_blobLoaderStatus == BlobLoaderStarted);
404 m_blobLoaderStatus = BlobLoaderFinished;
405 processOutgoingFrameQueue();
406 deref();
407 }
408
didFail(FileError::ErrorCode errorCode)409 void MainThreadWebSocketChannel::didFail(FileError::ErrorCode errorCode)
410 {
411 WTF_LOG(Network, "MainThreadWebSocketChannel %p didFail() errorCode=%d", this, errorCode);
412 ASSERT(m_blobLoader);
413 ASSERT(m_blobLoaderStatus == BlobLoaderStarted);
414 m_blobLoader.clear();
415 m_blobLoaderStatus = BlobLoaderFailed;
416 failAsError("Failed to load Blob: error code = " + String::number(errorCode)); // FIXME: Generate human-friendly reason message.
417 deref();
418 }
419
appendToBuffer(const char * data,size_t len)420 bool MainThreadWebSocketChannel::appendToBuffer(const char* data, size_t len)
421 {
422 size_t newBufferSize = m_buffer.size() + len;
423 if (newBufferSize < m_buffer.size()) {
424 WTF_LOG(Network, "MainThreadWebSocketChannel %p appendToBuffer() Buffer overflow (%lu bytes already in receive buffer and appending %lu bytes)", this, static_cast<unsigned long>(m_buffer.size()), static_cast<unsigned long>(len));
425 return false;
426 }
427 m_buffer.append(data, len);
428 return true;
429 }
430
skipBuffer(size_t len)431 void MainThreadWebSocketChannel::skipBuffer(size_t len)
432 {
433 ASSERT_WITH_SECURITY_IMPLICATION(len <= m_buffer.size());
434 memmove(m_buffer.data(), m_buffer.data() + len, m_buffer.size() - len);
435 m_buffer.resize(m_buffer.size() - len);
436 }
437
processBuffer()438 void MainThreadWebSocketChannel::processBuffer()
439 {
440 while (!m_suspended && m_client && !m_buffer.isEmpty()) {
441 if (!processOneItemFromBuffer())
442 break;
443 }
444 }
445
processOneItemFromBuffer()446 bool MainThreadWebSocketChannel::processOneItemFromBuffer()
447 {
448 ASSERT(!m_suspended);
449 ASSERT(m_client);
450 ASSERT(!m_buffer.isEmpty());
451 WTF_LOG(Network, "MainThreadWebSocketChannel %p processBuffer() Receive buffer has %lu bytes", this, static_cast<unsigned long>(m_buffer.size()));
452
453 if (m_shouldDiscardReceivedData)
454 return false;
455
456 if (m_receivedClosingHandshake) {
457 skipBuffer(m_buffer.size());
458 return false;
459 }
460
461 RefPtrWillBeRawPtr<MainThreadWebSocketChannel> protect(this); // The client can close the channel, potentially removing the last reference.
462
463 if (m_handshake->mode() == WebSocketHandshake::Incomplete) {
464 int headerLength = m_handshake->readServerHandshake(m_buffer.data(), m_buffer.size());
465 if (headerLength <= 0)
466 return false;
467 if (m_handshake->mode() == WebSocketHandshake::Connected) {
468 if (m_identifier) {
469 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "WebSocketReceiveHandshakeResponse", "data", InspectorWebSocketEvent::data(m_document, m_identifier));
470 // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing.
471 InspectorInstrumentation::didReceiveWebSocketHandshakeResponse(m_document, m_identifier, 0, &m_handshake->serverHandshakeResponse());
472 }
473
474 if (m_deflateFramer.enabled() && m_document) {
475 const String message = "WebSocket extension \"x-webkit-deflate-frame\" is deprecated";
476 m_document->addConsoleMessage(JSMessageSource, WarningMessageLevel, message, m_sourceURLAtConstruction, m_lineNumberAtConstruction);
477 }
478
479 WTF_LOG(Network, "MainThreadWebSocketChannel %p Connected", this);
480 skipBuffer(headerLength);
481 String subprotocol = m_handshake->serverWebSocketProtocol();
482 String extensions = m_handshake->acceptedExtensions();
483 m_client->didConnect(subprotocol.isNull() ? "" : subprotocol, extensions.isNull() ? "" : extensions);
484 WTF_LOG(Network, "MainThreadWebSocketChannel %p %lu bytes remaining in m_buffer", this, static_cast<unsigned long>(m_buffer.size()));
485 return !m_buffer.isEmpty();
486 }
487 ASSERT(m_handshake->mode() == WebSocketHandshake::Failed);
488 WTF_LOG(Network, "MainThreadWebSocketChannel %p Connection failed", this);
489 skipBuffer(headerLength);
490 m_shouldDiscardReceivedData = true;
491 failAsError(m_handshake->failureReason());
492 return false;
493 }
494 if (m_handshake->mode() != WebSocketHandshake::Connected)
495 return false;
496
497 return processFrame();
498 }
499
resumeTimerFired(Timer<MainThreadWebSocketChannel> * timer)500 void MainThreadWebSocketChannel::resumeTimerFired(Timer<MainThreadWebSocketChannel>* timer)
501 {
502 ASSERT_UNUSED(timer, timer == &m_resumeTimer);
503
504 RefPtrWillBeRawPtr<MainThreadWebSocketChannel> protect(this); // The client can close the channel, potentially removing the last reference.
505 processBuffer();
506 if (!m_suspended && m_client && (m_state == ChannelClosed) && m_handle)
507 didCloseSocketStream(m_handle.get());
508 }
509
startClosingHandshake(int code,const String & reason)510 void MainThreadWebSocketChannel::startClosingHandshake(int code, const String& reason)
511 {
512 WTF_LOG(Network, "MainThreadWebSocketChannel %p startClosingHandshake() code=%d m_state=%d m_receivedClosingHandshake=%d", this, code, m_state, m_receivedClosingHandshake);
513 if (m_state == ChannelClosing || m_state == ChannelClosed)
514 return;
515 ASSERT(m_handle);
516
517 Vector<char> buf;
518 if (!m_receivedClosingHandshake && code != CloseEventCodeNotSpecified) {
519 unsigned char highByte = code >> 8;
520 unsigned char lowByte = code;
521 buf.append(static_cast<char>(highByte));
522 buf.append(static_cast<char>(lowByte));
523 buf.append(reason.utf8().data(), reason.utf8().length());
524 }
525 enqueueRawFrame(WebSocketFrame::OpCodeClose, buf.data(), buf.size());
526 processOutgoingFrameQueue();
527
528 m_state = ChannelClosing;
529 if (m_client)
530 m_client->didStartClosingHandshake();
531 }
532
closingTimerFired(Timer<MainThreadWebSocketChannel> * timer)533 void MainThreadWebSocketChannel::closingTimerFired(Timer<MainThreadWebSocketChannel>* timer)
534 {
535 WTF_LOG(Network, "MainThreadWebSocketChannel %p closingTimerFired()", this);
536 ASSERT_UNUSED(timer, &m_closingTimer == timer);
537 disconnectHandle();
538 }
539
540
processFrame()541 bool MainThreadWebSocketChannel::processFrame()
542 {
543 ASSERT(!m_buffer.isEmpty());
544
545 WebSocketFrame frame;
546 const char* frameEnd;
547 String errorString;
548 WebSocketFrame::ParseFrameResult result = WebSocketFrame::parseFrame(m_buffer.data(), m_buffer.size(), frame, frameEnd, errorString);
549 if (result == WebSocketFrame::FrameIncomplete)
550 return false;
551 if (result == WebSocketFrame::FrameError) {
552 failAsError(errorString);
553 return false;
554 }
555
556 ASSERT(m_buffer.data() < frameEnd);
557 ASSERT(frameEnd <= m_buffer.data() + m_buffer.size());
558
559 OwnPtr<InflateResultHolder> inflateResult = m_deflateFramer.inflate(frame);
560 if (!inflateResult->succeeded()) {
561 failAsError(inflateResult->failureReason());
562 return false;
563 }
564 if (!m_perMessageDeflate.inflate(frame)) {
565 failAsError(m_perMessageDeflate.failureReason());
566 return false;
567 }
568
569 // Validate the frame data.
570 if (WebSocketFrame::isReservedOpCode(frame.opCode)) {
571 failAsError("Unrecognized frame opcode: " + String::number(frame.opCode));
572 return false;
573 }
574
575 if (frame.compress || frame.reserved2 || frame.reserved3) {
576 failAsError("One or more reserved bits are on: reserved1 = " + String::number(frame.compress) + ", reserved2 = " + String::number(frame.reserved2) + ", reserved3 = " + String::number(frame.reserved3));
577 return false;
578 }
579
580 if (frame.masked) {
581 failAsError("A server must not mask any frames that it sends to the client.");
582 return false;
583 }
584
585 // All control frames must not be fragmented.
586 if (WebSocketFrame::isControlOpCode(frame.opCode) && !frame.final) {
587 failAsError("Received fragmented control frame: opcode = " + String::number(frame.opCode));
588 return false;
589 }
590
591 // All control frames must have a payload of 125 bytes or less, which means the frame must not contain
592 // the "extended payload length" field.
593 if (WebSocketFrame::isControlOpCode(frame.opCode) && WebSocketFrame::needsExtendedLengthField(frame.payloadLength)) {
594 failAsError("Received control frame having too long payload: " + String::number(frame.payloadLength) + " bytes");
595 return false;
596 }
597
598 // A new data frame is received before the previous continuous frame finishes.
599 // Note that control frames are allowed to come in the middle of continuous frames.
600 if (m_hasContinuousFrame && frame.opCode != WebSocketFrame::OpCodeContinuation && !WebSocketFrame::isControlOpCode(frame.opCode)) {
601 failAsError("Received start of new message but previous message is unfinished.");
602 return false;
603 }
604
605 InspectorInstrumentation::didReceiveWebSocketFrame(m_document, m_identifier, frame.opCode, frame.masked, frame.payload, frame.payloadLength);
606
607 switch (frame.opCode) {
608 case WebSocketFrame::OpCodeContinuation:
609 // An unexpected continuation frame is received without any leading frame.
610 if (!m_hasContinuousFrame) {
611 failAsError("Received unexpected continuation frame.");
612 return false;
613 }
614 m_continuousFrameData.append(frame.payload, frame.payloadLength);
615 skipBuffer(frameEnd - m_buffer.data());
616 if (frame.final) {
617 // onmessage handler may eventually call the other methods of this channel,
618 // so we should pretend that we have finished to read this frame and
619 // make sure that the member variables are in a consistent state before
620 // the handler is invoked.
621 // Vector<char>::swap() is used here to clear m_continuousFrameData.
622 OwnPtr<Vector<char> > continuousFrameData = adoptPtr(new Vector<char>);
623 m_continuousFrameData.swap(*continuousFrameData);
624 m_hasContinuousFrame = false;
625 if (m_continuousFrameOpCode == WebSocketFrame::OpCodeText) {
626 String message;
627 if (continuousFrameData->size())
628 message = String::fromUTF8(continuousFrameData->data(), continuousFrameData->size());
629 else
630 message = "";
631 if (message.isNull())
632 failAsError("Could not decode a text frame as UTF-8.");
633 else
634 m_client->didReceiveMessage(message);
635 } else if (m_continuousFrameOpCode == WebSocketFrame::OpCodeBinary) {
636 m_client->didReceiveBinaryData(continuousFrameData.release());
637 }
638 }
639 break;
640
641 case WebSocketFrame::OpCodeText:
642 if (frame.final) {
643 String message;
644 if (frame.payloadLength)
645 message = String::fromUTF8(frame.payload, frame.payloadLength);
646 else
647 message = "";
648 skipBuffer(frameEnd - m_buffer.data());
649 if (message.isNull())
650 failAsError("Could not decode a text frame as UTF-8.");
651 else
652 m_client->didReceiveMessage(message);
653 } else {
654 m_hasContinuousFrame = true;
655 m_continuousFrameOpCode = WebSocketFrame::OpCodeText;
656 ASSERT(m_continuousFrameData.isEmpty());
657 m_continuousFrameData.append(frame.payload, frame.payloadLength);
658 skipBuffer(frameEnd - m_buffer.data());
659 }
660 break;
661
662 case WebSocketFrame::OpCodeBinary:
663 if (frame.final) {
664 OwnPtr<Vector<char> > binaryData = adoptPtr(new Vector<char>(frame.payloadLength));
665 memcpy(binaryData->data(), frame.payload, frame.payloadLength);
666 skipBuffer(frameEnd - m_buffer.data());
667 m_client->didReceiveBinaryData(binaryData.release());
668 } else {
669 m_hasContinuousFrame = true;
670 m_continuousFrameOpCode = WebSocketFrame::OpCodeBinary;
671 ASSERT(m_continuousFrameData.isEmpty());
672 m_continuousFrameData.append(frame.payload, frame.payloadLength);
673 skipBuffer(frameEnd - m_buffer.data());
674 }
675 break;
676
677 case WebSocketFrame::OpCodeClose:
678 if (!frame.payloadLength) {
679 m_closeEventCode = CloseEventCodeNoStatusRcvd;
680 } else if (frame.payloadLength == 1) {
681 m_closeEventCode = CloseEventCodeAbnormalClosure;
682 failAsError("Received a broken close frame containing an invalid size body.");
683 return false;
684 } else {
685 unsigned char highByte = static_cast<unsigned char>(frame.payload[0]);
686 unsigned char lowByte = static_cast<unsigned char>(frame.payload[1]);
687 m_closeEventCode = highByte << 8 | lowByte;
688 if (m_closeEventCode == CloseEventCodeNoStatusRcvd || m_closeEventCode == CloseEventCodeAbnormalClosure || m_closeEventCode == CloseEventCodeTLSHandshake) {
689 m_closeEventCode = CloseEventCodeAbnormalClosure;
690 failAsError("Received a broken close frame containing a reserved status code.");
691 return false;
692 }
693 }
694 if (frame.payloadLength >= 3)
695 m_closeEventReason = String::fromUTF8(&frame.payload[2], frame.payloadLength - 2);
696 else
697 m_closeEventReason = "";
698 skipBuffer(frameEnd - m_buffer.data());
699 m_receivedClosingHandshake = true;
700 startClosingHandshake(m_closeEventCode, m_closeEventReason);
701 m_outgoingFrameQueueStatus = OutgoingFrameQueueClosing;
702 processOutgoingFrameQueue();
703 break;
704
705 case WebSocketFrame::OpCodePing:
706 enqueueRawFrame(WebSocketFrame::OpCodePong, frame.payload, frame.payloadLength);
707 skipBuffer(frameEnd - m_buffer.data());
708 processOutgoingFrameQueue();
709 break;
710
711 case WebSocketFrame::OpCodePong:
712 // A server may send a pong in response to our ping, or an unsolicited pong which is not associated with
713 // any specific ping. Either way, there's nothing to do on receipt of pong.
714 skipBuffer(frameEnd - m_buffer.data());
715 break;
716
717 default:
718 ASSERT_NOT_REACHED();
719 skipBuffer(frameEnd - m_buffer.data());
720 break;
721 }
722
723 m_perMessageDeflate.resetInflateBuffer();
724 return !m_buffer.isEmpty();
725 }
726
enqueueTextFrame(const CString & string)727 void MainThreadWebSocketChannel::enqueueTextFrame(const CString& string)
728 {
729 ASSERT(m_outgoingFrameQueueStatus == OutgoingFrameQueueOpen);
730
731 OwnPtr<QueuedFrame> frame = adoptPtr(new QueuedFrame);
732 frame->opCode = WebSocketFrame::OpCodeText;
733 frame->frameType = QueuedFrameTypeString;
734 frame->stringData = string;
735 m_outgoingFrameQueue.append(frame.release());
736 }
737
enqueueRawFrame(WebSocketFrame::OpCode opCode,const char * data,size_t dataLength)738 void MainThreadWebSocketChannel::enqueueRawFrame(WebSocketFrame::OpCode opCode, const char* data, size_t dataLength)
739 {
740 ASSERT(m_outgoingFrameQueueStatus == OutgoingFrameQueueOpen);
741
742 OwnPtr<QueuedFrame> frame = adoptPtr(new QueuedFrame);
743 frame->opCode = opCode;
744 frame->frameType = QueuedFrameTypeVector;
745 frame->vectorData.resize(dataLength);
746 if (dataLength)
747 memcpy(frame->vectorData.data(), data, dataLength);
748 m_outgoingFrameQueue.append(frame.release());
749 }
750
enqueueVector(WebSocketFrame::OpCode opCode,PassOwnPtr<Vector<char>> data)751 void MainThreadWebSocketChannel::enqueueVector(WebSocketFrame::OpCode opCode, PassOwnPtr<Vector<char> > data)
752 {
753 ASSERT(m_outgoingFrameQueueStatus == OutgoingFrameQueueOpen);
754
755 OwnPtr<QueuedFrame> frame = adoptPtr(new QueuedFrame);
756 frame->opCode = opCode;
757 frame->frameType = QueuedFrameTypeVector;
758 frame->vectorData.swap(*data);
759 m_outgoingFrameQueue.append(frame.release());
760 }
761
enqueueBlobFrame(WebSocketFrame::OpCode opCode,PassRefPtr<BlobDataHandle> blobData)762 void MainThreadWebSocketChannel::enqueueBlobFrame(WebSocketFrame::OpCode opCode, PassRefPtr<BlobDataHandle> blobData)
763 {
764 ASSERT(m_outgoingFrameQueueStatus == OutgoingFrameQueueOpen);
765
766 OwnPtr<QueuedFrame> frame = adoptPtr(new QueuedFrame);
767 frame->opCode = opCode;
768 frame->frameType = QueuedFrameTypeBlob;
769 frame->blobData = blobData;
770 m_outgoingFrameQueue.append(frame.release());
771 }
772
processOutgoingFrameQueue()773 void MainThreadWebSocketChannel::processOutgoingFrameQueue()
774 {
775 if (m_outgoingFrameQueueStatus == OutgoingFrameQueueClosed)
776 return;
777
778 while (!m_outgoingFrameQueue.isEmpty()) {
779 OwnPtr<QueuedFrame> frame = m_outgoingFrameQueue.takeFirst();
780 switch (frame->frameType) {
781 case QueuedFrameTypeString: {
782 if (!sendFrame(frame->opCode, frame->stringData.data(), frame->stringData.length()))
783 failAsError("Failed to send WebSocket frame.");
784 break;
785 }
786
787 case QueuedFrameTypeVector:
788 if (!sendFrame(frame->opCode, frame->vectorData.data(), frame->vectorData.size()))
789 failAsError("Failed to send WebSocket frame.");
790 break;
791
792 case QueuedFrameTypeBlob: {
793 switch (m_blobLoaderStatus) {
794 case BlobLoaderNotStarted:
795 ref(); // Will be derefed after didFinishLoading() or didFail().
796 ASSERT(!m_blobLoader);
797 m_blobLoader = adoptPtr(new FileReaderLoader(FileReaderLoader::ReadAsArrayBuffer, this));
798 m_blobLoaderStatus = BlobLoaderStarted;
799 m_blobLoader->start(m_document, frame->blobData);
800 m_outgoingFrameQueue.prepend(frame.release());
801 return;
802
803 case BlobLoaderStarted:
804 case BlobLoaderFailed:
805 m_outgoingFrameQueue.prepend(frame.release());
806 return;
807
808 case BlobLoaderFinished: {
809 RefPtr<ArrayBuffer> result = m_blobLoader->arrayBufferResult();
810 m_blobLoader.clear();
811 m_blobLoaderStatus = BlobLoaderNotStarted;
812 if (!sendFrame(frame->opCode, static_cast<const char*>(result->data()), result->byteLength()))
813 failAsError("Failed to send WebSocket frame.");
814 break;
815 }
816 }
817 break;
818 }
819
820 default:
821 ASSERT_NOT_REACHED();
822 break;
823 }
824 }
825
826 ASSERT(m_outgoingFrameQueue.isEmpty());
827 if (m_outgoingFrameQueueStatus == OutgoingFrameQueueClosing) {
828 m_outgoingFrameQueueStatus = OutgoingFrameQueueClosed;
829 m_handle->close();
830 }
831 }
832
abortOutgoingFrameQueue()833 void MainThreadWebSocketChannel::abortOutgoingFrameQueue()
834 {
835 m_outgoingFrameQueue.clear();
836 m_outgoingFrameQueueStatus = OutgoingFrameQueueClosed;
837 if (m_blobLoaderStatus == BlobLoaderStarted) {
838 m_blobLoader->cancel();
839 didFail(FileError::ABORT_ERR);
840 }
841 }
842
sendFrame(WebSocketFrame::OpCode opCode,const char * data,size_t dataLength)843 bool MainThreadWebSocketChannel::sendFrame(WebSocketFrame::OpCode opCode, const char* data, size_t dataLength)
844 {
845 ASSERT(m_handle);
846 ASSERT(!m_suspended);
847
848 WebSocketFrame frame(opCode, data, dataLength, WebSocketFrame::Final | WebSocketFrame::Masked);
849 InspectorInstrumentation::didSendWebSocketFrame(m_document, m_identifier, frame.opCode, frame.masked, frame.payload, frame.payloadLength);
850
851 OwnPtr<DeflateResultHolder> deflateResult = m_deflateFramer.deflate(frame);
852 if (!deflateResult->succeeded()) {
853 failAsError(deflateResult->failureReason());
854 return false;
855 }
856
857 if (!m_perMessageDeflate.deflate(frame)) {
858 failAsError(m_perMessageDeflate.failureReason());
859 return false;
860 }
861
862 Vector<char> frameData;
863 frame.makeFrameData(frameData);
864 m_framingOverheadQueue.append(FramingOverhead(opCode, frameData.size(), dataLength));
865
866 m_perMessageDeflate.resetDeflateBuffer();
867 return m_handle->send(frameData.data(), frameData.size());
868 }
869
870 } // namespace WebCore
871