OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/websockets/websocket_channel.h" | 5 #include "net/websockets/websocket_channel.h" |
6 | 6 |
7 #include <limits.h> // for INT_MAX | 7 #include <limits.h> // for INT_MAX |
8 | 8 |
9 #include <algorithm> | 9 #include <algorithm> |
10 #include <deque> | 10 #include <deque> |
(...skipping 26 matching lines...) Expand all Loading... |
37 | 37 |
38 namespace net { | 38 namespace net { |
39 | 39 |
40 namespace { | 40 namespace { |
41 | 41 |
42 using base::StreamingUtf8Validator; | 42 using base::StreamingUtf8Validator; |
43 | 43 |
44 const int kDefaultSendQuotaLowWaterMark = 1 << 16; | 44 const int kDefaultSendQuotaLowWaterMark = 1 << 16; |
45 const int kDefaultSendQuotaHighWaterMark = 1 << 17; | 45 const int kDefaultSendQuotaHighWaterMark = 1 << 17; |
46 const size_t kWebSocketCloseCodeLength = 2; | 46 const size_t kWebSocketCloseCodeLength = 2; |
47 // This timeout is based on TCPMaximumSegmentLifetime * 2 from | 47 // Timeout for waiting for the server to acknowledge a closing handshake. |
48 // MainThreadWebSocketChannel.cpp in Blink. | 48 const int kClosingHandshakeTimeoutSeconds = 60; |
49 const int kClosingHandshakeTimeoutSeconds = 2 * 2 * 60; | 49 // We wait for the server to close the underlying connection as recommended in |
| 50 // https://tools.ietf.org/html/rfc6455#section-7.1.1 |
| 51 // We don't use 2MSL since there're server implementations that don't follow |
| 52 // the recommendation and wait for the client to close the underlying |
| 53 // connection. It leads to unnecessarily long time before CloseEvent |
| 54 // invocation. We want to avoid this rather than strictly following the spec |
| 55 // recommendation. |
| 56 const int kUnderlyingConnectionCloseTimeoutSeconds = 2; |
50 | 57 |
51 typedef WebSocketEventInterface::ChannelState ChannelState; | 58 typedef WebSocketEventInterface::ChannelState ChannelState; |
52 const ChannelState CHANNEL_ALIVE = WebSocketEventInterface::CHANNEL_ALIVE; | 59 const ChannelState CHANNEL_ALIVE = WebSocketEventInterface::CHANNEL_ALIVE; |
53 const ChannelState CHANNEL_DELETED = WebSocketEventInterface::CHANNEL_DELETED; | 60 const ChannelState CHANNEL_DELETED = WebSocketEventInterface::CHANNEL_DELETED; |
54 | 61 |
55 // Maximum close reason length = max control frame payload - | 62 // Maximum close reason length = max control frame payload - |
56 // status code length | 63 // status code length |
57 // = 125 - 2 | 64 // = 125 - 2 |
58 const size_t kMaximumCloseReasonLength = 125 - kWebSocketCloseCodeLength; | 65 const size_t kMaximumCloseReasonLength = 125 - kWebSocketCloseCodeLength; |
59 | 66 |
(...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
289 | 296 |
290 WebSocketChannel::WebSocketChannel( | 297 WebSocketChannel::WebSocketChannel( |
291 scoped_ptr<WebSocketEventInterface> event_interface, | 298 scoped_ptr<WebSocketEventInterface> event_interface, |
292 URLRequestContext* url_request_context) | 299 URLRequestContext* url_request_context) |
293 : event_interface_(event_interface.Pass()), | 300 : event_interface_(event_interface.Pass()), |
294 url_request_context_(url_request_context), | 301 url_request_context_(url_request_context), |
295 send_quota_low_water_mark_(kDefaultSendQuotaLowWaterMark), | 302 send_quota_low_water_mark_(kDefaultSendQuotaLowWaterMark), |
296 send_quota_high_water_mark_(kDefaultSendQuotaHighWaterMark), | 303 send_quota_high_water_mark_(kDefaultSendQuotaHighWaterMark), |
297 current_send_quota_(0), | 304 current_send_quota_(0), |
298 current_receive_quota_(0), | 305 current_receive_quota_(0), |
299 timeout_(base::TimeDelta::FromSeconds(kClosingHandshakeTimeoutSeconds)), | 306 closing_handshake_timeout_(base::TimeDelta::FromSeconds( |
| 307 kClosingHandshakeTimeoutSeconds)), |
| 308 underlying_connection_close_timeout_(base::TimeDelta::FromSeconds( |
| 309 kUnderlyingConnectionCloseTimeoutSeconds)), |
300 has_received_close_frame_(false), | 310 has_received_close_frame_(false), |
301 received_close_code_(0), | 311 received_close_code_(0), |
302 state_(FRESHLY_CONSTRUCTED), | 312 state_(FRESHLY_CONSTRUCTED), |
303 notification_sender_(new HandshakeNotificationSender(this)), | 313 notification_sender_(new HandshakeNotificationSender(this)), |
304 sending_text_message_(false), | 314 sending_text_message_(false), |
305 receiving_text_message_(false), | 315 receiving_text_message_(false), |
306 expecting_to_handle_continuation_(false), | 316 expecting_to_handle_continuation_(false), |
307 initial_frame_forwarded_(false) {} | 317 initial_frame_forwarded_(false) {} |
308 | 318 |
309 WebSocketChannel::~WebSocketChannel() { | 319 WebSocketChannel::~WebSocketChannel() { |
310 // The stream may hold a pointer to read_frames_, and so it needs to be | 320 // The stream may hold a pointer to read_frames_, and so it needs to be |
311 // destroyed first. | 321 // destroyed first. |
312 stream_.reset(); | 322 stream_.reset(); |
313 // The timer may have a callback pointing back to us, so stop it just in case | 323 // The timer may have a callback pointing back to us, so stop it just in case |
314 // someone decides to run the event loop from their destructor. | 324 // someone decides to run the event loop from their destructor. |
315 timer_.Stop(); | 325 close_timer_.Stop(); |
316 } | 326 } |
317 | 327 |
318 void WebSocketChannel::SendAddChannelRequest( | 328 void WebSocketChannel::SendAddChannelRequest( |
319 const GURL& socket_url, | 329 const GURL& socket_url, |
320 const std::vector<std::string>& requested_subprotocols, | 330 const std::vector<std::string>& requested_subprotocols, |
321 const url::Origin& origin) { | 331 const url::Origin& origin) { |
322 // Delegate to the tested version. | 332 // Delegate to the tested version. |
323 SendAddChannelRequestWithSuppliedCreator( | 333 SendAddChannelRequestWithSuppliedCreator( |
324 socket_url, | 334 socket_url, |
325 requested_subprotocols, | 335 requested_subprotocols, |
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
471 // Abort the in-progress handshake and drop the connection immediately. | 481 // Abort the in-progress handshake and drop the connection immediately. |
472 stream_request_.reset(); | 482 stream_request_.reset(); |
473 SetState(CLOSED); | 483 SetState(CLOSED); |
474 DoDropChannel(false, kWebSocketErrorAbnormalClosure, ""); | 484 DoDropChannel(false, kWebSocketErrorAbnormalClosure, ""); |
475 return; | 485 return; |
476 } | 486 } |
477 if (state_ != CONNECTED) { | 487 if (state_ != CONNECTED) { |
478 NOTREACHED() << "StartClosingHandshake() called in state " << state_; | 488 NOTREACHED() << "StartClosingHandshake() called in state " << state_; |
479 return; | 489 return; |
480 } | 490 } |
| 491 |
| 492 DCHECK(!close_timer_.IsRunning()); |
| 493 // This use of base::Unretained() is safe because we stop the timer in the |
| 494 // destructor. |
| 495 close_timer_.Start( |
| 496 FROM_HERE, |
| 497 closing_handshake_timeout_, |
| 498 base::Bind(&WebSocketChannel::CloseTimeout, base::Unretained(this))); |
| 499 |
481 // Javascript actually only permits 1000 and 3000-4999, but the implementation | 500 // Javascript actually only permits 1000 and 3000-4999, but the implementation |
482 // itself may produce different codes. The length of |reason| is also checked | 501 // itself may produce different codes. The length of |reason| is also checked |
483 // by Javascript. | 502 // by Javascript. |
484 if (!IsStrictlyValidCloseStatusCode(code) || | 503 if (!IsStrictlyValidCloseStatusCode(code) || |
485 reason.size() > kMaximumCloseReasonLength) { | 504 reason.size() > kMaximumCloseReasonLength) { |
486 // "InternalServerError" is actually used for errors from any endpoint, per | 505 // "InternalServerError" is actually used for errors from any endpoint, per |
487 // errata 3227 to RFC6455. If the renderer is sending us an invalid code or | 506 // errata 3227 to RFC6455. If the renderer is sending us an invalid code or |
488 // reason it must be malfunctioning in some way, and based on that we | 507 // reason it must be malfunctioning in some way, and based on that we |
489 // interpret this as an internal error. | 508 // interpret this as an internal error. |
490 if (SendClose(kWebSocketErrorInternalServerError, "") != CHANNEL_DELETED) { | 509 if (SendClose(kWebSocketErrorInternalServerError, "") != CHANNEL_DELETED) { |
(...skipping 15 matching lines...) Expand all Loading... |
506 const GURL& socket_url, | 525 const GURL& socket_url, |
507 const std::vector<std::string>& requested_subprotocols, | 526 const std::vector<std::string>& requested_subprotocols, |
508 const url::Origin& origin, | 527 const url::Origin& origin, |
509 const WebSocketStreamCreator& creator) { | 528 const WebSocketStreamCreator& creator) { |
510 SendAddChannelRequestWithSuppliedCreator( | 529 SendAddChannelRequestWithSuppliedCreator( |
511 socket_url, requested_subprotocols, origin, creator); | 530 socket_url, requested_subprotocols, origin, creator); |
512 } | 531 } |
513 | 532 |
514 void WebSocketChannel::SetClosingHandshakeTimeoutForTesting( | 533 void WebSocketChannel::SetClosingHandshakeTimeoutForTesting( |
515 base::TimeDelta delay) { | 534 base::TimeDelta delay) { |
516 timeout_ = delay; | 535 closing_handshake_timeout_ = delay; |
| 536 } |
| 537 |
| 538 void WebSocketChannel::SetUnderlyingConnectionCloseTimeoutForTesting( |
| 539 base::TimeDelta delay) { |
| 540 underlying_connection_close_timeout_ = delay; |
517 } | 541 } |
518 | 542 |
519 void WebSocketChannel::SendAddChannelRequestWithSuppliedCreator( | 543 void WebSocketChannel::SendAddChannelRequestWithSuppliedCreator( |
520 const GURL& socket_url, | 544 const GURL& socket_url, |
521 const std::vector<std::string>& requested_subprotocols, | 545 const std::vector<std::string>& requested_subprotocols, |
522 const url::Origin& origin, | 546 const url::Origin& origin, |
523 const WebSocketStreamCreator& creator) { | 547 const WebSocketStreamCreator& creator) { |
524 DCHECK_EQ(FRESHLY_CONSTRUCTED, state_); | 548 DCHECK_EQ(FRESHLY_CONSTRUCTED, state_); |
525 if (!socket_url.SchemeIsWSOrWSS()) { | 549 if (!socket_url.SchemeIsWSOrWSS()) { |
526 // TODO(ricea): Kill the renderer (this error should have been caught by | 550 // TODO(ricea): Kill the renderer (this error should have been caught by |
(...skipping 305 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
832 std::string message; | 856 std::string message; |
833 if (!ParseClose(data_buffer, size, &code, &reason, &message)) { | 857 if (!ParseClose(data_buffer, size, &code, &reason, &message)) { |
834 return FailChannel(message, code, reason); | 858 return FailChannel(message, code, reason); |
835 } | 859 } |
836 // TODO(ricea): Find a way to safely log the message from the close | 860 // TODO(ricea): Find a way to safely log the message from the close |
837 // message (escape control codes and so on). | 861 // message (escape control codes and so on). |
838 DVLOG(1) << "Got Close with code " << code; | 862 DVLOG(1) << "Got Close with code " << code; |
839 switch (state_) { | 863 switch (state_) { |
840 case CONNECTED: | 864 case CONNECTED: |
841 SetState(RECV_CLOSED); | 865 SetState(RECV_CLOSED); |
| 866 |
842 if (SendClose(code, reason) == CHANNEL_DELETED) | 867 if (SendClose(code, reason) == CHANNEL_DELETED) |
843 return CHANNEL_DELETED; | 868 return CHANNEL_DELETED; |
844 DCHECK_EQ(RECV_CLOSED, state_); | 869 DCHECK_EQ(RECV_CLOSED, state_); |
| 870 |
845 SetState(CLOSE_WAIT); | 871 SetState(CLOSE_WAIT); |
| 872 DCHECK(!close_timer_.IsRunning()); |
| 873 // This use of base::Unretained() is safe because we stop the timer |
| 874 // in the destructor. |
| 875 close_timer_.Start( |
| 876 FROM_HERE, |
| 877 underlying_connection_close_timeout_, |
| 878 base::Bind( |
| 879 &WebSocketChannel::CloseTimeout, base::Unretained(this))); |
846 | 880 |
847 if (event_interface_->OnClosingHandshake() == CHANNEL_DELETED) | 881 if (event_interface_->OnClosingHandshake() == CHANNEL_DELETED) |
848 return CHANNEL_DELETED; | 882 return CHANNEL_DELETED; |
849 has_received_close_frame_ = true; | 883 has_received_close_frame_ = true; |
850 received_close_code_ = code; | 884 received_close_code_ = code; |
851 received_close_reason_ = reason; | 885 received_close_reason_ = reason; |
852 break; | 886 break; |
853 | 887 |
854 case SEND_CLOSED: | 888 case SEND_CLOSED: |
855 SetState(CLOSE_WAIT); | 889 SetState(CLOSE_WAIT); |
| 890 DCHECK(close_timer_.IsRunning()); |
| 891 close_timer_.Stop(); |
| 892 // This use of base::Unretained() is safe because we stop the timer |
| 893 // in the destructor. |
| 894 close_timer_.Start( |
| 895 FROM_HERE, |
| 896 underlying_connection_close_timeout_, |
| 897 base::Bind( |
| 898 &WebSocketChannel::CloseTimeout, base::Unretained(this))); |
| 899 |
856 // From RFC6455 section 7.1.5: "Each endpoint | 900 // From RFC6455 section 7.1.5: "Each endpoint |
857 // will see the status code sent by the other end as _The WebSocket | 901 // will see the status code sent by the other end as _The WebSocket |
858 // Connection Close Code_." | 902 // Connection Close Code_." |
859 has_received_close_frame_ = true; | 903 has_received_close_frame_ = true; |
860 received_close_code_ = code; | 904 received_close_code_ = code; |
861 received_close_reason_ = reason; | 905 received_close_reason_ = reason; |
862 break; | 906 break; |
863 | 907 |
864 default: | 908 default: |
865 LOG(DFATAL) << "Got Close in unexpected state " << state_; | 909 LOG(DFATAL) << "Got Close in unexpected state " << state_; |
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1020 } else { | 1064 } else { |
1021 const size_t payload_length = kWebSocketCloseCodeLength + reason.length(); | 1065 const size_t payload_length = kWebSocketCloseCodeLength + reason.length(); |
1022 body = new IOBuffer(payload_length); | 1066 body = new IOBuffer(payload_length); |
1023 size = payload_length; | 1067 size = payload_length; |
1024 base::WriteBigEndian(body->data(), code); | 1068 base::WriteBigEndian(body->data(), code); |
1025 COMPILE_ASSERT(sizeof(code) == kWebSocketCloseCodeLength, | 1069 COMPILE_ASSERT(sizeof(code) == kWebSocketCloseCodeLength, |
1026 they_should_both_be_two); | 1070 they_should_both_be_two); |
1027 std::copy( | 1071 std::copy( |
1028 reason.begin(), reason.end(), body->data() + kWebSocketCloseCodeLength); | 1072 reason.begin(), reason.end(), body->data() + kWebSocketCloseCodeLength); |
1029 } | 1073 } |
1030 // This use of base::Unretained() is safe because we stop the timer in the | |
1031 // destructor. | |
1032 timer_.Start( | |
1033 FROM_HERE, | |
1034 timeout_, | |
1035 base::Bind(&WebSocketChannel::CloseTimeout, base::Unretained(this))); | |
1036 if (SendFrameFromIOBuffer( | 1074 if (SendFrameFromIOBuffer( |
1037 true, WebSocketFrameHeader::kOpCodeClose, body, size) == | 1075 true, WebSocketFrameHeader::kOpCodeClose, body, size) == |
1038 CHANNEL_DELETED) | 1076 CHANNEL_DELETED) |
1039 return CHANNEL_DELETED; | 1077 return CHANNEL_DELETED; |
1040 return CHANNEL_ALIVE; | 1078 return CHANNEL_ALIVE; |
1041 } | 1079 } |
1042 | 1080 |
1043 bool WebSocketChannel::ParseClose(const scoped_refptr<IOBuffer>& buffer, | 1081 bool WebSocketChannel::ParseClose(const scoped_refptr<IOBuffer>& buffer, |
1044 uint64 size, | 1082 uint64 size, |
1045 uint16* code, | 1083 uint16* code, |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1106 } | 1144 } |
1107 | 1145 |
1108 void WebSocketChannel::CloseTimeout() { | 1146 void WebSocketChannel::CloseTimeout() { |
1109 stream_->Close(); | 1147 stream_->Close(); |
1110 SetState(CLOSED); | 1148 SetState(CLOSED); |
1111 DoDropChannel(false, kWebSocketErrorAbnormalClosure, ""); | 1149 DoDropChannel(false, kWebSocketErrorAbnormalClosure, ""); |
1112 // |this| has been deleted. | 1150 // |this| has been deleted. |
1113 } | 1151 } |
1114 | 1152 |
1115 } // namespace net | 1153 } // namespace net |
OLD | NEW |