2 This file is part of GNUnet
3 Copyright (C) 2010-2015 Christian Grothoff (and other contributing authors)
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.
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.
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.
23 * @brief helper library to create JSON REST Objects and handle REST
25 * @author Martin Schanzenbach
28 #include "gnunet_util_lib.h"
29 #include "gnunet_rest_lib.h"
30 #include "microhttpd.h"
34 struct JsonApiResource
39 struct JsonApiResource *next;
44 struct JsonApiResource *prev;
58 struct JsonApiResource *res_list_head;
63 struct JsonApiResource *res_list_tail;
77 * Create a JSON API resource
79 * @param type the JSON API resource type
80 * @param id the JSON API resource id
81 * @return a new JSON API resource or NULL on error.
83 struct JsonApiResource*
84 GNUNET_REST_jsonapi_resource_new (const char *type, const char *id)
86 struct JsonApiResource *res;
88 if ( (NULL == type) || (0 == strlen (type)) )
90 if ( (NULL == id) || (0 == strlen (id)) )
93 res = GNUNET_new (struct JsonApiResource);
97 res->res_obj = json_object ();
99 json_object_set_new (res->res_obj, GNUNET_REST_JSONAPI_KEY_ID, json_string (id));
100 json_object_set_new (res->res_obj, GNUNET_REST_JSONAPI_KEY_TYPE, json_string (type));
106 * Delete a JSON API resource
108 * @param res the JSON resource
109 * @param result Pointer where the resource should be stored
112 GNUNET_REST_jsonapi_resource_delete (struct JsonApiResource *resource)
114 json_decref (resource->res_obj);
115 GNUNET_free (resource);
119 * Add a JSON API attribute
121 * @param res the JSON resource
122 * @param key the key for the attribute
123 * @param json the json_t attribute to add
124 * @return #GNUNET_OK if added successfully
125 * #GNUNET_SYSERR if not
128 GNUNET_REST_jsonapi_resource_add_attr (const struct JsonApiResource *resource,
132 if ( (NULL == resource) ||
135 return GNUNET_SYSERR;
136 json_object_set (resource->res_obj, key, json);
141 * Read a JSON API attribute
143 * @param res the JSON resource
144 * @param key the key for the attribute
145 * @return the json_t object
148 GNUNET_REST_jsonapi_resource_read_attr (const struct JsonApiResource *resource,
151 if ( (NULL == resource) ||
154 return json_object_get (resource->res_obj, key);
158 check_resource_attr_str (const struct JsonApiResource *resource,
163 if ( (NULL == resource) ||
167 value = json_object_get (resource->res_obj, key);
170 if (!json_is_string (value) ||
171 (0 != strcmp (attr, json_string_value(value))))
181 * Check a JSON API resource id
183 * @param res the JSON resource
184 * @param id the expected id
185 * @return GNUNET_YES if id matches
188 GNUNET_REST_jsonapi_resource_check_id (const struct JsonApiResource *resource,
191 return check_resource_attr_str (resource, GNUNET_REST_JSONAPI_KEY_ID, id);
196 * Check a JSON API resource type
198 * @param res the JSON resource
199 * @param type the expected type
200 * @return GNUNET_YES if id matches
203 GNUNET_REST_jsonapi_resource_check_type (const struct JsonApiResource *resource,
206 return check_resource_attr_str (resource, GNUNET_REST_JSONAPI_KEY_TYPE, type);
211 * Create a JSON API primary data
213 * @return a new JSON API resource or NULL on error.
215 struct JsonApiObject*
216 GNUNET_REST_jsonapi_object_new ()
218 struct JsonApiObject *result;
220 result = GNUNET_new (struct JsonApiObject);
221 result->res_count = 0;
227 add_json_resource (struct JsonApiObject *obj,
228 const json_t *res_json)
230 struct JsonApiResource *res;
234 id_json = json_object_get (res_json, GNUNET_REST_JSONAPI_KEY_ID);
235 type_json = json_object_get (res_json, GNUNET_REST_JSONAPI_KEY_TYPE);
236 if (!json_is_string (id_json) || !json_is_string (type_json))
238 res = GNUNET_new (struct JsonApiResource);
241 res->res_obj = json_deep_copy (res_json);
242 GNUNET_REST_jsonapi_object_resource_add (obj, res);
246 * Create a JSON API primary data from a string
248 * @param data the string of the JSON API data
249 * @return a new JSON API resource or NULL on error.
251 struct JsonApiObject*
252 GNUNET_REST_jsonapi_object_parse (const char* data)
254 struct JsonApiObject *result;
262 root_json = json_loads (data, 0, &error);
264 if ( (NULL == root_json) || !json_is_object (root_json))
266 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "json error: %s", error.text);
269 data_json = json_object_get (root_json, GNUNET_REST_JSONAPI_KEY_DATA);
270 if (NULL == data_json)
272 json_decref (root_json);
276 result = GNUNET_new (struct JsonApiObject);
277 result->res_count = 0;
278 if (json_is_object (data_json))
279 add_json_resource (result, data_json);
280 else if (json_is_array (data_json))
282 res_count = json_array_size (data_json);
283 for (i = 0; i < res_count; i++)
284 add_json_resource (result, json_array_get (data_json, i));
286 json_decref (root_json);
287 if (0 == result->res_count)
289 GNUNET_free (result);
297 * Delete a JSON API primary data
299 * @param type the JSON API resource type
300 * @param id the JSON API resource id
301 * @return a new JSON API resource or NULL on error.
304 GNUNET_REST_jsonapi_object_delete (struct JsonApiObject *resp)
306 struct JsonApiResource *res;
307 struct JsonApiResource *res_next;
309 for (res = resp->res_list_head;
312 GNUNET_CONTAINER_DLL_remove (resp->res_list_head,
315 res_next = res->next;
316 GNUNET_REST_jsonapi_resource_delete (res);
323 * Add a JSON API object to primary data
325 * @param data The JSON API data to add to
326 * @param res the JSON API resource to add
327 * @return the new number of resources
330 GNUNET_REST_jsonapi_object_resource_add (struct JsonApiObject *resp,
331 struct JsonApiResource *res)
333 GNUNET_CONTAINER_DLL_insert (resp->res_list_head,
342 * Get a JSON API object resource count
344 * @param resp the JSON API object
345 * @return the number of resources
348 GNUNET_REST_jsonapi_object_resource_count (struct JsonApiObject *resp)
350 return resp->res_count++;
354 * Get a JSON API object resource #num
356 * @param resp the JSON API object
357 * @param num the number of the resource
358 * @return the resource
360 struct JsonApiResource*
361 GNUNET_REST_jsonapi_object_get_resource (struct JsonApiObject *resp, int num)
363 struct JsonApiResource *res;
366 if ((0 == resp->res_count) ||
367 (num >= resp->res_count))
369 res = resp->res_list_head;
370 for (i = 0; i < num; i++)
379 * Add a JSON API resource to primary data
381 * @param data The JSON API data to add to
382 * @param res the JSON API resource to add
383 * @return the new number of resources
386 GNUNET_REST_jsonapi_data_resource_remove (struct JsonApiObject *resp,
387 struct JsonApiResource *res)
389 GNUNET_CONTAINER_DLL_remove (resp->res_list_head,
396 * String serialze jsonapi primary data
398 * @param data the JSON API primary data
399 * @param result where to store the result
400 * @return GNUNET_SYSERR on error else GNUNET_OK
403 GNUNET_REST_jsonapi_data_serialize (const struct JsonApiObject *resp,
406 struct JsonApiResource *res;
410 if ( (NULL == resp) ||
411 (0 == resp->res_count) )
412 return GNUNET_SYSERR;
414 root_json = json_object ();
416 if (1 == resp->res_count)
418 json_object_set (root_json, GNUNET_REST_JSONAPI_KEY_DATA, resp->res_list_head->res_obj);
422 res_arr = json_array ();
423 for (res = resp->res_list_head;
427 json_array_append (res_arr, res->res_obj);
429 json_object_set (root_json, GNUNET_REST_JSONAPI_KEY_DATA, res_arr);
431 *result = json_dumps (root_json, JSON_INDENT(2));
440 * Check if namespace is in URL.
442 * @param url URL to check
443 * @param namespace namespace to check against
444 * @retun GNUNET_YES if namespace matches
447 GNUNET_REST_namespace_match (const char *url, const char *namespace)
449 if (0 != strncmp (namespace, url, strlen (namespace)))
452 if ((strlen (namespace) < strlen (url)) &&
453 (url[strlen (namespace)] != '/'))
460 * Create JSON API MHD response
462 * @param data JSON result
463 * @retun MHD response
466 GNUNET_REST_create_json_response (const char *data)
468 struct MHD_Response *resp;
478 resp = MHD_create_response_from_buffer (len,
480 MHD_RESPMEM_MUST_COPY);
481 MHD_add_response_header (resp,MHD_HTTP_HEADER_CONTENT_TYPE,"application/json");
487 GNUNET_REST_handle_request (struct RestConnectionDataHandle *conn,
488 const struct GNUNET_REST_RestConnectionHandler *handlers,
496 while (NULL != handlers[count].method)
499 GNUNET_asprintf (&url, "%s", conn->url);
500 if (url[strlen (url)-1] == '/')
501 url[strlen (url)-1] = '\0';
502 for (i = 0; i < count; i++)
504 if (0 != strcasecmp (conn->method, handlers[i].method))
506 if (strlen (url) < strlen (handlers[i].namespace))
508 if (GNUNET_NO == GNUNET_REST_namespace_match (url, handlers[i].namespace))
511 handlers[i].proc (conn, (const char*)url, cls);