[evolution-data-server] I#260 - DAV: Relax collection's item href comparison



commit 90fadea23ab7712259762ea2874a794aca482e03
Author: Milan Crha <mcrha redhat com>
Date:   Wed Nov 11 13:54:10 2020 +0100

    I#260 - DAV: Relax collection's item href comparison
    
    Closes https://gitlab.gnome.org/GNOME/evolution-data-server/-/issues/260

 .../backends/carddav/e-book-backend-carddav.c      |  7 +-
 .../backends/caldav/e-cal-backend-caldav.c         |  7 +-
 src/libedataserver/e-webdav-session.c              | 81 ++++++++++++++++++++++
 src/libedataserver/e-webdav-session.h              |  2 +
 tests/libedataserver/CMakeLists.txt                |  1 +
 tests/libedataserver/libedataserver-test.c         | 81 ++++++++++++++++++++++
 6 files changed, 175 insertions(+), 4 deletions(-)
---
diff --git a/src/addressbook/backends/carddav/e-book-backend-carddav.c 
b/src/addressbook/backends/carddav/e-book-backend-carddav.c
index e8867f881..393276246 100644
--- a/src/addressbook/backends/carddav/e-book-backend-carddav.c
+++ b/src/addressbook/backends/carddav/e-book-backend-carddav.c
@@ -484,7 +484,7 @@ ebb_carddav_multiget_response_cb (EWebDAVSession *webdav,
                                                if (!nfo)
                                                        continue;
 
-                                               if (g_strcmp0 (nfo->extra, href) == 0) {
+                                               if (e_webdav_session_util_item_href_equal (nfo->extra, href)) 
{
                                                        /* If the server returns data in the same order as it 
had been requested,
                                                           then this speeds up lookup for the matching 
object. */
                                                        if (link == *from_link)
@@ -496,6 +496,9 @@ ebb_carddav_multiget_response_cb (EWebDAVSession *webdav,
                                                }
                                        }
 
+                                       if (!link && e_soup_session_get_log_level (E_SOUP_SESSION (webdav)) 
!= SOUP_LOGGER_LOG_NONE)
+                                               e_util_debug_print ("CardDAV", "Failed to find item with href 
'%s' in known server items\n", href);
+
                                        g_free (dequoted_etag);
                                }
 
@@ -513,7 +516,7 @@ ebb_carddav_multiget_response_cb (EWebDAVSession *webdav,
                        if (!nfo)
                                continue;
 
-                       if (g_strcmp0 (nfo->extra, href) == 0) {
+                       if (e_webdav_session_util_item_href_equal (nfo->extra, href)) {
                                /* If the server returns data in the same order as it had been requested,
                                   then this speeds up lookup for the matching object. */
                                if (link == *from_link)
diff --git a/src/calendar/backends/caldav/e-cal-backend-caldav.c 
b/src/calendar/backends/caldav/e-cal-backend-caldav.c
index 11af2d87d..e50bc0b57 100644
--- a/src/calendar/backends/caldav/e-cal-backend-caldav.c
+++ b/src/calendar/backends/caldav/e-cal-backend-caldav.c
@@ -460,7 +460,7 @@ ecb_caldav_multiget_response_cb (EWebDAVSession *webdav,
                                                if (!nfo)
                                                        continue;
 
-                                               if (g_strcmp0 (nfo->extra, href) == 0) {
+                                               if (e_webdav_session_util_item_href_equal (nfo->extra, href)) 
{
                                                        /* If the server returns data in the same order as it 
had been requested,
                                                           then this speeds up lookup for the matching 
object. */
                                                        if (link == md->from_link)
@@ -472,6 +472,9 @@ ecb_caldav_multiget_response_cb (EWebDAVSession *webdav,
                                                }
                                        }
 
+                                       if (!link && e_soup_session_get_log_level (E_SOUP_SESSION (webdav)) 
!= SOUP_LOGGER_LOG_NONE)
+                                               e_util_debug_print ("CalDAV", "Failed to find item with href 
'%s' in known server items\n", href);
+
                                        g_free (dequoted_etag);
                                }
 
@@ -489,7 +492,7 @@ ecb_caldav_multiget_response_cb (EWebDAVSession *webdav,
                        if (!nfo)
                                continue;
 
-                       if (g_strcmp0 (nfo->extra, href) == 0) {
+                       if (e_webdav_session_util_item_href_equal (nfo->extra, href)) {
                                /* If the server returns data in the same order as it had been requested,
                                   then this speeds up lookup for the matching object. */
                                if (link == md->from_link)
diff --git a/src/libedataserver/e-webdav-session.c b/src/libedataserver/e-webdav-session.c
index 8d970a1cd..ca95ec437 100644
--- a/src/libedataserver/e-webdav-session.c
+++ b/src/libedataserver/e-webdav-session.c
@@ -29,6 +29,7 @@
 #include "evolution-data-server-config.h"
 
 #include <stdio.h>
+#include <string.h>
 #include <glib/gi18n-lib.h>
 
 #include "camel/camel.h"
@@ -5137,3 +5138,83 @@ e_webdav_session_util_free_privileges (GNode *privileges)
        g_node_traverse (privileges, G_PRE_ORDER, G_TRAVERSE_ALL, -1, e_webdav_session_free_in_traverse_cb, 
NULL);
        g_node_destroy (privileges);
 }
+
+/**
+ * e_webdav_session_util_item_href_equal:
+ * @href1: the first href
+ * @href2: the second href
+ *
+ * Compares two hrefs and return whether they reference
+ * the same item on the server. The comparison is done in
+ * a relaxed way, not considering scheme part and comparing
+ * the host name case insensitively, while the path
+ * case sensitively. It also ignores the username/password
+ * information in the hostname part, if it's included.
+ * The function doesn't decode any URI-encoded characters.
+ *
+ * Returns: whether the two href-s reference the same item
+ *
+ * Since: 3.40
+ **/
+gboolean
+e_webdav_session_util_item_href_equal (const gchar *href1,
+                                      const gchar *href2)
+{
+       const gchar *ptr, *from1, *from2, *next1, *next2;
+
+       if (!href1 || !href2)
+               return href1 == href2;
+
+       if (g_strcmp0 (href1, href2) == 0)
+               return TRUE;
+
+       /* skip the scheme part */
+       ptr = strstr (href1, "://");
+       if (ptr)
+               href1 = ptr + 3;
+
+       ptr = strstr (href2, "://");
+       if (ptr)
+               href2 = ptr + 3;
+
+       for (from1 = href1, from2 = href2; from1 && from2; from1 = next1, from2 = next2) {
+               gint len;
+
+               ptr = strchr (from1, '/');
+               if (ptr)
+                       ptr++;
+               next1 = ptr;
+
+               ptr = strchr (from2, '/');
+               if (ptr)
+                       ptr++;
+               next2 = ptr;
+
+               if ((!next1 && next2) || (next1 && !next2))
+                       break;
+
+               len = next1 ? next1 - from1 : strlen (from1);
+
+               if (!len)
+                       len = next2 ? next2 - from2 : strlen (from2);
+
+               /* it's the hostname part */
+               if (from1 == href1) {
+                       /* ignore the username/password part */
+                       ptr = strchr (from1, '@');
+                       if (ptr)
+                               from1 = ptr + 1;
+
+                       ptr = strchr (from2, '@');
+                       if (ptr)
+                               from2 = ptr + 1;
+
+                       if (g_ascii_strncasecmp (from1, from2, len) != 0)
+                               return FALSE;
+               } else if (strncmp (from1, from2, len) != 0) {
+                       return FALSE;
+               }
+       }
+
+       return !from1 && !from2;
+}
diff --git a/src/libedataserver/e-webdav-session.h b/src/libedataserver/e-webdav-session.h
index aba424f3e..a9f6f5b0a 100644
--- a/src/libedataserver/e-webdav-session.h
+++ b/src/libedataserver/e-webdav-session.h
@@ -591,6 +591,8 @@ gboolean    e_webdav_session_principal_property_search_sync
                                                         GError **error);
 gchar *                e_webdav_session_util_maybe_dequote     (gchar *text);
 void           e_webdav_session_util_free_privileges   (GNode *privileges); /* EWebDAVPrivilege * */
+gboolean       e_webdav_session_util_item_href_equal   (const gchar *href1,
+                                                        const gchar *href2);
 
 G_END_DECLS
 
diff --git a/tests/libedataserver/CMakeLists.txt b/tests/libedataserver/CMakeLists.txt
index 13833069a..519745069 100644
--- a/tests/libedataserver/CMakeLists.txt
+++ b/tests/libedataserver/CMakeLists.txt
@@ -19,6 +19,7 @@ set(extra_ldflags
 # Should be kept ordered approximately from least to most difficult/complex
 set(TESTS
        e-source-registry-test
+       libedataserver-test
 )
 
 foreach(_test ${TESTS})
diff --git a/tests/libedataserver/libedataserver-test.c b/tests/libedataserver/libedataserver-test.c
new file mode 100644
index 000000000..8ff11b999
--- /dev/null
+++ b/tests/libedataserver/libedataserver-test.c
@@ -0,0 +1,81 @@
+/*
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "e-test-server-utils.h"
+
+#include <libedataserver/libedataserver.h>
+
+static ETestServerClosure test_closure = { E_TEST_SERVER_NONE, NULL, 0, FALSE, NULL };
+
+static void
+test_webdav_href_compare (ETestServerFixture *fixture,
+                         gconstpointer user_data)
+{
+       struct _hrefs {
+               const gchar *href1;
+               const gchar *href2;
+               gboolean same;
+       } hrefs[] = {
+               { "http://www.gnome.org/";, "http://www.gnome.org/";, TRUE },
+               { "https://www.gnome.org/";, "http://www.gnome.org/";, TRUE },
+               { "http://user www gnome org/", "https://www.gnome.org/";, TRUE },
+               { "http://www.gnome.org/index";, "http://www.gnome.org/";, FALSE },
+               { "http://www.GNOME.org/index";, "http://www.gnome.org/index";, TRUE },
+               { "http://www.GNOME.org/Index";, "http://www.gnome.org/index";, FALSE },
+               { "http://www.gnome.org/index/";, "http://www.gnome.org/index";, FALSE },
+               { "http://www.gnome.org/path/collection/data.ext";, 
"http://www.gnome.org/path/collection/data.ext";, TRUE },
+               { "https://www.gnome.org/path/collection/data.ext";, 
"http://www.gnome.org/path/collection/data.ext";, TRUE },
+               { "http://user www gnome org/path/collection/data.ext", 
"http://www.gnome.org/path/collection/data.ext";, TRUE },
+               { "http://www.gnome.org/Path/collection/data.ext";, 
"http://www.gnome.org/path/collection/data.ext";, FALSE },
+               { "http://www.gnome.org/path/Collection/data.ext";, 
"http://www.gnome.org/path/collection/data.ext";, FALSE },
+               { "http://www.gnome.org/path/collection/Data.ext";, 
"http://www.gnome.org/path/collection/data.ext";, FALSE },
+               { "http://www.GNOME.org/path/collection/data.ext";, 
"http://www.gnome.org/path/collection/data.ext";, TRUE },
+               { "http://www.gnome.org/path/collection/data.ext";, 
"http://www.server.org/path/collection/data.ext";, FALSE },
+               { "https://www.gnome.org";, "https://www.gnome.org/path/collection/data.ext";, FALSE },
+               { "https://www.gnome.org/";, "https://www.gnome.org/path/collection/data.ext";, FALSE },
+               { "https://www.gnome.org/path";, "https://www.gnome.org/path/collection/data.ext";, FALSE },
+               { "https://www.gnome.org/path/";, "https://www.gnome.org/path/collection/data.ext";, FALSE },
+               { "https://www.gnome.org/path/collection";, "https://www.gnome.org/path/collection/data.ext";, 
FALSE },
+               { "https://www.gnome.org/path/collection/";, "https://www.gnome.org/path/collection/data.ext";, 
FALSE }
+       };
+       gint ii;
+
+       for (ii = 0; ii < G_N_ELEMENTS (hrefs); ii++) {
+               if (hrefs[ii].same) {
+                       g_assert_cmpint (ii, ==, e_webdav_session_util_item_href_equal (hrefs[ii].href1, 
hrefs[ii].href2) ? ii : -1);
+                       g_assert_cmpint (ii, ==, e_webdav_session_util_item_href_equal (hrefs[ii].href2, 
hrefs[ii].href1) ? ii : -1);
+               } else {
+                       g_assert_cmpint (ii, !=, e_webdav_session_util_item_href_equal (hrefs[ii].href1, 
hrefs[ii].href2) ? ii : -1);
+                       g_assert_cmpint (ii, !=, e_webdav_session_util_item_href_equal (hrefs[ii].href2, 
hrefs[ii].href1) ? ii : -1);
+               }
+       }
+}
+
+gint
+main (gint argc,
+      gchar **argv)
+{
+       g_test_init (&argc, &argv, NULL);
+       g_test_bug_base ("https://gitlab.gnome.org/GNOME/evolution-data-server/issues";);
+
+       g_test_add (
+               "/libedataserver-test/WebDAVhrefCompare",
+               ETestServerFixture, &test_closure,
+               e_test_server_utils_setup,
+               test_webdav_href_compare,
+               e_test_server_utils_teardown);
+
+       return e_test_server_utils_run ();
+}


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