Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(116)

Side by Side Diff: third_party/WebKit/Source/modules/payments/PaymentRequest.cpp

Issue 2470463002: Add data parameter to payment details modifier. (Closed)
Patch Set: Address palmer and haraken comments Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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/ScriptPromiseResolver.h" 8 #include "bindings/core/v8/ScriptPromiseResolver.h"
9 #include "bindings/core/v8/ScriptState.h" 9 #include "bindings/core/v8/ScriptState.h"
10 #include "bindings/core/v8/V8StringResource.h" 10 #include "bindings/core/v8/V8StringResource.h"
(...skipping 17 matching lines...) Expand all
28 #include "modules/payments/PaymentShippingOption.h" 28 #include "modules/payments/PaymentShippingOption.h"
29 #include "modules/payments/PaymentsValidators.h" 29 #include "modules/payments/PaymentsValidators.h"
30 #include "mojo/public/cpp/bindings/interface_request.h" 30 #include "mojo/public/cpp/bindings/interface_request.h"
31 #include "mojo/public/cpp/bindings/wtf_array.h" 31 #include "mojo/public/cpp/bindings/wtf_array.h"
32 #include "platform/RuntimeEnabledFeatures.h" 32 #include "platform/RuntimeEnabledFeatures.h"
33 #include "platform/mojo/MojoHelper.h" 33 #include "platform/mojo/MojoHelper.h"
34 #include "public/platform/InterfaceProvider.h" 34 #include "public/platform/InterfaceProvider.h"
35 #include "public/platform/Platform.h" 35 #include "public/platform/Platform.h"
36 #include "public/platform/WebTraceLocation.h" 36 #include "public/platform/WebTraceLocation.h"
37 #include "wtf/HashSet.h" 37 #include "wtf/HashSet.h"
38 #include <stddef.h>
38 #include <utility> 39 #include <utility>
39 40
40 using payments::mojom::blink::ActivePaymentQueryResult; 41 using payments::mojom::blink::ActivePaymentQueryResult;
41 using payments::mojom::blink::PaymentAddressPtr; 42 using payments::mojom::blink::PaymentAddressPtr;
42 using payments::mojom::blink::PaymentCurrencyAmount; 43 using payments::mojom::blink::PaymentCurrencyAmount;
43 using payments::mojom::blink::PaymentCurrencyAmountPtr; 44 using payments::mojom::blink::PaymentCurrencyAmountPtr;
44 using payments::mojom::blink::PaymentDetails;
45 using payments::mojom::blink::PaymentDetailsModifier;
46 using payments::mojom::blink::PaymentDetailsModifierPtr; 45 using payments::mojom::blink::PaymentDetailsModifierPtr;
47 using payments::mojom::blink::PaymentDetailsPtr; 46 using payments::mojom::blink::PaymentDetailsPtr;
48 using payments::mojom::blink::PaymentDetailsPtr;
49 using payments::mojom::blink::PaymentErrorReason; 47 using payments::mojom::blink::PaymentErrorReason;
50 using payments::mojom::blink::PaymentItem;
51 using payments::mojom::blink::PaymentItemPtr; 48 using payments::mojom::blink::PaymentItemPtr;
52 using payments::mojom::blink::PaymentMethodData;
53 using payments::mojom::blink::PaymentMethodDataPtr; 49 using payments::mojom::blink::PaymentMethodDataPtr;
54 using payments::mojom::blink::PaymentOptions;
55 using payments::mojom::blink::PaymentOptionsPtr; 50 using payments::mojom::blink::PaymentOptionsPtr;
56 using payments::mojom::blink::PaymentResponsePtr; 51 using payments::mojom::blink::PaymentResponsePtr;
57 using payments::mojom::blink::PaymentShippingOption;
58 using payments::mojom::blink::PaymentShippingOptionPtr; 52 using payments::mojom::blink::PaymentShippingOptionPtr;
59 using payments::mojom::blink::PaymentShippingType; 53 using payments::mojom::blink::PaymentShippingType;
60 54
61 namespace mojo { 55 namespace mojo {
62 56
63 template <> 57 template <>
64 struct TypeConverter<PaymentCurrencyAmountPtr, blink::PaymentCurrencyAmount> { 58 struct TypeConverter<PaymentCurrencyAmountPtr, blink::PaymentCurrencyAmount> {
65 static PaymentCurrencyAmountPtr Convert( 59 static PaymentCurrencyAmountPtr Convert(
66 const blink::PaymentCurrencyAmount& input) { 60 const blink::PaymentCurrencyAmount& input) {
67 PaymentCurrencyAmountPtr output = PaymentCurrencyAmount::New(); 61 PaymentCurrencyAmountPtr output = PaymentCurrencyAmount::New();
68 output->currency = input.currency(); 62 output->currency = input.currency();
69 output->value = input.value(); 63 output->value = input.value();
70 if (input.hasCurrencySystem()) 64 if (input.hasCurrencySystem())
71 output->currencySystem = input.currencySystem(); 65 output->currencySystem = input.currencySystem();
72 return output; 66 return output;
73 } 67 }
74 }; 68 };
75 69
76 template <> 70 template <>
77 struct TypeConverter<PaymentItemPtr, blink::PaymentItem> { 71 struct TypeConverter<PaymentItemPtr, blink::PaymentItem> {
78 static PaymentItemPtr Convert(const blink::PaymentItem& input) { 72 static PaymentItemPtr Convert(const blink::PaymentItem& input) {
79 PaymentItemPtr output = PaymentItem::New(); 73 PaymentItemPtr output = payments::mojom::blink::PaymentItem::New();
80 output->label = input.label(); 74 output->label = input.label();
81 output->amount = PaymentCurrencyAmount::From(input.amount()); 75 output->amount = PaymentCurrencyAmount::From(input.amount());
82 output->pending = input.pending(); 76 output->pending = input.pending();
83 return output; 77 return output;
84 } 78 }
85 }; 79 };
86 80
87 template <> 81 template <>
88 struct TypeConverter<PaymentShippingOptionPtr, blink::PaymentShippingOption> { 82 struct TypeConverter<PaymentShippingOptionPtr, blink::PaymentShippingOption> {
89 static PaymentShippingOptionPtr Convert( 83 static PaymentShippingOptionPtr Convert(
90 const blink::PaymentShippingOption& input) { 84 const blink::PaymentShippingOption& input) {
91 PaymentShippingOptionPtr output = PaymentShippingOption::New(); 85 PaymentShippingOptionPtr output =
86 payments::mojom::blink::PaymentShippingOption::New();
92 output->id = input.id(); 87 output->id = input.id();
93 output->label = input.label(); 88 output->label = input.label();
94 output->amount = PaymentCurrencyAmount::From(input.amount()); 89 output->amount = PaymentCurrencyAmount::From(input.amount());
95 output->selected = input.hasSelected() && input.selected(); 90 output->selected = input.hasSelected() && input.selected();
96 return output; 91 return output;
97 } 92 }
98 }; 93 };
99 94
100 template <> 95 template <>
101 struct TypeConverter<PaymentDetailsModifierPtr, blink::PaymentDetailsModifier> {
102 static PaymentDetailsModifierPtr Convert(
103 const blink::PaymentDetailsModifier& input) {
104 PaymentDetailsModifierPtr output = PaymentDetailsModifier::New();
105 output->supported_methods = input.supportedMethods();
106
107 if (input.hasTotal())
108 output->total = PaymentItem::From(input.total());
109
110 if (input.hasAdditionalDisplayItems()) {
111 for (size_t i = 0; i < input.additionalDisplayItems().size(); ++i) {
112 output->additional_display_items.append(
113 PaymentItem::From(input.additionalDisplayItems()[i]));
114 }
115 }
116 return output;
117 }
118 };
119
120 template <>
121 struct TypeConverter<PaymentDetailsPtr, blink::PaymentDetails> {
122 static PaymentDetailsPtr Convert(const blink::PaymentDetails& input) {
123 PaymentDetailsPtr output = PaymentDetails::New();
124 output->total = PaymentItem::From(input.total());
125
126 if (input.hasDisplayItems()) {
127 for (size_t i = 0; i < input.displayItems().size(); ++i) {
128 output->display_items.append(
129 PaymentItem::From(input.displayItems()[i]));
130 }
131 }
132
133 if (input.hasShippingOptions()) {
134 for (size_t i = 0; i < input.shippingOptions().size(); ++i) {
135 output->shipping_options.append(
136 PaymentShippingOption::From(input.shippingOptions()[i]));
137 }
138 }
139
140 if (input.hasModifiers()) {
141 for (size_t i = 0; i < input.modifiers().size(); ++i) {
142 output->modifiers.append(
143 PaymentDetailsModifier::From(input.modifiers()[i]));
144 }
145 }
146
147 if (input.hasError())
148 output->error = input.error();
149 else
150 output->error = emptyString();
151
152 return output;
153 }
154 };
155
156 template <>
157 struct TypeConverter<PaymentOptionsPtr, blink::PaymentOptions> { 96 struct TypeConverter<PaymentOptionsPtr, blink::PaymentOptions> {
158 static PaymentOptionsPtr Convert(const blink::PaymentOptions& input) { 97 static PaymentOptionsPtr Convert(const blink::PaymentOptions& input) {
159 PaymentOptionsPtr output = PaymentOptions::New(); 98 PaymentOptionsPtr output = payments::mojom::blink::PaymentOptions::New();
160 output->request_payer_name = input.requestPayerName(); 99 output->request_payer_name = input.requestPayerName();
161 output->request_payer_email = input.requestPayerEmail(); 100 output->request_payer_email = input.requestPayerEmail();
162 output->request_payer_phone = input.requestPayerPhone(); 101 output->request_payer_phone = input.requestPayerPhone();
163 output->request_shipping = input.requestShipping(); 102 output->request_shipping = input.requestShipping();
164 103
165 if (input.shippingType() == "delivery") 104 if (input.shippingType() == "delivery")
166 output->shipping_type = PaymentShippingType::DELIVERY; 105 output->shipping_type = PaymentShippingType::DELIVERY;
167 else if (input.shippingType() == "pickup") 106 else if (input.shippingType() == "pickup")
168 output->shipping_type = PaymentShippingType::PICKUP; 107 output->shipping_type = PaymentShippingType::PICKUP;
169 else 108 else
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
233 return; 172 return;
234 } 173 }
235 174
236 if (!PaymentsValidators::isValidAmountFormat(item.amount().value(), 175 if (!PaymentsValidators::isValidAmountFormat(item.amount().value(),
237 &errorMessage)) { 176 &errorMessage)) {
238 exceptionState.throwTypeError(errorMessage); 177 exceptionState.throwTypeError(errorMessage);
239 return; 178 return;
240 } 179 }
241 } 180 }
242 181
243 void validateDisplayItems(const HeapVector<PaymentItem>& items, 182 void validateAndConvertDisplayItems(const HeapVector<PaymentItem>& input,
244 ExceptionState& exceptionState) { 183 Vector<PaymentItemPtr>& output,
245 for (const auto& item : items) { 184 ExceptionState& exceptionState) {
185 output.resize(input.size());
186 for (size_t i = 0; i < input.size(); ++i) {
187 const PaymentItem& item = input[i];
246 validateShippingOptionOrPaymentItem(item, exceptionState); 188 validateShippingOptionOrPaymentItem(item, exceptionState);
247 if (exceptionState.hadException()) 189 if (exceptionState.hadException())
248 return; 190 return;
191 output[i] = payments::mojom::blink::PaymentItem::From(item);
249 } 192 }
250 } 193 }
251 194
252 // Returns false if |options| should be ignored, even if an exception was not 195 // Validates and converts |input| shipping options into |output|. Throws an
253 // thrown. TODO(rouslan): Clear shipping options instead of ignoring them when 196 // exception if the data is not valid, except for duplicate identifiers, which
254 // http://crbug.com/601193 is fixed. 197 // returns an empty |output| instead of throwing an exception. There's no need
255 bool validateShippingOptions(const HeapVector<PaymentShippingOption>& options, 198 // to clear |output| when an exception is thrown, because the caller takes care
256 ExceptionState& exceptionState) { 199 // of deleting |output|.
200 void validateAndConvertShippingOptions(
201 const HeapVector<PaymentShippingOption>& input,
202 Vector<PaymentShippingOptionPtr>& output,
203 ExceptionState& exceptionState) {
204 output.resize(input.size());
257 HashSet<String> uniqueIds; 205 HashSet<String> uniqueIds;
258 for (const auto& option : options) { 206 for (size_t i = 0; i < input.size(); ++i) {
207 const PaymentShippingOption& option = input[i];
259 if (!option.hasId() || option.id().isEmpty()) { 208 if (!option.hasId() || option.id().isEmpty()) {
260 exceptionState.throwTypeError("ShippingOption id required"); 209 exceptionState.throwTypeError("ShippingOption id required");
261 return false; 210 return;
262 } 211 }
263 212
264 if (uniqueIds.contains(option.id())) 213 if (uniqueIds.contains(option.id())) {
265 return false; 214 // Clear |output| instead of throwing an exception.
215 output.clear();
216 return;
217 }
266 218
267 uniqueIds.add(option.id()); 219 uniqueIds.add(option.id());
268 220
269 validateShippingOptionOrPaymentItem(option, exceptionState); 221 validateShippingOptionOrPaymentItem(option, exceptionState);
270 if (exceptionState.hadException()) 222 if (exceptionState.hadException())
271 return false; 223 return;
224
225 output[i] = payments::mojom::blink::PaymentShippingOption::From(input[i]);
272 } 226 }
273
274 return true;
275 } 227 }
276 228
277 void validatePaymentDetailsModifiers( 229 void validateAndConvertTotal(const PaymentItem& input,
278 const HeapVector<PaymentDetailsModifier>& modifiers, 230 PaymentItemPtr& output,
279 ExceptionState& exceptionState) { 231 ExceptionState& exceptionState) {
280 if (modifiers.isEmpty()) { 232 validateShippingOptionOrPaymentItem(input, exceptionState);
281 exceptionState.throwTypeError( 233 if (exceptionState.hadException())
282 "Must specify at least one payment details modifier"); 234 return;
235
236 if (input.amount().value()[0] == '-') {
237 exceptionState.throwTypeError("Total amount value should be non-negative");
283 return; 238 return;
284 } 239 }
285 240
286 for (const auto& modifier : modifiers) { 241 output = payments::mojom::blink::PaymentItem::From(input);
287 if (modifier.supportedMethods().isEmpty()) {
288 exceptionState.throwTypeError(
289 "Must specify at least one payment method identifier");
290 return;
291 }
292
293 if (modifier.hasTotal()) {
294 validateShippingOptionOrPaymentItem(modifier.total(), exceptionState);
295 if (exceptionState.hadException())
296 return;
297
298 if (modifier.total().amount().value()[0] == '-') {
299 exceptionState.throwTypeError(
300 "Total amount value should be non-negative");
301 return;
302 }
303 }
304
305 if (modifier.hasAdditionalDisplayItems()) {
306 validateDisplayItems(modifier.additionalDisplayItems(), exceptionState);
307 if (exceptionState.hadException())
308 return;
309 }
310 }
311 } 242 }
312 243
313 // Returns false if the shipping options should be ignored without throwing an 244 void maybeSetAndroidPayMethodData(const ScriptValue& input,
314 // exception. 245 PaymentMethodDataPtr& output,
315 bool validatePaymentDetails(const PaymentDetails& details, 246 ExceptionState& exceptionState) {
316 ExceptionState& exceptionState) {
317 bool keepShippingOptions = true;
318 if (!details.hasTotal()) {
319 exceptionState.throwTypeError("Must specify total");
320 return keepShippingOptions;
321 }
322
323 validateShippingOptionOrPaymentItem(details.total(), exceptionState);
324 if (exceptionState.hadException())
325 return keepShippingOptions;
326
327 if (details.total().amount().value()[0] == '-') {
328 exceptionState.throwTypeError("Total amount value should be non-negative");
329 return keepShippingOptions;
330 }
331
332 if (details.hasDisplayItems()) {
333 validateDisplayItems(details.displayItems(), exceptionState);
334 if (exceptionState.hadException())
335 return keepShippingOptions;
336 }
337
338 if (details.hasShippingOptions()) {
339 keepShippingOptions =
340 validateShippingOptions(details.shippingOptions(), exceptionState);
341
342 if (exceptionState.hadException())
343 return keepShippingOptions;
344 }
345
346 if (details.hasModifiers()) {
347 validatePaymentDetailsModifiers(details.modifiers(), exceptionState);
348 if (exceptionState.hadException())
349 return keepShippingOptions;
350 }
351
352 String errorMessage;
353 if (!PaymentsValidators::isValidErrorMsgFormat(details.error(),
354 &errorMessage)) {
355 exceptionState.throwTypeError(errorMessage);
356 }
357
358 return keepShippingOptions;
359 }
360
361 void maybeSetAndroidPayMethodData(
362 const ScriptValue& input,
363 payments::mojom::blink::PaymentMethodDataPtr& output,
364 ExceptionState& exceptionState) {
365 AndroidPayMethodData androidPay; 247 AndroidPayMethodData androidPay;
366 TrackExceptionState trackExceptionState; 248 TrackExceptionState trackExceptionState;
367 V8AndroidPayMethodData::toImpl(input.isolate(), input.v8Value(), androidPay, 249 V8AndroidPayMethodData::toImpl(input.isolate(), input.v8Value(), androidPay,
368 trackExceptionState); 250 trackExceptionState);
369 if (trackExceptionState.hadException()) 251 if (trackExceptionState.hadException())
370 return; 252 return;
371 253
372 if (androidPay.hasEnvironment() && androidPay.environment() == "TEST") 254 if (androidPay.hasEnvironment() && androidPay.environment() == "TEST")
373 output->environment = payments::mojom::blink::AndroidPayEnvironment::TEST; 255 output->environment = payments::mojom::blink::AndroidPayEnvironment::TEST;
374 256
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
421 payments::mojom::blink::AndroidPayTokenizationParameter::New(); 303 payments::mojom::blink::AndroidPayTokenizationParameter::New();
422 output->parameters[numberOfParameters]->key = keys[i]; 304 output->parameters[numberOfParameters]->key = keys[i];
423 output->parameters[numberOfParameters]->value = value; 305 output->parameters[numberOfParameters]->value = value;
424 ++numberOfParameters; 306 ++numberOfParameters;
425 } 307 }
426 output->parameters.resize(numberOfParameters); 308 output->parameters.resize(numberOfParameters);
427 } 309 }
428 } 310 }
429 } 311 }
430 312
313 void stringifyAndParseMethodSpecificData(const ScriptValue& input,
314 PaymentMethodDataPtr& output,
315 ExceptionState& exceptionState) {
316 DCHECK(!input.isEmpty());
317 if (!input.v8Value()->IsObject() || input.v8Value()->IsArray()) {
318 exceptionState.throwTypeError("Data should be a JSON-serializable object");
319 return;
320 }
321
322 v8::Local<v8::String> value;
323 if (!v8::JSON::Stringify(input.context(), input.v8Value().As<v8::Object>())
324 .ToLocal(&value)) {
325 exceptionState.throwTypeError(
326 "Unable to parse payment method specific data");
327 return;
328 }
329
330 output->stringified_data =
331 v8StringToWebCoreString<String>(value, DoNotExternalize);
332 maybeSetAndroidPayMethodData(input, output, exceptionState);
333 }
334
335 void validateAndConvertPaymentDetailsModifiers(
336 const HeapVector<PaymentDetailsModifier>& input,
337 Vector<PaymentDetailsModifierPtr>& output,
338 ExceptionState& exceptionState) {
339 if (input.isEmpty()) {
340 exceptionState.throwTypeError(
341 "Must specify at least one payment details modifier");
342 return;
343 }
344
345 output.resize(input.size());
346 for (size_t i = 0; i < input.size(); ++i) {
347 const PaymentDetailsModifier& modifier = input[i];
348 output[i] = payments::mojom::blink::PaymentDetailsModifier::New();
349 if (modifier.hasTotal()) {
350 validateAndConvertTotal(modifier.total(), output[i]->total,
351 exceptionState);
352 if (exceptionState.hadException())
353 return;
354 }
355
356 if (modifier.hasAdditionalDisplayItems()) {
357 validateAndConvertDisplayItems(modifier.additionalDisplayItems(),
358 output[i]->additional_display_items,
359 exceptionState);
360 if (exceptionState.hadException())
361 return;
362 }
363
364 if (modifier.supportedMethods().isEmpty()) {
365 exceptionState.throwTypeError(
366 "Must specify at least one payment method identifier");
367 return;
368 }
369
370 output[i]->method_data = payments::mojom::blink::PaymentMethodData::New();
371 output[i]->method_data->supported_methods = modifier.supportedMethods();
372
373 if (modifier.hasData() && !modifier.data().isEmpty()) {
374 stringifyAndParseMethodSpecificData(
375 modifier.data(), output[i]->method_data, exceptionState);
376 if (exceptionState.hadException())
377 return;
378 } else {
379 output[i]->method_data->stringified_data = "";
380 }
381 }
382 }
383
384 String getSelectedShippingOption(
385 const Vector<PaymentShippingOptionPtr>& shippingOptions) {
386 String result;
387 for (size_t i = 0; i < shippingOptions.size(); ++i) {
388 if (shippingOptions[i]->selected)
389 result = shippingOptions[i]->id;
390 }
391 return result;
392 }
393
394 void validateAndConvertPaymentDetails(const PaymentDetails& input,
395 bool requestShipping,
396 PaymentDetailsPtr& output,
397 String& shippingOptionOutput,
398 ExceptionState& exceptionState) {
399 if (!input.hasTotal()) {
400 exceptionState.throwTypeError("Must specify total");
401 return;
402 }
403
404 validateAndConvertTotal(input.total(), output->total, exceptionState);
405 if (exceptionState.hadException())
406 return;
407
408 if (input.hasDisplayItems()) {
409 validateAndConvertDisplayItems(input.displayItems(), output->display_items,
410 exceptionState);
411 if (exceptionState.hadException())
412 return;
413 }
414
415 if (input.hasShippingOptions() && requestShipping) {
416 validateAndConvertShippingOptions(input.shippingOptions(),
417 output->shipping_options, exceptionState);
418 if (exceptionState.hadException())
419 return;
420 }
421
422 shippingOptionOutput = getSelectedShippingOption(output->shipping_options);
423
424 if (input.hasModifiers()) {
425 validateAndConvertPaymentDetailsModifiers(
426 input.modifiers(), output->modifiers, exceptionState);
427 if (exceptionState.hadException())
428 return;
429 }
430
431 if (input.hasError() && !input.error().isNull()) {
432 String errorMessage;
433 if (!PaymentsValidators::isValidErrorMsgFormat(input.error(),
434 &errorMessage)) {
435 exceptionState.throwTypeError(errorMessage);
436 return;
437 }
438 output->error = input.error();
439 } else {
440 output->error = "";
441 }
442 }
443
431 void validateAndConvertPaymentMethodData( 444 void validateAndConvertPaymentMethodData(
432 const HeapVector<PaymentMethodData>& input, 445 const HeapVector<PaymentMethodData>& input,
433 Vector<payments::mojom::blink::PaymentMethodDataPtr>& output, 446 Vector<payments::mojom::blink::PaymentMethodDataPtr>& output,
434 ExceptionState& exceptionState) { 447 ExceptionState& exceptionState) {
435 if (input.isEmpty()) { 448 if (input.isEmpty()) {
436 exceptionState.throwTypeError( 449 exceptionState.throwTypeError(
437 "Must specify at least one payment method identifier"); 450 "Must specify at least one payment method identifier");
438 return; 451 return;
439 } 452 }
440 453
441 output.resize(input.size()); 454 output.resize(input.size());
442 for (size_t i = 0; i < input.size(); ++i) { 455 for (size_t i = 0; i < input.size(); ++i) {
443 const auto& paymentMethodData = input[i]; 456 const auto& paymentMethodData = input[i];
444 if (paymentMethodData.supportedMethods().isEmpty()) { 457 if (paymentMethodData.supportedMethods().isEmpty()) {
445 exceptionState.throwTypeError( 458 exceptionState.throwTypeError(
446 "Must specify at least one payment method identifier"); 459 "Must specify at least one payment method identifier");
447 return; 460 return;
448 } 461 }
449 462
450 String stringifiedData = "";
451 if (paymentMethodData.hasData() && !paymentMethodData.data().isEmpty()) {
452 if (!paymentMethodData.data().v8Value()->IsObject() ||
453 paymentMethodData.data().v8Value()->IsArray()) {
454 exceptionState.throwTypeError(
455 "Data should be a JSON-serializable object");
456 return;
457 }
458
459 v8::Local<v8::String> value;
460 if (!v8::JSON::Stringify(
461 paymentMethodData.data().context(),
462 paymentMethodData.data().v8Value().As<v8::Object>())
463 .ToLocal(&value)) {
464 exceptionState.throwTypeError(
465 "Unable to parse payment method specific data");
466 return;
467 }
468 stringifiedData =
469 v8StringToWebCoreString<String>(value, DoNotExternalize);
470 }
471
472 output[i] = payments::mojom::blink::PaymentMethodData::New(); 463 output[i] = payments::mojom::blink::PaymentMethodData::New();
473 output[i]->supported_methods = paymentMethodData.supportedMethods(); 464 output[i]->supported_methods = paymentMethodData.supportedMethods();
474 output[i]->stringified_data = stringifiedData; 465
475 maybeSetAndroidPayMethodData(paymentMethodData.data(), output[i], 466 if (paymentMethodData.hasData() && !paymentMethodData.data().isEmpty()) {
476 exceptionState); 467 stringifyAndParseMethodSpecificData(paymentMethodData.data(), output[i],
477 if (exceptionState.hadException()) 468 exceptionState);
478 return; 469 if (exceptionState.hadException())
470 return;
471 } else {
472 output[i]->stringified_data = "";
473 }
479 } 474 }
480 } 475 }
481 476
482 String getSelectedShippingOption(const PaymentDetails& details) {
483 String result;
484 if (!details.hasShippingOptions())
485 return result;
486
487 for (int i = details.shippingOptions().size() - 1; i >= 0; --i) {
488 if (details.shippingOptions()[i].hasSelected() &&
489 details.shippingOptions()[i].selected()) {
490 return details.shippingOptions()[i].id();
491 }
492 }
493
494 return result;
495 }
496
497 String getValidShippingType(const String& shippingType) { 477 String getValidShippingType(const String& shippingType) {
498 static const char* const validValues[] = { 478 static const char* const validValues[] = {
499 "shipping", "delivery", "pickup", 479 "shipping", "delivery", "pickup",
500 }; 480 };
501 for (size_t i = 0; i < WTF_ARRAY_LENGTH(validValues); i++) { 481 for (size_t i = 0; i < WTF_ARRAY_LENGTH(validValues); i++) {
502 if (shippingType == validValues[i]) 482 if (shippingType == validValues[i])
503 return shippingType; 483 return shippingType;
504 } 484 }
505 return validValues[0]; 485 return validValues[0];
506 } 486 }
507 487
508 PaymentDetailsPtr maybeKeepShippingOptions(PaymentDetailsPtr details,
509 bool keep) {
510 if (!keep)
511 details->shipping_options.resize(0);
512
513 return details;
514 }
515
516 bool allowedToUsePaymentRequest(const Frame* frame) { 488 bool allowedToUsePaymentRequest(const Frame* frame) {
517 // To determine whether a Document object |document| is allowed to use the 489 // To determine whether a Document object |document| is allowed to use the
518 // feature indicated by attribute name |allowpaymentrequest|, run these steps: 490 // feature indicated by attribute name |allowpaymentrequest|, run these steps:
519 491
520 // 1. If |document| has no browsing context, then return false. 492 // 1. If |document| has no browsing context, then return false.
521 if (!frame) 493 if (!frame)
522 return false; 494 return false;
523 495
524 // 2. If |document|'s browsing context is a top-level browsing context, then 496 // 2. If |document|'s browsing context is a top-level browsing context, then
525 // return true. 497 // return true.
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after
665 V8PaymentDetails::toImpl(detailsScriptValue.isolate(), 637 V8PaymentDetails::toImpl(detailsScriptValue.isolate(),
666 detailsScriptValue.v8Value(), details, 638 detailsScriptValue.v8Value(), details,
667 exceptionState); 639 exceptionState);
668 if (exceptionState.hadException()) { 640 if (exceptionState.hadException()) {
669 m_showResolver->reject( 641 m_showResolver->reject(
670 DOMException::create(SyntaxError, exceptionState.message())); 642 DOMException::create(SyntaxError, exceptionState.message()));
671 clearResolversAndCloseMojoConnection(); 643 clearResolversAndCloseMojoConnection();
672 return; 644 return;
673 } 645 }
674 646
675 bool keepShippingOptions = validatePaymentDetails(details, exceptionState); 647 PaymentDetailsPtr validatedDetails =
648 payments::mojom::blink::PaymentDetails::New();
649 validateAndConvertPaymentDetails(details, m_options.requestShipping(),
650 validatedDetails, m_shippingOption,
651 exceptionState);
676 if (exceptionState.hadException()) { 652 if (exceptionState.hadException()) {
677 m_showResolver->reject( 653 m_showResolver->reject(
678 DOMException::create(SyntaxError, exceptionState.message())); 654 DOMException::create(SyntaxError, exceptionState.message()));
679 clearResolversAndCloseMojoConnection(); 655 clearResolversAndCloseMojoConnection();
680 return; 656 return;
681 } 657 }
682 658
683 if (m_options.requestShipping()) { 659 m_paymentProvider->UpdateWith(std::move(validatedDetails));
684 if (keepShippingOptions)
685 m_shippingOption = getSelectedShippingOption(details);
686 else
687 m_shippingOption = String();
688 }
689
690 m_paymentProvider->UpdateWith(maybeKeepShippingOptions(
691 payments::mojom::blink::PaymentDetails::From(details),
692 keepShippingOptions));
693 } 660 }
694 661
695 void PaymentRequest::onUpdatePaymentDetailsFailure(const String& error) { 662 void PaymentRequest::onUpdatePaymentDetailsFailure(const String& error) {
696 if (m_showResolver) 663 if (m_showResolver)
697 m_showResolver->reject(DOMException::create(AbortError, error)); 664 m_showResolver->reject(DOMException::create(AbortError, error));
698 if (m_completeResolver) 665 if (m_completeResolver)
699 m_completeResolver->reject(DOMException::create(AbortError, error)); 666 m_completeResolver->reject(DOMException::create(AbortError, error));
700 clearResolversAndCloseMojoConnection(); 667 clearResolversAndCloseMojoConnection();
701 } 668 }
702 669
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
739 706
740 if (!allowedToUsePaymentRequest(scriptState->domWindow()->frame())) { 707 if (!allowedToUsePaymentRequest(scriptState->domWindow()->frame())) {
741 exceptionState.throwSecurityError( 708 exceptionState.throwSecurityError(
742 RuntimeEnabledFeatures::paymentRequestIFrameEnabled() 709 RuntimeEnabledFeatures::paymentRequestIFrameEnabled()
743 ? "Must be in a top-level browsing context or an iframe needs to " 710 ? "Must be in a top-level browsing context or an iframe needs to "
744 "specify 'allowpaymentrequest' explicitly" 711 "specify 'allowpaymentrequest' explicitly"
745 : "Must be in a top-level browsing context"); 712 : "Must be in a top-level browsing context");
746 return; 713 return;
747 } 714 }
748 715
749 bool keepShippingOptions = validatePaymentDetails(details, exceptionState); 716 PaymentDetailsPtr validatedDetails =
717 payments::mojom::blink::PaymentDetails::New();
718 validateAndConvertPaymentDetails(details, m_options.requestShipping(),
719 validatedDetails, m_shippingOption,
720 exceptionState);
750 if (exceptionState.hadException()) 721 if (exceptionState.hadException())
751 return; 722 return;
752 723
753 if (details.hasError() && !details.error().isEmpty()) { 724 if (!validatedDetails->error.isEmpty()) {
754 exceptionState.throwTypeError("Error value should be empty"); 725 exceptionState.throwTypeError("Error value should be empty");
755 return; 726 return;
756 } 727 }
757 728
758 if (m_options.requestShipping()) { 729 if (m_options.requestShipping())
759 if (keepShippingOptions)
760 m_shippingOption = getSelectedShippingOption(details);
761 m_shippingType = getValidShippingType(m_options.shippingType()); 730 m_shippingType = getValidShippingType(m_options.shippingType());
762 }
763 731
764 scriptState->domWindow()->frame()->interfaceProvider()->getInterface( 732 scriptState->domWindow()->frame()->interfaceProvider()->getInterface(
765 mojo::GetProxy(&m_paymentProvider)); 733 mojo::GetProxy(&m_paymentProvider));
766 m_paymentProvider.set_connection_error_handler(convertToBaseCallback( 734 m_paymentProvider.set_connection_error_handler(convertToBaseCallback(
767 WTF::bind(&PaymentRequest::OnError, wrapWeakPersistent(this), 735 WTF::bind(&PaymentRequest::OnError, wrapWeakPersistent(this),
768 PaymentErrorReason::UNKNOWN))); 736 PaymentErrorReason::UNKNOWN)));
769 m_paymentProvider->Init( 737 m_paymentProvider->Init(
770 m_clientBinding.CreateInterfacePtrAndBind(), 738 m_clientBinding.CreateInterfacePtrAndBind(),
771 std::move(validatedMethodData), 739 std::move(validatedMethodData), std::move(validatedDetails),
772 maybeKeepShippingOptions(
773 payments::mojom::blink::PaymentDetails::From(details),
774 keepShippingOptions && m_options.requestShipping()),
775 payments::mojom::blink::PaymentOptions::From(m_options)); 740 payments::mojom::blink::PaymentOptions::From(m_options));
776 } 741 }
777 742
778 void PaymentRequest::contextDestroyed() { 743 void PaymentRequest::contextDestroyed() {
779 clearResolversAndCloseMojoConnection(); 744 clearResolversAndCloseMojoConnection();
780 } 745 }
781 746
782 void PaymentRequest::OnShippingAddressChange(PaymentAddressPtr address) { 747 void PaymentRequest::OnShippingAddressChange(PaymentAddressPtr address) {
783 DCHECK(m_showResolver); 748 DCHECK(m_showResolver);
784 DCHECK(!m_completeResolver); 749 DCHECK(!m_completeResolver);
(...skipping 21 matching lines...) Expand all
806 m_shippingOption = shippingOptionId; 771 m_shippingOption = shippingOptionId;
807 PaymentRequestUpdateEvent* event = 772 PaymentRequestUpdateEvent* event =
808 PaymentRequestUpdateEvent::create(EventTypeNames::shippingoptionchange); 773 PaymentRequestUpdateEvent::create(EventTypeNames::shippingoptionchange);
809 event->setTarget(this); 774 event->setTarget(this);
810 event->setPaymentDetailsUpdater(this); 775 event->setPaymentDetailsUpdater(this);
811 bool success = getExecutionContext()->getEventQueue()->enqueueEvent(event); 776 bool success = getExecutionContext()->getEventQueue()->enqueueEvent(event);
812 DCHECK(success); 777 DCHECK(success);
813 ALLOW_UNUSED_LOCAL(success); 778 ALLOW_UNUSED_LOCAL(success);
814 } 779 }
815 780
816 void PaymentRequest::OnPaymentResponse( 781 void PaymentRequest::OnPaymentResponse(PaymentResponsePtr response) {
817 payments::mojom::blink::PaymentResponsePtr response) {
818 DCHECK(m_showResolver); 782 DCHECK(m_showResolver);
819 DCHECK(!m_completeResolver); 783 DCHECK(!m_completeResolver);
820 DCHECK(!m_completeTimer.isActive()); 784 DCHECK(!m_completeTimer.isActive());
821 785
822 if (m_options.requestShipping()) { 786 if (m_options.requestShipping()) {
823 if (!response->shipping_address || response->shipping_option.isEmpty()) { 787 if (!response->shipping_address || response->shipping_option.isEmpty()) {
824 m_showResolver->reject(DOMException::create(SyntaxError)); 788 m_showResolver->reject(DOMException::create(SyntaxError));
825 clearResolversAndCloseMojoConnection(); 789 clearResolversAndCloseMojoConnection();
826 return; 790 return;
827 } 791 }
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after
972 m_completeResolver.clear(); 936 m_completeResolver.clear();
973 m_showResolver.clear(); 937 m_showResolver.clear();
974 m_abortResolver.clear(); 938 m_abortResolver.clear();
975 m_canMakeActivePaymentResolver.clear(); 939 m_canMakeActivePaymentResolver.clear();
976 if (m_clientBinding.is_bound()) 940 if (m_clientBinding.is_bound())
977 m_clientBinding.Close(); 941 m_clientBinding.Close();
978 m_paymentProvider.reset(); 942 m_paymentProvider.reset();
979 } 943 }
980 944
981 } // namespace blink 945 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698