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 |