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 return HandleDataFrame(opcode, final, data_buffer, size, false); | |
671 | |
669 case WebSocketFrameHeader::kOpCodeContinuation: | 672 case WebSocketFrameHeader::kOpCodeContinuation: |
670 if (state_ == CONNECTED) { | 673 return HandleDataFrame(opcode, final, data_buffer, size, true); |
671 if (opcode == WebSocketFrameHeader::kOpCodeText || | |
672 (opcode == WebSocketFrameHeader::kOpCodeContinuation && | |
673 receiving_text_message_)) { | |
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 } | |
700 VLOG(3) << "Ignored data packet received in state " << state_; | |
701 return CHANNEL_ALIVE; | |
702 | 674 |
703 case WebSocketFrameHeader::kOpCodePing: | 675 case WebSocketFrameHeader::kOpCodePing: |
704 VLOG(1) << "Got Ping of size " << size; | 676 VLOG(1) << "Got Ping of size " << size; |
705 if (state_ == CONNECTED) | 677 if (state_ == CONNECTED) |
706 return SendIOBuffer( | 678 return SendIOBuffer( |
707 true, WebSocketFrameHeader::kOpCodePong, data_buffer, size); | 679 true, WebSocketFrameHeader::kOpCodePong, data_buffer, size); |
708 VLOG(3) << "Ignored ping in state " << state_; | 680 VLOG(3) << "Ignored ping in state " << state_; |
709 return CHANNEL_ALIVE; | 681 return CHANNEL_ALIVE; |
710 | 682 |
711 case WebSocketFrameHeader::kOpCodePong: | 683 case WebSocketFrameHeader::kOpCodePong: |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
752 } | 724 } |
753 | 725 |
754 default: | 726 default: |
755 return FailChannel( | 727 return FailChannel( |
756 base::StringPrintf("Unrecognized frame opcode: %d", opcode), | 728 base::StringPrintf("Unrecognized frame opcode: %d", opcode), |
757 kWebSocketErrorProtocolError, | 729 kWebSocketErrorProtocolError, |
758 "Unknown opcode"); | 730 "Unknown opcode"); |
759 } | 731 } |
760 } | 732 } |
761 | 733 |
734 ChannelState WebSocketChannel::HandleDataFrame( | |
735 const WebSocketFrameHeader::OpCode opcode, | |
736 bool final, | |
737 const scoped_refptr<IOBuffer>& data_buffer, | |
738 size_t size, | |
739 bool expecting_continuation) { | |
740 if (state_ != CONNECTED) { | |
741 DVLOG(3) << "Ignored data packet received in state " << state_; | |
742 return CHANNEL_ALIVE; | |
743 } | |
744 if (expecting_continuation != expecting_to_read_continuation_) { | |
yhirano
2014/02/13 08:51:28
[opt] Just using |opcode| instead of |expecting_co
Adam Rice
2014/02/18 05:22:36
Yeah, this code is ugly. But I don't want to check
tyoshino (SeeGerritForStatus)
2014/02/18 06:24:12
In general, it's good to have exhaustive switch-ca
Adam Rice
2014/02/18 11:12:43
Is this what you mean?
| |
745 const bool got_continuation = !expecting_to_read_continuation_; | |
746 const std::string console_log = got_continuation | |
747 ? "Received unexpected continuation frame." | |
748 : "Received start of new message but previous message is unfinished."; | |
749 const std::string reason = got_continuation | |
750 ? "Unexpected continuation" | |
751 : "Previous data frame unfinished"; | |
752 return FailChannel(console_log, kWebSocketErrorProtocolError, reason); | |
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 |