mirror of
				https://bitbucket.org/chromiumembedded/cef
				synced 2025-06-05 21:39:12 +02:00 
			
		
		
		
	- Add new API to retrieve/observe configuration values. - cefclient: Add https://tests/config to inspect configuration values in real time.
		
			
				
	
	
		
			913 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			913 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
// 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 <algorithm>
 | 
						|
#include <map>
 | 
						|
#include <set>
 | 
						|
#include <sstream>
 | 
						|
#include <string>
 | 
						|
 | 
						|
#include "include/base/cef_callback.h"
 | 
						|
#include "include/base/cef_dump_without_crashing.h"
 | 
						|
#include "include/cef_parser.h"
 | 
						|
#include "include/cef_task.h"
 | 
						|
#include "include/cef_trace.h"
 | 
						|
#include "include/views/cef_browser_view.h"
 | 
						|
#include "include/wrapper/cef_closure_task.h"
 | 
						|
#include "include/wrapper/cef_stream_resource_handler.h"
 | 
						|
#include "tests/cefclient/browser/base_client_handler.h"
 | 
						|
#include "tests/cefclient/browser/binary_transfer_test.h"
 | 
						|
#include "tests/cefclient/browser/binding_test.h"
 | 
						|
#include "tests/cefclient/browser/config_test.h"
 | 
						|
#include "tests/cefclient/browser/dialog_test.h"
 | 
						|
#include "tests/cefclient/browser/hang_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/task_manager_test.h"
 | 
						|
#include "tests/cefclient/browser/urlrequest_test.h"
 | 
						|
#include "tests/cefclient/browser/window_test.h"
 | 
						|
#include "tests/shared/browser/resource_util.h"
 | 
						|
#include "tests/shared/common/string_util.h"
 | 
						|
 | 
						|
namespace client::test_runner {
 | 
						|
 | 
						|
namespace {
 | 
						|
 | 
						|
const char kTestHost[] = "tests";
 | 
						|
const char kLocalHost[] = "localhost";
 | 
						|
const char kTestOrigin[] = "https://tests/";
 | 
						|
 | 
						|
// Pages handled via StringResourceProvider.
 | 
						|
const char kTestGetSourcePage[] = "get_source.html";
 | 
						|
const char kTestGetTextPage[] = "get_text.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) {
 | 
						|
  BaseClientHandler::GetForBrowser(browser)->SetStringResource(page, data);
 | 
						|
  browser->GetMainFrame()->LoadURL(kTestOrigin + page);
 | 
						|
}
 | 
						|
 | 
						|
void RunGetSourceTest(CefRefPtr<CefBrowser> browser) {
 | 
						|
  class Visitor : public CefStringVisitor {
 | 
						|
   public:
 | 
						|
    explicit Visitor(CefRefPtr<CefBrowser> browser) : browser_(browser) {}
 | 
						|
    void Visit(const CefString& string) override {
 | 
						|
      std::string source = AsciiStrReplace(string, "<", "<");
 | 
						|
      source = AsciiStrReplace(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) {}
 | 
						|
    void Visit(const CefString& string) override {
 | 
						|
      std::string text = AsciiStrReplace(string, "<", "<");
 | 
						|
      text = AsciiStrReplace(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(kTestOrigin) != 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 " + std::string(kTestOrigin) +
 | 
						|
                       " URL. "
 | 
						|
                       "For example, first load Tests > Other Tests.");
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  // Set the request URL
 | 
						|
  request->SetURL(GetTestURL("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) {
 | 
						|
  auto config = std::make_unique<RootWindowConfig>();
 | 
						|
  config->with_controls = true;
 | 
						|
  config->with_osr = browser->GetHost()->IsWindowRenderingDisabled();
 | 
						|
  MainContext::Get()->GetRootWindowManager()->CreateRootWindow(
 | 
						|
      std::move(config));
 | 
						|
}
 | 
						|
 | 
						|
void RunPopupWindowTest(CefRefPtr<CefBrowser> browser) {
 | 
						|
  browser->GetMainFrame()->ExecuteJavaScript(
 | 
						|
      "window.open('https://www.google.com');", "about:blank", 0);
 | 
						|
}
 | 
						|
 | 
						|
void RunDialogWindowTest(CefRefPtr<CefBrowser> browser) {
 | 
						|
  auto browser_view = CefBrowserView::GetForBrowser(browser);
 | 
						|
  if (!browser_view) {
 | 
						|
    LOG(ERROR) << "Dialog windows require Views";
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  auto config = std::make_unique<RootWindowConfig>();
 | 
						|
  config->window_type = WindowType::DIALOG;
 | 
						|
  config->parent_window = browser_view->GetWindow();
 | 
						|
  MainContext::Get()->GetRootWindowManager()->CreateRootWindow(
 | 
						|
      std::move(config));
 | 
						|
}
 | 
						|
 | 
						|
const char kPrompt[] = "Prompt.";
 | 
						|
const char kPromptFPS[] = "FPS";
 | 
						|
const char kPromptDSF[] = "DSF";
 | 
						|
 | 
						|
// Handles execution of prompt results.
 | 
						|
class PromptHandler : public CefMessageRouterBrowserSide::Handler {
 | 
						|
 public:
 | 
						|
  PromptHandler() = default;
 | 
						|
 | 
						|
  // Called due to cefQuery execution.
 | 
						|
  bool OnQuery(CefRefPtr<CefBrowser> browser,
 | 
						|
               CefRefPtr<CefFrame> frame,
 | 
						|
               int64_t 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::BindOnce(&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::BindOnce(&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::BindOnce(&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::BindOnce(&BeginTracing));
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  CefBeginTracing(CefString(), nullptr);
 | 
						|
}
 | 
						|
 | 
						|
void EndTracing(CefRefPtr<CefBrowser> browser) {
 | 
						|
  if (!CefCurrentlyOn(TID_UI)) {
 | 
						|
    // Execute on the UI thread.
 | 
						|
    CefPostTask(TID_UI, base::BindOnce(&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(
 | 
						|
          FILE_DIALOG_SAVE,
 | 
						|
          /*title=*/CefString(), path,
 | 
						|
          /*accept_filters=*/std::vector<CefString>(), this);
 | 
						|
    }
 | 
						|
 | 
						|
    void OnFileDialogDismissed(
 | 
						|
        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::BindOnce(&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(FILE_DIALOG_SAVE,
 | 
						|
                                         /*title=*/CefString(), path,
 | 
						|
                                         accept_filters, this);
 | 
						|
    }
 | 
						|
 | 
						|
    void OnFileDialogDismissed(
 | 
						|
        const std::vector<CefString>& file_paths) override {
 | 
						|
      if (!file_paths.empty()) {
 | 
						|
        CefPdfPrintSettings settings;
 | 
						|
 | 
						|
        // Display a header and footer.
 | 
						|
        settings.display_header_footer = true;
 | 
						|
        CefString(&settings.header_template) =
 | 
						|
            "<div style=\"width: 100%; font-size: 9px; position: relative;\">"
 | 
						|
            "<div style=\"position: absolute; left: 5px;\">"
 | 
						|
            "<span class=\"title\"></span></div>"
 | 
						|
            "</div>";
 | 
						|
        CefString(&settings.footer_template) =
 | 
						|
            "<div style=\"width: 100%; font-size: 9px; position: relative;\">"
 | 
						|
            "<div style=\"position: absolute; left: 5px;\">"
 | 
						|
            "<span class=\"date\"></span></div>"
 | 
						|
            "<div style=\"position: absolute; right: 5px;\">"
 | 
						|
            "<span class=\"pageNumber\"></span>/"
 | 
						|
            "<span class=\"totalPages\"></span></div>"
 | 
						|
            "</div>";
 | 
						|
 | 
						|
        // 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(GetTestURL("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_WINDOW_DIALOG:
 | 
						|
      RunDialogWindowTest(browser);
 | 
						|
      break;
 | 
						|
    case ID_TESTS_REQUEST:
 | 
						|
      RunRequestTest(browser);
 | 
						|
      break;
 | 
						|
    case ID_TESTS_ZOOM_IN:
 | 
						|
      browser->GetHost()->Zoom(CEF_ZOOM_COMMAND_IN);
 | 
						|
      break;
 | 
						|
    case ID_TESTS_ZOOM_OUT:
 | 
						|
      browser->GetHost()->Zoom(CEF_ZOOM_COMMAND_OUT);
 | 
						|
      break;
 | 
						|
    case ID_TESTS_ZOOM_RESET:
 | 
						|
      browser->GetHost()->Zoom(CEF_ZOOM_COMMAND_RESET);
 | 
						|
      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;
 | 
						|
    case ID_TESTS_DUMP_WITHOUT_CRASHING:
 | 
						|
      CefDumpWithoutCrashing();
 | 
						|
      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) {
 | 
						|
      const std::string& key = AsciiStrToLower(it->first);
 | 
						|
      if (key == "origin") {
 | 
						|
        origin = it->second;
 | 
						|
        break;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (!origin.empty() &&
 | 
						|
      (origin.find("https://" + 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 std::to_string(static_cast<int>(code));
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
std::string GetErrorString(cef_termination_status_t status) {
 | 
						|
  switch (status) {
 | 
						|
    case TS_ABNORMAL_TERMINATION:
 | 
						|
      return "ABNORMAL_TERMINATION";
 | 
						|
    case TS_PROCESS_WAS_KILLED:
 | 
						|
      return "PROCESS_WAS_KILLED";
 | 
						|
    case TS_PROCESS_CRASHED:
 | 
						|
      return "PROCESS_CRASHED";
 | 
						|
    case TS_PROCESS_OOM:
 | 
						|
      return "PROCESS_OOM";
 | 
						|
    case TS_LAUNCH_FAILED:
 | 
						|
      return "LAUNCH_FAILED";
 | 
						|
    case TS_INTEGRITY_FAILURE:
 | 
						|
      return "INTEGRITY_FAILURE";
 | 
						|
    case TS_NUM_VALUES:
 | 
						|
      break;
 | 
						|
  }
 | 
						|
  NOTREACHED();
 | 
						|
  return std::string();
 | 
						|
}
 | 
						|
 | 
						|
void SetupResourceManager(CefRefPtr<CefResourceManager> resource_manager,
 | 
						|
                          StringResourceMap* string_resource_map) {
 | 
						|
  if (!CefCurrentlyOn(TID_IO)) {
 | 
						|
    // Execute on the browser IO thread.
 | 
						|
    CefPostTask(TID_IO, base::BindOnce(SetupResourceManager, resource_manager,
 | 
						|
                                       string_resource_map));
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  const std::string& test_origin = kTestOrigin;
 | 
						|
 | 
						|
  // Add the URL filter.
 | 
						|
  resource_manager->SetUrlFilter(base::BindRepeating(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);
 | 
						|
 | 
						|
  if (string_resource_map) {
 | 
						|
    // 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) {
 | 
						|
  // Escape special characters in the message.
 | 
						|
  std::string msg = AsciiStrReplace(message, "\\", "\\\\");
 | 
						|
  msg = AsciiStrReplace(msg, "'", "\\'");
 | 
						|
 | 
						|
  // Execute a JavaScript alert().
 | 
						|
  CefRefPtr<CefFrame> frame = browser->GetMainFrame();
 | 
						|
  frame->ExecuteJavaScript("alert('" + msg + "');", frame->GetURL(), 0);
 | 
						|
}
 | 
						|
 | 
						|
std::string GetTestURL(const std::string& path) {
 | 
						|
  return kTestOrigin + path;
 | 
						|
}
 | 
						|
 | 
						|
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 binary trasfer test handlers.
 | 
						|
  binary_transfer_test::CreateMessageHandlers(handlers);
 | 
						|
 | 
						|
  // Create the binding test handlers.
 | 
						|
  binding_test::CreateMessageHandlers(handlers);
 | 
						|
 | 
						|
  // Create the config test handlers.
 | 
						|
  config_test::CreateMessageHandlers(handlers);
 | 
						|
 | 
						|
  // Create the dialog test handlers.
 | 
						|
  dialog_test::CreateMessageHandlers(handlers);
 | 
						|
 | 
						|
  // Create the hang test handlers.
 | 
						|
  hang_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 task manager handlers.
 | 
						|
  task_manager_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 client::test_runner
 |