diff options
author | Patrick Griffis <pgriffis@igalia.com> | 2020-11-09 15:49:31 -0600 |
---|---|---|
committer | Patrick Griffis <pgriffis@igalia.com> | 2020-11-09 15:49:31 -0600 |
commit | 9552697194fc21f4e37d92474cc84d9ee23dd5d0 (patch) | |
tree | d39849d34409f25b86953aad8ae795f38a79976d /libsoup/content-sniffer | |
parent | 4998ae35d06aa67b841eee0100d4869e001670b1 (diff) | |
download | libsoup-9552697194fc21f4e37d92474cc84d9ee23dd5d0.tar.gz |
Move content-decoder sources to its own directory
Diffstat (limited to 'libsoup/content-sniffer')
-rw-r--r-- | libsoup/content-sniffer/soup-brotli-decompressor.c | 194 | ||||
-rw-r--r-- | libsoup/content-sniffer/soup-brotli-decompressor.h | 34 | ||||
-rw-r--r-- | libsoup/content-sniffer/soup-content-decoder.c | 267 | ||||
-rw-r--r-- | libsoup/content-sniffer/soup-content-decoder.h | 17 | ||||
-rw-r--r-- | libsoup/content-sniffer/soup-content-processor.c | 49 | ||||
-rw-r--r-- | libsoup/content-sniffer/soup-content-processor.h | 44 | ||||
-rw-r--r-- | libsoup/content-sniffer/soup-converter-wrapper.c | 346 | ||||
-rw-r--r-- | libsoup/content-sniffer/soup-converter-wrapper.h | 18 |
8 files changed, 0 insertions, 969 deletions
diff --git a/libsoup/content-sniffer/soup-brotli-decompressor.c b/libsoup/content-sniffer/soup-brotli-decompressor.c deleted file mode 100644 index 4c089477..00000000 --- a/libsoup/content-sniffer/soup-brotli-decompressor.c +++ /dev/null @@ -1,194 +0,0 @@ -/* 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/codes must match GZlibDecompressor */ - - 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) { - switch (result) { - case BROTLI_DECODER_RESULT_ERROR: - self->last_error = soup_brotli_decompressor_create_error (self); - break; - case 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)"); - break; - case BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT: - /* Just continue with more output then */ - break; - case BROTLI_DECODER_RESULT_SUCCESS: - /* Just continue returning finished next time */ - break; - } - - return G_CONVERTER_CONVERTED; - } - - switch (result) { - case BROTLI_DECODER_RESULT_SUCCESS: - return G_CONVERTER_FINISHED; - case BROTLI_DECODER_RESULT_ERROR: - soup_brotli_decompressor_set_error (self, error); - return G_CONVERTER_ERROR; - case BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT: - g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_PARTIAL_INPUT, "SoupBrotliDecompressorError: More input required (corrupt input)"); - return G_CONVERTER_ERROR; - case BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT: - g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NO_SPACE, "SoupBrotliDecompressorError: Larger output buffer required"); - return G_CONVERTER_ERROR; - } - - g_assert_not_reached (); - return G_CONVERTER_ERROR; -} - -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/content-sniffer/soup-brotli-decompressor.h b/libsoup/content-sniffer/soup-brotli-decompressor.h deleted file mode 100644 index 5c99155f..00000000 --- a/libsoup/content-sniffer/soup-brotli-decompressor.h +++ /dev/null @@ -1,34 +0,0 @@ -/* 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()) -SOUP_AVAILABLE_IN_2_68 -G_DECLARE_FINAL_TYPE (SoupBrotliDecompressor, soup_brotli_decompressor, SOUP, BROTLI_DECOMPRESSOR, GObject) - -SoupBrotliDecompressor *soup_brotli_decompressor_new (void); - -G_END_DECLS diff --git a/libsoup/content-sniffer/soup-content-decoder.c b/libsoup/content-sniffer/soup-content-decoder.c deleted file mode 100644 index 5be8cc38..00000000 --- a/libsoup/content-sniffer/soup-content-decoder.c +++ /dev/null @@ -1,267 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * soup-content-decoder.c - * - * Copyright (C) 2009 Red Hat, Inc. - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include "soup-content-decoder.h" -#include "soup-converter-wrapper.h" -#include "soup-session-feature.h" -#include "soup-message-private.h" -#include "soup-headers.h" -#ifdef WITH_BROTLI -#include "soup-brotli-decompressor.h" -#endif - -/** - * SECTION:soup-content-decoder - * @short_description: Content-Encoding handler - * - * #SoupContentDecoder handles adding the "Accept-Encoding" header on - * outgoing messages, and processing the "Content-Encoding" header on - * incoming ones. Currently it supports the "gzip", "deflate", and "br" - * content codings. - * - * A #SoupContentDecoder will automatically be - * added to the session by default. (You can use - * %SOUP_SESSION_REMOVE_FEATURE_BY_TYPE at construct time if you don't - * want this.) If you are using one of the deprecated #SoupSession - * subclasses, you can add a #SoupContentDecoder to your session with - * soup_session_add_feature() or soup_session_add_feature_by_type(). - * - * If #SoupContentDecoder successfully decodes the Content-Encoding, - * the message body will contain the decoded data; however, the message headers - * will be unchanged (and so "Content-Encoding" will still be present, - * "Content-Length" will describe the original encoded length, etc). - * - * If "Content-Encoding" contains any encoding types that - * #SoupContentDecoder doesn't recognize, then none of the encodings - * will be decoded. - * - * (Note that currently there is no way to (automatically) use - * Content-Encoding when sending a request body, or to pick specific - * encoding types to support.) - * - * Since: 2.30 - **/ - -/** - * SoupContentDecoder: - * - * Class handling decoding of HTTP messages. - */ - -struct _SoupContentDecoder { - GObject parent; -}; - -typedef struct { - GHashTable *decoders; -} SoupContentDecoderPrivate; - -typedef GConverter * (*SoupContentDecoderCreator) (void); - -static void soup_content_decoder_session_feature_init (SoupSessionFeatureInterface *feature_interface, gpointer interface_data); - -static SoupContentProcessorInterface *soup_content_decoder_default_content_processor_interface; -static void soup_content_decoder_content_processor_init (SoupContentProcessorInterface *interface, gpointer interface_data); - - -G_DEFINE_TYPE_WITH_CODE (SoupContentDecoder, soup_content_decoder, G_TYPE_OBJECT, - G_ADD_PRIVATE (SoupContentDecoder) - G_IMPLEMENT_INTERFACE (SOUP_TYPE_SESSION_FEATURE, - soup_content_decoder_session_feature_init) - G_IMPLEMENT_INTERFACE (SOUP_TYPE_CONTENT_PROCESSOR, - soup_content_decoder_content_processor_init)) - -static GSList * -soup_content_decoder_get_decoders_for_msg (SoupContentDecoder *decoder, SoupMessage *msg) -{ - SoupContentDecoderPrivate *priv = soup_content_decoder_get_instance_private (decoder); - const char *header; - GSList *encodings, *e, *decoders = NULL; - SoupContentDecoderCreator converter_creator; - GConverter *converter; - - header = soup_message_headers_get_list (soup_message_get_response_headers (msg), - "Content-Encoding"); - if (!header) - return NULL; - - /* Workaround for an apache bug (bgo 613361) */ - if (!g_ascii_strcasecmp (header, "gzip") || - !g_ascii_strcasecmp (header, "x-gzip")) { - const char *content_type = soup_message_headers_get_content_type (soup_message_get_response_headers (msg), NULL); - - if (content_type && - (!g_ascii_strcasecmp (content_type, "application/gzip") || - !g_ascii_strcasecmp (content_type, "application/x-gzip"))) - return NULL; - } - - /* OK, really, no one is ever going to use more than one - * encoding, but we'll be robust. - */ - encodings = soup_header_parse_list (header); - if (!encodings) - return NULL; - - for (e = encodings; e; e = e->next) { - if (!g_hash_table_lookup (priv->decoders, e->data)) { - soup_header_free_list (encodings); - return NULL; - } - } - - for (e = encodings; e; e = e->next) { - converter_creator = g_hash_table_lookup (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. - */ - decoders = g_slist_prepend (decoders, converter); - } - soup_header_free_list (encodings); - - return decoders; -} - -static GInputStream* -soup_content_decoder_content_processor_wrap_input (SoupContentProcessor *processor, - GInputStream *base_stream, - SoupMessage *msg, - GError **error) -{ - GSList *decoders, *d; - GInputStream *istream; - - decoders = soup_content_decoder_get_decoders_for_msg (SOUP_CONTENT_DECODER (processor), msg); - if (!decoders) - return NULL; - - istream = g_object_ref (base_stream); - for (d = decoders; d; d = d->next) { - GConverter *decoder, *wrapper; - GInputStream *filter; - - decoder = d->data; - wrapper = soup_converter_wrapper_new (decoder, msg); - filter = g_object_new (G_TYPE_CONVERTER_INPUT_STREAM, - "base-stream", istream, - "converter", wrapper, - NULL); - g_object_unref (istream); - g_object_unref (wrapper); - istream = filter; - } - - g_slist_free_full (decoders, g_object_unref); - - return istream; -} - -static void -soup_content_decoder_content_processor_init (SoupContentProcessorInterface *processor_interface, - gpointer interface_data) -{ - soup_content_decoder_default_content_processor_interface = - g_type_default_interface_peek (SOUP_TYPE_CONTENT_PROCESSOR); - - processor_interface->processing_stage = SOUP_STAGE_CONTENT_ENCODING; - processor_interface->wrap_input = soup_content_decoder_content_processor_wrap_input; -} - -/* This is constant for now */ -#ifdef WITH_BROTLI -/* Don't advertise br support atm until some edge cases are resolved: - https://gitlab.gnome.org/GNOME/libsoup/issues/146 */ -/* #define ACCEPT_ENCODING_HEADER "gzip, deflate, br" */ -#define ACCEPT_ENCODING_HEADER "gzip, deflate" -#else -#define ACCEPT_ENCODING_HEADER "gzip, deflate" -#endif - -static GConverter * -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); -} - -#ifdef WITH_BROTLI -static GConverter * -brotli_decoder_creator (void) -{ - return (GConverter *)soup_brotli_decompressor_new (); -} -#endif - -static void -soup_content_decoder_init (SoupContentDecoder *decoder) -{ - SoupContentDecoderPrivate *priv = soup_content_decoder_get_instance_private (decoder); - - priv->decoders = g_hash_table_new (g_str_hash, g_str_equal); - /* Hardcoded for now */ - g_hash_table_insert (priv->decoders, "gzip", - gzip_decoder_creator); - g_hash_table_insert (priv->decoders, "x-gzip", - gzip_decoder_creator); - g_hash_table_insert (priv->decoders, "deflate", - zlib_decoder_creator); -#ifdef WITH_BROTLI - g_hash_table_insert (priv->decoders, "br", - brotli_decoder_creator); -#endif -} - -static void -soup_content_decoder_finalize (GObject *object) -{ - SoupContentDecoder *decoder = SOUP_CONTENT_DECODER (object); - SoupContentDecoderPrivate *priv = soup_content_decoder_get_instance_private (decoder); - - g_hash_table_destroy (priv->decoders); - - G_OBJECT_CLASS (soup_content_decoder_parent_class)->finalize (object); -} - -static void -soup_content_decoder_class_init (SoupContentDecoderClass *decoder_class) -{ - GObjectClass *object_class = G_OBJECT_CLASS (decoder_class); - - object_class->finalize = soup_content_decoder_finalize; -} - -static void -soup_content_decoder_request_queued (SoupSessionFeature *feature, - SoupMessage *msg) -{ - if (!soup_message_headers_get_one (soup_message_get_request_headers (msg), - "Accept-Encoding")) { - soup_message_headers_append (soup_message_get_request_headers (msg), - "Accept-Encoding", - ACCEPT_ENCODING_HEADER); - } -} - -static void -soup_content_decoder_session_feature_init (SoupSessionFeatureInterface *feature_interface, - gpointer interface_data) -{ - feature_interface->request_queued = soup_content_decoder_request_queued; -} diff --git a/libsoup/content-sniffer/soup-content-decoder.h b/libsoup/content-sniffer/soup-content-decoder.h deleted file mode 100644 index f31c4055..00000000 --- a/libsoup/content-sniffer/soup-content-decoder.h +++ /dev/null @@ -1,17 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2009 Red Hat, Inc. - */ - -#pragma once - -#include "soup-types.h" -#include "soup-message-body.h" - -G_BEGIN_DECLS - -#define SOUP_TYPE_CONTENT_DECODER (soup_content_decoder_get_type ()) -SOUP_AVAILABLE_IN_2_30 -G_DECLARE_FINAL_TYPE (SoupContentDecoder, soup_content_decoder, SOUP, CONTENT_DECODER, GObject) - -G_END_DECLS diff --git a/libsoup/content-sniffer/soup-content-processor.c b/libsoup/content-sniffer/soup-content-processor.c deleted file mode 100644 index da9ad89e..00000000 --- a/libsoup/content-sniffer/soup-content-processor.c +++ /dev/null @@ -1,49 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2012 Igalia, S.L. - */ - - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include "soup-content-processor.h" -#include "soup.h" - -G_DEFINE_INTERFACE (SoupContentProcessor, soup_content_processor, G_TYPE_OBJECT) - -static GInputStream * -soup_content_processor_real_wrap_input (SoupContentProcessor *processor, - GInputStream *base_stream, - SoupMessage *msg, - GError **error) -{ - g_return_val_if_reached (NULL); -} - -static void -soup_content_processor_default_init (SoupContentProcessorInterface *interface) -{ - interface->processing_stage = SOUP_STAGE_INVALID; - interface->wrap_input = soup_content_processor_real_wrap_input; -} - -GInputStream * -soup_content_processor_wrap_input (SoupContentProcessor *processor, - GInputStream *base_stream, - SoupMessage *msg, - GError **error) -{ - g_return_val_if_fail (SOUP_IS_CONTENT_PROCESSOR (processor), NULL); - - return SOUP_CONTENT_PROCESSOR_GET_IFACE (processor)->wrap_input (processor, base_stream, msg, error); -} - -SoupProcessingStage -soup_content_processor_get_processing_stage (SoupContentProcessor *processor) -{ - g_return_val_if_fail (SOUP_IS_CONTENT_PROCESSOR (processor), SOUP_STAGE_INVALID); - - return SOUP_CONTENT_PROCESSOR_GET_IFACE (processor)->processing_stage; -} diff --git a/libsoup/content-sniffer/soup-content-processor.h b/libsoup/content-sniffer/soup-content-processor.h deleted file mode 100644 index 39075412..00000000 --- a/libsoup/content-sniffer/soup-content-processor.h +++ /dev/null @@ -1,44 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2012 Igalia, S.L. - */ - -#pragma once - -#include "soup-types.h" - -G_BEGIN_DECLS - -#define SOUP_TYPE_CONTENT_PROCESSOR (soup_content_processor_get_type ()) -G_DECLARE_INTERFACE (SoupContentProcessor, soup_content_processor, SOUP, CONTENT_PROCESSOR, GObject) - -typedef enum { - SOUP_STAGE_INVALID, - - SOUP_STAGE_MESSAGE_BODY, /* Raw network data */ - SOUP_STAGE_TRANSFER_ENCODING, /* SoupBodyInputStream is here */ - SOUP_STAGE_ENTITY_BODY, /* Has Transfer-Encoding removed */ - SOUP_STAGE_CONTENT_ENCODING, /* SoupContentDecoder works here */ - SOUP_STAGE_BODY_DATA /* Actual body data */ -} SoupProcessingStage; - -struct _SoupContentProcessorInterface { - GTypeInterface parent; - - SoupProcessingStage processing_stage; - - /* methods */ - GInputStream* (*wrap_input) (SoupContentProcessor *processor, - GInputStream *base_stream, - SoupMessage *msg, - GError **error); -}; - -GInputStream *soup_content_processor_wrap_input (SoupContentProcessor *processor, - GInputStream *base_stream, - SoupMessage *msg, - GError **error); - -SoupProcessingStage soup_content_processor_get_processing_stage (SoupContentProcessor *processor); - -G_END_DECLS diff --git a/libsoup/content-sniffer/soup-converter-wrapper.c b/libsoup/content-sniffer/soup-converter-wrapper.c deleted file mode 100644 index f669ee55..00000000 --- a/libsoup/content-sniffer/soup-converter-wrapper.c +++ /dev/null @@ -1,346 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * soup-converter-wrapper.c - * - * Copyright 2011 Red Hat, Inc. - */ - -#include "config.h" - -#include <string.h> - -#include <glib/gi18n-lib.h> - -#include "soup-converter-wrapper.h" -#include "soup.h" - -/* SoupConverterWrapper is a GConverter that wraps another GConverter. - * Mostly it is transparent, but it implements four special fallbacks - * for Content-Encoding handling: (1) "deflate" can mean either raw - * deflate or zlib-encoded deflate, (2) the server may mistakenly - * claim that a response is encoded when actually it isn't, (3) the - * response may contain trailing junk after the end of the encoded - * portion that we want to ignore, (4) the response may be truncated - * at an arbitrary point rather than containing a complete compressed - * representation. - * - */ - -enum { - PROP_0, - PROP_BASE_CONVERTER, - PROP_MESSAGE -}; - -struct _SoupConverterWrapper { - GObject parent; -}; - - -typedef struct { - GConverter *base_converter; - SoupMessage *msg; - gboolean try_deflate_fallback; - gboolean started; - gboolean discarding; -} SoupConverterWrapperPrivate; - -static void soup_converter_wrapper_iface_init (GConverterIface *iface); - -G_DEFINE_TYPE_WITH_CODE (SoupConverterWrapper, soup_converter_wrapper, G_TYPE_OBJECT, - G_ADD_PRIVATE (SoupConverterWrapper) - G_IMPLEMENT_INTERFACE (G_TYPE_CONVERTER, - soup_converter_wrapper_iface_init)) - -static void -soup_converter_wrapper_init (SoupConverterWrapper *converter) -{ -} - -static void -soup_converter_wrapper_finalize (GObject *object) -{ - SoupConverterWrapper *converter = (SoupConverterWrapper*)object; - SoupConverterWrapperPrivate *priv = soup_converter_wrapper_get_instance_private (converter); - - g_clear_object (&priv->base_converter); - g_clear_object (&priv->msg); - - G_OBJECT_CLASS (soup_converter_wrapper_parent_class)->finalize (object); -} - - -static void -soup_converter_wrapper_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - SoupConverterWrapper *converter = (SoupConverterWrapper*)object; - SoupConverterWrapperPrivate *priv = soup_converter_wrapper_get_instance_private (converter); - - switch (prop_id) { - case PROP_BASE_CONVERTER: - priv->base_converter = g_value_dup_object (value); - if (G_IS_ZLIB_DECOMPRESSOR (priv->base_converter)) { - GZlibCompressorFormat format; - - g_object_get (G_OBJECT (priv->base_converter), - "format", &format, - NULL); - if (format == G_ZLIB_COMPRESSOR_FORMAT_ZLIB) - priv->try_deflate_fallback = TRUE; - } - break; - - case PROP_MESSAGE: - priv->msg = g_value_dup_object (value); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -soup_converter_wrapper_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - SoupConverterWrapper *converter = (SoupConverterWrapper*)object; - SoupConverterWrapperPrivate *priv = soup_converter_wrapper_get_instance_private (converter); - - switch (prop_id) { - case PROP_BASE_CONVERTER: - g_value_set_object (value, priv->base_converter); - break; - - case PROP_MESSAGE: - g_value_set_object (value, priv->msg); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -soup_converter_wrapper_class_init (SoupConverterWrapperClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - - gobject_class->finalize = soup_converter_wrapper_finalize; - gobject_class->get_property = soup_converter_wrapper_get_property; - gobject_class->set_property = soup_converter_wrapper_set_property; - - g_object_class_install_property (gobject_class, - PROP_BASE_CONVERTER, - g_param_spec_object ("base-converter", - "Base GConverter", - "GConverter to wrap", - G_TYPE_CONVERTER, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, - PROP_MESSAGE, - g_param_spec_object ("message", - "Message", - "Associated SoupMessage", - SOUP_TYPE_MESSAGE, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS)); -} - -GConverter * -soup_converter_wrapper_new (GConverter *base_converter, - SoupMessage *msg) -{ - return g_object_new (SOUP_TYPE_CONVERTER_WRAPPER, - "base-converter", base_converter, - "message", msg, - NULL); -} - -static void -soup_converter_wrapper_reset (GConverter *converter) -{ - SoupConverterWrapperPrivate *priv = soup_converter_wrapper_get_instance_private (SOUP_CONVERTER_WRAPPER (converter)); - - if (priv->base_converter) - g_converter_reset (priv->base_converter); -} - -static GConverterResult -soup_converter_wrapper_fallback_convert (GConverter *converter, - const void *inbuf, - gsize inbuf_size, - void *outbuf, - gsize outbuf_size, - GConverterFlags flags, - gsize *bytes_read, - gsize *bytes_written, - GError **error) -{ - SoupConverterWrapperPrivate *priv = soup_converter_wrapper_get_instance_private (SOUP_CONVERTER_WRAPPER (converter)); - - if (outbuf_size == 0) { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_NO_SPACE, - _("Output buffer is too small")); - return G_CONVERTER_ERROR; - } - - if (priv->discarding) { - *bytes_read = inbuf_size; - *bytes_written = 0; - } else if (outbuf_size >= inbuf_size) { - memcpy (outbuf, inbuf, inbuf_size); - *bytes_read = *bytes_written = inbuf_size; - } else { - memcpy (outbuf, inbuf, outbuf_size); - *bytes_read = *bytes_written = outbuf_size; - } - - if (*bytes_read < inbuf_size) - return G_CONVERTER_CONVERTED; - - if (flags & G_CONVERTER_INPUT_AT_END) - return G_CONVERTER_FINISHED; - else if (flags & G_CONVERTER_FLUSH) - return G_CONVERTER_FLUSHED; - else if (inbuf_size) - return G_CONVERTER_CONVERTED; - else { - /* Force it to either read more input or - * try again with G_CONVERTER_INPUT_AT_END. - */ - g_set_error_literal (error, G_IO_ERROR, - G_IO_ERROR_PARTIAL_INPUT, - ""); - return G_CONVERTER_ERROR; - } -} - -static GConverterResult -soup_converter_wrapper_real_convert (GConverter *converter, - const void *inbuf, - gsize inbuf_size, - void *outbuf, - gsize outbuf_size, - GConverterFlags flags, - gsize *bytes_read, - gsize *bytes_written, - GError **error) -{ - SoupConverterWrapperPrivate *priv = soup_converter_wrapper_get_instance_private (SOUP_CONVERTER_WRAPPER (converter)); - GConverterResult result; - GError *my_error = NULL; - - try_again: - result = g_converter_convert (priv->base_converter, - inbuf, inbuf_size, - outbuf, outbuf_size, - flags, bytes_read, bytes_written, - &my_error); - if (result != G_CONVERTER_ERROR) { - if (!priv->started) - priv->started = TRUE; - - if (result == G_CONVERTER_FINISHED && - !(flags & G_CONVERTER_INPUT_AT_END)) { - /* We need to keep reading (and discarding) - * input to the end of the message body. - */ - g_clear_object (&priv->base_converter); - priv->discarding = TRUE; - - if (*bytes_written) - return G_CONVERTER_CONVERTED; - else { - g_set_error_literal (error, G_IO_ERROR, - G_IO_ERROR_PARTIAL_INPUT, - ""); - return G_CONVERTER_ERROR; - } - } - - return result; - } - - if (g_error_matches (my_error, G_IO_ERROR, G_IO_ERROR_PARTIAL_INPUT) && - inbuf_size == 0 && (flags & G_CONVERTER_INPUT_AT_END)) { - /* Server claimed compression but there was no message body. */ - g_error_free (my_error); - *bytes_written = 0; - return G_CONVERTER_FINISHED; - } - - if (!g_error_matches (my_error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA) || - priv->started) { - g_propagate_error (error, my_error); - return result; - } - g_clear_error (&my_error); - - /* Deflate hack: some servers (especially Apache with - * mod_deflate) return raw compressed data without the zlib - * headers when the client claims to support deflate. - */ - if (priv->try_deflate_fallback) { - priv->try_deflate_fallback = FALSE; - g_object_unref (priv->base_converter); - priv->base_converter = (GConverter *) - g_zlib_decompressor_new (G_ZLIB_COMPRESSOR_FORMAT_RAW); - goto try_again; - } - - /* Passthrough hack: some servers mistakenly claim to be - * sending encoded data when in fact they aren't, so fall - * back to just not decoding. - */ - g_clear_object (&priv->base_converter); - return soup_converter_wrapper_fallback_convert (converter, - inbuf, inbuf_size, - outbuf, outbuf_size, - flags, bytes_read, - bytes_written, error); -} - -static GConverterResult -soup_converter_wrapper_convert (GConverter *converter, - const void *inbuf, - gsize inbuf_size, - void *outbuf, - gsize outbuf_size, - GConverterFlags flags, - gsize *bytes_read, - gsize *bytes_written, - GError **error) -{ - SoupConverterWrapperPrivate *priv = soup_converter_wrapper_get_instance_private (SOUP_CONVERTER_WRAPPER (converter)); - - if (priv->base_converter) { - return soup_converter_wrapper_real_convert (converter, - inbuf, inbuf_size, - outbuf, outbuf_size, - flags, bytes_read, - bytes_written, error); - } else { - return soup_converter_wrapper_fallback_convert (converter, - inbuf, inbuf_size, - outbuf, outbuf_size, - flags, bytes_read, - bytes_written, error); - } -} - -static void -soup_converter_wrapper_iface_init (GConverterIface *iface) -{ - iface->convert = soup_converter_wrapper_convert; - iface->reset = soup_converter_wrapper_reset; -} diff --git a/libsoup/content-sniffer/soup-converter-wrapper.h b/libsoup/content-sniffer/soup-converter-wrapper.h deleted file mode 100644 index c1b6f627..00000000 --- a/libsoup/content-sniffer/soup-converter-wrapper.h +++ /dev/null @@ -1,18 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright 2011 Red Hat, Inc. - */ - -#pragma once - -#include "soup-types.h" - -G_BEGIN_DECLS - -#define SOUP_TYPE_CONVERTER_WRAPPER (soup_converter_wrapper_get_type ()) -G_DECLARE_FINAL_TYPE (SoupConverterWrapper, soup_converter_wrapper, SOUP, CONVERTER_WRAPPER, GObject) - -GConverter *soup_converter_wrapper_new (GConverter *base_converter, - SoupMessage *msg); - -G_END_DECLS |