Chromium Code Reviews| 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() && value->getType() != JSONValue::TypeObject) { | |
|
please use gerrit instead
2016/06/03 18:22:28
If value->isNull(), then you should not stringify
zino
2016/06/04 00:48:46
Done.
| |
| 214 exceptionState.throwTypeError("Data should be a JSON-serializabl e object"); | |
| 215 return; | |
| 216 } | |
| 217 stringifiedData = JSONObject::cast(value)->toJSONString(); | |
| 218 } | |
| 219 methodData->append(PaymentRequest::MethodData(pmd.supportedMethods(), st ringifiedData)); | |
| 220 } | |
| 221 } | |
| 222 | |
| 177 } // namespace | 223 } // namespace |
| 178 | 224 |
| 179 PaymentRequest* PaymentRequest::create(ScriptState* scriptState, const Vector<St ring>& supportedMethods, const PaymentDetails& details, ExceptionState& exceptio nState) | 225 PaymentRequest* PaymentRequest::create(ScriptState* scriptState, const HeapVecto r<PaymentMethodData>& methodData, const PaymentDetails& details, ExceptionState& exceptionState) |
| 180 { | 226 { |
| 181 return new PaymentRequest(scriptState, supportedMethods, details, PaymentOpt ions(), ScriptValue(), exceptionState); | 227 return new PaymentRequest(scriptState, methodData, details, PaymentOptions() , exceptionState); |
| 182 } | 228 } |
| 183 | 229 |
| 184 PaymentRequest* PaymentRequest::create(ScriptState* scriptState, const Vector<St ring>& supportedMethods, const PaymentDetails& details, const PaymentOptions& op tions, ExceptionState& exceptionState) | 230 PaymentRequest* PaymentRequest::create(ScriptState* scriptState, const HeapVecto r<PaymentMethodData>& methodData, const PaymentDetails& details, const PaymentOp tions& options, ExceptionState& exceptionState) |
| 185 { | 231 { |
| 186 return new PaymentRequest(scriptState, supportedMethods, details, options, S criptValue(), exceptionState); | 232 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 } | 233 } |
| 193 | 234 |
| 194 PaymentRequest::~PaymentRequest() | 235 PaymentRequest::~PaymentRequest() |
| 195 { | 236 { |
| 196 } | 237 } |
| 197 | 238 |
| 198 ScriptPromise PaymentRequest::show(ScriptState* scriptState) | 239 ScriptPromise PaymentRequest::show(ScriptState* scriptState) |
| 199 { | 240 { |
| 200 if (m_showResolver) | 241 if (m_showResolver) |
| 201 return ScriptPromise::rejectWithDOMException(scriptState, DOMException:: create(InvalidStateError, "Already called show() once")); | 242 return ScriptPromise::rejectWithDOMException(scriptState, DOMException:: create(InvalidStateError, "Already called show() once")); |
| 202 | 243 |
| 203 if (!scriptState->domWindow() || !scriptState->domWindow()->frame()) | 244 if (!scriptState->domWindow() || !scriptState->domWindow()->frame()) |
| 204 return ScriptPromise::rejectWithDOMException(scriptState, DOMException:: create(InvalidStateError, "Cannot show the payment request")); | 245 return ScriptPromise::rejectWithDOMException(scriptState, DOMException:: create(InvalidStateError, "Cannot show the payment request")); |
| 205 | 246 |
| 206 DCHECK(!m_paymentProvider.is_bound()); | 247 DCHECK(!m_paymentProvider.is_bound()); |
| 207 scriptState->domWindow()->frame()->serviceRegistry()->connectToRemoteService (mojo::GetProxy(&m_paymentProvider)); | 248 scriptState->domWindow()->frame()->serviceRegistry()->connectToRemoteService (mojo::GetProxy(&m_paymentProvider)); |
| 208 m_paymentProvider.set_connection_error_handler(createBaseCallback(bind(&Paym entRequest::OnError, WeakPersistentThisPointer<PaymentRequest>(this)))); | 249 m_paymentProvider.set_connection_error_handler(createBaseCallback(bind(&Paym entRequest::OnError, WeakPersistentThisPointer<PaymentRequest>(this)))); |
| 209 m_paymentProvider->SetClient(m_clientBinding.CreateInterfacePtrAndBind()); | 250 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); | 251 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); | 252 m_showResolver = ScriptPromiseResolver::create(scriptState); |
| 213 return m_showResolver->promise(); | 253 return m_showResolver->promise(); |
| 214 } | 254 } |
| 215 | 255 |
| 216 void PaymentRequest::abort(ExceptionState& exceptionState) | 256 void PaymentRequest::abort(ExceptionState& exceptionState) |
| 217 { | 257 { |
| 218 if (!m_showResolver) { | 258 if (!m_showResolver) { |
| 219 exceptionState.throwDOMException(InvalidStateError, "Never called show() , so nothing to abort"); | 259 exceptionState.throwDOMException(InvalidStateError, "Never called show() , so nothing to abort"); |
| 220 return; | 260 return; |
| 221 } | 261 } |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 288 { | 328 { |
| 289 visitor->trace(m_details); | 329 visitor->trace(m_details); |
| 290 visitor->trace(m_options); | 330 visitor->trace(m_options); |
| 291 visitor->trace(m_shippingAddress); | 331 visitor->trace(m_shippingAddress); |
| 292 visitor->trace(m_showResolver); | 332 visitor->trace(m_showResolver); |
| 293 visitor->trace(m_completeResolver); | 333 visitor->trace(m_completeResolver); |
| 294 EventTargetWithInlineData::trace(visitor); | 334 EventTargetWithInlineData::trace(visitor); |
| 295 ContextLifecycleObserver::trace(visitor); | 335 ContextLifecycleObserver::trace(visitor); |
| 296 } | 336 } |
| 297 | 337 |
| 298 PaymentRequest::PaymentRequest(ScriptState* scriptState, const Vector<String>& s upportedMethods, const PaymentDetails& details, const PaymentOptions& options, c onst ScriptValue& data, ExceptionState& exceptionState) | 338 PaymentRequest::PaymentRequest(ScriptState* scriptState, const HeapVector<Paymen tMethodData>& methodData, const PaymentDetails& details, const PaymentOptions& o ptions, ExceptionState& exceptionState) |
| 299 : ContextLifecycleObserver(scriptState->getExecutionContext()) | 339 : ContextLifecycleObserver(scriptState->getExecutionContext()) |
| 300 , ActiveScriptWrappable(this) | 340 , ActiveScriptWrappable(this) |
| 301 , m_options(options) | 341 , m_options(options) |
| 302 , m_clientBinding(this) | 342 , m_clientBinding(this) |
| 303 { | 343 { |
| 344 validateAndConvertPaymentMethodData(methodData, &m_methodData, exceptionStat e); | |
| 345 if (exceptionState.hadException()) | |
| 346 return; | |
| 347 | |
| 304 if (!scriptState->getExecutionContext()->isSecureContext()) { | 348 if (!scriptState->getExecutionContext()->isSecureContext()) { |
| 305 exceptionState.throwSecurityError("Must be in a secure context"); | 349 exceptionState.throwSecurityError("Must be in a secure context"); |
| 306 return; | 350 return; |
| 307 } | 351 } |
| 308 | 352 |
| 309 if (!scriptState->domWindow()->frame() || !scriptState->domWindow()->frame() ->isMainFrame()) { | 353 if (!scriptState->domWindow()->frame() || !scriptState->domWindow()->frame() ->isMainFrame()) { |
| 310 exceptionState.throwSecurityError("Must be in a top-level browsing conte xt"); | 354 exceptionState.throwSecurityError("Must be in a top-level browsing conte xt"); |
| 311 return; | 355 return; |
| 312 } | 356 } |
| 313 | 357 |
| 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); | 358 validatePaymentDetails(details, exceptionState); |
| 321 if (exceptionState.hadException()) | 359 if (exceptionState.hadException()) |
| 322 return; | 360 return; |
| 323 m_details = details; | 361 m_details = details; |
| 324 | 362 |
| 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. | 363 // 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) | 364 if (options.requestShipping() && details.hasShippingOptions() && details.shi ppingOptions().size() == 1) |
| 355 m_shippingOption = details.shippingOptions().begin()->id(); | 365 m_shippingOption = details.shippingOptions().begin()->id(); |
| 356 } | 366 } |
| 357 | 367 |
| 358 void PaymentRequest::contextDestroyed() | 368 void PaymentRequest::contextDestroyed() |
| 359 { | 369 { |
| 360 clearResolversAndCloseMojoConnection(); | 370 clearResolversAndCloseMojoConnection(); |
| 361 } | 371 } |
| 362 | 372 |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 443 void PaymentRequest::clearResolversAndCloseMojoConnection() | 453 void PaymentRequest::clearResolversAndCloseMojoConnection() |
| 444 { | 454 { |
| 445 m_completeResolver.clear(); | 455 m_completeResolver.clear(); |
| 446 m_showResolver.clear(); | 456 m_showResolver.clear(); |
| 447 if (m_clientBinding.is_bound()) | 457 if (m_clientBinding.is_bound()) |
| 448 m_clientBinding.Close(); | 458 m_clientBinding.Close(); |
| 449 m_paymentProvider.reset(); | 459 m_paymentProvider.reset(); |
| 450 } | 460 } |
| 451 | 461 |
| 452 } // namespace blink | 462 } // namespace blink |
| OLD | NEW |