1 /*
2  * librest - RESTful web services access
3  * Copyright (c) 2008, 2009, Intel Corporation.
4  *
5  * Authors: Rob Bradford <rob@linux.intel.com>
6  *          Ross Burton <ross@linux.intel.com>
7  *
8  * This program is free software; you can redistribute it and/or modify it
9  * under the terms and conditions of the GNU Lesser General Public License,
10  * version 2.1, as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope it will be useful, but WITHOUT ANY
13  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14  * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
15  * more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License
18  * along with this program; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  */
22 
23 #include <config.h>
24 #include <string.h>
25 
26 #include <libsoup/soup.h>
27 #if WITH_GNOME
28 #include <libsoup/soup-gnome.h>
29 #endif
30 
31 #include "rest-marshal.h"
32 #include "rest-proxy-auth-private.h"
33 #include "rest-proxy.h"
34 #include "rest-private.h"
35 
36 G_DEFINE_TYPE (RestProxy, rest_proxy, G_TYPE_OBJECT)
37 
38 #define GET_PRIVATE(o) \
39   (G_TYPE_INSTANCE_GET_PRIVATE ((o), REST_TYPE_PROXY, RestProxyPrivate))
40 
41 typedef struct _RestProxyPrivate RestProxyPrivate;
42 
43 struct _RestProxyPrivate {
44   gchar *url_format;
45   gchar *url;
46   gchar *user_agent;
47   gchar *username;
48   gchar *password;
49   gboolean binding_required;
50   SoupSession *session;
51   SoupSession *session_sync;
52   gboolean disable_cookies;
53   char *ssl_ca_file;
54 };
55 
56 enum
57 {
58   PROP0 = 0,
59   PROP_URL_FORMAT,
60   PROP_BINDING_REQUIRED,
61   PROP_USER_AGENT,
62   PROP_DISABLE_COOKIES,
63   PROP_USERNAME,
64   PROP_PASSWORD,
65   PROP_SSL_STRICT,
66   PROP_SSL_CA_FILE
67 };
68 
69 enum {
70   AUTHENTICATE,
71   LAST_SIGNAL
72 };
73 
74 static guint signals[LAST_SIGNAL] = { 0 };
75 
76 
77 static gboolean _rest_proxy_simple_run_valist (RestProxy *proxy,
78                                                char     **payload,
79                                                goffset   *len,
80                                                GError   **error,
81                                                va_list    params);
82 
83 static RestProxyCall *_rest_proxy_new_call (RestProxy *proxy);
84 
85 static gboolean _rest_proxy_bind_valist (RestProxy *proxy,
86                                          va_list    params);
87 
88 GQuark
rest_proxy_error_quark(void)89 rest_proxy_error_quark (void)
90 {
91   return g_quark_from_static_string ("rest-proxy-error-quark");
92 }
93 
94 static void
rest_proxy_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)95 rest_proxy_get_property (GObject   *object,
96                          guint      property_id,
97                          GValue     *value,
98                          GParamSpec *pspec)
99 {
100   RestProxyPrivate *priv = GET_PRIVATE (object);
101 
102   switch (property_id) {
103     case PROP_URL_FORMAT:
104       g_value_set_string (value, priv->url_format);
105       break;
106     case PROP_BINDING_REQUIRED:
107       g_value_set_boolean (value, priv->binding_required);
108       break;
109     case PROP_USER_AGENT:
110       g_value_set_string (value, priv->user_agent);
111       break;
112     case PROP_DISABLE_COOKIES:
113       g_value_set_boolean (value, priv->disable_cookies);
114       break;
115     case PROP_USERNAME:
116       g_value_set_string (value, priv->username);
117       break;
118     case PROP_PASSWORD:
119       g_value_set_string (value, priv->password);
120       break;
121     case PROP_SSL_STRICT: {
122       gboolean ssl_strict;
123       g_object_get (G_OBJECT(priv->session),
124                     "ssl-strict", &ssl_strict,
125                     NULL);
126       g_value_set_boolean (value, ssl_strict);
127       break;
128     }
129     case PROP_SSL_CA_FILE:
130       g_value_set_string (value, priv->ssl_ca_file);
131       break;
132 
133   default:
134     G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
135   }
136 }
137 
138 static void
rest_proxy_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)139 rest_proxy_set_property (GObject      *object,
140                          guint         property_id,
141                          const GValue *value,
142                          GParamSpec   *pspec)
143 {
144   RestProxyPrivate *priv = GET_PRIVATE (object);
145 
146   switch (property_id) {
147     case PROP_URL_FORMAT:
148       g_free (priv->url_format);
149       priv->url_format = g_value_dup_string (value);
150 
151       /* Clear the cached url */
152       g_free (priv->url);
153       priv->url = NULL;
154       break;
155     case PROP_BINDING_REQUIRED:
156       priv->binding_required = g_value_get_boolean (value);
157 
158       /* Clear cached url */
159       g_free (priv->url);
160       priv->url = NULL;
161       break;
162     case PROP_USER_AGENT:
163       g_free (priv->user_agent);
164       priv->user_agent = g_value_dup_string (value);
165       break;
166     case PROP_DISABLE_COOKIES:
167       priv->disable_cookies = g_value_get_boolean (value);
168       break;
169     case PROP_USERNAME:
170       g_free (priv->username);
171       priv->username = g_value_dup_string (value);
172       break;
173     case PROP_PASSWORD:
174       g_free (priv->password);
175       priv->password = g_value_dup_string (value);
176       break;
177     case PROP_SSL_STRICT:
178       g_object_set (G_OBJECT(priv->session),
179                     "ssl-strict", g_value_get_boolean (value),
180                     NULL);
181       g_object_set (G_OBJECT(priv->session_sync),
182                     "ssl-strict", g_value_get_boolean (value),
183                     NULL);
184       break;
185     case PROP_SSL_CA_FILE:
186       g_free(priv->ssl_ca_file);
187       priv->ssl_ca_file = g_value_dup_string (value);
188       break;
189   default:
190     G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
191   }
192 }
193 
194 static void
rest_proxy_dispose(GObject * object)195 rest_proxy_dispose (GObject *object)
196 {
197   RestProxyPrivate *priv = GET_PRIVATE (object);
198 
199   if (priv->session)
200   {
201     g_object_unref (priv->session);
202     priv->session = NULL;
203   }
204 
205   if (priv->session_sync)
206   {
207     g_object_unref (priv->session_sync);
208     priv->session_sync = NULL;
209   }
210 
211   G_OBJECT_CLASS (rest_proxy_parent_class)->dispose (object);
212 }
213 
214 static gboolean
default_authenticate_cb(RestProxy * self,G_GNUC_UNUSED RestProxyAuth * auth,gboolean retrying)215 default_authenticate_cb (RestProxy *self,
216                          G_GNUC_UNUSED RestProxyAuth *auth,
217                          gboolean retrying)
218 {
219   /* We only want to try the credentials once, otherwise we get in an
220    * infinite loop with failed credentials, retrying the same invalid
221    * ones again and again
222    */
223   return !retrying;
224 }
225 
226 static void
authenticate(RestProxy * self,SoupMessage * msg,SoupAuth * soup_auth,gboolean retrying,SoupSession * session)227 authenticate (RestProxy   *self,
228               SoupMessage *msg,
229               SoupAuth    *soup_auth,
230               gboolean     retrying,
231               SoupSession *session)
232 {
233   RestProxyPrivate *priv = GET_PRIVATE (self);
234   RestProxyAuth *rest_auth;
235   gboolean try_auth;
236 
237   rest_auth = rest_proxy_auth_new (self, session, msg, soup_auth);
238   g_signal_emit(self, signals[AUTHENTICATE], 0, rest_auth, retrying, &try_auth);
239   if (try_auth && !rest_proxy_auth_is_paused (rest_auth))
240     soup_auth_authenticate (soup_auth, priv->username, priv->password);
241   g_object_unref (G_OBJECT (rest_auth));
242 }
243 
244 static void
rest_proxy_constructed(GObject * object)245 rest_proxy_constructed (GObject *object)
246 {
247   RestProxyPrivate *priv = GET_PRIVATE (object);
248 
249   if (!priv->disable_cookies) {
250     SoupSessionFeature *cookie_jar =
251       (SoupSessionFeature *)soup_cookie_jar_new ();
252     soup_session_add_feature (priv->session, cookie_jar);
253     soup_session_add_feature (priv->session_sync, cookie_jar);
254     g_object_unref (cookie_jar);
255   }
256 
257   if (REST_DEBUG_ENABLED(PROXY)) {
258     SoupSessionFeature *logger = (SoupSessionFeature*)soup_logger_new (SOUP_LOGGER_LOG_BODY, 0);
259     soup_session_add_feature (priv->session, logger);
260     g_object_unref (logger);
261 
262     logger = (SoupSessionFeature*)soup_logger_new (SOUP_LOGGER_LOG_BODY, 0);
263     soup_session_add_feature (priv->session_sync, logger);
264     g_object_unref (logger);
265   }
266 
267   /* session lifetime is same as self, no need to keep signalid */
268   g_signal_connect_swapped (priv->session, "authenticate",
269                             G_CALLBACK(authenticate), object);
270   g_signal_connect_swapped (priv->session_sync, "authenticate",
271                             G_CALLBACK(authenticate), object);
272 }
273 
274 static void
rest_proxy_finalize(GObject * object)275 rest_proxy_finalize (GObject *object)
276 {
277   RestProxyPrivate *priv = GET_PRIVATE (object);
278 
279   g_free (priv->url);
280   g_free (priv->url_format);
281   g_free (priv->user_agent);
282   g_free (priv->username);
283   g_free (priv->password);
284   g_free (priv->ssl_ca_file);
285 
286   G_OBJECT_CLASS (rest_proxy_parent_class)->finalize (object);
287 }
288 
289 static void
rest_proxy_class_init(RestProxyClass * klass)290 rest_proxy_class_init (RestProxyClass *klass)
291 {
292   GParamSpec *pspec;
293   GObjectClass *object_class = G_OBJECT_CLASS (klass);
294   RestProxyClass *proxy_class = REST_PROXY_CLASS (klass);
295 
296   _rest_setup_debugging ();
297 
298   g_type_class_add_private (klass, sizeof (RestProxyPrivate));
299 
300   object_class->get_property = rest_proxy_get_property;
301   object_class->set_property = rest_proxy_set_property;
302   object_class->dispose = rest_proxy_dispose;
303   object_class->constructed = rest_proxy_constructed;
304   object_class->finalize = rest_proxy_finalize;
305 
306   proxy_class->simple_run_valist = _rest_proxy_simple_run_valist;
307   proxy_class->new_call = _rest_proxy_new_call;
308   proxy_class->bind_valist = _rest_proxy_bind_valist;
309 
310   pspec = g_param_spec_string ("url-format",
311                                "url-format",
312                                "Format string for the RESTful url",
313                                NULL,
314                                G_PARAM_READWRITE);
315   g_object_class_install_property (object_class,
316                                    PROP_URL_FORMAT,
317                                    pspec);
318 
319   pspec = g_param_spec_boolean ("binding-required",
320                                 "binding-required",
321                                 "Whether the URL format requires binding",
322                                 FALSE,
323                                 G_PARAM_READWRITE);
324   g_object_class_install_property (object_class,
325                                    PROP_BINDING_REQUIRED,
326                                    pspec);
327 
328   pspec = g_param_spec_string ("user-agent",
329                                "user-agent",
330                                "The User-Agent of the client",
331                                NULL,
332                                G_PARAM_READWRITE);
333   g_object_class_install_property (object_class,
334                                    PROP_USER_AGENT,
335                                    pspec);
336 
337   pspec = g_param_spec_boolean ("disable-cookies",
338                                 "disable-cookies",
339                                 "Whether to disable cookie support",
340                                 FALSE,
341                                 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
342   g_object_class_install_property (object_class,
343                                    PROP_DISABLE_COOKIES,
344                                    pspec);
345 
346   pspec = g_param_spec_string ("username",
347                                "username",
348                                "The username for authentication",
349                                NULL,
350                                G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
351   g_object_class_install_property (object_class,
352                                    PROP_USERNAME,
353                                    pspec);
354 
355   pspec = g_param_spec_string ("password",
356                                "password",
357                                "The password for authentication",
358                                NULL,
359                                G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
360   g_object_class_install_property (object_class,
361                                    PROP_PASSWORD,
362                                    pspec);
363 
364   pspec = g_param_spec_boolean ("ssl-strict",
365                                 "Strictly validate SSL certificates",
366                                 "Whether certificate errors should be considered a connection error",
367                                 TRUE,
368                                 G_PARAM_READWRITE);
369   g_object_class_install_property (object_class,
370                                    PROP_SSL_STRICT,
371                                    pspec);
372 
373   pspec = g_param_spec_string ("ssl-ca-file",
374                                "SSL CA file",
375                                "File containing SSL CA certificates.",
376                                NULL,
377                                G_PARAM_READWRITE);
378   g_object_class_install_property (object_class,
379                                    PROP_SSL_CA_FILE,
380                                    pspec);
381 
382   /**
383    * RestProxy::authenticate:
384    * @proxy: the proxy
385    * @auth: authentication state
386    * @retrying: %TRUE if this is the second (or later) attempt
387    *
388    * Emitted when the proxy requires authentication. If
389    * credentials are available, set the 'username' and 'password'
390    * properties on @proxy and return %TRUE from the callback.
391    * This will cause the signal emission to stop, and librest will
392    * try to connect with these credentials
393    * If these credentials fail, the signal will be
394    * emitted again, with @retrying set to %TRUE, which will
395    * continue until %FALSE is returned from the callback.
396    *
397    * If you call rest_proxy_auth_pause() on @auth before
398    * returning, then you can the authentication credentials on
399    * the #RestProxy object asynchronously. You have to make sure
400    * that @auth does not get destroyed with g_object_ref().
401    * You can then unpause the authentication with
402    * rest_proxy_auth_unpause() when everything is ready for it
403    * to continue.
404    **/
405   signals[AUTHENTICATE] =
406       g_signal_new ("authenticate",
407                     G_OBJECT_CLASS_TYPE (object_class),
408                     G_SIGNAL_RUN_LAST,
409                     G_STRUCT_OFFSET (RestProxyClass, authenticate),
410                     g_signal_accumulator_true_handled, NULL,
411                     g_cclosure_user_marshal_BOOLEAN__OBJECT_BOOLEAN,
412                     G_TYPE_BOOLEAN, 2,
413                     REST_TYPE_PROXY_AUTH,
414                     G_TYPE_BOOLEAN);
415 
416   proxy_class->authenticate = default_authenticate_cb;
417 }
418 
419 static void
rest_proxy_init(RestProxy * self)420 rest_proxy_init (RestProxy *self)
421 {
422   RestProxyPrivate *priv = GET_PRIVATE (self);
423 
424   priv->session = soup_session_async_new ();
425   priv->session_sync = soup_session_sync_new ();
426 
427 #ifdef REST_SYSTEM_CA_FILE
428   /* with ssl-strict (defaults TRUE) setting ssl-ca-file forces all
429    * certificates to be trusted */
430   g_object_set (priv->session,
431                 "ssl-ca-file", REST_SYSTEM_CA_FILE,
432                 NULL);
433   g_object_set (priv->session_sync,
434                 "ssl-ca-file", REST_SYSTEM_CA_FILE,
435                 NULL);
436 #endif
437   g_object_bind_property (self, "ssl-ca-file",
438                           priv->session, "ssl-ca-file",
439                           G_BINDING_BIDIRECTIONAL);
440   g_object_bind_property (self, "ssl-ca-file",
441                           priv->session_sync, "ssl-ca-file",
442                           G_BINDING_BIDIRECTIONAL);
443 
444 #if WITH_GNOME
445   soup_session_add_feature_by_type (priv->session,
446                                     SOUP_TYPE_PROXY_RESOLVER_GNOME);
447   soup_session_add_feature_by_type (priv->session_sync,
448                                     SOUP_TYPE_PROXY_RESOLVER_GNOME);
449 #endif
450 }
451 
452 /**
453  * rest_proxy_new:
454  * @url_format: the endpoint URL
455  * @binding_required: whether the URL needs to be bound before calling
456  *
457  * Create a new #RestProxy for the specified endpoint @url_format, using the
458  * "GET" method.
459  *
460  * Set @binding_required to %TRUE if the URL contains string formatting
461  * operations (for example "http://foo.com/%<!-- -->s".  These must be expanded
462  * using rest_proxy_bind() before invoking the proxy.
463  *
464  * Returns: A new #RestProxy.
465  */
466 RestProxy *
rest_proxy_new(const gchar * url_format,gboolean binding_required)467 rest_proxy_new (const gchar *url_format,
468                 gboolean     binding_required)
469 {
470   return g_object_new (REST_TYPE_PROXY,
471                        "url-format", url_format,
472                        "binding-required", binding_required,
473                        NULL);
474 }
475 
476 /**
477  * rest_proxy_new_with_authentication:
478  * @url_format: the endpoint URL
479  * @binding_required: whether the URL needs to be bound before calling
480  * @username: the username provided by the user or client
481  * @password: the password provided by the user or client
482  *
483  * Create a new #RestProxy for the specified endpoint @url_format, using the
484  * "GET" method.
485  *
486  * Set @binding_required to %TRUE if the URL contains string formatting
487  * operations (for example "http://foo.com/%<!-- -->s".  These must be expanded
488  * using rest_proxy_bind() before invoking the proxy.
489  *
490  * Returns: A new #RestProxy.
491  */
492 RestProxy *
rest_proxy_new_with_authentication(const gchar * url_format,gboolean binding_required,const gchar * username,const gchar * password)493 rest_proxy_new_with_authentication (const gchar *url_format,
494                                     gboolean     binding_required,
495                                     const gchar *username,
496                                     const gchar *password)
497 {
498   return g_object_new (REST_TYPE_PROXY,
499                        "url-format", url_format,
500                        "binding-required", binding_required,
501                        "username", username,
502                        "password", password,
503                        NULL);
504 }
505 
506 static gboolean
_rest_proxy_bind_valist(RestProxy * proxy,va_list params)507 _rest_proxy_bind_valist (RestProxy *proxy,
508                          va_list    params)
509 {
510   RestProxyPrivate *priv = GET_PRIVATE (proxy);
511 
512   g_return_val_if_fail (proxy != NULL, FALSE);
513   g_return_val_if_fail (priv->url_format != NULL, FALSE);
514   g_return_val_if_fail (priv->binding_required == TRUE, FALSE);
515 
516   g_free (priv->url);
517 
518   priv->url = g_strdup_vprintf (priv->url_format, params);
519 
520   return TRUE;
521 }
522 
523 
524 gboolean
rest_proxy_bind_valist(RestProxy * proxy,va_list params)525 rest_proxy_bind_valist (RestProxy *proxy,
526                         va_list    params)
527 {
528   RestProxyClass *proxy_class = REST_PROXY_GET_CLASS (proxy);
529 
530   return proxy_class->bind_valist (proxy, params);
531 }
532 
533 gboolean
rest_proxy_bind(RestProxy * proxy,...)534 rest_proxy_bind (RestProxy *proxy, ...)
535 {
536   g_return_val_if_fail (REST_IS_PROXY (proxy), FALSE);
537 
538   gboolean res;
539   va_list params;
540 
541   va_start (params, proxy);
542   res = rest_proxy_bind_valist (proxy, params);
543   va_end (params);
544 
545   return res;
546 }
547 
548 void
rest_proxy_set_user_agent(RestProxy * proxy,const char * user_agent)549 rest_proxy_set_user_agent (RestProxy  *proxy,
550                            const char *user_agent)
551 {
552   g_return_if_fail (REST_IS_PROXY (proxy));
553 
554   g_object_set (proxy, "user-agent", user_agent, NULL);
555 }
556 
557 const gchar *
rest_proxy_get_user_agent(RestProxy * proxy)558 rest_proxy_get_user_agent (RestProxy *proxy)
559 {
560   RestProxyPrivate *priv;
561 
562   g_return_val_if_fail (REST_IS_PROXY (proxy), NULL);
563 
564   priv = GET_PRIVATE (proxy);
565 
566   return priv->user_agent;
567 }
568 
569 /**
570  * rest_proxy_add_soup_feature:
571  * @proxy: The #RestProxy
572  * @feature: A #SoupSessionFeature
573  *
574  * This method can be used to add specific features to the #SoupSession objects
575  * that are used by librest for its HTTP connections. For example, if one needs
576  * extensive control over the cookies which are used for the REST HTTP
577  * communication, it's possible to get full access to libsoup cookie API by
578  * using
579  *
580  *   <programlisting>
581  *   RestProxy *proxy = g_object_new(REST_TYPE_PROXY,
582  *                                   "url-format", url,
583  *                                   "disable-cookies", TRUE,
584  *                                   NULL);
585  *   SoupSessionFeature *cookie_jar = SOUP_SESSION_FEATURE(soup_cookie_jar_new ());
586  *   rest_proxy_add_soup_feature(proxy, cookie_jar);
587  *   </programlisting>
588  *
589  * Since: 0.7.92
590  */
591 void
rest_proxy_add_soup_feature(RestProxy * proxy,SoupSessionFeature * feature)592 rest_proxy_add_soup_feature (RestProxy *proxy, SoupSessionFeature *feature)
593 {
594   RestProxyPrivate *priv;
595 
596   g_return_if_fail (REST_IS_PROXY(proxy));
597   priv = GET_PRIVATE (proxy);
598   g_return_if_fail (priv->session != NULL);
599   g_return_if_fail (priv->session_sync != NULL);
600 
601   soup_session_add_feature (priv->session, feature);
602   soup_session_add_feature (priv->session_sync, feature);
603 }
604 
605 static RestProxyCall *
_rest_proxy_new_call(RestProxy * proxy)606 _rest_proxy_new_call (RestProxy *proxy)
607 {
608   RestProxyCall *call;
609 
610   call = g_object_new (REST_TYPE_PROXY_CALL,
611                        "proxy", proxy,
612                        NULL);
613 
614   return call;
615 }
616 
617 /**
618  * rest_proxy_new_call:
619  * @proxy: the #RestProxy
620  *
621  * Create a new #RestProxyCall for making a call to the web service.  This call
622  * is one-shot and should not be re-used for making multiple calls.
623  *
624  * Returns: (transfer full): a new #RestProxyCall.
625  */
626 RestProxyCall *
rest_proxy_new_call(RestProxy * proxy)627 rest_proxy_new_call (RestProxy *proxy)
628 {
629   RestProxyClass *proxy_class = REST_PROXY_GET_CLASS (proxy);
630   return proxy_class->new_call (proxy);
631 }
632 
633 gboolean
_rest_proxy_get_binding_required(RestProxy * proxy)634 _rest_proxy_get_binding_required (RestProxy *proxy)
635 {
636   RestProxyPrivate *priv;
637 
638   g_return_val_if_fail (REST_IS_PROXY (proxy), FALSE);
639 
640   priv = GET_PRIVATE (proxy);
641 
642   return priv->binding_required;
643 }
644 
645 const gchar *
_rest_proxy_get_bound_url(RestProxy * proxy)646 _rest_proxy_get_bound_url (RestProxy *proxy)
647 {
648   RestProxyPrivate *priv;
649 
650   g_return_val_if_fail (REST_IS_PROXY (proxy), NULL);
651 
652   priv = GET_PRIVATE (proxy);
653 
654   if (!priv->url && !priv->binding_required)
655   {
656     priv->url = g_strdup (priv->url_format);
657   }
658 
659   return priv->url;
660 }
661 
662 static gboolean
_rest_proxy_simple_run_valist(RestProxy * proxy,gchar ** payload,goffset * len,GError ** error,va_list params)663 _rest_proxy_simple_run_valist (RestProxy *proxy,
664                                gchar     **payload,
665                                goffset   *len,
666                                GError   **error,
667                                va_list    params)
668 {
669   RestProxyCall *call;
670   gboolean ret;
671 
672   g_return_val_if_fail (REST_IS_PROXY (proxy), FALSE);
673   g_return_val_if_fail (payload, FALSE);
674 
675   call = rest_proxy_new_call (proxy);
676 
677   rest_proxy_call_add_params_from_valist (call, params);
678 
679   ret = rest_proxy_call_run (call, NULL, error);
680   if (ret) {
681     *payload = g_strdup (rest_proxy_call_get_payload (call));
682     if (len) *len = rest_proxy_call_get_payload_length (call);
683   } else {
684     *payload = NULL;
685     if (len) *len = 0;
686   }
687 
688   g_object_unref (call);
689 
690   return ret;
691 }
692 
693 gboolean
rest_proxy_simple_run_valist(RestProxy * proxy,char ** payload,goffset * len,GError ** error,va_list params)694 rest_proxy_simple_run_valist (RestProxy *proxy,
695                               char     **payload,
696                               goffset   *len,
697                               GError   **error,
698                               va_list    params)
699 {
700   RestProxyClass *proxy_class = REST_PROXY_GET_CLASS (proxy);
701   return proxy_class->simple_run_valist (proxy, payload, len, error, params);
702 }
703 
704 gboolean
rest_proxy_simple_run(RestProxy * proxy,gchar ** payload,goffset * len,GError ** error,...)705 rest_proxy_simple_run (RestProxy *proxy,
706                        gchar    **payload,
707                        goffset   *len,
708                        GError   **error,
709                        ...)
710 {
711   va_list params;
712   gboolean ret;
713 
714   g_return_val_if_fail (REST_IS_PROXY (proxy), FALSE);
715   g_return_val_if_fail (payload, FALSE);
716 
717   va_start (params, error);
718   ret = rest_proxy_simple_run_valist (proxy,
719                                       payload,
720                                       len,
721                                       error,
722                                       params);
723   va_end (params);
724 
725   return ret;
726 }
727 
728 void
_rest_proxy_queue_message(RestProxy * proxy,SoupMessage * message,SoupSessionCallback callback,gpointer user_data)729 _rest_proxy_queue_message (RestProxy   *proxy,
730                            SoupMessage *message,
731                            SoupSessionCallback callback,
732                            gpointer user_data)
733 {
734   RestProxyPrivate *priv;
735 
736   g_return_if_fail (REST_IS_PROXY (proxy));
737   g_return_if_fail (SOUP_IS_MESSAGE (message));
738 
739   priv = GET_PRIVATE (proxy);
740 
741   soup_session_queue_message (priv->session,
742                               message,
743                               callback,
744                               user_data);
745 }
746 
747 void
_rest_proxy_cancel_message(RestProxy * proxy,SoupMessage * message)748 _rest_proxy_cancel_message (RestProxy   *proxy,
749                             SoupMessage *message)
750 {
751   RestProxyPrivate *priv;
752 
753   g_return_if_fail (REST_IS_PROXY (proxy));
754   g_return_if_fail (SOUP_IS_MESSAGE (message));
755 
756   priv = GET_PRIVATE (proxy);
757   soup_session_cancel_message (priv->session,
758                                message,
759                                SOUP_STATUS_CANCELLED);
760 }
761 
762 guint
_rest_proxy_send_message(RestProxy * proxy,SoupMessage * message)763 _rest_proxy_send_message (RestProxy   *proxy,
764                           SoupMessage *message)
765 {
766   RestProxyPrivate *priv;
767 
768   g_return_val_if_fail (REST_IS_PROXY (proxy), 0);
769   g_return_val_if_fail (SOUP_IS_MESSAGE (message), 0);
770 
771   priv = GET_PRIVATE (proxy);
772 
773   return soup_session_send_message (priv->session_sync, message);
774 }
775