diff --git a/dom/bindings/Errors.msg b/dom/bindings/Errors.msg index 7f4f0d14ba7f..e1996da7315a 100644 --- a/dom/bindings/Errors.msg +++ b/dom/bindings/Errors.msg @@ -32,8 +32,6 @@ MSG_DEF(MSG_METHOD_THIS_DOES_NOT_IMPLEMENT_INTERFACE, 2, JSEXN_TYPEERR, "'{0}' c MSG_DEF(MSG_METHOD_THIS_UNWRAPPING_DENIED, 1, JSEXN_TYPEERR, "Permission to call '{0}' denied.") MSG_DEF(MSG_NOT_IN_UNION, 2, JSEXN_TYPEERR, "{0} could not be converted to any of: {1}.") MSG_DEF(MSG_ILLEGAL_CONSTRUCTOR, 0, JSEXN_TYPEERR, "Illegal constructor.") -MSG_DEF(MSG_ILLEGAL_TYPE_PR_CONSTRUCTOR, 1, JSEXN_TYPEERR, "TypeError:{0}") -MSG_DEF(MSG_ILLEGAL_RANGE_PR_CONSTRUCTOR, 1, JSEXN_RANGEERR, "RangeError:{0}") MSG_DEF(MSG_CONSTRUCTOR_WITHOUT_NEW, 1, JSEXN_TYPEERR, "Constructor {0} requires 'new'") MSG_DEF(MSG_ENFORCE_RANGE_NON_FINITE, 1, JSEXN_TYPEERR, "Non-finite value is out of range for {0}.") MSG_DEF(MSG_ENFORCE_RANGE_OUT_OF_RANGE, 1, JSEXN_TYPEERR, "Value is out of range for {0}.") diff --git a/dom/payments/BasicCardPayment.cpp b/dom/payments/BasicCardPayment.cpp index 2b4e12ab4385..6b2fa341fbca 100644 --- a/dom/payments/BasicCardPayment.cpp +++ b/dom/payments/BasicCardPayment.cpp @@ -111,14 +111,19 @@ bool BasicCardService::IsValidExpiryYear(const nsAString& aExpiryYear) { return true; } -bool BasicCardService::IsValidBasicCardErrors(JSContext* aCx, JSObject* aData) { - if (!aData) { - return true; - } +void BasicCardService::CheckForValidBasicCardErrors(JSContext* aCx, JSObject* aData, + ErrorResult& aRv) { + MOZ_ASSERT(aData, "Don't pass null data"); JS::RootedValue data(aCx, JS::ObjectValue(*aData)); + // XXXbz Just because aData converts to BasicCardErrors right now doesn't mean + // it will if someone tries again! Should we be replacing aData with a + // conversion of the BasicCardErrors dictionary to a JS object in a clean + // compartment or something? BasicCardErrors bcError; - return !bcError.Init(aCx, data); + if (!bcError.Init(aCx, data)) { + aRv.NoteJSContextException(aCx); + } } } // end of namespace dom } // end of namespace mozilla diff --git a/dom/payments/BasicCardPayment.h b/dom/payments/BasicCardPayment.h index 152ad6b48ce2..2899ec8172dd 100644 --- a/dom/payments/BasicCardPayment.h +++ b/dom/payments/BasicCardPayment.h @@ -24,7 +24,8 @@ class BasicCardService final { bool IsBasicCardPayment(const nsAString& aSupportedMethods); bool IsValidBasicCardRequest(JSContext* aCx, JSObject* aData, nsAString& aErrorMsg); - bool IsValidBasicCardErrors(JSContext* aCx, JSObject* aData); + void CheckForValidBasicCardErrors(JSContext* aCx, JSObject* aData, + ErrorResult& aRv); bool IsValidExpiryMonth(const nsAString& aExpiryMonth); bool IsValidExpiryYear(const nsAString& aExpiryYear); diff --git a/dom/payments/MerchantValidationEvent.cpp b/dom/payments/MerchantValidationEvent.cpp index 5299f0de0b2f..10b9e9507335 100644 --- a/dom/payments/MerchantValidationEvent.cpp +++ b/dom/payments/MerchantValidationEvent.cpp @@ -45,21 +45,8 @@ already_AddRefed MerchantValidationEvent::Constructor( RefPtr e = new MerchantValidationEvent(aOwner); bool trusted = e->Init(aOwner); e->InitEvent(aType, aEventInitDict.mBubbles, aEventInitDict.mCancelable); - nsString errMsg; - Result rv = e->init(aEventInitDict, errMsg); - if (rv.isErr()) { - auto err = rv.unwrapErr(); - switch (err) { - case NS_ERROR_TYPE_ERR: - aRv.ThrowRangeError(errMsg); - break; - case NS_ERROR_MALFORMED_URI: - aRv.ThrowTypeError(aEventInitDict.mValidationURL); - break; - default: - aRv.Throw(err); - break; - } + e->init(aEventInitDict, aRv); + if (aRv.Failed()) { return nullptr; } e->SetTrusted(trusted); @@ -67,26 +54,31 @@ already_AddRefed MerchantValidationEvent::Constructor( return e.forget(); } -Result MerchantValidationEvent::init( - const MerchantValidationEventInit& aEventInitDict, nsString& errMsg) { +void MerchantValidationEvent::init( + const MerchantValidationEventInit& aEventInitDict, ErrorResult& aRv) { // Check methodName is valid if (!aEventInitDict.mMethodName.IsEmpty()) { - nsresult rv = PaymentRequest::IsValidPaymentMethodIdentifier( - aEventInitDict.mMethodName, errMsg); - if (NS_FAILED(rv)) { - return Err(rv); + PaymentRequest::IsValidPaymentMethodIdentifier(aEventInitDict.mMethodName, + aRv); + if (aRv.Failed()) { + return; } } SetMethodName(aEventInitDict.mMethodName); nsCOMPtr window = do_QueryInterface(GetParentObject()); auto doc = window->GetExtantDoc(); if (!doc) { - return Err(NS_ERROR_UNEXPECTED); + aRv.Throw(NS_ERROR_UNEXPECTED); + return; } - MOZ_TRY_VAR(mValidationURL, - doc->ResolveWithBaseURI(aEventInitDict.mValidationURL)); - return Ok(); + Result, nsresult> rv = + doc->ResolveWithBaseURI(aEventInitDict.mValidationURL); + if (rv.isErr()) { + aRv.Throw(rv.unwrapErr()); + return; + } + mValidationURL = rv.unwrap(); } MerchantValidationEvent::MerchantValidationEvent(EventTarget* aOwner) diff --git a/dom/payments/MerchantValidationEvent.h b/dom/payments/MerchantValidationEvent.h index 5d1468bd6ffe..1c36ce7b4bc0 100644 --- a/dom/payments/MerchantValidationEvent.h +++ b/dom/payments/MerchantValidationEvent.h @@ -55,8 +55,8 @@ class MerchantValidationEvent : public Event, public PromiseNativeHandler { void SetMethodName(const nsAString& aMethodName); protected: - Result init(const MerchantValidationEventInit& aEventInitDict, - nsString& errMsg); + void init(const MerchantValidationEventInit& aEventInitDict, + ErrorResult& aRv); ~MerchantValidationEvent(); private: diff --git a/dom/payments/PaymentRequest.cpp b/dom/payments/PaymentRequest.cpp index c729438ae0c6..e45942c76780 100644 --- a/dom/payments/PaymentRequest.cpp +++ b/dom/payments/PaymentRequest.cpp @@ -93,8 +93,8 @@ bool PaymentRequest::PrefEnabled(JSContext* aCx, JSObject* aObj) { #endif } -nsresult PaymentRequest::IsValidStandardizedPMI(const nsAString& aIdentifier, - nsAString& aErrorMsg) { +void PaymentRequest::IsValidStandardizedPMI(const nsAString& aIdentifier, + ErrorResult& aRv) { /* * The syntax of a standardized payment method identifier is given by the * following [ABNF]: @@ -103,19 +103,20 @@ nsresult PaymentRequest::IsValidStandardizedPMI(const nsAString& aIdentifier, * part = 1loweralpha *( DIGIT / loweralpha ) * loweralpha = %x61-7A */ - nsString::const_iterator start, end; - aIdentifier.BeginReading(start); - aIdentifier.EndReading(end); + const char16_t* start = aIdentifier.BeginReading(); + const char16_t* end = aIdentifier.EndReading(); while (start != end) { // the first char must be in the range %x61-7A if ((*start < 'a' || *start > 'z')) { - aErrorMsg.AssignLiteral("'"); - aErrorMsg.Append(aIdentifier); - aErrorMsg.AppendLiteral("' is not valid. The character '"); - aErrorMsg.Append(*start); - aErrorMsg.AppendLiteral( + nsAutoString error; + error.AssignLiteral("'"); + error.Append(aIdentifier); + error.AppendLiteral("' is not valid. The character '"); + error.Append(*start); + error.AppendLiteral( "' at the beginning or after the '-' must be in the range [a-z]."); - return NS_ERROR_RANGE_ERR; + aRv.ThrowRangeError(error); + return; } ++start; // the rest can be in the range %x61-7A + DIGITs @@ -126,34 +127,37 @@ nsresult PaymentRequest::IsValidStandardizedPMI(const nsAString& aIdentifier, } // if the char is not in the range %x61-7A + DIGITs, it must be '-' if (start != end && *start != '-') { - aErrorMsg.AssignLiteral("'"); - aErrorMsg.Append(aIdentifier); - aErrorMsg.AppendLiteral("' is not valid. The character '"); - aErrorMsg.Append(*start); - aErrorMsg.AppendLiteral("' must be in the range [a-zA-z0-9-]."); - return NS_ERROR_RANGE_ERR; + nsAutoString error; + error.AssignLiteral("'"); + error.Append(aIdentifier); + error.AppendLiteral("' is not valid. The character '"); + error.Append(*start); + error.AppendLiteral("' must be in the range [a-zA-z0-9-]."); + aRv.ThrowRangeError(error); + return; } if (*start == '-') { ++start; // the last char can not be '-' if (start == end) { - aErrorMsg.AssignLiteral("'"); - aErrorMsg.Append(aIdentifier); - aErrorMsg.AppendLiteral("' is not valid. The last character '"); - aErrorMsg.Append(*start); - aErrorMsg.AppendLiteral("' must be in the range [a-z0-9]."); - return NS_ERROR_RANGE_ERR; + nsAutoString error; + error.AssignLiteral("'"); + error.Append(aIdentifier); + error.AppendLiteral("' is not valid. The last character '"); + error.Append(*start); + error.AppendLiteral("' must be in the range [a-z0-9]."); + aRv.ThrowRangeError(error); + return; } } } - return NS_OK; } -nsresult PaymentRequest::IsValidPaymentMethodIdentifier( - const nsAString& aIdentifier, nsAString& aErrorMsg) { +void PaymentRequest::IsValidPaymentMethodIdentifier( + const nsAString& aIdentifier, ErrorResult& aRv) { if (aIdentifier.IsEmpty()) { - aErrorMsg.AssignLiteral("Payment method identifier is required."); - return NS_ERROR_TYPE_ERR; + aRv.ThrowTypeError(u"Payment method identifier is required."); + return; } /* * URL-based payment method identifier @@ -172,22 +176,35 @@ nsresult PaymentRequest::IsValidPaymentMethodIdentifier( nsresult rv = urlParser->ParseURL(url.get(), url.Length(), &schemePos, &schemeLen, &authorityPos, &authorityLen, nullptr, nullptr); - NS_ENSURE_SUCCESS(rv, NS_ERROR_RANGE_ERR); + if (NS_FAILED(rv)) { + nsAutoString error; + error.AppendLiteral("Error parsing payment method identifier '"); + error.Append(aIdentifier); + error.AppendLiteral("'as a URL."); + aRv.ThrowRangeError(error); + return; + } + if (schemeLen == -1) { // The PMI is not a URL-based PMI, check if it is a standardized PMI - return IsValidStandardizedPMI(aIdentifier, aErrorMsg); + IsValidStandardizedPMI(aIdentifier, aRv); + return; } if (!Substring(aIdentifier, schemePos, schemeLen).EqualsASCII("https")) { - aErrorMsg.AssignLiteral("'"); - aErrorMsg.Append(aIdentifier); - aErrorMsg.AppendLiteral("' is not valid. The scheme must be 'https'."); - return NS_ERROR_RANGE_ERR; + nsAutoString error; + error.AssignLiteral("'"); + error.Append(aIdentifier); + error.AppendLiteral("' is not valid. The scheme must be 'https'."); + aRv.ThrowRangeError(error); + return; } if (Substring(aIdentifier, authorityPos, authorityLen).IsEmpty()) { - aErrorMsg.AssignLiteral("'"); - aErrorMsg.Append(aIdentifier); - aErrorMsg.AppendLiteral("' is not valid. hostname can not be empty."); - return NS_ERROR_RANGE_ERR; + nsAutoString error; + error.AssignLiteral("'"); + error.Append(aIdentifier); + error.AppendLiteral("' is not valid. hostname can not be empty."); + aRv.ThrowRangeError(error); + return; } uint32_t usernamePos = 0; @@ -234,10 +251,12 @@ nsresult PaymentRequest::IsValidPaymentMethodIdentifier( // not exist. if ((usernameLen <= 0) && (passwordLen <= 0)) { if (authority.Length() - atPos - 1 == 0) { - aErrorMsg.AssignLiteral("'"); - aErrorMsg.Append(aIdentifier); - aErrorMsg.AppendLiteral("' is not valid. hostname can not be empty."); - return NS_ERROR_RANGE_ERR; + nsAutoString error; + error.AssignLiteral("'"); + error.Append(aIdentifier); + error.AppendLiteral("' is not valid. hostname can not be empty."); + aRv.ThrowRangeError(error); + return; } // Re-using nsIURLParser::ParseServerInfo to extract the hostname and port // information. This can help us to handle complicated IPv6 cases. @@ -248,42 +267,48 @@ nsresult PaymentRequest::IsValidPaymentMethodIdentifier( if (NS_FAILED(rv)) { // ParseServerInfo returns NS_ERROR_MALFORMED_URI in all fail cases, we // probably need a followup bug to figure out the fail reason. - return NS_ERROR_RANGE_ERR; + nsAutoString error; + error.AssignLiteral("Error extracting hostname from '"); + error.Append(NS_ConvertUTF8toUTF16(serverInfo)); + error.AppendLiteral("'."); + aRv.ThrowRangeError(error); + return; } } } // PMI is valid when usernameLen/passwordLen equals to -1 or 0. if (usernameLen > 0 || passwordLen > 0) { - aErrorMsg.AssignLiteral("'"); - aErrorMsg.Append(aIdentifier); - aErrorMsg.AssignLiteral( - "' is not valid. Username and password must be empty."); - return NS_ERROR_RANGE_ERR; + nsAutoString error; + error.AssignLiteral("'"); + error.Append(aIdentifier); + error.AssignLiteral("' is not valid. Username and password must be empty."); + aRv.ThrowRangeError(error); + return; } // PMI is valid when hostnameLen is larger than 0 if (hostnameLen <= 0) { - aErrorMsg.AssignLiteral("'"); - aErrorMsg.Append(aIdentifier); - aErrorMsg.AppendLiteral("' is not valid. hostname can not be empty."); - return NS_ERROR_RANGE_ERR; + nsAutoString error; + error.AssignLiteral("'"); + error.Append(aIdentifier); + error.AppendLiteral("' is not valid. hostname can not be empty."); + aRv.ThrowRangeError(error); + return; } - return NS_OK; } -nsresult PaymentRequest::IsValidMethodData( +void PaymentRequest::IsValidMethodData( JSContext* aCx, const Sequence& aMethodData, - nsAString& aErrorMsg) { + ErrorResult& aRv) { if (!aMethodData.Length()) { - aErrorMsg.AssignLiteral("At least one payment method is required."); - return NS_ERROR_TYPE_ERR; + aRv.ThrowTypeError(u"At least one payment method is required."); + return; } for (const PaymentMethodData& methodData : aMethodData) { - nsresult rv = - IsValidPaymentMethodIdentifier(methodData.mSupportedMethods, aErrorMsg); - if (NS_FAILED(rv)) { - return rv; + IsValidPaymentMethodIdentifier(methodData.mSupportedMethods, aRv); + if (aRv.Failed()) { + return; } RefPtr service = BasicCardService::GetService(); @@ -293,19 +318,18 @@ nsresult PaymentRequest::IsValidMethodData( continue; } MOZ_ASSERT(aCx); + nsAutoString error; if (!service->IsValidBasicCardRequest(aCx, methodData.mData.Value(), - aErrorMsg)) { - return NS_ERROR_TYPE_ERR; + error)) { + aRv.ThrowTypeError(error); + return; } } } - - return NS_OK; } -nsresult PaymentRequest::IsValidNumber(const nsAString& aItem, - const nsAString& aStr, - nsAString& aErrorMsg) { +void PaymentRequest::IsValidNumber(const nsAString& aItem, + const nsAString& aStr, ErrorResult& aRv) { nsresult error = NS_ERROR_FAILURE; if (!aStr.IsEmpty()) { @@ -329,19 +353,20 @@ nsresult PaymentRequest::IsValidNumber(const nsAString& aItem, } if (NS_FAILED(error)) { - aErrorMsg.AssignLiteral("The amount.value of \""); - aErrorMsg.Append(aItem); - aErrorMsg.AppendLiteral("\"("); - aErrorMsg.Append(aStr); - aErrorMsg.AppendLiteral(") must be a valid decimal monetary value."); - return NS_ERROR_TYPE_ERR; + nsAutoString errorMsg; + errorMsg.AssignLiteral("The amount.value of \""); + errorMsg.Append(aItem); + errorMsg.AppendLiteral("\"("); + errorMsg.Append(aStr); + errorMsg.AppendLiteral(") must be a valid decimal monetary value."); + aRv.ThrowTypeError(errorMsg); + return; } - return NS_OK; } -nsresult PaymentRequest::IsNonNegativeNumber(const nsAString& aItem, - const nsAString& aStr, - nsAString& aErrorMsg) { +void PaymentRequest::IsNonNegativeNumber(const nsAString& aItem, + const nsAString& aStr, + ErrorResult& aRv) { nsresult error = NS_ERROR_FAILURE; if (!aStr.IsEmpty()) { @@ -356,20 +381,21 @@ nsresult PaymentRequest::IsNonNegativeNumber(const nsAString& aItem, } if (NS_FAILED(error)) { - aErrorMsg.AssignLiteral("The amount.value of \""); - aErrorMsg.Append(aItem); - aErrorMsg.AppendLiteral("\"("); - aErrorMsg.Append(aStr); - aErrorMsg.AppendLiteral( + nsAutoString errorMsg; + errorMsg.AssignLiteral("The amount.value of \""); + errorMsg.Append(aItem); + errorMsg.AppendLiteral("\"("); + errorMsg.Append(aStr); + errorMsg.AppendLiteral( ") must be a valid and non-negative decimal monetary value."); - return NS_ERROR_TYPE_ERR; + aRv.ThrowTypeError(errorMsg); + return; } - return NS_OK; } -nsresult PaymentRequest::IsValidCurrency(const nsAString& aItem, - const nsAString& aCurrency, - nsAString& aErrorMsg) { +void PaymentRequest::IsValidCurrency(const nsAString& aItem, + const nsAString& aCurrency, + ErrorResult& aRv) { /* * According to spec in * https://w3c.github.io/payment-request/#validity-checkers, perform currency @@ -379,12 +405,14 @@ nsresult PaymentRequest::IsValidCurrency(const nsAString& aItem, * "Z" (U+0041 to U+005A) or the range "a" to "z" (U+0061 to U+007A) */ if (aCurrency.Length() != 3) { - aErrorMsg.AssignLiteral("The length amount.currency of \""); - aErrorMsg.Append(aItem); - aErrorMsg.AppendLiteral("\"("); - aErrorMsg.Append(aCurrency); - aErrorMsg.AppendLiteral(") must be 3."); - return NS_ERROR_RANGE_ERR; + nsAutoString error; + error.AssignLiteral("The length amount.currency of \""); + error.Append(aItem); + error.AppendLiteral("\"("); + error.Append(aCurrency); + error.AppendLiteral(") must be 3."); + aRv.ThrowRangeError(error); + return; } // Don't use nsUnicharUtils::ToUpperCase, it converts the invalid "ınr" PMI to // to the valid one "INR". @@ -393,83 +421,82 @@ nsresult PaymentRequest::IsValidCurrency(const nsAString& aItem, (aCurrency.CharAt(idx) >= 'a' && aCurrency.CharAt(idx) <= 'z')) { continue; } - aErrorMsg.AssignLiteral("The character amount.currency of \""); - aErrorMsg.Append(aItem); - aErrorMsg.AppendLiteral("\"("); - aErrorMsg.Append(aCurrency); - aErrorMsg.AppendLiteral( + nsAutoString error; + error.AssignLiteral("The character amount.currency of \""); + error.Append(aItem); + error.AppendLiteral("\"("); + error.Append(aCurrency); + error.AppendLiteral( ") must be in the range 'A' to 'Z'(U+0041 to U+005A) or 'a' to " "'z'(U+0061 to U+007A)."); - return NS_ERROR_RANGE_ERR; + aRv.ThrowRangeError(error); + return; } - return NS_OK; } -nsresult PaymentRequest::IsValidCurrencyAmount( - const nsAString& aItem, const PaymentCurrencyAmount& aAmount, - const bool aIsTotalItem, nsAString& aErrorMsg) { - nsresult rv; - rv = IsValidCurrency(aItem, aAmount.mCurrency, aErrorMsg); - if (NS_FAILED(rv)) { - return rv; +void PaymentRequest::IsValidCurrencyAmount(const nsAString& aItem, + const PaymentCurrencyAmount& aAmount, + const bool aIsTotalItem, + ErrorResult& aRv) { + IsValidCurrency(aItem, aAmount.mCurrency, aRv); + if (aRv.Failed()) { + return; } if (aIsTotalItem) { - rv = IsNonNegativeNumber(aItem, aAmount.mValue, aErrorMsg); - if (NS_FAILED(rv)) { - return rv; + IsNonNegativeNumber(aItem, aAmount.mValue, aRv); + if (aRv.Failed()) { + return; } } else { - rv = IsValidNumber(aItem, aAmount.mValue, aErrorMsg); - if (NS_FAILED(rv)) { - return rv; + IsValidNumber(aItem, aAmount.mValue, aRv); + if (aRv.Failed()) { + return; } } - return NS_OK; } -nsresult PaymentRequest::IsValidDetailsInit(const PaymentDetailsInit& aDetails, - const bool aRequestShipping, - nsAString& aErrorMsg) { +void PaymentRequest::IsValidDetailsInit(const PaymentDetailsInit& aDetails, + const bool aRequestShipping, + ErrorResult& aRv) { // Check the amount.value and amount.currency of detail.total - nsresult rv = IsValidCurrencyAmount(NS_LITERAL_STRING("details.total"), - aDetails.mTotal.mAmount, - true, // isTotalItem - aErrorMsg); - if (NS_FAILED(rv)) { - return rv; + IsValidCurrencyAmount(NS_LITERAL_STRING("details.total"), + aDetails.mTotal.mAmount, + true, // isTotalItem + aRv); + if (aRv.Failed()) { + return; } - return IsValidDetailsBase(aDetails, aRequestShipping, aErrorMsg); + return IsValidDetailsBase(aDetails, aRequestShipping, aRv); } -nsresult PaymentRequest::IsValidDetailsUpdate( - const PaymentDetailsUpdate& aDetails, const bool aRequestShipping) { - nsAutoString message; +void PaymentRequest::IsValidDetailsUpdate(const PaymentDetailsUpdate& aDetails, + const bool aRequestShipping, + ErrorResult& aRv) { // Check the amount.value and amount.currency of detail.total if (aDetails.mTotal.WasPassed()) { - nsresult rv = IsValidCurrencyAmount(NS_LITERAL_STRING("details.total"), - aDetails.mTotal.Value().mAmount, - true, // isTotalItem - message); - if (NS_FAILED(rv)) { - return rv; + IsValidCurrencyAmount(NS_LITERAL_STRING("details.total"), + aDetails.mTotal.Value().mAmount, + true, // isTotalItem + aRv); + if (aRv.Failed()) { + return; } } - return IsValidDetailsBase(aDetails, aRequestShipping, message); + IsValidDetailsBase(aDetails, aRequestShipping, aRv); } -nsresult PaymentRequest::IsValidDetailsBase(const PaymentDetailsBase& aDetails, - const bool aRequestShipping, - nsAString& aErrorMsg) { - nsresult rv; +void PaymentRequest::IsValidDetailsBase(const PaymentDetailsBase& aDetails, + const bool aRequestShipping, + ErrorResult& aRv) { // Check the amount.value of each item in the display items if (aDetails.mDisplayItems.WasPassed()) { const Sequence& displayItems = aDetails.mDisplayItems.Value(); for (const PaymentItem& displayItem : displayItems) { - rv = IsValidCurrencyAmount(displayItem.mLabel, displayItem.mAmount, - false, // isTotalItem - aErrorMsg); - if (NS_FAILED(rv)) { - return rv; + IsValidCurrencyAmount(displayItem.mLabel, displayItem.mAmount, + false, // isTotalItem + aRv); + if (aRv.Failed()) { + return; } } } @@ -480,18 +507,20 @@ nsresult PaymentRequest::IsValidDetailsBase(const PaymentDetailsBase& aDetails, aDetails.mShippingOptions.Value(); nsTArray seenIDs; for (const PaymentShippingOption& shippingOption : shippingOptions) { - rv = IsValidCurrencyAmount(NS_LITERAL_STRING("details.shippingOptions"), - shippingOption.mAmount, - false, // isTotalItem - aErrorMsg); - if (NS_FAILED(rv)) { - return rv; + IsValidCurrencyAmount(NS_LITERAL_STRING("details.shippingOptions"), + shippingOption.mAmount, + false, // isTotalItem + aRv); + if (aRv.Failed()) { + return; } if (seenIDs.Contains(shippingOption.mId)) { - aErrorMsg.AssignLiteral("Duplicate shippingOption id '"); - aErrorMsg.Append(shippingOption.mId); - aErrorMsg.AppendLiteral("'"); - return NS_ERROR_TYPE_ERR; + nsAutoString error; + error.AssignLiteral("Duplicate shippingOption id '"); + error.Append(shippingOption.mId); + error.AppendLiteral("'"); + aRv.ThrowTypeError(error); + return; } seenIDs.AppendElement(shippingOption.mId); } @@ -502,36 +531,33 @@ nsresult PaymentRequest::IsValidDetailsBase(const PaymentDetailsBase& aDetails, const Sequence& modifiers = aDetails.mModifiers.Value(); for (const PaymentDetailsModifier& modifier : modifiers) { - rv = - IsValidPaymentMethodIdentifier(modifier.mSupportedMethods, aErrorMsg); - if (NS_FAILED(rv)) { - return rv; + IsValidPaymentMethodIdentifier(modifier.mSupportedMethods, aRv); + if (aRv.Failed()) { + return; } if (modifier.mTotal.WasPassed()) { - rv = IsValidCurrencyAmount(NS_LITERAL_STRING("details.modifiers.total"), - modifier.mTotal.Value().mAmount, - true, // isTotalItem - aErrorMsg); - if (NS_FAILED(rv)) { - return rv; + IsValidCurrencyAmount(NS_LITERAL_STRING("details.modifiers.total"), + modifier.mTotal.Value().mAmount, + true, // isTotalItem + aRv); + if (aRv.Failed()) { + return; } } if (modifier.mAdditionalDisplayItems.WasPassed()) { const Sequence& displayItems = modifier.mAdditionalDisplayItems.Value(); for (const PaymentItem& displayItem : displayItems) { - rv = IsValidCurrencyAmount(displayItem.mLabel, displayItem.mAmount, - false, // isTotalItem - aErrorMsg); - if (NS_FAILED(rv)) { - return rv; + IsValidCurrencyAmount(displayItem.mLabel, displayItem.mAmount, + false, // isTotalItem + aRv); + if (aRv.Failed()) { + return; } } } } } - - return NS_OK; } already_AddRefed PaymentRequest::Constructor( @@ -575,23 +601,12 @@ already_AddRefed PaymentRequest::Constructor( nsCOMPtr topLevelPrincipal = topLevelDoc->NodePrincipal(); // Check payment methods and details - nsAutoString message; - nsresult rv = IsValidMethodData(aGlobal.Context(), aMethodData, message); - if (NS_FAILED(rv)) { - if (rv == NS_ERROR_TYPE_ERR) { - aRv.ThrowTypeError(message); - } else if (rv == NS_ERROR_RANGE_ERR) { - aRv.ThrowRangeError(message); - } + IsValidMethodData(aGlobal.Context(), aMethodData, aRv); + if (aRv.Failed()) { return nullptr; } - rv = IsValidDetailsInit(aDetails, aOptions.mRequestShipping, message); - if (NS_FAILED(rv)) { - if (rv == NS_ERROR_TYPE_ERR) { - aRv.ThrowTypeError(message); - } else if (rv == NS_ERROR_RANGE_ERR) { - aRv.ThrowRangeError(message); - } + IsValidDetailsInit(aDetails, aOptions.mRequestShipping, aRv); + if (aRv.Failed()) { return nullptr; } @@ -602,9 +617,9 @@ already_AddRefed PaymentRequest::Constructor( // Create PaymentRequest and set its |mId| RefPtr request; - rv = manager->CreatePayment(aGlobal.Context(), window, topLevelPrincipal, - aMethodData, aDetails, aOptions, - getter_AddRefs(request)); + nsresult rv = manager->CreatePayment(aGlobal.Context(), window, + topLevelPrincipal, aMethodData, aDetails, + aOptions, getter_AddRefs(request)); if (NS_WARN_IF(NS_FAILED(rv))) { aRv.Throw(NS_ERROR_DOM_TYPE_ERR); return nullptr; @@ -641,7 +656,6 @@ PaymentRequest::PaymentRequest(nsPIDOMWindowInner* aWindow, mShippingAddress(nullptr), mUpdating(false), mRequestShipping(false), - mUpdateError(NS_OK), mState(eCreated), mIPC(nullptr) { MOZ_ASSERT(aWindow); @@ -748,7 +762,7 @@ already_AddRefed PaymentRequest::Show( return promise.forget(); } -void PaymentRequest::RejectShowPayment(nsresult aRejectReason) { +void PaymentRequest::RejectShowPayment(ErrorResult& aRejectReason) { MOZ_ASSERT(mAcceptPromise || mResponse); MOZ_ASSERT(mState == eInteractive); @@ -766,11 +780,11 @@ void PaymentRequest::RespondShowPayment(const nsAString& aMethodName, const nsAString& aPayerName, const nsAString& aPayerEmail, const nsAString& aPayerPhone, - nsresult aRv) { + ErrorResult& aRv) { MOZ_ASSERT(mAcceptPromise || mResponse); MOZ_ASSERT(mState == eInteractive); - if (NS_FAILED(aRv)) { + if (aRv.Failed()) { RejectShowPayment(aRv); return; } @@ -838,19 +852,19 @@ already_AddRefed PaymentRequest::Abort(ErrorResult& aRv) { void PaymentRequest::RespondAbortPayment(bool aSuccess) { // Check whether we are aborting the update: // - // - If |mUpdateError| is not NS_OK, we are aborting the update as + // - If |mUpdateError| is failed, we are aborting the update as // |mUpdateError| was set in method |AbortUpdate|. // => Reject |mAcceptPromise| and reset |mUpdateError| to complete // the action, regardless of |aSuccess|. // // - Otherwise, we are handling |Abort| method call from merchant. // => Resolve/Reject |mAbortPromise| based on |aSuccess|. - if (NS_FAILED(mUpdateError)) { + if (mUpdateError.Failed()) { // Respond show with mUpdateError, set mUpdating to false. mUpdating = false; RespondShowPayment(EmptyString(), ResponseData(), EmptyString(), EmptyString(), EmptyString(), mUpdateError); - mUpdateError = NS_OK; + mUpdateError.SuppressException(); return; } @@ -860,7 +874,9 @@ void PaymentRequest::RespondAbortPayment(bool aSuccess) { if (aSuccess) { mAbortPromise->MaybeResolve(JS::UndefinedHandleValue); mAbortPromise = nullptr; - RejectShowPayment(NS_ERROR_DOM_ABORT_ERR); + ErrorResult rv; + rv.Throw(NS_ERROR_DOM_ABORT_ERR); + RejectShowPayment(rv); } else { mAbortPromise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR); mAbortPromise = nullptr; @@ -885,12 +901,18 @@ nsresult PaymentRequest::UpdatePayment(JSContext* aCx, } void PaymentRequest::AbortUpdate(nsresult aRv) { + ErrorResult rv; + rv.Throw(aRv); + AbortUpdate(rv); +} + +void PaymentRequest::AbortUpdate(ErrorResult& aRv) { // perfect ignoring when the document is not fully active. if (!InFullyActiveDocument()) { return; } - MOZ_ASSERT(NS_FAILED(aRv)); + MOZ_ASSERT(aRv.Failed()); if (mState != eInteractive) { return; @@ -908,7 +930,7 @@ void PaymentRequest::AbortUpdate(nsresult aRv) { // 1. Set target.state to closed // 2. Reject the promise target.acceptPromise with exception "aRv" // 3. Abort the algorithm with update error - mUpdateError = aRv; + mUpdateError = std::move(aRv); } nsresult PaymentRequest::RetryPayment(JSContext* aCx, @@ -1086,13 +1108,15 @@ void PaymentRequest::ResolvedCallback(JSContext* aCx, // Converting value to a PaymentDetailsUpdate dictionary RootedDictionary details(aCx); if (!details.Init(aCx, aValue)) { - AbortUpdate(NS_ERROR_DOM_TYPE_ERR); - JS_ClearPendingException(aCx); + ErrorResult rv; + rv.StealExceptionFromJSContext(aCx); + AbortUpdate(rv); return; } - nsresult rv = IsValidDetailsUpdate(details, mRequestShipping); - if (NS_FAILED(rv)) { + ErrorResult rv; + IsValidDetailsUpdate(details, mRequestShipping, rv); + if (rv.Failed()) { AbortUpdate(rv); return; } @@ -1168,7 +1192,9 @@ void PaymentRequest::NotifyOwnerDocumentActivityChanged() { mAcceptPromise = nullptr; } if (mResponse) { - mResponse->RejectRetry(NS_ERROR_DOM_ABORT_ERR); + ErrorResult rv; + rv.Throw(NS_ERROR_DOM_ABORT_ERR); + mResponse->RejectRetry(rv); } if (mAbortPromise) { mAbortPromise->MaybeReject(NS_ERROR_DOM_ABORT_ERR); @@ -1187,6 +1213,11 @@ void PaymentRequest::NotifyOwnerDocumentActivityChanged() { } PaymentRequest::~PaymentRequest() { + // Suppress any pending unreported exception on mUpdateError. We don't use + // IgnoredErrorResult for mUpdateError because that doesn't play very nice + // with move assignment operators. + mUpdateError.SuppressException(); + if (mIPC) { // If we're being destroyed, the PaymentRequestManager isn't holding any // references to us and we can't be waiting for any replies. diff --git a/dom/payments/PaymentRequest.h b/dom/payments/PaymentRequest.h index ac76e448941b..9843251d8c64 100644 --- a/dom/payments/PaymentRequest.h +++ b/dom/payments/PaymentRequest.h @@ -101,41 +101,37 @@ class PaymentRequest final : public DOMEventTargetHelper, static bool PrefEnabled(JSContext* aCx, JSObject* aObj); - static nsresult IsValidStandardizedPMI(const nsAString& aIdentifier, - nsAString& aErrorMsg); + static void IsValidStandardizedPMI(const nsAString& aIdentifier, + ErrorResult& aRv); - static nsresult IsValidPaymentMethodIdentifier(const nsAString& aIdentifier, - nsAString& aErrorMsg); + static void IsValidPaymentMethodIdentifier(const nsAString& aIdentifier, + ErrorResult& aRv); - static nsresult IsValidMethodData( - JSContext* aCx, const Sequence& aMethodData, - nsAString& aErrorMsg); + static void IsValidMethodData(JSContext* aCx, + const Sequence& aMethodData, + ErrorResult& aRv); - static nsresult IsValidNumber(const nsAString& aItem, const nsAString& aStr, - nsAString& aErrorMsg); - static nsresult IsNonNegativeNumber(const nsAString& aItem, - const nsAString& aStr, - nsAString& aErrorMsg); + static void IsValidNumber(const nsAString& aItem, const nsAString& aStr, + ErrorResult& aRv); + static void IsNonNegativeNumber(const nsAString& aItem, const nsAString& aStr, + ErrorResult& aRv); - static nsresult IsValidCurrencyAmount(const nsAString& aItem, - const PaymentCurrencyAmount& aAmount, - const bool aIsTotalItem, - nsAString& aErrorMsg); + static void IsValidCurrencyAmount(const nsAString& aItem, + const PaymentCurrencyAmount& aAmount, + const bool aIsTotalItem, ErrorResult& aRv); - static nsresult IsValidCurrency(const nsAString& aItem, - const nsAString& aCurrency, - nsAString& aErrorMsg); + static void IsValidCurrency(const nsAString& aItem, + const nsAString& aCurrency, ErrorResult& aRv); - static nsresult IsValidDetailsInit(const PaymentDetailsInit& aDetails, - const bool aRequestShipping, - nsAString& aErrorMsg); + static void IsValidDetailsInit(const PaymentDetailsInit& aDetails, + const bool aRequestShipping, ErrorResult& aRv); - static nsresult IsValidDetailsUpdate(const PaymentDetailsUpdate& aDetails, - const bool aRequestShipping); + static void IsValidDetailsUpdate(const PaymentDetailsUpdate& aDetails, + const bool aRequestShipping, + ErrorResult& aRv); - static nsresult IsValidDetailsBase(const PaymentDetailsBase& aDetails, - const bool aRequestShipping, - nsAString& aErrorMsg); + static void IsValidDetailsBase(const PaymentDetailsBase& aDetails, + const bool aRequestShipping, ErrorResult& aRv); static already_AddRefed Constructor( const GlobalObject& aGlobal, @@ -152,8 +148,8 @@ class PaymentRequest final : public DOMEventTargetHelper, const ResponseData& aData, const nsAString& aPayerName, const nsAString& aPayerEmail, - const nsAString& aPayerPhone, nsresult aRv); - void RejectShowPayment(nsresult aRejectReason); + const nsAString& aPayerPhone, ErrorResult& aRv); + void RejectShowPayment(ErrorResult& aRejectReason); void RespondComplete(); already_AddRefed Abort(ErrorResult& aRv); @@ -191,6 +187,7 @@ class PaymentRequest final : public DOMEventTargetHelper, nsresult UpdatePayment(JSContext* aCx, const PaymentDetailsUpdate& aDetails); void AbortUpdate(nsresult aRv); + void AbortUpdate(ErrorResult& aRv); void SetShippingType(const Nullable& aShippingType); Nullable GetShippingType() const; @@ -266,8 +263,8 @@ class PaymentRequest final : public DOMEventTargetHelper, // but we don't actually store the full [[options]] internal slot. bool mRequestShipping; - // The error is set in AbortUpdate(). The value is NS_OK by default. - nsresult mUpdateError; + // The error is set in AbortUpdate(). The value is not-failed by default. + ErrorResult mUpdateError; enum { eUnknown, eCreated, eInteractive, eClosed } mState; diff --git a/dom/payments/PaymentRequestManager.cpp b/dom/payments/PaymentRequestManager.cpp index 166e0acb4b6e..6e26f3d0f635 100644 --- a/dom/payments/PaymentRequestManager.cpp +++ b/dom/payments/PaymentRequestManager.cpp @@ -651,31 +651,30 @@ nsresult PaymentRequestManager::RespondPayment( } case IPCPaymentActionResponse::TIPCPaymentShowActionResponse: { const IPCPaymentShowActionResponse& response = aResponse; - nsresult rejectedReason = NS_ERROR_DOM_ABORT_ERR; + ErrorResult rejectedReason; ResponseData responseData; ConvertResponseData(response.data(), responseData); switch (response.status()) { case nsIPaymentActionResponse::PAYMENT_ACCEPTED: { - rejectedReason = NS_OK; break; } case nsIPaymentActionResponse::PAYMENT_REJECTED: { - rejectedReason = NS_ERROR_DOM_ABORT_ERR; + rejectedReason.Throw(NS_ERROR_DOM_ABORT_ERR); break; } case nsIPaymentActionResponse::PAYMENT_NOTSUPPORTED: { - rejectedReason = NS_ERROR_DOM_NOT_SUPPORTED_ERR; + rejectedReason.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); break; } default: { - rejectedReason = NS_ERROR_UNEXPECTED; + rejectedReason.Throw(NS_ERROR_UNEXPECTED); break; } } aRequest->RespondShowPayment(response.methodName(), responseData, response.payerName(), response.payerEmail(), response.payerPhone(), rejectedReason); - if (NS_FAILED(rejectedReason)) { + if (rejectedReason.Failed()) { NotifyRequestDone(aRequest); } break; diff --git a/dom/payments/PaymentRequestUpdateEvent.cpp b/dom/payments/PaymentRequestUpdateEvent.cpp index 568a056cc28e..495eb2f0f56b 100644 --- a/dom/payments/PaymentRequestUpdateEvent.cpp +++ b/dom/payments/PaymentRequestUpdateEvent.cpp @@ -64,8 +64,9 @@ void PaymentRequestUpdateEvent::ResolvedCallback(JSContext* aCx, // Converting value to a PaymentDetailsUpdate dictionary RootedDictionary details(aCx); if (!details.Init(aCx, aValue)) { - mRequest->AbortUpdate(NS_ERROR_TYPE_ERR); - JS_ClearPendingException(aCx); + ErrorResult rv; + rv.StealExceptionFromJSContext(aCx); + mRequest->AbortUpdate(rv); return; } @@ -74,9 +75,9 @@ void PaymentRequestUpdateEvent::ResolvedCallback(JSContext* aCx, // dispatched when shippingAddress/shippingOption is changed, and it also // means Options.RequestShipping must be true while creating the corresponding // PaymentRequest. - nsresult rv = - mRequest->IsValidDetailsUpdate(details, true /*aRequestShipping*/); - if (NS_FAILED(rv)) { + ErrorResult rv; + mRequest->IsValidDetailsUpdate(details, true /*aRequestShipping*/, rv); + if (rv.Failed()) { mRequest->AbortUpdate(rv); return; } diff --git a/dom/payments/PaymentResponse.cpp b/dom/payments/PaymentResponse.cpp index e5620e6a7a2b..150aa51a4faa 100644 --- a/dom/payments/PaymentResponse.cpp +++ b/dom/payments/PaymentResponse.cpp @@ -259,14 +259,9 @@ already_AddRefed PaymentResponse::Retry( // Depending on the PMI, try to do IDL type conversion // (e.g., basic-card expects at BasicCardErrors dictionary) - nsAutoString errorMsg; - rv = ConvertPaymentMethodErrors(aCx, aErrors, errorMsg); - if (NS_WARN_IF(NS_FAILED(rv))) { - MOZ_ASSERT(!errorMsg.IsEmpty()); - ErrorResult error; - error.ThrowTypeError(errorMsg); - promise->MaybeReject(error); - return promise.forget(); + ConvertPaymentMethodErrors(aCx, aErrors, aRv); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; } MOZ_ASSERT(mRequest); @@ -308,28 +303,27 @@ void PaymentResponse::RespondRetry(const nsAString& aMethodName, mRetryPromise = nullptr; } -void PaymentResponse::RejectRetry(nsresult aRejectReason) { +void PaymentResponse::RejectRetry(ErrorResult& aRejectReason) { MOZ_ASSERT(mRetryPromise); mRetryPromise->MaybeReject(aRejectReason); mRetryPromise = nullptr; } -nsresult PaymentResponse::ConvertPaymentMethodErrors( +void PaymentResponse::ConvertPaymentMethodErrors( JSContext* aCx, const PaymentValidationErrors& aErrors, - nsAString& errorMsg) const { + ErrorResult& aRv) const { MOZ_ASSERT(aCx); if (!aErrors.mPaymentMethod.WasPassed()) { - return NS_OK; + return; } RefPtr service = BasicCardService::GetService(); MOZ_ASSERT(service); if (service->IsBasicCardPayment(mMethodName)) { - if (service->IsValidBasicCardErrors(aCx, aErrors.mPaymentMethod.Value())) { - errorMsg.Assign(NS_LITERAL_STRING("paymentMethod")); - return NS_ERROR_TYPE_ERR; - } + MOZ_ASSERT(aErrors.mPaymentMethod.Value(), + "The IDL says this is not nullable!"); + service->CheckForValidBasicCardErrors(aCx, aErrors.mPaymentMethod.Value(), + aRv); } - return NS_OK; } nsresult PaymentResponse::ValidatePaymentValidationErrors( diff --git a/dom/payments/PaymentResponse.h b/dom/payments/PaymentResponse.h index 5df24d227463..8e7b3c2e882a 100644 --- a/dom/payments/PaymentResponse.h +++ b/dom/payments/PaymentResponse.h @@ -141,7 +141,7 @@ class PaymentResponse final : public DOMEventTargetHelper, PaymentAddress* aShippingAddress, const ResponseData& aDetails, const nsAString& aPayerName, const nsAString& aPayerEmail, const nsAString& aPayerPhone); - void RejectRetry(nsresult aRejectReason); + void RejectRetry(ErrorResult& aRejectReason); protected: ~PaymentResponse(); @@ -149,9 +149,9 @@ class PaymentResponse final : public DOMEventTargetHelper, nsresult ValidatePaymentValidationErrors( const PaymentValidationErrors& aErrors); - nsresult ConvertPaymentMethodErrors(JSContext* aCx, - const PaymentValidationErrors& aErrors, - nsAString& aErrorMsg) const; + void ConvertPaymentMethodErrors(JSContext* aCx, + const PaymentValidationErrors& aErrors, + ErrorResult& aRv) const; nsresult DispatchUpdateEvent(const nsAString& aType);