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