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/confirm_infobar_delegate.h"
13#include "chrome/browser/infobars/infobar_service.h"
14#include "chrome/browser/profiles/profile.h"
15#include "chrome/browser/tab_contents/tab_util.h"
16#include "chrome/common/pref_names.h"
17#include "content/public/browser/browser_thread.h"
18#include "content/public/browser/navigation_details.h"
19#include "content/public/browser/web_contents.h"
20#include "grit/generated_resources.h"
21#include "grit/locale_settings.h"
22#include "net/base/net_util.h"
23#include "ui/base/l10n/l10n_util.h"
24#include "url/gurl.h"
25#include "webkit/common/quota/quota_types.h"
26
27
28
29// RequestQuotaInfoBarDelegate ------------------------------------------------
30
31namespace {
32
33class RequestQuotaInfoBarDelegate : public ConfirmInfoBarDelegate {
34 public:
35  // Creates a request quota infobar delegate and adds it to |infobar_service|.
36  static void Create(
37      InfoBarService* infobar_service,
38      ChromeQuotaPermissionContext* context,
39      const GURL& origin_url,
40      int64 requested_quota,
41      const std::string& display_languages,
42      const content::QuotaPermissionContext::PermissionCallback& callback);
43
44 private:
45  RequestQuotaInfoBarDelegate(
46      InfoBarService* infobar_service,
47      ChromeQuotaPermissionContext* context,
48      const GURL& origin_url,
49      int64 requested_quota,
50      const std::string& display_languages,
51      const content::QuotaPermissionContext::PermissionCallback& callback);
52  virtual ~RequestQuotaInfoBarDelegate();
53
54  // ConfirmInfoBarDelegate:
55  virtual bool ShouldExpireInternal(
56      const content::LoadCommittedDetails& details) const OVERRIDE;
57  virtual string16 GetMessageText() const OVERRIDE;
58  virtual bool Accept() OVERRIDE;
59  virtual bool Cancel() OVERRIDE;
60
61  scoped_refptr<ChromeQuotaPermissionContext> context_;
62  GURL origin_url_;
63  std::string display_languages_;
64  int64 requested_quota_;
65  content::QuotaPermissionContext::PermissionCallback callback_;
66
67  DISALLOW_COPY_AND_ASSIGN(RequestQuotaInfoBarDelegate);
68};
69
70// static
71void RequestQuotaInfoBarDelegate::Create(
72    InfoBarService* infobar_service,
73    ChromeQuotaPermissionContext* context,
74    const GURL& origin_url,
75    int64 requested_quota,
76    const std::string& display_languages,
77    const content::QuotaPermissionContext::PermissionCallback& callback) {
78  infobar_service->AddInfoBar(scoped_ptr<InfoBarDelegate>(
79      new RequestQuotaInfoBarDelegate(infobar_service, context, origin_url,
80                                      requested_quota, display_languages,
81                                      callback)));
82}
83
84RequestQuotaInfoBarDelegate::RequestQuotaInfoBarDelegate(
85    InfoBarService* infobar_service,
86    ChromeQuotaPermissionContext* context,
87    const GURL& origin_url,
88    int64 requested_quota,
89    const std::string& display_languages,
90    const content::QuotaPermissionContext::PermissionCallback& callback)
91    : ConfirmInfoBarDelegate(infobar_service),
92      context_(context),
93      origin_url_(origin_url),
94      display_languages_(display_languages),
95      requested_quota_(requested_quota),
96      callback_(callback) {
97}
98
99RequestQuotaInfoBarDelegate::~RequestQuotaInfoBarDelegate() {
100  if (!callback_.is_null()) {
101    context_->DispatchCallbackOnIOThread(
102        callback_,
103        content::QuotaPermissionContext::QUOTA_PERMISSION_RESPONSE_CANCELLED);
104  }
105}
106
107bool RequestQuotaInfoBarDelegate::ShouldExpireInternal(
108    const content::LoadCommittedDetails& details) const {
109  return false;
110}
111
112string16 RequestQuotaInfoBarDelegate::GetMessageText() const {
113  // If the site requested larger quota than this threshold, show a different
114  // message to the user.
115  const int64 kRequestLargeQuotaThreshold = 5 * 1024 * 1024;
116  return l10n_util::GetStringFUTF16(
117      (requested_quota_ > kRequestLargeQuotaThreshold ?
118          IDS_REQUEST_LARGE_QUOTA_INFOBAR_QUESTION :
119          IDS_REQUEST_QUOTA_INFOBAR_QUESTION),
120      net::FormatUrl(origin_url_, display_languages_));
121}
122
123bool RequestQuotaInfoBarDelegate::Accept() {
124  context_->DispatchCallbackOnIOThread(
125      callback_,
126      content::QuotaPermissionContext::QUOTA_PERMISSION_RESPONSE_ALLOW);
127  return true;
128}
129
130bool RequestQuotaInfoBarDelegate::Cancel() {
131  context_->DispatchCallbackOnIOThread(
132      callback_,
133      content::QuotaPermissionContext::QUOTA_PERMISSION_RESPONSE_CANCELLED);
134  return true;
135}
136
137}  // namespace
138
139
140// ChromeQuotaPermissionContext -----------------------------------------------
141
142ChromeQuotaPermissionContext::ChromeQuotaPermissionContext() {
143}
144
145void ChromeQuotaPermissionContext::RequestQuotaPermission(
146    const GURL& origin_url,
147    quota::StorageType type,
148    int64 requested_quota,
149    int render_process_id,
150    int render_view_id,
151    const PermissionCallback& callback) {
152  if (type != quota::kStorageTypePersistent) {
153    // For now we only support requesting quota with this interface
154    // for Persistent storage type.
155    callback.Run(QUOTA_PERMISSION_RESPONSE_DISALLOW);
156    return;
157  }
158
159  if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) {
160    content::BrowserThread::PostTask(
161        content::BrowserThread::UI, FROM_HERE,
162        base::Bind(&ChromeQuotaPermissionContext::RequestQuotaPermission, this,
163                   origin_url, type, requested_quota, render_process_id,
164                   render_view_id, callback));
165    return;
166  }
167
168  content::WebContents* web_contents =
169      tab_util::GetWebContentsByID(render_process_id, render_view_id);
170  if (!web_contents) {
171    // The tab may have gone away or the request may not be from a tab.
172    LOG(WARNING) << "Attempt to request quota tabless renderer: "
173                 << render_process_id << "," << render_view_id;
174    DispatchCallbackOnIOThread(callback, QUOTA_PERMISSION_RESPONSE_CANCELLED);
175    return;
176  }
177
178  InfoBarService* infobar_service =
179      InfoBarService::FromWebContents(web_contents);
180  if (!infobar_service) {
181    // The tab has no infobar service.
182    LOG(WARNING) << "Attempt to request quota from a background page: "
183                 << render_process_id << "," << render_view_id;
184    DispatchCallbackOnIOThread(callback, QUOTA_PERMISSION_RESPONSE_CANCELLED);
185    return;
186  }
187  RequestQuotaInfoBarDelegate::Create(
188      infobar_service, this, origin_url, requested_quota,
189      Profile::FromBrowserContext(web_contents->GetBrowserContext())->
190          GetPrefs()->GetString(prefs::kAcceptLanguages),
191      callback);
192}
193
194void ChromeQuotaPermissionContext::DispatchCallbackOnIOThread(
195    const PermissionCallback& callback,
196    QuotaPermissionResponse response) {
197  DCHECK_EQ(false, callback.is_null());
198
199  if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)) {
200    content::BrowserThread::PostTask(
201        content::BrowserThread::IO, FROM_HERE,
202        base::Bind(&ChromeQuotaPermissionContext::DispatchCallbackOnIOThread,
203                   this, callback, response));
204    return;
205  }
206
207  callback.Run(response);
208}
209
210ChromeQuotaPermissionContext::~ChromeQuotaPermissionContext() {}
211