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

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