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

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

Issue 9582034: Fork SPDY/2 and SPDY/3 versions of our SPDY tests, in preparation for landing (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Fix merge bug Created 8 years, 9 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 | Annotate | Revision Log
« no previous file with comments | « net/websockets/websocket_job_spdy3_unittest.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
(Empty)
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "net/websockets/websocket_job.h"
6
7 #include <string>
8 #include <vector>
9
10 #include "base/bind.h"
11 #include "base/bind_helpers.h"
12 #include "base/callback.h"
13 #include "base/memory/ref_counted.h"
14 #include "base/string_split.h"
15 #include "base/string_util.h"
16 #include "googleurl/src/gurl.h"
17 #include "net/base/completion_callback.h"
18 #include "net/base/cookie_store.h"
19 #include "net/base/cookie_store_test_helpers.h"
20 #include "net/base/mock_host_resolver.h"
21 #include "net/base/net_errors.h"
22 #include "net/base/ssl_config_service.h"
23 #include "net/base/sys_addrinfo.h"
24 #include "net/base/test_completion_callback.h"
25 #include "net/base/transport_security_state.h"
26 #include "net/http/http_transaction_factory.h"
27 #include "net/proxy/proxy_service.h"
28 #include "net/socket/socket_test_util.h"
29 #include "net/socket_stream/socket_stream.h"
30 #include "net/spdy/spdy_session.h"
31 #include "net/spdy/spdy_test_util.h"
32 #include "net/spdy/spdy_websocket_test_util.h"
33 #include "net/url_request/url_request_context.h"
34 #include "net/websockets/websocket_throttle.h"
35 #include "testing/gtest/include/gtest/gtest.h"
36 #include "testing/gmock/include/gmock/gmock.h"
37 #include "testing/platform_test.h"
38
39 namespace {
40
41 class MockSocketStream : public net::SocketStream {
42 public:
43 MockSocketStream(const GURL& url, net::SocketStream::Delegate* delegate)
44 : SocketStream(url, delegate) {}
45 virtual ~MockSocketStream() {}
46
47 virtual void Connect() OVERRIDE {}
48 virtual bool SendData(const char* data, int len) OVERRIDE {
49 sent_data_ += std::string(data, len);
50 return true;
51 }
52
53 virtual void Close() OVERRIDE {}
54 virtual void RestartWithAuth(
55 const net::AuthCredentials& credentials) OVERRIDE {
56 }
57
58 virtual void DetachDelegate() OVERRIDE {
59 delegate_ = NULL;
60 }
61
62 const std::string& sent_data() const {
63 return sent_data_;
64 }
65
66 private:
67 std::string sent_data_;
68 };
69
70 class MockSocketStreamDelegate : public net::SocketStream::Delegate {
71 public:
72 MockSocketStreamDelegate()
73 : amount_sent_(0), allow_all_cookies_(true) {}
74 void set_allow_all_cookies(bool allow_all_cookies) {
75 allow_all_cookies_ = allow_all_cookies;
76 }
77 virtual ~MockSocketStreamDelegate() {}
78
79 void SetOnStartOpenConnection(const base::Closure& callback) {
80 on_start_open_connection_ = callback;
81 }
82 void SetOnConnected(const base::Closure& callback) {
83 on_connected_ = callback;
84 }
85 void SetOnSentData(const base::Closure& callback) {
86 on_sent_data_ = callback;
87 }
88 void SetOnReceivedData(const base::Closure& callback) {
89 on_received_data_ = callback;
90 }
91 void SetOnClose(const base::Closure& callback) {
92 on_close_ = callback;
93 }
94
95 virtual int OnStartOpenConnection(net::SocketStream* socket,
96 const net::CompletionCallback& callback) {
97 if (!on_start_open_connection_.is_null())
98 on_start_open_connection_.Run();
99 return net::OK;
100 }
101 virtual void OnConnected(net::SocketStream* socket,
102 int max_pending_send_allowed) {
103 if (!on_connected_.is_null())
104 on_connected_.Run();
105 }
106 virtual void OnSentData(net::SocketStream* socket, int amount_sent) {
107 amount_sent_ += amount_sent;
108 if (!on_sent_data_.is_null())
109 on_sent_data_.Run();
110 }
111 virtual void OnReceivedData(net::SocketStream* socket,
112 const char* data, int len) {
113 received_data_ += std::string(data, len);
114 if (!on_received_data_.is_null())
115 on_received_data_.Run();
116 }
117 virtual void OnClose(net::SocketStream* socket) {
118 if (!on_close_.is_null())
119 on_close_.Run();
120 }
121 virtual bool CanGetCookies(net::SocketStream* socket, const GURL& url) {
122 return allow_all_cookies_;
123 }
124 virtual bool CanSetCookie(net::SocketStream* request,
125 const GURL& url,
126 const std::string& cookie_line,
127 net::CookieOptions* options) {
128 return allow_all_cookies_;
129 }
130
131 size_t amount_sent() const { return amount_sent_; }
132 const std::string& received_data() const { return received_data_; }
133
134 private:
135 int amount_sent_;
136 bool allow_all_cookies_;
137 std::string received_data_;
138 base::Closure on_start_open_connection_;
139 base::Closure on_connected_;
140 base::Closure on_sent_data_;
141 base::Closure on_received_data_;
142 base::Closure on_close_;
143 };
144
145 class MockCookieStore : public net::CookieStore {
146 public:
147 struct Entry {
148 GURL url;
149 std::string cookie_line;
150 net::CookieOptions options;
151 };
152 MockCookieStore() {}
153
154 virtual bool SetCookieWithOptions(const GURL& url,
155 const std::string& cookie_line,
156 const net::CookieOptions& options) {
157 Entry entry;
158 entry.url = url;
159 entry.cookie_line = cookie_line;
160 entry.options = options;
161 entries_.push_back(entry);
162 return true;
163 }
164
165 virtual void SetCookieWithOptionsAsync(
166 const GURL& url,
167 const std::string& cookie_line,
168 const net::CookieOptions& options,
169 const SetCookiesCallback& callback) {
170 bool result = SetCookieWithOptions(url, cookie_line, options);
171 if (!callback.is_null())
172 callback.Run(result);
173 }
174 virtual std::string GetCookiesWithOptions(
175 const GURL& url,
176 const net::CookieOptions& options) {
177 std::string result;
178 for (size_t i = 0; i < entries_.size(); i++) {
179 Entry &entry = entries_[i];
180 if (url == entry.url) {
181 if (!result.empty()) {
182 result += "; ";
183 }
184 result += entry.cookie_line;
185 }
186 }
187 return result;
188 }
189 virtual void GetCookiesWithOptionsAsync(
190 const GURL& url,
191 const net::CookieOptions& options,
192 const GetCookiesCallback& callback) {
193 if (!callback.is_null())
194 callback.Run(GetCookiesWithOptions(url, options));
195 }
196 virtual void GetCookiesWithInfo(const GURL& url,
197 const net::CookieOptions& options,
198 std::string* cookie_line,
199 std::vector<CookieInfo>* cookie_infos) {
200 ADD_FAILURE();
201 }
202 virtual void GetCookiesWithInfoAsync(
203 const GURL& url,
204 const net::CookieOptions& options,
205 const GetCookieInfoCallback& callback) {
206 ADD_FAILURE();
207 }
208 virtual void DeleteCookie(const GURL& url,
209 const std::string& cookie_name) {
210 ADD_FAILURE();
211 }
212 virtual void DeleteCookieAsync(const GURL& url,
213 const std::string& cookie_name,
214 const base::Closure& callback) {
215 ADD_FAILURE();
216 }
217 virtual void DeleteAllCreatedBetweenAsync(const base::Time& delete_begin,
218 const base::Time& delete_end,
219 const DeleteCallback& callback) {
220 ADD_FAILURE();
221 }
222
223 virtual net::CookieMonster* GetCookieMonster() { return NULL; }
224
225 const std::vector<Entry>& entries() const { return entries_; }
226
227 private:
228 friend class base::RefCountedThreadSafe<MockCookieStore>;
229 virtual ~MockCookieStore() {}
230
231 std::vector<Entry> entries_;
232 };
233
234 class MockSSLConfigService : public net::SSLConfigService {
235 public:
236 virtual void GetSSLConfig(net::SSLConfig* config) {};
237 };
238
239 class MockURLRequestContext : public net::URLRequestContext {
240 public:
241 explicit MockURLRequestContext(net::CookieStore* cookie_store)
242 : transport_security_state_(std::string()) {
243 set_cookie_store(cookie_store);
244 set_transport_security_state(&transport_security_state_);
245 net::TransportSecurityState::DomainState state;
246 state.expiry = base::Time::Now() + base::TimeDelta::FromSeconds(1000);
247 transport_security_state_.EnableHost("upgrademe.com", state);
248 }
249
250 private:
251 friend class base::RefCountedThreadSafe<MockURLRequestContext>;
252 virtual ~MockURLRequestContext() {}
253
254 net::TransportSecurityState transport_security_state_;
255 };
256
257 class MockHttpTransactionFactory : public net::HttpTransactionFactory {
258 public:
259 MockHttpTransactionFactory(net::OrderedSocketData* data) {
260 data_ = data;
261 net::MockConnect connect_data(net::SYNCHRONOUS, net::OK);
262 data_->set_connect_data(connect_data);
263 session_deps_.reset(new net::SpdySessionDependencies);
264 session_deps_->socket_factory->AddSocketDataProvider(data_);
265 http_session_ =
266 net::SpdySessionDependencies::SpdyCreateSession(session_deps_.get());
267 host_port_pair_.set_host("example.com");
268 host_port_pair_.set_port(80);
269 host_port_proxy_pair_.first = host_port_pair_;
270 host_port_proxy_pair_.second = net::ProxyServer::Direct();
271 net::SpdySessionPool* spdy_session_pool =
272 http_session_->spdy_session_pool();
273 DCHECK(spdy_session_pool);
274 EXPECT_FALSE(spdy_session_pool->HasSession(host_port_proxy_pair_));
275 session_ =
276 spdy_session_pool->Get(host_port_proxy_pair_, net::BoundNetLog());
277 EXPECT_TRUE(spdy_session_pool->HasSession(host_port_proxy_pair_));
278
279 transport_params_ = new net::TransportSocketParams(host_port_pair_,
280 net::MEDIUM,
281 false,
282 false);
283 net::ClientSocketHandle* connection = new net::ClientSocketHandle;
284 EXPECT_EQ(net::OK,
285 connection->Init(host_port_pair_.ToString(), transport_params_,
286 net::MEDIUM, net::CompletionCallback(),
287 http_session_->GetTransportSocketPool(),
288 net::BoundNetLog()));
289 EXPECT_EQ(net::OK,
290 session_->InitializeWithSocket(connection, false, net::OK));
291 }
292 virtual int CreateTransaction(scoped_ptr<net::HttpTransaction>* trans) {
293 NOTREACHED();
294 return net::ERR_UNEXPECTED;
295 }
296 virtual net::HttpCache* GetCache() {
297 NOTREACHED();
298 return NULL;
299 }
300 virtual net::HttpNetworkSession* GetSession() {
301 return http_session_.get();
302 }
303 private:
304 net::OrderedSocketData* data_;
305 scoped_ptr<net::SpdySessionDependencies> session_deps_;
306 scoped_refptr<net::HttpNetworkSession> http_session_;
307 scoped_refptr<net::TransportSocketParams> transport_params_;
308 scoped_refptr<net::SpdySession> session_;
309 net::HostPortPair host_port_pair_;
310 net::HostPortProxyPair host_port_proxy_pair_;
311 };
312 }
313
314 namespace net {
315
316 class WebSocketJobTest : public PlatformTest {
317 public:
318 virtual void SetUp() {
319 spdy::SpdyFramer::set_enable_compression_default(false);
320 stream_type_ = STREAM_INVALID;
321 cookie_store_ = new MockCookieStore;
322 context_ = new MockURLRequestContext(cookie_store_.get());
323 }
324 virtual void TearDown() {
325 cookie_store_ = NULL;
326 context_ = NULL;
327 websocket_ = NULL;
328 socket_ = NULL;
329 }
330 void DoSendRequest() {
331 EXPECT_TRUE(websocket_->SendData(kHandshakeRequestWithoutCookie,
332 kHandshakeRequestWithoutCookieLength));
333 }
334 void DoSendData() {
335 if (received_data().size() == kHandshakeResponseWithoutCookieLength)
336 websocket_->SendData(kDataHello, kDataHelloLength);
337 }
338 void DoSync() {
339 sync_test_callback_.callback().Run(OK);
340 }
341 int WaitForResult() {
342 return sync_test_callback_.WaitForResult();
343 }
344 protected:
345 enum StreamType {
346 STREAM_INVALID,
347 STREAM_MOCK_SOCKET,
348 STREAM_SOCKET,
349 STREAM_SPDY_WEBSOCKET,
350 };
351 enum ThrottlingOption {
352 THROTTLING_OFF,
353 THROTTLING_ON,
354 };
355 enum SpdyOption {
356 SPDY_OFF,
357 SPDY_ON,
358 };
359 void InitWebSocketJob(const GURL& url,
360 MockSocketStreamDelegate* delegate,
361 StreamType stream_type) {
362 DCHECK_NE(STREAM_INVALID, stream_type);
363 stream_type_ = stream_type;
364 websocket_ = new WebSocketJob(delegate);
365
366 if (stream_type == STREAM_MOCK_SOCKET)
367 socket_ = new MockSocketStream(url, websocket_.get());
368
369 if (stream_type == STREAM_SOCKET || stream_type == STREAM_SPDY_WEBSOCKET) {
370 if (stream_type == STREAM_SPDY_WEBSOCKET) {
371 http_factory_.reset(new MockHttpTransactionFactory(data_.get()));
372 context_->set_http_transaction_factory(http_factory_.get());
373 }
374
375 ssl_config_service_ = new MockSSLConfigService();
376 context_->set_ssl_config_service(ssl_config_service_);
377 proxy_service_.reset(net::ProxyService::CreateDirect());
378 context_->set_proxy_service(proxy_service_.get());
379 host_resolver_.reset(new net::MockHostResolver);
380 context_->set_host_resolver(host_resolver_.get());
381
382 socket_ = new SocketStream(url, websocket_.get());
383 socket_factory_.reset(new MockClientSocketFactory);
384 DCHECK(data_.get());
385 socket_factory_->AddSocketDataProvider(data_.get());
386 socket_->SetClientSocketFactory(socket_factory_.get());
387 }
388
389 websocket_->InitSocketStream(socket_.get());
390 websocket_->set_context(context_.get());
391 struct addrinfo addr;
392 memset(&addr, 0, sizeof(struct addrinfo));
393 addr.ai_family = AF_INET;
394 addr.ai_addrlen = sizeof(struct sockaddr_in);
395 struct sockaddr_in sa_in;
396 memset(&sa_in, 0, sizeof(struct sockaddr_in));
397 memcpy(&sa_in.sin_addr, "\x7f\0\0\1", 4);
398 addr.ai_addr = reinterpret_cast<sockaddr*>(&sa_in);
399 addr.ai_next = NULL;
400 websocket_->addresses_ = AddressList::CreateByCopying(&addr);
401 }
402 void SkipToConnecting() {
403 websocket_->state_ = WebSocketJob::CONNECTING;
404 WebSocketThrottle::GetInstance()->PutInQueue(websocket_);
405 }
406 WebSocketJob::State GetWebSocketJobState() {
407 return websocket_->state_;
408 }
409 void CloseWebSocketJob() {
410 if (websocket_->socket_) {
411 websocket_->socket_->DetachDelegate();
412 WebSocketThrottle::GetInstance()->RemoveFromQueue(websocket_);
413 }
414 websocket_->state_ = WebSocketJob::CLOSED;
415 websocket_->delegate_ = NULL;
416 websocket_->socket_ = NULL;
417 }
418 SocketStream* GetSocket(SocketStreamJob* job) {
419 return job->socket_.get();
420 }
421 const std::string& sent_data() const {
422 DCHECK_EQ(STREAM_MOCK_SOCKET, stream_type_);
423 MockSocketStream* socket =
424 static_cast<MockSocketStream*>(socket_.get());
425 DCHECK(socket);
426 return socket->sent_data();
427 }
428 const std::string& received_data() const {
429 DCHECK_NE(STREAM_INVALID, stream_type_);
430 MockSocketStreamDelegate* delegate =
431 static_cast<MockSocketStreamDelegate*>(websocket_->delegate_);
432 DCHECK(delegate);
433 return delegate->received_data();
434 }
435
436 void TestSimpleHandshake();
437 void TestSlowHandshake();
438 void TestHandshakeWithCookie();
439 void TestHandshakeWithCookieButNotAllowed();
440 void TestHSTSUpgrade();
441 void TestInvalidSendData();
442 void TestConnectByWebSocket(ThrottlingOption throttling);
443 void TestConnectBySpdy(SpdyOption spdy, ThrottlingOption throttling);
444
445 StreamType stream_type_;
446 scoped_refptr<MockCookieStore> cookie_store_;
447 scoped_refptr<MockURLRequestContext> context_;
448 scoped_refptr<WebSocketJob> websocket_;
449 scoped_refptr<SocketStream> socket_;
450 scoped_ptr<MockClientSocketFactory> socket_factory_;
451 scoped_ptr<OrderedSocketData> data_;
452 TestCompletionCallback sync_test_callback_;
453 scoped_refptr<MockSSLConfigService> ssl_config_service_;
454 scoped_ptr<net::ProxyService> proxy_service_;
455 scoped_ptr<net::MockHostResolver> host_resolver_;
456 scoped_ptr<MockHttpTransactionFactory> http_factory_;
457
458 static const char kHandshakeRequestWithoutCookie[];
459 static const char kHandshakeRequestWithCookie[];
460 static const char kHandshakeRequestWithFilteredCookie[];
461 static const char kHandshakeResponseWithoutCookie[];
462 static const char kHandshakeResponseWithCookie[];
463 static const char kDataHello[];
464 static const char kDataWorld[];
465 static const char* const kHandshakeRequestForSpdy[];
466 static const char* const kHandshakeResponseForSpdy[];
467 static const size_t kHandshakeRequestWithoutCookieLength;
468 static const size_t kHandshakeRequestWithCookieLength;
469 static const size_t kHandshakeRequestWithFilteredCookieLength;
470 static const size_t kHandshakeResponseWithoutCookieLength;
471 static const size_t kHandshakeResponseWithCookieLength;
472 static const size_t kDataHelloLength;
473 static const size_t kDataWorldLength;
474 };
475
476 const char WebSocketJobTest::kHandshakeRequestWithoutCookie[] =
477 "GET /demo HTTP/1.1\r\n"
478 "Host: example.com\r\n"
479 "Connection: Upgrade\r\n"
480 "Sec-WebSocket-Key2: 12998 5 Y3 1 .P00\r\n"
481 "Sec-WebSocket-Protocol: sample\r\n"
482 "Upgrade: WebSocket\r\n"
483 "Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5\r\n"
484 "Origin: http://example.com\r\n"
485 "\r\n"
486 "^n:ds[4U";
487
488 const char WebSocketJobTest::kHandshakeRequestWithCookie[] =
489 "GET /demo HTTP/1.1\r\n"
490 "Host: example.com\r\n"
491 "Connection: Upgrade\r\n"
492 "Sec-WebSocket-Key2: 12998 5 Y3 1 .P00\r\n"
493 "Sec-WebSocket-Protocol: sample\r\n"
494 "Upgrade: WebSocket\r\n"
495 "Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5\r\n"
496 "Origin: http://example.com\r\n"
497 "Cookie: WK-test=1\r\n"
498 "\r\n"
499 "^n:ds[4U";
500
501 const char WebSocketJobTest::kHandshakeRequestWithFilteredCookie[] =
502 "GET /demo HTTP/1.1\r\n"
503 "Host: example.com\r\n"
504 "Connection: Upgrade\r\n"
505 "Sec-WebSocket-Key2: 12998 5 Y3 1 .P00\r\n"
506 "Sec-WebSocket-Protocol: sample\r\n"
507 "Upgrade: WebSocket\r\n"
508 "Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5\r\n"
509 "Origin: http://example.com\r\n"
510 "Cookie: CR-test=1; CR-test-httponly=1\r\n"
511 "\r\n"
512 "^n:ds[4U";
513
514 const char WebSocketJobTest::kHandshakeResponseWithoutCookie[] =
515 "HTTP/1.1 101 WebSocket Protocol Handshake\r\n"
516 "Upgrade: WebSocket\r\n"
517 "Connection: Upgrade\r\n"
518 "Sec-WebSocket-Origin: http://example.com\r\n"
519 "Sec-WebSocket-Location: ws://example.com/demo\r\n"
520 "Sec-WebSocket-Protocol: sample\r\n"
521 "\r\n"
522 "8jKS'y:G*Co,Wxa-";
523
524 const char WebSocketJobTest::kHandshakeResponseWithCookie[] =
525 "HTTP/1.1 101 WebSocket Protocol Handshake\r\n"
526 "Upgrade: WebSocket\r\n"
527 "Connection: Upgrade\r\n"
528 "Sec-WebSocket-Origin: http://example.com\r\n"
529 "Sec-WebSocket-Location: ws://example.com/demo\r\n"
530 "Sec-WebSocket-Protocol: sample\r\n"
531 "Set-Cookie: CR-set-test=1\r\n"
532 "\r\n"
533 "8jKS'y:G*Co,Wxa-";
534
535 const char WebSocketJobTest::kDataHello[] = "Hello, ";
536
537 const char WebSocketJobTest::kDataWorld[] = "World!\n";
538
539 // TODO(toyoshim): I should clarify which WebSocket headers for handshake must
540 // be exported to SPDY SYN_STREAM and SYN_REPLY.
541 // Because it depends on HyBi versions, just define it as follow for now.
542 const char* const WebSocketJobTest::kHandshakeRequestForSpdy[] = {
543 "host", "example.com",
544 "origin", "http://example.com",
545 "sec-websocket-protocol", "sample",
546 "url", "ws://example.com/demo"
547 };
548
549 const char* const WebSocketJobTest::kHandshakeResponseForSpdy[] = {
550 "sec-websocket-origin", "http://example.com",
551 "sec-websocket-location", "ws://example.com/demo",
552 "sec-websocket-protocol", "sample",
553 };
554
555 const size_t WebSocketJobTest::kHandshakeRequestWithoutCookieLength =
556 arraysize(kHandshakeRequestWithoutCookie) - 1;
557 const size_t WebSocketJobTest::kHandshakeRequestWithCookieLength =
558 arraysize(kHandshakeRequestWithCookie) - 1;
559 const size_t WebSocketJobTest::kHandshakeRequestWithFilteredCookieLength =
560 arraysize(kHandshakeRequestWithFilteredCookie) - 1;
561 const size_t WebSocketJobTest::kHandshakeResponseWithoutCookieLength =
562 arraysize(kHandshakeResponseWithoutCookie) - 1;
563 const size_t WebSocketJobTest::kHandshakeResponseWithCookieLength =
564 arraysize(kHandshakeResponseWithCookie) - 1;
565 const size_t WebSocketJobTest::kDataHelloLength =
566 arraysize(kDataHello) - 1;
567 const size_t WebSocketJobTest::kDataWorldLength =
568 arraysize(kDataWorld) - 1;
569
570 void WebSocketJobTest::TestSimpleHandshake() {
571 GURL url("ws://example.com/demo");
572 MockSocketStreamDelegate delegate;
573 InitWebSocketJob(url, &delegate, STREAM_MOCK_SOCKET);
574 SkipToConnecting();
575
576 DoSendRequest();
577 MessageLoop::current()->RunAllPending();
578 EXPECT_EQ(kHandshakeRequestWithoutCookie, sent_data());
579 EXPECT_EQ(WebSocketJob::CONNECTING, GetWebSocketJobState());
580 websocket_->OnSentData(socket_.get(),
581 kHandshakeRequestWithoutCookieLength);
582 EXPECT_EQ(kHandshakeRequestWithoutCookieLength, delegate.amount_sent());
583
584 websocket_->OnReceivedData(socket_.get(),
585 kHandshakeResponseWithoutCookie,
586 kHandshakeResponseWithoutCookieLength);
587 MessageLoop::current()->RunAllPending();
588 EXPECT_EQ(kHandshakeResponseWithoutCookie, delegate.received_data());
589 EXPECT_EQ(WebSocketJob::OPEN, GetWebSocketJobState());
590 CloseWebSocketJob();
591 }
592
593 void WebSocketJobTest::TestSlowHandshake() {
594 GURL url("ws://example.com/demo");
595 MockSocketStreamDelegate delegate;
596 InitWebSocketJob(url, &delegate, STREAM_MOCK_SOCKET);
597 SkipToConnecting();
598
599 DoSendRequest();
600 // We assume request is sent in one data chunk (from WebKit)
601 // We don't support streaming request.
602 MessageLoop::current()->RunAllPending();
603 EXPECT_EQ(kHandshakeRequestWithoutCookie, sent_data());
604 EXPECT_EQ(WebSocketJob::CONNECTING, GetWebSocketJobState());
605 websocket_->OnSentData(socket_.get(),
606 kHandshakeRequestWithoutCookieLength);
607 EXPECT_EQ(kHandshakeRequestWithoutCookieLength, delegate.amount_sent());
608
609 std::vector<std::string> lines;
610 base::SplitString(kHandshakeResponseWithoutCookie, '\n', &lines);
611 for (size_t i = 0; i < lines.size() - 2; i++) {
612 std::string line = lines[i] + "\r\n";
613 SCOPED_TRACE("Line: " + line);
614 websocket_->OnReceivedData(socket_,
615 line.c_str(),
616 line.size());
617 MessageLoop::current()->RunAllPending();
618 EXPECT_TRUE(delegate.received_data().empty());
619 EXPECT_EQ(WebSocketJob::CONNECTING, GetWebSocketJobState());
620 }
621 websocket_->OnReceivedData(socket_.get(), "\r\n", 2);
622 MessageLoop::current()->RunAllPending();
623 EXPECT_TRUE(delegate.received_data().empty());
624 EXPECT_EQ(WebSocketJob::CONNECTING, GetWebSocketJobState());
625 websocket_->OnReceivedData(socket_.get(), "8jKS'y:G*Co,Wxa-", 16);
626 EXPECT_EQ(kHandshakeResponseWithoutCookie, delegate.received_data());
627 EXPECT_EQ(WebSocketJob::OPEN, GetWebSocketJobState());
628 CloseWebSocketJob();
629 }
630
631 TEST_F(WebSocketJobTest, DelayedCookies) {
632 WebSocketJob::set_websocket_over_spdy_enabled(true);
633 GURL url("ws://example.com/demo");
634 GURL cookieUrl("http://example.com/demo");
635 CookieOptions cookie_options;
636 scoped_refptr<DelayedCookieMonster> cookie_store = new DelayedCookieMonster();
637 context_->set_cookie_store(cookie_store);
638 cookie_store->SetCookieWithOptionsAsync(
639 cookieUrl, "CR-test=1", cookie_options,
640 net::CookieMonster::SetCookiesCallback());
641 cookie_options.set_include_httponly();
642 cookie_store->SetCookieWithOptionsAsync(
643 cookieUrl, "CR-test-httponly=1", cookie_options,
644 net::CookieMonster::SetCookiesCallback());
645
646 MockSocketStreamDelegate delegate;
647 InitWebSocketJob(url, &delegate, STREAM_MOCK_SOCKET);
648 SkipToConnecting();
649
650 bool sent = websocket_->SendData(kHandshakeRequestWithCookie,
651 kHandshakeRequestWithCookieLength);
652 EXPECT_TRUE(sent);
653 MessageLoop::current()->RunAllPending();
654 EXPECT_EQ(kHandshakeRequestWithFilteredCookie, sent_data());
655 EXPECT_EQ(WebSocketJob::CONNECTING, GetWebSocketJobState());
656 websocket_->OnSentData(socket_,
657 kHandshakeRequestWithFilteredCookieLength);
658 EXPECT_EQ(kHandshakeRequestWithCookieLength,
659 delegate.amount_sent());
660
661 websocket_->OnReceivedData(socket_.get(),
662 kHandshakeResponseWithCookie,
663 kHandshakeResponseWithCookieLength);
664 MessageLoop::current()->RunAllPending();
665 EXPECT_EQ(kHandshakeResponseWithoutCookie, delegate.received_data());
666 EXPECT_EQ(WebSocketJob::OPEN, GetWebSocketJobState());
667
668 CloseWebSocketJob();
669 }
670
671 void WebSocketJobTest::TestHandshakeWithCookie() {
672 GURL url("ws://example.com/demo");
673 GURL cookieUrl("http://example.com/demo");
674 CookieOptions cookie_options;
675 cookie_store_->SetCookieWithOptions(
676 cookieUrl, "CR-test=1", cookie_options);
677 cookie_options.set_include_httponly();
678 cookie_store_->SetCookieWithOptions(
679 cookieUrl, "CR-test-httponly=1", cookie_options);
680
681 MockSocketStreamDelegate delegate;
682 InitWebSocketJob(url, &delegate, STREAM_MOCK_SOCKET);
683 SkipToConnecting();
684
685 bool sent = websocket_->SendData(kHandshakeRequestWithCookie,
686 kHandshakeRequestWithCookieLength);
687 EXPECT_TRUE(sent);
688 MessageLoop::current()->RunAllPending();
689 EXPECT_EQ(kHandshakeRequestWithFilteredCookie, sent_data());
690 EXPECT_EQ(WebSocketJob::CONNECTING, GetWebSocketJobState());
691 websocket_->OnSentData(socket_,
692 kHandshakeRequestWithFilteredCookieLength);
693 EXPECT_EQ(kHandshakeRequestWithCookieLength,
694 delegate.amount_sent());
695
696 websocket_->OnReceivedData(socket_.get(),
697 kHandshakeResponseWithCookie,
698 kHandshakeResponseWithCookieLength);
699 MessageLoop::current()->RunAllPending();
700 EXPECT_EQ(kHandshakeResponseWithoutCookie, delegate.received_data());
701 EXPECT_EQ(WebSocketJob::OPEN, GetWebSocketJobState());
702
703 EXPECT_EQ(3U, cookie_store_->entries().size());
704 EXPECT_EQ(cookieUrl, cookie_store_->entries()[0].url);
705 EXPECT_EQ("CR-test=1", cookie_store_->entries()[0].cookie_line);
706 EXPECT_EQ(cookieUrl, cookie_store_->entries()[1].url);
707 EXPECT_EQ("CR-test-httponly=1", cookie_store_->entries()[1].cookie_line);
708 EXPECT_EQ(cookieUrl, cookie_store_->entries()[2].url);
709 EXPECT_EQ("CR-set-test=1", cookie_store_->entries()[2].cookie_line);
710
711 CloseWebSocketJob();
712 }
713
714 void WebSocketJobTest::TestHandshakeWithCookieButNotAllowed() {
715 GURL url("ws://example.com/demo");
716 GURL cookieUrl("http://example.com/demo");
717 CookieOptions cookie_options;
718 cookie_store_->SetCookieWithOptions(
719 cookieUrl, "CR-test=1", cookie_options);
720 cookie_options.set_include_httponly();
721 cookie_store_->SetCookieWithOptions(
722 cookieUrl, "CR-test-httponly=1", cookie_options);
723
724 MockSocketStreamDelegate delegate;
725 delegate.set_allow_all_cookies(false);
726 InitWebSocketJob(url, &delegate, STREAM_MOCK_SOCKET);
727 SkipToConnecting();
728
729 bool sent = websocket_->SendData(kHandshakeRequestWithCookie,
730 kHandshakeRequestWithCookieLength);
731 EXPECT_TRUE(sent);
732 MessageLoop::current()->RunAllPending();
733 EXPECT_EQ(kHandshakeRequestWithoutCookie, sent_data());
734 EXPECT_EQ(WebSocketJob::CONNECTING, GetWebSocketJobState());
735 websocket_->OnSentData(socket_, kHandshakeRequestWithoutCookieLength);
736 EXPECT_EQ(kHandshakeRequestWithCookieLength,
737 delegate.amount_sent());
738
739 websocket_->OnReceivedData(socket_.get(),
740 kHandshakeResponseWithCookie,
741 kHandshakeResponseWithCookieLength);
742 MessageLoop::current()->RunAllPending();
743 EXPECT_EQ(kHandshakeResponseWithoutCookie, delegate.received_data());
744 EXPECT_EQ(WebSocketJob::OPEN, GetWebSocketJobState());
745
746 EXPECT_EQ(2U, cookie_store_->entries().size());
747 EXPECT_EQ(cookieUrl, cookie_store_->entries()[0].url);
748 EXPECT_EQ("CR-test=1", cookie_store_->entries()[0].cookie_line);
749 EXPECT_EQ(cookieUrl, cookie_store_->entries()[1].url);
750 EXPECT_EQ("CR-test-httponly=1", cookie_store_->entries()[1].cookie_line);
751
752 CloseWebSocketJob();
753 }
754
755 void WebSocketJobTest::TestHSTSUpgrade() {
756 GURL url("ws://upgrademe.com/");
757 MockSocketStreamDelegate delegate;
758 scoped_refptr<SocketStreamJob> job =
759 SocketStreamJob::CreateSocketStreamJob(
760 url, &delegate, context_->transport_security_state(),
761 context_->ssl_config_service());
762 EXPECT_TRUE(GetSocket(job.get())->is_secure());
763 job->DetachDelegate();
764
765 url = GURL("ws://donotupgrademe.com/");
766 job = SocketStreamJob::CreateSocketStreamJob(
767 url, &delegate, context_->transport_security_state(),
768 context_->ssl_config_service());
769 EXPECT_FALSE(GetSocket(job.get())->is_secure());
770 job->DetachDelegate();
771 }
772
773 void WebSocketJobTest::TestInvalidSendData() {
774 GURL url("ws://example.com/demo");
775 MockSocketStreamDelegate delegate;
776 InitWebSocketJob(url, &delegate, STREAM_MOCK_SOCKET);
777 SkipToConnecting();
778
779 DoSendRequest();
780 // We assume request is sent in one data chunk (from WebKit)
781 // We don't support streaming request.
782 MessageLoop::current()->RunAllPending();
783 EXPECT_EQ(kHandshakeRequestWithoutCookie, sent_data());
784 EXPECT_EQ(WebSocketJob::CONNECTING, GetWebSocketJobState());
785 websocket_->OnSentData(socket_.get(),
786 kHandshakeRequestWithoutCookieLength);
787 EXPECT_EQ(kHandshakeRequestWithoutCookieLength, delegate.amount_sent());
788
789 // We could not send any data until connection is established.
790 bool sent = websocket_->SendData(kHandshakeRequestWithoutCookie,
791 kHandshakeRequestWithoutCookieLength);
792 EXPECT_FALSE(sent);
793 EXPECT_EQ(WebSocketJob::CONNECTING, GetWebSocketJobState());
794 CloseWebSocketJob();
795 }
796
797 // Following tests verify cooperation between WebSocketJob and SocketStream.
798 // Other former tests use MockSocketStream as SocketStream, so we could not
799 // check SocketStream behavior.
800 // OrderedSocketData provide socket level verifiation by checking out-going
801 // packets in comparison with the MockWrite array and emulating in-coming
802 // packets with MockRead array.
803
804 void WebSocketJobTest::TestConnectByWebSocket(ThrottlingOption throttling) {
805 // This is a test for verifying cooperation between WebSocketJob and
806 // SocketStream. If |throttling| was |THROTTLING_OFF|, it test basic
807 // situation. If |throttling| was |THROTTLING_ON|, throttling limits the
808 // latter connection.
809 MockWrite writes[] = {
810 MockWrite(ASYNC,
811 kHandshakeRequestWithoutCookie,
812 kHandshakeRequestWithoutCookieLength,
813 1),
814 MockWrite(ASYNC,
815 kDataHello,
816 kDataHelloLength,
817 3)
818 };
819 MockRead reads[] = {
820 MockRead(ASYNC,
821 kHandshakeResponseWithoutCookie,
822 kHandshakeResponseWithoutCookieLength,
823 2),
824 MockRead(ASYNC,
825 kDataWorld,
826 kDataWorldLength,
827 4),
828 MockRead(SYNCHRONOUS, 0, 5) // EOF
829 };
830 data_.reset(new OrderedSocketData(
831 reads, arraysize(reads), writes, arraysize(writes)));
832
833 GURL url("ws://example.com/demo");
834 MockSocketStreamDelegate delegate;
835 WebSocketJobTest* test = this;
836 if (throttling == THROTTLING_ON)
837 delegate.SetOnStartOpenConnection(
838 base::Bind(&WebSocketJobTest::DoSync, base::Unretained(test)));
839 delegate.SetOnConnected(
840 base::Bind(&WebSocketJobTest::DoSendRequest, base::Unretained(test)));
841 delegate.SetOnReceivedData(
842 base::Bind(&WebSocketJobTest::DoSendData, base::Unretained(test)));
843 delegate.SetOnClose(
844 base::Bind(&WebSocketJobTest::DoSync, base::Unretained(test)));
845 InitWebSocketJob(url, &delegate, STREAM_SOCKET);
846
847 scoped_refptr<WebSocketJob> block_websocket;
848 if (throttling == THROTTLING_ON) {
849 // Create former WebSocket object which obstructs the latter one.
850 block_websocket = new WebSocketJob(NULL);
851 block_websocket->addresses_ = AddressList(websocket_->address_list());
852 WebSocketThrottle::GetInstance()->PutInQueue(block_websocket.get());
853 }
854
855 websocket_->Connect();
856
857 if (throttling == THROTTLING_ON) {
858 EXPECT_EQ(OK, WaitForResult());
859 EXPECT_TRUE(websocket_->IsWaiting());
860
861 // Remove the former WebSocket object from throttling queue to unblock the
862 // latter.
863 WebSocketThrottle::GetInstance()->RemoveFromQueue(block_websocket);
864 block_websocket->state_ = WebSocketJob::CLOSED;
865 block_websocket = NULL;
866 WebSocketThrottle::GetInstance()->WakeupSocketIfNecessary();
867 }
868
869 EXPECT_EQ(OK, WaitForResult());
870 EXPECT_TRUE(data_->at_read_eof());
871 EXPECT_TRUE(data_->at_write_eof());
872 EXPECT_EQ(WebSocketJob::CLOSED, GetWebSocketJobState());
873 }
874
875 void WebSocketJobTest::TestConnectBySpdy(
876 SpdyOption spdy, ThrottlingOption throttling) {
877 // This is a test for verifying cooperation between WebSocketJob and
878 // SocketStream in the situation we have SPDY session to the server. If
879 // |throttling| was |THROTTLING_ON|, throttling limits the latter connection.
880 // If you enabled spdy, you should specify |spdy| as |SPDY_ON|. Expected
881 // results depend on its configuration.
882 MockWrite writes_websocket[] = {
883 MockWrite(ASYNC,
884 kHandshakeRequestWithoutCookie,
885 kHandshakeRequestWithoutCookieLength,
886 1),
887 MockWrite(ASYNC,
888 kDataHello,
889 kDataHelloLength,
890 3)
891 };
892 MockRead reads_websocket[] = {
893 MockRead(ASYNC,
894 kHandshakeResponseWithoutCookie,
895 kHandshakeResponseWithoutCookieLength,
896 2),
897 MockRead(ASYNC,
898 kDataWorld,
899 kDataWorldLength,
900 4),
901 MockRead(SYNCHRONOUS, 0, 5) // EOF
902 };
903
904 const spdy::SpdyStreamId kStreamId = 1;
905 scoped_ptr<spdy::SpdyFrame> request_frame(
906 ConstructSpdyWebSocketHandshakeRequestFrame(
907 kHandshakeRequestForSpdy,
908 arraysize(kHandshakeRequestForSpdy) / 2,
909 kStreamId,
910 MEDIUM));
911 scoped_ptr<spdy::SpdyFrame> response_frame(
912 ConstructSpdyWebSocketHandshakeResponseFrame(
913 kHandshakeResponseForSpdy,
914 arraysize(kHandshakeResponseForSpdy) / 2,
915 kStreamId,
916 MEDIUM));
917 scoped_ptr<spdy::SpdyFrame> data_hello_frame(
918 ConstructSpdyWebSocketDataFrame(
919 kDataHello,
920 kDataHelloLength,
921 kStreamId,
922 false));
923 scoped_ptr<spdy::SpdyFrame> data_world_frame(
924 ConstructSpdyWebSocketDataFrame(
925 kDataWorld,
926 kDataWorldLength,
927 kStreamId,
928 false));
929 MockWrite writes_spdy[] = {
930 CreateMockWrite(*request_frame.get(), 1),
931 CreateMockWrite(*data_hello_frame.get(), 3),
932 };
933 MockRead reads_spdy[] = {
934 CreateMockRead(*response_frame.get(), 2),
935 CreateMockRead(*data_world_frame.get(), 4),
936 MockRead(SYNCHRONOUS, 0, 5) // EOF
937 };
938
939 if (spdy == SPDY_ON)
940 data_.reset(new OrderedSocketData(
941 reads_spdy, arraysize(reads_spdy),
942 writes_spdy, arraysize(writes_spdy)));
943 else
944 data_.reset(new OrderedSocketData(
945 reads_websocket, arraysize(reads_websocket),
946 writes_websocket, arraysize(writes_websocket)));
947
948 GURL url("ws://example.com/demo");
949 MockSocketStreamDelegate delegate;
950 WebSocketJobTest* test = this;
951 if (throttling == THROTTLING_ON)
952 delegate.SetOnStartOpenConnection(
953 base::Bind(&WebSocketJobTest::DoSync, base::Unretained(test)));
954 delegate.SetOnConnected(
955 base::Bind(&WebSocketJobTest::DoSendRequest, base::Unretained(test)));
956 delegate.SetOnReceivedData(
957 base::Bind(&WebSocketJobTest::DoSendData, base::Unretained(test)));
958 delegate.SetOnClose(
959 base::Bind(&WebSocketJobTest::DoSync, base::Unretained(test)));
960 InitWebSocketJob(url, &delegate, STREAM_SPDY_WEBSOCKET);
961
962 scoped_refptr<WebSocketJob> block_websocket;
963 if (throttling == THROTTLING_ON) {
964 // Create former WebSocket object which obstructs the latter one.
965 block_websocket = new WebSocketJob(NULL);
966 block_websocket->addresses_ = AddressList(websocket_->address_list());
967 WebSocketThrottle::GetInstance()->PutInQueue(block_websocket.get());
968 }
969
970 websocket_->Connect();
971
972 if (throttling == THROTTLING_ON) {
973 EXPECT_EQ(OK, WaitForResult());
974 EXPECT_TRUE(websocket_->IsWaiting());
975
976 // Remove the former WebSocket object from throttling queue to unblock the
977 // latter.
978 WebSocketThrottle::GetInstance()->RemoveFromQueue(block_websocket);
979 block_websocket->state_ = WebSocketJob::CLOSED;
980 block_websocket = NULL;
981 WebSocketThrottle::GetInstance()->WakeupSocketIfNecessary();
982 }
983
984 EXPECT_EQ(OK, WaitForResult());
985 EXPECT_TRUE(data_->at_read_eof());
986 EXPECT_TRUE(data_->at_write_eof());
987 EXPECT_EQ(WebSocketJob::CLOSED, GetWebSocketJobState());
988 }
989
990 // Execute tests in both spdy-disabled mode and spdy-enabled mode.
991 TEST_F(WebSocketJobTest, SimpleHandshake) {
992 WebSocketJob::set_websocket_over_spdy_enabled(false);
993 TestSimpleHandshake();
994 }
995
996 TEST_F(WebSocketJobTest, SlowHandshake) {
997 WebSocketJob::set_websocket_over_spdy_enabled(false);
998 TestSlowHandshake();
999 }
1000
1001 TEST_F(WebSocketJobTest, HandshakeWithCookie) {
1002 WebSocketJob::set_websocket_over_spdy_enabled(false);
1003 TestHandshakeWithCookie();
1004 }
1005
1006 TEST_F(WebSocketJobTest, HandshakeWithCookieButNotAllowed) {
1007 WebSocketJob::set_websocket_over_spdy_enabled(false);
1008 TestHandshakeWithCookieButNotAllowed();
1009 }
1010
1011 TEST_F(WebSocketJobTest, HSTSUpgrade) {
1012 WebSocketJob::set_websocket_over_spdy_enabled(false);
1013 TestHSTSUpgrade();
1014 }
1015
1016 TEST_F(WebSocketJobTest, InvalidSendData) {
1017 WebSocketJob::set_websocket_over_spdy_enabled(false);
1018 TestInvalidSendData();
1019 }
1020
1021 TEST_F(WebSocketJobTest, SimpleHandshakeSpdyEnabled) {
1022 WebSocketJob::set_websocket_over_spdy_enabled(true);
1023 TestSimpleHandshake();
1024 }
1025
1026 TEST_F(WebSocketJobTest, SlowHandshakeSpdyEnabled) {
1027 WebSocketJob::set_websocket_over_spdy_enabled(true);
1028 TestSlowHandshake();
1029 }
1030
1031 TEST_F(WebSocketJobTest, HandshakeWithCookieSpdyEnabled) {
1032 WebSocketJob::set_websocket_over_spdy_enabled(true);
1033 TestHandshakeWithCookie();
1034 }
1035
1036 TEST_F(WebSocketJobTest, HandshakeWithCookieButNotAllowedSpdyEnabled) {
1037 WebSocketJob::set_websocket_over_spdy_enabled(true);
1038 TestHandshakeWithCookieButNotAllowed();
1039 }
1040
1041 TEST_F(WebSocketJobTest, HSTSUpgradeSpdyEnabled) {
1042 WebSocketJob::set_websocket_over_spdy_enabled(true);
1043 TestHSTSUpgrade();
1044 }
1045
1046 TEST_F(WebSocketJobTest, InvalidSendDataSpdyEnabled) {
1047 WebSocketJob::set_websocket_over_spdy_enabled(true);
1048 TestInvalidSendData();
1049 }
1050
1051 TEST_F(WebSocketJobTest, ConnectByWebSocket) {
1052 WebSocketJob::set_websocket_over_spdy_enabled(false);
1053 TestConnectByWebSocket(THROTTLING_OFF);
1054 }
1055
1056 TEST_F(WebSocketJobTest, ConnectByWebSocketSpdyEnabled) {
1057 WebSocketJob::set_websocket_over_spdy_enabled(true);
1058 TestConnectByWebSocket(THROTTLING_OFF);
1059 }
1060
1061 TEST_F(WebSocketJobTest, ConnectBySpdy) {
1062 WebSocketJob::set_websocket_over_spdy_enabled(false);
1063 TestConnectBySpdy(SPDY_OFF, THROTTLING_OFF);
1064 }
1065
1066 TEST_F(WebSocketJobTest, ConnectBySpdySpdyEnabled) {
1067 WebSocketJob::set_websocket_over_spdy_enabled(true);
1068 TestConnectBySpdy(SPDY_ON, THROTTLING_OFF);
1069 }
1070
1071 TEST_F(WebSocketJobTest, ThrottlingWebSocket) {
1072 WebSocketJob::set_websocket_over_spdy_enabled(false);
1073 TestConnectByWebSocket(THROTTLING_ON);
1074 }
1075
1076 TEST_F(WebSocketJobTest, ThrottlingWebSocketSpdyEnabled) {
1077 WebSocketJob::set_websocket_over_spdy_enabled(true);
1078 TestConnectByWebSocket(THROTTLING_ON);
1079 }
1080
1081 TEST_F(WebSocketJobTest, ThrottlingSpdy) {
1082 WebSocketJob::set_websocket_over_spdy_enabled(false);
1083 TestConnectBySpdy(SPDY_OFF, THROTTLING_ON);
1084 }
1085
1086 TEST_F(WebSocketJobTest, ThrottlingSpdySpdyEnabled) {
1087 WebSocketJob::set_websocket_over_spdy_enabled(true);
1088 TestConnectBySpdy(SPDY_ON, THROTTLING_ON);
1089 }
1090
1091 // TODO(toyoshim): Add tests to verify throttling, SPDY stream limitation.
1092 // TODO(toyoshim,yutak): Add tests to verify closing handshake.
1093
1094 } // namespace net
OLDNEW
« no previous file with comments | « net/websockets/websocket_job_spdy3_unittest.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698