GNUnet  0.10.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 {
47  char *data;
48 
52  size_t fill;
53 
57  size_t alloc;
58 
62  size_t max;
63 };
64 
65 
76 static int
78  const void *data,
79  size_t data_size,
80  size_t alloc_size,
81  size_t max_size)
82 {
83  if ((data_size > max_size) || (alloc_size > max_size))
84  return GNUNET_SYSERR;
85  if (data_size > alloc_size)
86  alloc_size = data_size;
87  buf->data = GNUNET_malloc(alloc_size);
88  buf->alloc = alloc_size;
89  GNUNET_memcpy(buf->data, data, data_size);
90  buf->fill = data_size;
91  buf->max = max_size;
92  return GNUNET_OK;
93 }
94 
95 
102 static void
104 {
105  GNUNET_free(buf->data);
106  buf->data = NULL;
107 }
108 
109 
120 static int
122  const void *data,
123  size_t data_size,
124  size_t max_size)
125 {
126  if (buf->fill + data_size > max_size)
127  return GNUNET_NO;
128  if (buf->fill + data_size > buf->alloc)
129  {
130  char *new_buf;
131  size_t new_size = buf->alloc;
132  while (new_size < buf->fill + data_size)
133  new_size += 2;
134  if (new_size > max_size)
135  return GNUNET_NO;
136  new_buf = GNUNET_malloc(new_size);
137  GNUNET_memcpy(new_buf, buf->data, buf->fill);
138  GNUNET_free(buf->data);
139  buf->data = new_buf;
140  buf->alloc = new_size;
141  }
142  GNUNET_memcpy(buf->data + buf->fill, data, data_size);
143  buf->fill += data_size;
144  return GNUNET_OK;
145 }
146 
147 
154 static enum GNUNET_JSON_PostResult
156 {
157  z_stream z;
158  char *tmp;
159  size_t tmp_size;
160  int ret;
161 
162  memset(&z, 0, sizeof(z));
163  z.next_in = (Bytef *)buf->data;
164  z.avail_in = buf->fill;
165  tmp_size = GNUNET_MIN(buf->max, buf->fill * 4);
166  tmp = GNUNET_malloc(tmp_size);
167  z.next_out = (Bytef *)tmp;
168  z.avail_out = tmp_size;
169  ret = inflateInit(&z);
170  switch (ret)
171  {
172  case Z_MEM_ERROR:
173  GNUNET_break(0);
175 
176  case Z_STREAM_ERROR:
177  GNUNET_break_op(0);
179 
180  case Z_OK:
181  break;
182  }
183  while (1)
184  {
185  ret = inflate(&z, 0);
186  switch (ret)
187  {
188  case Z_MEM_ERROR:
189  GNUNET_break(0);
190  GNUNET_break(Z_OK == inflateEnd(&z));
191  GNUNET_free(tmp);
193 
194  case Z_DATA_ERROR:
195  GNUNET_break(0);
196  GNUNET_break(Z_OK == inflateEnd(&z));
197  GNUNET_free(tmp);
199 
200  case Z_NEED_DICT:
201  GNUNET_break(0);
202  GNUNET_break(Z_OK == inflateEnd(&z));
203  GNUNET_free(tmp);
205 
206  case Z_OK:
207  if ((0 < z.avail_out) && (0 == z.avail_in))
208  {
209  /* truncated input stream */
210  GNUNET_break(0);
211  GNUNET_break(Z_OK == inflateEnd(&z));
212  GNUNET_free(tmp);
214  }
215  if (0 < z.avail_out)
216  continue; /* just call it again */
217  /* output buffer full, can we grow it? */
218  if (tmp_size == buf->max)
219  {
220  /* already at max */
221  GNUNET_break(0);
222  GNUNET_break(Z_OK == inflateEnd(&z));
223  GNUNET_free(tmp);
225  }
226  if (tmp_size * 2 < tmp_size)
227  tmp_size = buf->max;
228  else
229  tmp_size = GNUNET_MIN(buf->max, tmp_size * 2);
230  tmp = GNUNET_realloc(tmp, tmp_size);
231  z.next_out = (Bytef *)&tmp[z.total_out];
232  continue;
233 
234  case Z_STREAM_END:
235  /* decompression successful, make 'tmp' the new 'data' */
236  GNUNET_free(buf->data);
237  buf->data = tmp;
238  buf->alloc = tmp_size;
239  buf->fill = z.total_out;
240  GNUNET_break(Z_OK == inflateEnd(&z));
241  return GNUNET_JSON_PR_SUCCESS; /* at least for now */
242  }
243  } /* while (1) */
244 }
245 
246 
263 GNUNET_JSON_post_parser(size_t buffer_max,
264  struct MHD_Connection *connection,
265  void **con_cls,
266  const char *upload_data,
267  size_t *upload_data_size,
268  json_t **json)
269 {
270  struct Buffer *r = *con_cls;
271  const char *ce;
272  int ret;
273 
274  *json = NULL;
275  if (NULL == *con_cls)
276  {
277  /* We are seeing a fresh POST request. */
278  r = GNUNET_new(struct Buffer);
279  if (GNUNET_OK != buffer_init(r,
280  upload_data,
281  *upload_data_size,
283  buffer_max))
284  {
285  *con_cls = NULL;
286  buffer_deinit(r);
287  GNUNET_free(r);
289  }
290  /* everything OK, wait for more POST data */
291  *upload_data_size = 0;
292  *con_cls = r;
294  }
295  if (0 != *upload_data_size)
296  {
297  /* We are seeing an old request with more data available. */
298 
299  if (GNUNET_OK !=
300  buffer_append(r, upload_data, *upload_data_size, buffer_max))
301  {
302  /* Request too long */
303  *con_cls = NULL;
304  buffer_deinit(r);
305  GNUNET_free(r);
307  }
308  /* everything OK, wait for more POST data */
309  *upload_data_size = 0;
311  }
312 
313  /* We have seen the whole request. */
314  ce = MHD_lookup_connection_value(connection,
315  MHD_HEADER_KIND,
316  MHD_HTTP_HEADER_CONTENT_ENCODING);
317  if ((NULL != ce) && (0 == strcasecmp("deflate", ce)))
318  {
319  ret = inflate_data(r);
320  if (GNUNET_JSON_PR_SUCCESS != ret)
321  {
322  buffer_deinit(r);
323  GNUNET_free(r);
324  *con_cls = NULL;
325  return ret;
326  }
327  }
328 
329  *json = json_loadb(r->data, r->fill, 0, NULL);
330  if (NULL == *json)
331  {
333  "Failed to parse JSON request body\n");
334  buffer_deinit(r);
335  GNUNET_free(r);
336  *con_cls = NULL;
338  }
339  buffer_deinit(r);
340  GNUNET_free(r);
341  *con_cls = NULL;
342 
343  return GNUNET_JSON_PR_SUCCESS;
344 }
345 
346 
354 void
356 {
357  struct Buffer *r = con_cls;
358 
359  if (NULL != r)
360  {
361  buffer_deinit(r);
362  GNUNET_free(r);
363  }
364 }
365 
366 /* end of mhd_json.c */
JSON parsing failed.
static enum GNUNET_JSON_PostResult inflate_data(struct Buffer *buf)
Decompress data in buf.
Definition: json_mhd.c:155
functions to parse JSON objects into GNUnet objects
size_t alloc
Number of allocated bytes in buffer.
Definition: json_mhd.c:57
Buffer for POST requests.
Definition: json_mhd.c:43
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
#define GNUNET_NO
Definition: gnunet_common.h:78
#define GNUNET_OK
Named constants for return values.
Definition: gnunet_common.h:75
#define GNUNET_new(type)
Allocate a struct or union of the given type.
static int ret
Final status code.
Definition: gnunet-arm.c:89
size_t fill
Number of valid bytes in buffer.
Definition: json_mhd.c:52
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur...
Parsing successful, JSON result is in *json.
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:77
#define GNUNET_break_op(cond)
Use this for assertion violations caused by other peers (i.e.
#define GNUNET_realloc(ptr, size)
Wrapper around realloc.
#define GNUNET_MIN(a, b)
Definition: gnunet_common.h:80
static char buf[2048]
Sorry, memory allocation (malloc()) failed.
Request size exceeded buffer_max argument.
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:121
size_t max
Maximum buffer size allowed.
Definition: json_mhd.c:62
char * data
Allocated memory.
Definition: json_mhd.c:47
#define REQUEST_BUFFER_INITIAL
Initial size for POST request buffers.
Definition: json_mhd.c:37
#define GNUNET_SYSERR
Definition: gnunet_common.h:76
static size_t max_size
The maximal size the extended sampler elements should grow to.
GNUNET_JSON_PostResult
Return codes from GNUNET_JSON_post_parser().
Parsing continues, call again soon!
#define GNUNET_log(kind,...)
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:355
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:263
static void buffer_deinit(struct Buffer *buf)
Free the data in a buffer.
Definition: json_mhd.c:103
static size_t data_size
Number of bytes in data.
#define GNUNET_malloc(size)
Wrapper around malloc.
#define GNUNET_free(ptr)
Wrapper around free.