diff options
Diffstat (limited to 'src/json/json_mhd.c')
-rw-r--r-- | src/json/json_mhd.c | 122 |
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 | */ | ||
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 | 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); |