Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim:set ts=2 sw=2 sts=2 et cindent: */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #include "mozilla/ClearOnShutdown.h"
8 : #include "PaymentRequestData.h"
9 : #include "PaymentRequestService.h"
10 :
11 : namespace mozilla {
12 : namespace dom {
13 :
14 3 : StaticRefPtr<PaymentRequestService> gPaymentService;
15 :
16 : namespace {
17 :
18 : class PaymentRequestEnumerator final : public nsISimpleEnumerator
19 : {
20 : public:
21 : NS_DECL_ISUPPORTS
22 : NS_DECL_NSISIMPLEENUMERATOR
23 :
24 0 : PaymentRequestEnumerator()
25 0 : : mIndex(0)
26 0 : {}
27 : private:
28 : ~PaymentRequestEnumerator() = default;
29 : uint32_t mIndex;
30 : };
31 :
32 0 : NS_IMPL_ISUPPORTS(PaymentRequestEnumerator, nsISimpleEnumerator)
33 :
34 : NS_IMETHODIMP
35 0 : PaymentRequestEnumerator::HasMoreElements(bool* aReturn)
36 : {
37 0 : NS_ENSURE_ARG_POINTER(aReturn);
38 0 : *aReturn = false;
39 0 : if (NS_WARN_IF(!gPaymentService)) {
40 0 : return NS_ERROR_FAILURE;
41 : }
42 0 : RefPtr<PaymentRequestService> service = gPaymentService;
43 0 : *aReturn = mIndex < service->NumPayments();
44 0 : return NS_OK;
45 : }
46 :
47 : NS_IMETHODIMP
48 0 : PaymentRequestEnumerator::GetNext(nsISupports** aItem)
49 : {
50 0 : NS_ENSURE_ARG_POINTER(aItem);
51 0 : if (NS_WARN_IF(!gPaymentService)) {
52 0 : return NS_ERROR_FAILURE;
53 : }
54 : nsCOMPtr<nsIPaymentRequest> request =
55 0 : gPaymentService->GetPaymentRequestByIndex(mIndex);
56 0 : if (NS_WARN_IF(!request)) {
57 0 : return NS_ERROR_FAILURE;
58 : }
59 0 : nsCOMPtr<nsISupports> item = do_QueryInterface(request);
60 0 : if (NS_WARN_IF(!item)) {
61 0 : return NS_ERROR_FAILURE;
62 : }
63 0 : mIndex++;
64 0 : item.forget(aItem);
65 0 : return NS_OK;
66 : }
67 :
68 : } // end of anonymous namespace
69 :
70 : /* PaymentRequestService */
71 :
72 0 : NS_IMPL_ISUPPORTS(PaymentRequestService,
73 : nsIPaymentRequestService)
74 :
75 : already_AddRefed<PaymentRequestService>
76 0 : PaymentRequestService::GetSingleton()
77 : {
78 0 : MOZ_ASSERT(NS_IsMainThread());
79 0 : if (!gPaymentService) {
80 0 : gPaymentService = new PaymentRequestService();
81 0 : ClearOnShutdown(&gPaymentService);
82 : }
83 0 : RefPtr<PaymentRequestService> service = gPaymentService;
84 0 : return service.forget();
85 : }
86 :
87 : uint32_t
88 0 : PaymentRequestService::NumPayments() const
89 : {
90 0 : return mRequestQueue.Length();
91 : }
92 :
93 : already_AddRefed<nsIPaymentRequest>
94 0 : PaymentRequestService::GetPaymentRequestByIndex(const uint32_t aIndex)
95 : {
96 0 : if (aIndex >= mRequestQueue.Length()) {
97 0 : return nullptr;
98 : }
99 0 : nsCOMPtr<nsIPaymentRequest> request = mRequestQueue[aIndex];
100 0 : MOZ_ASSERT(request);
101 0 : return request.forget();
102 : }
103 :
104 : NS_IMETHODIMP
105 0 : PaymentRequestService::GetPaymentRequestById(const nsAString& aRequestId,
106 : nsIPaymentRequest** aRequest)
107 : {
108 0 : NS_ENSURE_ARG_POINTER(aRequest);
109 0 : *aRequest = nullptr;
110 0 : uint32_t numRequests = mRequestQueue.Length();
111 0 : for (uint32_t index = 0; index < numRequests; ++index) {
112 0 : nsCOMPtr<nsIPaymentRequest> request = mRequestQueue[index];
113 0 : MOZ_ASSERT(request);
114 0 : nsAutoString requestId;
115 0 : nsresult rv = request->GetRequestId(requestId);
116 0 : NS_ENSURE_SUCCESS(rv, rv);
117 0 : if (requestId == aRequestId) {
118 0 : request.forget(aRequest);
119 0 : break;
120 : }
121 : }
122 0 : return NS_OK;
123 : }
124 :
125 : NS_IMETHODIMP
126 0 : PaymentRequestService::Enumerate(nsISimpleEnumerator** aEnumerator)
127 : {
128 0 : NS_ENSURE_ARG_POINTER(aEnumerator);
129 0 : nsCOMPtr<nsISimpleEnumerator> enumerator = new PaymentRequestEnumerator();
130 0 : enumerator.forget(aEnumerator);
131 0 : return NS_OK;
132 : }
133 :
134 : NS_IMETHODIMP
135 0 : PaymentRequestService::Cleanup()
136 : {
137 0 : mRequestQueue.Clear();
138 0 : return NS_OK;
139 : }
140 :
141 : NS_IMETHODIMP
142 0 : PaymentRequestService::SetTestingUIService(nsIPaymentUIService* aUIService)
143 : {
144 : // aUIService can be nullptr
145 0 : mTestingUIService = aUIService;
146 0 : return NS_OK;
147 : }
148 :
149 : nsresult
150 0 : PaymentRequestService::CallTestingUIAction(const nsAString& aRequestId, uint32_t aActionType)
151 : {
152 0 : nsCOMPtr<nsIPaymentActionResponse> response;
153 : nsresult rv;
154 0 : if (mTestingUIService) {
155 0 : switch (aActionType) {
156 : case nsIPaymentActionRequest::CANMAKE_ACTION: {
157 0 : rv = mTestingUIService->CanMakePayment(aRequestId, getter_AddRefs(response));
158 0 : break;
159 : }
160 : case nsIPaymentActionRequest::SHOW_ACTION: {
161 0 : rv = mTestingUIService->ShowPayment(aRequestId, getter_AddRefs(response));
162 0 : break;
163 : }
164 : case nsIPaymentActionRequest::ABORT_ACTION: {
165 0 : rv = mTestingUIService->AbortPayment(aRequestId, getter_AddRefs(response));
166 0 : break;
167 : }
168 : case nsIPaymentActionRequest::COMPLETE_ACTION: {
169 0 : rv = mTestingUIService->CompletePayment(aRequestId, getter_AddRefs(response));
170 0 : break;
171 : }
172 : case nsIPaymentActionRequest::UPDATE_ACTION: {
173 0 : rv = mTestingUIService->UpdatePayment(aRequestId, getter_AddRefs(response));
174 0 : break;
175 : }
176 : default : {
177 0 : return NS_ERROR_FAILURE;
178 : }
179 : }
180 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
181 0 : return rv;
182 : }
183 : } else {
184 : // Since there is no UI implementation and no testing UI Service is registered,
185 : // set false response for canMakePayment(), ABORT_SUCCEEDED for abort() and
186 : // COMPLETE_SUCCEEDED for complete().
187 0 : switch (aActionType) {
188 : case nsIPaymentActionRequest::CANMAKE_ACTION: {
189 : nsCOMPtr<nsIPaymentCanMakeActionResponse> canMakeResponse =
190 0 : do_CreateInstance(NS_PAYMENT_CANMAKE_ACTION_RESPONSE_CONTRACT_ID);
191 0 : MOZ_ASSERT(canMakeResponse);
192 0 : rv = canMakeResponse->Init(aRequestId, false);
193 0 : NS_ENSURE_SUCCESS(rv, rv);
194 0 : response = do_QueryInterface(canMakeResponse);
195 0 : MOZ_ASSERT(response);
196 0 : break;
197 : }
198 : case nsIPaymentActionRequest::ABORT_ACTION: {
199 : nsCOMPtr<nsIPaymentAbortActionResponse> abortResponse =
200 0 : do_CreateInstance(NS_PAYMENT_ABORT_ACTION_RESPONSE_CONTRACT_ID);
201 0 : MOZ_ASSERT(abortResponse);
202 0 : rv = abortResponse->Init(aRequestId, nsIPaymentActionResponse::ABORT_SUCCEEDED);
203 0 : NS_ENSURE_SUCCESS(rv, rv);
204 0 : response = do_QueryInterface(abortResponse);
205 0 : MOZ_ASSERT(response);
206 0 : break;
207 : }
208 : case nsIPaymentActionRequest::COMPLETE_ACTION: {
209 : nsCOMPtr<nsIPaymentCompleteActionResponse> completeResponse =
210 0 : do_CreateInstance(NS_PAYMENT_COMPLETE_ACTION_RESPONSE_CONTRACT_ID);
211 0 : MOZ_ASSERT(completeResponse);
212 0 : rv = completeResponse->Init(aRequestId, nsIPaymentActionResponse::COMPLETE_SUCCEEDED);
213 0 : NS_ENSURE_SUCCESS(rv, rv);
214 0 : response = do_QueryInterface(completeResponse);
215 0 : MOZ_ASSERT(response);
216 0 : break;
217 : }
218 : default : {
219 0 : break;
220 : }
221 : }
222 : }
223 0 : if (response) {
224 0 : rv = RespondPayment(response);
225 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
226 0 : return rv;
227 : }
228 : }
229 0 : return NS_OK;
230 : }
231 :
232 : NS_IMETHODIMP
233 0 : PaymentRequestService::RemoveActionCallback(nsIPaymentActionCallback* aCallback)
234 : {
235 0 : NS_ENSURE_ARG_POINTER(aCallback);
236 0 : for (auto iter = mCallbackHashtable.Iter(); !iter.Done(); iter.Next()) {
237 0 : nsCOMPtr<nsIPaymentActionCallback> callback = iter.Data();
238 0 : MOZ_ASSERT(callback);
239 0 : if (callback == aCallback) {
240 0 : iter.Remove();
241 0 : return NS_OK;
242 : }
243 : }
244 0 : return NS_OK;
245 : }
246 :
247 : NS_IMETHODIMP
248 0 : PaymentRequestService::RequestPayment(nsIPaymentActionRequest* aRequest)
249 : {
250 0 : NS_ENSURE_ARG_POINTER(aRequest);
251 :
252 0 : nsAutoString requestId;
253 0 : nsresult rv = aRequest->GetRequestId(requestId);
254 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
255 0 : return rv;
256 : }
257 0 : nsCOMPtr<nsIPaymentActionCallback> callback;
258 0 : rv = aRequest->GetCallback(getter_AddRefs(callback));
259 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
260 0 : return rv;
261 : }
262 0 : rv = SetActionCallback(requestId, callback);
263 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
264 0 : return rv;
265 : }
266 :
267 : uint32_t type;
268 0 : rv = aRequest->GetType(&type);
269 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
270 0 : return rv;
271 : }
272 :
273 0 : switch (type) {
274 : case nsIPaymentActionRequest::CREATE_ACTION: {
275 : nsCOMPtr<nsIPaymentCreateActionRequest> request =
276 0 : do_QueryInterface(aRequest);
277 0 : MOZ_ASSERT(request);
278 : uint64_t tabId;
279 0 : rv = request->GetTabId(&tabId);
280 0 : NS_ENSURE_SUCCESS(rv, rv);
281 :
282 0 : nsCOMPtr<nsIArray> methodData;
283 0 : rv = request->GetMethodData(getter_AddRefs(methodData));
284 0 : NS_ENSURE_SUCCESS(rv, rv);
285 :
286 0 : nsCOMPtr<nsIPaymentDetails> details;
287 0 : rv = request->GetDetails(getter_AddRefs(details));
288 0 : NS_ENSURE_SUCCESS(rv, rv);
289 :
290 0 : nsCOMPtr<nsIPaymentOptions> options;
291 0 : rv = request->GetOptions(getter_AddRefs(options));
292 0 : NS_ENSURE_SUCCESS(rv, rv);
293 :
294 : nsCOMPtr<nsIPaymentRequest> payment =
295 0 : new payments::PaymentRequest(tabId, requestId, methodData, details, options);
296 :
297 0 : if (!mRequestQueue.AppendElement(payment, mozilla::fallible)) {
298 0 : return NS_ERROR_OUT_OF_MEMORY;
299 : }
300 0 : break;
301 : }
302 : /*
303 : * TODO: 1. Check basic card support once the Basic Card Payment spec is
304 : * implemented.
305 : * https://www.w3.org/TR/payment-method-basic-card/
306 : * 2. Check third party payment app support by traversing all
307 : * registered third party payment apps.
308 : */
309 : case nsIPaymentActionRequest::CANMAKE_ACTION:
310 : /*
311 : * TODO: Launch/inform payment UI here once the UI module is implemented.
312 : */
313 : case nsIPaymentActionRequest::SHOW_ACTION:
314 : case nsIPaymentActionRequest::ABORT_ACTION:
315 : case nsIPaymentActionRequest::COMPLETE_ACTION: {
316 0 : rv = CallTestingUIAction(requestId, type);
317 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
318 0 : return NS_ERROR_FAILURE;
319 : }
320 0 : break;
321 : }
322 : case nsIPaymentActionRequest::UPDATE_ACTION: {
323 0 : nsCOMPtr<nsIPaymentUpdateActionRequest> request = do_QueryInterface(aRequest);
324 0 : MOZ_ASSERT(request);
325 :
326 0 : nsCOMPtr<nsIPaymentDetails> details;
327 0 : rv = request->GetDetails(getter_AddRefs(details));
328 0 : NS_ENSURE_SUCCESS(rv, rv);
329 :
330 0 : rv = request->GetRequestId(requestId);
331 0 : NS_ENSURE_SUCCESS(rv, rv);
332 0 : nsCOMPtr<nsIPaymentRequest> payment;
333 0 : rv = GetPaymentRequestById(requestId, getter_AddRefs(payment));
334 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
335 0 : return rv;
336 : }
337 0 : rv = payment->UpdatePaymentDetails(details);
338 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
339 0 : return rv;
340 : }
341 0 : rv = CallTestingUIAction(requestId, type);
342 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
343 0 : return NS_ERROR_FAILURE;
344 : }
345 0 : break;
346 : }
347 : default: {
348 0 : return NS_ERROR_FAILURE;
349 : }
350 : }
351 0 : return NS_OK;
352 : }
353 :
354 : NS_IMETHODIMP
355 0 : PaymentRequestService::RespondPayment(nsIPaymentActionResponse* aResponse)
356 : {
357 0 : NS_ENSURE_ARG_POINTER(aResponse);
358 0 : nsAutoString requestId;
359 0 : nsresult rv = aResponse->GetRequestId(requestId);
360 0 : NS_ENSURE_SUCCESS(rv, rv);
361 :
362 0 : nsCOMPtr<nsIPaymentRequest> request;
363 0 : rv = GetPaymentRequestById(requestId, getter_AddRefs(request));
364 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
365 0 : return rv;
366 : }
367 :
368 0 : nsCOMPtr<nsIPaymentActionCallback> callback;
369 0 : if (!mCallbackHashtable.Get(requestId, getter_AddRefs(callback))) {
370 0 : return NS_ERROR_FAILURE;
371 : }
372 0 : if (NS_WARN_IF(!callback)) {
373 0 : return NS_ERROR_FAILURE;
374 : }
375 0 : rv = callback->RespondPayment(aResponse);
376 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
377 0 : return rv;
378 : }
379 :
380 : // Remove nsIPaymentRequest from mRequestQueue while receive succeeded abort
381 : // response or complete response
382 : uint32_t type;
383 0 : rv = aResponse->GetType(&type);
384 0 : NS_ENSURE_SUCCESS(rv, rv);
385 0 : switch (type) {
386 : case nsIPaymentActionResponse::ABORT_ACTION: {
387 : nsCOMPtr<nsIPaymentAbortActionResponse> response =
388 0 : do_QueryInterface(aResponse);
389 0 : MOZ_ASSERT(response);
390 : bool isSucceeded;
391 0 : rv = response->IsSucceeded(&isSucceeded);
392 0 : NS_ENSURE_SUCCESS(rv, rv);
393 0 : if (isSucceeded) {
394 0 : mRequestQueue.RemoveElement(request);
395 : }
396 0 : break;
397 : }
398 : case nsIPaymentActionResponse::COMPLETE_ACTION: {
399 0 : mRequestQueue.RemoveElement(request);
400 0 : break;
401 : }
402 : default: {
403 0 : break;
404 : }
405 : }
406 0 : return NS_OK;
407 : }
408 :
409 : NS_IMETHODIMP
410 0 : PaymentRequestService::ChangeShippingAddress(const nsAString& aRequestId,
411 : nsIPaymentAddress* aAddress)
412 : {
413 0 : nsCOMPtr<nsIPaymentActionCallback> callback;
414 0 : if (!mCallbackHashtable.Get(aRequestId, getter_AddRefs(callback))) {
415 0 : return NS_ERROR_FAILURE;
416 : }
417 0 : if (NS_WARN_IF(!callback)) {
418 0 : return NS_ERROR_FAILURE;
419 : }
420 :
421 0 : nsresult rv = callback->ChangeShippingAddress(aRequestId, aAddress);
422 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
423 0 : return rv;
424 : }
425 0 : return NS_OK;
426 : }
427 :
428 : NS_IMETHODIMP
429 0 : PaymentRequestService::ChangeShippingOption(const nsAString& aRequestId,
430 : const nsAString& aOption)
431 : {
432 0 : nsCOMPtr<nsIPaymentActionCallback> callback;
433 0 : if (!mCallbackHashtable.Get(aRequestId, getter_AddRefs(callback))) {
434 0 : return NS_ERROR_FAILURE;
435 : }
436 0 : if (NS_WARN_IF(!callback)) {
437 0 : return NS_ERROR_FAILURE;
438 : }
439 :
440 0 : nsresult rv = callback->ChangeShippingOption(aRequestId, aOption);
441 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
442 0 : return rv;
443 : }
444 :
445 0 : return NS_OK;
446 : }
447 :
448 : nsresult
449 0 : PaymentRequestService::SetActionCallback(const nsAString& aRequestId,
450 : nsIPaymentActionCallback* aCallback)
451 : {
452 0 : NS_ENSURE_ARG_POINTER(aCallback);
453 0 : nsCOMPtr<nsIPaymentActionCallback> callback;
454 0 : if (mCallbackHashtable.Get(aRequestId, getter_AddRefs(callback))) {
455 0 : mCallbackHashtable.Remove(aRequestId);
456 : }
457 0 : mCallbackHashtable.Put(aRequestId, aCallback);
458 0 : return NS_OK;
459 : }
460 :
461 : nsresult
462 0 : PaymentRequestService::RemoveActionCallback(const nsAString& aRequestId)
463 : {
464 0 : nsCOMPtr<nsIPaymentActionCallback> callback;
465 0 : if (!mCallbackHashtable.Get(aRequestId, getter_AddRefs(callback))) {
466 0 : return NS_ERROR_FAILURE;
467 : }
468 0 : mCallbackHashtable.Remove(aRequestId);
469 0 : return NS_OK;
470 : }
471 :
472 : } // end of namespace dom
473 : } // end of namespace mozilla
|