Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / modules / websockets / NewWebSocketChannelImpl.cpp
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