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