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

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

Issue 26544003: Make net::WebSocketChannel deletion safe and enable new IPCs (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Add missing "virtual" keyword Created 7 years, 2 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 <string.h> 7 #include <string.h>
8 8
9 #include <iostream> 9 #include <iostream>
10 #include <string> 10 #include <string>
11 #include <vector> 11 #include <vector>
12 12
13 #include "base/bind.h" 13 #include "base/bind.h"
14 #include "base/bind_helpers.h" 14 #include "base/bind_helpers.h"
15 #include "base/callback.h" 15 #include "base/callback.h"
16 #include "base/location.h" 16 #include "base/location.h"
17 #include "base/memory/scoped_ptr.h" 17 #include "base/memory/scoped_ptr.h"
18 #include "base/memory/scoped_vector.h" 18 #include "base/memory/scoped_vector.h"
19 #include "base/memory/weak_ptr.h"
19 #include "base/message_loop/message_loop.h" 20 #include "base/message_loop/message_loop.h"
20 #include "base/safe_numerics.h" 21 #include "base/safe_numerics.h"
21 #include "base/strings/string_piece.h" 22 #include "base/strings/string_piece.h"
22 #include "net/base/net_errors.h" 23 #include "net/base/net_errors.h"
23 #include "net/url_request/url_request_context.h" 24 #include "net/url_request/url_request_context.h"
24 #include "net/websockets/websocket_errors.h" 25 #include "net/websockets/websocket_errors.h"
25 #include "net/websockets/websocket_event_interface.h" 26 #include "net/websockets/websocket_event_interface.h"
26 #include "net/websockets/websocket_mux.h" 27 #include "net/websockets/websocket_mux.h"
27 #include "testing/gmock/include/gmock/gmock.h" 28 #include "testing/gmock/include/gmock/gmock.h"
28 #include "testing/gtest/include/gtest/gtest.h" 29 #include "testing/gtest/include/gtest/gtest.h"
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
78 } 79 }
79 80
80 std::ostream& operator<<(std::ostream& os, 81 std::ostream& operator<<(std::ostream& os,
81 const ScopedVector<WebSocketFrame>* vector) { 82 const ScopedVector<WebSocketFrame>* vector) {
82 return os << '&' << *vector; 83 return os << '&' << *vector;
83 } 84 }
84 85
85 namespace { 86 namespace {
86 87
87 using ::testing::AnyNumber; 88 using ::testing::AnyNumber;
89 using ::testing::DefaultValue;
88 using ::testing::InSequence; 90 using ::testing::InSequence;
89 using ::testing::MockFunction; 91 using ::testing::MockFunction;
90 using ::testing::Return; 92 using ::testing::Return;
91 using ::testing::SaveArg; 93 using ::testing::SaveArg;
92 using ::testing::StrictMock; 94 using ::testing::StrictMock;
93 using ::testing::_; 95 using ::testing::_;
94 96
95 // A selection of characters that have traditionally been mangled in some 97 // A selection of characters that have traditionally been mangled in some
96 // environment or other, for testing 8-bit cleanliness. 98 // environment or other, for testing 8-bit cleanliness.
97 const char kBinaryBlob[] = {'\n', '\r', // BACKWARDS CRNL 99 const char kBinaryBlob[] = {'\n', '\r', // BACKWARDS CRNL
(...skipping 11 matching lines...) Expand all
109 111
110 // The amount of quota a new connection gets by default. 112 // The amount of quota a new connection gets by default.
111 // TODO(ricea): If kDefaultSendQuotaHighWaterMark changes, then this value will 113 // TODO(ricea): If kDefaultSendQuotaHighWaterMark changes, then this value will
112 // need to be updated. 114 // need to be updated.
113 const size_t kDefaultInitialQuota = 1 << 17; 115 const size_t kDefaultInitialQuota = 1 << 17;
114 // The amount of bytes we need to send after the initial connection to trigger a 116 // The amount of bytes we need to send after the initial connection to trigger a
115 // quota refresh. TODO(ricea): Change this if kDefaultSendQuotaHighWaterMark or 117 // quota refresh. TODO(ricea): Change this if kDefaultSendQuotaHighWaterMark or
116 // kDefaultSendQuotaLowWaterMark change. 118 // kDefaultSendQuotaLowWaterMark change.
117 const size_t kDefaultQuotaRefreshTrigger = (1 << 16) + 1; 119 const size_t kDefaultQuotaRefreshTrigger = (1 << 16) + 1;
118 120
121 typedef WebSocketEventInterface::ChannelState ChannelState;
122 const ChannelState CHANNEL_ALIVE = WebSocketEventInterface::CHANNEL_ALIVE;
123 const ChannelState CHANNEL_DELETED = WebSocketEventInterface::CHANNEL_DELETED;
124
125 // This typedef mainly exists to avoid having to repeat the "NOLINT" incantation
126 // all over the place.
127 typedef MockFunction<void(int)> Checkpoint; // NOLINT
128
119 // This mock is for testing expectations about how the EventInterface is used. 129 // This mock is for testing expectations about how the EventInterface is used.
120 class MockWebSocketEventInterface : public WebSocketEventInterface { 130 class MockWebSocketEventInterface : public WebSocketEventInterface {
121 public: 131 public:
122 MOCK_METHOD2(OnAddChannelResponse, void(bool, const std::string&)); 132 MOCK_METHOD2(OnAddChannelResponse,
133 ChannelState(bool, const std::string&)); // NOLINT
123 MOCK_METHOD3(OnDataFrame, 134 MOCK_METHOD3(OnDataFrame,
124 void(bool, WebSocketMessageType, const std::vector<char>&)); 135 ChannelState(bool,
125 MOCK_METHOD1(OnFlowControl, void(int64)); 136 WebSocketMessageType,
126 MOCK_METHOD0(OnClosingHandshake, void(void)); 137 const std::vector<char>&)); // NOLINT
127 MOCK_METHOD2(OnDropChannel, void(uint16, const std::string&)); 138 MOCK_METHOD1(OnFlowControl, ChannelState(int64)); // NOLINT
139 MOCK_METHOD0(OnClosingHandshake, ChannelState(void)); // NOLINT
140 MOCK_METHOD2(OnDropChannel,
141 ChannelState(uint16, const std::string&)); // NOLINT
128 }; 142 };
129 143
130 // This fake EventInterface is for tests which need a WebSocketEventInterface 144 // This fake EventInterface is for tests which need a WebSocketEventInterface
131 // implementation but are not verifying how it is used. 145 // implementation but are not verifying how it is used.
132 class FakeWebSocketEventInterface : public WebSocketEventInterface { 146 class FakeWebSocketEventInterface : public WebSocketEventInterface {
133 virtual void OnAddChannelResponse( 147 virtual ChannelState OnAddChannelResponse(
134 bool fail, 148 bool fail,
135 const std::string& selected_protocol) OVERRIDE {} 149 const std::string& selected_protocol) OVERRIDE {
136 virtual void OnDataFrame(bool fin, 150 return fail ? CHANNEL_DELETED : CHANNEL_ALIVE;
137 WebSocketMessageType type, 151 }
138 const std::vector<char>& data) OVERRIDE {} 152 virtual ChannelState OnDataFrame(bool fin,
139 virtual void OnFlowControl(int64 quota) OVERRIDE {} 153 WebSocketMessageType type,
140 virtual void OnClosingHandshake() OVERRIDE {} 154 const std::vector<char>& data) OVERRIDE {
141 virtual void OnDropChannel(uint16 code, const std::string& reason) OVERRIDE {} 155 return CHANNEL_ALIVE;
156 }
157 virtual ChannelState OnFlowControl(int64 quota) OVERRIDE {
158 return CHANNEL_ALIVE;
159 }
160 virtual ChannelState OnClosingHandshake() OVERRIDE { return CHANNEL_ALIVE; }
161 virtual ChannelState OnDropChannel(uint16 code,
162 const std::string& reason) OVERRIDE {
163 return CHANNEL_DELETED;
164 }
142 }; 165 };
143 166
144 // This fake WebSocketStream is for tests that require a WebSocketStream but are 167 // This fake WebSocketStream is for tests that require a WebSocketStream but are
145 // not testing the way it is used. It has minimal functionality to return 168 // not testing the way it is used. It has minimal functionality to return
146 // the |protocol| and |extensions| that it was constructed with. 169 // the |protocol| and |extensions| that it was constructed with.
147 class FakeWebSocketStream : public WebSocketStream { 170 class FakeWebSocketStream : public WebSocketStream {
148 public: 171 public:
149 // Constructs with empty protocol and extensions. 172 // Constructs with empty protocol and extensions.
150 FakeWebSocketStream() {} 173 FakeWebSocketStream() {}
151 174
(...skipping 390 matching lines...) Expand 10 before | Expand all | Expand 10 after
542 CompletionCallback read_callback_; 565 CompletionCallback read_callback_;
543 // Owned by the caller of ReadFrames(). 566 // Owned by the caller of ReadFrames().
544 ScopedVector<WebSocketFrame>* read_frames_; 567 ScopedVector<WebSocketFrame>* read_frames_;
545 // True if we should close the connection. 568 // True if we should close the connection.
546 bool done_; 569 bool done_;
547 }; 570 };
548 571
549 // A FakeWebSocketStream where writes trigger a connection reset. 572 // A FakeWebSocketStream where writes trigger a connection reset.
550 // This differs from UnWriteableFakeWebSocketStream in that it is asynchronous 573 // This differs from UnWriteableFakeWebSocketStream in that it is asynchronous
551 // and triggers ReadFrames to return a reset as well. Tests using this need to 574 // and triggers ReadFrames to return a reset as well. Tests using this need to
552 // run the message loop. 575 // run the message loop. There are two tricky parts here:
576 // 1. Calling the write callback may call Close(), after which the read callback
577 // should not be called.
578 // 2. Calling either callback may delete the stream altogether.
553 class ResetOnWriteFakeWebSocketStream : public FakeWebSocketStream { 579 class ResetOnWriteFakeWebSocketStream : public FakeWebSocketStream {
554 public: 580 public:
581 ResetOnWriteFakeWebSocketStream() : closed_(false), weak_ptr_factory_(this) {}
582
555 virtual int WriteFrames(ScopedVector<WebSocketFrame>* frames, 583 virtual int WriteFrames(ScopedVector<WebSocketFrame>* frames,
556 const CompletionCallback& callback) OVERRIDE { 584 const CompletionCallback& callback) OVERRIDE {
557 base::MessageLoop::current()->PostTask( 585 base::MessageLoop::current()->PostTask(
558 FROM_HERE, base::Bind(callback, ERR_CONNECTION_RESET)); 586 FROM_HERE,
587 base::Bind(&ResetOnWriteFakeWebSocketStream::CallCallbackUnlessClosed,
588 weak_ptr_factory_.GetWeakPtr(),
589 callback,
590 ERR_CONNECTION_RESET));
559 base::MessageLoop::current()->PostTask( 591 base::MessageLoop::current()->PostTask(
560 FROM_HERE, base::Bind(read_callback_, ERR_CONNECTION_RESET)); 592 FROM_HERE,
593 base::Bind(&ResetOnWriteFakeWebSocketStream::CallCallbackUnlessClosed,
594 weak_ptr_factory_.GetWeakPtr(),
595 read_callback_,
596 ERR_CONNECTION_RESET));
561 return ERR_IO_PENDING; 597 return ERR_IO_PENDING;
562 } 598 }
563 599
564 virtual int ReadFrames(ScopedVector<WebSocketFrame>* frames, 600 virtual int ReadFrames(ScopedVector<WebSocketFrame>* frames,
565 const CompletionCallback& callback) OVERRIDE { 601 const CompletionCallback& callback) OVERRIDE {
566 read_callback_ = callback; 602 read_callback_ = callback;
567 return ERR_IO_PENDING; 603 return ERR_IO_PENDING;
568 } 604 }
569 605
606 virtual void Close() OVERRIDE { closed_ = true; }
607
570 private: 608 private:
609 void CallCallbackUnlessClosed(const CompletionCallback& callback, int value) {
610 if (!closed_)
611 callback.Run(value);
612 }
613
571 CompletionCallback read_callback_; 614 CompletionCallback read_callback_;
615 bool closed_;
616 // An IO error can result in the socket being deleted, so we use weak pointers
617 // to ensure correct behaviour in that case.
618 base::WeakPtrFactory<ResetOnWriteFakeWebSocketStream> weak_ptr_factory_;
572 }; 619 };
573 620
574 // This mock is for verifying that WebSocket protocol semantics are obeyed (to 621 // This mock is for verifying that WebSocket protocol semantics are obeyed (to
575 // the extent that they are implemented in WebSocketCommon). 622 // the extent that they are implemented in WebSocketCommon).
576 class MockWebSocketStream : public WebSocketStream { 623 class MockWebSocketStream : public WebSocketStream {
577 public: 624 public:
578 MOCK_METHOD2(ReadFrames, 625 MOCK_METHOD2(ReadFrames,
579 int(ScopedVector<WebSocketFrame>* frames, 626 int(ScopedVector<WebSocketFrame>* frames,
580 const CompletionCallback& callback)); 627 const CompletionCallback& callback));
581 MOCK_METHOD2(WriteFrames, 628 MOCK_METHOD2(WriteFrames,
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
686 }; 733 };
687 ConnectData connect_data_; 734 ConnectData connect_data_;
688 735
689 // The channel we are testing. Not initialised until SetChannel() is called. 736 // The channel we are testing. Not initialised until SetChannel() is called.
690 scoped_ptr<WebSocketChannel> channel_; 737 scoped_ptr<WebSocketChannel> channel_;
691 738
692 // A mock or fake stream for tests that need one. 739 // A mock or fake stream for tests that need one.
693 scoped_ptr<WebSocketStream> stream_; 740 scoped_ptr<WebSocketStream> stream_;
694 }; 741 };
695 742
743 // enum of WebSocketEventInterface calls. These are intended to be or'd together
744 // in order to instruct WebSocketChannelDeletingTest when it should fail.
745 enum EventInterfaceCall {
746 EVENT_ON_ADD_CHANNEL_RESPONSE = 0x1,
747 EVENT_ON_DATA_FRAME = 0x2,
748 EVENT_ON_FLOW_CONTROL = 0x4,
749 EVENT_ON_CLOSING_HANDSHAKE = 0x8,
750 EVENT_ON_DROP_CHANNEL = 0x10,
751 };
752
696 class WebSocketChannelDeletingTest : public WebSocketChannelTest { 753 class WebSocketChannelDeletingTest : public WebSocketChannelTest {
697 public: 754 public:
698 void ResetChannel() { channel_.reset(); } 755 ChannelState DeleteIfDeleting(EventInterfaceCall call) {
756 if (deleting_ & call) {
757 channel_.reset();
758 return CHANNEL_DELETED;
759 } else {
760 return CHANNEL_ALIVE;
761 }
762 }
699 763
700 protected: 764 protected:
765 WebSocketChannelDeletingTest()
766 : deleting_(EVENT_ON_ADD_CHANNEL_RESPONSE | EVENT_ON_DATA_FRAME |
767 EVENT_ON_FLOW_CONTROL |
768 EVENT_ON_CLOSING_HANDSHAKE |
769 EVENT_ON_DROP_CHANNEL) {}
701 // Create a ChannelDeletingFakeWebSocketEventInterface. Defined out-of-line to 770 // Create a ChannelDeletingFakeWebSocketEventInterface. Defined out-of-line to
702 // avoid circular dependency. 771 // avoid circular dependency.
703 virtual scoped_ptr<WebSocketEventInterface> CreateEventInterface() OVERRIDE; 772 virtual scoped_ptr<WebSocketEventInterface> CreateEventInterface() OVERRIDE;
773
774 // Tests can set deleting_ to a bitmap of EventInterfaceCall members that they
775 // want to cause Channel deletion. The default is for all calls to cause
776 // deletion.
777 int deleting_;
704 }; 778 };
705 779
706 // A FakeWebSocketEventInterface that deletes the WebSocketChannel on failure to 780 // A FakeWebSocketEventInterface that deletes the WebSocketChannel on failure to
707 // connect. 781 // connect.
708 class ChannelDeletingFakeWebSocketEventInterface 782 class ChannelDeletingFakeWebSocketEventInterface
709 : public FakeWebSocketEventInterface { 783 : public FakeWebSocketEventInterface {
710 public: 784 public:
711 ChannelDeletingFakeWebSocketEventInterface( 785 ChannelDeletingFakeWebSocketEventInterface(
712 WebSocketChannelDeletingTest* fixture) 786 WebSocketChannelDeletingTest* fixture)
713 : fixture_(fixture) {} 787 : fixture_(fixture) {}
714 788
715 virtual void OnAddChannelResponse( 789 virtual ChannelState OnAddChannelResponse(
716 bool fail, 790 bool fail,
717 const std::string& selected_protocol) OVERRIDE { 791 const std::string& selected_protocol) OVERRIDE {
718 if (fail) { 792 return fixture_->DeleteIfDeleting(EVENT_ON_ADD_CHANNEL_RESPONSE);
719 fixture_->ResetChannel(); 793 }
720 } 794
795 virtual ChannelState OnDataFrame(bool fin,
796 WebSocketMessageType type,
797 const std::vector<char>& data) OVERRIDE {
798 return fixture_->DeleteIfDeleting(EVENT_ON_DATA_FRAME);
799 }
800
801 virtual ChannelState OnFlowControl(int64 quota) OVERRIDE {
802 return fixture_->DeleteIfDeleting(EVENT_ON_FLOW_CONTROL);
803 }
804
805 virtual ChannelState OnClosingHandshake() OVERRIDE {
806 return fixture_->DeleteIfDeleting(EVENT_ON_CLOSING_HANDSHAKE);
807 }
808
809 virtual ChannelState OnDropChannel(uint16 code,
810 const std::string& reason) OVERRIDE {
811 return fixture_->DeleteIfDeleting(EVENT_ON_DROP_CHANNEL);
721 } 812 }
722 813
723 private: 814 private:
724 // A pointer to the test fixture. Owned by the test harness; this object will 815 // A pointer to the test fixture. Owned by the test harness; this object will
725 // be deleted before it is. 816 // be deleted before it is.
726 WebSocketChannelDeletingTest* fixture_; 817 WebSocketChannelDeletingTest* fixture_;
727 }; 818 };
728 819
729 scoped_ptr<WebSocketEventInterface> 820 scoped_ptr<WebSocketEventInterface>
730 WebSocketChannelDeletingTest::CreateEventInterface() { 821 WebSocketChannelDeletingTest::CreateEventInterface() {
731 return scoped_ptr<WebSocketEventInterface>( 822 return scoped_ptr<WebSocketEventInterface>(
732 new ChannelDeletingFakeWebSocketEventInterface(this)); 823 new ChannelDeletingFakeWebSocketEventInterface(this));
733 } 824 }
734 825
735 // Base class for tests which verify that EventInterface methods are called 826 // Base class for tests which verify that EventInterface methods are called
736 // appropriately. 827 // appropriately.
737 class WebSocketChannelEventInterfaceTest : public WebSocketChannelTest { 828 class WebSocketChannelEventInterfaceTest : public WebSocketChannelTest {
738 protected: 829 protected:
739 WebSocketChannelEventInterfaceTest() 830 WebSocketChannelEventInterfaceTest()
740 : event_interface_(new StrictMock<MockWebSocketEventInterface>) {} 831 : event_interface_(new StrictMock<MockWebSocketEventInterface>) {
832 DefaultValue<ChannelState>::Set(CHANNEL_ALIVE);
833 ON_CALL(*event_interface_, OnAddChannelResponse(true, _))
834 .WillByDefault(Return(CHANNEL_DELETED));
835 ON_CALL(*event_interface_, OnDropChannel(_, _))
836 .WillByDefault(Return(CHANNEL_DELETED));
837 }
838
839 virtual ~WebSocketChannelEventInterfaceTest() {
840 DefaultValue<ChannelState>::Clear();
841 }
741 842
742 // Tests using this fixture must set expectations on the event_interface_ mock 843 // Tests using this fixture must set expectations on the event_interface_ mock
743 // object before calling CreateChannelAndConnect() or 844 // object before calling CreateChannelAndConnect() or
744 // CreateChannelAndConnectSuccessfully(). This will only work once per test 845 // CreateChannelAndConnectSuccessfully(). This will only work once per test
745 // case, but once should be enough. 846 // case, but once should be enough.
746 virtual scoped_ptr<WebSocketEventInterface> CreateEventInterface() OVERRIDE { 847 virtual scoped_ptr<WebSocketEventInterface> CreateEventInterface() OVERRIDE {
747 return scoped_ptr<WebSocketEventInterface>(event_interface_.release()); 848 return scoped_ptr<WebSocketEventInterface>(event_interface_.release());
748 } 849 }
749 850
750 scoped_ptr<MockWebSocketEventInterface> event_interface_; 851 scoped_ptr<MockWebSocketEventInterface> event_interface_;
(...skipping 27 matching lines...) Expand all
778 connect_data_.factory; 879 connect_data_.factory;
779 880
780 EXPECT_EQ(&connect_data_.url_request_context, actual.url_request_context); 881 EXPECT_EQ(&connect_data_.url_request_context, actual.url_request_context);
781 882
782 EXPECT_EQ(connect_data_.socket_url, actual.socket_url); 883 EXPECT_EQ(connect_data_.socket_url, actual.socket_url);
783 EXPECT_EQ(connect_data_.requested_subprotocols, 884 EXPECT_EQ(connect_data_.requested_subprotocols,
784 actual.requested_subprotocols); 885 actual.requested_subprotocols);
785 EXPECT_EQ(connect_data_.origin, actual.origin); 886 EXPECT_EQ(connect_data_.origin, actual.origin);
786 } 887 }
787 888
788 // The documentation for WebSocketEventInterface::OnAddChannelResponse() says 889 // Any WebSocketEventInterface methods can delete the WebSocketChannel and
789 // that if the first argument is true, ie. the connection failed, then we can 890 // return CHANNEL_DELETED. The WebSocketChannelDeletingTests are intended to
790 // safely synchronously delete the WebSocketChannel. This test will only 891 // verify that there are no use-after-free bugs when this happens. Problems will
791 // reliably find problems if run with a memory debugger such as 892 // probably only be found when running under Address Sanitizer or a similar
792 // AddressSanitizer. 893 // tool.
793 TEST_F(WebSocketChannelDeletingTest, DeletingFromOnAddChannelResponseWorks) { 894 TEST_F(WebSocketChannelDeletingTest, OnAddChannelResponseFail) {
794 CreateChannelAndConnect(); 895 CreateChannelAndConnect();
896 EXPECT_TRUE(channel_);
795 connect_data_.factory.connect_delegate->OnFailure( 897 connect_data_.factory.connect_delegate->OnFailure(
796 kWebSocketErrorNoStatusReceived); 898 kWebSocketErrorNoStatusReceived);
797 EXPECT_EQ(NULL, channel_.get()); 899 EXPECT_EQ(NULL, channel_.get());
798 } 900 }
799 901
902 // Deletion is possible (due to IPC failure) even if the connect succeeds.
903 TEST_F(WebSocketChannelDeletingTest, OnAddChannelResponseSuccess) {
904 CreateChannelAndConnectSuccessfully();
905 EXPECT_EQ(NULL, channel_.get());
906 }
907
908 TEST_F(WebSocketChannelDeletingTest, OnDataFrameSync) {
909 scoped_ptr<ReadableFakeWebSocketStream> stream(
910 new ReadableFakeWebSocketStream);
911 static const InitFrame frames[] = {
912 {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, "HELLO"}};
913 stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames);
914 set_stream(stream.Pass());
915 deleting_ = EVENT_ON_DATA_FRAME;
916
917 CreateChannelAndConnectSuccessfully();
918 EXPECT_EQ(NULL, channel_.get());
919 }
920
921 TEST_F(WebSocketChannelDeletingTest, OnDataFrameAsync) {
922 scoped_ptr<ReadableFakeWebSocketStream> stream(
923 new ReadableFakeWebSocketStream);
924 static const InitFrame frames[] = {
925 {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, "HELLO"}};
926 stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, frames);
927 set_stream(stream.Pass());
928 deleting_ = EVENT_ON_DATA_FRAME;
929
930 CreateChannelAndConnectSuccessfully();
931 EXPECT_TRUE(channel_);
932 base::MessageLoop::current()->RunUntilIdle();
933 EXPECT_EQ(NULL, channel_.get());
934 }
935
936 TEST_F(WebSocketChannelDeletingTest, OnFlowControlAfterConnect) {
937 deleting_ = EVENT_ON_FLOW_CONTROL;
938
939 CreateChannelAndConnectSuccessfully();
940 EXPECT_EQ(NULL, channel_.get());
941 }
942
943 TEST_F(WebSocketChannelDeletingTest, OnFlowControlAfterSend) {
944 set_stream(make_scoped_ptr(new WriteableFakeWebSocketStream));
945 // Avoid deleting the channel yet.
946 deleting_ = EVENT_ON_DROP_CHANNEL;
947 CreateChannelAndConnectSuccessfully();
948 ASSERT_TRUE(channel_);
949 deleting_ = EVENT_ON_FLOW_CONTROL;
950 channel_->SendFrame(true,
951 WebSocketFrameHeader::kOpCodeText,
952 std::vector<char>(kDefaultInitialQuota, 'B'));
953 EXPECT_EQ(NULL, channel_.get());
954 }
955
956 TEST_F(WebSocketChannelDeletingTest, OnClosingHandshakeSync) {
957 scoped_ptr<ReadableFakeWebSocketStream> stream(
958 new ReadableFakeWebSocketStream);
959 static const InitFrame frames[] = {
960 {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
961 NOT_MASKED, CLOSE_DATA(NORMAL_CLOSURE, "Success")}};
962 stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames);
963 set_stream(stream.Pass());
964 deleting_ = EVENT_ON_CLOSING_HANDSHAKE;
965 CreateChannelAndConnectSuccessfully();
966 EXPECT_EQ(NULL, channel_.get());
967 }
968
969 TEST_F(WebSocketChannelDeletingTest, OnClosingHandshakeAsync) {
970 scoped_ptr<ReadableFakeWebSocketStream> stream(
971 new ReadableFakeWebSocketStream);
972 static const InitFrame frames[] = {
973 {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
974 NOT_MASKED, CLOSE_DATA(NORMAL_CLOSURE, "Success")}};
975 stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, frames);
976 set_stream(stream.Pass());
977 deleting_ = EVENT_ON_CLOSING_HANDSHAKE;
978 CreateChannelAndConnectSuccessfully();
979 ASSERT_TRUE(channel_);
980 base::MessageLoop::current()->RunUntilIdle();
981 EXPECT_EQ(NULL, channel_.get());
982 }
983
984 TEST_F(WebSocketChannelDeletingTest, OnDropChannelWriteError) {
985 set_stream(make_scoped_ptr(new UnWriteableFakeWebSocketStream));
986 deleting_ = EVENT_ON_DROP_CHANNEL;
987 CreateChannelAndConnectSuccessfully();
988 ASSERT_TRUE(channel_);
989 channel_->SendFrame(
990 true, WebSocketFrameHeader::kOpCodeText, AsVector("this will fail"));
991 EXPECT_EQ(NULL, channel_.get());
992 }
993
994 TEST_F(WebSocketChannelDeletingTest, OnDropChannelReadError) {
995 scoped_ptr<ReadableFakeWebSocketStream> stream(
996 new ReadableFakeWebSocketStream);
997 stream->PrepareReadFramesError(ReadableFakeWebSocketStream::ASYNC,
998 ERR_FAILED);
999 set_stream(stream.Pass());
1000 deleting_ = EVENT_ON_DROP_CHANNEL;
1001 CreateChannelAndConnectSuccessfully();
1002 ASSERT_TRUE(channel_);
1003 base::MessageLoop::current()->RunUntilIdle();
1004 EXPECT_EQ(NULL, channel_.get());
1005 }
1006
1007 TEST_F(WebSocketChannelDeletingTest, FailChannelInSendFrame) {
1008 set_stream(make_scoped_ptr(new WriteableFakeWebSocketStream));
1009 deleting_ = EVENT_ON_DROP_CHANNEL;
1010 CreateChannelAndConnectSuccessfully();
1011 ASSERT_TRUE(channel_);
1012 channel_->SendFrame(true,
1013 WebSocketFrameHeader::kOpCodeText,
1014 std::vector<char>(kDefaultInitialQuota * 2, 'T'));
1015 EXPECT_EQ(NULL, channel_.get());
1016 }
1017
1018 TEST_F(WebSocketChannelDeletingTest, FailChannelInOnReadDone) {
1019 scoped_ptr<ReadableFakeWebSocketStream> stream(
1020 new ReadableFakeWebSocketStream);
1021 stream->PrepareReadFramesError(ReadableFakeWebSocketStream::ASYNC,
1022 ERR_WS_PROTOCOL_ERROR);
1023 set_stream(stream.Pass());
1024 deleting_ = EVENT_ON_DROP_CHANNEL;
1025 CreateChannelAndConnectSuccessfully();
1026 ASSERT_TRUE(channel_);
1027 base::MessageLoop::current()->RunUntilIdle();
1028 EXPECT_EQ(NULL, channel_.get());
1029 }
1030
1031 TEST_F(WebSocketChannelDeletingTest, FailChannelDueToMaskedFrame) {
1032 scoped_ptr<ReadableFakeWebSocketStream> stream(
1033 new ReadableFakeWebSocketStream);
1034 static const InitFrame frames[] = {
1035 {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, MASKED, "HELLO"}};
1036 stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames);
1037 set_stream(stream.Pass());
1038 deleting_ = EVENT_ON_DROP_CHANNEL;
1039
1040 CreateChannelAndConnectSuccessfully();
1041 EXPECT_EQ(NULL, channel_.get());
1042 }
1043
1044 TEST_F(WebSocketChannelDeletingTest, FailChannelDueToBadControlFrame) {
1045 scoped_ptr<ReadableFakeWebSocketStream> stream(
1046 new ReadableFakeWebSocketStream);
1047 static const InitFrame frames[] = {
1048 {NOT_FINAL_FRAME, WebSocketFrameHeader::kOpCodePong, NOT_MASKED, ""}};
1049 stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames);
1050 set_stream(stream.Pass());
1051 deleting_ = EVENT_ON_DROP_CHANNEL;
1052
1053 CreateChannelAndConnectSuccessfully();
1054 EXPECT_EQ(NULL, channel_.get());
1055 }
1056
1057 TEST_F(WebSocketChannelDeletingTest, FailChannelDueToPongAfterClose) {
1058 scoped_ptr<ReadableFakeWebSocketStream> stream(
1059 new ReadableFakeWebSocketStream);
1060 static const InitFrame frames[] = {
1061 {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose, NOT_MASKED,
1062 CLOSE_DATA(NORMAL_CLOSURE, "Success")},
1063 {FINAL_FRAME, WebSocketFrameHeader::kOpCodePong, NOT_MASKED, ""}};
1064 stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames);
1065 set_stream(stream.Pass());
1066 deleting_ = EVENT_ON_DROP_CHANNEL;
1067
1068 CreateChannelAndConnectSuccessfully();
1069 EXPECT_EQ(NULL, channel_.get());
1070 }
1071
1072 TEST_F(WebSocketChannelDeletingTest, FailChannelDueToUnknownOpCode) {
1073 scoped_ptr<ReadableFakeWebSocketStream> stream(
1074 new ReadableFakeWebSocketStream);
1075 static const InitFrame frames[] = {{FINAL_FRAME, 0x7, NOT_MASKED, ""}};
1076 stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames);
1077 set_stream(stream.Pass());
1078 deleting_ = EVENT_ON_DROP_CHANNEL;
1079
1080 CreateChannelAndConnectSuccessfully();
1081 EXPECT_EQ(NULL, channel_.get());
1082 }
1083
800 TEST_F(WebSocketChannelEventInterfaceTest, ConnectSuccessReported) { 1084 TEST_F(WebSocketChannelEventInterfaceTest, ConnectSuccessReported) {
801 // false means success. 1085 // false means success.
802 EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, "")); 1086 EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, ""));
803 // OnFlowControl is always called immediately after connect to provide initial 1087 // OnFlowControl is always called immediately after connect to provide initial
804 // quota to the renderer. 1088 // quota to the renderer.
805 EXPECT_CALL(*event_interface_, OnFlowControl(_)); 1089 EXPECT_CALL(*event_interface_, OnFlowControl(_));
806 1090
807 CreateChannelAndConnect(); 1091 CreateChannelAndConnect();
808 1092
809 connect_data_.factory.connect_delegate->OnSuccess(stream_.Pass()); 1093 connect_data_.factory.connect_delegate->OnSuccess(stream_.Pass());
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after
896 CreateChannelAndConnectSuccessfully(); 1180 CreateChannelAndConnectSuccessfully();
897 } 1181 }
898 1182
899 TEST_F(WebSocketChannelEventInterfaceTest, NormalAsyncRead) { 1183 TEST_F(WebSocketChannelEventInterfaceTest, NormalAsyncRead) {
900 scoped_ptr<ReadableFakeWebSocketStream> stream( 1184 scoped_ptr<ReadableFakeWebSocketStream> stream(
901 new ReadableFakeWebSocketStream); 1185 new ReadableFakeWebSocketStream);
902 static const InitFrame frames[] = { 1186 static const InitFrame frames[] = {
903 {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, "HELLO"}}; 1187 {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, "HELLO"}};
904 // We use this checkpoint object to verify that the callback isn't called 1188 // We use this checkpoint object to verify that the callback isn't called
905 // until we expect it to be. 1189 // until we expect it to be.
906 MockFunction<void(int)> checkpoint; 1190 Checkpoint checkpoint;
907 stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, frames); 1191 stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, frames);
908 set_stream(stream.Pass()); 1192 set_stream(stream.Pass());
909 { 1193 {
910 InSequence s; 1194 InSequence s;
911 EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _)); 1195 EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _));
912 EXPECT_CALL(*event_interface_, OnFlowControl(_)); 1196 EXPECT_CALL(*event_interface_, OnFlowControl(_));
913 EXPECT_CALL(checkpoint, Call(1)); 1197 EXPECT_CALL(checkpoint, Call(1));
914 EXPECT_CALL( 1198 EXPECT_CALL(
915 *event_interface_, 1199 *event_interface_,
916 OnDataFrame( 1200 OnDataFrame(
(...skipping 267 matching lines...) Expand 10 before | Expand all | Expand 10 after
1184 CreateChannelAndConnectSuccessfully(); 1468 CreateChannelAndConnectSuccessfully();
1185 channel_->SendFrame(true, WebSocketFrameHeader::kOpCodeText, AsVector("B")); 1469 channel_->SendFrame(true, WebSocketFrameHeader::kOpCodeText, AsVector("B"));
1186 } 1470 }
1187 1471
1188 // If we send enough to go below send_quota_low_water_mask_ we should get our 1472 // If we send enough to go below send_quota_low_water_mask_ we should get our
1189 // quota refreshed. 1473 // quota refreshed.
1190 TEST_F(WebSocketChannelEventInterfaceTest, LargeWriteUpdatesQuota) { 1474 TEST_F(WebSocketChannelEventInterfaceTest, LargeWriteUpdatesQuota) {
1191 set_stream(make_scoped_ptr(new WriteableFakeWebSocketStream)); 1475 set_stream(make_scoped_ptr(new WriteableFakeWebSocketStream));
1192 // We use this checkpoint object to verify that the quota update comes after 1476 // We use this checkpoint object to verify that the quota update comes after
1193 // the write. 1477 // the write.
1194 MockFunction<void(int)> checkpoint; 1478 Checkpoint checkpoint;
1195 { 1479 {
1196 InSequence s; 1480 InSequence s;
1197 EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _)); 1481 EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _));
1198 EXPECT_CALL(*event_interface_, OnFlowControl(_)); 1482 EXPECT_CALL(*event_interface_, OnFlowControl(_));
1199 EXPECT_CALL(checkpoint, Call(1)); 1483 EXPECT_CALL(checkpoint, Call(1));
1200 EXPECT_CALL(*event_interface_, OnFlowControl(_)); 1484 EXPECT_CALL(*event_interface_, OnFlowControl(_));
1201 EXPECT_CALL(checkpoint, Call(2)); 1485 EXPECT_CALL(checkpoint, Call(2));
1202 } 1486 }
1203 1487
1204 CreateChannelAndConnectSuccessfully(); 1488 CreateChannelAndConnectSuccessfully();
1205 checkpoint.Call(1); 1489 checkpoint.Call(1);
1206 channel_->SendFrame(true, 1490 channel_->SendFrame(true,
1207 WebSocketFrameHeader::kOpCodeText, 1491 WebSocketFrameHeader::kOpCodeText,
1208 std::vector<char>(kDefaultInitialQuota, 'B')); 1492 std::vector<char>(kDefaultInitialQuota, 'B'));
1209 checkpoint.Call(2); 1493 checkpoint.Call(2);
1210 } 1494 }
1211 1495
1212 // Verify that our quota actually is refreshed when we are told it is. 1496 // Verify that our quota actually is refreshed when we are told it is.
1213 TEST_F(WebSocketChannelEventInterfaceTest, QuotaReallyIsRefreshed) { 1497 TEST_F(WebSocketChannelEventInterfaceTest, QuotaReallyIsRefreshed) {
1214 set_stream(make_scoped_ptr(new WriteableFakeWebSocketStream)); 1498 set_stream(make_scoped_ptr(new WriteableFakeWebSocketStream));
1215 MockFunction<void(int)> checkpoint; 1499 Checkpoint checkpoint;
1216 { 1500 {
1217 InSequence s; 1501 InSequence s;
1218 EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _)); 1502 EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _));
1219 EXPECT_CALL(*event_interface_, OnFlowControl(_)); 1503 EXPECT_CALL(*event_interface_, OnFlowControl(_));
1220 EXPECT_CALL(checkpoint, Call(1)); 1504 EXPECT_CALL(checkpoint, Call(1));
1221 EXPECT_CALL(*event_interface_, OnFlowControl(_)); 1505 EXPECT_CALL(*event_interface_, OnFlowControl(_));
1222 EXPECT_CALL(checkpoint, Call(2)); 1506 EXPECT_CALL(checkpoint, Call(2));
1223 // If quota was not really refreshed, we would get an OnDropChannel() 1507 // If quota was not really refreshed, we would get an OnDropChannel()
1224 // message. 1508 // message.
1225 EXPECT_CALL(*event_interface_, OnFlowControl(_)); 1509 EXPECT_CALL(*event_interface_, OnFlowControl(_));
(...skipping 27 matching lines...) Expand all
1253 1537
1254 CreateChannelAndConnectSuccessfully(); 1538 CreateChannelAndConnectSuccessfully();
1255 channel_->SendFrame(true, 1539 channel_->SendFrame(true,
1256 WebSocketFrameHeader::kOpCodeText, 1540 WebSocketFrameHeader::kOpCodeText,
1257 std::vector<char>(kDefaultInitialQuota + 1, 'C')); 1541 std::vector<char>(kDefaultInitialQuota + 1, 'C'));
1258 } 1542 }
1259 1543
1260 // If a write fails, the channel is dropped. 1544 // If a write fails, the channel is dropped.
1261 TEST_F(WebSocketChannelEventInterfaceTest, FailedWrite) { 1545 TEST_F(WebSocketChannelEventInterfaceTest, FailedWrite) {
1262 set_stream(make_scoped_ptr(new UnWriteableFakeWebSocketStream)); 1546 set_stream(make_scoped_ptr(new UnWriteableFakeWebSocketStream));
1263 MockFunction<void(int)> checkpoint; 1547 Checkpoint checkpoint;
1264 { 1548 {
1265 InSequence s; 1549 InSequence s;
1266 EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _)); 1550 EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _));
1267 EXPECT_CALL(*event_interface_, OnFlowControl(_)); 1551 EXPECT_CALL(*event_interface_, OnFlowControl(_));
1268 EXPECT_CALL(checkpoint, Call(1)); 1552 EXPECT_CALL(checkpoint, Call(1));
1269 EXPECT_CALL(*event_interface_, 1553 EXPECT_CALL(*event_interface_,
1270 OnDropChannel(kWebSocketErrorAbnormalClosure, _)); 1554 OnDropChannel(kWebSocketErrorAbnormalClosure, _));
1271 EXPECT_CALL(checkpoint, Call(2)); 1555 EXPECT_CALL(checkpoint, Call(2));
1272 } 1556 }
1273 1557
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after
1428 static const InitFrame frames_init[] = { 1712 static const InitFrame frames_init[] = {
1429 {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose, 1713 {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
1430 NOT_MASKED, CLOSE_DATA(NORMAL_CLOSURE, "Close")}}; 1714 NOT_MASKED, CLOSE_DATA(NORMAL_CLOSURE, "Close")}};
1431 1715
1432 // We store the parameters that were passed to ReadFrames() so that we can 1716 // We store the parameters that were passed to ReadFrames() so that we can
1433 // call them explicitly later. 1717 // call them explicitly later.
1434 CompletionCallback read_callback; 1718 CompletionCallback read_callback;
1435 ScopedVector<WebSocketFrame>* frames = NULL; 1719 ScopedVector<WebSocketFrame>* frames = NULL;
1436 1720
1437 // Use a checkpoint to make the ordering of events clearer. 1721 // Use a checkpoint to make the ordering of events clearer.
1438 MockFunction<void(int)> checkpoint; 1722 Checkpoint checkpoint;
1439 { 1723 {
1440 InSequence s; 1724 InSequence s;
1441 EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber()); 1725 EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
1442 EXPECT_CALL(*mock_stream_, ReadFrames(_, _)) 1726 EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
1443 .WillOnce(DoAll(SaveArg<0>(&frames), 1727 .WillOnce(DoAll(SaveArg<0>(&frames),
1444 SaveArg<1>(&read_callback), 1728 SaveArg<1>(&read_callback),
1445 Return(ERR_IO_PENDING))); 1729 Return(ERR_IO_PENDING)));
1446 EXPECT_CALL(checkpoint, Call(1)); 1730 EXPECT_CALL(checkpoint, Call(1));
1447 EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected), _)) 1731 EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected), _))
1448 .WillOnce(Return(OK)); 1732 .WillOnce(Return(OK));
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after
1547 } 1831 }
1548 1832
1549 // WriteFrames() may not be called until the previous write has completed. 1833 // WriteFrames() may not be called until the previous write has completed.
1550 // WebSocketChannel must buffer writes that happen in the meantime. 1834 // WebSocketChannel must buffer writes that happen in the meantime.
1551 TEST_F(WebSocketChannelStreamTest, WriteFramesOneAtATime) { 1835 TEST_F(WebSocketChannelStreamTest, WriteFramesOneAtATime) {
1552 static const InitFrame expected1[] = { 1836 static const InitFrame expected1[] = {
1553 {NOT_FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, MASKED, "Hello "}}; 1837 {NOT_FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, MASKED, "Hello "}};
1554 static const InitFrame expected2[] = { 1838 static const InitFrame expected2[] = {
1555 {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, MASKED, "World"}}; 1839 {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, MASKED, "World"}};
1556 CompletionCallback write_callback; 1840 CompletionCallback write_callback;
1557 MockFunction<void(int)> checkpoint; 1841 Checkpoint checkpoint;
1558 1842
1559 EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber()); 1843 EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
1560 EXPECT_CALL(*mock_stream_, ReadFrames(_, _)).WillOnce(Return(ERR_IO_PENDING)); 1844 EXPECT_CALL(*mock_stream_, ReadFrames(_, _)).WillOnce(Return(ERR_IO_PENDING));
1561 { 1845 {
1562 InSequence s; 1846 InSequence s;
1563 EXPECT_CALL(checkpoint, Call(1)); 1847 EXPECT_CALL(checkpoint, Call(1));
1564 EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected1), _)) 1848 EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected1), _))
1565 .WillOnce(DoAll(SaveArg<1>(&write_callback), Return(ERR_IO_PENDING))); 1849 .WillOnce(DoAll(SaveArg<1>(&write_callback), Return(ERR_IO_PENDING)));
1566 EXPECT_CALL(checkpoint, Call(2)); 1850 EXPECT_CALL(checkpoint, Call(2));
1567 EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected2), _)) 1851 EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected2), _))
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after
1728 .WillOnce(Return(ERR_WS_PROTOCOL_ERROR)); 2012 .WillOnce(Return(ERR_WS_PROTOCOL_ERROR));
1729 EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected), _)) 2013 EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected), _))
1730 .WillOnce(Return(OK)); 2014 .WillOnce(Return(OK));
1731 EXPECT_CALL(*mock_stream_, Close()); 2015 EXPECT_CALL(*mock_stream_, Close());
1732 2016
1733 CreateChannelAndConnectSuccessfully(); 2017 CreateChannelAndConnectSuccessfully();
1734 } 2018 }
1735 2019
1736 } // namespace 2020 } // namespace
1737 } // namespace net 2021 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698