Home | History | Annotate | Download | only in browser
      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