aboutsummaryrefslogtreecommitdiff
path: root/src/lib/json
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/json')
-rw-r--r--src/lib/json/.gitignore2
-rw-r--r--src/lib/json/Makefile.am57
-rw-r--r--src/lib/json/json.c161
-rw-r--r--src/lib/json/json_generator.c207
-rw-r--r--src/lib/json/json_helper.c1611
-rw-r--r--src/lib/json/json_mhd.c379
-rw-r--r--src/lib/json/json_pack.c480
-rw-r--r--src/lib/json/meson.build44
-rw-r--r--src/lib/json/test_json.c247
-rw-r--r--src/lib/json/test_json_mhd.c193
10 files changed, 3381 insertions, 0 deletions
diff --git a/src/lib/json/.gitignore b/src/lib/json/.gitignore
new file mode 100644
index 000000000..347bffd7b
--- /dev/null
+++ b/src/lib/json/.gitignore
@@ -0,0 +1,2 @@
1test_json
2test_json_mhd
diff --git a/src/lib/json/Makefile.am b/src/lib/json/Makefile.am
new file mode 100644
index 000000000..c67824ee4
--- /dev/null
+++ b/src/lib/json/Makefile.am
@@ -0,0 +1,57 @@
1# This Makefile.am is in the public domain
2AM_CPPFLAGS = -I$(top_srcdir)/src/include
3
4if USE_COVERAGE
5 AM_CFLAGS = --coverage -O0
6 XLIB = -lgcov
7endif
8
9lib_LTLIBRARIES = \
10 libgnunetjson.la
11
12libgnunetjson_la_LDFLAGS = \
13 $(GN_LIBINTL) \
14 -version-info 0:0:0 \
15 -no-undefined
16libgnunetjson_la_CFLAGS = \
17 $(MHD_CFLAGS) \
18 $(AM_CFLAGS)
19libgnunetjson_la_SOURCES = \
20 json.c \
21 json_generator.c \
22 json_helper.c \
23 json_mhd.c \
24 json_pack.c
25libgnunetjson_la_LIBADD = \
26 $(top_builddir)/src/lib/util/libgnunetutil.la \
27 -ljansson \
28 $(MHD_LIBS) \
29 $(XLIB) \
30 $(Z_LIBS)
31
32check_PROGRAMS = \
33 test_json \
34 test_json_mhd
35
36TESTS = \
37 $(check_PROGRAMS)
38
39test_json_SOURCES = \
40 test_json.c
41test_json_CFLAGS = $(MHD_CFLAGS) $(AM_CFLAGS)
42test_json_LDADD = \
43 libgnunetjson.la \
44 $(top_builddir)/src/lib/util/libgnunetutil.la \
45 -ljansson
46
47
48test_json_mhd_SOURCES = \
49 test_json_mhd.c
50test_json_mhd_LDADD = \
51 libgnunetjson.la \
52 $(top_builddir)/src/lib/util/libgnunetutil.la \
53 -ljansson \
54 $(MHD_LIBS) \
55 $(Z_LIBS) \
56 @LIBCURL@
57test_json_mhd_CFLAGS = $(MHD_CFLAGS) @LIBCURL_CPPFLAGS@ $(AM_CFLAGS)
diff --git a/src/lib/json/json.c b/src/lib/json/json.c
new file mode 100644
index 000000000..07ec158be
--- /dev/null
+++ b/src/lib/json/json.c
@@ -0,0 +1,161 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2014-2017, 2021, 2022 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 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file json/json.c
22 * @brief functions to parse JSON snippets
23 * @author Florian Dold
24 * @author Benedikt Mueller
25 * @author Christian Grothoff
26 */
27#include "platform.h"
28#include "gnunet_json_lib.h"
29
30
31enum GNUNET_GenericReturnValue
32GNUNET_JSON_parse (const json_t *root,
33 struct GNUNET_JSON_Specification *spec,
34 const char **error_json_name,
35 unsigned int *error_line)
36{
37 if (NULL == root)
38 return GNUNET_SYSERR;
39 for (unsigned int i = 0; NULL != spec[i].parser; i++)
40 {
41 json_t *pos;
42
43 if (NULL == spec[i].field)
44 pos = (json_t *) root;
45 else
46 pos = json_object_get (root,
47 spec[i].field);
48 if ( ( (NULL == pos) ||
49 (json_is_null (pos) ) ) &&
50 (spec[i].is_optional) )
51 {
52 if (NULL != spec[i].missing)
53 *spec[i].missing = true;
54 continue;
55 }
56 if ( (NULL == pos) ||
57 (GNUNET_OK !=
58 spec[i].parser (spec[i].cls,
59 pos,
60 &spec[i])) )
61 {
62 if (NULL != error_json_name)
63 *error_json_name = spec[i].field;
64 else
65 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
66 "Parsing failed for field `%s:%u`\n",
67 spec[i].field,
68 i);
69 if (NULL != error_line)
70 *error_line = i;
71 GNUNET_JSON_parse_free (spec);
72 return GNUNET_SYSERR;
73 }
74 if (NULL != spec[i].missing)
75 *spec[i].missing = false;
76 }
77 return GNUNET_OK; /* all OK! */
78}
79
80
81struct GNUNET_JSON_Specification
82GNUNET_JSON_spec_mark_optional (struct GNUNET_JSON_Specification spec,
83 bool *missing)
84{
85 struct GNUNET_JSON_Specification ret = spec;
86
87 ret.is_optional = true;
88 ret.missing = missing;
89 return ret;
90}
91
92
93void
94GNUNET_JSON_parse_free (struct GNUNET_JSON_Specification *spec)
95{
96 for (unsigned int i = 0; NULL != spec[i].parser; i++)
97 if (NULL != spec[i].cleaner)
98 spec[i].cleaner (spec[i].cls,
99 &spec[i]);
100}
101
102
103/**
104 * Set an option with a JSON value from the command line.
105 * A pointer to this function should be passed as part of the
106 * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options
107 * of this type.
108 *
109 * @param ctx command line processing context
110 * @param scls additional closure (will point to the 'json_t *')
111 * @param option name of the option
112 * @param value actual value of the option as a string.
113 * @return #GNUNET_OK if parsing the value worked
114 */
115static enum GNUNET_GenericReturnValue
116set_json (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
117 void *scls,
118 const char *option,
119 const char *value)
120{
121 json_t **json = scls;
122 json_error_t error;
123
124 *json = json_loads (value,
125 JSON_REJECT_DUPLICATES,
126 &error);
127 if (NULL == *json)
128 {
129 fprintf (stderr,
130 _ ("Failed to parse JSON in option `%s': %s (%s)\n"),
131 option,
132 error.text,
133 error.source);
134 return GNUNET_SYSERR;
135 }
136 return GNUNET_OK;
137}
138
139
140struct GNUNET_GETOPT_CommandLineOption
141GNUNET_JSON_getopt (char shortName,
142 const char *name,
143 const char *argumentHelp,
144 const char *description,
145 json_t **json)
146{
147 struct GNUNET_GETOPT_CommandLineOption clo = {
148 .shortName = shortName,
149 .name = name,
150 .argumentHelp = argumentHelp,
151 .description = description,
152 .require_argument = 1,
153 .processor = &set_json,
154 .scls = (void *) json
155 };
156
157 return clo;
158}
159
160
161/* end of json.c */
diff --git a/src/lib/json/json_generator.c b/src/lib/json/json_generator.c
new file mode 100644
index 000000000..43b72ba57
--- /dev/null
+++ b/src/lib/json/json_generator.c
@@ -0,0 +1,207 @@
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 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file json/json_generator.c
22 * @brief helper functions for generating JSON from GNUnet data structures
23 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
24 */
25#include "platform.h"
26#include "gnunet_util_lib.h"
27#include "gnunet_json_lib.h"
28
29
30json_t *
31GNUNET_JSON_from_data (const void *data,
32 size_t size)
33{
34 char *buf;
35 json_t *json;
36
37 if (size >= ( (GNUNET_MAX_MALLOC_CHECKED - 1) * 5) - 4 / 8)
38 {
39 GNUNET_break (0);
40 return NULL;
41 }
42 buf = GNUNET_STRINGS_data_to_string_alloc (data,
43 size);
44 json = json_string (buf);
45 GNUNET_free (buf);
46 GNUNET_break (NULL != json);
47 return json;
48}
49
50
51json_t *
52GNUNET_JSON_from_data64 (const void *data,
53 size_t size)
54{
55 char *buf = NULL;
56 json_t *json;
57 size_t len;
58
59 if (size >= ( ( (GNUNET_MAX_MALLOC_CHECKED - 1) * 6) - 5) / 8)
60 {
61 GNUNET_break (0);
62 return NULL;
63 }
64 len = GNUNET_STRINGS_base64_encode (data,
65 size,
66 &buf);
67 if (NULL == buf)
68 {
69 GNUNET_break (0);
70 return NULL;
71 }
72 json = json_stringn (buf,
73 len);
74 GNUNET_free (buf);
75 GNUNET_break (NULL != json);
76 return json;
77}
78
79
80json_t *
81GNUNET_JSON_from_timestamp (struct GNUNET_TIME_Timestamp stamp)
82{
83 json_t *j;
84
85 j = json_object ();
86 if (NULL == j)
87 {
88 GNUNET_break (0);
89 return NULL;
90 }
91 if (GNUNET_TIME_absolute_is_never (stamp.abs_time))
92 {
93 if (0 !=
94 json_object_set_new (j,
95 "t_s",
96 json_string ("never")))
97 {
98 GNUNET_break (0);
99 json_decref (j);
100 return NULL;
101 }
102 return j;
103 }
104 GNUNET_assert (
105 0 ==
106 (stamp.abs_time.abs_value_us
107 % GNUNET_TIME_UNIT_SECONDS.rel_value_us));
108 if (0 !=
109 json_object_set_new (
110 j,
111 "t_s",
112 json_integer (
113 (json_int_t) (stamp.abs_time.abs_value_us
114 / GNUNET_TIME_UNIT_SECONDS.rel_value_us))))
115 {
116 GNUNET_break (0);
117 json_decref (j);
118 return NULL;
119 }
120 return j;
121}
122
123
124json_t *
125GNUNET_JSON_from_timestamp_nbo (struct GNUNET_TIME_TimestampNBO stamp)
126{
127 return GNUNET_JSON_from_timestamp (GNUNET_TIME_timestamp_ntoh (stamp));
128}
129
130
131json_t *
132GNUNET_JSON_from_time_rel (struct GNUNET_TIME_Relative stamp)
133{
134 json_t *j;
135
136 j = json_object ();
137 if (NULL == j)
138 {
139 GNUNET_break (0);
140 return NULL;
141 }
142 if (GNUNET_TIME_relative_is_forever (stamp))
143 {
144 if (0 !=
145 json_object_set_new (j,
146 "d_us",
147 json_string ("forever")))
148 {
149 GNUNET_break (0);
150 json_decref (j);
151 return NULL;
152 }
153 return j;
154 }
155 if (stamp.rel_value_us >= (1LLU << 53))
156 {
157 /* value is larger than allowed */
158 GNUNET_break (0);
159 return NULL;
160 }
161 if (0 !=
162 json_object_set_new (
163 j,
164 "d_us",
165 json_integer ((json_int_t) stamp.rel_value_us)))
166 {
167 GNUNET_break (0);
168 json_decref (j);
169 return NULL;
170 }
171 return j;
172}
173
174
175json_t *
176GNUNET_JSON_from_rsa_public_key (const struct GNUNET_CRYPTO_RsaPublicKey *pk)
177{
178 void *buf;
179 size_t buf_len;
180 json_t *ret;
181
182 buf_len = GNUNET_CRYPTO_rsa_public_key_encode (pk,
183 &buf);
184 ret = GNUNET_JSON_from_data (buf,
185 buf_len);
186 GNUNET_free (buf);
187 return ret;
188}
189
190
191json_t *
192GNUNET_JSON_from_rsa_signature (const struct GNUNET_CRYPTO_RsaSignature *sig)
193{
194 void *buf;
195 size_t buf_len;
196 json_t *ret;
197
198 buf_len = GNUNET_CRYPTO_rsa_signature_encode (sig,
199 &buf);
200 ret = GNUNET_JSON_from_data (buf,
201 buf_len);
202 GNUNET_free (buf);
203 return ret;
204}
205
206
207/* End of json/json_generator.c */
diff --git a/src/lib/json/json_helper.c b/src/lib/json/json_helper.c
new file mode 100644
index 000000000..5c2f8ae05
--- /dev/null
+++ b/src/lib/json/json_helper.c
@@ -0,0 +1,1611 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2014-2022 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 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file json/json_helper.c
22 * @brief functions to generate specifciations for JSON parsing
23 * @author Florian Dold
24 * @author Benedikt Mueller
25 * @author Christian Grothoff
26 */
27#include "platform.h"
28#include "gnunet_json_lib.h"
29#include "gnunet_common.h"
30
31
32struct GNUNET_JSON_Specification
33GNUNET_JSON_spec_end ()
34{
35 struct GNUNET_JSON_Specification ret = {
36 .parser = NULL,
37 .cleaner = NULL,
38 .cls = NULL
39 };
40
41 return ret;
42}
43
44
45/**
46 * Convert string value to numeric cipher value.
47 *
48 * @param cipher_s input string
49 * @return numeric cipher value
50 */
51static enum GNUNET_CRYPTO_BlindSignatureAlgorithm
52string_to_cipher (const char *cipher_s)
53{
54 if ((0 == strcasecmp (cipher_s,
55 "RSA")) ||
56 (0 == strcasecmp (cipher_s,
57 "RSA+age_restricted")))
58 return GNUNET_CRYPTO_BSA_RSA;
59 if ((0 == strcasecmp (cipher_s,
60 "CS")) ||
61 (0 == strcasecmp (cipher_s,
62 "CS+age_restricted")))
63 return GNUNET_CRYPTO_BSA_CS;
64 return GNUNET_CRYPTO_BSA_INVALID;
65}
66
67
68/**
69 * Parse given JSON object to fixed size data
70 *
71 * @param cls closure, NULL
72 * @param root the json object representing data
73 * @param[out] spec where to write the data
74 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
75 */
76static enum GNUNET_GenericReturnValue
77parse_fixed_data (void *cls,
78 json_t *root,
79 struct GNUNET_JSON_Specification *spec)
80{
81 const char *enc;
82 size_t len;
83
84 if (NULL == (enc = json_string_value (root)))
85 {
86 GNUNET_break_op (0);
87 return GNUNET_SYSERR;
88 }
89 len = strlen (enc);
90 if (len >= SIZE_MAX / 5)
91 {
92 GNUNET_break_op (0);
93 return GNUNET_SYSERR;
94 }
95 if (((len * 5) / 8) != spec->ptr_size)
96 {
97 GNUNET_break_op (0);
98 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
99 "Field `%s' has wrong length\n",
100 spec->field);
101 return GNUNET_SYSERR;
102 }
103 if (GNUNET_OK !=
104 GNUNET_STRINGS_string_to_data (enc,
105 len,
106 spec->ptr,
107 spec->ptr_size))
108 {
109 GNUNET_break_op (0);
110 return GNUNET_SYSERR;
111 }
112 return GNUNET_OK;
113}
114
115
116struct GNUNET_JSON_Specification
117GNUNET_JSON_spec_fixed (const char *name,
118 void *obj,
119 size_t size)
120{
121 struct GNUNET_JSON_Specification ret = {
122 .parser = &parse_fixed_data,
123 .cleaner = NULL,
124 .cls = NULL,
125 .field = name,
126 .ptr = obj,
127 .ptr_size = size,
128 .size_ptr = NULL
129 };
130
131 return ret;
132}
133
134
135/**
136 * Parse given JSON object to fixed size data
137 *
138 * @param cls closure, NULL
139 * @param root the json object representing data
140 * @param[out] spec where to write the data
141 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
142 */
143static enum GNUNET_GenericReturnValue
144parse_fixed64_data (void *cls,
145 json_t *root,
146 struct GNUNET_JSON_Specification *spec)
147{
148 const char *enc;
149 unsigned int len;
150 void *output;
151 size_t olen;
152
153 if (NULL == (enc = json_string_value (root)))
154 {
155 GNUNET_break_op (0);
156 return GNUNET_SYSERR;
157 }
158 len = strlen (enc);
159 output = NULL;
160 olen = GNUNET_STRINGS_base64_decode (enc,
161 len,
162 &output);
163 if (olen != spec->ptr_size)
164 {
165 GNUNET_break_op (0);
166 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
167 "Field `%s' has wrong length\n",
168 spec->field);
169 GNUNET_free (output);
170 return GNUNET_SYSERR;
171 }
172 memcpy (spec->ptr,
173 output,
174 olen);
175 GNUNET_free (output);
176 return GNUNET_OK;
177}
178
179
180struct GNUNET_JSON_Specification
181GNUNET_JSON_spec_fixed64 (const char *name,
182 void *obj,
183 size_t size)
184{
185 struct GNUNET_JSON_Specification ret = {
186 .parser = &parse_fixed64_data,
187 .cleaner = NULL,
188 .cls = NULL,
189 .field = name,
190 .ptr = obj,
191 .ptr_size = size,
192 .size_ptr = NULL
193 };
194
195 return ret;
196}
197
198
199/**
200 * Parse given JSON object to variable size data
201 *
202 * @param cls closure, NULL
203 * @param root the json object representing data
204 * @param[out] spec where to write the data
205 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
206 */
207static enum GNUNET_GenericReturnValue
208parse_variable_data (void *cls,
209 json_t *root,
210 struct GNUNET_JSON_Specification *spec)
211{
212 const char *str;
213 size_t size;
214 void *data;
215
216 str = json_string_value (root);
217 if (NULL == str)
218 {
219 GNUNET_break_op (0);
220 return GNUNET_SYSERR;
221 }
222 if (GNUNET_OK !=
223 GNUNET_STRINGS_string_to_data_alloc (str,
224 strlen (str),
225 &data,
226 &size))
227 {
228 GNUNET_break_op (0);
229 return GNUNET_SYSERR;
230 }
231 *(void **) spec->ptr = data;
232 *spec->size_ptr = size;
233 return GNUNET_OK;
234}
235
236
237/**
238 * Cleanup data left from parsing variable size data
239 *
240 * @param cls closure, NULL
241 * @param[out] spec where to free the data
242 */
243static void
244clean_variable_data (void *cls,
245 struct GNUNET_JSON_Specification *spec)
246{
247 (void) cls;
248 if (0 != *spec->size_ptr)
249 {
250 GNUNET_free (*(void **) spec->ptr);
251 *(void **) spec->ptr = NULL;
252 *spec->size_ptr = 0;
253 }
254}
255
256
257struct GNUNET_JSON_Specification
258GNUNET_JSON_spec_varsize (const char *name,
259 void **obj,
260 size_t *size)
261{
262 struct GNUNET_JSON_Specification ret = {
263 .parser = &parse_variable_data,
264 .cleaner = &clean_variable_data,
265 .cls = NULL,
266 .field = name,
267 .ptr = obj,
268 .ptr_size = 0,
269 .size_ptr = size
270 };
271
272 *obj = NULL;
273 *size = 0;
274 return ret;
275}
276
277
278/**
279 * Parse given JSON object to string.
280 *
281 * @param cls closure, NULL
282 * @param root the json object representing data
283 * @param[out] spec where to write the data
284 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
285 */
286static enum GNUNET_GenericReturnValue
287parse_string (void *cls,
288 json_t *root,
289 struct GNUNET_JSON_Specification *spec)
290{
291 const char *str;
292
293 (void) cls;
294 str = json_string_value (root);
295 if (NULL == str)
296 {
297 GNUNET_break_op (0);
298 return GNUNET_SYSERR;
299 }
300 *(const char **) spec->ptr = str;
301 return GNUNET_OK;
302}
303
304
305struct GNUNET_JSON_Specification
306GNUNET_JSON_spec_string (const char *name,
307 const char **strptr)
308{
309 struct GNUNET_JSON_Specification ret = {
310 .parser = &parse_string,
311 .field = name,
312 .ptr = strptr
313 };
314
315 *strptr = NULL;
316 return ret;
317}
318
319
320/**
321 * Parse given JSON object to a JSON object. (Yes, trivial.)
322 *
323 * @param cls closure, NULL
324 * @param root the json object representing data
325 * @param[out] spec where to write the data
326 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
327 */
328static enum GNUNET_GenericReturnValue
329parse_json (void *cls,
330 json_t *root,
331 struct GNUNET_JSON_Specification *spec)
332{
333 if (! (json_is_object (root) || json_is_array (root)))
334 {
335 GNUNET_break_op (0);
336 return GNUNET_SYSERR;
337 }
338 json_incref (root);
339 *(json_t **) spec->ptr = root;
340 return GNUNET_OK;
341}
342
343
344/**
345 * Cleanup data left from parsing JSON object.
346 *
347 * @param cls closure, NULL
348 * @param[out] spec where to free the data
349 */
350static void
351clean_json (void *cls,
352 struct GNUNET_JSON_Specification *spec)
353{
354 json_t **ptr = (json_t **) spec->ptr;
355
356 if (NULL != *ptr)
357 {
358 json_decref (*ptr);
359 *ptr = NULL;
360 }
361}
362
363
364struct GNUNET_JSON_Specification
365GNUNET_JSON_spec_json (const char *name,
366 json_t **jsonp)
367{
368 struct GNUNET_JSON_Specification ret = {
369 .parser = &parse_json,
370 .cleaner = &clean_json,
371 .cls = NULL,
372 .field = name,
373 .ptr = jsonp,
374 .ptr_size = 0,
375 .size_ptr = NULL
376 };
377
378 *jsonp = NULL;
379 return ret;
380}
381
382
383/**
384 * Parse given JSON object to a JSON object.
385 *
386 * @param cls closure, NULL
387 * @param root the json object representing data
388 * @param[out] spec where to write the data
389 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
390 */
391static enum GNUNET_GenericReturnValue
392parse_object_const (void *cls,
393 json_t *root,
394 struct GNUNET_JSON_Specification *spec)
395{
396 if (NULL == root)
397 return GNUNET_OK;
398 if (! json_is_object (root))
399 {
400 GNUNET_break_op (0);
401 return GNUNET_SYSERR;
402 }
403 *(const json_t **) spec->ptr = (const json_t *) root;
404 return GNUNET_OK;
405}
406
407
408struct GNUNET_JSON_Specification
409GNUNET_JSON_spec_object_const (const char *name,
410 const json_t **jsonp)
411{
412 struct GNUNET_JSON_Specification ret = {
413 .parser = &parse_object_const,
414 .cls = NULL,
415 .field = name,
416 .ptr = jsonp,
417 .ptr_size = 0,
418 .size_ptr = NULL
419 };
420
421 *jsonp = NULL;
422 return ret;
423}
424
425
426/**
427 * Parse given JSON to a JSON array.
428 *
429 * @param cls closure, NULL
430 * @param root the json object representing data
431 * @param[out] spec where to write the data
432 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
433 */
434static enum GNUNET_GenericReturnValue
435parse_array_const (void *cls,
436 json_t *root,
437 struct GNUNET_JSON_Specification *spec)
438{
439 if (NULL == root)
440 return GNUNET_OK;
441 if (! json_is_array (root))
442 {
443 GNUNET_break_op (0);
444 return GNUNET_SYSERR;
445 }
446 *(const json_t **) spec->ptr = (const json_t *) root;
447 return GNUNET_OK;
448}
449
450
451struct GNUNET_JSON_Specification
452GNUNET_JSON_spec_array_const (const char *name,
453 const json_t **jsonp)
454{
455 struct GNUNET_JSON_Specification ret = {
456 .parser = &parse_array_const,
457 .cls = NULL,
458 .field = name,
459 .ptr = jsonp,
460 .ptr_size = 0,
461 .size_ptr = NULL
462 };
463
464 *jsonp = NULL;
465 return ret;
466}
467
468
469/**
470 * Parse given JSON object to a bool.
471 *
472 * @param cls closure, NULL
473 * @param root the json object representing data
474 * @param[out] spec where to write the data
475 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
476 */
477static enum GNUNET_GenericReturnValue
478parse_bool (void *cls,
479 json_t *root,
480 struct GNUNET_JSON_Specification *spec)
481{
482 bool *b = spec->ptr;
483
484 if (json_true () == root)
485 {
486 *b = true;
487 return GNUNET_OK;
488 }
489 if (json_false () == root)
490 {
491 *b = false;
492 return GNUNET_OK;
493 }
494 GNUNET_break_op (0);
495 return GNUNET_SYSERR;
496}
497
498
499struct GNUNET_JSON_Specification
500GNUNET_JSON_spec_bool (const char *name,
501 bool *b)
502{
503 struct GNUNET_JSON_Specification ret = {
504 .parser = &parse_bool,
505 .cleaner = NULL,
506 .cls = NULL,
507 .field = name,
508 .ptr = b,
509 .ptr_size = sizeof(bool),
510 .size_ptr = NULL
511 };
512
513 return ret;
514}
515
516
517/**
518 * Parse given JSON object to a double.
519 *
520 * @param cls closure, NULL
521 * @param root the json object representing data
522 * @param[out] spec where to write the data
523 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
524 */
525static enum GNUNET_GenericReturnValue
526parse_double (void *cls,
527 json_t *root,
528 struct GNUNET_JSON_Specification *spec)
529{
530 double *f = spec->ptr;
531
532 if (! json_is_real (root))
533 {
534 GNUNET_break_op (0);
535 return GNUNET_SYSERR;
536 }
537 *f = json_real_value (root);
538 return GNUNET_OK;
539}
540
541
542struct GNUNET_JSON_Specification
543GNUNET_JSON_spec_double (const char *name,
544 double *f)
545{
546 struct GNUNET_JSON_Specification ret = {
547 .parser = &parse_double,
548 .cleaner = NULL,
549 .cls = NULL,
550 .field = name,
551 .ptr = f,
552 .ptr_size = sizeof(double),
553 .size_ptr = NULL
554 };
555
556 return ret;
557}
558
559
560/**
561 * Parse given JSON object to a uint8_t.
562 *
563 * @param cls closure, NULL
564 * @param root the json object representing data
565 * @param[out] spec where to write the data
566 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
567 */
568static enum GNUNET_GenericReturnValue
569parse_u8 (void *cls,
570 json_t *root,
571 struct GNUNET_JSON_Specification *spec)
572{
573 json_int_t val;
574 uint8_t *up = spec->ptr;
575
576 if (! json_is_integer (root))
577 {
578 GNUNET_break_op (0);
579 return GNUNET_SYSERR;
580 }
581 val = json_integer_value (root);
582 if ((0 > val) || (val > UINT8_MAX))
583 {
584 GNUNET_break_op (0);
585 return GNUNET_SYSERR;
586 }
587 *up = (uint8_t) val;
588 return GNUNET_OK;
589}
590
591
592struct GNUNET_JSON_Specification
593GNUNET_JSON_spec_uint8 (const char *name,
594 uint8_t *u8)
595{
596 struct GNUNET_JSON_Specification ret = {
597 .parser = &parse_u8,
598 .cleaner = NULL,
599 .cls = NULL,
600 .field = name,
601 .ptr = u8,
602 .ptr_size = sizeof(uint8_t),
603 .size_ptr = NULL
604 };
605
606 return ret;
607}
608
609
610/**
611 * Parse given JSON object to a uint16_t.
612 *
613 * @param cls closure, NULL
614 * @param root the json object representing data
615 * @param[out] spec where to write the data
616 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
617 */
618static enum GNUNET_GenericReturnValue
619parse_u16 (void *cls,
620 json_t *root,
621 struct GNUNET_JSON_Specification *spec)
622{
623 json_int_t val;
624 uint16_t *up = spec->ptr;
625
626 if (! json_is_integer (root))
627 {
628 GNUNET_break_op (0);
629 return GNUNET_SYSERR;
630 }
631 val = json_integer_value (root);
632 if ((0 > val) || (val > UINT16_MAX))
633 {
634 GNUNET_break_op (0);
635 return GNUNET_SYSERR;
636 }
637 *up = (uint16_t) val;
638 return GNUNET_OK;
639}
640
641
642struct GNUNET_JSON_Specification
643GNUNET_JSON_spec_uint16 (const char *name,
644 uint16_t *u16)
645{
646 struct GNUNET_JSON_Specification ret = {
647 .parser = &parse_u16,
648 .cleaner = NULL,
649 .cls = NULL,
650 .field = name,
651 .ptr = u16,
652 .ptr_size = sizeof(uint16_t),
653 .size_ptr = NULL
654 };
655
656 return ret;
657}
658
659
660/**
661 * Parse given JSON object to a uint32_t.
662 *
663 * @param cls closure, NULL
664 * @param root the json object representing data
665 * @param[out] spec where to write the data
666 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
667 */
668static enum GNUNET_GenericReturnValue
669parse_u32 (void *cls,
670 json_t *root,
671 struct GNUNET_JSON_Specification *spec)
672{
673 json_int_t val;
674 uint32_t *up = spec->ptr;
675
676 if (! json_is_integer (root))
677 {
678 GNUNET_break_op (0);
679 return GNUNET_SYSERR;
680 }
681 val = json_integer_value (root);
682 if ((0 > val) || (val > UINT32_MAX))
683 {
684 GNUNET_break_op (0);
685 return GNUNET_SYSERR;
686 }
687 *up = (uint32_t) val;
688 return GNUNET_OK;
689}
690
691
692struct GNUNET_JSON_Specification
693GNUNET_JSON_spec_uint32 (const char *name,
694 uint32_t *u32)
695{
696 struct GNUNET_JSON_Specification ret = {
697 .parser = &parse_u32,
698 .cleaner = NULL,
699 .cls = NULL,
700 .field = name,
701 .ptr = u32,
702 .ptr_size = sizeof(uint32_t),
703 .size_ptr = NULL
704 };
705
706 return ret;
707}
708
709
710/**
711 * Parse given JSON object to a uint64_t.
712 *
713 * @param cls closure, NULL
714 * @param root the json object representing data
715 * @param[out] spec where to write the data
716 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
717 */
718static enum GNUNET_GenericReturnValue
719parse_u64 (void *cls,
720 json_t *root,
721 struct GNUNET_JSON_Specification *spec)
722{
723 json_int_t val;
724 uint64_t *up = spec->ptr;
725
726 if (! json_is_integer (root))
727 {
728 GNUNET_break_op (0);
729 return GNUNET_SYSERR;
730 }
731 val = json_integer_value (root);
732 *up = (uint64_t) val;
733 return GNUNET_OK;
734}
735
736
737struct GNUNET_JSON_Specification
738GNUNET_JSON_spec_uint64 (const char *name,
739 uint64_t *u64)
740{
741 struct GNUNET_JSON_Specification ret = {
742 .parser = &parse_u64,
743 .cleaner = NULL,
744 .cls = NULL,
745 .field = name,
746 .ptr = u64,
747 .ptr_size = sizeof(uint64_t),
748 .size_ptr = NULL
749 };
750
751 return ret;
752}
753
754
755/**
756 * Parse given JSON object to a int64_t.
757 *
758 * @param cls closure, NULL
759 * @param root the json object representing data
760 * @param[out] spec where to write the data
761 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
762 */
763static enum GNUNET_GenericReturnValue
764parse_i64 (void *cls,
765 json_t *root,
766 struct GNUNET_JSON_Specification *spec)
767{
768 json_int_t val;
769 int64_t *up = spec->ptr;
770
771 if (! json_is_integer (root))
772 {
773 GNUNET_break_op (0);
774 return GNUNET_SYSERR;
775 }
776 val = json_integer_value (root);
777 *up = (int64_t) val;
778 return GNUNET_OK;
779}
780
781
782struct GNUNET_JSON_Specification
783GNUNET_JSON_spec_int64 (const char *name,
784 int64_t *i64)
785{
786 struct GNUNET_JSON_Specification ret = {
787 .parser = &parse_i64,
788 .cleaner = NULL,
789 .cls = NULL,
790 .field = name,
791 .ptr = i64,
792 .ptr_size = sizeof(int64_t),
793 .size_ptr = NULL
794 };
795
796 return ret;
797}
798
799
800/* ************ GNUnet-specific parser specifications ******************* */
801
802/**
803 * Parse given JSON object to a timestamp.
804 *
805 * @param cls closure, NULL
806 * @param root the json object representing data
807 * @param[out] spec where to write the data
808 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
809 */
810static enum GNUNET_GenericReturnValue
811parse_timestamp (void *cls,
812 json_t *root,
813 struct GNUNET_JSON_Specification *spec)
814{
815 struct GNUNET_TIME_Timestamp *ts = spec->ptr;
816 json_t *json_t_s;
817 unsigned long long int tval;
818
819 if (! json_is_object (root))
820 {
821 GNUNET_break_op (0);
822 return GNUNET_SYSERR;
823 }
824 json_t_s = json_object_get (root,
825 "t_s");
826 if (json_is_integer (json_t_s))
827 {
828 tval = json_integer_value (json_t_s);
829 /* Time is in seconds in JSON, but in microseconds in GNUNET_TIME_Absolute */
830 ts->abs_time.abs_value_us
831 = tval * GNUNET_TIME_UNIT_SECONDS.rel_value_us;
832 if (ts->abs_time.abs_value_us
833 / GNUNET_TIME_UNIT_SECONDS.rel_value_us
834 != tval)
835 {
836 /* Integer overflow */
837 GNUNET_break_op (0);
838 return GNUNET_SYSERR;
839 }
840 return GNUNET_OK;
841 }
842 if (json_is_string (json_t_s))
843 {
844 const char *val;
845
846 val = json_string_value (json_t_s);
847 if ((0 == strcasecmp (val,
848 "never")))
849 {
850 ts->abs_time = GNUNET_TIME_UNIT_FOREVER_ABS;
851 return GNUNET_OK;
852 }
853 GNUNET_break_op (0);
854 return GNUNET_SYSERR;
855 }
856 GNUNET_break_op (0);
857 return GNUNET_SYSERR;
858}
859
860
861struct GNUNET_JSON_Specification
862GNUNET_JSON_spec_timestamp (const char *name,
863 struct GNUNET_TIME_Timestamp *t)
864{
865 struct GNUNET_JSON_Specification ret = {
866 .parser = &parse_timestamp,
867 .field = name,
868 .ptr = t,
869 .ptr_size = sizeof(struct GNUNET_TIME_Timestamp)
870 };
871
872 return ret;
873}
874
875
876/**
877 * Parse given JSON object to absolute time.
878 *
879 * @param cls closure, NULL
880 * @param root the json object representing data
881 * @param[out] spec where to write the data
882 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
883 */
884static enum GNUNET_GenericReturnValue
885parse_timestamp_nbo (void *cls,
886 json_t *root,
887 struct GNUNET_JSON_Specification *spec)
888{
889 struct GNUNET_TIME_TimestampNBO *ts = spec->ptr;
890 struct GNUNET_TIME_Timestamp a;
891 struct GNUNET_JSON_Specification ispec;
892
893 ispec = *spec;
894 ispec.parser = &parse_timestamp;
895 ispec.ptr = &a;
896 if (GNUNET_OK !=
897 parse_timestamp (NULL,
898 root,
899 &ispec))
900 return GNUNET_SYSERR;
901 *ts = GNUNET_TIME_timestamp_hton (a);
902 return GNUNET_OK;
903}
904
905
906struct GNUNET_JSON_Specification
907GNUNET_JSON_spec_timestamp_nbo (const char *name,
908 struct GNUNET_TIME_TimestampNBO *at)
909{
910 struct GNUNET_JSON_Specification ret = {
911 .parser = &parse_timestamp_nbo,
912 .field = name,
913 .ptr = at,
914 .ptr_size = sizeof(struct GNUNET_TIME_TimestampNBO)
915 };
916
917 return ret;
918}
919
920
921/**
922 * Parse given JSON object to relative time.
923 *
924 * @param cls closure, NULL
925 * @param root the json object representing data
926 * @param[out] spec where to write the data
927 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
928 */
929static enum GNUNET_GenericReturnValue
930parse_rel_time (void *cls,
931 json_t *root,
932 struct GNUNET_JSON_Specification *spec)
933{
934 struct GNUNET_TIME_Relative *rel = spec->ptr;
935 json_t *json_d_us;
936 unsigned long long int tval;
937
938 if (! json_is_object (root))
939 {
940 GNUNET_break_op (0);
941 return GNUNET_SYSERR;
942 }
943 json_d_us = json_object_get (root,
944 "d_us");
945 if (json_is_integer (json_d_us))
946 {
947 tval = json_integer_value (json_d_us);
948 if (tval >= (1LLU << 53))
949 {
950 /* value is larger than allowed */
951 GNUNET_break_op (0);
952 return GNUNET_SYSERR;
953 }
954 rel->rel_value_us = tval;
955 return GNUNET_OK;
956 }
957 if (json_is_string (json_d_us))
958 {
959 const char *val;
960
961 val = json_string_value (json_d_us);
962 if ((0 == strcasecmp (val,
963 "forever")))
964 {
965 *rel = GNUNET_TIME_UNIT_FOREVER_REL;
966 return GNUNET_OK;
967 }
968 GNUNET_break_op (0);
969 return GNUNET_SYSERR;
970 }
971 GNUNET_break_op (0);
972 return GNUNET_SYSERR;
973}
974
975
976struct GNUNET_JSON_Specification
977GNUNET_JSON_spec_relative_time (const char *name,
978 struct GNUNET_TIME_Relative *rt)
979{
980 struct GNUNET_JSON_Specification ret = {
981 .parser = &parse_rel_time,
982 .field = name,
983 .ptr = rt,
984 .ptr_size = sizeof(struct GNUNET_TIME_Relative)
985 };
986
987 return ret;
988}
989
990
991/**
992 * Parse given JSON object to RSA public key.
993 *
994 * @param cls closure, NULL
995 * @param root the json object representing data
996 * @param[out] spec where to write the data
997 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
998 */
999static enum GNUNET_GenericReturnValue
1000parse_rsa_public_key (void *cls,
1001 json_t *root,
1002 struct GNUNET_JSON_Specification *spec)
1003{
1004 struct GNUNET_CRYPTO_RsaPublicKey **pk = spec->ptr;
1005 const char *enc;
1006 char *buf;
1007 size_t len;
1008 size_t buf_len;
1009
1010 if (NULL == (enc = json_string_value (root)))
1011 {
1012 GNUNET_break_op (0);
1013 return GNUNET_SYSERR;
1014 }
1015 len = strlen (enc);
1016 buf_len = (len * 5) / 8;
1017 buf = GNUNET_malloc (buf_len);
1018 if (GNUNET_OK !=
1019 GNUNET_STRINGS_string_to_data (enc,
1020 len,
1021 buf,
1022 buf_len))
1023 {
1024 GNUNET_break_op (0);
1025 GNUNET_free (buf);
1026 return GNUNET_SYSERR;
1027 }
1028 if (NULL == (*pk = GNUNET_CRYPTO_rsa_public_key_decode (buf,
1029 buf_len)))
1030 {
1031 GNUNET_break_op (0);
1032 GNUNET_free (buf);
1033 return GNUNET_SYSERR;
1034 }
1035 GNUNET_free (buf);
1036 return GNUNET_OK;
1037}
1038
1039
1040/**
1041 * Cleanup data left from parsing RSA public key.
1042 *
1043 * @param cls closure, NULL
1044 * @param[out] spec where to free the data
1045 */
1046static void
1047clean_rsa_public_key (void *cls,
1048 struct GNUNET_JSON_Specification *spec)
1049{
1050 struct GNUNET_CRYPTO_RsaPublicKey **pk = spec->ptr;
1051
1052 if (NULL != *pk)
1053 {
1054 GNUNET_CRYPTO_rsa_public_key_free (*pk);
1055 *pk = NULL;
1056 }
1057}
1058
1059
1060struct GNUNET_JSON_Specification
1061GNUNET_JSON_spec_rsa_public_key (const char *name,
1062 struct GNUNET_CRYPTO_RsaPublicKey **pk)
1063{
1064 struct GNUNET_JSON_Specification ret = {
1065 .parser = &parse_rsa_public_key,
1066 .cleaner = &clean_rsa_public_key,
1067 .field = name,
1068 .ptr = pk
1069 };
1070
1071 *pk = NULL;
1072 return ret;
1073}
1074
1075
1076/**
1077 * Parse given JSON object to RSA signature.
1078 *
1079 * @param cls closure, NULL
1080 * @param root the json object representing data
1081 * @param[out] spec where to write the data
1082 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
1083 */
1084static enum GNUNET_GenericReturnValue
1085parse_rsa_signature (void *cls,
1086 json_t *root,
1087 struct GNUNET_JSON_Specification *spec)
1088{
1089 struct GNUNET_CRYPTO_RsaSignature **sig = spec->ptr;
1090 size_t size;
1091 const char *str;
1092 int res;
1093 void *buf;
1094
1095 str = json_string_value (root);
1096 if (NULL == str)
1097 {
1098 GNUNET_break_op (0);
1099 return GNUNET_SYSERR;
1100 }
1101 size = (strlen (str) * 5) / 8;
1102 buf = GNUNET_malloc (size);
1103 res = GNUNET_STRINGS_string_to_data (str,
1104 strlen (str),
1105 buf,
1106 size);
1107 if (GNUNET_OK != res)
1108 {
1109 GNUNET_free (buf);
1110 GNUNET_break_op (0);
1111 return GNUNET_SYSERR;
1112 }
1113 if (NULL == (*sig = GNUNET_CRYPTO_rsa_signature_decode (buf,
1114 size)))
1115 {
1116 GNUNET_break_op (0);
1117 GNUNET_free (buf);
1118 return GNUNET_SYSERR;
1119 }
1120 GNUNET_free (buf);
1121 return GNUNET_OK;
1122}
1123
1124
1125/**
1126 * Cleanup data left from parsing RSA signature.
1127 *
1128 * @param cls closure, NULL
1129 * @param[out] spec where to free the data
1130 */
1131static void
1132clean_rsa_signature (void *cls,
1133 struct GNUNET_JSON_Specification *spec)
1134{
1135 struct GNUNET_CRYPTO_RsaSignature **sig = spec->ptr;
1136
1137 if (NULL != *sig)
1138 {
1139 GNUNET_CRYPTO_rsa_signature_free (*sig);
1140 *sig = NULL;
1141 }
1142}
1143
1144
1145struct GNUNET_JSON_Specification
1146GNUNET_JSON_spec_rsa_signature (const char *name,
1147 struct GNUNET_CRYPTO_RsaSignature **sig)
1148{
1149 struct GNUNET_JSON_Specification ret = {
1150 .parser = &parse_rsa_signature,
1151 .cleaner = &clean_rsa_signature,
1152 .cls = NULL,
1153 .field = name,
1154 .ptr = sig,
1155 .ptr_size = 0,
1156 .size_ptr = NULL
1157 };
1158
1159 *sig = NULL;
1160 return ret;
1161}
1162
1163
1164/**
1165 * Parse given JSON object to an int as a boolean.
1166 *
1167 * @param cls closure, NULL
1168 * @param root the json object representing data
1169 * @param[out] spec where to write the data
1170 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
1171 */
1172static enum GNUNET_GenericReturnValue
1173parse_boolean (void *cls,
1174 json_t *root,
1175 struct GNUNET_JSON_Specification *spec)
1176{
1177 int *bp = spec->ptr;
1178
1179 if (! json_is_boolean (root))
1180 {
1181 GNUNET_break_op (0);
1182 return GNUNET_SYSERR;
1183 }
1184 *bp = json_boolean_value (root) ? GNUNET_YES : GNUNET_NO;
1185 return GNUNET_OK;
1186}
1187
1188
1189struct GNUNET_JSON_Specification
1190GNUNET_JSON_spec_boolean (const char *name,
1191 int *boolean)
1192{
1193 struct GNUNET_JSON_Specification ret = {
1194 .parser = &parse_boolean,
1195 .cleaner = NULL,
1196 .cls = NULL,
1197 .field = name,
1198 .ptr = boolean,
1199 .ptr_size = sizeof(int),
1200 .size_ptr = NULL
1201 };
1202
1203 return ret;
1204}
1205
1206
1207/**
1208 * Parse given JSON object to a blinded message.
1209 *
1210 * @param cls closure, NULL
1211 * @param root the json object representing data
1212 * @param[out] spec where to write the data
1213 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
1214 */
1215static enum GNUNET_GenericReturnValue
1216parse_blinded_message (void *cls,
1217 json_t *root,
1218 struct GNUNET_JSON_Specification *spec)
1219{
1220 struct GNUNET_CRYPTO_BlindedMessage **target = spec->ptr;
1221 struct GNUNET_CRYPTO_BlindedMessage *blinded_message;
1222 const char *cipher;
1223 struct GNUNET_JSON_Specification dspec[] = {
1224 GNUNET_JSON_spec_string ("cipher",
1225 &cipher),
1226 GNUNET_JSON_spec_end ()
1227 };
1228 const char *emsg;
1229 unsigned int eline;
1230
1231 (void) cls;
1232 if (GNUNET_OK !=
1233 GNUNET_JSON_parse (root,
1234 dspec,
1235 &emsg,
1236 &eline))
1237 {
1238 GNUNET_break_op (0);
1239 return GNUNET_SYSERR;
1240 }
1241 blinded_message = GNUNET_new (struct GNUNET_CRYPTO_BlindedMessage);
1242 blinded_message->rc = 1;
1243 blinded_message->cipher = string_to_cipher (cipher);
1244 switch (blinded_message->cipher)
1245 {
1246 case GNUNET_CRYPTO_BSA_INVALID:
1247 break;
1248 case GNUNET_CRYPTO_BSA_RSA:
1249 {
1250 struct GNUNET_JSON_Specification ispec[] = {
1251 GNUNET_JSON_spec_varsize (
1252 /* TODO: Change this field name to something
1253 more generic / pass in as argument. */
1254 "rsa_blinded_planchet",
1255 &blinded_message->details.rsa_blinded_message.blinded_msg,
1256 &blinded_message->details.rsa_blinded_message.blinded_msg_size),
1257 GNUNET_JSON_spec_end ()
1258 };
1259
1260 if (GNUNET_OK !=
1261 GNUNET_JSON_parse (root,
1262 ispec,
1263 &emsg,
1264 &eline))
1265 {
1266 GNUNET_break_op (0);
1267 GNUNET_free (blinded_message);
1268 return GNUNET_SYSERR;
1269 }
1270 *target = blinded_message;
1271 return GNUNET_OK;
1272 }
1273 case GNUNET_CRYPTO_BSA_CS:
1274 {
1275 struct GNUNET_JSON_Specification ispec[] = {
1276 GNUNET_JSON_spec_fixed_auto (
1277 "cs_nonce",
1278 &blinded_message->details.cs_blinded_message.nonce),
1279 GNUNET_JSON_spec_fixed_auto (
1280 "cs_blinded_c0",
1281 &blinded_message->details.cs_blinded_message.c[0]),
1282 GNUNET_JSON_spec_fixed_auto (
1283 "cs_blinded_c1",
1284 &blinded_message->details.cs_blinded_message.c[1]),
1285 GNUNET_JSON_spec_end ()
1286 };
1287
1288 if (GNUNET_OK !=
1289 GNUNET_JSON_parse (root,
1290 ispec,
1291 &emsg,
1292 &eline))
1293 {
1294 GNUNET_break_op (0);
1295 GNUNET_free (blinded_message);
1296 return GNUNET_SYSERR;
1297 }
1298 *target = blinded_message;
1299 return GNUNET_OK;
1300 }
1301 }
1302 GNUNET_break_op (0);
1303 GNUNET_free (blinded_message);
1304 return GNUNET_SYSERR;
1305}
1306
1307/**
1308 * Cleanup data left from parsing blinded message.
1309 *
1310 * @param cls closure, NULL
1311 * @param[out] spec where to free the data
1312 */
1313static void
1314clean_blinded_message (void *cls,
1315 struct GNUNET_JSON_Specification *spec)
1316{
1317 struct GNUNET_CRYPTO_BlindedMessage **blinded_message = spec->ptr;
1318
1319 (void) cls;
1320 if (NULL != blinded_message)
1321 {
1322 GNUNET_CRYPTO_blinded_message_decref (*blinded_message);
1323 *blinded_message = NULL;
1324 }
1325}
1326
1327
1328struct GNUNET_JSON_Specification
1329GNUNET_JSON_spec_blinded_message (const char *name,
1330 struct GNUNET_CRYPTO_BlindedMessage **msg)
1331{
1332 struct GNUNET_JSON_Specification ret = {
1333 .parser = &parse_blinded_message,
1334 .cleaner = &clean_blinded_message,
1335 .cls = NULL,
1336 .field = name,
1337 .ptr = msg,
1338 .ptr_size = 0,
1339 .size_ptr = NULL
1340 };
1341
1342 *msg = NULL;
1343 return ret;
1344}
1345
1346
1347/**
1348 * Parse given JSON object to a blinded signature.
1349 *
1350 * @param cls closure, NULL
1351 * @param root the json object representing data
1352 * @param[out] spec where to write the data
1353 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
1354 */
1355static enum GNUNET_GenericReturnValue
1356parse_blinded_sig (void *cls,
1357 json_t *root,
1358 struct GNUNET_JSON_Specification *spec)
1359{
1360 struct GNUNET_CRYPTO_BlindedSignature **target = spec->ptr;
1361 struct GNUNET_CRYPTO_BlindedSignature *blinded_sig;
1362 const char *cipher;
1363 struct GNUNET_JSON_Specification dspec[] = {
1364 GNUNET_JSON_spec_string ("cipher",
1365 &cipher),
1366 GNUNET_JSON_spec_end ()
1367 };
1368 const char *emsg;
1369 unsigned int eline;
1370
1371 (void) cls;
1372 if (GNUNET_OK !=
1373 GNUNET_JSON_parse (root,
1374 dspec,
1375 &emsg,
1376 &eline))
1377 {
1378 GNUNET_break_op (0);
1379 return GNUNET_SYSERR;
1380 }
1381 blinded_sig = GNUNET_new (struct GNUNET_CRYPTO_BlindedSignature);
1382 blinded_sig->cipher = string_to_cipher (cipher);
1383 blinded_sig->rc = 1;
1384 switch (blinded_sig->cipher)
1385 {
1386 case GNUNET_CRYPTO_BSA_INVALID:
1387 break;
1388 case GNUNET_CRYPTO_BSA_RSA:
1389 {
1390 struct GNUNET_JSON_Specification ispec[] = {
1391 GNUNET_JSON_spec_rsa_signature (
1392 "blinded_rsa_signature",
1393 &blinded_sig->details.blinded_rsa_signature),
1394 GNUNET_JSON_spec_end ()
1395 };
1396
1397 if (GNUNET_OK !=
1398 GNUNET_JSON_parse (root,
1399 ispec,
1400 &emsg,
1401 &eline))
1402 {
1403 GNUNET_break_op (0);
1404 GNUNET_free (blinded_sig);
1405 return GNUNET_SYSERR;
1406 }
1407 *target = blinded_sig;
1408 return GNUNET_OK;
1409 }
1410 case GNUNET_CRYPTO_BSA_CS:
1411 {
1412 struct GNUNET_JSON_Specification ispec[] = {
1413 GNUNET_JSON_spec_uint32 ("b",
1414 &blinded_sig->details.blinded_cs_answer.b),
1415 GNUNET_JSON_spec_fixed_auto ("s",
1416 &blinded_sig->details.blinded_cs_answer.
1417 s_scalar),
1418 GNUNET_JSON_spec_end ()
1419 };
1420
1421 if (GNUNET_OK !=
1422 GNUNET_JSON_parse (root,
1423 ispec,
1424 &emsg,
1425 &eline))
1426 {
1427 GNUNET_break_op (0);
1428 GNUNET_free (blinded_sig);
1429 return GNUNET_SYSERR;
1430 }
1431 *target = blinded_sig;
1432 return GNUNET_OK;
1433 }
1434 }
1435 GNUNET_break_op (0);
1436 GNUNET_free (blinded_sig);
1437 return GNUNET_SYSERR;
1438}
1439
1440
1441/**
1442 * Cleanup data left from parsing blinded sig.
1443 *
1444 * @param cls closure, NULL
1445 * @param[out] spec where to free the data
1446 */
1447static void
1448clean_blinded_sig (void *cls,
1449 struct GNUNET_JSON_Specification *spec)
1450{
1451 struct GNUNET_CRYPTO_BlindedSignature **b_sig = spec->ptr;
1452
1453 (void) cls;
1454
1455 if (NULL != *b_sig)
1456 {
1457 GNUNET_CRYPTO_blinded_sig_decref (*b_sig);
1458 *b_sig = NULL;
1459 }
1460}
1461
1462
1463struct GNUNET_JSON_Specification
1464GNUNET_JSON_spec_blinded_signature (const char *field,
1465 struct GNUNET_CRYPTO_BlindedSignature **b_sig)
1466{
1467 struct GNUNET_JSON_Specification ret = {
1468 .parser = &parse_blinded_sig,
1469 .cleaner = &clean_blinded_sig,
1470 .field = field,
1471 .ptr = b_sig
1472 };
1473
1474 *b_sig = NULL;
1475 return ret;
1476}
1477
1478/**
1479 * Parse given JSON object to unblinded signature.
1480 *
1481 * @param cls closure, NULL
1482 * @param root the json object representing data
1483 * @param[out] spec where to write the data
1484 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
1485 */
1486static enum GNUNET_GenericReturnValue
1487parse_unblinded_sig (void *cls,
1488 json_t *root,
1489 struct GNUNET_JSON_Specification *spec)
1490{
1491 struct GNUNET_CRYPTO_UnblindedSignature **target = spec->ptr;
1492 struct GNUNET_CRYPTO_UnblindedSignature *unblinded_sig;
1493 const char *cipher;
1494 struct GNUNET_JSON_Specification dspec[] = {
1495 GNUNET_JSON_spec_string ("cipher",
1496 &cipher),
1497 GNUNET_JSON_spec_end ()
1498 };
1499 const char *emsg;
1500 unsigned int eline;
1501
1502 (void) cls;
1503 if (GNUNET_OK !=
1504 GNUNET_JSON_parse (root,
1505 dspec,
1506 &emsg,
1507 &eline))
1508 {
1509 GNUNET_break_op (0);
1510 return GNUNET_SYSERR;
1511 }
1512 unblinded_sig = GNUNET_new (struct GNUNET_CRYPTO_UnblindedSignature);
1513 unblinded_sig->cipher = string_to_cipher (cipher);
1514 unblinded_sig->rc = 1;
1515 switch (unblinded_sig->cipher)
1516 {
1517 case GNUNET_CRYPTO_BSA_INVALID:
1518 break;
1519 case GNUNET_CRYPTO_BSA_RSA:
1520 {
1521 struct GNUNET_JSON_Specification ispec[] = {
1522 GNUNET_JSON_spec_rsa_signature (
1523 "rsa_signature",
1524 &unblinded_sig->details.rsa_signature),
1525 GNUNET_JSON_spec_end ()
1526 };
1527
1528 if (GNUNET_OK !=
1529 GNUNET_JSON_parse (root,
1530 ispec,
1531 &emsg,
1532 &eline))
1533 {
1534 GNUNET_break_op (0);
1535 GNUNET_free (unblinded_sig);
1536 return GNUNET_SYSERR;
1537 }
1538 *target = unblinded_sig;
1539 return GNUNET_OK;
1540 }
1541 case GNUNET_CRYPTO_BSA_CS:
1542 {
1543 struct GNUNET_JSON_Specification ispec[] = {
1544 GNUNET_JSON_spec_fixed_auto ("cs_signature_r",
1545 &unblinded_sig->details.cs_signature.
1546 r_point),
1547 GNUNET_JSON_spec_fixed_auto ("cs_signature_s",
1548 &unblinded_sig->details.cs_signature.
1549 s_scalar),
1550 GNUNET_JSON_spec_end ()
1551 };
1552
1553 if (GNUNET_OK !=
1554 GNUNET_JSON_parse (root,
1555 ispec,
1556 &emsg,
1557 &eline))
1558 {
1559 GNUNET_break_op (0);
1560 GNUNET_free (unblinded_sig);
1561 return GNUNET_SYSERR;
1562 }
1563 *target = unblinded_sig;
1564 return GNUNET_OK;
1565 }
1566 }
1567 GNUNET_break_op (0);
1568 GNUNET_free (unblinded_sig);
1569 return GNUNET_SYSERR;
1570}
1571
1572
1573/**
1574 * Cleanup data left from parsing unblinded signature.
1575 *
1576 * @param cls closure, NULL
1577 * @param[out] spec where to free the data
1578 */
1579static void
1580clean_unblinded_sig (void *cls,
1581 struct GNUNET_JSON_Specification *spec)
1582{
1583 struct GNUNET_CRYPTO_UnblindedSignature **ub_sig = spec->ptr;
1584
1585 (void) cls;
1586 if (NULL != *ub_sig)
1587 {
1588 GNUNET_CRYPTO_unblinded_sig_decref (*ub_sig);
1589 *ub_sig = NULL;
1590 }
1591}
1592
1593
1594struct GNUNET_JSON_Specification
1595GNUNET_JSON_spec_unblinded_signature (const char *field,
1596 struct GNUNET_CRYPTO_UnblindedSignature **ub_sig)
1597{
1598 struct GNUNET_JSON_Specification ret = {
1599 .parser = &parse_unblinded_sig,
1600 .cleaner = &clean_unblinded_sig,
1601 .field = field,
1602 .ptr = ub_sig
1603 };
1604
1605 *ub_sig = NULL;
1606 return ret;
1607}
1608
1609
1610
1611/* end of json_helper.c */
diff --git a/src/lib/json/json_mhd.c b/src/lib/json/json_mhd.c
new file mode 100644
index 000000000..0b0fa0538
--- /dev/null
+++ b/src/lib/json/json_mhd.c
@@ -0,0 +1,379 @@
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 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file json/json_mhd.c
22 * @brief functions to parse JSON snippets we receive via MHD
23 * @author Florian Dold
24 * @author Benedikt Mueller
25 * @author Christian Grothoff
26 */
27#include "platform.h"
28#include "gnunet_json_lib.h"
29#include <zlib.h>
30
31
32/**
33 * Initial size for POST request buffers. Should be big enough to
34 * usually not require a reallocation, but not so big that it hurts in
35 * terms of memory use.
36 */
37#define REQUEST_BUFFER_INITIAL (2 * 1024)
38
39
40/**
41 * Buffer for POST requests.
42 */
43struct Buffer
44{
45 /**
46 * Allocated memory
47 */
48 char *data;
49
50 /**
51 * Number of valid bytes in buffer.
52 */
53 size_t fill;
54
55 /**
56 * Number of allocated bytes in buffer.
57 */
58 size_t alloc;
59
60 /**
61 * Maximum buffer size allowed.
62 */
63 size_t max;
64};
65
66
67/**
68 * Initialize a buffer.
69 *
70 * @param buf the buffer to initialize
71 * @param data the initial data
72 * @param data_size size of the initial data
73 * @param alloc_size size of the buffer
74 * @param max_size maximum size that the buffer can grow to
75 * @return a GNUnet result code
76 */
77static int
78buffer_init (struct Buffer *buf,
79 const void *data,
80 size_t data_size,
81 size_t alloc_size,
82 size_t max_size)
83{
84 if ((data_size > max_size) || (alloc_size > max_size))
85 return GNUNET_SYSERR;
86 if (data_size > alloc_size)
87 alloc_size = data_size;
88 buf->data = GNUNET_malloc (alloc_size);
89 buf->alloc = alloc_size;
90 GNUNET_memcpy (buf->data, data, data_size);
91 buf->fill = data_size;
92 buf->max = max_size;
93 return GNUNET_OK;
94}
95
96
97/**
98 * Free the data in a buffer. Does *not* free
99 * the buffer object itself.
100 *
101 * @param buf buffer to de-initialize
102 */
103static void
104buffer_deinit (struct Buffer *buf)
105{
106 GNUNET_free (buf->data);
107 buf->data = NULL;
108}
109
110
111/**
112 * Append data to a buffer, growing the buffer if necessary.
113 *
114 * @param buf the buffer to append to
115 * @param data the data to append
116 * @param data_size the size of @a data
117 * @param max_size maximum size that the buffer can grow to
118 * @return #GNUNET_OK on success,
119 * #GNUNET_NO if the buffer can't accommodate for the new data
120 */
121static int
122buffer_append (struct Buffer *buf,
123 const void *data,
124 size_t data_size,
125 size_t max_size)
126{
127 if (buf->fill + data_size > max_size)
128 return GNUNET_NO;
129 if (buf->fill + data_size > buf->alloc)
130 {
131 char *new_buf;
132 size_t new_size = buf->alloc;
133 while (new_size < buf->fill + data_size)
134 new_size += 2;
135 if (new_size > max_size)
136 return GNUNET_NO;
137 new_buf = GNUNET_malloc (new_size);
138 GNUNET_memcpy (new_buf, buf->data, buf->fill);
139 GNUNET_free (buf->data);
140 buf->data = new_buf;
141 buf->alloc = new_size;
142 }
143 GNUNET_memcpy (buf->data + buf->fill, data, data_size);
144 buf->fill += data_size;
145 return GNUNET_OK;
146}
147
148
149/**
150 * Decompress data in @a buf.
151 *
152 * @param buf input data to inflate
153 * @return result code indicating the status of the operation
154 */
155static enum GNUNET_JSON_PostResult
156inflate_data (struct Buffer *buf)
157{
158 z_stream z;
159 char *tmp;
160 size_t tmp_size;
161 int ret;
162
163 memset (&z, 0, sizeof(z));
164 z.next_in = (Bytef *) buf->data;
165 z.avail_in = buf->fill;
166 tmp_size = GNUNET_MIN (buf->max, buf->fill * 4);
167 tmp = GNUNET_malloc (tmp_size);
168 z.next_out = (Bytef *) tmp;
169 z.avail_out = tmp_size;
170 ret = inflateInit (&z);
171 switch (ret)
172 {
173 case Z_MEM_ERROR:
174 GNUNET_break (0);
175 return GNUNET_JSON_PR_OUT_OF_MEMORY;
176
177 case Z_STREAM_ERROR:
178 GNUNET_break_op (0);
179 return GNUNET_JSON_PR_JSON_INVALID;
180
181 case Z_OK:
182 break;
183 }
184 while (1)
185 {
186 ret = inflate (&z, 0);
187 switch (ret)
188 {
189 case Z_BUF_ERROR:
190 GNUNET_break_op (0);
191 GNUNET_break (Z_OK == inflateEnd (&z));
192 GNUNET_free (tmp);
193 return GNUNET_JSON_PR_JSON_INVALID;
194 case Z_MEM_ERROR:
195 GNUNET_break (0);
196 GNUNET_break (Z_OK == inflateEnd (&z));
197 GNUNET_free (tmp);
198 return GNUNET_JSON_PR_OUT_OF_MEMORY;
199 case Z_DATA_ERROR:
200 GNUNET_break_op (0);
201 GNUNET_break (Z_OK == inflateEnd (&z));
202 GNUNET_free (tmp);
203 return GNUNET_JSON_PR_JSON_INVALID;
204 case Z_NEED_DICT:
205 GNUNET_break_op (0);
206 GNUNET_break (Z_OK == inflateEnd (&z));
207 GNUNET_free (tmp);
208 return GNUNET_JSON_PR_JSON_INVALID;
209 case Z_OK:
210 if ((0 < z.avail_out) && (0 == z.avail_in))
211 {
212 /* truncated input stream */
213 GNUNET_break (0);
214 GNUNET_break (Z_OK == inflateEnd (&z));
215 GNUNET_free (tmp);
216 return GNUNET_JSON_PR_JSON_INVALID;
217 }
218 if (0 < z.avail_out)
219 continue; /* just call it again */
220 /* output buffer full, can we grow it? */
221 if (tmp_size == buf->max)
222 {
223 /* already at max */
224 GNUNET_break (0);
225 GNUNET_break (Z_OK == inflateEnd (&z));
226 GNUNET_free (tmp);
227 return GNUNET_JSON_PR_OUT_OF_MEMORY;
228 }
229 if (tmp_size * 2 < tmp_size)
230 tmp_size = buf->max;
231 else
232 tmp_size = GNUNET_MIN (buf->max, tmp_size * 2);
233 tmp = GNUNET_realloc (tmp, tmp_size);
234 z.next_out = (Bytef *) &tmp[z.total_out];
235 continue;
236 case Z_STREAM_END:
237 /* decompression successful, make 'tmp' the new 'data' */
238 GNUNET_free (buf->data);
239 buf->data = tmp;
240 buf->alloc = tmp_size;
241 buf->fill = z.total_out;
242 GNUNET_break (Z_OK == inflateEnd (&z));
243 return GNUNET_JSON_PR_SUCCESS; /* at least for now */
244 }
245 } /* while (1) */
246}
247
248
249/**
250 * Process a POST request containing a JSON object. This function
251 * realizes an MHD POST processor that will (incrementally) process
252 * JSON data uploaded to the HTTP server. It will store the required
253 * state in the @a con_cls, which must be cleaned up using
254 * #GNUNET_JSON_post_parser_callback().
255 *
256 * @param buffer_max maximum allowed size for the buffer
257 * @param connection MHD connection handle (for meta data about the upload)
258 * @param con_cls the closure (will point to a `struct Buffer *`)
259 * @param upload_data the POST data
260 * @param upload_data_size number of bytes in @a upload_data
261 * @param json the JSON object for a completed request
262 * @return result code indicating the status of the operation
263 */
264enum GNUNET_JSON_PostResult
265GNUNET_JSON_post_parser (size_t buffer_max,
266 struct MHD_Connection *connection,
267 void **con_cls,
268 const char *upload_data,
269 size_t *upload_data_size,
270 json_t **json)
271{
272 struct Buffer *r = *con_cls;
273 const char *ce;
274 int ret;
275
276 *json = NULL;
277 if (NULL == *con_cls)
278 {
279 /* We are seeing a fresh POST request. */
280 r = GNUNET_new (struct Buffer);
281 if (GNUNET_OK != buffer_init (r,
282 upload_data,
283 *upload_data_size,
284 REQUEST_BUFFER_INITIAL,
285 buffer_max))
286 {
287 *con_cls = NULL;
288 buffer_deinit (r);
289 GNUNET_free (r);
290 return GNUNET_JSON_PR_OUT_OF_MEMORY;
291 }
292 /* everything OK, wait for more POST data */
293 *upload_data_size = 0;
294 *con_cls = r;
295 return GNUNET_JSON_PR_CONTINUE;
296 }
297 if (0 != *upload_data_size)
298 {
299 /* We are seeing an old request with more data available. */
300
301 if (GNUNET_OK !=
302 buffer_append (r, upload_data, *upload_data_size, buffer_max))
303 {
304 /* Request too long */
305 *con_cls = NULL;
306 buffer_deinit (r);
307 GNUNET_free (r);
308 return GNUNET_JSON_PR_REQUEST_TOO_LARGE;
309 }
310 /* everything OK, wait for more POST data */
311 *upload_data_size = 0;
312 return GNUNET_JSON_PR_CONTINUE;
313 }
314
315 /* We have seen the whole request. */
316 ce = MHD_lookup_connection_value (connection,
317 MHD_HEADER_KIND,
318 MHD_HTTP_HEADER_CONTENT_ENCODING);
319 if ((NULL != ce) && (0 == strcasecmp ("deflate", ce)))
320 {
321 ret = inflate_data (r);
322 if (GNUNET_JSON_PR_SUCCESS != ret)
323 {
324 buffer_deinit (r);
325 GNUNET_free (r);
326 *con_cls = NULL;
327 return ret;
328 }
329 }
330
331 {
332 json_error_t err;
333
334 *json = json_loadb (r->data,
335 r->fill,
336 0,
337 &err);
338 if (NULL == *json)
339 {
340 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
341 "Failed to parse JSON request body of %u byte at offset %d: %s\n",
342 (unsigned int) r->fill,
343 err.position,
344 err.text);
345 buffer_deinit (r);
346 GNUNET_free (r);
347 *con_cls = NULL;
348 return GNUNET_JSON_PR_JSON_INVALID;
349 }
350 }
351 buffer_deinit (r);
352 GNUNET_free (r);
353 *con_cls = NULL;
354
355 return GNUNET_JSON_PR_SUCCESS;
356}
357
358
359/**
360 * Function called whenever we are done with a request
361 * to clean up our state.
362 *
363 * @param con_cls value as it was left by
364 * #GNUNET_JSON_post_parser(), to be cleaned up
365 */
366void
367GNUNET_JSON_post_parser_cleanup (void *con_cls)
368{
369 struct Buffer *r = con_cls;
370
371 if (NULL != r)
372 {
373 buffer_deinit (r);
374 GNUNET_free (r);
375 }
376}
377
378
379/* end of mhd_json.c */
diff --git a/src/lib/json/json_pack.c b/src/lib/json/json_pack.c
new file mode 100644
index 000000000..d298e6efe
--- /dev/null
+++ b/src/lib/json/json_pack.c
@@ -0,0 +1,480 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2021 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 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file json/json_pack.c
22 * @brief functions to pack JSON objects
23 * @author Christian Grothoff
24 */
25#include "platform.h"
26#include "gnunet_json_lib.h"
27
28json_t *
29GNUNET_JSON_pack_ (struct GNUNET_JSON_PackSpec spec[])
30{
31 json_t *ret;
32
33 if (NULL == spec[0].field_name)
34 {
35 ret = spec[0].object;
36 spec[0].object = NULL;
37 return ret;
38 }
39 ret = json_object ();
40 GNUNET_assert (NULL != ret);
41 for (unsigned int i = 0;
42 NULL != spec[i].field_name;
43 i++)
44 {
45 if (NULL == spec[i].object)
46 {
47 if (! spec[i].allow_null)
48 {
49 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
50 "NULL not allowed for `%s'\n",
51 spec[i].field_name);
52 GNUNET_assert (0);
53 }
54 }
55 else
56 {
57 GNUNET_assert (0 ==
58 json_object_set_new (ret,
59 spec[i].field_name,
60 spec[i].object));
61 spec[i].object = NULL;
62 }
63 }
64 return ret;
65}
66
67
68struct GNUNET_JSON_PackSpec
69GNUNET_JSON_pack_end_ (void)
70{
71 struct GNUNET_JSON_PackSpec ps = {
72 .field_name = NULL
73 };
74
75 return ps;
76}
77
78
79struct GNUNET_JSON_PackSpec
80GNUNET_JSON_pack_allow_null (struct GNUNET_JSON_PackSpec in)
81{
82 in.allow_null = true;
83 return in;
84}
85
86
87struct GNUNET_JSON_PackSpec
88GNUNET_JSON_pack_bool (const char *name,
89 bool b)
90{
91 struct GNUNET_JSON_PackSpec ps = {
92 .field_name = name,
93 .object = json_boolean (b)
94 };
95
96 return ps;
97}
98
99
100struct GNUNET_JSON_PackSpec
101GNUNET_JSON_pack_double (const char *name,
102 double f)
103{
104 struct GNUNET_JSON_PackSpec ps = {
105 .field_name = name,
106 .object = json_real (f)
107 };
108
109 return ps;
110}
111
112
113struct GNUNET_JSON_PackSpec
114GNUNET_JSON_pack_string (const char *name,
115 const char *s)
116{
117 struct GNUNET_JSON_PackSpec ps = {
118 .field_name = name,
119 .object = json_string (s)
120 };
121
122 return ps;
123}
124
125
126struct GNUNET_JSON_PackSpec
127GNUNET_JSON_pack_uint64 (const char *name,
128 uint64_t num)
129{
130 struct GNUNET_JSON_PackSpec ps = {
131 .field_name = name,
132 .object = json_integer ((json_int_t) num)
133 };
134
135#if JSON_INTEGER_IS_LONG_LONG
136 GNUNET_assert (num <= LLONG_MAX);
137#else
138 GNUNET_assert (num <= LONG_MAX);
139#endif
140 return ps;
141}
142
143
144struct GNUNET_JSON_PackSpec
145GNUNET_JSON_pack_int64 (const char *name,
146 int64_t num)
147{
148 struct GNUNET_JSON_PackSpec ps = {
149 .field_name = name,
150 .object = json_integer ((json_int_t) num)
151 };
152
153#if JSON_INTEGER_IS_LONG_LONG
154 GNUNET_assert (num <= LLONG_MAX);
155 GNUNET_assert (num >= LLONG_MIN);
156#else
157 GNUNET_assert (num <= LONG_MAX);
158 GNUNET_assert (num >= LONG_MIN);
159#endif
160 return ps;
161}
162
163
164struct GNUNET_JSON_PackSpec
165GNUNET_JSON_pack_object_steal (const char *name,
166 json_t *o)
167{
168 struct GNUNET_JSON_PackSpec ps = {
169 .field_name = name,
170 .object = o
171 };
172
173 if (NULL == o)
174 return ps;
175 if (! json_is_object (o))
176 {
177 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
178 "Expected JSON object for field `%s'\n",
179 name);
180 GNUNET_assert (0);
181 }
182 return ps;
183}
184
185
186struct GNUNET_JSON_PackSpec
187GNUNET_JSON_pack_object_incref (const char *name,
188 json_t *o)
189{
190 struct GNUNET_JSON_PackSpec ps = {
191 .field_name = name,
192 .object = o
193 };
194
195 if (NULL == o)
196 return ps;
197 (void) json_incref (o);
198 if (! json_is_object (o))
199 {
200 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
201 "Expected JSON object for field `%s'\n",
202 name);
203 GNUNET_assert (0);
204 }
205 return ps;
206}
207
208
209struct GNUNET_JSON_PackSpec
210GNUNET_JSON_pack_array_steal (const char *name,
211 json_t *a)
212{
213 struct GNUNET_JSON_PackSpec ps = {
214 .field_name = name,
215 .object = a
216 };
217
218 if (NULL == a)
219 return ps;
220 if (! json_is_array (a))
221 {
222 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
223 "Expected JSON array for field `%s'\n",
224 name);
225 GNUNET_assert (0);
226 }
227 return ps;
228}
229
230
231struct GNUNET_JSON_PackSpec
232GNUNET_JSON_pack_array_incref (const char *name,
233 json_t *a)
234{
235 struct GNUNET_JSON_PackSpec ps = {
236 .field_name = name,
237 .object = a
238 };
239
240 if (NULL == a)
241 return ps;
242 (void) json_incref (a);
243 if (! json_is_array (a))
244 {
245 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
246 "Expected JSON array for field `%s'\n",
247 name);
248 GNUNET_assert (0);
249 }
250 return ps;
251}
252
253
254struct GNUNET_JSON_PackSpec
255GNUNET_JSON_pack_data_varsize (const char *name,
256 const void *blob,
257 size_t blob_size)
258{
259 struct GNUNET_JSON_PackSpec ps = {
260 .field_name = name,
261 .object = (NULL != blob)
262 ? GNUNET_JSON_from_data (blob,
263 blob_size)
264 : NULL
265 };
266
267 return ps;
268}
269
270
271struct GNUNET_JSON_PackSpec
272GNUNET_JSON_pack_data64_varsize (const char *name,
273 const void *blob,
274 size_t blob_size)
275{
276 struct GNUNET_JSON_PackSpec ps = {
277 .field_name = name,
278 .object = (NULL != blob)
279 ? GNUNET_JSON_from_data64 (blob,
280 blob_size)
281 : NULL
282 };
283
284 return ps;
285}
286
287
288struct GNUNET_JSON_PackSpec
289GNUNET_JSON_pack_timestamp (const char *name,
290 struct GNUNET_TIME_Timestamp t)
291{
292 struct GNUNET_JSON_PackSpec ps = {
293 .field_name = name
294 };
295
296 if (! GNUNET_TIME_absolute_is_zero (t.abs_time))
297 {
298 ps.object = GNUNET_JSON_from_timestamp (t);
299 GNUNET_assert (NULL != ps.object);
300 }
301 else
302 {
303 ps.object = NULL;
304 }
305 return ps;
306}
307
308
309struct GNUNET_JSON_PackSpec
310GNUNET_JSON_pack_timestamp_nbo (const char *name,
311 struct GNUNET_TIME_TimestampNBO at)
312{
313 return GNUNET_JSON_pack_timestamp (name,
314 GNUNET_TIME_timestamp_ntoh (at));
315}
316
317
318struct GNUNET_JSON_PackSpec
319GNUNET_JSON_pack_time_rel (const char *name,
320 struct GNUNET_TIME_Relative rt)
321{
322 json_t *json;
323
324 json = GNUNET_JSON_from_time_rel (rt);
325 GNUNET_assert (NULL != json);
326 return GNUNET_JSON_pack_object_steal (name,
327 json);
328}
329
330
331struct GNUNET_JSON_PackSpec
332GNUNET_JSON_pack_time_rel_nbo (const char *name,
333 struct GNUNET_TIME_RelativeNBO rt)
334{
335 return GNUNET_JSON_pack_time_rel (name,
336 GNUNET_TIME_relative_ntoh (rt));
337}
338
339
340struct GNUNET_JSON_PackSpec
341GNUNET_JSON_pack_rsa_public_key (const char *name,
342 const struct GNUNET_CRYPTO_RsaPublicKey *pk)
343{
344 struct GNUNET_JSON_PackSpec ps = {
345 .field_name = name,
346 .object = GNUNET_JSON_from_rsa_public_key (pk)
347 };
348
349 return ps;
350}
351
352
353struct GNUNET_JSON_PackSpec
354GNUNET_JSON_pack_rsa_signature (const char *name,
355 const struct GNUNET_CRYPTO_RsaSignature *sig)
356{
357 struct GNUNET_JSON_PackSpec ps = {
358 .field_name = name,
359 .object = GNUNET_JSON_from_rsa_signature (sig)
360 };
361
362 return ps;
363}
364
365
366struct GNUNET_JSON_PackSpec
367GNUNET_JSON_pack_unblinded_signature (const char *name,
368 const struct GNUNET_CRYPTO_UnblindedSignature *sig)
369{
370 struct GNUNET_JSON_PackSpec ps = {
371 .field_name = name
372 };
373
374 if (NULL == sig)
375 return ps;
376
377 switch (sig->cipher)
378 {
379 case GNUNET_CRYPTO_BSA_INVALID:
380 break;
381 case GNUNET_CRYPTO_BSA_RSA:
382 ps.object = GNUNET_JSON_PACK (
383 GNUNET_JSON_pack_string ("cipher",
384 "RSA"),
385 GNUNET_JSON_pack_rsa_signature ("rsa_signature",
386 sig->details.rsa_signature));
387 return ps;
388 case GNUNET_CRYPTO_BSA_CS:
389 ps.object = GNUNET_JSON_PACK (
390 GNUNET_JSON_pack_string ("cipher",
391 "CS"),
392 GNUNET_JSON_pack_data_auto ("cs_signature_r",
393 &sig->details.cs_signature.r_point),
394 GNUNET_JSON_pack_data_auto ("cs_signature_s",
395 &sig->details.cs_signature.s_scalar));
396 return ps;
397 }
398 GNUNET_assert (0);
399 return ps;
400}
401
402
403struct GNUNET_JSON_PackSpec
404GNUNET_JSON_pack_blinded_message (const char *name,
405 const struct GNUNET_CRYPTO_BlindedMessage *msg)
406{
407 struct GNUNET_JSON_PackSpec ps = {
408 .field_name = name,
409 };
410
411 switch (msg->cipher)
412 {
413 case GNUNET_CRYPTO_BSA_INVALID:
414 break;
415 case GNUNET_CRYPTO_BSA_RSA:
416 ps.object = GNUNET_JSON_PACK (
417 GNUNET_JSON_pack_string ("cipher",
418 "RSA"),
419 GNUNET_JSON_pack_data_varsize (
420 "rsa_blinded_planchet",
421 msg->details.rsa_blinded_message.blinded_msg,
422 msg->details.rsa_blinded_message.blinded_msg_size));
423 return ps;
424 case GNUNET_CRYPTO_BSA_CS:
425 ps.object = GNUNET_JSON_PACK (
426 GNUNET_JSON_pack_string ("cipher",
427 "CS"),
428 GNUNET_JSON_pack_data_auto (
429 "cs_nonce",
430 &msg->details.cs_blinded_message.nonce),
431 GNUNET_JSON_pack_data_auto (
432 "cs_blinded_c0",
433 &msg->details.cs_blinded_message.c[0]),
434 GNUNET_JSON_pack_data_auto (
435 "cs_blinded_c1",
436 &msg->details.cs_blinded_message.c[1]));
437 return ps;
438 }
439 GNUNET_assert (0);
440 return ps;
441}
442
443
444struct GNUNET_JSON_PackSpec
445GNUNET_JSON_pack_blinded_sig (
446 const char *name,
447 const struct GNUNET_CRYPTO_BlindedSignature *sig)
448{
449 struct GNUNET_JSON_PackSpec ps = {
450 .field_name = name,
451 };
452
453 if (NULL == sig)
454 return ps;
455 switch (sig->cipher)
456 {
457 case GNUNET_CRYPTO_BSA_INVALID:
458 break;
459 case GNUNET_CRYPTO_BSA_RSA:
460 ps.object = GNUNET_JSON_PACK (
461 GNUNET_JSON_pack_string ("cipher",
462 "RSA"),
463 GNUNET_JSON_pack_rsa_signature ("blinded_rsa_signature",
464 sig->details.blinded_rsa_signature));
465 return ps;
466 case GNUNET_CRYPTO_BSA_CS:
467 ps.object = GNUNET_JSON_PACK (
468 GNUNET_JSON_pack_string ("cipher",
469 "CS"),
470 GNUNET_JSON_pack_uint64 ("b",
471 sig->details.blinded_cs_answer.b),
472 GNUNET_JSON_pack_data_auto ("s",
473 &sig->details.blinded_cs_answer.s_scalar));
474 return ps;
475 }
476 GNUNET_assert (0);
477 return ps;
478}
479
480/* end of json_pack.c */
diff --git a/src/lib/json/meson.build b/src/lib/json/meson.build
new file mode 100644
index 000000000..d4c3b4528
--- /dev/null
+++ b/src/lib/json/meson.build
@@ -0,0 +1,44 @@
1libgnunetjson_src = ['json.c',
2 'json_generator.c',
3 'json_helper.c',
4 'json_mhd.c',
5 'json_pack.c']
6
7libgnunetjson = library('gnunetjson',
8 libgnunetjson_src,
9 soversion: '0',
10 version: '0.0.0',
11 dependencies: [libgnunetutil_dep, json_dep, mhd_dep, zlib_dep],
12 include_directories: [incdir, configuration_inc],
13 install: true,
14 install_dir: get_option('libdir'))
15libgnunetjson_dep = declare_dependency(link_with : libgnunetjson)
16pkg.generate(libgnunetjson, url: 'https://www.gnunet.org',
17 description : 'Library for JSON de/serialization')
18
19testjson = executable ('test_json',
20 ['test_json.c'],
21 dependencies: [libgnunetutil_dep,
22 json_dep,
23 libgnunetjson_dep],
24 include_directories: [incdir, configuration_inc],
25 build_by_default: false,
26 install: false)
27testjson_mhd = executable ('test_json_mhd',
28 ['test_json_mhd.c'],
29 dependencies: [libgnunetutil_dep,
30 json_dep,
31 mhd_dep,
32 curl_dep,
33 zlib_dep,
34 libgnunetjson_dep],
35 include_directories: [incdir, configuration_inc],
36 build_by_default: false,
37 install: false)
38test('test_json', testjson,
39 workdir: meson.current_build_dir(),
40 suite: ['json'])
41test('test_json_mhd', testjson_mhd,
42 workdir: meson.current_build_dir(),
43 suite: ['json'])
44
diff --git a/src/lib/json/test_json.c b/src/lib/json/test_json.c
new file mode 100644
index 000000000..1d27518b2
--- /dev/null
+++ b/src/lib/json/test_json.c
@@ -0,0 +1,247 @@
1/*
2 This file is part of GNUnet
3 (C) 2015, 2016, 2021 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 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file json/test_json.c
23 * @brief Tests for JSON conversion functions
24 * @author Christian Grothoff <christian@grothoff.org>
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_json_lib.h"
29
30
31/**
32 * Test absolute time conversion from/to JSON.
33 *
34 * @return 0 on success
35 */
36static int
37test_timestamp (void)
38{
39 json_t *j;
40 struct GNUNET_TIME_Absolute a1;
41 struct GNUNET_TIME_Timestamp t1;
42 struct GNUNET_TIME_Timestamp t2;
43 struct GNUNET_JSON_Specification s1[] = {
44 GNUNET_JSON_spec_timestamp (NULL,
45 &t2),
46 GNUNET_JSON_spec_end ()
47 };
48 struct GNUNET_JSON_Specification s2[] = {
49 GNUNET_JSON_spec_timestamp (NULL,
50 &t2),
51 GNUNET_JSON_spec_end ()
52 };
53
54 a1 = GNUNET_TIME_absolute_get ();
55 t1 = GNUNET_TIME_absolute_to_timestamp (a1);
56 j = GNUNET_JSON_from_timestamp (t1);
57 GNUNET_assert (NULL != j);
58 GNUNET_assert (GNUNET_OK ==
59 GNUNET_JSON_parse (j,
60 s1,
61 NULL,
62 NULL));
63 GNUNET_assert (GNUNET_TIME_timestamp_cmp (t1, ==, t2));
64 json_decref (j);
65
66 a1 = GNUNET_TIME_UNIT_FOREVER_ABS;
67 j = GNUNET_JSON_from_timestamp (t1);
68 GNUNET_assert (NULL != j);
69 GNUNET_assert (GNUNET_OK ==
70 GNUNET_JSON_parse (j,
71 s2,
72 NULL,
73 NULL));
74 GNUNET_assert (GNUNET_TIME_timestamp_cmp (t1, ==, t2));
75 json_decref (j);
76 return 0;
77}
78
79
80/**
81 * Test relative time conversion from/to JSON.
82 *
83 * @return 0 on success
84 */
85static int
86test_rel_time (void)
87{
88 json_t *j;
89 struct GNUNET_TIME_Relative r1;
90 struct GNUNET_TIME_Relative r2;
91 struct GNUNET_JSON_Specification s1[] = {
92 GNUNET_JSON_spec_relative_time (NULL,
93 &r2),
94 GNUNET_JSON_spec_end ()
95 };
96 struct GNUNET_JSON_Specification s2[] = {
97 GNUNET_JSON_spec_relative_time (NULL,
98 &r2),
99 GNUNET_JSON_spec_end ()
100 };
101
102 r1 = GNUNET_TIME_UNIT_SECONDS;
103 j = GNUNET_JSON_from_time_rel (r1);
104 GNUNET_assert (NULL != j);
105 GNUNET_assert (GNUNET_OK == GNUNET_JSON_parse (j, s1, NULL, NULL));
106 GNUNET_assert (r1.rel_value_us == r2.rel_value_us);
107 json_decref (j);
108
109 r1 = GNUNET_TIME_UNIT_FOREVER_REL;
110 j = GNUNET_JSON_from_time_rel (r1);
111 GNUNET_assert (NULL != j);
112 GNUNET_assert (GNUNET_OK == GNUNET_JSON_parse (j, s2, NULL, NULL));
113 GNUNET_assert (r1.rel_value_us == r2.rel_value_us);
114 json_decref (j);
115 return 0;
116}
117
118
119/**
120 * Test raw (binary) conversion from/to JSON.
121 *
122 * @return 0 on success
123 */
124static int
125test_raw ()
126{
127 char blob[256];
128 unsigned int i;
129 json_t *j;
130
131 for (i = 0; i <= 256; i++)
132 {
133 char blob2[256];
134 struct GNUNET_JSON_Specification spec[] = { GNUNET_JSON_spec_fixed (NULL,
135 blob2,
136 i),
137 GNUNET_JSON_spec_end () };
138
139 memset (blob, i, i);
140 j = GNUNET_JSON_from_data (blob, i);
141 GNUNET_assert (NULL != j);
142 GNUNET_assert (GNUNET_OK == GNUNET_JSON_parse (j, spec, NULL, NULL));
143 GNUNET_assert (0 == memcmp (blob, blob2, i));
144 json_decref (j);
145 }
146 return 0;
147}
148
149
150/**
151 * Test rsa conversions from/to JSON.
152 *
153 * @return 0 on success
154 */
155static int
156test_rsa ()
157{
158 struct GNUNET_CRYPTO_RsaPublicKey *pub;
159 struct GNUNET_CRYPTO_RsaPublicKey *pub2;
160 struct GNUNET_JSON_Specification pspec[] =
161 { GNUNET_JSON_spec_rsa_public_key (NULL, &pub2), GNUNET_JSON_spec_end () };
162 struct GNUNET_CRYPTO_RsaSignature *sig;
163 struct GNUNET_CRYPTO_RsaSignature *sig2;
164 struct GNUNET_JSON_Specification sspec[] =
165 { GNUNET_JSON_spec_rsa_signature (NULL, &sig2), GNUNET_JSON_spec_end () };
166 struct GNUNET_CRYPTO_RsaPrivateKey *priv;
167 struct GNUNET_HashCode msg;
168 json_t *jp;
169 json_t *js;
170
171 priv = GNUNET_CRYPTO_rsa_private_key_create (1024);
172 pub = GNUNET_CRYPTO_rsa_private_key_get_public (priv);
173 memset (&msg, 42, sizeof(msg));
174 sig = GNUNET_CRYPTO_rsa_sign_fdh (priv, &msg, sizeof (msg));
175 GNUNET_assert (NULL != (jp = GNUNET_JSON_from_rsa_public_key (pub)));
176 GNUNET_assert (NULL != (js = GNUNET_JSON_from_rsa_signature (sig)));
177 GNUNET_assert (GNUNET_OK == GNUNET_JSON_parse (jp, pspec, NULL, NULL));
178 GNUNET_assert (GNUNET_OK == GNUNET_JSON_parse (js, sspec, NULL, NULL));
179 GNUNET_break (0 == GNUNET_CRYPTO_rsa_signature_cmp (sig, sig2));
180 GNUNET_break (0 == GNUNET_CRYPTO_rsa_public_key_cmp (pub, pub2));
181 json_decref (jp);
182 json_decref (js);
183 GNUNET_CRYPTO_rsa_signature_free (sig);
184 GNUNET_CRYPTO_rsa_signature_free (sig2);
185 GNUNET_CRYPTO_rsa_private_key_free (priv);
186 GNUNET_CRYPTO_rsa_public_key_free (pub);
187 GNUNET_CRYPTO_rsa_public_key_free (pub2);
188 return 0;
189}
190
191
192/**
193 * Test rsa conversions from/to JSON.
194 *
195 * @return 0 on success
196 */
197static int
198test_boolean ()
199{
200 int b1;
201 int b2;
202 json_t *json;
203 struct GNUNET_JSON_Specification pspec[] = { GNUNET_JSON_spec_boolean ("b1",
204 &b1),
205 GNUNET_JSON_spec_boolean ("b2",
206 &b2),
207 GNUNET_JSON_spec_end () };
208
209 json = json_object ();
210 json_object_set_new (json, "b1", json_true ());
211 json_object_set_new (json, "b2", json_false ());
212
213 GNUNET_assert (GNUNET_OK == GNUNET_JSON_parse (json, pspec, NULL, NULL));
214
215 GNUNET_assert (GNUNET_YES == b1);
216 GNUNET_assert (GNUNET_NO == b2);
217
218 json_object_set_new (json, "b1", json_integer (42));
219
220 GNUNET_assert (GNUNET_OK != GNUNET_JSON_parse (json, pspec, NULL, NULL));
221
222 json_decref (json);
223
224 return 0;
225}
226
227
228int
229main (int argc, const char *const argv[])
230{
231 GNUNET_log_setup ("test-json", "WARNING", NULL);
232 if (0 != test_timestamp ())
233 return 1;
234 if (0 != test_rel_time ())
235 return 1;
236 if (0 != test_raw ())
237 return 1;
238 if (0 != test_rsa ())
239 return 1;
240 if (0 != test_boolean ())
241 return 1;
242 /* FIXME: test EdDSA signature conversion... */
243 return 0;
244}
245
246
247/* end of test_json.c */
diff --git a/src/lib/json/test_json_mhd.c b/src/lib/json/test_json_mhd.c
new file mode 100644
index 000000000..642715f25
--- /dev/null
+++ b/src/lib/json/test_json_mhd.c
@@ -0,0 +1,193 @@
1/*
2 This file is part of GNUnet
3 (C) 2019 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 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file json/test_json_mhd.c
23 * @brief Tests for JSON MHD integration functions
24 * @author Christian Grothoff <christian@grothoff.org>
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_json_lib.h"
29#include "gnunet_curl_lib.h"
30#include "gnunet_mhd_compat.h"
31#include <zlib.h>
32
33#define MAX_SIZE 1024 * 1024
34
35static json_t *bigj;
36
37static int global_ret;
38
39
40static MHD_RESULT
41access_handler_cb (void *cls,
42 struct MHD_Connection *connection,
43 const char *url,
44 const char *method,
45 const char *version,
46 const char *upload_data,
47 size_t *upload_data_size,
48 void **con_cls)
49{
50 int ret;
51 json_t *json;
52 struct MHD_Response *resp;
53
54 json = NULL;
55 ret = GNUNET_JSON_post_parser (MAX_SIZE,
56 connection,
57 con_cls,
58 upload_data,
59 upload_data_size,
60 &json);
61 switch (ret)
62 {
63 case GNUNET_JSON_PR_SUCCESS:
64 if (json_equal (bigj, json))
65 {
66 global_ret = 0;
67 }
68 else
69 {
70 GNUNET_break (0);
71 global_ret = 6;
72 }
73 json_decref (json);
74 resp = MHD_create_response_from_buffer (3, "OK\n", MHD_RESPMEM_PERSISTENT);
75 ret = MHD_queue_response (connection, MHD_HTTP_OK, resp);
76 MHD_destroy_response (resp);
77 return ret;
78
79 case GNUNET_JSON_PR_CONTINUE:
80 return MHD_YES;
81
82 case GNUNET_JSON_PR_OUT_OF_MEMORY:
83 GNUNET_break (0);
84 global_ret = 3;
85 break;
86
87 case GNUNET_JSON_PR_REQUEST_TOO_LARGE:
88 GNUNET_break (0);
89 global_ret = 4;
90 break;
91
92 case GNUNET_JSON_PR_JSON_INVALID:
93 GNUNET_break (0);
94 global_ret = 5;
95 break;
96 }
97 GNUNET_break (0);
98 return MHD_NO;
99}
100
101
102int
103main (int argc, const char *const argv[])
104{
105 struct MHD_Daemon *daemon;
106 uint16_t port;
107 CURL *easy;
108 char *url;
109 char *str;
110 size_t slen;
111 long post_data_size;
112 void *post_data;
113 uLongf dlen;
114 struct curl_slist *json_header;
115
116 GNUNET_log_setup ("test-json-mhd", "WARNING", NULL);
117 global_ret = 2;
118 daemon = MHD_start_daemon (MHD_USE_DUAL_STACK | MHD_USE_AUTO_INTERNAL_THREAD,
119 0,
120 NULL,
121 NULL,
122 &access_handler_cb,
123 NULL,
124 MHD_OPTION_END);
125 if (NULL == daemon)
126 return 77;
127 bigj = json_object ();
128 json_object_set_new (bigj, "test", json_string ("value"));
129 for (unsigned int i = 0; i < 1000; i++)
130 {
131 char tmp[5];
132
133 GNUNET_snprintf (tmp, sizeof(tmp), "%u", i);
134 json_object_set_new (bigj, tmp, json_string (tmp));
135 }
136 str = json_dumps (bigj, JSON_INDENT (2));
137 slen = strlen (str);
138
139#ifdef compressBound
140 dlen = compressBound (slen);
141#else
142 dlen = slen + slen / 100 + 20;
143 /* documentation says 100.1% oldSize + 12 bytes, but we
144 * should be able to overshoot by more to be safe */
145#endif
146 post_data = GNUNET_malloc (dlen);
147 if (Z_OK !=
148 compress2 ((Bytef *) post_data, &dlen, (const Bytef *) str, slen, 9))
149 {
150 GNUNET_break (0);
151 MHD_stop_daemon (daemon);
152 json_decref (bigj);
153 GNUNET_free (post_data);
154 GNUNET_free (str);
155 return 1;
156 }
157 post_data_size = (long) dlen;
158 port = MHD_get_daemon_info (daemon, MHD_DAEMON_INFO_BIND_PORT)->port;
159 easy = curl_easy_init ();
160 GNUNET_asprintf (&url, "http://localhost:%u/", (unsigned int) port);
161 curl_easy_setopt (easy, CURLOPT_VERBOSE, 0);
162 curl_easy_setopt (easy, CURLOPT_URL, url);
163 curl_easy_setopt (easy, CURLOPT_POST, 1);
164 curl_easy_setopt (easy, CURLOPT_POSTFIELDS, post_data);
165 curl_easy_setopt (easy, CURLOPT_POSTFIELDSIZE, post_data_size);
166
167 json_header = curl_slist_append (NULL, "Content-Type: application/json");
168 json_header = curl_slist_append (json_header, "Content-Encoding: deflate");
169 curl_easy_setopt (easy, CURLOPT_HTTPHEADER, json_header);
170 if (0 != curl_easy_perform (easy))
171 {
172 GNUNET_break (0);
173 MHD_stop_daemon (daemon);
174 GNUNET_free (url);
175 json_decref (bigj);
176 GNUNET_free (post_data);
177 GNUNET_free (str);
178 curl_slist_free_all (json_header);
179 curl_easy_cleanup (easy);
180 return 1;
181 }
182 MHD_stop_daemon (daemon);
183 GNUNET_free (url);
184 json_decref (bigj);
185 GNUNET_free (post_data);
186 GNUNET_free (str);
187 curl_slist_free_all (json_header);
188 curl_easy_cleanup (easy);
189 return global_ret;
190}
191
192
193/* end of test_json_mhd.c */