From: Dan Winship Date: Fri, 10 Dec 2010 11:44:59 +0000 (+0100) Subject: Remove SoupCoding, SoupCodingGZip, use GZlibDecompressor X-Git-Tag: LIBSOUP_2_33_4~8 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=8d77fee770814f33f287b26f2898ed986ff9d3b4;p=platform%2Fupstream%2Flibsoup.git Remove SoupCoding, SoupCodingGZip, use GZlibDecompressor also add a new test to coding-test for handling content that doesn't decode correctly --- diff --git a/libsoup/Makefile.am b/libsoup/Makefile.am index 5ed63f1..a26d820 100644 --- a/libsoup/Makefile.am +++ b/libsoup/Makefile.am @@ -125,10 +125,6 @@ libsoup_2_4_la_SOURCES = \ soup-auth-manager-ntlm.c \ soup-cache.c \ soup-cache-private.h \ - soup-coding.h \ - soup-coding.c \ - soup-coding-gzip.h \ - soup-coding-gzip.c \ soup-connection.h \ soup-connection.c \ soup-content-decoder.c \ diff --git a/libsoup/soup-coding-gzip.c b/libsoup/soup-coding-gzip.c deleted file mode 100644 index 60d57e2..0000000 --- a/libsoup/soup-coding-gzip.c +++ /dev/null @@ -1,148 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * soup-coding-gzip.c: "gzip" coding - * - * Copyright (C) 2005 Novell, Inc. - * Copyright (C) 2008 Red Hat, Inc. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "soup-coding-gzip.h" - -#include - -typedef struct { - z_stream stream; - -} SoupCodingGzipPrivate; -#define SOUP_CODING_GZIP_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUP_TYPE_CODING_GZIP, SoupCodingGzipPrivate)) - -G_DEFINE_TYPE (SoupCodingGzip, soup_coding_gzip, SOUP_TYPE_CODING) - -static void constructed (GObject *object); -static void finalize (GObject *object); -static SoupCodingStatus apply_into (SoupCoding *coding, - gconstpointer input, gsize input_length, - gsize *input_used, - gpointer output, gsize output_length, - gsize *output_used, - gboolean done, GError **error); - -static void -soup_coding_gzip_init (SoupCodingGzip *gzip) -{ - SoupCodingGzipPrivate *priv = SOUP_CODING_GZIP_GET_PRIVATE (gzip); - - priv->stream.zalloc = Z_NULL; - priv->stream.zfree = Z_NULL; - priv->stream.opaque = Z_NULL; -} - -static void -soup_coding_gzip_class_init (SoupCodingGzipClass *gzip_class) -{ - GObjectClass *object_class = G_OBJECT_CLASS (gzip_class); - SoupCodingClass *coding_class = SOUP_CODING_CLASS (gzip_class); - - g_type_class_add_private (gzip_class, sizeof (SoupCodingGzipPrivate)); - - coding_class->name = "gzip"; - - object_class->constructed = constructed; - object_class->finalize = finalize; - - coding_class->apply_into = apply_into; -} - -static void -constructed (GObject *object) -{ - SoupCodingGzipPrivate *priv = SOUP_CODING_GZIP_GET_PRIVATE (object); - - /* All of these values are the defaults according to the zlib - * documentation. "16" is a magic number that means gzip - * instead of zlib. - */ - if (SOUP_CODING (object)->direction == SOUP_CODING_ENCODE) { - deflateInit2 (&priv->stream, Z_DEFAULT_COMPRESSION, - Z_DEFLATED, MAX_WBITS | 16, 8, - Z_DEFAULT_STRATEGY); - } else - inflateInit2 (&priv->stream, MAX_WBITS | 16); -} - -static void -finalize (GObject *object) -{ - SoupCodingGzipPrivate *priv = SOUP_CODING_GZIP_GET_PRIVATE (object); - - if (SOUP_CODING (object)->direction == SOUP_CODING_ENCODE) - deflateEnd (&priv->stream); - else - inflateEnd (&priv->stream); - - G_OBJECT_CLASS (soup_coding_gzip_parent_class)->finalize (object); -} - -static SoupCodingStatus -apply_into (SoupCoding *coding, - gconstpointer input, gsize input_length, gsize *input_used, - gpointer output, gsize output_length, gsize *output_used, - gboolean done, GError **error) -{ - SoupCodingGzipPrivate *priv = SOUP_CODING_GZIP_GET_PRIVATE (coding); - int ret; - - priv->stream.avail_in = input_length; - priv->stream.next_in = (gpointer)input; - priv->stream.total_in = 0; - - priv->stream.avail_out = output_length; - priv->stream.next_out = output; - priv->stream.total_out = 0; - - if (coding->direction == SOUP_CODING_ENCODE) - ret = deflate (&priv->stream, done ? Z_FINISH : Z_NO_FLUSH); - else - ret = inflate (&priv->stream, Z_SYNC_FLUSH); - - *input_used = priv->stream.total_in; - *output_used = priv->stream.total_out; - - switch (ret) { - case Z_NEED_DICT: - case Z_DATA_ERROR: - case Z_STREAM_ERROR: - g_set_error_literal (error, SOUP_CODING_ERROR, - SOUP_CODING_ERROR_DATA_ERROR, - priv->stream.msg ? priv->stream.msg : "Bad data"); - return SOUP_CODING_STATUS_ERROR; - - case Z_BUF_ERROR: - case Z_MEM_ERROR: - g_set_error_literal (error, SOUP_CODING_ERROR, - SOUP_CODING_ERROR_INTERNAL_ERROR, - priv->stream.msg ? priv->stream.msg : "Internal error"); - return SOUP_CODING_STATUS_ERROR; - - case Z_STREAM_END: - /* Discard any trailing junk, for compatibility with - * other browsers. FIXME: this really belongs in - * soup-message-io, but it's not possible to do there - * with the current API. - */ - *input_used = input_length; - return SOUP_CODING_STATUS_COMPLETE; - - case Z_OK: - default: - if (*output_used == output_length && - *input_used < input_length) - return SOUP_CODING_STATUS_NEED_SPACE; - else - return SOUP_CODING_STATUS_OK; - } -} diff --git a/libsoup/soup-coding-gzip.h b/libsoup/soup-coding-gzip.h deleted file mode 100644 index abdca37..0000000 --- a/libsoup/soup-coding-gzip.h +++ /dev/null @@ -1,33 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2005 Novell, Inc. - * Copyright (C) 2008 Red Hat, Inc. - */ - -#ifndef SOUP_CODING_GZIP_H -#define SOUP_CODING_GZIP_H 1 - -#include "soup-coding.h" - -#define SOUP_TYPE_CODING_GZIP (soup_coding_gzip_get_type ()) -#define SOUP_CODING_GZIP(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), SOUP_TYPE_CODING_GZIP, SoupCodingGzip)) -#define SOUP_CODING_GZIP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SOUP_TYPE_CODING_GZIP, SoupCodingGzipClass)) -#define SOUP_IS_CODING_GZIP(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), SOUP_TYPE_CODING_GZIP)) -#define SOUP_IS_CODING_GZIP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SOUP_TYPE_CODING_GZIP)) -#define SOUP_CODING_GZIP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SOUP_TYPE_CODING_GZIP, SoupCodingGzipClass)) - -typedef struct { - SoupCoding parent; - -} SoupCodingGzip; - -typedef struct { - SoupCodingClass parent_class; - -} SoupCodingGzipClass; - -GType soup_coding_gzip_get_type (void); - -SoupCoding *soup_coding_gzip_new (SoupCodingDirection direction); - -#endif /* SOUP_CODING_GZIP_H */ diff --git a/libsoup/soup-coding.c b/libsoup/soup-coding.c deleted file mode 100644 index 74c4826..0000000 --- a/libsoup/soup-coding.c +++ /dev/null @@ -1,258 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * soup-coding.c: Data encoding/decoding class - * - * Copyright (C) 2005 Novell, Inc. - * Copyright (C) 2008 Red Hat, Inc. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "soup-coding.h" -#include "soup-enum-types.h" -#include "soup-session-feature.h" - -static void soup_coding_session_feature_init (SoupSessionFeatureInterface *feature_interface, gpointer interface_data); - -G_DEFINE_TYPE_WITH_CODE (SoupCoding, soup_coding, G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE (SOUP_TYPE_SESSION_FEATURE, - soup_coding_session_feature_init)) - -enum { - PROP_0, - - PROP_DIRECTION, - - LAST_PROP -}; - -static void set_property (GObject *object, guint prop_id, - const GValue *value, GParamSpec *pspec); -static void get_property (GObject *object, guint prop_id, - GValue *value, GParamSpec *pspec); - -static SoupBuffer *apply (SoupCoding *coding, - gconstpointer input, gsize input_length, - gboolean done, GError **error); - -static void -soup_coding_class_init (SoupCodingClass *coding_class) -{ - GObjectClass *object_class = (GObjectClass *)coding_class; - - object_class->set_property = set_property; - object_class->get_property = get_property; - - coding_class->apply = apply; - - /* properties */ - g_object_class_install_property ( - object_class, PROP_DIRECTION, -#if 0 - g_param_spec_enum (SOUP_CODING_DIRECTION, -#else - g_param_spec_uint (SOUP_CODING_DIRECTION, -#endif - "Direction", - "Whether to encode or decode", - 0, 2, - SOUP_CODING_ENCODE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); -} - -static void -soup_coding_session_feature_init (SoupSessionFeatureInterface *feature_interface, - gpointer interface_data) -{ - ; -} - -static void -soup_coding_init (SoupCoding *coding) -{ - ; -} - -static void -set_property (GObject *object, guint prop_id, - const GValue *value, GParamSpec *pspec) -{ - SoupCoding *coding = SOUP_CODING (object); - - switch (prop_id) { - case PROP_DIRECTION: -#if 0 - coding->direction = g_value_get_enum (value); -#else - coding->direction = g_value_get_uint (value); -#endif - break; - default: - break; - } -} - -static void -get_property (GObject *object, guint prop_id, - GValue *value, GParamSpec *pspec) -{ - SoupCoding *coding = SOUP_CODING (object); - - switch (prop_id) { - case PROP_DIRECTION: -#if 0 - g_value_set_enum (value, coding->direction); -#else - g_value_set_uint (value, coding->direction); -#endif - break; - default: - break; - } -} - -static SoupBuffer * -apply (SoupCoding *coding, - gconstpointer input, gsize input_length, - gboolean done, GError **error) -{ - gsize outbuf_length, outbuf_used, outbuf_cur, input_used, input_cur; - char *outbuf; - SoupCodingStatus status; - - if (coding->direction == SOUP_CODING_ENCODE) - outbuf_length = MAX (input_length / 2, 1024); - else - outbuf_length = MAX (input_length * 2, 1024); - outbuf = g_malloc (outbuf_length); - outbuf_cur = input_cur = 0; - - do { - status = soup_coding_apply_into ( - coding, - (guchar *)input + input_cur, input_length - input_cur, - &input_used, - outbuf + outbuf_cur, outbuf_length - outbuf_cur, - &outbuf_used, - done, error); - input_cur += input_used; - outbuf_cur += outbuf_used; - - switch (status) { - case SOUP_CODING_STATUS_OK: - case SOUP_CODING_STATUS_COMPLETE: - break; - - case SOUP_CODING_STATUS_NEED_SPACE: - outbuf_length *= 2; - outbuf = g_realloc (outbuf, outbuf_length); - break; - - case SOUP_CODING_STATUS_ERROR: - default: - g_free (outbuf); - return NULL; - } - } while (input_cur < input_length || - (done && status != SOUP_CODING_STATUS_COMPLETE)); - - if (outbuf_cur) - return soup_buffer_new (SOUP_MEMORY_TAKE, outbuf, outbuf_cur); - else { - g_free (outbuf); - return NULL; - } -} - -/** - * soup_coding_apply: - * @coding: a #SoupCoding - * @input: input data - * @input_length: length of @input - * @done: %TRUE if this is the last piece of data to encode/decode - * @error: error pointer - * - * Applies @coding to @input_length bytes of data from @input, and - * returns a new #SoupBuffer containing the encoded/decoded data. If - * @done is %FALSE, the encoder may buffer some or all of the data in - * @input rather than outputting it right away. If @done is %TRUE, the - * encoder will flush any buffered data, and (if possible) verify that - * the input has reached the end of the stream. - * - * Return value: a #SoupBuffer containing the encoded/decoded data, or - * %NULL if no data can be returned at this point, or if an error - * occurred. (If you pass %NULL for @error, there is no way to - * distinguish the latter two cases). - **/ -SoupBuffer * -soup_coding_apply (SoupCoding *coding, - gconstpointer input, gsize input_length, - gboolean done, GError **error) -{ - g_return_val_if_fail (SOUP_IS_CODING (coding), NULL); - - return SOUP_CODING_GET_CLASS (coding)->apply ( - coding, input, input_length, done, error); -} - -/** - * SoupCodingStatus: - * @SOUP_CODING_STATUS_OK: Success - * @SOUP_CODING_STATUS_ERROR: An error occurred - * @SOUP_CODING_STATUS_NEED_SPACE: Output buffer was too small to - * output any data. - * @SOUP_CODING_STATUS_COMPLETE: The stream end has been reached and - * the output buffer contains the last bytes of encoded/decoded data. - * - * The result from a call to soup_coding_apply_into(). - **/ - -/** - * soup_coding_apply_into: - * @coding: a #SoupCoding - * @input: input data - * @input_length: length of @input - * @input_used: on return, contains the number of bytes of @input that - * were encoded/decoded. - * @output: output buffer - * @output_length: length of @output - * @output_used: on return, contains the number of bytes of @output that - * were filled with encoded/decoded data. - * @done: %TRUE if this is the last piece of data to encode/decode - * @error: error pointer - * - * Applies @coding to @input_length bytes of data from @input, and - * outputs between %0 and @output_length encoded/decoded bytes into - * @output. @input and @output may not overlap. - * - * Return value: the status; %SOUP_CODING_STATUS_OK on intermediate - * success, %SOUP_CODING_STATUS_COMPLETE if the stream has been fully - * encoded/decoded, %SOUP_CODING_STATUS_NEED_SPACE if a larger - * @output_length is required to make progress, or - * %SOUP_CODING_STATUS_ERROR on error (in which case @error will be - * set). - **/ -SoupCodingStatus -soup_coding_apply_into (SoupCoding *coding, - gconstpointer input, gsize input_length, gsize *input_used, - gpointer output, gsize output_length, gsize *output_used, - gboolean done, GError **error) -{ - g_return_val_if_fail (SOUP_IS_CODING (coding), 0); - - return SOUP_CODING_GET_CLASS (coding)->apply_into ( - coding, input, input_length, input_used, - output, output_length, output_used, - done, error); -} - -GQuark -soup_coding_error_quark (void) -{ - static GQuark error; - if (!error) - error = g_quark_from_static_string ("soup_coding_error_quark"); - return error; -} diff --git a/libsoup/soup-coding.h b/libsoup/soup-coding.h deleted file mode 100644 index a00d014..0000000 --- a/libsoup/soup-coding.h +++ /dev/null @@ -1,92 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2005, Novell, Inc. - * Copyright (C) 2008, Red Hat, Inc. - */ - -#ifndef SOUP_CODING_H -#define SOUP_CODING_H 1 - -#include -#include - -#define SOUP_TYPE_CODING (soup_coding_get_type ()) -#define SOUP_CODING(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SOUP_TYPE_CODING, SoupCoding)) -#define SOUP_CODING_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SOUP_TYPE_CODING, SoupCodingClass)) -#define SOUP_IS_CODING(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SOUP_TYPE_CODING)) -#define SOUP_IS_CODING_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), SOUP_TYPE_CODING)) -#define SOUP_CODING_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SOUP_TYPE_CODING, SoupCodingClass)) - -typedef enum { - SOUP_CODING_ENCODE, - SOUP_CODING_DECODE -} SoupCodingDirection; - -typedef enum { - SOUP_CODING_STATUS_OK, - SOUP_CODING_STATUS_ERROR, - SOUP_CODING_STATUS_NEED_SPACE, - SOUP_CODING_STATUS_COMPLETE, -} SoupCodingStatus; - -typedef struct { - GObject parent; - - SoupCodingDirection direction; -} SoupCoding; - -typedef struct { - GObjectClass parent_class; - - const char *name; - - SoupBuffer * (*apply) (SoupCoding *coding, - gconstpointer input, - gsize input_length, - gboolean done, - GError **error); - SoupCodingStatus (*apply_into) (SoupCoding *coding, - gconstpointer input, - gsize input_length, - gsize *input_used, - gpointer output, - gsize output_length, - gsize *output_used, - gboolean done, - GError **error); - - /* Padding for future expansion */ - void (*_libsoup_reserved1) (void); - void (*_libsoup_reserved2) (void); - void (*_libsoup_reserved3) (void); - void (*_libsoup_reserved4) (void); -} SoupCodingClass; - -#define SOUP_CODING_DIRECTION "direction" - -GType soup_coding_get_type (void); - -SoupBuffer *soup_coding_apply (SoupCoding *coding, - gconstpointer input, - gsize input_length, - gboolean done, - GError **error); -SoupCodingStatus soup_coding_apply_into (SoupCoding *coding, - gconstpointer input, - gsize input_length, - gsize *input_used, - gpointer output, - gsize output_length, - gsize *output_used, - gboolean done, - GError **error); - -#define SOUP_CODING_ERROR soup_coding_error_quark() -GQuark soup_coding_error_quark (void); - -typedef enum { - SOUP_CODING_ERROR_DATA_ERROR, - SOUP_CODING_ERROR_INTERNAL_ERROR -} SoupCodingError; - -#endif /* SOUP_CODING_H */ diff --git a/libsoup/soup-content-decoder.c b/libsoup/soup-content-decoder.c index 7bc6f42..d7ddd77 100644 --- a/libsoup/soup-content-decoder.c +++ b/libsoup/soup-content-decoder.c @@ -13,7 +13,6 @@ #include #include "soup-content-decoder.h" -#include "soup-coding-gzip.h" #include "soup-enum-types.h" #include "soup-message.h" #include "soup-message-private.h" @@ -50,9 +49,11 @@ **/ struct _SoupContentDecoderPrivate { - GHashTable *codings; + GHashTable *decoders; }; +typedef GConverter * (*SoupContentDecoderCreator) (void); + static void soup_content_decoder_session_feature_init (SoupSessionFeatureInterface *feature_interface, gpointer interface_data); static void request_queued (SoupSessionFeature *feature, SoupSession *session, SoupMessage *msg); @@ -67,6 +68,12 @@ G_DEFINE_TYPE_WITH_CODE (SoupContentDecoder, soup_content_decoder, G_TYPE_OBJECT /* This is constant for now */ #define ACCEPT_ENCODING_HEADER "gzip" +static GConverter * +gzip_decoder_creator (void) +{ + return (GConverter *)g_zlib_decompressor_new (G_ZLIB_COMPRESSOR_FORMAT_GZIP); +} + static void soup_content_decoder_init (SoupContentDecoder *decoder) { @@ -74,12 +81,12 @@ soup_content_decoder_init (SoupContentDecoder *decoder) SOUP_TYPE_CONTENT_DECODER, SoupContentDecoderPrivate); - decoder->priv->codings = g_hash_table_new (g_str_hash, g_str_equal); + decoder->priv->decoders = g_hash_table_new (g_str_hash, g_str_equal); /* Hardcoded for now */ - g_hash_table_insert (decoder->priv->codings, "gzip", - GSIZE_TO_POINTER (SOUP_TYPE_CODING_GZIP)); - g_hash_table_insert (decoder->priv->codings, "x-gzip", - GSIZE_TO_POINTER (SOUP_TYPE_CODING_GZIP)); + g_hash_table_insert (decoder->priv->decoders, "gzip", + gzip_decoder_creator); + g_hash_table_insert (decoder->priv->decoders, "x-gzip", + gzip_decoder_creator); } static void @@ -105,7 +112,7 @@ finalize (GObject *object) { SoupContentDecoder *decoder = SOUP_CONTENT_DECODER (object); - g_hash_table_destroy (decoder->priv->codings); + g_hash_table_destroy (decoder->priv->decoders); G_OBJECT_CLASS (soup_content_decoder_parent_class)->finalize (object); } @@ -116,8 +123,8 @@ soup_content_decoder_got_headers_cb (SoupMessage *msg, SoupContentDecoder *decod SoupMessagePrivate *msgpriv = SOUP_MESSAGE_GET_PRIVATE (msg); const char *header; GSList *encodings, *e; - GType coding_type; - SoupCoding *coding; + SoupContentDecoderCreator converter_creator; + GConverter *converter; header = soup_message_headers_get_list (msg->response_headers, "Content-Encoding"); @@ -132,7 +139,7 @@ soup_content_decoder_got_headers_cb (SoupMessage *msg, SoupContentDecoder *decod return; for (e = encodings; e; e = e->next) { - if (!g_hash_table_lookup (decoder->priv->codings, e->data)) { + if (!g_hash_table_lookup (decoder->priv->decoders, e->data)) { soup_header_free_list (encodings); return; } @@ -147,17 +154,15 @@ soup_content_decoder_got_headers_cb (SoupMessage *msg, SoupContentDecoder *decod } for (e = encodings; e; e = e->next) { - coding_type = (GType) GPOINTER_TO_SIZE (g_hash_table_lookup (decoder->priv->codings, e->data)); - coding = g_object_new (coding_type, - SOUP_CODING_DIRECTION, SOUP_CODING_DECODE, - NULL); + converter_creator = g_hash_table_lookup (decoder->priv->decoders, e->data); + converter = converter_creator (); /* Content-Encoding lists the codings in the order * they were applied in, so we put decoders in reverse * order so the last-applied will be the first * decoded. */ - msgpriv->decoders = g_slist_prepend (msgpriv->decoders, coding); + msgpriv->decoders = g_slist_prepend (msgpriv->decoders, converter); } soup_header_free_list (encodings); diff --git a/libsoup/soup-message-io.c b/libsoup/soup-message-io.c index 865f208..d78aa39 100644 --- a/libsoup/soup-message-io.c +++ b/libsoup/soup-message-io.c @@ -12,7 +12,6 @@ #include #include -#include "soup-coding.h" #include "soup-connection.h" #include "soup-message.h" #include "soup-message-private.h" @@ -358,10 +357,56 @@ read_metadata (SoupMessage *msg, gboolean to_blank) } static SoupBuffer * +content_decode_one (SoupBuffer *buf, GConverter *converter, GError **error) +{ + gsize outbuf_length, outbuf_used, outbuf_cur, input_used, input_cur; + char *outbuf; + GConverterResult result; + + outbuf_length = MAX (buf->length * 2, 1024); + outbuf = g_malloc (outbuf_length); + outbuf_cur = input_cur = 0; + + do { + result = g_converter_convert ( + converter, + buf->data + input_cur, buf->length - input_cur, + outbuf + outbuf_cur, outbuf_length - outbuf_cur, + 0, &input_used, &outbuf_used, error); + input_cur += input_used; + outbuf_cur += outbuf_used; + + if (g_error_matches (*error, G_IO_ERROR, G_IO_ERROR_NO_SPACE) || + (!*error && outbuf_cur == outbuf_length)) { + g_clear_error (error); + outbuf_length *= 2; + outbuf = g_realloc (outbuf, outbuf_length); + } else if (*error) { + /* GZlibDecompressor can't ever return + * G_IO_ERROR_PARTIAL_INPUT unless we pass it + * input_length = 0, which we don't. Other + * converters might of course, so eventually + * this code needs to be rewritten to deal + * with that. + */ + g_free (outbuf); + return NULL; + } + } while (input_cur < buf->length && result != G_CONVERTER_FINISHED); + + if (outbuf_cur) + return soup_buffer_new (SOUP_MEMORY_TAKE, outbuf, outbuf_cur); + else { + g_free (outbuf); + return NULL; + } +} + +static SoupBuffer * content_decode (SoupMessage *msg, SoupBuffer *buf) { SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg); - SoupCoding *decoder; + GConverter *decoder; SoupBuffer *decoded; GError *error = NULL; GSList *d; @@ -369,10 +414,9 @@ content_decode (SoupMessage *msg, SoupBuffer *buf) for (d = priv->decoders; d; d = d->next) { decoder = d->data; - decoded = soup_coding_apply (decoder, buf->data, buf->length, - FALSE, &error); + decoded = content_decode_one (buf, decoder, &error); if (error) { - if (g_error_matches (error, SOUP_CODING_ERROR, SOUP_CODING_ERROR_INTERNAL_ERROR)) + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_FAILED)) g_warning ("Content-Decoding error: %s\n", error->message); g_error_free (error); diff --git a/tests/coding-test.c b/tests/coding-test.c index b587a2c..f3bd852 100644 --- a/tests/coding-test.c +++ b/tests/coding-test.c @@ -26,7 +26,7 @@ server_callback (SoupServer *server, SoupMessage *msg, const char *path, GHashTable *query, SoupClientContext *context, gpointer data) { - const char *accept_encoding, *junk; + const char *accept_encoding, *junk, *noencode; GSList *codings; char *file = NULL, *contents; gsize length; @@ -51,6 +51,16 @@ server_callback (SoupServer *server, SoupMessage *msg, } soup_header_free_list (codings); + noencode = soup_message_headers_get_one (msg->request_headers, + "X-No-Encode"); + if (noencode) { + /* Force it to send the ungzipped version, even though + * we already added "Content-Encoding: gzip" + */ + g_free (file); + file = NULL; + } + if (!file) file = g_strdup_printf (SRCDIR "/resources%s", path); if (!g_file_get_contents (file, &contents, &length, NULL)) { @@ -80,13 +90,14 @@ static void do_coding_test (void) { SoupSession *session; - SoupMessage *msg, *msgz, *msgj; + SoupMessage *msg, *msgz, *msgj, *msgn; SoupURI *uri; const char *coding; session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC, NULL); uri = soup_uri_new_with_base (base_uri, "/mbox"); + debug_printf (1, "GET /mbox, plain\n"); msg = soup_message_new_from_uri ("GET", uri); soup_session_send_message (session, msg); @@ -106,6 +117,7 @@ do_coding_test (void) errors++; } + debug_printf (1, "GET /mbox, Accept-Encoding: gzip\n"); soup_session_add_feature_by_type (session, SOUP_TYPE_CONTENT_DECODER); msgz = soup_message_new_from_uri ("GET", uri); @@ -138,6 +150,7 @@ do_coding_test (void) errors++; } + debug_printf (1, "GET /mbox, Accept-Encoding: gzip, plus trailing junk\n"); msgj = soup_message_new_from_uri ("GET", uri); soup_message_headers_append (msgj->request_headers, @@ -171,9 +184,51 @@ do_coding_test (void) errors++; } + + debug_printf (1, "GET /mbox, Accept-Encoding: gzip, with server error\n"); + msgn = soup_message_new_from_uri ("GET", uri); + soup_message_headers_append (msgn->request_headers, + "X-No-Encode", "true"); + soup_session_send_message (session, msgn); + if (!SOUP_STATUS_IS_SUCCESSFUL (msgn->status_code)) { + debug_printf (1, " Unexpected status %d %s\n", + msgn->status_code, msgn->reason_phrase); + errors++; + } + coding = soup_message_headers_get_one (msgn->response_headers, "Content-Encoding"); + if (!coding || g_ascii_strcasecmp (coding, "gzip") != 0) { + debug_printf (1, " Unexpected Content-Encoding: %s\n", + coding ? coding : "(none)"); + errors++; + } + /* Since the content wasn't actually gzip-encoded, decoding it + * should have failed and so the flag won't be set. + */ + if (soup_message_get_flags (msgn) & SOUP_MESSAGE_CONTENT_DECODED) { + debug_printf (1, " SOUP_MESSAGE_CONTENT_DECODED set!\n"); + errors++; + } + /* Failed content-decoding should have left the body untouched + * from what the server sent... which happens to be the + * uncompressed data. + */ + if (msg->response_body->length != msgn->response_body->length) { + debug_printf (1, " Message length mismatch: %lu (plain) vs %lu (mis-encoded)\n", + (gulong)msg->response_body->length, + (gulong)msgn->response_body->length); + errors++; + } else if (memcmp (msg->response_body->data, + msgn->response_body->data, + msg->response_body->length) != 0) { + debug_printf (1, " Message data mismatch (plain/misencoded)\n"); + errors++; + } + + g_object_unref (msg); g_object_unref (msgz); g_object_unref (msgj); + g_object_unref (msgn); soup_uri_free (uri); soup_test_session_abort_unref (session);