| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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 common functionality for the Chrome Extensions Cookies API. | 5 // Implements common functionality for the Chrome Extensions Cookies API. |
| 6 | 6 |
| 7 #include "chrome/browser/extensions/api/cookies/cookies_helpers.h" | 7 #include "chrome/browser/extensions/api/cookies/cookies_helpers.h" |
| 8 | 8 |
| 9 #include <vector> |
| 10 |
| 9 #include "base/logging.h" | 11 #include "base/logging.h" |
| 12 #include "base/memory/linked_ptr.h" |
| 13 #include "base/memory/scoped_ptr.h" |
| 10 #include "base/string_util.h" | 14 #include "base/string_util.h" |
| 11 #include "base/utf_string_conversions.h" | 15 #include "base/utf_string_conversions.h" |
| 12 #include "base/values.h" | 16 #include "base/values.h" |
| 13 #include "chrome/browser/extensions/api/cookies/cookies_api_constants.h" | 17 #include "chrome/browser/extensions/api/cookies/cookies_api_constants.h" |
| 14 #include "chrome/browser/extensions/extension_tab_util.h" | 18 #include "chrome/browser/extensions/extension_tab_util.h" |
| 15 #include "chrome/browser/profiles/profile.h" | 19 #include "chrome/browser/profiles/profile.h" |
| 16 #include "chrome/browser/ui/browser.h" | 20 #include "chrome/browser/ui/browser.h" |
| 17 #include "chrome/browser/ui/tab_contents/tab_contents.h" | 21 #include "chrome/browser/ui/tab_contents/tab_contents.h" |
| 18 #include "chrome/browser/ui/tabs/tab_strip_model.h" | 22 #include "chrome/browser/ui/tabs/tab_strip_model.h" |
| 23 #include "chrome/common/extensions/api/cookies.h" |
| 19 #include "chrome/common/extensions/extension.h" | 24 #include "chrome/common/extensions/extension.h" |
| 20 #include "chrome/common/url_constants.h" | 25 #include "chrome/common/url_constants.h" |
| 21 #include "content/public/browser/web_contents.h" | 26 #include "content/public/browser/web_contents.h" |
| 22 #include "googleurl/src/gurl.h" | 27 #include "googleurl/src/gurl.h" |
| 23 #include "net/cookies/canonical_cookie.h" | 28 #include "net/cookies/canonical_cookie.h" |
| 24 #include "net/cookies/cookie_util.h" | 29 #include "net/cookies/cookie_util.h" |
| 25 | 30 |
| 31 using extensions::api::cookies::Cookie; |
| 32 using extensions::api::cookies::CookieStore; |
| 33 |
| 34 namespace GetAll = extensions::api::cookies::GetAll; |
| 35 |
| 26 namespace extensions { | 36 namespace extensions { |
| 27 | 37 |
| 28 namespace keys = cookies_api_constants; | 38 namespace keys = cookies_api_constants; |
| 29 | 39 |
| 30 namespace cookies_helpers { | 40 namespace cookies_helpers { |
| 31 | 41 |
| 32 static const char kOriginalProfileStoreId[] = "0"; | 42 static const char kOriginalProfileStoreId[] = "0"; |
| 33 static const char kOffTheRecordProfileStoreId[] = "1"; | 43 static const char kOffTheRecordProfileStoreId[] = "1"; |
| 34 | 44 |
| 35 Profile* ChooseProfileFromStoreId(const std::string& store_id, | 45 Profile* ChooseProfileFromStoreId(const std::string& store_id, |
| 36 Profile* profile, | 46 Profile* profile, |
| 37 bool include_incognito) { | 47 bool include_incognito) { |
| 38 DCHECK(profile); | 48 DCHECK(profile); |
| 39 bool allow_original = !profile->IsOffTheRecord(); | 49 bool allow_original = !profile->IsOffTheRecord(); |
| 40 bool allow_incognito = profile->IsOffTheRecord() || | 50 bool allow_incognito = profile->IsOffTheRecord() || |
| 41 (include_incognito && profile->HasOffTheRecordProfile()); | 51 (include_incognito && profile->HasOffTheRecordProfile()); |
| 42 if (store_id == kOriginalProfileStoreId && allow_original) | 52 if (store_id == kOriginalProfileStoreId && allow_original) |
| 43 return profile->GetOriginalProfile(); | 53 return profile->GetOriginalProfile(); |
| 44 if (store_id == kOffTheRecordProfileStoreId && allow_incognito) | 54 if (store_id == kOffTheRecordProfileStoreId && allow_incognito) |
| 45 return profile->GetOffTheRecordProfile(); | 55 return profile->GetOffTheRecordProfile(); |
| 46 return NULL; | 56 return NULL; |
| 47 } | 57 } |
| 48 | 58 |
| 49 const char* GetStoreIdFromProfile(Profile* profile) { | 59 const char* GetStoreIdFromProfile(Profile* profile) { |
| 50 DCHECK(profile); | 60 DCHECK(profile); |
| 51 return profile->IsOffTheRecord() ? | 61 return profile->IsOffTheRecord() ? |
| 52 kOffTheRecordProfileStoreId : kOriginalProfileStoreId; | 62 kOffTheRecordProfileStoreId : kOriginalProfileStoreId; |
| 53 } | 63 } |
| 54 | 64 |
| 55 DictionaryValue* CreateCookieValue(const net::CanonicalCookie& cookie, | 65 scoped_ptr<Cookie> CreateCookie( |
| 56 const std::string& store_id) { | 66 const net::CanonicalCookie& canonical_cookie, |
| 57 DictionaryValue* result = new DictionaryValue(); | 67 const std::string& store_id) { |
| 68 scoped_ptr<Cookie> cookie(new Cookie()); |
| 58 | 69 |
| 59 // A cookie is a raw byte sequence. By explicitly parsing it as UTF8, we | 70 // A cookie is a raw byte sequence. By explicitly parsing it as UTF-8, we |
| 60 // apply error correction, so the string can be safely passed to the | 71 // apply error correction, so the string can be safely passed to the renderer. |
| 61 // renderer. | 72 cookie->name = UTF16ToUTF8(UTF8ToUTF16(canonical_cookie.Name())); |
| 62 result->SetString(keys::kNameKey, UTF8ToUTF16(cookie.Name())); | 73 cookie->value = UTF16ToUTF8(UTF8ToUTF16(canonical_cookie.Value())); |
| 63 result->SetString(keys::kValueKey, UTF8ToUTF16(cookie.Value())); | 74 cookie->domain = canonical_cookie.Domain(); |
| 64 result->SetString(keys::kDomainKey, cookie.Domain()); | 75 cookie->host_only = net::cookie_util::DomainIsHostOnly( |
| 65 result->SetBoolean(keys::kHostOnlyKey, | 76 canonical_cookie.Domain()); |
| 66 net::cookie_util::DomainIsHostOnly(cookie.Domain())); | 77 // A non-UTF8 path is invalid, so we just replace it with an empty string. |
| 78 cookie->path = IsStringUTF8(canonical_cookie.Path()) ? |
| 79 canonical_cookie.Path() : ""; |
| 80 cookie->secure = canonical_cookie.IsSecure(); |
| 81 cookie->http_only = canonical_cookie.IsHttpOnly(); |
| 82 cookie->session = !canonical_cookie.IsPersistent(); |
| 83 if (canonical_cookie.IsPersistent()) { |
| 84 cookie->expiration_date.reset( |
| 85 new double(canonical_cookie.ExpiryDate().ToDoubleT())); |
| 86 } |
| 87 cookie->store_id = store_id; |
| 67 | 88 |
| 68 // A non-UTF8 path is invalid, so we just replace it with an empty string. | 89 return cookie.Pass(); |
| 69 result->SetString(keys::kPathKey, | |
| 70 IsStringUTF8(cookie.Path()) ? cookie.Path() : ""); | |
| 71 result->SetBoolean(keys::kSecureKey, cookie.IsSecure()); | |
| 72 result->SetBoolean(keys::kHttpOnlyKey, cookie.IsHttpOnly()); | |
| 73 result->SetBoolean(keys::kSessionKey, !cookie.IsPersistent()); | |
| 74 if (cookie.IsPersistent()) { | |
| 75 result->SetDouble(keys::kExpirationDateKey, | |
| 76 cookie.ExpiryDate().ToDoubleT()); | |
| 77 } | |
| 78 result->SetString(keys::kStoreIdKey, store_id); | |
| 79 | |
| 80 return result; | |
| 81 } | 90 } |
| 82 | 91 |
| 83 DictionaryValue* CreateCookieStoreValue(Profile* profile, | 92 scoped_ptr<CookieStore> CreateCookieStore(Profile* profile, |
| 84 ListValue* tab_ids) { | 93 ListValue* tab_ids) { |
| 85 DCHECK(profile); | 94 DCHECK(profile); |
| 86 DCHECK(tab_ids); | 95 DCHECK(tab_ids); |
| 87 DictionaryValue* result = new DictionaryValue(); | 96 DictionaryValue dict; |
| 88 result->SetString(keys::kIdKey, GetStoreIdFromProfile(profile)); | 97 dict.SetString(keys::kIdKey, GetStoreIdFromProfile(profile)); |
| 89 result->Set(keys::kTabIdsKey, tab_ids); | 98 dict.Set(keys::kTabIdsKey, tab_ids); |
| 90 return result; | 99 |
| 100 CookieStore* cookie_store = new CookieStore(); |
| 101 bool rv = CookieStore::Populate(dict, cookie_store); |
| 102 CHECK(rv); |
| 103 return scoped_ptr<CookieStore>(cookie_store); |
| 91 } | 104 } |
| 92 | 105 |
| 93 void GetCookieListFromStore( | 106 void GetCookieListFromStore( |
| 94 net::CookieStore* cookie_store, const GURL& url, | 107 net::CookieStore* cookie_store, const GURL& url, |
| 95 const net::CookieMonster::GetCookieListCallback& callback) { | 108 const net::CookieMonster::GetCookieListCallback& callback) { |
| 96 DCHECK(cookie_store); | 109 DCHECK(cookie_store); |
| 97 net::CookieMonster* monster = cookie_store->GetCookieMonster(); | 110 net::CookieMonster* monster = cookie_store->GetCookieMonster(); |
| 98 if (!url.is_empty()) { | 111 if (!url.is_empty()) { |
| 99 DCHECK(url.is_valid()); | 112 DCHECK(url.is_valid()); |
| 100 monster->GetAllCookiesForURLAsync(url, callback); | 113 monster->GetAllCookiesForURLAsync(url, callback); |
| 101 } else { | 114 } else { |
| 102 monster->GetAllCookiesAsync(callback); | 115 monster->GetAllCookiesAsync(callback); |
| 103 } | 116 } |
| 104 } | 117 } |
| 105 | 118 |
| 106 GURL GetURLFromCanonicalCookie(const net::CanonicalCookie& cookie) { | 119 GURL GetURLFromCanonicalCookie(const net::CanonicalCookie& cookie) { |
| 107 const std::string& domain_key = cookie.Domain(); | 120 const std::string& domain_key = cookie.Domain(); |
| 108 const std::string scheme = | 121 const std::string scheme = |
| 109 cookie.IsSecure() ? chrome::kHttpsScheme : chrome::kHttpScheme; | 122 cookie.IsSecure() ? chrome::kHttpsScheme : chrome::kHttpScheme; |
| 110 const std::string host = | 123 const std::string host = |
| 111 domain_key.find('.') != 0 ? domain_key : domain_key.substr(1); | 124 domain_key.find('.') != 0 ? domain_key : domain_key.substr(1); |
| 112 return GURL(scheme + content::kStandardSchemeSeparator + host + "/"); | 125 return GURL(scheme + content::kStandardSchemeSeparator + host + "/"); |
| 113 } | 126 } |
| 114 | 127 |
| 115 void AppendMatchingCookiesToList( | 128 void AppendMatchingCookiesToVector(const net::CookieList& all_cookies, |
| 116 const net::CookieList& all_cookies, | 129 const GURL& url, |
| 117 const std::string& store_id, | 130 const GetAll::Params::Details* details, |
| 118 const GURL& url, const DictionaryValue* details, | 131 const Extension* extension, |
| 119 const Extension* extension, | 132 LinkedCookieVec* match_vector) { |
| 120 ListValue* match_list) { | |
| 121 net::CookieList::const_iterator it; | 133 net::CookieList::const_iterator it; |
| 122 for (it = all_cookies.begin(); it != all_cookies.end(); ++it) { | 134 for (it = all_cookies.begin(); it != all_cookies.end(); ++it) { |
| 123 // Ignore any cookie whose domain doesn't match the extension's | 135 // Ignore any cookie whose domain doesn't match the extension's |
| 124 // host permissions. | 136 // host permissions. |
| 125 GURL cookie_domain_url = GetURLFromCanonicalCookie(*it); | 137 GURL cookie_domain_url = GetURLFromCanonicalCookie(*it); |
| 126 if (!extension->HasHostPermission(cookie_domain_url)) | 138 if (!extension->HasHostPermission(cookie_domain_url)) |
| 127 continue; | 139 continue; |
| 128 // Filter the cookie using the match filter. | 140 // Filter the cookie using the match filter. |
| 129 cookies_helpers::MatchFilter filter(details); | 141 cookies_helpers::MatchFilter filter(details); |
| 130 if (filter.MatchesCookie(*it)) | 142 if (filter.MatchesCookie(*it)) { |
| 131 match_list->Append(CreateCookieValue(*it, store_id)); | 143 match_vector->push_back(make_linked_ptr( |
| 144 CreateCookie(*it, *details->store_id).release())); |
| 145 } |
| 132 } | 146 } |
| 133 } | 147 } |
| 134 | 148 |
| 135 void AppendToTabIdList(Browser* browser, ListValue* tab_ids) { | 149 void AppendToTabIdList(Browser* browser, ListValue* tab_ids) { |
| 136 DCHECK(browser); | 150 DCHECK(browser); |
| 137 DCHECK(tab_ids); | 151 DCHECK(tab_ids); |
| 138 TabStripModel* tab_strip = browser->tab_strip_model(); | 152 TabStripModel* tab_strip = browser->tab_strip_model(); |
| 139 for (int i = 0; i < tab_strip->count(); ++i) { | 153 for (int i = 0; i < tab_strip->count(); ++i) { |
| 140 tab_ids->Append(Value::CreateIntegerValue( | 154 tab_ids->Append(Value::CreateIntegerValue( |
| 141 ExtensionTabUtil::GetTabId( | 155 ExtensionTabUtil::GetTabId( |
| 142 tab_strip->GetTabContentsAt(i)->web_contents()))); | 156 tab_strip->GetTabContentsAt(i)->web_contents()))); |
| 143 } | 157 } |
| 144 } | 158 } |
| 145 | 159 |
| 146 MatchFilter::MatchFilter(const DictionaryValue* details) | 160 MatchFilter::MatchFilter(const GetAll::Params::Details* details) |
| 147 : details_(details) { | 161 : details_(details) { |
| 148 DCHECK(details_); | 162 DCHECK(details_); |
| 149 } | 163 } |
| 150 | 164 |
| 151 bool MatchFilter::MatchesCookie(const net::CanonicalCookie& cookie) { | 165 bool MatchFilter::MatchesCookie( |
| 152 return MatchesString(keys::kNameKey, cookie.Name()) && | 166 const net::CanonicalCookie& cookie) { |
| 153 MatchesDomain(cookie.Domain()) && | 167 if (details_->name.get() && *details_->name != cookie.Name()) |
| 154 MatchesString(keys::kPathKey, cookie.Path()) && | 168 return false; |
| 155 MatchesBoolean(keys::kSecureKey, cookie.IsSecure()) && | |
| 156 MatchesBoolean(keys::kSessionKey, !cookie.IsPersistent()); | |
| 157 } | |
| 158 | 169 |
| 159 bool MatchFilter::MatchesString(const char* key, const std::string& value) { | 170 if (!MatchesDomain(cookie.Domain())) |
| 160 if (!details_->HasKey(key)) | 171 return false; |
| 161 return true; | |
| 162 std::string filter_value; | |
| 163 return (details_->GetString(key, &filter_value) && | |
| 164 value == filter_value); | |
| 165 } | |
| 166 | 172 |
| 167 bool MatchFilter::MatchesBoolean(const char* key, bool value) { | 173 if (details_->path.get() && *details_->path != cookie.Path()) |
| 168 if (!details_->HasKey(key)) | 174 return false; |
| 169 return true; | 175 |
| 170 bool filter_value = false; | 176 if (details_->secure.get() && *details_->secure != cookie.IsSecure()) |
| 171 return (details_->GetBoolean(key, &filter_value) && | 177 return false; |
| 172 value == filter_value); | 178 |
| 179 if (details_->session.get() && *details_->session != !cookie.IsPersistent()) |
| 180 return false; |
| 181 |
| 182 return true; |
| 173 } | 183 } |
| 174 | 184 |
| 175 bool MatchFilter::MatchesDomain(const std::string& domain) { | 185 bool MatchFilter::MatchesDomain(const std::string& domain) { |
| 176 if (!details_->HasKey(keys::kDomainKey)) | 186 if (!details_->domain.get()) |
| 177 return true; | 187 return true; |
| 178 | 188 |
| 179 std::string filter_value; | |
| 180 if (!details_->GetString(keys::kDomainKey, &filter_value)) | |
| 181 return false; | |
| 182 // Add a leading '.' character to the filter domain if it doesn't exist. | 189 // Add a leading '.' character to the filter domain if it doesn't exist. |
| 183 if (net::cookie_util::DomainIsHostOnly(filter_value)) | 190 if (net::cookie_util::DomainIsHostOnly(*details_->domain)) |
| 184 filter_value.insert(0, "."); | 191 details_->domain->insert(0, "."); |
| 185 | 192 |
| 186 std::string sub_domain(domain); | 193 std::string sub_domain(domain); |
| 187 // Strip any leading '.' character from the input cookie domain. | 194 // Strip any leading '.' character from the input cookie domain. |
| 188 if (!net::cookie_util::DomainIsHostOnly(sub_domain)) | 195 if (!net::cookie_util::DomainIsHostOnly(sub_domain)) |
| 189 sub_domain = sub_domain.substr(1); | 196 sub_domain = sub_domain.substr(1); |
| 190 | 197 |
| 191 // Now check whether the domain argument is a subdomain of the filter domain. | 198 // Now check whether the domain argument is a subdomain of the filter domain. |
| 192 for (sub_domain.insert(0, "."); | 199 for (sub_domain.insert(0, "."); |
| 193 sub_domain.length() >= filter_value.length();) { | 200 sub_domain.length() >= details_->domain->length();) { |
| 194 if (sub_domain == filter_value) | 201 if (sub_domain == *details_->domain) |
| 195 return true; | 202 return true; |
| 196 const size_t next_dot = sub_domain.find('.', 1); // Skip over leading dot. | 203 const size_t next_dot = sub_domain.find('.', 1); // Skip over leading dot. |
| 197 sub_domain.erase(0, next_dot); | 204 sub_domain.erase(0, next_dot); |
| 198 } | 205 } |
| 199 return false; | 206 return false; |
| 200 } | 207 } |
| 201 | 208 |
| 202 } // namespace cookies_helpers | 209 } // namespace cookies_helpers |
| 203 } // namespace extension | 210 } // namespace extension |
| OLD | NEW |