summaryrefslogtreecommitdiff
path: root/libsoup/soup-session-sync.c
diff options
context:
space:
mode:
Diffstat (limited to 'libsoup/soup-session-sync.c')
-rw-r--r--libsoup/soup-session-sync.c466
1 files changed, 18 insertions, 448 deletions
diff --git a/libsoup/soup-session-sync.c b/libsoup/soup-session-sync.c
index 96ab9165..374f22bd 100644
--- a/libsoup/soup-session-sync.c
+++ b/libsoup/soup-session-sync.c
@@ -9,8 +9,6 @@
#include <config.h>
#endif
-#define LIBSOUP_I_HAVE_READ_BUG_594377_AND_KNOW_SOUP_PASSWORD_MANAGER_MIGHT_GO_AWAY
-
#include "soup-session-sync.h"
#include "soup.h"
#include "soup-session-private.h"
@@ -19,64 +17,35 @@
/**
* SECTION:soup-session-sync
- * @short_description: Soup session for blocking I/O in multithreaded
- * programs.
+ * @short_description: (Deprecated) SoupSession for blocking I/O in
+ * multithreaded programs.
*
* #SoupSessionSync is an implementation of #SoupSession that uses
* synchronous I/O, intended for use in multi-threaded programs.
*
- * You can use #SoupSessionSync from multiple threads concurrently.
- * Eg, you can send a #SoupMessage in one thread, and then while
- * waiting for the response, send another #SoupMessage from another
- * thread. You can also send a message from one thread and then call
- * soup_session_cancel_message() on it from any other thread (although
- * you need to be careful to avoid race conditions, where the message
- * finishes and is then unreffed by the sending thread just before you
- * cancel it).
- *
- * However, the majority of other types and methods in libsoup are not
- * MT-safe. In particular, you <emphasis>cannot</emphasis> modify or
- * examine a #SoupMessage while it is being transmitted by
- * #SoupSessionSync in another thread. Once a message has been handed
- * off to #SoupSessionSync, it can only be manipulated from its signal
- * handler callbacks, until I/O is complete.
+ * As of libsoup 2.42, this is deprecated in favor of the plain
+ * #SoupSession class (which uses both asynchronous and synchronous
+ * I/O, depending on the API used). See the <link
+ * linkend="libsoup-session-porting">porting guide</link>.
**/
-typedef struct {
- GMutex lock;
- GCond cond;
-} SoupSessionSyncPrivate;
-#define SOUP_SESSION_SYNC_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUP_TYPE_SESSION_SYNC, SoupSessionSyncPrivate))
-
G_DEFINE_TYPE (SoupSessionSync, soup_session_sync, SOUP_TYPE_SESSION)
static void
soup_session_sync_init (SoupSessionSync *ss)
{
- SoupSessionSyncPrivate *priv = SOUP_SESSION_SYNC_GET_PRIVATE (ss);
-
- g_mutex_init (&priv->lock);
- g_cond_init (&priv->cond);
-}
-
-static void
-soup_session_sync_finalize (GObject *object)
-{
- SoupSessionSyncPrivate *priv = SOUP_SESSION_SYNC_GET_PRIVATE (object);
-
- g_mutex_clear (&priv->lock);
- g_cond_clear (&priv->cond);
-
- G_OBJECT_CLASS (soup_session_sync_parent_class)->finalize (object);
}
-
/**
* soup_session_sync_new:
*
* Creates an synchronous #SoupSession with the default options.
*
* Return value: the new session.
+ *
+ * Deprecated: #SoupSessionSync is deprecated; use a plain
+ * #SoupSession, created with soup_session_new(). See the <link
+ * linkend="libsoup-session-porting">porting guide</link>.
**/
SoupSession *
soup_session_sync_new (void)
@@ -92,6 +61,10 @@ soup_session_sync_new (void)
* Creates an synchronous #SoupSession with the specified options.
*
* Return value: the new session.
+ *
+ * Deprecated: #SoupSessionSync is deprecated; use a plain
+ * #SoupSession, created with soup_session_new_with_options(). See the
+ * <link linkend="libsoup-session-porting">porting guide</link>.
**/
SoupSession *
soup_session_sync_new_with_options (const char *optname1, ...)
@@ -107,197 +80,12 @@ soup_session_sync_new_with_options (const char *optname1, ...)
return session;
}
-static guint
-tunnel_connect (SoupSession *session, SoupMessageQueueItem *related)
-{
- SoupConnection *conn = related->conn;
- SoupMessageQueueItem *item;
- guint status;
-
- g_object_ref (conn);
-
- item = soup_session_make_connect_message (session, conn);
- do {
- soup_session_send_queue_item (session, item, NULL);
- status = item->msg->status_code;
- if (item->state == SOUP_MESSAGE_RESTARTING &&
- soup_message_io_in_progress (item->msg)) {
- soup_message_restarted (item->msg);
- item->state = SOUP_MESSAGE_RUNNING;
- } else {
- if (item->state == SOUP_MESSAGE_RESTARTING)
- status = SOUP_STATUS_TRY_AGAIN;
- item->state = SOUP_MESSAGE_FINISHED;
- soup_message_finished (item->msg);
- }
- } while (item->state == SOUP_MESSAGE_STARTING);
- soup_session_unqueue_item (session, item);
- soup_message_queue_item_unref (item);
-
- if (SOUP_STATUS_IS_SUCCESSFUL (status)) {
- if (!soup_connection_start_ssl_sync (conn, related->cancellable))
- status = SOUP_STATUS_SSL_FAILED;
- soup_message_set_https_status (related->msg, conn);
- }
-
- if (!SOUP_STATUS_IS_SUCCESSFUL (status))
- soup_connection_disconnect (conn);
-
- g_object_unref (conn);
- return status;
-}
-
-static void
-get_connection (SoupMessageQueueItem *item)
-{
- SoupSession *session = item->session;
- SoupMessage *msg = item->msg;
- gboolean try_pruning = FALSE;
- guint status;
-
-try_again:
- soup_session_cleanup_connections (session, FALSE);
-
- if (!soup_session_get_connection (session, item, &try_pruning)) {
- if (!try_pruning)
- return;
- soup_session_cleanup_connections (session, TRUE);
- if (!soup_session_get_connection (session, item, &try_pruning))
- return;
- try_pruning = FALSE;
- }
-
- if (soup_connection_get_state (item->conn) != SOUP_CONNECTION_NEW) {
- item->state = SOUP_MESSAGE_READY;
- return;
- }
-
- status = soup_connection_connect_sync (item->conn, item->cancellable);
- if (status == SOUP_STATUS_TRY_AGAIN) {
- soup_connection_disconnect (item->conn);
- soup_message_queue_item_set_connection (item, NULL);
- goto try_again;
- }
-
- soup_message_set_https_status (msg, item->conn);
-
- if (!SOUP_STATUS_IS_SUCCESSFUL (status)) {
- if (!msg->status_code)
- soup_session_set_item_status (session, item, status);
- item->state = SOUP_MESSAGE_FINISHING;
- soup_connection_disconnect (item->conn);
- soup_message_queue_item_set_connection (item, NULL);
- return;
- }
-
- if (soup_connection_is_tunnelled (item->conn)) {
- status = tunnel_connect (session, item);
- if (!SOUP_STATUS_IS_SUCCESSFUL (status)) {
- soup_connection_disconnect (item->conn);
- soup_message_queue_item_set_connection (item, NULL);
- if (status == SOUP_STATUS_TRY_AGAIN)
- goto try_again;
- soup_session_set_item_status (session, item, status);
- item->state = SOUP_MESSAGE_FINISHING;
- return;
- }
- }
-
- item->state = SOUP_MESSAGE_READY;
-}
-
-static void process_queue_item (SoupMessageQueueItem *item);
-
-static void
-new_api_message_completed (SoupMessage *msg, gpointer user_data)
-{
- SoupMessageQueueItem *item = user_data;
-
- if (item->state != SOUP_MESSAGE_RESTARTING) {
- item->state = SOUP_MESSAGE_FINISHING;
- process_queue_item (item);
- }
-}
-
-static void
-process_queue_item (SoupMessageQueueItem *item)
-{
- SoupSession *session = item->session;
- SoupSessionSyncPrivate *priv = SOUP_SESSION_SYNC_GET_PRIVATE (session);
-
- soup_message_queue_item_ref (item);
-
- do {
- if (item->paused) {
- g_mutex_lock (&priv->lock);
- while (item->paused)
- g_cond_wait (&priv->cond, &priv->lock);
- g_mutex_unlock (&priv->lock);
- }
-
- switch (item->state) {
- case SOUP_MESSAGE_STARTING:
- item->state = SOUP_MESSAGE_AWAITING_CONNECTION;
- break;
-
- case SOUP_MESSAGE_AWAITING_CONNECTION:
- g_mutex_lock (&priv->lock);
- do {
- get_connection (item);
- if (item->state == SOUP_MESSAGE_AWAITING_CONNECTION)
- g_cond_wait (&priv->cond, &priv->lock);
- } while (item->state == SOUP_MESSAGE_AWAITING_CONNECTION);
- g_mutex_unlock (&priv->lock);
- break;
-
- case SOUP_MESSAGE_READY:
- item->state = SOUP_MESSAGE_RUNNING;
-
- if (item->new_api) {
- soup_session_send_queue_item (item->session, item, new_api_message_completed);
- goto out;
- }
-
- soup_session_send_queue_item (item->session, item, NULL);
- if (item->state != SOUP_MESSAGE_RESTARTING)
- item->state = SOUP_MESSAGE_FINISHING;
- break;
-
- case SOUP_MESSAGE_RUNNING:
- g_warn_if_fail (item->new_api);
- item->state = SOUP_MESSAGE_FINISHING;
- break;
-
- case SOUP_MESSAGE_RESTARTING:
- item->state = SOUP_MESSAGE_STARTING;
- soup_message_restarted (item->msg);
- break;
-
- case SOUP_MESSAGE_FINISHING:
- item->state = SOUP_MESSAGE_FINISHED;
- soup_message_finished (item->msg);
- soup_session_unqueue_item (session, item);
- g_cond_broadcast (&priv->cond);
- break;
-
- default:
- g_warn_if_reached ();
- item->state = SOUP_MESSAGE_FINISHING;
- break;
- }
- } while (item->state != SOUP_MESSAGE_FINISHED);
-
- out:
- soup_message_queue_item_unref (item);
-}
-
static gboolean
queue_message_callback (gpointer data)
{
SoupMessageQueueItem *item = data;
item->callback (item->session, item->msg, item->callback_data);
- g_object_unref (item->session);
soup_message_queue_item_unref (item);
return FALSE;
}
@@ -307,14 +95,12 @@ queue_message_thread (gpointer data)
{
SoupMessageQueueItem *item = data;
- process_queue_item (item);
+ soup_session_process_queue_item (item->session, item, NULL, TRUE);
if (item->callback) {
soup_add_completion (soup_session_get_async_context (item->session),
queue_message_callback, item);
- } else {
- g_object_unref (item->session);
+ } else
soup_message_queue_item_unref (item);
- }
return NULL;
}
@@ -326,234 +112,18 @@ soup_session_sync_queue_message (SoupSession *session, SoupMessage *msg,
SoupMessageQueueItem *item;
GThread *thread;
- g_object_ref (session);
- item = soup_session_append_queue_item (session, msg, callback, user_data);
+ item = soup_session_append_queue_item (session, msg, FALSE, FALSE,
+ callback, user_data);
thread = g_thread_new ("SoupSessionSync:queue_message",
queue_message_thread, item);
g_thread_unref (thread);
}
-static guint
-soup_session_sync_send_message (SoupSession *session, SoupMessage *msg)
-{
- SoupMessageQueueItem *item;
- guint status;
-
- item = soup_session_append_queue_item (session, msg, NULL, NULL);
- process_queue_item (item);
- status = msg->status_code;
- soup_message_queue_item_unref (item);
- return status;
-}
-
-static void
-soup_session_sync_cancel_message (SoupSession *session, SoupMessage *msg, guint status_code)
-{
- SoupSessionSyncPrivate *priv = SOUP_SESSION_SYNC_GET_PRIVATE (session);
-
- g_mutex_lock (&priv->lock);
- SOUP_SESSION_CLASS (soup_session_sync_parent_class)->cancel_message (session, msg, status_code);
- g_cond_broadcast (&priv->cond);
- g_mutex_unlock (&priv->lock);
-}
-
-static void
-soup_session_sync_auth_required (SoupSession *session, SoupMessage *msg,
- SoupAuth *auth, gboolean retrying)
-{
- SoupSessionFeature *password_manager;
-
- password_manager = soup_session_get_feature_for_message (
- session, SOUP_TYPE_PASSWORD_MANAGER, msg);
- if (password_manager) {
- soup_password_manager_get_passwords_sync (
- SOUP_PASSWORD_MANAGER (password_manager),
- msg, auth, NULL); /* FIXME cancellable */
- }
-
- SOUP_SESSION_CLASS (soup_session_sync_parent_class)->
- auth_required (session, msg, auth, retrying);
-}
-
-static void
-soup_session_sync_flush_queue (SoupSession *session)
-{
- SoupSessionSyncPrivate *priv = SOUP_SESSION_SYNC_GET_PRIVATE (session);
- SoupMessageQueue *queue;
- SoupMessageQueueItem *item;
- GHashTable *current;
- gboolean done = FALSE;
-
- /* Record the current contents of the queue */
- current = g_hash_table_new (NULL, NULL);
- queue = soup_session_get_queue (session);
- for (item = soup_message_queue_first (queue);
- item;
- item = soup_message_queue_next (queue, item))
- g_hash_table_insert (current, item, item);
-
- /* Cancel everything */
- SOUP_SESSION_CLASS (soup_session_sync_parent_class)->flush_queue (session);
-
- /* Wait until all of the items in @current have been removed
- * from the queue. (This is not the same as "wait for the
- * queue to be empty", because the app may queue new requests
- * in response to the cancellation of the old ones. We don't
- * try to cancel those requests as well, since we'd likely
- * just end up looping forever.)
- */
- g_mutex_lock (&priv->lock);
- do {
- done = TRUE;
- for (item = soup_message_queue_first (queue);
- item;
- item = soup_message_queue_next (queue, item)) {
- if (g_hash_table_lookup (current, item))
- done = FALSE;
- }
-
- if (!done)
- g_cond_wait (&priv->cond, &priv->lock);
- } while (!done);
- g_mutex_unlock (&priv->lock);
-
- g_hash_table_destroy (current);
-}
-
-static void
-soup_session_sync_kick (SoupSession *session)
-{
- SoupSessionSyncPrivate *priv = SOUP_SESSION_SYNC_GET_PRIVATE (session);
-
- g_mutex_lock (&priv->lock);
- g_cond_broadcast (&priv->cond);
- g_mutex_unlock (&priv->lock);
-}
-
static void
soup_session_sync_class_init (SoupSessionSyncClass *session_sync_class)
{
- GObjectClass *object_class = G_OBJECT_CLASS (session_sync_class);
SoupSessionClass *session_class = SOUP_SESSION_CLASS (session_sync_class);
- g_type_class_add_private (session_sync_class, sizeof (SoupSessionSyncPrivate));
-
/* virtual method override */
session_class->queue_message = soup_session_sync_queue_message;
- session_class->send_message = soup_session_sync_send_message;
- session_class->cancel_message = soup_session_sync_cancel_message;
- session_class->auth_required = soup_session_sync_auth_required;
- session_class->flush_queue = soup_session_sync_flush_queue;
- session_class->kick = soup_session_sync_kick;
-
- object_class->finalize = soup_session_sync_finalize;
-}
-
-
-GInputStream *
-soup_session_send_request (SoupSession *session,
- SoupMessage *msg,
- GCancellable *cancellable,
- GError **error)
-{
- SoupMessageQueueItem *item;
- GInputStream *stream = NULL;
- GOutputStream *ostream;
- GMemoryOutputStream *mostream;
- gssize size;
- GError *my_error = NULL;
-
- g_return_val_if_fail (SOUP_IS_SESSION_SYNC (session), NULL);
-
- item = soup_session_append_queue_item (session, msg, NULL, NULL);
-
- item->new_api = TRUE;
- if (cancellable) {
- g_object_unref (item->cancellable);
- item->cancellable = g_object_ref (cancellable);
- }
-
- while (!stream) {
- /* Get a connection, etc */
- process_queue_item (item);
- if (item->state != SOUP_MESSAGE_RUNNING)
- break;
-
- /* Send request, read headers */
- if (!soup_message_io_run_until_read (msg, item->cancellable, &my_error)) {
- if (g_error_matches (my_error, SOUP_HTTP_ERROR, SOUP_STATUS_TRY_AGAIN)) {
- item->state = SOUP_MESSAGE_RESTARTING;
- soup_message_io_finished (item->msg);
- g_clear_error (&my_error);
- continue;
- } else
- break;
- }
-
- stream = soup_message_io_get_response_istream (msg, &my_error);
- if (!stream)
- break;
-
- /* Break if the message doesn't look likely-to-be-requeued */
- if (msg->status_code != SOUP_STATUS_UNAUTHORIZED &&
- msg->status_code != SOUP_STATUS_PROXY_UNAUTHORIZED &&
- !soup_session_would_redirect (session, msg))
- break;
-
- /* Gather the current message body... */
- ostream = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
- if (g_output_stream_splice (ostream, stream,
- G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE |
- G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
- item->cancellable, &my_error) == -1) {
- g_object_unref (stream);
- g_object_unref (ostream);
- stream = NULL;
- break;
- }
- g_object_unref (stream);
- stream = NULL;
-
- /* If the message was requeued, loop */
- if (item->state == SOUP_MESSAGE_RESTARTING) {
- g_object_unref (ostream);
- continue;
- }
-
- /* Not requeued, so return the original body */
- mostream = G_MEMORY_OUTPUT_STREAM (ostream);
- size = g_memory_output_stream_get_data_size (mostream);
- stream = g_memory_input_stream_new ();
- if (size) {
- g_memory_input_stream_add_data (G_MEMORY_INPUT_STREAM (stream),
- g_memory_output_stream_steal_data (mostream),
- size, g_free);
- }
- g_object_unref (ostream);
- }
-
- if (my_error)
- g_propagate_error (error, my_error);
- else if (SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code)) {
- if (stream) {
- g_object_unref (stream);
- stream = NULL;
- }
- g_set_error_literal (error, SOUP_HTTP_ERROR, msg->status_code,
- msg->reason_phrase);
- } else if (!stream)
- stream = g_memory_input_stream_new ();
-
- if (!stream) {
- if (soup_message_io_in_progress (msg))
- soup_message_io_finished (msg);
- else if (item->state != SOUP_MESSAGE_FINISHED)
- item->state = SOUP_MESSAGE_FINISHING;
-
- if (item->state != SOUP_MESSAGE_FINISHED)
- process_queue_item (item);
- }
-
- soup_message_queue_item_unref (item);
- return stream;
}