Git init
[profile/ivi/libsoup2.4.git] / libsoup / soup-proxy-resolver-default.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * soup-proxy-resolver-default.c: proxy resolution based on GIO's GProxyResolver
4  *
5  * Copyright (C) 2011 Collabora Ltd.
6  */
7
8 #ifdef HAVE_CONFIG_H
9 #include <config.h>
10 #endif
11
12 #include <string.h>
13 #include <stdlib.h>
14
15 #include "soup-proxy-resolver-default.h"
16 #include "soup-proxy-uri-resolver.h"
17 #include "soup-session-feature.h"
18 #include "soup-uri.h"
19
20 /**
21  * SoupProxyResolverDefault:
22  *
23  * A #SoupProxyURIResolver implementation that uses the default gio
24  * #GProxyResolver to resolve proxies.
25  *
26  * Since: 2.34
27  */
28
29 static void soup_proxy_resolver_default_interface_init (SoupProxyURIResolverInterface *proxy_resolver_interface);
30
31 G_DEFINE_TYPE_EXTENDED (SoupProxyResolverDefault, soup_proxy_resolver_default, G_TYPE_OBJECT, 0,
32                         G_IMPLEMENT_INTERFACE (SOUP_TYPE_SESSION_FEATURE, NULL)
33                         G_IMPLEMENT_INTERFACE (SOUP_TYPE_PROXY_URI_RESOLVER, soup_proxy_resolver_default_interface_init))
34
35 enum {
36         PROP_0,
37         PROP_GPROXY_RESOLVER
38 };
39
40 typedef struct {
41         GProxyResolver *gproxy_resolver;
42 } SoupProxyResolverDefaultPrivate;
43 #define SOUP_PROXY_RESOLVER_DEFAULT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUP_TYPE_PROXY_RESOLVER_DEFAULT, SoupProxyResolverDefaultPrivate))
44
45 static void
46 soup_proxy_resolver_default_init (SoupProxyResolverDefault *resolver)
47 {
48 }
49
50 static void
51 soup_proxy_resolver_default_set_property (GObject *object, guint prop_id,
52                                           const GValue *value, GParamSpec *pspec)
53 {
54         SoupProxyResolverDefaultPrivate *priv = SOUP_PROXY_RESOLVER_DEFAULT_GET_PRIVATE (object);
55
56         switch (prop_id) {
57         case PROP_GPROXY_RESOLVER:
58                 if (priv->gproxy_resolver)
59                         g_object_unref (priv->gproxy_resolver);
60                 priv->gproxy_resolver = g_value_dup_object (value);
61                 break;
62         default:
63                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
64                 break;
65         }
66 }
67
68 static void
69 soup_proxy_resolver_default_constructed (GObject *object)
70 {
71         SoupProxyResolverDefaultPrivate *priv = SOUP_PROXY_RESOLVER_DEFAULT_GET_PRIVATE (object);
72
73         if (!priv->gproxy_resolver) {
74                 priv->gproxy_resolver = g_proxy_resolver_get_default ();
75                 g_object_ref (priv->gproxy_resolver);
76         }
77
78         G_OBJECT_CLASS (soup_proxy_resolver_default_parent_class)->constructed (object);
79 }
80
81 static void
82 soup_proxy_resolver_default_finalize (GObject *object)
83 {
84         SoupProxyResolverDefaultPrivate *priv = SOUP_PROXY_RESOLVER_DEFAULT_GET_PRIVATE (object);
85
86         if (priv->gproxy_resolver)
87                 g_object_unref (priv->gproxy_resolver);
88
89         G_OBJECT_CLASS (soup_proxy_resolver_default_parent_class)->finalize (object);
90 }
91
92 static void
93 soup_proxy_resolver_default_class_init (SoupProxyResolverDefaultClass *klass)
94 {
95         GObjectClass *object_class = G_OBJECT_CLASS (klass);
96
97         g_type_class_add_private (klass, sizeof (SoupProxyResolverDefaultPrivate));
98
99         object_class->set_property = soup_proxy_resolver_default_set_property;
100         object_class->constructed = soup_proxy_resolver_default_constructed;
101         object_class->finalize = soup_proxy_resolver_default_finalize;
102
103         g_object_class_install_property (
104                 object_class, PROP_GPROXY_RESOLVER,
105                 g_param_spec_object ("gproxy-resolver",
106                                      "GProxyResolver",
107                                      "The underlying GProxyResolver",
108                                      G_TYPE_PROXY_RESOLVER,
109                                      G_PARAM_WRITABLE));
110 }
111
112 typedef struct {
113         SoupProxyURIResolver *resolver;
114         GCancellable *cancellable;
115         SoupProxyURIResolverCallback callback;
116         gpointer user_data;
117 } SoupAsyncData;
118
119 static void
120 resolved_proxy (GObject *object, GAsyncResult *result, gpointer data)
121 {
122         GProxyResolver *proxy_resolver = G_PROXY_RESOLVER (object);
123         SoupAsyncData *async_data = data;
124         GError *error = NULL;
125         char **proxy_uris = NULL;
126         SoupURI *proxy_uri = NULL;
127         guint status = SOUP_STATUS_OK;
128
129         proxy_uris = g_proxy_resolver_lookup_finish (proxy_resolver,
130                                                      result,
131                                                      &error);
132
133         if (error || proxy_uris == NULL || proxy_uris[0] == NULL) {
134                 status = SOUP_STATUS_CANT_RESOLVE_PROXY;
135                 goto finish;
136         }
137
138         /* We need to handle direct:// specially, otherwise
139          * SoupSession will try to resolve it as the proxy address.
140          */
141         if (!g_strcmp0 (proxy_uris[0], "direct://"))
142                 goto finish;
143
144         proxy_uri = soup_uri_new (proxy_uris[0]);
145         if (proxy_uri == NULL)
146                 status = SOUP_STATUS_CANT_RESOLVE_PROXY;
147
148 finish:
149         async_data->callback (async_data->resolver,
150                               status,
151                               proxy_uri,
152                               async_data->user_data);
153
154         if (async_data->cancellable)
155                 g_object_unref (async_data->cancellable);
156
157         g_strfreev (proxy_uris);
158
159         if (proxy_uri)
160                 soup_uri_free (proxy_uri);
161
162         g_object_unref (async_data->resolver);
163         g_slice_free (SoupAsyncData, async_data);
164 }
165
166 static void
167 get_proxy_uri_async (SoupProxyURIResolver  *resolver,
168                      SoupURI               *uri,
169                      GMainContext          *async_context,
170                      GCancellable          *cancellable,
171                      SoupProxyURIResolverCallback callback,
172                      gpointer               user_data)
173 {
174         SoupProxyResolverDefaultPrivate *priv = SOUP_PROXY_RESOLVER_DEFAULT_GET_PRIVATE (resolver);
175         SoupAsyncData *async_data;
176         char *uri_string;
177
178         async_data = g_slice_new0 (SoupAsyncData);
179         async_data->resolver = (SoupProxyURIResolver*) g_object_ref (resolver);
180         async_data->cancellable = cancellable;
181         async_data->callback = callback;
182         async_data->user_data = user_data;
183
184         uri_string = soup_uri_to_string (uri, FALSE);
185
186         if (async_context)
187                 g_main_context_push_thread_default (async_context);
188
189         g_proxy_resolver_lookup_async (priv->gproxy_resolver,
190                                        uri_string,
191                                        cancellable ? g_object_ref (cancellable) : NULL,
192                                        resolved_proxy,
193                                        async_data);
194
195         if (async_context)
196                 g_main_context_pop_thread_default (async_context);
197
198         g_free (uri_string);
199 }
200
201 static guint
202 get_proxy_uri_sync (SoupProxyURIResolver  *resolver,
203                     SoupURI               *uri,
204                     GCancellable          *cancellable,
205                     SoupURI              **proxy_uri)
206 {
207         SoupProxyResolverDefaultPrivate *priv = SOUP_PROXY_RESOLVER_DEFAULT_GET_PRIVATE (resolver);
208         GError *error = NULL;
209         char** proxy_uris = NULL;
210         char *uri_string;
211         guint status = SOUP_STATUS_OK;
212
213         uri_string = soup_uri_to_string (uri, FALSE);
214
215         proxy_uris = g_proxy_resolver_lookup (priv->gproxy_resolver,
216                                               uri_string,
217                                               cancellable,
218                                               &error);
219
220         g_free (uri_string);
221
222         if (error || proxy_uris == NULL || proxy_uris[0] == NULL) {
223                 status = SOUP_STATUS_CANT_RESOLVE_PROXY;
224                 goto cleanup;
225         }
226
227         /* We need to handle direct:// specially, otherwise
228          * SoupSession will try to resolve it as the proxy address.
229          */
230         if (!g_strcmp0 (proxy_uris[0], "direct://"))
231                 goto cleanup;
232
233         *proxy_uri = soup_uri_new (proxy_uris[0]);
234
235         if (!*proxy_uri)
236                 status = SOUP_STATUS_CANT_RESOLVE_PROXY;
237
238 cleanup:
239         g_strfreev (proxy_uris);
240         if (error)
241                 g_clear_error (&error);
242         return status;
243 }
244
245 static void
246 soup_proxy_resolver_default_interface_init (SoupProxyURIResolverInterface *iface)
247 {
248         iface->get_proxy_uri_async = get_proxy_uri_async;
249         iface->get_proxy_uri_sync = get_proxy_uri_sync;
250 }