[libsoup/giobased: 10/11] Add a content-sniffing stream



commit b4a39abbbdfdf726cdcaf544e62cb82377740e8f
Author: Dan Winship <danw gnome org>
Date:   Mon Dec 27 11:42:00 2010 -0500

    Add a content-sniffing stream
    
    Unfortunately this doesn't clean up the inside of soup-message-io that
    much because the signal emissions keep things complicated.

 libsoup/Makefile.am                   |    2 +
 libsoup/soup-content-sniffer-stream.c |  324 +++++++++++++++++++++++++++++++++
 libsoup/soup-content-sniffer-stream.h |   47 +++++
 libsoup/soup-content-sniffer.c        |   11 +-
 libsoup/soup-content-sniffer.h        |   13 +-
 libsoup/soup-message-io.c             |   89 ++++------
 6 files changed, 422 insertions(+), 64 deletions(-)
---
diff --git a/libsoup/Makefile.am b/libsoup/Makefile.am
index 951a6b9..25e4dcb 100644
--- a/libsoup/Makefile.am
+++ b/libsoup/Makefile.am
@@ -129,6 +129,8 @@ libsoup_2_4_la_SOURCES =		\
 	soup-connection.c		\
 	soup-content-decoder.c		\
 	soup-content-sniffer.c		\
+	soup-content-sniffer-stream.h	\
+	soup-content-sniffer-stream.c	\
 	soup-cookie.c			\
 	soup-cookie-jar.c		\
 	soup-cookie-jar-text.c		\
diff --git a/libsoup/soup-content-sniffer-stream.c b/libsoup/soup-content-sniffer-stream.c
new file mode 100644
index 0000000..ab348fb
--- /dev/null
+++ b/libsoup/soup-content-sniffer-stream.c
@@ -0,0 +1,324 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * soup-content-sniffer-stream.c
+ *
+ * Copyright (C) 2010 Red Hat, Inc.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <gio/gio.h>
+
+#include "soup-content-sniffer-stream.h"
+#include "soup-content-sniffer.h"
+#include "soup-message.h"
+
+G_DEFINE_TYPE (SoupContentSnifferStream, soup_content_sniffer_stream, G_TYPE_FILTER_INPUT_STREAM)
+
+enum {
+	PROP_0,
+
+	PROP_SNIFFER,
+	PROP_MESSAGE,
+};
+
+struct _SoupContentSnifferStreamPrivate {
+	SoupContentSniffer *sniffer;
+	SoupMessage *msg;
+
+	gsize buffer_size;
+	gboolean sniffing;
+	GByteArray *buf;
+	GError *error;
+
+	char *content_type;
+	GHashTable *content_params;
+};
+
+static void
+soup_content_sniffer_stream_finalize (GObject *object)
+{
+	SoupContentSnifferStream *sniffer = SOUP_CONTENT_SNIFFER_STREAM (object);
+
+	if (sniffer->priv->sniffer)
+		g_object_unref (sniffer->priv->sniffer);
+	if (sniffer->priv->msg)
+		g_object_unref (sniffer->priv->msg);
+	if (sniffer->priv->buf)
+		g_byte_array_free (sniffer->priv->buf, TRUE);
+	if (sniffer->priv->error)
+		g_error_free (sniffer->priv->error);
+
+	if (sniffer->priv->content_type)
+		g_free (sniffer->priv->content_type);
+	if (sniffer->priv->content_params)
+		g_hash_table_destroy (sniffer->priv->content_params);
+
+	G_OBJECT_CLASS (soup_content_sniffer_stream_parent_class)->finalize (object);
+}
+
+static void
+soup_content_sniffer_stream_set_property (GObject *object, guint prop_id,
+					  const GValue *value, GParamSpec *pspec)
+{
+	SoupContentSnifferStream *sniffer = SOUP_CONTENT_SNIFFER_STREAM (object);
+
+	switch (prop_id) {
+	case PROP_SNIFFER:
+		sniffer->priv->sniffer = g_value_dup_object (value);
+		/* FIXME: supposed to wait until after got-headers for this */
+		sniffer->priv->buffer_size = soup_content_sniffer_get_buffer_size (sniffer->priv->sniffer);
+		break;
+	case PROP_MESSAGE:
+		sniffer->priv->msg = g_value_dup_object (value);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+soup_content_sniffer_stream_get_property (GObject *object, guint prop_id,
+					  GValue *value, GParamSpec *pspec)
+{
+	SoupContentSnifferStream *sniffer = SOUP_CONTENT_SNIFFER_STREAM (object);
+
+	switch (prop_id) {
+	case PROP_SNIFFER:
+		g_value_set_object (value, sniffer->priv->sniffer);
+		break;
+	case PROP_MESSAGE:
+		g_value_set_object (value, sniffer->priv->msg);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+/* Tries to read at least @sniffer->priv->buffer_size bytes into
+ * @buffer (which has a total size of @count bytes and already has
+ * * so_far bytes in it).
+ *
+ * read_and_sniff() only returns an error in two cases; if it gets an
+ * error while * so_far is still 0, or if it gets a
+ * %G_IO_ERROR_WOULD_BLOCK. In either case, it will return -1 and set
+ * * error (having updated * so_far to reflect any data that was
+ * successfully read in the second case). Likewise, 0 indicating EOF
+ * will only be returned if it occurs while * so_far is 0.
+ *
+ * Otherwise, if the return value is positive, then it indicates the
+ * amount of data in @buffer, which will have been sniffed. If an
+ * error had occurred after reading some data, that will be stored in
+ * @sniffer->priv->error and should be returned on the next read. (If
+ * an EOF occurred after reading some data, then the next read will
+ * just return 0.)
+ */
+static gssize
+read_and_sniff (GInputStream *stream, void *buffer, gsize count,
+		gsize *so_far, GCancellable *cancellable, GError **error)
+{
+	SoupContentSnifferStream *sniffer = SOUP_CONTENT_SNIFFER_STREAM (stream);
+	gssize nread;
+	GError *my_error = NULL;
+	SoupBuffer *buf;
+
+	g_return_val_if_fail (count >= sniffer->priv->buffer_size, -1);
+
+	do {
+		nread = G_INPUT_STREAM_CLASS (soup_content_sniffer_stream_parent_class)->
+			read_fn (stream, (guchar *)buffer + *so_far,
+				 count - *so_far, cancellable, &my_error);
+		if (nread <= 0)
+			break;
+		*so_far += nread;
+	} while (*so_far < sniffer->priv->buffer_size);
+
+	/* If we got EAGAIN before filling the buffer, just return that. */
+	if (g_error_matches (my_error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) {
+		g_propagate_error (error, my_error);
+		return -1;
+	}
+
+	/* Otherwise, we've either filled the buffer or gotten an EOF
+	 * or fatal error, so sniff the data.
+	 */
+	buf = soup_buffer_new (SOUP_MEMORY_TEMPORARY, buffer, *so_far);
+	sniffer->priv->content_type =
+		soup_content_sniffer_sniff (sniffer->priv->sniffer,
+					    sniffer->priv->msg,
+					    buf,
+					    &sniffer->priv->content_params);
+	soup_buffer_free (buf);
+	sniffer->priv->sniffing = FALSE;
+
+	if (nread <= 0 && *so_far) {
+		/* Save the error/EOF for later, return the data now. */
+		sniffer->priv->error = my_error;
+		my_error = NULL;
+		return *so_far;
+	}
+
+	return nread > 0 ? *so_far : nread;
+}	
+
+static gssize
+soup_content_sniffer_stream_read (GInputStream  *stream,
+				  void          *buffer,
+				  gsize          count,
+				  GCancellable  *cancellable,
+				  GError       **error)
+{
+	SoupContentSnifferStream *sniffer = SOUP_CONTENT_SNIFFER_STREAM (stream);
+	gssize nread;
+	gsize total;
+
+	if (sniffer->priv->error) {
+		g_propagate_error (error, sniffer->priv->error);
+		sniffer->priv->error = NULL;
+		return -1;
+	}
+
+	if (sniffer->priv->sniffing) {
+		if (!sniffer->priv->buf &&
+		    count > sniffer->priv->buffer_size) {
+			/* Try to read directly into @buffer */
+			total = 0;
+			nread = read_and_sniff (stream, buffer, count,
+						&total, cancellable, error);
+			if (nread < 0 && total > 0) {
+				/* error is WOULD_BLOCK, save the data */
+				sniffer->priv->buf = g_byte_array_sized_new (sniffer->priv->buffer_size);
+				g_byte_array_append (sniffer->priv->buf, buffer, total);
+			}
+			return nread;
+		} else {
+			/* We already read some, or else @buffer is too small,
+			 * so read into our own buffer.
+			 */
+			if (!sniffer->priv->buf)
+				sniffer->priv->buf = g_byte_array_sized_new (sniffer->priv->buffer_size);
+
+			total = sniffer->priv->buf->len;
+			nread = read_and_sniff (stream, sniffer->priv->buf->data,
+						sniffer->priv->buffer_size,
+						&total, cancellable, error);
+			sniffer->priv->buf->len = total;
+
+			if (nread <= 0)
+				return nread;
+			/* else, fall through to the "read from buf" case */
+		}
+	}
+
+	if (sniffer->priv->buf) {
+		nread = MIN (count, sniffer->priv->buf->len);
+		memcpy (buffer, sniffer->priv->buf->data, nread);
+		if (nread == sniffer->priv->buf->len) {
+			g_byte_array_free (sniffer->priv->buf, TRUE);
+			sniffer->priv->buf = NULL;
+		} else
+			g_byte_array_remove_range (sniffer->priv->buf, 0, nread);
+	} else {
+		nread = G_INPUT_STREAM_CLASS (soup_content_sniffer_stream_parent_class)->
+			read_fn (stream, buffer, count, cancellable, error);
+	}
+	return nread;
+}
+
+static gssize
+soup_content_sniffer_stream_skip (GInputStream  *stream,
+				  gsize          count,
+				  GCancellable  *cancellable,
+				  GError       **error)
+{
+	SoupContentSnifferStream *sniffer = SOUP_CONTENT_SNIFFER_STREAM (stream);
+	gssize nskipped;
+
+	if (sniffer->priv->sniffing) {
+		/* Read into the internal buffer... */
+		nskipped = soup_content_sniffer_stream_read (stream, NULL, 0, cancellable, error);
+		if (nskipped == -1)
+			return -1;
+		/* Now fall through */
+	}
+
+	if (sniffer->priv->buf) {
+		nskipped = MIN (count, sniffer->priv->buf->len);
+		if (nskipped == sniffer->priv->buf->len) {
+			g_byte_array_free (sniffer->priv->buf, TRUE);
+			sniffer->priv->buf = NULL;
+		} else
+			g_byte_array_remove_range (sniffer->priv->buf, 0, nskipped);
+	} else {
+		nskipped = G_INPUT_STREAM_CLASS (soup_content_sniffer_stream_parent_class)->
+			skip (stream, count, cancellable, error);
+	}
+	return nskipped;
+}
+
+static void
+soup_content_sniffer_stream_init (SoupContentSnifferStream *sniffer)
+{
+	sniffer->priv = G_TYPE_INSTANCE_GET_PRIVATE (sniffer,
+						     SOUP_TYPE_CONTENT_SNIFFER_STREAM,
+						     SoupContentSnifferStreamPrivate);
+	sniffer->priv->sniffing = TRUE;
+}
+
+static void
+soup_content_sniffer_stream_class_init (SoupContentSnifferStreamClass *sniffer_class)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (sniffer_class);
+	GInputStreamClass *input_stream_class =
+		G_INPUT_STREAM_CLASS (sniffer_class);
+ 
+	g_type_class_add_private (sniffer_class, sizeof (SoupContentSnifferStreamPrivate));
+
+	object_class->finalize = soup_content_sniffer_stream_finalize;
+	object_class->set_property = soup_content_sniffer_stream_set_property;
+	object_class->get_property = soup_content_sniffer_stream_get_property;
+
+	input_stream_class->read_fn = soup_content_sniffer_stream_read;
+	input_stream_class->skip = soup_content_sniffer_stream_skip;
+
+	g_object_class_install_property (
+		object_class, PROP_SNIFFER,
+		g_param_spec_object ("sniffer",
+				     "Sniffer",
+				     "The stream's SoupContentSniffer",
+				     SOUP_TYPE_CONTENT_SNIFFER,
+				     G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+	g_object_class_install_property (
+		object_class, PROP_MESSAGE,
+		g_param_spec_object ("message",
+				     "Message",
+				     "The stream's SoupMessage",
+				     SOUP_TYPE_MESSAGE,
+				     G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+}
+
+GInputStream *
+soup_content_sniffer_stream_new (SoupContentSniffer *sniffer,
+				 SoupMessage        *msg,
+				 GInputStream       *base_stream)
+{
+	return g_object_new (SOUP_TYPE_CONTENT_SNIFFER_STREAM,
+			     "base-stream", base_stream,
+			     "message", msg,
+			     "sniffer", sniffer,
+			     NULL);
+}
+
+const char *
+soup_content_sniffer_stream_sniff (SoupContentSnifferStream  *stream,
+				   GHashTable               **params)
+{
+	if (params)
+		*params = stream->priv->content_params;
+	return stream->priv->content_type;
+}
diff --git a/libsoup/soup-content-sniffer-stream.h b/libsoup/soup-content-sniffer-stream.h
new file mode 100644
index 0000000..dcbfcfa
--- /dev/null
+++ b/libsoup/soup-content-sniffer-stream.h
@@ -0,0 +1,47 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2010 Red Hat, Inc.
+ */
+
+#ifndef SOUP_CONTENT_SNIFFER_STREAM_H
+#define SOUP_CONTENT_SNIFFER_STREAM_H 1
+
+#include <libsoup/soup-types.h>
+#include <libsoup/soup-content-sniffer.h>
+
+G_BEGIN_DECLS
+
+#define SOUP_TYPE_CONTENT_SNIFFER_STREAM         (soup_content_sniffer_stream_get_type ())
+#define SOUP_CONTENT_SNIFFER_STREAM(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), SOUP_TYPE_CONTENT_SNIFFER_STREAM, SoupContentSnifferStream))
+#define SOUP_CONTENT_SNIFFER_STREAM_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), SOUP_TYPE_CONTENT_SNIFFER_STREAM, SoupContentSnifferStreamClass))
+#define SOUP_IS_CONTENT_SNIFFER_STREAM(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), SOUP_TYPE_CONTENT_SNIFFER_STREAM))
+#define SOUP_IS_CONTENT_SNIFFER_STREAM_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), SOUP_TYPE_CONTENT_SNIFFER_STREAM))
+#define SOUP_CONTENT_SNIFFER_STREAM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), SOUP_TYPE_CONTENT_SNIFFER_STREAM, SoupContentSnifferStreamClass))
+
+typedef struct _SoupContentSnifferStream        SoupContentSnifferStream;
+typedef struct _SoupContentSnifferStreamPrivate SoupContentSnifferStreamPrivate;
+typedef struct _SoupContentSnifferStreamClass   SoupContentSnifferStreamClass;
+
+struct _SoupContentSnifferStream {
+	GFilterInputStream parent_instance;
+
+	/*< private >*/
+	SoupContentSnifferStreamPrivate *priv;
+};
+
+struct _SoupContentSnifferStreamClass {
+	GFilterInputStreamClass parent_class;
+
+};
+
+GType soup_content_sniffer_stream_get_type (void) G_GNUC_CONST;
+
+GInputStream *soup_content_sniffer_stream_new   (SoupContentSniffer        *sniffer,
+						 SoupMessage               *msg,
+						 GInputStream              *base_stream);
+const char   *soup_content_sniffer_stream_sniff (SoupContentSnifferStream  *stream,
+						 GHashTable               **params);
+
+G_END_DECLS
+
+#endif /* SOUP_CONTENT_SNIFFER_STREAM_H */
diff --git a/libsoup/soup-content-sniffer.c b/libsoup/soup-content-sniffer.c
index de90a60..accb552 100644
--- a/libsoup/soup-content-sniffer.c
+++ b/libsoup/soup-content-sniffer.c
@@ -92,6 +92,14 @@ soup_content_sniffer_sniff (SoupContentSniffer *sniffer,
 	return SOUP_CONTENT_SNIFFER_GET_CLASS (sniffer)->sniff (sniffer, msg, buffer, params);
 }
 
+gsize
+soup_content_sniffer_get_buffer_size (SoupContentSniffer *sniffer)
+{
+	g_return_val_if_fail (SOUP_IS_CONTENT_SNIFFER (sniffer), 0);
+
+	return SOUP_CONTENT_SNIFFER_GET_CLASS (sniffer)->get_buffer_size (sniffer);
+}
+
 /* This table is based on the HTML5 spec;
  * See 2.7.4 Content-Type sniffing: unknown type
  */
@@ -570,9 +578,8 @@ static void
 soup_content_sniffer_got_headers_cb (SoupMessage *msg, SoupContentSniffer *sniffer)
 {
 	SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
-	SoupContentSnifferClass *content_sniffer_class = SOUP_CONTENT_SNIFFER_GET_CLASS (sniffer);
 
-	priv->bytes_for_sniffing = content_sniffer_class->get_buffer_size (sniffer);
+	priv->bytes_for_sniffing = soup_content_sniffer_get_buffer_size (sniffer);
 }
 
 static void
diff --git a/libsoup/soup-content-sniffer.h b/libsoup/soup-content-sniffer.h
index a8aa915..59c0154 100644
--- a/libsoup/soup-content-sniffer.h
+++ b/libsoup/soup-content-sniffer.h
@@ -43,14 +43,15 @@ typedef struct {
 	void (*_libsoup_reserved5) (void);
 } SoupContentSnifferClass;
 
-GType               soup_content_sniffer_get_type (void);
+GType               soup_content_sniffer_get_type        (void);
 
-SoupContentSniffer *soup_content_sniffer_new      (void);
+SoupContentSniffer *soup_content_sniffer_new             (void);
 
-char               *soup_content_sniffer_sniff    (SoupContentSniffer *sniffer,
-						   SoupMessage *msg,
-						   SoupBuffer *buffer,
-						   GHashTable **params);
+char               *soup_content_sniffer_sniff           (SoupContentSniffer  *sniffer,
+							  SoupMessage         *msg,
+							  SoupBuffer          *buffer,
+							  GHashTable         **params);
+gsize               soup_content_sniffer_get_buffer_size (SoupContentSniffer  *sniffer);
 
 G_END_DECLS
 
diff --git a/libsoup/soup-message-io.c b/libsoup/soup-message-io.c
index 83f3eb0..d77bf36 100644
--- a/libsoup/soup-message-io.c
+++ b/libsoup/soup-message-io.c
@@ -13,6 +13,7 @@
 #include <string.h>
 
 #include "soup-connection.h"
+#include "soup-content-sniffer-stream.h"
 #include "soup-input-stream.h"
 #include "soup-message.h"
 #include "soup-message-private.h"
@@ -61,8 +62,9 @@ typedef struct {
 	goffset               read_length;
 	gboolean              read_eof_ok;
 
-	gboolean              need_content_sniffed, need_got_chunk;
-	SoupMessageBody      *sniff_data;
+	SoupContentSnifferStream *sniffer_stream;
+	gboolean              need_content_sniffed;
+	SoupBuffer           *sniffed_buffer;
 
 	SoupMessageIOState    write_state;
 	SoupEncoding          write_encoding;
@@ -128,8 +130,8 @@ soup_message_io_cleanup (SoupMessage *msg)
 	if (io->write_chunk)
 		soup_buffer_free (io->write_chunk);
 
-	if (io->sniff_data)
-		soup_message_body_free (io->sniff_data);
+	if (io->sniffed_buffer)
+		soup_buffer_free (io->sniffed_buffer);
 
 	g_slice_free (SoupMessageIOData, io);
 }
@@ -219,44 +221,25 @@ io_error (SoupSocket *sock, SoupMessage *msg, GError *error)
 }
 
 static gboolean
-io_handle_sniffing (SoupMessage *msg, gboolean done_reading)
+io_handle_sniffing (SoupMessage *msg)
 {
 	SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
 	SoupMessageIOData *io = priv->io_data;
 	SoupBuffer *sniffed_buffer;
-	char *sniffed_mime_type;
+	const char *sniffed_mime_type;
 	GHashTable *params = NULL;
 
-	if (!priv->sniffer)
-		return TRUE;
-
-	if (!io->sniff_data) {
-		io->sniff_data = soup_message_body_new ();
-		io->need_content_sniffed = TRUE;
-	}
-
 	if (io->need_content_sniffed) {
-		if (io->sniff_data->length < priv->bytes_for_sniffing &&
-		    !done_reading)
-			return TRUE;
-
 		io->need_content_sniffed = FALSE;
-		sniffed_buffer = soup_message_body_flatten (io->sniff_data);
-		sniffed_mime_type = soup_content_sniffer_sniff (priv->sniffer, msg, sniffed_buffer, &params);
+
+		sniffed_mime_type = soup_content_sniffer_stream_sniff (io->sniffer_stream, &params);
 
 		SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
 		soup_message_content_sniffed (msg, sniffed_mime_type, params);
-		g_free (sniffed_mime_type);
-		if (params)
-			g_hash_table_destroy (params);
-		if (sniffed_buffer)
-			soup_buffer_free (sniffed_buffer);
 		SOUP_MESSAGE_IO_RETURN_VAL_IF_CANCELLED_OR_PAUSED (FALSE);
-	}
-
-	if (io->need_got_chunk) {
-		io->need_got_chunk = FALSE;
-		sniffed_buffer = soup_message_body_flatten (io->sniff_data);
+	} else if (io->sniffed_buffer) {
+		sniffed_buffer = io->sniffed_buffer;
+		io->sniffed_buffer = NULL;
 
 		SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
 		soup_message_got_chunk (msg, sniffed_buffer);
@@ -385,6 +368,15 @@ setup_body_istream (SoupMessage *msg)
 		g_object_unref (io->body_istream);
 		io->body_istream = filter;
 	}
+
+	if (priv->sniffer) {
+		filter = soup_content_sniffer_stream_new (priv->sniffer,
+							  msg, io->body_istream);
+		io->sniffer_stream = SOUP_CONTENT_SNIFFER_STREAM (filter);
+		g_object_unref (io->body_istream);
+		io->body_istream = filter;
+		io->need_content_sniffed = TRUE;
+	}
 }
 
 /* Reads as much message body data as is available on io->sock (but no
@@ -410,17 +402,17 @@ read_body_chunk (SoupMessage *msg)
 		return FALSE;
 	}
 
+	if (!io->body_istream)
+		setup_body_istream (msg);
+
+	if (io->sniffed_buffer && !io_handle_sniffing (msg))
+		return FALSE;
+
 	if (io->read_encoding == SOUP_ENCODING_NONE ||
 	    (io->read_encoding == SOUP_ENCODING_CONTENT_LENGTH &&
 	     io->read_length == 0))	    
 		return TRUE;
 
-	if (!io_handle_sniffing (msg, FALSE))
-		return FALSE;
-
-	if (!io->body_istream)
-		setup_body_istream (msg);
-
 	while (TRUE) {
 		if (priv->chunk_allocator) {
 			buffer = priv->chunk_allocator (msg, io->read_length, priv->chunk_allocator_data);
@@ -446,13 +438,10 @@ read_body_chunk (SoupMessage *msg)
 
 			soup_message_body_got_chunk (io->read_body, buffer);
 
-			if (io->need_content_sniffed) {
-				soup_message_body_append_buffer (io->sniff_data, buffer);
-				soup_buffer_free (buffer);
-				io->need_got_chunk = TRUE;
-				if (!io_handle_sniffing (msg, FALSE))
-					return FALSE;
-				continue;
+			if (io->need_content_sniffed &&
+			    !io_handle_sniffing (msg)) {
+				io->sniffed_buffer = buffer;
+				return FALSE;
 			}
 
 			SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
@@ -878,20 +867,8 @@ io_read (SoupInputStream *stream, SoupMessage *msg)
 		if (!read_body_chunk (msg))
 			return FALSE;
 
-		if (!io_handle_sniffing (msg, TRUE)) {
-			/* If the message was paused (as opposed to
-			 * cancelled), we need to make sure we wind up
-			 * back here when it's unpaused, even if it
-			 * was doing a chunked or EOF-terminated read
-			 * before.
-			 */
-			if (io == priv->io_data) {
-				io->read_state = SOUP_MESSAGE_IO_STATE_BODY;
-				io->read_encoding = SOUP_ENCODING_CONTENT_LENGTH;
-				io->read_length = 0;
-			}
+		if (!io_handle_sniffing (msg))
 			return FALSE;
-		}
 
 		io->read_state = SOUP_MESSAGE_IO_STATE_FINISHING;
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]