static void tunnel_message_completed (SoupMessage *msg, gpointer user_data) { SoupMessageQueueItem *item = user_data; SoupSession *session = item->session; if (item->state == SOUP_MESSAGE_RESTARTING) { soup_message_restarted (msg); if (item->conn) { soup_session_send_queue_item (session, item, tunnel_message_completed); return; } soup_message_set_status (msg, SOUP_STATUS_TRY_AGAIN); } item->state = SOUP_MESSAGE_FINISHED; if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) { if (item->conn) soup_connection_disconnect (item->conn); if (msg->status_code == SOUP_STATUS_TRY_AGAIN) { item->related->state = SOUP_MESSAGE_AWAITING_CONNECTION; g_object_unref (item->related->conn); item->related->conn = NULL; } else soup_message_set_status (item->related->msg, msg->status_code); goto done; } if (!soup_connection_start_ssl (item->conn)) { if (item->conn) soup_connection_disconnect (item->conn); soup_message_set_status (item->related->msg, SOUP_STATUS_SSL_FAILED); goto done; } g_signal_connect (item->conn, "disconnected", G_CALLBACK (connection_closed), item->session); soup_connection_set_state (item->conn, SOUP_CONNECTION_IDLE); soup_connection_set_state (item->conn, SOUP_CONNECTION_IN_USE); item->related->state = SOUP_MESSAGE_READY; done: soup_message_finished (msg); if (item->related->msg->status_code) item->related->state = SOUP_MESSAGE_FINISHING; do_idle_run_queue (item->session); soup_message_queue_item_unref (item->related); soup_session_unqueue_item (session, item); soup_message_queue_item_unref (item); g_object_unref (session); }
static void resolved_proxy_uri (SoupProxyURIResolver *proxy_resolver, guint status, SoupURI *proxy_uri, gpointer user_data) { SoupMessageQueueItem *item = user_data; SoupSession *session = item->session; if (item_failed (item, status)) return; if (proxy_uri) { SoupAddress *proxy_addr; item->state = SOUP_MESSAGE_RESOLVING_PROXY_ADDRESS; item->proxy_uri = soup_uri_copy (proxy_uri); proxy_addr = soup_address_new (proxy_uri->host, proxy_uri->port); soup_address_resolve_async (proxy_addr, soup_session_get_async_context (session), item->cancellable, resolved_proxy_addr, item); g_object_unref (proxy_addr); return; } item->state = SOUP_MESSAGE_AWAITING_CONNECTION; soup_message_queue_item_unref (item); /* If we got here we know session still exists */ run_queue ((SoupSessionAsync *)session); }
static void tunnel_connected (SoupMessage *msg, gpointer user_data) { SoupSessionAsyncTunnelData *data = user_data; if (SOUP_MESSAGE_IS_STARTING (msg)) { soup_session_send_queue_item (data->session, data->item, data->conn); return; } if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) { soup_session_connection_failed (data->session, data->conn, msg->status_code); goto done; } if (!soup_connection_start_ssl (data->conn)) { soup_session_connection_failed (data->session, data->conn, SOUP_STATUS_SSL_FAILED); goto done; } g_signal_connect (data->conn, "disconnected", G_CALLBACK (connection_closed), data->session); soup_connection_set_state (data->conn, SOUP_CONNECTION_IDLE); do_idle_run_queue (data->session); done: soup_message_queue_item_unref (data->item); g_slice_free (SoupSessionAsyncTunnelData, data); }
static void message_finished (SoupMessage *msg, gpointer user_data) { SoupMessageQueueItem *item = user_data; SoupSession *session = item->session; SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session); if (item->conn) { g_object_unref (item->conn); item->conn = NULL; } if (!SOUP_MESSAGE_IS_STARTING (msg)) { soup_message_queue_remove (priv->queue, item); g_signal_handlers_disconnect_by_func (msg, message_finished, item); /* g_signal_handlers_disconnect_by_func doesn't work if you * have a metamarshal, meaning it doesn't work with * soup_message_add_header_handler() */ g_signal_handlers_disconnect_matched (msg, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, session); g_signal_emit (session, signals[REQUEST_UNQUEUED], 0, msg); soup_message_queue_item_unref (item); } }
static void run_queue (SoupSessionAsync *sa) { SoupSession *session = SOUP_SESSION (sa); SoupMessageQueue *queue = soup_session_get_queue (session); SoupMessageQueueItem *item; SoupProxyURIResolver *proxy_resolver; SoupMessage *msg; SoupConnection *conn; gboolean try_pruning = TRUE, should_prune = FALSE; soup_session_cleanup_connections (session, FALSE); try_again: for (item = soup_message_queue_first (queue); item && !should_prune; item = soup_message_queue_next (queue, item)) { msg = item->msg; /* CONNECT messages are handled specially */ if (msg->method == SOUP_METHOD_CONNECT) continue; if (soup_message_io_in_progress (msg)) continue; if (!item->resolved_proxy_addr) { proxy_resolver = (SoupProxyURIResolver *)soup_session_get_feature_for_message (session, SOUP_TYPE_PROXY_URI_RESOLVER, msg); if (proxy_resolver) { resolve_proxy_addr (item, proxy_resolver); continue; } else item->resolved_proxy_addr = TRUE; } conn = soup_session_get_connection (session, item, &should_prune); if (!conn) continue; if (soup_connection_get_state (conn) == SOUP_CONNECTION_NEW) { soup_connection_connect_async (conn, got_connection, session); } else soup_session_send_queue_item (session, item, conn); } if (item) soup_message_queue_item_unref (item); if (try_pruning && should_prune) { /* 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_cleanup_connections (session, TRUE)) { try_pruning = should_prune = FALSE; goto try_again; } } }
static gboolean item_failed (SoupMessageQueueItem *item, guint status) { if (item->removed) { soup_message_queue_item_unref (item); return TRUE; } if (!SOUP_STATUS_IS_SUCCESSFUL (status)) { if (status != SOUP_STATUS_CANCELLED) soup_session_cancel_message (item->session, item->msg, status); soup_message_queue_item_unref (item); return TRUE; } return FALSE; }
static void got_connection (SoupConnection *conn, guint status, gpointer user_data) { SoupMessageQueueItem *item = user_data; SoupSession *session = item->session; SoupAddress *tunnel_addr; if (item->state != SOUP_MESSAGE_CONNECTING) { soup_connection_disconnect (conn); do_idle_run_queue (session); soup_message_queue_item_unref (item); g_object_unref (session); return; } if (status != SOUP_STATUS_OK) { soup_session_set_item_status (session, item, status); item->state = SOUP_MESSAGE_FINISHING; soup_connection_disconnect (conn); do_idle_run_queue (session); soup_message_queue_item_unref (item); g_object_unref (session); return; } tunnel_addr = soup_connection_get_tunnel_addr (conn); if (tunnel_addr) { SoupMessageQueueItem *tunnel_item; item->state = SOUP_MESSAGE_TUNNELING; tunnel_item = soup_session_make_connect_message (session, conn); tunnel_item->related = item; soup_session_send_queue_item (session, tunnel_item, tunnel_message_completed); return; } item->state = SOUP_MESSAGE_READY; g_signal_connect (conn, "disconnected", G_CALLBACK (connection_closed), session); run_queue ((SoupSessionAsync *)session); soup_message_queue_item_unref (item); g_object_unref (session); }
static gboolean queue_message_callback (gpointer data) { SoupMessageQueueItem *item = data; item->callback (item->session, item->msg, item->callback_data); soup_message_queue_item_unref (item); return FALSE; }
static gboolean item_failed (SoupMessageQueueItem *item, guint status) { if (item->removed) { soup_message_queue_item_unref (item); return TRUE; } if (!SOUP_STATUS_IS_SUCCESSFUL (status)) { item->state = SOUP_MESSAGE_FINISHING; if (!item->msg->status_code) soup_session_set_item_status (item->session, item, status); do_idle_run_queue (item->session); soup_message_queue_item_unref (item); return TRUE; } return FALSE; }
static gpointer queue_message_thread (gpointer data) { SoupMessageQueueItem *item = data; 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 soup_message_queue_item_unref (item); return NULL; }
/** * soup_message_queue_next: * @queue: a #SoupMessageQueue * @item: a #SoupMessageQueueItem * * Unrefs @item and gets the next item after it in @queue. As with * soup_message_queue_first(), you must unref the returned item * yourself with soup_message_queue_unref_item() if you do not finish * walking the queue. * * Return value: the next item in @queue. **/ SoupMessageQueueItem * soup_message_queue_next (SoupMessageQueue *queue, SoupMessageQueueItem *item) { SoupMessageQueueItem *next; g_mutex_lock (queue->mutex); next = item->next; while (next && next->removed) next = next->next; if (next) next->ref_count++; g_mutex_unlock (queue->mutex); soup_message_queue_item_unref (item); return next; }
static void resolved_proxy_addr (SoupAddress *addr, guint status, gpointer user_data) { SoupMessageQueueItem *item = user_data; SoupSession *session = item->session; if (item_failed (item, status)) return; item->proxy_addr = g_object_ref (addr); item->state = SOUP_MESSAGE_AWAITING_CONNECTION; soup_message_queue_item_unref (item); /* If we got here we know session still exists */ run_queue ((SoupSessionAsync *)session); }
static void cancel_message (SoupSession *session, SoupMessage *msg, guint status_code) { SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session); SoupMessageQueueItem *item; item = soup_message_queue_lookup (priv->queue, msg); if (item) { if (item->cancellable) g_cancellable_cancel (item->cancellable); soup_message_queue_item_unref (item); } soup_message_io_stop (msg); soup_message_set_status (msg, status_code); soup_message_finished (msg); }
static void final_finished (SoupMessage *req, gpointer user_data) { SoupMessageQueueItem *item = user_data; SoupSession *session = item->session; g_object_ref (session); if (!SOUP_MESSAGE_IS_STARTING (req)) { g_signal_handlers_disconnect_by_func (req, final_finished, item); g_signal_handlers_disconnect_by_func (req, request_restarted, item); if (item->callback) item->callback (session, req, item->callback_data); g_object_unref (req); soup_message_queue_item_unref (item); } do_idle_run_queue (session); g_object_unref (session); }
static guint send_message (SoupSession *session, SoupMessage *req) { SoupMessageQueueItem *item; GMainContext *async_context = soup_session_get_async_context (session); /* Balance out the unref that queuing will eventually do */ g_object_ref (req); queue_message (session, req, NULL, NULL); item = soup_message_queue_lookup (soup_session_get_queue (session), req); g_return_val_if_fail (item != NULL, SOUP_STATUS_MALFORMED); while (item->state != SOUP_MESSAGE_FINISHED) g_main_context_iteration (async_context, TRUE); soup_message_queue_item_unref (item); return req->status_code; }
static void run_queue (SoupSessionAsync *sa) { SoupSession *session = SOUP_SESSION (sa); SoupMessageQueue *queue = soup_session_get_queue (session); SoupMessageQueueItem *item; SoupMessage *msg; gboolean try_pruning = TRUE, should_prune = FALSE; g_object_ref (session); soup_session_cleanup_connections (session, FALSE); try_again: for (item = soup_message_queue_first (queue); item && !should_prune; item = soup_message_queue_next (queue, item)) { msg = item->msg; /* CONNECT messages are handled specially */ if (msg->method != SOUP_METHOD_CONNECT) process_queue_item (item, &should_prune, TRUE); } if (item) soup_message_queue_item_unref (item); if (try_pruning && should_prune) { /* 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_cleanup_connections (session, TRUE)) { try_pruning = should_prune = FALSE; goto try_again; } } g_object_unref (session); }
void soup_message_io_cleanup (SoupMessage *msg) { SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg); SoupMessageIOData *io; soup_message_io_stop (msg); io = priv->io_data; if (!io) return; priv->io_data = NULL; if (io->iostream) g_object_unref (io->iostream); if (io->body_istream) g_object_unref (io->body_istream); if (io->body_ostream) g_object_unref (io->body_ostream); if (io->async_context) g_main_context_unref (io->async_context); if (io->item) soup_message_queue_item_unref (io->item); g_byte_array_free (io->read_header_buf, TRUE); g_string_free (io->write_buf, TRUE); if (io->write_chunk) soup_buffer_free (io->write_chunk); if (io->async_close_wait) { g_cancellable_cancel (io->async_close_wait); g_clear_object (&io->async_close_wait); } g_clear_error (&io->async_close_error); g_slice_free (SoupMessageIOData, io); }
static void authenticate_auth (SoupAuthManager *manager, SoupAuth *auth, SoupMessage *msg, gboolean prior_auth_failed, gboolean proxy, gboolean can_interact) { SoupAuthManagerPrivate *priv = manager->priv; SoupURI *uri; if (proxy) { SoupMessageQueue *queue; SoupMessageQueueItem *item; queue = soup_session_get_queue (priv->session); item = soup_message_queue_lookup (queue, msg); if (item) { uri = soup_connection_get_proxy_uri (item->conn); soup_message_queue_item_unref (item); } else uri = NULL; if (!uri) return; } else uri = soup_message_get_uri (msg); /* If a password is specified explicitly in the URI, use it * even if the auth had previously already been authenticated. */ if (uri->password && uri->user) { soup_auth_authenticate (auth, uri->user, uri->password); soup_uri_set_password (uri, NULL); soup_uri_set_user (uri, NULL); } else if (!soup_auth_is_authenticated (auth) && can_interact) { g_signal_emit (manager, signals[AUTHENTICATE], 0, msg, auth, prior_auth_failed); } }
static void cancel_message (SoupSession *session, SoupMessage *msg, guint status_code) { SoupMessageQueue *queue; SoupMessageQueueItem *item; gboolean dummy; SOUP_SESSION_CLASS (soup_session_async_parent_class)-> cancel_message (session, msg, status_code); queue = soup_session_get_queue (session); item = soup_message_queue_lookup (queue, msg); if (!item || item->state != SOUP_MESSAGE_FINISHING) return; /* Force it to finish immediately, so that * soup_session_abort (session); g_object_unref (session); * will work. */ process_queue_item (item, &dummy, FALSE); soup_message_queue_item_unref (item); }