soup-message-io: use SoupMessageQueueItems and add SoupMessageCompletionFn
authorDan Winship <danw@gnome.org>
Sat, 29 May 2010 13:24:51 +0000 (15:24 +0200)
committerDan Winship <danw@gnome.org>
Wed, 9 Jun 2010 15:23:00 +0000 (11:23 -0400)
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.

14 files changed:
libsoup/soup-connection.c
libsoup/soup-connection.h
libsoup/soup-message-client-io.c
libsoup/soup-message-io.c
libsoup/soup-message-private.h
libsoup/soup-message-queue.c
libsoup/soup-message-queue.h
libsoup/soup-message-server-io.c
libsoup/soup-server.c
libsoup/soup-session-async.c
libsoup/soup-session-private.h
libsoup/soup-session-sync.c
libsoup/soup-session.c
libsoup/soup-types.h

index 58614ac..7174e21 100644 (file)
@@ -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);
 }
index 558a465..629676b 100644 (file)
@@ -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
 
index 0c091e6..ef97c99 100644 (file)
 #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);
 }
index 324b147..8314f96 100644 (file)
@@ -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;
index cd8a94e..eba92df 100644 (file)
@@ -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,
index 61bc5ca..6860524 100644 (file)
@@ -29,7 +29,7 @@
  * "removed" ones when walking the queue.
  **/
 
-struct SoupMessageQueue {
+struct _SoupMessageQueue {
        SoupSession *session;
 
        GMutex *mutex;
index d4376a7..9588e17 100644 (file)
@@ -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;
index bc8a1c1..573fcaf 100644 (file)
@@ -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);
 }
index 788bb59..e60ede9 100644 (file)
@@ -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
index 6df4ca4..57c0581 100644 (file)
@@ -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);
index 72b79c5..0a8f888 100644 (file)
@@ -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
 
index dd3cc82..1743f25 100644 (file)
@@ -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);
index 55bcf09..0022c99 100644 (file)
@@ -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);
index def6c85..5d7cb3c 100644 (file)
@@ -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