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_handle_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: |
669 case WebSocketFrameHeader::kOpCodeContinuation: | 670 case WebSocketFrameHeader::kOpCodeContinuation: |
670 if (state_ == CONNECTED) { | 671 return HandleDataFrame(opcode, final, data_buffer, size); |
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 | 672 |
703 case WebSocketFrameHeader::kOpCodePing: | 673 case WebSocketFrameHeader::kOpCodePing: |
704 VLOG(1) << "Got Ping of size " << size; | 674 VLOG(1) << "Got Ping of size " << size; |
705 if (state_ == CONNECTED) | 675 if (state_ == CONNECTED) |
706 return SendIOBuffer( | 676 return SendIOBuffer( |
707 true, WebSocketFrameHeader::kOpCodePong, data_buffer, size); | 677 true, WebSocketFrameHeader::kOpCodePong, data_buffer, size); |
708 VLOG(3) << "Ignored ping in state " << state_; | 678 VLOG(3) << "Ignored ping in state " << state_; |
709 return CHANNEL_ALIVE; | 679 return CHANNEL_ALIVE; |
710 | 680 |
711 case WebSocketFrameHeader::kOpCodePong: | 681 case WebSocketFrameHeader::kOpCodePong: |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
752 } | 722 } |
753 | 723 |
754 default: | 724 default: |
755 return FailChannel( | 725 return FailChannel( |
756 base::StringPrintf("Unrecognized frame opcode: %d", opcode), | 726 base::StringPrintf("Unrecognized frame opcode: %d", opcode), |
757 kWebSocketErrorProtocolError, | 727 kWebSocketErrorProtocolError, |
758 "Unknown opcode"); | 728 "Unknown opcode"); |
759 } | 729 } |
760 } | 730 } |
761 | 731 |
| 732 ChannelState WebSocketChannel::HandleDataFrame( |
| 733 const WebSocketFrameHeader::OpCode opcode, |
| 734 bool final, |
| 735 const scoped_refptr<IOBuffer>& data_buffer, |
| 736 size_t size) { |
| 737 if (state_ != CONNECTED) { |
| 738 DVLOG(3) << "Ignored data packet received in state " << state_; |
| 739 return CHANNEL_ALIVE; |
| 740 } |
| 741 DCHECK(opcode == WebSocketFrameHeader::kOpCodeContinuation || |
| 742 opcode == WebSocketFrameHeader::kOpCodeText || |
| 743 opcode == WebSocketFrameHeader::kOpCodeBinary); |
| 744 const bool got_continuation = |
| 745 (opcode == WebSocketFrameHeader::kOpCodeContinuation); |
| 746 if (got_continuation != expecting_to_handle_continuation_) { |
| 747 const std::string console_log = got_continuation |
| 748 ? "Received unexpected continuation frame." |
| 749 : "Received start of new message but previous message is unfinished."; |
| 750 const std::string reason = got_continuation |
| 751 ? "Unexpected continuation" |
| 752 : "Previous data frame unfinished"; |
| 753 return FailChannel(console_log, kWebSocketErrorProtocolError, reason); |
| 754 } |
| 755 expecting_to_handle_continuation_ = !final; |
| 756 if (opcode == WebSocketFrameHeader::kOpCodeText || |
| 757 (opcode == WebSocketFrameHeader::kOpCodeContinuation && |
| 758 receiving_text_message_)) { |
| 759 // This call is not redundant when size == 0 because it tells us what |
| 760 // the current state is. |
| 761 StreamingUtf8Validator::State state = incoming_utf8_validator_.AddBytes( |
| 762 size ? data_buffer->data() : NULL, size); |
| 763 if (state == StreamingUtf8Validator::INVALID || |
| 764 (state == StreamingUtf8Validator::VALID_MIDPOINT && final)) { |
| 765 return FailChannel("Could not decode a text frame as UTF-8.", |
| 766 kWebSocketErrorProtocolError, |
| 767 "Invalid UTF-8 in text frame"); |
| 768 } |
| 769 receiving_text_message_ = !final; |
| 770 DCHECK(!final || state == StreamingUtf8Validator::VALID_ENDPOINT); |
| 771 } |
| 772 // TODO(ricea): Can this copy be eliminated? |
| 773 const char* const data_begin = size ? data_buffer->data() : NULL; |
| 774 const char* const data_end = data_begin + size; |
| 775 const std::vector<char> data(data_begin, data_end); |
| 776 // TODO(ricea): Handle the case when ReadFrames returns far |
| 777 // more data at once than should be sent in a single IPC. This needs to |
| 778 // be handled carefully, as an overloaded IO thread is one possible |
| 779 // cause of receiving very large chunks. |
| 780 |
| 781 // Sends the received frame to the renderer process. |
| 782 return event_interface_->OnDataFrame(final, opcode, data); |
| 783 } |
| 784 |
762 ChannelState WebSocketChannel::SendIOBuffer( | 785 ChannelState WebSocketChannel::SendIOBuffer( |
763 bool fin, | 786 bool fin, |
764 WebSocketFrameHeader::OpCode op_code, | 787 WebSocketFrameHeader::OpCode op_code, |
765 const scoped_refptr<IOBuffer>& buffer, | 788 const scoped_refptr<IOBuffer>& buffer, |
766 size_t size) { | 789 size_t size) { |
767 DCHECK(state_ == CONNECTED || state_ == RECV_CLOSED); | 790 DCHECK(state_ == CONNECTED || state_ == RECV_CLOSED); |
768 DCHECK(stream_); | 791 DCHECK(stream_); |
769 scoped_ptr<WebSocketFrame> frame(new WebSocketFrame(op_code)); | 792 scoped_ptr<WebSocketFrame> frame(new WebSocketFrame(op_code)); |
770 WebSocketFrameHeader& header = frame->header; | 793 WebSocketFrameHeader& header = frame->header; |
771 header.final = fin; | 794 header.final = fin; |
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
907 | 930 |
908 void WebSocketChannel::CloseTimeout() { | 931 void WebSocketChannel::CloseTimeout() { |
909 stream_->Close(); | 932 stream_->Close(); |
910 DCHECK_NE(CLOSED, state_); | 933 DCHECK_NE(CLOSED, state_); |
911 state_ = CLOSED; | 934 state_ = CLOSED; |
912 AllowUnused(DoDropChannel(false, kWebSocketErrorAbnormalClosure, "")); | 935 AllowUnused(DoDropChannel(false, kWebSocketErrorAbnormalClosure, "")); |
913 // |this| has been deleted. | 936 // |this| has been deleted. |
914 } | 937 } |
915 | 938 |
916 } // namespace net | 939 } // namespace net |
OLD | NEW |