1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/automation/automation_provider_json.h" 6 7 #include "base/json/json_writer.h" 8 #include "base/json/string_escape.h" 9 #include "base/values.h" 10 #include "chrome/browser/autocomplete/autocomplete_match.h" 11 #include "chrome/browser/automation/automation_provider.h" 12 #include "chrome/browser/automation/automation_util.h" 13 #include "chrome/browser/extensions/extension_service.h" 14 #include "chrome/browser/extensions/extension_system.h" 15 #include "chrome/browser/profiles/profile.h" 16 #include "chrome/common/automation_id.h" 17 #include "chrome/common/automation_messages.h" 18 #include "chrome/common/extensions/extension.h" 19 #include "content/public/browser/web_contents.h" 20 21 using automation::Error; 22 using automation::ErrorCode; 23 using content::WebContents; 24 25 AutomationJSONReply::AutomationJSONReply(AutomationProvider* provider, 26 IPC::Message* reply_message) 27 : provider_(provider), 28 message_(reply_message) { 29 } 30 31 AutomationJSONReply::~AutomationJSONReply() { 32 DCHECK(!message_) << "JSON automation request not replied!"; 33 } 34 35 void AutomationJSONReply::SendSuccess(const Value* value) { 36 DCHECK(message_) << "Resending reply for JSON automation request"; 37 std::string json_string = "{}"; 38 if (value) 39 base::JSONWriter::Write(value, &json_string); 40 AutomationMsg_SendJSONRequest::WriteReplyParams( 41 message_, json_string, true); 42 provider_->Send(message_); 43 message_ = NULL; 44 } 45 46 void AutomationJSONReply::SendError(const std::string& error_message) { 47 SendError(Error(error_message)); 48 } 49 50 void AutomationJSONReply::SendErrorCode(ErrorCode code) { 51 SendError(Error(code)); 52 } 53 54 void AutomationJSONReply::SendError(const Error& error) { 55 DCHECK(message_) << "Resending reply for JSON automation request"; 56 57 base::DictionaryValue dict; 58 dict.SetString("error", error.message()); 59 dict.SetInteger("code", error.code()); 60 std::string json; 61 base::JSONWriter::Write(&dict, &json); 62 63 AutomationMsg_SendJSONRequest::WriteReplyParams(message_, json, false); 64 provider_->Send(message_); 65 message_ = NULL; 66 } 67 68 bool GetBrowserFromJSONArgs( 69 DictionaryValue* args, 70 Browser** browser, 71 std::string* error) { 72 if (args->HasKey("auto_id")) { 73 AutomationId id; 74 if (!GetAutomationIdFromJSONArgs(args, "auto_id", &id, error)) 75 return false; 76 WebContents* tab; 77 if (!automation_util::GetTabForId(id, &tab)) { 78 *error = "'auto_id' does not refer to an open tab"; 79 return false; 80 } 81 Browser* container = automation_util::GetBrowserForTab(tab); 82 if (!container) { 83 *error = "tab does not belong to an open browser"; 84 return false; 85 } 86 *browser = container; 87 } else { 88 int browser_index; 89 if (!args->GetInteger("windex", &browser_index)) { 90 *error = "'windex' missing or invalid"; 91 return false; 92 } 93 *browser = automation_util::GetBrowserAt(browser_index); 94 if (!*browser) { 95 *error = "Cannot locate browser from given index"; 96 return false; 97 } 98 } 99 return true; 100 } 101 102 bool GetTabFromJSONArgs( 103 DictionaryValue* args, 104 WebContents** tab, 105 std::string* error) { 106 if (args->HasKey("auto_id")) { 107 AutomationId id; 108 if (!GetAutomationIdFromJSONArgs(args, "auto_id", &id, error)) 109 return false; 110 if (!automation_util::GetTabForId(id, tab)) { 111 *error = "'auto_id' does not refer to an open tab"; 112 return false; 113 } 114 } else { 115 int browser_index, tab_index; 116 if (!args->GetInteger("windex", &browser_index)) { 117 *error = "'windex' missing or invalid"; 118 return false; 119 } 120 if (!args->GetInteger("tab_index", &tab_index)) { 121 *error = "'tab_index' missing or invalid"; 122 return false; 123 } 124 *tab = automation_util::GetWebContentsAt(browser_index, tab_index); 125 if (!*tab) { 126 *error = "Cannot locate tab from given indices"; 127 return false; 128 } 129 } 130 return true; 131 } 132 133 bool GetBrowserAndTabFromJSONArgs( 134 DictionaryValue* args, 135 Browser** browser, 136 WebContents** tab, 137 std::string* error) { 138 return GetBrowserFromJSONArgs(args, browser, error) && 139 GetTabFromJSONArgs(args, tab, error); 140 } 141 142 bool GetAutomationIdFromJSONArgs( 143 DictionaryValue* args, 144 const std::string& key, 145 AutomationId* id, 146 std::string* error) { 147 Value* id_value; 148 if (!args->Get(key, &id_value)) { 149 *error = base::StringPrintf("Missing parameter '%s'", key.c_str()); 150 return false; 151 } 152 return AutomationId::FromValue(id_value, id, error); 153 } 154 155 bool GetRenderViewFromJSONArgs( 156 DictionaryValue* args, 157 Profile* profile, 158 content::RenderViewHost** rvh, 159 std::string* error) { 160 Value* id_value; 161 if (args->Get("auto_id", &id_value)) { 162 AutomationId id; 163 if (!AutomationId::FromValue(id_value, &id, error)) 164 return false; 165 if (!automation_util::GetRenderViewForId(id, profile, rvh)) { 166 *error = "ID does not correspond to an open view"; 167 return false; 168 } 169 } else { 170 // If the render view id is not specified, check for browser/tab indices. 171 WebContents* tab = NULL; 172 if (!GetTabFromJSONArgs(args, &tab, error)) 173 return false; 174 *rvh = tab->GetRenderViewHost(); 175 } 176 return true; 177 } 178 179 namespace { 180 181 bool GetExtensionFromJSONArgsHelper( 182 base::DictionaryValue* args, 183 const std::string& key, 184 Profile* profile, 185 bool include_disabled, 186 const extensions::Extension** extension, 187 std::string* error) { 188 std::string id; 189 if (!args->GetString(key, &id)) { 190 *error = base::StringPrintf("Missing or invalid key: %s", key.c_str()); 191 return false; 192 } 193 ExtensionService* service = extensions::ExtensionSystem::Get(profile)-> 194 extension_service(); 195 if (!service) { 196 *error = "No extensions service."; 197 return false; 198 } 199 if (!service->GetInstalledExtension(id)) { 200 // The extension ID does not correspond to any extension, whether crashed 201 // or not. 202 *error = base::StringPrintf("Extension %s is not installed.", 203 id.c_str()); 204 return false; 205 } 206 const extensions::Extension* installed_extension = 207 service->GetExtensionById(id, include_disabled); 208 if (!installed_extension) { 209 *error = "Extension is disabled or has crashed."; 210 return false; 211 } 212 *extension = installed_extension; 213 return true; 214 } 215 216 } // namespace 217 218 bool GetExtensionFromJSONArgs( 219 base::DictionaryValue* args, 220 const std::string& key, 221 Profile* profile, 222 const extensions::Extension** extension, 223 std::string* error) { 224 return GetExtensionFromJSONArgsHelper( 225 args, key, profile, true /* include_disabled */, extension, error); 226 } 227 228 bool GetEnabledExtensionFromJSONArgs( 229 base::DictionaryValue* args, 230 const std::string& key, 231 Profile* profile, 232 const extensions::Extension** extension, 233 std::string* error) { 234 return GetExtensionFromJSONArgsHelper( 235 args, key, profile, false /* include_disabled */, extension, error); 236 } 237