source: trunk/third/libsoup/libsoup/soup-connection.c @ 21519

Revision 21519, 20.9 KB checked in by ghudson, 20 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r21518, which included commits to RCS files with non-trunk default branches.
Line 
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2/*
3 * soup-connection.c: A single HTTP/HTTPS connection
4 *
5 * Copyright (C) 2000-2003, Ximian, Inc.
6 */
7
8#ifdef HAVE_CONFIG_H
9#include <config.h>
10#endif
11
12#include <unistd.h>
13#include <string.h>
14#include <stdlib.h>
15#include <glib.h>
16
17#include <fcntl.h>
18#include <sys/types.h>
19
20#include <sys/socket.h>
21#include <netinet/tcp.h>
22#include <netinet/in.h>
23
24#include "soup-address.h"
25#include "soup-connection.h"
26#include "soup-marshal.h"
27#include "soup-message.h"
28#include "soup-message-filter.h"
29#include "soup-misc.h"
30#include "soup-socket.h"
31#include "soup-ssl.h"
32#include "soup-uri.h"
33
34struct SoupConnectionPrivate {
35        SoupSocket  *socket;
36
37        /* proxy_uri is the URI of the proxy server we are connected
38         * to, if any. origin_uri is the URI of the origin server.
39         * conn_uri is the uri of the host we are actually directly
40         * connected to, which will be proxy_uri if there's a proxy
41         * and origin_uri if not.
42         */
43        SoupUri     *proxy_uri, *origin_uri, *conn_uri;
44        gpointer     ssl_creds;
45
46        SoupMessageFilter *filter;
47
48        SoupMessage *cur_req;
49        time_t       last_used;
50        gboolean     connected, in_use;
51};
52
53#define PARENT_TYPE G_TYPE_OBJECT
54static GObjectClass *parent_class;
55
56enum {
57        CONNECT_RESULT,
58        DISCONNECTED,
59        AUTHENTICATE,
60        REAUTHENTICATE,
61        LAST_SIGNAL
62};
63
64static guint signals[LAST_SIGNAL] = { 0 };
65
66enum {
67  PROP_0,
68
69  PROP_ORIGIN_URI,
70  PROP_PROXY_URI,
71  PROP_SSL_CREDS,
72  PROP_MESSAGE_FILTER,
73
74  LAST_PROP
75};
76
77static void set_property (GObject *object, guint prop_id,
78                          const GValue *value, GParamSpec *pspec);
79static void get_property (GObject *object, guint prop_id,
80                          GValue *value, GParamSpec *pspec);
81
82static void request_done (SoupMessage *req, gpointer user_data);
83static void send_request (SoupConnection *conn, SoupMessage *req);
84
85static void
86init (GObject *object)
87{
88        SoupConnection *conn = SOUP_CONNECTION (object);
89
90        conn->priv = g_new0 (SoupConnectionPrivate, 1);
91}
92
93static void
94finalize (GObject *object)
95{
96        SoupConnection *conn = SOUP_CONNECTION (object);
97
98        if (conn->priv->proxy_uri)
99                soup_uri_free (conn->priv->proxy_uri);
100        if (conn->priv->origin_uri)
101                soup_uri_free (conn->priv->origin_uri);
102
103        if (conn->priv->filter)
104                g_object_unref (conn->priv->filter);
105
106        g_free (conn->priv);
107
108        G_OBJECT_CLASS (parent_class)->finalize (object);
109}
110
111static void
112dispose (GObject *object)
113{
114        SoupConnection *conn = SOUP_CONNECTION (object);
115
116        if (conn->priv->cur_req)
117                request_done (conn->priv->cur_req, conn);
118        soup_connection_disconnect (conn);
119
120        G_OBJECT_CLASS (parent_class)->dispose (object);
121}
122
123static void
124class_init (GObjectClass *object_class)
125{
126        SoupConnectionClass *connection_class =
127                SOUP_CONNECTION_CLASS (object_class);
128
129        parent_class = g_type_class_ref (PARENT_TYPE);
130
131        /* virtual method definition */
132        connection_class->send_request = send_request;
133
134        /* virtual method override */
135        object_class->dispose = dispose;
136        object_class->finalize = finalize;
137        object_class->set_property = set_property;
138        object_class->get_property = get_property;
139
140        /* signals */
141        signals[CONNECT_RESULT] =
142                g_signal_new ("connect_result",
143                              G_OBJECT_CLASS_TYPE (object_class),
144                              G_SIGNAL_RUN_FIRST,
145                              G_STRUCT_OFFSET (SoupConnectionClass, connect_result),
146                              NULL, NULL,
147                              soup_marshal_NONE__INT,
148                              G_TYPE_NONE, 1,
149                              G_TYPE_INT);
150        signals[DISCONNECTED] =
151                g_signal_new ("disconnected",
152                              G_OBJECT_CLASS_TYPE (object_class),
153                              G_SIGNAL_RUN_FIRST,
154                              G_STRUCT_OFFSET (SoupConnectionClass, disconnected),
155                              NULL, NULL,
156                              soup_marshal_NONE__NONE,
157                              G_TYPE_NONE, 0);
158        signals[AUTHENTICATE] =
159                g_signal_new ("authenticate",
160                              G_OBJECT_CLASS_TYPE (object_class),
161                              G_SIGNAL_RUN_FIRST,
162                              G_STRUCT_OFFSET (SoupConnectionClass, authenticate),
163                              NULL, NULL,
164                              soup_marshal_NONE__OBJECT_STRING_STRING_POINTER_POINTER,
165                              G_TYPE_NONE, 5,
166                              SOUP_TYPE_MESSAGE,
167                              G_TYPE_STRING,
168                              G_TYPE_STRING,
169                              G_TYPE_POINTER,
170                              G_TYPE_POINTER);
171        signals[REAUTHENTICATE] =
172                g_signal_new ("reauthenticate",
173                              G_OBJECT_CLASS_TYPE (object_class),
174                              G_SIGNAL_RUN_FIRST,
175                              G_STRUCT_OFFSET (SoupConnectionClass, reauthenticate),
176                              NULL, NULL,
177                              soup_marshal_NONE__OBJECT_STRING_STRING_POINTER_POINTER,
178                              G_TYPE_NONE, 5,
179                              SOUP_TYPE_MESSAGE,
180                              G_TYPE_STRING,
181                              G_TYPE_STRING,
182                              G_TYPE_POINTER,
183                              G_TYPE_POINTER);
184
185        /* properties */
186        g_object_class_install_property (
187                object_class, PROP_ORIGIN_URI,
188                g_param_spec_pointer (SOUP_CONNECTION_ORIGIN_URI,
189                                      "Origin URI",
190                                      "The HTTP origin server to use for this connection",
191                                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
192        g_object_class_install_property (
193                object_class, PROP_PROXY_URI,
194                g_param_spec_pointer (SOUP_CONNECTION_PROXY_URI,
195                                      "Proxy URI",
196                                      "The HTTP Proxy to use for this connection",
197                                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
198        g_object_class_install_property (
199                object_class, PROP_SSL_CREDS,
200                g_param_spec_pointer (SOUP_CONNECTION_SSL_CREDENTIALS,
201                                      "SSL credentials",
202                                      "Opaque SSL credentials for this connection",
203                                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
204        g_object_class_install_property (
205                object_class, PROP_MESSAGE_FILTER,
206                g_param_spec_pointer (SOUP_CONNECTION_MESSAGE_FILTER,
207                                      "Message filter",
208                                      "Message filter object for this connection",
209                                      G_PARAM_READWRITE));
210}
211
212SOUP_MAKE_TYPE (soup_connection, SoupConnection, class_init, init, PARENT_TYPE)
213
214
215/**
216 * soup_connection_new:
217 * @propname1: name of first property to set
218 * @...:
219 *
220 * Creates an HTTP connection. You must set at least one of
221 * %SOUP_CONNECTION_ORIGIN_URI or %SOUP_CONNECTION_PROXY_URI. If you
222 * set an origin server URI but no proxy URI, this will be a direct
223 * connection. If you set a proxy URI and an https origin server URI,
224 * this will be a tunnel. Otherwise it will be an http proxy
225 * connection.
226 *
227 * You must call soup_connection_connect_async() or
228 * soup_connection_connect_sync() to connect it after creating it.
229 *
230 * Return value: the new connection (not yet ready for use).
231 **/
232SoupConnection *
233soup_connection_new (const char *propname1, ...)
234{
235        SoupConnection *conn;
236        va_list ap;
237
238        va_start (ap, propname1);
239        conn = (SoupConnection *)g_object_new_valist (SOUP_TYPE_CONNECTION,
240                                                      propname1, ap);
241        va_end (ap);
242
243        return conn;
244}
245
246static void
247set_property (GObject *object, guint prop_id,
248              const GValue *value, GParamSpec *pspec)
249{
250        SoupConnection *conn = SOUP_CONNECTION (object);
251        gpointer pval;
252
253        switch (prop_id) {
254        case PROP_ORIGIN_URI:
255                pval = g_value_get_pointer (value);
256                conn->priv->origin_uri = pval ? soup_uri_copy (pval) : NULL;
257                if (!conn->priv->proxy_uri)
258                        conn->priv->conn_uri = conn->priv->origin_uri;
259                break;
260        case PROP_PROXY_URI:
261                pval = g_value_get_pointer (value);
262                conn->priv->proxy_uri = pval ? soup_uri_copy (pval) : NULL;
263                if (conn->priv->proxy_uri)
264                        conn->priv->conn_uri = conn->priv->proxy_uri;
265                else
266                        conn->priv->conn_uri = conn->priv->origin_uri;
267                break;
268        case PROP_SSL_CREDS:
269                conn->priv->ssl_creds = g_value_get_pointer (value);
270                break;
271        case PROP_MESSAGE_FILTER:
272                conn->priv->filter = g_object_ref (g_value_get_pointer (value));
273                break;
274        default:
275                break;
276        }
277}
278
279static void
280get_property (GObject *object, guint prop_id,
281              GValue *value, GParamSpec *pspec)
282{
283        SoupConnection *conn = SOUP_CONNECTION (object);
284
285        switch (prop_id) {
286        case PROP_ORIGIN_URI:
287                g_value_set_pointer (value, conn->priv->origin_uri ?
288                                     soup_uri_copy (conn->priv->origin_uri) :
289                                     NULL);
290                break;
291        case PROP_PROXY_URI:
292                g_value_set_pointer (value, conn->priv->proxy_uri ?
293                                     soup_uri_copy (conn->priv->proxy_uri) :
294                                     NULL);
295        case PROP_SSL_CREDS:
296                g_value_set_pointer (value, conn->priv->ssl_creds);
297                break;
298        case PROP_MESSAGE_FILTER:
299                g_value_set_pointer (value, g_object_ref (conn->priv->filter));
300                break;
301        default:
302                break;
303        }
304}
305
306static void
307set_current_request (SoupConnection *conn, SoupMessage *req)
308{
309        g_return_if_fail (conn->priv->cur_req == NULL);
310
311        req->status = SOUP_MESSAGE_STATUS_RUNNING;
312        conn->priv->cur_req = req;
313        conn->priv->in_use = TRUE;
314        g_object_add_weak_pointer (G_OBJECT (req),
315                                   (gpointer *)conn->priv->cur_req);
316}
317
318static void
319clear_current_request (SoupConnection *conn)
320{
321        if (conn->priv->cur_req) {
322                g_object_remove_weak_pointer (G_OBJECT (conn->priv->cur_req),
323                                              (gpointer *)conn->priv->cur_req);
324                conn->priv->cur_req = NULL;
325        }
326        conn->priv->in_use = FALSE;
327}
328
329static void
330socket_disconnected (SoupSocket *sock, gpointer conn)
331{
332        soup_connection_disconnect (conn);
333}
334
335static inline guint
336proxified_status (SoupConnection *conn, guint status)
337{
338        if (!conn->priv->proxy_uri)
339                return status;
340
341        if (status == SOUP_STATUS_CANT_RESOLVE)
342                return SOUP_STATUS_CANT_RESOLVE_PROXY;
343        else if (status == SOUP_STATUS_CANT_CONNECT)
344                return SOUP_STATUS_CANT_CONNECT_PROXY;
345        else
346                return status;
347}
348
349static void
350tunnel_connect_finished (SoupMessage *msg, gpointer user_data)
351{
352        SoupConnection *conn = user_data;
353        guint status = msg->status_code;
354
355        clear_current_request (conn);
356
357        if (SOUP_STATUS_IS_SUCCESSFUL (status)) {
358                if (soup_socket_start_proxy_ssl (conn->priv->socket,
359                                                 conn->priv->origin_uri->host))
360                        conn->priv->connected = TRUE;
361                else
362                        status = SOUP_STATUS_SSL_FAILED;
363        } else if (SOUP_STATUS_IS_REDIRECTION (status)) {
364                /* Oops, the proxy thinks we're a web browser. */
365                status = SOUP_STATUS_PROXY_AUTHENTICATION_REQUIRED;
366        }
367
368        g_signal_emit (conn, signals[CONNECT_RESULT], 0,
369                       proxified_status (conn, status));
370        g_object_unref (msg);
371}
372
373static void
374tunnel_connect_restarted (SoupMessage *msg, gpointer user_data)
375{
376        SoupConnection *conn = user_data;
377        guint status = msg->status_code;
378
379        /* We only allow one restart: if another one happens, treat
380         * it as "finished".
381         */
382        g_signal_handlers_disconnect_by_func (msg, tunnel_connect_restarted, conn);
383        g_signal_connect (msg, "restarted",
384                          G_CALLBACK (tunnel_connect_finished), conn);
385
386        if (status == SOUP_STATUS_PROXY_AUTHENTICATION_REQUIRED) {
387                /* Our parent session has handled the authentication
388                 * and attempted to restart the message.
389                 */
390                if (soup_message_is_keepalive (msg)) {
391                        /* Connection is still open, so just send the
392                         * message again.
393                         */
394                        soup_connection_send_request (conn, msg);
395                } else {
396                        /* Tell the session to try again. */
397                        soup_message_set_status (msg, SOUP_STATUS_TRY_AGAIN);
398                        soup_message_finished (msg);
399                }
400        } else
401                soup_message_finished (msg);
402}
403
404static void
405socket_connect_result (SoupSocket *sock, guint status, gpointer user_data)
406{
407        SoupConnection *conn = user_data;
408
409        if (!SOUP_STATUS_IS_SUCCESSFUL (status))
410                goto done;
411
412        if (conn->priv->conn_uri->protocol == SOUP_PROTOCOL_HTTPS) {
413                if (!soup_socket_start_ssl (sock)) {
414                        status = SOUP_STATUS_SSL_FAILED;
415                        goto done;
416                }
417        }
418
419        /* See if we need to tunnel */
420        if (conn->priv->proxy_uri &&
421            conn->priv->origin_uri &&
422            conn->priv->origin_uri->protocol == SOUP_PROTOCOL_HTTPS) {
423                SoupMessage *connect_msg;
424
425                connect_msg = soup_message_new_from_uri (SOUP_METHOD_CONNECT,
426                                                         conn->priv->origin_uri);
427
428                g_signal_connect (connect_msg, "restarted",
429                                  G_CALLBACK (tunnel_connect_restarted), conn);
430                g_signal_connect (connect_msg, "finished",
431                                  G_CALLBACK (tunnel_connect_finished), conn);
432
433                soup_connection_send_request (conn, connect_msg);
434                return;
435        }
436
437        conn->priv->connected = TRUE;
438
439 done:
440        g_signal_emit (conn, signals[CONNECT_RESULT], 0,
441                       proxified_status (conn, status));
442}
443
444/**
445 * soup_connection_connect_async:
446 * @conn: the connection
447 * @callback: callback to call when the connection succeeds or fails
448 * @user_data: data for @callback
449 *
450 * Asynchronously connects @conn.
451 **/
452void
453soup_connection_connect_async (SoupConnection *conn,
454                               SoupConnectionCallback callback,
455                               gpointer user_data)
456{
457        g_return_if_fail (SOUP_IS_CONNECTION (conn));
458        g_return_if_fail (conn->priv->socket == NULL);
459
460        if (callback) {
461                soup_signal_connect_once (conn, "connect_result",
462                                          G_CALLBACK (callback), user_data);
463        }
464
465        conn->priv->socket =
466                soup_socket_client_new_async (conn->priv->conn_uri->host,
467                                              conn->priv->conn_uri->port,
468                                              conn->priv->ssl_creds,
469                                              socket_connect_result, conn);
470        g_signal_connect (conn->priv->socket, "disconnected",
471                          G_CALLBACK (socket_disconnected), conn);
472}
473
474/**
475 * soup_connection_connect_sync:
476 * @conn: the connection
477 *
478 * Synchronously connects @conn.
479 *
480 * Return value: the soup status
481 **/
482guint
483soup_connection_connect_sync (SoupConnection *conn)
484{
485        guint status;
486
487        g_return_val_if_fail (SOUP_IS_CONNECTION (conn), SOUP_STATUS_MALFORMED);
488        g_return_val_if_fail (conn->priv->socket == NULL, SOUP_STATUS_MALFORMED);
489
490        conn->priv->socket =
491                soup_socket_client_new_sync (conn->priv->conn_uri->host,
492                                             conn->priv->conn_uri->port,
493                                             conn->priv->ssl_creds,
494                                             &status);
495
496        if (!SOUP_STATUS_IS_SUCCESSFUL (status))
497                goto fail;
498
499        g_signal_connect (conn->priv->socket, "disconnected",
500                          G_CALLBACK (socket_disconnected), conn);
501
502        if (conn->priv->conn_uri->protocol == SOUP_PROTOCOL_HTTPS) {
503                if (!soup_socket_start_ssl (conn->priv->socket)) {
504                        status = SOUP_STATUS_SSL_FAILED;
505                        goto fail;
506                }
507        }
508
509        /* See if we need to tunnel */
510        if (conn->priv->proxy_uri &&
511            conn->priv->origin_uri &&
512            conn->priv->origin_uri->protocol == SOUP_PROTOCOL_HTTPS) {
513                SoupMessage *connect_msg;
514
515                connect_msg = soup_message_new_from_uri (SOUP_METHOD_CONNECT,
516                                                         conn->priv->origin_uri);
517                soup_connection_send_request (conn, connect_msg);
518                status = connect_msg->status_code;
519
520                if (status == SOUP_STATUS_PROXY_AUTHENTICATION_REQUIRED &&
521                    SOUP_MESSAGE_IS_STARTING (connect_msg)) {
522                        if (soup_message_is_keepalive (connect_msg)) {
523                                /* Try once more */
524                                soup_connection_send_request (conn, connect_msg);
525                                status = connect_msg->status_code;
526                        } else
527                                status = SOUP_STATUS_TRY_AGAIN;
528                }
529
530                g_object_unref (connect_msg);
531        }
532
533        if (SOUP_STATUS_IS_SUCCESSFUL (status))
534                conn->priv->connected = TRUE;
535        else {
536        fail:
537                if (conn->priv->socket) {
538                        g_object_unref (conn->priv->socket);
539                        conn->priv->socket = NULL;
540                }
541        }
542
543        status = proxified_status (conn, status);
544        g_signal_emit (conn, signals[CONNECT_RESULT], 0, status);
545        return status;
546}
547
548
549/**
550 * soup_connection_disconnect:
551 * @conn: a connection
552 *
553 * Disconnects @conn's socket and emits a %disconnected signal.
554 * After calling this, @conn will be essentially useless.
555 **/
556void
557soup_connection_disconnect (SoupConnection *conn)
558{
559        g_return_if_fail (SOUP_IS_CONNECTION (conn));
560
561        if (!conn->priv->socket)
562                return;
563
564        g_signal_handlers_disconnect_by_func (conn->priv->socket,
565                                              socket_disconnected, conn);
566        soup_socket_disconnect (conn->priv->socket);
567        g_object_unref (conn->priv->socket);
568        conn->priv->socket = NULL;
569
570        /* Don't emit "disconnected" if we aren't yet connected */
571        if (!conn->priv->connected)
572                return;
573
574        conn->priv->connected = FALSE;
575        g_signal_emit (conn, signals[DISCONNECTED], 0);
576
577        if (!conn->priv->cur_req ||
578            conn->priv->cur_req->status_code != SOUP_STATUS_IO_ERROR)
579                return;
580
581        /* There was a message queued on this connection, but the
582         * socket was closed while it was being sent.
583         */
584
585        if (conn->priv->last_used != 0) {
586                /* If last_used is not 0, then that means at least one
587                 * message was successfully sent on this connection
588                 * before, and so the most likely cause of the
589                 * IO_ERROR is that the connection was idle for too
590                 * long and the server timed out and closed it (and we
591                 * didn't notice until after we started sending the
592                 * message). So we want the message to get tried again
593                 * on a new connection. The only code path that could
594                 * have gotten us to this point is through the call to
595                 * io_cleanup() in soup_message_io_finished(), and so
596                 * all we need to do to get the message requeued in
597                 * this case is to change its status.
598                 */
599                conn->priv->cur_req->status = SOUP_MESSAGE_STATUS_QUEUED;
600                return;
601        }
602
603        /* If conn->priv->last_used is 0, then that means this was the
604         * first message to be sent on this connection, so the error
605         * probably means that there's some network or server problem,
606         * so we let the IO_ERROR be returned to the caller.
607         *
608         * Of course, it's also possible that the error in the
609         * last_used != 0 case was because of a network/server problem
610         * too. It's even possible that the message crashed the
611         * server. In this case, requeuing it was the wrong thing to
612         * do, but presumably, the next attempt will also get an
613         * error, and eventually the message will be requeued onto a
614         * fresh connection and get an error, at which point the error
615         * will finally be returned to the caller.
616         */
617}
618
619/**
620 * soup_connection_is_in_use:
621 * @conn: a connection
622 *
623 * Tests whether or not @conn is in use.
624 *
625 * Return value: %TRUE if there is currently a request being processed
626 * on @conn.
627 **/
628gboolean
629soup_connection_is_in_use (SoupConnection *conn)
630{
631        g_return_val_if_fail (SOUP_IS_CONNECTION (conn), FALSE);
632
633        return conn->priv->in_use;
634}
635
636/**
637 * soup_connection_last_used:
638 * @conn: a #SoupConnection.
639 *
640 * Returns the last time a response was received on @conn.
641 *
642 * Return value: the last time a response was received on @conn, or 0
643 * if @conn has not been used yet.
644 */
645time_t
646soup_connection_last_used (SoupConnection *conn)
647{
648        g_return_val_if_fail (SOUP_IS_CONNECTION (conn), FALSE);
649
650        return conn->priv->last_used;
651}
652
653static void
654request_restarted (SoupMessage *req, gpointer conn)
655{
656        if (!soup_message_is_keepalive (req))
657                soup_connection_disconnect (conn);
658}
659
660static void
661request_done (SoupMessage *req, gpointer user_data)
662{
663        SoupConnection *conn = user_data;
664
665        clear_current_request (conn);
666        conn->priv->last_used = time (NULL);
667
668        if (!soup_message_is_keepalive (req))
669                soup_connection_disconnect (conn);
670
671        g_signal_handlers_disconnect_by_func (req, request_done, conn);
672        g_signal_handlers_disconnect_by_func (req, request_restarted, conn);
673        g_object_unref (conn);
674}
675
676static void
677send_request (SoupConnection *conn, SoupMessage *req)
678{
679        g_object_ref (conn);
680
681        if (req != conn->priv->cur_req) {
682                set_current_request (conn, req);
683
684                g_signal_connect (req, "restarted",
685                                  G_CALLBACK (request_restarted), conn);
686                g_signal_connect (req, "finished",
687                                  G_CALLBACK (request_done), conn);
688
689                if (conn->priv->filter)
690                        soup_message_filter_setup_message (conn->priv->filter, req);
691        }
692
693        soup_message_send_request (req, conn->priv->socket,
694                                   conn->priv->proxy_uri != NULL);
695}
696
697/**
698 * soup_connection_send_request:
699 * @conn: a #SoupConnection
700 * @req: a #SoupMessage
701 *
702 * Sends @req on @conn. This is a low-level function, intended for use
703 * by #SoupSession.
704 **/
705void
706soup_connection_send_request (SoupConnection *conn, SoupMessage *req)
707{
708        g_return_if_fail (SOUP_IS_CONNECTION (conn));
709        g_return_if_fail (SOUP_IS_MESSAGE (req));
710        g_return_if_fail (conn->priv->socket != NULL);
711
712        SOUP_CONNECTION_GET_CLASS (conn)->send_request (conn, req);
713}
714
715/**
716 * soup_connection_reserve:
717 * @conn: a #SoupConnection
718 *
719 * Marks @conn as "in use" despite not actually having a message on
720 * it. This is used by #SoupSession to keep it from accidentally
721 * trying to queue two messages on the same connection from different
722 * threads at the same time.
723 **/
724void
725soup_connection_reserve (SoupConnection *conn)
726{
727        g_return_if_fail (SOUP_IS_CONNECTION (conn));
728
729        conn->priv->in_use = TRUE;
730}
731
732/**
733 * soup_connection_release:
734 * @conn: a #SoupConnection
735 *
736 * Marks @conn as not "in use". This can be used to cancel the effect
737 * of a soup_session_reserve(). It is not necessary to call this
738 * after soup_connection_send_request().
739 **/
740void
741soup_connection_release (SoupConnection *conn)
742{
743        g_return_if_fail (SOUP_IS_CONNECTION (conn));
744
745        conn->priv->in_use = FALSE;
746}
747
748/**
749 * soup_connection_authenticate:
750 * @conn: a #SoupConnection
751 * @msg: the message to authenticate
752 * @auth_type: type of authentication to use
753 * @auth_realm: authentication realm
754 * @username: on successful return, will contain the username to
755 * authenticate with
756 * @password: on successful return, will contain the password to
757 * authenticate with
758 *
759 * Emits the %authenticate signal on @conn. For use by #SoupConnection
760 * subclasses.
761 **/
762void
763soup_connection_authenticate (SoupConnection *conn, SoupMessage *msg,
764                              const char *auth_type, const char *auth_realm,
765                              char **username, char **password)
766{
767        g_signal_emit (conn, signals[AUTHENTICATE], 0,
768                       msg, auth_type, auth_realm, username, password);
769}
770
771/**
772 * soup_connection_reauthenticate:
773 * @conn: a #SoupConnection
774 * @msg: the message to authenticate
775 * @auth_type: type of authentication to use
776 * @auth_realm: authentication realm
777 * @username: on successful return, will contain the username to
778 * authenticate with
779 * @password: on successful return, will contain the password to
780 * authenticate with
781 *
782 * Emits the %reauthenticate signal on @conn. For use by
783 * #SoupConnection subclasses.
784 **/
785void
786soup_connection_reauthenticate (SoupConnection *conn, SoupMessage *msg,
787                                const char *auth_type, const char *auth_realm,
788                                char **username, char **password)
789{
790        g_signal_emit (conn, signals[REAUTHENTICATE], 0,
791                       msg, auth_type, auth_realm, username, password);
792}
Note: See TracBrowser for help on using the repository browser.