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 568