data_lake_json.c
Go to the documentation of this file.
1 
9 #include "data_lake_json.h"
10 #include "mcl_core/mcl_memory.h"
12 #include "mcl_core/mcl_json_util.h"
13 
14 static const char generate_url_body_pre_path_list[] = "{\"paths\":[";
15 static const char generate_url_body_pre_path_object[] = "{\"path\":\"";
16 static const char generate_url_body_post_path_object[] = "\"}";
17 static const char object_urls_key[] = "objectUrls";
18 static const char signed_url_key[] = "signedUrl";
19 static const char object_path_key[] = "path";
20 static const char subtenant_id_key[] = ",\"subtenantId\":\"";
21 
22 #define GENERATE_URL_BODY_PRE_PATH_LIST_LENGTH (sizeof(generate_url_body_pre_path_list) - MCL_NULL_CHAR_SIZE)
23 #define GENERATE_URL_BODY_POST_PATH_LIST_LENGTH (sizeof("]}") - MCL_NULL_CHAR_SIZE)
24 #define GENERATE_URL_BODY_PRE_PATH_OBJECT_LENGTH (sizeof(generate_url_body_pre_path_object) - MCL_NULL_CHAR_SIZE)
25 #define GENERATE_URL_BODY_POST_PATH_OBJECT_LENGTH (sizeof(generate_url_body_post_path_object) - MCL_NULL_CHAR_SIZE)
26 #define SUBTENANT_KEY_LENGTH (sizeof(subtenant_id_key) - MCL_NULL_CHAR_SIZE)
27 #define SUBTENANT_OVERHEAD (SUBTENANT_KEY_LENGTH + sizeof("\"") - MCL_NULL_CHAR_SIZE)
28 #define DELIMITER_LENGTH 1
29 #define SLASH_LENGTH 1
30 #define SINGLE_CHARACTER_SIZE 1
31 
32 // Calculate total size for object paths.
33 static mcl_size_t _calculate_total_path_size(data_lake_object_t **object_array, mcl_size_t array_size, mcl_size_t *valid_path_count);
34 
35 // Find matching object and set signed url.
36 static mcl_error_t _find_matching_object(mcl_json_t *object_url_item, data_lake_object_t **object_array, mcl_size_t array_size,
37  const char *object_path, mcl_size_t compare_size);
38 
39 // Function to check if there is any object with path but without signed url.
40 static mcl_error_t _check_signed_urls(data_lake_object_t **object_array, mcl_size_t array_size);
41 
42 // Function to calculate body size for request to generate upload urls.
44  mcl_size_t array_size, mcl_size_t client_id_length, mcl_size_t subtenant_id_length);
45 
46 mcl_error_t data_lake_json_from_objects(data_lake_object_t **object_array, mcl_size_t array_size, const char *client_id, const char *subtenant_id, char **json)
47 {
48  mcl_error_t code = MCL_OK;
49  mcl_size_t index;
50  mcl_bool_t is_first_object = MCL_TRUE;
51  mcl_size_t client_id_length;
52  mcl_size_t subtenant_id_length = 0;
53  mcl_size_t body_size;
54  char *position = MCL_NULL;
55 
56  MCL_DEBUG_ENTRY("data_lake_object_t *object_array = <%p>, mcl_size_t array_size = <%lu>, const char *client_id = <%p>, "\
57  "const char *subtenant_id = <%p>, char **json = <%p>", object_array, array_size, client_id, subtenant_id, json);
58 
59  client_id_length = mcl_string_util_strlen(client_id);
60 
61  if (MCL_NULL != subtenant_id)
62  {
63  subtenant_id_length = mcl_string_util_strlen(subtenant_id);
64  }
65 
66  body_size = _data_lake_json_get_body_size_generate_upload_urls(object_array, array_size, client_id_length, subtenant_id_length);
67 
68  if (0 == body_size)
69  {
70  code = MCL_INVALID_PARAMETER;
71  }
72  else
73  {
74  *json = MCL_MALLOC(body_size + MCL_NULL_CHAR_SIZE);
75 
76  if (MCL_NULL == *json)
77  {
78  code = MCL_OUT_OF_MEMORY;
79  }
80  else
81  {
82  position = *json;
83  }
84  }
85 
86  if (MCL_OK == code)
87  {
88  // Prepare payload.
91 
92  // Array of paths.
93  for (index = 0; (index < array_size) && (MCL_OK == code); ++index)
94  {
95  mcl_size_t path_length;
96 
97  if (MCL_NULL == object_array[index]->path)
98  {
99  continue;
100  }
101 
102  if (MCL_FALSE == is_first_object)
103  {
105  position += DELIMITER_LENGTH;
106  }
107 
110 
111  mcl_string_util_memcpy(position, client_id, client_id_length);
112  position += client_id_length;
113 
114  mcl_string_util_memcpy(position, "/", SLASH_LENGTH);
115  position += SLASH_LENGTH;
116 
117  path_length = mcl_string_util_strlen(object_array[index]->path);
118  mcl_string_util_memcpy(position, object_array[index]->path, path_length);
119  position += path_length;
120 
123 
124  if (MCL_TRUE == is_first_object)
125  {
126  is_first_object = MCL_FALSE;
127  }
128  }
129 
130  // Finish array.
132  ++position;
133 
134  // Add subtenant id.
135  if (0 != subtenant_id_length)
136  {
138  position += SUBTENANT_KEY_LENGTH;
139 
140  mcl_string_util_memcpy(position, subtenant_id, subtenant_id_length);
141  position += subtenant_id_length;
142 
144  ++position;
145  }
146 
147  // Finish json.
149  (*json)[body_size] = MCL_NULL_CHAR;
150  }
151 
152  MCL_DEBUG_LEAVE("retVal = <%d>", code);
153  return code;
154 }
155 
157  mcl_size_t json_size, mcl_size_t client_id_length)
158 {
159  mcl_error_t code = MCL_OK;
160  mcl_size_t index;
161  mcl_size_t object_urls_array_size = 0;
162  mcl_json_t *response_json = MCL_NULL;
163  mcl_json_t *object_urls_array = MCL_NULL;
164  mcl_size_t path_overhead_length = client_id_length + SLASH_LENGTH;
165 
166  MCL_DEBUG_ENTRY("data_lake_object_t **object_array = <%p>, mcl_size_t array_size = <%lu>, char *json = <%p>, "\
167  "mcl_size_t json_size = <%lu>, mcl_size_t client_id_length = <%lu>", object_array, array_size, json, json_size, client_id_length);
168 
169  if (0 == json_size)
170  {
171  code = MCL_INVALID_PARAMETER;
172  }
173 
174  if (MCL_OK == code)
175  {
176  // Parse json.
177  code = mcl_json_util_parse(json, json_size, &response_json);
178  }
179 
180  if (MCL_OK == code)
181  {
182  code = mcl_json_util_get_object_item(response_json, object_urls_key, &object_urls_array);
183  }
184 
185  if (MCL_OK == code)
186  {
187  code = mcl_json_util_get_array_size(object_urls_array, &object_urls_array_size);
188  }
189 
190  for (index = 0; (index < object_urls_array_size) && (MCL_OK == code); ++index)
191  {
192  mcl_size_t object_path_length;
193  mcl_json_t *object_url_item = MCL_NULL;
194  mcl_json_t *object_path_json = MCL_NULL;
195  char *object_path = MCL_NULL;
196 
197  code = mcl_json_util_get_array_item(object_urls_array, (int) index, &object_url_item);
198 
199  if (MCL_OK == code)
200  {
201  code = mcl_json_util_get_object_item(object_url_item, object_path_key, &object_path_json);
202  }
203 
204  if (MCL_OK == code)
205  {
206  code = mcl_json_util_get_string(object_path_json, &object_path);
207  }
208 
209  if (MCL_OK == code)
210  {
211  object_path_length = mcl_string_util_strlen(object_path);
212  }
213 
214  if (MCL_OK == code)
215  {
216  if (object_path_length > path_overhead_length)
217  {
218  // Adding MCL_NULL_CHAR_SIZE to compare with null character.
219  _find_matching_object(object_url_item, object_array, array_size, object_path + path_overhead_length,
220  (object_path_length - path_overhead_length) + MCL_NULL_CHAR_SIZE);
221  }
222  else
223  {
224  MCL_WARN("Received invalid path %s", object_path);
225  }
226  }
227 
228  MCL_FREE(object_path);
229  }
230 
231  // Clean up.
232  mcl_json_util_destroy(&response_json);
233 
234  // Check signed urls.
235  if (MCL_OK == code)
236  {
237  code = _check_signed_urls(object_array, array_size);
238  }
239 
240  MCL_DEBUG_LEAVE("retVal = <%d>", code);
241  return code;
242 }
243 
244 static mcl_size_t _calculate_total_path_size(data_lake_object_t **object_array, mcl_size_t array_size, mcl_size_t *valid_path_count)
245 {
246  mcl_size_t total_path_size = 0;
247  mcl_size_t index;
248  *valid_path_count = 0;
249 
250  MCL_DEBUG_ENTRY("data_lake_object_array **object_array = <%p>, mcl_size_t array_size = <%lu>, mcl_size_t *valid_path_count = <%p>",
251  object_array, array_size, valid_path_count);
252 
253  for (index = 0; index < array_size; ++index)
254  {
255  if (MCL_NULL == object_array[index]->path)
256  {
257  MCL_WARN("Data lake object <%p> has no path to request signed URL.", object_array[index]);
258  }
259  else
260  {
261  ++(*valid_path_count);
262  total_path_size += mcl_string_util_strlen(object_array[index]->path);
263  }
264  }
265 
266  MCL_DEBUG_LEAVE("retVal = <%lu>", total_path_size);
267  return total_path_size;
268 }
269 
270 static mcl_error_t _find_matching_object(mcl_json_t *object_url_item, data_lake_object_t **object_array, mcl_size_t array_size,
271  const char *object_path, mcl_size_t compare_size)
272 {
273  mcl_size_t object_array_index;
274  mcl_error_t code = MCL_OK;
275 
276  for (object_array_index = 0; (object_array_index < array_size) && (MCL_OK == code); ++object_array_index)
277  {
278  char *signed_url = MCL_NULL;
279  mcl_json_t *signed_url_json = MCL_NULL;
280 
281  // If signed url is not NULL, it is already set.
282  if (MCL_NULL != object_array[object_array_index]->signed_url)
283  {
284  continue;
285  }
286 
287  // Compare with + MCL_NULL_CHAR_SIZE to include NULL character.
288  if (MCL_OK == mcl_string_util_strncmp(object_path, object_array[object_array_index]->path, compare_size))
289  {
290  code = mcl_json_util_get_object_item(object_url_item, signed_url_key, &signed_url_json);
291 
292  if (MCL_OK == code)
293  {
294  code = mcl_json_util_get_string(signed_url_json, &signed_url);
295  }
296 
297  if (MCL_OK == code)
298  {
299  object_array[object_array_index]->signed_url = signed_url;
300  }
301 
302  break;
303  }
304  }
305 
306  MCL_DEBUG_LEAVE("retVal = <%d>", code);
307  return code;
308 }
309 
311 {
312  mcl_error_t code = MCL_OK;
313  mcl_size_t index;
314  MCL_DEBUG_ENTRY("data_lake_object_t **object_array = <%p>, mcl_size_t array_size = <%lu>", object_array, array_size);
315 
316  for (index = 0; index < array_size; ++index)
317  {
318  if ((MCL_NULL != object_array[index]->path) && (MCL_NULL == object_array[index]->signed_url))
319  {
321  }
322  }
323 
324  MCL_DEBUG_LEAVE("retVal = <%d>", code);
325  return code;
326 }
327 
329  mcl_size_t client_id_length, mcl_size_t subtenant_id_length)
330 {
331  mcl_size_t total_path_length;
332  mcl_size_t valid_path_count;
333  mcl_size_t path_overhead_length;
334  mcl_size_t body_size;
335 
336  MCL_DEBUG_ENTRY("data_lake_object_t **object_array = <%p>, mcl_size_t array_size = <%lu>, mcl_size_t client_id_length = <%lu>, "\
337  "mcl_size_t subtenant_id_length = <%lu>", object_array, array_size, client_id_length, subtenant_id_length);
338 
339  total_path_length = _calculate_total_path_size(object_array, array_size, &valid_path_count);
340 
341  if (0 == valid_path_count)
342  {
343  body_size = 0;
344  }
345  else
346  {
347  path_overhead_length = client_id_length + SLASH_LENGTH;
349  body_size += (GENERATE_URL_BODY_PRE_PATH_OBJECT_LENGTH + GENERATE_URL_BODY_POST_PATH_OBJECT_LENGTH + path_overhead_length) * valid_path_count;
350  body_size += total_path_length + ((valid_path_count - 1) * DELIMITER_LENGTH);
351 
352  if (0 != subtenant_id_length)
353  {
354  body_size += SUBTENANT_OVERHEAD;
355  body_size += subtenant_id_length;
356  }
357  }
358 
359  MCL_DEBUG_LEAVE("retVal = <%lu>", body_size);
360  return body_size;
361 }
#define GENERATE_URL_BODY_POST_PATH_OBJECT_LENGTH
char * signed_url
Signed URL for the object.
size_t mcl_size_t
static const char signed_url_key[]
static mcl_error_t _find_matching_object(mcl_json_t *object_url_item, data_lake_object_t **object_array, mcl_size_t array_size, const char *object_path, mcl_size_t compare_size)
MCL_OK
void mcl_json_t
static const char generate_url_body_post_path_object[]
mcl_int32_t mcl_error_t
static const char generate_url_body_pre_path_object[]
static const char generate_url_body_pre_path_list[]
#define SUBTENANT_KEY_LENGTH
#define MCL_DEBUG_ENTRY(...)
MCL_CORE_EXPORT mcl_error_t mcl_json_util_parse(const char *json_string, mcl_size_t buffer_size, mcl_json_t **root)
#define MCL_FALSE
mcl_error_t data_lake_json_match_signed_urls_with_objects(data_lake_object_t **object_array, mcl_size_t array_size, char *json, mcl_size_t json_size, mcl_size_t client_id_length)
MCL_CORE_EXPORT mcl_size_t mcl_string_util_strlen(const char *buffer)
MCL_CORE_EXPORT void mcl_json_util_destroy(mcl_json_t **root)
#define MCL_NULL
mcl_error_t data_lake_json_from_objects(data_lake_object_t **object_array, mcl_size_t array_size, const char *client_id, const char *subtenant_id, char **json)
static const char subtenant_id_key[]
#define SLASH_LENGTH
#define SUBTENANT_OVERHEAD
#define MCL_FREE(p)
static const char object_path_key[]
MCL_CORE_EXPORT mcl_error_t mcl_json_util_get_object_item(mcl_json_t *json_parent, const char *child_name, mcl_json_t **json_child)
#define GENERATE_URL_BODY_PRE_PATH_OBJECT_LENGTH
MCL_CORE_EXPORT void mcl_string_util_memcpy(void *destination, const void *source, mcl_size_t count)
Data lake json module header file.
#define GENERATE_URL_BODY_POST_PATH_LIST_LENGTH
#define GENERATE_URL_BODY_PRE_PATH_LIST_LENGTH
mcl_uint8_t mcl_bool_t
static mcl_error_t _check_signed_urls(data_lake_object_t **object_array, mcl_size_t array_size)
Could not get signed url for all object paths.
static const char object_urls_key[]
MCL_OUT_OF_MEMORY
#define MCL_NULL_CHAR_SIZE
#define MCL_MALLOC(bytes)
#define DELIMITER_LENGTH
MCL_CORE_EXPORT mcl_error_t mcl_json_util_get_array_item(mcl_json_t *array, int index, mcl_json_t **item)
MCL_INVALID_PARAMETER
#define MCL_DEBUG_LEAVE(...)
#define MCL_TRUE
MCL_CORE_EXPORT mcl_error_t mcl_string_util_strncmp(const char *string_1, const char *string_2, mcl_size_t count)
static mcl_size_t _calculate_total_path_size(data_lake_object_t **object_array, mcl_size_t array_size, mcl_size_t *valid_path_count)
MCL_CORE_EXPORT mcl_error_t mcl_json_util_get_array_size(mcl_json_t *array, mcl_size_t *size)
#define MCL_NULL_CHAR
static mcl_size_t _data_lake_json_get_body_size_generate_upload_urls(data_lake_object_t **object_array, mcl_size_t array_size, mcl_size_t client_id_length, mcl_size_t subtenant_id_length)
#define MCL_WARN(...)
#define SINGLE_CHARACTER_SIZE
MCL_CORE_EXPORT mcl_error_t mcl_json_util_get_string(mcl_json_t *json, char **string_value)