/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* * GIO - GLib Input, Output and Streaming Library * * Copyright 2010 Collabora, Ltd. * * 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 * . * * Author: Nicolas Dufresne */ #include "config.h" #include #include #include #include "glibproxyresolver.h" #include #include struct _GLibproxyResolver { GObject parent_instance; pxProxyFactory *factory; }; static void g_libproxy_resolver_iface_init (GProxyResolverInterface *iface); #ifdef GLIBPROXY_MODULE static void g_libproxy_resolver_class_finalize (GLibproxyResolverClass *klass) { } G_DEFINE_DYNAMIC_TYPE_EXTENDED (GLibproxyResolver, g_libproxy_resolver, G_TYPE_OBJECT, G_TYPE_FLAG_FINAL, G_IMPLEMENT_INTERFACE_DYNAMIC (G_TYPE_PROXY_RESOLVER, g_libproxy_resolver_iface_init)) #else G_DEFINE_FINAL_TYPE_WITH_CODE (GLibproxyResolver, g_libproxy_resolver, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (G_TYPE_PROXY_RESOLVER, g_libproxy_resolver_iface_init)) #endif static void g_libproxy_resolver_finalize (GObject *object) { GLibproxyResolver *resolver = G_LIBPROXY_RESOLVER (object); if (resolver->factory) { px_proxy_factory_free (resolver->factory); resolver->factory = NULL; } /* must chain up */ G_OBJECT_CLASS (g_libproxy_resolver_parent_class)->finalize (object); } static gboolean is_running_environment_proxy_test (void) { return g_strcmp0 (g_getenv ("GIO_PROXY_TEST_NAME"), "environment") == 0; } static void g_libproxy_resolver_init (GLibproxyResolver *resolver) { if (!is_running_environment_proxy_test ()) resolver->factory = px_proxy_factory_new (); } static gboolean g_libproxy_resolver_is_supported (GProxyResolver *object) { GLibproxyResolver *resolver = G_LIBPROXY_RESOLVER (object); return resolver->factory != NULL; } static gchar ** copy_proxies (gchar **proxies) { gchar **copy; int len = 0; int i, j; GError *error = NULL; for (i = 0; proxies[i]; i++) { if (!strncmp ("socks://", proxies[i], 8)) len += 3; else len++; } copy = g_new (gchar *, len + 1); for (i = j = 0; proxies[i]; i++, j++) { if (!g_uri_is_valid (proxies[i], G_URI_FLAGS_NONE, &error)) { g_warning ("Received invalid URI %s from libproxy: %s", proxies[i], error->message); g_clear_error (&error); j--; continue; } if (!strncmp ("socks://", proxies[i], 8)) { copy[j++] = g_strdup_printf ("socks5://%s", proxies[i] + 8); copy[j++] = g_strdup_printf ("socks4a://%s", proxies[i] + 8); copy[j] = g_strdup_printf ("socks4://%s", proxies[i] + 8); } else { copy[j] = g_strdup (proxies[i]); } } copy[j] = NULL; return copy; } static void get_libproxy_proxies (GTask *task, gpointer source_object, gpointer task_data, GCancellable *cancellable) { GLibproxyResolver *resolver = source_object; const gchar *uri = task_data; GError *error = NULL; gchar **proxies; if (g_task_return_error_if_cancelled (task)) return; proxies = px_proxy_factory_get_proxies (resolver->factory, uri); if (proxies) { /* We always copy to be able to translate "socks" entry into * three entries ("socks5", "socks4a", "socks4"). */ g_task_return_pointer (task, copy_proxies (proxies), (GDestroyNotify) g_strfreev); px_proxy_factory_free_proxies (proxies); } else { g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Proxy resolver internal error.")); g_task_return_error (task, error); } } static gchar ** g_libproxy_resolver_lookup (GProxyResolver *iresolver, const gchar *uri, GCancellable *cancellable, GError **error) { GLibproxyResolver *resolver = G_LIBPROXY_RESOLVER (iresolver); GTask *task; gchar **proxies; task = g_task_new (resolver, cancellable, NULL, NULL); g_task_set_name (task, "[glib-networking] g_libproxy_resolver_lookup"); g_task_set_task_data (task, g_strdup (uri), g_free); g_task_set_return_on_cancel (task, TRUE); g_task_run_in_thread_sync (task, get_libproxy_proxies); proxies = g_task_propagate_pointer (task, error); g_object_unref (task); return proxies; } static void g_libproxy_resolver_lookup_async (GProxyResolver *resolver, const gchar *uri, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GTask *task; task = g_task_new (resolver, cancellable, callback, user_data); g_task_set_source_tag (task, g_libproxy_resolver_lookup_async); g_task_set_name (task, "[glib-networking] g_libproxy_resolver_lookup_async"); g_task_set_task_data (task, g_strdup (uri), g_free); g_task_set_return_on_cancel (task, TRUE); g_task_run_in_thread (task, get_libproxy_proxies); g_object_unref (task); } static gchar ** g_libproxy_resolver_lookup_finish (GProxyResolver *resolver, GAsyncResult *result, GError **error) { g_return_val_if_fail (g_task_is_valid (result, resolver), NULL); g_return_val_if_fail (g_task_get_source_tag (G_TASK (result)) == g_libproxy_resolver_lookup_async, NULL); return g_task_propagate_pointer (G_TASK (result), error); } static void g_libproxy_resolver_class_init (GLibproxyResolverClass *resolver_class) { GObjectClass *object_class; object_class = G_OBJECT_CLASS (resolver_class); object_class->finalize = g_libproxy_resolver_finalize; } static void g_libproxy_resolver_iface_init (GProxyResolverInterface *iface) { iface->is_supported = g_libproxy_resolver_is_supported; iface->lookup = g_libproxy_resolver_lookup; iface->lookup_async = g_libproxy_resolver_lookup_async; iface->lookup_finish = g_libproxy_resolver_lookup_finish; } #ifdef GLIBPROXY_MODULE void g_libproxy_resolver_register (GIOModule *module) { g_libproxy_resolver_register_type (G_TYPE_MODULE (module)); if (!module) g_io_extension_point_register (G_PROXY_RESOLVER_EXTENSION_POINT_NAME); g_io_extension_point_implement (G_PROXY_RESOLVER_EXTENSION_POINT_NAME, g_libproxy_resolver_get_type(), "libproxy", 10); } #endif