~ubuntu-branches/ubuntu/jaunty/libsoup2.4/jaunty-proposed

« back to all changes in this revision

Viewing changes to libsoup/soup-session.c

  • Committer: Bazaar Package Importer
  • Author(s): Sebastien Bacher
  • Date: 2008-12-17 14:51:11 UTC
  • mfrom: (1.1.12 upstream)
  • Revision ID: james.westby@ubuntu.com-20081217145111-sqbz10l57fmrh4vz
Tags: 2.25.4-0ubuntu1
* New upstream version
* debian/control.in:
  - build-depends on libgconf2-dev, libproxy-dev
* Updated to list the new libsoup-gnome binaries
* debian/rules:
  - updated shlibs version and list the new library

Show diffs side-by-side

added added

removed removed

Lines of Context:
13
13
#include <string.h>
14
14
#include <stdlib.h>
15
15
 
 
16
#include "soup-address.h"
16
17
#include "soup-auth.h"
17
18
#include "soup-auth-basic.h"
18
19
#include "soup-auth-digest.h"
21
22
#include "soup-marshal.h"
22
23
#include "soup-message-private.h"
23
24
#include "soup-message-queue.h"
 
25
#include "soup-proxy-resolver-static.h"
24
26
#include "soup-session.h"
25
27
#include "soup-session-feature.h"
26
28
#include "soup-session-private.h"
55
57
 **/
56
58
 
57
59
typedef struct {
58
 
        SoupURI    *root_uri;
59
 
 
60
 
        GSList     *connections;      /* CONTAINS: SoupConnection */
61
 
        guint       num_conns;
62
 
 
63
 
        GHashTable *auth_realms;      /* path -> scheme:realm */
64
 
        GHashTable *auths;            /* scheme:realm -> SoupAuth */
 
60
        SoupAddress *addr;
 
61
 
 
62
        GSList      *connections;      /* CONTAINS: SoupConnection */
 
63
        guint        num_conns;
65
64
} SoupSessionHost;
66
65
 
67
66
typedef struct {
68
 
        SoupURI *proxy_uri;
69
 
        SoupAuth *proxy_auth;
 
67
        SoupProxyResolver *proxy_resolver;
70
68
 
71
69
        char *ssl_ca_file;
72
70
        SoupSSLCredentials *ssl_creds;
78
76
        GSList *features;
79
77
        SoupAuthManager *auth_manager;
80
78
 
81
 
        GHashTable *hosts; /* SoupURI -> SoupSessionHost */
 
79
        GHashTable *hosts; /* SoupAddress -> SoupSessionHost */
82
80
        GHashTable *conns; /* SoupConnection -> SoupSessionHost */
83
81
        guint num_conns;
84
82
        guint max_conns, max_conns_per_host;
106
104
                                       SoupMessage *msg, SoupAuth *auth,
107
105
                                       gboolean retrying, gpointer user_data);
108
106
 
109
 
/* temporary until we fix this to index hosts by SoupAddress */
110
 
extern guint     soup_uri_host_hash  (gconstpointer  key);
111
 
extern gboolean  soup_uri_host_equal (gconstpointer  v1,
112
 
                                      gconstpointer  v2);
113
 
extern SoupURI  *soup_uri_copy_root  (SoupURI *uri);
114
 
 
115
107
#define SOUP_SESSION_MAX_CONNS_DEFAULT 10
116
108
#define SOUP_SESSION_MAX_CONNS_PER_HOST_DEFAULT 2
117
109
 
158
150
{
159
151
        SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
160
152
 
161
 
        priv->queue = soup_message_queue_new ();
 
153
        priv->queue = soup_message_queue_new (session);
162
154
 
163
155
        priv->host_lock = g_mutex_new ();
164
 
        priv->hosts = g_hash_table_new (soup_uri_host_hash,
165
 
                                        soup_uri_host_equal);
 
156
        priv->hosts = g_hash_table_new (soup_address_hash_by_ip,
 
157
                                        soup_address_equal_by_ip);
166
158
        priv->conns = g_hash_table_new (NULL, NULL);
167
159
 
168
160
        priv->max_conns = SOUP_SESSION_MAX_CONNS_DEFAULT;
192
184
 
193
185
        g_mutex_lock (priv->host_lock);
194
186
        old_hosts = priv->hosts;
195
 
        priv->hosts = g_hash_table_new (soup_uri_host_hash,
196
 
                                        soup_uri_host_equal);
 
187
        priv->hosts = g_hash_table_new (soup_address_hash_by_ip,
 
188
                                        soup_address_equal_by_ip);
197
189
        g_mutex_unlock (priv->host_lock);
198
190
 
199
191
        g_hash_table_foreach_remove (old_hosts, foreach_free_host, NULL);
232
224
        if (priv->auth_manager)
233
225
                g_object_unref (priv->auth_manager);
234
226
 
235
 
        if (priv->proxy_uri)
236
 
                soup_uri_free (priv->proxy_uri);
237
 
 
238
227
        if (priv->ssl_creds)
239
228
                soup_ssl_free_client_credentials (priv->ssl_creds);
240
229
 
511
500
}
512
501
 
513
502
static gboolean
514
 
safe_uri_equal (SoupURI *a, SoupURI *b)
515
 
{
516
 
        if (!a && !b)
517
 
                return TRUE;
518
 
 
519
 
        if ((a && !b) || (b && !a))
520
 
                return FALSE;
521
 
 
522
 
        return soup_uri_equal (a, b);
523
 
}
524
 
 
525
 
static gboolean
526
503
safe_str_equal (const char *a, const char *b)
527
504
{
528
505
        if (!a && !b)
541
518
        SoupSession *session = SOUP_SESSION (object);
542
519
        SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
543
520
        SoupURI *uri;
544
 
        gboolean need_abort = FALSE;
545
521
        gboolean ca_file_changed = FALSE;
546
522
        const char *new_ca_file, *user_agent;
547
523
 
549
525
        case PROP_PROXY_URI:
550
526
                uri = g_value_get_boxed (value);
551
527
 
552
 
                if (!safe_uri_equal (priv->proxy_uri, uri))
553
 
                        need_abort = TRUE;
554
 
 
555
 
                if (priv->proxy_uri)
556
 
                        soup_uri_free (priv->proxy_uri);
557
 
 
558
 
                priv->proxy_uri = uri ? soup_uri_copy (uri) : NULL;
559
 
 
560
 
                if (need_abort) {
561
 
                        soup_session_abort (session);
562
 
                        cleanup_hosts (priv);
563
 
                }
564
 
 
 
528
                if (uri) {
 
529
                        soup_session_remove_feature_by_type (session, SOUP_TYPE_PROXY_RESOLVER);
 
530
                        priv->proxy_resolver = soup_proxy_resolver_static_new (uri);
 
531
                        soup_session_add_feature (session, SOUP_SESSION_FEATURE (priv->proxy_resolver));
 
532
                        g_object_unref (priv->proxy_resolver);
 
533
                } else if (priv->proxy_resolver && SOUP_IS_PROXY_RESOLVER_STATIC (priv->proxy_resolver))
 
534
                        soup_session_remove_feature_by_type (session, SOUP_TYPE_PROXY_RESOLVER);
 
535
 
 
536
                soup_session_abort (session);
 
537
                cleanup_hosts (priv);
565
538
                break;
566
539
        case PROP_MAX_CONNS:
567
540
                priv->max_conns = g_value_get_int (value);
643
616
 
644
617
        switch (prop_id) {
645
618
        case PROP_PROXY_URI:
646
 
                g_value_set_boxed (value, priv->proxy_uri);
 
619
                if (priv->proxy_resolver && SOUP_IS_PROXY_RESOLVER_STATIC (priv->proxy_resolver)) {
 
620
                        g_object_get_property (G_OBJECT (priv->proxy_resolver),
 
621
                                               SOUP_PROXY_RESOLVER_STATIC_PROXY_URI,
 
622
                                               value);
 
623
                } else
 
624
                        g_value_set_boxed (value, NULL);
647
625
                break;
648
626
        case PROP_MAX_CONNS:
649
627
                g_value_set_int (value, priv->max_conns);
702
680
/* Hosts */
703
681
 
704
682
static SoupSessionHost *
705
 
soup_session_host_new (SoupSession *session, SoupURI *source_uri)
 
683
soup_session_host_new (SoupSession *session, SoupAddress *addr)
706
684
{
707
 
        SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
708
685
        SoupSessionHost *host;
709
686
 
710
687
        host = g_slice_new0 (SoupSessionHost);
711
 
        host->root_uri = soup_uri_copy_root (source_uri);
712
 
 
713
 
        if (host->root_uri->scheme == SOUP_URI_SCHEME_HTTPS &&
714
 
            !priv->ssl_creds) {
715
 
                priv->ssl_creds =
716
 
                        soup_ssl_get_client_credentials (priv->ssl_ca_file);
717
 
        }
718
 
 
 
688
        host->addr = g_object_ref (addr);
719
689
        return host;
720
690
}
721
691
 
728
698
{
729
699
        SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
730
700
        SoupSessionHost *host;
731
 
        SoupURI *source = soup_message_get_uri (msg);
 
701
        SoupAddress *addr = soup_message_get_address (msg);
732
702
 
733
 
        host = g_hash_table_lookup (priv->hosts, source);
 
703
        host = g_hash_table_lookup (priv->hosts, addr);
734
704
        if (host)
735
705
                return host;
736
706
 
737
 
        host = soup_session_host_new (session, source);
738
 
        g_hash_table_insert (priv->hosts, host->root_uri, host);
 
707
        host = soup_session_host_new (session, addr);
 
708
        g_hash_table_insert (priv->hosts, host->addr, host);
739
709
 
740
710
        return host;
741
711
}
750
720
                soup_connection_disconnect (conn);
751
721
        }
752
722
 
753
 
        soup_uri_free (host->root_uri);
 
723
        g_object_unref (host->addr);
754
724
        g_slice_free (SoupSessionHost, host);
755
725
}       
756
726
 
920
890
        SoupSession *session = user_data;
921
891
        SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
922
892
        SoupSessionHost *host;
923
 
        SoupMessageQueueIter iter;
 
893
        SoupMessageQueueItem *item;
924
894
        SoupMessage *msg;
925
895
 
926
896
        g_mutex_lock (priv->host_lock);
961
931
         * of luck.
962
932
         */
963
933
        g_object_ref (session);
964
 
        for (msg = soup_message_queue_first (priv->queue, &iter); msg; msg = soup_message_queue_next (priv->queue, &iter)) {
 
934
        for (item = soup_message_queue_first (priv->queue); item; item = soup_message_queue_next (priv->queue, item)) {
 
935
                msg = item->msg;
965
936
                if (get_host_for_message (session, msg) == host) {
966
937
                        if (status == SOUP_STATUS_TRY_AGAIN) {
967
938
                                if (soup_message_get_io_status (msg) == SOUP_MESSAGE_IO_STATUS_CONNECTING)
1015
986
 **/
1016
987
SoupConnection *
1017
988
soup_session_get_connection (SoupSession *session, SoupMessage *msg,
 
989
                             SoupAddress *proxy_addr,
1018
990
                             gboolean *try_pruning, gboolean *is_new)
1019
991
{
1020
992
        SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
1021
993
        SoupConnection *conn;
1022
994
        SoupSessionHost *host;
 
995
        SoupSSLCredentials *ssl_creds;
1023
996
        GSList *conns;
 
997
        SoupURI *uri;
1024
998
 
1025
999
        g_mutex_lock (priv->host_lock);
1026
1000
 
1053
1027
                return NULL;
1054
1028
        }
1055
1029
 
 
1030
        uri = soup_message_get_uri (msg);
 
1031
        if (uri->scheme == SOUP_URI_SCHEME_HTTPS) {
 
1032
                if (!priv->ssl_creds)
 
1033
                        priv->ssl_creds = soup_ssl_get_client_credentials (priv->ssl_ca_file);
 
1034
                ssl_creds = priv->ssl_creds;
 
1035
        } else
 
1036
                ssl_creds = NULL;
 
1037
 
1056
1038
        conn = soup_connection_new (
1057
 
                SOUP_CONNECTION_ORIGIN_URI, host->root_uri,
1058
 
                SOUP_CONNECTION_PROXY_URI, priv->proxy_uri,
1059
 
                SOUP_CONNECTION_SSL_CREDENTIALS, priv->ssl_creds,
 
1039
                SOUP_CONNECTION_SERVER_ADDRESS, host->addr,
 
1040
                SOUP_CONNECTION_PROXY_ADDRESS, proxy_addr,
 
1041
                SOUP_CONNECTION_SSL_CREDENTIALS, ssl_creds,
1060
1042
                SOUP_CONNECTION_ASYNC_CONTEXT, priv->async_context,
1061
1043
                SOUP_CONNECTION_TIMEOUT, priv->io_timeout,
1062
1044
                SOUP_CONNECTION_IDLE_TIMEOUT, priv->idle_timeout,
1101
1083
static void
1102
1084
message_finished (SoupMessage *msg, gpointer user_data)
1103
1085
{
1104
 
        SoupSession *session = user_data;
 
1086
        SoupMessageQueueItem *item = user_data;
 
1087
        SoupSession *session = item->session;
1105
1088
        SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
1106
1089
 
1107
1090
        if (!SOUP_MESSAGE_IS_STARTING (msg)) {
1108
 
                soup_message_queue_remove_message (priv->queue, msg);
1109
 
                g_signal_handlers_disconnect_by_func (msg, message_finished, session);
1110
 
                g_signal_handlers_disconnect_by_func (msg, redirect_handler, session);
 
1091
                soup_message_queue_remove (priv->queue, item);
 
1092
                g_signal_handlers_disconnect_by_func (msg, message_finished, item);
 
1093
                /* g_signal_handlers_disconnect_by_func doesn't work if you
 
1094
                 * have a metamarshal, meaning it doesn't work with
 
1095
                 * soup_message_add_header_handler()
 
1096
                 */
 
1097
                g_signal_handlers_disconnect_matched (msg, G_SIGNAL_MATCH_DATA,
 
1098
                                                      0, 0, NULL, NULL, session);
1111
1099
                g_signal_emit (session, signals[REQUEST_UNQUEUED], 0, msg);
 
1100
                soup_message_queue_item_unref (item);
1112
1101
        }
1113
1102
}
1114
1103
 
1117
1106
               SoupSessionCallback callback, gpointer user_data)
1118
1107
{
1119
1108
        SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
 
1109
        SoupMessageQueueItem *item;
 
1110
 
 
1111
        item = soup_message_queue_append (priv->queue, msg, callback, user_data);
 
1112
        soup_message_set_io_status (msg, SOUP_MESSAGE_IO_STATUS_QUEUED);
1120
1113
 
1121
1114
        g_signal_connect_after (msg, "finished",
1122
 
                                G_CALLBACK (message_finished), session);
 
1115
                                G_CALLBACK (message_finished), item);
1123
1116
 
1124
1117
        if (!(soup_message_get_flags (msg) & SOUP_MESSAGE_NO_REDIRECT)) {
1125
1118
                soup_message_add_header_handler (
1127
1120
                        G_CALLBACK (redirect_handler), session);
1128
1121
        }
1129
1122
 
1130
 
        soup_message_set_io_status (msg, SOUP_MESSAGE_IO_STATUS_QUEUED);
1131
 
        soup_message_queue_append (priv->queue, msg);
1132
 
 
1133
1123
        g_signal_emit (session, signals[REQUEST_QUEUED], 0, msg);
1134
1124
}
1135
1125
 
1263
1253
cancel_message (SoupSession *session, SoupMessage *msg, guint status_code)
1264
1254
{
1265
1255
        SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
1266
 
 
1267
 
        soup_message_queue_remove_message (priv->queue, msg);
 
1256
        SoupMessageQueueItem *item;
 
1257
 
 
1258
        item = soup_message_queue_lookup (priv->queue, msg);
 
1259
        if (item) {
 
1260
                if (item->cancellable)
 
1261
                        g_cancellable_cancel (item->cancellable);
 
1262
                soup_message_queue_item_unref (item);
 
1263
        }
 
1264
 
1268
1265
        soup_message_io_stop (msg);
1269
1266
        soup_message_set_status (msg, status_code);
1270
1267
        soup_message_finished (msg);
1297
1294
        SoupConnection *conn = key;
1298
1295
        GSList **conns = data;
1299
1296
 
1300
 
        *conns = g_slist_prepend (*conns, conn);
 
1297
        *conns = g_slist_prepend (*conns, g_object_ref (conn));
1301
1298
}
1302
1299
 
1303
1300
/**
1310
1307
soup_session_abort (SoupSession *session)
1311
1308
{
1312
1309
        SoupSessionPrivate *priv;
1313
 
        SoupMessageQueueIter iter;
1314
 
        SoupMessage *msg;
 
1310
        SoupMessageQueueItem *item;
1315
1311
        GSList *conns, *c;
1316
1312
 
1317
1313
        g_return_if_fail (SOUP_IS_SESSION (session));
1318
1314
        priv = SOUP_SESSION_GET_PRIVATE (session);
1319
1315
 
1320
 
        for (msg = soup_message_queue_first (priv->queue, &iter);
1321
 
             msg;
1322
 
             msg = soup_message_queue_next (priv->queue, &iter)) {
1323
 
                soup_session_cancel_message (session, msg,
 
1316
        for (item = soup_message_queue_first (priv->queue);
 
1317
             item;
 
1318
             item = soup_message_queue_next (priv->queue, item)) {
 
1319
                soup_session_cancel_message (session, item->msg,
1324
1320
                                             SOUP_STATUS_CANCELLED);
1325
1321
        }
1326
1322
 
1329
1325
        conns = NULL;
1330
1326
        g_hash_table_foreach (priv->conns, gather_conns, &conns);
1331
1327
 
1332
 
        for (c = conns; c; c = c->next)
1333
 
                g_object_ref (c->data);
1334
1328
        g_mutex_unlock (priv->host_lock);
1335
1329
        for (c = conns; c; c = c->next) {
1336
1330
                soup_connection_disconnect (c->data);
1360
1354
        priv = SOUP_SESSION_GET_PRIVATE (session);
1361
1355
        priv->features = g_slist_prepend (priv->features, g_object_ref (feature));
1362
1356
        soup_session_feature_attach (feature, session);
 
1357
 
 
1358
        if (SOUP_IS_PROXY_RESOLVER (feature))
 
1359
                priv->proxy_resolver = SOUP_PROXY_RESOLVER (feature);
1363
1360
}
1364
1361
 
1365
1362
/**
1405
1402
                priv->features = g_slist_remove (priv->features, feature);
1406
1403
                soup_session_feature_detach (feature, session);
1407
1404
                g_object_unref (feature);
 
1405
 
 
1406
                if (feature == (SoupSessionFeature *)priv->proxy_resolver)
 
1407
                        priv->proxy_resolver = NULL;
1408
1408
        }
1409
1409
}
1410
1410
 
1435
1435
                }
1436
1436
        }
1437
1437
}
 
1438
 
 
1439
/**
 
1440
 * soup_session_get_features:
 
1441
 * @session: a #SoupSession
 
1442
 * @feature_type: the #GType of the class of features to get
 
1443
 *
 
1444
 * Generates a list of @session's features of type @feature_type. (If
 
1445
 * you want to see all features, you can pass %G_TYPE_SESSION_FEATURE
 
1446
 * for @feature_type.)
 
1447
 *
 
1448
 * Return value: a list of features. You must free the list, but not
 
1449
 * its contents
 
1450
 **/
 
1451
GSList *
 
1452
soup_session_get_features (SoupSession *session, GType feature_type)
 
1453
{
 
1454
        SoupSessionPrivate *priv;
 
1455
        GSList *f, *ret;
 
1456
 
 
1457
        g_return_val_if_fail (SOUP_IS_SESSION (session), NULL);
 
1458
 
 
1459
        priv = SOUP_SESSION_GET_PRIVATE (session);
 
1460
        for (f = priv->features, ret = NULL; f; f = f->next) {
 
1461
                if (G_TYPE_CHECK_INSTANCE_TYPE (f->data, feature_type))
 
1462
                        ret = g_slist_prepend (ret, f->data);
 
1463
        }
 
1464
        return g_slist_reverse (ret);
 
1465
}
 
1466
 
 
1467
/**
 
1468
 * soup_session_get_feature:
 
1469
 * @session: a #SoupSession
 
1470
 * @feature_type: the #GType of the feature to get
 
1471
 *
 
1472
 * Gets the first feature in @session of type @feature_type. For
 
1473
 * features where there may be more than one feature of a given type,
 
1474
 * use soup_session_get_features().
 
1475
 *
 
1476
 * Return value: a #SoupSessionFeature, or %NULL. The feature is owned
 
1477
 * by @session.
 
1478
 **/
 
1479
SoupSessionFeature *
 
1480
soup_session_get_feature (SoupSession *session, GType feature_type)
 
1481
{
 
1482
        SoupSessionPrivate *priv;
 
1483
        GSList *f;
 
1484
 
 
1485
        g_return_val_if_fail (SOUP_IS_SESSION (session), NULL);
 
1486
 
 
1487
        priv = SOUP_SESSION_GET_PRIVATE (session);
 
1488
        for (f = priv->features; f; f = f->next) {
 
1489
                if (G_TYPE_CHECK_INSTANCE_TYPE (f->data, feature_type))
 
1490
                        return f->data;
 
1491
        }
 
1492
        return NULL;
 
1493
}
 
1494
 
 
1495
SoupProxyResolver *
 
1496
soup_session_get_proxy_resolver (SoupSession *session)
 
1497
{
 
1498
        SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
 
1499
 
 
1500
        return priv->proxy_resolver;
 
1501
}