GNUnet 0.21.1
json_mhd.c File Reference

functions to parse JSON snippets we receive via MHD More...

#include "platform.h"
#include "gnunet_json_lib.h"
#include <zlib.h>
Include dependency graph for json_mhd.c:

Go to the source code of this file.

Data Structures

struct  Buffer
 Buffer for POST requests. More...
 

Macros

#define REQUEST_BUFFER_INITIAL   (2 * 1024)
 Initial size for POST request buffers. More...
 

Functions

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. More...
 
static void buffer_deinit (struct Buffer *buf)
 Free the data in a buffer. More...
 
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. More...
 
static enum GNUNET_JSON_PostResult inflate_data (struct Buffer *buf)
 Decompress data in buf. More...
 
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. More...
 
void GNUNET_JSON_post_parser_cleanup (void *con_cls)
 Function called whenever we are done with a request to clean up our state. More...
 

Detailed Description

functions to parse JSON snippets we receive via MHD

Author
Florian Dold
Benedikt Mueller
Christian Grothoff

Definition in file json_mhd.c.

Macro Definition Documentation

◆ REQUEST_BUFFER_INITIAL

#define REQUEST_BUFFER_INITIAL   (2 * 1024)

Initial size for POST request buffers.

Should be big enough to usually not require a reallocation, but not so big that it hurts in terms of memory use.

Definition at line 37 of file json_mhd.c.

Function Documentation

◆ buffer_init()

static int buffer_init ( struct Buffer buf,
const void *  data,
size_t  data_size,
size_t  alloc_size,
size_t  max_size 
)
static

Initialize a buffer.

Parameters
bufthe buffer to initialize
datathe initial data
data_sizesize of the initial data
alloc_sizesize of the buffer
max_sizemaximum size that the buffer can grow to
Returns
a GNUnet result code

Definition at line 78 of file json_mhd.c.

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;
91 buf->fill = data_size;
92 buf->max = max_size;
93 return GNUNET_OK;
94}
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.
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
@ GNUNET_OK
@ GNUNET_SYSERR
#define GNUNET_malloc(size)
Wrapper around malloc.
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

References Buffer::alloc, data, Buffer::data, data_size, Buffer::fill, GNUNET_malloc, GNUNET_memcpy, GNUNET_OK, GNUNET_SYSERR, Buffer::max, and max_size.

Referenced by GNUNET_JSON_post_parser().

Here is the caller graph for this function:

◆ buffer_deinit()

static void buffer_deinit ( struct Buffer buf)
static

Free the data in a buffer.

Does not free the buffer object itself.

Parameters
bufbuffer to de-initialize

Definition at line 104 of file json_mhd.c.

105{
106 GNUNET_free (buf->data);
107 buf->data = NULL;
108}
#define GNUNET_free(ptr)
Wrapper around free.

References Buffer::data, and GNUNET_free.

Referenced by GNUNET_JSON_post_parser(), and GNUNET_JSON_post_parser_cleanup().

Here is the caller graph for this function:

◆ buffer_append()

static int buffer_append ( struct Buffer buf,
const void *  data,
size_t  data_size,
size_t  max_size 
)
static

Append data to a buffer, growing the buffer if necessary.

Parameters
bufthe buffer to append to
datathe data to append
data_sizethe size of data
max_sizemaximum size that the buffer can grow to
Returns
GNUNET_OK on success, GNUNET_NO if the buffer can't accommodate for the new data

Definition at line 122 of file json_mhd.c.

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}
@ GNUNET_NO

References Buffer::alloc, data, Buffer::data, data_size, Buffer::fill, GNUNET_free, GNUNET_malloc, GNUNET_memcpy, GNUNET_NO, GNUNET_OK, and max_size.

Referenced by GNUNET_JSON_post_parser().

Here is the caller graph for this function:

◆ inflate_data()

static enum GNUNET_JSON_PostResult inflate_data ( struct Buffer buf)
static

Decompress data in buf.

Parameters
bufinput data to inflate
Returns
result code indicating the status of the operation

Definition at line 156 of file json_mhd.c.

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}
static int ret
Final status code.
Definition: gnunet-arm.c:94
@ GNUNET_JSON_PR_OUT_OF_MEMORY
Sorry, memory allocation (malloc()) failed.
@ GNUNET_JSON_PR_JSON_INVALID
JSON parsing failed.
@ GNUNET_JSON_PR_SUCCESS
Parsing successful, JSON result is in *json.
#define GNUNET_MIN(a, b)
#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.
#define GNUNET_realloc(ptr, size)
Wrapper around realloc.

References Buffer::alloc, Buffer::data, Buffer::fill, GNUNET_break, GNUNET_break_op, GNUNET_free, GNUNET_JSON_PR_JSON_INVALID, GNUNET_JSON_PR_OUT_OF_MEMORY, GNUNET_JSON_PR_SUCCESS, GNUNET_malloc, GNUNET_MIN, GNUNET_realloc, Buffer::max, and ret.

Referenced by GNUNET_JSON_post_parser().

Here is the caller graph for this function:

◆ GNUNET_JSON_post_parser()

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.

This function realizes an MHD POST processor that will (incrementally) process JSON data uploaded to the HTTP server. It will store the required state in the con_cls, which must be cleaned up using #GNUNET_JSON_post_parser_callback().

Parameters
buffer_maxmaximum allowed size for the buffer
connectionMHD connection handle (for meta data about the upload)
con_clsthe closure (will point to a struct Buffer *)
upload_datathe POST data
upload_data_sizenumber of bytes in upload_data
jsonthe JSON object for a completed request
Returns
result code indicating the status of the operation

Definition at line 265 of file json_mhd.c.

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
356}
@ GNUNET_JSON_PR_CONTINUE
Parsing continues, call again soon!
@ GNUNET_JSON_PR_REQUEST_TOO_LARGE
Request size exceeded buffer_max argument.
#define GNUNET_log(kind,...)
@ GNUNET_ERROR_TYPE_WARNING
#define GNUNET_new(type)
Allocate a struct or union of the given type.
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
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
Buffer for POST requests.
Definition: json_mhd.c:44

References buffer_append(), buffer_deinit(), buffer_init(), Buffer::data, Buffer::fill, GNUNET_ERROR_TYPE_WARNING, GNUNET_free, GNUNET_JSON_PR_CONTINUE, GNUNET_JSON_PR_JSON_INVALID, GNUNET_JSON_PR_OUT_OF_MEMORY, GNUNET_JSON_PR_REQUEST_TOO_LARGE, GNUNET_JSON_PR_SUCCESS, GNUNET_log, GNUNET_new, GNUNET_OK, inflate_data(), REQUEST_BUFFER_INITIAL, and ret.

Here is the call graph for this function:

◆ GNUNET_JSON_post_parser_cleanup()

void GNUNET_JSON_post_parser_cleanup ( void *  con_cls)

Function called whenever we are done with a request to clean up our state.

Parameters
con_clsvalue as it was left by GNUNET_JSON_post_parser(), to be cleaned up

Definition at line 367 of file json_mhd.c.

368{
369 struct Buffer *r = con_cls;
370
371 if (NULL != r)
372 {
373 buffer_deinit (r);
374 GNUNET_free (r);
375 }
376}

References buffer_deinit(), and GNUNET_free.

Here is the call graph for this function: