2 This file is part of GNUnet
3 Copyright (C) 2014, 2015, 2016 GNUnet e.V.
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.
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.
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/>.
18 SPDX-License-Identifier: AGPL3.0-or-later
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
28 #include "gnunet_json_lib.h"
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.
37 #define REQUEST_BUFFER_INITIAL (2 * 1024)
41 * Buffer for POST requests.
51 * Number of valid bytes in buffer.
56 * Number of allocated bytes in buffer.
61 * Maximum buffer size allowed.
68 * Initialize a buffer.
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
78 buffer_init (struct Buffer *buf,
84 if ((data_size > max_size) || (alloc_size > max_size))
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;
98 * Free the data in a buffer. Does *not* free
99 * the buffer object itself.
101 * @param buf buffer to de-initialize
104 buffer_deinit (struct Buffer *buf)
106 GNUNET_free (buf->data);
112 * Append data to a buffer, growing the buffer if necessary.
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 accomodate for the new data
122 buffer_append (struct Buffer *buf,
127 if (buf->fill + data_size > max_size)
129 if (buf->fill + data_size > buf->alloc)
132 size_t new_size = buf->alloc;
133 while (new_size < buf->fill + data_size)
135 if (new_size > max_size)
137 new_buf = GNUNET_malloc (new_size);
138 GNUNET_memcpy (new_buf, buf->data, buf->fill);
139 GNUNET_free (buf->data);
141 buf->alloc = new_size;
143 GNUNET_memcpy (buf->data + buf->fill, data, data_size);
144 buf->fill += data_size;
150 * Decompress data in @a buf.
152 * @param buf input data to inflate
153 * @return result code indicating the status of the operation
155 static enum GNUNET_JSON_PostResult
156 inflate_data (struct Buffer *buf)
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);
175 return GNUNET_JSON_PR_OUT_OF_MEMORY;
179 return GNUNET_JSON_PR_JSON_INVALID;
186 ret = inflate (&z, 0);
191 GNUNET_break (Z_OK == inflateEnd (&z));
193 return GNUNET_JSON_PR_JSON_INVALID;
196 GNUNET_break (Z_OK == inflateEnd (&z));
198 return GNUNET_JSON_PR_OUT_OF_MEMORY;
201 GNUNET_break (Z_OK == inflateEnd (&z));
203 return GNUNET_JSON_PR_JSON_INVALID;
206 GNUNET_break (Z_OK == inflateEnd (&z));
208 return GNUNET_JSON_PR_JSON_INVALID;
210 if ((0 < z.avail_out) && (0 == z.avail_in))
212 /* truncated input stream */
214 GNUNET_break (Z_OK == inflateEnd (&z));
216 return GNUNET_JSON_PR_JSON_INVALID;
219 continue; /* just call it again */
220 /* output buffer full, can we grow it? */
221 if (tmp_size == buf->max)
225 GNUNET_break (Z_OK == inflateEnd (&z));
227 return GNUNET_JSON_PR_OUT_OF_MEMORY;
229 if (tmp_size * 2 < tmp_size)
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];
237 /* decompression successful, make 'tmp' the new 'data' */
238 GNUNET_free (buf->data);
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 */
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().
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
264 enum GNUNET_JSON_PostResult
265 GNUNET_JSON_post_parser (size_t buffer_max,
266 struct MHD_Connection *connection,
268 const char *upload_data,
269 size_t *upload_data_size,
272 struct Buffer *r = *con_cls;
277 if (NULL == *con_cls)
279 /* We are seeing a fresh POST request. */
280 r = GNUNET_new (struct Buffer);
281 if (GNUNET_OK != buffer_init (r,
284 REQUEST_BUFFER_INITIAL,
290 return GNUNET_JSON_PR_OUT_OF_MEMORY;
292 /* everything OK, wait for more POST data */
293 *upload_data_size = 0;
295 return GNUNET_JSON_PR_CONTINUE;
297 if (0 != *upload_data_size)
299 /* We are seeing an old request with more data available. */
302 buffer_append (r, upload_data, *upload_data_size, buffer_max))
304 /* Request too long */
308 return GNUNET_JSON_PR_REQUEST_TOO_LARGE;
310 /* everything OK, wait for more POST data */
311 *upload_data_size = 0;
312 return GNUNET_JSON_PR_CONTINUE;
315 /* We have seen the whole request. */
316 ce = MHD_lookup_connection_value (connection,
318 MHD_HTTP_HEADER_CONTENT_ENCODING);
319 if ((NULL != ce) && (0 == strcasecmp ("deflate", ce)))
321 ret = inflate_data (r);
322 if (GNUNET_JSON_PR_SUCCESS != ret)
331 *json = json_loadb (r->data, r->fill, 0, NULL);
334 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
335 "Failed to parse JSON request body\n");
339 return GNUNET_JSON_PR_JSON_INVALID;
345 return GNUNET_JSON_PR_SUCCESS;
350 * Function called whenever we are done with a request
351 * to clean up our state.
353 * @param con_cls value as it was left by
354 * #GNUNET_JSON_post_parser(), to be cleaned up
357 GNUNET_JSON_post_parser_cleanup (void *con_cls)
359 struct Buffer *r = con_cls;
369 /* end of mhd_json.c */