GNUnet  0.11.x
json_mhd.c
Go to the documentation of this file.
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  */
27 #include "platform.h"
28 #include "gnunet_json_lib.h"
29 #include <zlib.h>
30 
31 
37 #define REQUEST_BUFFER_INITIAL (2 * 1024)
38 
39 
43 struct Buffer
44 {
48  char *data;
49 
53  size_t fill;
54 
58  size_t alloc;
59 
63  size_t max;
64 };
65 
66 
77 static int
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 
103 static void
105 {
106  GNUNET_free (buf->data);
107  buf->data = NULL;
108 }
109 
110 
121 static int
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 
155 static enum GNUNET_JSON_PostResult
156 inflate_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);
176 
177  case Z_STREAM_ERROR:
178  GNUNET_break_op (0);
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);
194  case Z_MEM_ERROR:
195  GNUNET_break (0);
196  GNUNET_break (Z_OK == inflateEnd (&z));
197  GNUNET_free (tmp);
199  case Z_DATA_ERROR:
200  GNUNET_break_op (0);
201  GNUNET_break (Z_OK == inflateEnd (&z));
202  GNUNET_free (tmp);
204  case Z_NEED_DICT:
205  GNUNET_break_op (0);
206  GNUNET_break (Z_OK == inflateEnd (&z));
207  GNUNET_free (tmp);
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);
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);
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 
265 GNUNET_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,
285  buffer_max))
286  {
287  *con_cls = NULL;
288  buffer_deinit (r);
289  GNUNET_free (r);
291  }
292  /* everything OK, wait for more POST data */
293  *upload_data_size = 0;
294  *con_cls = r;
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);
309  }
310  /* everything OK, wait for more POST data */
311  *upload_data_size = 0;
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);
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  {
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;
349  }
350  }
351  buffer_deinit (r);
352  GNUNET_free (r);
353  *con_cls = NULL;
354 
355  return GNUNET_JSON_PR_SUCCESS;
356 }
357 
358 
366 void
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 */
static int ret
Return value of the commandline.
Definition: gnunet-abd.c:81
static size_t data_size
Number of bytes in data.
Definition: gnunet-abd.c:187
uint32_t data
The data value.
static size_t max_size
The maximal size the extended sampler elements should grow to.
static char buf[2048]
#define GNUNET_log(kind,...)
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
@ GNUNET_OK
Definition: gnunet_common.h:95
@ GNUNET_NO
Definition: gnunet_common.h:94
@ GNUNET_SYSERR
Definition: gnunet_common.h:93
#define GNUNET_MIN(a, b)
functions to parse JSON objects into GNUnet objects
GNUNET_JSON_PostResult
Return codes from GNUNET_JSON_post_parser().
@ GNUNET_JSON_PR_CONTINUE
Parsing continues, call again soon!
@ GNUNET_JSON_PR_OUT_OF_MEMORY
Sorry, memory allocation (malloc()) failed.
@ GNUNET_JSON_PR_JSON_INVALID
JSON parsing failed.
@ GNUNET_JSON_PR_REQUEST_TOO_LARGE
Request size exceeded buffer_max argument.
@ GNUNET_JSON_PR_SUCCESS
Parsing successful, JSON result is in *json.
#define GNUNET_break_op(cond)
Use this for assertion violations caused by other peers (i.e.
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur.
@ GNUNET_ERROR_TYPE_WARNING
#define GNUNET_new(type)
Allocate a struct or union of the given type.
#define GNUNET_malloc(size)
Wrapper around malloc.
#define GNUNET_realloc(ptr, size)
Wrapper around realloc.
#define GNUNET_free(ptr)
Wrapper around free.
static int buffer_init(struct Buffer *buf, const void *data, size_t data_size, size_t alloc_size, size_t max_size)
Initialize a buffer.
Definition: json_mhd.c:78
#define REQUEST_BUFFER_INITIAL
Initial size for POST request buffers.
Definition: json_mhd.c:37
enum GNUNET_JSON_PostResult GNUNET_JSON_post_parser(size_t buffer_max, struct MHD_Connection *connection, void **con_cls, const char *upload_data, size_t *upload_data_size, json_t **json)
Process a POST request containing a JSON object.
Definition: json_mhd.c:265
static enum GNUNET_JSON_PostResult inflate_data(struct Buffer *buf)
Decompress data in buf.
Definition: json_mhd.c:156
static void buffer_deinit(struct Buffer *buf)
Free the data in a buffer.
Definition: json_mhd.c:104
static int buffer_append(struct Buffer *buf, const void *data, size_t data_size, size_t max_size)
Append data to a buffer, growing the buffer if necessary.
Definition: json_mhd.c:122
void GNUNET_JSON_post_parser_cleanup(void *con_cls)
Function called whenever we are done with a request to clean up our state.
Definition: json_mhd.c:367
Buffer for POST requests.
Definition: json_mhd.c:44
size_t max
Maximum buffer size allowed.
Definition: json_mhd.c:63
size_t fill
Number of valid bytes in buffer.
Definition: json_mhd.c:53
size_t alloc
Number of allocated bytes in buffer.
Definition: json_mhd.c:58
char * data
Allocated memory.
Definition: json_mhd.c:48