1c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved. 2c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 3c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// found in the LICENSE file. 4c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 5c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/test/chromedriver/capabilities.h" 6c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 7c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include <map> 8c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 9c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/bind.h" 10c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/callback.h" 1158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "base/json/string_escape.h" 1258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "base/logging.h" 13424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "base/strings/string_number_conversions.h" 14424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "base/strings/string_split.h" 15424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "base/strings/string_tokenizer.h" 16868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h" 17868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/stringprintf.h" 1858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "base/strings/utf_string_conversions.h" 19c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/values.h" 20cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "chrome/test/chromedriver/chrome/mobile_device.h" 21c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/test/chromedriver/chrome/status.h" 2258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "chrome/test/chromedriver/logging.h" 23424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "net/base/net_util.h" 24c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 25c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace { 26c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 27c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)typedef base::Callback<Status(const base::Value&, Capabilities*)> Parser; 28c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 29424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)Status ParseBoolean( 30424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) bool* to_set, 3190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) const base::Value& option, 3290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) Capabilities* capabilities) { 33424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) if (!option.GetAsBoolean(to_set)) 3458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return Status(kUnknownError, "must be a boolean"); 35424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) return Status(kOk); 36424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)} 37424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 38424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)Status ParseString(std::string* to_set, 39424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) const base::Value& option, 40424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) Capabilities* capabilities) { 41424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) std::string str; 42424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) if (!option.GetAsString(&str)) 4358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return Status(kUnknownError, "must be a string"); 44424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) if (str.empty()) 4558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return Status(kUnknownError, "cannot be empty"); 46424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) *to_set = str; 4790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return Status(kOk); 4890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 4990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 5003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)Status ParseInterval(int* to_set, 5103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) const base::Value& option, 5203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) Capabilities* capabilities) { 5303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) int parsed_int = 0; 5403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (!option.GetAsInteger(&parsed_int)) 5503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) return Status(kUnknownError, "must be an integer"); 5603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (parsed_int <= 0) 5703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) return Status(kUnknownError, "must be positive"); 5803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) *to_set = parsed_int; 5903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) return Status(kOk); 6003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)} 6103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 6258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)Status ParseFilePath(base::FilePath* to_set, 6358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) const base::Value& option, 6458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) Capabilities* capabilities) { 6558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) base::FilePath::StringType str; 6658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (!option.GetAsString(&str)) 6758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return Status(kUnknownError, "must be a string"); 6858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) *to_set = base::FilePath(str); 69c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch return Status(kOk); 70c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch} 71c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch 7258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)Status ParseDict(scoped_ptr<base::DictionaryValue>* to_set, 7358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) const base::Value& option, 7458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) Capabilities* capabilities) { 7558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) const base::DictionaryValue* dict = NULL; 7658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (!option.GetAsDictionary(&dict)) 7758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return Status(kUnknownError, "must be a dictionary"); 7858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) to_set->reset(dict->DeepCopy()); 79424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) return Status(kOk); 80424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)} 81424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 8258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)Status IgnoreDeprecatedOption( 8358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) const char* option_name, 84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const base::Value& option, 85c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) Capabilities* capabilities) { 8658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) LOG(WARNING) << "Deprecated chrome option is ignored: " << option_name; 8758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return Status(kOk); 8858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 8958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 9058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)Status IgnoreCapability(const base::Value& option, Capabilities* capabilities) { 91c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return Status(kOk); 92c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 93c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 94c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)Status ParseLogPath(const base::Value& option, Capabilities* capabilities) { 95c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!option.GetAsString(&capabilities->log_path)) 9658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return Status(kUnknownError, "must be a string"); 97c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return Status(kOk); 98c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 99c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 100cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)Status ParseDeviceName(std::string device_name, Capabilities* capabilities) { 101cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) scoped_ptr<MobileDevice> device; 102cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) Status status = FindMobileDevice(device_name, &device); 103cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 104cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (status.IsError()) { 105cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return Status(kUnknownError, 106cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) "'" + device_name + "' must be a valid device", 107cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) status); 108cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 109cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 110cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) capabilities->device_metrics.reset(device->device_metrics.release()); 111cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) capabilities->switches.SetSwitch("user-agent", device->user_agent); 112cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 113cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return Status(kOk); 114cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 115cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 116cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)Status ParseMobileEmulation(const base::Value& option, 117cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) Capabilities* capabilities) { 118cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const base::DictionaryValue* mobile_emulation; 119cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (!option.GetAsDictionary(&mobile_emulation)) 120cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return Status(kUnknownError, "'mobileEmulation' must be a dictionary"); 121cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 122cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (mobile_emulation->HasKey("deviceName")) { 123cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Cannot use any other options with deviceName. 124cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (mobile_emulation->size() > 1) 125cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return Status(kUnknownError, "'deviceName' must be used alone"); 126cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 127cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) std::string device_name; 128cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (!mobile_emulation->GetString("deviceName", &device_name)) 129cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return Status(kUnknownError, "'deviceName' must be a string"); 130cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 131cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return ParseDeviceName(device_name, capabilities); 132cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 133cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 134cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (mobile_emulation->HasKey("deviceMetrics")) { 135cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const base::DictionaryValue* metrics; 136cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (!mobile_emulation->GetDictionary("deviceMetrics", &metrics)) 137cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return Status(kUnknownError, "'deviceMetrics' must be a dictionary"); 138cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 139116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch int width = 0; 140116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch int height = 0; 141116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch double device_scale_factor = 0; 142cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (!metrics->GetInteger("width", &width) || 143cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) !metrics->GetInteger("height", &height) || 144cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) !metrics->GetDouble("pixelRatio", &device_scale_factor)) 145cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return Status(kUnknownError, "invalid 'deviceMetrics'"); 146cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 147cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DeviceMetrics* device_metrics = 148cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) new DeviceMetrics(width, height, device_scale_factor); 149cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) capabilities->device_metrics = 150cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) scoped_ptr<DeviceMetrics>(device_metrics); 151cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 152cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 153cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (mobile_emulation->HasKey("userAgent")) { 154cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) std::string user_agent; 155cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (!mobile_emulation->GetString("userAgent", &user_agent)) 156cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return Status(kUnknownError, "'userAgent' must be a string"); 157cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 158cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) capabilities->switches.SetSwitch("user-agent", user_agent); 159cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 160cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 161cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return Status(kOk); 162cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 163cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 16458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)Status ParseSwitches(const base::Value& option, 16558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) Capabilities* capabilities) { 16658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) const base::ListValue* switches_list = NULL; 16758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (!option.GetAsList(&switches_list)) 16858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return Status(kUnknownError, "must be a list"); 16958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) for (size_t i = 0; i < switches_list->GetSize(); ++i) { 170c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) std::string arg_string; 17158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (!switches_list->GetString(i, &arg_string)) 172c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return Status(kUnknownError, "each argument must be a string"); 17358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) capabilities->switches.SetUnparsedSwitch(arg_string); 174c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 175c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return Status(kOk); 176c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 177c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 178c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)Status ParseExtensions(const base::Value& option, Capabilities* capabilities) { 179c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const base::ListValue* extensions = NULL; 180c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!option.GetAsList(&extensions)) 18158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return Status(kUnknownError, "must be a list"); 182c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) for (size_t i = 0; i < extensions->GetSize(); ++i) { 183c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) std::string extension; 184c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!extensions->GetString(i, &extension)) { 185c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return Status(kUnknownError, 186c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) "each extension must be a base64 encoded string"); 187c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 188c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) capabilities->extensions.push_back(extension); 189c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 190c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return Status(kOk); 191c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 192c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 193c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)Status ParseProxy(const base::Value& option, Capabilities* capabilities) { 194c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const base::DictionaryValue* proxy_dict; 195c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!option.GetAsDictionary(&proxy_dict)) 19658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return Status(kUnknownError, "must be a dictionary"); 197c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) std::string proxy_type; 198c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!proxy_dict->GetString("proxyType", &proxy_type)) 199c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return Status(kUnknownError, "'proxyType' must be a string"); 2006e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) proxy_type = base::StringToLowerASCII(proxy_type); 201c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (proxy_type == "direct") { 20258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) capabilities->switches.SetSwitch("no-proxy-server"); 203c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } else if (proxy_type == "system") { 204c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Chrome default. 205c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } else if (proxy_type == "pac") { 206c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) CommandLine::StringType proxy_pac_url; 207c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!proxy_dict->GetString("proxyAutoconfigUrl", &proxy_pac_url)) 208c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return Status(kUnknownError, "'proxyAutoconfigUrl' must be a string"); 20958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) capabilities->switches.SetSwitch("proxy-pac-url", proxy_pac_url); 210c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } else if (proxy_type == "autodetect") { 21158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) capabilities->switches.SetSwitch("proxy-auto-detect"); 212c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } else if (proxy_type == "manual") { 213c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const char* proxy_servers_options[][2] = { 214c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) {"ftpProxy", "ftp"}, {"httpProxy", "http"}, {"sslProxy", "https"}}; 215c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const base::Value* option_value = NULL; 216c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) std::string proxy_servers; 217c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) for (size_t i = 0; i < arraysize(proxy_servers_options); ++i) { 218c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!proxy_dict->Get(proxy_servers_options[i][0], &option_value) || 219c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) option_value->IsType(base::Value::TYPE_NULL)) { 220c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) continue; 221c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 222c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) std::string value; 223c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!option_value->GetAsString(&value)) { 224c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return Status( 225c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) kUnknownError, 226c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) base::StringPrintf("'%s' must be a string", 227c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) proxy_servers_options[i][0])); 228c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 229c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Converts into Chrome proxy scheme. 230c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Example: "http=localhost:9000;ftp=localhost:8000". 231c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!proxy_servers.empty()) 232c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) proxy_servers += ";"; 233c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) proxy_servers += base::StringPrintf( 234c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) "%s=%s", proxy_servers_options[i][1], value.c_str()); 235c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 236c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 237c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) std::string proxy_bypass_list; 238c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (proxy_dict->Get("noProxy", &option_value) && 239c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) !option_value->IsType(base::Value::TYPE_NULL)) { 240c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!option_value->GetAsString(&proxy_bypass_list)) 241c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return Status(kUnknownError, "'noProxy' must be a string"); 242c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 243c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 244c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (proxy_servers.empty() && proxy_bypass_list.empty()) { 245c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return Status(kUnknownError, 246c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) "proxyType is 'manual' but no manual " 247c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) "proxy capabilities were found"); 248c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 249c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!proxy_servers.empty()) 25058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) capabilities->switches.SetSwitch("proxy-server", proxy_servers); 251c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!proxy_bypass_list.empty()) { 25258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) capabilities->switches.SetSwitch("proxy-bypass-list", 25358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) proxy_bypass_list); 254c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 255c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } else { 256c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return Status(kUnknownError, "unrecognized proxy type:" + proxy_type); 257c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 258c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return Status(kOk); 259c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 260c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 2613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)Status ParseExcludeSwitches(const base::Value& option, 2623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) Capabilities* capabilities) { 2633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) const base::ListValue* switches = NULL; 2643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) if (!option.GetAsList(&switches)) 26558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return Status(kUnknownError, "must be a list"); 2663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) for (size_t i = 0; i < switches->GetSize(); ++i) { 2673551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) std::string switch_name; 2683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) if (!switches->GetString(i, &switch_name)) { 2693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) return Status(kUnknownError, 2703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) "each switch to be removed must be a string"); 2713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) } 2723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) capabilities->exclude_switches.insert(switch_name); 2733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) } 2743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) return Status(kOk); 2753551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)} 2763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 277cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)Status ParseUseRemoteBrowser(const base::Value& option, 278424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) Capabilities* capabilities) { 279424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) std::string server_addr; 280424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) if (!option.GetAsString(&server_addr)) 281424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) return Status(kUnknownError, "must be 'host:port'"); 282424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 283424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) std::vector<std::string> values; 284424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) base::SplitString(server_addr, ':', &values); 285424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) if (values.size() != 2) 286424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) return Status(kUnknownError, "must be 'host:port'"); 287424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 288424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) int port = 0; 289424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) base::StringToInt(values[1], &port); 290424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) if (port <= 0) 29158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return Status(kUnknownError, "port must be > 0"); 292424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 29358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) capabilities->debugger_address = NetAddress(values[0], port); 294424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) return Status(kOk); 295424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)} 296424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 297424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)Status ParseLoggingPrefs(const base::Value& option, 298424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) Capabilities* capabilities) { 29958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) const base::DictionaryValue* logging_prefs = NULL; 30058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (!option.GetAsDictionary(&logging_prefs)) 30158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return Status(kUnknownError, "must be a dictionary"); 30258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 30358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) for (base::DictionaryValue::Iterator pref(*logging_prefs); 30458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) !pref.IsAtEnd(); pref.Advance()) { 30558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) std::string type = pref.key(); 30658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) Log::Level level; 30758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) std::string level_name; 30858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (!pref.value().GetAsString(&level_name) || 30958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) !WebDriverLog::NameToLevel(level_name, &level)) { 31058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return Status(kUnknownError, "invalid log level for '" + type + "' log"); 31158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 31258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) capabilities->logging_prefs.insert(std::make_pair(type, level)); 31358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 314424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) return Status(kOk); 315424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)} 316424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 3175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)Status ParseInspectorDomainStatus( 3185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) PerfLoggingPrefs::InspectorDomainStatus* to_set, 3195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const base::Value& option, 3205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) Capabilities* capabilities) { 3215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) bool desired_value; 3225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (!option.GetAsBoolean(&desired_value)) 3235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return Status(kUnknownError, "must be a boolean"); 3245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (desired_value) 3255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) *to_set = PerfLoggingPrefs::InspectorDomainStatus::kExplicitlyEnabled; 3265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) else 3275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) *to_set = PerfLoggingPrefs::InspectorDomainStatus::kExplicitlyDisabled; 3285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return Status(kOk); 3295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 3305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 3315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)Status ParsePerfLoggingPrefs(const base::Value& option, 3325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) Capabilities* capabilities) { 3335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const base::DictionaryValue* perf_logging_prefs = NULL; 3345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (!option.GetAsDictionary(&perf_logging_prefs)) 3355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return Status(kUnknownError, "must be a dictionary"); 3365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 3375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) std::map<std::string, Parser> parser_map; 33803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) parser_map["bufferUsageReportingInterval"] = base::Bind(&ParseInterval, 33903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) &capabilities->perf_logging_prefs.buffer_usage_reporting_interval); 3405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) parser_map["enableNetwork"] = base::Bind( 3415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) &ParseInspectorDomainStatus, &capabilities->perf_logging_prefs.network); 3425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) parser_map["enablePage"] = base::Bind( 3435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) &ParseInspectorDomainStatus, &capabilities->perf_logging_prefs.page); 3445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) parser_map["enableTimeline"] = base::Bind( 3455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) &ParseInspectorDomainStatus, &capabilities->perf_logging_prefs.timeline); 3465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) parser_map["traceCategories"] = base::Bind( 3475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) &ParseString, &capabilities->perf_logging_prefs.trace_categories); 3485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 3495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) for (base::DictionaryValue::Iterator it(*perf_logging_prefs); !it.IsAtEnd(); 3505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) it.Advance()) { 3515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (parser_map.find(it.key()) == parser_map.end()) 3525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return Status(kUnknownError, "unrecognized performance logging " 3535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) "option: " + it.key()); 3545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) Status status = parser_map[it.key()].Run(it.value(), capabilities); 3555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (status.IsError()) 3565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return Status(kUnknownError, "cannot parse " + it.key(), status); 3575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 3585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return Status(kOk); 3595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 3605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 361424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)Status ParseChromeOptions( 362c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const base::Value& capability, 363c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) Capabilities* capabilities) { 364c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const base::DictionaryValue* chrome_options = NULL; 365c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!capability.GetAsDictionary(&chrome_options)) 36658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return Status(kUnknownError, "must be a dictionary"); 367c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 368424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) bool is_android = chrome_options->HasKey("androidPackage"); 369cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) bool is_remote = chrome_options->HasKey("debuggerAddress"); 370c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 371424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) std::map<std::string, Parser> parser_map; 37258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // Ignore 'args', 'binary' and 'extensions' capabilities by default, since the 37358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // Java client always passes them. 37458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) parser_map["args"] = base::Bind(&IgnoreCapability); 375424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) parser_map["binary"] = base::Bind(&IgnoreCapability); 376424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) parser_map["extensions"] = base::Bind(&IgnoreCapability); 3775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 3785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) parser_map["perfLoggingPrefs"] = base::Bind(&ParsePerfLoggingPrefs); 3795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 380424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) if (is_android) { 381424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) parser_map["androidActivity"] = 382424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) base::Bind(&ParseString, &capabilities->android_activity); 383424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) parser_map["androidDeviceSerial"] = 384424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) base::Bind(&ParseString, &capabilities->android_device_serial); 385424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) parser_map["androidPackage"] = 386424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) base::Bind(&ParseString, &capabilities->android_package); 387424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) parser_map["androidProcess"] = 388424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) base::Bind(&ParseString, &capabilities->android_process); 389a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) parser_map["androidUseRunningApp"] = 390a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::Bind(&ParseBoolean, &capabilities->android_use_running_app); 39158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) parser_map["args"] = base::Bind(&ParseSwitches); 3921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci parser_map["excludeSwitches"] = base::Bind(&ParseExcludeSwitches); 3935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) parser_map["loadAsync"] = base::Bind(&IgnoreDeprecatedOption, "loadAsync"); 394cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } else if (is_remote) { 395cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) parser_map["debuggerAddress"] = base::Bind(&ParseUseRemoteBrowser); 396424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) } else { 39758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) parser_map["args"] = base::Bind(&ParseSwitches); 39858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) parser_map["binary"] = base::Bind(&ParseFilePath, &capabilities->binary); 399424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) parser_map["detach"] = base::Bind(&ParseBoolean, &capabilities->detach); 400424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) parser_map["excludeSwitches"] = base::Bind(&ParseExcludeSwitches); 401424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) parser_map["extensions"] = base::Bind(&ParseExtensions); 40258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) parser_map["forceDevToolsScreenshot"] = base::Bind( 40358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) &ParseBoolean, &capabilities->force_devtools_screenshot); 40458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) parser_map["loadAsync"] = base::Bind(&IgnoreDeprecatedOption, "loadAsync"); 40558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) parser_map["localState"] = 40658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) base::Bind(&ParseDict, &capabilities->local_state); 407424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) parser_map["logPath"] = base::Bind(&ParseLogPath); 4081e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) parser_map["minidumpPath"] = 4091e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) base::Bind(&ParseString, &capabilities->minidump_path); 4101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci parser_map["mobileEmulation"] = base::Bind(&ParseMobileEmulation); 41158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) parser_map["prefs"] = base::Bind(&ParseDict, &capabilities->prefs); 412424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) } 413c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 414c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) for (base::DictionaryValue::Iterator it(*chrome_options); !it.IsAtEnd(); 415c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) it.Advance()) { 416c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (parser_map.find(it.key()) == parser_map.end()) { 417c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return Status(kUnknownError, 418c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) "unrecognized chrome option: " + it.key()); 419c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 420c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) Status status = parser_map[it.key()].Run(it.value(), capabilities); 421c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (status.IsError()) 422424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) return Status(kUnknownError, "cannot parse " + it.key(), status); 423c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 424c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return Status(kOk); 425c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 426c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 427c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} // namespace 428c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 42958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)Switches::Switches() {} 43058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 43158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)Switches::~Switches() {} 43258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 43358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void Switches::SetSwitch(const std::string& name) { 43458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) SetSwitch(name, NativeString()); 43558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 43658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 43758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void Switches::SetSwitch(const std::string& name, const std::string& value) { 43858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#if defined(OS_WIN) 4395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) SetSwitch(name, base::UTF8ToUTF16(value)); 44058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#else 44158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) switch_map_[name] = value; 44258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#endif 44358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 44458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 4455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void Switches::SetSwitch(const std::string& name, const base::string16& value) { 44658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#if defined(OS_WIN) 44758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) switch_map_[name] = value; 44858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#else 4495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) SetSwitch(name, base::UTF16ToUTF8(value)); 45058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#endif 45158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 45258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 45358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void Switches::SetSwitch(const std::string& name, const base::FilePath& value) { 45458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) SetSwitch(name, value.value()); 45558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 45658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 45758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void Switches::SetFromSwitches(const Switches& switches) { 45858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) for (SwitchMap::const_iterator iter = switches.switch_map_.begin(); 45958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) iter != switches.switch_map_.end(); 46058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) ++iter) { 46158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) switch_map_[iter->first] = iter->second; 46258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 46358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 46458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 46558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void Switches::SetUnparsedSwitch(const std::string& unparsed_switch) { 46658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) std::string value; 46758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) size_t equals_index = unparsed_switch.find('='); 46858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (equals_index != std::string::npos) 46958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) value = unparsed_switch.substr(equals_index + 1); 47058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 47158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) std::string name; 47258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) size_t start_index = 0; 47358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (unparsed_switch.substr(0, 2) == "--") 47458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) start_index = 2; 47558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) name = unparsed_switch.substr(start_index, equals_index - start_index); 47658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 47758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) SetSwitch(name, value); 47858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 47958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 48058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void Switches::RemoveSwitch(const std::string& name) { 48158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) switch_map_.erase(name); 48258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 48358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 48458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)bool Switches::HasSwitch(const std::string& name) const { 48558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return switch_map_.count(name) > 0; 48658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 48758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 48858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)std::string Switches::GetSwitchValue(const std::string& name) const { 48958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) NativeString value = GetSwitchValueNative(name); 49058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#if defined(OS_WIN) 4915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return base::UTF16ToUTF8(value); 49258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#else 49358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return value; 49458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#endif 49558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 49658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 49758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)Switches::NativeString Switches::GetSwitchValueNative( 49858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) const std::string& name) const { 49958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) SwitchMap::const_iterator iter = switch_map_.find(name); 50058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (iter == switch_map_.end()) 50158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return NativeString(); 50258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return iter->second; 50358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 50458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 50558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)size_t Switches::GetSize() const { 50658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return switch_map_.size(); 50758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 50858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 50958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void Switches::AppendToCommandLine(CommandLine* command) const { 51058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) for (SwitchMap::const_iterator iter = switch_map_.begin(); 51158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) iter != switch_map_.end(); 51258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) ++iter) { 51358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) command->AppendSwitchNative(iter->first, iter->second); 51458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 51558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 51658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 51758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)std::string Switches::ToString() const { 51858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) std::string str; 51958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) SwitchMap::const_iterator iter = switch_map_.begin(); 52058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) while (iter != switch_map_.end()) { 52158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) str += "--" + iter->first; 52258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) std::string value = GetSwitchValue(iter->first); 52358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (value.length()) { 52458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (value.find(' ') != std::string::npos) 5255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) value = base::GetQuotedJSONString(value); 52658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) str += "=" + value; 52758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 52858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) ++iter; 52958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (iter == switch_map_.end()) 53058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) break; 53158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) str += " "; 53258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 53358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return str; 53458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 53558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 5365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)PerfLoggingPrefs::PerfLoggingPrefs() 5375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) : network(InspectorDomainStatus::kDefaultEnabled), 5385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) page(InspectorDomainStatus::kDefaultEnabled), 5395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) timeline(InspectorDomainStatus::kDefaultEnabled), 54003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) trace_categories(), 54103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) buffer_usage_reporting_interval(1000) {} 5425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 5435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)PerfLoggingPrefs::~PerfLoggingPrefs() {} 5445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 54590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)Capabilities::Capabilities() 546a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) : android_use_running_app(false), 547a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) detach(false), 54858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) force_devtools_screenshot(false) {} 549c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 550c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)Capabilities::~Capabilities() {} 551c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 552c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool Capabilities::IsAndroid() const { 553c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return !android_package.empty(); 554c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 555c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 556cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)bool Capabilities::IsRemoteBrowser() const { 55758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return debugger_address.IsValid(); 558424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)} 559424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 56058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)Status Capabilities::Parse(const base::DictionaryValue& desired_caps) { 561c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) std::map<std::string, Parser> parser_map; 56258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) parser_map["chromeOptions"] = base::Bind(&ParseChromeOptions); 563424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) parser_map["loggingPrefs"] = base::Bind(&ParseLoggingPrefs); 564c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) parser_map["proxy"] = base::Bind(&ParseProxy); 565c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) for (std::map<std::string, Parser>::iterator it = parser_map.begin(); 566c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) it != parser_map.end(); ++it) { 567c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const base::Value* capability = NULL; 568c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (desired_caps.Get(it->first, &capability)) { 569424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) Status status = it->second.Run(*capability, this); 570424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) if (status.IsError()) { 571424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) return Status( 572424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) kUnknownError, "cannot parse capability: " + it->first, status); 573424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) } 574c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 575c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 5765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Perf log must be enabled if perf log prefs are specified; otherwise, error. 5775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) LoggingPrefs::const_iterator iter = logging_prefs.find( 5785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) WebDriverLog::kPerformanceType); 5795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (iter == logging_prefs.end() || iter->second == Log::kOff) { 5805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const base::DictionaryValue* chrome_options = NULL; 5815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (desired_caps.GetDictionary("chromeOptions", &chrome_options) && 5825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) chrome_options->HasKey("perfLoggingPrefs")) { 5835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return Status(kUnknownError, "perfLoggingPrefs specified, " 5845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) "but performance logging was not enabled"); 5855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 5865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 587c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return Status(kOk); 588c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 589