• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, "<", "&lt;");
83       source = StringReplace(source, ">", "&gt;");
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, "<", "&lt;");
104       text = StringReplace(text, ">", "&gt;");
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