| 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/DocumentWebSocketChannel.h" | 5 #include "modules/websockets/WebSocketChannel.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/WebSocketChannel.h" | 13 #include "modules/websockets/DocumentWebSocketChannel.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" | |
| 26 #include "testing/gmock/include/gmock/gmock.h" | 22 #include "testing/gmock/include/gmock/gmock.h" |
| 27 #include "testing/gtest/include/gtest/gtest.h" | 23 #include "testing/gtest/include/gtest/gtest.h" |
| 28 | 24 |
| 29 using testing::_; | 25 using testing::_; |
| 30 using testing::InSequence; | 26 using testing::InSequence; |
| 31 using testing::PrintToString; | 27 using testing::PrintToString; |
| 32 using testing::AnyNumber; | 28 using testing::AnyNumber; |
| 33 using testing::SaveArg; | 29 using testing::SaveArg; |
| 34 | 30 |
| 35 namespace blink { | 31 namespace blink { |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 86 SecurityOrigin*, | 82 SecurityOrigin*, |
| 87 const KURL&, | 83 const KURL&, |
| 88 const String&, | 84 const String&, |
| 89 WebSocketHandleClient*)); | 85 WebSocketHandleClient*)); |
| 90 MOCK_METHOD4(Send, | 86 MOCK_METHOD4(Send, |
| 91 void(bool, WebSocketHandle::MessageType, const char*, size_t)); | 87 void(bool, WebSocketHandle::MessageType, const char*, size_t)); |
| 92 MOCK_METHOD1(FlowControl, void(int64_t)); | 88 MOCK_METHOD1(FlowControl, void(int64_t)); |
| 93 MOCK_METHOD2(Close, void(unsigned short, const String&)); | 89 MOCK_METHOD2(Close, void(unsigned short, const String&)); |
| 94 }; | 90 }; |
| 95 | 91 |
| 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 | |
| 114 class DocumentWebSocketChannelTest : public ::testing::Test { | 92 class DocumentWebSocketChannelTest : public ::testing::Test { |
| 115 public: | 93 public: |
| 116 DocumentWebSocketChannelTest() | 94 DocumentWebSocketChannelTest() |
| 117 : page_holder_(DummyPageHolder::Create()), | 95 : page_holder_(DummyPageHolder::Create()), |
| 118 channel_client_(MockWebSocketChannelClient::Create()), | 96 channel_client_(MockWebSocketChannelClient::Create()), |
| 119 handle_(MockWebSocketHandle::Create()), | 97 handle_(MockWebSocketHandle::Create()), |
| 120 handshake_throttle_(nullptr), | 98 channel_(DocumentWebSocketChannel::Create(&page_holder_->GetDocument(), |
| 99 channel_client_.Get(), |
| 100 SourceLocation::Capture(), |
| 101 Handle())), |
| 121 sum_of_consumed_buffered_amount_(0) { | 102 sum_of_consumed_buffered_amount_(0) { |
| 122 ON_CALL(*ChannelClient(), DidConsumeBufferedAmount(_)) | 103 ON_CALL(*ChannelClient(), DidConsumeBufferedAmount(_)) |
| 123 .WillByDefault(Invoke( | 104 .WillByDefault(Invoke( |
| 124 this, &DocumentWebSocketChannelTest::DidConsumeBufferedAmount)); | 105 this, &DocumentWebSocketChannelTest::DidConsumeBufferedAmount)); |
| 125 } | 106 } |
| 126 | 107 |
| 127 ~DocumentWebSocketChannelTest() { Channel()->Disconnect(); } | 108 ~DocumentWebSocketChannelTest() { Channel()->Disconnect(); } |
| 128 | 109 |
| 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 | |
| 136 MockWebSocketChannelClient* ChannelClient() { return channel_client_.Get(); } | 110 MockWebSocketChannelClient* ChannelClient() { return channel_client_.Get(); } |
| 137 | 111 |
| 138 WebSocketChannel* Channel() { | 112 WebSocketChannel* Channel() { |
| 139 return static_cast<WebSocketChannel*>(channel_.Get()); | 113 return static_cast<WebSocketChannel*>(channel_.Get()); |
| 140 } | 114 } |
| 141 | 115 |
| 142 WebSocketHandleClient* HandleClient() { | 116 WebSocketHandleClient* HandleClient() { |
| 143 return static_cast<WebSocketHandleClient*>(channel_.Get()); | 117 return static_cast<WebSocketHandleClient*>(channel_.Get()); |
| 144 } | 118 } |
| 145 | 119 |
| 146 WebCallbacks<void, const WebString&>* WebCallbacks() { | |
| 147 return channel_.Get(); | |
| 148 } | |
| 149 | |
| 150 MockWebSocketHandle* Handle() { return handle_; } | 120 MockWebSocketHandle* Handle() { return handle_; } |
| 151 | 121 |
| 152 void DidConsumeBufferedAmount(unsigned long a) { | 122 void DidConsumeBufferedAmount(unsigned long a) { |
| 153 sum_of_consumed_buffered_amount_ += a; | 123 sum_of_consumed_buffered_amount_ += a; |
| 154 } | 124 } |
| 155 | 125 |
| 156 void Connect() { | 126 void Connect() { |
| 157 { | 127 { |
| 158 InSequence s; | 128 InSequence s; |
| 159 EXPECT_CALL(*Handle(), Initialize(_)); | 129 EXPECT_CALL(*Handle(), Initialize(_)); |
| 160 EXPECT_CALL(*Handle(), Connect(KURL(KURL(), "ws://localhost/"), _, _, _, | 130 EXPECT_CALL(*Handle(), Connect(KURL(KURL(), "ws://localhost/"), _, _, _, |
| 161 _, HandleClient())); | 131 _, HandleClient())); |
| 162 EXPECT_CALL(*Handle(), FlowControl(65536)); | 132 EXPECT_CALL(*Handle(), FlowControl(65536)); |
| 163 EXPECT_CALL(*ChannelClient(), DidConnect(String("a"), String("b"))); | 133 EXPECT_CALL(*ChannelClient(), DidConnect(String("a"), String("b"))); |
| 164 } | 134 } |
| 165 EXPECT_TRUE(Channel()->Connect(KURL(KURL(), "ws://localhost/"), "x")); | 135 EXPECT_TRUE(Channel()->Connect(KURL(KURL(), "ws://localhost/"), "x")); |
| 166 HandleClient()->DidConnect(Handle(), String("a"), String("b")); | 136 HandleClient()->DidConnect(Handle(), String("a"), String("b")); |
| 167 ::testing::Mock::VerifyAndClearExpectations(this); | 137 ::testing::Mock::VerifyAndClearExpectations(this); |
| 168 } | 138 } |
| 169 | 139 |
| 170 std::unique_ptr<DummyPageHolder> page_holder_; | 140 std::unique_ptr<DummyPageHolder> page_holder_; |
| 171 Persistent<MockWebSocketChannelClient> channel_client_; | 141 Persistent<MockWebSocketChannelClient> channel_client_; |
| 172 MockWebSocketHandle* handle_; | 142 MockWebSocketHandle* handle_; |
| 173 // |handshake_throttle_| is owned by |channel_| once SetUp() has been called. | |
| 174 MockWebSocketHandshakeThrottle* handshake_throttle_; | |
| 175 Persistent<DocumentWebSocketChannel> channel_; | 143 Persistent<DocumentWebSocketChannel> channel_; |
| 176 unsigned long sum_of_consumed_buffered_amount_; | 144 unsigned long sum_of_consumed_buffered_amount_; |
| 177 }; | 145 }; |
| 178 | 146 |
| 179 MATCHER_P2(MemEq, | 147 MATCHER_P2(MemEq, |
| 180 p, | 148 p, |
| 181 len, | 149 len, |
| 182 std::string("pointing to memory") + (negation ? " not" : "") + | 150 std::string("pointing to memory") + (negation ? " not" : "") + |
| 183 " equal to \"" + | 151 " equal to \"" + |
| 184 std::string(p, len) + | 152 std::string(p, len) + |
| (...skipping 615 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 800 EXPECT_CALL( | 768 EXPECT_CALL( |
| 801 *ChannelClient(), | 769 *ChannelClient(), |
| 802 DidClose(WebSocketChannelClient::kClosingHandshakeIncomplete, | 770 DidClose(WebSocketChannelClient::kClosingHandshakeIncomplete, |
| 803 WebSocketChannel::kCloseEventCodeAbnormalClosure, String())); | 771 WebSocketChannel::kCloseEventCodeAbnormalClosure, String())); |
| 804 } | 772 } |
| 805 | 773 |
| 806 Channel()->Fail("fail message from WebSocket", kErrorMessageLevel, | 774 Channel()->Fail("fail message from WebSocket", kErrorMessageLevel, |
| 807 SourceLocation::Create(String(), 0, 0, nullptr)); | 775 SourceLocation::Create(String(), 0, 0, nullptr)); |
| 808 } | 776 } |
| 809 | 777 |
| 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 | |
| 1025 } // namespace | 778 } // namespace |
| 1026 | 779 |
| 1027 } // namespace blink | 780 } // namespace blink |
| OLD | NEW |