summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Winship <danw@gnome.org>2009-07-26 10:43:14 -0400
committerDan Winship <danw@gnome.org>2011-11-05 09:10:03 -0400
commitc68bff78ac88efb0abc5bf2aa50866d67ed64d76 (patch)
treef6eb2ad3f836cb6504358453b96794c75306d3e9
parent917650e918ff55d0b78a4784474285ca43e84703 (diff)
downloadlibsoup-c68bff78ac88efb0abc5bf2aa50866d67ed64d76.tar.gz
SoupSession: Add http-aliases and https-aliases properties
Currently SoupSession treats all URI schemes except "https" as aliases for "http", and some apps depend on this. (Eg, iTunes sometimes returns redirects involving "daap" URIs, which Rhythmbox needs to treat as "http".) Unfortunately, this also means that it mishandles redirects to, eg, ftp. The http-aliases and https-aliases properties allow an app to explicitly indicate which URI schemes should be considered aliases for http and https, with other schemes considered to be unknown and unhandled.
-rw-r--r--docs/reference/libsoup-2.4-sections.txt2
-rw-r--r--libsoup/soup-session.c166
-rw-r--r--libsoup/soup-session.h2
3 files changed, 168 insertions, 2 deletions
diff --git a/docs/reference/libsoup-2.4-sections.txt b/docs/reference/libsoup-2.4-sections.txt
index 30613519..7d462c8f 100644
--- a/docs/reference/libsoup-2.4-sections.txt
+++ b/docs/reference/libsoup-2.4-sections.txt
@@ -419,6 +419,8 @@ SOUP_SESSION_REMOVE_FEATURE_BY_TYPE
SOUP_SESSION_ACCEPT_LANGUAGE
SOUP_SESSION_ACCEPT_LANGUAGE_AUTO
SOUP_SESSION_SSL_STRICT
+SOUP_SESSION_HTTP_ALIASES
+SOUP_SESSION_HTTPS_ALIASES
<SUBSECTION Standard>
SOUP_IS_SESSION
SOUP_IS_SESSION_CLASS
diff --git a/libsoup/soup-session.c b/libsoup/soup-session.c
index e46b19d3..0015dba1 100644
--- a/libsoup/soup-session.c
+++ b/libsoup/soup-session.c
@@ -103,6 +103,8 @@ typedef struct {
GMainContext *async_context;
GResolver *resolver;
+
+ char **http_aliases, **https_aliases;
} SoupSessionPrivate;
#define SOUP_SESSION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUP_TYPE_SESSION, SoupSessionPrivate))
@@ -162,6 +164,8 @@ enum {
PROP_ADD_FEATURE,
PROP_ADD_FEATURE_BY_TYPE,
PROP_REMOVE_FEATURE_BY_TYPE,
+ PROP_HTTP_ALIASES,
+ PROP_HTTPS_ALIASES,
LAST_PROP
};
@@ -206,6 +210,10 @@ soup_session_init (SoupSession *session)
priv->resolver = g_resolver_get_default ();
priv->ssl_strict = TRUE;
+
+ priv->http_aliases = g_new (char *, 2);
+ priv->http_aliases[0] = (char *)g_intern_string ("*");
+ priv->http_aliases[1] = NULL;
}
static void
@@ -248,6 +256,9 @@ finalize (GObject *object)
g_object_unref (priv->resolver);
+ g_free (priv->http_aliases);
+ g_free (priv->https_aliases);
+
G_OBJECT_CLASS (soup_session_parent_class)->finalize (object);
}
@@ -826,6 +837,69 @@ soup_session_class_init (SoupSessionClass *session_class)
"Remove features of the given type from the session",
SOUP_TYPE_SESSION_FEATURE,
G_PARAM_READWRITE));
+ /**
+ * SoupSession:http-aliases:
+ *
+ * A %NULL-terminated array of URI schemes that should be
+ * considered to be aliases for "http". Eg, if this included
+ * <literal>"dav"</literal>, than a URI of
+ * <literal>dav://example.com/path</literal> would be treated
+ * identically to <literal>http://example.com/path</literal>.
+ * If the value is %NULL, then only "http" is recognized as
+ * meaning "http".
+ *
+ * For backward-compatibility reasons, the default value for
+ * this property is an array containing the single element
+ * <literal>"*"</literal>, a special value which means that
+ * any scheme except "https" is considered to be an alias for
+ * "http".
+ *
+ * See also #SoupSession:https-aliases.
+ *
+ * Since: 2.38
+ */
+ /**
+ * SOUP_SESSION_HTTP_ALIASES:
+ *
+ * Alias for the #SoupSession:http-aliases property. (URI
+ * schemes that will be considered aliases for "http".)
+ *
+ * Since: 2.38
+ */
+ g_object_class_install_property (
+ object_class, PROP_HTTP_ALIASES,
+ g_param_spec_boxed (SOUP_SESSION_HTTP_ALIASES,
+ "http aliases",
+ "URI schemes that are considered aliases for 'http'",
+ G_TYPE_STRV,
+ G_PARAM_READWRITE));
+ /**
+ * SoupSession:https-aliases:
+ *
+ * A comma-delimited list of URI schemes that should be
+ * considered to be aliases for "https". See
+ * #SoupSession:http-aliases for more information.
+ *
+ * The default value is %NULL, meaning that no URI schemes
+ * are considered aliases for "https".
+ *
+ * Since: 2.38
+ */
+ /**
+ * SOUP_SESSION_HTTPS_ALIASES:
+ *
+ * Alias for the #SoupSession:https-aliases property. (URI
+ * schemes that will be considered aliases for "https".)
+ *
+ * Since: 2.38
+ **/
+ g_object_class_install_property (
+ object_class, PROP_HTTPS_ALIASES,
+ g_param_spec_boxed (SOUP_SESSION_HTTPS_ALIASES,
+ "https aliases",
+ "URI schemes that are considered aliases for 'https'",
+ G_TYPE_STRV,
+ G_PARAM_READWRITE));
}
/* Converts a language in POSIX format and to be RFC2616 compliant */
@@ -939,6 +1013,23 @@ load_ssl_ca_file (SoupSessionPrivate *priv)
g_error_free (error);
}
+/* priv->http_aliases and priv->https_aliases are stored as arrays of
+ * *interned* strings, so we can't just use g_strdupv() to set them.
+ */
+static void
+set_aliases (char ***variable, char **value)
+{
+ int len = g_strv_length (value), i;
+
+ if (*variable)
+ g_free (*variable);
+
+ *variable = g_new (char *, len);
+ for (i = 0; i < len; i++)
+ (*variable)[i] = (char *)g_intern_string (value[i]);
+ (*variable)[i] = NULL;
+}
+
static void
set_property (GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec)
@@ -1064,6 +1155,12 @@ set_property (GObject *object, guint prop_id,
case PROP_REMOVE_FEATURE_BY_TYPE:
soup_session_remove_feature_by_type (session, g_value_get_gtype (value));
break;
+ case PROP_HTTP_ALIASES:
+ set_aliases (&priv->http_aliases, g_value_get_boxed (value));
+ break;
+ case PROP_HTTPS_ALIASES:
+ set_aliases (&priv->https_aliases, g_value_get_boxed (value));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -1134,12 +1231,60 @@ get_property (GObject *object, guint prop_id,
case PROP_IDLE_TIMEOUT:
g_value_set_uint (value, priv->idle_timeout);
break;
+ case PROP_HTTP_ALIASES:
+ g_value_set_boxed (value, priv->http_aliases);
+ break;
+ case PROP_HTTPS_ALIASES:
+ g_value_set_boxed (value, priv->https_aliases);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
+static gboolean
+uri_is_http (SoupSessionPrivate *priv, SoupURI *uri)
+{
+ int i;
+
+ if (uri->scheme == SOUP_URI_SCHEME_HTTP)
+ return TRUE;
+ else if (uri->scheme == SOUP_URI_SCHEME_HTTPS)
+ return FALSE;
+ else if (!priv->http_aliases)
+ return FALSE;
+
+ for (i = 0; priv->http_aliases[i]; i++) {
+ if (uri->scheme == priv->http_aliases[i])
+ return TRUE;
+ }
+
+ if (!priv->http_aliases[1] && !strcmp (priv->http_aliases[0], "*"))
+ return TRUE;
+ else
+ return FALSE;
+}
+
+static gboolean
+uri_is_https (SoupSessionPrivate *priv, SoupURI *uri)
+{
+ int i;
+
+ if (uri->scheme == SOUP_URI_SCHEME_HTTPS)
+ return TRUE;
+ else if (uri->scheme == SOUP_URI_SCHEME_HTTP)
+ return FALSE;
+ else if (!priv->https_aliases)
+ return FALSE;
+
+ for (i = 0; priv->https_aliases[i]; i++) {
+ if (uri->scheme == priv->https_aliases[i])
+ return TRUE;
+ }
+
+ return FALSE;
+}
/**
* soup_session_get_async_context:
@@ -1252,6 +1397,7 @@ redirect_handler (SoupMessage *msg, gpointer user_data)
{
SoupMessageQueueItem *item = user_data;
SoupSession *session = item->session;
+ SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
const char *new_loc;
SoupURI *new_uri;
@@ -1320,6 +1466,22 @@ redirect_handler (SoupMessage *msg, gpointer user_data)
return;
}
+ /* If the URI is not "http" or "https" or a recognized alias,
+ * then we let the redirect response be returned to the caller.
+ */
+ if (!uri_is_http (priv, new_uri) && !uri_is_https (priv, new_uri)) {
+ soup_uri_free (new_uri);
+ return;
+ }
+
+ if (!new_uri->host) {
+ soup_uri_free (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);
@@ -1544,14 +1706,14 @@ soup_session_get_connection (SoupSession *session,
}
uri = soup_message_get_uri (item->msg);
- if (uri->scheme == SOUP_URI_SCHEME_HTTPS && item->proxy_addr)
+ if (uri_is_https (priv, uri) && item->proxy_addr)
tunnel_addr = host->addr;
conn = soup_connection_new (
SOUP_CONNECTION_REMOTE_ADDRESS, remote_addr,
SOUP_CONNECTION_TUNNEL_ADDRESS, tunnel_addr,
SOUP_CONNECTION_PROXY_URI, item->proxy_uri,
- SOUP_CONNECTION_SSL, uri->scheme == SOUP_URI_SCHEME_HTTPS,
+ SOUP_CONNECTION_SSL, uri_is_https (priv, uri),
SOUP_CONNECTION_SSL_CREDENTIALS, priv->tlsdb,
SOUP_CONNECTION_SSL_STRICT, (priv->tlsdb != NULL) && priv->ssl_strict,
SOUP_CONNECTION_ASYNC_CONTEXT, priv->async_context,
diff --git a/libsoup/soup-session.h b/libsoup/soup-session.h
index a7aab0e9..6afbbd17 100644
--- a/libsoup/soup-session.h
+++ b/libsoup/soup-session.h
@@ -76,6 +76,8 @@ GType soup_session_get_type (void);
#define SOUP_SESSION_ADD_FEATURE "add-feature"
#define SOUP_SESSION_ADD_FEATURE_BY_TYPE "add-feature-by-type"
#define SOUP_SESSION_REMOVE_FEATURE_BY_TYPE "remove-feature-by-type"
+#define SOUP_SESSION_HTTP_ALIASES "http-aliases"
+#define SOUP_SESSION_HTTPS_ALIASES "https-aliases"
GMainContext *soup_session_get_async_context(SoupSession *session);