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

Side by Side Diff: extensions/browser/api/cast_channel/cast_socket.cc

Issue 408633002: Fix error handling for message parse errors that occur during connection setup. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Merging in changes Created 6 years, 4 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 | « no previous file | extensions/browser/api/cast_channel/cast_socket_unittest.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 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 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 "extensions/browser/api/cast_channel/cast_socket.h" 5 #include "extensions/browser/api/cast_channel/cast_socket.h"
6 6
7 #include <stdlib.h> 7 #include <stdlib.h>
8 #include <string.h> 8 #include <string.h>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after
155 return false; 155 return false;
156 bool result = net::X509Certificate::GetDEREncoded( 156 bool result = net::X509Certificate::GetDEREncoded(
157 ssl_info.cert->os_cert_handle(), cert); 157 ssl_info.cert->os_cert_handle(), cert);
158 if (result) 158 if (result)
159 VLOG_WITH_CONNECTION(1) << "Successfully extracted peer certificate: " 159 VLOG_WITH_CONNECTION(1) << "Successfully extracted peer certificate: "
160 << *cert; 160 << *cert;
161 return result; 161 return result;
162 } 162 }
163 163
164 bool CastSocket::VerifyChallengeReply() { 164 bool CastSocket::VerifyChallengeReply() {
165 return AuthenticateChallengeReply(*challenge_reply_.get(), peer_cert_); 165 return AuthenticateChallengeReply(*challenge_reply_, peer_cert_);
166 } 166 }
167 167
168 void CastSocket::Connect(const net::CompletionCallback& callback) { 168 void CastSocket::Connect(const net::CompletionCallback& callback) {
169 DCHECK(CalledOnValidThread()); 169 DCHECK(CalledOnValidThread());
170 VLOG_WITH_CONNECTION(1) << "Connect readyState = " << ready_state_; 170 VLOG_WITH_CONNECTION(1) << "Connect readyState = " << ready_state_;
171 if (ready_state_ != READY_STATE_NONE) { 171 if (ready_state_ != READY_STATE_NONE) {
172 callback.Run(net::ERR_CONNECTION_FAILED); 172 callback.Run(net::ERR_CONNECTION_FAILED);
173 return; 173 return;
174 } 174 }
175 ready_state_ = READY_STATE_CONNECTING; 175 ready_state_ = READY_STATE_CONNECTING;
(...skipping 379 matching lines...) Expand 10 before | Expand all | Expand 10 after
555 rv = DoRead(); 555 rv = DoRead();
556 break; 556 break;
557 case READ_STATE_READ_COMPLETE: 557 case READ_STATE_READ_COMPLETE:
558 rv = DoReadComplete(rv); 558 rv = DoReadComplete(rv);
559 break; 559 break;
560 case READ_STATE_DO_CALLBACK: 560 case READ_STATE_DO_CALLBACK:
561 rv = DoReadCallback(); 561 rv = DoReadCallback();
562 break; 562 break;
563 case READ_STATE_ERROR: 563 case READ_STATE_ERROR:
564 rv = DoReadError(rv); 564 rv = DoReadError(rv);
565 DCHECK_EQ(read_state_, READ_STATE_NONE);
565 break; 566 break;
566 default: 567 default:
567 NOTREACHED() << "BUG in read flow. Unknown state: " << state; 568 NOTREACHED() << "BUG in read flow. Unknown state: " << state;
568 break; 569 break;
569 } 570 }
570 } while (rv != net::ERR_IO_PENDING && read_state_ != READ_STATE_NONE); 571 } while (rv != net::ERR_IO_PENDING && read_state_ != READ_STATE_NONE);
571 572
572 // Read loop is done - If the result is ERR_FAILED then close with error. 573 if (rv == net::ERR_FAILED) {
573 if (rv == net::ERR_FAILED) 574 if (ready_state_ == READY_STATE_CONNECTING) {
574 CloseWithError(error_state_); 575 // Read errors during the handshake should notify the caller via
576 // the connect callback, rather than the message event delegate.
577 PostTaskToStartConnectLoop(net::ERR_FAILED);
578 } else {
579 // Connection is already established.
580 // Close and send error status via the message event delegate.
581 CloseWithError(error_state_);
582 }
583 }
575 } 584 }
576 585
577 int CastSocket::DoRead() { 586 int CastSocket::DoRead() {
578 read_state_ = READ_STATE_READ_COMPLETE; 587 read_state_ = READ_STATE_READ_COMPLETE;
579 // Figure out whether to read header or body, and the remaining bytes. 588 // Figure out whether to read header or body, and the remaining bytes.
580 uint32 num_bytes_to_read = 0; 589 uint32 num_bytes_to_read = 0;
581 if (header_read_buffer_->RemainingCapacity() > 0) { 590 if (header_read_buffer_->RemainingCapacity() > 0) {
582 current_read_buffer_ = header_read_buffer_; 591 current_read_buffer_ = header_read_buffer_;
583 num_bytes_to_read = header_read_buffer_->RemainingCapacity(); 592 num_bytes_to_read = header_read_buffer_->RemainingCapacity();
584 DCHECK_LE(num_bytes_to_read, MessageHeader::header_size()); 593 CHECK_LE(num_bytes_to_read, MessageHeader::header_size());
585 } else { 594 } else {
586 DCHECK_GT(current_message_size_, 0U); 595 DCHECK_GT(current_message_size_, 0U);
587 num_bytes_to_read = current_message_size_ - body_read_buffer_->offset(); 596 num_bytes_to_read = current_message_size_ - body_read_buffer_->offset();
588 current_read_buffer_ = body_read_buffer_; 597 current_read_buffer_ = body_read_buffer_;
589 DCHECK_LE(num_bytes_to_read, MessageHeader::max_message_size()); 598 CHECK_LE(num_bytes_to_read, MessageHeader::max_message_size());
590 } 599 }
591 DCHECK_GT(num_bytes_to_read, 0U); 600 CHECK_GT(num_bytes_to_read, 0U);
592 601
593 // Read up to num_bytes_to_read into |current_read_buffer_|. 602 // Read up to num_bytes_to_read into |current_read_buffer_|.
594 return socket_->Read( 603 return socket_->Read(
595 current_read_buffer_.get(), 604 current_read_buffer_.get(),
596 num_bytes_to_read, 605 num_bytes_to_read,
597 base::Bind(&CastSocket::DoReadLoop, AsWeakPtr())); 606 base::Bind(&CastSocket::DoReadLoop, AsWeakPtr()));
598 } 607 }
599 608
600 int CastSocket::DoReadComplete(int result) { 609 int CastSocket::DoReadComplete(int result) {
601 VLOG_WITH_CONNECTION(2) << "DoReadComplete result = " << result 610 VLOG_WITH_CONNECTION(2) << "DoReadComplete result = " << result
602 << " header offset = " 611 << " header offset = "
603 << header_read_buffer_->offset() 612 << header_read_buffer_->offset()
604 << " body offset = " << body_read_buffer_->offset(); 613 << " body offset = " << body_read_buffer_->offset();
605 if (result <= 0) { // 0 means EOF: the peer closed the socket 614 if (result <= 0) { // 0 means EOF: the peer closed the socket
606 VLOG_WITH_CONNECTION(1) << "Read error, peer closed the socket"; 615 VLOG_WITH_CONNECTION(1) << "Read error, peer closed the socket";
607 error_state_ = CHANNEL_ERROR_SOCKET_ERROR; 616 error_state_ = CHANNEL_ERROR_SOCKET_ERROR;
608 read_state_ = READ_STATE_ERROR; 617 read_state_ = READ_STATE_ERROR;
609 return result == 0 ? net::ERR_FAILED : result; 618 return result == 0 ? net::ERR_FAILED : result;
610 } 619 }
611 620
612 // Some data was read. Move the offset in the current buffer forward. 621 // Some data was read. Move the offset in the current buffer forward.
613 DCHECK_LE(current_read_buffer_->offset() + result, 622 CHECK_LE(current_read_buffer_->offset() + result,
614 current_read_buffer_->capacity()); 623 current_read_buffer_->capacity());
615 current_read_buffer_->set_offset(current_read_buffer_->offset() + result); 624 current_read_buffer_->set_offset(current_read_buffer_->offset() + result);
616 read_state_ = READ_STATE_READ; 625 read_state_ = READ_STATE_READ;
617 626
618 if (current_read_buffer_.get() == header_read_buffer_.get() && 627 if (current_read_buffer_.get() == header_read_buffer_.get() &&
619 current_read_buffer_->RemainingCapacity() == 0) { 628 current_read_buffer_->RemainingCapacity() == 0) {
620 // A full header is read, process the contents. 629 // A full header is read, process the contents.
621 if (!ProcessHeader()) { 630 if (!ProcessHeader()) {
622 error_state_ = cast_channel::CHANNEL_ERROR_INVALID_MESSAGE; 631 error_state_ = cast_channel::CHANNEL_ERROR_INVALID_MESSAGE;
623 read_state_ = READ_STATE_ERROR; 632 read_state_ = READ_STATE_ERROR;
624 } 633 }
625 } else if (current_read_buffer_.get() == body_read_buffer_.get() && 634 } else if (current_read_buffer_.get() == body_read_buffer_.get() &&
626 static_cast<uint32>(current_read_buffer_->offset()) == 635 static_cast<uint32>(current_read_buffer_->offset()) ==
627 current_message_size_) { 636 current_message_size_) {
628 // Full body is read, process the contents. 637 // Full body is read, process the contents.
629 if (ProcessBody()) { 638 if (ProcessBody()) {
630 read_state_ = READ_STATE_DO_CALLBACK; 639 read_state_ = READ_STATE_DO_CALLBACK;
631 } else { 640 } else {
632 error_state_ = cast_channel::CHANNEL_ERROR_INVALID_MESSAGE; 641 error_state_ = cast_channel::CHANNEL_ERROR_INVALID_MESSAGE;
633 read_state_ = READ_STATE_ERROR; 642 read_state_ = READ_STATE_ERROR;
634 } 643 }
635 } 644 }
636 645
637 return net::OK; 646 return net::OK;
638 } 647 }
639 648
640 int CastSocket::DoReadCallback() { 649 int CastSocket::DoReadCallback() {
641 read_state_ = READ_STATE_READ; 650 read_state_ = READ_STATE_READ;
642 const CastMessage& message = *(current_message_.get()); 651 const CastMessage& message = *current_message_;
643 if (IsAuthMessage(message)) { 652 if (ready_state_ == READY_STATE_CONNECTING) {
644 // An auth message is received, check that connect flow is running. 653 if (IsAuthMessage(message)) {
645 if (ready_state_ == READY_STATE_CONNECTING) {
646 challenge_reply_.reset(new CastMessage(message)); 654 challenge_reply_.reset(new CastMessage(message));
647 PostTaskToStartConnectLoop(net::OK); 655 PostTaskToStartConnectLoop(net::OK);
656 return net::OK;
648 } else { 657 } else {
658 // Expected an auth message, got something else instead. Handle as error.
649 read_state_ = READ_STATE_ERROR; 659 read_state_ = READ_STATE_ERROR;
660 return net::ERR_INVALID_RESPONSE;
650 } 661 }
651 } else if (delegate_) {
652 MessageInfo message_info;
653 if (CastMessageToMessageInfo(message, &message_info))
654 delegate_->OnMessage(this, message_info);
655 else
656 read_state_ = READ_STATE_ERROR;
657 } 662 }
663
664 MessageInfo message_info;
665 if (!CastMessageToMessageInfo(message, &message_info)) {
666 current_message_->Clear();
667 read_state_ = READ_STATE_ERROR;
668 return net::ERR_INVALID_RESPONSE;
669 }
670 delegate_->OnMessage(this, message_info);
658 current_message_->Clear(); 671 current_message_->Clear();
659 return net::OK; 672 return net::OK;
660 } 673 }
661 674
662 int CastSocket::DoReadError(int result) { 675 int CastSocket::DoReadError(int result) {
663 DCHECK_LE(result, 0); 676 DCHECK_LE(result, 0);
664 // If inside connection flow, then get back to connect loop.
665 if (ready_state_ == READY_STATE_CONNECTING) {
666 PostTaskToStartConnectLoop(result);
667 // does not try to report error also.
668 return net::OK;
669 }
670 return net::ERR_FAILED; 677 return net::ERR_FAILED;
671 } 678 }
672 679
673 bool CastSocket::ProcessHeader() { 680 bool CastSocket::ProcessHeader() {
674 DCHECK_EQ(static_cast<uint32>(header_read_buffer_->offset()), 681 CHECK_EQ(static_cast<uint32>(header_read_buffer_->offset()),
675 MessageHeader::header_size()); 682 MessageHeader::header_size());
676 MessageHeader header; 683 MessageHeader header;
677 MessageHeader::ReadFromIOBuffer(header_read_buffer_.get(), &header); 684 MessageHeader::ReadFromIOBuffer(header_read_buffer_.get(), &header);
678 if (header.message_size > MessageHeader::max_message_size()) 685 if (header.message_size > MessageHeader::max_message_size())
679 return false; 686 return false;
680 687
681 VLOG_WITH_CONNECTION(2) << "Parsed header { message_size: " 688 VLOG_WITH_CONNECTION(2) << "Parsed header { message_size: "
682 << header.message_size << " }"; 689 << header.message_size << " }";
683 current_message_size_ = header.message_size; 690 current_message_size_ = header.message_size;
684 return true; 691 return true;
685 } 692 }
686 693
687 bool CastSocket::ProcessBody() { 694 bool CastSocket::ProcessBody() {
688 DCHECK_EQ(static_cast<uint32>(body_read_buffer_->offset()), 695 CHECK_EQ(static_cast<uint32>(body_read_buffer_->offset()),
689 current_message_size_); 696 current_message_size_);
690 if (!current_message_->ParseFromArray( 697 if (!current_message_->ParseFromArray(
691 body_read_buffer_->StartOfBuffer(), current_message_size_)) { 698 body_read_buffer_->StartOfBuffer(), current_message_size_)) {
692 return false; 699 return false;
693 } 700 }
694 current_message_size_ = 0; 701 current_message_size_ = 0;
695 header_read_buffer_->set_offset(0); 702 header_read_buffer_->set_offset(0);
696 body_read_buffer_->set_offset(0); 703 body_read_buffer_->set_offset(0);
697 current_read_buffer_ = header_read_buffer_; 704 current_read_buffer_ = header_read_buffer_;
698 return true; 705 return true;
699 } 706 }
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
734 741
735 base::Timer* CastSocket::GetTimer() { 742 base::Timer* CastSocket::GetTimer() {
736 return connect_timeout_timer_.get(); 743 return connect_timeout_timer_.get();
737 } 744 }
738 745
739 CastSocket::MessageHeader::MessageHeader() : message_size(0) { } 746 CastSocket::MessageHeader::MessageHeader() : message_size(0) { }
740 747
741 void CastSocket::MessageHeader::SetMessageSize(size_t size) { 748 void CastSocket::MessageHeader::SetMessageSize(size_t size) {
742 DCHECK_LT(size, static_cast<size_t>(kuint32max)); 749 DCHECK_LT(size, static_cast<size_t>(kuint32max));
743 DCHECK_GT(size, 0U); 750 DCHECK_GT(size, 0U);
744 message_size = static_cast<size_t>(size); 751 message_size = size;
745 } 752 }
746 753
747 // TODO(mfoltz): Investigate replacing header serialization with base::Pickle, 754 // TODO(mfoltz): Investigate replacing header serialization with base::Pickle,
748 // if bit-for-bit compatible. 755 // if bit-for-bit compatible.
749 void CastSocket::MessageHeader::PrependToString(std::string* str) { 756 void CastSocket::MessageHeader::PrependToString(std::string* str) {
750 MessageHeader output = *this; 757 MessageHeader output = *this;
751 output.message_size = base::HostToNet32(message_size); 758 output.message_size = base::HostToNet32(message_size);
752 size_t header_size = base::checked_cast<size_t,uint32>( 759 size_t header_size = base::checked_cast<size_t,uint32>(
753 MessageHeader::header_size()); 760 MessageHeader::header_size());
754 scoped_ptr<char, base::FreeDeleter> char_array( 761 scoped_ptr<char, base::FreeDeleter> char_array(
(...skipping 30 matching lines...) Expand all
785 return true; 792 return true;
786 } 793 }
787 794
788 CastSocket::WriteRequest::~WriteRequest() { } 795 CastSocket::WriteRequest::~WriteRequest() { }
789 796
790 } // namespace cast_channel 797 } // namespace cast_channel
791 } // namespace core_api 798 } // namespace core_api
792 } // namespace extensions 799 } // namespace extensions
793 800
794 #undef VLOG_WITH_CONNECTION 801 #undef VLOG_WITH_CONNECTION
OLDNEW
« no previous file with comments | « no previous file | extensions/browser/api/cast_channel/cast_socket_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698