Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / third_party / WebKit / Source / modules / websockets / DocumentWebSocketChannel.cpp
blob67688efcbfa9b0a448c0be345501727e236af9e1
1 /*
2 * Copyright (C) 2013 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
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.
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.
31 #include "config.h"
32 #include "modules/websockets/DocumentWebSocketChannel.h"
34 #include "core/dom/DOMArrayBuffer.h"
35 #include "core/dom/Document.h"
36 #include "core/dom/ExecutionContext.h"
37 #include "core/fetch/UniqueIdentifier.h"
38 #include "core/fileapi/FileReaderLoader.h"
39 #include "core/fileapi/FileReaderLoaderClient.h"
40 #include "core/frame/LocalFrame.h"
41 #include "core/inspector/ConsoleMessage.h"
42 #include "core/inspector/InspectorInstrumentation.h"
43 #include "core/loader/FrameLoader.h"
44 #include "core/loader/FrameLoaderClient.h"
45 #include "core/loader/MixedContentChecker.h"
46 #include "modules/websockets/InspectorWebSocketEvents.h"
47 #include "modules/websockets/WebSocketChannelClient.h"
48 #include "modules/websockets/WebSocketFrame.h"
49 #include "platform/Logging.h"
50 #include "platform/network/WebSocketHandshakeRequest.h"
51 #include "platform/weborigin/SecurityOrigin.h"
52 #include "public/platform/Platform.h"
53 #include "public/platform/WebSecurityOrigin.h"
54 #include "public/platform/WebSocketHandshakeRequestInfo.h"
55 #include "public/platform/WebSocketHandshakeResponseInfo.h"
56 #include "public/platform/WebString.h"
57 #include "public/platform/WebURL.h"
58 #include "public/platform/WebVector.h"
60 using blink::WebSocketHandle;
62 namespace blink {
64 class DocumentWebSocketChannel::BlobLoader final : public GarbageCollectedFinalized<DocumentWebSocketChannel::BlobLoader>, public FileReaderLoaderClient {
65 public:
66 BlobLoader(PassRefPtr<BlobDataHandle>, DocumentWebSocketChannel*);
67 ~BlobLoader() override { }
69 void cancel();
71 // FileReaderLoaderClient functions.
72 void didStartLoading() override { }
73 void didReceiveData() override { }
74 void didFinishLoading() override;
75 void didFail(FileError::ErrorCode) override;
77 DEFINE_INLINE_TRACE()
79 visitor->trace(m_channel);
82 private:
83 Member<DocumentWebSocketChannel> m_channel;
84 FileReaderLoader m_loader;
87 DocumentWebSocketChannel::BlobLoader::BlobLoader(PassRefPtr<BlobDataHandle> blobDataHandle, DocumentWebSocketChannel* channel)
88 : m_channel(channel)
89 , m_loader(FileReaderLoader::ReadAsArrayBuffer, this)
91 m_loader.start(channel->executionContext(), blobDataHandle);
94 void DocumentWebSocketChannel::BlobLoader::cancel()
96 m_loader.cancel();
97 // didFail will be called immediately.
98 // |this| is deleted here.
101 void DocumentWebSocketChannel::BlobLoader::didFinishLoading()
103 m_channel->didFinishLoadingBlob(m_loader.arrayBufferResult());
104 // |this| is deleted here.
107 void DocumentWebSocketChannel::BlobLoader::didFail(FileError::ErrorCode errorCode)
109 m_channel->didFailLoadingBlob(errorCode);
110 // |this| is deleted here.
113 DocumentWebSocketChannel::DocumentWebSocketChannel(ExecutionContext* context, WebSocketChannelClient* client, const String& sourceURL, unsigned lineNumber, WebSocketHandle *handle)
114 : ContextLifecycleObserver(context)
115 , m_handle(adoptPtr(handle ? handle : Platform::current()->createWebSocketHandle()))
116 , m_client(client)
117 , m_identifier(0)
118 , m_sendingQuota(0)
119 , m_receivedDataSizeForFlowControl(receivedDataSizeForFlowControlHighWaterMark * 2) // initial quota
120 , m_sentSizeOfTopMessage(0)
121 , m_sourceURLAtConstruction(sourceURL)
122 , m_lineNumberAtConstruction(lineNumber)
124 if (context->isDocument())
125 m_identifier = createUniqueIdentifier();
128 DocumentWebSocketChannel::~DocumentWebSocketChannel()
130 ASSERT(!m_blobLoader);
133 bool DocumentWebSocketChannel::connect(const KURL& url, const String& protocol)
135 WTF_LOG(Network, "DocumentWebSocketChannel %p connect()", this);
136 if (!m_handle)
137 return false;
139 if (executionContext()->isDocument() && document()->frame()) {
140 if (MixedContentChecker::shouldBlockWebSocket(document()->frame(), url))
141 return false;
143 if (MixedContentChecker::isMixedContent(document()->securityOrigin(), url)) {
144 String message = "Connecting to a non-secure WebSocket server from a secure origin is deprecated.";
145 document()->addConsoleMessage(ConsoleMessage::create(JSMessageSource, WarningMessageLevel, message));
148 m_url = url;
149 Vector<String> protocols;
150 // Avoid placing an empty token in the Vector when the protocol string is
151 // empty.
152 if (!protocol.isEmpty()) {
153 // Since protocol is already verified and escaped, we can simply split
154 // it.
155 protocol.split(", ", true, protocols);
157 WebVector<WebString> webProtocols(protocols.size());
158 for (size_t i = 0; i < protocols.size(); ++i) {
159 webProtocols[i] = protocols[i];
162 if (executionContext()->isDocument() && document()->frame())
163 document()->frame()->loader().client()->dispatchWillOpenWebSocket(m_handle.get());
164 m_handle->connect(url, webProtocols, WebSecurityOrigin(executionContext()->securityOrigin()), this);
166 flowControlIfNecessary();
167 if (m_identifier) {
168 TRACE_EVENT_INSTANT1("devtools.timeline", "WebSocketCreate", TRACE_EVENT_SCOPE_THREAD, "data", InspectorWebSocketCreateEvent::data(document(), m_identifier, url, protocol));
169 InspectorInstrumentation::didCreateWebSocket(document(), m_identifier, url, protocol);
171 return true;
174 void DocumentWebSocketChannel::send(const CString& message)
176 WTF_LOG(Network, "DocumentWebSocketChannel %p sendText(%s)", this, message.data());
177 if (m_identifier) {
178 // FIXME: Change the inspector API to show the entire message instead
179 // of individual frames.
180 InspectorInstrumentation::didSendWebSocketFrame(document(), m_identifier, WebSocketFrame::OpCodeText, true, message.data(), message.length());
182 m_messages.append(adoptPtr(new Message(message)));
183 processSendQueue();
186 void DocumentWebSocketChannel::send(PassRefPtr<BlobDataHandle> blobDataHandle)
188 WTF_LOG(Network, "DocumentWebSocketChannel %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);
197 m_messages.append(adoptPtr(new Message(blobDataHandle)));
198 processSendQueue();
201 void DocumentWebSocketChannel::send(const DOMArrayBuffer& buffer, unsigned byteOffset, unsigned byteLength)
203 WTF_LOG(Network, "DocumentWebSocketChannel %p sendArrayBuffer(%p, %u, %u)", this, buffer.data(), byteOffset, byteLength);
204 if (m_identifier) {
205 // FIXME: Change the inspector API to show the entire message instead
206 // of individual frames.
207 InspectorInstrumentation::didSendWebSocketFrame(document(), m_identifier, WebSocketFrame::OpCodeBinary, true, static_cast<const char*>(buffer.data()) + byteOffset, byteLength);
209 // buffer.slice copies its contents.
210 // FIXME: Reduce copy by sending the data immediately when we don't need to
211 // queue the data.
212 m_messages.append(adoptPtr(new Message(buffer.slice(byteOffset, byteOffset + byteLength))));
213 processSendQueue();
216 void DocumentWebSocketChannel::sendTextAsCharVector(PassOwnPtr<Vector<char>> data)
218 WTF_LOG(Network, "DocumentWebSocketChannel %p sendTextAsCharVector(%p, %llu)", this, data.get(), static_cast<unsigned long long>(data->size()));
219 if (m_identifier) {
220 // FIXME: Change the inspector API to show the entire message instead
221 // of individual frames.
222 InspectorInstrumentation::didSendWebSocketFrame(document(), m_identifier, WebSocketFrame::OpCodeText, true, data->data(), data->size());
224 m_messages.append(adoptPtr(new Message(data, MessageTypeTextAsCharVector)));
225 processSendQueue();
228 void DocumentWebSocketChannel::sendBinaryAsCharVector(PassOwnPtr<Vector<char>> data)
230 WTF_LOG(Network, "DocumentWebSocketChannel %p sendBinaryAsCharVector(%p, %llu)", this, data.get(), static_cast<unsigned long long>(data->size()));
231 if (m_identifier) {
232 // FIXME: Change the inspector API to show the entire message instead
233 // of individual frames.
234 InspectorInstrumentation::didSendWebSocketFrame(document(), m_identifier, WebSocketFrame::OpCodeBinary, true, data->data(), data->size());
236 m_messages.append(adoptPtr(new Message(data, MessageTypeBinaryAsCharVector)));
237 processSendQueue();
240 void DocumentWebSocketChannel::close(int code, const String& reason)
242 WTF_LOG(Network, "DocumentWebSocketChannel %p close(%d, %s)", this, code, reason.utf8().data());
243 ASSERT(m_handle);
244 unsigned short codeToSend = static_cast<unsigned short>(code == CloseEventCodeNotSpecified ? CloseEventCodeNoStatusRcvd : code);
245 m_messages.append(adoptPtr(new Message(codeToSend, reason)));
246 processSendQueue();
249 void DocumentWebSocketChannel::fail(const String& reason, MessageLevel level, const String& sourceURL, unsigned lineNumber)
251 WTF_LOG(Network, "DocumentWebSocketChannel %p fail(%s)", this, reason.utf8().data());
252 // m_handle and m_client can be null here.
254 if (m_identifier)
255 InspectorInstrumentation::didReceiveWebSocketFrameError(document(), m_identifier, reason);
256 const String message = "WebSocket connection to '" + m_url.elidedString() + "' failed: " + reason;
257 executionContext()->addConsoleMessage(ConsoleMessage::create(JSMessageSource, level, message, sourceURL, lineNumber));
259 if (m_client)
260 m_client->didError();
261 // |reason| is only for logging and should not be provided for scripts,
262 // hence close reason must be empty.
263 handleDidClose(false, CloseEventCodeAbnormalClosure, String());
264 // handleDidClose may delete this object.
267 void DocumentWebSocketChannel::disconnect()
269 WTF_LOG(Network, "DocumentWebSocketChannel %p disconnect()", this);
270 if (m_identifier) {
271 TRACE_EVENT_INSTANT1("devtools.timeline", "WebSocketDestroy", TRACE_EVENT_SCOPE_THREAD, "data", InspectorWebSocketEvent::data(document(), m_identifier));
272 InspectorInstrumentation::didCloseWebSocket(document(), m_identifier);
274 abortAsyncOperations();
275 m_handle.clear();
276 m_client = nullptr;
277 m_identifier = 0;
280 DocumentWebSocketChannel::Message::Message(const CString& text)
281 : type(MessageTypeText)
282 , text(text) { }
284 DocumentWebSocketChannel::Message::Message(PassRefPtr<BlobDataHandle> blobDataHandle)
285 : type(MessageTypeBlob)
286 , blobDataHandle(blobDataHandle) { }
288 DocumentWebSocketChannel::Message::Message(PassRefPtr<DOMArrayBuffer> arrayBuffer)
289 : type(MessageTypeArrayBuffer)
290 , arrayBuffer(arrayBuffer) { }
292 DocumentWebSocketChannel::Message::Message(PassOwnPtr<Vector<char>> vectorData, MessageType type)
293 : type(type)
294 , vectorData(vectorData)
296 ASSERT(type == MessageTypeTextAsCharVector || type == MessageTypeBinaryAsCharVector);
299 DocumentWebSocketChannel::Message::Message(unsigned short code, const String& reason)
300 : type(MessageTypeClose)
301 , code(code)
302 , reason(reason) { }
304 void DocumentWebSocketChannel::sendInternal(WebSocketHandle::MessageType messageType, const char* data, size_t totalSize, uint64_t* consumedBufferedAmount)
306 WebSocketHandle::MessageType frameType =
307 m_sentSizeOfTopMessage ? WebSocketHandle::MessageTypeContinuation : messageType;
308 ASSERT(totalSize >= m_sentSizeOfTopMessage);
309 // The first cast is safe since the result of min() never exceeds
310 // the range of size_t. The second cast is necessary to compile
311 // min() on ILP32.
312 size_t size = static_cast<size_t>(std::min(m_sendingQuota, static_cast<uint64_t>(totalSize - m_sentSizeOfTopMessage)));
313 bool final = (m_sentSizeOfTopMessage + size == totalSize);
315 m_handle->send(final, frameType, data + m_sentSizeOfTopMessage, size);
317 m_sentSizeOfTopMessage += size;
318 m_sendingQuota -= size;
319 *consumedBufferedAmount += size;
321 if (final) {
322 m_messages.removeFirst();
323 m_sentSizeOfTopMessage = 0;
327 void DocumentWebSocketChannel::processSendQueue()
329 ASSERT(m_handle);
330 uint64_t consumedBufferedAmount = 0;
331 while (!m_messages.isEmpty() && !m_blobLoader) {
332 Message* message = m_messages.first().get();
333 if (m_sendingQuota == 0 && message->type != MessageTypeClose)
334 break;
335 switch (message->type) {
336 case MessageTypeText:
337 sendInternal(WebSocketHandle::MessageTypeText, message->text.data(), message->text.length(), &consumedBufferedAmount);
338 break;
339 case MessageTypeBlob:
340 ASSERT(!m_blobLoader);
341 m_blobLoader = new BlobLoader(message->blobDataHandle, this);
342 break;
343 case MessageTypeArrayBuffer:
344 sendInternal(WebSocketHandle::MessageTypeBinary, static_cast<const char*>(message->arrayBuffer->data()), message->arrayBuffer->byteLength(), &consumedBufferedAmount);
345 break;
346 case MessageTypeTextAsCharVector:
347 sendInternal(WebSocketHandle::MessageTypeText, message->vectorData->data(), message->vectorData->size(), &consumedBufferedAmount);
348 break;
349 case MessageTypeBinaryAsCharVector:
350 sendInternal(WebSocketHandle::MessageTypeBinary, message->vectorData->data(), message->vectorData->size(), &consumedBufferedAmount);
351 break;
352 case MessageTypeClose: {
353 // No message should be sent from now on.
354 ASSERT(m_messages.size() == 1);
355 ASSERT(m_sentSizeOfTopMessage == 0);
356 m_handle->close(message->code, message->reason);
357 m_messages.removeFirst();
358 break;
362 if (m_client && consumedBufferedAmount > 0)
363 m_client->didConsumeBufferedAmount(consumedBufferedAmount);
366 void DocumentWebSocketChannel::flowControlIfNecessary()
368 if (!m_handle || m_receivedDataSizeForFlowControl < receivedDataSizeForFlowControlHighWaterMark) {
369 return;
371 m_handle->flowControl(m_receivedDataSizeForFlowControl);
372 m_receivedDataSizeForFlowControl = 0;
375 void DocumentWebSocketChannel::abortAsyncOperations()
377 if (m_blobLoader) {
378 m_blobLoader->cancel();
379 m_blobLoader.clear();
383 void DocumentWebSocketChannel::handleDidClose(bool wasClean, unsigned short code, const String& reason)
385 m_handle.clear();
386 abortAsyncOperations();
387 if (!m_client) {
388 return;
390 WebSocketChannelClient* client = m_client;
391 m_client = nullptr;
392 WebSocketChannelClient::ClosingHandshakeCompletionStatus status =
393 wasClean ? WebSocketChannelClient::ClosingHandshakeComplete : WebSocketChannelClient::ClosingHandshakeIncomplete;
394 client->didClose(status, code, reason);
395 // client->didClose may delete this object.
398 Document* DocumentWebSocketChannel::document()
400 ASSERT(m_identifier);
401 ExecutionContext* context = executionContext();
402 ASSERT(context->isDocument());
403 return toDocument(context);
406 void DocumentWebSocketChannel::didConnect(WebSocketHandle* handle, const WebString& selectedProtocol, const WebString& extensions)
408 WTF_LOG(Network, "DocumentWebSocketChannel %p didConnect(%p, %s, %s)", this, handle, selectedProtocol.utf8().c_str(), extensions.utf8().c_str());
410 ASSERT(m_handle);
411 ASSERT(handle == m_handle);
412 ASSERT(m_client);
414 m_client->didConnect(selectedProtocol, extensions);
417 void DocumentWebSocketChannel::didStartOpeningHandshake(WebSocketHandle* handle, const WebSocketHandshakeRequestInfo& request)
419 WTF_LOG(Network, "DocumentWebSocketChannel %p didStartOpeningHandshake(%p)", this, handle);
421 ASSERT(m_handle);
422 ASSERT(handle == m_handle);
424 if (m_identifier) {
425 TRACE_EVENT_INSTANT1("devtools.timeline", "WebSocketSendHandshakeRequest", TRACE_EVENT_SCOPE_THREAD, "data", InspectorWebSocketEvent::data(document(), m_identifier));
426 InspectorInstrumentation::willSendWebSocketHandshakeRequest(document(), m_identifier, &request.toCoreRequest());
427 m_handshakeRequest = WebSocketHandshakeRequest::create(request.toCoreRequest());
431 void DocumentWebSocketChannel::didFinishOpeningHandshake(WebSocketHandle* handle, const WebSocketHandshakeResponseInfo& response)
433 WTF_LOG(Network, "DocumentWebSocketChannel %p didFinishOpeningHandshake(%p)", this, handle);
435 ASSERT(m_handle);
436 ASSERT(handle == m_handle);
438 if (m_identifier) {
439 TRACE_EVENT_INSTANT1("devtools.timeline", "WebSocketReceiveHandshakeResponse", TRACE_EVENT_SCOPE_THREAD, "data", InspectorWebSocketEvent::data(document(), m_identifier));
440 InspectorInstrumentation::didReceiveWebSocketHandshakeResponse(document(), m_identifier, m_handshakeRequest.get(), &response.toCoreResponse());
442 m_handshakeRequest.clear();
445 void DocumentWebSocketChannel::didFail(WebSocketHandle* handle, const WebString& message)
447 WTF_LOG(Network, "DocumentWebSocketChannel %p didFail(%p, %s)", this, handle, message.utf8().data());
449 ASSERT(m_handle);
450 ASSERT(handle == m_handle);
452 // This function is called when the browser is required to fail the
453 // WebSocketConnection. Hence we fail this channel by calling
454 // |this->failAsError| function.
455 failAsError(message);
456 // |this| may be deleted.
459 void DocumentWebSocketChannel::didReceiveData(WebSocketHandle* handle, bool fin, WebSocketHandle::MessageType type, const char* data, size_t size)
461 WTF_LOG(Network, "DocumentWebSocketChannel %p didReceiveData(%p, %d, %d, (%p, %zu))", this, handle, fin, type, data, size);
463 ASSERT(m_handle);
464 ASSERT(handle == m_handle);
465 ASSERT(m_client);
466 // Non-final frames cannot be empty.
467 ASSERT(fin || size);
469 switch (type) {
470 case WebSocketHandle::MessageTypeText:
471 ASSERT(m_receivingMessageData.isEmpty());
472 m_receivingMessageTypeIsText = true;
473 break;
474 case WebSocketHandle::MessageTypeBinary:
475 ASSERT(m_receivingMessageData.isEmpty());
476 m_receivingMessageTypeIsText = false;
477 break;
478 case WebSocketHandle::MessageTypeContinuation:
479 ASSERT(!m_receivingMessageData.isEmpty());
480 break;
483 m_receivingMessageData.append(data, size);
484 m_receivedDataSizeForFlowControl += size;
485 flowControlIfNecessary();
486 if (!fin) {
487 return;
489 if (m_identifier) {
490 // FIXME: Change the inspector API to show the entire message instead
491 // of individual frames.
492 WebSocketFrame::OpCode opcode = m_receivingMessageTypeIsText ? WebSocketFrame::OpCodeText : WebSocketFrame::OpCodeBinary;
493 WebSocketFrame frame(opcode, m_receivingMessageData.data(), m_receivingMessageData.size(), WebSocketFrame::Final);
494 InspectorInstrumentation::didReceiveWebSocketFrame(document(), m_identifier, frame.opCode, frame.masked, frame.payload, frame.payloadLength);
496 if (m_receivingMessageTypeIsText) {
497 String message = m_receivingMessageData.isEmpty() ? emptyString() : String::fromUTF8(m_receivingMessageData.data(), m_receivingMessageData.size());
498 m_receivingMessageData.clear();
499 if (message.isNull()) {
500 failAsError("Could not decode a text frame as UTF-8.");
501 // failAsError may delete this object.
502 } else {
503 m_client->didReceiveTextMessage(message);
505 } else {
506 OwnPtr<Vector<char>> binaryData = adoptPtr(new Vector<char>);
507 binaryData->swap(m_receivingMessageData);
508 m_client->didReceiveBinaryMessage(binaryData.release());
512 void DocumentWebSocketChannel::didClose(WebSocketHandle* handle, bool wasClean, unsigned short code, const WebString& reason)
514 WTF_LOG(Network, "DocumentWebSocketChannel %p didClose(%p, %d, %u, %s)", this, handle, wasClean, code, String(reason).utf8().data());
516 ASSERT(m_handle);
517 ASSERT(handle == m_handle);
519 m_handle.clear();
521 if (m_identifier) {
522 TRACE_EVENT_INSTANT1("devtools.timeline", "WebSocketDestroy", TRACE_EVENT_SCOPE_THREAD, "data", InspectorWebSocketEvent::data(document(), m_identifier));
523 InspectorInstrumentation::didCloseWebSocket(document(), m_identifier);
524 m_identifier = 0;
527 handleDidClose(wasClean, code, reason);
528 // handleDidClose may delete this object.
531 void DocumentWebSocketChannel::didReceiveFlowControl(WebSocketHandle* handle, int64_t quota)
533 WTF_LOG(Network, "DocumentWebSocketChannel %p didReceiveFlowControl(%p, %ld)", this, handle, static_cast<long>(quota));
535 ASSERT(m_handle);
536 ASSERT(handle == m_handle);
537 ASSERT(quota >= 0);
539 m_sendingQuota += quota;
540 processSendQueue();
543 void DocumentWebSocketChannel::didStartClosingHandshake(WebSocketHandle* handle)
545 WTF_LOG(Network, "DocumentWebSocketChannel %p didStartClosingHandshake(%p)", this, handle);
547 ASSERT(m_handle);
548 ASSERT(handle == m_handle);
550 if (m_client)
551 m_client->didStartClosingHandshake();
554 void DocumentWebSocketChannel::didFinishLoadingBlob(PassRefPtr<DOMArrayBuffer> buffer)
556 m_blobLoader.clear();
557 ASSERT(m_handle);
558 // The loaded blob is always placed on m_messages[0].
559 ASSERT(m_messages.size() > 0 && m_messages.first()->type == MessageTypeBlob);
560 // We replace it with the loaded blob.
561 m_messages.first() = adoptPtr(new Message(buffer));
562 processSendQueue();
565 void DocumentWebSocketChannel::didFailLoadingBlob(FileError::ErrorCode errorCode)
567 m_blobLoader.clear();
568 if (errorCode == FileError::ABORT_ERR) {
569 // The error is caused by cancel().
570 return;
572 // FIXME: Generate human-friendly reason message.
573 failAsError("Failed to load Blob: error code = " + String::number(errorCode));
574 // |this| can be deleted here.
577 DEFINE_TRACE(DocumentWebSocketChannel)
579 visitor->trace(m_blobLoader);
580 visitor->trace(m_client);
581 WebSocketChannel::trace(visitor);
582 ContextLifecycleObserver::trace(visitor);
585 } // namespace blink