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