STATUS initializeCurlSession()

in src/source/Response.c [125:235]


STATUS initializeCurlSession(PRequestInfo pRequestInfo, PCallInfo pCallInfo, CURL** ppCurl, PVOID data, CurlCallbackFunc writeHeaderFn,
                             CurlCallbackFunc readFn, CurlCallbackFunc writeFn, CurlCallbackFunc responseWriteFn)
{
    ENTERS();
    STATUS retStatus = STATUS_SUCCESS;
    BOOL secureConnection;
    CURL* pCurl = NULL;
    UINT32 length;
    STAT_STRUCT entryStat;

    CHK(pRequestInfo != NULL && pCallInfo != NULL && ppCurl != NULL, STATUS_NULL_ARG);

    pCallInfo->pRequestInfo = pRequestInfo;
    pCallInfo->httpStatus = HTTP_STATUS_CODE_NOT_SET;
    pCallInfo->callResult = SERVICE_CALL_RESULT_NOT_SET;

    // Initialize curl and set options
    pCurl = curl_easy_init();
    CHK(pCurl != NULL, STATUS_CURL_INIT_FAILED);

    // set up the friendly error message buffer
    pCallInfo->errorBuffer[0] = '\0';
    curl_easy_setopt(pCurl, CURLOPT_ERRORBUFFER, pCallInfo->errorBuffer);

    curl_easy_setopt(pCurl, CURLOPT_URL, pRequestInfo->url);
    curl_easy_setopt(pCurl, CURLOPT_NOSIGNAL, 1);

    // Setting up limits for curl timeout
    curl_easy_setopt(pCurl, CURLOPT_LOW_SPEED_TIME, DEFAULT_LOW_SPEED_TIME_LIMIT / HUNDREDS_OF_NANOS_IN_A_SECOND);
    curl_easy_setopt(pCurl, CURLOPT_LOW_SPEED_LIMIT, DEFAULT_LOW_SPEED_LIMIT);

    // set verification for SSL connections
    CHK_STATUS(requestRequiresSecureConnection(pRequestInfo->url, &secureConnection));
    if (secureConnection) {
        // Use the default cert store at /etc/ssl in most common platforms
        if (pRequestInfo->certPath[0] != '\0') {
            CHK(0 == FSTAT(pRequestInfo->certPath, &entryStat), STATUS_DIRECTORY_ENTRY_STAT_ERROR);

            if (S_ISDIR(entryStat.st_mode)) {
                // Assume it's the path as we have a directory
                curl_easy_setopt(pCurl, CURLOPT_CAPATH, pRequestInfo->certPath);
            } else {
                // We should check for the extension being PEM
                length = (UINT32) STRNLEN(pRequestInfo->certPath, MAX_PATH_LEN);
                CHK(length > ARRAY_SIZE(CA_CERT_FILE_SUFFIX), STATUS_INVALID_ARG_LEN);
                CHK(0 == STRCMPI(CA_CERT_FILE_SUFFIX, &pRequestInfo->certPath[length - ARRAY_SIZE(CA_CERT_FILE_SUFFIX) + 1]),
                    STATUS_INVALID_CA_CERT_PATH);

                curl_easy_setopt(pCurl, CURLOPT_CAINFO, pRequestInfo->certPath);
            }
        }

        // Enforce the public cert verification - even though this is the default
        curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYPEER, 1L);
        curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYHOST, 2L);
        curl_easy_setopt(pCurl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2);
    }

    // set request completion timeout in milliseconds
    if (pRequestInfo->completionTimeout != SERVICE_CALL_INFINITE_TIMEOUT) {
        curl_easy_setopt(pCurl, CURLOPT_TIMEOUT_MS, pRequestInfo->completionTimeout / HUNDREDS_OF_NANOS_IN_A_MILLISECOND);
    }
    curl_easy_setopt(pCurl, CURLOPT_CONNECTTIMEOUT_MS, pRequestInfo->connectionTimeout / HUNDREDS_OF_NANOS_IN_A_MILLISECOND);
    curl_easy_setopt(pCurl, CURLOPT_TCP_NODELAY, 1);

    // set header callback
    curl_easy_setopt(pCurl, CURLOPT_HEADERFUNCTION, writeHeaderFn);
    curl_easy_setopt(pCurl, CURLOPT_HEADERDATA, data);

    switch (pRequestInfo->verb) {
        case HTTP_REQUEST_VERB_GET:
            curl_easy_setopt(pCurl, CURLOPT_HTTPGET, 1L);
            break;

        case HTTP_REQUEST_VERB_PUT:
            curl_easy_setopt(pCurl, CURLOPT_PUT, 1L);
            break;

        case HTTP_REQUEST_VERB_POST:
            curl_easy_setopt(pCurl, CURLOPT_POST, 1L);
            if (pRequestInfo->body == NULL) {
                // Set the read callback from the request
                curl_easy_setopt(pCurl, CURLOPT_READFUNCTION, readFn);
                curl_easy_setopt(pCurl, CURLOPT_READDATA, data);

                // Set the write callback from the request
                curl_easy_setopt(pCurl, CURLOPT_WRITEFUNCTION, writeFn);
                curl_easy_setopt(pCurl, CURLOPT_WRITEDATA, data);
            } else {
                // Set the read data and it's size
                curl_easy_setopt(pCurl, CURLOPT_POSTFIELDSIZE, pRequestInfo->bodySize);
                curl_easy_setopt(pCurl, CURLOPT_POSTFIELDS, pRequestInfo->body);

                // Set response callback
                curl_easy_setopt(pCurl, CURLOPT_WRITEFUNCTION, responseWriteFn);
                curl_easy_setopt(pCurl, CURLOPT_WRITEDATA, data);
            }

            break;
    }

    // Create the response headers list
    CHK_STATUS(stackQueueCreate(&pCallInfo->pResponseHeaders));

    *ppCurl = pCurl;

CleanUp:

    LEAVES();
    return retStatus;
}