summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMilan Crha <mcrha@redhat.com>2020-11-11 13:54:10 +0100
committerMilan Crha <mcrha@redhat.com>2020-11-11 13:54:10 +0100
commit90fadea23ab7712259762ea2874a794aca482e03 (patch)
treef033ef73fe274db1efca820fe32022ad3f1aac80
parentbe71f233180f3c34b6dc50fe28bfc4e08158a951 (diff)
downloadevolution-data-server-90fadea23ab7712259762ea2874a794aca482e03.tar.gz
I#260 - DAV: Relax collection's item href comparison
Closes https://gitlab.gnome.org/GNOME/evolution-data-server/-/issues/260
-rw-r--r--src/addressbook/backends/carddav/e-book-backend-carddav.c7
-rw-r--r--src/calendar/backends/caldav/e-cal-backend-caldav.c7
-rw-r--r--src/libedataserver/e-webdav-session.c81
-rw-r--r--src/libedataserver/e-webdav-session.h2
-rw-r--r--tests/libedataserver/CMakeLists.txt1
-rw-r--r--tests/libedataserver/libedataserver-test.c81
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 ();
+}