1 /* 2 * Copyright (C) 2013 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include "config.h" 32 #include "modules/websockets/NewWebSocketChannelImpl.h" 33 34 #include "core/dom/Document.h" 35 #include "core/dom/ExecutionContext.h" 36 #include "core/fileapi/FileReaderLoader.h" 37 #include "core/fileapi/FileReaderLoaderClient.h" 38 #include "core/frame/LocalFrame.h" 39 #include "core/inspector/InspectorInstrumentation.h" 40 #include "core/inspector/InspectorTraceEvents.h" 41 #include "core/loader/FrameLoader.h" 42 #include "core/loader/FrameLoaderClient.h" 43 #include "core/loader/MixedContentChecker.h" 44 #include "core/loader/UniqueIdentifier.h" 45 #include "modules/websockets/WebSocketChannelClient.h" 46 #include "modules/websockets/WebSocketFrame.h" 47 #include "platform/Logging.h" 48 #include "platform/network/WebSocketHandshakeRequest.h" 49 #include "platform/weborigin/SecurityOrigin.h" 50 #include "public/platform/Platform.h" 51 #include "public/platform/WebSerializedOrigin.h" 52 #include "public/platform/WebSocketHandshakeRequestInfo.h" 53 #include "public/platform/WebSocketHandshakeResponseInfo.h" 54 #include "public/platform/WebString.h" 55 #include "public/platform/WebURL.h" 56 #include "public/platform/WebVector.h" 57 58 using blink::WebSocketHandle; 59 60 namespace WebCore { 61 62 class NewWebSocketChannelImpl::BlobLoader FINAL : public NoBaseWillBeGarbageCollectedFinalized<NewWebSocketChannelImpl::BlobLoader>, public FileReaderLoaderClient { 63 public: 64 BlobLoader(PassRefPtr<BlobDataHandle>, NewWebSocketChannelImpl*); 65 virtual ~BlobLoader() { } 66 67 void cancel(); 68 69 // FileReaderLoaderClient functions. 70 virtual void didStartLoading() OVERRIDE { } 71 virtual void didReceiveData() OVERRIDE { } 72 virtual void didFinishLoading() OVERRIDE; 73 virtual void didFail(FileError::ErrorCode) OVERRIDE; 74 75 void trace(Visitor* visitor) 76 { 77 visitor->trace(m_channel); 78 } 79 80 private: 81 RawPtrWillBeMember<NewWebSocketChannelImpl> m_channel; 82 FileReaderLoader m_loader; 83 }; 84 85 NewWebSocketChannelImpl::BlobLoader::BlobLoader(PassRefPtr<BlobDataHandle> blobDataHandle, NewWebSocketChannelImpl* channel) 86 : m_channel(channel) 87 , m_loader(FileReaderLoader::ReadAsArrayBuffer, this) 88 { 89 m_loader.start(channel->executionContext(), blobDataHandle); 90 } 91 92 void NewWebSocketChannelImpl::BlobLoader::cancel() 93 { 94 m_loader.cancel(); 95 // didFail will be called immediately. 96 // |this| is deleted here. 97 } 98 99 void NewWebSocketChannelImpl::BlobLoader::didFinishLoading() 100 { 101 m_channel->didFinishLoadingBlob(m_loader.arrayBufferResult()); 102 // |this| is deleted here. 103 } 104 105 void NewWebSocketChannelImpl::BlobLoader::didFail(FileError::ErrorCode errorCode) 106 { 107 m_channel->didFailLoadingBlob(errorCode); 108 // |this| is deleted here. 109 } 110 111 NewWebSocketChannelImpl::NewWebSocketChannelImpl(ExecutionContext* context, WebSocketChannelClient* client, const String& sourceURL, unsigned lineNumber) 112 : ContextLifecycleObserver(context) 113 , m_handle(adoptPtr(blink::Platform::current()->createWebSocketHandle())) 114 , m_client(client) 115 , m_identifier(0) 116 , m_sendingQuota(0) 117 , m_receivedDataSizeForFlowControl(receivedDataSizeForFlowControlHighWaterMark * 2) // initial quota 118 , m_sentSizeOfTopMessage(0) 119 , m_sourceURLAtConstruction(sourceURL) 120 , m_lineNumberAtConstruction(lineNumber) 121 { 122 if (context->isDocument() && toDocument(context)->page()) 123 m_identifier = createUniqueIdentifier(); 124 } 125 126 NewWebSocketChannelImpl::~NewWebSocketChannelImpl() 127 { 128 abortAsyncOperations(); 129 } 130 131 bool NewWebSocketChannelImpl::connect(const KURL& url, const String& protocol) 132 { 133 WTF_LOG(Network, "NewWebSocketChannelImpl %p connect()", this); 134 if (!m_handle) 135 return false; 136 137 if (executionContext()->isDocument() && document()->frame() && !document()->frame()->loader().mixedContentChecker()->canConnectInsecureWebSocket(document()->securityOrigin(), url)) 138 return false; 139 if (MixedContentChecker::isMixedContent(document()->securityOrigin(), url)) { 140 String message = "Connecting to a non-secure WebSocket server from a secure origin is deprecated."; 141 document()->addConsoleMessage(JSMessageSource, WarningMessageLevel, message); 142 } 143 144 m_url = url; 145 Vector<String> protocols; 146 // Avoid placing an empty token in the Vector when the protocol string is 147 // empty. 148 if (!protocol.isEmpty()) { 149 // Since protocol is already verified and escaped, we can simply split 150 // it. 151 protocol.split(", ", true, protocols); 152 } 153 blink::WebVector<blink::WebString> webProtocols(protocols.size()); 154 for (size_t i = 0; i < protocols.size(); ++i) { 155 webProtocols[i] = protocols[i]; 156 } 157 158 if (executionContext()->isDocument() && document()->frame()) 159 document()->frame()->loader().client()->dispatchWillOpenWebSocket(m_handle.get()); 160 m_handle->connect(url, webProtocols, *executionContext()->securityOrigin(), this); 161 162 flowControlIfNecessary(); 163 if (m_identifier) { 164 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "WebSocketCreate", "data", InspectorWebSocketCreateEvent::data(document(), m_identifier, url, protocol)); 165 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline.stack"), "CallStack", "stack", InspectorCallStackEvent::currentCallStack()); 166 // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing. 167 InspectorInstrumentation::didCreateWebSocket(document(), m_identifier, url, protocol); 168 } 169 return true; 170 } 171 172 WebSocketChannel::SendResult NewWebSocketChannelImpl::send(const String& message) 173 { 174 WTF_LOG(Network, "NewWebSocketChannelImpl %p sendText(%s)", this, message.utf8().data()); 175 if (m_identifier) { 176 // FIXME: Change the inspector API to show the entire message instead 177 // of individual frames. 178 CString data = message.utf8(); 179 InspectorInstrumentation::didSendWebSocketFrame(document(), m_identifier, WebSocketFrame::OpCodeText, true, data.data(), data.length()); 180 } 181 m_messages.append(adoptPtr(new Message(message))); 182 sendInternal(); 183 return SendSuccess; 184 } 185 186 WebSocketChannel::SendResult NewWebSocketChannelImpl::send(PassRefPtr<BlobDataHandle> blobDataHandle) 187 { 188 WTF_LOG(Network, "NewWebSocketChannelImpl %p sendBlob(%s, %s, %llu)", this, blobDataHandle->uuid().utf8().data(), blobDataHandle->type().utf8().data(), blobDataHandle->size()); 189 if (m_identifier) { 190 // FIXME: Change the inspector API to show the entire message instead 191 // of individual frames. 192 // FIXME: We can't access the data here. 193 // Since Binary data are not displayed in Inspector, this does not 194 // affect actual behavior. 195 InspectorInstrumentation::didSendWebSocketFrame(document(), m_identifier, WebSocketFrame::OpCodeBinary, true, "", 0); 196 } 197 m_messages.append(adoptPtr(new Message(blobDataHandle))); 198 sendInternal(); 199 return SendSuccess; 200 } 201 202 WebSocketChannel::SendResult NewWebSocketChannelImpl::send(const ArrayBuffer& buffer, unsigned byteOffset, unsigned byteLength) 203 { 204 WTF_LOG(Network, "NewWebSocketChannelImpl %p sendArrayBuffer(%p, %u, %u)", this, buffer.data(), byteOffset, byteLength); 205 if (m_identifier) { 206 // FIXME: Change the inspector API to show the entire message instead 207 // of individual frames. 208 InspectorInstrumentation::didSendWebSocketFrame(document(), m_identifier, WebSocketFrame::OpCodeBinary, true, static_cast<const char*>(buffer.data()) + byteOffset, byteLength); 209 } 210 // buffer.slice copies its contents. 211 // FIXME: Reduce copy by sending the data immediately when we don't need to 212 // queue the data. 213 m_messages.append(adoptPtr(new Message(buffer.slice(byteOffset, byteOffset + byteLength)))); 214 sendInternal(); 215 return SendSuccess; 216 } 217 218 WebSocketChannel::SendResult NewWebSocketChannelImpl::send(PassOwnPtr<Vector<char> > data) 219 { 220 WTF_LOG(Network, "NewWebSocketChannelImpl %p sendVector(%p, %llu)", this, data.get(), static_cast<unsigned long long>(data->size())); 221 if (m_identifier) { 222 // FIXME: Change the inspector API to show the entire message instead 223 // of individual frames. 224 InspectorInstrumentation::didSendWebSocketFrame(document(), m_identifier, WebSocketFrame::OpCodeBinary, true, data->data(), data->size()); 225 } 226 m_messages.append(adoptPtr(new Message(data))); 227 sendInternal(); 228 return SendSuccess; 229 } 230 231 void NewWebSocketChannelImpl::close(int code, const String& reason) 232 { 233 WTF_LOG(Network, "NewWebSocketChannelImpl %p close(%d, %s)", this, code, reason.utf8().data()); 234 ASSERT(m_handle); 235 unsigned short codeToSend = static_cast<unsigned short>(code == CloseEventCodeNotSpecified ? CloseEventCodeNoStatusRcvd : code); 236 m_handle->close(codeToSend, reason); 237 } 238 239 void NewWebSocketChannelImpl::fail(const String& reason, MessageLevel level, const String& sourceURL, unsigned lineNumber) 240 { 241 WTF_LOG(Network, "NewWebSocketChannelImpl %p fail(%s)", this, reason.utf8().data()); 242 // m_handle and m_client can be null here. 243 244 if (m_identifier) 245 InspectorInstrumentation::didReceiveWebSocketFrameError(document(), m_identifier, reason); 246 const String message = "WebSocket connection to '" + m_url.elidedString() + "' failed: " + reason; 247 executionContext()->addConsoleMessage(JSMessageSource, level, message, sourceURL, lineNumber); 248 249 if (m_client) 250 m_client->didReceiveMessageError(); 251 // |reason| is only for logging and should not be provided for scripts, 252 // hence close reason must be empty. 253 handleDidClose(false, CloseEventCodeAbnormalClosure, String()); 254 // handleDidClose may delete this object. 255 } 256 257 void NewWebSocketChannelImpl::disconnect() 258 { 259 WTF_LOG(Network, "NewWebSocketChannelImpl %p disconnect()", this); 260 if (m_identifier) { 261 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "WebSocketDestroy", "data", InspectorWebSocketEvent::data(document(), m_identifier)); 262 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline.stack"), "CallStack", "stack", InspectorCallStackEvent::currentCallStack()); 263 // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing. 264 InspectorInstrumentation::didCloseWebSocket(document(), m_identifier); 265 } 266 abortAsyncOperations(); 267 m_handle.clear(); 268 m_client = 0; 269 m_identifier = 0; 270 } 271 272 void NewWebSocketChannelImpl::suspend() 273 { 274 WTF_LOG(Network, "NewWebSocketChannelImpl %p suspend()", this); 275 } 276 277 void NewWebSocketChannelImpl::resume() 278 { 279 WTF_LOG(Network, "NewWebSocketChannelImpl %p resume()", this); 280 } 281 282 NewWebSocketChannelImpl::Message::Message(const String& text) 283 : type(MessageTypeText) 284 , text(text.utf8(StrictUTF8ConversionReplacingUnpairedSurrogatesWithFFFD)) { } 285 286 NewWebSocketChannelImpl::Message::Message(PassRefPtr<BlobDataHandle> blobDataHandle) 287 : type(MessageTypeBlob) 288 , blobDataHandle(blobDataHandle) { } 289 290 NewWebSocketChannelImpl::Message::Message(PassRefPtr<ArrayBuffer> arrayBuffer) 291 : type(MessageTypeArrayBuffer) 292 , arrayBuffer(arrayBuffer) { } 293 294 NewWebSocketChannelImpl::Message::Message(PassOwnPtr<Vector<char> > vectorData) 295 : type(MessageTypeVector) 296 , vectorData(vectorData) { } 297 298 void NewWebSocketChannelImpl::sendInternal() 299 { 300 ASSERT(m_handle); 301 unsigned long consumedBufferedAmount = 0; 302 while (!m_messages.isEmpty() && m_sendingQuota > 0 && !m_blobLoader) { 303 bool final = false; 304 Message* message = m_messages.first().get(); 305 switch (message->type) { 306 case MessageTypeText: { 307 WebSocketHandle::MessageType type = 308 m_sentSizeOfTopMessage ? WebSocketHandle::MessageTypeContinuation : WebSocketHandle::MessageTypeText; 309 size_t size = std::min(static_cast<size_t>(m_sendingQuota), message->text.length() - m_sentSizeOfTopMessage); 310 final = (m_sentSizeOfTopMessage + size == message->text.length()); 311 m_handle->send(final, type, message->text.data() + m_sentSizeOfTopMessage, size); 312 m_sentSizeOfTopMessage += size; 313 m_sendingQuota -= size; 314 consumedBufferedAmount += size; 315 break; 316 } 317 case MessageTypeBlob: 318 ASSERT(!m_blobLoader); 319 m_blobLoader = adoptPtrWillBeNoop(new BlobLoader(message->blobDataHandle, this)); 320 break; 321 case MessageTypeArrayBuffer: { 322 WebSocketHandle::MessageType type = 323 m_sentSizeOfTopMessage ? WebSocketHandle::MessageTypeContinuation : WebSocketHandle::MessageTypeBinary; 324 size_t size = std::min(static_cast<size_t>(m_sendingQuota), message->arrayBuffer->byteLength() - m_sentSizeOfTopMessage); 325 final = (m_sentSizeOfTopMessage + size == message->arrayBuffer->byteLength()); 326 m_handle->send(final, type, static_cast<const char*>(message->arrayBuffer->data()) + m_sentSizeOfTopMessage, size); 327 m_sentSizeOfTopMessage += size; 328 m_sendingQuota -= size; 329 consumedBufferedAmount += size; 330 break; 331 } 332 case MessageTypeVector: { 333 WebSocketHandle::MessageType type = 334 m_sentSizeOfTopMessage ? WebSocketHandle::MessageTypeContinuation : WebSocketHandle::MessageTypeBinary; 335 size_t size = std::min(static_cast<size_t>(m_sendingQuota), message->vectorData->size() - m_sentSizeOfTopMessage); 336 final = (m_sentSizeOfTopMessage + size == message->vectorData->size()); 337 m_handle->send(final, type, message->vectorData->data() + m_sentSizeOfTopMessage, size); 338 m_sentSizeOfTopMessage += size; 339 m_sendingQuota -= size; 340 consumedBufferedAmount += size; 341 break; 342 } 343 } 344 if (final) { 345 m_messages.removeFirst(); 346 m_sentSizeOfTopMessage = 0; 347 } 348 } 349 if (m_client && consumedBufferedAmount > 0) 350 m_client->didConsumeBufferedAmount(consumedBufferedAmount); 351 } 352 353 void NewWebSocketChannelImpl::flowControlIfNecessary() 354 { 355 if (!m_handle || m_receivedDataSizeForFlowControl < receivedDataSizeForFlowControlHighWaterMark) { 356 return; 357 } 358 m_handle->flowControl(m_receivedDataSizeForFlowControl); 359 m_receivedDataSizeForFlowControl = 0; 360 } 361 362 void NewWebSocketChannelImpl::abortAsyncOperations() 363 { 364 if (m_blobLoader) { 365 m_blobLoader->cancel(); 366 m_blobLoader.clear(); 367 } 368 } 369 370 void NewWebSocketChannelImpl::handleDidClose(bool wasClean, unsigned short code, const String& reason) 371 { 372 m_handle.clear(); 373 abortAsyncOperations(); 374 if (!m_client) { 375 return; 376 } 377 WebSocketChannelClient* client = m_client; 378 m_client = 0; 379 WebSocketChannelClient::ClosingHandshakeCompletionStatus status = 380 wasClean ? WebSocketChannelClient::ClosingHandshakeComplete : WebSocketChannelClient::ClosingHandshakeIncomplete; 381 client->didClose(status, code, reason); 382 // client->didClose may delete this object. 383 } 384 385 Document* NewWebSocketChannelImpl::document() 386 { 387 ASSERT(m_identifier); 388 ExecutionContext* context = executionContext(); 389 ASSERT(context->isDocument()); 390 return toDocument(context); 391 } 392 393 void NewWebSocketChannelImpl::didConnect(WebSocketHandle* handle, bool fail, const blink::WebString& selectedProtocol, const blink::WebString& extensions) 394 { 395 WTF_LOG(Network, "NewWebSocketChannelImpl %p didConnect(%p, %d, %s, %s)", this, handle, fail, selectedProtocol.utf8().data(), extensions.utf8().data()); 396 ASSERT(m_handle); 397 ASSERT(handle == m_handle); 398 ASSERT(m_client); 399 if (fail) { 400 failAsError("Cannot connect to " + m_url.string() + "."); 401 // failAsError may delete this object. 402 return; 403 } 404 m_client->didConnect(selectedProtocol, extensions); 405 } 406 407 void NewWebSocketChannelImpl::didStartOpeningHandshake(WebSocketHandle* handle, const blink::WebSocketHandshakeRequestInfo& request) 408 { 409 WTF_LOG(Network, "NewWebSocketChannelImpl %p didStartOpeningHandshake(%p)", this, handle); 410 if (m_identifier) { 411 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "WebSocketSendHandshakeRequest", "data", InspectorWebSocketEvent::data(document(), m_identifier)); 412 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline.stack"), "CallStack", "stack", InspectorCallStackEvent::currentCallStack()); 413 // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing. 414 InspectorInstrumentation::willSendWebSocketHandshakeRequest(document(), m_identifier, &request.toCoreRequest()); 415 m_handshakeRequest = WebSocketHandshakeRequest::create(request.toCoreRequest()); 416 } 417 } 418 419 void NewWebSocketChannelImpl::didFinishOpeningHandshake(WebSocketHandle* handle, const blink::WebSocketHandshakeResponseInfo& response) 420 { 421 WTF_LOG(Network, "NewWebSocketChannelImpl %p didFinishOpeningHandshake(%p)", this, handle); 422 if (m_identifier) { 423 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "WebSocketReceiveHandshakeResponse", "data", InspectorWebSocketEvent::data(document(), m_identifier)); 424 // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing. 425 InspectorInstrumentation::didReceiveWebSocketHandshakeResponse(document(), m_identifier, m_handshakeRequest.get(), &response.toCoreResponse()); 426 } 427 m_handshakeRequest.clear(); 428 } 429 430 void NewWebSocketChannelImpl::didFail(WebSocketHandle* handle, const blink::WebString& message) 431 { 432 WTF_LOG(Network, "NewWebSocketChannelImpl %p didFail(%p, %s)", this, handle, message.utf8().data()); 433 // This function is called when the browser is required to fail the 434 // WebSocketConnection. Hence we fail this channel by calling 435 // |this->failAsError| function. 436 failAsError(message); 437 // |this| may be deleted. 438 } 439 440 void NewWebSocketChannelImpl::didReceiveData(WebSocketHandle* handle, bool fin, WebSocketHandle::MessageType type, const char* data, size_t size) 441 { 442 WTF_LOG(Network, "NewWebSocketChannelImpl %p didReceiveData(%p, %d, %d, (%p, %zu))", this, handle, fin, type, data, size); 443 ASSERT(m_handle); 444 ASSERT(handle == m_handle); 445 ASSERT(m_client); 446 // Non-final frames cannot be empty. 447 ASSERT(fin || size); 448 switch (type) { 449 case WebSocketHandle::MessageTypeText: 450 ASSERT(m_receivingMessageData.isEmpty()); 451 m_receivingMessageTypeIsText = true; 452 break; 453 case WebSocketHandle::MessageTypeBinary: 454 ASSERT(m_receivingMessageData.isEmpty()); 455 m_receivingMessageTypeIsText = false; 456 break; 457 case WebSocketHandle::MessageTypeContinuation: 458 ASSERT(!m_receivingMessageData.isEmpty()); 459 break; 460 } 461 462 m_receivingMessageData.append(data, size); 463 m_receivedDataSizeForFlowControl += size; 464 flowControlIfNecessary(); 465 if (!fin) { 466 return; 467 } 468 if (m_identifier) { 469 // FIXME: Change the inspector API to show the entire message instead 470 // of individual frames. 471 WebSocketFrame::OpCode opcode = m_receivingMessageTypeIsText ? WebSocketFrame::OpCodeText : WebSocketFrame::OpCodeBinary; 472 WebSocketFrame frame(opcode, m_receivingMessageData.data(), m_receivingMessageData.size(), WebSocketFrame::Final); 473 InspectorInstrumentation::didReceiveWebSocketFrame(document(), m_identifier, frame.opCode, frame.masked, frame.payload, frame.payloadLength); 474 } 475 if (m_receivingMessageTypeIsText) { 476 String message = m_receivingMessageData.isEmpty() ? emptyString() : String::fromUTF8(m_receivingMessageData.data(), m_receivingMessageData.size()); 477 m_receivingMessageData.clear(); 478 if (message.isNull()) { 479 failAsError("Could not decode a text frame as UTF-8."); 480 // failAsError may delete this object. 481 } else { 482 m_client->didReceiveMessage(message); 483 } 484 } else { 485 OwnPtr<Vector<char> > binaryData = adoptPtr(new Vector<char>); 486 binaryData->swap(m_receivingMessageData); 487 m_client->didReceiveBinaryData(binaryData.release()); 488 } 489 } 490 491 void NewWebSocketChannelImpl::didClose(WebSocketHandle* handle, bool wasClean, unsigned short code, const blink::WebString& reason) 492 { 493 WTF_LOG(Network, "NewWebSocketChannelImpl %p didClose(%p, %d, %u, %s)", this, handle, wasClean, code, String(reason).utf8().data()); 494 ASSERT(m_handle); 495 m_handle.clear(); 496 if (m_identifier) { 497 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "WebSocketDestroy", "data", InspectorWebSocketEvent::data(document(), m_identifier)); 498 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline.stack"), "CallStack", "stack", InspectorCallStackEvent::currentCallStack()); 499 // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing. 500 InspectorInstrumentation::didCloseWebSocket(document(), m_identifier); 501 m_identifier = 0; 502 } 503 504 handleDidClose(wasClean, code, reason); 505 // handleDidClose may delete this object. 506 } 507 508 void NewWebSocketChannelImpl::didReceiveFlowControl(WebSocketHandle* handle, int64_t quota) 509 { 510 WTF_LOG(Network, "NewWebSocketChannelImpl %p didReceiveFlowControl(%p, %ld)", this, handle, static_cast<long>(quota)); 511 ASSERT(m_handle); 512 m_sendingQuota += quota; 513 sendInternal(); 514 } 515 516 void NewWebSocketChannelImpl::didStartClosingHandshake(WebSocketHandle* handle) 517 { 518 WTF_LOG(Network, "NewWebSocketChannelImpl %p didStartClosingHandshake(%p)", this, handle); 519 if (m_client) 520 m_client->didStartClosingHandshake(); 521 } 522 523 void NewWebSocketChannelImpl::didFinishLoadingBlob(PassRefPtr<ArrayBuffer> buffer) 524 { 525 m_blobLoader.clear(); 526 ASSERT(m_handle); 527 // The loaded blob is always placed on m_messages[0]. 528 ASSERT(m_messages.size() > 0 && m_messages.first()->type == MessageTypeBlob); 529 // We replace it with the loaded blob. 530 m_messages.first() = adoptPtr(new Message(buffer)); 531 sendInternal(); 532 } 533 534 void NewWebSocketChannelImpl::didFailLoadingBlob(FileError::ErrorCode errorCode) 535 { 536 m_blobLoader.clear(); 537 if (errorCode == FileError::ABORT_ERR) { 538 // The error is caused by cancel(). 539 return; 540 } 541 // FIXME: Generate human-friendly reason message. 542 failAsError("Failed to load Blob: error code = " + String::number(errorCode)); 543 // |this| can be deleted here. 544 } 545 546 void NewWebSocketChannelImpl::trace(Visitor* visitor) 547 { 548 visitor->trace(m_blobLoader); 549 WebSocketChannel::trace(visitor); 550 } 551 552 } // namespace WebCore 553