static void PerformWebPageDownload()

in HTTPS_MutualAuth/Azsphere/main.c [239:418]


static void PerformWebPageDownload(void)
{
    CURL *curlHandle = NULL;
    CURLcode res = 0;
    MemoryBlock block = {.data = NULL, .size = 0, .paused = false};
    char *certificatePath = NULL;
    char *clientCertPath = NULL;
    char *clientKeyPath = NULL;

    printedEntireResponse = false;

    if (IsNetworkReady() == false) {
        goto exitLabel;
    }

    Log_Debug("\n -===- START-OF-DOWNLOAD -===-\n");

    // Init the cURL library.
    if ((res = curl_global_init(CURL_GLOBAL_ALL)) != CURLE_OK) {
        LogCurlError("curl_global_init", res);
        goto exitLabel;
    }

    if ((curlHandle = curl_easy_init()) == NULL) {
        Log_Debug("curl_easy_init() failed\n");
        goto cleanupLabel;
    }

    // Set the cURL handle to allow access to the cURL handle in callbacks.
    block.curlHandle = curlHandle;

    // Specify URL to download.
    // Important: Any change in the domain name must be reflected in the AllowedConnections
    // capability in app_manifest.json.
#warning Change the following line to specify the server address and delete this warning!
    if ((res = curl_easy_setopt(curlHandle, CURLOPT_URL, "https://CHANGE.THIS:5000/")) != CURLE_OK) {
        LogCurlError("curl_easy_setopt CURLOPT_URL", res);
        goto cleanupLabel;
    }

    // Set output level to verbose.
    if ((res = curl_easy_setopt(curlHandle, CURLOPT_VERBOSE, 1L)) != CURLE_OK) {
        LogCurlError("curl_easy_setopt CURLOPT_VERBOSE", res);
        goto cleanupLabel;
    }

    // Get the full path to the certificate file used to authenticate the HTTPS server identity.
    certificatePath = Storage_GetAbsolutePathInImagePackage("certs/ca-bundle.pem");
    if (certificatePath == NULL) {
        Log_Debug("The certificate path could not be resolved: errno=%d (%s)\n", errno,
                  strerror(errno));
        goto cleanupLabel;
    }

    // Set the path for the certificate file that cURL uses to validate the server certificate.
    if ((res = curl_easy_setopt(curlHandle, CURLOPT_CAINFO, certificatePath)) != CURLE_OK) {
        LogCurlError("curl_easy_setopt CURLOPT_CAINFO", res);
        goto cleanupLabel;
    }

    clientCertPath= Storage_GetAbsolutePathInImagePackage("certs/device-cert.pem");
    if (clientCertPath == NULL) {
        Log_Debug("The client certificate path could not be resolved: errno=%d (%s)\n", errno,
                  strerror(errno));
        goto cleanupLabel;
    }
    
    if ((res = curl_easy_setopt(curlHandle, CURLOPT_SSLCERT, clientCertPath)) != CURLE_OK) {
        LogCurlError("curl_easy_setopt CURLOPT_SSLCERT", res);
        goto cleanupLabel;
    }
    
    clientKeyPath= Storage_GetAbsolutePathInImagePackage("certs/device-key.pem");
    if (clientKeyPath == NULL) {
        Log_Debug("The client key path could not be resolved: errno=%d (%s)\n", errno,
                  strerror(errno));
        goto cleanupLabel;
    }

    if ((res = curl_easy_setopt(curlHandle, CURLOPT_SSLKEY, clientKeyPath)) != CURLE_OK) {
        LogCurlError("curl_easy_setopt CURLOPT_SSLKEY", res);
        goto cleanupLabel;
    }

    if ((res = curl_easy_setopt(curlHandle, CURLOPT_SSL_VERIFYPEER, 1L)) != CURLE_OK) {
        LogCurlError("curl_easy_setopt CURLOPT_SSL_VERIFYPEER", res);
        goto cleanupLabel;
    }

    if ((res = curl_easy_setopt(curlHandle, CURLOPT_SSL_VERIFYHOST, 1L)) != CURLE_OK) {
        LogCurlError("curl_easy_setopt CURLOPT_SSL_VERIFYHOST", res);
        goto cleanupLabel;
    }

    // Let cURL follow any HTTP 3xx redirects.
    // Important: Any redirection to different domain names requires that domain name to be added to
    // app_manifest.json.
    if ((res = curl_easy_setopt(curlHandle, CURLOPT_FOLLOWLOCATION, 1L)) != CURLE_OK) {
        LogCurlError("curl_easy_setopt CURLOPT_FOLLOWLOCATION", res);
        goto cleanupLabel;
    }

    // Set up callback for cURL to use when downloading data.
    if ((res = curl_easy_setopt(curlHandle, CURLOPT_WRITEFUNCTION, StoreDownloadedDataCallback)) !=
        CURLE_OK) {
        LogCurlError("curl_easy_setopt CURLOPT_WRITEFUNCTION", res);
        goto cleanupLabel;
    }

    // Set the custom parameter of the callback to the memory block.
    if ((res = curl_easy_setopt(curlHandle, CURLOPT_WRITEDATA, (void *)&block)) != CURLE_OK) {
        LogCurlError("curl_easy_setopt CURLOPT_WRITEDATA", res);
        goto cleanupLabel;
    }

    // Specify a user agent.
    if ((res = curl_easy_setopt(curlHandle, CURLOPT_USERAGENT, "libcurl-agent/1.0")) != CURLE_OK) {
        LogCurlError("curl_easy_setopt CURLOPT_USERAGENT", res);
        goto cleanupLabel;
    }

    // Set up callback for cURL to report transfer information.
    if ((res = curl_easy_setopt(curlHandle, CURLOPT_XFERINFOFUNCTION, TransferInfoCallback)) !=
        CURLE_OK) {
        LogCurlError("curl_easy_setopt CURLOPT_XFERINFOFUNCTION", res);
        goto cleanupLabel;
    }

    // Set the custom parameter of the callback to the memory block. It is not used by cURL but is
    // only passed along from the application to the callback.
    if ((res = curl_easy_setopt(curlHandle, CURLOPT_XFERINFODATA, (void *)&block)) != CURLE_OK) {
        LogCurlError("curl_easy_setopt CURLOPT_XFERINFODATA", res);
        goto cleanupLabel;
    }

    // Turn on the progress meter. This enables CURLOPT_XFERINFOFUNCTION callbacks.
    if ((res = curl_easy_setopt(curlHandle, CURLOPT_NOPROGRESS, 0L)) != CURLE_OK) {
        LogCurlError("curl_easy_setopt CURLOPT_NOPROGRESS", res);
        goto cleanupLabel;
    }

    // Configure the cURL handle to use the proxy.
    if (!bypassProxy) {
        if (Networking_Curl_SetDefaultProxy(curlHandle) != 0) {
            Log_Debug("Networking_Curl_SetDefaultProxy failed: errno=%d (%s)\n", errno,
                      strerror(errno));
            exitCode = ExitCode_CurlSetDefaultProxy_Failed;
            goto cleanupLabel;
        }
    }

    // When using libcurl, as with other networking applications, the Azure Sphere OS will
    // allocate socket buffers which are attributed to your application's RAM usage. You can tune
    // the size of these buffers to reduce the RAM footprint of your application as appropriate.
    // Refer to https://learn.microsoft.com/azure-sphere/app-development/ram-usage-best-practices
    // for further details.

    // Perform the download of the web page.
    if ((res = curl_easy_perform(curlHandle)) != CURLE_OK) {
        LogCurlError("curl_easy_perform", res);
    } else {
        if (!printedEntireResponse) {
            // Log the remaining downloaded content if it wasn't logged in TransferInfoCallback.
            PrintResponseAndResetData(&block);
        }
    }

cleanupLabel:
    // Clean up allocated memory.
    free(block.data);
    free(certificatePath);
    // Clean up sample's cURL resources.
    curl_easy_cleanup(curlHandle);
    // Clean up cURL library's resources.
    curl_global_cleanup();
    Log_Debug("\n -===- END-OF-DOWNLOAD -===-\n");

exitLabel:
    return;
}