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
GetCookiesOnIOThread(const GURL & url,const scoped_refptr<net::URLRequestContextGetter> & context_getter,base::WaitableEvent * event,std::string * cookies)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
GetCanonicalCookiesOnIOThread(const GURL & url,const scoped_refptr<net::URLRequestContextGetter> & context_getter,base::WaitableEvent * event,net::CookieList * cookie_list)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
SetCookieOnIOThread(const GURL & url,const std::string & value,const scoped_refptr<net::URLRequestContextGetter> & context_getter,base::WaitableEvent * event,bool * success)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
SetCookieWithDetailsOnIOThread(const GURL & url,const net::CookieMonster::CanonicalCookie & cookie,const std::string & original_domain,const scoped_refptr<net::URLRequestContextGetter> & context_getter,base::WaitableEvent * event,bool * success)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
DeleteCookieOnIOThread(const GURL & url,const std::string & name,const scoped_refptr<net::URLRequestContextGetter> & context_getter,base::WaitableEvent * event)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
GetBrowserAt(int index)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
GetTabContentsAt(int browser_index,int tab_index)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
GetCookies(const GURL & url,TabContents * contents,int * value_size,std::string * value)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
SetCookie(const GURL & url,const std::string & value,TabContents * contents,int * response_value)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
DeleteCookie(const GURL & url,const std::string & cookie_name,TabContents * contents,bool * success)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
GetCookiesJSON(AutomationProvider * provider,DictionaryValue * args,IPC::Message * reply_message)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
DeleteCookieJSON(AutomationProvider * provider,DictionaryValue * args,IPC::Message * reply_message)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
SetCookieJSON(AutomationProvider * provider,DictionaryValue * args,IPC::Message * reply_message)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