aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog3
-rw-r--r--src/exchange/Makefile.am1
-rw-r--r--src/exchange/taler-exchange-httpd_keystate.c51
-rw-r--r--src/exchange/taler-exchange-httpd_responses.c104
-rw-r--r--src/exchange/taler-exchange-httpd_responses.h23
5 files changed, 176 insertions, 6 deletions
diff --git a/ChangeLog b/ChangeLog
index 93d03f45b..ee0cae82e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,6 @@
+Mon Apr 17 01:29:07 CEST 2017
+ Add support for HTTP body compression (#4982). -CG
+
Mon Mar 20 04:37:46 CET 2017
Implemented first working version of taler-auditor. -CG
diff --git a/src/exchange/Makefile.am b/src/exchange/Makefile.am
index ecb774b29..f936c3a48 100644
--- a/src/exchange/Makefile.am
+++ b/src/exchange/Makefile.am
@@ -55,6 +55,7 @@ taler_exchange_httpd_LDADD = \
-lgnunetutil \
-lgnunetjson \
-ljansson \
+ -lz \
-lpthread
if HAVE_DEVELOPER
diff --git a/src/exchange/taler-exchange-httpd_keystate.c b/src/exchange/taler-exchange-httpd_keystate.c
index 95ddd04bf..057f89ce3 100644
--- a/src/exchange/taler-exchange-httpd_keystate.c
+++ b/src/exchange/taler-exchange-httpd_keystate.c
@@ -72,6 +72,16 @@ struct TEH_KS_StateHandle
char *keys_json;
/**
+ * deflate-compressed version of @e keys_json, or NULL if not available.
+ */
+ void *keys_jsonz;
+
+ /**
+ * Number of bytes in @e keys_jsonz.
+ */
+ size_t keys_jsonz_size;
+
+ /**
* Mapping from denomination keys to denomination key issue struct.
* Used to lookup the key by hash.
*/
@@ -709,6 +719,7 @@ ks_release_ (struct TEH_KS_StateHandle *key_state)
key_state->revoked_map = NULL;
}
GNUNET_free_non_null (key_state->keys_json);
+ GNUNET_free_non_null (key_state->keys_jsonz);
GNUNET_free (key_state);
}
}
@@ -851,6 +862,17 @@ TEH_KS_acquire_ (const char *location)
JSON_INDENT (2));
GNUNET_assert (NULL != key_state->keys_json);
json_decref (keys);
+ /* also compute compressed version of /keys */
+ key_state->keys_jsonz = GNUNET_strdup (key_state->keys_json);
+ key_state->keys_jsonz_size = strlen (key_state->keys_json);
+ if (MHD_YES !=
+ TEH_RESPONSE_body_compress (&key_state->keys_jsonz,
+ &key_state->keys_jsonz_size))
+ {
+ GNUNET_free (key_state->keys_jsonz);
+ key_state->keys_jsonz = NULL;
+ key_state->keys_jsonz_size = 0;
+ }
internal_key_state = key_state;
}
key_state = internal_key_state;
@@ -1225,10 +1247,26 @@ TEH_KS_handler_keys (struct TEH_RequestHandler *rh,
struct MHD_Response *response;
int ret;
char dat[128];
+ char *json;
+ size_t json_len;
+ int comp;
key_state = TEH_KS_acquire ();
- response = MHD_create_response_from_buffer (strlen (key_state->keys_json),
- key_state->keys_json,
+ comp = MHD_NO;
+ if (NULL != key_state->keys_jsonz)
+ comp = TEH_RESPONSE_can_compress (connection);
+ if (MHD_YES == comp)
+ {
+ json = key_state->keys_jsonz;
+ json_len = key_state->keys_jsonz_size;
+ }
+ else
+ {
+ json = key_state->keys_json;
+ json_len = strlen (key_state->keys_json);
+ }
+ response = MHD_create_response_from_buffer (json_len,
+ json,
MHD_RESPMEM_MUST_COPY);
TEH_KS_release (key_state);
if (NULL == response)
@@ -1241,6 +1279,15 @@ TEH_KS_handler_keys (struct TEH_RequestHandler *rh,
MHD_add_response_header (response,
MHD_HTTP_HEADER_CONTENT_TYPE,
rh->mime_type));
+ if (MHD_YES !=
+ MHD_add_response_header (response,
+ MHD_HTTP_HEADER_CONTENT_ENCODING,
+ "deflate"))
+ {
+ GNUNET_break (0);
+ MHD_destroy_response (response);
+ return MHD_NO;
+ }
get_date_string (key_state->reload_time,
dat);
GNUNET_break (MHD_YES ==
diff --git a/src/exchange/taler-exchange-httpd_responses.c b/src/exchange/taler-exchange-httpd_responses.c
index eea534195..c67c885ec 100644
--- a/src/exchange/taler-exchange-httpd_responses.c
+++ b/src/exchange/taler-exchange-httpd_responses.c
@@ -23,6 +23,7 @@
* @author Christian Grothoff
*/
#include "platform.h"
+#include <zlib.h>
#include "taler-exchange-httpd_responses.h"
#include "taler_util.h"
#include "taler_json_lib.h"
@@ -47,6 +48,74 @@ TEH_RESPONSE_add_global_headers (struct MHD_Response *response)
}
+/**
+ * Is HTTP body deflate compression supported by the client?
+ *
+ * @param connection connection to check
+ * @return #MHD_YES if 'deflate' compression is allowed
+ */
+int
+TEH_RESPONSE_can_compress (struct MHD_Connection *connection)
+{
+ const char *ae;
+ const char *de;
+
+ ae = MHD_lookup_connection_value (connection,
+ MHD_HEADER_KIND,
+ MHD_HTTP_HEADER_ACCEPT_ENCODING);
+ if (NULL == ae)
+ return MHD_NO;
+ de = strstr (ae,
+ "deflate");
+ if (NULL == de)
+ return MHD_NO;
+ if ( ( (de == ae) ||
+ ( de[-1] == ',') ||
+ (de[-1] == ' ') ) &&
+ ( (de[strlen ("deflate")] == '\0') ||
+ (de[strlen ("deflate")] == ',') ) )
+ return MHD_YES;
+ return MHD_NO;
+}
+
+
+/**
+ * Try to compress a response body. Updates @a buf and @buf_size.
+ *
+ * @param[in,out] buf pointer to body to compress
+ * @param[in,out] buf_size pointer to initial size of @a buf
+ * @return #MHD_TES if @a buf was compressed
+ */
+int
+TEH_RESPONSE_body_compress (void **buf,
+ size_t *buf_size)
+{
+ Bytef *cbuf;
+ uLongf cbuf_size;
+ int ret;
+
+ cbuf_size = compressBound (*buf_size);
+ cbuf = malloc (cbuf_size);
+ if (NULL == cbuf)
+ return MHD_NO;
+ ret = compress (cbuf,
+ &cbuf_size,
+ (const Bytef *) *buf,
+ *buf_size);
+ if ( (Z_OK != ret) ||
+ (cbuf_size >= *buf_size) )
+ {
+ /* compression failed */
+ free (cbuf);
+ return MHD_NO;
+ }
+ free (*buf);
+ *buf = (void *) cbuf;
+ *buf_size = (size_t) cbuf_size;
+ return MHD_YES;
+}
+
+
/**
* Send JSON object as response.
*
@@ -61,12 +130,26 @@ TEH_RESPONSE_reply_json (struct MHD_Connection *connection,
unsigned int response_code)
{
struct MHD_Response *resp;
- char *json_str;
+ void *json_str;
+ size_t json_len;
int ret;
+ int comp;
- json_str = json_dumps (json, JSON_INDENT(2));
- GNUNET_assert (NULL != json_str);
- resp = MHD_create_response_from_buffer (strlen (json_str),
+ json_str = json_dumps (json,
+ JSON_INDENT(2));
+ if (NULL == json_str)
+ {
+ GNUNET_break (0);
+ return MHD_NO;
+ }
+ json_len = strlen (json_str);
+ /* try to compress the body */
+ comp = MHD_NO;
+ if (MHD_YES ==
+ TEH_RESPONSE_can_compress (connection))
+ comp = TEH_RESPONSE_body_compress (&json_str,
+ &json_len);
+ resp = MHD_create_response_from_buffer (json_len,
json_str,
MHD_RESPMEM_MUST_FREE);
if (NULL == resp)
@@ -79,6 +162,19 @@ TEH_RESPONSE_reply_json (struct MHD_Connection *connection,
(void) MHD_add_response_header (resp,
MHD_HTTP_HEADER_CONTENT_TYPE,
"application/json");
+ if (MHD_YES == comp)
+ {
+ /* Need to indicate to client that body is compressed */
+ if (MHD_NO ==
+ MHD_add_response_header (resp,
+ MHD_HTTP_HEADER_CONTENT_ENCODING,
+ "deflate"))
+ {
+ GNUNET_break (0);
+ MHD_destroy_response (resp);
+ return MHD_NO;
+ }
+ }
ret = MHD_queue_response (connection,
response_code,
resp);
diff --git a/src/exchange/taler-exchange-httpd_responses.h b/src/exchange/taler-exchange-httpd_responses.h
index 83dafdca3..091d43862 100644
--- a/src/exchange/taler-exchange-httpd_responses.h
+++ b/src/exchange/taler-exchange-httpd_responses.h
@@ -33,6 +33,7 @@
#include "taler-exchange-httpd.h"
#include "taler-exchange-httpd_db.h"
+
/**
* Add headers we want to return in every response.
* Useful for testing, like if we want to always close
@@ -45,6 +46,28 @@ TEH_RESPONSE_add_global_headers (struct MHD_Response *response);
/**
+ * Try to compress a response body. Updates @a buf and @buf_size.
+ *
+ * @param[in,out] buf pointer to body to compress
+ * @param[in,out] buf_size pointer to initial size of @a buf
+ * @return #MHD_TES if @a buf was compressed
+ */
+int
+TEH_RESPONSE_body_compress (void **buf,
+ size_t *buf_size);
+
+
+/**
+ * Is HTTP body deflate compression supported by the client?
+ *
+ * @param connection connection to check
+ * @return #MHD_YES if 'deflate' compression is allowed
+ */
+int
+TEH_RESPONSE_can_compress (struct MHD_Connection *connection);
+
+
+/**
* Send JSON object as response.
*
* @param connection the MHD connection