21 #if (1 == HAVE_OPENSSL_SSL_H_) 22 #include <openssl/ssl.h> 23 #include <openssl/err.h> 26 #define CARRIAGE_RETURN '\r' 27 #define LINE_FEED '\n' 28 #define DOMAIN_SEPERATOR '\\' 30 #define SUPPORTED_CIPHERS_LIST \ 31 "AES128-SHA256:AES256-SHA256:AES128-GCM-SHA256:AES256-GCM-SHA384:"\ 32 "ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:" 54 DEBUG_ENTRY(
"configuration_t *configuration = <%p>, http_client_t *http_client = <%p>", configuration, http_client)
70 (*http_client)->curl = curl_easy_init();
72 MCL_DEBUG(
"Libcurl easy interface is initialized.");
75 curl = (*http_client)->curl;
89 curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2);
92 curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2);
93 curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1);
98 #if MCL_LOG_UTIL_LEVEL < LOG_UTIL_LEVEL_INFO 101 curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
106 curl_easy_setopt(curl, CURLOPT_HEADER, 0);
115 curl_easy_setopt(curl, CURLOPT_HEADEROPT, CURLHEADER_UNIFIED);
118 curl_easy_setopt(curl, CURLOPT_FORBID_REUSE, 1);
124 curl_easy_setopt(curl, CURLOPT_PROXYPORT, configuration->
proxy_port);
125 curl_easy_setopt(curl, CURLOPT_PROXYTYPE, configuration->
proxy_type);
136 "Memory can not be allocated for the concatenated string which contains domain and username.");
140 curl_easy_setopt(curl, CURLOPT_PROXYUSERNAME, proxy_username->
buffer);
158 DEBUG_ENTRY(
"http_client_t *http_client = <%p>, http_request_t *http_request = <%p>, http_client_send_callback_info_t *callback_info = <%p>, http_response_t **http_response = <%p>",
159 http_client, http_request, callback_info, http_response)
162 struct curl_slist *request_header_list;
174 "String array for http response header can not be initialized.");
177 curl_easy_setopt(http_client->
curl, CURLOPT_HEADERDATA, response_header);
182 response_payload->
size = 0;
183 curl_easy_setopt(http_client->
curl, CURLOPT_WRITEDATA, response_payload);
186 MCL_INFO(
"Sending HTTP request...");
188 curl_code = curl_easy_perform(http_client->
curl);
190 MCL_INFO(
"HTTP request sent. Result code = <%u>", return_code);
193 curl_slist_free_all(request_header_list);
195 if (
MCL_OK != return_code)
200 MCL_ERROR_RETURN(return_code,
"curl_easy_perform() failed: %s", curl_easy_strerror(curl_code));
204 curl_easy_getinfo(http_client->
curl, CURLINFO_RESPONSE_CODE, &response_code);
207 if (
MCL_OK != return_code)
224 mcl_size_t termination_code = CURL_READFUNC_ABORT;
227 return termination_code;
232 DEBUG_ENTRY(
"http_client_t **http_client = <%p>", http_client)
236 curl_easy_cleanup((*http_client)->curl);
239 MCL_DEBUG(
"Http client handle is destroyed.");
243 MCL_DEBUG(
"Http client is already null.");
252 DEBUG_ENTRY(
"CURL *curl = <%p>, void *ssl_context = <%p>, void *certificate = <%p>", curl, ssl_context, certificate)
257 struct stack_st_X509_INFO *certificate_info;
265 MCL_INFO(
"No certificate is provided by the user for peer verification. Continuing with the existing CA certificate store.");
269 certificate_local = (
string_t *)certificate;
272 store = SSL_CTX_get_cert_store((SSL_CTX *)ssl_context);
275 bio = BIO_new_mem_buf(certificate_local->
buffer, (
int)certificate_local->
length);
285 for (index = 0; index < sk_X509_INFO_num(certificate_info); index++)
287 X509_INFO *temp_info = sk_X509_INFO_value(certificate_info, (
int)index);
290 if (!X509_STORE_add_cert(store, temp_info->x509))
294 unsigned long error = ERR_peek_last_error();
296 if(ERR_GET_LIB(error) != ERR_LIB_X509 || ERR_GET_REASON(error) != X509_R_CERT_ALREADY_IN_HASH_TABLE)
298 MCL_ERROR_RETURN(CURLE_SSL_CERTPROBLEM,
"Certificate can not be added to store.");
302 MCL_INFO(
"Did not add the certificate to store since it is already in the store.");
306 else if (temp_info->crl)
308 ASSERT_CODE_MESSAGE(0 != X509_STORE_add_crl(store, temp_info->crl), CURLE_SSL_CERTPROBLEM,
"Certificate can not be added to store.");
313 sk_X509_INFO_pop_free(certificate_info, X509_INFO_free);
324 DEBUG_ENTRY(
"void *received_data = <%p>, mcl_size_t size = <%u>, mcl_size_t count = <%u>, void *response_payload = <%p>", received_data, size, count, response_payload)
343 payload->
size += received_data_size;
346 return received_data_size;
354 DEBUG_ENTRY(
"void *received_data = <%p>, mcl_size_t size = <%u>, mcl_size_t count = <%u>, void *response_header = <%p>", received_data, size, count, response_header)
365 return received_data_size;
371 MCL_ERROR(
"MCL string can not be initialized for the response header line.");
379 MCL_ERROR(
"MCL string of response header line can not be added to string array of response header.");
385 return received_data_size;
392 DEBUG_ENTRY(
"char *buffer = <%s>, mcl_size_t size = <%u>, mcl_size_t count = <%u>, void *http_request = <%p>", buffer, size, count, http_request)
398 mcl_size_t payload_size = (buffer_size > remaining_size) ? remaining_size : buffer_size;
401 if (payload_size == 0)
403 MCL_DEBUG(
"Remaining payload size is zero. Nothing will be copied.");
429 DEBUG_ENTRY(
"CURL *curl = <%p>, http_request_t *http_request = <%p>, http_client_send_callback_info_t *callback_info = <%p>", curl, http_request, callback_info)
431 struct curl_slist *request_header_list =
MCL_NULL;
437 curl_easy_setopt(curl, CURLOPT_URL, http_request->
uri->
buffer);
440 curl_easy_setopt(curl, CURLOPT_HTTPGET, 0);
441 curl_easy_setopt(curl, CURLOPT_POST, 0);
442 curl_easy_setopt(curl, CURLOPT_UPLOAD, 0);
444 curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, -1);
445 curl_easy_setopt(curl, CURLOPT_INFILESIZE, -1);
446 curl_easy_setopt(curl, CURLOPT_READDATA,
MCL_NULL);
447 curl_easy_setopt(curl, CURLOPT_POSTFIELDS,
MCL_NULL);
449 switch (http_request->
method)
452 curl_easy_setopt(curl, CURLOPT_HTTPGET, 1);
457 curl_easy_setopt(curl, CURLOPT_POST, 1);
463 curl_easy_setopt(curl, CURLOPT_POSTFIELDS, (
void *)http_request->
payload);
466 curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, http_request->
payload_size);
471 curl_easy_setopt(curl, CURLOPT_READFUNCTION, callback_info->
read_callback);
472 curl_easy_setopt(curl, CURLOPT_READDATA, callback_info->
user_context);
483 curl_easy_setopt(curl, CURLOPT_UPLOAD, 1);
485 curl_easy_setopt(curl, CURLOPT_READDATA, http_request);
486 curl_easy_setopt(curl, CURLOPT_INFILESIZE, http_request->
payload_size);
499 for (index = 0; index < http_request->
header->
index; index++)
502 request_header_list = curl_slist_append(request_header_list, request_header_line->
buffer);
506 request_header_list = curl_slist_append(request_header_list,
"Expect:");
509 curl_easy_setopt(curl, CURLOPT_HEADEROPT, CURLHEADER_SEPARATE);
510 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, request_header_list);
511 curl_easy_setopt(curl, CURLOPT_PROXYHEADER,
MCL_NULL);
514 return request_header_list;
517 #if MCL_LOG_UTIL_LEVEL < LOG_UTIL_LEVEL_INFO 527 case CURLINFO_HEADER_OUT :
528 text =
"=> Send header";
531 case CURLINFO_DATA_OUT :
532 text =
"=> Send data";
535 case CURLINFO_SSL_DATA_OUT :
536 text =
"=> Send SSL data";
539 case CURLINFO_HEADER_IN :
540 text =
"<= Recv header";
543 case CURLINFO_DATA_IN :
544 text =
"<= Recv data";
547 case CURLINFO_SSL_DATA_IN :
548 text =
"<= Recv SSL data";
562 DEBUG_ENTRY(
"CURLcode curl_code = <%d>", curl_code)
572 case CURLE_COULDNT_RESOLVE_PROXY :
576 case CURLE_COULDNT_RESOLVE_HOST :
580 case CURLE_COULDNT_CONNECT :
584 case CURLE_OUT_OF_MEMORY :
588 case CURLE_SSL_CONNECT_ERROR :
592 case CURLE_PEER_FAILED_VERIFICATION :
596 case CURLE_SEND_ERROR :
600 case CURLE_RECV_ERROR :
604 case CURLE_SSL_CERTPROBLEM :
608 case CURLE_OPERATION_TIMEDOUT :
mcl_size_t http_client_get_callback_termination_code()
To get the implementation specific code for returning from callback function in order to terminate th...
string_t * proxy_domain
Proxy domain. Optional if proxy_hostname and proxy_username are not used.
void string_destroy(string_t **string)
Destroys the allocated resources of the string.
E_MCL_ERROR_CODE string_array_add(string_array_t *array, string_t *string, mcl_bool_t destroy)
Adds an string_t string object into the array.
static E_MCL_ERROR_CODE _convert_to_mcl_error_code(CURLcode curl_code)
char * string_util_strdup(const char *string)
Standard library strdup wrapper.
Memory module header file.
mcl_uint32_t http_request_timeout
Timeout value (in seconds) for HTTP requests. Default timeout is 300 seconds.
string_array_t * header
Header of http request.
static mcl_size_t _response_payload_callback(void *received_data, mcl_size_t size, mcl_size_t count, void *response_payload)
string_t * proxy_password
Proxy password. Optional if proxy_hostname and proxy_username are not used.
E_MCL_HTTP_METHOD method
Http method of http request.
The server certificate provided is in improper format and it can not be parsed.
mcl_size_t index
Item index.
static mcl_size_t _response_header_callback(void *received_data, mcl_size_t size, mcl_size_t count, void *response_header)
E_MCL_ERROR_CODE string_initialize_new(const char *value, mcl_size_t value_length, string_t **string)
Initializes a new string_t object with the given value and length.
mcl_uint8_t * payload
Payload of http request.
A problem occured when sending data to the network.
char * buffer
Buffer of string handle.
static struct curl_slist * _set_request_options(CURL *curl, http_request_t *http_request, http_client_send_callback_info_t *callback_info)
void string_array_destroy(string_array_t **array)
Destroys the string array handle.
#define MCL_FALSE
MCL bool type.
#define SUPPORTED_CIPHERS_LIST
string_t * string_array_get(string_array_t *array, mcl_size_t index)
To get the string_t string object at a specified index.
#define MCL_MALLOC(bytes)
MCL failed to connect to the host or proxy.
Log utility module header file.
E_MCL_PROXY proxy_type
Proxy type E_MCL_PROXY. Optional if proxy_hostname is not used.
E_MCL_ERROR_CODE
MCL Error code definitions. Every function returning an error code uses this enum values...
static CURLcode _ssl_context_callback(CURL *curl, void *ssl_context, void *certificate)
E_MCL_ERROR_CODE string_util_snprintf(char *string, mcl_size_t length, const char *format,...)
Standard library snprintf wrapper.
#define MCL_RESIZE(p, bytes)
static int _curl_debug_callback(CURL *curl, curl_infotype info_type, char *data, mcl_size_t size, void *debug_data)
void * memory_malloc(mcl_size_t size)
malloc wrapper
HTTP client libcurl module header file.
HTTP Client Handler definition. Members are implementation specific and are declared in implementatio...
#define ASSERT_STATEMENT_CODE_MESSAGE(condition, statement, return_code,...)
mcl_uint16_t proxy_port
Proxy port no. Optional if proxy_hostname is not used.
void string_util_memcpy(void *destination, const void *source, mcl_size_t count)
Standard library memcpy wrapper.
http_client_read_callback read_callback
#define ASSERT_CODE_MESSAGE(condition, return_code,...)
string_t http_header_names[HTTP_HEADER_NAMES_END]
Definitions module header file.
void memory_free(void *p)
free wrapper
mcl_size_t payload_offset
Payload offset of http request.
#define MCL_DEBUG_MEMORY(data, data_size,...)
Proxy host name given as a configuration parameter could not be resolved.
Mindsphere certificate was not verified.
mcl_size_t length
Length of buffer.
Initialization of MCL fails.
string_t * proxy_hostname
Proxy hostname. Optional.
mcl_uint16_t mindsphere_port
Mindsphere port no.
#define SSL_CERTIFICATE_TYPE_PEM
static mcl_bool_t _is_empty_line(char *line)
Http transfer encoding chunked header.
E_MCL_ERROR_CODE string_array_initialize(mcl_size_t count, string_array_t **array)
String array initialize method.
Host name given as a configuration parameter could not be resolved.
E_MCL_ERROR_CODE http_client_send(http_client_t *http_client, http_request_t *http_request, http_client_send_callback_info_t *callback_info, http_response_t **http_response)
Send/Receive function.
A problem occured during SSL/TLS handshake.
E_MCL_HTTP_RESULT_CODE
HTTP Result Codes.
The server did not respond within a timeout period.
void http_client_destroy(http_client_t **http_client)
To destroy the HTTP Client Handler.
E_MCL_ERROR_CODE http_client_initialize(configuration_t *configuration, http_client_t **http_client)
HTTP Client initializer.
A problem occured when receiving data from the network.
static mcl_size_t _request_payload_callback_for_put(char *buffer, mcl_size_t size, mcl_size_t count, void *http_request)
string_t * proxy_username
Proxy username. Optional if proxy_hostname is not used.
void * memory_calloc(mcl_size_t count, mcl_size_t bytes)
calloc wrapper
static mcl_bool_t curl_global_initialized
mcl_size_t payload_size
Payload size of http request.
void * memory_realloc(void *p, mcl_size_t bytes)
realloc wrapper
string_t * mindsphere_certificate
Mindsphere certificate. Optional. If NULL, MCL will use default CA certificate store (if provided at ...
string_t * uri
Uri of http request.
E_MCL_ERROR_CODE http_response_initialize(string_array_t *header, mcl_uint8_t *payload, mcl_size_t payload_size, E_MCL_HTTP_RESULT_CODE result_code, http_response_t **http_response)
HTTP Response Module Initialize function.
#define MCL_ERROR_RETURN(return_value,...)