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 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
63 | 63 |
64 // Maximum close reason length = max control frame payload - | 64 // Maximum close reason length = max control frame payload - |
65 // status code length | 65 // status code length |
66 // = 125 - 2 | 66 // = 125 - 2 |
67 const size_t kMaximumCloseReasonLength = 125 - kWebSocketCloseCodeLength; | 67 const size_t kMaximumCloseReasonLength = 125 - kWebSocketCloseCodeLength; |
68 | 68 |
69 // Check a close status code for strict compliance with RFC6455. This is only | 69 // Check a close status code for strict compliance with RFC6455. This is only |
70 // used for close codes received from a renderer that we are intending to send | 70 // used for close codes received from a renderer that we are intending to send |
71 // out over the network. See ParseClose() for the restrictions on incoming close | 71 // out over the network. See ParseClose() for the restrictions on incoming close |
72 // codes. The |code| parameter is type int for convenience of implementation; | 72 // codes. The |code| parameter is type int for convenience of implementation; |
73 // the real type is uint16. Code 1005 is treated specially; it cannot be set | 73 // the real type is uint16_t. Code 1005 is treated specially; it cannot be set |
74 // explicitly by Javascript but the renderer uses it to indicate we should send | 74 // explicitly by Javascript but the renderer uses it to indicate we should send |
75 // a Close frame with no payload. | 75 // a Close frame with no payload. |
76 bool IsStrictlyValidCloseStatusCode(int code) { | 76 bool IsStrictlyValidCloseStatusCode(int code) { |
77 static const int kInvalidRanges[] = { | 77 static const int kInvalidRanges[] = { |
78 // [BAD, OK) | 78 // [BAD, OK) |
79 0, 1000, // 1000 is the first valid code | 79 0, 1000, // 1000 is the first valid code |
80 1006, 1007, // 1006 MUST NOT be set. | 80 1006, 1007, // 1006 MUST NOT be set. |
81 1014, 3000, // 1014 unassigned; 1015 up to 2999 are reserved. | 81 1014, 3000, // 1014 unassigned; 1015 up to 2999 are reserved. |
82 5000, 65536, // Codes above 5000 are invalid. | 82 5000, 65536, // Codes above 5000 are invalid. |
83 }; | 83 }; |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
140 // Return a pointer to the frames_ for write purposes. | 140 // Return a pointer to the frames_ for write purposes. |
141 ScopedVector<WebSocketFrame>* frames() { return &frames_; } | 141 ScopedVector<WebSocketFrame>* frames() { return &frames_; } |
142 | 142 |
143 private: | 143 private: |
144 // The frames_ that will be sent in the next call to WriteFrames(). | 144 // The frames_ that will be sent in the next call to WriteFrames(). |
145 ScopedVector<WebSocketFrame> frames_; | 145 ScopedVector<WebSocketFrame> frames_; |
146 | 146 |
147 // The total size of the payload data in |frames_|. This will be used to | 147 // The total size of the payload data in |frames_|. This will be used to |
148 // measure the throughput of the link. | 148 // measure the throughput of the link. |
149 // TODO(ricea): Measure the throughput of the link. | 149 // TODO(ricea): Measure the throughput of the link. |
150 uint64 total_bytes_; | 150 uint64_t total_bytes_; |
151 }; | 151 }; |
152 | 152 |
153 void WebSocketChannel::SendBuffer::AddFrame(scoped_ptr<WebSocketFrame> frame) { | 153 void WebSocketChannel::SendBuffer::AddFrame(scoped_ptr<WebSocketFrame> frame) { |
154 total_bytes_ += frame->header.payload_length; | 154 total_bytes_ += frame->header.payload_length; |
155 frames_.push_back(frame.Pass()); | 155 frames_.push_back(frame.Pass()); |
156 } | 156 } |
157 | 157 |
158 // Implementation of WebSocketStream::ConnectDelegate that simply forwards the | 158 // Implementation of WebSocketStream::ConnectDelegate that simply forwards the |
159 // calls on to the WebSocketChannel that created it. | 159 // calls on to the WebSocketChannel that created it. |
160 class WebSocketChannel::ConnectDelegate | 160 class WebSocketChannel::ConnectDelegate |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
268 // there will be no more opening handshake notification. | 268 // there will be no more opening handshake notification. |
269 } | 269 } |
270 | 270 |
271 return CHANNEL_ALIVE; | 271 return CHANNEL_ALIVE; |
272 } | 272 } |
273 | 273 |
274 WebSocketChannel::PendingReceivedFrame::PendingReceivedFrame( | 274 WebSocketChannel::PendingReceivedFrame::PendingReceivedFrame( |
275 bool final, | 275 bool final, |
276 WebSocketFrameHeader::OpCode opcode, | 276 WebSocketFrameHeader::OpCode opcode, |
277 const scoped_refptr<IOBuffer>& data, | 277 const scoped_refptr<IOBuffer>& data, |
278 uint64 offset, | 278 uint64_t offset, |
279 uint64 size) | 279 uint64_t size) |
280 : final_(final), | 280 : final_(final), |
281 opcode_(opcode), | 281 opcode_(opcode), |
282 data_(data), | 282 data_(data), |
283 offset_(offset), | 283 offset_(offset), |
284 size_(size) {} | 284 size_(size) {} |
285 | 285 |
286 WebSocketChannel::PendingReceivedFrame::~PendingReceivedFrame() {} | 286 WebSocketChannel::PendingReceivedFrame::~PendingReceivedFrame() {} |
287 | 287 |
288 void WebSocketChannel::PendingReceivedFrame::ResetOpcode() { | 288 void WebSocketChannel::PendingReceivedFrame::ResetOpcode() { |
289 DCHECK(WebSocketFrameHeader::IsKnownDataOpCode(opcode_)); | 289 DCHECK(WebSocketFrameHeader::IsKnownDataOpCode(opcode_)); |
290 opcode_ = WebSocketFrameHeader::kOpCodeContinuation; | 290 opcode_ = WebSocketFrameHeader::kOpCodeContinuation; |
291 } | 291 } |
292 | 292 |
293 void WebSocketChannel::PendingReceivedFrame::DidConsume(uint64 bytes) { | 293 void WebSocketChannel::PendingReceivedFrame::DidConsume(uint64_t bytes) { |
294 DCHECK_LE(offset_, size_); | 294 DCHECK_LE(offset_, size_); |
295 DCHECK_LE(bytes, size_ - offset_); | 295 DCHECK_LE(bytes, size_ - offset_); |
296 offset_ += bytes; | 296 offset_ += bytes; |
297 } | 297 } |
298 | 298 |
299 WebSocketChannel::WebSocketChannel( | 299 WebSocketChannel::WebSocketChannel( |
300 scoped_ptr<WebSocketEventInterface> event_interface, | 300 scoped_ptr<WebSocketEventInterface> event_interface, |
301 URLRequestContext* url_request_context) | 301 URLRequestContext* url_request_context) |
302 : event_interface_(event_interface.Pass()), | 302 : event_interface_(event_interface.Pass()), |
303 url_request_context_(url_request_context), | 303 url_request_context_(url_request_context), |
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
417 // TODO(ricea): If current_send_quota_ has dropped below | 417 // TODO(ricea): If current_send_quota_ has dropped below |
418 // send_quota_low_water_mark_, it might be good to increase the "low | 418 // send_quota_low_water_mark_, it might be good to increase the "low |
419 // water mark" and "high water mark", but only if the link to the WebSocket | 419 // water mark" and "high water mark", but only if the link to the WebSocket |
420 // server is not saturated. | 420 // server is not saturated. |
421 scoped_refptr<IOBuffer> buffer(new IOBuffer(data.size())); | 421 scoped_refptr<IOBuffer> buffer(new IOBuffer(data.size())); |
422 std::copy(data.begin(), data.end(), buffer->data()); | 422 std::copy(data.begin(), data.end(), buffer->data()); |
423 ignore_result(SendFrameFromIOBuffer(fin, op_code, buffer, data.size())); | 423 ignore_result(SendFrameFromIOBuffer(fin, op_code, buffer, data.size())); |
424 // |this| may have been deleted. | 424 // |this| may have been deleted. |
425 } | 425 } |
426 | 426 |
427 void WebSocketChannel::SendFlowControl(int64 quota) { | 427 void WebSocketChannel::SendFlowControl(int64_t quota) { |
428 DCHECK(state_ == CONNECTING || state_ == CONNECTED || state_ == SEND_CLOSED || | 428 DCHECK(state_ == CONNECTING || state_ == CONNECTED || state_ == SEND_CLOSED || |
429 state_ == CLOSE_WAIT); | 429 state_ == CLOSE_WAIT); |
430 // TODO(ricea): Kill the renderer if it tries to send us a negative quota | 430 // TODO(ricea): Kill the renderer if it tries to send us a negative quota |
431 // value or > INT_MAX. | 431 // value or > INT_MAX. |
432 DCHECK_GE(quota, 0); | 432 DCHECK_GE(quota, 0); |
433 DCHECK_LE(quota, INT_MAX); | 433 DCHECK_LE(quota, INT_MAX); |
434 if (!pending_received_frames_.empty()) { | 434 if (!pending_received_frames_.empty()) { |
435 DCHECK_EQ(0u, current_receive_quota_); | 435 DCHECK_EQ(0u, current_receive_quota_); |
436 } | 436 } |
437 while (!pending_received_frames_.empty() && quota > 0) { | 437 while (!pending_received_frames_.empty() && quota > 0) { |
438 PendingReceivedFrame& front = pending_received_frames_.front(); | 438 PendingReceivedFrame& front = pending_received_frames_.front(); |
439 const uint64 data_size = front.size() - front.offset(); | 439 const uint64_t data_size = front.size() - front.offset(); |
440 const uint64 bytes_to_send = | 440 const uint64_t bytes_to_send = |
441 std::min(base::checked_cast<uint64>(quota), data_size); | 441 std::min(base::checked_cast<uint64_t>(quota), data_size); |
442 const bool final = front.final() && data_size == bytes_to_send; | 442 const bool final = front.final() && data_size == bytes_to_send; |
443 const char* data = | 443 const char* data = |
444 front.data().get() ? front.data()->data() + front.offset() : NULL; | 444 front.data().get() ? front.data()->data() + front.offset() : NULL; |
445 DCHECK(!bytes_to_send || data) << "Non empty data should not be null."; | 445 DCHECK(!bytes_to_send || data) << "Non empty data should not be null."; |
446 const std::vector<char> data_vector(data, data + bytes_to_send); | 446 const std::vector<char> data_vector(data, data + bytes_to_send); |
447 DVLOG(3) << "Sending frame previously split due to quota to the " | 447 DVLOG(3) << "Sending frame previously split due to quota to the " |
448 << "renderer: quota=" << quota << " data_size=" << data_size | 448 << "renderer: quota=" << quota << " data_size=" << data_size |
449 << " bytes_to_send=" << bytes_to_send; | 449 << " bytes_to_send=" << bytes_to_send; |
450 if (event_interface_->OnDataFrame(final, front.opcode(), data_vector) == | 450 if (event_interface_->OnDataFrame(final, front.opcode(), data_vector) == |
451 CHANNEL_DELETED) | 451 CHANNEL_DELETED) |
(...skipping 11 matching lines...) Expand all Loading... |
463 // operation. | 463 // operation. |
464 const bool start_read = | 464 const bool start_read = |
465 current_receive_quota_ == 0 && quota > 0 && | 465 current_receive_quota_ == 0 && quota > 0 && |
466 (state_ == CONNECTED || state_ == SEND_CLOSED || state_ == CLOSE_WAIT); | 466 (state_ == CONNECTED || state_ == SEND_CLOSED || state_ == CLOSE_WAIT); |
467 current_receive_quota_ += quota; | 467 current_receive_quota_ += quota; |
468 if (start_read) | 468 if (start_read) |
469 ignore_result(ReadFrames()); | 469 ignore_result(ReadFrames()); |
470 // |this| may have been deleted. | 470 // |this| may have been deleted. |
471 } | 471 } |
472 | 472 |
473 void WebSocketChannel::StartClosingHandshake(uint16 code, | 473 void WebSocketChannel::StartClosingHandshake(uint16_t code, |
474 const std::string& reason) { | 474 const std::string& reason) { |
475 if (InClosingState()) { | 475 if (InClosingState()) { |
476 // When the associated renderer process is killed while the channel is in | 476 // When the associated renderer process is killed while the channel is in |
477 // CLOSING state we reach here. | 477 // CLOSING state we reach here. |
478 DVLOG(1) << "StartClosingHandshake called in state " << state_ | 478 DVLOG(1) << "StartClosingHandshake called in state " << state_ |
479 << ". This may be a bug, or a harmless race."; | 479 << ". This may be a bug, or a harmless race."; |
480 return; | 480 return; |
481 } | 481 } |
482 if (state_ == CONNECTING) { | 482 if (state_ == CONNECTING) { |
483 // Abort the in-progress handshake and drop the connection immediately. | 483 // Abort the in-progress handshake and drop the connection immediately. |
(...skipping 277 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
761 kWebSocketErrorProtocolError, | 761 kWebSocketErrorProtocolError, |
762 "WebSocket Protocol Error"); | 762 "WebSocket Protocol Error"); |
763 | 763 |
764 default: | 764 default: |
765 DCHECK_LT(result, 0) | 765 DCHECK_LT(result, 0) |
766 << "ReadFrames() should only return OK or ERR_ codes"; | 766 << "ReadFrames() should only return OK or ERR_ codes"; |
767 | 767 |
768 stream_->Close(); | 768 stream_->Close(); |
769 SetState(CLOSED); | 769 SetState(CLOSED); |
770 | 770 |
771 uint16 code = kWebSocketErrorAbnormalClosure; | 771 uint16_t code = kWebSocketErrorAbnormalClosure; |
772 std::string reason = ""; | 772 std::string reason = ""; |
773 bool was_clean = false; | 773 bool was_clean = false; |
774 if (has_received_close_frame_) { | 774 if (has_received_close_frame_) { |
775 code = received_close_code_; | 775 code = received_close_code_; |
776 reason = received_close_reason_; | 776 reason = received_close_reason_; |
777 was_clean = (result == ERR_CONNECTION_CLOSED); | 777 was_clean = (result == ERR_CONNECTION_CLOSED); |
778 } | 778 } |
779 | 779 |
780 return DoDropChannel(was_clean, code, reason); | 780 return DoDropChannel(was_clean, code, reason); |
781 } | 781 } |
(...skipping 26 matching lines...) Expand all Loading... |
808 | 808 |
809 // Respond to the frame appropriately to its type. | 809 // Respond to the frame appropriately to its type. |
810 return HandleFrameByState( | 810 return HandleFrameByState( |
811 opcode, frame->header.final, frame->data, frame->header.payload_length); | 811 opcode, frame->header.final, frame->data, frame->header.payload_length); |
812 } | 812 } |
813 | 813 |
814 ChannelState WebSocketChannel::HandleFrameByState( | 814 ChannelState WebSocketChannel::HandleFrameByState( |
815 const WebSocketFrameHeader::OpCode opcode, | 815 const WebSocketFrameHeader::OpCode opcode, |
816 bool final, | 816 bool final, |
817 const scoped_refptr<IOBuffer>& data_buffer, | 817 const scoped_refptr<IOBuffer>& data_buffer, |
818 uint64 size) { | 818 uint64_t size) { |
819 DCHECK_NE(RECV_CLOSED, state_) | 819 DCHECK_NE(RECV_CLOSED, state_) |
820 << "HandleFrame() does not support being called re-entrantly from within " | 820 << "HandleFrame() does not support being called re-entrantly from within " |
821 "SendClose()"; | 821 "SendClose()"; |
822 DCHECK_NE(CLOSED, state_); | 822 DCHECK_NE(CLOSED, state_); |
823 if (state_ == CLOSE_WAIT) { | 823 if (state_ == CLOSE_WAIT) { |
824 std::string frame_name; | 824 std::string frame_name; |
825 GetFrameTypeForOpcode(opcode, &frame_name); | 825 GetFrameTypeForOpcode(opcode, &frame_name); |
826 | 826 |
827 // FailChannel() won't send another Close frame. | 827 // FailChannel() won't send another Close frame. |
828 return FailChannel( | 828 return FailChannel( |
(...skipping 16 matching lines...) Expand all Loading... |
845 case WebSocketFrameHeader::kOpCodePong: | 845 case WebSocketFrameHeader::kOpCodePong: |
846 DVLOG(1) << "Got Pong of size " << size; | 846 DVLOG(1) << "Got Pong of size " << size; |
847 // There is no need to do anything with pong messages. | 847 // There is no need to do anything with pong messages. |
848 return CHANNEL_ALIVE; | 848 return CHANNEL_ALIVE; |
849 | 849 |
850 case WebSocketFrameHeader::kOpCodeClose: { | 850 case WebSocketFrameHeader::kOpCodeClose: { |
851 // TODO(ricea): If there is a message which is queued for transmission to | 851 // TODO(ricea): If there is a message which is queued for transmission to |
852 // the renderer, then the renderer should not receive an | 852 // the renderer, then the renderer should not receive an |
853 // OnClosingHandshake or OnDropChannel IPC until the queued message has | 853 // OnClosingHandshake or OnDropChannel IPC until the queued message has |
854 // been completedly transmitted. | 854 // been completedly transmitted. |
855 uint16 code = kWebSocketNormalClosure; | 855 uint16_t code = kWebSocketNormalClosure; |
856 std::string reason; | 856 std::string reason; |
857 std::string message; | 857 std::string message; |
858 if (!ParseClose(data_buffer, size, &code, &reason, &message)) { | 858 if (!ParseClose(data_buffer, size, &code, &reason, &message)) { |
859 return FailChannel(message, code, reason); | 859 return FailChannel(message, code, reason); |
860 } | 860 } |
861 // TODO(ricea): Find a way to safely log the message from the close | 861 // TODO(ricea): Find a way to safely log the message from the close |
862 // message (escape control codes and so on). | 862 // message (escape control codes and so on). |
863 DVLOG(1) << "Got Close with code " << code; | 863 DVLOG(1) << "Got Close with code " << code; |
864 switch (state_) { | 864 switch (state_) { |
865 case CONNECTED: | 865 case CONNECTED: |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
918 base::StringPrintf("Unrecognized frame opcode: %d", opcode), | 918 base::StringPrintf("Unrecognized frame opcode: %d", opcode), |
919 kWebSocketErrorProtocolError, | 919 kWebSocketErrorProtocolError, |
920 "Unknown opcode"); | 920 "Unknown opcode"); |
921 } | 921 } |
922 } | 922 } |
923 | 923 |
924 ChannelState WebSocketChannel::HandleDataFrame( | 924 ChannelState WebSocketChannel::HandleDataFrame( |
925 WebSocketFrameHeader::OpCode opcode, | 925 WebSocketFrameHeader::OpCode opcode, |
926 bool final, | 926 bool final, |
927 const scoped_refptr<IOBuffer>& data_buffer, | 927 const scoped_refptr<IOBuffer>& data_buffer, |
928 uint64 size) { | 928 uint64_t size) { |
929 if (state_ != CONNECTED) { | 929 if (state_ != CONNECTED) { |
930 DVLOG(3) << "Ignored data packet received in state " << state_; | 930 DVLOG(3) << "Ignored data packet received in state " << state_; |
931 return CHANNEL_ALIVE; | 931 return CHANNEL_ALIVE; |
932 } | 932 } |
933 DCHECK(opcode == WebSocketFrameHeader::kOpCodeContinuation || | 933 DCHECK(opcode == WebSocketFrameHeader::kOpCodeContinuation || |
934 opcode == WebSocketFrameHeader::kOpCodeText || | 934 opcode == WebSocketFrameHeader::kOpCodeText || |
935 opcode == WebSocketFrameHeader::kOpCodeBinary); | 935 opcode == WebSocketFrameHeader::kOpCodeBinary); |
936 const bool got_continuation = | 936 const bool got_continuation = |
937 (opcode == WebSocketFrameHeader::kOpCodeContinuation); | 937 (opcode == WebSocketFrameHeader::kOpCodeContinuation); |
938 if (got_continuation != expecting_to_handle_continuation_) { | 938 if (got_continuation != expecting_to_handle_continuation_) { |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
994 current_receive_quota_ -= size; | 994 current_receive_quota_ -= size; |
995 | 995 |
996 // Sends the received frame to the renderer process. | 996 // Sends the received frame to the renderer process. |
997 return event_interface_->OnDataFrame(final, opcode_to_send, data); | 997 return event_interface_->OnDataFrame(final, opcode_to_send, data); |
998 } | 998 } |
999 | 999 |
1000 ChannelState WebSocketChannel::SendFrameFromIOBuffer( | 1000 ChannelState WebSocketChannel::SendFrameFromIOBuffer( |
1001 bool fin, | 1001 bool fin, |
1002 WebSocketFrameHeader::OpCode op_code, | 1002 WebSocketFrameHeader::OpCode op_code, |
1003 const scoped_refptr<IOBuffer>& buffer, | 1003 const scoped_refptr<IOBuffer>& buffer, |
1004 uint64 size) { | 1004 uint64_t size) { |
1005 DCHECK(state_ == CONNECTED || state_ == RECV_CLOSED); | 1005 DCHECK(state_ == CONNECTED || state_ == RECV_CLOSED); |
1006 DCHECK(stream_); | 1006 DCHECK(stream_); |
1007 | 1007 |
1008 scoped_ptr<WebSocketFrame> frame(new WebSocketFrame(op_code)); | 1008 scoped_ptr<WebSocketFrame> frame(new WebSocketFrame(op_code)); |
1009 WebSocketFrameHeader& header = frame->header; | 1009 WebSocketFrameHeader& header = frame->header; |
1010 header.final = fin; | 1010 header.final = fin; |
1011 header.masked = true; | 1011 header.masked = true; |
1012 header.payload_length = size; | 1012 header.payload_length = size; |
1013 frame->data = buffer; | 1013 frame->data = buffer; |
1014 | 1014 |
1015 if (data_being_sent_) { | 1015 if (data_being_sent_) { |
1016 // Either the link to the WebSocket server is saturated, or several messages | 1016 // Either the link to the WebSocket server is saturated, or several messages |
1017 // are being sent in a batch. | 1017 // are being sent in a batch. |
1018 // TODO(ricea): Keep some statistics to work out the situation and adjust | 1018 // TODO(ricea): Keep some statistics to work out the situation and adjust |
1019 // quota appropriately. | 1019 // quota appropriately. |
1020 if (!data_to_send_next_) | 1020 if (!data_to_send_next_) |
1021 data_to_send_next_.reset(new SendBuffer); | 1021 data_to_send_next_.reset(new SendBuffer); |
1022 data_to_send_next_->AddFrame(frame.Pass()); | 1022 data_to_send_next_->AddFrame(frame.Pass()); |
1023 return CHANNEL_ALIVE; | 1023 return CHANNEL_ALIVE; |
1024 } | 1024 } |
1025 | 1025 |
1026 data_being_sent_.reset(new SendBuffer); | 1026 data_being_sent_.reset(new SendBuffer); |
1027 data_being_sent_->AddFrame(frame.Pass()); | 1027 data_being_sent_->AddFrame(frame.Pass()); |
1028 return WriteFrames(); | 1028 return WriteFrames(); |
1029 } | 1029 } |
1030 | 1030 |
1031 ChannelState WebSocketChannel::FailChannel(const std::string& message, | 1031 ChannelState WebSocketChannel::FailChannel(const std::string& message, |
1032 uint16 code, | 1032 uint16_t code, |
1033 const std::string& reason) { | 1033 const std::string& reason) { |
1034 DCHECK_NE(FRESHLY_CONSTRUCTED, state_); | 1034 DCHECK_NE(FRESHLY_CONSTRUCTED, state_); |
1035 DCHECK_NE(CONNECTING, state_); | 1035 DCHECK_NE(CONNECTING, state_); |
1036 DCHECK_NE(CLOSED, state_); | 1036 DCHECK_NE(CLOSED, state_); |
1037 | 1037 |
1038 // TODO(ricea): Logging. | 1038 // TODO(ricea): Logging. |
1039 if (state_ == CONNECTED) { | 1039 if (state_ == CONNECTED) { |
1040 if (SendClose(code, reason) == CHANNEL_DELETED) | 1040 if (SendClose(code, reason) == CHANNEL_DELETED) |
1041 return CHANNEL_DELETED; | 1041 return CHANNEL_DELETED; |
1042 } | 1042 } |
1043 | 1043 |
1044 // Careful study of RFC6455 section 7.1.7 and 7.1.1 indicates the browser | 1044 // Careful study of RFC6455 section 7.1.7 and 7.1.1 indicates the browser |
1045 // should close the connection itself without waiting for the closing | 1045 // should close the connection itself without waiting for the closing |
1046 // handshake. | 1046 // handshake. |
1047 stream_->Close(); | 1047 stream_->Close(); |
1048 SetState(CLOSED); | 1048 SetState(CLOSED); |
1049 ChannelState result = event_interface_->OnFailChannel(message); | 1049 ChannelState result = event_interface_->OnFailChannel(message); |
1050 DCHECK_EQ(CHANNEL_DELETED, result); | 1050 DCHECK_EQ(CHANNEL_DELETED, result); |
1051 return result; | 1051 return result; |
1052 } | 1052 } |
1053 | 1053 |
1054 ChannelState WebSocketChannel::SendClose(uint16 code, | 1054 ChannelState WebSocketChannel::SendClose(uint16_t code, |
1055 const std::string& reason) { | 1055 const std::string& reason) { |
1056 DCHECK(state_ == CONNECTED || state_ == RECV_CLOSED); | 1056 DCHECK(state_ == CONNECTED || state_ == RECV_CLOSED); |
1057 DCHECK_LE(reason.size(), kMaximumCloseReasonLength); | 1057 DCHECK_LE(reason.size(), kMaximumCloseReasonLength); |
1058 scoped_refptr<IOBuffer> body; | 1058 scoped_refptr<IOBuffer> body; |
1059 uint64 size = 0; | 1059 uint64_t size = 0; |
1060 if (code == kWebSocketErrorNoStatusReceived) { | 1060 if (code == kWebSocketErrorNoStatusReceived) { |
1061 // Special case: translate kWebSocketErrorNoStatusReceived into a Close | 1061 // Special case: translate kWebSocketErrorNoStatusReceived into a Close |
1062 // frame with no payload. | 1062 // frame with no payload. |
1063 DCHECK(reason.empty()); | 1063 DCHECK(reason.empty()); |
1064 body = new IOBuffer(0); | 1064 body = new IOBuffer(0); |
1065 } else { | 1065 } else { |
1066 const size_t payload_length = kWebSocketCloseCodeLength + reason.length(); | 1066 const size_t payload_length = kWebSocketCloseCodeLength + reason.length(); |
1067 body = new IOBuffer(payload_length); | 1067 body = new IOBuffer(payload_length); |
1068 size = payload_length; | 1068 size = payload_length; |
1069 base::WriteBigEndian(body->data(), code); | 1069 base::WriteBigEndian(body->data(), code); |
1070 static_assert(sizeof(code) == kWebSocketCloseCodeLength, | 1070 static_assert(sizeof(code) == kWebSocketCloseCodeLength, |
1071 "they should both be two"); | 1071 "they should both be two"); |
1072 std::copy( | 1072 std::copy( |
1073 reason.begin(), reason.end(), body->data() + kWebSocketCloseCodeLength); | 1073 reason.begin(), reason.end(), body->data() + kWebSocketCloseCodeLength); |
1074 } | 1074 } |
1075 if (SendFrameFromIOBuffer( | 1075 if (SendFrameFromIOBuffer( |
1076 true, WebSocketFrameHeader::kOpCodeClose, body, size) == | 1076 true, WebSocketFrameHeader::kOpCodeClose, body, size) == |
1077 CHANNEL_DELETED) | 1077 CHANNEL_DELETED) |
1078 return CHANNEL_DELETED; | 1078 return CHANNEL_DELETED; |
1079 return CHANNEL_ALIVE; | 1079 return CHANNEL_ALIVE; |
1080 } | 1080 } |
1081 | 1081 |
1082 bool WebSocketChannel::ParseClose(const scoped_refptr<IOBuffer>& buffer, | 1082 bool WebSocketChannel::ParseClose(const scoped_refptr<IOBuffer>& buffer, |
1083 uint64 size, | 1083 uint64_t size, |
1084 uint16* code, | 1084 uint16_t* code, |
1085 std::string* reason, | 1085 std::string* reason, |
1086 std::string* message) { | 1086 std::string* message) { |
1087 reason->clear(); | 1087 reason->clear(); |
1088 if (size < kWebSocketCloseCodeLength) { | 1088 if (size < kWebSocketCloseCodeLength) { |
1089 if (size == 0U) { | 1089 if (size == 0U) { |
1090 *code = kWebSocketErrorNoStatusReceived; | 1090 *code = kWebSocketErrorNoStatusReceived; |
1091 return true; | 1091 return true; |
1092 } | 1092 } |
1093 | 1093 |
1094 DVLOG(1) << "Close frame with payload size " << size << " received " | 1094 DVLOG(1) << "Close frame with payload size " << size << " received " |
1095 << "(the first byte is " << std::hex | 1095 << "(the first byte is " << std::hex |
1096 << static_cast<int>(buffer->data()[0]) << ")"; | 1096 << static_cast<int>(buffer->data()[0]) << ")"; |
1097 *code = kWebSocketErrorProtocolError; | 1097 *code = kWebSocketErrorProtocolError; |
1098 *message = | 1098 *message = |
1099 "Received a broken close frame containing an invalid size body."; | 1099 "Received a broken close frame containing an invalid size body."; |
1100 return false; | 1100 return false; |
1101 } | 1101 } |
1102 | 1102 |
1103 const char* data = buffer->data(); | 1103 const char* data = buffer->data(); |
1104 uint16 unchecked_code = 0; | 1104 uint16_t unchecked_code = 0; |
1105 base::ReadBigEndian(data, &unchecked_code); | 1105 base::ReadBigEndian(data, &unchecked_code); |
1106 static_assert(sizeof(unchecked_code) == kWebSocketCloseCodeLength, | 1106 static_assert(sizeof(unchecked_code) == kWebSocketCloseCodeLength, |
1107 "they should both be two bytes"); | 1107 "they should both be two bytes"); |
1108 | 1108 |
1109 switch (unchecked_code) { | 1109 switch (unchecked_code) { |
1110 case kWebSocketErrorNoStatusReceived: | 1110 case kWebSocketErrorNoStatusReceived: |
1111 case kWebSocketErrorAbnormalClosure: | 1111 case kWebSocketErrorAbnormalClosure: |
1112 case kWebSocketErrorTlsHandshake: | 1112 case kWebSocketErrorTlsHandshake: |
1113 *code = kWebSocketErrorProtocolError; | 1113 *code = kWebSocketErrorProtocolError; |
1114 *message = | 1114 *message = |
(...skipping 11 matching lines...) Expand all Loading... |
1126 return true; | 1126 return true; |
1127 } | 1127 } |
1128 | 1128 |
1129 *code = kWebSocketErrorProtocolError; | 1129 *code = kWebSocketErrorProtocolError; |
1130 *reason = "Invalid UTF-8 in Close frame"; | 1130 *reason = "Invalid UTF-8 in Close frame"; |
1131 *message = "Received a broken close frame containing invalid UTF-8."; | 1131 *message = "Received a broken close frame containing invalid UTF-8."; |
1132 return false; | 1132 return false; |
1133 } | 1133 } |
1134 | 1134 |
1135 ChannelState WebSocketChannel::DoDropChannel(bool was_clean, | 1135 ChannelState WebSocketChannel::DoDropChannel(bool was_clean, |
1136 uint16 code, | 1136 uint16_t code, |
1137 const std::string& reason) { | 1137 const std::string& reason) { |
1138 if (CHANNEL_DELETED == | 1138 if (CHANNEL_DELETED == |
1139 notification_sender_->SendImmediately(event_interface_.get())) | 1139 notification_sender_->SendImmediately(event_interface_.get())) |
1140 return CHANNEL_DELETED; | 1140 return CHANNEL_DELETED; |
1141 ChannelState result = | 1141 ChannelState result = |
1142 event_interface_->OnDropChannel(was_clean, code, reason); | 1142 event_interface_->OnDropChannel(was_clean, code, reason); |
1143 DCHECK_EQ(CHANNEL_DELETED, result); | 1143 DCHECK_EQ(CHANNEL_DELETED, result); |
1144 return result; | 1144 return result; |
1145 } | 1145 } |
1146 | 1146 |
1147 void WebSocketChannel::CloseTimeout() { | 1147 void WebSocketChannel::CloseTimeout() { |
1148 stream_->Close(); | 1148 stream_->Close(); |
1149 SetState(CLOSED); | 1149 SetState(CLOSED); |
1150 DoDropChannel(false, kWebSocketErrorAbnormalClosure, ""); | 1150 DoDropChannel(false, kWebSocketErrorAbnormalClosure, ""); |
1151 // |this| has been deleted. | 1151 // |this| has been deleted. |
1152 } | 1152 } |
1153 | 1153 |
1154 } // namespace net | 1154 } // namespace net |
OLD | NEW |