AC_SUBST(FEATURE_HTTPS_INSPECTION_ONLY)
+dnl ========================================================
+dnl Check for Brotli which can be used for decompression
+dnl ========================================================
+WITH_BROTLI=no
+AC_ARG_WITH(brotli,
+AC_HELP_STRING([--with-brotli], [Enable Brotli detection])
+AC_HELP_STRING([--without-brotli], [Disable Brotli detection]),
+ WITH_BROTLI=$withval)
+
+if test X"$WITH_BROTLI" != Xno; then
+
+ LIBS="$LIBS -lbrotlidec"
+
+ AC_CHECK_LIB(brotlidec, BrotliDecoderDecompress)
+
+ AC_CHECK_HEADERS(brotli/decode.h,
+ FEATURE_BROTLI=1
+ AC_DEFINE(FEATURE_BROTLI, 1, [If Brotli is used for decompression])
+ AC_SUBST(FEATURE_BROTLI, [1])
+ )
+fi
+
+
dnl =================================================================
dnl Final cleanup and output
dnl =================================================================
* If the body has a supported transfer-encoding,
* decompress it, adjusting size and iob->eod.
*/
- if (csp->content_type & (CT_GZIP|CT_DEFLATE))
+ if ((csp->content_type & (CT_GZIP|CT_DEFLATE))
+#ifdef FEATURE_BROTLI
+ || (csp->content_type & CT_BROTLI)
+#endif
+ )
{
if (0 == csp->iob->eod - csp->iob->cur)
{
else
{
/*
- * Unset CT_GZIP and CT_DEFLATE to remember not
- * to modify the Content-Encoding header later.
+ * Unset content types to remember not to
+ * modify the Content-Encoding header later.
*/
csp->content_type &= ~CT_GZIP;
csp->content_type &= ~CT_DEFLATE;
+#ifdef FEATURE_BROTLI
+ csp->content_type &= ~CT_BROTLI;
+#endif
}
}
#endif
#define GZIP_FLAG_COMMENT 0x10
#define GZIP_FLAG_RESERVED_BITS 0xe0
#endif
+#ifdef FEATURE_BROTLI
+#include <brotli/decode.h>
+#endif
#if !defined(_WIN32) && !defined(__OS2__)
#include <unistd.h>
#ifdef FEATURE_ZLIB
+#ifdef FEATURE_BROTLI
+/*********************************************************************
+ *
+ * Function : decompress_iob_with_brotli
+ *
+ * Description : Decompress buffered page using Brotli.
+ *
+ * Parameters :
+ * 1 : csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns : JB_ERR_OK on success,
+ * JB_ERR_MEMORY if out-of-memory limit reached, and
+ * JB_ERR_COMPRESS if error decompressing buffer.
+ *
+ *********************************************************************/
+static jb_err decompress_iob_with_brotli(struct client_state *csp)
+{
+ BrotliDecoderResult result;
+ char *decoded_buffer;
+ size_t decoded_size;
+ size_t decoded_buffer_size;
+ size_t encoded_size;
+ enum { MAX_COMPRESSION_FACTOR = 15 };
+
+ encoded_size = (size_t)(csp->iob->eod - csp->iob->cur);
+ /*
+ * The BrotliDecoderDecompress() api is a bit unfortunate
+ * and requires the caller to reserve enough memory for
+ * the decompressed content. Hopefully reserving
+ * MAX_COMPRESSION_FACTOR times the original size is
+ * sufficient. If not, BrotliDecoderDecompress() will fail.
+ */
+ decoded_buffer_size = encoded_size * MAX_COMPRESSION_FACTOR;
+
+ if (decoded_buffer_size > csp->config->buffer_limit)
+ {
+ log_error(LOG_LEVEL_ERROR,
+ "Buffer limit reached before decompressing iob with Brotli");
+ return JB_ERR_MEMORY;
+ }
+
+ decoded_buffer = malloc(decoded_buffer_size);
+ if (decoded_buffer == NULL)
+ {
+ log_error(LOG_LEVEL_ERROR,
+ "Failed to allocate %d bytes for Brotli decompression",
+ decoded_buffer_size);
+ return JB_ERR_MEMORY;
+ }
+
+ decoded_size = decoded_buffer_size;
+ result = BrotliDecoderDecompress(encoded_size,
+ (const uint8_t *)csp->iob->cur, &decoded_size,
+ (uint8_t *)decoded_buffer);
+ if (result == BROTLI_DECODER_RESULT_SUCCESS)
+ {
+ /*
+ * Update the iob, since the decompression was successful.
+ */
+ freez(csp->iob->buf);
+ csp->iob->buf = decoded_buffer;
+ csp->iob->cur = csp->iob->buf;
+ csp->iob->eod = csp->iob->cur + decoded_size;
+ csp->iob->size = decoded_buffer_size;
+
+ log_error(LOG_LEVEL_RE_FILTER,
+ "Decompression successful. Old size: %d, new size: %d.",
+ encoded_size, decoded_size);
+
+ return JB_ERR_OK;
+ }
+ else
+ {
+ log_error(LOG_LEVEL_ERROR, "Failed to decompress buffer with Brotli");
+ freez(decoded_buffer);
+
+ return JB_ERR_COMPRESS;
+ }
+}
+#endif
+
/*********************************************************************
*
* Function : decompress_iob
return JB_ERR_COMPRESS;
}
+#ifdef FEATURE_BROTLI
+ if (csp->content_type & CT_BROTLI)
+ {
+ return decompress_iob_with_brotli(csp);
+ }
+#endif
+
if (csp->content_type & CT_GZIP)
{
/*
/* Mark for zlib decompression */
csp->content_type |= CT_DEFLATE;
}
+ else if (strstr(*header, "br"))
+ {
+#ifdef FEATURE_BROTLI
+ /* Mark for Brotli decompression */
+ csp->content_type |= CT_BROTLI;
+#else
+ csp->content_type |= CT_TABOO;
+#endif
+ }
else if (strstr(*header, "compress"))
{
/*
static jb_err server_adjust_content_encoding(struct client_state *csp, char **header)
{
if ((csp->flags & CSP_FLAG_MODIFIED)
- && (csp->content_type & (CT_GZIP | CT_DEFLATE)))
+ && ((csp->content_type & (CT_GZIP | CT_DEFLATE))
+#ifdef FEATURE_BROTLI
+ || (csp->content_type & CT_BROTLI)
+#endif
+ )
+ )
{
/*
* We successfully decompressed the content,