From: Marc-André Lureau <marcandre.lureau@xxxxxxxxxx> Generalize a little bit SpiceProxy to allow easy URI manipulation by clients. --- doc/reference/Makefile.am | 1 + doc/reference/spice-gtk-docs.xml | 1 + doc/reference/spice-gtk-sections.txt | 26 ++ gtk/Makefile.am | 5 +- gtk/map-file | 12 + gtk/spice-client.h | 1 + gtk/spice-glib-sym-file | 12 + gtk/spice-proxy.c | 357 -------------------------- gtk/spice-proxy.h | 64 ----- gtk/spice-session-priv.h | 3 +- gtk/spice-session.c | 28 +-- gtk/spice-session.h | 1 + gtk/spice-uri-priv.h | 30 +++ gtk/spice-uri.c | 473 +++++++++++++++++++++++++++++++++++ gtk/spice-uri.h | 52 ++++ 15 files changed, 627 insertions(+), 439 deletions(-) delete mode 100644 gtk/spice-proxy.c delete mode 100644 gtk/spice-proxy.h create mode 100644 gtk/spice-uri-priv.h create mode 100644 gtk/spice-uri.c create mode 100644 gtk/spice-uri.h diff --git a/doc/reference/Makefile.am b/doc/reference/Makefile.am index a0a856c..76c7d34 100644 --- a/doc/reference/Makefile.am +++ b/doc/reference/Makefile.am @@ -44,6 +44,7 @@ IGNORE_HFILES= \ spice-marshal.h \ spice-pulse.h \ spice-session-priv.h \ + spice-uri-priv.h \ spice-util-priv.h \ spice-widget-priv.h \ usb-acl-helper.h \ diff --git a/doc/reference/spice-gtk-docs.xml b/doc/reference/spice-gtk-docs.xml index 4a9a3cf..d2c1a2b 100644 --- a/doc/reference/spice-gtk-docs.xml +++ b/doc/reference/spice-gtk-docs.xml @@ -52,6 +52,7 @@ <xi:include href="xml/smartcard-manager.xml"/> <xi:include href="xml/usb-device-manager.xml"/> <xi:include href="xml/spice-util.xml"/> + <xi:include href="xml/spice-uri.xml"/> </chapter> </part> diff --git a/doc/reference/spice-gtk-sections.txt b/doc/reference/spice-gtk-sections.txt index 8d61aa9..411ca0e 100644 --- a/doc/reference/spice-gtk-sections.txt +++ b/doc/reference/spice-gtk-sections.txt @@ -429,3 +429,29 @@ SPICE_PORT_CHANNEL_GET_CLASS SpicePortChannelPrivate </SECTION> +<SECTION> +<FILE>spice-uri</FILE> +spice_uri_get_scheme +spice_uri_set_scheme +spice_uri_get_hostname +spice_uri_set_hostname +spice_uri_get_port +spice_uri_set_port +spice_uri_get_user +spice_uri_set_user +spice_uri_get_password +spice_uri_set_password +spice_uri_to_string +SpiceURIClass +SpiceURI +<SUBSECTION Standard> +SPICE_IS_URI +SPICE_IS_URI_CLASS +SPICE_TYPE_URI +SPICE_URI +SPICE_URI_CLASS +SPICE_URI_GET_CLASS +spice_uri_get_type +<SUBSECTION Private> +SpiceURIPrivate +</SECTION> diff --git a/gtk/Makefile.am b/gtk/Makefile.am index 840d129..45d6796 100644 --- a/gtk/Makefile.am +++ b/gtk/Makefile.am @@ -248,8 +248,8 @@ libspice_client_glib_2_0_la_SOURCES = \ channel-usbredir-priv.h \ smartcard-manager.c \ smartcard-manager-priv.h \ - spice-proxy.c \ - spice-proxy.h \ + spice-uri.c \ + spice-uri-priv.h \ usb-device-manager.c \ usb-device-manager-priv.h \ usbutil.c \ @@ -282,6 +282,7 @@ libspice_client_glibincludedir = $(includedir)/spice-client-glib-2.0 libspice_client_glibinclude_HEADERS = \ spice-audio.h \ spice-client.h \ + spice-uri.h \ spice-types.h \ spice-session.h \ spice-channel.h \ diff --git a/gtk/map-file b/gtk/map-file index 368b44f..cf65db0 100644 --- a/gtk/map-file +++ b/gtk/map-file @@ -118,6 +118,18 @@ spice_util_get_debug; spice_util_get_version_string; spice_util_set_debug; spice_uuid_to_string; +spice_uri_get_hostname; +spice_uri_get_password; +spice_uri_get_port; +spice_uri_get_scheme; +spice_uri_get_type; +spice_uri_get_user; +spice_uri_set_hostname; +spice_uri_set_password; +spice_uri_set_port; +spice_uri_set_scheme; +spice_uri_set_user; +spice_uri_to_string; local: *; }; diff --git a/gtk/spice-client.h b/gtk/spice-client.h index 730d11a..975259a 100644 --- a/gtk/spice-client.h +++ b/gtk/spice-client.h @@ -31,6 +31,7 @@ #include "spice-session.h" #include "spice-channel.h" #include "spice-option.h" +#include "spice-uri.h" #include "channel-main.h" #include "channel-display.h" diff --git a/gtk/spice-glib-sym-file b/gtk/spice-glib-sym-file index 4fc8643..ac7e871 100644 --- a/gtk/spice-glib-sym-file +++ b/gtk/spice-glib-sym-file @@ -92,3 +92,15 @@ spice_util_get_debug spice_util_get_version_string spice_util_set_debug spice_uuid_to_string +spice_uri_get_hostname +spice_uri_get_password +spice_uri_get_port +spice_uri_get_scheme +spice_uri_get_type +spice_uri_get_user +spice_uri_set_hostname +spice_uri_set_password +spice_uri_set_port +spice_uri_set_scheme +spice_uri_set_user +spice_uri_to_string diff --git a/gtk/spice-proxy.c b/gtk/spice-proxy.c deleted file mode 100644 index ecf7e54..0000000 --- a/gtk/spice-proxy.c +++ /dev/null @@ -1,357 +0,0 @@ -/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */ -/* - Copyright (C) 2012 Red Hat, Inc. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, see <http://www.gnu.org/licenses/>. -*/ - -#include <stdlib.h> -#include <string.h> - -#include "glib-compat.h" -#include "spice-client.h" -#include "spice-proxy.h" - -struct _SpiceProxyPrivate { - gchar *protocol; - gchar *hostname; - guint port; - gchar *user; - gchar *password; -}; - -#define SPICE_PROXY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), SPICE_TYPE_PROXY, SpiceProxyPrivate)) - -G_DEFINE_TYPE(SpiceProxy, spice_proxy, G_TYPE_OBJECT); - -enum { - SPICE_PROXY_DUMMY_PROPERTY, - SPICE_PROXY_PROTOCOL, - SPICE_PROXY_USER, - SPICE_PROXY_PASSWORD, - SPICE_PROXY_HOSTNAME, - SPICE_PROXY_PORT -}; - -G_GNUC_INTERNAL -SpiceProxy* spice_proxy_new(void) -{ - SpiceProxy * self = NULL; - self = (SpiceProxy*)g_object_new(SPICE_TYPE_PROXY, NULL); - return self; -} - -G_GNUC_INTERNAL -gboolean spice_proxy_parse(SpiceProxy *self, const gchar *proxyuri, GError **error) -{ - gchar *dup, *uri; - gboolean success = FALSE; - size_t len; - - g_return_val_if_fail(self != NULL, FALSE); - g_return_val_if_fail(proxyuri != NULL, FALSE); - - uri = dup = g_strdup(proxyuri); - /* FIXME: use GUri when it is ready... only support http atm */ - /* the code is voluntarily not parsing thoroughly the uri */ - if (g_ascii_strncasecmp("http://", uri, 7) == 0) { - uri += 7; - spice_proxy_set_protocol(self, "http"); - spice_proxy_set_port(self, 3128); - } else if (g_ascii_strncasecmp("https://", uri, 8) == 0) { - uri += 8; - spice_proxy_set_protocol(self, "https"); - spice_proxy_set_port(self, 3129); - } else { - return FALSE; - } - /* remove trailing slash */ - len = strlen(uri); - for (; len > 0; len--) - if (uri[len-1] == '/') - uri[len-1] = '\0'; - else - break; - - - gchar *saveptr, *auth = strtok_r(uri, "@", &saveptr); - if (saveptr && *saveptr) { - gchar *saveptr2; - const gchar *user = strtok_r(auth, ":", &saveptr2); - const gchar *pass = strtok_r(NULL, ":", &saveptr2); - spice_proxy_set_user(self, user); - spice_proxy_set_password(self, pass); - uri = saveptr; - } - - gchar **proxyv = g_strsplit(uri, ":", 2); - const gchar *proxy_port = NULL; - - if (proxyv[0] == NULL || strlen(proxyv[0]) == 0) { - g_set_error(error, SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED, - "Invalid hostname in proxy address"); - goto end; - } - - spice_proxy_set_hostname(self, proxyv[0]); - if (proxyv[0] != NULL) - proxy_port = proxyv[1]; - - if (proxy_port != NULL) { - char *endptr; - guint port = strtoul(proxy_port, &endptr, 10); - if (*endptr != '\0') { - g_set_error(error, SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED, - "Invalid proxy port: %s", proxy_port); - goto end; - } - spice_proxy_set_port(self, port); - } - - success = TRUE; - -end: - g_free(dup); - g_strfreev(proxyv); - return success; -} - -G_GNUC_INTERNAL -const gchar* spice_proxy_get_protocol(SpiceProxy *self) -{ - g_return_val_if_fail(SPICE_IS_PROXY(self), NULL); - return self->priv->protocol; -} - -G_GNUC_INTERNAL -void spice_proxy_set_protocol(SpiceProxy *self, const gchar *value) -{ - g_return_if_fail(SPICE_IS_PROXY(self)); - - g_free(self->priv->protocol); - self->priv->protocol = g_strdup(value); - g_object_notify((GObject *)self, "protocol"); -} - -G_GNUC_INTERNAL -const gchar* spice_proxy_get_hostname(SpiceProxy *self) -{ - g_return_val_if_fail(SPICE_IS_PROXY(self), NULL); - return self->priv->hostname; -} - - -G_GNUC_INTERNAL -void spice_proxy_set_hostname(SpiceProxy *self, const gchar *value) -{ - g_return_if_fail(SPICE_IS_PROXY(self)); - - g_free(self->priv->hostname); - self->priv->hostname = g_strdup(value); - g_object_notify((GObject *)self, "hostname"); -} - -G_GNUC_INTERNAL -guint spice_proxy_get_port(SpiceProxy *self) -{ - g_return_val_if_fail(SPICE_IS_PROXY(self), 0); - return self->priv->port; -} - -G_GNUC_INTERNAL -void spice_proxy_set_port(SpiceProxy *self, guint port) -{ - g_return_if_fail(SPICE_IS_PROXY(self)); - self->priv->port = port; - g_object_notify((GObject *)self, "port"); -} - -static void spice_proxy_get_property(GObject *object, guint property_id, - GValue *value, GParamSpec *pspec) -{ - SpiceProxy *self; - self = G_TYPE_CHECK_INSTANCE_CAST(object, SPICE_TYPE_PROXY, SpiceProxy); - - switch (property_id) { - case SPICE_PROXY_PROTOCOL: - g_value_set_string(value, spice_proxy_get_protocol(self)); - break; - case SPICE_PROXY_HOSTNAME: - g_value_set_string(value, spice_proxy_get_hostname(self)); - break; - case SPICE_PROXY_PORT: - g_value_set_uint(value, spice_proxy_get_port(self)); - break; - case SPICE_PROXY_USER: - g_value_set_string(value, spice_proxy_get_user(self)); - break; - case SPICE_PROXY_PASSWORD: - g_value_set_string(value, spice_proxy_get_password(self)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); - break; - } -} - - -static void spice_proxy_set_property(GObject *object, guint property_id, - const GValue *value, GParamSpec *pspec) -{ - SpiceProxy * self; - self = G_TYPE_CHECK_INSTANCE_CAST(object, SPICE_TYPE_PROXY, SpiceProxy); - - switch (property_id) { - case SPICE_PROXY_PROTOCOL: - spice_proxy_set_protocol(self, g_value_get_string(value)); - break; - case SPICE_PROXY_HOSTNAME: - spice_proxy_set_hostname(self, g_value_get_string(value)); - break; - case SPICE_PROXY_USER: - spice_proxy_set_user(self, g_value_get_string(value)); - break; - case SPICE_PROXY_PASSWORD: - spice_proxy_set_password(self, g_value_get_string(value)); - break; - case SPICE_PROXY_PORT: - spice_proxy_set_port(self, g_value_get_uint(value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); - break; - } -} - -static void spice_proxy_finalize(GObject* obj) -{ - SpiceProxy *self; - - self = G_TYPE_CHECK_INSTANCE_CAST(obj, SPICE_TYPE_PROXY, SpiceProxy); - g_free(self->priv->protocol); - g_free(self->priv->hostname); - - G_OBJECT_CLASS (spice_proxy_parent_class)->finalize (obj); -} - -static void spice_proxy_init (SpiceProxy *self) -{ - self->priv = SPICE_PROXY_GET_PRIVATE(self); -} - - -static void spice_proxy_class_init(SpiceProxyClass *klass) -{ - spice_proxy_parent_class = g_type_class_peek_parent (klass); - g_type_class_add_private(klass, sizeof(SpiceProxyPrivate)); - - G_OBJECT_CLASS (klass)->get_property = spice_proxy_get_property; - G_OBJECT_CLASS (klass)->set_property = spice_proxy_set_property; - G_OBJECT_CLASS (klass)->finalize = spice_proxy_finalize; - - g_object_class_install_property(G_OBJECT_CLASS (klass), - SPICE_PROXY_PROTOCOL, - g_param_spec_string ("protocol", - "protocol", - "protocol", - NULL, - G_PARAM_STATIC_STRINGS | - G_PARAM_READWRITE)); - - g_object_class_install_property(G_OBJECT_CLASS (klass), - SPICE_PROXY_HOSTNAME, - g_param_spec_string ("hostname", - "hostname", - "hostname", - NULL, - G_PARAM_STATIC_STRINGS | - G_PARAM_READWRITE)); - - g_object_class_install_property(G_OBJECT_CLASS (klass), - SPICE_PROXY_PORT, - g_param_spec_uint ("port", - "port", - "port", - 0, G_MAXUINT, 0, - G_PARAM_STATIC_STRINGS | - G_PARAM_READWRITE)); - - g_object_class_install_property(G_OBJECT_CLASS (klass), - SPICE_PROXY_USER, - g_param_spec_string ("user", - "user", - "user", - NULL, - G_PARAM_STATIC_STRINGS | - G_PARAM_READWRITE)); - - g_object_class_install_property(G_OBJECT_CLASS (klass), - SPICE_PROXY_PASSWORD, - g_param_spec_string ("password", - "password", - "password", - NULL, - G_PARAM_STATIC_STRINGS | - G_PARAM_READWRITE)); -} - -G_GNUC_INTERNAL -gchar* spice_proxy_to_string(SpiceProxy* self) -{ - SpiceProxyPrivate *p; - - g_return_val_if_fail(SPICE_IS_PROXY(self), NULL); - p = self->priv; - - if (p->protocol == NULL || p->hostname == NULL) - return NULL; - - return g_strdup_printf("%s://%s:%u", p->protocol, p->hostname, p->port); -} - -G_GNUC_INTERNAL -const gchar* spice_proxy_get_user(SpiceProxy *self) -{ - g_return_val_if_fail(SPICE_IS_PROXY(self), NULL); - return self->priv->user; -} - - -G_GNUC_INTERNAL -void spice_proxy_set_user(SpiceProxy *self, const gchar *value) -{ - g_return_if_fail(SPICE_IS_PROXY(self)); - - g_free(self->priv->user); - self->priv->user = g_strdup(value); - g_object_notify((GObject *)self, "user"); -} - -G_GNUC_INTERNAL -const gchar* spice_proxy_get_password(SpiceProxy *self) -{ - g_return_val_if_fail(SPICE_IS_PROXY(self), NULL); - return self->priv->password; -} - - -G_GNUC_INTERNAL -void spice_proxy_set_password(SpiceProxy *self, const gchar *value) -{ - g_return_if_fail(SPICE_IS_PROXY(self)); - - g_free(self->priv->password); - self->priv->password = g_strdup(value); - g_object_notify((GObject *)self, "password"); -} diff --git a/gtk/spice-proxy.h b/gtk/spice-proxy.h deleted file mode 100644 index e74053b..0000000 --- a/gtk/spice-proxy.h +++ /dev/null @@ -1,64 +0,0 @@ -/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */ -/* - Copyright (C) 2012 Red Hat, Inc. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, see <http://www.gnu.org/licenses/>. -*/ -#ifndef __SPICE_PROXY_H__ -#define __SPICE_PROXY_H__ - -#include <glib-object.h> - -G_BEGIN_DECLS - -#define SPICE_TYPE_PROXY (spice_proxy_get_type ()) -#define SPICE_PROXY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SPICE_TYPE_PROXY, SpiceProxy)) -#define SPICE_PROXY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SPICE_TYPE_PROXY, SpiceProxyClass)) -#define SPICE_IS_PROXY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SPICE_TYPE_PROXY)) -#define SPICE_IS_PROXY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SPICE_TYPE_PROXY)) -#define SPICE_PROXY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SPICE_TYPE_PROXY, SpiceProxyClass)) - -typedef struct _SpiceProxy SpiceProxy; -typedef struct _SpiceProxyClass SpiceProxyClass; -typedef struct _SpiceProxyPrivate SpiceProxyPrivate; - -struct _SpiceProxy { - GObject parent_instance; - SpiceProxyPrivate * priv; -}; - -struct _SpiceProxyClass { - GObjectClass parent_class; -}; - - -GType spice_proxy_get_type(void) G_GNUC_CONST; - -SpiceProxy* spice_proxy_new(void); -gboolean spice_proxy_parse(SpiceProxy* self, const gchar* uri, GError** error); -const gchar* spice_proxy_get_protocol(SpiceProxy* self); -void spice_proxy_set_protocol(SpiceProxy* self, const gchar* value); -const gchar* spice_proxy_get_hostname(SpiceProxy* self); -void spice_proxy_set_hostname(SpiceProxy* self, const gchar* value); -guint spice_proxy_get_port(SpiceProxy* self); -void spice_proxy_set_port(SpiceProxy* self, guint port); -gchar *spice_proxy_to_string(SpiceProxy* self); -const gchar* spice_proxy_get_user(SpiceProxy* self); -void spice_proxy_set_user(SpiceProxy* self, const gchar* value); -const gchar* spice_proxy_get_password(SpiceProxy* self); -void spice_proxy_set_password(SpiceProxy* self, const gchar* value); - -G_END_DECLS - -#endif /* __SPICE_PROXY_H__ */ diff --git a/gtk/spice-session-priv.h b/gtk/spice-session-priv.h index 55fee47..0dc2bfb 100644 --- a/gtk/spice-session-priv.h +++ b/gtk/spice-session-priv.h @@ -22,7 +22,6 @@ #include <gio/gio.h> #include "desktop-integration.h" #include "spice-session.h" -#include "spice-proxy.h" #include "spice-gtk-session.h" #include "spice-channel-cache.h" #include "decode.h" @@ -45,7 +44,7 @@ struct _SpiceSessionPrivate { char *cert_subject; guint verify; gboolean read_only; - SpiceProxy *proxy; + SpiceURI *proxy; /* whether to enable audio */ gboolean audio; diff --git a/gtk/spice-session.c b/gtk/spice-session.c index 29c84e8..e229c64 100644 --- a/gtk/spice-session.c +++ b/gtk/spice-session.c @@ -28,7 +28,7 @@ #include "gio-coroutine.h" #include "glib-compat.h" #include "wocky-http-proxy.h" -#include "spice-proxy.h" +#include "spice-uri-priv.h" #include "channel-playback-priv.h" struct channel { @@ -139,7 +139,7 @@ static void do_emit_main_context(GObject *object, int signum, gpointer params) static void update_proxy(SpiceSession *self, const gchar *str) { SpiceSessionPrivate *s = self->priv; - SpiceProxy *proxy = NULL; + SpiceURI *proxy = NULL; GError *error = NULL; if (str == NULL) @@ -149,8 +149,8 @@ static void update_proxy(SpiceSession *self, const gchar *str) return; } - proxy = spice_proxy_new(); - if (!spice_proxy_parse(proxy, str, &error)) + proxy = spice_uri_new(); + if (!spice_uri_parse(proxy, str, &error)) g_clear_object(&proxy); if (error) { g_warning("%s", error->message); @@ -269,7 +269,7 @@ static int spice_uri_create(SpiceSession *session, char *dest, int len) return pos; } -static int spice_uri_parse(SpiceSession *session, const char *original_uri) +static int spice_parse_uri(SpiceSession *session, const char *original_uri) { SpiceSessionPrivate *s = SPICE_SESSION_GET_PRIVATE(session); gchar *host = NULL, *port = NULL, *tls_port = NULL, *uri = NULL, *password = NULL; @@ -499,7 +499,7 @@ static void spice_session_get_property(GObject *gobject, g_value_set_pointer(value, s->uuid); break; case PROP_PROXY: - g_value_take_string(value, spice_proxy_to_string(s->proxy)); + g_value_take_string(value, spice_uri_to_string(s->proxy)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, pspec); @@ -547,7 +547,7 @@ static void spice_session_set_property(GObject *gobject, case PROP_URI: str = g_value_get_string(value); if (str != NULL) - spice_uri_parse(session, str); + spice_parse_uri(session, str); break; case PROP_CLIENT_SOCKETS: s->client_provided_sockets = g_value_get_boolean(value); @@ -1664,7 +1664,7 @@ struct spice_open_host { struct coroutine *from; SpiceSession *session; SpiceChannel *channel; - SpiceProxy *proxy; + SpiceURI *proxy; int port; GCancellable *cancellable; GError *error; @@ -1723,11 +1723,11 @@ static void proxy_lookup_ready(GObject *source_object, GAsyncResult *result, for (it = addresses; it != NULL; it = it->next) { address = g_proxy_address_new(G_INET_ADDRESS(it->data), - spice_proxy_get_port(open_host->proxy), - spice_proxy_get_protocol(open_host->proxy), + spice_uri_get_port(open_host->proxy), + spice_uri_get_scheme(open_host->proxy), s->host, open_host->port, - spice_proxy_get_user(open_host->proxy), - spice_proxy_get_password(open_host->proxy)); + spice_uri_get_user(open_host->proxy), + spice_uri_get_password(open_host->proxy)); if (address != NULL) break; } @@ -1755,7 +1755,7 @@ static gboolean open_host_idle_cb(gpointer data) if (open_host->proxy) g_resolver_lookup_by_name_async(g_resolver_get_default(), - spice_proxy_get_hostname(open_host->proxy), + spice_uri_get_hostname(open_host->proxy), open_host->cancellable, proxy_lookup_ready, open_host); else @@ -1770,7 +1770,7 @@ static gboolean open_host_idle_cb(gpointer data) SPICE_DEBUG("open host %s:%d", s->host, open_host->port); if (open_host->proxy != NULL) { - gchar *str = spice_proxy_to_string(open_host->proxy); + gchar *str = spice_uri_to_string(open_host->proxy); SPICE_DEBUG("(with proxy %s)", str); g_free(str); } diff --git a/gtk/spice-session.h b/gtk/spice-session.h index b07f525..4ea645e 100644 --- a/gtk/spice-session.h +++ b/gtk/spice-session.h @@ -20,6 +20,7 @@ #include <glib-object.h> #include "spice-types.h" +#include "spice-uri.h" #include "spice-glib-enums.h" #include "spice-util.h" diff --git a/gtk/spice-uri-priv.h b/gtk/spice-uri-priv.h new file mode 100644 index 0000000..54351de --- /dev/null +++ b/gtk/spice-uri-priv.h @@ -0,0 +1,30 @@ +/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* + Copyright (C) 2012 Red Hat, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see <http://www.gnu.org/licenses/>. +*/ +#ifndef __SPICE_URI_PRIV_H__ +#define __SPICE_URI_PRIV_H__ + +#include "spice-uri.h" + +G_BEGIN_DECLS + +SpiceURI* spice_uri_new(void); +gboolean spice_uri_parse(SpiceURI* self, const gchar* uri, GError** error); + +G_END_DECLS + +#endif /* __SPICE_URI_PRIV_H__ */ diff --git a/gtk/spice-uri.c b/gtk/spice-uri.c new file mode 100644 index 0000000..8a51208 --- /dev/null +++ b/gtk/spice-uri.c @@ -0,0 +1,473 @@ +/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* + Copyright (C) 2012 Red Hat, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see <http://www.gnu.org/licenses/>. +*/ + +#include <stdlib.h> +#include <string.h> + +#include "glib-compat.h" +#include "spice-client.h" +#include "spice-uri.h" + +/** + * SECTION:spice-uri + * @short_description: URIs handling + * @title: SpiceURI + * @section_id: + * @stability: Stable + * @include: spice-uri.h + * + * A SpiceURI represents a (parsed) URI. + * Since: 0.23 + */ + +struct _SpiceURI { + GObject parent_instance; + SpiceURIPrivate * priv; +}; + +struct _SpiceURIClass { + GObjectClass parent_class; +}; + +struct _SpiceURIPrivate { + gchar *scheme; + gchar *hostname; + guint port; + gchar *user; + gchar *password; +}; + +#define SPICE_URI_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), SPICE_TYPE_URI, SpiceURIPrivate)) + +G_DEFINE_TYPE(SpiceURI, spice_uri, G_TYPE_OBJECT); + +enum { + SPICE_URI_DUMMY_PROPERTY, + SPICE_URI_SCHEME, + SPICE_URI_USER, + SPICE_URI_PASSWORD, + SPICE_URI_HOSTNAME, + SPICE_URI_PORT +}; + +G_GNUC_INTERNAL +SpiceURI* spice_uri_new(void) +{ + SpiceURI * self = NULL; + self = (SpiceURI*)g_object_new(SPICE_TYPE_URI, NULL); + return self; +} + +G_GNUC_INTERNAL +gboolean spice_uri_parse(SpiceURI *self, const gchar *_uri, GError **error) +{ + gchar *dup, *uri; + gboolean success = FALSE; + size_t len; + + g_return_val_if_fail(self != NULL, FALSE); + g_return_val_if_fail(_uri != NULL, FALSE); + + uri = dup = g_strdup(_uri); + /* FIXME: use GURI when it is ready... only support http atm */ + /* the code is voluntarily not parsing thoroughly the uri */ + if (g_ascii_strncasecmp("http://", uri, 7) == 0) { + uri += 7; + spice_uri_set_scheme(self, "http"); + spice_uri_set_port(self, 3128); + } else if (g_ascii_strncasecmp("https://", uri, 8) == 0) { + uri += 8; + spice_uri_set_scheme(self, "https"); + spice_uri_set_port(self, 3129); + } else { + return FALSE; + } + /* remove trailing slash */ + len = strlen(uri); + for (; len > 0; len--) + if (uri[len-1] == '/') + uri[len-1] = '\0'; + else + break; + + + gchar *saveptr, *auth = strtok_r(uri, "@", &saveptr); + if (saveptr && *saveptr) { + gchar *saveptr2; + const gchar *user = strtok_r(auth, ":", &saveptr2); + const gchar *pass = strtok_r(NULL, ":", &saveptr2); + spice_uri_set_user(self, user); + spice_uri_set_password(self, pass); + uri = saveptr; + } + + gchar **uriv = g_strsplit(uri, ":", 2); + const gchar *uri_port = NULL; + + if (uriv[0] == NULL || strlen(uriv[0]) == 0) { + g_set_error(error, SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED, + "Invalid hostname in uri address"); + goto end; + } + + spice_uri_set_hostname(self, uriv[0]); + if (uriv[0] != NULL) + uri_port = uriv[1]; + + if (uri_port != NULL) { + char *endptr; + guint port = strtoul(uri_port, &endptr, 10); + if (*endptr != '\0') { + g_set_error(error, SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED, + "Invalid uri port: %s", uri_port); + goto end; + } + spice_uri_set_port(self, port); + } + + success = TRUE; + +end: + g_free(dup); + g_strfreev(uriv); + return success; +} + +/** + * spice_uri_get_scheme: + * @uri: a #SpiceURI + * + * Gets @uri's scheme. + * + * Returns: @uri's scheme. + * Since: 0.23 + **/ +const gchar* spice_uri_get_scheme(SpiceURI *self) +{ + g_return_val_if_fail(SPICE_IS_URI(self), NULL); + + return self->priv->scheme; +} + +/** + * spice_uri_set_scheme: + * @uri: a #SpiceURI + * @scheme: the scheme + * + * Sets @uri's scheme to @scheme. + * Since: 0.23 + **/ +void spice_uri_set_scheme(SpiceURI *self, const gchar *value) +{ + g_return_if_fail(SPICE_IS_URI(self)); + + g_free(self->priv->scheme); + self->priv->scheme = g_strdup(value); + g_object_notify((GObject *)self, "scheme"); +} + +/** + * spice_uri_get_hostname: + * @uri: a #SpiceURI + * + * Gets @uri's hostname. + * + * Returns: @uri's hostname. + * Since: 0.23 + **/ +const gchar* spice_uri_get_hostname(SpiceURI *self) +{ + g_return_val_if_fail(SPICE_IS_URI(self), NULL); + + return self->priv->hostname; +} + + +/** + * spice_uri_set_hostname: + * @uri: a #SpiceURI + * @hostname: the hostname + * + * Sets @uri's hostname to @hostname. + * Since: 0.23 + **/ +void spice_uri_set_hostname(SpiceURI *self, const gchar *hostname) +{ + g_return_if_fail(SPICE_IS_URI(self)); + + g_free(self->priv->hostname); + self->priv->hostname = g_strdup(hostname); + g_object_notify((GObject *)self, "hostname"); +} + +/** + * spice_uri_get_port: + * @uri: a #SpiceURI + * + * Gets @uri's port. + * + * Returns: @uri's port. + * Since: 0.23 + **/ +guint spice_uri_get_port(SpiceURI *self) +{ + g_return_val_if_fail(SPICE_IS_URI(self), 0); + + return self->priv->port; +} + +/** + * spice_uri_set_port: + * @uri: a #SpiceURI + * @port: the port + * + * Sets @uri's port to @port. + * Since: 0.23 + **/ +void spice_uri_set_port(SpiceURI *self, guint port) +{ + g_return_if_fail(SPICE_IS_URI(self)); + + self->priv->port = port; + g_object_notify((GObject *)self, "port"); +} + +static void spice_uri_get_property(GObject *object, guint property_id, + GValue *value, GParamSpec *pspec) +{ + SpiceURI *self; + self = G_TYPE_CHECK_INSTANCE_CAST(object, SPICE_TYPE_URI, SpiceURI); + + switch (property_id) { + case SPICE_URI_SCHEME: + g_value_set_string(value, spice_uri_get_scheme(self)); + break; + case SPICE_URI_HOSTNAME: + g_value_set_string(value, spice_uri_get_hostname(self)); + break; + case SPICE_URI_PORT: + g_value_set_uint(value, spice_uri_get_port(self)); + break; + case SPICE_URI_USER: + g_value_set_string(value, spice_uri_get_user(self)); + break; + case SPICE_URI_PASSWORD: + g_value_set_string(value, spice_uri_get_password(self)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); + break; + } +} + + +static void spice_uri_set_property(GObject *object, guint property_id, + const GValue *value, GParamSpec *pspec) +{ + SpiceURI * self; + self = G_TYPE_CHECK_INSTANCE_CAST(object, SPICE_TYPE_URI, SpiceURI); + + switch (property_id) { + case SPICE_URI_SCHEME: + spice_uri_set_scheme(self, g_value_get_string(value)); + break; + case SPICE_URI_HOSTNAME: + spice_uri_set_hostname(self, g_value_get_string(value)); + break; + case SPICE_URI_USER: + spice_uri_set_user(self, g_value_get_string(value)); + break; + case SPICE_URI_PASSWORD: + spice_uri_set_password(self, g_value_get_string(value)); + break; + case SPICE_URI_PORT: + spice_uri_set_port(self, g_value_get_uint(value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); + break; + } +} + +static void spice_uri_finalize(GObject* obj) +{ + SpiceURI *self; + + self = G_TYPE_CHECK_INSTANCE_CAST(obj, SPICE_TYPE_URI, SpiceURI); + g_free(self->priv->scheme); + g_free(self->priv->hostname); + + G_OBJECT_CLASS (spice_uri_parent_class)->finalize (obj); +} + +static void spice_uri_init (SpiceURI *self) +{ + self->priv = SPICE_URI_GET_PRIVATE(self); +} + + +static void spice_uri_class_init(SpiceURIClass *klass) +{ + spice_uri_parent_class = g_type_class_peek_parent (klass); + g_type_class_add_private(klass, sizeof(SpiceURIPrivate)); + + G_OBJECT_CLASS (klass)->get_property = spice_uri_get_property; + G_OBJECT_CLASS (klass)->set_property = spice_uri_set_property; + G_OBJECT_CLASS (klass)->finalize = spice_uri_finalize; + + g_object_class_install_property(G_OBJECT_CLASS (klass), + SPICE_URI_SCHEME, + g_param_spec_string ("scheme", + "scheme", + "scheme", + NULL, + G_PARAM_STATIC_STRINGS | + G_PARAM_READWRITE)); + + g_object_class_install_property(G_OBJECT_CLASS (klass), + SPICE_URI_HOSTNAME, + g_param_spec_string ("hostname", + "hostname", + "hostname", + NULL, + G_PARAM_STATIC_STRINGS | + G_PARAM_READWRITE)); + + g_object_class_install_property(G_OBJECT_CLASS (klass), + SPICE_URI_PORT, + g_param_spec_uint ("port", + "port", + "port", + 0, G_MAXUINT, 0, + G_PARAM_STATIC_STRINGS | + G_PARAM_READWRITE)); + + g_object_class_install_property(G_OBJECT_CLASS (klass), + SPICE_URI_USER, + g_param_spec_string ("user", + "user", + "user", + NULL, + G_PARAM_STATIC_STRINGS | + G_PARAM_READWRITE)); + + g_object_class_install_property(G_OBJECT_CLASS (klass), + SPICE_URI_PASSWORD, + g_param_spec_string ("password", + "password", + "password", + NULL, + G_PARAM_STATIC_STRINGS | + G_PARAM_READWRITE)); +} + +/** + * spice_uri_to_string: + * @uri: a #SpiceURI + * + * Returns a string representing @uri. + * + * Returns: a string representing @uri, which the caller must free. + * Since: 0.23 + **/ +gchar* spice_uri_to_string(SpiceURI* self) +{ + SpiceURIPrivate *p; + + g_return_val_if_fail(SPICE_IS_URI(self), NULL); + p = self->priv; + + if (p->scheme == NULL || p->hostname == NULL) + return NULL; + + if (p->user || p->password) { + return g_strdup_printf("%s://%s:%s@%s:%u", + p->scheme, + p->user ?: "", p->password ?: "", + p->hostname, p->port); + } else { + return g_strdup_printf("%s://%s:%u", p->scheme, p->hostname, p->port); + } +} + +/** + * spice_uri_get_user: + * @uri: a #SpiceURI + * + * Gets @uri's user. + * + * Returns: @uri's user. + * Since: 0.23 + **/ +const gchar* spice_uri_get_user(SpiceURI *self) +{ + g_return_val_if_fail(SPICE_IS_URI(self), NULL); + + return self->priv->user; +} + + +/** + * spice_uri_set_user: + * @uri: a #SpiceURI + * @password: the user, or %NULL. + * + * Sets @uri's user to @password. + * Since: 0.23 + **/ +void spice_uri_set_user(SpiceURI *self, const gchar *user) +{ + g_return_if_fail(SPICE_IS_URI(self)); + + g_free(self->priv->user); + self->priv->user = g_strdup(user); + g_object_notify((GObject *)self, "user"); +} + +/** + * spice_uri_get_password: + * @uri: a #SpiceURI + * + * Gets @uri's password. + * + * Returns: @uri's password. + * Since: 0.23 + **/ +const gchar* spice_uri_get_password(SpiceURI *self) +{ + g_return_val_if_fail(SPICE_IS_URI(self), NULL); + + return self->priv->password; +} + +/** + * spice_uri_set_password: + * @uri: a #SpiceURI + * @password: the password, or %NULL. + * + * Sets @uri's password to @password. + * Since: 0.23 + **/ +void spice_uri_set_password(SpiceURI *self, const gchar *password) +{ + g_return_if_fail(SPICE_IS_URI(self)); + + g_free(self->priv->password); + self->priv->password = g_strdup(password); + g_object_notify((GObject *)self, "password"); +} diff --git a/gtk/spice-uri.h b/gtk/spice-uri.h new file mode 100644 index 0000000..9e8d590 --- /dev/null +++ b/gtk/spice-uri.h @@ -0,0 +1,52 @@ +/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* + Copyright (C) 2012 Red Hat, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see <http://www.gnu.org/licenses/>. +*/ +#ifndef __SPICE_URI_H__ +#define __SPICE_URI_H__ + +#include <glib-object.h> + +G_BEGIN_DECLS + +#define SPICE_TYPE_URI (spice_uri_get_type ()) +#define SPICE_URI(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SPICE_TYPE_URI, SpiceURI)) +#define SPICE_URI_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SPICE_TYPE_URI, SpiceURIClass)) +#define SPICE_IS_URI(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SPICE_TYPE_URI)) +#define SPICE_IS_URI_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SPICE_TYPE_URI)) +#define SPICE_URI_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SPICE_TYPE_URI, SpiceURIClass)) + +typedef struct _SpiceURI SpiceURI; +typedef struct _SpiceURIClass SpiceURIClass; +typedef struct _SpiceURIPrivate SpiceURIPrivate; + +GType spice_uri_get_type(void) G_GNUC_CONST; + +const gchar* spice_uri_get_scheme(SpiceURI* uri); +void spice_uri_set_scheme(SpiceURI* uri, const gchar* scheme); +const gchar* spice_uri_get_hostname(SpiceURI* uri); +void spice_uri_set_hostname(SpiceURI* uri, const gchar* hostname); +guint spice_uri_get_port(SpiceURI* uri); +void spice_uri_set_port(SpiceURI* uri, guint port); +gchar *spice_uri_to_string(SpiceURI* uri); +const gchar* spice_uri_get_user(SpiceURI* uri); +void spice_uri_set_user(SpiceURI* uri, const gchar* user); +const gchar* spice_uri_get_password(SpiceURI* uri); +void spice_uri_set_password(SpiceURI* uri, const gchar* password); + +G_END_DECLS + +#endif /* __SPICE_URI_H__ */ -- 1.8.4.2 _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/spice-devel