summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Winship <danw@gnome.org>2013-12-09 12:16:05 +0100
committerDan Winship <danw@gnome.org>2013-12-09 14:51:51 +0100
commit3f8e0d45cdf97f999c3f9362578b2ff0871021f2 (patch)
treed0fcb7c37663459b61ea0ae8eaf0df690e3beab7
parent229569ec354c498efdaca430856fe48b3c4c273d (diff)
downloadlibsoup-3f8e0d45cdf97f999c3f9362578b2ff0871021f2.tar.gz
SoupSessionHost: split from SoupSession
HTTP/2.0 will need to do connection management differently, so let's split SoupSessionHost out of soup-session.c in preparation for making it more complicated. (The split is a little bit awkward at the moment but will hopefully be cleaned up some.)
-rw-r--r--libsoup/Makefile.am2
-rw-r--r--libsoup/soup-connection.c8
-rw-r--r--libsoup/soup-connection.h1
-rw-r--r--libsoup/soup-misc-private.h4
-rw-r--r--libsoup/soup-misc.c17
-rw-r--r--libsoup/soup-session-host.c249
-rw-r--r--libsoup/soup-session-host.h57
-rw-r--r--libsoup/soup-session-private.h2
-rw-r--r--libsoup/soup-session.c259
9 files changed, 409 insertions, 190 deletions
diff --git a/libsoup/Makefile.am b/libsoup/Makefile.am
index 32502df6..73b4fb53 100644
--- a/libsoup/Makefile.am
+++ b/libsoup/Makefile.am
@@ -181,6 +181,8 @@ libsoup_2_4_la_SOURCES = \
soup-session.c \
soup-session-async.c \
soup-session-feature.c \
+ soup-session-host.c \
+ soup-session-host.h \
soup-session-private.h \
soup-session-sync.c \
soup-socket.c \
diff --git a/libsoup/soup-connection.c b/libsoup/soup-connection.c
index 32a52c06..f59a9f85 100644
--- a/libsoup/soup-connection.c
+++ b/libsoup/soup-connection.c
@@ -44,7 +44,6 @@ enum {
PROP_0,
PROP_REMOTE_URI,
- PROP_SSL,
PROP_SSL_FALLBACK,
PROP_SOCKET_PROPERTIES,
PROP_STATE,
@@ -101,9 +100,7 @@ soup_connection_set_property (GObject *object, guint prop_id,
switch (prop_id) {
case PROP_REMOTE_URI:
priv->remote_uri = g_value_dup_boxed (value);
- break;
- case PROP_SSL:
- priv->ssl = g_value_get_boolean (value);
+ priv->ssl = (priv->remote_uri->scheme == SOUP_URI_SCHEME_HTTPS);
break;
case PROP_SSL_FALLBACK:
priv->ssl_fallback = g_value_get_boolean (value);
@@ -130,9 +127,6 @@ soup_connection_get_property (GObject *object, guint prop_id,
case PROP_REMOTE_URI:
g_value_set_boxed (value, priv->remote_uri);
break;
- case PROP_SSL:
- g_value_set_boolean (value, priv->ssl);
- break;
case PROP_SSL_FALLBACK:
g_value_set_boolean (value, priv->ssl_fallback);
break;
diff --git a/libsoup/soup-connection.h b/libsoup/soup-connection.h
index 3fd6721f..8df61129 100644
--- a/libsoup/soup-connection.h
+++ b/libsoup/soup-connection.h
@@ -36,7 +36,6 @@ GType soup_connection_get_type (void);
#define SOUP_CONNECTION_REMOTE_URI "remote-uri"
-#define SOUP_CONNECTION_SSL "ssl"
#define SOUP_CONNECTION_SSL_FALLBACK "ssl-fallback"
#define SOUP_CONNECTION_SOCKET_PROPERTIES "socket-properties"
#define SOUP_CONNECTION_STATE "state"
diff --git a/libsoup/soup-misc-private.h b/libsoup/soup-misc-private.h
index 52b815e3..01253c75 100644
--- a/libsoup/soup-misc-private.h
+++ b/libsoup/soup-misc-private.h
@@ -66,6 +66,10 @@ SoupURI *soup_socket_get_http_proxy_uri (SoupSocket *sock);
GSource *soup_add_completion_reffed (GMainContext *async_context,
GSourceFunc function,
gpointer data);
+GSource *soup_add_timeout_reffed (GMainContext *async_context,
+ guint interval,
+ GSourceFunc function,
+ gpointer data);
guint soup_message_headers_get_ranges_internal (SoupMessageHeaders *hdrs,
goffset total_length,
diff --git a/libsoup/soup-misc.c b/libsoup/soup-misc.c
index 325b5872..747a5d44 100644
--- a/libsoup/soup-misc.c
+++ b/libsoup/soup-misc.c
@@ -153,6 +153,17 @@ soup_add_completion (GMainContext *async_context,
return source;
}
+GSource *
+soup_add_timeout_reffed (GMainContext *async_context,
+ guint interval,
+ GSourceFunc function, gpointer data)
+{
+ GSource *source = g_timeout_source_new (interval);
+ g_source_set_callback (source, function, data, NULL);
+ g_source_attach (source, async_context);
+ return source;
+}
+
/**
* soup_add_timeout: (skip)
* @async_context: (allow-none): the #GMainContext to dispatch the I/O
@@ -172,9 +183,9 @@ soup_add_timeout (GMainContext *async_context,
guint interval,
GSourceFunc function, gpointer data)
{
- GSource *source = g_timeout_source_new (interval);
- g_source_set_callback (source, function, data, NULL);
- g_source_attach (source, async_context);
+ GSource *source;
+
+ source = soup_add_timeout_reffed (async_context, interval, function, data);
g_source_unref (source);
return source;
}
diff --git a/libsoup/soup-session-host.c b/libsoup/soup-session-host.c
new file mode 100644
index 00000000..ba3e7f62
--- /dev/null
+++ b/libsoup/soup-session-host.c
@@ -0,0 +1,249 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * soup-session-host.c
+ *
+ * Copyright 2013 Red Hat, Inc.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "soup-session-host.h"
+#include "soup.h"
+#include "soup-connection.h"
+#include "soup-misc-private.h"
+#include "soup-session-private.h"
+#include "soup-socket-properties.h"
+
+G_DEFINE_TYPE (SoupSessionHost, soup_session_host, G_TYPE_OBJECT)
+
+typedef struct {
+ SoupURI *uri;
+ SoupAddress *addr;
+
+ GSList *connections; /* CONTAINS: SoupConnection */
+ guint num_conns;
+ guint max_conns;
+
+ guint num_messages;
+
+ gboolean ssl_fallback;
+
+ GSource *keep_alive_src;
+ SoupSession *session;
+} SoupSessionHostPrivate;
+#define SOUP_SESSION_HOST_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUP_TYPE_SESSION_HOST, SoupSessionHostPrivate))
+
+enum {
+ UNUSED,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+#define HOST_KEEP_ALIVE 5 * 60 * 1000 /* 5 min in msecs */
+
+static void
+soup_session_host_init (SoupSessionHost *host)
+{
+}
+
+static void
+soup_session_host_finalize (GObject *object)
+{
+ SoupSessionHostPrivate *priv = SOUP_SESSION_HOST_GET_PRIVATE (object);
+
+ g_warn_if_fail (priv->connections == NULL);
+
+ if (priv->keep_alive_src) {
+ g_source_destroy (priv->keep_alive_src);
+ g_source_unref (priv->keep_alive_src);
+ }
+
+ soup_uri_free (priv->uri);
+ g_object_unref (priv->addr);
+
+ G_OBJECT_CLASS (soup_session_host_parent_class)->finalize (object);
+}
+
+static void
+soup_session_host_class_init (SoupSessionHostClass *host_class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (host_class);
+
+ g_type_class_add_private (host_class, sizeof (SoupSessionHostClass));
+
+ object_class->finalize = soup_session_host_finalize;
+
+ signals[UNUSED] =
+ g_signal_new ("unused",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ NULL,
+ G_TYPE_NONE, 0);
+
+}
+
+SoupSessionHost *
+soup_session_host_new (SoupSession *session,
+ SoupURI *uri)
+{
+ SoupSessionHost *host;
+ SoupSessionHostPrivate *priv;
+
+ host = g_object_new (SOUP_TYPE_SESSION_HOST, NULL);
+ priv = SOUP_SESSION_HOST_GET_PRIVATE (host);
+
+ priv->uri = soup_uri_copy_host (uri);
+ priv->addr = g_object_new (SOUP_TYPE_ADDRESS,
+ SOUP_ADDRESS_NAME, priv->uri->host,
+ SOUP_ADDRESS_PORT, priv->uri->port,
+ SOUP_ADDRESS_PROTOCOL, priv->uri->scheme,
+ NULL);
+ priv->keep_alive_src = NULL;
+ priv->session = session;
+
+ g_object_get (G_OBJECT (session),
+ SOUP_SESSION_MAX_CONNS_PER_HOST, &priv->max_conns,
+ NULL);
+
+ return host;
+}
+
+SoupURI *
+soup_session_host_get_uri (SoupSessionHost *host)
+{
+ return SOUP_SESSION_HOST_GET_PRIVATE (host)->uri;
+}
+
+SoupAddress *
+soup_session_host_get_address (SoupSessionHost *host)
+{
+ return SOUP_SESSION_HOST_GET_PRIVATE (host)->addr;
+}
+
+void
+soup_session_host_add_message (SoupSessionHost *host,
+ SoupMessage *msg)
+{
+ SOUP_SESSION_HOST_GET_PRIVATE (host)->num_messages++;
+}
+
+void
+soup_session_host_remove_message (SoupSessionHost *host,
+ SoupMessage *msg)
+{
+ SOUP_SESSION_HOST_GET_PRIVATE (host)->num_messages--;
+}
+
+static gboolean
+emit_unused (gpointer host)
+{
+ g_signal_emit (host, signals[UNUSED], 0);
+ return FALSE;
+}
+
+SoupConnection *
+soup_session_host_get_connection (SoupSessionHost *host,
+ gboolean need_new_connection,
+ gboolean at_max_conns,
+ gboolean *try_cleanup)
+{
+ SoupSessionHostPrivate *priv = SOUP_SESSION_HOST_GET_PRIVATE (host);
+ SoupConnection *conn;
+ GSList *conns;
+ int num_pending = 0;
+ SoupSocketProperties *socket_props;
+
+ for (conns = priv->connections; conns; conns = conns->next) {
+ conn = conns->data;
+
+ if (!need_new_connection && soup_connection_get_state (conn) == SOUP_CONNECTION_IDLE) {
+ soup_connection_set_state (conn, SOUP_CONNECTION_IN_USE);
+ return conn;
+ } else if (soup_connection_get_state (conn) == SOUP_CONNECTION_CONNECTING)
+ num_pending++;
+ }
+
+ /* Limit the number of pending connections; num_messages / 2
+ * is somewhat arbitrary...
+ */
+ if (num_pending > priv->num_messages / 2)
+ return NULL;
+
+ if (priv->num_conns >= priv->max_conns) {
+ if (need_new_connection)
+ *try_cleanup = TRUE;
+ return NULL;
+ }
+
+ if (at_max_conns) {
+ *try_cleanup = TRUE;
+ return NULL;
+ }
+
+ g_object_get (G_OBJECT (priv->session),
+ SOUP_SESSION_SOCKET_PROPERTIES, &socket_props,
+ NULL);
+ conn = g_object_new (SOUP_TYPE_CONNECTION,
+ SOUP_CONNECTION_REMOTE_URI, priv->uri,
+ SOUP_CONNECTION_SSL_FALLBACK, priv->ssl_fallback,
+ SOUP_CONNECTION_SOCKET_PROPERTIES, socket_props,
+ NULL);
+ soup_socket_properties_unref (socket_props);
+
+ priv->num_conns++;
+ priv->connections = g_slist_prepend (priv->connections, conn);
+
+ if (priv->keep_alive_src) {
+ g_source_destroy (priv->keep_alive_src);
+ g_source_unref (priv->keep_alive_src);
+ priv->keep_alive_src = NULL;
+ }
+
+ return conn;
+}
+
+void
+soup_session_host_remove_connection (SoupSessionHost *host,
+ SoupConnection *conn)
+{
+ SoupSessionHostPrivate *priv = SOUP_SESSION_HOST_GET_PRIVATE (host);
+
+ if (soup_connection_get_ssl_fallback (conn))
+ priv->ssl_fallback = TRUE;
+
+ priv->connections = g_slist_remove (priv->connections, conn);
+ priv->num_conns--;
+
+ if (priv->num_conns == 0) {
+ g_assert (priv->keep_alive_src == NULL);
+ priv->keep_alive_src = soup_add_timeout_reffed (soup_session_get_async_context (priv->session),
+ HOST_KEEP_ALIVE,
+ emit_unused,
+ host);
+ }
+}
+
+int
+soup_session_host_get_num_connections (SoupSessionHost *host)
+{
+ return SOUP_SESSION_HOST_GET_PRIVATE (host)->num_conns;
+}
+
+gboolean
+soup_session_host_get_ssl_fallback (SoupSessionHost *host)
+{
+ return SOUP_SESSION_HOST_GET_PRIVATE (host)->ssl_fallback;
+}
+
+void
+soup_session_host_set_ssl_fallback (SoupSessionHost *host,
+ gboolean ssl_fallback)
+{
+ SOUP_SESSION_HOST_GET_PRIVATE (host)->ssl_fallback = ssl_fallback;
+}
+
diff --git a/libsoup/soup-session-host.h b/libsoup/soup-session-host.h
new file mode 100644
index 00000000..fecd5d23
--- /dev/null
+++ b/libsoup/soup-session-host.h
@@ -0,0 +1,57 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright 2013 Red Hat, Inc.
+ */
+
+#ifndef SOUP_SESSION_HOST_H
+#define SOUP_SESSION_HOST_H 1
+
+#include "soup-types.h"
+
+G_BEGIN_DECLS
+
+#define SOUP_TYPE_SESSION_HOST (soup_session_host_get_type ())
+#define SOUP_SESSION_HOST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SOUP_TYPE_SESSION_HOST, SoupSessionHost))
+#define SOUP_SESSION_HOST_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SOUP_TYPE_SESSION_HOST, SoupSessionHostClass))
+#define SOUP_IS_SESSION_HOST(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SOUP_TYPE_SESSION_HOST))
+#define SOUP_IS_SESSION_HOST_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), SOUP_TYPE_SESSION_HOST))
+#define SOUP_SESSION_HOST_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SOUP_TYPE_SESSION_HOST, SoupSessionHostClass))
+
+typedef struct {
+ GObject parent;
+
+} SoupSessionHost;
+
+typedef struct {
+ GObjectClass parent_class;
+
+} SoupSessionHostClass;
+
+GType soup_session_host_get_type (void);
+
+SoupSessionHost *soup_session_host_new (SoupSession *session,
+ SoupURI *uri);
+
+SoupURI *soup_session_host_get_uri (SoupSessionHost *host);
+SoupAddress *soup_session_host_get_address (SoupSessionHost *host);
+
+void soup_session_host_add_message (SoupSessionHost *host,
+ SoupMessage *msg);
+void soup_session_host_remove_message (SoupSessionHost *host,
+ SoupMessage *msg);
+
+SoupConnection *soup_session_host_get_connection (SoupSessionHost *host,
+ gboolean need_new_connection,
+ gboolean at_max_conns,
+ gboolean *try_cleanup);
+void soup_session_host_remove_connection (SoupSessionHost *host,
+ SoupConnection *conn);
+int soup_session_host_get_num_connections (SoupSessionHost *host);
+
+gboolean soup_session_host_get_ssl_fallback (SoupSessionHost *host);
+void soup_session_host_set_ssl_fallback (SoupSessionHost *host,
+ gboolean ssl_fallback);
+
+G_END_DECLS
+
+#endif /* SOUP_SESSION_HOST_H */
diff --git a/libsoup/soup-session-private.h b/libsoup/soup-session-private.h
index dc4d300b..b769e9d8 100644
--- a/libsoup/soup-session-private.h
+++ b/libsoup/soup-session-private.h
@@ -12,6 +12,8 @@
G_BEGIN_DECLS
+#define SOUP_SESSION_SOCKET_PROPERTIES "socket-properties"
+
/* "protected" methods for subclasses */
SoupMessageQueue *soup_session_get_queue (SoupSession *session);
diff --git a/libsoup/soup-session.c b/libsoup/soup-session.c
index 9f0c2cd0..03af7cd4 100644
--- a/libsoup/soup-session.c
+++ b/libsoup/soup-session.c
@@ -20,11 +20,10 @@
#include "soup-misc-private.h"
#include "soup-message-queue.h"
#include "soup-proxy-resolver-wrapper.h"
+#include "soup-session-host.h"
#include "soup-session-private.h"
#include "soup-socket-properties.h"
-#define HOST_KEEP_ALIVE 5 * 60 * 1000 /* 5 min in msecs */
-
/**
* SECTION:soup-session
* @short_description: Soup session state object
@@ -65,22 +64,9 @@ soup_init (void)
#endif
}
-typedef struct {
- SoupURI *uri;
- SoupAddress *addr;
-
- GSList *connections; /* CONTAINS: SoupConnection */
- guint num_conns;
-
- guint num_messages;
-
- gboolean ssl_fallback;
-
- GSource *keep_alive_src;
- SoupSession *session;
-} SoupSessionHost;
static guint soup_host_uri_hash (gconstpointer key);
static gboolean soup_host_uri_equal (gconstpointer v1, gconstpointer v2);
+static void free_unused_host (SoupSessionHost *host, gpointer session);
typedef struct {
SoupSession *session;
@@ -135,7 +121,6 @@ typedef struct {
#define SOUP_IS_PLAIN_SESSION(o) (G_TYPE_FROM_INSTANCE (o) == SOUP_TYPE_SESSION)
-static void free_host (SoupSessionHost *host);
static void connection_state_changed (GObject *object, GParamSpec *param,
gpointer user_data);
static void connection_disconnected (SoupConnection *conn, gpointer user_data);
@@ -176,6 +161,7 @@ static guint signals[LAST_SIGNAL] = { 0 };
enum {
PROP_0,
+ PROP_SOCKET_PROPERTIES,
PROP_PROXY_URI,
PROP_PROXY_RESOLVER,
PROP_MAX_CONNS,
@@ -216,10 +202,10 @@ soup_session_init (SoupSession *session)
g_cond_init (&priv->conn_cond);
priv->http_hosts = g_hash_table_new_full (soup_host_uri_hash,
soup_host_uri_equal,
- NULL, (GDestroyNotify)free_host);
+ NULL, g_object_unref);
priv->https_hosts = g_hash_table_new_full (soup_host_uri_hash,
soup_host_uri_equal,
- NULL, (GDestroyNotify)free_host);
+ NULL, g_object_unref);
priv->conns = g_hash_table_new (NULL, NULL);
priv->max_conns = SOUP_SESSION_MAX_CONNS_DEFAULT;
@@ -754,8 +740,21 @@ soup_session_get_property (GObject *object, guint prop_id,
SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
SoupSessionFeature *feature;
GTlsDatabase *tlsdb;
+ SoupSocketProperties *props;
switch (prop_id) {
+ case PROP_SOCKET_PROPERTIES:
+ tlsdb = get_tls_database (session);
+ props = soup_socket_properties_new (priv->async_context,
+ priv->use_thread_context,
+ get_proxy_resolver (session),
+ priv->local_addr,
+ tlsdb,
+ priv->ssl_strict && (tlsdb != NULL || SOUP_IS_PLAIN_SESSION (priv->session)),
+ priv->io_timeout,
+ priv->idle_timeout);
+ g_value_take_boxed (value, props);
+ break;
case PROP_LOCAL_ADDRESS:
g_value_set_object (value, priv->local_addr);
break;
@@ -925,55 +924,38 @@ soup_host_uri_equal (gconstpointer v1, gconstpointer v2)
return g_ascii_strcasecmp (one->host, two->host) == 0;
}
-
-static SoupSessionHost *
-soup_session_host_new (SoupSession *session, SoupURI *uri)
-{
- SoupSessionHost *host;
-
- host = g_slice_new0 (SoupSessionHost);
- host->uri = soup_uri_copy_host (uri);
- if (host->uri->scheme != SOUP_URI_SCHEME_HTTP &&
- host->uri->scheme != SOUP_URI_SCHEME_HTTPS) {
- SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
-
- if (soup_uri_is_https (host->uri, priv->https_aliases))
- host->uri->scheme = SOUP_URI_SCHEME_HTTPS;
- else
- host->uri->scheme = SOUP_URI_SCHEME_HTTP;
- }
-
- host->addr = g_object_new (SOUP_TYPE_ADDRESS,
- SOUP_ADDRESS_NAME, host->uri->host,
- SOUP_ADDRESS_PORT, host->uri->port,
- SOUP_ADDRESS_PROTOCOL, host->uri->scheme,
- NULL);
- host->keep_alive_src = NULL;
- host->session = session;
-
- return host;
-}
-
/* Requires conn_lock to be locked */
static SoupSessionHost *
get_host_for_uri (SoupSession *session, SoupURI *uri)
{
SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
SoupSessionHost *host;
+ gboolean https;
+ SoupURI *uri_tmp = NULL;
- if (soup_uri_is_https (uri, priv->https_aliases))
+ https = soup_uri_is_https (uri, priv->https_aliases);
+ if (https)
host = g_hash_table_lookup (priv->https_hosts, uri);
else
host = g_hash_table_lookup (priv->http_hosts, uri);
if (host)
return host;
+ if (uri->scheme != SOUP_URI_SCHEME_HTTP &&
+ uri->scheme != SOUP_URI_SCHEME_HTTPS) {
+ uri = uri_tmp = soup_uri_copy (uri);
+ uri->scheme = https ? SOUP_URI_SCHEME_HTTPS : SOUP_URI_SCHEME_HTTP;
+ }
host = soup_session_host_new (session, uri);
+ if (uri_tmp)
+ soup_uri_free (uri_tmp);
- if (soup_uri_is_https (uri, priv->https_aliases))
- g_hash_table_insert (priv->https_hosts, host->uri, host);
+ if (https)
+ g_hash_table_insert (priv->https_hosts, soup_session_host_get_uri (host), host);
else
- g_hash_table_insert (priv->http_hosts, host->uri, host);
+ g_hash_table_insert (priv->http_hosts, soup_session_host_get_uri (host), host);
+
+ g_signal_connect (host, "unused", G_CALLBACK (free_unused_host), session);
return host;
}
@@ -986,21 +968,6 @@ get_host_for_message (SoupSession *session, SoupMessage *msg)
}
static void
-free_host (SoupSessionHost *host)
-{
- g_warn_if_fail (host->connections == NULL);
-
- if (host->keep_alive_src) {
- g_source_destroy (host->keep_alive_src);
- g_source_unref (host->keep_alive_src);
- }
-
- soup_uri_free (host->uri);
- g_object_unref (host->addr);
- g_slice_free (SoupSessionHost, host);
-}
-
-static void
auth_manager_authenticate (SoupAuthManager *manager, SoupMessage *msg,
SoupAuth *auth, gboolean retrying,
gpointer session)
@@ -1221,7 +1188,7 @@ soup_session_append_queue_item (SoupSession *session, SoupMessage *msg,
g_mutex_lock (&priv->conn_lock);
host = get_host_for_message (session, item->msg);
- host->num_messages++;
+ soup_session_host_add_message (host, msg);
g_mutex_unlock (&priv->conn_lock);
if (!(soup_message_get_flags (msg) & SOUP_MESSAGE_NO_REDIRECT)) {
@@ -1313,32 +1280,32 @@ soup_session_cleanup_connections (SoupSession *session,
return TRUE;
}
-static gboolean
-free_unused_host (gpointer user_data)
+static void
+free_unused_host (SoupSessionHost *host,
+ gpointer session)
{
- SoupSessionHost *host = (SoupSessionHost *) user_data;
- SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (host->session);
+ SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
+ SoupURI *uri;
g_mutex_lock (&priv->conn_lock);
/* In a multithreaded session, a connection might have been
* added while we were waiting for conn_lock.
*/
- if (host->connections) {
+ if (soup_session_host_get_num_connections (host)) {
g_mutex_unlock (&priv->conn_lock);
- return FALSE;
+ return;
}
/* This will free the host in addition to removing it from the
* hash table
*/
- if (host->uri->scheme == SOUP_URI_SCHEME_HTTPS)
- g_hash_table_remove (priv->https_hosts, host->uri);
+ uri = soup_session_host_get_uri (host);
+ if (uri->scheme == SOUP_URI_SCHEME_HTTPS)
+ g_hash_table_remove (priv->https_hosts, uri);
else
- g_hash_table_remove (priv->http_hosts, host->uri);
+ g_hash_table_remove (priv->http_hosts, uri);
g_mutex_unlock (&priv->conn_lock);
-
- return FALSE;
}
static void
@@ -1350,26 +1317,8 @@ drop_connection (SoupSession *session, SoupSessionHost *host, SoupConnection *co
* from priv->conns itself.
*/
- if (host) {
- host->connections = g_slist_remove (host->connections, conn);
- host->num_conns--;
-
- /* Free the SoupHost (and its SoupAddress) if there
- * has not been any new connection to the host during
- * the last HOST_KEEP_ALIVE msecs.
- */
- if (host->num_conns == 0) {
- g_assert (host->keep_alive_src == NULL);
- host->keep_alive_src = soup_add_timeout (priv->async_context,
- HOST_KEEP_ALIVE,
- free_unused_host,
- host);
- host->keep_alive_src = g_source_ref (host->keep_alive_src);
- }
-
- if (soup_connection_get_ssl_fallback (conn))
- host->ssl_fallback = TRUE;
- }
+ if (host)
+ soup_session_host_remove_connection (host, conn);
g_signal_handlers_disconnect_by_func (conn, connection_disconnected, session);
g_signal_handlers_disconnect_by_func (conn, connection_state_changed, session);
@@ -1438,7 +1387,7 @@ soup_session_unqueue_item (SoupSession *session,
g_mutex_lock (&priv->conn_lock);
host = get_host_for_message (session, item->msg);
- host->num_messages--;
+ soup_session_host_remove_message (host, item->msg);
g_cond_broadcast (&priv->conn_cond);
g_mutex_unlock (&priv->conn_lock);
@@ -1527,8 +1476,8 @@ status_from_connect_error (SoupMessageQueueItem *item, GError *error)
g_mutex_lock (&priv->conn_lock);
host = get_host_for_message (item->session, item->msg);
- if (!host->ssl_fallback) {
- host->ssl_fallback = TRUE;
+ if (!soup_session_host_get_ssl_fallback (host)) {
+ soup_session_host_set_ssl_fallback (host, TRUE);
status = SOUP_STATUS_TRY_AGAIN;
} else
status = SOUP_STATUS_SSL_FAILED;
@@ -1728,90 +1677,35 @@ get_connection_for_host (SoupSession *session,
{
SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
SoupConnection *conn;
- GSList *conns;
- int num_pending = 0;
- GTlsDatabase *tlsdb;
- gboolean ssl_strict;
- SoupSocketProperties *socket_props;
if (priv->disposed)
- return FALSE;
+ return NULL;
if (item->conn) {
- g_return_val_if_fail (soup_connection_get_state (item->conn) != SOUP_CONNECTION_DISCONNECTED, FALSE);
+ g_return_val_if_fail (soup_connection_get_state (item->conn) != SOUP_CONNECTION_DISCONNECTED, NULL);
return item->conn;
}
- for (conns = host->connections; conns; conns = conns->next) {
- conn = conns->data;
-
- if (!need_new_connection && soup_connection_get_state (conn) == SOUP_CONNECTION_IDLE) {
- soup_connection_set_state (conn, SOUP_CONNECTION_IN_USE);
- return conn;
- } else if (soup_connection_get_state (conn) == SOUP_CONNECTION_CONNECTING)
- num_pending++;
- }
-
- /* Limit the number of pending connections; num_messages / 2
- * is somewhat arbitrary...
- */
- if (num_pending > host->num_messages / 2)
- return NULL;
-
- if (host->num_conns >= priv->max_conns_per_host) {
- if (need_new_connection)
- *try_cleanup = TRUE;
- return NULL;
- }
-
- if (priv->num_conns >= priv->max_conns) {
- *try_cleanup = TRUE;
- return NULL;
- }
-
- tlsdb = get_tls_database (session);
- ssl_strict = priv->ssl_strict && (tlsdb != NULL || SOUP_IS_PLAIN_SESSION (priv->session));
- socket_props = soup_socket_properties_new (priv->async_context,
- priv->use_thread_context,
- get_proxy_resolver (session),
- priv->local_addr,
- tlsdb,
- ssl_strict,
- priv->io_timeout,
- priv->idle_timeout);
-
- conn = g_object_new (
- SOUP_TYPE_CONNECTION,
- SOUP_CONNECTION_REMOTE_URI, host->uri,
- SOUP_CONNECTION_SSL, soup_uri_is_https (soup_message_get_uri (item->msg), priv->https_aliases),
- SOUP_CONNECTION_SSL_FALLBACK, host->ssl_fallback,
- SOUP_CONNECTION_SOCKET_PROPERTIES, socket_props,
- NULL);
- soup_socket_properties_unref (socket_props);
-
- g_signal_connect (conn, "disconnected",
- G_CALLBACK (connection_disconnected),
- session);
- g_signal_connect (conn, "notify::state",
- G_CALLBACK (connection_state_changed),
- session);
-
- /* This is a debugging-related signal, and so can ignore the
- * usual rule about not emitting signals while holding
- * conn_lock.
- */
- g_signal_emit (session, signals[CONNECTION_CREATED], 0, conn);
-
- g_hash_table_insert (priv->conns, conn, host);
-
- priv->num_conns++;
- host->num_conns++;
- host->connections = g_slist_prepend (host->connections, conn);
+ conn = soup_session_host_get_connection (host, need_new_connection,
+ priv->num_conns >= priv->max_conns,
+ try_cleanup);
+
+ if (conn && soup_connection_get_state (conn) == SOUP_CONNECTION_NEW) {
+ g_signal_connect (conn, "disconnected",
+ G_CALLBACK (connection_disconnected),
+ session);
+ g_signal_connect (conn, "notify::state",
+ G_CALLBACK (connection_state_changed),
+ session);
+
+ /* This is a debugging-related signal, and so can ignore the
+ * usual rule about not emitting signals while holding
+ * conn_lock.
+ */
+ g_signal_emit (session, signals[CONNECTION_CREATED], 0, conn);
- if (host->keep_alive_src) {
- g_source_destroy (host->keep_alive_src);
- g_source_unref (host->keep_alive_src);
- host->keep_alive_src = NULL;
+ g_hash_table_insert (priv->conns, conn, host);
+ priv->num_conns++;
}
return conn;
@@ -2488,7 +2382,7 @@ prefetch_uri (SoupSession *session, SoupURI *uri,
g_mutex_lock (&priv->conn_lock);
host = get_host_for_uri (session, uri);
- addr = g_object_ref (host->addr);
+ addr = g_object_ref (soup_session_host_get_address (host));
g_mutex_unlock (&priv->conn_lock);
soup_address_resolve_async (addr,
@@ -3098,6 +2992,13 @@ soup_session_class_init (SoupSessionClass *session_class)
/* properties */
+ g_object_class_install_property (
+ object_class, PROP_SOCKET_PROPERTIES,
+ g_param_spec_boxed (SOUP_SESSION_SOCKET_PROPERTIES,
+ "Socket properties",
+ "Socket properties",
+ SOUP_TYPE_SOCKET_PROPERTIES,
+ G_PARAM_READABLE));
/**
* SoupSession:proxy-uri:
*