aboutsummaryrefslogtreecommitdiff
path: root/src/namestore/plugin_rest_namestore.c
diff options
context:
space:
mode:
authorMartin Schanzenbach <mschanzenbach@posteo.de>2015-09-11 15:56:39 +0000
committerMartin Schanzenbach <mschanzenbach@posteo.de>2015-09-11 15:56:39 +0000
commitc8aace43c41d50e03bd28b6e696b33c1da8b6c4c (patch)
tree375181e89bd4f099e0a2039ed0962bf7cfd48131 /src/namestore/plugin_rest_namestore.c
parenta12f20bd4c621a7b5e88ca52830ad1bb74a8e2d8 (diff)
downloadgnunet-c8aace43c41d50e03bd28b6e696b33c1da8b6c4c.tar.gz
gnunet-c8aace43c41d50e03bd28b6e696b33c1da8b6c4c.zip
- move rest plugins into rest directory where they belong
Diffstat (limited to 'src/namestore/plugin_rest_namestore.c')
-rw-r--r--src/namestore/plugin_rest_namestore.c1063
1 files changed, 0 insertions, 1063 deletions
diff --git a/src/namestore/plugin_rest_namestore.c b/src/namestore/plugin_rest_namestore.c
deleted file mode 100644
index 9b6b5c57c..000000000
--- a/src/namestore/plugin_rest_namestore.c
+++ /dev/null
@@ -1,1063 +0,0 @@
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., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, 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 */
223static void
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 */
277static json_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 */
354static void
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->list_it = NULL;
375 //Handle response
376 if (GNUNET_SYSERR == GNUNET_REST_jsonapi_data_serialize (handle->resp_object, &result))
377 {
378 GNUNET_SCHEDULER_add_now (&do_error, handle);
379 return;
380 }
381 GNUNET_REST_jsonapi_object_delete (handle->resp_object);
382 resp = GNUNET_REST_create_json_response (result);
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 result_array = json_array ();
399 for (i=0; i<rd_len; i++)
400 {
401 if ( (GNUNET_GNSRECORD_TYPE_NICK == rd[i].record_type) &&
402 (0 != strcmp (rname, "+")) )
403 continue;
404
405 if ( (rd[i].record_type != handle->type) &&
406 (GNUNET_GNSRECORD_TYPE_ANY != handle->type) )
407 continue;
408 record_obj = gnsrecord_to_json (&(rd[i]));
409 json_array_append (result_array, record_obj);
410 json_decref (record_obj);
411 }
412
413 json_resource = GNUNET_REST_jsonapi_resource_new (GNUNET_REST_JSONAPI_NAMESTORE_TYPEINFO,
414 rname);
415 GNUNET_REST_jsonapi_resource_add_attr (json_resource,
416 GNUNET_REST_JSONAPI_NAMESTORE_RECORD,
417 result_array);
418 GNUNET_REST_jsonapi_object_resource_add (handle->resp_object, json_resource);
419
420 json_decref (result_array);
421 GNUNET_NAMESTORE_zone_iterator_next (handle->list_it);
422}
423
424static void
425create_finished (void *cls, int32_t success, const char *emsg)
426{
427 struct RequestHandle *handle = cls;
428 struct MHD_Response *resp;
429
430 handle->add_qe = NULL;
431 if (GNUNET_YES != success)
432 {
433 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
434 "Error storing records%s%s\n",
435 (NULL == emsg) ? "" : ": ",
436 (NULL == emsg) ? "" : emsg);
437 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
438 return;
439 }
440 resp = GNUNET_REST_create_json_response (NULL);
441 handle->proc (handle->proc_cls, resp, MHD_HTTP_NO_CONTENT);
442 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
443}
444
445
446/**
447 * We're storing a new record; this requires
448 * that no record already exists
449 *
450 * @param cls closure, unused
451 * @param zone_key private key of the zone
452 * @param rec_name name that is being mapped (at most 255 characters long)
453 * @param rd_count number of entries in @a rd array
454 * @param rd array of records with data to store
455 */
456static void
457create_new_record_cont (void *cls,
458 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
459 const char *rec_name,
460 unsigned int rd_count,
461 const struct GNUNET_GNSRECORD_Data *rd)
462{
463 struct RequestHandle *handle = cls;
464
465 handle->add_qe = NULL;
466 if ( (NULL != zone_key) &&
467 (0 != strcmp (rec_name, handle->name)) )
468 {
469 GNUNET_break (0);
470 GNUNET_SCHEDULER_add_now (&do_error, handle);
471 return;
472 }
473
474 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
475 "Received %u records for name `%s'\n",
476 rd_count, rec_name);
477 if (0 != rd_count)
478 {
479 handle->proc (handle->proc_cls,
480 GNUNET_REST_create_json_response (NULL),
481 MHD_HTTP_CONFLICT);
482 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
483 return;
484 }
485
486 GNUNET_assert (NULL != handle->name);
487 handle->add_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle,
488 &handle->zone_pkey,
489 handle->name,
490 handle->rd_count,
491 handle->rd,
492 &create_finished,
493 handle);
494}
495
496static void
497del_finished (void *cls,
498 int32_t success,
499 const char *emsg)
500{
501 struct RequestHandle *handle = cls;
502
503 handle->add_qe = NULL;
504 if (GNUNET_NO == success)
505 {
506 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
507 _("Deleting record failed, record does not exist%s%s\n"),
508 (NULL != emsg) ? ": " : "",
509 (NULL != emsg) ? emsg : "");
510 GNUNET_SCHEDULER_add_now (&do_error, handle); //do_not_found TODO
511 return;
512 }
513 if (GNUNET_SYSERR == success)
514 {
515 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
516 _("Deleting record failed%s%s\n"),
517 (NULL != emsg) ? ": " : "",
518 (NULL != emsg) ? emsg : "");
519 GNUNET_SCHEDULER_add_now (&do_error, handle);
520 return;
521 }
522 handle->proc (handle->proc_cls,
523 GNUNET_REST_create_json_response (NULL),
524 MHD_HTTP_NO_CONTENT);
525 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
526}
527
528static void
529del_cont (void *cls,
530 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
531 const char *label,
532 unsigned int rd_count,
533 const struct GNUNET_GNSRECORD_Data *rd)
534{
535 struct RequestHandle *handle = cls;
536
537 if (0 == rd_count)
538 {
539 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
540 _("There are no records under label `%s' that could be deleted.\n"),
541 label);
542 GNUNET_SCHEDULER_add_now (&do_error, handle);
543 return;
544 }
545
546 handle->add_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle,
547 &handle->zone_pkey,
548 handle->name,
549 0, NULL,
550 &del_finished,
551 handle);
552}
553
554static void
555namestore_delete_cont (struct RestConnectionDataHandle *con,
556 const char *url,
557 void *cls)
558{
559 struct RequestHandle *handle = cls;
560
561 if (NULL == handle->name)
562 {
563 GNUNET_SCHEDULER_add_now (&do_error, handle);
564 return;
565 }
566
567 handle->add_qe = GNUNET_NAMESTORE_records_lookup (handle->ns_handle,
568 &handle->zone_pkey,
569 handle->name,
570 &del_cont,
571 handle);
572}
573
574static int
575json_to_gnsrecord (const json_t *records_json,
576 struct GNUNET_GNSRECORD_Data **rd,
577 unsigned int *rd_count)
578{
579 struct GNUNET_TIME_Relative etime_rel;
580 struct GNUNET_TIME_Absolute etime_abs;
581 char *value;
582 void *rdata;
583 size_t rdata_size;
584 const char *typestring;
585 const char *expirationstring;
586 int i;
587 json_t *type_json;
588 json_t *value_json;
589 json_t *record_json;
590 json_t *exp_json;
591
592 *rd_count = json_array_size (records_json);
593 *rd = GNUNET_malloc (sizeof (struct GNUNET_GNSRECORD_Data) * *rd_count);
594 for (i = 0; i < *rd_count; i++)
595 {
596 memset (&((*rd)[i]), 0, sizeof (struct GNUNET_GNSRECORD_Data));
597 record_json = json_array_get (records_json, i);
598 type_json = json_object_get (record_json,
599 GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE);
600 if (!json_is_string (type_json))
601 {
602 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
603 "Type property is no string\n");
604 return GNUNET_SYSERR;
605 }
606 typestring = json_string_value (type_json);
607 (*rd)[i].record_type = GNUNET_GNSRECORD_typename_to_number (typestring);
608 if (UINT32_MAX == (*rd)[i].record_type)
609 {
610 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Unsupported type `%s'\n"),
611 json_string_value (type_json));
612 return GNUNET_SYSERR;
613 }
614 value_json = json_object_get (record_json,
615 GNUNET_REST_JSONAPI_NAMESTORE_VALUE);
616 if (!json_is_string (value_json))
617 {
618 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
619 "Value property is no string\n");
620 return GNUNET_SYSERR;
621 }
622 GNUNET_asprintf (&value, "%s", json_string_value (value_json));
623 if (GNUNET_OK != GNUNET_GNSRECORD_string_to_value ((*rd)[i].record_type,
624 value,
625 &rdata,
626 &rdata_size))
627 {
628 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Value `%s' invalid for record type `%s'\n"),
629 value, typestring);
630 return GNUNET_SYSERR;
631 }
632 (*rd)[i].data = rdata;
633 (*rd)[i].data_size = rdata_size;
634 /**TODO
635 * if (1 == handle->is_shadow)
636 rde->flags |= GNUNET_GNSRECORD_RF_SHADOW_RECORD;
637 if (1 != handle->is_public)
638 rde->flags |= GNUNET_GNSRECORD_RF_PRIVATE;
639 */
640 exp_json = json_object_get (record_json,
641 GNUNET_REST_JSONAPI_NAMESTORE_EXPIRATION);
642 if (!json_is_string (exp_json))
643 {
644 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
645 "Expiration property is no string\n");
646 return GNUNET_SYSERR;
647 }
648 expirationstring = json_string_value (exp_json);
649 if (0 == strcmp (expirationstring, "never"))
650 {
651 (*rd)[i].expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us;
652 }
653 else if (GNUNET_OK ==
654 GNUNET_STRINGS_fancy_time_to_relative (expirationstring,
655 &etime_rel))
656 {
657 (*rd)[i].expiration_time = etime_rel.rel_value_us;
658 (*rd)[i].flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
659 }
660 else if (GNUNET_OK ==
661 GNUNET_STRINGS_fancy_time_to_absolute (expirationstring,
662 &etime_abs))
663 {
664 (*rd)[i].expiration_time = etime_abs.abs_value_us;
665 }
666 else
667 {
668 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Value `%s' invalid for record type `%s'\n"),
669 value, typestring);
670 return GNUNET_SYSERR;
671 }
672 }
673 return GNUNET_OK;
674}
675
676static void
677namestore_create_cont (struct RestConnectionDataHandle *con,
678 const char *url,
679 void *cls)
680{
681 struct RequestHandle *handle = cls;
682 struct MHD_Response *resp;
683 struct JsonApiObject *json_obj;
684 struct JsonApiResource *json_res;
685 json_t *name_json;
686 json_t *records_json;
687 char term_data[handle->data_size+1];
688
689 if (strlen (GNUNET_REST_API_NS_NAMESTORE) != strlen (handle->url))
690 {
691 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
692 "Cannot create under %s\n", handle->url);
693 GNUNET_SCHEDULER_add_now (&do_error, handle);
694 return;
695 }
696 if (0 >= handle->data_size)
697 {
698 GNUNET_SCHEDULER_add_now (&do_error, handle);
699 return;
700 }
701 term_data[handle->data_size] = '\0';
702 memcpy (term_data, handle->data, handle->data_size);
703 json_obj = GNUNET_REST_jsonapi_object_parse (term_data);
704 if (NULL == json_obj)
705 {
706 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
707 "Unable to parse JSONAPI Object from %s\n",
708 term_data);
709 GNUNET_SCHEDULER_add_now (&do_error, handle);
710 return;
711 }
712 if (1 != GNUNET_REST_jsonapi_object_resource_count (json_obj))
713 {
714 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
715 "Cannot create more than 1 resource! (Got %d)\n",
716 GNUNET_REST_jsonapi_object_resource_count (json_obj));
717 GNUNET_REST_jsonapi_object_delete (json_obj);
718 GNUNET_SCHEDULER_add_now (&do_error, handle);
719 return;
720 }
721 json_res = GNUNET_REST_jsonapi_object_get_resource (json_obj, 0);
722 if (GNUNET_NO == GNUNET_REST_jsonapi_resource_check_type (json_res,
723 GNUNET_REST_JSONAPI_NAMESTORE_RECORD))
724 {
725 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
726 "Unsupported JSON data type\n");
727 GNUNET_REST_jsonapi_object_delete (json_obj);
728 resp = GNUNET_REST_create_json_response (NULL);
729 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
730 cleanup_handle (handle);
731 return;
732 }
733 name_json = GNUNET_REST_jsonapi_resource_read_attr (json_res, GNUNET_REST_JSONAPI_KEY_ID);
734 if (!json_is_string (name_json))
735 {
736 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
737 "Name property is no string\n");
738 GNUNET_REST_jsonapi_object_delete (json_obj);
739 GNUNET_SCHEDULER_add_now (&do_error, handle);
740 return;
741 }
742 GNUNET_asprintf (&handle->name, "%s", json_string_value (name_json));
743 records_json = GNUNET_REST_jsonapi_resource_read_attr (json_res,
744 GNUNET_REST_JSONAPI_NAMESTORE_RECORD);
745 if (NULL == records_json)
746 {
747 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
748 "No records given\n");
749 GNUNET_REST_jsonapi_object_delete (json_obj);
750 GNUNET_SCHEDULER_add_now (&do_error, handle);
751 return;
752 }
753 if (GNUNET_SYSERR == json_to_gnsrecord (records_json, &handle->rd, &handle->rd_count))
754 {
755 GNUNET_REST_jsonapi_object_delete (json_obj);
756 GNUNET_SCHEDULER_add_now (&do_error, handle);
757 return;
758 }
759 GNUNET_REST_jsonapi_object_delete (json_obj);
760
761 handle->add_qe = GNUNET_NAMESTORE_records_lookup (handle->ns_handle,
762 &handle->zone_pkey,
763 handle->name,
764 &create_new_record_cont, handle );
765}
766
767
768
769
770
771static void
772namestore_info_cont (struct RestConnectionDataHandle *con,
773 const char *url,
774 void *cls)
775{
776 struct RequestHandle *handle = cls;
777 handle->list_it = GNUNET_NAMESTORE_zone_iteration_start (handle->ns_handle,
778 &handle->zone_pkey,
779 &namestore_list_response,
780 handle);
781}
782
783static char*
784get_name_from_url (const char* url)
785{
786 if (strlen (url) <= strlen (GNUNET_REST_API_NS_NAMESTORE))
787 return NULL;
788 return (char*)url + strlen (GNUNET_REST_API_NS_NAMESTORE) + 1;
789}
790
791/**
792 * Function called with the result from the check if the namestore
793 * service is actually running. If it is, we start the actual
794 * operation.
795 *
796 * @param cls closure with our configuration
797 * @param result #GNUNET_YES if the namestore service is running
798 */
799static void
800testservice_task (void *cls,
801 int result)
802{
803 struct RequestHandle *handle = cls;
804 static const struct GNUNET_REST_RestConnectionHandler handlers[] = {
805 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_NAMESTORE, &namestore_info_cont}, //list
806 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_NAMESTORE, &namestore_create_cont}, //create
807 // {MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_NAMESTORE, &namestore_edit_cont}, //update. TODO this shoul be PATCH
808 {MHD_HTTP_METHOD_DELETE, GNUNET_REST_API_NS_NAMESTORE, &namestore_delete_cont}, //delete
809 GNUNET_REST_HANDLER_END
810 };
811
812 if (GNUNET_YES != result)
813 {
814 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Service `%s' is not running\n"),
815 "namestore");
816 GNUNET_SCHEDULER_add_now (&do_error, handle);
817 return;
818 }
819 handle->ns_handle = GNUNET_NAMESTORE_connect (cfg);
820 if (NULL == handle->ns_handle)
821 {
822 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
823 _("Failed to connect to namestore\n"));
824 GNUNET_SCHEDULER_add_now (&do_error, handle);
825 return;
826 }
827
828 if (GNUNET_NO == GNUNET_REST_handle_request (handle->conndata_handle, handlers, handle))
829 GNUNET_SCHEDULER_add_now (&do_error, (void*) handle);
830
831}
832
833/**
834 * Callback invoked from identity service with ego information.
835 * An @a ego of NULL means the ego was not found.
836 *
837 * @param cls closure with the configuration
838 * @param ego an ego known to identity service, or NULL
839 */
840static void
841identity_cb (void *cls,
842 const struct GNUNET_IDENTITY_Ego *ego)
843{
844 struct RequestHandle *handle = cls;
845 struct MHD_Response *resp;
846
847 handle->ego_lookup = NULL;
848 if (NULL == ego)
849 {
850 if (NULL != handle->ego_name)
851 {
852 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
853 _("Ego `%s' not known to identity service\n"),
854 handle->ego_name);
855 }
856 resp = GNUNET_REST_create_json_response (NULL);
857 handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
858 cleanup_handle (handle);
859 return;
860 }
861 handle->zone_pkey = *GNUNET_IDENTITY_ego_get_private_key (ego);
862 GNUNET_CLIENT_service_test ("namestore", handle->cfg,
863 GNUNET_TIME_UNIT_SECONDS,
864 &testservice_task,
865 (void *) handle);
866}
867
868static void
869default_ego_cb (void *cls,
870 struct GNUNET_IDENTITY_Ego *ego,
871 void **ctx,
872 const char *name)
873{
874 struct RequestHandle *handle = cls;
875 struct MHD_Response *resp;
876 handle->get_default = NULL;
877 if (NULL == ego)
878 {
879 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
880 _("No default ego configured in identity service\n"));
881 resp = GNUNET_REST_create_json_response (NULL);
882 handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
883 cleanup_handle (handle);
884 return;
885 }
886 else
887 {
888 identity_cb (cls, ego);
889 }
890}
891
892static void
893id_connect_cb (void *cls,
894 struct GNUNET_IDENTITY_Ego *ego,
895 void **ctx,
896 const char *name)
897{
898 struct RequestHandle *handle = cls;
899 if (NULL == ego)
900 {
901 handle->get_default = GNUNET_IDENTITY_get (handle->identity_handle,
902 "namestore",
903 &default_ego_cb, handle);
904 }
905}
906
907static void
908testservice_id_task (void *cls, int result)
909{
910 struct RequestHandle *handle = cls;
911 struct MHD_Response *resp;
912 struct GNUNET_HashCode key;
913 char *ego;
914 char *name;
915 char *type;
916
917 if (result != GNUNET_YES)
918 {
919 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
920 _("Identity service is not running\n"));
921 resp = GNUNET_REST_create_json_response (NULL);
922 handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
923 cleanup_handle (handle);
924 return;
925 }
926 ego = NULL;
927 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_NAMESTORE_EGO,
928 strlen (GNUNET_REST_JSONAPI_NAMESTORE_EGO),
929 &key);
930 if ( GNUNET_YES ==
931 GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
932 &key) )
933 {
934 ego = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
935 &key);
936 }
937
938 type = GNUNET_GNSRECORD_TYPE_ANY;
939 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE,
940 strlen (GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE),
941 &key);
942 if ( GNUNET_YES ==
943 GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
944 &key) )
945 {
946 type = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
947 &key);
948 }
949 handle->type = GNUNET_GNSRECORD_typename_to_number (type);
950 name = get_name_from_url (handle->url);
951 if (NULL != ego)
952 GNUNET_asprintf (&handle->ego_name, "%s", ego);
953 if (NULL != name)
954 GNUNET_asprintf (&handle->name, "%s", name);
955 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n", handle->ego_name);
956 if (NULL == handle->ego_name)
957 {
958 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n", handle->ego_name);
959 handle->identity_handle = GNUNET_IDENTITY_connect (handle->cfg, &id_connect_cb, handle);
960 if (NULL == handle->identity_handle)
961 {
962 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Cannot connect to identity service\n"));
963 resp = GNUNET_REST_create_json_response (NULL);
964 handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
965 cleanup_handle (handle);
966 }
967 return;
968 }
969 handle->ego_lookup = GNUNET_IDENTITY_ego_lookup (cfg,
970 handle->ego_name,
971 &identity_cb,
972 handle);
973}
974
975/**
976 * Function processing the REST call
977 *
978 * @param method HTTP method
979 * @param url URL of the HTTP request
980 * @param data body of the HTTP request (optional)
981 * @param data_size length of the body
982 * @param proc callback function for the result
983 * @param proc_cls closure for callback function
984 * @return GNUNET_OK if request accepted
985 */
986static void
987rest_identity_process_request(struct RestConnectionDataHandle *conndata_handle,
988 GNUNET_REST_ResultProcessor proc,
989 void *proc_cls)
990{
991 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
992
993 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
994 handle->proc_cls = proc_cls;
995 handle->proc = proc;
996 handle->conndata_handle = conndata_handle;
997 handle->data = conndata_handle->data;
998 handle->data_size = conndata_handle->data_size;
999 GNUNET_asprintf (&handle->url, "%s", conndata_handle->url);
1000 if (handle->url[strlen (handle->url)-1] == '/')
1001 handle->url[strlen (handle->url)-1] = '\0';
1002 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1003 "Connecting...\n");
1004 handle->cfg = cfg;
1005 GNUNET_CLIENT_service_test ("identity",
1006 cfg,
1007 GNUNET_TIME_UNIT_SECONDS,
1008 &testservice_id_task,
1009 handle);
1010 handle->timeout_task = GNUNET_SCHEDULER_add_delayed (handle->timeout,
1011 &do_error,
1012 handle);
1013
1014
1015}
1016
1017/**
1018 * Entry point for the plugin.
1019 *
1020 * @param cls Config info
1021 * @return NULL on error, otherwise the plugin context
1022 */
1023void *
1024libgnunet_plugin_rest_namestore_init (void *cls)
1025{
1026 static struct Plugin plugin;
1027 cfg = cls;
1028 struct GNUNET_REST_Plugin *api;
1029
1030 if (NULL != plugin.cfg)
1031 return NULL; /* can only initialize once! */
1032 memset (&plugin, 0, sizeof (struct Plugin));
1033 plugin.cfg = cfg;
1034 api = GNUNET_new (struct GNUNET_REST_Plugin);
1035 api->cls = &plugin;
1036 api->name = GNUNET_REST_API_NS_NAMESTORE;
1037 api->process_request = &rest_identity_process_request;
1038 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1039 _("Namestore REST API initialized\n"));
1040 return api;
1041}
1042
1043
1044/**
1045 * Exit point from the plugin.
1046 *
1047 * @param cls the plugin context (as returned by "init")
1048 * @return always NULL
1049 */
1050void *
1051libgnunet_plugin_rest_namestore_done (void *cls)
1052{
1053 struct GNUNET_REST_Plugin *api = cls;
1054 struct Plugin *plugin = api->cls;
1055
1056 plugin->cfg = NULL;
1057 GNUNET_free (api);
1058 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1059 "Namestore REST plugin is finished\n");
1060 return NULL;
1061}
1062
1063/* end of plugin_rest_namestore.c */