aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPhil <phil.buschmann@tum.de>2018-07-03 10:47:40 +0200
committerPhil <phil.buschmann@tum.de>2018-07-03 10:47:40 +0200
commit6efdf409484a0b694bb3d6bcf95b1891f70886fb (patch)
treec7f19c59dc64109c0460d168123ec50806b81aad /src
parent6ede545d597509fefcc3d4fd2ef865bc5f57603f (diff)
downloadgnunet-6efdf409484a0b694bb3d6bcf95b1891f70886fb.tar.gz
gnunet-6efdf409484a0b694bb3d6bcf95b1891f70886fb.zip
-wip namestore
Diffstat (limited to 'src')
-rw-r--r--src/include/gnunet_json_lib.h64
-rw-r--r--src/json/Makefile.am3
-rw-r--r--src/json/json_parser.c169
-rw-r--r--src/namestore/plugin_rest_namestore.c1163
-rw-r--r--src/namestore/plugin_rest_namestore2.c1229
5 files changed, 1882 insertions, 746 deletions
diff --git a/src/include/gnunet_json_lib.h b/src/include/gnunet_json_lib.h
index 06749590c..6340d1f41 100644
--- a/src/include/gnunet_json_lib.h
+++ b/src/include/gnunet_json_lib.h
@@ -479,6 +479,70 @@ GNUNET_JSON_getopt (char shortName,
479 const char *description, 479 const char *description,
480 json_t **json); 480 json_t **json);
481 481
482/* ****************** GETOPT JSON parser ******************* */
483
484struct GNUNET_REST_JSON_Data
485{
486 /**
487 * Public key of an identity
488 */
489 char *pubkey;
490
491 /**
492 * Name
493 */
494 char *name;
495
496 /**
497 * Nickname
498 */
499 char *nickname;
500
501 /**
502 * New name
503 */
504 char *new_name;
505
506 /**
507 * Name of subsystem
508 */
509 char *subsystem;
510
511 /**
512 * Should data be handled as public (GNUNET_YES or GNUNET_NO)
513 */
514 int is_public;
515
516 /**
517 * Expiration date of data
518 */
519 char *expiration_time;
520
521 /**
522 * Type of data
523 */
524 char *type;
525
526 /**
527 * Value of data
528 */
529 char *value;
530
531 /**
532 * Zone
533 */
534 char *zone;
535};
536/*
537 * Test
538 */
539int
540GNUNET_REST_JSON_parse (struct GNUNET_REST_JSON_Data** rest_json_data,
541 json_t *json_data);
542
543int
544GNUNET_REST_JSON_free (struct GNUNET_REST_JSON_Data* rest_json_data);
545
482 546
483#endif 547#endif
484 548
diff --git a/src/json/Makefile.am b/src/json/Makefile.am
index da19e7955..5aac23654 100644
--- a/src/json/Makefile.am
+++ b/src/json/Makefile.am
@@ -16,7 +16,8 @@ libgnunetjson_la_SOURCES = \
16 json.c \ 16 json.c \
17 json_mhd.c \ 17 json_mhd.c \
18 json_generator.c \ 18 json_generator.c \
19 json_helper.c 19 json_helper.c \
20 json_parser.c
20libgnunetjson_la_LIBADD = \ 21libgnunetjson_la_LIBADD = \
21 $(top_builddir)/src/util/libgnunetutil.la \ 22 $(top_builddir)/src/util/libgnunetutil.la \
22 -ljansson \ 23 -ljansson \
diff --git a/src/json/json_parser.c b/src/json/json_parser.c
new file mode 100644
index 000000000..cfe553b34
--- /dev/null
+++ b/src/json/json_parser.c
@@ -0,0 +1,169 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2014, 2015, 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your 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 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18/**
19 * @file json/json_helper.c
20 * @brief functions for REST JSON parsing
21 * @author Philippe Buschmann
22 */
23
24#include "platform.h"
25#include "gnunet_util_lib.h"
26#include "gnunet_json_lib.h"
27
28#define GNUNET_REST_JSON_PUBKEY_ENTRY "pubkey"
29#define GNUNET_REST_JSON_NAME_ENTRY "name"
30#define GNUNET_REST_JSON_NICKNAME_ENTRY "nickname"
31#define GNUNET_REST_JSON_NEWNAME_ENTRY "newname"
32#define GNUNET_REST_JSON_SUBSYSTEM_ENTRY "subsystem"
33#define GNUNET_REST_JSON_IS_PUBLIC_ENTRY "is_public"
34#define GNUNET_REST_JSON_EXPIRATION_DATE_ENTRY "expiration_time"
35#define GNUNET_REST_JSON_TYPE_ENTRY "type"
36#define GNUNET_REST_JSON_VALUE_ENTRY "value"
37#define GNUNET_REST_JSON_ZONE_ENTRY "zone"
38
39
40int
41GNUNET_REST_JSON_parse (struct GNUNET_REST_JSON_Data** output_data ,json_t *json_data)
42{
43 struct GNUNET_REST_JSON_Data *rest_json_data;
44 json_t *cache;
45
46 rest_json_data = GNUNET_malloc(sizeof(struct GNUNET_REST_JSON_Data));
47
48 cache = json_object_get (json_data, GNUNET_REST_JSON_EXPIRATION_DATE_ENTRY);
49 rest_json_data->expiration_time = NULL;
50 if (NULL != cache)
51 {
52 if (json_is_string(cache))
53 {
54 rest_json_data->expiration_time = GNUNET_strdup(json_string_value(cache));
55 }
56 }
57 cache = json_object_get (json_data, GNUNET_REST_JSON_NAME_ENTRY);
58 rest_json_data->name = NULL;
59 if (NULL != cache)
60 {
61 if (json_is_string(cache))
62 {
63 rest_json_data->name = GNUNET_strdup(json_string_value(cache));
64 }
65 }
66 cache = json_object_get (json_data, GNUNET_REST_JSON_NEWNAME_ENTRY);
67 rest_json_data->new_name = NULL;
68 if (NULL != cache)
69 {
70 if (json_is_string(cache))
71 {
72 rest_json_data->new_name = GNUNET_strdup(json_string_value(cache));
73 }
74 }
75 cache = json_object_get (json_data, GNUNET_REST_JSON_NICKNAME_ENTRY);
76 rest_json_data->nickname = NULL;
77 if (NULL != cache)
78 {
79 if (json_is_string(cache))
80 {
81 rest_json_data->nickname = GNUNET_strdup(json_string_value(cache));
82 }
83 }
84 cache = json_object_get (json_data, GNUNET_REST_JSON_PUBKEY_ENTRY);
85 rest_json_data->pubkey = NULL;
86 if (NULL != cache)
87 {
88 if (json_is_string(cache))
89 {
90 rest_json_data->pubkey = GNUNET_strdup(json_string_value(cache));
91 }
92 }
93 cache = json_object_get (json_data, GNUNET_REST_JSON_SUBSYSTEM_ENTRY);
94 rest_json_data->subsystem = NULL;
95 if (NULL != cache)
96 {
97 if (json_is_string(cache))
98 {
99 rest_json_data->subsystem = GNUNET_strdup(json_string_value(cache));
100 }
101 }
102 cache = json_object_get (json_data, GNUNET_REST_JSON_TYPE_ENTRY);
103 rest_json_data->type = NULL;
104 if (NULL != cache)
105 {
106 if (json_is_string(cache))
107 {
108 rest_json_data->type = GNUNET_strdup(json_string_value(cache));
109 }
110 }
111 cache = json_object_get (json_data, GNUNET_REST_JSON_VALUE_ENTRY);
112 rest_json_data->value = NULL;
113 if (NULL != cache)
114 {
115 if (json_is_string(cache))
116 {
117 rest_json_data->value = GNUNET_strdup(json_string_value(cache));
118 }
119 }
120 cache = json_object_get (json_data, GNUNET_REST_JSON_ZONE_ENTRY);
121 rest_json_data->zone = NULL;
122 if (NULL != cache)
123 {
124 if (json_is_string(cache))
125 {
126 rest_json_data->zone = GNUNET_strdup(json_string_value(cache));
127 }
128 }
129 cache = json_object_get (json_data, GNUNET_REST_JSON_IS_PUBLIC_ENTRY);
130 if (NULL != cache)
131 {
132 if (json_is_integer(cache))
133 {
134 rest_json_data->is_public = json_integer_value(cache);
135 }
136 }
137 *output_data = rest_json_data;
138 return GNUNET_OK;
139}
140
141
142
143int
144GNUNET_REST_JSON_free (struct GNUNET_REST_JSON_Data* rest_json_data)
145{
146 if (rest_json_data != NULL)
147 {
148 GNUNET_free_non_null(rest_json_data->expiration_time);
149 GNUNET_free_non_null(rest_json_data->name);
150 GNUNET_free_non_null(rest_json_data->new_name);
151 GNUNET_free_non_null(rest_json_data->nickname);
152 GNUNET_free_non_null(rest_json_data->pubkey);
153 GNUNET_free_non_null(rest_json_data->subsystem);
154 GNUNET_free_non_null(rest_json_data->type);
155 GNUNET_free_non_null(rest_json_data->value);
156 GNUNET_free_non_null(rest_json_data->zone);
157 }
158 GNUNET_free_non_null(rest_json_data);
159 return GNUNET_OK;
160}
161
162
163
164
165
166
167
168
169
diff --git a/src/namestore/plugin_rest_namestore.c b/src/namestore/plugin_rest_namestore.c
index ec44046e0..ab490c04f 100644
--- a/src/namestore/plugin_rest_namestore.c
+++ b/src/namestore/plugin_rest_namestore.c
@@ -2,24 +2,26 @@
2 This file is part of GNUnet. 2 This file is part of GNUnet.
3 Copyright (C) 2012-2015 GNUnet e.V. 3 Copyright (C) 2012-2015 GNUnet e.V.
4 4
5 GNUnet is free software: you can redistribute it and/or modify it 5 GNUnet is free software; you can redistribute it and/or modify
6 under the terms of the GNU Affero General Public License as published 6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation, either version 3 of the License, 7 by the Free Software Foundation; either version 3, or (at your
8 or (at your option) any later version. 8 option) any later version.
9 9
10 GNUnet is distributed in the hope that it will be useful, but 10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of 11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details. 13 General Public License for more details.
14 14
15 You should have received a copy of the GNU Affero General Public License 15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>. 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.
17 */ 19 */
18/** 20/**
19 * @author Martin Schanzenbach 21 * @author Martin Schanzenbach
22 * @author Philippe Buschmann
20 * @file namestore/plugin_rest_namestore.c 23 * @file namestore/plugin_rest_namestore.c
21 * @brief GNUnet Namestore REST plugin 24 * @brief GNUnet Namestore REST plugin
22 *
23 */ 25 */
24 26
25#include "platform.h" 27#include "platform.h"
@@ -28,38 +30,32 @@
28#include "gnunet_namestore_service.h" 30#include "gnunet_namestore_service.h"
29#include "gnunet_identity_service.h" 31#include "gnunet_identity_service.h"
30#include "gnunet_rest_lib.h" 32#include "gnunet_rest_lib.h"
31#include "gnunet_jsonapi_lib.h" 33#include "gnunet_json_lib.h"
32#include "gnunet_jsonapi_util.h"
33#include "microhttpd.h" 34#include "microhttpd.h"
34#include <jansson.h> 35#include <jansson.h>
35 36
36#define GNUNET_REST_API_NS_NAMESTORE "/names" 37#define GNUNET_REST_API_NS_NAMESTORE "/namestore"
37
38#define GNUNET_REST_API_NS_NAMESTORE_ZKEY "/names/zkey"
39
40#define GNUNET_REST_JSONAPI_NAMESTORE_TYPEINFO "record"
41
42#define GNUNET_REST_JSONAPI_NAMESTORE_NAME "name"
43
44#define GNUNET_REST_JSONAPI_NAMESTORE_REVINFO "revinfo"
45 38
46#define GNUNET_REST_JSONAPI_NAMESTORE_RECORD GNUNET_REST_JSONAPI_NAMESTORE_TYPEINFO 39#define GNUNET_REST_SUBSYSTEM_NAMESTORE "namestore"
47 40
48#define GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE "record_type" 41#define GNUNET_REST_JSON_NAMESTORE_RECORD_TYPE "record_type"
42#define GNUNET_REST_JSON_NAMESTORE_VALUE "value"
43#define GNUNET_REST_JSON_NAMESTORE_EXPIRATION "expiration"
44#define GNUNET_REST_JSON_NAMESTORE_EXPIRED "expired"
49 45
50#define GNUNET_REST_JSONAPI_NAMESTORE_VALUE "value" 46#define GNUNET_REST_NAMESTORE_RD_COUNT 1
51 47
52#define GNUNET_REST_JSONAPI_NAMESTORE_PUBLIC "public" 48//TODO define other variables
53 49
54#define GNUNET_REST_JSONAPI_NAMESTORE_SHADOW "shadow" 50/**
55 51 * The configuration handle
56#define GNUNET_REST_JSONAPI_NAMESTORE_PKEY "pkey" 52 */
57 53const struct GNUNET_CONFIGURATION_Handle *cfg;
58#define GNUNET_REST_JSONAPI_NAMESTORE_ZKEY "zkey"
59
60#define GNUNET_REST_JSONAPI_NAMESTORE_EXPIRATION "expiration"
61 54
62#define GNUNET_REST_JSONAPI_NAMESTORE_EGO "ego" 55/**
56 * HTTP methods allows for this plugin
57 */
58static char* allow_methods;
63 59
64/** 60/**
65 * @brief struct returned by the initialization function of the plugin 61 * @brief struct returned by the initialization function of the plugin
@@ -69,54 +65,53 @@ struct Plugin
69 const struct GNUNET_CONFIGURATION_Handle *cfg; 65 const struct GNUNET_CONFIGURATION_Handle *cfg;
70}; 66};
71 67
68//TODO add specific structs
72 69
73/** 70/**
74 * HTTP methods allows for this plugin 71 * The default namestore ego
75 */ 72 */
76static char* allow_methods; 73struct EgoEntry
77
78const struct GNUNET_CONFIGURATION_Handle *cfg;
79
80struct RecordEntry
81{ 74{
82 /** 75 /**
83 * DLL 76 * Ego Identifier
84 */ 77 */
85 struct RecordEntry *next; 78 const char *identifier;
86 79
87 /** 80 /**
88 * DLL 81 * Public key string
89 */ 82 */
90 struct RecordEntry *prev; 83 char *keystring;
91 84
85 /**
86 * The Ego
87 */
88 struct GNUNET_IDENTITY_Ego *ego;
92}; 89};
93 90
91
94struct RequestHandle 92struct RequestHandle
95{ 93{
96 /** 94 //TODO add specific entries
97 * Ego list
98 */
99 struct RecordEntry *record_head;
100 95
101 /** 96 /**
102 * Ego list 97 * Records to store
103 */ 98 */
104 struct record_entry *record_tail; 99 struct GNUNET_GNSRECORD_Data *rd;
105 100
106 /** 101 /**
107 * JSON response object 102 * NAMESTORE Operation
108 */ 103 */
109 struct GNUNET_JSONAPI_Document *resp_object; 104 struct GNUNET_NAMESTORE_QueueEntry *add_qe;
110 105
111 /** 106 /**
112 * Rest connection 107 * JSON data parser
113 */ 108 */
114 struct GNUNET_REST_RequestHandle *rest_handle; 109 struct GNUNET_REST_JSON_Data *json_data;
115 110
116 /** 111 /**
117 * Handle to GNS service. 112 * Response object
118 */ 113 */
119 struct GNUNET_IDENTITY_Handle *identity_handle; 114 json_t *resp_object;
120 115
121 /** 116 /**
122 * Handle to NAMESTORE 117 * Handle to NAMESTORE
@@ -134,70 +129,25 @@ struct RequestHandle
134 struct GNUNET_CRYPTO_EcdsaPrivateKey zone_pkey; 129 struct GNUNET_CRYPTO_EcdsaPrivateKey zone_pkey;
135 130
136 /** 131 /**
137 * Handle to identity lookup 132 * IDENTITY Operation
138 */
139 struct GNUNET_IDENTITY_EgoLookup *ego_lookup;
140
141 /**
142 * Default Ego operation
143 */
144 struct GNUNET_IDENTITY_Operation *get_default;
145
146 /**
147 * Name of the ego
148 */
149 char *ego_name;
150
151 /**
152 * Record is public
153 */
154 int is_public;
155
156 /**
157 * Shadow record
158 */
159 int is_shadow;
160
161 /**
162 * Name of the record to modify
163 */
164 char *name;
165
166 /**
167 * Value of the record
168 */
169 char *value;
170
171 /**
172 * Zkey string
173 */
174 const char* zkey_str;
175
176 /**
177 * record type
178 */ 133 */
179 uint32_t type; 134 struct EgoEntry *ego_entry;
180
181 /**
182 * Records to store
183 */
184 struct GNUNET_GNSRECORD_Data *rd;
185 135
186 /** 136 /**
187 * record count 137 * IDENTITY Operation
188 */ 138 */
189 unsigned int rd_count; 139 struct GNUNET_IDENTITY_Operation *op;
190 140
191 /** 141 /**
192 * NAMESTORE Operation 142 * Handle to Identity service.
193 */ 143 */
194 struct GNUNET_NAMESTORE_QueueEntry *add_qe; 144 struct GNUNET_IDENTITY_Handle *identity_handle;
195 145
196 /** 146 /**
197 * NAMESTORE Operation 147 * Rest connection
198 */ 148 */
199 struct GNUNET_NAMESTORE_QueueEntry *reverse_qe; 149 struct GNUNET_REST_RequestHandle *rest_handle;
200 150
201 /** 151 /**
202 * Desired timeout for the lookup (default is no timeout). 152 * Desired timeout for the lookup (default is no timeout).
203 */ 153 */
@@ -206,7 +156,7 @@ struct RequestHandle
206 /** 156 /**
207 * ID of a task associated with the resolution process. 157 * ID of a task associated with the resolution process.
208 */ 158 */
209 struct GNUNET_SCHEDULER_Task * timeout_task; 159 struct GNUNET_SCHEDULER_Task *timeout_task;
210 160
211 /** 161 /**
212 * The plugin result processor 162 * The plugin result processor
@@ -224,76 +174,123 @@ struct RequestHandle
224 char *url; 174 char *url;
225 175
226 /** 176 /**
227 * Cfg 177 * Error response message
228 */ 178 */
229 const struct GNUNET_CONFIGURATION_Handle *cfg; 179 char *emsg;
230 180
231 /** 181 /**
232 * HTTP response code 182 * Reponse code
233 */ 183 */
234 int response_code; 184 int response_code;
235 185
236}; 186};
237 187
238 188
189//TODO add specific cleanup
239/** 190/**
240 * Cleanup lookup handle 191 * Cleanup lookup handle
241 *
242 * @param handle Handle to clean up 192 * @param handle Handle to clean up
243 */ 193 */
244static void 194static void
245cleanup_handle (struct RequestHandle *handle) 195cleanup_handle (struct RequestHandle *handle)
246{ 196{
247 struct RecordEntry *record_entry; 197 size_t index;
248 struct RecordEntry *record_tmp; 198 json_t *json_ego;
249 199
250 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 200 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
251 "Cleaning up\n"); 201 "Cleaning up\n");
252 if (NULL != handle->resp_object)
253 GNUNET_JSONAPI_document_delete (handle->resp_object);
254 if (NULL != handle->name)
255 GNUNET_free (handle->name);
256 if (NULL != handle->timeout_task) 202 if (NULL != handle->timeout_task)
203 {
257 GNUNET_SCHEDULER_cancel (handle->timeout_task); 204 GNUNET_SCHEDULER_cancel (handle->timeout_task);
258 if (NULL != handle->ego_lookup) 205 handle->timeout_task = NULL;
259 GNUNET_IDENTITY_ego_lookup_cancel (handle->ego_lookup); 206 }
260 if (NULL != handle->get_default) 207 if (NULL != handle->url)
261 GNUNET_IDENTITY_cancel (handle->get_default); 208 GNUNET_free(handle->url);
209 if (NULL != handle->emsg)
210 GNUNET_free(handle->emsg);
211 if (NULL != handle->rd)
212 {
213 if (NULL != handle->rd->data)
214 GNUNET_free((void*)handle->rd->data);
215 GNUNET_free(handle->rd);
216 }
217 if (NULL != handle->timeout_task)
218 GNUNET_SCHEDULER_cancel(handle->timeout_task);
262 if (NULL != handle->list_it) 219 if (NULL != handle->list_it)
263 GNUNET_NAMESTORE_zone_iteration_stop (handle->list_it); 220 GNUNET_NAMESTORE_zone_iteration_stop(handle->list_it);
264 if (NULL != handle->add_qe) 221 if (NULL != handle->add_qe)
265 GNUNET_NAMESTORE_cancel (handle->add_qe); 222 GNUNET_NAMESTORE_cancel(handle->add_qe);
266 if (NULL != handle->identity_handle) 223 if (NULL != handle->identity_handle)
267 GNUNET_IDENTITY_disconnect (handle->identity_handle); 224 GNUNET_IDENTITY_disconnect(handle->identity_handle);
268 if (NULL != handle->ns_handle) 225 if (NULL != handle->ns_handle)
269 GNUNET_NAMESTORE_disconnect (handle->ns_handle);
270 if (NULL != handle->url)
271 GNUNET_free (handle->url);
272 if (NULL != handle->value)
273 GNUNET_free (handle->value);
274 if (NULL != handle->rd)
275 { 226 {
276 for (unsigned int i = 0; i < handle->rd_count; i++) 227 GNUNET_NAMESTORE_disconnect(handle->ns_handle);
277 {
278 if (NULL != handle->rd[i].data)
279 GNUNET_free ((void*)handle->rd[i].data);
280 }
281 GNUNET_free (handle->rd);
282 } 228 }
283 if (NULL != handle->ego_name) 229
284 GNUNET_free (handle->ego_name); 230 if (NULL != handle->ego_entry)
285 for (record_entry = handle->record_head;
286 NULL != record_entry;)
287 { 231 {
288 record_tmp = record_entry; 232 if (NULL != handle->ego_entry->keystring)
289 record_entry = record_entry->next; 233 GNUNET_free(handle->ego_entry->keystring);
290 GNUNET_free (record_tmp); 234
235 GNUNET_free(handle->ego_entry);
236 }
237
238 if(NULL != handle->resp_object)
239 {
240 json_array_foreach(handle->resp_object, index, json_ego )
241 {
242 json_decref (json_ego);
243 }
244 json_decref(handle->resp_object);
291 } 245 }
246
247 if (NULL != handle->json_data)
248 GNUNET_REST_JSON_free(handle->json_data);
249
292 GNUNET_free (handle); 250 GNUNET_free (handle);
293} 251}
294 252
295 253
296/** 254/**
255 * Task run on errors. Reports an error and cleans up everything.
256 *
257 * @param cls the `struct RequestHandle`
258 */
259static void
260do_error (void *cls)
261{
262 struct RequestHandle *handle = cls;
263 struct MHD_Response *resp;
264 char *json_error;
265
266 if (NULL == handle->emsg)
267 handle->emsg = GNUNET_strdup("Unknown Error");
268
269 GNUNET_asprintf (&json_error, "{\"error\": \"%s\"}", handle->emsg);
270
271 if (0 == handle->response_code)
272 handle->response_code = MHD_HTTP_OK;
273
274 resp = GNUNET_REST_create_response (json_error);
275 handle->proc (handle->proc_cls, resp, handle->response_code);
276 cleanup_handle (handle);
277 GNUNET_free(json_error);
278}
279
280/**
281 * Does internal server error when iteration failed.
282 */
283static void
284namestore_iteration_error (void *cls)
285{
286 struct RequestHandle *handle = cls;
287 struct MHD_Response *resp = GNUNET_REST_create_response (NULL);
288 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
289 handle->proc (handle->proc_cls, resp, handle->response_code);
290 cleanup_handle (handle);
291}
292
293/**
297 * Create json representation of a GNSRECORD 294 * Create json representation of a GNSRECORD
298 * 295 *
299 * @param rd the GNSRECORD_Data 296 * @param rd the GNSRECORD_Data
@@ -313,19 +310,19 @@ gnsrecord_to_json (const struct GNUNET_GNSRECORD_Data *rd)
313 310
314 if (NULL == string_val) 311 if (NULL == string_val)
315 { 312 {
316 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 313 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
317 "Record of type %d malformed, skipping\n", 314 "Record of type %d malformed, skipping\n",
318 (int) rd->record_type); 315 (int) rd->record_type);
319 return NULL; 316 return NULL;
320 } 317 }
321 record_obj = json_object(); 318 record_obj = json_object();
322 json_object_set_new (record_obj, 319 json_object_set_new (record_obj,
323 GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE, 320 GNUNET_REST_JSON_NAMESTORE_RECORD_TYPE,
324 json_string (typename)); 321 json_string (typename));
325 json_object_set_new (record_obj, 322 json_object_set_new (record_obj,
326 GNUNET_REST_JSONAPI_NAMESTORE_VALUE, 323 GNUNET_REST_JSON_NAMESTORE_VALUE,
327 json_string (string_val)); 324 json_string (string_val));
328 GNUNET_free (string_val); 325 //GNUNET_free (string_val);
329 326
330 if (GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION & rd->flags) 327 if (GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION & rd->flags)
331 { 328 {
@@ -339,52 +336,33 @@ gnsrecord_to_json (const struct GNUNET_GNSRECORD_Data *rd)
339 time_abs.abs_value_us = rd->expiration_time; 336 time_abs.abs_value_us = rd->expiration_time;
340 exp_str = GNUNET_STRINGS_absolute_time_to_string (time_abs); 337 exp_str = GNUNET_STRINGS_absolute_time_to_string (time_abs);
341 } 338 }
342 json_object_set_new (record_obj, GNUNET_REST_JSONAPI_NAMESTORE_EXPIRATION, json_string (exp_str)); 339 json_object_set_new (record_obj,
343 340 GNUNET_REST_JSON_NAMESTORE_EXPIRATION,
341 json_string (exp_str));
344 json_object_set_new (record_obj, "expired", 342 json_object_set_new (record_obj, "expired",
345 json_boolean (GNUNET_YES == GNUNET_GNSRECORD_is_expired (rd))); 343 json_boolean (GNUNET_YES == GNUNET_GNSRECORD_is_expired (rd)));
346 return record_obj; 344 return record_obj;
347} 345}
348 346
349 347
350/**
351 * Task run on error. Generates error response and cleans up.
352 *
353 * @param cls the request to generate an error response for
354 */
355static void
356do_error (void *cls)
357{
358 struct RequestHandle *handle = cls;
359 struct MHD_Response *resp = GNUNET_REST_create_response (NULL);
360
361 handle->proc (handle->proc_cls, resp, handle->response_code);
362 cleanup_handle (handle);
363}
364
365
366/**
367 * Task run on timeout.
368 *
369 * @param cls the request to time out
370 */
371static void 348static void
372do_timeout (void *cls) 349create_finished (void *cls, int32_t success, const char *emsg)
373{ 350{
374 struct RequestHandle *handle = cls; 351 struct RequestHandle *handle = cls;
352 struct MHD_Response *resp;
375 353
376 handle->timeout_task = NULL; 354 handle->add_qe = NULL;
377 do_error (handle); 355 if (GNUNET_YES != success)
378} 356 {
379 357 handle->emsg = GNUNET_strdup("Error storing records");
380 358 GNUNET_SCHEDULER_add_now (&do_error, handle);
381static void 359 return;
382cleanup_handle_delayed (void *cls) 360 }
383{ 361 resp = GNUNET_REST_create_response (NULL);
384 cleanup_handle (cls); 362 handle->proc (handle->proc_cls, resp, MHD_HTTP_NO_CONTENT);
363 cleanup_handle(handle);
385} 364}
386 365
387
388/** 366/**
389 * Iteration over all results finished, build final 367 * Iteration over all results finished, build final
390 * response. 368 * response.
@@ -395,29 +373,25 @@ static void
395namestore_list_finished (void *cls) 373namestore_list_finished (void *cls)
396{ 374{
397 struct RequestHandle *handle = cls; 375 struct RequestHandle *handle = cls;
398 char *result; 376 char *result_str;
399 struct MHD_Response *resp; 377 struct MHD_Response *resp;
400 378
401 handle->list_it = NULL; 379 handle->list_it = NULL;
402 if (NULL == handle->resp_object)
403 handle->resp_object = GNUNET_JSONAPI_document_new ();
404 380
405 if (GNUNET_SYSERR == 381 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "HEY\n");
406 GNUNET_JSONAPI_document_serialize (handle->resp_object, 382 if (NULL == handle->resp_object)
407 &result))
408 { 383 {
409 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; 384 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "OH\n");
410 GNUNET_SCHEDULER_add_now (&do_error, 385 GNUNET_SCHEDULER_add_now (&do_error, handle);
411 handle);
412 return; 386 return;
413 } 387 }
414 resp = GNUNET_REST_create_response (result); 388
415 handle->proc (handle->proc_cls, 389 result_str = json_dumps (handle->resp_object, 0);
416 resp, 390 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
417 MHD_HTTP_OK); 391 resp = GNUNET_REST_create_response (result_str);
418 GNUNET_free_non_null (result); 392 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
419 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, 393 GNUNET_free_non_null (result_str);
420 handle); 394 cleanup_handle(handle);
421} 395}
422 396
423 397
@@ -428,84 +402,172 @@ namestore_list_finished (void *cls)
428 * @param handle the RequestHandle 402 * @param handle the RequestHandle
429 */ 403 */
430static void 404static void
431namestore_list_response (void *cls, 405namestore_list_iteration (void *cls,
432 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key, 406 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
433 const char *rname, 407 const char *rname,
434 unsigned int rd_len, 408 unsigned int rd_len,
435 const struct GNUNET_GNSRECORD_Data *rd) 409 const struct GNUNET_GNSRECORD_Data *rd)
436{ 410{
437 struct RequestHandle *handle = cls; 411 struct RequestHandle *handle = cls;
438 struct GNUNET_JSONAPI_Resource *json_resource;
439 json_t *result_array;
440 json_t *record_obj; 412 json_t *record_obj;
441 413
442 if (NULL == handle->resp_object) 414 if (NULL == handle->resp_object)
443 handle->resp_object = GNUNET_JSONAPI_document_new (); 415 handle->resp_object = json_array();
444 416
445 if ( (NULL != handle->name) && 417 char *result_str = json_dumps (handle->resp_object, 0);
446 (0 != strcmp (handle->name, 418 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "%s\n", result_str);
419 GNUNET_free(result_str);
420 /*if ( (NULL != handle->ego_entry->identifier) &&
421 (0 != strcmp (handle->ego_entry->identifier,
447 rname)) ) 422 rname)) )
448 { 423 {
449 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 424 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
450 "%s does not match %s\n", 425 "%s does not match %s\n", rname,
451 rname, 426 handle->ego_entry->identifier);
452 handle->name); 427 GNUNET_NAMESTORE_zone_iterator_next (handle->list_it, 1);
453 GNUNET_NAMESTORE_zone_iterator_next (handle->list_it,
454 1);
455 return; 428 return;
456 } 429 }*/
457 430
458 result_array = json_array (); 431 for (unsigned int i = 0; i < rd_len; i++)
459 for (unsigned int i=0; i<rd_len; i++)
460 { 432 {
461 if ( (GNUNET_GNSRECORD_TYPE_NICK == rd[i].record_type) && 433 if ( (GNUNET_GNSRECORD_TYPE_NICK == rd[i].record_type) &&
462 (0 != strcmp (rname, GNUNET_GNS_EMPTY_LABEL_AT)) ) 434 (0 != strcmp (rname, GNUNET_GNS_EMPTY_LABEL_AT)) )
463 continue; 435 continue;
464 436
465 if ( (rd[i].record_type != handle->type) &&
466 (GNUNET_GNSRECORD_TYPE_ANY != handle->type) )
467 continue;
468 record_obj = gnsrecord_to_json (&rd[i]); 437 record_obj = gnsrecord_to_json (&rd[i]);
469 json_array_append (result_array, 438
439 if(NULL == record_obj)
440 continue;
441
442 json_array_append (handle->resp_object,
470 record_obj); 443 record_obj);
471 json_decref (record_obj); 444 json_decref (record_obj);
472 } 445 }
473 446
474 if (0 < json_array_size(result_array)) 447 GNUNET_NAMESTORE_zone_iterator_next (handle->list_it, 1);
448}
449
450
451/**
452 * Handle namestore GET request
453 *
454 * @param con_handle the connection handle
455 * @param url the url
456 * @param cls the RequestHandle
457 */
458void
459namestore_get (struct GNUNET_REST_RequestHandle *con_handle,
460 const char* url,
461 void *cls)
462{
463 struct RequestHandle *handle = cls;
464 if (strlen (GNUNET_REST_API_NS_NAMESTORE) != strlen (handle->url))
475 { 465 {
476 json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_NAMESTORE_TYPEINFO, 466 handle->emsg = GNUNET_strdup("Wrong URL");
477 rname); 467 GNUNET_SCHEDULER_add_now (&do_error, handle);
478 GNUNET_JSONAPI_resource_add_attr (json_resource, 468 return;
479 GNUNET_REST_JSONAPI_NAMESTORE_RECORD,
480 result_array);
481 GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource);
482 } 469 }
483 470 handle->list_it = GNUNET_NAMESTORE_zone_iteration_start (handle->ns_handle,
484 json_decref (result_array); 471 &handle->zone_pkey,
485 GNUNET_NAMESTORE_zone_iterator_next (handle->list_it, 472 &namestore_iteration_error,
486 1); 473 handle,
474 &namestore_list_iteration,
475 handle,
476 &namestore_list_finished,
477 handle);
487} 478}
488 479
480int
481check_needed_data(struct RequestHandle *handle){
482 if(NULL == handle->json_data->name)
483 {
484 handle->emsg = GNUNET_strdup("Missing JSON parameter: name");
485 return GNUNET_SYSERR;
486 }
487
488 if(NULL == handle->json_data->type)
489 {
490 handle->emsg = GNUNET_strdup("Missing JSON parameter: type");
491 return GNUNET_SYSERR;
492 }
489 493
490static void 494 if(NULL == handle->json_data->value)
491create_finished (void *cls, int32_t success, const char *emsg) 495 {
496 handle->emsg = GNUNET_strdup("Missing JSON parameter: value");
497 return GNUNET_SYSERR;
498 }
499
500 if(NULL == handle->json_data->expiration_time)
501 {
502 handle->emsg = GNUNET_strdup("Missing JSON parameter: expiration time");
503 return GNUNET_SYSERR;
504 }
505 return GNUNET_OK;
506}
507
508//TODO filter input
509static int
510json_to_gnsrecord (struct RequestHandle *handle)
492{ 511{
493 struct RequestHandle *handle = cls; 512 struct GNUNET_TIME_Relative etime_rel;
494 struct MHD_Response *resp; 513 struct GNUNET_TIME_Absolute etime_abs;
514 void *rdata;
515 size_t rdata_size;
495 516
496 handle->add_qe = NULL; 517 handle->rd = GNUNET_new_array(GNUNET_REST_NAMESTORE_RD_COUNT,
497 if (GNUNET_YES != success) 518 struct GNUNET_GNSRECORD_Data);
519 memset (handle->rd, 0, sizeof(struct GNUNET_GNSRECORD_Data));
520 handle->rd->record_type = GNUNET_GNSRECORD_typename_to_number (
521 handle->json_data->type);
522 if (UINT32_MAX == (*handle->rd).record_type)
498 { 523 {
499 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 524 handle->emsg = GNUNET_strdup("Unsupported type");
500 "Error storing records%s%s\n", 525 return GNUNET_SYSERR;
501 (NULL == emsg) ? "" : ": ",
502 (NULL == emsg) ? "" : emsg);
503 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
504 return;
505 } 526 }
506 resp = GNUNET_REST_create_response (NULL); 527 if (GNUNET_OK
507 handle->proc (handle->proc_cls, resp, MHD_HTTP_NO_CONTENT); 528 != GNUNET_GNSRECORD_string_to_value ((*handle->rd).record_type,
508 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle); 529 handle->json_data->value, &rdata,
530 &rdata_size))
531 {
532 handle->emsg = GNUNET_strdup("Value invalid for record type");
533 return GNUNET_SYSERR;
534 }
535 (*handle->rd).data = rdata;
536 (*handle->rd).data_size = rdata_size;
537 //TODO other flags
538 if (0 == handle->json_data->is_public)
539 {
540 handle->rd->flags |= GNUNET_GNSRECORD_RF_PRIVATE;
541 }
542 /**TODO
543 * if (1 == handle->is_shadow)
544 rde->flags |= GNUNET_GNSRECORD_RF_SHADOW_RECORD;
545 if (1 != handle->is_public)
546 rde->flags |= GNUNET_GNSRECORD_RF_PRIVATE;
547 */
548 if (0 == strcmp (handle->json_data->expiration_time, "never"))
549 {
550 (*handle->rd).expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us;
551 }
552 else if (GNUNET_OK
553 == GNUNET_STRINGS_fancy_time_to_relative (
554 handle->json_data->expiration_time, &etime_rel))
555 {
556 (*handle->rd).expiration_time = etime_rel.rel_value_us;
557 (*handle->rd).flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
558 }
559 else if (GNUNET_OK
560 == GNUNET_STRINGS_fancy_time_to_absolute (
561 handle->json_data->expiration_time, &etime_abs))
562 {
563 (*handle->rd).expiration_time = etime_abs.abs_value_us;
564 }
565 else
566 {
567 handle->emsg = GNUNET_strdup("Value invalid for record type");
568 return GNUNET_SYSERR;
569 }
570 return GNUNET_OK;
509} 571}
510 572
511 573
@@ -529,7 +591,7 @@ create_new_record_cont (void *cls,
529 struct RequestHandle *handle = cls; 591 struct RequestHandle *handle = cls;
530 592
531 handle->add_qe = NULL; 593 handle->add_qe = NULL;
532 if (0 != strcmp (rec_name, handle->name)) 594 if (0 != strcmp (rec_name, handle->json_data->name))
533 { 595 {
534 GNUNET_break (0); 596 GNUNET_break (0);
535 do_error (handle); 597 do_error (handle);
@@ -541,426 +603,99 @@ create_new_record_cont (void *cls,
541 handle->proc (handle->proc_cls, 603 handle->proc (handle->proc_cls,
542 GNUNET_REST_create_response (NULL), 604 GNUNET_REST_create_response (NULL),
543 MHD_HTTP_CONFLICT); 605 MHD_HTTP_CONFLICT);
544 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle); 606 cleanup_handle(handle);
545 return; 607 return;
546 } 608 }
547
548 GNUNET_assert (NULL != handle->name);
549 handle->add_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle, 609 handle->add_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle,
550 &handle->zone_pkey, 610 &handle->zone_pkey,
551 handle->name, 611 handle->json_data->name,
552 handle->rd_count, 612 GNUNET_REST_NAMESTORE_RD_COUNT,
553 handle->rd, 613 handle->rd,
554 &create_finished, 614 &create_finished,
555 handle); 615 handle);
556} 616}
557 617
558 618
559static void 619/**
560del_finished (void *cls, 620 * Handle namestore POST request
561 int32_t success, 621 *
562 const char *emsg) 622 * @param con_handle the connection handle
563{ 623 * @param url the url
564 struct RequestHandle *handle = cls; 624 * @param cls the RequestHandle
565 625 */
566 handle->add_qe = NULL; 626void
567 if (GNUNET_NO == success) 627namestore_add (struct GNUNET_REST_RequestHandle *con_handle,
568 { 628 const char* url,
569 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 629 void *cls)
570 _("Deleting record failed, record does not exist%s%s\n"),
571 (NULL != emsg) ? ": " : "",
572 (NULL != emsg) ? emsg : "");
573 GNUNET_SCHEDULER_add_now (&do_error, handle); //do_not_found TODO
574 return;
575 }
576 if (GNUNET_SYSERR == success)
577 {
578 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
579 _("Deleting record failed%s%s\n"),
580 (NULL != emsg) ? ": " : "",
581 (NULL != emsg) ? emsg : "");
582 GNUNET_SCHEDULER_add_now (&do_error, handle);
583 return;
584 }
585 handle->proc (handle->proc_cls,
586 GNUNET_REST_create_response (NULL),
587 MHD_HTTP_NO_CONTENT);
588 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
589}
590
591
592static void
593del_cont (void *cls,
594 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
595 const char *label,
596 unsigned int rd_count,
597 const struct GNUNET_GNSRECORD_Data *rd)
598{
599 struct RequestHandle *handle = cls;
600
601 handle->add_qe = NULL;
602 if (0 == rd_count)
603 {
604 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
605 _("There are no records under label `%s' that could be deleted.\n"),
606 label);
607 do_error (handle);
608 return;
609 }
610
611 handle->add_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle,
612 &handle->zone_pkey,
613 handle->name,
614 0, NULL,
615 &del_finished,
616 handle);
617}
618
619
620static void
621namestore_delete_cont (struct GNUNET_REST_RequestHandle *con,
622 const char *url,
623 void *cls)
624{
625 struct RequestHandle *handle = cls;
626
627 if (NULL == handle->name)
628 {
629 GNUNET_SCHEDULER_add_now (&do_error, handle);
630 return;
631 }
632
633 handle->add_qe = GNUNET_NAMESTORE_records_lookup (handle->ns_handle,
634 &handle->zone_pkey,
635 handle->name,
636 &do_error,
637 handle,
638 &del_cont,
639 handle);
640}
641
642
643static int
644json_to_gnsrecord (const json_t *records_json,
645 struct GNUNET_GNSRECORD_Data **rd,
646 unsigned int *rd_count)
647{
648 struct GNUNET_TIME_Relative etime_rel;
649 struct GNUNET_TIME_Absolute etime_abs;
650 char *value;
651 void *rdata;
652 size_t rdata_size;
653 const char *typestring;
654 const char *expirationstring;
655 json_t *type_json;
656 json_t *value_json;
657 json_t *record_json;
658 json_t *exp_json;
659
660 *rd_count = json_array_size (records_json);
661 *rd = GNUNET_new_array (*rd_count,
662 struct GNUNET_GNSRECORD_Data);
663 for (unsigned int i = 0; i < *rd_count; i++)
664 {
665 memset (&(*rd)[i],
666 0,
667 sizeof (struct GNUNET_GNSRECORD_Data));
668 record_json = json_array_get (records_json,
669 i);
670 type_json = json_object_get (record_json,
671 GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE);
672 if (! json_is_string (type_json))
673 {
674 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
675 "Type property is no string\n");
676 return GNUNET_SYSERR;
677 }
678 typestring = json_string_value (type_json);
679 (*rd)[i].record_type = GNUNET_GNSRECORD_typename_to_number (typestring);
680 if (UINT32_MAX == (*rd)[i].record_type)
681 {
682 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Unsupported type `%s'\n"),
683 json_string_value (type_json));
684 return GNUNET_SYSERR;
685 }
686 value_json = json_object_get (record_json,
687 GNUNET_REST_JSONAPI_NAMESTORE_VALUE);
688 if (! json_is_string (value_json))
689 {
690 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
691 "Value property is no string\n");
692 return GNUNET_SYSERR;
693 }
694 value = GNUNET_strdup (json_string_value (value_json));
695 if (GNUNET_OK !=
696 GNUNET_GNSRECORD_string_to_value ((*rd)[i].record_type,
697 value,
698 &rdata,
699 &rdata_size))
700 {
701 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
702 _("Value `%s' invalid for record type `%s'\n"),
703 value,
704 typestring);
705 return GNUNET_SYSERR;
706 }
707 (*rd)[i].data = rdata;
708 (*rd)[i].data_size = rdata_size;
709 /**TODO
710 * if (1 == handle->is_shadow)
711 rde->flags |= GNUNET_GNSRECORD_RF_SHADOW_RECORD;
712 if (1 != handle->is_public)
713 rde->flags |= GNUNET_GNSRECORD_RF_PRIVATE;
714 */
715 exp_json = json_object_get (record_json,
716 GNUNET_REST_JSONAPI_NAMESTORE_EXPIRATION);
717 if (! json_is_string (exp_json))
718 {
719 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
720 "Expiration property is no string\n");
721 return GNUNET_SYSERR;
722 }
723 expirationstring = json_string_value (exp_json);
724 if (0 == strcmp (expirationstring, "never"))
725 {
726 (*rd)[i].expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us;
727 }
728 else if (GNUNET_OK ==
729 GNUNET_STRINGS_fancy_time_to_relative (expirationstring,
730 &etime_rel))
731 {
732 (*rd)[i].expiration_time = etime_rel.rel_value_us;
733 (*rd)[i].flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
734 }
735 else if (GNUNET_OK ==
736 GNUNET_STRINGS_fancy_time_to_absolute (expirationstring,
737 &etime_abs))
738 {
739 (*rd)[i].expiration_time = etime_abs.abs_value_us;
740 }
741 else
742 {
743 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
744 _("Value `%s' invalid for record type `%s'\n"),
745 value,
746 typestring);
747 return GNUNET_SYSERR;
748 }
749 }
750 return GNUNET_OK;
751}
752
753
754static void
755namestore_create_cont (struct GNUNET_REST_RequestHandle *con,
756 const char *url,
757 void *cls)
758{ 630{
759 struct RequestHandle *handle = cls; 631 struct RequestHandle *handle = cls;
760 struct MHD_Response *resp;
761 struct GNUNET_JSONAPI_Document *json_obj;
762 struct GNUNET_JSONAPI_Resource *json_res;
763 json_t *records_json;
764 json_t *data_js; 632 json_t *data_js;
765 json_error_t err; 633 json_error_t err;
766 char term_data[handle->rest_handle->data_size+1]; 634 char term_data[handle->rest_handle->data_size + 1];
767 struct GNUNET_JSON_Specification docspec[] = {
768 GNUNET_JSON_spec_jsonapi_document (&json_obj),
769 GNUNET_JSON_spec_end()
770 };
771 635
772 if (strlen (GNUNET_REST_API_NS_NAMESTORE) != strlen (handle->url)) 636 if (strlen (GNUNET_REST_API_NS_NAMESTORE) != strlen (handle->url))
773 { 637 {
774 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 638 handle->emsg = GNUNET_strdup("Wrong URL");
775 "Cannot create under %s\n", handle->url);
776 GNUNET_SCHEDULER_add_now (&do_error, handle); 639 GNUNET_SCHEDULER_add_now (&do_error, handle);
777 return; 640 return;
778 } 641 }
779 if (0 >= handle->rest_handle->data_size) 642 if (0 >= handle->rest_handle->data_size)
780 { 643 {
644 handle->emsg = GNUNET_strdup("No data");
781 GNUNET_SCHEDULER_add_now (&do_error, handle); 645 GNUNET_SCHEDULER_add_now (&do_error, handle);
782 return; 646 return;
783 } 647 }
784 term_data[handle->rest_handle->data_size] = '\0'; 648 term_data[handle->rest_handle->data_size] = '\0';
785 GNUNET_memcpy (term_data, 649 GNUNET_memcpy(term_data, handle->rest_handle->data,
786 handle->rest_handle->data, 650 handle->rest_handle->data_size);
787 handle->rest_handle->data_size); 651 data_js = json_loads (term_data, JSON_DECODE_ANY, &err);
788 data_js = json_loads (term_data, 652 GNUNET_REST_JSON_parse(&handle->json_data, data_js);
789 JSON_DECODE_ANY, 653 if(NULL == handle->json_data)
790 &err);
791 GNUNET_assert (GNUNET_OK ==
792 GNUNET_JSON_parse (data_js, docspec,
793 NULL, NULL));
794 json_decref (data_js);
795 if (NULL == json_obj)
796 {
797 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
798 "Unable to parse JSONAPI Object from %s\n",
799 term_data);
800 GNUNET_SCHEDULER_add_now (&do_error, handle);
801 return;
802 }
803 if (1 != GNUNET_JSONAPI_document_resource_count (json_obj))
804 {
805 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
806 "Cannot create more than 1 resource! (Got %d)\n",
807 GNUNET_JSONAPI_document_resource_count (json_obj));
808 GNUNET_JSONAPI_document_delete (json_obj);
809 GNUNET_SCHEDULER_add_now (&do_error, handle);
810 return;
811 }
812 json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0);
813 if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res,
814 GNUNET_REST_JSONAPI_NAMESTORE_RECORD))
815 { 654 {
816 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 655 handle->emsg = GNUNET_strdup("Wrong data");
817 "Unsupported JSON data type\n");
818 GNUNET_JSONAPI_document_delete (json_obj);
819 resp = GNUNET_REST_create_response (NULL);
820 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
821 cleanup_handle (handle);
822 return;
823 }
824 handle->name = GNUNET_strdup (GNUNET_JSONAPI_resource_get_id (json_res));
825 records_json = GNUNET_JSONAPI_resource_read_attr (json_res,
826 GNUNET_REST_JSONAPI_NAMESTORE_RECORD);
827 if (NULL == records_json)
828 {
829 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
830 "No records given\n");
831 GNUNET_JSONAPI_document_delete (json_obj);
832 GNUNET_SCHEDULER_add_now (&do_error, handle); 656 GNUNET_SCHEDULER_add_now (&do_error, handle);
833 return; 657 return;
834 } 658 }
835 if (GNUNET_SYSERR == json_to_gnsrecord (records_json, &handle->rd, &handle->rd_count)) 659 if(GNUNET_SYSERR == check_needed_data(handle))
836 { 660 {
837 GNUNET_JSONAPI_document_delete (json_obj); 661 json_decref (data_js);
838 GNUNET_SCHEDULER_add_now (&do_error, handle); 662 GNUNET_SCHEDULER_add_now (&do_error, handle);
839 return; 663 return;
840 } 664 }
841 GNUNET_JSONAPI_document_delete (json_obj); 665 json_decref (data_js);
842 666 json_to_gnsrecord (handle);
843 handle->add_qe = GNUNET_NAMESTORE_records_lookup (handle->ns_handle, 667 handle->add_qe = GNUNET_NAMESTORE_records_lookup (handle->ns_handle,
844 &handle->zone_pkey, 668 &handle->zone_pkey,
845 handle->name, 669 handle->json_data->name,
846 &do_error, 670 &do_error,
847 handle, 671 handle,
848 &create_new_record_cont, 672 &create_new_record_cont,
849 handle); 673 handle);
850}
851
852
853static void
854namestore_zkey_response (void *cls,
855 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
856 const char *label,
857 unsigned int rd_count,
858 const struct GNUNET_GNSRECORD_Data *rd)
859{
860 struct RequestHandle *handle = cls;
861 struct MHD_Response *resp;
862 struct GNUNET_JSONAPI_Document *json_obj;
863 struct GNUNET_JSONAPI_Resource *json_res;
864 json_t *name_json;
865 char* result;
866
867 handle->reverse_qe = NULL;
868 json_obj = GNUNET_JSONAPI_document_new ();
869 if (NULL != label)
870 {
871 name_json = json_string (label);
872 json_res = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_NAMESTORE_REVINFO,
873 handle->zkey_str);
874 GNUNET_JSONAPI_resource_add_attr (json_res,
875 GNUNET_REST_JSONAPI_NAMESTORE_NAME,
876 name_json);
877 GNUNET_JSONAPI_document_resource_add (json_obj, json_res);
878 json_decref (name_json);
879 }
880 //Handle response
881 if (GNUNET_SYSERR == GNUNET_JSONAPI_document_serialize (json_obj, &result))
882 {
883 GNUNET_JSONAPI_document_delete (json_obj);
884 GNUNET_SCHEDULER_add_now (&do_error, handle);
885 return;
886 }
887 resp = GNUNET_REST_create_response (result);
888 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
889 GNUNET_JSONAPI_document_delete (json_obj);
890 GNUNET_free (result);
891 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
892}
893
894
895static void
896namestore_zkey_cont (struct GNUNET_REST_RequestHandle *con,
897 const char *url,
898 void *cls)
899{
900 struct RequestHandle *handle = cls;
901 struct GNUNET_HashCode key;
902 struct GNUNET_CRYPTO_EcdsaPublicKey pubkey;
903
904 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_NAMESTORE_ZKEY,
905 strlen (GNUNET_REST_JSONAPI_NAMESTORE_ZKEY),
906 &key);
907 if ( GNUNET_NO ==
908 GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
909 &key) )
910 {
911 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
912 "No zkey given %s\n", handle->url);
913 GNUNET_SCHEDULER_add_now (&do_error, handle);
914 return;
915 }
916 handle->zkey_str = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map,
917 &key);
918 if ((NULL == handle->zkey_str) ||
919 (GNUNET_OK !=
920 GNUNET_CRYPTO_ecdsa_public_key_from_string (handle->zkey_str,
921 strlen (handle->zkey_str),
922 &pubkey)))
923 {
924 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
925 "Zkey invalid %s\n", handle->zkey_str);
926 GNUNET_SCHEDULER_add_now (&do_error, handle);
927 return;
928 }
929 handle->reverse_qe = GNUNET_NAMESTORE_zone_to_name (handle->ns_handle,
930 &handle->zone_pkey,
931 &pubkey,
932 &do_error,
933 handle,
934 &namestore_zkey_response,
935 handle);
936} 674}
937 675
938 676
939static void 677/**
940namestore_info_cont (struct GNUNET_REST_RequestHandle *con, 678 * Handle namestore DELETE request
941 const char *url, 679 *
942 void *cls) 680 * @param con_handle the connection handle
681 * @param url the url
682 * @param cls the RequestHandle
683 */
684void
685namestore_delete (struct GNUNET_REST_RequestHandle *con_handle,
686 const char* url,
687 void *cls)
943{ 688{
944 struct RequestHandle *handle = cls; 689 struct RequestHandle *handle = cls;
945 690
946 handle->list_it = GNUNET_NAMESTORE_zone_iteration_start (handle->ns_handle, 691 //TODO add behaviour and response
947 &handle->zone_pkey, 692
948 &do_error, 693 handle->emsg = GNUNET_strdup ("Not implemented yet");
949 handle, 694 GNUNET_SCHEDULER_add_now (&do_error, handle);
950 &namestore_list_response, 695 return;
951 handle,
952 &namestore_list_finished,
953 handle);
954} 696}
955 697
956 698
957static char*
958get_name_from_url (const char* url)
959{
960 if (strlen (url) <= strlen (GNUNET_REST_API_NS_NAMESTORE))
961 return NULL;
962 return (char*)url + strlen (GNUNET_REST_API_NS_NAMESTORE) + 1;
963}
964 699
965/** 700/**
966 * Respond to OPTIONS request 701 * Respond to OPTIONS request
@@ -977,77 +712,48 @@ options_cont (struct GNUNET_REST_RequestHandle *con_handle,
977 struct MHD_Response *resp; 712 struct MHD_Response *resp;
978 struct RequestHandle *handle = cls; 713 struct RequestHandle *handle = cls;
979 714
980 //For now, independent of path return all options 715 //independent of path return all options
981 resp = GNUNET_REST_create_response (NULL); 716 resp = GNUNET_REST_create_response (NULL);
982 MHD_add_response_header (resp, 717 MHD_add_response_header (resp,
983 "Access-Control-Allow-Methods", 718 "Access-Control-Allow-Methods",
984 allow_methods); 719 allow_methods);
985 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); 720 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
986 cleanup_handle (handle); 721 cleanup_handle (handle);
722 return;
987} 723}
988 724
989 725
990/** 726/**
991 * Callback invoked from identity service with ego information. 727 * Handle rest request
992 * An @a ego of NULL means the ego was not found.
993 * 728 *
994 * @param cls closure with the configuration 729 * @param handle the request handle
995 * @param ego an ego known to identity service, or NULL
996 */ 730 */
997static void 731static void
998identity_cb (void *cls, 732init_cont (struct RequestHandle *handle)
999 const struct GNUNET_IDENTITY_Ego *ego)
1000{ 733{
1001 struct RequestHandle *handle = cls; 734 //TODO specify parameter of init_cont if necessary
1002 struct MHD_Response *resp;
1003 struct GNUNET_REST_RequestHandlerError err; 735 struct GNUNET_REST_RequestHandlerError err;
1004 static const struct GNUNET_REST_RequestHandler handlers[] = { 736 static const struct GNUNET_REST_RequestHandler handlers[] = {
1005 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_NAMESTORE_ZKEY, &namestore_zkey_cont}, //reverse 737 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_NAMESTORE, &namestore_get},
1006 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_NAMESTORE, &namestore_info_cont}, //list 738 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_NAMESTORE, &namestore_add},
1007 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_NAMESTORE, &namestore_create_cont}, //create 739 {MHD_HTTP_METHOD_DELETE, GNUNET_REST_API_NS_NAMESTORE, &namestore_delete},
1008 // {MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_NAMESTORE, &namestore_edit_cont}, //update. TODO this shoul be PATCH
1009 {MHD_HTTP_METHOD_DELETE, GNUNET_REST_API_NS_NAMESTORE, &namestore_delete_cont}, //delete
1010 {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_NAMESTORE, &options_cont}, 740 {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_NAMESTORE, &options_cont},
1011 GNUNET_REST_HANDLER_END 741 GNUNET_REST_HANDLER_END
1012 }; 742 };
1013 743
1014 handle->ego_lookup = NULL; 744 if (GNUNET_NO == GNUNET_REST_handle_request (handle->rest_handle,
1015 if (NULL == ego) 745 handlers,
1016 { 746 &err,
1017 if (NULL != handle->ego_name) 747 handle))
1018 {
1019 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1020 _("Ego `%s' not known to identity service\n"),
1021 handle->ego_name);
1022 }
1023 resp = GNUNET_REST_create_response (NULL);
1024 handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
1025 cleanup_handle (handle);
1026 return;
1027 }
1028 handle->zone_pkey = *GNUNET_IDENTITY_ego_get_private_key (ego);
1029 handle->ns_handle = GNUNET_NAMESTORE_connect (cfg);
1030 if (NULL == handle->ns_handle)
1031 {
1032 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1033 _("Failed to connect to namestore\n"));
1034 GNUNET_SCHEDULER_add_now (&do_error, handle);
1035 return;
1036 }
1037
1038 if (GNUNET_OK !=
1039 GNUNET_JSONAPI_handle_request (handle->rest_handle,
1040 handlers,
1041 &err,
1042 handle))
1043 { 748 {
1044 handle->response_code = err.error_code; 749 handle->response_code = err.error_code;
1045 GNUNET_SCHEDULER_add_now (&do_error, 750 GNUNET_SCHEDULER_add_now (&do_error, handle);
1046 (void *) handle);
1047 } 751 }
1048} 752}
1049 753
1050 754/**
755 *
756 */
1051static void 757static void
1052default_ego_cb (void *cls, 758default_ego_cb (void *cls,
1053 struct GNUNET_IDENTITY_Ego *ego, 759 struct GNUNET_IDENTITY_Ego *ego,
@@ -1055,23 +761,31 @@ default_ego_cb (void *cls,
1055 const char *name) 761 const char *name)
1056{ 762{
1057 struct RequestHandle *handle = cls; 763 struct RequestHandle *handle = cls;
1058 struct MHD_Response *resp; 764 struct EgoEntry *ego_entry;
1059 handle->get_default = NULL; 765 struct GNUNET_CRYPTO_EcdsaPublicKey pk;
766
767 handle->op = NULL;
768
1060 if (NULL == ego) 769 if (NULL == ego)
1061 { 770 {
1062 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 771 handle->emsg = GNUNET_strdup ("No default ego configured in identity service");
1063 _("No default ego configured in identity service\n")); 772 GNUNET_SCHEDULER_add_now (&do_error, handle);
1064 resp = GNUNET_REST_create_response (NULL);
1065 handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
1066 cleanup_handle (handle);
1067 return; 773 return;
1068 } 774 }
1069 else 775 ego_entry = GNUNET_new(struct EgoEntry);
1070 { 776 GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
1071 identity_cb (cls, ego); 777 ego_entry->keystring = GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
1072 } 778 ego_entry->identifier = name;
779 ego_entry->ego = ego;
780 handle->ego_entry = ego_entry;
781 handle->zone_pkey = *GNUNET_IDENTITY_ego_get_private_key (ego);
782 init_cont (handle);
1073} 783}
1074 784
785
786/**
787 * Connect to identity callback
788 */
1075static void 789static void
1076id_connect_cb (void *cls, 790id_connect_cb (void *cls,
1077 struct GNUNET_IDENTITY_Ego *ego, 791 struct GNUNET_IDENTITY_Ego *ego,
@@ -1081,9 +795,10 @@ id_connect_cb (void *cls,
1081 struct RequestHandle *handle = cls; 795 struct RequestHandle *handle = cls;
1082 if (NULL == ego) 796 if (NULL == ego)
1083 { 797 {
1084 handle->get_default = GNUNET_IDENTITY_get (handle->identity_handle, 798 handle->op = GNUNET_IDENTITY_get (handle->identity_handle,
1085 "namestore", 799 GNUNET_REST_SUBSYSTEM_NAMESTORE,
1086 &default_ego_cb, handle); 800 &default_ego_cb,
801 handle);
1087 } 802 }
1088} 803}
1089 804
@@ -1097,81 +812,37 @@ id_connect_cb (void *cls,
1097 * @param data_size length of the body 812 * @param data_size length of the body
1098 * @param proc callback function for the result 813 * @param proc callback function for the result
1099 * @param proc_cls closure for callback function 814 * @param proc_cls closure for callback function
1100 * @return #GNUNET_OK if request accepted 815 * @return GNUNET_OK if request accepted
1101 */ 816 */
1102static void 817static void
1103rest_identity_process_request(struct GNUNET_REST_RequestHandle *rest_handle, 818rest_process_request(struct GNUNET_REST_RequestHandle *rest_handle,
1104 GNUNET_REST_ResultProcessor proc, 819 GNUNET_REST_ResultProcessor proc,
1105 void *proc_cls) 820 void *proc_cls)
1106{ 821{
1107 struct RequestHandle *handle = GNUNET_new (struct RequestHandle); 822 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
1108 struct MHD_Response *resp; 823
1109 struct GNUNET_HashCode key; 824 handle->response_code = 0;
1110 char *ego;
1111 char *name;
1112 char *type;
1113
1114 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL; 825 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1115 handle->proc_cls = proc_cls; 826 handle->proc_cls = proc_cls;
1116 handle->proc = proc; 827 handle->proc = proc;
1117 handle->rest_handle = rest_handle; 828 handle->rest_handle = rest_handle;
829
1118 handle->url = GNUNET_strdup (rest_handle->url); 830 handle->url = GNUNET_strdup (rest_handle->url);
1119 if (handle->url[strlen (handle->url)-1] == '/') 831 if (handle->url[strlen (handle->url)-1] == '/')
1120 handle->url[strlen (handle->url)-1] = '\0'; 832 handle->url[strlen (handle->url)-1] = '\0';
1121 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 833 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n");
1122 "Connecting...\n");
1123 handle->cfg = cfg;
1124 ego = NULL;
1125 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_NAMESTORE_EGO,
1126 strlen (GNUNET_REST_JSONAPI_NAMESTORE_EGO),
1127 &key);
1128 if ( GNUNET_YES ==
1129 GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1130 &key) )
1131 {
1132 ego = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map,
1133 &key);
1134 }
1135 834
1136 handle->type = GNUNET_GNSRECORD_TYPE_ANY; 835 handle->identity_handle = GNUNET_IDENTITY_connect (cfg, &id_connect_cb, handle);
1137 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE, 836 handle->ns_handle = GNUNET_NAMESTORE_connect (cfg);
1138 strlen (GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE), 837 handle->timeout_task =
1139 &key); 838 GNUNET_SCHEDULER_add_delayed (handle->timeout,
1140 if ( GNUNET_YES == 839 &do_error,
1141 GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map, 840 handle);
1142 &key) ) 841
1143 { 842 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected\n");
1144 type = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map,
1145 &key);
1146 if (NULL != type)
1147 handle->type = GNUNET_GNSRECORD_typename_to_number (type);
1148 }
1149 name = get_name_from_url (handle->url);
1150 if (NULL != ego)
1151 handle->ego_name = GNUNET_strdup (ego);
1152 if (NULL != name)
1153 handle->name = GNUNET_strdup (name);
1154 if (NULL == handle->ego_name)
1155 {
1156 handle->identity_handle = GNUNET_IDENTITY_connect (handle->cfg, &id_connect_cb, handle);
1157 if (NULL == handle->identity_handle)
1158 {
1159 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Cannot connect to identity service\n"));
1160 resp = GNUNET_REST_create_response (NULL);
1161 handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
1162 cleanup_handle (handle);
1163 }
1164 return;
1165 }
1166 handle->ego_lookup = GNUNET_IDENTITY_ego_lookup (cfg,
1167 handle->ego_name,
1168 &identity_cb,
1169 handle);
1170 handle->timeout_task = GNUNET_SCHEDULER_add_delayed (handle->timeout,
1171 &do_timeout,
1172 handle);
1173} 843}
1174 844
845
1175/** 846/**
1176 * Entry point for the plugin. 847 * Entry point for the plugin.
1177 * 848 *
@@ -1182,9 +853,9 @@ void *
1182libgnunet_plugin_rest_namestore_init (void *cls) 853libgnunet_plugin_rest_namestore_init (void *cls)
1183{ 854{
1184 static struct Plugin plugin; 855 static struct Plugin plugin;
1185 cfg = cls;
1186 struct GNUNET_REST_Plugin *api; 856 struct GNUNET_REST_Plugin *api;
1187 857
858 cfg = cls;
1188 if (NULL != plugin.cfg) 859 if (NULL != plugin.cfg)
1189 return NULL; /* can only initialize once! */ 860 return NULL; /* can only initialize once! */
1190 memset (&plugin, 0, sizeof (struct Plugin)); 861 memset (&plugin, 0, sizeof (struct Plugin));
@@ -1192,7 +863,7 @@ libgnunet_plugin_rest_namestore_init (void *cls)
1192 api = GNUNET_new (struct GNUNET_REST_Plugin); 863 api = GNUNET_new (struct GNUNET_REST_Plugin);
1193 api->cls = &plugin; 864 api->cls = &plugin;
1194 api->name = GNUNET_REST_API_NS_NAMESTORE; 865 api->name = GNUNET_REST_API_NS_NAMESTORE;
1195 api->process_request = &rest_identity_process_request; 866 api->process_request = &rest_process_request;
1196 GNUNET_asprintf (&allow_methods, 867 GNUNET_asprintf (&allow_methods,
1197 "%s, %s, %s, %s, %s", 868 "%s, %s, %s, %s, %s",
1198 MHD_HTTP_METHOD_GET, 869 MHD_HTTP_METHOD_GET,
@@ -1200,7 +871,8 @@ libgnunet_plugin_rest_namestore_init (void *cls)
1200 MHD_HTTP_METHOD_PUT, 871 MHD_HTTP_METHOD_PUT,
1201 MHD_HTTP_METHOD_DELETE, 872 MHD_HTTP_METHOD_DELETE,
1202 MHD_HTTP_METHOD_OPTIONS); 873 MHD_HTTP_METHOD_OPTIONS);
1203 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 874
875 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1204 _("Namestore REST API initialized\n")); 876 _("Namestore REST API initialized\n"));
1205 return api; 877 return api;
1206} 878}
@@ -1217,13 +889,14 @@ libgnunet_plugin_rest_namestore_done (void *cls)
1217{ 889{
1218 struct GNUNET_REST_Plugin *api = cls; 890 struct GNUNET_REST_Plugin *api = cls;
1219 struct Plugin *plugin = api->cls; 891 struct Plugin *plugin = api->cls;
1220
1221 plugin->cfg = NULL; 892 plugin->cfg = NULL;
1222 GNUNET_free (api); 893
1223 GNUNET_free_non_null (allow_methods); 894 GNUNET_free_non_null (allow_methods);
895 GNUNET_free (api);
1224 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 896 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1225 "Namestore REST plugin is finished\n"); 897 "Namestore REST plugin is finished\n");
1226 return NULL; 898 return NULL;
1227} 899}
1228 900
1229/* end of plugin_rest_namestore.c */ 901/* end of plugin_rest_namestore.c */
902
diff --git a/src/namestore/plugin_rest_namestore2.c b/src/namestore/plugin_rest_namestore2.c
new file mode 100644
index 000000000..ec44046e0
--- /dev/null
+++ b/src/namestore/plugin_rest_namestore2.c
@@ -0,0 +1,1229 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012-2015 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your 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 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18/**
19 * @author Martin Schanzenbach
20 * @file namestore/plugin_rest_namestore.c
21 * @brief GNUnet Namestore REST plugin
22 *
23 */
24
25#include "platform.h"
26#include "gnunet_rest_plugin.h"
27#include "gnunet_gns_service.h"
28#include "gnunet_namestore_service.h"
29#include "gnunet_identity_service.h"
30#include "gnunet_rest_lib.h"
31#include "gnunet_jsonapi_lib.h"
32#include "gnunet_jsonapi_util.h"
33#include "microhttpd.h"
34#include <jansson.h>
35
36#define GNUNET_REST_API_NS_NAMESTORE "/names"
37
38#define GNUNET_REST_API_NS_NAMESTORE_ZKEY "/names/zkey"
39
40#define GNUNET_REST_JSONAPI_NAMESTORE_TYPEINFO "record"
41
42#define GNUNET_REST_JSONAPI_NAMESTORE_NAME "name"
43
44#define GNUNET_REST_JSONAPI_NAMESTORE_REVINFO "revinfo"
45
46#define GNUNET_REST_JSONAPI_NAMESTORE_RECORD GNUNET_REST_JSONAPI_NAMESTORE_TYPEINFO
47
48#define GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE "record_type"
49
50#define GNUNET_REST_JSONAPI_NAMESTORE_VALUE "value"
51
52#define GNUNET_REST_JSONAPI_NAMESTORE_PUBLIC "public"
53
54#define GNUNET_REST_JSONAPI_NAMESTORE_SHADOW "shadow"
55
56#define GNUNET_REST_JSONAPI_NAMESTORE_PKEY "pkey"
57
58#define GNUNET_REST_JSONAPI_NAMESTORE_ZKEY "zkey"
59
60#define GNUNET_REST_JSONAPI_NAMESTORE_EXPIRATION "expiration"
61
62#define GNUNET_REST_JSONAPI_NAMESTORE_EGO "ego"
63
64/**
65 * @brief struct returned by the initialization function of the plugin
66 */
67struct Plugin
68{
69 const struct GNUNET_CONFIGURATION_Handle *cfg;
70};
71
72
73/**
74 * HTTP methods allows for this plugin
75 */
76static char* allow_methods;
77
78const struct GNUNET_CONFIGURATION_Handle *cfg;
79
80struct RecordEntry
81{
82 /**
83 * DLL
84 */
85 struct RecordEntry *next;
86
87 /**
88 * DLL
89 */
90 struct RecordEntry *prev;
91
92};
93
94struct RequestHandle
95{
96 /**
97 * Ego list
98 */
99 struct RecordEntry *record_head;
100
101 /**
102 * Ego list
103 */
104 struct record_entry *record_tail;
105
106 /**
107 * JSON response object
108 */
109 struct GNUNET_JSONAPI_Document *resp_object;
110
111 /**
112 * Rest connection
113 */
114 struct GNUNET_REST_RequestHandle *rest_handle;
115
116 /**
117 * Handle to GNS service.
118 */
119 struct GNUNET_IDENTITY_Handle *identity_handle;
120
121 /**
122 * Handle to NAMESTORE
123 */
124 struct GNUNET_NAMESTORE_Handle *ns_handle;
125
126 /**
127 * Handle to NAMESTORE it
128 */
129 struct GNUNET_NAMESTORE_ZoneIterator *list_it;
130
131 /**
132 * Private key for the zone
133 */
134 struct GNUNET_CRYPTO_EcdsaPrivateKey zone_pkey;
135
136 /**
137 * Handle to identity lookup
138 */
139 struct GNUNET_IDENTITY_EgoLookup *ego_lookup;
140
141 /**
142 * Default Ego operation
143 */
144 struct GNUNET_IDENTITY_Operation *get_default;
145
146 /**
147 * Name of the ego
148 */
149 char *ego_name;
150
151 /**
152 * Record is public
153 */
154 int is_public;
155
156 /**
157 * Shadow record
158 */
159 int is_shadow;
160
161 /**
162 * Name of the record to modify
163 */
164 char *name;
165
166 /**
167 * Value of the record
168 */
169 char *value;
170
171 /**
172 * Zkey string
173 */
174 const char* zkey_str;
175
176 /**
177 * record type
178 */
179 uint32_t type;
180
181 /**
182 * Records to store
183 */
184 struct GNUNET_GNSRECORD_Data *rd;
185
186 /**
187 * record count
188 */
189 unsigned int rd_count;
190
191 /**
192 * NAMESTORE Operation
193 */
194 struct GNUNET_NAMESTORE_QueueEntry *add_qe;
195
196 /**
197 * NAMESTORE Operation
198 */
199 struct GNUNET_NAMESTORE_QueueEntry *reverse_qe;
200
201 /**
202 * Desired timeout for the lookup (default is no timeout).
203 */
204 struct GNUNET_TIME_Relative timeout;
205
206 /**
207 * ID of a task associated with the resolution process.
208 */
209 struct GNUNET_SCHEDULER_Task * timeout_task;
210
211 /**
212 * The plugin result processor
213 */
214 GNUNET_REST_ResultProcessor proc;
215
216 /**
217 * The closure of the result processor
218 */
219 void *proc_cls;
220
221 /**
222 * The url
223 */
224 char *url;
225
226 /**
227 * Cfg
228 */
229 const struct GNUNET_CONFIGURATION_Handle *cfg;
230
231 /**
232 * HTTP response code
233 */
234 int response_code;
235
236};
237
238
239/**
240 * Cleanup lookup handle
241 *
242 * @param handle Handle to clean up
243 */
244static void
245cleanup_handle (struct RequestHandle *handle)
246{
247 struct RecordEntry *record_entry;
248 struct RecordEntry *record_tmp;
249
250 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
251 "Cleaning up\n");
252 if (NULL != handle->resp_object)
253 GNUNET_JSONAPI_document_delete (handle->resp_object);
254 if (NULL != handle->name)
255 GNUNET_free (handle->name);
256 if (NULL != handle->timeout_task)
257 GNUNET_SCHEDULER_cancel (handle->timeout_task);
258 if (NULL != handle->ego_lookup)
259 GNUNET_IDENTITY_ego_lookup_cancel (handle->ego_lookup);
260 if (NULL != handle->get_default)
261 GNUNET_IDENTITY_cancel (handle->get_default);
262 if (NULL != handle->list_it)
263 GNUNET_NAMESTORE_zone_iteration_stop (handle->list_it);
264 if (NULL != handle->add_qe)
265 GNUNET_NAMESTORE_cancel (handle->add_qe);
266 if (NULL != handle->identity_handle)
267 GNUNET_IDENTITY_disconnect (handle->identity_handle);
268 if (NULL != handle->ns_handle)
269 GNUNET_NAMESTORE_disconnect (handle->ns_handle);
270 if (NULL != handle->url)
271 GNUNET_free (handle->url);
272 if (NULL != handle->value)
273 GNUNET_free (handle->value);
274 if (NULL != handle->rd)
275 {
276 for (unsigned int i = 0; i < handle->rd_count; i++)
277 {
278 if (NULL != handle->rd[i].data)
279 GNUNET_free ((void*)handle->rd[i].data);
280 }
281 GNUNET_free (handle->rd);
282 }
283 if (NULL != handle->ego_name)
284 GNUNET_free (handle->ego_name);
285 for (record_entry = handle->record_head;
286 NULL != record_entry;)
287 {
288 record_tmp = record_entry;
289 record_entry = record_entry->next;
290 GNUNET_free (record_tmp);
291 }
292 GNUNET_free (handle);
293}
294
295
296/**
297 * Create json representation of a GNSRECORD
298 *
299 * @param rd the GNSRECORD_Data
300 */
301static json_t *
302gnsrecord_to_json (const struct GNUNET_GNSRECORD_Data *rd)
303{
304 const char *typename;
305 char *string_val;
306 const char *exp_str;
307 json_t *record_obj;
308
309 typename = GNUNET_GNSRECORD_number_to_typename (rd->record_type);
310 string_val = GNUNET_GNSRECORD_value_to_string (rd->record_type,
311 rd->data,
312 rd->data_size);
313
314 if (NULL == string_val)
315 {
316 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
317 "Record of type %d malformed, skipping\n",
318 (int) rd->record_type);
319 return NULL;
320 }
321 record_obj = json_object();
322 json_object_set_new (record_obj,
323 GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE,
324 json_string (typename));
325 json_object_set_new (record_obj,
326 GNUNET_REST_JSONAPI_NAMESTORE_VALUE,
327 json_string (string_val));
328 GNUNET_free (string_val);
329
330 if (GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION & rd->flags)
331 {
332 struct GNUNET_TIME_Relative time_rel;
333 time_rel.rel_value_us = rd->expiration_time;
334 exp_str = GNUNET_STRINGS_relative_time_to_string (time_rel, 1);
335 }
336 else
337 {
338 struct GNUNET_TIME_Absolute time_abs;
339 time_abs.abs_value_us = rd->expiration_time;
340 exp_str = GNUNET_STRINGS_absolute_time_to_string (time_abs);
341 }
342 json_object_set_new (record_obj, GNUNET_REST_JSONAPI_NAMESTORE_EXPIRATION, json_string (exp_str));
343
344 json_object_set_new (record_obj, "expired",
345 json_boolean (GNUNET_YES == GNUNET_GNSRECORD_is_expired (rd)));
346 return record_obj;
347}
348
349
350/**
351 * Task run on error. Generates error response and cleans up.
352 *
353 * @param cls the request to generate an error response for
354 */
355static void
356do_error (void *cls)
357{
358 struct RequestHandle *handle = cls;
359 struct MHD_Response *resp = GNUNET_REST_create_response (NULL);
360
361 handle->proc (handle->proc_cls, resp, handle->response_code);
362 cleanup_handle (handle);
363}
364
365
366/**
367 * Task run on timeout.
368 *
369 * @param cls the request to time out
370 */
371static void
372do_timeout (void *cls)
373{
374 struct RequestHandle *handle = cls;
375
376 handle->timeout_task = NULL;
377 do_error (handle);
378}
379
380
381static void
382cleanup_handle_delayed (void *cls)
383{
384 cleanup_handle (cls);
385}
386
387
388/**
389 * Iteration over all results finished, build final
390 * response.
391 *
392 * @param cls the `struct RequestHandle`
393 */
394static void
395namestore_list_finished (void *cls)
396{
397 struct RequestHandle *handle = cls;
398 char *result;
399 struct MHD_Response *resp;
400
401 handle->list_it = NULL;
402 if (NULL == handle->resp_object)
403 handle->resp_object = GNUNET_JSONAPI_document_new ();
404
405 if (GNUNET_SYSERR ==
406 GNUNET_JSONAPI_document_serialize (handle->resp_object,
407 &result))
408 {
409 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
410 GNUNET_SCHEDULER_add_now (&do_error,
411 handle);
412 return;
413 }
414 resp = GNUNET_REST_create_response (result);
415 handle->proc (handle->proc_cls,
416 resp,
417 MHD_HTTP_OK);
418 GNUNET_free_non_null (result);
419 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed,
420 handle);
421}
422
423
424
425/**
426 * Create a response with requested records
427 *
428 * @param handle the RequestHandle
429 */
430static void
431namestore_list_response (void *cls,
432 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
433 const char *rname,
434 unsigned int rd_len,
435 const struct GNUNET_GNSRECORD_Data *rd)
436{
437 struct RequestHandle *handle = cls;
438 struct GNUNET_JSONAPI_Resource *json_resource;
439 json_t *result_array;
440 json_t *record_obj;
441
442 if (NULL == handle->resp_object)
443 handle->resp_object = GNUNET_JSONAPI_document_new ();
444
445 if ( (NULL != handle->name) &&
446 (0 != strcmp (handle->name,
447 rname)) )
448 {
449 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
450 "%s does not match %s\n",
451 rname,
452 handle->name);
453 GNUNET_NAMESTORE_zone_iterator_next (handle->list_it,
454 1);
455 return;
456 }
457
458 result_array = json_array ();
459 for (unsigned int i=0; i<rd_len; i++)
460 {
461 if ( (GNUNET_GNSRECORD_TYPE_NICK == rd[i].record_type) &&
462 (0 != strcmp (rname, GNUNET_GNS_EMPTY_LABEL_AT)) )
463 continue;
464
465 if ( (rd[i].record_type != handle->type) &&
466 (GNUNET_GNSRECORD_TYPE_ANY != handle->type) )
467 continue;
468 record_obj = gnsrecord_to_json (&rd[i]);
469 json_array_append (result_array,
470 record_obj);
471 json_decref (record_obj);
472 }
473
474 if (0 < json_array_size(result_array))
475 {
476 json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_NAMESTORE_TYPEINFO,
477 rname);
478 GNUNET_JSONAPI_resource_add_attr (json_resource,
479 GNUNET_REST_JSONAPI_NAMESTORE_RECORD,
480 result_array);
481 GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource);
482 }
483
484 json_decref (result_array);
485 GNUNET_NAMESTORE_zone_iterator_next (handle->list_it,
486 1);
487}
488
489
490static void
491create_finished (void *cls, int32_t success, const char *emsg)
492{
493 struct RequestHandle *handle = cls;
494 struct MHD_Response *resp;
495
496 handle->add_qe = NULL;
497 if (GNUNET_YES != success)
498 {
499 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
500 "Error storing records%s%s\n",
501 (NULL == emsg) ? "" : ": ",
502 (NULL == emsg) ? "" : emsg);
503 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
504 return;
505 }
506 resp = GNUNET_REST_create_response (NULL);
507 handle->proc (handle->proc_cls, resp, MHD_HTTP_NO_CONTENT);
508 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
509}
510
511
512/**
513 * We're storing a new record; this requires
514 * that no record already exists
515 *
516 * @param cls closure, unused
517 * @param zone_key private key of the zone
518 * @param rec_name name that is being mapped (at most 255 characters long)
519 * @param rd_count number of entries in @a rd array
520 * @param rd array of records with data to store
521 */
522static void
523create_new_record_cont (void *cls,
524 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
525 const char *rec_name,
526 unsigned int rd_count,
527 const struct GNUNET_GNSRECORD_Data *rd)
528{
529 struct RequestHandle *handle = cls;
530
531 handle->add_qe = NULL;
532 if (0 != strcmp (rec_name, handle->name))
533 {
534 GNUNET_break (0);
535 do_error (handle);
536 return;
537 }
538
539 if (0 != rd_count)
540 {
541 handle->proc (handle->proc_cls,
542 GNUNET_REST_create_response (NULL),
543 MHD_HTTP_CONFLICT);
544 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
545 return;
546 }
547
548 GNUNET_assert (NULL != handle->name);
549 handle->add_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle,
550 &handle->zone_pkey,
551 handle->name,
552 handle->rd_count,
553 handle->rd,
554 &create_finished,
555 handle);
556}
557
558
559static void
560del_finished (void *cls,
561 int32_t success,
562 const char *emsg)
563{
564 struct RequestHandle *handle = cls;
565
566 handle->add_qe = NULL;
567 if (GNUNET_NO == success)
568 {
569 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
570 _("Deleting record failed, record does not exist%s%s\n"),
571 (NULL != emsg) ? ": " : "",
572 (NULL != emsg) ? emsg : "");
573 GNUNET_SCHEDULER_add_now (&do_error, handle); //do_not_found TODO
574 return;
575 }
576 if (GNUNET_SYSERR == success)
577 {
578 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
579 _("Deleting record failed%s%s\n"),
580 (NULL != emsg) ? ": " : "",
581 (NULL != emsg) ? emsg : "");
582 GNUNET_SCHEDULER_add_now (&do_error, handle);
583 return;
584 }
585 handle->proc (handle->proc_cls,
586 GNUNET_REST_create_response (NULL),
587 MHD_HTTP_NO_CONTENT);
588 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
589}
590
591
592static void
593del_cont (void *cls,
594 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
595 const char *label,
596 unsigned int rd_count,
597 const struct GNUNET_GNSRECORD_Data *rd)
598{
599 struct RequestHandle *handle = cls;
600
601 handle->add_qe = NULL;
602 if (0 == rd_count)
603 {
604 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
605 _("There are no records under label `%s' that could be deleted.\n"),
606 label);
607 do_error (handle);
608 return;
609 }
610
611 handle->add_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle,
612 &handle->zone_pkey,
613 handle->name,
614 0, NULL,
615 &del_finished,
616 handle);
617}
618
619
620static void
621namestore_delete_cont (struct GNUNET_REST_RequestHandle *con,
622 const char *url,
623 void *cls)
624{
625 struct RequestHandle *handle = cls;
626
627 if (NULL == handle->name)
628 {
629 GNUNET_SCHEDULER_add_now (&do_error, handle);
630 return;
631 }
632
633 handle->add_qe = GNUNET_NAMESTORE_records_lookup (handle->ns_handle,
634 &handle->zone_pkey,
635 handle->name,
636 &do_error,
637 handle,
638 &del_cont,
639 handle);
640}
641
642
643static int
644json_to_gnsrecord (const json_t *records_json,
645 struct GNUNET_GNSRECORD_Data **rd,
646 unsigned int *rd_count)
647{
648 struct GNUNET_TIME_Relative etime_rel;
649 struct GNUNET_TIME_Absolute etime_abs;
650 char *value;
651 void *rdata;
652 size_t rdata_size;
653 const char *typestring;
654 const char *expirationstring;
655 json_t *type_json;
656 json_t *value_json;
657 json_t *record_json;
658 json_t *exp_json;
659
660 *rd_count = json_array_size (records_json);
661 *rd = GNUNET_new_array (*rd_count,
662 struct GNUNET_GNSRECORD_Data);
663 for (unsigned int i = 0; i < *rd_count; i++)
664 {
665 memset (&(*rd)[i],
666 0,
667 sizeof (struct GNUNET_GNSRECORD_Data));
668 record_json = json_array_get (records_json,
669 i);
670 type_json = json_object_get (record_json,
671 GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE);
672 if (! json_is_string (type_json))
673 {
674 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
675 "Type property is no string\n");
676 return GNUNET_SYSERR;
677 }
678 typestring = json_string_value (type_json);
679 (*rd)[i].record_type = GNUNET_GNSRECORD_typename_to_number (typestring);
680 if (UINT32_MAX == (*rd)[i].record_type)
681 {
682 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Unsupported type `%s'\n"),
683 json_string_value (type_json));
684 return GNUNET_SYSERR;
685 }
686 value_json = json_object_get (record_json,
687 GNUNET_REST_JSONAPI_NAMESTORE_VALUE);
688 if (! json_is_string (value_json))
689 {
690 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
691 "Value property is no string\n");
692 return GNUNET_SYSERR;
693 }
694 value = GNUNET_strdup (json_string_value (value_json));
695 if (GNUNET_OK !=
696 GNUNET_GNSRECORD_string_to_value ((*rd)[i].record_type,
697 value,
698 &rdata,
699 &rdata_size))
700 {
701 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
702 _("Value `%s' invalid for record type `%s'\n"),
703 value,
704 typestring);
705 return GNUNET_SYSERR;
706 }
707 (*rd)[i].data = rdata;
708 (*rd)[i].data_size = rdata_size;
709 /**TODO
710 * if (1 == handle->is_shadow)
711 rde->flags |= GNUNET_GNSRECORD_RF_SHADOW_RECORD;
712 if (1 != handle->is_public)
713 rde->flags |= GNUNET_GNSRECORD_RF_PRIVATE;
714 */
715 exp_json = json_object_get (record_json,
716 GNUNET_REST_JSONAPI_NAMESTORE_EXPIRATION);
717 if (! json_is_string (exp_json))
718 {
719 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
720 "Expiration property is no string\n");
721 return GNUNET_SYSERR;
722 }
723 expirationstring = json_string_value (exp_json);
724 if (0 == strcmp (expirationstring, "never"))
725 {
726 (*rd)[i].expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us;
727 }
728 else if (GNUNET_OK ==
729 GNUNET_STRINGS_fancy_time_to_relative (expirationstring,
730 &etime_rel))
731 {
732 (*rd)[i].expiration_time = etime_rel.rel_value_us;
733 (*rd)[i].flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
734 }
735 else if (GNUNET_OK ==
736 GNUNET_STRINGS_fancy_time_to_absolute (expirationstring,
737 &etime_abs))
738 {
739 (*rd)[i].expiration_time = etime_abs.abs_value_us;
740 }
741 else
742 {
743 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
744 _("Value `%s' invalid for record type `%s'\n"),
745 value,
746 typestring);
747 return GNUNET_SYSERR;
748 }
749 }
750 return GNUNET_OK;
751}
752
753
754static void
755namestore_create_cont (struct GNUNET_REST_RequestHandle *con,
756 const char *url,
757 void *cls)
758{
759 struct RequestHandle *handle = cls;
760 struct MHD_Response *resp;
761 struct GNUNET_JSONAPI_Document *json_obj;
762 struct GNUNET_JSONAPI_Resource *json_res;
763 json_t *records_json;
764 json_t *data_js;
765 json_error_t err;
766 char term_data[handle->rest_handle->data_size+1];
767 struct GNUNET_JSON_Specification docspec[] = {
768 GNUNET_JSON_spec_jsonapi_document (&json_obj),
769 GNUNET_JSON_spec_end()
770 };
771
772 if (strlen (GNUNET_REST_API_NS_NAMESTORE) != strlen (handle->url))
773 {
774 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
775 "Cannot create under %s\n", handle->url);
776 GNUNET_SCHEDULER_add_now (&do_error, handle);
777 return;
778 }
779 if (0 >= handle->rest_handle->data_size)
780 {
781 GNUNET_SCHEDULER_add_now (&do_error, handle);
782 return;
783 }
784 term_data[handle->rest_handle->data_size] = '\0';
785 GNUNET_memcpy (term_data,
786 handle->rest_handle->data,
787 handle->rest_handle->data_size);
788 data_js = json_loads (term_data,
789 JSON_DECODE_ANY,
790 &err);
791 GNUNET_assert (GNUNET_OK ==
792 GNUNET_JSON_parse (data_js, docspec,
793 NULL, NULL));
794 json_decref (data_js);
795 if (NULL == json_obj)
796 {
797 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
798 "Unable to parse JSONAPI Object from %s\n",
799 term_data);
800 GNUNET_SCHEDULER_add_now (&do_error, handle);
801 return;
802 }
803 if (1 != GNUNET_JSONAPI_document_resource_count (json_obj))
804 {
805 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
806 "Cannot create more than 1 resource! (Got %d)\n",
807 GNUNET_JSONAPI_document_resource_count (json_obj));
808 GNUNET_JSONAPI_document_delete (json_obj);
809 GNUNET_SCHEDULER_add_now (&do_error, handle);
810 return;
811 }
812 json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0);
813 if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res,
814 GNUNET_REST_JSONAPI_NAMESTORE_RECORD))
815 {
816 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
817 "Unsupported JSON data type\n");
818 GNUNET_JSONAPI_document_delete (json_obj);
819 resp = GNUNET_REST_create_response (NULL);
820 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
821 cleanup_handle (handle);
822 return;
823 }
824 handle->name = GNUNET_strdup (GNUNET_JSONAPI_resource_get_id (json_res));
825 records_json = GNUNET_JSONAPI_resource_read_attr (json_res,
826 GNUNET_REST_JSONAPI_NAMESTORE_RECORD);
827 if (NULL == records_json)
828 {
829 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
830 "No records given\n");
831 GNUNET_JSONAPI_document_delete (json_obj);
832 GNUNET_SCHEDULER_add_now (&do_error, handle);
833 return;
834 }
835 if (GNUNET_SYSERR == json_to_gnsrecord (records_json, &handle->rd, &handle->rd_count))
836 {
837 GNUNET_JSONAPI_document_delete (json_obj);
838 GNUNET_SCHEDULER_add_now (&do_error, handle);
839 return;
840 }
841 GNUNET_JSONAPI_document_delete (json_obj);
842
843 handle->add_qe = GNUNET_NAMESTORE_records_lookup (handle->ns_handle,
844 &handle->zone_pkey,
845 handle->name,
846 &do_error,
847 handle,
848 &create_new_record_cont,
849 handle);
850}
851
852
853static void
854namestore_zkey_response (void *cls,
855 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
856 const char *label,
857 unsigned int rd_count,
858 const struct GNUNET_GNSRECORD_Data *rd)
859{
860 struct RequestHandle *handle = cls;
861 struct MHD_Response *resp;
862 struct GNUNET_JSONAPI_Document *json_obj;
863 struct GNUNET_JSONAPI_Resource *json_res;
864 json_t *name_json;
865 char* result;
866
867 handle->reverse_qe = NULL;
868 json_obj = GNUNET_JSONAPI_document_new ();
869 if (NULL != label)
870 {
871 name_json = json_string (label);
872 json_res = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_NAMESTORE_REVINFO,
873 handle->zkey_str);
874 GNUNET_JSONAPI_resource_add_attr (json_res,
875 GNUNET_REST_JSONAPI_NAMESTORE_NAME,
876 name_json);
877 GNUNET_JSONAPI_document_resource_add (json_obj, json_res);
878 json_decref (name_json);
879 }
880 //Handle response
881 if (GNUNET_SYSERR == GNUNET_JSONAPI_document_serialize (json_obj, &result))
882 {
883 GNUNET_JSONAPI_document_delete (json_obj);
884 GNUNET_SCHEDULER_add_now (&do_error, handle);
885 return;
886 }
887 resp = GNUNET_REST_create_response (result);
888 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
889 GNUNET_JSONAPI_document_delete (json_obj);
890 GNUNET_free (result);
891 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
892}
893
894
895static void
896namestore_zkey_cont (struct GNUNET_REST_RequestHandle *con,
897 const char *url,
898 void *cls)
899{
900 struct RequestHandle *handle = cls;
901 struct GNUNET_HashCode key;
902 struct GNUNET_CRYPTO_EcdsaPublicKey pubkey;
903
904 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_NAMESTORE_ZKEY,
905 strlen (GNUNET_REST_JSONAPI_NAMESTORE_ZKEY),
906 &key);
907 if ( GNUNET_NO ==
908 GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
909 &key) )
910 {
911 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
912 "No zkey given %s\n", handle->url);
913 GNUNET_SCHEDULER_add_now (&do_error, handle);
914 return;
915 }
916 handle->zkey_str = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map,
917 &key);
918 if ((NULL == handle->zkey_str) ||
919 (GNUNET_OK !=
920 GNUNET_CRYPTO_ecdsa_public_key_from_string (handle->zkey_str,
921 strlen (handle->zkey_str),
922 &pubkey)))
923 {
924 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
925 "Zkey invalid %s\n", handle->zkey_str);
926 GNUNET_SCHEDULER_add_now (&do_error, handle);
927 return;
928 }
929 handle->reverse_qe = GNUNET_NAMESTORE_zone_to_name (handle->ns_handle,
930 &handle->zone_pkey,
931 &pubkey,
932 &do_error,
933 handle,
934 &namestore_zkey_response,
935 handle);
936}
937
938
939static void
940namestore_info_cont (struct GNUNET_REST_RequestHandle *con,
941 const char *url,
942 void *cls)
943{
944 struct RequestHandle *handle = cls;
945
946 handle->list_it = GNUNET_NAMESTORE_zone_iteration_start (handle->ns_handle,
947 &handle->zone_pkey,
948 &do_error,
949 handle,
950 &namestore_list_response,
951 handle,
952 &namestore_list_finished,
953 handle);
954}
955
956
957static char*
958get_name_from_url (const char* url)
959{
960 if (strlen (url) <= strlen (GNUNET_REST_API_NS_NAMESTORE))
961 return NULL;
962 return (char*)url + strlen (GNUNET_REST_API_NS_NAMESTORE) + 1;
963}
964
965/**
966 * Respond to OPTIONS request
967 *
968 * @param con_handle the connection handle
969 * @param url the url
970 * @param cls the RequestHandle
971 */
972static void
973options_cont (struct GNUNET_REST_RequestHandle *con_handle,
974 const char* url,
975 void *cls)
976{
977 struct MHD_Response *resp;
978 struct RequestHandle *handle = cls;
979
980 //For now, independent of path return all options
981 resp = GNUNET_REST_create_response (NULL);
982 MHD_add_response_header (resp,
983 "Access-Control-Allow-Methods",
984 allow_methods);
985 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
986 cleanup_handle (handle);
987}
988
989
990/**
991 * Callback invoked from identity service with ego information.
992 * An @a ego of NULL means the ego was not found.
993 *
994 * @param cls closure with the configuration
995 * @param ego an ego known to identity service, or NULL
996 */
997static void
998identity_cb (void *cls,
999 const struct GNUNET_IDENTITY_Ego *ego)
1000{
1001 struct RequestHandle *handle = cls;
1002 struct MHD_Response *resp;
1003 struct GNUNET_REST_RequestHandlerError err;
1004 static const struct GNUNET_REST_RequestHandler handlers[] = {
1005 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_NAMESTORE_ZKEY, &namestore_zkey_cont}, //reverse
1006 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_NAMESTORE, &namestore_info_cont}, //list
1007 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_NAMESTORE, &namestore_create_cont}, //create
1008 // {MHD_HTTP_METHOD_PUT, GNUNET_REST_API_NS_NAMESTORE, &namestore_edit_cont}, //update. TODO this shoul be PATCH
1009 {MHD_HTTP_METHOD_DELETE, GNUNET_REST_API_NS_NAMESTORE, &namestore_delete_cont}, //delete
1010 {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_NAMESTORE, &options_cont},
1011 GNUNET_REST_HANDLER_END
1012 };
1013
1014 handle->ego_lookup = NULL;
1015 if (NULL == ego)
1016 {
1017 if (NULL != handle->ego_name)
1018 {
1019 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1020 _("Ego `%s' not known to identity service\n"),
1021 handle->ego_name);
1022 }
1023 resp = GNUNET_REST_create_response (NULL);
1024 handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
1025 cleanup_handle (handle);
1026 return;
1027 }
1028 handle->zone_pkey = *GNUNET_IDENTITY_ego_get_private_key (ego);
1029 handle->ns_handle = GNUNET_NAMESTORE_connect (cfg);
1030 if (NULL == handle->ns_handle)
1031 {
1032 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1033 _("Failed to connect to namestore\n"));
1034 GNUNET_SCHEDULER_add_now (&do_error, handle);
1035 return;
1036 }
1037
1038 if (GNUNET_OK !=
1039 GNUNET_JSONAPI_handle_request (handle->rest_handle,
1040 handlers,
1041 &err,
1042 handle))
1043 {
1044 handle->response_code = err.error_code;
1045 GNUNET_SCHEDULER_add_now (&do_error,
1046 (void *) handle);
1047 }
1048}
1049
1050
1051static void
1052default_ego_cb (void *cls,
1053 struct GNUNET_IDENTITY_Ego *ego,
1054 void **ctx,
1055 const char *name)
1056{
1057 struct RequestHandle *handle = cls;
1058 struct MHD_Response *resp;
1059 handle->get_default = NULL;
1060 if (NULL == ego)
1061 {
1062 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1063 _("No default ego configured in identity service\n"));
1064 resp = GNUNET_REST_create_response (NULL);
1065 handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
1066 cleanup_handle (handle);
1067 return;
1068 }
1069 else
1070 {
1071 identity_cb (cls, ego);
1072 }
1073}
1074
1075static void
1076id_connect_cb (void *cls,
1077 struct GNUNET_IDENTITY_Ego *ego,
1078 void **ctx,
1079 const char *name)
1080{
1081 struct RequestHandle *handle = cls;
1082 if (NULL == ego)
1083 {
1084 handle->get_default = GNUNET_IDENTITY_get (handle->identity_handle,
1085 "namestore",
1086 &default_ego_cb, handle);
1087 }
1088}
1089
1090
1091/**
1092 * Function processing the REST call
1093 *
1094 * @param method HTTP method
1095 * @param url URL of the HTTP request
1096 * @param data body of the HTTP request (optional)
1097 * @param data_size length of the body
1098 * @param proc callback function for the result
1099 * @param proc_cls closure for callback function
1100 * @return #GNUNET_OK if request accepted
1101 */
1102static void
1103rest_identity_process_request(struct GNUNET_REST_RequestHandle *rest_handle,
1104 GNUNET_REST_ResultProcessor proc,
1105 void *proc_cls)
1106{
1107 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
1108 struct MHD_Response *resp;
1109 struct GNUNET_HashCode key;
1110 char *ego;
1111 char *name;
1112 char *type;
1113
1114 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1115 handle->proc_cls = proc_cls;
1116 handle->proc = proc;
1117 handle->rest_handle = rest_handle;
1118 handle->url = GNUNET_strdup (rest_handle->url);
1119 if (handle->url[strlen (handle->url)-1] == '/')
1120 handle->url[strlen (handle->url)-1] = '\0';
1121 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1122 "Connecting...\n");
1123 handle->cfg = cfg;
1124 ego = NULL;
1125 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_NAMESTORE_EGO,
1126 strlen (GNUNET_REST_JSONAPI_NAMESTORE_EGO),
1127 &key);
1128 if ( GNUNET_YES ==
1129 GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1130 &key) )
1131 {
1132 ego = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map,
1133 &key);
1134 }
1135
1136 handle->type = GNUNET_GNSRECORD_TYPE_ANY;
1137 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE,
1138 strlen (GNUNET_REST_JSONAPI_NAMESTORE_RECORD_TYPE),
1139 &key);
1140 if ( GNUNET_YES ==
1141 GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1142 &key) )
1143 {
1144 type = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map,
1145 &key);
1146 if (NULL != type)
1147 handle->type = GNUNET_GNSRECORD_typename_to_number (type);
1148 }
1149 name = get_name_from_url (handle->url);
1150 if (NULL != ego)
1151 handle->ego_name = GNUNET_strdup (ego);
1152 if (NULL != name)
1153 handle->name = GNUNET_strdup (name);
1154 if (NULL == handle->ego_name)
1155 {
1156 handle->identity_handle = GNUNET_IDENTITY_connect (handle->cfg, &id_connect_cb, handle);
1157 if (NULL == handle->identity_handle)
1158 {
1159 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Cannot connect to identity service\n"));
1160 resp = GNUNET_REST_create_response (NULL);
1161 handle->proc (handle->proc_cls, resp, MHD_HTTP_NOT_FOUND);
1162 cleanup_handle (handle);
1163 }
1164 return;
1165 }
1166 handle->ego_lookup = GNUNET_IDENTITY_ego_lookup (cfg,
1167 handle->ego_name,
1168 &identity_cb,
1169 handle);
1170 handle->timeout_task = GNUNET_SCHEDULER_add_delayed (handle->timeout,
1171 &do_timeout,
1172 handle);
1173}
1174
1175/**
1176 * Entry point for the plugin.
1177 *
1178 * @param cls Config info
1179 * @return NULL on error, otherwise the plugin context
1180 */
1181void *
1182libgnunet_plugin_rest_namestore_init (void *cls)
1183{
1184 static struct Plugin plugin;
1185 cfg = cls;
1186 struct GNUNET_REST_Plugin *api;
1187
1188 if (NULL != plugin.cfg)
1189 return NULL; /* can only initialize once! */
1190 memset (&plugin, 0, sizeof (struct Plugin));
1191 plugin.cfg = cfg;
1192 api = GNUNET_new (struct GNUNET_REST_Plugin);
1193 api->cls = &plugin;
1194 api->name = GNUNET_REST_API_NS_NAMESTORE;
1195 api->process_request = &rest_identity_process_request;
1196 GNUNET_asprintf (&allow_methods,
1197 "%s, %s, %s, %s, %s",
1198 MHD_HTTP_METHOD_GET,
1199 MHD_HTTP_METHOD_POST,
1200 MHD_HTTP_METHOD_PUT,
1201 MHD_HTTP_METHOD_DELETE,
1202 MHD_HTTP_METHOD_OPTIONS);
1203 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1204 _("Namestore REST API initialized\n"));
1205 return api;
1206}
1207
1208
1209/**
1210 * Exit point from the plugin.
1211 *
1212 * @param cls the plugin context (as returned by "init")
1213 * @return always NULL
1214 */
1215void *
1216libgnunet_plugin_rest_namestore_done (void *cls)
1217{
1218 struct GNUNET_REST_Plugin *api = cls;
1219 struct Plugin *plugin = api->cls;
1220
1221 plugin->cfg = NULL;
1222 GNUNET_free (api);
1223 GNUNET_free_non_null (allow_methods);
1224 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1225 "Namestore REST plugin is finished\n");
1226 return NULL;
1227}
1228
1229/* end of plugin_rest_namestore.c */