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 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 87 QuotaPermissionRequest::~QuotaPermissionRequest() {} 88 89 int QuotaPermissionRequest::GetIconID() const { 90 // TODO(gbillock): get the proper image here 91 return IDR_INFOBAR_WARNING; 92 } 93 94 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 106 base::string16 QuotaPermissionRequest::GetMessageTextFragment() const { 107 return l10n_util::GetStringUTF16(IDS_REQUEST_QUOTA_PERMISSION_FRAGMENT); 108 } 109 110 bool QuotaPermissionRequest::HasUserGesture() const { 111 return user_gesture_; 112 } 113 114 GURL QuotaPermissionRequest::GetRequestingHostname() const { 115 return origin_url_; 116 } 117 118 void QuotaPermissionRequest::PermissionGranted() { 119 context_->DispatchCallbackOnIOThread( 120 callback_, 121 content::QuotaPermissionContext::QUOTA_PERMISSION_RESPONSE_ALLOW); 122 callback_ = content::QuotaPermissionContext::PermissionCallback(); 123 } 124 125 void QuotaPermissionRequest::PermissionDenied() { 126 context_->DispatchCallbackOnIOThread( 127 callback_, 128 content::QuotaPermissionContext::QUOTA_PERMISSION_RESPONSE_DISALLOW); 129 callback_ = content::QuotaPermissionContext::PermissionCallback(); 130 } 131 132 void QuotaPermissionRequest::Cancelled() { 133 } 134 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 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 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 210 RequestQuotaInfoBarDelegate::~RequestQuotaInfoBarDelegate() { 211 if (!callback_.is_null()) { 212 context_->DispatchCallbackOnIOThread( 213 callback_, 214 content::QuotaPermissionContext::QUOTA_PERMISSION_RESPONSE_CANCELLED); 215 } 216 } 217 218 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 232 bool RequestQuotaInfoBarDelegate::Accept() { 233 context_->DispatchCallbackOnIOThread( 234 callback_, 235 content::QuotaPermissionContext::QUOTA_PERMISSION_RESPONSE_ALLOW); 236 return true; 237 } 238 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 251 ChromeQuotaPermissionContext::ChromeQuotaPermissionContext() { 252 } 253 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 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 329 ChromeQuotaPermissionContext::~ChromeQuotaPermissionContext() {} 330