json_mhd.c 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  1. /*
  2. This file is part of GNUnet
  3. Copyright (C) 2014, 2015, 2016 GNUnet e.V.
  4. GNUnet is free software: you can redistribute it and/or modify it
  5. under the terms of the GNU Affero General Public License as published
  6. by the Free Software Foundation, either version 3 of the License,
  7. or (at your option) any later version.
  8. GNUnet is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Affero General Public License for more details.
  12. You should have received a copy of the GNU Affero General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. SPDX-License-Identifier: AGPL3.0-or-later
  15. */
  16. /**
  17. * @file json/json_mhd.c
  18. * @brief functions to parse JSON snippets we receive via MHD
  19. * @author Florian Dold
  20. * @author Benedikt Mueller
  21. * @author Christian Grothoff
  22. */
  23. #include "platform.h"
  24. #include "gnunet_json_lib.h"
  25. #include <zlib.h>
  26. /**
  27. * Initial size for POST request buffers. Should be big enough to
  28. * usually not require a reallocation, but not so big that it hurts in
  29. * terms of memory use.
  30. */
  31. #define REQUEST_BUFFER_INITIAL (2 * 1024)
  32. /**
  33. * Buffer for POST requests.
  34. */
  35. struct Buffer
  36. {
  37. /**
  38. * Allocated memory
  39. */
  40. char *data;
  41. /**
  42. * Number of valid bytes in buffer.
  43. */
  44. size_t fill;
  45. /**
  46. * Number of allocated bytes in buffer.
  47. */
  48. size_t alloc;
  49. /**
  50. * Maximum buffer size allowed.
  51. */
  52. size_t max;
  53. };
  54. /**
  55. * Initialize a buffer.
  56. *
  57. * @param buf the buffer to initialize
  58. * @param data the initial data
  59. * @param data_size size of the initial data
  60. * @param alloc_size size of the buffer
  61. * @param max_size maximum size that the buffer can grow to
  62. * @return a GNUnet result code
  63. */
  64. static int
  65. buffer_init (struct Buffer *buf,
  66. const void *data,
  67. size_t data_size,
  68. size_t alloc_size,
  69. size_t max_size)
  70. {
  71. if ((data_size > max_size) || (alloc_size > max_size))
  72. return GNUNET_SYSERR;
  73. if (data_size > alloc_size)
  74. alloc_size = data_size;
  75. buf->data = GNUNET_malloc (alloc_size);
  76. buf->alloc = alloc_size;
  77. GNUNET_memcpy (buf->data, data, data_size);
  78. buf->fill = data_size;
  79. buf->max = max_size;
  80. return GNUNET_OK;
  81. }
  82. /**
  83. * Free the data in a buffer. Does *not* free
  84. * the buffer object itself.
  85. *
  86. * @param buf buffer to de-initialize
  87. */
  88. static void
  89. buffer_deinit (struct Buffer *buf)
  90. {
  91. GNUNET_free (buf->data);
  92. buf->data = NULL;
  93. }
  94. /**
  95. * Append data to a buffer, growing the buffer if necessary.
  96. *
  97. * @param buf the buffer to append to
  98. * @param data the data to append
  99. * @param data_size the size of @a data
  100. * @param max_size maximum size that the buffer can grow to
  101. * @return #GNUNET_OK on success,
  102. * #GNUNET_NO if the buffer can't accomodate for the new data
  103. */
  104. static int
  105. buffer_append (struct Buffer *buf,
  106. const void *data,
  107. size_t data_size,
  108. size_t max_size)
  109. {
  110. if (buf->fill + data_size > max_size)
  111. return GNUNET_NO;
  112. if (buf->fill + data_size > buf->alloc)
  113. {
  114. char *new_buf;
  115. size_t new_size = buf->alloc;
  116. while (new_size < buf->fill + data_size)
  117. new_size += 2;
  118. if (new_size > max_size)
  119. return GNUNET_NO;
  120. new_buf = GNUNET_malloc (new_size);
  121. GNUNET_memcpy (new_buf, buf->data, buf->fill);
  122. GNUNET_free (buf->data);
  123. buf->data = new_buf;
  124. buf->alloc = new_size;
  125. }
  126. GNUNET_memcpy (buf->data + buf->fill, data, data_size);
  127. buf->fill += data_size;
  128. return GNUNET_OK;
  129. }
  130. /**
  131. * Decompress data in @a buf.
  132. *
  133. * @param buf input data to inflate
  134. * @return result code indicating the status of the operation
  135. */
  136. static enum GNUNET_JSON_PostResult
  137. inflate_data (struct Buffer *buf)
  138. {
  139. z_stream z;
  140. char *tmp;
  141. size_t tmp_size;
  142. int ret;
  143. memset (&z, 0, sizeof (z));
  144. z.next_in = (Bytef *) buf->data;
  145. z.avail_in = buf->fill;
  146. tmp_size = GNUNET_MIN (buf->max, buf->fill * 4);
  147. tmp = GNUNET_malloc (tmp_size);
  148. z.next_out = (Bytef *) tmp;
  149. z.avail_out = tmp_size;
  150. ret = inflateInit (&z);
  151. switch (ret)
  152. {
  153. case Z_MEM_ERROR:
  154. GNUNET_break (0);
  155. return GNUNET_JSON_PR_OUT_OF_MEMORY;
  156. case Z_STREAM_ERROR:
  157. GNUNET_break_op (0);
  158. return GNUNET_JSON_PR_JSON_INVALID;
  159. case Z_OK:
  160. break;
  161. }
  162. while (1)
  163. {
  164. ret = inflate (&z, 0);
  165. switch (ret)
  166. {
  167. case Z_MEM_ERROR:
  168. GNUNET_break (0);
  169. GNUNET_break (Z_OK == inflateEnd (&z));
  170. GNUNET_free (tmp);
  171. return GNUNET_JSON_PR_OUT_OF_MEMORY;
  172. case Z_DATA_ERROR:
  173. GNUNET_break (0);
  174. GNUNET_break (Z_OK == inflateEnd (&z));
  175. GNUNET_free (tmp);
  176. return GNUNET_JSON_PR_JSON_INVALID;
  177. case Z_NEED_DICT:
  178. GNUNET_break (0);
  179. GNUNET_break (Z_OK == inflateEnd (&z));
  180. GNUNET_free (tmp);
  181. return GNUNET_JSON_PR_JSON_INVALID;
  182. case Z_OK:
  183. if ((0 < z.avail_out) && (0 == z.avail_in))
  184. {
  185. /* truncated input stream */
  186. GNUNET_break (0);
  187. GNUNET_break (Z_OK == inflateEnd (&z));
  188. GNUNET_free (tmp);
  189. return GNUNET_JSON_PR_JSON_INVALID;
  190. }
  191. if (0 < z.avail_out)
  192. continue; /* just call it again */
  193. /* output buffer full, can we grow it? */
  194. if (tmp_size == buf->max)
  195. {
  196. /* already at max */
  197. GNUNET_break (0);
  198. GNUNET_break (Z_OK == inflateEnd (&z));
  199. GNUNET_free (tmp);
  200. return GNUNET_JSON_PR_OUT_OF_MEMORY;
  201. }
  202. if (tmp_size * 2 < tmp_size)
  203. tmp_size = buf->max;
  204. else
  205. tmp_size = GNUNET_MIN (buf->max, tmp_size * 2);
  206. tmp = GNUNET_realloc (tmp, tmp_size);
  207. z.next_out = (Bytef *) &tmp[z.total_out];
  208. continue;
  209. case Z_STREAM_END:
  210. /* decompression successful, make 'tmp' the new 'data' */
  211. GNUNET_free (buf->data);
  212. buf->data = tmp;
  213. buf->alloc = tmp_size;
  214. buf->fill = z.total_out;
  215. GNUNET_break (Z_OK == inflateEnd (&z));
  216. return GNUNET_JSON_PR_SUCCESS; /* at least for now */
  217. }
  218. } /* while (1) */
  219. }
  220. /**
  221. * Process a POST request containing a JSON object. This function
  222. * realizes an MHD POST processor that will (incrementally) process
  223. * JSON data uploaded to the HTTP server. It will store the required
  224. * state in the @a con_cls, which must be cleaned up using
  225. * #GNUNET_JSON_post_parser_callback().
  226. *
  227. * @param buffer_max maximum allowed size for the buffer
  228. * @param connection MHD connection handle (for meta data about the upload)
  229. * @param con_cls the closure (will point to a `struct Buffer *`)
  230. * @param upload_data the POST data
  231. * @param upload_data_size number of bytes in @a upload_data
  232. * @param json the JSON object for a completed request
  233. * @return result code indicating the status of the operation
  234. */
  235. enum GNUNET_JSON_PostResult
  236. GNUNET_JSON_post_parser (size_t buffer_max,
  237. struct MHD_Connection *connection,
  238. void **con_cls,
  239. const char *upload_data,
  240. size_t *upload_data_size,
  241. json_t **json)
  242. {
  243. struct Buffer *r = *con_cls;
  244. const char *ce;
  245. int ret;
  246. *json = NULL;
  247. if (NULL == *con_cls)
  248. {
  249. /* We are seeing a fresh POST request. */
  250. r = GNUNET_new (struct Buffer);
  251. if (GNUNET_OK != buffer_init (r,
  252. upload_data,
  253. *upload_data_size,
  254. REQUEST_BUFFER_INITIAL,
  255. buffer_max))
  256. {
  257. *con_cls = NULL;
  258. buffer_deinit (r);
  259. GNUNET_free (r);
  260. return GNUNET_JSON_PR_OUT_OF_MEMORY;
  261. }
  262. /* everything OK, wait for more POST data */
  263. *upload_data_size = 0;
  264. *con_cls = r;
  265. return GNUNET_JSON_PR_CONTINUE;
  266. }
  267. if (0 != *upload_data_size)
  268. {
  269. /* We are seeing an old request with more data available. */
  270. if (GNUNET_OK !=
  271. buffer_append (r, upload_data, *upload_data_size, buffer_max))
  272. {
  273. /* Request too long */
  274. *con_cls = NULL;
  275. buffer_deinit (r);
  276. GNUNET_free (r);
  277. return GNUNET_JSON_PR_REQUEST_TOO_LARGE;
  278. }
  279. /* everything OK, wait for more POST data */
  280. *upload_data_size = 0;
  281. return GNUNET_JSON_PR_CONTINUE;
  282. }
  283. /* We have seen the whole request. */
  284. ce = MHD_lookup_connection_value (connection,
  285. MHD_HEADER_KIND,
  286. MHD_HTTP_HEADER_CONTENT_ENCODING);
  287. if ((NULL != ce) && (0 == strcasecmp ("deflate", ce)))
  288. {
  289. ret = inflate_data (r);
  290. if (GNUNET_JSON_PR_SUCCESS != ret)
  291. {
  292. buffer_deinit (r);
  293. GNUNET_free (r);
  294. *con_cls = NULL;
  295. return ret;
  296. }
  297. }
  298. *json = json_loadb (r->data, r->fill, 0, NULL);
  299. if (NULL == *json)
  300. {
  301. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  302. "Failed to parse JSON request body\n");
  303. buffer_deinit (r);
  304. GNUNET_free (r);
  305. *con_cls = NULL;
  306. return GNUNET_JSON_PR_JSON_INVALID;
  307. }
  308. buffer_deinit (r);
  309. GNUNET_free (r);
  310. *con_cls = NULL;
  311. return GNUNET_JSON_PR_SUCCESS;
  312. }
  313. /**
  314. * Function called whenever we are done with a request
  315. * to clean up our state.
  316. *
  317. * @param con_cls value as it was left by
  318. * #GNUNET_JSON_post_parser(), to be cleaned up
  319. */
  320. void
  321. GNUNET_JSON_post_parser_cleanup (void *con_cls)
  322. {
  323. struct Buffer *r = con_cls;
  324. if (NULL != r)
  325. {
  326. buffer_deinit (r);
  327. GNUNET_free (r);
  328. }
  329. }
  330. /* end of mhd_json.c */