Jake Short
Jake Short

Reputation: 57

read ECONNRESET error when working with HTTP request in cloud function

I am trying to send a post request to the App Store verifyReceipt endpoint in a Firebase cloud function. However, I get the following error in the cloud function log:

{ Error: read ECONNRESET
    at TLSWrap.onread (net.js:622:25)
  errno: 'ECONNRESET',
  code: 'ECONNRESET',
  syscall: 'read',

However, this error is only occasional. It does not happen every time, so the function obviously works, but something is going wrong sometimes and I'm not sure what.

Most other solutions relating to this were due to a promise error, but I do not believe that is the problem here. Below is the complete function:

exports.handleSubscriptionIAP_IOS_S2S = functions.https.onRequest((req, res) => {
    let data = req.body;

    console.log('received ios s2s notification with body:', data);

    let base64String = data.unified_receipt.latest_receipt;

    let boolStatus = true;
    // The user has changed the auto renewal status, store the change
    if(data.notification_type === 'DID_CHANGE_RENEWAL_STATUS') {
        boolStatus = (data.auto_renew_status === 'true');
    }

    console.log(data.notification_type);

    if(base64String) {
        var options = {
            method: 'post',
            url: 'https://buy.itunes.apple.com/verifyReceipt',
            data: ({
                "receipt-data" : base64String,
                "password" : "***",
                "exclude-old-transactions" : true
            })
        };

        var optionsSandbox = {
            method: 'post',
            url: 'https://sandbox.itunes.apple.com/verifyReceipt',
            data: ({
                "receipt-data" : base64String,
                "password" : "***",
                "exclude-old-transactions" : true
            })
        };

        return axios(options)
        .then((response) => {
            if(response.data.status === 21007) {
                return 'handle_sandbox';
            }

            // Got valid response from Apple, pass down chain
            else {
                return response;
            }
        })
        .then((response) => {
            // Send post request to sandbox endpoint
            if(response === 'handle_sandbox') {
                return axios(optionsSandbox);
            }

            // Pass response down chain
            else {
                return response;
            }
        })
        .then((response) => {
            // Handle response from Apple verifyReceipt endpoint here
            // Both production and sandbox will end up here
            // See here for values in response.data: https://developer.apple.com/documentation/appstorereceipts/responsebody/latest_receipt_info

            console.log('received ios s2s notification verify receipt response with body:', response.data);
            // Status 0 means request is valid
            if(response.data.status === 0) {
                // Get receipt info of latest receipt
                // Only one object in array is return since we exclude old transactions
                let latestReceipt = response.data.latest_receipt_info[0];

                // Save receipt into Firestore
                return db.collection('appStoreReceipts').doc(latestReceipt.original_transaction_id).set({
                    latest_receipt_info: latestReceipt,

                    expiresTimestamp: admin.firestore.Timestamp.fromMillis(parseInt(latestReceipt.expires_date_ms)),
                    originalTransactionID: latestReceipt.original_transaction_id,

                    autoRenewStatus: boolStatus,

                    base64Receipt: response.data.latest_receipt,
                }, { merge: true });
            }
            else {
                return null;
            }
        })
        .then((result) => {
            if(result) {
                return res.status(200).end();
            }
            else {
                return res.status(400).end();
            }
        })
        .catch((error) => {
            console.log('an error occured handling the subscription', error);

            return res.status(400).end();
        })
    }
    else {
        console.log('invalid receipt', data);

        return res.status(400).end();
    }
});

Thank you for any help that you can give!

Upvotes: 2

Views: 15287

Answers (1)

Doug Stevenson
Doug Stevenson

Reputation: 317712

ECONNRESET just means that the other end of the connection closed it. That could mean any number of things. It's probably not your code's fault, unless you've done something so bad in this one request that Apple decided to close the connection. You should contact their support directly if you think they're doing this incorrectly.

Upvotes: 4

Related Questions