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

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: Remove |expecting_continuation| parameter from 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
« no previous file with comments | « net/websockets/websocket_channel.h ('k') | net/websockets/websocket_channel_test.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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_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
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
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
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
OLDNEW
« no previous file with comments | « net/websockets/websocket_channel.h ('k') | net/websockets/websocket_channel_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698