[evolution-data-server] [CalDAV/CardDAV] Improve logic for object load from the server



commit 873ac14923c8a26629ad0f4fae355a1585fe3af1
Author: Milan Crha <mcrha redhat com>
Date:   Wed Oct 11 17:38:51 2017 +0200

    [CalDAV/CardDAV] Improve logic for object load from the server
    
    One change related specifically for Google servers, to not try twice when
    the first load fails with "404 Not Found".
    
    The other change is to verify that the collection on the server did change
    meanwhile. If it did, then it's possible it was due to the component which
    is not in the local cache yes, thus try to load it. If the collection did
    not change, then it means the local cache is up-to-date with the server
    content, thus the to-be-loaded object is not on the server, thus no need
    to poke it and receive failure anyway. This works only if the server
    supports getctag extension.

 .../backends/webdav/e-book-backend-webdav.c        |   39 +++++++++++++++++++-
 .../libedata-book/e-book-meta-backend.c            |   37 +++++++++++++++++++
 .../libedata-book/e-book-meta-backend.h            |    1 +
 .../backends/caldav/e-cal-backend-caldav.c         |   30 +++++++++++++++-
 src/calendar/libedata-cal/e-cal-meta-backend.c     |   37 +++++++++++++++++++
 src/calendar/libedata-cal/e-cal-meta-backend.h     |    1 +
 tests/libedata-book/test-book-meta-backend.c       |   25 +++++++++----
 tests/libedata-cal/test-cal-meta-backend.c         |   25 +++++++++----
 8 files changed, 178 insertions(+), 17 deletions(-)
---
diff --git a/src/addressbook/backends/webdav/e-book-backend-webdav.c 
b/src/addressbook/backends/webdav/e-book-backend-webdav.c
index b4a16fa..b3fe648 100644
--- a/src/addressbook/backends/webdav/e-book-backend-webdav.c
+++ b/src/addressbook/backends/webdav/e-book-backend-webdav.c
@@ -41,6 +41,9 @@ struct _EBookBackendWebDAVPrivate {
 
        /* support for 'getctag' extension */
        gboolean ctag_supported;
+
+       /* Whether talking to the Google server */
+       gboolean is_google;
 };
 
 G_DEFINE_TYPE (EBookBackendWebDAV, e_book_backend_webdav, E_TYPE_BOOK_META_BACKEND)
@@ -163,6 +166,10 @@ ebb_webdav_connect_sync (EBookMetaBackend *meta_backend,
                        e_book_backend_set_writable (E_BOOK_BACKEND (bbdav), is_writable);
 
                        e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_CONNECTED);
+
+                       bbdav->priv->is_google = soup_uri && soup_uri->host && (
+                               g_ascii_strcasecmp (soup_uri->host, "www.google.com") == 0 ||
+                               g_ascii_strcasecmp (soup_uri->host, "apidata.googleusercontent.com") == 0);
                } else {
                        gchar *uri;
 
@@ -852,14 +859,42 @@ 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) {
+                       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_error (&local_error);
+                               g_free (last_sync_tag);
+                               g_free (new_sync_tag);
+
+                               g_propagate_error (error, EDB_ERROR (E_DATA_BOOK_STATUS_CONTACT_NOT_FOUND));
+
+                               return FALSE;
+                       }
+
+                       g_free (last_sync_tag);
+               }
+
+               g_free (new_sync_tag);
+       }
+
        if (!success) {
-               uri = ebb_webdav_uid_to_uri (bbdav, uid, ".vcf");
+               uri = ebb_webdav_uid_to_uri (bbdav, uid, bbdav->priv->is_google ? NULL : ".vcf");
                g_return_val_if_fail (uri != NULL, FALSE);
 
                g_clear_error (&local_error);
 
                success = e_webdav_session_get_data_sync (bbdav->priv->webdav, uri, &href, &etag, &bytes, 
&length, cancellable, &local_error);
-               if (!success && !g_cancellable_is_cancelled (cancellable) &&
+
+               /* Do not try twice with Google, it's either without extension or not there.
+                  The worst, it counts to the Error requests quota limit. */
+               if (!success && !bbdav->priv->is_google && !g_cancellable_is_cancelled (cancellable) &&
                    g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_NOT_FOUND)) {
                        g_free (uri);
                        uri = ebb_webdav_uid_to_uri (bbdav, uid, NULL);
diff --git a/src/addressbook/libedata-book/e-book-meta-backend.c 
b/src/addressbook/libedata-book/e-book-meta-backend.c
index 20767fc..860a42a 100644
--- a/src/addressbook/libedata-book/e-book-meta-backend.c
+++ b/src/addressbook/libedata-book/e-book-meta-backend.c
@@ -2569,6 +2569,43 @@ e_book_meta_backend_get_connected_writable (EBookMetaBackend *meta_backend)
        return result;
 }
 
+/**
+ * e_book_meta_backend_dup_sync_tag:
+ * @meta_backend: an #EBookMetaBackend
+ *
+ * Returns the last known synchronization tag, the same as used to
+ * call e_book_meta_backend_get_changes_sync().
+ *
+ * Free the returned string with g_free(), when no longer needed.
+ *
+ * Returns: (transfer full) (nullable): The last known synchronization tag,
+ *    or %NULL, when none is stored.
+ *
+ * Since: 3.28
+ **/
+gchar *
+e_book_meta_backend_dup_sync_tag (EBookMetaBackend *meta_backend)
+{
+       EBookCache *book_cache;
+       gchar *sync_tag;
+
+       g_return_val_if_fail (E_IS_BOOK_META_BACKEND (meta_backend), NULL);
+
+       book_cache = e_book_meta_backend_ref_cache (meta_backend);
+       if (!book_cache)
+               return NULL;
+
+       sync_tag = e_cache_dup_key (E_CACHE (book_cache), EBMB_KEY_SYNC_TAG, NULL);
+       if (sync_tag && !*sync_tag) {
+               g_free (sync_tag);
+               sync_tag = NULL;
+       }
+
+       g_clear_object (&book_cache);
+
+       return sync_tag;
+}
+
 static void
 ebmb_cache_revision_changed_cb (ECache *cache,
                                gpointer user_data)
diff --git a/src/addressbook/libedata-book/e-book-meta-backend.h 
b/src/addressbook/libedata-book/e-book-meta-backend.h
index 4e82724..67adcb7 100644
--- a/src/addressbook/libedata-book/e-book-meta-backend.h
+++ b/src/addressbook/libedata-book/e-book-meta-backend.h
@@ -185,6 +185,7 @@ void                e_book_meta_backend_set_connected_writable
                                                 gboolean value);
 gboolean       e_book_meta_backend_get_connected_writable
                                                (EBookMetaBackend *meta_backend);
+gchar *                e_book_meta_backend_dup_sync_tag(EBookMetaBackend *meta_backend);
 void           e_book_meta_backend_set_cache   (EBookMetaBackend *meta_backend,
                                                 EBookCache *cache);
 EBookCache *   e_book_meta_backend_ref_cache   (EBookMetaBackend *meta_backend);
diff --git a/src/calendar/backends/caldav/e-cal-backend-caldav.c 
b/src/calendar/backends/caldav/e-cal-backend-caldav.c
index 94a0984..577cf8b 100644
--- a/src/calendar/backends/caldav/e-cal-backend-caldav.c
+++ b/src/calendar/backends/caldav/e-cal-backend-caldav.c
@@ -968,6 +968,31 @@ 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) {
+                       gchar *last_sync_tag;
+
+                       last_sync_tag = e_cal_meta_backend_dup_sync_tag (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_free (last_sync_tag);
+                               g_free (new_sync_tag);
+
+                               g_propagate_error (error, EDC_ERROR (ObjectNotFound));
+
+                               return FALSE;
+                       }
+
+                       g_free (last_sync_tag);
+               }
+
+               g_free (new_sync_tag);
+       }
+
        if (!success) {
                uri = ecb_caldav_uid_to_uri (cbdav, uid, ".ics");
                g_return_val_if_fail (uri != NULL, FALSE);
@@ -975,7 +1000,10 @@ 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);
-               if (!success && !g_cancellable_is_cancelled (cancellable) &&
+
+               /* 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. */
+               if (!success && !cbdav->priv->is_google && !g_cancellable_is_cancelled (cancellable) &&
                    g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_NOT_FOUND)) {
                        g_free (uri);
                        uri = ecb_caldav_uid_to_uri (cbdav, uid, NULL);
diff --git a/src/calendar/libedata-cal/e-cal-meta-backend.c b/src/calendar/libedata-cal/e-cal-meta-backend.c
index e87f218..db6e5c2 100644
--- a/src/calendar/libedata-cal/e-cal-meta-backend.c
+++ b/src/calendar/libedata-cal/e-cal-meta-backend.c
@@ -3332,6 +3332,43 @@ e_cal_meta_backend_get_connected_writable (ECalMetaBackend *meta_backend)
        return result;
 }
 
+/**
+ * e_cal_meta_backend_dup_sync_tag:
+ * @meta_backend: an #ECalMetaBackend
+ *
+ * Returns the last known synchronization tag, the same as used to
+ * call e_cal_meta_backend_get_changes_sync().
+ *
+ * Free the returned string with g_free(), when no longer needed.
+ *
+ * Returns: (transfer full) (nullable): The last known synchronization tag,
+ *    or %NULL, when none is stored.
+ *
+ * Since: 3.28
+ **/
+gchar *
+e_cal_meta_backend_dup_sync_tag (ECalMetaBackend *meta_backend)
+{
+       ECalCache *cal_cache;
+       gchar *sync_tag;
+
+       g_return_val_if_fail (E_IS_CAL_META_BACKEND (meta_backend), NULL);
+
+       cal_cache = e_cal_meta_backend_ref_cache (meta_backend);
+       if (!cal_cache)
+               return NULL;
+
+       sync_tag = e_cache_dup_key (E_CACHE (cal_cache), ECMB_KEY_SYNC_TAG, NULL);
+       if (sync_tag && !*sync_tag) {
+               g_free (sync_tag);
+               sync_tag = NULL;
+       }
+
+       g_clear_object (&cal_cache);
+
+       return sync_tag;
+}
+
 static void
 ecmb_cache_revision_changed_cb (ECache *cache,
                                gpointer user_data)
diff --git a/src/calendar/libedata-cal/e-cal-meta-backend.h b/src/calendar/libedata-cal/e-cal-meta-backend.h
index c8dd2a5..29e51be 100644
--- a/src/calendar/libedata-cal/e-cal-meta-backend.h
+++ b/src/calendar/libedata-cal/e-cal-meta-backend.h
@@ -182,6 +182,7 @@ void                e_cal_meta_backend_set_connected_writable
                                                 gboolean value);
 gboolean       e_cal_meta_backend_get_connected_writable
                                                (ECalMetaBackend *meta_backend);
+gchar *                e_cal_meta_backend_dup_sync_tag (ECalMetaBackend *meta_backend);
 void           e_cal_meta_backend_set_cache    (ECalMetaBackend *meta_backend,
                                                 ECalCache *cache);
 ECalCache *    e_cal_meta_backend_ref_cache    (ECalMetaBackend *meta_backend);
diff --git a/tests/libedata-book/test-book-meta-backend.c b/tests/libedata-book/test-book-meta-backend.c
index a0de5cb..cdd0683 100644
--- a/tests/libedata-book/test-book-meta-backend.c
+++ b/tests/libedata-book/test-book-meta-backend.c
@@ -297,15 +297,15 @@ e_book_meta_backend_test_get_changes_sync (EBookMetaBackend *meta_backend,
        } else {
                g_assert_nonnull (last_sync_tag);
                g_assert_cmpint (atoi (last_sync_tag), ==, test_backend->sync_tag_index);
+       }
 
-               test_backend->sync_tag_index++;
-               *out_new_sync_tag = g_strdup_printf ("%d", test_backend->sync_tag_index);
+       test_backend->sync_tag_index++;
+       *out_new_sync_tag = g_strdup_printf ("%d", test_backend->sync_tag_index);
 
-               if (test_backend->sync_tag_index == 2)
-                       *out_repeat = TRUE;
-               else if (test_backend->sync_tag_index == 3)
-                       return TRUE;
-       }
+       if (test_backend->sync_tag_index == 2)
+               *out_repeat = TRUE;
+       else if (test_backend->sync_tag_index == 3)
+               return TRUE;
 
        /* Nothing to do here at the moment, left the work to the parent class,
           which calls list_existing_sync() internally. */
@@ -1342,6 +1342,7 @@ test_refresh (EBookMetaBackend *meta_backend)
        ECache *cache;
        guint count;
        EContact *contact;
+       gchar *sync_tag;
        GError *error = NULL;
 
        g_assert_nonnull (meta_backend);
@@ -1379,6 +1380,11 @@ test_refresh (EBookMetaBackend *meta_backend)
 
        ebmb_test_cache_and_server_equal (book_cache, test_backend->contacts, E_CACHE_INCLUDE_DELETED);
 
+       sync_tag = e_book_meta_backend_dup_sync_tag (meta_backend);
+       g_assert_nonnull (sync_tag);
+       g_assert_cmpstr (sync_tag, ==, "1");
+       g_free (sync_tag);
+
        /* Add new contact */
        ebmb_test_add_test_case (test_backend, "custom-5");
 
@@ -1486,6 +1492,11 @@ test_refresh (EBookMetaBackend *meta_backend)
 
        ebmb_test_cache_and_server_equal (book_cache, test_backend->contacts, E_CACHE_INCLUDE_DELETED);
 
+       sync_tag = e_book_meta_backend_dup_sync_tag (meta_backend);
+       g_assert_nonnull (sync_tag);
+       g_assert_cmpstr (sync_tag, ==, "7");
+       g_free (sync_tag);
+
        g_object_unref (book_cache);
 }
 
diff --git a/tests/libedata-cal/test-cal-meta-backend.c b/tests/libedata-cal/test-cal-meta-backend.c
index 2382b09..e313fe9 100644
--- a/tests/libedata-cal/test-cal-meta-backend.c
+++ b/tests/libedata-cal/test-cal-meta-backend.c
@@ -342,15 +342,15 @@ e_cal_meta_backend_test_get_changes_sync (ECalMetaBackend *meta_backend,
        } else {
                g_assert_nonnull (last_sync_tag);
                g_assert_cmpint (atoi (last_sync_tag), ==, test_backend->sync_tag_index);
+       }
 
-               test_backend->sync_tag_index++;
-               *out_new_sync_tag = g_strdup_printf ("%d", test_backend->sync_tag_index);
+       test_backend->sync_tag_index++;
+       *out_new_sync_tag = g_strdup_printf ("%d", test_backend->sync_tag_index);
 
-               if (test_backend->sync_tag_index == 2)
-                       *out_repeat = TRUE;
-               else if (test_backend->sync_tag_index == 3)
-                       return TRUE;
-       }
+       if (test_backend->sync_tag_index == 2)
+               *out_repeat = TRUE;
+       else if (test_backend->sync_tag_index == 3)
+               return TRUE;
 
        /* Nothing to do here at the moment, left the work to the parent class,
           which calls list_existing_sync() internally. */
@@ -2398,6 +2398,7 @@ test_refresh (ECalMetaBackend *meta_backend)
        ECache *cache;
        guint count;
        icalcomponent *icalcomp;
+       gchar *sync_tag;
        GError *error = NULL;
 
        g_assert_nonnull (meta_backend);
@@ -2437,6 +2438,11 @@ test_refresh (ECalMetaBackend *meta_backend)
 
        ecmb_test_cache_and_server_equal (cal_cache, test_backend->vcalendar, E_CACHE_INCLUDE_DELETED);
 
+       sync_tag = e_cal_meta_backend_dup_sync_tag (meta_backend);
+       g_assert_nonnull (sync_tag);
+       g_assert_cmpstr (sync_tag, ==, "1");
+       g_free (sync_tag);
+
        /* Add detached instance, but do not modify the master object, thus it looks like unchanged */
        ecmb_test_add_test_case (test_backend, "event-6-a");
 
@@ -2560,6 +2566,11 @@ test_refresh (ECalMetaBackend *meta_backend)
 
        ecmb_test_cache_and_server_equal (cal_cache, test_backend->vcalendar, E_CACHE_INCLUDE_DELETED);
 
+       sync_tag = e_cal_meta_backend_dup_sync_tag (meta_backend);
+       g_assert_nonnull (sync_tag);
+       g_assert_cmpstr (sync_tag, ==, "7");
+       g_free (sync_tag);
+
        g_object_unref (cal_cache);
 }
 


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