Skip to content

Commit

Permalink
Add: compress responses in exec_gmp_get with Brotli
Browse files Browse the repository at this point in the history
  • Loading branch information
mattmundell authored and timopollmeier committed Jan 9, 2024
1 parent c216336 commit 2cf505d
Show file tree
Hide file tree
Showing 2 changed files with 122 additions and 21 deletions.
8 changes: 7 additions & 1 deletion src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ pkg_check_modules (LIBGVM_UTIL REQUIRED libgvm_util>=22.6)
pkg_check_modules (LIBGVM_GMP REQUIRED libgvm_gmp>=22.6)
pkg_check_modules (GNUTLS REQUIRED gnutls>=3.2.15)
pkg_check_modules (ZLIB REQUIRED zlib>=1.2)
pkg_check_modules (BROTLI libbrotlienc)

message (STATUS "Looking for libgcrypt...")
find_library (LIBGCRYPT gcrypt)
Expand Down Expand Up @@ -63,6 +64,9 @@ set (HARDENING_FLAGS "-D_FORTIFY_SOURCE=2 -fstack-protector")
set (LINKER_HARDENING_FLAGS "-Wl,-z,relro -Wl,-z,now")

set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wformat -Wformat-security")
if (BROTLI_FOUND)
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DHAVE_BROTLI=1")
endif (BROTLI_FOUND)

set (CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Werror")
set (CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${HARDENING_FLAGS}")
Expand All @@ -73,7 +77,8 @@ include_directories (${LIBMICROHTTPD_INCLUDE_DIRS} ${LIBXML_INCLUDE_DIRS}
${LIBGVM_UTIL_INCLUDE_DIRS}
${LIBGVM_GMP_INCLUDE_DIRS}
${GNUTLS_INCLUDE_DIRS}
${ZLIB_INCLUDE_DIRS})
${ZLIB_INCLUDE_DIRS}
${BROTLI_INCLUDE_DIRS})

find_package (Threads)

Expand Down Expand Up @@ -104,6 +109,7 @@ target_link_libraries (gsad ${LIBMICROHTTPD_LDFLAGS}
${LIBGCRYPT_LDFLAGS}
${GNUTLS_LDFLAGS}
${ZLIB_LDFLAGS}
${BROTLI_LDFLAGS}
${LIBGVM_BASE_LDFLAGS}
${LIBGVM_UTIL_LDFLAGS}
${LIBGVM_GMP_LDFLAGS}
Expand Down
135 changes: 115 additions & 20 deletions src/gsad.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@

#include <arpa/inet.h>
#include <assert.h>
#ifdef HAVE_BROTLI
#include <brotli/encode.h>
#endif
#include <errno.h>
#include <gcrypt.h>
#include <glib.h>
Expand Down Expand Up @@ -1158,32 +1161,59 @@ watch_client_connection (void *data)
* @return 1 if may, else 0.
*/
static int
may_compress_response (http_connection_t *con)
may_compress (http_connection_t *con, const char *encoding)
{
const char *ae;
const char *de;
const char *all, *one;

ae = MHD_lookup_connection_value (con, MHD_HEADER_KIND,
MHD_HTTP_HEADER_ACCEPT_ENCODING);
if (ae == NULL)
all = MHD_lookup_connection_value (con, MHD_HEADER_KIND,
MHD_HTTP_HEADER_ACCEPT_ENCODING);
if (all == NULL)
return 0;
if (strcmp (ae, "*") == 0)
if (strcmp (all, "*") == 0)
return 1;

de = strstr (ae, "deflate");
if (de == NULL)
one = strstr (all, encoding);
if (one == NULL)
return 0;

if (((de == ae) || (de[-1] == ',') || (de[-1] == ' '))
&& ((de[strlen ("deflate")] == '\0') || (de[strlen ("deflate")] == ',')
|| (de[strlen ("deflate")] == ';')))
if (((one == all) || (one[-1] == ',') || (one[-1] == ' '))
&& ((one[strlen (encoding)] == '\0') || (one[strlen (encoding)] == ',')
|| (one[strlen (encoding)] == ';')))
return 1;

return 0;
}

/**
* @brief Compress response.
* @brief Check whether may compress response.
*
* @param[in] con HTTP Connection
*
* @return 1 if may, else 0.
*/
static int
may_deflate (http_connection_t *con)
{
return may_compress (con, "deflate");
}

#ifdef HAVE_BROTLI
/**
* @brief Check whether may compress response.
*
* @param[in] con HTTP Connection
*
* @return 1 if may, else 0.
*/
static int
may_brotli (http_connection_t *con)
{
return may_compress (con, "br");
}
#endif

/**
* @brief Compress response with zlib.
*
* @param[in] res_len Response length.
* @param[in] res Response.
Expand All @@ -1193,8 +1223,8 @@ may_compress_response (http_connection_t *con)
* @return 1 on success, else 0.
*/
static int
compress_response (const size_t res_len, const char *res, size_t *comp_len,
char **comp)
compress_response_deflate (const size_t res_len, const char *res, size_t *comp_len,
char **comp)
{
Bytef *cbuf;
uLongf cbuf_size;
Expand All @@ -1216,6 +1246,50 @@ compress_response (const size_t res_len, const char *res, size_t *comp_len,
return 0;
}

#ifdef HAVE_BROTLI
/**
* @brief Compress response with Brotli.
*
* @param[in] res_len Response length.
* @param[in] res Response.
* @param[out] comp_len Compressed length.
* @param[out] comp Compressed response.
*
* @return 1 on success, else 0.
*/
static int
compress_response_brotli (const size_t res_len, const char *res, size_t *comp_len,
char **comp)
{
size_t cbuf_size;
uint8_t *cbuf;
int ret;

cbuf_size = BrotliEncoderMaxCompressedSize (res_len);
cbuf = g_malloc (cbuf_size);

ret = BrotliEncoderCompress (BROTLI_DEFAULT_QUALITY,
BROTLI_DEFAULT_WINDOW,
BROTLI_DEFAULT_MODE,
res_len,
(uint8_t*) res,
&cbuf_size,
cbuf);

if ((ret == BROTLI_TRUE) && (cbuf_size < res_len))
{
*comp = (char *) cbuf;
*comp_len = cbuf_size;
g_warning ("%s: 1", __func__);
return 1;
}

g_free (cbuf);
g_warning ("%s: 0", __func__);
return 0;
}
#endif

/**
* @brief Handle a complete GET request.
*
Expand All @@ -1242,8 +1316,10 @@ exec_gmp_get (http_connection_t *con, gsad_connection_info_t *con_info,
cmd_response_data_t *response_data;
pthread_t watch_thread;
connection_watcher_data_t *watcher_data;
validator_t validator = get_validator ();
validator_t validator;
gchar *encoding;

validator = get_validator ();
response_data = cmd_response_data_new ();

cmd = params_value (params, "cmd");
Expand Down Expand Up @@ -1547,24 +1623,43 @@ exec_gmp_get (http_connection_t *con, gsad_connection_info_t *con_info,
if (res_len == 0)
res_len = strlen (res);

if (may_compress_response (con))
encoding = NULL;

#ifdef HAVE_BROTLI
if (may_brotli (con))
{
gsize comp_len;

if (compress_response_brotli (res_len, res, &comp_len, &comp))
{
free (res);
res_len = comp_len;
res = comp;
encoding = "br";
}
}
#endif

if ((encoding == NULL)
&& may_deflate (con))
{
gsize comp_len;

if (compress_response (res_len, res, &comp_len, &comp))
if (compress_response_deflate (res_len, res, &comp_len, &comp))
{
free (res);
res_len = comp_len;
res = comp;
encoding = "deflate";
}
}

response = MHD_create_response_from_buffer (res_len, (void *) res,
MHD_RESPMEM_MUST_FREE);

if (comp)
if (encoding)
MHD_add_response_header (response, MHD_HTTP_HEADER_CONTENT_ENCODING,
"deflate");
encoding);

if (watcher_data)
{
Expand Down

0 comments on commit 2cf505d

Please sign in to comment.