1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * soup-connection.c: A single HTTP/HTTPS connection
5 * Copyright (C) 2000-2003, Ximian, Inc.
12 #include "soup-connection.h"
14 #include "soup-marshal.h"
15 #include "soup-message-queue.h"
16 #include "soup-misc-private.h"
21 SoupURI *remote_uri, *proxy_uri;
22 SoupProxyURIResolver *proxy_resolver;
23 gboolean use_gproxyresolver;
25 gboolean ssl, ssl_strict, ssl_fallback;
27 GMainContext *async_context;
28 gboolean use_thread_context;
30 SoupMessage *current_msg;
31 SoupConnectionState state;
32 time_t unused_timeout;
33 guint io_timeout, idle_timeout;
34 GSource *idle_timeout_src;
36 } SoupConnectionPrivate;
37 #define SOUP_CONNECTION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUP_TYPE_CONNECTION, SoupConnectionPrivate))
39 G_DEFINE_TYPE (SoupConnection, soup_connection, G_TYPE_OBJECT)
47 static guint signals[LAST_SIGNAL] = { 0 };
59 PROP_USE_THREAD_CONTEXT,
67 static void stop_idle_timer (SoupConnectionPrivate *priv);
69 /* Number of seconds after which we close a connection that hasn't yet
72 #define SOUP_CONNECTION_UNUSED_TIMEOUT 3
75 soup_connection_init (SoupConnection *conn)
80 soup_connection_finalize (GObject *object)
82 SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (object);
84 g_clear_pointer (&priv->remote_uri, soup_uri_free);
85 g_clear_pointer (&priv->proxy_uri, soup_uri_free);
86 g_clear_object (&priv->tlsdb);
87 g_clear_object (&priv->proxy_resolver);
88 g_clear_pointer (&priv->async_context, g_main_context_unref);
90 G_OBJECT_CLASS (soup_connection_parent_class)->finalize (object);
94 soup_connection_dispose (GObject *object)
96 SoupConnection *conn = SOUP_CONNECTION (object);
97 SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (conn);
99 stop_idle_timer (priv);
102 g_warning ("Disposing connection while connected");
103 soup_connection_disconnect (conn);
106 G_OBJECT_CLASS (soup_connection_parent_class)->dispose (object);
110 soup_connection_set_property (GObject *object, guint prop_id,
111 const GValue *value, GParamSpec *pspec)
113 SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (object);
114 SoupProxyURIResolver *proxy_resolver;
117 case PROP_REMOTE_URI:
118 priv->remote_uri = g_value_dup_boxed (value);
120 case PROP_PROXY_RESOLVER:
121 proxy_resolver = g_value_get_object (value);
122 if (proxy_resolver && SOUP_IS_PROXY_RESOLVER_DEFAULT (proxy_resolver))
123 priv->use_gproxyresolver = TRUE;
124 else if (proxy_resolver)
125 priv->proxy_resolver = g_object_ref (proxy_resolver);
128 priv->ssl = g_value_get_boolean (value);
132 g_object_unref (priv->tlsdb);
133 priv->tlsdb = g_value_dup_object (value);
135 case PROP_SSL_STRICT:
136 priv->ssl_strict = g_value_get_boolean (value);
138 case PROP_SSL_FALLBACK:
139 priv->ssl_fallback = g_value_get_boolean (value);
141 case PROP_ASYNC_CONTEXT:
142 priv->async_context = g_value_get_pointer (value);
143 if (priv->async_context)
144 g_main_context_ref (priv->async_context);
146 case PROP_USE_THREAD_CONTEXT:
147 priv->use_thread_context = g_value_get_boolean (value);
150 priv->io_timeout = g_value_get_uint (value);
152 case PROP_IDLE_TIMEOUT:
153 priv->idle_timeout = g_value_get_uint (value);
156 soup_connection_set_state (SOUP_CONNECTION (object), g_value_get_uint (value));
159 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
165 soup_connection_get_property (GObject *object, guint prop_id,
166 GValue *value, GParamSpec *pspec)
168 SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (object);
171 case PROP_REMOTE_URI:
172 g_value_set_boxed (value, priv->remote_uri);
175 g_value_set_boolean (value, priv->ssl);
178 g_value_set_object (value, priv->tlsdb);
180 case PROP_SSL_STRICT:
181 g_value_set_boolean (value, priv->ssl_strict);
183 case PROP_SSL_FALLBACK:
184 g_value_set_boolean (value, priv->ssl_fallback);
186 case PROP_ASYNC_CONTEXT:
187 g_value_set_pointer (value, priv->async_context ? g_main_context_ref (priv->async_context) : NULL);
189 case PROP_USE_THREAD_CONTEXT:
190 g_value_set_boolean (value, priv->use_thread_context);
193 g_value_set_uint (value, priv->io_timeout);
195 case PROP_IDLE_TIMEOUT:
196 g_value_set_uint (value, priv->idle_timeout);
199 g_value_set_enum (value, priv->state);
202 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
208 soup_connection_class_init (SoupConnectionClass *connection_class)
210 GObjectClass *object_class = G_OBJECT_CLASS (connection_class);
212 g_type_class_add_private (connection_class, sizeof (SoupConnectionPrivate));
214 /* virtual method override */
215 object_class->dispose = soup_connection_dispose;
216 object_class->finalize = soup_connection_finalize;
217 object_class->set_property = soup_connection_set_property;
218 object_class->get_property = soup_connection_get_property;
222 g_signal_new ("event",
223 G_OBJECT_CLASS_TYPE (object_class),
229 G_TYPE_SOCKET_CLIENT_EVENT,
231 signals[DISCONNECTED] =
232 g_signal_new ("disconnected",
233 G_OBJECT_CLASS_TYPE (object_class),
235 G_STRUCT_OFFSET (SoupConnectionClass, disconnected),
237 _soup_marshal_NONE__NONE,
241 g_object_class_install_property (
242 object_class, PROP_REMOTE_URI,
243 g_param_spec_boxed (SOUP_CONNECTION_REMOTE_URI,
245 "The URI of the HTTP server",
247 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
248 g_object_class_install_property (
249 object_class, PROP_PROXY_RESOLVER,
250 g_param_spec_object (SOUP_CONNECTION_PROXY_RESOLVER,
252 "SoupProxyURIResolver to use",
253 SOUP_TYPE_PROXY_URI_RESOLVER,
254 G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
255 g_object_class_install_property (
256 object_class, PROP_SSL,
257 g_param_spec_boolean (SOUP_CONNECTION_SSL,
259 "Whether this is an SSL connection",
261 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
262 g_object_class_install_property (
263 object_class, PROP_SSL_CREDS,
264 g_param_spec_object (SOUP_CONNECTION_SSL_CREDENTIALS,
266 "SSL credentials for this connection",
268 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
269 g_object_class_install_property (
270 object_class, PROP_SSL_STRICT,
271 g_param_spec_boolean (SOUP_CONNECTION_SSL_STRICT,
272 "Strictly validate SSL certificates",
273 "Whether certificate errors should be considered a connection error",
275 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
276 g_object_class_install_property (
277 object_class, PROP_SSL_FALLBACK,
278 g_param_spec_boolean (SOUP_CONNECTION_SSL_FALLBACK,
280 "Use SSLv3 instead of TLS",
282 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
283 g_object_class_install_property (
284 object_class, PROP_ASYNC_CONTEXT,
285 g_param_spec_pointer (SOUP_CONNECTION_ASYNC_CONTEXT,
286 "Async GMainContext",
287 "GMainContext to dispatch this connection's async I/O in",
288 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
289 g_object_class_install_property (
290 object_class, PROP_USE_THREAD_CONTEXT,
291 g_param_spec_boolean (SOUP_CONNECTION_USE_THREAD_CONTEXT,
292 "Use thread context",
293 "Use g_main_context_get_thread_default",
295 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
296 g_object_class_install_property (
297 object_class, PROP_TIMEOUT,
298 g_param_spec_uint (SOUP_CONNECTION_TIMEOUT,
300 "Value in seconds to timeout a blocking I/O",
303 g_object_class_install_property (
304 object_class, PROP_IDLE_TIMEOUT,
305 g_param_spec_uint (SOUP_CONNECTION_IDLE_TIMEOUT,
307 "Connection lifetime when idle",
309 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
310 g_object_class_install_property (
311 object_class, PROP_STATE,
312 g_param_spec_enum (SOUP_CONNECTION_STATE,
314 "Current state of connection",
315 SOUP_TYPE_CONNECTION_STATE, SOUP_CONNECTION_NEW,
320 soup_connection_event (SoupConnection *conn,
321 GSocketClientEvent event,
322 GIOStream *connection)
324 SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (conn);
326 if (!connection && priv->socket)
327 connection = soup_socket_get_connection (priv->socket);
329 g_signal_emit (conn, signals[EVENT], 0,
334 idle_timeout (gpointer conn)
336 soup_connection_disconnect (conn);
341 start_idle_timer (SoupConnection *conn)
343 SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (conn);
345 if (priv->idle_timeout > 0 && !priv->idle_timeout_src) {
346 priv->idle_timeout_src =
347 soup_add_timeout (priv->async_context,
348 priv->idle_timeout * 1000,
354 stop_idle_timer (SoupConnectionPrivate *priv)
356 if (priv->idle_timeout_src) {
357 g_source_destroy (priv->idle_timeout_src);
358 priv->idle_timeout_src = NULL;
363 current_msg_got_body (SoupMessage *msg, gpointer user_data)
365 SoupConnection *conn = user_data;
366 SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (conn);
368 priv->unused_timeout = 0;
370 if (priv->proxy_uri &&
371 msg->method == SOUP_METHOD_CONNECT &&
372 SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
373 soup_connection_event (conn, G_SOCKET_CLIENT_PROXY_NEGOTIATED, NULL);
375 /* We're now effectively no longer proxying */
376 g_clear_pointer (&priv->proxy_uri, soup_uri_free);
379 priv->reusable = soup_message_is_keepalive (msg);
383 clear_current_msg (SoupConnection *conn)
385 SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (conn);
388 msg = priv->current_msg;
389 priv->current_msg = NULL;
391 g_signal_handlers_disconnect_by_func (msg, G_CALLBACK (current_msg_got_body), conn);
392 g_object_unref (msg);
396 set_current_msg (SoupConnection *conn, SoupMessage *msg)
398 SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (conn);
400 g_return_if_fail (priv->state == SOUP_CONNECTION_IN_USE);
402 g_object_freeze_notify (G_OBJECT (conn));
404 if (priv->current_msg) {
405 g_return_if_fail (priv->current_msg->method == SOUP_METHOD_CONNECT);
406 clear_current_msg (conn);
409 stop_idle_timer (priv);
411 priv->current_msg = g_object_ref (msg);
412 priv->reusable = FALSE;
414 g_signal_connect (msg, "got-body",
415 G_CALLBACK (current_msg_got_body), conn);
417 if (priv->proxy_uri && msg->method == SOUP_METHOD_CONNECT)
418 soup_connection_event (conn, G_SOCKET_CLIENT_PROXY_NEGOTIATING, NULL);
420 g_object_thaw_notify (G_OBJECT (conn));
424 proxy_socket_event (SoupSocket *socket,
425 GSocketClientEvent event,
426 GIOStream *connection,
429 SoupConnection *conn = user_data;
431 /* We handle COMPLETE ourselves */
432 if (event != G_SOCKET_CLIENT_COMPLETE)
433 soup_connection_event (conn, event, connection);
437 SoupConnection *conn;
438 SoupConnectionCallback callback;
439 gpointer callback_data;
440 GCancellable *cancellable;
442 } SoupConnectionAsyncConnectData;
445 socket_connect_finished (SoupSocket *socket, guint status, gpointer user_data)
447 SoupConnectionAsyncConnectData *data = user_data;
448 SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (data->conn);
450 g_signal_handler_disconnect (socket, data->event_id);
452 if (SOUP_STATUS_IS_SUCCESSFUL (status)) {
453 if (priv->ssl && !priv->proxy_uri) {
454 soup_connection_event (data->conn,
455 G_SOCKET_CLIENT_TLS_HANDSHAKED,
458 if (!priv->ssl || !priv->proxy_uri) {
459 soup_connection_event (data->conn,
460 G_SOCKET_CLIENT_COMPLETE,
464 soup_connection_set_state (data->conn, SOUP_CONNECTION_IN_USE);
465 priv->unused_timeout = time (NULL) + SOUP_CONNECTION_UNUSED_TIMEOUT;
466 start_idle_timer (data->conn);
467 } else if (status == SOUP_STATUS_TLS_FAILED) {
468 priv->ssl_fallback = TRUE;
469 status = SOUP_STATUS_TRY_AGAIN;
472 if (data->callback) {
473 if (priv->proxy_uri != NULL)
474 status = soup_status_proxify (status);
475 data->callback (data->conn, status, data->callback_data);
477 if (!SOUP_STATUS_IS_SUCCESSFUL (status) && status != SOUP_STATUS_TRY_AGAIN)
478 soup_connection_disconnect (data->conn);
479 g_object_unref (data->conn);
480 if (data->cancellable)
481 g_object_unref (data->cancellable);
482 g_slice_free (SoupConnectionAsyncConnectData, data);
486 socket_connect_result (SoupSocket *sock, guint status, gpointer user_data)
488 SoupConnectionAsyncConnectData *data = user_data;
489 SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (data->conn);
491 if (!SOUP_STATUS_IS_SUCCESSFUL (status)) {
492 socket_connect_finished (sock, status, data);
496 if (priv->use_gproxyresolver)
497 priv->proxy_uri = soup_socket_get_http_proxy_uri (priv->socket);
499 if (priv->ssl && !priv->proxy_uri) {
500 if (soup_socket_start_ssl (sock, data->cancellable)) {
501 soup_connection_event (data->conn,
502 G_SOCKET_CLIENT_TLS_HANDSHAKING,
504 soup_socket_handshake_async (sock, data->cancellable,
505 socket_connect_finished, data);
509 status = SOUP_STATUS_SSL_FAILED;
512 socket_connect_finished (sock, status, data);
516 connect_async_to_uri (SoupConnectionAsyncConnectData *data, SoupURI *uri)
518 SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (data->conn);
519 SoupAddress *remote_addr;
521 remote_addr = soup_address_new (uri->host, uri->port);
523 soup_socket_new (SOUP_SOCKET_REMOTE_ADDRESS, remote_addr,
524 SOUP_SOCKET_SSL_CREDENTIALS, priv->tlsdb,
525 SOUP_SOCKET_SSL_STRICT, priv->ssl_strict,
526 SOUP_SOCKET_SSL_FALLBACK, priv->ssl_fallback,
527 SOUP_SOCKET_ASYNC_CONTEXT, priv->async_context,
528 SOUP_SOCKET_USE_THREAD_CONTEXT, priv->use_thread_context,
529 SOUP_SOCKET_USE_PROXY, priv->use_gproxyresolver,
530 SOUP_SOCKET_TIMEOUT, priv->io_timeout,
531 SOUP_SOCKET_CLEAN_DISPOSE, TRUE,
533 g_object_unref (remote_addr);
535 data->event_id = g_signal_connect (priv->socket, "event",
536 G_CALLBACK (proxy_socket_event),
539 soup_socket_connect_async (priv->socket, data->cancellable,
540 socket_connect_result, data);
544 proxy_resolver_result (SoupProxyURIResolver *resolver,
545 guint status, SoupURI *proxy_uri,
548 SoupConnectionAsyncConnectData *data = user_data;
549 SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (data->conn);
551 if (status != SOUP_STATUS_OK) {
552 socket_connect_finished (NULL, status, data);
557 priv->proxy_uri = soup_uri_copy (proxy_uri);
558 connect_async_to_uri (data, proxy_uri);
560 connect_async_to_uri (data, priv->remote_uri);
564 soup_connection_connect_async (SoupConnection *conn,
565 GCancellable *cancellable,
566 SoupConnectionCallback callback,
569 SoupConnectionAsyncConnectData *data;
570 SoupConnectionPrivate *priv;
571 GMainContext *async_context;
573 g_return_if_fail (SOUP_IS_CONNECTION (conn));
574 priv = SOUP_CONNECTION_GET_PRIVATE (conn);
575 g_return_if_fail (priv->socket == NULL);
577 soup_connection_set_state (conn, SOUP_CONNECTION_CONNECTING);
579 data = g_slice_new (SoupConnectionAsyncConnectData);
580 data->conn = g_object_ref (conn);
581 data->callback = callback;
582 data->callback_data = user_data;
583 data->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
585 if (!priv->proxy_resolver) {
586 connect_async_to_uri (data, priv->remote_uri);
590 if (priv->use_thread_context)
591 async_context = g_main_context_get_thread_default ();
593 async_context = priv->async_context;
595 soup_proxy_uri_resolver_get_proxy_uri_async (priv->proxy_resolver,
599 proxy_resolver_result,
604 soup_connection_connect_sync (SoupConnection *conn, GCancellable *cancellable)
606 SoupConnectionPrivate *priv;
607 guint status, event_id = 0;
608 SoupURI *connect_uri;
609 SoupAddress *remote_addr;
611 g_return_val_if_fail (SOUP_IS_CONNECTION (conn), SOUP_STATUS_MALFORMED);
612 priv = SOUP_CONNECTION_GET_PRIVATE (conn);
613 g_return_val_if_fail (priv->socket == NULL, SOUP_STATUS_MALFORMED);
615 soup_connection_set_state (conn, SOUP_CONNECTION_CONNECTING);
617 if (priv->proxy_resolver) {
618 status = soup_proxy_uri_resolver_get_proxy_uri_sync (priv->proxy_resolver,
622 if (status != SOUP_STATUS_OK)
626 connect_uri = priv->proxy_uri;
628 connect_uri = priv->remote_uri;
630 connect_uri = priv->remote_uri;
632 remote_addr = soup_address_new (connect_uri->host, connect_uri->port);
634 soup_socket_new (SOUP_SOCKET_REMOTE_ADDRESS, remote_addr,
635 SOUP_SOCKET_USE_PROXY, priv->use_gproxyresolver,
636 SOUP_SOCKET_SSL_CREDENTIALS, priv->tlsdb,
637 SOUP_SOCKET_SSL_STRICT, priv->ssl_strict,
638 SOUP_SOCKET_SSL_FALLBACK, priv->ssl_fallback,
639 SOUP_SOCKET_FLAG_NONBLOCKING, FALSE,
640 SOUP_SOCKET_TIMEOUT, priv->io_timeout,
641 SOUP_SOCKET_CLEAN_DISPOSE, TRUE,
643 g_object_unref (remote_addr);
644 event_id = g_signal_connect (priv->socket, "event",
645 G_CALLBACK (proxy_socket_event), conn);
646 status = soup_socket_connect_sync (priv->socket, cancellable);
648 if (!SOUP_STATUS_IS_SUCCESSFUL (status))
651 if (priv->use_gproxyresolver)
652 priv->proxy_uri = soup_socket_get_http_proxy_uri (priv->socket);
654 if (priv->ssl && !priv->proxy_uri) {
655 if (!soup_socket_start_ssl (priv->socket, cancellable))
656 status = SOUP_STATUS_SSL_FAILED;
658 soup_connection_event (conn,
659 G_SOCKET_CLIENT_TLS_HANDSHAKING,
661 status = soup_socket_handshake_sync (priv->socket, cancellable);
662 if (status == SOUP_STATUS_OK) {
663 soup_connection_event (conn,
664 G_SOCKET_CLIENT_TLS_HANDSHAKED,
666 } else if (status == SOUP_STATUS_TLS_FAILED) {
667 priv->ssl_fallback = TRUE;
668 status = SOUP_STATUS_TRY_AGAIN;
673 if (SOUP_STATUS_IS_SUCCESSFUL (status)) {
674 if (!priv->ssl || !priv->proxy_uri) {
675 soup_connection_event (conn,
676 G_SOCKET_CLIENT_COMPLETE,
679 soup_connection_set_state (conn, SOUP_CONNECTION_IN_USE);
680 priv->unused_timeout = time (NULL) + SOUP_CONNECTION_UNUSED_TIMEOUT;
681 start_idle_timer (conn);
682 } else if (status != SOUP_STATUS_TRY_AGAIN) {
685 soup_socket_disconnect (priv->socket);
686 g_object_unref (priv->socket);
690 soup_connection_disconnect (conn);
693 if (priv->socket && event_id)
694 g_signal_handler_disconnect (priv->socket, event_id);
696 if (priv->proxy_uri != NULL)
697 status = soup_status_proxify (status);
702 soup_connection_is_tunnelled (SoupConnection *conn)
704 SoupConnectionPrivate *priv;
706 g_return_val_if_fail (SOUP_IS_CONNECTION (conn), FALSE);
707 priv = SOUP_CONNECTION_GET_PRIVATE (conn);
709 return priv->ssl && priv->proxy_uri != NULL;
713 soup_connection_start_ssl_sync (SoupConnection *conn,
714 GCancellable *cancellable)
716 SoupConnectionPrivate *priv;
719 g_return_val_if_fail (SOUP_IS_CONNECTION (conn), FALSE);
720 priv = SOUP_CONNECTION_GET_PRIVATE (conn);
722 if (!soup_socket_start_proxy_ssl (priv->socket,
723 priv->remote_uri->host,
725 soup_connection_disconnect (conn);
726 return SOUP_STATUS_SSL_FAILED;
729 soup_connection_event (conn, G_SOCKET_CLIENT_TLS_HANDSHAKING, NULL);
730 status = soup_socket_handshake_sync (priv->socket, cancellable);
731 if (status == SOUP_STATUS_OK) {
732 soup_connection_event (conn, G_SOCKET_CLIENT_TLS_HANDSHAKED, NULL);
733 soup_connection_event (conn, G_SOCKET_CLIENT_COMPLETE, NULL);
734 } else if (status == SOUP_STATUS_TLS_FAILED) {
735 priv->ssl_fallback = TRUE;
736 status = SOUP_STATUS_TRY_AGAIN;
739 if (!SOUP_STATUS_IS_SUCCESSFUL (status) && status != SOUP_STATUS_TRY_AGAIN)
740 soup_connection_disconnect (conn);
746 start_ssl_completed (SoupSocket *socket, guint status, gpointer user_data)
748 SoupConnectionAsyncConnectData *data = user_data;
749 SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (data->conn);
751 if (status == SOUP_STATUS_OK) {
752 soup_connection_event (data->conn, G_SOCKET_CLIENT_TLS_HANDSHAKED, NULL);
753 soup_connection_event (data->conn, G_SOCKET_CLIENT_COMPLETE, NULL);
754 } else if (status == SOUP_STATUS_TLS_FAILED) {
755 priv->ssl_fallback = TRUE;
756 status = SOUP_STATUS_TRY_AGAIN;
759 data->callback (data->conn, status, data->callback_data);
760 if (!SOUP_STATUS_IS_SUCCESSFUL (status) && status != SOUP_STATUS_TRY_AGAIN)
761 soup_connection_disconnect (data->conn);
762 g_object_unref (data->conn);
763 g_slice_free (SoupConnectionAsyncConnectData, data);
767 idle_start_ssl_completed (gpointer user_data)
769 SoupConnectionAsyncConnectData *data = user_data;
771 start_ssl_completed (NULL, SOUP_STATUS_SSL_FAILED, data);
776 soup_connection_start_ssl_async (SoupConnection *conn,
777 GCancellable *cancellable,
778 SoupConnectionCallback callback,
781 SoupConnectionPrivate *priv;
782 SoupConnectionAsyncConnectData *data;
783 GMainContext *async_context;
785 g_return_if_fail (SOUP_IS_CONNECTION (conn));
786 priv = SOUP_CONNECTION_GET_PRIVATE (conn);
788 data = g_slice_new (SoupConnectionAsyncConnectData);
789 data->conn = g_object_ref (conn);
790 data->callback = callback;
791 data->callback_data = user_data;
793 if (priv->use_thread_context)
794 async_context = g_main_context_get_thread_default ();
796 async_context = priv->async_context;
798 if (!soup_socket_start_proxy_ssl (priv->socket,
799 priv->remote_uri->host,
801 soup_add_completion (async_context,
802 idle_start_ssl_completed, data);
806 soup_connection_event (conn, G_SOCKET_CLIENT_TLS_HANDSHAKING, NULL);
807 soup_socket_handshake_async (priv->socket, cancellable,
808 start_ssl_completed, data);
812 * soup_connection_disconnect:
813 * @conn: a connection
815 * Disconnects @conn's socket and emits a %disconnected signal.
816 * After calling this, @conn will be essentially useless.
819 soup_connection_disconnect (SoupConnection *conn)
821 SoupConnectionPrivate *priv;
822 SoupConnectionState old_state;
824 g_return_if_fail (SOUP_IS_CONNECTION (conn));
825 priv = SOUP_CONNECTION_GET_PRIVATE (conn);
827 old_state = priv->state;
828 if (old_state != SOUP_CONNECTION_DISCONNECTED)
829 soup_connection_set_state (conn, SOUP_CONNECTION_DISCONNECTED);
832 SoupSocket *socket = priv->socket;
835 soup_socket_disconnect (socket);
836 g_object_unref (socket);
839 if (old_state != SOUP_CONNECTION_DISCONNECTED)
840 g_signal_emit (conn, signals[DISCONNECTED], 0);
844 soup_connection_get_socket (SoupConnection *conn)
846 g_return_val_if_fail (SOUP_IS_CONNECTION (conn), NULL);
848 return SOUP_CONNECTION_GET_PRIVATE (conn)->socket;
852 soup_connection_get_remote_uri (SoupConnection *conn)
854 g_return_val_if_fail (SOUP_IS_CONNECTION (conn), NULL);
856 return SOUP_CONNECTION_GET_PRIVATE (conn)->remote_uri;
860 soup_connection_get_proxy_uri (SoupConnection *conn)
862 g_return_val_if_fail (SOUP_IS_CONNECTION (conn), NULL);
864 return SOUP_CONNECTION_GET_PRIVATE (conn)->proxy_uri;
868 soup_connection_is_via_proxy (SoupConnection *conn)
870 g_return_val_if_fail (SOUP_IS_CONNECTION (conn), FALSE);
872 return SOUP_CONNECTION_GET_PRIVATE (conn)->proxy_uri != NULL;
876 soup_connection_get_state (SoupConnection *conn)
878 SoupConnectionPrivate *priv;
880 g_return_val_if_fail (SOUP_IS_CONNECTION (conn),
881 SOUP_CONNECTION_DISCONNECTED);
882 priv = SOUP_CONNECTION_GET_PRIVATE (conn);
884 if (priv->state == SOUP_CONNECTION_IDLE &&
885 g_socket_condition_check (soup_socket_get_gsocket (priv->socket), G_IO_IN))
886 soup_connection_set_state (conn, SOUP_CONNECTION_REMOTE_DISCONNECTED);
888 if (priv->state == SOUP_CONNECTION_IDLE &&
889 priv->unused_timeout && priv->unused_timeout < time (NULL))
890 soup_connection_set_state (conn, SOUP_CONNECTION_REMOTE_DISCONNECTED);
896 soup_connection_set_state (SoupConnection *conn, SoupConnectionState state)
898 SoupConnectionPrivate *priv;
900 g_return_if_fail (SOUP_IS_CONNECTION (conn));
901 g_return_if_fail (state >= SOUP_CONNECTION_NEW &&
902 state <= SOUP_CONNECTION_DISCONNECTED);
904 g_object_freeze_notify (G_OBJECT (conn));
906 priv = SOUP_CONNECTION_GET_PRIVATE (conn);
908 if (priv->current_msg) {
909 g_warn_if_fail (state == SOUP_CONNECTION_IDLE ||
910 state == SOUP_CONNECTION_DISCONNECTED);
911 clear_current_msg (conn);
914 if (state == SOUP_CONNECTION_IDLE && !priv->reusable) {
915 /* This will recursively call set_state() */
916 soup_connection_disconnect (conn);
920 if (priv->state == SOUP_CONNECTION_IDLE)
921 start_idle_timer (conn);
923 g_object_notify (G_OBJECT (conn), "state");
926 g_object_thaw_notify (G_OBJECT (conn));
930 soup_connection_get_ever_used (SoupConnection *conn)
932 g_return_val_if_fail (SOUP_IS_CONNECTION (conn), FALSE);
934 return SOUP_CONNECTION_GET_PRIVATE (conn)->unused_timeout == 0;
938 soup_connection_get_ssl_fallback (SoupConnection *conn)
940 return SOUP_CONNECTION_GET_PRIVATE (conn)->ssl_fallback;
944 soup_connection_send_request (SoupConnection *conn,
945 SoupMessageQueueItem *item,
946 SoupMessageCompletionFn completion_cb,
949 SoupConnectionPrivate *priv;
951 g_return_if_fail (SOUP_IS_CONNECTION (conn));
952 g_return_if_fail (item != NULL);
953 priv = SOUP_CONNECTION_GET_PRIVATE (conn);
954 g_return_if_fail (priv->state != SOUP_CONNECTION_NEW &&
955 priv->state != SOUP_CONNECTION_DISCONNECTED);
957 if (item->msg != priv->current_msg)
958 set_current_msg (conn, item->msg);
959 soup_message_send_request (item, completion_cb, user_data);