From: Dan Winship Date: Sat, 26 Jan 2013 14:54:03 +0000 (-0500) Subject: GSimpleProxyResolver: new simple GProxyResolver class X-Git-Tag: 2.35.8~13 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=ee17a54c289b8be286a54c594cff5c2d46345054;p=platform%2Fupstream%2Fglib.git GSimpleProxyResolver: new simple GProxyResolver class Add GSimpleProxyResolver, for letting people do static proxy resolution, and to use as a base class for other resolvers (such as GProxyResolverGnome). https://bugzilla.gnome.org/show_bug.cgi?id=691105 --- diff --git a/docs/reference/gio/gio-docs.xml b/docs/reference/gio/gio-docs.xml index 1fca51c..3c66dad 100644 --- a/docs/reference/gio/gio-docs.xml +++ b/docs/reference/gio/gio-docs.xml @@ -153,6 +153,7 @@ DNS resolution + diff --git a/docs/reference/gio/gio-sections.txt b/docs/reference/gio/gio-sections.txt index 04e9310..03e8400 100644 --- a/docs/reference/gio/gio-sections.txt +++ b/docs/reference/gio/gio-sections.txt @@ -4002,3 +4002,23 @@ g_task_get_type gnetworking.h g_networking_init + +
+gsimpleproxyresolver +GSimpleProxyResolver +GSimpleProxyResolver +g_simple_proxy_resolver_new +g_simple_proxy_resolver_set_default_proxy +g_simple_proxy_resolver_set_ignore_hosts +g_simple_proxy_resolver_set_uri_proxy + +GSimpleProxyResolverClass +GSimpleProxyResolverPrivate +G_TYPE_SIMPLE_PROXY_RESOLVER +G_SIMPLE_PROXY_RESOLVER +G_IS_SIMPLE_PROXY_RESOLVER +G_SIMPLE_PROXY_RESOLVER_CLASS +G_IS_SIMPLE_PROXY_RESOLVER_CLASS +G_SIMPLE_PROXY_RESOLVER_GET_CLASS +g_simple_proxy_resolver_get_type +
diff --git a/docs/reference/gio/gio.types b/docs/reference/gio/gio.types index 5cd996c..8e4825d 100644 --- a/docs/reference/gio/gio.types +++ b/docs/reference/gio/gio.types @@ -136,3 +136,4 @@ g_menu_item_get_type g_test_dbus_get_type g_test_dbus_flags_get_type g_task_get_type +g_simple_proxy_resolver_get_type diff --git a/gio/Makefile.am b/gio/Makefile.am index 136f9ef..06c71b9 100644 --- a/gio/Makefile.am +++ b/gio/Makefile.am @@ -403,6 +403,9 @@ libgio_2_0_la_SOURCES = \ gpollableutils.c \ gpollfilemonitor.c \ gpollfilemonitor.h \ + gproxy.c \ + gproxyaddress.c \ + gproxyaddressenumerator.c \ gproxyresolver.c \ gresolver.c \ gresource.c \ @@ -423,11 +426,9 @@ libgio_2_0_la_SOURCES = \ gsocketlistener.c \ gsocketoutputstream.c \ gsocketoutputstream.h \ - gproxy.c \ - gproxyaddress.c \ - gproxyaddressenumerator.c \ gsocketservice.c \ gsrvtarget.c \ + gsimpleproxyresolver.c \ gtask.c \ gtcpconnection.c \ gtcpwrapperconnection.c \ @@ -586,6 +587,7 @@ gio_headers = \ gsocketlistener.h \ gsocketservice.h \ gsrvtarget.h \ + gsimpleproxyresolver.h \ gtask.h \ gtcpconnection.h \ gtcpwrapperconnection.h \ diff --git a/gio/gio.h b/gio/gio.h index 1998a64..1f83062 100644 --- a/gio/gio.h +++ b/gio/gio.h @@ -122,6 +122,7 @@ #include #include #include +#include #include #include #include diff --git a/gio/gsimpleproxyresolver.c b/gio/gsimpleproxyresolver.c new file mode 100644 index 0000000..c6ac9b4 --- /dev/null +++ b/gio/gsimpleproxyresolver.c @@ -0,0 +1,593 @@ +/* GIO - GLib Input, Output and Streaming Library + * + * Copyright 2010, 2013 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 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 + * . + */ + +#include "config.h" + +#include + +#include "gsimpleproxyresolver.h" +#include "ginetaddress.h" +#include "ginetaddressmask.h" +#include "gnetworkingprivate.h" +#include "gtask.h" + +#include "glibintl.h" + +/** + * SECTION:gsimpleproxyresolver + * @short_description: Simple proxy resolver implementation + * @include: gio/gio.h + * @see_also: g_socket_client_set_proxy_resolver() + * + * #GSimpleProxyResolver is a simple #GProxyResolver implementation + * that handles a single default proxy, multiple URI-scheme-specific + * proxies, and a list of hosts that proxies should not be used for. + * + * #GSimpleProxyResolver is never the default proxy resolver, but it + * can be used as the base class for another proxy resolver + * implementation, or it can be created and used manually, such as + * with g_socket_client_set_proxy_resolver(). + * + * Since: 2.36 + */ + +typedef struct { + gchar *name; + gint length; + gushort port; +} GSimpleProxyResolverDomain; + +struct _GSimpleProxyResolverPrivate { + gchar *default_proxy, **ignore_hosts; + GHashTable *uri_proxies; + + GPtrArray *ignore_ips; + GSimpleProxyResolverDomain *ignore_domains; +}; + +static void g_simple_proxy_resolver_iface_init (GProxyResolverInterface *iface); + +G_DEFINE_TYPE_WITH_CODE (GSimpleProxyResolver, g_simple_proxy_resolver, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (G_TYPE_PROXY_RESOLVER, + g_simple_proxy_resolver_iface_init)) + +enum +{ + PROP_0, + PROP_DEFAULT_PROXY, + PROP_IGNORE_HOSTS +}; + +static void reparse_ignore_hosts (GSimpleProxyResolver *resolver); + +static void +g_simple_proxy_resolver_finalize (GObject *object) +{ + GSimpleProxyResolver *resolver = G_SIMPLE_PROXY_RESOLVER (object); + GSimpleProxyResolverPrivate *priv = resolver->priv; + + g_free (priv->default_proxy); + g_hash_table_destroy (priv->uri_proxies); + + g_clear_pointer (&priv->ignore_hosts, g_strfreev); + /* This will free ignore_ips and ignore_domains */ + reparse_ignore_hosts (resolver); + + G_OBJECT_CLASS (g_simple_proxy_resolver_parent_class)->finalize (object); +} + +static void +g_simple_proxy_resolver_init (GSimpleProxyResolver *resolver) +{ + resolver->priv = G_TYPE_INSTANCE_GET_PRIVATE (resolver, + G_TYPE_SIMPLE_PROXY_RESOLVER, + GSimpleProxyResolverPrivate); + resolver->priv->uri_proxies = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, g_free); +} + +static void +g_simple_proxy_resolver_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GSimpleProxyResolver *resolver = G_SIMPLE_PROXY_RESOLVER (object); + + switch (prop_id) + { + case PROP_DEFAULT_PROXY: + g_simple_proxy_resolver_set_default_proxy (resolver, g_value_get_string (value)); + break; + + case PROP_IGNORE_HOSTS: + g_simple_proxy_resolver_set_ignore_hosts (resolver, g_value_get_boxed (value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +g_simple_proxy_resolver_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GSimpleProxyResolver *resolver = G_SIMPLE_PROXY_RESOLVER (object); + + switch (prop_id) + { + case PROP_DEFAULT_PROXY: + g_value_set_string (value, resolver->priv->default_proxy); + break; + + case PROP_IGNORE_HOSTS: + g_value_set_boxed (value, resolver->priv->ignore_hosts); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +reparse_ignore_hosts (GSimpleProxyResolver *resolver) +{ + GSimpleProxyResolverPrivate *priv = resolver->priv; + GPtrArray *ignore_ips; + GArray *ignore_domains; + gchar *host, *tmp, *colon, *bracket; + GInetAddress *iaddr; + GInetAddressMask *mask; + GSimpleProxyResolverDomain domain; + gushort port; + int i; + + if (priv->ignore_ips) + g_ptr_array_free (priv->ignore_ips, TRUE); + if (priv->ignore_domains) + { + for (i = 0; priv->ignore_domains[i].name; i++) + g_free (priv->ignore_domains[i].name); + g_free (priv->ignore_domains); + } + priv->ignore_ips = NULL; + priv->ignore_domains = NULL; + + if (!priv->ignore_hosts || !priv->ignore_hosts[0]) + return; + + ignore_ips = g_ptr_array_new_with_free_func (g_object_unref); + ignore_domains = g_array_new (TRUE, FALSE, sizeof (GSimpleProxyResolverDomain)); + + for (i = 0; priv->ignore_hosts[i]; i++) + { + host = g_strchomp (priv->ignore_hosts[i]); + + /* See if it's an IP address or IP/length mask */ + mask = g_inet_address_mask_new_from_string (host, NULL); + if (mask) + { + g_ptr_array_add (ignore_ips, mask); + continue; + } + + port = 0; + + if (*host == '[') + { + /* [IPv6]:port */ + host++; + bracket = strchr (host, ']'); + if (!bracket || !bracket[1] || bracket[1] != ':') + goto bad; + + port = strtoul (bracket + 2, &tmp, 10); + if (*tmp) + goto bad; + + *bracket = '\0'; + } + else + { + colon = strchr (host, ':'); + if (colon && !strchr (colon + 1, ':')) + { + /* hostname:port or IPv4:port */ + port = strtoul (colon + 1, &tmp, 10); + if (*tmp) + goto bad; + *colon = '\0'; + } + } + + iaddr = g_inet_address_new_from_string (host); + if (iaddr) + g_object_unref (iaddr); + else + { + if (g_str_has_prefix (host, "*.")) + host += 2; + else if (*host == '.') + host++; + } + + memset (&domain, 0, sizeof (domain)); + domain.name = g_strdup (host); + domain.length = strlen (domain.name); + domain.port = port; + g_array_append_val (ignore_domains, domain); + continue; + + bad: + g_warning ("Ignoring invalid ignore_hosts value '%s'", host); + } + + if (ignore_ips->len) + priv->ignore_ips = ignore_ips; + else + g_ptr_array_free (ignore_ips, TRUE); + + if (ignore_domains->len) + priv->ignore_domains = (GSimpleProxyResolverDomain *)ignore_domains->data; + g_array_free (ignore_domains, ignore_domains->len == 0); +} + +static gboolean +ignore_host (GSimpleProxyResolver *resolver, + const gchar *host, + gushort port) +{ + GSimpleProxyResolverPrivate *priv = resolver->priv; + gchar *ascii_host = NULL; + gboolean ignore = FALSE; + gint i, length, offset; + + if (priv->ignore_ips) + { + GInetAddress *iaddr; + + iaddr = g_inet_address_new_from_string (host); + if (iaddr) + { + for (i = 0; i < priv->ignore_ips->len; i++) + { + GInetAddressMask *mask = priv->ignore_ips->pdata[i]; + + if (g_inet_address_mask_matches (mask, iaddr)) + { + ignore = TRUE; + break; + } + } + + g_object_unref (iaddr); + if (ignore) + return TRUE; + } + } + + if (priv->ignore_domains) + { + if (g_hostname_is_non_ascii (host)) + host = ascii_host = g_hostname_to_ascii (host); + length = strlen (host); + + for (i = 0; priv->ignore_domains[i].length; i++) + { + GSimpleProxyResolverDomain *domain = &priv->ignore_domains[i]; + + offset = length - domain->length; + if ((domain->port == 0 || domain->port == port) && + (offset == 0 || (offset > 0 && host[offset - 1] == '.')) && + (g_ascii_strcasecmp (domain->name, host + offset) == 0)) + { + ignore = TRUE; + break; + } + } + + g_free (ascii_host); + } + + return ignore; +} + +static gchar ** +g_simple_proxy_resolver_lookup (GProxyResolver *proxy_resolver, + const gchar *uri, + GCancellable *cancellable, + GError **error) +{ + GSimpleProxyResolver *resolver = G_SIMPLE_PROXY_RESOLVER (proxy_resolver); + GSimpleProxyResolverPrivate *priv = resolver->priv; + const gchar *proxy = NULL; + gchar **proxies; + + if (priv->ignore_ips || priv->ignore_domains) + { + gchar *host = NULL; + gushort port; + + if (_g_uri_parse_authority (uri, &host, &port, NULL) && + ignore_host (resolver, host, port)) + proxy = "direct://"; + + g_free (host); + } + + if (!proxy && g_hash_table_size (priv->uri_proxies)) + { + gchar *scheme = g_ascii_strdown (uri, strcspn (uri, ":")); + + proxy = g_hash_table_lookup (priv->uri_proxies, scheme); + g_free (scheme); + } + + if (!proxy) + proxy = priv->default_proxy; + + if (!strncmp (proxy, "socks://", 8)) + { + proxies = g_new0 (gchar *, 4); + proxies[0] = g_strdup_printf ("socks5://%s", proxy + 8); + proxies[1] = g_strdup_printf ("socks4a://%s", proxy + 8); + proxies[2] = g_strdup_printf ("socks4://%s", proxy + 8); + proxies[3] = NULL; + } + else + { + proxies = g_new0 (gchar *, 2); + proxies[0] = g_strdup (proxy); + } + + return proxies; +} + +static void +g_simple_proxy_resolver_lookup_async (GProxyResolver *proxy_resolver, + const gchar *uri, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleProxyResolver *resolver = G_SIMPLE_PROXY_RESOLVER (proxy_resolver); + GTask *task; + GError *error = NULL; + char **proxies; + + task = g_task_new (resolver, cancellable, callback, user_data); + + proxies = g_simple_proxy_resolver_lookup (proxy_resolver, uri, + cancellable, &error); + if (proxies) + g_task_return_pointer (task, proxies, (GDestroyNotify)g_strfreev); + else + g_task_return_error (task, error); + g_object_unref (task); +} + +static gchar ** +g_simple_proxy_resolver_lookup_finish (GProxyResolver *resolver, + GAsyncResult *result, + GError **error) +{ + g_return_val_if_fail (g_task_is_valid (result, resolver), NULL); + + return g_task_propagate_pointer (G_TASK (result), error); +} + +static void +g_simple_proxy_resolver_class_init (GSimpleProxyResolverClass *resolver_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (resolver_class); + + g_type_class_add_private (resolver_class, sizeof (GSimpleProxyResolverPrivate)); + + object_class->get_property = g_simple_proxy_resolver_get_property; + object_class->set_property = g_simple_proxy_resolver_set_property; + object_class->finalize = g_simple_proxy_resolver_finalize; + + /** + * GSimpleProxyResolver:default-proxy: + * + * The default proxy URI that will be used for any URI that doesn't + * match #GSimpleProxyResolver:ignore-hosts, and doesn't match any + * of the schemes set with g_simple_proxy_resolver_set_uri_proxy(). + * + * Note that as a special case, if this URI starts with + * "socks://", #GSimpleProxyResolver will treat + * it as referring to all three of the socks5, + * socks4a, and socks4 proxy + * types. + */ + g_object_class_install_property (object_class, PROP_DEFAULT_PROXY, + g_param_spec_string ("default-proxy", + P_("Default proxy"), + P_("The default proxy URI"), + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + /** + * GSimpleProxyResolver:ignore-hosts: + * + * A list of hostnames and IP addresses that the resolver should + * allow direct connections to. + * + * Entries can be in one of 4 formats: + * + * + * + * A hostname, such as "example.com", + * ".example.com", or + * "*.example.com", any of which match + * "example.com" or any subdomain of it. + * + * + * An IPv4 or IPv6 address, such as + * "192.168.1.1", which matches only + * that address. + * + * + * A hostname or IP address followed by a port, such as + * "example.com:80", which matches whatever + * the hostname or IP address would match, but only for URLs + * with the (explicitly) indicated port. In the case of an IPv6 + * address, the address part must appear in brackets: + * "[::1]:443" + * + * + * An IP address range, given by a base address and prefix length, + * such as "fe80::/10", which matches any + * address in that range. + * + * + * + * Note that when dealing with Unicode hostnames, the matching is + * done against the ASCII form of the name. + * + * Also note that hostname exclusions apply only to connections made + * to hosts identified by name, and IP address exclusions apply only + * to connections made to hosts identified by address. That is, if + * example.com has an address of + * 192.168.1.1, and the :ignore-hosts list + * contains only "192.168.1.1", then a connection + * to "example.com" (eg, via a #GNetworkAddress) + * will use the proxy, and a connection to + * "192.168.1.1" (eg, via a #GInetSocketAddress) + * will not. + * + * These rules match the "ignore-hosts"/"noproxy" rules most + * commonly used by other applications. + */ + g_object_class_install_property (object_class, PROP_IGNORE_HOSTS, + g_param_spec_boxed ("ignore-hosts", + P_("Ignore hosts"), + P_("Hosts that will not use the proxy"), + G_TYPE_STRV, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + +} + +static void +g_simple_proxy_resolver_iface_init (GProxyResolverInterface *iface) +{ + iface->lookup = g_simple_proxy_resolver_lookup; + iface->lookup_async = g_simple_proxy_resolver_lookup_async; + iface->lookup_finish = g_simple_proxy_resolver_lookup_finish; +} + +/** + * g_simple_proxy_resolver_new: + * @default_proxy: (allow-none): the default proxy to use, eg + * "socks://192.168.1.1" + * @ignore_hosts: (allow-none): an optional list of hosts/IP addresses + * to not use a proxy for. + * + * Creates a new #GSimpleProxyResolver. See + * #GSimpleProxyResolver:default-proxy and + * #GSimpleProxyResolver:ignore-hosts for more details on how the + * arguments are interpreted. + * + * Returns: a new #GSimpleProxyResolver + * + * Since: 2.36 + */ +GProxyResolver * +g_simple_proxy_resolver_new (const gchar *default_proxy, + gchar **ignore_hosts) +{ + return g_object_new (G_TYPE_SIMPLE_PROXY_RESOLVER, + "default-proxy", default_proxy, + "ignore-hosts", ignore_hosts, + NULL); +} + +/** + * g_simple_proxy_resolver_set_default_proxy: + * @resolver: a #GSimpleProxyResolver + * @default_proxy: the default proxy to use + * + * Sets the default proxy on @resolver, to be used for any URIs that + * don't match #GSimpleProxyResolver:ignore-hosts or a proxy set + * via g_simple_proxy_resolver_set_uri_proxy(). + * + * If @default_proxy starts with "socks://", + * #GSimpleProxyResolver will treat it as referring to all three of + * the socks5, socks4a, and + * socks4 proxy types. + * + * Since: 2.36 + */ +void +g_simple_proxy_resolver_set_default_proxy (GSimpleProxyResolver *resolver, + const gchar *default_proxy) +{ + g_return_if_fail (G_IS_SIMPLE_PROXY_RESOLVER (resolver)); + + g_free (resolver->priv->default_proxy); + resolver->priv->default_proxy = g_strdup (default_proxy); + g_object_notify (G_OBJECT (resolver), "default-proxy"); +} + +void +g_simple_proxy_resolver_set_ignore_hosts (GSimpleProxyResolver *resolver, + gchar **ignore_hosts) +{ + g_return_if_fail (G_IS_SIMPLE_PROXY_RESOLVER (resolver)); + + g_strfreev (resolver->priv->ignore_hosts); + resolver->priv->ignore_hosts = g_strdupv (ignore_hosts); + reparse_ignore_hosts (resolver); + g_object_notify (G_OBJECT (resolver), "ignore-hosts"); +} + +/** + * g_simple_proxy_resolver_set_uri_proxy: + * @resolver: a #GSimpleProxyResolver + * @uri_scheme: the URI scheme to add a proxy for + * @proxy: the proxy to use for @uri_scheme + * + * Adds a URI-scheme-specific proxy to @resolver; URIs whose scheme + * matches @uri_scheme (and which don't match + * #GSimpleProxyResolver:ignore-hosts) will be proxied via @proxy. + * + * As with #GSimpleProxyResolver:default-proxy, if @proxy starts with + * "socks://", #GSimpleProxyResolver will treat it + * as referring to all three of the socks5, + * socks4a, and socks4 proxy + * types. + * + * Since: 2.36 + */ +void +g_simple_proxy_resolver_set_uri_proxy (GSimpleProxyResolver *resolver, + const gchar *uri_scheme, + const gchar *proxy) +{ + g_return_if_fail (G_IS_SIMPLE_PROXY_RESOLVER (resolver)); + + g_hash_table_replace (resolver->priv->uri_proxies, + g_ascii_strdown (uri_scheme, -1), + g_strdup (proxy)); +} diff --git a/gio/gsimpleproxyresolver.h b/gio/gsimpleproxyresolver.h new file mode 100644 index 0000000..a451f99 --- /dev/null +++ b/gio/gsimpleproxyresolver.h @@ -0,0 +1,91 @@ +/* GIO - GLib Input, Output and Streaming Library + * + * Copyright 2010, 2013 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 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, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __G_SIMPLE_PROXY_RESOLVER_H__ +#define __G_SIMPLE_PROXY_RESOLVER_H__ + +#if !defined (__GIO_GIO_H_INSIDE__) && !defined (GIO_COMPILATION) +#error "Only can be included directly." +#endif + +#include + +G_BEGIN_DECLS + +#define G_TYPE_SIMPLE_PROXY_RESOLVER (g_simple_proxy_resolver_get_type ()) +#define G_SIMPLE_PROXY_RESOLVER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_SIMPLE_PROXY_RESOLVER, GSimpleProxyResolver)) +#define G_SIMPLE_PROXY_RESOLVER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_SIMPLE_PROXY_RESOLVER, GSimpleProxyResolverClass)) +#define G_IS_SIMPLE_PROXY_RESOLVER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_SIMPLE_PROXY_RESOLVER)) +#define G_IS_SIMPLE_PROXY_RESOLVER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_SIMPLE_PROXY_RESOLVER)) +#define G_SIMPLE_PROXY_RESOLVER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_SIMPLE_PROXY_RESOLVER, GSimpleProxyResolverClass)) + +/** + * GSimpleProxyResolver: + * + * A #GProxyResolver implementation for using a fixed set of proxies. + **/ +typedef struct _GSimpleProxyResolver GSimpleProxyResolver; +typedef struct _GSimpleProxyResolverPrivate GSimpleProxyResolverPrivate; +typedef struct _GSimpleProxyResolverClass GSimpleProxyResolverClass; + +struct _GSimpleProxyResolver +{ + GObject parent_instance; + + /*< private >*/ + GSimpleProxyResolverPrivate *priv; +}; + +struct _GSimpleProxyResolverClass +{ + GObjectClass parent_class; + + /*< private >*/ + /* Padding for future expansion */ + void (*_g_reserved1) (void); + void (*_g_reserved2) (void); + void (*_g_reserved3) (void); + void (*_g_reserved4) (void); + void (*_g_reserved5) (void); +}; + +GLIB_AVAILABLE_IN_2_36 +GType g_simple_proxy_resolver_get_type (void) G_GNUC_CONST; + +GLIB_AVAILABLE_IN_2_36 +GProxyResolver *g_simple_proxy_resolver_new (const gchar *default_proxy, + gchar **ignore_hosts); + +GLIB_AVAILABLE_IN_2_36 +void g_simple_proxy_resolver_set_default_proxy (GSimpleProxyResolver *resolver, + const gchar *default_proxy); + +GLIB_AVAILABLE_IN_2_36 +void g_simple_proxy_resolver_set_ignore_hosts (GSimpleProxyResolver *resolver, + gchar **ignore_hosts); + +GLIB_AVAILABLE_IN_2_36 +void g_simple_proxy_resolver_set_uri_proxy (GSimpleProxyResolver *resolver, + const gchar *uri_scheme, + const gchar *proxy); + +G_END_DECLS + +#endif /* __G_SIMPLE_PROXY_RESOLVER_H__ */ diff --git a/gio/tests/.gitignore b/gio/tests/.gitignore index ca0cb93..4e172ae 100644 --- a/gio/tests/.gitignore +++ b/gio/tests/.gitignore @@ -96,6 +96,7 @@ resources send-data services/org.gtk.GDBus.Examples.ObjectManager.service simple-async-result +simple-proxy sleepy-stream socket socket-client diff --git a/gio/tests/Makefile.am b/gio/tests/Makefile.am index 1f8e2cb..a6c56e1 100644 --- a/gio/tests/Makefile.am +++ b/gio/tests/Makefile.am @@ -62,6 +62,7 @@ TEST_PROGS += \ fileattributematcher \ resources \ proxy-test \ + simple-proxy \ inet-address \ permission \ task \ diff --git a/gio/tests/simple-proxy.c b/gio/tests/simple-proxy.c new file mode 100644 index 0000000..306ebdd --- /dev/null +++ b/gio/tests/simple-proxy.c @@ -0,0 +1,236 @@ +/* GStaticProxyResolver tests + * + * Copyright 2011, 2013 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 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 + * . + */ + +#include + +static void +test_uris (void) +{ + GProxyResolver *resolver; + gchar *ignore_hosts[2] = { "127.0.0.1", NULL }; + gchar **proxies; + GError *error = NULL; + + resolver = g_simple_proxy_resolver_new ("default://", ignore_hosts); + g_simple_proxy_resolver_set_uri_proxy (G_SIMPLE_PROXY_RESOLVER (resolver), + "http", "http://proxy.example.com"); + g_simple_proxy_resolver_set_uri_proxy (G_SIMPLE_PROXY_RESOLVER (resolver), + "ftp", "ftp://proxy.example.com"); + + proxies = g_proxy_resolver_lookup (resolver, "http://one.example.com/", + NULL, &error); + g_assert_no_error (error); + g_assert_cmpint (g_strv_length (proxies), ==, 1); + g_assert_cmpstr (proxies[0], ==, "http://proxy.example.com"); + g_strfreev (proxies); + + proxies = g_proxy_resolver_lookup (resolver, "HTTP://uppercase.example.com/", + NULL, &error); + g_assert_no_error (error); + g_assert_cmpint (g_strv_length (proxies), ==, 1); + g_assert_cmpstr (proxies[0], ==, "http://proxy.example.com"); + g_strfreev (proxies); + + proxies = g_proxy_resolver_lookup (resolver, "htt://missing-letter.example.com/", + NULL, &error); + g_assert_no_error (error); + g_assert_cmpint (g_strv_length (proxies), ==, 1); + g_assert_cmpstr (proxies[0], ==, "default://"); + g_strfreev (proxies); + + proxies = g_proxy_resolver_lookup (resolver, "https://extra-letter.example.com/", + NULL, &error); + g_assert_no_error (error); + g_assert_cmpint (g_strv_length (proxies), ==, 1); + g_assert_cmpstr (proxies[0], ==, "default://"); + g_strfreev (proxies); + + proxies = g_proxy_resolver_lookup (resolver, "ftp://five.example.com/", + NULL, &error); + g_assert_no_error (error); + g_assert_cmpint (g_strv_length (proxies), ==, 1); + g_assert_cmpstr (proxies[0], ==, "ftp://proxy.example.com"); + g_strfreev (proxies); + + proxies = g_proxy_resolver_lookup (resolver, "http://127.0.0.1/", + NULL, &error); + g_assert_no_error (error); + g_assert_cmpint (g_strv_length (proxies), ==, 1); + g_assert_cmpstr (proxies[0], ==, "direct://"); + g_strfreev (proxies); + + g_object_unref (resolver); +} + +static void +test_socks (void) +{ + GProxyResolver *resolver; + gchar *ignore_hosts[2] = { "127.0.0.1", NULL }; + gchar **proxies; + GError *error = NULL; + + resolver = g_simple_proxy_resolver_new ("socks://proxy.example.com", ignore_hosts); + + proxies = g_proxy_resolver_lookup (resolver, "http://one.example.com/", + NULL, &error); + g_assert_no_error (error); + g_assert_cmpint (g_strv_length (proxies), ==, 3); + g_assert_cmpstr (proxies[0], ==, "socks5://proxy.example.com"); + g_assert_cmpstr (proxies[1], ==, "socks4a://proxy.example.com"); + g_assert_cmpstr (proxies[2], ==, "socks4://proxy.example.com"); + g_strfreev (proxies); + + proxies = g_proxy_resolver_lookup (resolver, "http://127.0.0.1/", + NULL, &error); + g_assert_no_error (error); + g_assert_cmpint (g_strv_length (proxies), ==, 1); + g_assert_cmpstr (proxies[0], ==, "direct://"); + g_strfreev (proxies); + + g_object_unref (resolver); + + resolver = g_simple_proxy_resolver_new ("default-proxy://", ignore_hosts); + g_simple_proxy_resolver_set_uri_proxy (G_SIMPLE_PROXY_RESOLVER (resolver), + "http", "socks://proxy.example.com"); + + proxies = g_proxy_resolver_lookup (resolver, "http://one.example.com/", + NULL, &error); + g_assert_no_error (error); + g_assert_cmpint (g_strv_length (proxies), ==, 3); + g_assert_cmpstr (proxies[0], ==, "socks5://proxy.example.com"); + g_assert_cmpstr (proxies[1], ==, "socks4a://proxy.example.com"); + g_assert_cmpstr (proxies[2], ==, "socks4://proxy.example.com"); + g_strfreev (proxies); + + proxies = g_proxy_resolver_lookup (resolver, "ftp://two.example.com/", + NULL, &error); + g_assert_no_error (error); + g_assert_cmpint (g_strv_length (proxies), ==, 1); + g_assert_cmpstr (proxies[0], ==, "default-proxy://"); + g_strfreev (proxies); + + proxies = g_proxy_resolver_lookup (resolver, "http://127.0.0.1/", + NULL, &error); + g_assert_no_error (error); + g_assert_cmpint (g_strv_length (proxies), ==, 1); + g_assert_cmpstr (proxies[0], ==, "direct://"); + g_strfreev (proxies); + + g_object_unref (resolver); +} + +static const char *ignore_hosts[] = { + ".bbb.xx", + "*.ccc.xx", + "ddd.xx", + "*.eee.xx:8000", + "127.0.0.0/24", + "10.0.0.1:8000", + "::1", + "fe80::/10", + NULL +}; + +static const struct { + const char *uri; + const char *proxy; +} ignore_tests[] = { + { "http://aaa.xx/", "http://localhost:8080" }, + { "http://aaa.xx:8000/", "http://localhost:8080" }, + { "http://www.aaa.xx/", "http://localhost:8080" }, + { "http://www.aaa.xx:8000/", "http://localhost:8080" }, + { "https://aaa.xx/", "http://localhost:8080" }, + { "http://bbb.xx/", "direct://" }, + { "http://www.bbb.xx/", "direct://" }, + { "http://bbb.xx:8000/", "direct://" }, + { "http://www.bbb.xx:8000/", "direct://" }, + { "https://bbb.xx/", "direct://" }, + { "http://nobbb.xx/", "http://localhost:8080" }, + { "http://www.nobbb.xx/", "http://localhost:8080" }, + { "http://nobbb.xx:8000/", "http://localhost:8080" }, + { "http://www.nobbb.xx:8000/", "http://localhost:8080" }, + { "https://nobbb.xx/", "http://localhost:8080" }, + { "http://ccc.xx/", "direct://" }, + { "http://www.ccc.xx/", "direct://" }, + { "http://ccc.xx:8000/", "direct://" }, + { "http://www.ccc.xx:8000/", "direct://" }, + { "https://ccc.xx/", "direct://" }, + { "http://ddd.xx/", "direct://" }, + { "http://ddd.xx:8000/", "direct://" }, + { "http://www.ddd.xx/", "direct://" }, + { "http://www.ddd.xx:8000/", "direct://" }, + { "https://ddd.xx/", "direct://" }, + { "http://eee.xx/", "http://localhost:8080" }, + { "http://eee.xx:8000/", "direct://" }, + { "http://www.eee.xx/", "http://localhost:8080" }, + { "http://www.eee.xx:8000/", "direct://" }, + { "https://eee.xx/", "http://localhost:8080" }, + { "http://1.2.3.4/", "http://localhost:8080" }, + { "http://127.0.0.1/", "direct://" }, + { "http://127.0.0.2/", "direct://" }, + { "http://127.0.0.255/", "direct://" }, + { "http://127.0.1.0/", "http://localhost:8080" }, + { "http://10.0.0.1/", "http://localhost:8080" }, + { "http://10.0.0.1:8000/", "direct://" }, + { "http://[::1]/", "direct://" }, + { "http://[::1]:80/", "direct://" }, + { "http://[::1:1]/", "http://localhost:8080" }, + { "http://[::1:1]:80/", "http://localhost:8080" }, + { "http://[fe80::1]/", "direct://" }, + { "http://[fe80::1]:80/", "direct://" }, + { "http://[fec0::1]/", "http://localhost:8080" }, + { "http://[fec0::1]:80/", "http://localhost:8080" } +}; +static const int n_ignore_tests = G_N_ELEMENTS (ignore_tests); + +static void +test_ignore (void) +{ + GProxyResolver *resolver; + GError *error = NULL; + char **proxies; + int i; + + resolver = g_simple_proxy_resolver_new ("http://localhost:8080", + (char **)ignore_hosts); + + for (i = 0; i < n_ignore_tests; i++) + { + proxies = g_proxy_resolver_lookup (resolver, ignore_tests[i].uri, + NULL, &error); + g_assert_no_error (error); + + g_assert_cmpstr (proxies[0], ==, ignore_tests[i].proxy); + g_strfreev (proxies); + } +} + +int +main (int argc, + char *argv[]) +{ + g_test_init (&argc, &argv, NULL); + + g_test_add_func ("/static-proxy/uri", test_uris); + g_test_add_func ("/static-proxy/socks", test_socks); + g_test_add_func ("/static-proxy/ignore", test_ignore); + + return g_test_run(); +}