Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / automation / automation_util.cc
blob3627ba8c8fc98c9ea6b30002be733acc43a64cdd
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.
5 #include "chrome/browser/automation/automation_util.h"
7 #include <string>
9 #include "base/bind.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/synchronization/waitable_event.h"
14 #include "base/time/time.h"
15 #include "base/values.h"
16 #include "chrome/browser/automation/automation_provider.h"
17 #include "chrome/browser/automation/automation_provider_json.h"
18 #include "chrome/browser/extensions/extension_service.h"
19 #include "chrome/browser/extensions/extension_system.h"
20 #include "chrome/browser/profiles/profile.h"
21 #include "chrome/browser/sessions/session_id.h"
22 #include "chrome/browser/sessions/session_tab_helper.h"
23 #include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog_queue.h"
24 #include "chrome/browser/ui/browser.h"
25 #include "chrome/browser/ui/browser_iterator.h"
26 #include "chrome/browser/ui/browser_list.h"
27 #include "chrome/browser/ui/host_desktop.h"
28 #include "chrome/browser/ui/tabs/tab_strip_model.h"
29 #include "content/public/browser/browser_thread.h"
30 #include "content/public/browser/render_process_host.h"
31 #include "content/public/browser/render_view_host.h"
32 #include "content/public/browser/web_contents.h"
33 #include "extensions/browser/process_manager.h"
34 #include "extensions/browser/view_type_utils.h"
35 #include "extensions/common/extension.h"
36 #include "net/cookies/canonical_cookie.h"
37 #include "net/cookies/cookie_constants.h"
38 #include "net/cookies/cookie_monster.h"
39 #include "net/cookies/cookie_store.h"
40 #include "net/url_request/url_request_context.h"
41 #include "net/url_request/url_request_context_getter.h"
43 #if defined(OS_CHROMEOS)
44 #include "chrome/browser/chromeos/login/existing_user_controller.h"
45 #include "chrome/browser/chromeos/login/login_display.h"
46 #include "chrome/browser/chromeos/login/login_display_host_impl.h"
47 #include "chrome/browser/chromeos/login/webui_login_display.h"
48 #include "chrome/browser/profiles/profile_manager.h"
49 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
50 #endif
52 using content::BrowserThread;
53 using content::RenderViewHost;
54 using content::WebContents;
56 #if defined(OS_CHROMEOS)
57 using chromeos::ExistingUserController;
58 using chromeos::User;
59 using chromeos::UserManager;
60 #endif
62 namespace {
64 void GetCookiesCallback(base::WaitableEvent* event,
65 std::string* cookies,
66 const std::string& cookie_line) {
67 *cookies = cookie_line;
68 event->Signal();
71 void GetCookiesOnIOThread(
72 const GURL& url,
73 const scoped_refptr<net::URLRequestContextGetter>& context_getter,
74 base::WaitableEvent* event,
75 std::string* cookies) {
76 context_getter->GetURLRequestContext()->cookie_store()->
77 GetCookiesWithOptionsAsync(url, net::CookieOptions(),
78 base::Bind(&GetCookiesCallback, event, cookies));
81 void GetCanonicalCookiesCallback(
82 base::WaitableEvent* event,
83 net::CookieList* cookie_list,
84 const net::CookieList& cookies) {
85 *cookie_list = cookies;
86 event->Signal();
89 void GetCanonicalCookiesOnIOThread(
90 const GURL& url,
91 const scoped_refptr<net::URLRequestContextGetter>& context_getter,
92 base::WaitableEvent* event,
93 net::CookieList* cookie_list) {
94 context_getter->GetURLRequestContext()->cookie_store()->
95 GetCookieMonster()->GetAllCookiesForURLAsync(
96 url,
97 base::Bind(&GetCanonicalCookiesCallback, event, cookie_list));
100 void SetCookieCallback(base::WaitableEvent* event,
101 bool* success,
102 bool result) {
103 *success = result;
104 event->Signal();
107 void SetCookieOnIOThread(
108 const GURL& url,
109 const std::string& value,
110 const scoped_refptr<net::URLRequestContextGetter>& context_getter,
111 base::WaitableEvent* event,
112 bool* success) {
113 context_getter->GetURLRequestContext()->cookie_store()->
114 SetCookieWithOptionsAsync(
115 url, value, net::CookieOptions(),
116 base::Bind(&SetCookieCallback, event, success));
119 void SetCookieWithDetailsOnIOThread(
120 const GURL& url,
121 const net::CanonicalCookie& cookie,
122 const std::string& original_domain,
123 const scoped_refptr<net::URLRequestContextGetter>& context_getter,
124 base::WaitableEvent* event,
125 bool* success) {
126 net::CookieMonster* cookie_monster =
127 context_getter->GetURLRequestContext()->cookie_store()->
128 GetCookieMonster();
129 cookie_monster->SetCookieWithDetailsAsync(
130 url, cookie.Name(), cookie.Value(), original_domain,
131 cookie.Path(), cookie.ExpiryDate(), cookie.IsSecure(),
132 cookie.IsHttpOnly(), cookie.Priority(),
133 base::Bind(&SetCookieCallback, event, success));
136 void DeleteCookieCallback(base::WaitableEvent* event) {
137 event->Signal();
140 void DeleteCookieOnIOThread(
141 const GURL& url,
142 const std::string& name,
143 const scoped_refptr<net::URLRequestContextGetter>& context_getter,
144 base::WaitableEvent* event) {
145 context_getter->GetURLRequestContext()->cookie_store()->
146 DeleteCookieAsync(url, name,
147 base::Bind(&DeleteCookieCallback, event));
150 } // namespace
152 namespace automation_util {
154 Browser* GetBrowserAt(int index) {
155 // The automation layer doesn't support non-native desktops.
156 BrowserList* native_list =
157 BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_NATIVE);
158 if (index < 0 || index >= static_cast<int>(native_list->size()))
159 return NULL;
160 return native_list->get(index);
163 WebContents* GetWebContentsAt(int browser_index, int tab_index) {
164 if (tab_index < 0)
165 return NULL;
166 Browser* browser = GetBrowserAt(browser_index);
167 if (!browser || tab_index >= browser->tab_strip_model()->count())
168 return NULL;
169 return browser->tab_strip_model()->GetWebContentsAt(tab_index);
172 #if defined(OS_CHROMEOS)
173 Profile* GetCurrentProfileOnChromeOS(std::string* error_message) {
174 const UserManager* user_manager = UserManager::Get();
175 if (!user_manager) {
176 *error_message = "No user manager.";
177 return NULL;
179 if (!user_manager->IsUserLoggedIn()) {
180 ExistingUserController* controller =
181 ExistingUserController::current_controller();
182 if (!controller) {
183 *error_message = "Cannot get controller though user is not logged in.";
184 return NULL;
186 chromeos::LoginDisplayHostImpl* webui_host =
187 static_cast<chromeos::LoginDisplayHostImpl*>(
188 controller->login_display_host());
189 content::WebUI* web_ui = webui_host->GetOobeUI()->web_ui();
190 if (!web_ui) {
191 *error_message = "Unable to get webui from login display host.";
192 return NULL;
194 return Profile::FromWebUI(web_ui);
195 } else {
196 return ProfileManager::GetActiveUserProfile();
198 return NULL;
200 #endif // defined(OS_CHROMEOS)
202 Browser* GetBrowserForTab(WebContents* tab) {
203 for (chrome::BrowserIterator it; !it.done(); it.Next()) {
204 Browser* browser = *it;
205 for (int tab_index = 0;
206 tab_index < browser->tab_strip_model()->count();
207 ++tab_index) {
208 if (browser->tab_strip_model()->GetWebContentsAt(tab_index) == tab)
209 return browser;
212 return NULL;
215 net::URLRequestContextGetter* GetRequestContext(WebContents* contents) {
216 // Since we may be on the UI thread don't call GetURLRequestContext().
217 // Get the request context specific to the current WebContents and app.
218 return contents->GetBrowserContext()->GetRequestContextForRenderProcess(
219 contents->GetRenderProcessHost()->GetID());
222 void GetCookies(const GURL& url,
223 WebContents* contents,
224 int* value_size,
225 std::string* value) {
226 *value_size = -1;
227 if (url.is_valid() && contents) {
228 scoped_refptr<net::URLRequestContextGetter> context_getter =
229 GetRequestContext(contents);
230 base::WaitableEvent event(true /* manual reset */,
231 false /* not initially signaled */);
232 CHECK(BrowserThread::PostTask(
233 BrowserThread::IO, FROM_HERE,
234 base::Bind(&GetCookiesOnIOThread, url, context_getter, &event, value)));
235 event.Wait();
237 *value_size = static_cast<int>(value->size());
241 void SetCookie(const GURL& url,
242 const std::string& value,
243 WebContents* contents,
244 int* response_value) {
245 *response_value = -1;
247 if (url.is_valid() && contents) {
248 scoped_refptr<net::URLRequestContextGetter> context_getter =
249 GetRequestContext(contents);
250 base::WaitableEvent event(true /* manual reset */,
251 false /* not initially signaled */);
252 bool success = false;
253 CHECK(BrowserThread::PostTask(
254 BrowserThread::IO, FROM_HERE,
255 base::Bind(&SetCookieOnIOThread, url, value, context_getter, &event,
256 &success)));
257 event.Wait();
258 if (success)
259 *response_value = 1;
263 void DeleteCookie(const GURL& url,
264 const std::string& cookie_name,
265 WebContents* contents,
266 bool* success) {
267 *success = false;
268 if (url.is_valid() && contents) {
269 scoped_refptr<net::URLRequestContextGetter> context_getter =
270 GetRequestContext(contents);
271 base::WaitableEvent event(true /* manual reset */,
272 false /* not initially signaled */);
273 CHECK(BrowserThread::PostTask(
274 BrowserThread::IO, FROM_HERE,
275 base::Bind(&DeleteCookieOnIOThread, url, cookie_name, context_getter,
276 &event)));
277 event.Wait();
278 *success = true;
282 void GetCookiesJSON(AutomationProvider* provider,
283 base::DictionaryValue* args,
284 IPC::Message* reply_message) {
285 AutomationJSONReply reply(provider, reply_message);
286 std::string url;
287 if (!args->GetString("url", &url)) {
288 reply.SendError("'url' missing or invalid");
289 return;
292 // Since we may be on the UI thread don't call GetURLRequestContext().
293 scoped_refptr<net::URLRequestContextGetter> context_getter =
294 provider->profile()->GetRequestContext();
296 net::CookieList cookie_list;
297 base::WaitableEvent event(true /* manual reset */,
298 false /* not initially signaled */);
299 base::Closure task = base::Bind(&GetCanonicalCookiesOnIOThread, GURL(url),
300 context_getter, &event, &cookie_list);
301 if (!BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, task)) {
302 reply.SendError("Couldn't post task to get the cookies");
303 return;
305 event.Wait();
307 base::ListValue* list = new base::ListValue();
308 for (size_t i = 0; i < cookie_list.size(); ++i) {
309 const net::CanonicalCookie& cookie = cookie_list[i];
310 base::DictionaryValue* cookie_dict = new base::DictionaryValue();
311 cookie_dict->SetString("name", cookie.Name());
312 cookie_dict->SetString("value", cookie.Value());
313 cookie_dict->SetString("path", cookie.Path());
314 cookie_dict->SetString("domain", cookie.Domain());
315 cookie_dict->SetBoolean("secure", cookie.IsSecure());
316 cookie_dict->SetBoolean("http_only", cookie.IsHttpOnly());
317 if (cookie.IsPersistent())
318 cookie_dict->SetDouble("expiry", cookie.ExpiryDate().ToDoubleT());
319 if (cookie.Priority() != net::COOKIE_PRIORITY_DEFAULT) {
320 cookie_dict->SetString("priority",
321 net::CookiePriorityToString(cookie.Priority()));
323 list->Append(cookie_dict);
325 base::DictionaryValue dict;
326 dict.Set("cookies", list);
327 reply.SendSuccess(&dict);
330 void DeleteCookieJSON(AutomationProvider* provider,
331 base::DictionaryValue* args,
332 IPC::Message* reply_message) {
333 AutomationJSONReply reply(provider, reply_message);
334 std::string url, name;
335 if (!args->GetString("url", &url)) {
336 reply.SendError("'url' missing or invalid");
337 return;
339 if (!args->GetString("name", &name)) {
340 reply.SendError("'name' missing or invalid");
341 return;
344 // Since we may be on the UI thread don't call GetURLRequestContext().
345 scoped_refptr<net::URLRequestContextGetter> context_getter =
346 provider->profile()->GetRequestContext();
348 base::WaitableEvent event(true /* manual reset */,
349 false /* not initially signaled */);
350 base::Closure task = base::Bind(&DeleteCookieOnIOThread, GURL(url), name,
351 context_getter, &event);
352 if (!BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, task)) {
353 reply.SendError("Couldn't post task to delete the cookie");
354 return;
356 event.Wait();
357 reply.SendSuccess(NULL);
360 void SetCookieJSON(AutomationProvider* provider,
361 base::DictionaryValue* args,
362 IPC::Message* reply_message) {
363 AutomationJSONReply reply(provider, reply_message);
364 std::string url;
365 if (!args->GetString("url", &url)) {
366 reply.SendError("'url' missing or invalid");
367 return;
369 base::DictionaryValue* cookie_dict;
370 if (!args->GetDictionary("cookie", &cookie_dict)) {
371 reply.SendError("'cookie' missing or invalid");
372 return;
374 std::string name, value;
375 std::string domain;
376 std::string path = "/";
377 bool secure = false;
378 double expiry = 0;
379 bool http_only = false;
380 net::CookiePriority priority = net::COOKIE_PRIORITY_DEFAULT;
382 if (!cookie_dict->GetString("name", &name)) {
383 reply.SendError("'name' missing or invalid");
384 return;
386 if (!cookie_dict->GetString("value", &value)) {
387 reply.SendError("'value' missing or invalid");
388 return;
390 if (cookie_dict->HasKey("domain") &&
391 !cookie_dict->GetString("domain", &domain)) {
392 reply.SendError("optional 'domain' invalid");
393 return;
395 if (cookie_dict->HasKey("path") &&
396 !cookie_dict->GetString("path", &path)) {
397 reply.SendError("optional 'path' invalid");
398 return;
400 if (cookie_dict->HasKey("secure") &&
401 !cookie_dict->GetBoolean("secure", &secure)) {
402 reply.SendError("optional 'secure' invalid");
403 return;
405 if (cookie_dict->HasKey("expiry")) {
406 if (!cookie_dict->GetDouble("expiry", &expiry)) {
407 reply.SendError("optional 'expiry' invalid");
408 return;
411 if (cookie_dict->HasKey("http_only") &&
412 !cookie_dict->GetBoolean("http_only", &http_only)) {
413 reply.SendError("optional 'http_only' invalid");
414 return;
416 if (cookie_dict->HasKey("priority")) {
417 std::string priority_string;
418 if (!cookie_dict->GetString("priority", &priority_string)) {
419 reply.SendError("optional 'priority' invalid");
420 return;
422 priority = net::StringToCookiePriority(priority_string);
425 scoped_ptr<net::CanonicalCookie> cookie(
426 net::CanonicalCookie::Create(
427 GURL(url), name, value, domain, path, base::Time(),
428 base::Time::FromDoubleT(expiry), secure, http_only, priority));
429 if (!cookie.get()) {
430 reply.SendError("given 'cookie' parameters are invalid");
431 return;
434 // Since we may be on the UI thread don't call GetURLRequestContext().
435 scoped_refptr<net::URLRequestContextGetter> context_getter =
436 provider->profile()->GetRequestContext();
438 base::WaitableEvent event(true /* manual reset */,
439 false /* not initially signaled */);
440 bool success = false;
441 base::Closure task = base::Bind(
442 &SetCookieWithDetailsOnIOThread, GURL(url), *cookie.get(), domain,
443 context_getter, &event, &success);
444 if (!BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, task)) {
445 reply.SendError("Couldn't post task to set the cookie");
446 return;
448 event.Wait();
450 if (!success) {
451 reply.SendError("Could not set the cookie");
452 return;
454 reply.SendSuccess(NULL);
457 bool SendErrorIfModalDialogActive(AutomationProvider* provider,
458 IPC::Message* message) {
459 bool active = AppModalDialogQueue::GetInstance()->HasActiveDialog();
460 if (active)
461 AutomationJSONReply(provider, message).SendError("Blocked by modal dialog");
462 return active;
465 } // namespace automation_util