http_client_basic.c
Go to the documentation of this file.
1 
9 #include "mcl_core/mcl_memory.h"
10 #include "mcl_core/mcl_list.h"
12 #include "http_client_basic.h"
13 #include <stdio.h>
14 
15 static const char crlf[] = "\r\n";
16 static const char https_prefix[] = "https://";
17 
18 static const char get_string[] = "GET ";
19 static const char put_string[] = "PUT ";
20 static const char post_string[] = "POST ";
21 static const char http_string[] = " HTTP/1.1\r\n";
22 
23 static const char content_length_header[] = "Content-Length";
24 static const char transfer_encoding_header[] = "Transfer-Encoding: chunked";
25 
26 #define TLS_DEFAULT_PORT 443
27 #define HTTP_CALLBACK_BUFFER_SIZE 1024
28 #define HTTP_PARSE_BUFFER_SIZE 2048
29 #define SIZE_OF_STRING(x) (sizeof(x) - MCL_NULL_CHAR_SIZE)
30 
31 #define TO_STRING_HELPER(x) (#x)
32 #define TO_STRING(x) TO_STRING_HELPER(x)
33 
34 #define PORT_STRING_BUFFER_SIZE 6
35 #define CRLF_SIZE (sizeof(crlf) - MCL_NULL_CHAR_SIZE)
36 #define HTTPS_PREFIX_SIZE (sizeof(https_prefix) - MCL_NULL_CHAR_SIZE)
37 #define GET_STRING_SIZE (sizeof(get_string) - MCL_NULL_CHAR_SIZE)
38 #define PUT_STRING_SIZE (sizeof(put_string) - MCL_NULL_CHAR_SIZE)
39 #define POST_STRING_SIZE (sizeof(post_string) - MCL_NULL_CHAR_SIZE)
40 #define HTTP_STRING_SIZE (sizeof(http_string) - MCL_NULL_CHAR_SIZE)
41 #define CONTENT_LENGTH_BUFFER_SIZE (sizeof(TO_STRING(SIZE_MAX)))
42 #define CONTENT_LENGTH_SIZE (sizeof(content_length_header) - MCL_NULL_CHAR_SIZE)
43 #define TRANSFER_ENCODING_SIZE (sizeof(transfer_encoding_header) - MCL_NULL_CHAR_SIZE)
44 #define CHUNK_LENGTH_IN_HEX_BUFFER_SIZE (sizeof(TO_STRING(HTTP_CALLBACK_BUFFER_SIZE)) + CRLF_SIZE)
45 
46 static mcl_error_t start_http(mcl_tls_socket_handle tls_socket, mcl_http_client_t *http_client, mcl_http_request_t *request);
47 static mcl_error_t get_response(mcl_tls_socket_handle tls_socket, mcl_http_response_t **http_response);
48 static mcl_error_t get_chunked_response(mcl_tls_socket_handle tls_socket, char **response_body, mcl_size_t *body_size);
49 static mcl_error_t get_content_length_response(mcl_tls_socket_handle tls_socket, char **response_body, mcl_size_t body_size);
50 static mcl_error_t receive_to_buffer(mcl_tls_socket_handle tls_socket, void *buffer, mcl_size_t size);
51 static mcl_error_t receive_until_lf(mcl_tls_socket_handle tls_socket, void *buffer, mcl_size_t *size);
52 static mcl_error_t send_buffer(mcl_tls_socket_handle tls_socket, const void *buffer, mcl_size_t size);
53 static mcl_error_t send_header_list(mcl_tls_socket_handle tls_socket, mcl_list_t *header_list);
54 static mcl_error_t send_header(mcl_tls_socket_handle tls_socket, const char *header_name, const char *header_value);
55 static mcl_error_t send_with_callback(mcl_tls_socket_handle tls_socket, mcl_http_payload_callback callback, void *stream_data, mcl_size_t payload_size);
56 static void header_list_destroy_callback(void **item);
57 
59 {
60  mcl_error_t code = MCL_OK;
61 
62  MCL_DEBUG_ENTRY("mcl_http_client_configuration_t *configuration = <%p>, mcl_http_client_t **http_client = <%p>", configuration, http_client);
63 
64  MCL_ASSERT_NOT_NULL(http_client, code);
65 
66  *http_client = MCL_NULL;
67 
68  MCL_ASSERT_NOT_NULL(configuration, code);
69 
70  if (MCL_NULL != configuration->proxy_hostname)
71  {
72  MCL_ERROR_STRING("Proxy is not supported for this specific configuration.");
73  code = MCL_INVALID_PARAMETER;
74  }
75 
76  if (MCL_OK == code)
77  {
78  MCL_NEW(*http_client);
79 
80  if (MCL_NULL == *http_client)
81  {
82  code = MCL_OUT_OF_MEMORY;
83  }
84  else
85  {
86  (*http_client)->user_agent = configuration->user_agent;
87  (*http_client)->timeout = configuration->http_request_timeout;
88  (*http_client)->port = configuration->port;
89 
90  code = mcl_tls_ca_chain_init(&((*http_client)->certificate_chain));
91  }
92  }
93 
94  if ((MCL_OK == code) && (MCL_NULL != configuration->certificate))
95  {
96  code = mcl_tls_ca_chain_add_certificate((*http_client)->certificate_chain, configuration->certificate, configuration->certificate_is_file);
97  }
98 
100  if ((MCL_OK != code) && (MCL_TRIGGERED_WITH_NULL != code))
101  {
102  mcl_http_client_destroy(http_client);
103  }
104 
105  MCL_DEBUG_LEAVE("retVal = <%d>", code);
106  return code;
107 }
108 
109 mcl_error_t mcl_http_client_add_certificate(mcl_http_client_t *http_client, const char *certificate, mcl_bool_t is_file)
110 {
111  mcl_error_t code;
112 
113  MCL_DEBUG_ENTRY("mcl_http_client_t *http_client = <%p>, const char *certificate = <%p>, mcl_bool_t certificate_is_file = <%u>", http_client, certificate, is_file);
114 
115  MCL_ASSERT_NOT_NULL(http_client, code);
116  MCL_ASSERT_NOT_NULL(certificate, code);
117 
118  code = mcl_tls_ca_chain_add_certificate(http_client->certificate_chain, certificate, is_file);
119 
121  MCL_DEBUG_LEAVE("retVal = <%d>", code);
122  return code;
123 }
124 
126 {
127  mcl_error_t code;
128  mcl_tls_socket_handle tls_socket;
129 
130  MCL_ASSERT_NOT_NULL(http_response, code);
131  *http_response = MCL_NULL;
132 
133  MCL_ASSERT_NOT_NULL(http_client, code);
134  MCL_ASSERT_NOT_NULL(http_request, code);
135 
136  if ((MCL_HTTP_GET != http_request->method) && (MCL_NULL == http_request->payload) && (MCL_NULL == http_request->stream_callback))
137  {
138  code = MCL_INVALID_PARAMETER;
139  }
140  else if ((MCL_NULL != http_request->payload) && (0 == http_request->payload_size))
141  {
142  MCL_ERROR_STRING("If payload buffer is given, payload size must be set.");
143  code = MCL_INVALID_PARAMETER;
144  }
145  else if (MCL_OK != mcl_string_util_strncmp(http_request->uri, https_prefix, HTTPS_PREFIX_SIZE))
146  {
147  MCL_ERROR_STRING("Only HTTPS is supported.");
149  }
150  else
151  {
152  code = mcl_tls_socket_init(&tls_socket);
153  }
154 
155  if (MCL_OK == code)
156  {
157  code = mcl_tls_socket_set_parameter(tls_socket, MCL_TLS_SOCKET_PARAMETER_TIMEOUT, &(http_client->timeout));
158  }
159 
160  if (MCL_OK == code)
161  {
163  }
164 
165  if (MCL_OK == code)
166  {
167  code = mcl_tls_socket_open(tls_socket);
168  }
169 
170  if (MCL_OK == code)
171  {
172  code = start_http(tls_socket, http_client, http_request);
173  }
174 
175  if (MCL_OK == code)
176  {
177  code = send_header_list(tls_socket, http_request->header);
178  }
179 
180  if (MCL_OK == code)
181  {
182  code = send_header(tls_socket, "User-Agent", http_client->user_agent);
183  }
184 
185  if ((MCL_OK == code) && (MCL_HTTP_GET != http_request->method))
186  {
187  if (0 != http_request->payload_size)
188  {
189  char content_length[CONTENT_LENGTH_BUFFER_SIZE];
190 
191  code = mcl_string_util_snprintf(content_length, CONTENT_LENGTH_BUFFER_SIZE, "%lu", (unsigned long) http_request->payload_size);
192 
193  if (MCL_OK == code)
194  {
195  code = send_header(tls_socket, content_length_header, content_length);
196  }
197  }
198  else
199  {
201 
202  if (MCL_OK == code)
203  {
204  code = send_buffer(tls_socket, (const mcl_uint8_t *) crlf, CRLF_SIZE);
205  }
206  }
207  }
208 
209  // One more CRLF to complete headers.
210  if (MCL_OK == code)
211  {
212  code = send_buffer(tls_socket, (const mcl_uint8_t *) crlf, CRLF_SIZE);
213  }
214 
215  if ((MCL_OK == code) && (MCL_HTTP_GET != http_request->method))
216  {
217  if (MCL_NULL == http_request->payload)
218  {
219  code = send_with_callback(tls_socket, http_request->stream_callback, http_request->stream_data, http_request->payload_size);
220  }
221  else
222  {
223  code = send_buffer(tls_socket, http_request->payload, http_request->payload_size);
224  }
225  }
226 
227  if (MCL_OK == code)
228  {
229  code = get_response(tls_socket, http_response);
230  }
231 
232  mcl_tls_socket_destroy(&tls_socket);
233 
235  MCL_DEBUG_LEAVE("retVal = <%d>", code);
236  return code;
237 }
238 
240 {
241  MCL_DEBUG_ENTRY("mcl_http_client_t **http_client = <%p>", http_client);
242 
243  if ((MCL_NULL != http_client) && (MCL_NULL != *http_client))
244  {
245  mcl_tls_ca_chain_destroy(&(*http_client)->certificate_chain);
246  MCL_FREE(*http_client);
247  }
248 
249  MCL_DEBUG_LEAVE("retVal = void");
250 }
251 
252 static mcl_error_t start_http(mcl_tls_socket_handle tls_socket, mcl_http_client_t *http_client, mcl_http_request_t *http_request)
253 {
254  mcl_error_t code = MCL_OK;
255  char *hostname = MCL_NULL;
256  mcl_size_t hostname_length;
257  mcl_size_t uri_length;
258 
259  MCL_DEBUG_ENTRY("mcl_tls_socket_handle tls_socket = <%p>, mcl_http_client_t *http_client = <%p>, mcl_http_request_t *http_request = <%p>", tls_socket, http_client, http_request);
260 
261  uri_length = mcl_string_util_strlen(http_request->uri) - HTTPS_PREFIX_SIZE;
262 
263  for (hostname_length = 0; hostname_length < uri_length; ++hostname_length)
264  {
265  if('/' == http_request->uri[hostname_length + HTTPS_PREFIX_SIZE])
266  {
267  break;
268  }
269  }
270 
271  hostname = MCL_MALLOC(hostname_length + MCL_NULL_CHAR_SIZE);
272 
273  if (MCL_NULL == hostname)
274  {
275  code = MCL_OUT_OF_MEMORY;
276  }
277  else
278  {
279  mcl_string_util_memcpy(hostname, http_request->uri + HTTPS_PREFIX_SIZE, hostname_length);
280  hostname[hostname_length] = MCL_NULL_CHAR;
281  }
282 
283  if (MCL_OK == code)
284  {
285  code = mcl_tls_socket_connect(tls_socket, hostname, http_client->port);
286  }
287 
288  if (MCL_OK == code)
289  {
290  switch(http_request->method)
291  {
292  case MCL_HTTP_GET:
293  code = send_buffer(tls_socket, get_string, GET_STRING_SIZE);
294  break;
295 
296  case MCL_HTTP_PUT:
297  code = send_buffer(tls_socket, put_string, PUT_STRING_SIZE);
298  break;
299 
300  case MCL_HTTP_POST:
301  code = send_buffer(tls_socket, post_string, POST_STRING_SIZE);
302  break;
303 
304  default:
305  code = MCL_FAIL;
306  break;
307  }
308  }
309 
310  if (MCL_OK == code)
311  {
312  code = send_buffer(tls_socket, http_request->uri + HTTPS_PREFIX_SIZE + hostname_length, uri_length - hostname_length);
313  }
314 
315  if (MCL_OK == code)
316  {
317  code = send_buffer(tls_socket, http_string, HTTP_STRING_SIZE);
318  }
319 
320  if (MCL_OK == code)
321  {
322  code = send_buffer(tls_socket, "Host: ", SIZE_OF_STRING("Host: "));
323  }
324 
325  if (MCL_OK == code)
326  {
327  code = send_buffer(tls_socket, hostname, hostname_length);
328  }
329 
330  MCL_FREE(hostname);
331 
332  if ((MCL_OK == code) && (TLS_DEFAULT_PORT != http_client->port))
333  {
334  char port_string[PORT_STRING_BUFFER_SIZE];
335 
336  code = mcl_string_util_snprintf(port_string, PORT_STRING_BUFFER_SIZE, "%u", http_client->port);
337 
338  if (MCL_OK == code)
339  {
340  code = send_buffer(tls_socket, ":", SIZE_OF_STRING(":"));
341  }
342 
343  if (MCL_OK == code)
344  {
345  code = send_buffer(tls_socket, port_string, mcl_string_util_strlen(port_string));
346  }
347  }
348 
349  if (MCL_OK == code)
350  {
351  code = send_buffer(tls_socket, crlf, CRLF_SIZE);
352  }
353 
354  MCL_DEBUG_LEAVE("retVal = <%d>", code);
355  return code;
356 }
357 
358 static mcl_error_t send_header_list(mcl_tls_socket_handle tls_socket, mcl_list_t *header_list)
359 {
360  mcl_error_t code = MCL_OK;
361  mcl_size_t index;
362 
363  MCL_DEBUG_ENTRY("mcl_tls_socket_handle tls_socket = <%p>, mcl_list_t *header_list = <%p>", tls_socket, header_list);
364 
365  mcl_list_reset(header_list);
366 
367  for (index = 0; (MCL_OK == code) && (index < header_list->count); ++index)
368  {
369  mcl_list_node_t *header_node = MCL_NULL;
370 
371  code = mcl_list_next(header_list, &header_node);
372 
373  if (MCL_OK == code)
374  {
375  const char *header = (const char *) header_node->data;
376 
377  code = send_buffer(tls_socket, header, mcl_string_util_strlen(header));
378  }
379 
380  if (MCL_OK == code)
381  {
382  code = send_buffer(tls_socket, crlf, CRLF_SIZE);
383  }
384  }
385 
386  MCL_DEBUG_LEAVE("retVal = <%d>", code);
387  return code;
388 }
389 
390 static mcl_error_t send_header(mcl_tls_socket_handle tls_socket, const char *header_name, const char *header_value)
391 {
392  mcl_error_t code = MCL_OK;
393 
394  MCL_DEBUG_ENTRY("mcl_tls_socket_handle tls_socket = <%p>, const char *header_name = <%p>, const char *header_value = <%p>", tls_socket, header_name, header_value);
395 
396  code = send_buffer(tls_socket, header_name, mcl_string_util_strlen(header_name));
397 
398  if (MCL_OK == code)
399  {
400  code = send_buffer(tls_socket, ": ", sizeof(": ") - MCL_NULL_CHAR_SIZE);
401  }
402 
403  if (MCL_OK == code)
404  {
405  code = send_buffer(tls_socket, header_value, mcl_string_util_strlen(header_value));
406  }
407 
408  if (MCL_OK == code)
409  {
410  code = send_buffer(tls_socket, crlf, CRLF_SIZE);
411  }
412 
413  MCL_DEBUG_LEAVE("retVal = <%d>", code);
414  return code;
415 }
416 
417 static mcl_error_t send_buffer(mcl_tls_socket_handle tls_socket, const void *buffer, mcl_size_t size)
418 {
419  mcl_error_t code = MCL_OK;
420  mcl_size_t sent_already = 0;
421 
422  MCL_VERBOSE_ENTRY("mcl_tls_socket_handle tls_socket = <%p>, const void *buffer = <%p>, mcl_size_t size = <%lu>", tls_socket, buffer, (long unsigned) size);
423 
424  while ((MCL_OK == code) && (size > sent_already))
425  {
426  mcl_size_t in_requested_out_sent = size - sent_already;
427 
428  code = mcl_tls_socket_send(tls_socket, ((const mcl_uint8_t *) buffer ) + sent_already, &in_requested_out_sent);
429 
430  sent_already += in_requested_out_sent;
431  }
432 
433  MCL_VERBOSE_LEAVE("retVal = <%d>", code);
434  return code;
435 }
436 
437 static mcl_error_t send_with_callback(mcl_tls_socket_handle tls_socket, mcl_http_payload_callback callback, void *stream_data, mcl_size_t payload_size)
438 {
439  mcl_error_t code = MCL_OK;
440  mcl_size_t size;
441  char callback_buffer[HTTP_CALLBACK_BUFFER_SIZE];
442 
443  MCL_DEBUG_ENTRY("mcl_tls_socket_handle tls_socket = <%p>, mcl_http_payload_callback callback = <%p>, void *stream_data = <%p>, mcl_size_t payload_size = <%lu>", tls_socket, callback, stream_data, payload_size);
444 
445  // remaining_size will not be used if transfer encoding is used.
446  mcl_size_t remaining_size = payload_size;
447  mcl_bool_t using_transfer_encoding = (0 == payload_size) ? MCL_TRUE : MCL_FALSE;
448 
449  do
450  {
451  size = callback(callback_buffer, 1, HTTP_CALLBACK_BUFFER_SIZE, stream_data);
452 
453  if (HTTP_CALLBACK_BUFFER_SIZE < size)
454  {
455  MCL_ERROR_STRING("HTTP payload callback cannot return greater value than HTTP_CALLBACK_BUFFER_SIZE.");
456  code = MCL_FAIL;
457  }
458  else if (MCL_TRUE == using_transfer_encoding)
459  {
460  char hex_string[CHUNK_LENGTH_IN_HEX_BUFFER_SIZE];
461 
462  code = mcl_string_util_snprintf(hex_string, CHUNK_LENGTH_IN_HEX_BUFFER_SIZE, "%X\r\n", size);
463 
464  if (MCL_OK == code)
465  {
466  code = send_buffer(tls_socket, hex_string, mcl_string_util_strlen(hex_string));
467  }
468  }
469  // If content-length is given, track remaining_size.
470  else if (size > remaining_size)
471  {
472  MCL_ERROR_STRING("User tries to send more data than Content-Length.");
473  code = MCL_FAIL;
474  }
475  else
476  {
477  remaining_size -= size;
478  }
479 
480  if ((MCL_OK == code) && (0 != size))
481  {
482  code = send_buffer(tls_socket, callback_buffer, size);
483  }
484 
485  // While using "Transfer-Encoding: chunked", CR LF must be sent after chunk, even if chunk size is 0.
486  if ((MCL_OK == code) && (MCL_TRUE == using_transfer_encoding))
487  {
488  code = send_buffer(tls_socket, crlf, CRLF_SIZE);
489  }
490 
491  } while((MCL_OK == code) && (0 != size));
492 
493  if ((MCL_OK == code) && (0 != remaining_size))
494  {
495  MCL_ERROR_STRING("User sent less data than expected.");
496  code = MCL_FAIL;
497  }
498 
499  MCL_DEBUG_LEAVE("retVal = <%d>", code);
500  return code;
501 }
502 
503 static mcl_error_t get_response(mcl_tls_socket_handle tls_socket, mcl_http_response_t **http_response)
504 {
505  mcl_error_t code;
506  mcl_list_t *header_list = MCL_NULL;
507  mcl_size_t in_requested_out_received;
508  E_MCL_HTTP_STATUS_CODE status_code;
509  char parse_buffer[HTTP_PARSE_BUFFER_SIZE];
510  char *response_body = MCL_NULL;
511  mcl_size_t body_size = 0;
512  mcl_bool_t using_transfer_encoding = MCL_FALSE;
513  mcl_bool_t found_content_length = MCL_FALSE;
514 
515  MCL_DEBUG_ENTRY("mcl_tls_socket_handle tls_socket = <%p>, mcl_http_response_t **http_response = <%p>", tls_socket, http_response);
516 
517  in_requested_out_received = HTTP_PARSE_BUFFER_SIZE;
518 
519  code = receive_until_lf(tls_socket, parse_buffer, &in_requested_out_received);
520 
521  if (MCL_OK == code)
522  {
523  mcl_uint32_t status;
524 
525  if (1 == sscanf(parse_buffer, "HTTP/1.1 %u", &status))
526  {
527  status_code = (E_MCL_HTTP_STATUS_CODE) status;
528  }
529  else
530  {
531  code = MCL_FAIL;
532  }
533  }
534 
535  if (MCL_OK == code)
536  {
537  code = mcl_list_initialize(&header_list);
538  }
539 
540  while (MCL_OK == code)
541  {
542  char *header = MCL_NULL;
543  in_requested_out_received = HTTP_PARSE_BUFFER_SIZE;
544 
545  code = receive_until_lf(tls_socket, parse_buffer, &in_requested_out_received);
546 
547  if (CRLF_SIZE >= in_requested_out_received)
548  {
549  break;
550  }
551 
552  header = MCL_MALLOC(in_requested_out_received - CRLF_SIZE + MCL_NULL_CHAR_SIZE);
553 
554  if (MCL_NULL == header)
555  {
556  code = MCL_OUT_OF_MEMORY;
557  }
558  else
559  {
560  mcl_string_util_memcpy(header, parse_buffer, in_requested_out_received - CRLF_SIZE);
561  header[in_requested_out_received - CRLF_SIZE] = MCL_NULL_CHAR;
562  }
563 
564  if (MCL_OK == code)
565  {
566  code = mcl_list_add(header_list, header);
567 
568  if (MCL_OK != code)
569  {
570  MCL_FREE(header);
571  }
572  }
573 
574  if ((MCL_OK == code) && (MCL_FALSE == found_content_length) && (MCL_FALSE == using_transfer_encoding))
575  {
576  if (1 == sscanf(parse_buffer, "Content-Length: %lu", (unsigned long *) &body_size))
577  {
578  found_content_length = MCL_TRUE;
579  MCL_DEBUG("Received Content-Length header: %lu.", (unsigned long *) body_size);
580  }
581  else if (MCL_TRUE == mcl_string_util_find_case_insensitive(parse_buffer, transfer_encoding_header, &in_requested_out_received))
582  {
583  using_transfer_encoding = MCL_TRUE;
584  MCL_DEBUG("Received %s header.", transfer_encoding_header);
585  }
586  }
587  }
588 
589  if (MCL_OK == code)
590  {
591  if (MCL_TRUE == using_transfer_encoding)
592  {
593  code = get_chunked_response(tls_socket, &response_body, &body_size);
594  }
595  else if (MCL_TRUE == found_content_length)
596  {
597  if (0 != body_size)
598  {
599  code = get_content_length_response(tls_socket, &response_body, body_size);
600  }
601  }
602  else
603  {
604  code = MCL_FAIL;
605  }
606  }
607 
608  if (MCL_OK == code)
609  {
610  code = mcl_http_response_initialize(header_list, (mcl_uint8_t *) response_body, body_size, status_code, http_response);
611  }
612 
613  if (MCL_OK != code)
614  {
616  MCL_FREE(response_body);
617  }
618 
619  MCL_DEBUG_LEAVE("retVal = <%d>", code);
620  return code;
621 }
622 
623 static mcl_error_t get_chunked_response(mcl_tls_socket_handle tls_socket, char **response_body, mcl_size_t *body_size)
624 {
625  mcl_error_t code = MCL_OK;
626  char chunk_string[CONTENT_LENGTH_BUFFER_SIZE + CRLF_SIZE];
627  *response_body = MCL_NULL;
628  *body_size = 0;
629 
630  MCL_DEBUG_ENTRY("mcl_tls_socket_handle tls_socket = <%p>, char **response_body = <%p>, mcl_size_t *body_size = <%p>", tls_socket, response_body, body_size);
631 
632  while (MCL_OK == code)
633  {
634  mcl_size_t chunk_size;
635  mcl_size_t in_requested_out_received;
636 
637  in_requested_out_received = CONTENT_LENGTH_BUFFER_SIZE + CRLF_SIZE;
638  code = receive_until_lf(tls_socket, chunk_string, &in_requested_out_received);
639 
640  if (MCL_OK == code)
641  {
642  if (1 == sscanf(chunk_string, "%x\r\n", (unsigned int *) &chunk_size))
643  {
644  MCL_DEBUG("Chunk size: %lu.", (unsigned long) chunk_size);
645  }
646  else
647  {
648  code = MCL_FAIL;
649  MCL_ERROR_STRING("Could not get chunk size.");
650  }
651  }
652 
653  if ((MCL_OK == code) && (0 != chunk_size))
654  {
655  if (MCL_NULL == *response_body)
656  {
657  *response_body = MCL_MALLOC(chunk_size);
658  }
659  else
660  {
661  *response_body = MCL_RESIZE(*response_body, *body_size + chunk_size);
662  }
663 
664  if (MCL_NULL == *response_body)
665  {
666  code = MCL_OUT_OF_MEMORY;
667  }
668  else
669  {
670  code = receive_to_buffer(tls_socket, *response_body + *body_size, chunk_size);
671  }
672 
673  *body_size += chunk_size;
674  }
675 
676  if (MCL_OK == code)
677  {
678  code = receive_to_buffer(tls_socket, chunk_string, CRLF_SIZE);
679  }
680 
681  if (0 == chunk_size)
682  {
683  break;
684  }
685  }
686 
687  if (MCL_OK != code)
688  {
689  MCL_FREE(*response_body);
690  }
691 
692  MCL_DEBUG_LEAVE("retVal = <%d>", code);
693  return code;
694 }
695 
696 static mcl_error_t get_content_length_response(mcl_tls_socket_handle tls_socket, char **response_body, mcl_size_t body_size)
697 {
698  mcl_error_t code;
699 
700  MCL_DEBUG_ENTRY("mcl_tls_socket_handle tls_socket = <%p>, char **response_body = <%p>, mcl_size_t body_size = <%lu>", tls_socket, response_body, (long unsigned) body_size);
701 
702  *response_body = MCL_MALLOC(body_size);
703 
704  if (MCL_NULL == *response_body)
705  {
706  code = MCL_OUT_OF_MEMORY;
707  }
708  else
709  {
710  code = receive_to_buffer(tls_socket, *response_body, body_size);
711 
712  if (MCL_OK != code)
713  {
714  MCL_FREE(*response_body);
715  }
716  }
717 
718  MCL_DEBUG_LEAVE("retVal = <%d>", code);
719  return code;
720 }
721 
722 static mcl_error_t receive_to_buffer(mcl_tls_socket_handle tls_socket, void *buffer, mcl_size_t size)
723 {
724  mcl_error_t code = MCL_OK;
725  mcl_size_t received_already = 0;
726 
727  MCL_VERBOSE_ENTRY("mcl_tls_socket_handle tls_socket = <%p>, void *buffer = <%p>, mcl_size_t size = <%lu>", tls_socket, buffer, (long unsigned) size);
728 
729  while ((MCL_OK == code) && (size > received_already))
730  {
731  mcl_size_t in_requested_out_received = size - received_already;
732 
733  code = mcl_tls_socket_receive(tls_socket, ((mcl_uint8_t *) buffer ) + received_already, &in_requested_out_received);
734 
735  received_already += in_requested_out_received;
736  }
737 
738  MCL_VERBOSE_LEAVE("retVal = <%d>", code);
739  return code;
740 }
741 
742 static mcl_error_t receive_until_lf(mcl_tls_socket_handle tls_socket, void *buffer, mcl_size_t *size)
743 {
744  mcl_error_t code = MCL_OK;
745  mcl_size_t requested_size = *size;
746  *size = 0;
747 
748  MCL_DEBUG_ENTRY("mcl_tls_socket_handle tls_socket = <%p>, void *buffer = <%p>, mcl_size_t *size = <%p>", tls_socket, buffer, size);
749 
750  while (MCL_OK == code)
751  {
752  mcl_size_t single_byte_size = 1;
753  char received_char;
754 
755  code = mcl_tls_socket_receive(tls_socket, &received_char, &single_byte_size);
756 
757  if (MCL_OK == code)
758  {
759  ((char *) buffer)[*size] = received_char;
760  ++(*size);
761 
762  if ('\n' == received_char)
763  {
764  break;
765  }
766 
767  if ((requested_size - MCL_NULL_CHAR_SIZE) == *size)
768  {
769  code = MCL_FAIL;
770  }
771  }
772  }
773 
774  if (MCL_OK == code)
775  {
776  ((char *) buffer)[*size] = MCL_NULL_CHAR;
777  }
778 
779  MCL_DEBUG_LEAVE("retVal = <%d>", code);
780  return code;
781 }
782 
783 static void header_list_destroy_callback(void **item)
784 {
785  MCL_FREE(*item);
786 }
static mcl_error_t receive_until_lf(mcl_tls_socket_handle tls_socket, void *buffer, mcl_size_t *size)
#define MCL_FUNCTION_LEAVE_LABEL
static void header_list_destroy_callback(void **item)
size_t mcl_size_t
mcl_error_t mcl_tls_socket_send(mcl_tls_socket_handle tls_socket_handle, const mcl_uint8_t *buffer, mcl_size_t *size)
Success.
#define MCL_DEBUG(...)
Definition: mcl_log_util.h:114
char * uri
Uri of http request.
void mcl_http_client_destroy(mcl_http_client_t **http_client)
Received parameter is null.
#define HTTP_PARSE_BUFFER_SIZE
mcl_error_t mcl_http_client_initialize(mcl_http_client_configuration_t *configuration, mcl_http_client_t **http_client)
#define PUT_STRING_SIZE
MCL_CORE_EXPORT mcl_error_t mcl_http_response_initialize(mcl_list_t *header, mcl_uint8_t *payload, mcl_size_t payload_size, E_MCL_HTTP_STATUS_CODE status_code, mcl_http_response_t **http_response)
Definition: http_response.c:17
mcl_int32_t mcl_error_t
#define TLS_DEFAULT_PORT
static const char content_length_header[]
static const char get_string[]
#define MCL_DEBUG_ENTRY(...)
Definition: mcl_log_util.h:115
mcl_tls_ca_chain_handle certificate_chain
Http put method.
mcl_size_t payload_size
Payload size of http request.
void * stream_data
Stream data.
uint32_t mcl_uint32_t
static const char http_string[]
#define MCL_FALSE
#define POST_STRING_SIZE
mcl_error_t mcl_http_client_add_certificate(mcl_http_client_t *http_client, const char *certificate, mcl_bool_t is_file)
const char * user_agent
User agent.
Requested operation is not supported.
MCL_CORE_EXPORT mcl_size_t mcl_string_util_strlen(const char *buffer)
Definition: string_util.c:23
MCL_CORE_EXPORT mcl_error_t mcl_list_next(mcl_list_t *list, mcl_list_node_t **node)
Definition: list.c:76
static mcl_error_t send_with_callback(mcl_tls_socket_handle tls_socket, mcl_http_payload_callback callback, void *stream_data, mcl_size_t payload_size)
static const char crlf[]
#define MCL_ERROR_STRING(string)
Definition: mcl_log_util.h:143
const char * user_agent
#define GET_STRING_SIZE
#define MCL_NEW(p)
Definition: mcl_memory.h:55
mcl_bool_t certificate_is_file
Flag to check if certificate is given as file or string.
#define MCL_NULL
List module interface header file.
static mcl_error_t send_header_list(mcl_tls_socket_handle tls_socket, mcl_list_t *header_list)
#define TRANSFER_ENCODING_SIZE
#define MCL_VERBOSE_LEAVE(...)
Definition: mcl_log_util.h:104
static mcl_error_t receive_to_buffer(mcl_tls_socket_handle tls_socket, void *buffer, mcl_size_t size)
mcl_error_t mcl_tls_socket_connect(mcl_tls_socket_handle tls_socket_handle, const char *host, mcl_uint16_t port)
Http get method.
static mcl_error_t send_buffer(mcl_tls_socket_handle tls_socket, const void *buffer, mcl_size_t size)
const char * certificate
Certificate. If it is NULL, default CA certificate store will be used (if available).
MCL_CORE_EXPORT mcl_error_t mcl_list_add(mcl_list_t *list, void *data)
Definition: list.c:34
mcl_error_t mcl_tls_ca_chain_add_certificate(mcl_tls_ca_chain_handle tls_ca_chain_handle, const char *certificate, mcl_bool_t is_file)
static mcl_error_t get_chunked_response(mcl_tls_socket_handle tls_socket, char **response_body, mcl_size_t *body_size)
mcl_error_t mcl_tls_socket_set_parameter(mcl_tls_socket_handle tls_socket_handle, E_MCL_TLS_SOCKET_PARAMETER parameter, const void *value)
#define MCL_FREE(p)
Definition: mcl_memory.h:59
#define CHUNK_LENGTH_IN_HEX_BUFFER_SIZE
#define MCL_RESIZE(p, bytes)
Definition: mcl_memory.h:58
#define CRLF_SIZE
E_MCL_HTTP_METHOD method
Http method of http request.
MCL_CORE_EXPORT void mcl_list_destroy_with_content(mcl_list_t **list, mcl_list_item_destroy_callback callback)
Definition: list.c:302
uint8_t mcl_uint8_t
static mcl_error_t start_http(mcl_tls_socket_handle tls_socket, mcl_http_client_t *http_client, mcl_http_request_t *request)
#define MCL_ASSERT_NOT_NULL(argument, return_variable)
Definition: mcl_assert.h:38
#define HTTP_CALLBACK_BUFFER_SIZE
MCL_CORE_EXPORT void mcl_string_util_memcpy(void *destination, const void *source, mcl_size_t count)
Definition: string_util.c:220
mcl_error_t mcl_http_client_send(mcl_http_client_t *http_client, mcl_http_request_t *http_request, mcl_http_response_t **http_response)
mcl_error_t mcl_tls_ca_chain_init(mcl_tls_ca_chain_handle *tls_ca_chain_handle)
static const char https_prefix[]
MCL_CORE_EXPORT mcl_bool_t mcl_string_util_find_case_insensitive(const char *source, const char *target, mcl_size_t *start_index)
Definition: string_util.c:342
MCL_CORE_EXPORT mcl_error_t mcl_string_util_snprintf(char *string, mcl_size_t length, const char *format,...)
Definition: string_util.c:158
MCL_CORE_EXPORT void mcl_list_reset(mcl_list_t *list)
Definition: list.c:276
#define HTTP_STRING_SIZE
mcl_error_t mcl_tls_socket_receive(mcl_tls_socket_handle tls_socket_handle, mcl_uint8_t *buffer, mcl_size_t *size)
mcl_uint32_t http_request_timeout
Timeout value (in seconds) for HTTP requests. Default timeout is 300 seconds.
Http post method.
static mcl_error_t send_header(mcl_tls_socket_handle tls_socket, const char *header_name, const char *header_value)
#define PORT_STRING_BUFFER_SIZE
static mcl_error_t get_response(mcl_tls_socket_handle tls_socket, mcl_http_response_t **http_response)
mcl_size_t(* mcl_http_payload_callback)(char *buffer, mcl_size_t size, mcl_size_t count, void *user_context)
mcl_http_payload_callback stream_callback
Callback to be used with chunked Transfer-Encoding. If not used, it must be NULL. ...
mcl_uint8_t mcl_bool_t
mcl_uint16_t port
Port number.
String utility module interface header file.
mcl_uint8_t * payload
Payload of http request.
void mcl_tls_ca_chain_destroy(mcl_tls_ca_chain_handle *tls_ca_chain_handle)
#define CONTENT_LENGTH_BUFFER_SIZE
Memory allocation fail.
static mcl_error_t get_content_length_response(mcl_tls_socket_handle tls_socket, char **response_body, mcl_size_t body_size)
static const char transfer_encoding_header[]
Basic HTTP client module header file.
MCL_CORE_EXPORT mcl_error_t mcl_list_initialize(mcl_list_t **list)
Definition: list.c:13
#define MCL_NULL_CHAR_SIZE
#define MCL_MALLOC(bytes)
Definition: mcl_memory.h:54
mcl_error_t mcl_tls_socket_open(mcl_tls_socket_handle tls_socket_handle)
static const char put_string[]
General invalid parameter fail.
const char * proxy_hostname
Proxy hostname. Optional.
void mcl_tls_socket_destroy(mcl_tls_socket_handle *tls_socket_handle)
#define MCL_DEBUG_LEAVE(...)
Definition: mcl_log_util.h:116
#define MCL_TRUE
#define SIZE_OF_STRING(x)
#define MCL_VERBOSE_ENTRY(...)
Definition: mcl_log_util.h:103
mcl_list_t * header
Header of http request.
mcl_error_t mcl_tls_socket_init(mcl_tls_socket_handle *tls_socket_handle)
Internal failure in MCL.
void * data
Data of the node.
Definition: mcl_list.h:27
MCL_CORE_EXPORT mcl_error_t mcl_string_util_strncmp(const char *string_1, const char *string_2, mcl_size_t count)
Definition: string_util.c:118
#define MCL_NULL_CHAR
#define HTTPS_PREFIX_SIZE
static const char post_string[]
E_MCL_HTTP_STATUS_CODE
Memory module interface header file.