• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #undef SOUP_VERSION_MIN_REQUIRED
13 #define SOUP_VERSION_MIN_REQUIRED SOUP_VERSION_2_42
14 
15 #include "soup-proxy-resolver-default.h"
16 #include "soup.h"
17 
18 /**
19  * SECTION:soup-proxy-resolver-default
20  * @short_description: System proxy configuration integration
21  *
22  * #SoupProxyResolverDefault is a <type>SoupProxyURIResolver</type>
23  * implementation that uses the default gio #GProxyResolver to resolve
24  * proxies.
25  *
26  * In libsoup 2.44 and later, you can set the session's
27  * #SoupSession:proxy-resolver property to the resolver returned by
28  * g_proxy_resolver_get_default() to get the same effect. Note that
29  * for "plain" #SoupSessions (ie, not #SoupSessionAsync or
30  * #SoupSessionSync), this is done for you automatically.
31  *
32  * Since: 2.34
33  *
34  * Deprecated: Use #SoupSession:proxy-resolver
35  */
36 
37 enum {
38 	PROP_0,
39 	PROP_GPROXY_RESOLVER
40 };
41 
42 typedef struct {
43 	GProxyResolver *gproxy_resolver;
44 } SoupProxyResolverDefaultPrivate;
45 
46 static void soup_proxy_resolver_default_interface_init (SoupProxyURIResolverInterface *proxy_resolver_interface);
47 
48 G_DEFINE_TYPE_EXTENDED (SoupProxyResolverDefault, soup_proxy_resolver_default, G_TYPE_OBJECT, 0,
49                         G_ADD_PRIVATE (SoupProxyResolverDefault)
50 			G_IMPLEMENT_INTERFACE (SOUP_TYPE_SESSION_FEATURE, NULL)
51 			G_IMPLEMENT_INTERFACE (SOUP_TYPE_PROXY_URI_RESOLVER, soup_proxy_resolver_default_interface_init))
52 
53 static void
soup_proxy_resolver_default_init(SoupProxyResolverDefault * resolver)54 soup_proxy_resolver_default_init (SoupProxyResolverDefault *resolver)
55 {
56 }
57 
58 static void
soup_proxy_resolver_default_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)59 soup_proxy_resolver_default_set_property (GObject *object, guint prop_id,
60 					  const GValue *value, GParamSpec *pspec)
61 {
62 	SoupProxyResolverDefault *resolver = SOUP_PROXY_RESOLVER_DEFAULT (object);
63 	SoupProxyResolverDefaultPrivate *priv = soup_proxy_resolver_default_get_instance_private (resolver);
64 
65 	switch (prop_id) {
66 	case PROP_GPROXY_RESOLVER:
67 		if (priv->gproxy_resolver)
68 			g_object_unref (priv->gproxy_resolver);
69 		priv->gproxy_resolver = g_value_dup_object (value);
70 		break;
71 	default:
72 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
73 		break;
74 	}
75 }
76 
77 static void
soup_proxy_resolver_default_constructed(GObject * object)78 soup_proxy_resolver_default_constructed (GObject *object)
79 {
80 	SoupProxyResolverDefault *resolver = SOUP_PROXY_RESOLVER_DEFAULT (object);
81 	SoupProxyResolverDefaultPrivate *priv = soup_proxy_resolver_default_get_instance_private (resolver);
82 
83 	if (!priv->gproxy_resolver) {
84 		priv->gproxy_resolver = g_proxy_resolver_get_default ();
85 		g_object_ref (priv->gproxy_resolver);
86 	}
87 
88 	G_OBJECT_CLASS (soup_proxy_resolver_default_parent_class)->constructed (object);
89 }
90 
91 static void
soup_proxy_resolver_default_finalize(GObject * object)92 soup_proxy_resolver_default_finalize (GObject *object)
93 {
94 	SoupProxyResolverDefault *resolver = SOUP_PROXY_RESOLVER_DEFAULT (object);
95 	SoupProxyResolverDefaultPrivate *priv = soup_proxy_resolver_default_get_instance_private (resolver);
96 
97 	g_clear_object (&priv->gproxy_resolver);
98 
99 	G_OBJECT_CLASS (soup_proxy_resolver_default_parent_class)->finalize (object);
100 }
101 
102 static void
soup_proxy_resolver_default_class_init(SoupProxyResolverDefaultClass * klass)103 soup_proxy_resolver_default_class_init (SoupProxyResolverDefaultClass *klass)
104 {
105 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
106 
107 	object_class->set_property = soup_proxy_resolver_default_set_property;
108 	object_class->constructed = soup_proxy_resolver_default_constructed;
109 	object_class->finalize = soup_proxy_resolver_default_finalize;
110 
111 	g_object_class_install_property (
112 		object_class, PROP_GPROXY_RESOLVER,
113 		g_param_spec_object ("gproxy-resolver",
114 				     "GProxyResolver",
115 				     "The underlying GProxyResolver",
116 				     G_TYPE_PROXY_RESOLVER,
117 				     G_PARAM_WRITABLE |
118 				     G_PARAM_STATIC_STRINGS));
119 }
120 
121 typedef struct {
122 	SoupProxyURIResolver *resolver;
123 	GCancellable *cancellable;
124 	SoupProxyURIResolverCallback callback;
125 	gpointer user_data;
126 } SoupAsyncData;
127 
128 static void
resolved_proxy(GObject * object,GAsyncResult * result,gpointer data)129 resolved_proxy (GObject *object, GAsyncResult *result, gpointer data)
130 {
131 	GProxyResolver *proxy_resolver = G_PROXY_RESOLVER (object);
132 	SoupAsyncData *async_data = data;
133 	GError *error = NULL;
134 	char **proxy_uris = NULL;
135 	SoupURI *proxy_uri = NULL;
136 	guint status = SOUP_STATUS_OK;
137 
138 	proxy_uris = g_proxy_resolver_lookup_finish (proxy_resolver,
139 						     result,
140 						     &error);
141 
142 	if (error || proxy_uris == NULL || proxy_uris[0] == NULL) {
143 		status = SOUP_STATUS_CANT_RESOLVE_PROXY;
144 		goto finish;
145 	}
146 
147 	/* We need to handle direct:// specially, otherwise
148 	 * SoupSession will try to resolve it as the proxy address.
149 	 */
150 	if (!g_strcmp0 (proxy_uris[0], "direct://"))
151 		goto finish;
152 
153 	proxy_uri = soup_uri_new (proxy_uris[0]);
154 	if (proxy_uri == NULL)
155 		status = SOUP_STATUS_CANT_RESOLVE_PROXY;
156 
157 finish:
158 	async_data->callback (async_data->resolver,
159 			      status,
160 			      proxy_uri,
161 			      async_data->user_data);
162 
163 	if (async_data->cancellable)
164 		g_object_unref (async_data->cancellable);
165 
166 	g_strfreev (proxy_uris);
167 
168 	if (proxy_uri)
169 		soup_uri_free (proxy_uri);
170 
171 	g_object_unref (async_data->resolver);
172 	g_slice_free (SoupAsyncData, async_data);
173 }
174 
175 static void
get_proxy_uri_async(SoupProxyURIResolver * resolver,SoupURI * uri,GMainContext * async_context,GCancellable * cancellable,SoupProxyURIResolverCallback callback,gpointer user_data)176 get_proxy_uri_async (SoupProxyURIResolver  *resolver,
177 		     SoupURI		   *uri,
178 		     GMainContext	   *async_context,
179 		     GCancellable	   *cancellable,
180 		     SoupProxyURIResolverCallback callback,
181 		     gpointer		    user_data)
182 {
183 	SoupProxyResolverDefault *resolver_default = SOUP_PROXY_RESOLVER_DEFAULT (resolver);
184 	SoupProxyResolverDefaultPrivate *priv = soup_proxy_resolver_default_get_instance_private (resolver_default);
185 	SoupAsyncData *async_data;
186 	char *uri_string;
187 
188 	async_data = g_slice_new0 (SoupAsyncData);
189 	async_data->resolver = (SoupProxyURIResolver*) g_object_ref (resolver);
190 	async_data->cancellable = cancellable;
191 	async_data->callback = callback;
192 	async_data->user_data = user_data;
193 
194 	uri_string = soup_uri_to_string (uri, FALSE);
195 
196 	if (async_context)
197 		g_main_context_push_thread_default (async_context);
198 
199 	g_proxy_resolver_lookup_async (priv->gproxy_resolver,
200 				       uri_string,
201 				       cancellable ? g_object_ref (cancellable) : NULL,
202 				       resolved_proxy,
203 				       async_data);
204 
205 	if (async_context)
206 		g_main_context_pop_thread_default (async_context);
207 
208 	g_free (uri_string);
209 }
210 
211 static guint
get_proxy_uri_sync(SoupProxyURIResolver * resolver,SoupURI * uri,GCancellable * cancellable,SoupURI ** proxy_uri)212 get_proxy_uri_sync (SoupProxyURIResolver  *resolver,
213 		    SoupURI		  *uri,
214 		    GCancellable	  *cancellable,
215 		    SoupURI		 **proxy_uri)
216 {
217 	SoupProxyResolverDefault *resolver_default = SOUP_PROXY_RESOLVER_DEFAULT (resolver);
218 	SoupProxyResolverDefaultPrivate *priv = soup_proxy_resolver_default_get_instance_private (resolver_default);
219 	GError *error = NULL;
220 	char** proxy_uris = NULL;
221 	char *uri_string;
222 	guint status = SOUP_STATUS_OK;
223 
224 	uri_string = soup_uri_to_string (uri, FALSE);
225 
226 	proxy_uris = g_proxy_resolver_lookup (priv->gproxy_resolver,
227 					      uri_string,
228 					      cancellable,
229 					      &error);
230 
231 	g_free (uri_string);
232 
233 	if (error || proxy_uris == NULL || proxy_uris[0] == NULL) {
234 		status = SOUP_STATUS_CANT_RESOLVE_PROXY;
235 		goto cleanup;
236 	}
237 
238 	/* We need to handle direct:// specially, otherwise
239 	 * SoupSession will try to resolve it as the proxy address.
240 	 */
241 	if (!g_strcmp0 (proxy_uris[0], "direct://"))
242 		goto cleanup;
243 
244 	*proxy_uri = soup_uri_new (proxy_uris[0]);
245 
246 	if (!*proxy_uri)
247 		status = SOUP_STATUS_CANT_RESOLVE_PROXY;
248 
249 cleanup:
250 	g_strfreev (proxy_uris);
251 	if (error)
252 		g_clear_error (&error);
253 	return status;
254 }
255 
256 static void
soup_proxy_resolver_default_interface_init(SoupProxyURIResolverInterface * iface)257 soup_proxy_resolver_default_interface_init (SoupProxyURIResolverInterface *iface)
258 {
259 	iface->get_proxy_uri_async = get_proxy_uri_async;
260 	iface->get_proxy_uri_sync = get_proxy_uri_sync;
261 }
262