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 21 matching lines...) Expand all Loading... | |
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::PaymentOptions; | 38 using blink::mojom::blink::PaymentOptions; |
39 using blink::mojom::blink::PaymentOptionsPtr; | 39 using blink::mojom::blink::PaymentOptionsPtr; |
40 using blink::mojom::blink::ShippingOption; | 40 using blink::mojom::blink::ShippingOption; |
41 using blink::mojom::blink::ShippingOptionPtr; | 41 using blink::mojom::blink::ShippingOptionPtr; |
42 using blink::mojom::blink::PaymentMethodData; | |
43 using blink::mojom::blink::PaymentMethodDataPtr; | |
please use gerrit instead
2016/05/29 19:57:12
Sort alphabetically.
zino
2016/06/01 17:43:46
Done.
| |
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(); |
48 output->currency_code = input.currency(); | 50 output->currency_code = input.currency(); |
49 output->value = input.value(); | 51 output->value = input.value(); |
50 return output; | 52 return output; |
51 } | 53 } |
(...skipping 39 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<PaymentMethodDataPtr, blink::PaymentMethodData> { | |
105 static PaymentMethodDataPtr Convert(const blink::PaymentMethodData& input) | |
106 { | |
107 PaymentMethodDataPtr output = PaymentMethodData::New(); | |
108 output->supported_methods = Vector<WTF::String>(input.supportedMethods() ); | |
please use gerrit instead
2016/05/29 19:57:12
output->supported_methods = mojom::WTFArray<String
zino
2016/06/01 17:43:46
I'm not sure but it's better to avoid unnecessary
| |
109 if (!input.data().isEmpty()) | |
please use gerrit instead
2016/05/29 19:57:12
if (input.hasData() && !input.data().isEmpty())
zino
2016/06/01 17:43:46
Done.
| |
110 output->data = blink::JSONObject::cast(blink::toJSONValue(input.data ().context(), input.data().v8Value()))->toJSONString(); | |
111 return output; | |
112 } | |
113 }; | |
114 | |
101 } // namespace mojo | 115 } // namespace mojo |
102 | 116 |
103 namespace blink { | 117 namespace blink { |
104 namespace { | 118 namespace { |
105 | 119 |
106 // Validates ShippingOption and PaymentItem dictionaries, which happen to have i dentical fields. | 120 // Validates ShippingOption and PaymentItem dictionaries, which happen to have i dentical fields. |
107 // except for "id", which is present only in ShippingOption. | 121 // except for "id", which is present only in ShippingOption. |
108 template <typename T> | 122 template <typename T> |
109 void validateShippingOptionsOrPaymentItems(HeapVector<T> items, ExceptionState& exceptionState) | 123 void validateShippingOptionsOrPaymentItems(HeapVector<T> items, ExceptionState& exceptionState) |
110 { | 124 { |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
167 validateShippingOptionsOrPaymentItems(details.items(), exceptionState); | 181 validateShippingOptionsOrPaymentItems(details.items(), exceptionState); |
168 if (exceptionState.hadException()) | 182 if (exceptionState.hadException()) |
169 return; | 183 return; |
170 | 184 |
171 if (details.hasShippingOptions()) { | 185 if (details.hasShippingOptions()) { |
172 validateShippingOptionsOrPaymentItems(details.shippingOptions(), excepti onState); | 186 validateShippingOptionsOrPaymentItems(details.shippingOptions(), excepti onState); |
173 validateShippingOptionsIds(details.shippingOptions(), exceptionState); | 187 validateShippingOptionsIds(details.shippingOptions(), exceptionState); |
174 } | 188 } |
175 } | 189 } |
176 | 190 |
191 void validatePaymentMethodData(const HeapVector<PaymentMethodData>& methodData, ExceptionState& exceptionState) | |
192 { | |
193 for (const auto& md : methodData) { | |
194 if (md.supportedMethods().isEmpty()) { | |
195 exceptionState.throwTypeError("Must specify at least one payment met hod identifier"); | |
196 return; | |
197 } | |
198 | |
199 if (!md.data().isEmpty()) { | |
200 RefPtr<JSONValue> value = toJSONValue(md.data().context(), md.data() .v8Value()); | |
201 if (!value) { | |
202 exceptionState.throwTypeError("Unable to parse payment method sp ecific data"); | |
203 return; | |
204 } | |
205 if (!value->isNull() && value->getType() != JSONValue::TypeObject) { | |
206 exceptionState.throwTypeError("Data should be a JSON-serializabl e object"); | |
207 return; | |
208 } | |
209 } | |
210 } | |
211 } | |
212 | |
177 } // namespace | 213 } // namespace |
178 | 214 |
179 PaymentRequest* PaymentRequest::create(ScriptState* scriptState, const Vector<St ring>& supportedMethods, const PaymentDetails& details, ExceptionState& exceptio nState) | 215 PaymentRequest* PaymentRequest::create(ScriptState* scriptState, const HeapVecto r<PaymentMethodData>& methodData, const PaymentDetails& details, ExceptionState& exceptionState) |
180 { | 216 { |
181 return new PaymentRequest(scriptState, supportedMethods, details, PaymentOpt ions(), ScriptValue(), exceptionState); | 217 return new PaymentRequest(scriptState, methodData, details, PaymentOptions() , exceptionState); |
182 } | 218 } |
183 | 219 |
184 PaymentRequest* PaymentRequest::create(ScriptState* scriptState, const Vector<St ring>& supportedMethods, const PaymentDetails& details, const PaymentOptions& op tions, ExceptionState& exceptionState) | 220 PaymentRequest* PaymentRequest::create(ScriptState* scriptState, const HeapVecto r<PaymentMethodData>& methodData, const PaymentDetails& details, const PaymentOp tions& options, ExceptionState& exceptionState) |
185 { | 221 { |
186 return new PaymentRequest(scriptState, supportedMethods, details, options, S criptValue(), exceptionState); | 222 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 } | 223 } |
193 | 224 |
194 PaymentRequest::~PaymentRequest() | 225 PaymentRequest::~PaymentRequest() |
195 { | 226 { |
196 } | 227 } |
197 | 228 |
198 ScriptPromise PaymentRequest::show(ScriptState* scriptState) | 229 ScriptPromise PaymentRequest::show(ScriptState* scriptState) |
199 { | 230 { |
200 if (m_showResolver) | 231 if (m_showResolver) |
201 return ScriptPromise::rejectWithDOMException(scriptState, DOMException:: create(InvalidStateError, "Already called show() once")); | 232 return ScriptPromise::rejectWithDOMException(scriptState, DOMException:: create(InvalidStateError, "Already called show() once")); |
202 | 233 |
203 if (!scriptState->domWindow() || !scriptState->domWindow()->frame()) | 234 if (!scriptState->domWindow() || !scriptState->domWindow()->frame()) |
204 return ScriptPromise::rejectWithDOMException(scriptState, DOMException:: create(InvalidStateError, "Cannot show the payment request")); | 235 return ScriptPromise::rejectWithDOMException(scriptState, DOMException:: create(InvalidStateError, "Cannot show the payment request")); |
205 | 236 |
206 DCHECK(!m_paymentProvider.is_bound()); | 237 DCHECK(!m_paymentProvider.is_bound()); |
207 scriptState->domWindow()->frame()->serviceRegistry()->connectToRemoteService (mojo::GetProxy(&m_paymentProvider)); | 238 scriptState->domWindow()->frame()->serviceRegistry()->connectToRemoteService (mojo::GetProxy(&m_paymentProvider)); |
208 m_paymentProvider.set_connection_error_handler(createBaseCallback(bind(&Paym entRequest::OnError, WeakPersistentThisPointer<PaymentRequest>(this)))); | 239 m_paymentProvider.set_connection_error_handler(createBaseCallback(bind(&Paym entRequest::OnError, WeakPersistentThisPointer<PaymentRequest>(this)))); |
209 m_paymentProvider->SetClient(m_clientBinding.CreateInterfacePtrAndBind()); | 240 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); | 241 m_paymentProvider->Show(mojo::WTFArray<blink::mojom::blink::PaymentMethodDat aPtr>::From(m_methodData), mojom::blink::PaymentDetails::From(m_details), mojom: :blink::PaymentOptions::From(m_options)); |
211 | |
212 m_showResolver = ScriptPromiseResolver::create(scriptState); | 242 m_showResolver = ScriptPromiseResolver::create(scriptState); |
213 return m_showResolver->promise(); | 243 return m_showResolver->promise(); |
214 } | 244 } |
215 | 245 |
216 void PaymentRequest::abort(ExceptionState& exceptionState) | 246 void PaymentRequest::abort(ExceptionState& exceptionState) |
217 { | 247 { |
218 if (!m_showResolver) { | 248 if (!m_showResolver) { |
219 exceptionState.throwDOMException(InvalidStateError, "Never called show() , so nothing to abort"); | 249 exceptionState.throwDOMException(InvalidStateError, "Never called show() , so nothing to abort"); |
220 return; | 250 return; |
221 } | 251 } |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
279 { | 309 { |
280 if (m_showResolver) | 310 if (m_showResolver) |
281 m_showResolver->reject(error); | 311 m_showResolver->reject(error); |
282 if (m_completeResolver) | 312 if (m_completeResolver) |
283 m_completeResolver->reject(error); | 313 m_completeResolver->reject(error); |
284 clearResolversAndCloseMojoConnection(); | 314 clearResolversAndCloseMojoConnection(); |
285 } | 315 } |
286 | 316 |
287 DEFINE_TRACE(PaymentRequest) | 317 DEFINE_TRACE(PaymentRequest) |
288 { | 318 { |
319 visitor->trace(m_methodData); | |
289 visitor->trace(m_details); | 320 visitor->trace(m_details); |
290 visitor->trace(m_options); | 321 visitor->trace(m_options); |
291 visitor->trace(m_shippingAddress); | 322 visitor->trace(m_shippingAddress); |
292 visitor->trace(m_showResolver); | 323 visitor->trace(m_showResolver); |
293 visitor->trace(m_completeResolver); | 324 visitor->trace(m_completeResolver); |
294 EventTargetWithInlineData::trace(visitor); | 325 EventTargetWithInlineData::trace(visitor); |
295 ContextLifecycleObserver::trace(visitor); | 326 ContextLifecycleObserver::trace(visitor); |
296 } | 327 } |
297 | 328 |
298 PaymentRequest::PaymentRequest(ScriptState* scriptState, const Vector<String>& s upportedMethods, const PaymentDetails& details, const PaymentOptions& options, c onst ScriptValue& data, ExceptionState& exceptionState) | 329 PaymentRequest::PaymentRequest(ScriptState* scriptState, const HeapVector<Paymen tMethodData>& methodData, const PaymentDetails& details, const PaymentOptions& o ptions, ExceptionState& exceptionState) |
299 : ContextLifecycleObserver(scriptState->getExecutionContext()) | 330 : ContextLifecycleObserver(scriptState->getExecutionContext()) |
300 , ActiveScriptWrappable(this) | 331 , ActiveScriptWrappable(this) |
301 , m_options(options) | 332 , m_options(options) |
302 , m_clientBinding(this) | 333 , m_clientBinding(this) |
303 { | 334 { |
335 if (methodData.isEmpty()) { | |
please use gerrit instead
2016/05/29 19:57:12
This block should be inside of validatePaymentMeth
zino
2016/06/01 17:43:46
Done.
| |
336 exceptionState.throwTypeError("Must specify at least one payment method identifier"); | |
337 return; | |
338 } | |
339 | |
340 validatePaymentMethodData(methodData, exceptionState); | |
341 if (exceptionState.hadException()) | |
342 return; | |
343 m_methodData = methodData; | |
344 | |
304 // TODO(rouslan): Also check for a top-level browsing context. | 345 // TODO(rouslan): Also check for a top-level browsing context. |
305 // https://github.com/w3c/browser-payment-api/issues/2 | 346 // https://github.com/w3c/browser-payment-api/issues/2 |
306 if (!scriptState->getExecutionContext()->isSecureContext()) { | 347 if (!scriptState->getExecutionContext()->isSecureContext()) { |
307 exceptionState.throwSecurityError("Must be in a secure context"); | 348 exceptionState.throwSecurityError("Must be in a secure context"); |
308 return; | 349 return; |
309 } | 350 } |
310 | 351 |
311 if (supportedMethods.isEmpty()) { | |
312 exceptionState.throwTypeError("Must specify at least one payment method identifier"); | |
313 return; | |
314 } | |
315 m_supportedMethods = supportedMethods; | |
316 | |
317 validatePaymentDetails(details, exceptionState); | 352 validatePaymentDetails(details, exceptionState); |
318 if (exceptionState.hadException()) | 353 if (exceptionState.hadException()) |
319 return; | 354 return; |
320 m_details = details; | 355 m_details = details; |
321 | 356 |
322 if (!data.isEmpty()) { | |
323 RefPtr<JSONValue> value = toJSONValue(data.context(), data.v8Value()); | |
324 if (!value) { | |
325 exceptionState.throwTypeError("Unable to parse payment method specif ic data"); | |
326 return; | |
327 } | |
328 if (!value->isNull()) { | |
329 if (value->getType() != JSONValue::TypeObject) { | |
330 exceptionState.throwTypeError("Payment method specific data shou ld be a JSON-serializable object"); | |
331 return; | |
332 } | |
333 | |
334 RefPtr<JSONObject> jsonData = JSONObject::cast(value); | |
335 for (const auto& paymentMethodSpecificKeyValue : *jsonData) { | |
336 if (!supportedMethods.contains(paymentMethodSpecificKeyValue.key )) { | |
337 exceptionState.throwTypeError("'" + paymentMethodSpecificKey Value.key + "' should match one of the payment method identifiers"); | |
338 return; | |
339 } | |
340 if (paymentMethodSpecificKeyValue.value->getType() != JSONValue: :TypeObject) { | |
341 exceptionState.throwTypeError("Data for '" + paymentMethodSp ecificKeyValue.key + "' should be a JSON-serializable object"); | |
342 return; | |
343 } | |
344 } | |
345 | |
346 m_stringifiedData = jsonData->toJSONString(); | |
347 } | |
348 } | |
349 | |
350 // Set the currently selected option if only one option is passed and shippi ng is requested. | 357 // Set the currently selected option if only one option is passed and shippi ng is requested. |
351 if (options.requestShipping() && details.hasShippingOptions() && details.shi ppingOptions().size() == 1) | 358 if (options.requestShipping() && details.hasShippingOptions() && details.shi ppingOptions().size() == 1) |
352 m_shippingOption = details.shippingOptions().begin()->id(); | 359 m_shippingOption = details.shippingOptions().begin()->id(); |
353 } | 360 } |
354 | 361 |
355 void PaymentRequest::contextDestroyed() | 362 void PaymentRequest::contextDestroyed() |
356 { | 363 { |
357 clearResolversAndCloseMojoConnection(); | 364 clearResolversAndCloseMojoConnection(); |
358 } | 365 } |
359 | 366 |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
440 void PaymentRequest::clearResolversAndCloseMojoConnection() | 447 void PaymentRequest::clearResolversAndCloseMojoConnection() |
441 { | 448 { |
442 m_completeResolver.clear(); | 449 m_completeResolver.clear(); |
443 m_showResolver.clear(); | 450 m_showResolver.clear(); |
444 if (m_clientBinding.is_bound()) | 451 if (m_clientBinding.is_bound()) |
445 m_clientBinding.Close(); | 452 m_clientBinding.Close(); |
446 m_paymentProvider.reset(); | 453 m_paymentProvider.reset(); |
447 } | 454 } |
448 | 455 |
449 } // namespace blink | 456 } // namespace blink |
OLD | NEW |