Chromium Code Reviews| 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 <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/basictypes.h" // for size_t | 9 #include "base/basictypes.h" // for size_t |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| (...skipping 211 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 222 : event_interface_(event_interface.Pass()), | 222 : event_interface_(event_interface.Pass()), |
| 223 url_request_context_(url_request_context), | 223 url_request_context_(url_request_context), |
| 224 send_quota_low_water_mark_(kDefaultSendQuotaLowWaterMark), | 224 send_quota_low_water_mark_(kDefaultSendQuotaLowWaterMark), |
| 225 send_quota_high_water_mark_(kDefaultSendQuotaHighWaterMark), | 225 send_quota_high_water_mark_(kDefaultSendQuotaHighWaterMark), |
| 226 current_send_quota_(0), | 226 current_send_quota_(0), |
| 227 timeout_(base::TimeDelta::FromSeconds(kClosingHandshakeTimeoutSeconds)), | 227 timeout_(base::TimeDelta::FromSeconds(kClosingHandshakeTimeoutSeconds)), |
| 228 closing_code_(0), | 228 closing_code_(0), |
| 229 state_(FRESHLY_CONSTRUCTED), | 229 state_(FRESHLY_CONSTRUCTED), |
| 230 notification_sender_(new HandshakeNotificationSender(this)), | 230 notification_sender_(new HandshakeNotificationSender(this)), |
| 231 sending_text_message_(false), | 231 sending_text_message_(false), |
| 232 receiving_text_message_(false) {} | 232 receiving_text_message_(false), |
| 233 expecting_to_read_continuation_(false) {} | |
| 233 | 234 |
| 234 WebSocketChannel::~WebSocketChannel() { | 235 WebSocketChannel::~WebSocketChannel() { |
| 235 // The stream may hold a pointer to read_frames_, and so it needs to be | 236 // The stream may hold a pointer to read_frames_, and so it needs to be |
| 236 // destroyed first. | 237 // destroyed first. |
| 237 stream_.reset(); | 238 stream_.reset(); |
| 238 // The timer may have a callback pointing back to us, so stop it just in case | 239 // The timer may have a callback pointing back to us, so stop it just in case |
| 239 // someone decides to run the event loop from their destructor. | 240 // someone decides to run the event loop from their destructor. |
| 240 timer_.Stop(); | 241 timer_.Stop(); |
| 241 } | 242 } |
| 242 | 243 |
| (...skipping 415 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 658 default: | 659 default: |
| 659 frame_name = "Unknown frame type"; | 660 frame_name = "Unknown frame type"; |
| 660 break; | 661 break; |
| 661 } | 662 } |
| 662 // FailChannel() won't send another Close frame. | 663 // FailChannel() won't send another Close frame. |
| 663 return FailChannel( | 664 return FailChannel( |
| 664 frame_name + " received after close", kWebSocketErrorProtocolError, ""); | 665 frame_name + " received after close", kWebSocketErrorProtocolError, ""); |
| 665 } | 666 } |
| 666 switch (opcode) { | 667 switch (opcode) { |
| 667 case WebSocketFrameHeader::kOpCodeText: // fall-thru | 668 case WebSocketFrameHeader::kOpCodeText: // fall-thru |
| 668 case WebSocketFrameHeader::kOpCodeBinary: // fall-thru | 669 case WebSocketFrameHeader::kOpCodeBinary: |
| 670 if (expecting_to_read_continuation_) { | |
|
yhirano
2014/02/13 05:36:42
Shouldn't the received message be ignored when the
Adam Rice
2014/02/13 07:29:49
Yes, you are right. Done.
| |
| 671 return FailChannel( | |
| 672 "Received start of new message but previous message is unfinished.", | |
| 673 kWebSocketErrorProtocolError, | |
| 674 "Previous data frame unfinished"); | |
| 675 } | |
| 676 return HandleDataFrame(opcode, final, data_buffer, size); | |
| 677 | |
| 669 case WebSocketFrameHeader::kOpCodeContinuation: | 678 case WebSocketFrameHeader::kOpCodeContinuation: |
| 670 if (state_ == CONNECTED) { | 679 if (!expecting_to_read_continuation_) { |
|
yhirano
2014/02/13 05:36:42
ditto
Adam Rice
2014/02/13 07:29:49
Done.
| |
| 671 if (opcode == WebSocketFrameHeader::kOpCodeText || | 680 return FailChannel("Received unexpected continuation frame.", |
| 672 (opcode == WebSocketFrameHeader::kOpCodeContinuation && | 681 kWebSocketErrorProtocolError, |
| 673 receiving_text_message_)) { | 682 "Unexpected continuation"); |
| 674 // This call is not redundant when size == 0 because it tells us what | |
| 675 // the current state is. | |
| 676 StreamingUtf8Validator::State state = | |
| 677 incoming_utf8_validator_.AddBytes( | |
| 678 size ? data_buffer->data() : NULL, size); | |
| 679 if (state == StreamingUtf8Validator::INVALID || | |
| 680 (state == StreamingUtf8Validator::VALID_MIDPOINT && final)) { | |
| 681 return FailChannel("Could not decode a text frame as UTF-8.", | |
| 682 kWebSocketErrorProtocolError, | |
| 683 "Invalid UTF-8 in text frame"); | |
| 684 } | |
| 685 receiving_text_message_ = !final; | |
| 686 DCHECK(!final || state == StreamingUtf8Validator::VALID_ENDPOINT); | |
| 687 } | |
| 688 // TODO(ricea): Can this copy be eliminated? | |
| 689 const char* const data_begin = size ? data_buffer->data() : NULL; | |
| 690 const char* const data_end = data_begin + size; | |
| 691 const std::vector<char> data(data_begin, data_end); | |
| 692 // TODO(ricea): Handle the case when ReadFrames returns far | |
| 693 // more data at once than should be sent in a single IPC. This needs to | |
| 694 // be handled carefully, as an overloaded IO thread is one possible | |
| 695 // cause of receiving very large chunks. | |
| 696 | |
| 697 // Sends the received frame to the renderer process. | |
| 698 return event_interface_->OnDataFrame(final, opcode, data); | |
| 699 } | 683 } |
| 700 VLOG(3) << "Ignored data packet received in state " << state_; | 684 return HandleDataFrame(opcode, final, data_buffer, size); |
| 701 return CHANNEL_ALIVE; | |
| 702 | 685 |
| 703 case WebSocketFrameHeader::kOpCodePing: | 686 case WebSocketFrameHeader::kOpCodePing: |
| 704 VLOG(1) << "Got Ping of size " << size; | 687 VLOG(1) << "Got Ping of size " << size; |
| 705 if (state_ == CONNECTED) | 688 if (state_ == CONNECTED) |
| 706 return SendIOBuffer( | 689 return SendIOBuffer( |
| 707 true, WebSocketFrameHeader::kOpCodePong, data_buffer, size); | 690 true, WebSocketFrameHeader::kOpCodePong, data_buffer, size); |
| 708 VLOG(3) << "Ignored ping in state " << state_; | 691 VLOG(3) << "Ignored ping in state " << state_; |
| 709 return CHANNEL_ALIVE; | 692 return CHANNEL_ALIVE; |
| 710 | 693 |
| 711 case WebSocketFrameHeader::kOpCodePong: | 694 case WebSocketFrameHeader::kOpCodePong: |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 752 } | 735 } |
| 753 | 736 |
| 754 default: | 737 default: |
| 755 return FailChannel( | 738 return FailChannel( |
| 756 base::StringPrintf("Unrecognized frame opcode: %d", opcode), | 739 base::StringPrintf("Unrecognized frame opcode: %d", opcode), |
| 757 kWebSocketErrorProtocolError, | 740 kWebSocketErrorProtocolError, |
| 758 "Unknown opcode"); | 741 "Unknown opcode"); |
| 759 } | 742 } |
| 760 } | 743 } |
| 761 | 744 |
| 745 ChannelState WebSocketChannel::HandleDataFrame( | |
| 746 const WebSocketFrameHeader::OpCode opcode, | |
| 747 bool final, | |
| 748 const scoped_refptr<IOBuffer>& data_buffer, | |
| 749 size_t size) { | |
| 750 if (state_ != CONNECTED) { | |
| 751 DVLOG(3) << "Ignored data packet received in state " << state_; | |
| 752 return CHANNEL_ALIVE; | |
| 753 } | |
| 754 expecting_to_read_continuation_ = !final; | |
| 755 if (opcode == WebSocketFrameHeader::kOpCodeText || | |
| 756 (opcode == WebSocketFrameHeader::kOpCodeContinuation && | |
| 757 receiving_text_message_)) { | |
| 758 // This call is not redundant when size == 0 because it tells us what | |
| 759 // the current state is. | |
| 760 StreamingUtf8Validator::State state = incoming_utf8_validator_.AddBytes( | |
| 761 size ? data_buffer->data() : NULL, size); | |
| 762 if (state == StreamingUtf8Validator::INVALID || | |
| 763 (state == StreamingUtf8Validator::VALID_MIDPOINT && final)) { | |
| 764 return FailChannel("Could not decode a text frame as UTF-8.", | |
| 765 kWebSocketErrorProtocolError, | |
| 766 "Invalid UTF-8 in text frame"); | |
| 767 } | |
| 768 receiving_text_message_ = !final; | |
| 769 DCHECK(!final || state == StreamingUtf8Validator::VALID_ENDPOINT); | |
| 770 } | |
| 771 // TODO(ricea): Can this copy be eliminated? | |
| 772 const char* const data_begin = size ? data_buffer->data() : NULL; | |
| 773 const char* const data_end = data_begin + size; | |
| 774 const std::vector<char> data(data_begin, data_end); | |
| 775 // TODO(ricea): Handle the case when ReadFrames returns far | |
| 776 // more data at once than should be sent in a single IPC. This needs to | |
| 777 // be handled carefully, as an overloaded IO thread is one possible | |
| 778 // cause of receiving very large chunks. | |
| 779 | |
| 780 // Sends the received frame to the renderer process. | |
| 781 return event_interface_->OnDataFrame(final, opcode, data); | |
| 782 } | |
| 783 | |
| 762 ChannelState WebSocketChannel::SendIOBuffer( | 784 ChannelState WebSocketChannel::SendIOBuffer( |
| 763 bool fin, | 785 bool fin, |
| 764 WebSocketFrameHeader::OpCode op_code, | 786 WebSocketFrameHeader::OpCode op_code, |
| 765 const scoped_refptr<IOBuffer>& buffer, | 787 const scoped_refptr<IOBuffer>& buffer, |
| 766 size_t size) { | 788 size_t size) { |
| 767 DCHECK(state_ == CONNECTED || state_ == RECV_CLOSED); | 789 DCHECK(state_ == CONNECTED || state_ == RECV_CLOSED); |
| 768 DCHECK(stream_); | 790 DCHECK(stream_); |
| 769 scoped_ptr<WebSocketFrame> frame(new WebSocketFrame(op_code)); | 791 scoped_ptr<WebSocketFrame> frame(new WebSocketFrame(op_code)); |
| 770 WebSocketFrameHeader& header = frame->header; | 792 WebSocketFrameHeader& header = frame->header; |
| 771 header.final = fin; | 793 header.final = fin; |
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 907 | 929 |
| 908 void WebSocketChannel::CloseTimeout() { | 930 void WebSocketChannel::CloseTimeout() { |
| 909 stream_->Close(); | 931 stream_->Close(); |
| 910 DCHECK_NE(CLOSED, state_); | 932 DCHECK_NE(CLOSED, state_); |
| 911 state_ = CLOSED; | 933 state_ = CLOSED; |
| 912 AllowUnused(DoDropChannel(false, kWebSocketErrorAbnormalClosure, "")); | 934 AllowUnused(DoDropChannel(false, kWebSocketErrorAbnormalClosure, "")); |
| 913 // |this| has been deleted. | 935 // |this| has been deleted. |
| 914 } | 936 } |
| 915 | 937 |
| 916 } // namespace net | 938 } // namespace net |
| OLD | NEW |