http_client_libcurl.c
Go to the documentation of this file.
1 /*!**********************************************************************
2  *
3  * @copyright Copyright (C) 2016 Siemens Aktiengesellschaft.\n
4  * All rights reserved.
5  *
6  *************************************************************************
7  *
8  * @file http_client_libcurl.c
9  * @date Jul 20, 2016
10  * @brief HTTP client libcurl implementation file.
11  *
12  * HTTP client implementation file using LibCurl.
13  *
14  ************************************************************************/
15 
16 #include "http_client_libcurl.h"
17 #include "log_util.h"
18 #include "memory.h"
19 #include "definitions.h"
20 
21 #if (1 == HAVE_OPENSSL_SSL_H_)
22 #include <openssl/ssl.h>
23 #include <openssl/err.h>
24 #endif
25 
26 #define CARRIAGE_RETURN '\r'
27 #define LINE_FEED '\n'
28 #define DOMAIN_SEPERATOR '\\'
29 
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:"
33 
34 // Data structure to be passed as an argument to libcurl callback set with CURLOPT_WRITEFUNCTION option.
35 typedef struct libcurl_payload_t
36 {
40 
42 
43 static CURLcode _ssl_context_callback(CURL *curl, void *ssl_context, void *certificate);
44 static mcl_size_t _response_payload_callback(void *received_data, mcl_size_t size, mcl_size_t count, void *response_payload);
45 static mcl_size_t _response_header_callback(void *received_data, mcl_size_t size, mcl_size_t count, void *response_header);
46 static mcl_size_t _request_payload_callback_for_put(char *buffer, mcl_size_t size, mcl_size_t count, void *http_request);
47 static mcl_bool_t _is_empty_line(char *line);
48 static struct curl_slist *_set_request_options(CURL *curl, http_request_t *http_request, http_client_send_callback_info_t *callback_info);
49 static int _curl_debug_callback(CURL *curl, curl_infotype info_type, char *data, mcl_size_t size, void *debug_data);
50 static E_MCL_ERROR_CODE _convert_to_mcl_error_code(CURLcode curl_code);
51 
53 {
54  DEBUG_ENTRY("configuration_t *configuration = <%p>, http_client_t *http_client = <%p>", configuration, http_client)
55 
56  CURL *curl;
57 
58  // Create http client.
59  MCL_NEW(*http_client);
60  ASSERT_CODE_MESSAGE(MCL_NULL != *http_client, MCL_OUT_OF_MEMORY, "Memory can not be allocated for http client.");
61 
62  // Initialize curl memory functions
64  {
66  curl_global_init_mem(CURL_GLOBAL_DEFAULT, memory_malloc, memory_free, memory_realloc, string_util_strdup, memory_calloc);
67  }
68 
69  // Initialize curl object.
70  (*http_client)->curl = curl_easy_init();
71  ASSERT_CODE_MESSAGE(MCL_NULL != (*http_client)->curl, MCL_INITIALIZATION_FAIL, "Libcurl easy interface can not be initialized.");
72  MCL_DEBUG("Libcurl easy interface is initialized.");
73 
74  // Declare a local curl instance for code clarity.
75  curl = (*http_client)->curl;
76 
77  // Set remote port number to work with.
78  curl_easy_setopt(curl, CURLOPT_PORT, configuration->mindsphere_port);
79 
80  // Set timeout values.
81  curl_easy_setopt(curl, CURLOPT_TIMEOUT, (long)configuration->http_request_timeout);
82  curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, (long)configuration->http_request_timeout);
83 
84  // Set server certificate.
85  curl_easy_setopt(curl, CURLOPT_SSLCERTTYPE, SSL_CERTIFICATE_TYPE_PEM);
86  curl_easy_setopt(curl, CURLOPT_SSL_CTX_DATA, configuration->mindsphere_certificate);
87  curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, *_ssl_context_callback);
88  curl_easy_setopt(curl, CURLOPT_SSL_CIPHER_LIST, SUPPORTED_CIPHERS_LIST);
89  curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2);
90 
91  // Verify the server's SSL certificate.
92  curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2);
93  curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1);
94 
95  // enable this if MindSphere supports OCSP
96  // curl_easy_setopt(curl, CURLOPT_SSL_VERIFYSTATUS, 1);
97 
98 #if MCL_LOG_UTIL_LEVEL < LOG_UTIL_LEVEL_INFO
99 
100  // set logging if enabled and level set at least DEBUG
101  curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
102  curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, _curl_debug_callback);
103 #endif
104 
105  // Make sure header of the response is processed by a different callback from its payload.
106  curl_easy_setopt(curl, CURLOPT_HEADER, 0);
107 
108  // Set callback for processing the received header.
109  curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, _response_header_callback);
110 
111  // Set callback for processing the received payload.
112  curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, _response_payload_callback);
113 
114  // The headers specified in CURLOPT_HEADER will be used in requests to both servers and proxies.
115  curl_easy_setopt(curl, CURLOPT_HEADEROPT, CURLHEADER_UNIFIED);
116 
117  // Close the connection when done with the transfer.
118  curl_easy_setopt(curl, CURLOPT_FORBID_REUSE, 1);
119 
120  // Set proxy options if proxy is used.
121  if (MCL_NULL != configuration->proxy_hostname)
122  {
123  curl_easy_setopt(curl, CURLOPT_PROXY, configuration->proxy_hostname->buffer);
124  curl_easy_setopt(curl, CURLOPT_PROXYPORT, configuration->proxy_port);
125  curl_easy_setopt(curl, CURLOPT_PROXYTYPE, configuration->proxy_type);
126 
127  if (MCL_NULL != configuration->proxy_username)
128  {
129  if (MCL_NULL != configuration->proxy_domain)
130  {
131  E_MCL_ERROR_CODE code;
132  string_t *proxy_username;
133  mcl_size_t proxy_username_length = configuration->proxy_domain->length + configuration->proxy_username->length + 1;
134  code = string_initialize_new(MCL_NULL, proxy_username_length, &proxy_username);
136  "Memory can not be allocated for the concatenated string which contains domain and username.");
137 
138  code = string_util_snprintf(proxy_username->buffer, proxy_username_length + 1, "%s%c%s", configuration->proxy_domain->buffer, DOMAIN_SEPERATOR,
139  configuration->proxy_username->buffer);
140  curl_easy_setopt(curl, CURLOPT_PROXYUSERNAME, proxy_username->buffer);
141  string_destroy(&proxy_username);
142  ASSERT_CODE_MESSAGE(code == MCL_OK, code, "Domain and username strings could not be concatenated.");
143  }
144  else
145  {
146  curl_easy_setopt(curl, CURLOPT_PROXYUSERNAME, configuration->proxy_username->buffer);
147  }
148  curl_easy_setopt(curl, CURLOPT_PROXYPASSWORD, configuration->proxy_password->buffer);
149  }
150  }
151 
152  DEBUG_LEAVE("retVal = <%d>", MCL_OK);
153  return MCL_OK;
154 }
155 
157 {
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)
160 
161  E_MCL_ERROR_CODE return_code;
162  struct curl_slist *request_header_list;
163  string_array_t *response_header = MCL_NULL;
164  libcurl_payload_t *response_payload;
165  CURLcode curl_code;
166  mcl_int64_t response_code;
167 
168  // Set request options. If there are no request headers, this function returns null but the other options for the request are set anyway.
169  request_header_list = _set_request_options(http_client->curl, http_request, callback_info);
170 
171  // Initialize a string array to store response header, clear the list of request headers if this initialization fails and return.
172  return_code = string_array_initialize(10, &response_header);
173  ASSERT_STATEMENT_CODE_MESSAGE(return_code == MCL_OK, curl_slist_free_all(request_header_list), return_code,
174  "String array for http response header can not be initialized.");
175 
176  // Set pointer passed to the _response_header_callback function as fourth argument.
177  curl_easy_setopt(http_client->curl, CURLOPT_HEADERDATA, response_header);
178 
179  // Set pointer passed to the _response_callback function as fourth argument.
180  MCL_NEW(response_payload);
181  response_payload->data = MCL_NULL;
182  response_payload->size = 0;
183  curl_easy_setopt(http_client->curl, CURLOPT_WRITEDATA, response_payload);
184 
185  // Perform the transfer.
186  MCL_INFO("Sending HTTP request...");
187 
188  curl_code = curl_easy_perform(http_client->curl);
189  return_code = _convert_to_mcl_error_code(curl_code);
190  MCL_INFO("HTTP request sent. Result code = <%u>", return_code);
191 
192  // Free the list of http request header.
193  curl_slist_free_all(request_header_list);
194 
195  if (MCL_OK != return_code)
196  {
197  string_array_destroy(&response_header);
198  MCL_FREE(response_payload->data);
199  MCL_FREE(response_payload);
200  MCL_ERROR_RETURN(return_code, "curl_easy_perform() failed: %s", curl_easy_strerror(curl_code));
201  }
202 
203  // Gather response into http_response object.
204  curl_easy_getinfo(http_client->curl, CURLINFO_RESPONSE_CODE, &response_code);
205 
206  return_code = http_response_initialize(response_header, response_payload->data, response_payload->size, (E_MCL_HTTP_RESULT_CODE)response_code, http_response);
207  if (MCL_OK != return_code)
208  {
209  string_array_destroy(&response_header);
210  MCL_FREE(response_payload->data);
211  MCL_FREE(response_payload);
212  MCL_ERROR_RETURN(return_code, "Http response can not be initialized.");
213  }
214  MCL_FREE(response_payload);
215 
216  DEBUG_LEAVE("retVal = <%d>", MCL_OK);
217  return MCL_OK;
218 }
219 
221 {
222  DEBUG_ENTRY("void")
223 
224  mcl_size_t termination_code = CURL_READFUNC_ABORT;
225 
226  DEBUG_LEAVE("retVal = <%u>", termination_code);
227  return termination_code;
228 }
229 
231 {
232  DEBUG_ENTRY("http_client_t **http_client = <%p>", http_client)
233 
234  if (MCL_NULL != *http_client)
235  {
236  curl_easy_cleanup((*http_client)->curl);
237  MCL_FREE(*http_client);
238 
239  MCL_DEBUG("Http client handle is destroyed.");
240  }
241  else
242  {
243  MCL_DEBUG("Http client is already null.");
244  }
245 
246  DEBUG_LEAVE("retVal = void");
247 }
248 
249 // This function is the callback which is called to set the SSL certificate given by the parameter "certificate".
250 static CURLcode _ssl_context_callback(CURL *curl, void *ssl_context, void *certificate)
251 {
252  DEBUG_ENTRY("CURL *curl = <%p>, void *ssl_context = <%p>, void *certificate = <%p>", curl, ssl_context, certificate)
253 
254  string_t *certificate_local;
255  X509_STORE *store;
256  BIO *bio;
257  struct stack_st_X509_INFO *certificate_info;
258  mcl_size_t index;
259 
260  // Unused parameter.
261  (void)curl;
262 
263  if (MCL_NULL == certificate)
264  {
265  MCL_INFO("No certificate is provided by the user for peer verification. Continuing with the existing CA certificate store.");
266  return CURLE_OK;
267  }
268 
269  certificate_local = (string_t *)certificate;
270 
271  // Get a pointer to the X509 certificate store (which may be empty!).
272  store = SSL_CTX_get_cert_store((SSL_CTX *)ssl_context);
273 
274  // Get BIO.
275  bio = BIO_new_mem_buf(certificate_local->buffer, (int)certificate_local->length);
276  ASSERT_CODE_MESSAGE(MCL_NULL != bio, CURLE_OUT_OF_MEMORY, "Memory for BIO could not be allocated!");
277 
278  // Read certificate info
279  certificate_info = PEM_X509_INFO_read_bio(bio, MCL_NULL, MCL_NULL, MCL_NULL);
280 
281  BIO_free(bio);
282  ASSERT_CODE_MESSAGE(MCL_NULL != certificate_info, CURLE_SSL_CERTPROBLEM, "Certificate info can not be read from memory");
283 
284  // Read all PEM formatted certificates from memory into an X509 structure that SSL can use.
285  for (index = 0; index < sk_X509_INFO_num(certificate_info); index++)
286  {
287  X509_INFO *temp_info = sk_X509_INFO_value(certificate_info, (int)index);
288  if (temp_info->x509)
289  {
290  if (!X509_STORE_add_cert(store, temp_info->x509))
291  {
292  // Ignore error X509_R_CERT_ALREADY_IN_HASH_TABLE which means the certificate is already in the store.
293  // That could happen if libcurl already loaded the certificate from a ca cert bundle set at libcurl build-time or runtime.
294  unsigned long error = ERR_peek_last_error();
295 
296  if(ERR_GET_LIB(error) != ERR_LIB_X509 || ERR_GET_REASON(error) != X509_R_CERT_ALREADY_IN_HASH_TABLE)
297  {
298  MCL_ERROR_RETURN(CURLE_SSL_CERTPROBLEM, "Certificate can not be added to store.");
299  }
300  else
301  {
302  MCL_INFO("Did not add the certificate to store since it is already in the store.");
303  }
304  }
305  }
306  else if (temp_info->crl)
307  {
308  ASSERT_CODE_MESSAGE(0 != X509_STORE_add_crl(store, temp_info->crl), CURLE_SSL_CERTPROBLEM, "Certificate can not be added to store.");
309  }
310  }
311 
312  // Clean up.
313  sk_X509_INFO_pop_free(certificate_info, X509_INFO_free);
314 
315  DEBUG_LEAVE("retVal = <%d>", CURLE_OK);
316  return CURLE_OK;
317 }
318 
319 // This function is the callback which is called once for the payload of the received response.
320 // The function initializes an string_t from the received data in the buffer "received_data"
321 // composed of "count" elements of each "size" bytes long and copies this string to the string array "response_payload".
322 static mcl_size_t _response_payload_callback(void *received_data, mcl_size_t size, mcl_size_t count, void *response_payload)
323 {
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)
325 
326  mcl_size_t received_data_size = size * count;
327  libcurl_payload_t *payload = (libcurl_payload_t *)response_payload;
328 
329  // ASSERT_CODE_MESSAGE(MCL_NULL == payload->data, 0, "Payload data was already allocated!");
330  if (payload->data)
331  {
332  MCL_RESIZE(payload->data, payload->size + received_data_size);
333  ASSERT_CODE_MESSAGE(MCL_NULL != payload->data, 0, "Memory re-allocation for payload data failed!");
334  }
335  else
336  {
337  payload->data = MCL_MALLOC(received_data_size);
338  ASSERT_CODE_MESSAGE(MCL_NULL != payload->data, 0, "Memory allocation for payload data failed!");
339  }
340 
341  string_util_memcpy(payload->data + payload->size, received_data, received_data_size);
342 
343  payload->size += received_data_size;
344 
345  DEBUG_LEAVE("retVal = <%d>", received_data_size);
346  return received_data_size;
347 }
348 
349 // This function is the callback which is called once for every header line of the received http response.
350 // The function initializes a string_t from the received data in the buffer "received_data"
351 // composed of "count" elements of each "size" bytes long and copies this string to the string array "response_header".
352 static mcl_size_t _response_header_callback(void *received_data, mcl_size_t size, mcl_size_t count, void *response_header)
353 {
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)
355 
356  string_array_t *header_array = (string_array_t *)response_header;
357 
358  string_t *header_line = MCL_NULL;
359  mcl_size_t received_data_size = size * count;
360 
361  // Eliminate empty line
362  if ((2 == received_data_size) && (MCL_TRUE == _is_empty_line((char *)received_data)))
363  {
364  DEBUG_LEAVE("retVal = <%d>", received_data_size);
365  return received_data_size;
366  }
367 
368  // Create an mcl string for the received header line (CRLF excluded).
369  if (MCL_OK != string_initialize_new(received_data, received_data_size - 2, &header_line))
370  {
371  MCL_ERROR("MCL string can not be initialized for the response header line.");
372  return 0;
373  }
374 
375  // Add header line to header array, destroy header line if the add operation is unsuccessful.
376  if (MCL_OK != string_array_add(header_array, header_line, MCL_TRUE))
377  {
378  string_destroy(&header_line);
379  MCL_ERROR("MCL string of response header line can not be added to string array of response header.");
380  DEBUG_LEAVE("retVal = <0>");
381  return 0;
382  }
383 
384  DEBUG_LEAVE("retVal = <%d>", received_data_size);
385  return received_data_size;
386 }
387 
388 // This function is the callback which is called when HTTP PUT is requested.
389 // The function takes in parameter "http_request" of type http_request_t and copies its payload to "buffer".
390 static mcl_size_t _request_payload_callback_for_put(char *buffer, mcl_size_t size, mcl_size_t count, void *http_request)
391 {
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)
393 
394  http_request_t *request = (http_request_t *)http_request;
395 
396  mcl_size_t buffer_size = size * count;
397  mcl_size_t remaining_size = request->payload_size - request->payload_offset;
398  mcl_size_t payload_size = (buffer_size > remaining_size) ? remaining_size : buffer_size;
399 
400  // TODO Maximum size check. Shall we check it where we set it CURLOPT_INFILESIZE option or here.
401  if (payload_size == 0)
402  {
403  MCL_DEBUG("Remaining payload size is zero. Nothing will be copied.");
404  }
405  else
406  {
407  string_util_memcpy(buffer, request->payload + request->payload_offset, payload_size);
408  }
409  request->payload_offset += payload_size;
410 
411  DEBUG_LEAVE("retVal = <%u>", payload_size);
412  return payload_size;
413 }
414 
415 // This function checks if the given line is an empty line or not.
416 static mcl_bool_t _is_empty_line(char *line)
417 {
418  DEBUG_ENTRY("char *line = <%s>", line)
419 
420  mcl_bool_t is_empty = (CARRIAGE_RETURN == line[0]) && (LINE_FEED == line[1]) ? MCL_TRUE : MCL_FALSE;
421 
422  DEBUG_LEAVE("retVal = <%d>", is_empty);
423  return is_empty;
424 }
425 
426 // This function sets the options for the http request and returns the curl list of request headers.
427 static struct curl_slist *_set_request_options(CURL *curl, http_request_t *http_request, http_client_send_callback_info_t *callback_info)
428 {
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)
430 
431  struct curl_slist *request_header_list = MCL_NULL;
432  string_t *request_header_line = MCL_NULL;
433  mcl_size_t index;
434 
435  // Set the URL to use in the request.
436  // Reminder: Request URI is an absolute path including the host name.
437  curl_easy_setopt(curl, CURLOPT_URL, http_request->uri->buffer);
438 
439  // Set http method and data for post and put methods.
440  curl_easy_setopt(curl, CURLOPT_HTTPGET, 0);
441  curl_easy_setopt(curl, CURLOPT_POST, 0);
442  curl_easy_setopt(curl, CURLOPT_UPLOAD, 0);
443 
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);
448 
449  switch (http_request->method)
450  {
451  case MCL_HTTP_GET :
452  curl_easy_setopt(curl, CURLOPT_HTTPGET, 1);
453 
454  break;
455 
456  case MCL_HTTP_POST :
457  curl_easy_setopt(curl, CURLOPT_POST, 1);
458 
459  // If a callback function is present, use Transfer-Encoding : chunked:
460  if (MCL_NULL == callback_info)
461  {
462  // Normal http transfer without chunked encoding
463  curl_easy_setopt(curl, CURLOPT_POSTFIELDS, (void *)http_request->payload);
464 
465  // if post field size is not set, you have to use transfer-encoding:chunked otherwise no data will be send.
466  curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, http_request->payload_size);
467  }
468  else
469  {
470  // Transfer-Encoding : chunked
471  curl_easy_setopt(curl, CURLOPT_READFUNCTION, callback_info->read_callback);
472  curl_easy_setopt(curl, CURLOPT_READDATA, callback_info->user_context);
473  request_header_list = curl_slist_append(request_header_list, http_header_names[HTTP_HEADER_TRANSFER_ENCODING_CHUNKED].buffer);
474  }
475 
476  break;
477 
478  case MCL_HTTP_PUT :
479 
480  // set payload_offset to 0 to indicate for read callback what part of the payload is already written to libcurl
481  http_request->payload_offset = 0;
482 
483  curl_easy_setopt(curl, CURLOPT_UPLOAD, 1);
484  curl_easy_setopt(curl, CURLOPT_READFUNCTION, _request_payload_callback_for_put);
485  curl_easy_setopt(curl, CURLOPT_READDATA, http_request);
486  curl_easy_setopt(curl, CURLOPT_INFILESIZE, http_request->payload_size);
487 
488  // TODO Use CURLOPT_INFILESIZE_LARGE for data larger than 2GB. Shall we check it here?
489 
490  break;
491 
492  default :
493  MCL_ERROR_RETURN(MCL_NULL, "Unsupported HTTP method is requested.");
494 
495  break;
496  }
497 
498  // Set request header.
499  for (index = 0; index < http_request->header->index; index++)
500  {
501  request_header_line = string_array_get(http_request->header, index);
502  request_header_list = curl_slist_append(request_header_list, request_header_line->buffer);
503  }
504 
505  // Add expect header to prevent that libcurl adds it automatically (HTTP continue bug)
506  request_header_list = curl_slist_append(request_header_list, "Expect:");
507 
508  // Separate HTTP headers for MindSphere and Proxy
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);
512 
513  DEBUG_LEAVE("retVal = <%p>", request_header_list);
514  return request_header_list;
515 }
516 
517 #if MCL_LOG_UTIL_LEVEL < LOG_UTIL_LEVEL_INFO
518 static int _curl_debug_callback(CURL *curl, curl_infotype info_type, char *data, mcl_size_t size, void *debug_data)
519 {
520  const char *text;
521 
522  switch (info_type)
523  {
524  case CURLINFO_TEXT :
525  MCL_DEBUG("== Info: %s", data);
526  return CURLE_OK;
527  case CURLINFO_HEADER_OUT :
528  text = "=> Send header";
529 
530  break;
531  case CURLINFO_DATA_OUT :
532  text = "=> Send data";
533 
534  break;
535  case CURLINFO_SSL_DATA_OUT :
536  text = "=> Send SSL data";
537 
538  break;
539  case CURLINFO_HEADER_IN :
540  text = "<= Recv header";
541 
542  break;
543  case CURLINFO_DATA_IN :
544  text = "<= Recv data";
545 
546  break;
547  case CURLINFO_SSL_DATA_IN :
548  text = "<= Recv SSL data";
549 
550  break;
551  default :
552  return CURLE_OK;
553  }
554 
555  MCL_DEBUG_MEMORY(data, (const unsigned int)size, "%s, %10.10d bytes (0x%8.8X)\n", text, size, size);
556  return CURLE_OK;
557 }
558 #endif
559 
561 {
562  DEBUG_ENTRY("CURLcode curl_code = <%d>", curl_code)
563 
564  E_MCL_ERROR_CODE mcl_code;
565 
566  switch (curl_code)
567  {
568  case CURLE_OK :
569  mcl_code = MCL_OK;
570 
571  break;
572  case CURLE_COULDNT_RESOLVE_PROXY :
573  mcl_code = MCL_COULD_NOT_RESOLVE_PROXY;
574 
575  break;
576  case CURLE_COULDNT_RESOLVE_HOST :
577  mcl_code = MCL_COULD_NOT_RESOLVE_HOST;
578 
579  break;
580  case CURLE_COULDNT_CONNECT :
581  mcl_code = MCL_COULD_NOT_CONNECT;
582 
583  break;
584  case CURLE_OUT_OF_MEMORY :
585  mcl_code = MCL_OUT_OF_MEMORY;
586 
587  break;
588  case CURLE_SSL_CONNECT_ERROR :
589  mcl_code = MCL_SSL_HANDSHAKE_FAIL;
590 
591  break;
592  case CURLE_PEER_FAILED_VERIFICATION :
594 
595  break;
596  case CURLE_SEND_ERROR :
597  mcl_code = MCL_NETWORK_SEND_FAIL;
598 
599  break;
600  case CURLE_RECV_ERROR :
601  mcl_code = MCL_NETWORK_RECEIVE_FAIL;
602 
603  break;
604  case CURLE_SSL_CERTPROBLEM :
605  mcl_code = MCL_IMPROPER_CERTIFICATE;
606 
607  break;
608  case CURLE_OPERATION_TIMEDOUT :
609  mcl_code = MCL_REQUEST_TIMEOUT;
610 
611  break;
612  default :
613  mcl_code = MCL_FAIL;
614 
615  break;
616  }
617 
618  DEBUG_LEAVE("retVal = <%d>", mcl_code);
619  return mcl_code;
620 }
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...
HTTP Request Handle.
Definition: http_request.h:79
string_t * proxy_domain
Proxy domain. Optional if proxy_hostname and proxy_username are not used.
Definition: configuration.h:34
void string_destroy(string_t **string)
Destroys the allocated resources of the string.
Definition: string_type.c:326
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.
Definition: string_array.c:70
static E_MCL_ERROR_CODE _convert_to_mcl_error_code(CURLcode curl_code)
Internal failure in MCL.
Definition: mcl_common.h:141
char * string_util_strdup(const char *string)
Standard library strdup wrapper.
Definition: string_util.c:140
Memory module header file.
int64_t mcl_int64_t
Definition: mcl_common.h:42
mcl_uint32_t http_request_timeout
Timeout value (in seconds) for HTTP requests. Default timeout is 300 seconds.
Definition: configuration.h:37
string_array_t * header
Header of http request.
Definition: http_request.h:81
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.
Definition: configuration.h:33
#define DEBUG_LEAVE(...)
Definition: log_util.h:81
E_MCL_HTTP_METHOD method
Http method of http request.
Definition: http_request.h:85
The server certificate provided is in improper format and it can not be parsed.
Definition: mcl_common.h:179
#define DEBUG_ENTRY(...)
Definition: log_util.h:80
Http put method.
Definition: http_request.h:67
mcl_size_t index
Item index.
Definition: string_array.h:47
static mcl_size_t _response_header_callback(void *received_data, mcl_size_t size, mcl_size_t count, void *response_header)
#define MCL_NEW(p)
Definition: memory.h:121
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.
Definition: string_type.c:46
mcl_uint8_t * payload
Payload of http request.
Definition: http_request.h:82
A problem occured when sending data to the network.
Definition: mcl_common.h:176
#define MCL_TRUE
Definition: mcl_common.h:54
char * buffer
Buffer of string handle.
Definition: string_type.h:45
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.
Definition: string_array.c:174
#define MCL_DEBUG(...)
Definition: log_util.h:70
#define MCL_FALSE
MCL bool type.
Definition: mcl_common.h:53
#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.
Definition: string_array.c:114
#define MCL_MALLOC(bytes)
Definition: memory.h:120
MCL failed to connect to the host or proxy.
Definition: mcl_common.h:174
Log utility module header file.
E_MCL_PROXY proxy_type
Proxy type E_MCL_PROXY. Optional if proxy_hostname is not used.
Definition: configuration.h:31
E_MCL_ERROR_CODE
MCL Error code definitions. Every function returning an error code uses this enum values...
Definition: mcl_common.h:137
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.
Definition: string_util.c:95
CURL * curl
Curl handle.
#define MCL_RESIZE(p, bytes)
Definition: memory.h:124
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
Definition: memory.c:99
HTTP client libcurl module header file.
#define MCL_FREE(p)
Definition: memory.h:125
HTTP Client Handler definition. Members are implementation specific and are declared in implementatio...
#define ASSERT_STATEMENT_CODE_MESSAGE(condition, statement, return_code,...)
Definition: definitions.h:121
mcl_uint16_t proxy_port
Proxy port no. Optional if proxy_hostname is not used.
Definition: configuration.h:30
uint8_t mcl_uint8_t
Definition: mcl_common.h:43
Http post method.
Definition: http_request.h:66
void string_util_memcpy(void *destination, const void *source, mcl_size_t count)
Standard library memcpy wrapper.
Definition: string_util.c:131
http_client_read_callback read_callback
Definition: http_client.h:30
#define ASSERT_CODE_MESSAGE(condition, return_code,...)
Definition: definitions.h:105
string_t http_header_names[HTTP_HEADER_NAMES_END]
Definitions module header file.
void memory_free(void *p)
free wrapper
Definition: memory.c:129
mcl_size_t payload_offset
Payload offset of http request.
Definition: http_request.h:84
#define MCL_DEBUG_MEMORY(data, data_size,...)
Definition: log_util.h:72
Proxy host name given as a configuration parameter could not be resolved.
Definition: mcl_common.h:172
Http get method.
Definition: http_request.h:64
Mindsphere certificate was not verified.
Definition: mcl_common.h:178
#define LINE_FEED
mcl_size_t length
Length of buffer.
Definition: string_type.h:46
Initialization of MCL fails.
Definition: mcl_common.h:204
string_t * proxy_hostname
Proxy hostname. Optional.
Definition: configuration.h:29
mcl_uint16_t mindsphere_port
Mindsphere port no.
Definition: configuration.h:27
#define SSL_CERTIFICATE_TYPE_PEM
Definition: http_client.h:24
#define DOMAIN_SEPERATOR
static mcl_bool_t _is_empty_line(char *line)
size_t mcl_size_t
Definition: mcl_common.h:38
Http transfer encoding chunked header.
mcl_uint8_t mcl_bool_t
Definition: mcl_common.h:47
Success.
Definition: mcl_common.h:140
E_MCL_ERROR_CODE string_array_initialize(mcl_size_t count, string_array_t **array)
String array initialize method.
Definition: string_array.c:19
Host name given as a configuration parameter could not be resolved.
Definition: mcl_common.h:173
#define MCL_ERROR(...)
Definition: log_util.h:97
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.
Definition: mcl_common.h:175
#define CARRIAGE_RETURN
E_MCL_HTTP_RESULT_CODE
HTTP Result Codes.
Definition: http_response.h:26
#define MCL_INFO(...)
Definition: log_util.h:87
The server did not respond within a timeout period.
Definition: mcl_common.h:180
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.
HTTP Response Handle.
Definition: http_response.h:64
Memory allocation fail.
Definition: mcl_common.h:143
#define MCL_NULL
Definition: definitions.h:24
A problem occured when receiving data from the network.
Definition: mcl_common.h:177
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.
Definition: configuration.h:32
void * memory_calloc(mcl_size_t count, mcl_size_t bytes)
calloc wrapper
Definition: memory.c:109
static mcl_bool_t curl_global_initialized
mcl_size_t payload_size
Payload size of http request.
Definition: http_request.h:83
void * memory_realloc(void *p, mcl_size_t bytes)
realloc wrapper
Definition: memory.c:119
string_t * mindsphere_certificate
Mindsphere certificate. Optional. If NULL, MCL will use default CA certificate store (if provided at ...
Definition: configuration.h:28
string_t * uri
Uri of http request.
Definition: http_request.h:86
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.
Definition: http_response.c:19
#define MCL_ERROR_RETURN(return_value,...)
Definition: definitions.h:69