[libsoup/wip/tingping/brotli] Implement Brotli decompression support
- From: Patrick Griffis <pgriffis src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libsoup/wip/tingping/brotli] Implement Brotli decompression support
- Date: Wed, 27 Feb 2019 18:59:24 +0000 (UTC)
commit b4cd510be35ce8ba43b08a4980092ae2f9b112d1
Author: Patrick Griffis <pgriffis igalia com>
Date: Wed Feb 27 13:26:36 2019 -0500
Implement Brotli decompression support
libsoup/meson.build | 10 +-
libsoup/soup-brotli-decompressor.c | 181 +++++++++++++++++++++++++++++++++++++
libsoup/soup-brotli-decompressor.h | 37 ++++++++
libsoup/soup-content-decoder.c | 21 ++++-
meson.build | 8 ++
meson_options.txt | 6 ++
tests/brotli-data/compressed.br | Bin 0 -> 1218 bytes
tests/brotli-data/corrupt.br | Bin 0 -> 1218 bytes
tests/brotli-data/uncompressed.txt | 9 ++
tests/brotli-decompressor-test.c | 158 ++++++++++++++++++++++++++++++++
tests/meson.build | 6 ++
11 files changed, 434 insertions(+), 2 deletions(-)
---
diff --git a/libsoup/meson.build b/libsoup/meson.build
index 5f2a2156..0636dca2 100644
--- a/libsoup/meson.build
+++ b/libsoup/meson.build
@@ -84,6 +84,7 @@ soup_headers = [
'soup-auth-negotiate.h',
'soup-body-input-stream.h',
'soup-body-output-stream.h',
+ 'soup-brotli-decompressor.h',
'soup-cache-client-input-stream.h',
'soup-cache-input-stream.h',
'soup-cache-private.h',
@@ -183,6 +184,12 @@ soup_gnome_installed_headers = soup_gnome_introspection_headers + [
'soup-gnome.h'
]
+if brotlidec_dep.found()
+ soup_sources += 'soup-brotli-decompressor.c'
+ soup_headers += 'soup-brotli-decompressor.h'
+endif
+
+
includedir = join_paths(libsoup_api_name, meson.project_name())
install_headers(soup_installed_headers, subdir : includedir)
@@ -220,7 +227,8 @@ deps = [
libxml_dep,
sqlite_dep,
libpsl_dep,
- platform_deps
+ brotlidec_dep,
+ platform_deps,
]
libsoup = library('soup-@0@'.format(apiversion),
diff --git a/libsoup/soup-brotli-decompressor.c b/libsoup/soup-brotli-decompressor.c
new file mode 100644
index 00000000..cb7da557
--- /dev/null
+++ b/libsoup/soup-brotli-decompressor.c
@@ -0,0 +1,181 @@
+/* soup-brotli-decompressor.c
+ *
+ * Copyright 2019 Igalia S.L.
+ *
+ * This file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.0-or-later
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <brotli/decode.h>
+#include <gio/gio.h>
+
+#include "soup-brotli-decompressor.h"
+
+struct _SoupBrotliDecompressor
+{
+ GObject parent_instance;
+ BrotliDecoderState *state;
+ GError *last_error;
+};
+
+static void soup_brotli_decompressor_iface_init (GConverterIface *iface);
+
+G_DEFINE_TYPE_EXTENDED (SoupBrotliDecompressor, soup_brotli_decompressor, G_TYPE_OBJECT, 0,
+ G_IMPLEMENT_INTERFACE (G_TYPE_CONVERTER, soup_brotli_decompressor_iface_init))
+
+SoupBrotliDecompressor *
+soup_brotli_decompressor_new (void)
+{
+ return g_object_new (SOUP_TYPE_BROTLI_DECOMPRESSOR, NULL);
+}
+
+static GError *
+soup_brotli_decompressor_create_error (SoupBrotliDecompressor *self)
+{
+ BrotliDecoderErrorCode code;
+ const char *error_string;
+
+ g_assert (self->state != NULL);
+ code = BrotliDecoderGetErrorCode (self->state);
+ error_string = BrotliDecoderErrorString (code);
+ return g_error_new (G_IO_ERROR, G_IO_ERROR_FAILED, "SoupBrotliDecompressorError: %s", error_string);
+}
+
+static void
+soup_brotli_decompressor_set_error (SoupBrotliDecompressor *self,
+ GError **error)
+{
+ BrotliDecoderErrorCode code;
+ const char *error_string;
+
+ if (error == NULL)
+ return;
+
+ g_assert (self->state != NULL);
+ code = BrotliDecoderGetErrorCode (self->state);
+ error_string = BrotliDecoderErrorString (code);
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "SoupBrotliDecompressorError: %s", error_string);
+}
+
+static GConverterResult
+soup_brotli_decompressor_convert (GConverter *converter,
+ const void *inbuf,
+ gsize inbuf_size,
+ void *outbuf,
+ gsize outbuf_size,
+ GConverterFlags flags,
+ gsize *bytes_read,
+ gsize *bytes_written,
+ GError **error)
+{
+ SoupBrotliDecompressor *self = SOUP_BROTLI_DECOMPRESSOR (converter);
+ BrotliDecoderResult result;
+ gsize available_in = inbuf_size;
+ const guint8 *next_in = inbuf;
+ gsize available_out = outbuf_size;
+ guchar *next_out = outbuf;
+
+ g_return_val_if_fail (inbuf, G_CONVERTER_ERROR);
+
+ if (self->last_error) {
+ if (error)
+ *error = g_steal_pointer (&self->last_error);
+ g_clear_error (&self->last_error);
+ return G_CONVERTER_ERROR;
+ }
+
+ /* NOTE: all error domains/quarks are designed to match GZlibDecompressor even if GConverter has its
own */
+
+ if (self->state == NULL) {
+ self->state = BrotliDecoderCreateInstance (NULL, NULL, NULL);
+ if (self->state == NULL) {
+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"SoupBrotliDecompressorError: Failed to initialize state");
+ return G_CONVERTER_ERROR;
+ }
+ }
+
+ result = BrotliDecoderDecompressStream (self->state, &available_in, &next_in, &available_out,
&next_out, NULL);
+
+ /* available_in is now set to *unread* input size */
+ *bytes_read = inbuf_size - available_in;
+ /* available_out is now set to *unwritten* output size */
+ *bytes_written = outbuf_size - available_out;
+
+ /* As per API docs: If any data was either produced or consumed, and then an error happens, then only
+ * the successful conversion is reported and the error is returned on the next call. */
+ if (*bytes_read || *bytes_written) {
+ if (result == BROTLI_DECODER_RESULT_ERROR)
+ self->last_error = soup_brotli_decompressor_create_error (self);
+ else if (result == BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT)
+ self->last_error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_PARTIAL_INPUT,
"SoupBrotliDecompressorError: More input required (corrupt input)");
+
+ /* BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT just means continue */
+ return G_CONVERTER_CONVERTED;
+ }
+
+ if (result == BROTLI_DECODER_RESULT_SUCCESS)
+ return G_CONVERTER_FINISHED;
+ else if (result == BROTLI_DECODER_RESULT_ERROR) {
+ soup_brotli_decompressor_set_error (self, error);
+ return G_CONVERTER_ERROR;
+ } else if (result == BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT) {
+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_PARTIAL_INPUT,
"SoupBrotliDecompressorError 2: More input required (corrupt input)");
+ return G_CONVERTER_ERROR;
+ }
+
+ g_assert_not_reached ();
+ return G_CONVERTER_CONVERTED;
+}
+
+static void
+soup_brotli_decompressor_reset (GConverter *converter)
+{
+ SoupBrotliDecompressor *self = SOUP_BROTLI_DECOMPRESSOR (converter);
+
+ if (self->state && BrotliDecoderIsUsed (self->state))
+ g_clear_pointer (&self->state, BrotliDecoderDestroyInstance);
+ g_clear_error (&self->last_error);
+}
+
+static void
+soup_brotli_decompressor_finalize (GObject *object)
+{
+ SoupBrotliDecompressor *self = (SoupBrotliDecompressor *)object;
+ g_clear_pointer (&self->state, BrotliDecoderDestroyInstance);
+ g_clear_error (&self->last_error);
+ G_OBJECT_CLASS (soup_brotli_decompressor_parent_class)->finalize (object);
+}
+
+static void soup_brotli_decompressor_iface_init (GConverterIface *iface)
+{
+ iface->convert = soup_brotli_decompressor_convert;
+ iface->reset = soup_brotli_decompressor_reset;
+}
+
+static void
+soup_brotli_decompressor_class_init (SoupBrotliDecompressorClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ object_class->finalize = soup_brotli_decompressor_finalize;
+}
+
+static void
+soup_brotli_decompressor_init (SoupBrotliDecompressor *self)
+{
+}
diff --git a/libsoup/soup-brotli-decompressor.h b/libsoup/soup-brotli-decompressor.h
new file mode 100644
index 00000000..ddce4fe3
--- /dev/null
+++ b/libsoup/soup-brotli-decompressor.h
@@ -0,0 +1,37 @@
+/* soup-brotli-decompressor.h
+ *
+ * Copyright 2019 Igalia S.L.
+ *
+ * This file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.0-or-later
+ */
+
+#pragma once
+
+#include <glib-object.h>
+#include "soup-version.h"
+
+G_BEGIN_DECLS
+
+#define SOUP_TYPE_BROTLI_DECOMPRESSOR (soup_brotli_decompressor_get_type())
+G_DECLARE_FINAL_TYPE (SoupBrotliDecompressor, soup_brotli_decompressor, SOUP, BROTLI_DECOMPRESSOR, GObject)
+
+SOUP_AVAILABLE_IN_2_66
+SoupBrotliDecompressor *soup_brotli_decompressor_new (void);
+
+SOUP_AVAILABLE_IN_2_66
+GType soup_brotli_decompressor_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
diff --git a/libsoup/soup-content-decoder.c b/libsoup/soup-content-decoder.c
index 080904aa..c485c6e6 100644
--- a/libsoup/soup-content-decoder.c
+++ b/libsoup/soup-content-decoder.c
@@ -13,6 +13,9 @@
#include "soup-converter-wrapper.h"
#include "soup.h"
#include "soup-message-private.h"
+#ifdef WITH_BROTLI
+#include "soup-brotli-decompressor.h"
+#endif
/**
* SECTION:soup-content-decoder
@@ -20,7 +23,7 @@
*
* #SoupContentDecoder handles adding the "Accept-Encoding" header on
* outgoing messages, and processing the "Content-Encoding" header on
- * incoming ones. Currently it supports the "gzip" and "deflate"
+ * incoming ones. Currently it supports the "gzip", "deflate", and "br"
* content codings.
*
* If you are using a plain #SoupSession (ie, not #SoupSessionAsync or
@@ -169,7 +172,11 @@ soup_content_decoder_content_processor_init (SoupContentProcessorInterface *proc
}
/* This is constant for now */
+#ifdef WITH_BROTLI
+#define ACCEPT_ENCODING_HEADER "gzip, deflate, br"
+#else
#define ACCEPT_ENCODING_HEADER "gzip, deflate"
+#endif
static GConverter *
gzip_decoder_creator (void)
@@ -183,6 +190,14 @@ zlib_decoder_creator (void)
return (GConverter *)g_zlib_decompressor_new (G_ZLIB_COMPRESSOR_FORMAT_ZLIB);
}
+#ifdef WITH_BROTLI
+static GConverter *
+brotli_decoder_creator (void)
+{
+ return (GConverter *)soup_brotli_decompressor_new ();
+}
+#endif
+
static void
soup_content_decoder_init (SoupContentDecoder *decoder)
{
@@ -196,6 +211,10 @@ soup_content_decoder_init (SoupContentDecoder *decoder)
gzip_decoder_creator);
g_hash_table_insert (decoder->priv->decoders, "deflate",
zlib_decoder_creator);
+#ifdef WITH_BROTLI
+ g_hash_table_insert (decoder->priv->decoders, "br",
+ brotli_decoder_creator);
+#endif
}
static void
diff --git a/meson.build b/meson.build
index bb5ea925..65de51a3 100644
--- a/meson.build
+++ b/meson.build
@@ -64,6 +64,7 @@ glib_dep = [dependency('glib-2.0', version : glib_required_version,
sqlite_dep = dependency('sqlite3', required: false)
+
# Fallback check for sqlite, not all platforms ship pkg-config file
if not sqlite_dep.found()
cc.has_header('sqlite3.h')
@@ -83,6 +84,13 @@ endif
cdata = configuration_data()
+if get_option('brotli')
+ brotlidec_dep = dependency('libbrotlidec')
+ cdata.set('WITH_BROTLI', true)
+else
+ brotlidec_dep = dependency('', required: false)
+endif
+
platform_deps = []
hidden_visibility_flag = []
is_static_library = get_option('default_library') == 'static'
diff --git a/meson_options.txt b/meson_options.txt
index 774e8777..74f58da9 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -22,6 +22,12 @@ option('ntlm_auth',
description : 'Where to look for ntlm_auth, path points to ntlm_auth installation (defaultly looking in
PATH)'
)
+option('brotli',
+ type : 'boolean',
+ value : true,
+ description : 'Build with Brotli decompression support'
+)
+
option('tls_check',
type : 'boolean',
value : true,
diff --git a/tests/brotli-data/compressed.br b/tests/brotli-data/compressed.br
new file mode 100644
index 00000000..affb5ff7
Binary files /dev/null and b/tests/brotli-data/compressed.br differ
diff --git a/tests/brotli-data/corrupt.br b/tests/brotli-data/corrupt.br
new file mode 100644
index 00000000..2bbbeba5
Binary files /dev/null and b/tests/brotli-data/corrupt.br differ
diff --git a/tests/brotli-data/uncompressed.txt b/tests/brotli-data/uncompressed.txt
new file mode 100644
index 00000000..cd141c03
--- /dev/null
+++ b/tests/brotli-data/uncompressed.txt
@@ -0,0 +1,9 @@
+Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam facilisis imperdiet arcu, cursus feugiat
velit ultricies vel. Sed consequat velit id purus finibus, ut semper felis tincidunt. Phasellus non lobortis
justo. Duis et fermentum dui, id pharetra tellus. Aenean egestas est diam. Etiam lacinia eu diam et
fringilla. Integer fringilla, neque non rhoncus venenatis, mauris leo lobortis dolor, id porta dui mi a nibh.
Quisque libero orci, eleifend id ornare ut, tristique quis tellus. Nullam urna sem, sollicitudin sit amet
urna id, elementum ornare lectus. Curabitur at luctus arcu, nec viverra odio. Donec luctus, ante ac imperdiet
dictum, purus diam fringilla tortor, in posuere nisl nibh et ante. Mauris dapibus, est sed condimentum
eleifend, sapien ante rhoncus dui, id porta ante libero at leo.
+
+Vivamus in ligula a mi mollis pellentesque eget sed nisl. Cras viverra semper diam. Donec consectetur
placerat dignissim. Donec et porttitor urna. Pellentesque placerat at mi a blandit. Sed nec tellus ac sem
semper mattis. Mauris mollis libero quam, vitae tincidunt nisi ullamcorper vel. Proin sapien purus, commodo
at urna nec, viverra volutpat neque. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+
+Duis consectetur, justo a consequat condimentum, lectus tortor ultricies justo, nec tincidunt turpis erat
vitae nisi. Praesent at volutpat lacus. Orci varius natoque penatibus et magnis dis parturient montes,
nascetur ridiculus mus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis
egestas. Cras sodales libero vitae ultricies dictum. Integer sollicitudin eu arcu non hendrerit. Etiam vel
maximus odio. Quisque ex diam, porta sit amet scelerisque vel, tempor nec purus. In fermentum lectus at risus
ullamcorper rhoncus. Vestibulum nulla arcu, commodo a vestibulum vel, porttitor et metus. Phasellus facilisis
justo vitae quam maximus, interdum fermentum risus dignissim.
+
+Phasellus tristique sollicitudin orci ac scelerisque. Integer vulputate laoreet rutrum. Nullam mauris elit,
lobortis et elementum at, vestibulum at magna. Curabitur accumsan leo ut nisi scelerisque maximus. Cras risus
metus, suscipit non volutpat eget, lobortis eu erat. Vestibulum sed dolor egestas, ornare est nec, molestie
nisi. Integer laoreet, ipsum non finibus rhoncus, erat nisi lacinia dui, vulputate imperdiet odio nulla eget
ipsum. Nam sed cursus metus. Quisque lacinia consectetur erat, et dictum mi interdum sit amet. Praesent
eleifend luctus odio in faucibus.
+
+Donec in diam rhoncus, vehicula tortor at, molestie erat. Nulla tempor in justo ut gravida. Praesent ornare
laoreet ante non faucibus. Donec cursus mi sit amet fringilla bibendum. Ut tincidunt, libero nec scelerisque
lobortis, nisi nunc laoreet velit, vitae sodales est purus vehicula urna. Phasellus fringilla mi tellus, in
convallis diam maximus et. Praesent iaculis id sem sit amet posuere. Integer ullamcorper, eros ultrices
placerat finibus, turpis sem commodo augue, ac ornare massa ante nec nulla.
diff --git a/tests/brotli-decompressor-test.c b/tests/brotli-decompressor-test.c
new file mode 100644
index 00000000..df236677
--- /dev/null
+++ b/tests/brotli-decompressor-test.c
@@ -0,0 +1,158 @@
+/* brotli-decompressor-test.c
+ *
+ * Copyright 2019 Igalia S.L.
+ *
+ * This file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.0-or-later
+ */
+
+#include "test-utils.h"
+#include "libsoup/soup-brotli-decompressor.h"
+
+static void
+test_brotli (void)
+{
+ SoupBrotliDecompressor *dec = soup_brotli_decompressor_new ();
+ char *compressed_filename = g_build_filename (g_test_get_dir (G_TEST_DIST), "brotli-data",
"compressed.br", NULL);
+ char *uncompressed_filename = g_build_filename (g_test_get_dir (G_TEST_DIST), "brotli-data",
"uncompressed.txt", NULL);
+ char *contents;
+ gsize length;
+ GByteArray *out_bytes = g_byte_array_new ();
+ char *in_buf;
+ GConverterResult result;
+
+ g_assert_true (g_file_get_contents (compressed_filename, &contents, &length, NULL));
+ in_buf = contents;
+
+ do {
+ GError *error = NULL;
+ guint8 out_buf[16]; /* This is stupidly small just to simulate common usage of converting in
chunks */
+ gsize bytes_read, bytes_written;
+ result = g_converter_convert (G_CONVERTER (dec), in_buf, length, out_buf, sizeof out_buf, 0,
+ &bytes_read, &bytes_written, &error);
+
+ g_assert_no_error (error);
+ g_assert_cmpint (result, !=, G_CONVERTER_ERROR);
+
+ g_byte_array_append (out_bytes, out_buf, bytes_written);
+ in_buf += bytes_read;
+ length -= bytes_read;
+
+ } while (result == G_CONVERTER_CONVERTED);
+
+ g_assert_cmpint (result, ==, G_CONVERTER_FINISHED);
+
+ g_free (contents);
+ g_assert_true (g_file_get_contents (uncompressed_filename, &contents, &length, NULL));
+ g_assert_cmpstr ((char*)out_bytes->data, ==, contents);
+
+ g_byte_array_free (out_bytes, TRUE);
+ g_object_unref (dec);
+ g_free (compressed_filename);
+ g_free (contents);
+}
+
+static void
+test_brotli_corrupt (void)
+{
+ SoupBrotliDecompressor *dec = soup_brotli_decompressor_new ();
+ char *compressed_filename = g_build_filename (g_test_get_dir (G_TEST_DIST), "brotli-data",
"corrupt.br", NULL);
+ GError *error = NULL;
+ char *contents;
+ gsize length;
+ char *in_buf;
+ GConverterResult result;
+
+ g_assert_true (g_file_get_contents (compressed_filename, &contents, &length, NULL));
+ in_buf = contents;
+
+ do {
+ guint8 out_buf[4096];
+ gsize bytes_read, bytes_written;
+ result = g_converter_convert (G_CONVERTER (dec), in_buf, length, out_buf, sizeof out_buf, 0,
+ &bytes_read, &bytes_written, &error);
+
+ in_buf += bytes_read;
+ length -= bytes_read;
+ } while (result == G_CONVERTER_CONVERTED);
+
+ g_assert_cmpint (result, ==, G_CONVERTER_ERROR);
+ g_assert_error (error, G_IO_ERROR, G_IO_ERROR_FAILED);
+
+ g_object_unref (dec);
+ g_free (compressed_filename);
+ g_free (contents);
+ g_error_free (error);
+}
+
+static void
+test_brotli_reset (void)
+{
+ SoupBrotliDecompressor *dec = soup_brotli_decompressor_new ();
+ char *compressed_filename = g_build_filename (g_test_get_dir (G_TEST_DIST), "brotli-data",
"compressed.br", NULL);
+ char *contents;
+ gsize length, in_len;
+ char *in_buf;
+ GConverterResult result;
+ int iterations = 0;
+
+ g_assert_true (g_file_get_contents (compressed_filename, &contents, &length, NULL));
+ in_buf = contents;
+ in_len = length;
+
+ do {
+ GError *error = NULL;
+ guint8 out_buf[16];
+ gsize bytes_read, bytes_written;
+ result = g_converter_convert (G_CONVERTER (dec), in_buf, in_len, out_buf, sizeof out_buf, 0,
+ &bytes_read, &bytes_written, &error);
+
+ /* Just randomly reset in the middle and ensure everything keeps working */
+ if (iterations == 6) {
+ g_converter_reset (G_CONVERTER (dec));
+ in_buf = contents;
+ in_len = length;
+ }
+
+ g_assert_no_error (error);
+ g_assert_cmpint (result, !=, G_CONVERTER_ERROR);
+ in_buf += bytes_read;
+ in_len -= bytes_read;
+ ++iterations;
+ } while (result == G_CONVERTER_CONVERTED);
+
+ g_assert_cmpint (result, ==, G_CONVERTER_FINISHED);
+
+ g_object_unref (dec);
+ g_free (compressed_filename);
+ g_free (contents);
+}
+
+int
+main (int argc, char **argv)
+{
+
+ int ret;
+
+ test_init (argc, argv, NULL);
+
+ g_test_add_func ("/brotli/basic", test_brotli);
+ g_test_add_func ("/brotli/corrupt", test_brotli_corrupt);
+ g_test_add_func ("/brotli/reset", test_brotli_reset);
+
+ ret = g_test_run ();
+ test_cleanup ();
+ return ret;
+}
diff --git a/tests/meson.build b/tests/meson.build
index 8176f29b..ea1cabd3 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -44,6 +44,12 @@ tests = [
['websocket', true]
]
+if brotlidec_dep.found()
+ tests += [
+ ['brotli-decompressor', true],
+ ]
+endif
+
if have_apache
tests += [
['auth', false],
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]