[libsoup] soup-message-io: use SoupMessageQueueItems and add SoupMessageCompletionFn



commit b5cc3e113a9f29f0a77cf8f634c233323844d9f7
Author: Dan Winship <danw gnome org>
Date:   Sat May 29 15:24:51 2010 +0200

    soup-message-io: use SoupMessageQueueItems and add SoupMessageCompletionFn
    
    push SoupMessageQueueItem down into soup-message-io, and end the I/O
    process by calling a completion callback rather than emitting the
    SoupMessage signals directly, which gives the session greater control.

 libsoup/soup-connection.c        |   73 +++++++++++++++++++--------------
 libsoup/soup-connection.h        |   12 ++++--
 libsoup/soup-message-client-io.c |   18 +++++---
 libsoup/soup-message-io.c        |   84 +++++++++++++++++++------------------
 libsoup/soup-message-private.h   |   44 ++++++++++++--------
 libsoup/soup-message-queue.c     |    2 +-
 libsoup/soup-message-queue.h     |   12 ++---
 libsoup/soup-message-server-io.c |   10 +++-
 libsoup/soup-server.c            |    8 ++-
 libsoup/soup-session-async.c     |   43 +++++++++++++------
 libsoup/soup-session-private.h   |    6 +-
 libsoup/soup-session-sync.c      |   31 +++++++++++---
 libsoup/soup-session.c           |   58 ++------------------------
 libsoup/soup-types.h             |    5 ++
 14 files changed, 214 insertions(+), 192 deletions(-)
---
diff --git a/libsoup/soup-connection.c b/libsoup/soup-connection.c
index 58614ac..7174e21 100644
--- a/libsoup/soup-connection.c
+++ b/libsoup/soup-connection.c
@@ -22,6 +22,7 @@
 #include "soup-marshal.h"
 #include "soup-message.h"
 #include "soup-message-private.h"
+#include "soup-message-queue.h"
 #include "soup-misc.h"
 #include "soup-socket.h"
 #include "soup-ssl.h"
@@ -38,7 +39,7 @@ typedef struct {
 
 	GMainContext      *async_context;
 
-	SoupMessage *cur_req;
+	SoupMessageQueueItem *cur_item;
 	SoupConnectionState state;
 	time_t       unused_timeout;
 	guint        io_timeout, idle_timeout;
@@ -78,7 +79,7 @@ static void get_property (GObject *object, guint prop_id,
 			  GValue *value, GParamSpec *pspec);
 
 static void stop_idle_timer (SoupConnectionPrivate *priv);
-static void clear_current_request (SoupConnection *conn);
+static void clear_current_item (SoupConnection *conn);
 
 /* Number of seconds after which we close a connection that hasn't yet
  * been used.
@@ -116,12 +117,12 @@ dispose (GObject *object)
 	SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (conn);
 
 	stop_idle_timer (priv);
-	/* Make sure clear_current_request doesn't re-establish the timeout */
+	/* Make sure clear_current_item doesn't re-establish the timeout */
 	priv->idle_timeout = 0;
 
-	if (priv->cur_req) {
-		g_warning ("Disposing connection with cur_req set");
-		clear_current_request (conn);
+	if (priv->cur_item) {
+		g_warning ("Disposing connection with cur_item set");
+		clear_current_item (conn);
 	}
 	if (priv->socket) {
 		g_warning ("Disposing connection while connected");
@@ -319,7 +320,10 @@ get_property (GObject *object, guint prop_id,
 		g_value_set_enum (value, priv->state);
 		break;
 	case PROP_MESSAGE:
-		g_value_set_object (value, priv->cur_req);
+		if (priv->cur_item)
+			g_value_set_object (value, priv->cur_item->msg);
+		else
+			g_value_set_object (value, NULL);
 		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -357,29 +361,29 @@ stop_idle_timer (SoupConnectionPrivate *priv)
 }
 
 static void
-set_current_request (SoupConnection *conn, SoupMessage *req)
+set_current_item (SoupConnection *conn, SoupMessageQueueItem *item)
 {
 	SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (conn);
 
-	g_return_if_fail (priv->cur_req == NULL);
+	g_return_if_fail (priv->cur_item == NULL);
 
 	g_object_freeze_notify (G_OBJECT (conn));
 
 	stop_idle_timer (priv);
 
-	soup_message_set_io_status (req, SOUP_MESSAGE_IO_STATUS_RUNNING);
-	priv->cur_req = req;
+	soup_message_set_io_status (item->msg, SOUP_MESSAGE_IO_STATUS_RUNNING);
+	priv->cur_item = item;
 	g_object_notify (G_OBJECT (conn), "message");
 
 	if (priv->state == SOUP_CONNECTION_IDLE ||
-	    req->method != SOUP_METHOD_CONNECT)
+	    item->msg->method != SOUP_METHOD_CONNECT)
 		soup_connection_set_state (conn, SOUP_CONNECTION_IN_USE);
 
 	g_object_thaw_notify (G_OBJECT (conn));
 }
 
 static void
-clear_current_request (SoupConnection *conn)
+clear_current_item (SoupConnection *conn)
 {
 	SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (conn);
 
@@ -387,13 +391,22 @@ clear_current_request (SoupConnection *conn)
 
 	priv->unused_timeout = 0;
 	start_idle_timer (conn);
-	if (priv->cur_req) {
-		SoupMessage *cur_req = priv->cur_req;
 
-		priv->cur_req = NULL;
+	if (priv->cur_item) {
+		SoupMessageQueueItem *item;
+
+		item = priv->cur_item;
+		priv->cur_item = NULL;
 		g_object_notify (G_OBJECT (conn), "message");
 
-		if (!soup_message_is_keepalive (cur_req))
+		if (item->msg->method == SOUP_METHOD_CONNECT &&
+		    SOUP_STATUS_IS_SUCCESSFUL (item->msg->status_code)) {
+			/* We're now effectively no longer proxying */
+			soup_uri_free (priv->proxy_uri);
+			priv->proxy_uri = NULL;
+		}
+
+		if (!soup_message_is_keepalive (item->msg))
 			soup_connection_disconnect (conn);
 	}
 
@@ -651,15 +664,18 @@ soup_connection_set_state (SoupConnection *conn, SoupConnectionState state)
 	g_return_if_fail (state >= SOUP_CONNECTION_NEW &&
 			  state <= SOUP_CONNECTION_DISCONNECTED);
 
+	g_object_freeze_notify (G_OBJECT (conn));
+
 	priv = SOUP_CONNECTION_GET_PRIVATE (conn);
 	old_state = priv->state;
 	priv->state = state;
 	if ((state == SOUP_CONNECTION_IDLE ||
 	     state == SOUP_CONNECTION_DISCONNECTED) &&
 	    old_state == SOUP_CONNECTION_IN_USE)
-		clear_current_request (conn);
+		clear_current_item (conn);
 
 	g_object_notify (G_OBJECT (conn), "state");
+	g_object_thaw_notify (G_OBJECT (conn));
 }
 
 gboolean
@@ -670,25 +686,20 @@ soup_connection_get_ever_used (SoupConnection *conn)
 	return SOUP_CONNECTION_GET_PRIVATE (conn)->unused_timeout == 0;
 }
 
-/**
- * soup_connection_send_request:
- * @conn: a #SoupConnection
- * @req: a #SoupMessage
- *
- * Sends @req on @conn. This is a low-level function, intended for use
- * by #SoupSession.
- **/
 void
-soup_connection_send_request (SoupConnection *conn, SoupMessage *req)
+soup_connection_send_request (SoupConnection          *conn,
+			      SoupMessageQueueItem    *item,
+			      SoupMessageCompletionFn  completion_cb,
+			      gpointer                 user_data)
 {
 	SoupConnectionPrivate *priv;
 
 	g_return_if_fail (SOUP_IS_CONNECTION (conn));
-	g_return_if_fail (SOUP_IS_MESSAGE (req));
+	g_return_if_fail (item != NULL);
 	priv = SOUP_CONNECTION_GET_PRIVATE (conn);
 	g_return_if_fail (priv->state != SOUP_CONNECTION_NEW && priv->state != SOUP_CONNECTION_DISCONNECTED);
 
-	if (req != priv->cur_req)
-		set_current_request (conn, req);
-	soup_message_send_request (req, conn);
+	if (item != priv->cur_item)
+		set_current_item (conn, item);
+	soup_message_send_request (item, completion_cb, user_data);
 }
diff --git a/libsoup/soup-connection.h b/libsoup/soup-connection.h
index 558a465..629676b 100644
--- a/libsoup/soup-connection.h
+++ b/libsoup/soup-connection.h
@@ -9,6 +9,7 @@
 #include <gio/gio.h>
 
 #include "soup-types.h"
+#include "soup-message-private.h"
 #include "soup-misc.h"
 
 G_BEGIN_DECLS
@@ -20,10 +21,10 @@ G_BEGIN_DECLS
 #define SOUP_IS_CONNECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), SOUP_TYPE_CONNECTION))
 #define SOUP_CONNECTION_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), SOUP_TYPE_CONNECTION, SoupConnectionClass))
 
-typedef struct {
+struct _SoupConnection {
 	GObject parent;
 
-} SoupConnection;
+};
 
 typedef struct {
 	GObjectClass parent_class;
@@ -75,8 +76,11 @@ void                soup_connection_set_state  (SoupConnection   *conn,
 
 gboolean        soup_connection_get_ever_used  (SoupConnection   *conn);
 
-void            soup_connection_send_request   (SoupConnection   *conn,
-						SoupMessage      *req);
+void            soup_connection_send_request   (SoupConnection          *conn,
+						SoupMessageQueueItem    *item,
+						SoupMessageCompletionFn  completion_cb,
+						gpointer                 user_data);
+
 
 G_END_DECLS
 
diff --git a/libsoup/soup-message-client-io.c b/libsoup/soup-message-client-io.c
index 0c091e6..ef97c99 100644
--- a/libsoup/soup-message-client-io.c
+++ b/libsoup/soup-message-client-io.c
@@ -12,10 +12,12 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include "soup-connection.h"
 #include "soup-message-private.h"
 #include "soup-auth.h"
 #include "soup-connection.h"
 #include "soup-headers.h"
+#include "soup-message-queue.h"
 #include "soup-uri.h"
 
 static guint
@@ -77,7 +79,7 @@ get_request_headers (SoupMessage *req, GString *header,
 		     SoupEncoding *encoding, gpointer user_data)
 {
 	SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (req);
-	SoupConnection *conn = user_data;
+	SoupMessageQueueItem *item = user_data;
 	SoupURI *uri = soup_message_get_uri (req);
 	char *uri_host;
 	char *uri_string;
@@ -93,7 +95,7 @@ get_request_headers (SoupMessage *req, GString *header,
 		/* CONNECT URI is hostname:port for tunnel destination */
 		uri_string = g_strdup_printf ("%s:%d", uri_host, uri->port);
 	} else {
-		gboolean proxy = soup_connection_is_via_proxy (conn);
+		gboolean proxy = soup_connection_is_via_proxy (item->conn);
 
 		/* Proxy expects full URI to destination. Otherwise
 		 * just the path.
@@ -146,12 +148,14 @@ get_request_headers (SoupMessage *req, GString *header,
 }
 
 void
-soup_message_send_request (SoupMessage    *msg,
-			   SoupConnection *conn)
+soup_message_send_request (SoupMessageQueueItem      *item,
+			   SoupMessageCompletionFn    completion_cb,
+			   gpointer                   user_data)
 {
-	soup_message_cleanup_response (msg);
-	soup_message_io_client (msg, conn,
+	soup_message_cleanup_response (item->msg);
+	soup_message_io_client (item,
 				get_request_headers,
 				parse_response_headers,
-				conn);
+				item,
+				completion_cb, user_data);
 }
diff --git a/libsoup/soup-message-io.c b/libsoup/soup-message-io.c
index 324b147..8314f96 100644
--- a/libsoup/soup-message-io.c
+++ b/libsoup/soup-message-io.c
@@ -16,6 +16,7 @@
 #include "soup-connection.h"
 #include "soup-message.h"
 #include "soup-message-private.h"
+#include "soup-message-queue.h"
 #include "soup-misc.h"
 #include "soup-socket.h"
 #include "soup-ssl.h"
@@ -45,7 +46,7 @@ typedef enum {
 
 typedef struct {
 	SoupSocket           *sock;
-	SoupConnection       *conn;
+	SoupMessageQueueItem *item;
 	SoupMessageIOMode     mode;
 
 	SoupMessageIOState    read_state;
@@ -71,7 +72,9 @@ typedef struct {
 
 	SoupMessageGetHeadersFn   get_headers_cb;
 	SoupMessageParseHeadersFn parse_headers_cb;
-	gpointer                  user_data;
+	gpointer                  header_data;
+	SoupMessageCompletionFn   completion_cb;
+	gpointer                  completion_data;
 } SoupMessageIOData;
 	
 
@@ -100,8 +103,8 @@ soup_message_io_cleanup (SoupMessage *msg)
 
 	if (io->sock)
 		g_object_unref (io->sock);
-	if (io->conn)
-		g_object_unref (io->conn);
+	if (io->item)
+		soup_message_queue_item_unref (io->item);
 
 	g_byte_array_free (io->read_meta_buf, TRUE);
 
@@ -115,17 +118,6 @@ soup_message_io_cleanup (SoupMessage *msg)
 	g_slice_free (SoupMessageIOData, io);
 }
 
-/**
- * soup_message_io_stop:
- * @msg: a #SoupMessage
- *
- * Immediately stops I/O on msg; if the connection would be left in an
- * inconsistent state, it will be closed.
- *
- * Note: this is a low-level function that does not cause any signals
- * to be emitted on @msg; it is up to the caller to make sure that
- * @msg doesn't get "stranded".
- **/
 void
 soup_message_io_stop (SoupMessage *msg)
 {
@@ -155,12 +147,8 @@ soup_message_io_stop (SoupMessage *msg)
 
 	if (io->read_state < SOUP_MESSAGE_IO_STATE_FINISHING)
 		soup_socket_disconnect (io->sock);
-	else if (io->conn) {
-		SoupConnection *conn = io->conn;
-		io->conn = NULL;
-		soup_connection_set_state (conn, SOUP_CONNECTION_IDLE);
-		g_object_unref (conn);
-	}
+	else if (io->item && io->item->conn)
+		soup_connection_set_state (io->item->conn, SOUP_CONNECTION_IDLE);
 }
 
 #define SOUP_MESSAGE_IO_EOL            "\r\n"
@@ -169,12 +157,15 @@ soup_message_io_stop (SoupMessage *msg)
 static void
 soup_message_io_finished (SoupMessage *msg)
 {
+	SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
+	SoupMessageIOData *io = priv->io_data;
+	SoupMessageCompletionFn completion_cb = io->completion_cb;
+	gpointer completion_data = io->completion_data;
+
 	g_object_ref (msg);
 	soup_message_io_cleanup (msg);
-	if (SOUP_MESSAGE_IS_STARTING (msg))
-		soup_message_restarted (msg);
-	else
-		soup_message_finished (msg);
+	if (completion_cb)
+		completion_cb (msg, completion_data);
 	g_object_unref (msg);
 }
 
@@ -200,7 +191,7 @@ io_error (SoupSocket *sock, SoupMessage *msg, GError *error)
 	} else if (io->mode == SOUP_MESSAGE_IO_CLIENT &&
 		   io->read_state <= SOUP_MESSAGE_IO_STATE_HEADERS &&
 		   io->read_meta_buf->len == 0 &&
-		   soup_connection_get_ever_used (io->conn) &&
+		   soup_connection_get_ever_used (io->item->conn) &&
 		   !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT) &&
 		   request_is_idempotent (msg)) {
 		/* Connection got closed, but we can safely try again */
@@ -589,7 +580,7 @@ io_write (SoupSocket *sock, SoupMessage *msg)
 		if (!io->write_buf->len) {
 			io->get_headers_cb (msg, io->write_buf,
 					    &io->write_encoding,
-					    io->user_data);
+					    io->header_data);
 			if (!io->write_buf->len) {
 				soup_message_io_pause (msg);
 				return;
@@ -833,7 +824,7 @@ io_read (SoupSocket *sock, SoupMessage *msg)
 		status = io->parse_headers_cb (msg, (char *)io->read_meta_buf->data,
 					       io->read_meta_buf->len,
 					       &io->read_encoding,
-					       io->user_data);
+					       io->header_data);
 		g_byte_array_set_size (io->read_meta_buf, 0);
 
 		if (status != SOUP_STATUS_OK) {
@@ -1011,7 +1002,9 @@ static SoupMessageIOData *
 new_iostate (SoupMessage *msg, SoupSocket *sock, SoupMessageIOMode mode,
 	     SoupMessageGetHeadersFn get_headers_cb,
 	     SoupMessageParseHeadersFn parse_headers_cb,
-	     gpointer user_data)
+	     gpointer header_data,
+	     SoupMessageCompletionFn completion_cb,
+	     gpointer completion_data)
 {
 	SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
 	SoupMessageIOData *io;
@@ -1021,7 +1014,9 @@ new_iostate (SoupMessage *msg, SoupSocket *sock, SoupMessageIOMode mode,
 	io->mode = mode;
 	io->get_headers_cb   = get_headers_cb;
 	io->parse_headers_cb = parse_headers_cb;
-	io->user_data        = user_data;
+	io->header_data      = header_data;
+	io->completion_cb    = completion_cb;
+	io->completion_data  = completion_data;
 
 	io->read_meta_buf    = g_byte_array_new ();
 	io->write_buf        = g_string_new (NULL);
@@ -1043,36 +1038,43 @@ new_iostate (SoupMessage *msg, SoupSocket *sock, SoupMessageIOMode mode,
 }
 
 void
-soup_message_io_client (SoupMessage *msg, SoupConnection *conn,
+soup_message_io_client (SoupMessageQueueItem *item,
 			SoupMessageGetHeadersFn get_headers_cb,
 			SoupMessageParseHeadersFn parse_headers_cb,
-			gpointer user_data)
+			gpointer header_data,
+			SoupMessageCompletionFn completion_cb,
+			gpointer completion_data)
 {
 	SoupMessageIOData *io;
-	SoupSocket *sock = soup_connection_get_socket (conn);
+	SoupSocket *sock = soup_connection_get_socket (item->conn);
 
-	io = new_iostate (msg, sock, SOUP_MESSAGE_IO_CLIENT,
-			  get_headers_cb, parse_headers_cb, user_data);
+	io = new_iostate (item->msg, sock, SOUP_MESSAGE_IO_CLIENT,
+			  get_headers_cb, parse_headers_cb, header_data,
+			  completion_cb, completion_data);
 
-	io->conn = g_object_ref (conn);
+	io->item = item;
+	soup_message_queue_item_ref (item);
 
-	io->read_body       = msg->response_body;
-	io->write_body      = msg->request_body;
+	io->read_body       = item->msg->response_body;
+	io->write_body      = item->msg->request_body;
 
 	io->write_state     = SOUP_MESSAGE_IO_STATE_HEADERS;
-	io_write (sock, msg);
+	io_write (sock, item->msg);
 }
 
 void
 soup_message_io_server (SoupMessage *msg, SoupSocket *sock,
 			SoupMessageGetHeadersFn get_headers_cb,
 			SoupMessageParseHeadersFn parse_headers_cb,
-			gpointer user_data)
+			gpointer header_data,
+			SoupMessageCompletionFn completion_cb,
+			gpointer completion_data)
 {
 	SoupMessageIOData *io;
 
 	io = new_iostate (msg, sock, SOUP_MESSAGE_IO_SERVER,
-			  get_headers_cb, parse_headers_cb, user_data);
+			  get_headers_cb, parse_headers_cb, header_data,
+			  completion_cb, completion_data);
 
 	io->read_body       = msg->request_body;
 	io->write_body      = msg->response_body;
diff --git a/libsoup/soup-message-private.h b/libsoup/soup-message-private.h
index cd8a94e..eba92df 100644
--- a/libsoup/soup-message-private.h
+++ b/libsoup/soup-message-private.h
@@ -8,7 +8,6 @@
 
 #include "soup-message.h"
 #include "soup-auth.h"
-#include "soup-connection.h"
 #include "soup-content-sniffer.h"
 
 typedef enum {
@@ -46,7 +45,7 @@ typedef struct {
 } SoupMessagePrivate;
 #define SOUP_MESSAGE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUP_TYPE_MESSAGE, SoupMessagePrivate))
 
-#define SOUP_MESSAGE_IS_STARTING(msg) (SOUP_MESSAGE_GET_PRIVATE (msg)->io_status == SOUP_MESSAGE_IO_STATUS_QUEUED)
+#define SOUP_MESSAGE_IS_STARTING(msg) (SOUP_MESSAGE_GET_PRIVATE (msg)->io_status == SOUP_MESSAGE_IO_STATUS_QUEUED && !SOUP_STATUS_IS_TRANSPORT_ERROR ((msg)->status_code))
 
 void             soup_message_cleanup_response (SoupMessage      *req);
 
@@ -60,23 +59,32 @@ typedef guint    (*SoupMessageParseHeadersFn)(SoupMessage      *msg,
 					      guint             header_len,
 					      SoupEncoding     *encoding,
 					      gpointer          user_data);
+typedef void     (*SoupMessageCompletionFn)  (SoupMessage      *msg,
+					      gpointer          user_data);
+
 
-void           soup_message_send_request        (SoupMessage       *req,
-						 SoupConnection    *conn);
-void           soup_message_read_request        (SoupMessage       *req,
-						 SoupSocket        *sock);
-
-void soup_message_io_client  (SoupMessage               *msg,
-			      SoupConnection            *conn,
-			      SoupMessageGetHeadersFn    get_headers_cb,
-			      SoupMessageParseHeadersFn  parse_headers_cb,
-			      gpointer                   user_data);
-void soup_message_io_server  (SoupMessage               *msg,
-			      SoupSocket                *sock,
-			      SoupMessageGetHeadersFn    get_headers_cb,
-			      SoupMessageParseHeadersFn  parse_headers_cb,
-			      gpointer                   user_data);
-void soup_message_io_cleanup (SoupMessage               *msg);
+void soup_message_send_request (SoupMessageQueueItem      *item,
+				SoupMessageCompletionFn    completion_cb,
+				gpointer                   user_data);
+void soup_message_read_request (SoupMessage               *req,
+				SoupSocket                *sock,
+				SoupMessageCompletionFn    completion_cb,
+				gpointer                   user_data);
+
+void soup_message_io_client    (SoupMessageQueueItem      *item,
+				SoupMessageGetHeadersFn    get_headers_cb,
+				SoupMessageParseHeadersFn  parse_headers_cb,
+				gpointer                   headers_data,
+				SoupMessageCompletionFn    completion_cb,
+				gpointer                   user_data);
+void soup_message_io_server    (SoupMessage               *msg,
+				SoupSocket                *sock,
+				SoupMessageGetHeadersFn    get_headers_cb,
+				SoupMessageParseHeadersFn  parse_headers_cb,
+				gpointer                   headers_data,
+				SoupMessageCompletionFn    completion_cb,
+				gpointer                   user_data);
+void soup_message_io_cleanup   (SoupMessage               *msg);
 
 /* Auth handling */
 void           soup_message_set_auth       (SoupMessage *msg,
diff --git a/libsoup/soup-message-queue.c b/libsoup/soup-message-queue.c
index 61bc5ca..6860524 100644
--- a/libsoup/soup-message-queue.c
+++ b/libsoup/soup-message-queue.c
@@ -29,7 +29,7 @@
  * "removed" ones when walking the queue.
  **/
 
-struct SoupMessageQueue {
+struct _SoupMessageQueue {
 	SoupSession *session;
 
 	GMutex *mutex;
diff --git a/libsoup/soup-message-queue.h b/libsoup/soup-message-queue.h
index d4376a7..9588e17 100644
--- a/libsoup/soup-message-queue.h
+++ b/libsoup/soup-message-queue.h
@@ -9,16 +9,14 @@
 
 #include <glib.h>
 #include <gio/gio.h>
-#include <libsoup/soup-connection.h>
-#include <libsoup/soup-message.h>
-#include <libsoup/soup-session.h>
 
-G_BEGIN_DECLS
+#include "soup-connection.h"
+#include "soup-message.h"
+#include "soup-session.h"
 
-typedef struct SoupMessageQueue SoupMessageQueue; 
-typedef struct SoupMessageQueueItem SoupMessageQueueItem;
+G_BEGIN_DECLS
 
-struct SoupMessageQueueItem {
+struct _SoupMessageQueueItem {
 	/*< public >*/
 	SoupSession *session;
 	SoupMessageQueue *queue;
diff --git a/libsoup/soup-message-server-io.c b/libsoup/soup-message-server-io.c
index bc8a1c1..573fcaf 100644
--- a/libsoup/soup-message-server-io.c
+++ b/libsoup/soup-message-server-io.c
@@ -235,10 +235,14 @@ get_response_headers (SoupMessage *msg, GString *headers,
 }
 
 void
-soup_message_read_request (SoupMessage *req, SoupSocket *sock)
+soup_message_read_request (SoupMessage               *msg,
+			   SoupSocket                *sock,
+			   SoupMessageCompletionFn    completion_cb,
+			   gpointer                   user_data)
 {
-	soup_message_io_server (req, sock,
+	soup_message_io_server (msg, sock,
 				get_response_headers,
 				parse_request_headers,
-				sock);
+				sock,
+				completion_cb, user_data);
 }
diff --git a/libsoup/soup-server.c b/libsoup/soup-server.c
index 788bb59..e60ede9 100644
--- a/libsoup/soup-server.c
+++ b/libsoup/soup-server.c
@@ -709,11 +709,13 @@ soup_client_context_unref (SoupClientContext *client)
 }
 
 static void
-request_finished (SoupMessage *msg, SoupClientContext *client)
+request_finished (SoupMessage *msg, gpointer user_data)
 {
+	SoupClientContext *client = user_data;
 	SoupServer *server = client->server;
 	SoupSocket *sock = client->sock;
 
+	soup_message_finished (msg);
 	g_signal_emit (server,
 		       msg->status_code == SOUP_STATUS_IO_ERROR ?
 		       signals[REQUEST_ABORTED] : signals[REQUEST_FINISHED],
@@ -868,13 +870,13 @@ start_request (SoupServer *server, SoupClientContext *client)
 
 	g_signal_connect (msg, "got_headers", G_CALLBACK (got_headers), client);
 	g_signal_connect (msg, "got_body", G_CALLBACK (call_handler), client);
-	g_signal_connect (msg, "finished", G_CALLBACK (request_finished), client);
 
 	g_signal_emit (server, signals[REQUEST_STARTED], 0,
 		       msg, client);
 
 	g_object_ref (client->sock);
-	soup_message_read_request (msg, client->sock);
+	soup_message_read_request (msg, client->sock,
+				   request_finished, client);
 }
 
 static void
diff --git a/libsoup/soup-session-async.c b/libsoup/soup-session-async.c
index 6df4ca4..57c0581 100644
--- a/libsoup/soup-session-async.c
+++ b/libsoup/soup-session-async.c
@@ -16,6 +16,7 @@
 #include "soup-session-private.h"
 #include "soup-address.h"
 #include "soup-message-private.h"
+#include "soup-message-queue.h"
 #include "soup-misc.h"
 #include "soup-password-manager.h"
 #include "soup-proxy-uri-resolver.h"
@@ -211,6 +212,24 @@ connection_closed (SoupConnection *conn, gpointer session)
 }
 
 static void
+tunnel_message_completed (SoupMessage *msg, gpointer user_data)
+{
+	SoupMessageQueueItem *item = user_data;
+
+	if (SOUP_MESSAGE_IS_STARTING (msg)) {
+		soup_message_restarted (msg);
+		if (soup_connection_get_state (item->conn) != SOUP_CONNECTION_DISCONNECTED) {
+			soup_session_send_queue_item (item->session, item, item->conn, tunnel_message_completed);
+			return;
+		}
+
+		soup_message_set_status (msg, SOUP_STATUS_TRY_AGAIN);
+	}
+
+	soup_message_finished (msg);
+}
+
+static void
 tunnel_connected (SoupMessage *msg, gpointer user_data)
 {
 	SoupMessageQueueItem *item = user_data;
@@ -238,15 +257,6 @@ done:
 }
 
 static void
-tunnel_connect_restarted (SoupMessage *msg, gpointer user_data)
-{
-	SoupMessageQueueItem *item = user_data;
-
-	if (SOUP_MESSAGE_IS_STARTING (msg))
-		soup_session_send_queue_item (item->session, item, item->conn);
-}
-
-static void
 got_connection (SoupConnection *conn, guint status, gpointer user_data)
 {
 	SoupSession *session = user_data;
@@ -271,9 +281,7 @@ got_connection (SoupConnection *conn, guint status, gpointer user_data)
 		g_signal_emit_by_name (session, "tunneling", conn);
 		g_signal_connect (item->msg, "finished",
 				  G_CALLBACK (tunnel_connected), item);
-		g_signal_connect (item->msg, "restarted",
-				  G_CALLBACK (tunnel_connect_restarted), item);
-		soup_session_send_queue_item (session, item, conn);
+		soup_session_send_queue_item (session, item, conn, tunnel_message_completed);
 		return;
 	}
 
@@ -296,6 +304,15 @@ got_connection (SoupConnection *conn, guint status, gpointer user_data)
 }
 
 static void
+message_completed (SoupMessage *msg, gpointer user_data)
+{
+	if (SOUP_MESSAGE_IS_STARTING (msg))
+		soup_message_restarted (msg);
+	else
+		soup_message_finished (msg);
+}
+
+static void
 run_queue (SoupSessionAsync *sa)
 {
 	SoupSession *session = SOUP_SESSION (sa);
@@ -340,7 +357,7 @@ run_queue (SoupSessionAsync *sa)
 						       got_connection,
 						       g_object_ref (session));
 		} else
-			soup_session_send_queue_item (session, item, conn);
+			soup_session_send_queue_item (session, item, conn, message_completed);
 	}
 	if (item)
 		soup_message_queue_item_unref (item);
diff --git a/libsoup/soup-session-private.h b/libsoup/soup-session-private.h
index 72b79c5..0a8f888 100644
--- a/libsoup/soup-session-private.h
+++ b/libsoup/soup-session-private.h
@@ -7,8 +7,7 @@
 #define SOUP_SESSION_PRIVATE_H 1
 
 #include "soup-session.h"
-#include "soup-connection.h"
-#include "soup-message-queue.h"
+#include "soup-message-private.h"
 #include "soup-proxy-uri-resolver.h"
 
 G_BEGIN_DECLS
@@ -29,7 +28,8 @@ void                  soup_session_connection_failed    (SoupSession          *s
 
 void                  soup_session_send_queue_item      (SoupSession          *session,
 							 SoupMessageQueueItem *item,
-							 SoupConnection       *conn);
+							 SoupConnection       *conn,
+							 SoupMessageCompletionFn completion_cb);
 
 G_END_DECLS
 
diff --git a/libsoup/soup-session-sync.c b/libsoup/soup-session-sync.c
index dd3cc82..1743f25 100644
--- a/libsoup/soup-session-sync.c
+++ b/libsoup/soup-session-sync.c
@@ -16,6 +16,7 @@
 #include "soup-session-private.h"
 #include "soup-address.h"
 #include "soup-message-private.h"
+#include "soup-message-queue.h"
 #include "soup-misc.h"
 #include "soup-password-manager.h"
 #include "soup-proxy-uri-resolver.h"
@@ -146,11 +147,22 @@ tunnel_connect (SoupSession *session, SoupConnection *conn,
 
 	g_signal_emit_by_name (session, "tunneling", conn);
 	item = soup_session_make_connect_message (session, tunnel_addr);
-	do
-		soup_session_send_queue_item (session, item, conn);
-	while (SOUP_MESSAGE_IS_STARTING (item->msg));
-
-	status = item->msg->status_code;
+	do {
+		soup_session_send_queue_item (session, item, conn, NULL);
+		if (SOUP_MESSAGE_IS_STARTING (item->msg))
+			soup_message_restarted (item->msg) ;
+		else
+			soup_message_finished (item->msg);
+	} while (SOUP_MESSAGE_IS_STARTING (item->msg) &&
+		 soup_connection_get_state (conn) != SOUP_CONNECTION_DISCONNECTED);
+
+	/* If the message was requeued but its connection was closed,
+	 * return TRY_AGAIN to our caller.
+	 */
+	if (SOUP_MESSAGE_IS_STARTING (item->msg))
+		status = SOUP_STATUS_TRY_AGAIN;
+	else
+		status = item->msg->status_code;
 	soup_message_queue_item_unref (item);
 
 	if (SOUP_STATUS_IS_SUCCESSFUL (status)) {
@@ -226,7 +238,8 @@ wait_for_connection (SoupMessageQueueItem *item)
 				status = tunnel_connect (session, conn, tunnel_addr);
 				if (!SOUP_STATUS_IS_SUCCESSFUL (status)) {
 					conn = NULL;
-					goto try_again;
+					if (status == SOUP_STATUS_TRY_AGAIN)
+						goto try_again;
 				}
                         }
 		}
@@ -264,7 +277,11 @@ process_queue_item (SoupMessageQueueItem *item)
 		if (!conn)
 			break;
 
-		soup_session_send_queue_item (item->session, item, conn);
+		soup_session_send_queue_item (item->session, item, conn, NULL);
+		if (SOUP_MESSAGE_IS_STARTING (item->msg))
+			soup_message_restarted (item->msg);
+		else
+			soup_message_finished (item->msg);
 		g_cond_broadcast (priv->cond);
 	} while (soup_message_get_io_status (item->msg) !=
 		 SOUP_MESSAGE_IO_STATUS_FINISHED);
diff --git a/libsoup/soup-session.c b/libsoup/soup-session.c
index 55bcf09..0022c99 100644
--- a/libsoup/soup-session.c
+++ b/libsoup/soup-session.c
@@ -1174,7 +1174,8 @@ redirect_handler (SoupMessage *msg, gpointer user_data)
 void
 soup_session_send_queue_item (SoupSession *session,
 			      SoupMessageQueueItem *item,
-			      SoupConnection *conn)
+			      SoupConnection *conn,
+			      SoupMessageCompletionFn completion_cb)
 {
 	SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
 
@@ -1201,7 +1202,7 @@ soup_session_send_queue_item (SoupSession *session,
 
 	g_signal_emit (session, signals[REQUEST_STARTED], 0,
 		       item->msg, soup_connection_get_socket (conn));
-	soup_connection_send_request (conn, item->msg);
+	soup_connection_send_request (conn, item, completion_cb, item);
 }
 
 gboolean
@@ -1296,51 +1297,6 @@ soup_session_connection_failed (SoupSession *session,
 	g_object_unref (session);
 }
 
-static void
-tunnel_connected (SoupMessage *msg, gpointer user_data)
-{
-	SoupSession *session = user_data;
-
-	if (SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
-		SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
-		SoupMessageQueueItem *item =
-			soup_message_queue_lookup (priv->queue, msg);
-
-		/* Clear the connection's proxy_uri, since it is now
-		 * (effectively) directly connected.
-		 */
-		g_object_set (item->conn,
-			      SOUP_CONNECTION_PROXY_URI, NULL,
-			      NULL);
-		soup_message_queue_item_unref (item);
-	}
-}
-
-static void
-tunnel_connect_restarted (SoupMessage *msg, gpointer session)
-{
-	SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
-	SoupMessageQueueItem *item;
-
-	if (msg->status_code != SOUP_STATUS_PROXY_AUTHENTICATION_REQUIRED)
-		return;
-
-	item = soup_message_queue_lookup (priv->queue, msg);
-	if (!item)
-		return;
-	if (soup_connection_get_state (item->conn) == SOUP_CONNECTION_DISCONNECTED) {
-		/* We got a 407, and the session provided auth and
-		 * restarted the message, but the proxy closed the
-		 * connection, so we need to create a new one. The
-		 * easiest way to do this is to just give up on the
-		 * current msg and conn, and re-run the queue.
-		 */
-		soup_session_cancel_message (session, msg,
-					     SOUP_STATUS_TRY_AGAIN);
-	}
-	soup_message_queue_item_unref (item);
-}
-
 SoupMessageQueueItem *
 soup_session_make_connect_message (SoupSession *session,
 				   SoupAddress *server_addr)
@@ -1361,14 +1317,8 @@ soup_session_make_connect_message (SoupSession *session,
 
 	/* Call the base implementation of soup_session_queue_message
 	 * directly, to add msg to the SoupMessageQueue and cause all
-	 * the right signals to be emitted. We can't use
-	 * queue_message's callback arg in this case because that's
-	 * actually implemented by the subclasses.
+	 * the right signals to be emitted.
 	 */
-	g_signal_connect (msg, "finished",
-			  G_CALLBACK (tunnel_connected), session);
-	g_signal_connect (msg, "restarted",
-			  G_CALLBACK (tunnel_connect_restarted), session);
 	queue_message (session, msg, NULL, NULL);
 	item = soup_message_queue_lookup (priv->queue, msg);
 	g_object_unref (msg);
diff --git a/libsoup/soup-types.h b/libsoup/soup-types.h
index def6c85..5d7cb3c 100644
--- a/libsoup/soup-types.h
+++ b/libsoup/soup-types.h
@@ -28,6 +28,11 @@ typedef struct _SoupSessionSync       SoupSessionSync;
 typedef struct _SoupSocket            SoupSocket;
 typedef struct _SoupURI               SoupURI;
 
+/*< private >*/
+typedef struct _SoupConnection        SoupConnection;
+typedef struct _SoupMessageQueue      SoupMessageQueue;
+typedef struct _SoupMessageQueueItem  SoupMessageQueueItem;
+
 G_END_DECLS
 
 #endif



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