Imported Upstream version 2.74.0
[platform/upstream/glib-networking.git] / proxy / libproxy / glibproxyresolver.c
1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /*
3  * GIO - GLib Input, Output and Streaming Library
4  *
5  * Copyright 2010 Collabora, Ltd.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General
18  * Public License along with this library; if not, see
19  * <http://www.gnu.org/licenses/>.
20  *
21  * Author: Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
22  */
23
24 #include "config.h"
25
26 #include <proxy.h>
27 #include <stdlib.h>
28 #include <string.h>
29
30 #include "glibproxyresolver.h"
31
32 #include <glib.h>
33 #include <glib/gi18n-lib.h>
34
35 struct _GLibproxyResolver {
36   GObject parent_instance;
37   pxProxyFactory *factory;
38 };
39
40 static void g_libproxy_resolver_iface_init (GProxyResolverInterface *iface);
41
42 #ifdef GLIBPROXY_MODULE
43 static void
44 g_libproxy_resolver_class_finalize (GLibproxyResolverClass *klass)
45 {
46 }
47
48 G_DEFINE_DYNAMIC_TYPE_EXTENDED (GLibproxyResolver,
49                                 g_libproxy_resolver,
50                                 G_TYPE_OBJECT, 0,
51                                 G_IMPLEMENT_INTERFACE_DYNAMIC (G_TYPE_PROXY_RESOLVER,
52                                                                g_libproxy_resolver_iface_init))
53 #else
54 G_DEFINE_TYPE_EXTENDED (GLibproxyResolver,
55                         g_libproxy_resolver,
56                         G_TYPE_OBJECT, 0,
57                         G_IMPLEMENT_INTERFACE (G_TYPE_PROXY_RESOLVER,
58                                                g_libproxy_resolver_iface_init))
59 #endif
60
61 static void
62 g_libproxy_resolver_finalize (GObject *object)
63 {
64   GLibproxyResolver *resolver = G_LIBPROXY_RESOLVER (object);
65   
66   if (resolver->factory)
67     {
68       px_proxy_factory_free (resolver->factory);
69       resolver->factory = NULL;
70     }
71
72   /* must chain up */
73   G_OBJECT_CLASS (g_libproxy_resolver_parent_class)->finalize (object);
74 }
75
76 static gboolean
77 is_running_environment_proxy_test (void)
78 {
79   return g_strcmp0 (g_getenv ("GIO_PROXY_TEST_NAME"), "environment") == 0;
80 }
81
82 static void
83 g_libproxy_resolver_init (GLibproxyResolver *resolver)
84 {
85   if (!is_running_environment_proxy_test ())
86     resolver->factory = px_proxy_factory_new ();
87 }
88
89 static gboolean
90 g_libproxy_resolver_is_supported (GProxyResolver *object)
91 {
92   GLibproxyResolver *resolver = G_LIBPROXY_RESOLVER (object);
93   return resolver->factory != NULL;
94 }
95
96 static gchar **
97 copy_proxies (gchar **proxies)
98 {
99   gchar **copy;
100   int len = 0;
101   int i, j;
102   GError *error = NULL;
103
104   for (i = 0; proxies[i]; i++)
105     {
106       if (!strncmp ("socks://", proxies[i], 8))
107         len += 3;
108       else
109         len++;
110     }
111
112   copy = g_new (gchar *, len + 1);
113   for (i = j = 0; proxies[i]; i++, j++)
114     {
115       if (!g_uri_is_valid (proxies[i], G_URI_FLAGS_NONE, &error))
116         {
117           g_warning ("Received invalid URI %s from libproxy: %s", proxies[i], error->message);
118           g_clear_error (&error);
119           j--;
120           continue;
121         }
122
123       if (!strncmp ("socks://", proxies[i], 8))
124         {
125           copy[j++] = g_strdup_printf ("socks5://%s", proxies[i] + 8);
126           copy[j++] = g_strdup_printf ("socks4a://%s", proxies[i] + 8);
127           copy[j] = g_strdup_printf ("socks4://%s", proxies[i] + 8);
128         }
129       else
130         {
131           copy[j] = g_strdup (proxies[i]);
132         }
133     }
134   copy[j] = NULL;
135
136   return copy;
137 }
138
139 static void
140 get_libproxy_proxies (GTask        *task,
141                       gpointer      source_object,
142                       gpointer      task_data,
143                       GCancellable *cancellable)
144 {
145   GLibproxyResolver *resolver = source_object;
146   const gchar *uri = task_data;
147   GError *error = NULL;
148   gchar **proxies;
149
150   if (g_task_return_error_if_cancelled (task))
151     return;
152
153   proxies = px_proxy_factory_get_proxies (resolver->factory, uri);
154   if (proxies)
155     {
156       /* We always copy to be able to translate "socks" entry into
157        * three entries ("socks5", "socks4a", "socks4").
158        */
159       g_task_return_pointer (task, copy_proxies (proxies), (GDestroyNotify) g_strfreev);
160       px_proxy_factory_free_proxies (proxies);
161     }
162   else
163     {
164       g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_FAILED,
165                            _("Proxy resolver internal error."));
166       g_task_return_error (task, error);
167     }
168 }
169
170 static gchar **
171 g_libproxy_resolver_lookup (GProxyResolver  *iresolver,
172                             const gchar     *uri,
173                             GCancellable    *cancellable,
174                             GError         **error)
175 {
176   GLibproxyResolver *resolver = G_LIBPROXY_RESOLVER (iresolver);
177   GTask *task;
178   gchar **proxies;
179
180   task = g_task_new (resolver, cancellable, NULL, NULL);
181   g_task_set_name (task, "[glib-networking] g_libproxy_resolver_lookup");
182   g_task_set_task_data (task, g_strdup (uri), g_free);
183   g_task_set_return_on_cancel (task, TRUE);
184
185   g_task_run_in_thread_sync (task, get_libproxy_proxies);
186   proxies = g_task_propagate_pointer (task, error);
187   g_object_unref (task);
188
189   return proxies;
190 }
191
192 static void
193 g_libproxy_resolver_lookup_async (GProxyResolver      *resolver,
194                                   const gchar         *uri,
195                                   GCancellable        *cancellable,
196                                   GAsyncReadyCallback  callback,
197                                   gpointer             user_data)
198 {
199   GTask *task;
200
201   task = g_task_new (resolver, cancellable, callback, user_data);
202   g_task_set_source_tag (task, g_libproxy_resolver_lookup_async);
203   g_task_set_name (task, "[glib-networking] g_libproxy_resolver_lookup_async");
204   g_task_set_task_data (task, g_strdup (uri), g_free);
205   g_task_set_return_on_cancel (task, TRUE);
206   g_task_run_in_thread (task, get_libproxy_proxies);
207   g_object_unref (task);
208 }
209
210 static gchar **
211 g_libproxy_resolver_lookup_finish (GProxyResolver     *resolver,
212                                    GAsyncResult       *result,
213                                    GError            **error)
214 {
215   g_return_val_if_fail (g_task_is_valid (result, resolver), NULL);
216   g_return_val_if_fail (g_task_get_source_tag (G_TASK (result)) == g_libproxy_resolver_lookup_async, NULL);
217
218   return g_task_propagate_pointer (G_TASK (result), error);
219 }
220
221 static void
222 g_libproxy_resolver_class_init (GLibproxyResolverClass *resolver_class)
223 {
224   GObjectClass *object_class;
225   
226   object_class = G_OBJECT_CLASS (resolver_class);
227   object_class->finalize = g_libproxy_resolver_finalize;
228 }
229
230 static void
231 g_libproxy_resolver_iface_init (GProxyResolverInterface *iface)
232 {
233   iface->is_supported = g_libproxy_resolver_is_supported;
234   iface->lookup = g_libproxy_resolver_lookup;
235   iface->lookup_async = g_libproxy_resolver_lookup_async;
236   iface->lookup_finish = g_libproxy_resolver_lookup_finish;
237 }
238
239 #ifdef GLIBPROXY_MODULE
240 void
241 g_libproxy_resolver_register (GIOModule *module)
242 {
243   g_libproxy_resolver_register_type (G_TYPE_MODULE (module));
244   if (!module)
245     g_io_extension_point_register (G_PROXY_RESOLVER_EXTENSION_POINT_NAME);
246   g_io_extension_point_implement (G_PROXY_RESOLVER_EXTENSION_POINT_NAME,
247                                   g_libproxy_resolver_get_type(),
248                                   "libproxy",
249                                   10);
250 }
251 #endif