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

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

Issue 105833003: Fail WebSocket channel when handshake fails. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 11 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
« no previous file with comments | « net/websockets/websocket_stream.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 <string> 7 #include <string>
8 #include <vector> 8 #include <vector>
9 9
10 #include "base/run_loop.h" 10 #include "base/run_loop.h"
(...skipping 27 matching lines...) Expand all
38 // This will break in an obvious way if the type created by 38 // This will break in an obvious way if the type created by
39 // CreateBasicStream() changes. 39 // CreateBasicStream() changes.
40 static_cast<WebSocketBasicHandshakeStream*>(stream()) 40 static_cast<WebSocketBasicHandshakeStream*>(stream())
41 ->SetWebSocketKeyForTesting("dGhlIHNhbXBsZSBub25jZQ=="); 41 ->SetWebSocketKeyForTesting("dGhlIHNhbXBsZSBub25jZQ==");
42 return stream(); 42 return stream();
43 } 43 }
44 }; 44 };
45 45
46 class WebSocketStreamCreateTest : public ::testing::Test { 46 class WebSocketStreamCreateTest : public ::testing::Test {
47 protected: 47 protected:
48 WebSocketStreamCreateTest() : websocket_error_(0) {} 48 WebSocketStreamCreateTest(): has_failed_(false) {}
49 49
50 void CreateAndConnectCustomResponse( 50 void CreateAndConnectCustomResponse(
51 const std::string& socket_url, 51 const std::string& socket_url,
52 const std::string& socket_path, 52 const std::string& socket_path,
53 const std::vector<std::string>& sub_protocols, 53 const std::vector<std::string>& sub_protocols,
54 const std::string& origin, 54 const std::string& origin,
55 const std::string& extra_request_headers, 55 const std::string& extra_request_headers,
56 const std::string& response_body) { 56 const std::string& response_body) {
57 url_request_context_host_.SetExpectations( 57 url_request_context_host_.SetExpectations(
58 WebSocketStandardRequest(socket_path, origin, extra_request_headers), 58 WebSocketStandardRequest(socket_path, origin, extra_request_headers),
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
103 new TestConnectDelegate(this))); 103 new TestConnectDelegate(this)));
104 } 104 }
105 105
106 static void RunUntilIdle() { base::RunLoop().RunUntilIdle(); } 106 static void RunUntilIdle() { base::RunLoop().RunUntilIdle(); }
107 107
108 // A simple function to make the tests more readable. Creates an empty vector. 108 // A simple function to make the tests more readable. Creates an empty vector.
109 static std::vector<std::string> NoSubProtocols() { 109 static std::vector<std::string> NoSubProtocols() {
110 return std::vector<std::string>(); 110 return std::vector<std::string>();
111 } 111 }
112 112
113 uint16 error() const { return websocket_error_; } 113 const std::string& failure_message() const { return failure_message_; }
114 bool has_failed() const { return has_failed_; }
114 115
115 class TestConnectDelegate : public WebSocketStream::ConnectDelegate { 116 class TestConnectDelegate : public WebSocketStream::ConnectDelegate {
116 public: 117 public:
117 TestConnectDelegate(WebSocketStreamCreateTest* owner) : owner_(owner) {} 118 explicit TestConnectDelegate(WebSocketStreamCreateTest* owner)
119 : owner_(owner) {}
118 120
119 virtual void OnSuccess(scoped_ptr<WebSocketStream> stream) OVERRIDE { 121 virtual void OnSuccess(scoped_ptr<WebSocketStream> stream) OVERRIDE {
120 stream.swap(owner_->stream_); 122 stream.swap(owner_->stream_);
121 } 123 }
122 124
123 virtual void OnFailure(uint16 websocket_error) OVERRIDE { 125 virtual void OnFailure(const std::string& message) OVERRIDE {
124 owner_->websocket_error_ = websocket_error; 126 owner_->has_failed_ = true;
127 owner_->failure_message_ = message;
125 } 128 }
126 129
127 private: 130 private:
128 WebSocketStreamCreateTest* owner_; 131 WebSocketStreamCreateTest* owner_;
129 }; 132 };
130 133
131 WebSocketTestURLRequestContextHost url_request_context_host_; 134 WebSocketTestURLRequestContextHost url_request_context_host_;
132 scoped_ptr<WebSocketStreamRequest> stream_request_; 135 scoped_ptr<WebSocketStreamRequest> stream_request_;
133 // Only set if the connection succeeded. 136 // Only set if the connection succeeded.
134 scoped_ptr<WebSocketStream> stream_; 137 scoped_ptr<WebSocketStream> stream_;
135 // Only set if the connection failed. 0 otherwise. 138 // Only set if the connection failed.
136 uint16 websocket_error_; 139 std::string failure_message_;
140 bool has_failed_;
137 }; 141 };
138 142
139 // Confirm that the basic case works as expected. 143 // Confirm that the basic case works as expected.
140 TEST_F(WebSocketStreamCreateTest, SimpleSuccess) { 144 TEST_F(WebSocketStreamCreateTest, SimpleSuccess) {
141 CreateAndConnectStandard( 145 CreateAndConnectStandard(
142 "ws://localhost/", "/", NoSubProtocols(), "http://localhost/", "", ""); 146 "ws://localhost/", "/", NoSubProtocols(), "http://localhost/", "", "");
143 RunUntilIdle(); 147 RunUntilIdle();
148 EXPECT_FALSE(has_failed());
144 EXPECT_TRUE(stream_); 149 EXPECT_TRUE(stream_);
145 } 150 }
146 151
147 // Confirm that the stream isn't established until the message loop runs. 152 // Confirm that the stream isn't established until the message loop runs.
148 TEST_F(WebSocketStreamCreateTest, NeedsToRunLoop) { 153 TEST_F(WebSocketStreamCreateTest, NeedsToRunLoop) {
149 CreateAndConnectStandard( 154 CreateAndConnectStandard(
150 "ws://localhost/", "/", NoSubProtocols(), "http://localhost/", "", ""); 155 "ws://localhost/", "/", NoSubProtocols(), "http://localhost/", "", "");
156 EXPECT_FALSE(has_failed());
151 EXPECT_FALSE(stream_); 157 EXPECT_FALSE(stream_);
152 } 158 }
153 159
154 // Check the path is used. 160 // Check the path is used.
155 TEST_F(WebSocketStreamCreateTest, PathIsUsed) { 161 TEST_F(WebSocketStreamCreateTest, PathIsUsed) {
156 CreateAndConnectStandard("ws://localhost/testing_path", 162 CreateAndConnectStandard("ws://localhost/testing_path",
157 "/testing_path", 163 "/testing_path",
158 NoSubProtocols(), 164 NoSubProtocols(),
159 "http://localhost/", 165 "http://localhost/",
160 "", 166 "",
161 ""); 167 "");
162 RunUntilIdle(); 168 RunUntilIdle();
169 EXPECT_FALSE(has_failed());
163 EXPECT_TRUE(stream_); 170 EXPECT_TRUE(stream_);
164 } 171 }
165 172
166 // Check that the origin is used. 173 // Check that the origin is used.
167 TEST_F(WebSocketStreamCreateTest, OriginIsUsed) { 174 TEST_F(WebSocketStreamCreateTest, OriginIsUsed) {
168 CreateAndConnectStandard("ws://localhost/testing_path", 175 CreateAndConnectStandard("ws://localhost/testing_path",
169 "/testing_path", 176 "/testing_path",
170 NoSubProtocols(), 177 NoSubProtocols(),
171 "http://google.com/", 178 "http://google.com/",
172 "", 179 "",
173 ""); 180 "");
174 RunUntilIdle(); 181 RunUntilIdle();
182 EXPECT_FALSE(has_failed());
175 EXPECT_TRUE(stream_); 183 EXPECT_TRUE(stream_);
176 } 184 }
177 185
178 // Check that sub-protocols are sent and parsed. 186 // Check that sub-protocols are sent and parsed.
179 TEST_F(WebSocketStreamCreateTest, SubProtocolIsUsed) { 187 TEST_F(WebSocketStreamCreateTest, SubProtocolIsUsed) {
180 std::vector<std::string> sub_protocols; 188 std::vector<std::string> sub_protocols;
181 sub_protocols.push_back("chatv11.chromium.org"); 189 sub_protocols.push_back("chatv11.chromium.org");
182 sub_protocols.push_back("chatv20.chromium.org"); 190 sub_protocols.push_back("chatv20.chromium.org");
183 CreateAndConnectStandard("ws://localhost/testing_path", 191 CreateAndConnectStandard("ws://localhost/testing_path",
184 "/testing_path", 192 "/testing_path",
185 sub_protocols, 193 sub_protocols,
186 "http://google.com/", 194 "http://google.com/",
187 "Sec-WebSocket-Protocol: chatv11.chromium.org, " 195 "Sec-WebSocket-Protocol: chatv11.chromium.org, "
188 "chatv20.chromium.org\r\n", 196 "chatv20.chromium.org\r\n",
189 "Sec-WebSocket-Protocol: chatv20.chromium.org\r\n"); 197 "Sec-WebSocket-Protocol: chatv20.chromium.org\r\n");
190 RunUntilIdle(); 198 RunUntilIdle();
191 EXPECT_TRUE(stream_); 199 EXPECT_TRUE(stream_);
200 EXPECT_FALSE(has_failed());
192 EXPECT_EQ("chatv20.chromium.org", stream_->GetSubProtocol()); 201 EXPECT_EQ("chatv20.chromium.org", stream_->GetSubProtocol());
193 } 202 }
194 203
195 // Unsolicited sub-protocols are rejected. 204 // Unsolicited sub-protocols are rejected.
196 TEST_F(WebSocketStreamCreateTest, UnsolicitedSubProtocol) { 205 TEST_F(WebSocketStreamCreateTest, UnsolicitedSubProtocol) {
197 CreateAndConnectStandard("ws://localhost/testing_path", 206 CreateAndConnectStandard("ws://localhost/testing_path",
198 "/testing_path", 207 "/testing_path",
199 NoSubProtocols(), 208 NoSubProtocols(),
200 "http://google.com/", 209 "http://google.com/",
201 "", 210 "",
202 "Sec-WebSocket-Protocol: chatv20.chromium.org\r\n"); 211 "Sec-WebSocket-Protocol: chatv20.chromium.org\r\n");
203 RunUntilIdle(); 212 RunUntilIdle();
204 EXPECT_FALSE(stream_); 213 EXPECT_FALSE(stream_);
205 EXPECT_EQ(1006, error()); 214 EXPECT_TRUE(has_failed());
215 EXPECT_EQ("Error during WebSocket handshake: "
216 "Response must not include 'Sec-WebSocket-Protocol' header "
217 "if not present in request: chatv20.chromium.org",
218 failure_message());
206 } 219 }
207 220
208 // Missing sub-protocol response is rejected. 221 // Missing sub-protocol response is rejected.
209 TEST_F(WebSocketStreamCreateTest, UnacceptedSubProtocol) { 222 TEST_F(WebSocketStreamCreateTest, UnacceptedSubProtocol) {
223 std::vector<std::string> sub_protocols;
224 sub_protocols.push_back("chat.example.com");
210 CreateAndConnectStandard("ws://localhost/testing_path", 225 CreateAndConnectStandard("ws://localhost/testing_path",
211 "/testing_path", 226 "/testing_path",
212 std::vector<std::string>(1, "chat.example.com"), 227 sub_protocols,
213 "http://localhost/", 228 "http://localhost/",
214 "Sec-WebSocket-Protocol: chat.example.com\r\n", 229 "Sec-WebSocket-Protocol: chat.example.com\r\n",
215 ""); 230 "");
216 RunUntilIdle(); 231 RunUntilIdle();
217 EXPECT_FALSE(stream_); 232 EXPECT_FALSE(stream_);
218 EXPECT_EQ(1006, error()); 233 EXPECT_TRUE(has_failed());
234 EXPECT_EQ("Error during WebSocket handshake: "
235 "Sent non-empty 'Sec-WebSocket-Protocol' header "
236 "but no response was received",
237 failure_message());
219 } 238 }
220 239
221 // Only one sub-protocol can be accepted. 240 // Only one sub-protocol can be accepted.
222 TEST_F(WebSocketStreamCreateTest, MultipleSubProtocolsInResponse) { 241 TEST_F(WebSocketStreamCreateTest, MultipleSubProtocolsInResponse) {
223 std::vector<std::string> sub_protocols; 242 std::vector<std::string> sub_protocols;
224 sub_protocols.push_back("chatv11.chromium.org"); 243 sub_protocols.push_back("chatv11.chromium.org");
225 sub_protocols.push_back("chatv20.chromium.org"); 244 sub_protocols.push_back("chatv20.chromium.org");
226 CreateAndConnectStandard("ws://localhost/testing_path", 245 CreateAndConnectStandard("ws://localhost/testing_path",
227 "/testing_path", 246 "/testing_path",
228 sub_protocols, 247 sub_protocols,
229 "http://google.com/", 248 "http://google.com/",
230 "Sec-WebSocket-Protocol: chatv11.chromium.org, " 249 "Sec-WebSocket-Protocol: chatv11.chromium.org, "
231 "chatv20.chromium.org\r\n", 250 "chatv20.chromium.org\r\n",
232 "Sec-WebSocket-Protocol: chatv11.chromium.org, " 251 "Sec-WebSocket-Protocol: chatv11.chromium.org, "
233 "chatv20.chromium.org\r\n"); 252 "chatv20.chromium.org\r\n");
234 RunUntilIdle(); 253 RunUntilIdle();
235 EXPECT_FALSE(stream_); 254 EXPECT_FALSE(stream_);
236 EXPECT_EQ(1006, error()); 255 EXPECT_TRUE(has_failed());
256 EXPECT_EQ("Error during WebSocket handshake: "
257 "'Sec-WebSocket-Protocol' header must not appear "
258 "more than once in a response",
259 failure_message());
260 }
261
262 // Unmatched sub-protocol should be rejected.
263 TEST_F(WebSocketStreamCreateTest, UnmatchedSubProtocolInResponse) {
264 std::vector<std::string> sub_protocols;
265 sub_protocols.push_back("chatv11.chromium.org");
266 sub_protocols.push_back("chatv20.chromium.org");
267 CreateAndConnectStandard("ws://localhost/testing_path",
268 "/testing_path",
269 sub_protocols,
270 "http://google.com/",
271 "Sec-WebSocket-Protocol: chatv11.chromium.org, "
272 "chatv20.chromium.org\r\n",
273 "Sec-WebSocket-Protocol: chatv21.chromium.org\r\n");
274 RunUntilIdle();
275 EXPECT_FALSE(stream_);
276 EXPECT_TRUE(has_failed());
277 EXPECT_EQ("Error during WebSocket handshake: "
278 "'Sec-WebSocket-Protocol' header value 'chatv21.chromium.org' "
279 "in response does not match any of sent values",
280 failure_message());
237 } 281 }
238 282
239 // Unknown extension in the response is rejected 283 // Unknown extension in the response is rejected
240 TEST_F(WebSocketStreamCreateTest, UnknownExtension) { 284 TEST_F(WebSocketStreamCreateTest, UnknownExtension) {
241 CreateAndConnectStandard("ws://localhost/testing_path", 285 CreateAndConnectStandard("ws://localhost/testing_path",
242 "/testing_path", 286 "/testing_path",
243 NoSubProtocols(), 287 NoSubProtocols(),
244 "http://localhost/", 288 "http://localhost/",
245 "", 289 "",
246 "Sec-WebSocket-Extensions: x-unknown-extension\r\n"); 290 "Sec-WebSocket-Extensions: x-unknown-extension\r\n");
247 RunUntilIdle(); 291 RunUntilIdle();
248 EXPECT_FALSE(stream_); 292 EXPECT_FALSE(stream_);
249 EXPECT_EQ(1006, error()); 293 EXPECT_TRUE(has_failed());
294 EXPECT_EQ("Error during WebSocket handshake: "
295 "Found an unsupported extension 'x-unknown-extension' "
296 "in 'Sec-WebSocket-Extensions' header",
297 failure_message());
250 } 298 }
251 299
252 // Additional Sec-WebSocket-Accept headers should be rejected. 300 // Additional Sec-WebSocket-Accept headers should be rejected.
253 TEST_F(WebSocketStreamCreateTest, DoubleAccept) { 301 TEST_F(WebSocketStreamCreateTest, DoubleAccept) {
254 CreateAndConnectStandard( 302 CreateAndConnectStandard(
255 "ws://localhost/", 303 "ws://localhost/",
256 "/", 304 "/",
257 NoSubProtocols(), 305 NoSubProtocols(),
258 "http://localhost/", 306 "http://localhost/",
259 "", 307 "",
260 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"); 308 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n");
261 RunUntilIdle(); 309 RunUntilIdle();
262 EXPECT_FALSE(stream_); 310 EXPECT_FALSE(stream_);
263 EXPECT_EQ(1006, error()); 311 EXPECT_TRUE(has_failed());
312 EXPECT_EQ("Error during WebSocket handshake: "
313 "'Sec-WebSocket-Accept' header must not appear "
314 "more than once in a response",
315 failure_message());
264 } 316 }
265 317
266 // Response code 200 must be rejected. 318 // Response code 200 must be rejected.
267 TEST_F(WebSocketStreamCreateTest, InvalidStatusCode) { 319 TEST_F(WebSocketStreamCreateTest, InvalidStatusCode) {
268 static const char kInvalidStatusCodeResponse[] = 320 static const char kInvalidStatusCodeResponse[] =
269 "HTTP/1.1 200 OK\r\n" 321 "HTTP/1.1 200 OK\r\n"
270 "Upgrade: websocket\r\n" 322 "Upgrade: websocket\r\n"
271 "Connection: Upgrade\r\n" 323 "Connection: Upgrade\r\n"
272 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n" 324 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
273 "\r\n"; 325 "\r\n";
274 CreateAndConnectCustomResponse("ws://localhost/", 326 CreateAndConnectCustomResponse("ws://localhost/",
275 "/", 327 "/",
276 NoSubProtocols(), 328 NoSubProtocols(),
277 "http://localhost/", 329 "http://localhost/",
278 "", 330 "",
279 kInvalidStatusCodeResponse); 331 kInvalidStatusCodeResponse);
280 RunUntilIdle(); 332 RunUntilIdle();
281 EXPECT_EQ(1006, error()); 333 EXPECT_TRUE(has_failed());
334 EXPECT_EQ("Unexpected status code: 200", failure_message());
282 } 335 }
283 336
284 // Redirects are not followed (according to the WHATWG WebSocket API, which 337 // Redirects are not followed (according to the WHATWG WebSocket API, which
285 // overrides RFC6455 for browser applications). 338 // overrides RFC6455 for browser applications).
286 TEST_F(WebSocketStreamCreateTest, RedirectsRejected) { 339 TEST_F(WebSocketStreamCreateTest, RedirectsRejected) {
287 static const char kRedirectResponse[] = 340 static const char kRedirectResponse[] =
288 "HTTP/1.1 302 Moved Temporarily\r\n" 341 "HTTP/1.1 302 Moved Temporarily\r\n"
289 "Content-Type: text/html\r\n" 342 "Content-Type: text/html\r\n"
290 "Content-Length: 34\r\n" 343 "Content-Length: 34\r\n"
291 "Connection: keep-alive\r\n" 344 "Connection: keep-alive\r\n"
292 "Location: ws://localhost/other\r\n" 345 "Location: ws://localhost/other\r\n"
293 "\r\n" 346 "\r\n"
294 "<title>Moved</title><h1>Moved</h1>"; 347 "<title>Moved</title><h1>Moved</h1>";
295 CreateAndConnectCustomResponse("ws://localhost/", 348 CreateAndConnectCustomResponse("ws://localhost/",
296 "/", 349 "/",
297 NoSubProtocols(), 350 NoSubProtocols(),
298 "http://localhost/", 351 "http://localhost/",
299 "", 352 "",
300 kRedirectResponse); 353 kRedirectResponse);
301 RunUntilIdle(); 354 RunUntilIdle();
302 EXPECT_EQ(1006, error()); 355 EXPECT_TRUE(has_failed());
356 EXPECT_EQ("Unexpected status code: 302", failure_message());
303 } 357 }
304 358
305 // Malformed responses should be rejected. HttpStreamParser will accept just 359 // Malformed responses should be rejected. HttpStreamParser will accept just
306 // about any garbage in the middle of the headers. To make it give up, the junk 360 // about any garbage in the middle of the headers. To make it give up, the junk
307 // has to be at the start of the response. Even then, it just gets treated as an 361 // has to be at the start of the response. Even then, it just gets treated as an
308 // HTTP/0.9 response. 362 // HTTP/0.9 response.
309 TEST_F(WebSocketStreamCreateTest, MalformedResponse) { 363 TEST_F(WebSocketStreamCreateTest, MalformedResponse) {
310 static const char kMalformedResponse[] = 364 static const char kMalformedResponse[] =
311 "220 mx.google.com ESMTP\r\n" 365 "220 mx.google.com ESMTP\r\n"
312 "HTTP/1.1 101 OK\r\n" 366 "HTTP/1.1 101 OK\r\n"
313 "Upgrade: websocket\r\n" 367 "Upgrade: websocket\r\n"
314 "Connection: Upgrade\r\n" 368 "Connection: Upgrade\r\n"
315 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n" 369 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
316 "\r\n"; 370 "\r\n";
317 CreateAndConnectCustomResponse("ws://localhost/", 371 CreateAndConnectCustomResponse("ws://localhost/",
318 "/", 372 "/",
319 NoSubProtocols(), 373 NoSubProtocols(),
320 "http://localhost/", 374 "http://localhost/",
321 "", 375 "",
322 kMalformedResponse); 376 kMalformedResponse);
323 RunUntilIdle(); 377 RunUntilIdle();
324 EXPECT_EQ(1006, error()); 378 EXPECT_TRUE(has_failed());
379 EXPECT_EQ("Unexpected status code: 200", failure_message());
325 } 380 }
326 381
327 // Upgrade header must be present. 382 // Upgrade header must be present.
328 TEST_F(WebSocketStreamCreateTest, MissingUpgradeHeader) { 383 TEST_F(WebSocketStreamCreateTest, MissingUpgradeHeader) {
329 static const char kMissingUpgradeResponse[] = 384 static const char kMissingUpgradeResponse[] =
330 "HTTP/1.1 101 Switching Protocols\r\n" 385 "HTTP/1.1 101 Switching Protocols\r\n"
331 "Connection: Upgrade\r\n" 386 "Connection: Upgrade\r\n"
332 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n" 387 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
333 "\r\n"; 388 "\r\n";
334 CreateAndConnectCustomResponse("ws://localhost/", 389 CreateAndConnectCustomResponse("ws://localhost/",
335 "/", 390 "/",
336 NoSubProtocols(), 391 NoSubProtocols(),
337 "http://localhost/", 392 "http://localhost/",
338 "", 393 "",
339 kMissingUpgradeResponse); 394 kMissingUpgradeResponse);
340 RunUntilIdle(); 395 RunUntilIdle();
341 EXPECT_EQ(1006, error()); 396 EXPECT_TRUE(has_failed());
397 EXPECT_EQ("Error during WebSocket handshake: 'Upgrade' header is missing",
398 failure_message());
342 } 399 }
343 400
344 // There must only be one upgrade header. 401 // There must only be one upgrade header.
345 TEST_F(WebSocketStreamCreateTest, DoubleUpgradeHeader) { 402 TEST_F(WebSocketStreamCreateTest, DoubleUpgradeHeader) {
346 CreateAndConnectStandard( 403 CreateAndConnectStandard(
347 "ws://localhost/", 404 "ws://localhost/",
348 "/", 405 "/",
349 NoSubProtocols(), 406 NoSubProtocols(),
350 "http://localhost/", 407 "http://localhost/",
351 "", "Upgrade: HTTP/2.0\r\n"); 408 "", "Upgrade: HTTP/2.0\r\n");
352 RunUntilIdle(); 409 RunUntilIdle();
353 EXPECT_EQ(1006, error()); 410 EXPECT_TRUE(has_failed());
411 EXPECT_EQ("Error during WebSocket handshake: "
412 "'Upgrade' header must not appear more than once in a response",
413 failure_message());
414 }
415
416 // There must only be one correct upgrade header.
417 TEST_F(WebSocketStreamCreateTest, IncorrectUpgradeHeader) {
418 static const char kMissingUpgradeResponse[] =
419 "HTTP/1.1 101 Switching Protocols\r\n"
420 "Connection: Upgrade\r\n"
421 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
422 "Upgrade: hogefuga\r\n"
423 "\r\n";
424 CreateAndConnectCustomResponse("ws://localhost/",
425 "/",
426 NoSubProtocols(),
427 "http://localhost/",
428 "",
429 kMissingUpgradeResponse);
430 RunUntilIdle();
431 EXPECT_TRUE(has_failed());
432 EXPECT_EQ("Error during WebSocket handshake: "
433 "'Upgrade' header value is not 'WebSocket': hogefuga",
434 failure_message());
354 } 435 }
355 436
356 // Connection header must be present. 437 // Connection header must be present.
357 TEST_F(WebSocketStreamCreateTest, MissingConnectionHeader) { 438 TEST_F(WebSocketStreamCreateTest, MissingConnectionHeader) {
358 static const char kMissingConnectionResponse[] = 439 static const char kMissingConnectionResponse[] =
359 "HTTP/1.1 101 Switching Protocols\r\n" 440 "HTTP/1.1 101 Switching Protocols\r\n"
360 "Upgrade: websocket\r\n" 441 "Upgrade: websocket\r\n"
361 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n" 442 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
362 "\r\n"; 443 "\r\n";
363 CreateAndConnectCustomResponse("ws://localhost/", 444 CreateAndConnectCustomResponse("ws://localhost/",
364 "/", 445 "/",
365 NoSubProtocols(), 446 NoSubProtocols(),
366 "http://localhost/", 447 "http://localhost/",
367 "", 448 "",
368 kMissingConnectionResponse); 449 kMissingConnectionResponse);
369 RunUntilIdle(); 450 RunUntilIdle();
370 EXPECT_EQ(1006, error()); 451 EXPECT_TRUE(has_failed());
452 EXPECT_EQ("Error during WebSocket handshake: "
453 "'Connection' header is missing",
454 failure_message());
455 }
456
457 // Connection header must contain "Upgrade".
458 TEST_F(WebSocketStreamCreateTest, IncorrectConnectionHeader) {
459 static const char kMissingConnectionResponse[] =
460 "HTTP/1.1 101 Switching Protocols\r\n"
461 "Upgrade: websocket\r\n"
462 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
463 "Connection: hogefuga\r\n"
464 "\r\n";
465 CreateAndConnectCustomResponse("ws://localhost/",
466 "/",
467 NoSubProtocols(),
468 "http://localhost/",
469 "",
470 kMissingConnectionResponse);
471 RunUntilIdle();
472 EXPECT_TRUE(has_failed());
473 EXPECT_EQ("Error during WebSocket handshake: "
474 "'Connection' header value must contain 'Upgrade'",
475 failure_message());
371 } 476 }
372 477
373 // Connection header is permitted to contain other tokens. 478 // Connection header is permitted to contain other tokens.
374 TEST_F(WebSocketStreamCreateTest, AdditionalTokenInConnectionHeader) { 479 TEST_F(WebSocketStreamCreateTest, AdditionalTokenInConnectionHeader) {
375 static const char kAdditionalConnectionTokenResponse[] = 480 static const char kAdditionalConnectionTokenResponse[] =
376 "HTTP/1.1 101 Switching Protocols\r\n" 481 "HTTP/1.1 101 Switching Protocols\r\n"
377 "Upgrade: websocket\r\n" 482 "Upgrade: websocket\r\n"
378 "Connection: Upgrade, Keep-Alive\r\n" 483 "Connection: Upgrade, Keep-Alive\r\n"
379 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n" 484 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
380 "\r\n"; 485 "\r\n";
381 CreateAndConnectCustomResponse("ws://localhost/", 486 CreateAndConnectCustomResponse("ws://localhost/",
382 "/", 487 "/",
383 NoSubProtocols(), 488 NoSubProtocols(),
384 "http://localhost/", 489 "http://localhost/",
385 "", 490 "",
386 kAdditionalConnectionTokenResponse); 491 kAdditionalConnectionTokenResponse);
387 RunUntilIdle(); 492 RunUntilIdle();
493 EXPECT_FALSE(has_failed());
388 EXPECT_TRUE(stream_); 494 EXPECT_TRUE(stream_);
389 } 495 }
390 496
391 // Sec-WebSocket-Accept header must be present. 497 // Sec-WebSocket-Accept header must be present.
392 TEST_F(WebSocketStreamCreateTest, MissingSecWebSocketAccept) { 498 TEST_F(WebSocketStreamCreateTest, MissingSecWebSocketAccept) {
393 static const char kMissingAcceptResponse[] = 499 static const char kMissingAcceptResponse[] =
394 "HTTP/1.1 101 Switching Protocols\r\n" 500 "HTTP/1.1 101 Switching Protocols\r\n"
395 "Upgrade: websocket\r\n" 501 "Upgrade: websocket\r\n"
396 "Connection: Upgrade\r\n" 502 "Connection: Upgrade\r\n"
397 "\r\n"; 503 "\r\n";
398 CreateAndConnectCustomResponse("ws://localhost/", 504 CreateAndConnectCustomResponse("ws://localhost/",
399 "/", 505 "/",
400 NoSubProtocols(), 506 NoSubProtocols(),
401 "http://localhost/", 507 "http://localhost/",
402 "", 508 "",
403 kMissingAcceptResponse); 509 kMissingAcceptResponse);
404 RunUntilIdle(); 510 RunUntilIdle();
405 EXPECT_EQ(1006, error()); 511 EXPECT_TRUE(has_failed());
512 EXPECT_EQ("Error during WebSocket handshake: "
513 "'Sec-WebSocket-Accept' header is missing",
514 failure_message());
406 } 515 }
407 516
408 // Sec-WebSocket-Accept header must match the key that was sent. 517 // Sec-WebSocket-Accept header must match the key that was sent.
409 TEST_F(WebSocketStreamCreateTest, WrongSecWebSocketAccept) { 518 TEST_F(WebSocketStreamCreateTest, WrongSecWebSocketAccept) {
410 static const char kIncorrectAcceptResponse[] = 519 static const char kIncorrectAcceptResponse[] =
411 "HTTP/1.1 101 Switching Protocols\r\n" 520 "HTTP/1.1 101 Switching Protocols\r\n"
412 "Upgrade: websocket\r\n" 521 "Upgrade: websocket\r\n"
413 "Connection: Upgrade\r\n" 522 "Connection: Upgrade\r\n"
414 "Sec-WebSocket-Accept: x/byyPZ2tOFvJCGkkugcKvqhhPk=\r\n" 523 "Sec-WebSocket-Accept: x/byyPZ2tOFvJCGkkugcKvqhhPk=\r\n"
415 "\r\n"; 524 "\r\n";
416 CreateAndConnectCustomResponse("ws://localhost/", 525 CreateAndConnectCustomResponse("ws://localhost/",
417 "/", 526 "/",
418 NoSubProtocols(), 527 NoSubProtocols(),
419 "http://localhost/", 528 "http://localhost/",
420 "", 529 "",
421 kIncorrectAcceptResponse); 530 kIncorrectAcceptResponse);
422 RunUntilIdle(); 531 RunUntilIdle();
423 EXPECT_EQ(1006, error()); 532 EXPECT_TRUE(has_failed());
533 EXPECT_EQ("Error during WebSocket handshake: "
534 "Incorrect 'Sec-WebSocket-Accept' header value",
535 failure_message());
424 } 536 }
425 537
426 // Cancellation works. 538 // Cancellation works.
427 TEST_F(WebSocketStreamCreateTest, Cancellation) { 539 TEST_F(WebSocketStreamCreateTest, Cancellation) {
428 CreateAndConnectStandard( 540 CreateAndConnectStandard(
429 "ws://localhost/", "/", NoSubProtocols(), "http://localhost/", "", ""); 541 "ws://localhost/", "/", NoSubProtocols(), "http://localhost/", "", "");
430 stream_request_.reset(); 542 stream_request_.reset();
431 RunUntilIdle(); 543 RunUntilIdle();
544 EXPECT_FALSE(has_failed());
432 EXPECT_FALSE(stream_); 545 EXPECT_FALSE(stream_);
433 } 546 }
434 547
435 // Connect failure must look just like negotiation failure. 548 // Connect failure must look just like negotiation failure.
436 TEST_F(WebSocketStreamCreateTest, ConnectionFailure) { 549 TEST_F(WebSocketStreamCreateTest, ConnectionFailure) {
437 scoped_ptr<DeterministicSocketData> socket_data( 550 scoped_ptr<DeterministicSocketData> socket_data(
438 new DeterministicSocketData(NULL, 0, NULL, 0)); 551 new DeterministicSocketData(NULL, 0, NULL, 0));
439 socket_data->set_connect_data( 552 socket_data->set_connect_data(
440 MockConnect(SYNCHRONOUS, ERR_CONNECTION_REFUSED)); 553 MockConnect(SYNCHRONOUS, ERR_CONNECTION_REFUSED));
441 CreateAndConnectRawExpectations("ws://localhost/", NoSubProtocols(), 554 CreateAndConnectRawExpectations("ws://localhost/", NoSubProtocols(),
442 "http://localhost/", socket_data.Pass()); 555 "http://localhost/", socket_data.Pass());
443 RunUntilIdle(); 556 RunUntilIdle();
444 EXPECT_EQ(1006, error()); 557 EXPECT_TRUE(has_failed());
558 EXPECT_EQ("Error in connection establishment: net::ERR_CONNECTION_REFUSED",
559 failure_message());
445 } 560 }
446 561
447 // Connect timeout must look just like any other failure. 562 // Connect timeout must look just like any other failure.
448 TEST_F(WebSocketStreamCreateTest, ConnectionTimeout) { 563 TEST_F(WebSocketStreamCreateTest, ConnectionTimeout) {
449 scoped_ptr<DeterministicSocketData> socket_data( 564 scoped_ptr<DeterministicSocketData> socket_data(
450 new DeterministicSocketData(NULL, 0, NULL, 0)); 565 new DeterministicSocketData(NULL, 0, NULL, 0));
451 socket_data->set_connect_data( 566 socket_data->set_connect_data(
452 MockConnect(ASYNC, ERR_CONNECTION_TIMED_OUT)); 567 MockConnect(ASYNC, ERR_CONNECTION_TIMED_OUT));
453 CreateAndConnectRawExpectations("ws://localhost/", NoSubProtocols(), 568 CreateAndConnectRawExpectations("ws://localhost/", NoSubProtocols(),
454 "http://localhost/", socket_data.Pass()); 569 "http://localhost/", socket_data.Pass());
455 RunUntilIdle(); 570 RunUntilIdle();
456 EXPECT_EQ(1006, error()); 571 EXPECT_TRUE(has_failed());
572 EXPECT_EQ("Error in connection establishment: net::ERR_CONNECTION_TIMED_OUT",
573 failure_message());
457 } 574 }
458 575
459 // Cancellation during connect works. 576 // Cancellation during connect works.
460 TEST_F(WebSocketStreamCreateTest, CancellationDuringConnect) { 577 TEST_F(WebSocketStreamCreateTest, CancellationDuringConnect) {
461 scoped_ptr<DeterministicSocketData> socket_data( 578 scoped_ptr<DeterministicSocketData> socket_data(
462 new DeterministicSocketData(NULL, 0, NULL, 0)); 579 new DeterministicSocketData(NULL, 0, NULL, 0));
463 socket_data->set_connect_data(MockConnect(SYNCHRONOUS, ERR_IO_PENDING)); 580 socket_data->set_connect_data(MockConnect(SYNCHRONOUS, ERR_IO_PENDING));
464 CreateAndConnectRawExpectations("ws://localhost/", 581 CreateAndConnectRawExpectations("ws://localhost/",
465 NoSubProtocols(), 582 NoSubProtocols(),
466 "http://localhost/", 583 "http://localhost/",
467 socket_data.Pass()); 584 socket_data.Pass());
468 stream_request_.reset(); 585 stream_request_.reset();
469 RunUntilIdle(); 586 RunUntilIdle();
587 EXPECT_FALSE(has_failed());
470 EXPECT_FALSE(stream_); 588 EXPECT_FALSE(stream_);
471 } 589 }
472 590
473 // Cancellation during write of the request headers works. 591 // Cancellation during write of the request headers works.
474 TEST_F(WebSocketStreamCreateTest, CancellationDuringWrite) { 592 TEST_F(WebSocketStreamCreateTest, CancellationDuringWrite) {
475 // We seem to need at least two operations in order to use SetStop(). 593 // We seem to need at least two operations in order to use SetStop().
476 MockWrite writes[] = {MockWrite(ASYNC, 0, "GET / HTTP/"), 594 MockWrite writes[] = {MockWrite(ASYNC, 0, "GET / HTTP/"),
477 MockWrite(ASYNC, 1, "1.1\r\n")}; 595 MockWrite(ASYNC, 1, "1.1\r\n")};
478 // We keep a copy of the pointer so that we can call RunFor() on it later. 596 // We keep a copy of the pointer so that we can call RunFor() on it later.
479 DeterministicSocketData* socket_data( 597 DeterministicSocketData* socket_data(
480 new DeterministicSocketData(NULL, 0, writes, arraysize(writes))); 598 new DeterministicSocketData(NULL, 0, writes, arraysize(writes)));
481 socket_data->set_connect_data(MockConnect(SYNCHRONOUS, OK)); 599 socket_data->set_connect_data(MockConnect(SYNCHRONOUS, OK));
482 socket_data->SetStop(1); 600 socket_data->SetStop(1);
483 CreateAndConnectRawExpectations("ws://localhost/", 601 CreateAndConnectRawExpectations("ws://localhost/",
484 NoSubProtocols(), 602 NoSubProtocols(),
485 "http://localhost/", 603 "http://localhost/",
486 make_scoped_ptr(socket_data)); 604 make_scoped_ptr(socket_data));
487 socket_data->Run(); 605 socket_data->Run();
488 stream_request_.reset(); 606 stream_request_.reset();
489 RunUntilIdle(); 607 RunUntilIdle();
608 EXPECT_FALSE(has_failed());
490 EXPECT_FALSE(stream_); 609 EXPECT_FALSE(stream_);
491 } 610 }
492 611
493 // Cancellation during read of the response headers works. 612 // Cancellation during read of the response headers works.
494 TEST_F(WebSocketStreamCreateTest, CancellationDuringRead) { 613 TEST_F(WebSocketStreamCreateTest, CancellationDuringRead) {
495 std::string request = WebSocketStandardRequest("/", "http://localhost/", ""); 614 std::string request = WebSocketStandardRequest("/", "http://localhost/", "");
496 MockWrite writes[] = {MockWrite(ASYNC, 0, request.c_str())}; 615 MockWrite writes[] = {MockWrite(ASYNC, 0, request.c_str())};
497 MockRead reads[] = { 616 MockRead reads[] = {
498 MockRead(ASYNC, 1, "HTTP/1.1 101 Switching Protocols\r\nUpgr"), 617 MockRead(ASYNC, 1, "HTTP/1.1 101 Switching Protocols\r\nUpgr"),
499 }; 618 };
500 DeterministicSocketData* socket_data(new DeterministicSocketData( 619 DeterministicSocketData* socket_data(new DeterministicSocketData(
501 reads, arraysize(reads), writes, arraysize(writes))); 620 reads, arraysize(reads), writes, arraysize(writes)));
502 socket_data->set_connect_data(MockConnect(SYNCHRONOUS, OK)); 621 socket_data->set_connect_data(MockConnect(SYNCHRONOUS, OK));
503 socket_data->SetStop(1); 622 socket_data->SetStop(1);
504 CreateAndConnectRawExpectations("ws://localhost/", 623 CreateAndConnectRawExpectations("ws://localhost/",
505 NoSubProtocols(), 624 NoSubProtocols(),
506 "http://localhost/", 625 "http://localhost/",
507 make_scoped_ptr(socket_data)); 626 make_scoped_ptr(socket_data));
508 socket_data->Run(); 627 socket_data->Run();
509 stream_request_.reset(); 628 stream_request_.reset();
510 RunUntilIdle(); 629 RunUntilIdle();
630 EXPECT_FALSE(has_failed());
511 EXPECT_FALSE(stream_); 631 EXPECT_FALSE(stream_);
512 } 632 }
513 633
514 } // namespace 634 } // namespace
515 } // namespace net 635 } // namespace net
OLDNEW
« no previous file with comments | « net/websockets/websocket_stream.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698