summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Winship <danw@src.gnome.org>2003-12-19 20:54:38 +0000
committerDan Winship <danw@src.gnome.org>2003-12-19 20:54:38 +0000
commite81e61c7612793a1fa20812c2a329726dd29a2c8 (patch)
treec7954ffdcff304ad30716a0db6a0fda5dd7838d4
parent654248bcf1cf2fc71d7df3e21cb7c551964b8a08 (diff)
downloadlibsoup-e81e61c7612793a1fa20812c2a329726dd29a2c8.tar.gz
New. An interface for objects that want to act on every message passing
* libsoup/soup-message-filter.c: New. An interface for objects that want to act on every message passing through a session. (Initially being used for authentication, but could also be used for cache handling, cookie management, etc.) * libsoup/soup-connection.c (class_init, etc): Add a message filter property. (send_request): If the connection has a message filter set, run it on the message before sending it. (soup_connection_connect_async, etc): When setting up a tunnel, if we get back a 407 and the session tries to requeue the message, either re-send it, or return SOUP_STATUS_TRY_AGAIN (depending on whether or not the proxy closed the connection). (soup_connection_connect_sync): Likewise (send_request, request_done): Ref/unref the connection * libsoup/soup-session.c (soup_session_get_type): Implement the SoupMessageFilter interface. (soup_session_get_connection): Use the session as the connection's message filter (soup_session_add_filter, soup_session_remove_filter): Add/remove filters from the session (setup_message): do auth handling, and call each of the session's filters' setup_message methods as well. (soup_session_send_message_via): No longer needed. (connect_result): Handle SOUP_STATUS_TRY_AGAIN. * libsoup/soup-session-async.c (run_queue): Use soup_connection_send_request, since soup_session_send_message_via is gone now. * libsoup/soup-session-sync.c (send_message): Likewise * libsoup/soup-message.c (soup_message_is_keepalive): A successful response to a CONNECT is always keepalive, even if it's HTTP/1.0 with no Connection header. * libsoup/soup-status.h: add SOUP_STATUS_TRY_AGAIN * libsoup/soup-types.h: Add SoupMessageFilter, and macros for gobject interface types. * tests/get.c (main): Add a -p flag to specify a proxy * tests/simple-proxy.c: Fix #includes
-rw-r--r--ChangeLog48
-rw-r--r--libsoup/Makefile.am2
-rw-r--r--libsoup/soup-connection.c105
-rw-r--r--libsoup/soup-connection.h1
-rw-r--r--libsoup/soup-message-filter.c30
-rw-r--r--libsoup/soup-message-filter.h30
-rw-r--r--libsoup/soup-message.c4
-rw-r--r--libsoup/soup-session-async.c2
-rw-r--r--libsoup/soup-session-sync.c2
-rw-r--r--libsoup/soup-session.c112
-rw-r--r--libsoup/soup-session.h9
-rw-r--r--libsoup/soup-status.c1
-rw-r--r--libsoup/soup-status.h1
-rw-r--r--libsoup/soup-types.h69
-rw-r--r--tests/get.c13
-rw-r--r--tests/simple-proxy.c2
16 files changed, 389 insertions, 42 deletions
diff --git a/ChangeLog b/ChangeLog
index 594aced8..9e919868 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,51 @@
+2003-12-19 Dan Winship <danw@ximian.com>
+
+ * libsoup/soup-message-filter.c: New. An interface for objects
+ that want to act on every message passing through a session.
+ (Initially being used for authentication, but could also be used
+ for cache handling, cookie management, etc.)
+
+ * libsoup/soup-connection.c (class_init, etc): Add a message
+ filter property.
+ (send_request): If the connection has a message filter set, run
+ it on the message before sending it.
+ (soup_connection_connect_async, etc): When setting up a tunnel, if
+ we get back a 407 and the session tries to requeue the message,
+ either re-send it, or return SOUP_STATUS_TRY_AGAIN (depending on
+ whether or not the proxy closed the connection).
+ (soup_connection_connect_sync): Likewise
+ (send_request, request_done): Ref/unref the connection
+
+ * libsoup/soup-session.c (soup_session_get_type): Implement the
+ SoupMessageFilter interface.
+ (soup_session_get_connection): Use the session as the connection's
+ message filter
+ (soup_session_add_filter, soup_session_remove_filter): Add/remove
+ filters from the session
+ (setup_message): do auth handling, and call each of the session's
+ filters' setup_message methods as well.
+ (soup_session_send_message_via): No longer needed.
+ (connect_result): Handle SOUP_STATUS_TRY_AGAIN.
+
+ * libsoup/soup-session-async.c (run_queue): Use
+ soup_connection_send_request, since soup_session_send_message_via
+ is gone now.
+
+ * libsoup/soup-session-sync.c (send_message): Likewise
+
+ * libsoup/soup-message.c (soup_message_is_keepalive): A successful
+ response to a CONNECT is always keepalive, even if it's HTTP/1.0
+ with no Connection header.
+
+ * libsoup/soup-status.h: add SOUP_STATUS_TRY_AGAIN
+
+ * libsoup/soup-types.h: Add SoupMessageFilter, and macros for
+ gobject interface types.
+
+ * tests/get.c (main): Add a -p flag to specify a proxy
+
+ * tests/simple-proxy.c: Fix #includes
+
2003-12-18 Dan Winship <danw@ximian.com>
* libsoup/soup-connection.c (soup_connection_disconnect): Actually
diff --git a/libsoup/Makefile.am b/libsoup/Makefile.am
index 458b9a8e..342aee14 100644
--- a/libsoup/Makefile.am
+++ b/libsoup/Makefile.am
@@ -32,6 +32,7 @@ libsoupinclude_HEADERS = \
soup-connection.h \
soup-headers.h \
soup-message.h \
+ soup-message-filter.h \
soup-message-queue.h \
soup-method.h \
soup-misc.h \
@@ -78,6 +79,7 @@ libsoup_2_2_la_SOURCES = \
soup-md5-utils.c \
soup-message.c \
soup-message-client-io.c \
+ soup-message-filter.c \
soup-message-handlers.c \
soup-message-io.c \
soup-message-private.h \
diff --git a/libsoup/soup-connection.c b/libsoup/soup-connection.c
index 7c1535ab..5e3d3bda 100644
--- a/libsoup/soup-connection.c
+++ b/libsoup/soup-connection.c
@@ -25,6 +25,7 @@
#include "soup-connection.h"
#include "soup-marshal.h"
#include "soup-message.h"
+#include "soup-message-filter.h"
#include "soup-misc.h"
#include "soup-socket.h"
#include "soup-ssl.h"
@@ -42,6 +43,8 @@ struct SoupConnectionPrivate {
SoupUri *proxy_uri, *origin_uri, *conn_uri;
gpointer ssl_creds;
+ SoupMessageFilter *filter;
+
SoupMessage *cur_req;
time_t last_used;
gboolean in_use;
@@ -66,6 +69,7 @@ enum {
PROP_ORIGIN_URI,
PROP_PROXY_URI,
PROP_SSL_CREDS,
+ PROP_MESSAGE_FILTER,
LAST_PROP
};
@@ -96,6 +100,9 @@ finalize (GObject *object)
if (conn->priv->origin_uri)
soup_uri_free (conn->priv->origin_uri);
+ if (conn->priv->filter)
+ g_object_unref (conn->priv->filter);
+
g_free (conn->priv);
G_OBJECT_CLASS (parent_class)->finalize (object);
@@ -194,6 +201,12 @@ class_init (GObjectClass *object_class)
"SSL credentials",
"Opaque SSL credentials for this connection",
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property (
+ object_class, PROP_MESSAGE_FILTER,
+ g_param_spec_pointer (SOUP_CONNECTION_MESSAGE_FILTER,
+ "Message filter",
+ "Message filter object for this connection",
+ G_PARAM_READWRITE));
}
SOUP_MAKE_TYPE (soup_connection, SoupConnection, class_init, init, PARENT_TYPE)
@@ -255,6 +268,9 @@ set_property (GObject *object, guint prop_id,
case PROP_SSL_CREDS:
conn->priv->ssl_creds = g_value_get_pointer (value);
break;
+ case PROP_MESSAGE_FILTER:
+ conn->priv->filter = g_object_ref (g_value_get_pointer (value));
+ break;
default:
break;
}
@@ -279,12 +295,38 @@ get_property (GObject *object, guint prop_id,
case PROP_SSL_CREDS:
g_value_set_pointer (value, conn->priv->ssl_creds);
break;
+ case PROP_MESSAGE_FILTER:
+ g_value_set_pointer (value, g_object_ref (conn->priv->filter));
+ break;
default:
break;
}
}
static void
+set_current_request (SoupConnection *conn, SoupMessage *req)
+{
+ g_return_if_fail (conn->priv->cur_req == NULL);
+
+ req->status = SOUP_MESSAGE_STATUS_RUNNING;
+ conn->priv->cur_req = req;
+ conn->priv->in_use = TRUE;
+ g_object_add_weak_pointer (G_OBJECT (req),
+ (gpointer *)conn->priv->cur_req);
+}
+
+static void
+clear_current_request (SoupConnection *conn)
+{
+ if (conn->priv->cur_req) {
+ g_object_remove_weak_pointer (G_OBJECT (conn->priv->cur_req),
+ (gpointer *)conn->priv->cur_req);
+ conn->priv->cur_req = NULL;
+ }
+ conn->priv->in_use = FALSE;
+}
+
+static void
socket_disconnected (SoupSocket *sock, gpointer conn)
{
soup_connection_disconnect (conn);
@@ -310,6 +352,8 @@ tunnel_connect_finished (SoupMessage *msg, gpointer user_data)
SoupConnection *conn = user_data;
guint status = msg->status_code;
+ clear_current_request (conn);
+
if (SOUP_STATUS_IS_SUCCESSFUL (status)) {
if (!soup_socket_start_ssl (conn->priv->socket))
status = SOUP_STATUS_SSL_FAILED;
@@ -321,6 +365,37 @@ tunnel_connect_finished (SoupMessage *msg, gpointer user_data)
}
static void
+tunnel_connect_restarted (SoupMessage *msg, gpointer user_data)
+{
+ SoupConnection *conn = user_data;
+ guint status = msg->status_code;
+
+ /* We only allow one restart: if another one happens, treat
+ * it as "finished".
+ */
+ g_signal_handlers_disconnect_by_func (msg, tunnel_connect_restarted, conn);
+ g_signal_connect (msg, "restarted",
+ G_CALLBACK (tunnel_connect_finished), conn);
+
+ if (status == SOUP_STATUS_PROXY_AUTHENTICATION_REQUIRED) {
+ /* Our parent session has handled the authentication
+ * and attempted to restart the message.
+ */
+ if (soup_message_is_keepalive (msg)) {
+ /* Connection is still open, so just send the
+ * message again.
+ */
+ soup_connection_send_request (conn, msg);
+ } else {
+ /* Tell the session to try again. */
+ soup_message_set_status (msg, SOUP_STATUS_TRY_AGAIN);
+ soup_message_finished (msg);
+ }
+ } else
+ soup_message_finished (msg);
+}
+
+static void
socket_connect_result (SoupSocket *sock, guint status, gpointer user_data)
{
SoupConnection *conn = user_data;
@@ -344,6 +419,8 @@ socket_connect_result (SoupSocket *sock, guint status, gpointer user_data)
connect_msg = soup_message_new_from_uri (SOUP_METHOD_CONNECT,
conn->priv->origin_uri);
+ g_signal_connect (connect_msg, "restarted",
+ G_CALLBACK (tunnel_connect_restarted), conn);
g_signal_connect (connect_msg, "finished",
G_CALLBACK (tunnel_connect_finished), conn);
@@ -428,6 +505,17 @@ soup_connection_connect_sync (SoupConnection *conn)
conn->priv->origin_uri);
soup_connection_send_request (conn, connect_msg);
status = connect_msg->status_code;
+
+ if (status == SOUP_STATUS_PROXY_AUTHENTICATION_REQUIRED &&
+ SOUP_MESSAGE_IS_STARTING (connect_msg)) {
+ if (soup_message_is_keepalive (connect_msg)) {
+ /* Try once more */
+ soup_connection_send_request (conn, connect_msg);
+ status = connect_msg->status_code;
+ } else
+ status = SOUP_STATUS_TRY_AGAIN;
+ }
+
g_object_unref (connect_msg);
}
@@ -509,33 +597,32 @@ request_done (SoupMessage *req, gpointer user_data)
{
SoupConnection *conn = user_data;
- g_object_remove_weak_pointer (G_OBJECT (conn->priv->cur_req),
- (gpointer *)conn->priv->cur_req);
- conn->priv->cur_req = NULL;
+ clear_current_request (conn);
conn->priv->last_used = time (NULL);
- conn->priv->in_use = FALSE;
if (!soup_message_is_keepalive (req))
soup_connection_disconnect (conn);
g_signal_handlers_disconnect_by_func (req, request_done, conn);
g_signal_handlers_disconnect_by_func (req, request_restarted, conn);
+ g_object_unref (conn);
}
static void
send_request (SoupConnection *conn, SoupMessage *req)
{
+ g_object_ref (conn);
+
if (req != conn->priv->cur_req) {
- g_return_if_fail (conn->priv->cur_req == NULL);
- conn->priv->cur_req = req;
- conn->priv->in_use = TRUE;
- g_object_add_weak_pointer (G_OBJECT (req),
- (gpointer *)conn->priv->cur_req);
+ set_current_request (conn, req);
g_signal_connect (req, "restarted",
G_CALLBACK (request_restarted), conn);
g_signal_connect (req, "finished",
G_CALLBACK (request_done), conn);
+
+ if (conn->priv->filter)
+ soup_message_filter_setup_message (conn->priv->filter, req);
}
soup_message_io_cancel (req);
diff --git a/libsoup/soup-connection.h b/libsoup/soup-connection.h
index d25b6a92..5d08b080 100644
--- a/libsoup/soup-connection.h
+++ b/libsoup/soup-connection.h
@@ -49,6 +49,7 @@ GType soup_connection_get_type (void);
#define SOUP_CONNECTION_ORIGIN_URI "origin-uri"
#define SOUP_CONNECTION_PROXY_URI "proxy-uri"
#define SOUP_CONNECTION_SSL_CREDENTIALS "ssl-creds"
+#define SOUP_CONNECTION_MESSAGE_FILTER "message-filter"
SoupConnection *soup_connection_new (const char *propname1,
...);
diff --git a/libsoup/soup-message-filter.c b/libsoup/soup-message-filter.c
new file mode 100644
index 00000000..4b516c1a
--- /dev/null
+++ b/libsoup/soup-message-filter.c
@@ -0,0 +1,30 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-filter-offset: 8 -*- */
+/*
+ * soup-message-filter.c: Interface for arbitrary message manipulation
+ *
+ * Copyright (C) 2003, Ximian, Inc.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "soup-message-filter.h"
+
+SOUP_MAKE_INTERFACE (soup_message_filter, SoupMessageFilter, NULL)
+
+/**
+ * soup_message_filter_setup_message:
+ * @filter: an object that implements the #SoupMessageFilter interface
+ * @msg: a #SoupMessage
+ *
+ * Performs some sort of processing on @msg in preparation for it
+ * being sent. This will generally involve some combination of adding
+ * headers, adding handlers, and connecting to signals.
+ **/
+void
+soup_message_filter_setup_message (SoupMessageFilter *filter,
+ SoupMessage *msg)
+{
+ SOUP_MESSAGE_FILTER_GET_CLASS (filter)->setup_message (filter, msg);
+}
diff --git a/libsoup/soup-message-filter.h b/libsoup/soup-message-filter.h
new file mode 100644
index 00000000..a5471cfa
--- /dev/null
+++ b/libsoup/soup-message-filter.h
@@ -0,0 +1,30 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2000-2003, Ximian, Inc.
+ */
+
+#ifndef SOUP_MESSAGE_FILTER_H
+#define SOUP_MESSAGE_FILTER_H 1
+
+#include <libsoup/soup-types.h>
+
+#define SOUP_TYPE_MESSAGE_FILTER (soup_message_filter_get_type ())
+#define SOUP_MESSAGE_FILTER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SOUP_TYPE_MESSAGE_FILTER, SoupMessageFilter))
+#define SOUP_MESSAGE_FILTER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SOUP_TYPE_MESSAGE_FILTER, SoupMessageFilterClass))
+#define SOUP_IS_MESSAGE_FILTER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SOUP_TYPE_MESSAGE_FILTER))
+#define SOUP_IS_MESSAGE_FILTER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), SOUP_TYPE_MESSAGE_FILTER))
+#define SOUP_MESSAGE_FILTER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), SOUP_TYPE_MESSAGE_FILTER, SoupMessageFilterClass))
+
+typedef struct {
+ GTypeInterface parent;
+
+ /* methods */
+ void (*setup_message) (SoupMessageFilter *filter, SoupMessage *msg);
+} SoupMessageFilterClass;
+
+GType soup_message_filter_get_type (void);
+
+void soup_message_filter_setup_message (SoupMessageFilter *filter,
+ SoupMessage *msg);
+
+#endif /* SOUP_MESSAGE_FILTER_H */
diff --git a/libsoup/soup-message.c b/libsoup/soup-message.c
index 6d858259..7fb4bfdc 100644
--- a/libsoup/soup-message.c
+++ b/libsoup/soup-message.c
@@ -602,6 +602,10 @@ soup_message_is_keepalive (SoupMessage *msg)
c_conn = soup_message_get_header (msg->request_headers, "Connection");
s_conn = soup_message_get_header (msg->response_headers, "Connection");
+ if (msg->status_code == SOUP_STATUS_OK &&
+ soup_method_get_id (msg->method) == SOUP_METHOD_ID_CONNECT)
+ return TRUE;
+
if (msg->priv->http_version == SOUP_HTTP_1_0) {
/* Only persistent if the client requested keepalive
* and the server agreed.
diff --git a/libsoup/soup-session-async.c b/libsoup/soup-session-async.c
index 1a61d615..f6addaf9 100644
--- a/libsoup/soup-session-async.c
+++ b/libsoup/soup-session-async.c
@@ -133,7 +133,7 @@ run_queue (SoupSessionAsync *sa, gboolean try_pruning)
soup_connection_connect_async (conn, got_connection,
session);
} else
- soup_session_send_message_via (session, msg, conn);
+ soup_connection_send_request (conn, msg);
started_any = TRUE;
}
diff --git a/libsoup/soup-session-sync.c b/libsoup/soup-session-sync.c
index 5c078041..63110736 100644
--- a/libsoup/soup-session-sync.c
+++ b/libsoup/soup-session-sync.c
@@ -170,7 +170,7 @@ send_message (SoupSession *session, SoupMessage *msg)
* until either it's done, or the connection is closed.
*/
while (msg->status != SOUP_MESSAGE_STATUS_FINISHED && conn)
- soup_session_send_message_via (session, msg, conn);
+ soup_connection_send_request (conn, msg);
if (conn) {
g_object_remove_weak_pointer (G_OBJECT (conn),
diff --git a/libsoup/soup-session.c b/libsoup/soup-session.c
index 65da4641..6922740a 100644
--- a/libsoup/soup-session.c
+++ b/libsoup/soup-session.c
@@ -18,6 +18,7 @@
#include "soup-connection.h"
#include "soup-connection-ntlm.h"
#include "soup-marshal.h"
+#include "soup-message-filter.h"
#include "soup-message-queue.h"
#include "soup-ssl.h"
#include "soup-uri.h"
@@ -40,6 +41,8 @@ struct SoupSessionPrivate {
char *ssl_ca_file;
gpointer ssl_creds;
+ GSList *filters;
+
GHashTable *hosts; /* SoupUri -> SoupSessionHost */
GHashTable *conns; /* SoupConnection -> SoupSessionHost */
guint num_conns;
@@ -57,6 +60,8 @@ static guint host_uri_hash (gconstpointer key);
static gboolean host_uri_equal (gconstpointer v1, gconstpointer v2);
static void free_host (SoupSessionHost *host, SoupSession *session);
+static void setup_message (SoupMessageFilter *filter, SoupMessage *msg);
+
static void queue_message (SoupSession *session, SoupMessage *msg,
SoupMessageCallbackFn callback,
gpointer user_data);
@@ -128,10 +133,18 @@ static void
dispose (GObject *object)
{
SoupSession *session = SOUP_SESSION (object);
+ GSList *f;
soup_session_abort (session);
cleanup_hosts (session);
+ if (session->priv->filters) {
+ for (f = session->priv->filters; f; f = f->next)
+ g_object_unref (f->data);
+ g_slist_free (session->priv->filters);
+ session->priv->filters = NULL;
+ }
+
G_OBJECT_CLASS (parent_class)->dispose (object);
}
@@ -236,7 +249,14 @@ class_init (GObjectClass *object_class)
G_PARAM_READWRITE));
}
-SOUP_MAKE_TYPE (soup_session, SoupSession, class_init, init, PARENT_TYPE)
+static void
+filter_iface_init (SoupMessageFilterClass *filter_class)
+{
+ /* interface implementation */
+ filter_class->setup_message = setup_message;
+}
+
+SOUP_MAKE_TYPE_WITH_IFACE (soup_session, SoupSession, class_init, init, PARENT_TYPE, filter_iface_init, SOUP_TYPE_MESSAGE_FILTER)
static gboolean
safe_uri_equal (const SoupUri *a, const SoupUri *b)
@@ -324,6 +344,42 @@ get_property (GObject *object, guint prop_id,
}
+/**
+ * soup_session_add_filter:
+ * @session: a #SoupSession
+ * @filter: an object implementing the #SoupMessageFilter interface
+ *
+ * Adds @filter to @session's list of message filters to be applied to
+ * all messages.
+ **/
+void
+soup_session_add_filter (SoupSession *session, SoupMessageFilter *filter)
+{
+ g_return_if_fail (SOUP_IS_SESSION (session));
+ g_return_if_fail (SOUP_IS_MESSAGE_FILTER (filter));
+
+ session->priv->filters = g_slist_prepend (session->priv->filters,
+ filter);
+}
+
+/**
+ * soup_session_remove_filter:
+ * @session: a #SoupSession
+ * @filter: an object implementing the #SoupMessageFilter interface
+ *
+ * Removes @filter from @session's list of message filters
+ **/
+void
+soup_session_remove_filter (SoupSession *session, SoupMessageFilter *filter)
+{
+ g_return_if_fail (SOUP_IS_SESSION (session));
+ g_return_if_fail (SOUP_IS_MESSAGE_FILTER (filter));
+
+ session->priv->filters = g_slist_remove (session->priv->filters,
+ filter);
+}
+
+
/* Hosts */
static guint
host_uri_hash (gconstpointer key)
@@ -728,16 +784,30 @@ add_auth (SoupSession *session, SoupMessage *msg, gboolean proxy)
}
}
-void
-soup_session_send_message_via (SoupSession *session, SoupMessage *msg,
- SoupConnection *conn)
+static void
+setup_message (SoupMessageFilter *filter, SoupMessage *msg)
{
- msg->status = SOUP_MESSAGE_STATUS_RUNNING;
+ SoupSession *session = SOUP_SESSION (filter);
+ GSList *f;
+
+ for (f = session->priv->filters; f; f = f->next) {
+ filter = f->data;
+ soup_message_filter_setup_message (filter, msg);
+ }
add_auth (session, msg, FALSE);
- if (session->priv->proxy_uri)
+ soup_message_add_status_code_handler (
+ msg, SOUP_STATUS_UNAUTHORIZED,
+ SOUP_HANDLER_POST_BODY,
+ authorize_handler, session);
+
+ if (session->priv->proxy_uri) {
add_auth (session, msg, TRUE);
- soup_connection_send_request (conn, msg);
+ soup_message_add_status_code_handler (
+ msg, SOUP_STATUS_PROXY_UNAUTHORIZED,
+ SOUP_HANDLER_POST_BODY,
+ authorize_handler, session);
+ }
}
static void
@@ -847,11 +917,24 @@ connect_result (SoupConnection *conn, guint status, gpointer user_data)
return;
}
- /* It's hopeless. Cancel everything that was waiting for this host. */
+ /* There are two possibilities: either status is
+ * SOUP_STATUS_TRY_AGAIN, in which case the session implementation
+ * will create a new connection (and all we need to do here
+ * is downgrade the message from CONNECTING to QUEUED); or
+ * status is something else, probably CANT_CONNECT or
+ * CANT_RESOLVE or the like, in which case we need to cancel
+ * any messages waiting for this host, since they're out
+ * of luck.
+ */
for (msg = soup_message_queue_first (session->queue, &iter); msg; msg = soup_message_queue_next (session->queue, &iter)) {
if (get_host_for_message (session, msg) == host) {
- soup_message_set_status (msg, status);
- soup_session_cancel_message (session, msg);
+ if (status == SOUP_STATUS_TRY_AGAIN) {
+ if (msg->status == SOUP_MESSAGE_STATUS_CONNECTING)
+ msg->status = SOUP_MESSAGE_STATUS_QUEUED;
+ } else {
+ soup_message_set_status (msg, status);
+ soup_session_cancel_message (session, msg);
+ }
}
}
}
@@ -932,6 +1015,7 @@ soup_session_get_connection (SoupSession *session, SoupMessage *msg,
SOUP_CONNECTION_ORIGIN_URI, host->root_uri,
SOUP_CONNECTION_PROXY_URI, session->priv->proxy_uri,
SOUP_CONNECTION_SSL_CREDENTIALS, session->priv->ssl_creds,
+ SOUP_CONNECTION_MESSAGE_FILTER, session,
NULL);
g_signal_connect (conn, "connect_result",
G_CALLBACK (connect_result),
@@ -983,14 +1067,6 @@ queue_message (SoupSession *session, SoupMessage *msg,
g_signal_connect_after (msg, "finished",
G_CALLBACK (message_finished), session);
- soup_message_add_status_code_handler (msg, SOUP_STATUS_UNAUTHORIZED,
- SOUP_HANDLER_POST_BODY,
- authorize_handler, session);
- soup_message_add_status_code_handler (msg,
- SOUP_STATUS_PROXY_UNAUTHORIZED,
- SOUP_HANDLER_POST_BODY,
- authorize_handler, session);
-
if (!(soup_message_get_flags (msg) & SOUP_MESSAGE_NO_REDIRECT)) {
soup_message_add_status_class_handler (
msg, SOUP_STATUS_CLASS_REDIRECT,
diff --git a/libsoup/soup-session.h b/libsoup/soup-session.h
index a8f9bf15..8e5be50c 100644
--- a/libsoup/soup-session.h
+++ b/libsoup/soup-session.h
@@ -58,6 +58,11 @@ GType soup_session_get_type (void);
#define SOUP_SESSION_USE_NTLM "use-ntlm"
#define SOUP_SESSION_SSL_CA_FILE "ssl-ca-file"
+void soup_session_add_filter (SoupSession *session,
+ SoupMessageFilter *filter);
+void soup_session_remove_filter (SoupSession *session,
+ SoupMessageFilter *filter);
+
void soup_session_queue_message (SoupSession *session,
SoupMessage *msg,
SoupMessageCallbackFn callback,
@@ -80,9 +85,5 @@ SoupConnection *soup_session_get_connection (SoupSession *session,
gboolean *is_new);
gboolean soup_session_try_prune_connection (SoupSession *session);
-void soup_session_send_message_via (SoupSession *session,
- SoupMessage *msg,
- SoupConnection *conn);
-
#endif /* SOUP_SESSION_H */
diff --git a/libsoup/soup-status.c b/libsoup/soup-status.c
index 1f601010..83b5bad7 100644
--- a/libsoup/soup-status.c
+++ b/libsoup/soup-status.c
@@ -22,6 +22,7 @@ struct {
{ SOUP_STATUS_SSL_FAILED, "SSL handshake failed" },
{ SOUP_STATUS_IO_ERROR, "Connection terminated unexpectedly" },
{ SOUP_STATUS_MALFORMED, "Message Corrupt" },
+ /* SOUP_STATUS_TRY_AGAIN should never be returned to the caller */
/* Informational */
{ SOUP_STATUS_CONTINUE, "Continue" },
diff --git a/libsoup/soup-status.h b/libsoup/soup-status.h
index fd8f9843..d4d643b7 100644
--- a/libsoup/soup-status.h
+++ b/libsoup/soup-status.h
@@ -34,6 +34,7 @@ typedef enum {
SOUP_STATUS_SSL_FAILED,
SOUP_STATUS_IO_ERROR,
SOUP_STATUS_MALFORMED,
+ SOUP_STATUS_TRY_AGAIN,
/* HTTP Status Codes */
SOUP_STATUS_CONTINUE = 100,
diff --git a/libsoup/soup-types.h b/libsoup/soup-types.h
index ffdcbba4..c7a97aa7 100644
--- a/libsoup/soup-types.h
+++ b/libsoup/soup-types.h
@@ -14,6 +14,7 @@
typedef struct SoupAddress SoupAddress;
typedef struct SoupConnection SoupConnection;
typedef struct SoupMessage SoupMessage;
+typedef struct SoupMessageFilter SoupMessageFilter;
typedef struct SoupServer SoupServer;
typedef union SoupServerAuth SoupServerAuth;
typedef struct SoupServerAuthContext SoupServerAuthContext;
@@ -24,26 +25,80 @@ typedef struct SoupSessionSync SoupSessionSync;
typedef struct SoupSocket SoupSocket;
typedef struct SoupUri SoupUri;
-#define SOUP_MAKE_TYPE(l,t,ci,i,parent) \
-GType l##_get_type(void)\
+#define SOUP_MAKE_TYPE(type_name,TypeName,class_init,init,parent) \
+GType type_name##_get_type(void)\
{\
static GType type = 0; \
if (!type){ \
static GTypeInfo const object_info = { \
- sizeof (t##Class), \
+ sizeof (TypeName##Class), \
\
(GBaseInitFunc) NULL, \
(GBaseFinalizeFunc) NULL, \
\
- (GClassInitFunc) ci, \
+ (GClassInitFunc) class_init, \
(GClassFinalizeFunc) NULL, \
NULL, /* class_data */ \
\
- sizeof (t), \
+ sizeof (TypeName), \
0, /* n_preallocs */ \
- (GInstanceInitFunc) i, \
+ (GInstanceInitFunc) init, \
}; \
- type = g_type_register_static (parent, #t, &object_info, 0); \
+ type = g_type_register_static (parent, #TypeName, &object_info, 0); \
+ } \
+ return type; \
+}
+
+#define SOUP_MAKE_INTERFACE(type_name,TypeName,base_init) \
+GType type_name##_get_type(void)\
+{\
+ static GType type = 0; \
+ if (!type){ \
+ static GTypeInfo const object_info = { \
+ sizeof (TypeName##Class), \
+ \
+ (GBaseInitFunc) base_init, \
+ (GBaseFinalizeFunc) NULL, \
+ \
+ (GClassInitFunc) NULL, \
+ (GClassFinalizeFunc) NULL, \
+ NULL, /* class_data */ \
+ \
+ 0, \
+ 0, /* n_preallocs */ \
+ (GInstanceInitFunc) NULL, \
+ }; \
+ type = g_type_register_static (G_TYPE_INTERFACE, #TypeName, &object_info, 0); \
+ } \
+ return type; \
+}
+
+#define SOUP_MAKE_TYPE_WITH_IFACE(type_name,TypeName,class_init,init,parent,iface_init,iparent) \
+GType type_name##_get_type(void)\
+{\
+ static GType type = 0; \
+ if (!type){ \
+ static GTypeInfo const object_info = { \
+ sizeof (TypeName##Class), \
+ \
+ (GBaseInitFunc) NULL, \
+ (GBaseFinalizeFunc) NULL, \
+ \
+ (GClassInitFunc) class_init, \
+ (GClassFinalizeFunc) NULL, \
+ NULL, /* class_data */ \
+ \
+ sizeof (TypeName), \
+ 0, /* n_preallocs */ \
+ (GInstanceInitFunc) init, \
+ }; \
+ static GInterfaceInfo const iface_info = { \
+ (GInterfaceInitFunc) iface_init, \
+ NULL, \
+ NULL \
+ }; \
+ type = g_type_register_static (parent, #TypeName, &object_info, 0); \
+ g_type_add_interface_static (type, iparent, &iface_info); \
} \
return type; \
}
diff --git a/tests/get.c b/tests/get.c
index 69566521..5c7e5d07 100644
--- a/tests/get.c
+++ b/tests/get.c
@@ -205,17 +205,27 @@ int
main (int argc, char **argv)
{
const char *cafile = NULL;
+ SoupUri *proxy = NULL;
int opt;
g_type_init ();
g_thread_init (NULL);
- while ((opt = getopt (argc, argv, "c:r")) != -1) {
+ while ((opt = getopt (argc, argv, "c:p:r")) != -1) {
switch (opt) {
case 'c':
cafile = optarg;
break;
+ case 'p':
+ proxy = soup_uri_new (optarg);
+ if (!proxy) {
+ fprintf (stderr, "Could not parse %s as URI\n",
+ optarg);
+ exit (1);
+ }
+ break;
+
case 'r':
recurse = TRUE;
break;
@@ -239,6 +249,7 @@ main (int argc, char **argv)
session = soup_session_async_new_with_options (
SOUP_SESSION_SSL_CA_FILE, cafile,
+ SOUP_SESSION_PROXY_URI, proxy,
NULL);
if (recurse) {
diff --git a/tests/simple-proxy.c b/tests/simple-proxy.c
index 85b647cf..c4ae793e 100644
--- a/tests/simple-proxy.c
+++ b/tests/simple-proxy.c
@@ -18,7 +18,7 @@
#include <libsoup/soup-message.h>
#include <libsoup/soup-server.h>
#include <libsoup/soup-server-message.h>
-#include <libsoup/soup-session.h>
+#include <libsoup/soup-session-async.h>
/* WARNING: this is really really really not especially compliant with
* RFC 2616. But it does work for basic stuff.