summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Winship <danw@src.gnome.org>2003-12-17 19:49:14 +0000
committerDan Winship <danw@src.gnome.org>2003-12-17 19:49:14 +0000
commitc2720d6770639fed2bf57a972fa7c9b47919d0ac (patch)
treed00e278329a0e3f3053f556099a3eb518a6a8c02
parentde3cf1fc96532d10cdd1d6e55aea3c4f81501579 (diff)
downloadlibsoup-c2720d6770639fed2bf57a972fa7c9b47919d0ac.tar.gz
Add gthread to glib check
* configure.in: Add gthread to glib check * libsoup/soup-session.c: Make this an abstract class. * libsoup/soup-session-async.c: A SoupSession class for asynchronous gmain-based operation; replaces the old SoupSession. * libsoup/soup-session-sync.c: A SoupSession class for synchronous blocking operation for use with threaded apps. * libsoup/soup-types.h, libsoup/soup.h: add the new session subclasses * libsoup/soup-connection.c (soup_connection_connect_sync): Don't try to unref the socket if the socket creation fails. (soup_connection_reserve): New, to explicitly mark a connection as being in use without queueing a message on it. * libsoup/soup-dns.c (check_hostent): Oof. Fix the logic of the "block" flag to not be reversed. * libsoup/soup-message.c (finished): set status to FINISHED here. (soup_message_cancel): Gone; needs to be done at the session level. * libsoup/soup-message-queue.c: Add a mutex and make all of the operations thread-safe. * libsoup/soup-socket.c (disconnect_internal): Make this thread-safe. (soup_socket_connect): Make the sync case work correctly. * libsoup/Makefile.am: add the SoupSession subclasses * tests/Makefile.am: libsoup depends on libgthread now, so revserver doesn't need to explicitly. * tests/get.c, tests/auth-test.c, tests/simple-proxy.c: Use soup_session_async_new().
-rw-r--r--ChangeLog42
-rw-r--r--configure.in2
-rw-r--r--libsoup/Makefile.am4
-rw-r--r--libsoup/soup-connection.c21
-rw-r--r--libsoup/soup-connection.h1
-rw-r--r--libsoup/soup-dns.c4
-rw-r--r--libsoup/soup-message-queue.c103
-rw-r--r--libsoup/soup-message.c31
-rw-r--r--libsoup/soup-message.h2
-rw-r--r--libsoup/soup-session-async.c213
-rw-r--r--libsoup/soup-session-async.h39
-rw-r--r--libsoup/soup-session-sync.c197
-rw-r--r--libsoup/soup-session-sync.h39
-rw-r--r--libsoup/soup-session.c552
-rw-r--r--libsoup/soup-session.h37
-rw-r--r--libsoup/soup-socket.c31
-rw-r--r--libsoup/soup-types.h2
-rw-r--r--libsoup/soup.h3
-rw-r--r--tests/Makefile.am1
-rw-r--r--tests/auth-test.c75
-rw-r--r--tests/get.c3
-rw-r--r--tests/simple-proxy.c2
22 files changed, 1018 insertions, 386 deletions
diff --git a/ChangeLog b/ChangeLog
index 29e9e674..9eefbf81 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,45 @@
+2003-12-17 Dan Winship <danw@ximian.com>
+
+ * configure.in: Add gthread to glib check
+
+ * libsoup/soup-session.c: Make this an abstract class.
+
+ * libsoup/soup-session-async.c: A SoupSession class for
+ asynchronous gmain-based operation; replaces the old SoupSession.
+
+ * libsoup/soup-session-sync.c: A SoupSession class for synchronous
+ blocking operation for use with threaded apps.
+
+ * libsoup/soup-types.h, libsoup/soup.h: add the new session
+ subclasses
+
+ * libsoup/soup-connection.c (soup_connection_connect_sync): Don't
+ try to unref the socket if the socket creation fails.
+ (soup_connection_reserve): New, to explicitly mark a connection as
+ being in use without queueing a message on it.
+
+ * libsoup/soup-dns.c (check_hostent): Oof. Fix the logic of the
+ "block" flag to not be reversed.
+
+ * libsoup/soup-message.c (finished): set status to FINISHED here.
+ (soup_message_cancel): Gone; needs to be done at the session
+ level.
+
+ * libsoup/soup-message-queue.c: Add a mutex and make all of the
+ operations thread-safe.
+
+ * libsoup/soup-socket.c (disconnect_internal): Make this
+ thread-safe.
+ (soup_socket_connect): Make the sync case work correctly.
+
+ * libsoup/Makefile.am: add the SoupSession subclasses
+
+ * tests/Makefile.am: libsoup depends on libgthread now, so
+ revserver doesn't need to explicitly.
+
+ * tests/get.c, tests/auth-test.c, tests/simple-proxy.c: Use
+ soup_session_async_new().
+
2003-12-16 Rodrigo Moya <rodrigo@ximian.com>
* libsoup/soup-soap-response.[ch] (soup_soap_parameter_get_int_value):
diff --git a/configure.in b/configure.in
index d0454895..8215a25c 100644
--- a/configure.in
+++ b/configure.in
@@ -72,7 +72,7 @@ dnl ***********************
dnl *** Checks for glib ***
dnl ***********************
-AM_PATH_GLIB_2_0(2.0.0,,,gobject)
+AM_PATH_GLIB_2_0(2.0.0,,,gobject gthread)
PKG_CHECK_MODULES(XML, libxml-2.0)
AC_SUBST(XML_CFLAGS)
diff --git a/libsoup/Makefile.am b/libsoup/Makefile.am
index 2781ff8d..e49a43e0 100644
--- a/libsoup/Makefile.am
+++ b/libsoup/Makefile.am
@@ -38,6 +38,8 @@ libsoupinclude_HEADERS = \
soup-server-message.h \
soup-server.h \
soup-session.h \
+ soup-session-async.h \
+ soup-session-sync.h \
soup-soap-message.h \
soup-soap-response.h \
soup-socket.h \
@@ -88,6 +90,8 @@ libsoup_2_2_la_SOURCES = \
soup-server-auth.c \
soup-server-message.c \
soup-session.c \
+ soup-session-async.c \
+ soup-session-sync.c \
soup-soap-message.c \
soup-soap-response.c \
soup-socket.c \
diff --git a/libsoup/soup-connection.c b/libsoup/soup-connection.c
index c37f813a..67bbfca3 100644
--- a/libsoup/soup-connection.c
+++ b/libsoup/soup-connection.c
@@ -44,6 +44,7 @@ struct SoupConnectionPrivate {
SoupMessage *cur_req;
time_t last_used;
+ gboolean in_use;
};
#define PARENT_TYPE G_TYPE_OBJECT
@@ -432,10 +433,14 @@ soup_connection_connect_sync (SoupConnection *conn)
if (!SOUP_STATUS_IS_SUCCESSFUL (status)) {
fail:
- g_object_unref (conn->priv->socket);
- conn->priv->socket = NULL;
+ if (conn->priv->socket) {
+ g_object_unref (conn->priv->socket);
+ conn->priv->socket = NULL;
+ }
}
+ g_signal_emit (conn, signals[CONNECT_RESULT], 0,
+ proxified_status (conn, status));
return proxified_status (conn, status);
}
@@ -473,7 +478,7 @@ soup_connection_is_in_use (SoupConnection *conn)
{
g_return_val_if_fail (SOUP_IS_CONNECTION (conn), FALSE);
- return conn->priv->cur_req != NULL;
+ return conn->priv->in_use;
}
/**
@@ -500,6 +505,7 @@ request_done (SoupMessage *req, gpointer user_data)
(gpointer *)conn->priv->cur_req);
conn->priv->cur_req = NULL;
conn->priv->last_used = time (NULL);
+ conn->priv->in_use = FALSE;
g_signal_handlers_disconnect_by_func (req, request_done, conn);
@@ -513,6 +519,7 @@ send_request (SoupConnection *conn, SoupMessage *req)
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);
@@ -536,6 +543,14 @@ soup_connection_send_request (SoupConnection *conn, SoupMessage *req)
}
void
+soup_connection_reserve (SoupConnection *conn)
+{
+ g_return_if_fail (SOUP_IS_CONNECTION (conn));
+
+ conn->priv->in_use = TRUE;
+}
+
+void
soup_connection_authenticate (SoupConnection *conn, SoupMessage *msg,
const char *auth_type, const char *auth_realm,
char **username, char **password)
diff --git a/libsoup/soup-connection.h b/libsoup/soup-connection.h
index 2d88b5a9..d25b6a92 100644
--- a/libsoup/soup-connection.h
+++ b/libsoup/soup-connection.h
@@ -69,6 +69,7 @@ time_t soup_connection_last_used (SoupConnection *conn);
void soup_connection_send_request (SoupConnection *conn,
SoupMessage *req);
+void soup_connection_reserve (SoupConnection *conn);
/* protected */
void soup_connection_authenticate (SoupConnection *conn,
diff --git a/libsoup/soup-dns.c b/libsoup/soup-dns.c
index a3fed01e..1789abba 100644
--- a/libsoup/soup-dns.c
+++ b/libsoup/soup-dns.c
@@ -613,9 +613,9 @@ check_hostent (SoupDNSEntry *entry, gboolean block)
}
if (block)
- tvp = &tv;
- else
tvp = NULL;
+ else
+ tvp = &tv;
do {
FD_ZERO (&readfds);
diff --git a/libsoup/soup-message-queue.c b/libsoup/soup-message-queue.c
index 0bf1f7d5..9b89381e 100644
--- a/libsoup/soup-message-queue.c
+++ b/libsoup/soup-message-queue.c
@@ -14,6 +14,8 @@
struct SoupMessageQueue {
GList *head, *tail;
GList *iters;
+
+ GMutex *mutex;
};
/**
@@ -24,7 +26,11 @@ struct SoupMessageQueue {
SoupMessageQueue *
soup_message_queue_new (void)
{
- return g_new0 (SoupMessageQueue, 1);
+ SoupMessageQueue *queue;
+
+ queue = g_new0 (SoupMessageQueue, 1);
+ queue->mutex = g_mutex_new ();
+ return queue;
}
/**
@@ -40,6 +46,7 @@ soup_message_queue_destroy (SoupMessageQueue *queue)
g_list_free (queue->head);
g_list_free (queue->iters);
+ g_mutex_free (queue->mutex);
g_free (queue);
}
@@ -53,6 +60,7 @@ soup_message_queue_destroy (SoupMessageQueue *queue)
void
soup_message_queue_append (SoupMessageQueue *queue, SoupMessage *msg)
{
+ g_mutex_lock (queue->mutex);
if (queue->head) {
queue->tail = g_list_append (queue->tail, msg);
queue->tail = queue->tail->next;
@@ -60,6 +68,7 @@ soup_message_queue_append (SoupMessageQueue *queue, SoupMessage *msg)
queue->head = queue->tail = g_list_append (NULL, msg);
g_object_add_weak_pointer (G_OBJECT (msg), &queue->tail->data);
+ g_mutex_unlock (queue->mutex);
}
/**
@@ -77,16 +86,60 @@ soup_message_queue_append (SoupMessageQueue *queue, SoupMessage *msg)
SoupMessage *
soup_message_queue_first (SoupMessageQueue *queue, SoupMessageQueueIter *iter)
{
- if (!queue->head)
+ g_mutex_lock (queue->mutex);
+
+ if (!queue->head) {
+ g_mutex_unlock (queue->mutex);
return NULL;
+ }
queue->iters = g_list_prepend (queue->iters, iter);
iter->cur = NULL;
iter->next = queue->head;
+ g_mutex_unlock (queue->mutex);
+
return soup_message_queue_next (queue, iter);
}
+static SoupMessage *
+queue_remove_internal (SoupMessageQueue *queue, SoupMessageQueueIter *iter)
+{
+ GList *i;
+ SoupMessageQueueIter *iter2;
+ SoupMessage *msg;
+
+ if (!iter->cur) {
+ /* We're at end of list or this item was already removed */
+ return NULL;
+ }
+
+ /* Fix any other iters pointing to iter->cur */
+ for (i = queue->iters; i; i = i->next) {
+ iter2 = i->data;
+ if (iter2 != iter) {
+ if (iter2->cur == iter->cur)
+ iter2->cur = NULL;
+ else if (iter2->next == iter->cur)
+ iter2->next = iter->cur->next;
+ }
+ }
+
+ msg = iter->cur->data;
+ if (msg)
+ g_object_remove_weak_pointer (G_OBJECT (msg), &iter->cur->data);
+
+ /* If deleting the last item, fix tail */
+ if (queue->tail == iter->cur)
+ queue->tail = queue->tail->prev;
+
+ /* Remove the item */
+ queue->head = g_list_delete_link (queue->head, iter->cur);
+ iter->cur = NULL;
+
+ return msg;
+}
+
/**
* soup_message_queue_next:
* @queue: a queue
@@ -97,19 +150,25 @@ soup_message_queue_first (SoupMessageQueue *queue, SoupMessageQueueIter *iter)
SoupMessage *
soup_message_queue_next (SoupMessageQueue *queue, SoupMessageQueueIter *iter)
{
+ g_mutex_lock (queue->mutex);
+
while (iter->next) {
iter->cur = iter->next;
iter->next = iter->cur->next;
- if (iter->cur->data)
+ if (iter->cur->data) {
+ g_mutex_unlock (queue->mutex);
return iter->cur->data;
+ }
/* Message was finalized, remove dead queue element */
- soup_message_queue_remove (queue, iter);
+ queue_remove_internal (queue, iter);
}
/* Nothing left */
iter->cur = NULL;
- soup_message_queue_free_iter (queue, iter);
+ queue->iters = g_list_remove (queue->iters, iter);
+
+ g_mutex_unlock (queue->mutex);
return NULL;
}
@@ -128,37 +187,11 @@ soup_message_queue_next (SoupMessageQueue *queue, SoupMessageQueueIter *iter)
SoupMessage *
soup_message_queue_remove (SoupMessageQueue *queue, SoupMessageQueueIter *iter)
{
- GList *i;
- SoupMessageQueueIter *iter2;
SoupMessage *msg;
- if (!iter->cur) {
- /* We're at end of list or this item was already removed */
- return NULL;
- }
-
- /* Fix any other iters pointing to iter->cur */
- for (i = queue->iters; i; i = i->next) {
- iter2 = i->data;
- if (iter2 != iter) {
- if (iter2->cur == iter->cur)
- iter2->cur = NULL;
- else if (iter2->next == iter->cur)
- iter2->next = iter->cur->next;
- }
- }
-
- msg = iter->cur->data;
- if (msg)
- g_object_remove_weak_pointer (G_OBJECT (msg), &iter->cur->data);
-
- /* If deleting the last item, fix tail */
- if (queue->tail == iter->cur)
- queue->tail = queue->tail->prev;
-
- /* Remove the item */
- queue->head = g_list_delete_link (queue->head, iter->cur);
- iter->cur = NULL;
+ g_mutex_lock (queue->mutex);
+ msg = queue_remove_internal (queue, iter);
+ g_mutex_unlock (queue->mutex);
return msg;
}
@@ -190,5 +223,7 @@ void
soup_message_queue_free_iter (SoupMessageQueue *queue,
SoupMessageQueueIter *iter)
{
+ g_mutex_lock (queue->mutex);
queue->iters = g_list_remove (queue->iters, iter);
+ g_mutex_unlock (queue->mutex);
}
diff --git a/libsoup/soup-message.c b/libsoup/soup-message.c
index fe6edf8e..6d858259 100644
--- a/libsoup/soup-message.c
+++ b/libsoup/soup-message.c
@@ -40,7 +40,8 @@ static void wrote_body (SoupMessage *req);
static void got_headers (SoupMessage *req);
static void got_chunk (SoupMessage *req);
static void got_body (SoupMessage *req);
-static void stop_io (SoupMessage *req);
+static void restarted (SoupMessage *req);
+static void finished (SoupMessage *req);
static void free_chunks (SoupMessage *msg);
static void
@@ -105,8 +106,8 @@ class_init (GObjectClass *object_class)
message_class->got_headers = got_headers;
message_class->got_chunk = got_chunk;
message_class->got_body = got_body;
- message_class->restarted = stop_io;
- message_class->finished = stop_io;
+ message_class->restarted = restarted;
+ message_class->finished = finished;
/* virtual method override */
object_class->finalize = finalize;
@@ -390,7 +391,7 @@ soup_message_got_body (SoupMessage *msg)
}
static void
-stop_io (SoupMessage *req)
+restarted (SoupMessage *req)
{
soup_message_io_cancel (req);
}
@@ -401,27 +402,17 @@ soup_message_restarted (SoupMessage *msg)
g_signal_emit (msg, signals[RESTARTED], 0);
}
-void
-soup_message_finished (SoupMessage *msg)
+static void
+finished (SoupMessage *req)
{
- g_signal_emit (msg, signals[FINISHED], 0);
+ soup_message_io_cancel (req);
+ req->status = SOUP_MESSAGE_STATUS_FINISHED;
}
-/**
- * soup_message_cancel:
- * @msg: a #SoupMessage currently being processed.
- *
- * Cancel a running message, and issue completion callback with an
- * status code of %SOUP_STATUS_CANCELLED. If not requeued by the
- * completion callback, the @msg will be destroyed.
- */
void
-soup_message_cancel (SoupMessage *msg)
+soup_message_finished (SoupMessage *msg)
{
- if (msg->status != SOUP_MESSAGE_STATUS_FINISHED) {
- soup_message_set_status (msg, SOUP_STATUS_CANCELLED);
- soup_message_finished (msg);
- }
+ g_signal_emit (msg, signals[FINISHED], 0);
}
static gboolean
diff --git a/libsoup/soup-message.h b/libsoup/soup-message.h
index 89a1753c..f72fb7ad 100644
--- a/libsoup/soup-message.h
+++ b/libsoup/soup-message.h
@@ -102,8 +102,6 @@ void soup_message_set_response (SoupMessage *msg,
char *resp_body,
gulong resp_length);
-void soup_message_cancel (SoupMessage *msg);
-
void soup_message_add_header (GHashTable *hash,
const char *name,
const char *value);
diff --git a/libsoup/soup-session-async.c b/libsoup/soup-session-async.c
new file mode 100644
index 00000000..2d073a19
--- /dev/null
+++ b/libsoup/soup-session-async.c
@@ -0,0 +1,213 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * soup-session-async.c
+ *
+ * Copyright (C) 2000-2003, Ximian, Inc.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "soup-session-async.h"
+#include "soup-connection.h"
+
+struct SoupSessionAsyncPrivate {
+ int dummy;
+};
+
+static gboolean run_queue (SoupSessionAsync *sa, gboolean try_pruning);
+
+static void queue_message (SoupSession *session, SoupMessage *req,
+ SoupMessageCallbackFn callback,
+ gpointer user_data);
+static guint send_message (SoupSession *session, SoupMessage *req);
+
+#define PARENT_TYPE SOUP_TYPE_SESSION
+static SoupSessionClass *parent_class;
+
+static void
+init (GObject *object)
+{
+ SoupSessionAsync *sa = SOUP_SESSION_ASYNC (object);
+
+ sa->priv = g_new0 (SoupSessionAsyncPrivate, 1);
+}
+
+static void
+finalize (GObject *object)
+{
+ SoupSessionAsync *sa = SOUP_SESSION_ASYNC (object);
+
+ g_free (sa->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+class_init (GObjectClass *object_class)
+{
+ SoupSessionClass *session_class = SOUP_SESSION_CLASS (object_class);
+
+ parent_class = g_type_class_ref (PARENT_TYPE);
+
+ /* virtual method override */
+ session_class->queue_message = queue_message;
+ session_class->send_message = send_message;
+ object_class->finalize = finalize;
+}
+
+SOUP_MAKE_TYPE (soup_session_async, SoupSessionAsync, class_init, init, PARENT_TYPE)
+
+SoupSession *
+soup_session_async_new (void)
+{
+ return g_object_new (SOUP_TYPE_SESSION_ASYNC, NULL);
+}
+
+SoupSession *
+soup_session_async_new_with_options (const char *optname1, ...)
+{
+ SoupSession *session;
+ va_list ap;
+
+ va_start (ap, optname1);
+ session = (SoupSession *)g_object_new_valist (SOUP_TYPE_SESSION_ASYNC,
+ optname1, ap);
+ va_end (ap);
+
+ return session;
+}
+
+
+static void
+connection_closed (SoupConnection *conn, SoupSessionAsync *sa)
+{
+ /* Run the queue in case anyone was waiting for a connection
+ * to be closed.
+ */
+ run_queue (sa, FALSE);
+}
+
+static void
+got_connection (SoupConnection *conn, guint status, gpointer user_data)
+{
+ SoupSessionAsync *sa = user_data;
+
+ if (status == SOUP_STATUS_OK) {
+ g_signal_connect (conn, "disconnected",
+ G_CALLBACK (connection_closed),
+ sa);
+ }
+
+ /* Either we just got a connection, or we just failed to
+ * open a connection and so decremented the open connection
+ * count by one. Either way, we need to run the queue now.
+ */
+ run_queue (sa, FALSE);
+}
+
+static gboolean
+run_queue (SoupSessionAsync *sa, gboolean try_pruning)
+{
+ SoupSession *session = SOUP_SESSION (sa);
+ SoupMessageQueueIter iter;
+ SoupMessage *msg;
+ SoupConnection *conn;
+ gboolean should_prune = FALSE, started_any = FALSE, is_new;
+
+ /* FIXME: prefer CONNECTING messages */
+
+ try_again:
+ for (msg = soup_message_queue_first (session->queue, &iter); msg; msg = soup_message_queue_next (session->queue, &iter)) {
+
+ if (!SOUP_MESSAGE_IS_STARTING (msg))
+ continue;
+
+ conn = soup_session_get_connection (session, msg,
+ &should_prune, &is_new);
+ if (!conn)
+ continue;
+
+ if (is_new) {
+ soup_connection_connect_async (conn, got_connection,
+ session);
+ } else
+ soup_session_send_message_via (session, msg, conn);
+
+ started_any = TRUE;
+ }
+
+ if (try_pruning && should_prune && !started_any) {
+ /* We didn't manage to start any message, but there is
+ * at least one message in the queue that could be
+ * sent if we pruned an idle connection from some
+ * other server.
+ */
+ if (soup_session_try_prune_connection (session)) {
+ try_pruning = FALSE;
+ goto try_again;
+ }
+ }
+
+ return started_any;
+}
+
+static void
+request_restarted (SoupMessage *req, gpointer sa)
+{
+ run_queue (sa, FALSE);
+}
+
+static void
+final_finished (SoupMessage *req, gpointer user_data)
+{
+ SoupSessionAsync *sa = user_data;
+
+ if (!SOUP_MESSAGE_IS_STARTING (req)) {
+ g_signal_handlers_disconnect_by_func (req, request_finished, sa);
+ g_signal_handlers_disconnect_by_func (req, final_finished, sa);
+ g_object_unref (req);
+ }
+
+ run_queue (sa, FALSE);
+}
+
+static void
+queue_message (SoupSession *session, SoupMessage *req,
+ SoupMessageCallbackFn callback, gpointer user_data)
+{
+ SoupSessionAsync *sa = SOUP_SESSION_ASYNC (session);
+
+ g_signal_connect (req, "restarted",
+ G_CALLBACK (request_restarted), sa);
+
+ g_signal_connect (req, "finished",
+ G_CALLBACK (request_finished), sa);
+ if (callback) {
+ g_signal_connect (req, "finished",
+ G_CALLBACK (callback), user_data);
+ }
+ g_signal_connect_after (req, "finished",
+ G_CALLBACK (final_finished), sa);
+
+ SOUP_SESSION_CLASS (parent_class)->queue_message (session, req,
+ callback, user_data);
+
+ run_queue (sa, TRUE);
+}
+
+static guint
+send_message (SoupSession *session, SoupMessage *req)
+{
+ /* Balance out the unref that final_finished will do */
+ g_object_ref (req);
+
+ queue_message (session, req, NULL, NULL);
+
+ while (req->status != SOUP_MESSAGE_STATUS_FINISHED &&
+ !SOUP_STATUS_IS_TRANSPORT_ERROR (req->status_code))
+ g_main_iteration (TRUE);
+
+ return req->status_code;
+}
diff --git a/libsoup/soup-session-async.h b/libsoup/soup-session-async.h
new file mode 100644
index 00000000..26f5fe75
--- /dev/null
+++ b/libsoup/soup-session-async.h
@@ -0,0 +1,39 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2000-2003, Ximian, Inc.
+ */
+
+#ifndef SOUP_SESSION_ASYNC_H
+#define SOUP_SESSION_ASYNC_H 1
+
+#include <libsoup/soup-types.h>
+#include <libsoup/soup-session.h>
+
+#define SOUP_TYPE_SESSION_ASYNC (soup_session_async_get_type ())
+#define SOUP_SESSION_ASYNC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SOUP_TYPE_SESSION_ASYNC, SoupSessionAsync))
+#define SOUP_SESSION_ASYNC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SOUP_TYPE_SESSION_ASYNC, SoupSessionAsyncClass))
+#define SOUP_IS_SESSION_ASYNC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SOUP_TYPE_SESSION_ASYNC))
+#define SOUP_IS_SESSION_ASYNC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), SOUP_TYPE_SESSION_ASYNC))
+#define SOUP_SESSION_ASYNC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SOUP_TYPE_SESSION_ASYNC, SoupSessionAsyncClass))
+
+typedef struct SoupSessionAsyncPrivate SoupSessionAsyncPrivate;
+
+struct SoupSessionAsync {
+ SoupSession parent;
+
+ SoupSessionAsyncPrivate *priv;
+};
+
+typedef struct {
+ SoupSessionClass parent_class;
+
+} SoupSessionAsyncClass;
+
+GType soup_session_async_get_type (void);
+
+SoupSession *soup_session_async_new (void);
+SoupSession *soup_session_async_new_with_options (const char *optname1,
+ ...);
+
+
+#endif /* SOUP_SESSION_ASYNC_H */
diff --git a/libsoup/soup-session-sync.c b/libsoup/soup-session-sync.c
new file mode 100644
index 00000000..5c078041
--- /dev/null
+++ b/libsoup/soup-session-sync.c
@@ -0,0 +1,197 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * soup-session-sync.c
+ *
+ * Copyright (C) 2000-2003, Ximian, Inc.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "soup-session-sync.h"
+#include "soup-connection.h"
+
+struct SoupSessionSyncPrivate {
+ GMutex *lock;
+ GCond *cond;
+};
+
+void queue_message (SoupSession *session, SoupMessage *msg,
+ SoupMessageCallbackFn callback,
+ gpointer user_data);
+static guint send_message (SoupSession *session, SoupMessage *msg);
+static void cancel_message (SoupSession *session, SoupMessage *msg);
+
+#define PARENT_TYPE SOUP_TYPE_SESSION
+static SoupSessionClass *parent_class;
+
+static void
+init (GObject *object)
+{
+ SoupSessionSync *ss = SOUP_SESSION_SYNC (object);
+
+ ss->priv = g_new0 (SoupSessionSyncPrivate, 1);
+ ss->priv->lock = g_mutex_new ();
+ ss->priv->cond = g_cond_new ();
+}
+
+static void
+finalize (GObject *object)
+{
+ SoupSessionSync *ss = SOUP_SESSION_SYNC (object);
+
+ g_mutex_free (ss->priv->lock);
+ g_cond_free (ss->priv->cond);
+ g_free (ss->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+class_init (GObjectClass *object_class)
+{
+ SoupSessionClass *session_class = SOUP_SESSION_CLASS (object_class);
+
+ parent_class = g_type_class_ref (PARENT_TYPE);
+
+ /* virtual method override */
+ session_class->queue_message = queue_message;
+ session_class->send_message = send_message;
+ session_class->cancel_message = cancel_message;
+ object_class->finalize = finalize;
+}
+
+SOUP_MAKE_TYPE (soup_session_sync, SoupSessionSync, class_init, init, PARENT_TYPE)
+
+SoupSession *
+soup_session_sync_new (void)
+{
+ return g_object_new (SOUP_TYPE_SESSION_SYNC, NULL);
+}
+
+SoupSession *
+soup_session_sync_new_with_options (const char *optname1, ...)
+{
+ SoupSession *session;
+ va_list ap;
+
+ va_start (ap, optname1);
+ session = (SoupSession *)g_object_new_valist (SOUP_TYPE_SESSION_SYNC,
+ optname1, ap);
+ va_end (ap);
+
+ return session;
+}
+
+
+void
+queue_message (SoupSession *session, SoupMessage *msg,
+ SoupMessageCallbackFn callback, gpointer user_data)
+{
+ /* FIXME */
+ g_warning ("soup_session_queue_message called on synchronous session");
+}
+
+static SoupConnection *
+wait_for_connection (SoupSession *session, SoupMessage *msg)
+{
+ SoupSessionSync *ss = SOUP_SESSION_SYNC (session);
+ SoupConnection *conn;
+ gboolean try_pruning = FALSE, is_new = FALSE;
+ guint status;
+
+ g_mutex_lock (ss->priv->lock);
+
+ try_again:
+ conn = soup_session_get_connection (session, msg,
+ &try_pruning, &is_new);
+ if (conn) {
+ if (is_new) {
+ status = soup_connection_connect_sync (conn);
+
+ /* If the connection attempt fails, SoupSession
+ * will notice, unref conn, and set an error
+ * status on msg. So all we need to do is just
+ * not return the no-longer-valid connection.
+ */
+
+ if (!SOUP_STATUS_IS_SUCCESSFUL (status))
+ conn = NULL;
+ else if (msg->status == SOUP_MESSAGE_STATUS_FINISHED) {
+ /* Message was cancelled while we were
+ * connecting.
+ */
+ soup_connection_disconnect (conn);
+ conn = NULL;
+ }
+ }
+
+ g_mutex_unlock (ss->priv->lock);
+ return conn;
+ }
+
+ if (try_pruning && soup_session_try_prune_connection (session))
+ goto try_again;
+
+ /* Wait... */
+ g_cond_wait (ss->priv->cond, ss->priv->lock);
+
+ /* See if something bad happened */
+ if (msg->status == SOUP_MESSAGE_STATUS_FINISHED) {
+ g_mutex_unlock (ss->priv->lock);
+ return NULL;
+ }
+
+ goto try_again;
+}
+
+static guint
+send_message (SoupSession *session, SoupMessage *msg)
+{
+ SoupConnection *conn;
+
+ SOUP_SESSION_CLASS (parent_class)->queue_message (session, msg,
+ NULL, NULL);
+
+ do {
+ /* Get a connection */
+ conn = wait_for_connection (session, msg);
+ if (!conn)
+ return msg->status_code;
+
+ /* Set up a weak pointer so that "conn" is zeroed out
+ * if the connection is destroyed.
+ */
+ g_object_add_weak_pointer (G_OBJECT (conn),
+ (gpointer *)&conn);
+
+ /* Now repeatedly send the message across the connection
+ * 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);
+
+ if (conn) {
+ g_object_remove_weak_pointer (G_OBJECT (conn),
+ (gpointer *)&conn);
+ }
+
+ /* If the message isn't finished, that means we need to
+ * re-send it on a new connection, so loop back to the
+ * beginning.
+ */
+ } while (msg->status != SOUP_MESSAGE_STATUS_FINISHED);
+
+ return msg->status_code;
+}
+
+static void
+cancel_message (SoupSession *session, SoupMessage *msg)
+{
+ SoupSessionSync *ss = SOUP_SESSION_SYNC (session);
+
+ SOUP_SESSION_CLASS (parent_class)->cancel_message (session, msg);
+ g_cond_broadcast (ss->priv->cond);
+}
+
diff --git a/libsoup/soup-session-sync.h b/libsoup/soup-session-sync.h
new file mode 100644
index 00000000..87652791
--- /dev/null
+++ b/libsoup/soup-session-sync.h
@@ -0,0 +1,39 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2000-2003, Ximian, Inc.
+ */
+
+#ifndef SOUP_SESSION_SYNC_H
+#define SOUP_SESSION_SYNC_H 1
+
+#include <libsoup/soup-types.h>
+#include <libsoup/soup-session.h>
+
+#define SOUP_TYPE_SESSION_SYNC (soup_session_sync_get_type ())
+#define SOUP_SESSION_SYNC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SOUP_TYPE_SESSION_SYNC, SoupSessionSync))
+#define SOUP_SESSION_SYNC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SOUP_TYPE_SESSION_SYNC, SoupSessionSyncClass))
+#define SOUP_IS_SESSION_SYNC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SOUP_TYPE_SESSION_SYNC))
+#define SOUP_IS_SESSION_SYNC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), SOUP_TYPE_SESSION_SYNC))
+#define SOUP_SESSION_SYNC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SOUP_TYPE_SESSION_SYNC, SoupSessionSyncClass))
+
+typedef struct SoupSessionSyncPrivate SoupSessionSyncPrivate;
+
+struct SoupSessionSync {
+ SoupSession parent;
+
+ SoupSessionSyncPrivate *priv;
+};
+
+typedef struct {
+ SoupSessionClass parent_class;
+
+} SoupSessionSyncClass;
+
+GType soup_session_sync_get_type (void);
+
+SoupSession *soup_session_sync_new (void);
+SoupSession *soup_session_sync_new_with_options (const char *optname1,
+ ...);
+
+
+#endif /* SOUP_SESSION_SYNC_H */
diff --git a/libsoup/soup-session.c b/libsoup/soup-session.c
index bc4d79c1..65da4641 100644
--- a/libsoup/soup-session.c
+++ b/libsoup/soup-session.c
@@ -24,7 +24,6 @@
typedef struct {
SoupUri *root_uri;
- guint error;
GSList *connections; /* CONTAINS: SoupConnection */
guint num_conns;
@@ -41,20 +40,28 @@ struct SoupSessionPrivate {
char *ssl_ca_file;
gpointer ssl_creds;
- SoupMessageQueue *queue;
-
GHashTable *hosts; /* SoupUri -> SoupSessionHost */
GHashTable *conns; /* SoupConnection -> SoupSessionHost */
guint num_conns;
SoupSessionHost *proxy_host;
+
+ /* Must hold the host_lock before potentially creating a
+ * new SoupSessionHost, or adding/removing a connection.
+ * Must not emit signals or destroy objects while holding it.
+ */
+ GMutex *host_lock;
};
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 gboolean run_queue (SoupSession *session, gboolean try_pruning);
+static void queue_message (SoupSession *session, SoupMessage *msg,
+ SoupMessageCallbackFn callback,
+ gpointer user_data);
+static void requeue_message (SoupSession *session, SoupMessage *msg);
+static void cancel_message (SoupSession *session, SoupMessage *msg);
#define SOUP_SESSION_MAX_CONNS_DEFAULT 10
#define SOUP_SESSION_MAX_CONNS_PER_HOST_DEFAULT 4
@@ -93,7 +100,8 @@ init (GObject *object)
SoupSession *session = SOUP_SESSION (object);
session->priv = g_new0 (SoupSessionPrivate, 1);
- session->priv->queue = soup_message_queue_new ();
+ session->priv->host_lock = g_mutex_new ();
+ session->queue = soup_message_queue_new ();
session->priv->hosts = g_hash_table_new (host_uri_hash,
host_uri_equal);
session->priv->conns = g_hash_table_new (NULL, NULL);
@@ -132,7 +140,8 @@ finalize (GObject *object)
{
SoupSession *session = SOUP_SESSION (object);
- soup_message_queue_destroy (session->priv->queue);
+ g_mutex_free (session->priv->host_lock);
+ soup_message_queue_destroy (session->queue);
g_hash_table_destroy (session->priv->hosts);
g_hash_table_destroy (session->priv->conns);
g_free (session->priv);
@@ -143,8 +152,15 @@ finalize (GObject *object)
static void
class_init (GObjectClass *object_class)
{
+ SoupSessionClass *session_class = SOUP_SESSION_CLASS (object_class);
+
parent_class = g_type_class_ref (PARENT_TYPE);
+ /* virtual method definition */
+ session_class->queue_message = queue_message;
+ session_class->requeue_message = requeue_message;
+ session_class->cancel_message = cancel_message;
+
/* virtual method override */
object_class->dispose = dispose;
object_class->finalize = finalize;
@@ -222,32 +238,13 @@ class_init (GObjectClass *object_class)
SOUP_MAKE_TYPE (soup_session, SoupSession, class_init, init, PARENT_TYPE)
-SoupSession *
-soup_session_new (void)
-{
- return g_object_new (SOUP_TYPE_SESSION, NULL);
-}
-
-SoupSession *
-soup_session_new_with_options (const char *optname1, ...)
-{
- SoupSession *session;
- va_list ap;
-
- va_start (ap, optname1);
- session = (SoupSession *)g_object_new_valist (SOUP_TYPE_SESSION, optname1, ap);
- va_end (ap);
-
- return session;
-}
-
static gboolean
safe_uri_equal (const SoupUri *a, const SoupUri *b)
{
if (!a && !b)
return TRUE;
- if (a && !b || b && !a)
+ if ((a && !b) || (b && !a))
return FALSE;
return soup_uri_equal (a, b);
@@ -367,6 +364,10 @@ soup_session_host_new (SoupSession *session, const SoupUri *source_uri)
return host;
}
+/* Note: get_host_for_message doesn't lock the host_lock. The caller
+ * must do it itself if there's a chance the host doesn't already
+ * exist.
+ */
static SoupSessionHost *
get_host_for_message (SoupSession *session, SoupMessage *msg)
{
@@ -378,21 +379,22 @@ get_host_for_message (SoupSession *session, SoupMessage *msg)
return host;
host = soup_session_host_new (session, source);
-
g_hash_table_insert (session->priv->hosts, host->root_uri, host);
return host;
}
+/* Note: get_proxy_host doesn't lock the host_lock. The caller must do
+ * it itself if there's a chance the host doesn't already exist.
+ */
static SoupSessionHost *
get_proxy_host (SoupSession *session)
{
- if (session->priv->proxy_host)
+ if (session->priv->proxy_host || !session->priv->proxy_uri)
return session->priv->proxy_host;
session->priv->proxy_host =
soup_session_host_new (session, session->priv->proxy_uri);
-
return session->priv->proxy_host;
}
@@ -430,6 +432,7 @@ free_host (SoupSessionHost *host, SoupSession *session)
}
soup_uri_free (host->root_uri);
+ g_free (host);
}
/* Authentication */
@@ -627,8 +630,8 @@ update_auth_internal (SoupSession *session, SoupMessage *msg,
/* If we need to authenticate, try to do it. */
if (!soup_auth_is_authenticated (new_auth)) {
- return authenticate_auth (session, new_auth, msg,
- prior_auth_failed, proxy);
+ return authenticate_auth (session, new_auth,
+ msg, prior_auth_failed, proxy);
}
/* Otherwise we're good. */
@@ -689,47 +692,17 @@ redirect_handler (SoupMessage *msg, gpointer user_data)
if (!new_loc)
return;
new_uri = soup_uri_new (new_loc);
- if (!new_uri)
- goto INVALID_REDIRECT;
+ if (!new_uri) {
+ soup_message_set_status_full (msg,
+ SOUP_STATUS_MALFORMED,
+ "Invalid Redirect URL");
+ return;
+ }
soup_message_set_uri (msg, new_uri);
soup_uri_free (new_uri);
soup_session_requeue_message (session, msg);
- return;
-
- INVALID_REDIRECT:
- soup_message_set_status_full (msg,
- SOUP_STATUS_MALFORMED,
- "Invalid Redirect URL");
-}
-
-static void
-request_restarted (SoupMessage *req, gpointer session)
-{
- run_queue (session, FALSE);
-}
-
-static void
-request_finished (SoupMessage *req, gpointer user_data)
-{
- req->status = SOUP_MESSAGE_STATUS_FINISHED;
-}
-
-static void
-final_finished (SoupMessage *req, gpointer user_data)
-{
- SoupSession *session = user_data;
-
- if (!SOUP_MESSAGE_IS_STARTING (req)) {
- soup_message_queue_remove_message (session->priv->queue, req);
-
- g_signal_handlers_disconnect_by_func (req, request_finished, session);
- g_signal_handlers_disconnect_by_func (req, final_finished, session);
- g_object_unref (req);
- }
-
- run_queue (session, FALSE);
}
static void
@@ -755,15 +728,16 @@ add_auth (SoupSession *session, SoupMessage *msg, gboolean proxy)
}
}
-static void
-send_request (SoupSession *session, SoupMessage *req, SoupConnection *conn)
+void
+soup_session_send_message_via (SoupSession *session, SoupMessage *msg,
+ SoupConnection *conn)
{
- req->status = SOUP_MESSAGE_STATUS_RUNNING;
+ msg->status = SOUP_MESSAGE_STATUS_RUNNING;
- add_auth (session, req, FALSE);
+ add_auth (session, msg, FALSE);
if (session->priv->proxy_uri)
- add_auth (session, req, TRUE);
- soup_connection_send_request (conn, req);
+ add_auth (session, msg, TRUE);
+ soup_connection_send_request (conn, msg);
}
static void
@@ -771,8 +745,11 @@ find_oldest_connection (gpointer key, gpointer host, gpointer data)
{
SoupConnection *conn = key, **oldest = data;
- /* Don't prune a connection that hasn't even been used yet. */
- if (soup_connection_last_used (conn) == 0)
+ /* Don't prune a connection that is currently in use, or
+ * hasn't been used yet.
+ */
+ if (soup_connection_is_in_use (conn) ||
+ soup_connection_last_used (conn) == 0)
return;
if (!*oldest || (soup_connection_last_used (conn) <
@@ -780,67 +757,86 @@ find_oldest_connection (gpointer key, gpointer host, gpointer data)
*oldest = conn;
}
-static gboolean
-try_prune_connection (SoupSession *session)
+/**
+ * soup_session_try_prune_connection:
+ * @session: a #SoupSession
+ *
+ * Finds the least-recently-used idle connection in @session and closes
+ * it.
+ *
+ * Return value: %TRUE if a connection was closed, %FALSE if there are
+ * no idle connections.
+ **/
+gboolean
+soup_session_try_prune_connection (SoupSession *session)
{
SoupConnection *oldest = NULL;
+ g_mutex_lock (session->priv->host_lock);
g_hash_table_foreach (session->priv->conns, find_oldest_connection,
&oldest);
if (oldest) {
+ /* Ref the connection before unlocking the mutex in
+ * case someone else tries to prune it too.
+ */
+ g_object_ref (oldest);
+ g_mutex_unlock (session->priv->host_lock);
soup_connection_disconnect (oldest);
g_object_unref (oldest);
return TRUE;
- } else
+ } else {
+ g_mutex_unlock (session->priv->host_lock);
return FALSE;
+ }
}
-static void connection_closed (SoupConnection *conn, SoupSession *session);
-
static void
-cleanup_connection (SoupSession *session, SoupConnection *conn)
+connection_disconnected (SoupConnection *conn, gpointer user_data)
{
- SoupSessionHost *host =
- g_hash_table_lookup (session->priv->conns, conn);
+ SoupSession *session = user_data;
+ SoupSessionHost *host;
- g_return_if_fail (host != NULL);
+ g_mutex_lock (session->priv->host_lock);
- g_hash_table_remove (session->priv->conns, conn);
- g_signal_handlers_disconnect_by_func (conn, connection_closed, session);
- session->priv->num_conns--;
-
- host->connections = g_slist_remove (host->connections, conn);
- host->num_conns--;
-}
+ host = g_hash_table_lookup (session->priv->conns, conn);
+ if (host) {
+ g_hash_table_remove (session->priv->conns, conn);
+ host->connections = g_slist_remove (host->connections, conn);
+ host->num_conns--;
+ }
-static void
-connection_closed (SoupConnection *conn, SoupSession *session)
-{
- cleanup_connection (session, conn);
+ g_signal_handlers_disconnect_by_func (conn, connection_disconnected, session);
+ session->priv->num_conns--;
- /* Run the queue in case anyone was waiting for a connection
- * to be closed.
- */
- run_queue (session, FALSE);
+ g_mutex_unlock (session->priv->host_lock);
+ g_object_unref (conn);
}
static void
-got_connection (SoupConnection *conn, guint status, gpointer user_data)
+connect_result (SoupConnection *conn, guint status, gpointer user_data)
{
SoupSession *session = user_data;
- SoupSessionHost *host = g_hash_table_lookup (session->priv->conns, conn);
+ SoupSessionHost *host;
+ SoupMessageQueueIter iter;
+ SoupMessage *msg;
- g_return_if_fail (host != NULL);
+ g_mutex_lock (session->priv->host_lock);
+
+ host = g_hash_table_lookup (session->priv->conns, conn);
+ if (!host) {
+ g_mutex_unlock (session->priv->host_lock);
+ return;
+ }
if (status == SOUP_STATUS_OK) {
host->connections = g_slist_prepend (host->connections, conn);
- run_queue (session, FALSE);
+ g_mutex_unlock (session->priv->host_lock);
return;
}
- /* We failed */
- cleanup_connection (session, conn);
- g_object_unref (conn);
+ /* The connection failed. */
+ g_mutex_unlock (session->priv->host_lock);
+ connection_disconnected (conn, session);
if (host->connections) {
/* Something went wrong this time, but we have at
@@ -851,240 +847,258 @@ got_connection (SoupConnection *conn, guint status, gpointer user_data)
return;
}
- /* Flush any queued messages for this host */
- host->error = status;
- run_queue (session, FALSE);
-
- if (status != SOUP_STATUS_CANT_RESOLVE &&
- status != SOUP_STATUS_CANT_RESOLVE_PROXY) {
- /* If the error was "can't resolve", then it's not likely
- * to improve. But if it was something else, it may have
- * been transient, so we clear the error so the user can
- * try again later.
- */
- host->error = 0;
+ /* It's hopeless. Cancel everything that was waiting for this host. */
+ 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);
+ }
}
}
-static gboolean
-run_queue (SoupSession *session, gboolean try_pruning)
+/**
+ * soup_session_get_connection:
+ * @session: a #SoupSession
+ * @msg: a #SoupMessage
+ * @try_pruning: on return, whether or not to try pruning a connection
+ * @is_new: on return, %TRUE if the returned connection is new and not
+ * yet connected
+ *
+ * Tries to find or create a connection for @msg. If there is an idle
+ * connection to the relevant host available, then it will be returned
+ * (with *@is_new set to %FALSE). Otherwise, if it is possible to
+ * create a new connection, one will be created and returned, with
+ * *@is_new set to %TRUE.
+ *
+ * If no connection can be made, it will return %NULL. If @session has
+ * the maximum number of open connections open, but does not have the
+ * maximum number of per-host connections open to the relevant host, then
+ * *@try_pruning will be set to %TRUE. In this case, the caller can
+ * call soup_session_try_prune_connection() to close an idle connection,
+ * and then try soup_session_get_connection() again. (If calling
+ * soup_session_try_prune_connection() wouldn't help, then *@try_pruning
+ * is left untouched; it is NOT set to %FALSE.)
+ *
+ * Return value: a #SoupConnection, or %NULL
+ **/
+SoupConnection *
+soup_session_get_connection (SoupSession *session, SoupMessage *msg,
+ gboolean *try_pruning, gboolean *is_new)
{
- SoupMessageQueueIter iter;
- SoupMessage *msg;
SoupConnection *conn;
SoupSessionHost *host;
- gboolean skipped_any = FALSE, started_any = FALSE;
GSList *conns;
- /* FIXME: prefer CONNECTING messages */
-
- try_again:
- for (msg = soup_message_queue_first (session->priv->queue, &iter); msg; msg = soup_message_queue_next (session->priv->queue, &iter)) {
-
- if (!SOUP_MESSAGE_IS_STARTING (msg))
- continue;
-
- host = get_host_for_message (session, msg);
+ g_mutex_lock (session->priv->host_lock);
- /* If the hostname is known to be bad, fail right away */
- if (host->error) {
- soup_message_set_status (msg, host->error);
- msg->status = SOUP_MESSAGE_STATUS_FINISHED;
- soup_message_finished (msg);
+ host = get_host_for_message (session, msg);
+ for (conns = host->connections; conns; conns = conns->next) {
+ if (!soup_connection_is_in_use (conns->data)) {
+ soup_connection_reserve (conns->data);
+ g_mutex_unlock (session->priv->host_lock);
+ *is_new = FALSE;
+ return conns->data;
}
+ }
- /* If there is an idle connection, use it */
- for (conns = host->connections; conns; conns = conns->next) {
- if (!soup_connection_is_in_use (conns->data))
- break;
- }
- if (conns) {
- send_request (session, msg, conns->data);
- started_any = TRUE;
- continue;
- }
+ if (msg->status == SOUP_MESSAGE_STATUS_CONNECTING) {
+ /* We already started a connection for this
+ * message, so don't start another one.
+ */
+ g_mutex_unlock (session->priv->host_lock);
+ return NULL;
+ }
- if (msg->status == SOUP_MESSAGE_STATUS_CONNECTING) {
- /* We already started a connection for this
- * message, so don't start another one.
- */
- continue;
- }
+ if (host->num_conns >= session->priv->max_conns_per_host) {
+ g_mutex_unlock (session->priv->host_lock);
+ return NULL;
+ }
- /* If we have the max number of per-host connections
- * or total connections open, we'll have to wait.
- */
- if (host->num_conns >= session->priv->max_conns_per_host)
- continue;
- else if (session->priv->num_conns >= session->priv->max_conns) {
- /* In this case, closing an idle connection
- * somewhere else would let us open one here.
- */
- skipped_any = TRUE;
- continue;
- }
+ if (session->priv->num_conns >= session->priv->max_conns) {
+ *try_pruning = TRUE;
+ g_mutex_unlock (session->priv->host_lock);
+ return NULL;
+ }
- /* Otherwise, open a new connection */
- conn = g_object_new (
- (session->priv->use_ntlm ?
- SOUP_TYPE_CONNECTION_NTLM : SOUP_TYPE_CONNECTION),
- SOUP_CONNECTION_ORIGIN_URI, host->root_uri,
- SOUP_CONNECTION_PROXY_URI, session->priv->proxy_uri,
- SOUP_CONNECTION_SSL_CREDENTIALS, session->priv->ssl_creds,
- NULL);
- g_signal_connect (conn, "authenticate",
- G_CALLBACK (connection_authenticate),
- session);
- g_signal_connect (conn, "reauthenticate",
- G_CALLBACK (connection_reauthenticate),
- session);
-
- soup_connection_connect_async (conn, got_connection, session);
- g_signal_connect (conn, "disconnected",
- G_CALLBACK (connection_closed), session);
- g_hash_table_insert (session->priv->conns, conn, host);
- session->priv->num_conns++;
-
- /* Increment the host's connection count, but don't add
- * this connection to the list yet, since it's not ready.
- */
- host->num_conns++;
+ /* Make sure session->priv->proxy_host gets set now while
+ * we have the host_lock.
+ */
+ if (session->priv->proxy_uri)
+ get_proxy_host (session);
+
+ conn = g_object_new (
+ (session->priv->use_ntlm ?
+ SOUP_TYPE_CONNECTION_NTLM : SOUP_TYPE_CONNECTION),
+ SOUP_CONNECTION_ORIGIN_URI, host->root_uri,
+ SOUP_CONNECTION_PROXY_URI, session->priv->proxy_uri,
+ SOUP_CONNECTION_SSL_CREDENTIALS, session->priv->ssl_creds,
+ NULL);
+ g_signal_connect (conn, "connect_result",
+ G_CALLBACK (connect_result),
+ session);
+ g_signal_connect (conn, "disconnected",
+ G_CALLBACK (connection_disconnected),
+ session);
+ g_signal_connect (conn, "authenticate",
+ G_CALLBACK (connection_authenticate),
+ session);
+ g_signal_connect (conn, "reauthenticate",
+ G_CALLBACK (connection_reauthenticate),
+ session);
+
+ g_hash_table_insert (session->priv->conns, conn, host);
+
+ /* We increment the connection counts so it counts against the
+ * totals, but we don't add it to the host's connection list
+ * yet, since it's not ready for use.
+ */
+ session->priv->num_conns++;
+ host->num_conns++;
- /* Mark the request as connecting, so we don't try to
- * open another new connection for it next time around.
- */
- msg->status = SOUP_MESSAGE_STATUS_CONNECTING;
+ /* Mark the request as connecting, so we don't try to open
+ * another new connection for it while waiting for this one.
+ */
+ msg->status = SOUP_MESSAGE_STATUS_CONNECTING;
- started_any = TRUE;
- }
+ g_mutex_unlock (session->priv->host_lock);
+ *is_new = TRUE;
+ return conn;
+}
- if (try_pruning && skipped_any && !started_any) {
- /* We didn't manage to start any message, but there is
- * at least one message in the queue that could be
- * sent if we pruned an idle connection from some
- * other server.
- */
- if (try_prune_connection (session)) {
- try_pruning = FALSE;
- goto try_again;
- }
- }
+static void
+message_finished (SoupMessage *msg, gpointer user_data)
+{
+ SoupSession *session = user_data;
- return started_any;
+ if (!SOUP_MESSAGE_IS_STARTING (msg)) {
+ soup_message_queue_remove_message (session->queue, msg);
+ g_signal_handlers_disconnect_by_func (msg, message_finished, session);
+ }
}
static void
-queue_message (SoupSession *session, SoupMessage *req, gboolean requeue)
+queue_message (SoupSession *session, SoupMessage *msg,
+ SoupMessageCallbackFn callback, gpointer user_data)
{
- req->status = SOUP_MESSAGE_STATUS_QUEUED;
- if (!requeue) {
- soup_message_queue_append (session->priv->queue, req);
- run_queue (session, TRUE);
+ 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,
+ SOUP_HANDLER_POST_BODY,
+ redirect_handler, session);
}
+
+ msg->status = SOUP_MESSAGE_STATUS_QUEUED;
+ soup_message_queue_append (session->queue, msg);
}
/**
* soup_session_queue_message:
* @session: a #SoupSession
- * @req: the message to queue
+ * @msg: the message to queue
* @callback: a #SoupMessageCallbackFn which will be called after the
* message completes or when an unrecoverable error occurs.
* @user_data: a pointer passed to @callback.
*
- * Queues the message @req for sending. All messages are processed
- * while the glib main loop runs. If @req has been processed before,
+ * Queues the message @msg for sending. All messages are processed
+ * while the glib main loop runs. If @msg has been processed before,
* any resources related to the time it was last sent are freed.
*
* Upon message completion, the callback specified in @callback will
* be invoked. If after returning from this callback the message has
- * not been requeued, @req will be unreffed.
+ * not been requeued, @msg will be unreffed.
*/
void
-soup_session_queue_message (SoupSession *session, SoupMessage *req,
+soup_session_queue_message (SoupSession *session, SoupMessage *msg,
SoupMessageCallbackFn callback, gpointer user_data)
{
g_return_if_fail (SOUP_IS_SESSION (session));
- g_return_if_fail (SOUP_IS_MESSAGE (req));
-
- g_signal_connect (req, "restarted",
- G_CALLBACK (request_restarted), session);
-
- g_signal_connect (req, "finished",
- G_CALLBACK (request_finished), session);
-
- if (callback) {
- g_signal_connect (req, "finished",
- G_CALLBACK (callback), user_data);
- }
-
- g_signal_connect_after (req, "finished",
- G_CALLBACK (final_finished), session);
-
- soup_message_add_status_code_handler (req, SOUP_STATUS_UNAUTHORIZED,
- SOUP_HANDLER_POST_BODY,
- authorize_handler, session);
- soup_message_add_status_code_handler (req,
- SOUP_STATUS_PROXY_UNAUTHORIZED,
- SOUP_HANDLER_POST_BODY,
- authorize_handler, session);
+ g_return_if_fail (SOUP_IS_MESSAGE (msg));
- if (!(soup_message_get_flags (req) & SOUP_MESSAGE_NO_REDIRECT)) {
- soup_message_add_status_class_handler (
- req, SOUP_STATUS_CLASS_REDIRECT,
- SOUP_HANDLER_POST_BODY,
- redirect_handler, session);
- }
+ SOUP_SESSION_GET_CLASS (session)->queue_message (session, msg,
+ callback, user_data);
+}
- queue_message (session, req, FALSE);
+static void
+requeue_message (SoupSession *session, SoupMessage *msg)
+{
+ msg->status = SOUP_MESSAGE_STATUS_QUEUED;
}
/**
* soup_session_requeue_message:
* @session: a #SoupSession
- * @req: the message to requeue
+ * @msg: the message to requeue
*
- * This causes @req to be placed back on the queue to be attempted
+ * This causes @msg to be placed back on the queue to be attempted
* again.
**/
void
-soup_session_requeue_message (SoupSession *session, SoupMessage *req)
+soup_session_requeue_message (SoupSession *session, SoupMessage *msg)
{
g_return_if_fail (SOUP_IS_SESSION (session));
- g_return_if_fail (SOUP_IS_MESSAGE (req));
+ g_return_if_fail (SOUP_IS_MESSAGE (msg));
- queue_message (session, req, TRUE);
+ SOUP_SESSION_GET_CLASS (session)->requeue_message (session, msg);
}
/**
* soup_session_send_message:
* @session: a #SoupSession
- * @req: the message to send
+ * @msg: the message to send
*
- * Synchronously send @req. This call will not return until the
+ * Synchronously send @msg. This call will not return until the
* transfer is finished successfully or there is an unrecoverable
* error.
*
- * @req is not freed upon return.
+ * @msg is not freed upon return.
*
* Return value: the HTTP status code of the response
*/
guint
-soup_session_send_message (SoupSession *session, SoupMessage *req)
+soup_session_send_message (SoupSession *session, SoupMessage *msg)
{
g_return_val_if_fail (SOUP_IS_SESSION (session), SOUP_STATUS_MALFORMED);
- g_return_val_if_fail (SOUP_IS_MESSAGE (req), SOUP_STATUS_MALFORMED);
+ g_return_val_if_fail (SOUP_IS_MESSAGE (msg), SOUP_STATUS_MALFORMED);
- /* Balance out the unref that final_finished will do */
- g_object_ref (req);
+ return SOUP_SESSION_GET_CLASS (session)->send_message (session, msg);
+}
- soup_session_queue_message (session, req, NULL, NULL);
- while (req->status != SOUP_MESSAGE_STATUS_FINISHED &&
- !SOUP_STATUS_IS_TRANSPORT_ERROR (req->status_code))
- g_main_iteration (TRUE);
+static void
+cancel_message (SoupSession *session, SoupMessage *msg)
+{
+ soup_message_queue_remove_message (session->queue, msg);
+ soup_message_finished (msg);
+}
- return req->status_code;
+/**
+ * soup_session_cancel_message:
+ * @session: a #SoupSession
+ * @msg: the message to cancel
+ *
+ * Causes @session to immediately finish processing @msg. You should
+ * set a status code on @msg with soup_message_set_status() before
+ * calling this function.
+ **/
+void
+soup_session_cancel_message (SoupSession *session, SoupMessage *msg)
+{
+ g_return_if_fail (SOUP_IS_SESSION (session));
+ g_return_if_fail (SOUP_IS_MESSAGE (msg));
+
+ SOUP_SESSION_GET_CLASS (session)->cancel_message (session, msg);
}
/**
@@ -1099,8 +1113,10 @@ soup_session_abort (SoupSession *session)
SoupMessageQueueIter iter;
SoupMessage *msg;
- for (msg = soup_message_queue_first (session->priv->queue, &iter); msg; msg = soup_message_queue_next (session->priv->queue, &iter)) {
- soup_message_queue_remove (session->priv->queue, &iter);
- soup_message_cancel (msg);
+ g_return_if_fail (SOUP_IS_SESSION (session));
+
+ for (msg = soup_message_queue_first (session->queue, &iter); msg; msg = soup_message_queue_next (session->queue, &iter)) {
+ soup_message_set_status (msg, SOUP_STATUS_CANCELLED);
+ soup_session_cancel_message (session, msg);
}
}
diff --git a/libsoup/soup-session.h b/libsoup/soup-session.h
index 2f2d9e72..a8f9bf15 100644
--- a/libsoup/soup-session.h
+++ b/libsoup/soup-session.h
@@ -8,6 +8,7 @@
#include <libsoup/soup-types.h>
#include <libsoup/soup-message.h>
+#include <libsoup/soup-message-queue.h>
#define SOUP_TYPE_SESSION (soup_session_get_type ())
#define SOUP_SESSION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SOUP_TYPE_SESSION, SoupSession))
@@ -22,6 +23,9 @@ struct SoupSession {
GObject parent;
SoupSessionPrivate *priv;
+
+ /* protected */
+ SoupMessageQueue *queue;
};
typedef struct {
@@ -35,6 +39,15 @@ typedef struct {
const char *auth_type, const char *auth_realm,
char **username, char **password);
+ /* methods */
+ void (*queue_message) (SoupSession *session, SoupMessage *msg,
+ SoupMessageCallbackFn callback,
+ gpointer user_data);
+ void (*requeue_message) (SoupSession *session, SoupMessage *msg);
+ guint (*send_message) (SoupSession *session, SoupMessage *msg);
+
+ void (*cancel_message) (SoupSession *session, SoupMessage *msg);
+
} SoupSessionClass;
GType soup_session_get_type (void);
@@ -45,21 +58,31 @@ GType soup_session_get_type (void);
#define SOUP_SESSION_USE_NTLM "use-ntlm"
#define SOUP_SESSION_SSL_CA_FILE "ssl-ca-file"
-SoupSession *soup_session_new (void);
-SoupSession *soup_session_new_with_options (const char *optname1,
- ...);
-
void soup_session_queue_message (SoupSession *session,
- SoupMessage *req,
+ SoupMessage *msg,
SoupMessageCallbackFn callback,
gpointer user_data);
void soup_session_requeue_message (SoupSession *session,
- SoupMessage *req);
+ SoupMessage *msg);
guint soup_session_send_message (SoupSession *session,
- SoupMessage *req);
+ SoupMessage *msg);
+void soup_session_cancel_message (SoupSession *session,
+ SoupMessage *msg);
void soup_session_abort (SoupSession *session);
+/* Protected methods */
+SoupConnection *soup_session_get_connection (SoupSession *session,
+ SoupMessage *msg,
+ gboolean *try_pruning,
+ 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-socket.c b/libsoup/soup-socket.c
index 9e6cc9a7..ece538fc 100644
--- a/libsoup/soup-socket.c
+++ b/libsoup/soup-socket.c
@@ -90,11 +90,24 @@ init (GObject *object)
sock->priv->reuseaddr = TRUE;
}
-static void
+static gboolean
disconnect_internal (SoupSocket *sock)
{
- g_io_channel_unref (sock->priv->iochannel);
+ GIOChannel *iochannel;
+
+ /* If we close the socket from one thread while
+ * reading/writing from another, it's possible that the other
+ * thread will get an I/O error and try to close the socket
+ * while we're still in this function. So we clear
+ * sock->priv->iochannel early to make sure that the other
+ * thread's attempt to close the socket becomes a no-op.
+ */
+ iochannel = sock->priv->iochannel;
sock->priv->iochannel = NULL;
+ if (iochannel == NULL)
+ return FALSE;
+
+ g_io_channel_unref (iochannel);
if (sock->priv->read_tag) {
g_source_remove (sock->priv->read_tag);
@@ -108,6 +121,8 @@ disconnect_internal (SoupSocket *sock)
g_source_remove (sock->priv->error_tag);
sock->priv->error_tag = 0;
}
+
+ return TRUE;
}
static void
@@ -471,9 +486,11 @@ soup_socket_connect (SoupSocket *sock, SoupAddress *remote_addr)
if (sock->priv->non_blocking) {
sock->priv->watch = g_idle_add (idle_connect_result, sock);
return SOUP_STATUS_CONTINUE;
- } else {
- return sock->priv->sockfd != -1 ?
- SOUP_STATUS_OK : SOUP_STATUS_CANT_CONNECT;
+ } else if (sock->priv->sockfd == -1)
+ return SOUP_STATUS_CANT_CONNECT;
+ else {
+ get_iochannel (sock);
+ return SOUP_STATUS_OK;
}
}
@@ -723,11 +740,9 @@ soup_socket_disconnect (SoupSocket *sock)
{
g_return_if_fail (SOUP_IS_SOCKET (sock));
- if (!sock->priv->iochannel)
+ if (!disconnect_internal (sock))
return;
- disconnect_internal (sock);
-
/* Give all readers a chance to notice the connection close */
g_signal_emit (sock, signals[READABLE], 0);
diff --git a/libsoup/soup-types.h b/libsoup/soup-types.h
index 17842be7..ffdcbba4 100644
--- a/libsoup/soup-types.h
+++ b/libsoup/soup-types.h
@@ -19,6 +19,8 @@ typedef union SoupServerAuth SoupServerAuth;
typedef struct SoupServerAuthContext SoupServerAuthContext;
typedef struct SoupServerMessage SoupServerMessage;
typedef struct SoupSession SoupSession;
+typedef struct SoupSessionAsync SoupSessionAsync;
+typedef struct SoupSessionSync SoupSessionSync;
typedef struct SoupSocket SoupSocket;
typedef struct SoupUri SoupUri;
diff --git a/libsoup/soup.h b/libsoup/soup.h
index a2f4774e..da67d871 100644
--- a/libsoup/soup.h
+++ b/libsoup/soup.h
@@ -12,7 +12,8 @@ extern "C" {
#include <libsoup/soup-message.h>
#include <libsoup/soup-misc.h>
-#include <libsoup/soup-session.h>
+#include <libsoup/soup-session-async.h>
+#include <libsoup/soup-session-sync.h>
#include <libsoup/soup-socket.h>
#include <libsoup/soup-uri.h>
diff --git a/tests/Makefile.am b/tests/Makefile.am
index cb099e20..9d8fc350 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -17,7 +17,6 @@ get_SOURCES = get.c
simple_httpd_SOURCES = simple-httpd.c
simple_proxy_SOURCES = simple-proxy.c
revserver_SOURCES = revserver.c
-revserver_LDFLAGS = `pkg-config --libs gthread-2.0`
uri_parsing_SOURCES = uri-parsing.c
EXTRA_DIST = libsoup.supp test-cert.pem test-key.pem
diff --git a/tests/auth-test.c b/tests/auth-test.c
index 151a2818..65d7cb4d 100644
--- a/tests/auth-test.c
+++ b/tests/auth-test.c
@@ -37,150 +37,150 @@ typedef struct {
SoupAuthTest tests[] = {
{ "No auth available, should fail",
- "http://primates.ximian.com/~danw/soup-test/Basic/realm1/index.txt",
+ "http://developer.ximian.com/test/soup-test/Basic/realm1/index.txt",
"", "0", SOUP_STATUS_UNAUTHORIZED },
{ "Should fail with no auth, fail again with bad password, and give up",
- "http://primates.ximian.com/~danw/soup-test/Basic/realm2/index.txt",
+ "http://developer.ximian.com/test/soup-test/Basic/realm2/index.txt",
"4", "04", SOUP_STATUS_UNAUTHORIZED },
{ "Known realm, auth provided, so should succeed immediately",
- "http://primates.ximian.com/~danw/soup-test/Basic/realm1/index.txt",
+ "http://developer.ximian.com/test/soup-test/Basic/realm1/index.txt",
"1", "1", SOUP_STATUS_OK },
{ "Now should automatically reuse previous auth",
- "http://primates.ximian.com/~danw/soup-test/Basic/realm1/index.txt",
+ "http://developer.ximian.com/test/soup-test/Basic/realm1/index.txt",
"", "1", SOUP_STATUS_OK },
{ "Subdir should also automatically reuse auth",
- "http://primates.ximian.com/~danw/soup-test/Basic/realm1/subdir/index.txt",
+ "http://developer.ximian.com/test/soup-test/Basic/realm1/subdir/index.txt",
"", "1", SOUP_STATUS_OK },
{ "Subdir should retry last auth, but will fail this time",
- "http://primates.ximian.com/~danw/soup-test/Basic/realm1/realm2/index.txt",
+ "http://developer.ximian.com/test/soup-test/Basic/realm1/realm2/index.txt",
"", "1", SOUP_STATUS_UNAUTHORIZED },
{ "Now should use provided auth on first try",
- "http://primates.ximian.com/~danw/soup-test/Basic/realm1/realm2/index.txt",
+ "http://developer.ximian.com/test/soup-test/Basic/realm1/realm2/index.txt",
"2", "2", SOUP_STATUS_OK },
{ "Reusing last auth. Should succeed on first try",
- "http://primates.ximian.com/~danw/soup-test/Basic/realm1/realm2/index.txt",
+ "http://developer.ximian.com/test/soup-test/Basic/realm1/realm2/index.txt",
"", "2", SOUP_STATUS_OK },
{ "Reuse will fail, but 2nd try will succeed because it's a known realm",
- "http://primates.ximian.com/~danw/soup-test/Basic/realm1/realm2/realm1/index.txt",
+ "http://developer.ximian.com/test/soup-test/Basic/realm1/realm2/realm1/index.txt",
"", "21", SOUP_STATUS_OK },
{ "Should succeed on first try. (Known realm with cached password)",
- "http://primates.ximian.com/~danw/soup-test/Basic/realm2/index.txt",
+ "http://developer.ximian.com/test/soup-test/Basic/realm2/index.txt",
"", "2", SOUP_STATUS_OK },
{ "Fail once, then use typoed password, then use right password",
- "http://primates.ximian.com/~danw/soup-test/Basic/realm3/index.txt",
+ "http://developer.ximian.com/test/soup-test/Basic/realm3/index.txt",
"43", "043", SOUP_STATUS_OK },
{ "No auth available, should fail",
- "http://primates.ximian.com/~danw/soup-test/Digest/realm1/index.txt",
+ "http://developer.ximian.com/test/soup-test/Digest/realm1/index.txt",
"", "0", SOUP_STATUS_UNAUTHORIZED },
{ "Should fail with no auth, fail again with bad password, and give up",
- "http://primates.ximian.com/~danw/soup-test/Digest/realm2/index.txt",
+ "http://developer.ximian.com/test/soup-test/Digest/realm2/index.txt",
"4", "04", SOUP_STATUS_UNAUTHORIZED },
{ "Known realm, auth provided, so should succeed immediately",
- "http://primates.ximian.com/~danw/soup-test/Digest/realm1/index.txt",
+ "http://developer.ximian.com/test/soup-test/Digest/realm1/index.txt",
"1", "1", SOUP_STATUS_OK },
{ "Now should automatically reuse previous auth",
- "http://primates.ximian.com/~danw/soup-test/Digest/realm1/index.txt",
+ "http://developer.ximian.com/test/soup-test/Digest/realm1/index.txt",
"", "1", SOUP_STATUS_OK },
{ "Subdir should also automatically reuse auth",
- "http://primates.ximian.com/~danw/soup-test/Digest/realm1/subdir/index.txt",
+ "http://developer.ximian.com/test/soup-test/Digest/realm1/subdir/index.txt",
"", "1", SOUP_STATUS_OK },
{ "Subdir should retry last auth, but will fail this time",
- "http://primates.ximian.com/~danw/soup-test/Digest/realm1/realm2/index.txt",
+ "http://developer.ximian.com/test/soup-test/Digest/realm1/realm2/index.txt",
"", "1", SOUP_STATUS_UNAUTHORIZED },
{ "Now should use provided auth on first try",
- "http://primates.ximian.com/~danw/soup-test/Digest/realm1/realm2/index.txt",
+ "http://developer.ximian.com/test/soup-test/Digest/realm1/realm2/index.txt",
"2", "2", SOUP_STATUS_OK },
{ "Reusing last auth. Should succeed on first try",
- "http://primates.ximian.com/~danw/soup-test/Digest/realm1/realm2/index.txt",
+ "http://developer.ximian.com/test/soup-test/Digest/realm1/realm2/index.txt",
"", "2", SOUP_STATUS_OK },
{ "Should succeed on first try because of earlier domain directive",
- "http://primates.ximian.com/~danw/soup-test/Digest/realm1/realm2/realm1/index.txt",
+ "http://developer.ximian.com/test/soup-test/Digest/realm1/realm2/realm1/index.txt",
"", "1", SOUP_STATUS_OK },
{ "Should succeed on first try. (Known realm with cached password)",
- "http://primates.ximian.com/~danw/soup-test/Digest/realm2/index.txt",
+ "http://developer.ximian.com/test/soup-test/Digest/realm2/index.txt",
"", "2", SOUP_STATUS_OK },
{ "Fail once, then use typoed password, then use right password",
- "http://primates.ximian.com/~danw/soup-test/Digest/realm3/index.txt",
+ "http://developer.ximian.com/test/soup-test/Digest/realm3/index.txt",
"43", "043", SOUP_STATUS_OK },
{ "Make sure we haven't forgotten anything",
- "http://primates.ximian.com/~danw/soup-test/Basic/realm1/index.txt",
+ "http://developer.ximian.com/test/soup-test/Basic/realm1/index.txt",
"", "1", SOUP_STATUS_OK },
{ "Make sure we haven't forgotten anything",
- "http://primates.ximian.com/~danw/soup-test/Basic/realm1/realm2/index.txt",
+ "http://developer.ximian.com/test/soup-test/Basic/realm1/realm2/index.txt",
"", "2", SOUP_STATUS_OK },
{ "Make sure we haven't forgotten anything",
- "http://primates.ximian.com/~danw/soup-test/Basic/realm1/realm2/realm1/index.txt",
+ "http://developer.ximian.com/test/soup-test/Basic/realm1/realm2/realm1/index.txt",
"", "1", SOUP_STATUS_OK },
{ "Make sure we haven't forgotten anything",
- "http://primates.ximian.com/~danw/soup-test/Basic/realm2/index.txt",
+ "http://developer.ximian.com/test/soup-test/Basic/realm2/index.txt",
"", "2", SOUP_STATUS_OK },
{ "Make sure we haven't forgotten anything",
- "http://primates.ximian.com/~danw/soup-test/Basic/realm3/index.txt",
+ "http://developer.ximian.com/test/soup-test/Basic/realm3/index.txt",
"", "3", SOUP_STATUS_OK },
{ "Make sure we haven't forgotten anything",
- "http://primates.ximian.com/~danw/soup-test/Digest/realm1/index.txt",
+ "http://developer.ximian.com/test/soup-test/Digest/realm1/index.txt",
"", "1", SOUP_STATUS_OK },
{ "Make sure we haven't forgotten anything",
- "http://primates.ximian.com/~danw/soup-test/Digest/realm1/realm2/index.txt",
+ "http://developer.ximian.com/test/soup-test/Digest/realm1/realm2/index.txt",
"", "2", SOUP_STATUS_OK },
{ "Make sure we haven't forgotten anything",
- "http://primates.ximian.com/~danw/soup-test/Digest/realm1/realm2/realm1/index.txt",
+ "http://developer.ximian.com/test/soup-test/Digest/realm1/realm2/realm1/index.txt",
"", "1", SOUP_STATUS_OK },
{ "Make sure we haven't forgotten anything",
- "http://primates.ximian.com/~danw/soup-test/Digest/realm2/index.txt",
+ "http://developer.ximian.com/test/soup-test/Digest/realm2/index.txt",
"", "2", SOUP_STATUS_OK },
{ "Make sure we haven't forgotten anything",
- "http://primates.ximian.com/~danw/soup-test/Digest/realm3/index.txt",
+ "http://developer.ximian.com/test/soup-test/Digest/realm3/index.txt",
"", "3", SOUP_STATUS_OK },
{ "Now the server will reject the formerly-good password",
- "http://primates.ximian.com/~danw/soup-test/Basic/realm1/not/index.txt",
+ "http://developer.ximian.com/test/soup-test/Basic/realm1/not/index.txt",
"1" /* should not be used */, "1", SOUP_STATUS_UNAUTHORIZED },
{ "Make sure we've forgotten it",
- "http://primates.ximian.com/~danw/soup-test/Basic/realm1/index.txt",
+ "http://developer.ximian.com/test/soup-test/Basic/realm1/index.txt",
"", "0", SOUP_STATUS_UNAUTHORIZED },
{ "Likewise, reject the formerly-good Digest password",
- "http://primates.ximian.com/~danw/soup-test/Digest/realm1/not/index.txt",
+ "http://developer.ximian.com/test/soup-test/Digest/realm1/not/index.txt",
"1" /* should not be used */, "1", SOUP_STATUS_UNAUTHORIZED },
{ "Make sure we've forgotten it",
- "http://primates.ximian.com/~danw/soup-test/Digest/realm1/index.txt",
+ "http://developer.ximian.com/test/soup-test/Digest/realm1/index.txt",
"", "0", SOUP_STATUS_UNAUTHORIZED }
};
int ntests = sizeof (tests) / sizeof (tests[0]);
@@ -283,8 +283,9 @@ main (int argc, char **argv)
int i;
g_type_init ();
+ g_thread_init (NULL);
- session = soup_session_new ();
+ session = soup_session_async_new ();
g_signal_connect (session, "authenticate",
G_CALLBACK (authenticate), &i);
g_signal_connect (session, "reauthenticate",
diff --git a/tests/get.c b/tests/get.c
index d3f4928e..69566521 100644
--- a/tests/get.c
+++ b/tests/get.c
@@ -208,6 +208,7 @@ main (int argc, char **argv)
int opt;
g_type_init ();
+ g_thread_init (NULL);
while ((opt = getopt (argc, argv, "c:r")) != -1) {
switch (opt) {
@@ -236,7 +237,7 @@ main (int argc, char **argv)
exit (1);
}
- session = soup_session_new_with_options (
+ session = soup_session_async_new_with_options (
SOUP_SESSION_SSL_CA_FILE, cafile,
NULL);
diff --git a/tests/simple-proxy.c b/tests/simple-proxy.c
index fafebccd..79044efa 100644
--- a/tests/simple-proxy.c
+++ b/tests/simple-proxy.c
@@ -160,7 +160,7 @@ main (int argc, char **argv)
soup_server_get_port (server));
soup_server_run_async (server);
- session = soup_session_new ();
+ session = soup_session_async_new ();
printf ("\nWaiting for requests...\n");