[libsoup] Miscellaneous content-sniffing fixes



commit d9bcaac69203e8f6501a3a60aae350a0cfc342bb
Author: Dan Winship <danw gnome org>
Date:   Fri Jul 10 13:11:07 2009 -0400

    Miscellaneous content-sniffing fixes
    
    Remove the should_sniff_content flag; if there is a sniffer, we always
    sniff.
    
    Clean up soup-message-io a bit to require fewer special cases, and fix
    a few potential leaks/crashes where it wasn't dealing with
    IF_CANCELLED_OR_PAUSED correctly. (Although this looks like a large
    patch, it actually results in a much smaller diff relative to 2.26.
    
    Fix tests/sniffing-test to do chunked encoding correctly, make sure to
    return data in chunks that are smaller than the sniffing buffer size,
    and make resources/mbox larger than the sniffing buffer size so it
    takes multiple reads to get enough data (when using chunked encoding).
    Also add tests for empty response bodies (from Gustavo).
    
    http://bugzilla.gnome.org/show_bug.cgi?id=587907

 libsoup/soup-content-sniffer.c |    1 -
 libsoup/soup-message-io.c      |  167 ++++++++++++++++------------------------
 libsoup/soup-message-private.h |    1 -
 tests/resources/mbox           |   48 ++++++++++++
 tests/sniffing-test.c          |  160 ++++++++++++++++++++++++--------------
 5 files changed, 215 insertions(+), 162 deletions(-)
---
diff --git a/libsoup/soup-content-sniffer.c b/libsoup/soup-content-sniffer.c
index 5fdee5c..7a39473 100644
--- a/libsoup/soup-content-sniffer.c
+++ b/libsoup/soup-content-sniffer.c
@@ -541,7 +541,6 @@ soup_content_sniffer_got_headers_cb (SoupMessage *msg, SoupContentSniffer *sniff
 	SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
 	SoupContentSnifferClass *content_sniffer_class = SOUP_CONTENT_SNIFFER_GET_CLASS (sniffer);
 
-	priv->should_sniff_content = TRUE;
 	priv->bytes_for_sniffing = content_sniffer_class->get_buffer_size (sniffer);
 }
 
diff --git a/libsoup/soup-message-io.c b/libsoup/soup-message-io.c
index 5951e98..74c934f 100644
--- a/libsoup/soup-message-io.c
+++ b/libsoup/soup-message-io.c
@@ -18,7 +18,6 @@
 #include "soup-misc.h"
 #include "soup-socket.h"
 #include "soup-ssl.h"
-#include "soup-uri.h"
 
 typedef enum {
 	SOUP_MESSAGE_IO_CLIENT,
@@ -54,10 +53,8 @@ typedef struct {
 	SoupMessageBody      *read_body;
 	goffset               read_length;
 
-	gboolean              acked_content_sniff_decision;
-	gboolean              delay_got_chunks;
-	SoupMessageBody      *delayed_chunk_data;
-	gsize                 delayed_chunk_length;
+	gboolean              need_content_sniffed, need_got_chunk;
+	SoupMessageBody      *sniff_data;
 
 	SoupMessageIOState    write_state;
 	SoupEncoding          write_encoding;
@@ -111,8 +108,8 @@ soup_message_io_cleanup (SoupMessage *msg)
 	if (io->write_chunk)
 		soup_buffer_free (io->write_chunk);
 
-	if (io->delayed_chunk_data)
-		soup_message_body_free (io->delayed_chunk_data);
+	if (io->sniff_data)
+		soup_message_body_free (io->sniff_data);
 
 	g_slice_free (SoupMessageIOData, io);
 }
@@ -217,30 +214,50 @@ io_disconnected (SoupSocket *sock, SoupMessage *msg)
 }
 
 static gboolean
-io_sniff_content (SoupMessage *msg)
+io_handle_sniffing (SoupMessage *msg, gboolean done_reading)
 {
 	SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
 	SoupMessageIOData *io = priv->io_data;
-	SoupBuffer *sniffed_buffer = soup_message_body_flatten (io->delayed_chunk_data);
+	SoupBuffer *sniffed_buffer;
 	char *sniffed_mime_type;
 	GHashTable *params = NULL;
 
-	io->delay_got_chunks = FALSE;
+	if (!priv->sniffer)
+		return TRUE;
 
-	sniffed_mime_type = soup_content_sniffer_sniff (priv->sniffer, msg, sniffed_buffer, &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);
-	SOUP_MESSAGE_IO_RETURN_VAL_IF_CANCELLED_OR_PAUSED (FALSE);
+	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);
 
-	SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
-	soup_message_got_chunk (msg, sniffed_buffer);
-	soup_buffer_free (sniffed_buffer);
-	soup_message_body_free (io->delayed_chunk_data);
-	io->delayed_chunk_data = NULL;
-	SOUP_MESSAGE_IO_RETURN_VAL_IF_CANCELLED_OR_PAUSED (FALSE);
+		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);
+
+		SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
+		soup_message_got_chunk (msg, sniffed_buffer);
+		soup_buffer_free (sniffed_buffer);
+		SOUP_MESSAGE_IO_RETURN_VAL_IF_CANCELLED_OR_PAUSED (FALSE);
+	}
 
 	return TRUE;
 }
@@ -332,20 +349,8 @@ read_body_chunk (SoupMessage *msg)
 	GError *error = NULL;
 	SoupBuffer *buffer;
 
-	if (!io->acked_content_sniff_decision) {
-		/* The content sniffer feature decides whether a
-		 * message needs to be sniffed while handling
-		 * got-headers, but the message may be paused in a
-		 * user handler, so we need to make sure the signal is
-		 * emitted, or delay_got_chunks is correctly setup
-		 * here.
-		 */
-		if (priv->should_sniff_content)
-			io->delay_got_chunks = TRUE;
-		else if (priv->sniffer)
-			soup_message_content_sniffed (msg, NULL, NULL);
-		io->acked_content_sniff_decision = TRUE;
-	}
+	if (!io_handle_sniffing (msg, FALSE))
+		return FALSE;
 
 	while (read_to_eof || io->read_length > 0) {
 		if (priv->chunk_allocator) {
@@ -377,24 +382,18 @@ read_body_chunk (SoupMessage *msg)
 
 			io->read_length -= nread;
 
-			if (io->delay_got_chunks) {
-				if (!io->delayed_chunk_data)
-					io->delayed_chunk_data = soup_message_body_new ();
-
-				soup_message_body_append_buffer (io->delayed_chunk_data, buffer);
-				io->delayed_chunk_length += buffer->length;
-
-				/* We already have enough data to perform sniffing, so do it */
-				if (io->delayed_chunk_length > priv->bytes_for_sniffing) {
-					if (!io_sniff_content (msg))
-						return FALSE;
-				}
-			} else {
-				SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
-				soup_message_got_chunk (msg, buffer);
-				soup_buffer_free (buffer);
-				SOUP_MESSAGE_IO_RETURN_VAL_IF_CANCELLED_OR_PAUSED (FALSE);
+			if (io->need_content_sniffed) {
+				soup_message_body_append_buffer (io->sniff_data, buffer);
+				io->need_got_chunk = TRUE;
+				if (!io_handle_sniffing (msg, FALSE))
+					return FALSE;
+				continue;
 			}
+
+			SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
+			soup_message_got_chunk (msg, buffer);
+			soup_buffer_free (buffer);
+			SOUP_MESSAGE_IO_RETURN_VAL_IF_CANCELLED_OR_PAUSED (FALSE);
 			continue;
 		}
 
@@ -742,23 +741,6 @@ io_read (SoupSocket *sock, SoupMessage *msg)
 	guint status;
 
  read_more:
-	/* We have delayed chunks, but are no longer delaying, so this
-	 * means we already sniffed but the message got paused while
-	 * content-sniffed was being handled, in which case we did not
-	 * emit the necessary got-chunk; See also the handling for
-	 * state SOUP_MESSAGE_IO_STATE_BODY in the switch bellow.
-	 */
-	if (io->delayed_chunk_data && !io->delay_got_chunks) {
-		SoupBuffer *sniffed_buffer = soup_message_body_flatten (io->delayed_chunk_data);
-
-		SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
-		soup_message_got_chunk (msg, sniffed_buffer);
-		soup_buffer_free (sniffed_buffer);
-		soup_message_body_free (io->delayed_chunk_data);
-		io->delayed_chunk_data = NULL;
-		SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
-	}
-
 	switch (io->read_state) {
 	case SOUP_MESSAGE_IO_STATE_NOT_STARTED:
 		return;
@@ -866,35 +848,19 @@ io_read (SoupSocket *sock, SoupMessage *msg)
 			return;
 
 	got_body:
-		/* If we end up returning, read_state needs to be set
-		 * to IO_STATE_BODY, and read_length must be 0; since
-		 * we may be coming from STATE_TRAILERS, or may be
-		 * doing a read-to-eof, we sanitize these here.
-		 */
-		io->read_state = SOUP_MESSAGE_IO_STATE_BODY;
-		io->read_length = 0;
-
-		/* A chunk of data may have been read and the emission
-		 * of got_chunk delayed because we wanted to wait for
-		 * more chunks to arrive, for doing content sniffing,
-		 * but the body was too small, so we need to check if
-		 * an emission is in order here, along with the
-		 * sniffing, if we haven't done it yet, of course.
-		 */
-		if (io->delayed_chunk_data) {
-			if (io->delay_got_chunks) {
-				if (!io_sniff_content (msg))
-					return;
-			} else {
-				SoupBuffer *sniffed_buffer = soup_message_body_flatten (io->delayed_chunk_data);
-
-				SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
-				soup_message_got_chunk (msg, sniffed_buffer);
-				soup_buffer_free (sniffed_buffer);
-				soup_message_body_free (io->delayed_chunk_data);
-				io->delayed_chunk_data = NULL;
-				SOUP_MESSAGE_IO_RETURN_IF_CANCELLED_OR_PAUSED;
+		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;
 			}
+			return;
 		}
 
 		io->read_state = SOUP_MESSAGE_IO_STATE_FINISHING;
@@ -1000,9 +966,6 @@ new_iostate (SoupMessage *msg, SoupSocket *sock, SoupMessageIOMode mode,
 	io->read_state  = SOUP_MESSAGE_IO_STATE_NOT_STARTED;
 	io->write_state = SOUP_MESSAGE_IO_STATE_NOT_STARTED;
 
-	if (priv->should_sniff_content)
-		io->delay_got_chunks = TRUE;
-
 	if (priv->io_data)
 		soup_message_io_cleanup (msg);
 	priv->io_data = io;
diff --git a/libsoup/soup-message-private.h b/libsoup/soup-message-private.h
index 999c335..5c88cbc 100644
--- a/libsoup/soup-message-private.h
+++ b/libsoup/soup-message-private.h
@@ -31,7 +31,6 @@ typedef struct {
 	gboolean           server_side;
 
 	SoupContentSniffer *sniffer;
-	gboolean           should_sniff_content;
 	gsize              bytes_for_sniffing;
 
 	SoupHTTPVersion    http_version, orig_http_version;
diff --git a/tests/resources/mbox b/tests/resources/mbox
index 929ad2b..2e96727 100644
--- a/tests/resources/mbox
+++ b/tests/resources/mbox
@@ -14,3 +14,51 @@ Date: Wed, 17 Jun 2009 21:20:48 -0300
 
 This is a dumb email.
 
+From email here Wed Jun 17 21:20:48 2009
+Return-path: <email here>
+Envelope-to: email here
+Delivery-date: Wed, 17 Jun 2009 21:20:48 -0300
+Received: from email by here.domain with local (Exim 4.69)
+	(envelope-from <email here>)
+	id 1MH5N2-0008Lq-7c
+	for email here; Wed, 17 Jun 2009 21:20:48 -0300
+To: email here
+Subject: This is just so that I have a mailbox
+Message-Id: <E1MH5N2-0008Lq-7c here domain>
+From: A Nice User <email here>
+Date: Wed, 17 Jun 2009 21:20:48 -0300
+
+This is a dumb email.
+
+From email here Wed Jun 17 21:20:48 2009
+Return-path: <email here>
+Envelope-to: email here
+Delivery-date: Wed, 17 Jun 2009 21:20:48 -0300
+Received: from email by here.domain with local (Exim 4.69)
+	(envelope-from <email here>)
+	id 1MH5N2-0008Lq-7c
+	for email here; Wed, 17 Jun 2009 21:20:48 -0300
+To: email here
+Subject: This is just so that I have a mailbox
+Message-Id: <E1MH5N2-0008Lq-7c here domain>
+From: A Nice User <email here>
+Date: Wed, 17 Jun 2009 21:20:48 -0300
+
+This is a dumb email.
+
+From email here Wed Jun 17 21:20:48 2009
+Return-path: <email here>
+Envelope-to: email here
+Delivery-date: Wed, 17 Jun 2009 21:20:48 -0300
+Received: from email by here.domain with local (Exim 4.69)
+	(envelope-from <email here>)
+	id 1MH5N2-0008Lq-7c
+	for email here; Wed, 17 Jun 2009 21:20:48 -0300
+To: email here
+Subject: This is just so that I have a mailbox
+Message-Id: <E1MH5N2-0008Lq-7c here domain>
+From: A Nice User <email here>
+Date: Wed, 17 Jun 2009 21:20:48 -0300
+
+This is a dumb email.
+
diff --git a/tests/sniffing-test.c b/tests/sniffing-test.c
index 6cf6a03..18be7d2 100644
--- a/tests/sniffing-test.c
+++ b/tests/sniffing-test.c
@@ -21,10 +21,10 @@ server_callback (SoupServer *server, SoupMessage *msg,
 		 SoupClientContext *context, gpointer data)
 {
 	GError *error = NULL;
-	char *chunked;
+	char *query_key;
 	char *contents;
-	gsize length;
-	gboolean use_chunked_encoding = FALSE;
+	gsize length, offset;
+	gboolean empty_response = FALSE;
 
 	if (msg->method != SOUP_METHOD_GET) {
 		soup_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED);
@@ -34,18 +34,26 @@ server_callback (SoupServer *server, SoupMessage *msg,
 	soup_message_set_status (msg, SOUP_STATUS_OK);
 
 	if (query) {
-		chunked = g_hash_table_lookup (query, "chunked");
-		if (chunked && g_str_equal (chunked, "yes")) {
+		query_key = g_hash_table_lookup (query, "chunked");
+		if (query_key && g_str_equal (query_key, "yes")) {
 			soup_message_headers_set_encoding (msg->response_headers,
 							   SOUP_ENCODING_CHUNKED);
-			use_chunked_encoding = TRUE;
 		}
+
+		query_key = g_hash_table_lookup (query, "empty_response");
+		if (query_key && g_str_equal (query_key, "yes"))
+			empty_response = TRUE;
 	}
 
 	if (!strcmp (path, "/mbox")) {
-		g_file_get_contents ("resources/mbox",
-				     &contents, &length,
-				     &error);
+		if (empty_response) {
+			contents = g_strdup ("");
+			length = 0;
+		} else {
+			g_file_get_contents ("resources/mbox",
+					     &contents, &length,
+					     &error);
+		}
 
 		if (error) {
 			g_error ("%s", error->message);
@@ -53,10 +61,8 @@ server_callback (SoupServer *server, SoupMessage *msg,
 			exit (1);
 		}
 
-		soup_message_set_response (msg, "text/plain",
-					   SOUP_MEMORY_TAKE,
-					   contents,
-					   length);
+		soup_message_headers_append (msg->response_headers,
+					     "Content-Type", "text/plain");
 	}
 
 	if (g_str_has_prefix (path, "/text_or_binary/")) {
@@ -76,10 +82,8 @@ server_callback (SoupServer *server, SoupMessage *msg,
 			exit (1);
 		}
 
-		soup_message_set_response (msg, "text/plain",
-					   SOUP_MEMORY_TAKE,
-					   contents,
-					   length);
+		soup_message_headers_append (msg->response_headers,
+					     "Content-Type", "text/plain");
 	}
 
 	if (g_str_has_prefix (path, "/unknown/")) {
@@ -99,10 +103,8 @@ server_callback (SoupServer *server, SoupMessage *msg,
 			exit (1);
 		}
 
-		soup_message_set_response (msg, "UNKNOWN/unknown",
-					   SOUP_MEMORY_TAKE,
-					   contents,
-					   length);
+		soup_message_headers_append (msg->response_headers,
+					     "Content-Type", "UNKNOWN/unknown");
 	}
 
 	if (g_str_has_prefix (path, "/type/")) {
@@ -129,11 +131,8 @@ server_callback (SoupServer *server, SoupMessage *msg,
 		ptr = g_strrstr (components[2], "_");
 		*ptr = '/';
 
-		soup_message_set_response (msg, components[2],
-					   SOUP_MEMORY_TAKE,
-					   contents,
-					   length);
-
+		soup_message_headers_append (msg->response_headers,
+					     "Content-Type", components[2]);
 		g_strfreev (components);
 	}
 
@@ -154,23 +153,26 @@ server_callback (SoupServer *server, SoupMessage *msg,
 			exit (1);
 		}
 
-		soup_message_set_response (msg, "text/xml",
-					   SOUP_MEMORY_TAKE,
-					   contents,
-					   length);
-
+		soup_message_headers_append (msg->response_headers,
+					     "Content-Type", "text/xml");
 		soup_message_headers_append (msg->response_headers,
 					     "Content-Type", "text/plain");
 	}
 
-	if (use_chunked_encoding)
-		soup_message_body_complete (msg->response_body);
+	for (offset = 0; offset < length; offset += 500) {
+		soup_message_body_append (msg->response_body,
+					  SOUP_MEMORY_COPY,
+					  contents + offset,
+					  MIN(500, length - offset));
+	}
+	soup_message_body_complete (msg->response_body);
 }
 
 static gboolean
 unpause_msg (gpointer data)
 {
 	SoupMessage *msg = (SoupMessage*)data;
+	debug_printf (2, "  unpause\n");
 	soup_session_unpause_message (session, msg);
 	return FALSE;
 }
@@ -181,6 +183,8 @@ content_sniffed (SoupMessage *msg, char *content_type, GHashTable *params, gpoin
 {
 	gboolean should_pause = GPOINTER_TO_INT (data);
 
+	debug_printf (2, "  content-sniffed -> %s\n", content_type);
+
 	if (g_object_get_data (G_OBJECT (msg), "got-chunk")) {
 		debug_printf (1, "  got-chunk got emitted before content-sniffed\n");
 		errors++;
@@ -189,6 +193,7 @@ content_sniffed (SoupMessage *msg, char *content_type, GHashTable *params, gpoin
 	g_object_set_data (G_OBJECT (msg), "content-sniffed", GINT_TO_POINTER (TRUE));
 
 	if (should_pause) {
+		debug_printf (2, "  pause\n");
 		soup_session_pause_message (session, msg);
 		g_idle_add (unpause_msg, msg);
 	}
@@ -199,6 +204,8 @@ got_headers (SoupMessage *msg, gpointer data)
 {
 	gboolean should_pause = GPOINTER_TO_INT (data);
 
+	debug_printf (2, "  got-headers\n");
+
 	if (g_object_get_data (G_OBJECT (msg), "content-sniffed")) {
 		debug_printf (1, "  content-sniffed got emitted before got-headers\n");
 		errors++;
@@ -207,6 +214,7 @@ got_headers (SoupMessage *msg, gpointer data)
 	g_object_set_data (G_OBJECT (msg), "got-headers", GINT_TO_POINTER (TRUE));
 
 	if (should_pause) {
+		debug_printf (2, "  pause\n");
 		soup_session_pause_message (session, msg);
 		g_idle_add (unpause_msg, msg);
 	}
@@ -217,6 +225,8 @@ got_chunk (SoupMessage *msg, SoupBuffer *chunk, gpointer data)
 {
 	gboolean should_accumulate = GPOINTER_TO_INT (data);
 
+	debug_printf (2, "  got-chunk\n");
+
 	g_object_set_data (G_OBJECT (msg), "got-chunk", GINT_TO_POINTER (TRUE));
 
 	if (!should_accumulate) {
@@ -237,7 +247,8 @@ static void
 do_signals_test (gboolean should_content_sniff,
 		 gboolean should_pause,
 		 gboolean should_accumulate,
-		 gboolean chunked_encoding)
+		 gboolean chunked_encoding,
+		 gboolean empty_response)
 {
 	SoupURI *uri = soup_uri_new_with_base (base_uri, "/mbox");
 	SoupMessage *msg = soup_message_new_from_uri ("GET", uri);
@@ -247,9 +258,25 @@ do_signals_test (gboolean should_content_sniff,
 	GError *error = NULL;
 	SoupBuffer *body;
 
+	debug_printf (1, "do_signals_test(%ssniff, %spause, %saccumulate, %schunked, %sempty)\n",
+		      should_content_sniff ? "" : "!",
+		      should_pause ? "" : "!",
+		      should_accumulate ? "" : "!",
+		      chunked_encoding ? "" : "!",
+		      empty_response ? "" : "!");
+
 	if (chunked_encoding)
 		soup_uri_set_query (uri, "chunked=yes");
 
+	if (empty_response) {
+		if (uri->query) {
+			char *tmp = uri->query;
+			uri->query = g_strdup_printf("%s&empty_response=yes", tmp);
+			g_free (tmp);
+		} else
+			soup_uri_set_query (uri, "empty_response=yes");
+	}
+
 	soup_message_set_uri (msg, uri);
 
 	soup_message_body_set_accumulate (msg->response_body, should_accumulate);
@@ -275,9 +302,14 @@ do_signals_test (gboolean should_content_sniff,
 		errors++;
 	}
 
-	g_file_get_contents ("resources/mbox",
-			     &contents, &length,
-			     &error);
+	if (empty_response) {
+		contents = g_strdup ("");
+		length = 0;
+	} else {
+		g_file_get_contents ("resources/mbox",
+				     &contents, &length,
+				     &error);
+	}
 
 	if (error) {
 		g_error ("%s", error->message);
@@ -285,11 +317,11 @@ do_signals_test (gboolean should_content_sniff,
 		exit (1);
 	}
 
-	if (!should_accumulate) {
+	if (!should_accumulate && chunk_data) {
 		body = soup_message_body_flatten (chunk_data);
 		soup_message_body_free (chunk_data);
 		chunk_data = NULL;
-	} else
+	} else if (msg->response_body)
 		body = soup_message_body_flatten (msg->response_body);
 
 	if (body->length != length) {
@@ -302,7 +334,6 @@ do_signals_test (gboolean should_content_sniff,
 		errors++;
 	}
 
-	g_free (contents);
 	soup_buffer_free (body);
 
 	soup_uri_free (uri);
@@ -329,6 +360,8 @@ test_sniffing (const char *path, const char *expected_type)
 	SoupMessage *msg = soup_message_new_from_uri ("GET", uri);
 	GMainLoop *loop = g_main_loop_new (NULL, TRUE);
 
+	debug_printf (1, "test_sniffing(\"%s\", \"%s\")\n", path, expected_type);
+
 	g_object_connect (msg,
 			  "signal::content_sniffed", sniffing_content_sniffed, expected_type,
 			  NULL);
@@ -357,18 +390,25 @@ main (int argc, char **argv)
 	base_uri = soup_uri_new ("http://127.0.0.1/";);
 	soup_uri_set_port (base_uri, soup_server_get_port (server));
 
-	session = soup_session_async_new ();
+	session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC, NULL);
 
 	/* No sniffer, no content_sniffed should be emitted */
-	do_signals_test (FALSE, FALSE, FALSE, FALSE);
-	do_signals_test (FALSE, FALSE, FALSE, TRUE);
-	do_signals_test (FALSE, FALSE, TRUE, FALSE);
-	do_signals_test (FALSE, FALSE, TRUE, TRUE);
+	do_signals_test (FALSE, FALSE, FALSE, FALSE, FALSE);
+	do_signals_test (FALSE, FALSE, FALSE, TRUE, FALSE);
+	do_signals_test (FALSE, FALSE, TRUE, FALSE, FALSE);
+	do_signals_test (FALSE, FALSE, TRUE, TRUE, FALSE);
+
+	do_signals_test (FALSE, TRUE, TRUE, FALSE, FALSE);
+	do_signals_test (FALSE, TRUE, TRUE, TRUE, FALSE);
+	do_signals_test (FALSE, TRUE, FALSE, FALSE, FALSE);
+	do_signals_test (FALSE, TRUE, FALSE, TRUE, FALSE);
+
+	/* Tests that the signals are correctly emitted for empty
+	 * responses; see
+	 * http://bugzilla.gnome.org/show_bug.cgi?id=587907 */
 
-	do_signals_test (FALSE, TRUE, TRUE, FALSE);
-	do_signals_test (FALSE, TRUE, TRUE, TRUE);
-	do_signals_test (FALSE, TRUE, FALSE, FALSE);
-	do_signals_test (FALSE, TRUE, FALSE, TRUE);
+	do_signals_test (FALSE, TRUE, TRUE, FALSE, TRUE);
+	do_signals_test (FALSE, TRUE, TRUE, TRUE, TRUE);
 
 	sniffer = soup_content_sniffer_new ();
 	soup_session_add_feature (session, (SoupSessionFeature*)sniffer);
@@ -376,15 +416,19 @@ main (int argc, char **argv)
 	/* Now, with a sniffer, content_sniffed must be emitted after
 	 * got-headers, and before got-chunk.
 	 */
-	do_signals_test (TRUE, FALSE, FALSE, FALSE);
-	do_signals_test (TRUE, FALSE, FALSE, TRUE);
-	do_signals_test (TRUE, FALSE, TRUE, FALSE);
-	do_signals_test (TRUE, FALSE, TRUE, TRUE);
-
-	do_signals_test (TRUE, TRUE, TRUE, FALSE);
-	do_signals_test (TRUE, TRUE, TRUE, TRUE);
-	do_signals_test (TRUE, TRUE, FALSE, FALSE);
-	do_signals_test (TRUE, TRUE, FALSE, TRUE);
+	do_signals_test (TRUE, FALSE, FALSE, FALSE, FALSE);
+	do_signals_test (TRUE, FALSE, FALSE, TRUE, FALSE);
+	do_signals_test (TRUE, FALSE, TRUE, FALSE, FALSE);
+	do_signals_test (TRUE, FALSE, TRUE, TRUE, FALSE);
+
+	do_signals_test (TRUE, TRUE, TRUE, FALSE, FALSE);
+	do_signals_test (TRUE, TRUE, TRUE, TRUE, FALSE);
+	do_signals_test (TRUE, TRUE, FALSE, FALSE, FALSE);
+	do_signals_test (TRUE, TRUE, FALSE, TRUE, FALSE);
+
+	/* Empty response tests */
+	do_signals_test (TRUE, TRUE, TRUE, FALSE, TRUE);
+	do_signals_test (TRUE, TRUE, TRUE, TRUE, TRUE);
 
 	/* Test the text_or_binary sniffing path */
 



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