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

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

Issue 565573002: Implement handshake timeout on WebSocket (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 3 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_stream.h" 5 #include "net/websockets/websocket_stream.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <string> 8 #include <string>
9 #include <utility> 9 #include <utility>
10 #include <vector> 10 #include <vector>
11 11
12 #include "base/compiler_specific.h" 12 #include "base/compiler_specific.h"
13 #include "base/memory/scoped_vector.h" 13 #include "base/memory/scoped_vector.h"
14 #include "base/metrics/histogram.h" 14 #include "base/metrics/histogram.h"
15 #include "base/metrics/histogram_samples.h" 15 #include "base/metrics/histogram_samples.h"
16 #include "base/metrics/statistics_recorder.h" 16 #include "base/metrics/statistics_recorder.h"
17 #include "base/run_loop.h" 17 #include "base/run_loop.h"
18 #include "base/strings/stringprintf.h" 18 #include "base/strings/stringprintf.h"
19 #include "base/timer/mock_timer.h"
20 #include "base/timer/timer.h"
19 #include "net/base/net_errors.h" 21 #include "net/base/net_errors.h"
20 #include "net/base/test_data_directory.h" 22 #include "net/base/test_data_directory.h"
21 #include "net/http/http_request_headers.h" 23 #include "net/http/http_request_headers.h"
22 #include "net/http/http_response_headers.h" 24 #include "net/http/http_response_headers.h"
23 #include "net/socket/client_socket_handle.h" 25 #include "net/socket/client_socket_handle.h"
24 #include "net/socket/socket_test_util.h" 26 #include "net/socket/socket_test_util.h"
25 #include "net/test/cert_test_util.h" 27 #include "net/test/cert_test_util.h"
26 #include "net/url_request/url_request_test_util.h" 28 #include "net/url_request/url_request_test_util.h"
27 #include "net/websockets/websocket_basic_handshake_stream.h" 29 #include "net/websockets/websocket_basic_handshake_stream.h"
28 #include "net/websockets/websocket_frame.h" 30 #include "net/websockets/websocket_frame.h"
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
72 socket_data->SetStop(reads_count + writes_count); 74 socket_data->SetStop(reads_count + writes_count);
73 return socket_data.Pass(); 75 return socket_data.Pass();
74 } 76 }
75 77
76 // Builder for a DeterministicSocketData that expects nothing. This does not 78 // Builder for a DeterministicSocketData that expects nothing. This does not
77 // set the connect data, so the calling code must do that explicitly. 79 // set the connect data, so the calling code must do that explicitly.
78 scoped_ptr<DeterministicSocketData> BuildNullSocketData() { 80 scoped_ptr<DeterministicSocketData> BuildNullSocketData() {
79 return make_scoped_ptr(new DeterministicSocketData(NULL, 0, NULL, 0)); 81 return make_scoped_ptr(new DeterministicSocketData(NULL, 0, NULL, 0));
80 } 82 }
81 83
84 class MockWeakTimer : public base::MockTimer,
85 public base::SupportsWeakPtr<MockWeakTimer> {
86 public:
87 MockWeakTimer(bool retain_user_task, bool is_repeating)
88 : MockTimer(retain_user_task, is_repeating) {}
89 };
90
82 // A sub-class of WebSocketHandshakeStreamCreateHelper which always sets a 91 // A sub-class of WebSocketHandshakeStreamCreateHelper which always sets a
83 // deterministic key to use in the WebSocket handshake. 92 // deterministic key to use in the WebSocket handshake.
84 class DeterministicKeyWebSocketHandshakeStreamCreateHelper 93 class DeterministicKeyWebSocketHandshakeStreamCreateHelper
85 : public WebSocketHandshakeStreamCreateHelper { 94 : public WebSocketHandshakeStreamCreateHelper {
86 public: 95 public:
87 DeterministicKeyWebSocketHandshakeStreamCreateHelper( 96 DeterministicKeyWebSocketHandshakeStreamCreateHelper(
88 WebSocketStream::ConnectDelegate* connect_delegate, 97 WebSocketStream::ConnectDelegate* connect_delegate,
89 const std::vector<std::string>& requested_subprotocols) 98 const std::vector<std::string>& requested_subprotocols)
90 : WebSocketHandshakeStreamCreateHelper(connect_delegate, 99 : WebSocketHandshakeStreamCreateHelper(connect_delegate,
91 requested_subprotocols) {} 100 requested_subprotocols) {}
92 101
93 virtual void OnStreamCreated(WebSocketBasicHandshakeStream* stream) OVERRIDE { 102 virtual void OnStreamCreated(WebSocketBasicHandshakeStream* stream) OVERRIDE {
94 stream->SetWebSocketKeyForTesting("dGhlIHNhbXBsZSBub25jZQ=="); 103 stream->SetWebSocketKeyForTesting("dGhlIHNhbXBsZSBub25jZQ==");
95 } 104 }
96 }; 105 };
97 106
98 class WebSocketStreamCreateTest : public ::testing::Test { 107 class WebSocketStreamCreateTest : public ::testing::Test {
99 public: 108 public:
100 WebSocketStreamCreateTest() : has_failed_(false), ssl_fatal_(false) {} 109 WebSocketStreamCreateTest() : has_failed_(false), ssl_fatal_(false) {}
101 110
102 void CreateAndConnectCustomResponse( 111 void CreateAndConnectCustomResponse(
103 const std::string& socket_url, 112 const std::string& socket_url,
104 const std::string& socket_path, 113 const std::string& socket_path,
105 const std::vector<std::string>& sub_protocols, 114 const std::vector<std::string>& sub_protocols,
106 const std::string& origin, 115 const std::string& origin,
107 const std::string& extra_request_headers, 116 const std::string& extra_request_headers,
108 const std::string& response_body) { 117 const std::string& response_body,
118 scoped_ptr<base::Timer> timer = scoped_ptr<base::Timer>()) {
109 url_request_context_host_.SetExpectations( 119 url_request_context_host_.SetExpectations(
110 WebSocketStandardRequest(socket_path, origin, extra_request_headers), 120 WebSocketStandardRequest(socket_path, origin, extra_request_headers),
111 response_body); 121 response_body);
112 CreateAndConnectStream(socket_url, sub_protocols, origin); 122 CreateAndConnectStream(socket_url, sub_protocols, origin, timer.Pass());
113 } 123 }
114 124
115 // |extra_request_headers| and |extra_response_headers| must end in "\r\n" or 125 // |extra_request_headers| and |extra_response_headers| must end in "\r\n" or
116 // errors like "Unable to perform synchronous IO while stopped" will occur. 126 // errors like "Unable to perform synchronous IO while stopped" will occur.
117 void CreateAndConnectStandard(const std::string& socket_url, 127 void CreateAndConnectStandard(const std::string& socket_url,
118 const std::string& socket_path, 128 const std::string& socket_path,
119 const std::vector<std::string>& sub_protocols, 129 const std::vector<std::string>& sub_protocols,
120 const std::string& origin, 130 const std::string& origin,
121 const std::string& extra_request_headers, 131 const std::string& extra_request_headers,
122 const std::string& extra_response_headers) { 132 const std::string& extra_response_headers,
133 scoped_ptr<base::Timer> timer =
134 scoped_ptr<base::Timer>()) {
123 CreateAndConnectCustomResponse( 135 CreateAndConnectCustomResponse(
124 socket_url, 136 socket_url,
125 socket_path, 137 socket_path,
126 sub_protocols, 138 sub_protocols,
127 origin, 139 origin,
128 extra_request_headers, 140 extra_request_headers,
129 WebSocketStandardResponse(extra_response_headers)); 141 WebSocketStandardResponse(extra_response_headers),
142 timer.Pass());
130 } 143 }
131 144
132 void CreateAndConnectRawExpectations( 145 void CreateAndConnectRawExpectations(
133 const std::string& socket_url, 146 const std::string& socket_url,
134 const std::vector<std::string>& sub_protocols, 147 const std::vector<std::string>& sub_protocols,
135 const std::string& origin, 148 const std::string& origin,
136 scoped_ptr<DeterministicSocketData> socket_data) { 149 scoped_ptr<DeterministicSocketData> socket_data,
150 scoped_ptr<base::Timer> timer = scoped_ptr<base::Timer>()) {
137 AddRawExpectations(socket_data.Pass()); 151 AddRawExpectations(socket_data.Pass());
138 CreateAndConnectStream(socket_url, sub_protocols, origin); 152 CreateAndConnectStream(socket_url, sub_protocols, origin, timer.Pass());
139 } 153 }
140 154
141 // Add additional raw expectations for sockets created before the final one. 155 // Add additional raw expectations for sockets created before the final one.
142 void AddRawExpectations(scoped_ptr<DeterministicSocketData> socket_data) { 156 void AddRawExpectations(scoped_ptr<DeterministicSocketData> socket_data) {
143 url_request_context_host_.AddRawExpectations(socket_data.Pass()); 157 url_request_context_host_.AddRawExpectations(socket_data.Pass());
144 } 158 }
145 159
146 // A wrapper for CreateAndConnectStreamForTesting that knows about our default 160 // A wrapper for CreateAndConnectStreamForTesting that knows about our default
147 // parameters. 161 // parameters.
148 void CreateAndConnectStream(const std::string& socket_url, 162 void CreateAndConnectStream(const std::string& socket_url,
149 const std::vector<std::string>& sub_protocols, 163 const std::vector<std::string>& sub_protocols,
150 const std::string& origin) { 164 const std::string& origin,
165 scoped_ptr<base::Timer> timer) {
151 for (size_t i = 0; i < ssl_data_.size(); ++i) { 166 for (size_t i = 0; i < ssl_data_.size(); ++i) {
152 scoped_ptr<SSLSocketDataProvider> ssl_data(ssl_data_[i]); 167 scoped_ptr<SSLSocketDataProvider> ssl_data(ssl_data_[i]);
153 ssl_data_[i] = NULL; 168 ssl_data_[i] = NULL;
154 url_request_context_host_.AddSSLSocketDataProvider(ssl_data.Pass()); 169 url_request_context_host_.AddSSLSocketDataProvider(ssl_data.Pass());
155 } 170 }
156 ssl_data_.clear(); 171 ssl_data_.clear();
157 scoped_ptr<WebSocketStream::ConnectDelegate> connect_delegate( 172 scoped_ptr<WebSocketStream::ConnectDelegate> connect_delegate(
158 new TestConnectDelegate(this)); 173 new TestConnectDelegate(this));
159 WebSocketStream::ConnectDelegate* delegate = connect_delegate.get(); 174 WebSocketStream::ConnectDelegate* delegate = connect_delegate.get();
160 scoped_ptr<WebSocketHandshakeStreamCreateHelper> create_helper( 175 scoped_ptr<WebSocketHandshakeStreamCreateHelper> create_helper(
161 new DeterministicKeyWebSocketHandshakeStreamCreateHelper( 176 new DeterministicKeyWebSocketHandshakeStreamCreateHelper(
162 delegate, sub_protocols)); 177 delegate, sub_protocols));
163 stream_request_ = ::net::CreateAndConnectStreamForTesting( 178 stream_request_ = ::net::CreateAndConnectStreamForTesting(
164 GURL(socket_url), 179 GURL(socket_url),
165 create_helper.Pass(), 180 create_helper.Pass(),
166 url::Origin(origin), 181 url::Origin(origin),
167 url_request_context_host_.GetURLRequestContext(), 182 url_request_context_host_.GetURLRequestContext(),
168 BoundNetLog(), 183 BoundNetLog(),
169 connect_delegate.Pass()); 184 connect_delegate.Pass(),
185 timer ? timer.Pass() : scoped_ptr<base::Timer>(
186 new base::Timer(false, false)));
170 } 187 }
171 188
172 static void RunUntilIdle() { base::RunLoop().RunUntilIdle(); } 189 static void RunUntilIdle() { base::RunLoop().RunUntilIdle(); }
173 190
174 // A simple function to make the tests more readable. Creates an empty vector. 191 // A simple function to make the tests more readable. Creates an empty vector.
175 static std::vector<std::string> NoSubProtocols() { 192 static std::vector<std::string> NoSubProtocols() {
176 return std::vector<std::string>(); 193 return std::vector<std::string>();
177 } 194 }
178 195
179 const std::string& failure_message() const { return failure_message_; } 196 const std::string& failure_message() const { return failure_message_; }
(...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after
397 scoped_ptr<base::HistogramSamples> GetSamples(const std::string& name) { 414 scoped_ptr<base::HistogramSamples> GetSamples(const std::string& name) {
398 base::HistogramBase* histogram = 415 base::HistogramBase* histogram =
399 base::StatisticsRecorder::FindHistogram(name); 416 base::StatisticsRecorder::FindHistogram(name);
400 return histogram ? histogram->SnapshotSamples() 417 return histogram ? histogram->SnapshotSamples()
401 : scoped_ptr<base::HistogramSamples>(); 418 : scoped_ptr<base::HistogramSamples>();
402 } 419 }
403 }; 420 };
404 421
405 // Confirm that the basic case works as expected. 422 // Confirm that the basic case works as expected.
406 TEST_F(WebSocketStreamCreateTest, SimpleSuccess) { 423 TEST_F(WebSocketStreamCreateTest, SimpleSuccess) {
424 scoped_ptr<MockWeakTimer> timer(new MockWeakTimer(false, false));
Adam Rice 2014/09/11 07:52:42 You should create a separate test that the timer r
yhirano 2014/09/11 08:45:36 Done.
425 base::WeakPtr<MockWeakTimer> weak_timer = timer->AsWeakPtr();
426
407 CreateAndConnectStandard( 427 CreateAndConnectStandard(
408 "ws://localhost/", "/", NoSubProtocols(), "http://localhost", "", ""); 428 "ws://localhost/", "/", NoSubProtocols(), "http://localhost", "", "",
429 timer.PassAs<base::Timer>());
409 EXPECT_FALSE(request_info_); 430 EXPECT_FALSE(request_info_);
410 EXPECT_FALSE(response_info_); 431 EXPECT_FALSE(response_info_);
432 ASSERT_TRUE(weak_timer);
433 EXPECT_TRUE(weak_timer->IsRunning());
434
411 RunUntilIdle(); 435 RunUntilIdle();
412 EXPECT_FALSE(has_failed()); 436 EXPECT_FALSE(has_failed());
413 EXPECT_TRUE(stream_); 437 EXPECT_TRUE(stream_);
414 EXPECT_TRUE(request_info_); 438 EXPECT_TRUE(request_info_);
415 EXPECT_TRUE(response_info_); 439 EXPECT_TRUE(response_info_);
440 ASSERT_TRUE(weak_timer);
441 EXPECT_FALSE(weak_timer->IsRunning());
416 } 442 }
417 443
418 TEST_F(WebSocketStreamCreateTest, HandshakeInfo) { 444 TEST_F(WebSocketStreamCreateTest, HandshakeInfo) {
419 static const char kResponse[] = 445 static const char kResponse[] =
420 "HTTP/1.1 101 Switching Protocols\r\n" 446 "HTTP/1.1 101 Switching Protocols\r\n"
421 "Upgrade: websocket\r\n" 447 "Upgrade: websocket\r\n"
422 "Connection: Upgrade\r\n" 448 "Connection: Upgrade\r\n"
423 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n" 449 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
424 "foo: bar, baz\r\n" 450 "foo: bar, baz\r\n"
425 "hoge: fuga\r\n" 451 "hoge: fuga\r\n"
(...skipping 642 matching lines...) Expand 10 before | Expand all | Expand 10 after
1068 EXPECT_FALSE(stream_); 1094 EXPECT_FALSE(stream_);
1069 EXPECT_FALSE(request_info_); 1095 EXPECT_FALSE(request_info_);
1070 EXPECT_FALSE(response_info_); 1096 EXPECT_FALSE(response_info_);
1071 } 1097 }
1072 1098
1073 // Connect failure must look just like negotiation failure. 1099 // Connect failure must look just like negotiation failure.
1074 TEST_F(WebSocketStreamCreateTest, ConnectionFailure) { 1100 TEST_F(WebSocketStreamCreateTest, ConnectionFailure) {
1075 scoped_ptr<DeterministicSocketData> socket_data(BuildNullSocketData()); 1101 scoped_ptr<DeterministicSocketData> socket_data(BuildNullSocketData());
1076 socket_data->set_connect_data( 1102 socket_data->set_connect_data(
1077 MockConnect(SYNCHRONOUS, ERR_CONNECTION_REFUSED)); 1103 MockConnect(SYNCHRONOUS, ERR_CONNECTION_REFUSED));
1104 scoped_ptr<MockWeakTimer> timer(new MockWeakTimer(false, false));
1105 base::WeakPtr<MockWeakTimer> weak_timer = timer->AsWeakPtr();
1078 CreateAndConnectRawExpectations("ws://localhost/", NoSubProtocols(), 1106 CreateAndConnectRawExpectations("ws://localhost/", NoSubProtocols(),
1079 "http://localhost", socket_data.Pass()); 1107 "http://localhost", socket_data.Pass(),
1108 timer.PassAs<base::Timer>());
1109 ASSERT_TRUE(weak_timer.get());
1110 EXPECT_TRUE(weak_timer->IsRunning());
1111
1080 RunUntilIdle(); 1112 RunUntilIdle();
1081 EXPECT_TRUE(has_failed()); 1113 EXPECT_TRUE(has_failed());
1082 EXPECT_EQ("Error in connection establishment: net::ERR_CONNECTION_REFUSED", 1114 EXPECT_EQ("Error in connection establishment: net::ERR_CONNECTION_REFUSED",
1083 failure_message()); 1115 failure_message());
1084 EXPECT_FALSE(request_info_); 1116 EXPECT_FALSE(request_info_);
1085 EXPECT_FALSE(response_info_); 1117 EXPECT_FALSE(response_info_);
1118 ASSERT_TRUE(weak_timer.get());
1119 EXPECT_FALSE(weak_timer->IsRunning());
1086 } 1120 }
1087 1121
1088 // Connect timeout must look just like any other failure. 1122 // Connect timeout must look just like any other failure.
1089 TEST_F(WebSocketStreamCreateTest, ConnectionTimeout) { 1123 TEST_F(WebSocketStreamCreateTest, ConnectionTimeout) {
1090 scoped_ptr<DeterministicSocketData> socket_data(BuildNullSocketData()); 1124 scoped_ptr<DeterministicSocketData> socket_data(BuildNullSocketData());
1091 socket_data->set_connect_data( 1125 socket_data->set_connect_data(
1092 MockConnect(ASYNC, ERR_CONNECTION_TIMED_OUT)); 1126 MockConnect(ASYNC, ERR_CONNECTION_TIMED_OUT));
1093 CreateAndConnectRawExpectations("ws://localhost/", NoSubProtocols(), 1127 CreateAndConnectRawExpectations("ws://localhost/", NoSubProtocols(),
1094 "http://localhost", socket_data.Pass()); 1128 "http://localhost", socket_data.Pass());
1095 RunUntilIdle(); 1129 RunUntilIdle();
1096 EXPECT_TRUE(has_failed()); 1130 EXPECT_TRUE(has_failed());
1097 EXPECT_EQ("Error in connection establishment: net::ERR_CONNECTION_TIMED_OUT", 1131 EXPECT_EQ("Error in connection establishment: net::ERR_CONNECTION_TIMED_OUT",
1098 failure_message()); 1132 failure_message());
1099 } 1133 }
1100 1134
1135 // The server doesn't respond to the opening handshake.
1136 TEST_F(WebSocketStreamCreateTest, HandshakeTimeout) {
1137 scoped_ptr<DeterministicSocketData> socket_data(BuildNullSocketData());
1138 socket_data->set_connect_data(MockConnect(SYNCHRONOUS, ERR_IO_PENDING));
1139 scoped_ptr<MockWeakTimer> timer(new MockWeakTimer(false, false));
1140 base::WeakPtr<MockWeakTimer> weak_timer = timer->AsWeakPtr();
1141 CreateAndConnectRawExpectations("ws://localhost/", NoSubProtocols(),
1142 "http://localhost", socket_data.Pass(),
1143 timer.PassAs<base::Timer>());
1144 EXPECT_FALSE(has_failed());
1145 ASSERT_TRUE(weak_timer.get());
1146 EXPECT_TRUE(weak_timer->IsRunning());
1147
1148 weak_timer->Fire();
1149 RunUntilIdle();
1150
1151 EXPECT_TRUE(has_failed());
1152 EXPECT_EQ("WebSocket opening handshake timed out", failure_message());
1153 ASSERT_TRUE(weak_timer.get());
1154 EXPECT_FALSE(weak_timer->IsRunning());
1155 }
1156
1101 // Cancellation during connect works. 1157 // Cancellation during connect works.
1102 TEST_F(WebSocketStreamCreateTest, CancellationDuringConnect) { 1158 TEST_F(WebSocketStreamCreateTest, CancellationDuringConnect) {
1103 scoped_ptr<DeterministicSocketData> socket_data(BuildNullSocketData()); 1159 scoped_ptr<DeterministicSocketData> socket_data(BuildNullSocketData());
1104 socket_data->set_connect_data(MockConnect(SYNCHRONOUS, ERR_IO_PENDING)); 1160 socket_data->set_connect_data(MockConnect(SYNCHRONOUS, ERR_IO_PENDING));
1105 CreateAndConnectRawExpectations("ws://localhost/", 1161 CreateAndConnectRawExpectations("ws://localhost/",
1106 NoSubProtocols(), 1162 NoSubProtocols(),
1107 "http://localhost", 1163 "http://localhost",
1108 socket_data.Pass()); 1164 socket_data.Pass());
1109 stream_request_.reset(); 1165 stream_request_.reset();
1110 RunUntilIdle(); 1166 RunUntilIdle();
(...skipping 256 matching lines...) Expand 10 before | Expand all | Expand 10 after
1367 if (original) { 1423 if (original) {
1368 samples->Subtract(*original); // Cancel the original values. 1424 samples->Subtract(*original); // Cancel the original values.
1369 } 1425 }
1370 EXPECT_EQ(1, samples->GetCount(INCOMPLETE)); 1426 EXPECT_EQ(1, samples->GetCount(INCOMPLETE));
1371 EXPECT_EQ(0, samples->GetCount(CONNECTED)); 1427 EXPECT_EQ(0, samples->GetCount(CONNECTED));
1372 EXPECT_EQ(0, samples->GetCount(FAILED)); 1428 EXPECT_EQ(0, samples->GetCount(FAILED));
1373 } 1429 }
1374 1430
1375 } // namespace 1431 } // namespace
1376 } // namespace net 1432 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698