Upstream version 7.35.144.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / automation / automation_util.cc
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_util.h"
6
7 #include <string>
8
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/profiles/profile.h"
20 #include "chrome/browser/sessions/session_id.h"
21 #include "chrome/browser/sessions/session_tab_helper.h"
22 #include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog_queue.h"
23 #include "chrome/browser/ui/browser.h"
24 #include "chrome/browser/ui/browser_iterator.h"
25 #include "chrome/browser/ui/browser_list.h"
26 #include "chrome/browser/ui/host_desktop.h"
27 #include "chrome/browser/ui/tabs/tab_strip_model.h"
28 #include "content/public/browser/browser_thread.h"
29 #include "content/public/browser/render_process_host.h"
30 #include "content/public/browser/render_view_host.h"
31 #include "content/public/browser/web_contents.h"
32 #include "extensions/browser/extension_system.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"
42
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
51
52 using content::BrowserThread;
53 using content::RenderViewHost;
54 using content::WebContents;
55
56 #if defined(OS_CHROMEOS)
57 using chromeos::ExistingUserController;
58 using chromeos::User;
59 using chromeos::UserManager;
60 #endif
61
62 namespace {
63
64 void GetCookiesCallback(base::WaitableEvent* event,
65                         std::string* cookies,
66                         const std::string& cookie_line) {
67   *cookies = cookie_line;
68   event->Signal();
69 }
70
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));
79 }
80
81 void GetCanonicalCookiesCallback(
82     base::WaitableEvent* event,
83     net::CookieList* cookie_list,
84     const net::CookieList& cookies) {
85   *cookie_list = cookies;
86   event->Signal();
87 }
88
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));
98 }
99
100 void SetCookieCallback(base::WaitableEvent* event,
101                        bool* success,
102                        bool result) {
103   *success = result;
104   event->Signal();
105 }
106
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));
117 }
118
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));
134 }
135
136 void DeleteCookieCallback(base::WaitableEvent* event) {
137   event->Signal();
138 }
139
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));
148 }
149
150 }  // namespace
151
152 namespace automation_util {
153
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);
161 }
162
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);
170 }
171
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;
178   }
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;
185     }
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;
193     }
194     return Profile::FromWebUI(web_ui);
195   } else {
196     return ProfileManager::GetActiveUserProfile();
197   }
198   return NULL;
199 }
200 #endif  // defined(OS_CHROMEOS)
201
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;
210     }
211   }
212   return NULL;
213 }
214
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());
220 }
221
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();
236
237     *value_size = static_cast<int>(value->size());
238   }
239 }
240
241 void SetCookie(const GURL& url,
242                const std::string& value,
243                WebContents* contents,
244                int* response_value) {
245   *response_value = -1;
246
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;
260   }
261 }
262
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;
279   }
280 }
281
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;
290   }
291
292   // Since we may be on the UI thread don't call GetURLRequestContext().
293   scoped_refptr<net::URLRequestContextGetter> context_getter =
294       provider->profile()->GetRequestContext();
295
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;
304   }
305   event.Wait();
306
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()));
322     }
323     list->Append(cookie_dict);
324   }
325   base::DictionaryValue dict;
326   dict.Set("cookies", list);
327   reply.SendSuccess(&dict);
328 }
329
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;
338   }
339   if (!args->GetString("name", &name)) {
340     reply.SendError("'name' missing or invalid");
341     return;
342   }
343
344   // Since we may be on the UI thread don't call GetURLRequestContext().
345   scoped_refptr<net::URLRequestContextGetter> context_getter =
346       provider->profile()->GetRequestContext();
347
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;
355   }
356   event.Wait();
357   reply.SendSuccess(NULL);
358 }
359
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;
368   }
369   base::DictionaryValue* cookie_dict;
370   if (!args->GetDictionary("cookie", &cookie_dict)) {
371     reply.SendError("'cookie' missing or invalid");
372     return;
373   }
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;
381
382   if (!cookie_dict->GetString("name", &name)) {
383     reply.SendError("'name' missing or invalid");
384     return;
385   }
386   if (!cookie_dict->GetString("value", &value)) {
387     reply.SendError("'value' missing or invalid");
388     return;
389   }
390   if (cookie_dict->HasKey("domain") &&
391       !cookie_dict->GetString("domain", &domain)) {
392     reply.SendError("optional 'domain' invalid");
393     return;
394   }
395   if (cookie_dict->HasKey("path") &&
396       !cookie_dict->GetString("path", &path)) {
397     reply.SendError("optional 'path' invalid");
398     return;
399   }
400   if (cookie_dict->HasKey("secure") &&
401       !cookie_dict->GetBoolean("secure", &secure)) {
402     reply.SendError("optional 'secure' invalid");
403     return;
404   }
405   if (cookie_dict->HasKey("expiry")) {
406     if (!cookie_dict->GetDouble("expiry", &expiry)) {
407       reply.SendError("optional 'expiry' invalid");
408       return;
409     }
410   }
411   if (cookie_dict->HasKey("http_only") &&
412       !cookie_dict->GetBoolean("http_only", &http_only)) {
413     reply.SendError("optional 'http_only' invalid");
414     return;
415   }
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;
421     }
422     priority = net::StringToCookiePriority(priority_string);
423   }
424
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;
432   }
433
434   // Since we may be on the UI thread don't call GetURLRequestContext().
435   scoped_refptr<net::URLRequestContextGetter> context_getter =
436       provider->profile()->GetRequestContext();
437
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;
447   }
448   event.Wait();
449
450   if (!success) {
451     reply.SendError("Could not set the cookie");
452     return;
453   }
454   reply.SendSuccess(NULL);
455 }
456
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;
463 }
464
465 }  // namespace automation_util