1 /* 2 * Copyright (C) 2011, 2012 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/MainThreadWebSocketChannel.h" 33 34 #include "bindings/core/v8/ExceptionStatePlaceholder.h" 35 #include "core/dom/Document.h" 36 #include "core/dom/ExecutionContext.h" 37 #include "core/fileapi/Blob.h" 38 #include "core/fileapi/FileReaderLoader.h" 39 #include "core/frame/LocalFrame.h" 40 #include "core/inspector/ConsoleMessage.h" 41 #include "core/inspector/InspectorInstrumentation.h" 42 #include "core/inspector/InspectorTraceEvents.h" 43 #include "core/loader/FrameLoader.h" 44 #include "core/loader/FrameLoaderClient.h" 45 #include "core/loader/MixedContentChecker.h" 46 #include "core/loader/UniqueIdentifier.h" 47 #include "core/page/Page.h" 48 #include "modules/websockets/WebSocketChannelClient.h" 49 #include "platform/Logging.h" 50 #include "platform/network/SocketStreamError.h" 51 #include "platform/network/SocketStreamHandle.h" 52 #include "wtf/ArrayBuffer.h" 53 #include "wtf/FastMalloc.h" 54 #include "wtf/HashMap.h" 55 #include "wtf/OwnPtr.h" 56 #include "wtf/text/StringHash.h" 57 #include "wtf/text/WTFString.h" 58 59 namespace blink { 60 61 const double TCPMaximumSegmentLifetime = 2 * 60.0; 62 63 MainThreadWebSocketChannel::MainThreadWebSocketChannel(Document* document, WebSocketChannelClient* client, const String& sourceURL, unsigned lineNumber) 64 : m_document(document) 65 , m_client(client) 66 , m_resumeTimer(this, &MainThreadWebSocketChannel::resumeTimerFired) 67 , m_suspended(false) 68 , m_didFailOfClientAlreadyRun(false) 69 , m_hasCalledDisconnectOnHandle(false) 70 , m_receivedClosingHandshake(false) 71 , m_closingTimer(this, &MainThreadWebSocketChannel::closingTimerFired) 72 , m_state(ChannelIdle) 73 , m_shouldDiscardReceivedData(false) 74 , m_identifier(0) 75 , m_hasContinuousFrame(false) 76 , m_closeEventCode(CloseEventCodeAbnormalClosure) 77 , m_outgoingFrameQueueStatus(OutgoingFrameQueueOpen) 78 , m_numConsumedBytesInCurrentFrame(0) 79 , m_blobLoaderStatus(BlobLoaderNotStarted) 80 , m_sourceURLAtConstruction(sourceURL) 81 , m_lineNumberAtConstruction(lineNumber) 82 { 83 if (m_document->page()) 84 m_identifier = createUniqueIdentifier(); 85 } 86 87 MainThreadWebSocketChannel::~MainThreadWebSocketChannel() 88 { 89 } 90 91 bool MainThreadWebSocketChannel::connect(const KURL& url, const String& protocol) 92 { 93 WTF_LOG(Network, "MainThreadWebSocketChannel %p connect()", this); 94 ASSERT(!m_handle); 95 ASSERT(!m_suspended); 96 97 if (m_document->frame() && !m_document->frame()->loader().mixedContentChecker()->canConnectInsecureWebSocket(m_document->securityOrigin(), url)) 98 return false; 99 if (MixedContentChecker::isMixedContent(m_document->securityOrigin(), url)) { 100 String message = "Connecting to a non-secure WebSocket server from a secure origin is deprecated."; 101 m_document->addConsoleMessage(ConsoleMessage::create(JSMessageSource, WarningMessageLevel, message)); 102 } 103 104 m_handshake = new WebSocketHandshake(url, protocol, m_document); 105 m_handshake->reset(); 106 m_handshake->addExtensionProcessor(m_perMessageDeflate.createExtensionProcessor()); 107 m_handshake->addExtensionProcessor(m_deflateFramer.createExtensionProcessor()); 108 if (m_identifier) { 109 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "WebSocketCreate", "data", InspectorWebSocketCreateEvent::data(m_document, m_identifier, url, protocol)); 110 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline.stack"), "CallStack", "stack", InspectorCallStackEvent::currentCallStack()); 111 // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing. 112 InspectorInstrumentation::didCreateWebSocket(m_document, m_identifier, url, protocol); 113 } 114 ref(); 115 116 m_handle = SocketStreamHandle::create(this); 117 ASSERT(m_handle); 118 if (m_document->frame()) { 119 m_document->frame()->loader().client()->dispatchWillOpenSocketStream(m_handle.get()); 120 } 121 m_handle->connect(m_handshake->url()); 122 123 return true; 124 } 125 126 void MainThreadWebSocketChannel::send(const String& message) 127 { 128 WTF_LOG(Network, "MainThreadWebSocketChannel %p send() Sending String '%s'", this, message.utf8().data()); 129 CString utf8 = message.utf8(StrictUTF8ConversionReplacingUnpairedSurrogatesWithFFFD); 130 enqueueTextFrame(utf8); 131 processOutgoingFrameQueue(); 132 } 133 134 void MainThreadWebSocketChannel::send(const ArrayBuffer& binaryData, unsigned byteOffset, unsigned byteLength) 135 { 136 WTF_LOG(Network, "MainThreadWebSocketChannel %p send() Sending ArrayBuffer %p byteOffset=%u byteLength=%u", this, &binaryData, byteOffset, byteLength); 137 enqueueRawFrame(WebSocketFrame::OpCodeBinary, static_cast<const char*>(binaryData.data()) + byteOffset, byteLength); 138 processOutgoingFrameQueue(); 139 } 140 141 void MainThreadWebSocketChannel::send(PassRefPtr<BlobDataHandle> binaryData) 142 { 143 WTF_LOG(Network, "MainThreadWebSocketChannel %p send() Sending Blob '%s'", this, binaryData->uuid().utf8().data()); 144 enqueueBlobFrame(WebSocketFrame::OpCodeBinary, binaryData); 145 processOutgoingFrameQueue(); 146 } 147 148 void MainThreadWebSocketChannel::send(PassOwnPtr<Vector<char> > data) 149 { 150 WTF_LOG(Network, "MainThreadWebSocketChannel %p send() Sending Vector %p", this, data.get()); 151 enqueueVector(WebSocketFrame::OpCodeBinary, data); 152 processOutgoingFrameQueue(); 153 } 154 155 void MainThreadWebSocketChannel::close(int code, const String& reason) 156 { 157 WTF_LOG(Network, "MainThreadWebSocketChannel %p close() code=%d reason='%s'", this, code, reason.utf8().data()); 158 ASSERT(!m_suspended); 159 if (!m_handle) 160 return; 161 startClosingHandshake(code, reason); 162 if (!m_closingTimer.isActive()) 163 m_closingTimer.startOneShot(2 * TCPMaximumSegmentLifetime, FROM_HERE); 164 } 165 166 void MainThreadWebSocketChannel::clearDocument() 167 { 168 if (m_handshake) 169 m_handshake->clearDocument(); 170 m_document = nullptr; 171 } 172 173 void MainThreadWebSocketChannel::disconnectHandle() 174 { 175 if (!m_handle) 176 return; 177 m_hasCalledDisconnectOnHandle = true; 178 m_handle->disconnect(); 179 } 180 181 void MainThreadWebSocketChannel::callDidReceiveMessageError() 182 { 183 if (!m_client || m_didFailOfClientAlreadyRun) 184 return; 185 m_didFailOfClientAlreadyRun = true; 186 m_client->didReceiveMessageError(); 187 } 188 189 void MainThreadWebSocketChannel::fail(const String& reason, MessageLevel level, const String& sourceURL, unsigned lineNumber) 190 { 191 WTF_LOG(Network, "MainThreadWebSocketChannel %p fail() reason='%s'", this, reason.utf8().data()); 192 if (m_document) { 193 InspectorInstrumentation::didReceiveWebSocketFrameError(m_document, m_identifier, reason); 194 const String message = "WebSocket connection to '" + m_handshake->url().elidedString() + "' failed: " + reason; 195 m_document->addConsoleMessage(ConsoleMessage::create(JSMessageSource, level, message, sourceURL, lineNumber)); 196 } 197 // Hybi-10 specification explicitly states we must not continue to handle incoming data 198 // once the WebSocket connection is failed (section 7.1.7). 199 m_shouldDiscardReceivedData = true; 200 if (!m_buffer.isEmpty()) 201 skipBuffer(m_buffer.size()); // Save memory. 202 m_deflateFramer.didFail(); 203 m_perMessageDeflate.didFail(); 204 m_hasContinuousFrame = false; 205 m_continuousFrameData.clear(); 206 207 callDidReceiveMessageError(); 208 209 if (m_state != ChannelClosed) 210 disconnectHandle(); // Will call didCloseSocketStream(). 211 } 212 213 void MainThreadWebSocketChannel::disconnect() 214 { 215 WTF_LOG(Network, "MainThreadWebSocketChannel %p disconnect()", this); 216 if (m_identifier && m_document) { 217 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "WebSocketDestroy", "data", InspectorWebSocketEvent::data(m_document, m_identifier)); 218 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline.stack"), "CallStack", "stack", InspectorCallStackEvent::currentCallStack()); 219 // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing. 220 InspectorInstrumentation::didCloseWebSocket(m_document, m_identifier); 221 } 222 223 clearDocument(); 224 225 m_client = nullptr; 226 disconnectHandle(); 227 } 228 229 void MainThreadWebSocketChannel::suspend() 230 { 231 m_suspended = true; 232 } 233 234 void MainThreadWebSocketChannel::resume() 235 { 236 m_suspended = false; 237 if ((!m_buffer.isEmpty() || (m_state == ChannelClosed)) && m_client && !m_resumeTimer.isActive()) 238 m_resumeTimer.startOneShot(0, FROM_HERE); 239 } 240 241 void MainThreadWebSocketChannel::didOpenSocketStream(SocketStreamHandle* handle) 242 { 243 WTF_LOG(Network, "MainThreadWebSocketChannel %p didOpenSocketStream()", this); 244 ASSERT(handle == m_handle); 245 if (!m_document) 246 return; 247 if (m_identifier) { 248 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "WebSocketSendHandshakeRequest", "data", InspectorWebSocketEvent::data(m_document, m_identifier)); 249 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline.stack"), "CallStack", "stack", InspectorCallStackEvent::currentCallStack()); 250 // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing. 251 InspectorInstrumentation::willSendWebSocketHandshakeRequest(m_document, m_identifier, m_handshake->clientHandshakeRequest().get()); 252 } 253 CString handshakeMessage = m_handshake->clientHandshakeMessage(); 254 if (!handle->send(handshakeMessage.data(), handshakeMessage.length())) 255 failAsError("Failed to send WebSocket handshake."); 256 } 257 258 void MainThreadWebSocketChannel::didCloseSocketStream(SocketStreamHandle* handle) 259 { 260 WTF_LOG(Network, "MainThreadWebSocketChannel %p didCloseSocketStream()", this); 261 if (m_identifier && m_document) { 262 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "WebSocketDestroy", "data", InspectorWebSocketEvent::data(m_document, m_identifier)); 263 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline.stack"), "CallStack", "stack", InspectorCallStackEvent::currentCallStack()); 264 // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing. 265 InspectorInstrumentation::didCloseWebSocket(m_document, m_identifier); 266 } 267 ASSERT_UNUSED(handle, handle == m_handle || !m_handle); 268 269 // Show error message on JS console if this is unexpected connection close 270 // during opening handshake. 271 if (!m_hasCalledDisconnectOnHandle && m_handshake->mode() == WebSocketHandshake::Incomplete && m_document) { 272 const String message = "WebSocket connection to '" + m_handshake->url().elidedString() + "' failed: Connection closed before receiving a handshake response"; 273 m_document->addConsoleMessage(ConsoleMessage::create(JSMessageSource, ErrorMessageLevel, message, m_sourceURLAtConstruction, m_lineNumberAtConstruction)); 274 } 275 276 m_state = ChannelClosed; 277 if (m_closingTimer.isActive()) 278 m_closingTimer.stop(); 279 if (m_outgoingFrameQueueStatus != OutgoingFrameQueueClosed) 280 abortOutgoingFrameQueue(); 281 if (m_handle) { 282 WebSocketChannelClient* client = m_client; 283 m_client = nullptr; 284 clearDocument(); 285 m_handle = nullptr; 286 if (client) 287 client->didClose(m_receivedClosingHandshake ? WebSocketChannelClient::ClosingHandshakeComplete : WebSocketChannelClient::ClosingHandshakeIncomplete, m_closeEventCode, m_closeEventReason); 288 } 289 deref(); 290 } 291 292 void MainThreadWebSocketChannel::didReceiveSocketStreamData(SocketStreamHandle* handle, const char* data, int len) 293 { 294 WTF_LOG(Network, "MainThreadWebSocketChannel %p didReceiveSocketStreamData() Received %d bytes", this, len); 295 ASSERT(handle == m_handle); 296 if (!m_document) 297 return; 298 if (len <= 0) { 299 disconnectHandle(); 300 return; 301 } 302 if (!m_client) { 303 m_shouldDiscardReceivedData = true; 304 disconnectHandle(); 305 return; 306 } 307 if (m_shouldDiscardReceivedData) 308 return; 309 if (!appendToBuffer(data, len)) { 310 m_shouldDiscardReceivedData = true; 311 failAsError("Ran out of memory while receiving WebSocket data."); 312 return; 313 } 314 processBuffer(); 315 } 316 317 void MainThreadWebSocketChannel::didConsumeBufferedAmount(SocketStreamHandle*, size_t consumed) 318 { 319 if (m_framingOverheadQueue.isEmpty()) { 320 // Ignore the handshake consumption. 321 return; 322 } 323 if (!m_client || m_state == ChannelClosed) 324 return; 325 size_t remain = consumed; 326 while (remain > 0) { 327 ASSERT(!m_framingOverheadQueue.isEmpty()); 328 const FramingOverhead& frame = m_framingOverheadQueue.first(); 329 330 ASSERT(m_numConsumedBytesInCurrentFrame <= frame.frameDataSize()); 331 size_t consumedInThisFrame = std::min(remain, frame.frameDataSize() - m_numConsumedBytesInCurrentFrame); 332 remain -= consumedInThisFrame; 333 m_numConsumedBytesInCurrentFrame += consumedInThisFrame; 334 335 if (m_numConsumedBytesInCurrentFrame == frame.frameDataSize()) { 336 if (m_client && WebSocketFrame::isNonControlOpCode(frame.opcode())) { 337 // FIXME: As |consumed| is the number of possibly compressed 338 // bytes, we can't determine the number of consumed original 339 // bytes in the middle of a frame. 340 m_client->didConsumeBufferedAmount(frame.originalPayloadLength()); 341 } 342 m_framingOverheadQueue.takeFirst(); 343 m_numConsumedBytesInCurrentFrame = 0; 344 } 345 } 346 } 347 348 void MainThreadWebSocketChannel::didFailSocketStream(SocketStreamHandle* handle, const SocketStreamError& error) 349 { 350 WTF_LOG(Network, "MainThreadWebSocketChannel %p didFailSocketStream()", this); 351 ASSERT_UNUSED(handle, handle == m_handle || !m_handle); 352 m_shouldDiscardReceivedData = true; 353 String message; 354 if (error.isNull()) 355 message = "WebSocket network error"; 356 else if (error.localizedDescription().isNull()) 357 message = "WebSocket network error: error code " + String::number(error.errorCode()); 358 else 359 message = "WebSocket network error: error code " + String::number(error.errorCode()) + ", " + error.localizedDescription(); 360 String failingURL = error.failingURL(); 361 ASSERT(failingURL.isNull() || m_handshake->url().string() == failingURL); 362 if (failingURL.isNull()) 363 failingURL = m_handshake->url().string(); 364 WTF_LOG(Network, "Error Message: '%s', FailURL: '%s'", message.utf8().data(), failingURL.utf8().data()); 365 366 if (m_state != ChannelClosing && m_state != ChannelClosed) 367 callDidReceiveMessageError(); 368 369 if (m_state != ChannelClosed) 370 disconnectHandle(); 371 } 372 373 void MainThreadWebSocketChannel::didStartLoading() 374 { 375 WTF_LOG(Network, "MainThreadWebSocketChannel %p didStartLoading()", this); 376 ASSERT(m_blobLoader); 377 ASSERT(m_blobLoaderStatus == BlobLoaderStarted); 378 } 379 380 void MainThreadWebSocketChannel::didReceiveData() 381 { 382 WTF_LOG(Network, "MainThreadWebSocketChannel %p didReceiveData()", this); 383 ASSERT(m_blobLoader); 384 ASSERT(m_blobLoaderStatus == BlobLoaderStarted); 385 } 386 387 void MainThreadWebSocketChannel::didFinishLoading() 388 { 389 WTF_LOG(Network, "MainThreadWebSocketChannel %p didFinishLoading()", this); 390 ASSERT(m_blobLoader); 391 ASSERT(m_blobLoaderStatus == BlobLoaderStarted); 392 m_blobLoaderStatus = BlobLoaderFinished; 393 processOutgoingFrameQueue(); 394 deref(); 395 } 396 397 void MainThreadWebSocketChannel::didFail(FileError::ErrorCode errorCode) 398 { 399 WTF_LOG(Network, "MainThreadWebSocketChannel %p didFail() errorCode=%d", this, errorCode); 400 ASSERT(m_blobLoader); 401 ASSERT(m_blobLoaderStatus == BlobLoaderStarted); 402 m_blobLoader.clear(); 403 m_blobLoaderStatus = BlobLoaderFailed; 404 failAsError("Failed to load Blob: error code = " + String::number(errorCode)); // FIXME: Generate human-friendly reason message. 405 deref(); 406 } 407 408 bool MainThreadWebSocketChannel::appendToBuffer(const char* data, size_t len) 409 { 410 size_t newBufferSize = m_buffer.size() + len; 411 if (newBufferSize < m_buffer.size()) { 412 WTF_LOG(Network, "MainThreadWebSocketChannel %p appendToBuffer() Buffer overflow (%lu bytes already in receive buffer and appending %lu bytes)", this, static_cast<unsigned long>(m_buffer.size()), static_cast<unsigned long>(len)); 413 return false; 414 } 415 m_buffer.append(data, len); 416 return true; 417 } 418 419 void MainThreadWebSocketChannel::skipBuffer(size_t len) 420 { 421 ASSERT_WITH_SECURITY_IMPLICATION(len <= m_buffer.size()); 422 memmove(m_buffer.data(), m_buffer.data() + len, m_buffer.size() - len); 423 m_buffer.resize(m_buffer.size() - len); 424 } 425 426 void MainThreadWebSocketChannel::processBuffer() 427 { 428 while (!m_suspended && m_client && !m_buffer.isEmpty()) { 429 if (!processOneItemFromBuffer()) 430 break; 431 } 432 } 433 434 bool MainThreadWebSocketChannel::processOneItemFromBuffer() 435 { 436 ASSERT(!m_suspended); 437 ASSERT(m_client); 438 ASSERT(!m_buffer.isEmpty()); 439 WTF_LOG(Network, "MainThreadWebSocketChannel %p processBuffer() Receive buffer has %lu bytes", this, static_cast<unsigned long>(m_buffer.size())); 440 441 if (m_shouldDiscardReceivedData) 442 return false; 443 444 if (m_receivedClosingHandshake) { 445 skipBuffer(m_buffer.size()); 446 return false; 447 } 448 449 if (m_handshake->mode() == WebSocketHandshake::Incomplete) { 450 int headerLength = m_handshake->readServerHandshake(m_buffer.data(), m_buffer.size()); 451 if (headerLength <= 0) 452 return false; 453 if (m_handshake->mode() == WebSocketHandshake::Connected) { 454 if (m_identifier) { 455 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "WebSocketReceiveHandshakeResponse", "data", InspectorWebSocketEvent::data(m_document, m_identifier)); 456 // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing. 457 InspectorInstrumentation::didReceiveWebSocketHandshakeResponse(m_document, m_identifier, 0, &m_handshake->serverHandshakeResponse()); 458 } 459 460 if (m_deflateFramer.enabled() && m_document) { 461 const String message = "WebSocket extension \"x-webkit-deflate-frame\" is deprecated"; 462 m_document->addConsoleMessage(ConsoleMessage::create(JSMessageSource, WarningMessageLevel, message, m_sourceURLAtConstruction, m_lineNumberAtConstruction)); 463 } 464 465 WTF_LOG(Network, "MainThreadWebSocketChannel %p Connected", this); 466 skipBuffer(headerLength); 467 String subprotocol = m_handshake->serverWebSocketProtocol(); 468 String extensions = m_handshake->acceptedExtensions(); 469 m_client->didConnect(subprotocol.isNull() ? "" : subprotocol, extensions.isNull() ? "" : extensions); 470 WTF_LOG(Network, "MainThreadWebSocketChannel %p %lu bytes remaining in m_buffer", this, static_cast<unsigned long>(m_buffer.size())); 471 return !m_buffer.isEmpty(); 472 } 473 ASSERT(m_handshake->mode() == WebSocketHandshake::Failed); 474 WTF_LOG(Network, "MainThreadWebSocketChannel %p Connection failed", this); 475 skipBuffer(headerLength); 476 m_shouldDiscardReceivedData = true; 477 failAsError(m_handshake->failureReason()); 478 return false; 479 } 480 if (m_handshake->mode() != WebSocketHandshake::Connected) 481 return false; 482 483 return processFrame(); 484 } 485 486 void MainThreadWebSocketChannel::resumeTimerFired(Timer<MainThreadWebSocketChannel>* timer) 487 { 488 ASSERT_UNUSED(timer, timer == &m_resumeTimer); 489 490 processBuffer(); 491 if (!m_suspended && m_client && (m_state == ChannelClosed) && m_handle) 492 didCloseSocketStream(m_handle.get()); 493 } 494 495 void MainThreadWebSocketChannel::startClosingHandshake(int code, const String& reason) 496 { 497 WTF_LOG(Network, "MainThreadWebSocketChannel %p startClosingHandshake() code=%d m_state=%d m_receivedClosingHandshake=%d", this, code, m_state, m_receivedClosingHandshake); 498 if (m_state == ChannelClosing || m_state == ChannelClosed) 499 return; 500 ASSERT(m_handle); 501 502 Vector<char> buf; 503 if (!m_receivedClosingHandshake && code != CloseEventCodeNotSpecified) { 504 unsigned char highByte = code >> 8; 505 unsigned char lowByte = code; 506 buf.append(static_cast<char>(highByte)); 507 buf.append(static_cast<char>(lowByte)); 508 buf.append(reason.utf8().data(), reason.utf8().length()); 509 } 510 enqueueRawFrame(WebSocketFrame::OpCodeClose, buf.data(), buf.size()); 511 processOutgoingFrameQueue(); 512 513 m_state = ChannelClosing; 514 if (m_client) 515 m_client->didStartClosingHandshake(); 516 } 517 518 void MainThreadWebSocketChannel::closingTimerFired(Timer<MainThreadWebSocketChannel>* timer) 519 { 520 WTF_LOG(Network, "MainThreadWebSocketChannel %p closingTimerFired()", this); 521 ASSERT_UNUSED(timer, &m_closingTimer == timer); 522 disconnectHandle(); 523 } 524 525 526 bool MainThreadWebSocketChannel::processFrame() 527 { 528 ASSERT(!m_buffer.isEmpty()); 529 530 WebSocketFrame frame; 531 const char* frameEnd; 532 String errorString; 533 WebSocketFrame::ParseFrameResult result = WebSocketFrame::parseFrame(m_buffer.data(), m_buffer.size(), frame, frameEnd, errorString); 534 if (result == WebSocketFrame::FrameIncomplete) 535 return false; 536 if (result == WebSocketFrame::FrameError) { 537 failAsError(errorString); 538 return false; 539 } 540 541 ASSERT(m_buffer.data() < frameEnd); 542 ASSERT(frameEnd <= m_buffer.data() + m_buffer.size()); 543 544 OwnPtr<InflateResultHolder> inflateResult = m_deflateFramer.inflate(frame); 545 if (!inflateResult->succeeded()) { 546 failAsError(inflateResult->failureReason()); 547 return false; 548 } 549 if (!m_perMessageDeflate.inflate(frame)) { 550 failAsError(m_perMessageDeflate.failureReason()); 551 return false; 552 } 553 554 // Validate the frame data. 555 if (WebSocketFrame::isReservedOpCode(frame.opCode)) { 556 failAsError("Unrecognized frame opcode: " + String::number(frame.opCode)); 557 return false; 558 } 559 560 if (frame.compress || frame.reserved2 || frame.reserved3) { 561 failAsError("One or more reserved bits are on: reserved1 = " + String::number(frame.compress) + ", reserved2 = " + String::number(frame.reserved2) + ", reserved3 = " + String::number(frame.reserved3)); 562 return false; 563 } 564 565 if (frame.masked) { 566 failAsError("A server must not mask any frames that it sends to the client."); 567 return false; 568 } 569 570 // All control frames must not be fragmented. 571 if (WebSocketFrame::isControlOpCode(frame.opCode) && !frame.final) { 572 failAsError("Received fragmented control frame: opcode = " + String::number(frame.opCode)); 573 return false; 574 } 575 576 // All control frames must have a payload of 125 bytes or less, which means the frame must not contain 577 // the "extended payload length" field. 578 if (WebSocketFrame::isControlOpCode(frame.opCode) && WebSocketFrame::needsExtendedLengthField(frame.payloadLength)) { 579 failAsError("Received control frame having too long payload: " + String::number(frame.payloadLength) + " bytes"); 580 return false; 581 } 582 583 // A new data frame is received before the previous continuous frame finishes. 584 // Note that control frames are allowed to come in the middle of continuous frames. 585 if (m_hasContinuousFrame && frame.opCode != WebSocketFrame::OpCodeContinuation && !WebSocketFrame::isControlOpCode(frame.opCode)) { 586 failAsError("Received start of new message but previous message is unfinished."); 587 return false; 588 } 589 590 InspectorInstrumentation::didReceiveWebSocketFrame(m_document, m_identifier, frame.opCode, frame.masked, frame.payload, frame.payloadLength); 591 592 switch (frame.opCode) { 593 case WebSocketFrame::OpCodeContinuation: 594 // An unexpected continuation frame is received without any leading frame. 595 if (!m_hasContinuousFrame) { 596 failAsError("Received unexpected continuation frame."); 597 return false; 598 } 599 m_continuousFrameData.append(frame.payload, frame.payloadLength); 600 skipBuffer(frameEnd - m_buffer.data()); 601 if (frame.final) { 602 // onmessage handler may eventually call the other methods of this channel, 603 // so we should pretend that we have finished to read this frame and 604 // make sure that the member variables are in a consistent state before 605 // the handler is invoked. 606 // Vector<char>::swap() is used here to clear m_continuousFrameData. 607 OwnPtr<Vector<char> > continuousFrameData = adoptPtr(new Vector<char>); 608 m_continuousFrameData.swap(*continuousFrameData); 609 m_hasContinuousFrame = false; 610 if (m_continuousFrameOpCode == WebSocketFrame::OpCodeText) { 611 String message; 612 if (continuousFrameData->size()) 613 message = String::fromUTF8(continuousFrameData->data(), continuousFrameData->size()); 614 else 615 message = ""; 616 if (message.isNull()) 617 failAsError("Could not decode a text frame as UTF-8."); 618 else 619 m_client->didReceiveMessage(message); 620 } else if (m_continuousFrameOpCode == WebSocketFrame::OpCodeBinary) { 621 m_client->didReceiveBinaryData(continuousFrameData.release()); 622 } 623 } 624 break; 625 626 case WebSocketFrame::OpCodeText: 627 if (frame.final) { 628 String message; 629 if (frame.payloadLength) 630 message = String::fromUTF8(frame.payload, frame.payloadLength); 631 else 632 message = ""; 633 skipBuffer(frameEnd - m_buffer.data()); 634 if (message.isNull()) 635 failAsError("Could not decode a text frame as UTF-8."); 636 else 637 m_client->didReceiveMessage(message); 638 } else { 639 m_hasContinuousFrame = true; 640 m_continuousFrameOpCode = WebSocketFrame::OpCodeText; 641 ASSERT(m_continuousFrameData.isEmpty()); 642 m_continuousFrameData.append(frame.payload, frame.payloadLength); 643 skipBuffer(frameEnd - m_buffer.data()); 644 } 645 break; 646 647 case WebSocketFrame::OpCodeBinary: 648 if (frame.final) { 649 OwnPtr<Vector<char> > binaryData = adoptPtr(new Vector<char>(frame.payloadLength)); 650 memcpy(binaryData->data(), frame.payload, frame.payloadLength); 651 skipBuffer(frameEnd - m_buffer.data()); 652 m_client->didReceiveBinaryData(binaryData.release()); 653 } else { 654 m_hasContinuousFrame = true; 655 m_continuousFrameOpCode = WebSocketFrame::OpCodeBinary; 656 ASSERT(m_continuousFrameData.isEmpty()); 657 m_continuousFrameData.append(frame.payload, frame.payloadLength); 658 skipBuffer(frameEnd - m_buffer.data()); 659 } 660 break; 661 662 case WebSocketFrame::OpCodeClose: 663 if (!frame.payloadLength) { 664 m_closeEventCode = CloseEventCodeNoStatusRcvd; 665 } else if (frame.payloadLength == 1) { 666 m_closeEventCode = CloseEventCodeAbnormalClosure; 667 failAsError("Received a broken close frame containing an invalid size body."); 668 return false; 669 } else { 670 unsigned char highByte = static_cast<unsigned char>(frame.payload[0]); 671 unsigned char lowByte = static_cast<unsigned char>(frame.payload[1]); 672 m_closeEventCode = highByte << 8 | lowByte; 673 if (m_closeEventCode == CloseEventCodeNoStatusRcvd || m_closeEventCode == CloseEventCodeAbnormalClosure || m_closeEventCode == CloseEventCodeTLSHandshake) { 674 m_closeEventCode = CloseEventCodeAbnormalClosure; 675 failAsError("Received a broken close frame containing a reserved status code."); 676 return false; 677 } 678 } 679 if (frame.payloadLength >= 3) 680 m_closeEventReason = String::fromUTF8(&frame.payload[2], frame.payloadLength - 2); 681 else 682 m_closeEventReason = ""; 683 skipBuffer(frameEnd - m_buffer.data()); 684 m_receivedClosingHandshake = true; 685 startClosingHandshake(m_closeEventCode, m_closeEventReason); 686 m_outgoingFrameQueueStatus = OutgoingFrameQueueClosing; 687 processOutgoingFrameQueue(); 688 break; 689 690 case WebSocketFrame::OpCodePing: 691 enqueueRawFrame(WebSocketFrame::OpCodePong, frame.payload, frame.payloadLength); 692 skipBuffer(frameEnd - m_buffer.data()); 693 processOutgoingFrameQueue(); 694 break; 695 696 case WebSocketFrame::OpCodePong: 697 // A server may send a pong in response to our ping, or an unsolicited pong which is not associated with 698 // any specific ping. Either way, there's nothing to do on receipt of pong. 699 skipBuffer(frameEnd - m_buffer.data()); 700 break; 701 702 default: 703 ASSERT_NOT_REACHED(); 704 skipBuffer(frameEnd - m_buffer.data()); 705 break; 706 } 707 708 m_perMessageDeflate.resetInflateBuffer(); 709 return !m_buffer.isEmpty(); 710 } 711 712 void MainThreadWebSocketChannel::enqueueTextFrame(const CString& string) 713 { 714 ASSERT(m_outgoingFrameQueueStatus == OutgoingFrameQueueOpen); 715 716 OwnPtr<QueuedFrame> frame = adoptPtr(new QueuedFrame); 717 frame->opCode = WebSocketFrame::OpCodeText; 718 frame->frameType = QueuedFrameTypeString; 719 frame->stringData = string; 720 m_outgoingFrameQueue.append(frame.release()); 721 } 722 723 void MainThreadWebSocketChannel::enqueueRawFrame(WebSocketFrame::OpCode opCode, const char* data, size_t dataLength) 724 { 725 ASSERT(m_outgoingFrameQueueStatus == OutgoingFrameQueueOpen); 726 727 OwnPtr<QueuedFrame> frame = adoptPtr(new QueuedFrame); 728 frame->opCode = opCode; 729 frame->frameType = QueuedFrameTypeVector; 730 frame->vectorData.resize(dataLength); 731 if (dataLength) 732 memcpy(frame->vectorData.data(), data, dataLength); 733 m_outgoingFrameQueue.append(frame.release()); 734 } 735 736 void MainThreadWebSocketChannel::enqueueVector(WebSocketFrame::OpCode opCode, PassOwnPtr<Vector<char> > data) 737 { 738 ASSERT(m_outgoingFrameQueueStatus == OutgoingFrameQueueOpen); 739 740 OwnPtr<QueuedFrame> frame = adoptPtr(new QueuedFrame); 741 frame->opCode = opCode; 742 frame->frameType = QueuedFrameTypeVector; 743 frame->vectorData.swap(*data); 744 m_outgoingFrameQueue.append(frame.release()); 745 } 746 747 void MainThreadWebSocketChannel::enqueueBlobFrame(WebSocketFrame::OpCode opCode, PassRefPtr<BlobDataHandle> blobData) 748 { 749 ASSERT(m_outgoingFrameQueueStatus == OutgoingFrameQueueOpen); 750 751 OwnPtr<QueuedFrame> frame = adoptPtr(new QueuedFrame); 752 frame->opCode = opCode; 753 frame->frameType = QueuedFrameTypeBlob; 754 frame->blobData = blobData; 755 m_outgoingFrameQueue.append(frame.release()); 756 } 757 758 void MainThreadWebSocketChannel::processOutgoingFrameQueue() 759 { 760 if (m_outgoingFrameQueueStatus == OutgoingFrameQueueClosed) 761 return; 762 763 while (!m_outgoingFrameQueue.isEmpty()) { 764 OwnPtr<QueuedFrame> frame = m_outgoingFrameQueue.takeFirst(); 765 switch (frame->frameType) { 766 case QueuedFrameTypeString: { 767 if (!sendFrame(frame->opCode, frame->stringData.data(), frame->stringData.length())) 768 failAsError("Failed to send WebSocket frame."); 769 break; 770 } 771 772 case QueuedFrameTypeVector: 773 if (!sendFrame(frame->opCode, frame->vectorData.data(), frame->vectorData.size())) 774 failAsError("Failed to send WebSocket frame."); 775 break; 776 777 case QueuedFrameTypeBlob: { 778 switch (m_blobLoaderStatus) { 779 case BlobLoaderNotStarted: 780 ref(); // Will be derefed after didFinishLoading() or didFail(). 781 ASSERT(!m_blobLoader); 782 m_blobLoader = adoptPtr(new FileReaderLoader(FileReaderLoader::ReadAsArrayBuffer, this)); 783 m_blobLoaderStatus = BlobLoaderStarted; 784 m_blobLoader->start(m_document, frame->blobData); 785 m_outgoingFrameQueue.prepend(frame.release()); 786 return; 787 788 case BlobLoaderStarted: 789 case BlobLoaderFailed: 790 m_outgoingFrameQueue.prepend(frame.release()); 791 return; 792 793 case BlobLoaderFinished: { 794 RefPtr<ArrayBuffer> result = m_blobLoader->arrayBufferResult(); 795 m_blobLoader.clear(); 796 m_blobLoaderStatus = BlobLoaderNotStarted; 797 if (!sendFrame(frame->opCode, static_cast<const char*>(result->data()), result->byteLength())) 798 failAsError("Failed to send WebSocket frame."); 799 break; 800 } 801 } 802 break; 803 } 804 805 default: 806 ASSERT_NOT_REACHED(); 807 break; 808 } 809 } 810 811 ASSERT(m_outgoingFrameQueue.isEmpty()); 812 if (m_outgoingFrameQueueStatus == OutgoingFrameQueueClosing) { 813 m_outgoingFrameQueueStatus = OutgoingFrameQueueClosed; 814 m_handle->close(); 815 } 816 } 817 818 void MainThreadWebSocketChannel::abortOutgoingFrameQueue() 819 { 820 m_outgoingFrameQueue.clear(); 821 m_outgoingFrameQueueStatus = OutgoingFrameQueueClosed; 822 if (m_blobLoaderStatus == BlobLoaderStarted) { 823 m_blobLoader->cancel(); 824 didFail(FileError::ABORT_ERR); 825 } 826 } 827 828 bool MainThreadWebSocketChannel::sendFrame(WebSocketFrame::OpCode opCode, const char* data, size_t dataLength) 829 { 830 ASSERT(m_handle); 831 ASSERT(!m_suspended); 832 833 WebSocketFrame frame(opCode, data, dataLength, WebSocketFrame::Final | WebSocketFrame::Masked); 834 InspectorInstrumentation::didSendWebSocketFrame(m_document, m_identifier, frame.opCode, frame.masked, frame.payload, frame.payloadLength); 835 836 OwnPtr<DeflateResultHolder> deflateResult = m_deflateFramer.deflate(frame); 837 if (!deflateResult->succeeded()) { 838 failAsError(deflateResult->failureReason()); 839 return false; 840 } 841 842 if (!m_perMessageDeflate.deflate(frame)) { 843 failAsError(m_perMessageDeflate.failureReason()); 844 return false; 845 } 846 847 Vector<char> frameData; 848 frame.makeFrameData(frameData); 849 m_framingOverheadQueue.append(FramingOverhead(opCode, frameData.size(), dataLength)); 850 851 m_perMessageDeflate.resetDeflateBuffer(); 852 return m_handle->send(frameData.data(), frameData.size()); 853 } 854 855 void MainThreadWebSocketChannel::trace(Visitor* visitor) 856 { 857 visitor->trace(m_document); 858 visitor->trace(m_client); 859 visitor->trace(m_handshake); 860 visitor->trace(m_handle); 861 WebSocketChannel::trace(visitor); 862 SocketStreamHandleClient::trace(visitor); 863 } 864 865 } // namespace blink 866