Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(69)

Side by Side Diff: chrome/browser/extensions/extension_cookies_api.cc

Issue 2756003: Make CookieMonster NonThreadSafe. (Closed) Base URL: http://src.chromium.org/git/chromium.git
Patch Set: Address eroman's and cindylau's comments. Created 10 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 // Implements the Chrome Extensions Cookies API. 5 // Implements the Chrome Extensions Cookies API.
6 6
7 #include "chrome/browser/extensions/extension_cookies_api.h" 7 #include "chrome/browser/extensions/extension_cookies_api.h"
8 8
9 #include "base/json/json_writer.h" 9 #include "base/json/json_writer.h"
10 #include "base/task.h"
10 #include "chrome/browser/browser_list.h" 11 #include "chrome/browser/browser_list.h"
12 #include "chrome/browser/chrome_thread.h"
11 #include "chrome/browser/extensions/extension_cookies_api_constants.h" 13 #include "chrome/browser/extensions/extension_cookies_api_constants.h"
12 #include "chrome/browser/extensions/extension_cookies_helpers.h" 14 #include "chrome/browser/extensions/extension_cookies_helpers.h"
13 #include "chrome/browser/extensions/extension_message_service.h" 15 #include "chrome/browser/extensions/extension_message_service.h"
14 #include "chrome/browser/profile.h" 16 #include "chrome/browser/profile.h"
15 #include "chrome/common/extensions/extension_error_utils.h" 17 #include "chrome/common/extensions/extension_error_utils.h"
16 #include "chrome/common/net/url_request_context_getter.h" 18 #include "chrome/common/net/url_request_context_getter.h"
17 #include "chrome/common/notification_type.h" 19 #include "chrome/common/notification_type.h"
18 #include "chrome/common/notification_service.h" 20 #include "chrome/common/notification_service.h"
19 #include "net/base/cookie_monster.h" 21 #include "net/base/cookie_monster.h"
20 22
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
93 // Check against host permissions if needed. 95 // Check against host permissions if needed.
94 if (check_host_permissions && 96 if (check_host_permissions &&
95 !GetExtension()->HasHostPermission(*url)) { 97 !GetExtension()->HasHostPermission(*url)) {
96 error_ = ExtensionErrorUtils::FormatErrorMessage( 98 error_ = ExtensionErrorUtils::FormatErrorMessage(
97 keys::kNoHostPermissionsError, url->spec()); 99 keys::kNoHostPermissionsError, url->spec());
98 return false; 100 return false;
99 } 101 }
100 return true; 102 return true;
101 } 103 }
102 104
103 bool CookiesFunction::ParseCookieStore(const DictionaryValue* details, 105 bool CookiesFunction::ParseStoreContext(const DictionaryValue* details,
104 net::CookieStore** store, 106 URLRequestContextGetter** context,
105 std::string* store_id) { 107 std::string* store_id) {
106 DCHECK(details && (store || store_id)); 108 DCHECK(details && (context || store_id));
107 Profile* store_profile = NULL; 109 Profile* store_profile = NULL;
108 if (details->HasKey(keys::kStoreIdKey)) { 110 if (details->HasKey(keys::kStoreIdKey)) {
109 // The store ID was explicitly specified in the details dictionary. 111 // The store ID was explicitly specified in the details dictionary.
110 // Retrieve its corresponding cookie store. 112 // Retrieve its corresponding cookie store.
111 std::string store_id_value; 113 std::string store_id_value;
112 // Get the store ID string or return false. 114 // Get the store ID string or return false.
113 EXTENSION_FUNCTION_VALIDATE( 115 EXTENSION_FUNCTION_VALIDATE(
114 details->GetString(keys::kStoreIdKey, &store_id_value)); 116 details->GetString(keys::kStoreIdKey, &store_id_value));
115 store_profile = extension_cookies_helpers::ChooseProfileFromStoreId( 117 store_profile = extension_cookies_helpers::ChooseProfileFromStoreId(
116 store_id_value, profile(), include_incognito()); 118 store_id_value, profile(), include_incognito());
117 if (!store_profile) { 119 if (!store_profile) {
118 error_ = ExtensionErrorUtils::FormatErrorMessage( 120 error_ = ExtensionErrorUtils::FormatErrorMessage(
119 keys::kInvalidStoreIdError, store_id_value); 121 keys::kInvalidStoreIdError, store_id_value);
120 return false; 122 return false;
121 } 123 }
122 } else { 124 } else {
123 // The store ID was not specified; use the current execution context's 125 // The store ID was not specified; use the current execution context's
124 // cookie store by default. 126 // cookie store by default.
125 // GetCurrentBrowser() already takes into account incognito settings. 127 // GetCurrentBrowser() already takes into account incognito settings.
126 Browser* current_browser = GetCurrentBrowser(); 128 Browser* current_browser = GetCurrentBrowser();
127 if (!current_browser) { 129 if (!current_browser) {
128 error_ = keys::kNoCookieStoreFoundError; 130 error_ = keys::kNoCookieStoreFoundError;
129 return false; 131 return false;
130 } 132 }
131 store_profile = current_browser->profile(); 133 store_profile = current_browser->profile();
132 } 134 }
133 DCHECK(store_profile); 135 DCHECK(store_profile);
134 if (store) 136
135 *store = store_profile->GetRequestContext()->GetCookieStore(); 137 if (context)
138 *context = store_profile->GetRequestContext();
136 if (store_id) 139 if (store_id)
137 *store_id = 140 *store_id = extension_cookies_helpers::GetStoreIdFromProfile(store_profile);
138 extension_cookies_helpers::GetStoreIdFromProfile(store_profile); 141
139 return true; 142 return true;
140 } 143 }
141 144
145 GetCookieFunction::GetCookieFunction() {}
146
142 bool GetCookieFunction::RunImpl() { 147 bool GetCookieFunction::RunImpl() {
143 // Return false if the arguments are malformed. 148 // Return false if the arguments are malformed.
144 DictionaryValue* details; 149 DictionaryValue* details;
145 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &details)); 150 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &details));
146 DCHECK(details); 151 DCHECK(details);
147 152
148 // Read/validate input parameters. 153 // Read/validate input parameters.
149 GURL url; 154 if (!ParseUrl(details, &url_, true))
150 if (!ParseUrl(details, &url, true))
151 return false; 155 return false;
152 156
153 std::string name;
154 // Get the cookie name string or return false. 157 // Get the cookie name string or return false.
155 EXTENSION_FUNCTION_VALIDATE(details->GetString(keys::kNameKey, &name)); 158 EXTENSION_FUNCTION_VALIDATE(details->GetString(keys::kNameKey, &name_));
156 159
157 net::CookieStore* cookie_store; 160 URLRequestContextGetter* store_context = NULL;
158 std::string store_id; 161 if (!ParseStoreContext(details, &store_context, &store_id_))
159 if (!ParseCookieStore(details, &cookie_store, &store_id))
160 return false; 162 return false;
161 DCHECK(cookie_store && !store_id.empty());
162 163
163 net::CookieMonster::CookieList cookie_list = 164 DCHECK(store_context && !store_id_.empty());
164 extension_cookies_helpers::GetCookieListFromStore(cookie_store, url); 165 store_context_ = store_context;
166
167 bool rv = ChromeThread::PostTask(
168 ChromeThread::IO, FROM_HERE,
169 NewRunnableMethod(this, &GetCookieFunction::GetCookieOnIOThread));
170 DCHECK(rv);
171
172 // Will finish asynchronously.
173 return true;
174 }
175
176 void GetCookieFunction::GetCookieOnIOThread() {
177 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
178 net::CookieStore* cookie_store = store_context_->GetCookieStore();
179 cookie_list_ =
180 extension_cookies_helpers::GetCookieListFromStore(cookie_store, url_);
181
182 bool rv = ChromeThread::PostTask(
183 ChromeThread::UI, FROM_HERE,
184 NewRunnableMethod(this, &GetCookieFunction::RespondOnUIThread));
185 DCHECK(rv);
186 }
187
188 void GetCookieFunction::RespondOnUIThread() {
189 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
190
165 net::CookieMonster::CookieList::iterator it; 191 net::CookieMonster::CookieList::iterator it;
166 for (it = cookie_list.begin(); it != cookie_list.end(); ++it) { 192 for (it = cookie_list_.begin(); it != cookie_list_.end(); ++it) {
167 // Return the first matching cookie. Relies on the fact that the 193 // Return the first matching cookie. Relies on the fact that the
168 // CookieMonster retrieves them in reverse domain-length order. 194 // CookieMonster retrieves them in reverse domain-length order.
169 const net::CookieMonster::CanonicalCookie& cookie = it->second; 195 const net::CookieMonster::CanonicalCookie& cookie = it->second;
170 if (cookie.Name() == name) { 196 if (cookie.Name() == name_) {
171 result_.reset( 197 result_.reset(
172 extension_cookies_helpers::CreateCookieValue(*it, store_id)); 198 extension_cookies_helpers::CreateCookieValue(*it, store_id_));
173 return true; 199 break;
174 } 200 }
175 } 201 }
202
176 // The cookie doesn't exist; return null. 203 // The cookie doesn't exist; return null.
177 result_.reset(Value::CreateNullValue()); 204 if (it == cookie_list_.end())
205 result_.reset(Value::CreateNullValue());
206
207 SendResponse(true);
208 }
209
210 GetAllCookiesFunction::GetAllCookiesFunction() {}
211
212 bool GetAllCookiesFunction::RunImpl() {
213 // Return false if the arguments are malformed.
214 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &details_));
215 DCHECK(details_);
216
217 // Read/validate input parameters.
218 if (details_->HasKey(keys::kUrlKey) && !ParseUrl(details_, &url_, false))
219 return false;
220
221 URLRequestContextGetter* store_context = NULL;
222 if (!ParseStoreContext(details_, &store_context, &store_id_))
223 return false;
224 DCHECK(store_context);
225 store_context_ = store_context;
226
227 bool rv = ChromeThread::PostTask(
228 ChromeThread::IO, FROM_HERE,
229 NewRunnableMethod(this, &GetAllCookiesFunction::GetAllCookiesOnIOThread));
230 DCHECK(rv);
231
232 // Will finish asynchronously.
178 return true; 233 return true;
179 } 234 }
180 235
181 bool GetAllCookiesFunction::RunImpl() { 236 void GetAllCookiesFunction::GetAllCookiesOnIOThread() {
182 // Return false if the arguments are malformed. 237 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
183 DictionaryValue* details; 238 net::CookieStore* cookie_store = store_context_->GetCookieStore();
184 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &details)); 239 cookie_list_ =
185 DCHECK(details); 240 extension_cookies_helpers::GetCookieListFromStore(cookie_store, url_);
186 241
187 // Read/validate input parameters. 242 bool rv = ChromeThread::PostTask(
188 GURL url; 243 ChromeThread::UI, FROM_HERE,
189 if (details->HasKey(keys::kUrlKey) && !ParseUrl(details, &url, false)) 244 NewRunnableMethod(this, &GetAllCookiesFunction::RespondOnUIThread));
190 return false; 245 DCHECK(rv);
246 }
191 247
192 net::CookieStore* cookie_store; 248 void GetAllCookiesFunction::RespondOnUIThread() {
193 std::string store_id; 249 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
194 if (!ParseCookieStore(details, &cookie_store, &store_id))
195 return false;
196 DCHECK(cookie_store);
197 250
198 ListValue* matching_list = new ListValue(); 251 const Extension* extension = GetExtension();
199 extension_cookies_helpers::AppendMatchingCookiesToList( 252 if (extension) {
200 cookie_store, store_id, url, details, GetExtension(), matching_list); 253 ListValue* matching_list = new ListValue();
201 result_.reset(matching_list); 254 extension_cookies_helpers::AppendMatchingCookiesToList(
202 return true; 255 cookie_list_, store_id_, url_, details_, GetExtension(), matching_list);
256 result_.reset(matching_list);
257 }
258 SendResponse(true);
203 } 259 }
204 260
261 SetCookieFunction::SetCookieFunction() : secure_(false), http_only_(false) {}
262
205 bool SetCookieFunction::RunImpl() { 263 bool SetCookieFunction::RunImpl() {
206 // Return false if the arguments are malformed. 264 // Return false if the arguments are malformed.
207 DictionaryValue* details; 265 DictionaryValue* details;
208 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &details)); 266 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &details));
209 DCHECK(details); 267 DCHECK(details);
210 268
211 // Read/validate input parameters. 269 // Read/validate input parameters.
212 GURL url; 270 if (!ParseUrl(details, &url_, true))
213 if (!ParseUrl(details, &url, true))
214 return false; 271 return false;
215 // The macros below return false if argument types are not as expected. 272 // The macros below return false if argument types are not as expected.
216 std::string name; 273 if (details->HasKey(keys::kNameKey))
217 if (details->HasKey(keys::kNameKey)) { 274 EXTENSION_FUNCTION_VALIDATE(details->GetString(keys::kNameKey, &name_));
218 EXTENSION_FUNCTION_VALIDATE(details->GetString(keys::kNameKey, &name)); 275 if (details->HasKey(keys::kValueKey))
276 EXTENSION_FUNCTION_VALIDATE(details->GetString(keys::kValueKey, &value_));
277 if (details->HasKey(keys::kDomainKey))
278 EXTENSION_FUNCTION_VALIDATE(details->GetString(keys::kDomainKey, &domain_));
279 if (details->HasKey(keys::kPathKey))
280 EXTENSION_FUNCTION_VALIDATE(details->GetString(keys::kPathKey, &path_));
281
282 if (details->HasKey(keys::kSecureKey)) {
283 EXTENSION_FUNCTION_VALIDATE(
284 details->GetBoolean(keys::kSecureKey, &secure_));
219 } 285 }
220 std::string value;
221 if (details->HasKey(keys::kValueKey)) {
222 EXTENSION_FUNCTION_VALIDATE(details->GetString(keys::kValueKey, &value));
223 }
224 std::string domain;
225 if (details->HasKey(keys::kDomainKey)) {
226 EXTENSION_FUNCTION_VALIDATE(details->GetString(keys::kDomainKey, &domain));
227 }
228 std::string path;
229 if (details->HasKey(keys::kPathKey)) {
230 EXTENSION_FUNCTION_VALIDATE(details->GetString(keys::kPathKey, &path));
231 }
232 bool secure = false;
233 if (details->HasKey(keys::kSecureKey)) {
234 EXTENSION_FUNCTION_VALIDATE(details->GetBoolean(keys::kSecureKey, &secure));
235 }
236 bool http_only = false;
237 if (details->HasKey(keys::kHttpOnlyKey)) { 286 if (details->HasKey(keys::kHttpOnlyKey)) {
238 EXTENSION_FUNCTION_VALIDATE( 287 EXTENSION_FUNCTION_VALIDATE(
239 details->GetBoolean(keys::kHttpOnlyKey, &http_only)); 288 details->GetBoolean(keys::kHttpOnlyKey, &http_only_));
240 } 289 }
241 base::Time expiration_time;
242 if (details->HasKey(keys::kExpirationDateKey)) { 290 if (details->HasKey(keys::kExpirationDateKey)) {
243 Value* expiration_date_value; 291 Value* expiration_date_value;
244 EXTENSION_FUNCTION_VALIDATE(details->Get(keys::kExpirationDateKey, 292 EXTENSION_FUNCTION_VALIDATE(details->Get(keys::kExpirationDateKey,
245 &expiration_date_value)); 293 &expiration_date_value));
246 double expiration_date; 294 double expiration_date;
247 if (expiration_date_value->IsType(Value::TYPE_INTEGER)) { 295 if (expiration_date_value->IsType(Value::TYPE_INTEGER)) {
248 int expiration_date_int; 296 int expiration_date_int;
249 EXTENSION_FUNCTION_VALIDATE( 297 EXTENSION_FUNCTION_VALIDATE(
250 expiration_date_value->GetAsInteger(&expiration_date_int)); 298 expiration_date_value->GetAsInteger(&expiration_date_int));
251 expiration_date = static_cast<double>(expiration_date_int); 299 expiration_date = static_cast<double>(expiration_date_int);
252 } else { 300 } else {
253 EXTENSION_FUNCTION_VALIDATE( 301 EXTENSION_FUNCTION_VALIDATE(
254 expiration_date_value->GetAsReal(&expiration_date)); 302 expiration_date_value->GetAsReal(&expiration_date));
255 } 303 }
256 expiration_time = base::Time::FromDoubleT(expiration_date); 304 expiration_time_ = base::Time::FromDoubleT(expiration_date);
257 } 305 }
258 306
259 net::CookieStore* cookie_store; 307 URLRequestContextGetter* store_context = NULL;
260 if (!ParseCookieStore(details, &cookie_store, NULL)) 308 if (!ParseStoreContext(details, &store_context, NULL))
261 return false; 309 return false;
262 DCHECK(cookie_store); 310 DCHECK(store_context);
311 store_context_ = store_context;
263 312
264 if (!cookie_store->GetCookieMonster()->SetCookieWithDetails( 313 bool rv = ChromeThread::PostTask(
265 url, name, value, domain, path, expiration_time, secure, 314 ChromeThread::IO, FROM_HERE,
266 http_only)) { 315 NewRunnableMethod(this, &SetCookieFunction::SetCookieOnIOThread));
267 error_ = ExtensionErrorUtils::FormatErrorMessage( 316 DCHECK(rv);
268 keys::kCookieSetFailedError, name); 317
269 return false; 318 // Will finish asynchronously.
270 }
271 return true; 319 return true;
272 } 320 }
273 321
322 void SetCookieFunction::SetCookieOnIOThread() {
323 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
324 net::CookieMonster* cookie_monster =
325 store_context_->GetCookieStore()->GetCookieMonster();
326 success_ = cookie_monster->SetCookieWithDetails(
327 url_, name_, value_, domain_, path_, expiration_time_,
328 secure_, http_only_);
329
330 bool rv = ChromeThread::PostTask(
331 ChromeThread::UI, FROM_HERE,
332 NewRunnableMethod(this, &SetCookieFunction::RespondOnUIThread));
333 DCHECK(rv);
334 }
335
336 void SetCookieFunction::RespondOnUIThread() {
337 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
338 if (!success_) {
339 error_ = ExtensionErrorUtils::FormatErrorMessage(
340 keys::kCookieSetFailedError, name_);
341 }
342 SendResponse(success_);
343 }
344
345 namespace {
346
347 class RemoveCookieTask : public Task {
348 public:
349 RemoveCookieTask(const GURL& url,
350 const std::string& name,
351 const scoped_refptr<URLRequestContextGetter>& context_getter)
352 : url_(url),
353 name_(name),
354 context_getter_(context_getter) {}
355
356 virtual void Run() {
357 net::CookieStore* cookie_store = context_getter_->GetCookieStore();
358 cookie_store->DeleteCookie(url_, name_);
359 }
360
361 private:
362 const GURL url_;
363 const std::string name_;
364 const scoped_refptr<URLRequestContextGetter> context_getter_;
365
366 DISALLOW_COPY_AND_ASSIGN(RemoveCookieTask);
367 };
368
369 } // namespace
370
274 bool RemoveCookieFunction::RunImpl() { 371 bool RemoveCookieFunction::RunImpl() {
275 // Return false if the arguments are malformed. 372 // Return false if the arguments are malformed.
276 DictionaryValue* details; 373 DictionaryValue* details;
277 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &details)); 374 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &details));
278 DCHECK(details); 375 DCHECK(details);
279 376
280 // Read/validate input parameters. 377 // Read/validate input parameters.
281 GURL url; 378 GURL url;
282 if (!ParseUrl(details, &url, true)) 379 if (!ParseUrl(details, &url, true))
283 return false; 380 return false;
284 381
285 std::string name; 382 std::string name;
286 // Get the cookie name string or return false. 383 // Get the cookie name string or return false.
287 EXTENSION_FUNCTION_VALIDATE(details->GetString(keys::kNameKey, &name)); 384 EXTENSION_FUNCTION_VALIDATE(details->GetString(keys::kNameKey, &name));
288 385
289 net::CookieStore* cookie_store; 386 URLRequestContextGetter* store_context = NULL;
290 if (!ParseCookieStore(details, &cookie_store, NULL)) 387 if (!ParseStoreContext(details, &store_context, NULL))
291 return false; 388 return false;
292 DCHECK(cookie_store); 389 DCHECK(store_context);
293 390
294 cookie_store->DeleteCookie(url, name); 391 // We don't bother to synchronously wait for the result here, because
392 // CookieMonster is only ever accessed on the IO thread, so any other accesses
393 // should happen after this.
394 bool rv = ChromeThread::PostTask(
395 ChromeThread::IO, FROM_HERE,
396 new RemoveCookieTask(url, name, store_context));
397 DCHECK(rv);
398
295 return true; 399 return true;
296 } 400 }
297 401
298 bool GetAllCookieStoresFunction::RunImpl() { 402 bool GetAllCookieStoresFunction::RunImpl() {
299 Profile* original_profile = profile()->GetOriginalProfile(); 403 Profile* original_profile = profile()->GetOriginalProfile();
300 DCHECK(original_profile); 404 DCHECK(original_profile);
301 scoped_ptr<ListValue> original_tab_ids(new ListValue()); 405 scoped_ptr<ListValue> original_tab_ids(new ListValue());
302 Profile* incognito_profile = NULL; 406 Profile* incognito_profile = NULL;
303 scoped_ptr<ListValue> incognito_tab_ids; 407 scoped_ptr<ListValue> incognito_tab_ids;
304 if (include_incognito()) { 408 if (include_incognito()) {
(...skipping 24 matching lines...) Expand all
329 original_profile, original_tab_ids.release())); 433 original_profile, original_tab_ids.release()));
330 } 434 }
331 if (incognito_tab_ids.get() && incognito_tab_ids->GetSize() > 0) { 435 if (incognito_tab_ids.get() && incognito_tab_ids->GetSize() > 0) {
332 cookie_store_list->Append( 436 cookie_store_list->Append(
333 extension_cookies_helpers::CreateCookieStoreValue( 437 extension_cookies_helpers::CreateCookieStoreValue(
334 incognito_profile, incognito_tab_ids.release())); 438 incognito_profile, incognito_tab_ids.release()));
335 } 439 }
336 result_.reset(cookie_store_list); 440 result_.reset(cookie_store_list);
337 return true; 441 return true;
338 } 442 }
OLDNEW
« no previous file with comments | « chrome/browser/extensions/extension_cookies_api.h ('k') | chrome/browser/extensions/extension_cookies_helpers.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698