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

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

Powered by Google App Engine
This is Rietveld 408576698