1 // Copyright (c) 2017 The Chromium Embedded Framework Authors. All rights
2 // reserved. Use of this source code is governed by a BSD-style license that
3 // can be found in the LICENSE file.
4
5 #include <list>
6 #include <map>
7 #include <set>
8
9 #include "include/base/cef_bind.h"
10 #include "include/base/cef_ref_counted.h"
11 #include "include/base/cef_scoped_ptr.h"
12 #include "include/cef_command_line.h"
13 #include "include/cef_server.h"
14 #include "include/cef_task.h"
15 #include "include/cef_urlrequest.h"
16 #include "include/wrapper/cef_closure_task.h"
17 #include "tests/ceftests/routing_test_handler.h"
18 #include "tests/ceftests/test_util.h"
19 #include "tests/gtest/include/gtest/gtest.h"
20
21 namespace {
22
23 // Must use a different port than test_server.cc.
24 const char kTestServerAddress[] = "127.0.0.1";
25 const uint16 kTestServerPort = 8099;
26 const int kTestTimeout = 5000;
27
GetTestServerOrigin(bool is_websocket)28 std::string GetTestServerOrigin(bool is_websocket) {
29 std::stringstream ss;
30 ss << (is_websocket ? "ws://" : "http://") << kTestServerAddress << ":"
31 << kTestServerPort;
32 return ss.str();
33 }
34
35 // Handles the test server. Used for both HTTP and WebSocket tests.
36 class TestServerHandler : public CefServerHandler {
37 public:
38 // HTTP test handler.
39 // The methods of this class are always executed on the server thread.
40 class HttpRequestHandler {
41 public:
~HttpRequestHandler()42 virtual ~HttpRequestHandler() {}
43 virtual bool HandleRequest(CefRefPtr<CefServer> server,
44 int connection_id,
45 const CefString& client_address,
46 CefRefPtr<CefRequest> request) = 0;
47 virtual bool VerifyResults() = 0;
48 virtual std::string ToString() = 0;
49 };
50
51 // WebSocket test handler.
52 // The methods of this class are always executed on the server thread.
53 class WsRequestHandler {
54 public:
~WsRequestHandler()55 virtual ~WsRequestHandler() {}
56 virtual bool HandleRequest(CefRefPtr<CefServer> server,
57 int connection_id,
58 const CefString& client_address,
59 CefRefPtr<CefRequest> request,
60 CefRefPtr<CefCallback> callback) = 0;
61 virtual bool HandleConnected(CefRefPtr<CefServer> server,
62 int connection_id) = 0;
63 virtual bool HandleMessage(CefRefPtr<CefServer> server,
64 int connection_id,
65 const void* data,
66 size_t data_size) = 0;
67 virtual bool VerifyResults() = 0;
68 virtual std::string ToString() = 0;
69 };
70
71 // |start_callback| will be executed on the UI thread after the server is
72 // started.
73 // |destroy_callback| will be executed on the UI thread after this handler
74 // object is destroyed.
TestServerHandler(const base::Closure & start_callback,const base::Closure & destroy_callback)75 TestServerHandler(const base::Closure& start_callback,
76 const base::Closure& destroy_callback)
77 : initialized_(false),
78 start_callback_(start_callback),
79 destroy_callback_(destroy_callback),
80 expected_connection_ct_(0),
81 actual_connection_ct_(0),
82 expected_http_request_ct_(0),
83 actual_http_request_ct_(0),
84 expected_ws_request_ct_(0),
85 actual_ws_request_ct_(0),
86 expected_ws_connected_ct_(0),
87 actual_ws_connected_ct_(0),
88 expected_ws_message_ct_(0),
89 actual_ws_message_ct_(0) {
90 EXPECT_FALSE(destroy_callback_.is_null());
91 }
92
~TestServerHandler()93 virtual ~TestServerHandler() {
94 EXPECT_UI_THREAD();
95
96 if (!http_request_handler_list_.empty()) {
97 HttpRequestHandlerList::const_iterator it =
98 http_request_handler_list_.begin();
99 for (; it != http_request_handler_list_.end(); ++it)
100 delete *it;
101 }
102
103 if (!ws_request_handler_list_.empty()) {
104 WsRequestHandlerList::const_iterator it =
105 ws_request_handler_list_.begin();
106 for (; it != ws_request_handler_list_.end(); ++it)
107 delete *it;
108 }
109
110 destroy_callback_.Run();
111 }
112
113 // Must be called before CreateServer().
SetExpectedConnectionCount(int expected)114 void SetExpectedConnectionCount(int expected) {
115 EXPECT_FALSE(initialized_);
116 expected_connection_ct_ = expected;
117 }
118
119 // Must be called before CreateServer().
AddHttpRequestHandler(scoped_ptr<HttpRequestHandler> request_handler)120 void AddHttpRequestHandler(scoped_ptr<HttpRequestHandler> request_handler) {
121 EXPECT_FALSE(initialized_);
122 EXPECT_TRUE(request_handler);
123 http_request_handler_list_.push_back(request_handler.release());
124 }
125
126 // Must be called before CreateServer().
SetExpectedHttpRequestCount(int expected)127 void SetExpectedHttpRequestCount(int expected) {
128 EXPECT_FALSE(initialized_);
129 expected_http_request_ct_ = expected;
130 }
131
132 // Must be called before CreateServer().
AddWsRequestHandler(scoped_ptr<WsRequestHandler> request_handler)133 void AddWsRequestHandler(scoped_ptr<WsRequestHandler> request_handler) {
134 EXPECT_FALSE(initialized_);
135 EXPECT_TRUE(request_handler);
136 ws_request_handler_list_.push_back(request_handler.release());
137 }
138
139 // Must be called before CreateServer().
SetExpectedWsRequestCount(int expected)140 void SetExpectedWsRequestCount(int expected) {
141 EXPECT_FALSE(initialized_);
142 expected_ws_request_ct_ = expected;
143 }
144
145 // Must be called before CreateServer().
SetExpectedWsConnectedCount(int expected)146 void SetExpectedWsConnectedCount(int expected) {
147 EXPECT_FALSE(initialized_);
148 expected_ws_connected_ct_ = expected;
149 }
150
151 // Must be called before CreateServer().
SetExpectedWsMessageCount(int expected)152 void SetExpectedWsMessageCount(int expected) {
153 EXPECT_FALSE(initialized_);
154 expected_ws_message_ct_ = expected;
155 }
156
CreateServer()157 void CreateServer() {
158 EXPECT_FALSE(initialized_);
159 initialized_ = true;
160 CefServer::CreateServer(kTestServerAddress, kTestServerPort, 10, this);
161 }
162
163 // Results in a call to VerifyResults() and eventual execution of the
164 // |destroy_callback|.
ShutdownServer()165 void ShutdownServer() {
166 EXPECT_TRUE(server_);
167 if (server_)
168 server_->Shutdown();
169 }
170
OnServerCreated(CefRefPtr<CefServer> server)171 void OnServerCreated(CefRefPtr<CefServer> server) override {
172 EXPECT_TRUE(server);
173 EXPECT_TRUE(server->IsRunning());
174 EXPECT_FALSE(server->HasConnection());
175
176 EXPECT_FALSE(got_server_created_);
177 got_server_created_.yes();
178
179 EXPECT_FALSE(server_);
180 server_ = server;
181
182 EXPECT_FALSE(server_runner_);
183 server_runner_ = server_->GetTaskRunner();
184 EXPECT_TRUE(server_runner_);
185 EXPECT_TRUE(server_runner_->BelongsToCurrentThread());
186
187 RunStartCallback();
188 }
189
OnServerDestroyed(CefRefPtr<CefServer> server)190 void OnServerDestroyed(CefRefPtr<CefServer> server) override {
191 EXPECT_TRUE(VerifyServer(server));
192 EXPECT_FALSE(server->IsRunning());
193 EXPECT_FALSE(server->HasConnection());
194
195 EXPECT_FALSE(got_server_destroyed_);
196 got_server_destroyed_.yes();
197
198 server_ = nullptr;
199
200 VerifyResults();
201 }
202
OnClientConnected(CefRefPtr<CefServer> server,int connection_id)203 void OnClientConnected(CefRefPtr<CefServer> server,
204 int connection_id) override {
205 EXPECT_TRUE(VerifyServer(server));
206 EXPECT_TRUE(server->HasConnection());
207 EXPECT_TRUE(server->IsValidConnection(connection_id));
208
209 EXPECT_TRUE(connection_id_set_.find(connection_id) ==
210 connection_id_set_.end());
211 connection_id_set_.insert(connection_id);
212
213 actual_connection_ct_++;
214 }
215
OnClientDisconnected(CefRefPtr<CefServer> server,int connection_id)216 void OnClientDisconnected(CefRefPtr<CefServer> server,
217 int connection_id) override {
218 EXPECT_TRUE(VerifyServer(server));
219 EXPECT_FALSE(server->IsValidConnection(connection_id));
220
221 ConnectionIdSet::iterator it = connection_id_set_.find(connection_id);
222 EXPECT_TRUE(it != connection_id_set_.end());
223 connection_id_set_.erase(it);
224
225 ConnectionIdSet::iterator it2 = ws_connection_id_set_.find(connection_id);
226 if (it2 != ws_connection_id_set_.end())
227 ws_connection_id_set_.erase(it2);
228
229 if (connection_id_set_.empty()) {
230 EXPECT_TRUE(ws_connection_id_set_.empty());
231 EXPECT_FALSE(server->HasConnection());
232 }
233 }
234
OnHttpRequest(CefRefPtr<CefServer> server,int connection_id,const CefString & client_address,CefRefPtr<CefRequest> request)235 void OnHttpRequest(CefRefPtr<CefServer> server,
236 int connection_id,
237 const CefString& client_address,
238 CefRefPtr<CefRequest> request) override {
239 EXPECT_TRUE(VerifyServer(server));
240 EXPECT_TRUE(VerifyConnection(connection_id));
241 EXPECT_FALSE(client_address.empty());
242 EXPECT_TRUE(VerifyRequest(request, false));
243
244 bool handled = false;
245 HttpRequestHandlerList::const_iterator it =
246 http_request_handler_list_.begin();
247 for (; it != http_request_handler_list_.end(); ++it) {
248 handled =
249 (*it)->HandleRequest(server, connection_id, client_address, request);
250 if (handled)
251 break;
252 }
253 EXPECT_TRUE(handled) << "missing HttpRequestHandler for "
254 << request->GetURL().ToString();
255
256 actual_http_request_ct_++;
257 }
258
OnWebSocketRequest(CefRefPtr<CefServer> server,int connection_id,const CefString & client_address,CefRefPtr<CefRequest> request,CefRefPtr<CefCallback> callback)259 void OnWebSocketRequest(CefRefPtr<CefServer> server,
260 int connection_id,
261 const CefString& client_address,
262 CefRefPtr<CefRequest> request,
263 CefRefPtr<CefCallback> callback) override {
264 EXPECT_TRUE(VerifyServer(server));
265 EXPECT_TRUE(VerifyConnection(connection_id));
266 EXPECT_FALSE(client_address.empty());
267 EXPECT_TRUE(VerifyRequest(request, true));
268
269 EXPECT_TRUE(ws_connection_id_set_.find(connection_id) ==
270 ws_connection_id_set_.end());
271 ws_connection_id_set_.insert(connection_id);
272
273 bool handled = false;
274 WsRequestHandlerList::const_iterator it = ws_request_handler_list_.begin();
275 for (; it != ws_request_handler_list_.end(); ++it) {
276 handled = (*it)->HandleRequest(server, connection_id, client_address,
277 request, callback);
278 if (handled)
279 break;
280 }
281 EXPECT_TRUE(handled) << "missing WsRequestHandler for "
282 << request->GetURL().ToString();
283
284 actual_ws_request_ct_++;
285 }
286
OnWebSocketConnected(CefRefPtr<CefServer> server,int connection_id)287 void OnWebSocketConnected(CefRefPtr<CefServer> server,
288 int connection_id) override {
289 EXPECT_TRUE(VerifyServer(server));
290 EXPECT_TRUE(VerifyConnection(connection_id));
291
292 EXPECT_TRUE(ws_connection_id_set_.find(connection_id) !=
293 ws_connection_id_set_.end());
294
295 bool handled = false;
296 WsRequestHandlerList::const_iterator it = ws_request_handler_list_.begin();
297 for (; it != ws_request_handler_list_.end(); ++it) {
298 handled = (*it)->HandleConnected(server, connection_id);
299 if (handled)
300 break;
301 }
302 EXPECT_TRUE(handled) << "missing WsRequestHandler for " << connection_id;
303
304 actual_ws_connected_ct_++;
305 }
306
OnWebSocketMessage(CefRefPtr<CefServer> server,int connection_id,const void * data,size_t data_size)307 void OnWebSocketMessage(CefRefPtr<CefServer> server,
308 int connection_id,
309 const void* data,
310 size_t data_size) override {
311 EXPECT_TRUE(VerifyServer(server));
312 EXPECT_TRUE(VerifyConnection(connection_id));
313 EXPECT_TRUE(data);
314 EXPECT_GT(data_size, 0U);
315
316 EXPECT_TRUE(ws_connection_id_set_.find(connection_id) !=
317 ws_connection_id_set_.end());
318
319 bool handled = false;
320 WsRequestHandlerList::const_iterator it = ws_request_handler_list_.begin();
321 for (; it != ws_request_handler_list_.end(); ++it) {
322 handled = (*it)->HandleMessage(server, connection_id, data, data_size);
323 if (handled)
324 break;
325 }
326 EXPECT_TRUE(handled) << "missing WsRequestHandler for " << connection_id;
327
328 actual_ws_message_ct_++;
329 }
330
331 private:
RunningOnServerThread()332 bool RunningOnServerThread() {
333 return server_runner_ && server_runner_->BelongsToCurrentThread();
334 }
335
VerifyServer(CefRefPtr<CefServer> server)336 bool VerifyServer(CefRefPtr<CefServer> server) {
337 V_DECLARE();
338 V_EXPECT_TRUE(RunningOnServerThread());
339 V_EXPECT_TRUE(server);
340 V_EXPECT_TRUE(server_);
341 V_EXPECT_TRUE(server->GetAddress().ToString() ==
342 server_->GetAddress().ToString());
343 V_RETURN();
344 }
345
VerifyConnection(int connection_id)346 bool VerifyConnection(int connection_id) {
347 return connection_id_set_.find(connection_id) != connection_id_set_.end();
348 }
349
VerifyRequest(CefRefPtr<CefRequest> request,bool is_websocket)350 bool VerifyRequest(CefRefPtr<CefRequest> request, bool is_websocket) {
351 V_DECLARE();
352
353 V_EXPECT_FALSE(request->GetMethod().empty());
354
355 const std::string& url = request->GetURL();
356 V_EXPECT_FALSE(url.empty());
357 const std::string& address = server_->GetAddress();
358 V_EXPECT_TRUE(url.find((is_websocket ? "ws://" : "http://") + address) == 0)
359 << "url " << url << " address " << address;
360
361 CefRefPtr<CefPostData> post_data = request->GetPostData();
362 if (post_data) {
363 CefPostData::ElementVector elements;
364 post_data->GetElements(elements);
365 V_EXPECT_TRUE(elements.size() == 1);
366 V_EXPECT_TRUE(elements[0]->GetBytesCount() > 0U);
367 }
368
369 V_RETURN();
370 }
371
VerifyResults()372 void VerifyResults() {
373 EXPECT_TRUE(RunningOnServerThread());
374
375 EXPECT_TRUE(got_server_created_);
376 EXPECT_TRUE(got_server_destroyed_);
377 EXPECT_TRUE(connection_id_set_.empty());
378 EXPECT_EQ(expected_connection_ct_, actual_connection_ct_);
379
380 // HTTP
381
382 EXPECT_EQ(expected_http_request_ct_, actual_http_request_ct_);
383
384 if (!http_request_handler_list_.empty()) {
385 HttpRequestHandlerList::const_iterator it =
386 http_request_handler_list_.begin();
387 for (; it != http_request_handler_list_.end(); ++it) {
388 EXPECT_TRUE((*it)->VerifyResults())
389 << "HttpRequestHandler for " << (*it)->ToString();
390 }
391 }
392
393 // WebSocket
394
395 EXPECT_EQ(expected_ws_request_ct_, actual_ws_request_ct_);
396 EXPECT_EQ(expected_ws_connected_ct_, actual_ws_connected_ct_);
397 EXPECT_EQ(expected_ws_message_ct_, actual_ws_message_ct_);
398
399 if (!ws_request_handler_list_.empty()) {
400 WsRequestHandlerList::const_iterator it =
401 ws_request_handler_list_.begin();
402 for (; it != ws_request_handler_list_.end(); ++it) {
403 EXPECT_TRUE((*it)->VerifyResults())
404 << "WsRequestHandler for " << (*it)->ToString();
405 }
406 }
407 }
408
409 private:
RunStartCallback()410 void RunStartCallback() {
411 if (!CefCurrentlyOn(TID_UI)) {
412 CefPostTask(TID_UI,
413 base::Bind(&TestServerHandler::RunStartCallback, this));
414 return;
415 }
416
417 EXPECT_FALSE(start_callback_.is_null());
418 start_callback_.Run();
419 start_callback_.Reset();
420 }
421
422 CefRefPtr<CefServer> server_;
423 CefRefPtr<CefTaskRunner> server_runner_;
424 bool initialized_;
425
426 // After initialization only accessed on the UI thread.
427 base::Closure start_callback_;
428 base::Closure destroy_callback_;
429
430 // After initialization the below members are only accessed on the server
431 // thread.
432
433 TrackCallback got_server_created_;
434 TrackCallback got_server_destroyed_;
435
436 typedef std::set<int> ConnectionIdSet;
437 ConnectionIdSet connection_id_set_;
438
439 int expected_connection_ct_;
440 int actual_connection_ct_;
441
442 // HTTP
443
444 typedef std::list<HttpRequestHandler*> HttpRequestHandlerList;
445 HttpRequestHandlerList http_request_handler_list_;
446
447 int expected_http_request_ct_;
448 int actual_http_request_ct_;
449
450 // WebSocket
451
452 typedef std::list<WsRequestHandler*> WsRequestHandlerList;
453 WsRequestHandlerList ws_request_handler_list_;
454
455 ConnectionIdSet ws_connection_id_set_;
456
457 int expected_ws_request_ct_;
458 int actual_ws_request_ct_;
459
460 int expected_ws_connected_ct_;
461 int actual_ws_connected_ct_;
462
463 int expected_ws_message_ct_;
464 int actual_ws_message_ct_;
465
466 IMPLEMENT_REFCOUNTING(TestServerHandler);
467 DISALLOW_COPY_AND_ASSIGN(TestServerHandler);
468 };
469
470 // HTTP TESTS
471
472 // Test runner for 1 or more HTTP requests/responses.
473 // Works similarly to TestHandler but without the CefClient dependencies.
474 class HttpTestRunner : public base::RefCountedThreadSafe<HttpTestRunner> {
475 public:
476 // The methods of this class are always executed on the UI thread.
477 class RequestRunner {
478 public:
~RequestRunner()479 virtual ~RequestRunner() {}
480
481 // Create the server-side handler for the request.
482 virtual scoped_ptr<TestServerHandler::HttpRequestHandler>
483 CreateHttpRequestHandler() = 0;
484
485 // Run the request and execute |complete_callback| on completion.
486 virtual void RunRequest(const base::Closure& complete_callback) = 0;
487
488 virtual bool VerifyResults() = 0;
489 virtual std::string ToString() = 0;
490 };
491
492 // If |parallel_requests| is true all requests will be run at the same time,
493 // otherwise one request will be run at a time.
HttpTestRunner(bool parallel_requests)494 HttpTestRunner(bool parallel_requests)
495 : parallel_requests_(parallel_requests),
496 initialized_(false),
497 next_request_id_(0) {
498 handler_ = new TestServerHandler(
499 base::Bind(&HttpTestRunner::OnServerStarted, this),
500 base::Bind(&HttpTestRunner::OnServerDestroyed, this));
501 }
502
~HttpTestRunner()503 virtual ~HttpTestRunner() {
504 if (destroy_event_)
505 destroy_event_->Signal();
506 }
507
AddRequestRunner(scoped_ptr<RequestRunner> request_runner)508 void AddRequestRunner(scoped_ptr<RequestRunner> request_runner) {
509 EXPECT_FALSE(initialized_);
510 request_runner_map_.insert(
511 std::make_pair(++next_request_id_, request_runner.release()));
512 }
513
514 // Blocks until the test has completed or timed out.
ExecuteTest()515 void ExecuteTest() {
516 EXPECT_FALSE(CefCurrentlyOn(TID_UI));
517
518 run_event_ = CefWaitableEvent::CreateWaitableEvent(false, false);
519
520 CefPostTask(TID_UI, base::Bind(&HttpTestRunner::RunTest, this));
521
522 // Block until test completion.
523 run_event_->Wait();
524 }
525
526 // Event that will be signaled from the HttpTestRunner destructor.
527 // Used by ReleaseAndWaitForDestructor.
SetDestroyEvent(CefRefPtr<CefWaitableEvent> event)528 void SetDestroyEvent(CefRefPtr<CefWaitableEvent> event) {
529 destroy_event_ = event;
530 }
531
532 private:
RunTest()533 void RunTest() {
534 EXPECT_UI_THREAD();
535 EXPECT_FALSE(initialized_);
536 initialized_ = true;
537
538 EXPECT_FALSE(request_runner_map_.empty());
539 RequestRunnerMap::const_iterator it = request_runner_map_.begin();
540 for (; it != request_runner_map_.end(); ++it) {
541 handler_->AddHttpRequestHandler(it->second->CreateHttpRequestHandler());
542 }
543
544 handler_->SetExpectedConnectionCount(
545 static_cast<int>(request_runner_map_.size()));
546 handler_->SetExpectedHttpRequestCount(
547 static_cast<int>(request_runner_map_.size()));
548
549 handler_->CreateServer();
550
551 SetTestTimeout(kTestTimeout);
552 }
553
OnServerStarted()554 void OnServerStarted() {
555 EXPECT_UI_THREAD();
556 if (parallel_requests_) {
557 RunAllRequests();
558 } else {
559 RunNextRequest();
560 }
561 }
562
OnServerDestroyed()563 void OnServerDestroyed() {
564 EXPECT_UI_THREAD();
565 EXPECT_FALSE(got_server_destroyed_);
566 got_server_destroyed_.yes();
567
568 // Allow the call stack to unwind.
569 CefPostTask(TID_UI, base::Bind(&HttpTestRunner::DestroyTest, this));
570 }
571
572 // Run all requests in parallel.
RunAllRequests()573 void RunAllRequests() {
574 RequestRunnerMap::const_iterator it = request_runner_map_.begin();
575 for (; it != request_runner_map_.end(); ++it) {
576 it->second->RunRequest(
577 base::Bind(&HttpTestRunner::OnRequestComplete, this, it->first));
578 }
579 }
580
581 // Run one request at a time.
RunNextRequest()582 void RunNextRequest() {
583 RequestRunnerMap::const_iterator it = request_runner_map_.begin();
584 it->second->RunRequest(
585 base::Bind(&HttpTestRunner::OnRequestComplete, this, it->first));
586 }
587
OnRequestComplete(int request_id)588 void OnRequestComplete(int request_id) {
589 EXPECT_UI_THREAD()
590 // Allow the call stack to unwind.
591 CefPostTask(TID_UI, base::Bind(&HttpTestRunner::OnRequestCompleteContinue,
592 this, request_id));
593 }
594
OnRequestCompleteContinue(int request_id)595 void OnRequestCompleteContinue(int request_id) {
596 RequestRunnerMap::iterator it = request_runner_map_.find(request_id);
597 EXPECT_TRUE(it != request_runner_map_.end());
598
599 // Verify the request results.
600 EXPECT_TRUE(it->second->VerifyResults())
601 << "request_id " << request_id << " RequestRunner for "
602 << it->second->ToString();
603 delete it->second;
604 request_runner_map_.erase(it);
605
606 if (request_runner_map_.empty()) {
607 got_all_requests_.yes();
608
609 // Will trigger TestServerHandler::HttpRequestHandler verification and a
610 // call to OnServerDestroyed().
611 handler_->ShutdownServer();
612 handler_ = nullptr;
613 } else if (!parallel_requests_) {
614 RunNextRequest();
615 }
616 }
617
DestroyTest()618 void DestroyTest() {
619 EXPECT_UI_THREAD();
620
621 EXPECT_TRUE(got_all_requests_);
622 EXPECT_TRUE(got_server_destroyed_);
623 EXPECT_TRUE(request_runner_map_.empty());
624
625 // Cancel the timeout, if any.
626 if (ui_thread_helper_)
627 ui_thread_helper_.reset();
628
629 // Signal test completion.
630 run_event_->Signal();
631 }
632
GetUIThreadHelper()633 TestHandler::UIThreadHelper* GetUIThreadHelper() {
634 EXPECT_UI_THREAD();
635 if (!ui_thread_helper_)
636 ui_thread_helper_.reset(new TestHandler::UIThreadHelper());
637 return ui_thread_helper_.get();
638 }
639
SetTestTimeout(int timeout_ms)640 void SetTestTimeout(int timeout_ms) {
641 EXPECT_UI_THREAD();
642 if (CefCommandLine::GetGlobalCommandLine()->HasSwitch(
643 "disable-test-timeout")) {
644 return;
645 }
646
647 // Use a weak reference to |this| via UIThreadHelper so that the
648 // test runner can be destroyed before the timeout expires.
649 GetUIThreadHelper()->PostDelayedTask(
650 base::Bind(&HttpTestRunner::OnTestTimeout, base::Unretained(this),
651 timeout_ms),
652 timeout_ms);
653 }
654
OnTestTimeout(int timeout_ms)655 void OnTestTimeout(int timeout_ms) {
656 EXPECT_UI_THREAD();
657 EXPECT_TRUE(false) << "Test timed out after " << timeout_ms << "ms";
658 DestroyTest();
659 }
660
661 bool parallel_requests_;
662 CefRefPtr<CefWaitableEvent> run_event_;
663 CefRefPtr<CefWaitableEvent> destroy_event_;
664 CefRefPtr<TestServerHandler> handler_;
665 bool initialized_;
666
667 // After initialization the below members are only accessed on the UI thread.
668
669 int next_request_id_;
670
671 // Map of request ID to RequestRunner.
672 typedef std::map<int, RequestRunner*> RequestRunnerMap;
673 RequestRunnerMap request_runner_map_;
674
675 TrackCallback got_all_requests_;
676 TrackCallback got_server_destroyed_;
677
678 scoped_ptr<TestHandler::UIThreadHelper> ui_thread_helper_;
679
680 DISALLOW_COPY_AND_ASSIGN(HttpTestRunner);
681 };
682
683 // Structure representing the data that can be sent via
684 // CefServer::SendHttp*Response().
685 struct HttpServerResponse {
686 enum Type { TYPE_200, TYPE_404, TYPE_500, TYPE_CUSTOM };
687
HttpServerResponse__anon0a9898000111::HttpServerResponse688 explicit HttpServerResponse(Type response_type)
689 : type(response_type), no_content_length(false) {}
690
691 Type type;
692
693 // Used with 200 and CUSTOM response type.
694 std::string content;
695 std::string content_type;
696
697 // Used with 500 response type.
698 std::string error_message;
699
700 // Used with CUSTOM response type.
701 int response_code;
702 CefServer::HeaderMap extra_headers;
703 bool no_content_length;
704 };
705
SendHttpServerResponse(CefRefPtr<CefServer> server,int connection_id,const HttpServerResponse & response)706 void SendHttpServerResponse(CefRefPtr<CefServer> server,
707 int connection_id,
708 const HttpServerResponse& response) {
709 EXPECT_TRUE(server->GetTaskRunner()->BelongsToCurrentThread());
710 EXPECT_TRUE(server->IsValidConnection(connection_id));
711
712 switch (response.type) {
713 case HttpServerResponse::TYPE_200:
714 EXPECT_TRUE(!response.content_type.empty());
715 server->SendHttp200Response(connection_id, response.content_type,
716 response.content.data(),
717 response.content.size());
718 break;
719 case HttpServerResponse::TYPE_404:
720 server->SendHttp404Response(connection_id);
721 break;
722 case HttpServerResponse::TYPE_500:
723 server->SendHttp500Response(connection_id, response.error_message);
724 break;
725 case HttpServerResponse::TYPE_CUSTOM:
726 EXPECT_TRUE(!response.content_type.empty());
727 server->SendHttpResponse(
728 connection_id, response.response_code, response.content_type,
729 response.no_content_length
730 ? -1
731 : static_cast<int64>(response.content.size()),
732 response.extra_headers);
733 if (!response.content.empty()) {
734 server->SendRawData(connection_id, response.content.data(),
735 response.content.size());
736 }
737 if (!response.content.empty() ||
738 (response.content.empty() && response.no_content_length)) {
739 server->CloseConnection(connection_id);
740 }
741 break;
742 }
743
744 // All of the above responses should close the connection.
745 EXPECT_FALSE(server->IsValidConnection(connection_id));
746 }
747
GetHeaderValue(const CefServer::HeaderMap & header_map,const std::string & header_name)748 std::string GetHeaderValue(const CefServer::HeaderMap& header_map,
749 const std::string& header_name) {
750 CefServer::HeaderMap::const_iterator it = header_map.find(header_name);
751 if (it != header_map.end())
752 return it->second;
753 return std::string();
754 }
755
VerifyHttpServerResponse(const HttpServerResponse & expected_response,CefRefPtr<CefResponse> response,const std::string & data)756 void VerifyHttpServerResponse(const HttpServerResponse& expected_response,
757 CefRefPtr<CefResponse> response,
758 const std::string& data) {
759 CefServer::HeaderMap header_map;
760 response->GetHeaderMap(header_map);
761
762 switch (expected_response.type) {
763 case HttpServerResponse::TYPE_200:
764 EXPECT_EQ(200, response->GetStatus());
765 EXPECT_STREQ(expected_response.content_type.c_str(),
766 GetHeaderValue(header_map, "Content-Type").c_str());
767 EXPECT_STREQ(expected_response.content.c_str(), data.c_str());
768 break;
769 case HttpServerResponse::TYPE_404:
770 EXPECT_EQ(404, response->GetStatus());
771 break;
772 case HttpServerResponse::TYPE_500:
773 EXPECT_EQ(500, response->GetStatus());
774 break;
775 case HttpServerResponse::TYPE_CUSTOM:
776 EXPECT_EQ(expected_response.response_code, response->GetStatus());
777 EXPECT_STREQ(expected_response.content_type.c_str(),
778 GetHeaderValue(header_map, "Content-Type").c_str());
779 if (expected_response.no_content_length) {
780 EXPECT_TRUE(GetHeaderValue(header_map, "Content-Length").empty());
781 } else {
782 EXPECT_FALSE(GetHeaderValue(header_map, "Content-Length").empty());
783 }
784 EXPECT_STREQ(expected_response.content.c_str(), data.c_str());
785 TestMapEqual(expected_response.extra_headers, header_map, true);
786 break;
787 }
788 }
789
CreateTestServerRequest(const std::string & path,const std::string & method,const std::string & data=std::string (),const std::string & content_type=std::string (),const CefRequest::HeaderMap & extra_headers=CefRequest::HeaderMap ())790 CefRefPtr<CefRequest> CreateTestServerRequest(
791 const std::string& path,
792 const std::string& method,
793 const std::string& data = std::string(),
794 const std::string& content_type = std::string(),
795 const CefRequest::HeaderMap& extra_headers = CefRequest::HeaderMap()) {
796 CefRefPtr<CefRequest> request = CefRequest::Create();
797 request->SetURL(GetTestServerOrigin(false) + "/" + path);
798 request->SetMethod(method);
799
800 CefRequest::HeaderMap header_map;
801
802 if (!data.empty()) {
803 CefRefPtr<CefPostData> post_data = CefPostData::Create();
804 CefRefPtr<CefPostDataElement> post_element = CefPostDataElement::Create();
805 post_element->SetToBytes(data.size(), data.data());
806 post_data->AddElement(post_element);
807 request->SetPostData(post_data);
808
809 EXPECT_FALSE(content_type.empty());
810 header_map.insert(std::make_pair("content-type", content_type));
811 }
812
813 if (!extra_headers.empty())
814 header_map.insert(extra_headers.begin(), extra_headers.end());
815 request->SetHeaderMap(header_map);
816
817 return request;
818 }
819
820 // RequestHandler that returns a static response for 1 or more requests.
821 class StaticHttpServerRequestHandler
822 : public TestServerHandler::HttpRequestHandler {
823 public:
StaticHttpServerRequestHandler(CefRefPtr<CefRequest> expected_request,int expected_request_ct,const HttpServerResponse & response)824 StaticHttpServerRequestHandler(CefRefPtr<CefRequest> expected_request,
825 int expected_request_ct,
826 const HttpServerResponse& response)
827 : expected_request_(expected_request),
828 expected_request_ct_(expected_request_ct),
829 actual_request_ct_(0),
830 response_(response) {}
831
HandleRequest(CefRefPtr<CefServer> server,int connection_id,const CefString & client_address,CefRefPtr<CefRequest> request)832 bool HandleRequest(CefRefPtr<CefServer> server,
833 int connection_id,
834 const CefString& client_address,
835 CefRefPtr<CefRequest> request) override {
836 if (request->GetURL() == expected_request_->GetURL() &&
837 request->GetMethod() == expected_request_->GetMethod()) {
838 TestRequestEqual(expected_request_, request, true);
839 actual_request_ct_++;
840
841 SendHttpServerResponse(server, connection_id, response_);
842 return true;
843 }
844
845 return false;
846 }
847
VerifyResults()848 bool VerifyResults() override {
849 EXPECT_EQ(expected_request_ct_, actual_request_ct_);
850 return expected_request_ct_ == actual_request_ct_;
851 }
852
ToString()853 std::string ToString() override { return expected_request_->GetURL(); }
854
855 private:
856 CefRefPtr<CefRequest> expected_request_;
857 int expected_request_ct_;
858 int actual_request_ct_;
859 HttpServerResponse response_;
860
861 DISALLOW_COPY_AND_ASSIGN(StaticHttpServerRequestHandler);
862 };
863
864 // URLRequestClient that runs a single request and executes a callback with the
865 // response.
866 class StaticHttpURLRequestClient : public CefURLRequestClient {
867 public:
868 typedef base::Callback<void(cef_errorcode_t /* error */,
869 CefRefPtr<CefResponse> /* response */,
870 const std::string& /* data */)>
871 ResponseCallback;
872
873 // |response_callback| will be executed on the UI thread when the response
874 // is complete.
StaticHttpURLRequestClient(CefRefPtr<CefRequest> request,const ResponseCallback & response_callback)875 StaticHttpURLRequestClient(CefRefPtr<CefRequest> request,
876 const ResponseCallback& response_callback)
877 : request_(request), response_callback_(response_callback) {
878 EXPECT_TRUE(request_);
879 EXPECT_FALSE(response_callback_.is_null());
880 }
881
RunRequest()882 void RunRequest() {
883 EXPECT_UI_THREAD();
884 CefURLRequest::Create(request_, this, nullptr);
885 }
886
OnRequestComplete(CefRefPtr<CefURLRequest> request)887 void OnRequestComplete(CefRefPtr<CefURLRequest> request) override {
888 EXPECT_FALSE(response_callback_.is_null());
889 response_callback_.Run(request->GetRequestError(), request->GetResponse(),
890 data_);
891 response_callback_.Reset();
892 }
893
OnUploadProgress(CefRefPtr<CefURLRequest> request,int64 current,int64 total)894 void OnUploadProgress(CefRefPtr<CefURLRequest> request,
895 int64 current,
896 int64 total) override {}
897
OnDownloadProgress(CefRefPtr<CefURLRequest> request,int64 current,int64 total)898 void OnDownloadProgress(CefRefPtr<CefURLRequest> request,
899 int64 current,
900 int64 total) override {}
901
OnDownloadData(CefRefPtr<CefURLRequest> request,const void * data,size_t data_length)902 void OnDownloadData(CefRefPtr<CefURLRequest> request,
903 const void* data,
904 size_t data_length) override {
905 data_.append(static_cast<const char*>(data), data_length);
906 }
907
GetAuthCredentials(bool isProxy,const CefString & host,int port,const CefString & realm,const CefString & scheme,CefRefPtr<CefAuthCallback> callback)908 bool GetAuthCredentials(bool isProxy,
909 const CefString& host,
910 int port,
911 const CefString& realm,
912 const CefString& scheme,
913 CefRefPtr<CefAuthCallback> callback) override {
914 return false;
915 }
916
917 private:
918 CefRefPtr<CefRequest> request_;
919 ResponseCallback response_callback_;
920 std::string data_;
921
922 IMPLEMENT_REFCOUNTING(StaticHttpURLRequestClient);
923 DISALLOW_COPY_AND_ASSIGN(StaticHttpURLRequestClient);
924 };
925
926 // RequestRunner that will manage a single static HTTP request/response.
927 class StaticHttpRequestRunner : public HttpTestRunner::RequestRunner {
928 public:
StaticHttpRequestRunner(CefRefPtr<CefRequest> request,const HttpServerResponse & response)929 StaticHttpRequestRunner(CefRefPtr<CefRequest> request,
930 const HttpServerResponse& response)
931 : request_(request), response_(response) {}
932
Create200(const std::string & path,bool with_content=true)933 static scoped_ptr<HttpTestRunner::RequestRunner> Create200(
934 const std::string& path,
935 bool with_content = true) {
936 CefRefPtr<CefRequest> request = CreateTestServerRequest(path, "GET");
937 HttpServerResponse response(HttpServerResponse::TYPE_200);
938 response.content_type = "text/html";
939 if (with_content)
940 response.content = "<html>200 response content</html>";
941 return make_scoped_ptr<HttpTestRunner::RequestRunner>(
942 new StaticHttpRequestRunner(request, response));
943 }
944
Create404(const std::string & path)945 static scoped_ptr<HttpTestRunner::RequestRunner> Create404(
946 const std::string& path) {
947 CefRefPtr<CefRequest> request = CreateTestServerRequest(path, "GET");
948 HttpServerResponse response(HttpServerResponse::TYPE_404);
949 return make_scoped_ptr<HttpTestRunner::RequestRunner>(
950 new StaticHttpRequestRunner(request, response));
951 }
952
Create500(const std::string & path)953 static scoped_ptr<HttpTestRunner::RequestRunner> Create500(
954 const std::string& path) {
955 CefRefPtr<CefRequest> request = CreateTestServerRequest(path, "GET");
956 // Don't retry the request.
957 request->SetFlags(UR_FLAG_NO_RETRY_ON_5XX);
958 HttpServerResponse response(HttpServerResponse::TYPE_500);
959 response.error_message = "Something went wrong!";
960 return make_scoped_ptr<HttpTestRunner::RequestRunner>(
961 new StaticHttpRequestRunner(request, response));
962 }
963
CreateCustom(const std::string & path,bool with_content=true,bool with_content_length=true)964 static scoped_ptr<HttpTestRunner::RequestRunner> CreateCustom(
965 const std::string& path,
966 bool with_content = true,
967 bool with_content_length = true) {
968 CefRequest::HeaderMap request_headers;
969 request_headers.insert(std::make_pair("x-request-custom1", "My Value A"));
970 request_headers.insert(std::make_pair("x-request-custom2", "My Value B"));
971 CefRefPtr<CefRequest> request = CreateTestServerRequest(
972 path, "POST", "foo=bar&choo=too", "application/x-www-form-urlencoded",
973 request_headers);
974 request->SetReferrer("http://tests/referer.html", REFERRER_POLICY_DEFAULT);
975
976 HttpServerResponse response(HttpServerResponse::TYPE_CUSTOM);
977 response.response_code = 202;
978 if (with_content)
979 response.content = "BlahBlahBlah";
980 if (!with_content_length)
981 response.no_content_length = true;
982 response.content_type = "application/x-blah-blah";
983 response.extra_headers.insert(
984 std::make_pair("x-response-custom1", "My Value 1"));
985 response.extra_headers.insert(
986 std::make_pair("x-response-custom2", "My Value 2"));
987
988 return make_scoped_ptr<HttpTestRunner::RequestRunner>(
989 new StaticHttpRequestRunner(request, response));
990 }
991
CreateHttpRequestHandler()992 scoped_ptr<TestServerHandler::HttpRequestHandler> CreateHttpRequestHandler()
993 override {
994 EXPECT_FALSE(got_create_handler_);
995 got_create_handler_.yes();
996 return make_scoped_ptr<TestServerHandler::HttpRequestHandler>(
997 new StaticHttpServerRequestHandler(request_, 1, response_));
998 }
999
RunRequest(const base::Closure & complete_callback)1000 void RunRequest(const base::Closure& complete_callback) override {
1001 EXPECT_UI_THREAD();
1002
1003 EXPECT_FALSE(got_run_request_);
1004 got_run_request_.yes();
1005
1006 complete_callback_ = complete_callback;
1007
1008 request_client_ = new StaticHttpURLRequestClient(
1009 request_, base::Bind(&StaticHttpRequestRunner::OnResponseComplete,
1010 base::Unretained(this)));
1011 request_client_->RunRequest();
1012 }
1013
VerifyResults()1014 bool VerifyResults() override {
1015 V_DECLARE();
1016 V_EXPECT_TRUE(got_create_handler_);
1017 V_EXPECT_TRUE(got_run_request_);
1018 V_EXPECT_TRUE(got_response_complete_);
1019 V_RETURN();
1020 }
1021
ToString()1022 std::string ToString() override { return request_->GetURL(); }
1023
1024 private:
OnResponseComplete(cef_errorcode_t error,CefRefPtr<CefResponse> response,const std::string & data)1025 void OnResponseComplete(cef_errorcode_t error,
1026 CefRefPtr<CefResponse> response,
1027 const std::string& data) {
1028 EXPECT_UI_THREAD();
1029
1030 EXPECT_FALSE(got_response_complete_);
1031 got_response_complete_.yes();
1032
1033 EXPECT_EQ(error, ERR_NONE)
1034 << "OnResponseComplete for " << request_->GetURL().ToString();
1035 if (error == ERR_NONE)
1036 VerifyHttpServerResponse(response_, response, data);
1037
1038 complete_callback_.Run();
1039 complete_callback_.Reset();
1040 }
1041
1042 CefRefPtr<CefRequest> request_;
1043 HttpServerResponse response_;
1044
1045 CefRefPtr<StaticHttpURLRequestClient> request_client_;
1046 base::Closure complete_callback_;
1047
1048 TrackCallback got_run_request_;
1049 TrackCallback got_create_handler_;
1050 TrackCallback got_response_complete_;
1051
1052 DISALLOW_COPY_AND_ASSIGN(StaticHttpRequestRunner);
1053 };
1054
1055 } // namespace
1056
1057 // Verify handling of a single HTTP 200 request.
TEST(ServerTest,HttpSingle200)1058 TEST(ServerTest, HttpSingle200) {
1059 CefRefPtr<HttpTestRunner> runner = new HttpTestRunner(false);
1060 runner->AddRequestRunner(StaticHttpRequestRunner::Create200("200.html"));
1061 runner->ExecuteTest();
1062 ReleaseAndWaitForDestructor(runner);
1063 }
1064
1065 // Verify handling of a single HTTP 200 request with no content.
TEST(ServerTest,HttpSingle200NoContent)1066 TEST(ServerTest, HttpSingle200NoContent) {
1067 CefRefPtr<HttpTestRunner> runner = new HttpTestRunner(false);
1068 runner->AddRequestRunner(
1069 StaticHttpRequestRunner::Create200("200.html", false));
1070 runner->ExecuteTest();
1071 ReleaseAndWaitForDestructor(runner);
1072 }
1073
1074 // Verify handling of a single HTTP 404 request.
TEST(ServerTest,HttpSingle404)1075 TEST(ServerTest, HttpSingle404) {
1076 CefRefPtr<HttpTestRunner> runner = new HttpTestRunner(false);
1077 runner->AddRequestRunner(StaticHttpRequestRunner::Create404("404.html"));
1078 runner->ExecuteTest();
1079 ReleaseAndWaitForDestructor(runner);
1080 }
1081
1082 // Verify handling of a single HTTP 500 request.
TEST(ServerTest,HttpSingle500)1083 TEST(ServerTest, HttpSingle500) {
1084 CefRefPtr<HttpTestRunner> runner = new HttpTestRunner(false);
1085 runner->AddRequestRunner(StaticHttpRequestRunner::Create500("500.html"));
1086 runner->ExecuteTest();
1087 ReleaseAndWaitForDestructor(runner);
1088 }
1089
1090 // Verify handling of a single HTTP custom request.
TEST(ServerTest,HttpSingleCustom)1091 TEST(ServerTest, HttpSingleCustom) {
1092 CefRefPtr<HttpTestRunner> runner = new HttpTestRunner(false);
1093 runner->AddRequestRunner(StaticHttpRequestRunner::CreateCustom("202.html"));
1094 runner->ExecuteTest();
1095 ReleaseAndWaitForDestructor(runner);
1096 }
1097
1098 // Verify handling of a single HTTP custom request with no content.
TEST(ServerTest,HttpSingleCustomNoContent)1099 TEST(ServerTest, HttpSingleCustomNoContent) {
1100 CefRefPtr<HttpTestRunner> runner = new HttpTestRunner(false);
1101 runner->AddRequestRunner(
1102 StaticHttpRequestRunner::CreateCustom("202.html", false));
1103 runner->ExecuteTest();
1104 ReleaseAndWaitForDestructor(runner);
1105 }
1106
1107 // Verify handling of a single HTTP custom request with no Content-Length
1108 // header.
TEST(ServerTest,HttpSingleCustomNoContentLength)1109 TEST(ServerTest, HttpSingleCustomNoContentLength) {
1110 CefRefPtr<HttpTestRunner> runner = new HttpTestRunner(false);
1111 runner->AddRequestRunner(
1112 StaticHttpRequestRunner::CreateCustom("202.html", true, false));
1113 runner->ExecuteTest();
1114 ReleaseAndWaitForDestructor(runner);
1115 }
1116
1117 // Verify handling of a single HTTP custom request with no content and no
1118 // Content-Length header.
TEST(ServerTest,HttpSingleCustomNoContentAndNoLength)1119 TEST(ServerTest, HttpSingleCustomNoContentAndNoLength) {
1120 CefRefPtr<HttpTestRunner> runner = new HttpTestRunner(false);
1121 runner->AddRequestRunner(
1122 StaticHttpRequestRunner::CreateCustom("202.html", false, false));
1123 runner->ExecuteTest();
1124 ReleaseAndWaitForDestructor(runner);
1125 }
1126
1127 // Verify handling of multiple HTTP requests in parallel.
TEST(ServerTest,HttpMultipleParallel200)1128 TEST(ServerTest, HttpMultipleParallel200) {
1129 CefRefPtr<HttpTestRunner> runner = new HttpTestRunner(true);
1130 runner->AddRequestRunner(StaticHttpRequestRunner::Create200("200a.html"));
1131 runner->AddRequestRunner(StaticHttpRequestRunner::Create200("200b.html"));
1132 runner->AddRequestRunner(StaticHttpRequestRunner::Create200("200c.html"));
1133 runner->ExecuteTest();
1134 ReleaseAndWaitForDestructor(runner);
1135 }
1136
1137 // Verify handling of multiple HTTP requests in serial.
TEST(ServerTest,HttpMultipleSerial200)1138 TEST(ServerTest, HttpMultipleSerial200) {
1139 CefRefPtr<HttpTestRunner> runner = new HttpTestRunner(false);
1140 runner->AddRequestRunner(StaticHttpRequestRunner::Create200("200a.html"));
1141 runner->AddRequestRunner(StaticHttpRequestRunner::Create200("200b.html"));
1142 runner->AddRequestRunner(StaticHttpRequestRunner::Create200("200c.html"));
1143 runner->ExecuteTest();
1144 ReleaseAndWaitForDestructor(runner);
1145 }
1146
1147 // Verify handling of multiple HTTP requests in parallel.
TEST(ServerTest,HttpMultipleParallelMixed)1148 TEST(ServerTest, HttpMultipleParallelMixed) {
1149 CefRefPtr<HttpTestRunner> runner = new HttpTestRunner(true);
1150 runner->AddRequestRunner(StaticHttpRequestRunner::Create200("200.html"));
1151 runner->AddRequestRunner(StaticHttpRequestRunner::Create404("404.html"));
1152 runner->AddRequestRunner(StaticHttpRequestRunner::Create500("500.html"));
1153 runner->AddRequestRunner(StaticHttpRequestRunner::CreateCustom("202.html"));
1154 runner->ExecuteTest();
1155 ReleaseAndWaitForDestructor(runner);
1156 }
1157
1158 // Verify handling of multiple HTTP requests in serial.
TEST(ServerTest,HttpMultipleSerialMixed)1159 TEST(ServerTest, HttpMultipleSerialMixed) {
1160 CefRefPtr<HttpTestRunner> runner = new HttpTestRunner(false);
1161 runner->AddRequestRunner(StaticHttpRequestRunner::Create200("200.html"));
1162 runner->AddRequestRunner(StaticHttpRequestRunner::Create404("404.html"));
1163 runner->AddRequestRunner(StaticHttpRequestRunner::Create500("500.html"));
1164 runner->AddRequestRunner(StaticHttpRequestRunner::CreateCustom("202.html"));
1165 runner->ExecuteTest();
1166 ReleaseAndWaitForDestructor(runner);
1167 }
1168
1169 namespace {
1170
1171 // WEBSOCKET TESTS
1172
1173 const char kWebSocketUrl[] = "http://tests-display/websocket.html";
1174 const char kDoneMsgPrefix[] = "done:";
1175
1176 class WebSocketTestHandler : public RoutingTestHandler {
1177 public:
WebSocketTestHandler()1178 WebSocketTestHandler() {}
1179
RunTest()1180 void RunTest() override {
1181 handler_ = new TestServerHandler(
1182 base::Bind(&WebSocketTestHandler::OnServerStarted, this),
1183 base::Bind(&WebSocketTestHandler::OnServerDestroyed, this));
1184 OnHandlerCreated(handler_);
1185
1186 handler_->CreateServer();
1187
1188 // Time out the test after a reasonable period of time.
1189 SetTestTimeout();
1190 }
1191
OnQuery(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,int64 query_id,const CefString & request,bool persistent,CefRefPtr<Callback> callback)1192 bool OnQuery(CefRefPtr<CefBrowser> browser,
1193 CefRefPtr<CefFrame> frame,
1194 int64 query_id,
1195 const CefString& request,
1196 bool persistent,
1197 CefRefPtr<Callback> callback) override {
1198 const std::string& request_str = request.ToString();
1199 if (request_str.find(kDoneMsgPrefix) == 0) {
1200 EXPECT_FALSE(got_done_message_);
1201 got_done_message_.yes();
1202 OnDoneMessage(request_str.substr(strlen(kDoneMsgPrefix)));
1203 DestroyTestIfDone();
1204 return true;
1205 }
1206 return false;
1207 }
1208
DestroyTest()1209 void DestroyTest() override {
1210 EXPECT_TRUE(got_server_started_);
1211 EXPECT_TRUE(got_done_message_);
1212 EXPECT_TRUE(got_server_destroyed_);
1213
1214 TestHandler::DestroyTest();
1215 }
1216
1217 protected:
1218 // Returns the HTML/JS for the client.
1219 virtual std::string GetClientHtml() = 0;
1220
1221 // Called after the server handler is created to set test expectations.
1222 virtual void OnHandlerCreated(CefRefPtr<TestServerHandler> handler) = 0;
1223
1224 // Returns the JS to execute when the test is done.
GetDoneJS(const std::string & result)1225 std::string GetDoneJS(const std::string& result) {
1226 return "window.testQuery({request:'" + std::string(kDoneMsgPrefix) +
1227 "' + " + result + "});";
1228 }
1229
1230 // Called with the result from the done message.
1231 virtual void OnDoneMessage(const std::string& result) = 0;
1232
ShutdownServer()1233 void ShutdownServer() {
1234 EXPECT_TRUE(handler_);
1235 handler_->ShutdownServer();
1236 handler_ = nullptr;
1237 }
1238
1239 private:
OnServerStarted()1240 void OnServerStarted() {
1241 EXPECT_UI_THREAD();
1242 EXPECT_FALSE(got_server_started_);
1243 got_server_started_.yes();
1244
1245 // Add the WebSocket client code.
1246 AddResource(kWebSocketUrl, GetClientHtml(), "text/html");
1247
1248 // Create the browser.
1249 CreateBrowser(kWebSocketUrl);
1250 }
1251
OnServerDestroyed()1252 void OnServerDestroyed() {
1253 EXPECT_UI_THREAD();
1254 EXPECT_FALSE(got_server_destroyed_);
1255 got_server_destroyed_.yes();
1256 DestroyTestIfDone();
1257 }
1258
DestroyTestIfDone()1259 void DestroyTestIfDone() {
1260 if (got_server_destroyed_ && got_done_message_) {
1261 // Allow the call stack to unwind.
1262 CefPostTask(TID_UI, base::Bind(&WebSocketTestHandler::DestroyTest, this));
1263 }
1264 }
1265
1266 CefRefPtr<TestServerHandler> handler_;
1267
1268 TrackCallback got_server_started_;
1269 TrackCallback got_done_message_;
1270 TrackCallback got_server_destroyed_;
1271
1272 DISALLOW_COPY_AND_ASSIGN(WebSocketTestHandler);
1273 };
1274
1275 // WebSocket request handler that echoes each message sent.
1276 class EchoWebSocketRequestHandler : public TestServerHandler::WsRequestHandler {
1277 public:
EchoWebSocketRequestHandler(int expected_message_ct)1278 explicit EchoWebSocketRequestHandler(int expected_message_ct)
1279 : expected_message_ct_(expected_message_ct), actual_message_ct_(0) {}
1280
GetWebSocketUrl()1281 std::string GetWebSocketUrl() { return GetTestServerOrigin(true) + "/echo"; }
1282
HandleRequest(CefRefPtr<CefServer> server,int connection_id,const CefString & client_address,CefRefPtr<CefRequest> request,CefRefPtr<CefCallback> callback)1283 bool HandleRequest(CefRefPtr<CefServer> server,
1284 int connection_id,
1285 const CefString& client_address,
1286 CefRefPtr<CefRequest> request,
1287 CefRefPtr<CefCallback> callback) override {
1288 EXPECT_STREQ(GetWebSocketUrl().c_str(),
1289 request->GetURL().ToString().c_str());
1290
1291 callback->Continue();
1292 return true;
1293 }
1294
HandleConnected(CefRefPtr<CefServer> server,int connection_id)1295 bool HandleConnected(CefRefPtr<CefServer> server,
1296 int connection_id) override {
1297 return true;
1298 }
1299
HandleMessage(CefRefPtr<CefServer> server,int connection_id,const void * data,size_t data_size)1300 bool HandleMessage(CefRefPtr<CefServer> server,
1301 int connection_id,
1302 const void* data,
1303 size_t data_size) override {
1304 actual_message_ct_++;
1305
1306 // Echo the message back to the sender.
1307 server->SendWebSocketMessage(connection_id, data, data_size);
1308
1309 return true;
1310 }
1311
VerifyResults()1312 bool VerifyResults() override {
1313 EXPECT_EQ(expected_message_ct_, actual_message_ct_);
1314 return expected_message_ct_ == actual_message_ct_;
1315 }
1316
ToString()1317 std::string ToString() override { return "EchoRequestHandler"; }
1318
1319 private:
1320 int expected_message_ct_;
1321 int actual_message_ct_;
1322
1323 DISALLOW_COPY_AND_ASSIGN(EchoWebSocketRequestHandler);
1324 };
1325
1326 class EchoWebSocketTestHandler : public WebSocketTestHandler {
1327 public:
1328 // Create |connection_ct| connections and send |message_ct| messages to each
1329 // connection. If |in_parallel| is true the connections will be created in
1330 // parallel.
EchoWebSocketTestHandler(int connection_ct,int message_ct,bool in_parallel)1331 EchoWebSocketTestHandler(int connection_ct, int message_ct, bool in_parallel)
1332 : connection_ct_(connection_ct),
1333 message_ct_(message_ct),
1334 in_parallel_(in_parallel) {}
1335
GetClientHtml()1336 std::string GetClientHtml() override {
1337 std::stringstream ss;
1338 ss << connection_ct_;
1339 std::string cct_str = ss.str();
1340 ss.str("");
1341 ss << message_ct_;
1342 std::string mct_str = ss.str();
1343
1344 // clang-format off
1345 return
1346 "<html><body><script>\n"
1347
1348 // Input variables.
1349 "var url = '" + ws_url_ +"';\n"
1350 "var expected_connection_ct = " + cct_str + ";\n"
1351 "var expected_message_ct = " + mct_str + ";\n"
1352 "var in_parallel = " + (in_parallel_ ? "true" : "false") + ";\n"
1353 "var complete_callback = function() { " +
1354 GetDoneJS("complete_message_ct") + " }\n"
1355
1356 // Result variables.
1357 "var complete_connection_ct = 0;\n"
1358 "var complete_message_ct = 0;\n"
1359
1360 // Send the next message on the connection asynchronously, or close the
1361 // connection if all messages have been sent.
1362 "function sendNextMessage(ws, connection_id, message_id) {\n"
1363 " if (message_id < expected_message_ct) {\n"
1364 " setTimeout(function() {\n"
1365 " ws.send('message:' + connection_id + ':' + message_id);\n"
1366 " }, 1);\n"
1367 " } else {\n"
1368 " ws.close();\n"
1369 " }\n"
1370 "}\n"
1371
1372 // Handle a received message.
1373 "function onMessage(ws, connection_id, data) {\n"
1374 " var parts = data.split(':');\n"
1375 " if (parts.length == 3 && parts[0] == 'message') {\n"
1376 " var cid = parseInt(parts[1]);\n"
1377 " var mid = parseInt(parts[2]);\n"
1378 " if (cid == connection_id) {\n"
1379 " complete_message_ct++;\n"
1380 " sendNextMessage(ws, connection_id, mid + 1);\n"
1381 " } else {\n"
1382 " console.log('Connection id mismatch; expected ' +\n"
1383 " connection_id + ', actual ' + cid);\n"
1384 " }\n"
1385 " } else {\n"
1386 " console.log('Unexpected message format: ' + data);\n"
1387 " }\n"
1388 "}\n"
1389
1390 // Handle socket closed. If all messages have been sent on all
1391 // connections then complete the test.
1392 "function onClose(ws) {\n"
1393 " if (++complete_connection_ct == expected_connection_ct) {\n"
1394 " complete_callback();\n"
1395 " } else if (!in_parallel) {\n"
1396 " startConnection(complete_connection_ct);\n"
1397 " }\n"
1398 "}\n"
1399
1400 // Start a new WebSocket connection.
1401 "function startConnection(connection_id) {\n"
1402 " var ws = new WebSocket(url);\n"
1403 " ws.onopen = function() {\n"
1404 " sendNextMessage(ws, connection_id, 0);\n"
1405 " };\n"
1406 " ws.onmessage = function(event) {\n"
1407 " onMessage(ws, connection_id, event.data);\n"
1408 " };\n"
1409 " ws.onclose = function() { onClose(ws); };\n"
1410 "}\n"
1411
1412 // JS entry point.
1413 "if (in_parallel) {\n"
1414 " for (var i = 0; i < expected_connection_ct; ++i) {\n"
1415 " startConnection(i);\n"
1416 " }\n"
1417 "} else {\n"
1418 " startConnection(0);\n"
1419 "}\n"
1420
1421 "</script>WebSocket Test</body></html>";
1422 // clang-format on
1423 }
1424
OnHandlerCreated(CefRefPtr<TestServerHandler> handler)1425 void OnHandlerCreated(CefRefPtr<TestServerHandler> handler) override {
1426 handler->SetExpectedConnectionCount(connection_ct_);
1427 handler->SetExpectedWsRequestCount(connection_ct_);
1428 handler->SetExpectedWsConnectedCount(connection_ct_);
1429 handler->SetExpectedWsMessageCount(connection_ct_ * message_ct_);
1430
1431 EchoWebSocketRequestHandler* echo_handler =
1432 new EchoWebSocketRequestHandler(connection_ct_ * message_ct_);
1433 ws_url_ = echo_handler->GetWebSocketUrl();
1434 handler->AddWsRequestHandler(
1435 make_scoped_ptr<TestServerHandler::WsRequestHandler>(echo_handler));
1436 }
1437
OnDoneMessage(const std::string & result)1438 void OnDoneMessage(const std::string& result) override {
1439 const int complete_message_ct = atoi(result.c_str());
1440 EXPECT_EQ(connection_ct_ * message_ct_, complete_message_ct);
1441 ShutdownServer();
1442 }
1443
1444 private:
1445 int connection_ct_;
1446 int message_ct_;
1447 bool in_parallel_;
1448 std::string ws_url_;
1449
1450 IMPLEMENT_REFCOUNTING(EchoWebSocketTestHandler);
1451 DISALLOW_COPY_AND_ASSIGN(EchoWebSocketTestHandler);
1452 };
1453
1454 } // namespace
1455
1456 // Test handling of a single connection with a single message.
TEST(ServerTest,WebSocketSingleConnectionSingleMessage)1457 TEST(ServerTest, WebSocketSingleConnectionSingleMessage) {
1458 CefRefPtr<EchoWebSocketTestHandler> handler =
1459 new EchoWebSocketTestHandler(1, 1, true);
1460 handler->ExecuteTest();
1461 ReleaseAndWaitForDestructor(handler);
1462 }
1463
1464 // Test handling of a single connection with multiple messages.
TEST(ServerTest,WebSocketSingleConnectionMultipleMessages)1465 TEST(ServerTest, WebSocketSingleConnectionMultipleMessages) {
1466 CefRefPtr<EchoWebSocketTestHandler> handler =
1467 new EchoWebSocketTestHandler(1, 5, true);
1468 handler->ExecuteTest();
1469 ReleaseAndWaitForDestructor(handler);
1470 }
1471
1472 // Test handling of multiple connections and multiple messages in parallel.
TEST(ServerTest,WebSocketMultipleConnectionsMultipleMessagesInParallel)1473 TEST(ServerTest, WebSocketMultipleConnectionsMultipleMessagesInParallel) {
1474 CefRefPtr<EchoWebSocketTestHandler> handler =
1475 new EchoWebSocketTestHandler(4, 6, true);
1476 handler->ExecuteTest();
1477 ReleaseAndWaitForDestructor(handler);
1478 }
1479
1480 // Test handling of multiple connections and multiple messages in serial.
TEST(ServerTest,WebSocketMultipleConnectionsMultipleMessagesInSerial)1481 TEST(ServerTest, WebSocketMultipleConnectionsMultipleMessagesInSerial) {
1482 CefRefPtr<EchoWebSocketTestHandler> handler =
1483 new EchoWebSocketTestHandler(4, 6, false);
1484 handler->ExecuteTest();
1485 ReleaseAndWaitForDestructor(handler);
1486 }
1487