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
3 // found in the LICENSE file.
4
5 #include "chrome/browser/chrome_quota_permission_context.h"
6
7 #include <string>
8
9 #include "base/bind.h"
10 #include "base/prefs/pref_service.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "chrome/browser/infobars/infobar_service.h"
13 #include "chrome/browser/profiles/profile.h"
14 #include "chrome/browser/tab_contents/tab_util.h"
15 #include "chrome/browser/ui/website_settings/permission_bubble_manager.h"
16 #include "chrome/browser/ui/website_settings/permission_bubble_request.h"
17 #include "chrome/common/pref_names.h"
18 #include "chrome/grit/generated_resources.h"
19 #include "chrome/grit/locale_settings.h"
20 #include "components/infobars/core/confirm_infobar_delegate.h"
21 #include "components/infobars/core/infobar.h"
22 #include "content/public/browser/browser_thread.h"
23 #include "content/public/browser/navigation_details.h"
24 #include "content/public/browser/web_contents.h"
25 #include "grit/theme_resources.h"
26 #include "net/base/net_util.h"
27 #include "storage/common/quota/quota_types.h"
28 #include "ui/base/l10n/l10n_util.h"
29 #include "url/gurl.h"
30
31 namespace {
32
33 // If the site requested larger quota than this threshold, show a different
34 // message to the user.
35 const int64 kRequestLargeQuotaThreshold = 5 * 1024 * 1024;
36
37 // QuotaPermissionRequest ---------------------------------------------
38
39 class QuotaPermissionRequest : public PermissionBubbleRequest {
40 public:
41 QuotaPermissionRequest(
42 ChromeQuotaPermissionContext* context,
43 const GURL& origin_url,
44 int64 requested_quota,
45 bool user_gesture,
46 const std::string& display_languages,
47 const content::QuotaPermissionContext::PermissionCallback& callback);
48
49 virtual ~QuotaPermissionRequest();
50
51 // PermissionBubbleRequest:
52 virtual int GetIconID() const OVERRIDE;
53 virtual base::string16 GetMessageText() const OVERRIDE;
54 virtual base::string16 GetMessageTextFragment() const OVERRIDE;
55 virtual bool HasUserGesture() const OVERRIDE;
56 virtual GURL GetRequestingHostname() const OVERRIDE;
57 virtual void PermissionGranted() OVERRIDE;
58 virtual void PermissionDenied() OVERRIDE;
59 virtual void Cancelled() OVERRIDE;
60 virtual void RequestFinished() OVERRIDE;
61
62 private:
63 scoped_refptr<ChromeQuotaPermissionContext> context_;
64 GURL origin_url_;
65 std::string display_languages_;
66 int64 requested_quota_;
67 bool user_gesture_;
68 content::QuotaPermissionContext::PermissionCallback callback_;
69
70 DISALLOW_COPY_AND_ASSIGN(QuotaPermissionRequest);
71 };
72
QuotaPermissionRequest(ChromeQuotaPermissionContext * context,const GURL & origin_url,int64 requested_quota,bool user_gesture,const std::string & display_languages,const content::QuotaPermissionContext::PermissionCallback & callback)73 QuotaPermissionRequest::QuotaPermissionRequest(
74 ChromeQuotaPermissionContext* context,
75 const GURL& origin_url,
76 int64 requested_quota,
77 bool user_gesture,
78 const std::string& display_languages,
79 const content::QuotaPermissionContext::PermissionCallback& callback)
80 : context_(context),
81 origin_url_(origin_url),
82 display_languages_(display_languages),
83 requested_quota_(requested_quota),
84 user_gesture_(user_gesture),
85 callback_(callback) {}
86
~QuotaPermissionRequest()87 QuotaPermissionRequest::~QuotaPermissionRequest() {}
88
GetIconID() const89 int QuotaPermissionRequest::GetIconID() const {
90 // TODO(gbillock): get the proper image here
91 return IDR_INFOBAR_WARNING;
92 }
93
GetMessageText() const94 base::string16 QuotaPermissionRequest::GetMessageText() const {
95 return l10n_util::GetStringFUTF16(
96 (requested_quota_ > kRequestLargeQuotaThreshold ?
97 IDS_REQUEST_LARGE_QUOTA_INFOBAR_QUESTION :
98 IDS_REQUEST_QUOTA_INFOBAR_QUESTION),
99 net::FormatUrl(origin_url_, display_languages_,
100 net::kFormatUrlOmitUsernamePassword |
101 net::kFormatUrlOmitTrailingSlashOnBareHostname,
102 net::UnescapeRule::SPACES, NULL, NULL, NULL)
103 );
104 }
105
GetMessageTextFragment() const106 base::string16 QuotaPermissionRequest::GetMessageTextFragment() const {
107 return l10n_util::GetStringUTF16(IDS_REQUEST_QUOTA_PERMISSION_FRAGMENT);
108 }
109
HasUserGesture() const110 bool QuotaPermissionRequest::HasUserGesture() const {
111 return user_gesture_;
112 }
113
GetRequestingHostname() const114 GURL QuotaPermissionRequest::GetRequestingHostname() const {
115 return origin_url_;
116 }
117
PermissionGranted()118 void QuotaPermissionRequest::PermissionGranted() {
119 context_->DispatchCallbackOnIOThread(
120 callback_,
121 content::QuotaPermissionContext::QUOTA_PERMISSION_RESPONSE_ALLOW);
122 callback_ = content::QuotaPermissionContext::PermissionCallback();
123 }
124
PermissionDenied()125 void QuotaPermissionRequest::PermissionDenied() {
126 context_->DispatchCallbackOnIOThread(
127 callback_,
128 content::QuotaPermissionContext::QUOTA_PERMISSION_RESPONSE_DISALLOW);
129 callback_ = content::QuotaPermissionContext::PermissionCallback();
130 }
131
Cancelled()132 void QuotaPermissionRequest::Cancelled() {
133 }
134
RequestFinished()135 void QuotaPermissionRequest::RequestFinished() {
136 if (!callback_.is_null()) {
137 context_->DispatchCallbackOnIOThread(
138 callback_,
139 content::QuotaPermissionContext::QUOTA_PERMISSION_RESPONSE_CANCELLED);
140 }
141
142 delete this;
143 }
144
145
146 // RequestQuotaInfoBarDelegate ------------------------------------------------
147
148 class RequestQuotaInfoBarDelegate : public ConfirmInfoBarDelegate {
149 public:
150 // Creates a request quota infobar and delegate and adds the infobar to
151 // |infobar_service|.
152 static void Create(
153 InfoBarService* infobar_service,
154 ChromeQuotaPermissionContext* context,
155 const GURL& origin_url,
156 int64 requested_quota,
157 const std::string& display_languages,
158 const content::QuotaPermissionContext::PermissionCallback& callback);
159
160 private:
161 RequestQuotaInfoBarDelegate(
162 ChromeQuotaPermissionContext* context,
163 const GURL& origin_url,
164 int64 requested_quota,
165 const std::string& display_languages,
166 const content::QuotaPermissionContext::PermissionCallback& callback);
167 virtual ~RequestQuotaInfoBarDelegate();
168
169 // ConfirmInfoBarDelegate:
170 virtual base::string16 GetMessageText() const OVERRIDE;
171 virtual bool Accept() OVERRIDE;
172 virtual bool Cancel() OVERRIDE;
173
174 scoped_refptr<ChromeQuotaPermissionContext> context_;
175 GURL origin_url_;
176 std::string display_languages_;
177 int64 requested_quota_;
178 content::QuotaPermissionContext::PermissionCallback callback_;
179
180 DISALLOW_COPY_AND_ASSIGN(RequestQuotaInfoBarDelegate);
181 };
182
183 // static
Create(InfoBarService * infobar_service,ChromeQuotaPermissionContext * context,const GURL & origin_url,int64 requested_quota,const std::string & display_languages,const content::QuotaPermissionContext::PermissionCallback & callback)184 void RequestQuotaInfoBarDelegate::Create(
185 InfoBarService* infobar_service,
186 ChromeQuotaPermissionContext* context,
187 const GURL& origin_url,
188 int64 requested_quota,
189 const std::string& display_languages,
190 const content::QuotaPermissionContext::PermissionCallback& callback) {
191 infobar_service->AddInfoBar(ConfirmInfoBarDelegate::CreateInfoBar(
192 scoped_ptr<ConfirmInfoBarDelegate>(new RequestQuotaInfoBarDelegate(
193 context, origin_url, requested_quota, display_languages, callback))));
194 }
195
RequestQuotaInfoBarDelegate(ChromeQuotaPermissionContext * context,const GURL & origin_url,int64 requested_quota,const std::string & display_languages,const content::QuotaPermissionContext::PermissionCallback & callback)196 RequestQuotaInfoBarDelegate::RequestQuotaInfoBarDelegate(
197 ChromeQuotaPermissionContext* context,
198 const GURL& origin_url,
199 int64 requested_quota,
200 const std::string& display_languages,
201 const content::QuotaPermissionContext::PermissionCallback& callback)
202 : ConfirmInfoBarDelegate(),
203 context_(context),
204 origin_url_(origin_url),
205 display_languages_(display_languages),
206 requested_quota_(requested_quota),
207 callback_(callback) {
208 }
209
~RequestQuotaInfoBarDelegate()210 RequestQuotaInfoBarDelegate::~RequestQuotaInfoBarDelegate() {
211 if (!callback_.is_null()) {
212 context_->DispatchCallbackOnIOThread(
213 callback_,
214 content::QuotaPermissionContext::QUOTA_PERMISSION_RESPONSE_CANCELLED);
215 }
216 }
217
GetMessageText() const218 base::string16 RequestQuotaInfoBarDelegate::GetMessageText() const {
219 // If the site requested larger quota than this threshold, show a different
220 // message to the user.
221 return l10n_util::GetStringFUTF16(
222 (requested_quota_ > kRequestLargeQuotaThreshold ?
223 IDS_REQUEST_LARGE_QUOTA_INFOBAR_QUESTION :
224 IDS_REQUEST_QUOTA_INFOBAR_QUESTION),
225 net::FormatUrl(origin_url_, display_languages_,
226 net::kFormatUrlOmitUsernamePassword |
227 net::kFormatUrlOmitTrailingSlashOnBareHostname,
228 net::UnescapeRule::SPACES, NULL, NULL, NULL)
229 );
230 }
231
Accept()232 bool RequestQuotaInfoBarDelegate::Accept() {
233 context_->DispatchCallbackOnIOThread(
234 callback_,
235 content::QuotaPermissionContext::QUOTA_PERMISSION_RESPONSE_ALLOW);
236 return true;
237 }
238
Cancel()239 bool RequestQuotaInfoBarDelegate::Cancel() {
240 context_->DispatchCallbackOnIOThread(
241 callback_,
242 content::QuotaPermissionContext::QUOTA_PERMISSION_RESPONSE_CANCELLED);
243 return true;
244 }
245
246 } // namespace
247
248
249 // ChromeQuotaPermissionContext -----------------------------------------------
250
ChromeQuotaPermissionContext()251 ChromeQuotaPermissionContext::ChromeQuotaPermissionContext() {
252 }
253
RequestQuotaPermission(const content::StorageQuotaParams & params,int render_process_id,const PermissionCallback & callback)254 void ChromeQuotaPermissionContext::RequestQuotaPermission(
255 const content::StorageQuotaParams& params,
256 int render_process_id,
257 const PermissionCallback& callback) {
258 if (params.storage_type != storage::kStorageTypePersistent) {
259 // For now we only support requesting quota with this interface
260 // for Persistent storage type.
261 callback.Run(QUOTA_PERMISSION_RESPONSE_DISALLOW);
262 return;
263 }
264
265 if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) {
266 content::BrowserThread::PostTask(
267 content::BrowserThread::UI, FROM_HERE,
268 base::Bind(&ChromeQuotaPermissionContext::RequestQuotaPermission, this,
269 params, render_process_id, callback));
270 return;
271 }
272
273 content::WebContents* web_contents =
274 tab_util::GetWebContentsByID(render_process_id,
275 params.render_view_id);
276 if (!web_contents) {
277 // The tab may have gone away or the request may not be from a tab.
278 LOG(WARNING) << "Attempt to request quota tabless renderer: "
279 << render_process_id << "," << params.render_view_id;
280 DispatchCallbackOnIOThread(callback, QUOTA_PERMISSION_RESPONSE_CANCELLED);
281 return;
282 }
283
284 if (PermissionBubbleManager::Enabled()) {
285 PermissionBubbleManager* bubble_manager =
286 PermissionBubbleManager::FromWebContents(web_contents);
287 if (bubble_manager) {
288 bubble_manager->AddRequest(new QuotaPermissionRequest(this,
289 params.origin_url, params.requested_size, params.user_gesture,
290 Profile::FromBrowserContext(web_contents->GetBrowserContext())->
291 GetPrefs()->GetString(prefs::kAcceptLanguages),
292 callback));
293 }
294 return;
295 }
296
297 InfoBarService* infobar_service =
298 InfoBarService::FromWebContents(web_contents);
299 if (!infobar_service) {
300 // The tab has no infobar service.
301 LOG(WARNING) << "Attempt to request quota from a background page: "
302 << render_process_id << "," << params.render_view_id;
303 DispatchCallbackOnIOThread(callback, QUOTA_PERMISSION_RESPONSE_CANCELLED);
304 return;
305 }
306 RequestQuotaInfoBarDelegate::Create(
307 infobar_service, this, params.origin_url, params.requested_size,
308 Profile::FromBrowserContext(web_contents->GetBrowserContext())->
309 GetPrefs()->GetString(prefs::kAcceptLanguages),
310 callback);
311 }
312
DispatchCallbackOnIOThread(const PermissionCallback & callback,QuotaPermissionResponse response)313 void ChromeQuotaPermissionContext::DispatchCallbackOnIOThread(
314 const PermissionCallback& callback,
315 QuotaPermissionResponse response) {
316 DCHECK_EQ(false, callback.is_null());
317
318 if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)) {
319 content::BrowserThread::PostTask(
320 content::BrowserThread::IO, FROM_HERE,
321 base::Bind(&ChromeQuotaPermissionContext::DispatchCallbackOnIOThread,
322 this, callback, response));
323 return;
324 }
325
326 callback.Run(response);
327 }
328
~ChromeQuotaPermissionContext()329 ChromeQuotaPermissionContext::~ChromeQuotaPermissionContext() {}
330