[evolution-data-server] [CalDAV] Race condition on connection object



commit 1d8db749060ebe807ad3d56c79326fc8509a3f54
Author: Milan Crha <mcrha redhat com>
Date:   Wed Jun 13 17:38:41 2018 +0200

    [CalDAV] Race condition on connection object
    
    It could happen that one thread had been working with the connection
    while another thread disconnected it, which could lead to a race
    condition on the connection object, especially when the code execution
    had been within that object.
    
    The change makes sure to either add a reference on the connection
    object while working with it or it adds a connection lock which is
    acquired for the whole time when the connection object is used.

 .../backends/google/e-book-backend-google.c        |  64 +++++--
 .../backends/webdav/e-book-backend-webdav.c        | 164 +++++++++++++----
 .../backends/caldav/e-cal-backend-caldav.c         | 199 ++++++++++++++++-----
 .../backends/gtasks/e-cal-backend-gtasks.c         |  96 +++++++---
 src/calendar/backends/http/e-cal-backend-http.c    |  30 +++-
 5 files changed, 427 insertions(+), 126 deletions(-)
---
diff --git a/src/addressbook/backends/google/e-book-backend-google.c 
b/src/addressbook/backends/google/e-book-backend-google.c
index c6671005c..d627cb476 100644
--- a/src/addressbook/backends/google/e-book-backend-google.c
+++ b/src/addressbook/backends/google/e-book-backend-google.c
@@ -56,6 +56,7 @@ struct _EBookBackendGooglePrivate {
        /* Did the server-side groups change? If so, re-download the book */
        gboolean groups_changed;
 
+       GRecMutex conn_lock;
        GDataAuthorizer *authorizer;
        GDataService *service;
        GHashTable *preloaded; /* gchar *uid ~> EContact * */
@@ -147,7 +148,7 @@ ebb_google_data_book_error_from_gdata_error (GError **error,
 }
 
 static gboolean
-ebb_google_is_authorized (EBookBackendGoogle *bbgoogle)
+ebb_google_is_authorized_locked (EBookBackendGoogle *bbgoogle)
 {
        g_return_val_if_fail (E_IS_BOOK_BACKEND_GOOGLE (bbgoogle), FALSE);
 
@@ -158,10 +159,10 @@ ebb_google_is_authorized (EBookBackendGoogle *bbgoogle)
 }
 
 static gboolean
-ebb_google_request_authorization (EBookBackendGoogle *bbgoogle,
-                                 const ENamedParameters *credentials,
-                                 GCancellable *cancellable,
-                                 GError **error)
+ebb_google_request_authorization_locked (EBookBackendGoogle *bbgoogle,
+                                        const ENamedParameters *credentials,
+                                        GCancellable *cancellable,
+                                        GError **error)
 {
        /* Make sure we have the GDataService configured
         * before requesting authorization. */
@@ -314,10 +315,10 @@ ebb_google_process_group (GDataEntry *entry,
 }
 
 static gboolean
-ebb_google_get_groups_sync (EBookBackendGoogle *bbgoogle,
-                           gboolean with_time_constraint,
-                           GCancellable *cancellable,
-                           GError **error)
+ebb_google_get_groups_locked_sync (EBookBackendGoogle *bbgoogle,
+                                  gboolean with_time_constraint,
+                                  GCancellable *cancellable,
+                                  GError **error)
 {
        GDataQuery *query;
        GDataFeed *feed;
@@ -325,7 +326,7 @@ ebb_google_get_groups_sync (EBookBackendGoogle *bbgoogle,
        GError *local_error = NULL;
 
        g_return_val_if_fail (E_IS_BOOK_BACKEND_GOOGLE (bbgoogle), FALSE);
-       g_return_val_if_fail (ebb_google_is_authorized (bbgoogle), FALSE);
+       g_return_val_if_fail (ebb_google_is_authorized_locked (bbgoogle), FALSE);
 
        g_rec_mutex_lock (&bbgoogle->priv->groups_lock);
 
@@ -390,15 +391,21 @@ ebb_google_connect_sync (EBookMetaBackend *meta_backend,
 
        *out_auth_result = E_SOURCE_AUTHENTICATION_ACCEPTED;
 
-       if (ebb_google_is_authorized (bbgoogle))
+       g_rec_mutex_lock (&bbgoogle->priv->conn_lock);
+
+       if (ebb_google_is_authorized_locked (bbgoogle)) {
+               g_rec_mutex_unlock (&bbgoogle->priv->conn_lock);
                return TRUE;
+       }
 
-       success = ebb_google_request_authorization (bbgoogle, credentials, cancellable, &local_error);
+       success = ebb_google_request_authorization_locked (bbgoogle, credentials, cancellable, &local_error);
        if (success)
                success = gdata_authorizer_refresh_authorization (bbgoogle->priv->authorizer, cancellable, 
&local_error);
 
        if (success)
-               success = ebb_google_get_groups_sync (bbgoogle, FALSE, cancellable, &local_error);
+               success = ebb_google_get_groups_locked_sync (bbgoogle, FALSE, cancellable, &local_error);
+
+       g_rec_mutex_unlock (&bbgoogle->priv->conn_lock);
 
        if (!success) {
                if (g_error_matches (local_error, GDATA_SERVICE_ERROR, 
GDATA_SERVICE_ERROR_AUTHENTICATION_REQUIRED)) {
@@ -430,9 +437,13 @@ ebb_google_disconnect_sync (EBookMetaBackend *meta_backend,
 
        bbgoogle = E_BOOK_BACKEND_GOOGLE (meta_backend);
 
+       g_rec_mutex_lock (&bbgoogle->priv->conn_lock);
+
        g_clear_object (&bbgoogle->priv->service);
        g_clear_object (&bbgoogle->priv->authorizer);
 
+       g_rec_mutex_unlock (&bbgoogle->priv->conn_lock);
+
        return TRUE;
 }
 
@@ -469,8 +480,12 @@ ebb_google_get_changes_sync (EBookMetaBackend *meta_backend,
        *out_modified_objects = NULL;
        *out_removed_objects = NULL;
 
-       if (!ebb_google_get_groups_sync (bbgoogle, TRUE, cancellable, error))
+       g_rec_mutex_lock (&bbgoogle->priv->conn_lock);
+
+       if (!ebb_google_get_groups_locked_sync (bbgoogle, TRUE, cancellable, error)) {
+               g_rec_mutex_unlock (&bbgoogle->priv->conn_lock);
                return FALSE;
+       }
 
        book_cache = e_book_meta_backend_ref_cache (meta_backend);
 
@@ -657,6 +672,7 @@ ebb_google_get_changes_sync (EBookMetaBackend *meta_backend,
                }
        }
 
+       g_rec_mutex_unlock (&bbgoogle->priv->conn_lock);
        g_clear_object (&contacts_query);
        g_clear_object (&feed);
 
@@ -766,10 +782,12 @@ ebb_google_create_group_sync (EBookBackendGoogle *bbgoogle,
        gdata_entry_set_title (group, category_name);
 
        /* Insert the new group */
+       g_rec_mutex_lock (&bbgoogle->priv->conn_lock);
        new_group = GDATA_ENTRY (gdata_contacts_service_insert_group (
                        GDATA_CONTACTS_SERVICE (bbgoogle->priv->service),
                        GDATA_CONTACTS_GROUP (group),
                        cancellable, error));
+       g_rec_mutex_unlock (&bbgoogle->priv->conn_lock);
        g_object_unref (group);
 
        if (new_group == NULL)
@@ -937,11 +955,12 @@ ebb_google_save_contact_sync (EBookMetaBackend *meta_backend,
        if (extra && *extra)
                entry = GDATA_ENTRY (gdata_parsable_new_from_xml (GDATA_TYPE_CONTACTS_CONTACT, extra, -1, 
NULL));
 
+       g_rec_mutex_lock (&bbgoogle->priv->conn_lock);
        g_rec_mutex_lock (&bbgoogle->priv->groups_lock);
 
        /* Ensure the system groups have been fetched. */
        if (g_hash_table_size (bbgoogle->priv->system_groups_by_id) == 0)
-               ebb_google_get_groups_sync (bbgoogle, FALSE, cancellable, NULL);
+               ebb_google_get_groups_locked_sync (bbgoogle, FALSE, cancellable, NULL);
 
        if (overwrite_existing || entry) {
                if (gdata_entry_update_from_e_contact (entry, contact, FALSE,
@@ -973,6 +992,7 @@ ebb_google_save_contact_sync (EBookMetaBackend *meta_backend,
        g_clear_object (&book_cache);
 
        if (!entry) {
+               g_rec_mutex_unlock (&bbgoogle->priv->conn_lock);
                g_propagate_error (error, e_data_book_create_error (E_DATA_BOOK_STATUS_OTHER_ERROR, _("Object 
to save is not a valid vCard")));
                return FALSE;
        }
@@ -994,6 +1014,7 @@ ebb_google_save_contact_sync (EBookMetaBackend *meta_backend,
        g_object_unref (entry);
 
        if (!gdata_contact) {
+               g_rec_mutex_unlock (&bbgoogle->priv->conn_lock);
                ebb_google_data_book_error_from_gdata_error (error, local_error);
                g_clear_error (&local_error);
                e_contact_photo_free (photo);
@@ -1004,6 +1025,7 @@ ebb_google_save_contact_sync (EBookMetaBackend *meta_backend,
        if (photo_changed) {
                entry = ebb_google_update_contact_photo_sync (gdata_contact, GDATA_CONTACTS_SERVICE 
(bbgoogle->priv->service), photo, cancellable, &local_error);
                if (!entry) {
+                       g_rec_mutex_unlock (&bbgoogle->priv->conn_lock);
                        ebb_google_data_book_error_from_gdata_error (error, local_error);
                        g_clear_error (&local_error);
                        e_contact_photo_free (photo);
@@ -1016,6 +1038,8 @@ ebb_google_save_contact_sync (EBookMetaBackend *meta_backend,
                gdata_contact = GDATA_CONTACTS_CONTACT (entry);
        }
 
+       g_rec_mutex_unlock (&bbgoogle->priv->conn_lock);
+
        g_rec_mutex_lock (&bbgoogle->priv->groups_lock);
        new_contact = e_contact_new_from_gdata_entry (GDATA_ENTRY (gdata_contact),
                bbgoogle->priv->groups_by_id,
@@ -1085,9 +1109,12 @@ ebb_google_remove_contact_sync (EBookMetaBackend *meta_backend,
 
        bbgoogle = E_BOOK_BACKEND_GOOGLE (meta_backend);
 
+       g_rec_mutex_lock (&bbgoogle->priv->conn_lock);
+
        if (!gdata_service_delete_entry (bbgoogle->priv->service,
                gdata_contacts_service_get_primary_authorization_domain (), entry,
                cancellable, &local_error)) {
+               g_rec_mutex_unlock (&bbgoogle->priv->conn_lock);
                ebb_google_data_book_error_from_gdata_error (error, local_error);
                g_error_free (local_error);
                g_object_unref (entry);
@@ -1095,6 +1122,7 @@ ebb_google_remove_contact_sync (EBookMetaBackend *meta_backend,
                return FALSE;
        }
 
+       g_rec_mutex_unlock (&bbgoogle->priv->conn_lock);
        g_object_unref (entry);
 
        return TRUE;
@@ -1273,9 +1301,13 @@ ebb_google_dispose (GObject *object)
 {
        EBookBackendGoogle *bbgoogle = E_BOOK_BACKEND_GOOGLE (object);
 
+       g_rec_mutex_lock (&bbgoogle->priv->conn_lock);
+
        g_clear_object (&bbgoogle->priv->service);
        g_clear_object (&bbgoogle->priv->authorizer);
 
+       g_rec_mutex_unlock (&bbgoogle->priv->conn_lock);
+
        g_hash_table_destroy (bbgoogle->priv->preloaded);
        bbgoogle->priv->preloaded = NULL;
 
@@ -1295,6 +1327,7 @@ ebb_google_finalize (GObject *object)
        g_clear_pointer (&bbgoogle->priv->system_groups_by_id, (GDestroyNotify) g_hash_table_destroy);
 
        g_rec_mutex_clear (&bbgoogle->priv->groups_lock);
+       g_rec_mutex_clear (&bbgoogle->priv->conn_lock);
 
        /* Chain up to parent's method. */
        G_OBJECT_CLASS (e_book_backend_google_parent_class)->finalize (object);
@@ -1307,6 +1340,7 @@ e_book_backend_google_init (EBookBackendGoogle *bbgoogle)
        bbgoogle->priv->preloaded = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
 
        g_rec_mutex_init (&bbgoogle->priv->groups_lock);
+       g_rec_mutex_init (&bbgoogle->priv->conn_lock);
 
        bbgoogle->priv->groups_by_id = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
        bbgoogle->priv->groups_by_name = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
diff --git a/src/addressbook/backends/webdav/e-book-backend-webdav.c 
b/src/addressbook/backends/webdav/e-book-backend-webdav.c
index de5ebfe26..94d198bb7 100644
--- a/src/addressbook/backends/webdav/e-book-backend-webdav.c
+++ b/src/addressbook/backends/webdav/e-book-backend-webdav.c
@@ -38,6 +38,7 @@
 struct _EBookBackendWebDAVPrivate {
        /* The main WebDAV session  */
        EWebDAVSession *webdav;
+       GMutex webdav_lock;
 
        /* support for 'getctag' extension */
        gboolean ctag_supported;
@@ -48,6 +49,23 @@ struct _EBookBackendWebDAVPrivate {
 
 G_DEFINE_TYPE (EBookBackendWebDAV, e_book_backend_webdav, E_TYPE_BOOK_META_BACKEND)
 
+static EWebDAVSession *
+ebb_webdav_ref_session (EBookBackendWebDAV *bbdav)
+{
+       EWebDAVSession *webdav;
+
+       g_return_val_if_fail (E_IS_BOOK_BACKEND_WEBDAV (bbdav), NULL);
+
+       g_mutex_lock (&bbdav->priv->webdav_lock);
+       if (bbdav->priv->webdav)
+               webdav = g_object_ref (bbdav->priv->webdav);
+       else
+               webdav = NULL;
+       g_mutex_unlock (&bbdav->priv->webdav_lock);
+
+       return webdav;
+}
+
 static gboolean
 ebb_webdav_connect_sync (EBookMetaBackend *meta_backend,
                         const ENamedParameters *credentials,
@@ -58,6 +76,7 @@ ebb_webdav_connect_sync (EBookMetaBackend *meta_backend,
                         GError **error)
 {
        EBookBackendWebDAV *bbdav;
+       EWebDAVSession *webdav;
        GHashTable *capabilities = NULL, *allows = NULL;
        ESource *source;
        gboolean success, is_writable = FALSE;
@@ -68,18 +87,22 @@ ebb_webdav_connect_sync (EBookMetaBackend *meta_backend,
 
        bbdav = E_BOOK_BACKEND_WEBDAV (meta_backend);
 
-       if (bbdav->priv->webdav)
+       g_mutex_lock (&bbdav->priv->webdav_lock);
+       if (bbdav->priv->webdav) {
+               g_mutex_unlock (&bbdav->priv->webdav_lock);
                return TRUE;
+       }
+       g_mutex_unlock (&bbdav->priv->webdav_lock);
 
        source = e_backend_get_source (E_BACKEND (meta_backend));
 
-       bbdav->priv->webdav = e_webdav_session_new (source);
+       webdav = e_webdav_session_new (source);
 
-       e_soup_session_setup_logging (E_SOUP_SESSION (bbdav->priv->webdav), g_getenv ("WEBDAV_DEBUG"));
+       e_soup_session_setup_logging (E_SOUP_SESSION (webdav), g_getenv ("WEBDAV_DEBUG"));
 
        e_binding_bind_property (
                bbdav, "proxy-resolver",
-               bbdav->priv->webdav, "proxy-resolver",
+               webdav, "proxy-resolver",
                G_BINDING_SYNC_CREATE);
 
        /* Thinks the 'getctag' extension is available the first time, but unset it when realizes it isn't. */
@@ -87,9 +110,9 @@ ebb_webdav_connect_sync (EBookMetaBackend *meta_backend,
 
        e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_CONNECTING);
 
-       e_soup_session_set_credentials (E_SOUP_SESSION (bbdav->priv->webdav), credentials);
+       e_soup_session_set_credentials (E_SOUP_SESSION (webdav), credentials);
 
-       success = e_webdav_session_options_sync (bbdav->priv->webdav, NULL,
+       success = e_webdav_session_options_sync (webdav, NULL,
                &capabilities, &allows, cancellable, &local_error);
 
        /* iCloud and Google servers can return "404 Not Found" when issued OPTIONS on the addressbook 
collection */
@@ -119,7 +142,7 @@ ebb_webdav_connect_sync (EBookMetaBackend *meta_backend,
                                        if (uri) {
                                                g_clear_error (&local_error);
 
-                                               success = e_webdav_session_options_sync (bbdav->priv->webdav, 
uri,
+                                               success = e_webdav_session_options_sync (webdav, uri,
                                                        &capabilities, &allows, cancellable, &local_error);
                                        }
 
@@ -147,7 +170,7 @@ ebb_webdav_connect_sync (EBookMetaBackend *meta_backend,
                GSList *privileges = NULL, *link;
 
                /* Ignore any errors here */
-               if (e_webdav_session_get_current_user_privilege_set_sync (bbdav->priv->webdav, NULL, 
&privileges, cancellable, NULL)) {
+               if (e_webdav_session_get_current_user_privilege_set_sync (webdav, NULL, &privileges, 
cancellable, NULL)) {
                        for (link = privileges; link && !is_writable; link = g_slist_next (link)) {
                                EWebDAVPrivilege *privilege = link->data;
 
@@ -213,7 +236,7 @@ ebb_webdav_connect_sync (EBookMetaBackend *meta_backend,
 
                   The 'getctag' extension is not required, thuch check
                   for unauthorized error only. */
-               if (!e_webdav_session_getctag_sync (bbdav->priv->webdav, NULL, &ctag, cancellable, 
&local_error) &&
+               if (!e_webdav_session_getctag_sync (webdav, NULL, &ctag, cancellable, &local_error) &&
                    g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_UNAUTHORIZED)) {
                        success = FALSE;
                } else {
@@ -230,7 +253,7 @@ ebb_webdav_connect_sync (EBookMetaBackend *meta_backend,
                gboolean is_ssl_error;
 
                credentials_empty = (!credentials || !e_named_parameters_count (credentials)) &&
-                       e_soup_session_get_authentication_requires_credentials (E_SOUP_SESSION 
(bbdav->priv->webdav));
+                       e_soup_session_get_authentication_requires_credentials (E_SOUP_SESSION (webdav));
                is_ssl_error = g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_SSL_FAILED);
 
                *out_auth_result = E_SOURCE_AUTHENTICATION_ERROR;
@@ -247,7 +270,7 @@ ebb_webdav_connect_sync (EBookMetaBackend *meta_backend,
                        else
                                *out_auth_result = E_SOURCE_AUTHENTICATION_REJECTED;
                } else if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_CONNECTION_REFUSED) ||
-                          (!e_soup_session_get_authentication_requires_credentials (E_SOUP_SESSION 
(bbdav->priv->webdav)) &&
+                          (!e_soup_session_get_authentication_requires_credentials (E_SOUP_SESSION (webdav)) 
&&
                           g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))) {
                        *out_auth_result = E_SOURCE_AUTHENTICATION_REJECTED;
                } else if (!local_error) {
@@ -264,7 +287,7 @@ ebb_webdav_connect_sync (EBookMetaBackend *meta_backend,
                        *out_auth_result = E_SOURCE_AUTHENTICATION_ERROR_SSL_FAILED;
 
                        e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_SSL_FAILED);
-                       e_soup_session_get_ssl_error_details (E_SOUP_SESSION (bbdav->priv->webdav), 
out_certificate_pem, out_certificate_errors);
+                       e_soup_session_get_ssl_error_details (E_SOUP_SESSION (webdav), out_certificate_pem, 
out_certificate_errors);
                } else {
                        e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_DISCONNECTED);
                }
@@ -275,8 +298,18 @@ ebb_webdav_connect_sync (EBookMetaBackend *meta_backend,
        if (allows)
                g_hash_table_destroy (allows);
 
-       if (!success)
-               g_clear_object (&bbdav->priv->webdav);
+       if (success && !g_cancellable_set_error_if_cancelled (cancellable, error)) {
+               g_mutex_lock (&bbdav->priv->webdav_lock);
+               bbdav->priv->webdav = webdav;
+               g_mutex_unlock (&bbdav->priv->webdav_lock);
+       } else {
+               if (success) {
+                       e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_DISCONNECTED);
+                       success = FALSE;
+               }
+
+               g_clear_object (&webdav);
+       }
 
        return success;
 }
@@ -293,11 +326,15 @@ ebb_webdav_disconnect_sync (EBookMetaBackend *meta_backend,
 
        bbdav = E_BOOK_BACKEND_WEBDAV (meta_backend);
 
+       g_mutex_lock (&bbdav->priv->webdav_lock);
+
        if (bbdav->priv->webdav)
                soup_session_abort (SOUP_SESSION (bbdav->priv->webdav));
 
        g_clear_object (&bbdav->priv->webdav);
 
+       g_mutex_unlock (&bbdav->priv->webdav_lock);
+
        source = e_backend_get_source (E_BACKEND (meta_backend));
        e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_DISCONNECTED);
 
@@ -403,6 +440,7 @@ ebb_webdav_multiget_response_cb (EWebDAVSession *webdav,
 
 static gboolean
 ebb_webdav_multiget_from_sets_sync (EBookBackendWebDAV *bbdav,
+                                   EWebDAVSession *webdav,
                                    GSList **in_link,
                                    GSList **set2,
                                    GCancellable *cancellable,
@@ -461,7 +499,7 @@ ebb_webdav_multiget_from_sets_sync (EBookBackendWebDAV *bbdav,
        if (left_to_go != E_WEBDAV_MAX_MULTIGET_AMOUNT && success) {
                GSList *from_link = *in_link;
 
-               success = e_webdav_session_report_sync (bbdav->priv->webdav, NULL, NULL, xml,
+               success = e_webdav_session_report_sync (webdav, NULL, NULL, xml,
                        ebb_webdav_multiget_response_cb, &from_link, NULL, NULL, cancellable, error);
        }
 
@@ -565,11 +603,12 @@ ebb_webdav_search_changes_cb (EBookCache *book_cache,
 
 static void
 ebb_webdav_check_credentials_error (EBookBackendWebDAV *bbdav,
+                                   EWebDAVSession *webdav,
                                    GError *op_error)
 {
        g_return_if_fail (E_IS_BOOK_BACKEND_WEBDAV (bbdav));
 
-       if (g_error_matches (op_error, SOUP_HTTP_ERROR, SOUP_STATUS_SSL_FAILED) && bbdav->priv->webdav) {
+       if (g_error_matches (op_error, SOUP_HTTP_ERROR, SOUP_STATUS_SSL_FAILED) && webdav) {
                op_error->domain = E_DATA_BOOK_ERROR;
                op_error->code = E_DATA_BOOK_STATUS_TLS_NOT_AVAILABLE;
        } else if (g_error_matches (op_error, SOUP_HTTP_ERROR, SOUP_STATUS_UNAUTHORIZED) ||
@@ -577,10 +616,10 @@ ebb_webdav_check_credentials_error (EBookBackendWebDAV *bbdav,
                op_error->domain = E_DATA_BOOK_ERROR;
                op_error->code = E_DATA_BOOK_STATUS_AUTHENTICATION_REQUIRED;
 
-               if (bbdav->priv->webdav) {
+               if (webdav) {
                        ENamedParameters *credentials;
 
-                       credentials = e_soup_session_dup_credentials (E_SOUP_SESSION (bbdav->priv->webdav));
+                       credentials = e_soup_session_dup_credentials (E_SOUP_SESSION (webdav));
                        if (credentials && e_named_parameters_count (credentials) > 0)
                                op_error->code = E_DATA_BOOK_STATUS_AUTHENTICATION_FAILED;
 
@@ -602,6 +641,7 @@ ebb_webdav_get_changes_sync (EBookMetaBackend *meta_backend,
                             GError **error)
 {
        EBookBackendWebDAV *bbdav;
+       EWebDAVSession *webdav;
        EXmlDocument *xml;
        GHashTable *known_items; /* gchar *href ~> EBookMetaBackendInfo * */
        GHashTableIter iter;
@@ -621,17 +661,21 @@ ebb_webdav_get_changes_sync (EBookMetaBackend *meta_backend,
        *out_removed_objects = NULL;
 
        bbdav = E_BOOK_BACKEND_WEBDAV (meta_backend);
+       webdav = ebb_webdav_ref_session (bbdav);
 
        if (bbdav->priv->ctag_supported) {
                gchar *new_sync_tag = NULL;
 
-               success = e_webdav_session_getctag_sync (bbdav->priv->webdav, NULL, &new_sync_tag, 
cancellable, NULL);
+               success = e_webdav_session_getctag_sync (webdav, NULL, &new_sync_tag, cancellable, NULL);
                if (!success) {
                        bbdav->priv->ctag_supported = g_cancellable_set_error_if_cancelled (cancellable, 
error);
-                       if (bbdav->priv->ctag_supported || !bbdav->priv->webdav)
+                       if (bbdav->priv->ctag_supported || !webdav) {
+                               g_clear_object (&webdav);
                                return FALSE;
+                       }
                } else if (new_sync_tag && last_sync_tag && g_strcmp0 (last_sync_tag, new_sync_tag) == 0) {
                        *out_new_sync_tag = new_sync_tag;
+                       g_clear_object (&webdav);
                        return TRUE;
                }
 
@@ -647,7 +691,7 @@ ebb_webdav_get_changes_sync (EBookMetaBackend *meta_backend,
 
        known_items = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, e_book_meta_backend_info_free);
 
-       success = e_webdav_session_propfind_sync (bbdav->priv->webdav, NULL, 
E_WEBDAV_DEPTH_THIS_AND_CHILDREN, xml,
+       success = e_webdav_session_propfind_sync (webdav, NULL, E_WEBDAV_DEPTH_THIS_AND_CHILDREN, xml,
                ebb_webdav_get_contact_items_cb, known_items, cancellable, &local_error);
 
        g_object_unref (xml);
@@ -687,15 +731,17 @@ ebb_webdav_get_changes_sync (EBookMetaBackend *meta_backend,
                }
 
                do {
-                       success = ebb_webdav_multiget_from_sets_sync (bbdav, &link, &set2, cancellable, 
&local_error);
+                       success = ebb_webdav_multiget_from_sets_sync (bbdav, webdav, &link, &set2, 
cancellable, &local_error);
                } while (success && link);
        }
 
        if (local_error) {
-               ebb_webdav_check_credentials_error (bbdav, local_error);
+               ebb_webdav_check_credentials_error (bbdav, webdav, local_error);
                g_propagate_error (error, local_error);
        }
 
+       g_clear_object (&webdav);
+
        return success;
 }
 
@@ -757,6 +803,7 @@ ebb_webdav_list_existing_sync (EBookMetaBackend *meta_backend,
                               GError **error)
 {
        EBookBackendWebDAV *bbdav;
+       EWebDAVSession *webdav;
        EXmlDocument *xml;
        GError *local_error = NULL;
        gboolean success;
@@ -785,7 +832,9 @@ ebb_webdav_list_existing_sync (EBookMetaBackend *meta_backend,
        e_xml_document_end_element (xml); /* address-data */
        e_xml_document_end_element (xml); /* prop */
 
-       success = e_webdav_session_report_sync (bbdav->priv->webdav, NULL, E_WEBDAV_DEPTH_THIS, xml,
+       webdav = ebb_webdav_ref_session (bbdav);
+
+       success = e_webdav_session_report_sync (webdav, NULL, E_WEBDAV_DEPTH_THIS, xml,
                ebb_webdav_extract_existing_cb, out_existing_objects, NULL, NULL, cancellable, &local_error);
 
        g_object_unref (xml);
@@ -794,10 +843,12 @@ ebb_webdav_list_existing_sync (EBookMetaBackend *meta_backend,
                *out_existing_objects = g_slist_reverse (*out_existing_objects);
 
        if (local_error) {
-               ebb_webdav_check_credentials_error (bbdav, local_error);
+               ebb_webdav_check_credentials_error (bbdav, webdav, local_error);
                g_propagate_error (error, local_error);
        }
 
+       g_clear_object (&webdav);
+
        return success;
 }
 
@@ -869,6 +920,7 @@ ebb_webdav_load_contact_sync (EBookMetaBackend *meta_backend,
                              GError **error)
 {
        EBookBackendWebDAV *bbdav;
+       EWebDAVSession *webdav;
        gchar *uri = NULL, *href = NULL, *etag = NULL, *bytes = NULL;
        gsize length = -1;
        gboolean success = FALSE;
@@ -879,11 +931,12 @@ ebb_webdav_load_contact_sync (EBookMetaBackend *meta_backend,
        g_return_val_if_fail (out_contact != NULL, FALSE);
 
        bbdav = E_BOOK_BACKEND_WEBDAV (meta_backend);
+       webdav = ebb_webdav_ref_session (bbdav);
 
        if (extra && *extra) {
                uri = g_strdup (extra);
 
-               success = e_webdav_session_get_data_sync (bbdav->priv->webdav, uri, &href, &etag, &bytes, 
&length, cancellable, &local_error);
+               success = e_webdav_session_get_data_sync (webdav, uri, &href, &etag, &bytes, &length, 
cancellable, &local_error);
 
                if (!success) {
                        g_free (uri);
@@ -894,13 +947,14 @@ ebb_webdav_load_contact_sync (EBookMetaBackend *meta_backend,
        if (!success && bbdav->priv->ctag_supported) {
                gchar *new_sync_tag = NULL;
 
-               if (e_webdav_session_getctag_sync (bbdav->priv->webdav, NULL, &new_sync_tag, cancellable, 
NULL) && new_sync_tag) {
+               if (e_webdav_session_getctag_sync (webdav, NULL, &new_sync_tag, cancellable, NULL) && 
new_sync_tag) {
                        gchar *last_sync_tag;
 
                        last_sync_tag = e_book_meta_backend_dup_sync_tag (meta_backend);
 
                        /* The book didn't change, thus the contact cannot be there */
                        if (g_strcmp0 (last_sync_tag, new_sync_tag) == 0) {
+                               g_clear_object (&webdav);
                                g_clear_error (&local_error);
                                g_free (last_sync_tag);
                                g_free (new_sync_tag);
@@ -922,7 +976,7 @@ ebb_webdav_load_contact_sync (EBookMetaBackend *meta_backend,
 
                g_clear_error (&local_error);
 
-               success = e_webdav_session_get_data_sync (bbdav->priv->webdav, uri, &href, &etag, &bytes, 
&length, cancellable, &local_error);
+               success = e_webdav_session_get_data_sync (webdav, uri, &href, &etag, &bytes, &length, 
cancellable, &local_error);
 
                /* Do not try twice with Google, it's either without extension or not there.
                   The worst, it counts to the Error requests quota limit. */
@@ -934,7 +988,7 @@ ebb_webdav_load_contact_sync (EBookMetaBackend *meta_backend,
                        if (uri) {
                                g_clear_error (&local_error);
 
-                               success = e_webdav_session_get_data_sync (bbdav->priv->webdav, uri, &href, 
&etag, &bytes, &length, cancellable, &local_error);
+                               success = e_webdav_session_get_data_sync (webdav, uri, &href, &etag, &bytes, 
&length, cancellable, &local_error);
                        }
                }
        }
@@ -964,10 +1018,12 @@ ebb_webdav_load_contact_sync (EBookMetaBackend *meta_backend,
        g_free (bytes);
 
        if (local_error) {
-               ebb_webdav_check_credentials_error (bbdav, local_error);
+               ebb_webdav_check_credentials_error (bbdav, webdav, local_error);
                g_propagate_error (error, local_error);
        }
 
+       g_clear_object (&webdav);
+
        return success;
 }
 
@@ -983,6 +1039,7 @@ ebb_webdav_save_contact_sync (EBookMetaBackend *meta_backend,
                              GError **error)
 {
        EBookBackendWebDAV *bbdav;
+       EWebDAVSession *webdav;
        gchar *href = NULL, *etag = NULL, *uid = NULL;
        gchar *vcard_string = NULL;
        GError *local_error = NULL;
@@ -994,6 +1051,7 @@ ebb_webdav_save_contact_sync (EBookMetaBackend *meta_backend,
        g_return_val_if_fail (out_new_extra, FALSE);
 
        bbdav = E_BOOK_BACKEND_WEBDAV (meta_backend);
+       webdav = ebb_webdav_ref_session (bbdav);
 
        uid = e_contact_get (contact, E_CONTACT_UID);
        etag = e_vcard_util_dup_x_attribute (E_VCARD (contact), E_WEBDAV_X_ETAG);
@@ -1021,7 +1079,7 @@ ebb_webdav_save_contact_sync (EBookMetaBackend *meta_backend,
                        }
                }
 
-               success = e_webdav_session_put_data_sync (bbdav->priv->webdav, (extra && *extra) ? extra : 
href,
+               success = e_webdav_session_put_data_sync (webdav, (extra && *extra) ? extra : href,
                        force_write ? "" : overwrite_existing ? etag : NULL, E_WEBDAV_CONTENT_TYPE_VCARD,
                        vcard_string, -1, out_new_extra, NULL, cancellable, &local_error);
 
@@ -1039,10 +1097,12 @@ ebb_webdav_save_contact_sync (EBookMetaBackend *meta_backend,
        g_free (uid);
 
        if (local_error) {
-               ebb_webdav_check_credentials_error (bbdav, local_error);
+               ebb_webdav_check_credentials_error (bbdav, webdav, local_error);
                g_propagate_error (error, local_error);
        }
 
+       g_clear_object (&webdav);
+
        return success;
 }
 
@@ -1056,6 +1116,7 @@ ebb_webdav_remove_contact_sync (EBookMetaBackend *meta_backend,
                                GError **error)
 {
        EBookBackendWebDAV *bbdav;
+       EWebDAVSession *webdav;
        EContact *contact;
        gchar *etag = NULL;
        gboolean success;
@@ -1081,7 +1142,9 @@ ebb_webdav_remove_contact_sync (EBookMetaBackend *meta_backend,
        if (conflict_resolution == E_CONFLICT_RESOLUTION_FAIL)
                etag = e_vcard_util_dup_x_attribute (E_VCARD (contact), E_WEBDAV_X_ETAG);
 
-       success = e_webdav_session_delete_sync (bbdav->priv->webdav, extra,
+       webdav = ebb_webdav_ref_session (bbdav);
+
+       success = e_webdav_session_delete_sync (webdav, extra,
                NULL, etag, cancellable, &local_error);
 
        if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_NOT_FOUND)) {
@@ -1090,7 +1153,7 @@ ebb_webdav_remove_contact_sync (EBookMetaBackend *meta_backend,
                href = ebb_webdav_uid_to_uri (bbdav, uid, ".vcf");
                if (href) {
                        g_clear_error (&local_error);
-                       success = e_webdav_session_delete_sync (bbdav->priv->webdav, href,
+                       success = e_webdav_session_delete_sync (webdav, href,
                                NULL, etag, cancellable, &local_error);
 
                        g_free (href);
@@ -1100,7 +1163,7 @@ ebb_webdav_remove_contact_sync (EBookMetaBackend *meta_backend,
                        href = ebb_webdav_uid_to_uri (bbdav, uid, NULL);
                        if (href) {
                                g_clear_error (&local_error);
-                               success = e_webdav_session_delete_sync (bbdav->priv->webdav, href,
+                               success = e_webdav_session_delete_sync (webdav, href,
                                        NULL, etag, cancellable, &local_error);
 
                                g_free (href);
@@ -1112,10 +1175,12 @@ ebb_webdav_remove_contact_sync (EBookMetaBackend *meta_backend,
        g_free (etag);
 
        if (local_error) {
-               ebb_webdav_check_credentials_error (bbdav, local_error);
+               ebb_webdav_check_credentials_error (bbdav, webdav, local_error);
                g_propagate_error (error, local_error);
        }
 
+       g_clear_object (&webdav);
+
        return success;
 }
 
@@ -1125,15 +1190,22 @@ ebb_webdav_get_ssl_error_details (EBookMetaBackend *meta_backend,
                                  GTlsCertificateFlags *out_certificate_errors)
 {
        EBookBackendWebDAV *bbdav;
+       EWebDAVSession *webdav;
+       gboolean res;
 
        g_return_val_if_fail (E_IS_BOOK_BACKEND_WEBDAV (meta_backend), FALSE);
 
        bbdav = E_BOOK_BACKEND_WEBDAV (meta_backend);
+       webdav = ebb_webdav_ref_session (bbdav);
 
-       if (!bbdav->priv->webdav)
+       if (!webdav)
                return FALSE;
 
-       return e_soup_session_get_ssl_error_details (E_SOUP_SESSION (bbdav->priv->webdav), 
out_certificate_pem, out_certificate_errors);
+       res = e_soup_session_get_ssl_error_details (E_SOUP_SESSION (webdav), out_certificate_pem, 
out_certificate_errors);
+
+       g_clear_object (&webdav);
+
+       return res;
 }
 
 static gchar *
@@ -1187,16 +1259,31 @@ e_book_backend_webdav_dispose (GObject *object)
 {
        EBookBackendWebDAV *bbdav = E_BOOK_BACKEND_WEBDAV (object);
 
+       g_mutex_lock (&bbdav->priv->webdav_lock);
        g_clear_object (&bbdav->priv->webdav);
+       g_mutex_unlock (&bbdav->priv->webdav_lock);
 
        /* Chain up to parent's method. */
        G_OBJECT_CLASS (e_book_backend_webdav_parent_class)->dispose (object);
 }
 
+static void
+e_book_backend_webdav_finalize (GObject *object)
+{
+       EBookBackendWebDAV *bbdav = E_BOOK_BACKEND_WEBDAV (object);
+
+       g_mutex_clear (&bbdav->priv->webdav_lock);
+
+       /* Chain up to parent's method. */
+       G_OBJECT_CLASS (e_book_backend_webdav_parent_class)->finalize (object);
+}
+
 static void
 e_book_backend_webdav_init (EBookBackendWebDAV *bbdav)
 {
        bbdav->priv = G_TYPE_INSTANCE_GET_PRIVATE (bbdav, E_TYPE_BOOK_BACKEND_WEBDAV, 
EBookBackendWebDAVPrivate);
+
+       g_mutex_init (&bbdav->priv->webdav_lock);
 }
 
 static void
@@ -1226,4 +1313,5 @@ e_book_backend_webdav_class_init (EBookBackendWebDAVClass *klass)
        object_class = G_OBJECT_CLASS (klass);
        object_class->constructed = e_book_backend_webdav_constructed;
        object_class->dispose = e_book_backend_webdav_dispose;
+       object_class->finalize = e_book_backend_webdav_finalize;
 }
diff --git a/src/calendar/backends/caldav/e-cal-backend-caldav.c 
b/src/calendar/backends/caldav/e-cal-backend-caldav.c
index 23ef90bb0..fc9d5539a 100644
--- a/src/calendar/backends/caldav/e-cal-backend-caldav.c
+++ b/src/calendar/backends/caldav/e-cal-backend-caldav.c
@@ -36,6 +36,7 @@
 struct _ECalBackendCalDAVPrivate {
        /* The main WebDAV session  */
        EWebDAVSession *webdav;
+       GMutex webdav_lock;
 
        /* support for 'getctag' extension */
        gboolean ctag_supported;
@@ -58,6 +59,23 @@ struct _ECalBackendCalDAVPrivate {
 
 G_DEFINE_TYPE (ECalBackendCalDAV, e_cal_backend_caldav, E_TYPE_CAL_META_BACKEND)
 
+static EWebDAVSession *
+ecb_caldav_ref_session (ECalBackendCalDAV *cbdav)
+{
+       EWebDAVSession *webdav;
+
+       g_return_val_if_fail (E_IS_CAL_BACKEND_CALDAV (cbdav), NULL);
+
+       g_mutex_lock (&cbdav->priv->webdav_lock);
+       if (cbdav->priv->webdav)
+               webdav = g_object_ref (cbdav->priv->webdav);
+       else
+               webdav = NULL;
+       g_mutex_unlock (&cbdav->priv->webdav_lock);
+
+       return webdav;
+}
+
 static void
 ecb_caldav_update_tweaks (ECalBackendCalDAV *cbdav)
 {
@@ -95,6 +113,7 @@ ecb_caldav_connect_sync (ECalMetaBackend *meta_backend,
                         GError **error)
 {
        ECalBackendCalDAV *cbdav;
+       EWebDAVSession *webdav;
        GHashTable *capabilities = NULL, *allows = NULL;
        ESource *source;
        gboolean success, is_writable = FALSE;
@@ -105,18 +124,22 @@ ecb_caldav_connect_sync (ECalMetaBackend *meta_backend,
 
        cbdav = E_CAL_BACKEND_CALDAV (meta_backend);
 
-       if (cbdav->priv->webdav)
+       g_mutex_lock (&cbdav->priv->webdav_lock);
+       if (cbdav->priv->webdav) {
+               g_mutex_unlock (&cbdav->priv->webdav_lock);
                return TRUE;
+       }
+       g_mutex_unlock (&cbdav->priv->webdav_lock);
 
        source = e_backend_get_source (E_BACKEND (meta_backend));
 
-       cbdav->priv->webdav = e_webdav_session_new (source);
+       webdav = e_webdav_session_new (source);
 
-       e_soup_session_setup_logging (E_SOUP_SESSION (cbdav->priv->webdav), g_getenv ("CALDAV_DEBUG"));
+       e_soup_session_setup_logging (E_SOUP_SESSION (webdav), g_getenv ("CALDAV_DEBUG"));
 
        e_binding_bind_property (
                cbdav, "proxy-resolver",
-               cbdav->priv->webdav, "proxy-resolver",
+               webdav, "proxy-resolver",
                G_BINDING_SYNC_CREATE);
 
        /* Thinks the 'getctag' extension is available the first time, but unset it when realizes it isn't. */
@@ -124,16 +147,16 @@ ecb_caldav_connect_sync (ECalMetaBackend *meta_backend,
 
        e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_CONNECTING);
 
-       e_soup_session_set_credentials (E_SOUP_SESSION (cbdav->priv->webdav), credentials);
+       e_soup_session_set_credentials (E_SOUP_SESSION (webdav), credentials);
 
-       success = e_webdav_session_options_sync (cbdav->priv->webdav, NULL,
+       success = e_webdav_session_options_sync (webdav, NULL,
                &capabilities, &allows, cancellable, &local_error);
 
        if (success && !g_cancellable_is_cancelled (cancellable)) {
                GSList *privileges = NULL, *link;
 
                /* Ignore any errors here */
-               if (e_webdav_session_get_current_user_privilege_set_sync (cbdav->priv->webdav, NULL, 
&privileges, cancellable, NULL)) {
+               if (e_webdav_session_get_current_user_privilege_set_sync (webdav, NULL, &privileges, 
cancellable, NULL)) {
                        for (link = privileges; link && !is_writable; link = g_slist_next (link)) {
                                EWebDAVPrivilege *privilege = link->data;
 
@@ -199,7 +222,7 @@ ecb_caldav_connect_sync (ECalMetaBackend *meta_backend,
 
                   The 'getctag' extension is not required, thuch check
                   for unauthorized error only. */
-               if (!e_webdav_session_getctag_sync (cbdav->priv->webdav, NULL, &ctag, cancellable, 
&local_error) &&
+               if (!e_webdav_session_getctag_sync (webdav, NULL, &ctag, cancellable, &local_error) &&
                    g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_UNAUTHORIZED)) {
                        success = FALSE;
                } else {
@@ -214,7 +237,7 @@ ecb_caldav_connect_sync (ECalMetaBackend *meta_backend,
                gboolean is_ssl_error;
 
                credentials_empty = (!credentials || !e_named_parameters_count (credentials)) &&
-                       e_soup_session_get_authentication_requires_credentials (E_SOUP_SESSION 
(cbdav->priv->webdav));
+                       e_soup_session_get_authentication_requires_credentials (E_SOUP_SESSION (webdav));
                is_ssl_error = g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_SSL_FAILED);
 
                *out_auth_result = E_SOURCE_AUTHENTICATION_ERROR;
@@ -231,7 +254,7 @@ ecb_caldav_connect_sync (ECalMetaBackend *meta_backend,
                        else
                                *out_auth_result = E_SOURCE_AUTHENTICATION_REJECTED;
                } else if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_CONNECTION_REFUSED) ||
-                          (!e_soup_session_get_authentication_requires_credentials (E_SOUP_SESSION 
(cbdav->priv->webdav)) &&
+                          (!e_soup_session_get_authentication_requires_credentials (E_SOUP_SESSION (webdav)) 
&&
                           g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))) {
                        *out_auth_result = E_SOURCE_AUTHENTICATION_REJECTED;
                } else if (!local_error) {
@@ -248,7 +271,7 @@ ecb_caldav_connect_sync (ECalMetaBackend *meta_backend,
                        *out_auth_result = E_SOURCE_AUTHENTICATION_ERROR_SSL_FAILED;
 
                        e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_SSL_FAILED);
-                       e_soup_session_get_ssl_error_details (E_SOUP_SESSION (cbdav->priv->webdav), 
out_certificate_pem, out_certificate_errors);
+                       e_soup_session_get_ssl_error_details (E_SOUP_SESSION (webdav), out_certificate_pem, 
out_certificate_errors);
                } else {
                        e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_DISCONNECTED);
                }
@@ -259,8 +282,18 @@ ecb_caldav_connect_sync (ECalMetaBackend *meta_backend,
        if (allows)
                g_hash_table_destroy (allows);
 
-       if (!success)
-               g_clear_object (&cbdav->priv->webdav);
+       if (success && !g_cancellable_set_error_if_cancelled (cancellable, error)) {
+               g_mutex_lock (&cbdav->priv->webdav_lock);
+               cbdav->priv->webdav = webdav;
+               g_mutex_unlock (&cbdav->priv->webdav_lock);
+       } else {
+               if (success) {
+                       e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_DISCONNECTED);
+                       success = FALSE;
+               }
+
+               g_clear_object (&webdav);
+       }
 
        return success;
 }
@@ -277,10 +310,12 @@ ecb_caldav_disconnect_sync (ECalMetaBackend *meta_backend,
 
        cbdav = E_CAL_BACKEND_CALDAV (meta_backend);
 
+       g_mutex_lock (&cbdav->priv->webdav_lock);
        if (cbdav->priv->webdav)
                soup_session_abort (SOUP_SESSION (cbdav->priv->webdav));
 
        g_clear_object (&cbdav->priv->webdav);
+       g_mutex_unlock (&cbdav->priv->webdav_lock);
 
        source = e_backend_get_source (E_BACKEND (meta_backend));
        e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_DISCONNECTED);
@@ -424,6 +459,7 @@ ecb_caldav_multiget_response_cb (EWebDAVSession *webdav,
 
 static gboolean
 ecb_caldav_multiget_from_sets_sync (ECalBackendCalDAV *cbdav,
+                                   EWebDAVSession *webdav,
                                    GSList **in_link,
                                    GSList **set2,
                                    GCancellable *cancellable,
@@ -470,7 +506,7 @@ ecb_caldav_multiget_from_sets_sync (ECalBackendCalDAV *cbdav,
                if (cbdav->priv->is_icloud) {
                        gchar *calendar_data = NULL, *etag = NULL;
 
-                       success = e_webdav_session_get_data_sync (cbdav->priv->webdav,
+                       success = e_webdav_session_get_data_sync (webdav,
                                nfo->extra, NULL, &etag, &calendar_data, NULL, cancellable, error);
 
                        if (success && calendar_data) {
@@ -510,7 +546,7 @@ ecb_caldav_multiget_from_sets_sync (ECalBackendCalDAV *cbdav,
            !cbdav->priv->is_icloud && success) {
                GSList *from_link = *in_link;
 
-               success = e_webdav_session_report_sync (cbdav->priv->webdav, NULL, NULL, xml,
+               success = e_webdav_session_report_sync (webdav, NULL, NULL, xml,
                        ecb_caldav_multiget_response_cb, &from_link, NULL, NULL, cancellable, error);
        }
 
@@ -616,11 +652,12 @@ ecb_caldav_search_changes_cb (ECalCache *cal_cache,
 
 static void
 ecb_caldav_check_credentials_error (ECalBackendCalDAV *cbdav,
+                                   EWebDAVSession *webdav,
                                    GError *op_error)
 {
        g_return_if_fail (E_IS_CAL_BACKEND_CALDAV (cbdav));
 
-       if (g_error_matches (op_error, SOUP_HTTP_ERROR, SOUP_STATUS_SSL_FAILED) && cbdav->priv->webdav) {
+       if (g_error_matches (op_error, SOUP_HTTP_ERROR, SOUP_STATUS_SSL_FAILED) && webdav) {
                op_error->domain = E_DATA_CAL_ERROR;
                op_error->code = TLSNotAvailable;
        } else if (g_error_matches (op_error, SOUP_HTTP_ERROR, SOUP_STATUS_UNAUTHORIZED) ||
@@ -628,10 +665,10 @@ ecb_caldav_check_credentials_error (ECalBackendCalDAV *cbdav,
                op_error->domain = E_DATA_CAL_ERROR;
                op_error->code = AuthenticationRequired;
 
-               if (cbdav->priv->webdav) {
+               if (webdav) {
                        ENamedParameters *credentials;
 
-                       credentials = e_soup_session_dup_credentials (E_SOUP_SESSION (cbdav->priv->webdav));
+                       credentials = e_soup_session_dup_credentials (E_SOUP_SESSION (webdav));
                        if (credentials && e_named_parameters_count (credentials) > 0)
                                op_error->code = AuthenticationFailed;
 
@@ -653,6 +690,7 @@ ecb_caldav_get_changes_sync (ECalMetaBackend *meta_backend,
                             GError **error)
 {
        ECalBackendCalDAV *cbdav;
+       EWebDAVSession *webdav;
        EXmlDocument *xml;
        GHashTable *known_items; /* gchar *href ~> ECalMetaBackendInfo * */
        GHashTableIter iter;
@@ -673,17 +711,21 @@ ecb_caldav_get_changes_sync (ECalMetaBackend *meta_backend,
        *out_removed_objects = NULL;
 
        cbdav = E_CAL_BACKEND_CALDAV (meta_backend);
+       webdav = ecb_caldav_ref_session (cbdav);
 
        if (cbdav->priv->ctag_supported) {
                gchar *new_sync_tag = NULL;
 
-               success = e_webdav_session_getctag_sync (cbdav->priv->webdav, NULL, &new_sync_tag, 
cancellable, NULL);
+               success = e_webdav_session_getctag_sync (webdav, NULL, &new_sync_tag, cancellable, NULL);
                if (!success) {
                        cbdav->priv->ctag_supported = g_cancellable_set_error_if_cancelled (cancellable, 
error);
-                       if (cbdav->priv->ctag_supported || !cbdav->priv->webdav)
+                       if (cbdav->priv->ctag_supported || !webdav) {
+                               g_clear_object (&webdav);
                                return FALSE;
+                       }
                } else if (!is_repeat && new_sync_tag && last_sync_tag && g_strcmp0 (last_sync_tag, 
new_sync_tag) == 0) {
                        *out_new_sync_tag = new_sync_tag;
+                       g_clear_object (&webdav);
                        return TRUE;
                }
 
@@ -752,7 +794,7 @@ ecb_caldav_get_changes_sync (ECalMetaBackend *meta_backend,
 
        known_items = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, e_cal_meta_backend_info_free);
 
-       success = e_webdav_session_report_sync (cbdav->priv->webdav, NULL, E_WEBDAV_DEPTH_THIS_AND_CHILDREN, 
xml,
+       success = e_webdav_session_report_sync (webdav, NULL, E_WEBDAV_DEPTH_THIS_AND_CHILDREN, xml,
                ecb_caldav_get_calendar_items_cb, known_items, NULL, NULL, cancellable, &local_error);
 
        g_object_unref (xml);
@@ -793,15 +835,17 @@ ecb_caldav_get_changes_sync (ECalMetaBackend *meta_backend,
                }
 
                do {
-                       success = ecb_caldav_multiget_from_sets_sync (cbdav, &link, &set2, cancellable, 
&local_error);
+                       success = ecb_caldav_multiget_from_sets_sync (cbdav, webdav, &link, &set2, 
cancellable, &local_error);
                } while (success && link);
        }
 
        if (local_error) {
-               ecb_caldav_check_credentials_error (cbdav, local_error);
+               ecb_caldav_check_credentials_error (cbdav, webdav, local_error);
                g_propagate_error (error, local_error);
        }
 
+       g_clear_object (&webdav);
+
        return success;
 }
 
@@ -863,6 +907,7 @@ ecb_caldav_list_existing_sync (ECalMetaBackend *meta_backend,
                               GError **error)
 {
        ECalBackendCalDAV *cbdav;
+       EWebDAVSession *webdav;
        icalcomponent_kind kind;
        EXmlDocument *xml;
        GError *local_error = NULL;
@@ -874,6 +919,7 @@ ecb_caldav_list_existing_sync (ECalMetaBackend *meta_backend,
        *out_existing_objects = NULL;
 
        cbdav = E_CAL_BACKEND_CALDAV (meta_backend);
+
        kind = e_cal_backend_get_kind (E_CAL_BACKEND (cbdav));
 
        xml = e_xml_document_new (E_WEBDAV_NS_CALDAV, "calendar-query");
@@ -917,7 +963,9 @@ ecb_caldav_list_existing_sync (ECalMetaBackend *meta_backend,
        e_xml_document_end_element (xml); /* comp-filter / VCALENDAR */
        e_xml_document_end_element (xml); /* filter */
 
-       success = e_webdav_session_report_sync (cbdav->priv->webdav, NULL, E_WEBDAV_DEPTH_THIS, xml,
+       webdav = ecb_caldav_ref_session (cbdav);
+
+       success = e_webdav_session_report_sync (webdav, NULL, E_WEBDAV_DEPTH_THIS, xml,
                ecb_caldav_extract_existing_cb, out_existing_objects, NULL, NULL, cancellable, &local_error);
 
        g_object_unref (xml);
@@ -926,10 +974,12 @@ ecb_caldav_list_existing_sync (ECalMetaBackend *meta_backend,
                *out_existing_objects = g_slist_reverse (*out_existing_objects);
 
        if (local_error) {
-               ecb_caldav_check_credentials_error (cbdav, local_error);
+               ecb_caldav_check_credentials_error (cbdav, webdav, local_error);
                g_propagate_error (error, local_error);
        }
 
+       g_clear_object (&webdav);
+
        return success;
 }
 
@@ -1000,6 +1050,7 @@ ecb_caldav_load_component_sync (ECalMetaBackend *meta_backend,
                                GError **error)
 {
        ECalBackendCalDAV *cbdav;
+       EWebDAVSession *webdav;
        gchar *uri = NULL, *href = NULL, *etag = NULL, *bytes = NULL;
        gsize length = -1;
        gboolean success = FALSE;
@@ -1010,11 +1061,12 @@ ecb_caldav_load_component_sync (ECalMetaBackend *meta_backend,
        g_return_val_if_fail (out_component != NULL, FALSE);
 
        cbdav = E_CAL_BACKEND_CALDAV (meta_backend);
+       webdav = ecb_caldav_ref_session (cbdav);
 
        if (extra && *extra) {
                uri = g_strdup (extra);
 
-               success = e_webdav_session_get_data_sync (cbdav->priv->webdav, uri, &href, &etag, &bytes, 
&length, cancellable, &local_error);
+               success = e_webdav_session_get_data_sync (webdav, uri, &href, &etag, &bytes, &length, 
cancellable, &local_error);
 
                if (!success) {
                        g_free (uri);
@@ -1025,7 +1077,7 @@ ecb_caldav_load_component_sync (ECalMetaBackend *meta_backend,
        if (!success && cbdav->priv->ctag_supported) {
                gchar *new_sync_tag = NULL;
 
-               if (e_webdav_session_getctag_sync (cbdav->priv->webdav, NULL, &new_sync_tag, cancellable, 
NULL) && new_sync_tag) {
+               if (e_webdav_session_getctag_sync (webdav, NULL, &new_sync_tag, cancellable, NULL) && 
new_sync_tag) {
                        gchar *last_sync_tag;
 
                        last_sync_tag = e_cal_meta_backend_dup_sync_tag (meta_backend);
@@ -1033,6 +1085,7 @@ ecb_caldav_load_component_sync (ECalMetaBackend *meta_backend,
                        /* The calendar didn't change, thus the component cannot be there */
                        if (g_strcmp0 (last_sync_tag, new_sync_tag) == 0) {
                                g_clear_error (&local_error);
+                               g_clear_object (&webdav);
                                g_free (last_sync_tag);
                                g_free (new_sync_tag);
 
@@ -1053,7 +1106,7 @@ ecb_caldav_load_component_sync (ECalMetaBackend *meta_backend,
 
                g_clear_error (&local_error);
 
-               success = e_webdav_session_get_data_sync (cbdav->priv->webdav, uri, &href, &etag, &bytes, 
&length, cancellable, &local_error);
+               success = e_webdav_session_get_data_sync (webdav, uri, &href, &etag, &bytes, &length, 
cancellable, &local_error);
 
                /* Do not try twice with Google, it's either with ".ics" extension or not there.
                   The worst, it counts to the Error requests quota limit. */
@@ -1065,7 +1118,7 @@ ecb_caldav_load_component_sync (ECalMetaBackend *meta_backend,
                        if (uri) {
                                g_clear_error (&local_error);
 
-                               success = e_webdav_session_get_data_sync (cbdav->priv->webdav, uri, &href, 
&etag, &bytes, &length, cancellable, &local_error);
+                               success = e_webdav_session_get_data_sync (webdav, uri, &href, &etag, &bytes, 
&length, cancellable, &local_error);
                        }
                }
        }
@@ -1108,10 +1161,12 @@ ecb_caldav_load_component_sync (ECalMetaBackend *meta_backend,
        g_free (bytes);
 
        if (local_error) {
-               ecb_caldav_check_credentials_error (cbdav, local_error);
+               ecb_caldav_check_credentials_error (cbdav, webdav, local_error);
                g_propagate_error (error, local_error);
        }
 
+       g_clear_object (&webdav);
+
        return success;
 }
 
@@ -1127,6 +1182,7 @@ ecb_caldav_save_component_sync (ECalMetaBackend *meta_backend,
                                GError **error)
 {
        ECalBackendCalDAV *cbdav;
+       EWebDAVSession *webdav;
        icalcomponent *vcalendar, *subcomp;
        gchar *href = NULL, *etag = NULL, *uid = NULL;
        gchar *ical_string = NULL;
@@ -1163,6 +1219,8 @@ ecb_caldav_save_component_sync (ECalMetaBackend *meta_backend,
        ical_string = icalcomponent_as_ical_string_r (vcalendar);
        icalcomponent_free (vcalendar);
 
+       webdav = ecb_caldav_ref_session (cbdav);
+
        if (uid && ical_string && (!overwrite_existing || (extra && *extra))) {
                gboolean force_write = FALSE;
 
@@ -1182,7 +1240,7 @@ ecb_caldav_save_component_sync (ECalMetaBackend *meta_backend,
                        }
                }
 
-               success = e_webdav_session_put_data_sync (cbdav->priv->webdav, (extra && *extra) ? extra : 
href,
+               success = e_webdav_session_put_data_sync (webdav, (extra && *extra) ? extra : href,
                        force_write ? "" : overwrite_existing ? etag : NULL, E_WEBDAV_CONTENT_TYPE_CALENDAR,
                        ical_string, -1, out_new_extra, NULL, cancellable, &local_error);
 
@@ -1200,10 +1258,12 @@ ecb_caldav_save_component_sync (ECalMetaBackend *meta_backend,
        g_free (uid);
 
        if (local_error) {
-               ecb_caldav_check_credentials_error (cbdav, local_error);
+               ecb_caldav_check_credentials_error (cbdav, webdav, local_error);
                g_propagate_error (error, local_error);
        }
 
+       g_clear_object (&webdav);
+
        return success;
 }
 
@@ -1217,6 +1277,7 @@ ecb_caldav_remove_component_sync (ECalMetaBackend *meta_backend,
                                  GError **error)
 {
        ECalBackendCalDAV *cbdav;
+       EWebDAVSession *webdav;
        icalcomponent *icalcomp;
        gchar *etag = NULL;
        gboolean success;
@@ -1242,7 +1303,9 @@ ecb_caldav_remove_component_sync (ECalMetaBackend *meta_backend,
        if (conflict_resolution == E_CONFLICT_RESOLUTION_FAIL)
                etag = e_cal_util_dup_x_property (icalcomp, E_CALDAV_X_ETAG);
 
-       success = e_webdav_session_delete_sync (cbdav->priv->webdav, extra,
+       webdav = ecb_caldav_ref_session (cbdav);
+
+       success = e_webdav_session_delete_sync (webdav, extra,
                NULL, etag, cancellable, &local_error);
 
        if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_NOT_FOUND)) {
@@ -1251,7 +1314,7 @@ ecb_caldav_remove_component_sync (ECalMetaBackend *meta_backend,
                href = ecb_caldav_uid_to_uri (cbdav, uid, ".ics");
                if (href) {
                        g_clear_error (&local_error);
-                       success = e_webdav_session_delete_sync (cbdav->priv->webdav, href,
+                       success = e_webdav_session_delete_sync (webdav, href,
                                NULL, etag, cancellable, &local_error);
 
                        g_free (href);
@@ -1261,7 +1324,7 @@ ecb_caldav_remove_component_sync (ECalMetaBackend *meta_backend,
                        href = ecb_caldav_uid_to_uri (cbdav, uid, NULL);
                        if (href) {
                                g_clear_error (&local_error);
-                               success = e_webdav_session_delete_sync (cbdav->priv->webdav, href,
+                               success = e_webdav_session_delete_sync (webdav, href,
                                        NULL, etag, cancellable, &local_error);
 
                                g_free (href);
@@ -1273,10 +1336,12 @@ ecb_caldav_remove_component_sync (ECalMetaBackend *meta_backend,
        g_free (etag);
 
        if (local_error) {
-               ecb_caldav_check_credentials_error (cbdav, local_error);
+               ecb_caldav_check_credentials_error (cbdav, webdav, local_error);
                g_propagate_error (error, local_error);
        }
 
+       g_clear_object (&webdav);
+
        return success;
 }
 
@@ -1286,15 +1351,22 @@ ecb_caldav_get_ssl_error_details (ECalMetaBackend *meta_backend,
                                  GTlsCertificateFlags *out_certificate_errors)
 {
        ECalBackendCalDAV *cbdav;
+       EWebDAVSession *webdav;
+       gboolean res;
 
        g_return_val_if_fail (E_IS_CAL_BACKEND_CALDAV (meta_backend), FALSE);
 
        cbdav = E_CAL_BACKEND_CALDAV (meta_backend);
+       webdav = ecb_caldav_ref_session (cbdav);
 
-       if (!cbdav->priv->webdav)
+       if (!webdav)
                return FALSE;
 
-       return e_soup_session_get_ssl_error_details (E_SOUP_SESSION (cbdav->priv->webdav), 
out_certificate_pem, out_certificate_errors);
+       res = e_soup_session_get_ssl_error_details (E_SOUP_SESSION (webdav), out_certificate_pem, 
out_certificate_errors);
+
+       g_clear_object (&webdav);
+
+       return res;
 }
 
 static gboolean
@@ -1360,6 +1432,7 @@ ecb_caldav_receive_schedule_outbox_url_sync (ECalBackendCalDAV *cbdav,
                                             GError **error)
 {
        EXmlDocument *xml;
+       EWebDAVSession *webdav;
        gchar *owner_href = NULL, *schedule_outbox_url = NULL;
        gboolean success;
 
@@ -1373,12 +1446,15 @@ ecb_caldav_receive_schedule_outbox_url_sync (ECalBackendCalDAV *cbdav,
        e_xml_document_add_empty_element (xml, NULL, "owner");
        e_xml_document_end_element (xml); /* prop */
 
-       success = e_webdav_session_propfind_sync (cbdav->priv->webdav, NULL, E_WEBDAV_DEPTH_THIS, xml,
+       webdav = ecb_caldav_ref_session (cbdav);
+
+       success = e_webdav_session_propfind_sync (webdav, NULL, E_WEBDAV_DEPTH_THIS, xml,
                ecb_caldav_propfind_get_owner_cb, &owner_href, cancellable, error);
 
        g_object_unref (xml);
 
        if (!success || !owner_href || !*owner_href) {
+               g_clear_object (&webdav);
                g_free (owner_href);
                return FALSE;
        }
@@ -1386,6 +1462,7 @@ ecb_caldav_receive_schedule_outbox_url_sync (ECalBackendCalDAV *cbdav,
        xml = e_xml_document_new (E_WEBDAV_NS_DAV, "propfind");
        if (!xml) {
                g_warn_if_fail (xml != NULL);
+               g_clear_object (&webdav);
                g_free (owner_href);
                return FALSE;
        }
@@ -1396,9 +1473,10 @@ ecb_caldav_receive_schedule_outbox_url_sync (ECalBackendCalDAV *cbdav,
        e_xml_document_add_empty_element (xml, E_WEBDAV_NS_CALDAV, "schedule-outbox-URL");
        e_xml_document_end_element (xml); /* prop */
 
-       success = e_webdav_session_propfind_sync (cbdav->priv->webdav, owner_href, E_WEBDAV_DEPTH_THIS, xml,
+       success = e_webdav_session_propfind_sync (webdav, owner_href, E_WEBDAV_DEPTH_THIS, xml,
                ecb_caldav_propfind_get_schedule_outbox_url_cb, &schedule_outbox_url, cancellable, error);
 
+       g_clear_object (&webdav);
        g_object_unref (xml);
        g_free (owner_href);
 
@@ -1526,6 +1604,7 @@ ecb_caldav_get_free_busy_from_schedule_outbox_sync (ECalBackendCalDAV *cbdav,
        ECalComponentOrganizer organizer = { NULL };
        ESourceAuthentication *auth_extension;
        ESource *source;
+       EWebDAVSession *webdav;
        struct icaltimetype dtvalue;
        icaltimezone *utc;
        gchar *str;
@@ -1620,7 +1699,9 @@ ecb_caldav_get_free_busy_from_schedule_outbox_sync (ECalBackendCalDAV *cbdav,
        icalcomponent_free (icalcomp);
        g_object_unref (comp);
 
-       if (e_webdav_session_post_sync (cbdav->priv->webdav, cbdav->priv->schedule_outbox_url, str, -1, NULL, 
&response, cancellable, &local_error) &&
+       webdav = ecb_caldav_ref_session (cbdav);
+
+       if (e_webdav_session_post_sync (webdav, cbdav->priv->schedule_outbox_url, str, -1, NULL, &response, 
cancellable, &local_error) &&
            response) {
                /* parse returned xml */
                xmlDocPtr doc;
@@ -1689,6 +1770,7 @@ ecb_caldav_get_free_busy_from_schedule_outbox_sync (ECalBackendCalDAV *cbdav,
                        xmlFreeDoc (doc);
        }
 
+       g_clear_object (&webdav);
        if (response)
                g_byte_array_free (response, TRUE);
        g_free (str);
@@ -1708,6 +1790,7 @@ ecb_caldav_get_free_busy_from_principal_sync (ECalBackendCalDAV *cbdav,
                                              GCancellable *cancellable,
                                              GError **error)
 {
+       EWebDAVSession *webdav;
        EWebDAVResource *resource;
        GSList *principals = NULL;
        EXmlDocument *xml;
@@ -1720,13 +1803,17 @@ ecb_caldav_get_free_busy_from_principal_sync (ECalBackendCalDAV *cbdav,
        g_return_val_if_fail (usermail != NULL, FALSE);
        g_return_val_if_fail (out_freebusy != NULL, FALSE);
 
-       if (!e_webdav_session_principal_property_search_sync (cbdav->priv->webdav, NULL, TRUE,
+       webdav = ecb_caldav_ref_session (cbdav);
+
+       if (!e_webdav_session_principal_property_search_sync (webdav, NULL, TRUE,
                E_WEBDAV_NS_CALDAV, "calendar-user-address-set", usermail, &principals, cancellable, error)) {
+               g_clear_object (&webdav);
                return FALSE;
        }
 
        if (!principals || principals->next || !principals->data) {
                g_slist_free_full (principals, e_webdav_resource_free);
+               g_clear_object (&webdav);
                return FALSE;
        }
 
@@ -1736,6 +1823,7 @@ ecb_caldav_get_free_busy_from_principal_sync (ECalBackendCalDAV *cbdav,
        g_slist_free_full (principals, e_webdav_resource_free);
 
        if (!href || !*href) {
+               g_clear_object (&webdav);
                g_free (href);
                return FALSE;
        }
@@ -1747,8 +1835,9 @@ ecb_caldav_get_free_busy_from_principal_sync (ECalBackendCalDAV *cbdav,
        e_xml_document_add_attribute_time (xml, NULL, "end", end);
        e_xml_document_end_element (xml); /* time-range */
 
-       success = e_webdav_session_report_sync (cbdav->priv->webdav, NULL, E_WEBDAV_DEPTH_INFINITY, xml, 
NULL, NULL, &content_type, &content, cancellable, error);
+       success = e_webdav_session_report_sync (webdav, NULL, E_WEBDAV_DEPTH_INFINITY, xml, NULL, NULL, 
&content_type, &content, cancellable, error);
 
+       g_clear_object (&webdav);
        g_object_unref (xml);
 
        if (success && content_type && content && content->data && content->len &&
@@ -1811,24 +1900,29 @@ ecb_caldav_get_free_busy_sync (ECalBackendSync *sync_backend,
                               GError **error)
 {
        ECalBackendCalDAV *cbdav;
+       EWebDAVSession *webdav;
 
        g_return_if_fail (E_IS_CAL_BACKEND_CALDAV (sync_backend));
        g_return_if_fail (out_freebusy != NULL);
 
        cbdav = E_CAL_BACKEND_CALDAV (sync_backend);
+       webdav = ecb_caldav_ref_session (cbdav);
 
-       if (e_backend_get_online (E_BACKEND (cbdav)) &&
-           cbdav->priv->webdav) {
+       if (e_backend_get_online (E_BACKEND (cbdav)) && webdav) {
                const GSList *link;
                GError *local_error = NULL;
 
-               if (ecb_caldav_get_free_busy_from_schedule_outbox_sync (cbdav, users, start, end, 
out_freebusy, cancellable, &local_error))
+               if (ecb_caldav_get_free_busy_from_schedule_outbox_sync (cbdav, users, start, end, 
out_freebusy, cancellable, &local_error)) {
+                       g_clear_object (&webdav);
                        return;
+               }
 
                g_clear_error (&local_error);
 
-               if (g_cancellable_set_error_if_cancelled (cancellable, error))
+               if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
+                       g_clear_object (&webdav);
                        return;
+               }
 
                *out_freebusy = NULL;
 
@@ -1839,10 +1933,14 @@ ecb_caldav_get_free_busy_sync (ECalBackendSync *sync_backend,
 
                g_clear_error (&local_error);
 
-               if (*out_freebusy || g_cancellable_set_error_if_cancelled (cancellable, error))
+               if (*out_freebusy || g_cancellable_set_error_if_cancelled (cancellable, error)) {
+                       g_clear_object (&webdav);
                        return;
+               }
        }
 
+       g_clear_object (&webdav);
+
        /* Chain up to parent's method. */
        E_CAL_BACKEND_SYNC_CLASS (e_cal_backend_caldav_parent_class)->get_free_busy_sync (sync_backend, cal, 
cancellable,
                users, start, end, out_freebusy, error);
@@ -1928,7 +2026,9 @@ e_cal_backend_caldav_dispose (GObject *object)
 {
        ECalBackendCalDAV *cbdav = E_CAL_BACKEND_CALDAV (object);
 
+       g_mutex_lock (&cbdav->priv->webdav_lock);
        g_clear_object (&cbdav->priv->webdav);
+       g_mutex_unlock (&cbdav->priv->webdav_lock);
 
        /* Chain up to parent's method. */
        G_OBJECT_CLASS (e_cal_backend_caldav_parent_class)->dispose (object);
@@ -1940,6 +2040,7 @@ e_cal_backend_caldav_finalize (GObject *object)
        ECalBackendCalDAV *cbdav = E_CAL_BACKEND_CALDAV (object);
 
        g_clear_pointer (&cbdav->priv->schedule_outbox_url, g_free);
+       g_mutex_clear (&cbdav->priv->webdav_lock);
 
        /* Chain up to parent's method. */
        G_OBJECT_CLASS (e_cal_backend_caldav_parent_class)->finalize (object);
@@ -1949,6 +2050,8 @@ static void
 e_cal_backend_caldav_init (ECalBackendCalDAV *cbdav)
 {
        cbdav->priv = G_TYPE_INSTANCE_GET_PRIVATE (cbdav, E_TYPE_CAL_BACKEND_CALDAV, 
ECalBackendCalDAVPrivate);
+
+       g_mutex_init (&cbdav->priv->webdav_lock);
 }
 
 static void
diff --git a/src/calendar/backends/gtasks/e-cal-backend-gtasks.c 
b/src/calendar/backends/gtasks/e-cal-backend-gtasks.c
index 3a97bc160..5f0e005c9 100644
--- a/src/calendar/backends/gtasks/e-cal-backend-gtasks.c
+++ b/src/calendar/backends/gtasks/e-cal-backend-gtasks.c
@@ -42,6 +42,7 @@ struct _ECalBackendGTasksPrivate {
        GDataAuthorizer *authorizer;
        GDataTasksService *service;
        GDataTasksTasklist *tasklist;
+       GRecMutex conn_lock;
        GHashTable *preloaded; /* gchar *uid ~> ECalComponent * */
        gboolean bad_request_for_timed_query;
 };
@@ -255,22 +256,26 @@ ecb_gtasks_comp_to_gdata (ECalComponent *comp,
 }
 
 static gboolean
-ecb_gtasks_is_authorized (ECalBackendGTasks *cbgtasks)
+ecb_gtasks_is_authorized_locked (ECalBackendGTasks *cbgtasks)
 {
+       gboolean res;
+
        g_return_val_if_fail (E_IS_CAL_BACKEND_GTASKS (cbgtasks), FALSE);
 
        if (!cbgtasks->priv->service ||
            !cbgtasks->priv->tasklist)
                return FALSE;
 
-       return gdata_service_is_authorized (GDATA_SERVICE (cbgtasks->priv->service));
+       res = gdata_service_is_authorized (GDATA_SERVICE (cbgtasks->priv->service));
+
+       return res;
 }
 
 static gboolean
-ecb_gtasks_request_authorization (ECalBackendGTasks *cbgtasks,
-                                 const ENamedParameters *credentials,
-                                 GCancellable *cancellable,
-                                 GError **error)
+ecb_gtasks_request_authorization_locked (ECalBackendGTasks *cbgtasks,
+                                        const ENamedParameters *credentials,
+                                        GCancellable *cancellable,
+                                        GError **error)
 {
        /* Make sure we have the GDataService configured
         * before requesting authorization. */
@@ -314,9 +319,9 @@ ecb_gtasks_request_authorization (ECalBackendGTasks *cbgtasks,
 }
 
 static gboolean
-ecb_gtasks_prepare_tasklist (ECalBackendGTasks *cbgtasks,
-                            GCancellable *cancellable,
-                            GError **error)
+ecb_gtasks_prepare_tasklist_locked (ECalBackendGTasks *cbgtasks,
+                                   GCancellable *cancellable,
+                                   GError **error)
 {
        ESourceResource *resource;
        ESource *source;
@@ -432,14 +437,20 @@ ecb_gtasks_connect_sync (ECalMetaBackend *meta_backend,
 
        *out_auth_result = E_SOURCE_AUTHENTICATION_ACCEPTED;
 
-       if (ecb_gtasks_is_authorized (cbgtasks))
+       g_rec_mutex_lock (&cbgtasks->priv->conn_lock);
+
+       if (ecb_gtasks_is_authorized_locked (cbgtasks)) {
+               g_rec_mutex_unlock (&cbgtasks->priv->conn_lock);
                return TRUE;
+       }
 
-       success = ecb_gtasks_request_authorization (cbgtasks, credentials, cancellable, &local_error);
+       success = ecb_gtasks_request_authorization_locked (cbgtasks, credentials, cancellable, &local_error);
        if (success)
                success = gdata_authorizer_refresh_authorization (cbgtasks->priv->authorizer, cancellable, 
&local_error);
        if (success)
-               success = ecb_gtasks_prepare_tasklist (cbgtasks, cancellable, &local_error);
+               success = ecb_gtasks_prepare_tasklist_locked (cbgtasks, cancellable, &local_error);
+
+       g_rec_mutex_unlock (&cbgtasks->priv->conn_lock);
 
        if (!success) {
                if (g_error_matches (local_error, GDATA_SERVICE_ERROR, 
GDATA_SERVICE_ERROR_AUTHENTICATION_REQUIRED)) {
@@ -469,20 +480,24 @@ ecb_gtasks_disconnect_sync (ECalMetaBackend *meta_backend,
 
        cbgtasks = E_CAL_BACKEND_GTASKS (meta_backend);
 
+       g_rec_mutex_lock (&cbgtasks->priv->conn_lock);
+
        g_clear_object (&cbgtasks->priv->service);
        g_clear_object (&cbgtasks->priv->authorizer);
        g_clear_object (&cbgtasks->priv->tasklist);
 
+       g_rec_mutex_unlock (&cbgtasks->priv->conn_lock);
+
        return TRUE;
 }
 
 static gboolean
-ecb_gtasks_check_tasklist_changed_sync (ECalBackendGTasks *cbgtasks,
-                                       const gchar *last_sync_tag,
-                                       gboolean *out_changed,
-                                       gint64 *out_taskslist_time,
-                                       GCancellable *cancellable,
-                                       GError **error)
+ecb_gtasks_check_tasklist_changed_locked_sync (ECalBackendGTasks *cbgtasks,
+                                              const gchar *last_sync_tag,
+                                              gboolean *out_changed,
+                                              gint64 *out_taskslist_time,
+                                              GCancellable *cancellable,
+                                              GError **error)
 {
        GDataFeed *feed;
        gchar *id = NULL;
@@ -575,11 +590,17 @@ ecb_gtasks_get_changes_sync (ECalMetaBackend *meta_backend,
        *out_modified_objects = NULL;
        *out_removed_objects = NULL;
 
-       if (!ecb_gtasks_check_tasklist_changed_sync (cbgtasks, last_sync_tag, &changed, &taskslist_time, 
cancellable, error))
+       g_rec_mutex_lock (&cbgtasks->priv->conn_lock);
+
+       if (!ecb_gtasks_check_tasklist_changed_locked_sync (cbgtasks, last_sync_tag, &changed, 
&taskslist_time, cancellable, error)) {
+               g_rec_mutex_unlock (&cbgtasks->priv->conn_lock);
                return FALSE;
+       }
 
-       if (!changed)
+       if (!changed) {
+               g_rec_mutex_unlock (&cbgtasks->priv->conn_lock);
                return TRUE;
+       }
 
        cal_cache = e_cal_meta_backend_ref_cache (meta_backend);
 
@@ -704,6 +725,7 @@ ecb_gtasks_get_changes_sync (ECalMetaBackend *meta_backend,
 #endif
        }
 
+       g_rec_mutex_unlock (&cbgtasks->priv->conn_lock);
        g_clear_object (&tasks_query);
        g_clear_object (&feed);
 
@@ -825,11 +847,15 @@ ecb_gtasks_save_component_sync (ECalMetaBackend *meta_backend,
                return FALSE;
        }
 
+       g_rec_mutex_lock (&cbgtasks->priv->conn_lock);
+
        if (overwrite_existing)
                new_task = gdata_tasks_service_update_task (cbgtasks->priv->service, comp_task, cancellable, 
error);
        else
                new_task = gdata_tasks_service_insert_task (cbgtasks->priv->service, comp_task, 
cbgtasks->priv->tasklist, cancellable, error);
 
+       g_rec_mutex_unlock (&cbgtasks->priv->conn_lock);
+
        g_object_unref (comp_task);
 
        if (!new_task)
@@ -896,10 +922,13 @@ ecb_gtasks_remove_component_sync (ECalMetaBackend *meta_backend,
                return FALSE;
        }
 
+       g_rec_mutex_lock (&cbgtasks->priv->conn_lock);
+
        /* Ignore protocol errors here, libgdata 0.15.1 results with "Error code 204 when deleting an entry: 
No Content",
           while the delete succeeded */
        if (!gdata_tasks_service_delete_task (cbgtasks->priv->service, task, cancellable, &local_error) &&
            !g_error_matches (local_error, GDATA_SERVICE_ERROR, GDATA_SERVICE_ERROR_PROTOCOL_ERROR)) {
+               g_rec_mutex_unlock (&cbgtasks->priv->conn_lock);
                g_object_unref (cached_comp);
                g_object_unref (task);
                g_propagate_error (error, local_error);
@@ -909,6 +938,7 @@ ecb_gtasks_remove_component_sync (ECalMetaBackend *meta_backend,
                g_clear_error (&local_error);
        }
 
+       g_rec_mutex_unlock (&cbgtasks->priv->conn_lock);
        g_object_unref (cached_comp);
        g_object_unref (task);
 
@@ -927,8 +957,13 @@ ecb_gtasks_requires_reconnect (ECalMetaBackend *meta_backend)
        g_return_val_if_fail (E_IS_CAL_BACKEND_GTASKS (meta_backend), FALSE);
 
        cbgtasks = E_CAL_BACKEND_GTASKS (meta_backend);
-       if (!cbgtasks->priv->tasklist)
+
+       g_rec_mutex_lock (&cbgtasks->priv->conn_lock);
+
+       if (!cbgtasks->priv->tasklist) {
+               g_rec_mutex_unlock (&cbgtasks->priv->conn_lock);
                return TRUE;
+       }
 
        source = e_backend_get_source (E_BACKEND (cbgtasks));
        resource = e_source_get_extension (source, E_SOURCE_EXTENSION_RESOURCE);
@@ -937,6 +972,7 @@ ecb_gtasks_requires_reconnect (ECalMetaBackend *meta_backend)
        changed = id && *id && g_strcmp0 (id, gdata_entry_get_id (GDATA_ENTRY (cbgtasks->priv->tasklist))) != 
0 &&
                g_strcmp0 (GTASKS_DEFAULT_TASKLIST_NAME, gdata_entry_get_id (GDATA_ENTRY 
(cbgtasks->priv->tasklist))) != 0;
 
+       g_rec_mutex_unlock (&cbgtasks->priv->conn_lock);
        g_free (id);
 
        return changed;
@@ -969,6 +1005,8 @@ e_cal_backend_gtasks_init (ECalBackendGTasks *cbgtasks)
        cbgtasks->priv = G_TYPE_INSTANCE_GET_PRIVATE (cbgtasks, E_TYPE_CAL_BACKEND_GTASKS, 
ECalBackendGTasksPrivate);
        cbgtasks->priv->preloaded = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
        cbgtasks->priv->bad_request_for_timed_query = FALSE;
+
+       g_rec_mutex_init (&cbgtasks->priv->conn_lock);
 }
 
 static void
@@ -996,10 +1034,14 @@ ecb_gtasks_dispose (GObject *object)
 {
        ECalBackendGTasks *cbgtasks = E_CAL_BACKEND_GTASKS (object);
 
+       g_rec_mutex_lock (&cbgtasks->priv->conn_lock);
+
        g_clear_object (&cbgtasks->priv->service);
        g_clear_object (&cbgtasks->priv->authorizer);
        g_clear_object (&cbgtasks->priv->tasklist);
 
+       g_rec_mutex_unlock (&cbgtasks->priv->conn_lock);
+
        g_hash_table_destroy (cbgtasks->priv->preloaded);
        cbgtasks->priv->preloaded = NULL;
 
@@ -1007,6 +1049,17 @@ ecb_gtasks_dispose (GObject *object)
        G_OBJECT_CLASS (e_cal_backend_gtasks_parent_class)->dispose (object);
 }
 
+static void
+ecb_gtasks_finalize (GObject *object)
+{
+       ECalBackendGTasks *cbgtasks = E_CAL_BACKEND_GTASKS (object);
+
+       g_rec_mutex_clear (&cbgtasks->priv->conn_lock);
+
+       /* Chain up to parent's method. */
+       G_OBJECT_CLASS (e_cal_backend_gtasks_parent_class)->finalize (object);
+}
+
 static void
 e_cal_backend_gtasks_class_init (ECalBackendGTasksClass *klass)
 {
@@ -1031,4 +1084,5 @@ e_cal_backend_gtasks_class_init (ECalBackendGTasksClass *klass)
        object_class = G_OBJECT_CLASS (klass);
        object_class->constructed = ecb_gtasks_constructed;
        object_class->dispose = ecb_gtasks_dispose;
+       object_class->finalize = ecb_gtasks_finalize;
 }
diff --git a/src/calendar/backends/http/e-cal-backend-http.c b/src/calendar/backends/http/e-cal-backend-http.c
index cbeb2d87c..8ede6054d 100644
--- a/src/calendar/backends/http/e-cal-backend-http.c
+++ b/src/calendar/backends/http/e-cal-backend-http.c
@@ -39,6 +39,7 @@ struct _ECalBackendHttpPrivate {
 
        SoupRequestHTTP *request;
        GInputStream *input_stream;
+       GRecMutex conn_lock;
        GHashTable *components; /* gchar *uid ~> icalcomponent * */
 };
 
@@ -119,8 +120,12 @@ ecb_http_connect_sync (ECalMetaBackend *meta_backend,
 
        cbhttp = E_CAL_BACKEND_HTTP (meta_backend);
 
-       if (cbhttp->priv->request && cbhttp->priv->input_stream)
+       g_rec_mutex_lock (&cbhttp->priv->conn_lock);
+
+       if (cbhttp->priv->request && cbhttp->priv->input_stream) {
+               g_rec_mutex_unlock (&cbhttp->priv->conn_lock);
                return TRUE;
+       }
 
        source = e_backend_get_source (E_BACKEND (meta_backend));
 
@@ -130,6 +135,7 @@ ecb_http_connect_sync (ECalMetaBackend *meta_backend,
        uri = ecb_http_dup_uri (cbhttp);
 
        if (!uri || !*uri) {
+               g_rec_mutex_unlock (&cbhttp->priv->conn_lock);
                g_free (uri);
 
                g_propagate_error (error, EDC_ERROR_EX (OtherError, _("URI not set")));
@@ -214,6 +220,7 @@ ecb_http_connect_sync (ECalMetaBackend *meta_backend,
                g_clear_object (&input_stream);
        }
 
+       g_rec_mutex_unlock (&cbhttp->priv->conn_lock);
        g_clear_error (&local_error);
        g_free (uri);
 
@@ -232,6 +239,8 @@ ecb_http_disconnect_sync (ECalMetaBackend *meta_backend,
 
        cbhttp = E_CAL_BACKEND_HTTP (meta_backend);
 
+       g_rec_mutex_lock (&cbhttp->priv->conn_lock);
+
        g_clear_object (&cbhttp->priv->input_stream);
        g_clear_object (&cbhttp->priv->request);
 
@@ -243,6 +252,8 @@ ecb_http_disconnect_sync (ECalMetaBackend *meta_backend,
                cbhttp->priv->components = NULL;
        }
 
+       g_rec_mutex_unlock (&cbhttp->priv->conn_lock);
+
        source = e_backend_get_source (E_BACKEND (meta_backend));
        e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_DISCONNECTED);
 
@@ -305,7 +316,10 @@ ecb_http_get_changes_sync (ECalMetaBackend *meta_backend,
 
        cbhttp = E_CAL_BACKEND_HTTP (meta_backend);
 
+       g_rec_mutex_lock (&cbhttp->priv->conn_lock);
+
        if (!cbhttp->priv->request || !cbhttp->priv->input_stream) {
+               g_rec_mutex_unlock (&cbhttp->priv->conn_lock);
                g_propagate_error (error, EDC_ERROR (RepositoryOffline));
                return FALSE;
        }
@@ -318,6 +332,7 @@ ecb_http_get_changes_sync (ECalMetaBackend *meta_backend,
                if (new_etag && !*new_etag) {
                        new_etag = NULL;
                } else if (new_etag && g_strcmp0 (last_sync_tag, new_etag) == 0) {
+                       g_rec_mutex_unlock (&cbhttp->priv->conn_lock);
                        /* Nothing changed */
                        g_object_unref (message);
 
@@ -334,6 +349,8 @@ ecb_http_get_changes_sync (ECalMetaBackend *meta_backend,
        icalstring = ecb_http_read_stream_sync (cbhttp->priv->input_stream,
                soup_request_get_content_length (SOUP_REQUEST (cbhttp->priv->request)), cancellable, error);
 
+       g_rec_mutex_unlock (&cbhttp->priv->conn_lock);
+
        if (!icalstring) {
                /* The error is already set */
                e_cal_meta_backend_empty_cache_sync (meta_backend, cancellable, NULL);
@@ -582,19 +599,21 @@ e_cal_backend_http_dispose (GObject *object)
 
        cbhttp = E_CAL_BACKEND_HTTP (object);
 
+       g_rec_mutex_lock (&cbhttp->priv->conn_lock);
+
        g_clear_object (&cbhttp->priv->request);
        g_clear_object (&cbhttp->priv->input_stream);
 
-       if (cbhttp->priv->session) {
+       if (cbhttp->priv->session)
                soup_session_abort (SOUP_SESSION (cbhttp->priv->session));
-               g_clear_object (&cbhttp->priv->session);
-       }
 
        if (cbhttp->priv->components) {
                g_hash_table_destroy (cbhttp->priv->components);
                cbhttp->priv->components = NULL;
        }
 
+       g_rec_mutex_unlock (&cbhttp->priv->conn_lock);
+
        /* Chain up to parent's method. */
        G_OBJECT_CLASS (e_cal_backend_http_parent_class)->dispose (object);
 }
@@ -605,6 +624,7 @@ e_cal_backend_http_finalize (GObject *object)
        ECalBackendHttp *cbhttp = E_CAL_BACKEND_HTTP (object);
 
        g_clear_object (&cbhttp->priv->session);
+       g_rec_mutex_clear (&cbhttp->priv->conn_lock);
 
        /* Chain up to parent's method. */
        G_OBJECT_CLASS (e_cal_backend_http_parent_class)->finalize (object);
@@ -615,6 +635,8 @@ e_cal_backend_http_init (ECalBackendHttp *cbhttp)
 {
        cbhttp->priv = G_TYPE_INSTANCE_GET_PRIVATE (cbhttp, E_TYPE_CAL_BACKEND_HTTP, ECalBackendHttpPrivate);
 
+       g_rec_mutex_init (&cbhttp->priv->conn_lock);
+
        e_cal_backend_set_writable (E_CAL_BACKEND (cbhttp), FALSE);
 }
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]