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