Imported Upstream version 2.59.0
[platform/upstream/glib.git] / gio / gproxyaddressenumerator.c
1 /* GIO - GLib Input, Output and Streaming Library
2  *
3  * Copyright (C) 2010 Collabora, Ltd.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General
16  * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
17  *
18  * Author: Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
19  */
20
21 #include "config.h"
22 #include "gproxyaddressenumerator.h"
23
24 #include <string.h>
25
26 #include "gasyncresult.h"
27 #include "ginetaddress.h"
28 #include "glibintl.h"
29 #include "gnetworkaddress.h"
30 #include "gnetworkingprivate.h"
31 #include "gproxy.h"
32 #include "gproxyaddress.h"
33 #include "gproxyresolver.h"
34 #include "gtask.h"
35 #include "gresolver.h"
36 #include "gsocketaddress.h"
37 #include "gsocketaddressenumerator.h"
38 #include "gsocketconnectable.h"
39
40 /**
41  * SECTION:gproxyaddressenumerator
42  * @short_description: Proxy wrapper enumerator for socket addresses
43  * @include: gio/gio.h
44  *
45  * #GProxyAddressEnumerator is a wrapper around #GSocketAddressEnumerator which
46  * takes the #GSocketAddress instances returned by the #GSocketAddressEnumerator
47  * and wraps them in #GProxyAddress instances, using the given
48  * #GProxyAddressEnumerator:proxy-resolver.
49  *
50  * This enumerator will be returned (for example, by
51  * g_socket_connectable_enumerate()) as appropriate when a proxy is configured;
52  * there should be no need to manually wrap a #GSocketAddressEnumerator instance
53  * with one.
54  */
55
56 #define GET_PRIVATE(o) (G_PROXY_ADDRESS_ENUMERATOR (o)->priv)
57
58 enum
59 {
60   PROP_0,
61   PROP_URI,
62   PROP_DEFAULT_PORT,
63   PROP_CONNECTABLE,
64   PROP_PROXY_RESOLVER
65 };
66
67 struct _GProxyAddressEnumeratorPrivate
68 {
69   /* Destination address */
70   GSocketConnectable *connectable;
71   gchar              *dest_uri;
72   guint16             default_port;
73   gchar              *dest_hostname;
74   guint16             dest_port;
75   GList              *dest_ips;
76
77   /* Proxy enumeration */
78   GProxyResolver           *proxy_resolver;
79   gchar                   **proxies;
80   gchar                   **next_proxy;
81   GSocketAddressEnumerator *addr_enum;
82   GSocketAddress           *proxy_address;
83   const gchar              *proxy_uri;
84   gchar                    *proxy_type;
85   gchar                    *proxy_username;
86   gchar                    *proxy_password;
87   gboolean                  supports_hostname;
88   GList                    *next_dest_ip;
89   GError                   *last_error;
90 };
91
92 G_DEFINE_TYPE_WITH_PRIVATE (GProxyAddressEnumerator, g_proxy_address_enumerator, G_TYPE_SOCKET_ADDRESS_ENUMERATOR)
93
94 static void
95 save_userinfo (GProxyAddressEnumeratorPrivate *priv,
96                const gchar *proxy)
97 {
98   gchar *userinfo;
99
100   if (priv->proxy_username)
101     {
102       g_free (priv->proxy_username);
103       priv->proxy_username = NULL;
104     }
105
106   if (priv->proxy_password)
107     {
108       g_free (priv->proxy_password);
109       priv->proxy_password = NULL;
110     }
111   
112   if (_g_uri_parse_authority (proxy, NULL, NULL, &userinfo, NULL))
113     {
114       if (userinfo)
115         {
116           gchar **split = g_strsplit (userinfo, ":", 2);
117
118           if (split[0] != NULL)
119             {
120               priv->proxy_username = g_uri_unescape_string (split[0], NULL);
121               if (split[1] != NULL)
122                 priv->proxy_password = g_uri_unescape_string (split[1], NULL);
123             }
124
125           g_strfreev (split);
126           g_free (userinfo);
127         }
128     }
129 }
130
131 static void
132 next_enumerator (GProxyAddressEnumeratorPrivate *priv)
133 {
134   if (priv->proxy_address)
135     return;
136
137   while (priv->addr_enum == NULL && *priv->next_proxy)
138     {
139       GSocketConnectable *connectable = NULL;
140       GProxy *proxy;
141
142       priv->proxy_uri = *priv->next_proxy++;
143       g_free (priv->proxy_type);
144       priv->proxy_type = g_uri_parse_scheme (priv->proxy_uri);
145
146       if (priv->proxy_type == NULL)
147         continue;
148
149       /* Assumes hostnames are supported for unknown protocols */
150       priv->supports_hostname = TRUE;
151       proxy = g_proxy_get_default_for_protocol (priv->proxy_type);
152       if (proxy)
153         {
154           priv->supports_hostname = g_proxy_supports_hostname (proxy);
155           g_object_unref (proxy);
156         }
157
158       if (strcmp ("direct", priv->proxy_type) == 0)
159         {
160           if (priv->connectable)
161             connectable = g_object_ref (priv->connectable);
162           else
163             connectable = g_network_address_new (priv->dest_hostname,
164                                                  priv->dest_port);
165         }
166       else
167         {
168           GError *error = NULL;
169
170           connectable = g_network_address_parse_uri (priv->proxy_uri, 0, &error);
171
172           if (error)
173             {
174               g_warning ("Invalid proxy URI '%s': %s",
175                          priv->proxy_uri, error->message);
176               g_error_free (error);
177             }
178
179           save_userinfo (priv, priv->proxy_uri);
180         }
181
182       if (connectable)
183         {
184           priv->addr_enum = g_socket_connectable_enumerate (connectable);
185           g_object_unref (connectable);
186         }
187     }
188 }
189
190 static GSocketAddress *
191 g_proxy_address_enumerator_next (GSocketAddressEnumerator  *enumerator,
192                                  GCancellable              *cancellable,
193                                  GError                   **error)
194 {
195   GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (enumerator);
196   GSocketAddress *result = NULL;
197   GError *first_error = NULL;
198
199   if (priv->proxies == NULL)
200     {
201       priv->proxies = g_proxy_resolver_lookup (priv->proxy_resolver,
202                                                priv->dest_uri,
203                                                cancellable,
204                                                error);
205       priv->next_proxy = priv->proxies;
206
207       if (priv->proxies == NULL)
208         return NULL;
209     }
210
211   while (result == NULL && (*priv->next_proxy || priv->addr_enum))
212     {
213       gchar *dest_hostname;
214       gchar *dest_protocol;
215       GInetSocketAddress *inetsaddr;
216       GInetAddress *inetaddr;
217       guint16 port;
218
219       next_enumerator (priv);
220
221       if (!priv->addr_enum)
222         continue;
223
224       if (priv->proxy_address == NULL)
225         {
226           priv->proxy_address = g_socket_address_enumerator_next (
227                                     priv->addr_enum,
228                                     cancellable,
229                                     first_error ? NULL : &first_error);
230         }
231
232       if (priv->proxy_address == NULL)
233         {
234           g_object_unref (priv->addr_enum);
235           priv->addr_enum = NULL;
236
237           if (priv->dest_ips)
238             {
239               g_resolver_free_addresses (priv->dest_ips);
240               priv->dest_ips = NULL;
241             }
242
243           continue;
244         }
245
246       if (strcmp ("direct", priv->proxy_type) == 0)
247         {
248           result = priv->proxy_address;
249           priv->proxy_address = NULL;
250           continue;
251         }
252
253       if (!priv->supports_hostname)
254         {
255           GInetAddress *dest_ip;
256
257           if (!priv->dest_ips)
258             {
259               GResolver *resolver;
260
261               resolver = g_resolver_get_default();
262               priv->dest_ips = g_resolver_lookup_by_name (resolver,
263                                                           priv->dest_hostname,
264                                                           cancellable,
265                                                           first_error ? NULL : &first_error);
266               g_object_unref (resolver);
267
268               if (!priv->dest_ips)
269                 {
270                   g_object_unref (priv->proxy_address);
271                   priv->proxy_address = NULL;
272                   continue;
273                 }
274             }
275
276           if (!priv->next_dest_ip)
277             priv->next_dest_ip = priv->dest_ips;
278         
279           dest_ip = G_INET_ADDRESS (priv->next_dest_ip->data);
280           dest_hostname = g_inet_address_to_string (dest_ip);
281
282           priv->next_dest_ip = g_list_next (priv->next_dest_ip);
283         }
284       else
285         {
286           dest_hostname = g_strdup (priv->dest_hostname);
287         }
288       dest_protocol = g_uri_parse_scheme (priv->dest_uri);
289                                   
290       g_return_val_if_fail (G_IS_INET_SOCKET_ADDRESS (priv->proxy_address),
291                             NULL);
292
293       inetsaddr = G_INET_SOCKET_ADDRESS (priv->proxy_address);
294       inetaddr = g_inet_socket_address_get_address (inetsaddr);
295       port = g_inet_socket_address_get_port (inetsaddr);
296
297       result = g_object_new (G_TYPE_PROXY_ADDRESS,
298                              "address", inetaddr,
299                              "port", port,
300                              "protocol", priv->proxy_type,
301                              "destination-protocol", dest_protocol,
302                              "destination-hostname", dest_hostname,
303                              "destination-port", priv->dest_port,
304                              "username", priv->proxy_username,
305                              "password", priv->proxy_password,
306                              "uri", priv->proxy_uri,
307                              NULL);
308       g_free (dest_hostname);
309       g_free (dest_protocol);
310
311       if (priv->supports_hostname || priv->next_dest_ip == NULL)
312         {
313           g_object_unref (priv->proxy_address);
314           priv->proxy_address = NULL;
315         }
316     }
317
318   if (result == NULL && first_error)
319     g_propagate_error (error, first_error);
320   else if (first_error)
321     g_error_free (first_error);
322
323   return result;
324 }
325
326
327
328 static void
329 complete_async (GTask *task)
330 {
331   GProxyAddressEnumeratorPrivate *priv = g_task_get_task_data (task);
332
333   if (priv->last_error)
334     {
335       g_task_return_error (task, priv->last_error);
336       priv->last_error = NULL;
337     }
338   else
339     g_task_return_pointer (task, NULL, NULL);
340
341   g_object_unref (task);
342 }
343
344 static void
345 return_result (GTask *task)
346 {
347   GProxyAddressEnumeratorPrivate *priv = g_task_get_task_data (task);
348   GSocketAddress *result;
349
350   if (strcmp ("direct", priv->proxy_type) == 0)
351     {
352       result = priv->proxy_address;
353       priv->proxy_address = NULL;
354     }
355   else
356     {
357       gchar *dest_hostname, *dest_protocol;
358       GInetSocketAddress *inetsaddr;
359       GInetAddress *inetaddr;
360       guint16 port;
361
362       if (!priv->supports_hostname)
363         {
364           GInetAddress *dest_ip;
365
366           if (!priv->next_dest_ip)
367             priv->next_dest_ip = priv->dest_ips;
368
369           dest_ip = G_INET_ADDRESS (priv->next_dest_ip->data);
370           dest_hostname = g_inet_address_to_string (dest_ip);
371
372           priv->next_dest_ip = g_list_next (priv->next_dest_ip);
373         }
374       else
375         {
376           dest_hostname = g_strdup (priv->dest_hostname);
377         }
378       dest_protocol = g_uri_parse_scheme (priv->dest_uri);
379
380       g_return_if_fail (G_IS_INET_SOCKET_ADDRESS (priv->proxy_address));
381
382       inetsaddr = G_INET_SOCKET_ADDRESS (priv->proxy_address);
383       inetaddr = g_inet_socket_address_get_address (inetsaddr);
384       port = g_inet_socket_address_get_port (inetsaddr);
385
386       result = g_object_new (G_TYPE_PROXY_ADDRESS,
387                              "address", inetaddr,
388                              "port", port,
389                              "protocol", priv->proxy_type,
390                              "destination-protocol", dest_protocol,
391                              "destination-hostname", dest_hostname,
392                              "destination-port", priv->dest_port,
393                              "username", priv->proxy_username,
394                              "password", priv->proxy_password,
395                              "uri", priv->proxy_uri,
396                              NULL);
397       g_free (dest_hostname);
398       g_free (dest_protocol);
399
400       if (priv->supports_hostname || priv->next_dest_ip == NULL)
401         {
402           g_object_unref (priv->proxy_address);
403           priv->proxy_address = NULL;
404         }
405     }
406
407   g_task_return_pointer (task, result, g_object_unref);
408   g_object_unref (task);
409 }
410
411 static void address_enumerate_cb (GObject      *object,
412                                   GAsyncResult *result,
413                                   gpointer      user_data);
414
415 static void
416 next_proxy (GTask *task)
417 {
418   GProxyAddressEnumeratorPrivate *priv = g_task_get_task_data (task);
419
420   if (*priv->next_proxy)
421     {
422       g_object_unref (priv->addr_enum);
423       priv->addr_enum = NULL;
424
425       if (priv->dest_ips)
426         {
427           g_resolver_free_addresses (priv->dest_ips);
428           priv->dest_ips = NULL;
429         }
430
431       next_enumerator (priv);
432
433       if (priv->addr_enum)
434         {
435           g_socket_address_enumerator_next_async (priv->addr_enum,
436                                                   g_task_get_cancellable (task),
437                                                   address_enumerate_cb,
438                                                   task);
439           return;
440         }
441     }
442
443   complete_async (task);
444 }
445
446 static void
447 dest_hostname_lookup_cb (GObject           *object,
448                          GAsyncResult      *result,
449                          gpointer           user_data)
450 {
451   GTask *task = user_data;
452   GProxyAddressEnumeratorPrivate *priv = g_task_get_task_data (task);
453
454   g_clear_error (&priv->last_error);
455   priv->dest_ips = g_resolver_lookup_by_name_finish (G_RESOLVER (object),
456                                                      result,
457                                                      &priv->last_error);
458   if (priv->dest_ips)
459     return_result (task);
460   else
461     {
462       g_clear_object (&priv->proxy_address);
463       next_proxy (task);
464     }
465 }
466
467 static void
468 address_enumerate_cb (GObject      *object,
469                       GAsyncResult *result,
470                       gpointer      user_data)
471 {
472   GTask *task = user_data;
473   GProxyAddressEnumeratorPrivate *priv = g_task_get_task_data (task);
474
475   g_clear_error (&priv->last_error);
476   priv->proxy_address =
477     g_socket_address_enumerator_next_finish (priv->addr_enum,
478                                              result,
479                                              &priv->last_error);
480   if (priv->proxy_address)
481     {
482       if (!priv->supports_hostname && !priv->dest_ips)
483         {
484           GResolver *resolver;
485           resolver = g_resolver_get_default();
486           g_resolver_lookup_by_name_async (resolver,
487                                            priv->dest_hostname,
488                                            g_task_get_cancellable (task),
489                                            dest_hostname_lookup_cb,
490                                            task);
491           g_object_unref (resolver);
492           return;
493         }
494
495       return_result (task);
496     }
497   else
498     next_proxy (task);
499 }
500
501 static void
502 proxy_lookup_cb (GObject      *object,
503                  GAsyncResult *result,
504                  gpointer      user_data)
505 {
506   GTask *task = user_data;
507   GProxyAddressEnumeratorPrivate *priv = g_task_get_task_data (task);
508
509   g_clear_error (&priv->last_error);
510   priv->proxies = g_proxy_resolver_lookup_finish (G_PROXY_RESOLVER (object),
511                                                   result,
512                                                   &priv->last_error);
513   priv->next_proxy = priv->proxies;
514
515   if (priv->last_error)
516     {
517       complete_async (task);
518       return;
519     }
520   else
521     {
522       next_enumerator (priv);
523       if (priv->addr_enum)
524         {
525           g_socket_address_enumerator_next_async (priv->addr_enum,
526                                                   g_task_get_cancellable (task),
527                                                   address_enumerate_cb,
528                                                   task);
529           return;
530         }
531     }
532
533   complete_async (task);
534 }
535
536 static void
537 g_proxy_address_enumerator_next_async (GSocketAddressEnumerator *enumerator,
538                                        GCancellable             *cancellable,
539                                        GAsyncReadyCallback       callback,
540                                        gpointer                  user_data)
541 {
542   GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (enumerator);
543   GTask *task;
544
545   task = g_task_new (enumerator, cancellable, callback, user_data);
546   g_task_set_source_tag (task, g_proxy_address_enumerator_next_async);
547   g_task_set_task_data (task, priv, NULL);
548
549   if (priv->proxies == NULL)
550     {
551       g_proxy_resolver_lookup_async (priv->proxy_resolver,
552                                      priv->dest_uri,
553                                      cancellable,
554                                      proxy_lookup_cb,
555                                      task);
556       return;
557     }
558
559   if (priv->addr_enum)
560     {
561       if (priv->proxy_address)
562         {
563           return_result (task);
564           return;
565         }
566       else
567         {
568           g_socket_address_enumerator_next_async (priv->addr_enum,
569                                                   cancellable,
570                                                   address_enumerate_cb,
571                                                   task);
572           return;
573         }
574     }
575
576   complete_async (task);
577 }
578
579 static GSocketAddress *
580 g_proxy_address_enumerator_next_finish (GSocketAddressEnumerator  *enumerator,
581                                         GAsyncResult              *result,
582                                         GError                   **error)
583 {
584   g_return_val_if_fail (g_task_is_valid (result, enumerator), NULL);
585
586   return g_task_propagate_pointer (G_TASK (result), error);
587 }
588
589 static void
590 g_proxy_address_enumerator_constructed (GObject *object)
591 {
592   GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (object);
593   GSocketConnectable *conn;
594   guint port;
595
596   if (priv->dest_uri)
597     {
598       conn = g_network_address_parse_uri (priv->dest_uri, priv->default_port, NULL);
599       if (conn)
600         {
601           g_object_get (conn,
602                         "hostname", &priv->dest_hostname,
603                         "port", &port,
604                         NULL);
605           priv->dest_port = port;
606
607           g_object_unref (conn);
608         }
609       else
610         g_warning ("Invalid URI '%s'", priv->dest_uri);
611     }
612
613   G_OBJECT_CLASS (g_proxy_address_enumerator_parent_class)->constructed (object);
614 }
615
616 static void
617 g_proxy_address_enumerator_get_property (GObject        *object,
618                                          guint           property_id,
619                                          GValue         *value,
620                                          GParamSpec     *pspec)
621 {
622   GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (object);
623   switch (property_id)
624     {
625     case PROP_URI:
626       g_value_set_string (value, priv->dest_uri);
627       break;
628
629     case PROP_DEFAULT_PORT:
630       g_value_set_uint (value, priv->default_port);
631       break;
632
633     case PROP_CONNECTABLE:
634       g_value_set_object (value, priv->connectable);
635       break;
636
637     case PROP_PROXY_RESOLVER:
638       g_value_set_object (value, priv->proxy_resolver);
639       break;
640
641     default:
642       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
643     }
644 }
645
646 static void
647 g_proxy_address_enumerator_set_property (GObject        *object,
648                                          guint           property_id,
649                                          const GValue   *value,
650                                          GParamSpec     *pspec)
651 {
652   GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (object);
653   switch (property_id)
654     {
655     case PROP_URI:
656       priv->dest_uri = g_value_dup_string (value);
657       break;
658
659     case PROP_DEFAULT_PORT:
660       priv->default_port = g_value_get_uint (value);
661       break;
662
663     case PROP_CONNECTABLE:
664       priv->connectable = g_value_dup_object (value);
665       break;
666
667     case PROP_PROXY_RESOLVER:
668       if (priv->proxy_resolver)
669         g_object_unref (priv->proxy_resolver);
670       priv->proxy_resolver = g_value_get_object (value);
671       if (!priv->proxy_resolver)
672         priv->proxy_resolver = g_proxy_resolver_get_default ();
673       g_object_ref (priv->proxy_resolver);
674       break;
675
676     default:
677       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
678     }
679 }
680
681 static void
682 g_proxy_address_enumerator_finalize (GObject *object)
683 {
684   GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (object);
685
686   if (priv->connectable)
687     g_object_unref (priv->connectable);
688
689   if (priv->proxy_resolver)
690     g_object_unref (priv->proxy_resolver);
691
692   g_free (priv->dest_uri);
693   g_free (priv->dest_hostname);
694
695   if (priv->dest_ips)
696     g_resolver_free_addresses (priv->dest_ips);
697
698   g_strfreev (priv->proxies);
699
700   if (priv->addr_enum)
701     g_object_unref (priv->addr_enum);
702
703   g_free (priv->proxy_type);
704   g_free (priv->proxy_username);
705   g_free (priv->proxy_password);
706
707   g_clear_error (&priv->last_error);
708
709   G_OBJECT_CLASS (g_proxy_address_enumerator_parent_class)->finalize (object);
710 }
711
712 static void
713 g_proxy_address_enumerator_init (GProxyAddressEnumerator *self)
714 {
715   self->priv = g_proxy_address_enumerator_get_instance_private (self);
716 }
717
718 static void
719 g_proxy_address_enumerator_class_init (GProxyAddressEnumeratorClass *proxy_enumerator_class)
720 {
721   GObjectClass *object_class = G_OBJECT_CLASS (proxy_enumerator_class);
722   GSocketAddressEnumeratorClass *enumerator_class = G_SOCKET_ADDRESS_ENUMERATOR_CLASS (proxy_enumerator_class);
723
724   object_class->constructed = g_proxy_address_enumerator_constructed;
725   object_class->set_property = g_proxy_address_enumerator_set_property;
726   object_class->get_property = g_proxy_address_enumerator_get_property;
727   object_class->finalize = g_proxy_address_enumerator_finalize;
728
729   enumerator_class->next = g_proxy_address_enumerator_next;
730   enumerator_class->next_async = g_proxy_address_enumerator_next_async;
731   enumerator_class->next_finish = g_proxy_address_enumerator_next_finish;
732
733   g_object_class_install_property (object_class,
734                                    PROP_URI,
735                                    g_param_spec_string ("uri",
736                                                         P_("URI"),
737                                                         P_("The destination URI, use none:// for generic socket"),
738                                                         NULL,
739                                                         G_PARAM_READWRITE |
740                                                         G_PARAM_CONSTRUCT_ONLY |
741                                                         G_PARAM_STATIC_STRINGS));
742
743   /**
744    * GProxyAddressEnumerator:default-port:
745    *
746    * The default port to use if #GProxyAddressEnumerator:uri does not
747    * specify one.
748    *
749    * Since: 2.38
750    */
751   g_object_class_install_property (object_class,
752                                    PROP_DEFAULT_PORT,
753                                    g_param_spec_uint ("default-port",
754                                                       P_("Default port"),
755                                                       P_("The default port to use if uri does not specify one"),
756                                                       0, 65535, 0,
757                                                       G_PARAM_READWRITE |
758                                                       G_PARAM_CONSTRUCT_ONLY |
759                                                       G_PARAM_STATIC_STRINGS));
760
761   g_object_class_install_property (object_class,
762                                    PROP_CONNECTABLE,
763                                    g_param_spec_object ("connectable",
764                                                         P_("Connectable"),
765                                                         P_("The connectable being enumerated."),
766                                                         G_TYPE_SOCKET_CONNECTABLE,
767                                                         G_PARAM_READWRITE |
768                                                         G_PARAM_CONSTRUCT_ONLY |
769                                                         G_PARAM_STATIC_STRINGS));
770
771   /**
772    * GProxyAddressEnumerator:proxy-resolver:
773    *
774    * The proxy resolver to use.
775    *
776    * Since: 2.36
777    */
778   g_object_class_install_property (object_class,
779                                    PROP_PROXY_RESOLVER,
780                                    g_param_spec_object ("proxy-resolver",
781                                                         P_("Proxy resolver"),
782                                                         P_("The proxy resolver to use."),
783                                                         G_TYPE_PROXY_RESOLVER,
784                                                         G_PARAM_READWRITE |
785                                                         G_PARAM_CONSTRUCT |
786                                                         G_PARAM_STATIC_STRINGS));
787 }