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 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 |