#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";
const int kMessageFormatError = 1;
const int kPreferenceApplicationError = 1;
const char kNameKey[] = "name";
const char kNameValueGet[] = "preferences_get";
const char kNameValueSet[] = "preferences_set";
const char kNameValueState[] = "preferences_state";
const char kIncludeDefaultsKey[] = "include_defaults";
const char kPreferencesKey[] = "preferences";
class Handler : public CefMessageRouterBrowserSide::Handler {
public:
typedef std::vector<std::string> NameVector;
Handler() { CEF_REQUIRE_UI_THREAD(); }
bool OnQuery(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
int64 query_id,
const CefString& request,
bool persistent,
CefRefPtr<Callback> callback) override {
CEF_REQUIRE_UI_THREAD();
const std::string& url = frame->GetURL();
if (!test_runner::IsTestURL(url, kTestUrlPath))
return false;
CefRefPtr<CefDictionaryValue> request_dict = ParseJSON(request);
if (!request_dict) {
callback->Failure(kMessageFormatError, "Incorrect message format");
return true;
}
if (!VerifyKey(request_dict, kNameKey, VTYPE_STRING, callback))
return true;
const std::string& message_name = request_dict->GetString(kNameKey);
if (message_name == kNameValueGet) {
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) {
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) {
OnPreferencesState(browser, callback);
return true;
}
return false;
}
private:
static void OnPreferencesGet(CefRefPtr<CefBrowser> browser,
bool include_defaults,
CefRefPtr<Callback> callback) {
CefRefPtr<CefRequestContext> context =
browser->GetHost()->GetRequestContext();
CefRefPtr<CefDictionaryValue> prefs =
context->GetAllPreferences(include_defaults);
callback->Success(GetJSON(prefs));
}
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;
const bool success =
ApplyPrefs(context, std::string(), value, error, changed_names);
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.";
}
if (success)
callback->Success(message);
else
callback->Failure(kPreferenceApplicationError, message);
}
static void OnPreferencesState(CefRefPtr<CefBrowser> browser,
CefRefPtr<Callback> callback) {
CefRefPtr<CefCommandLine> command_line =
CefCommandLine::GetGlobalCommandLine();
CefRefPtr<CefDictionaryValue> dict = CefDictionaryValue::Create();
dict->SetBool("spellcheck_disabled",
command_line->HasSwitch("disable-spell-checking"));
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"));
dict->SetBool("allow_running_insecure_content",
command_line->HasSwitch("allow-running-insecure-content"));
callback->Success(GetJSON(dict));
}
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;
}
static CefString GetJSON(CefRefPtr<CefDictionaryValue> dictionary) {
CefRefPtr<CefValue> value = CefValue::Create();
value->SetDictionary(dictionary);
return CefWriteJSON(value, JSON_WRITER_DEFAULT);
}
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;
}
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)) {
return SetPref(context, name, value, error, changed_names);
}
if (value->GetType() == VTYPE_DICTIONARY) {
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;
}
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) {
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:
break;
}
}
if (existing_value->IsEqual(value))
return true;
CefString error_str;
if (!context->SetPreference(name, value, error_str)) {
error = error_str.ToString() + ": " + name;
return false;
}
changed_names.push_back(name);
return true;
}
DISALLOW_COPY_AND_ASSIGN(Handler);
};
}
void CreateMessageHandlers(test_runner::MessageHandlerSet& handlers) {
handlers.insert(new Handler());
}
}
}