SoupContentDecoder: add support for deflate Content-Encoding
authorSergio Villar Senin <svillar@igalia.com>
Thu, 13 Oct 2011 16:37:24 +0000 (18:37 +0200)
committerSergio Villar Senin <svillar@igalia.com>
Mon, 14 Nov 2011 15:19:57 +0000 (16:19 +0100)
Claim that we support both gzip and deflate content encodings. Added support
to handle data compressed with deflate with and without zlib headers.

https://bugzilla.gnome.org/show_bug.cgi?id=661682

libsoup/soup-content-decoder.c
libsoup/soup-message-io.c

index 3ab240c..2146612 100644 (file)
@@ -66,7 +66,7 @@ G_DEFINE_TYPE_WITH_CODE (SoupContentDecoder, soup_content_decoder, G_TYPE_OBJECT
                                                soup_content_decoder_session_feature_init))
 
 /* This is constant for now */
-#define ACCEPT_ENCODING_HEADER "gzip"
+#define ACCEPT_ENCODING_HEADER "gzip, deflate"
 
 static GConverter *
 gzip_decoder_creator (void)
@@ -74,6 +74,12 @@ gzip_decoder_creator (void)
        return (GConverter *)g_zlib_decompressor_new (G_ZLIB_COMPRESSOR_FORMAT_GZIP);
 }
 
+static GConverter *
+zlib_decoder_creator (void)
+{
+       return (GConverter *)g_zlib_decompressor_new (G_ZLIB_COMPRESSOR_FORMAT_ZLIB);
+}
+
 static void
 soup_content_decoder_init (SoupContentDecoder *decoder)
 {
@@ -87,6 +93,8 @@ soup_content_decoder_init (SoupContentDecoder *decoder)
                             gzip_decoder_creator);
        g_hash_table_insert (decoder->priv->decoders, "x-gzip",
                             gzip_decoder_creator);
+       g_hash_table_insert (decoder->priv->decoders, "deflate",
+                            zlib_decoder_creator);
 }
 
 static void
index 4f2e839..b589ef2 100644 (file)
@@ -338,6 +338,7 @@ content_decode_one (SoupBuffer *buf, GConverter *converter, GError **error)
        gsize outbuf_length, outbuf_used, outbuf_cur, input_used, input_cur;
        char *outbuf;
        GConverterResult result;
+       gboolean dummy_zlib_header_used = FALSE;
 
        outbuf_length = MAX (buf->length * 2, 1024);
        outbuf = g_malloc (outbuf_length);
@@ -357,6 +358,39 @@ content_decode_one (SoupBuffer *buf, GConverter *converter, GError **error)
                        g_clear_error (error);
                        outbuf_length *= 2;
                        outbuf = g_realloc (outbuf, outbuf_length);
+               } else if (input_cur == 0 &&
+                          !dummy_zlib_header_used &&
+                          G_IS_ZLIB_DECOMPRESSOR (converter) &&
+                          g_error_matches (*error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA)) {
+
+                       GZlibCompressorFormat format;
+                       g_object_get (G_OBJECT (converter), "format", &format, NULL);
+
+                       if (format == G_ZLIB_COMPRESSOR_FORMAT_ZLIB) {
+                               /* Some servers (especially Apache with mod_deflate)
+                                * return RAW compressed data without the zlib headers
+                                * when the client claims to support deflate. For
+                                * those cases use a dummy header (stolen from
+                                * Mozilla's nsHTTPCompressConv.cpp) and try to
+                                * continue uncompressing data.
+                                */
+                               static char dummy_zlib_header[2] = { 0x78, 0x9C };
+
+                               g_converter_reset (converter);
+                               result = g_converter_convert (converter,
+                                                             dummy_zlib_header, sizeof(dummy_zlib_header),
+                                                             outbuf + outbuf_cur, outbuf_length - outbuf_cur,
+                                                             0, &input_used, &outbuf_used, NULL);
+                               dummy_zlib_header_used = TRUE;
+                               if (result == G_CONVERTER_CONVERTED) {
+                                       g_clear_error (error);
+                                       continue;
+                               }
+                       }
+
+                       g_free (outbuf);
+                       return NULL;
+
                } else if (*error) {
                        /* GZlibDecompressor can't ever return
                         * G_IO_ERROR_PARTIAL_INPUT unless we pass it