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