text: //###_ORIGINAL D:\projects\cef_binary_3.3163.1671.win32\tests\cefclient\browser//preferences_test.cc
  // 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"
  
  namespace client {
  namespace preferences_test {
  
  //###_BEGIN
  #include "tests/cefclient/myext/mycef_buildconfig.h"
  #if BUILD_TEST
  //###_END
  
  namespace {
  
  const char kTestUrl[] = "http://tests/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.
      std::string url = frame->GetURL();
      if (url.find(kTestUrl) != 0)
        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 NULL;
    }
  
    // 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());
  }
  
  //###_BEGIN
  #else
  void CreateMessageHandlers(test_runner::MessageHandlerSet& handlers) {
  //blank
  }
  #endif //BUILD_TEST
  //###_END
  
  }  // namespace preferences_test
  }  // namespace client
  