| // Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights |
| // reserved. Use of this source code is governed by a BSD-style license that |
| // can be found in the LICENSE file. |
| |
| #include "tests/cefclient/browser/test_runner.h" |
| |
| #include <map> |
| #include <set> |
| #include <sstream> |
| |
| #include "include/base/cef_bind.h" |
| #include "include/cef_parser.h" |
| #include "include/cef_task.h" |
| #include "include/cef_trace.h" |
| #include "include/cef_web_plugin.h" |
| #include "include/wrapper/cef_closure_task.h" |
| #include "include/wrapper/cef_stream_resource_handler.h" |
| #include "tests/cefclient/browser/binding_test.h" |
| #include "tests/cefclient/browser/client_handler.h" |
| #include "tests/cefclient/browser/dialog_test.h" |
| #include "tests/cefclient/browser/drm_test.h" |
| #include "tests/cefclient/browser/main_context.h" |
| #include "tests/cefclient/browser/media_router_test.h" |
| #include "tests/cefclient/browser/preferences_test.h" |
| #include "tests/cefclient/browser/resource.h" |
| #include "tests/cefclient/browser/response_filter_test.h" |
| #include "tests/cefclient/browser/root_window_manager.h" |
| #include "tests/cefclient/browser/scheme_test.h" |
| #include "tests/cefclient/browser/server_test.h" |
| #include "tests/cefclient/browser/urlrequest_test.h" |
| #include "tests/cefclient/browser/window_test.h" |
| #include "tests/shared/browser/resource_util.h" |
| |
| namespace client { |
| namespace test_runner { |
| |
| namespace { |
| |
| const char kTestHost[] = "tests"; |
| const char kLocalHost[] = "localhost"; |
| const char kTestOrigin[] = "http://tests/"; |
| |
| // Pages handled via StringResourceProvider. |
| const char kTestGetSourcePage[] = "get_source.html"; |
| const char kTestGetTextPage[] = "get_text.html"; |
| const char kTestPluginInfoPage[] = "plugin_info.html"; |
| |
| // Set page data and navigate the browser. Used in combination with |
| // StringResourceProvider. |
| void LoadStringResourcePage(CefRefPtr<CefBrowser> browser, |
| const std::string& page, |
| const std::string& data) { |
| CefRefPtr<CefClient> client = browser->GetHost()->GetClient(); |
| ClientHandler* client_handler = static_cast<ClientHandler*>(client.get()); |
| client_handler->SetStringResource(page, data); |
| browser->GetMainFrame()->LoadURL(kTestOrigin + page); |
| } |
| |
| // Replace all instances of |from| with |to| in |str|. |
| std::string StringReplace(const std::string& str, |
| const std::string& from, |
| const std::string& to) { |
| std::string result = str; |
| std::string::size_type pos = 0; |
| std::string::size_type from_len = from.length(); |
| std::string::size_type to_len = to.length(); |
| do { |
| pos = result.find(from, pos); |
| if (pos != std::string::npos) { |
| result.replace(pos, from_len, to); |
| pos += to_len; |
| } |
| } while (pos != std::string::npos); |
| return result; |
| } |
| |
| void RunGetSourceTest(CefRefPtr<CefBrowser> browser) { |
| class Visitor : public CefStringVisitor { |
| public: |
| explicit Visitor(CefRefPtr<CefBrowser> browser) : browser_(browser) {} |
| virtual void Visit(const CefString& string) OVERRIDE { |
| std::string source = StringReplace(string, "<", "<"); |
| source = StringReplace(source, ">", ">"); |
| std::stringstream ss; |
| ss << "<html><body bgcolor=\"white\">Source:<pre>" << source |
| << "</pre></body></html>"; |
| LoadStringResourcePage(browser_, kTestGetSourcePage, ss.str()); |
| } |
| |
| private: |
| CefRefPtr<CefBrowser> browser_; |
| IMPLEMENT_REFCOUNTING(Visitor); |
| }; |
| |
| browser->GetMainFrame()->GetSource(new Visitor(browser)); |
| } |
| |
| void RunGetTextTest(CefRefPtr<CefBrowser> browser) { |
| class Visitor : public CefStringVisitor { |
| public: |
| explicit Visitor(CefRefPtr<CefBrowser> browser) : browser_(browser) {} |
| virtual void Visit(const CefString& string) OVERRIDE { |
| std::string text = StringReplace(string, "<", "<"); |
| text = StringReplace(text, ">", ">"); |
| std::stringstream ss; |
| ss << "<html><body bgcolor=\"white\">Text:<pre>" << text |
| << "</pre></body></html>"; |
| LoadStringResourcePage(browser_, kTestGetTextPage, ss.str()); |
| } |
| |
| private: |
| CefRefPtr<CefBrowser> browser_; |
| IMPLEMENT_REFCOUNTING(Visitor); |
| }; |
| |
| browser->GetMainFrame()->GetText(new Visitor(browser)); |
| } |
| |
| void RunRequestTest(CefRefPtr<CefBrowser> browser) { |
| // Create a new request |
| CefRefPtr<CefRequest> request(CefRequest::Create()); |
| |
| if (browser->GetMainFrame()->GetURL().ToString().find("http://tests/") != 0) { |
| // The LoadRequest method will fail with "bad IPC message" reason |
| // INVALID_INITIATOR_ORIGIN (213) unless you first navigate to the |
| // request origin using some other mechanism (LoadURL, link click, etc). |
| Alert(browser, |
| "Please first navigate to a http://tests/ URL. " |
| "For example, first load Tests > Other Tests."); |
| return; |
| } |
| |
| // Set the request URL |
| request->SetURL("http://tests/request"); |
| |
| // Add post data to the request. The correct method and content- |
| // type headers will be set by CEF. |
| CefRefPtr<CefPostDataElement> postDataElement(CefPostDataElement::Create()); |
| std::string data = "arg1=val1&arg2=val2"; |
| postDataElement->SetToBytes(data.length(), data.c_str()); |
| CefRefPtr<CefPostData> postData(CefPostData::Create()); |
| postData->AddElement(postDataElement); |
| request->SetPostData(postData); |
| |
| // Add a custom header |
| CefRequest::HeaderMap headerMap; |
| headerMap.insert(std::make_pair("X-My-Header", "My Header Value")); |
| request->SetHeaderMap(headerMap); |
| |
| // Load the request |
| browser->GetMainFrame()->LoadRequest(request); |
| } |
| |
| void RunNewWindowTest(CefRefPtr<CefBrowser> browser) { |
| RootWindowConfig config; |
| config.with_controls = true; |
| config.with_osr = browser->GetHost()->IsWindowRenderingDisabled(); |
| MainContext::Get()->GetRootWindowManager()->CreateRootWindow(config); |
| } |
| |
| void RunPopupWindowTest(CefRefPtr<CefBrowser> browser) { |
| browser->GetMainFrame()->ExecuteJavaScript( |
| "window.open('http://www.google.com');", "about:blank", 0); |
| } |
| |
| void RunPluginInfoTest(CefRefPtr<CefBrowser> browser) { |
| class Visitor : public CefWebPluginInfoVisitor { |
| public: |
| explicit Visitor(CefRefPtr<CefBrowser> browser) : browser_(browser) { |
| html_ = |
| "<html><head><title>Plugin Info Test</title></head>" |
| "<body bgcolor=\"white\">" |
| "\n<b>Installed plugins:</b>"; |
| } |
| ~Visitor() { |
| html_ += "\n</body></html>"; |
| |
| // Load the html in the browser. |
| LoadStringResourcePage(browser_, kTestPluginInfoPage, html_); |
| } |
| |
| virtual bool Visit(CefRefPtr<CefWebPluginInfo> info, |
| int count, |
| int total) OVERRIDE { |
| html_ += "\n<br/><br/>Name: " + info->GetName().ToString() + |
| "\n<br/>Description: " + info->GetDescription().ToString() + |
| "\n<br/>Version: " + info->GetVersion().ToString() + |
| "\n<br/>Path: " + info->GetPath().ToString(); |
| return true; |
| } |
| |
| private: |
| std::string html_; |
| CefRefPtr<CefBrowser> browser_; |
| IMPLEMENT_REFCOUNTING(Visitor); |
| }; |
| |
| CefVisitWebPluginInfo(new Visitor(browser)); |
| } |
| |
| void ModifyZoom(CefRefPtr<CefBrowser> browser, double delta) { |
| if (!CefCurrentlyOn(TID_UI)) { |
| // Execute on the UI thread. |
| CefPostTask(TID_UI, base::Bind(&ModifyZoom, browser, delta)); |
| return; |
| } |
| |
| browser->GetHost()->SetZoomLevel(browser->GetHost()->GetZoomLevel() + delta); |
| } |
| |
| const char kPrompt[] = "Prompt."; |
| const char kPromptFPS[] = "FPS"; |
| const char kPromptDSF[] = "DSF"; |
| |
| // Handles execution of prompt results. |
| class PromptHandler : public CefMessageRouterBrowserSide::Handler { |
| public: |
| PromptHandler() {} |
| |
| // Called due to cefQuery execution. |
| virtual bool OnQuery(CefRefPtr<CefBrowser> browser, |
| CefRefPtr<CefFrame> frame, |
| int64 query_id, |
| const CefString& request, |
| bool persistent, |
| CefRefPtr<Callback> callback) OVERRIDE { |
| // Parse |request| which takes the form "Prompt.[type]:[value]". |
| const std::string& request_str = request; |
| if (request_str.find(kPrompt) != 0) |
| return false; |
| |
| std::string type = request_str.substr(sizeof(kPrompt) - 1); |
| size_t delim = type.find(':'); |
| if (delim == std::string::npos) |
| return false; |
| |
| const std::string& value = type.substr(delim + 1); |
| type = type.substr(0, delim); |
| |
| // Canceling the prompt dialog returns a value of "null". |
| if (value != "null") { |
| if (type == kPromptFPS) |
| SetFPS(browser, atoi(value.c_str())); |
| else if (type == kPromptDSF) |
| SetDSF(browser, static_cast<float>(atof(value.c_str()))); |
| } |
| |
| // Nothing is done with the response. |
| callback->Success(CefString()); |
| return true; |
| } |
| |
| private: |
| void SetFPS(CefRefPtr<CefBrowser> browser, int fps) { |
| if (fps <= 0) { |
| // Reset to the default value. |
| CefBrowserSettings settings; |
| MainContext::Get()->PopulateBrowserSettings(&settings); |
| fps = settings.windowless_frame_rate; |
| } |
| |
| browser->GetHost()->SetWindowlessFrameRate(fps); |
| } |
| |
| void SetDSF(CefRefPtr<CefBrowser> browser, float dsf) { |
| MainMessageLoop::Get()->PostClosure( |
| base::Bind(&PromptHandler::SetDSFOnMainThread, browser, dsf)); |
| } |
| |
| static void SetDSFOnMainThread(CefRefPtr<CefBrowser> browser, float dsf) { |
| RootWindow::GetForBrowser(browser->GetIdentifier()) |
| ->SetDeviceScaleFactor(dsf); |
| } |
| }; |
| |
| void Prompt(CefRefPtr<CefBrowser> browser, |
| const std::string& type, |
| const std::string& label, |
| const std::string& default_value) { |
| // Prompt the user for a new value. Works as follows: |
| // 1. Show a prompt() dialog via JavaScript. |
| // 2. Pass the result to window.cefQuery(). |
| // 3. Handle the result in PromptHandler::OnQuery. |
| const std::string& code = "window.cefQuery({'request': '" + |
| std::string(kPrompt) + type + ":' + prompt('" + |
| label + "', '" + default_value + "')});"; |
| browser->GetMainFrame()->ExecuteJavaScript( |
| code, browser->GetMainFrame()->GetURL(), 0); |
| } |
| |
| void PromptFPS(CefRefPtr<CefBrowser> browser) { |
| if (!CefCurrentlyOn(TID_UI)) { |
| // Execute on the UI thread. |
| CefPostTask(TID_UI, base::Bind(&PromptFPS, browser)); |
| return; |
| } |
| |
| // Format the default value string. |
| std::stringstream ss; |
| ss << browser->GetHost()->GetWindowlessFrameRate(); |
| |
| Prompt(browser, kPromptFPS, "Enter FPS", ss.str()); |
| } |
| |
| void PromptDSF(CefRefPtr<CefBrowser> browser) { |
| if (!MainMessageLoop::Get()->RunsTasksOnCurrentThread()) { |
| // Execute on the main thread. |
| MainMessageLoop::Get()->PostClosure(base::Bind(&PromptDSF, browser)); |
| return; |
| } |
| |
| // Format the default value string. |
| std::stringstream ss; |
| ss << RootWindow::GetForBrowser(browser->GetIdentifier()) |
| ->GetDeviceScaleFactor(); |
| |
| Prompt(browser, kPromptDSF, "Enter Device Scale Factor", ss.str()); |
| } |
| |
| void BeginTracing() { |
| if (!CefCurrentlyOn(TID_UI)) { |
| // Execute on the UI thread. |
| CefPostTask(TID_UI, base::Bind(&BeginTracing)); |
| return; |
| } |
| |
| CefBeginTracing(CefString(), nullptr); |
| } |
| |
| void EndTracing(CefRefPtr<CefBrowser> browser) { |
| if (!CefCurrentlyOn(TID_UI)) { |
| // Execute on the UI thread. |
| CefPostTask(TID_UI, base::Bind(&EndTracing, browser)); |
| return; |
| } |
| |
| class Client : public CefEndTracingCallback, public CefRunFileDialogCallback { |
| public: |
| explicit Client(CefRefPtr<CefBrowser> browser) : browser_(browser) { |
| RunDialog(); |
| } |
| |
| void RunDialog() { |
| static const char kDefaultFileName[] = "trace.txt"; |
| std::string path = MainContext::Get()->GetDownloadPath(kDefaultFileName); |
| if (path.empty()) |
| path = kDefaultFileName; |
| |
| // Results in a call to OnFileDialogDismissed. |
| browser_->GetHost()->RunFileDialog( |
| static_cast<cef_file_dialog_mode_t>(FILE_DIALOG_SAVE | |
| FILE_DIALOG_OVERWRITEPROMPT_FLAG), |
| CefString(), // title |
| path, |
| std::vector<CefString>(), // accept_filters |
| 0, // selected_accept_filter |
| this); |
| } |
| |
| void OnFileDialogDismissed( |
| int selected_accept_filter, |
| const std::vector<CefString>& file_paths) OVERRIDE { |
| if (!file_paths.empty()) { |
| // File selected. Results in a call to OnEndTracingComplete. |
| CefEndTracing(file_paths.front(), this); |
| } else { |
| // No file selected. Discard the trace data. |
| CefEndTracing(CefString(), nullptr); |
| } |
| } |
| |
| void OnEndTracingComplete(const CefString& tracing_file) OVERRIDE { |
| Alert(browser_, |
| "File \"" + tracing_file.ToString() + "\" saved successfully."); |
| } |
| |
| private: |
| CefRefPtr<CefBrowser> browser_; |
| |
| IMPLEMENT_REFCOUNTING(Client); |
| }; |
| |
| new Client(browser); |
| } |
| |
| void PrintToPDF(CefRefPtr<CefBrowser> browser) { |
| if (!CefCurrentlyOn(TID_UI)) { |
| // Execute on the UI thread. |
| CefPostTask(TID_UI, base::Bind(&PrintToPDF, browser)); |
| return; |
| } |
| |
| class Client : public CefPdfPrintCallback, public CefRunFileDialogCallback { |
| public: |
| explicit Client(CefRefPtr<CefBrowser> browser) : browser_(browser) { |
| RunDialog(); |
| } |
| |
| void RunDialog() { |
| static const char kDefaultFileName[] = "output.pdf"; |
| std::string path = MainContext::Get()->GetDownloadPath(kDefaultFileName); |
| if (path.empty()) |
| path = kDefaultFileName; |
| |
| std::vector<CefString> accept_filters; |
| accept_filters.push_back(".pdf"); |
| |
| // Results in a call to OnFileDialogDismissed. |
| browser_->GetHost()->RunFileDialog( |
| static_cast<cef_file_dialog_mode_t>(FILE_DIALOG_SAVE | |
| FILE_DIALOG_OVERWRITEPROMPT_FLAG), |
| CefString(), // title |
| path, accept_filters, |
| 0, // selected_accept_filter |
| this); |
| } |
| |
| void OnFileDialogDismissed( |
| int selected_accept_filter, |
| const std::vector<CefString>& file_paths) OVERRIDE { |
| if (!file_paths.empty()) { |
| CefPdfPrintSettings settings; |
| |
| // Show the URL in the footer. |
| settings.header_footer_enabled = true; |
| CefString(&settings.header_footer_url) = |
| browser_->GetMainFrame()->GetURL(); |
| |
| // Print to the selected PDF file. |
| browser_->GetHost()->PrintToPDF(file_paths[0], settings, this); |
| } |
| } |
| |
| void OnPdfPrintFinished(const CefString& path, bool ok) OVERRIDE { |
| Alert(browser_, "File \"" + path.ToString() + "\" " + |
| (ok ? "saved successfully." : "failed to save.")); |
| } |
| |
| private: |
| CefRefPtr<CefBrowser> browser_; |
| |
| IMPLEMENT_REFCOUNTING(Client); |
| }; |
| |
| new Client(browser); |
| } |
| |
| void MuteAudio(CefRefPtr<CefBrowser> browser, bool mute) { |
| CefRefPtr<CefBrowserHost> host = browser->GetHost(); |
| host->SetAudioMuted(mute); |
| } |
| |
| void RunOtherTests(CefRefPtr<CefBrowser> browser) { |
| browser->GetMainFrame()->LoadURL("http://tests/other_tests"); |
| } |
| |
| // Provider that dumps the request contents. |
| class RequestDumpResourceProvider : public CefResourceManager::Provider { |
| public: |
| explicit RequestDumpResourceProvider(const std::string& url) : url_(url) { |
| DCHECK(!url.empty()); |
| } |
| |
| bool OnRequest(scoped_refptr<CefResourceManager::Request> request) OVERRIDE { |
| CEF_REQUIRE_IO_THREAD(); |
| |
| const std::string& url = request->url(); |
| if (url != url_) { |
| // Not handled by this provider. |
| return false; |
| } |
| |
| CefResponse::HeaderMap response_headers; |
| CefRefPtr<CefStreamReader> response = |
| GetDumpResponse(request->request(), response_headers); |
| |
| request->Continue(new CefStreamResourceHandler(200, "OK", "text/html", |
| response_headers, response)); |
| return true; |
| } |
| |
| private: |
| std::string url_; |
| |
| DISALLOW_COPY_AND_ASSIGN(RequestDumpResourceProvider); |
| }; |
| |
| // Provider that returns string data for specific pages. Used in combination |
| // with LoadStringResourcePage(). |
| class StringResourceProvider : public CefResourceManager::Provider { |
| public: |
| StringResourceProvider(const std::set<std::string>& pages, |
| StringResourceMap* string_resource_map) |
| : pages_(pages), string_resource_map_(string_resource_map) { |
| DCHECK(!pages.empty()); |
| } |
| |
| bool OnRequest(scoped_refptr<CefResourceManager::Request> request) OVERRIDE { |
| CEF_REQUIRE_IO_THREAD(); |
| |
| const std::string& url = request->url(); |
| if (url.find(kTestOrigin) != 0U) { |
| // Not handled by this provider. |
| return false; |
| } |
| |
| const std::string& page = url.substr(strlen(kTestOrigin)); |
| if (pages_.find(page) == pages_.end()) { |
| // Not handled by this provider. |
| return false; |
| } |
| |
| std::string value; |
| StringResourceMap::const_iterator it = string_resource_map_->find(page); |
| if (it != string_resource_map_->end()) { |
| value = it->second; |
| } else { |
| value = "<html><body>No data available</body></html>"; |
| } |
| |
| CefRefPtr<CefStreamReader> response = CefStreamReader::CreateForData( |
| static_cast<void*>(const_cast<char*>(value.c_str())), value.size()); |
| |
| request->Continue(new CefStreamResourceHandler( |
| 200, "OK", "text/html", CefResponse::HeaderMap(), response)); |
| return true; |
| } |
| |
| private: |
| const std::set<std::string> pages_; |
| |
| // Only accessed on the IO thread. |
| StringResourceMap* string_resource_map_; |
| |
| DISALLOW_COPY_AND_ASSIGN(StringResourceProvider); |
| }; |
| |
| // Add a file extension to |url| if none is currently specified. |
| std::string RequestUrlFilter(const std::string& url) { |
| if (url.find(kTestOrigin) != 0U) { |
| // Don't filter anything outside of the test origin. |
| return url; |
| } |
| |
| // Identify where the query or fragment component, if any, begins. |
| size_t suffix_pos = url.find('?'); |
| if (suffix_pos == std::string::npos) |
| suffix_pos = url.find('#'); |
| |
| std::string url_base, url_suffix; |
| if (suffix_pos == std::string::npos) { |
| url_base = url; |
| } else { |
| url_base = url.substr(0, suffix_pos); |
| url_suffix = url.substr(suffix_pos); |
| } |
| |
| // Identify the last path component. |
| size_t path_pos = url_base.rfind('/'); |
| if (path_pos == std::string::npos) |
| return url; |
| |
| const std::string& path_component = url_base.substr(path_pos); |
| |
| // Identify if a file extension is currently specified. |
| size_t ext_pos = path_component.rfind("."); |
| if (ext_pos != std::string::npos) |
| return url; |
| |
| // Rebuild the URL with a file extension. |
| return url_base + ".html" + url_suffix; |
| } |
| |
| } // namespace |
| |
| void RunTest(CefRefPtr<CefBrowser> browser, int id) { |
| if (!browser) |
| return; |
| |
| switch (id) { |
| case ID_TESTS_GETSOURCE: |
| RunGetSourceTest(browser); |
| break; |
| case ID_TESTS_GETTEXT: |
| RunGetTextTest(browser); |
| break; |
| case ID_TESTS_WINDOW_NEW: |
| RunNewWindowTest(browser); |
| break; |
| case ID_TESTS_WINDOW_POPUP: |
| RunPopupWindowTest(browser); |
| break; |
| case ID_TESTS_REQUEST: |
| RunRequestTest(browser); |
| break; |
| case ID_TESTS_PLUGIN_INFO: |
| RunPluginInfoTest(browser); |
| break; |
| case ID_TESTS_ZOOM_IN: |
| ModifyZoom(browser, 0.5); |
| break; |
| case ID_TESTS_ZOOM_OUT: |
| ModifyZoom(browser, -0.5); |
| break; |
| case ID_TESTS_ZOOM_RESET: |
| browser->GetHost()->SetZoomLevel(0.0); |
| break; |
| case ID_TESTS_OSR_FPS: |
| PromptFPS(browser); |
| break; |
| case ID_TESTS_OSR_DSF: |
| PromptDSF(browser); |
| break; |
| case ID_TESTS_TRACING_BEGIN: |
| BeginTracing(); |
| break; |
| case ID_TESTS_TRACING_END: |
| EndTracing(browser); |
| break; |
| case ID_TESTS_PRINT: |
| browser->GetHost()->Print(); |
| break; |
| case ID_TESTS_PRINT_TO_PDF: |
| PrintToPDF(browser); |
| break; |
| case ID_TESTS_MUTE_AUDIO: |
| MuteAudio(browser, true); |
| break; |
| case ID_TESTS_UNMUTE_AUDIO: |
| MuteAudio(browser, false); |
| break; |
| case ID_TESTS_OTHER_TESTS: |
| RunOtherTests(browser); |
| break; |
| } |
| } |
| |
| std::string DumpRequestContents(CefRefPtr<CefRequest> request) { |
| std::stringstream ss; |
| |
| ss << "URL: " << std::string(request->GetURL()); |
| ss << "\nMethod: " << std::string(request->GetMethod()); |
| |
| CefRequest::HeaderMap headerMap; |
| request->GetHeaderMap(headerMap); |
| if (headerMap.size() > 0) { |
| ss << "\nHeaders:"; |
| CefRequest::HeaderMap::const_iterator it = headerMap.begin(); |
| for (; it != headerMap.end(); ++it) { |
| ss << "\n\t" << std::string((*it).first) << ": " |
| << std::string((*it).second); |
| } |
| } |
| |
| CefRefPtr<CefPostData> postData = request->GetPostData(); |
| if (postData.get()) { |
| CefPostData::ElementVector elements; |
| postData->GetElements(elements); |
| if (elements.size() > 0) { |
| ss << "\nPost Data:"; |
| CefRefPtr<CefPostDataElement> element; |
| CefPostData::ElementVector::const_iterator it = elements.begin(); |
| for (; it != elements.end(); ++it) { |
| element = (*it); |
| if (element->GetType() == PDE_TYPE_BYTES) { |
| // the element is composed of bytes |
| ss << "\n\tBytes: "; |
| if (element->GetBytesCount() == 0) { |
| ss << "(empty)"; |
| } else { |
| // retrieve the data. |
| size_t size = element->GetBytesCount(); |
| char* bytes = new char[size]; |
| element->GetBytes(size, bytes); |
| ss << std::string(bytes, size); |
| delete[] bytes; |
| } |
| } else if (element->GetType() == PDE_TYPE_FILE) { |
| ss << "\n\tFile: " << std::string(element->GetFile()); |
| } |
| } |
| } |
| } |
| |
| return ss.str(); |
| } |
| |
| CefRefPtr<CefStreamReader> GetDumpResponse( |
| CefRefPtr<CefRequest> request, |
| CefResponse::HeaderMap& response_headers) { |
| std::string origin; |
| |
| // Extract the origin request header, if any. It will be specified for |
| // cross-origin requests. |
| { |
| CefRequest::HeaderMap requestMap; |
| request->GetHeaderMap(requestMap); |
| |
| CefRequest::HeaderMap::const_iterator it = requestMap.begin(); |
| for (; it != requestMap.end(); ++it) { |
| std::string key = it->first; |
| std::transform(key.begin(), key.end(), key.begin(), ::tolower); |
| if (key == "origin") { |
| origin = it->second; |
| break; |
| } |
| } |
| } |
| |
| if (!origin.empty() && |
| (origin.find("http://" + std::string(kTestHost)) == 0 || |
| origin.find("http://" + std::string(kLocalHost)) == 0)) { |
| // Allow cross-origin XMLHttpRequests from test origins. |
| response_headers.insert( |
| std::make_pair("Access-Control-Allow-Origin", origin)); |
| |
| // Allow the custom header from the xmlhttprequest.html example. |
| response_headers.insert( |
| std::make_pair("Access-Control-Allow-Headers", "My-Custom-Header")); |
| } |
| |
| const std::string& dump = DumpRequestContents(request); |
| std::string str = |
| "<html><body bgcolor=\"white\"><pre>" + dump + "</pre></body></html>"; |
| CefRefPtr<CefStreamReader> stream = CefStreamReader::CreateForData( |
| static_cast<void*>(const_cast<char*>(str.c_str())), str.size()); |
| DCHECK(stream); |
| return stream; |
| } |
| |
| std::string GetDataURI(const std::string& data, const std::string& mime_type) { |
| return "data:" + mime_type + ";base64," + |
| CefURIEncode(CefBase64Encode(data.data(), data.size()), false) |
| .ToString(); |
| } |
| |
| std::string GetErrorString(cef_errorcode_t code) { |
| // Case condition that returns |code| as a string. |
| #define CASE(code) \ |
| case code: \ |
| return #code |
| |
| switch (code) { |
| CASE(ERR_NONE); |
| CASE(ERR_FAILED); |
| CASE(ERR_ABORTED); |
| CASE(ERR_INVALID_ARGUMENT); |
| CASE(ERR_INVALID_HANDLE); |
| CASE(ERR_FILE_NOT_FOUND); |
| CASE(ERR_TIMED_OUT); |
| CASE(ERR_FILE_TOO_BIG); |
| CASE(ERR_UNEXPECTED); |
| CASE(ERR_ACCESS_DENIED); |
| CASE(ERR_NOT_IMPLEMENTED); |
| CASE(ERR_CONNECTION_CLOSED); |
| CASE(ERR_CONNECTION_RESET); |
| CASE(ERR_CONNECTION_REFUSED); |
| CASE(ERR_CONNECTION_ABORTED); |
| CASE(ERR_CONNECTION_FAILED); |
| CASE(ERR_NAME_NOT_RESOLVED); |
| CASE(ERR_INTERNET_DISCONNECTED); |
| CASE(ERR_SSL_PROTOCOL_ERROR); |
| CASE(ERR_ADDRESS_INVALID); |
| CASE(ERR_ADDRESS_UNREACHABLE); |
| CASE(ERR_SSL_CLIENT_AUTH_CERT_NEEDED); |
| CASE(ERR_TUNNEL_CONNECTION_FAILED); |
| CASE(ERR_NO_SSL_VERSIONS_ENABLED); |
| CASE(ERR_SSL_VERSION_OR_CIPHER_MISMATCH); |
| CASE(ERR_SSL_RENEGOTIATION_REQUESTED); |
| CASE(ERR_CERT_COMMON_NAME_INVALID); |
| CASE(ERR_CERT_DATE_INVALID); |
| CASE(ERR_CERT_AUTHORITY_INVALID); |
| CASE(ERR_CERT_CONTAINS_ERRORS); |
| CASE(ERR_CERT_NO_REVOCATION_MECHANISM); |
| CASE(ERR_CERT_UNABLE_TO_CHECK_REVOCATION); |
| CASE(ERR_CERT_REVOKED); |
| CASE(ERR_CERT_INVALID); |
| CASE(ERR_CERT_END); |
| CASE(ERR_INVALID_URL); |
| CASE(ERR_DISALLOWED_URL_SCHEME); |
| CASE(ERR_UNKNOWN_URL_SCHEME); |
| CASE(ERR_TOO_MANY_REDIRECTS); |
| CASE(ERR_UNSAFE_REDIRECT); |
| CASE(ERR_UNSAFE_PORT); |
| CASE(ERR_INVALID_RESPONSE); |
| CASE(ERR_INVALID_CHUNKED_ENCODING); |
| CASE(ERR_METHOD_NOT_SUPPORTED); |
| CASE(ERR_UNEXPECTED_PROXY_AUTH); |
| CASE(ERR_EMPTY_RESPONSE); |
| CASE(ERR_RESPONSE_HEADERS_TOO_BIG); |
| CASE(ERR_CACHE_MISS); |
| CASE(ERR_INSECURE_RESPONSE); |
| default: |
| return "UNKNOWN"; |
| } |
| } |
| |
| void SetupResourceManager(CefRefPtr<CefResourceManager> resource_manager, |
| StringResourceMap* string_resource_map) { |
| if (!CefCurrentlyOn(TID_IO)) { |
| // Execute on the browser IO thread. |
| CefPostTask(TID_IO, base::Bind(SetupResourceManager, resource_manager, |
| string_resource_map)); |
| return; |
| } |
| |
| const std::string& test_origin = kTestOrigin; |
| |
| // Add the URL filter. |
| resource_manager->SetUrlFilter(base::Bind(RequestUrlFilter)); |
| |
| // Add provider for resource dumps. |
| resource_manager->AddProvider( |
| new RequestDumpResourceProvider(test_origin + "request.html"), 0, |
| std::string()); |
| |
| // Set of supported string pages. |
| std::set<std::string> string_pages; |
| string_pages.insert(kTestGetSourcePage); |
| string_pages.insert(kTestGetTextPage); |
| string_pages.insert(kTestPluginInfoPage); |
| |
| // Add provider for string resources. |
| resource_manager->AddProvider( |
| new StringResourceProvider(string_pages, string_resource_map), 0, |
| std::string()); |
| |
| // Add provider for bundled resource files. |
| #if defined(OS_WIN) |
| // Read resources from the binary. |
| resource_manager->AddProvider( |
| CreateBinaryResourceProvider(test_origin, std::string()), 100, |
| std::string()); |
| #elif defined(OS_POSIX) |
| // Read resources from a directory on disk. |
| std::string resource_dir; |
| if (GetResourceDir(resource_dir)) { |
| resource_manager->AddDirectoryProvider(test_origin, resource_dir, 100, |
| std::string()); |
| } |
| #endif |
| } |
| |
| void Alert(CefRefPtr<CefBrowser> browser, const std::string& message) { |
| if (browser->GetHost()->GetExtension()) { |
| // Alerts originating from extension hosts should instead be displayed in |
| // the active browser. |
| browser = MainContext::Get()->GetRootWindowManager()->GetActiveBrowser(); |
| if (!browser) |
| return; |
| } |
| |
| // Escape special characters in the message. |
| std::string msg = StringReplace(message, "\\", "\\\\"); |
| msg = StringReplace(msg, "'", "\\'"); |
| |
| // Execute a JavaScript alert(). |
| CefRefPtr<CefFrame> frame = browser->GetMainFrame(); |
| frame->ExecuteJavaScript("alert('" + msg + "');", frame->GetURL(), 0); |
| } |
| |
| bool IsTestURL(const std::string& url, const std::string& path) { |
| CefURLParts parts; |
| CefParseURL(url, parts); |
| |
| const std::string& url_host = CefString(&parts.host); |
| if (url_host != kTestHost && url_host != kLocalHost) |
| return false; |
| |
| const std::string& url_path = CefString(&parts.path); |
| return url_path.find(path) == 0; |
| } |
| |
| void CreateMessageHandlers(MessageHandlerSet& handlers) { |
| handlers.insert(new PromptHandler); |
| |
| // Create the binding test handlers. |
| binding_test::CreateMessageHandlers(handlers); |
| |
| // Create the dialog test handlers. |
| dialog_test::CreateMessageHandlers(handlers); |
| |
| // Create the drm test handlers. |
| drm_test::CreateMessageHandlers(handlers); |
| |
| // Create the media router test handlers. |
| media_router_test::CreateMessageHandlers(handlers); |
| |
| // Create the preferences test handlers. |
| preferences_test::CreateMessageHandlers(handlers); |
| |
| // Create the server test handlers. |
| server_test::CreateMessageHandlers(handlers); |
| |
| // Create the urlrequest test handlers. |
| urlrequest_test::CreateMessageHandlers(handlers); |
| |
| // Create the window test handlers. |
| window_test::CreateMessageHandlers(handlers); |
| } |
| |
| void RegisterSchemeHandlers() { |
| // Register the scheme handler. |
| scheme_test::RegisterSchemeHandlers(); |
| } |
| |
| CefRefPtr<CefResponseFilter> GetResourceResponseFilter( |
| CefRefPtr<CefBrowser> browser, |
| CefRefPtr<CefFrame> frame, |
| CefRefPtr<CefRequest> request, |
| CefRefPtr<CefResponse> response) { |
| // Create the response filter. |
| return response_filter_test::GetResourceResponseFilter(browser, frame, |
| request, response); |
| } |
| |
| } // namespace test_runner |
| } // namespace client |