| OLD | NEW |
| 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 "modules/websockets/WebSocketChannel.h" | 5 #include "modules/websockets/DocumentWebSocketChannel.h" |
| 6 | 6 |
| 7 #include <stdint.h> | 7 #include <stdint.h> |
| 8 #include <memory> | 8 #include <memory> |
| 9 #include "core/dom/DOMArrayBuffer.h" | 9 #include "core/dom/DOMArrayBuffer.h" |
| 10 #include "core/dom/Document.h" | 10 #include "core/dom/Document.h" |
| 11 #include "core/fileapi/Blob.h" | 11 #include "core/fileapi/Blob.h" |
| 12 #include "core/testing/DummyPageHolder.h" | 12 #include "core/testing/DummyPageHolder.h" |
| 13 #include "modules/websockets/DocumentWebSocketChannel.h" | 13 #include "modules/websockets/WebSocketChannel.h" |
| 14 #include "modules/websockets/WebSocketChannelClient.h" | 14 #include "modules/websockets/WebSocketChannelClient.h" |
| 15 #include "modules/websockets/WebSocketHandle.h" | 15 #include "modules/websockets/WebSocketHandle.h" |
| 16 #include "modules/websockets/WebSocketHandleClient.h" | 16 #include "modules/websockets/WebSocketHandleClient.h" |
| 17 #include "platform/heap/Handle.h" | 17 #include "platform/heap/Handle.h" |
| 18 #include "platform/weborigin/KURL.h" | 18 #include "platform/weborigin/KURL.h" |
| 19 #include "platform/wtf/PtrUtil.h" | 19 #include "platform/wtf/PtrUtil.h" |
| 20 #include "platform/wtf/Vector.h" | 20 #include "platform/wtf/Vector.h" |
| 21 #include "platform/wtf/text/WTFString.h" | 21 #include "platform/wtf/text/WTFString.h" |
| 22 #include "public/platform/WebCallbacks.h" |
| 23 #include "public/platform/WebSocketHandshakeThrottle.h" |
| 24 #include "public/platform/WebURL.h" |
| 25 #include "public/web/WebLocalFrame.h" |
| 22 #include "testing/gmock/include/gmock/gmock.h" | 26 #include "testing/gmock/include/gmock/gmock.h" |
| 23 #include "testing/gtest/include/gtest/gtest.h" | 27 #include "testing/gtest/include/gtest/gtest.h" |
| 24 | 28 |
| 25 using testing::_; | 29 using testing::_; |
| 26 using testing::InSequence; | 30 using testing::InSequence; |
| 27 using testing::PrintToString; | 31 using testing::PrintToString; |
| 28 using testing::AnyNumber; | 32 using testing::AnyNumber; |
| 29 using testing::SaveArg; | 33 using testing::SaveArg; |
| 30 | 34 |
| 31 namespace blink { | 35 namespace blink { |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 82 SecurityOrigin*, | 86 SecurityOrigin*, |
| 83 const KURL&, | 87 const KURL&, |
| 84 const String&, | 88 const String&, |
| 85 WebSocketHandleClient*)); | 89 WebSocketHandleClient*)); |
| 86 MOCK_METHOD4(Send, | 90 MOCK_METHOD4(Send, |
| 87 void(bool, WebSocketHandle::MessageType, const char*, size_t)); | 91 void(bool, WebSocketHandle::MessageType, const char*, size_t)); |
| 88 MOCK_METHOD1(FlowControl, void(int64_t)); | 92 MOCK_METHOD1(FlowControl, void(int64_t)); |
| 89 MOCK_METHOD2(Close, void(unsigned short, const String&)); | 93 MOCK_METHOD2(Close, void(unsigned short, const String&)); |
| 90 }; | 94 }; |
| 91 | 95 |
| 96 class MockWebSocketHandshakeThrottle : public WebSocketHandshakeThrottle { |
| 97 public: |
| 98 static MockWebSocketHandshakeThrottle* Create() { |
| 99 return new testing::StrictMock<MockWebSocketHandshakeThrottle>(); |
| 100 } |
| 101 MockWebSocketHandshakeThrottle() {} |
| 102 ~MockWebSocketHandshakeThrottle() override { Destructor(); } |
| 103 |
| 104 MOCK_METHOD3(ThrottleHandshake, |
| 105 void(const WebURL&, |
| 106 WebLocalFrame*, |
| 107 WebCallbacks<void, const WebString&>*)); |
| 108 |
| 109 // This method is used to allow us to require that the destructor is called at |
| 110 // a particular time. |
| 111 MOCK_METHOD0(Destructor, void()); |
| 112 }; |
| 113 |
| 92 class DocumentWebSocketChannelTest : public ::testing::Test { | 114 class DocumentWebSocketChannelTest : public ::testing::Test { |
| 93 public: | 115 public: |
| 94 DocumentWebSocketChannelTest() | 116 DocumentWebSocketChannelTest() |
| 95 : page_holder_(DummyPageHolder::Create()), | 117 : page_holder_(DummyPageHolder::Create()), |
| 96 channel_client_(MockWebSocketChannelClient::Create()), | 118 channel_client_(MockWebSocketChannelClient::Create()), |
| 97 handle_(MockWebSocketHandle::Create()), | 119 handle_(MockWebSocketHandle::Create()), |
| 98 channel_(DocumentWebSocketChannel::Create(&page_holder_->GetDocument(), | 120 handshake_throttle_(nullptr), |
| 99 channel_client_.Get(), | |
| 100 SourceLocation::Capture(), | |
| 101 Handle())), | |
| 102 sum_of_consumed_buffered_amount_(0) { | 121 sum_of_consumed_buffered_amount_(0) { |
| 103 ON_CALL(*ChannelClient(), DidConsumeBufferedAmount(_)) | 122 ON_CALL(*ChannelClient(), DidConsumeBufferedAmount(_)) |
| 104 .WillByDefault(Invoke( | 123 .WillByDefault(Invoke( |
| 105 this, &DocumentWebSocketChannelTest::DidConsumeBufferedAmount)); | 124 this, &DocumentWebSocketChannelTest::DidConsumeBufferedAmount)); |
| 106 } | 125 } |
| 107 | 126 |
| 108 ~DocumentWebSocketChannelTest() { Channel()->Disconnect(); } | 127 ~DocumentWebSocketChannelTest() { Channel()->Disconnect(); } |
| 109 | 128 |
| 129 void SetUp() override { |
| 130 channel_ = DocumentWebSocketChannel::CreateForTesting( |
| 131 &page_holder_->GetDocument(), channel_client_.Get(), |
| 132 SourceLocation::Capture(), Handle(), |
| 133 WTF::WrapUnique(handshake_throttle_)); |
| 134 } |
| 135 |
| 110 MockWebSocketChannelClient* ChannelClient() { return channel_client_.Get(); } | 136 MockWebSocketChannelClient* ChannelClient() { return channel_client_.Get(); } |
| 111 | 137 |
| 112 WebSocketChannel* Channel() { | 138 WebSocketChannel* Channel() { |
| 113 return static_cast<WebSocketChannel*>(channel_.Get()); | 139 return static_cast<WebSocketChannel*>(channel_.Get()); |
| 114 } | 140 } |
| 115 | 141 |
| 116 WebSocketHandleClient* HandleClient() { | 142 WebSocketHandleClient* HandleClient() { |
| 117 return static_cast<WebSocketHandleClient*>(channel_.Get()); | 143 return static_cast<WebSocketHandleClient*>(channel_.Get()); |
| 118 } | 144 } |
| 119 | 145 |
| 146 WebCallbacks<void, const WebString&>* WebCallbacks() { |
| 147 return channel_.Get(); |
| 148 } |
| 149 |
| 120 MockWebSocketHandle* Handle() { return handle_; } | 150 MockWebSocketHandle* Handle() { return handle_; } |
| 121 | 151 |
| 122 void DidConsumeBufferedAmount(unsigned long a) { | 152 void DidConsumeBufferedAmount(unsigned long a) { |
| 123 sum_of_consumed_buffered_amount_ += a; | 153 sum_of_consumed_buffered_amount_ += a; |
| 124 } | 154 } |
| 125 | 155 |
| 126 void Connect() { | 156 void Connect() { |
| 127 { | 157 { |
| 128 InSequence s; | 158 InSequence s; |
| 129 EXPECT_CALL(*Handle(), Initialize(_)); | 159 EXPECT_CALL(*Handle(), Initialize(_)); |
| 130 EXPECT_CALL(*Handle(), Connect(KURL(KURL(), "ws://localhost/"), _, _, _, | 160 EXPECT_CALL(*Handle(), Connect(KURL(KURL(), "ws://localhost/"), _, _, _, |
| 131 _, HandleClient())); | 161 _, HandleClient())); |
| 132 EXPECT_CALL(*Handle(), FlowControl(65536)); | 162 EXPECT_CALL(*Handle(), FlowControl(65536)); |
| 133 EXPECT_CALL(*ChannelClient(), DidConnect(String("a"), String("b"))); | 163 EXPECT_CALL(*ChannelClient(), DidConnect(String("a"), String("b"))); |
| 134 } | 164 } |
| 135 EXPECT_TRUE(Channel()->Connect(KURL(KURL(), "ws://localhost/"), "x")); | 165 EXPECT_TRUE(Channel()->Connect(KURL(KURL(), "ws://localhost/"), "x")); |
| 136 HandleClient()->DidConnect(Handle(), String("a"), String("b")); | 166 HandleClient()->DidConnect(Handle(), String("a"), String("b")); |
| 137 ::testing::Mock::VerifyAndClearExpectations(this); | 167 ::testing::Mock::VerifyAndClearExpectations(this); |
| 138 } | 168 } |
| 139 | 169 |
| 140 std::unique_ptr<DummyPageHolder> page_holder_; | 170 std::unique_ptr<DummyPageHolder> page_holder_; |
| 141 Persistent<MockWebSocketChannelClient> channel_client_; | 171 Persistent<MockWebSocketChannelClient> channel_client_; |
| 142 MockWebSocketHandle* handle_; | 172 MockWebSocketHandle* handle_; |
| 173 // |handshake_throttle_| is owned by |channel_| once SetUp() has been called. |
| 174 MockWebSocketHandshakeThrottle* handshake_throttle_; |
| 143 Persistent<DocumentWebSocketChannel> channel_; | 175 Persistent<DocumentWebSocketChannel> channel_; |
| 144 unsigned long sum_of_consumed_buffered_amount_; | 176 unsigned long sum_of_consumed_buffered_amount_; |
| 145 }; | 177 }; |
| 146 | 178 |
| 147 MATCHER_P2(MemEq, | 179 MATCHER_P2(MemEq, |
| 148 p, | 180 p, |
| 149 len, | 181 len, |
| 150 std::string("pointing to memory") + (negation ? " not" : "") + | 182 std::string("pointing to memory") + (negation ? " not" : "") + |
| 151 " equal to \"" + | 183 " equal to \"" + |
| 152 std::string(p, len) + | 184 std::string(p, len) + |
| (...skipping 615 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 768 EXPECT_CALL( | 800 EXPECT_CALL( |
| 769 *ChannelClient(), | 801 *ChannelClient(), |
| 770 DidClose(WebSocketChannelClient::kClosingHandshakeIncomplete, | 802 DidClose(WebSocketChannelClient::kClosingHandshakeIncomplete, |
| 771 WebSocketChannel::kCloseEventCodeAbnormalClosure, String())); | 803 WebSocketChannel::kCloseEventCodeAbnormalClosure, String())); |
| 772 } | 804 } |
| 773 | 805 |
| 774 Channel()->Fail("fail message from WebSocket", kErrorMessageLevel, | 806 Channel()->Fail("fail message from WebSocket", kErrorMessageLevel, |
| 775 SourceLocation::Create(String(), 0, 0, nullptr)); | 807 SourceLocation::Create(String(), 0, 0, nullptr)); |
| 776 } | 808 } |
| 777 | 809 |
| 810 class DocumentWebSocketChannelHandshakeThrottleTest |
| 811 : public DocumentWebSocketChannelTest { |
| 812 public: |
| 813 DocumentWebSocketChannelHandshakeThrottleTest() { |
| 814 handshake_throttle_ = MockWebSocketHandshakeThrottle::Create(); |
| 815 } |
| 816 |
| 817 // Expectations for the normal result of calling Channel()->Connect() with a |
| 818 // non-null throttle. |
| 819 void NormalHandshakeExpectations() { |
| 820 EXPECT_CALL(*Handle(), Initialize(_)); |
| 821 EXPECT_CALL(*Handle(), Connect(_, _, _, _, _, _)); |
| 822 EXPECT_CALL(*Handle(), FlowControl(_)); |
| 823 EXPECT_CALL(*handshake_throttle_, ThrottleHandshake(_, _, _)); |
| 824 } |
| 825 |
| 826 static KURL url() { return KURL(KURL(), "ws://localhost/"); } |
| 827 }; |
| 828 |
| 829 TEST_F(DocumentWebSocketChannelHandshakeThrottleTest, ThrottleArguments) { |
| 830 EXPECT_CALL(*Handle(), Initialize(_)); |
| 831 EXPECT_CALL(*Handle(), Connect(_, _, _, _, _, _)); |
| 832 EXPECT_CALL(*Handle(), FlowControl(_)); |
| 833 EXPECT_CALL(*handshake_throttle_, |
| 834 ThrottleHandshake(WebURL(url()), _, WebCallbacks())); |
| 835 EXPECT_CALL(*handshake_throttle_, Destructor()); |
| 836 Channel()->Connect(url(), ""); |
| 837 } |
| 838 |
| 839 TEST_F(DocumentWebSocketChannelHandshakeThrottleTest, ThrottleSucceedsFirst) { |
| 840 Checkpoint checkpoint; |
| 841 NormalHandshakeExpectations(); |
| 842 { |
| 843 InSequence s; |
| 844 EXPECT_CALL(checkpoint, Call(1)); |
| 845 EXPECT_CALL(*handshake_throttle_, Destructor()); |
| 846 EXPECT_CALL(checkpoint, Call(2)); |
| 847 EXPECT_CALL(*ChannelClient(), DidConnect(String("a"), String("b"))); |
| 848 } |
| 849 Channel()->Connect(url(), ""); |
| 850 checkpoint.Call(1); |
| 851 WebCallbacks()->OnSuccess(); |
| 852 checkpoint.Call(2); |
| 853 HandleClient()->DidConnect(Handle(), String("a"), String("b")); |
| 854 } |
| 855 |
| 856 TEST_F(DocumentWebSocketChannelHandshakeThrottleTest, HandshakeSucceedsFirst) { |
| 857 Checkpoint checkpoint; |
| 858 NormalHandshakeExpectations(); |
| 859 { |
| 860 InSequence s; |
| 861 EXPECT_CALL(checkpoint, Call(1)); |
| 862 EXPECT_CALL(checkpoint, Call(2)); |
| 863 EXPECT_CALL(*handshake_throttle_, Destructor()); |
| 864 EXPECT_CALL(*ChannelClient(), DidConnect(String("a"), String("b"))); |
| 865 } |
| 866 Channel()->Connect(url(), ""); |
| 867 checkpoint.Call(1); |
| 868 HandleClient()->DidConnect(Handle(), String("a"), String("b")); |
| 869 checkpoint.Call(2); |
| 870 WebCallbacks()->OnSuccess(); |
| 871 } |
| 872 |
| 873 // This happens if JS code calls close() during the handshake. |
| 874 TEST_F(DocumentWebSocketChannelHandshakeThrottleTest, FailDuringThrottle) { |
| 875 Checkpoint checkpoint; |
| 876 NormalHandshakeExpectations(); |
| 877 { |
| 878 InSequence s; |
| 879 EXPECT_CALL(*handshake_throttle_, Destructor()); |
| 880 EXPECT_CALL(*ChannelClient(), DidError()); |
| 881 EXPECT_CALL(*ChannelClient(), DidClose(_, _, _)); |
| 882 EXPECT_CALL(checkpoint, Call(1)); |
| 883 } |
| 884 Channel()->Connect(url(), ""); |
| 885 Channel()->Fail("close during handshake", kWarningMessageLevel, |
| 886 SourceLocation::Create(String(), 0, 0, nullptr)); |
| 887 checkpoint.Call(1); |
| 888 } |
| 889 |
| 890 // It makes no difference to the behaviour if the WebSocketHandle has actually |
| 891 // connected. |
| 892 TEST_F(DocumentWebSocketChannelHandshakeThrottleTest, |
| 893 FailDuringThrottleAfterConnect) { |
| 894 Checkpoint checkpoint; |
| 895 NormalHandshakeExpectations(); |
| 896 { |
| 897 InSequence s; |
| 898 EXPECT_CALL(*handshake_throttle_, Destructor()); |
| 899 EXPECT_CALL(*ChannelClient(), DidError()); |
| 900 EXPECT_CALL(*ChannelClient(), DidClose(_, _, _)); |
| 901 EXPECT_CALL(checkpoint, Call(1)); |
| 902 } |
| 903 Channel()->Connect(url(), ""); |
| 904 HandleClient()->DidConnect(Handle(), String("a"), String("b")); |
| 905 Channel()->Fail("close during handshake", kWarningMessageLevel, |
| 906 SourceLocation::Create(String(), 0, 0, nullptr)); |
| 907 checkpoint.Call(1); |
| 908 } |
| 909 |
| 910 // This happens if the JS context is destroyed during the handshake. |
| 911 TEST_F(DocumentWebSocketChannelHandshakeThrottleTest, CloseDuringThrottle) { |
| 912 Checkpoint checkpoint; |
| 913 NormalHandshakeExpectations(); |
| 914 { |
| 915 InSequence s; |
| 916 EXPECT_CALL(*handshake_throttle_, Destructor()); |
| 917 EXPECT_CALL(*Handle(), Close(_, _)); |
| 918 EXPECT_CALL(checkpoint, Call(1)); |
| 919 } |
| 920 Channel()->Connect(url(), ""); |
| 921 Channel()->Close(DocumentWebSocketChannel::kCloseEventCodeGoingAway, ""); |
| 922 checkpoint.Call(1); |
| 923 } |
| 924 |
| 925 TEST_F(DocumentWebSocketChannelHandshakeThrottleTest, |
| 926 CloseDuringThrottleAfterConnect) { |
| 927 Checkpoint checkpoint; |
| 928 NormalHandshakeExpectations(); |
| 929 { |
| 930 InSequence s; |
| 931 EXPECT_CALL(*handshake_throttle_, Destructor()); |
| 932 EXPECT_CALL(*Handle(), Close(_, _)); |
| 933 EXPECT_CALL(checkpoint, Call(1)); |
| 934 } |
| 935 Channel()->Connect(url(), ""); |
| 936 HandleClient()->DidConnect(Handle(), String("a"), String("b")); |
| 937 Channel()->Close(DocumentWebSocketChannel::kCloseEventCodeGoingAway, ""); |
| 938 checkpoint.Call(1); |
| 939 } |
| 940 |
| 941 TEST_F(DocumentWebSocketChannelHandshakeThrottleTest, |
| 942 DisconnectDuringThrottle) { |
| 943 Checkpoint checkpoint; |
| 944 NormalHandshakeExpectations(); |
| 945 { |
| 946 InSequence s; |
| 947 EXPECT_CALL(*handshake_throttle_, Destructor()); |
| 948 EXPECT_CALL(checkpoint, Call(1)); |
| 949 } |
| 950 Channel()->Connect(url(), ""); |
| 951 Channel()->Disconnect(); |
| 952 checkpoint.Call(1); |
| 953 } |
| 954 |
| 955 TEST_F(DocumentWebSocketChannelHandshakeThrottleTest, |
| 956 DisconnectDuringThrottleAfterConnect) { |
| 957 Checkpoint checkpoint; |
| 958 NormalHandshakeExpectations(); |
| 959 { |
| 960 InSequence s; |
| 961 EXPECT_CALL(*handshake_throttle_, Destructor()); |
| 962 EXPECT_CALL(checkpoint, Call(1)); |
| 963 } |
| 964 Channel()->Connect(url(), ""); |
| 965 HandleClient()->DidConnect(Handle(), String("a"), String("b")); |
| 966 Channel()->Disconnect(); |
| 967 checkpoint.Call(1); |
| 968 } |
| 969 |
| 970 TEST_F(DocumentWebSocketChannelHandshakeThrottleTest, |
| 971 ThrottleReportsErrorBeforeConnect) { |
| 972 NormalHandshakeExpectations(); |
| 973 { |
| 974 InSequence s; |
| 975 EXPECT_CALL(*handshake_throttle_, Destructor()); |
| 976 EXPECT_CALL(*ChannelClient(), DidError()); |
| 977 EXPECT_CALL(*ChannelClient(), DidClose(_, _, _)); |
| 978 } |
| 979 Channel()->Connect(url(), ""); |
| 980 WebCallbacks()->OnError("Connection blocked by throttle"); |
| 981 } |
| 982 |
| 983 TEST_F(DocumentWebSocketChannelHandshakeThrottleTest, |
| 984 ThrottleReportsErrorAfterConnect) { |
| 985 NormalHandshakeExpectations(); |
| 986 { |
| 987 InSequence s; |
| 988 EXPECT_CALL(*handshake_throttle_, Destructor()); |
| 989 EXPECT_CALL(*ChannelClient(), DidError()); |
| 990 EXPECT_CALL(*ChannelClient(), DidClose(_, _, _)); |
| 991 } |
| 992 Channel()->Connect(url(), ""); |
| 993 HandleClient()->DidConnect(Handle(), String("a"), String("b")); |
| 994 WebCallbacks()->OnError("Connection blocked by throttle"); |
| 995 } |
| 996 |
| 997 TEST_F(DocumentWebSocketChannelHandshakeThrottleTest, |
| 998 ConnectFailBeforeThrottle) { |
| 999 NormalHandshakeExpectations(); |
| 1000 { |
| 1001 InSequence s; |
| 1002 EXPECT_CALL(*handshake_throttle_, Destructor()); |
| 1003 EXPECT_CALL(*ChannelClient(), DidError()); |
| 1004 EXPECT_CALL(*ChannelClient(), DidClose(_, _, _)); |
| 1005 } |
| 1006 Channel()->Connect(url(), ""); |
| 1007 HandleClient()->DidFail(Handle(), "connect failed"); |
| 1008 } |
| 1009 |
| 1010 // TODO(ricea): Can this actually happen? |
| 1011 TEST_F(DocumentWebSocketChannelHandshakeThrottleTest, |
| 1012 ConnectCloseBeforeThrottle) { |
| 1013 NormalHandshakeExpectations(); |
| 1014 { |
| 1015 InSequence s; |
| 1016 EXPECT_CALL(*handshake_throttle_, Destructor()); |
| 1017 EXPECT_CALL(*ChannelClient(), DidClose(_, _, _)); |
| 1018 } |
| 1019 Channel()->Connect(url(), ""); |
| 1020 HandleClient()->DidClose(Handle(), false, |
| 1021 WebSocketChannel::kCloseEventCodeProtocolError, |
| 1022 "connect error"); |
| 1023 } |
| 1024 |
| 778 } // namespace | 1025 } // namespace |
| 779 | 1026 |
| 780 } // namespace blink | 1027 } // namespace blink |
| OLD | NEW |