• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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*);
~BlobLoader()65     virtual ~BlobLoader() { }
66 
67     void cancel();
68 
69     // FileReaderLoaderClient functions.
didStartLoading()70     virtual void didStartLoading() OVERRIDE { }
didReceiveData()71     virtual void didReceiveData() OVERRIDE { }
72     virtual void didFinishLoading() OVERRIDE;
73     virtual void didFail(FileError::ErrorCode) OVERRIDE;
74 
trace(Visitor * visitor)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 
BlobLoader(PassRefPtr<BlobDataHandle> blobDataHandle,NewWebSocketChannelImpl * channel)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 
cancel()92 void NewWebSocketChannelImpl::BlobLoader::cancel()
93 {
94     m_loader.cancel();
95     // didFail will be called immediately.
96     // |this| is deleted here.
97 }
98 
didFinishLoading()99 void NewWebSocketChannelImpl::BlobLoader::didFinishLoading()
100 {
101     m_channel->didFinishLoadingBlob(m_loader.arrayBufferResult());
102     // |this| is deleted here.
103 }
104 
didFail(FileError::ErrorCode errorCode)105 void NewWebSocketChannelImpl::BlobLoader::didFail(FileError::ErrorCode errorCode)
106 {
107     m_channel->didFailLoadingBlob(errorCode);
108     // |this| is deleted here.
109 }
110 
NewWebSocketChannelImpl(ExecutionContext * context,WebSocketChannelClient * client,const String & sourceURL,unsigned lineNumber)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 
~NewWebSocketChannelImpl()126 NewWebSocketChannelImpl::~NewWebSocketChannelImpl()
127 {
128     abortAsyncOperations();
129 }
130 
connect(const KURL & url,const String & protocol)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 
send(const String & message)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 
send(PassRefPtr<BlobDataHandle> blobDataHandle)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 
send(const ArrayBuffer & buffer,unsigned byteOffset,unsigned byteLength)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 
send(PassOwnPtr<Vector<char>> data)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 
close(int code,const String & reason)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 
fail(const String & reason,MessageLevel level,const String & sourceURL,unsigned lineNumber)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 
disconnect()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 
suspend()272 void NewWebSocketChannelImpl::suspend()
273 {
274     WTF_LOG(Network, "NewWebSocketChannelImpl %p suspend()", this);
275 }
276 
resume()277 void NewWebSocketChannelImpl::resume()
278 {
279     WTF_LOG(Network, "NewWebSocketChannelImpl %p resume()", this);
280 }
281 
Message(const String & text)282 NewWebSocketChannelImpl::Message::Message(const String& text)
283     : type(MessageTypeText)
284     , text(text.utf8(StrictUTF8ConversionReplacingUnpairedSurrogatesWithFFFD)) { }
285 
Message(PassRefPtr<BlobDataHandle> blobDataHandle)286 NewWebSocketChannelImpl::Message::Message(PassRefPtr<BlobDataHandle> blobDataHandle)
287     : type(MessageTypeBlob)
288     , blobDataHandle(blobDataHandle) { }
289 
Message(PassRefPtr<ArrayBuffer> arrayBuffer)290 NewWebSocketChannelImpl::Message::Message(PassRefPtr<ArrayBuffer> arrayBuffer)
291     : type(MessageTypeArrayBuffer)
292     , arrayBuffer(arrayBuffer) { }
293 
Message(PassOwnPtr<Vector<char>> vectorData)294 NewWebSocketChannelImpl::Message::Message(PassOwnPtr<Vector<char> > vectorData)
295     : type(MessageTypeVector)
296     , vectorData(vectorData) { }
297 
sendInternal()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 
flowControlIfNecessary()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 
abortAsyncOperations()362 void NewWebSocketChannelImpl::abortAsyncOperations()
363 {
364     if (m_blobLoader) {
365         m_blobLoader->cancel();
366         m_blobLoader.clear();
367     }
368 }
369 
handleDidClose(bool wasClean,unsigned short code,const String & reason)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 
document()385 Document* NewWebSocketChannelImpl::document()
386 {
387     ASSERT(m_identifier);
388     ExecutionContext* context = executionContext();
389     ASSERT(context->isDocument());
390     return toDocument(context);
391 }
392 
didConnect(WebSocketHandle * handle,bool fail,const blink::WebString & selectedProtocol,const blink::WebString & extensions)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 
didStartOpeningHandshake(WebSocketHandle * handle,const blink::WebSocketHandshakeRequestInfo & request)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 
didFinishOpeningHandshake(WebSocketHandle * handle,const blink::WebSocketHandshakeResponseInfo & response)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 
didFail(WebSocketHandle * handle,const blink::WebString & message)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 
didReceiveData(WebSocketHandle * handle,bool fin,WebSocketHandle::MessageType type,const char * data,size_t size)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 
didClose(WebSocketHandle * handle,bool wasClean,unsigned short code,const blink::WebString & reason)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 
didReceiveFlowControl(WebSocketHandle * handle,int64_t quota)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 
didStartClosingHandshake(WebSocketHandle * handle)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 
didFinishLoadingBlob(PassRefPtr<ArrayBuffer> buffer)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 
didFailLoadingBlob(FileError::ErrorCode errorCode)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 
trace(Visitor * visitor)546 void NewWebSocketChannelImpl::trace(Visitor* visitor)
547 {
548     visitor->trace(m_blobLoader);
549     WebSocketChannel::trace(visitor);
550 }
551 
552 } // namespace WebCore
553