remove 'illegal' (non-reentrant) log logic from signal handler
[oweals/gnunet.git] / src / json / json_mhd.c
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  */
43 struct 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  */
77 static int
78 buffer_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  */
103 static void
104 buffer_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 accomodate for the new data
120  */
121 static int
122 buffer_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  */
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);
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  */
264 enum GNUNET_JSON_PostResult
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,
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   *json = json_loadb (r->data, r->fill, 0, NULL);
332   if (NULL == *json)
333   {
334     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
335                 "Failed to parse JSON request body\n");
336     buffer_deinit (r);
337     GNUNET_free (r);
338     *con_cls = NULL;
339     return GNUNET_JSON_PR_JSON_INVALID;
340   }
341   buffer_deinit (r);
342   GNUNET_free (r);
343   *con_cls = NULL;
344
345   return GNUNET_JSON_PR_SUCCESS;
346 }
347
348
349 /**
350  * Function called whenever we are done with a request
351  * to clean up our state.
352  *
353  * @param con_cls value as it was left by
354  *        #GNUNET_JSON_post_parser(), to be cleaned up
355  */
356 void
357 GNUNET_JSON_post_parser_cleanup (void *con_cls)
358 {
359   struct Buffer *r = con_cls;
360
361   if (NULL != r)
362   {
363     buffer_deinit (r);
364     GNUNET_free (r);
365   }
366 }
367
368
369 /* end of mhd_json.c */