HTTPAPI_RESULT HTTPAPI_SetOption()

in adapters/httpapi_compact.c [1294:1499]


HTTPAPI_RESULT HTTPAPI_SetOption(HTTP_HANDLE handle, const char* optionName, const void* value)
{
    HTTPAPI_RESULT result;
    HTTP_HANDLE_DATA* http_instance = (HTTP_HANDLE_DATA*)handle;

    if (
        (http_instance == NULL) ||
        (optionName == NULL) ||
        (value == NULL)
        )
    {
        /*Codes_SRS_HTTPAPI_COMPACT_21_059: [ If the handle is NULL, the HTTPAPI_SetOption shall return HTTPAPI_INVALID_ARG. ]*/
        /*Codes_SRS_HTTPAPI_COMPACT_21_060: [ If the optionName is NULL, the HTTPAPI_SetOption shall return HTTPAPI_INVALID_ARG. ]*/
        /*Codes_SRS_HTTPAPI_COMPACT_21_061: [ If the value is NULL, the HTTPAPI_SetOption shall return HTTPAPI_INVALID_ARG. ]*/
        result = HTTPAPI_INVALID_ARG;
    }
    else if (strcmp(OPTION_TRUSTED_CERT, optionName) == 0)
    {
#ifdef DO_NOT_COPY_TRUSTED_CERTS_STRING
        result = HTTPAPI_OK;
        http_instance->certificate = (char*)value;
#else

        if (http_instance->certificate)
        {
            free(http_instance->certificate);
        }

        size_t len = strlen((char*)value);
        size_t malloc_size = safe_add_size_t(len, 1);
        malloc_size = safe_multiply_size_t(malloc_size, sizeof(char));
        if (malloc_size == SIZE_MAX)
        {
            LogError("Invalid malloc size");
            http_instance->certificate = NULL;
        }
        else
        {
            http_instance->certificate = (char*)malloc(malloc_size);
        }

        if (http_instance->certificate == NULL)
        {
            /*Codes_SRS_HTTPAPI_COMPACT_21_062: [ If any memory allocation get fail, the HTTPAPI_SetOption shall return HTTPAPI_ALLOC_FAILED. ]*/
            result = HTTPAPI_ALLOC_FAILED;
            LogInfo("unable to allocate memory for the certificate in HTTPAPI_SetOption");
        }
        else
        {
            /*Codes_SRS_HTTPAPI_COMPACT_21_064: [ If the HTTPAPI_SetOption get success setting the option, it shall return HTTPAPI_OK. ]*/
            (void)strcpy(http_instance->certificate, (const char*)value);
            result = HTTPAPI_OK;
        }
#endif // DO_NOT_COPY_TRUSTED_CERTS_STRING
    }
    else if (strcmp(SU_OPTION_X509_CERT, optionName) == 0 || strcmp(OPTION_X509_ECC_CERT, optionName) == 0)
    {
        if (http_instance->x509ClientCertificate)
        {
            free(http_instance->x509ClientCertificate);
        }

        size_t len = strlen((char*)value);
        size_t malloc_size = safe_add_size_t(len, 1);
        malloc_size = safe_multiply_size_t(malloc_size, sizeof(char));
        if (malloc_size == SIZE_MAX)
        {
            LogError("Invalid malloc size");
            http_instance->x509ClientCertificate = NULL;
        }
        else
        {
            http_instance->x509ClientCertificate = (char*)malloc(malloc_size);
        }

        if (http_instance->x509ClientCertificate == NULL)
        {
            /*Codes_SRS_HTTPAPI_COMPACT_21_062: [ If any memory allocation get fail, the HTTPAPI_SetOption shall return HTTPAPI_ALLOC_FAILED. ]*/
            result = HTTPAPI_ALLOC_FAILED;
            LogInfo("unable to allocate memory for the client certificate in HTTPAPI_SetOption");
        }
        else
        {
            /*Codes_SRS_HTTPAPI_COMPACT_21_064: [ If the HTTPAPI_SetOption get success setting the option, it shall return HTTPAPI_OK. ]*/
            (void)strcpy(http_instance->x509ClientCertificate, (const char*)value);
            result = HTTPAPI_OK;
        }
    }
    else if (strcmp(SU_OPTION_X509_PRIVATE_KEY, optionName) == 0 || strcmp(OPTION_X509_ECC_KEY, optionName) == 0)
    {
        if (http_instance->x509ClientPrivateKey)
        {
            free(http_instance->x509ClientPrivateKey);
        }

        size_t len = strlen((char*)value);
        size_t malloc_size = safe_add_size_t(len, 1);
        malloc_size = safe_multiply_size_t(malloc_size, sizeof(char));
        if (malloc_size == SIZE_MAX)
        {
            LogError("Invalid malloc size");
            http_instance->x509ClientPrivateKey = NULL;
        }
        else
        {
            http_instance->x509ClientPrivateKey = (char*)malloc(malloc_size);
        }

        if (http_instance->x509ClientPrivateKey == NULL)
        {
            /*Codes_SRS_HTTPAPI_COMPACT_21_062: [ If any memory allocation get fail, the HTTPAPI_SetOption shall return HTTPAPI_ALLOC_FAILED. ]*/
            result = HTTPAPI_ALLOC_FAILED;
            LogInfo("unable to allocate memory for the client private key in HTTPAPI_SetOption");
        }
        else
        {
            /*Codes_SRS_HTTPAPI_COMPACT_21_064: [ If the HTTPAPI_SetOption get success setting the option, it shall return HTTPAPI_OK. ]*/
            (void)strcpy(http_instance->x509ClientPrivateKey, (const char*)value);
            result = HTTPAPI_OK;
        }
    }
    else if (strcmp(OPTION_HTTP_PROXY, optionName) == 0)
    {
        TLSIO_CONFIG tlsio_config;
        HTTP_PROXY_IO_CONFIG proxy_config;
        HTTP_PROXY_OPTIONS* proxy_options = (HTTP_PROXY_OPTIONS*)value;

        if (proxy_options->host_address == NULL)
        {
            LogError("NULL host_address in proxy options");
            result = HTTPAPI_ERROR;
        }
        else if (((proxy_options->username == NULL) || (proxy_options->password == NULL)) &&
                (proxy_options->username != proxy_options->password))
        {
            LogError("Only one of username and password for proxy settings was NULL");
            result = HTTPAPI_ERROR;
        }
        else
        {

            /* Workaround: xio interface is already created when HTTPAPI_CreateConnection is call without proxy support
             * need to destroy the interface and create a new one with proxy information
             */
            OPTIONHANDLER_HANDLE xio_options;
            if ((xio_options = xio_retrieveoptions(http_instance->xio_handle)) == NULL)
            {
                LogError("failed saving underlying I/O transport options");
                result = HTTPAPI_ERROR;
            }
            else
            {
                xio_destroy(http_instance->xio_handle);

                proxy_config.hostname = http_instance->hostName;
                proxy_config.proxy_hostname = proxy_options->host_address;
                proxy_config.password = proxy_options->password;
                proxy_config.username = proxy_options->username;
                proxy_config.proxy_port = proxy_options->port;
                proxy_config.port = 443;

                tlsio_config.hostname = http_instance->hostName;
                tlsio_config.port = 443;
                tlsio_config.underlying_io_interface =  http_proxy_io_get_interface_description();
                tlsio_config.underlying_io_parameters = &proxy_config;
                tlsio_config.invoke_on_send_complete_callback_for_fragments = true;

                http_instance->xio_handle = xio_create(platform_get_default_tlsio(), (void*)&tlsio_config);

                if (http_instance->xio_handle == NULL)
                {
                    LogError("Failed to create xio handle with proxy configuration");
                    result = HTTPAPI_ERROR;
                }
                else
                {
                    if (OptionHandler_FeedOptions(xio_options, http_instance->xio_handle) != OPTIONHANDLER_OK)
                    {
                        LogError("Failed feeding existing options to new xio instance.");
                        result = HTTPAPI_ERROR;
                    }
                    else
                    {
                        result = HTTPAPI_OK;
                    }
                }

                OptionHandler_Destroy(xio_options);
            }
        }
    }
    else if (strcmp(OPTION_SET_TLS_RENEGOTIATION, optionName) == 0)
    {
        bool tls_renegotiation = *(bool*)value;
        http_instance->tls_renegotiation = tls_renegotiation;
        result = HTTPAPI_OK;
    }
    else
    {
        /*Codes_SRS_HTTPAPI_COMPACT_21_063: [ If the HTTP do not support the optionName, the HTTPAPI_SetOption shall return HTTPAPI_INVALID_ARG. ]*/
        result = HTTPAPI_INVALID_ARG;
        LogInfo("unknown option %s", optionName);
    }

    return result;
}