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() const { return id_; } |
| 141 void set_id(int id) { id_ = id; } |
| 142 |
| 143 size_t RequestSize() const { return types_.size(); } |
| 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_; |
| 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 std::vector<PermissionDescriptorPtr> permissions; | 197 std::vector<PermissionDescriptorPtr> permissions; |
(...skipping 23 matching lines...) Expand all Loading... |
133 for (size_t i = 0; i < permissions.size(); ++i) | 221 for (size_t i = 0; i < permissions.size(); ++i) |
134 result[i] = GetPermissionStatus(permissions[i], origin); | 222 result[i] = GetPermissionStatus(permissions[i], origin); |
135 callback.Run(result); | 223 callback.Run(result); |
136 return; | 224 return; |
137 } | 225 } |
138 | 226 |
139 std::vector<PermissionType> types(permissions.size()); | 227 std::vector<PermissionType> types(permissions.size()); |
140 for (size_t i = 0; i < types.size(); ++i) | 228 for (size_t i = 0; i < types.size(); ++i) |
141 types[i] = PermissionDescriptorToPermissionType(permissions[i]); | 229 types[i] = PermissionDescriptorToPermissionType(permissions[i]); |
142 | 230 |
143 int pending_request_id = pending_requests_.Add( | 231 std::unique_ptr<PendingRequest> pending_request = |
144 base::MakeUnique<PendingRequest>(callback, permissions.size())); | 232 base::MakeUnique<PendingRequest>(types, callback); |
| 233 std::vector<PermissionType> request_types; |
| 234 for (size_t i = 0; i < types.size(); ++i) { |
| 235 // Check feature policy. |
| 236 if (!AllowedByFeaturePolicy(context_->render_frame_host(), types[i])) |
| 237 pending_request->SetResult(i, PermissionStatus::DENIED); |
| 238 else |
| 239 request_types.push_back(types[i]); |
| 240 } |
| 241 |
| 242 int pending_request_id = pending_requests_.Add(std::move(pending_request)); |
145 int id = browser_context->GetPermissionManager()->RequestPermissions( | 243 int id = browser_context->GetPermissionManager()->RequestPermissions( |
146 types, context_->render_frame_host(), origin.GetURL(), user_gesture, | 244 request_types, context_->render_frame_host(), origin.GetURL(), |
| 245 user_gesture, |
147 base::Bind(&PermissionServiceImpl::OnRequestPermissionsResponse, | 246 base::Bind(&PermissionServiceImpl::OnRequestPermissionsResponse, |
148 weak_factory_.GetWeakPtr(), pending_request_id)); | 247 weak_factory_.GetWeakPtr(), pending_request_id)); |
149 | 248 |
150 // Check if the request still exists. It may have been removed by the | 249 // Check if the request still exists. It may have been removed by the |
151 // the response callback. | 250 // the response callback. |
152 PendingRequest* pending_request = pending_requests_.Lookup( | 251 PendingRequest* in_progress_request = |
153 pending_request_id); | 252 pending_requests_.Lookup(pending_request_id); |
154 if (!pending_request) | 253 if (!in_progress_request) |
155 return; | 254 return; |
156 pending_request->id = id; | 255 in_progress_request->set_id(id); |
157 } | 256 } |
158 | 257 |
159 void PermissionServiceImpl::OnRequestPermissionsResponse( | 258 void PermissionServiceImpl::OnRequestPermissionsResponse( |
160 int pending_request_id, | 259 int pending_request_id, |
161 const std::vector<PermissionStatus>& result) { | 260 const std::vector<PermissionStatus>& partial_result) { |
162 PendingRequest* request = pending_requests_.Lookup(pending_request_id); | 261 PendingRequest* request = pending_requests_.Lookup(pending_request_id); |
163 RequestPermissionsCallback callback(request->callback); | 262 auto partial_result_it = partial_result.begin(); |
164 request->callback.Reset(); | 263 // Fill in the unset results in the request. Some results in the request are |
| 264 // set synchronously because they are blocked by feature policy. Others are |
| 265 // determined by a call to RequestPermission. All unset results will be |
| 266 // contained in |partial_result| in the same order that they were requested. |
| 267 // We fill in the unset results in the request with |partial_result|. |
| 268 for (size_t i = 0; i < request->RequestSize(); ++i) { |
| 269 if (!request->HasResultBeenSet(i)) { |
| 270 request->SetResult(i, *partial_result_it); |
| 271 ++partial_result_it; |
| 272 } |
| 273 } |
| 274 DCHECK(partial_result.end() == partial_result_it); |
| 275 |
| 276 request->RunCallback(); |
165 pending_requests_.Remove(pending_request_id); | 277 pending_requests_.Remove(pending_request_id); |
166 callback.Run(result); | |
167 } | 278 } |
168 | 279 |
169 void PermissionServiceImpl::HasPermission( | 280 void PermissionServiceImpl::HasPermission( |
170 PermissionDescriptorPtr permission, | 281 PermissionDescriptorPtr permission, |
171 const url::Origin& origin, | 282 const url::Origin& origin, |
172 const PermissionStatusCallback& callback) { | 283 const PermissionStatusCallback& callback) { |
173 callback.Run(GetPermissionStatus(permission, origin)); | 284 callback.Run(GetPermissionStatus(permission, origin)); |
174 } | 285 } |
175 | 286 |
176 void PermissionServiceImpl::RevokePermission( | 287 void PermissionServiceImpl::RevokePermission( |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
214 const url::Origin& origin) { | 325 const url::Origin& origin) { |
215 return GetPermissionStatusFromType( | 326 return GetPermissionStatusFromType( |
216 PermissionDescriptorToPermissionType(permission), origin); | 327 PermissionDescriptorToPermissionType(permission), origin); |
217 } | 328 } |
218 | 329 |
219 PermissionStatus PermissionServiceImpl::GetPermissionStatusFromType( | 330 PermissionStatus PermissionServiceImpl::GetPermissionStatusFromType( |
220 PermissionType type, | 331 PermissionType type, |
221 const url::Origin& origin) { | 332 const url::Origin& origin) { |
222 BrowserContext* browser_context = context_->GetBrowserContext(); | 333 BrowserContext* browser_context = context_->GetBrowserContext(); |
223 DCHECK(browser_context); | 334 DCHECK(browser_context); |
224 if (!browser_context->GetPermissionManager()) | 335 if (!browser_context->GetPermissionManager() || |
| 336 !AllowedByFeaturePolicy(context_->render_frame_host(), type)) { |
225 return PermissionStatus::DENIED; | 337 return PermissionStatus::DENIED; |
| 338 } |
226 | 339 |
227 GURL requesting_origin(origin.Serialize()); | 340 GURL requesting_origin(origin.Serialize()); |
228 // If the embedding_origin is empty we'll use |origin| instead. | 341 // If the embedding_origin is empty we'll use |origin| instead. |
229 GURL embedding_origin = context_->GetEmbeddingOrigin(); | 342 GURL embedding_origin = context_->GetEmbeddingOrigin(); |
230 return browser_context->GetPermissionManager()->GetPermissionStatus( | 343 return browser_context->GetPermissionManager()->GetPermissionStatus( |
231 type, requesting_origin, | 344 type, requesting_origin, |
232 embedding_origin.is_empty() ? requesting_origin : embedding_origin); | 345 embedding_origin.is_empty() ? requesting_origin : embedding_origin); |
233 } | 346 } |
234 | 347 |
235 void PermissionServiceImpl::ResetPermissionStatus(PermissionType type, | 348 void PermissionServiceImpl::ResetPermissionStatus(PermissionType type, |
236 const url::Origin& origin) { | 349 const url::Origin& origin) { |
237 BrowserContext* browser_context = context_->GetBrowserContext(); | 350 BrowserContext* browser_context = context_->GetBrowserContext(); |
238 DCHECK(browser_context); | 351 DCHECK(browser_context); |
239 if (!browser_context->GetPermissionManager()) | 352 if (!browser_context->GetPermissionManager()) |
240 return; | 353 return; |
241 | 354 |
242 GURL requesting_origin(origin.Serialize()); | 355 GURL requesting_origin(origin.Serialize()); |
243 // If the embedding_origin is empty we'll use |origin| instead. | 356 // If the embedding_origin is empty we'll use |origin| instead. |
244 GURL embedding_origin = context_->GetEmbeddingOrigin(); | 357 GURL embedding_origin = context_->GetEmbeddingOrigin(); |
245 browser_context->GetPermissionManager()->ResetPermission( | 358 browser_context->GetPermissionManager()->ResetPermission( |
246 type, requesting_origin, | 359 type, requesting_origin, |
247 embedding_origin.is_empty() ? requesting_origin : embedding_origin); | 360 embedding_origin.is_empty() ? requesting_origin : embedding_origin); |
248 } | 361 } |
249 | 362 |
250 } // namespace content | 363 } // namespace content |
OLD | NEW |