• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 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/media/midi_permission_context.h"
6 
7 #include "base/prefs/pref_service.h"
8 #include "chrome/browser/content_settings/host_content_settings_map.h"
9 #include "chrome/browser/content_settings/permission_queue_controller.h"
10 #include "chrome/browser/content_settings/permission_request_id.h"
11 #include "chrome/browser/content_settings/tab_specific_content_settings.h"
12 #include "chrome/browser/profiles/profile.h"
13 #include "chrome/browser/tab_contents/tab_util.h"
14 #include "chrome/browser/ui/website_settings/permission_bubble_manager.h"
15 #include "chrome/browser/ui/website_settings/permission_bubble_request.h"
16 #include "chrome/common/pref_names.h"
17 #include "content/public/browser/browser_thread.h"
18 #include "content/public/browser/render_process_host.h"
19 #include "content/public/browser/render_view_host.h"
20 #include "content/public/browser/web_contents.h"
21 #include "grit/generated_resources.h"
22 #include "grit/theme_resources.h"
23 #include "net/base/net_util.h"
24 #include "ui/base/l10n/l10n_util.h"
25 
26 class MidiPermissionRequest : public PermissionBubbleRequest {
27  public:
28   MidiPermissionRequest(
29       MidiPermissionContext* context,
30       const PermissionRequestID& id,
31       const GURL& requesting_frame,
32       bool user_gesture,
33       const std::string& display_languages,
34       const base::Callback<void(bool)>& callback);
35   virtual ~MidiPermissionRequest();
36 
37   // PermissionBubbleDelegate:
38   virtual int GetIconID() const OVERRIDE;
39   virtual base::string16 GetMessageText() const OVERRIDE;
40   virtual base::string16 GetMessageTextFragment() const OVERRIDE;
41   virtual bool HasUserGesture() const OVERRIDE;
42   virtual GURL GetRequestingHostname() const OVERRIDE;
43   virtual void PermissionGranted() OVERRIDE;
44   virtual void PermissionDenied() OVERRIDE;
45   virtual void Cancelled() OVERRIDE;
46   virtual void RequestFinished() OVERRIDE;
47 
48  private:
49   MidiPermissionContext* context_;
50   const PermissionRequestID id_;
51   GURL requesting_frame_;
52   bool user_gesture_;
53   std::string display_languages_;
54   const base::Callback<void(bool)>& callback_;
55   bool is_finished_;
56 
57   DISALLOW_COPY_AND_ASSIGN(MidiPermissionRequest);
58 };
59 
MidiPermissionRequest(MidiPermissionContext * context,const PermissionRequestID & id,const GURL & requesting_frame,bool user_gesture,const std::string & display_languages,const base::Callback<void (bool)> & callback)60 MidiPermissionRequest::MidiPermissionRequest(
61     MidiPermissionContext* context,
62     const PermissionRequestID& id,
63     const GURL& requesting_frame,
64     bool user_gesture,
65     const std::string& display_languages,
66     const base::Callback<void(bool)>& callback)
67     : context_(context),
68       id_(id),
69       requesting_frame_(requesting_frame),
70       user_gesture_(user_gesture),
71       display_languages_(display_languages),
72       callback_(callback),
73       is_finished_(false) {}
74 
~MidiPermissionRequest()75 MidiPermissionRequest::~MidiPermissionRequest() {
76   DCHECK(is_finished_);
77 }
78 
GetIconID() const79 int MidiPermissionRequest::GetIconID() const {
80   return IDR_ALLOWED_MIDI_SYSEX;
81 }
82 
GetMessageText() const83 base::string16 MidiPermissionRequest::GetMessageText() const {
84   return l10n_util::GetStringFUTF16(
85       IDS_MIDI_SYSEX_INFOBAR_QUESTION,
86       net::FormatUrl(requesting_frame_.GetOrigin(), display_languages_));
87 }
88 
GetMessageTextFragment() const89 base::string16 MidiPermissionRequest::GetMessageTextFragment() const {
90   return l10n_util::GetStringUTF16(IDS_MIDI_SYSEX_PERMISSION_FRAGMENT);
91 }
92 
HasUserGesture() const93 bool MidiPermissionRequest::HasUserGesture() const {
94   return user_gesture_;
95 }
96 
GetRequestingHostname() const97 GURL MidiPermissionRequest::GetRequestingHostname() const {
98   return requesting_frame_;
99 }
100 
PermissionGranted()101 void MidiPermissionRequest::PermissionGranted() {
102   context_->NotifyPermissionSet(id_, requesting_frame_, callback_, true);
103 }
104 
PermissionDenied()105 void MidiPermissionRequest::PermissionDenied() {
106   context_->NotifyPermissionSet(id_, requesting_frame_, callback_, false);
107 }
108 
Cancelled()109 void MidiPermissionRequest::Cancelled() {
110 }
111 
RequestFinished()112 void MidiPermissionRequest::RequestFinished() {
113   is_finished_ = true;
114   // Deletes 'this'.
115   context_->RequestFinished(this);
116 }
117 
MidiPermissionContext(Profile * profile)118 MidiPermissionContext::MidiPermissionContext(Profile* profile)
119     : profile_(profile),
120       shutting_down_(false),
121       weak_factory_(this) {
122   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
123 }
124 
~MidiPermissionContext()125 MidiPermissionContext::~MidiPermissionContext() {
126   DCHECK(!permission_queue_controller_);
127   DCHECK(pending_requests_.empty());
128   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
129 }
130 
Shutdown()131 void MidiPermissionContext::Shutdown() {
132   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
133   permission_queue_controller_.reset();
134   shutting_down_ = true;
135 }
136 
RequestMidiSysExPermission(content::WebContents * web_contents,int bridge_id,const GURL & requesting_frame,bool user_gesture,const base::Callback<void (bool)> & result_callback,base::Closure * cancel_callback)137 void MidiPermissionContext::RequestMidiSysExPermission(
138     content::WebContents* web_contents,
139     int bridge_id,
140     const GURL& requesting_frame,
141     bool user_gesture,
142     const base::Callback<void(bool)>& result_callback,
143     base::Closure* cancel_callback) {
144   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
145   DCHECK(!shutting_down_);
146 
147   // TODO(toyoshim): Support Extension's manifest declared permission.
148   // See http://crbug.com/266338.
149 
150   int render_process_id = web_contents->GetRenderProcessHost()->GetID();
151   int render_view_id = web_contents->GetRenderViewHost()->GetRoutingID();
152   if (cancel_callback) {
153     *cancel_callback = base::Bind(
154         &MidiPermissionContext::CancelMidiSysExPermissionRequest,
155         weak_factory_.GetWeakPtr(), render_process_id, render_view_id,
156         bridge_id);
157   }
158 
159   const PermissionRequestID id(
160       render_process_id, render_view_id, bridge_id, GURL());
161 
162   GURL embedder = web_contents->GetURL();
163   // |requesting_frame| can be empty and invalid when the frame is a local
164   // file. Here local files should be granted to show an infobar.
165   // Any user's action will not be stored to content settings data base.
166   if ((!requesting_frame.is_valid() && !requesting_frame.is_empty()) ||
167       !embedder.is_valid()) {
168     LOG(WARNING) << "Attempt to use MIDI sysex from an invalid URL: "
169                  << requesting_frame << "," << embedder
170                  << " (Web MIDI is not supported in popups)";
171     PermissionDecided(id, requesting_frame, embedder, result_callback, false);
172     return;
173   }
174 
175   DecidePermission(web_contents, id, requesting_frame, embedder, user_gesture,
176                    result_callback);
177 }
178 
CancelMidiSysExPermissionRequest(int render_process_id,int render_view_id,int bridge_id)179 void MidiPermissionContext::CancelMidiSysExPermissionRequest(
180     int render_process_id,
181     int render_view_id,
182     int bridge_id) {
183   CancelPendingInfobarRequest(
184       PermissionRequestID(
185           render_process_id, render_view_id, bridge_id, GURL()));
186 }
187 
DecidePermission(content::WebContents * web_contents,const PermissionRequestID & id,const GURL & requesting_frame,const GURL & embedder,bool user_gesture,const base::Callback<void (bool)> & callback)188 void MidiPermissionContext::DecidePermission(
189     content::WebContents* web_contents,
190     const PermissionRequestID& id,
191     const GURL& requesting_frame,
192     const GURL& embedder,
193     bool user_gesture,
194     const base::Callback<void(bool)>& callback) {
195   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
196 
197   ContentSetting content_setting =
198       profile_->GetHostContentSettingsMap()->GetContentSetting(
199           requesting_frame,
200           embedder,
201           CONTENT_SETTINGS_TYPE_MIDI_SYSEX,
202           std::string());
203   switch (content_setting) {
204     case CONTENT_SETTING_BLOCK:
205       PermissionDecided(id, requesting_frame, embedder, callback, false);
206       break;
207     case CONTENT_SETTING_ALLOW:
208       PermissionDecided(id, requesting_frame, embedder, callback, true);
209       break;
210     default:
211       if (PermissionBubbleManager::Enabled()) {
212         PermissionBubbleManager* bubble_manager =
213             PermissionBubbleManager::FromWebContents(web_contents);
214         if (bubble_manager) {
215           scoped_ptr<MidiPermissionRequest> request_ptr(
216               new MidiPermissionRequest(
217                   this, id, requesting_frame, user_gesture,
218                   profile_->GetPrefs()->GetString(prefs::kAcceptLanguages),
219                   callback));
220           MidiPermissionRequest* request = request_ptr.get();
221           bool inserted = pending_requests_.add(
222               id.ToString(), request_ptr.Pass()).second;
223           DCHECK(inserted) << "Duplicate id " << id.ToString();
224           bubble_manager->AddRequest(request);
225         }
226         return;
227       }
228 
229       // TODO(gbillock): Delete this and the infobar delegate when
230       // we're using only bubbles. crbug.com/337458
231       GetQueueController()->CreateInfoBarRequest(
232           id, requesting_frame, embedder, std::string(), base::Bind(
233               &MidiPermissionContext::NotifyPermissionSet,
234               base::Unretained(this), id, requesting_frame, callback));
235   }
236 }
237 
PermissionDecided(const PermissionRequestID & id,const GURL & requesting_frame,const GURL & embedder,const base::Callback<void (bool)> & callback,bool allowed)238 void MidiPermissionContext::PermissionDecided(
239     const PermissionRequestID& id,
240     const GURL& requesting_frame,
241     const GURL& embedder,
242     const base::Callback<void(bool)>& callback,
243     bool allowed) {
244   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
245   NotifyPermissionSet(id, requesting_frame, callback, allowed);
246 }
247 
NotifyPermissionSet(const PermissionRequestID & id,const GURL & requesting_frame,const base::Callback<void (bool)> & callback,bool allowed)248 void MidiPermissionContext::NotifyPermissionSet(
249     const PermissionRequestID& id,
250     const GURL& requesting_frame,
251     const base::Callback<void(bool)>& callback,
252     bool allowed) {
253   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
254 
255   TabSpecificContentSettings* content_settings =
256       TabSpecificContentSettings::Get(id.render_process_id(),
257                                       id.render_view_id());
258   if (content_settings) {
259     if (allowed)
260       content_settings->OnMidiSysExAccessed(requesting_frame);
261     else
262       content_settings->OnMidiSysExAccessBlocked(requesting_frame);
263   }
264 
265   callback.Run(allowed);
266 }
267 
GetQueueController()268 PermissionQueueController* MidiPermissionContext::GetQueueController() {
269   if (!permission_queue_controller_) {
270     permission_queue_controller_.reset(
271         new PermissionQueueController(profile_,
272                                       CONTENT_SETTINGS_TYPE_MIDI_SYSEX));
273   }
274   return permission_queue_controller_.get();
275 }
276 
RequestFinished(MidiPermissionRequest * request)277 void MidiPermissionContext::RequestFinished(
278     MidiPermissionRequest* request) {
279   base::ScopedPtrHashMap<std::string, MidiPermissionRequest>::iterator it;
280   for (it = pending_requests_.begin(); it != pending_requests_.end(); it++) {
281     if (it->second == request) {
282       pending_requests_.take_and_erase(it);
283       return;
284     }
285   }
286 
287   NOTREACHED() << "Missing request";
288 }
289 
CancelPendingInfobarRequest(const PermissionRequestID & id)290 void MidiPermissionContext::CancelPendingInfobarRequest(
291     const PermissionRequestID& id) {
292   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
293   if (shutting_down_)
294     return;
295 
296   if (PermissionBubbleManager::Enabled()) {
297     MidiPermissionRequest* cancelling = pending_requests_.get(id.ToString());
298     content::WebContents* web_contents = tab_util::GetWebContentsByID(
299         id.render_process_id(), id.render_view_id());
300     if (cancelling != NULL && web_contents != NULL &&
301         PermissionBubbleManager::FromWebContents(web_contents) != NULL) {
302       PermissionBubbleManager::FromWebContents(web_contents)->
303           CancelRequest(cancelling);
304     }
305     return;
306   }
307 
308   GetQueueController()->CancelInfoBarRequest(id);
309 }
310