1 // Copyright (c) 2015 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 "tests/cefclient/browser/test_runner.h"
6
7 #include <map>
8 #include <set>
9 #include <sstream>
10
11 #include "include/base/cef_bind.h"
12 #include "include/cef_parser.h"
13 #include "include/cef_task.h"
14 #include "include/cef_trace.h"
15 #include "include/cef_web_plugin.h"
16 #include "include/wrapper/cef_closure_task.h"
17 #include "include/wrapper/cef_stream_resource_handler.h"
18 #include "tests/cefclient/browser/binding_test.h"
19 #include "tests/cefclient/browser/client_handler.h"
20 #include "tests/cefclient/browser/dialog_test.h"
21 #include "tests/cefclient/browser/drm_test.h"
22 #include "tests/cefclient/browser/main_context.h"
23 #include "tests/cefclient/browser/media_router_test.h"
24 #include "tests/cefclient/browser/preferences_test.h"
25 #include "tests/cefclient/browser/resource.h"
26 #include "tests/cefclient/browser/response_filter_test.h"
27 #include "tests/cefclient/browser/root_window_manager.h"
28 #include "tests/cefclient/browser/scheme_test.h"
29 #include "tests/cefclient/browser/server_test.h"
30 #include "tests/cefclient/browser/urlrequest_test.h"
31 #include "tests/cefclient/browser/window_test.h"
32 #include "tests/shared/browser/resource_util.h"
33
34 namespace client {
35 namespace test_runner {
36
37 namespace {
38
39 const char kTestHost[] = "tests";
40 const char kLocalHost[] = "localhost";
41 const char kTestOrigin[] = "http://tests/";
42
43 // Pages handled via StringResourceProvider.
44 const char kTestGetSourcePage[] = "get_source.html";
45 const char kTestGetTextPage[] = "get_text.html";
46 const char kTestPluginInfoPage[] = "plugin_info.html";
47
48 // Set page data and navigate the browser. Used in combination with
49 // StringResourceProvider.
LoadStringResourcePage(CefRefPtr<CefBrowser> browser,const std::string & page,const std::string & data)50 void LoadStringResourcePage(CefRefPtr<CefBrowser> browser,
51 const std::string& page,
52 const std::string& data) {
53 CefRefPtr<CefClient> client = browser->GetHost()->GetClient();
54 ClientHandler* client_handler = static_cast<ClientHandler*>(client.get());
55 client_handler->SetStringResource(page, data);
56 browser->GetMainFrame()->LoadURL(kTestOrigin + page);
57 }
58
59 // Replace all instances of |from| with |to| in |str|.
StringReplace(const std::string & str,const std::string & from,const std::string & to)60 std::string StringReplace(const std::string& str,
61 const std::string& from,
62 const std::string& to) {
63 std::string result = str;
64 std::string::size_type pos = 0;
65 std::string::size_type from_len = from.length();
66 std::string::size_type to_len = to.length();
67 do {
68 pos = result.find(from, pos);
69 if (pos != std::string::npos) {
70 result.replace(pos, from_len, to);
71 pos += to_len;
72 }
73 } while (pos != std::string::npos);
74 return result;
75 }
76
RunGetSourceTest(CefRefPtr<CefBrowser> browser)77 void RunGetSourceTest(CefRefPtr<CefBrowser> browser) {
78 class Visitor : public CefStringVisitor {
79 public:
80 explicit Visitor(CefRefPtr<CefBrowser> browser) : browser_(browser) {}
81 virtual void Visit(const CefString& string) OVERRIDE {
82 std::string source = StringReplace(string, "<", "<");
83 source = StringReplace(source, ">", ">");
84 std::stringstream ss;
85 ss << "<html><body bgcolor=\"white\">Source:<pre>" << source
86 << "</pre></body></html>";
87 LoadStringResourcePage(browser_, kTestGetSourcePage, ss.str());
88 }
89
90 private:
91 CefRefPtr<CefBrowser> browser_;
92 IMPLEMENT_REFCOUNTING(Visitor);
93 };
94
95 browser->GetMainFrame()->GetSource(new Visitor(browser));
96 }
97
RunGetTextTest(CefRefPtr<CefBrowser> browser)98 void RunGetTextTest(CefRefPtr<CefBrowser> browser) {
99 class Visitor : public CefStringVisitor {
100 public:
101 explicit Visitor(CefRefPtr<CefBrowser> browser) : browser_(browser) {}
102 virtual void Visit(const CefString& string) OVERRIDE {
103 std::string text = StringReplace(string, "<", "<");
104 text = StringReplace(text, ">", ">");
105 std::stringstream ss;
106 ss << "<html><body bgcolor=\"white\">Text:<pre>" << text
107 << "</pre></body></html>";
108 LoadStringResourcePage(browser_, kTestGetTextPage, ss.str());
109 }
110
111 private:
112 CefRefPtr<CefBrowser> browser_;
113 IMPLEMENT_REFCOUNTING(Visitor);
114 };
115
116 browser->GetMainFrame()->GetText(new Visitor(browser));
117 }
118
RunRequestTest(CefRefPtr<CefBrowser> browser)119 void RunRequestTest(CefRefPtr<CefBrowser> browser) {
120 // Create a new request
121 CefRefPtr<CefRequest> request(CefRequest::Create());
122
123 if (browser->GetMainFrame()->GetURL().ToString().find("http://tests/") != 0) {
124 // The LoadRequest method will fail with "bad IPC message" reason
125 // INVALID_INITIATOR_ORIGIN (213) unless you first navigate to the
126 // request origin using some other mechanism (LoadURL, link click, etc).
127 Alert(browser,
128 "Please first navigate to a http://tests/ URL. "
129 "For example, first load Tests > Other Tests.");
130 return;
131 }
132
133 // Set the request URL
134 request->SetURL("http://tests/request");
135
136 // Add post data to the request. The correct method and content-
137 // type headers will be set by CEF.
138 CefRefPtr<CefPostDataElement> postDataElement(CefPostDataElement::Create());
139 std::string data = "arg1=val1&arg2=val2";
140 postDataElement->SetToBytes(data.length(), data.c_str());
141 CefRefPtr<CefPostData> postData(CefPostData::Create());
142 postData->AddElement(postDataElement);
143 request->SetPostData(postData);
144
145 // Add a custom header
146 CefRequest::HeaderMap headerMap;
147 headerMap.insert(std::make_pair("X-My-Header", "My Header Value"));
148 request->SetHeaderMap(headerMap);
149
150 // Load the request
151 browser->GetMainFrame()->LoadRequest(request);
152 }
153
RunNewWindowTest(CefRefPtr<CefBrowser> browser)154 void RunNewWindowTest(CefRefPtr<CefBrowser> browser) {
155 RootWindowConfig config;
156 config.with_controls = true;
157 config.with_osr = browser->GetHost()->IsWindowRenderingDisabled();
158 MainContext::Get()->GetRootWindowManager()->CreateRootWindow(config);
159 }
160
RunPopupWindowTest(CefRefPtr<CefBrowser> browser)161 void RunPopupWindowTest(CefRefPtr<CefBrowser> browser) {
162 browser->GetMainFrame()->ExecuteJavaScript(
163 "window.open('http://www.google.com');", "about:blank", 0);
164 }
165
RunPluginInfoTest(CefRefPtr<CefBrowser> browser)166 void RunPluginInfoTest(CefRefPtr<CefBrowser> browser) {
167 class Visitor : public CefWebPluginInfoVisitor {
168 public:
169 explicit Visitor(CefRefPtr<CefBrowser> browser) : browser_(browser) {
170 html_ =
171 "<html><head><title>Plugin Info Test</title></head>"
172 "<body bgcolor=\"white\">"
173 "\n<b>Installed plugins:</b>";
174 }
175 ~Visitor() {
176 html_ += "\n</body></html>";
177
178 // Load the html in the browser.
179 LoadStringResourcePage(browser_, kTestPluginInfoPage, html_);
180 }
181
182 virtual bool Visit(CefRefPtr<CefWebPluginInfo> info,
183 int count,
184 int total) OVERRIDE {
185 html_ += "\n<br/><br/>Name: " + info->GetName().ToString() +
186 "\n<br/>Description: " + info->GetDescription().ToString() +
187 "\n<br/>Version: " + info->GetVersion().ToString() +
188 "\n<br/>Path: " + info->GetPath().ToString();
189 return true;
190 }
191
192 private:
193 std::string html_;
194 CefRefPtr<CefBrowser> browser_;
195 IMPLEMENT_REFCOUNTING(Visitor);
196 };
197
198 CefVisitWebPluginInfo(new Visitor(browser));
199 }
200
ModifyZoom(CefRefPtr<CefBrowser> browser,double delta)201 void ModifyZoom(CefRefPtr<CefBrowser> browser, double delta) {
202 if (!CefCurrentlyOn(TID_UI)) {
203 // Execute on the UI thread.
204 CefPostTask(TID_UI, base::Bind(&ModifyZoom, browser, delta));
205 return;
206 }
207
208 browser->GetHost()->SetZoomLevel(browser->GetHost()->GetZoomLevel() + delta);
209 }
210
211 const char kPrompt[] = "Prompt.";
212 const char kPromptFPS[] = "FPS";
213 const char kPromptDSF[] = "DSF";
214
215 // Handles execution of prompt results.
216 class PromptHandler : public CefMessageRouterBrowserSide::Handler {
217 public:
PromptHandler()218 PromptHandler() {}
219
220 // Called due to cefQuery execution.
OnQuery(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,int64 query_id,const CefString & request,bool persistent,CefRefPtr<Callback> callback)221 virtual bool OnQuery(CefRefPtr<CefBrowser> browser,
222 CefRefPtr<CefFrame> frame,
223 int64 query_id,
224 const CefString& request,
225 bool persistent,
226 CefRefPtr<Callback> callback) OVERRIDE {
227 // Parse |request| which takes the form "Prompt.[type]:[value]".
228 const std::string& request_str = request;
229 if (request_str.find(kPrompt) != 0)
230 return false;
231
232 std::string type = request_str.substr(sizeof(kPrompt) - 1);
233 size_t delim = type.find(':');
234 if (delim == std::string::npos)
235 return false;
236
237 const std::string& value = type.substr(delim + 1);
238 type = type.substr(0, delim);
239
240 // Canceling the prompt dialog returns a value of "null".
241 if (value != "null") {
242 if (type == kPromptFPS)
243 SetFPS(browser, atoi(value.c_str()));
244 else if (type == kPromptDSF)
245 SetDSF(browser, static_cast<float>(atof(value.c_str())));
246 }
247
248 // Nothing is done with the response.
249 callback->Success(CefString());
250 return true;
251 }
252
253 private:
SetFPS(CefRefPtr<CefBrowser> browser,int fps)254 void SetFPS(CefRefPtr<CefBrowser> browser, int fps) {
255 if (fps <= 0) {
256 // Reset to the default value.
257 CefBrowserSettings settings;
258 MainContext::Get()->PopulateBrowserSettings(&settings);
259 fps = settings.windowless_frame_rate;
260 }
261
262 browser->GetHost()->SetWindowlessFrameRate(fps);
263 }
264
SetDSF(CefRefPtr<CefBrowser> browser,float dsf)265 void SetDSF(CefRefPtr<CefBrowser> browser, float dsf) {
266 MainMessageLoop::Get()->PostClosure(
267 base::Bind(&PromptHandler::SetDSFOnMainThread, browser, dsf));
268 }
269
SetDSFOnMainThread(CefRefPtr<CefBrowser> browser,float dsf)270 static void SetDSFOnMainThread(CefRefPtr<CefBrowser> browser, float dsf) {
271 RootWindow::GetForBrowser(browser->GetIdentifier())
272 ->SetDeviceScaleFactor(dsf);
273 }
274 };
275
Prompt(CefRefPtr<CefBrowser> browser,const std::string & type,const std::string & label,const std::string & default_value)276 void Prompt(CefRefPtr<CefBrowser> browser,
277 const std::string& type,
278 const std::string& label,
279 const std::string& default_value) {
280 // Prompt the user for a new value. Works as follows:
281 // 1. Show a prompt() dialog via JavaScript.
282 // 2. Pass the result to window.cefQuery().
283 // 3. Handle the result in PromptHandler::OnQuery.
284 const std::string& code = "window.cefQuery({'request': '" +
285 std::string(kPrompt) + type + ":' + prompt('" +
286 label + "', '" + default_value + "')});";
287 browser->GetMainFrame()->ExecuteJavaScript(
288 code, browser->GetMainFrame()->GetURL(), 0);
289 }
290
PromptFPS(CefRefPtr<CefBrowser> browser)291 void PromptFPS(CefRefPtr<CefBrowser> browser) {
292 if (!CefCurrentlyOn(TID_UI)) {
293 // Execute on the UI thread.
294 CefPostTask(TID_UI, base::Bind(&PromptFPS, browser));
295 return;
296 }
297
298 // Format the default value string.
299 std::stringstream ss;
300 ss << browser->GetHost()->GetWindowlessFrameRate();
301
302 Prompt(browser, kPromptFPS, "Enter FPS", ss.str());
303 }
304
PromptDSF(CefRefPtr<CefBrowser> browser)305 void PromptDSF(CefRefPtr<CefBrowser> browser) {
306 if (!MainMessageLoop::Get()->RunsTasksOnCurrentThread()) {
307 // Execute on the main thread.
308 MainMessageLoop::Get()->PostClosure(base::Bind(&PromptDSF, browser));
309 return;
310 }
311
312 // Format the default value string.
313 std::stringstream ss;
314 ss << RootWindow::GetForBrowser(browser->GetIdentifier())
315 ->GetDeviceScaleFactor();
316
317 Prompt(browser, kPromptDSF, "Enter Device Scale Factor", ss.str());
318 }
319
BeginTracing()320 void BeginTracing() {
321 if (!CefCurrentlyOn(TID_UI)) {
322 // Execute on the UI thread.
323 CefPostTask(TID_UI, base::Bind(&BeginTracing));
324 return;
325 }
326
327 CefBeginTracing(CefString(), nullptr);
328 }
329
EndTracing(CefRefPtr<CefBrowser> browser)330 void EndTracing(CefRefPtr<CefBrowser> browser) {
331 if (!CefCurrentlyOn(TID_UI)) {
332 // Execute on the UI thread.
333 CefPostTask(TID_UI, base::Bind(&EndTracing, browser));
334 return;
335 }
336
337 class Client : public CefEndTracingCallback, public CefRunFileDialogCallback {
338 public:
339 explicit Client(CefRefPtr<CefBrowser> browser) : browser_(browser) {
340 RunDialog();
341 }
342
343 void RunDialog() {
344 static const char kDefaultFileName[] = "trace.txt";
345 std::string path = MainContext::Get()->GetDownloadPath(kDefaultFileName);
346 if (path.empty())
347 path = kDefaultFileName;
348
349 // Results in a call to OnFileDialogDismissed.
350 browser_->GetHost()->RunFileDialog(
351 static_cast<cef_file_dialog_mode_t>(FILE_DIALOG_SAVE |
352 FILE_DIALOG_OVERWRITEPROMPT_FLAG),
353 CefString(), // title
354 path,
355 std::vector<CefString>(), // accept_filters
356 0, // selected_accept_filter
357 this);
358 }
359
360 void OnFileDialogDismissed(
361 int selected_accept_filter,
362 const std::vector<CefString>& file_paths) OVERRIDE {
363 if (!file_paths.empty()) {
364 // File selected. Results in a call to OnEndTracingComplete.
365 CefEndTracing(file_paths.front(), this);
366 } else {
367 // No file selected. Discard the trace data.
368 CefEndTracing(CefString(), nullptr);
369 }
370 }
371
372 void OnEndTracingComplete(const CefString& tracing_file) OVERRIDE {
373 Alert(browser_,
374 "File \"" + tracing_file.ToString() + "\" saved successfully.");
375 }
376
377 private:
378 CefRefPtr<CefBrowser> browser_;
379
380 IMPLEMENT_REFCOUNTING(Client);
381 };
382
383 new Client(browser);
384 }
385
PrintToPDF(CefRefPtr<CefBrowser> browser)386 void PrintToPDF(CefRefPtr<CefBrowser> browser) {
387 if (!CefCurrentlyOn(TID_UI)) {
388 // Execute on the UI thread.
389 CefPostTask(TID_UI, base::Bind(&PrintToPDF, browser));
390 return;
391 }
392
393 class Client : public CefPdfPrintCallback, public CefRunFileDialogCallback {
394 public:
395 explicit Client(CefRefPtr<CefBrowser> browser) : browser_(browser) {
396 RunDialog();
397 }
398
399 void RunDialog() {
400 static const char kDefaultFileName[] = "output.pdf";
401 std::string path = MainContext::Get()->GetDownloadPath(kDefaultFileName);
402 if (path.empty())
403 path = kDefaultFileName;
404
405 std::vector<CefString> accept_filters;
406 accept_filters.push_back(".pdf");
407
408 // Results in a call to OnFileDialogDismissed.
409 browser_->GetHost()->RunFileDialog(
410 static_cast<cef_file_dialog_mode_t>(FILE_DIALOG_SAVE |
411 FILE_DIALOG_OVERWRITEPROMPT_FLAG),
412 CefString(), // title
413 path, accept_filters,
414 0, // selected_accept_filter
415 this);
416 }
417
418 void OnFileDialogDismissed(
419 int selected_accept_filter,
420 const std::vector<CefString>& file_paths) OVERRIDE {
421 if (!file_paths.empty()) {
422 CefPdfPrintSettings settings;
423
424 // Show the URL in the footer.
425 settings.header_footer_enabled = true;
426 CefString(&settings.header_footer_url) =
427 browser_->GetMainFrame()->GetURL();
428
429 // Print to the selected PDF file.
430 browser_->GetHost()->PrintToPDF(file_paths[0], settings, this);
431 }
432 }
433
434 void OnPdfPrintFinished(const CefString& path, bool ok) OVERRIDE {
435 Alert(browser_, "File \"" + path.ToString() + "\" " +
436 (ok ? "saved successfully." : "failed to save."));
437 }
438
439 private:
440 CefRefPtr<CefBrowser> browser_;
441
442 IMPLEMENT_REFCOUNTING(Client);
443 };
444
445 new Client(browser);
446 }
447
MuteAudio(CefRefPtr<CefBrowser> browser,bool mute)448 void MuteAudio(CefRefPtr<CefBrowser> browser, bool mute) {
449 CefRefPtr<CefBrowserHost> host = browser->GetHost();
450 host->SetAudioMuted(mute);
451 }
452
RunOtherTests(CefRefPtr<CefBrowser> browser)453 void RunOtherTests(CefRefPtr<CefBrowser> browser) {
454 browser->GetMainFrame()->LoadURL("http://tests/other_tests");
455 }
456
457 // Provider that dumps the request contents.
458 class RequestDumpResourceProvider : public CefResourceManager::Provider {
459 public:
RequestDumpResourceProvider(const std::string & url)460 explicit RequestDumpResourceProvider(const std::string& url) : url_(url) {
461 DCHECK(!url.empty());
462 }
463
OnRequest(scoped_refptr<CefResourceManager::Request> request)464 bool OnRequest(scoped_refptr<CefResourceManager::Request> request) OVERRIDE {
465 CEF_REQUIRE_IO_THREAD();
466
467 const std::string& url = request->url();
468 if (url != url_) {
469 // Not handled by this provider.
470 return false;
471 }
472
473 CefResponse::HeaderMap response_headers;
474 CefRefPtr<CefStreamReader> response =
475 GetDumpResponse(request->request(), response_headers);
476
477 request->Continue(new CefStreamResourceHandler(200, "OK", "text/html",
478 response_headers, response));
479 return true;
480 }
481
482 private:
483 std::string url_;
484
485 DISALLOW_COPY_AND_ASSIGN(RequestDumpResourceProvider);
486 };
487
488 // Provider that returns string data for specific pages. Used in combination
489 // with LoadStringResourcePage().
490 class StringResourceProvider : public CefResourceManager::Provider {
491 public:
StringResourceProvider(const std::set<std::string> & pages,StringResourceMap * string_resource_map)492 StringResourceProvider(const std::set<std::string>& pages,
493 StringResourceMap* string_resource_map)
494 : pages_(pages), string_resource_map_(string_resource_map) {
495 DCHECK(!pages.empty());
496 }
497
OnRequest(scoped_refptr<CefResourceManager::Request> request)498 bool OnRequest(scoped_refptr<CefResourceManager::Request> request) OVERRIDE {
499 CEF_REQUIRE_IO_THREAD();
500
501 const std::string& url = request->url();
502 if (url.find(kTestOrigin) != 0U) {
503 // Not handled by this provider.
504 return false;
505 }
506
507 const std::string& page = url.substr(strlen(kTestOrigin));
508 if (pages_.find(page) == pages_.end()) {
509 // Not handled by this provider.
510 return false;
511 }
512
513 std::string value;
514 StringResourceMap::const_iterator it = string_resource_map_->find(page);
515 if (it != string_resource_map_->end()) {
516 value = it->second;
517 } else {
518 value = "<html><body>No data available</body></html>";
519 }
520
521 CefRefPtr<CefStreamReader> response = CefStreamReader::CreateForData(
522 static_cast<void*>(const_cast<char*>(value.c_str())), value.size());
523
524 request->Continue(new CefStreamResourceHandler(
525 200, "OK", "text/html", CefResponse::HeaderMap(), response));
526 return true;
527 }
528
529 private:
530 const std::set<std::string> pages_;
531
532 // Only accessed on the IO thread.
533 StringResourceMap* string_resource_map_;
534
535 DISALLOW_COPY_AND_ASSIGN(StringResourceProvider);
536 };
537
538 // Add a file extension to |url| if none is currently specified.
RequestUrlFilter(const std::string & url)539 std::string RequestUrlFilter(const std::string& url) {
540 if (url.find(kTestOrigin) != 0U) {
541 // Don't filter anything outside of the test origin.
542 return url;
543 }
544
545 // Identify where the query or fragment component, if any, begins.
546 size_t suffix_pos = url.find('?');
547 if (suffix_pos == std::string::npos)
548 suffix_pos = url.find('#');
549
550 std::string url_base, url_suffix;
551 if (suffix_pos == std::string::npos) {
552 url_base = url;
553 } else {
554 url_base = url.substr(0, suffix_pos);
555 url_suffix = url.substr(suffix_pos);
556 }
557
558 // Identify the last path component.
559 size_t path_pos = url_base.rfind('/');
560 if (path_pos == std::string::npos)
561 return url;
562
563 const std::string& path_component = url_base.substr(path_pos);
564
565 // Identify if a file extension is currently specified.
566 size_t ext_pos = path_component.rfind(".");
567 if (ext_pos != std::string::npos)
568 return url;
569
570 // Rebuild the URL with a file extension.
571 return url_base + ".html" + url_suffix;
572 }
573
574 } // namespace
575
RunTest(CefRefPtr<CefBrowser> browser,int id)576 void RunTest(CefRefPtr<CefBrowser> browser, int id) {
577 if (!browser)
578 return;
579
580 switch (id) {
581 case ID_TESTS_GETSOURCE:
582 RunGetSourceTest(browser);
583 break;
584 case ID_TESTS_GETTEXT:
585 RunGetTextTest(browser);
586 break;
587 case ID_TESTS_WINDOW_NEW:
588 RunNewWindowTest(browser);
589 break;
590 case ID_TESTS_WINDOW_POPUP:
591 RunPopupWindowTest(browser);
592 break;
593 case ID_TESTS_REQUEST:
594 RunRequestTest(browser);
595 break;
596 case ID_TESTS_PLUGIN_INFO:
597 RunPluginInfoTest(browser);
598 break;
599 case ID_TESTS_ZOOM_IN:
600 ModifyZoom(browser, 0.5);
601 break;
602 case ID_TESTS_ZOOM_OUT:
603 ModifyZoom(browser, -0.5);
604 break;
605 case ID_TESTS_ZOOM_RESET:
606 browser->GetHost()->SetZoomLevel(0.0);
607 break;
608 case ID_TESTS_OSR_FPS:
609 PromptFPS(browser);
610 break;
611 case ID_TESTS_OSR_DSF:
612 PromptDSF(browser);
613 break;
614 case ID_TESTS_TRACING_BEGIN:
615 BeginTracing();
616 break;
617 case ID_TESTS_TRACING_END:
618 EndTracing(browser);
619 break;
620 case ID_TESTS_PRINT:
621 browser->GetHost()->Print();
622 break;
623 case ID_TESTS_PRINT_TO_PDF:
624 PrintToPDF(browser);
625 break;
626 case ID_TESTS_MUTE_AUDIO:
627 MuteAudio(browser, true);
628 break;
629 case ID_TESTS_UNMUTE_AUDIO:
630 MuteAudio(browser, false);
631 break;
632 case ID_TESTS_OTHER_TESTS:
633 RunOtherTests(browser);
634 break;
635 }
636 }
637
DumpRequestContents(CefRefPtr<CefRequest> request)638 std::string DumpRequestContents(CefRefPtr<CefRequest> request) {
639 std::stringstream ss;
640
641 ss << "URL: " << std::string(request->GetURL());
642 ss << "\nMethod: " << std::string(request->GetMethod());
643
644 CefRequest::HeaderMap headerMap;
645 request->GetHeaderMap(headerMap);
646 if (headerMap.size() > 0) {
647 ss << "\nHeaders:";
648 CefRequest::HeaderMap::const_iterator it = headerMap.begin();
649 for (; it != headerMap.end(); ++it) {
650 ss << "\n\t" << std::string((*it).first) << ": "
651 << std::string((*it).second);
652 }
653 }
654
655 CefRefPtr<CefPostData> postData = request->GetPostData();
656 if (postData.get()) {
657 CefPostData::ElementVector elements;
658 postData->GetElements(elements);
659 if (elements.size() > 0) {
660 ss << "\nPost Data:";
661 CefRefPtr<CefPostDataElement> element;
662 CefPostData::ElementVector::const_iterator it = elements.begin();
663 for (; it != elements.end(); ++it) {
664 element = (*it);
665 if (element->GetType() == PDE_TYPE_BYTES) {
666 // the element is composed of bytes
667 ss << "\n\tBytes: ";
668 if (element->GetBytesCount() == 0) {
669 ss << "(empty)";
670 } else {
671 // retrieve the data.
672 size_t size = element->GetBytesCount();
673 char* bytes = new char[size];
674 element->GetBytes(size, bytes);
675 ss << std::string(bytes, size);
676 delete[] bytes;
677 }
678 } else if (element->GetType() == PDE_TYPE_FILE) {
679 ss << "\n\tFile: " << std::string(element->GetFile());
680 }
681 }
682 }
683 }
684
685 return ss.str();
686 }
687
GetDumpResponse(CefRefPtr<CefRequest> request,CefResponse::HeaderMap & response_headers)688 CefRefPtr<CefStreamReader> GetDumpResponse(
689 CefRefPtr<CefRequest> request,
690 CefResponse::HeaderMap& response_headers) {
691 std::string origin;
692
693 // Extract the origin request header, if any. It will be specified for
694 // cross-origin requests.
695 {
696 CefRequest::HeaderMap requestMap;
697 request->GetHeaderMap(requestMap);
698
699 CefRequest::HeaderMap::const_iterator it = requestMap.begin();
700 for (; it != requestMap.end(); ++it) {
701 std::string key = it->first;
702 std::transform(key.begin(), key.end(), key.begin(), ::tolower);
703 if (key == "origin") {
704 origin = it->second;
705 break;
706 }
707 }
708 }
709
710 if (!origin.empty() &&
711 (origin.find("http://" + std::string(kTestHost)) == 0 ||
712 origin.find("http://" + std::string(kLocalHost)) == 0)) {
713 // Allow cross-origin XMLHttpRequests from test origins.
714 response_headers.insert(
715 std::make_pair("Access-Control-Allow-Origin", origin));
716
717 // Allow the custom header from the xmlhttprequest.html example.
718 response_headers.insert(
719 std::make_pair("Access-Control-Allow-Headers", "My-Custom-Header"));
720 }
721
722 const std::string& dump = DumpRequestContents(request);
723 std::string str =
724 "<html><body bgcolor=\"white\"><pre>" + dump + "</pre></body></html>";
725 CefRefPtr<CefStreamReader> stream = CefStreamReader::CreateForData(
726 static_cast<void*>(const_cast<char*>(str.c_str())), str.size());
727 DCHECK(stream);
728 return stream;
729 }
730
GetDataURI(const std::string & data,const std::string & mime_type)731 std::string GetDataURI(const std::string& data, const std::string& mime_type) {
732 return "data:" + mime_type + ";base64," +
733 CefURIEncode(CefBase64Encode(data.data(), data.size()), false)
734 .ToString();
735 }
736
GetErrorString(cef_errorcode_t code)737 std::string GetErrorString(cef_errorcode_t code) {
738 // Case condition that returns |code| as a string.
739 #define CASE(code) \
740 case code: \
741 return #code
742
743 switch (code) {
744 CASE(ERR_NONE);
745 CASE(ERR_FAILED);
746 CASE(ERR_ABORTED);
747 CASE(ERR_INVALID_ARGUMENT);
748 CASE(ERR_INVALID_HANDLE);
749 CASE(ERR_FILE_NOT_FOUND);
750 CASE(ERR_TIMED_OUT);
751 CASE(ERR_FILE_TOO_BIG);
752 CASE(ERR_UNEXPECTED);
753 CASE(ERR_ACCESS_DENIED);
754 CASE(ERR_NOT_IMPLEMENTED);
755 CASE(ERR_CONNECTION_CLOSED);
756 CASE(ERR_CONNECTION_RESET);
757 CASE(ERR_CONNECTION_REFUSED);
758 CASE(ERR_CONNECTION_ABORTED);
759 CASE(ERR_CONNECTION_FAILED);
760 CASE(ERR_NAME_NOT_RESOLVED);
761 CASE(ERR_INTERNET_DISCONNECTED);
762 CASE(ERR_SSL_PROTOCOL_ERROR);
763 CASE(ERR_ADDRESS_INVALID);
764 CASE(ERR_ADDRESS_UNREACHABLE);
765 CASE(ERR_SSL_CLIENT_AUTH_CERT_NEEDED);
766 CASE(ERR_TUNNEL_CONNECTION_FAILED);
767 CASE(ERR_NO_SSL_VERSIONS_ENABLED);
768 CASE(ERR_SSL_VERSION_OR_CIPHER_MISMATCH);
769 CASE(ERR_SSL_RENEGOTIATION_REQUESTED);
770 CASE(ERR_CERT_COMMON_NAME_INVALID);
771 CASE(ERR_CERT_DATE_INVALID);
772 CASE(ERR_CERT_AUTHORITY_INVALID);
773 CASE(ERR_CERT_CONTAINS_ERRORS);
774 CASE(ERR_CERT_NO_REVOCATION_MECHANISM);
775 CASE(ERR_CERT_UNABLE_TO_CHECK_REVOCATION);
776 CASE(ERR_CERT_REVOKED);
777 CASE(ERR_CERT_INVALID);
778 CASE(ERR_CERT_END);
779 CASE(ERR_INVALID_URL);
780 CASE(ERR_DISALLOWED_URL_SCHEME);
781 CASE(ERR_UNKNOWN_URL_SCHEME);
782 CASE(ERR_TOO_MANY_REDIRECTS);
783 CASE(ERR_UNSAFE_REDIRECT);
784 CASE(ERR_UNSAFE_PORT);
785 CASE(ERR_INVALID_RESPONSE);
786 CASE(ERR_INVALID_CHUNKED_ENCODING);
787 CASE(ERR_METHOD_NOT_SUPPORTED);
788 CASE(ERR_UNEXPECTED_PROXY_AUTH);
789 CASE(ERR_EMPTY_RESPONSE);
790 CASE(ERR_RESPONSE_HEADERS_TOO_BIG);
791 CASE(ERR_CACHE_MISS);
792 CASE(ERR_INSECURE_RESPONSE);
793 default:
794 return "UNKNOWN";
795 }
796 }
797
SetupResourceManager(CefRefPtr<CefResourceManager> resource_manager,StringResourceMap * string_resource_map)798 void SetupResourceManager(CefRefPtr<CefResourceManager> resource_manager,
799 StringResourceMap* string_resource_map) {
800 if (!CefCurrentlyOn(TID_IO)) {
801 // Execute on the browser IO thread.
802 CefPostTask(TID_IO, base::Bind(SetupResourceManager, resource_manager,
803 string_resource_map));
804 return;
805 }
806
807 const std::string& test_origin = kTestOrigin;
808
809 // Add the URL filter.
810 resource_manager->SetUrlFilter(base::Bind(RequestUrlFilter));
811
812 // Add provider for resource dumps.
813 resource_manager->AddProvider(
814 new RequestDumpResourceProvider(test_origin + "request.html"), 0,
815 std::string());
816
817 // Set of supported string pages.
818 std::set<std::string> string_pages;
819 string_pages.insert(kTestGetSourcePage);
820 string_pages.insert(kTestGetTextPage);
821 string_pages.insert(kTestPluginInfoPage);
822
823 // Add provider for string resources.
824 resource_manager->AddProvider(
825 new StringResourceProvider(string_pages, string_resource_map), 0,
826 std::string());
827
828 // Add provider for bundled resource files.
829 #if defined(OS_WIN)
830 // Read resources from the binary.
831 resource_manager->AddProvider(
832 CreateBinaryResourceProvider(test_origin, std::string()), 100,
833 std::string());
834 #elif defined(OS_POSIX)
835 // Read resources from a directory on disk.
836 std::string resource_dir;
837 if (GetResourceDir(resource_dir)) {
838 resource_manager->AddDirectoryProvider(test_origin, resource_dir, 100,
839 std::string());
840 }
841 #endif
842 }
843
Alert(CefRefPtr<CefBrowser> browser,const std::string & message)844 void Alert(CefRefPtr<CefBrowser> browser, const std::string& message) {
845 if (browser->GetHost()->GetExtension()) {
846 // Alerts originating from extension hosts should instead be displayed in
847 // the active browser.
848 browser = MainContext::Get()->GetRootWindowManager()->GetActiveBrowser();
849 if (!browser)
850 return;
851 }
852
853 // Escape special characters in the message.
854 std::string msg = StringReplace(message, "\\", "\\\\");
855 msg = StringReplace(msg, "'", "\\'");
856
857 // Execute a JavaScript alert().
858 CefRefPtr<CefFrame> frame = browser->GetMainFrame();
859 frame->ExecuteJavaScript("alert('" + msg + "');", frame->GetURL(), 0);
860 }
861
IsTestURL(const std::string & url,const std::string & path)862 bool IsTestURL(const std::string& url, const std::string& path) {
863 CefURLParts parts;
864 CefParseURL(url, parts);
865
866 const std::string& url_host = CefString(&parts.host);
867 if (url_host != kTestHost && url_host != kLocalHost)
868 return false;
869
870 const std::string& url_path = CefString(&parts.path);
871 return url_path.find(path) == 0;
872 }
873
CreateMessageHandlers(MessageHandlerSet & handlers)874 void CreateMessageHandlers(MessageHandlerSet& handlers) {
875 handlers.insert(new PromptHandler);
876
877 // Create the binding test handlers.
878 binding_test::CreateMessageHandlers(handlers);
879
880 // Create the dialog test handlers.
881 dialog_test::CreateMessageHandlers(handlers);
882
883 // Create the drm test handlers.
884 drm_test::CreateMessageHandlers(handlers);
885
886 // Create the media router test handlers.
887 media_router_test::CreateMessageHandlers(handlers);
888
889 // Create the preferences test handlers.
890 preferences_test::CreateMessageHandlers(handlers);
891
892 // Create the server test handlers.
893 server_test::CreateMessageHandlers(handlers);
894
895 // Create the urlrequest test handlers.
896 urlrequest_test::CreateMessageHandlers(handlers);
897
898 // Create the window test handlers.
899 window_test::CreateMessageHandlers(handlers);
900 }
901
RegisterSchemeHandlers()902 void RegisterSchemeHandlers() {
903 // Register the scheme handler.
904 scheme_test::RegisterSchemeHandlers();
905 }
906
GetResourceResponseFilter(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,CefRefPtr<CefResponse> response)907 CefRefPtr<CefResponseFilter> GetResourceResponseFilter(
908 CefRefPtr<CefBrowser> browser,
909 CefRefPtr<CefFrame> frame,
910 CefRefPtr<CefRequest> request,
911 CefRefPtr<CefResponse> response) {
912 // Create the response filter.
913 return response_filter_test::GetResourceResponseFilter(browser, frame,
914 request, response);
915 }
916
917 } // namespace test_runner
918 } // namespace client
919