[evolution-data-server/wip/mcrha/soup3: 6/6] M!85 - Port to libsoup3




commit d096c540ee25813974644b1f34cf802a26b54a44
Author: Milan Crha <mcrha redhat com>
Date:   Tue Nov 9 17:48:03 2021 +0100

    M!85 - Port to libsoup3
    
    Closes https://gitlab.gnome.org/GNOME/evolution-data-server/-/merge_requests/85

 CMakeLists.txt                                     |   70 +-
 config.h.in                                        |    6 -
 .../evolution-data-server-docs.sgml.in             |    3 -
 .../backends/carddav/e-book-backend-carddav.c      |  150 +--
 .../libedata-book/e-book-meta-backend.c            |   22 +-
 .../backends/caldav/e-cal-backend-caldav.c         |  194 ++--
 .../backends/contacts/e-cal-backend-contacts.c     |    2 +-
 src/calendar/backends/http/e-cal-backend-http.c    |  178 ++-
 .../backends/weather/e-cal-backend-weather.c       |    8 -
 src/calendar/backends/weather/e-weather-source.c   |   46 +-
 .../webdav-notes/e-cal-backend-webdav-notes.c      |   81 +-
 src/calendar/libecal/CMakeLists.txt                |    2 +-
 src/calendar/libedata-cal/CMakeLists.txt           |    2 +-
 src/calendar/libedata-cal/e-cal-meta-backend.c     |   22 +-
 src/camel/camel-message-info-base.c                |   10 +-
 src/camel/camel-text-index.c                       |    6 +-
 src/camel/providers/nntp/camel-nntp-folder.c       |    2 +-
 src/libebackend/CMakeLists.txt                     |    2 +-
 src/libebackend/e-webdav-collection-backend.c      |   30 +-
 src/libedataserver/CMakeLists.txt                  |    6 +-
 src/libedataserver/e-data-server-util.c            |   59 +
 src/libedataserver/e-data-server-util.h            |    6 +
 src/libedataserver/e-gdata-oauth2-authorizer.c     |    2 +-
 src/libedataserver/e-oauth2-service-google.c       |    8 +-
 src/libedataserver/e-oauth2-service-outlook.c      |   10 +-
 src/libedataserver/e-oauth2-service-yahoo.c        |    8 +-
 src/libedataserver/e-oauth2-service.c              |   69 +-
 src/libedataserver/e-proxy.c                       | 1082 ------------------
 src/libedataserver/e-proxy.h                       |   94 --
 src/libedataserver/e-soup-auth-bearer.c            |    8 +-
 src/libedataserver/e-soup-logger.c                 |  201 ----
 src/libedataserver/e-soup-logger.h                 |   34 -
 src/libedataserver/e-soup-session.c                | 1184 +++++++++++++++-----
 src/libedataserver/e-soup-session.h                |   56 +-
 src/libedataserver/e-soup-ssl-trust.c              |   80 +-
 src/libedataserver/e-source-webdav.c               |  141 +--
 src/libedataserver/e-source-webdav.h               |    6 +-
 src/libedataserver/e-source.c                      |    2 +-
 src/libedataserver/e-webdav-discover.c             |   65 +-
 src/libedataserver/e-webdav-session.c              |  853 ++++++--------
 src/libedataserver/e-webdav-session.h              |   36 +-
 src/libedataserver/libedataserver.h                |    2 -
 src/libedataserver/libedataserver.pc.in            |    2 +-
 src/libedataserverui/CMakeLists.txt                |    2 +-
 .../e-credentials-prompter-impl-oauth2.c           |   74 +-
 src/libedataserverui/e-trust-prompt.c              |    8 +-
 src/libedataserverui/e-webdav-discover-widget.c    |   22 +-
 src/libedataserverui/libedataserverui.pc.in        |    2 +-
 src/modules/gnome-online-accounts/goaewsclient.c   |  185 +--
 .../module-gnome-online-accounts.c                 |    8 +-
 .../evolution-source-registry-migrate-sources.c    |  120 +-
 src/vala/CMakeLists.txt                            |   16 +-
 52 files changed, 2103 insertions(+), 3184 deletions(-)
---
diff --git a/CMakeLists.txt b/CMakeLists.txt
index f84bcb455..a9fc4703d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -52,49 +52,49 @@ set(LIBCAMEL_CURRENT 64)
 set(LIBCAMEL_REVISION 0)
 set(LIBCAMEL_AGE 0)
 
-set(LIBEBACKEND_CURRENT 10)
+set(LIBEBACKEND_CURRENT 11)
 set(LIBEBACKEND_REVISION 0)
 set(LIBEBACKEND_AGE 0)
 
-set(LIBEDATASERVER_CURRENT 26)
+set(LIBEDATASERVER_CURRENT 27)
 set(LIBEDATASERVER_REVISION 0)
 set(LIBEDATASERVER_AGE 0)
 
-set(LIBEDATASERVERUI_CURRENT 3)
+set(LIBEDATASERVERUI_CURRENT 4)
 set(LIBEDATASERVERUI_REVISION 0)
 set(LIBEDATASERVERUI_AGE 0)
 
-set(LIBEBOOK_CURRENT 20)
+set(LIBEBOOK_CURRENT 21)
 set(LIBEBOOK_REVISION 1)
 set(LIBEBOOK_AGE 3)
 
-set(LIBEBOOK_CONTACTS_CURRENT 3)
+set(LIBEBOOK_CONTACTS_CURRENT 4)
 set(LIBEBOOK_CONTACTS_REVISION 0)
 set(LIBEBOOK_CONTACTS_AGE 0)
 
-set(LIBEDATABOOK_CURRENT 26)
+set(LIBEDATABOOK_CURRENT 27)
 set(LIBEDATABOOK_REVISION 0)
 set(LIBEDATABOOK_AGE 0)
 
-set(LIBECAL_CURRENT 1)
+set(LIBECAL_CURRENT 2)
 set(LIBECAL_REVISION 0)
 set(LIBECAL_AGE 0)
 
-set(LIBEDATACAL_CURRENT 1)
+set(LIBEDATACAL_CURRENT 2)
 set(LIBEDATACAL_REVISION 0)
 set(LIBEDATACAL_AGE 0)
 
 # Keep these two definitions in agreement.
-set(glib_minimum_version 2.46)
-set(glib_encoded_version GLIB_VERSION_2_46)
+set(glib_minimum_version 2.68)
+set(glib_encoded_version GLIB_VERSION_2_68)
 
 # Keep these two definitions in agreement.
 set(gdk_minimum_version 3.16)
 set(gdk_encoded_version GDK_VERSION_3_16)
 
 # Keep these two definitions in agreement.
-set(soup_minimum_version 2.58)
-set(soup_encoded_version SOUP_VERSION_2_58)
+set(soup_minimum_version 3.0)
+set(soup_encoded_version SOUP_VERSION_3_0)
 
 # Warn about API usage that violates our minimum requirements.
 add_definitions(-DGLIB_VERSION_MAX_ALLOWED=${glib_encoded_version})
@@ -118,12 +118,11 @@ set(sqlite_minimum_version 3.7.17)
 
 # Optional Packages
 set(goa_minimum_version 3.8)
-set(gweather_minimum_version 3.10)
-set(gweather4_minimum_version 3.91.0)
+set(gweather_minimum_version 3.91)
 set(libaccounts_glib_minimum_version 1.4)
 set(libsignon_glib_minimum_version 1.8)
 set(json_glib_minimum_version 1.0.4)
-set(webkit2gtk_minimum_version 2.28.0)
+set(webkit2gtk_minimum_version 2.34.0)
 set(libcanberra_gtk_minimum_version 0.25)
 
 # Load modules from the source tree
@@ -342,7 +341,7 @@ pkg_check_modules(GNOME_PLATFORM REQUIRED
        gio-2.0>=${glib_minimum_version}
        gmodule-2.0>=${glib_minimum_version}
        libxml-2.0>=${libxml_minimum_version}
-       libsoup-2.4>=${soup_minimum_version}
+       libsoup-3.0>=${soup_minimum_version}
 )
 
 if(WIN32)
@@ -402,7 +401,7 @@ add_printable_option(ENABLE_OAUTH2_WEBKITGTK "Enable WebKitGTK for built-in OAut
 
 if(ENABLE_OAUTH2_WEBKITGTK)
        pkg_check_modules_for_option(ENABLE_OAUTH2_WEBKITGTK "WebKitGTK for built-in OAuth2 authentications" 
OAUTH2_WEBKITGTK
-               webkit2gtk-4.0>=${webkit2gtk_minimum_version}
+               webkit2gtk-4.1>=${webkit2gtk_minimum_version}
        )
 endif(ENABLE_OAUTH2_WEBKITGTK)
 
@@ -754,26 +753,13 @@ endif(NOT have_addrinfo)
 add_printable_option(ENABLE_WEATHER "Build the weather calendar backend" ON)
 
 if(ENABLE_WEATHER)
-       add_printable_variable(WITH_GWEATHER4 "Use GWeather 4 instead of 3" OFF)
+       pkg_check_modules_for_option(ENABLE_WEATHER "weather calendar backend" LIBGWEATHER 
gweather4>=${gweather_minimum_version})
 
-       if(WITH_GWEATHER4)
-               pkg_check_modules_for_option(ENABLE_WEATHER "weather calendar backend" LIBGWEATHER 
gweather4>=${gweather4_minimum_version})
-       else(WITH_GWEATHER4)
-               pkg_check_modules_for_option(ENABLE_WEATHER "weather calendar backend" LIBGWEATHER 
gweather-3.0>=${gweather_minimum_version})
-       endif(WITH_GWEATHER4)
-
-       set(CMAKE_REQUIRED_INCLUDES ${LIBGWEATHER_INCLUDE_DIRS})
-       set(CMAKE_REQUIRED_LIBRARIES ${LIBGWEATHER_LDFLAGS})
-       CHECK_C_SOURCE_COMPILES("#define GWEATHER_I_KNOW_THIS_IS_UNSTABLE
-                               #include <libgweather/gweather.h>
-                               #undef GWEATHER_I_KNOW_THIS_IS_UNSTABLE
-
-                               int main(void) {
-                                       gweather_info_new (NULL);
-                                       return 0;
-                               }" HAVE_ONE_ARG_GWEATHER_INFO_NEW)
-       unset(CMAKE_REQUIRED_INCLUDES)
-       unset(CMAKE_REQUIRED_LIBRARIES)
+       # compatibility check
+       pkg_check_variable(gweather_soupapiversion gweather4 soupapiversion)
+       if(NOT "${gweather_soupapiversion}" STREQUAL "3.0")
+               message(FATAL_ERROR "Requires libgweather compiled with libsoup 3.0 API, but found version 
'${gweather_soupapiversion}' instead. If you want to disable weather calendar backend, please use 
-DENABLE_WEATHER=OFF argument to cmake command.")
+       endif(NOT "${gweather_soupapiversion}" STREQUAL "3.0")
 endif(ENABLE_WEATHER)
 
 # ************************************************
@@ -839,7 +825,7 @@ add_printable_option(ENABLE_GOOGLE "Enable Google support" ON)
 if(ENABLE_GOOGLE)
        pkg_check_modules_for_option(ENABLE_GOOGLE "Google" LIBGDATA libgdata>=${libgdata_minimum_version})
        set(HAVE_LIBGDATA ON)
-       set(LIBGDATA_GIR GData-0.0)
+       set(LIBGDATA_GIR GData-1.0)
        set(LIBGDATA_VAPI libgdata)
 
        set(CMAKE_REQUIRED_DEFINITIONS ${LIBGDATA_CFLAGS_OTHER})
@@ -935,14 +921,14 @@ unset(CMAKE_REQUIRED_LIBRARIES)
 # subparts flags
 # ******************************
 
-pkg_check_modules(SOUP REQUIRED libsoup-2.4)
-pkg_check_modules(DATA_SERVER REQUIRED gio-2.0 gmodule-2.0 libsecret-1 libxml-2.0 libsoup-2.4 
${mozilla_nspr} ${mozilla_nss})
+pkg_check_modules(SOUP REQUIRED libsoup-3.0)
+pkg_check_modules(DATA_SERVER REQUIRED gio-2.0 gmodule-2.0 libsecret-1 libxml-2.0 libsoup-3.0 
${mozilla_nspr} ${mozilla_nss})
 set(E_DATA_SERVER_INCLUDES ${E_DATA_SERVER_INCLUDES} ${MANUAL_NSPR_INCLUDES} ${MANUAL_NSS_INCLUDES})
 set(E_DATA_SERVER_LDFLAGS ${E_DATA_SERVER_LDFLAGS} ${MANUAL_NSPR_LIBS} ${MANUAL_NSS_LIBS})
 
-pkg_check_modules(BACKEND REQUIRED gio-2.0 gmodule-2.0 libsecret-1 libsoup-2.4 libxml-2.0)
-pkg_check_modules(ADDRESSBOOK REQUIRED gio-2.0 libxml-2.0 libsoup-2.4 libsecret-1)
-pkg_check_modules(CALENDAR REQUIRED gio-2.0 libical-glib>=${libical_glib_minimum_version} libsoup-2.4 
libxml-2.0 libsecret-1)
+pkg_check_modules(BACKEND REQUIRED gio-2.0 gmodule-2.0 libsecret-1 libsoup-3.0 libxml-2.0)
+pkg_check_modules(ADDRESSBOOK REQUIRED gio-2.0 libxml-2.0 libsoup-3.0 libsecret-1)
+pkg_check_modules(CALENDAR REQUIRED gio-2.0 libical-glib>=${libical_glib_minimum_version} libsoup-3.0 
libxml-2.0 libsecret-1)
 set(ADDRESSBOOK_CFLAGS ${ADDRESSBOOK_CFLAGS} ${PHONENUMBER_DEFINITIONS})
 set(ADDRESSBOOK_INCLUDE_DIRS ${ADDRESSBOOK_INCLUDE_DIRS} ${PHONENUMBER_INCLUDE_DIRS})
 set(ADDRESSBOOK_LDFLAGS ${ADDRESSBOOK_LDFLAGS} ${PHONENUMBER_LDFLAGS})
diff --git a/config.h.in b/config.h.in
index 0ec3eaa71..62743fb23 100644
--- a/config.h.in
+++ b/config.h.in
@@ -194,12 +194,6 @@
 #define O_LARGEFILE 0
 #endif /* HAVE_O_LARGEFILE */
 
-/* gweather_info_new() has only one argument */
-#cmakedefine HAVE_ONE_ARG_GWEATHER_INFO_NEW 1
-
-/* Defined when linking against gweather4. Cannot just use GWEATHER_CHECK_VERSION because 40.0 made the 
versions non-monotonic. */
-#cmakedefine WITH_GWEATHER4 1
-
 /* evolution-alarm-notify - Define if using Canberra-GTK for sound */
 #cmakedefine HAVE_CANBERRA 1
 
diff --git a/docs/reference/evolution-data-server/evolution-data-server-docs.sgml.in 
b/docs/reference/evolution-data-server/evolution-data-server-docs.sgml.in
index 3cdabb3dd..f6e1e75e8 100644
--- a/docs/reference/evolution-data-server/evolution-data-server-docs.sgml.in
+++ b/docs/reference/evolution-data-server/evolution-data-server-docs.sgml.in
@@ -110,7 +110,6 @@
       <xi:include href="xml/e-source-mdn.xml"/>
       <xi:include href="xml/e-source-offline.xml"/>
       <xi:include href="xml/e-source-openpgp.xml"/>
-      <xi:include href="xml/e-source-proxy.xml"/>
       <xi:include href="xml/e-source-refresh.xml"/>
       <xi:include href="xml/e-source-resource.xml"/>
       <xi:include href="xml/e-source-revision-guards.xml"/>
@@ -249,7 +248,6 @@
       <xi:include href="xml/e-operation-pool.xml"/>
       <xi:include href="xml/e-secret-store.xml"/>
       <xi:include href="xml/e-sexp.xml"/>
-      <xi:include href="xml/e-soup-logger.xml"/>
       <xi:include href="xml/e-soup-session.xml"/>
       <xi:include href="xml/e-soup-ssl-trust.xml"/>
       <xi:include href="xml/e-source-registry-watcher.xml"/>
@@ -334,7 +332,6 @@
       <xi:include href="xml/e-iterator.xml"/>
       <xi:include href="xml/e-list.xml"/>
       <xi:include href="xml/e-list-iterator.xml"/>
-      <xi:include href="xml/e-proxy.xml"/>
       <xi:include href="xml/e-url.xml"/>
     </chapter>
     <chapter>
diff --git a/src/addressbook/backends/carddav/e-book-backend-carddav.c 
b/src/addressbook/backends/carddav/e-book-backend-carddav.c
index 05e9c1b5c..19aa9802f 100644
--- a/src/addressbook/backends/carddav/e-book-backend-carddav.c
+++ b/src/addressbook/backends/carddav/e-book-backend-carddav.c
@@ -129,31 +129,35 @@ ebb_carddav_connect_sync (EBookMetaBackend *meta_backend,
                &capabilities, &allows, cancellable, &local_error);
 
        /* iCloud and Google servers can return "404 Not Found" when issued OPTIONS on the addressbook 
collection */
-       if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_NOT_FOUND) ||
-           g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_BAD_REQUEST)) {
+       if (g_error_matches (local_error, E_SOUP_SESSION_ERROR, SOUP_STATUS_NOT_FOUND) ||
+           g_error_matches (local_error, E_SOUP_SESSION_ERROR, SOUP_STATUS_BAD_REQUEST)) {
                ESourceWebdav *webdav_extension;
-               SoupURI *soup_uri;
+               GUri *g_uri;
 
                webdav_extension = e_source_get_extension (source, E_SOURCE_EXTENSION_WEBDAV_BACKEND);
-               soup_uri = e_source_webdav_dup_soup_uri (webdav_extension);
-               if (soup_uri) {
-                       if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_NOT_FOUND) &&
-                           soup_uri->host && soup_uri->path && *soup_uri->path &&
-                           e_util_utf8_strstrcase (soup_uri->host, ".icloud.com")) {
+               g_uri = e_source_webdav_dup_uri (webdav_extension);
+               if (g_uri) {
+                       if (g_error_matches (local_error, E_SOUP_SESSION_ERROR, SOUP_STATUS_NOT_FOUND) &&
+                           g_uri_get_host (g_uri) && *g_uri_get_path (g_uri) &&
+                           e_util_utf8_strstrcase (g_uri_get_host (g_uri), ".icloud.com")) {
                                /* Try parent directory */
                                gchar *path;
-                               gint len = strlen (soup_uri->path);
+                               gint len = strlen (g_uri_get_path (g_uri));
 
-                               if (soup_uri->path[len - 1] == '/')
-                                       soup_uri->path[len - 1] = '\0';
+                               if (g_uri_get_path (g_uri)[len - 1] == '/') {
+                                       gchar *np = g_strdup (g_uri_get_path (g_uri));
+                                       np[len - 1] = '\0';
+                                       e_util_change_uri_component (&g_uri, SOUP_URI_PATH, np);
+                                       g_free (np);
+                               }
 
-                               path = g_path_get_dirname (soup_uri->path);
-                               if (path && g_str_has_prefix (soup_uri->path, path)) {
+                               path = g_path_get_dirname (g_uri_get_path (g_uri));
+                               if (path && g_str_has_prefix (g_uri_get_path (g_uri), path)) {
                                        gchar *uri;
 
-                                       soup_uri_set_path (soup_uri, path);
+                                       e_util_change_uri_component (&g_uri, SOUP_URI_PATH, path);
 
-                                       uri = soup_uri_to_string (soup_uri, FALSE);
+                                       uri = g_uri_to_string_partial (g_uri, SOUP_HTTP_URI_FLAGS);
                                        if (uri) {
                                                g_clear_error (&local_error);
 
@@ -165,8 +169,8 @@ ebb_carddav_connect_sync (EBookMetaBackend *meta_backend,
                                }
 
                                g_free (path);
-                       } else if (soup_uri->host && (e_util_utf8_strstrcase (soup_uri->host, 
".googleusercontent.com") ||
-                                                     e_util_utf8_strstrcase (soup_uri->host, 
".googleapis.com"))) {
+                       } else if (g_uri_get_host (g_uri) && (e_util_utf8_strstrcase (g_uri_get_host (g_uri), 
".googleusercontent.com") ||
+                                                     e_util_utf8_strstrcase (g_uri_get_host (g_uri), 
".googleapis.com"))) {
                                g_clear_error (&local_error);
                                success = TRUE;
 
@@ -178,7 +182,7 @@ ebb_carddav_connect_sync (EBookMetaBackend *meta_backend,
                                g_hash_table_insert (allows, g_strdup (SOUP_METHOD_PUT), GINT_TO_POINTER (1));
                        }
 
-                       soup_uri_free (soup_uri);
+                       g_uri_unref (g_uri);
                }
        }
 
@@ -208,11 +212,11 @@ ebb_carddav_connect_sync (EBookMetaBackend *meta_backend,
 
        if (success) {
                ESourceWebdav *webdav_extension;
-               SoupURI *soup_uri;
+               GUri *g_uri;
                gboolean addressbook;
 
                webdav_extension = e_source_get_extension (source, E_SOURCE_EXTENSION_WEBDAV_BACKEND);
-               soup_uri = e_source_webdav_dup_soup_uri (webdav_extension);
+               g_uri = e_source_webdav_dup_uri (webdav_extension);
 
                addressbook = capabilities && g_hash_table_contains (capabilities, 
E_WEBDAV_CAPABILITY_ADDRESSBOOK);
 
@@ -221,13 +225,13 @@ ebb_carddav_connect_sync (EBookMetaBackend *meta_backend,
 
                        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);
+                       bbdav->priv->is_google = g_uri && g_uri_get_host (g_uri) && (
+                               g_ascii_strcasecmp (g_uri_get_host (g_uri), "www.google.com") == 0 ||
+                               g_ascii_strcasecmp (g_uri_get_host (g_uri), "apidata.googleusercontent.com") 
== 0);
                } else {
                        gchar *uri;
 
-                       uri = soup_uri_to_string (soup_uri, FALSE);
+                       uri = g_uri_to_string_partial (g_uri, G_URI_HIDE_PASSWORD);
 
                        success = FALSE;
                        g_set_error (&local_error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA,
@@ -238,7 +242,7 @@ ebb_carddav_connect_sync (EBookMetaBackend *meta_backend,
                        e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_DISCONNECTED);
                }
 
-               soup_uri_free (soup_uri);
+               g_uri_unref (g_uri);
        }
 
        if (success) {
@@ -251,7 +255,7 @@ ebb_carddav_connect_sync (EBookMetaBackend *meta_backend,
                   The 'getctag' extension is not required, thus check
                   for unauthorized error only. */
                if (!e_webdav_session_getctag_sync (webdav, NULL, &ctag, cancellable, &local_error) &&
-                   g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_UNAUTHORIZED)) {
+                   g_error_matches (local_error, E_SOUP_SESSION_ERROR, SOUP_STATUS_UNAUTHORIZED)) {
                        success = FALSE;
                } else {
                        g_clear_error (&local_error);
@@ -264,22 +268,19 @@ ebb_carddav_connect_sync (EBookMetaBackend *meta_backend,
                *out_auth_result = E_SOURCE_AUTHENTICATION_ACCEPTED;
        } else {
                gboolean credentials_empty;
-               gboolean is_ssl_error;
+               gboolean is_tls_error = FALSE;
 
                credentials_empty = (!credentials || !e_named_parameters_count (credentials) ||
                        (e_named_parameters_count (credentials) == 1 && e_named_parameters_exists 
(credentials, E_SOURCE_CREDENTIAL_SSL_TRUST))) &&
                        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);
+               is_tls_error = g_error_matches (local_error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE);
 
                *out_auth_result = E_SOURCE_AUTHENTICATION_ERROR;
 
                /* because evolution knows only G_IO_ERROR_CANCELLED */
-               if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_CANCELLED)) {
-                       local_error->domain = G_IO_ERROR;
-                       local_error->code = G_IO_ERROR_CANCELLED;
-               } else if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_FORBIDDEN) && 
credentials_empty) {
+               if (g_error_matches (local_error, E_SOUP_SESSION_ERROR, SOUP_STATUS_FORBIDDEN) && 
credentials_empty) {
                        *out_auth_result = E_SOURCE_AUTHENTICATION_REQUIRED;
-               } else if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_UNAUTHORIZED)) {
+               } else if (g_error_matches (local_error, E_SOUP_SESSION_ERROR, SOUP_STATUS_UNAUTHORIZED)) {
                        if (credentials_empty)
                                *out_auth_result = E_SOURCE_AUTHENTICATION_REQUIRED;
                        else
@@ -298,7 +299,7 @@ ebb_carddav_connect_sync (EBookMetaBackend *meta_backend,
                        local_error = NULL;
                }
 
-               if (is_ssl_error) {
+               if (is_tls_error) {
                        *out_auth_result = E_SOURCE_AUTHENTICATION_ERROR_SSL_FAILED;
 
                        e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_SSL_FAILED);
@@ -443,7 +444,7 @@ ebb_carddav_ensure_uid (EContact *contact,
 static gboolean
 ebb_carddav_multiget_response_cb (EWebDAVSession *webdav,
                                  xmlNodePtr prop_node,
-                                 const SoupURI *request_uri,
+                                 const GUri *request_uri,
                                  const gchar *href,
                                  guint status_code,
                                  gpointer user_data)
@@ -567,7 +568,7 @@ ebb_carddav_multiget_from_sets_sync (EBookBackendCardDAV *bbdav,
 
        while (link && left_to_go > 0) {
                EBookMetaBackendInfo *nfo = link->data;
-               SoupURI *suri;
+               GUri *suri;
                gchar *path = NULL;
 
                link = g_slist_next (link);
@@ -581,10 +582,15 @@ ebb_carddav_multiget_from_sets_sync (EBookBackendCardDAV *bbdav,
 
                left_to_go--;
 
-               suri = soup_uri_new (nfo->extra);
+               suri = g_uri_parse (nfo->extra, SOUP_HTTP_URI_FLAGS, NULL);
                if (suri) {
-                       path = soup_uri_to_string (suri, TRUE);
-                       soup_uri_free (suri);
+                       if (g_uri_get_query (suri))
+                               path = g_strdup_printf ("%s?%s",
+                                                       *g_uri_get_path (suri) ? g_uri_get_path (suri) : "/",
+                                                       g_uri_get_query (suri));
+                       else
+                               path = g_strdup (*g_uri_get_path (suri) ? g_uri_get_path (suri) : "/");
+                       g_uri_unref (suri);
                }
 
                e_xml_document_start_element (xml, E_WEBDAV_NS_DAV, "href");
@@ -611,7 +617,7 @@ ebb_carddav_multiget_from_sets_sync (EBookBackendCardDAV *bbdav,
 static gboolean
 ebb_carddav_get_contact_items_cb (EWebDAVSession *webdav,
                                  xmlNodePtr prop_node,
-                                 const SoupURI *request_uri,
+                                 const GUri *request_uri,
                                  const gchar *href,
                                  guint status_code,
                                  gpointer user_data)
@@ -629,7 +635,7 @@ ebb_carddav_get_contact_items_cb (EWebDAVSession *webdav,
 
                /* Skip collection resource, if returned by the server (like iCloud.com does) */
                if (g_str_has_suffix (href, "/") ||
-                   (request_uri && request_uri->path && g_str_has_suffix (href, request_uri->path))) {
+                   (request_uri && *g_uri_get_path ((GUri *) request_uri) && g_str_has_suffix (href, 
g_uri_get_path ((GUri *) request_uri)))) {
                        return TRUE;
                }
 
@@ -705,12 +711,12 @@ ebb_carddav_check_credentials_error (EBookBackendCardDAV *bbdav,
 {
        g_return_if_fail (E_IS_BOOK_BACKEND_CARDDAV (bbdav));
 
-       if (g_error_matches (op_error, SOUP_HTTP_ERROR, SOUP_STATUS_SSL_FAILED) && webdav) {
+       if (g_error_matches (op_error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE) && webdav) {
                op_error->domain = E_CLIENT_ERROR;
                op_error->code = E_CLIENT_ERROR_TLS_NOT_AVAILABLE;
-       } else if (g_error_matches (op_error, SOUP_HTTP_ERROR, SOUP_STATUS_UNAUTHORIZED) ||
-                  g_error_matches (op_error, SOUP_HTTP_ERROR, SOUP_STATUS_FORBIDDEN)) {
-               gboolean was_forbidden = g_error_matches (op_error, SOUP_HTTP_ERROR, SOUP_STATUS_FORBIDDEN);
+       } else if (g_error_matches (op_error, E_SOUP_SESSION_ERROR, SOUP_STATUS_UNAUTHORIZED) ||
+                  g_error_matches (op_error, E_SOUP_SESSION_ERROR, SOUP_STATUS_FORBIDDEN)) {
+               gboolean was_forbidden = g_error_matches (op_error, E_SOUP_SESSION_ERROR, 
SOUP_STATUS_FORBIDDEN);
 
                op_error->domain = E_CLIENT_ERROR;
                op_error->code = E_CLIENT_ERROR_AUTHENTICATION_REQUIRED;
@@ -863,7 +869,7 @@ ebb_carddav_get_changes_sync (EBookMetaBackend *meta_backend,
 static gboolean
 ebb_carddav_extract_existing_cb (EWebDAVSession *webdav,
                                 xmlNodePtr prop_node,
-                                const SoupURI *request_uri,
+                                const GUri *request_uri,
                                 const gchar *href,
                                 guint status_code,
                                 gpointer user_data)
@@ -978,15 +984,15 @@ ebb_carddav_uid_to_uri (EBookBackendCardDAV *bbdav,
                        const gchar *extension)
 {
        ESourceWebdav *webdav_extension;
-       SoupURI *soup_uri;
+       GUri *guri;
        gchar *uri, *tmp, *filename, *uid_hash = NULL;
 
        g_return_val_if_fail (E_IS_BOOK_BACKEND_CARDDAV (bbdav), NULL);
        g_return_val_if_fail (uid != NULL, NULL);
 
        webdav_extension = e_source_get_extension (e_backend_get_source (E_BACKEND (bbdav)), 
E_SOURCE_EXTENSION_WEBDAV_BACKEND);
-       soup_uri = e_source_webdav_dup_soup_uri (webdav_extension);
-       g_return_val_if_fail (soup_uri != NULL, NULL);
+       guri = e_source_webdav_dup_uri (webdav_extension);
+       g_return_val_if_fail (guri != NULL, NULL);
 
        /* UIDs with forward slashes can cause trouble, because the destination server
           can consider them as a path delimiter. For example Google book backend uses
@@ -1001,29 +1007,29 @@ ebb_carddav_uid_to_uri (EBookBackendCardDAV *bbdav,
 
        if (extension) {
                tmp = g_strconcat (uid, extension, NULL);
-               filename = soup_uri_encode (tmp, NULL);
+               filename = g_uri_escape_string (tmp, NULL, FALSE);
                g_free (tmp);
        } else {
-               filename = soup_uri_encode (uid, NULL);
+               filename = g_uri_escape_string (uid, NULL, FALSE);
        }
 
-       if (soup_uri->path) {
-               gchar *slash = strrchr (soup_uri->path, '/');
+       if (g_uri_get_path (guri) && *g_uri_get_path (guri)) {
+               const gchar *slash = strrchr (g_uri_get_path (guri), '/');
 
                if (slash && !slash[1])
-                       *slash = '\0';
+                       tmp = g_strconcat (g_uri_get_path (guri), filename, NULL);
+               else
+                       tmp = g_strconcat (g_uri_get_path (guri), "/", filename, NULL);
+       } else {
+               tmp = g_strconcat ("/", filename, NULL);
        }
 
-       soup_uri_set_user (soup_uri, NULL);
-       soup_uri_set_password (soup_uri, NULL);
-
-       tmp = g_strconcat (soup_uri->path && *soup_uri->path ? soup_uri->path : "", "/", filename, NULL);
-       soup_uri_set_path (soup_uri, tmp);
+       e_util_change_uri_component (&guri, SOUP_URI_PATH, tmp);
        g_free (tmp);
 
-       uri = soup_uri_to_string (soup_uri, FALSE);
+       uri = g_uri_to_string_partial (guri, G_URI_HIDE_USERINFO | G_URI_HIDE_PASSWORD);
 
-       soup_uri_free (soup_uri);
+       g_uri_unref (guri);
        g_free (filename);
        g_free (uid_hash);
 
@@ -1078,7 +1084,7 @@ ebb_carddav_load_contact_sync (EBookMetaBackend *meta_backend,
        if (extra && *extra) {
                uri = g_strdup (extra);
 
-               success = e_webdav_session_get_data_sync (webdav, uri, &href, &etag, &bytes, &length, 
cancellable, &local_error);
+               success = e_webdav_session_get_data_sync (webdav, uri, &href, &etag, NULL, &bytes, &length, 
cancellable, &local_error);
 
                if (!success) {
                        g_free (uri);
@@ -1118,19 +1124,19 @@ ebb_carddav_load_contact_sync (EBookMetaBackend *meta_backend,
 
                g_clear_error (&local_error);
 
-               success = e_webdav_session_get_data_sync (webdav, uri, &href, &etag, &bytes, &length, 
cancellable, &local_error);
+               success = e_webdav_session_get_data_sync (webdav, uri, &href, &etag, NULL, &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. */
                if (!success && !bbdav->priv->is_google && !g_cancellable_is_cancelled (cancellable) &&
-                   g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_NOT_FOUND)) {
+                   g_error_matches (local_error, E_SOUP_SESSION_ERROR, SOUP_STATUS_NOT_FOUND)) {
                        g_free (uri);
                        uri = ebb_carddav_uid_to_uri (bbdav, uid, NULL);
 
                        if (uri) {
                                g_clear_error (&local_error);
 
-                               success = e_webdav_session_get_data_sync (webdav, uri, &href, &etag, &bytes, 
&length, cancellable, &local_error);
+                               success = e_webdav_session_get_data_sync (webdav, uri, &href, &etag, NULL, 
&bytes, &length, cancellable, &local_error);
                        }
                }
        }
@@ -1170,7 +1176,7 @@ ebb_carddav_load_contact_sync (EBookMetaBackend *meta_backend,
        if (local_error) {
                ebb_carddav_check_credentials_error (bbdav, webdav, local_error);
 
-               if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_NOT_FOUND)) {
+               if (g_error_matches (local_error, E_SOUP_SESSION_ERROR, SOUP_STATUS_NOT_FOUND)) {
                        local_error->domain = E_BOOK_CLIENT_ERROR;
                        local_error->code = E_BOOK_CLIENT_ERROR_CONTACT_NOT_FOUND;
                }
@@ -1239,7 +1245,7 @@ ebb_carddav_save_contact_sync (EBookMetaBackend *meta_backend,
 
                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, &new_extra, &new_etag, cancellable, &local_error);
+                       NULL, vcard_string, -1, &new_extra, &new_etag, NULL, cancellable, &local_error);
 
                if (success) {
                        /* Only if both are returned and it's not a weak ETag */
@@ -1284,7 +1290,7 @@ ebb_carddav_save_contact_sync (EBookMetaBackend *meta_backend,
        g_free (etag);
        g_free (uid);
 
-       if (overwrite_existing && g_error_matches (local_error, SOUP_HTTP_ERROR, 
SOUP_STATUS_PRECONDITION_FAILED)) {
+       if (overwrite_existing && g_error_matches (local_error, E_SOUP_SESSION_ERROR, 
SOUP_STATUS_PRECONDITION_FAILED)) {
                g_clear_error (&local_error);
 
                /* Pretend success when using the serer version on conflict,
@@ -1347,7 +1353,7 @@ ebb_carddav_remove_contact_sync (EBookMetaBackend *meta_backend,
        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)) {
+       if (g_error_matches (local_error, E_SOUP_SESSION_ERROR, SOUP_STATUS_NOT_FOUND)) {
                gchar *href;
 
                href = ebb_carddav_uid_to_uri (bbdav, uid, ".vcf");
@@ -1359,7 +1365,7 @@ ebb_carddav_remove_contact_sync (EBookMetaBackend *meta_backend,
                        g_free (href);
                }
 
-               if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_NOT_FOUND)) {
+               if (g_error_matches (local_error, E_SOUP_SESSION_ERROR, SOUP_STATUS_NOT_FOUND)) {
                        href = ebb_carddav_uid_to_uri (bbdav, uid, NULL);
                        if (href) {
                                g_clear_error (&local_error);
@@ -1376,10 +1382,10 @@ ebb_carddav_remove_contact_sync (EBookMetaBackend *meta_backend,
 
        /* Ignore not found errors, this was a delete and the resource is gone.
           It can be that it had been deleted on the server by other application. */
-       if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_NOT_FOUND)) {
+       if (g_error_matches (local_error, E_SOUP_SESSION_ERROR, SOUP_STATUS_NOT_FOUND)) {
                g_clear_error (&local_error);
                success = TRUE;
-       } else if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_PRECONDITION_FAILED)) {
+       } else if (g_error_matches (local_error, E_SOUP_SESSION_ERROR, SOUP_STATUS_PRECONDITION_FAILED)) {
                g_clear_error (&local_error);
 
                /* Pretend success when using the serer version on conflict,
diff --git a/src/addressbook/libedata-book/e-book-meta-backend.c 
b/src/addressbook/libedata-book/e-book-meta-backend.c
index 350d4cfd7..d3f130e78 100644
--- a/src/addressbook/libedata-book/e-book-meta-backend.c
+++ b/src/addressbook/libedata-book/e-book-meta-backend.c
@@ -90,7 +90,7 @@ struct _EBookMetaBackendPrivate {
        gchar *authentication_method;
        gchar *authentication_proxy_uid;
        gchar *authentication_credential_name;
-       SoupURI *webdav_soup_uri;
+       GUri *webdav_uri;
 
        GSList *cursors;
 };
@@ -287,7 +287,7 @@ ebmb_update_connection_values (EBookMetaBackend *meta_backend)
        g_clear_pointer (&meta_backend->priv->authentication_method, g_free);
        g_clear_pointer (&meta_backend->priv->authentication_proxy_uid, g_free);
        g_clear_pointer (&meta_backend->priv->authentication_credential_name, g_free);
-       g_clear_pointer (&meta_backend->priv->webdav_soup_uri, (GDestroyNotify) soup_uri_free);
+       g_clear_pointer (&meta_backend->priv->webdav_uri, g_uri_unref);
 
        if (source && e_source_has_extension (source, E_SOURCE_EXTENSION_AUTHENTICATION)) {
                ESourceAuthentication *auth_extension;
@@ -307,7 +307,7 @@ ebmb_update_connection_values (EBookMetaBackend *meta_backend)
 
                webdav_extension = e_source_get_extension (source, E_SOURCE_EXTENSION_WEBDAV_BACKEND);
 
-               meta_backend->priv->webdav_soup_uri = e_source_webdav_dup_soup_uri (webdav_extension);
+               meta_backend->priv->webdav_uri = e_source_webdav_dup_uri (webdav_extension);
        }
 
        g_mutex_unlock (&meta_backend->priv->property_lock);
@@ -485,17 +485,17 @@ ebmb_requires_reconnect (EBookMetaBackend *meta_backend)
 
        if (!requires && e_source_has_extension (source, E_SOURCE_EXTENSION_WEBDAV_BACKEND)) {
                ESourceWebdav *webdav_extension;
-               SoupURI *soup_uri;
+               GUri *g_uri;
 
                webdav_extension = e_source_get_extension (source, E_SOURCE_EXTENSION_WEBDAV_BACKEND);
-               soup_uri = e_source_webdav_dup_soup_uri (webdav_extension);
+               g_uri = e_source_webdav_dup_uri (webdav_extension);
 
-               requires = (!meta_backend->priv->webdav_soup_uri && soup_uri) ||
-                       (soup_uri && meta_backend->priv->webdav_soup_uri &&
-                       !soup_uri_equal (meta_backend->priv->webdav_soup_uri, soup_uri));
+               requires = (!meta_backend->priv->webdav_uri && g_uri) ||
+                       (g_uri && meta_backend->priv->webdav_uri &&
+                       !soup_uri_equal (meta_backend->priv->webdav_uri, g_uri));
 
-               if (soup_uri)
-                       soup_uri_free (soup_uri);
+               if (g_uri)
+                       g_uri_unref (g_uri);
        }
 
        g_mutex_unlock (&meta_backend->priv->property_lock);
@@ -2521,7 +2521,7 @@ e_book_meta_backend_finalize (GObject *object)
        g_clear_pointer (&meta_backend->priv->authentication_method, g_free);
        g_clear_pointer (&meta_backend->priv->authentication_proxy_uid, g_free);
        g_clear_pointer (&meta_backend->priv->authentication_credential_name, g_free);
-       g_clear_pointer (&meta_backend->priv->webdav_soup_uri, (GDestroyNotify) soup_uri_free);
+       g_clear_pointer (&meta_backend->priv->webdav_uri, g_uri_unref);
 
        g_mutex_clear (&meta_backend->priv->connect_lock);
        g_mutex_clear (&meta_backend->priv->property_lock);
diff --git a/src/calendar/backends/caldav/e-cal-backend-caldav.c 
b/src/calendar/backends/caldav/e-cal-backend-caldav.c
index 2aeed3c91..63858d8f3 100644
--- a/src/calendar/backends/caldav/e-cal-backend-caldav.c
+++ b/src/calendar/backends/caldav/e-cal-backend-caldav.c
@@ -85,7 +85,7 @@ static void
 ecb_caldav_update_tweaks (ECalBackendCalDAV *cbdav)
 {
        ESource *source;
-       SoupURI *soup_uri;
+       GUri *parsed_uri;
 
        g_return_if_fail (E_IS_CAL_BACKEND_CALDAV (cbdav));
 
@@ -94,18 +94,18 @@ ecb_caldav_update_tweaks (ECalBackendCalDAV *cbdav)
        if (!e_source_has_extension (source, E_SOURCE_EXTENSION_WEBDAV_BACKEND))
                return;
 
-       soup_uri = e_source_webdav_dup_soup_uri (e_source_get_extension (source, 
E_SOURCE_EXTENSION_WEBDAV_BACKEND));
-       if (!soup_uri)
+       parsed_uri = e_source_webdav_dup_uri (e_source_get_extension (source, 
E_SOURCE_EXTENSION_WEBDAV_BACKEND));
+       if (!parsed_uri)
                return;
 
-       cbdav->priv->is_google = soup_uri->host && (
-               g_ascii_strcasecmp (soup_uri->host, "www.google.com") == 0 ||
-               g_ascii_strcasecmp (soup_uri->host, "apidata.googleusercontent.com") == 0);
+       cbdav->priv->is_google = g_uri_get_host (parsed_uri) && (
+               g_ascii_strcasecmp (g_uri_get_host (parsed_uri), "www.google.com") == 0 ||
+               g_ascii_strcasecmp (g_uri_get_host (parsed_uri), "apidata.googleusercontent.com") == 0);
 
-       cbdav->priv->is_icloud = soup_uri->host &&
-               e_util_utf8_strstrcase (soup_uri->host, ".icloud.com");
+       cbdav->priv->is_icloud = g_uri_get_host (parsed_uri) &&
+               e_util_utf8_strstrcase (g_uri_get_host (parsed_uri), ".icloud.com");
 
-       soup_uri_free (soup_uri);
+       g_uri_unref (parsed_uri);
 }
 
 static gboolean
@@ -184,19 +184,19 @@ ecb_caldav_connect_sync (ECalMetaBackend *meta_backend,
                        g_slist_free_full (privileges, e_webdav_privilege_free);
                } else {
                        is_writable = allows && (
-                               g_hash_table_contains (allows, SOUP_METHOD_PUT) ||
-                               g_hash_table_contains (allows, SOUP_METHOD_POST) ||
-                               g_hash_table_contains (allows, SOUP_METHOD_DELETE));
+                               g_hash_table_contains (allows, "PUT") ||
+                               g_hash_table_contains (allows, "POST") ||
+                               g_hash_table_contains (allows, "DELETE"));
                }
        }
 
        if (success) {
                ESourceWebdav *webdav_extension;
-               SoupURI *soup_uri;
+               GUri *parsed_uri;
                gboolean calendar_access;
 
                webdav_extension = e_source_get_extension (source, E_SOURCE_EXTENSION_WEBDAV_BACKEND);
-               soup_uri = e_source_webdav_dup_soup_uri (webdav_extension);
+               parsed_uri = e_source_webdav_dup_uri (webdav_extension);
 
                cbdav->priv->calendar_schedule = e_cal_backend_get_kind (E_CAL_BACKEND (cbdav)) != 
I_CAL_VJOURNAL_COMPONENT &&
                        (!capabilities || g_hash_table_contains (capabilities, 
E_WEBDAV_CAPABILITY_CALENDAR_AUTO_SCHEDULE) ||
@@ -212,7 +212,7 @@ ecb_caldav_connect_sync (ECalMetaBackend *meta_backend,
                } else {
                        gchar *uri;
 
-                       uri = soup_uri_to_string (soup_uri, FALSE);
+                       uri = g_uri_to_string_partial (parsed_uri, G_URI_HIDE_PASSWORD);
 
                        success = FALSE;
                        g_set_error (&local_error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA,
@@ -223,7 +223,7 @@ ecb_caldav_connect_sync (ECalMetaBackend *meta_backend,
                        e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_DISCONNECTED);
                }
 
-               soup_uri_free (soup_uri);
+               g_uri_unref (parsed_uri);
        }
 
        if (success) {
@@ -236,33 +236,28 @@ ecb_caldav_connect_sync (ECalMetaBackend *meta_backend,
                   The 'getctag' extension is not required, thus check
                   for unauthorized error only. */
                if (!e_webdav_session_getctag_sync (webdav, NULL, &ctag, cancellable, &local_error) &&
-                   g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_UNAUTHORIZED)) {
+                   g_error_matches (local_error, E_SOUP_SESSION_ERROR, SOUP_STATUS_UNAUTHORIZED)) {
                        success = FALSE;
                } else {
                        g_clear_error (&local_error);
                }
-
                g_free (ctag);
        }
 
        if (!success) {
                gboolean credentials_empty;
-               gboolean is_ssl_error;
+               gboolean is_tls_error;
 
                credentials_empty = (!credentials || !e_named_parameters_count (credentials) ||
                        (e_named_parameters_count (credentials) == 1 && e_named_parameters_exists 
(credentials, E_SOURCE_CREDENTIAL_SSL_TRUST))) &&
                        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);
+               is_tls_error = g_error_matches (local_error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE);
 
                *out_auth_result = E_SOURCE_AUTHENTICATION_ERROR;
 
-               /* because evolution knows only G_IO_ERROR_CANCELLED */
-               if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_CANCELLED)) {
-                       local_error->domain = G_IO_ERROR;
-                       local_error->code = G_IO_ERROR_CANCELLED;
-               } else if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_FORBIDDEN) && 
credentials_empty) {
+               if (g_error_matches (local_error, E_SOUP_SESSION_ERROR, SOUP_STATUS_FORBIDDEN) && 
credentials_empty) {
                        *out_auth_result = E_SOURCE_AUTHENTICATION_REQUIRED;
-               } else if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_UNAUTHORIZED)) {
+               } else if (g_error_matches (local_error, E_SOUP_SESSION_ERROR, SOUP_STATUS_UNAUTHORIZED)) {
                        if (credentials_empty)
                                *out_auth_result = E_SOURCE_AUTHENTICATION_REQUIRED;
                        else
@@ -281,7 +276,7 @@ ecb_caldav_connect_sync (ECalMetaBackend *meta_backend,
                        local_error = NULL;
                }
 
-               if (is_ssl_error) {
+               if (is_tls_error) {
                        *out_auth_result = E_SOURCE_AUTHENTICATION_ERROR_SSL_FAILED;
 
                        e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_SSL_FAILED);
@@ -418,7 +413,7 @@ typedef struct _MultigetData {
 static gboolean
 ecb_caldav_multiget_response_cb (EWebDAVSession *webdav,
                                 xmlNodePtr prop_node,
-                                const SoupURI *request_uri,
+                                const GUri *request_uri,
                                 const gchar *href,
                                 guint status_code,
                                 gpointer user_data)
@@ -570,49 +565,33 @@ ecb_caldav_multiget_from_sets_sync (ECalBackendCalDAV *cbdav,
                        /* iCloud returns '@' escaped as "%40", but it doesn't accept it in GET,
                           thus try to unescape it, together with some other characters */
                        if (nfo->extra && strchr (nfo->extra, '%')) {
-                               SoupURI *suri;
+                               GUri *suri;
                                gchar *new_uri = NULL;
 
-                               suri = soup_uri_new (nfo->extra);
+                               suri = g_uri_parse (nfo->extra, SOUP_HTTP_URI_FLAGS, NULL);
 
                                if (suri) {
                                        const gchar *path;
+                                       gchar *unesc;
+                                       gchar *esc;
 
-                                       path = soup_uri_get_path (suri);
-
-                                       if (path && *path) {
-                                               gchar **parts, *new_path;
-                                               gint jj;
-
-                                               parts = g_strsplit (path, "/", -1);
-
-                                               for (jj = 0; parts && parts[jj]; jj++) {
-                                                       if (parts[jj][0]) {
-                                                               gchar *part;
+                                       path = g_uri_get_path (suri);
+                                       unesc = g_uri_unescape_string (path, NULL);
 
-                                                               part = soup_uri_normalize (parts[jj], "@");
+                                       /* now re-escape the string but allowing a @ */
+                                       esc = g_uri_escape_string (unesc, "@", FALSE);
 
-                                                               if (part) {
-                                                                       g_free (parts[jj]);
-                                                                       parts[jj] = part;
-                                                               }
-                                                       }
-                                               }
-
-                                               new_path = g_strjoinv ("/", parts);
-                                               soup_uri_set_path (suri, new_path);
+                                       e_util_change_uri_component (&suri, SOUP_URI_PATH, esc);
 
-                                               new_uri = soup_uri_to_string (suri, FALSE);
-
-                                               g_strfreev (parts);
-                                               g_free (new_path);
-                                       }
+                                       g_free (unesc);
+                                       g_free (esc);
 
-                                       soup_uri_free (suri);
+                                       new_uri = g_uri_to_string_partial (suri, G_URI_HIDE_PASSWORD);
+                                       g_uri_unref (suri);
                                }
 
                                if (new_uri) {
-                                       success = e_webdav_session_get_data_sync (webdav, new_uri, NULL, 
&etag, &calendar_data, NULL, cancellable, NULL);
+                                       success = e_webdav_session_get_data_sync (webdav, new_uri, NULL, 
&etag, NULL, &calendar_data, NULL, cancellable, NULL);
 
                                        if (success) {
                                                /* Remember the corrected URI */
@@ -628,9 +607,9 @@ ecb_caldav_multiget_from_sets_sync (ECalBackendCalDAV *cbdav,
                        if (!success) {
                                GError *local_error = NULL;
 
-                               success = e_webdav_session_get_data_sync (webdav, nfo->extra, NULL, &etag, 
&calendar_data, NULL, cancellable, &local_error);
+                               success = e_webdav_session_get_data_sync (webdav, nfo->extra, NULL, &etag, 
NULL, &calendar_data, NULL, cancellable, &local_error);
 
-                               if (!success && g_error_matches (local_error, SOUP_HTTP_ERROR, 
SOUP_STATUS_NOT_FOUND)) {
+                               if (!success && g_error_matches (local_error, E_SOUP_SESSION_ERROR, 
SOUP_STATUS_NOT_FOUND)) {
                                        if (out_removed_objects)
                                                *out_removed_objects = g_slist_prepend (*out_removed_objects, 
nfo);
                                        else
@@ -660,13 +639,24 @@ ecb_caldav_multiget_from_sets_sync (ECalBackendCalDAV *cbdav,
                        if (!success)
                                break;
                } else {
-                       SoupURI *suri;
+                       GUri *suri;
                        gchar *path = NULL;
 
-                       suri = soup_uri_new (nfo->extra);
+                       suri = g_uri_parse (nfo->extra, SOUP_HTTP_URI_FLAGS, NULL);
+
                        if (suri) {
-                               path = soup_uri_to_string (suri, TRUE);
-                               soup_uri_free (suri);
+                               const gchar *upath, *uquery;
+
+                               upath = g_uri_get_path (suri);
+                               if (!*upath) upath = "/";
+                               uquery = g_uri_get_query (suri);
+
+                               if (uquery)
+                                       path = g_strdup_printf ("%s?%s", upath, uquery);
+                               else
+                                       path = g_strdup (upath);
+
+                               g_uri_unref (suri);
                        }
 
                        e_xml_document_start_element (xml, E_WEBDAV_NS_DAV, "href");
@@ -698,7 +688,7 @@ ecb_caldav_multiget_from_sets_sync (ECalBackendCalDAV *cbdav,
 static gboolean
 ecb_caldav_get_calendar_items_cb (EWebDAVSession *webdav,
                                  xmlNodePtr prop_node,
-                                 const SoupURI *request_uri,
+                                 const GUri *request_uri,
                                  const gchar *href,
                                  guint status_code,
                                  gpointer user_data)
@@ -717,7 +707,7 @@ ecb_caldav_get_calendar_items_cb (EWebDAVSession *webdav,
 
        /* Skip collection resource, if returned by the server (like iCloud.com does) */
        if (g_str_has_suffix (href, "/") ||
-           (request_uri && request_uri->path && g_str_has_suffix (href, request_uri->path)))
+           (request_uri && *g_uri_get_path ((GUri *) request_uri) && g_str_has_suffix (href, g_uri_get_path 
((GUri *) request_uri))))
                return TRUE;
 
        etag = e_webdav_session_util_maybe_dequote (g_strdup ((const gchar *) e_xml_find_child_and_get_text 
(prop_node, E_WEBDAV_NS_DAV, "getetag")));
@@ -793,12 +783,12 @@ ecb_caldav_check_credentials_error (ECalBackendCalDAV *cbdav,
 {
        g_return_if_fail (E_IS_CAL_BACKEND_CALDAV (cbdav));
 
-       if (g_error_matches (op_error, SOUP_HTTP_ERROR, SOUP_STATUS_SSL_FAILED) && webdav) {
+       if (g_error_matches (op_error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE) && webdav) {
                op_error->domain = E_CLIENT_ERROR;
                op_error->code = E_CLIENT_ERROR_TLS_NOT_AVAILABLE;
-       } else if (g_error_matches (op_error, SOUP_HTTP_ERROR, SOUP_STATUS_UNAUTHORIZED) ||
-                  g_error_matches (op_error, SOUP_HTTP_ERROR, SOUP_STATUS_FORBIDDEN)) {
-               gboolean was_forbidden = g_error_matches (op_error, SOUP_HTTP_ERROR, SOUP_STATUS_FORBIDDEN);
+       } else if (g_error_matches (op_error, E_SOUP_SESSION_ERROR, SOUP_STATUS_UNAUTHORIZED) ||
+                  g_error_matches (op_error, E_SOUP_SESSION_ERROR, SOUP_STATUS_FORBIDDEN)) {
+               gboolean was_forbidden = g_error_matches (op_error, E_SOUP_SESSION_ERROR, 
SOUP_STATUS_FORBIDDEN);
 
                op_error->domain = E_CLIENT_ERROR;
                op_error->code = E_CLIENT_ERROR_AUTHENTICATION_REQUIRED;
@@ -1037,7 +1027,7 @@ ecb_caldav_get_changes_sync (ECalMetaBackend *meta_backend,
 static gboolean
 ecb_caldav_extract_existing_cb (EWebDAVSession *webdav,
                                xmlNodePtr prop_node,
-                               const SoupURI *request_uri,
+                               const GUri *request_uri,
                                const gchar *href,
                                guint status_code,
                                gpointer user_data)
@@ -1176,15 +1166,15 @@ ecb_caldav_uid_to_uri (ECalBackendCalDAV *cbdav,
                       const gchar *extension)
 {
        ESourceWebdav *webdav_extension;
-       SoupURI *soup_uri;
+       GUri *guri;
        gchar *uri, *tmp, *filename, *uid_hash = NULL;
 
        g_return_val_if_fail (E_IS_CAL_BACKEND_CALDAV (cbdav), NULL);
        g_return_val_if_fail (uid != NULL, NULL);
 
        webdav_extension = e_source_get_extension (e_backend_get_source (E_BACKEND (cbdav)), 
E_SOURCE_EXTENSION_WEBDAV_BACKEND);
-       soup_uri = e_source_webdav_dup_soup_uri (webdav_extension);
-       g_return_val_if_fail (soup_uri != NULL, NULL);
+       guri = e_source_webdav_dup_uri (webdav_extension);
+       g_return_val_if_fail (guri != NULL, NULL);
 
        /* UIDs with forward slashes can cause trouble, because the destination server can
           consider them as a path delimiter. Double-encode the URL doesn't always work,
@@ -1198,29 +1188,29 @@ ecb_caldav_uid_to_uri (ECalBackendCalDAV *cbdav,
 
        if (extension) {
                tmp = g_strconcat (uid, extension, NULL);
-               filename = soup_uri_encode (tmp, NULL);
+               filename = g_uri_escape_string (tmp, NULL, FALSE);
                g_free (tmp);
        } else {
-               filename = soup_uri_encode (uid, NULL);
+               filename = g_uri_escape_string (uid, NULL, FALSE);
        }
 
-       if (soup_uri->path) {
-               gchar *slash = strrchr (soup_uri->path, '/');
+       if (g_uri_get_path (guri) && *g_uri_get_path (guri)) {
+               const gchar *slash = strrchr (g_uri_get_path (guri), '/');
 
                if (slash && !slash[1])
-                       *slash = '\0';
+                       tmp = g_strconcat (g_uri_get_path (guri), filename, NULL);
+               else
+                       tmp = g_strconcat (g_uri_get_path (guri), "/", filename, NULL);
+       } else {
+               tmp = g_strconcat ("/", filename, NULL);
        }
 
-       soup_uri_set_user (soup_uri, NULL);
-       soup_uri_set_password (soup_uri, NULL);
-
-       tmp = g_strconcat (soup_uri->path && *soup_uri->path ? soup_uri->path : "", "/", filename, NULL);
-       soup_uri_set_path (soup_uri, tmp);
+       e_util_change_uri_component (&guri, SOUP_URI_PATH, tmp);
        g_free (tmp);
 
-       uri = soup_uri_to_string (soup_uri, FALSE);
+       uri = g_uri_to_string_partial (guri, G_URI_HIDE_USERINFO | G_URI_HIDE_PASSWORD);
 
-       soup_uri_free (soup_uri);
+       g_uri_unref (guri);
        g_free (filename);
        g_free (uid_hash);
 
@@ -1299,7 +1289,7 @@ ecb_caldav_load_component_sync (ECalMetaBackend *meta_backend,
        if (extra && *extra) {
                uri = g_strdup (extra);
 
-               success = e_webdav_session_get_data_sync (webdav, uri, &href, &etag, &bytes, &length, 
cancellable, &local_error);
+               success = e_webdav_session_get_data_sync (webdav, uri, &href, &etag, NULL, &bytes, &length, 
cancellable, &local_error);
 
                if (!success) {
                        g_free (uri);
@@ -1339,19 +1329,19 @@ ecb_caldav_load_component_sync (ECalMetaBackend *meta_backend,
 
                g_clear_error (&local_error);
 
-               success = e_webdav_session_get_data_sync (webdav, uri, &href, &etag, &bytes, &length, 
cancellable, &local_error);
+               success = e_webdav_session_get_data_sync (webdav, uri, &href, &etag, NULL, &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. */
                if (!success && !cbdav->priv->is_google && !g_cancellable_is_cancelled (cancellable) &&
-                   g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_NOT_FOUND)) {
+                   g_error_matches (local_error, E_SOUP_SESSION_ERROR, SOUP_STATUS_NOT_FOUND)) {
                        g_free (uri);
                        uri = ecb_caldav_uid_to_uri (cbdav, uid, NULL);
 
                        if (uri) {
                                g_clear_error (&local_error);
 
-                               success = e_webdav_session_get_data_sync (webdav, uri, &href, &etag, &bytes, 
&length, cancellable, &local_error);
+                               success = e_webdav_session_get_data_sync (webdav, uri, &href, &etag, NULL, 
&bytes, &length, cancellable, &local_error);
                        }
                }
        }
@@ -1393,7 +1383,7 @@ ecb_caldav_load_component_sync (ECalMetaBackend *meta_backend,
        if (local_error) {
                ecb_caldav_check_credentials_error (cbdav, webdav, local_error);
 
-               if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_NOT_FOUND)) {
+               if (g_error_matches (local_error, E_SOUP_SESSION_ERROR, SOUP_STATUS_NOT_FOUND)) {
                        local_error->domain = E_CAL_CLIENT_ERROR;
                        local_error->code = E_CAL_CLIENT_ERROR_OBJECT_NOT_FOUND;
                }
@@ -1479,7 +1469,7 @@ ecb_caldav_save_component_sync (ECalMetaBackend *meta_backend,
 
                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, &new_extra, &new_etag, cancellable, &local_error);
+                       NULL, ical_string, -1, &new_extra, &new_etag, NULL, cancellable, &local_error);
 
                if (success) {
                        /* Only if both are returned and it's not a weak ETag */
@@ -1524,7 +1514,7 @@ ecb_caldav_save_component_sync (ECalMetaBackend *meta_backend,
        g_free (etag);
        g_free (uid);
 
-       if (overwrite_existing && g_error_matches (local_error, SOUP_HTTP_ERROR, 
SOUP_STATUS_PRECONDITION_FAILED)) {
+       if (overwrite_existing && g_error_matches (local_error, E_SOUP_SESSION_ERROR, 
SOUP_STATUS_PRECONDITION_FAILED)) {
                g_clear_error (&local_error);
 
                /* Pretend success when using the serer version on conflict,
@@ -1587,7 +1577,7 @@ ecb_caldav_remove_component_sync (ECalMetaBackend *meta_backend,
        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)) {
+       if (g_error_matches (local_error, E_SOUP_SESSION_ERROR, SOUP_STATUS_NOT_FOUND)) {
                gchar *href;
 
                href = ecb_caldav_uid_to_uri (cbdav, uid, ".ics");
@@ -1599,7 +1589,7 @@ ecb_caldav_remove_component_sync (ECalMetaBackend *meta_backend,
                        g_free (href);
                }
 
-               if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_NOT_FOUND)) {
+               if (g_error_matches (local_error, E_SOUP_SESSION_ERROR, SOUP_STATUS_NOT_FOUND)) {
                        href = ecb_caldav_uid_to_uri (cbdav, uid, NULL);
                        if (href) {
                                g_clear_error (&local_error);
@@ -1616,10 +1606,10 @@ ecb_caldav_remove_component_sync (ECalMetaBackend *meta_backend,
 
        /* Ignore not found errors, this was a delete and the resource is gone.
           It can be that it had been deleted on the server by other application. */
-       if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_NOT_FOUND)) {
+       if (g_error_matches (local_error, E_SOUP_SESSION_ERROR, SOUP_STATUS_NOT_FOUND)) {
                g_clear_error (&local_error);
                success = TRUE;
-       } else if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_PRECONDITION_FAILED)) {
+       } else if (g_error_matches (local_error, E_SOUP_SESSION_ERROR, SOUP_STATUS_PRECONDITION_FAILED)) {
                g_clear_error (&local_error);
 
                /* Pretend success when using the serer version on conflict,
@@ -1666,7 +1656,7 @@ ecb_caldav_get_ssl_error_details (ECalMetaBackend *meta_backend,
 
 static gboolean
 ecb_caldav_dup_href_node_value (EWebDAVSession *webdav,
-                               const SoupURI *request_uri,
+                               const GUri *request_uri,
                                xmlNodePtr from_node,
                                const gchar *parent_ns_href,
                                const gchar *parent_name,
@@ -1699,7 +1689,7 @@ ecb_caldav_dup_href_node_value (EWebDAVSession *webdav,
 static gboolean
 ecb_caldav_propfind_get_owner_cb (EWebDAVSession *webdav,
                                  xmlNodePtr prop_node,
-                                 const SoupURI *request_uri,
+                                 const GUri *request_uri,
                                  const gchar *href,
                                  guint status_code,
                                  gpointer user_data)
@@ -1720,7 +1710,7 @@ ecb_caldav_propfind_get_owner_cb (EWebDAVSession *webdav,
 static gboolean
 ecb_caldav_propfind_get_schedule_outbox_url_cb (EWebDAVSession *webdav,
                                                xmlNodePtr prop_node,
-                                               const SoupURI *request_uri,
+                                               const GUri *request_uri,
                                                const gchar *href,
                                                guint status_code,
                                                gpointer user_data)
@@ -2013,8 +2003,8 @@ ecb_caldav_get_free_busy_from_schedule_outbox_sync (ECalBackendCalDAV *cbdav,
 
        webdav = ecb_caldav_ref_session (cbdav);
 
-       if (e_webdav_session_post_with_content_type_sync (webdav, cbdav->priv->schedule_outbox_url, str, -1,
-                                                         E_WEBDAV_CONTENT_TYPE_CALENDAR, NULL, &response, 
cancellable, &local_error) &&
+       if (e_webdav_session_post_sync (webdav, cbdav->priv->schedule_outbox_url, str, -1, 
E_WEBDAV_CONTENT_TYPE_CALENDAR,
+                                       NULL, NULL, NULL, &response, cancellable, &local_error) &&
            response) {
                /* parse returned xml */
                xmlDocPtr doc;
diff --git a/src/calendar/backends/contacts/e-cal-backend-contacts.c 
b/src/calendar/backends/contacts/e-cal-backend-contacts.c
index e69686177..42f345792 100644
--- a/src/calendar/backends/contacts/e-cal-backend-contacts.c
+++ b/src/calendar/backends/contacts/e-cal-backend-contacts.c
@@ -409,7 +409,7 @@ book_client_connected_cb (GObject *source_object,
        }
 
        source = e_client_get_source (client);
-       br->book_client = g_object_ref (client);
+       br->book_client = g_object_ref (E_BOOK_CLIENT (client));
        br->online = e_client_is_online (client);
        br->notify_online_id = g_signal_connect (client, "notify::online", G_CALLBACK 
(book_client_notify_online_cb), br);
        cal_backend_contacts_insert_book_record (br->cbc, source, br);
diff --git a/src/calendar/backends/http/e-cal-backend-http.c b/src/calendar/backends/http/e-cal-backend-http.c
index bfe9b4554..90b64cb07 100644
--- a/src/calendar/backends/http/e-cal-backend-http.c
+++ b/src/calendar/backends/http/e-cal-backend-http.c
@@ -36,8 +36,8 @@
 struct _ECalBackendHttpPrivate {
        ESoupSession *session;
 
-       SoupRequestHTTP *request;
-       GInputStream *input_stream;
+       SoupMessage *message;
+       gchar *icalstring;
        GRecMutex conn_lock;
        GHashTable *components; /* gchar *uid ~> ICalComponent * */
        gint64 hsts_until_time;
@@ -69,7 +69,7 @@ ecb_http_dup_uri (ECalBackendHttp *cbhttp)
        ESource *source;
        ESourceSecurity *security_extension;
        ESourceWebdav *webdav_extension;
-       SoupURI *soup_uri;
+       GUri *parsed_uri;
        gboolean secure_connection;
        const gchar *extension_name;
        gchar *uri_string, *uri;
@@ -86,9 +86,9 @@ ecb_http_dup_uri (ECalBackendHttp *cbhttp)
 
        secure_connection = e_source_security_get_secure (security_extension);
 
-       soup_uri = e_source_webdav_dup_soup_uri (webdav_extension);
-       uri_string = soup_uri_to_string (soup_uri, FALSE);
-       soup_uri_free (soup_uri);
+       parsed_uri = e_source_webdav_dup_uri (webdav_extension);
+       uri_string = g_uri_to_string_partial (parsed_uri, G_URI_HIDE_PASSWORD);
+       g_uri_unref (parsed_uri);
 
        if (!uri_string || !*uri_string) {
                g_free (uri_string);
@@ -108,24 +108,20 @@ ecb_http_dup_uri (ECalBackendHttp *cbhttp)
 static gint64
 ecb_http_extract_hsts_until_time (ECalBackendHttp *cbhttp)
 {
-       SoupMessage *message;
        GTlsCertificate *cert = NULL;
        GTlsCertificateFlags cert_errors = 0;
        gint64 hsts_until_time = 0;
 
        g_return_val_if_fail (E_IS_CAL_BACKEND_HTTP (cbhttp), hsts_until_time);
-       g_return_val_if_fail (cbhttp->priv->request, hsts_until_time);
+       g_return_val_if_fail (cbhttp->priv->message, hsts_until_time);
 
-       message = soup_request_http_get_message (cbhttp->priv->request);
-       if (!message)
-               return hsts_until_time;
+       cert = soup_message_get_tls_peer_certificate (cbhttp->priv->message);
+       cert_errors = soup_message_get_tls_peer_certificate_errors (cbhttp->priv->message);
 
-       if (message->response_headers &&
-           soup_message_get_https_status (message, &cert, &cert_errors) &&
-           !cert_errors) {
+       if (soup_message_get_response_headers (cbhttp->priv->message) && cert && !cert_errors) {
                const gchar *hsts_header;
 
-               hsts_header = soup_message_headers_get_one (message->response_headers, 
"Strict-Transport-Security");
+               hsts_header = soup_message_headers_get_one (soup_message_get_response_headers 
(cbhttp->priv->message), "Strict-Transport-Security");
                if (hsts_header && *hsts_header) {
                        GHashTable *params;
 
@@ -152,8 +148,6 @@ ecb_http_extract_hsts_until_time (ECalBackendHttp *cbhttp)
                }
        }
 
-       g_object_unref (message);
-
        return hsts_until_time;
 }
 
@@ -195,7 +189,7 @@ ecb_http_connect_sync (ECalMetaBackend *meta_backend,
 {
        ECalBackendHttp *cbhttp;
        ESource *source;
-       SoupRequestHTTP *request;
+       SoupMessage *message;
        GInputStream *input_stream = NULL;
        gchar *uri;
        gboolean success;
@@ -208,15 +202,15 @@ ecb_http_connect_sync (ECalMetaBackend *meta_backend,
 
        g_rec_mutex_lock (&cbhttp->priv->conn_lock);
 
-       if (cbhttp->priv->request && cbhttp->priv->input_stream) {
+       if (cbhttp->priv->message && cbhttp->priv->icalstring) {
                g_rec_mutex_unlock (&cbhttp->priv->conn_lock);
                return TRUE;
        }
 
        source = e_backend_get_source (E_BACKEND (meta_backend));
 
-       g_clear_object (&cbhttp->priv->input_stream);
-       g_clear_object (&cbhttp->priv->request);
+       g_clear_pointer (&cbhttp->priv->icalstring, g_free);
+       g_clear_object (&cbhttp->priv->message);
 
        uri = ecb_http_dup_uri (cbhttp);
 
@@ -232,32 +226,30 @@ ecb_http_connect_sync (ECalMetaBackend *meta_backend,
 
        e_soup_session_set_credentials (cbhttp->priv->session, credentials);
 
-       request = e_soup_session_new_request (cbhttp->priv->session, SOUP_METHOD_GET, uri, &local_error);
-       success = request != NULL;
+       message = e_soup_session_new_message (cbhttp->priv->session, SOUP_METHOD_GET, uri, &local_error);
+       success = message != NULL;
 
        if (success) {
-               SoupMessage *message;
+               gchar *last_etag;
 
-               message = soup_request_http_get_message (request);
+               last_etag = e_cal_meta_backend_dup_sync_tag (meta_backend);
 
-               if (message) {
-                       gchar *last_etag;
+               if (last_etag && *last_etag)
+                       soup_message_headers_append (soup_message_get_request_headers (message), 
"If-None-Match", last_etag);
 
-                       last_etag = e_cal_meta_backend_dup_sync_tag (meta_backend);
+               g_free (last_etag);
 
-                       if (last_etag && *last_etag)
-                               soup_message_headers_append (message->request_headers, "If-None-Match", 
last_etag);
-
-                       g_free (last_etag);
-               }
-
-               input_stream = e_soup_session_send_request_sync (cbhttp->priv->session, request, cancellable, 
&local_error);
+               input_stream = e_soup_session_send_message_sync (cbhttp->priv->session, message, cancellable, 
&local_error);
 
                success = input_stream != NULL;
 
-               if (success && message && !SOUP_STATUS_IS_SUCCESSFUL (message->status_code) && 
message->status_code != SOUP_STATUS_NOT_MODIFIED) {
+               if (success && !SOUP_STATUS_IS_SUCCESSFUL (soup_message_get_status (message)) && 
soup_message_get_status (message) != SOUP_STATUS_NOT_MODIFIED) {
                        g_clear_object (&input_stream);
                        success = FALSE;
+               } else if (g_error_matches (local_error, E_SOUP_SESSION_ERROR, SOUP_STATUS_NOT_MODIFIED)) {
+                       g_clear_object (&input_stream);
+                       g_clear_error (&local_error);
+                       success = TRUE;
                }
 
                if (success) {
@@ -265,22 +257,19 @@ ecb_http_connect_sync (ECalMetaBackend *meta_backend,
                } else {
                        guint status_code;
                        gboolean credentials_empty;
+                       gboolean is_tsl_error;
 
-                       if (local_error && local_error->domain == SOUP_HTTP_ERROR)
+                       if (local_error && local_error->domain == E_SOUP_SESSION_ERROR)
                                status_code = local_error->code;
                        else
-                               status_code = message ? message->status_code : SOUP_STATUS_MALFORMED;
+                               status_code = soup_message_get_status (message);
 
                        credentials_empty = !credentials || !e_named_parameters_count (credentials);
+                       is_tsl_error = g_error_matches (local_error, G_TLS_ERROR, 
G_TLS_ERROR_BAD_CERTIFICATE);
 
                        *out_auth_result = E_SOURCE_AUTHENTICATION_ERROR;
 
-                       /* because evolution knows only G_IO_ERROR_CANCELLED */
-                       if (status_code == SOUP_STATUS_CANCELLED) {
-                               g_set_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED,
-                                       "%s", (local_error && local_error->domain == SOUP_HTTP_ERROR) ? 
local_error->message :
-                                       (message && message->reason_phrase) ? message->reason_phrase : 
soup_status_get_phrase (status_code));
-                       } else if (status_code == SOUP_STATUS_FORBIDDEN && credentials_empty) {
+                       if (status_code == SOUP_STATUS_FORBIDDEN && credentials_empty) {
                                *out_auth_result = E_SOURCE_AUTHENTICATION_REQUIRED;
                        } else if (status_code == SOUP_STATUS_UNAUTHORIZED) {
                                if (credentials_empty)
@@ -291,11 +280,11 @@ ecb_http_connect_sync (ECalMetaBackend *meta_backend,
                                g_propagate_error (error, local_error);
                                local_error = NULL;
                        } else {
-                               g_set_error_literal (error, SOUP_HTTP_ERROR, status_code,
-                                       message ? message->reason_phrase : soup_status_get_phrase 
(status_code));
+                               g_set_error_literal (error, E_SOUP_SESSION_ERROR, status_code,
+                                       soup_message_get_reason_phrase (message) ? 
soup_message_get_reason_phrase (message) : soup_status_get_phrase (status_code));
                        }
 
-                       if (status_code == SOUP_STATUS_SSL_FAILED) {
+                       if (is_tsl_error) {
                                *out_auth_result = E_SOURCE_AUTHENTICATION_ERROR_SSL_FAILED;
 
                                e_source_set_connection_status (source, 
E_SOURCE_CONNECTION_STATUS_SSL_FAILED);
@@ -304,8 +293,6 @@ ecb_http_connect_sync (ECalMetaBackend *meta_backend,
                                e_source_set_connection_status (source, 
E_SOURCE_CONNECTION_STATUS_DISCONNECTED);
                        }
                }
-
-               g_clear_object (&message);
        } else {
                e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_DISCONNECTED);
 
@@ -314,14 +301,18 @@ ecb_http_connect_sync (ECalMetaBackend *meta_backend,
        }
 
        if (success) {
-               cbhttp->priv->request = request;
-               cbhttp->priv->input_stream = input_stream;
+               cbhttp->priv->icalstring = ecb_http_read_stream_sync (input_stream,
+                       soup_message_headers_get_content_length (soup_message_get_response_headers 
(message)), cancellable, error);
+               success =  cbhttp->priv->icalstring != NULL;
+       }
+
+       if (success) {
+               cbhttp->priv->message = message;
                cbhttp->priv->hsts_until_time = ecb_http_extract_hsts_until_time (cbhttp);
 
                *out_auth_result = E_SOURCE_AUTHENTICATION_ACCEPTED;
        } else {
-               g_clear_object (&request);
-               g_clear_object (&input_stream);
+               g_clear_object (&message);
 
                if (*out_auth_result != E_SOURCE_AUTHENTICATION_REQUIRED &&
                    *out_auth_result != E_SOURCE_AUTHENTICATION_REJECTED)
@@ -329,6 +320,7 @@ ecb_http_connect_sync (ECalMetaBackend *meta_backend,
        }
 
        g_rec_mutex_unlock (&cbhttp->priv->conn_lock);
+       g_clear_object (&input_stream);
        g_clear_error (&local_error);
        g_free (uri);
 
@@ -349,8 +341,8 @@ ecb_http_disconnect_sync (ECalMetaBackend *meta_backend,
 
        g_rec_mutex_lock (&cbhttp->priv->conn_lock);
 
-       g_clear_object (&cbhttp->priv->input_stream);
-       g_clear_object (&cbhttp->priv->request);
+       g_clear_pointer (&cbhttp->priv->icalstring, g_free);
+       g_clear_object (&cbhttp->priv->message);
 
        if (cbhttp->priv->session)
                soup_session_abort (SOUP_SESSION (cbhttp->priv->session));
@@ -378,12 +370,11 @@ ecb_http_get_changes_sync (ECalMetaBackend *meta_backend,
                           GError **error)
 {
        ECalBackendHttp *cbhttp;
-       SoupMessage *message;
-       gchar *icalstring;
        ICalCompIter *iter = NULL;
        ICalComponent *maincomp, *subcomp;
        ICalComponentKind backend_kind;
        GHashTable *components = NULL;
+       const gchar *new_etag;
        gboolean success = TRUE;
 
        g_return_val_if_fail (E_IS_CAL_BACKEND_HTTP (meta_backend), FALSE);
@@ -397,67 +388,46 @@ ecb_http_get_changes_sync (ECalMetaBackend *meta_backend,
 
        g_rec_mutex_lock (&cbhttp->priv->conn_lock);
 
-       if (!cbhttp->priv->request || !cbhttp->priv->input_stream) {
+       if (!cbhttp->priv->message || !cbhttp->priv->icalstring) {
                g_rec_mutex_unlock (&cbhttp->priv->conn_lock);
                g_propagate_error (error, EC_ERROR (E_CLIENT_ERROR_REPOSITORY_OFFLINE));
                return FALSE;
        }
 
-       message = soup_request_http_get_message (cbhttp->priv->request);
-       if (message) {
-               const gchar *new_etag;
-
-               if (message->status_code == SOUP_STATUS_NOT_MODIFIED) {
-                       g_rec_mutex_unlock (&cbhttp->priv->conn_lock);
-                       g_object_unref (message);
-
-                       ecb_http_disconnect_sync (meta_backend, cancellable, NULL);
+       if (soup_message_get_status (cbhttp->priv->message) == SOUP_STATUS_NOT_MODIFIED) {
+               g_rec_mutex_unlock (&cbhttp->priv->conn_lock);
 
-                       return TRUE;
-               }
+               ecb_http_disconnect_sync (meta_backend, cancellable, NULL);
 
-               new_etag = soup_message_headers_get_one (message->response_headers, "ETag");
-               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);
+               return TRUE;
+       }
 
-                       ecb_http_disconnect_sync (meta_backend, cancellable, NULL);
+       new_etag = soup_message_headers_get_one (soup_message_get_response_headers (cbhttp->priv->message), 
"ETag");
+       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);
 
-                       return TRUE;
-               }
+               /* Nothing changed */
+               ecb_http_disconnect_sync (meta_backend, cancellable, NULL);
 
-               *out_new_sync_tag = g_strdup (new_etag);
+               return TRUE;
        }
 
-       g_clear_object (&message);
-
-       icalstring = ecb_http_read_stream_sync (cbhttp->priv->input_stream,
-               soup_request_get_content_length (SOUP_REQUEST (cbhttp->priv->request)), cancellable, error);
+       *out_new_sync_tag = g_strdup (new_etag);
 
        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);
-               ecb_http_disconnect_sync (meta_backend, cancellable, NULL);
-               return FALSE;
-       }
-
        /* Skip the UTF-8 marker at the beginning of the string */
-       if (((guchar) icalstring[0]) == 0xEF &&
-           ((guchar) icalstring[1]) == 0xBB &&
-           ((guchar) icalstring[2]) == 0xBF)
-               maincomp = i_cal_parser_parse_string (icalstring + 3);
+       if (((guchar) cbhttp->priv->icalstring[0]) == 0xEF &&
+           ((guchar) cbhttp->priv->icalstring[1]) == 0xBB &&
+           ((guchar) cbhttp->priv->icalstring[2]) == 0xBF)
+               maincomp = i_cal_parser_parse_string (cbhttp->priv->icalstring + 3);
        else
-               maincomp = i_cal_parser_parse_string (icalstring);
-
-       g_free (icalstring);
+               maincomp = i_cal_parser_parse_string (cbhttp->priv->icalstring);
 
        if (!maincomp) {
-               g_set_error (error, SOUP_HTTP_ERROR, SOUP_STATUS_MALFORMED, _("Bad file format."));
+               g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Bad file format."));
                e_cal_meta_backend_empty_cache_sync (meta_backend, cancellable, NULL);
                ecb_http_disconnect_sync (meta_backend, cancellable, NULL);
                return FALSE;
@@ -466,7 +436,7 @@ ecb_http_get_changes_sync (ECalMetaBackend *meta_backend,
        if (i_cal_component_isa (maincomp) != I_CAL_VCALENDAR_COMPONENT &&
            i_cal_component_isa (maincomp) != I_CAL_XROOT_COMPONENT) {
                g_object_unref (maincomp);
-               g_set_error (error, SOUP_HTTP_ERROR, SOUP_STATUS_MALFORMED, _("Not a calendar."));
+               g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Not a calendar."));
                e_cal_meta_backend_empty_cache_sync (meta_backend, cancellable, NULL);
                ecb_http_disconnect_sync (meta_backend, cancellable, NULL);
                return FALSE;
@@ -563,8 +533,8 @@ ecb_http_get_changes_sync (ECalMetaBackend *meta_backend,
                g_object_unref (maincomp);
        }
 
-       if (!success)
-               ecb_http_disconnect_sync (meta_backend, cancellable, NULL);
+       /* Always disconnect, to free the resources needed to download the iCalendar file */
+       ecb_http_disconnect_sync (meta_backend, cancellable, NULL);
 
        return success;
 }
@@ -700,8 +670,8 @@ e_cal_backend_http_dispose (GObject *object)
 
        g_rec_mutex_lock (&cbhttp->priv->conn_lock);
 
-       g_clear_object (&cbhttp->priv->request);
-       g_clear_object (&cbhttp->priv->input_stream);
+       g_clear_object (&cbhttp->priv->message);
+       g_clear_pointer (&cbhttp->priv->icalstring, g_free);
 
        if (cbhttp->priv->session)
                soup_session_abort (SOUP_SESSION (cbhttp->priv->session));
diff --git a/src/calendar/backends/weather/e-cal-backend-weather.c 
b/src/calendar/backends/weather/e-cal-backend-weather.c
index c4999671f..abab67fd9 100644
--- a/src/calendar/backends/weather/e-cal-backend-weather.c
+++ b/src/calendar/backends/weather/e-cal-backend-weather.c
@@ -464,11 +464,7 @@ create_weather (ECalBackendWeather *cbw,
        time_t                     update_time;
        ICalTimezone              *update_zone = NULL;
        const GWeatherLocation    *location;
-       #ifdef WITH_GWEATHER4
        GTimeZone                 *w_timezone;
-       #else
-       const GWeatherTimezone    *w_timezone;
-       #endif
        gdouble tmin = 0.0, tmax = 0.0, temp = 0.0;
 
        g_return_val_if_fail (E_IS_CAL_BACKEND_WEATHER (cbw), NULL);
@@ -488,11 +484,7 @@ create_weather (ECalBackendWeather *cbw,
        /* use timezone of the location to determine date for which this is set */
        location = gweather_info_get_location (report);
        if (location && (w_timezone = gweather_location_get_timezone ((GWeatherLocation *) location)))
-               #ifdef WITH_GWEATHER4
                update_zone = i_cal_timezone_get_builtin_timezone (g_time_zone_get_identifier (w_timezone));
-               #else
-               update_zone = i_cal_timezone_get_builtin_timezone (gweather_timezone_get_tzid 
((GWeatherTimezone *) w_timezone));
-               #endif
 
        if (!update_zone)
                update_zone = i_cal_timezone_get_utc_timezone ();
diff --git a/src/calendar/backends/weather/e-weather-source.c 
b/src/calendar/backends/weather/e-weather-source.c
index 7aff1f6ac..23df3a0f9 100644
--- a/src/calendar/backends/weather/e-weather-source.c
+++ b/src/calendar/backends/weather/e-weather-source.c
@@ -39,11 +39,7 @@ weather_source_dispose (GObject *object)
        EWeatherSourcePrivate *priv;
 
        priv = E_WEATHER_SOURCE (object)->priv;
-       #ifdef WITH_GWEATHER4
        g_clear_object (&priv->location);
-       #else
-       g_clear_pointer (&priv->location, gweather_location_unref);
-       #endif
 
        g_clear_object (&priv->info);
 
@@ -72,12 +68,7 @@ weather_source_find_location_by_coords (GWeatherLocation *start,
                                         gdouble longitude)
 {
        GWeatherLocation *location;
-       #if GWEATHER_CHECK_VERSION(3, 39, 0)
        GWeatherLocation *child = NULL;
-       #else
-       GWeatherLocation **children;
-       gint ii;
-       #endif
 
        if (!start)
                return NULL;
@@ -89,39 +80,20 @@ weather_source_find_location_by_coords (GWeatherLocation *start,
                gweather_location_get_coords (location, &lat, &lon);
 
                if (lat == latitude && lon == longitude) {
-                       #ifdef WITH_GWEATHER4
                        g_object_ref (location);
-                       #else
-                       gweather_location_ref (location);
-                       #endif
                        return location;
                }
        }
 
-       #if GWEATHER_CHECK_VERSION(3, 39, 0)
        while (child = gweather_location_next_child (location, child), child) {
                GWeatherLocation *result;
 
                result = weather_source_find_location_by_coords (child, latitude, longitude);
                if (result) {
-                       #ifdef WITH_GWEATHER4
                        g_object_unref (child);
-                       #else
-                       gweather_location_unref (child);
-                       #endif
                        return result;
                }
        }
-       #else
-       children = gweather_location_get_children (location);
-       for (ii = 0; children[ii]; ii++) {
-               location = weather_source_find_location_by_coords (children[ii], latitude, longitude);
-               if (location) {
-                       gweather_location_ref (location);
-                       return location;
-               }
-       }
-       #endif
 
        return NULL;
 }
@@ -155,11 +127,6 @@ e_weather_source_new (const gchar *location)
 
        glocation = gweather_location_find_by_station_code (world, tokens[0]);
 
-#if !GWEATHER_CHECK_VERSION(3, 39, 0)
-       if (glocation)
-               gweather_location_ref (glocation);
-#endif
-
        if (!glocation) {
                gdouble latitude, longitude;
                gchar *endptr = NULL;
@@ -171,11 +138,7 @@ e_weather_source_new (const gchar *location)
                }
        }
 
-#ifdef WITH_GWEATHER4
        g_object_unref (world);
-#elif GWEATHER_CHECK_VERSION(3, 39, 0)
-       gweather_location_unref (world);
-#endif
        g_strfreev (tokens);
 
        if (glocation == NULL)
@@ -216,16 +179,9 @@ e_weather_source_parse (EWeatherSource *source,
        source->priv->done = done;
 
        if (source->priv->info == NULL) {
-               source->priv->info = gweather_info_new (
-                       source->priv->location
-               #ifndef HAVE_ONE_ARG_GWEATHER_INFO_NEW
-                       , GWEATHER_FORECAST_LIST
-               #endif
-               );
-               #if GWEATHER_CHECK_VERSION(3, 39, 0)
+               source->priv->info = gweather_info_new (source->priv->location);
                gweather_info_set_application_id (source->priv->info, "org.gnome.Evolution-data-server");
                gweather_info_set_contact_info (source->priv->info, "evolution-hackers gnome org");
-               #endif
                gweather_info_set_enabled_providers (source->priv->info, GWEATHER_PROVIDER_METAR | 
GWEATHER_PROVIDER_IWIN);
                g_signal_connect_object (
                        source->priv->info, "updated",
diff --git a/src/calendar/backends/webdav-notes/e-cal-backend-webdav-notes.c 
b/src/calendar/backends/webdav-notes/e-cal-backend-webdav-notes.c
index 3eed5fc19..bd6146a87 100644
--- a/src/calendar/backends/webdav-notes/e-cal-backend-webdav-notes.c
+++ b/src/calendar/backends/webdav-notes/e-cal-backend-webdav-notes.c
@@ -175,9 +175,9 @@ ecb_webdav_notes_connect_sync (ECalMetaBackend *meta_backend,
                        g_slist_free_full (privileges, e_webdav_privilege_free);
                } else {
                        is_writable = allows && (
-                               g_hash_table_contains (allows, SOUP_METHOD_PUT) ||
-                               g_hash_table_contains (allows, SOUP_METHOD_POST) ||
-                               g_hash_table_contains (allows, SOUP_METHOD_DELETE));
+                               g_hash_table_contains (allows, "PUT") ||
+                               g_hash_table_contains (allows, "POST") ||
+                               g_hash_table_contains (allows, "DELETE"));
                }
        }
 
@@ -196,7 +196,7 @@ ecb_webdav_notes_connect_sync (ECalMetaBackend *meta_backend,
                   The 'getctag' extension is not required, thus check
                   for unauthorized error only. */
                if (!e_webdav_session_getctag_sync (webdav, NULL, &ctag, cancellable, &local_error) &&
-                   g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_UNAUTHORIZED)) {
+                   g_error_matches (local_error, E_SOUP_SESSION_ERROR, SOUP_STATUS_UNAUTHORIZED)) {
                        success = FALSE;
                } else {
                        g_clear_error (&local_error);
@@ -207,22 +207,18 @@ ecb_webdav_notes_connect_sync (ECalMetaBackend *meta_backend,
 
        if (!success) {
                gboolean credentials_empty;
-               gboolean is_ssl_error;
+               gboolean is_tls_error = FALSE;
 
                credentials_empty = (!credentials || !e_named_parameters_count (credentials) ||
                        (e_named_parameters_count (credentials) == 1 && e_named_parameters_exists 
(credentials, E_SOURCE_CREDENTIAL_SSL_TRUST))) &&
                        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);
+               is_tls_error = g_error_matches (local_error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE);
 
                *out_auth_result = E_SOURCE_AUTHENTICATION_ERROR;
 
-               /* because evolution knows only G_IO_ERROR_CANCELLED */
-               if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_CANCELLED)) {
-                       local_error->domain = G_IO_ERROR;
-                       local_error->code = G_IO_ERROR_CANCELLED;
-               } else if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_FORBIDDEN) && 
credentials_empty) {
+               if (g_error_matches (local_error, E_SOUP_SESSION_ERROR, SOUP_STATUS_FORBIDDEN) && 
credentials_empty) {
                        *out_auth_result = E_SOURCE_AUTHENTICATION_REQUIRED;
-               } else if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_UNAUTHORIZED)) {
+               } else if (g_error_matches (local_error, E_SOUP_SESSION_ERROR, SOUP_STATUS_UNAUTHORIZED)) {
                        if (credentials_empty)
                                *out_auth_result = E_SOURCE_AUTHENTICATION_REQUIRED;
                        else
@@ -241,7 +237,7 @@ ecb_webdav_notes_connect_sync (ECalMetaBackend *meta_backend,
                        local_error = NULL;
                }
 
-               if (is_ssl_error) {
+               if (is_tls_error) {
                        *out_auth_result = E_SOURCE_AUTHENTICATION_ERROR_SSL_FAILED;
 
                        e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_SSL_FAILED);
@@ -355,12 +351,12 @@ ecb_webdav_notes_check_credentials_error (ECalBackendWebDAVNotes *cbnotes,
 {
        g_return_if_fail (E_IS_CAL_BACKEND_WEBDAV_NOTES (cbnotes));
 
-       if (g_error_matches (op_error, SOUP_HTTP_ERROR, SOUP_STATUS_SSL_FAILED) && webdav) {
+       if (g_error_matches (op_error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE) && webdav) {
                op_error->domain = E_CLIENT_ERROR;
                op_error->code = E_CLIENT_ERROR_TLS_NOT_AVAILABLE;
-       } else if (g_error_matches (op_error, SOUP_HTTP_ERROR, SOUP_STATUS_UNAUTHORIZED) ||
-                  g_error_matches (op_error, SOUP_HTTP_ERROR, SOUP_STATUS_FORBIDDEN)) {
-               gboolean was_forbidden = g_error_matches (op_error, SOUP_HTTP_ERROR, SOUP_STATUS_FORBIDDEN);
+       } else if (g_error_matches (op_error, E_SOUP_SESSION_ERROR, SOUP_STATUS_UNAUTHORIZED) ||
+                  g_error_matches (op_error, E_SOUP_SESSION_ERROR, SOUP_STATUS_FORBIDDEN)) {
+               gboolean was_forbidden = g_error_matches (op_error, E_SOUP_SESSION_ERROR, 
SOUP_STATUS_FORBIDDEN);
 
                op_error->domain = E_CLIENT_ERROR;
                op_error->code = E_CLIENT_ERROR_AUTHENTICATION_REQUIRED;
@@ -396,7 +392,7 @@ ecb_webdav_notes_check_credentials_error (ECalBackendWebDAVNotes *cbnotes,
 static gboolean
 ecb_webdav_notes_getetag_cb (EWebDAVSession *webdav,
                             xmlNodePtr prop_node,
-                            const SoupURI *request_uri,
+                            const GUri *request_uri,
                             const gchar *href,
                             guint status_code,
                             gpointer user_data)
@@ -520,7 +516,7 @@ ecb_webdav_notes_get_objects_sync (EWebDAVSession *webdav,
                if (!nfo)
                        continue;
 
-               success = e_webdav_session_get_data_sync (webdav, nfo->extra, NULL, &etag, &bytes, NULL, 
cancellable, error);
+               success = e_webdav_session_get_data_sync (webdav, nfo->extra, NULL, &etag, NULL, &bytes, 
NULL, cancellable, error);
 
                if (success) {
                        EWebDAVResource *resource;
@@ -754,15 +750,15 @@ ecb_webdav_notes_uid_to_uri (ECalBackendWebDAVNotes *cbnotes,
                             const gchar *uid)
 {
        ESourceWebdav *webdav_extension;
-       SoupURI *soup_uri;
+       GUri *parsed_uri;
        gchar *uri, *tmp, *filename, *uid_hash = NULL;
 
        g_return_val_if_fail (E_IS_CAL_BACKEND_WEBDAV_NOTES (cbnotes), NULL);
        g_return_val_if_fail (uid != NULL, NULL);
 
        webdav_extension = e_source_get_extension (e_backend_get_source (E_BACKEND (cbnotes)), 
E_SOURCE_EXTENSION_WEBDAV_BACKEND);
-       soup_uri = e_source_webdav_dup_soup_uri (webdav_extension);
-       g_return_val_if_fail (soup_uri != NULL, NULL);
+       parsed_uri = e_source_webdav_dup_uri (webdav_extension);
+       g_return_val_if_fail (parsed_uri != NULL, NULL);
 
        /* UIDs with forward slashes can cause trouble, because the destination server can
           consider them as a path delimiter. Double-encode the URL doesn't always work,
@@ -774,25 +770,22 @@ ecb_webdav_notes_uid_to_uri (ECalBackendWebDAVNotes *cbnotes,
                        uid = uid_hash;
        }
 
-       filename = soup_uri_encode (uid, NULL);
+       filename = g_uri_escape_string (uid, NULL, FALSE);
 
-       if (soup_uri->path) {
-               gchar *slash = strrchr (soup_uri->path, '/');
+       if (*g_uri_get_path (parsed_uri)) {
+               const gchar *slash = strrchr (g_uri_get_path (parsed_uri), '/');
 
                if (slash && !slash[1])
-                       *slash = '\0';
-       }
-
-       soup_uri_set_user (soup_uri, NULL);
-       soup_uri_set_password (soup_uri, NULL);
-
-       tmp = g_strconcat (soup_uri->path && *soup_uri->path ? soup_uri->path : "", "/", filename, NULL);
-       soup_uri_set_path (soup_uri, tmp);
-       g_free (tmp);
+                       tmp = g_strconcat (g_uri_get_path (parsed_uri), filename, NULL);
+               else
+                       tmp = g_strconcat (g_uri_get_path (parsed_uri), "/", filename, NULL);
+       } else
+               tmp = g_strconcat ("/", filename, NULL);
 
-       uri = soup_uri_to_string (soup_uri, FALSE);
+       e_util_change_uri_component (&parsed_uri, SOUP_URI_PATH, tmp);
+       uri = g_uri_to_string_partial (parsed_uri, G_URI_HIDE_USERINFO | G_URI_HIDE_PASSWORD);
 
-       soup_uri_free (soup_uri);
+       g_uri_unref (parsed_uri);
        g_free (filename);
        g_free (uid_hash);
 
@@ -870,7 +863,7 @@ ecb_webdav_notes_load_component_sync (ECalMetaBackend *meta_backend,
        if (extra && *extra) {
                uri = g_strdup (extra);
 
-               success = e_webdav_session_get_data_sync (webdav, uri, &href, &etag, &bytes, &length, 
cancellable, &local_error);
+               success = e_webdav_session_get_data_sync (webdav, uri, &href, &etag, NULL, &bytes, &length, 
cancellable, &local_error);
 
                if (!success) {
                        g_free (uri);
@@ -910,7 +903,7 @@ ecb_webdav_notes_load_component_sync (ECalMetaBackend *meta_backend,
 
                g_clear_error (&local_error);
 
-               success = e_webdav_session_get_data_sync (webdav, uri, &href, &etag, &bytes, &length, 
cancellable, &local_error);
+               success = e_webdav_session_get_data_sync (webdav, uri, &href, &etag, NULL, &bytes, &length, 
cancellable, &local_error);
        }
 
        if (success) {
@@ -988,7 +981,7 @@ ecb_webdav_notes_load_component_sync (ECalMetaBackend *meta_backend,
        if (local_error) {
                ecb_webdav_notes_check_credentials_error (cbnotes, webdav, local_error);
 
-               if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_NOT_FOUND)) {
+               if (g_error_matches (local_error, E_SOUP_SESSION_ERROR, SOUP_STATUS_NOT_FOUND)) {
                        local_error->domain = E_CAL_CLIENT_ERROR;
                        local_error->code = E_CAL_CLIENT_ERROR_OBJECT_NOT_FOUND;
                }
@@ -1169,11 +1162,11 @@ ecb_webdav_notes_save_component_sync (ECalMetaBackend *meta_backend,
 
                        success = e_webdav_session_put_data_sync (webdav, (!new_filename && extra && *extra) 
? extra : href,
                                force_write ? "" : (overwrite_existing && !new_filename) ? etag : NULL, 
use_content_type,
-                               description ? description : "", -1, &new_extra, &new_etag, cancellable, 
&local_error);
+                               NULL, description ? description : "", -1, &new_extra, &new_etag, NULL, 
cancellable, &local_error);
 
                        counter++;
                } while (!success && new_filename && !g_cancellable_is_cancelled (cancellable) &&
-                        g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_PRECONDITION_FAILED));
+                        g_error_matches (local_error, E_SOUP_SESSION_ERROR, 
SOUP_STATUS_PRECONDITION_FAILED));
 
                if (success && new_filename && extra && *extra) {
                        /* The name on the server changed, remove the old file */
@@ -1233,7 +1226,7 @@ ecb_webdav_notes_save_component_sync (ECalMetaBackend *meta_backend,
        g_free (href);
        g_free (etag);
 
-       if (overwrite_existing && g_error_matches (local_error, SOUP_HTTP_ERROR, 
SOUP_STATUS_PRECONDITION_FAILED)) {
+       if (overwrite_existing && g_error_matches (local_error, E_SOUP_SESSION_ERROR, 
SOUP_STATUS_PRECONDITION_FAILED)) {
                g_clear_error (&local_error);
 
                /* Pretend success when using the serer version on conflict,
@@ -1301,10 +1294,10 @@ ecb_webdav_notes_remove_component_sync (ECalMetaBackend *meta_backend,
 
        /* Ignore not found errors, this was a delete and the resource is gone.
           It can be that it had been deleted on the server by other application. */
-       if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_NOT_FOUND)) {
+       if (g_error_matches (local_error, E_SOUP_SESSION_ERROR, SOUP_STATUS_NOT_FOUND)) {
                g_clear_error (&local_error);
                success = TRUE;
-       } else if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_PRECONDITION_FAILED)) {
+       } else if (g_error_matches (local_error, E_SOUP_SESSION_ERROR, SOUP_STATUS_PRECONDITION_FAILED)) {
                g_clear_error (&local_error);
 
                /* Pretend success when using the serer version on conflict,
diff --git a/src/calendar/libecal/CMakeLists.txt b/src/calendar/libecal/CMakeLists.txt
index 55291e0cc..9ebce0856 100644
--- a/src/calendar/libecal/CMakeLists.txt
+++ b/src/calendar/libecal/CMakeLists.txt
@@ -119,7 +119,7 @@ install(FILES ${HEADERS}
 
 set(gir_sources ${SOURCES} ${HEADERS})
 set(gir_identifies_prefixes ECal E)
-set(gir_includes GObject-2.0 Gio-2.0 Soup-2.4 libxml2-2.0 ICalGLib-3.0)
+set(gir_includes GObject-2.0 Gio-2.0 Soup-3.0 libxml2-2.0 ICalGLib-3.0)
 set(gir_cflags
        -DLIBECAL_COMPILATION
        -DEDS_DISABLE_DEPRECATED=1
diff --git a/src/calendar/libedata-cal/CMakeLists.txt b/src/calendar/libedata-cal/CMakeLists.txt
index e85555a3f..cde635959 100644
--- a/src/calendar/libedata-cal/CMakeLists.txt
+++ b/src/calendar/libedata-cal/CMakeLists.txt
@@ -91,7 +91,7 @@ install(FILES ${HEADERS}
 
 set(gir_sources ${SOURCES} ${HEADERS})
 set(gir_identifies_prefixes E)
-set(gir_includes GObject-2.0 Gio-2.0 Soup-2.4 libxml2-2.0 ICalGLib-3.0)
+set(gir_includes GObject-2.0 Gio-2.0 Soup-3.0 libxml2-2.0 ICalGLib-3.0)
 set(gir_cflags
        -DLIBEDATA_CAL_COMPILATION
        -DEDS_DISABLE_DEPRECATED=1
diff --git a/src/calendar/libedata-cal/e-cal-meta-backend.c b/src/calendar/libedata-cal/e-cal-meta-backend.c
index 4f595eae9..94a875f91 100644
--- a/src/calendar/libedata-cal/e-cal-meta-backend.c
+++ b/src/calendar/libedata-cal/e-cal-meta-backend.c
@@ -88,7 +88,7 @@ struct _ECalMetaBackendPrivate {
        gchar *authentication_method;
        gchar *authentication_proxy_uid;
        gchar *authentication_credential_name;
-       SoupURI *webdav_soup_uri;
+       GUri *webdav_parsed_uri;
 };
 
 enum {
@@ -301,7 +301,7 @@ ecmb_update_connection_values (ECalMetaBackend *meta_backend)
        g_clear_pointer (&meta_backend->priv->authentication_method, g_free);
        g_clear_pointer (&meta_backend->priv->authentication_proxy_uid, g_free);
        g_clear_pointer (&meta_backend->priv->authentication_credential_name, g_free);
-       g_clear_pointer (&meta_backend->priv->webdav_soup_uri, (GDestroyNotify) soup_uri_free);
+       g_clear_pointer (&meta_backend->priv->webdav_parsed_uri, g_uri_unref);
 
        if (source && e_source_has_extension (source, E_SOURCE_EXTENSION_AUTHENTICATION)) {
                ESourceAuthentication *auth_extension;
@@ -321,7 +321,7 @@ ecmb_update_connection_values (ECalMetaBackend *meta_backend)
 
                webdav_extension = e_source_get_extension (source, E_SOURCE_EXTENSION_WEBDAV_BACKEND);
 
-               meta_backend->priv->webdav_soup_uri = e_source_webdav_dup_soup_uri (webdav_extension);
+               meta_backend->priv->webdav_parsed_uri = e_source_webdav_dup_uri (webdav_extension);
        }
 
        g_mutex_unlock (&meta_backend->priv->property_lock);
@@ -499,17 +499,17 @@ ecmb_requires_reconnect (ECalMetaBackend *meta_backend)
 
        if (!requires && e_source_has_extension (source, E_SOURCE_EXTENSION_WEBDAV_BACKEND)) {
                ESourceWebdav *webdav_extension;
-               SoupURI *soup_uri;
+               GUri *parsed_uri;
 
                webdav_extension = e_source_get_extension (source, E_SOURCE_EXTENSION_WEBDAV_BACKEND);
-               soup_uri = e_source_webdav_dup_soup_uri (webdav_extension);
+               parsed_uri = e_source_webdav_dup_uri (webdav_extension);
 
-               requires = (!meta_backend->priv->webdav_soup_uri && soup_uri) ||
-                       (soup_uri && meta_backend->priv->webdav_soup_uri &&
-                       !soup_uri_equal (meta_backend->priv->webdav_soup_uri, soup_uri));
+               requires = (!meta_backend->priv->webdav_parsed_uri && parsed_uri) ||
+                       (parsed_uri && meta_backend->priv->webdav_parsed_uri &&
+                       !soup_uri_equal (meta_backend->priv->webdav_parsed_uri, parsed_uri));
 
-               if (soup_uri)
-                       soup_uri_free (soup_uri);
+               if (parsed_uri)
+                       g_uri_unref (parsed_uri);
        }
 
        g_mutex_unlock (&meta_backend->priv->property_lock);
@@ -3455,7 +3455,7 @@ e_cal_meta_backend_finalize (GObject *object)
        g_clear_pointer (&meta_backend->priv->authentication_method, g_free);
        g_clear_pointer (&meta_backend->priv->authentication_proxy_uid, g_free);
        g_clear_pointer (&meta_backend->priv->authentication_credential_name, g_free);
-       g_clear_pointer (&meta_backend->priv->webdav_soup_uri, (GDestroyNotify) soup_uri_free);
+       g_clear_pointer (&meta_backend->priv->webdav_parsed_uri, g_uri_unref);
 
        g_mutex_clear (&meta_backend->priv->connect_lock);
        g_mutex_clear (&meta_backend->priv->property_lock);
diff --git a/src/camel/camel-message-info-base.c b/src/camel/camel-message-info-base.c
index 76ebefe3b..656a9ccea 100644
--- a/src/camel/camel-message-info-base.c
+++ b/src/camel/camel-message-info-base.c
@@ -947,11 +947,11 @@ message_info_base_dispose (GObject *object)
        camel_name_value_array_free (bmi->priv->user_tags);
        bmi->priv->user_tags = NULL;
 
-       g_clear_pointer (&bmi->priv->subject, (GDestroyNotify) camel_pstring_free);
-       g_clear_pointer (&bmi->priv->from, (GDestroyNotify) camel_pstring_free);
-       g_clear_pointer (&bmi->priv->to, (GDestroyNotify) camel_pstring_free);
-       g_clear_pointer (&bmi->priv->cc, (GDestroyNotify) camel_pstring_free);
-       g_clear_pointer (&bmi->priv->mlist, (GDestroyNotify) camel_pstring_free);
+       g_clear_pointer (&bmi->priv->subject, camel_pstring_free);
+       g_clear_pointer (&bmi->priv->from, camel_pstring_free);
+       g_clear_pointer (&bmi->priv->to, camel_pstring_free);
+       g_clear_pointer (&bmi->priv->cc, camel_pstring_free);
+       g_clear_pointer (&bmi->priv->mlist, camel_pstring_free);
        g_clear_pointer (&bmi->priv->preview, g_free);
 
        g_clear_pointer (&bmi->priv->references, g_array_unref);
diff --git a/src/camel/camel-text-index.c b/src/camel/camel-text-index.c
index 2afef6e78..a9827ed2a 100644
--- a/src/camel/camel-text-index.c
+++ b/src/camel/camel-text-index.c
@@ -1600,7 +1600,7 @@ camel_text_index_name_new (CamelTextIndex *idx,
        CamelIndexName *cin = &idn->parent;
        CamelTextIndexNamePrivate *p = CAMEL_TEXT_INDEX_NAME (idn)->priv;
 
-       cin->index = g_object_ref (idx);
+       cin->index = CAMEL_INDEX (g_object_ref (idx));
        cin->name = camel_mempool_strdup (p->pool, name);
        p->nameid = nameid;
 
@@ -1692,7 +1692,7 @@ camel_text_index_cursor_new (CamelTextIndex *idx,
        CamelIndexCursor *cic = &idc->parent;
        CamelTextIndexCursorPrivate *p = CAMEL_TEXT_INDEX_CURSOR (idc)->priv;
 
-       cic->index = g_object_ref (idx);
+       cic->index = CAMEL_INDEX (g_object_ref (idx));
        p->first = data;
        p->next = data;
        p->record_count = 0;
@@ -1787,7 +1787,7 @@ camel_text_index_key_cursor_new (CamelTextIndex *idx,
        CamelIndexCursor *cic = &idc->parent;
        CamelTextIndexKeyCursorPrivate *p = CAMEL_TEXT_INDEX_KEY_CURSOR (idc)->priv;
 
-       cic->index = g_object_ref (idx);
+       cic->index = CAMEL_INDEX (g_object_ref (idx));
        p->table = g_object_ref (table);
 
        return idc;
diff --git a/src/camel/providers/nntp/camel-nntp-folder.c b/src/camel/providers/nntp/camel-nntp-folder.c
index 3295bf4b2..34010a024 100644
--- a/src/camel/providers/nntp/camel-nntp-folder.c
+++ b/src/camel/providers/nntp/camel-nntp-folder.c
@@ -270,7 +270,7 @@ nntp_folder_download_message (CamelNNTPFolder *nntp_folder,
                        if (!success)
                                goto fail;
                } else {
-                       stream = g_object_ref (nntp_stream);
+                       stream = CAMEL_STREAM (g_object_ref (nntp_stream));
                }
 
        } else if (ret == 423 || ret == 430) {
diff --git a/src/libebackend/CMakeLists.txt b/src/libebackend/CMakeLists.txt
index 61c857ed7..e8d58bc7b 100644
--- a/src/libebackend/CMakeLists.txt
+++ b/src/libebackend/CMakeLists.txt
@@ -142,7 +142,7 @@ install(FILES ${HEADERS}
 
 set(gir_sources ${SOURCES} ${HEADERS})
 set(gir_identifies_prefixes E)
-set(gir_includes GObject-2.0 Gio-2.0 Soup-2.4 libxml2-2.0)
+set(gir_includes GObject-2.0 Gio-2.0 Soup-3.0 libxml2-2.0)
 set(gir_cflags
        -DLIBEBACKEND_COMPILATION
        -DEDS_DISABLE_DEPRECATED=1
diff --git a/src/libebackend/e-webdav-collection-backend.c b/src/libebackend/e-webdav-collection-backend.c
index e4301e66f..179b656d5 100644
--- a/src/libebackend/e-webdav-collection-backend.c
+++ b/src/libebackend/e-webdav-collection-backend.c
@@ -103,7 +103,7 @@ webdav_collection_remove_unknown_sources_cb (gpointer resource_id,
 static void
 webdav_collection_add_found_source (ECollectionBackend *collection,
                                    EWebDAVDiscoverSupports source_type,
-                                   SoupURI *uri,
+                                   GUri *uri,
                                    const gchar *display_name,
                                    const gchar *color,
                                    guint order,
@@ -167,7 +167,7 @@ webdav_collection_add_found_source (ECollectionBackend *collection,
        if (!server)
                return;
 
-       url = soup_uri_to_string (uri, FALSE);
+       url = g_uri_to_string_partial (uri, G_URI_HIDE_PASSWORD);
        identity = g_strconcat (identity_prefix, "::", url, NULL);
        source_uid = g_hash_table_lookup (known_sources, identity);
        is_new = !source_uid;
@@ -198,7 +198,7 @@ webdav_collection_add_found_source (ECollectionBackend *collection,
                if (!is_subscribed_icalendar)
                        e_source_authentication_set_user (child_auth, e_source_collection_get_identity 
(collection_extension));
 
-               e_source_webdav_set_soup_uri (child_webdav, uri);
+               e_source_webdav_set_uri (child_webdav, uri);
                e_source_resource_set_identity (resource, identity);
 
                if (is_new) {
@@ -280,25 +280,25 @@ webdav_collection_process_discovered_sources (ECollectionBackend *collection,
 
        for (link = discovered_sources; link; link = g_slist_next (link)) {
                EWebDAVDiscoveredSource *discovered_source = link->data;
-               SoupURI *soup_uri;
+               GUri *parsed_uri;
 
                if (!discovered_source || !discovered_source->href || !discovered_source->display_name)
                        continue;
 
-               soup_uri = soup_uri_new (discovered_source->href);
-               if (!soup_uri)
+               parsed_uri = g_uri_parse (discovered_source->href, SOUP_HTTP_URI_FLAGS, NULL);
+               if (!parsed_uri)
                        continue;
 
                for (ii = 0; ii < n_source_types; ii++) {
                        if ((discovered_source->supports & source_types[ii]) == source_types[ii])
-                               webdav_collection_add_found_source (collection, source_types[ii], soup_uri,
+                               webdav_collection_add_found_source (collection, source_types[ii], parsed_uri,
                                        discovered_source->display_name, discovered_source->color, 
discovered_source->order,
                                        (discovered_source->supports & 
E_WEBDAV_DISCOVER_SUPPORTS_CALENDAR_AUTO_SCHEDULE) != 0,
                                        (discovered_source->supports & 
E_WEBDAV_DISCOVER_SUPPORTS_SUBSCRIBED_ICALENDAR) != 0,
                                        known_sources);
                }
 
-               soup_uri_free (soup_uri);
+               g_uri_unref (parsed_uri);
        }
 }
 
@@ -627,8 +627,8 @@ e_webdav_collection_backend_discover_sync (EWebDAVCollectionBackend *webdav_back
 
                if (webdav_collection_debug_enabled () &&
                    (!credentials_empty || (
-                    !g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_UNAUTHORIZED) &&
-                    !g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_FORBIDDEN))))
+                    !g_error_matches (local_error, E_SOUP_SESSION_ERROR, SOUP_STATUS_UNAUTHORIZED) &&
+                    !g_error_matches (local_error, E_SOUP_SESSION_ERROR, SOUP_STATUS_FORBIDDEN))))
                        e_util_debug_print ("WEBDAV", "%p: Failed to get calendars from '%s': %s\n", 
webdav_backend, calendar_url, local_error->message);
        } else if (e_source_collection_get_calendar_enabled (collection_extension) && calendar_url) {
                if (webdav_collection_debug_enabled ()) {
@@ -665,8 +665,8 @@ e_webdav_collection_backend_discover_sync (EWebDAVCollectionBackend *webdav_back
 
                if (webdav_collection_debug_enabled () &&
                    (!credentials_empty || (
-                    !g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_UNAUTHORIZED) &&
-                    !g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_FORBIDDEN))))
+                    !g_error_matches (local_error, E_SOUP_SESSION_ERROR, SOUP_STATUS_UNAUTHORIZED) &&
+                    !g_error_matches (local_error, E_SOUP_SESSION_ERROR, SOUP_STATUS_FORBIDDEN))))
                        e_util_debug_print ("WEBDAV", "%p: Failed to get books from '%s': %s\n", 
webdav_backend, contacts_url, local_error->message);
        } else if (e_source_collection_get_contacts_enabled (collection_extension) && contacts_url) {
                if (webdav_collection_debug_enabled ()) {
@@ -696,14 +696,14 @@ e_webdav_collection_backend_discover_sync (EWebDAVCollectionBackend *webdav_back
        if (local_error == NULL) {
                result = E_SOURCE_AUTHENTICATION_ACCEPTED;
                e_collection_backend_authenticate_children (collection, credentials);
-       } else if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_UNAUTHORIZED) ||
-                  g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_FORBIDDEN)) {
+       } else if (g_error_matches (local_error, E_SOUP_SESSION_ERROR, SOUP_STATUS_UNAUTHORIZED) ||
+                  g_error_matches (local_error, E_SOUP_SESSION_ERROR, SOUP_STATUS_FORBIDDEN)) {
                if (credentials_empty)
                        result = E_SOURCE_AUTHENTICATION_REQUIRED;
                else
                        result = E_SOURCE_AUTHENTICATION_REJECTED;
                g_clear_error (&local_error);
-       } else if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_SSL_FAILED)) {
+       } else if (g_error_matches (local_error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE)) {
                result = E_SOURCE_AUTHENTICATION_ERROR_SSL_FAILED;
                g_propagate_error (error, local_error);
        } else {
diff --git a/src/libedataserver/CMakeLists.txt b/src/libedataserver/CMakeLists.txt
index 32fcb543a..93ab4be3a 100644
--- a/src/libedataserver/CMakeLists.txt
+++ b/src/libedataserver/CMakeLists.txt
@@ -71,11 +71,9 @@ set(SOURCES
        e-oauth2-service-yahoo.c
        e-oauth2-services.c
        e-operation-pool.c
-       e-proxy.c
        e-secret-store.c
        e-sexp.c
        e-soup-auth-bearer.c
-       e-soup-logger.c
        e-soup-session.c
        e-soup-ssl-trust.c
        e-source.c
@@ -163,11 +161,9 @@ set(HEADERS
        e-oauth2-service-yahoo.h
        e-oauth2-services.h
        e-operation-pool.h
-       e-proxy.h
        e-secret-store.h
        e-sexp.h
        e-soup-auth-bearer.h
-       e-soup-logger.h
        e-soup-session.h
        e-soup-ssl-trust.h
        e-source.h
@@ -299,7 +295,7 @@ install(FILES ${HEADERS}
 
 set(gir_sources ${SOURCES} ${HEADERS})
 set(gir_identifies_prefixes E)
-set(gir_includes GObject-2.0 Gio-2.0 Soup-2.4 libxml2-2.0 ${LIBGDATA_GIR})
+set(gir_includes GObject-2.0 Gio-2.0 Soup-3.0 libxml2-2.0 ${LIBGDATA_GIR})
 set(gir_cflags
        -DLIBEDATASERVER_COMPILATION
 )
diff --git a/src/libedataserver/e-data-server-util.c b/src/libedataserver/e-data-server-util.c
index c1a792019..9fa497859 100644
--- a/src/libedataserver/e-data-server-util.c
+++ b/src/libedataserver/e-data-server-util.c
@@ -31,6 +31,7 @@
 #endif
 
 #include <glib-object.h>
+#include <libsoup/soup.h>
 
 #include "e-source.h"
 #include "e-source-address-book.h"
@@ -3444,3 +3445,61 @@ e_util_get_directory_variants (const gchar *main_path,
 
        return camel_util_get_directory_variants (main_path, replace_prefix, with_modules_dir);
 }
+
+/**
+ * e_util_change_uri_component:
+ * @inout_uri: (inout): a #GUri
+ * @component: a string #SoupURIComponent to change
+ * @value: (nullable): a value to set, or %NULL to unset
+ *
+ * Changes component @component in the @inout_uri to value @value.
+ * As the #GUri cannot be modified the @inout_uri points to a new #GUri
+ * at the end of the call and the previous structure is unreffed.
+ *
+ * See: e_util_change_uri_port()
+ *
+ * Since: 3.48
+ **/
+void
+e_util_change_uri_component (GUri **inout_uri,
+                            SoupURIComponent component,
+                            const gchar *value)
+{
+       GUri *tmp;
+
+       g_return_if_fail (inout_uri != NULL);
+       g_return_if_fail (*inout_uri != NULL);
+       g_return_if_fail (component != SOUP_URI_PORT);
+       g_return_if_fail (component != SOUP_URI_NONE);
+
+       tmp = soup_uri_copy (*inout_uri, component, value, SOUP_URI_NONE);
+       g_uri_unref (*inout_uri);
+       *inout_uri = tmp;
+}
+
+/**
+ * e_util_change_uri_port:
+ * @inout_uri: (inout): a #GUri
+ * @port: the port number to set
+ *
+ * Changes the port in the @inout_uri to value @port.
+ * As the #GUri cannot be modified the @inout_uri points to a new #GUri
+ * at the end of the call and the previous structure is unreffed.
+ *
+ * See: e_util_change_uri_component()
+ *
+ * Since: 3.48
+ **/
+void
+e_util_change_uri_port (GUri **inout_uri,
+                       gint port)
+{
+       GUri *tmp;
+
+       g_return_if_fail (inout_uri != NULL);
+       g_return_if_fail (*inout_uri != NULL);
+
+       tmp = soup_uri_copy (*inout_uri, SOUP_URI_PORT, port, SOUP_URI_NONE);
+       g_uri_unref (*inout_uri);
+       *inout_uri = tmp;
+}
diff --git a/src/libedataserver/e-data-server-util.h b/src/libedataserver/e-data-server-util.h
index 797760012..33acbd6b6 100644
--- a/src/libedataserver/e-data-server-util.h
+++ b/src/libedataserver/e-data-server-util.h
@@ -28,6 +28,7 @@
 
 #include <sys/types.h>
 #include <gio/gio.h>
+#include <libsoup/soup.h>
 
 #include <libedataserver/e-source-enums.h>
 
@@ -298,6 +299,11 @@ gint               e_util_source_compare_for_sort  (struct _ESource *source_a,
 GPtrArray *    e_util_get_directory_variants   (const gchar *main_path,
                                                 const gchar *replace_prefix,
                                                 gboolean with_modules_dir);
+void           e_util_change_uri_component     (GUri **inout_uri,
+                                                SoupURIComponent component,
+                                                const gchar *value);
+void           e_util_change_uri_port          (GUri **inout_uri,
+                                                gint port);
 
 G_END_DECLS
 
diff --git a/src/libedataserver/e-gdata-oauth2-authorizer.c b/src/libedataserver/e-gdata-oauth2-authorizer.c
index 038ca86db..8eec022ba 100644
--- a/src/libedataserver/e-gdata-oauth2-authorizer.c
+++ b/src/libedataserver/e-gdata-oauth2-authorizer.c
@@ -218,7 +218,7 @@ e_gdata_oauth2_authorizer_process_request (GDataAuthorizer *authorizer,
        /* Use replace here, not append, to make sure
         * there's only one "Authorization" header. */
        soup_message_headers_replace (
-               message->request_headers,
+               soup_message_get_request_headers (message),
                "Authorization", authorization);
 
        g_free (authorization);
diff --git a/src/libedataserver/e-oauth2-service-google.c b/src/libedataserver/e-oauth2-service-google.c
index 93af1cb0b..5cdc68c21 100644
--- a/src/libedataserver/e-oauth2-service-google.c
+++ b/src/libedataserver/e-oauth2-service-google.c
@@ -226,11 +226,11 @@ eos_google_extract_authorization_code (EOAuth2Service *service,
        }
 
        if (page_uri && *page_uri) {
-               SoupURI *suri;
+               GUri *suri;
 
-               suri = soup_uri_new (page_uri);
+               suri = g_uri_parse (page_uri, SOUP_HTTP_URI_FLAGS, NULL);
                if (suri) {
-                       const gchar *query = soup_uri_get_query (suri);
+                       const gchar *query = g_uri_get_query (suri);
                        gboolean known = FALSE;
 
                        if (query && *query) {
@@ -252,7 +252,7 @@ eos_google_extract_authorization_code (EOAuth2Service *service,
                                }
                        }
 
-                       soup_uri_free (suri);
+                       g_uri_unref (suri);
 
                        if (known)
                                return TRUE;
diff --git a/src/libedataserver/e-oauth2-service-outlook.c b/src/libedataserver/e-oauth2-service-outlook.c
index 687c10d3b..758aa7dd8 100644
--- a/src/libedataserver/e-oauth2-service-outlook.c
+++ b/src/libedataserver/e-oauth2-service-outlook.c
@@ -162,7 +162,7 @@ eos_outlook_extract_authorization_code (EOAuth2Service *service,
                                        const gchar *page_content,
                                        gchar **out_authorization_code)
 {
-       SoupURI *suri;
+       GUri *suri;
        gboolean known = FALSE;
 
        g_return_val_if_fail (out_authorization_code != NULL, FALSE);
@@ -172,12 +172,12 @@ eos_outlook_extract_authorization_code (EOAuth2Service *service,
        if (!page_uri || !*page_uri)
                return FALSE;
 
-       suri = soup_uri_new (page_uri);
+       suri = g_uri_parse (page_uri, SOUP_HTTP_URI_FLAGS, NULL);
        if (!suri)
                return FALSE;
 
-       if (suri->query) {
-               GHashTable *uri_query = soup_form_decode (suri->query);
+       if (g_uri_get_query (suri)) {
+               GHashTable *uri_query = soup_form_decode (g_uri_get_query (suri));
 
                if (uri_query) {
                        const gchar *code;
@@ -195,7 +195,7 @@ eos_outlook_extract_authorization_code (EOAuth2Service *service,
                }
        }
 
-       soup_uri_free (suri);
+       g_uri_unref (suri);
 
        return known;
 }
diff --git a/src/libedataserver/e-oauth2-service-yahoo.c b/src/libedataserver/e-oauth2-service-yahoo.c
index b16e6b18a..cd750fa7e 100644
--- a/src/libedataserver/e-oauth2-service-yahoo.c
+++ b/src/libedataserver/e-oauth2-service-yahoo.c
@@ -175,11 +175,11 @@ eos_yahoo_extract_authorization_code (EOAuth2Service *service,
        *out_authorization_code = NULL;
 
        if (page_uri && *page_uri) {
-               SoupURI *suri;
+               GUri *suri;
 
-               suri = soup_uri_new (page_uri);
+               suri = g_uri_parse (page_uri, SOUP_HTTP_URI_FLAGS, NULL);
                if (suri) {
-                       const gchar *query = soup_uri_get_query (suri);
+                       const gchar *query = g_uri_get_query (suri);
                        gboolean known = FALSE;
 
                        if (query && *query) {
@@ -199,7 +199,7 @@ eos_yahoo_extract_authorization_code (EOAuth2Service *service,
                                }
                        }
 
-                       soup_uri_free (suri);
+                       g_uri_unref (suri);
 
                        if (known)
                                return TRUE;
diff --git a/src/libedataserver/e-oauth2-service.c b/src/libedataserver/e-oauth2-service.c
index 25c8483cf..8f6990f95 100644
--- a/src/libedataserver/e-oauth2-service.c
+++ b/src/libedataserver/e-oauth2-service.c
@@ -35,6 +35,7 @@
 #include <json-glib/json-glib.h>
 
 #include "e-secret-store.h"
+#include "e-soup-session.h"
 #include "e-soup-ssl-trust.h"
 #include "e-source-authentication.h"
 
@@ -805,16 +806,14 @@ eos_create_soup_session (EOAuth2ServiceRefSourceFunc ref_source,
        session = soup_session_new ();
        g_object_set (
                session,
-               SOUP_SESSION_TIMEOUT, 90,
-               SOUP_SESSION_SSL_STRICT, TRUE,
-               SOUP_SESSION_SSL_USE_SYSTEM_CA_FILE, TRUE,
-               SOUP_SESSION_ACCEPT_LANGUAGE_AUTO, TRUE,
+               "timeout", 90,
+               "accept-language-auto", TRUE,
                NULL);
 
        if (oauth2_debug) {
                SoupLogger *logger;
 
-               logger = soup_logger_new (SOUP_LOGGER_LOG_BODY, -1);
+               logger = soup_logger_new (SOUP_LOGGER_LOG_BODY);
                soup_session_add_feature (session, SOUP_SESSION_FEATURE (logger));
                g_object_unref (logger);
        }
@@ -835,7 +834,7 @@ eos_create_soup_session (EOAuth2ServiceRefSourceFunc ref_source,
 
                proxy_resolver = G_PROXY_RESOLVER (proxy_source);
                if (g_proxy_resolver_is_supported (proxy_resolver))
-                       g_object_set (session, SOUP_SESSION_PROXY_RESOLVER, proxy_resolver, NULL);
+                       g_object_set (session, "proxy-resolver", proxy_resolver, NULL);
 
                g_object_unref (proxy_source);
        }
@@ -866,12 +865,10 @@ eos_create_soup_message (ESource *source,
                return NULL;
        }
 
-       soup_message_set_request (message, "application/x-www-form-urlencoded",
-               SOUP_MEMORY_TAKE, post_data, strlen (post_data));
-
+       e_soup_session_util_set_message_request_body_from_data (message, FALSE, 
"application/x-www-form-urlencoded", post_data, strlen (post_data), g_free);
        e_soup_ssl_trust_connect (message, source);
 
-       soup_message_headers_append (message->request_headers, "Connection", "close");
+       soup_message_headers_append (soup_message_get_request_headers (message), "Connection", "close");
 
        return message;
 }
@@ -886,11 +883,12 @@ eos_abort_session_cb (GCancellable *cancellable,
 static gboolean
 eos_send_message (SoupSession *session,
                  SoupMessage *message,
-                 gchar **out_response_body,
+                 GBytes **out_response_body,
                  GCancellable *cancellable,
                  GError **error)
 {
-       guint status_code = SOUP_STATUS_CANCELLED;
+       guint status_code = 0;
+       GBytes *response_body = NULL;
        gboolean success = FALSE;
 
        g_return_val_if_fail (SOUP_IS_SESSION (session), FALSE);
@@ -903,35 +901,39 @@ eos_send_message (SoupSession *session,
                if (cancellable)
                        cancel_handler_id = g_cancellable_connect (cancellable, G_CALLBACK 
(eos_abort_session_cb), session, NULL);
 
-               status_code = soup_session_send_message (session, message);
+               response_body = soup_session_send_and_read (session, message, cancellable, error);
 
                if (cancel_handler_id)
                        g_cancellable_disconnect (cancellable, cancel_handler_id);
+
+               status_code = soup_message_get_status (message);
        }
 
        if (SOUP_STATUS_IS_SUCCESSFUL (status_code)) {
-               if (message->response_body) {
-                       *out_response_body = g_strndup (message->response_body->data, 
message->response_body->length);
+               if (response_body) {
+                       *out_response_body = g_steal_pointer (&response_body);
                        success = TRUE;
                } else {
-                       status_code = SOUP_STATUS_MALFORMED;
-                       g_set_error_literal (error, SOUP_HTTP_ERROR, status_code, _("Malformed, no message 
body set"));
+                       g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, _("Malformed, no 
message body set"));
                }
-       } else if (status_code != SOUP_STATUS_CANCELLED) {
+       } else if (status_code != 0) {
                GString *error_msg;
 
-               error_msg = g_string_new (message->reason_phrase);
-               if (message->response_body && message->response_body->length) {
+               error_msg = g_string_new (soup_message_get_reason_phrase (message));
+               if (response_body && g_bytes_get_size (response_body)) {
                        g_string_append (error_msg, " (");
-                       g_string_append_len (error_msg, message->response_body->data, 
message->response_body->length);
+                       g_string_append_len (error_msg, (const gchar *) g_bytes_get_data (response_body, 
NULL), g_bytes_get_size (response_body));
                        g_string_append_c (error_msg, ')');
                }
 
-               g_set_error_literal (error, SOUP_HTTP_ERROR, message->status_code, error_msg->str);
+               g_set_error_literal (error, E_SOUP_SESSION_ERROR, soup_message_get_status (message), 
error_msg->str);
 
                g_string_free (error_msg, TRUE);
        }
 
+       if (response_body)
+               g_object_unref (response_body);
+
        return success;
 }
 
@@ -1034,12 +1036,14 @@ eos_encode_to_secret (gchar **out_secret,
 
 static gboolean
 eos_decode_from_secret (const gchar *secret,
+                       gssize length,
                        const gchar *key1_name,
                        gchar **out_value1,
                        ...) G_GNUC_NULL_TERMINATED;
 
 static gboolean
 eos_decode_from_secret (const gchar *secret,
+                       gssize length,
                        const gchar *key1_name,
                        gchar **out_value1,
                        ...)
@@ -1058,7 +1062,7 @@ eos_decode_from_secret (const gchar *secret,
                return FALSE;
 
        parser = json_parser_new ();
-       if (!json_parser_load_from_data (parser, secret, -1, &error)) {
+       if (!json_parser_load_from_data (parser, secret, length, &error)) {
                g_object_unref (parser);
 
                g_debug ("%s: Failed to parse secret '%s': %s", G_STRFUNC, secret, error ? error->message : 
"Unknown error");
@@ -1210,7 +1214,7 @@ eos_lookup_token_sync (EOAuth2Service *service,
                return FALSE;
        }
 
-       success = eos_decode_from_secret (secret,
+       success = eos_decode_from_secret (secret, -1,
                E_OAUTH2_SECRET_REFRESH_TOKEN, out_refresh_token,
                E_OAUTH2_SECRET_ACCESS_TOKEN, out_access_token,
                E_OAUTH2_SECRET_EXPIRES_AFTER, &expires_after,
@@ -1269,7 +1273,7 @@ e_oauth2_service_receive_and_store_token_sync (EOAuth2Service *service,
        SoupSession *session;
        SoupMessage *message;
        GHashTable *post_form;
-       gchar *response_json = NULL;
+       GBytes *response_json = NULL;
        gboolean success;
 
        g_return_val_if_fail (E_IS_OAUTH2_SERVICE (service), FALSE);
@@ -1300,7 +1304,7 @@ e_oauth2_service_receive_and_store_token_sync (EOAuth2Service *service,
        if (success) {
                gchar *access_token = NULL, *refresh_token = NULL, *expires_in = NULL, *token_type = NULL;
 
-               if (eos_decode_from_secret (response_json,
+               if (eos_decode_from_secret (g_bytes_get_data (response_json, NULL), g_bytes_get_size 
(response_json),
                        "access_token", &access_token,
                        "refresh_token", &refresh_token,
                        "expires_in", &expires_in,
@@ -1323,7 +1327,8 @@ e_oauth2_service_receive_and_store_token_sync (EOAuth2Service *service,
 
        g_object_unref (message);
        g_object_unref (session);
-       e_util_safe_free_string (response_json);
+       if (response_json)
+               g_bytes_unref (response_json);
 
        return success;
 }
@@ -1358,7 +1363,7 @@ e_oauth2_service_refresh_and_store_token_sync (EOAuth2Service *service,
        SoupSession *session;
        SoupMessage *message;
        GHashTable *post_form;
-       gchar *response_json = NULL;
+       GBytes *response_json = NULL;
        gboolean success;
        GError *local_error = NULL;
 
@@ -1387,10 +1392,11 @@ e_oauth2_service_refresh_and_store_token_sync (EOAuth2Service *service,
        e_oauth2_service_prepare_refresh_token_message (service, source, message);
 
        success = eos_send_message (session, message, &response_json, cancellable, &local_error);
+
        if (success) {
                gchar *access_token = NULL, *expires_in = NULL, *new_refresh_token = NULL;
 
-               if (eos_decode_from_secret (response_json,
+               if (eos_decode_from_secret (g_bytes_get_data (response_json, NULL), g_bytes_get_size 
(response_json),
                        "access_token", &access_token,
                        "expires_in", &expires_in,
                        "refresh_token", &new_refresh_token,
@@ -1408,7 +1414,7 @@ e_oauth2_service_refresh_and_store_token_sync (EOAuth2Service *service,
                e_util_safe_free_string (access_token);
                g_free (new_refresh_token);
                g_free (expires_in);
-       } else if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_BAD_REQUEST)) {
+       } else if (g_error_matches (local_error, E_SOUP_SESSION_ERROR, SOUP_STATUS_BAD_REQUEST)) {
                g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_CONNECTION_REFUSED,
                        _("Failed to refresh access token. Sign to the server again, please."));
                g_clear_error (&local_error);
@@ -1419,7 +1425,8 @@ e_oauth2_service_refresh_and_store_token_sync (EOAuth2Service *service,
 
        g_object_unref (message);
        g_object_unref (session);
-       e_util_safe_free_string (response_json);
+       if (response_json)
+               g_bytes_unref (response_json);
 
        return success;
 }
diff --git a/src/libedataserver/e-soup-auth-bearer.c b/src/libedataserver/e-soup-auth-bearer.c
index 46b2bcf5f..d332d5fa5 100644
--- a/src/libedataserver/e-soup-auth-bearer.c
+++ b/src/libedataserver/e-soup-auth-bearer.c
@@ -81,7 +81,7 @@ e_soup_auth_bearer_update (SoupAuth *auth,
                            SoupMessage *message,
                            GHashTable *auth_header)
 {
-       if (message && message->status_code == SOUP_STATUS_UNAUTHORIZED) {
+       if (message && soup_message_get_status (message) == SOUP_STATUS_UNAUTHORIZED) {
                ESoupAuthBearer *bearer;
 
                g_return_val_if_fail (E_IS_SOUP_AUTH_BEARER (auth), FALSE);
@@ -103,7 +103,7 @@ e_soup_auth_bearer_update (SoupAuth *auth,
 
 static GSList *
 e_soup_auth_bearer_get_protection_space (SoupAuth *auth,
-                                         SoupURI *source_uri)
+                                         GUri *source_uri)
 {
        /* XXX Not sure what to do here.  Need to return something. */
 
@@ -238,9 +238,7 @@ e_soup_auth_bearer_set_access_token (ESoupAuthBearer *bearer,
        now_authenticated = soup_auth_is_authenticated (SOUP_AUTH (bearer));
 
        if (was_authenticated != now_authenticated)
-               g_object_notify (
-                       G_OBJECT (bearer),
-                       SOUP_AUTH_IS_AUTHENTICATED);
+               g_object_notify (G_OBJECT (bearer), "is-authenticated");
 }
 
 /**
diff --git a/src/libedataserver/e-soup-session.c b/src/libedataserver/e-soup-session.c
index 381b9f88d..ef2843203 100644
--- a/src/libedataserver/e-soup-session.c
+++ b/src/libedataserver/e-soup-session.c
@@ -31,17 +31,19 @@
 
 #include "e-oauth2-services.h"
 #include "e-soup-auth-bearer.h"
-#include "e-soup-logger.h"
 #include "e-soup-ssl-trust.h"
 #include "e-source-authentication.h"
 #include "e-source-webdav.h"
 
 #include "e-soup-session.h"
 
+G_DEFINE_QUARK (e-soup-session-error-quark, e_soup_session_error)
+
 #define BUFFER_SIZE 16384
 
 struct _ESoupSessionPrivate {
        GMutex property_lock;
+       GRecMutex session_lock; /* libsoup3 has no thread safety */
        ESource *source;
        ENamedParameters *credentials;
 
@@ -67,44 +69,53 @@ G_DEFINE_TYPE_WITH_PRIVATE (ESoupSession, e_soup_session, SOUP_TYPE_SESSION)
 
 static void
 e_soup_session_ensure_auth_usage (ESoupSession *session,
-                                 SoupURI *in_soup_uri,
+                                 GUri *in_g_uri,
                                  SoupMessage *message,
                                  SoupAuth *soup_auth)
 {
        SoupAuthManager *auth_manager;
        SoupSessionFeature *feature;
-       SoupURI *soup_uri;
+       GUri *g_uri;
        GType auth_type;
 
        g_return_if_fail (E_IS_SOUP_SESSION (session));
        g_return_if_fail (SOUP_IS_AUTH (soup_auth));
 
+       g_rec_mutex_lock (&session->priv->session_lock);
+
        feature = soup_session_get_feature (SOUP_SESSION (session), SOUP_TYPE_AUTH_MANAGER);
 
        auth_type = G_OBJECT_TYPE (soup_auth);
 
-       if (!soup_session_feature_has_feature (feature, auth_type)) {
+       if (!soup_session_has_feature (SOUP_SESSION (session), auth_type)) {
                /* Add the SoupAuth type to support it. */
-               soup_session_feature_add_feature (feature, auth_type);
+               soup_session_add_feature_by_type (SOUP_SESSION (session), auth_type);
        }
 
-       if (in_soup_uri) {
-               soup_uri = in_soup_uri;
+       if (in_g_uri) {
+               g_uri = in_g_uri;
        } else {
-               soup_uri = message ? soup_message_get_uri (message) : NULL;
-               if (soup_uri && soup_uri->host && *soup_uri->host) {
-                       soup_uri = soup_uri_copy_host (soup_uri);
+               g_uri = message ? soup_message_get_uri (message) : NULL;
+               if (g_uri && g_uri_get_host (g_uri) && *g_uri_get_host (g_uri)) {
+                       g_uri = g_uri_build (SOUP_HTTP_URI_FLAGS,
+                                            g_uri_get_scheme (g_uri),
+                                            NULL,
+                                            g_uri_get_host (g_uri),
+                                            g_uri_get_port (g_uri),
+                                            "",
+                                            NULL,
+                                            NULL);
                } else {
-                       soup_uri = NULL;
+                       g_uri = NULL;
                }
 
-               if (!soup_uri) {
+               if (!g_uri) {
                        ESourceWebdav *extension;
                        ESource *source;
 
                        source = e_soup_session_get_source (session);
                        extension = e_source_get_extension (source, E_SOURCE_EXTENSION_WEBDAV_BACKEND);
-                       soup_uri = e_source_webdav_dup_soup_uri (extension);
+                       g_uri = e_source_webdav_dup_uri (extension);
                }
        }
 
@@ -113,10 +124,12 @@ e_soup_session_ensure_auth_usage (ESoupSession *session,
        /* This will make sure the 'soup_auth' is used regardless of the current 'auth_manager' state.
           See https://gitlab.gnome.org/GNOME/libsoup/-/issues/196 for more information. */
        soup_auth_manager_clear_cached_credentials (auth_manager);
-       soup_auth_manager_use_auth (auth_manager, soup_uri, soup_auth);
+       soup_auth_manager_use_auth (auth_manager, g_uri, soup_auth);
 
-       if (!in_soup_uri)
-               soup_uri_free (soup_uri);
+       g_rec_mutex_unlock (&session->priv->session_lock);
+
+       if (!in_g_uri)
+               g_uri_unref (g_uri);
 }
 
 static gboolean
@@ -157,7 +170,7 @@ e_soup_session_setup_bearer_auth (ESoupSession *session,
 
 static gboolean
 e_soup_session_maybe_prepare_bearer_auth (ESoupSession *session,
-                                         SoupURI *soup_uri,
+                                         GUri *g_uri,
                                          SoupMessage *message,
                                          GCancellable *cancellable,
                                          GError **error)
@@ -165,7 +178,7 @@ e_soup_session_maybe_prepare_bearer_auth (ESoupSession *session,
        gboolean success;
 
        g_return_val_if_fail (E_IS_SOUP_SESSION (session), FALSE);
-       g_return_val_if_fail (soup_uri != NULL, FALSE);
+       g_return_val_if_fail (g_uri != NULL, FALSE);
 
        g_mutex_lock (&session->priv->property_lock);
        if (session->priv->using_bearer_auth) {
@@ -177,13 +190,13 @@ e_soup_session_maybe_prepare_bearer_auth (ESoupSession *session,
 
                g_clear_object (&using_bearer_auth);
        } else {
-               SoupAuth *soup_auth;
+               ESoupAuthBearer *soup_auth;
 
                g_mutex_unlock (&session->priv->property_lock);
 
                soup_auth = g_object_new (
                        E_TYPE_SOUP_AUTH_BEARER,
-                       SOUP_AUTH_HOST, soup_uri->host, NULL);
+                       "authority", g_uri_get_host (g_uri), NULL);
 
                success = e_soup_session_setup_bearer_auth (session, message, FALSE, E_SOUP_AUTH_BEARER 
(soup_auth), cancellable, error);
                if (success) {
@@ -201,7 +214,7 @@ e_soup_session_maybe_prepare_bearer_auth (ESoupSession *session,
 
 static gboolean
 e_soup_session_maybe_prepare_basic_auth (ESoupSession *session,
-                                        SoupURI *soup_uri,
+                                        GUri *g_uri,
                                         SoupMessage *message,
                                         const gchar *in_username,
                                         const ENamedParameters *credentials,
@@ -212,15 +225,11 @@ e_soup_session_maybe_prepare_basic_auth (ESoupSession *session,
        const gchar *username;
 
        g_return_val_if_fail (E_IS_SOUP_SESSION (session), FALSE);
-       g_return_val_if_fail (soup_uri != NULL, FALSE);
+       g_return_val_if_fail (g_uri != NULL, FALSE);
 
        if (!credentials || !e_named_parameters_exists (credentials, E_SOURCE_CREDENTIAL_PASSWORD)) {
                /* This error message won't get into the UI */
-               g_set_error_literal (error, SOUP_HTTP_ERROR, SOUP_STATUS_UNAUTHORIZED, soup_status_get_phrase 
(SOUP_STATUS_UNAUTHORIZED));
-
-               if (message)
-                       soup_message_set_status (message, SOUP_STATUS_UNAUTHORIZED);
-
+               g_set_error_literal (error, E_SOUP_SESSION_ERROR, SOUP_STATUS_UNAUTHORIZED, 
soup_status_get_phrase (SOUP_STATUS_UNAUTHORIZED));
                return FALSE;
        }
 
@@ -236,7 +245,7 @@ e_soup_session_maybe_prepare_basic_auth (ESoupSession *session,
        session->priv->auth_prefilled = TRUE;
        g_mutex_unlock (&session->priv->property_lock);
 
-       e_soup_session_ensure_auth_usage (session, soup_uri, message, soup_auth);
+       e_soup_session_ensure_auth_usage (session, g_uri, message, soup_auth);
 
        g_clear_object (&soup_auth);
 
@@ -245,14 +254,13 @@ e_soup_session_maybe_prepare_basic_auth (ESoupSession *session,
 
 static gboolean
 e_soup_session_maybe_prepare_auth (ESoupSession *session,
-                                  SoupRequestHTTP *request,
+                                  SoupMessage *message,
                                   GCancellable *cancellable,
                                   GError **error)
 {
        ESource *source;
        ENamedParameters *credentials;
-       SoupMessage *message;
-       SoupURI *soup_uri;
+       GUri *g_uri;
        gchar *auth_method = NULL, *user = NULL;
        gboolean success = TRUE;
 
@@ -271,19 +279,25 @@ e_soup_session_maybe_prepare_auth (ESoupSession *session,
        }
 
        credentials = e_soup_session_dup_credentials (session);
-       message = soup_request_http_get_message (request);
-       soup_uri = message ? soup_message_get_uri (message) : NULL;
-       if (soup_uri && soup_uri->host && *soup_uri->host) {
-               soup_uri = soup_uri_copy_host (soup_uri);
+       g_uri = message ? soup_message_get_uri (message) : NULL;
+       if (g_uri && g_uri_get_host (g_uri) && *g_uri_get_host (g_uri)) {
+               g_uri = g_uri_build (SOUP_HTTP_URI_FLAGS,
+                                    g_uri_get_scheme (g_uri),
+                                    NULL,
+                                    g_uri_get_host (g_uri),
+                                    g_uri_get_port (g_uri),
+                                    "",
+                                    NULL,
+                                    NULL);
        } else {
-               soup_uri = NULL;
+               g_uri = NULL;
        }
 
-       if (!soup_uri) {
+       if (!g_uri) {
                ESourceWebdav *extension;
 
                extension = e_source_get_extension (source, E_SOURCE_EXTENSION_WEBDAV_BACKEND);
-               soup_uri = e_source_webdav_dup_soup_uri (extension);
+               g_uri = e_source_webdav_dup_uri (extension);
        }
 
        g_mutex_lock (&session->priv->property_lock);
@@ -291,45 +305,56 @@ e_soup_session_maybe_prepare_auth (ESoupSession *session,
        g_mutex_unlock (&session->priv->property_lock);
 
        /* Provide credentials beforehand only on secure connections */
-       if (soup_uri_get_scheme (soup_uri) == SOUP_URI_SCHEME_HTTPS) {
+       if (g_strcmp0 (g_uri_get_scheme (g_uri), "https") == 0) {
                if (g_strcmp0 (auth_method, "OAuth2") == 0 ||
                    e_oauth2_services_is_oauth2_alias_static (auth_method)) {
-                       success = e_soup_session_maybe_prepare_bearer_auth (session, soup_uri, message, 
cancellable, error);
+                       success = e_soup_session_maybe_prepare_bearer_auth (session, g_uri, message, 
cancellable, error);
                } else if (g_strcmp0 (auth_method, "GSSAPI") == 0 && soup_auth_negotiate_supported ()) {
                        SoupSession *soup_session = SOUP_SESSION (session);
 
-                       soup_session_add_feature_by_type (soup_session, SOUP_TYPE_AUTH_NEGOTIATE);
+                       g_rec_mutex_lock (&session->priv->session_lock);
+
+                       if (!soup_session_get_feature (soup_session, SOUP_TYPE_AUTH_NEGOTIATE))
+                               soup_session_add_feature_by_type (soup_session, SOUP_TYPE_AUTH_NEGOTIATE);
                        soup_session_remove_feature_by_type (soup_session, SOUP_TYPE_AUTH_BASIC);
+
+                       g_rec_mutex_unlock (&session->priv->session_lock);
+               } else if (g_strcmp0 (auth_method, "NTLM") == 0) {
+                       SoupSession *soup_session = SOUP_SESSION (session);
+
+                       g_rec_mutex_lock (&session->priv->session_lock);
+
+                       if (!soup_session_get_feature (soup_session, SOUP_TYPE_AUTH_NTLM))
+                               soup_session_add_feature_by_type (soup_session, SOUP_TYPE_AUTH_NTLM);
+                       /* Keep the basic auth, as a fallback */
+
+                       g_rec_mutex_unlock (&session->priv->session_lock);
                } else if (user && *user) {
                        /* Default to Basic authentication when user is filled */
-                       success = e_soup_session_maybe_prepare_basic_auth (session, soup_uri, message, user, 
credentials, cancellable, error);
+                       success = e_soup_session_maybe_prepare_basic_auth (session, g_uri, message, user, 
credentials, cancellable, error);
                }
        }
 
        e_named_parameters_free (credentials);
-       g_clear_object (&message);
-       soup_uri_free (soup_uri);
+       g_uri_unref (g_uri);
        g_free (auth_method);
        g_free (user);
 
        return success;
 }
 
-static void
-e_soup_session_authenticate_cb (SoupSession *soup_session,
-                               SoupMessage *message,
+static gboolean
+e_soup_session_authenticate_cb (SoupMessage *message,
                                SoupAuth *auth,
                                gboolean retrying,
                                gpointer user_data)
 {
-       ESoupSession *session;
+       ESoupSession *session = user_data;
        const gchar *username;
        ENamedParameters *credentials;
        gchar *auth_user = NULL;
 
-       g_return_if_fail (E_IS_SOUP_SESSION (soup_session));
-
-       session = E_SOUP_SESSION (soup_session);
+       g_return_val_if_fail (E_IS_SOUP_SESSION (session), FALSE);
 
        if (E_IS_SOUP_AUTH_BEARER (auth)) {
                g_object_ref (auth);
@@ -341,7 +366,7 @@ e_soup_session_authenticate_cb (SoupSession *soup_session,
        g_mutex_lock (&session->priv->property_lock);
        if (retrying && !session->priv->auth_prefilled) {
                g_mutex_unlock (&session->priv->property_lock);
-               return;
+               return FALSE;
        }
        session->priv->auth_prefilled = FALSE;
        g_mutex_unlock (&session->priv->property_lock);
@@ -365,7 +390,7 @@ e_soup_session_authenticate_cb (SoupSession *soup_session,
                        g_mutex_unlock (&session->priv->property_lock);
                }
 
-               return;
+               return FALSE;
        }
 
        credentials = e_soup_session_dup_credentials (session);
@@ -381,14 +406,14 @@ e_soup_session_authenticate_cb (SoupSession *soup_session,
                username = auth_user;
        }
 
-       if (!username || !*username || !credentials ||
-           !e_named_parameters_exists (credentials, E_SOURCE_CREDENTIAL_PASSWORD))
-               soup_message_set_status (message, SOUP_STATUS_UNAUTHORIZED);
-       else
+       if (username && *username && credentials &&
+           e_named_parameters_exists (credentials, E_SOURCE_CREDENTIAL_PASSWORD))
                soup_auth_authenticate (auth, username, e_named_parameters_get (credentials, 
E_SOURCE_CREDENTIAL_PASSWORD));
 
        e_named_parameters_free (credentials);
        g_free (auth_user);
+
+       return FALSE;
 }
 
 static void
@@ -462,6 +487,7 @@ e_soup_session_finalize (GObject *object)
        g_clear_pointer (&session->priv->ssl_certificate_pem, g_free);
 
        g_mutex_clear (&session->priv->property_lock);
+       g_rec_mutex_clear (&session->priv->session_lock);
 
        /* Chain up to parent's method. */
        G_OBJECT_CLASS (e_soup_session_parent_class)->finalize (object);
@@ -525,19 +551,16 @@ e_soup_session_init (ESoupSession *session)
        session->priv->auth_prefilled = FALSE;
 
        g_mutex_init (&session->priv->property_lock);
+       g_rec_mutex_init (&session->priv->session_lock);
 
        g_object_set (
                G_OBJECT (session),
-               SOUP_SESSION_TIMEOUT, 90,
-               SOUP_SESSION_SSL_STRICT, TRUE,
-               SOUP_SESSION_SSL_USE_SYSTEM_CA_FILE, TRUE,
-               SOUP_SESSION_ACCEPT_LANGUAGE_AUTO, TRUE,
+               "timeout", 90,
+               "accept-language-auto", TRUE,
                NULL);
 
-       soup_session_add_feature_by_type (SOUP_SESSION (session), SOUP_TYPE_CONTENT_DECODER);
-
-       g_signal_connect (session, "authenticate",
-               G_CALLBACK (e_soup_session_authenticate_cb), NULL);
+       if (!soup_session_get_feature (SOUP_SESSION (session), SOUP_TYPE_CONTENT_DECODER))
+               soup_session_add_feature_by_type (SOUP_SESSION (session), SOUP_TYPE_CONTENT_DECODER);
 }
 
 /**
@@ -589,11 +612,15 @@ e_soup_session_setup_logging (ESoupSession *session,
 
        g_return_if_fail (E_IS_SOUP_SESSION (session));
 
+       g_rec_mutex_lock (&session->priv->session_lock);
+
        soup_session_remove_feature_by_type (SOUP_SESSION (session), SOUP_TYPE_LOGGER);
        session->priv->log_level = SOUP_LOGGER_LOG_NONE;
 
-       if (!logging_level)
+       if (!logging_level) {
+               g_rec_mutex_unlock (&session->priv->session_lock);
                return;
+       }
 
        if (g_ascii_strcasecmp (logging_level, "all") == 0 ||
            g_ascii_strcasecmp (logging_level, "body") == 0 ||
@@ -603,12 +630,16 @@ e_soup_session_setup_logging (ESoupSession *session,
                session->priv->log_level = SOUP_LOGGER_LOG_HEADERS;
        else if (g_ascii_strcasecmp (logging_level, "min") == 0)
                session->priv->log_level = SOUP_LOGGER_LOG_MINIMAL;
-       else
+       else {
+               g_rec_mutex_unlock (&session->priv->session_lock);
                return;
+       }
 
-       logger = soup_logger_new (session->priv->log_level, -1);
+       logger = soup_logger_new (session->priv->log_level);
        soup_session_add_feature (SOUP_SESSION (session), SOUP_SESSION_FEATURE (logger));
        g_object_unref (logger);
+
+       g_rec_mutex_unlock (&session->priv->session_lock);
 }
 
 /**
@@ -657,6 +688,8 @@ void
 e_soup_session_set_credentials (ESoupSession *session,
                                const ENamedParameters *credentials)
 {
+       SoupSessionFeature *feature;
+
        g_return_if_fail (E_IS_SOUP_SESSION (session));
 
        g_mutex_lock (&session->priv->property_lock);
@@ -675,6 +708,12 @@ e_soup_session_set_credentials (ESoupSession *session,
        g_mutex_unlock (&session->priv->property_lock);
 
        g_object_notify (G_OBJECT (session), "credentials");
+
+       /* Update also internal SoupSession state */
+       g_rec_mutex_lock (&session->priv->session_lock);
+       feature = soup_session_get_feature (SOUP_SESSION (session), SOUP_TYPE_AUTH_MANAGER);
+       soup_auth_manager_clear_cached_credentials (SOUP_AUTH_MANAGER (feature));
+       g_rec_mutex_unlock (&session->priv->session_lock);
 }
 
 /**
@@ -733,7 +772,7 @@ e_soup_session_get_authentication_requires_credentials (ESoupSession *session)
  *   with certificate error flags when the operation failed with a TLS/SSL error
  *
  * Populates @out_certificate_pem and @out_certificate_errors with the last values
- * returned on #SOUP_STATUS_SSL_FAILED error.
+ * returned on #G_TLS_ERROR_BAD_CERTIFICATE error.
  *
  * Returns: Whether the information was available and set to the out parameters.
  *
@@ -763,147 +802,183 @@ e_soup_session_get_ssl_error_details (ESoupSession *session,
 }
 
 static void
-e_soup_session_preset_request (SoupRequestHTTP *request)
+e_soup_session_preset_message (SoupMessage *message)
 {
-       SoupMessage *message;
+       if (message) {
+               GUri *normalized_uri;
 
-       if (!request)
-               return;
+               normalized_uri = e_soup_session_util_normalize_uri_path (soup_message_get_uri (message));
 
-       message = soup_request_http_get_message (request);
-       if (message) {
-               e_soup_session_util_normalize_uri_path (soup_message_get_uri (message));
+               if (normalized_uri) {
+                       soup_message_set_uri (message, normalized_uri);
+                       g_uri_unref (normalized_uri);
+               }
 
-               soup_message_headers_append (message->request_headers, "User-Agent", "Evolution/" VERSION);
-               soup_message_headers_append (message->request_headers, "Connection", "close");
+               soup_message_headers_append (soup_message_get_request_headers (message), "User-Agent", 
"Evolution/" VERSION);
+               soup_message_headers_append (soup_message_get_request_headers (message), "Connection", 
"close");
 
                /* Disable caching for proxies (RFC 4918, section 10.4.5) */
-               soup_message_headers_append (message->request_headers, "Cache-Control", "no-cache");
-               soup_message_headers_append (message->request_headers, "Pragma", "no-cache");
-
-               g_clear_object (&message);
+               soup_message_headers_append (soup_message_get_request_headers (message), "Cache-Control", 
"no-cache");
+               soup_message_headers_append (soup_message_get_request_headers (message), "Pragma", 
"no-cache");
        }
 }
 
 /**
- * e_soup_session_new_request:
+ * e_soup_session_new_message:
  * @session: an #ESoupSession
  * @method: an HTTP method
  * @uri_string: a URI string to use for the request
  * @error: return location for a #GError, or %NULL
  *
- * Creates a new #SoupRequestHTTP, similar to soup_session_request_http(),
+ * Creates a new #SoupMessage, similar to soup_message_new(),
  * but also presets request headers with "User-Agent" to be "Evolution/version"
  * and with "Connection" to be "close".
  *
- * See also e_soup_session_new_request_uri().
+ * See also e_soup_session_new_message_from_uri().
  *
- * Returns: (transfer full): a new #SoupRequestHTTP, or %NULL on error
+ * Returns: (transfer full): a new #SoupMessage, or %NULL on error
  *
  * Since: 3.26
  **/
-SoupRequestHTTP *
-e_soup_session_new_request (ESoupSession *session,
+SoupMessage *
+e_soup_session_new_message (ESoupSession *session,
                            const gchar *method,
                            const gchar *uri_string,
                            GError **error)
 {
-       SoupRequestHTTP *request;
+       SoupMessage *message;
+       GUri *uri;
 
        g_return_val_if_fail (E_IS_SOUP_SESSION (session), NULL);
 
-       request = soup_session_request_http (SOUP_SESSION (session), method, uri_string, error);
-       if (!request)
+       uri = g_uri_parse (uri_string, SOUP_HTTP_URI_FLAGS, error);
+       if (!uri)
                return NULL;
 
-       e_soup_session_preset_request (request);
+       message = e_soup_session_new_message_from_uri (session, method, uri, error);
+
+       g_uri_unref (uri);
 
-       return request;
+       return message;
 }
 
 /**
- * e_soup_session_new_request_uri:
+ * e_soup_session_new_message_from_uri:
  * @session: an #ESoupSession
  * @method: an HTTP method
- * @uri: a #SoupURI to use for the request
+ * @uri: a #GUri to use for the request
  * @error: return location for a #GError, or %NULL
  *
- * Creates a new #SoupRequestHTTP, similar to soup_session_request_http_uri(),
+ * Creates a new #SoupMessage, similar to soup_message_new_from_uri(),
  * but also presets request headers with "User-Agent" to be "Evolution/version"
  * and with "Connection" to be "close".
  *
- * See also e_soup_session_new_request().
+ * See also e_soup_session_new_message().
  *
- * Returns: (transfer full): a new #SoupRequestHTTP, or %NULL on error
+ * Returns: (transfer full): a new #SoupMessage, or %NULL on error
  *
- * Since: 3.26
+ * Since: 3.48
  **/
-SoupRequestHTTP *
-e_soup_session_new_request_uri (ESoupSession *session,
-                               const gchar *method,
-                               SoupURI *uri,
-                               GError **error)
+SoupMessage *
+e_soup_session_new_message_from_uri (ESoupSession *session,
+                                    const gchar *method,
+                                    GUri *uri,
+                                    GError **error)
 {
-       SoupRequestHTTP *request;
+       SoupMessage *message;
 
        g_return_val_if_fail (E_IS_SOUP_SESSION (session), NULL);
 
-       request = soup_session_request_http_uri (SOUP_SESSION (session), method, uri, error);
-       if (!request)
+       if (g_uri_get_user (uri) && !g_uri_get_password (uri)) {
+               /* Do not allow setting user without password in the URI, because libsoup3 tries
+                  to authenticate even without password, which can break the code. */
+               GUri *uri_copy;
+
+               uri_copy = soup_uri_copy (uri,
+                       SOUP_URI_USER, NULL,
+                       SOUP_URI_PASSWORD, NULL,
+                       SOUP_URI_NONE);
+
+               message = soup_message_new_from_uri (method, uri_copy);
+
+               g_uri_unref (uri_copy);
+       } else {
+               message = soup_message_new_from_uri (method, uri);
+       }
+
+       if (!message)
                return NULL;
 
-       e_soup_session_preset_request (request);
+       e_soup_session_preset_message (message);
 
-       return request;
+       return message;
 }
 
-static void
+static gboolean
 e_soup_session_extract_ssl_data (ESoupSession *session,
-                                SoupMessage *message)
+                                SoupMessage *message,
+                                gchar **out_certificate_pem,
+                                GTlsCertificateFlags *out_certificate_errors)
 {
        GTlsCertificate *certificate = NULL;
+       gboolean res = FALSE;
 
-       g_return_if_fail (E_IS_SOUP_SESSION (session));
-       g_return_if_fail (SOUP_IS_MESSAGE (message));
-
-       g_mutex_lock (&session->priv->property_lock);
+       g_return_val_if_fail (E_IS_SOUP_SESSION (session), FALSE);
+       g_return_val_if_fail (SOUP_IS_MESSAGE (message), FALSE);
 
-       g_clear_pointer (&session->priv->ssl_certificate_pem, g_free);
-       session->priv->ssl_info_set = FALSE;
+       if (!out_certificate_pem)
+               return FALSE;
 
        g_object_get (G_OBJECT (message),
-               "tls-certificate", &certificate,
-               "tls-errors", &session->priv->ssl_certificate_errors,
+               "tls-peer-certificate", &certificate,
+               out_certificate_errors ? "tls-peer-certificate-errors" : NULL, out_certificate_errors,
                NULL);
 
        if (certificate) {
-               g_object_get (certificate, "certificate-pem", &session->priv->ssl_certificate_pem, NULL);
-               session->priv->ssl_info_set = TRUE;
+               g_object_get (certificate, "certificate-pem", out_certificate_pem, NULL);
+               res = TRUE;
 
                g_object_unref (certificate);
        }
 
+       return res;
+}
+
+static void
+e_soup_session_extract_ssl_data_internal (ESoupSession *session,
+                                         SoupMessage *message)
+{
+       g_return_if_fail (E_IS_SOUP_SESSION (session));
+       g_return_if_fail (SOUP_IS_MESSAGE (message));
+
+       g_mutex_lock (&session->priv->property_lock);
+
+       g_clear_pointer (&session->priv->ssl_certificate_pem, g_free);
+
+       session->priv->ssl_info_set = e_soup_session_extract_ssl_data (session, message,
+               &session->priv->ssl_certificate_pem, &session->priv->ssl_certificate_errors);
+
        g_mutex_unlock (&session->priv->property_lock);
 }
 
 static gboolean
-e_soup_session_extract_google_daily_limit_error (SoupMessage *message,
+e_soup_session_extract_google_daily_limit_error (gconstpointer read_bytes,
+                                                gsize bytes_length,
                                                 GError **error)
 {
        gchar *body;
        gboolean contains_daily_limit = FALSE;
 
-       if (!message || !message->response_body ||
-           !message->response_body->data || !message->response_body->length)
+       if (!read_bytes || !bytes_length)
                return FALSE;
 
-       body = g_strndup (message->response_body->data, message->response_body->length);
+       body = g_strndup (read_bytes, bytes_length);
 
        /* Do not localize this string, it is returned by the server. */
        if (body && (e_util_strstrcase (body, "Daily Limit") ||
            e_util_strstrcase (body, "https://console.developers.google.com/";))) {
                /* Special-case this condition and provide this error up to the UI. */
-               g_set_error_literal (error, SOUP_HTTP_ERROR, SOUP_STATUS_FORBIDDEN, body);
+               g_set_error_literal (error, E_SOUP_SESSION_ERROR, SOUP_STATUS_FORBIDDEN, body);
                contains_daily_limit = TRUE;
        }
 
@@ -915,15 +990,14 @@ e_soup_session_extract_google_daily_limit_error (SoupMessage *message,
 /**
  * e_soup_session_check_result:
  * @session: an #ESoupSession
- * @request: a #SoupRequestHTTP
+ * @message: a #SoupMessage
  * @read_bytes: (nullable): optional bytes which had been read from the stream, or %NULL
  * @bytes_length: how many bytes had been read; ignored when @read_bytes is %NULL
  * @error: return location for a #GError, or %NULL
  *
- * Checks result of the @request and sets the @error if it failed.
+ * Checks result of the @message and sets the @error if it failed.
  * When it failed and the @read_bytes is provided, then these are
- * set to @request's message response_body, thus it can be used
- * later.
+ * set to @message's response body, thus it can be used later.
  *
  * Returns: Whether succeeded, aka %TRUE, when no error recognized
  *    and %FALSE otherwise.
@@ -932,102 +1006,390 @@ e_soup_session_extract_google_daily_limit_error (SoupMessage *message,
  **/
 gboolean
 e_soup_session_check_result (ESoupSession *session,
-                            SoupRequestHTTP *request,
+                            SoupMessage *message,
                             gconstpointer read_bytes,
                             gsize bytes_length,
                             GError **error)
 {
-       SoupMessage *message;
        gboolean success;
 
        g_return_val_if_fail (E_IS_SOUP_SESSION (session), FALSE);
-       g_return_val_if_fail (SOUP_IS_REQUEST_HTTP (request), FALSE);
-
-       message = soup_request_http_get_message (request);
        g_return_val_if_fail (SOUP_IS_MESSAGE (message), FALSE);
 
-       success = SOUP_STATUS_IS_SUCCESSFUL (message->status_code);
+       success = SOUP_STATUS_IS_SUCCESSFUL (soup_message_get_status (message));
        if (!success) {
-               if (read_bytes && bytes_length > 0) {
-                       SoupBuffer *buffer;
+               if (soup_message_get_status (message) == SOUP_STATUS_FORBIDDEN &&
+                   e_soup_session_extract_google_daily_limit_error (read_bytes, bytes_length, error)) {
+                       /* Nothing to do */
+               } else {
+                       g_set_error (error, E_SOUP_SESSION_ERROR, soup_message_get_status (message),
+                               _("Failed with HTTP error %d: %s"), soup_message_get_status (message),
+                               e_soup_session_util_status_to_string (soup_message_get_status (message),
+                               soup_message_get_reason_phrase (message)));
+               }
 
-                       soup_message_body_append (message->response_body, SOUP_MEMORY_COPY, read_bytes, 
bytes_length);
+               e_soup_session_extract_ssl_data_internal (session, message);
+       }
 
-                       /* This writes data to message->response_body->data */
-                       buffer = soup_message_body_flatten (message->response_body);
-                       if (buffer)
-                               soup_buffer_free (buffer);
+       return success;
+}
+
+static void
+e_soup_session_restore_method_on_restarted_cb (SoupMessage *message,
+                                              gpointer user_data)
+{
+       const gchar *orig_method = user_data;
+
+       g_return_if_fail (orig_method != NULL);
+
+       /* Redirect can change the method, this makes sure it'll be preserved. */
+       if (g_strcmp0 (orig_method, soup_message_get_method (message)) != 0)
+               soup_message_set_method (message, orig_method);
+}
+
+static gboolean
+e_soup_session_prepare_message_send_phase1_sync (ESoupSession *session,
+                                                SoupMessage *message,
+                                                gulong *out_authenticate_id,
+                                                gulong *out_restarted_id,
+                                                GCancellable *cancellable,
+                                                GError **error)
+{
+       g_return_val_if_fail (E_IS_SOUP_SESSION (session), FALSE);
+       g_return_val_if_fail (SOUP_IS_MESSAGE (message), FALSE);
+
+       if (!e_soup_session_maybe_prepare_auth (session, message, cancellable, error))
+               return FALSE;
+
+       *out_authenticate_id = g_signal_connect (message, "authenticate",
+               G_CALLBACK (e_soup_session_authenticate_cb), session);
+
+       *out_restarted_id = g_signal_connect_data (message, "restarted",
+               G_CALLBACK (e_soup_session_restore_method_on_restarted_cb), g_strdup (soup_message_get_method 
(message)), (GClosureNotify) g_free, 0);
+
+       /* Always connect the SSL trust, even when the WebDAV extension is not present on the source,
+          otherwise any SSL trust is not properly handled. */
+       if (session->priv->source)
+               e_soup_ssl_trust_connect (message, session->priv->source);
+
+       return TRUE;
+}
+
+static gboolean
+e_soup_session_prepare_message_send_phase2_sync (ESoupSession *session,
+                                                SoupMessage *message,
+                                                GCancellable *cancellable,
+                                                GError **error)
+{
+       ESoupAuthBearer *using_bearer_auth = NULL;
+
+       g_return_val_if_fail (E_IS_SOUP_SESSION (session), FALSE);
+       g_return_val_if_fail (SOUP_IS_MESSAGE (message), FALSE);
+
+       g_mutex_lock (&session->priv->property_lock);
+       if (session->priv->using_bearer_auth)
+               using_bearer_auth = g_object_ref (session->priv->using_bearer_auth);
+       g_mutex_unlock (&session->priv->property_lock);
+
+       if (using_bearer_auth &&
+           e_soup_auth_bearer_is_expired (using_bearer_auth)) {
+               GError *local_error = NULL;
+
+               if (!e_soup_session_setup_bearer_auth (session, message, FALSE, using_bearer_auth, 
cancellable, &local_error)) {
+                       if (local_error) {
+                               g_propagate_error (error, local_error);
+                       } else {
+                               g_set_error_literal (&local_error, E_SOUP_SESSION_ERROR, 
SOUP_STATUS_BAD_REQUEST, _("Failed to setup authentication"));
+                       }
+
+                       g_object_unref (using_bearer_auth);
+
+                       return FALSE;
                }
+       }
 
-               if (message->status_code == SOUP_STATUS_CANCELLED) {
-                       g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_CANCELLED, _("Operation was 
cancelled"));
-               } else if (message->status_code == SOUP_STATUS_FORBIDDEN &&
-                          e_soup_session_extract_google_daily_limit_error (message, error)) {
-                       /* Nothing to do */
-               } else {
-                       g_set_error (error, SOUP_HTTP_ERROR, message->status_code,
-                               _("Failed with HTTP error %d: %s"), message->status_code,
-                               e_soup_session_util_status_to_string (message->status_code, 
message->reason_phrase));
+       g_clear_object (&using_bearer_auth);
+
+       return TRUE;
+}
+
+typedef struct _AsyncSendData {
+       guint size;
+       ESoupSession *session;
+       GTask *task;
+       gulong authenticate_id;
+       gulong restarted_id;
+       gchar *certificate_pem;
+       GTlsCertificateFlags certificate_errors;
+} AsyncSendData;
+
+static void
+async_send_data_free (gpointer ptr)
+{
+       AsyncSendData *asd = ptr;
+
+       if (asd) {
+               /* The ads->task is unreffed in e_soup_session_send_message_ready_cb() */
+               g_clear_object (&asd->session);
+               g_free (asd->certificate_pem);
+               g_slice_free (AsyncSendData, asd);
+       }
+}
+
+/**
+ * e_soup_session_prepare_message_send_sync:
+ * @session: an #ESoupSession
+ * @message: a #SoupMessage to prepare for asynchronous send
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @error: return location for a #GError, or %NULL
+ *
+ * Prepares the @message to be a sent asynchronously with
+ * e_soup_session_send_message(). The returned pointer is passed
+ * to the e_soup_session_send_message() as the prepare_data
+ * parameter.
+ *
+ * Returns: (nullable) (transfer full): prepare data for e_soup_session_send_message(),
+ *   or %NULL on error.
+ *
+ * Since: 3.48
+ **/
+gpointer
+e_soup_session_prepare_message_send_sync (ESoupSession *session,
+                                         SoupMessage *message,
+                                         GCancellable *cancellable,
+                                         GError **error)
+{
+       gulong authenticate_id = 0;
+       gulong restarted_id = 0;
+       gboolean success;
+
+       g_return_val_if_fail (E_IS_SOUP_SESSION (session), NULL);
+       g_return_val_if_fail (SOUP_IS_MESSAGE (message), NULL);
+
+       success = e_soup_session_prepare_message_send_phase1_sync (session, message, &authenticate_id, 
&restarted_id, cancellable, error);
+       if (success) {
+               success = e_soup_session_prepare_message_send_phase2_sync (session, message, cancellable, 
error);
+               if (!success) {
+                       if (authenticate_id)
+                               g_signal_handler_disconnect (message, authenticate_id);
+                       if (restarted_id)
+                               g_signal_handler_disconnect (message, restarted_id);
+               }
+       }
+
+       if (success) {
+               AsyncSendData *asd;
+
+               asd = g_slice_new0 (AsyncSendData);
+               asd->size = sizeof (AsyncSendData);
+               asd->authenticate_id = authenticate_id;
+               asd->restarted_id = restarted_id;
+
+               return asd;
+       }
+
+       return NULL;
+}
+
+static void
+e_soup_session_send_message_ready_cb (GObject *source_object,
+                                     GAsyncResult *result,
+                                     gpointer user_data)
+{
+       AsyncSendData *asd = user_data;
+       ESoupSession *esession;
+       SoupSession *session;
+       SoupMessage *message;
+       GInputStream *input_stream;
+       GError *local_error = NULL;
+
+       g_return_if_fail (asd != NULL);
+
+       session = SOUP_SESSION (source_object);
+       esession = E_SOUP_SESSION (session);
+
+       g_rec_mutex_lock (&esession->priv->session_lock);
+
+       input_stream = soup_session_send_finish (session, result, &local_error);
+       message = soup_session_get_async_result_message (session, result);
+
+       if (message) {
+               if (g_error_matches (local_error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE)) {
+                       e_soup_session_extract_ssl_data (E_SOUP_SESSION (session), message, 
&asd->certificate_pem, &asd->certificate_errors);
+               } else if (!local_error && !SOUP_STATUS_IS_SUCCESSFUL (soup_message_get_status (message))) {
+                       if (soup_message_get_status (message) != SOUP_STATUS_FORBIDDEN ||
+                           !e_soup_session_extract_google_daily_limit_error (NULL, 0, &local_error))
+                               g_set_error_literal (&local_error, E_SOUP_SESSION_ERROR, 
soup_message_get_status (message),
+                                       soup_message_get_reason_phrase (message));
                }
+       }
 
-               if (message->status_code == SOUP_STATUS_SSL_FAILED)
-                       e_soup_session_extract_ssl_data (session, message);
+       g_rec_mutex_unlock (&esession->priv->session_lock);
+
+       if (local_error) {
+               g_task_return_error (asd->task, local_error);
+               g_clear_object (&input_stream);
+       } else {
+               g_task_return_pointer (asd->task, input_stream, g_object_unref);
        }
 
-       g_object_unref (message);
+       g_object_unref (asd->task);
+}
+
+/**
+ * e_soup_session_send_message:
+ * @session: an #ESoupSession
+ * @message: a #SoupMessage to send
+ * @io_priority: the I/O priority of the request, like %G_PRIORITY_DEFAULT
+ * @prepare_data: (transfer full): data returned from e_soup_session_prepare_message_send_sync()
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @callback: (scope async): the callback to invoke once the request is finished
+ * @user_data: user data for @callback
+ *
+ * Asynchronously sends the @message. Finish the call with
+ * e_soup_session_send_message_finish().
+ *
+ * The @prepare_data is a result of the e_soup_session_prepare_message_send_sync()
+ * and this function assumes ownership of it. The @prepare_data cannot be used
+ * again after this call.
+ *
+ * Since: 3.48
+ **/
+void
+e_soup_session_send_message (ESoupSession *session,
+                            SoupMessage *message,
+                            gint io_priority,
+                            gpointer prepare_data,
+                            GCancellable *cancellable,
+                            GAsyncReadyCallback callback,
+                            gpointer user_data)
+{
+       AsyncSendData *asd = prepare_data;
 
-       return success;
+       g_return_if_fail (E_IS_SOUP_SESSION (session));
+       g_return_if_fail (SOUP_IS_MESSAGE (message));
+       g_return_if_fail (prepare_data != NULL);
+       g_return_if_fail (asd->size == sizeof (AsyncSendData));
+       g_return_if_fail (asd->session == NULL);
+       g_return_if_fail (asd->task == NULL);
+
+       asd->session = g_object_ref (session);
+       asd->task = g_task_new (session, cancellable, callback, user_data);
+       g_task_set_source_tag (asd->task, e_soup_session_send_message);
+       g_task_set_task_data (asd->task, asd, async_send_data_free);
+
+       g_rec_mutex_lock (&session->priv->session_lock);
+
+       soup_session_send_async (SOUP_SESSION (session), message, io_priority, cancellable,
+               e_soup_session_send_message_ready_cb, asd);
+
+       g_rec_mutex_unlock (&session->priv->session_lock);
+}
+
+/**
+ * e_soup_session_send_message_finish:
+ * @session: an #ESoupSession
+ * @result: a #GAsyncResult object
+ * @out_certificate_pem: (out) (optional) (nullable): return location for a server TLS/SSL certificate
+ *   in PEM format, when the last operation failed with a TLS/SSL error
+ * @out_certificate_errors: (out) (optional): return location for a #GTlsCertificateFlags,
+ *   with certificate error flags when the operation failed with a TLS/SSL error
+ * @error: return location for a #GError, or %NULL
+ *
+ * Finishes the call of e_soup_session_send_message(). This is supposed to
+ * be called from the callback passed to the e_soup_session_send_message().
+ *
+ * The optional @out_certificate_pem and @out_certificate_errors are set,
+ * when provided, only if the operation failed with a TLS/SSL error.
+ *
+ * Make sure the #GInputStream is read and freed from the same thread,
+ * and with the same thread default main context, which this function
+ * was called from, otherwise it can break libsoup3.
+ *
+ * Returns: (transfer full) (nullable): a #GInputStream for reading the response body, or %NULL on error
+ *
+ * Since: 3.48
+ **/
+GInputStream *
+e_soup_session_send_message_finish (ESoupSession *session,
+                                   GAsyncResult *result,
+                                   gchar **out_certificate_pem,
+                                   GTlsCertificateFlags *out_certificate_errors,
+                                   GError **error)
+{
+       GInputStream *input_stream;
+
+       g_return_val_if_fail (E_IS_SOUP_SESSION (session), NULL);
+
+       input_stream = g_task_propagate_pointer (G_TASK (result), error);
+
+       if (!input_stream) {
+               AsyncSendData *asd = g_task_get_task_data (G_TASK (result));
+
+               if (out_certificate_pem)
+                       *out_certificate_pem = asd ? g_steal_pointer (&asd->certificate_pem) : NULL;
+
+               if (out_certificate_errors)
+                       *out_certificate_errors = asd ? asd->certificate_errors : 0;
+       }
+
+       return input_stream;
 }
 
 /**
- * e_soup_session_send_request_sync:
+ * e_soup_session_send_message_sync:
  * @session: an #ESoupSession
- * @request: a #SoupRequestHTTP to send
+ * @message: a #SoupMessage to send
  * @cancellable: optional #GCancellable object, or %NULL
  * @error: return location for a #GError, or %NULL
  *
- * Synchronously sends prepared request and returns #GInputStream
+ * Synchronously sends prepared message and returns #GInputStream
  * that can be used to read its contents.
  *
- * This calls soup_request_send() internally, but it also setups
- * the request according to #ESoupSession:source authentication
+ * This calls soup_session_send() internally, but it also setups
+ * the @message according to #ESoupSession:source authentication
  * settings. It also extracts information about used certificate,
- * in case of SOUP_STATUS_SSL_FAILED error and keeps it for later use
- * by e_soup_session_get_ssl_error_details().
+ * in case of G_TLS_ERROR_BAD_CERTIFICATE error and keeps it
+ * for later use by e_soup_session_get_ssl_error_details().
  *
- * Use e_soup_session_send_request_simple_sync() to read whole
+ * Use e_soup_session_send_message_simple_sync() to read whole
  * content into a #GByteArray.
  *
  * Note that SoupSession doesn't log content read from GInputStream,
  * thus the caller may print the read content on its own when needed.
  *
- * Note the @request is fully filled only after there is anything
+ * Note the @message is fully filled only after there is anything
  * read from the resulting #GInputStream, thus use
  * e_soup_session_check_result() to verify that the receive had
  * been finished properly.
  *
+ * Make sure the #GInputStream is read and freed from the same thread,
+ * and with the same thread default main context, which this function
+ * was called from, otherwise it can break libsoup3.
+ *
  * Returns: (transfer full): A newly allocated #GInputStream,
- *    that can be used to read from the URI pointed to by @request.
+ *    that can be used to read from the URI pointed to by @message.
  *    Free it with g_object_unref(), when no longer needed.
  *
  * Since: 3.26
  **/
 GInputStream *
-e_soup_session_send_request_sync (ESoupSession *session,
-                                 SoupRequestHTTP *request,
+e_soup_session_send_message_sync (ESoupSession *session,
+                                 SoupMessage *message,
                                  GCancellable *cancellable,
                                  GError **error)
 {
        GInputStream *input_stream;
-       SoupMessage *message;
        gboolean redirected;
        gint resend_count = 0;
+       gulong authenticate_id = 0;
+       gulong restarted_id = 0;
        GError *local_error = NULL;
 
        g_return_val_if_fail (E_IS_SOUP_SESSION (session), NULL);
-       g_return_val_if_fail (SOUP_IS_REQUEST_HTTP (request), NULL);
+       g_return_val_if_fail (SOUP_IS_MESSAGE (message), NULL);
 
-       if (!e_soup_session_maybe_prepare_auth (session, request, cancellable, error))
+       if (!e_soup_session_prepare_message_send_phase1_sync (session, message, &authenticate_id, 
&restarted_id, cancellable, error))
                return NULL;
 
        g_mutex_lock (&session->priv->property_lock);
@@ -1036,73 +1398,44 @@ e_soup_session_send_request_sync (ESoupSession *session,
        session->priv->ssl_info_set = FALSE;
        g_mutex_unlock (&session->priv->property_lock);
 
-       if (session->priv->source &&
-           e_source_has_extension (session->priv->source, E_SOURCE_EXTENSION_WEBDAV_BACKEND)) {
-               message = soup_request_http_get_message (request);
-
-               e_soup_ssl_trust_connect (message, session->priv->source);
-
-               g_clear_object (&message);
-       }
-
        redirected = TRUE;
        while (redirected) {
-               ESoupAuthBearer *using_bearer_auth = NULL;
-
                redirected = FALSE;
 
-               g_mutex_lock (&session->priv->property_lock);
-               if (session->priv->using_bearer_auth)
-                       using_bearer_auth = g_object_ref (session->priv->using_bearer_auth);
-               g_mutex_unlock (&session->priv->property_lock);
+               if (!e_soup_session_prepare_message_send_phase2_sync (session, message, cancellable, error)) {
+                       if (authenticate_id)
+                               g_signal_handler_disconnect (message, authenticate_id);
+                       if (restarted_id)
+                               g_signal_handler_disconnect (message, restarted_id);
 
-               if (using_bearer_auth &&
-                   e_soup_auth_bearer_is_expired (using_bearer_auth)) {
-                       message = soup_request_http_get_message (request);
-
-                       if (!e_soup_session_setup_bearer_auth (session, message, FALSE, using_bearer_auth, 
cancellable, &local_error)) {
-                               if (local_error) {
-                                       soup_message_set_status_full (message, SOUP_STATUS_BAD_REQUEST, 
local_error->message);
-                                       g_propagate_error (error, local_error);
-                               } else {
-                                       soup_message_set_status (message, SOUP_STATUS_BAD_REQUEST);
-                               }
-
-                               g_object_unref (using_bearer_auth);
-                               g_clear_object (&message);
-
-                               return NULL;
-                       }
-
-                       g_clear_object (&message);
+                       return NULL;
                }
 
-               g_clear_object (&using_bearer_auth);
+               g_rec_mutex_lock (&session->priv->session_lock);
 
-               input_stream = soup_request_send (SOUP_REQUEST (request), cancellable, &local_error);
-               if (input_stream) {
-                       message = soup_request_http_get_message (request);
+               input_stream = soup_session_send (SOUP_SESSION (session), message, cancellable, &local_error);
 
-                       if (message && e_soup_session_get_log_level (session) == SOUP_LOGGER_LOG_BODY)
-                               input_stream = e_soup_logger_attach (message, input_stream);
+               g_rec_mutex_unlock (&session->priv->session_lock);
 
-                       if (message && SOUP_STATUS_IS_REDIRECTION (message->status_code)) {
+               if (input_stream) {
+                       if (SOUP_STATUS_IS_REDIRECTION (soup_message_get_status (message))) {
                                /* libsoup uses 20, but the constant is not in any public header */
                                if (resend_count >= 30) {
-                                       soup_message_set_status (message, SOUP_STATUS_TOO_MANY_REDIRECTS);
+                                       g_set_error_literal (&local_error, SOUP_SESSION_ERROR, 
SOUP_SESSION_ERROR_TOO_MANY_REDIRECTS, _("Too many redirects"));
+                                       g_clear_object (&input_stream);
                                } else {
                                        const gchar *new_location;
 
-                                       new_location = soup_message_headers_get_list 
(message->response_headers, "Location");
+                                       new_location = soup_message_headers_get_list 
(soup_message_get_response_headers (message), "Location");
                                        if (new_location) {
-                                               SoupURI *new_uri;
+                                               GUri *new_uri;
 
-                                               new_uri = soup_uri_new_with_base (soup_message_get_uri 
(message), new_location);
+                                               new_uri = g_uri_parse_relative (soup_message_get_uri 
(message), new_location, SOUP_HTTP_URI_FLAGS, NULL);
 
                                                soup_message_set_uri (message, new_uri);
 
                                                g_clear_object (&input_stream);
-                                               soup_uri_free (new_uri);
+                                               g_uri_unref (new_uri);
 
                                                g_signal_emit_by_name (message, "restarted");
 
@@ -1111,63 +1444,52 @@ e_soup_session_send_request_sync (ESoupSession *session,
                                        }
                                }
                        }
-
-                       g_clear_object (&message);
                }
        }
 
-       if (input_stream)
-               return input_stream;
+       if (authenticate_id)
+               g_signal_handler_disconnect (message, authenticate_id);
 
-       if (g_error_matches (local_error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE)) {
-               local_error->domain = SOUP_HTTP_ERROR;
-               local_error->code = SOUP_STATUS_SSL_FAILED;
-       }
+       if (restarted_id)
+               g_signal_handler_disconnect (message, restarted_id);
 
-       if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_SSL_FAILED)) {
-               message = soup_request_http_get_message (request);
-
-               e_soup_session_extract_ssl_data (session, message);
-
-               g_clear_object (&message);
-       } else if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_FORBIDDEN)) {
-               message = soup_request_http_get_message (request);
-
-               if (e_soup_session_extract_google_daily_limit_error (message, error))
-                       g_clear_error (&local_error);
-
-               g_clear_object (&message);
+       if (g_error_matches (local_error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE)) {
+               e_soup_session_extract_ssl_data_internal (session, message);
+       } else if (!local_error && !SOUP_STATUS_IS_SUCCESSFUL (soup_message_get_status (message))) {
+               if (soup_message_get_status (message) != SOUP_STATUS_FORBIDDEN ||
+                   !e_soup_session_extract_google_daily_limit_error (NULL, 0, error))
+                       g_set_error_literal (&local_error, E_SOUP_SESSION_ERROR, soup_message_get_status 
(message),
+                               soup_message_get_reason_phrase (message));
        }
 
-       if (local_error)
+       if (local_error) {
                g_propagate_error (error, local_error);
+               g_clear_object (&input_stream);
+       }
 
-       return NULL;
+       return input_stream;
 }
 
 /**
- * e_soup_session_send_request_simple_sync:
+ * e_soup_session_send_message_simple_sync:
  * @session: an #ESoupSession
- * @request: a #SoupRequestHTTP to send
+ * @message: a #SoupMessage to send
  * @cancellable: optional #GCancellable object, or %NULL
  * @error: return location for a #GError, or %NULL
  *
- * Similar to e_soup_session_send_request_sync(), except it reads
+ * Similar to e_soup_session_send_message_sync(), except it reads
  * whole response content into memory and returns it as a #GByteArray.
- * Use e_soup_session_send_request_sync() when you want to have
+ * Use e_soup_session_send_message_sync() when you want to have
  * more control on the content read.
  *
- * The function prints read content to stdout when
- * e_soup_session_get_log_level() returns #SOUP_LOGGER_LOG_BODY.
- *
  * Returns: (transfer full): A newly allocated #GByteArray,
- *    which contains whole content from the URI pointed to by @request.
+ *    which contains whole content from the URI pointed to by @message.
  *
  * Since: 3.26
  **/
 GByteArray *
-e_soup_session_send_request_simple_sync (ESoupSession *session,
-                                        SoupRequestHTTP *request,
+e_soup_session_send_message_simple_sync (ESoupSession *session,
+                                        SoupMessage *message,
                                         GCancellable *cancellable,
                                         GError **error)
 {
@@ -1179,15 +1501,15 @@ e_soup_session_send_request_simple_sync (ESoupSession *session,
        gboolean success = FALSE;
 
        g_return_val_if_fail (E_IS_SOUP_SESSION (session), NULL);
-       g_return_val_if_fail (SOUP_IS_REQUEST_HTTP (request), NULL);
+       g_return_val_if_fail (SOUP_IS_MESSAGE (message), NULL);
 
-       input_stream = e_soup_session_send_request_sync (session, request, cancellable, error);
+       input_stream = e_soup_session_send_message_sync (session, message, cancellable, error);
        if (!input_stream)
                return NULL;
 
-       expected_length = soup_request_get_content_length (SOUP_REQUEST (request));
+       expected_length = soup_message_headers_get_content_length (soup_message_get_response_headers 
(message));
        if (expected_length > 0)
-               bytes = g_byte_array_sized_new (expected_length);
+               bytes = g_byte_array_sized_new (expected_length > 1024 * 1024 * 10 ? 1024 * 1024 * 10 : 
expected_length);
        else
                bytes = g_byte_array_new ();
 
@@ -1202,7 +1524,7 @@ e_soup_session_send_request_simple_sync (ESoupSession *session,
        g_object_unref (input_stream);
 
        if (success)
-               success = e_soup_session_check_result (session, request, bytes->data, bytes->len, error);
+               success = e_soup_session_check_result (session, message, bytes->data, bytes->len, error);
 
        if (!success) {
                g_byte_array_free (bytes, TRUE);
@@ -1261,64 +1583,370 @@ part_needs_encoding (const gchar *part)
 
 /**
  * e_soup_session_util_normalize_uri_path:
- * @suri: a #SoupURI to normalize the path for
+ * @uri: a #GUri to normalize the path for
  *
- * Normalizes the path of the @suri, aka encodes characters, which should
- * be encoded, if needed. Returns, whether any change had been made to the path.
- * It doesn't touch other parts of the @suri.
+ * Normalizes the path of the @uri, aka encodes characters, which should
+ * be encoded, if needed. Returns, modified URI when any change had been made to the path.
+ * It doesn't touch other parts of the @uri.
  *
- * Returns: whether made any changes
+ * Returns: (transfer full) (nullable): a new #GUri with modified path, or %NULL, when
+ *    no change was required.
  *
- * Since: 3.38
+ * Since: 3.48
  **/
-gboolean
-e_soup_session_util_normalize_uri_path (SoupURI *suri)
+GUri *
+e_soup_session_util_normalize_uri_path (GUri *uri)
 {
        const gchar *path;
        gchar **parts, *tmp;
-       gboolean did_change = FALSE;
+       GUri *nuri = NULL;
        gint ii;
 
-       if (!suri)
-               return FALSE;
+       if (!uri)
+               return NULL;
 
-       path = soup_uri_get_path (suri);
+       path = g_uri_get_path (uri);
 
-       if (!path || !*path || g_strcmp0 (path, "/") == 0)
-               return FALSE;
+       if (!*path || g_strcmp0 (path, "/") == 0)
+               return NULL;
 
        if (!part_needs_encoding (path))
-               return FALSE;
+               return NULL;
 
        parts = g_strsplit (path, "/", -1);
 
        if (!parts)
-               return FALSE;
+               return NULL;
 
        for (ii = 0; parts[ii]; ii++) {
                gchar *part = parts[ii];
 
                if (part_needs_encoding (part)) {
                        if (strchr (part, '%')) {
-                               tmp = soup_uri_decode (part);
+                               tmp = g_uri_unescape_string (part, NULL);
                                g_free (part);
                                part = tmp;
                        }
 
-                       tmp = soup_uri_encode (part, NULL);
+                       tmp = g_uri_escape_string (part, NULL, FALSE);
                        g_free (part);
                        parts[ii] = tmp;
                }
        }
 
        tmp = g_strjoinv ("/", parts);
-       if (g_strcmp0 (path, tmp) != 0) {
-               soup_uri_set_path (suri, tmp);
-               did_change = TRUE;
-       }
+       if (g_strcmp0 (path, tmp) != 0)
+               nuri = soup_uri_copy (uri, SOUP_URI_PATH, tmp, SOUP_URI_NONE);
 
        g_free (tmp);
        g_strfreev (parts);
 
-       return did_change;
+       return nuri;
+}
+
+typedef struct _EInputStreamWrapper {
+       GInputStream parent;
+
+       GInputStream *input_stream;
+       goffset read_from;
+} EInputStreamWrapper;
+
+typedef struct _EInputStreamWrapperClass {
+       GInputStreamClass parent_class;
+} EInputStreamWrapperClass;
+
+GType e_input_stream_wrapper_get_type (void);
+
+static void e_input_stream_wrapper_pollable_iface_init (GPollableInputStreamInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (EInputStreamWrapper, e_input_stream_wrapper, G_TYPE_INPUT_STREAM,
+       G_IMPLEMENT_INTERFACE (G_TYPE_POLLABLE_INPUT_STREAM, e_input_stream_wrapper_pollable_iface_init))
+
+#define E_INPUT_STREAM_WRAPPER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), e_input_stream_wrapper_get_type (), 
EInputStreamWrapper))
+
+static gssize
+e_input_stream_wrapper_read_fn (GInputStream *stream,
+                                void *buffer,
+                               gsize count,
+                               GCancellable *cancellable,
+                               GError **error)
+{
+       EInputStreamWrapper *wrapper = E_INPUT_STREAM_WRAPPER (stream);
+
+       return g_input_stream_read (wrapper->input_stream, buffer, count, cancellable, error);
+}
+
+static gssize
+e_input_stream_wrapper_skip (GInputStream *stream,
+                            gsize count,
+                            GCancellable *cancellable,
+                            GError **error)
+{
+       EInputStreamWrapper *wrapper = E_INPUT_STREAM_WRAPPER (stream);
+
+       return g_input_stream_skip (wrapper->input_stream, count, cancellable, error);
+}
+
+static gboolean
+e_input_stream_wrapper_close_fn (GInputStream *stream,
+                                GCancellable *cancellable,
+                                GError **error)
+{
+       /* Always success, but without closing the self::input_stream */
+       return TRUE;
+}
+
+static gboolean
+e_input_stream_wrapper_is_readable (GPollableInputStream *stream)
+{
+       return TRUE;
+}
+
+static GSource *
+e_input_stream_wrapper_create_source (GPollableInputStream *stream,
+                                     GCancellable *cancellable)
+{
+       GSource *base_source, *pollable_source;
+
+       base_source = g_timeout_source_new (0);
+       pollable_source = g_pollable_source_new_full (stream, base_source, cancellable);
+       g_source_unref (base_source);
+
+       return pollable_source;
+}
+
+static void
+e_input_stream_wrapper_dispose (GObject *object)
+{
+       EInputStreamWrapper *wrapper = E_INPUT_STREAM_WRAPPER (object);
+
+       g_clear_object (&wrapper->input_stream);
+
+       /* Chain up to parent's method. */
+       G_OBJECT_CLASS (e_input_stream_wrapper_parent_class)->dispose (object);
+}
+
+static void
+e_input_stream_wrapper_class_init (EInputStreamWrapperClass *klass)
+{
+       GInputStreamClass *input_stream_class;
+       GObjectClass *object_class;
+
+       input_stream_class = G_INPUT_STREAM_CLASS (klass);
+       input_stream_class->read_fn = e_input_stream_wrapper_read_fn;
+       input_stream_class->skip = e_input_stream_wrapper_skip;
+       input_stream_class->close_fn = e_input_stream_wrapper_close_fn;
+
+       object_class = G_OBJECT_CLASS (klass);
+       object_class->dispose = e_input_stream_wrapper_dispose;
+}
+
+static void
+e_input_stream_wrapper_pollable_iface_init (GPollableInputStreamInterface *iface)
+{
+       iface->is_readable = e_input_stream_wrapper_is_readable;
+       iface->create_source = e_input_stream_wrapper_create_source;
+}
+
+static void
+e_input_stream_wrapper_init (EInputStreamWrapper *self)
+{
+}
+
+static void
+e_input_stream_wrapper_assign (EInputStreamWrapper *self,
+                              GInputStream *input_stream)
+{
+       self->input_stream = g_object_ref (input_stream);
+
+       if (G_IS_SEEKABLE (input_stream))
+               self->read_from = g_seekable_tell (G_SEEKABLE (input_stream));
+}
+
+static void
+e_input_stream_wrapper_rewind (EInputStreamWrapper *self)
+{
+       if (G_IS_SEEKABLE (self->input_stream) && self->read_from != g_seekable_tell (G_SEEKABLE 
(self->input_stream)))
+               g_seekable_seek (G_SEEKABLE (self->input_stream), self->read_from, G_SEEK_SET, NULL, NULL);
+}
+
+static GInputStream *
+e_input_stream_wrapper_dup (EInputStreamWrapper *self)
+{
+       EInputStreamWrapper *dup;
+
+       e_input_stream_wrapper_rewind (self);
+
+       dup = g_object_new (e_input_stream_wrapper_get_type (), NULL);
+       dup->input_stream = g_object_ref (self->input_stream);
+       dup->read_from = self->read_from;
+
+       return G_INPUT_STREAM (dup);
+}
+
+typedef struct _MessageData {
+       GInputStream *input_stream;
+       gssize length;
+} MessageData;
+
+static MessageData *
+message_data_new (GInputStream *input_stream,
+                 gssize length)
+{
+       MessageData *md;
+       EInputStreamWrapper *wrapper;
+
+       wrapper = g_object_new (e_input_stream_wrapper_get_type (), NULL);
+       e_input_stream_wrapper_assign (wrapper, input_stream);
+
+       md = g_slice_new0 (MessageData);
+       md->input_stream = G_INPUT_STREAM (wrapper);
+       md->length = length;
+
+       return md;
+}
+
+static void
+message_data_free (gpointer ptr)
+{
+       MessageData *md = ptr;
+
+       if (md) {
+               g_object_unref (md->input_stream);
+               g_slice_free (MessageData, md);
+       }
+}
+
+static void
+e_soup_session_message_restarted_cb (SoupMessage *message,
+                                    gpointer user_data)
+{
+       GInputStream *input_stream;
+       gssize length = 0;
+
+       input_stream = e_soup_session_util_ref_message_request_body (message, &length);
+
+       g_return_if_fail (input_stream != NULL);
+
+       soup_message_set_request_body (message, NULL, input_stream, length);
+
+       g_clear_object (&input_stream);
+}
+
+#define MESSAGE_DATA_KEY "ESoupSession::message-data"
+
+/**
+ * e_soup_session_util_set_message_request_body:
+ * @message: a #SoupMessage
+ * @content_type: (optional): optional Content-Type of the @data, or %NULL
+ * @input_stream (transfer none): the request body data as a #GInputStream
+ * @length: length of the @data
+ *
+ * Sets the request body of the @message from the @input_stream of the @length, with optional
+ * @content_type. The function makes sure the @message request body is set again
+ * when the message is restarted.
+ *
+ * The @input_stream should implement the #GSeekable interface.
+ *
+ * Since: 3.48
+ **/
+void
+e_soup_session_util_set_message_request_body (SoupMessage *message,
+                                             const gchar *content_type,
+                                             GInputStream *input_stream,
+                                             gssize length)
+{
+       MessageData *md;
+
+       g_return_if_fail (SOUP_IS_MESSAGE (message));
+       g_return_if_fail (G_IS_SEEKABLE (input_stream));
+
+       md = message_data_new (input_stream, length);
+
+       g_object_set_data_full (G_OBJECT (message), MESSAGE_DATA_KEY, md, message_data_free);
+
+       g_signal_connect (message, "restarted",
+               G_CALLBACK (e_soup_session_message_restarted_cb), NULL);
+
+       soup_message_set_request_body (message, content_type, md->input_stream, length);
+}
+
+/**
+ * e_soup_session_util_set_message_request_body_from_data:
+ * @message: a #SoupMessage
+ * @create_copy: whether to create copy of the @data
+ * @content_type: (optional): optional Content-Type of the @data, or %NULL
+ * @data: the request body data
+ * @length: length of the @data
+ * @free_func: (optional): a free function for the @data, or %NULL
+ *
+ * Sets the request body of the @message from the @data of the @length, with optional
+ * @content_type. The function makes sure the @message request body is set again
+ * when the message is restarted.
+ *
+ * When the @create_copy is %TRUE, the @free_func should be %NULL.
+ *
+ * Since: 3.48
+ **/
+void
+e_soup_session_util_set_message_request_body_from_data (SoupMessage *message,
+                                                       gboolean create_copy,
+                                                       const gchar *content_type,
+                                                       gconstpointer data,
+                                                       gssize length,
+                                                       GDestroyNotify free_func)
+{
+       GInputStream *input_stream;
+
+       g_return_if_fail (SOUP_IS_MESSAGE (message));
+       g_return_if_fail (data != NULL);
+       if (create_copy)
+               g_return_if_fail (free_func == NULL);
+
+       if (create_copy)
+               input_stream = g_memory_input_stream_new_from_data (g_memdup2 (data, length), length, g_free);
+       else
+               input_stream = g_memory_input_stream_new_from_data (data, length, free_func);
+
+       e_soup_session_util_set_message_request_body (message, content_type, input_stream, length);
+
+       g_object_unref (input_stream);
+}
+
+/**
+ * e_soup_session_util_ref_message_request_body:
+ * @message: a #SoupMessage
+ * @out_length: (out) (optional): length of the input stream
+ *
+ * Returns referenced request data for the @message, as being previously
+ * set by the e_soup_session_util_set_message_request_body() or
+ * e_soup_session_util_set_message_request_body_from_data().
+ *
+ * Do not call this function while the @message is queued in
+ * a #SoupSession, nor modify the input stream position until
+ * the @message lefts the #SoupSession.
+ *
+ * Returns: (nullable) (transfer full): a new #GInputStream with the request
+ *    body being previously set, or %NULL. The @out_length is set to the length
+ *    of the returned input stream.
+ *
+ * Since: 3.48
+ **/
+GInputStream *
+e_soup_session_util_ref_message_request_body (SoupMessage *message,
+                                             gssize *out_length)
+{
+       MessageData *md;
+
+       g_return_val_if_fail (SOUP_IS_MESSAGE (message), NULL);
+
+       md = g_object_get_data (G_OBJECT (message), MESSAGE_DATA_KEY);
+
+       if (!md || !md->input_stream)
+               return NULL;
+
+       if (out_length)
+               *out_length = md->length;
+
+       return e_input_stream_wrapper_dup (E_INPUT_STREAM_WRAPPER (md->input_stream));
 }
diff --git a/src/libedataserver/e-soup-session.h b/src/libedataserver/e-soup-session.h
index 78a75f41f..d5112397d 100644
--- a/src/libedataserver/e-soup-session.h
+++ b/src/libedataserver/e-soup-session.h
@@ -47,6 +47,8 @@
        (G_TYPE_INSTANCE_GET_CLASS \
        ((obj), E_TYPE_SOUP_SESSION, ESoupSessionClass))
 
+#define E_SOUP_SESSION_ERROR (e_soup_session_error_quark())
+
 G_BEGIN_DECLS
 
 typedef struct _ESoupSession ESoupSession;
@@ -74,6 +76,8 @@ struct _ESoupSessionClass {
        gpointer reserved[10];
 };
 
+GQuark         e_soup_session_error_quark              (void) G_GNUC_CONST;
+
 GType          e_soup_session_get_type                 (void) G_GNUC_CONST;
 
 ESoupSession * e_soup_session_new                      (ESource *source);
@@ -91,33 +95,61 @@ gboolean    e_soup_session_get_authentication_requires_credentials
 gboolean       e_soup_session_get_ssl_error_details    (ESoupSession *session,
                                                         gchar **out_certificate_pem,
                                                         GTlsCertificateFlags *out_certificate_errors);
-SoupRequestHTTP *
-               e_soup_session_new_request              (ESoupSession *session,
+SoupMessage *  e_soup_session_new_message              (ESoupSession *session,
                                                         const gchar *method,
                                                         const gchar *uri_string,
                                                         GError **error);
-SoupRequestHTTP *
-               e_soup_session_new_request_uri          (ESoupSession *session,
+SoupMessage *  e_soup_session_new_message_from_uri     (ESoupSession *session,
                                                         const gchar *method,
-                                                        SoupURI *uri,
+                                                        GUri *uri,
                                                         GError **error);
 gboolean       e_soup_session_check_result             (ESoupSession *session,
-                                                        SoupRequestHTTP *request,
+                                                        SoupMessage *message,
                                                         gconstpointer read_bytes,
                                                         gsize bytes_length,
                                                         GError **error);
-GInputStream * e_soup_session_send_request_sync        (ESoupSession *session,
-                                                        SoupRequestHTTP *request,
+gpointer       e_soup_session_prepare_message_send_sync(ESoupSession *session,
+                                                        SoupMessage *message,
+                                                        GCancellable *cancellable,
+                                                        GError **error);
+void           e_soup_session_send_message             (ESoupSession *session,
+                                                        SoupMessage *message,
+                                                        gint io_priority,
+                                                        gpointer prepare_data,
+                                                        GCancellable *cancellable,
+                                                        GAsyncReadyCallback callback,
+                                                        gpointer user_data);
+GInputStream * e_soup_session_send_message_finish      (ESoupSession *session,
+                                                        GAsyncResult *result,
+                                                        gchar **out_certificate_pem,
+                                                        GTlsCertificateFlags *out_certificate_errors,
+                                                        GError **error);
+GInputStream * e_soup_session_send_message_sync        (ESoupSession *session,
+                                                        SoupMessage *message,
                                                         GCancellable *cancellable,
                                                         GError **error);
-GByteArray *   e_soup_session_send_request_simple_sync (ESoupSession *session,
-                                                        SoupRequestHTTP *request,
+GByteArray *   e_soup_session_send_message_simple_sync (ESoupSession *session,
+                                                        SoupMessage *message,
                                                         GCancellable *cancellable,
                                                         GError **error);
 const gchar *  e_soup_session_util_status_to_string    (guint status_code,
                                                         const gchar *reason_phrase);
-gboolean       e_soup_session_util_normalize_uri_path  (SoupURI *suri);
-
+GUri *         e_soup_session_util_normalize_uri_path  (GUri *uri);
+void           e_soup_session_util_set_message_request_body
+                                                       (SoupMessage *message,
+                                                        const gchar *content_type,
+                                                        GInputStream *input_stream,
+                                                        gssize length);
+void           e_soup_session_util_set_message_request_body_from_data
+                                                       (SoupMessage *message,
+                                                        gboolean create_copy,
+                                                        const gchar *content_type,
+                                                        gconstpointer data,
+                                                        gssize length,
+                                                        GDestroyNotify free_func);
+GInputStream * e_soup_session_util_ref_message_request_body
+                                                       (SoupMessage *message,
+                                                        gssize *out_length);
 G_END_DECLS
 
 #endif /* E_SOUP_SESSION_H */
diff --git a/src/libedataserver/e-soup-ssl-trust.c b/src/libedataserver/e-soup-ssl-trust.c
index a97a7f269..5e6c8a73a 100644
--- a/src/libedataserver/e-soup-ssl-trust.c
+++ b/src/libedataserver/e-soup-ssl-trust.c
@@ -30,35 +30,28 @@
 
 #include "e-soup-ssl-trust.h"
 
-typedef struct _ESoupSslTrustData {
-       SoupMessage *soup_message; /* weak */
-       ESource *source;
-
-       GClosure *accept_certificate_closure;
-} ESoupSslTrustData;
-
 static gboolean
-e_soup_ssl_trust_accept_certificate_cb (GTlsConnection *conn,
+e_soup_ssl_trust_accept_certificate_cb (SoupMessage *message,
                                        GTlsCertificate *peer_cert,
                                        GTlsCertificateFlags errors,
                                        gpointer user_data)
 {
-       ESoupSslTrustData *handler = user_data;
+       ESource *source = user_data;
        ETrustPromptResponse response;
-       SoupURI *soup_uri;
+       GUri *g_uri;
        const gchar *host;
        gchar *auth_host = NULL;
 
-       soup_uri = soup_message_get_uri (handler->soup_message);
-       if (!soup_uri || !soup_uri_get_host (soup_uri))
+       g_uri = soup_message_get_uri (message);
+       if (!g_uri || !g_uri_get_host (g_uri))
                return FALSE;
 
-       host = soup_uri_get_host (soup_uri);
+       host = g_uri_get_host (g_uri);
 
-       if (e_source_has_extension (handler->source, E_SOURCE_EXTENSION_AUTHENTICATION)) {
+       if (e_source_has_extension (source, E_SOURCE_EXTENSION_AUTHENTICATION)) {
                ESourceAuthentication *extension_authentication;
 
-               extension_authentication = e_source_get_extension (handler->source, 
E_SOURCE_EXTENSION_AUTHENTICATION);
+               extension_authentication = e_source_get_extension (source, E_SOURCE_EXTENSION_AUTHENTICATION);
                auth_host = e_source_authentication_dup_host (extension_authentication);
 
                if (auth_host && *auth_host) {
@@ -73,7 +66,7 @@ e_soup_ssl_trust_accept_certificate_cb (GTlsConnection *conn,
        }
 
        response = e_source_webdav_verify_ssl_trust (
-               e_source_get_extension (handler->source, E_SOURCE_EXTENSION_WEBDAV_BACKEND),
+               e_source_get_extension (source, E_SOURCE_EXTENSION_WEBDAV_BACKEND),
                host, peer_cert, errors);
 
        g_free (auth_host);
@@ -82,43 +75,6 @@ e_soup_ssl_trust_accept_certificate_cb (GTlsConnection *conn,
                response == E_TRUST_PROMPT_RESPONSE_ACCEPT_TEMPORARILY);
 }
 
-static void
-e_soup_ssl_trust_network_event_cb (SoupMessage *msg,
-                                  GSocketClientEvent event,
-                                  GIOStream *connection,
-                                  gpointer user_data)
-{
-       ESoupSslTrustData *handler = user_data;
-
-       /* It's either a GTlsConnection or a GTcpConnection */
-       if (event == G_SOCKET_CLIENT_TLS_HANDSHAKING &&
-           G_IS_TLS_CONNECTION (connection)) {
-               g_signal_connect_closure (
-                       G_TLS_CONNECTION (connection), "accept-certificate",
-                       handler->accept_certificate_closure, FALSE);
-       }
-}
-
-static void
-e_soup_ssl_trust_message_finalized_cb (gpointer data,
-                                      GObject *unused_message)
-{
-       ESoupSslTrustData *handler;
-
-       /* The network event handler will be disconnected from the message just
-        * before this is called. */
-       handler = data;
-
-       g_clear_object (&handler->source);
-
-       /* Synchronously disconnects the accept certificate handler from all
-        * GTlsConnections. */
-       g_closure_invalidate (handler->accept_certificate_closure);
-       g_closure_unref (handler->accept_certificate_closure);
-
-       g_free (handler);
-}
-
 /**
  * e_soup_ssl_trust_connect:
  * @soup_message: a #SoupMessage about to be sent to the source
@@ -144,21 +100,11 @@ void
 e_soup_ssl_trust_connect (SoupMessage *soup_message,
                           ESource *source)
 {
-       ESoupSslTrustData *handler;
-
        g_return_if_fail (SOUP_IS_MESSAGE (soup_message));
        g_return_if_fail (E_IS_SOURCE (source));
 
-       handler = g_malloc (sizeof (ESoupSslTrustData));
-       handler->soup_message = soup_message;
-       g_object_weak_ref (G_OBJECT (soup_message), e_soup_ssl_trust_message_finalized_cb, handler);
-       handler->source = g_object_ref (source);
-       handler->accept_certificate_closure = g_cclosure_new (G_CALLBACK 
(e_soup_ssl_trust_accept_certificate_cb), handler, NULL);
-
-       g_closure_ref (handler->accept_certificate_closure);
-       g_closure_sink (handler->accept_certificate_closure);
-
-       g_signal_connect (
-               soup_message, "network-event",
-               G_CALLBACK (e_soup_ssl_trust_network_event_cb), handler);
+       g_signal_connect_data (
+               soup_message, "accept-certificate",
+               G_CALLBACK (e_soup_ssl_trust_accept_certificate_cb), g_object_ref (source),
+               (GClosureNotify) g_object_unref, 0);
 }
diff --git a/src/libedataserver/e-source-webdav.c b/src/libedataserver/e-source-webdav.c
index 09b9cd09a..6ca9b20f3 100644
--- a/src/libedataserver/e-source-webdav.c
+++ b/src/libedataserver/e-source-webdav.c
@@ -28,7 +28,7 @@
  * this class directly or subclass it with additional settings.
  * Subclasses should override the extension name.
  *
- * The #SoupURI is parsed into components and distributed across
+ * The #GUri is parsed into components and distributed across
  * several other built-in extensions such as #ESourceAuthentication
  * and #ESourceSecurity.
  *
@@ -67,7 +67,7 @@ struct _ESourceWebdavPrivate {
        gchar *ssl_trust;
        gboolean avoid_ifmatch;
        gboolean calendar_auto_schedule;
-       SoupURI *soup_uri;
+       GUri *uri;
        guint order;
 };
 
@@ -80,7 +80,7 @@ enum {
        PROP_EMAIL_ADDRESS,
        PROP_RESOURCE_PATH,
        PROP_RESOURCE_QUERY,
-       PROP_SOUP_URI,
+       PROP_URI,
        PROP_SSL_TRUST,
        PROP_ORDER
 };
@@ -95,7 +95,7 @@ source_webdav_notify_cb (GObject *object,
                          GParamSpec *pspec,
                          ESourceWebdav *extension)
 {
-       g_object_notify (G_OBJECT (extension), "soup-uri");
+       g_object_notify (G_OBJECT (extension), "uri");
 }
 
 static gboolean
@@ -141,17 +141,17 @@ source_webdav_user_to_method (GBinding *binding,
 }
 
 static void
-source_webdav_update_properties_from_soup_uri (ESourceWebdav *webdav_extension)
+source_webdav_update_properties_from_uri (ESourceWebdav *webdav_extension)
 {
        ESource *source;
        ESourceExtension *extension;
-       SoupURI *soup_uri;
+       GUri *uri;
        const gchar *extension_name;
 
-       /* Do not use e_source_webdav_dup_soup_uri() here.  That
+       /* Do not use e_source_webdav_dup_uri() here.  That
         * builds the URI from properties we haven't yet updated. */
        e_source_extension_property_lock (E_SOURCE_EXTENSION (webdav_extension));
-       soup_uri = soup_uri_copy (webdav_extension->priv->soup_uri);
+       uri = g_uri_ref (webdav_extension->priv->uri);
        e_source_extension_property_unlock (E_SOURCE_EXTENSION (webdav_extension));
 
        extension = E_SOURCE_EXTENSION (webdav_extension);
@@ -159,8 +159,8 @@ source_webdav_update_properties_from_soup_uri (ESourceWebdav *webdav_extension)
 
        g_object_set (
                extension,
-               "resource-path", soup_uri->path,
-               "resource-query", soup_uri->query,
+               "resource-path", g_uri_get_path (uri),
+               "resource-query", g_uri_get_query (uri),
                NULL);
 
        extension_name = E_SOURCE_EXTENSION_AUTHENTICATION;
@@ -168,14 +168,14 @@ source_webdav_update_properties_from_soup_uri (ESourceWebdav *webdav_extension)
 
        g_object_set (
                extension,
-               "host", soup_uri->host,
-               "port", soup_uri->port,
+               "host", g_uri_get_host (uri),
+               "port", g_uri_get_port (uri),
                NULL);
 
-       if (soup_uri->user && *soup_uri->user)
+       if (g_uri_get_user (uri) && *g_uri_get_user (uri))
                g_object_set (
                        extension,
-                       "user", soup_uri->user,
+                       "user", g_uri_get_user (uri),
                        NULL);
 
        extension_name = E_SOURCE_EXTENSION_SECURITY;
@@ -183,21 +183,22 @@ source_webdav_update_properties_from_soup_uri (ESourceWebdav *webdav_extension)
 
        g_object_set (
                extension,
-               "secure", (soup_uri->scheme == SOUP_URI_SCHEME_HTTPS),
+               "secure", !strcmp(g_uri_get_scheme (uri), "https"),
                NULL);
 
        g_object_unref (source);
 
-       soup_uri_free (soup_uri);
+       g_uri_unref (uri);
 }
 
 static void
-source_webdav_update_soup_uri_from_properties (ESourceWebdav *webdav_extension)
+source_webdav_update_uri_from_properties (ESourceWebdav *webdav_extension)
 {
        ESource *source;
+       GUri *nuri;
        ESourceExtension *extension;
-       SoupURI *soup_uri;
        const gchar *extension_name;
+       const gchar *scheme;
        gchar *user;
        gchar *host;
        gchar *path;
@@ -236,25 +237,29 @@ source_webdav_update_soup_uri_from_properties (ESourceWebdav *webdav_extension)
 
        e_source_extension_property_lock (E_SOURCE_EXTENSION (webdav_extension));
 
-       soup_uri = webdav_extension->priv->soup_uri;
+       if (port == 0)
+               port = g_uri_get_port (webdav_extension->priv->uri);
+
+       scheme = g_uri_get_scheme (webdav_extension->priv->uri);
 
        /* Try not to disturb the scheme, in case it's "webcal" or some
         * other non-standard value.  But if we have to change it, do it. */
-       if (secure && soup_uri->scheme != SOUP_URI_SCHEME_HTTPS)
-               soup_uri_set_scheme (soup_uri, SOUP_URI_SCHEME_HTTPS);
-       if (!secure && soup_uri->scheme == SOUP_URI_SCHEME_HTTPS)
-               soup_uri_set_scheme (soup_uri, SOUP_URI_SCHEME_HTTP);
-
-       soup_uri_set_user (soup_uri, user);
-       soup_uri_set_host (soup_uri, host);
-
-       if (port > 0)
-               soup_uri_set_port (soup_uri, port);
-
-       /* SoupURI doesn't like NULL paths. */
-       soup_uri_set_path (soup_uri, (path != NULL) ? path : "");
-
-       soup_uri_set_query (soup_uri, query);
+       if (secure && strcmp (scheme, "https"))
+               scheme = "https";
+       if (!secure && !strcmp (scheme, "https"))
+               scheme = "http";
+
+       nuri = soup_uri_copy (webdav_extension->priv->uri,
+                             SOUP_URI_SCHEME, scheme,
+                             SOUP_URI_HOST, host,
+                             SOUP_URI_USER, user,
+                             SOUP_URI_PORT, port,
+                             SOUP_URI_PATH, (path != NULL) ? path : "",
+                             SOUP_URI_QUERY, query,
+                             SOUP_URI_NONE);
+
+       g_uri_unref (webdav_extension->priv->uri);
+       webdav_extension->priv->uri = nuri;
 
        e_source_extension_property_unlock (E_SOURCE_EXTENSION (webdav_extension));
 
@@ -313,8 +318,8 @@ source_webdav_set_property (GObject *object,
                                g_value_get_string (value));
                        return;
 
-               case PROP_SOUP_URI:
-                       e_source_webdav_set_soup_uri (
+               case PROP_URI:
+                       e_source_webdav_set_uri (
                                E_SOURCE_WEBDAV (object),
                                g_value_get_boxed (value));
                        return;
@@ -391,10 +396,10 @@ source_webdav_get_property (GObject *object,
                                E_SOURCE_WEBDAV (object)));
                        return;
 
-               case PROP_SOUP_URI:
+               case PROP_URI:
                        g_value_take_boxed (
                                value,
-                               e_source_webdav_dup_soup_uri (
+                               e_source_webdav_dup_uri (
                                E_SOURCE_WEBDAV (object)));
                        return;
 
@@ -430,7 +435,7 @@ source_webdav_finalize (GObject *object)
        g_free (priv->resource_query);
        g_free (priv->ssl_trust);
 
-       soup_uri_free (priv->soup_uri);
+       g_uri_unref (priv->uri);
 
        /* Chain up to parent's finalize() method. */
        G_OBJECT_CLASS (e_source_webdav_parent_class)->finalize (object);
@@ -613,12 +618,12 @@ e_source_webdav_class_init (ESourceWebdavClass *class)
 
        g_object_class_install_property (
                object_class,
-               PROP_SOUP_URI,
+               PROP_URI,
                g_param_spec_boxed (
-                       "soup-uri",
-                       "SoupURI",
-                       "WebDAV service as a SoupURI",
-                       SOUP_TYPE_URI,
+                       "uri",
+                       "Uri",
+                       "WebDAV service as a GUri",
+                       G_TYPE_URI,
                        G_PARAM_READWRITE |
                        G_PARAM_EXPLICIT_NOTIFY |
                        G_PARAM_STATIC_STRINGS));
@@ -657,10 +662,9 @@ e_source_webdav_init (ESourceWebdav *extension)
 {
        extension->priv = e_source_webdav_get_instance_private (extension);
 
-       /* Initialize this enough for SOUP_URI_IS_VALID() to pass. */
-       extension->priv->soup_uri = soup_uri_new (NULL);
-       extension->priv->soup_uri->scheme = SOUP_URI_SCHEME_HTTP;
-       extension->priv->soup_uri->path = g_strdup ("");
+       /* Initialize this enough */
+       extension->priv->uri = g_uri_build (SOUP_HTTP_URI_FLAGS, "http", NULL,
+                                           NULL, -1, "", NULL, NULL);
 }
 
 /**
@@ -1286,31 +1290,31 @@ e_source_webdav_set_ssl_trust (ESourceWebdav *extension,
 }
 
 /**
- * e_source_webdav_dup_soup_uri:
+ * e_source_webdav_dup_uri:
  * @extension: an #ESourceWebdav
  *
  * This is a convenience function which returns a newly-allocated
- * #SoupURI, its contents assembled from the #ESourceAuthentication
+ * #GUri, its contents assembled from the #ESourceAuthentication
  * extension, the #ESourceSecurity extension, and @extension itself.
- * Free the returned #SoupURI with soup_uri_free().
+ * Free the returned #GUri with g_uri_unref().
  *
- * Returns: (transfer full): a newly-allocated #SoupURI
+ * Returns: (transfer full): a newly-allocated #GUri
  *
- * Since: 3.6
+ * Since: 3.48
  **/
-SoupURI *
-e_source_webdav_dup_soup_uri (ESourceWebdav *extension)
+GUri *
+e_source_webdav_dup_uri (ESourceWebdav *extension)
 {
-       SoupURI *duplicate;
+       GUri *duplicate;
 
        g_return_val_if_fail (E_IS_SOURCE_WEBDAV (extension), NULL);
 
        /* Keep this outside of the property lock. */
-       source_webdav_update_soup_uri_from_properties (extension);
+       source_webdav_update_uri_from_properties (extension);
 
        e_source_extension_property_lock (E_SOURCE_EXTENSION (extension));
 
-       duplicate = soup_uri_copy (extension->priv->soup_uri);
+       duplicate = g_uri_ref (extension->priv->uri);
 
        e_source_extension_property_unlock (E_SOURCE_EXTENSION (extension));
 
@@ -1318,37 +1322,36 @@ e_source_webdav_dup_soup_uri (ESourceWebdav *extension)
 }
 
 /**
- * e_source_webdav_set_soup_uri:
+ * e_source_webdav_set_uri:
  * @extension: an #ESourceWebdav
- * @soup_uri: a #SoupURI
+ * @uri: a #GUri
  *
  * This is a convenience function which propagates the components of
  * @uri to the #ESourceAuthentication extension, the #ESourceSecurity
  * extension, and @extension itself.  (The "fragment" component of
  * @uri is ignored.)
  *
- * Since: 3.6
+ * Since: 3.48
  **/
 void
-e_source_webdav_set_soup_uri (ESourceWebdav *extension,
-                              SoupURI *soup_uri)
+e_source_webdav_set_uri (ESourceWebdav *extension,
+                        GUri *uri)
 {
        g_return_if_fail (E_IS_SOURCE_WEBDAV (extension));
-       g_return_if_fail (SOUP_URI_IS_VALID (soup_uri));
 
        e_source_extension_property_lock (E_SOURCE_EXTENSION (extension));
 
        /* Do not test for URI equality because our
-        * internal SoupURI might not be up-to-date. */
+        * internal GUri might not be up-to-date. */
 
-       soup_uri_free (extension->priv->soup_uri);
-       extension->priv->soup_uri = soup_uri_copy (soup_uri);
+       g_uri_unref (extension->priv->uri);
+       extension->priv->uri = g_uri_ref (uri);
 
        e_source_extension_property_unlock (E_SOURCE_EXTENSION (extension));
 
        g_object_freeze_notify (G_OBJECT (extension));
-       source_webdav_update_properties_from_soup_uri (extension);
-       g_object_notify (G_OBJECT (extension), "soup-uri");
+       source_webdav_update_properties_from_uri (extension);
+       g_object_notify (G_OBJECT (extension), "uri");
        g_object_thaw_notify (G_OBJECT (extension));
 }
 
diff --git a/src/libedataserver/e-source-webdav.h b/src/libedataserver/e-source-webdav.h
index e72e553f4..e0a0aabdb 100644
--- a/src/libedataserver/e-source-webdav.h
+++ b/src/libedataserver/e-source-webdav.h
@@ -131,9 +131,9 @@ const gchar *       e_source_webdav_get_ssl_trust   (ESourceWebdav *extension);
 gchar *                e_source_webdav_dup_ssl_trust   (ESourceWebdav *extension);
 void           e_source_webdav_set_ssl_trust   (ESourceWebdav *extension,
                                                 const gchar *ssl_trust);
-SoupURI *      e_source_webdav_dup_soup_uri    (ESourceWebdav *extension);
-void           e_source_webdav_set_soup_uri    (ESourceWebdav *extension,
-                                                SoupURI *soup_uri);
+GUri *         e_source_webdav_dup_uri         (ESourceWebdav *extension);
+void           e_source_webdav_set_uri         (ESourceWebdav *extension,
+                                                GUri *uri);
 void           e_source_webdav_update_ssl_trust
                                                (ESourceWebdav *extension,
                                                 const gchar *host,
diff --git a/src/libedataserver/e-source.c b/src/libedataserver/e-source.c
index b2fb6102d..9490e420c 100644
--- a/src/libedataserver/e-source.c
+++ b/src/libedataserver/e-source.c
@@ -1053,7 +1053,7 @@ source_set_dbus_object (ESource *source,
        g_return_if_fail (E_DBUS_IS_OBJECT (dbus_object));
        g_return_if_fail (source->priv->dbus_object == NULL);
 
-       source->priv->dbus_object = g_object_ref (dbus_object);
+       source->priv->dbus_object = G_DBUS_OBJECT (g_object_ref (dbus_object));
 }
 
 static void
diff --git a/src/libedataserver/e-webdav-discover.c b/src/libedataserver/e-webdav-discover.c
index a824cdf2c..189467fda 100644
--- a/src/libedataserver/e-webdav-discover.c
+++ b/src/libedataserver/e-webdav-discover.c
@@ -157,7 +157,7 @@ e_webdav_discover_propfind_uri_sync (EWebDAVSession *webdav,
 static gboolean
 e_webdav_discover_traverse_propfind_response_cb (EWebDAVSession *webdav,
                                                 xmlNodePtr prop_node,
-                                                const SoupURI *request_uri,
+                                                const GUri *request_uri,
                                                 const gchar *href,
                                                 guint status_code,
                                                 gpointer user_data)
@@ -548,7 +548,7 @@ e_webdav_discover_setup_proxy_resolver (EWebDAVSession *webdav,
 
                proxy_resolver = G_PROXY_RESOLVER (source);
                if (g_proxy_resolver_is_supported (proxy_resolver))
-                       g_object_set (E_SOUP_SESSION (webdav), SOUP_SESSION_PROXY_RESOLVER, proxy_resolver, 
NULL);
+                       g_object_set (E_SOUP_SESSION (webdav), "proxy-resolver", proxy_resolver, NULL);
 
                g_object_unref (source);
        }
@@ -660,7 +660,7 @@ e_webdav_discover_sources_full (ESource *source,
  * error occurred, the function will set @error and return %FALSE. The function
  * can return success and no discovered sources, the same as it can return failure,
  * but still set some output arguments, like the certificate related output
- * arguments with SOUP_STATUS_SSL_FAILED error.
+ * arguments with G_TLS_ERROR_BAD_CERTIFICATE error.
  *
  * The return value of @out_certificate_pem should be freed with g_free()
  * when no longer needed.
@@ -726,8 +726,8 @@ e_webdav_discover_maybe_replace_auth_error (GError **target,
        g_return_val_if_fail (target != NULL, FALSE);
        g_return_val_if_fail (candidate != NULL, FALSE);
 
-       if (!g_error_matches (*target, SOUP_HTTP_ERROR, SOUP_STATUS_UNAUTHORIZED) &&
-           g_error_matches (*candidate, SOUP_HTTP_ERROR, SOUP_STATUS_UNAUTHORIZED)) {
+       if (!g_error_matches (*target, E_SOUP_SESSION_ERROR, SOUP_STATUS_UNAUTHORIZED) &&
+           g_error_matches (*candidate, E_SOUP_SESSION_ERROR, SOUP_STATUS_UNAUTHORIZED)) {
                g_clear_error (target);
                *target = *candidate;
                *candidate = NULL;
@@ -735,7 +735,7 @@ e_webdav_discover_maybe_replace_auth_error (GError **target,
                return TRUE;
        }
 
-       return g_error_matches (*target, SOUP_HTTP_ERROR, SOUP_STATUS_UNAUTHORIZED);
+       return g_error_matches (*target, E_SOUP_SESSION_ERROR, SOUP_STATUS_UNAUTHORIZED);
 }
 
 /**
@@ -766,7 +766,7 @@ e_webdav_discover_maybe_replace_auth_error (GError **target,
  * If an error occurred, the function will set @error and return %FALSE. The function
  * can return success and no discovered sources, the same as it can return failure,
  * but still set some output arguments, like the certificate related output
- * arguments with SOUP_STATUS_SSL_FAILED error.
+ * arguments with G_TLS_ERROR_BAD_CERTIFICATE error.
  *
  * The return value of @out_certificate_pem should be freed with g_free()
  * when no longer needed.
@@ -869,23 +869,23 @@ e_webdav_discover_sources_full_sync (ESource *source,
 {
        ESourceWebdav *webdav_extension;
        EWebDAVSession *webdav;
-       SoupURI *soup_uri;
+       GUri *guri;
        gboolean success;
 
        g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
 
        if (url_use_path && (g_ascii_strncasecmp (url_use_path, "http://";, 7) == 0 ||
            g_ascii_strncasecmp (url_use_path, "https://";, 8) == 0)) {
-               soup_uri = soup_uri_new (url_use_path);
+               guri = g_uri_parse (url_use_path, SOUP_HTTP_URI_FLAGS, NULL);
                url_use_path = NULL;
        } else {
                g_return_val_if_fail (e_source_has_extension (source, E_SOURCE_EXTENSION_WEBDAV_BACKEND), 
FALSE);
 
                webdav_extension = e_source_get_extension (source, E_SOURCE_EXTENSION_WEBDAV_BACKEND);
-               soup_uri = e_source_webdav_dup_soup_uri (webdav_extension);
+               guri = e_source_webdav_dup_uri (webdav_extension);
        }
 
-       g_return_val_if_fail (soup_uri != NULL, FALSE);
+       g_return_val_if_fail (guri != NULL, FALSE);
 
        if (url_use_path) {
                GString *new_path;
@@ -896,7 +896,7 @@ e_webdav_discover_sources_full_sync (ESource *source,
                } else {
                        const gchar *current_path;
 
-                       current_path = soup_uri_get_path (soup_uri);
+                       current_path = g_uri_get_path (guri);
                        new_path = g_string_new (current_path ? current_path : "");
                        if (!new_path->len || new_path->str[new_path->len - 1] != '/')
                                g_string_append_c (new_path, '/');
@@ -906,7 +906,7 @@ e_webdav_discover_sources_full_sync (ESource *source,
                if (!new_path->len || new_path->str[new_path->len - 1] != '/')
                        g_string_append_c (new_path, '/');
 
-               soup_uri_set_path (soup_uri, new_path->str);
+               e_util_change_uri_component (&guri, SOUP_URI_PATH, new_path->str);
 
                g_string_free (new_path, TRUE);
        }
@@ -914,7 +914,7 @@ e_webdav_discover_sources_full_sync (ESource *source,
        webdav = e_webdav_session_new (source);
 
        if (!e_webdav_discover_setup_proxy_resolver (webdav, source, ref_source_func, 
ref_source_func_user_data, cancellable, error)) {
-               soup_uri_free (soup_uri);
+               g_uri_unref (guri);
                g_object_unref (webdav);
 
                return FALSE;
@@ -937,7 +937,7 @@ e_webdav_discover_sources_full_sync (ESource *source,
                wdd.cancellable = cancellable;
                wdd.error = &local_error;
 
-               uri = soup_uri_to_string (soup_uri, FALSE);
+               uri = g_uri_to_string_partial (guri, G_URI_HIDE_PASSWORD);
 
                success = uri && *uri && e_webdav_discover_propfind_uri_sync (webdav, &wdd, uri, FALSE);
 
@@ -948,15 +948,15 @@ e_webdav_discover_sources_full_sync (ESource *source,
                if (!fatal_error && !g_cancellable_is_cancelled (cancellable) && !wdd.calendars &&
                    ((only_supports & (~CUSTOM_SUPPORTS_FLAGS)) == E_WEBDAV_DISCOVER_SUPPORTS_NONE ||
                    (only_supports & (E_WEBDAV_DISCOVER_SUPPORTS_EVENTS | E_WEBDAV_DISCOVER_SUPPORTS_MEMOS | 
E_WEBDAV_DISCOVER_SUPPORTS_TASKS)) != 0) &&
-                   (!soup_uri_get_path (soup_uri) || !strstr (soup_uri_get_path (soup_uri), 
"/.well-known/"))) {
+                   (!g_uri_get_path (guri) || !strstr (g_uri_get_path (guri), "/.well-known/"))) {
                        gchar *saved_path;
                        GError *local_error_2nd = NULL;
 
-                       saved_path = g_strdup (soup_uri_get_path (soup_uri));
+                       saved_path = g_strdup (g_uri_get_path (guri));
 
-                       soup_uri_set_path (soup_uri, "/.well-known/caldav");
+                       e_util_change_uri_component (&guri, SOUP_URI_PATH, "/.well-known/caldav");
 
-                       uri = soup_uri_to_string (soup_uri, FALSE);
+                       uri = g_uri_to_string_partial (guri, SOUP_HTTP_URI_FLAGS);
 
                        wdd.error = &local_error_2nd;
                        wdd.only_supports = E_WEBDAV_DISCOVER_SUPPORTS_EVENTS | 
E_WEBDAV_DISCOVER_SUPPORTS_MEMOS | E_WEBDAV_DISCOVER_SUPPORTS_TASKS;
@@ -968,7 +968,8 @@ e_webdav_discover_sources_full_sync (ESource *source,
 
                        fatal_error = e_webdav_discover_is_fatal_error (local_error_2nd);
 
-                       soup_uri_set_path (soup_uri, saved_path);
+                       e_util_change_uri_component (&guri, SOUP_URI_PATH, saved_path);
+
                        g_free (saved_path);
 
                        if (e_webdav_discover_maybe_replace_auth_error (&local_error, &local_error_2nd))
@@ -982,15 +983,15 @@ e_webdav_discover_sources_full_sync (ESource *source,
                if (!fatal_error && !g_cancellable_is_cancelled (cancellable) &&
                    ((only_supports & (~CUSTOM_SUPPORTS_FLAGS)) == E_WEBDAV_DISCOVER_SUPPORTS_NONE ||
                    (only_supports & (E_WEBDAV_DISCOVER_SUPPORTS_WEBDAV_NOTES)) != 0) &&
-                   (!soup_uri_get_path (soup_uri) || !strstr (soup_uri_get_path (soup_uri), 
"/.well-known/"))) {
+                   (!g_uri_get_path (guri) || !strstr (g_uri_get_path (guri), "/.well-known/"))) {
                        gchar *saved_path;
                        GError *local_error_2nd = NULL;
 
-                       saved_path = g_strdup (soup_uri_get_path (soup_uri));
+                       saved_path = g_strdup (g_uri_get_path (guri));
 
-                       soup_uri_set_path (soup_uri, "/.well-known/webdav/Notes/");
+                       e_util_change_uri_component (&guri, SOUP_URI_PATH, "/.well-known/webdav/Notes/");
 
-                       uri = soup_uri_to_string (soup_uri, FALSE);
+                       uri = g_uri_to_string_partial (guri, G_URI_HIDE_PASSWORD);
 
                        wdd.error = &local_error_2nd;
                        wdd.only_supports = E_WEBDAV_DISCOVER_SUPPORTS_WEBDAV_NOTES;
@@ -1002,7 +1003,8 @@ e_webdav_discover_sources_full_sync (ESource *source,
 
                        fatal_error = e_webdav_discover_is_fatal_error (local_error_2nd);
 
-                       soup_uri_set_path (soup_uri, saved_path);
+                       e_util_change_uri_component (&guri, SOUP_URI_PATH, saved_path);
+
                        g_free (saved_path);
 
                        if (e_webdav_discover_maybe_replace_auth_error (&local_error, &local_error_2nd))
@@ -1016,15 +1018,15 @@ e_webdav_discover_sources_full_sync (ESource *source,
                if (!fatal_error && !g_cancellable_is_cancelled (cancellable) && !wdd.addressbooks &&
                    ((only_supports & (~CUSTOM_SUPPORTS_FLAGS)) == E_WEBDAV_DISCOVER_SUPPORTS_NONE ||
                    (only_supports & (E_WEBDAV_DISCOVER_SUPPORTS_CONTACTS)) != 0) &&
-                   (!soup_uri_get_path (soup_uri) || !strstr (soup_uri_get_path (soup_uri), 
"/.well-known/"))) {
+                   (!g_uri_get_path (guri) || !strstr (g_uri_get_path (guri), "/.well-known/"))) {
                        gchar *saved_path;
                        GError *local_error_2nd = NULL;
 
-                       saved_path = g_strdup (soup_uri_get_path (soup_uri));
+                       saved_path = g_strdup (g_uri_get_path (guri));
 
-                       soup_uri_set_path (soup_uri, "/.well-known/carddav");
+                       e_util_change_uri_component (&guri, SOUP_URI_PATH, "/.well-known/carddav");
 
-                       uri = soup_uri_to_string (soup_uri, FALSE);
+                       uri = g_uri_to_string_partial (guri, SOUP_HTTP_URI_FLAGS);
 
                        wdd.error = &local_error_2nd;
                        wdd.only_supports = E_WEBDAV_DISCOVER_SUPPORTS_CONTACTS;
@@ -1034,7 +1036,8 @@ e_webdav_discover_sources_full_sync (ESource *source,
 
                        g_free (uri);
 
-                       soup_uri_set_path (soup_uri, saved_path);
+                       e_util_change_uri_component (&guri, SOUP_URI_PATH, saved_path);
+
                        g_free (saved_path);
 
                        fatal_error = e_webdav_discover_is_fatal_error (local_error_2nd);
@@ -1107,7 +1110,7 @@ e_webdav_discover_sources_full_sync (ESource *source,
        if (!success)
                e_soup_session_get_ssl_error_details (E_SOUP_SESSION (webdav), out_certificate_pem, 
out_certificate_errors);
 
-       soup_uri_free (soup_uri);
+       g_uri_unref (guri);
        g_object_unref (webdav);
 
        return success;
diff --git a/src/libedataserver/e-webdav-session.c b/src/libedataserver/e-webdav-session.c
index e9825a24f..785dc316f 100644
--- a/src/libedataserver/e-webdav-session.c
+++ b/src/libedataserver/e-webdav-session.c
@@ -692,27 +692,27 @@ e_webdav_session_get_last_dav_error_is_permission (EWebDAVSession *webdav)
 }
 
 /**
- * e_webdav_session_new_request:
+ * e_webdav_session_new_message:
  * @webdav: an #EWebDAVSession
  * @method: an HTTP method
  * @uri: (nullable): URI to create the request for, or %NULL to read from #ESource
  * @error: return location for a #GError, or %NULL
  *
- * Returns: (transfer full): A new #SoupRequestHTTP for the given @uri, or, when %NULL,
+ * Returns: (transfer full): A new #SoupMessage for the given @uri, or, when %NULL,
  *    for the URI stored in the associated #ESource. Free the returned structure
  *    with g_object_unref(), when no longer needed.
  *
  * Since: 3.26
  **/
-SoupRequestHTTP *
-e_webdav_session_new_request (EWebDAVSession *webdav,
+SoupMessage *
+e_webdav_session_new_message (EWebDAVSession *webdav,
                              const gchar *method,
                              const gchar *uri,
                              GError **error)
 {
        ESoupSession *session;
-       SoupRequestHTTP *request;
-       SoupURI *soup_uri;
+       SoupMessage *message;
+       GUri *guri;
        ESource *source;
        ESourceWebdav *webdav_extension;
        const gchar *path;
@@ -721,7 +721,7 @@ e_webdav_session_new_request (EWebDAVSession *webdav,
 
        session = E_SOUP_SESSION (webdav);
        if (uri && *uri)
-               return e_soup_session_new_request (session, method, uri, error);
+               return e_soup_session_new_message (session, method, uri, error);
 
        source = e_soup_session_get_source (session);
        g_return_val_if_fail (E_IS_SOURCE (source), NULL);
@@ -733,32 +733,32 @@ e_webdav_session_new_request (EWebDAVSession *webdav,
        }
 
        webdav_extension = e_source_get_extension (source, E_SOURCE_EXTENSION_WEBDAV_BACKEND);
-       soup_uri = e_source_webdav_dup_soup_uri (webdav_extension);
+       guri = e_source_webdav_dup_uri (webdav_extension);
 
-       g_return_val_if_fail (soup_uri != NULL, NULL);
+       g_return_val_if_fail (guri != NULL, NULL);
 
        /* The URI in the ESource should be to a collection, with an ending
           forward slash, thus ensure it's there. */
-       path = soup_uri_get_path (soup_uri);
+       path = g_uri_get_path (guri);
        if (!path || !*path || !g_str_has_suffix (path, "/")) {
                gchar *new_path;
 
                new_path = g_strconcat (path ? path : "", "/", NULL);
-               soup_uri_set_path (soup_uri, new_path);
+               e_util_change_uri_component (&guri, SOUP_URI_PATH, new_path);
                g_free (new_path);
        }
 
-       request = e_soup_session_new_request_uri (session, method, soup_uri, error);
+       message = e_soup_session_new_message_from_uri (session, method, guri, error);
 
-       soup_uri_free (soup_uri);
+       g_uri_unref (guri);
 
-       return request;
+       return message;
 }
 
 static gboolean
 e_webdav_session_extract_propstat_error_cb (EWebDAVSession *webdav,
                                            xmlNodePtr prop_node,
-                                           const SoupURI *request_uri,
+                                           const GUri *request_uri,
                                            const gchar *href,
                                            guint status_code,
                                            gpointer user_data)
@@ -790,7 +790,7 @@ e_webdav_session_extract_propstat_error_cb (EWebDAVSession *webdav,
                }
 
                g_clear_error (error);
-               g_set_error_literal (error, SOUP_HTTP_ERROR, status_code,
+               g_set_error_literal (error, E_SOUP_SESSION_ERROR, status_code,
                        e_soup_session_util_status_to_string (status_code, (const gchar *) description));
        }
 
@@ -864,7 +864,7 @@ e_webdav_session_extract_dav_error (EWebDAVSession *webdav,
 
 static gboolean
 e_webdav_session_replace_with_detailed_error_internal (EWebDAVSession *webdav,
-                                                      SoupRequestHTTP *request,
+                                                      SoupMessage *message,
                                                       const GByteArray *response_data,
                                                       gboolean ignore_multistatus,
                                                       const gchar *prefix,
@@ -872,7 +872,6 @@ e_webdav_session_replace_with_detailed_error_internal (EWebDAVSession *webdav,
                                                       gboolean can_change_last_dav_error_code,
                                                       gboolean skip_text_on_success)
 {
-       SoupMessage *message;
        GByteArray byte_array = { 0 };
        const gchar *content_type, *reason_phrase;
        gchar *detail_text = NULL;
@@ -882,23 +881,16 @@ e_webdav_session_replace_with_detailed_error_internal (EWebDAVSession *webdav,
        GError *local_error = NULL;
 
        g_return_val_if_fail (E_IS_WEBDAV_SESSION (webdav), FALSE);
-       g_return_val_if_fail (SOUP_IS_REQUEST_HTTP (request), FALSE);
+       g_return_val_if_fail (SOUP_IS_MESSAGE (message), FALSE);
 
-       message = soup_request_http_get_message (request);
-       if (!message)
-               return FALSE;
-
-       status_code = message->status_code;
-       reason_phrase = message->reason_phrase;
+       status_code = soup_message_get_status (message);
+       reason_phrase = soup_message_get_reason_phrase (message);
        byte_array.data = NULL;
        byte_array.len = 0;
 
        if (response_data && response_data->len) {
                byte_array.data = (gpointer) response_data->data;
                byte_array.len = response_data->len;
-       } else if (message->response_body && message->response_body->length) {
-               byte_array.data = (gpointer) message->response_body->data;
-               byte_array.len = message->response_body->length;
        }
 
        if (!byte_array.data || !byte_array.len)
@@ -916,12 +908,10 @@ e_webdav_session_replace_with_detailed_error_internal (EWebDAVSession *webdav,
                        g_prefix_error (&local_error, "%s: ", prefix);
                g_propagate_error (inout_error, local_error);
 
-               g_object_unref (message);
-
                return TRUE;
        }
 
-       content_type = soup_message_headers_get_content_type (message->response_headers, NULL);
+       content_type = soup_message_headers_get_content_type (soup_message_get_response_headers (message), 
NULL);
        if (content_type && (!skip_text_on_success || (status_code && !SOUP_STATUS_IS_SUCCESSFUL 
(status_code))) && (
            (g_ascii_strcasecmp (content_type, "application/xml") == 0 ||
             g_ascii_strcasecmp (content_type, "text/xml") == 0))) {
@@ -984,17 +974,12 @@ e_webdav_session_replace_with_detailed_error_internal (EWebDAVSession *webdav,
                detail_text = g_strndup ((const gchar *) byte_array.data, byte_array.len);
        } else if (content_type && (!skip_text_on_success || (status_code && !SOUP_STATUS_IS_SUCCESSFUL 
(status_code))) &&
             g_ascii_strcasecmp (content_type, "text/html") == 0) {
-               SoupURI *soup_uri;
+               GUri *g_uri;
                gchar *uri = NULL;
 
-               soup_uri = soup_message_get_uri (message);
-               if (soup_uri) {
-                       soup_uri = soup_uri_copy (soup_uri);
-                       soup_uri_set_password (soup_uri, NULL);
-
-                       uri = soup_uri_to_string (soup_uri, FALSE);
-
-                       soup_uri_free (soup_uri);
+               g_uri = soup_message_get_uri (message);
+               if (g_uri) {
+                       uri = g_uri_to_string_partial (g_uri, G_URI_HIDE_PASSWORD);
                }
 
                if (uri && *uri)
@@ -1015,7 +1000,7 @@ e_webdav_session_replace_with_detailed_error_internal (EWebDAVSession *webdav,
                g_clear_error (inout_error);
 
                if (prefix) {
-                       g_set_error (inout_error, SOUP_HTTP_ERROR, status_code,
+                       g_set_error (inout_error, E_SOUP_SESSION_ERROR, status_code,
                                /* Translators: The first '%s' is replaced with error prefix, as provided
                                   by the caller, which can be in a form: "Failed with something".
                                   The '%d' is replaced with actual HTTP status code.
@@ -1025,7 +1010,7 @@ e_webdav_session_replace_with_detailed_error_internal (EWebDAVSession *webdav,
                                e_soup_session_util_status_to_string (status_code, reason_phrase),
                                detail_text);
                } else {
-                       g_set_error (inout_error, SOUP_HTTP_ERROR, status_code,
+                       g_set_error (inout_error, E_SOUP_SESSION_ERROR, status_code,
                                /* Translators: The '%d' is replaced with actual HTTP status code.
                                   The '%s' is replaced with a reason phrase of the error (user readable 
text).
                                   The last '%s' is replaced with detailed error text, as returned by the 
server. */
@@ -1039,7 +1024,7 @@ e_webdav_session_replace_with_detailed_error_internal (EWebDAVSession *webdav,
                g_clear_error (inout_error);
 
                if (prefix) {
-                       g_set_error (inout_error, SOUP_HTTP_ERROR, status_code,
+                       g_set_error (inout_error, E_SOUP_SESSION_ERROR, status_code,
                                /* Translators: The first '%s' is replaced with error prefix, as provided
                                   by the caller, which can be in a form: "Failed with something".
                                   The '%d' is replaced with actual HTTP status code.
@@ -1047,7 +1032,7 @@ e_webdav_session_replace_with_detailed_error_internal (EWebDAVSession *webdav,
                                _("%s: HTTP error code %d (%s)"), prefix, status_code,
                                e_soup_session_util_status_to_string (status_code, reason_phrase));
                } else {
-                       g_set_error (inout_error, SOUP_HTTP_ERROR, status_code,
+                       g_set_error (inout_error, E_SOUP_SESSION_ERROR, status_code,
                                /* Translators: The '%d' is replaced with actual HTTP status code.
                                   The '%s' is replaced with a reason phrase of the error (user readable 
text). */
                                _("Failed with HTTP error code %d (%s)"), status_code,
@@ -1055,7 +1040,6 @@ e_webdav_session_replace_with_detailed_error_internal (EWebDAVSession *webdav,
                }
        }
 
-       g_object_unref (message);
        g_free (reason_phrase_copy);
        g_free (detail_text);
 
@@ -1065,14 +1049,14 @@ e_webdav_session_replace_with_detailed_error_internal (EWebDAVSession *webdav,
 /**
  * e_webdav_session_replace_with_detailed_error:
  * @webdav: an #EWebDAVSession
- * @request: a #SoupRequestHTTP
+ * @message: a #SoupMessage
  * @response_data: (nullable): received response data, or %NULL
  * @ignore_multistatus: whether to ignore multistatus responses
  * @prefix: (nullable): error message prefix, used when replacing, or %NULL
  * @inout_error: (inout) (nullable) (transfer full): a #GError variable to replace content to, or %NULL
  *
  * Tries to read detailed error information from @response_data,
- * if not provided, then from @request's response_body. If the detailed
+ * if not provided, then from @message's response_body. If the detailed
  * error cannot be found, then does nothing, otherwise frees the content
  * of @inout_error, if any, and then populates it with an error message
  * prefixed with @prefix.
@@ -1092,19 +1076,19 @@ e_webdav_session_replace_with_detailed_error_internal (EWebDAVSession *webdav,
  **/
 gboolean
 e_webdav_session_replace_with_detailed_error (EWebDAVSession *webdav,
-                                             SoupRequestHTTP *request,
+                                             SoupMessage *message,
                                              const GByteArray *response_data,
                                              gboolean ignore_multistatus,
                                              const gchar *prefix,
                                              GError **inout_error)
 {
-       return e_webdav_session_replace_with_detailed_error_internal (webdav, request, response_data, 
ignore_multistatus, prefix, inout_error, FALSE, FALSE);
+       return e_webdav_session_replace_with_detailed_error_internal (webdav, message, response_data, 
ignore_multistatus, prefix, inout_error, FALSE, FALSE);
 }
 
 /**
  * e_webdav_session_ensure_full_uri:
  * @webdav: an #EWebDAVSession
- * @request_uri: (nullable): a #SoupURI to which the @href belongs, or %NULL
+ * @request_uri: (nullable): a #GUri to which the @href belongs, or %NULL
  * @href: a possibly path-only href
  *
  * Converts possibly path-only @href into a full URI under the @request_uri.
@@ -1119,18 +1103,18 @@ e_webdav_session_replace_with_detailed_error (EWebDAVSession *webdav,
  **/
 gchar *
 e_webdav_session_ensure_full_uri (EWebDAVSession *webdav,
-                                 const SoupURI *request_uri,
+                                 const GUri *request_uri,
                                  const gchar *href)
 {
        g_return_val_if_fail (E_IS_WEBDAV_SESSION (webdav), NULL);
        g_return_val_if_fail (href != NULL, NULL);
 
        if (*href == '/' || !strstr (href, "://")) {
-               SoupURI *soup_uri;
+               GUri *guri;
                gchar *full_uri;
 
                if (request_uri) {
-                       soup_uri = soup_uri_copy ((SoupURI *) request_uri);
+                       guri = g_uri_ref ((GUri *) request_uri);
                } else {
                        ESource *source;
                        ESourceWebdav *webdav_extension;
@@ -1142,18 +1126,15 @@ e_webdav_session_ensure_full_uri (EWebDAVSession *webdav,
                                return g_strdup (href);
 
                        webdav_extension = e_source_get_extension (source, E_SOURCE_EXTENSION_WEBDAV_BACKEND);
-                       soup_uri = e_source_webdav_dup_soup_uri (webdav_extension);
+                       guri = e_source_webdav_dup_uri (webdav_extension);
                }
 
-               g_return_val_if_fail (soup_uri != NULL, NULL);
-
-               soup_uri_set_path (soup_uri, href);
-               soup_uri_set_user (soup_uri, NULL);
-               soup_uri_set_password (soup_uri, NULL);
+               g_return_val_if_fail (guri != NULL, NULL);
 
-               full_uri = soup_uri_to_string (soup_uri, FALSE);
+               e_util_change_uri_component (&guri, SOUP_URI_PATH, href);
+               full_uri = g_uri_to_string_partial (guri, G_URI_HIDE_PASSWORD | G_URI_HIDE_USERINFO);
 
-               soup_uri_free (soup_uri);
+               g_uri_unref (guri);
 
                return full_uri;
        }
@@ -1234,7 +1215,6 @@ e_webdav_session_options_sync (EWebDAVSession *webdav,
                               GCancellable *cancellable,
                               GError **error)
 {
-       SoupRequestHTTP *request;
        SoupMessage *message;
        GByteArray *bytes;
 
@@ -1247,50 +1227,73 @@ e_webdav_session_options_sync (EWebDAVSession *webdav,
 
        g_clear_pointer (&webdav->priv->last_dav_error_code, g_free);
 
-       request = e_webdav_session_new_request (webdav, SOUP_METHOD_OPTIONS, uri, error);
-       if (!request)
-               return FALSE;
+       message = e_webdav_session_new_message (webdav, SOUP_METHOD_OPTIONS, uri, error);
 
-       bytes = e_soup_session_send_request_simple_sync (E_SOUP_SESSION (webdav), request, cancellable, 
error);
+       bytes = e_soup_session_send_message_simple_sync (E_SOUP_SESSION (webdav), message, cancellable, 
error);
 
        if (!bytes) {
-               g_object_unref (request);
+               g_object_unref (message);
                return FALSE;
        }
 
-       message = soup_request_http_get_message (request);
-
        g_byte_array_free (bytes, TRUE);
-       g_object_unref (request);
 
        g_return_val_if_fail (message != NULL, FALSE);
 
-       *out_capabilities = e_webdav_session_comma_header_to_hashtable (message->response_headers, "DAV");
-       *out_allows = e_webdav_session_comma_header_to_hashtable (message->response_headers, "Allow");
+       *out_capabilities = e_webdav_session_comma_header_to_hashtable (soup_message_get_response_headers 
(message), "DAV");
+       *out_allows = e_webdav_session_comma_header_to_hashtable (soup_message_get_response_headers 
(message), "Allow");
 
        g_object_unref (message);
 
        return TRUE;
 }
 
+static void
+e_webdav_session_copy_request_headers (SoupMessage *message,
+                                      SoupMessageHeaders *headers)
+{
+       SoupMessageHeaders *request_headers;
+       SoupMessageHeadersIter iter;
+       const gchar *name, *value;
+
+       if (!headers)
+               return;
+
+       request_headers = soup_message_get_request_headers (message);
+
+       soup_message_headers_iter_init (&iter, headers);
+
+       while (soup_message_headers_iter_next (&iter, &name, &value)) {
+               soup_message_headers_replace (request_headers, name, value);
+       }
+}
+
 /**
- * e_webdav_session_post_with_content_type_sync:
+ * e_webdav_session_post_sync:
  * @webdav: an #EWebDAVSession
  * @uri: (nullable): URI to issue the request for, or %NULL to read from #ESource
  * @data: data to post to the server
  * @data_length: length of @data, or -1, when @data is NUL-terminated
  * @in_content_type: (nullable): a Content-Type of the @data, or %NULL, to use application/xml
- * @out_content_type: (nullable) (transfer full): return location for response Content-Type, or %NULL
- * @out_content: (nullable) (transfer full): return location for response content, or %NULL
+ * @in_headers: (optional): additional #SoupMessageHeaders to be added to the request, or %NULL
+ * @out_content_type: (out) (nullable) (transfer full): return location for response Content-Type, or %NULL
+ * @out_headers: (out) (optional) (transfer full): optional return location for response 
#SoupMessageHeaders, or %NULL
+ * @out_content: (out) (nullable) (transfer full): return location for response content, or %NULL
  * @cancellable: optional #GCancellable object, or %NULL
  * @error: return location for a #GError, or %NULL
  *
  * Issues POST request on the provided @uri, or, in case it's %NULL, on the URI
  * defined in associated #ESource.
  *
+ * The optional @in_headers can contain additional headers to be added to the request.
+ * These headers replace any existing in the request headers, without support for the list-values headers.
+ *
  * The optional @out_content_type can be used to get content type of the response.
  * Free it with g_free(), when no longer needed.
  *
+ * The optional @out_headers contains response headers. Free it with soup_message_headers_free(),
+ * when no longer needed.
+ *
  * The optional @out_content can be used to get actual result content. Free it
  * with g_byte_array_free(), when no longer needed.
  *
@@ -1299,17 +1302,18 @@ e_webdav_session_options_sync (EWebDAVSession *webdav,
  * Since: 3.32
  **/
 gboolean
-e_webdav_session_post_with_content_type_sync (EWebDAVSession *webdav,
-                                             const gchar *uri,
-                                             const gchar *data,
-                                             gsize data_length,
-                                             const gchar *in_content_type,
-                                             gchar **out_content_type,
-                                             GByteArray **out_content,
-                                             GCancellable *cancellable,
-                                             GError **error)
+e_webdav_session_post_sync (EWebDAVSession *webdav,
+                           const gchar *uri,
+                           const gchar *data,
+                           gsize data_length,
+                           const gchar *in_content_type,
+                           SoupMessageHeaders *in_headers,
+                           gchar **out_content_type,
+                           SoupMessageHeaders **out_headers,
+                           GByteArray **out_content,
+                           GCancellable *cancellable,
+                           GError **error)
 {
-       SoupRequestHTTP *request;
        SoupMessage *message;
        GByteArray *bytes;
        gboolean success;
@@ -1320,6 +1324,9 @@ e_webdav_session_post_with_content_type_sync (EWebDAVSession *webdav,
        if (out_content_type)
                *out_content_type = NULL;
 
+       if (out_headers)
+               *out_headers = NULL;
+
        if (out_content)
                *out_content = NULL;
 
@@ -1328,31 +1335,29 @@ e_webdav_session_post_with_content_type_sync (EWebDAVSession *webdav,
 
        g_clear_pointer (&webdav->priv->last_dav_error_code, g_free);
 
-       request = e_webdav_session_new_request (webdav, SOUP_METHOD_POST, uri, error);
-       if (!request)
+       message = e_webdav_session_new_message (webdav, SOUP_METHOD_POST, uri, error);
+       if (!message)
                return FALSE;
 
-       message = soup_request_http_get_message (request);
-       if (!message) {
-               g_warn_if_fail (message != NULL);
-               g_object_unref (request);
+       e_webdav_session_copy_request_headers (message, in_headers);
 
-               return FALSE;
-       }
+       e_soup_session_util_set_message_request_body_from_data (message, FALSE,
+               (in_content_type && *in_content_type) ? in_content_type : E_WEBDAV_CONTENT_TYPE_XML,
+               data, data_length, NULL);
 
-       soup_message_set_request (message, (in_content_type && *in_content_type) ? in_content_type : 
E_WEBDAV_CONTENT_TYPE_XML,
-               SOUP_MEMORY_COPY, data, data_length);
+       bytes = e_soup_session_send_message_simple_sync (E_SOUP_SESSION (webdav), message, cancellable, 
error);
 
-       bytes = e_soup_session_send_request_simple_sync (E_SOUP_SESSION (webdav), request, cancellable, 
error);
-
-       success = !e_webdav_session_replace_with_detailed_error_internal (webdav, request, bytes, TRUE, 
_("Failed to post data"), error, TRUE, FALSE) &&
+       success = !e_webdav_session_replace_with_detailed_error_internal (webdav, message, bytes, TRUE, 
_("Failed to post data"), error, TRUE, FALSE) &&
                bytes != NULL;
 
        if (success) {
                if (out_content_type) {
-                       *out_content_type = g_strdup (soup_message_headers_get_content_type 
(message->response_headers, NULL));
+                       *out_content_type = g_strdup (soup_message_headers_get_content_type 
(soup_message_get_response_headers (message), NULL));
                }
 
+               if (out_headers)
+                       *out_headers = g_boxed_copy (SOUP_TYPE_MESSAGE_HEADERS, 
soup_message_get_response_headers (message));
+
                if (out_content) {
                        *out_content = bytes;
                        bytes = NULL;
@@ -1362,53 +1367,10 @@ e_webdav_session_post_with_content_type_sync (EWebDAVSession *webdav,
        if (bytes)
                g_byte_array_free (bytes, TRUE);
        g_object_unref (message);
-       g_object_unref (request);
 
        return success;
 }
 
-/**
- * e_webdav_session_post_sync:
- * @webdav: an #EWebDAVSession
- * @uri: (nullable): URI to issue the request for, or %NULL to read from #ESource
- * @data: data to post to the server
- * @data_length: length of @data, or -1, when @data is NUL-terminated
- * @out_content_type: (nullable) (transfer full): return location for response Content-Type, or %NULL
- * @out_content: (nullable) (transfer full): return location for response content, or %NULL
- * @cancellable: optional #GCancellable object, or %NULL
- * @error: return location for a #GError, or %NULL
- *
- * Issues POST request on the provided @uri, or, in case it's %NULL, on the URI
- * defined in associated #ESource. The Content-Type of the @data is set to
- * application/xml. To POST the @data with a different Content-Type use
- * e_webdav_session_post_with_content_type_sync().
- *
- * The optional @out_content_type can be used to get content type of the response.
- * Free it with g_free(), when no longer needed.
- *
- * The optional @out_content can be used to get actual result content. Free it
- * with g_byte_array_free(), when no longer needed.
- *
- * Returns: Whether succeeded.
- *
- * Since: 3.26
- **/
-gboolean
-e_webdav_session_post_sync (EWebDAVSession *webdav,
-                           const gchar *uri,
-                           const gchar *data,
-                           gsize data_length,
-                           gchar **out_content_type,
-                           GByteArray **out_content,
-                           GCancellable *cancellable,
-                           GError **error)
-{
-       g_return_val_if_fail (E_IS_WEBDAV_SESSION (webdav), FALSE);
-       g_return_val_if_fail (data != NULL, FALSE);
-
-       return e_webdav_session_post_with_content_type_sync (webdav, uri, data, data_length, NULL, 
out_content_type, out_content, cancellable, error);
-}
-
 /**
  * e_webdav_session_propfind_sync:
  * @webdav: an #EWebDAVSession
@@ -1440,7 +1402,6 @@ e_webdav_session_propfind_sync (EWebDAVSession *webdav,
                                GCancellable *cancellable,
                                GError **error)
 {
-       SoupRequestHTTP *request;
        SoupMessage *message;
        GByteArray *bytes;
        gboolean success;
@@ -1453,19 +1414,11 @@ e_webdav_session_propfind_sync (EWebDAVSession *webdav,
 
        g_clear_pointer (&webdav->priv->last_dav_error_code, g_free);
 
-       request = e_webdav_session_new_request (webdav, SOUP_METHOD_PROPFIND, uri, error);
-       if (!request)
-               return FALSE;
-
-       message = soup_request_http_get_message (request);
-       if (!message) {
-               g_warn_if_fail (message != NULL);
-               g_object_unref (request);
-
+       message = e_webdav_session_new_message (webdav, SOUP_METHOD_PROPFIND, uri, error);
+       if (!message)
                return FALSE;
-       }
 
-       soup_message_headers_replace (message->request_headers, "Depth", depth);
+       soup_message_headers_replace (soup_message_get_request_headers (message), "Depth", depth);
 
        if (xml) {
                gchar *content;
@@ -1474,20 +1427,19 @@ e_webdav_session_propfind_sync (EWebDAVSession *webdav,
                content = e_xml_document_get_content (xml, &content_length);
                if (!content) {
                        g_object_unref (message);
-                       g_object_unref (request);
 
                        g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, _("Failed to get 
input XML content"));
 
                        return FALSE;
                }
 
-               soup_message_set_request (message, E_WEBDAV_CONTENT_TYPE_XML,
-                       SOUP_MEMORY_TAKE, content, content_length);
+               e_soup_session_util_set_message_request_body_from_data (message, FALSE, 
E_WEBDAV_CONTENT_TYPE_XML,
+                       content, content_length, g_free);
        }
 
-       bytes = e_soup_session_send_request_simple_sync (E_SOUP_SESSION (webdav), request, cancellable, 
error);
+       bytes = e_soup_session_send_message_simple_sync (E_SOUP_SESSION (webdav), message, cancellable, 
error);
 
-       success = !e_webdav_session_replace_with_detailed_error_internal (webdav, request, bytes, TRUE, 
_("Failed to get properties"), error, TRUE, FALSE) &&
+       success = !e_webdav_session_replace_with_detailed_error_internal (webdav, message, bytes, TRUE, 
_("Failed to get properties"), error, TRUE, FALSE) &&
                bytes != NULL;
 
        if (success)
@@ -1496,7 +1448,6 @@ e_webdav_session_propfind_sync (EWebDAVSession *webdav,
        if (bytes)
                g_byte_array_free (bytes, TRUE);
        g_object_unref (message);
-       g_object_unref (request);
 
        return success;
 }
@@ -1524,7 +1475,6 @@ e_webdav_session_proppatch_sync (EWebDAVSession *webdav,
                                 GCancellable *cancellable,
                                 GError **error)
 {
-       SoupRequestHTTP *request;
        SoupMessage *message;
        GByteArray *bytes;
        gchar *content;
@@ -1536,40 +1486,30 @@ e_webdav_session_proppatch_sync (EWebDAVSession *webdav,
 
        g_clear_pointer (&webdav->priv->last_dav_error_code, g_free);
 
-       request = e_webdav_session_new_request (webdav, SOUP_METHOD_PROPPATCH, uri, error);
-       if (!request)
+       message = e_webdav_session_new_message (webdav, SOUP_METHOD_PROPPATCH, uri, error);
+       if (!message)
                return FALSE;
 
-       message = soup_request_http_get_message (request);
-       if (!message) {
-               g_warn_if_fail (message != NULL);
-               g_object_unref (request);
-
-               return FALSE;
-       }
-
        content = e_xml_document_get_content (xml, &content_length);
        if (!content) {
                g_object_unref (message);
-               g_object_unref (request);
 
                g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, _("Failed to get input 
XML content"));
 
                return FALSE;
        }
 
-       soup_message_set_request (message, E_WEBDAV_CONTENT_TYPE_XML,
-               SOUP_MEMORY_TAKE, content, content_length);
+       e_soup_session_util_set_message_request_body_from_data (message, FALSE, E_WEBDAV_CONTENT_TYPE_XML,
+               content, content_length, g_free);
 
-       bytes = e_soup_session_send_request_simple_sync (E_SOUP_SESSION (webdav), request, cancellable, 
error);
+       bytes = e_soup_session_send_message_simple_sync (E_SOUP_SESSION (webdav), message, cancellable, 
error);
 
-       success = !e_webdav_session_replace_with_detailed_error_internal (webdav, request, bytes, FALSE, 
_("Failed to update properties"), error, TRUE, FALSE) &&
+       success = !e_webdav_session_replace_with_detailed_error_internal (webdav, message, bytes, FALSE, 
_("Failed to update properties"), error, TRUE, FALSE) &&
                bytes != NULL;
 
        if (bytes)
                g_byte_array_free (bytes, TRUE);
        g_object_unref (message);
-       g_object_unref (request);
 
        return success;
 }
@@ -1617,7 +1557,6 @@ e_webdav_session_report_sync (EWebDAVSession *webdav,
                              GCancellable *cancellable,
                              GError **error)
 {
-       SoupRequestHTTP *request;
        SoupMessage *message;
        GByteArray *bytes;
        gchar *content;
@@ -1635,45 +1574,36 @@ e_webdav_session_report_sync (EWebDAVSession *webdav,
 
        g_clear_pointer (&webdav->priv->last_dav_error_code, g_free);
 
-       request = e_webdav_session_new_request (webdav, "REPORT", uri, error);
-       if (!request)
-               return FALSE;
-
-       message = soup_request_http_get_message (request);
-       if (!message) {
-               g_warn_if_fail (message != NULL);
-               g_object_unref (request);
-
+       message = e_webdav_session_new_message (webdav, "REPORT", uri, error);
+       if (!message)
                return FALSE;
-       }
 
        if (depth)
-               soup_message_headers_replace (message->request_headers, "Depth", depth);
+               soup_message_headers_replace (soup_message_get_request_headers (message), "Depth", depth);
 
        content = e_xml_document_get_content (xml, &content_length);
        if (!content) {
                g_object_unref (message);
-               g_object_unref (request);
 
                g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, _("Failed to get input 
XML content"));
 
                return FALSE;
        }
 
-       soup_message_set_request (message, E_WEBDAV_CONTENT_TYPE_XML,
-               SOUP_MEMORY_TAKE, content, content_length);
+       e_soup_session_util_set_message_request_body_from_data (message, FALSE, E_WEBDAV_CONTENT_TYPE_XML,
+               content, content_length, g_free);
 
-       bytes = e_soup_session_send_request_simple_sync (E_SOUP_SESSION (webdav), request, cancellable, 
error);
+       bytes = e_soup_session_send_message_simple_sync (E_SOUP_SESSION (webdav), message, cancellable, 
error);
 
-       success = !e_webdav_session_replace_with_detailed_error_internal (webdav, request, bytes, TRUE, 
_("Failed to issue REPORT"), error, TRUE, FALSE) &&
+       success = !e_webdav_session_replace_with_detailed_error_internal (webdav, message, bytes, TRUE, 
_("Failed to issue REPORT"), error, TRUE, FALSE) &&
                bytes != NULL;
 
-       if (success && func && message->status_code == SOUP_STATUS_MULTI_STATUS)
+       if (success && func && soup_message_get_status (message) == SOUP_STATUS_MULTI_STATUS)
                success = e_webdav_session_traverse_multistatus_response (webdav, message, bytes, func, 
func_user_data, error);
 
        if (success) {
                if (out_content_type) {
-                       *out_content_type = g_strdup (soup_message_headers_get_content_type 
(message->response_headers, NULL));
+                       *out_content_type = g_strdup (soup_message_headers_get_content_type 
(soup_message_get_response_headers (message), NULL));
                }
 
                if (out_content) {
@@ -1685,7 +1615,6 @@ e_webdav_session_report_sync (EWebDAVSession *webdav,
        if (bytes)
                g_byte_array_free (bytes, TRUE);
        g_object_unref (message);
-       g_object_unref (request);
 
        return success;
 }
@@ -1711,7 +1640,7 @@ e_webdav_session_mkcol_sync (EWebDAVSession *webdav,
                             GCancellable *cancellable,
                             GError **error)
 {
-       SoupRequestHTTP *request;
+       SoupMessage *message;
        GByteArray *bytes;
        gboolean success;
 
@@ -1720,18 +1649,18 @@ e_webdav_session_mkcol_sync (EWebDAVSession *webdav,
 
        g_clear_pointer (&webdav->priv->last_dav_error_code, g_free);
 
-       request = e_webdav_session_new_request (webdav, SOUP_METHOD_MKCOL, uri, error);
-       if (!request)
+       message = e_webdav_session_new_message (webdav, SOUP_METHOD_MKCOL, uri, error);
+       if (!message)
                return FALSE;
 
-       bytes = e_soup_session_send_request_simple_sync (E_SOUP_SESSION (webdav), request, cancellable, 
error);
+       bytes = e_soup_session_send_message_simple_sync (E_SOUP_SESSION (webdav), message, cancellable, 
error);
 
-       success = !e_webdav_session_replace_with_detailed_error_internal (webdav, request, bytes, FALSE, 
_("Failed to create collection"), error, TRUE, FALSE) &&
+       success = !e_webdav_session_replace_with_detailed_error_internal (webdav, message, bytes, FALSE, 
_("Failed to create collection"), error, TRUE, FALSE) &&
                bytes != NULL;
 
        if (bytes)
                g_byte_array_free (bytes, TRUE);
-       g_object_unref (request);
+       g_object_unref (message);
 
        return success;
 }
@@ -1763,7 +1692,6 @@ e_webdav_session_mkcol_addressbook_sync (EWebDAVSession *webdav,
                                         GCancellable *cancellable,
                                         GError **error)
 {
-       SoupRequestHTTP *request;
        SoupMessage *message;
        EXmlDocument *xml;
        gchar *content;
@@ -1776,17 +1704,9 @@ e_webdav_session_mkcol_addressbook_sync (EWebDAVSession *webdav,
 
        g_clear_pointer (&webdav->priv->last_dav_error_code, g_free);
 
-       request = e_webdav_session_new_request (webdav, SOUP_METHOD_MKCOL, uri, error);
-       if (!request)
-               return FALSE;
-
-       message = soup_request_http_get_message (request);
-       if (!message) {
-               g_warn_if_fail (message != NULL);
-               g_object_unref (request);
-
+       message = e_webdav_session_new_message (webdav, SOUP_METHOD_MKCOL, uri, error);
+       if (!message)
                return FALSE;
-       }
 
        xml = e_xml_document_new (E_WEBDAV_NS_DAV, "mkcol");
        e_xml_document_add_namespaces (xml, "A", E_WEBDAV_NS_CARDDAV, NULL);
@@ -1816,7 +1736,6 @@ e_webdav_session_mkcol_addressbook_sync (EWebDAVSession *webdav,
        content = e_xml_document_get_content (xml, &content_length);
        if (!content) {
                g_object_unref (message);
-               g_object_unref (request);
                g_object_unref (xml);
 
                g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, _("Failed to get XML 
request content"));
@@ -1824,20 +1743,19 @@ e_webdav_session_mkcol_addressbook_sync (EWebDAVSession *webdav,
                return FALSE;
        }
 
-       soup_message_set_request (message, E_WEBDAV_CONTENT_TYPE_XML,
-               SOUP_MEMORY_TAKE, content, content_length);
+       e_soup_session_util_set_message_request_body_from_data (message, FALSE, E_WEBDAV_CONTENT_TYPE_XML,
+               content, content_length, g_free);
 
        g_object_unref (xml);
 
-       bytes = e_soup_session_send_request_simple_sync (E_SOUP_SESSION (webdav), request, cancellable, 
error);
+       bytes = e_soup_session_send_message_simple_sync (E_SOUP_SESSION (webdav), message, cancellable, 
error);
 
-       success = !e_webdav_session_replace_with_detailed_error_internal (webdav, request, bytes, FALSE, 
_("Failed to create address book"), error, TRUE, FALSE) &&
+       success = !e_webdav_session_replace_with_detailed_error_internal (webdav, message, bytes, FALSE, 
_("Failed to create address book"), error, TRUE, FALSE) &&
                bytes != NULL;
 
        if (bytes)
                g_byte_array_free (bytes, TRUE);
        g_object_unref (message);
-       g_object_unref (request);
 
        return success;
 }
@@ -1877,7 +1795,6 @@ e_webdav_session_mkcalendar_sync (EWebDAVSession *webdav,
                                  GCancellable *cancellable,
                                  GError **error)
 {
-       SoupRequestHTTP *request;
        SoupMessage *message;
        GByteArray *bytes;
        gboolean success;
@@ -1887,17 +1804,9 @@ e_webdav_session_mkcalendar_sync (EWebDAVSession *webdav,
 
        g_clear_pointer (&webdav->priv->last_dav_error_code, g_free);
 
-       request = e_webdav_session_new_request (webdav, "MKCALENDAR", uri, error);
-       if (!request)
-               return FALSE;
-
-       message = soup_request_http_get_message (request);
-       if (!message) {
-               g_warn_if_fail (message != NULL);
-               g_object_unref (request);
-
+       message = e_webdav_session_new_message (webdav, "MKCALENDAR", uri, error);
+       if (!message)
                return FALSE;
-       }
 
        supports = supports & (
                E_WEBDAV_RESOURCE_SUPPORTS_EVENTS |
@@ -1977,7 +1886,6 @@ e_webdav_session_mkcalendar_sync (EWebDAVSession *webdav,
                content = e_xml_document_get_content (xml, &content_length);
                if (!content) {
                        g_object_unref (message);
-                       g_object_unref (request);
                        g_object_unref (xml);
 
                        g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, _("Failed to get 
XML request content"));
@@ -1985,21 +1893,20 @@ e_webdav_session_mkcalendar_sync (EWebDAVSession *webdav,
                        return FALSE;
                }
 
-               soup_message_set_request (message, E_WEBDAV_CONTENT_TYPE_XML,
-                       SOUP_MEMORY_TAKE, content, content_length);
+               e_soup_session_util_set_message_request_body_from_data (message, FALSE, 
E_WEBDAV_CONTENT_TYPE_XML,
+                       content, content_length, g_free);
 
                g_object_unref (xml);
        }
 
-       bytes = e_soup_session_send_request_simple_sync (E_SOUP_SESSION (webdav), request, cancellable, 
error);
+       bytes = e_soup_session_send_message_simple_sync (E_SOUP_SESSION (webdav), message, cancellable, 
error);
 
-       success = !e_webdav_session_replace_with_detailed_error_internal (webdav, request, bytes, FALSE, 
_("Failed to create calendar"), error, TRUE, FALSE) &&
+       success = !e_webdav_session_replace_with_detailed_error_internal (webdav, message, bytes, FALSE, 
_("Failed to create calendar"), error, TRUE, FALSE) &&
                bytes != NULL;
 
        if (bytes)
                g_byte_array_free (bytes, TRUE);
        g_object_unref (message);
-       g_object_unref (request);
 
        return success;
 }
@@ -2016,20 +1923,21 @@ e_webdav_session_extract_href_and_etag (SoupMessage *message,
 
                *out_href = NULL;
 
-               header = soup_message_headers_get_list (message->response_headers, "Location");
+               header = soup_message_headers_get_one (soup_message_get_response_headers (message), 
"Location");
                if (header) {
-                       SoupURI *uri;
+                       GUri *uri;
+
+                       uri = g_uri_parse_relative (soup_message_get_uri (message), header, 
SOUP_HTTP_URI_FLAGS, NULL);
 
-                       uri = soup_uri_new_with_base (soup_message_get_uri (message), header);
-                       if (uri && uri->host)
-                               *out_href = soup_uri_to_string (uri, FALSE);
+                       if (uri && g_uri_get_host (uri))
+                               *out_href = g_uri_to_string_partial (uri, G_URI_HIDE_PASSWORD);
 
                        if (uri)
-                               soup_uri_free (uri);
+                               g_uri_unref (uri);
                }
 
                if (!*out_href)
-                       *out_href = soup_uri_to_string (soup_message_get_uri (message), FALSE);
+                       *out_href = g_uri_to_string_partial (soup_message_get_uri (message), 
G_URI_HIDE_PASSWORD);
        }
 
        if (out_etag) {
@@ -2037,7 +1945,7 @@ e_webdav_session_extract_href_and_etag (SoupMessage *message,
 
                *out_etag = NULL;
 
-               header = soup_message_headers_get_list (message->response_headers, "ETag");
+               header = soup_message_headers_get_list (soup_message_get_response_headers (message), "ETag");
                if (header)
                        *out_etag = e_webdav_session_util_maybe_dequote (g_strdup (header));
        }
@@ -2049,6 +1957,7 @@ e_webdav_session_extract_href_and_etag (SoupMessage *message,
  * @uri: URI of the resource to read
  * @out_href: (out) (nullable) (transfer full): optional return location for href of the resource, or %NULL
  * @out_etag: (out) (nullable) (transfer full): optional return location for etag of the resource, or %NULL
+ * @out_headers: (out) (optional) (transfer full): optional return location for response 
#SoupMessageHeaders, or %NULL
  * @out_stream: (out caller-allocates): a #GOutputStream to write data to
  * @cancellable: optional #GCancellable object, or %NULL
  * @error: return location for a #GError, or %NULL
@@ -2059,6 +1968,9 @@ e_webdav_session_extract_href_and_etag (SoupMessage *message,
  * Free returned pointer of @out_href and @out_etag, if not %NULL, with g_free(),
  * when no longer needed.
  *
+ * The optional @out_headers contains response headers. Free it with soup_message_headers_free(),
+ * when no longer needed.
+ *
  * The e_webdav_session_get_data_sync() can be used to read the resource data
  * directly to memory.
  *
@@ -2071,11 +1983,11 @@ e_webdav_session_get_sync (EWebDAVSession *webdav,
                           const gchar *uri,
                           gchar **out_href,
                           gchar **out_etag,
+                          SoupMessageHeaders **out_headers,
                           GOutputStream *out_stream,
                           GCancellable *cancellable,
                           GError **error)
 {
-       SoupRequestHTTP *request;
        SoupMessage *message;
        GInputStream *input_stream;
        gboolean success;
@@ -2086,19 +1998,14 @@ e_webdav_session_get_sync (EWebDAVSession *webdav,
 
        g_clear_pointer (&webdav->priv->last_dav_error_code, g_free);
 
-       request = e_webdav_session_new_request (webdav, SOUP_METHOD_GET, uri, error);
-       if (!request)
-               return FALSE;
-
-       message = soup_request_http_get_message (request);
-       if (!message) {
-               g_warn_if_fail (message != NULL);
-               g_object_unref (request);
+       if (out_headers)
+               *out_headers = NULL;
 
+       message = e_webdav_session_new_message (webdav, SOUP_METHOD_GET, uri, error);
+       if (!message)
                return FALSE;
-       }
 
-       input_stream = e_soup_session_send_request_sync (E_SOUP_SESSION (webdav), request, cancellable, 
error);
+       input_stream = e_soup_session_send_message_sync (E_SOUP_SESSION (webdav), message, cancellable, 
error);
 
        success = input_stream != NULL;
 
@@ -2119,7 +2026,7 @@ e_webdav_session_get_sync (EWebDAVSession *webdav,
                                tmp_bytes.data = buffer;
                                tmp_bytes.len = nread;
 
-                               success = !e_webdav_session_replace_with_detailed_error_internal (webdav, 
request, &tmp_bytes, FALSE, _("Failed to read resource"), error, TRUE, TRUE);
+                               success = !e_webdav_session_replace_with_detailed_error_internal (webdav, 
message, &tmp_bytes, FALSE, _("Failed to read resource"), error, TRUE, TRUE);
                                if (!success)
                                        break;
                        }
@@ -2130,18 +2037,21 @@ e_webdav_session_get_sync (EWebDAVSession *webdav,
                }
 
                if (success && first_chunk) {
-                       success = !e_webdav_session_replace_with_detailed_error_internal (webdav, request, 
NULL, FALSE, _("Failed to read resource"), error, TRUE, TRUE);
+                       success = !e_webdav_session_replace_with_detailed_error_internal (webdav, message, 
NULL, FALSE, _("Failed to read resource"), error, TRUE, TRUE);
                }
 
                g_free (buffer);
        }
 
-       if (success)
+       if (success) {
                e_webdav_session_extract_href_and_etag (message, out_href, out_etag);
 
+               if (out_headers)
+                       *out_headers = g_boxed_copy (SOUP_TYPE_MESSAGE_HEADERS, 
soup_message_get_response_headers (message));
+       }
+
        g_clear_object (&input_stream);
        g_object_unref (message);
-       g_object_unref (request);
 
        return success;
 }
@@ -2152,6 +2062,7 @@ e_webdav_session_get_sync (EWebDAVSession *webdav,
  * @uri: URI of the resource to read
  * @out_href: (out) (nullable) (transfer full): optional return location for href of the resource, or %NULL
  * @out_etag: (out) (nullable) (transfer full): optional return location for etag of the resource, or %NULL
+ * @out_headers: (out) (optional) (transfer full): optional return location for response 
#SoupMessageHeaders, or %NULL
  * @out_bytes: (out) (transfer full): return location for bytes being read
  * @out_length: (out) (nullable): option return location for length of bytes being read, or %NULL
  * @cancellable: optional #GCancellable object, or %NULL
@@ -2168,6 +2079,9 @@ e_webdav_session_get_sync (EWebDAVSession *webdav,
  * Free returned pointer of @out_href and @out_etag, if not %NULL, with g_free(),
  * when no longer needed.
  *
+ * The optional @out_headers contains response headers. Free it with soup_message_headers_free(),
+ * when no longer needed.
+ *
  * To read large data use e_webdav_session_get_sync() instead.
  *
  * Returns: Whether succeeded.
@@ -2179,6 +2093,7 @@ e_webdav_session_get_data_sync (EWebDAVSession *webdav,
                                const gchar *uri,
                                gchar **out_href,
                                gchar **out_etag,
+                               SoupMessageHeaders **out_headers,
                                gchar **out_bytes,
                                gsize *out_length,
                                GCancellable *cancellable,
@@ -2193,12 +2108,16 @@ e_webdav_session_get_data_sync (EWebDAVSession *webdav,
        g_return_val_if_fail (out_bytes != NULL, FALSE);
 
        *out_bytes = NULL;
+
        if (out_length)
                *out_length = 0;
 
+       if (out_headers)
+               *out_headers = NULL;
+
        output_stream = g_memory_output_stream_new_resizable ();
 
-       success = e_webdav_session_get_sync (webdav, uri, out_href, out_etag, output_stream, cancellable, 
error) &&
+       success = e_webdav_session_get_sync (webdav, uri, out_href, out_etag, out_headers, output_stream, 
cancellable, error) &&
                g_output_stream_write_all (output_stream, "", 1, &bytes_written, cancellable, error) &&
                g_output_stream_close (output_stream, cancellable, error);
 
@@ -2214,71 +2133,6 @@ e_webdav_session_get_data_sync (EWebDAVSession *webdav,
        return success;
 }
 
-typedef struct _ChunkWriteData {
-       SoupSession *session;
-       GInputStream *stream;
-       goffset read_from;
-       gboolean wrote_any;
-       gsize buffer_size;
-       gpointer buffer;
-       GCancellable *cancellable;
-       GError *error;
-} ChunkWriteData;
-
-static void
-e_webdav_session_write_next_chunk (SoupMessage *message,
-                                  gpointer user_data)
-{
-       ChunkWriteData *cwd = user_data;
-       gsize nread;
-
-       g_return_if_fail (SOUP_IS_MESSAGE (message));
-       g_return_if_fail (cwd != NULL);
-
-       if (!g_input_stream_read_all (cwd->stream, cwd->buffer, cwd->buffer_size, &nread, cwd->cancellable, 
&cwd->error)) {
-               soup_session_cancel_message (cwd->session, message, SOUP_STATUS_CANCELLED);
-               return;
-       }
-
-       if (nread == 0) {
-               soup_message_body_complete (message->request_body);
-       } else {
-               cwd->wrote_any = TRUE;
-               soup_message_body_append (message->request_body, SOUP_MEMORY_TEMPORARY, cwd->buffer, nread);
-       }
-}
-
-static void
-e_webdav_session_write_restarted (SoupMessage *message,
-                                 gpointer user_data)
-{
-       ChunkWriteData *cwd = user_data;
-
-       g_return_if_fail (SOUP_IS_MESSAGE (message));
-       g_return_if_fail (cwd != NULL);
-
-       /* The 302 redirect will turn it into a GET request and
-        * reset the body encoding back to "NONE". Fix that.
-        */
-       soup_message_headers_set_encoding (message->request_headers, SOUP_ENCODING_CHUNKED);
-       message->method = SOUP_METHOD_PUT;
-
-       if (cwd->wrote_any) {
-               cwd->wrote_any = FALSE;
-
-               if (!G_IS_SEEKABLE (cwd->stream) || !g_seekable_can_seek (G_SEEKABLE (cwd->stream)) ||
-                   !g_seekable_seek (G_SEEKABLE (cwd->stream), cwd->read_from, G_SEEK_SET, cwd->cancellable, 
&cwd->error)) {
-                       if (!cwd->error)
-                               g_set_error_literal (&cwd->error, G_IO_ERROR, G_IO_ERROR_PARTIAL_INPUT,
-                                       _("Cannot rewind input stream: Not supported"));
-
-                       soup_session_cancel_message (cwd->session, message, SOUP_STATUS_CANCELLED);
-               } else {
-                       soup_message_body_truncate (message->request_body);
-               }
-       }
-}
-
 static void
 e_webdav_session_set_if_match_header (SoupMessage *message,
                                      const gchar *etag)
@@ -2291,12 +2145,12 @@ e_webdav_session_set_if_match_header (SoupMessage *message,
        len = strlen (etag);
 
        if ((*etag == '\"' && len > 2 && etag[len - 1] == '\"') || strchr (etag, '\"')) {
-               soup_message_headers_replace (message->request_headers, "If-Match", etag);
+               soup_message_headers_replace (soup_message_get_request_headers (message), "If-Match", etag);
        } else {
                gchar *quoted;
 
                quoted = g_strconcat ("\"", etag, "\"", NULL);
-               soup_message_headers_replace (message->request_headers, "If-Match", quoted);
+               soup_message_headers_replace (soup_message_get_request_headers (message), "If-Match", quoted);
                g_free (quoted);
        }
 }
@@ -2307,9 +2161,12 @@ e_webdav_session_set_if_match_header (SoupMessage *message,
  * @uri: URI of the resource to write
  * @etag: (nullable): an ETag of the resource, if it's an existing resource, or %NULL
  * @content_type: Content-Type of the @bytes to be written
+ * @in_headers: (optional): additional #SoupMessageHeaders to be added to the request, or %NULL
  * @stream: a #GInputStream with data to be written
+ * @stream_length: length of the @stream, or -1 if unknown
  * @out_href: (out) (nullable) (transfer full): optional return location for href of the resource, or %NULL
  * @out_etag: (out) (nullable) (transfer full): optional return location for etag of the resource, or %NULL
+ * @out_headers: (out) (optional) (transfer full): optional return location for response 
#SoupMessageHeaders, or %NULL
  * @cancellable: optional #GCancellable object, or %NULL
  * @error: return location for a #GError, or %NULL
  *
@@ -2325,12 +2182,18 @@ e_webdav_session_set_if_match_header (SoupMessage *message,
  * Note that the actual behaviour is also influenced by #ESourceWebdav:avoid-ifmatch
  * property of the associated #ESource.
  *
+ * The optional @in_headers can contain additional headers to be added to the request.
+ * These headers replace any existing in the request headers, without support for the list-values headers.
+ *
  * The @out_href, if provided, is filled with the resulting URI
  * of the written resource. It can be different from the @uri when the server
  * redirected to a different location.
  *
  * The @out_etag contains ETag of the resource after it had been saved.
  *
+ * The optional @out_headers contains response headers. Free it with soup_message_headers_free(),
+ * when no longer needed.
+ *
  * The @stream should support also #GSeekable interface, because the data
  * send can require restart of the send due to redirect or other reasons.
  *
@@ -2347,17 +2210,17 @@ e_webdav_session_put_sync (EWebDAVSession *webdav,
                           const gchar *uri,
                           const gchar *etag,
                           const gchar *content_type,
+                          SoupMessageHeaders *in_headers,
                           GInputStream *stream,
+                          gssize stream_length,
                           gchar **out_href,
                           gchar **out_etag,
+                          SoupMessageHeaders **out_headers,
                           GCancellable *cancellable,
                           GError **error)
 {
-       ChunkWriteData cwd;
-       SoupRequestHTTP *request;
        SoupMessage *message;
        GByteArray *bytes;
-       gulong restarted_id, wrote_headers_id, wrote_chunk_id;
        gboolean success;
 
        g_return_val_if_fail (E_IS_WEBDAV_SESSION (webdav), FALSE);
@@ -2369,20 +2232,16 @@ e_webdav_session_put_sync (EWebDAVSession *webdav,
                *out_href = NULL;
        if (out_etag)
                *out_etag = NULL;
+       if (out_headers)
+               *out_headers = NULL;
 
        g_clear_pointer (&webdav->priv->last_dav_error_code, g_free);
 
-       request = e_webdav_session_new_request (webdav, SOUP_METHOD_PUT, uri, error);
-       if (!request)
+       message = e_webdav_session_new_message (webdav, SOUP_METHOD_PUT, uri, error);
+       if (!message)
                return FALSE;
 
-       message = soup_request_http_get_message (request);
-       if (!message) {
-               g_warn_if_fail (message != NULL);
-               g_object_unref (request);
-
-               return FALSE;
-       }
+       e_webdav_session_copy_request_headers (message, in_headers);
 
        if (!etag || *etag) {
                ESource *source;
@@ -2400,67 +2259,43 @@ e_webdav_session_put_sync (EWebDAVSession *webdav,
                        if (etag) {
                                e_webdav_session_set_if_match_header (message, etag);
                        } else {
-                               soup_message_headers_replace (message->request_headers, "If-None-Match", "*");
+                               soup_message_headers_replace (soup_message_get_request_headers (message), 
"If-None-Match", "*");
                        }
                }
        }
 
-       cwd.session = SOUP_SESSION (webdav);
-       cwd.stream = stream;
-       cwd.read_from = 0;
-       cwd.wrote_any = FALSE;
-       cwd.buffer_size = BUFFER_SIZE;
-       cwd.buffer = g_malloc (cwd.buffer_size);
-       cwd.cancellable = cancellable;
-       cwd.error = NULL;
-
-       if (G_IS_SEEKABLE (stream) && g_seekable_can_seek (G_SEEKABLE (stream)))
-               cwd.read_from = g_seekable_tell (G_SEEKABLE (stream));
+       e_soup_session_util_set_message_request_body (message, NULL, stream, stream_length);
 
        if (content_type && *content_type)
-               soup_message_headers_replace (message->request_headers, "Content-Type", content_type);
-
-       soup_message_headers_set_encoding (message->request_headers, SOUP_ENCODING_CHUNKED);
-       soup_message_body_set_accumulate (message->request_body, FALSE);
-       soup_message_set_flags (message, SOUP_MESSAGE_CAN_REBUILD);
-
-       restarted_id = g_signal_connect (message, "restarted", G_CALLBACK (e_webdav_session_write_restarted), 
&cwd);
-       wrote_headers_id = g_signal_connect (message, "wrote-headers", G_CALLBACK 
(e_webdav_session_write_next_chunk), &cwd);
-       wrote_chunk_id = g_signal_connect (message, "wrote-chunk", G_CALLBACK 
(e_webdav_session_write_next_chunk), &cwd);
+               soup_message_headers_replace (soup_message_get_request_headers (message), "Content-Type", 
content_type);
 
-       bytes = e_soup_session_send_request_simple_sync (E_SOUP_SESSION (webdav), request, cancellable, 
error);
+       soup_message_headers_set_encoding (soup_message_get_request_headers (message), SOUP_ENCODING_CHUNKED);
 
-       g_signal_handler_disconnect (message, restarted_id);
-       g_signal_handler_disconnect (message, wrote_headers_id);
-       g_signal_handler_disconnect (message, wrote_chunk_id);
+       bytes = e_soup_session_send_message_simple_sync (E_SOUP_SESSION (webdav), message, cancellable, 
error);
 
-       success = !e_webdav_session_replace_with_detailed_error_internal (webdav, request, bytes, FALSE, 
_("Failed to put data"), error, TRUE, TRUE) &&
+       success = !e_webdav_session_replace_with_detailed_error_internal (webdav, message, bytes, FALSE, 
_("Failed to put data"), error, TRUE, TRUE) &&
                bytes != NULL;
 
-       if (cwd.error) {
-               g_clear_error (error);
-               g_propagate_error (error, cwd.error);
-               success = FALSE;
-       }
-
        if (success) {
-               if (success && !SOUP_STATUS_IS_SUCCESSFUL (message->status_code)) {
+               if (success && !SOUP_STATUS_IS_SUCCESSFUL (soup_message_get_status (message))) {
                        success = FALSE;
 
-                       g_set_error (error, SOUP_HTTP_ERROR, message->status_code,
-                               _("Failed to put data to server, error code %d (%s)"), message->status_code,
-                               e_soup_session_util_status_to_string (message->status_code, 
message->reason_phrase));
+                       g_set_error (error, E_SOUP_SESSION_ERROR, soup_message_get_status (message),
+                               _("Failed to put data to server, error code %d (%s)"), 
soup_message_get_status (message),
+                               e_soup_session_util_status_to_string (soup_message_get_status (message), 
soup_message_get_reason_phrase (message)));
                }
        }
 
-       if (success)
+       if (success) {
                e_webdav_session_extract_href_and_etag (message, out_href, out_etag);
 
+               if (out_headers)
+                       *out_headers = g_boxed_copy (SOUP_TYPE_MESSAGE_HEADERS, 
soup_message_get_response_headers (message));
+       }
+
        if (bytes)
                g_byte_array_free (bytes, TRUE);
        g_object_unref (message);
-       g_object_unref (request);
-       g_free (cwd.buffer);
 
        return success;
 }
@@ -2471,10 +2306,12 @@ e_webdav_session_put_sync (EWebDAVSession *webdav,
  * @uri: URI of the resource to write
  * @etag: (nullable): an ETag of the resource, if it's an existing resource, or %NULL
  * @content_type: Content-Type of the @bytes to be written
+ * @in_headers: (optional): additional #SoupMessageHeaders to be added to the request, or %NULL
  * @bytes: actual bytes to be written
  * @length: how many bytes to write, or -1, when the @bytes is NUL-terminated
  * @out_href: (out) (nullable) (transfer full): optional return location for href of the resource, or %NULL
  * @out_etag: (out) (nullable) (transfer full): optional return location for etag of the resource, or %NULL
+ * @out_headers: (out) (optional) (transfer full): optional return location for response 
#SoupMessageHeaders, or %NULL
  * @cancellable: optional #GCancellable object, or %NULL
  * @error: return location for a #GError, or %NULL
  *
@@ -2490,12 +2327,18 @@ e_webdav_session_put_sync (EWebDAVSession *webdav,
  * Note that the actual usage of @etag is also influenced by #ESourceWebdav:avoid-ifmatch
  * property of the associated #ESource.
  *
+ * The optional @in_headers can contain additional headers to be added to the request.
+ * These headers replace any existing in the request headers, without support for the list-values headers.
+ *
  * The @out_href, if provided, is filled with the resulting URI
  * of the written resource. It can be different from the @uri when the server
  * redirected to a different location.
  *
  * The @out_etag contains ETag of the resource after it had been saved.
  *
+ * The optional @out_headers contains response headers. Free it with soup_message_headers_free(),
+ * when no longer needed.
+ *
  * To write large data use e_webdav_session_put_sync() instead.
  *
  * Returns: Whether succeeded.
@@ -2507,14 +2350,15 @@ e_webdav_session_put_data_sync (EWebDAVSession *webdav,
                                const gchar *uri,
                                const gchar *etag,
                                const gchar *content_type,
+                               SoupMessageHeaders *in_headers,
                                const gchar *bytes,
                                gsize length,
                                gchar **out_href,
                                gchar **out_etag,
+                               SoupMessageHeaders **out_headers,
                                GCancellable *cancellable,
                                GError **error)
 {
-       SoupRequestHTTP *request;
        SoupMessage *message;
        GByteArray *ret_bytes;
        gboolean success;
@@ -2530,20 +2374,16 @@ e_webdav_session_put_data_sync (EWebDAVSession *webdav,
                *out_href = NULL;
        if (out_etag)
                *out_etag = NULL;
+       if (out_headers)
+               *out_headers = NULL;
 
        g_clear_pointer (&webdav->priv->last_dav_error_code, g_free);
 
-       request = e_webdav_session_new_request (webdav, SOUP_METHOD_PUT, uri, error);
-       if (!request)
+       message = e_webdav_session_new_message (webdav, SOUP_METHOD_PUT, uri, error);
+       if (!message)
                return FALSE;
 
-       message = soup_request_http_get_message (request);
-       if (!message) {
-               g_warn_if_fail (message != NULL);
-               g_object_unref (request);
-
-               return FALSE;
-       }
+       e_webdav_session_copy_request_headers (message, in_headers);
 
        if (!etag || *etag) {
                ESource *source;
@@ -2561,40 +2401,43 @@ e_webdav_session_put_data_sync (EWebDAVSession *webdav,
                        if (etag) {
                                e_webdav_session_set_if_match_header (message, etag);
                        } else {
-                               soup_message_headers_replace (message->request_headers, "If-None-Match", "*");
+                               soup_message_headers_replace (soup_message_get_request_headers (message), 
"If-None-Match", "*");
                        }
                }
        }
 
        if (content_type && *content_type)
-               soup_message_headers_replace (message->request_headers, "Content-Type", content_type);
+               soup_message_headers_replace (soup_message_get_request_headers (message), "Content-Type", 
content_type);
 
-       soup_message_headers_replace (message->request_headers, "Prefer", "return=minimal");
+       soup_message_headers_replace (soup_message_get_request_headers (message), "Prefer", "return=minimal");
 
-       soup_message_set_request (message, content_type, SOUP_MEMORY_TEMPORARY, bytes, length);
+       e_soup_session_util_set_message_request_body_from_data (message, FALSE, content_type, bytes, length, 
NULL);
 
-       ret_bytes = e_soup_session_send_request_simple_sync (E_SOUP_SESSION (webdav), request, cancellable, 
error);
+       ret_bytes = e_soup_session_send_message_simple_sync (E_SOUP_SESSION (webdav), message, cancellable, 
error);
 
-       success = !e_webdav_session_replace_with_detailed_error_internal (webdav, request, ret_bytes, FALSE, 
_("Failed to put data"), error, TRUE, TRUE) &&
+       success = !e_webdav_session_replace_with_detailed_error_internal (webdav, message, ret_bytes, FALSE, 
_("Failed to put data"), error, TRUE, TRUE) &&
                ret_bytes != NULL;
 
        if (success) {
-               if (success && !SOUP_STATUS_IS_SUCCESSFUL (message->status_code)) {
+               if (success && !SOUP_STATUS_IS_SUCCESSFUL (soup_message_get_status (message))) {
                        success = FALSE;
 
-                       g_set_error (error, SOUP_HTTP_ERROR, message->status_code,
-                               _("Failed to put data to server, error code %d (%s)"), message->status_code,
-                               e_soup_session_util_status_to_string (message->status_code, 
message->reason_phrase));
+                       g_set_error (error, E_SOUP_SESSION_ERROR, soup_message_get_status (message),
+                               _("Failed to put data to server, error code %d (%s)"), 
soup_message_get_status (message),
+                               e_soup_session_util_status_to_string (soup_message_get_status (message), 
soup_message_get_reason_phrase (message)));
                }
        }
 
-       if (success)
+       if (success) {
                e_webdav_session_extract_href_and_etag (message, out_href, out_etag);
 
+               if (out_headers)
+                       *out_headers = g_boxed_copy (SOUP_TYPE_MESSAGE_HEADERS, 
soup_message_get_response_headers (message));
+       }
+
        if (ret_bytes)
                g_byte_array_free (ret_bytes, TRUE);
        g_object_unref (message);
-       g_object_unref (request);
 
        return success;
 }
@@ -2633,7 +2476,6 @@ e_webdav_session_delete_sync (EWebDAVSession *webdav,
                              GCancellable *cancellable,
                              GError **error)
 {
-       SoupRequestHTTP *request;
        SoupMessage *message;
        GByteArray *bytes;
        gboolean success;
@@ -2643,17 +2485,9 @@ e_webdav_session_delete_sync (EWebDAVSession *webdav,
 
        g_clear_pointer (&webdav->priv->last_dav_error_code, g_free);
 
-       request = e_webdav_session_new_request (webdav, SOUP_METHOD_DELETE, uri, error);
-       if (!request)
-               return FALSE;
-
-       message = soup_request_http_get_message (request);
-       if (!message) {
-               g_warn_if_fail (message != NULL);
-               g_object_unref (request);
-
+       message = e_webdav_session_new_message (webdav, SOUP_METHOD_DELETE, uri, error);
+       if (!message)
                return FALSE;
-       }
 
        if (etag) {
                ESource *source;
@@ -2673,17 +2507,16 @@ e_webdav_session_delete_sync (EWebDAVSession *webdav,
        }
 
        if (depth)
-               soup_message_headers_replace (message->request_headers, "Depth", depth);
+               soup_message_headers_replace (soup_message_get_request_headers (message), "Depth", depth);
 
-       bytes = e_soup_session_send_request_simple_sync (E_SOUP_SESSION (webdav), request, cancellable, 
error);
+       bytes = e_soup_session_send_message_simple_sync (E_SOUP_SESSION (webdav), message, cancellable, 
error);
 
-       success = !e_webdav_session_replace_with_detailed_error_internal (webdav, request, bytes, FALSE, 
_("Failed to delete resource"), error, TRUE, FALSE) &&
+       success = !e_webdav_session_replace_with_detailed_error_internal (webdav, message, bytes, FALSE, 
_("Failed to delete resource"), error, TRUE, FALSE) &&
                bytes != NULL;
 
        if (bytes)
                g_byte_array_free (bytes, TRUE);
        g_object_unref (message);
-       g_object_unref (request);
 
        return success;
 }
@@ -2716,7 +2549,6 @@ e_webdav_session_copy_sync (EWebDAVSession *webdav,
                            GCancellable *cancellable,
                            GError **error)
 {
-       SoupRequestHTTP *request;
        SoupMessage *message;
        GByteArray *bytes;
        gboolean success;
@@ -2728,31 +2560,22 @@ e_webdav_session_copy_sync (EWebDAVSession *webdav,
 
        g_clear_pointer (&webdav->priv->last_dav_error_code, g_free);
 
-       request = e_webdav_session_new_request (webdav, SOUP_METHOD_COPY, source_uri, error);
-       if (!request)
-               return FALSE;
-
-       message = soup_request_http_get_message (request);
-       if (!message) {
-               g_warn_if_fail (message != NULL);
-               g_object_unref (request);
-
+       message = e_webdav_session_new_message (webdav, SOUP_METHOD_COPY, source_uri, error);
+       if (!message)
                return FALSE;
-       }
 
-       soup_message_headers_replace (message->request_headers, "Depth", depth);
-       soup_message_headers_replace (message->request_headers, "Destination", destination_uri);
-       soup_message_headers_replace (message->request_headers, "Overwrite", can_overwrite ? "T" : "F");
+       soup_message_headers_replace (soup_message_get_request_headers (message), "Depth", depth);
+       soup_message_headers_replace (soup_message_get_request_headers (message), "Destination", 
destination_uri);
+       soup_message_headers_replace (soup_message_get_request_headers (message), "Overwrite", can_overwrite 
? "T" : "F");
 
-       bytes = e_soup_session_send_request_simple_sync (E_SOUP_SESSION (webdav), request, cancellable, 
error);
+       bytes = e_soup_session_send_message_simple_sync (E_SOUP_SESSION (webdav), message, cancellable, 
error);
 
-       success = !e_webdav_session_replace_with_detailed_error_internal (webdav, request, bytes, FALSE, 
_("Failed to copy resource"), error, TRUE, FALSE) &&
+       success = !e_webdav_session_replace_with_detailed_error_internal (webdav, message, bytes, FALSE, 
_("Failed to copy resource"), error, TRUE, FALSE) &&
                bytes != NULL;
 
        if (bytes)
                g_byte_array_free (bytes, TRUE);
        g_object_unref (message);
-       g_object_unref (request);
 
        return success;
 }
@@ -2781,7 +2604,6 @@ e_webdav_session_move_sync (EWebDAVSession *webdav,
                            GCancellable *cancellable,
                            GError **error)
 {
-       SoupRequestHTTP *request;
        SoupMessage *message;
        GByteArray *bytes;
        gboolean success;
@@ -2792,31 +2614,22 @@ e_webdav_session_move_sync (EWebDAVSession *webdav,
 
        g_clear_pointer (&webdav->priv->last_dav_error_code, g_free);
 
-       request = e_webdav_session_new_request (webdav, SOUP_METHOD_MOVE, source_uri, error);
-       if (!request)
-               return FALSE;
-
-       message = soup_request_http_get_message (request);
-       if (!message) {
-               g_warn_if_fail (message != NULL);
-               g_object_unref (request);
-
+       message = e_webdav_session_new_message (webdav, SOUP_METHOD_MOVE, source_uri, error);
+       if (!message)
                return FALSE;
-       }
 
-       soup_message_headers_replace (message->request_headers, "Depth", E_WEBDAV_DEPTH_INFINITY);
-       soup_message_headers_replace (message->request_headers, "Destination", destination_uri);
-       soup_message_headers_replace (message->request_headers, "Overwrite", can_overwrite ? "T" : "F");
+       soup_message_headers_replace (soup_message_get_request_headers (message), "Depth", 
E_WEBDAV_DEPTH_INFINITY);
+       soup_message_headers_replace (soup_message_get_request_headers (message), "Destination", 
destination_uri);
+       soup_message_headers_replace (soup_message_get_request_headers (message), "Overwrite", can_overwrite 
? "T" : "F");
 
-       bytes = e_soup_session_send_request_simple_sync (E_SOUP_SESSION (webdav), request, cancellable, 
error);
+       bytes = e_soup_session_send_message_simple_sync (E_SOUP_SESSION (webdav), message, cancellable, 
error);
 
-       success = !e_webdav_session_replace_with_detailed_error_internal (webdav, request, bytes, FALSE, 
_("Failed to move resource"), error, TRUE, FALSE) &&
+       success = !e_webdav_session_replace_with_detailed_error_internal (webdav, message, bytes, FALSE, 
_("Failed to move resource"), error, TRUE, FALSE) &&
                bytes != NULL;
 
        if (bytes)
                g_byte_array_free (bytes, TRUE);
        g_object_unref (message);
-       g_object_unref (request);
 
        return success;
 }
@@ -2858,7 +2671,6 @@ e_webdav_session_lock_sync (EWebDAVSession *webdav,
                            GCancellable *cancellable,
                            GError **error)
 {
-       SoupRequestHTTP *request;
        SoupMessage *message;
        GByteArray *bytes;
        gboolean success;
@@ -2872,29 +2684,21 @@ e_webdav_session_lock_sync (EWebDAVSession *webdav,
 
        g_clear_pointer (&webdav->priv->last_dav_error_code, g_free);
 
-       request = e_webdav_session_new_request (webdav, SOUP_METHOD_LOCK, uri, error);
-       if (!request)
+       message = e_webdav_session_new_message (webdav, SOUP_METHOD_LOCK, uri, error);
+       if (!message)
                return FALSE;
 
-       message = soup_request_http_get_message (request);
-       if (!message) {
-               g_warn_if_fail (message != NULL);
-               g_object_unref (request);
-
-               return FALSE;
-       }
-
        if (depth)
-               soup_message_headers_replace (message->request_headers, "Depth", depth);
+               soup_message_headers_replace (soup_message_get_request_headers (message), "Depth", depth);
 
        if (lock_timeout) {
                gchar *value;
 
                value = g_strdup_printf ("Second-%d", lock_timeout);
-               soup_message_headers_replace (message->request_headers, "Timeout", value);
+               soup_message_headers_replace (soup_message_get_request_headers (message), "Timeout", value);
                g_free (value);
        } else {
-               soup_message_headers_replace (message->request_headers, "Timeout", "Infinite");
+               soup_message_headers_replace (soup_message_get_request_headers (message), "Timeout", 
"Infinite");
        }
 
        if (xml) {
@@ -2904,20 +2708,19 @@ e_webdav_session_lock_sync (EWebDAVSession *webdav,
                content = e_xml_document_get_content (xml, &content_length);
                if (!content) {
                        g_object_unref (message);
-                       g_object_unref (request);
 
                        g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, _("Failed to get 
input XML content"));
 
                        return FALSE;
                }
 
-               soup_message_set_request (message, E_WEBDAV_CONTENT_TYPE_XML,
-                       SOUP_MEMORY_TAKE, content, content_length);
+               e_soup_session_util_set_message_request_body_from_data (message, FALSE, 
E_WEBDAV_CONTENT_TYPE_XML,
+                       content, content_length, g_free);
        }
 
-       bytes = e_soup_session_send_request_simple_sync (E_SOUP_SESSION (webdav), request, cancellable, 
error);
+       bytes = e_soup_session_send_message_simple_sync (E_SOUP_SESSION (webdav), message, cancellable, 
error);
 
-       success = !e_webdav_session_replace_with_detailed_error_internal (webdav, request, bytes, FALSE, 
_("Failed to lock resource"), error, TRUE, FALSE) &&
+       success = !e_webdav_session_replace_with_detailed_error_internal (webdav, message, bytes, FALSE, 
_("Failed to lock resource"), error, TRUE, FALSE) &&
                bytes != NULL;
 
        if (success && out_xml_response) {
@@ -2925,7 +2728,7 @@ e_webdav_session_lock_sync (EWebDAVSession *webdav,
 
                *out_xml_response = NULL;
 
-               content_type = soup_message_headers_get_content_type (message->response_headers, NULL);
+               content_type = soup_message_headers_get_content_type (soup_message_get_response_headers 
(message), NULL);
                if (!content_type ||
                    (g_ascii_strcasecmp (content_type, "application/xml") != 0 &&
                     g_ascii_strcasecmp (content_type, "text/xml") != 0)) {
@@ -2956,12 +2759,11 @@ e_webdav_session_lock_sync (EWebDAVSession *webdav,
        }
 
        if (success)
-               *out_lock_token = g_strdup (soup_message_headers_get_list (message->response_headers, 
"Lock-Token"));
+               *out_lock_token = g_strdup (soup_message_headers_get_list (soup_message_get_response_headers 
(message), "Lock-Token"));
 
        if (bytes)
                g_byte_array_free (bytes, TRUE);
        g_object_unref (message);
-       g_object_unref (request);
 
        return success;
 }
@@ -2992,7 +2794,6 @@ e_webdav_session_refresh_lock_sync (EWebDAVSession *webdav,
                                    GCancellable *cancellable,
                                    GError **error)
 {
-       SoupRequestHTTP *request;
        SoupMessage *message;
        GByteArray *bytes;
        gchar *value;
@@ -3003,37 +2804,28 @@ e_webdav_session_refresh_lock_sync (EWebDAVSession *webdav,
 
        g_clear_pointer (&webdav->priv->last_dav_error_code, g_free);
 
-       request = e_webdav_session_new_request (webdav, SOUP_METHOD_LOCK, uri, error);
-       if (!request)
-               return FALSE;
-
-       message = soup_request_http_get_message (request);
-       if (!message) {
-               g_warn_if_fail (message != NULL);
-               g_object_unref (request);
-
+       message = e_webdav_session_new_message (webdav, SOUP_METHOD_LOCK, uri, error);
+       if (!message)
                return FALSE;
-       }
 
        if (lock_timeout) {
                value = g_strdup_printf ("Second-%d", lock_timeout);
-               soup_message_headers_replace (message->request_headers, "Timeout", value);
+               soup_message_headers_replace (soup_message_get_request_headers (message), "Timeout", value);
                g_free (value);
        } else {
-               soup_message_headers_replace (message->request_headers, "Timeout", "Infinite");
+               soup_message_headers_replace (soup_message_get_request_headers (message), "Timeout", 
"Infinite");
        }
 
-       soup_message_headers_replace (message->request_headers, "Lock-Token", lock_token);
+       soup_message_headers_replace (soup_message_get_request_headers (message), "Lock-Token", lock_token);
 
-       bytes = e_soup_session_send_request_simple_sync (E_SOUP_SESSION (webdav), request, cancellable, 
error);
+       bytes = e_soup_session_send_message_simple_sync (E_SOUP_SESSION (webdav), message, cancellable, 
error);
 
-       success = !e_webdav_session_replace_with_detailed_error_internal (webdav, request, bytes, FALSE, 
_("Failed to refresh lock"), error, TRUE, FALSE) &&
+       success = !e_webdav_session_replace_with_detailed_error_internal (webdav, message, bytes, FALSE, 
_("Failed to refresh lock"), error, TRUE, FALSE) &&
                bytes != NULL;
 
        if (bytes)
                g_byte_array_free (bytes, TRUE);
        g_object_unref (message);
-       g_object_unref (request);
 
        return success;
 }
@@ -3062,7 +2854,6 @@ e_webdav_session_unlock_sync (EWebDAVSession *webdav,
                              GCancellable *cancellable,
                              GError **error)
 {
-       SoupRequestHTTP *request;
        SoupMessage *message;
        GByteArray *bytes;
        gboolean success;
@@ -3072,36 +2863,27 @@ e_webdav_session_unlock_sync (EWebDAVSession *webdav,
 
        g_clear_pointer (&webdav->priv->last_dav_error_code, g_free);
 
-       request = e_webdav_session_new_request (webdav, SOUP_METHOD_UNLOCK, uri, error);
-       if (!request)
+       message = e_webdav_session_new_message (webdav, SOUP_METHOD_UNLOCK, uri, error);
+       if (!message)
                return FALSE;
 
-       message = soup_request_http_get_message (request);
-       if (!message) {
-               g_warn_if_fail (message != NULL);
-               g_object_unref (request);
-
-               return FALSE;
-       }
+       soup_message_headers_replace (soup_message_get_request_headers (message), "Lock-Token", lock_token);
 
-       soup_message_headers_replace (message->request_headers, "Lock-Token", lock_token);
+       bytes = e_soup_session_send_message_simple_sync (E_SOUP_SESSION (webdav), message, cancellable, 
error);
 
-       bytes = e_soup_session_send_request_simple_sync (E_SOUP_SESSION (webdav), request, cancellable, 
error);
-
-       success = !e_webdav_session_replace_with_detailed_error_internal (webdav, request, bytes, FALSE, 
_("Failed to unlock"), error, TRUE, FALSE) &&
+       success = !e_webdav_session_replace_with_detailed_error_internal (webdav, message, bytes, FALSE, 
_("Failed to unlock"), error, TRUE, FALSE) &&
                bytes != NULL;
 
        if (bytes)
                g_byte_array_free (bytes, TRUE);
        g_object_unref (message);
-       g_object_unref (request);
 
        return success;
 }
 
 static gboolean
 e_webdav_session_traverse_propstat_response (EWebDAVSession *webdav,
-                                            const SoupMessage *message,
+                                            SoupMessage *message,
                                             const GByteArray *xml_data,
                                             gboolean require_multistatus,
                                             const gchar *top_path_ns_href1,
@@ -3112,7 +2894,7 @@ e_webdav_session_traverse_propstat_response (EWebDAVSession *webdav,
                                             gpointer func_user_data,
                                             GError **error)
 {
-       SoupURI *request_uri = NULL;
+       GUri *request_uri = NULL;
        xmlDocPtr doc;
        xmlNodePtr top_node, node;
        gboolean do_stop = FALSE;
@@ -3125,15 +2907,15 @@ e_webdav_session_traverse_propstat_response (EWebDAVSession *webdav,
        if (message) {
                const gchar *content_type;
 
-               if (require_multistatus && message->status_code != SOUP_STATUS_MULTI_STATUS) {
-                       g_set_error (error, SOUP_HTTP_ERROR, message->status_code,
-                               _("Expected multistatus response, but %d returned (%s)"), 
message->status_code,
-                               e_soup_session_util_status_to_string (message->status_code, 
message->reason_phrase));
+               if (require_multistatus && soup_message_get_status (message) != SOUP_STATUS_MULTI_STATUS) {
+                       g_set_error (error, E_SOUP_SESSION_ERROR, soup_message_get_status (message),
+                               _("Expected multistatus response, but %d returned (%s)"), 
soup_message_get_status (message),
+                               e_soup_session_util_status_to_string (soup_message_get_status (message), 
soup_message_get_reason_phrase (message)));
 
                        return FALSE;
                }
 
-               content_type = soup_message_headers_get_content_type (message->response_headers, NULL);
+               content_type = soup_message_headers_get_content_type (soup_message_get_response_headers 
(message), NULL);
                if (!content_type ||
                    (g_ascii_strcasecmp (content_type, "application/xml") != 0 &&
                     g_ascii_strcasecmp (content_type, "text/xml") != 0)) {
@@ -3265,7 +3047,7 @@ e_webdav_session_traverse_propstat_response (EWebDAVSession *webdav,
  **/
 gboolean
 e_webdav_session_traverse_multistatus_response (EWebDAVSession *webdav,
-                                               const SoupMessage *message,
+                                               SoupMessage *message,
                                                const GByteArray *xml_data,
                                                EWebDAVPropstatTraverseFunc func,
                                                gpointer func_user_data,
@@ -3301,7 +3083,7 @@ e_webdav_session_traverse_multistatus_response (EWebDAVSession *webdav,
  **/
 gboolean
 e_webdav_session_traverse_mkcol_response (EWebDAVSession *webdav,
-                                         const SoupMessage *message,
+                                         SoupMessage *message,
                                          const GByteArray *xml_data,
                                          EWebDAVPropstatTraverseFunc func,
                                          gpointer func_user_data,
@@ -3337,7 +3119,7 @@ e_webdav_session_traverse_mkcol_response (EWebDAVSession *webdav,
  **/
 gboolean
 e_webdav_session_traverse_mkcalendar_response (EWebDAVSession *webdav,
-                                              const SoupMessage *message,
+                                              SoupMessage *message,
                                               const GByteArray *xml_data,
                                               EWebDAVPropstatTraverseFunc func,
                                               gpointer func_user_data,
@@ -3356,7 +3138,7 @@ e_webdav_session_traverse_mkcalendar_response (EWebDAVSession *webdav,
 static gboolean
 e_webdav_session_getctag_cb (EWebDAVSession *webdav,
                             xmlNodePtr prop_node,
-                            const SoupURI *request_uri,
+                            const GUri *request_uri,
                             const gchar *href,
                             guint status_code,
                             gpointer user_data)
@@ -3630,7 +3412,7 @@ e_webdav_session_extract_datetime (xmlNodePtr parent,
 static gboolean
 e_webdav_session_list_cb (EWebDAVSession *webdav,
                          xmlNodePtr prop_node,
-                         const SoupURI *request_uri,
+                         const GUri *request_uri,
                          const gchar *href,
                          guint status_code,
                          gpointer user_data)
@@ -3850,7 +3632,7 @@ e_webdav_session_list_sync (EWebDAVSession *webdav,
                        EWebDAVResource *resource = link->data;
 
                        if (resource && !resource->display_name && resource->href) {
-                               gchar *href_decoded = soup_uri_decode (resource->href);
+                               gchar *href_decoded = g_filename_from_uri (resource->href, NULL, NULL);
 
                                if (href_decoded) {
                                        gchar *cp;
@@ -4110,7 +3892,7 @@ e_webdav_session_traverse_privilege_level (xmlNodePtr parent_node,
 static gboolean
 e_webdav_session_supported_privilege_set_cb (EWebDAVSession *webdav,
                                             xmlNodePtr prop_node,
-                                            const SoupURI *request_uri,
+                                            const GUri *request_uri,
                                             const gchar *href,
                                             guint status_code,
                                             gpointer user_data)
@@ -4155,7 +3937,6 @@ e_webdav_session_acl_sync (EWebDAVSession *webdav,
                           GCancellable *cancellable,
                           GError **error)
 {
-       SoupRequestHTTP *request;
        SoupMessage *message;
        GByteArray *bytes;
        gchar *content;
@@ -4167,40 +3948,30 @@ e_webdav_session_acl_sync (EWebDAVSession *webdav,
 
        g_clear_pointer (&webdav->priv->last_dav_error_code, g_free);
 
-       request = e_webdav_session_new_request (webdav, "ACL", uri, error);
-       if (!request)
-               return FALSE;
-
-       message = soup_request_http_get_message (request);
-       if (!message) {
-               g_warn_if_fail (message != NULL);
-               g_object_unref (request);
-
+       message = e_webdav_session_new_message (webdav, "ACL", uri, error);
+       if (!message)
                return FALSE;
-       }
 
        content = e_xml_document_get_content (xml, &content_length);
        if (!content) {
                g_object_unref (message);
-               g_object_unref (request);
 
                g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, _("Failed to get input 
XML content"));
 
                return FALSE;
        }
 
-       soup_message_set_request (message, E_WEBDAV_CONTENT_TYPE_XML,
-               SOUP_MEMORY_TAKE, content, content_length);
+       e_soup_session_util_set_message_request_body_from_data (message, FALSE, E_WEBDAV_CONTENT_TYPE_XML,
+               content, content_length, g_free);
 
-       bytes = e_soup_session_send_request_simple_sync (E_SOUP_SESSION (webdav), request, cancellable, 
error);
+       bytes = e_soup_session_send_message_simple_sync (E_SOUP_SESSION (webdav), message, cancellable, 
error);
 
-       success = !e_webdav_session_replace_with_detailed_error_internal (webdav, request, bytes, TRUE, 
_("Failed to get access control list"), error, TRUE, FALSE) &&
+       success = !e_webdav_session_replace_with_detailed_error_internal (webdav, message, bytes, TRUE, 
_("Failed to get access control list"), error, TRUE, FALSE) &&
                bytes != NULL;
 
        if (bytes)
                g_byte_array_free (bytes, TRUE);
        g_object_unref (message);
-       g_object_unref (request);
 
        return success;
 }
@@ -4286,7 +4057,7 @@ typedef struct _PrivilegeSetData {
 static gboolean
 e_webdav_session_current_user_privilege_set_cb (EWebDAVSession *webdav,
                                                xmlNodePtr prop_node,
-                                               const SoupURI *request_uri,
+                                               const GUri *request_uri,
                                                const gchar *href,
                                                guint status_code,
                                                gpointer user_data)
@@ -4369,7 +4140,7 @@ e_webdav_session_get_current_user_privilege_set_sync (EWebDAVSession *webdav,
 
        if (success && !psd.any_found) {
                success = FALSE;
-               g_set_error_literal (error, SOUP_HTTP_ERROR, SOUP_STATUS_NOT_FOUND, soup_status_get_phrase 
(SOUP_STATUS_NOT_FOUND));
+               g_set_error_literal (error, E_SOUP_SESSION_ERROR, SOUP_STATUS_NOT_FOUND, 
soup_status_get_phrase (SOUP_STATUS_NOT_FOUND));
        } else if (success) {
                *out_privileges = g_slist_reverse (*out_privileges);
        }
@@ -4472,7 +4243,7 @@ e_webdav_session_extract_acl_principal (xmlNodePtr principal_node,
 static gboolean
 e_webdav_session_acl_cb (EWebDAVSession *webdav,
                         xmlNodePtr prop_node,
-                        const SoupURI *request_uri,
+                        const GUri *request_uri,
                         const gchar *href,
                         guint status_code,
                         gpointer user_data)
@@ -4622,7 +4393,7 @@ typedef struct _ACLRestrictionsData {
 static gboolean
 e_webdav_session_acl_restrictions_cb (EWebDAVSession *webdav,
                                      xmlNodePtr prop_node,
-                                     const SoupURI *request_uri,
+                                     const GUri *request_uri,
                                      const gchar *href,
                                      guint status_code,
                                      gpointer user_data)
@@ -4729,7 +4500,7 @@ e_webdav_session_get_acl_restrictions_sync (EWebDAVSession *webdav,
 static gboolean
 e_webdav_session_principal_collection_set_cb (EWebDAVSession *webdav,
                                              xmlNodePtr prop_node,
-                                             const SoupURI *request_uri,
+                                             const GUri *request_uri,
                                              const gchar *href,
                                              guint status_code,
                                              gpointer user_data)
@@ -4991,7 +4762,7 @@ e_webdav_session_set_acl_sync (EWebDAVSession *webdav,
 static gboolean
 e_webdav_session_principal_property_search_cb (EWebDAVSession *webdav,
                                               xmlNodePtr prop_node,
-                                              const SoupURI *request_uri,
+                                              const GUri *request_uri,
                                               const gchar *href,
                                               guint status_code,
                                               gpointer user_data)
diff --git a/src/libedataserver/e-webdav-session.h b/src/libedataserver/e-webdav-session.h
index 45752f2ff..6636492dc 100644
--- a/src/libedataserver/e-webdav-session.h
+++ b/src/libedataserver/e-webdav-session.h
@@ -158,7 +158,7 @@ typedef enum {
  * EWebDAVPropstatTraverseFunc:
  * @webdav: an #EWebDAVSession
  * @prop_node: an #xmlNode
- * @request_uri: a #SoupURI, containing the request URI, maybe redirected by the server
+ * @request_uri: a #GUri, containing the request URI, maybe redirected by the server
  * @href: (nullable): a full URI to which the property belongs, or %NULL, when not found
  * @status_code: an HTTP status code for this property
  * @user_data: user data, as passed to e_webdav_session_propfind_sync()
@@ -176,7 +176,7 @@ typedef enum {
  **/
 typedef gboolean (* EWebDAVPropstatTraverseFunc)       (EWebDAVSession *webdav,
                                                         xmlNode *prop_node,
-                                                        const SoupURI *request_uri,
+                                                        const GUri *request_uri,
                                                         const gchar *href,
                                                         guint status_code,
                                                         gpointer user_data);
@@ -342,20 +342,20 @@ EWebDAVSession *e_webdav_session_new                      (ESource *source);
 const gchar *  e_webdav_session_get_last_dav_error_code(EWebDAVSession *webdav);
 gboolean       e_webdav_session_get_last_dav_error_is_permission
                                                        (EWebDAVSession *webdav);
-SoupRequestHTTP *
-               e_webdav_session_new_request            (EWebDAVSession *webdav,
+SoupMessage *
+               e_webdav_session_new_message            (EWebDAVSession *webdav,
                                                         const gchar *method,
                                                         const gchar *uri,
                                                         GError **error);
 gboolean       e_webdav_session_replace_with_detailed_error
                                                        (EWebDAVSession *webdav,
-                                                        SoupRequestHTTP *request,
+                                                        SoupMessage *request,
                                                         const GByteArray *response_data,
                                                         gboolean ignore_multistatus,
                                                         const gchar *prefix,
                                                         GError **inout_error);
 gchar *                e_webdav_session_ensure_full_uri        (EWebDAVSession *webdav,
-                                                        const SoupURI *request_uri,
+                                                        const GUri *request_uri,
                                                         const gchar *href);
 gboolean       e_webdav_session_options_sync           (EWebDAVSession *webdav,
                                                         const gchar *uri,
@@ -364,20 +364,13 @@ gboolean  e_webdav_session_options_sync           (EWebDAVSession *webdav,
                                                         GCancellable *cancellable,
                                                         GError **error);
 gboolean       e_webdav_session_post_sync              (EWebDAVSession *webdav,
-                                                        const gchar *uri,
-                                                        const gchar *data,
-                                                        gsize data_length,
-                                                        gchar **out_content_type,
-                                                        GByteArray **out_content,
-                                                        GCancellable *cancellable,
-                                                        GError **error);
-gboolean       e_webdav_session_post_with_content_type_sync
-                                                       (EWebDAVSession *webdav,
                                                         const gchar *uri,
                                                         const gchar *data,
                                                         gsize data_length,
                                                         const gchar *in_content_type,
+                                                        SoupMessageHeaders *in_headers,
                                                         gchar **out_content_type,
+                                                        SoupMessageHeaders **out_headers,
                                                         GByteArray **out_content,
                                                         GCancellable *cancellable,
                                                         GError **error);
@@ -426,6 +419,7 @@ gboolean    e_webdav_session_get_sync               (EWebDAVSession *webdav,
                                                         const gchar *uri,
                                                         gchar **out_href,
                                                         gchar **out_etag,
+                                                        SoupMessageHeaders **out_headers,
                                                         GOutputStream *out_stream,
                                                         GCancellable *cancellable,
                                                         GError **error);
@@ -433,6 +427,7 @@ gboolean    e_webdav_session_get_data_sync          (EWebDAVSession *webdav,
                                                         const gchar *uri,
                                                         gchar **out_href,
                                                         gchar **out_etag,
+                                                        SoupMessageHeaders **out_headers,
                                                         gchar **out_bytes,
                                                         gsize *out_length,
                                                         GCancellable *cancellable,
@@ -441,19 +436,24 @@ gboolean  e_webdav_session_put_sync               (EWebDAVSession *webdav,
                                                         const gchar *uri,
                                                         const gchar *etag,
                                                         const gchar *content_type,
+                                                        SoupMessageHeaders *in_headers,
                                                         GInputStream *stream,
+                                                        gssize stream_length,
                                                         gchar **out_href,
                                                         gchar **out_etag,
+                                                        SoupMessageHeaders **out_headers,
                                                         GCancellable *cancellable,
                                                         GError **error);
 gboolean       e_webdav_session_put_data_sync          (EWebDAVSession *webdav,
                                                         const gchar *uri,
                                                         const gchar *etag,
                                                         const gchar *content_type,
+                                                        SoupMessageHeaders *in_headers,
                                                         const gchar *bytes,
                                                         gsize length,
                                                         gchar **out_href,
                                                         gchar **out_etag,
+                                                        SoupMessageHeaders **out_headers,
                                                         GCancellable *cancellable,
                                                         GError **error);
 gboolean       e_webdav_session_delete_sync            (EWebDAVSession *webdav,
@@ -497,21 +497,21 @@ gboolean  e_webdav_session_unlock_sync            (EWebDAVSession *webdav,
                                                         GError **error);
 gboolean       e_webdav_session_traverse_multistatus_response
                                                        (EWebDAVSession *webdav,
-                                                        const SoupMessage *message,
+                                                        SoupMessage *message,
                                                         const GByteArray *xml_data,
                                                         EWebDAVPropstatTraverseFunc func,
                                                         gpointer func_user_data,
                                                         GError **error);
 gboolean       e_webdav_session_traverse_mkcol_response
                                                        (EWebDAVSession *webdav,
-                                                        const SoupMessage *message,
+                                                        SoupMessage *message,
                                                         const GByteArray *xml_data,
                                                         EWebDAVPropstatTraverseFunc func,
                                                         gpointer func_user_data,
                                                         GError **error);
 gboolean       e_webdav_session_traverse_mkcalendar_response
                                                        (EWebDAVSession *webdav,
-                                                        const SoupMessage *message,
+                                                        SoupMessage *message,
                                                         const GByteArray *xml_data,
                                                         EWebDAVPropstatTraverseFunc func,
                                                         gpointer func_user_data,
diff --git a/src/libedataserver/libedataserver.h b/src/libedataserver/libedataserver.h
index 311beed84..c9e58081c 100644
--- a/src/libedataserver/libedataserver.h
+++ b/src/libedataserver/libedataserver.h
@@ -45,11 +45,9 @@
 #include <libedataserver/e-oauth2-service-yahoo.h>
 #include <libedataserver/e-oauth2-services.h>
 #include <libedataserver/e-operation-pool.h>
-#include <libedataserver/e-proxy.h>
 #include <libedataserver/e-secret-store.h>
 #include <libedataserver/e-sexp.h>
 #include <libedataserver/e-soup-auth-bearer.h>
-#include <libedataserver/e-soup-logger.h>
 #include <libedataserver/e-soup-session.h>
 #include <libedataserver/e-soup-ssl-trust.h>
 #include <libedataserver/e-source-address-book.h>
diff --git a/src/libedataserver/libedataserver.pc.in b/src/libedataserver/libedataserver.pc.in
index f34d5a6f5..911cd319d 100644
--- a/src/libedataserver/libedataserver.pc.in
+++ b/src/libedataserver/libedataserver.pc.in
@@ -12,7 +12,7 @@ credentialmoduledir=@credentialmoduledir@
 Name: libedataserver
 Description: Utility library for Evolution Data Server
 Version: @PROJECT_VERSION@
-Requires: gio-2.0 gmodule-2.0 libsecret-1 libxml-2.0 libsoup-2.4
+Requires: gio-2.0 gmodule-2.0 libsecret-1 libxml-2.0 libsoup-3.0
 Requires.private: camel-@API_VERSION@
 Libs: -L${libdir} -ledataserver-@API_VERSION@
 Cflags: -I${privincludedir}
diff --git a/src/libedataserverui/CMakeLists.txt b/src/libedataserverui/CMakeLists.txt
index def120959..11757c172 100644
--- a/src/libedataserverui/CMakeLists.txt
+++ b/src/libedataserverui/CMakeLists.txt
@@ -107,7 +107,7 @@ install(FILES ${HEADERS}
 
 set(gir_sources ${SOURCES} ${HEADERS})
 set(gir_identifies_prefixes E)
-set(gir_includes GObject-2.0 Gio-2.0 Gtk-3.0 Soup-2.4)
+set(gir_includes GObject-2.0 Gio-2.0 Gtk-3.0 Soup-3.0)
 set(gir_cflags
        -DLIBEDATASERVERUI_COMPILATION
        -I${CMAKE_BINARY_DIR}/src/calendar
diff --git a/src/libedataserverui/e-credentials-prompter-impl-oauth2.c 
b/src/libedataserverui/e-credentials-prompter-impl-oauth2.c
index a99408808..f9b41a21c 100644
--- a/src/libedataserverui/e-credentials-prompter-impl-oauth2.c
+++ b/src/libedataserverui/e-credentials-prompter-impl-oauth2.c
@@ -74,24 +74,25 @@ cpi_oauth2_create_auth_uri (EOAuth2Service *service,
                            ESource *source)
 {
        GHashTable *uri_query;
-       SoupURI *soup_uri;
-       gchar *uri;
+       GUri *parsed_uri;
+       gchar *uri, *query;
 
        g_return_val_if_fail (E_IS_OAUTH2_SERVICE (service), NULL);
        g_return_val_if_fail (E_IS_SOURCE (source), NULL);
 
-       soup_uri = soup_uri_new (e_oauth2_service_get_authentication_uri (service, source));
-       g_return_val_if_fail (soup_uri != NULL, NULL);
+       parsed_uri = g_uri_parse (e_oauth2_service_get_authentication_uri (service, source), 
SOUP_HTTP_URI_FLAGS, NULL);
+       g_return_val_if_fail (parsed_uri != NULL, NULL);
 
        uri_query = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
 
        e_oauth2_service_prepare_authentication_uri_query (service, source, uri_query);
 
-       soup_uri_set_query_from_form (soup_uri, uri_query);
+       query = soup_form_encode_hash (uri_query);
+       e_util_change_uri_component (&parsed_uri, SOUP_URI_QUERY, query);
 
-       uri = soup_uri_to_string (soup_uri, FALSE);
+       uri = g_uri_to_string_partial (parsed_uri, G_URI_HIDE_PASSWORD);
 
-       soup_uri_free (soup_uri);
+       g_uri_unref (parsed_uri);
        g_hash_table_destroy (uri_query);
 
        return uri;
@@ -629,7 +630,7 @@ credentials_prompter_impl_oauth2_set_proxy (WebKitWebContext *web_context,
                ESourceProxy *proxy;
                WebKitWebsiteDataManager *data_manager;
                WebKitNetworkProxySettings *proxy_settings = NULL;
-               SoupURI *suri;
+               GUri *guri;
                gchar **ignore_hosts = NULL;
                gchar *tmp;
                guint16 port;
@@ -646,18 +647,13 @@ credentials_prompter_impl_oauth2_set_proxy (WebKitWebContext *web_context,
 
                        tmp = credentials_prompter_impl_oauth2_sanitize_host (e_source_proxy_dup_socks_host 
(proxy));
                        if (tmp && *tmp) {
-                               suri = soup_uri_new (NULL);
-                               soup_uri_set_scheme (suri, "socks");
-                               soup_uri_set_host (suri, tmp);
-                               soup_uri_set_path (suri, "");
                                port = e_source_proxy_get_socks_port (proxy);
-                               if (port)
-                                       soup_uri_set_port (suri, port);
+                               guri = g_uri_build (G_URI_FLAGS_PARSE_RELAXED | SOUP_HTTP_URI_FLAGS, "socks", 
NULL, tmp, port ? port : -1, "", NULL, NULL);
                                g_free (tmp);
-                               tmp = soup_uri_to_string (suri, FALSE);
+                               tmp = g_uri_to_string_partial (guri, G_URI_HIDE_NONE);
                                proxy_settings = webkit_network_proxy_settings_new (tmp, (const gchar * const 
*) ignore_hosts);
                                webkit_network_proxy_settings_add_proxy_for_scheme (proxy_settings, "socks", 
tmp);
-                               soup_uri_free (suri);
+                               g_uri_unref (guri);
                        } else {
                                proxy_settings = webkit_network_proxy_settings_new (NULL, (const gchar * 
const *) ignore_hosts);
                        }
@@ -665,44 +661,36 @@ credentials_prompter_impl_oauth2_set_proxy (WebKitWebContext *web_context,
 
                        tmp = credentials_prompter_impl_oauth2_sanitize_host (e_source_proxy_dup_http_host 
(proxy));
                        if (tmp && *tmp) {
-                               suri = soup_uri_new (NULL);
-                               soup_uri_set_scheme (suri, SOUP_URI_SCHEME_HTTP);
-                               soup_uri_set_host (suri, tmp);
-                               soup_uri_set_path (suri, "");
                                port = e_source_proxy_get_http_port (proxy);
-                               if (port)
-                                       soup_uri_set_port (suri, port);
                                if (e_source_proxy_get_http_use_auth (proxy)) {
-                                       g_free (tmp);
-                                       tmp = e_source_proxy_dup_http_auth_user (proxy);
-                                       if (tmp)
-                                               soup_uri_set_user (suri, tmp);
-
-                                       g_free (tmp);
-                                       tmp = e_source_proxy_dup_http_auth_password (proxy);
-                                       if (tmp)
-                                               soup_uri_set_password (suri, tmp);
+                                       gchar *user, *password;
+
+                                       user = e_source_proxy_dup_http_auth_user (proxy);
+                                       password = e_source_proxy_dup_http_auth_password (proxy);
+
+                                       guri = g_uri_build_with_user (G_URI_FLAGS_PARSE_RELAXED | 
SOUP_HTTP_URI_FLAGS, "http",
+                                               user, password, NULL, tmp, port ? port : -1, "", NULL, NULL);
+
+                                       e_util_safe_free_string (password);
+                                       g_free (user);
+                               } else {
+                                       guri = g_uri_build (G_URI_FLAGS_PARSE_RELAXED | SOUP_HTTP_URI_FLAGS, 
"http", NULL, tmp, port ? port : -1, "", NULL, NULL);
                                }
                                g_free (tmp);
-                               tmp = soup_uri_to_string (suri, FALSE);
-                               webkit_network_proxy_settings_add_proxy_for_scheme (proxy_settings, 
SOUP_URI_SCHEME_HTTP, tmp);
-                               soup_uri_free (suri);
+                               tmp = g_uri_to_string_partial (guri, G_URI_HIDE_NONE);
+                               webkit_network_proxy_settings_add_proxy_for_scheme (proxy_settings, "http", 
tmp);
+                               g_uri_unref (guri);
                        }
                        g_free (tmp);
 
                        tmp = credentials_prompter_impl_oauth2_sanitize_host (e_source_proxy_dup_https_host 
(proxy));
                        if (tmp && *tmp) {
-                               suri = soup_uri_new (NULL);
-                               soup_uri_set_scheme (suri, SOUP_URI_SCHEME_HTTP);
-                               soup_uri_set_host (suri, tmp);
-                               soup_uri_set_path (suri, "");
                                port = e_source_proxy_get_https_port (proxy);
-                               if (port)
-                                       soup_uri_set_port (suri, port);
+                               guri = g_uri_build (G_URI_FLAGS_PARSE_RELAXED | SOUP_HTTP_URI_FLAGS, "http", 
NULL, tmp, port ? port : -1, "", NULL, NULL);
                                g_free (tmp);
-                               tmp = soup_uri_to_string (suri, FALSE);
-                               webkit_network_proxy_settings_add_proxy_for_scheme (proxy_settings, 
SOUP_URI_SCHEME_HTTPS, tmp);
-                               soup_uri_free (suri);
+                               tmp = g_uri_to_string_partial (guri, G_URI_HIDE_NONE);
+                               webkit_network_proxy_settings_add_proxy_for_scheme (proxy_settings, "https", 
tmp);
+                               g_uri_unref (guri);
                        }
                        g_free (tmp);
 
diff --git a/src/libedataserverui/e-trust-prompt.c b/src/libedataserverui/e-trust-prompt.c
index 4604c33ad..ecbe63e7b 100644
--- a/src/libedataserverui/e-trust-prompt.c
+++ b/src/libedataserverui/e-trust-prompt.c
@@ -489,24 +489,24 @@ save_source_thread (GTask *task,
 static gchar *
 trust_prompt_get_host_from_url (const gchar *url)
 {
-       SoupURI *suri;
+       GUri *suri;
        gchar *host;
 
        if (!url || !*url)
                return NULL;
 
-       suri = soup_uri_new (url);
+       suri = g_uri_parse (url, SOUP_HTTP_URI_FLAGS, NULL);
        if (!suri)
                return NULL;
 
-       host = g_strdup (soup_uri_get_host (suri));
+       host = g_strdup (g_uri_get_host (suri));
 
        if (!host || !*host) {
                g_free (host);
                host = NULL;
        }
 
-       soup_uri_free (suri);
+       g_uri_unref (suri);
 
        return host;
 }
diff --git a/src/libedataserverui/e-webdav-discover-widget.c b/src/libedataserverui/e-webdav-discover-widget.c
index c1679630a..dadc793d9 100644
--- a/src/libedataserverui/e-webdav-discover-widget.c
+++ b/src/libedataserverui/e-webdav-discover-widget.c
@@ -744,7 +744,7 @@ e_webdav_discover_content_refresh_done_cb (GObject *source_object,
                &certificate_pem, &certificate_errors, &discovered_sources,
                &calendar_user_addresses, &local_error)) {
                if (!g_cancellable_is_cancelled (cancellable) && certificate_pem &&
-                   g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_SSL_FAILED)) {
+                   g_error_matches (local_error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE)) {
                        GtkWindow *parent;
                        GtkWidget *widget;
 
@@ -756,8 +756,8 @@ e_webdav_discover_content_refresh_done_cb (GObject *source_object,
                } else if (g_cancellable_is_cancelled (cancellable) ||
                    (!g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED) &&
                    !g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND) &&
-                   !g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_UNAUTHORIZED) &&
-                   !g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_FORBIDDEN))) {
+                   !g_error_matches (local_error, E_SOUP_SESSION_ERROR, SOUP_STATUS_UNAUTHORIZED) &&
+                   !g_error_matches (local_error, E_SOUP_SESSION_ERROR, SOUP_STATUS_FORBIDDEN))) {
                        g_task_return_error (task, g_steal_pointer (&local_error));
                } else {
                        EWebDAVDiscoverContent *content = rd->content;
@@ -837,7 +837,7 @@ e_webdav_discover_content_refresh (GtkWidget *content,
        GTask *task;
        RefreshData *rd;
        ESource *source;
-       SoupURI *soup_uri;
+       GUri *parsed_uri;
        GtkWidget *label;
 
        g_return_if_fail (E_IS_WEBDAV_DISCOVER_CONTENT (content));
@@ -849,8 +849,8 @@ e_webdav_discover_content_refresh (GtkWidget *content,
        use_cancellable = cancellable ? g_object_ref (cancellable) : g_cancellable_new ();
        task = g_task_new (self, use_cancellable, callback, user_data);
        g_task_set_source_tag (task, e_webdav_discover_content_refresh);
-       soup_uri = soup_uri_new (self->base_url);
-       if (!soup_uri) {
+       parsed_uri = g_uri_parse (self->base_url, SOUP_HTTP_URI_FLAGS, NULL);
+       if (!parsed_uri) {
                g_task_return_new_error (task,
                        G_IO_ERROR,
                        G_IO_ERROR_INVALID_ARGUMENT,
@@ -886,10 +886,10 @@ e_webdav_discover_content_refresh (GtkWidget *content,
 
                if (display_name && *display_name)
                        e_source_set_display_name (source, display_name);
-               e_source_webdav_set_soup_uri (webdav_extension, soup_uri);
-               e_source_authentication_set_host (auth_extension, soup_uri_get_host (soup_uri));
-               e_source_authentication_set_port (auth_extension, soup_uri_get_port (soup_uri));
-               e_source_authentication_set_user (auth_extension, soup_uri_get_user (soup_uri));
+               e_source_webdav_set_uri (webdav_extension, parsed_uri);
+               e_source_authentication_set_host (auth_extension, g_uri_get_host (parsed_uri));
+               e_source_authentication_set_port (auth_extension, g_uri_get_port (parsed_uri));
+               e_source_authentication_set_user (auth_extension, g_uri_get_user (parsed_uri));
        }
 
        gtk_list_store_clear (GTK_LIST_STORE (gtk_tree_view_get_model (self->sources_tree_view)));
@@ -921,7 +921,7 @@ e_webdav_discover_content_refresh (GtkWidget *content,
 
        g_object_unref (source);
        g_object_unref (use_cancellable);
-       soup_uri_free (soup_uri);
+       g_uri_unref (parsed_uri);
 }
 
 /**
diff --git a/src/libedataserverui/libedataserverui.pc.in b/src/libedataserverui/libedataserverui.pc.in
index f631fe1ec..d1bcf6261 100644
--- a/src/libedataserverui/libedataserverui.pc.in
+++ b/src/libedataserverui/libedataserverui.pc.in
@@ -14,7 +14,7 @@ uimoduledir=@uimoduledir@
 Name: libedataserverui
 Description: UI utility library for Evolution Data Server
 Version: @PROJECT_VERSION@
-Requires: gio-2.0 gmodule-2.0 libsecret-1 libxml-2.0 libsoup-2.4 gtk+-3.0 libedataserver-@API_VERSION@ 
libecal-@CAL_API_VERSION@
+Requires: gio-2.0 gmodule-2.0 libsecret-1 libxml-2.0 libsoup-3.0 gtk+-3.0 libedataserver-@API_VERSION@ 
libecal-@CAL_API_VERSION@
 Requires.private: camel-@API_VERSION@
 Libs: -L${libdir} -ledataserver-@API_VERSION@ -ledataserverui-@API_VERSION@
 Cflags: -I${privincludedir}
diff --git a/src/modules/gnome-online-accounts/goaewsclient.c 
b/src/modules/gnome-online-accounts/goaewsclient.c
index fa3c3e346..bde027ff2 100644
--- a/src/modules/gnome-online-accounts/goaewsclient.c
+++ b/src/modules/gnome-online-accounts/goaewsclient.c
@@ -91,17 +91,16 @@ ews_check_node (const xmlNode *node,
                (g_strcmp0 ((gchar *) node->name, name) == 0);
 }
 
-static void
-ews_authenticate (SoupSession *session,
-                  SoupMessage *msg,
+static gboolean
+ews_authenticate (SoupMessage *msg,
                   SoupAuth *auth,
                   gboolean retrying,
                   AutodiscoverAuthData *data)
 {
-       if (retrying)
-               return;
+       if (!retrying)
+               soup_auth_authenticate (auth, data->username, data->password);
 
-       soup_auth_authenticate (auth, data->username, data->password);
+       return FALSE;
 }
 
 static void
@@ -180,27 +179,41 @@ ews_autodiscover_parse_protocol (xmlNode *node,
        return (got_as_url && got_oab_url);
 }
 
+typedef struct _ResponseData {
+       SoupMessage *msg;
+       GSimpleAsyncResult *simple;
+} ResponseData;
+
 static void
-ews_autodiscover_response_cb (SoupSession *session,
-                              SoupMessage *msg,
+ews_autodiscover_response_cb (GObject *source_object,
+                              GAsyncResult *result,
                               gpointer user_data)
 {
-       GSimpleAsyncResult *simple;
+       ResponseData *rd = user_data;
+       GSimpleAsyncResult *simple = rd->simple;
+       SoupMessage *msg = rd->msg;
        AutodiscoverData *data;
+       GBytes *bytes;
        gboolean success = FALSE;
-       guint status;
        gint idx;
        gsize size;
        xmlDoc *doc;
        xmlNode *node;
        GError *error = NULL;
 
-       simple = G_SIMPLE_ASYNC_RESULT (user_data);
        data = g_simple_async_result_get_op_res_gpointer (simple);
 
-       status = msg->status_code;
-       if (status == SOUP_STATUS_CANCELLED)
+       g_slice_free (ResponseData, rd);
+       rd = NULL;
+
+       bytes = soup_session_send_and_read_finish (SOUP_SESSION (source_object), result, &error);
+
+       if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+               g_clear_error (&error);
+               g_clear_object (&msg);
+               g_clear_object (&simple);
                return;
+       }
 
        size = sizeof (data->msgs) / sizeof (data->msgs[0]);
 
@@ -208,32 +221,41 @@ ews_autodiscover_response_cb (SoupSession *session,
                if (data->msgs[idx] == msg)
                        break;
        }
-       if (idx == size)
+       if (idx == size) {
+               g_clear_error (&error);
+               if (bytes)
+                       g_bytes_unref (bytes);
+               g_clear_object (&msg);
+               g_clear_object (&simple);
                return;
+       }
 
        data->msgs[idx] = NULL;
 
-       if (status != SOUP_STATUS_OK) {
-               g_set_error (
-                       &error, GOA_ERROR,
-                       GOA_ERROR_FAILED, /* TODO: more specific */
-                       _("Code: %u — Unexpected response from server"),
-                       status);
+       if (soup_message_get_status (msg) != SOUP_STATUS_OK) {
+               if (!error) {
+                       g_set_error (
+                               &error, GOA_ERROR,
+                               GOA_ERROR_FAILED, /* TODO: more specific */
+                               _("Code: %u — Unexpected response from server"),
+                               soup_message_get_status (msg));
+               }
+               if (bytes)
+                       g_bytes_unref (bytes);
                goto out;
        }
 
-       soup_buffer_free (
-               soup_message_body_flatten (
-               SOUP_MESSAGE (msg)->response_body));
-
-       g_debug ("The response headers");
+       g_debug ("The response body");
        g_debug ("===================");
-       g_debug ("%s", SOUP_MESSAGE (msg)->response_body->data);
+       g_debug ("%.*s", (gint) g_bytes_get_size (bytes), (const gchar *) g_bytes_get_data (bytes, NULL));
 
        doc = xmlReadMemory (
-               msg->response_body->data,
-               msg->response_body->length,
+               g_bytes_get_data (bytes, NULL),
+               g_bytes_get_size (bytes),
                "autodiscover.xml", NULL, 0);
+
+       g_clear_pointer (&bytes, g_bytes_unref);
+
        if (doc == NULL) {
                g_set_error (
                        &error, GOA_ERROR,
@@ -291,24 +313,25 @@ ews_autodiscover_response_cb (SoupSession *session,
 
        for (idx = 0; idx < size; idx++) {
                if (data->msgs[idx] != NULL) {
-                       /* Since we are cancelling from the same thread
-                        * that we queued the message, the callback (ie.
-                        * this function) will be invoked before
-                        * soup_session_cancel_message returns. */
-                       soup_session_cancel_message (
-                               data->session, data->msgs[idx],
-                               SOUP_STATUS_CANCELLED);
                        data->msgs[idx] = NULL;
                }
        }
 
-out:
+       /* Since we are cancelling from the same thread
+        * that we queued the message, the callback (ie.
+        * this function) will be invoked before
+        * soup_session_abort returns. */
+       soup_session_abort (data->session);
+
+ out:
        if (error != NULL) {
                for (idx = 0; idx < size; idx++) {
                        if (data->msgs[idx] != NULL) {
                                /* There's another request outstanding.
                                 * Hope that it has better luck. */
                                g_clear_error (&error);
+                               g_clear_object (&msg);
+                               g_clear_object (&simple);
                                return;
                        }
                }
@@ -317,6 +340,8 @@ out:
 
        g_simple_async_result_complete_in_idle (simple);
        g_object_unref (simple);
+       g_clear_object (&msg);
+       g_clear_object (&simple);
 }
 
 static xmlDoc *
@@ -369,20 +394,17 @@ ews_post_restarted_cb (SoupMessage *msg,
        /* In violation of RFC2616, libsoup will change a
         * POST request to a GET on receiving a 302 redirect. */
        g_debug ("Working around libsoup bug with redirect");
-       g_object_set (msg, SOUP_MESSAGE_METHOD, "POST", NULL);
+       g_object_set (msg, "method", "POST", NULL);
 
        buf_content = compat_libxml_output_buffer_get_content (buf, &buf_size);
-       soup_message_set_request (
-               msg, "text/xml; charset=utf-8",
-               SOUP_MEMORY_COPY,
-               buf_content, buf_size);
+       e_soup_session_util_set_message_request_body_from_data (msg, TRUE, "text/xml; charset=utf-8", 
buf_content, buf_size, NULL);
 }
 
 static gboolean
-go_ews_client_accept_certificate_cb (GTlsConnection *conn,
-                                    GTlsCertificate *peer_cert,
-                                    GTlsCertificateFlags errors,
-                                    gpointer user_data)
+goa_ews_client_accept_certificate_cb (SoupMessage *msg,
+                                     GTlsCertificate *tls_peer_certificate,
+                                     GTlsCertificateFlags tls_peer_errors,
+                                     gpointer user_data)
 {
        /* As much as EDS is interested, any certificate error during
           autodiscover is ignored, because it had been allowed during
@@ -391,21 +413,6 @@ go_ews_client_accept_certificate_cb (GTlsConnection *conn,
        return TRUE;
 }
 
-static void
-goa_ews_client_network_event_cb (SoupMessage *msg,
-                                GSocketClientEvent event,
-                                GIOStream *connection,
-                                gpointer user_data)
-{
-       /* It's either a GTlsConnection or a GTcpConnection */
-       if (event == G_SOCKET_CLIENT_TLS_HANDSHAKING &&
-           G_IS_TLS_CONNECTION (connection)) {
-               g_signal_connect (
-                       G_TLS_CONNECTION (connection), "accept-certificate",
-                       G_CALLBACK (go_ews_client_accept_certificate_cb), NULL);
-       }
-}
-
 static SoupMessage *
 ews_create_msg_for_url (const gchar *url,
                         xmlOutputBuffer *buf)
@@ -416,30 +423,19 @@ ews_create_msg_for_url (const gchar *url,
 
        msg = soup_message_new (buf != NULL ? "POST" : "GET", url);
        soup_message_headers_append (
-               msg->request_headers, "User-Agent", "libews/0.1");
+               soup_message_get_request_headers (msg), "User-Agent", "libews/0.1");
 
-       g_signal_connect (msg, "network-event",
-               G_CALLBACK (goa_ews_client_network_event_cb), NULL);
+       g_signal_connect (msg, "accept-certificate",
+               G_CALLBACK (goa_ews_client_accept_certificate_cb), NULL);
 
        if (buf != NULL) {
                buf_content = compat_libxml_output_buffer_get_content (buf, &buf_size);
-               soup_message_set_request (
-                       msg, "text/xml; charset=utf-8",
-                       SOUP_MEMORY_COPY,
-                       buf_content, buf_size);
+               e_soup_session_util_set_message_request_body_from_data (msg, TRUE, "text/xml; charset=utf-8", 
buf_content, buf_size, NULL);
                g_signal_connect (
                        msg, "restarted",
                        G_CALLBACK (ews_post_restarted_cb), buf);
        }
 
-       soup_buffer_free (
-               soup_message_body_flatten (
-               SOUP_MESSAGE (msg)->request_body));
-
-       g_debug ("The request headers");
-       g_debug ("===================");
-       g_debug ("%s", SOUP_MESSAGE (msg)->request_body->data);
-
        return msg;
 }
 
@@ -496,11 +492,9 @@ goa_ews_autodiscover (GoaObject *goa_object,
        data->buf = buf;
        data->msgs[0] = ews_create_msg_for_url (url1, buf);
        data->msgs[1] = ews_create_msg_for_url (url2, buf);
-       data->session = soup_session_async_new_with_options (
-               SOUP_SESSION_USE_NTLM, TRUE,
-               SOUP_SESSION_USE_THREAD_CONTEXT, TRUE,
-               SOUP_SESSION_TIMEOUT, 90,
-               SOUP_SESSION_ACCEPT_LANGUAGE_AUTO, TRUE,
+       data->session = soup_session_new_with_options (
+               "timeout", 90,
+               "accept-language-auto", TRUE,
                NULL);
        if (G_IS_CANCELLABLE (cancellable)) {
                data->cancellable = g_object_ref (cancellable);
@@ -528,6 +522,7 @@ goa_ews_autodiscover (GoaObject *goa_object,
                ((password == NULL) && (error != NULL)));
 
        if (error == NULL) {
+               ResponseData *rd;
                gchar *username;
 
                username = goa_account_dup_identity (goa_account);
@@ -537,16 +532,32 @@ goa_ews_autodiscover (GoaObject *goa_object,
                auth->password = password;  /* takes ownership */
 
                g_signal_connect_data (
-                       data->session, "authenticate",
+                       data->msgs[0], "authenticate",
                        G_CALLBACK (ews_authenticate), auth,
                        ews_autodiscover_auth_data_free, 0);
 
-               soup_session_queue_message (
-                       data->session, data->msgs[0],
-                       ews_autodiscover_response_cb, simple);
-               soup_session_queue_message (
-                       data->session, data->msgs[1],
-                       ews_autodiscover_response_cb, simple);
+               auth = g_slice_new0 (AutodiscoverAuthData);
+               auth->username = g_strdup (username);
+               auth->password = g_strdup (password);
+
+               g_signal_connect_data (
+                       data->msgs[1], "authenticate",
+                       G_CALLBACK (ews_authenticate), auth,
+                       ews_autodiscover_auth_data_free, 0);
+
+               rd = g_slice_new (ResponseData);
+               rd->msg = g_object_ref (data->msgs[0]);
+               rd->simple = g_object_ref (simple);
+
+               soup_session_send_and_read_async (data->session, data->msgs[0], G_PRIORITY_DEFAULT, 
cancellable,
+                       ews_autodiscover_response_cb, rd);
+
+               rd = g_slice_new (ResponseData);
+               rd->msg = g_object_ref (data->msgs[1]);
+               rd->simple = g_object_ref (simple);
+
+               soup_session_send_and_read_async (data->session, data->msgs[1], G_PRIORITY_DEFAULT, 
cancellable,
+                       ews_autodiscover_response_cb, rd);
        } else {
                g_dbus_error_strip_remote_error (error);
                g_simple_async_result_take_error (simple, error);
diff --git a/src/modules/gnome-online-accounts/module-gnome-online-accounts.c 
b/src/modules/gnome-online-accounts/module-gnome-online-accounts.c
index b05dd59c2..0831d54a1 100644
--- a/src/modules/gnome-online-accounts/module-gnome-online-accounts.c
+++ b/src/modules/gnome-online-accounts/module-gnome-online-accounts.c
@@ -281,14 +281,14 @@ goa_ews_autodiscover_done_cb (GObject *source_object,
        if (source_extension != NULL) {
                GoaAccount *goa_account;
                CamelSettings *settings;
-               SoupURI *suri;
+               GUri *suri;
                gchar *user, *email;
 
                goa_account = goa_object_peek_account (goa_object);
                user = goa_account_dup_identity (goa_account);
                email = goa_account_dup_presentation_identity (goa_account);
 
-               suri = soup_uri_new (as_url);
+               suri = g_uri_parse (as_url, SOUP_HTTP_URI_FLAGS, NULL);
 
                g_object_set (
                        source_extension,
@@ -302,12 +302,12 @@ goa_ews_autodiscover_done_cb (GObject *source_object,
 
                g_object_set (
                        settings,
-                       "host", soup_uri_get_host (suri),
+                       "host", g_uri_get_host (suri),
                        "user", user,
                        "email", email,
                        NULL);
 
-               soup_uri_free (suri);
+               g_uri_unref (suri);
                g_free (user);
                g_free (email);
        } else {
diff --git a/src/services/evolution-source-registry/evolution-source-registry-migrate-sources.c 
b/src/services/evolution-source-registry/evolution-source-registry-migrate-sources.c
index 87c69c9c3..a2998f68f 100644
--- a/src/services/evolution-source-registry/evolution-source-registry-migrate-sources.c
+++ b/src/services/evolution-source-registry/evolution-source-registry-migrate-sources.c
@@ -140,7 +140,7 @@ struct _ParseData {
 
        /* Set by <source> tags. */
        gchar *mangled_uri;
-       SoupURI *soup_uri;
+       GUri *parsed_uri;
        PropertyFunc property_func;
 };
 
@@ -218,8 +218,8 @@ parse_data_free (ParseData *parse_data)
        g_free (parse_data->base_uri);
        g_free (parse_data->mangled_uri);
 
-       if (parse_data->soup_uri != NULL)
-               soup_uri_free (parse_data->soup_uri);
+       if (parse_data->parsed_uri != NULL)
+               g_uri_unref (parse_data->parsed_uri);
 
        g_slice_free (ParseData, parse_data);
 }
@@ -2263,38 +2263,38 @@ migrate_parse_caldav_property (ParseData *parse_data,
 static void
 migrate_parse_caldav_source (ParseData *parse_data)
 {
-       if (parse_data->soup_uri->host != NULL)
+       if (g_uri_get_host (parse_data->parsed_uri) != NULL)
                g_key_file_set_string (
                        parse_data->key_file,
                        E_SOURCE_EXTENSION_AUTHENTICATION,
-                       "Host", parse_data->soup_uri->host);
+                       "Host", g_uri_get_host (parse_data->parsed_uri));
 
        /* We may override this later if we see an "ssl" property. */
-       if (parse_data->soup_uri->port == 0)
-               parse_data->soup_uri->port = 80;
+       if (g_uri_get_port (parse_data->parsed_uri) < 0)
+               e_util_change_uri_port (&parse_data->parsed_uri, 80);
 
        g_key_file_set_integer (
                parse_data->key_file,
                E_SOURCE_EXTENSION_AUTHENTICATION,
-               "Port", parse_data->soup_uri->port);
+               "Port", g_uri_get_port (parse_data->parsed_uri));
 
-       if (parse_data->soup_uri->user != NULL)
+       if (g_uri_get_user (parse_data->parsed_uri) != NULL)
                g_key_file_set_string (
                        parse_data->key_file,
                        E_SOURCE_EXTENSION_AUTHENTICATION,
-                       "User", parse_data->soup_uri->user);
+                       "User", g_uri_get_user (parse_data->parsed_uri));
 
-       if (parse_data->soup_uri->path != NULL)
+       if (g_uri_get_path (parse_data->parsed_uri) != NULL)
                g_key_file_set_string (
                        parse_data->key_file,
                        E_SOURCE_EXTENSION_WEBDAV_BACKEND,
-                       "ResourcePath", parse_data->soup_uri->path);
+                       "ResourcePath", g_uri_get_path (parse_data->parsed_uri));
 
-       if (parse_data->soup_uri->query != NULL)
+       if (g_uri_get_query (parse_data->parsed_uri) != NULL)
                g_key_file_set_string (
                        parse_data->key_file,
                        E_SOURCE_EXTENSION_WEBDAV_BACKEND,
-                       "ResourceQuery", parse_data->soup_uri->query);
+                       "ResourceQuery", g_uri_get_query (parse_data->parsed_uri));
 
        parse_data->property_func = migrate_parse_caldav_property;
 }
@@ -2407,38 +2407,38 @@ migrate_parse_ldap_property (ParseData *parse_data,
 static void
 migrate_parse_ldap_source (ParseData *parse_data)
 {
-       if (parse_data->soup_uri->host != NULL)
+       if (g_uri_get_host (parse_data->parsed_uri) != NULL)
                g_key_file_set_string (
                        parse_data->key_file,
                        E_SOURCE_EXTENSION_AUTHENTICATION,
-                       "Host", parse_data->soup_uri->host);
+                       "Host", g_uri_get_host (parse_data->parsed_uri));
 
-       if (parse_data->soup_uri->port != 0)
+       if (g_uri_get_port (parse_data->parsed_uri) > 0)
                g_key_file_set_integer (
                        parse_data->key_file,
                        E_SOURCE_EXTENSION_AUTHENTICATION,
-                       "Port", parse_data->soup_uri->port);
+                       "Port", g_uri_get_port (parse_data->parsed_uri));
 
-       if (parse_data->soup_uri->user != NULL)
+       if (g_uri_get_user (parse_data->parsed_uri) != NULL)
                g_key_file_set_string (
                        parse_data->key_file,
                        E_SOURCE_EXTENSION_AUTHENTICATION,
-                       "User", parse_data->soup_uri->user);
+                       "User", g_uri_get_user (parse_data->parsed_uri));
 
        /* Skip the leading slash on the URI path to get the RootDn. */
-       if (parse_data->soup_uri->path != NULL)
+       if (g_uri_get_path (parse_data->parsed_uri) != NULL)
                g_key_file_set_string (
                        parse_data->key_file,
                        E_SOURCE_EXTENSION_LDAP_BACKEND,
-                       "RootDn", parse_data->soup_uri->path + 1);
+                       "RootDn", g_uri_get_path (parse_data->parsed_uri) + 1);
 
-       if (g_strcmp0 (parse_data->soup_uri->query, "?sub?") == 0)
+       if (g_strcmp0 (g_uri_get_query (parse_data->parsed_uri), "?sub?") == 0)
                g_key_file_set_string (
                        parse_data->key_file,
                        E_SOURCE_EXTENSION_LDAP_BACKEND,
                        "Scope", "subtree");
 
-       if (g_strcmp0 (parse_data->soup_uri->query, "?one?") == 0)
+       if (g_strcmp0 (g_uri_get_query (parse_data->parsed_uri), "?one?") == 0)
                g_key_file_set_string (
                        parse_data->key_file,
                        E_SOURCE_EXTENSION_LDAP_BACKEND,
@@ -2450,11 +2450,11 @@ migrate_parse_ldap_source (ParseData *parse_data)
 static void
 migrate_parse_vcf_source (ParseData *parse_data)
 {
-       if (parse_data->soup_uri->path != NULL)
+       if (g_uri_get_path (parse_data->parsed_uri) != NULL)
                g_key_file_set_string (
                        parse_data->key_file,
                        E_SOURCE_EXTENSION_VCF_BACKEND,
-                       "Path", parse_data->soup_uri->path);
+                       "Path", g_uri_get_path (parse_data->parsed_uri));
 
        /* VCF Backend has no special properties to parse. */
 }
@@ -2493,15 +2493,15 @@ migrate_parse_weather_source (ParseData *parse_data)
        /* Oh man, we actually try to shove a weather location into
         * a URI!  The station code winds up as the host component,
         * and the location name winds up as the path component. */
-       if (parse_data->soup_uri->host != NULL) {
+       if (g_uri_get_host (parse_data->parsed_uri) != NULL) {
                gchar *location;
 
-               if (parse_data->soup_uri->path != NULL)
+               if (g_uri_get_path (parse_data->parsed_uri) != NULL)
                        location = g_strconcat (
-                               parse_data->soup_uri->host,
-                               parse_data->soup_uri->path, NULL);
+                               g_uri_get_host (parse_data->parsed_uri),
+                               g_uri_get_path (parse_data->parsed_uri), NULL);
                else
-                       location = g_strdup (parse_data->soup_uri->host);
+                       location = g_strdup (g_uri_get_host (parse_data->parsed_uri));
 
                g_key_file_set_string (
                        parse_data->key_file,
@@ -2517,38 +2517,38 @@ migrate_parse_weather_source (ParseData *parse_data)
 static void
 migrate_parse_webcal_source (ParseData *parse_data)
 {
-       if (parse_data->soup_uri->host != NULL)
+       if (g_uri_get_host (parse_data->parsed_uri) != NULL)
                g_key_file_set_string (
                        parse_data->key_file,
                        E_SOURCE_EXTENSION_AUTHENTICATION,
-                       "Host", parse_data->soup_uri->host);
+                       "Host", g_uri_get_host (parse_data->parsed_uri));
 
        /* We may override this later if we see an "ssl" property. */
-       if (parse_data->soup_uri->port == 0)
-               parse_data->soup_uri->port = 80;
+       if (g_uri_get_port (parse_data->parsed_uri) < 0)
+               e_util_change_uri_port (&parse_data->parsed_uri, 80);
 
        g_key_file_set_integer (
                parse_data->key_file,
                E_SOURCE_EXTENSION_AUTHENTICATION,
-               "Port", parse_data->soup_uri->port);
+               "Port", g_uri_get_port (parse_data->parsed_uri));
 
-       if (parse_data->soup_uri->user != NULL)
+       if (g_uri_get_user (parse_data->parsed_uri) != NULL)
                g_key_file_set_string (
                        parse_data->key_file,
                        E_SOURCE_EXTENSION_AUTHENTICATION,
-                       "User", parse_data->soup_uri->user);
+                       "User", g_uri_get_user (parse_data->parsed_uri));
 
-       if (parse_data->soup_uri->path != NULL)
+       if (g_uri_get_path (parse_data->parsed_uri) != NULL)
                g_key_file_set_string (
                        parse_data->key_file,
                        E_SOURCE_EXTENSION_WEBDAV_BACKEND,
-                       "ResourcePath", parse_data->soup_uri->path);
+                       "ResourcePath", g_uri_get_path (parse_data->parsed_uri));
 
-       if (parse_data->soup_uri->query != NULL)
+       if (g_uri_get_query (parse_data->parsed_uri) != NULL)
                g_key_file_set_string (
                        parse_data->key_file,
                        E_SOURCE_EXTENSION_WEBDAV_BACKEND,
-                       "ResourceQuery", parse_data->soup_uri->query);
+                       "ResourceQuery", g_uri_get_query (parse_data->parsed_uri));
 
        /* Webcal Backend has no special properties to parse. */
 }
@@ -2570,35 +2570,35 @@ migrate_parse_webdav_property (ParseData *parse_data,
 static void
 migrate_parse_webdav_source (ParseData *parse_data)
 {
-       if (parse_data->soup_uri->host != NULL)
+       if (g_uri_get_host (parse_data->parsed_uri) != NULL)
                g_key_file_set_string (
                        parse_data->key_file,
                        E_SOURCE_EXTENSION_AUTHENTICATION,
-                       "Host", parse_data->soup_uri->host);
+                       "Host", g_uri_get_host (parse_data->parsed_uri));
 
-       if (parse_data->soup_uri->port != 0)
+       if (g_uri_get_port (parse_data->parsed_uri) > 0)
                g_key_file_set_integer (
                        parse_data->key_file,
                        E_SOURCE_EXTENSION_AUTHENTICATION,
-                       "Port", parse_data->soup_uri->port);
+                       "Port", g_uri_get_port (parse_data->parsed_uri));
 
-       if (parse_data->soup_uri->user != NULL)
+       if (g_uri_get_user (parse_data->parsed_uri) != NULL)
                g_key_file_set_string (
                        parse_data->key_file,
                        E_SOURCE_EXTENSION_AUTHENTICATION,
-                       "User", parse_data->soup_uri->user);
+                       "User", g_uri_get_user (parse_data->parsed_uri));
 
-       if (parse_data->soup_uri->path != NULL)
+       if (g_uri_get_path (parse_data->parsed_uri) != NULL)
                g_key_file_set_string (
                        parse_data->key_file,
                        E_SOURCE_EXTENSION_WEBDAV_BACKEND,
-                       "ResourcePath", parse_data->soup_uri->path);
+                       "ResourcePath", g_uri_get_path (parse_data->parsed_uri));
 
-       if (parse_data->soup_uri->query != NULL)
+       if (g_uri_get_query (parse_data->parsed_uri) != NULL)
                g_key_file_set_string (
                        parse_data->key_file,
                        E_SOURCE_EXTENSION_WEBDAV_BACKEND,
-                       "ResourceQuery", parse_data->soup_uri->query);
+                       "ResourceQuery", g_uri_get_query (parse_data->parsed_uri));
 
        parse_data->property_func = migrate_parse_webdav_property;
 }
@@ -2780,7 +2780,7 @@ migrate_parse_source (ParseData *parse_data,
                uri_string = g_strconcat (
                        parse_data->base_uri, "/", relative_uri, NULL);
 
-       parse_data->soup_uri = soup_uri_new (uri_string);
+       parse_data->parsed_uri = g_uri_parse (uri_string, SOUP_HTTP_URI_FLAGS, NULL);
 
        /* Mangle the URI to not contain invalid characters.  We'll need
         * this later to rename the source's cache and data directories. */
@@ -2790,7 +2790,7 @@ migrate_parse_source (ParseData *parse_data,
         * now owns 'uri_string'.  Clear the pointer to emphasize that. */
        uri_string = NULL;
 
-       if (parse_data->soup_uri == NULL) {
+       if (parse_data->parsed_uri == NULL) {
                g_warning (
                        "  Failed to parse source URI: %s",
                        (absolute_uri != NULL) ? absolute_uri : relative_uri);
@@ -2825,9 +2825,9 @@ migrate_parse_source (ParseData *parse_data,
 
        migrate_keyring_entry (
                uid,
-               parse_data->soup_uri->user,
-               parse_data->soup_uri->host,
-               parse_data->soup_uri->scheme);
+               g_uri_get_user (parse_data->parsed_uri),
+               g_uri_get_host (parse_data->parsed_uri),
+               g_uri_get_scheme (parse_data->parsed_uri));
 }
 
 static void
@@ -2949,7 +2949,7 @@ migrate_parse_property (ParseData *parse_data,
                 * (http://) by default.  If we see that and we're
                 * using a secure connection, bump the port to 443
                 * (https://). */
-               if (parse_data->soup_uri->port == 80)
+               if (g_uri_get_port (parse_data->parsed_uri) == 80)
                        if (is_true (property_value))
                                g_key_file_set_integer (
                                        parse_data->key_file,
@@ -2968,7 +2968,7 @@ migrate_parse_property (ParseData *parse_data,
                 * (http://) by default.  If we see that and we're
                 * using a secure connection, bump the port to 443
                 * (https://). */
-               if (parse_data->soup_uri->port == 80)
+               if (g_uri_get_port (parse_data->parsed_uri) == 80)
                        if (is_true (property_value))
                                g_key_file_set_integer (
                                        parse_data->key_file,
@@ -3134,7 +3134,7 @@ migrate_parse_source_xml_end_element (GMarkupParseContext *context,
                        g_free (parse_data->mangled_uri);
                        parse_data->mangled_uri = NULL;
 
-                       g_clear_pointer (&parse_data->soup_uri, soup_uri_free);
+                       g_clear_pointer (&parse_data->parsed_uri, g_uri_unref);
 
                        parse_data->property_func = NULL;
 
diff --git a/src/vala/CMakeLists.txt b/src/vala/CMakeLists.txt
index caf940374..d68893e1d 100644
--- a/src/vala/CMakeLists.txt
+++ b/src/vala/CMakeLists.txt
@@ -105,7 +105,7 @@ set(gir_dirs
 set(vala_deps
        *camel-${API_VERSION}
        gio-2.0
-       libsoup-2.4
+       libsoup-3.0
        libxml-2.0
        posix
        ${LIBGDATA_VAPI}
@@ -137,7 +137,7 @@ set(gir_dirs
 set(vala_deps
        *libedataserver-${API_VERSION}
        gio-2.0
-       libsoup-2.4
+       libsoup-3.0
        libxml-2.0
        posix
 )
@@ -168,7 +168,7 @@ set(vala_deps
        *camel-${API_VERSION}
        *libedataserver-${API_VERSION}
        gio-2.0
-       libsoup-2.4
+       libsoup-3.0
        libxml-2.0
        posix
 )
@@ -203,7 +203,7 @@ set(vala_deps
        *libedataserver-${API_VERSION}
        *libebook-contacts-${API_VERSION}
        gio-2.0
-       libsoup-2.4
+       libsoup-3.0
        libxml-2.0
        posix
 )
@@ -238,7 +238,7 @@ set(vala_deps
        *libebackend-${API_VERSION}
        *libebook-contacts-${API_VERSION}
        gio-2.0
-       libsoup-2.4
+       libsoup-3.0
        libxml-2.0
        posix
 )
@@ -271,7 +271,7 @@ set(vala_deps
        *libedataserver-${API_VERSION}
        gio-2.0
        libical-glib
-       libsoup-2.4
+       libsoup-3.0
        libxml-2.0
        posix
 )
@@ -308,7 +308,7 @@ set(vala_deps
        *libecal-${CAL_API_VERSION}
        gio-2.0
        libical-glib
-       libsoup-2.4
+       libsoup-3.0
        libxml-2.0
        posix
 )
@@ -342,7 +342,7 @@ if(HAVE_GTK)
                *libecal-${CAL_API_VERSION}
                gio-2.0
                gtk+-3.0
-               libsoup-2.4
+               libsoup-3.0
                libxml-2.0
                posix
        )


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