Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(37)

Side by Side Diff: third_party/WebKit/Source/modules/permissions/Permissions.cpp

Issue 2108003002: Merge //content/child/permissions into Blink's permissions module. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebased. Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 "modules/permissions/Permissions.h" 5 #include "modules/permissions/Permissions.h"
6 6
7 #include "bindings/core/v8/Dictionary.h" 7 #include "bindings/core/v8/Dictionary.h"
8 #include "bindings/core/v8/Nullable.h" 8 #include "bindings/core/v8/Nullable.h"
9 #include "bindings/core/v8/ScriptPromise.h" 9 #include "bindings/core/v8/ScriptPromise.h"
10 #include "bindings/core/v8/ScriptPromiseResolver.h" 10 #include "bindings/core/v8/ScriptPromiseResolver.h"
11 #include "bindings/modules/v8/V8MidiPermissionDescriptor.h" 11 #include "bindings/modules/v8/V8MidiPermissionDescriptor.h"
12 #include "bindings/modules/v8/V8PermissionDescriptor.h" 12 #include "bindings/modules/v8/V8PermissionDescriptor.h"
13 #include "bindings/modules/v8/V8PushPermissionDescriptor.h" 13 #include "bindings/modules/v8/V8PushPermissionDescriptor.h"
14 #include "core/dom/DOMException.h" 14 #include "core/dom/DOMException.h"
15 #include "core/dom/Document.h" 15 #include "core/dom/Document.h"
16 #include "core/dom/ExceptionCode.h" 16 #include "core/dom/ExceptionCode.h"
17 #include "modules/permissions/PermissionCallback.h" 17 #include "core/frame/LocalFrame.h"
18 #include "modules/permissions/PermissionController.h"
19 #include "modules/permissions/PermissionDescriptor.h" 18 #include "modules/permissions/PermissionDescriptor.h"
20 #include "modules/permissions/PermissionStatus.h" 19 #include "modules/permissions/PermissionStatus.h"
21 #include "modules/permissions/PermissionsCallback.h"
22 #include "platform/Logging.h" 20 #include "platform/Logging.h"
21 #include "platform/UserGestureIndicator.h"
23 #include "public/platform/Platform.h" 22 #include "public/platform/Platform.h"
24 #include "public/platform/modules/permissions/WebPermissionClient.h" 23 #include "public/platform/ServiceRegistry.h"
24 #include "wtf/Functional.h"
25 #include "wtf/NotFound.h" 25 #include "wtf/NotFound.h"
26 #include "wtf/PtrUtil.h" 26 #include "wtf/PtrUtil.h"
27 #include "wtf/Vector.h" 27 #include "wtf/Vector.h"
28 #include <memory> 28 #include <memory>
29 29
30 namespace blink { 30 namespace blink {
31 31
32 using mojom::blink::PermissionName;
33 using mojom::blink::PermissionService;
34
32 namespace { 35 namespace {
33 36
34 // Websites will be able to run code when `name()` is called, changing the 37 // Websites will be able to run code when `name()` is called, changing the
35 // current context. The caller should make sure that no assumption is made 38 // current context. The caller should make sure that no assumption is made
36 // after this has been called. 39 // after this has been called.
37 WebPermissionType getPermissionType(ScriptState* scriptState, const Dictionary& rawPermission, const PermissionDescriptor& permission, ExceptionState& exception State) 40 PermissionName getPermissionName(ScriptState* scriptState, const Dictionary& raw Permission, const PermissionDescriptor& permission, ExceptionState& exceptionSta te)
38 { 41 {
39 const String& name = permission.name(); 42 const String& name = permission.name();
40 if (name == "geolocation") 43 if (name == "geolocation")
41 return WebPermissionTypeGeolocation; 44 return PermissionName::GEOLOCATION;
42 if (name == "notifications") 45 if (name == "notifications")
43 return WebPermissionTypeNotifications; 46 return PermissionName::NOTIFICATIONS;
44 if (name == "push") 47 if (name == "push")
45 return WebPermissionTypePushNotifications; 48 return PermissionName::PUSH_NOTIFICATIONS;
46 if (name == "midi") { 49 if (name == "midi") {
47 MidiPermissionDescriptor midiPermission = NativeValueTraits<MidiPermissi onDescriptor>::nativeValue(scriptState->isolate(), rawPermission.v8Value(), exce ptionState); 50 MidiPermissionDescriptor midiPermission = NativeValueTraits<MidiPermissi onDescriptor>::nativeValue(scriptState->isolate(), rawPermission.v8Value(), exce ptionState);
48 return midiPermission.sysex() ? WebPermissionTypeMidiSysEx : WebPermissi onTypeMidi; 51 return midiPermission.sysex() ? PermissionName::MIDI_SYSEX : PermissionN ame::MIDI;
49 } 52 }
50 if (name == "background-sync") 53 if (name == "background-sync")
51 return WebPermissionTypeBackgroundSync; 54 return PermissionName::BACKGROUND_SYNC;
52 55
53 ASSERT_NOT_REACHED(); 56 ASSERT_NOT_REACHED();
54 return WebPermissionTypeGeolocation; 57 return PermissionName::GEOLOCATION;
55 } 58 }
56 59
57 // Parses the raw permission dictionary and returns the PermissionType if 60 // Parses the raw permission dictionary and returns the PermissionType if
58 // parsing was successful. If an exception occurs, it will be stored in 61 // parsing was successful. If an exception occurs, it will be stored in
59 // |exceptionState| and null will be returned. Therefore, the |exceptionState| 62 // |exceptionState| and null will be returned. Therefore, the |exceptionState|
60 // should be checked before attempting to use the returned permission as the 63 // should be checked before attempting to use the returned permission as the
61 // non-null assert will be fired otherwise. 64 // non-null assert will be fired otherwise.
62 Nullable<WebPermissionType> parsePermission(ScriptState* scriptState, const Dict ionary rawPermission, ExceptionState& exceptionState) 65 Nullable<PermissionName> parsePermission(ScriptState* scriptState, const Diction ary rawPermission, ExceptionState& exceptionState)
63 { 66 {
64 PermissionDescriptor permission = NativeValueTraits<PermissionDescriptor>::n ativeValue(scriptState->isolate(), rawPermission.v8Value(), exceptionState); 67 PermissionDescriptor permission = NativeValueTraits<PermissionDescriptor>::n ativeValue(scriptState->isolate(), rawPermission.v8Value(), exceptionState);
65 68
66 if (exceptionState.hadException()) { 69 if (exceptionState.hadException()) {
67 exceptionState.throwTypeError(exceptionState.message()); 70 exceptionState.throwTypeError(exceptionState.message());
68 return Nullable<WebPermissionType>(); 71 return Nullable<PermissionName>();
69 } 72 }
70 73
71 WebPermissionType type = getPermissionType(scriptState, rawPermission, permi ssion, exceptionState); 74 PermissionName name = getPermissionName(scriptState, rawPermission, permissi on, exceptionState);
72 if (exceptionState.hadException()) { 75 if (exceptionState.hadException()) {
73 exceptionState.throwTypeError(exceptionState.message()); 76 exceptionState.throwTypeError(exceptionState.message());
74 return Nullable<WebPermissionType>(); 77 return Nullable<PermissionName>();
75 } 78 }
76 79
77 // Here we reject any permissions which are not yet supported by Blink. 80 // Here we reject any permissions which are not yet supported by Blink.
78 if (type == WebPermissionTypePushNotifications) { 81 if (name == PermissionName::PUSH_NOTIFICATIONS) {
79 PushPermissionDescriptor pushPermission = NativeValueTraits<PushPermissi onDescriptor>::nativeValue(scriptState->isolate(), rawPermission.v8Value(), exce ptionState); 82 PushPermissionDescriptor pushPermission = NativeValueTraits<PushPermissi onDescriptor>::nativeValue(scriptState->isolate(), rawPermission.v8Value(), exce ptionState);
80 if (exceptionState.hadException()) { 83 if (exceptionState.hadException()) {
81 exceptionState.throwTypeError(exceptionState.message()); 84 exceptionState.throwTypeError(exceptionState.message());
82 return Nullable<WebPermissionType>(); 85 return Nullable<PermissionName>();
83 } 86 }
84 87
85 // Only "userVisibleOnly" push is supported for now. 88 // Only "userVisibleOnly" push is supported for now.
86 if (!pushPermission.userVisibleOnly()) { 89 if (!pushPermission.userVisibleOnly()) {
87 exceptionState.throwDOMException(NotSupportedError, "Push Permission without userVisibleOnly:true isn't supported yet."); 90 exceptionState.throwDOMException(NotSupportedError, "Push Permission without userVisibleOnly:true isn't supported yet.");
88 return Nullable<WebPermissionType>(); 91 return Nullable<PermissionName>();
89 } 92 }
90 } 93 }
91 94
92 return Nullable<WebPermissionType>(type); 95 return Nullable<PermissionName>(name);
93 } 96 }
94 97
95 } // anonymous namespace 98 } // anonymous namespace
96 99
97 // static 100 // static
98 WebPermissionClient* Permissions::getClient(ExecutionContext* executionContext) 101 bool Permissions::connectToService(ExecutionContext* executionContext, mojom::bl ink::PermissionServiceRequest request)
99 { 102 {
103 ServiceRegistry* serviceRegistry = nullptr;
100 if (executionContext->isDocument()) { 104 if (executionContext->isDocument()) {
101 Document* document = toDocument(executionContext); 105 Document* document = toDocument(executionContext);
102 if (!document->frame()) 106 if (document->frame())
103 return nullptr; 107 serviceRegistry = document->frame()->serviceRegistry();
104 PermissionController* controller = PermissionController::from(*document- >frame()); 108 } else {
105 return controller ? controller->client() : nullptr; 109 serviceRegistry = Platform::current()->serviceRegistry();
106 } 110 }
107 return Platform::current()->permissionClient(); 111
112 if (serviceRegistry)
113 serviceRegistry->connectToRemoteService(std::move(request));
114 return serviceRegistry;
108 } 115 }
109 116
110 ScriptPromise Permissions::query(ScriptState* scriptState, const Dictionary& raw Permission) 117 ScriptPromise Permissions::query(ScriptState* scriptState, const Dictionary& raw Permission)
111 { 118 {
112 ExceptionState exceptionState(ExceptionState::GetterContext, "query", "Perm issions", scriptState->context()->Global(), scriptState->isolate()); 119 ExceptionState exceptionState(ExceptionState::GetterContext, "query", "Perm issions", scriptState->context()->Global(), scriptState->isolate());
113 Nullable<WebPermissionType> type = parsePermission(scriptState, rawPermissio n, exceptionState); 120 Nullable<PermissionName> name = parsePermission(scriptState, rawPermission, exceptionState);
114 if (exceptionState.hadException()) 121 if (exceptionState.hadException())
115 return exceptionState.reject(scriptState); 122 return exceptionState.reject(scriptState);
116 123
117 // This must be called after `parsePermission` because the website might 124 // This must be called after `parsePermission` because the website might
118 // be able to run code. 125 // be able to run code.
119 WebPermissionClient* client = getClient(scriptState->getExecutionContext()); 126 PermissionService* service = getService(scriptState->getExecutionContext());
120 if (!client) 127 if (!service)
121 return ScriptPromise::rejectWithDOMException(scriptState, DOMException:: create(InvalidStateError, "In its current state, the global scope can't query pe rmissions.")); 128 return ScriptPromise::rejectWithDOMException(scriptState, DOMException:: create(InvalidStateError, "In its current state, the global scope can't query pe rmissions."));
122 129
123 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState) ; 130 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState) ;
124 ScriptPromise promise = resolver->promise(); 131 ScriptPromise promise = resolver->promise();
125 132
126 // If the current origin is a file scheme, it will unlikely return a 133 // If the current origin is a file scheme, it will unlikely return a
127 // meaningful value because most APIs are broken on file scheme and no 134 // meaningful value because most APIs are broken on file scheme and no
128 // permission prompt will be shown even if the returned permission will most 135 // permission prompt will be shown even if the returned permission will most
129 // likely be "prompt". 136 // likely be "prompt".
130 client->queryPermission(type.get(), KURL(KURL(), scriptState->getExecutionCo ntext()->getSecurityOrigin()->toString()), new PermissionCallback(resolver, type .get())); 137 service->HasPermission(name.get(), scriptState->getExecutionContext()->getSe curityOrigin()->toString(), convertToBaseCallback(WTF::bind(&Permissions::taskCo mplete, wrapPersistent(this), wrapPersistent(resolver), name.get())));
131 return promise; 138 return promise;
132 } 139 }
133 140
134 ScriptPromise Permissions::request(ScriptState* scriptState, const Dictionary& r awPermission) 141 ScriptPromise Permissions::request(ScriptState* scriptState, const Dictionary& r awPermission)
135 { 142 {
136 ExceptionState exceptionState(ExceptionState::GetterContext, "request", "Pe rmissions", scriptState->context()->Global(), scriptState->isolate()); 143 ExceptionState exceptionState(ExceptionState::GetterContext, "request", "Pe rmissions", scriptState->context()->Global(), scriptState->isolate());
137 Nullable<WebPermissionType> type = parsePermission(scriptState, rawPermissio n, exceptionState); 144 Nullable<PermissionName> name = parsePermission(scriptState, rawPermission, exceptionState);
138 if (exceptionState.hadException()) 145 if (exceptionState.hadException())
139 return exceptionState.reject(scriptState); 146 return exceptionState.reject(scriptState);
140 147
141 // This must be called after `parsePermission` because the website might 148 // This must be called after `parsePermission` because the website might
142 // be able to run code. 149 // be able to run code.
143 WebPermissionClient* client = getClient(scriptState->getExecutionContext()); 150 PermissionService* service = getService(scriptState->getExecutionContext());
144 if (!client) 151 if (!service)
145 return ScriptPromise::rejectWithDOMException(scriptState, DOMException:: create(InvalidStateError, "In its current state, the global scope can't request permissions.")); 152 return ScriptPromise::rejectWithDOMException(scriptState, DOMException:: create(InvalidStateError, "In its current state, the global scope can't request permissions."));
146 153
147 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState) ; 154 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState) ;
148 ScriptPromise promise = resolver->promise(); 155 ScriptPromise promise = resolver->promise();
149 156
150 client->requestPermission(type.get(), KURL(KURL(), scriptState->getExecution Context()->getSecurityOrigin()->toString()), new PermissionCallback(resolver, ty pe.get())); 157 service->RequestPermission(name.get(), scriptState->getExecutionContext()->g etSecurityOrigin()->toString(), UserGestureIndicator::processingUserGesture(), c onvertToBaseCallback(WTF::bind(&Permissions::taskComplete, wrapPersistent(this), wrapPersistent(resolver), name.get())));
151 return promise; 158 return promise;
152 } 159 }
153 160
154 ScriptPromise Permissions::revoke(ScriptState* scriptState, const Dictionary& ra wPermission) 161 ScriptPromise Permissions::revoke(ScriptState* scriptState, const Dictionary& ra wPermission)
155 { 162 {
156 ExceptionState exceptionState(ExceptionState::GetterContext, "revoke", "Per missions", scriptState->context()->Global(), scriptState->isolate()); 163 ExceptionState exceptionState(ExceptionState::GetterContext, "revoke", "Per missions", scriptState->context()->Global(), scriptState->isolate());
157 Nullable<WebPermissionType> type = parsePermission(scriptState, rawPermissio n, exceptionState); 164 Nullable<PermissionName> name = parsePermission(scriptState, rawPermission, exceptionState);
158 if (exceptionState.hadException()) 165 if (exceptionState.hadException())
159 return exceptionState.reject(scriptState); 166 return exceptionState.reject(scriptState);
160 167
161 // This must be called after `parsePermission` because the website might 168 // This must be called after `parsePermission` because the website might
162 // be able to run code. 169 // be able to run code.
163 WebPermissionClient* client = getClient(scriptState->getExecutionContext()); 170 PermissionService* service = getService(scriptState->getExecutionContext());
164 if (!client) 171 if (!service)
165 return ScriptPromise::rejectWithDOMException(scriptState, DOMException:: create(InvalidStateError, "In its current state, the global scope can't revoke p ermissions.")); 172 return ScriptPromise::rejectWithDOMException(scriptState, DOMException:: create(InvalidStateError, "In its current state, the global scope can't revoke p ermissions."));
166 173
167 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState) ; 174 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState) ;
168 ScriptPromise promise = resolver->promise(); 175 ScriptPromise promise = resolver->promise();
169 176
170 client->revokePermission(type.get(), KURL(KURL(), scriptState->getExecutionC ontext()->getSecurityOrigin()->toString()), new PermissionCallback(resolver, typ e.get())); 177 service->RevokePermission(name.get(), scriptState->getExecutionContext()->ge tSecurityOrigin()->toString(), convertToBaseCallback(WTF::bind(&Permissions::tas kComplete, wrapPersistent(this), wrapPersistent(resolver), name.get())));
171 return promise; 178 return promise;
172 } 179 }
173 180
174 ScriptPromise Permissions::requestAll(ScriptState* scriptState, const Vector<Dic tionary>& rawPermissions) 181 ScriptPromise Permissions::requestAll(ScriptState* scriptState, const Vector<Dic tionary>& rawPermissions)
175 { 182 {
176 ExceptionState exceptionState(ExceptionState::GetterContext, "request", "Pe rmissions", scriptState->context()->Global(), scriptState->isolate()); 183 ExceptionState exceptionState(ExceptionState::GetterContext, "request", "Pe rmissions", scriptState->context()->Global(), scriptState->isolate());
177 std::unique_ptr<Vector<WebPermissionType>> internalPermissions = wrapUnique( new Vector<WebPermissionType>()); 184 Vector<PermissionName> internalPermissions;
178 std::unique_ptr<Vector<int>> callerIndexToInternalIndex = wrapUnique(new Vec tor<int>(rawPermissions.size())); 185 Vector<int> callerIndexToInternalIndex;
186 callerIndexToInternalIndex.resize(rawPermissions.size());
179 for (size_t i = 0; i < rawPermissions.size(); ++i) { 187 for (size_t i = 0; i < rawPermissions.size(); ++i) {
180 const Dictionary& rawPermission = rawPermissions[i]; 188 const Dictionary& rawPermission = rawPermissions[i];
181 189
182 Nullable<WebPermissionType> type = parsePermission(scriptState, rawPermi ssion, exceptionState); 190 Nullable<PermissionName> name = parsePermission(scriptState, rawPermissi on, exceptionState);
183 if (exceptionState.hadException()) 191 if (exceptionState.hadException())
184 return exceptionState.reject(scriptState); 192 return exceptionState.reject(scriptState);
185 193
186 // Only append permissions to the vector that is passed to the client if it is not already 194 // Only append permissions to the vector that is passed to the client if it is not already
187 // in the vector (i.e. do not duplicate permisison types). 195 // in the vector (i.e. do not duplicate permisison types).
188 int internalIndex; 196 int internalIndex;
189 auto it = internalPermissions->find(type.get()); 197 auto it = internalPermissions.find(name.get());
190 if (it == kNotFound) { 198 if (it == kNotFound) {
191 internalIndex = internalPermissions->size(); 199 internalIndex = internalPermissions.size();
192 internalPermissions->append(type.get()); 200 internalPermissions.append(name.get());
193 } else { 201 } else {
194 internalIndex = it; 202 internalIndex = it;
195 } 203 }
196 callerIndexToInternalIndex->operator[](i) = internalIndex; 204 callerIndexToInternalIndex[i] = internalIndex;
197 } 205 }
198 206
199 // This must be called after `parsePermission` because the website might 207 // This must be called after `parsePermission` because the website might
200 // be able to run code. 208 // be able to run code.
201 WebPermissionClient* client = getClient(scriptState->getExecutionContext()); 209 PermissionService* service = getService(scriptState->getExecutionContext());
202 if (!client) 210 if (!service)
203 return ScriptPromise::rejectWithDOMException(scriptState, DOMException:: create(InvalidStateError, "In its current state, the global scope can't request permissions.")); 211 return ScriptPromise::rejectWithDOMException(scriptState, DOMException:: create(InvalidStateError, "In its current state, the global scope can't request permissions."));
204 212
205 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState) ; 213 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState) ;
206 ScriptPromise promise = resolver->promise(); 214 ScriptPromise promise = resolver->promise();
207 215
208 WebVector<WebPermissionType> internalWebPermissions = *internalPermissions; 216 Vector<PermissionName> internalPermissionsCopy(internalPermissions);
209 client->requestPermissions(internalWebPermissions, KURL(KURL(), scriptState- >getExecutionContext()->getSecurityOrigin()->toString()), 217 service->RequestPermissions(std::move(internalPermissions), scriptState->get ExecutionContext()->getSecurityOrigin()->toString(), UserGestureIndicator::proce ssingUserGesture(),
210 new PermissionsCallback(resolver, std::move(internalPermissions), std::m ove(callerIndexToInternalIndex))); 218 convertToBaseCallback(WTF::bind(&Permissions::batchTaskComplete, wrapPer sistent(this), wrapPersistent(resolver), std::move(internalPermissionsCopy), std ::move(callerIndexToInternalIndex))));
211 return promise; 219 return promise;
212 } 220 }
213 221
222 PermissionService* Permissions::getService(ExecutionContext* executionContext)
223 {
224 if (!m_service && connectToService(executionContext, mojo::GetProxy(&m_servi ce)))
225 m_service.set_connection_error_handler(convertToBaseCallback(WTF::bind(& Permissions::serviceConnectionError, wrapWeakPersistent(this))));
226 return m_service.get();
227 }
228
229 void Permissions::serviceConnectionError()
230 {
231 m_service.reset();
232 }
233
234 void Permissions::taskComplete(ScriptPromiseResolver* resolver, PermissionName n ame, mojom::blink::PermissionStatus result)
235 {
236 if (!resolver->getExecutionContext() || resolver->getExecutionContext()->act iveDOMObjectsAreStopped())
237 return;
238 resolver->resolve(PermissionStatus::take(resolver, result, name));
239 }
240
241 void Permissions::batchTaskComplete(ScriptPromiseResolver* resolver, Vector<Perm issionName> names, Vector<int> callerIndexToInternalIndex, mojo::WTFArray<mojom: :blink::PermissionStatus> results)
242 {
243 if (!resolver->getExecutionContext() || resolver->getExecutionContext()->act iveDOMObjectsAreStopped())
244 return;
245
246 // Create the response vector by finding the status for each index by
247 // using the caller to internal index mapping and looking up the status
248 // using the internal index obtained.
249 HeapVector<Member<PermissionStatus>> result;
250 result.reserveInitialCapacity(callerIndexToInternalIndex.size());
251 for (int internalIndex : callerIndexToInternalIndex)
252 result.append(PermissionStatus::createAndListen(resolver->getExecutionCo ntext(), results[internalIndex], names[internalIndex]));
253 resolver->resolve(result);
254 }
255
214 } // namespace blink 256 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698