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 | |
parent | ca11046195a840932edb04900669a38cd60ae682 (diff) | |
download | gnunet-a44744499d8f3df64cc1d15cd6b40b4b0e4a3683.tar.gz gnunet-a44744499d8f3df64cc1d15cd6b40b4b0e4a3683.zip |
Update jsonapi to current specs, refactor
Diffstat (limited to 'src/jsonapi')
-rw-r--r-- | src/jsonapi/Makefile.am | 6 | ||||
-rw-r--r-- | src/jsonapi/jsonapi.c | 454 | ||||
-rw-r--r-- | src/jsonapi/jsonapi_document.c | 374 | ||||
-rw-r--r-- | src/jsonapi/jsonapi_error.c | 205 | ||||
-rw-r--r-- | src/jsonapi/jsonapi_objects.h | 162 | ||||
-rw-r--r-- | src/jsonapi/jsonapi_relationship.c | 17 | ||||
-rw-r--r-- | src/jsonapi/jsonapi_resource.c | 367 | ||||
-rw-r--r-- | src/jsonapi/test_jsonapi.c | 18 |
8 files changed, 1140 insertions, 463 deletions
diff --git a/src/jsonapi/Makefile.am b/src/jsonapi/Makefile.am index bcd4172c6..7e881acbd 100644 --- a/src/jsonapi/Makefile.am +++ b/src/jsonapi/Makefile.am | |||
@@ -13,7 +13,11 @@ libgnunetjsonapi_la_LDFLAGS = \ | |||
13 | -version-info 0:0:0 \ | 13 | -version-info 0:0:0 \ |
14 | -no-undefined | 14 | -no-undefined |
15 | libgnunetjsonapi_la_SOURCES = \ | 15 | libgnunetjsonapi_la_SOURCES = \ |
16 | jsonapi.c | 16 | jsonapi.c \ |
17 | jsonapi_document.c \ | ||
18 | jsonapi_resource.c \ | ||
19 | jsonapi_error.c \ | ||
20 | jsonapi_relationship.c | ||
17 | libgnunetjsonapi_la_LIBADD = \ | 21 | libgnunetjsonapi_la_LIBADD = \ |
18 | $(top_builddir)/src/util/libgnunetutil.la \ | 22 | $(top_builddir)/src/util/libgnunetutil.la \ |
19 | $(top_builddir)/src/json/libgnunetjson.la \ | 23 | $(top_builddir)/src/json/libgnunetjson.la \ |
diff --git a/src/jsonapi/jsonapi.c b/src/jsonapi/jsonapi.c index b648590e5..53ff64694 100644 --- a/src/jsonapi/jsonapi.c +++ b/src/jsonapi/jsonapi.c | |||
@@ -22,462 +22,10 @@ | |||
22 | #include "gnunet_json_lib.h" | 22 | #include "gnunet_json_lib.h" |
23 | #include "gnunet_rest_lib.h" | 23 | #include "gnunet_rest_lib.h" |
24 | 24 | ||
25 | #define GNUNET_JSONAPI_KEY_DATA "data" | ||
26 | |||
27 | #define GNUNET_JSONAPI_KEY_ID "id" | ||
28 | |||
29 | #define GNUNET_JSONAPI_KEY_TYPE "type" | ||
30 | |||
31 | struct GNUNET_JSONAPI_Resource | ||
32 | { | ||
33 | /** | ||
34 | * DLL | ||
35 | */ | ||
36 | struct GNUNET_JSONAPI_Resource *next; | ||
37 | |||
38 | /** | ||
39 | * DLL | ||
40 | */ | ||
41 | struct GNUNET_JSONAPI_Resource *prev; | ||
42 | |||
43 | /** | ||
44 | * Resource content | ||
45 | */ | ||
46 | json_t *res_obj; | ||
47 | }; | ||
48 | |||
49 | |||
50 | struct GNUNET_JSONAPI_Object | ||
51 | { | ||
52 | /** | ||
53 | * DLL Resource | ||
54 | */ | ||
55 | struct GNUNET_JSONAPI_Resource *res_list_head; | ||
56 | |||
57 | /** | ||
58 | * DLL Resource | ||
59 | */ | ||
60 | struct GNUNET_JSONAPI_Resource *res_list_tail; | ||
61 | |||
62 | /** | ||
63 | * num resources | ||
64 | */ | ||
65 | int res_count; | ||
66 | }; | ||
67 | |||
68 | |||
69 | /** | 25 | /** |
70 | * JSON API | 26 | * TODO move this to jsonapi-utils |
71 | */ | 27 | */ |
72 | 28 | ||
73 | |||
74 | /** | ||
75 | * Create a JSON API resource | ||
76 | * | ||
77 | * @param type the JSON API resource type | ||
78 | * @param id the JSON API resource id | ||
79 | * @return a new JSON API resource or NULL on error. | ||
80 | */ | ||
81 | struct GNUNET_JSONAPI_Resource* | ||
82 | GNUNET_JSONAPI_resource_new (const char *type, const char *id) | ||
83 | { | ||
84 | struct GNUNET_JSONAPI_Resource *res; | ||
85 | |||
86 | if ( (NULL == type) || (0 == strlen (type)) ) | ||
87 | return NULL; | ||
88 | if ( (NULL == id) || (0 == strlen (id)) ) | ||
89 | return NULL; | ||
90 | |||
91 | res = GNUNET_new (struct GNUNET_JSONAPI_Resource); | ||
92 | res->prev = NULL; | ||
93 | res->next = NULL; | ||
94 | |||
95 | res->res_obj = json_object (); | ||
96 | |||
97 | json_object_set_new (res->res_obj, GNUNET_JSONAPI_KEY_ID, json_string (id)); | ||
98 | json_object_set_new (res->res_obj, GNUNET_JSONAPI_KEY_TYPE, json_string (type)); | ||
99 | |||
100 | return res; | ||
101 | } | ||
102 | |||
103 | |||
104 | |||
105 | /** | ||
106 | * Add a JSON API attribute | ||
107 | * | ||
108 | * @param res the JSON resource | ||
109 | * @param key the key for the attribute | ||
110 | * @param json the json_t attribute to add | ||
111 | * @return #GNUNET_OK if added successfully | ||
112 | * #GNUNET_SYSERR if not | ||
113 | */ | ||
114 | int | ||
115 | GNUNET_JSONAPI_resource_add_attr (const struct GNUNET_JSONAPI_Resource *resource, | ||
116 | const char* key, | ||
117 | json_t *json) | ||
118 | { | ||
119 | if ( (NULL == resource) || | ||
120 | (NULL == key) || | ||
121 | (NULL == json) ) | ||
122 | return GNUNET_SYSERR; | ||
123 | json_object_set (resource->res_obj, key, json); | ||
124 | return GNUNET_OK; | ||
125 | } | ||
126 | |||
127 | /** | ||
128 | * Read a JSON API attribute | ||
129 | * | ||
130 | * @param res the JSON resource | ||
131 | * @param key the key for the attribute | ||
132 | * @return the json_t object | ||
133 | */ | ||
134 | json_t* | ||
135 | GNUNET_JSONAPI_resource_read_attr (const struct GNUNET_JSONAPI_Resource *resource, | ||
136 | const char* key) | ||
137 | { | ||
138 | if ( (NULL == resource) || | ||
139 | (NULL == key)) | ||
140 | return NULL; | ||
141 | return json_object_get (resource->res_obj, key); | ||
142 | } | ||
143 | |||
144 | int | ||
145 | check_resource_attr_str (const struct GNUNET_JSONAPI_Resource *resource, | ||
146 | const char* key, | ||
147 | const char* attr) | ||
148 | { | ||
149 | json_t *value; | ||
150 | if ( (NULL == resource) || | ||
151 | (NULL == key) || | ||
152 | (NULL == attr)) | ||
153 | return GNUNET_NO; | ||
154 | value = json_object_get (resource->res_obj, key); | ||
155 | if (NULL == value) | ||
156 | return GNUNET_NO; | ||
157 | if (!json_is_string (value) || | ||
158 | (0 != strcmp (attr, json_string_value(value)))) | ||
159 | { | ||
160 | return GNUNET_NO; | ||
161 | } | ||
162 | return GNUNET_YES; | ||
163 | } | ||
164 | |||
165 | /** | ||
166 | * Check a JSON API resource id | ||
167 | * | ||
168 | * @param res the JSON resource | ||
169 | * @param id the expected id | ||
170 | * @return GNUNET_YES if id matches | ||
171 | */ | ||
172 | int | ||
173 | GNUNET_JSONAPI_resource_check_id (const struct GNUNET_JSONAPI_Resource *resource, | ||
174 | const char* id) | ||
175 | { | ||
176 | return check_resource_attr_str (resource, GNUNET_JSONAPI_KEY_ID, id); | ||
177 | } | ||
178 | |||
179 | /** | ||
180 | * Check a JSON API resource id | ||
181 | * | ||
182 | * @param res the JSON resource | ||
183 | * @return the resource id | ||
184 | */ | ||
185 | json_t* | ||
186 | GNUNET_JSONAPI_resource_get_id (const struct GNUNET_JSONAPI_Resource *resource) | ||
187 | { | ||
188 | return GNUNET_JSONAPI_resource_read_attr (resource, GNUNET_JSONAPI_KEY_ID); | ||
189 | } | ||
190 | |||
191 | /** | ||
192 | * Check a JSON API resource type | ||
193 | * | ||
194 | * @param res the JSON resource | ||
195 | * @param type the expected type | ||
196 | * @return GNUNET_YES if id matches | ||
197 | */ | ||
198 | int | ||
199 | GNUNET_JSONAPI_resource_check_type (const struct GNUNET_JSONAPI_Resource *resource, | ||
200 | const char* type) | ||
201 | { | ||
202 | return check_resource_attr_str (resource, GNUNET_JSONAPI_KEY_TYPE, type); | ||
203 | } | ||
204 | |||
205 | /** | ||
206 | * Get a JSON API object resource count | ||
207 | * | ||
208 | * @param resp the JSON API object | ||
209 | * @return the number of resources | ||
210 | */ | ||
211 | int | ||
212 | GNUNET_JSONAPI_object_resource_count (struct GNUNET_JSONAPI_Object *resp) | ||
213 | { | ||
214 | return resp->res_count; | ||
215 | } | ||
216 | |||
217 | /** | ||
218 | * Get a JSON API object resource by index | ||
219 | * | ||
220 | * @param resp the JSON API object | ||
221 | * @param num the number of the resource | ||
222 | * @return the resource | ||
223 | */ | ||
224 | struct GNUNET_JSONAPI_Resource* | ||
225 | GNUNET_JSONAPI_object_get_resource (struct GNUNET_JSONAPI_Object *resp, | ||
226 | int num) | ||
227 | { | ||
228 | struct GNUNET_JSONAPI_Resource *res; | ||
229 | int i; | ||
230 | |||
231 | if ((0 == resp->res_count) || | ||
232 | (num >= resp->res_count)) | ||
233 | return NULL; | ||
234 | res = resp->res_list_head; | ||
235 | for (i = 0; i < num; i++) | ||
236 | { | ||
237 | res = res->next; | ||
238 | } | ||
239 | return res; | ||
240 | } | ||
241 | |||
242 | /** | ||
243 | * Delete a JSON API resource | ||
244 | * | ||
245 | * @param res the JSON resource | ||
246 | * @param result Pointer where the resource should be stored | ||
247 | */ | ||
248 | void | ||
249 | GNUNET_JSONAPI_resource_delete (struct GNUNET_JSONAPI_Resource *resource) | ||
250 | { | ||
251 | json_decref (resource->res_obj); | ||
252 | GNUNET_free (resource); | ||
253 | resource = NULL; | ||
254 | } | ||
255 | |||
256 | /** | ||
257 | * Delete a JSON API primary data | ||
258 | * | ||
259 | * @param type the JSON API resource type | ||
260 | * @param id the JSON API resource id | ||
261 | * @return a new JSON API resource or NULL on error. | ||
262 | */ | ||
263 | void | ||
264 | GNUNET_JSONAPI_object_delete (struct GNUNET_JSONAPI_Object *resp) | ||
265 | { | ||
266 | struct GNUNET_JSONAPI_Resource *res; | ||
267 | struct GNUNET_JSONAPI_Resource *res_next; | ||
268 | |||
269 | for (res = resp->res_list_head; | ||
270 | res != NULL;) | ||
271 | { | ||
272 | res_next = res->next; | ||
273 | GNUNET_CONTAINER_DLL_remove (resp->res_list_head, | ||
274 | resp->res_list_tail, | ||
275 | res); | ||
276 | GNUNET_JSONAPI_resource_delete (res); | ||
277 | res = res_next; | ||
278 | } | ||
279 | GNUNET_free (resp); | ||
280 | resp = NULL; | ||
281 | } | ||
282 | |||
283 | /** | ||
284 | * Create a JSON API primary data | ||
285 | * | ||
286 | * @return a new JSON API resource or NULL on error. | ||
287 | */ | ||
288 | struct GNUNET_JSONAPI_Object* | ||
289 | GNUNET_JSONAPI_object_new () | ||
290 | { | ||
291 | struct GNUNET_JSONAPI_Object *result; | ||
292 | |||
293 | result = GNUNET_new (struct GNUNET_JSONAPI_Object); | ||
294 | result->res_count = 0; | ||
295 | return result; | ||
296 | } | ||
297 | |||
298 | /** | ||
299 | * Add a JSON API object to primary data | ||
300 | * | ||
301 | * @param data The JSON API data to add to | ||
302 | * @param res the JSON API resource to add | ||
303 | * @return the new number of resources | ||
304 | */ | ||
305 | void | ||
306 | GNUNET_JSONAPI_object_resource_add (struct GNUNET_JSONAPI_Object *resp, | ||
307 | struct GNUNET_JSONAPI_Resource *res) | ||
308 | { | ||
309 | GNUNET_CONTAINER_DLL_insert (resp->res_list_head, | ||
310 | resp->res_list_tail, | ||
311 | res); | ||
312 | |||
313 | resp->res_count++; | ||
314 | } | ||
315 | |||
316 | static void | ||
317 | add_json_resource (struct GNUNET_JSONAPI_Object *obj, | ||
318 | const json_t *res_json) | ||
319 | { | ||
320 | struct GNUNET_JSONAPI_Resource *res; | ||
321 | const char *type_json; | ||
322 | |||
323 | struct GNUNET_JSON_Specification dspec[] = { | ||
324 | GNUNET_JSON_spec_string (GNUNET_JSONAPI_KEY_TYPE, &type_json), | ||
325 | GNUNET_JSON_spec_end() | ||
326 | }; | ||
327 | |||
328 | GNUNET_assert (GNUNET_OK == | ||
329 | GNUNET_JSON_parse (res_json, dspec, | ||
330 | NULL, NULL)); | ||
331 | GNUNET_JSON_parse_free (dspec); | ||
332 | res = GNUNET_new (struct GNUNET_JSONAPI_Resource); | ||
333 | res->next = NULL; | ||
334 | res->prev = NULL; | ||
335 | res->res_obj = json_deep_copy (res_json); | ||
336 | GNUNET_JSONAPI_object_resource_add (obj, res); | ||
337 | } | ||
338 | |||
339 | /** | ||
340 | * Parse given JSON object to RSA public key. | ||
341 | * | ||
342 | * @param cls closure, NULL | ||
343 | * @param root the json object representing data | ||
344 | * @param[out] spec where to write the data | ||
345 | * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error | ||
346 | */ | ||
347 | static int | ||
348 | parse_jsonapiobject (void *cls, | ||
349 | json_t *root, | ||
350 | struct GNUNET_JSON_Specification *spec) | ||
351 | { | ||
352 | struct GNUNET_JSONAPI_Object *result; | ||
353 | json_t *data_json; | ||
354 | int res_count = 0; | ||
355 | int i; | ||
356 | |||
357 | struct GNUNET_JSON_Specification jsonapispec[] = { | ||
358 | GNUNET_JSON_spec_json (GNUNET_JSONAPI_KEY_DATA, &data_json), | ||
359 | GNUNET_JSON_spec_end() | ||
360 | }; | ||
361 | if (GNUNET_OK != | ||
362 | GNUNET_JSON_parse (root, jsonapispec, | ||
363 | NULL, NULL) || (NULL == data_json)) | ||
364 | { | ||
365 | return GNUNET_SYSERR; | ||
366 | } | ||
367 | |||
368 | result = GNUNET_new (struct GNUNET_JSONAPI_Object); | ||
369 | result->res_count = 0; | ||
370 | if (json_is_object (data_json)) | ||
371 | add_json_resource (result, data_json); | ||
372 | else if (json_is_array (data_json)) | ||
373 | { | ||
374 | res_count = json_array_size (data_json); | ||
375 | for (i = 0; i < res_count; i++) | ||
376 | add_json_resource (result, json_array_get (data_json, i)); | ||
377 | } | ||
378 | if (0 == result->res_count) | ||
379 | { | ||
380 | GNUNET_free (result); | ||
381 | GNUNET_JSON_parse_free (jsonapispec); | ||
382 | return GNUNET_SYSERR; | ||
383 | } | ||
384 | *(struct GNUNET_JSONAPI_Object **) spec->ptr = result; | ||
385 | GNUNET_JSON_parse_free (jsonapispec); | ||
386 | return GNUNET_OK; | ||
387 | } | ||
388 | |||
389 | |||
390 | /** | ||
391 | * Cleanup data left from parsing RSA public key. | ||
392 | * | ||
393 | * @param cls closure, NULL | ||
394 | * @param[out] spec where to free the data | ||
395 | */ | ||
396 | static void | ||
397 | clean_jsonapiobject (void *cls, | ||
398 | struct GNUNET_JSON_Specification *spec) | ||
399 | { | ||
400 | struct GNUNET_JSONAPI_Object **jsonapi_obj; | ||
401 | jsonapi_obj = (struct GNUNET_JSONAPI_Object **) spec->ptr; | ||
402 | if (NULL != *jsonapi_obj) | ||
403 | { | ||
404 | GNUNET_JSONAPI_object_delete (*jsonapi_obj); | ||
405 | *jsonapi_obj = NULL; | ||
406 | } | ||
407 | } | ||
408 | |||
409 | /** | ||
410 | * Add a JSON API resource to primary data | ||
411 | * | ||
412 | * @param data The JSON API data to add to | ||
413 | * @param res the JSON API resource to add | ||
414 | * @return the new number of resources | ||
415 | */ | ||
416 | void | ||
417 | GNUNET_JSONAPI_data_resource_remove (struct GNUNET_JSONAPI_Object *resp, | ||
418 | struct GNUNET_JSONAPI_Resource *res) | ||
419 | { | ||
420 | GNUNET_CONTAINER_DLL_remove (resp->res_list_head, | ||
421 | resp->res_list_tail, | ||
422 | res); | ||
423 | resp->res_count--; | ||
424 | } | ||
425 | |||
426 | /** | ||
427 | * String serialze jsonapi primary data | ||
428 | * | ||
429 | * @param data the JSON API primary data | ||
430 | * @param result where to store the result | ||
431 | * @return GNUNET_SYSERR on error else GNUNET_OK | ||
432 | */ | ||
433 | int | ||
434 | GNUNET_JSONAPI_data_serialize (const struct GNUNET_JSONAPI_Object *resp, | ||
435 | char **result) | ||
436 | { | ||
437 | struct GNUNET_JSONAPI_Resource *res; | ||
438 | json_t *root_json; | ||
439 | json_t *res_arr; | ||
440 | |||
441 | if ((NULL == resp)) | ||
442 | return GNUNET_SYSERR; | ||
443 | |||
444 | root_json = json_object (); | ||
445 | res_arr = json_array (); | ||
446 | for (res = resp->res_list_head; | ||
447 | res != NULL; | ||
448 | res = res->next) | ||
449 | { | ||
450 | json_array_append (res_arr, res->res_obj); | ||
451 | } | ||
452 | json_object_set (root_json, GNUNET_JSONAPI_KEY_DATA, res_arr); | ||
453 | *result = json_dumps (root_json, JSON_INDENT(2)); | ||
454 | json_decref (root_json); | ||
455 | json_decref (res_arr); | ||
456 | return GNUNET_OK; | ||
457 | } | ||
458 | |||
459 | /** | ||
460 | * JSON object. | ||
461 | * | ||
462 | * @param name name of the JSON field | ||
463 | * @param[out] jsonp where to store the JSON found under @a name | ||
464 | */ | ||
465 | struct GNUNET_JSON_Specification | ||
466 | GNUNET_JSON_spec_jsonapi (struct GNUNET_JSONAPI_Object **jsonapi_object) | ||
467 | { | ||
468 | struct GNUNET_JSON_Specification ret = { | ||
469 | .parser = &parse_jsonapiobject, | ||
470 | .cleaner = &clean_jsonapiobject, | ||
471 | .cls = NULL, | ||
472 | .field = NULL, | ||
473 | .ptr = jsonapi_object, | ||
474 | .ptr_size = 0, | ||
475 | .size_ptr = NULL | ||
476 | }; | ||
477 | *jsonapi_object = NULL; | ||
478 | return ret; | ||
479 | } | ||
480 | |||
481 | /** | 29 | /** |
482 | * Check rest request for validity | 30 | * Check rest request for validity |
483 | * | 31 | * |
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 | |||
diff --git a/src/jsonapi/jsonapi_error.c b/src/jsonapi/jsonapi_error.c new file mode 100644 index 000000000..d91f0a650 --- /dev/null +++ b/src/jsonapi/jsonapi_error.c | |||
@@ -0,0 +1,205 @@ | |||
1 | #include "platform.h" | ||
2 | #include "gnunet_jsonapi_lib.h" | ||
3 | #include "jsonapi_objects.h" | ||
4 | |||
5 | /** | ||
6 | * Parse json to error object | ||
7 | * | ||
8 | * @param err_json JSON object | ||
9 | * @param[out] err error object | ||
10 | * @return GNUNET_OK on success | ||
11 | */ | ||
12 | int | ||
13 | GNUNET_JSONAPI_json_to_error (json_t *err_json, | ||
14 | struct GNUNET_JSONAPI_Error **err) | ||
15 | { | ||
16 | struct GNUNET_JSON_Specification jsonapispecerror[] = { | ||
17 | GNUNET_JSON_spec_jsonapi_error (err), | ||
18 | GNUNET_JSON_spec_end() | ||
19 | }; | ||
20 | return GNUNET_JSON_parse (err_json, jsonapispecerror, | ||
21 | NULL, NULL); | ||
22 | } | ||
23 | |||
24 | /** | ||
25 | * Serialze jsonapi errors | ||
26 | * | ||
27 | * @param data the JSON API errors | ||
28 | * @param result where to store the result | ||
29 | * @return GNUNET_SYSERR on error else GNUNET_OK | ||
30 | */ | ||
31 | int | ||
32 | GNUNET_JSONAPI_error_to_json (const struct GNUNET_JSONAPI_Error *err, | ||
33 | json_t **result) | ||
34 | { | ||
35 | *result = json_object (); | ||
36 | |||
37 | if ((NULL != err->id) && | ||
38 | (0 != json_object_set_new (*result, | ||
39 | GNUNET_JSONAPI_KEY_ID, | ||
40 | json_string (err->id)))) | ||
41 | return GNUNET_SYSERR; | ||
42 | if ((NULL != err->status) && | ||
43 | (0 != json_object_set_new (*result, | ||
44 | GNUNET_JSONAPI_KEY_STATUS, | ||
45 | json_string (err->status)))) | ||
46 | return GNUNET_SYSERR; | ||
47 | if ((NULL != err->code) && | ||
48 | (0 != json_object_set_new (*result, | ||
49 | GNUNET_JSONAPI_KEY_CODE, | ||
50 | json_string (err->code)))) | ||
51 | return GNUNET_SYSERR; | ||
52 | |||
53 | if ((NULL != err->title) && | ||
54 | (0 != json_object_set_new (*result, | ||
55 | GNUNET_JSONAPI_KEY_TITLE, | ||
56 | json_string (err->title)))) | ||
57 | return GNUNET_SYSERR; | ||
58 | if ((NULL != err->detail) && | ||
59 | (0 != json_object_set_new (*result, | ||
60 | GNUNET_JSONAPI_KEY_DETAIL, | ||
61 | json_string (err->detail)))) | ||
62 | return GNUNET_SYSERR; | ||
63 | if ((NULL != err->source) && | ||
64 | (0 != json_object_set_new (*result, | ||
65 | GNUNET_JSONAPI_KEY_SOURCE, | ||
66 | err->source))) | ||
67 | return GNUNET_SYSERR; | ||
68 | if ((NULL != err->links) && | ||
69 | (0 != json_object_set_new (*result, | ||
70 | GNUNET_JSONAPI_KEY_LINKS, | ||
71 | err->links))) | ||
72 | return GNUNET_SYSERR; | ||
73 | if ((NULL != err->meta) && | ||
74 | (0 != json_object_set_new (*result, | ||
75 | GNUNET_JSONAPI_KEY_META, | ||
76 | err->meta))) | ||
77 | return GNUNET_SYSERR; | ||
78 | return GNUNET_OK; | ||
79 | } | ||
80 | |||
81 | |||
82 | /** | ||
83 | * Parse given JSON object to jsonapi document. | ||
84 | * | ||
85 | * @param cls closure, NULL | ||
86 | * @param root the json object representing data | ||
87 | * @param[out] spec where to write the data | ||
88 | * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error | ||
89 | */ | ||
90 | static int | ||
91 | parse_jsonapierror (void *cls, | ||
92 | json_t *root, | ||
93 | struct GNUNET_JSON_Specification *spec) | ||
94 | { | ||
95 | struct GNUNET_JSONAPI_Error *result; | ||
96 | json_t *pos; | ||
97 | |||
98 | GNUNET_assert (NULL != root); | ||
99 | result = GNUNET_new (struct GNUNET_JSONAPI_Error); | ||
100 | pos = json_object_get (root, GNUNET_JSONAPI_KEY_ID); | ||
101 | if (json_is_string (pos)) | ||
102 | result->id = GNUNET_strdup (json_string_value (pos)); | ||
103 | |||
104 | pos = json_object_get (root, GNUNET_JSONAPI_KEY_LINKS); | ||
105 | if (json_is_object (pos)) | ||
106 | result->links = json_deep_copy (pos); | ||
107 | |||
108 | pos = json_object_get (root, GNUNET_JSONAPI_KEY_STATUS); | ||
109 | if (json_is_string (pos)) | ||
110 | result->status = GNUNET_strdup (json_string_value (pos)); | ||
111 | |||
112 | pos = json_object_get (root, GNUNET_JSONAPI_KEY_CODE); | ||
113 | if (json_is_string (pos)) | ||
114 | result->code = GNUNET_strdup (json_string_value (pos)); | ||
115 | |||
116 | pos = json_object_get (root, GNUNET_JSONAPI_KEY_TITLE); | ||
117 | if (json_is_string (pos)) | ||
118 | result->title = GNUNET_strdup (json_string_value (pos)); | ||
119 | |||
120 | pos = json_object_get (root, GNUNET_JSONAPI_KEY_DETAIL); | ||
121 | if (json_is_string (pos)) | ||
122 | result->detail = GNUNET_strdup (json_string_value (pos)); | ||
123 | |||
124 | pos = json_object_get (root, GNUNET_JSONAPI_KEY_SOURCE); | ||
125 | if (json_is_object (pos)) | ||
126 | result->source = json_deep_copy (pos); | ||
127 | pos = json_object_get (root, GNUNET_JSONAPI_KEY_META); | ||
128 | if (json_is_object (pos)) | ||
129 | result->meta = json_deep_copy (pos); | ||
130 | *(struct GNUNET_JSONAPI_Error **) spec->ptr = result; | ||
131 | return GNUNET_OK; | ||
132 | } | ||
133 | |||
134 | /** | ||
135 | * Delete a JSON API error | ||
136 | * | ||
137 | * @param res the JSON error | ||
138 | */ | ||
139 | void | ||
140 | GNUNET_JSONAPI_error_delete (struct GNUNET_JSONAPI_Error *error) | ||
141 | { | ||
142 | GNUNET_assert (NULL != error); | ||
143 | |||
144 | if (NULL != error->id) | ||
145 | GNUNET_free (error->id); | ||
146 | if (NULL != error->status) | ||
147 | GNUNET_free (error->status); | ||
148 | if (NULL != error->code) | ||
149 | GNUNET_free (error->code); | ||
150 | if (NULL != error->title) | ||
151 | GNUNET_free (error->title); | ||
152 | if (NULL != error->detail) | ||
153 | GNUNET_free (error->detail); | ||
154 | if (NULL != error->links) | ||
155 | json_decref (error->links); | ||
156 | if (NULL != error->source) | ||
157 | json_decref (error->source); | ||
158 | if (NULL != error->meta) | ||
159 | json_decref (error->meta); | ||
160 | GNUNET_free (error); | ||
161 | } | ||
162 | |||
163 | |||
164 | |||
165 | /** | ||
166 | * Cleanup data left from parsing RSA public key. | ||
167 | * | ||
168 | * @param cls closure, NULL | ||
169 | * @param[out] spec where to free the data | ||
170 | */ | ||
171 | static void | ||
172 | clean_jsonapierror (void *cls, | ||
173 | struct GNUNET_JSON_Specification *spec) | ||
174 | { | ||
175 | struct GNUNET_JSONAPI_Error **jsonapi_obj; | ||
176 | jsonapi_obj = (struct GNUNET_JSONAPI_Error **) spec->ptr; | ||
177 | if (NULL != *jsonapi_obj) | ||
178 | { | ||
179 | GNUNET_JSONAPI_error_delete (*jsonapi_obj); | ||
180 | *jsonapi_obj = NULL; | ||
181 | } | ||
182 | } | ||
183 | /** | ||
184 | * JSON object. | ||
185 | * | ||
186 | * @param name name of the JSON field | ||
187 | * @param[out] jsonp where to store the JSON found under @a name | ||
188 | */ | ||
189 | struct GNUNET_JSON_Specification | ||
190 | GNUNET_JSON_spec_jsonapi_error (struct GNUNET_JSONAPI_Error **jsonapi_object) | ||
191 | { | ||
192 | struct GNUNET_JSON_Specification ret = { | ||
193 | .parser = &parse_jsonapierror, | ||
194 | .cleaner = &clean_jsonapierror, | ||
195 | .cls = NULL, | ||
196 | .field = NULL, | ||
197 | .ptr = jsonapi_object, | ||
198 | .ptr_size = 0, | ||
199 | .size_ptr = NULL | ||
200 | }; | ||
201 | *jsonapi_object = NULL; | ||
202 | return ret; | ||
203 | } | ||
204 | |||
205 | |||
diff --git a/src/jsonapi/jsonapi_objects.h b/src/jsonapi/jsonapi_objects.h new file mode 100644 index 000000000..27c64eeb7 --- /dev/null +++ b/src/jsonapi/jsonapi_objects.h | |||
@@ -0,0 +1,162 @@ | |||
1 | #include "platform.h" | ||
2 | #include "gnunet_jsonapi_lib.h" | ||
3 | /** | ||
4 | * jsonapi error object | ||
5 | */ | ||
6 | struct GNUNET_JSONAPI_Error | ||
7 | { | ||
8 | /** | ||
9 | * DLL | ||
10 | */ | ||
11 | struct GNUNET_JSONAPI_Error *next; | ||
12 | |||
13 | /** | ||
14 | * DLL | ||
15 | */ | ||
16 | struct GNUNET_JSONAPI_Error *prev; | ||
17 | |||
18 | /** | ||
19 | * Unique error id | ||
20 | */ | ||
21 | char *id; | ||
22 | |||
23 | /** | ||
24 | * Links object | ||
25 | */ | ||
26 | json_t *links; | ||
27 | |||
28 | /** | ||
29 | * HTTP status code for this error | ||
30 | */ | ||
31 | char *status; | ||
32 | |||
33 | /** | ||
34 | * Application error code | ||
35 | */ | ||
36 | char *code; | ||
37 | |||
38 | /** | ||
39 | * Error title | ||
40 | */ | ||
41 | char *title; | ||
42 | |||
43 | /** | ||
44 | * Error details | ||
45 | */ | ||
46 | char *detail; | ||
47 | |||
48 | /** | ||
49 | * Error source | ||
50 | */ | ||
51 | json_t *source; | ||
52 | |||
53 | /** | ||
54 | * Meta info for the error | ||
55 | */ | ||
56 | json_t *meta; | ||
57 | }; | ||
58 | |||
59 | struct GNUNET_JSONAPI_Relationship | ||
60 | { | ||
61 | /** | ||
62 | * Links object | ||
63 | */ | ||
64 | struct GNUNET_JSONAPI_Link *links; | ||
65 | |||
66 | /** | ||
67 | * Resource linkage data | ||
68 | */ | ||
69 | struct GNUNET_JSONAPI_Resource *res_list_head; | ||
70 | |||
71 | /** | ||
72 | * DLL | ||
73 | */ | ||
74 | struct GNUNET_JSONAPI_Resource *res_list_tail; | ||
75 | |||
76 | /** | ||
77 | * Number of resources in data section | ||
78 | */ | ||
79 | int res_count; | ||
80 | |||
81 | /** | ||
82 | * Meta information | ||
83 | */ | ||
84 | json_t *meta; | ||
85 | }; | ||
86 | |||
87 | /** | ||
88 | * A jsonapi resource object | ||
89 | */ | ||
90 | struct GNUNET_JSONAPI_Resource | ||
91 | { | ||
92 | /** | ||
93 | * DLL | ||
94 | */ | ||
95 | struct GNUNET_JSONAPI_Resource *next; | ||
96 | |||
97 | /** | ||
98 | * DLL | ||
99 | */ | ||
100 | struct GNUNET_JSONAPI_Resource *prev; | ||
101 | |||
102 | /** | ||
103 | * Resource type | ||
104 | */ | ||
105 | char *type; | ||
106 | |||
107 | /** | ||
108 | * Resource ID | ||
109 | */ | ||
110 | char *id; | ||
111 | |||
112 | /** | ||
113 | * Attributes object | ||
114 | */ | ||
115 | json_t *attr_obj; | ||
116 | |||
117 | /** | ||
118 | * Relationship | ||
119 | */ | ||
120 | struct GNUNET_JSONAPI_Relationship *relationship; | ||
121 | }; | ||
122 | |||
123 | |||
124 | struct GNUNET_JSONAPI_Document | ||
125 | { | ||
126 | /** | ||
127 | * DLL Resource | ||
128 | */ | ||
129 | struct GNUNET_JSONAPI_Resource *res_list_head; | ||
130 | |||
131 | /** | ||
132 | * DLL Resource | ||
133 | */ | ||
134 | struct GNUNET_JSONAPI_Resource *res_list_tail; | ||
135 | |||
136 | /** | ||
137 | * num resources | ||
138 | */ | ||
139 | int res_count; | ||
140 | |||
141 | /** | ||
142 | * DLL Error | ||
143 | */ | ||
144 | struct GNUNET_JSONAPI_Error *err_list_head; | ||
145 | |||
146 | /** | ||
147 | * DLL Error | ||
148 | */ | ||
149 | struct GNUNET_JSONAPI_Error *err_list_tail; | ||
150 | |||
151 | /** | ||
152 | * num errors | ||
153 | */ | ||
154 | int err_count; | ||
155 | |||
156 | /** | ||
157 | * Meta info | ||
158 | */ | ||
159 | json_t *meta; | ||
160 | }; | ||
161 | |||
162 | |||
diff --git a/src/jsonapi/jsonapi_relationship.c b/src/jsonapi/jsonapi_relationship.c new file mode 100644 index 000000000..b88e74cc9 --- /dev/null +++ b/src/jsonapi/jsonapi_relationship.c | |||
@@ -0,0 +1,17 @@ | |||
1 | #include "platform.h" | ||
2 | #include "gnunet_jsonapi_lib.h" | ||
3 | |||
4 | |||
5 | /** | ||
6 | * Delete a JSON API relationship TODO | ||
7 | * | ||
8 | * @param res the JSON relationship | ||
9 | */ | ||
10 | void | ||
11 | GNUNET_JSONAPI_relationship_delete (struct GNUNET_JSONAPI_Relationship *relationship) | ||
12 | { | ||
13 | GNUNET_assert (NULL != relationship); | ||
14 | GNUNET_free (relationship); | ||
15 | } | ||
16 | |||
17 | |||
diff --git a/src/jsonapi/jsonapi_resource.c b/src/jsonapi/jsonapi_resource.c new file mode 100644 index 000000000..09217279a --- /dev/null +++ b/src/jsonapi/jsonapi_resource.c | |||
@@ -0,0 +1,367 @@ | |||
1 | #include "platform.h" | ||
2 | #include "gnunet_jsonapi_lib.h" | ||
3 | #include "jsonapi_objects.h" | ||
4 | |||
5 | /** | ||
6 | * String serialze jsonapi resources | ||
7 | * | ||
8 | * @param data the JSON API resource | ||
9 | * @param result where to store the result | ||
10 | * @return GNUNET_SYSERR on error else GNUNET_OK | ||
11 | */ | ||
12 | int | ||
13 | GNUNET_JSONAPI_resource_to_json (const struct GNUNET_JSONAPI_Resource *res, | ||
14 | json_t **result) | ||
15 | { | ||
16 | struct GNUNET_JSONAPI_Resource *rel_res; | ||
17 | json_t *relationship; | ||
18 | json_t *res_json_tmp; | ||
19 | *result = json_object (); | ||
20 | |||
21 | if (0 != json_object_set_new (*result, | ||
22 | GNUNET_JSONAPI_KEY_ID, | ||
23 | json_string (res->id))) | ||
24 | return GNUNET_SYSERR; | ||
25 | if (0 != json_object_set_new (*result, | ||
26 | GNUNET_JSONAPI_KEY_TYPE, | ||
27 | json_string (res->type))) | ||
28 | return GNUNET_SYSERR; | ||
29 | if ((NULL != res->attr_obj) && | ||
30 | (0 != json_object_set (*result, | ||
31 | GNUNET_JSONAPI_KEY_ATTRIBUTES, | ||
32 | res->attr_obj))) | ||
33 | return GNUNET_SYSERR; | ||
34 | |||
35 | //Relationships | ||
36 | if (NULL != res->relationship) | ||
37 | { | ||
38 | relationship = json_object (); | ||
39 | if (0 != res->relationship->res_count) | ||
40 | { | ||
41 | json_t *res_json; | ||
42 | switch (res->relationship->res_count) | ||
43 | { | ||
44 | case 0: | ||
45 | res_json = json_null(); | ||
46 | break; | ||
47 | case 1: | ||
48 | GNUNET_assert (GNUNET_OK == | ||
49 | GNUNET_JSONAPI_resource_to_json (res->relationship->res_list_head, | ||
50 | &res_json)); | ||
51 | break; | ||
52 | default: | ||
53 | res_json = json_array (); | ||
54 | rel_res = NULL; | ||
55 | for (rel_res = rel_res->relationship->res_list_head; | ||
56 | rel_res != NULL; | ||
57 | rel_res = rel_res->next) | ||
58 | { | ||
59 | GNUNET_assert (GNUNET_OK == | ||
60 | GNUNET_JSONAPI_resource_to_json (rel_res, | ||
61 | &res_json_tmp)); | ||
62 | json_array_append_new (res_json, res_json_tmp); | ||
63 | } | ||
64 | break; | ||
65 | } | ||
66 | json_object_set_new (relationship, | ||
67 | GNUNET_JSONAPI_KEY_DATA, | ||
68 | res_json); | ||
69 | } | ||
70 | if ((NULL != res->relationship->meta) && | ||
71 | (0 != json_object_set_new (relationship, | ||
72 | GNUNET_JSONAPI_KEY_META, | ||
73 | res->relationship->meta))) | ||
74 | return GNUNET_SYSERR; | ||
75 | //TODO link | ||
76 | } | ||
77 | |||
78 | |||
79 | return GNUNET_OK; | ||
80 | } | ||
81 | |||
82 | |||
83 | /** | ||
84 | * Create a JSON API resource | ||
85 | * | ||
86 | * @param type the JSON API resource type | ||
87 | * @param id the JSON API resource id | ||
88 | * @return a new JSON API resource or NULL on error. | ||
89 | */ | ||
90 | struct GNUNET_JSONAPI_Resource* | ||
91 | GNUNET_JSONAPI_resource_new (const char *type, const char *id) | ||
92 | { | ||
93 | struct GNUNET_JSONAPI_Resource *res; | ||
94 | |||
95 | if ( (NULL == type) || (0 == strlen (type)) ) | ||
96 | return NULL; | ||
97 | if ( (NULL == id) || (0 == strlen (id)) ) | ||
98 | return NULL; | ||
99 | |||
100 | res = GNUNET_new (struct GNUNET_JSONAPI_Resource); | ||
101 | res->prev = NULL; | ||
102 | res->next = NULL; | ||
103 | res->attr_obj = NULL; | ||
104 | res->relationship = NULL; | ||
105 | res->id = GNUNET_strdup (id); | ||
106 | res->type = GNUNET_strdup (type); | ||
107 | return res; | ||
108 | } | ||
109 | |||
110 | /** | ||
111 | * Add a jsonapi relationship | ||
112 | * @param res the resource to add to | ||
113 | * @param rel the relationship to add | ||
114 | * @return #GNUNETOK if added successfully | ||
115 | */ | ||
116 | int | ||
117 | GNUNET_JSONAPI_resource_set_relationship (struct GNUNET_JSONAPI_Resource *res, | ||
118 | struct GNUNET_JSONAPI_Relationship *rel) | ||
119 | { | ||
120 | GNUNET_assert (NULL != res); | ||
121 | GNUNET_assert (NULL != rel); | ||
122 | if (NULL != res->relationship) | ||
123 | return GNUNET_SYSERR; | ||
124 | res->relationship = rel; | ||
125 | return GNUNET_OK; | ||
126 | } | ||
127 | |||
128 | /** | ||
129 | * Add a JSON API attribute | ||
130 | * | ||
131 | * @param res the JSON resource | ||
132 | * @param key the key for the attribute | ||
133 | * @param json the json_t attribute to add | ||
134 | * @return #GNUNET_OK if added successfully | ||
135 | * #GNUNET_SYSERR if not | ||
136 | */ | ||
137 | int | ||
138 | GNUNET_JSONAPI_resource_add_attr (struct GNUNET_JSONAPI_Resource *resource, | ||
139 | const char* key, | ||
140 | json_t *json) | ||
141 | { | ||
142 | if ( (NULL == resource) || | ||
143 | (NULL == key) || | ||
144 | (NULL == json) ) | ||
145 | return GNUNET_SYSERR; | ||
146 | if (NULL == resource->attr_obj) | ||
147 | resource->attr_obj = json_object (); | ||
148 | json_object_set (resource->attr_obj, key, json); | ||
149 | return GNUNET_OK; | ||
150 | } | ||
151 | |||
152 | /** | ||
153 | * Read a JSON API attribute | ||
154 | * | ||
155 | * @param res the JSON resource | ||
156 | * @param key the key for the attribute | ||
157 | * @return the json_t object | ||
158 | */ | ||
159 | json_t* | ||
160 | GNUNET_JSONAPI_resource_read_attr (const struct GNUNET_JSONAPI_Resource *resource, | ||
161 | const char* key) | ||
162 | { | ||
163 | if ( (NULL == resource) || | ||
164 | (NULL == key) || | ||
165 | (NULL == resource->attr_obj)) | ||
166 | return NULL; | ||
167 | return json_object_get (resource->attr_obj, key); | ||
168 | } | ||
169 | |||
170 | int | ||
171 | check_resource_attr_str (const struct GNUNET_JSONAPI_Resource *resource, | ||
172 | const char* key, | ||
173 | const char* attr) | ||
174 | { | ||
175 | json_t *value; | ||
176 | if ( (NULL == resource) || | ||
177 | (NULL == key) || | ||
178 | (NULL == attr) || | ||
179 | (NULL == resource->attr_obj)) | ||
180 | return GNUNET_NO; | ||
181 | value = json_object_get (resource->attr_obj, key); | ||
182 | if (NULL == value) | ||
183 | return GNUNET_NO; | ||
184 | if (!json_is_string (value) || | ||
185 | (0 != strcmp (attr, json_string_value(value)))) | ||
186 | { | ||
187 | return GNUNET_NO; | ||
188 | } | ||
189 | return GNUNET_YES; | ||
190 | } | ||
191 | |||
192 | /** | ||
193 | * Check a JSON API resource type | ||
194 | * | ||
195 | * @param res the JSON resource | ||
196 | * @param type the expected type | ||
197 | * @return GNUNET_YES if id matches | ||
198 | */ | ||
199 | int | ||
200 | GNUNET_JSONAPI_resource_check_type (const struct GNUNET_JSONAPI_Resource *resource, | ||
201 | const char* type) | ||
202 | { | ||
203 | return (0 == memcmp (type, resource->type, | ||
204 | strlen (resource->type))) ? GNUNET_YES : GNUNET_NO; | ||
205 | } | ||
206 | |||
207 | |||
208 | /** | ||
209 | * Delete a JSON API resource | ||
210 | * | ||
211 | * @param res the JSON resource | ||
212 | * @param result Pointer where the resource should be stored | ||
213 | */ | ||
214 | void | ||
215 | GNUNET_JSONAPI_resource_delete (struct GNUNET_JSONAPI_Resource *resource) | ||
216 | { | ||
217 | GNUNET_free (resource->id); | ||
218 | GNUNET_free (resource->type); | ||
219 | if (NULL != resource->attr_obj) | ||
220 | json_decref (resource->attr_obj); | ||
221 | if (NULL != resource->relationship) | ||
222 | GNUNET_JSONAPI_relationship_delete (resource->relationship); | ||
223 | GNUNET_free (resource); | ||
224 | resource = NULL; | ||
225 | } | ||
226 | |||
227 | |||
228 | /** | ||
229 | * Check a JSON API resource id | ||
230 | * | ||
231 | * @param res the JSON resource | ||
232 | * @param id the expected id | ||
233 | * @return GNUNET_YES if id matches | ||
234 | */ | ||
235 | int | ||
236 | GNUNET_JSONAPI_resource_check_id (const struct GNUNET_JSONAPI_Resource *resource, | ||
237 | const char* id) | ||
238 | { | ||
239 | return (0 == memcmp (resource->id, id, strlen (id))) ? GNUNET_YES : GNUNET_NO; | ||
240 | } | ||
241 | |||
242 | /** | ||
243 | * Check a JSON API resource id | ||
244 | * | ||
245 | * @param res the JSON resource | ||
246 | * @return the resource id | ||
247 | */ | ||
248 | char* | ||
249 | GNUNET_JSONAPI_resource_get_id (const struct GNUNET_JSONAPI_Resource *resource) | ||
250 | { | ||
251 | return resource->id; | ||
252 | } | ||
253 | |||
254 | /** | ||
255 | * Parse json to resource object | ||
256 | * | ||
257 | * @param res_json JSON object | ||
258 | * @param[out] res resource object | ||
259 | * @return GNUNET_OK on success | ||
260 | */ | ||
261 | int | ||
262 | GNUNET_JSONAPI_json_to_resource (json_t *res_json, | ||
263 | struct GNUNET_JSONAPI_Resource **res) | ||
264 | { | ||
265 | struct GNUNET_JSON_Specification jsonapispecresource[] = { | ||
266 | GNUNET_JSON_spec_jsonapi_resource (res), | ||
267 | GNUNET_JSON_spec_end() | ||
268 | }; | ||
269 | return GNUNET_JSON_parse (res_json, jsonapispecresource, | ||
270 | NULL, NULL); | ||
271 | } | ||
272 | |||
273 | /** | ||
274 | * Parse given JSON object to jsonapi document. | ||
275 | * | ||
276 | * @param cls closure, NULL | ||
277 | * @param root the json object representing data | ||
278 | * @param[out] spec where to write the data | ||
279 | * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error | ||
280 | */ | ||
281 | static int | ||
282 | parse_jsonapiresource (void *cls, | ||
283 | json_t *root, | ||
284 | struct GNUNET_JSON_Specification *spec) | ||
285 | { | ||
286 | struct GNUNET_JSONAPI_Resource *res; | ||
287 | const char *type; | ||
288 | const char *id; | ||
289 | json_t *attrs; | ||
290 | |||
291 | struct GNUNET_JSON_Specification dspec[] = { | ||
292 | GNUNET_JSON_spec_string (GNUNET_JSONAPI_KEY_TYPE, &type), | ||
293 | GNUNET_JSON_spec_string (GNUNET_JSONAPI_KEY_ID, &id), | ||
294 | GNUNET_JSON_spec_end() | ||
295 | }; | ||
296 | |||
297 | if (GNUNET_OK != | ||
298 | GNUNET_JSON_parse (root, dspec, | ||
299 | NULL, NULL)) | ||
300 | { | ||
301 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unable to parse resource\n"); | ||
302 | return GNUNET_SYSERR; | ||
303 | } | ||
304 | res = GNUNET_JSONAPI_resource_new (type, id); | ||
305 | GNUNET_JSON_parse_free (dspec); | ||
306 | |||
307 | struct GNUNET_JSON_Specification attrspec[] = { | ||
308 | GNUNET_JSON_spec_json (GNUNET_JSONAPI_KEY_ATTRIBUTES, &attrs), | ||
309 | GNUNET_JSON_spec_end() | ||
310 | }; | ||
311 | if (GNUNET_OK != | ||
312 | GNUNET_JSON_parse (root, attrspec, | ||
313 | NULL, NULL)) | ||
314 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Resource does not contain attributes\n"); | ||
315 | if (NULL != attrs) | ||
316 | res->attr_obj = json_deep_copy (attrs); | ||
317 | |||
318 | //TODO relationship | ||
319 | GNUNET_JSON_parse_free (attrspec); | ||
320 | *(struct GNUNET_JSONAPI_Resource **) spec->ptr = res; | ||
321 | return GNUNET_OK; | ||
322 | } | ||
323 | |||
324 | |||
325 | /** | ||
326 | * Cleanup data left from parsing resource. | ||
327 | * | ||
328 | * @param cls closure, NULL | ||
329 | * @param[out] spec where to free the data | ||
330 | */ | ||
331 | static void | ||
332 | clean_jsonapiresource (void *cls, | ||
333 | struct GNUNET_JSON_Specification *spec) | ||
334 | { | ||
335 | struct GNUNET_JSONAPI_Resource **jsonapi_obj; | ||
336 | jsonapi_obj = (struct GNUNET_JSONAPI_Resource **) spec->ptr; | ||
337 | if (NULL != *jsonapi_obj) | ||
338 | { | ||
339 | GNUNET_JSONAPI_resource_delete (*jsonapi_obj); | ||
340 | *jsonapi_obj = NULL; | ||
341 | } | ||
342 | } | ||
343 | |||
344 | |||
345 | /** | ||
346 | * JSON object. | ||
347 | * | ||
348 | * @param name name of the JSON field | ||
349 | * @param[out] jsonp where to store the JSON found under @a name | ||
350 | */ | ||
351 | struct GNUNET_JSON_Specification | ||
352 | GNUNET_JSON_spec_jsonapi_resource (struct GNUNET_JSONAPI_Resource **jsonapi_object) | ||
353 | { | ||
354 | struct GNUNET_JSON_Specification ret = { | ||
355 | .parser = &parse_jsonapiresource, | ||
356 | .cleaner = &clean_jsonapiresource, | ||
357 | .cls = NULL, | ||
358 | .field = NULL, | ||
359 | .ptr = jsonapi_object, | ||
360 | .ptr_size = 0, | ||
361 | .size_ptr = NULL | ||
362 | }; | ||
363 | *jsonapi_object = NULL; | ||
364 | return ret; | ||
365 | } | ||
366 | |||
367 | |||
diff --git a/src/jsonapi/test_jsonapi.c b/src/jsonapi/test_jsonapi.c index e9c85eaf6..8b0b13566 100644 --- a/src/jsonapi/test_jsonapi.c +++ b/src/jsonapi/test_jsonapi.c | |||
@@ -27,14 +27,14 @@ | |||
27 | static int | 27 | static int |
28 | test_serialize () | 28 | test_serialize () |
29 | { | 29 | { |
30 | struct GNUNET_JSONAPI_Object *obj; | 30 | struct GNUNET_JSONAPI_Document *obj; |
31 | char* data = "{\"data\":[{\"id\":\"1\", \"type\":\"test\"}]}"; | 31 | char* data = "{\"data\":{\"id\":\"1\",\"type\":\"bar\", \"attributes\":{\"foo\":\"bar\"}}}"; |
32 | char* tmp_data; | 32 | char* tmp_data; |
33 | json_t* data_js; | 33 | json_t* data_js; |
34 | json_t* tmp_data_js; | 34 | json_t* tmp_data_js; |
35 | json_error_t err; | 35 | json_error_t err; |
36 | struct GNUNET_JSON_Specification jsonapispec[] = { | 36 | struct GNUNET_JSON_Specification jsonapispec[] = { |
37 | GNUNET_JSON_spec_jsonapi (&obj), | 37 | GNUNET_JSON_spec_jsonapi_document (&obj), |
38 | GNUNET_JSON_spec_end() | 38 | GNUNET_JSON_spec_end() |
39 | }; | 39 | }; |
40 | data_js = json_loads (data, JSON_DECODE_ANY, &err); | 40 | data_js = json_loads (data, JSON_DECODE_ANY, &err); |
@@ -42,8 +42,8 @@ test_serialize () | |||
42 | GNUNET_assert (GNUNET_OK == | 42 | GNUNET_assert (GNUNET_OK == |
43 | GNUNET_JSON_parse (data_js, jsonapispec, | 43 | GNUNET_JSON_parse (data_js, jsonapispec, |
44 | NULL, NULL)); | 44 | NULL, NULL)); |
45 | GNUNET_assert (GNUNET_OK == GNUNET_JSONAPI_data_serialize (obj, | 45 | GNUNET_assert (GNUNET_OK == GNUNET_JSONAPI_document_serialize (obj, |
46 | &tmp_data)); | 46 | &tmp_data)); |
47 | GNUNET_JSON_parse_free (jsonapispec); | 47 | GNUNET_JSON_parse_free (jsonapispec); |
48 | tmp_data_js = json_loads (tmp_data, JSON_DECODE_ANY, &err); | 48 | tmp_data_js = json_loads (tmp_data, JSON_DECODE_ANY, &err); |
49 | GNUNET_assert (NULL != tmp_data_js); | 49 | GNUNET_assert (NULL != tmp_data_js); |
@@ -62,14 +62,14 @@ test_serialize () | |||
62 | static int | 62 | static int |
63 | test_spec_jsonapi () | 63 | test_spec_jsonapi () |
64 | { | 64 | { |
65 | struct GNUNET_JSONAPI_Object *obj; | 65 | struct GNUNET_JSONAPI_Document *obj; |
66 | struct GNUNET_JSONAPI_Resource *res; | 66 | struct GNUNET_JSONAPI_Resource *res; |
67 | const char* data = "{\"data\":{\"id\":\"1\", \"type\":\"test\"}}"; | 67 | const char* data = "{\"data\":{\"id\":\"1\", \"type\":\"test\"}}"; |
68 | json_t* data_js; | 68 | json_t* data_js; |
69 | json_error_t err; | 69 | json_error_t err; |
70 | 70 | ||
71 | struct GNUNET_JSON_Specification jsonapispec[] = { | 71 | struct GNUNET_JSON_Specification jsonapispec[] = { |
72 | GNUNET_JSON_spec_jsonapi (&obj), | 72 | GNUNET_JSON_spec_jsonapi_document (&obj), |
73 | GNUNET_JSON_spec_end() | 73 | GNUNET_JSON_spec_end() |
74 | }; | 74 | }; |
75 | data_js = json_loads (data, JSON_DECODE_ANY, &err); | 75 | data_js = json_loads (data, JSON_DECODE_ANY, &err); |
@@ -78,10 +78,10 @@ test_spec_jsonapi () | |||
78 | GNUNET_JSON_parse (data_js, jsonapispec, | 78 | GNUNET_JSON_parse (data_js, jsonapispec, |
79 | NULL, NULL)); | 79 | NULL, NULL)); |
80 | json_decref (data_js); | 80 | json_decref (data_js); |
81 | res = GNUNET_JSONAPI_object_get_resource (obj, 0); | 81 | res = GNUNET_JSONAPI_document_get_resource (obj, 0); |
82 | GNUNET_assert (GNUNET_YES == GNUNET_JSONAPI_resource_check_id (res, "1")); | 82 | GNUNET_assert (GNUNET_YES == GNUNET_JSONAPI_resource_check_id (res, "1")); |
83 | GNUNET_assert (GNUNET_YES == GNUNET_JSONAPI_resource_check_type (res, "test")); | 83 | GNUNET_assert (GNUNET_YES == GNUNET_JSONAPI_resource_check_type (res, "test")); |
84 | GNUNET_assert (1 == GNUNET_JSONAPI_object_resource_count (obj)); | 84 | GNUNET_assert (1 == GNUNET_JSONAPI_document_resource_count (obj)); |
85 | GNUNET_JSON_parse_free (jsonapispec); | 85 | GNUNET_JSON_parse_free (jsonapispec); |
86 | return 0; | 86 | return 0; |
87 | } | 87 | } |