OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/permissions/permission_service_impl.h" | 5 #include "content/browser/permissions/permission_service_impl.h" |
6 | 6 |
7 #include <stddef.h> | 7 #include <stddef.h> |
8 | 8 |
9 #include <memory> | 9 #include <memory> |
10 #include <utility> | 10 #include <utility> |
11 | 11 |
12 #include "base/bind.h" | 12 #include "base/bind.h" |
13 #include "base/feature_list.h" | |
13 #include "base/memory/ptr_util.h" | 14 #include "base/memory/ptr_util.h" |
14 #include "content/public/browser/browser_context.h" | 15 #include "content/public/browser/browser_context.h" |
15 #include "content/public/browser/permission_manager.h" | 16 #include "content/public/browser/permission_manager.h" |
16 #include "content/public/browser/permission_type.h" | 17 #include "content/public/browser/permission_type.h" |
18 #include "content/public/browser/render_frame_host.h" | |
19 #include "content/public/common/content_features.h" | |
20 #include "third_party/WebKit/public/platform/WebFeaturePolicy.h" | |
17 | 21 |
18 using blink::mojom::PermissionDescriptorPtr; | 22 using blink::mojom::PermissionDescriptorPtr; |
19 using blink::mojom::PermissionName; | 23 using blink::mojom::PermissionName; |
20 using blink::mojom::PermissionObserverPtr; | 24 using blink::mojom::PermissionObserverPtr; |
21 using blink::mojom::PermissionStatus; | 25 using blink::mojom::PermissionStatus; |
22 | 26 |
23 namespace content { | 27 namespace content { |
24 | 28 |
25 namespace { | 29 namespace { |
26 | 30 |
(...skipping 22 matching lines...) Expand all Loading... | |
49 case PermissionName::VIDEO_CAPTURE: | 53 case PermissionName::VIDEO_CAPTURE: |
50 return PermissionType::VIDEO_CAPTURE; | 54 return PermissionType::VIDEO_CAPTURE; |
51 case PermissionName::BACKGROUND_SYNC: | 55 case PermissionName::BACKGROUND_SYNC: |
52 return PermissionType::BACKGROUND_SYNC; | 56 return PermissionType::BACKGROUND_SYNC; |
53 } | 57 } |
54 | 58 |
55 NOTREACHED(); | 59 NOTREACHED(); |
56 return PermissionType::NUM; | 60 return PermissionType::NUM; |
57 } | 61 } |
58 | 62 |
59 // This function allows the usage of the the multiple request map | 63 blink::WebFeaturePolicyFeature PermissionTypeToFeaturePolicyFeature( |
60 // with single requests. | 64 PermissionType type) { |
65 switch (type) { | |
66 case PermissionType::MIDI: | |
67 case PermissionType::MIDI_SYSEX: | |
68 return blink::WebFeaturePolicyFeature::kMidiFeature; | |
69 case PermissionType::GEOLOCATION: | |
70 return blink::WebFeaturePolicyFeature::kGeolocation; | |
71 case PermissionType::PROTECTED_MEDIA_IDENTIFIER: | |
72 return blink::WebFeaturePolicyFeature::kEme; | |
73 case PermissionType::AUDIO_CAPTURE: | |
74 return blink::WebFeaturePolicyFeature::kMicrophone; | |
75 case PermissionType::VIDEO_CAPTURE: | |
76 return blink::WebFeaturePolicyFeature::kCamera; | |
77 case PermissionType::PUSH_MESSAGING: | |
78 case PermissionType::NOTIFICATIONS: | |
79 case PermissionType::DURABLE_STORAGE: | |
80 case PermissionType::BACKGROUND_SYNC: | |
81 case PermissionType::FLASH: | |
82 case PermissionType::NUM: | |
83 // These aren't exposed by feature policy. | |
84 return blink::WebFeaturePolicyFeature::kNotFound; | |
85 } | |
86 | |
87 NOTREACHED(); | |
88 return blink::WebFeaturePolicyFeature::kNotFound; | |
89 } | |
90 | |
91 bool AllowedByFeaturePolicy(RenderFrameHost* rfh, PermissionType type) { | |
92 if (!base::FeatureList::IsEnabled( | |
93 features::kUseFeaturePolicyForPermissions)) { | |
94 // Default to ignoring the feature policy. | |
95 return true; | |
96 } | |
97 | |
98 blink::WebFeaturePolicyFeature feature_policy_feature = | |
99 PermissionTypeToFeaturePolicyFeature(type); | |
100 if (feature_policy_feature == blink::WebFeaturePolicyFeature::kNotFound) | |
101 return true; | |
102 | |
103 // If there is no frame, there is no policy, so disable the feature for | |
104 // safety. | |
105 if (!rfh) | |
106 return false; | |
107 | |
108 return rfh->IsFeatureEnabled(feature_policy_feature); | |
109 } | |
110 | |
111 // This function allows the usage of the the multiple request map with single | |
112 // requests. | |
61 void PermissionRequestResponseCallbackWrapper( | 113 void PermissionRequestResponseCallbackWrapper( |
62 const base::Callback<void(PermissionStatus)>& callback, | 114 const base::Callback<void(PermissionStatus)>& callback, |
63 const std::vector<PermissionStatus>& vector) { | 115 const std::vector<PermissionStatus>& vector) { |
64 DCHECK_EQ(vector.size(), 1ul); | 116 DCHECK_EQ(vector.size(), 1ul); |
65 callback.Run(vector[0]); | 117 callback.Run(vector[0]); |
66 } | 118 } |
67 | 119 |
68 } // anonymous namespace | 120 } // anonymous namespace |
69 | 121 |
70 PermissionServiceImpl::PendingRequest::PendingRequest( | 122 class PermissionServiceImpl::PendingRequest { |
71 const RequestPermissionsCallback& callback, | 123 public: |
72 int request_count) | 124 PendingRequest(std::vector<PermissionType> types, |
73 : callback(callback), | 125 const RequestPermissionsCallback& callback) |
74 request_count(request_count) { | 126 : types_(types), |
75 } | 127 callback_(callback), |
128 has_result_been_set_(types.size(), false), | |
129 results_(types.size(), PermissionStatus::DENIED) {} | |
76 | 130 |
77 PermissionServiceImpl::PendingRequest::~PendingRequest() { | 131 ~PendingRequest() { |
78 if (callback.is_null()) | 132 if (callback_.is_null()) |
79 return; | 133 return; |
80 | 134 |
81 std::vector<PermissionStatus> result(request_count, PermissionStatus::DENIED); | 135 std::vector<PermissionStatus> result(types_.size(), |
82 callback.Run(result); | 136 PermissionStatus::DENIED); |
83 } | 137 callback_.Run(result); |
138 } | |
139 | |
140 int id() { return id_; } | |
mlamouri (slow - plz ping)
2017/05/30 09:38:22
nit: `const`
raymes
2017/05/31 05:32:00
Done.
| |
141 void set_id(int id) { id_ = id; } | |
142 | |
143 size_t RequestSize() { return types_.size(); } | |
mlamouri (slow - plz ping)
2017/05/30 09:38:22
ditto
raymes
2017/05/31 05:32:00
Done.
| |
144 | |
145 void SetResult(int index, PermissionStatus result) { | |
146 DCHECK_EQ(false, has_result_been_set_[index]); | |
147 has_result_been_set_[index] = true; | |
148 results_[index] = result; | |
149 } | |
150 | |
151 bool HasResultBeenSet(size_t index) const { | |
152 return has_result_been_set_[index]; | |
153 } | |
154 | |
155 void RunCallback() { | |
156 // Check that all results have been set. | |
157 DCHECK(std::find(has_result_been_set_.begin(), has_result_been_set_.end(), | |
158 false) == has_result_been_set_.end()); | |
159 callback_.Run(results_); | |
160 callback_.Reset(); | |
161 } | |
162 | |
163 private: | |
164 // Request ID received from the PermissionManager. | |
165 int id_; | |
166 std::vector<PermissionType> types_; | |
167 RequestPermissionsCallback callback_; | |
168 | |
169 std::vector<bool> has_result_been_set_; | |
170 std::vector<PermissionStatus> results_; | |
mlamouri (slow - plz ping)
2017/05/30 09:38:22
Did you consider:
`std::vector<base::Optional<Perm
raymes
2017/05/31 05:32:00
Good idea. I tried this but it meant having to tra
| |
171 }; | |
84 | 172 |
85 PermissionServiceImpl::PermissionServiceImpl(PermissionServiceContext* context) | 173 PermissionServiceImpl::PermissionServiceImpl(PermissionServiceContext* context) |
86 : context_(context), weak_factory_(this) {} | 174 : context_(context), weak_factory_(this) {} |
87 | 175 |
88 PermissionServiceImpl::~PermissionServiceImpl() { | 176 PermissionServiceImpl::~PermissionServiceImpl() { |
89 DCHECK(context_->GetBrowserContext()); | 177 DCHECK(context_->GetBrowserContext()); |
90 | 178 |
91 PermissionManager* permission_manager = | 179 PermissionManager* permission_manager = |
92 context_->GetBrowserContext()->GetPermissionManager(); | 180 context_->GetBrowserContext()->GetPermissionManager(); |
93 if (!permission_manager) | 181 if (!permission_manager) |
94 return; | 182 return; |
95 | 183 |
96 // Cancel pending requests. | 184 // Cancel pending requests. |
97 for (RequestsMap::Iterator<PendingRequest> it(&pending_requests_); | 185 for (RequestsMap::Iterator<PendingRequest> it(&pending_requests_); |
98 !it.IsAtEnd(); it.Advance()) { | 186 !it.IsAtEnd(); it.Advance()) { |
99 permission_manager->CancelPermissionRequest(it.GetCurrentValue()->id); | 187 permission_manager->CancelPermissionRequest(it.GetCurrentValue()->id()); |
100 } | 188 } |
101 pending_requests_.Clear(); | 189 pending_requests_.Clear(); |
102 } | 190 } |
103 | 191 |
104 void PermissionServiceImpl::RequestPermission( | 192 void PermissionServiceImpl::RequestPermission( |
105 PermissionDescriptorPtr permission, | 193 PermissionDescriptorPtr permission, |
106 const url::Origin& origin, | 194 const url::Origin& origin, |
107 bool user_gesture, | 195 bool user_gesture, |
108 const PermissionStatusCallback& callback) { | 196 const PermissionStatusCallback& callback) { |
109 // This condition is valid if the call is coming from a ChildThread instead of | 197 // This condition is valid if the call is coming from a ChildThread instead of |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
166 for (size_t i = 0; i < permissions.size(); ++i) | 254 for (size_t i = 0; i < permissions.size(); ++i) |
167 result[i] = GetPermissionStatus(permissions[i], origin); | 255 result[i] = GetPermissionStatus(permissions[i], origin); |
168 callback.Run(result); | 256 callback.Run(result); |
169 return; | 257 return; |
170 } | 258 } |
171 | 259 |
172 std::vector<PermissionType> types(permissions.size()); | 260 std::vector<PermissionType> types(permissions.size()); |
173 for (size_t i = 0; i < types.size(); ++i) | 261 for (size_t i = 0; i < types.size(); ++i) |
174 types[i] = PermissionDescriptorToPermissionType(permissions[i]); | 262 types[i] = PermissionDescriptorToPermissionType(permissions[i]); |
175 | 263 |
176 int pending_request_id = pending_requests_.Add( | 264 std::unique_ptr<PendingRequest> pending_request = |
177 base::MakeUnique<PendingRequest>(callback, permissions.size())); | 265 base::MakeUnique<PendingRequest>(types, callback); |
266 std::vector<PermissionType> request_types; | |
267 for (size_t i = 0; i < types.size(); ++i) { | |
268 // Check feature policy. | |
269 if (!AllowedByFeaturePolicy(context_->render_frame_host(), types[i])) | |
270 pending_request->SetResult(i, PermissionStatus::DENIED); | |
271 else | |
272 request_types.push_back(types[i]); | |
273 } | |
274 | |
275 int pending_request_id = pending_requests_.Add(std::move(pending_request)); | |
178 int id = browser_context->GetPermissionManager()->RequestPermissions( | 276 int id = browser_context->GetPermissionManager()->RequestPermissions( |
179 types, context_->render_frame_host(), origin.GetURL(), user_gesture, | 277 request_types, context_->render_frame_host(), origin.GetURL(), |
278 user_gesture, | |
180 base::Bind(&PermissionServiceImpl::OnRequestPermissionsResponse, | 279 base::Bind(&PermissionServiceImpl::OnRequestPermissionsResponse, |
181 weak_factory_.GetWeakPtr(), pending_request_id)); | 280 weak_factory_.GetWeakPtr(), pending_request_id)); |
182 | 281 |
183 // Check if the request still exists. It may have been removed by the | 282 // Check if the request still exists. It may have been removed by the |
184 // the response callback. | 283 // the response callback. |
185 PendingRequest* pending_request = pending_requests_.Lookup( | 284 PendingRequest* in_progress_request = |
186 pending_request_id); | 285 pending_requests_.Lookup(pending_request_id); |
187 if (!pending_request) | 286 if (!in_progress_request) |
188 return; | 287 return; |
189 pending_request->id = id; | 288 in_progress_request->set_id(id); |
190 } | 289 } |
191 | 290 |
192 void PermissionServiceImpl::OnRequestPermissionsResponse( | 291 void PermissionServiceImpl::OnRequestPermissionsResponse( |
193 int pending_request_id, | 292 int pending_request_id, |
194 const std::vector<PermissionStatus>& result) { | 293 const std::vector<PermissionStatus>& partial_result) { |
195 PendingRequest* request = pending_requests_.Lookup(pending_request_id); | 294 PendingRequest* request = pending_requests_.Lookup(pending_request_id); |
196 RequestPermissionsCallback callback(request->callback); | 295 auto partial_result_it = partial_result.begin(); |
197 request->callback.Reset(); | 296 for (size_t i = 0; i < request->RequestSize(); ++i) { |
mlamouri (slow - plz ping)
2017/05/30 09:38:22
Can you add a comment on top of this loop explaini
raymes
2017/05/31 05:32:00
Thanks - I tried to make the comment clearer.
| |
297 // We fill in the unset results with those from the call to | |
298 // RequestPermissions. | |
299 if (!request->HasResultBeenSet(i)) { | |
300 request->SetResult(i, *partial_result_it); | |
301 ++partial_result_it; | |
302 } | |
303 } | |
304 DCHECK(partial_result.end() == partial_result_it); | |
mlamouri (slow - plz ping)
2017/05/30 09:38:22
Would DCHECK_EQ work here?
raymes
2017/05/31 05:32:00
Unfortunately it fails to compile I think because
| |
305 | |
306 request->RunCallback(); | |
198 pending_requests_.Remove(pending_request_id); | 307 pending_requests_.Remove(pending_request_id); |
199 callback.Run(result); | |
200 } | 308 } |
201 | 309 |
202 void PermissionServiceImpl::HasPermission( | 310 void PermissionServiceImpl::HasPermission( |
203 PermissionDescriptorPtr permission, | 311 PermissionDescriptorPtr permission, |
204 const url::Origin& origin, | 312 const url::Origin& origin, |
205 const PermissionStatusCallback& callback) { | 313 const PermissionStatusCallback& callback) { |
206 callback.Run(GetPermissionStatus(permission, origin)); | 314 callback.Run(GetPermissionStatus(permission, origin)); |
207 } | 315 } |
208 | 316 |
209 void PermissionServiceImpl::RevokePermission( | 317 void PermissionServiceImpl::RevokePermission( |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
247 const url::Origin& origin) { | 355 const url::Origin& origin) { |
248 return GetPermissionStatusFromType( | 356 return GetPermissionStatusFromType( |
249 PermissionDescriptorToPermissionType(permission), origin); | 357 PermissionDescriptorToPermissionType(permission), origin); |
250 } | 358 } |
251 | 359 |
252 PermissionStatus PermissionServiceImpl::GetPermissionStatusFromType( | 360 PermissionStatus PermissionServiceImpl::GetPermissionStatusFromType( |
253 PermissionType type, | 361 PermissionType type, |
254 const url::Origin& origin) { | 362 const url::Origin& origin) { |
255 BrowserContext* browser_context = context_->GetBrowserContext(); | 363 BrowserContext* browser_context = context_->GetBrowserContext(); |
256 DCHECK(browser_context); | 364 DCHECK(browser_context); |
257 if (!browser_context->GetPermissionManager()) | 365 if (!browser_context->GetPermissionManager() || |
366 !AllowedByFeaturePolicy(context_->render_frame_host(), type)) { | |
258 return PermissionStatus::DENIED; | 367 return PermissionStatus::DENIED; |
368 } | |
259 | 369 |
260 GURL requesting_origin(origin.Serialize()); | 370 GURL requesting_origin(origin.Serialize()); |
261 // If the embedding_origin is empty we'll use |origin| instead. | 371 // If the embedding_origin is empty we'll use |origin| instead. |
262 GURL embedding_origin = context_->GetEmbeddingOrigin(); | 372 GURL embedding_origin = context_->GetEmbeddingOrigin(); |
263 return browser_context->GetPermissionManager()->GetPermissionStatus( | 373 return browser_context->GetPermissionManager()->GetPermissionStatus( |
264 type, requesting_origin, | 374 type, requesting_origin, |
265 embedding_origin.is_empty() ? requesting_origin : embedding_origin); | 375 embedding_origin.is_empty() ? requesting_origin : embedding_origin); |
266 } | 376 } |
267 | 377 |
268 void PermissionServiceImpl::ResetPermissionStatus(PermissionType type, | 378 void PermissionServiceImpl::ResetPermissionStatus(PermissionType type, |
269 const url::Origin& origin) { | 379 const url::Origin& origin) { |
270 BrowserContext* browser_context = context_->GetBrowserContext(); | 380 BrowserContext* browser_context = context_->GetBrowserContext(); |
271 DCHECK(browser_context); | 381 DCHECK(browser_context); |
272 if (!browser_context->GetPermissionManager()) | 382 if (!browser_context->GetPermissionManager()) |
273 return; | 383 return; |
274 | 384 |
275 GURL requesting_origin(origin.Serialize()); | 385 GURL requesting_origin(origin.Serialize()); |
276 // If the embedding_origin is empty we'll use |origin| instead. | 386 // If the embedding_origin is empty we'll use |origin| instead. |
277 GURL embedding_origin = context_->GetEmbeddingOrigin(); | 387 GURL embedding_origin = context_->GetEmbeddingOrigin(); |
278 browser_context->GetPermissionManager()->ResetPermission( | 388 browser_context->GetPermissionManager()->ResetPermission( |
279 type, requesting_origin, | 389 type, requesting_origin, |
280 embedding_origin.is_empty() ? requesting_origin : embedding_origin); | 390 embedding_origin.is_empty() ? requesting_origin : embedding_origin); |
281 } | 391 } |
282 | 392 |
283 } // namespace content | 393 } // namespace content |
OLD | NEW |