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