aboutsummaryrefslogtreecommitdiff
path: root/src/json/json_mhd.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2019-05-03 16:18:59 +0200
committerChristian Grothoff <christian@grothoff.org>2019-05-03 16:18:59 +0200
commit782565417337605572b66758bf13d7123e26f744 (patch)
treeaaf2094c7bdea5fa809f03573cb4292f1895160d /src/json/json_mhd.c
parent4444fb80284aa86fe24f3640a0b1e4c841a98f9a (diff)
downloadgnunet-782565417337605572b66758bf13d7123e26f744.tar.gz
gnunet-782565417337605572b66758bf13d7123e26f744.zip
support compressed JSON uploads
Diffstat (limited to 'src/json/json_mhd.c')
-rw-r--r--src/json/json_mhd.c122
1 files changed, 122 insertions, 0 deletions
diff --git a/src/json/json_mhd.c b/src/json/json_mhd.c
index 30b29b88e..b6ab2d116 100644
--- a/src/json/json_mhd.c
+++ b/src/json/json_mhd.c
@@ -26,6 +26,7 @@
26 */ 26 */
27#include "platform.h" 27#include "platform.h"
28#include "gnunet_json_lib.h" 28#include "gnunet_json_lib.h"
29#include <zlib.h>
29 30
30 31
31/** 32/**
@@ -55,6 +56,11 @@ struct Buffer
55 * Number of allocated bytes in buffer. 56 * Number of allocated bytes in buffer.
56 */ 57 */
57 size_t alloc; 58 size_t alloc;
59
60 /**
61 * Maximum buffer size allowed.
62 */
63 size_t max;
58}; 64};
59 65
60 66
@@ -80,7 +86,10 @@ buffer_init (struct Buffer *buf,
80 if (data_size > alloc_size) 86 if (data_size > alloc_size)
81 alloc_size = data_size; 87 alloc_size = data_size;
82 buf->data = GNUNET_malloc (alloc_size); 88 buf->data = GNUNET_malloc (alloc_size);
89 buf->alloc = alloc_size;
83 GNUNET_memcpy (buf->data, data, data_size); 90 GNUNET_memcpy (buf->data, data, data_size);
91 buf->fill = data_size;
92 buf->max = max_size;
84 return GNUNET_OK; 93 return GNUNET_OK;
85} 94}
86 95
@@ -138,6 +147,99 @@ buffer_append (struct Buffer *buf,
138 147
139 148
140/** 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 */
155static enum GNUNET_JSON_PostResult
156inflate_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 case Z_STREAM_ERROR:
177 GNUNET_break_op (0);
178 return GNUNET_JSON_PR_JSON_INVALID;
179 case Z_OK:
180 break;
181 }
182 while (1)
183 {
184 ret = inflate (&z, 0);
185 switch (ret)
186 {
187 case Z_MEM_ERROR:
188 GNUNET_break (0);
189 GNUNET_break (Z_OK == inflateEnd (&z));
190 GNUNET_free (tmp);
191 return GNUNET_JSON_PR_OUT_OF_MEMORY;
192 case Z_DATA_ERROR:
193 GNUNET_break (0);
194 GNUNET_break (Z_OK == inflateEnd (&z));
195 GNUNET_free (tmp);
196 return GNUNET_JSON_PR_JSON_INVALID;
197 case Z_NEED_DICT:
198 GNUNET_break (0);
199 GNUNET_break (Z_OK == inflateEnd (&z));
200 GNUNET_free (tmp);
201 return GNUNET_JSON_PR_JSON_INVALID;
202 case Z_OK:
203 if ((0 < z.avail_out) && (0 == z.avail_in))
204 {
205 /* truncated input stream */
206 GNUNET_break (0);
207 GNUNET_break (Z_OK == inflateEnd (&z));
208 GNUNET_free (tmp);
209 return GNUNET_JSON_PR_JSON_INVALID;
210 }
211 if (0 < z.avail_out)
212 continue; /* just call it again */
213 /* output buffer full, can we grow it? */
214 if (tmp_size == buf->max)
215 {
216 /* already at max */
217 GNUNET_break (0);
218 GNUNET_break (Z_OK == inflateEnd (&z));
219 GNUNET_free (tmp);
220 return GNUNET_JSON_PR_OUT_OF_MEMORY;
221 }
222 if (tmp_size * 2 < tmp_size)
223 tmp_size = buf->max;
224 else
225 tmp_size = GNUNET_MIN (buf->max, tmp_size * 2);
226 tmp = GNUNET_realloc (tmp, tmp_size);
227 z.next_out = (Bytef *) &tmp[z.total_out];
228 continue;
229 case Z_STREAM_END:
230 /* decompression successful, make 'tmp' the new 'data' */
231 GNUNET_free (buf->data);
232 buf->data = tmp;
233 buf->alloc = tmp_size;
234 buf->fill = z.total_out;
235 GNUNET_break (Z_OK == inflateEnd (&z));
236 return GNUNET_JSON_PR_SUCCESS; /* at least for now */
237 }
238 } /* while (1) */
239}
240
241
242/**
141 * Process a POST request containing a JSON object. This function 243 * Process a POST request containing a JSON object. This function
142 * realizes an MHD POST processor that will (incrementally) process 244 * realizes an MHD POST processor that will (incrementally) process
143 * JSON data uploaded to the HTTP server. It will store the required 245 * JSON data uploaded to the HTTP server. It will store the required
@@ -161,10 +263,13 @@ GNUNET_JSON_post_parser (size_t buffer_max,
161 json_t **json) 263 json_t **json)
162{ 264{
163 struct Buffer *r = *con_cls; 265 struct Buffer *r = *con_cls;
266 const char *ce;
267 int ret;
164 268
165 *json = NULL; 269 *json = NULL;
166 if (NULL == *con_cls) 270 if (NULL == *con_cls)
167 { 271 {
272
168 /* We are seeing a fresh POST request. */ 273 /* We are seeing a fresh POST request. */
169 r = GNUNET_new (struct Buffer); 274 r = GNUNET_new (struct Buffer);
170 if (GNUNET_OK != buffer_init (r, 275 if (GNUNET_OK != buffer_init (r,
@@ -202,12 +307,29 @@ GNUNET_JSON_post_parser (size_t buffer_max,
202 } 307 }
203 308
204 /* We have seen the whole request. */ 309 /* We have seen the whole request. */
310 ce = MHD_lookup_connection_value (connection,
311 MHD_HEADER_KIND,
312 MHD_HTTP_HEADER_CONTENT_ENCODING);
313 if ((NULL != ce) && (0 == strcasecmp ("deflate", ce)))
314 {
315 ret = inflate_data (r);
316 if (GNUNET_JSON_PR_SUCCESS != ret)
317 {
318 buffer_deinit (r);
319 GNUNET_free (r);
320 *con_cls = NULL;
321 return ret;
322 }
323 }
205 324
206 *json = json_loadb (r->data, r->fill, 0, NULL); 325 *json = json_loadb (r->data, r->fill, 0, NULL);
207 if (NULL == *json) 326 if (NULL == *json)
208 { 327 {
209 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 328 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
210 "Failed to parse JSON request body\n"); 329 "Failed to parse JSON request body\n");
330 buffer_deinit (r);
331 GNUNET_free (r);
332 *con_cls = NULL;
211 return GNUNET_JSON_PR_JSON_INVALID; 333 return GNUNET_JSON_PR_JSON_INVALID;
212 } 334 }
213 buffer_deinit (r); 335 buffer_deinit (r);