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

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

Issue 2470463002: Add data parameter to payment details modifier. (Closed)
Patch Set: Rebase 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 for (const PaymentItem& item : input) {
246 validateShippingOptionOrPaymentItem(item, exceptionState); 186 validateShippingOptionOrPaymentItem(item, exceptionState);
247 if (exceptionState.hadException()) 187 if (exceptionState.hadException())
248 return; 188 return;
189 output.append(payments::mojom::blink::PaymentItem::From(item));
249 } 190 }
250 } 191 }
251 192
252 // Returns false if |options| should be ignored, even if an exception was not 193 // Validates and converts |input| shipping options into |output|. Throws an
253 // thrown. TODO(rouslan): Clear shipping options instead of ignoring them when 194 // exception if the data is not valid, except for duplicate identifiers, which
254 // http://crbug.com/601193 is fixed. 195 // returns an empty |output| instead of throwing an exception. There's no need
255 bool validateShippingOptions(const HeapVector<PaymentShippingOption>& options, 196 // to clear |output| when an exception is thrown, because the caller takes care
256 ExceptionState& exceptionState) { 197 // of deleting |output|.
198 void validateAndConvertShippingOptions(
199 const HeapVector<PaymentShippingOption>& input,
200 Vector<PaymentShippingOptionPtr>& output,
201 ExceptionState& exceptionState) {
257 HashSet<String> uniqueIds; 202 HashSet<String> uniqueIds;
258 for (const auto& option : options) { 203 for (const PaymentShippingOption& option : input) {
259 if (!option.hasId() || option.id().isEmpty()) { 204 if (!option.hasId() || option.id().isEmpty()) {
260 exceptionState.throwTypeError("ShippingOption id required"); 205 exceptionState.throwTypeError("ShippingOption id required");
261 return false; 206 return;
262 } 207 }
263 208
264 if (uniqueIds.contains(option.id())) 209 if (uniqueIds.contains(option.id())) {
265 return false; 210 // Clear |output| instead of throwing an exception.
211 output.clear();
212 return;
213 }
266 214
267 uniqueIds.add(option.id()); 215 uniqueIds.add(option.id());
268 216
269 validateShippingOptionOrPaymentItem(option, exceptionState); 217 validateShippingOptionOrPaymentItem(option, exceptionState);
270 if (exceptionState.hadException()) 218 if (exceptionState.hadException())
271 return false; 219 return;
220
221 output.append(payments::mojom::blink::PaymentShippingOption::From(option));
272 } 222 }
273
274 return true;
275 } 223 }
276 224
277 void validatePaymentDetailsModifiers( 225 void validateAndConvertTotal(const PaymentItem& input,
278 const HeapVector<PaymentDetailsModifier>& modifiers, 226 PaymentItemPtr& output,
279 ExceptionState& exceptionState) { 227 ExceptionState& exceptionState) {
280 if (modifiers.isEmpty()) { 228 validateShippingOptionOrPaymentItem(input, exceptionState);
281 exceptionState.throwTypeError( 229 if (exceptionState.hadException())
282 "Must specify at least one payment details modifier"); 230 return;
231
232 if (input.amount().value()[0] == '-') {
233 exceptionState.throwTypeError("Total amount value should be non-negative");
283 return; 234 return;
284 } 235 }
285 236
286 for (const auto& modifier : modifiers) { 237 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 } 238 }
312 239
313 // Returns false if the shipping options should be ignored without throwing an 240 void maybeSetAndroidPayMethodData(const ScriptValue& input,
314 // exception. 241 PaymentMethodDataPtr& output,
315 bool validatePaymentDetails(const PaymentDetails& details, 242 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; 243 AndroidPayMethodData androidPay;
366 DummyExceptionStateForTesting dummyExceptionState; 244 DummyExceptionStateForTesting dummyExceptionState;
367 V8AndroidPayMethodData::toImpl(input.isolate(), input.v8Value(), androidPay, 245 V8AndroidPayMethodData::toImpl(input.isolate(), input.v8Value(), androidPay,
368 dummyExceptionState); 246 dummyExceptionState);
369 if (dummyExceptionState.hadException()) 247 if (dummyExceptionState.hadException())
370 return; 248 return;
371 249
372 if (androidPay.hasEnvironment() && androidPay.environment() == "TEST") 250 if (androidPay.hasEnvironment() && androidPay.environment() == "TEST")
373 output->environment = payments::mojom::blink::AndroidPayEnvironment::TEST; 251 output->environment = payments::mojom::blink::AndroidPayEnvironment::TEST;
374 252
375 output->merchant_name = androidPay.merchantName(); 253 output->merchant_name = androidPay.merchantName();
376 output->merchant_id = androidPay.merchantId(); 254 output->merchant_id = androidPay.merchantId();
377 255
378 if (androidPay.hasAllowedCardNetworks()) { 256 if (androidPay.hasAllowedCardNetworks()) {
379 output->allowed_card_networks.resize( 257 for (const String& allowedCardNetwork : androidPay.allowedCardNetworks()) {
380 androidPay.allowedCardNetworks().size()); 258 for (size_t i = 0; i < arraysize(kAndroidPayNetwork); ++i) {
381 size_t numberOfNetworks = 0; 259 if (allowedCardNetwork == kAndroidPayNetwork[i].name) {
382 for (size_t i = 0; i < androidPay.allowedCardNetworks().size(); ++i) { 260 output->allowed_card_networks.append(kAndroidPayNetwork[i].code);
383 for (size_t j = 0; j < arraysize(kAndroidPayNetwork); ++j) {
384 if (androidPay.allowedCardNetworks()[i] == kAndroidPayNetwork[j].name) {
385 output->allowed_card_networks[numberOfNetworks++] =
386 kAndroidPayNetwork[j].code;
387 break; 261 break;
388 } 262 }
389 } 263 }
390 } 264 }
391 output->allowed_card_networks.resize(numberOfNetworks);
392 } 265 }
393 266
394 if (androidPay.hasPaymentMethodTokenizationParameters()) { 267 if (androidPay.hasPaymentMethodTokenizationParameters()) {
395 const blink::AndroidPayTokenization& tokenization = 268 const blink::AndroidPayTokenization& tokenization =
396 androidPay.paymentMethodTokenizationParameters(); 269 androidPay.paymentMethodTokenizationParameters();
397 output->tokenization_type = 270 output->tokenization_type =
398 payments::mojom::blink::AndroidPayTokenization::UNSPECIFIED; 271 payments::mojom::blink::AndroidPayTokenization::UNSPECIFIED;
399 if (tokenization.hasTokenizationType()) { 272 if (tokenization.hasTokenizationType()) {
400 for (size_t j = 0; j < arraysize(kAndroidPayTokenization); ++j) { 273 for (size_t i = 0; i < arraysize(kAndroidPayTokenization); ++i) {
401 if (tokenization.tokenizationType() == 274 if (tokenization.tokenizationType() ==
402 kAndroidPayTokenization[j].name) { 275 kAndroidPayTokenization[i].name) {
403 output->tokenization_type = kAndroidPayTokenization[j].code; 276 output->tokenization_type = kAndroidPayTokenization[i].code;
404 break; 277 break;
405 } 278 }
406 } 279 }
407 } 280 }
408 281
409 if (tokenization.hasParameters()) { 282 if (tokenization.hasParameters()) {
410 const Vector<String>& keys = 283 const Vector<String>& keys =
411 tokenization.parameters().getPropertyNames(exceptionState); 284 tokenization.parameters().getPropertyNames(exceptionState);
412 if (exceptionState.hadException()) 285 if (exceptionState.hadException())
413 return; 286 return;
414 output->parameters.resize(keys.size());
415 size_t numberOfParameters = 0;
416 String value; 287 String value;
417 for (size_t i = 0; i < keys.size(); ++i) { 288 for (const String& key : keys) {
418 if (!DictionaryHelper::get(tokenization.parameters(), keys[i], value)) 289 if (!DictionaryHelper::get(tokenization.parameters(), key, value))
419 continue; 290 continue;
420 output->parameters[numberOfParameters] = 291 output->parameters.append(
421 payments::mojom::blink::AndroidPayTokenizationParameter::New(); 292 payments::mojom::blink::AndroidPayTokenizationParameter::New());
422 output->parameters[numberOfParameters]->key = keys[i]; 293 output->parameters.back()->key = key;
423 output->parameters[numberOfParameters]->value = value; 294 output->parameters.back()->value = value;
424 ++numberOfParameters;
425 } 295 }
426 output->parameters.resize(numberOfParameters);
427 } 296 }
428 } 297 }
429 } 298 }
430 299
300 void stringifyAndParseMethodSpecificData(const ScriptValue& input,
301 PaymentMethodDataPtr& output,
302 ExceptionState& exceptionState) {
303 DCHECK(!input.isEmpty());
304 if (!input.v8Value()->IsObject() || input.v8Value()->IsArray()) {
305 exceptionState.throwTypeError("Data should be a JSON-serializable object");
306 return;
307 }
308
309 v8::Local<v8::String> value;
310 if (!v8::JSON::Stringify(input.context(), input.v8Value().As<v8::Object>())
311 .ToLocal(&value)) {
312 exceptionState.throwTypeError(
313 "Unable to parse payment method specific data");
314 return;
315 }
316
317 output->stringified_data =
318 v8StringToWebCoreString<String>(value, DoNotExternalize);
319 maybeSetAndroidPayMethodData(input, output, exceptionState);
320 }
321
322 void validateAndConvertPaymentDetailsModifiers(
323 const HeapVector<PaymentDetailsModifier>& input,
324 Vector<PaymentDetailsModifierPtr>& output,
325 ExceptionState& exceptionState) {
326 if (input.isEmpty()) {
327 exceptionState.throwTypeError(
328 "Must specify at least one payment details modifier");
329 return;
330 }
331
332 for (const PaymentDetailsModifier& modifier : input) {
333 output.append(payments::mojom::blink::PaymentDetailsModifier::New());
334 if (modifier.hasTotal()) {
335 validateAndConvertTotal(modifier.total(), output.back()->total,
336 exceptionState);
337 if (exceptionState.hadException())
338 return;
339 }
340
341 if (modifier.hasAdditionalDisplayItems()) {
342 validateAndConvertDisplayItems(modifier.additionalDisplayItems(),
343 output.back()->additional_display_items,
344 exceptionState);
345 if (exceptionState.hadException())
346 return;
347 }
348
349 if (modifier.supportedMethods().isEmpty()) {
350 exceptionState.throwTypeError(
351 "Must specify at least one payment method identifier");
352 return;
353 }
354
355 output.back()->method_data =
356 payments::mojom::blink::PaymentMethodData::New();
357 output.back()->method_data->supported_methods = modifier.supportedMethods();
358
359 if (modifier.hasData() && !modifier.data().isEmpty()) {
360 stringifyAndParseMethodSpecificData(
361 modifier.data(), output.back()->method_data, exceptionState);
362 } else {
363 output.back()->method_data->stringified_data = "";
364 }
365 }
366 }
367
368 String getSelectedShippingOption(
369 const Vector<PaymentShippingOptionPtr>& shippingOptions) {
370 String result;
371 for (const PaymentShippingOptionPtr& shippingOption : shippingOptions) {
372 if (shippingOption->selected)
373 result = shippingOption->id;
374 }
375 return result;
376 }
377
378 void validateAndConvertPaymentDetails(const PaymentDetails& input,
379 bool requestShipping,
380 PaymentDetailsPtr& output,
381 String& shippingOptionOutput,
382 ExceptionState& exceptionState) {
383 if (!input.hasTotal()) {
384 exceptionState.throwTypeError("Must specify total");
385 return;
386 }
387
388 validateAndConvertTotal(input.total(), output->total, exceptionState);
389 if (exceptionState.hadException())
390 return;
391
392 if (input.hasDisplayItems()) {
393 validateAndConvertDisplayItems(input.displayItems(), output->display_items,
394 exceptionState);
395 if (exceptionState.hadException())
396 return;
397 }
398
399 if (input.hasShippingOptions() && requestShipping) {
400 validateAndConvertShippingOptions(input.shippingOptions(),
401 output->shipping_options, exceptionState);
402 if (exceptionState.hadException())
403 return;
404 }
405
406 shippingOptionOutput = getSelectedShippingOption(output->shipping_options);
407
408 if (input.hasModifiers()) {
409 validateAndConvertPaymentDetailsModifiers(
410 input.modifiers(), output->modifiers, exceptionState);
411 if (exceptionState.hadException())
412 return;
413 }
414
415 if (input.hasError() && !input.error().isNull()) {
416 String errorMessage;
417 if (!PaymentsValidators::isValidErrorMsgFormat(input.error(),
418 &errorMessage)) {
419 exceptionState.throwTypeError(errorMessage);
420 return;
421 }
422 output->error = input.error();
423 } else {
424 output->error = "";
425 }
426 }
427
431 void validateAndConvertPaymentMethodData( 428 void validateAndConvertPaymentMethodData(
432 const HeapVector<PaymentMethodData>& input, 429 const HeapVector<PaymentMethodData>& input,
433 Vector<payments::mojom::blink::PaymentMethodDataPtr>& output, 430 Vector<payments::mojom::blink::PaymentMethodDataPtr>& output,
434 ExceptionState& exceptionState) { 431 ExceptionState& exceptionState) {
435 if (input.isEmpty()) { 432 if (input.isEmpty()) {
436 exceptionState.throwTypeError( 433 exceptionState.throwTypeError(
437 "Must specify at least one payment method identifier"); 434 "Must specify at least one payment method identifier");
438 return; 435 return;
439 } 436 }
440 437
441 output.resize(input.size()); 438 for (const PaymentMethodData paymentMethodData : input) {
442 for (size_t i = 0; i < input.size(); ++i) {
443 const auto& paymentMethodData = input[i];
444 if (paymentMethodData.supportedMethods().isEmpty()) { 439 if (paymentMethodData.supportedMethods().isEmpty()) {
445 exceptionState.throwTypeError( 440 exceptionState.throwTypeError(
446 "Must specify at least one payment method identifier"); 441 "Must specify at least one payment method identifier");
447 return; 442 return;
448 } 443 }
449 444
450 String stringifiedData = ""; 445 output.append(payments::mojom::blink::PaymentMethodData::New());
446 output.back()->supported_methods = paymentMethodData.supportedMethods();
447
451 if (paymentMethodData.hasData() && !paymentMethodData.data().isEmpty()) { 448 if (paymentMethodData.hasData() && !paymentMethodData.data().isEmpty()) {
452 if (!paymentMethodData.data().v8Value()->IsObject() || 449 stringifyAndParseMethodSpecificData(paymentMethodData.data(),
453 paymentMethodData.data().v8Value()->IsArray()) { 450 output.back(), exceptionState);
454 exceptionState.throwTypeError( 451 } else {
455 "Data should be a JSON-serializable object"); 452 output.back()->stringified_data = "";
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();
473 output[i]->supported_methods = paymentMethodData.supportedMethods();
474 output[i]->stringified_data = stringifiedData;
475 maybeSetAndroidPayMethodData(paymentMethodData.data(), output[i],
476 exceptionState);
477 if (exceptionState.hadException())
478 return;
479 }
480 }
481
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 } 453 }
492 } 454 }
493
494 return result;
495 } 455 }
496 456
497 String getValidShippingType(const String& shippingType) { 457 String getValidShippingType(const String& shippingType) {
498 static const char* const validValues[] = { 458 static const char* const validValues[] = {
499 "shipping", "delivery", "pickup", 459 "shipping", "delivery", "pickup",
500 }; 460 };
501 for (size_t i = 0; i < WTF_ARRAY_LENGTH(validValues); i++) { 461 for (size_t i = 0; i < arraysize(validValues); i++) {
502 if (shippingType == validValues[i]) 462 if (shippingType == validValues[i])
503 return shippingType; 463 return shippingType;
504 } 464 }
505 return validValues[0]; 465 return validValues[0];
506 } 466 }
507 467
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) { 468 bool allowedToUsePaymentRequest(const Frame* frame) {
517 // To determine whether a Document object |document| is allowed to use the 469 // To determine whether a Document object |document| is allowed to use the
518 // feature indicated by attribute name |allowpaymentrequest|, run these steps: 470 // feature indicated by attribute name |allowpaymentrequest|, run these steps:
519 471
520 // 1. If |document| has no browsing context, then return false. 472 // 1. If |document| has no browsing context, then return false.
521 if (!frame) 473 if (!frame)
522 return false; 474 return false;
523 475
524 // 2. If |document|'s browsing context is a top-level browsing context, then 476 // 2. If |document|'s browsing context is a top-level browsing context, then
525 // return true. 477 // return true.
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after
665 V8PaymentDetails::toImpl(detailsScriptValue.isolate(), 617 V8PaymentDetails::toImpl(detailsScriptValue.isolate(),
666 detailsScriptValue.v8Value(), details, 618 detailsScriptValue.v8Value(), details,
667 exceptionState); 619 exceptionState);
668 if (exceptionState.hadException()) { 620 if (exceptionState.hadException()) {
669 m_showResolver->reject( 621 m_showResolver->reject(
670 DOMException::create(SyntaxError, exceptionState.message())); 622 DOMException::create(SyntaxError, exceptionState.message()));
671 clearResolversAndCloseMojoConnection(); 623 clearResolversAndCloseMojoConnection();
672 return; 624 return;
673 } 625 }
674 626
675 bool keepShippingOptions = validatePaymentDetails(details, exceptionState); 627 PaymentDetailsPtr validatedDetails =
628 payments::mojom::blink::PaymentDetails::New();
629 validateAndConvertPaymentDetails(details, m_options.requestShipping(),
630 validatedDetails, m_shippingOption,
631 exceptionState);
676 if (exceptionState.hadException()) { 632 if (exceptionState.hadException()) {
677 m_showResolver->reject( 633 m_showResolver->reject(
678 DOMException::create(SyntaxError, exceptionState.message())); 634 DOMException::create(SyntaxError, exceptionState.message()));
679 clearResolversAndCloseMojoConnection(); 635 clearResolversAndCloseMojoConnection();
680 return; 636 return;
681 } 637 }
682 638
683 if (m_options.requestShipping()) { 639 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 } 640 }
694 641
695 void PaymentRequest::onUpdatePaymentDetailsFailure(const String& error) { 642 void PaymentRequest::onUpdatePaymentDetailsFailure(const String& error) {
696 if (m_showResolver) 643 if (m_showResolver)
697 m_showResolver->reject(DOMException::create(AbortError, error)); 644 m_showResolver->reject(DOMException::create(AbortError, error));
698 if (m_completeResolver) 645 if (m_completeResolver)
699 m_completeResolver->reject(DOMException::create(AbortError, error)); 646 m_completeResolver->reject(DOMException::create(AbortError, error));
700 clearResolversAndCloseMojoConnection(); 647 clearResolversAndCloseMojoConnection();
701 } 648 }
702 649
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
739 686
740 if (!allowedToUsePaymentRequest(scriptState->domWindow()->frame())) { 687 if (!allowedToUsePaymentRequest(scriptState->domWindow()->frame())) {
741 exceptionState.throwSecurityError( 688 exceptionState.throwSecurityError(
742 RuntimeEnabledFeatures::paymentRequestIFrameEnabled() 689 RuntimeEnabledFeatures::paymentRequestIFrameEnabled()
743 ? "Must be in a top-level browsing context or an iframe needs to " 690 ? "Must be in a top-level browsing context or an iframe needs to "
744 "specify 'allowpaymentrequest' explicitly" 691 "specify 'allowpaymentrequest' explicitly"
745 : "Must be in a top-level browsing context"); 692 : "Must be in a top-level browsing context");
746 return; 693 return;
747 } 694 }
748 695
749 bool keepShippingOptions = validatePaymentDetails(details, exceptionState); 696 PaymentDetailsPtr validatedDetails =
697 payments::mojom::blink::PaymentDetails::New();
698 validateAndConvertPaymentDetails(details, m_options.requestShipping(),
699 validatedDetails, m_shippingOption,
700 exceptionState);
750 if (exceptionState.hadException()) 701 if (exceptionState.hadException())
751 return; 702 return;
752 703
753 if (details.hasError()) { 704 if (details.hasError()) {
754 exceptionState.throwTypeError("Error message not allowed in constructor"); 705 exceptionState.throwTypeError("Error message not allowed in constructor");
755 return; 706 return;
756 } 707 }
757 708
758 if (m_options.requestShipping()) { 709 if (m_options.requestShipping())
759 if (keepShippingOptions)
760 m_shippingOption = getSelectedShippingOption(details);
761 m_shippingType = getValidShippingType(m_options.shippingType()); 710 m_shippingType = getValidShippingType(m_options.shippingType());
762 }
763 711
764 scriptState->domWindow()->frame()->interfaceProvider()->getInterface( 712 scriptState->domWindow()->frame()->interfaceProvider()->getInterface(
765 mojo::GetProxy(&m_paymentProvider)); 713 mojo::GetProxy(&m_paymentProvider));
766 m_paymentProvider.set_connection_error_handler(convertToBaseCallback( 714 m_paymentProvider.set_connection_error_handler(convertToBaseCallback(
767 WTF::bind(&PaymentRequest::OnError, wrapWeakPersistent(this), 715 WTF::bind(&PaymentRequest::OnError, wrapWeakPersistent(this),
768 PaymentErrorReason::UNKNOWN))); 716 PaymentErrorReason::UNKNOWN)));
769 m_paymentProvider->Init( 717 m_paymentProvider->Init(
770 m_clientBinding.CreateInterfacePtrAndBind(), 718 m_clientBinding.CreateInterfacePtrAndBind(),
771 std::move(validatedMethodData), 719 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)); 720 payments::mojom::blink::PaymentOptions::From(m_options));
776 } 721 }
777 722
778 void PaymentRequest::contextDestroyed() { 723 void PaymentRequest::contextDestroyed() {
779 clearResolversAndCloseMojoConnection(); 724 clearResolversAndCloseMojoConnection();
780 } 725 }
781 726
782 void PaymentRequest::OnShippingAddressChange(PaymentAddressPtr address) { 727 void PaymentRequest::OnShippingAddressChange(PaymentAddressPtr address) {
783 DCHECK(m_showResolver); 728 DCHECK(m_showResolver);
784 DCHECK(!m_completeResolver); 729 DCHECK(!m_completeResolver);
(...skipping 21 matching lines...) Expand all
806 m_shippingOption = shippingOptionId; 751 m_shippingOption = shippingOptionId;
807 PaymentRequestUpdateEvent* event = 752 PaymentRequestUpdateEvent* event =
808 PaymentRequestUpdateEvent::create(EventTypeNames::shippingoptionchange); 753 PaymentRequestUpdateEvent::create(EventTypeNames::shippingoptionchange);
809 event->setTarget(this); 754 event->setTarget(this);
810 event->setPaymentDetailsUpdater(this); 755 event->setPaymentDetailsUpdater(this);
811 bool success = getExecutionContext()->getEventQueue()->enqueueEvent(event); 756 bool success = getExecutionContext()->getEventQueue()->enqueueEvent(event);
812 DCHECK(success); 757 DCHECK(success);
813 ALLOW_UNUSED_LOCAL(success); 758 ALLOW_UNUSED_LOCAL(success);
814 } 759 }
815 760
816 void PaymentRequest::OnPaymentResponse( 761 void PaymentRequest::OnPaymentResponse(PaymentResponsePtr response) {
817 payments::mojom::blink::PaymentResponsePtr response) {
818 DCHECK(m_showResolver); 762 DCHECK(m_showResolver);
819 DCHECK(!m_completeResolver); 763 DCHECK(!m_completeResolver);
820 DCHECK(!m_completeTimer.isActive()); 764 DCHECK(!m_completeTimer.isActive());
821 765
822 if (m_options.requestShipping()) { 766 if (m_options.requestShipping()) {
823 if (!response->shipping_address || response->shipping_option.isEmpty()) { 767 if (!response->shipping_address || response->shipping_option.isEmpty()) {
824 m_showResolver->reject(DOMException::create(SyntaxError)); 768 m_showResolver->reject(DOMException::create(SyntaxError));
825 clearResolversAndCloseMojoConnection(); 769 clearResolversAndCloseMojoConnection();
826 return; 770 return;
827 } 771 }
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after
972 m_completeResolver.clear(); 916 m_completeResolver.clear();
973 m_showResolver.clear(); 917 m_showResolver.clear();
974 m_abortResolver.clear(); 918 m_abortResolver.clear();
975 m_canMakeActivePaymentResolver.clear(); 919 m_canMakeActivePaymentResolver.clear();
976 if (m_clientBinding.is_bound()) 920 if (m_clientBinding.is_bound())
977 m_clientBinding.Close(); 921 m_clientBinding.Close();
978 m_paymentProvider.reset(); 922 m_paymentProvider.reset();
979 } 923 }
980 924
981 } // namespace blink 925 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698