diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/identity/Makefile.am | 1 | ||||
-rw-r--r-- | src/identity/plugin_rest_identity.c | 123 | ||||
-rw-r--r-- | src/include/gnunet_rest_lib.h | 156 | ||||
-rw-r--r-- | src/include/gnunet_rest_plugin.h | 1 | ||||
-rw-r--r-- | src/rest/Makefile.am | 12 | ||||
-rw-r--r-- | src/rest/rest.c | 299 |
6 files changed, 502 insertions, 90 deletions
diff --git a/src/identity/Makefile.am b/src/identity/Makefile.am index 6aabddd39..b0e7645b0 100644 --- a/src/identity/Makefile.am +++ b/src/identity/Makefile.am | |||
@@ -32,6 +32,7 @@ libgnunet_plugin_rest_identity_la_SOURCES = \ | |||
32 | plugin_rest_identity.c | 32 | plugin_rest_identity.c |
33 | libgnunet_plugin_rest_identity_la_LIBADD = \ | 33 | libgnunet_plugin_rest_identity_la_LIBADD = \ |
34 | $(top_builddir)/src/identity/libgnunetidentity.la \ | 34 | $(top_builddir)/src/identity/libgnunetidentity.la \ |
35 | $(top_builddir)/src/rest/libgnunetrest.la \ | ||
35 | $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \ | 36 | $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \ |
36 | $(LTLIBINTL) -ljansson -lmicrohttpd | 37 | $(LTLIBINTL) -ljansson -lmicrohttpd |
37 | libgnunet_plugin_rest_identity_la_LDFLAGS = \ | 38 | libgnunet_plugin_rest_identity_la_LDFLAGS = \ |
diff --git a/src/identity/plugin_rest_identity.c b/src/identity/plugin_rest_identity.c index 1bc5f6fea..ea611128d 100644 --- a/src/identity/plugin_rest_identity.c +++ b/src/identity/plugin_rest_identity.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include "platform.h" | 27 | #include "platform.h" |
28 | #include "gnunet_rest_plugin.h" | 28 | #include "gnunet_rest_plugin.h" |
29 | #include "gnunet_identity_service.h" | 29 | #include "gnunet_identity_service.h" |
30 | #include "gnunet_rest_lib.h" | ||
30 | #include "microhttpd.h" | 31 | #include "microhttpd.h" |
31 | #include <jansson.h> | 32 | #include <jansson.h> |
32 | 33 | ||
@@ -40,9 +41,9 @@ | |||
40 | 41 | ||
41 | #define URL_PARAM_SUBSYS "service" | 42 | #define URL_PARAM_SUBSYS "service" |
42 | 43 | ||
43 | #define JSON_API_TYPE_EGO "ego" | 44 | #define GNUNET_REST_JSONAPI_IDENTITY_EGO "ego" |
44 | 45 | ||
45 | #define JSON_API_TYPE_DATA "data" | 46 | #define GNUNET_REST_JSONAPI_IDENTITY_KEY "key" |
46 | 47 | ||
47 | /** | 48 | /** |
48 | * @brief struct returned by the initialization function of the plugin | 49 | * @brief struct returned by the initialization function of the plugin |
@@ -168,27 +169,6 @@ struct RequestHandle | |||
168 | 169 | ||
169 | }; | 170 | }; |
170 | 171 | ||
171 | /** | ||
172 | * Create s JSON Response for MHD | ||
173 | * | ||
174 | * @param data the JSON to return (can be NULL) | ||
175 | * @return a MHD_Response handle | ||
176 | */ | ||
177 | struct MHD_Response* | ||
178 | create_json_response (const char *data) | ||
179 | { | ||
180 | size_t len; | ||
181 | if (NULL == data) | ||
182 | len = 0; | ||
183 | else | ||
184 | len = strlen (data); | ||
185 | struct MHD_Response *resp = MHD_create_response_from_buffer (len, | ||
186 | (void*)data, | ||
187 | MHD_RESPMEM_MUST_COPY); | ||
188 | MHD_add_response_header (resp,MHD_HTTP_HEADER_CONTENT_TYPE,"application/json"); | ||
189 | return resp; | ||
190 | } | ||
191 | |||
192 | 172 | ||
193 | /** | 173 | /** |
194 | * Cleanup lookup handle | 174 | * Cleanup lookup handle |
@@ -236,7 +216,7 @@ do_error (void *cls, | |||
236 | const struct GNUNET_SCHEDULER_TaskContext *tc) | 216 | const struct GNUNET_SCHEDULER_TaskContext *tc) |
237 | { | 217 | { |
238 | struct RequestHandle *handle = cls; | 218 | struct RequestHandle *handle = cls; |
239 | struct MHD_Response *resp = create_json_response (NULL); | 219 | struct MHD_Response *resp = GNUNET_REST_create_json_response (NULL); |
240 | handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST); | 220 | handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST); |
241 | cleanup_handle (handle); | 221 | cleanup_handle (handle); |
242 | } | 222 | } |
@@ -277,7 +257,7 @@ get_ego_for_subsys (void *cls, | |||
277 | ego_json = json_object (); | 257 | ego_json = json_object (); |
278 | keystring = GNUNET_CRYPTO_ecdsa_public_key_to_string (&ego_entry->pk); | 258 | keystring = GNUNET_CRYPTO_ecdsa_public_key_to_string (&ego_entry->pk); |
279 | json_object_set_new (ego_json, "id", json_string (ego_entry->identifier)); | 259 | json_object_set_new (ego_json, "id", json_string (ego_entry->identifier)); |
280 | json_object_set_new (ego_json, "type", json_string (JSON_API_TYPE_EGO)); | 260 | json_object_set_new (ego_json, "type", json_string (GNUNET_REST_JSONAPI_IDENTITY_EGO)); |
281 | json_object_set_new (ego_json, "key", json_string (keystring)); | 261 | json_object_set_new (ego_json, "key", json_string (keystring)); |
282 | GNUNET_free (keystring); | 262 | GNUNET_free (keystring); |
283 | break; | 263 | break; |
@@ -288,43 +268,18 @@ get_ego_for_subsys (void *cls, | |||
288 | GNUNET_SCHEDULER_add_now (&do_error, handle); | 268 | GNUNET_SCHEDULER_add_now (&do_error, handle); |
289 | return; | 269 | return; |
290 | } | 270 | } |
291 | json_object_set (root_json, JSON_API_TYPE_DATA, ego_json); | 271 | json_object_set (root_json, GNUNET_REST_JSONAPI_KEY_DATA, ego_json); |
292 | result_str = json_dumps (root_json, JSON_COMPACT); | 272 | result_str = json_dumps (root_json, JSON_COMPACT); |
293 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str); | 273 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str); |
294 | json_decref (ego_json); | 274 | json_decref (ego_json); |
295 | json_decref (root_json); | 275 | json_decref (root_json); |
296 | resp = create_json_response (result_str); | 276 | resp = GNUNET_REST_create_json_response (result_str); |
297 | handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); | 277 | handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); |
298 | GNUNET_free (result_str); | 278 | GNUNET_free (result_str); |
299 | cleanup_handle (handle); | 279 | cleanup_handle (handle); |
300 | } | 280 | } |
301 | 281 | ||
302 | /** | 282 | /** |
303 | * Validate the namespace of the requested url | ||
304 | * TODO move this to a lib | ||
305 | * | ||
306 | * @param url the url | ||
307 | * @param ns the namespace | ||
308 | */ | ||
309 | int | ||
310 | check_namespace (const char *url, const char *ns) | ||
311 | { | ||
312 | if (0 != strncmp (EGO_NAMESPACE, url, strlen (EGO_NAMESPACE))) | ||
313 | { | ||
314 | return GNUNET_NO; | ||
315 | } | ||
316 | |||
317 | if ((strlen (EGO_NAMESPACE) < strlen (url)) && | ||
318 | (url[strlen (EGO_NAMESPACE)] != '/')) | ||
319 | { | ||
320 | return GNUNET_NO; | ||
321 | } | ||
322 | return GNUNET_YES; | ||
323 | |||
324 | |||
325 | } | ||
326 | |||
327 | /** | ||
328 | * Create a response with requested ego(s) | 283 | * Create a response with requested ego(s) |
329 | * | 284 | * |
330 | * @param handle the RequestHandle | 285 | * @param handle the RequestHandle |
@@ -339,18 +294,19 @@ ego_info_response (struct RequestHandle *handle) | |||
339 | struct EgoEntry *ego_entry; | 294 | struct EgoEntry *ego_entry; |
340 | struct GNUNET_HashCode key; | 295 | struct GNUNET_HashCode key; |
341 | struct MHD_Response *resp; | 296 | struct MHD_Response *resp; |
342 | json_t *ego_arr; | 297 | struct JsonApiResponse *json_response; |
343 | json_t *ego_json; | 298 | struct JsonApiResource *json_resource; |
344 | json_t *root_json; | 299 | json_t *key_str; |
345 | 300 | ||
346 | if (GNUNET_NO == check_namespace (handle->url, EGO_NAMESPACE)) | 301 | if (GNUNET_NO == GNUNET_REST_namespace_match (handle->url, EGO_NAMESPACE)) |
347 | { | 302 | { |
348 | resp = create_json_response (NULL); | 303 | resp = GNUNET_REST_create_json_response (NULL); |
349 | handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST); | 304 | handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST); |
350 | cleanup_handle (handle); | 305 | cleanup_handle (handle); |
351 | GNUNET_break (0); | 306 | GNUNET_break (0); |
352 | return; | 307 | return; |
353 | } | 308 | } |
309 | json_response = GNUNET_REST_jsonapi_response_new (); | ||
354 | if ( (strlen (EGO_NAMESPACE) == strlen (handle->url) )) { | 310 | if ( (strlen (EGO_NAMESPACE) == strlen (handle->url) )) { |
355 | GNUNET_CRYPTO_hash (URL_PARAM_SUBSYS, strlen (URL_PARAM_SUBSYS), &key); | 311 | GNUNET_CRYPTO_hash (URL_PARAM_SUBSYS, strlen (URL_PARAM_SUBSYS), &key); |
356 | if ( GNUNET_YES == | 312 | if ( GNUNET_YES == |
@@ -371,8 +327,7 @@ ego_info_response (struct RequestHandle *handle) | |||
371 | } | 327 | } |
372 | } | 328 | } |
373 | } | 329 | } |
374 | ego_arr = json_array (); | 330 | json_response = GNUNET_REST_jsonapi_response_new (); |
375 | root_json = json_object (); | ||
376 | egoname = &handle->url[strlen (EGO_NAMESPACE)+1]; | 331 | egoname = &handle->url[strlen (EGO_NAMESPACE)+1]; |
377 | 332 | ||
378 | if (strlen (EGO_NAMESPACE) == strlen (handle->url)) | 333 | if (strlen (EGO_NAMESPACE) == strlen (handle->url)) |
@@ -387,36 +342,24 @@ ego_info_response (struct RequestHandle *handle) | |||
387 | { | 342 | { |
388 | if ( (NULL != egoname) && (0 != strcmp (egoname, ego_entry->identifier)) ) | 343 | if ( (NULL != egoname) && (0 != strcmp (egoname, ego_entry->identifier)) ) |
389 | continue; | 344 | continue; |
390 | ego_json = json_object (); | ||
391 | keystring = GNUNET_CRYPTO_ecdsa_public_key_to_string (&ego_entry->pk); | 345 | keystring = GNUNET_CRYPTO_ecdsa_public_key_to_string (&ego_entry->pk); |
392 | json_object_set_new (ego_json, "id", json_string (ego_entry->identifier)); | 346 | json_resource = GNUNET_REST_jsonapi_resource_new (GNUNET_REST_JSONAPI_IDENTITY_EGO, ego_entry->identifier); |
393 | json_object_set_new (ego_json, "key", json_string (keystring)); | 347 | key_str = json_string (keystring); |
394 | json_object_set_new (ego_json, "type", json_string (JSON_API_TYPE_EGO)); | 348 | GNUNET_REST_jsonapi_resource_add_attr (json_resource, |
349 | GNUNET_REST_JSONAPI_IDENTITY_KEY, | ||
350 | key_str); | ||
351 | json_decref (key_str); | ||
395 | GNUNET_free (keystring); | 352 | GNUNET_free (keystring); |
396 | if (NULL == egoname) | 353 | GNUNET_REST_jsonapi_response_resource_add (json_response, json_resource); |
397 | { | ||
398 | json_array_append (ego_arr, ego_json); | ||
399 | json_decref (ego_json); | ||
400 | } | ||
401 | else | ||
402 | break; | ||
403 | } | 354 | } |
404 | if (NULL == egoname) | ||
405 | json_object_set (root_json, "egos", ego_arr); | ||
406 | else | ||
407 | json_object_set (root_json, "ego", ego_json); | ||
408 | 355 | ||
409 | result_str = json_dumps (root_json, JSON_COMPACT); | 356 | GNUNET_REST_jsonapi_data_serialize (json_response, &result_str); |
410 | json_decref (ego_arr); | ||
411 | if (NULL != egoname) | ||
412 | json_decref (ego_json); | ||
413 | 357 | ||
414 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str); | 358 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str); |
415 | resp = create_json_response (result_str); | 359 | resp = GNUNET_REST_create_json_response (result_str); |
416 | handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); | 360 | handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); |
417 | GNUNET_free (result_str); | 361 | GNUNET_free (result_str); |
418 | cleanup_handle (handle); | 362 | cleanup_handle (handle); |
419 | |||
420 | } | 363 | } |
421 | 364 | ||
422 | static void | 365 | static void |
@@ -431,7 +374,7 @@ do_finished (void *cls, const char *emsg) | |||
431 | GNUNET_SCHEDULER_add_now (&do_error, handle); | 374 | GNUNET_SCHEDULER_add_now (&do_error, handle); |
432 | return; | 375 | return; |
433 | } | 376 | } |
434 | resp = create_json_response (NULL); | 377 | resp = GNUNET_REST_create_json_response (NULL); |
435 | handle->proc (handle->proc_cls, resp, MHD_HTTP_NO_CONTENT); | 378 | handle->proc (handle->proc_cls, resp, MHD_HTTP_NO_CONTENT); |
436 | cleanup_handle (handle); | 379 | cleanup_handle (handle); |
437 | } | 380 | } |
@@ -448,7 +391,7 @@ set_finished (void *cls, const char *emsg) | |||
448 | GNUNET_SCHEDULER_add_now (&do_error, handle); | 391 | GNUNET_SCHEDULER_add_now (&do_error, handle); |
449 | return; | 392 | return; |
450 | } | 393 | } |
451 | resp = create_json_response (NULL); | 394 | resp = GNUNET_REST_create_json_response (NULL); |
452 | handle->proc (handle->proc_cls, resp, MHD_HTTP_NO_CONTENT); | 395 | handle->proc (handle->proc_cls, resp, MHD_HTTP_NO_CONTENT); |
453 | cleanup_handle (handle); | 396 | cleanup_handle (handle); |
454 | } | 397 | } |
@@ -465,7 +408,7 @@ create_finished (void *cls, const char *emsg) | |||
465 | GNUNET_SCHEDULER_add_now (&do_error, handle); | 408 | GNUNET_SCHEDULER_add_now (&do_error, handle); |
466 | return; | 409 | return; |
467 | } | 410 | } |
468 | resp = create_json_response (NULL); | 411 | resp = GNUNET_REST_create_json_response (NULL); |
469 | handle->proc (handle->proc_cls, resp, MHD_HTTP_NO_CONTENT); | 412 | handle->proc (handle->proc_cls, resp, MHD_HTTP_NO_CONTENT); |
470 | cleanup_handle (handle); | 413 | cleanup_handle (handle); |
471 | } | 414 | } |
@@ -503,7 +446,7 @@ ego_create_cont (struct RequestHandle *handle) | |||
503 | GNUNET_SCHEDULER_add_now (&do_error, handle); | 446 | GNUNET_SCHEDULER_add_now (&do_error, handle); |
504 | return; | 447 | return; |
505 | } | 448 | } |
506 | data_json = json_object_get (root_json, JSON_API_TYPE_DATA); | 449 | data_json = json_object_get (root_json, GNUNET_REST_JSONAPI_KEY_DATA); |
507 | if ((NULL == data_json) || !json_is_object (data_json)) | 450 | if ((NULL == data_json) || !json_is_object (data_json)) |
508 | { | 451 | { |
509 | GNUNET_SCHEDULER_add_now (&do_error, handle); | 452 | GNUNET_SCHEDULER_add_now (&do_error, handle); |
@@ -511,11 +454,11 @@ ego_create_cont (struct RequestHandle *handle) | |||
511 | } | 454 | } |
512 | type_json = json_object_get (data_json, "type"); | 455 | type_json = json_object_get (data_json, "type"); |
513 | if (!json_is_string (type_json) || | 456 | if (!json_is_string (type_json) || |
514 | (0 != strcmp (JSON_API_TYPE_EGO, json_string_value (type_json)))) | 457 | (0 != strcmp (GNUNET_REST_JSONAPI_IDENTITY_EGO, json_string_value (type_json)))) |
515 | { | 458 | { |
516 | json_decref (data_json); | 459 | json_decref (data_json); |
517 | json_decref (root_json); | 460 | json_decref (root_json); |
518 | resp = create_json_response (NULL); | 461 | resp = GNUNET_REST_create_json_response (NULL); |
519 | handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT); | 462 | handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT); |
520 | cleanup_handle (handle); | 463 | cleanup_handle (handle); |
521 | return; | 464 | return; |
@@ -540,7 +483,7 @@ ego_create_cont (struct RequestHandle *handle) | |||
540 | json_decref (egoname_json); | 483 | json_decref (egoname_json); |
541 | json_decref (data_json); | 484 | json_decref (data_json); |
542 | json_decref (root_json); | 485 | json_decref (root_json); |
543 | resp = create_json_response (NULL); | 486 | resp = GNUNET_REST_create_json_response (NULL); |
544 | handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT); | 487 | handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT); |
545 | cleanup_handle (handle); | 488 | cleanup_handle (handle); |
546 | return; | 489 | return; |
@@ -591,7 +534,7 @@ subsys_set_cont (struct RequestHandle *handle) | |||
591 | } | 534 | } |
592 | if (GNUNET_NO == ego_exists) | 535 | if (GNUNET_NO == ego_exists) |
593 | { | 536 | { |
594 | resp = create_json_response (NULL); | 537 | resp = GNUNET_REST_create_json_response (NULL); |
595 | handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND); | 538 | handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND); |
596 | cleanup_handle (handle); | 539 | cleanup_handle (handle); |
597 | return; | 540 | return; |
@@ -632,7 +575,7 @@ subsys_set_cont (struct RequestHandle *handle) | |||
632 | 575 | ||
633 | type_json = json_object_get (data_json, "type"); | 576 | type_json = json_object_get (data_json, "type"); |
634 | if (!json_is_string (type_json) || | 577 | if (!json_is_string (type_json) || |
635 | (0 != strcmp (JSON_API_TYPE_EGO, json_string_value (type_json)))) | 578 | (0 != strcmp (GNUNET_REST_JSONAPI_IDENTITY_EGO, json_string_value (type_json)))) |
636 | { | 579 | { |
637 | json_decref (root_json); | 580 | json_decref (root_json); |
638 | json_decref (data_json); | 581 | json_decref (data_json); |
@@ -687,7 +630,7 @@ ego_delete_cont (struct RequestHandle *handle) | |||
687 | } | 630 | } |
688 | if (GNUNET_NO == ego_exists) | 631 | if (GNUNET_NO == ego_exists) |
689 | { | 632 | { |
690 | resp = create_json_response (NULL); | 633 | resp = GNUNET_REST_create_json_response (NULL); |
691 | handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND); | 634 | handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND); |
692 | cleanup_handle (handle); | 635 | cleanup_handle (handle); |
693 | return; | 636 | return; |
diff --git a/src/include/gnunet_rest_lib.h b/src/include/gnunet_rest_lib.h new file mode 100644 index 000000000..19a0168e5 --- /dev/null +++ b/src/include/gnunet_rest_lib.h | |||
@@ -0,0 +1,156 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet | ||
3 | Copyright (C) 2010-2015 Christian Grothoff (and other contributing authors) | ||
4 | |||
5 | GNUnet is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 3, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with GNUnet; see the file COPYING. If not, write to the | ||
17 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file include/gnunet_rest_lib.h | ||
23 | * @brief API for helper library to parse/create REST | ||
24 | * @author Martin Schanzenbach | ||
25 | */ | ||
26 | #ifndef GNUNET_REST_LIB_H | ||
27 | #define GNUNET_REST_LIB_H | ||
28 | |||
29 | #include "gnunet_util_lib.h" | ||
30 | #include "microhttpd.h" | ||
31 | #include <jansson.h> | ||
32 | |||
33 | #define GNUNET_REST_JSONAPI_KEY_DATA "data" | ||
34 | |||
35 | #define GNUNET_REST_JSONAPI_KEY_ID "id" | ||
36 | |||
37 | #define GNUNET_REST_JSONAPI_KEY_TYPE "type" | ||
38 | |||
39 | /** | ||
40 | * Resource structs for JSON API | ||
41 | */ | ||
42 | struct JsonApiResource; | ||
43 | |||
44 | /** | ||
45 | * Responses for JSON API | ||
46 | */ | ||
47 | struct JsonApiResponse; | ||
48 | |||
49 | /** | ||
50 | * Create a JSON API resource | ||
51 | * | ||
52 | * @param type the JSON API resource type | ||
53 | * @param id the JSON API resource id | ||
54 | * @return a new JSON API resource or NULL on error. | ||
55 | */ | ||
56 | struct JsonApiResource* | ||
57 | GNUNET_REST_jsonapi_resource_new (const char *type, const char *id); | ||
58 | |||
59 | /** | ||
60 | * Delete a JSON API resource | ||
61 | * | ||
62 | * @param res the JSON resource | ||
63 | * @param result Pointer where the resource should be stored | ||
64 | */ | ||
65 | void | ||
66 | GNUNET_REST_jsonapi_resource_delete (struct JsonApiResource *resource); | ||
67 | |||
68 | /** | ||
69 | * Add a JSON API attribute | ||
70 | * | ||
71 | * @param res the JSON resource | ||
72 | * @param key the key for the attribute | ||
73 | * @param json the json_t attribute to add | ||
74 | * @return #GNUNET_OK if added successfully | ||
75 | * #GNUNET_SYSERR if not | ||
76 | */ | ||
77 | int | ||
78 | GNUNET_REST_jsonapi_resource_add_attr (const struct JsonApiResource *resource, | ||
79 | const char* key, | ||
80 | json_t *json); | ||
81 | |||
82 | /** | ||
83 | * Create a JSON API primary data | ||
84 | * | ||
85 | * @param type the JSON API resource type | ||
86 | * @param id the JSON API resource id | ||
87 | * @return a new JSON API resource or NULL on error. | ||
88 | */ | ||
89 | struct JsonApiResponse* | ||
90 | GNUNET_REST_jsonapi_response_new (); | ||
91 | |||
92 | /** | ||
93 | * Delete a JSON API primary data | ||
94 | * | ||
95 | * @param type the JSON API resource type | ||
96 | * @param id the JSON API resource id | ||
97 | * @return a new JSON API resource or NULL on error. | ||
98 | */ | ||
99 | void | ||
100 | GNUNET_REST_jsonapi_response_delete (struct JsonApiResponse *resp); | ||
101 | |||
102 | /** | ||
103 | * Add a JSON API resource to primary data | ||
104 | * | ||
105 | * @param data The JSON API data to add to | ||
106 | * @param res the JSON API resource to add | ||
107 | * @return the new number of resources | ||
108 | */ | ||
109 | void | ||
110 | GNUNET_REST_jsonapi_response_resource_add (struct JsonApiResponse *resp, | ||
111 | struct JsonApiResource *res); | ||
112 | |||
113 | /** | ||
114 | * Add a JSON API resource to primary data | ||
115 | * | ||
116 | * @param resp The JSON API data to add to | ||
117 | * @param res the JSON API resource to add | ||
118 | * @return the new number of resources | ||
119 | */ | ||
120 | void | ||
121 | GNUNET_REST_jsonapi_data_resource_remove (struct JsonApiResponse *resp, | ||
122 | struct JsonApiResource *res); | ||
123 | |||
124 | /** | ||
125 | * String serialze jsonapi primary data | ||
126 | * | ||
127 | * @param data the JSON API primary data | ||
128 | * @param result where to store the result | ||
129 | * @return GNUNET_SYSERR on error else GNUNET_OK | ||
130 | */ | ||
131 | int | ||
132 | GNUNET_REST_jsonapi_data_serialize (const struct JsonApiResponse *resp, | ||
133 | char **result); | ||
134 | |||
135 | /** | ||
136 | * Check if namespace is in URL. | ||
137 | * | ||
138 | * @param url URL to check | ||
139 | * @param namespace namespace to check against | ||
140 | * @retun GNUNET_YES if namespace matches | ||
141 | */ | ||
142 | int | ||
143 | GNUNET_REST_namespace_match (const char *url, const char *namespace); | ||
144 | |||
145 | /** | ||
146 | * Create JSON API MHD response | ||
147 | * | ||
148 | * @param data JSON result | ||
149 | * @retun MHD response | ||
150 | */ | ||
151 | struct MHD_Response* | ||
152 | GNUNET_REST_create_json_response (const char *data); | ||
153 | |||
154 | |||
155 | |||
156 | #endif | ||
diff --git a/src/include/gnunet_rest_plugin.h b/src/include/gnunet_rest_plugin.h index 1d5a2db59..e085ccf32 100644 --- a/src/include/gnunet_rest_plugin.h +++ b/src/include/gnunet_rest_plugin.h | |||
@@ -37,6 +37,7 @@ extern "C" | |||
37 | #endif | 37 | #endif |
38 | #endif | 38 | #endif |
39 | 39 | ||
40 | |||
40 | /** | 41 | /** |
41 | * Iterator called on obtained result for a REST result. | 42 | * Iterator called on obtained result for a REST result. |
42 | * | 43 | * |
diff --git a/src/rest/Makefile.am b/src/rest/Makefile.am index 00021cce2..8ea87fc6a 100644 --- a/src/rest/Makefile.am +++ b/src/rest/Makefile.am | |||
@@ -20,6 +20,9 @@ if USE_COVERAGE | |||
20 | XLIBS = -lgcov | 20 | XLIBS = -lgcov |
21 | endif | 21 | endif |
22 | 22 | ||
23 | lib_LTLIBRARIES = \ | ||
24 | libgnunetrest.la | ||
25 | |||
23 | libexec_PROGRAMS = \ | 26 | libexec_PROGRAMS = \ |
24 | gnunet-rest-server | 27 | gnunet-rest-server |
25 | 28 | ||
@@ -29,3 +32,12 @@ gnunet_rest_server_SOURCES = \ | |||
29 | gnunet_rest_server_LDADD = \ | 32 | gnunet_rest_server_LDADD = \ |
30 | $(top_builddir)/src/util/libgnunetutil.la \ | 33 | $(top_builddir)/src/util/libgnunetutil.la \ |
31 | $(GN_LIBINTL) -lmicrohttpd | 34 | $(GN_LIBINTL) -lmicrohttpd |
35 | |||
36 | libgnunetrest_la_SOURCES = \ | ||
37 | rest.c | ||
38 | libgnunetrest_la_LIBADD = \ | ||
39 | $(top_builddir)/src/util/libgnunetutil.la $(XLIB) \ | ||
40 | $(GN_LIBINTL) -lmicrohttpd -ljansson | ||
41 | libgnunetrest_la_LDFLAGS = \ | ||
42 | $(GN_LIB_LDFLAGS) \ | ||
43 | -version-info 0:0:0 | ||
diff --git a/src/rest/rest.c b/src/rest/rest.c new file mode 100644 index 000000000..0b843ec61 --- /dev/null +++ b/src/rest/rest.c | |||
@@ -0,0 +1,299 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet | ||
3 | Copyright (C) 2010-2015 Christian Grothoff (and other contributing authors) | ||
4 | |||
5 | GNUnet is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 3, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with GNUnet; see the file COPYING. If not, write to the | ||
17 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file rest/rest.c | ||
23 | * @brief helper library to create JSON REST Objects and handle REST | ||
24 | * responses/requests. | ||
25 | * @author Martin Schanzenbach | ||
26 | */ | ||
27 | #include "platform.h" | ||
28 | #include "gnunet_util_lib.h" | ||
29 | #include "gnunet_rest_lib.h" | ||
30 | #include "microhttpd.h" | ||
31 | #include <jansson.h> | ||
32 | |||
33 | |||
34 | struct JsonApiResource | ||
35 | { | ||
36 | /** | ||
37 | * DLL | ||
38 | */ | ||
39 | struct JsonApiResource *next; | ||
40 | |||
41 | /** | ||
42 | * DLL | ||
43 | */ | ||
44 | struct JsonApiResource *prev; | ||
45 | |||
46 | /** | ||
47 | * Resource content | ||
48 | */ | ||
49 | json_t *res_obj; | ||
50 | }; | ||
51 | |||
52 | |||
53 | struct JsonApiResponse | ||
54 | { | ||
55 | /** | ||
56 | * DLL Resource | ||
57 | */ | ||
58 | struct JsonApiResource *res_list_head; | ||
59 | |||
60 | /** | ||
61 | * DLL Resource | ||
62 | */ | ||
63 | struct JsonApiResource *res_list_tail; | ||
64 | |||
65 | /** | ||
66 | * num resources | ||
67 | */ | ||
68 | int res_count; | ||
69 | }; | ||
70 | |||
71 | /** | ||
72 | * JSON API | ||
73 | */ | ||
74 | |||
75 | /** | ||
76 | * Create a JSON API resource | ||
77 | * | ||
78 | * @param type the JSON API resource type | ||
79 | * @param id the JSON API resource id | ||
80 | * @return a new JSON API resource or NULL on error. | ||
81 | */ | ||
82 | struct JsonApiResource* | ||
83 | GNUNET_REST_jsonapi_resource_new (const char *type, const char *id) | ||
84 | { | ||
85 | struct JsonApiResource *res; | ||
86 | |||
87 | if ( (NULL == type) || (0 == strlen (type)) ) | ||
88 | return NULL; | ||
89 | if ( (NULL == id) || (0 == strlen (id)) ) | ||
90 | return NULL; | ||
91 | |||
92 | res = GNUNET_new (struct JsonApiResource); | ||
93 | |||
94 | res->res_obj = json_object (); | ||
95 | |||
96 | json_object_set_new (res->res_obj, GNUNET_REST_JSONAPI_KEY_ID, json_string (id)); | ||
97 | json_object_set_new (res->res_obj, GNUNET_REST_JSONAPI_KEY_TYPE, json_string (type)); | ||
98 | |||
99 | return res; | ||
100 | } | ||
101 | |||
102 | /** | ||
103 | * Delete a JSON API resource | ||
104 | * | ||
105 | * @param res the JSON resource | ||
106 | * @param result Pointer where the resource should be stored | ||
107 | */ | ||
108 | void | ||
109 | GNUNET_REST_jsonapi_resource_delete (struct JsonApiResource *resource) | ||
110 | { | ||
111 | json_decref (resource->res_obj); | ||
112 | GNUNET_free (resource); | ||
113 | } | ||
114 | |||
115 | /** | ||
116 | * Add a JSON API attribute | ||
117 | * | ||
118 | * @param res the JSON resource | ||
119 | * @param key the key for the attribute | ||
120 | * @param json the json_t attribute to add | ||
121 | * @return #GNUNET_OK if added successfully | ||
122 | * #GNUNET_SYSERR if not | ||
123 | */ | ||
124 | int | ||
125 | GNUNET_REST_jsonapi_resource_add_attr (const struct JsonApiResource *resource, | ||
126 | const char* key, | ||
127 | json_t *json) | ||
128 | { | ||
129 | if ( (NULL == resource) || | ||
130 | (NULL == key) || | ||
131 | (NULL == json) ) | ||
132 | return GNUNET_SYSERR; | ||
133 | json_object_set (resource->res_obj, key, json); | ||
134 | return GNUNET_OK; | ||
135 | } | ||
136 | |||
137 | |||
138 | |||
139 | |||
140 | /** | ||
141 | * Create a JSON API primary data | ||
142 | * | ||
143 | * @param type the JSON API resource type | ||
144 | * @param id the JSON API resource id | ||
145 | * @return a new JSON API resource or NULL on error. | ||
146 | */ | ||
147 | struct JsonApiResponse* | ||
148 | GNUNET_REST_jsonapi_response_new () | ||
149 | { | ||
150 | struct JsonApiResponse *result; | ||
151 | |||
152 | result = GNUNET_new (struct JsonApiResponse); | ||
153 | result->res_count = 0; | ||
154 | return result; | ||
155 | } | ||
156 | |||
157 | /** | ||
158 | * Delete a JSON API primary data | ||
159 | * | ||
160 | * @param type the JSON API resource type | ||
161 | * @param id the JSON API resource id | ||
162 | * @return a new JSON API resource or NULL on error. | ||
163 | */ | ||
164 | void | ||
165 | GNUNET_REST_jsonapi_response_delete (struct JsonApiResponse *resp) | ||
166 | { | ||
167 | struct JsonApiResource *res; | ||
168 | |||
169 | for (res = resp->res_list_head; | ||
170 | res != NULL; | ||
171 | res = res->next) | ||
172 | GNUNET_REST_jsonapi_resource_delete (res); | ||
173 | GNUNET_free (resp); | ||
174 | } | ||
175 | |||
176 | /** | ||
177 | * Add a JSON API resource to primary data | ||
178 | * | ||
179 | * @param data The JSON API data to add to | ||
180 | * @param res the JSON API resource to add | ||
181 | * @return the new number of resources | ||
182 | */ | ||
183 | void | ||
184 | GNUNET_REST_jsonapi_response_resource_add (struct JsonApiResponse *resp, | ||
185 | struct JsonApiResource *res) | ||
186 | { | ||
187 | GNUNET_CONTAINER_DLL_insert (resp->res_list_head, | ||
188 | resp->res_list_tail, | ||
189 | res); | ||
190 | |||
191 | resp->res_count++; | ||
192 | } | ||
193 | |||
194 | /** | ||
195 | * Add a JSON API resource to primary data | ||
196 | * | ||
197 | * @param data The JSON API data to add to | ||
198 | * @param res the JSON API resource to add | ||
199 | * @return the new number of resources | ||
200 | */ | ||
201 | void | ||
202 | GNUNET_REST_jsonapi_data_resource_remove (struct JsonApiResponse *resp, | ||
203 | struct JsonApiResource *res) | ||
204 | { | ||
205 | GNUNET_CONTAINER_DLL_remove (resp->res_list_head, | ||
206 | resp->res_list_tail, | ||
207 | res); | ||
208 | resp->res_count--; | ||
209 | } | ||
210 | |||
211 | /** | ||
212 | * String serialze jsonapi primary data | ||
213 | * | ||
214 | * @param data the JSON API primary data | ||
215 | * @param result where to store the result | ||
216 | * @return GNUNET_SYSERR on error else GNUNET_OK | ||
217 | */ | ||
218 | int | ||
219 | GNUNET_REST_jsonapi_data_serialize (const struct JsonApiResponse *resp, | ||
220 | char **result) | ||
221 | { | ||
222 | struct JsonApiResource *res; | ||
223 | json_t *root_json; | ||
224 | json_t *res_arr; | ||
225 | |||
226 | if ( (NULL == resp) || | ||
227 | (0 == resp->res_count) ) | ||
228 | return GNUNET_SYSERR; | ||
229 | |||
230 | root_json = json_object (); | ||
231 | |||
232 | if (1 == resp->res_count) | ||
233 | { | ||
234 | json_object_set (root_json, GNUNET_REST_JSONAPI_KEY_DATA, resp->res_list_head->res_obj); | ||
235 | } | ||
236 | else | ||
237 | { | ||
238 | res_arr = json_array (); | ||
239 | for (res = resp->res_list_head; | ||
240 | res != NULL; | ||
241 | res = res->next) | ||
242 | { | ||
243 | json_array_append (res_arr, res->res_obj); | ||
244 | } | ||
245 | json_object_set (root_json, GNUNET_REST_JSONAPI_KEY_DATA, res_arr); | ||
246 | } | ||
247 | *result = json_dumps (root_json, JSON_COMPACT); | ||
248 | return GNUNET_OK; | ||
249 | } | ||
250 | |||
251 | /** | ||
252 | * REST Utilities | ||
253 | */ | ||
254 | |||
255 | /** | ||
256 | * Check if namespace is in URL. | ||
257 | * | ||
258 | * @param url URL to check | ||
259 | * @param namespace namespace to check against | ||
260 | * @retun GNUNET_YES if namespace matches | ||
261 | */ | ||
262 | int | ||
263 | GNUNET_REST_namespace_match (const char *url, const char *namespace) | ||
264 | { | ||
265 | if (0 != strncmp (namespace, url, strlen (namespace))) | ||
266 | return GNUNET_NO; | ||
267 | |||
268 | if ((strlen (namespace) < strlen (url)) && | ||
269 | (url[strlen (namespace)] != '/')) | ||
270 | return GNUNET_NO; | ||
271 | |||
272 | return GNUNET_YES; | ||
273 | } | ||
274 | |||
275 | /** | ||
276 | * Create JSON API MHD response | ||
277 | * | ||
278 | * @param data JSON result | ||
279 | * @retun MHD response | ||
280 | */ | ||
281 | struct MHD_Response* | ||
282 | GNUNET_REST_create_json_response (const char *data) | ||
283 | { | ||
284 | struct MHD_Response *resp; | ||
285 | size_t len; | ||
286 | |||
287 | if (NULL == data) | ||
288 | len = 0; | ||
289 | else | ||
290 | len = strlen (data); | ||
291 | resp = MHD_create_response_from_buffer (len, | ||
292 | (void*)data, | ||
293 | MHD_RESPMEM_MUST_COPY); | ||
294 | MHD_add_response_header (resp,MHD_HTTP_HEADER_CONTENT_TYPE,"application/json"); | ||
295 | return resp; | ||
296 | |||
297 | } | ||
298 | |||
299 | /* end of rest.c */ | ||