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