diff options
author | Martin Schanzenbach <mschanzenbach@posteo.de> | 2016-05-04 17:18:02 +0000 |
---|---|---|
committer | Martin Schanzenbach <mschanzenbach@posteo.de> | 2016-05-04 17:18:02 +0000 |
commit | a44744499d8f3df64cc1d15cd6b40b4b0e4a3683 (patch) | |
tree | 27621a6ee20cbe8e344ffdc18c05754e67d67bf3 /src/jsonapi/jsonapi_document.c | |
parent | ca11046195a840932edb04900669a38cd60ae682 (diff) | |
download | gnunet-a44744499d8f3df64cc1d15cd6b40b4b0e4a3683.tar.gz gnunet-a44744499d8f3df64cc1d15cd6b40b4b0e4a3683.zip |
Update jsonapi to current specs, refactor
Diffstat (limited to 'src/jsonapi/jsonapi_document.c')
-rw-r--r-- | src/jsonapi/jsonapi_document.c | 374 |
1 files changed, 374 insertions, 0 deletions
diff --git a/src/jsonapi/jsonapi_document.c b/src/jsonapi/jsonapi_document.c new file mode 100644 index 000000000..4837ee2be --- /dev/null +++ b/src/jsonapi/jsonapi_document.c | |||
@@ -0,0 +1,374 @@ | |||
1 | |||
2 | #include "platform.h" | ||
3 | #include "gnunet_util_lib.h" | ||
4 | #include "gnunet_json_lib.h" | ||
5 | #include "jsonapi_objects.h" | ||
6 | |||
7 | /** | ||
8 | * Get a JSON API object resource count | ||
9 | * | ||
10 | * @param resp the JSON API object | ||
11 | * @return the number of resources | ||
12 | */ | ||
13 | int | ||
14 | GNUNET_JSONAPI_document_resource_count (struct GNUNET_JSONAPI_Document *doc) | ||
15 | { | ||
16 | return doc->res_count; | ||
17 | } | ||
18 | |||
19 | /** | ||
20 | * Get a JSON API object resource by index | ||
21 | * | ||
22 | * @param resp the JSON API object | ||
23 | * @param idx index of the resource | ||
24 | * @return the resource | ||
25 | */ | ||
26 | struct GNUNET_JSONAPI_Resource* | ||
27 | GNUNET_JSONAPI_document_get_resource (struct GNUNET_JSONAPI_Document *doc, | ||
28 | int idx) | ||
29 | { | ||
30 | struct GNUNET_JSONAPI_Resource *res; | ||
31 | int i; | ||
32 | |||
33 | if ((0 == doc->res_count) || | ||
34 | (idx >= doc->res_count)) | ||
35 | return NULL; | ||
36 | res = doc->res_list_head; | ||
37 | for (i = 0; i < idx; i++) | ||
38 | { | ||
39 | res = res->next; | ||
40 | } | ||
41 | return res; | ||
42 | } | ||
43 | |||
44 | /** | ||
45 | * Delete a JSON API primary data | ||
46 | * | ||
47 | * @param type the JSON API resource type | ||
48 | * @param id the JSON API resource id | ||
49 | * @return a new JSON API resource or NULL on error. | ||
50 | */ | ||
51 | void | ||
52 | GNUNET_JSONAPI_document_delete (struct GNUNET_JSONAPI_Document *doc) | ||
53 | { | ||
54 | struct GNUNET_JSONAPI_Resource *res; | ||
55 | struct GNUNET_JSONAPI_Resource *res_next; | ||
56 | |||
57 | |||
58 | for (res = doc->res_list_head; | ||
59 | res != NULL;) | ||
60 | { | ||
61 | res_next = res->next; | ||
62 | GNUNET_CONTAINER_DLL_remove (doc->res_list_head, | ||
63 | doc->res_list_tail, | ||
64 | res); | ||
65 | GNUNET_JSONAPI_resource_delete (res); | ||
66 | res = res_next; | ||
67 | } | ||
68 | GNUNET_free (doc); | ||
69 | doc = NULL; | ||
70 | } | ||
71 | |||
72 | /** | ||
73 | * Create a JSON API primary data | ||
74 | * | ||
75 | * @return a new JSON API resource or NULL on error. | ||
76 | */ | ||
77 | struct GNUNET_JSONAPI_Document* | ||
78 | GNUNET_JSONAPI_document_new () | ||
79 | { | ||
80 | struct GNUNET_JSONAPI_Document *result; | ||
81 | |||
82 | result = GNUNET_new (struct GNUNET_JSONAPI_Document); | ||
83 | result->res_count = 0; | ||
84 | result->err_count = 0; | ||
85 | result->meta = 0; | ||
86 | return result; | ||
87 | } | ||
88 | |||
89 | /** | ||
90 | * Add a JSON API error to document | ||
91 | * | ||
92 | * @param data The JSON API document to add to | ||
93 | * @param res the JSON API error to add | ||
94 | * @return the new number of resources | ||
95 | */ | ||
96 | void | ||
97 | GNUNET_JSONAPI_document_error_add (struct GNUNET_JSONAPI_Document *doc, | ||
98 | struct GNUNET_JSONAPI_Error *err) | ||
99 | { | ||
100 | GNUNET_CONTAINER_DLL_insert (doc->err_list_head, | ||
101 | doc->err_list_tail, | ||
102 | err); | ||
103 | |||
104 | doc->err_count++; | ||
105 | } | ||
106 | |||
107 | /** | ||
108 | * Add a JSON API resource to primary data | ||
109 | * | ||
110 | * @param data The JSON API data to add to | ||
111 | * @param res the JSON API resource to add | ||
112 | * @return the new number of resources | ||
113 | */ | ||
114 | void | ||
115 | GNUNET_JSONAPI_document_resource_add (struct GNUNET_JSONAPI_Document *doc, | ||
116 | struct GNUNET_JSONAPI_Resource *res) | ||
117 | { | ||
118 | GNUNET_CONTAINER_DLL_insert (doc->res_list_head, | ||
119 | doc->res_list_tail, | ||
120 | res); | ||
121 | |||
122 | doc->res_count++; | ||
123 | } | ||
124 | |||
125 | |||
126 | /** | ||
127 | * Parse given JSON object to jsonapi document. | ||
128 | * | ||
129 | * @param cls closure, NULL | ||
130 | * @param root the json object representing data | ||
131 | * @param[out] spec where to write the data | ||
132 | * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error | ||
133 | */ | ||
134 | static int | ||
135 | parse_jsonapiobject (void *cls, | ||
136 | json_t *root, | ||
137 | struct GNUNET_JSON_Specification *spec) | ||
138 | { | ||
139 | struct GNUNET_JSONAPI_Document *result; | ||
140 | struct GNUNET_JSONAPI_Error *error; | ||
141 | struct GNUNET_JSONAPI_Resource *resource; | ||
142 | json_t *meta_json; | ||
143 | json_t *resource_json; | ||
144 | json_t *errors_json; | ||
145 | json_t *value; | ||
146 | size_t index; | ||
147 | |||
148 | struct GNUNET_JSON_Specification jsonapispecerrors[] = { | ||
149 | GNUNET_JSON_spec_json (GNUNET_JSONAPI_KEY_ERRORS, &errors_json), | ||
150 | GNUNET_JSON_spec_end() | ||
151 | }; | ||
152 | if (GNUNET_OK != | ||
153 | GNUNET_JSON_parse (root, jsonapispecerrors, | ||
154 | NULL, NULL)) | ||
155 | { | ||
156 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
157 | "JSONAPI document does not contain error objects\n"); | ||
158 | } else if (!json_is_array (errors_json)) | ||
159 | { | ||
160 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
161 | "Error object is not array!\n"); | ||
162 | GNUNET_JSON_parse_free (jsonapispecerrors); | ||
163 | return GNUNET_SYSERR; | ||
164 | } | ||
165 | struct GNUNET_JSON_Specification jsonapispecmeta[] = { | ||
166 | GNUNET_JSON_spec_json (GNUNET_JSONAPI_KEY_META, &meta_json), | ||
167 | GNUNET_JSON_spec_end() | ||
168 | }; | ||
169 | if (GNUNET_OK != | ||
170 | GNUNET_JSON_parse (root, jsonapispecmeta, | ||
171 | NULL, NULL)) | ||
172 | { | ||
173 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
174 | "JSONAPI document does not contain error objects\n"); | ||
175 | } | ||
176 | struct GNUNET_JSON_Specification jsonapispecresource[] = { | ||
177 | GNUNET_JSON_spec_json (GNUNET_JSONAPI_KEY_DATA, &resource_json), | ||
178 | GNUNET_JSON_spec_end() | ||
179 | }; | ||
180 | if (GNUNET_OK != | ||
181 | GNUNET_JSON_parse (root, jsonapispecresource, | ||
182 | NULL, NULL)) | ||
183 | { | ||
184 | if (NULL == errors_json) | ||
185 | { | ||
186 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
187 | "JSONAPI document contains neither error nor data!\n"); | ||
188 | GNUNET_JSON_parse_free (jsonapispecerrors); | ||
189 | GNUNET_JSON_parse_free (jsonapispecmeta); | ||
190 | return GNUNET_SYSERR; | ||
191 | } | ||
192 | } else { | ||
193 | if (NULL != errors_json) | ||
194 | { | ||
195 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
196 | "JSONAPI document contains both error and data!\n"); | ||
197 | GNUNET_JSON_parse_free (jsonapispecerrors); | ||
198 | GNUNET_JSON_parse_free (jsonapispecmeta); | ||
199 | GNUNET_JSON_parse_free (jsonapispecresource); | ||
200 | return GNUNET_SYSERR; | ||
201 | } | ||
202 | } | ||
203 | |||
204 | result = GNUNET_new (struct GNUNET_JSONAPI_Document); | ||
205 | result->res_count = 0; | ||
206 | result->err_count = 0; | ||
207 | if (NULL != meta_json) | ||
208 | result->meta = json_deep_copy (meta_json); | ||
209 | if (NULL != errors_json) { | ||
210 | json_array_foreach(errors_json, index, value) { | ||
211 | GNUNET_assert (GNUNET_OK == | ||
212 | GNUNET_JSONAPI_json_to_error (value, | ||
213 | &error)); | ||
214 | GNUNET_JSONAPI_document_error_add (result, error); | ||
215 | } | ||
216 | } | ||
217 | if (NULL != resource_json) { | ||
218 | if (0 != json_is_array (resource_json)) | ||
219 | { | ||
220 | json_array_foreach(resource_json, index, value) { | ||
221 | GNUNET_assert (GNUNET_OK == | ||
222 | GNUNET_JSONAPI_json_to_resource (value, | ||
223 | &resource)); | ||
224 | GNUNET_JSONAPI_document_resource_add (result, resource); | ||
225 | } | ||
226 | } else { | ||
227 | GNUNET_assert (GNUNET_OK == | ||
228 | GNUNET_JSONAPI_json_to_resource (resource_json, | ||
229 | &resource)); | ||
230 | GNUNET_JSONAPI_document_resource_add (result, resource); | ||
231 | } | ||
232 | } | ||
233 | if (NULL != errors_json) | ||
234 | GNUNET_JSON_parse_free (jsonapispecerrors); | ||
235 | if (NULL != resource) | ||
236 | GNUNET_JSON_parse_free (jsonapispecresource); | ||
237 | if (NULL != meta_json) | ||
238 | GNUNET_JSON_parse_free (jsonapispecmeta); | ||
239 | *(struct GNUNET_JSONAPI_Document **) spec->ptr = result; | ||
240 | return GNUNET_OK; | ||
241 | } | ||
242 | |||
243 | |||
244 | /** | ||
245 | * Cleanup data left from parsing RSA public key. | ||
246 | * | ||
247 | * @param cls closure, NULL | ||
248 | * @param[out] spec where to free the data | ||
249 | */ | ||
250 | static void | ||
251 | clean_jsonapiobject (void *cls, | ||
252 | struct GNUNET_JSON_Specification *spec) | ||
253 | { | ||
254 | struct GNUNET_JSONAPI_Document **jsonapi_obj; | ||
255 | jsonapi_obj = (struct GNUNET_JSONAPI_Document **) spec->ptr; | ||
256 | if (NULL != *jsonapi_obj) | ||
257 | { | ||
258 | GNUNET_JSONAPI_document_delete (*jsonapi_obj); | ||
259 | *jsonapi_obj = NULL; | ||
260 | } | ||
261 | } | ||
262 | |||
263 | /** | ||
264 | * Add a JSON API resource to primary data | ||
265 | * | ||
266 | * @param data The JSON API data to add to | ||
267 | * @param res the JSON API resource to add | ||
268 | * @return the new number of resources | ||
269 | */ | ||
270 | void | ||
271 | GNUNET_JSONAPI_document_resource_remove (struct GNUNET_JSONAPI_Document *resp, | ||
272 | struct GNUNET_JSONAPI_Resource *res) | ||
273 | { | ||
274 | GNUNET_CONTAINER_DLL_remove (resp->res_list_head, | ||
275 | resp->res_list_tail, | ||
276 | res); | ||
277 | resp->res_count--; | ||
278 | } | ||
279 | |||
280 | |||
281 | /** | ||
282 | * String serialze jsonapi primary data | ||
283 | * | ||
284 | * @param data the JSON API primary data | ||
285 | * @param result where to store the result | ||
286 | * @return GNUNET_SYSERR on error else GNUNET_OK | ||
287 | */ | ||
288 | int | ||
289 | GNUNET_JSONAPI_document_serialize (const struct GNUNET_JSONAPI_Document *doc, | ||
290 | char **result) | ||
291 | { | ||
292 | struct GNUNET_JSONAPI_Resource *res; | ||
293 | struct GNUNET_JSONAPI_Error *error; | ||
294 | json_t *root_json; | ||
295 | json_t *res_json; | ||
296 | json_t *res_json_tmp; | ||
297 | |||
298 | if ((NULL == doc)) | ||
299 | return GNUNET_SYSERR; | ||
300 | |||
301 | root_json = json_object (); | ||
302 | |||
303 | //Check for errors first | ||
304 | if (doc->err_count != 0) | ||
305 | { | ||
306 | res_json = json_array (); | ||
307 | for (error = doc->err_list_head; | ||
308 | error != NULL; | ||
309 | error = error->next) | ||
310 | { | ||
311 | GNUNET_assert (GNUNET_OK == | ||
312 | GNUNET_JSONAPI_error_to_json (error, | ||
313 | &res_json_tmp)); | ||
314 | json_array_append (res_json, res_json_tmp); | ||
315 | } | ||
316 | json_object_set (root_json, GNUNET_JSONAPI_KEY_ERRORS, res_json); | ||
317 | } else { | ||
318 | switch (doc->res_count) | ||
319 | { | ||
320 | case 0: | ||
321 | res_json = json_null(); | ||
322 | break; | ||
323 | case 1: | ||
324 | GNUNET_assert (GNUNET_OK == | ||
325 | GNUNET_JSONAPI_resource_to_json (doc->res_list_head, | ||
326 | &res_json)); | ||
327 | break; | ||
328 | default: | ||
329 | res_json = json_array (); | ||
330 | for (res = doc->res_list_head; | ||
331 | res != NULL; | ||
332 | res = res->next) | ||
333 | { | ||
334 | GNUNET_assert (GNUNET_OK == | ||
335 | GNUNET_JSONAPI_resource_to_json (res, | ||
336 | &res_json_tmp)); | ||
337 | json_array_append (res_json, res_json_tmp); | ||
338 | } | ||
339 | break; | ||
340 | } | ||
341 | json_object_set (root_json, GNUNET_JSONAPI_KEY_DATA, res_json); | ||
342 | } | ||
343 | |||
344 | //Add meta | ||
345 | json_object_set (root_json, GNUNET_JSONAPI_KEY_META, doc->meta); | ||
346 | *result = json_dumps (root_json, JSON_INDENT(2)); | ||
347 | json_decref (root_json); | ||
348 | json_decref (res_json); | ||
349 | return GNUNET_OK; | ||
350 | } | ||
351 | |||
352 | /** | ||
353 | * JSON object. | ||
354 | * | ||
355 | * @param name name of the JSON field | ||
356 | * @param[out] jsonp where to store the JSON found under @a name | ||
357 | */ | ||
358 | struct GNUNET_JSON_Specification | ||
359 | GNUNET_JSON_spec_jsonapi_document (struct GNUNET_JSONAPI_Document **jsonapi_object) | ||
360 | { | ||
361 | struct GNUNET_JSON_Specification ret = { | ||
362 | .parser = &parse_jsonapiobject, | ||
363 | .cleaner = &clean_jsonapiobject, | ||
364 | .cls = NULL, | ||
365 | .field = NULL, | ||
366 | .ptr = jsonapi_object, | ||
367 | .ptr_size = 0, | ||
368 | .size_ptr = NULL | ||
369 | }; | ||
370 | *jsonapi_object = NULL; | ||
371 | return ret; | ||
372 | } | ||
373 | |||
374 | |||