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 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
99 template <> | 101 template <> |
100 struct TypeConverter<PaymentOptionsPtr, blink::PaymentOptions> { | 102 struct TypeConverter<PaymentOptionsPtr, blink::PaymentOptions> { |
101 static PaymentOptionsPtr Convert(const blink::PaymentOptions& input) | 103 static PaymentOptionsPtr Convert(const blink::PaymentOptions& input) |
102 { | 104 { |
103 PaymentOptionsPtr output = PaymentOptions::New(); | 105 PaymentOptionsPtr output = PaymentOptions::New(); |
104 output->request_shipping = input.requestShipping(); | 106 output->request_shipping = input.requestShipping(); |
105 return output; | 107 return output; |
106 } | 108 } |
107 }; | 109 }; |
108 | 110 |
| 111 template <> |
| 112 struct TypeConverter<WTFArray<PaymentMethodDataPtr>, WTF::Vector<blink::PaymentR
equest::MethodData>> { |
| 113 static WTFArray<PaymentMethodDataPtr> Convert(const WTF::Vector<blink::Payme
ntRequest::MethodData>& input) |
| 114 { |
| 115 WTFArray<PaymentMethodDataPtr> output(input.size()); |
| 116 for (size_t i = 0; i < input.size(); ++i) { |
| 117 output[i] = PaymentMethodData::New(); |
| 118 output[i]->supported_methods = WTF::Vector<WTF::String>(input[i].sup
portedMethods); |
| 119 output[i]->stringified_data = input[i].stringifiedData; |
| 120 } |
| 121 return output; |
| 122 } |
| 123 }; |
| 124 |
109 } // namespace mojo | 125 } // namespace mojo |
110 | 126 |
111 namespace blink { | 127 namespace blink { |
112 namespace { | 128 namespace { |
113 | 129 |
114 // Validates ShippingOption or PaymentItem, which happen to have identical field
s, | 130 // Validates ShippingOption or PaymentItem, which happen to have identical field
s, |
115 // except for "id", which is present only in ShippingOption. | 131 // except for "id", which is present only in ShippingOption. |
116 template <typename T> | 132 template <typename T> |
117 void validateShippingOptionOrPaymentItem(const T& item, ExceptionState& exceptio
nState) | 133 void validateShippingOptionOrPaymentItem(const T& item, ExceptionState& exceptio
nState) |
118 { | 134 { |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
191 validateDisplayItems(details.displayItems(), exceptionState); | 207 validateDisplayItems(details.displayItems(), exceptionState); |
192 if (exceptionState.hadException()) | 208 if (exceptionState.hadException()) |
193 return; | 209 return; |
194 } | 210 } |
195 | 211 |
196 if (details.hasShippingOptions()) { | 212 if (details.hasShippingOptions()) { |
197 validateShippingOptions(details.shippingOptions(), exceptionState); | 213 validateShippingOptions(details.shippingOptions(), exceptionState); |
198 } | 214 } |
199 } | 215 } |
200 | 216 |
| 217 void validateAndConvertPaymentMethodData(const HeapVector<PaymentMethodData>& pa
ymentMethodData, Vector<PaymentRequest::MethodData>* methodData, ExceptionState&
exceptionState) |
| 218 { |
| 219 if (paymentMethodData.isEmpty()) { |
| 220 exceptionState.throwTypeError("Must specify at least one payment method
identifier"); |
| 221 return; |
| 222 } |
| 223 |
| 224 for (const auto& pmd : paymentMethodData) { |
| 225 if (pmd.supportedMethods().isEmpty()) { |
| 226 exceptionState.throwTypeError("Must specify at least one payment met
hod identifier"); |
| 227 return; |
| 228 } |
| 229 |
| 230 String stringifiedData = ""; |
| 231 if (pmd.hasData() && !pmd.data().isEmpty()) { |
| 232 RefPtr<JSONValue> value = toJSONValue(pmd.data().context(), pmd.data
().v8Value()); |
| 233 if (!value) { |
| 234 exceptionState.throwTypeError("Unable to parse payment method sp
ecific data"); |
| 235 return; |
| 236 } |
| 237 if (!value->isNull()) { |
| 238 if (value->getType() != JSONValue::TypeObject) { |
| 239 exceptionState.throwTypeError("Data should be a JSON-seriali
zable object"); |
| 240 return; |
| 241 } |
| 242 stringifiedData = JSONObject::cast(value)->toJSONString(); |
| 243 } |
| 244 } |
| 245 methodData->append(PaymentRequest::MethodData(pmd.supportedMethods(), st
ringifiedData)); |
| 246 } |
| 247 } |
| 248 |
201 String getSelectedShippingOption(const PaymentDetails& details) | 249 String getSelectedShippingOption(const PaymentDetails& details) |
202 { | 250 { |
203 String result; | 251 String result; |
204 if (!details.hasShippingOptions()) | 252 if (!details.hasShippingOptions()) |
205 return result; | 253 return result; |
206 | 254 |
207 for (size_t i = 0; i < details.shippingOptions().size(); ++i) { | 255 for (size_t i = 0; i < details.shippingOptions().size(); ++i) { |
208 if (details.shippingOptions()[i].hasSelected() && details.shippingOption
s()[i].selected()) { | 256 if (details.shippingOptions()[i].hasSelected() && details.shippingOption
s()[i].selected()) { |
209 result = details.shippingOptions()[i].id(); | 257 result = details.shippingOptions()[i].id(); |
210 } | 258 } |
211 } | 259 } |
212 | 260 |
213 return result; | 261 return result; |
214 } | 262 } |
215 | 263 |
216 } // namespace | 264 } // namespace |
217 | 265 |
218 PaymentRequest* PaymentRequest::create(ScriptState* scriptState, const Vector<St
ring>& supportedMethods, const PaymentDetails& details, ExceptionState& exceptio
nState) | 266 PaymentRequest* PaymentRequest::create(ScriptState* scriptState, const HeapVecto
r<PaymentMethodData>& methodData, const PaymentDetails& details, ExceptionState&
exceptionState) |
219 { | 267 { |
220 return new PaymentRequest(scriptState, supportedMethods, details, PaymentOpt
ions(), ScriptValue(), exceptionState); | 268 return new PaymentRequest(scriptState, methodData, details, PaymentOptions()
, exceptionState); |
221 } | 269 } |
222 | 270 |
223 PaymentRequest* PaymentRequest::create(ScriptState* scriptState, const Vector<St
ring>& supportedMethods, const PaymentDetails& details, const PaymentOptions& op
tions, ExceptionState& exceptionState) | 271 PaymentRequest* PaymentRequest::create(ScriptState* scriptState, const HeapVecto
r<PaymentMethodData>& methodData, const PaymentDetails& details, const PaymentOp
tions& options, ExceptionState& exceptionState) |
224 { | 272 { |
225 return new PaymentRequest(scriptState, supportedMethods, details, options, S
criptValue(), exceptionState); | 273 return new PaymentRequest(scriptState, methodData, details, options, excepti
onState); |
226 } | |
227 | |
228 PaymentRequest* PaymentRequest::create(ScriptState* scriptState, const Vector<St
ring>& supportedMethods, const PaymentDetails& details, const PaymentOptions& op
tions, const ScriptValue& data, ExceptionState& exceptionState) | |
229 { | |
230 return new PaymentRequest(scriptState, supportedMethods, details, options, d
ata, exceptionState); | |
231 } | 274 } |
232 | 275 |
233 PaymentRequest::~PaymentRequest() | 276 PaymentRequest::~PaymentRequest() |
234 { | 277 { |
235 } | 278 } |
236 | 279 |
237 ScriptPromise PaymentRequest::show(ScriptState* scriptState) | 280 ScriptPromise PaymentRequest::show(ScriptState* scriptState) |
238 { | 281 { |
239 if (m_showResolver) | 282 if (m_showResolver) |
240 return ScriptPromise::rejectWithDOMException(scriptState, DOMException::
create(InvalidStateError, "Already called show() once")); | 283 return ScriptPromise::rejectWithDOMException(scriptState, DOMException::
create(InvalidStateError, "Already called show() once")); |
241 | 284 |
242 if (!scriptState->domWindow() || !scriptState->domWindow()->frame()) | 285 if (!scriptState->domWindow() || !scriptState->domWindow()->frame()) |
243 return ScriptPromise::rejectWithDOMException(scriptState, DOMException::
create(InvalidStateError, "Cannot show the payment request")); | 286 return ScriptPromise::rejectWithDOMException(scriptState, DOMException::
create(InvalidStateError, "Cannot show the payment request")); |
244 | 287 |
245 DCHECK(!m_paymentProvider.is_bound()); | 288 DCHECK(!m_paymentProvider.is_bound()); |
246 scriptState->domWindow()->frame()->serviceRegistry()->connectToRemoteService
(mojo::GetProxy(&m_paymentProvider)); | 289 scriptState->domWindow()->frame()->serviceRegistry()->connectToRemoteService
(mojo::GetProxy(&m_paymentProvider)); |
247 m_paymentProvider.set_connection_error_handler(createBaseCallback(bind(&Paym
entRequest::OnError, WeakPersistentThisPointer<PaymentRequest>(this)))); | 290 m_paymentProvider.set_connection_error_handler(createBaseCallback(bind(&Paym
entRequest::OnError, WeakPersistentThisPointer<PaymentRequest>(this)))); |
248 m_paymentProvider->SetClient(m_clientBinding.CreateInterfacePtrAndBind()); | 291 m_paymentProvider->SetClient(m_clientBinding.CreateInterfacePtrAndBind()); |
249 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); | 292 m_paymentProvider->Show(mojo::WTFArray<mojom::blink::PaymentMethodDataPtr>::
From(m_methodData), mojom::blink::PaymentDetails::From(m_details), mojom::blink:
:PaymentOptions::From(m_options)); |
250 | 293 |
251 m_showResolver = ScriptPromiseResolver::create(scriptState); | 294 m_showResolver = ScriptPromiseResolver::create(scriptState); |
252 return m_showResolver->promise(); | 295 return m_showResolver->promise(); |
253 } | 296 } |
254 | 297 |
255 void PaymentRequest::abort(ExceptionState& exceptionState) | 298 void PaymentRequest::abort(ExceptionState& exceptionState) |
256 { | 299 { |
257 if (!m_showResolver) { | 300 if (!m_showResolver) { |
258 exceptionState.throwDOMException(InvalidStateError, "Never called show()
, so nothing to abort"); | 301 exceptionState.throwDOMException(InvalidStateError, "Never called show()
, so nothing to abort"); |
259 return; | 302 return; |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
324 { | 367 { |
325 visitor->trace(m_details); | 368 visitor->trace(m_details); |
326 visitor->trace(m_options); | 369 visitor->trace(m_options); |
327 visitor->trace(m_shippingAddress); | 370 visitor->trace(m_shippingAddress); |
328 visitor->trace(m_showResolver); | 371 visitor->trace(m_showResolver); |
329 visitor->trace(m_completeResolver); | 372 visitor->trace(m_completeResolver); |
330 EventTargetWithInlineData::trace(visitor); | 373 EventTargetWithInlineData::trace(visitor); |
331 ContextLifecycleObserver::trace(visitor); | 374 ContextLifecycleObserver::trace(visitor); |
332 } | 375 } |
333 | 376 |
334 PaymentRequest::PaymentRequest(ScriptState* scriptState, const Vector<String>& s
upportedMethods, const PaymentDetails& details, const PaymentOptions& options, c
onst ScriptValue& data, ExceptionState& exceptionState) | 377 PaymentRequest::PaymentRequest(ScriptState* scriptState, const HeapVector<Paymen
tMethodData>& methodData, const PaymentDetails& details, const PaymentOptions& o
ptions, ExceptionState& exceptionState) |
335 : ContextLifecycleObserver(scriptState->getExecutionContext()) | 378 : ContextLifecycleObserver(scriptState->getExecutionContext()) |
336 , ActiveScriptWrappable(this) | 379 , ActiveScriptWrappable(this) |
337 , m_options(options) | 380 , m_options(options) |
338 , m_clientBinding(this) | 381 , m_clientBinding(this) |
339 { | 382 { |
| 383 validateAndConvertPaymentMethodData(methodData, &m_methodData, exceptionStat
e); |
| 384 if (exceptionState.hadException()) |
| 385 return; |
| 386 |
340 if (!scriptState->getExecutionContext()->isSecureContext()) { | 387 if (!scriptState->getExecutionContext()->isSecureContext()) { |
341 exceptionState.throwSecurityError("Must be in a secure context"); | 388 exceptionState.throwSecurityError("Must be in a secure context"); |
342 return; | 389 return; |
343 } | 390 } |
344 | 391 |
345 if (!scriptState->domWindow()->frame() || !scriptState->domWindow()->frame()
->isMainFrame()) { | 392 if (!scriptState->domWindow()->frame() || !scriptState->domWindow()->frame()
->isMainFrame()) { |
346 exceptionState.throwSecurityError("Must be in a top-level browsing conte
xt"); | 393 exceptionState.throwSecurityError("Must be in a top-level browsing conte
xt"); |
347 return; | 394 return; |
348 } | 395 } |
349 | 396 |
350 if (supportedMethods.isEmpty()) { | |
351 exceptionState.throwTypeError("Must specify at least one payment method
identifier"); | |
352 return; | |
353 } | |
354 m_supportedMethods = supportedMethods; | |
355 | |
356 validatePaymentDetails(details, exceptionState); | 397 validatePaymentDetails(details, exceptionState); |
357 if (exceptionState.hadException()) | 398 if (exceptionState.hadException()) |
358 return; | 399 return; |
359 m_details = details; | 400 m_details = details; |
360 | 401 |
361 if (!data.isEmpty()) { | |
362 RefPtr<JSONValue> value = toJSONValue(data.context(), data.v8Value()); | |
363 if (!value) { | |
364 exceptionState.throwTypeError("Unable to parse payment method specif
ic data"); | |
365 return; | |
366 } | |
367 if (!value->isNull()) { | |
368 if (value->getType() != JSONValue::TypeObject) { | |
369 exceptionState.throwTypeError("Payment method specific data shou
ld be a JSON-serializable object"); | |
370 return; | |
371 } | |
372 | |
373 RefPtr<JSONObject> jsonData = JSONObject::cast(value); | |
374 for (const auto& paymentMethodSpecificKeyValue : *jsonData) { | |
375 if (!supportedMethods.contains(paymentMethodSpecificKeyValue.key
)) { | |
376 exceptionState.throwTypeError("'" + paymentMethodSpecificKey
Value.key + "' should match one of the payment method identifiers"); | |
377 return; | |
378 } | |
379 if (paymentMethodSpecificKeyValue.value->getType() != JSONValue:
:TypeObject) { | |
380 exceptionState.throwTypeError("Data for '" + paymentMethodSp
ecificKeyValue.key + "' should be a JSON-serializable object"); | |
381 return; | |
382 } | |
383 } | |
384 | |
385 m_stringifiedData = jsonData->toJSONString(); | |
386 } | |
387 } | |
388 | |
389 if (m_options.requestShipping()) | 402 if (m_options.requestShipping()) |
390 m_shippingOption = getSelectedShippingOption(details); | 403 m_shippingOption = getSelectedShippingOption(details); |
391 } | 404 } |
392 | 405 |
393 void PaymentRequest::contextDestroyed() | 406 void PaymentRequest::contextDestroyed() |
394 { | 407 { |
395 clearResolversAndCloseMojoConnection(); | 408 clearResolversAndCloseMojoConnection(); |
396 } | 409 } |
397 | 410 |
398 bool PaymentRequest::hasPendingActivity() const | 411 bool PaymentRequest::hasPendingActivity() const |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
490 void PaymentRequest::clearResolversAndCloseMojoConnection() | 503 void PaymentRequest::clearResolversAndCloseMojoConnection() |
491 { | 504 { |
492 m_completeResolver.clear(); | 505 m_completeResolver.clear(); |
493 m_showResolver.clear(); | 506 m_showResolver.clear(); |
494 if (m_clientBinding.is_bound()) | 507 if (m_clientBinding.is_bound()) |
495 m_clientBinding.Close(); | 508 m_clientBinding.Close(); |
496 m_paymentProvider.reset(); | 509 m_paymentProvider.reset(); |
497 } | 510 } |
498 | 511 |
499 } // namespace blink | 512 } // namespace blink |
OLD | NEW |