Home | History | Annotate | Download | only in websockets
      1 /*
      2  * Copyright (C) 2013 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/NewWebSocketChannelImpl.h"
     33 
     34 #include "core/dom/Document.h"
     35 #include "core/dom/ExecutionContext.h"
     36 #include "core/fileapi/FileReaderLoader.h"
     37 #include "core/fileapi/FileReaderLoaderClient.h"
     38 #include "core/frame/LocalFrame.h"
     39 #include "core/inspector/ConsoleMessage.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 "modules/websockets/WebSocketChannelClient.h"
     47 #include "modules/websockets/WebSocketFrame.h"
     48 #include "platform/Logging.h"
     49 #include "platform/network/WebSocketHandshakeRequest.h"
     50 #include "platform/weborigin/SecurityOrigin.h"
     51 #include "public/platform/Platform.h"
     52 #include "public/platform/WebSerializedOrigin.h"
     53 #include "public/platform/WebSocketHandshakeRequestInfo.h"
     54 #include "public/platform/WebSocketHandshakeResponseInfo.h"
     55 #include "public/platform/WebString.h"
     56 #include "public/platform/WebURL.h"
     57 #include "public/platform/WebVector.h"
     58 
     59 using blink::WebSocketHandle;
     60 
     61 namespace blink {
     62 
     63 class NewWebSocketChannelImpl::BlobLoader FINAL : public GarbageCollectedFinalized<NewWebSocketChannelImpl::BlobLoader>, public FileReaderLoaderClient {
     64 public:
     65     BlobLoader(PassRefPtr<BlobDataHandle>, NewWebSocketChannelImpl*);
     66     virtual ~BlobLoader() { }
     67 
     68     void cancel();
     69 
     70     // FileReaderLoaderClient functions.
     71     virtual void didStartLoading() OVERRIDE { }
     72     virtual void didReceiveData() OVERRIDE { }
     73     virtual void didFinishLoading() OVERRIDE;
     74     virtual void didFail(FileError::ErrorCode) OVERRIDE;
     75 
     76     void trace(Visitor* visitor)
     77     {
     78         visitor->trace(m_channel);
     79     }
     80 
     81 private:
     82     Member<NewWebSocketChannelImpl> m_channel;
     83     FileReaderLoader m_loader;
     84 };
     85 
     86 NewWebSocketChannelImpl::BlobLoader::BlobLoader(PassRefPtr<BlobDataHandle> blobDataHandle, NewWebSocketChannelImpl* channel)
     87     : m_channel(channel)
     88     , m_loader(FileReaderLoader::ReadAsArrayBuffer, this)
     89 {
     90     m_loader.start(channel->executionContext(), blobDataHandle);
     91 }
     92 
     93 void NewWebSocketChannelImpl::BlobLoader::cancel()
     94 {
     95     m_loader.cancel();
     96     // didFail will be called immediately.
     97     // |this| is deleted here.
     98 }
     99 
    100 void NewWebSocketChannelImpl::BlobLoader::didFinishLoading()
    101 {
    102     m_channel->didFinishLoadingBlob(m_loader.arrayBufferResult());
    103     // |this| is deleted here.
    104 }
    105 
    106 void NewWebSocketChannelImpl::BlobLoader::didFail(FileError::ErrorCode errorCode)
    107 {
    108     m_channel->didFailLoadingBlob(errorCode);
    109     // |this| is deleted here.
    110 }
    111 
    112 NewWebSocketChannelImpl::NewWebSocketChannelImpl(ExecutionContext* context, WebSocketChannelClient* client, const String& sourceURL, unsigned lineNumber, WebSocketHandle *handle)
    113     : ContextLifecycleObserver(context)
    114     , m_handle(adoptPtr(handle ? handle : Platform::current()->createWebSocketHandle()))
    115     , m_client(client)
    116     , m_identifier(0)
    117     , m_sendingQuota(0)
    118     , m_receivedDataSizeForFlowControl(receivedDataSizeForFlowControlHighWaterMark * 2) // initial quota
    119     , m_sentSizeOfTopMessage(0)
    120     , m_sourceURLAtConstruction(sourceURL)
    121     , m_lineNumberAtConstruction(lineNumber)
    122 {
    123     if (context->isDocument() && toDocument(context)->page())
    124         m_identifier = createUniqueIdentifier();
    125 }
    126 
    127 NewWebSocketChannelImpl::~NewWebSocketChannelImpl()
    128 {
    129     ASSERT(!m_blobLoader);
    130 }
    131 
    132 bool NewWebSocketChannelImpl::connect(const KURL& url, const String& protocol)
    133 {
    134     WTF_LOG(Network, "NewWebSocketChannelImpl %p connect()", this);
    135     if (!m_handle)
    136         return false;
    137 
    138     if (executionContext()->isDocument() && document()->frame()) {
    139         if (!document()->frame()->loader().mixedContentChecker()->canConnectInsecureWebSocket(document()->securityOrigin(), url))
    140             return false;
    141     }
    142     if (MixedContentChecker::isMixedContent(document()->securityOrigin(), url)) {
    143         String message = "Connecting to a non-secure WebSocket server from a secure origin is deprecated.";
    144         document()->addConsoleMessage(ConsoleMessage::create(JSMessageSource, WarningMessageLevel, message));
    145     }
    146 
    147     m_url = url;
    148     Vector<String> protocols;
    149     // Avoid placing an empty token in the Vector when the protocol string is
    150     // empty.
    151     if (!protocol.isEmpty()) {
    152         // Since protocol is already verified and escaped, we can simply split
    153         // it.
    154         protocol.split(", ", true, protocols);
    155     }
    156     WebVector<WebString> webProtocols(protocols.size());
    157     for (size_t i = 0; i < protocols.size(); ++i) {
    158         webProtocols[i] = protocols[i];
    159     }
    160 
    161     if (executionContext()->isDocument() && document()->frame())
    162         document()->frame()->loader().client()->dispatchWillOpenWebSocket(m_handle.get());
    163     m_handle->connect(url, webProtocols, *executionContext()->securityOrigin(), this);
    164 
    165     flowControlIfNecessary();
    166     if (m_identifier) {
    167         TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "WebSocketCreate", "data", InspectorWebSocketCreateEvent::data(document(), m_identifier, url, protocol));
    168         TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline.stack"), "CallStack", "stack", InspectorCallStackEvent::currentCallStack());
    169         // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing.
    170         InspectorInstrumentation::didCreateWebSocket(document(), m_identifier, url, protocol);
    171     }
    172     return true;
    173 }
    174 
    175 void NewWebSocketChannelImpl::send(const String& message)
    176 {
    177     WTF_LOG(Network, "NewWebSocketChannelImpl %p sendText(%s)", this, message.utf8().data());
    178     if (m_identifier) {
    179         // FIXME: Change the inspector API to show the entire message instead
    180         // of individual frames.
    181         CString data = message.utf8();
    182         InspectorInstrumentation::didSendWebSocketFrame(document(), m_identifier, WebSocketFrame::OpCodeText, true, data.data(), data.length());
    183     }
    184     m_messages.append(adoptPtr(new Message(message)));
    185     sendInternal();
    186 }
    187 
    188 void NewWebSocketChannelImpl::send(PassRefPtr<BlobDataHandle> blobDataHandle)
    189 {
    190     WTF_LOG(Network, "NewWebSocketChannelImpl %p sendBlob(%s, %s, %llu)", this, blobDataHandle->uuid().utf8().data(), blobDataHandle->type().utf8().data(), blobDataHandle->size());
    191     if (m_identifier) {
    192         // FIXME: Change the inspector API to show the entire message instead
    193         // of individual frames.
    194         // FIXME: We can't access the data here.
    195         // Since Binary data are not displayed in Inspector, this does not
    196         // affect actual behavior.
    197         InspectorInstrumentation::didSendWebSocketFrame(document(), m_identifier, WebSocketFrame::OpCodeBinary, true, "", 0);
    198     }
    199     m_messages.append(adoptPtr(new Message(blobDataHandle)));
    200     sendInternal();
    201 }
    202 
    203 void NewWebSocketChannelImpl::send(const ArrayBuffer& buffer, unsigned byteOffset, unsigned byteLength)
    204 {
    205     WTF_LOG(Network, "NewWebSocketChannelImpl %p sendArrayBuffer(%p, %u, %u)", this, buffer.data(), byteOffset, byteLength);
    206     if (m_identifier) {
    207         // FIXME: Change the inspector API to show the entire message instead
    208         // of individual frames.
    209         InspectorInstrumentation::didSendWebSocketFrame(document(), m_identifier, WebSocketFrame::OpCodeBinary, true, static_cast<const char*>(buffer.data()) + byteOffset, byteLength);
    210     }
    211     // buffer.slice copies its contents.
    212     // FIXME: Reduce copy by sending the data immediately when we don't need to
    213     // queue the data.
    214     m_messages.append(adoptPtr(new Message(buffer.slice(byteOffset, byteOffset + byteLength))));
    215     sendInternal();
    216 }
    217 
    218 void NewWebSocketChannelImpl::send(PassOwnPtr<Vector<char> > data)
    219 {
    220     WTF_LOG(Network, "NewWebSocketChannelImpl %p sendVector(%p, %llu)", this, data.get(), static_cast<unsigned long long>(data->size()));
    221     if (m_identifier) {
    222         // FIXME: Change the inspector API to show the entire message instead
    223         // of individual frames.
    224         InspectorInstrumentation::didSendWebSocketFrame(document(), m_identifier, WebSocketFrame::OpCodeBinary, true, data->data(), data->size());
    225     }
    226     m_messages.append(adoptPtr(new Message(data)));
    227     sendInternal();
    228 }
    229 
    230 void NewWebSocketChannelImpl::close(int code, const String& reason)
    231 {
    232     WTF_LOG(Network, "NewWebSocketChannelImpl %p close(%d, %s)", this, code, reason.utf8().data());
    233     ASSERT(m_handle);
    234     unsigned short codeToSend = static_cast<unsigned short>(code == CloseEventCodeNotSpecified ? CloseEventCodeNoStatusRcvd : code);
    235     m_messages.append(adoptPtr(new Message(codeToSend, reason)));
    236     sendInternal();
    237 }
    238 
    239 void NewWebSocketChannelImpl::fail(const String& reason, MessageLevel level, const String& sourceURL, unsigned lineNumber)
    240 {
    241     WTF_LOG(Network, "NewWebSocketChannelImpl %p fail(%s)", this, reason.utf8().data());
    242     // m_handle and m_client can be null here.
    243 
    244     if (m_identifier)
    245         InspectorInstrumentation::didReceiveWebSocketFrameError(document(), m_identifier, reason);
    246     const String message = "WebSocket connection to '" + m_url.elidedString() + "' failed: " + reason;
    247     executionContext()->addConsoleMessage(ConsoleMessage::create(JSMessageSource, level, message, sourceURL, lineNumber));
    248 
    249     if (m_client)
    250         m_client->didReceiveMessageError();
    251     // |reason| is only for logging and should not be provided for scripts,
    252     // hence close reason must be empty.
    253     handleDidClose(false, CloseEventCodeAbnormalClosure, String());
    254     // handleDidClose may delete this object.
    255 }
    256 
    257 void NewWebSocketChannelImpl::disconnect()
    258 {
    259     WTF_LOG(Network, "NewWebSocketChannelImpl %p disconnect()", this);
    260     if (m_identifier) {
    261         TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "WebSocketDestroy", "data", InspectorWebSocketEvent::data(document(), m_identifier));
    262         TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline.stack"), "CallStack", "stack", InspectorCallStackEvent::currentCallStack());
    263         // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing.
    264         InspectorInstrumentation::didCloseWebSocket(document(), m_identifier);
    265     }
    266     abortAsyncOperations();
    267     m_handle.clear();
    268     m_client = nullptr;
    269     m_identifier = 0;
    270 }
    271 
    272 void NewWebSocketChannelImpl::suspend()
    273 {
    274     WTF_LOG(Network, "NewWebSocketChannelImpl %p suspend()", this);
    275 }
    276 
    277 void NewWebSocketChannelImpl::resume()
    278 {
    279     WTF_LOG(Network, "NewWebSocketChannelImpl %p resume()", this);
    280 }
    281 
    282 NewWebSocketChannelImpl::Message::Message(const String& text)
    283     : type(MessageTypeText)
    284     , text(text.utf8(StrictUTF8ConversionReplacingUnpairedSurrogatesWithFFFD)) { }
    285 
    286 NewWebSocketChannelImpl::Message::Message(PassRefPtr<BlobDataHandle> blobDataHandle)
    287     : type(MessageTypeBlob)
    288     , blobDataHandle(blobDataHandle) { }
    289 
    290 NewWebSocketChannelImpl::Message::Message(PassRefPtr<ArrayBuffer> arrayBuffer)
    291     : type(MessageTypeArrayBuffer)
    292     , arrayBuffer(arrayBuffer) { }
    293 
    294 NewWebSocketChannelImpl::Message::Message(PassOwnPtr<Vector<char> > vectorData)
    295     : type(MessageTypeVector)
    296     , vectorData(vectorData) { }
    297 
    298 NewWebSocketChannelImpl::Message::Message(unsigned short code, const String& reason)
    299     : type(MessageTypeClose)
    300     , code(code)
    301     , reason(reason) { }
    302 
    303 void NewWebSocketChannelImpl::sendInternal()
    304 {
    305     ASSERT(m_handle);
    306     unsigned long consumedBufferedAmount = 0;
    307     while (!m_messages.isEmpty() && !m_blobLoader) {
    308         bool final = false;
    309         Message* message = m_messages.first().get();
    310         if (m_sendingQuota <= 0 && message->type != MessageTypeClose)
    311             break;
    312         switch (message->type) {
    313         case MessageTypeText: {
    314             WebSocketHandle::MessageType type =
    315                 m_sentSizeOfTopMessage ? WebSocketHandle::MessageTypeContinuation : WebSocketHandle::MessageTypeText;
    316             size_t size = std::min(static_cast<size_t>(m_sendingQuota), message->text.length() - m_sentSizeOfTopMessage);
    317             final = (m_sentSizeOfTopMessage + size == message->text.length());
    318             m_handle->send(final, type, message->text.data() + m_sentSizeOfTopMessage, size);
    319             m_sentSizeOfTopMessage += size;
    320             m_sendingQuota -= size;
    321             consumedBufferedAmount += size;
    322             break;
    323         }
    324         case MessageTypeBlob:
    325             ASSERT(!m_blobLoader);
    326             m_blobLoader = new BlobLoader(message->blobDataHandle, this);
    327             break;
    328         case MessageTypeArrayBuffer: {
    329             WebSocketHandle::MessageType type =
    330                 m_sentSizeOfTopMessage ? WebSocketHandle::MessageTypeContinuation : WebSocketHandle::MessageTypeBinary;
    331             size_t size = std::min(static_cast<size_t>(m_sendingQuota), message->arrayBuffer->byteLength() - m_sentSizeOfTopMessage);
    332             final = (m_sentSizeOfTopMessage + size == message->arrayBuffer->byteLength());
    333             m_handle->send(final, type, static_cast<const char*>(message->arrayBuffer->data()) + m_sentSizeOfTopMessage, size);
    334             m_sentSizeOfTopMessage += size;
    335             m_sendingQuota -= size;
    336             consumedBufferedAmount += size;
    337             break;
    338         }
    339         case MessageTypeVector: {
    340             WebSocketHandle::MessageType type =
    341                 m_sentSizeOfTopMessage ? WebSocketHandle::MessageTypeContinuation : WebSocketHandle::MessageTypeBinary;
    342             size_t size = std::min(static_cast<size_t>(m_sendingQuota), message->vectorData->size() - m_sentSizeOfTopMessage);
    343             final = (m_sentSizeOfTopMessage + size == message->vectorData->size());
    344             m_handle->send(final, type, message->vectorData->data() + m_sentSizeOfTopMessage, size);
    345             m_sentSizeOfTopMessage += size;
    346             m_sendingQuota -= size;
    347             consumedBufferedAmount += size;
    348             break;
    349         }
    350         case MessageTypeClose: {
    351             // No message should be sent from now on.
    352             ASSERT(m_messages.size() == 1);
    353             m_handle->close(message->code, message->reason);
    354             final = true;
    355             break;
    356         }
    357         }
    358         if (final) {
    359             m_messages.removeFirst();
    360             m_sentSizeOfTopMessage = 0;
    361         }
    362     }
    363     if (m_client && consumedBufferedAmount > 0)
    364         m_client->didConsumeBufferedAmount(consumedBufferedAmount);
    365 }
    366 
    367 void NewWebSocketChannelImpl::flowControlIfNecessary()
    368 {
    369     if (!m_handle || m_receivedDataSizeForFlowControl < receivedDataSizeForFlowControlHighWaterMark) {
    370         return;
    371     }
    372     m_handle->flowControl(m_receivedDataSizeForFlowControl);
    373     m_receivedDataSizeForFlowControl = 0;
    374 }
    375 
    376 void NewWebSocketChannelImpl::abortAsyncOperations()
    377 {
    378     if (m_blobLoader) {
    379         m_blobLoader->cancel();
    380         m_blobLoader.clear();
    381     }
    382 }
    383 
    384 void NewWebSocketChannelImpl::handleDidClose(bool wasClean, unsigned short code, const String& reason)
    385 {
    386     m_handle.clear();
    387     abortAsyncOperations();
    388     if (!m_client) {
    389         return;
    390     }
    391     WebSocketChannelClient* client = m_client;
    392     m_client = nullptr;
    393     WebSocketChannelClient::ClosingHandshakeCompletionStatus status =
    394         wasClean ? WebSocketChannelClient::ClosingHandshakeComplete : WebSocketChannelClient::ClosingHandshakeIncomplete;
    395     client->didClose(status, code, reason);
    396     // client->didClose may delete this object.
    397 }
    398 
    399 Document* NewWebSocketChannelImpl::document()
    400 {
    401     ASSERT(m_identifier);
    402     ExecutionContext* context = executionContext();
    403     ASSERT(context->isDocument());
    404     return toDocument(context);
    405 }
    406 
    407 void NewWebSocketChannelImpl::didConnect(WebSocketHandle* handle, bool fail, const WebString& selectedProtocol, const WebString& extensions)
    408 {
    409     WTF_LOG(Network, "NewWebSocketChannelImpl %p didConnect(%p, %d, %s, %s)", this, handle, fail, selectedProtocol.utf8().data(), extensions.utf8().data());
    410     ASSERT(m_handle);
    411     ASSERT(handle == m_handle);
    412     ASSERT(m_client);
    413     if (fail) {
    414         failAsError("Cannot connect to " + m_url.string() + ".");
    415         // failAsError may delete this object.
    416         return;
    417     }
    418     m_client->didConnect(selectedProtocol, extensions);
    419 }
    420 
    421 void NewWebSocketChannelImpl::didStartOpeningHandshake(WebSocketHandle* handle, const WebSocketHandshakeRequestInfo& request)
    422 {
    423     WTF_LOG(Network, "NewWebSocketChannelImpl %p didStartOpeningHandshake(%p)", this, handle);
    424     if (m_identifier) {
    425         TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "WebSocketSendHandshakeRequest", "data", InspectorWebSocketEvent::data(document(), m_identifier));
    426         TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline.stack"), "CallStack", "stack", InspectorCallStackEvent::currentCallStack());
    427         // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing.
    428         InspectorInstrumentation::willSendWebSocketHandshakeRequest(document(), m_identifier, &request.toCoreRequest());
    429         m_handshakeRequest = WebSocketHandshakeRequest::create(request.toCoreRequest());
    430     }
    431 }
    432 
    433 void NewWebSocketChannelImpl::didFinishOpeningHandshake(WebSocketHandle* handle, const WebSocketHandshakeResponseInfo& response)
    434 {
    435     WTF_LOG(Network, "NewWebSocketChannelImpl %p didFinishOpeningHandshake(%p)", this, handle);
    436     if (m_identifier) {
    437         TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "WebSocketReceiveHandshakeResponse", "data", InspectorWebSocketEvent::data(document(), m_identifier));
    438         // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing.
    439         InspectorInstrumentation::didReceiveWebSocketHandshakeResponse(document(), m_identifier, m_handshakeRequest.get(), &response.toCoreResponse());
    440     }
    441     m_handshakeRequest.clear();
    442 }
    443 
    444 void NewWebSocketChannelImpl::didFail(WebSocketHandle* handle, const WebString& message)
    445 {
    446     WTF_LOG(Network, "NewWebSocketChannelImpl %p didFail(%p, %s)", this, handle, message.utf8().data());
    447     // This function is called when the browser is required to fail the
    448     // WebSocketConnection. Hence we fail this channel by calling
    449     // |this->failAsError| function.
    450     failAsError(message);
    451     // |this| may be deleted.
    452 }
    453 
    454 void NewWebSocketChannelImpl::didReceiveData(WebSocketHandle* handle, bool fin, WebSocketHandle::MessageType type, const char* data, size_t size)
    455 {
    456     WTF_LOG(Network, "NewWebSocketChannelImpl %p didReceiveData(%p, %d, %d, (%p, %zu))", this, handle, fin, type, data, size);
    457     ASSERT(m_handle);
    458     ASSERT(handle == m_handle);
    459     ASSERT(m_client);
    460     // Non-final frames cannot be empty.
    461     ASSERT(fin || size);
    462     switch (type) {
    463     case WebSocketHandle::MessageTypeText:
    464         ASSERT(m_receivingMessageData.isEmpty());
    465         m_receivingMessageTypeIsText = true;
    466         break;
    467     case WebSocketHandle::MessageTypeBinary:
    468         ASSERT(m_receivingMessageData.isEmpty());
    469         m_receivingMessageTypeIsText = false;
    470         break;
    471     case WebSocketHandle::MessageTypeContinuation:
    472         ASSERT(!m_receivingMessageData.isEmpty());
    473         break;
    474     }
    475 
    476     m_receivingMessageData.append(data, size);
    477     m_receivedDataSizeForFlowControl += size;
    478     flowControlIfNecessary();
    479     if (!fin) {
    480         return;
    481     }
    482     if (m_identifier) {
    483         // FIXME: Change the inspector API to show the entire message instead
    484         // of individual frames.
    485         WebSocketFrame::OpCode opcode = m_receivingMessageTypeIsText ? WebSocketFrame::OpCodeText : WebSocketFrame::OpCodeBinary;
    486         WebSocketFrame frame(opcode, m_receivingMessageData.data(), m_receivingMessageData.size(), WebSocketFrame::Final);
    487         InspectorInstrumentation::didReceiveWebSocketFrame(document(), m_identifier, frame.opCode, frame.masked, frame.payload, frame.payloadLength);
    488     }
    489     if (m_receivingMessageTypeIsText) {
    490         String message = m_receivingMessageData.isEmpty() ? emptyString() : String::fromUTF8(m_receivingMessageData.data(), m_receivingMessageData.size());
    491         m_receivingMessageData.clear();
    492         if (message.isNull()) {
    493             failAsError("Could not decode a text frame as UTF-8.");
    494             // failAsError may delete this object.
    495         } else {
    496             m_client->didReceiveMessage(message);
    497         }
    498     } else {
    499         OwnPtr<Vector<char> > binaryData = adoptPtr(new Vector<char>);
    500         binaryData->swap(m_receivingMessageData);
    501         m_client->didReceiveBinaryData(binaryData.release());
    502     }
    503 }
    504 
    505 void NewWebSocketChannelImpl::didClose(WebSocketHandle* handle, bool wasClean, unsigned short code, const WebString& reason)
    506 {
    507     WTF_LOG(Network, "NewWebSocketChannelImpl %p didClose(%p, %d, %u, %s)", this, handle, wasClean, code, String(reason).utf8().data());
    508     ASSERT(m_handle);
    509     m_handle.clear();
    510     if (m_identifier) {
    511         TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "WebSocketDestroy", "data", InspectorWebSocketEvent::data(document(), m_identifier));
    512         TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline.stack"), "CallStack", "stack", InspectorCallStackEvent::currentCallStack());
    513         // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing.
    514         InspectorInstrumentation::didCloseWebSocket(document(), m_identifier);
    515         m_identifier = 0;
    516     }
    517 
    518     handleDidClose(wasClean, code, reason);
    519     // handleDidClose may delete this object.
    520 }
    521 
    522 void NewWebSocketChannelImpl::didReceiveFlowControl(WebSocketHandle* handle, int64_t quota)
    523 {
    524     WTF_LOG(Network, "NewWebSocketChannelImpl %p didReceiveFlowControl(%p, %ld)", this, handle, static_cast<long>(quota));
    525     ASSERT(m_handle);
    526     m_sendingQuota += quota;
    527     sendInternal();
    528 }
    529 
    530 void NewWebSocketChannelImpl::didStartClosingHandshake(WebSocketHandle* handle)
    531 {
    532     WTF_LOG(Network, "NewWebSocketChannelImpl %p didStartClosingHandshake(%p)", this, handle);
    533     if (m_client)
    534         m_client->didStartClosingHandshake();
    535 }
    536 
    537 void NewWebSocketChannelImpl::didFinishLoadingBlob(PassRefPtr<ArrayBuffer> buffer)
    538 {
    539     m_blobLoader.clear();
    540     ASSERT(m_handle);
    541     // The loaded blob is always placed on m_messages[0].
    542     ASSERT(m_messages.size() > 0 && m_messages.first()->type == MessageTypeBlob);
    543     // We replace it with the loaded blob.
    544     m_messages.first() = adoptPtr(new Message(buffer));
    545     sendInternal();
    546 }
    547 
    548 void NewWebSocketChannelImpl::didFailLoadingBlob(FileError::ErrorCode errorCode)
    549 {
    550     m_blobLoader.clear();
    551     if (errorCode == FileError::ABORT_ERR) {
    552         // The error is caused by cancel().
    553         return;
    554     }
    555     // FIXME: Generate human-friendly reason message.
    556     failAsError("Failed to load Blob: error code = " + String::number(errorCode));
    557     // |this| can be deleted here.
    558 }
    559 
    560 void NewWebSocketChannelImpl::trace(Visitor* visitor)
    561 {
    562     visitor->trace(m_blobLoader);
    563     visitor->trace(m_client);
    564     WebSocketChannel::trace(visitor);
    565 }
    566 
    567 } // namespace blink
    568