GNUnet 0.24.1-14-gdb0ea5ed9
mhd_upload.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_mhd_lib.h"
29#include <zlib.h>
30#include <jansson.h>
31
32
38#define REQUEST_BUFFER_INITIAL (2 * 1024)
39
40
44struct Buffer
45{
49 char *data;
50
54 size_t fill;
55
59 size_t alloc;
60
64 size_t max;
65};
66
67
78static int
79buffer_init (struct Buffer *buf,
80 const void *data,
81 size_t data_size,
82 size_t alloc_size,
83 size_t max_size)
84{
85 if ((data_size > max_size) || (alloc_size > max_size))
86 return GNUNET_SYSERR;
87 if (data_size > alloc_size)
88 alloc_size = data_size;
89 buf->data = GNUNET_malloc (alloc_size);
90 buf->alloc = alloc_size;
92 buf->fill = data_size;
93 buf->max = max_size;
94 return GNUNET_OK;
95}
96
97
104static void
106{
107 GNUNET_free (buf->data);
108 buf->data = NULL;
109}
110
111
122static int
124 const void *data,
125 size_t data_size,
126 size_t max_size)
127{
128 if (buf->fill + data_size > max_size)
129 return GNUNET_NO;
130 if (buf->fill + data_size > buf->alloc)
131 {
132 char *new_buf;
133 size_t new_size = buf->alloc;
134 while (new_size < buf->fill + data_size)
135 new_size += 2;
136 if (new_size > max_size)
137 return GNUNET_NO;
138 new_buf = GNUNET_malloc (new_size);
139 GNUNET_memcpy (new_buf, buf->data, buf->fill);
140 GNUNET_free (buf->data);
141 buf->data = new_buf;
142 buf->alloc = new_size;
143 }
144 GNUNET_memcpy (buf->data + buf->fill, data, data_size);
145 buf->fill += data_size;
146 return GNUNET_OK;
147}
148
149
156static enum GNUNET_MHD_PostResult
157inflate_data (struct Buffer *buf)
158{
159 z_stream z;
160 char *tmp;
161 size_t tmp_size;
162 int ret;
163
164 memset (&z, 0, sizeof(z));
165 z.next_in = (Bytef *) buf->data;
166 z.avail_in = buf->fill;
167 tmp_size = GNUNET_MIN (buf->max, buf->fill * 4);
168 tmp = GNUNET_malloc (tmp_size);
169 z.next_out = (Bytef *) tmp;
170 z.avail_out = tmp_size;
171 ret = inflateInit (&z);
172 switch (ret)
173 {
174 case Z_MEM_ERROR:
175 GNUNET_break (0);
177
178 case Z_STREAM_ERROR:
179 GNUNET_break_op (0);
181
182 case Z_OK:
183 break;
184 }
185 while (1)
186 {
187 ret = inflate (&z, 0);
188 switch (ret)
189 {
190 case Z_BUF_ERROR:
191 GNUNET_break_op (0);
192 GNUNET_break (Z_OK == inflateEnd (&z));
193 GNUNET_free (tmp);
195 case Z_MEM_ERROR:
196 GNUNET_break (0);
197 GNUNET_break (Z_OK == inflateEnd (&z));
198 GNUNET_free (tmp);
200 case Z_DATA_ERROR:
201 GNUNET_break_op (0);
202 GNUNET_break (Z_OK == inflateEnd (&z));
203 GNUNET_free (tmp);
205 case Z_NEED_DICT:
206 GNUNET_break_op (0);
207 GNUNET_break (Z_OK == inflateEnd (&z));
208 GNUNET_free (tmp);
210 case Z_OK:
211 if ((0 < z.avail_out) && (0 == z.avail_in))
212 {
213 /* truncated input stream */
214 GNUNET_break (0);
215 GNUNET_break (Z_OK == inflateEnd (&z));
216 GNUNET_free (tmp);
218 }
219 if (0 < z.avail_out)
220 continue; /* just call it again */
221 /* output buffer full, can we grow it? */
222 if (tmp_size == buf->max)
223 {
224 /* already at max */
225 GNUNET_break (0);
226 GNUNET_break (Z_OK == inflateEnd (&z));
227 GNUNET_free (tmp);
229 }
230 if (tmp_size * 2 < tmp_size)
231 tmp_size = buf->max;
232 else
233 tmp_size = GNUNET_MIN (buf->max, tmp_size * 2);
234 tmp = GNUNET_realloc (tmp, tmp_size);
235 z.next_out = (Bytef *) &tmp[z.total_out];
236 continue;
237 case Z_STREAM_END:
238 /* decompression successful, make 'tmp' the new 'data' */
239 GNUNET_free (buf->data);
240 buf->data = tmp;
241 buf->alloc = tmp_size;
242 buf->fill = z.total_out;
243 GNUNET_break (Z_OK == inflateEnd (&z));
244 return GNUNET_MHD_PR_SUCCESS; /* at least for now */
245 }
246 } /* while (1) */
247}
248
249
266GNUNET_MHD_post_parser (size_t buffer_max,
267 struct MHD_Connection *connection,
268 void **con_cls,
269 const char *upload_data,
270 size_t *upload_data_size,
271 json_t **json)
272{
273 struct Buffer *r = *con_cls;
274 const char *ce;
275 int ret;
276
277 *json = NULL;
278 if (NULL == *con_cls)
279 {
280 /* We are seeing a fresh POST request. */
281 r = GNUNET_new (struct Buffer);
282 if (GNUNET_OK != buffer_init (r,
283 upload_data,
284 *upload_data_size,
286 buffer_max))
287 {
288 *con_cls = NULL;
289 buffer_deinit (r);
290 GNUNET_free (r);
292 }
293 /* everything OK, wait for more POST data */
294 *upload_data_size = 0;
295 *con_cls = r;
297 }
298 if (0 != *upload_data_size)
299 {
300 /* We are seeing an old request with more data available. */
301
302 if (GNUNET_OK !=
303 buffer_append (r, upload_data, *upload_data_size, buffer_max))
304 {
305 /* Request too long */
306 *con_cls = NULL;
307 buffer_deinit (r);
308 GNUNET_free (r);
310 }
311 /* everything OK, wait for more POST data */
312 *upload_data_size = 0;
314 }
315
316 /* We have seen the whole request. */
317 ce = MHD_lookup_connection_value (connection,
318 MHD_HEADER_KIND,
319 MHD_HTTP_HEADER_CONTENT_ENCODING);
320 if ((NULL != ce) && (0 == strcasecmp ("deflate", ce)))
321 {
322 ret = inflate_data (r);
324 {
325 buffer_deinit (r);
326 GNUNET_free (r);
327 *con_cls = NULL;
328 return ret;
329 }
330 }
331
332 {
333 json_error_t err;
334
335 *json = json_loadb (r->data,
336 r->fill,
337 0,
338 &err);
339 if (NULL == *json)
340 {
342 "Failed to parse JSON request body of %u byte at offset %d: %s\n",
343 (unsigned int) r->fill,
344 err.position,
345 err.text);
346 buffer_deinit (r);
347 GNUNET_free (r);
348 *con_cls = NULL;
350 }
351 }
352 buffer_deinit (r);
353 GNUNET_free (r);
354 *con_cls = NULL;
355
357}
358
359
367void
369{
370 struct Buffer *r = con_cls;
371
372 if (NULL != r)
373 {
374 buffer_deinit (r);
375 GNUNET_free (r);
376 }
377}
378
379
380/* end of mhd_upload.c */
static int ret
Final status code.
Definition: gnunet-arm.c:93
static char * data
The data to insert into the dht.
static size_t data_size
Number of bytes in data.
static size_t max_size
The maximal size the extended sampler elements should grow to.
functions to parse HTTP uploads with MHD
GNUNET_MHD_PostResult
Return codes from GNUNET_MHD_post_parser().
@ GNUNET_MHD_PR_CONTINUE
Parsing continues, call again soon!
@ GNUNET_MHD_PR_SUCCESS
Parsing successful, JSON result is in *json.
@ GNUNET_MHD_PR_OUT_OF_MEMORY
Sorry, memory allocation (malloc()) failed.
@ GNUNET_MHD_PR_REQUEST_TOO_LARGE
Request size exceeded buffer_max argument.
@ GNUNET_MHD_PR_JSON_INVALID
JSON parsing failed.
#define GNUNET_log(kind,...)
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
#define GNUNET_MIN(a, b)
@ GNUNET_OK
@ GNUNET_NO
@ GNUNET_SYSERR
#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 enum GNUNET_MHD_PostResult inflate_data(struct Buffer *buf)
Decompress data in buf.
Definition: mhd_upload.c:157
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: mhd_upload.c:79
#define REQUEST_BUFFER_INITIAL
Initial size for POST request buffers.
Definition: mhd_upload.c:38
enum GNUNET_MHD_PostResult GNUNET_MHD_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: mhd_upload.c:266
void GNUNET_MHD_post_parser_cleanup(void *con_cls)
Function called whenever we are done with a request to clean up our state.
Definition: mhd_upload.c:368
static void buffer_deinit(struct Buffer *buf)
Free the data in a buffer.
Definition: mhd_upload.c:105
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: mhd_upload.c:123
Buffer for POST requests.
Definition: mhd_upload.c:45
size_t max
Maximum buffer size allowed.
Definition: mhd_upload.c:64
size_t fill
Number of valid bytes in buffer.
Definition: mhd_upload.c:54
size_t alloc
Number of allocated bytes in buffer.
Definition: mhd_upload.c:59
char * data
Allocated memory.
Definition: mhd_upload.c:49