Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(91)

Side by Side Diff: net/websockets/websocket_channel.cc

Issue 157033013: Check for invalid use of data frame opcodes. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Move continuation checking into HandleDataFrame. Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698