Home | History | Annotate | Download | only in automation
      1 // Copyright (c) 2011 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/memory/scoped_ptr.h"
     10 #include "base/time.h"
     11 #include "base/values.h"
     12 #include "chrome/browser/automation/automation_provider.h"
     13 #include "chrome/browser/automation/automation_provider_json.h"
     14 #include "chrome/browser/profiles/profile.h"
     15 #include "chrome/browser/ui/browser.h"
     16 #include "chrome/browser/ui/browser_list.h"
     17 #include "chrome/browser/ui/browser.h"
     18 #include "content/browser/browser_thread.h"
     19 #include "content/browser/renderer_host/browser_render_process_host.h"
     20 #include "content/browser/renderer_host/render_view_host.h"
     21 #include "content/browser/tab_contents/tab_contents.h"
     22 #include "net/base/cookie_monster.h"
     23 #include "net/base/cookie_store.h"
     24 #include "net/url_request/url_request_context.h"
     25 #include "net/url_request/url_request_context_getter.h"
     26 
     27 namespace {
     28 
     29 void GetCookiesOnIOThread(
     30     const GURL& url,
     31     const scoped_refptr<net::URLRequestContextGetter>& context_getter,
     32     base::WaitableEvent* event,
     33     std::string* cookies) {
     34   *cookies =
     35       context_getter->GetURLRequestContext()->cookie_store()->GetCookies(url);
     36   event->Signal();
     37 }
     38 
     39 void GetCanonicalCookiesOnIOThread(
     40     const GURL& url,
     41     const scoped_refptr<net::URLRequestContextGetter>& context_getter,
     42     base::WaitableEvent* event,
     43     net::CookieList* cookie_list) {
     44   *cookie_list =
     45       context_getter->GetURLRequestContext()->cookie_store()->
     46       GetCookieMonster()->GetAllCookiesForURL(url);
     47   event->Signal();
     48 }
     49 
     50 void SetCookieOnIOThread(
     51     const GURL& url,
     52     const std::string& value,
     53     const scoped_refptr<net::URLRequestContextGetter>& context_getter,
     54     base::WaitableEvent* event,
     55     bool* success) {
     56   *success =
     57       context_getter->GetURLRequestContext()->cookie_store()->
     58       SetCookie(url, value);
     59   event->Signal();
     60 }
     61 
     62 void SetCookieWithDetailsOnIOThread(
     63     const GURL& url,
     64     const net::CookieMonster::CanonicalCookie& cookie,
     65     const std::string& original_domain,
     66     const scoped_refptr<net::URLRequestContextGetter>& context_getter,
     67     base::WaitableEvent* event,
     68     bool* success) {
     69   net::CookieMonster* cookie_monster =
     70       context_getter->GetURLRequestContext()->cookie_store()->
     71       GetCookieMonster();
     72   *success = cookie_monster->SetCookieWithDetails(
     73       url, cookie.Name(), cookie.Value(), original_domain,
     74       cookie.Path(), cookie.ExpiryDate(), cookie.IsSecure(),
     75       cookie.IsHttpOnly());
     76   event->Signal();
     77 }
     78 
     79 void DeleteCookieOnIOThread(
     80     const GURL& url,
     81     const std::string& name,
     82     const scoped_refptr<net::URLRequestContextGetter>& context_getter,
     83     base::WaitableEvent* event) {
     84   context_getter->GetURLRequestContext()->cookie_store()->
     85       DeleteCookie(url, name);
     86   event->Signal();
     87 }
     88 
     89 }  // namespace
     90 
     91 namespace automation_util {
     92 
     93 Browser* GetBrowserAt(int index) {
     94   if (index < 0 || index >= static_cast<int>(BrowserList::size()))
     95     return NULL;
     96   return *(BrowserList::begin() + index);
     97 }
     98 
     99 TabContents* GetTabContentsAt(int browser_index, int tab_index) {
    100   if (tab_index < 0)
    101     return NULL;
    102   Browser* browser = GetBrowserAt(browser_index);
    103   if (!browser || tab_index >= browser->tab_count())
    104     return NULL;
    105   return browser->GetTabContentsAt(tab_index);
    106 }
    107 
    108 void GetCookies(const GURL& url,
    109                 TabContents* contents,
    110                 int* value_size,
    111                 std::string* value) {
    112   *value_size = -1;
    113   if (url.is_valid() && contents) {
    114     // Since we may be on the UI thread don't call GetURLRequestContext().
    115     // Get the request context specific to the current TabContents and app.
    116     const Extension* installed_app = static_cast<BrowserRenderProcessHost*>(
    117         contents->render_view_host()->process())->installed_app();
    118     scoped_refptr<net::URLRequestContextGetter> context_getter =
    119         contents->profile()->GetRequestContextForPossibleApp(installed_app);
    120 
    121     base::WaitableEvent event(true /* manual reset */,
    122                               false /* not initially signaled */);
    123     CHECK(BrowserThread::PostTask(
    124               BrowserThread::IO, FROM_HERE,
    125               NewRunnableFunction(&GetCookiesOnIOThread,
    126                                   url, context_getter, &event, value)));
    127     event.Wait();
    128 
    129     *value_size = static_cast<int>(value->size());
    130   }
    131 }
    132 
    133 void SetCookie(const GURL& url,
    134                const std::string& value,
    135                TabContents* contents,
    136                int* response_value) {
    137   *response_value = -1;
    138 
    139   if (url.is_valid() && contents) {
    140     // Since we may be on the UI thread don't call GetURLRequestContext().
    141     // Get the request context specific to the current TabContents and app.
    142     const Extension* installed_app = static_cast<BrowserRenderProcessHost*>(
    143         contents->render_view_host()->process())->installed_app();
    144     scoped_refptr<net::URLRequestContextGetter> context_getter =
    145         contents->profile()->GetRequestContextForPossibleApp(installed_app);
    146 
    147     base::WaitableEvent event(true /* manual reset */,
    148                               false /* not initially signaled */);
    149     bool success = false;
    150     CHECK(BrowserThread::PostTask(
    151               BrowserThread::IO, FROM_HERE,
    152               NewRunnableFunction(&SetCookieOnIOThread,
    153                                   url, value, context_getter, &event,
    154                                   &success)));
    155     event.Wait();
    156     if (success)
    157       *response_value = 1;
    158   }
    159 }
    160 
    161 void DeleteCookie(const GURL& url,
    162                   const std::string& cookie_name,
    163                   TabContents* contents,
    164                   bool* success) {
    165   *success = false;
    166   if (url.is_valid() && contents) {
    167     // Since we may be on the UI thread don't call GetURLRequestContext().
    168     // Get the request context specific to the current TabContents and app.
    169     const Extension* installed_app = static_cast<BrowserRenderProcessHost*>(
    170         contents->render_view_host()->process())->installed_app();
    171     scoped_refptr<net::URLRequestContextGetter> context_getter =
    172         contents->profile()->GetRequestContextForPossibleApp(installed_app);
    173 
    174     base::WaitableEvent event(true /* manual reset */,
    175                               false /* not initially signaled */);
    176     CHECK(BrowserThread::PostTask(
    177               BrowserThread::IO, FROM_HERE,
    178               NewRunnableFunction(&DeleteCookieOnIOThread,
    179                                   url, cookie_name, context_getter, &event)));
    180     event.Wait();
    181     *success = true;
    182   }
    183 }
    184 
    185 void GetCookiesJSON(AutomationProvider* provider,
    186                     DictionaryValue* args,
    187                     IPC::Message* reply_message) {
    188   AutomationJSONReply reply(provider, reply_message);
    189   std::string url;
    190   if (!args->GetString("url", &url)) {
    191     reply.SendError("'url' missing or invalid");
    192     return;
    193   }
    194 
    195   // Since we may be on the UI thread don't call GetURLRequestContext().
    196   scoped_refptr<net::URLRequestContextGetter> context_getter =
    197       provider->profile()->GetRequestContext();
    198 
    199   net::CookieList cookie_list;
    200   base::WaitableEvent event(true /* manual reset */,
    201                             false /* not initially signaled */);
    202   Task* task = NewRunnableFunction(
    203       &GetCanonicalCookiesOnIOThread,
    204       GURL(url), context_getter, &event, &cookie_list);
    205   if (!BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, task)) {
    206     reply.SendError("Couldn't post task to get the cookies");
    207     return;
    208   }
    209   event.Wait();
    210 
    211   ListValue* list = new ListValue();
    212   for (size_t i = 0; i < cookie_list.size(); ++i) {
    213     const net::CookieMonster::CanonicalCookie& cookie = cookie_list[i];
    214     DictionaryValue* cookie_dict = new DictionaryValue();
    215     cookie_dict->SetString("name", cookie.Name());
    216     cookie_dict->SetString("value", cookie.Value());
    217     cookie_dict->SetString("path", cookie.Path());
    218     cookie_dict->SetString("domain", cookie.Domain());
    219     cookie_dict->SetBoolean("secure", cookie.IsSecure());
    220     cookie_dict->SetBoolean("http_only", cookie.IsHttpOnly());
    221     if (cookie.DoesExpire())
    222       cookie_dict->SetDouble("expiry", cookie.ExpiryDate().ToDoubleT());
    223     list->Append(cookie_dict);
    224   }
    225   DictionaryValue dict;
    226   dict.Set("cookies", list);
    227   reply.SendSuccess(&dict);
    228 }
    229 
    230 void DeleteCookieJSON(AutomationProvider* provider,
    231                       DictionaryValue* args,
    232                       IPC::Message* reply_message) {
    233   AutomationJSONReply reply(provider, reply_message);
    234   std::string url, name;
    235   if (!args->GetString("url", &url)) {
    236     reply.SendError("'url' missing or invalid");
    237     return;
    238   }
    239   if (!args->GetString("name", &name)) {
    240     reply.SendError("'name' missing or invalid");
    241     return;
    242   }
    243 
    244   // Since we may be on the UI thread don't call GetURLRequestContext().
    245   scoped_refptr<net::URLRequestContextGetter> context_getter =
    246       provider->profile()->GetRequestContext();
    247 
    248   base::WaitableEvent event(true /* manual reset */,
    249                             false /* not initially signaled */);
    250   Task* task = NewRunnableFunction(
    251       &DeleteCookieOnIOThread,
    252       GURL(url), name, context_getter, &event);
    253   if (!BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, task)) {
    254     reply.SendError("Couldn't post task to delete the cookie");
    255     return;
    256   }
    257   event.Wait();
    258   reply.SendSuccess(NULL);
    259 }
    260 
    261 void SetCookieJSON(AutomationProvider* provider,
    262                    DictionaryValue* args,
    263                    IPC::Message* reply_message) {
    264   AutomationJSONReply reply(provider, reply_message);
    265   std::string url;
    266   if (!args->GetString("url", &url)) {
    267     reply.SendError("'url' missing or invalid");
    268     return;
    269   }
    270   DictionaryValue* cookie_dict;
    271   if (!args->GetDictionary("cookie", &cookie_dict)) {
    272     reply.SendError("'cookie' missing or invalid");
    273     return;
    274   }
    275   std::string name, value;
    276   std::string domain;
    277   std::string path = "/";
    278   bool secure = false;
    279   double expiry = 0;
    280   bool http_only = false;
    281   if (!cookie_dict->GetString("name", &name)) {
    282     reply.SendError("'name' missing or invalid");
    283     return;
    284   }
    285   if (!cookie_dict->GetString("value", &value)) {
    286     reply.SendError("'value' missing or invalid");
    287     return;
    288   }
    289   if (cookie_dict->HasKey("domain") &&
    290       !cookie_dict->GetString("domain", &domain)) {
    291     reply.SendError("optional 'domain' invalid");
    292     return;
    293   }
    294   if (cookie_dict->HasKey("path") &&
    295       !cookie_dict->GetString("path", &path)) {
    296     reply.SendError("optional 'path' invalid");
    297     return;
    298   }
    299   if (cookie_dict->HasKey("secure") &&
    300       !cookie_dict->GetBoolean("secure", &secure)) {
    301     reply.SendError("optional 'secure' invalid");
    302     return;
    303   }
    304   if (cookie_dict->HasKey("expiry")) {
    305     int expiry_int;
    306     if (cookie_dict->GetInteger("expiry", &expiry_int)) {
    307       expiry = expiry_int;
    308     } else if (!cookie_dict->GetDouble("expiry", &expiry)) {
    309       reply.SendError("optional 'expiry' invalid");
    310       return;
    311     }
    312   }
    313   if (cookie_dict->HasKey("http_only") &&
    314       !cookie_dict->GetBoolean("http_only", &http_only)) {
    315     reply.SendError("optional 'http_only' invalid");
    316     return;
    317   }
    318 
    319   scoped_ptr<net::CookieMonster::CanonicalCookie> cookie(
    320       net::CookieMonster::CanonicalCookie::Create(
    321           GURL(url), name, value, domain, path, base::Time(),
    322           base::Time::FromDoubleT(expiry), secure, http_only));
    323   if (!cookie.get()) {
    324     reply.SendError("given 'cookie' parameters are invalid");
    325     return;
    326   }
    327 
    328   // Since we may be on the UI thread don't call GetURLRequestContext().
    329   scoped_refptr<net::URLRequestContextGetter> context_getter =
    330       provider->profile()->GetRequestContext();
    331 
    332   base::WaitableEvent event(true /* manual reset */,
    333                             false /* not initially signaled */);
    334   bool success = false;
    335   Task* task = NewRunnableFunction(
    336       &SetCookieWithDetailsOnIOThread,
    337       GURL(url), *cookie.get(), domain, context_getter, &event, &success);
    338   if (!BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, task)) {
    339     reply.SendError("Couldn't post task to set the cookie");
    340     return;
    341   }
    342   event.Wait();
    343 
    344   if (!success) {
    345     reply.SendError("Could not set the cookie");
    346     return;
    347   }
    348   reply.SendSuccess(NULL);
    349 }
    350 
    351 }  // namespace automation_util
    352