blob: f3290795368b9c11f135e5f695ca5eee0ae9f942 [file] [log] [blame]
// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "cobalt/webdriver/protocol/capabilities.h"
#include "base/memory/scoped_ptr.h"
#include "base/values.h"
#include "cobalt/version.h"
namespace cobalt {
namespace webdriver {
namespace protocol {
namespace {
const char kBrowserNameKey[] = "browserName";
const char kVersionKey[] = "version";
const char kPlatformKey[] = "platform";
const char kJavascriptEnabledKey[] = "javascriptEnabled";
const char kTakesScreenshotKey[] = "takesScreenshot";
const char kHandlesAlertsKey[] = "handlesAlerts";
const char kDatabaseEnabled[] = "databaseEnabled";
const char kLocationContextEnabledKey[] = "locationContextEnabled";
const char kApplicationCacheEnabledKey[] = "applicationCacheEnabled";
const char kBrowserConnectionEnabledKey[] = "browserConnectionEnabled";
const char kCssSelectorsEnabledKey[] = "cssSelectorsEnabled";
const char kWebStorageEnabledKey[] = "webStorageEnabled";
const char kRotatableKey[] = "rotatable";
const char kAcceptSslCertsKey[] = "acceptSslCerts";
const char kNativeEventsKey[] = "nativeEvents";
const char kProxyKey[] = "proxy";
const char kDesiredCapabilitiesKey[] = "desiredCapabilities";
const char kRequiredCapabilitiesKey[] = "requiredCapabilities";
// Helper class for reading from the base::DictionaryValue representing
// capabilities from the client into a Capabilities object.
// This will parse a capability and set its corresponding member in the
// Capabilities object, and then remove the handled capability from the
// source base::DictionaryValue.
class CapabilityReader {
public:
CapabilityReader(Capabilities* capabilities,
base::DictionaryValue* capabilities_value)
: capabilities_(capabilities), capabilities_value_(capabilities_value) {}
template <base::optional<std::string> Capabilities::*member>
void TryReadCapability(const char* key) {
std::string value;
if (capabilities_value_->GetString(key, &value)) {
(capabilities_->*member) = value;
bool removed = capabilities_value_->Remove(key, NULL);
DCHECK(removed);
}
}
template <base::optional<bool> Capabilities::*member>
void TryReadCapability(const char* key) {
bool value;
if (capabilities_value_->GetBoolean(key, &value)) {
(capabilities_->*member) = value;
bool removed = capabilities_value_->Remove(key, NULL);
DCHECK(removed);
}
}
template <typename T, base::optional<T> Capabilities::*member>
void TryReadCapability(const char* key) {
const base::DictionaryValue* dictionary_value;
if (capabilities_value_->GetDictionary(key, &dictionary_value)) {
(capabilities_->*member) = T::FromValue(dictionary_value);
if (capabilities_->*member) {
bool removed = capabilities_value_->Remove(key, NULL);
DCHECK(removed);
}
}
}
private:
Capabilities* capabilities_;
base::DictionaryValue* capabilities_value_;
};
class CapabilityWriter {
public:
CapabilityWriter(const Capabilities& capabilities,
base::DictionaryValue* capabilities_value)
: capabilities_(capabilities), capabilities_value_(capabilities_value) {}
template <base::optional<std::string> Capabilities::*member>
void TryWriteCapability(const char* key) {
if (capabilities_.*member) {
capabilities_value_->SetString(key, (capabilities_.*member).value());
}
}
template <base::optional<bool> Capabilities::*member>
void TryWriteCapability(const char* key) {
if (capabilities_.*member) {
capabilities_value_->SetBoolean(key, (capabilities_.*member).value());
}
}
private:
const Capabilities& capabilities_;
base::DictionaryValue* capabilities_value_;
};
} // namespace
scoped_ptr<base::Value> Capabilities::ToValue(
const Capabilities& capabilities) {
scoped_ptr<base::DictionaryValue> capabilities_value(
new base::DictionaryValue());
CapabilityWriter writer(capabilities, capabilities_value.get());
// Write all the capabilities that have been set.
writer.TryWriteCapability<&Capabilities::browser_name_>(kBrowserNameKey);
writer.TryWriteCapability<&Capabilities::version_>(kVersionKey);
writer.TryWriteCapability<&Capabilities::platform_>(kPlatformKey);
writer.TryWriteCapability<&Capabilities::javascript_enabled_>(
kJavascriptEnabledKey);
writer.TryWriteCapability<&Capabilities::takes_screenshot_>(
kTakesScreenshotKey);
writer.TryWriteCapability<&Capabilities::handles_alerts_>(kHandlesAlertsKey);
writer.TryWriteCapability<&Capabilities::database_enabled_>(kDatabaseEnabled);
writer.TryWriteCapability<&Capabilities::location_context_enabled_>(
kLocationContextEnabledKey);
writer.TryWriteCapability<&Capabilities::application_cache_enabled_>(
kApplicationCacheEnabledKey);
writer.TryWriteCapability<&Capabilities::browser_connection_enabled_>(
kBrowserConnectionEnabledKey);
writer.TryWriteCapability<&Capabilities::css_selectors_enabled_>(
kCssSelectorsEnabledKey);
writer.TryWriteCapability<&Capabilities::web_storage_enabled_>(
kWebStorageEnabledKey);
writer.TryWriteCapability<&Capabilities::rotatable_>(kRotatableKey);
writer.TryWriteCapability<&Capabilities::accept_ssl_certs_>(
kAcceptSslCertsKey);
writer.TryWriteCapability<&Capabilities::native_events_>(kNativeEventsKey);
return capabilities_value.PassAs<base::Value>();
}
base::optional<Capabilities> Capabilities::FromValue(const base::Value* value) {
const base::DictionaryValue* value_as_dictionary;
if (!value->GetAsDictionary(&value_as_dictionary)) {
return base::nullopt;
}
// Create a new Capabilities object, and copy the capabilities dictionary
// from which we will read capabilities
Capabilities capabilities;
scoped_ptr<base::DictionaryValue> capabilities_copy(
value_as_dictionary->DeepCopy());
// Read all the capabilities we know about, and remove handled capabilities
// from the dictionary.
CapabilityReader reader(&capabilities, capabilities_copy.get());
reader.TryReadCapability<&Capabilities::browser_name_>(kBrowserNameKey);
reader.TryReadCapability<&Capabilities::version_>(kVersionKey);
reader.TryReadCapability<&Capabilities::platform_>(kPlatformKey);
reader.TryReadCapability<&Capabilities::javascript_enabled_>(
kJavascriptEnabledKey);
reader.TryReadCapability<&Capabilities::takes_screenshot_>(
kTakesScreenshotKey);
reader.TryReadCapability<&Capabilities::handles_alerts_>(kHandlesAlertsKey);
reader.TryReadCapability<&Capabilities::database_enabled_>(kDatabaseEnabled);
reader.TryReadCapability<&Capabilities::location_context_enabled_>(
kLocationContextEnabledKey);
reader.TryReadCapability<&Capabilities::application_cache_enabled_>(
kApplicationCacheEnabledKey);
reader.TryReadCapability<&Capabilities::browser_connection_enabled_>(
kBrowserConnectionEnabledKey);
reader.TryReadCapability<&Capabilities::css_selectors_enabled_>(
kCssSelectorsEnabledKey);
reader.TryReadCapability<&Capabilities::web_storage_enabled_>(
kWebStorageEnabledKey);
reader.TryReadCapability<&Capabilities::rotatable_>(kRotatableKey);
reader.TryReadCapability<&Capabilities::accept_ssl_certs_>(
kAcceptSslCertsKey);
reader.TryReadCapability<&Capabilities::native_events_>(kNativeEventsKey);
reader.TryReadCapability<Proxy, &Capabilities::proxy_>(kProxyKey);
return capabilities;
}
Capabilities Capabilities::CreateActualCapabilities() {
Capabilities capabilities;
// Set the capabilities that we know we support.
capabilities.browser_name_ = "Cobalt";
capabilities.version_ = COBALT_VERSION;
// TODO: Support platforms other than Linux.
capabilities.platform_ = "Linux";
capabilities.javascript_enabled_ = true;
capabilities.css_selectors_enabled_ = true;
return capabilities;
}
bool Capabilities::AreCapabilitiesSupported() const {
// TODO: Check for unsupported capabilities.
return true;
}
base::optional<RequestedCapabilities> RequestedCapabilities::FromValue(
const base::Value* value) {
DCHECK(value);
const base::DictionaryValue* requested_capabilities_value;
if (!value->GetAsDictionary(&requested_capabilities_value)) {
return base::nullopt;
}
base::optional<Capabilities> desired;
const base::Value* capabilities_value = NULL;
if (requested_capabilities_value->Get(kDesiredCapabilitiesKey,
&capabilities_value)) {
desired = Capabilities::FromValue(capabilities_value);
}
if (!desired) {
// Desired capabilities are required.
return base::nullopt;
}
base::optional<Capabilities> required;
if (requested_capabilities_value->Get(kRequiredCapabilitiesKey,
&capabilities_value)) {
required = Capabilities::FromValue(capabilities_value);
}
if (required) {
return RequestedCapabilities(desired.value(), required.value());
} else {
return RequestedCapabilities(desired.value());
}
}
} // namespace protocol
} // namespace webdriver
} // namespace cobalt