GNUnet debian-0.24.3
mhd_upload.c
Go to the documentation of this file.
1/*
2 This file is part of GNUnet
3 Copyright (C) 2014, 2015, 2016, 2025 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
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) ||
86 (alloc_size > max_size) )
87 return GNUNET_SYSERR;
88 if (data_size > alloc_size)
89 alloc_size = data_size;
90 buf->data = GNUNET_malloc (alloc_size);
91 buf->alloc = alloc_size;
92 GNUNET_memcpy (buf->data,
93 data,
94 data_size);
95 buf->fill = data_size;
96 buf->max = max_size;
97 return GNUNET_OK;
98}
99
100
107static void
109{
110 GNUNET_free (buf->data);
111 buf->data = NULL;
112}
113
114
127 const void *data,
128 size_t data_size,
129 size_t max_size)
130{
131 if (buf->fill + data_size < data_size)
132 {
133 GNUNET_break (0);
134 return GNUNET_NO; /* overflow */
135 }
136 if (buf->fill + data_size > max_size)
137 return GNUNET_NO;
138 if (buf->fill + data_size > buf->alloc)
139 {
140 size_t new_size = buf->alloc;
141
142 while ( (new_size < buf->fill + data_size) &&
143 (new_size < SIZE_MAX / 2) )
144 new_size *= 2;
145 if ( (new_size > max_size) ||
146 (new_size < buf->fill + data_size) )
147 return GNUNET_NO;
148 buf->data = GNUNET_realloc (buf->data,
149 new_size);
150 buf->alloc = new_size;
151 }
152 GNUNET_memcpy (buf->data + buf->fill,
153 data,
154 data_size);
155 buf->fill += data_size;
156 return GNUNET_OK;
157}
158
159
166static enum GNUNET_MHD_PostResult
167inflate_data (struct Buffer *buf)
168{
169 z_stream z;
170 char *tmp;
171 size_t tmp_size;
172 int ret;
173
174 memset (&z,
175 0,
176 sizeof(z));
177 z.next_in = (Bytef *) buf->data;
178 z.avail_in = buf->fill;
179 tmp_size = GNUNET_MIN (buf->max,
180 buf->fill * 4);
181 tmp = GNUNET_malloc (tmp_size);
182 z.next_out = (Bytef *) tmp;
183 z.avail_out = tmp_size;
184 ret = inflateInit (&z);
185 switch (ret)
186 {
187 case Z_MEM_ERROR:
188 GNUNET_break (0);
190 case Z_STREAM_ERROR:
191 GNUNET_break_op (0);
193 case Z_OK:
194 break;
195 }
196 while (1)
197 {
198 ret = inflate (&z,
199 0);
200 switch (ret)
201 {
202 case Z_BUF_ERROR:
203 GNUNET_break_op (0);
204 GNUNET_break (Z_OK == inflateEnd (&z));
205 GNUNET_free (tmp);
207 case Z_MEM_ERROR:
208 GNUNET_break (0);
209 GNUNET_break (Z_OK == inflateEnd (&z));
210 GNUNET_free (tmp);
212 case Z_DATA_ERROR:
213 GNUNET_break_op (0);
214 GNUNET_break (Z_OK == inflateEnd (&z));
215 GNUNET_free (tmp);
217 case Z_NEED_DICT:
218 GNUNET_break_op (0);
219 GNUNET_break (Z_OK == inflateEnd (&z));
220 GNUNET_free (tmp);
222 case Z_OK:
223 if ( (0 < z.avail_out) &&
224 (0 == z.avail_in) )
225 {
226 /* truncated input stream */
227 GNUNET_break (0);
228 GNUNET_break (Z_OK == inflateEnd (&z));
229 GNUNET_free (tmp);
231 }
232 if (0 < z.avail_out)
233 continue; /* just call it again */
234 /* output buffer full, can we grow it? */
235 if (tmp_size == buf->max)
236 {
237 /* already at max */
238 GNUNET_break (0);
239 GNUNET_break (Z_OK == inflateEnd (&z));
240 GNUNET_free (tmp);
242 }
243 if (tmp_size * 2 < tmp_size)
244 tmp_size = buf->max; /* overflow */
245 else
246 tmp_size = GNUNET_MIN (buf->max,
247 tmp_size * 2);
248 tmp = GNUNET_realloc (tmp,
249 tmp_size);
250 z.next_out = (Bytef *) &tmp[z.total_out];
251 z.avail_out = tmp_size - z.total_out;
252 continue;
253 case Z_STREAM_END:
254 /* decompression successful, make 'tmp' the new 'data' */
255 GNUNET_free (buf->data);
256 buf->data = tmp;
257 buf->alloc = tmp_size;
258 buf->fill = z.total_out;
259 GNUNET_break (Z_OK == inflateEnd (&z));
260 return GNUNET_MHD_PR_SUCCESS; /* at least for now */
261 }
262 } /* while (1) */
263}
264
265
282GNUNET_MHD_post_parser (size_t buffer_max,
283 struct MHD_Connection *connection,
284 void **con_cls,
285 const char *upload_data,
286 size_t *upload_data_size,
287 json_t **json)
288{
289 struct Buffer *r = *con_cls;
290 const char *ce;
291
292 *json = NULL;
293 if (NULL == *con_cls)
294 {
295 /* We are seeing a fresh POST request. */
296 r = GNUNET_new (struct Buffer);
297 if (GNUNET_OK !=
298 buffer_init (r,
299 upload_data,
300 *upload_data_size,
302 buffer_max))
303 {
304 *con_cls = NULL;
305 buffer_deinit (r);
306 GNUNET_free (r);
308 }
309 /* everything OK, wait for more POST data */
310 *upload_data_size = 0;
311 *con_cls = r;
313 }
314 if (0 != *upload_data_size)
315 {
316 /* We are seeing an old request with more data available. */
317
318 if (GNUNET_OK !=
319 buffer_append (r,
320 upload_data,
321 *upload_data_size,
322 buffer_max))
323 {
324 /* Request too long */
325 *con_cls = NULL;
326 buffer_deinit (r);
327 GNUNET_free (r);
329 }
330 /* everything OK, wait for more POST data */
331 *upload_data_size = 0;
333 }
334
335 /* We have seen the whole request. */
336 ce = MHD_lookup_connection_value (connection,
337 MHD_HEADER_KIND,
338 MHD_HTTP_HEADER_CONTENT_ENCODING);
339 if ( (NULL != ce) &&
340 (0 == strcasecmp ("deflate",
341 ce)) )
342 {
344
345 ret = inflate_data (r);
347 {
348 buffer_deinit (r);
349 GNUNET_free (r);
350 *con_cls = NULL;
351 return ret;
352 }
353 }
354
355 {
356 json_error_t err;
357
358 *json = json_loadb (r->data,
359 r->fill,
360 0,
361 &err);
362 if (NULL == *json)
363 {
365 "Failed to parse JSON request body of %u byte at offset %d: %s\n",
366 (unsigned int) r->fill,
367 err.position,
368 err.text);
369 buffer_deinit (r);
370 GNUNET_free (r);
371 *con_cls = NULL;
373 }
374 }
375 buffer_deinit (r);
376 GNUNET_free (r);
377 *con_cls = NULL;
379}
380
381
389void
391{
392 struct Buffer *r = con_cls;
393
394 if (NULL != r)
395 {
396 buffer_deinit (r);
397 GNUNET_free (r);
398 }
399}
400
401
402/* 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.
GNUNET_GenericReturnValue
Named constants for return values.
#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:167
#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:282
static enum GNUNET_GenericReturnValue 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:126
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:390
static void buffer_deinit(struct Buffer *buf)
Free the data in a buffer.
Definition: mhd_upload.c:108
static enum GNUNET_GenericReturnValue 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 SIZE_MAX
Definition: platform.h:209
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