| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2011, 2012 Google Inc. All rights reserved. | 2 * Copyright (C) 2011, 2012 Google Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
| 6 * met: | 6 * met: |
| 7 * | 7 * |
| 8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 69 | 69 |
| 70 namespace WebCore { | 70 namespace WebCore { |
| 71 | 71 |
| 72 const double TCPMaximumSegmentLifetime = 2 * 60.0; | 72 const double TCPMaximumSegmentLifetime = 2 * 60.0; |
| 73 | 73 |
| 74 MainThreadWebSocketChannel::MainThreadWebSocketChannel(Document* document, WebSo
cketChannelClient* client, const String& sourceURL, unsigned lineNumber) | 74 MainThreadWebSocketChannel::MainThreadWebSocketChannel(Document* document, WebSo
cketChannelClient* client, const String& sourceURL, unsigned lineNumber) |
| 75 : m_document(document) | 75 : m_document(document) |
| 76 , m_client(client) | 76 , m_client(client) |
| 77 , m_resumeTimer(this, &MainThreadWebSocketChannel::resumeTimerFired) | 77 , m_resumeTimer(this, &MainThreadWebSocketChannel::resumeTimerFired) |
| 78 , m_suspended(false) | 78 , m_suspended(false) |
| 79 , m_closing(false) | |
| 80 , m_didFailOfClientAlreadyRun(false) | 79 , m_didFailOfClientAlreadyRun(false) |
| 81 , m_receivedClosingHandshake(false) | 80 , m_receivedClosingHandshake(false) |
| 82 , m_closingTimer(this, &MainThreadWebSocketChannel::closingTimerFired) | 81 , m_closingTimer(this, &MainThreadWebSocketChannel::closingTimerFired) |
| 83 , m_closed(false) | 82 , m_state(ChannelIdle) |
| 84 , m_shouldDiscardReceivedData(false) | 83 , m_shouldDiscardReceivedData(false) |
| 85 , m_unhandledBufferedAmount(0) | 84 , m_unhandledBufferedAmount(0) |
| 86 , m_identifier(0) | 85 , m_identifier(0) |
| 87 , m_hasContinuousFrame(false) | 86 , m_hasContinuousFrame(false) |
| 88 , m_closeEventCode(CloseEventCodeAbnormalClosure) | 87 , m_closeEventCode(CloseEventCodeAbnormalClosure) |
| 89 , m_outgoingFrameQueueStatus(OutgoingFrameQueueOpen) | 88 , m_outgoingFrameQueueStatus(OutgoingFrameQueueOpen) |
| 90 , m_blobLoaderStatus(BlobLoaderNotStarted) | 89 , m_blobLoaderStatus(BlobLoaderNotStarted) |
| 91 , m_sourceURLAtConnection(sourceURL) | 90 , m_sourceURLAtConnection(sourceURL) |
| 92 , m_lineNumberAtConnection(lineNumber) | 91 , m_lineNumberAtConnection(lineNumber) |
| 93 { | 92 { |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 190 return m_handle->bufferedAmount(); | 189 return m_handle->bufferedAmount(); |
| 191 } | 190 } |
| 192 | 191 |
| 193 void MainThreadWebSocketChannel::close(int code, const String& reason) | 192 void MainThreadWebSocketChannel::close(int code, const String& reason) |
| 194 { | 193 { |
| 195 LOG(Network, "MainThreadWebSocketChannel %p close() code=%d reason='%s'", th
is, code, reason.utf8().data()); | 194 LOG(Network, "MainThreadWebSocketChannel %p close() code=%d reason='%s'", th
is, code, reason.utf8().data()); |
| 196 ASSERT(!m_suspended); | 195 ASSERT(!m_suspended); |
| 197 if (!m_handle) | 196 if (!m_handle) |
| 198 return; | 197 return; |
| 199 startClosingHandshake(code, reason); | 198 startClosingHandshake(code, reason); |
| 200 if (m_closing && !m_closingTimer.isActive()) | 199 if ((m_state == ChannelClosing || m_state == ChannelClosed) && !m_closingTim
er.isActive()) |
| 201 m_closingTimer.startOneShot(2 * TCPMaximumSegmentLifetime); | 200 m_closingTimer.startOneShot(2 * TCPMaximumSegmentLifetime); |
| 202 } | 201 } |
| 203 | 202 |
| 204 void MainThreadWebSocketChannel::fail(const String& reason, MessageLevel level,
const String& sourceURL, unsigned lineNumber) | 203 void MainThreadWebSocketChannel::fail(const String& reason, MessageLevel level,
const String& sourceURL, unsigned lineNumber) |
| 205 { | 204 { |
| 206 LOG(Network, "MainThreadWebSocketChannel %p fail() reason='%s'", this, reaso
n.utf8().data()); | 205 LOG(Network, "MainThreadWebSocketChannel %p fail() reason='%s'", this, reaso
n.utf8().data()); |
| 207 ASSERT(!m_suspended); | 206 ASSERT(!m_suspended); |
| 208 if (m_document) { | 207 if (m_document) { |
| 209 InspectorInstrumentation::didReceiveWebSocketFrameError(m_document, m_id
entifier, reason); | 208 InspectorInstrumentation::didReceiveWebSocketFrameError(m_document, m_id
entifier, reason); |
| 210 const String message = "WebSocket connection to '" + m_handshake->url().
elidedString() + "' failed: " + reason; | 209 const String message = "WebSocket connection to '" + m_handshake->url().
elidedString() + "' failed: " + reason; |
| 211 static_cast<ScriptExecutionContext*>(m_document)->addConsoleMessage(JSMe
ssageSource, level, message, sourceURL, lineNumber); | 210 static_cast<ScriptExecutionContext*>(m_document)->addConsoleMessage(JSMe
ssageSource, level, message, sourceURL, lineNumber); |
| 212 } | 211 } |
| 213 // Hybi-10 specification explicitly states we must not continue to handle in
coming data | 212 // Hybi-10 specification explicitly states we must not continue to handle in
coming data |
| 214 // once the WebSocket connection is failed (section 7.1.7). | 213 // once the WebSocket connection is failed (section 7.1.7). |
| 215 RefPtr<MainThreadWebSocketChannel> protect(this); // The client can close th
e channel, potentially removing the last reference. | 214 RefPtr<MainThreadWebSocketChannel> protect(this); // The client can close th
e channel, potentially removing the last reference. |
| 216 m_shouldDiscardReceivedData = true; | 215 m_shouldDiscardReceivedData = true; |
| 217 if (!m_buffer.isEmpty()) | 216 if (!m_buffer.isEmpty()) |
| 218 skipBuffer(m_buffer.size()); // Save memory. | 217 skipBuffer(m_buffer.size()); // Save memory. |
| 219 m_deflateFramer.didFail(); | 218 m_deflateFramer.didFail(); |
| 220 m_perMessageDeflate.didFail(); | 219 m_perMessageDeflate.didFail(); |
| 221 m_hasContinuousFrame = false; | 220 m_hasContinuousFrame = false; |
| 222 m_continuousFrameData.clear(); | 221 m_continuousFrameData.clear(); |
| 223 if (!m_didFailOfClientAlreadyRun) { | 222 if (!m_didFailOfClientAlreadyRun) { |
| 224 m_didFailOfClientAlreadyRun = true; | 223 m_didFailOfClientAlreadyRun = true; |
| 225 if (m_client) | 224 if (m_client) |
| 226 m_client->didReceiveMessageError(); | 225 m_client->didReceiveMessageError(); |
| 227 } | 226 } |
| 228 if (m_handle && !m_closed) | 227 if (m_handle && (m_state != ChannelClosed)) |
| 229 m_handle->disconnect(); // Will call didCloseSocketStream(). | 228 m_handle->disconnect(); // Will call didCloseSocketStream(). |
| 230 } | 229 } |
| 231 | 230 |
| 232 void MainThreadWebSocketChannel::disconnect() | 231 void MainThreadWebSocketChannel::disconnect() |
| 233 { | 232 { |
| 234 LOG(Network, "MainThreadWebSocketChannel %p disconnect()", this); | 233 LOG(Network, "MainThreadWebSocketChannel %p disconnect()", this); |
| 235 if (m_identifier && m_document) | 234 if (m_identifier && m_document) |
| 236 InspectorInstrumentation::didCloseWebSocket(m_document, m_identifier); | 235 InspectorInstrumentation::didCloseWebSocket(m_document, m_identifier); |
| 237 if (m_handshake) | 236 if (m_handshake) |
| 238 m_handshake->clearScriptExecutionContext(); | 237 m_handshake->clearScriptExecutionContext(); |
| 239 m_client = 0; | 238 m_client = 0; |
| 240 m_document = 0; | 239 m_document = 0; |
| 241 if (m_handle) | 240 if (m_handle) |
| 242 m_handle->disconnect(); | 241 m_handle->disconnect(); |
| 243 } | 242 } |
| 244 | 243 |
| 245 void MainThreadWebSocketChannel::suspend() | 244 void MainThreadWebSocketChannel::suspend() |
| 246 { | 245 { |
| 247 m_suspended = true; | 246 m_suspended = true; |
| 248 } | 247 } |
| 249 | 248 |
| 250 void MainThreadWebSocketChannel::resume() | 249 void MainThreadWebSocketChannel::resume() |
| 251 { | 250 { |
| 252 m_suspended = false; | 251 m_suspended = false; |
| 253 if ((!m_buffer.isEmpty() || m_closed) && m_client && !m_resumeTimer.isActive
()) | 252 if ((!m_buffer.isEmpty() || (m_state == ChannelClosed)) && m_client && !m_re
sumeTimer.isActive()) |
| 254 m_resumeTimer.startOneShot(0); | 253 m_resumeTimer.startOneShot(0); |
| 255 } | 254 } |
| 256 | 255 |
| 257 void MainThreadWebSocketChannel::willOpenSocketStream(SocketStreamHandle* handle
) | 256 void MainThreadWebSocketChannel::willOpenSocketStream(SocketStreamHandle* handle
) |
| 258 { | 257 { |
| 259 LOG(Network, "MainThreadWebSocketChannel %p willOpenSocketStream()", this); | 258 LOG(Network, "MainThreadWebSocketChannel %p willOpenSocketStream()", this); |
| 260 ASSERT(handle); | 259 ASSERT(handle); |
| 261 if (m_document->frame()) | 260 if (m_document->frame()) |
| 262 m_document->frame()->loader()->client()->dispatchWillOpenSocketStream(ha
ndle); | 261 m_document->frame()->loader()->client()->dispatchWillOpenSocketStream(ha
ndle); |
| 263 } | 262 } |
| (...skipping 10 matching lines...) Expand all Loading... |
| 274 if (!handle->send(handshakeMessage.data(), handshakeMessage.length())) | 273 if (!handle->send(handshakeMessage.data(), handshakeMessage.length())) |
| 275 failAsError("Failed to send WebSocket handshake."); | 274 failAsError("Failed to send WebSocket handshake."); |
| 276 } | 275 } |
| 277 | 276 |
| 278 void MainThreadWebSocketChannel::didCloseSocketStream(SocketStreamHandle* handle
) | 277 void MainThreadWebSocketChannel::didCloseSocketStream(SocketStreamHandle* handle
) |
| 279 { | 278 { |
| 280 LOG(Network, "MainThreadWebSocketChannel %p didCloseSocketStream()", this); | 279 LOG(Network, "MainThreadWebSocketChannel %p didCloseSocketStream()", this); |
| 281 if (m_identifier && m_document) | 280 if (m_identifier && m_document) |
| 282 InspectorInstrumentation::didCloseWebSocket(m_document, m_identifier); | 281 InspectorInstrumentation::didCloseWebSocket(m_document, m_identifier); |
| 283 ASSERT_UNUSED(handle, handle == m_handle || !m_handle); | 282 ASSERT_UNUSED(handle, handle == m_handle || !m_handle); |
| 284 m_closed = true; | 283 m_state = ChannelClosed; |
| 285 if (m_closingTimer.isActive()) | 284 if (m_closingTimer.isActive()) |
| 286 m_closingTimer.stop(); | 285 m_closingTimer.stop(); |
| 287 if (m_outgoingFrameQueueStatus != OutgoingFrameQueueClosed) | 286 if (m_outgoingFrameQueueStatus != OutgoingFrameQueueClosed) |
| 288 abortOutgoingFrameQueue(); | 287 abortOutgoingFrameQueue(); |
| 289 if (m_handle) { | 288 if (m_handle) { |
| 290 m_unhandledBufferedAmount = m_handle->bufferedAmount(); | 289 m_unhandledBufferedAmount = m_handle->bufferedAmount(); |
| 291 if (m_suspended) | 290 if (m_suspended) |
| 292 return; | 291 return; |
| 293 WebSocketChannelClient* client = m_client; | 292 WebSocketChannelClient* client = m_client; |
| 294 m_client = 0; | 293 m_client = 0; |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 345 else if (error.localizedDescription().isNull()) | 344 else if (error.localizedDescription().isNull()) |
| 346 message = "WebSocket network error: error code " + String::number(error.
errorCode()); | 345 message = "WebSocket network error: error code " + String::number(error.
errorCode()); |
| 347 else | 346 else |
| 348 message = "WebSocket network error: error code " + String::number(error.
errorCode()) + ", " + error.localizedDescription(); | 347 message = "WebSocket network error: error code " + String::number(error.
errorCode()) + ", " + error.localizedDescription(); |
| 349 String failingURL = error.failingURL(); | 348 String failingURL = error.failingURL(); |
| 350 ASSERT(failingURL.isNull() || m_handshake->url().string() == failingURL); | 349 ASSERT(failingURL.isNull() || m_handshake->url().string() == failingURL); |
| 351 if (failingURL.isNull()) | 350 if (failingURL.isNull()) |
| 352 failingURL = m_handshake->url().string(); | 351 failingURL = m_handshake->url().string(); |
| 353 LOG(Network, "Error Message: '%s', FailURL: '%s'", message.utf8().data(), fa
ilingURL.utf8().data()); | 352 LOG(Network, "Error Message: '%s', FailURL: '%s'", message.utf8().data(), fa
ilingURL.utf8().data()); |
| 354 RefPtr<WebSocketChannel> protect(this); | 353 RefPtr<WebSocketChannel> protect(this); |
| 355 if (m_client && !m_closing && !m_didFailOfClientAlreadyRun) { | 354 if (m_client && (m_state != ChannelClosing && m_state != ChannelClosed) && !
m_didFailOfClientAlreadyRun) { |
| 356 m_didFailOfClientAlreadyRun = true; | 355 m_didFailOfClientAlreadyRun = true; |
| 357 m_client->didReceiveMessageError(); | 356 m_client->didReceiveMessageError(); |
| 358 } | 357 } |
| 359 if (m_handle && !m_closed) | 358 if (m_handle && (m_state != ChannelClosed)) |
| 360 m_handle->disconnect(); | 359 m_handle->disconnect(); |
| 361 } | 360 } |
| 362 | 361 |
| 363 void MainThreadWebSocketChannel::didStartLoading() | 362 void MainThreadWebSocketChannel::didStartLoading() |
| 364 { | 363 { |
| 365 LOG(Network, "MainThreadWebSocketChannel %p didStartLoading()", this); | 364 LOG(Network, "MainThreadWebSocketChannel %p didStartLoading()", this); |
| 366 ASSERT(m_blobLoader); | 365 ASSERT(m_blobLoader); |
| 367 ASSERT(m_blobLoaderStatus == BlobLoaderStarted); | 366 ASSERT(m_blobLoaderStatus == BlobLoaderStarted); |
| 368 } | 367 } |
| 369 | 368 |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 464 } | 463 } |
| 465 | 464 |
| 466 void MainThreadWebSocketChannel::resumeTimerFired(Timer<MainThreadWebSocketChann
el>* timer) | 465 void MainThreadWebSocketChannel::resumeTimerFired(Timer<MainThreadWebSocketChann
el>* timer) |
| 467 { | 466 { |
| 468 ASSERT_UNUSED(timer, timer == &m_resumeTimer); | 467 ASSERT_UNUSED(timer, timer == &m_resumeTimer); |
| 469 | 468 |
| 470 RefPtr<MainThreadWebSocketChannel> protect(this); // The client can close th
e channel, potentially removing the last reference. | 469 RefPtr<MainThreadWebSocketChannel> protect(this); // The client can close th
e channel, potentially removing the last reference. |
| 471 while (!m_suspended && m_client && !m_buffer.isEmpty()) | 470 while (!m_suspended && m_client && !m_buffer.isEmpty()) |
| 472 if (!processBuffer()) | 471 if (!processBuffer()) |
| 473 break; | 472 break; |
| 474 if (!m_suspended && m_client && m_closed && m_handle) | 473 if (!m_suspended && m_client && (m_state == ChannelClosed) && m_handle) |
| 475 didCloseSocketStream(m_handle.get()); | 474 didCloseSocketStream(m_handle.get()); |
| 476 } | 475 } |
| 477 | 476 |
| 478 void MainThreadWebSocketChannel::startClosingHandshake(int code, const String& r
eason) | 477 void MainThreadWebSocketChannel::startClosingHandshake(int code, const String& r
eason) |
| 479 { | 478 { |
| 480 LOG(Network, "MainThreadWebSocketChannel %p startClosingHandshake() code=%d
m_receivedClosingHandshake=%d", this, m_closing, m_receivedClosingHandshake); | 479 LOG(Network, "MainThreadWebSocketChannel %p startClosingHandshake() code=%d
m_receivedClosingHandshake=%d", this, (m_state == ChannelClosing), m_receivedClo
singHandshake); |
| 481 if (m_closing) | 480 if (m_state == ChannelClosing || m_state == ChannelClosed) |
| 482 return; | 481 return; |
| 483 ASSERT(m_handle); | 482 ASSERT(m_handle); |
| 484 | 483 |
| 485 Vector<char> buf; | 484 Vector<char> buf; |
| 486 if (!m_receivedClosingHandshake && code != CloseEventCodeNotSpecified) { | 485 if (!m_receivedClosingHandshake && code != CloseEventCodeNotSpecified) { |
| 487 unsigned char highByte = code >> 8; | 486 unsigned char highByte = code >> 8; |
| 488 unsigned char lowByte = code; | 487 unsigned char lowByte = code; |
| 489 buf.append(static_cast<char>(highByte)); | 488 buf.append(static_cast<char>(highByte)); |
| 490 buf.append(static_cast<char>(lowByte)); | 489 buf.append(static_cast<char>(lowByte)); |
| 491 buf.append(reason.utf8().data(), reason.utf8().length()); | 490 buf.append(reason.utf8().data(), reason.utf8().length()); |
| 492 } | 491 } |
| 493 enqueueRawFrame(WebSocketFrame::OpCodeClose, buf.data(), buf.size()); | 492 enqueueRawFrame(WebSocketFrame::OpCodeClose, buf.data(), buf.size()); |
| 494 processOutgoingFrameQueue(); | 493 processOutgoingFrameQueue(); |
| 495 | 494 |
| 496 m_closing = true; | 495 m_state = ChannelClosing; |
| 497 if (m_client) | 496 if (m_client) |
| 498 m_client->didStartClosingHandshake(); | 497 m_client->didStartClosingHandshake(); |
| 499 } | 498 } |
| 500 | 499 |
| 501 void MainThreadWebSocketChannel::closingTimerFired(Timer<MainThreadWebSocketChan
nel>* timer) | 500 void MainThreadWebSocketChannel::closingTimerFired(Timer<MainThreadWebSocketChan
nel>* timer) |
| 502 { | 501 { |
| 503 LOG(Network, "MainThreadWebSocketChannel %p closingTimerFired()", this); | 502 LOG(Network, "MainThreadWebSocketChannel %p closingTimerFired()", this); |
| 504 ASSERT_UNUSED(timer, &m_closingTimer == timer); | 503 ASSERT_UNUSED(timer, &m_closingTimer == timer); |
| 505 if (m_handle) | 504 if (m_handle) |
| 506 m_handle->disconnect(); | 505 m_handle->disconnect(); |
| (...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 659 return false; | 658 return false; |
| 660 } | 659 } |
| 661 } | 660 } |
| 662 if (frame.payloadLength >= 3) | 661 if (frame.payloadLength >= 3) |
| 663 m_closeEventReason = String::fromUTF8(&frame.payload[2], frame.paylo
adLength - 2); | 662 m_closeEventReason = String::fromUTF8(&frame.payload[2], frame.paylo
adLength - 2); |
| 664 else | 663 else |
| 665 m_closeEventReason = ""; | 664 m_closeEventReason = ""; |
| 666 skipBuffer(frameEnd - m_buffer.data()); | 665 skipBuffer(frameEnd - m_buffer.data()); |
| 667 m_receivedClosingHandshake = true; | 666 m_receivedClosingHandshake = true; |
| 668 startClosingHandshake(m_closeEventCode, m_closeEventReason); | 667 startClosingHandshake(m_closeEventCode, m_closeEventReason); |
| 669 if (m_closing) { | 668 if (m_state == ChannelClosing || m_state == ChannelClosed) { |
| 670 m_outgoingFrameQueueStatus = OutgoingFrameQueueClosing; | 669 m_outgoingFrameQueueStatus = OutgoingFrameQueueClosing; |
| 671 processOutgoingFrameQueue(); | 670 processOutgoingFrameQueue(); |
| 672 } | 671 } |
| 673 break; | 672 break; |
| 674 | 673 |
| 675 case WebSocketFrame::OpCodePing: | 674 case WebSocketFrame::OpCodePing: |
| 676 enqueueRawFrame(WebSocketFrame::OpCodePong, frame.payload, frame.payload
Length); | 675 enqueueRawFrame(WebSocketFrame::OpCodePong, frame.payload, frame.payload
Length); |
| 677 skipBuffer(frameEnd - m_buffer.data()); | 676 skipBuffer(frameEnd - m_buffer.data()); |
| 678 processOutgoingFrameQueue(); | 677 processOutgoingFrameQueue(); |
| 679 break; | 678 break; |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 816 } | 815 } |
| 817 | 816 |
| 818 Vector<char> frameData; | 817 Vector<char> frameData; |
| 819 frame.makeFrameData(frameData); | 818 frame.makeFrameData(frameData); |
| 820 | 819 |
| 821 m_perMessageDeflate.resetDeflateBuffer(); | 820 m_perMessageDeflate.resetDeflateBuffer(); |
| 822 return m_handle->send(frameData.data(), frameData.size()); | 821 return m_handle->send(frameData.data(), frameData.size()); |
| 823 } | 822 } |
| 824 | 823 |
| 825 } // namespace WebCore | 824 } // namespace WebCore |
| OLD | NEW |