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 |