OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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/payments/PaymentRequest.h" | 5 #include "modules/payments/PaymentRequest.h" |
6 | 6 |
7 #include "bindings/core/v8/ExceptionState.h" | 7 #include "bindings/core/v8/ExceptionState.h" |
8 #include "bindings/core/v8/JSONValuesForV8.h" | 8 #include "bindings/core/v8/JSONValuesForV8.h" |
9 #include "bindings/core/v8/ScriptPromiseResolver.h" | 9 #include "bindings/core/v8/ScriptPromiseResolver.h" |
10 #include "bindings/core/v8/ScriptState.h" | 10 #include "bindings/core/v8/ScriptState.h" |
(...skipping 17 matching lines...) Expand all Loading... |
28 #include <utility> | 28 #include <utility> |
29 | 29 |
30 namespace mojo { | 30 namespace mojo { |
31 | 31 |
32 using blink::mojom::blink::CurrencyAmount; | 32 using blink::mojom::blink::CurrencyAmount; |
33 using blink::mojom::blink::CurrencyAmountPtr; | 33 using blink::mojom::blink::CurrencyAmountPtr; |
34 using blink::mojom::blink::PaymentDetails; | 34 using blink::mojom::blink::PaymentDetails; |
35 using blink::mojom::blink::PaymentDetailsPtr; | 35 using blink::mojom::blink::PaymentDetailsPtr; |
36 using blink::mojom::blink::PaymentItem; | 36 using blink::mojom::blink::PaymentItem; |
37 using blink::mojom::blink::PaymentItemPtr; | 37 using blink::mojom::blink::PaymentItemPtr; |
| 38 using blink::mojom::blink::PaymentMethodData; |
| 39 using blink::mojom::blink::PaymentMethodDataPtr; |
38 using blink::mojom::blink::PaymentOptions; | 40 using blink::mojom::blink::PaymentOptions; |
39 using blink::mojom::blink::PaymentOptionsPtr; | 41 using blink::mojom::blink::PaymentOptionsPtr; |
40 using blink::mojom::blink::ShippingOption; | 42 using blink::mojom::blink::ShippingOption; |
41 using blink::mojom::blink::ShippingOptionPtr; | 43 using blink::mojom::blink::ShippingOptionPtr; |
42 | 44 |
43 template <> | 45 template <> |
44 struct TypeConverter<CurrencyAmountPtr, blink::CurrencyAmount> { | 46 struct TypeConverter<CurrencyAmountPtr, blink::CurrencyAmount> { |
45 static CurrencyAmountPtr Convert(const blink::CurrencyAmount& input) | 47 static CurrencyAmountPtr Convert(const blink::CurrencyAmount& input) |
46 { | 48 { |
47 CurrencyAmountPtr output = CurrencyAmount::New(); | 49 CurrencyAmountPtr output = CurrencyAmount::New(); |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
98 template <> | 100 template <> |
99 struct TypeConverter<PaymentOptionsPtr, blink::PaymentOptions> { | 101 struct TypeConverter<PaymentOptionsPtr, blink::PaymentOptions> { |
100 static PaymentOptionsPtr Convert(const blink::PaymentOptions& input) | 102 static PaymentOptionsPtr Convert(const blink::PaymentOptions& input) |
101 { | 103 { |
102 PaymentOptionsPtr output = PaymentOptions::New(); | 104 PaymentOptionsPtr output = PaymentOptions::New(); |
103 output->request_shipping = input.requestShipping(); | 105 output->request_shipping = input.requestShipping(); |
104 return output; | 106 return output; |
105 } | 107 } |
106 }; | 108 }; |
107 | 109 |
| 110 template <> |
| 111 struct TypeConverter<WTFArray<PaymentMethodDataPtr>, WTF::Vector<blink::PaymentR
equest::MethodData>> { |
| 112 static WTFArray<PaymentMethodDataPtr> Convert(const WTF::Vector<blink::Payme
ntRequest::MethodData>& input) |
| 113 { |
| 114 WTFArray<PaymentMethodDataPtr> output(input.size()); |
| 115 for (size_t i = 0; i < input.size(); ++i) { |
| 116 output[i] = PaymentMethodData::New(); |
| 117 output[i]->supported_methods = WTF::Vector<WTF::String>(input[i].sup
portedMethods); |
| 118 output[i]->data = input[i].stringifiedData; |
| 119 } |
| 120 return output; |
| 121 } |
| 122 }; |
| 123 |
108 } // namespace mojo | 124 } // namespace mojo |
109 | 125 |
110 namespace blink { | 126 namespace blink { |
111 namespace { | 127 namespace { |
112 | 128 |
113 // Validates ShippingOption or PaymentItem, which happen to have identical field
s, | 129 // Validates ShippingOption or PaymentItem, which happen to have identical field
s, |
114 // except for "id", which is present only in ShippingOption. | 130 // except for "id", which is present only in ShippingOption. |
115 template <typename T> | 131 template <typename T> |
116 void validateShippingOptionOrPaymentItem(const T& item, ExceptionState& exceptio
nState) | 132 void validateShippingOptionOrPaymentItem(const T& item, ExceptionState& exceptio
nState) |
117 { | 133 { |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
190 validateDisplayItems(details.displayItems(), exceptionState); | 206 validateDisplayItems(details.displayItems(), exceptionState); |
191 if (exceptionState.hadException()) | 207 if (exceptionState.hadException()) |
192 return; | 208 return; |
193 } | 209 } |
194 | 210 |
195 if (details.hasShippingOptions()) { | 211 if (details.hasShippingOptions()) { |
196 validateShippingOptions(details.shippingOptions(), exceptionState); | 212 validateShippingOptions(details.shippingOptions(), exceptionState); |
197 } | 213 } |
198 } | 214 } |
199 | 215 |
| 216 void validateAndConvertPaymentMethodData(const HeapVector<PaymentMethodData>& pa
ymentMethodData, Vector<PaymentRequest::MethodData>* methodData, ExceptionState&
exceptionState) |
| 217 { |
| 218 if (paymentMethodData.isEmpty()) { |
| 219 exceptionState.throwTypeError("Must specify at least one payment method
identifier"); |
| 220 return; |
| 221 } |
| 222 |
| 223 for (const auto& pmd : paymentMethodData) { |
| 224 if (pmd.supportedMethods().isEmpty()) { |
| 225 exceptionState.throwTypeError("Must specify at least one payment met
hod identifier"); |
| 226 return; |
| 227 } |
| 228 |
| 229 String stringifiedData = ""; |
| 230 if (pmd.hasData() && !pmd.data().isEmpty()) { |
| 231 RefPtr<JSONValue> value = toJSONValue(pmd.data().context(), pmd.data
().v8Value()); |
| 232 if (!value) { |
| 233 exceptionState.throwTypeError("Unable to parse payment method sp
ecific data"); |
| 234 return; |
| 235 } |
| 236 if (!value->isNull()) { |
| 237 if (value->getType() != JSONValue::TypeObject) { |
| 238 exceptionState.throwTypeError("Data should be a JSON-seriali
zable object"); |
| 239 return; |
| 240 } |
| 241 stringifiedData = JSONObject::cast(value)->toJSONString(); |
| 242 } |
| 243 } |
| 244 methodData->append(PaymentRequest::MethodData(pmd.supportedMethods(), st
ringifiedData)); |
| 245 } |
| 246 } |
| 247 |
200 } // namespace | 248 } // namespace |
201 | 249 |
202 PaymentRequest* PaymentRequest::create(ScriptState* scriptState, const Vector<St
ring>& supportedMethods, const PaymentDetails& details, ExceptionState& exceptio
nState) | 250 PaymentRequest* PaymentRequest::create(ScriptState* scriptState, const HeapVecto
r<PaymentMethodData>& methodData, const PaymentDetails& details, ExceptionState&
exceptionState) |
203 { | 251 { |
204 return new PaymentRequest(scriptState, supportedMethods, details, PaymentOpt
ions(), ScriptValue(), exceptionState); | 252 return new PaymentRequest(scriptState, methodData, details, PaymentOptions()
, exceptionState); |
205 } | 253 } |
206 | 254 |
207 PaymentRequest* PaymentRequest::create(ScriptState* scriptState, const Vector<St
ring>& supportedMethods, const PaymentDetails& details, const PaymentOptions& op
tions, ExceptionState& exceptionState) | 255 PaymentRequest* PaymentRequest::create(ScriptState* scriptState, const HeapVecto
r<PaymentMethodData>& methodData, const PaymentDetails& details, const PaymentOp
tions& options, ExceptionState& exceptionState) |
208 { | 256 { |
209 return new PaymentRequest(scriptState, supportedMethods, details, options, S
criptValue(), exceptionState); | 257 return new PaymentRequest(scriptState, methodData, details, options, excepti
onState); |
210 } | |
211 | |
212 PaymentRequest* PaymentRequest::create(ScriptState* scriptState, const Vector<St
ring>& supportedMethods, const PaymentDetails& details, const PaymentOptions& op
tions, const ScriptValue& data, ExceptionState& exceptionState) | |
213 { | |
214 return new PaymentRequest(scriptState, supportedMethods, details, options, d
ata, exceptionState); | |
215 } | 258 } |
216 | 259 |
217 PaymentRequest::~PaymentRequest() | 260 PaymentRequest::~PaymentRequest() |
218 { | 261 { |
219 } | 262 } |
220 | 263 |
221 ScriptPromise PaymentRequest::show(ScriptState* scriptState) | 264 ScriptPromise PaymentRequest::show(ScriptState* scriptState) |
222 { | 265 { |
223 if (m_showResolver) | 266 if (m_showResolver) |
224 return ScriptPromise::rejectWithDOMException(scriptState, DOMException::
create(InvalidStateError, "Already called show() once")); | 267 return ScriptPromise::rejectWithDOMException(scriptState, DOMException::
create(InvalidStateError, "Already called show() once")); |
225 | 268 |
226 if (!scriptState->domWindow() || !scriptState->domWindow()->frame()) | 269 if (!scriptState->domWindow() || !scriptState->domWindow()->frame()) |
227 return ScriptPromise::rejectWithDOMException(scriptState, DOMException::
create(InvalidStateError, "Cannot show the payment request")); | 270 return ScriptPromise::rejectWithDOMException(scriptState, DOMException::
create(InvalidStateError, "Cannot show the payment request")); |
228 | 271 |
229 DCHECK(!m_paymentProvider.is_bound()); | 272 DCHECK(!m_paymentProvider.is_bound()); |
230 scriptState->domWindow()->frame()->serviceRegistry()->connectToRemoteService
(mojo::GetProxy(&m_paymentProvider)); | 273 scriptState->domWindow()->frame()->serviceRegistry()->connectToRemoteService
(mojo::GetProxy(&m_paymentProvider)); |
231 m_paymentProvider.set_connection_error_handler(createBaseCallback(bind(&Paym
entRequest::OnError, WeakPersistentThisPointer<PaymentRequest>(this)))); | 274 m_paymentProvider.set_connection_error_handler(createBaseCallback(bind(&Paym
entRequest::OnError, WeakPersistentThisPointer<PaymentRequest>(this)))); |
232 m_paymentProvider->SetClient(m_clientBinding.CreateInterfacePtrAndBind()); | 275 m_paymentProvider->SetClient(m_clientBinding.CreateInterfacePtrAndBind()); |
233 m_paymentProvider->Show(std::move(m_supportedMethods), mojom::blink::Payment
Details::From(m_details), mojom::blink::PaymentOptions::From(m_options), m_strin
gifiedData.isNull() ? "" : m_stringifiedData); | 276 m_paymentProvider->Show(mojo::WTFArray<mojom::blink::PaymentMethodDataPtr>::
From(m_methodData), mojom::blink::PaymentDetails::From(m_details), mojom::blink:
:PaymentOptions::From(m_options)); |
234 | |
235 m_showResolver = ScriptPromiseResolver::create(scriptState); | 277 m_showResolver = ScriptPromiseResolver::create(scriptState); |
236 return m_showResolver->promise(); | 278 return m_showResolver->promise(); |
237 } | 279 } |
238 | 280 |
239 void PaymentRequest::abort(ExceptionState& exceptionState) | 281 void PaymentRequest::abort(ExceptionState& exceptionState) |
240 { | 282 { |
241 if (!m_showResolver) { | 283 if (!m_showResolver) { |
242 exceptionState.throwDOMException(InvalidStateError, "Never called show()
, so nothing to abort"); | 284 exceptionState.throwDOMException(InvalidStateError, "Never called show()
, so nothing to abort"); |
243 return; | 285 return; |
244 } | 286 } |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
311 { | 353 { |
312 visitor->trace(m_details); | 354 visitor->trace(m_details); |
313 visitor->trace(m_options); | 355 visitor->trace(m_options); |
314 visitor->trace(m_shippingAddress); | 356 visitor->trace(m_shippingAddress); |
315 visitor->trace(m_showResolver); | 357 visitor->trace(m_showResolver); |
316 visitor->trace(m_completeResolver); | 358 visitor->trace(m_completeResolver); |
317 EventTargetWithInlineData::trace(visitor); | 359 EventTargetWithInlineData::trace(visitor); |
318 ContextLifecycleObserver::trace(visitor); | 360 ContextLifecycleObserver::trace(visitor); |
319 } | 361 } |
320 | 362 |
321 PaymentRequest::PaymentRequest(ScriptState* scriptState, const Vector<String>& s
upportedMethods, const PaymentDetails& details, const PaymentOptions& options, c
onst ScriptValue& data, ExceptionState& exceptionState) | 363 PaymentRequest::PaymentRequest(ScriptState* scriptState, const HeapVector<Paymen
tMethodData>& methodData, const PaymentDetails& details, const PaymentOptions& o
ptions, ExceptionState& exceptionState) |
322 : ContextLifecycleObserver(scriptState->getExecutionContext()) | 364 : ContextLifecycleObserver(scriptState->getExecutionContext()) |
323 , ActiveScriptWrappable(this) | 365 , ActiveScriptWrappable(this) |
324 , m_options(options) | 366 , m_options(options) |
325 , m_clientBinding(this) | 367 , m_clientBinding(this) |
326 { | 368 { |
| 369 validateAndConvertPaymentMethodData(methodData, &m_methodData, exceptionStat
e); |
| 370 if (exceptionState.hadException()) |
| 371 return; |
| 372 |
327 if (!scriptState->getExecutionContext()->isSecureContext()) { | 373 if (!scriptState->getExecutionContext()->isSecureContext()) { |
328 exceptionState.throwSecurityError("Must be in a secure context"); | 374 exceptionState.throwSecurityError("Must be in a secure context"); |
329 return; | 375 return; |
330 } | 376 } |
331 | 377 |
332 if (!scriptState->domWindow()->frame() || !scriptState->domWindow()->frame()
->isMainFrame()) { | 378 if (!scriptState->domWindow()->frame() || !scriptState->domWindow()->frame()
->isMainFrame()) { |
333 exceptionState.throwSecurityError("Must be in a top-level browsing conte
xt"); | 379 exceptionState.throwSecurityError("Must be in a top-level browsing conte
xt"); |
334 return; | 380 return; |
335 } | 381 } |
336 | 382 |
337 if (supportedMethods.isEmpty()) { | |
338 exceptionState.throwTypeError("Must specify at least one payment method
identifier"); | |
339 return; | |
340 } | |
341 m_supportedMethods = supportedMethods; | |
342 | |
343 validatePaymentDetails(details, exceptionState); | 383 validatePaymentDetails(details, exceptionState); |
344 if (exceptionState.hadException()) | 384 if (exceptionState.hadException()) |
345 return; | 385 return; |
346 m_details = details; | 386 m_details = details; |
347 | 387 |
348 if (!data.isEmpty()) { | |
349 RefPtr<JSONValue> value = toJSONValue(data.context(), data.v8Value()); | |
350 if (!value) { | |
351 exceptionState.throwTypeError("Unable to parse payment method specif
ic data"); | |
352 return; | |
353 } | |
354 if (!value->isNull()) { | |
355 if (value->getType() != JSONValue::TypeObject) { | |
356 exceptionState.throwTypeError("Payment method specific data shou
ld be a JSON-serializable object"); | |
357 return; | |
358 } | |
359 | |
360 RefPtr<JSONObject> jsonData = JSONObject::cast(value); | |
361 for (const auto& paymentMethodSpecificKeyValue : *jsonData) { | |
362 if (!supportedMethods.contains(paymentMethodSpecificKeyValue.key
)) { | |
363 exceptionState.throwTypeError("'" + paymentMethodSpecificKey
Value.key + "' should match one of the payment method identifiers"); | |
364 return; | |
365 } | |
366 if (paymentMethodSpecificKeyValue.value->getType() != JSONValue:
:TypeObject) { | |
367 exceptionState.throwTypeError("Data for '" + paymentMethodSp
ecificKeyValue.key + "' should be a JSON-serializable object"); | |
368 return; | |
369 } | |
370 } | |
371 | |
372 m_stringifiedData = jsonData->toJSONString(); | |
373 } | |
374 } | |
375 | |
376 // Set the currently selected option if only one option is passed and shippi
ng is requested. | 388 // Set the currently selected option if only one option is passed and shippi
ng is requested. |
377 if (options.requestShipping() && details.hasShippingOptions() && details.shi
ppingOptions().size() == 1) | 389 if (options.requestShipping() && details.hasShippingOptions() && details.shi
ppingOptions().size() == 1) |
378 m_shippingOption = details.shippingOptions().begin()->id(); | 390 m_shippingOption = details.shippingOptions().begin()->id(); |
379 } | 391 } |
380 | 392 |
381 void PaymentRequest::contextDestroyed() | 393 void PaymentRequest::contextDestroyed() |
382 { | 394 { |
383 clearResolversAndCloseMojoConnection(); | 395 clearResolversAndCloseMojoConnection(); |
384 } | 396 } |
385 | 397 |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
478 void PaymentRequest::clearResolversAndCloseMojoConnection() | 490 void PaymentRequest::clearResolversAndCloseMojoConnection() |
479 { | 491 { |
480 m_completeResolver.clear(); | 492 m_completeResolver.clear(); |
481 m_showResolver.clear(); | 493 m_showResolver.clear(); |
482 if (m_clientBinding.is_bound()) | 494 if (m_clientBinding.is_bound()) |
483 m_clientBinding.Close(); | 495 m_clientBinding.Close(); |
484 m_paymentProvider.reset(); | 496 m_paymentProvider.reset(); |
485 } | 497 } |
486 | 498 |
487 } // namespace blink | 499 } // namespace blink |
OLD | NEW |