Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #ifdef MOZ_WIDGET_GONK
6 #include "GonkPermission.h"
7 #include "mozilla/dom/ContentParent.h"
8 #endif // MOZ_WIDGET_GONK
9 #include "nsCOMPtr.h"
10 #include "nsIDOMElement.h"
11 #include "nsIPrincipal.h"
12 #include "mozilla/dom/Element.h"
13 #include "mozilla/dom/PContentPermission.h"
14 #include "mozilla/dom/PermissionMessageUtils.h"
15 #include "mozilla/dom/PContentPermissionRequestParent.h"
16 #include "mozilla/dom/TabParent.h"
17 #include "mozilla/unused.h"
18 #include "nsComponentManagerUtils.h"
19 #include "nsArrayUtils.h"
20 #include "nsIMutableArray.h"
21 #include "nsContentPermissionHelper.h"
22 #include "nsCxPusher.h"
23 #include "nsJSUtils.h"
24 #include "nsISupportsPrimitives.h"
26 using mozilla::unused; // <snicker>
27 using namespace mozilla::dom;
28 using namespace mozilla;
30 namespace mozilla {
31 namespace dom {
33 class ContentPermissionRequestParent : public PContentPermissionRequestParent
34 {
35 public:
36 ContentPermissionRequestParent(const nsTArray<PermissionRequest>& aRequests,
37 Element* element,
38 const IPC::Principal& principal);
39 virtual ~ContentPermissionRequestParent();
41 bool IsBeingDestroyed();
43 nsCOMPtr<nsIPrincipal> mPrincipal;
44 nsCOMPtr<Element> mElement;
45 nsRefPtr<nsContentPermissionRequestProxy> mProxy;
46 nsTArray<PermissionRequest> mRequests;
48 private:
49 virtual bool Recvprompt();
50 virtual void ActorDestroy(ActorDestroyReason why);
51 };
53 ContentPermissionRequestParent::ContentPermissionRequestParent(const nsTArray<PermissionRequest>& aRequests,
54 Element* aElement,
55 const IPC::Principal& aPrincipal)
56 {
57 MOZ_COUNT_CTOR(ContentPermissionRequestParent);
59 mPrincipal = aPrincipal;
60 mElement = aElement;
61 mRequests = aRequests;
62 }
64 ContentPermissionRequestParent::~ContentPermissionRequestParent()
65 {
66 MOZ_COUNT_DTOR(ContentPermissionRequestParent);
67 }
69 bool
70 ContentPermissionRequestParent::Recvprompt()
71 {
72 mProxy = new nsContentPermissionRequestProxy();
73 NS_ASSERTION(mProxy, "Alloc of request proxy failed");
74 if (NS_FAILED(mProxy->Init(mRequests, this))) {
75 mProxy->Cancel();
76 }
77 return true;
78 }
80 void
81 ContentPermissionRequestParent::ActorDestroy(ActorDestroyReason why)
82 {
83 if (mProxy) {
84 mProxy->OnParentDestroyed();
85 }
86 }
88 bool
89 ContentPermissionRequestParent::IsBeingDestroyed()
90 {
91 // When TabParent::Destroy() is called, we are being destroyed. It's unsafe
92 // to send out any message now.
93 TabParent* tabParent = static_cast<TabParent*>(Manager());
94 return tabParent->IsDestroyed();
95 }
97 NS_IMPL_ISUPPORTS(ContentPermissionType, nsIContentPermissionType)
99 ContentPermissionType::ContentPermissionType(const nsACString& aType,
100 const nsACString& aAccess,
101 const nsTArray<nsString>& aOptions)
102 {
103 mType = aType;
104 mAccess = aAccess;
105 mOptions = aOptions;
106 }
108 ContentPermissionType::~ContentPermissionType()
109 {
110 }
112 NS_IMETHODIMP
113 ContentPermissionType::GetType(nsACString& aType)
114 {
115 aType = mType;
116 return NS_OK;
117 }
119 NS_IMETHODIMP
120 ContentPermissionType::GetAccess(nsACString& aAccess)
121 {
122 aAccess = mAccess;
123 return NS_OK;
124 }
126 NS_IMETHODIMP
127 ContentPermissionType::GetOptions(nsIArray** aOptions)
128 {
129 NS_ENSURE_ARG_POINTER(aOptions);
131 *aOptions = nullptr;
133 nsresult rv;
134 nsCOMPtr<nsIMutableArray> options =
135 do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
136 NS_ENSURE_SUCCESS(rv, rv);
138 // copy options into JS array
139 for (uint32_t i = 0; i < mOptions.Length(); ++i) {
140 nsCOMPtr<nsISupportsString> isupportsString =
141 do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv);
142 NS_ENSURE_SUCCESS(rv, rv);
144 rv = isupportsString->SetData(mOptions[i]);
145 NS_ENSURE_SUCCESS(rv, rv);
147 rv = options->AppendElement(isupportsString, false);
148 NS_ENSURE_SUCCESS(rv, rv);
149 }
151 NS_ADDREF(*aOptions = options);
152 return NS_OK;
153 }
155 uint32_t
156 ConvertPermissionRequestToArray(nsTArray<PermissionRequest>& aSrcArray,
157 nsIMutableArray* aDesArray)
158 {
159 uint32_t len = aSrcArray.Length();
160 for (uint32_t i = 0; i < len; i++) {
161 nsRefPtr<ContentPermissionType> cpt =
162 new ContentPermissionType(aSrcArray[i].type(),
163 aSrcArray[i].access(),
164 aSrcArray[i].options());
165 aDesArray->AppendElement(cpt, false);
166 }
167 return len;
168 }
170 nsresult
171 CreatePermissionArray(const nsACString& aType,
172 const nsACString& aAccess,
173 const nsTArray<nsString>& aOptions,
174 nsIArray** aTypesArray)
175 {
176 nsCOMPtr<nsIMutableArray> types = do_CreateInstance(NS_ARRAY_CONTRACTID);
177 nsRefPtr<ContentPermissionType> permType = new ContentPermissionType(aType,
178 aAccess,
179 aOptions);
180 types->AppendElement(permType, false);
181 types.forget(aTypesArray);
183 return NS_OK;
184 }
186 PContentPermissionRequestParent*
187 CreateContentPermissionRequestParent(const nsTArray<PermissionRequest>& aRequests,
188 Element* element,
189 const IPC::Principal& principal)
190 {
191 return new ContentPermissionRequestParent(aRequests, element, principal);
192 }
194 } // namespace dom
195 } // namespace mozilla
197 nsContentPermissionRequestProxy::nsContentPermissionRequestProxy()
198 {
199 MOZ_COUNT_CTOR(nsContentPermissionRequestProxy);
200 }
202 nsContentPermissionRequestProxy::~nsContentPermissionRequestProxy()
203 {
204 MOZ_COUNT_DTOR(nsContentPermissionRequestProxy);
205 }
207 nsresult
208 nsContentPermissionRequestProxy::Init(const nsTArray<PermissionRequest>& requests,
209 ContentPermissionRequestParent* parent)
210 {
211 NS_ASSERTION(parent, "null parent");
212 mParent = parent;
213 mPermissionRequests = requests;
215 nsCOMPtr<nsIContentPermissionPrompt> prompt = do_CreateInstance(NS_CONTENT_PERMISSION_PROMPT_CONTRACTID);
216 if (!prompt) {
217 return NS_ERROR_FAILURE;
218 }
220 prompt->Prompt(this);
221 return NS_OK;
222 }
224 void
225 nsContentPermissionRequestProxy::OnParentDestroyed()
226 {
227 mParent = nullptr;
228 }
230 NS_IMPL_ISUPPORTS(nsContentPermissionRequestProxy, nsIContentPermissionRequest)
232 NS_IMETHODIMP
233 nsContentPermissionRequestProxy::GetTypes(nsIArray** aTypes)
234 {
235 nsCOMPtr<nsIMutableArray> types = do_CreateInstance(NS_ARRAY_CONTRACTID);
236 if (ConvertPermissionRequestToArray(mPermissionRequests, types)) {
237 types.forget(aTypes);
238 return NS_OK;
239 }
240 return NS_ERROR_FAILURE;
241 }
243 NS_IMETHODIMP
244 nsContentPermissionRequestProxy::GetWindow(nsIDOMWindow * *aRequestingWindow)
245 {
246 NS_ENSURE_ARG_POINTER(aRequestingWindow);
247 *aRequestingWindow = nullptr; // ipc doesn't have a window
248 return NS_OK;
249 }
251 NS_IMETHODIMP
252 nsContentPermissionRequestProxy::GetPrincipal(nsIPrincipal * *aRequestingPrincipal)
253 {
254 NS_ENSURE_ARG_POINTER(aRequestingPrincipal);
255 if (mParent == nullptr) {
256 return NS_ERROR_FAILURE;
257 }
259 NS_ADDREF(*aRequestingPrincipal = mParent->mPrincipal);
260 return NS_OK;
261 }
263 NS_IMETHODIMP
264 nsContentPermissionRequestProxy::GetElement(nsIDOMElement * *aRequestingElement)
265 {
266 NS_ENSURE_ARG_POINTER(aRequestingElement);
267 if (mParent == nullptr) {
268 return NS_ERROR_FAILURE;
269 }
271 nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(mParent->mElement);
272 elem.forget(aRequestingElement);
273 return NS_OK;
274 }
276 NS_IMETHODIMP
277 nsContentPermissionRequestProxy::Cancel()
278 {
279 if (mParent == nullptr) {
280 return NS_ERROR_FAILURE;
281 }
283 // Don't send out the delete message when the managing protocol (PBrowser) is
284 // being destroyed and PContentPermissionRequest will soon be.
285 if (mParent->IsBeingDestroyed()) {
286 return NS_ERROR_FAILURE;
287 }
289 nsTArray<PermissionChoice> emptyChoices;
291 unused << ContentPermissionRequestParent::Send__delete__(mParent, false, emptyChoices);
292 mParent = nullptr;
293 return NS_OK;
294 }
296 NS_IMETHODIMP
297 nsContentPermissionRequestProxy::Allow(JS::HandleValue aChoices)
298 {
299 if (mParent == nullptr) {
300 return NS_ERROR_FAILURE;
301 }
303 // Don't send out the delete message when the managing protocol (PBrowser) is
304 // being destroyed and PContentPermissionRequest will soon be.
305 if (mParent->IsBeingDestroyed()) {
306 return NS_ERROR_FAILURE;
307 }
309 #ifdef MOZ_WIDGET_GONK
310 uint32_t len = mPermissionRequests.Length();
311 for (uint32_t i = 0; i < len; i++) {
312 if (mPermissionRequests[i].type().Equals("audio-capture")) {
313 GonkPermissionService::GetInstance()->addGrantInfo(
314 "android.permission.RECORD_AUDIO",
315 static_cast<TabParent*>(mParent->Manager())->Manager()->Pid());
316 }
317 if (mPermissionRequests[i].type().Equals("video-capture")) {
318 GonkPermissionService::GetInstance()->addGrantInfo(
319 "android.permission.CAMERA",
320 static_cast<TabParent*>(mParent->Manager())->Manager()->Pid());
321 }
322 }
323 #endif
325 nsTArray<PermissionChoice> choices;
326 if (aChoices.isNullOrUndefined()) {
327 // No choice is specified.
328 } else if (aChoices.isObject()) {
329 // Iterate through all permission types.
330 for (uint32_t i = 0; i < mPermissionRequests.Length(); ++i) {
331 nsCString type = mPermissionRequests[i].type();
333 mozilla::AutoSafeJSContext cx;
334 JS::Rooted<JSObject*> obj(cx, &aChoices.toObject());
335 JSAutoCompartment ac(cx, obj);
337 JS::Rooted<JS::Value> val(cx);
339 if (!JS_GetProperty(cx, obj, type.BeginReading(), &val) ||
340 !val.isString()) {
341 // no setting for the permission type, skip it
342 } else {
343 nsDependentJSString choice;
344 if (!choice.init(cx, val)) {
345 return NS_ERROR_FAILURE;
346 }
347 choices.AppendElement(PermissionChoice(type, choice));
348 }
349 }
350 } else {
351 MOZ_ASSERT(false, "SelectedChoices should be undefined or an JS object");
352 return NS_ERROR_FAILURE;
353 }
355 unused << ContentPermissionRequestParent::Send__delete__(mParent, true, choices);
356 mParent = nullptr;
357 return NS_OK;
358 }