mirror of
				https://bitbucket.org/chromiumembedded/cef
				synced 2025-06-05 21:39:12 +02:00 
			
		
		
		
	
		
			
				
	
	
		
			335 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			335 lines
		
	
	
		
			11 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/preferences_test.h"
 | 
						|
 | 
						|
#include <sstream>
 | 
						|
#include <string>
 | 
						|
#include <vector>
 | 
						|
 | 
						|
#include "include/base/cef_logging.h"
 | 
						|
#include "include/cef_command_line.h"
 | 
						|
#include "include/cef_parser.h"
 | 
						|
#include "tests/cefclient/browser/test_runner.h"
 | 
						|
 | 
						|
namespace client {
 | 
						|
namespace preferences_test {
 | 
						|
 | 
						|
namespace {
 | 
						|
 | 
						|
const char kTestUrlPath[] = "/preferences";
 | 
						|
 | 
						|
// Application-specific error codes.
 | 
						|
const int kMessageFormatError = 1;
 | 
						|
const int kPreferenceApplicationError = 1;
 | 
						|
 | 
						|
// Common to all messages.
 | 
						|
const char kNameKey[] = "name";
 | 
						|
const char kNameValueGet[] = "preferences_get";
 | 
						|
const char kNameValueSet[] = "preferences_set";
 | 
						|
const char kNameValueState[] = "preferences_state";
 | 
						|
 | 
						|
// Used with "preferences_get" messages.
 | 
						|
const char kIncludeDefaultsKey[] = "include_defaults";
 | 
						|
 | 
						|
// Used with "preferences_set" messages.
 | 
						|
const char kPreferencesKey[] = "preferences";
 | 
						|
 | 
						|
// Handle messages in the browser process. Only accessed on the UI thread.
 | 
						|
class Handler : public CefMessageRouterBrowserSide::Handler {
 | 
						|
 public:
 | 
						|
  typedef std::vector<std::string> NameVector;
 | 
						|
 | 
						|
  Handler() { CEF_REQUIRE_UI_THREAD(); }
 | 
						|
 | 
						|
  // Called due to cefQuery execution in preferences.html.
 | 
						|
  bool OnQuery(CefRefPtr<CefBrowser> browser,
 | 
						|
               CefRefPtr<CefFrame> frame,
 | 
						|
               int64 query_id,
 | 
						|
               const CefString& request,
 | 
						|
               bool persistent,
 | 
						|
               CefRefPtr<Callback> callback) OVERRIDE {
 | 
						|
    CEF_REQUIRE_UI_THREAD();
 | 
						|
 | 
						|
    // Only handle messages from the test URL.
 | 
						|
    const std::string& url = frame->GetURL();
 | 
						|
    if (!test_runner::IsTestURL(url, kTestUrlPath))
 | 
						|
      return false;
 | 
						|
 | 
						|
    // Parse |request| as a JSON dictionary.
 | 
						|
    CefRefPtr<CefDictionaryValue> request_dict = ParseJSON(request);
 | 
						|
    if (!request_dict) {
 | 
						|
      callback->Failure(kMessageFormatError, "Incorrect message format");
 | 
						|
      return true;
 | 
						|
    }
 | 
						|
 | 
						|
    // Verify the "name" key.
 | 
						|
    if (!VerifyKey(request_dict, kNameKey, VTYPE_STRING, callback))
 | 
						|
      return true;
 | 
						|
 | 
						|
    const std::string& message_name = request_dict->GetString(kNameKey);
 | 
						|
    if (message_name == kNameValueGet) {
 | 
						|
      // JavaScript is requesting a JSON representation of the preferences tree.
 | 
						|
 | 
						|
      // Verify the "include_defaults" key.
 | 
						|
      if (!VerifyKey(request_dict, kIncludeDefaultsKey, VTYPE_BOOL, callback))
 | 
						|
        return true;
 | 
						|
 | 
						|
      const bool include_defaults = request_dict->GetBool(kIncludeDefaultsKey);
 | 
						|
 | 
						|
      OnPreferencesGet(browser, include_defaults, callback);
 | 
						|
 | 
						|
      return true;
 | 
						|
    } else if (message_name == kNameValueSet) {
 | 
						|
      // JavaScript is requesting that preferences be updated to match the
 | 
						|
      // specified JSON representation.
 | 
						|
 | 
						|
      // Verify the "preferences" key.
 | 
						|
      if (!VerifyKey(request_dict, kPreferencesKey, VTYPE_DICTIONARY, callback))
 | 
						|
        return true;
 | 
						|
 | 
						|
      CefRefPtr<CefDictionaryValue> preferences =
 | 
						|
          request_dict->GetDictionary(kPreferencesKey);
 | 
						|
 | 
						|
      OnPreferencesSet(browser, preferences, callback);
 | 
						|
 | 
						|
      return true;
 | 
						|
    } else if (message_name == kNameValueState) {
 | 
						|
      // JavaScript is requesting global state information.
 | 
						|
 | 
						|
      OnPreferencesState(browser, callback);
 | 
						|
 | 
						|
      return true;
 | 
						|
    }
 | 
						|
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
 private:
 | 
						|
  // Execute |callback| with the preferences dictionary as a JSON string.
 | 
						|
  static void OnPreferencesGet(CefRefPtr<CefBrowser> browser,
 | 
						|
                               bool include_defaults,
 | 
						|
                               CefRefPtr<Callback> callback) {
 | 
						|
    CefRefPtr<CefRequestContext> context =
 | 
						|
        browser->GetHost()->GetRequestContext();
 | 
						|
 | 
						|
    // Retrieve all preference values.
 | 
						|
    CefRefPtr<CefDictionaryValue> prefs =
 | 
						|
        context->GetAllPreferences(include_defaults);
 | 
						|
 | 
						|
    // Serialize the preferences to JSON and return to the JavaScript caller.
 | 
						|
    callback->Success(GetJSON(prefs));
 | 
						|
  }
 | 
						|
 | 
						|
  // Set preferences based on the contents of |preferences|. Execute |callback|
 | 
						|
  // with a descriptive result message.
 | 
						|
  static void OnPreferencesSet(CefRefPtr<CefBrowser> browser,
 | 
						|
                               CefRefPtr<CefDictionaryValue> preferences,
 | 
						|
                               CefRefPtr<Callback> callback) {
 | 
						|
    CefRefPtr<CefRequestContext> context =
 | 
						|
        browser->GetHost()->GetRequestContext();
 | 
						|
 | 
						|
    CefRefPtr<CefValue> value = CefValue::Create();
 | 
						|
    value->SetDictionary(preferences);
 | 
						|
 | 
						|
    std::string error;
 | 
						|
    NameVector changed_names;
 | 
						|
 | 
						|
    // Apply preferences. This may result in errors.
 | 
						|
    const bool success =
 | 
						|
        ApplyPrefs(context, std::string(), value, error, changed_names);
 | 
						|
 | 
						|
    // Create a message that accurately represents the result.
 | 
						|
    std::string message;
 | 
						|
    if (!changed_names.empty()) {
 | 
						|
      std::stringstream ss;
 | 
						|
      ss << "Successfully changed " << changed_names.size() << " preferences; ";
 | 
						|
      for (size_t i = 0; i < changed_names.size(); ++i) {
 | 
						|
        ss << changed_names[i];
 | 
						|
        if (i < changed_names.size() - 1)
 | 
						|
          ss << ", ";
 | 
						|
      }
 | 
						|
      message = ss.str();
 | 
						|
    }
 | 
						|
 | 
						|
    if (!success) {
 | 
						|
      DCHECK(!error.empty());
 | 
						|
      if (!message.empty())
 | 
						|
        message += "\n";
 | 
						|
      message += error;
 | 
						|
    }
 | 
						|
 | 
						|
    if (changed_names.empty()) {
 | 
						|
      if (!message.empty())
 | 
						|
        message += "\n";
 | 
						|
      message += "No preferences changed.";
 | 
						|
    }
 | 
						|
 | 
						|
    // Return the message to the JavaScript caller.
 | 
						|
    if (success)
 | 
						|
      callback->Success(message);
 | 
						|
    else
 | 
						|
      callback->Failure(kPreferenceApplicationError, message);
 | 
						|
  }
 | 
						|
 | 
						|
  // Execute |callback| with the global state dictionary as a JSON string.
 | 
						|
  static void OnPreferencesState(CefRefPtr<CefBrowser> browser,
 | 
						|
                                 CefRefPtr<Callback> callback) {
 | 
						|
    CefRefPtr<CefCommandLine> command_line =
 | 
						|
        CefCommandLine::GetGlobalCommandLine();
 | 
						|
 | 
						|
    CefRefPtr<CefDictionaryValue> dict = CefDictionaryValue::Create();
 | 
						|
 | 
						|
    // If spell checking is disabled via the command-line then it cannot be
 | 
						|
    // enabled via preferences.
 | 
						|
    dict->SetBool("spellcheck_disabled",
 | 
						|
                  command_line->HasSwitch("disable-spell-checking"));
 | 
						|
 | 
						|
    // If proxy settings are configured via the command-line then they cannot
 | 
						|
    // be modified via preferences.
 | 
						|
    dict->SetBool("proxy_configured",
 | 
						|
                  command_line->HasSwitch("no-proxy-server") ||
 | 
						|
                      command_line->HasSwitch("proxy-auto-detect") ||
 | 
						|
                      command_line->HasSwitch("proxy-pac-url") ||
 | 
						|
                      command_line->HasSwitch("proxy-server"));
 | 
						|
 | 
						|
    // If allow running insecure content is enabled via the command-line then it
 | 
						|
    // cannot be enabled via preferences.
 | 
						|
    dict->SetBool("allow_running_insecure_content",
 | 
						|
                  command_line->HasSwitch("allow-running-insecure-content"));
 | 
						|
 | 
						|
    // Serialize the state to JSON and return to the JavaScript caller.
 | 
						|
    callback->Success(GetJSON(dict));
 | 
						|
  }
 | 
						|
 | 
						|
  // Convert a JSON string to a dictionary value.
 | 
						|
  static CefRefPtr<CefDictionaryValue> ParseJSON(const CefString& string) {
 | 
						|
    CefRefPtr<CefValue> value = CefParseJSON(string, JSON_PARSER_RFC);
 | 
						|
    if (value.get() && value->GetType() == VTYPE_DICTIONARY)
 | 
						|
      return value->GetDictionary();
 | 
						|
    return nullptr;
 | 
						|
  }
 | 
						|
 | 
						|
  // Convert a dictionary value to a JSON string.
 | 
						|
  static CefString GetJSON(CefRefPtr<CefDictionaryValue> dictionary) {
 | 
						|
    CefRefPtr<CefValue> value = CefValue::Create();
 | 
						|
    value->SetDictionary(dictionary);
 | 
						|
    return CefWriteJSON(value, JSON_WRITER_DEFAULT);
 | 
						|
  }
 | 
						|
 | 
						|
  // Verify that |key| exists in |dictionary| and has type |value_type|. Fails
 | 
						|
  // |callback| and returns false on failure.
 | 
						|
  static bool VerifyKey(CefRefPtr<CefDictionaryValue> dictionary,
 | 
						|
                        const char* key,
 | 
						|
                        cef_value_type_t value_type,
 | 
						|
                        CefRefPtr<Callback> callback) {
 | 
						|
    if (!dictionary->HasKey(key) || dictionary->GetType(key) != value_type) {
 | 
						|
      callback->Failure(
 | 
						|
          kMessageFormatError,
 | 
						|
          "Missing or incorrectly formatted message key: " + std::string(key));
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
  // Apply preferences. Returns true on success. Returns false and sets |error|
 | 
						|
  // to a descriptive error string on failure. |changed_names| is the list of
 | 
						|
  // preferences that were successfully changed.
 | 
						|
  static bool ApplyPrefs(CefRefPtr<CefRequestContext> context,
 | 
						|
                         const std::string& name,
 | 
						|
                         CefRefPtr<CefValue> value,
 | 
						|
                         std::string& error,
 | 
						|
                         NameVector& changed_names) {
 | 
						|
    if (!name.empty() && context->HasPreference(name)) {
 | 
						|
      // The preference exists. Set the value.
 | 
						|
      return SetPref(context, name, value, error, changed_names);
 | 
						|
    }
 | 
						|
 | 
						|
    if (value->GetType() == VTYPE_DICTIONARY) {
 | 
						|
      // A dictionary type value that is not an existing preference. Try to set
 | 
						|
      // each of the elements individually.
 | 
						|
      CefRefPtr<CefDictionaryValue> dict = value->GetDictionary();
 | 
						|
 | 
						|
      CefDictionaryValue::KeyList keys;
 | 
						|
      dict->GetKeys(keys);
 | 
						|
      for (size_t i = 0; i < keys.size(); ++i) {
 | 
						|
        const std::string& key = keys[i];
 | 
						|
        const std::string& current_name = name.empty() ? key : name + "." + key;
 | 
						|
        if (!ApplyPrefs(context, current_name, dict->GetValue(key), error,
 | 
						|
                        changed_names)) {
 | 
						|
          return false;
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      return true;
 | 
						|
    }
 | 
						|
 | 
						|
    error = "Trying to create an unregistered preference: " + name;
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  // Set a specific preference value. Returns true if the value is set
 | 
						|
  // successfully or has not changed. If the value has changed then |name| will
 | 
						|
  // be added to |changed_names|. Returns false and sets |error| to a
 | 
						|
  // descriptive error string on failure.
 | 
						|
  static bool SetPref(CefRefPtr<CefRequestContext> context,
 | 
						|
                      const std::string& name,
 | 
						|
                      CefRefPtr<CefValue> value,
 | 
						|
                      std::string& error,
 | 
						|
                      NameVector& changed_names) {
 | 
						|
    CefRefPtr<CefValue> existing_value = context->GetPreference(name);
 | 
						|
    DCHECK(existing_value);
 | 
						|
 | 
						|
    if (value->GetType() == VTYPE_STRING &&
 | 
						|
        existing_value->GetType() != VTYPE_STRING) {
 | 
						|
      // Since |value| is coming from JSON all basic types will be represented
 | 
						|
      // as strings. Convert to the expected data type.
 | 
						|
      const std::string& string_val = value->GetString();
 | 
						|
      switch (existing_value->GetType()) {
 | 
						|
        case VTYPE_BOOL:
 | 
						|
          if (string_val == "true" || string_val == "1")
 | 
						|
            value->SetBool(true);
 | 
						|
          else if (string_val == "false" || string_val == "0")
 | 
						|
            value->SetBool(false);
 | 
						|
          break;
 | 
						|
        case VTYPE_INT:
 | 
						|
          value->SetInt(atoi(string_val.c_str()));
 | 
						|
          break;
 | 
						|
        case VTYPE_DOUBLE:
 | 
						|
          value->SetInt(atof(string_val.c_str()));
 | 
						|
          break;
 | 
						|
        default:
 | 
						|
          // Other types cannot be converted.
 | 
						|
          break;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    // Nothing to do if the value hasn't changed.
 | 
						|
    if (existing_value->IsEqual(value))
 | 
						|
      return true;
 | 
						|
 | 
						|
    // Attempt to set the preference.
 | 
						|
    CefString error_str;
 | 
						|
    if (!context->SetPreference(name, value, error_str)) {
 | 
						|
      error = error_str.ToString() + ": " + name;
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
 | 
						|
    // The preference was set successfully.
 | 
						|
    changed_names.push_back(name);
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
  DISALLOW_COPY_AND_ASSIGN(Handler);
 | 
						|
};
 | 
						|
 | 
						|
}  // namespace
 | 
						|
 | 
						|
void CreateMessageHandlers(test_runner::MessageHandlerSet& handlers) {
 | 
						|
  handlers.insert(new Handler());
 | 
						|
}
 | 
						|
 | 
						|
}  // namespace preferences_test
 | 
						|
}  // namespace client
 |