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