*/
#include "platform.h"
#include "gnunet_json_lib.h"
+#include <zlib.h>
/**
* Number of allocated bytes in buffer.
*/
size_t alloc;
+
+ /**
+ * Maximum buffer size allowed.
+ */
+ size_t max;
};
if (data_size > alloc_size)
alloc_size = data_size;
buf->data = GNUNET_malloc (alloc_size);
+ buf->alloc = alloc_size;
GNUNET_memcpy (buf->data, data, data_size);
+ buf->fill = data_size;
+ buf->max = max_size;
return GNUNET_OK;
}
}
+/**
+ * Decompress data in @a buf.
+ *
+ * @param buf input data to inflate
+ * @return result code indicating the status of the operation
+ */
+static enum GNUNET_JSON_PostResult
+inflate_data (struct Buffer *buf)
+{
+ z_stream z;
+ char *tmp;
+ size_t tmp_size;
+ int ret;
+
+ memset (&z, 0, sizeof (z));
+ z.next_in = (Bytef *) buf->data;
+ z.avail_in = buf->fill;
+ tmp_size = GNUNET_MIN (buf->max, buf->fill * 4);
+ tmp = GNUNET_malloc (tmp_size);
+ z.next_out = (Bytef *) tmp;
+ z.avail_out = tmp_size;
+ ret = inflateInit (&z);
+ switch (ret)
+ {
+ case Z_MEM_ERROR:
+ GNUNET_break (0);
+ return GNUNET_JSON_PR_OUT_OF_MEMORY;
+ case Z_STREAM_ERROR:
+ GNUNET_break_op (0);
+ return GNUNET_JSON_PR_JSON_INVALID;
+ case Z_OK:
+ break;
+ }
+ while (1)
+ {
+ ret = inflate (&z, 0);
+ switch (ret)
+ {
+ case Z_MEM_ERROR:
+ GNUNET_break (0);
+ GNUNET_break (Z_OK == inflateEnd (&z));
+ GNUNET_free (tmp);
+ return GNUNET_JSON_PR_OUT_OF_MEMORY;
+ case Z_DATA_ERROR:
+ GNUNET_break (0);
+ GNUNET_break (Z_OK == inflateEnd (&z));
+ GNUNET_free (tmp);
+ return GNUNET_JSON_PR_JSON_INVALID;
+ case Z_NEED_DICT:
+ GNUNET_break (0);
+ GNUNET_break (Z_OK == inflateEnd (&z));
+ GNUNET_free (tmp);
+ return GNUNET_JSON_PR_JSON_INVALID;
+ case Z_OK:
+ if ((0 < z.avail_out) && (0 == z.avail_in))
+ {
+ /* truncated input stream */
+ GNUNET_break (0);
+ GNUNET_break (Z_OK == inflateEnd (&z));
+ GNUNET_free (tmp);
+ return GNUNET_JSON_PR_JSON_INVALID;
+ }
+ if (0 < z.avail_out)
+ continue; /* just call it again */
+ /* output buffer full, can we grow it? */
+ if (tmp_size == buf->max)
+ {
+ /* already at max */
+ GNUNET_break (0);
+ GNUNET_break (Z_OK == inflateEnd (&z));
+ GNUNET_free (tmp);
+ return GNUNET_JSON_PR_OUT_OF_MEMORY;
+ }
+ if (tmp_size * 2 < tmp_size)
+ tmp_size = buf->max;
+ else
+ tmp_size = GNUNET_MIN (buf->max, tmp_size * 2);
+ tmp = GNUNET_realloc (tmp, tmp_size);
+ z.next_out = (Bytef *) &tmp[z.total_out];
+ continue;
+ case Z_STREAM_END:
+ /* decompression successful, make 'tmp' the new 'data' */
+ GNUNET_free (buf->data);
+ buf->data = tmp;
+ buf->alloc = tmp_size;
+ buf->fill = z.total_out;
+ GNUNET_break (Z_OK == inflateEnd (&z));
+ return GNUNET_JSON_PR_SUCCESS; /* at least for now */
+ }
+ } /* while (1) */
+}
+
+
/**
* Process a POST request containing a JSON object. This function
* realizes an MHD POST processor that will (incrementally) process
json_t **json)
{
struct Buffer *r = *con_cls;
+ const char *ce;
+ int ret;
*json = NULL;
if (NULL == *con_cls)
{
+
/* We are seeing a fresh POST request. */
r = GNUNET_new (struct Buffer);
if (GNUNET_OK != buffer_init (r,
}
/* We have seen the whole request. */
+ ce = MHD_lookup_connection_value (connection,
+ MHD_HEADER_KIND,
+ MHD_HTTP_HEADER_CONTENT_ENCODING);
+ if ((NULL != ce) && (0 == strcasecmp ("deflate", ce)))
+ {
+ ret = inflate_data (r);
+ if (GNUNET_JSON_PR_SUCCESS != ret)
+ {
+ buffer_deinit (r);
+ GNUNET_free (r);
+ *con_cls = NULL;
+ return ret;
+ }
+ }
*json = json_loadb (r->data, r->fill, 0, NULL);
if (NULL == *json)
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Failed to parse JSON request body\n");
+ buffer_deinit (r);
+ GNUNET_free (r);
+ *con_cls = NULL;
return GNUNET_JSON_PR_JSON_INVALID;
}
buffer_deinit (r);
#include "gnunet_util_lib.h"
#include "gnunet_json_lib.h"
#include "gnunet_curl_lib.h"
+#include <zlib.h>
#define MAX_SIZE 1024 * 1024
global_ret = 6;
}
json_decref (json);
- resp = MHD_create_response_from_buffer (2, "OK", MHD_RESPMEM_PERSISTENT);
+ resp = MHD_create_response_from_buffer (3, "OK\n", MHD_RESPMEM_PERSISTENT);
ret = MHD_queue_response (connection, MHD_HTTP_OK, resp);
MHD_destroy_response (resp);
return ret;
uint16_t port;
CURL *easy;
char *url;
+ char *str;
+ size_t slen;
long post_data_size;
void *post_data;
+ uLongf dlen;
+ struct curl_slist *json_header;
GNUNET_log_setup ("test-json-mhd", "WARNING", NULL);
global_ret = 2;
GNUNET_snprintf (tmp, sizeof (tmp), "%u", i);
json_object_set_new (bigj, tmp, json_string (tmp));
}
- post_data = json_dumps (bigj, JSON_INDENT (2));
- post_data_size = strlen (post_data);
-
+ str = json_dumps (bigj, JSON_INDENT (2));
+ slen = strlen (str);
+
+#ifdef compressBound
+ dlen = compressBound (slen);
+#else
+ dlen = slen + slen / 100 + 20;
+ /* documentation says 100.1% oldSize + 12 bytes, but we
+ * should be able to overshoot by more to be safe */
+#endif
+ post_data = GNUNET_malloc (dlen);
+ if (Z_OK !=
+ compress2 ((Bytef *) post_data, &dlen, (const Bytef *) str, slen, 9))
+ {
+ GNUNET_break (0);
+ MHD_stop_daemon (daemon);
+ GNUNET_free (url);
+ json_decref (bigj);
+ GNUNET_free (post_data);
+ GNUNET_free (str);
+ return 1;
+ }
+ post_data_size = (long) dlen;
port = MHD_get_daemon_info (daemon, MHD_DAEMON_INFO_BIND_PORT)->port;
easy = curl_easy_init ();
GNUNET_asprintf (&url, "http://localhost:%u/", (unsigned int) port);
- curl_easy_setopt (easy, CURLOPT_VERBOSE, 1);
+ curl_easy_setopt (easy, CURLOPT_VERBOSE, 0);
curl_easy_setopt (easy, CURLOPT_URL, url);
curl_easy_setopt (easy, CURLOPT_POST, 1);
curl_easy_setopt (easy, CURLOPT_POSTFIELDS, post_data);
curl_easy_setopt (easy, CURLOPT_POSTFIELDSIZE, post_data_size);
+
+ json_header = curl_slist_append (NULL, "Content-Type: application/json");
+ json_header = curl_slist_append (json_header, "Content-Encoding: deflate");
+ curl_easy_setopt (easy, CURLOPT_HTTPHEADER, json_header);
if (0 != curl_easy_perform (easy))
{
GNUNET_break (0);
MHD_stop_daemon (daemon);
GNUNET_free (url);
json_decref (bigj);
+ GNUNET_free (post_data);
+ GNUNET_free (str);
+ curl_slist_free_all (json_header);
+ curl_easy_cleanup (easy);
return 1;
}
MHD_stop_daemon (daemon);
GNUNET_free (url);
json_decref (bigj);
+ GNUNET_free (post_data);
+ GNUNET_free (str);
+ curl_slist_free_all (json_header);
+ curl_easy_cleanup (easy);
return global_ret;
}