OLD | NEW |
---|---|
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> |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
48 | 48 |
49 std::vector<HeaderKeyValuePair> ToVector(const HttpResponseHeaders& headers) { | 49 std::vector<HeaderKeyValuePair> ToVector(const HttpResponseHeaders& headers) { |
50 void* iter = NULL; | 50 void* iter = NULL; |
51 std::string name, value; | 51 std::string name, value; |
52 std::vector<HeaderKeyValuePair> result; | 52 std::vector<HeaderKeyValuePair> result; |
53 while (headers.EnumerateHeaderLines(&iter, &name, &value)) | 53 while (headers.EnumerateHeaderLines(&iter, &name, &value)) |
54 result.push_back(HeaderKeyValuePair(name, value)); | 54 result.push_back(HeaderKeyValuePair(name, value)); |
55 return result; | 55 return result; |
56 } | 56 } |
57 | 57 |
58 // Simple builder for a DeterministicSocketData object to save repetitive code. | |
59 // It always sets the connect data to MockConnect(SYNCHRONOUS, OK), so it cannot | |
60 // be used in tests where the connect fails. In practice, those tests never have | |
61 // any read/write data and so can't benefit from it anyway. The arrays are not | |
62 // copied. It is up to the caller to ensure they stay in scope until the test | |
63 // ends. | |
64 template <size_t reads_count, size_t writes_count> | |
65 scoped_ptr<DeterministicSocketData> BuildSocketData( | |
66 MockRead (&reads)[reads_count], | |
67 MockWrite (&writes)[writes_count]) { | |
68 scoped_ptr<DeterministicSocketData> socket_data( | |
69 new DeterministicSocketData(reads, reads_count, writes, writes_count)); | |
70 socket_data->set_connect_data(MockConnect(SYNCHRONOUS, OK)); | |
71 socket_data->SetStop(reads_count + writes_count); | |
72 return socket_data.Pass(); | |
73 } | |
74 | |
75 // Builder for a DeterministicSocketData that expects nothing. This does not | |
76 // set the connect data, so the calling code must do that explicitly. | |
77 scoped_ptr<DeterministicSocketData> BuildNullSocketData() { | |
78 return make_scoped_ptr(new DeterministicSocketData(NULL, 0, NULL, 0)); | |
79 } | |
80 | |
58 // A sub-class of WebSocketHandshakeStreamCreateHelper which always sets a | 81 // A sub-class of WebSocketHandshakeStreamCreateHelper which always sets a |
59 // deterministic key to use in the WebSocket handshake. | 82 // deterministic key to use in the WebSocket handshake. |
60 class DeterministicKeyWebSocketHandshakeStreamCreateHelper | 83 class DeterministicKeyWebSocketHandshakeStreamCreateHelper |
61 : public WebSocketHandshakeStreamCreateHelper { | 84 : public WebSocketHandshakeStreamCreateHelper { |
62 public: | 85 public: |
63 DeterministicKeyWebSocketHandshakeStreamCreateHelper( | 86 DeterministicKeyWebSocketHandshakeStreamCreateHelper( |
64 WebSocketStream::ConnectDelegate* connect_delegate, | 87 WebSocketStream::ConnectDelegate* connect_delegate, |
65 const std::vector<std::string>& requested_subprotocols) | 88 const std::vector<std::string>& requested_subprotocols) |
66 : WebSocketHandshakeStreamCreateHelper(connect_delegate, | 89 : WebSocketHandshakeStreamCreateHelper(connect_delegate, |
67 requested_subprotocols) {} | 90 requested_subprotocols) {} |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
111 origin, | 134 origin, |
112 extra_request_headers, | 135 extra_request_headers, |
113 WebSocketStandardResponse(extra_response_headers)); | 136 WebSocketStandardResponse(extra_response_headers)); |
114 } | 137 } |
115 | 138 |
116 void CreateAndConnectRawExpectations( | 139 void CreateAndConnectRawExpectations( |
117 const std::string& socket_url, | 140 const std::string& socket_url, |
118 const std::vector<std::string>& sub_protocols, | 141 const std::vector<std::string>& sub_protocols, |
119 const std::string& origin, | 142 const std::string& origin, |
120 scoped_ptr<DeterministicSocketData> socket_data) { | 143 scoped_ptr<DeterministicSocketData> socket_data) { |
144 AddRawExpectations(socket_data.Pass()); | |
145 CreateAndConnectStream(socket_url, sub_protocols, origin); | |
146 } | |
147 | |
148 // Add additional raw expectations for sockets created before the final one. | |
149 void AddRawExpectations(scoped_ptr<DeterministicSocketData> socket_data) { | |
121 url_request_context_host_.AddRawExpectations(socket_data.Pass()); | 150 url_request_context_host_.AddRawExpectations(socket_data.Pass()); |
122 CreateAndConnectStream(socket_url, sub_protocols, origin); | |
123 } | 151 } |
124 | 152 |
125 // A wrapper for CreateAndConnectStreamForTesting that knows about our default | 153 // A wrapper for CreateAndConnectStreamForTesting that knows about our default |
126 // parameters. | 154 // parameters. |
127 void CreateAndConnectStream(const std::string& socket_url, | 155 void CreateAndConnectStream(const std::string& socket_url, |
128 const std::vector<std::string>& sub_protocols, | 156 const std::vector<std::string>& sub_protocols, |
129 const std::string& origin) { | 157 const std::string& origin) { |
130 for (size_t i = 0; i < ssl_data_.size(); ++i) { | 158 for (size_t i = 0; i < ssl_data_.size(); ++i) { |
131 scoped_ptr<SSLSocketDataProvider> ssl_data(ssl_data_[i]); | 159 scoped_ptr<SSLSocketDataProvider> ssl_data(ssl_data_[i]); |
132 ssl_data_[i] = NULL; | 160 ssl_data_[i] = NULL; |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
167 stream.swap(owner_->stream_); | 195 stream.swap(owner_->stream_); |
168 } | 196 } |
169 | 197 |
170 virtual void OnFailure(const std::string& message) OVERRIDE { | 198 virtual void OnFailure(const std::string& message) OVERRIDE { |
171 owner_->has_failed_ = true; | 199 owner_->has_failed_ = true; |
172 owner_->failure_message_ = message; | 200 owner_->failure_message_ = message; |
173 } | 201 } |
174 | 202 |
175 virtual void OnStartOpeningHandshake( | 203 virtual void OnStartOpeningHandshake( |
176 scoped_ptr<WebSocketHandshakeRequestInfo> request) OVERRIDE { | 204 scoped_ptr<WebSocketHandshakeRequestInfo> request) OVERRIDE { |
177 if (owner_->request_info_) | 205 // Can be called multiple times (in the case of HTTP auth). Last call |
178 ADD_FAILURE(); | 206 // wins. |
179 owner_->request_info_ = request.Pass(); | 207 owner_->request_info_ = request.Pass(); |
180 } | 208 } |
181 virtual void OnFinishOpeningHandshake( | 209 virtual void OnFinishOpeningHandshake( |
182 scoped_ptr<WebSocketHandshakeResponseInfo> response) OVERRIDE { | 210 scoped_ptr<WebSocketHandshakeResponseInfo> response) OVERRIDE { |
183 if (owner_->response_info_) | 211 if (owner_->response_info_) |
184 ADD_FAILURE(); | 212 ADD_FAILURE(); |
185 owner_->response_info_ = response.Pass(); | 213 owner_->response_info_ = response.Pass(); |
186 } | 214 } |
187 virtual void OnSSLCertificateError( | 215 virtual void OnSSLCertificateError( |
188 scoped_ptr<WebSocketEventInterface::SSLErrorCallbacks> | 216 scoped_ptr<WebSocketEventInterface::SSLErrorCallbacks> |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
226 "ws://localhost/testing_path", | 254 "ws://localhost/testing_path", |
227 "/testing_path", | 255 "/testing_path", |
228 NoSubProtocols(), | 256 NoSubProtocols(), |
229 "http://localhost", | 257 "http://localhost", |
230 "", | 258 "", |
231 "Sec-WebSocket-Extensions: " + extensions_header_value + "\r\n"); | 259 "Sec-WebSocket-Extensions: " + extensions_header_value + "\r\n"); |
232 RunUntilIdle(); | 260 RunUntilIdle(); |
233 } | 261 } |
234 }; | 262 }; |
235 | 263 |
264 // Common code to construct expectations for authentication tests that receive | |
265 // the auth challenge on one connection and then create a second connection to | |
266 // send the authenticated request on. | |
267 class CommonAuthTestHelper { | |
268 public: | |
269 scoped_ptr<DeterministicSocketData> BuildSocketData1( | |
270 const std::string& response) { | |
271 request1 = WebSocketStandardRequest("/", "http://localhost", ""); | |
272 writes1[0] = MockWrite(SYNCHRONOUS, 0, request1.c_str()); | |
273 response1 = response; | |
274 reads1[0] = MockRead(SYNCHRONOUS, 1, response1.c_str()); | |
275 reads1[1] = MockRead(SYNCHRONOUS, OK, 2); // Close connection | |
276 | |
277 return BuildSocketData(reads1, writes1); | |
278 } | |
279 | |
280 scoped_ptr<DeterministicSocketData> BuildSocketData2( | |
281 const std::string& request, | |
282 const std::string& response) { | |
283 request2 = request; | |
284 response2 = response; | |
285 writes2[0] = MockWrite(SYNCHRONOUS, 0, request2.c_str()); | |
286 reads2[0] = MockRead(SYNCHRONOUS, 1, response2.c_str()); | |
287 return BuildSocketData(reads2, writes2); | |
288 } | |
289 | |
290 private: | |
291 // These need to be object-scoped since they have to remain valid until all | |
292 // socket operations in the test are complete. | |
293 std::string request1; | |
Johnny
2014/07/08 20:27:40
Trailing underscores?
Adam Rice
2014/07/09 06:35:01
Okay, that's weird. In my brain this was a struct,
| |
294 std::string request2; | |
295 std::string response1; | |
296 std::string response2; | |
297 MockRead reads1[2]; | |
298 MockWrite writes1[1]; | |
299 MockRead reads2[1]; | |
300 MockWrite writes2[1]; | |
301 }; | |
302 | |
303 // Data and methods for BasicAuth tests. | |
304 class WebSocketStreamCreateBasicAuthTest : public WebSocketStreamCreateTest { | |
305 protected: | |
306 void CreateAndConnectAuthHandshake(const std::string& url, | |
307 const std::string& base64_user_pass, | |
308 const std::string& response2) { | |
309 AddRawExpectations(helper_.BuildSocketData1(kUnauthorizedResponse)); | |
310 | |
311 static const char request2format[] = | |
312 "GET / HTTP/1.1\r\n" | |
313 "Host: localhost\r\n" | |
314 "Connection: Upgrade\r\n" | |
315 "Pragma: no-cache\r\n" | |
316 "Cache-Control: no-cache\r\n" | |
317 "Authorization: Basic %s\r\n" | |
318 "Upgrade: websocket\r\n" | |
319 "Origin: http://localhost\r\n" | |
320 "Sec-WebSocket-Version: 13\r\n" | |
321 "User-Agent:\r\n" | |
322 "Accept-Encoding: gzip,deflate\r\n" | |
323 "Accept-Language: en-us,fr\r\n" | |
324 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" | |
325 "Sec-WebSocket-Extensions: permessage-deflate; " | |
326 "client_max_window_bits\r\n" | |
327 "\r\n"; | |
328 const std::string request = | |
329 base::StringPrintf(request2format, base64_user_pass.c_str()); | |
330 CreateAndConnectRawExpectations( | |
331 url, | |
332 NoSubProtocols(), | |
333 "http://localhost", | |
334 helper_.BuildSocketData2(request, response2)); | |
335 } | |
336 | |
337 static const char kUnauthorizedResponse[]; | |
338 | |
339 CommonAuthTestHelper helper_; | |
340 }; | |
341 | |
342 class WebSocketStreamCreateDigestAuthTest : public WebSocketStreamCreateTest { | |
343 protected: | |
344 static const char kUnauthorizedResponse[]; | |
345 static const char kAuthorizedRequest[]; | |
346 | |
347 CommonAuthTestHelper helper_; | |
348 }; | |
349 | |
350 const char WebSocketStreamCreateBasicAuthTest::kUnauthorizedResponse[] = | |
351 "HTTP/1.1 401 Unauthorized\r\n" | |
352 "Content-Length: 0\r\n" | |
353 "WWW-Authenticate: Basic realm=\"camelot\"\r\n" | |
354 "\r\n"; | |
355 | |
356 // These negotiation values are borrowed from | |
357 // http_auth_handler_digest_unittest.cc. Feel free to come up with new ones if | |
358 // you are bored. Only the weakest (no qop) variants of Digest authentication | |
359 // can be tested by this method, because the others involve random input. | |
360 const char WebSocketStreamCreateDigestAuthTest::kUnauthorizedResponse[] = | |
361 "HTTP/1.1 401 Unauthorized\r\n" | |
362 "Content-Length: 0\r\n" | |
363 "WWW-Authenticate: Digest realm=\"Oblivion\", nonce=\"nonce-value\"\r\n" | |
364 "\r\n"; | |
365 | |
366 const char WebSocketStreamCreateDigestAuthTest::kAuthorizedRequest[] = | |
367 "GET / HTTP/1.1\r\n" | |
368 "Host: localhost\r\n" | |
369 "Connection: Upgrade\r\n" | |
370 "Pragma: no-cache\r\n" | |
371 "Cache-Control: no-cache\r\n" | |
372 "Authorization: Digest username=\"FooBar\", realm=\"Oblivion\", " | |
373 "nonce=\"nonce-value\", uri=\"/\", " | |
374 "response=\"f72ff54ebde2f928860f806ec04acd1b\"\r\n" | |
375 "Upgrade: websocket\r\n" | |
376 "Origin: http://localhost\r\n" | |
377 "Sec-WebSocket-Version: 13\r\n" | |
378 "User-Agent:\r\n" | |
379 "Accept-Encoding: gzip,deflate\r\n" | |
380 "Accept-Language: en-us,fr\r\n" | |
381 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" | |
382 "Sec-WebSocket-Extensions: permessage-deflate; " | |
383 "client_max_window_bits\r\n" | |
384 "\r\n"; | |
385 | |
236 class WebSocketStreamCreateUMATest : public ::testing::Test { | 386 class WebSocketStreamCreateUMATest : public ::testing::Test { |
237 public: | 387 public: |
238 // This enum should match with the enum in Delegate in websocket_stream.cc. | 388 // This enum should match with the enum in Delegate in websocket_stream.cc. |
239 enum HandshakeResult { | 389 enum HandshakeResult { |
240 INCOMPLETE, | 390 INCOMPLETE, |
241 CONNECTED, | 391 CONNECTED, |
242 FAILED, | 392 FAILED, |
243 NUM_HANDSHAKE_RESULT_TYPES, | 393 NUM_HANDSHAKE_RESULT_TYPES, |
244 }; | 394 }; |
245 | 395 |
(...skipping 672 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
918 stream_request_.reset(); | 1068 stream_request_.reset(); |
919 RunUntilIdle(); | 1069 RunUntilIdle(); |
920 EXPECT_FALSE(has_failed()); | 1070 EXPECT_FALSE(has_failed()); |
921 EXPECT_FALSE(stream_); | 1071 EXPECT_FALSE(stream_); |
922 EXPECT_FALSE(request_info_); | 1072 EXPECT_FALSE(request_info_); |
923 EXPECT_FALSE(response_info_); | 1073 EXPECT_FALSE(response_info_); |
924 } | 1074 } |
925 | 1075 |
926 // Connect failure must look just like negotiation failure. | 1076 // Connect failure must look just like negotiation failure. |
927 TEST_F(WebSocketStreamCreateTest, ConnectionFailure) { | 1077 TEST_F(WebSocketStreamCreateTest, ConnectionFailure) { |
928 scoped_ptr<DeterministicSocketData> socket_data( | 1078 scoped_ptr<DeterministicSocketData> socket_data(BuildNullSocketData()); |
929 new DeterministicSocketData(NULL, 0, NULL, 0)); | |
930 socket_data->set_connect_data( | 1079 socket_data->set_connect_data( |
931 MockConnect(SYNCHRONOUS, ERR_CONNECTION_REFUSED)); | 1080 MockConnect(SYNCHRONOUS, ERR_CONNECTION_REFUSED)); |
932 CreateAndConnectRawExpectations("ws://localhost/", NoSubProtocols(), | 1081 CreateAndConnectRawExpectations("ws://localhost/", NoSubProtocols(), |
933 "http://localhost", socket_data.Pass()); | 1082 "http://localhost", socket_data.Pass()); |
934 RunUntilIdle(); | 1083 RunUntilIdle(); |
935 EXPECT_TRUE(has_failed()); | 1084 EXPECT_TRUE(has_failed()); |
936 EXPECT_EQ("Error in connection establishment: net::ERR_CONNECTION_REFUSED", | 1085 EXPECT_EQ("Error in connection establishment: net::ERR_CONNECTION_REFUSED", |
937 failure_message()); | 1086 failure_message()); |
938 EXPECT_FALSE(request_info_); | 1087 EXPECT_FALSE(request_info_); |
939 EXPECT_FALSE(response_info_); | 1088 EXPECT_FALSE(response_info_); |
940 } | 1089 } |
941 | 1090 |
942 // Connect timeout must look just like any other failure. | 1091 // Connect timeout must look just like any other failure. |
943 TEST_F(WebSocketStreamCreateTest, ConnectionTimeout) { | 1092 TEST_F(WebSocketStreamCreateTest, ConnectionTimeout) { |
944 scoped_ptr<DeterministicSocketData> socket_data( | 1093 scoped_ptr<DeterministicSocketData> socket_data(BuildNullSocketData()); |
945 new DeterministicSocketData(NULL, 0, NULL, 0)); | |
946 socket_data->set_connect_data( | 1094 socket_data->set_connect_data( |
947 MockConnect(ASYNC, ERR_CONNECTION_TIMED_OUT)); | 1095 MockConnect(ASYNC, ERR_CONNECTION_TIMED_OUT)); |
948 CreateAndConnectRawExpectations("ws://localhost/", NoSubProtocols(), | 1096 CreateAndConnectRawExpectations("ws://localhost/", NoSubProtocols(), |
949 "http://localhost", socket_data.Pass()); | 1097 "http://localhost", socket_data.Pass()); |
950 RunUntilIdle(); | 1098 RunUntilIdle(); |
951 EXPECT_TRUE(has_failed()); | 1099 EXPECT_TRUE(has_failed()); |
952 EXPECT_EQ("Error in connection establishment: net::ERR_CONNECTION_TIMED_OUT", | 1100 EXPECT_EQ("Error in connection establishment: net::ERR_CONNECTION_TIMED_OUT", |
953 failure_message()); | 1101 failure_message()); |
954 } | 1102 } |
955 | 1103 |
956 // Cancellation during connect works. | 1104 // Cancellation during connect works. |
957 TEST_F(WebSocketStreamCreateTest, CancellationDuringConnect) { | 1105 TEST_F(WebSocketStreamCreateTest, CancellationDuringConnect) { |
958 scoped_ptr<DeterministicSocketData> socket_data( | 1106 scoped_ptr<DeterministicSocketData> socket_data(BuildNullSocketData()); |
959 new DeterministicSocketData(NULL, 0, NULL, 0)); | |
960 socket_data->set_connect_data(MockConnect(SYNCHRONOUS, ERR_IO_PENDING)); | 1107 socket_data->set_connect_data(MockConnect(SYNCHRONOUS, ERR_IO_PENDING)); |
961 CreateAndConnectRawExpectations("ws://localhost/", | 1108 CreateAndConnectRawExpectations("ws://localhost/", |
962 NoSubProtocols(), | 1109 NoSubProtocols(), |
963 "http://localhost", | 1110 "http://localhost", |
964 socket_data.Pass()); | 1111 socket_data.Pass()); |
965 stream_request_.reset(); | 1112 stream_request_.reset(); |
966 RunUntilIdle(); | 1113 RunUntilIdle(); |
967 EXPECT_FALSE(has_failed()); | 1114 EXPECT_FALSE(has_failed()); |
968 EXPECT_FALSE(stream_); | 1115 EXPECT_FALSE(stream_); |
969 } | 1116 } |
(...skipping 21 matching lines...) Expand all Loading... | |
991 EXPECT_FALSE(response_info_); | 1138 EXPECT_FALSE(response_info_); |
992 } | 1139 } |
993 | 1140 |
994 // Cancellation during read of the response headers works. | 1141 // Cancellation during read of the response headers works. |
995 TEST_F(WebSocketStreamCreateTest, CancellationDuringRead) { | 1142 TEST_F(WebSocketStreamCreateTest, CancellationDuringRead) { |
996 std::string request = WebSocketStandardRequest("/", "http://localhost", ""); | 1143 std::string request = WebSocketStandardRequest("/", "http://localhost", ""); |
997 MockWrite writes[] = {MockWrite(ASYNC, 0, request.c_str())}; | 1144 MockWrite writes[] = {MockWrite(ASYNC, 0, request.c_str())}; |
998 MockRead reads[] = { | 1145 MockRead reads[] = { |
999 MockRead(ASYNC, 1, "HTTP/1.1 101 Switching Protocols\r\nUpgr"), | 1146 MockRead(ASYNC, 1, "HTTP/1.1 101 Switching Protocols\r\nUpgr"), |
1000 }; | 1147 }; |
1001 DeterministicSocketData* socket_data(new DeterministicSocketData( | 1148 scoped_ptr<DeterministicSocketData> socket_data( |
1002 reads, arraysize(reads), writes, arraysize(writes))); | 1149 BuildSocketData(reads, writes)); |
1003 socket_data->set_connect_data(MockConnect(SYNCHRONOUS, OK)); | |
1004 socket_data->SetStop(1); | 1150 socket_data->SetStop(1); |
1151 DeterministicSocketData* socket_data_raw_ptr = socket_data.get(); | |
1005 CreateAndConnectRawExpectations("ws://localhost/", | 1152 CreateAndConnectRawExpectations("ws://localhost/", |
1006 NoSubProtocols(), | 1153 NoSubProtocols(), |
1007 "http://localhost", | 1154 "http://localhost", |
1008 make_scoped_ptr(socket_data)); | 1155 socket_data.Pass()); |
Johnny
2014/07/08 20:27:40
Why is ownership of |socket_data| passed to WebSoc
Adam Rice
2014/07/09 06:35:01
Short explanation: WebSocketDeterministicMockClien
Johnny
2014/07/09 16:16:17
SGTM.
| |
1009 socket_data->Run(); | 1156 socket_data_raw_ptr->Run(); |
1010 stream_request_.reset(); | 1157 stream_request_.reset(); |
1011 RunUntilIdle(); | 1158 RunUntilIdle(); |
1012 EXPECT_FALSE(has_failed()); | 1159 EXPECT_FALSE(has_failed()); |
1013 EXPECT_FALSE(stream_); | 1160 EXPECT_FALSE(stream_); |
1014 EXPECT_TRUE(request_info_); | 1161 EXPECT_TRUE(request_info_); |
1015 EXPECT_FALSE(response_info_); | 1162 EXPECT_FALSE(response_info_); |
1016 } | 1163 } |
1017 | 1164 |
1018 // Over-size response headers (> 256KB) should not cause a crash. This is a | 1165 // Over-size response headers (> 256KB) should not cause a crash. This is a |
1019 // regression test for crbug.com/339456. It is based on the layout test | 1166 // regression test for crbug.com/339456. It is based on the layout test |
(...skipping 12 matching lines...) Expand all Loading... | |
1032 EXPECT_FALSE(response_info_); | 1179 EXPECT_FALSE(response_info_); |
1033 } | 1180 } |
1034 | 1181 |
1035 // If the remote host closes the connection without sending headers, we should | 1182 // If the remote host closes the connection without sending headers, we should |
1036 // log the console message "Connection closed before receiving a handshake | 1183 // log the console message "Connection closed before receiving a handshake |
1037 // response". | 1184 // response". |
1038 TEST_F(WebSocketStreamCreateTest, NoResponse) { | 1185 TEST_F(WebSocketStreamCreateTest, NoResponse) { |
1039 std::string request = WebSocketStandardRequest("/", "http://localhost", ""); | 1186 std::string request = WebSocketStandardRequest("/", "http://localhost", ""); |
1040 MockWrite writes[] = {MockWrite(ASYNC, request.data(), request.size(), 0)}; | 1187 MockWrite writes[] = {MockWrite(ASYNC, request.data(), request.size(), 0)}; |
1041 MockRead reads[] = {MockRead(ASYNC, 0, 1)}; | 1188 MockRead reads[] = {MockRead(ASYNC, 0, 1)}; |
1042 DeterministicSocketData* socket_data(new DeterministicSocketData( | 1189 scoped_ptr<DeterministicSocketData> socket_data( |
1043 reads, arraysize(reads), writes, arraysize(writes))); | 1190 BuildSocketData(reads, writes)); |
1044 socket_data->set_connect_data(MockConnect(SYNCHRONOUS, OK)); | 1191 DeterministicSocketData* socket_data_raw_ptr = socket_data.get(); |
1045 CreateAndConnectRawExpectations("ws://localhost/", | 1192 CreateAndConnectRawExpectations("ws://localhost/", |
1046 NoSubProtocols(), | 1193 NoSubProtocols(), |
1047 "http://localhost", | 1194 "http://localhost", |
1048 make_scoped_ptr(socket_data)); | 1195 socket_data.Pass()); |
1049 socket_data->RunFor(2); | 1196 socket_data_raw_ptr->RunFor(2); |
1050 EXPECT_TRUE(has_failed()); | 1197 EXPECT_TRUE(has_failed()); |
1051 EXPECT_FALSE(stream_); | 1198 EXPECT_FALSE(stream_); |
1052 EXPECT_FALSE(response_info_); | 1199 EXPECT_FALSE(response_info_); |
1053 EXPECT_EQ("Connection closed before receiving a handshake response", | 1200 EXPECT_EQ("Connection closed before receiving a handshake response", |
1054 failure_message()); | 1201 failure_message()); |
1055 } | 1202 } |
1056 | 1203 |
1057 TEST_F(WebSocketStreamCreateTest, SelfSignedCertificateFailure) { | 1204 TEST_F(WebSocketStreamCreateTest, SelfSignedCertificateFailure) { |
1058 ssl_data_.push_back( | 1205 ssl_data_.push_back( |
1059 new SSLSocketDataProvider(ASYNC, ERR_CERT_AUTHORITY_INVALID)); | 1206 new SSLSocketDataProvider(ASYNC, ERR_CERT_AUTHORITY_INVALID)); |
1060 ssl_data_[0]->cert = | 1207 ssl_data_[0]->cert = |
1061 ImportCertFromFile(GetTestCertsDirectory(), "unittest.selfsigned.der"); | 1208 ImportCertFromFile(GetTestCertsDirectory(), "unittest.selfsigned.der"); |
1062 ASSERT_TRUE(ssl_data_[0]->cert); | 1209 ASSERT_TRUE(ssl_data_[0]->cert); |
1063 scoped_ptr<DeterministicSocketData> raw_socket_data( | 1210 scoped_ptr<DeterministicSocketData> raw_socket_data(BuildNullSocketData()); |
1064 new DeterministicSocketData(NULL, 0, NULL, 0)); | |
1065 CreateAndConnectRawExpectations("wss://localhost/", | 1211 CreateAndConnectRawExpectations("wss://localhost/", |
1066 NoSubProtocols(), | 1212 NoSubProtocols(), |
1067 "http://localhost", | 1213 "http://localhost", |
1068 raw_socket_data.Pass()); | 1214 raw_socket_data.Pass()); |
1069 RunUntilIdle(); | 1215 RunUntilIdle(); |
1070 EXPECT_FALSE(has_failed()); | 1216 EXPECT_FALSE(has_failed()); |
1071 ASSERT_TRUE(ssl_error_callbacks_); | 1217 ASSERT_TRUE(ssl_error_callbacks_); |
1072 ssl_error_callbacks_->CancelSSLRequest(ERR_CERT_AUTHORITY_INVALID, | 1218 ssl_error_callbacks_->CancelSSLRequest(ERR_CERT_AUTHORITY_INVALID, |
1073 &ssl_info_); | 1219 &ssl_info_); |
1074 RunUntilIdle(); | 1220 RunUntilIdle(); |
1075 EXPECT_TRUE(has_failed()); | 1221 EXPECT_TRUE(has_failed()); |
1076 } | 1222 } |
1077 | 1223 |
1078 TEST_F(WebSocketStreamCreateTest, SelfSignedCertificateSuccess) { | 1224 TEST_F(WebSocketStreamCreateTest, SelfSignedCertificateSuccess) { |
1079 scoped_ptr<SSLSocketDataProvider> ssl_data( | 1225 scoped_ptr<SSLSocketDataProvider> ssl_data( |
1080 new SSLSocketDataProvider(ASYNC, ERR_CERT_AUTHORITY_INVALID)); | 1226 new SSLSocketDataProvider(ASYNC, ERR_CERT_AUTHORITY_INVALID)); |
1081 ssl_data->cert = | 1227 ssl_data->cert = |
1082 ImportCertFromFile(GetTestCertsDirectory(), "unittest.selfsigned.der"); | 1228 ImportCertFromFile(GetTestCertsDirectory(), "unittest.selfsigned.der"); |
1083 ASSERT_TRUE(ssl_data->cert); | 1229 ASSERT_TRUE(ssl_data->cert); |
1084 ssl_data_.push_back(ssl_data.release()); | 1230 ssl_data_.push_back(ssl_data.release()); |
1085 ssl_data.reset(new SSLSocketDataProvider(ASYNC, OK)); | 1231 ssl_data.reset(new SSLSocketDataProvider(ASYNC, OK)); |
1086 ssl_data_.push_back(ssl_data.release()); | 1232 ssl_data_.push_back(ssl_data.release()); |
1087 url_request_context_host_.AddRawExpectations( | 1233 url_request_context_host_.AddRawExpectations(BuildNullSocketData()); |
1088 make_scoped_ptr(new DeterministicSocketData(NULL, 0, NULL, 0))); | |
1089 CreateAndConnectStandard( | 1234 CreateAndConnectStandard( |
1090 "wss://localhost/", "/", NoSubProtocols(), "http://localhost", "", ""); | 1235 "wss://localhost/", "/", NoSubProtocols(), "http://localhost", "", ""); |
1091 RunUntilIdle(); | 1236 RunUntilIdle(); |
1092 ASSERT_TRUE(ssl_error_callbacks_); | 1237 ASSERT_TRUE(ssl_error_callbacks_); |
1093 ssl_error_callbacks_->ContinueSSLRequest(); | 1238 ssl_error_callbacks_->ContinueSSLRequest(); |
1094 RunUntilIdle(); | 1239 RunUntilIdle(); |
1095 EXPECT_FALSE(has_failed()); | 1240 EXPECT_FALSE(has_failed()); |
1096 EXPECT_TRUE(stream_); | 1241 EXPECT_TRUE(stream_); |
1097 } | 1242 } |
1098 | 1243 |
1244 // If the server requests authorisation, but we have no credentials, the | |
1245 // connection should fail cleanly. | |
1246 TEST_F(WebSocketStreamCreateBasicAuthTest, FailureNoCredentials) { | |
1247 CreateAndConnectCustomResponse("ws://localhost/", | |
1248 "/", | |
1249 NoSubProtocols(), | |
1250 "http://localhost", | |
1251 "", | |
1252 kUnauthorizedResponse); | |
1253 RunUntilIdle(); | |
1254 EXPECT_TRUE(has_failed()); | |
1255 EXPECT_EQ("HTTP Authentication failed; no valid credentials available", | |
1256 failure_message()); | |
1257 EXPECT_TRUE(response_info_); | |
1258 } | |
1259 | |
1260 TEST_F(WebSocketStreamCreateBasicAuthTest, SuccessPasswordInUrl) { | |
1261 CreateAndConnectAuthHandshake("ws://foo:bar@localhost/", | |
1262 "Zm9vOmJhcg==", | |
1263 WebSocketStandardResponse(std::string())); | |
1264 RunUntilIdle(); | |
1265 EXPECT_FALSE(has_failed()); | |
1266 EXPECT_TRUE(stream_); | |
1267 ASSERT_TRUE(response_info_); | |
1268 EXPECT_EQ(101, response_info_->status_code); | |
1269 } | |
1270 | |
1271 TEST_F(WebSocketStreamCreateBasicAuthTest, FailureIncorrectPasswordInUrl) { | |
1272 CreateAndConnectAuthHandshake( | |
1273 "ws://foo:baz@localhost/", "Zm9vOmJheg==", kUnauthorizedResponse); | |
1274 RunUntilIdle(); | |
1275 EXPECT_TRUE(has_failed()); | |
1276 EXPECT_TRUE(response_info_); | |
1277 } | |
1278 | |
1279 // Digest auth has the same connection semantics as Basic auth, so we can | |
1280 // generally assume that whatever works for Basic auth will also work for | |
1281 // Digest. There's just one test here, to confirm that it works at all. | |
1282 TEST_F(WebSocketStreamCreateDigestAuthTest, DigestPasswordInUrl) { | |
1283 AddRawExpectations(helper_.BuildSocketData1(kUnauthorizedResponse)); | |
1284 | |
1285 CreateAndConnectRawExpectations( | |
1286 "ws://FooBar:pass@localhost/", | |
1287 NoSubProtocols(), | |
1288 "http://localhost", | |
1289 helper_.BuildSocketData2(kAuthorizedRequest, | |
1290 WebSocketStandardResponse(std::string()))); | |
1291 RunUntilIdle(); | |
1292 EXPECT_FALSE(has_failed()); | |
1293 EXPECT_TRUE(stream_); | |
1294 ASSERT_TRUE(response_info_); | |
1295 EXPECT_EQ(101, response_info_->status_code); | |
1296 } | |
1297 | |
1099 TEST_F(WebSocketStreamCreateUMATest, Incomplete) { | 1298 TEST_F(WebSocketStreamCreateUMATest, Incomplete) { |
1100 const std::string name("Net.WebSocket.HandshakeResult"); | 1299 const std::string name("Net.WebSocket.HandshakeResult"); |
1101 scoped_ptr<base::HistogramSamples> original(GetSamples(name)); | 1300 scoped_ptr<base::HistogramSamples> original(GetSamples(name)); |
1102 | 1301 |
1103 { | 1302 { |
1104 StreamCreation creation; | 1303 StreamCreation creation; |
1105 creation.CreateAndConnectStandard("ws://localhost/", | 1304 creation.CreateAndConnectStandard("ws://localhost/", |
1106 "/", | 1305 "/", |
1107 creation.NoSubProtocols(), | 1306 creation.NoSubProtocols(), |
1108 "http://localhost", | 1307 "http://localhost", |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1171 if (original) { | 1370 if (original) { |
1172 samples->Subtract(*original); // Cancel the original values. | 1371 samples->Subtract(*original); // Cancel the original values. |
1173 } | 1372 } |
1174 EXPECT_EQ(1, samples->GetCount(INCOMPLETE)); | 1373 EXPECT_EQ(1, samples->GetCount(INCOMPLETE)); |
1175 EXPECT_EQ(0, samples->GetCount(CONNECTED)); | 1374 EXPECT_EQ(0, samples->GetCount(CONNECTED)); |
1176 EXPECT_EQ(0, samples->GetCount(FAILED)); | 1375 EXPECT_EQ(0, samples->GetCount(FAILED)); |
1177 } | 1376 } |
1178 | 1377 |
1179 } // namespace | 1378 } // namespace |
1180 } // namespace net | 1379 } // namespace net |
OLD | NEW |