Remove SoupCoding, SoupCodingGZip, use GZlibDecompressor
authorDan Winship <danw@gnome.org>
Fri, 10 Dec 2010 11:44:59 +0000 (12:44 +0100)
committerDan Winship <danw@gnome.org>
Fri, 10 Dec 2010 11:49:39 +0000 (12:49 +0100)
also add a new test to coding-test for handling content that
doesn't decode correctly

libsoup/Makefile.am
libsoup/soup-coding-gzip.c [deleted file]
libsoup/soup-coding-gzip.h [deleted file]
libsoup/soup-coding.c [deleted file]
libsoup/soup-coding.h [deleted file]
libsoup/soup-content-decoder.c
libsoup/soup-message-io.c
tests/coding-test.c

index 5ed63f1..a26d820 100644 (file)
@@ -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 (file)
index 60d57e2..0000000
+++ /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 <config.h>
-#endif
-
-#include "soup-coding-gzip.h"
-
-#include <zlib.h>
-
-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 (file)
index abdca37..0000000
+++ /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 (file)
index 74c4826..0000000
+++ /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 <config.h>
-#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 (file)
index a00d014..0000000
+++ /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 <libsoup/soup-types.h>
-#include <libsoup/soup-message-body.h>
-
-#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 */
index 7bc6f42..d7ddd77 100644 (file)
@@ -13,7 +13,6 @@
 #include <gio/gio.h>
 
 #include "soup-content-decoder.h"
-#include "soup-coding-gzip.h"
 #include "soup-enum-types.h"
 #include "soup-message.h"
 #include "soup-message-private.h"
  **/
 
 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);
 
index 865f208..d78aa39 100644 (file)
@@ -12,7 +12,6 @@
 #include <stdlib.h>
 #include <string.h>
 
-#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);
 
index b587a2c..f3bd852 100644 (file)
@@ -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);