aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMartin Schanzenbach <mschanzenbach@posteo.de>2015-04-01 14:02:35 +0000
committerMartin Schanzenbach <mschanzenbach@posteo.de>2015-04-01 14:02:35 +0000
commit7f2c9fde223cf7734fec8cdfb913b16579af41a3 (patch)
tree6fedf4aa5a856bf51eeaba2128f368756daf1214 /src
parent0be69c24d931816c063e89409ff09a605afbcbad (diff)
downloadgnunet-7f2c9fde223cf7734fec8cdfb913b16579af41a3.tar.gz
gnunet-7f2c9fde223cf7734fec8cdfb913b16579af41a3.zip
- namestore rest
Diffstat (limited to 'src')
-rw-r--r--src/namestore/Makefile.am19
-rw-r--r--src/namestore/plugin_rest_namestore.c1048
-rw-r--r--src/rest/rest.c2
3 files changed, 1066 insertions, 3 deletions
diff --git a/src/namestore/Makefile.am b/src/namestore/Makefile.am
index 98043373d..2f8c81425 100644
--- a/src/namestore/Makefile.am
+++ b/src/namestore/Makefile.am
@@ -98,6 +98,22 @@ libexec_PROGRAMS += \
98 gnunet-namestore-fcfsd 98 gnunet-namestore-fcfsd
99endif 99endif
100 100
101if HAVE_REST
102REST_PLUGIN = libgnunet_plugin_rest_namestore.la
103endif
104
105libgnunet_plugin_rest_namestore_la_SOURCES = \
106 plugin_rest_namestore.c
107libgnunet_plugin_rest_namestore_la_LIBADD = \
108 $(top_builddir)/src/namestore/libgnunetnamestore.la \
109 $(top_builddir)/src/identity/libgnunetidentity.la \
110 $(top_builddir)/src/rest/libgnunetrest.la \
111 $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \
112 $(LTLIBINTL) -ljansson -lmicrohttpd
113libgnunet_plugin_rest_namestore_la_LDFLAGS = \
114 $(GN_PLUGIN_LDFLAGS)
115
116
101gnunet_namestore_SOURCES = \ 117gnunet_namestore_SOURCES = \
102 gnunet-namestore.c 118 gnunet-namestore.c
103gnunet_namestore_LDADD = \ 119gnunet_namestore_LDADD = \
@@ -133,7 +149,8 @@ gnunet_service_namestore_LDADD = \
133 149
134plugin_LTLIBRARIES = \ 150plugin_LTLIBRARIES = \
135 $(SQLITE_PLUGIN) \ 151 $(SQLITE_PLUGIN) \
136 $(POSTGRES_PLUGIN) 152 $(POSTGRES_PLUGIN) \
153 $(REST_PLUGIN)
137 154
138libgnunet_plugin_namestore_sqlite_la_SOURCES = \ 155libgnunet_plugin_namestore_sqlite_la_SOURCES = \
139 plugin_namestore_sqlite.c 156 plugin_namestore_sqlite.c
diff --git a/src/namestore/plugin_rest_namestore.c b/src/namestore/plugin_rest_namestore.c
new file mode 100644
index 000000000..365e10046
--- /dev/null
+++ b/src/namestore/plugin_rest_namestore.c
@@ -0,0 +1,1048 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012-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 * @author Martin Schanzenbach
22 * @file namestore/plugin_rest_namestore.c
23 * @brief GNUnet Namestore REST plugin
24 *
25 */
26
27#include "platform.h"
28#include "gnunet_rest_plugin.h"
29#include "gnunet_namestore_service.h"
30#include "gnunet_identity_service.h"
31#include "gnunet_rest_lib.h"
32#include "microhttpd.h"
33#include <jansson.h>
34
35#define GNUNET_REST_API_NS_NAMESTORE "/names"
36
37#define GNUNET_REST_JSONAPI_NAMESTORE_TYPEINFO "record"
38
39#define GNUNET_REST_JSONAPI_NAMESTORE_RECORD GNUNET_REST_JSONAPI_NAMESTORE_TYPEINFO
40
41#define GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE "record_type"
42
43#define GNUNET_REST_JSONAPI_NAMESTORE_VALUE "value"
44
45#define GNUNET_REST_JSONAPI_NAMESTORE_PUBLIC "public"
46
47#define GNUNET_REST_JSONAPI_NAMESTORE_SHADOW "shadow"
48
49#define GNUNET_REST_JSONAPI_NAMESTORE_PKEY "pkey"
50
51#define GNUNET_REST_JSONAPI_NAMESTORE_EXPIRATION "expiration"
52
53#define GNUNET_REST_JSONAPI_NAMESTORE_EGO "ego"
54
55/**
56 * @brief struct returned by the initialization function of the plugin
57 */
58struct Plugin
59{
60 const struct GNUNET_CONFIGURATION_Handle *cfg;
61};
62
63const struct GNUNET_CONFIGURATION_Handle *cfg;
64
65struct RecordEntry
66{
67 /**
68 * DLL
69 */
70 struct RecordEntry *next;
71
72 /**
73 * DLL
74 */
75 struct RecordEntry *prev;
76
77};
78
79struct RequestHandle
80{
81 /**
82 * Ego list
83 */
84 struct RecordEntry *record_head;
85
86 /**
87 * Ego list
88 */
89 struct record_entry *record_tail;
90
91 /**
92 * JSON response object
93 */
94 struct JsonApiObject *resp_object;
95
96 /**
97 * Rest connection
98 */
99 struct RestConnectionDataHandle *conndata_handle;
100
101 /**
102 * Handle to GNS service.
103 */
104 struct GNUNET_IDENTITY_Handle *identity_handle;
105
106 /**
107 * Handle to NAMESTORE
108 */
109 struct GNUNET_NAMESTORE_Handle *ns_handle;
110
111 /**
112 * Handle to NAMESTORE it
113 */
114 struct GNUNET_NAMESTORE_ZoneIterator *list_it;
115
116 /**
117 * Private key for the zone
118 */
119 struct GNUNET_CRYPTO_EcdsaPrivateKey zone_pkey;
120
121 /**
122 * Handle to identity lookup
123 */
124 struct GNUNET_IDENTITY_EgoLookup *ego_lookup;
125
126 /**
127 * Default Ego operation
128 */
129 struct GNUNET_IDENTITY_Operation *get_default;
130
131 /**
132 * Name of the ego
133 */
134 char *ego_name;
135
136 /**
137 * Record is public
138 */
139 int is_public;
140
141 /**
142 * Shadow record
143 */
144 int is_shadow;
145
146 /**
147 * Name of the record to modify
148 */
149 char *name;
150
151 /**
152 * Value of the record
153 */
154 char *value;
155
156 /**
157 * record type
158 */
159 uint32_t type;
160
161 /**
162 * Records to store
163 */
164 struct GNUNET_GNSRECORD_Data *rd;
165
166 /**
167 * record count
168 */
169 unsigned int rd_count;
170
171 /**
172 * NAMESTORE Operation
173 */
174 struct GNUNET_NAMESTORE_QueueEntry *add_qe;
175
176 /**
177 * Desired timeout for the lookup (default is no timeout).
178 */
179 struct GNUNET_TIME_Relative timeout;
180
181 /**
182 * ID of a task associated with the resolution process.
183 */
184 struct GNUNET_SCHEDULER_Task * timeout_task;
185
186 /**
187 * The plugin result processor
188 */
189 GNUNET_REST_ResultProcessor proc;
190
191 /**
192 * The closure of the result processor
193 */
194 void *proc_cls;
195
196 /**
197 * The url
198 */
199 char *url;
200
201 /**
202 * The data from the REST request
203 */
204 const char* data;
205
206 /**
207 * the length of the REST data
208 */
209 size_t data_size;
210
211 /**
212 * Cfg
213 */
214 const struct GNUNET_CONFIGURATION_Handle *cfg;
215
216};
217
218
219/**
220 * Cleanup lookup handle
221 * @param handle Handle to clean up
222 */
223void
224cleanup_handle (struct RequestHandle *handle)
225{
226 struct RecordEntry *record_entry;
227 struct RecordEntry *record_tmp;
228 int i;
229 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
230 "Cleaning up\n");
231 if (NULL != handle->name)
232 GNUNET_free (handle->name);
233 if (NULL != handle->timeout_task)
234 GNUNET_SCHEDULER_cancel (handle->timeout_task);
235 if (NULL != handle->ego_lookup)
236 GNUNET_IDENTITY_ego_lookup_cancel (handle->ego_lookup);
237 if (NULL != handle->get_default)
238 GNUNET_IDENTITY_cancel (handle->get_default);
239 if (NULL != handle->list_it)
240 GNUNET_NAMESTORE_zone_iteration_stop (handle->list_it);
241 if (NULL != handle->add_qe)
242 GNUNET_NAMESTORE_cancel (handle->add_qe);
243 if (NULL != handle->identity_handle)
244 GNUNET_IDENTITY_disconnect (handle->identity_handle);
245 if (NULL != handle->ns_handle)
246 GNUNET_NAMESTORE_disconnect (handle->ns_handle);
247 if (NULL != handle->url)
248 GNUNET_free (handle->url);
249 if (NULL != handle->value)
250 GNUNET_free (handle->value);
251 if (NULL != handle->rd)
252 {
253 for (i = 0; i < handle->rd_count; i++)
254 {
255 if (NULL != handle->rd[i].data)
256 GNUNET_free ((void*)handle->rd[i].data);
257 }
258 GNUNET_free (handle->rd);
259 }
260 if (NULL != handle->ego_name)
261 GNUNET_free (handle->ego_name);
262 for (record_entry = handle->record_head;
263 NULL != record_entry;)
264 {
265 record_tmp = record_entry;
266 record_entry = record_entry->next;
267 GNUNET_free (record_tmp);
268 }
269 GNUNET_free (handle);
270}
271
272/**
273 * Create json representation of a GNSRECORD
274 *
275 * @param rd the GNSRECORD_Data
276 */
277json_t *
278gnsrecord_to_json (const struct GNUNET_GNSRECORD_Data *rd)
279{
280 const char *typename;
281 char *string_val;
282 const char *exp_str;
283 json_t *record_obj;
284
285 typename = GNUNET_GNSRECORD_number_to_typename (rd->record_type);
286 string_val = GNUNET_GNSRECORD_value_to_string (rd->record_type,
287 rd->data,
288 rd->data_size);
289
290 if (NULL == string_val)
291 {
292 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
293 "Record of type %d malformed, skipping\n",
294 (int) rd->record_type);
295 return NULL;
296 }
297 record_obj = json_object();
298 json_object_set_new (record_obj,
299 GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE,
300 json_string (typename));
301 json_object_set_new (record_obj,
302 GNUNET_REST_JSONAPI_NAMESTORE_VALUE,
303 json_string (string_val));
304 GNUNET_free (string_val);
305
306 if (GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION & rd->flags)
307 {
308 struct GNUNET_TIME_Relative time_rel;
309 time_rel.rel_value_us = rd->expiration_time;
310 exp_str = GNUNET_STRINGS_relative_time_to_string (time_rel, 1);
311 }
312 else
313 {
314 struct GNUNET_TIME_Absolute time_abs;
315 time_abs.abs_value_us = rd->expiration_time;
316 exp_str = GNUNET_STRINGS_absolute_time_to_string (time_abs);
317 }
318 json_object_set_new (record_obj, GNUNET_REST_JSONAPI_NAMESTORE_EXPIRATION, json_string (exp_str));
319
320 json_object_set_new (record_obj, "expired",
321 json_boolean (GNUNET_YES == GNUNET_GNSRECORD_is_expired (rd)));
322 return record_obj;
323}
324
325
326/**
327 * Task run on shutdown. Cleans up everything.
328 *
329 * @param cls unused
330 * @param tc scheduler context
331 */
332static void
333do_error (void *cls,
334 const struct GNUNET_SCHEDULER_TaskContext *tc)
335{
336 struct RequestHandle *handle = cls;
337 struct MHD_Response *resp = GNUNET_REST_create_json_response (NULL);
338 handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST);
339 cleanup_handle (handle);
340}
341
342static void
343cleanup_handle_delayed (void *cls,
344 const struct GNUNET_SCHEDULER_TaskContext *tc)
345{
346 cleanup_handle (cls);
347}
348
349/**
350 * Create a response with requested records
351 *
352 * @param handle the RequestHandle
353 */
354void
355namestore_list_response (void *cls,
356 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
357 const char *rname,
358 unsigned int rd_len,
359 const struct GNUNET_GNSRECORD_Data *rd)
360{
361 struct RequestHandle *handle = cls;
362 struct JsonApiResource *json_resource;
363 struct MHD_Response *resp;
364 json_t *result_array;
365 json_t *record_obj;
366 int i;
367 char *result;
368
369 if (NULL == handle->resp_object)
370 handle->resp_object = GNUNET_REST_jsonapi_object_new ();
371
372 if (NULL == rname)
373 {
374 //Handle response
375 if (GNUNET_SYSERR == GNUNET_REST_jsonapi_data_serialize (handle->resp_object, &result))
376 {
377 GNUNET_SCHEDULER_add_now (&do_error, handle);
378 return;
379 }
380 GNUNET_REST_jsonapi_object_delete (handle->resp_object);
381 resp = GNUNET_REST_create_json_response (result);
382 handle->list_it = NULL;
383 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
384 GNUNET_free (result);
385 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
386 return;
387 }
388
389 if ( (NULL != handle->name) &&
390 (0 != strcmp (handle->name, rname)) )
391 {
392 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
393 "%s does not match %s\n", rname, handle->name);
394 GNUNET_NAMESTORE_zone_iterator_next (handle->list_it);
395 return;
396 }
397
398 json_resource = GNUNET_REST_jsonapi_resource_new (GNUNET_REST_JSONAPI_NAMESTORE_TYPEINFO,
399 rname);
400 result_array = json_array ();
401 for (i=0; i<rd_len; i++)
402 {
403 if ( (GNUNET_GNSRECORD_TYPE_NICK == rd[i].record_type) &&
404 (0 != strcmp (rname, "+")) )
405 continue;
406
407 if ( (rd[i].record_type != handle->type) &&
408 (GNUNET_GNSRECORD_TYPE_ANY != handle->type) )
409 continue;
410 record_obj = gnsrecord_to_json (&(rd[i]));
411 json_array_append (result_array, record_obj);
412 json_decref (record_obj);
413 }
414 GNUNET_REST_jsonapi_resource_add_attr (json_resource,
415 GNUNET_REST_JSONAPI_NAMESTORE_RECORD,
416 result_array);
417 GNUNET_REST_jsonapi_object_resource_add (handle->resp_object, json_resource);
418 json_decref (result_array);
419 GNUNET_NAMESTORE_zone_iterator_next (handle->list_it);
420}
421
422static void
423create_finished (void *cls, int32_t success, const char *emsg)
424{
425 struct RequestHandle *handle = cls;
426 struct MHD_Response *resp;
427
428 handle->add_qe = NULL;
429 if (GNUNET_YES != success)
430 {
431 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
432 "Error storing records%s%s\n",
433 (NULL == emsg) ? "" : ": ",
434 (NULL == emsg) ? "" : emsg);
435 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
436 return;
437 }
438 resp = GNUNET_REST_create_json_response (NULL);
439 handle->proc (handle->proc_cls, resp, MHD_HTTP_NO_CONTENT);
440 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
441}
442
443
444/**
445 * We're storing a new record; this requires
446 * that no record already exists
447 *
448 * @param cls closure, unused
449 * @param zone_key private key of the zone
450 * @param rec_name name that is being mapped (at most 255 characters long)
451 * @param rd_count number of entries in @a rd array
452 * @param rd array of records with data to store
453 */
454static void
455create_new_record_cont (void *cls,
456 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
457 const char *rec_name,
458 unsigned int rd_count,
459 const struct GNUNET_GNSRECORD_Data *rd)
460{
461 struct RequestHandle *handle = cls;
462
463 handle->add_qe = NULL;
464 if ( (NULL != zone_key) &&
465 (0 != strcmp (rec_name, handle->name)) )
466 {
467 GNUNET_break (0);
468 GNUNET_SCHEDULER_add_now (&do_error, handle);
469 return;
470 }
471
472 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
473 "Received %u records for name `%s'\n",
474 rd_count, rec_name);
475 if (0 != rd_count)
476 {
477 handle->proc (handle->proc_cls,
478 GNUNET_REST_create_json_response (NULL),
479 MHD_HTTP_CONFLICT);
480 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
481 return;
482 }
483
484 GNUNET_assert (NULL != handle->name);
485 handle->add_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle,
486 &handle->zone_pkey,
487 handle->name,
488 handle->rd_count,
489 handle->rd,
490 &create_finished,
491 handle);
492}
493
494static void
495del_finished (void *cls,
496 int32_t success,
497 const char *emsg)
498{
499 struct RequestHandle *handle = cls;
500
501 handle->add_qe = NULL;
502 if (GNUNET_NO == success)
503 {
504 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
505 _("Deleting record failed, record does not exist%s%s\n"),
506 (NULL != emsg) ? ": " : "",
507 (NULL != emsg) ? emsg : "");
508 GNUNET_SCHEDULER_add_now (&do_error, handle); //do_not_found TODO
509 return;
510 }
511 if (GNUNET_SYSERR == success)
512 {
513 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
514 _("Deleting record failed%s%s\n"),
515 (NULL != emsg) ? ": " : "",
516 (NULL != emsg) ? emsg : "");
517 GNUNET_SCHEDULER_add_now (&do_error, handle);
518 return;
519 }
520 handle->proc (handle->proc_cls,
521 GNUNET_REST_create_json_response (NULL),
522 MHD_HTTP_NO_CONTENT);
523 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
524}
525
526static void
527del_cont (void *cls,
528 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
529 const char *label,
530 unsigned int rd_count,
531 const struct GNUNET_GNSRECORD_Data *rd)
532{
533 struct RequestHandle *handle = cls;
534
535 if (0 == rd_count)
536 {
537 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
538 _("There are no records under label `%s' that could be deleted.\n"),
539 label);
540 GNUNET_SCHEDULER_add_now (&do_error, handle);
541 return;
542 }
543
544 handle->add_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle,
545 &handle->zone_pkey,
546 handle->name,
547 0, NULL,
548 &del_finished,
549 handle);
550}
551
552static void
553namestore_delete_cont (struct RestConnectionDataHandle *con,
554 const char *url,
555 void *cls)
556{
557 struct RequestHandle *handle = cls;
558
559 if (NULL == handle->name)
560 {
561 GNUNET_SCHEDULER_add_now (&do_error, handle);
562 return;
563 }
564
565 handle->add_qe = GNUNET_NAMESTORE_records_lookup (handle->ns_handle,
566 &handle->zone_pkey,
567 handle->name,
568 &del_cont,
569 handle);
570}
571
572static int
573json_to_gnsrecord (const json_t *records_json,
574 struct GNUNET_GNSRECORD_Data **rd,
575 unsigned int *rd_count)
576{
577 struct GNUNET_TIME_Relative etime_rel;
578 struct GNUNET_TIME_Absolute etime_abs;
579 char *value;
580 void *rdata;
581 size_t rdata_size;
582 const char *typestring;
583 const char *expirationstring;
584 int i;
585 json_t *type_json;
586 json_t *value_json;
587 json_t *record_json;
588 json_t *exp_json;
589
590 *rd_count = json_array_size (records_json);
591 *rd = GNUNET_malloc (sizeof (struct GNUNET_GNSRECORD_Data) * *rd_count);
592 for (i = 0; i < *rd_count; i++)
593 {
594 memset (&((*rd)[i]), 0, sizeof (struct GNUNET_GNSRECORD_Data));
595 record_json = json_array_get (records_json, i);
596 type_json = json_object_get (record_json,
597 GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE);
598 if (!json_is_string (type_json))
599 {
600 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
601 "Type property is no string\n");
602 return GNUNET_SYSERR;
603 }
604 typestring = json_string_value (type_json);
605 (*rd)[i].record_type = GNUNET_GNSRECORD_typename_to_number (typestring);
606 if (UINT32_MAX == (*rd)[i].record_type)
607 {
608 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Unsupported type `%s'\n"),
609 json_string_value (type_json));
610 return GNUNET_SYSERR;
611 }
612 value_json = json_object_get (record_json,
613 GNUNET_REST_JSONAPI_NAMESTORE_VALUE);
614 if (!json_is_string (value_json))
615 {
616 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
617 "Value property is no string\n");
618 return GNUNET_SYSERR;
619 }
620 GNUNET_asprintf (&value, "%s", json_string_value (value_json));
621 if (GNUNET_OK != GNUNET_GNSRECORD_string_to_value ((*rd)[i].record_type,
622 value,
623 &rdata,
624 &rdata_size))
625 {
626 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Value `%s' invalid for record type `%s'\n"),
627 value, typestring);
628 return GNUNET_SYSERR;
629 }
630 (*rd)[i].data = rdata;
631 (*rd)[i].data_size = rdata_size;
632 /**TODO
633 * if (1 == handle->is_shadow)
634 rde->flags |= GNUNET_GNSRECORD_RF_SHADOW_RECORD;
635 if (1 != handle->is_public)
636 rde->flags |= GNUNET_GNSRECORD_RF_PRIVATE;
637 */
638 exp_json = json_object_get (record_json,
639 GNUNET_REST_JSONAPI_NAMESTORE_EXPIRATION);
640 if (!json_is_string (exp_json))
641 {
642 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
643 "Expiration property is no string\n");
644 return GNUNET_SYSERR;
645 }
646 expirationstring = json_string_value (exp_json);
647 if (0 == strcmp (expirationstring, "never"))
648 {
649 (*rd)[i].expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us;
650 }
651 else if (GNUNET_OK ==
652 GNUNET_STRINGS_fancy_time_to_relative (expirationstring,
653 &etime_rel))
654 {
655 (*rd)[i].expiration_time = etime_rel.rel_value_us;
656 (*rd)[i].flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
657 }
658 else if (GNUNET_OK ==
659 GNUNET_STRINGS_fancy_time_to_absolute (expirationstring,
660 &etime_abs))
661 {
662 (*rd)[i].expiration_time = etime_abs.abs_value_us;
663 }
664 else
665 {
666 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Value `%s' invalid for record type `%s'\n"),
667 value, typestring);
668 return GNUNET_SYSERR;
669 }
670 }
671 return GNUNET_OK;
672}
673
674static void
675namestore_create_cont (struct RestConnectionDataHandle *con,
676 const char *url,
677 void *cls)
678{
679 struct RequestHandle *handle = cls;
680 struct MHD_Response *resp;
681 struct JsonApiObject *json_obj;
682 struct JsonApiResource *json_res;
683 json_t *name_json;
684 json_t *records_json;
685 char term_data[handle->data_size+1];
686
687 if (strlen (GNUNET_REST_API_NS_NAMESTORE) != strlen (handle->url))
688 {
689 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
690 "Cannot create under %s\n", handle->url);
691 GNUNET_SCHEDULER_add_now (&do_error, handle);
692 return;
693 }
694 if (0 >= handle->data_size)
695 {
696 GNUNET_SCHEDULER_add_now (&do_error, handle);
697 return;
698 }
699 term_data[handle->data_size] = '\0';
700 memcpy (term_data, handle->data, handle->data_size);
701 json_obj = GNUNET_REST_jsonapi_object_parse (term_data);
702 if (NULL == json_obj)
703 {
704 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
705 "Unable to parse JSONAPI Object from %s\n",
706 term_data);
707 GNUNET_SCHEDULER_add_now (&do_error, handle);
708 return;
709 }
710 if (1 != GNUNET_REST_jsonapi_object_resource_count (json_obj))
711 {
712 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
713 "Cannot create more than 1 resource! (Got %d)\n",
714 GNUNET_REST_jsonapi_object_resource_count (json_obj));
715 GNUNET_REST_jsonapi_object_delete (json_obj);
716 GNUNET_SCHEDULER_add_now (&do_error, handle);
717 return;
718 }
719 json_res = GNUNET_REST_jsonapi_object_get_resource (json_obj, 0);
720 if (GNUNET_NO == GNUNET_REST_jsonapi_resource_check_type (json_res,
721 GNUNET_REST_JSONAPI_NAMESTORE_RECORD))
722 {
723 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
724 "Unsupported JSON data type\n");
725 GNUNET_REST_jsonapi_object_delete (json_obj);
726 resp = GNUNET_REST_create_json_response (NULL);
727 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
728 cleanup_handle (handle);
729 return;
730 }
731 name_json = GNUNET_REST_jsonapi_resource_read_attr (json_res, GNUNET_REST_JSONAPI_KEY_ID);
732 if (!json_is_string (name_json))
733 {
734 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
735 "Name property is no string\n");
736 GNUNET_REST_jsonapi_object_delete (json_obj);
737 GNUNET_SCHEDULER_add_now (&do_error, handle);
738 return;
739 }
740 GNUNET_asprintf (&handle->name, "%s", json_string_value (name_json));
741 records_json = GNUNET_REST_jsonapi_resource_read_attr (json_res,
742 GNUNET_REST_JSONAPI_NAMESTORE_RECORD);
743 if (NULL == records_json)
744 {
745 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
746 "No records given\n");
747 GNUNET_REST_jsonapi_object_delete (json_obj);
748 GNUNET_SCHEDULER_add_now (&do_error, handle);
749 return;
750 }
751 if (GNUNET_SYSERR == json_to_gnsrecord (records_json, &handle->rd, &handle->rd_count))
752 {
753 GNUNET_REST_jsonapi_object_delete (json_obj);
754 json_decref (records_json);
755 GNUNET_SCHEDULER_add_now (&do_error, handle);
756 return;
757 }
758 GNUNET_REST_jsonapi_object_delete (json_obj);
759
760 handle->add_qe = GNUNET_NAMESTORE_records_lookup (handle->ns_handle,
761 &handle->zone_pkey,
762 handle->name,
763 &create_new_record_cont, handle );
764}
765
766
767
768
769
770static void
771namestore_info_cont (struct RestConnectionDataHandle *con,
772 const char *url,
773 void *cls)
774{
775 struct RequestHandle *handle = cls;
776 handle->list_it = GNUNET_NAMESTORE_zone_iteration_start (handle->ns_handle,
777 &handle->zone_pkey,
778 &namestore_list_response,
779 handle);
780}
781
782static char*
783get_name_from_url (const char* url)
784{
785 if (strlen (url) <= strlen (GNUNET_REST_API_NS_NAMESTORE))
786 return NULL;
787 return (char*)url + strlen (GNUNET_REST_API_NS_NAMESTORE) + 1;
788}
789
790/**
791 * Function called with the result from the check if the namestore
792 * service is actually running. If it is, we start the actual
793 * operation.
794 *
795 * @param cls closure with our configuration
796 * @param result #GNUNET_YES if the namestore service is running
797 */
798static void
799testservice_task (void *cls,
800 int result)
801{
802 struct RequestHandle *handle = cls;
803 static const struct GNUNET_REST_RestConnectionHandler handlers[] = {
804 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_NAMESTORE, &namestore_info_cont}, //list
805 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_NAMESTORE, &namestore_create_cont}, //create
806 // {MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_NAMESTORE, &namestore_edit_cont}, //update. TODO this shoul be PATCH
807 {MHD_HTTP_METHOD_DELETE, GNUNET_REST_API_NS_NAMESTORE, &namestore_delete_cont}, //delete
808 GNUNET_REST_HANDLER_END
809 };
810
811 if (GNUNET_YES != result)
812 {
813 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Service `%s' is not running\n"),
814 "namestore");
815 GNUNET_SCHEDULER_add_now (&do_error, handle);
816 return;
817 }
818 handle->ns_handle = GNUNET_NAMESTORE_connect (cfg);
819 if (NULL == handle->ns_handle)
820 {
821 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
822 _("Failed to connect to namestore\n"));
823 GNUNET_SCHEDULER_add_now (&do_error, handle);
824 return;
825 }
826
827 if (GNUNET_NO == GNUNET_REST_handle_request (handle->conndata_handle, handlers, handle))
828 GNUNET_SCHEDULER_add_now (&do_error, (void*) handle);
829
830}
831
832/**
833 * Callback invoked from identity service with ego information.
834 * An @a ego of NULL means the ego was not found.
835 *
836 * @param cls closure with the configuration
837 * @param ego an ego known to identity service, or NULL
838 */
839static void
840identity_cb (void *cls,
841 const struct GNUNET_IDENTITY_Ego *ego)
842{
843 struct RequestHandle *handle = cls;
844 struct MHD_Response *resp;
845
846 handle->ego_lookup = NULL;
847 if (NULL == ego)
848 {
849 if (NULL != handle->ego_name)
850 {
851 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
852 _("Ego `%s' not known to identity service\n"),
853 handle->ego_name);
854 }
855 resp = GNUNET_REST_create_json_response (NULL);
856 handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
857 cleanup_handle (handle);
858 return;
859 }
860 handle->zone_pkey = *GNUNET_IDENTITY_ego_get_private_key (ego);
861 GNUNET_CLIENT_service_test ("namestore", handle->cfg,
862 GNUNET_TIME_UNIT_SECONDS,
863 &testservice_task,
864 (void *) handle);
865}
866
867static void
868default_ego_cb (void *cls,
869 struct GNUNET_IDENTITY_Ego *ego,
870 void **ctx,
871 const char *name)
872{
873 struct RequestHandle *handle = cls;
874 struct MHD_Response *resp;
875 handle->get_default = NULL;
876 if (NULL == ego)
877 {
878 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
879 _("No default ego configured in identity service\n"));
880 resp = GNUNET_REST_create_json_response (NULL);
881 handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
882 cleanup_handle (handle);
883 return;
884 }
885 else
886 {
887 identity_cb (cls, ego);
888 }
889}
890
891static void
892id_connect_cb (void *cls,
893 struct GNUNET_IDENTITY_Ego *ego,
894 void **ctx,
895 const char *name)
896{
897 struct RequestHandle *handle = cls;
898 if (NULL == ego)
899 {
900 handle->get_default = GNUNET_IDENTITY_get (handle->identity_handle,
901 "namestore",
902 &default_ego_cb, handle);
903 }
904}
905
906static void
907testservice_id_task (void *cls, int result)
908{
909 struct RequestHandle *handle = cls;
910 struct MHD_Response *resp;
911 struct GNUNET_HashCode key;
912 char *ego;
913 char *name;
914
915 if (result != GNUNET_YES)
916 {
917 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
918 _("Identity service is not running\n"));
919 resp = GNUNET_REST_create_json_response (NULL);
920 handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
921 cleanup_handle (handle);
922 return;
923 }
924 ego = NULL;
925 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_NAMESTORE_EGO,
926 strlen (GNUNET_REST_JSONAPI_NAMESTORE_EGO),
927 &key);
928 if ( GNUNET_YES ==
929 GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
930 &key) )
931 {
932 ego = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
933 &key);
934 }
935 name = get_name_from_url (handle->url);
936 if (NULL != ego)
937 GNUNET_asprintf (&handle->ego_name, "%s", ego);
938 if (NULL != name)
939 GNUNET_asprintf (&handle->name, "%s", name);
940 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n", handle->ego_name);
941 if (NULL == handle->ego_name)
942 {
943 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n", handle->ego_name);
944 handle->identity_handle = GNUNET_IDENTITY_connect (handle->cfg, &id_connect_cb, handle);
945 if (NULL == handle->identity_handle)
946 {
947 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Cannot connect to identity service\n"));
948 resp = GNUNET_REST_create_json_response (NULL);
949 handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
950 cleanup_handle (handle);
951 }
952 return;
953 }
954 handle->ego_lookup = GNUNET_IDENTITY_ego_lookup (cfg,
955 handle->ego_name,
956 &identity_cb,
957 handle);
958}
959
960/**
961 * Function processing the REST call
962 *
963 * @param method HTTP method
964 * @param url URL of the HTTP request
965 * @param data body of the HTTP request (optional)
966 * @param data_size length of the body
967 * @param proc callback function for the result
968 * @param proc_cls closure for callback function
969 * @return GNUNET_OK if request accepted
970 */
971void
972rest_identity_process_request(struct RestConnectionDataHandle *conndata_handle,
973 GNUNET_REST_ResultProcessor proc,
974 void *proc_cls)
975{
976 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
977
978 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
979 handle->proc_cls = proc_cls;
980 handle->proc = proc;
981 handle->conndata_handle = conndata_handle;
982 handle->data = conndata_handle->data;
983 handle->data_size = conndata_handle->data_size;
984 GNUNET_asprintf (&handle->url, "%s", conndata_handle->url);
985 if (handle->url[strlen (handle->url)-1] == '/')
986 handle->url[strlen (handle->url)-1] = '\0';
987 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
988 "Connecting...\n");
989 handle->cfg = cfg;
990 GNUNET_CLIENT_service_test ("identity",
991 cfg,
992 GNUNET_TIME_UNIT_SECONDS,
993 &testservice_id_task,
994 handle);
995 handle->timeout_task = GNUNET_SCHEDULER_add_delayed (handle->timeout,
996 &do_error,
997 handle);
998
999
1000}
1001
1002/**
1003 * Entry point for the plugin.
1004 *
1005 * @param cls Config info
1006 * @return NULL on error, otherwise the plugin context
1007 */
1008void *
1009libgnunet_plugin_rest_namestore_init (void *cls)
1010{
1011 static struct Plugin plugin;
1012 cfg = cls;
1013 struct GNUNET_REST_Plugin *api;
1014
1015 if (NULL != plugin.cfg)
1016 return NULL; /* can only initialize once! */
1017 memset (&plugin, 0, sizeof (struct Plugin));
1018 plugin.cfg = cfg;
1019 api = GNUNET_new (struct GNUNET_REST_Plugin);
1020 api->cls = &plugin;
1021 api->name = GNUNET_REST_API_NS_NAMESTORE;
1022 api->process_request = &rest_identity_process_request;
1023 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1024 _("Namestore REST API initialized\n"));
1025 return api;
1026}
1027
1028
1029/**
1030 * Exit point from the plugin.
1031 *
1032 * @param cls the plugin context (as returned by "init")
1033 * @return always NULL
1034 */
1035void *
1036libgnunet_plugin_rest_namestore_done (void *cls)
1037{
1038 struct GNUNET_REST_Plugin *api = cls;
1039 struct Plugin *plugin = api->cls;
1040
1041 plugin->cfg = NULL;
1042 GNUNET_free (api);
1043 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1044 "Namestore REST plugin is finished\n");
1045 return NULL;
1046}
1047
1048/* end of plugin_rest_namestore.c */
diff --git a/src/rest/rest.c b/src/rest/rest.c
index d14df54c5..ac64ea065 100644
--- a/src/rest/rest.c
+++ b/src/rest/rest.c
@@ -170,10 +170,8 @@ check_resource_attr_str (const struct JsonApiResource *resource,
170 if (!json_is_string (value) || 170 if (!json_is_string (value) ||
171 (0 != strcmp (attr, json_string_value(value)))) 171 (0 != strcmp (attr, json_string_value(value))))
172 { 172 {
173 json_decref (value);
174 return GNUNET_NO; 173 return GNUNET_NO;
175 } 174 }
176 json_decref (value);
177 return GNUNET_YES; 175 return GNUNET_YES;
178} 176}
179 177