mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-12-25 15:06:14 +01:00
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>
This commit is contained in:
parent
466111c960
commit
63105d1074
@ -1662,7 +1662,9 @@ GNetworkAddress
|
|||||||
g_network_address_new
|
g_network_address_new
|
||||||
g_network_address_get_hostname
|
g_network_address_get_hostname
|
||||||
g_network_address_get_port
|
g_network_address_get_port
|
||||||
|
g_network_address_get_scheme
|
||||||
g_network_address_parse
|
g_network_address_parse
|
||||||
|
g_network_address_parse_uri
|
||||||
<SUBSECTION Standard>
|
<SUBSECTION Standard>
|
||||||
GNetworkAddressClass
|
GNetworkAddressClass
|
||||||
GNetworkAddressPrivate
|
GNetworkAddressPrivate
|
||||||
|
@ -1212,8 +1212,10 @@ g_srv_target_list_sort
|
|||||||
g_network_address_get_type G_GNUC_CONST
|
g_network_address_get_type G_GNUC_CONST
|
||||||
g_network_address_get_hostname
|
g_network_address_get_hostname
|
||||||
g_network_address_get_port
|
g_network_address_get_port
|
||||||
|
g_network_address_get_scheme
|
||||||
g_network_address_new
|
g_network_address_new
|
||||||
g_network_address_parse
|
g_network_address_parse
|
||||||
|
g_network_address_parse_uri
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -63,12 +63,14 @@ struct _GNetworkAddressPrivate {
|
|||||||
gchar *hostname;
|
gchar *hostname;
|
||||||
guint16 port;
|
guint16 port;
|
||||||
GList *sockaddrs;
|
GList *sockaddrs;
|
||||||
|
gchar *scheme;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
PROP_0,
|
PROP_0,
|
||||||
PROP_HOSTNAME,
|
PROP_HOSTNAME,
|
||||||
PROP_PORT,
|
PROP_PORT,
|
||||||
|
PROP_SCHEME,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void g_network_address_set_property (GObject *object,
|
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);
|
GNetworkAddress *addr = G_NETWORK_ADDRESS (object);
|
||||||
|
|
||||||
g_free (addr->priv->hostname);
|
g_free (addr->priv->hostname);
|
||||||
|
g_free (addr->priv->scheme);
|
||||||
|
|
||||||
if (addr->priv->sockaddrs)
|
if (addr->priv->sockaddrs)
|
||||||
{
|
{
|
||||||
@ -133,6 +136,15 @@ g_network_address_class_init (GNetworkAddressClass *klass)
|
|||||||
G_PARAM_READWRITE |
|
G_PARAM_READWRITE |
|
||||||
G_PARAM_CONSTRUCT_ONLY |
|
G_PARAM_CONSTRUCT_ONLY |
|
||||||
G_PARAM_STATIC_STRINGS));
|
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
|
static void
|
||||||
@ -167,6 +179,12 @@ g_network_address_set_property (GObject *object,
|
|||||||
addr->priv->port = g_value_get_uint (value);
|
addr->priv->port = g_value_get_uint (value);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case PROP_SCHEME:
|
||||||
|
if (addr->priv->scheme)
|
||||||
|
g_free (addr->priv->scheme);
|
||||||
|
addr->priv->scheme = g_value_dup_string (value);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
@ -192,6 +210,10 @@ g_network_address_get_property (GObject *object,
|
|||||||
g_value_set_uint (value, addr->priv->port);
|
g_value_set_uint (value, addr->priv->port);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case PROP_SCHEME:
|
||||||
|
g_value_set_string (value, addr->priv->scheme);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
@ -396,6 +418,262 @@ g_network_address_parse (const gchar *host_and_port,
|
|||||||
return connectable;
|
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:
|
* g_network_address_get_hostname:
|
||||||
* @addr: a #GNetworkAddress
|
* @addr: a #GNetworkAddress
|
||||||
@ -433,6 +711,24 @@ g_network_address_get_port (GNetworkAddress *addr)
|
|||||||
return addr->priv->port;
|
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_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))
|
#define G_NETWORK_ADDRESS_ADDRESS_ENUMERATOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), G_TYPE_NETWORK_ADDRESS_ADDRESS_ENUMERATOR, GNetworkAddressAddressEnumerator))
|
||||||
|
|
||||||
|
@ -60,8 +60,12 @@ GSocketConnectable *g_network_address_new (const gchar *hostname,
|
|||||||
GSocketConnectable *g_network_address_parse (const gchar *host_and_port,
|
GSocketConnectable *g_network_address_parse (const gchar *host_and_port,
|
||||||
guint16 default_port,
|
guint16 default_port,
|
||||||
GError **error);
|
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);
|
const gchar *g_network_address_get_hostname (GNetworkAddress *addr);
|
||||||
guint16 g_network_address_get_port (GNetworkAddress *addr);
|
guint16 g_network_address_get_port (GNetworkAddress *addr);
|
||||||
|
const gchar *g_network_address_get_scheme (GNetworkAddress *addr);
|
||||||
|
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
Loading…
Reference in New Issue
Block a user