http_request.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_request.c
9  * @date Jun 28, 2016
10  * @brief HTTP request module implementation file.
11  *
12  ************************************************************************/
13 
14 #include "data_types.h"
15 #include "http_request.h"
16 #include "log_util.h"
17 #include "definitions.h"
18 #include "memory.h"
19 #include "random.h"
20 
24 typedef enum E_MCL_BOUNDARY_TYPE
25 {
29 
30 char *boundary_characters = "1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
32 
33 // 5 BOUNDARY_LINE_LENGTH : 1 Open main boundary, 3 open/close subboundary, 1 close main boundary
34 // 1 CONTENT_TYPE_LINE_LENGTH : For the multipart/related main content type line
35 // 1 MCL_NULL_CHAR_SIZE : For string terminating null char
36 // 2 CONTENT_TYPE_HEADER_LENGTH : For tuple sections "Content-Type: " parts.
37 // 4 NEW_LINE_LENGTH : 2 for each sub content-type headers.
39 
40 // 2 BOUNDARY_LINE_LENGTH : 1 Open main boundary, 1 close main boundary
41 // 1 CONTENT_TYPE_LINE_LENGTH : For the multipart/related main content type line
42 // 1 MCL_NULL_CHAR_SIZE : For string terminating null char
43 // 1 CONTENT_TYPE_HEADER_LENGTH : For single sections "Content-Type: " part.
44 // 1 CONTENT_ID_HEADER_LENGTH : For single sections "Content-Id: " part.
45 // 2 NEW_LINE_LENGTH : 2 for sub content-type header.
48 
49 // 1 BOUNDARY_LINE_LENGTH : for open main boundary
50 // 1 MCL_NULL_CHAR_SIZE : For string terminating null char
52 
53 // 1 BOUNDARY_LINE_LENGTH : for open subboundary
54 // 1 CONTENT_TYPE_HEADER_LENGTH : For sub boundary content type header
55 // 1 MCL_NULL_CHAR_SIZE : For string terminating null char
56 // 2 NEW_LINE_LENGTH : 1 for content type line, 1 for blank line after that
57 // 1 CONTENT_TYPE_LINE_LENGTH : For the multipart/related main content type line where the subboundary defined.
59  + MCL_NULL_CHAR_SIZE;
60 
61 // 1 BOUNDARY_LINE_LENGTH : for open subboundary
62 // 1 CONTENT_TYPE_HEADER_LENGTH : For sub boundary content type header
63 // 1 MCL_NULL_CHAR_SIZE : For string terminating null char
64 // 2 NEW_LINE_LENGTH : 1 for content type line, 1 for blank line after that
66 
67 // Private Function Prototypes:
69 static E_MCL_ERROR_CODE _add_boundary(mcl_uint8_t *payload, mcl_size_t *payload_offset, char *boundary, E_MCL_BOUNDARY_TYPE boundary_type);
70 static E_MCL_ERROR_CODE _resize_payload_buffer_if_necessary(mcl_size_t required_empty_size, http_request_t *http_request, mcl_bool_t finalize);
71 static void _add_meta(string_t *meta, http_request_t *http_request, mcl_size_t *payload_offset);
72 static void _add_payload(http_request_t *http_request, payload_copy_callback_t payload_copy_callback, void *user_context, mcl_uint8_t *payload, mcl_size_t payload_size,
73  mcl_size_t *payload_offset);
74 static E_MCL_ERROR_CODE _add_content_info(http_request_t *http_request, char *content_info_name, char *content_info_value, mcl_size_t *payload_offset,
75  mcl_size_t content_info_line_length, char *sub_boundary);
76 static void _add_blank_line(http_request_t *http_request, mcl_size_t *payload_offset);
77 static mcl_size_t _get_available_space(http_request_t *http_request, mcl_size_t overhead);
78 
79 E_MCL_ERROR_CODE http_request_initialize(E_MCL_HTTP_METHOD method, string_t *uri, mcl_size_t header_size, mcl_size_t payload_size, mcl_bool_t resize_enabled,
80  string_t *user_agent, mcl_size_t max_http_payload_size, http_request_t **http_request)
81 {
82  DEBUG_ENTRY("E_MCL_HTTP_METHOD method = <%d>, string_t *uri = <%p>, mcl_size_t header_size = <%u>, mcl_size_t payload_size = <%u>, mcl_bool_t resize_enabled = <%p>, string_t *user_agent = <%p>, mcl_size_t max_http_payload_size = <%u>, http_request_t **http_request = <%p>",
83  method, uri, header_size, payload_size, &resize_enabled, user_agent, max_http_payload_size, http_request)
84 
85  E_MCL_ERROR_CODE return_code;
86  // Create new http_request object.
87  MCL_NEW(*http_request);
88  ASSERT_CODE_MESSAGE(MCL_NULL != *http_request, MCL_OUT_OF_MEMORY, "Memory can not be allocated for http request.");
89 
90  // Makes sure members of http_request_t are null in case of unexpected call to http_request_destroy() within assert macros.
91  (*http_request)->resize_enabled = resize_enabled;
92  (*http_request)->boundary = MCL_NULL;
93  (*http_request)->header = MCL_NULL;
94  (*http_request)->payload = MCL_NULL;
95  (*http_request)->uri = MCL_NULL;
96 
97  // Set request method and size of the payload.
98  (*http_request)->method = method;
99  (*http_request)->payload_size = payload_size;
100  (*http_request)->payload_offset = 0;
101  (*http_request)->finalized = MCL_FALSE;
102  (*http_request)->max_http_payload_size = max_http_payload_size;
103 
104  // Initialize a string array for the request header. User-Agent is for all HTTP requests the same : header_size + 1
105  return_code = string_array_initialize(header_size + 1, &((*http_request)->header));
106  ASSERT_STATEMENT_CODE_MESSAGE(return_code == MCL_OK, http_request_destroy(http_request), return_code, "String array for http request header can not be initialized.");
107 
108  // Add fix HTTP header: User-Agent = MCL/<MCL_VERSION> (<CUSTOM_USER_AGENT>)
109  return_code = http_request_add_header(*http_request, &http_header_names[HTTP_HEADER_USER_AGENT], user_agent);
110  ASSERT_STATEMENT_CODE_MESSAGE(MCL_OK == return_code, http_request_destroy(http_request), return_code, "Add header to request has been failed for <User-Agent>.");
111 
112  // Allocate memory for the payload if it is present.
113  if (0 < payload_size)
114  {
115  (*http_request)->payload = MCL_MALLOC(payload_size);
116  ASSERT_STATEMENT_CODE_MESSAGE(MCL_NULL != (*http_request)->payload, http_request_destroy(http_request), MCL_OUT_OF_MEMORY,
117  "Memory can not be allocated for the payload of http request.");
118  }
119 
120  // Allocate memory for the request URI.
121  return_code = string_initialize(uri, &((*http_request)->uri));
122  ASSERT_STATEMENT_CODE_MESSAGE(MCL_OK == return_code, http_request_destroy(http_request), return_code, "Memory can not be allocated for the URI of http request.");
123 
124  return_code = _generate_random_boundary(&((*http_request)->boundary));
125  ASSERT_STATEMENT_CODE_MESSAGE(MCL_OK == return_code, http_request_destroy(http_request), return_code, "Random boundary generation failed.");
126 
127  DEBUG_LEAVE("retVal = <%d>", MCL_OK);
128  return MCL_OK;
129 }
130 
131 E_MCL_ERROR_CODE http_request_add_header(http_request_t *http_request, string_t *header_name, string_t *header_value)
132 {
133  DEBUG_ENTRY("http_request_t *http_request = <%p>, string_t *header_name = <%p>, string_t *header_value = <%p>", http_request, header_name, header_value)
134 
135  E_MCL_ERROR_CODE return_code;
136  mcl_size_t header_line_length;
137  string_t *header_line = MCL_NULL;
138  char *header_format = MCL_NULL;
139  char *boundary = MCL_NULL;
140 
143  {
144  // Length of the header line, +26 is for the string ": " + ";boundary=" + ";charset=utf-8".
145  header_line_length = header_name->length + header_value->length + http_request->boundary->length + 26;
146  header_format = "%s: %s;boundary=%s;charset=utf-8";
147  boundary = http_request->boundary->buffer;
148  }
149  else
150  {
151  // Length of the header line, +2 is for the string ": ".
152  header_line_length = header_name->length + header_value->length + 2;
153  header_format = "%s: %s";
154  }
155 
156  // Initialize a string_t for the header line.
157  return_code = string_initialize_new(MCL_NULL, header_line_length, &header_line);
158  ASSERT_CODE_MESSAGE(MCL_OK == return_code, return_code, "Memory can not be allocated for the request header line.");
159 
160  // Compose the header line.
161  return_code = string_util_snprintf(header_line->buffer, header_line_length + 1, header_format, header_name->buffer, header_value->buffer, boundary);
162  ASSERT_STATEMENT_CODE_MESSAGE(MCL_OK == return_code, string_destroy(&header_line), return_code, "New header line can not be composed.");
163 
164  // Add header line to the array of header lines.
165  return_code = string_array_add(http_request->header, header_line, MCL_TRUE);
166  ASSERT_STATEMENT_CODE_MESSAGE(MCL_OK == return_code, string_destroy(&header_line), return_code, "New header line can not be added to request header array.");
167 
168  DEBUG_LEAVE("retVal = <%d>", MCL_OK);
169  return MCL_OK;
170 }
171 
172 E_MCL_ERROR_CODE http_request_add_single(http_request_t *http_request, string_t *content_type, string_t *content_id, string_t *meta_string)
173 {
174  DEBUG_ENTRY("http_request_t *http_request = <%p>, string_t *content_type = <%p>, string_t *content_id = <%p>, string_t *meta_string = <%p>", http_request, content_type,
175  content_id, meta_string)
176 
177  E_MCL_ERROR_CODE return_code;
178  mcl_size_t payload_offset_local;
179  mcl_size_t required_empty_size = OVERHEAD_FOR_SINGLE + content_type->length + content_id->length + meta_string->length + NEW_LINE_LENGTH + MCL_NULL_CHAR_SIZE;
180 
181  // Check if the empty space in payload buffer is enough.If not so, resize payload buffer if possible.
182  return_code = _resize_payload_buffer_if_necessary(required_empty_size, http_request, MCL_FALSE);
183  ASSERT_CODE_MESSAGE(MCL_OK == return_code, return_code, "Inadequate memory in payload buffer for HTTP message.");
184 
185  payload_offset_local = http_request->payload_offset;
186 
187  // Add opening main boundary.
188  return_code = _add_boundary(http_request->payload, &payload_offset_local, http_request->boundary->buffer, MCL_OPEN_BOUNDARY);
189  ASSERT_CODE_MESSAGE(MCL_OK == return_code, return_code, "Boundary couldn't be composed.");
190 
191  // Add content_type.
192  return_code = _add_content_info(http_request, http_header_names[HTTP_HEADER_CONTENT_TYPE].buffer, content_type->buffer, &payload_offset_local,
194  ASSERT_CODE_MESSAGE(MCL_OK == return_code, return_code, "content_type couldn't be composed.");
195 
196  // Add content_id.
197  return_code = _add_content_info(http_request, http_header_names[HTTP_HEADER_CONTENT_ID].buffer, content_id->buffer, &payload_offset_local,
199  ASSERT_CODE_MESSAGE(MCL_OK == return_code, return_code, "content_id couldn't be composed.");
200 
201  // Add blank line.
202  _add_blank_line(http_request, &payload_offset_local);
203 
204  // Add meta.
205  _add_meta(meta_string, http_request, &payload_offset_local);
206 
207  // If single is added successfully, update payload_offset with local one.
208  http_request->payload_offset = payload_offset_local;
209 
210  DEBUG_LEAVE("retVal = <%d>", MCL_OK);
211  return MCL_OK;
212 }
213 
214 E_MCL_ERROR_CODE http_request_add_tuple(http_request_t *http_request, string_t *meta, string_t *meta_content_type, payload_copy_callback_t payload_copy_callback,
215  void *user_context, void *payload, mcl_size_t payload_size, string_t *payload_content_type)
216 {
217  DEBUG_ENTRY("http_request_t *http_request = <%p>, string_t *meta = <%p>, string_t *meta_content_type = <%p>, payload_copy_callback_t payload_copy_callback = <%p>, void *user_context = <%p>, void *payload = <%p>, mcl_size_t payload_size = <%u>, string_t *payload_content_type = <%p>",
218  http_request, meta, meta_content_type, payload_copy_callback, user_context, payload, payload_size, payload_content_type)
219 
220  E_MCL_ERROR_CODE return_code;
221  string_t *sub_boundary = MCL_NULL;
222  mcl_size_t payload_offset_local;
223  mcl_size_t required_empty_size = OVERHEAD_FOR_TUPLE + meta_content_type->length + payload_content_type->length + payload_size + meta->length;
224 
225  // Check if the empty space in payload buffer is enough.If not so, resize payload buffer if possible.
226  return_code = _resize_payload_buffer_if_necessary(required_empty_size, http_request, MCL_FALSE);
227  ASSERT_CODE_MESSAGE(MCL_OK == return_code, return_code, "Inadequate memory in payload buffer for HTTP message.");
228 
229  payload_offset_local = http_request->payload_offset;
230 
231  // Add opening main boundary.
232  return_code = _add_boundary(http_request->payload, &payload_offset_local, http_request->boundary->buffer, MCL_OPEN_BOUNDARY);
233  ASSERT_CODE_MESSAGE(MCL_OK == return_code, return_code, "Boundary couldn't be composed.");
234 
235  // Create sub_boundary.
236  return_code = _generate_random_boundary(&sub_boundary);
237  ASSERT_CODE_MESSAGE(MCL_OK == return_code, return_code, "sub_boundary couldn't be composed.");
238 
239  // Add tuple content_type.
241  &payload_offset_local, CONTENT_TYPE_LINE_LENGTH, sub_boundary->buffer);
242  ASSERT_STATEMENT_CODE_MESSAGE(MCL_OK == return_code, string_destroy(&sub_boundary), return_code, "content_type couldn't be composed.");
243 
244  // Add blank line.
245  _add_blank_line(http_request, &payload_offset_local);
246 
247  // Add open sub_boundary.
248  return_code = _add_boundary(http_request->payload, &payload_offset_local, sub_boundary->buffer, MCL_OPEN_BOUNDARY);
249  ASSERT_STATEMENT_CODE_MESSAGE(MCL_OK == return_code, string_destroy(&sub_boundary), return_code, "sub_boundary couldn't be composed.");
250 
251  // Add content_type.
252  return_code = _add_content_info(http_request, http_header_names[HTTP_HEADER_CONTENT_TYPE].buffer, meta_content_type->buffer, &payload_offset_local,
254  ASSERT_STATEMENT_CODE_MESSAGE(MCL_OK == return_code, string_destroy(&sub_boundary), return_code, "content_type couldn't be composed.");
255 
256  // Add blank line.
257  _add_blank_line(http_request, &payload_offset_local);
258 
259  // Add meta.
260  _add_meta(meta, http_request, &payload_offset_local);
261 
262  // Add open sub_boundary.
263  return_code = _add_boundary(http_request->payload, &payload_offset_local, sub_boundary->buffer, MCL_OPEN_BOUNDARY);
264  ASSERT_STATEMENT_CODE_MESSAGE(MCL_OK == return_code, string_destroy(&sub_boundary), return_code, "sub_boundary couldn't be composed.");
265 
266  // Add payload content-type.
267  return_code = _add_content_info(http_request, http_header_names[HTTP_HEADER_CONTENT_TYPE].buffer, payload_content_type->buffer, &payload_offset_local,
268  CONTENT_TYPE_HEADER_LENGTH + payload_content_type->length + NEW_LINE_LENGTH, MCL_NULL);
269  ASSERT_STATEMENT_CODE_MESSAGE(MCL_OK == return_code, string_destroy(&sub_boundary), return_code, "payload content_type couldn't be composed.");
270 
271  // Add blank line.
272  _add_blank_line(http_request, &payload_offset_local);
273 
274  // Add payload.
275  _add_payload(http_request, payload_copy_callback, user_context, payload, payload_size, &payload_offset_local);
276 
277  // Add blank line.
278  _add_blank_line(http_request, &payload_offset_local);
279 
280  // Add close sub_boundary.
281  return_code = _add_boundary(http_request->payload, &payload_offset_local, sub_boundary->buffer, MCL_CLOSE_BOUNDARY);
282  ASSERT_STATEMENT_CODE_MESSAGE(MCL_OK == return_code, string_destroy(&sub_boundary), return_code, "sub_boundary couldn't be composed.");
283 
284  // Add memory size to be used to payload_offset.
285  http_request->payload_offset = payload_offset_local;
286 
287  // Destroy local sub_boundary.
288  string_destroy(&sub_boundary);
289 
290  DEBUG_LEAVE("retVal = <%d>", MCL_OK);
291  return MCL_OK;
292 }
293 
295 {
296  DEBUG_ENTRY("http_request_t *http_request = <%p>", http_request)
297 
298  E_MCL_ERROR_CODE return_code;
299 
300  // Only 1 open boundary is necessary
301  mcl_size_t required_empty_size = OVERHEAD_FOR_BOUNDARY;
302  mcl_size_t payload_offset_local;
303 
304  // Check if the empty space in payload buffer is enough.If not so, resize payload buffer if possible.
305  return_code = _resize_payload_buffer_if_necessary(required_empty_size, http_request, MCL_FALSE);
306  ASSERT_CODE_MESSAGE(MCL_OK == return_code, return_code, "Inadequate memory in payload buffer for HTTP message.");
307 
308  payload_offset_local = http_request->payload_offset;
309 
310  // Add opening main boundary.
311  return_code = _add_boundary(http_request->payload, &payload_offset_local, http_request->boundary->buffer, MCL_OPEN_BOUNDARY);
312  ASSERT_CODE_MESSAGE(MCL_OK == return_code, return_code, "Boundary couldn't be composed.");
313 
314  // Add memory size to be used to payload_offset.
315  http_request->payload_offset = payload_offset_local;
316 
317  DEBUG_LEAVE("retVal = <%d>", MCL_OK);
318  return MCL_OK;
319 }
320 
321 E_MCL_ERROR_CODE http_request_start_tuple_sub_section(http_request_t *http_request, string_t *content_type, string_t *content_id, string_t **sub_boundary)
322 {
323  DEBUG_ENTRY("http_request_t *http_request = <%p>, string_t *content_type = <%p>, string_t *content_id = <%p>, string_t **sub_boundary = <%p>", http_request, content_type,
324  content_id, sub_boundary)
325 
326  E_MCL_ERROR_CODE return_code;
327  mcl_size_t payload_offset_local;
328 
329  // mcl_size_t content_type_line_length = http_header_names[HTTP_HEADER_CONTENT_TYPE].length + COLON_FORMAT_LENGTH + content_type->length + NEW_LINE_LENGTH;
330  mcl_size_t required_empty_size = 0;
331 
332  // Unused parameter.
333  (void)content_id;
334 
335  if (MCL_NULL == *sub_boundary)
336  {
337  // since it is NULL, a new subboundary will be generated and added to the reqeust for multipart/related line :
338  required_empty_size = OVERHEAD_FOR_TUPLE_SUBSECTION_WITH_BOUNDARY_DEFINITION + content_type->length;
339  }
340  else
341  {
342  required_empty_size = OVERHEAD_FOR_TUPLE_SUBSECTION + content_type->length;
343  }
344 
345  // Check if the empty space in payload buffer is enough.If not so, resize payload buffer if possible.
346  return_code = _resize_payload_buffer_if_necessary(required_empty_size, http_request, MCL_FALSE);
347  ASSERT_CODE_MESSAGE(MCL_OK == return_code, return_code, "Inadequate memory in payload buffer for HTTP message.");
348 
349  payload_offset_local = http_request->payload_offset;
350 
351  // Create sub_boundary if it is not created :
352  if (MCL_NULL == *sub_boundary)
353  {
354  return_code = _generate_random_boundary(sub_boundary);
355  ASSERT_CODE_MESSAGE(MCL_OK == return_code, return_code, "sub_boundary couldn't be composed.");
356 
357  // Add tuple content_type.
359  &payload_offset_local, CONTENT_TYPE_LINE_LENGTH, (*sub_boundary)->buffer);
360  ASSERT_CODE_MESSAGE(MCL_OK == return_code, return_code, "content_type couldn't be composed.");
361  }
362 
363  // Add open sub_boundary.
364  return_code = _add_boundary(http_request->payload, &payload_offset_local, (*sub_boundary)->buffer, MCL_OPEN_BOUNDARY);
365  ASSERT_CODE_MESSAGE(MCL_OK == return_code, return_code, "sub_boundary couldn't be composed.");
366 
367  // Add content_type.
368  return_code = _add_content_info(http_request, http_header_names[HTTP_HEADER_CONTENT_TYPE].buffer, content_type->buffer, &payload_offset_local,
370  ASSERT_CODE_MESSAGE(MCL_OK == return_code, return_code, "content_type couldn't be composed.");
371 
372  // Add blank line.
373  _add_blank_line(http_request, &payload_offset_local);
374 
375  // Add memory size to be used to payload_offset.
376  http_request->payload_offset = payload_offset_local;
377 
378  DEBUG_LEAVE("retVal = <%d>", MCL_OK);
379  return MCL_OK;
380 }
381 
383 {
384  DEBUG_ENTRY("http_request_t *http_request = <%p>, string_t **sub_boundary = <%p>", http_request, sub_boundary)
385 
386  E_MCL_ERROR_CODE return_code;
387  mcl_size_t payload_offset_local;
388  mcl_size_t required_empty_size = BOUNDARY_LINE_LENGTH + MCL_NULL_CHAR_SIZE;
389 
390  // Check if the empty space in payload buffer is enough. If not so, resize payload buffer if possible.
391  return_code = _resize_payload_buffer_if_necessary(required_empty_size, http_request, MCL_FALSE);
392  ASSERT_CODE_MESSAGE(MCL_OK == return_code, return_code, "Inadequate memory in payload buffer for HTTP message.");
393 
394  payload_offset_local = http_request->payload_offset;
395 
396  // Add close sub_boundary.
397  return_code = _add_boundary(http_request->payload, &payload_offset_local, sub_boundary->buffer, MCL_CLOSE_BOUNDARY);
398  ASSERT_CODE_MESSAGE(MCL_OK == return_code, return_code, "sub_boundary couldn't be composed.");
399 
400  // Add memory size to be used to payload_offset.
401  http_request->payload_offset = payload_offset_local;
402 
403  DEBUG_LEAVE("retVal = <%d>", MCL_OK);
404  return MCL_OK;
405 }
406 
407 E_MCL_ERROR_CODE http_request_add_raw_data(http_request_t *http_request, payload_copy_callback_t copy_callback, void *user_context, void *data, mcl_size_t data_size,
408  mcl_size_t *actual_written_size)
409 {
410  DEBUG_ENTRY("http_request_t *http_request = <%p>, payload_copy_callback_t copy_callback = <%p>, void *user_context = <%p>, void *data = <%p>, mcl_size_t data_size = <%u>, mcl_size_t *actual_written_size = <%p>",
411  http_request, copy_callback, user_context, data, data_size, actual_written_size)
412 
413  E_MCL_ERROR_CODE return_code;
414  mcl_size_t payload_offset_local;
415 
416  // Check if the empty space in payload buffer is enough.If not so, resize payload buffer if possible.
417  return_code = _resize_payload_buffer_if_necessary(data_size, http_request, MCL_FALSE);
418  ASSERT_CODE_MESSAGE(MCL_OK == return_code, return_code, "Inadequate memory in payload buffer for HTTP message.");
419 
420  payload_offset_local = http_request->payload_offset;
421 
422  // Add data.
423  _add_payload(http_request, copy_callback, user_context, (mcl_uint8_t *)data, data_size, &payload_offset_local);
424 
425  // save actually written count if requested:
426  if (MCL_NULL != actual_written_size)
427  {
428  *actual_written_size = payload_offset_local - http_request->payload_offset;
429  }
430 
431  // Add memory size to be used to payload_offset.
432  http_request->payload_offset = payload_offset_local;
433 
434  DEBUG_LEAVE("retVal = <%d>", MCL_OK);
435  return MCL_OK;
436 }
437 
439 {
440  DEBUG_ENTRY("http_request_t *http_request = <%p>", http_request)
441 
442  mcl_size_t empty_size = _get_available_space(http_request, 0);
443 
444  DEBUG_LEAVE("retVal = <%u>", empty_size);
445  return empty_size;
446 }
447 
449 {
450  DEBUG_ENTRY("http_request_t *http_request = <%p>", http_request)
451 
452  mcl_size_t empty_size = _get_available_space(http_request, OVERHEAD_FOR_TUPLE);
453 
454  DEBUG_LEAVE("retVal = <%u>", empty_size);
455  return empty_size;
456 }
457 
459 {
460  DEBUG_ENTRY("http_request_t *http_request = <%p>", http_request)
461 
462  // 5 is main and tuples opening and closing boudary count:
463  mcl_size_t empty_size = _get_available_space(http_request, OVERHEAD_FOR_SINGLE);
464 
465  DEBUG_LEAVE("retVal = <%u>", empty_size);
466  return empty_size;
467 }
468 
470 {
471  DEBUG_ENTRY("http_request_t *http_request = <%p>", http_request)
472 
473  E_MCL_ERROR_CODE return_code;
474  mcl_size_t required_empty_size = 2 * BOUNDARY_SIGN_LENGTH + BOUNDARY_LENGTH;
475 
476  // Check if the empty space in payload buffer is enough.If not so, resize only as much as required.
477  // If there is more memory space unused, release and shrink the payload buffer.
478  return_code = _resize_payload_buffer_if_necessary(required_empty_size, http_request, MCL_TRUE);
479  ASSERT_CODE_MESSAGE(MCL_OK == return_code, MCL_HTTP_REQUEST_FINALIZE_FAILED, "Inadequate memory in payload buffer for HTTP message.");
480 
481  // Add front sign of closing main boundary.
483  http_request->payload_offset += BOUNDARY_SIGN_LENGTH;
484 
485  // Add closing main boundary.
486  string_util_memcpy(&http_request->payload[http_request->payload_offset], http_request->boundary->buffer, BOUNDARY_LENGTH);
487  http_request->payload_offset += BOUNDARY_LENGTH;
488 
489  // Add back sign of closing main boundary.
491  http_request->payload_offset += BOUNDARY_SIGN_LENGTH;
492 
493  DEBUG_LEAVE("retVal = <%d>", MCL_OK);
494  return MCL_OK;
495 }
496 
498 {
499  DEBUG_ENTRY("http_request_t **http_request = <%p>", http_request)
500 
501  if (MCL_NULL != *http_request)
502  {
503  // Free http request with its members.
504  string_array_destroy(&((*http_request)->header));
505  string_destroy(&((*http_request)->uri));
506  string_destroy(&((*http_request)->boundary));
507  MCL_FREE((*http_request)->payload);
508  MCL_FREE(*http_request);
509 
510  MCL_DEBUG("Http request is destroyed successfully.");
511  }
512  else
513  {
514  MCL_DEBUG("Http request is already NULL.");
515  }
516 
517  DEBUG_LEAVE("retVal = void");
518 }
519 
521 {
522  mcl_size_t limit = (http_request->resize_enabled) ? http_request->max_http_payload_size : http_request->payload_size;
523 
524  // We do following check first to make sure the calculation is ok.
525  // It is for the case : payload_offset + overhead is larger than the MAX_SIZE
526  // and looped to a small value since it will exceeds the mcl_size_t limit.
527 
528  // MCL_MAX_SIZE is always greater than offset. Can be safely written :
529  if ((MCL_MAX_SIZE - http_request->payload_offset > overhead) && (limit > http_request->payload_offset + overhead))
530  {
531  // since we're sure now that the overhead+offset is less than the limit, we can extract it from the limit to calculate the empty size :
532  return limit - http_request->payload_offset - overhead;
533  }
534 
535  // else, it means there is no space.
536  return 0;
537 }
538 
540 {
541  DEBUG_ENTRY("string_t **boundary = <%p>", boundary)
542 
543  E_MCL_ERROR_CODE code;
544  mcl_size_t index;
546  ASSERT_CODE_MESSAGE(MCL_OK == code, code, "String initialize fail for boundary.");
547 
548  // Take (BOUNDARY_LENGTH) random characters from boundary_characters[] array and fill boundary buffer.
549  for (index = 0; index < BOUNDARY_LENGTH; index++)
550  {
551  mcl_uint32_t random_index = 0;
552  code = random_generate_number(&random_index);
553  if (MCL_OK == code)
554  {
555  (*boundary)->buffer[index] = boundary_characters[random_index % BOUNDARY_CHARACTER_COUNT];
556  }
557  else
558  {
559  string_destroy(boundary);
560  break;
561  }
562  }
563 
564  DEBUG_LEAVE("retVal = <%d>", code);
565  return code;
566 }
567 
568 static E_MCL_ERROR_CODE _add_boundary(mcl_uint8_t *payload, mcl_size_t *payload_offset, char *boundary, E_MCL_BOUNDARY_TYPE boundary_type)
569 {
570  DEBUG_ENTRY("mcl_uint8_t *payload = <%p>, mcl_size_t *payload_offset = <%p>, char *boundary = <%s>, E_MCL_BOUNDARY_TYPE boundary_type = <%d>", payload, payload_offset,
571  boundary, boundary_type)
572 
573  E_MCL_ERROR_CODE return_code;
574  char *boundary_format = MCL_NULL;
575  mcl_size_t boundary_line_total_length;
576 
577  // Boundary format selection for either open or close.
578  if (MCL_OPEN_BOUNDARY == boundary_type)
579  {
580  boundary_format = "--%s\r\n";
581  boundary_line_total_length = BOUNDARY_LINE_LENGTH;
582  }
583  else
584  {
585  boundary_format = "--%s--\r\n";
586  boundary_line_total_length = BOUNDARY_LINE_LENGTH + BOUNDARY_SIGN_LENGTH;
587  }
588 
589  return_code = string_util_snprintf((char *)&payload[*payload_offset], boundary_line_total_length + MCL_NULL_CHAR_SIZE, boundary_format, boundary);
590  ASSERT_CODE_MESSAGE(MCL_OK == return_code, return_code, "Boundary couldn't be composed.");
591  *payload_offset += boundary_line_total_length;
592 
593  DEBUG_LEAVE("retVal = <%d>", MCL_OK);
594  return MCL_OK;
595 }
596 
598 {
599  DEBUG_ENTRY("mcl_size_t required_empty_size = <%u>, http_request_t *http_request = <%p>, mcl_bool_t finalize = <%d>", required_empty_size, http_request, finalize)
600 
601  // Maximum allowed available size can be used after extending the payload buffer up to MAX_PAYLOAD_SIZE.
602  mcl_size_t max_allowed_available_size = 0;
603  if (MCL_TRUE == http_request->resize_enabled)
604  {
605  max_allowed_available_size = http_request->max_http_payload_size - http_request->payload_offset;
606  }
607  else
608  {
609  // since resize is not available, available size calculation must be done on current payload size :
610  max_allowed_available_size = http_request->payload_size - http_request->payload_offset;
611  }
612 
613  if (MCL_TRUE == finalize)
614  {
615  // If we need extra memory space, extend payload buffer and If there is more space unused, then shrink the payload size.
616  // else return no more space error.
617  if (required_empty_size <= max_allowed_available_size)
618  {
619  if (MCL_TRUE == http_request->resize_enabled)
620  {
621  MCL_RESIZE(http_request->payload, http_request->payload_offset + required_empty_size);
622  ASSERT_CODE_MESSAGE(MCL_NULL != http_request->payload, MCL_OUT_OF_MEMORY, "http_request->payload couldn't be resized as required_empty_size!");
623  http_request->payload_size = http_request->payload_offset + required_empty_size;
624  }
625  else
626  {
627  MCL_DEBUG("Resizing is disabled. Not shrinking extra payload space.");
628  }
629  }
630  else
631  {
632  // if the empty space is even lower than the required_empty_size, return error code.
633  MCL_ERROR_RETURN(MCL_HTTP_REQUEST_NO_MORE_SPACE, "Inadequate memory in payload buffer for HTTP message.");
634  }
635  }
636  else
637  {
638  // Current available size.
639  mcl_size_t available_size = http_request->payload_size - http_request->payload_offset;
640 
641  // Check if any resize operation is necessary (required_empty_size > available_size).
642  if (required_empty_size > available_size)
643  {
644  // +1 is to round floating number to a next upper integer.
645  mcl_size_t new_size = 0;
646  if (http_request->payload_size == 0)
647  {
648  new_size = (mcl_size_t)(((1.0 * required_empty_size) * GROWTH_FACTOR) + 1.0);
649  }
650  else
651  {
652  new_size = (mcl_size_t)(((1.0 * required_empty_size / http_request->payload_size + 1.0) * GROWTH_FACTOR) * http_request->payload_size);
653  }
654 
655  if ((new_size <= http_request->max_http_payload_size) && http_request->resize_enabled)
656  {
657  MCL_RESIZE(http_request->payload, new_size);
658  ASSERT_CODE_MESSAGE(MCL_NULL != http_request->payload, MCL_OUT_OF_MEMORY, "http_request->payload couldn't be resized as new_size!");
659  http_request->payload_size = new_size;
660  }
661  else if ((required_empty_size <= max_allowed_available_size) && http_request->resize_enabled)
662  {
663  // if new_size is higher than MAX_PAYLOAD_SIZE, check if the empty space is enough for only required_empty_size, than resize with MAX_PAYLOAD_SIZE.
664  MCL_RESIZE(http_request->payload, http_request->max_http_payload_size);
665  ASSERT_CODE_MESSAGE(MCL_NULL != http_request->payload, MCL_OUT_OF_MEMORY, "http_request->payload couldn't be resized as MAX_PAYLOAD_SIZE!");
666  http_request->payload_size = http_request->max_http_payload_size;
667  }
668  else
669  {
670  // if the empty space is even lower than the required_empty_size, return error code.
671  MCL_ERROR_RETURN(MCL_HTTP_REQUEST_NO_MORE_SPACE, "Inadequate memory in payload buffer for HTTP message.");
672  }
673  }
674  }
675 
676  DEBUG_LEAVE("retVal = <%d>", MCL_OK);
677  return MCL_OK;
678 }
679 
680 static void _add_meta(string_t *meta, http_request_t *http_request, mcl_size_t *payload_offset)
681 {
682  DEBUG_ENTRY("string_t *meta = <%p>, http_request_t *http_request = <%p>, mcl_size_t *payload_offset = <%p>", meta, http_request, payload_offset)
683 
684  // Compose meta_string.
685  string_util_memcpy(&http_request->payload[*payload_offset], (mcl_uint8_t *)meta->buffer, meta->length);
686  *payload_offset += meta->length;
687 
688  // Add blank line.
689  _add_blank_line(http_request, payload_offset);
690 
691  DEBUG_LEAVE("retVal = void");
692 }
693 
694 static void _add_payload(http_request_t *http_request, payload_copy_callback_t payload_copy_callback, void *user_context, mcl_uint8_t *payload, mcl_size_t payload_size,
695  mcl_size_t *payload_offset)
696 {
697  DEBUG_ENTRY("http_request_t *http_request = <%p>, payload_copy_callback_t payload_copy_callback = <%p>, void *user_context = <%p>, mcl_uint8_t *payload = <%p>, mcl_size_t payload_size = <%u>, mcl_size_t *payload_offset = <%p>",
698  http_request, payload_copy_callback, user_context, payload, payload_size, payload_offset)
699 
700  // Compose payload.
701  mcl_size_t count = payload_copy_callback(&http_request->payload[*payload_offset], payload, payload_size, user_context);
702 
703  // Count might be different than the payload_size we requested:
704  *payload_offset += count;
705 
706  DEBUG_LEAVE("retVal = void");
707 }
708 
709 static E_MCL_ERROR_CODE _add_content_info(http_request_t *http_request, char *content_info_name, char *content_info_value, mcl_size_t *payload_offset,
710  mcl_size_t content_info_line_length, char *sub_boundary)
711 {
712  DEBUG_ENTRY("http_request_t *http_request = <%p>, char *content_info_name = <%s>, char *content_info_value = <%s>, mcl_size_t *payload_offset = <%p>, mcl_size_t content_info_line_length = <%u>, char *sub_boundary = <%s>",
713  http_request, content_info_name, content_info_value, payload_offset, content_info_line_length, sub_boundary)
714 
715  E_MCL_ERROR_CODE return_code;
716  char *content_info_format = MCL_NULL;
717 
718  if (MCL_NULL == sub_boundary)
719  {
720  // Meta and payload format.
721  content_info_format = "%s: %s\r\n";
722  }
723  else
724  {
725  // Multipart format.
726  content_info_format = "%s: %s;boundary=%s\r\n";
727  }
728 
729  return_code = string_util_snprintf((char *)&http_request->payload[*payload_offset], content_info_line_length + MCL_NULL_CHAR_SIZE, (const char *)content_info_format,
730  content_info_name, content_info_value, sub_boundary);
731  ASSERT_CODE_MESSAGE(MCL_OK == return_code, return_code, "Content info couldn't be composed.");
732  *payload_offset += content_info_line_length;
733 
734  DEBUG_LEAVE("retVal = <%d>", MCL_OK);
735  return MCL_OK;
736 }
737 
738 static void _add_blank_line(http_request_t *http_request, mcl_size_t *payload_offset)
739 {
740  DEBUG_ENTRY("http_request_t *http_request = <%p>, mcl_size_t *payload_offset = <%p>", http_request, payload_offset)
741 
742  // Compose blank line.
743  string_util_memcpy(&http_request->payload[*payload_offset], NEW_LINE, NEW_LINE_LENGTH);
744  *payload_offset += NEW_LINE_LENGTH;
745  http_request->payload[*payload_offset] = MCL_NULL_CHAR;
746 
747  DEBUG_LEAVE("retVal = void");
748 }
HTTP Request Handle.
Definition: http_request.h:79
E_MCL_BOUNDARY_TYPE
Open and close boundary types.
Definition: http_request.c:24
static void _add_payload(http_request_t *http_request, payload_copy_callback_t payload_copy_callback, void *user_context, mcl_uint8_t *payload, mcl_size_t payload_size, mcl_size_t *payload_offset)
Definition: http_request.c:694
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
Memory module header file.
static void _add_meta(string_t *meta, http_request_t *http_request, mcl_size_t *payload_offset)
Definition: http_request.c:680
mcl_size_t OVERHEAD_FOR_TUPLE
Definition: http_request.c:38
string_array_t * header
Header of http request.
Definition: http_request.h:81
#define DEBUG_LEAVE(...)
Definition: log_util.h:81
mcl_size_t(* payload_copy_callback_t)(void *destination, void *source, mcl_size_t size, void *user_context)
Definition: http_request.h:93
#define CONTENT_ID_HEADER_LENGTH
Definition: http_request.h:43
#define DEBUG_ENTRY(...)
Definition: log_util.h:80
mcl_size_t OVERHEAD_FOR_TUPLE_SUBSECTION
Definition: http_request.c:65
#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
static E_MCL_ERROR_CODE _add_content_info(http_request_t *http_request, char *content_info_name, char *content_info_value, mcl_size_t *payload_offset, mcl_size_t content_info_line_length, char *sub_boundary)
Definition: http_request.c:709
#define MCL_TRUE
Definition: mcl_common.h:54
E_MCL_ERROR_CODE http_request_start_tuple_sub_section(http_request_t *http_request, string_t *content_type, string_t *content_id, string_t **sub_boundary)
To start a sub tuple section inside of the http request body.
Definition: http_request.c:321
char * buffer
Buffer of string handle.
Definition: string_type.h:45
mcl_size_t http_request_get_available_space_for_single(http_request_t *http_request)
To be used to get the available space left in the request buffer in order to add a single...
Definition: http_request.c:458
void string_array_destroy(string_array_t **array)
Destroys the string array handle.
Definition: string_array.c:174
E_MCL_ERROR_CODE http_request_add_raw_data(http_request_t *http_request, payload_copy_callback_t copy_callback, void *user_context, void *data, mcl_size_t data_size, mcl_size_t *actual_written_size)
To add raw data into an http_request.
Definition: http_request.c:407
#define MCL_DEBUG(...)
Definition: log_util.h:70
#define MCL_FALSE
MCL bool type.
Definition: mcl_common.h:53
char * boundary_characters
Definition: http_request.c:30
#define MCL_MALLOC(bytes)
Definition: memory.h:120
E_MCL_ERROR_CODE http_request_start_tuple(http_request_t *http_request)
To start a new tuple structure inside the http request body.
Definition: http_request.c:294
Log utility module header file.
static mcl_size_t _get_available_space(http_request_t *http_request, mcl_size_t overhead)
Definition: http_request.c:520
static E_MCL_ERROR_CODE _generate_random_boundary(string_t **boundary)
Definition: http_request.c:539
#define CONTENT_TYPE_HEADER_LENGTH
Definition: http_request.h:40
E_MCL_ERROR_CODE
MCL Error code definitions. Every function returning an error code uses this enum values...
Definition: mcl_common.h:137
static E_MCL_ERROR_CODE _resize_payload_buffer_if_necessary(mcl_size_t required_empty_size, http_request_t *http_request, mcl_bool_t finalize)
Definition: http_request.c:597
E_MCL_ERROR_CODE http_request_end_tuple_sub_section(http_request_t *http_request, string_t *sub_boundary)
To end a sub tuple section previously started with http_request_start_tuple_sub_section().
Definition: http_request.c:382
mcl_size_t max_http_payload_size
Maximum http payload size of http request.
Definition: http_request.h:88
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
#define MCL_RESIZE(p, bytes)
Definition: memory.h:124
Content type is multipart mixed.
Definition: data_types.h:317
static E_MCL_ERROR_CODE _add_boundary(mcl_uint8_t *payload, mcl_size_t *payload_offset, char *boundary, E_MCL_BOUNDARY_TYPE boundary_type)
Definition: http_request.c:568
#define MCL_FREE(p)
Definition: memory.h:125
Content type is multipart related.
Definition: data_types.h:318
uint32_t mcl_uint32_t
Definition: mcl_common.h:45
#define ASSERT_STATEMENT_CODE_MESSAGE(condition, statement, return_code,...)
Definition: definitions.h:121
E_MCL_HTTP_METHOD
HTTP Method Types.
Definition: http_request.h:62
#define NEW_LINE_LENGTH
Definition: http_request.h:46
There is no more space left in http message buffer. No data has been written in current call...
Definition: mcl_common.h:216
E_MCL_ERROR_CODE http_request_add_header(http_request_t *http_request, string_t *header_name, string_t *header_value)
To be used to add an HTTP header to the request with it&#39;s value.
Definition: http_request.c:131
E_MCL_ERROR_CODE string_compare(const string_t *string, const string_t *other)
Compare the contents of two string_t&#39;s.
Definition: string_type.c:129
mcl_size_t MCL_MAX_SIZE
Definition: http_request.c:31
uint8_t mcl_uint8_t
Definition: mcl_common.h:43
#define BOUNDARY_LINE_LENGTH
Definition: http_request.h:51
void string_util_memcpy(void *destination, const void *source, mcl_size_t count)
Standard library memcpy wrapper.
Definition: string_util.c:131
string_t content_type_values[CONTENT_TYPE_VALUES_END]
Definition: data_types.c:94
#define ASSERT_CODE_MESSAGE(condition, return_code,...)
Definition: definitions.h:105
string_t http_header_names[HTTP_HEADER_NAMES_END]
E_MCL_ERROR_CODE http_request_finalize(http_request_t *http_request)
Adds closing boundary to the payload and resizes the payload buffer to release unused memory space...
Definition: http_request.c:469
mcl_size_t OVERHEAD_FOR_SINGLE
Definition: http_request.c:46
Definitions module header file.
mcl_size_t http_request_get_available_space_for_tuple(http_request_t *http_request)
To be used to get the available space left in the request buffer in order to add a tuple...
Definition: http_request.c:448
Adding final closing boundary and Authentication header is failed.
Definition: mcl_common.h:220
Http content type header.
mcl_size_t payload_offset
Payload offset of http request.
Definition: http_request.h:84
Http user agent header.
E_MCL_ERROR_CODE string_initialize(const string_t *other, string_t **string)
Initializes an string_t object with another one.
Definition: string_type.c:24
E_MCL_ERROR_CODE random_generate_number(mcl_uint32_t *random_number)
Generates random integer number.
Definition: random.c:61
mcl_size_t length
Length of buffer.
Definition: string_type.h:46
Opening boundary.
Definition: http_request.c:27
Closing boundary.
Definition: http_request.c:26
#define NEW_LINE
Definition: http_request.h:47
#define BOUNDARY_LENGTH
Definition: http_request.h:31
#define GROWTH_FACTOR
Definition: http_request.h:34
mcl_size_t OVERHEAD_FOR_TUPLE_SUBSECTION_WITH_BOUNDARY_DEFINITION
Definition: http_request.c:58
Http content id header.
size_t mcl_size_t
Definition: mcl_common.h:38
HTTP request module header file.
void http_request_destroy(http_request_t **http_request)
To destroy the HTTP Request Handler.
Definition: http_request.c:497
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
mcl_size_t OVERHEAD_FOR_BOUNDARY
Definition: http_request.c:51
#define BOUNDARY_SIGN_LENGTH
Definition: http_request.h:24
mcl_bool_t resize_enabled
The state or condition of being resizable.
Definition: http_request.h:89
Random module header file.
#define BOUNDARY_CHARACTER_COUNT
Definition: http_request.h:32
Memory allocation fail.
Definition: mcl_common.h:143
E_MCL_ERROR_CODE http_request_add_single(http_request_t *http_request, string_t *content_type, string_t *content_id, string_t *meta_string)
To be used to add a single to the HTTP Request.
Definition: http_request.c:172
#define MCL_NULL
Definition: definitions.h:24
string_t * boundary
Boundary of http request.
Definition: http_request.h:87
mcl_size_t http_request_get_available_space_for_raw_data(http_request_t *http_request)
To be used to get the available space left in the request buffer in order to add a raw data...
Definition: http_request.c:438
E_MCL_ERROR_CODE http_request_initialize(E_MCL_HTTP_METHOD method, string_t *uri, mcl_size_t header_size, mcl_size_t payload_size, mcl_bool_t resize_enabled, string_t *user_agent, mcl_size_t max_http_payload_size, http_request_t **http_request)
HTTP Request Initializer.
Definition: http_request.c:79
mcl_size_t payload_size
Payload size of http request.
Definition: http_request.h:83
E_MCL_ERROR_CODE http_request_add_tuple(http_request_t *http_request, string_t *meta, string_t *meta_content_type, payload_copy_callback_t payload_copy_callback, void *user_context, void *payload, mcl_size_t payload_size, string_t *payload_content_type)
To be used to add a tuple to the HTTP Request.
Definition: http_request.c:214
#define MCL_NULL_CHAR_SIZE
Definition: definitions.h:27
#define BOUNDARY_SIGN
Definition: http_request.h:25
#define CONTENT_TYPE_LINE_LENGTH
Definition: http_request.h:37
static void _add_blank_line(http_request_t *http_request, mcl_size_t *payload_offset)
Definition: http_request.c:738
#define MCL_NULL_CHAR
Definition: definitions.h:26
Data types module header file.
#define MCL_ERROR_RETURN(return_value,...)
Definition: definitions.h:69