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 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
91 template <> | 93 template <> |
92 struct TypeConverter<PaymentOptionsPtr, blink::PaymentOptions> { | 94 struct TypeConverter<PaymentOptionsPtr, blink::PaymentOptions> { |
93 static PaymentOptionsPtr Convert(const blink::PaymentOptions& input) | 95 static PaymentOptionsPtr Convert(const blink::PaymentOptions& input) |
94 { | 96 { |
95 PaymentOptionsPtr output = PaymentOptions::New(); | 97 PaymentOptionsPtr output = PaymentOptions::New(); |
96 output->request_shipping = input.requestShipping(); | 98 output->request_shipping = input.requestShipping(); |
97 return output; | 99 return output; |
98 } | 100 } |
99 }; | 101 }; |
100 | 102 |
| 103 template <> |
| 104 struct TypeConverter<WTFArray<PaymentMethodDataPtr>, WTF::Vector<blink::PaymentR
equest::MethodData>> { |
| 105 static WTFArray<PaymentMethodDataPtr> Convert(const WTF::Vector<blink::Payme
ntRequest::MethodData>& input) |
| 106 { |
| 107 WTFArray<PaymentMethodDataPtr> output(input.size()); |
| 108 for (size_t i = 0; i < input.size(); ++i) { |
| 109 output[i] = PaymentMethodData::New(); |
| 110 output[i]->supported_methods = WTF::Vector<WTF::String>(input[i].sup
portedMethods); |
| 111 output[i]->data = input[i].stringifiedData; |
| 112 } |
| 113 return output; |
| 114 } |
| 115 }; |
| 116 |
101 } // namespace mojo | 117 } // namespace mojo |
102 | 118 |
103 namespace blink { | 119 namespace blink { |
104 namespace { | 120 namespace { |
105 | 121 |
106 // Validates ShippingOption and PaymentItem dictionaries, which happen to have i
dentical fields, | 122 // Validates ShippingOption and PaymentItem dictionaries, which happen to have i
dentical fields, |
107 // except for "id", which is present only in ShippingOption. | 123 // except for "id", which is present only in ShippingOption. |
108 template <typename T> | 124 template <typename T> |
109 void validateShippingOptionsOrPaymentItems(HeapVector<T> items, ExceptionState&
exceptionState) | 125 void validateShippingOptionsOrPaymentItems(HeapVector<T> items, ExceptionState&
exceptionState) |
110 { | 126 { |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
167 validateShippingOptionsOrPaymentItems(details.displayItems(), exceptionState
); | 183 validateShippingOptionsOrPaymentItems(details.displayItems(), exceptionState
); |
168 if (exceptionState.hadException()) | 184 if (exceptionState.hadException()) |
169 return; | 185 return; |
170 | 186 |
171 if (details.hasShippingOptions()) { | 187 if (details.hasShippingOptions()) { |
172 validateShippingOptionsOrPaymentItems(details.shippingOptions(), excepti
onState); | 188 validateShippingOptionsOrPaymentItems(details.shippingOptions(), excepti
onState); |
173 validateShippingOptionsIds(details.shippingOptions(), exceptionState); | 189 validateShippingOptionsIds(details.shippingOptions(), exceptionState); |
174 } | 190 } |
175 } | 191 } |
176 | 192 |
| 193 void validateAndConvertPaymentMethodData(const HeapVector<PaymentMethodData>& pa
ymentMethodData, Vector<PaymentRequest::MethodData>* methodData, ExceptionState&
exceptionState) |
| 194 { |
| 195 if (paymentMethodData.isEmpty()) { |
| 196 exceptionState.throwTypeError("Must specify at least one payment method
identifier"); |
| 197 return; |
| 198 } |
| 199 |
| 200 for (const auto& pmd : paymentMethodData) { |
| 201 if (pmd.supportedMethods().isEmpty()) { |
| 202 exceptionState.throwTypeError("Must specify at least one payment met
hod identifier"); |
| 203 return; |
| 204 } |
| 205 |
| 206 String stringifiedData = ""; |
| 207 if (pmd.hasData() && !pmd.data().isEmpty()) { |
| 208 RefPtr<JSONValue> value = toJSONValue(pmd.data().context(), pmd.data
().v8Value()); |
| 209 if (!value) { |
| 210 exceptionState.throwTypeError("Unable to parse payment method sp
ecific data"); |
| 211 return; |
| 212 } |
| 213 if (!value->isNull()) { |
| 214 if (value->getType() != JSONValue::TypeObject) { |
| 215 exceptionState.throwTypeError("Data should be a JSON-seriali
zable object"); |
| 216 return; |
| 217 } |
| 218 stringifiedData = JSONObject::cast(value)->toJSONString(); |
| 219 } |
| 220 } |
| 221 methodData->append(PaymentRequest::MethodData(pmd.supportedMethods(), st
ringifiedData)); |
| 222 } |
| 223 } |
| 224 |
177 } // namespace | 225 } // namespace |
178 | 226 |
179 PaymentRequest* PaymentRequest::create(ScriptState* scriptState, const Vector<St
ring>& supportedMethods, const PaymentDetails& details, ExceptionState& exceptio
nState) | 227 PaymentRequest* PaymentRequest::create(ScriptState* scriptState, const HeapVecto
r<PaymentMethodData>& methodData, const PaymentDetails& details, ExceptionState&
exceptionState) |
180 { | 228 { |
181 return new PaymentRequest(scriptState, supportedMethods, details, PaymentOpt
ions(), ScriptValue(), exceptionState); | 229 return new PaymentRequest(scriptState, methodData, details, PaymentOptions()
, exceptionState); |
182 } | 230 } |
183 | 231 |
184 PaymentRequest* PaymentRequest::create(ScriptState* scriptState, const Vector<St
ring>& supportedMethods, const PaymentDetails& details, const PaymentOptions& op
tions, ExceptionState& exceptionState) | 232 PaymentRequest* PaymentRequest::create(ScriptState* scriptState, const HeapVecto
r<PaymentMethodData>& methodData, const PaymentDetails& details, const PaymentOp
tions& options, ExceptionState& exceptionState) |
185 { | 233 { |
186 return new PaymentRequest(scriptState, supportedMethods, details, options, S
criptValue(), exceptionState); | 234 return new PaymentRequest(scriptState, methodData, details, options, excepti
onState); |
187 } | |
188 | |
189 PaymentRequest* PaymentRequest::create(ScriptState* scriptState, const Vector<St
ring>& supportedMethods, const PaymentDetails& details, const PaymentOptions& op
tions, const ScriptValue& data, ExceptionState& exceptionState) | |
190 { | |
191 return new PaymentRequest(scriptState, supportedMethods, details, options, d
ata, exceptionState); | |
192 } | 235 } |
193 | 236 |
194 PaymentRequest::~PaymentRequest() | 237 PaymentRequest::~PaymentRequest() |
195 { | 238 { |
196 } | 239 } |
197 | 240 |
198 ScriptPromise PaymentRequest::show(ScriptState* scriptState) | 241 ScriptPromise PaymentRequest::show(ScriptState* scriptState) |
199 { | 242 { |
200 if (m_showResolver) | 243 if (m_showResolver) |
201 return ScriptPromise::rejectWithDOMException(scriptState, DOMException::
create(InvalidStateError, "Already called show() once")); | 244 return ScriptPromise::rejectWithDOMException(scriptState, DOMException::
create(InvalidStateError, "Already called show() once")); |
202 | 245 |
203 if (!scriptState->domWindow() || !scriptState->domWindow()->frame()) | 246 if (!scriptState->domWindow() || !scriptState->domWindow()->frame()) |
204 return ScriptPromise::rejectWithDOMException(scriptState, DOMException::
create(InvalidStateError, "Cannot show the payment request")); | 247 return ScriptPromise::rejectWithDOMException(scriptState, DOMException::
create(InvalidStateError, "Cannot show the payment request")); |
205 | 248 |
206 DCHECK(!m_paymentProvider.is_bound()); | 249 DCHECK(!m_paymentProvider.is_bound()); |
207 scriptState->domWindow()->frame()->serviceRegistry()->connectToRemoteService
(mojo::GetProxy(&m_paymentProvider)); | 250 scriptState->domWindow()->frame()->serviceRegistry()->connectToRemoteService
(mojo::GetProxy(&m_paymentProvider)); |
208 m_paymentProvider.set_connection_error_handler(createBaseCallback(bind(&Paym
entRequest::OnError, WeakPersistentThisPointer<PaymentRequest>(this)))); | 251 m_paymentProvider.set_connection_error_handler(createBaseCallback(bind(&Paym
entRequest::OnError, WeakPersistentThisPointer<PaymentRequest>(this)))); |
209 m_paymentProvider->SetClient(m_clientBinding.CreateInterfacePtrAndBind()); | 252 m_paymentProvider->SetClient(m_clientBinding.CreateInterfacePtrAndBind()); |
210 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); | 253 m_paymentProvider->Show(mojo::WTFArray<mojom::blink::PaymentMethodDataPtr>::
From(m_methodData), mojom::blink::PaymentDetails::From(m_details), mojom::blink:
:PaymentOptions::From(m_options)); |
211 | |
212 m_showResolver = ScriptPromiseResolver::create(scriptState); | 254 m_showResolver = ScriptPromiseResolver::create(scriptState); |
213 return m_showResolver->promise(); | 255 return m_showResolver->promise(); |
214 } | 256 } |
215 | 257 |
216 void PaymentRequest::abort(ExceptionState& exceptionState) | 258 void PaymentRequest::abort(ExceptionState& exceptionState) |
217 { | 259 { |
218 if (!m_showResolver) { | 260 if (!m_showResolver) { |
219 exceptionState.throwDOMException(InvalidStateError, "Never called show()
, so nothing to abort"); | 261 exceptionState.throwDOMException(InvalidStateError, "Never called show()
, so nothing to abort"); |
220 return; | 262 return; |
221 } | 263 } |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
288 { | 330 { |
289 visitor->trace(m_details); | 331 visitor->trace(m_details); |
290 visitor->trace(m_options); | 332 visitor->trace(m_options); |
291 visitor->trace(m_shippingAddress); | 333 visitor->trace(m_shippingAddress); |
292 visitor->trace(m_showResolver); | 334 visitor->trace(m_showResolver); |
293 visitor->trace(m_completeResolver); | 335 visitor->trace(m_completeResolver); |
294 EventTargetWithInlineData::trace(visitor); | 336 EventTargetWithInlineData::trace(visitor); |
295 ContextLifecycleObserver::trace(visitor); | 337 ContextLifecycleObserver::trace(visitor); |
296 } | 338 } |
297 | 339 |
298 PaymentRequest::PaymentRequest(ScriptState* scriptState, const Vector<String>& s
upportedMethods, const PaymentDetails& details, const PaymentOptions& options, c
onst ScriptValue& data, ExceptionState& exceptionState) | 340 PaymentRequest::PaymentRequest(ScriptState* scriptState, const HeapVector<Paymen
tMethodData>& methodData, const PaymentDetails& details, const PaymentOptions& o
ptions, ExceptionState& exceptionState) |
299 : ContextLifecycleObserver(scriptState->getExecutionContext()) | 341 : ContextLifecycleObserver(scriptState->getExecutionContext()) |
300 , ActiveScriptWrappable(this) | 342 , ActiveScriptWrappable(this) |
301 , m_options(options) | 343 , m_options(options) |
302 , m_clientBinding(this) | 344 , m_clientBinding(this) |
303 { | 345 { |
| 346 validateAndConvertPaymentMethodData(methodData, &m_methodData, exceptionStat
e); |
| 347 if (exceptionState.hadException()) |
| 348 return; |
| 349 |
304 if (!scriptState->getExecutionContext()->isSecureContext()) { | 350 if (!scriptState->getExecutionContext()->isSecureContext()) { |
305 exceptionState.throwSecurityError("Must be in a secure context"); | 351 exceptionState.throwSecurityError("Must be in a secure context"); |
306 return; | 352 return; |
307 } | 353 } |
308 | 354 |
309 if (!scriptState->domWindow()->frame() || !scriptState->domWindow()->frame()
->isMainFrame()) { | 355 if (!scriptState->domWindow()->frame() || !scriptState->domWindow()->frame()
->isMainFrame()) { |
310 exceptionState.throwSecurityError("Must be in a top-level browsing conte
xt"); | 356 exceptionState.throwSecurityError("Must be in a top-level browsing conte
xt"); |
311 return; | 357 return; |
312 } | 358 } |
313 | 359 |
314 if (supportedMethods.isEmpty()) { | |
315 exceptionState.throwTypeError("Must specify at least one payment method
identifier"); | |
316 return; | |
317 } | |
318 m_supportedMethods = supportedMethods; | |
319 | |
320 validatePaymentDetails(details, exceptionState); | 360 validatePaymentDetails(details, exceptionState); |
321 if (exceptionState.hadException()) | 361 if (exceptionState.hadException()) |
322 return; | 362 return; |
323 m_details = details; | 363 m_details = details; |
324 | 364 |
325 if (!data.isEmpty()) { | |
326 RefPtr<JSONValue> value = toJSONValue(data.context(), data.v8Value()); | |
327 if (!value) { | |
328 exceptionState.throwTypeError("Unable to parse payment method specif
ic data"); | |
329 return; | |
330 } | |
331 if (!value->isNull()) { | |
332 if (value->getType() != JSONValue::TypeObject) { | |
333 exceptionState.throwTypeError("Payment method specific data shou
ld be a JSON-serializable object"); | |
334 return; | |
335 } | |
336 | |
337 RefPtr<JSONObject> jsonData = JSONObject::cast(value); | |
338 for (const auto& paymentMethodSpecificKeyValue : *jsonData) { | |
339 if (!supportedMethods.contains(paymentMethodSpecificKeyValue.key
)) { | |
340 exceptionState.throwTypeError("'" + paymentMethodSpecificKey
Value.key + "' should match one of the payment method identifiers"); | |
341 return; | |
342 } | |
343 if (paymentMethodSpecificKeyValue.value->getType() != JSONValue:
:TypeObject) { | |
344 exceptionState.throwTypeError("Data for '" + paymentMethodSp
ecificKeyValue.key + "' should be a JSON-serializable object"); | |
345 return; | |
346 } | |
347 } | |
348 | |
349 m_stringifiedData = jsonData->toJSONString(); | |
350 } | |
351 } | |
352 | |
353 // Set the currently selected option if only one option is passed and shippi
ng is requested. | 365 // Set the currently selected option if only one option is passed and shippi
ng is requested. |
354 if (options.requestShipping() && details.hasShippingOptions() && details.shi
ppingOptions().size() == 1) | 366 if (options.requestShipping() && details.hasShippingOptions() && details.shi
ppingOptions().size() == 1) |
355 m_shippingOption = details.shippingOptions().begin()->id(); | 367 m_shippingOption = details.shippingOptions().begin()->id(); |
356 } | 368 } |
357 | 369 |
358 void PaymentRequest::contextDestroyed() | 370 void PaymentRequest::contextDestroyed() |
359 { | 371 { |
360 clearResolversAndCloseMojoConnection(); | 372 clearResolversAndCloseMojoConnection(); |
361 } | 373 } |
362 | 374 |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
443 void PaymentRequest::clearResolversAndCloseMojoConnection() | 455 void PaymentRequest::clearResolversAndCloseMojoConnection() |
444 { | 456 { |
445 m_completeResolver.clear(); | 457 m_completeResolver.clear(); |
446 m_showResolver.clear(); | 458 m_showResolver.clear(); |
447 if (m_clientBinding.is_bound()) | 459 if (m_clientBinding.is_bound()) |
448 m_clientBinding.Close(); | 460 m_clientBinding.Close(); |
449 m_paymentProvider.reset(); | 461 m_paymentProvider.reset(); |
450 } | 462 } |
451 | 463 |
452 } // namespace blink | 464 } // namespace blink |
OLD | NEW |