[glib] Added method g_network_address_parse_uri()
- From: Nicolas Dufresne <nicolasd src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib] Added method g_network_address_parse_uri()
- Date: Thu, 19 Aug 2010 21:04:44 +0000 (UTC)
commit 63105d1074ce54fdda9c81bb0353abc9b0a24d62
Author: Nicolas Dufresne <nicolas dufresne collabora co uk>
Date: Tue Aug 10 15:23:37 2010 -0400
Added method g_network_address_parse_uri()
This method allow creating a network address from a URI. If no port is
found in the URI, the default_port parameter will be used. Note that new
property scheme is there for future TLS implementation.
Reviewed-by: Dan Winship <danw gnome org>
docs/reference/gio/gio-sections.txt | 2 +
gio/gio.symbols | 2 +
gio/gnetworkaddress.c | 296 +++++++++++++++++++++++++++++++++++
gio/gnetworkaddress.h | 4 +
4 files changed, 304 insertions(+), 0 deletions(-)
---
diff --git a/docs/reference/gio/gio-sections.txt b/docs/reference/gio/gio-sections.txt
index 202b689..92f074e 100644
--- a/docs/reference/gio/gio-sections.txt
+++ b/docs/reference/gio/gio-sections.txt
@@ -1662,7 +1662,9 @@ GNetworkAddress
g_network_address_new
g_network_address_get_hostname
g_network_address_get_port
+g_network_address_get_scheme
g_network_address_parse
+g_network_address_parse_uri
<SUBSECTION Standard>
GNetworkAddressClass
GNetworkAddressPrivate
diff --git a/gio/gio.symbols b/gio/gio.symbols
index 2a579b6..e538c1b 100644
--- a/gio/gio.symbols
+++ b/gio/gio.symbols
@@ -1212,8 +1212,10 @@ g_srv_target_list_sort
g_network_address_get_type G_GNUC_CONST
g_network_address_get_hostname
g_network_address_get_port
+g_network_address_get_scheme
g_network_address_new
g_network_address_parse
+g_network_address_parse_uri
#endif
#endif
diff --git a/gio/gnetworkaddress.c b/gio/gnetworkaddress.c
index 0093be7..77a82ee 100644
--- a/gio/gnetworkaddress.c
+++ b/gio/gnetworkaddress.c
@@ -63,12 +63,14 @@ struct _GNetworkAddressPrivate {
gchar *hostname;
guint16 port;
GList *sockaddrs;
+ gchar *scheme;
};
enum {
PROP_0,
PROP_HOSTNAME,
PROP_PORT,
+ PROP_SCHEME,
};
static void g_network_address_set_property (GObject *object,
@@ -93,6 +95,7 @@ g_network_address_finalize (GObject *object)
GNetworkAddress *addr = G_NETWORK_ADDRESS (object);
g_free (addr->priv->hostname);
+ g_free (addr->priv->scheme);
if (addr->priv->sockaddrs)
{
@@ -133,6 +136,15 @@ g_network_address_class_init (GNetworkAddressClass *klass)
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (gobject_class, PROP_SCHEME,
+ g_param_spec_string ("scheme",
+ P_("Scheme"),
+ P_("URI Scheme"),
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
}
static void
@@ -167,6 +179,12 @@ g_network_address_set_property (GObject *object,
addr->priv->port = g_value_get_uint (value);
break;
+ case PROP_SCHEME:
+ if (addr->priv->scheme)
+ g_free (addr->priv->scheme);
+ addr->priv->scheme = g_value_dup_string (value);
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -192,6 +210,10 @@ g_network_address_get_property (GObject *object,
g_value_set_uint (value, addr->priv->port);
break;
+ case PROP_SCHEME:
+ g_value_set_string (value, addr->priv->scheme);
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -396,6 +418,262 @@ g_network_address_parse (const gchar *host_and_port,
return connectable;
}
+/* Allowed characters outside alphanumeric for unreserved. */
+#define G_URI_OTHER_UNRESERVED "-._~"
+
+/* This or something equivalent will eventually go into glib/guri.h */
+static gboolean
+_g_uri_parse_authority (const char *uri,
+ char **host,
+ guint16 *port,
+ char **userinfo)
+{
+ char *tmp_str;
+ const char *start, *p;
+ char c;
+
+ g_return_val_if_fail (uri != NULL, FALSE);
+
+ if (host)
+ *host = NULL;
+
+ if (port)
+ *port = 0;
+
+ if (userinfo)
+ *userinfo = NULL;
+
+ /* From RFC 3986 Decodes:
+ * URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
+ * hier-part = "//" authority path-abempty
+ * path-abempty = *( "/" segment )
+ * authority = [ userinfo "@" ] host [ ":" port ]
+ */
+
+ /* Check we have a valid scheme */
+ tmp_str = g_uri_parse_scheme (uri);
+
+ if (tmp_str == NULL)
+ return FALSE;
+
+ g_free (tmp_str);
+
+ /* Decode hier-part:
+ * hier-part = "//" authority path-abempty
+ */
+ p = uri;
+ start = strstr (p, "//");
+
+ if (start == NULL)
+ return FALSE;
+
+ start += 2;
+ p = strchr (start, '@');
+
+ if (p != NULL)
+ {
+ /* Decode userinfo:
+ * userinfo = *( unreserved / pct-encoded / sub-delims / ":" )
+ * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
+ * pct-encoded = "%" HEXDIG HEXDIG
+ */
+ while (1)
+ {
+ c = *p++;
+
+ if (c == '@')
+ break;
+
+ /* pct-encoded */
+ if (c == '%')
+ {
+ if (!(g_ascii_isxdigit (p[0]) ||
+ g_ascii_isxdigit (p[1])))
+ return FALSE;
+
+ p++;
+
+ continue;
+ }
+
+ /* unreserved / sub-delims / : */
+ if (!(g_ascii_isalnum(c) ||
+ strchr (G_URI_OTHER_UNRESERVED, c) ||
+ strchr (G_URI_RESERVED_CHARS_SUBCOMPONENT_DELIMITERS, c) ||
+ c == ':'))
+ return FALSE;
+ }
+
+ if (userinfo)
+ *userinfo = g_strndup (start, p - start - 1);
+
+ start = p;
+ }
+ else
+ {
+ p = start;
+ }
+
+
+ /* decode host:
+ * host = IP-literal / IPv4address / reg-name
+ * reg-name = *( unreserved / pct-encoded / sub-delims )
+ */
+
+ /* If IPv6 or IPvFuture */
+ if (*p == '[')
+ {
+ while (1)
+ {
+ c = *p++;
+
+ if (c == ']')
+ break;
+
+ /* unreserved / sub-delims */
+ if (!(g_ascii_isalnum(c) ||
+ strchr (G_URI_OTHER_UNRESERVED, c) ||
+ strchr (G_URI_RESERVED_CHARS_SUBCOMPONENT_DELIMITERS, c) ||
+ c == ':' ||
+ c == '.'))
+ goto error;
+ }
+ }
+ else
+ {
+ while (1)
+ {
+ c = *p++;
+
+ if (c == ':' ||
+ c == '/' ||
+ c == '?' ||
+ c == '#' ||
+ c == '\0')
+ break;
+
+ /* pct-encoded */
+ if (c == '%')
+ {
+ if (!(g_ascii_isxdigit (p[0]) ||
+ g_ascii_isxdigit (p[1])))
+ goto error;
+
+ p++;
+
+ continue;
+ }
+
+ /* unreserved / sub-delims */
+ if (!(g_ascii_isalnum(c) ||
+ strchr (G_URI_OTHER_UNRESERVED, c) ||
+ strchr (G_URI_RESERVED_CHARS_SUBCOMPONENT_DELIMITERS, c)))
+ goto error;
+ }
+ }
+
+ if (host)
+ *host = g_uri_unescape_segment (start, p - 1, NULL);
+
+ if (c == ':')
+ {
+ /* Decode pot:
+ * port = *DIGIT
+ */
+ guint tmp = 0;
+
+ while (1)
+ {
+ c = *p++;
+
+ if (c == '/' ||
+ c == '?' ||
+ c == '#' ||
+ c == '\0')
+ break;
+
+ if (!g_ascii_isdigit (c))
+ goto error;
+
+ tmp = (tmp * 10) + (c - '0');
+
+ if (tmp > 65535)
+ goto error;
+ }
+ if (port)
+ *port = (guint16) tmp;
+ }
+
+ return TRUE;
+
+error:
+ if (host && *host)
+ {
+ g_free (*host);
+ *host = NULL;
+ }
+
+ if (userinfo && *userinfo)
+ {
+ g_free (*userinfo);
+ *userinfo = NULL;
+ }
+
+ return FALSE;
+}
+
+/**
+ * g_network_address_parse_uri:
+ * @uri: the hostname and optionally a port
+ * @default_port: The default port if none is found in the URI
+ * @error: a pointer to a #GError, or %NULL
+ *
+ * Creates a new #GSocketConnectable for connecting to the given
+ * @uri. May fail and return %NULL in case parsing @uri fails.
+ *
+ * Using this rather than g_network_address_new() or
+ * g_network_address_parse_host() allows #GSocketClient to determine
+ * when to use application-specific proxy protocols.
+ *
+ * Return value: the new #GNetworkAddress, or %NULL on error
+ *
+ * Since: 2.26
+ */
+GSocketConnectable *
+g_network_address_parse_uri (const gchar *uri,
+ guint16 default_port,
+ GError **error)
+{
+ GSocketConnectable *conn;
+ gchar *scheme;
+ gchar *hostname;
+ guint16 port;
+
+ if (!_g_uri_parse_authority (uri, &hostname, &port, NULL))
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
+ "Invalid URI '%s'",
+ uri);
+ return NULL;
+ }
+
+ if (port == 0)
+ port = default_port;
+
+ scheme = g_uri_parse_scheme (uri);
+
+ conn = g_object_new (G_TYPE_NETWORK_ADDRESS,
+ "hostname", hostname,
+ "port", port,
+ "scheme", scheme,
+ NULL);
+
+ g_free (scheme);
+ g_free (hostname);
+
+ return conn;
+}
+
/**
* g_network_address_get_hostname:
* @addr: a #GNetworkAddress
@@ -433,6 +711,24 @@ g_network_address_get_port (GNetworkAddress *addr)
return addr->priv->port;
}
+/**
+ * g_network_address_get_scheme:
+ * @addr: a #GNetworkAddress
+ *
+ * Gets @addr's scheme
+ *
+ * Return value: @addr's scheme (%NULL if not built from URI)
+ *
+ * Since: 2.26
+ */
+const gchar *
+g_network_address_get_scheme (GNetworkAddress *addr)
+{
+ g_return_val_if_fail (G_IS_NETWORK_ADDRESS (addr), NULL);
+
+ return addr->priv->scheme;
+}
+
#define G_TYPE_NETWORK_ADDRESS_ADDRESS_ENUMERATOR (_g_network_address_address_enumerator_get_type ())
#define G_NETWORK_ADDRESS_ADDRESS_ENUMERATOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), G_TYPE_NETWORK_ADDRESS_ADDRESS_ENUMERATOR, GNetworkAddressAddressEnumerator))
diff --git a/gio/gnetworkaddress.h b/gio/gnetworkaddress.h
index 0111f70..af16321 100644
--- a/gio/gnetworkaddress.h
+++ b/gio/gnetworkaddress.h
@@ -60,8 +60,12 @@ GSocketConnectable *g_network_address_new (const gchar *hostname,
GSocketConnectable *g_network_address_parse (const gchar *host_and_port,
guint16 default_port,
GError **error);
+GSocketConnectable *g_network_address_parse_uri (const gchar *uri,
+ guint16 default_port,
+ GError **error);
const gchar *g_network_address_get_hostname (GNetworkAddress *addr);
guint16 g_network_address_get_port (GNetworkAddress *addr);
+const gchar *g_network_address_get_scheme (GNetworkAddress *addr);
G_END_DECLS
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]