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
59using blink::WebSocketHandle;
60
61namespace blink {
62
63class NewWebSocketChannelImpl::BlobLoader FINAL : public GarbageCollectedFinalized<NewWebSocketChannelImpl::BlobLoader>, public FileReaderLoaderClient {
64public:
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
81private:
82    Member<NewWebSocketChannelImpl> m_channel;
83    FileReaderLoader m_loader;
84};
85
86NewWebSocketChannelImpl::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
93void NewWebSocketChannelImpl::BlobLoader::cancel()
94{
95    m_loader.cancel();
96    // didFail will be called immediately.
97    // |this| is deleted here.
98}
99
100void NewWebSocketChannelImpl::BlobLoader::didFinishLoading()
101{
102    m_channel->didFinishLoadingBlob(m_loader.arrayBufferResult());
103    // |this| is deleted here.
104}
105
106void NewWebSocketChannelImpl::BlobLoader::didFail(FileError::ErrorCode errorCode)
107{
108    m_channel->didFailLoadingBlob(errorCode);
109    // |this| is deleted here.
110}
111
112NewWebSocketChannelImpl::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
127NewWebSocketChannelImpl::~NewWebSocketChannelImpl()
128{
129    ASSERT(!m_blobLoader);
130}
131
132bool 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
175void 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
188void 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
203void 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
218void 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
230void 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
239void 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
257void 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
272void NewWebSocketChannelImpl::suspend()
273{
274    WTF_LOG(Network, "NewWebSocketChannelImpl %p suspend()", this);
275}
276
277void NewWebSocketChannelImpl::resume()
278{
279    WTF_LOG(Network, "NewWebSocketChannelImpl %p resume()", this);
280}
281
282NewWebSocketChannelImpl::Message::Message(const String& text)
283    : type(MessageTypeText)
284    , text(text.utf8(StrictUTF8ConversionReplacingUnpairedSurrogatesWithFFFD)) { }
285
286NewWebSocketChannelImpl::Message::Message(PassRefPtr<BlobDataHandle> blobDataHandle)
287    : type(MessageTypeBlob)
288    , blobDataHandle(blobDataHandle) { }
289
290NewWebSocketChannelImpl::Message::Message(PassRefPtr<ArrayBuffer> arrayBuffer)
291    : type(MessageTypeArrayBuffer)
292    , arrayBuffer(arrayBuffer) { }
293
294NewWebSocketChannelImpl::Message::Message(PassOwnPtr<Vector<char> > vectorData)
295    : type(MessageTypeVector)
296    , vectorData(vectorData) { }
297
298NewWebSocketChannelImpl::Message::Message(unsigned short code, const String& reason)
299    : type(MessageTypeClose)
300    , code(code)
301    , reason(reason) { }
302
303void 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
367void 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
376void NewWebSocketChannelImpl::abortAsyncOperations()
377{
378    if (m_blobLoader) {
379        m_blobLoader->cancel();
380        m_blobLoader.clear();
381    }
382}
383
384void 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
399Document* NewWebSocketChannelImpl::document()
400{
401    ASSERT(m_identifier);
402    ExecutionContext* context = executionContext();
403    ASSERT(context->isDocument());
404    return toDocument(context);
405}
406
407void 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
421void 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
433void 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
444void 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
454void 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
505void 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
522void 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
530void 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
537void 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
548void 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
560void 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