[gvfs] dav, http: port to libsoup3



commit beaaf78b72640f8231f49fdfc1b6dcfc3d14f149
Author: Daniel Kolesa <dkolesa igalia com>
Date:   Thu Feb 11 22:43:53 2021 +0100

    dav, http: port to libsoup3
    
    The dav and http backends of the daemon now use libsoup3. Things
    should work more or less the same as before.
    
    One caveat is that the soup session no longer defaults to
    ssl-strict, so it will no longer silently accept certificates.
    This does not affect the DAV backend (it has its own handling
    which is replicated in the soup3 port) but it does affect the
    http backend.
    
    Fixes: https://gitlab.gnome.org/GNOME/gvfs/-/issues/208

 daemon/gvfsbackenddav.c      | 1584 +++++++++++++++++++++++-------------------
 daemon/gvfsbackendhttp.c     |  250 +++----
 daemon/gvfsbackendhttp.h     |   16 +-
 daemon/gvfshttpinputstream.c |   63 +-
 daemon/gvfshttpinputstream.h |    3 +-
 meson.build                  |    2 +-
 6 files changed, 1052 insertions(+), 866 deletions(-)
---
diff --git a/daemon/gvfsbackenddav.c b/daemon/gvfsbackenddav.c
index 12de62e5..559b8657 100644
--- a/daemon/gvfsbackenddav.c
+++ b/daemon/gvfsbackenddav.c
@@ -1,6 +1,7 @@
 /* GIO - GLib Input, Output and Streaming Library
  * 
  * Copyright (C) 2008 Red Hat, Inc.
+ * Copyright (C) 2021 Igalia S.L.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -66,10 +67,6 @@
 #include "gvfsdnssdresolver.h"
 #endif
 
-/* Overwrite maximal number of connections that libsoup can open in one time in
-   order to prevent backend lockups when too many files is opened concurrently. */
-#define MAX_CONNS 32
-
 typedef struct _MountAuthData MountAuthData;
 
 static void mount_auth_info_free (MountAuthData *info);
@@ -79,6 +76,12 @@ static void mount_auth_info_free (MountAuthData *info);
 static void dns_sd_resolver_changed  (GVfsDnsSdResolver *resolver, GVfsBackendDav *dav_backend);
 #endif
 
+static gboolean
+soup_authenticate (SoupMessage *msg,
+                   SoupAuth    *auth,
+                   gboolean     retrying,
+                   gpointer     user_data);
+
 typedef struct _AuthInfo {
 
    /* for server authentication */
@@ -95,6 +98,7 @@ struct _MountAuthData {
   SoupSession  *session;
   GMountSource *mount_source;
   gboolean retrying_after_403;
+  gboolean interactive;
 
   AuthInfo server_auth;
   AuthInfo proxy_auth;
@@ -164,7 +168,8 @@ string_to_uint64 (const char *str, guint64 *value)
 static inline gboolean
 sm_has_header (SoupMessage *msg, const char *header)
 {
-  return soup_message_headers_get_one (msg->response_headers, header) != NULL;
+  return soup_message_headers_get_one (soup_message_get_response_headers (msg),
+                                       header) != NULL;
 }
 
 static char *
@@ -193,12 +198,12 @@ path_get_parent_dir (const char *path)
 
 static void
 message_add_destination_header (SoupMessage *msg,
-                                SoupURI     *uri)
+                                GUri     *uri)
 {
   char *string;
 
-  string = soup_uri_to_string (uri, FALSE);
-  soup_message_headers_append (msg->request_headers,
+  string = g_uri_to_string_partial (uri, G_URI_HIDE_PASSWORD);
+  soup_message_headers_append (soup_message_get_request_headers (msg),
                                "Destination",
                                string);
   g_free (string);
@@ -207,7 +212,7 @@ static void
 message_add_overwrite_header (SoupMessage *msg,
                               gboolean     overwrite)
 {
-  soup_message_headers_append (msg->request_headers,
+  soup_message_headers_append (soup_message_get_request_headers (msg),
                                "Overwrite",
                                overwrite ? "T" : "F");
 }
@@ -224,7 +229,7 @@ message_add_redirect_header (SoupMessage         *msg,
   else
       header_redirect = "T";
 
-  soup_message_headers_append (msg->request_headers,
+  soup_message_headers_append (soup_message_get_request_headers (msg),
                                "Apply-To-Redirect-Ref",
                                header_redirect);
 }
@@ -267,21 +272,21 @@ path_equal (const char *a, const char *b, gboolean relax)
   return res;
 }
 
-/* Like soup_uri_equal */
 static gboolean
-dav_uri_match (SoupURI *a, SoupURI *b, gboolean relax)
+dav_uri_match (GUri *a, GUri *b, gboolean relax)
 {
   gboolean diff;
   char *ua, *ub;
 
-  ua = g_uri_unescape_string (a->path, "/");
-  ub = g_uri_unescape_string (b->path, "/");
+  ua = g_uri_unescape_string (g_uri_get_path (a), "/");
+  ub = g_uri_unescape_string (g_uri_get_path (b), "/");
 
-  diff = a->scheme != b->scheme || a->port != b->port  ||
-    ! str_equal (a->host, b->host, TRUE)               ||
-    ! path_equal (ua, ub, relax)                       ||
-    ! str_equal (a->query, b->query, FALSE)            ||
-    ! str_equal (a->fragment, b->fragment, FALSE);
+  diff = g_uri_get_port (a) != g_uri_get_port (b) ||
+         !str_equal (g_uri_get_scheme (a), g_uri_get_scheme (b), FALSE) ||
+         !str_equal (g_uri_get_host (a), g_uri_get_host (b), TRUE) ||
+         !path_equal (ua, ub, relax) ||
+         !str_equal (g_uri_get_query (a), g_uri_get_query (b), FALSE) ||
+         !str_equal (g_uri_get_fragment (a), g_uri_get_fragment (b), FALSE);
 
   g_free (ua);
   g_free (ub);
@@ -307,7 +312,7 @@ message_should_apply_redir_ref (SoupMessage *msg)
 {
   const char *header;
 
-  header = soup_message_headers_get_one (msg->request_headers,
+  header = soup_message_headers_get_one (soup_message_get_request_headers (msg),
                                          "Apply-To-Redirect-Ref");
 
   if (header == NULL || g_ascii_strcasecmp (header, "T"))
@@ -316,23 +321,38 @@ message_should_apply_redir_ref (SoupMessage *msg)
   return TRUE;
 }
 
+static GUri *
+dav_uri_dup_with (GUri *uri, const char *path, const char *userinfo)
+{
+  if (!path && !userinfo)
+    return g_uri_ref (uri);
+
+  return g_uri_build (g_uri_get_flags (uri),
+                      g_uri_get_scheme (uri),
+                      userinfo ? userinfo : g_uri_get_userinfo (uri),
+                      g_uri_get_host (uri),
+                      g_uri_get_port (uri),
+                      path ? path : g_uri_get_path (uri),
+                      g_uri_get_query (uri),
+                      g_uri_get_fragment (uri));
+}
+
 
-static SoupURI *
+static GUri *
 g_vfs_backend_dav_uri_for_path (GVfsBackend *backend,
                                 const char  *path,
                                 gboolean     is_dir)
 {
-  SoupURI *mount_base;
-  SoupURI *uri;
-  char    *fn_encoded;
-  char    *new_path;
+  GUri *mount_base;
+  GUri *uri;
+  char *fn_encoded;
+  char *new_path;
 
   mount_base = http_backend_get_mount_base (backend);
-  uri = soup_uri_copy (mount_base);
 
   /* "/" means "whatever mount_base is" */
   if (!strcmp (path, "/"))
-    return uri;
+    return g_uri_ref (mount_base);
 
   /* The mount_base path is escaped already so we need to
      escape the new path as well */
@@ -345,139 +365,154 @@ g_vfs_backend_dav_uri_for_path (GVfsBackend *backend,
    * to be a directory to avoid redirections
    */
   if (is_dir == FALSE || g_str_has_suffix (path, "/"))
-    new_path = g_build_path ("/", uri->path, fn_encoded, NULL);
+    new_path = g_build_path ("/", g_uri_get_path (mount_base), fn_encoded, NULL);
   else
-    new_path = g_build_path ("/", uri->path, fn_encoded, "/", NULL);
+    new_path = g_build_path ("/", g_uri_get_path (mount_base), fn_encoded, "/", NULL);
+
+  uri = dav_uri_dup_with (mount_base, new_path, NULL);
 
   g_free (fn_encoded);
-  g_free (uri->path);
-  uri->path = new_path;
+  g_free (new_path);
 
   return uri;
 }
 
-/* redirection */
-static void
-redirect_handler (SoupMessage *msg, gpointer user_data)
+static gboolean
+g_vfs_backend_dav_stream_skip (GInputStream *stream, GError **error)
 {
-    SoupSession *session = user_data;
-    const char  *new_loc;
-    SoupURI     *new_uri;
-    SoupURI     *old_uri;
-    guint        status;
-    gboolean     redirect;
+  for (;;)
+    {
+      gssize skipped = g_input_stream_skip (stream, 4096, NULL, error);
+      if (skipped < 0)
+        {
+          return FALSE;
+        }
+      else if (!skipped)
+        break;
+    }
 
-    status = msg->status_code;
-    new_loc = soup_message_headers_get_one (msg->response_headers, "Location");
+  g_input_stream_close (stream, NULL, NULL);
+  return TRUE;
+}
 
-    /* If we don't have a location to redirect to, just fail */
-    if (new_loc == NULL)
-      return;
+/* redirection */
+static GInputStream *
+g_vfs_backend_dav_redirect (SoupSession  *session,
+                            SoupMessage  *msg,
+                            GError      **error)
+{
+  GInputStream *res;
+  const char *new_loc;
+  GUri *new_uri;
+  GUri *old_uri;
+  GUri *tmp;
+  guint status;
+  gboolean redirect;
 
-    if (!SOUP_STATUS_IS_REDIRECTION(status))
-      return;
+  res = soup_session_send (session, msg, NULL, error);
+  if (!res)
+    return NULL;
 
-   new_uri = soup_uri_new_with_base (soup_message_get_uri (msg), new_loc);
-   if (new_uri == NULL)
-     {
-       soup_message_set_status_full (msg,
-                                     SOUP_STATUS_MALFORMED,
-                                     "Invalid Redirect URL");
-       return;
-     }
-
-   old_uri = soup_message_get_uri (msg);
-
-   /* copy over username and password to new_uri */
-   soup_uri_set_user(new_uri, old_uri->user);
-   soup_uri_set_password(new_uri, old_uri->password);
-
-   /* Check if this is a trailing slash redirect (i.e. /a/b to /a/b/),
-    * redirect it right away
-    */
-   redirect = dav_uri_match (new_uri, old_uri, TRUE);
-
-   if (redirect == TRUE)
-     {
-       const char *dest;
-
-       dest = soup_message_headers_get_one (msg->request_headers,
-                                            "Destination");
-
-       if (dest && g_str_has_suffix (dest, "/") == FALSE)
-         {
-           char *new_dest = g_strconcat (dest, "/", NULL);
-           soup_message_headers_replace (msg->request_headers,
-                                         "Destination",
-                                         new_dest);
-           g_free (new_dest);
-         }
-     }
-   else if (message_should_apply_redir_ref (msg))
-     {
-
-
-       if (status == SOUP_STATUS_MOVED_PERMANENTLY ||
-           status == SOUP_STATUS_TEMPORARY_REDIRECT)
-         {
-
-           /* Only corss-site redirect safe methods */
-           if (msg->method == SOUP_METHOD_GET &&
-               msg->method == SOUP_METHOD_HEAD &&
-               msg->method == SOUP_METHOD_OPTIONS &&
-               msg->method == SOUP_METHOD_PROPFIND)
-             redirect = TRUE;
-         }
-
-#if 0
-       else if (msg->status_code == SOUP_STATUS_SEE_OTHER ||
-                msg->status_code == SOUP_STATUS_FOUND)
-         {
-           /* Redirect using a GET */
-           g_object_set (msg,
-                         SOUP_MESSAGE_METHOD, SOUP_METHOD_GET,
-                         NULL);
-           soup_message_set_request (msg, NULL,
-                                     SOUP_MEMORY_STATIC, NULL, 0);
-           soup_message_headers_set_encoding (msg->request_headers,
-                                              SOUP_ENCODING_NONE);
-         }
-#endif
-         /* ELSE:
-          *
-          * Two possibilities:
-          *
-          *   1) It's a non-redirecty 3xx response (300, 304,
-          *      305, 306)
-          *   2) It's some newly-defined 3xx response (308+)
-          *
-          * We ignore both of these cases. In the first,
-          * redirecting would be explicitly wrong, and in the
-          * last case, we have no clue if the 3xx response is
-          * supposed to be redirecty or non-redirecty. Plus,
-          * 2616 says unrecognized status codes should be
-          * treated as the equivalent to the x00 code, and we
-          * don't redirect on 300, so therefore we shouldn't
-          * redirect on 308+ either.
-          */
-     }
-
-    if (redirect)
-      {
-        soup_message_set_uri (msg, new_uri);
-        soup_session_requeue_message (session, msg);
-      }
+  status = soup_message_get_status (msg);
+  if (!SOUP_STATUS_IS_REDIRECTION (status))
+    return res;
+
+  new_loc = soup_message_headers_get_one (soup_message_get_response_headers (msg),
+                                          "Location");
+  if (new_loc == NULL)
+    return res;
+
+  old_uri = soup_message_get_uri (msg);
+  new_uri = g_uri_parse_relative (old_uri, new_loc,
+                                  SOUP_HTTP_URI_FLAGS, error);
+  if (new_uri == NULL)
+    {
+      g_object_unref (res);
+      return NULL;
+    }
+
+  tmp = new_uri;
+  new_uri = dav_uri_dup_with (new_uri, NULL, g_uri_get_userinfo (old_uri));
+  g_uri_unref (tmp);
+
+  /* Check if this is a trailing slash redirect (i.e. /a/b to /a/b/),
+   * redirect it right away
+   */
+  redirect = dav_uri_match (new_uri, old_uri, TRUE);
+  if (redirect)
+    {
+      const char *dest;
+
+      dest = soup_message_headers_get_one (soup_message_get_request_headers (msg),
+                                           "Destination");
+      if (dest && g_str_has_suffix (dest, "/") == FALSE)
+        {
+          char *new_dest = g_strconcat (dest, "/", NULL);
+          soup_message_headers_replace (soup_message_get_request_headers (msg),
+                                        "Destination",
+                                        new_dest);
+          g_free (new_dest);
+        }
+    }
+  else if (message_should_apply_redir_ref (msg))
+    {
+      if (status == SOUP_STATUS_MOVED_PERMANENTLY ||
+          status == SOUP_STATUS_TEMPORARY_REDIRECT)
+        {
+          const char *method = soup_message_get_method (msg);
+
+          /* Only cross-site redirect safe methods */
+          if (method == SOUP_METHOD_GET &&
+              method == SOUP_METHOD_HEAD &&
+              method == SOUP_METHOD_OPTIONS &&
+              method == SOUP_METHOD_PROPFIND)
+            redirect = TRUE;
+        }
+
+        /* Two possibilities:
+         *
+         *   1) It's a non-redirecty 3xx response (300, 304,
+         *      305, 306)
+         *   2) It's some newly-defined 3xx response (308+)
+         *
+         * We ignore both of these cases. In the first,
+         * redirecting would be explicitly wrong, and in the
+         * last case, we have no clue if the 3xx response is
+         * supposed to be redirecty or non-redirecty. Plus,
+         * 2616 says unrecognized status codes should be
+         * treated as the equivalent to the x00 code, and we
+         * don't redirect on 300, so therefore we shouldn't
+         * redirect on 308+ either.
+         */
+    }
+
+  if (!redirect)
+    {
+      g_uri_unref (new_uri);
+      return res;
+    }
+
+  if (!g_vfs_backend_dav_stream_skip (res, error))
+    {
+      g_object_unref (res);
+      return NULL;
+    }
+
+  g_object_unref (res);
+
+  soup_message_set_uri (msg, new_uri);
 
-    soup_uri_free (new_uri);
+  return g_vfs_backend_dav_redirect (session, msg, error);
 }
 
 static void
 g_vfs_backend_dav_setup_display_name (GVfsBackend *backend)
 {
   GVfsBackendDav *dav_backend;
-  SoupURI        *mount_base;
+  GUri           *mount_base;
   char           *display_name;
   char            port[7] = {0, };
+  gint            gport;
 
   dav_backend = G_VFS_BACKEND_DAV (backend);
 
@@ -493,83 +528,86 @@ g_vfs_backend_dav_setup_display_name (GVfsBackend *backend)
 
   mount_base = http_backend_get_mount_base (backend);
 
-  if (! soup_uri_uses_default_port (mount_base))
-    g_snprintf (port, sizeof (port), ":%u", mount_base->port);
+  gport = g_uri_get_port (mount_base);
+  if ((gport > 0) && (gport != 80) && (gport != 443))
+    g_snprintf (port, sizeof (port), ":%u", g_uri_get_port (mount_base));
 
-  if (mount_base->user != NULL)
+  if (g_uri_get_user (mount_base) != NULL)
     /* Translators: This is the name of the WebDAV share constructed as
        "WebDAV as <username> on <hostname>:<port>"; the ":<port>" part is
        the second %s and only shown if it is not the default http(s) port. */
     display_name = g_strdup_printf (_("%s on %s%s"),
-                                   mount_base->user,
-                                   mount_base->host,
-                                   port);
+                                    g_uri_get_user (mount_base),
+                                    g_uri_get_host (mount_base),
+                                    port);
   else
     display_name = g_strdup_printf ("%s%s",
-                                   mount_base->host,
-                                   port);
+                                    g_uri_get_host (mount_base),
+                                    port);
 
   g_vfs_backend_set_display_name (backend, display_name);
   g_free (display_name);
 }
 
-static void
-certificate_error_handler (SoupMessage *msg,
-                           GParamSpec *pspec,
-                           gpointer user_data)
+static gboolean
+accept_certificate (SoupMessage         *msg,
+                    GTlsCertificate     *certificate,
+                    GTlsCertificateFlags errors,
+                    gpointer             user_data)
 {
   GVfsBackendDav *dav = G_VFS_BACKEND_DAV (user_data);
-  GTlsCertificate *certificate;
-  GTlsCertificateFlags errors;
 
-  /* Fail the message if the certificate errors change or the certificate is
-   * different. */
-  if (soup_message_get_https_status (msg, &certificate, &errors))
-    {
-      if (errors != dav->certificate_errors ||
-          !g_tls_certificate_is_same (certificate, dav->certificate))
-        {
-          soup_session_cancel_message (G_VFS_BACKEND_HTTP (dav)->session,
-                                       msg,
-                                       SOUP_STATUS_SSL_FAILED);
-        }
-    }
+  return (errors == dav->certificate_errors &&
+          g_tls_certificate_is_same (certificate, dav->certificate));
 }
 
-static guint
-g_vfs_backend_dav_send_message (GVfsBackend *backend, SoupMessage *message)
+static void
+dav_message_connect_signals (SoupMessage *message, GVfsBackend *backend)
 {
-  GVfsBackendHttp *http_backend;
-  SoupSession     *session;
+  GVfsBackendDav *dav_backend = G_VFS_BACKEND_DAV (backend);
+
+  /* we always have to connect this as the message can be
+   * re-sent with a differently set certificate_errors field
+   */
+  g_signal_connect (message, "accept-certificate",
+                    G_CALLBACK (accept_certificate), backend);
 
-  http_backend = G_VFS_BACKEND_HTTP (backend);
-  session = http_backend->session;
+  g_signal_connect (message, "authenticate",
+                    G_CALLBACK (soup_authenticate),
+                    &dav_backend->auth_info);
+}
+
+static GInputStream *
+g_vfs_backend_dav_send (GVfsBackend *backend,
+                        SoupMessage *message,
+                        gboolean     cb_connect,
+                        GError     **error)
+{
+  SoupSession *session = G_VFS_BACKEND_HTTP (backend)->session;
 
   /* We have our own custom redirect handler */
   soup_message_set_flags (message, SOUP_MESSAGE_NO_REDIRECT);
 
-  if (G_VFS_BACKEND_DAV (backend)->certificate_errors)
-    g_signal_connect (message, "notify::tls-errors",
-                      G_CALLBACK (certificate_error_handler), backend);
+  if (cb_connect)
+    dav_message_connect_signals (message, backend);
 
-  soup_message_add_header_handler (message, "got_body", "Location",
-                                   G_CALLBACK (redirect_handler), session);
-
-  return http_backend_send_message (backend, message);
+  return g_vfs_backend_dav_redirect (session, message, error);
 }
 
 static void
-g_vfs_backend_dav_queue_message (GVfsBackend *backend,
-                                 SoupMessage *msg,
-                                 SoupSessionCallback callback,
-                                 gpointer user_data)
+g_vfs_backend_dav_send_async (GVfsBackend *backend,
+                              SoupMessage *message,
+                              gboolean     cb_connect,
+                              GAsyncReadyCallback callback,
+                              gpointer user_data)
 {
-  if (G_VFS_BACKEND_DAV (backend)->certificate_errors)
-    g_signal_connect (msg, "notify::tls-errors",
-                      G_CALLBACK (certificate_error_handler), backend);
+  SoupSession *session = G_VFS_BACKEND_HTTP (backend)->session;
+
+  if (cb_connect)
+    dav_message_connect_signals (message, backend);
 
-  soup_session_queue_message (G_VFS_BACKEND_HTTP (backend)->session, msg,
-                              callback, user_data);
+  soup_session_send_async (session, message, G_PRIORITY_DEFAULT, NULL,
+                           callback, user_data);
 }
 
 /* ************************************************************************* */
@@ -692,33 +730,38 @@ xml_node_iter_get_current (xmlNodeIter *iter)
   return iter->cur_node;
 }
 
+static int
+xml_read_cb (void *ctx, char *buf, int len)
+{
+  return g_input_stream_read (ctx, buf, len, NULL, NULL);
+}
+
 static xmlDocPtr
 parse_xml (SoupMessage  *msg,
+           GInputStream *body,
            xmlNodePtr   *root,
            const char   *name,
            GError      **error)
 {
- xmlDocPtr  doc;
+  xmlDocPtr doc;
 
-  if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code))
+  if (!SOUP_STATUS_IS_SUCCESSFUL (soup_message_get_status (msg)))
     {
       g_set_error (error,
                    G_IO_ERROR,
-                   http_error_code_from_status (msg->status_code),
-                   _("HTTP Error: %s"), msg->reason_phrase);
+                   http_error_code_from_status (soup_message_get_status (msg)),
+                   _("HTTP Error: %s"), soup_message_get_reason_phrase (msg));
       return NULL;
     }
 
-  doc = xmlReadMemory (msg->response_body->data,
-                       msg->response_body->length,
-                       "response.xml",
-                       NULL,
-                       XML_PARSE_NONET |
-                       XML_PARSE_NOWARNING |
-                       XML_PARSE_NOBLANKS |
-                       XML_PARSE_NSCLEAN |
-                       XML_PARSE_NOCDATA |
-                       XML_PARSE_COMPACT);
+  doc = xmlReadIO (xml_read_cb, NULL, body, "response.xml", NULL,
+                   XML_PARSE_NONET |
+                   XML_PARSE_NOWARNING |
+                   XML_PARSE_NOBLANKS |
+                   XML_PARSE_NSCLEAN |
+                   XML_PARSE_NOCDATA |
+                   XML_PARSE_COMPACT);
+
   if (doc == NULL)
     { 
       g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
@@ -759,7 +802,7 @@ struct _Multistatus {
   xmlDocPtr  doc;
   xmlNodePtr root;
 
-  SoupURI *target;
+  GUri    *target;
   char    *path;
 
 };
@@ -784,13 +827,16 @@ struct _MsPropstat {
 
 
 static gboolean
-multistatus_parse (SoupMessage *msg, Multistatus *multistatus, GError **error)
+multistatus_parse (SoupMessage  *msg,
+                   GInputStream *body,
+                   Multistatus  *multistatus,
+                   GError      **error)
 {
   xmlDocPtr   doc;
   xmlNodePtr  root;
-  SoupURI    *uri;
+  GUri       *uri;
 
-  doc = parse_xml (msg, &root, "multistatus", error);
+  doc = parse_xml (msg, body, &root, "multistatus", error);
 
   if (doc == NULL)
     return FALSE;
@@ -800,7 +846,7 @@ multistatus_parse (SoupMessage *msg, Multistatus *multistatus, GError **error)
   multistatus->doc = doc;
   multistatus->root = root;
   multistatus->target = uri;
-  multistatus->path = g_uri_unescape_string (uri->path, "/");
+  multistatus->path = g_uri_unescape_string (g_uri_get_path (uri), "/");
 
   return TRUE;
 }
@@ -830,7 +876,7 @@ multistatus_get_response (xmlNodeIter *resp_iter, MsResponse *response)
   xmlNodePtr   iter;
   xmlNodePtr   href;
   xmlNodePtr   propstat;
-  SoupURI     *uri;
+  GUri        *uri;
   const char  *text;
   char        *path;
 
@@ -871,13 +917,12 @@ multistatus_get_response (xmlNodeIter *resp_iter, MsResponse *response)
   if (text == NULL)
     return FALSE;
 
-  uri = soup_uri_new_with_base (multistatus->target, text);
-
+  uri = g_uri_parse_relative (multistatus->target, text, SOUP_HTTP_URI_FLAGS, NULL);
   if (uri == NULL)
     return FALSE;
 
-  path = g_uri_unescape_string (uri->path, "/");
-  soup_uri_free (uri);
+  path = g_uri_unescape_string (g_uri_get_path (uri), "/");
+  g_uri_unref (uri);
 
   response->path = path;
   response->is_target = path_equal (path, multistatus->path, TRUE);
@@ -1102,16 +1147,16 @@ ms_response_to_file_info (MsResponse *response,
             }
           else if (node_has_name (node, "getlastmodified"))
             {
-              SoupDate *sd;
+              GDateTime *gd;
 
-             sd = soup_date_new_from_string(text);
-             if (sd)
-               {
-                  g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_MODIFIED, 
soup_date_to_time_t (sd));
+              gd = soup_date_time_new_from_http_string (text);
+              if (gd)
+                {
+                  g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_MODIFIED, 
g_date_time_to_unix (gd));
                   g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC, 0);
-                 soup_date_free (sd);
-               }
-           }
+                  g_date_time_unref (gd);
+                }
+            }
         }
     }
 
@@ -1250,6 +1295,19 @@ typedef struct _PropName {
 
 } PropName;
 
+static void
+propfind_stat_msg_starting_restarted (SoupMessage *msg, gpointer user_data)
+{
+  soup_message_set_request_body_from_bytes (msg, "application/xml", user_data);
+}
+
+static void
+propfind_stat_bytes_unref (gpointer data, GClosure *closure)
+{
+  (void)closure;
+  g_bytes_unref (data);
+}
+
 
 static SoupMessage *
 propfind_request_new (GVfsBackend     *backend,
@@ -1258,13 +1316,14 @@ propfind_request_new (GVfsBackend     *backend,
                       const PropName  *properties)
 {
   SoupMessage *msg;
-  SoupURI     *uri;
+  GUri        *uri;
   const char  *header_depth;
   GString     *body;
+  GBytes      *bytes;
 
   uri = g_vfs_backend_dav_uri_for_path (backend, filename, depth > 0);
   msg = soup_message_new_from_uri (SOUP_METHOD_PROPFIND, uri);
-  soup_uri_free (uri);
+  g_uri_unref (uri);
 
   if (msg == NULL)
     return NULL;
@@ -1276,7 +1335,8 @@ propfind_request_new (GVfsBackend     *backend,
   else
     header_depth = "infinity";
 
-  soup_message_headers_append (msg->request_headers, "Depth", header_depth);
+  soup_message_headers_append (soup_message_get_request_headers (msg),
+                               "Depth", header_depth);
 
   body = g_string_new (PROPSTAT_XML_BEGIN);
 
@@ -1302,22 +1362,29 @@ propfind_request_new (GVfsBackend     *backend,
 
   g_string_append (body, PROPSTAT_XML_END);
 
-  soup_message_set_request (msg, "application/xml",
-                            SOUP_MEMORY_TAKE,
-                            body->str,
-                            body->len);
+  bytes = g_string_free_to_bytes (body);
+
+  g_signal_connect_data (msg, "starting",
+                         G_CALLBACK (propfind_stat_msg_starting_restarted),
+                         g_bytes_ref (bytes), propfind_stat_bytes_unref, 0);
 
-  g_string_free (body, FALSE);
+  /* only called with implicit redirects enabled */
+  g_signal_connect_data (msg, "restarted",
+                         G_CALLBACK (propfind_stat_msg_starting_restarted),
+                         g_bytes_ref (bytes), propfind_stat_bytes_unref, 0);
+
+  g_bytes_unref (bytes);
 
   return msg;
 }
 
 static SoupMessage *
-stat_location_begin (SoupURI  *uri,
-                     gboolean  count_children)
+stat_location_begin (GUri      *uri,
+                     gboolean   count_children)
 {
   SoupMessage       *msg;
   const char        *depth;
+  GBytes            *bytes;
   static const char *stat_profind_body =
     PROPSTAT_XML_BEGIN
     PROPSTAT_XML_PROP_BEGIN
@@ -1333,33 +1400,42 @@ stat_location_begin (SoupURI  *uri,
   else
     depth = "0";
 
-  soup_message_headers_append (msg->request_headers, "Depth", depth);
+  soup_message_headers_append (soup_message_get_request_headers (msg),
+                               "Depth", depth);
+
+  bytes = g_bytes_new (stat_profind_body, strlen (stat_profind_body));
+
+  g_signal_connect_data (msg, "starting",
+                         G_CALLBACK (propfind_stat_msg_starting_restarted),
+                         g_bytes_ref (bytes), propfind_stat_bytes_unref, 0);
+
+  /* only called with implicit redirects enabled */
+  g_signal_connect_data (msg, "restarted",
+                         G_CALLBACK (propfind_stat_msg_starting_restarted),
+                         g_bytes_ref (bytes), propfind_stat_bytes_unref, 0);
+
+  g_bytes_unref (bytes);
 
-  soup_message_set_request (msg, "application/xml",
-                            SOUP_MEMORY_STATIC,
-                            stat_profind_body,
-                            strlen (stat_profind_body));
   return msg;
 }
 
 static gboolean
-stat_location_finish (SoupMessage *msg,
-                      GFileType   *target_type,
-                      gint64      *target_size,
-                      guint       *num_children)
+stat_location_finish (SoupMessage  *msg,
+                      GInputStream *body,
+                      GFileType    *target_type,
+                      gint64       *target_size,
+                      guint        *num_children)
 {
   Multistatus  ms;
   xmlNodeIter  iter;
   gboolean     res;
-  GError      *error;
   guint        child_count;
   GFileInfo   *file_info;
 
-  if (msg->status_code != 207)
+  if (!body || soup_message_get_status (msg) != SOUP_STATUS_MULTI_STATUS)
     return FALSE;
 
-  res = multistatus_parse (msg, &ms, &error);
-
+  res = multistatus_parse (msg, body, &ms, NULL);
   if (res == FALSE)
     return FALSE;
 
@@ -1405,43 +1481,52 @@ stat_location_finish (SoupMessage *msg,
 
 static gboolean
 stat_location (GVfsBackend  *backend,
-               SoupURI      *uri,
+               GUri         *uri,
                GFileType    *target_type,
                gint64       *target_size,
                guint        *num_children,
                GError      **error)
 {
   SoupMessage *msg;
-  guint        status;
-  gboolean     count_children;
-  gboolean     res;
+  GInputStream *body;
+  guint status;
+  gboolean count_children;
+  gboolean res;
 
   count_children = num_children != NULL;
   msg = stat_location_begin (uri, count_children);
-
   if (msg == NULL)
     return FALSE;
 
-  status = g_vfs_backend_dav_send_message (backend, msg);
+  body = g_vfs_backend_dav_send (backend, msg, TRUE, error);
 
-  if (status != 207)
+  if (!body)
+    {
+      g_object_unref (msg);
+      return FALSE;
+    }
+
+  status = soup_message_get_status (msg);
+  if (status != SOUP_STATUS_MULTI_STATUS)
     {
       g_set_error_literal (error,
-                          G_IO_ERROR,
-                          http_error_code_from_status (status),
-                          msg->reason_phrase);
+                           G_IO_ERROR,
+                           http_error_code_from_status (status),
+                           soup_message_get_reason_phrase (msg));
 
       g_object_unref (msg);
+      g_object_unref (body);
       return FALSE;
     }
 
-  res = stat_location_finish (msg, target_type, target_size, num_children);
+  res = stat_location_finish (msg, body, target_type, target_size, num_children);
   g_object_unref (msg);
+  g_object_unref (body);
 
   if (res == FALSE)
-    g_set_error_literal (error, 
-                        G_IO_ERROR, G_IO_ERROR_FAILED,
-                        _("Response invalid"));
+    g_set_error_literal (error,
+                         G_IO_ERROR, G_IO_ERROR_FAILED,
+                         _("Response invalid"));
 
   return res;
 }
@@ -1464,38 +1549,11 @@ mount_auth_info_free (MountAuthData *data)
 
 }
 
-static void
-soup_authenticate_from_data (SoupSession *session,
-                             SoupMessage *msg,
-                             SoupAuth    *auth,
-                             gboolean     retrying,
-                             gpointer     user_data)
-{
-  MountAuthData *data;
-  AuthInfo      *info;
-
-  g_debug ("+ soup_authenticate_from_data (%s) \n",
-           retrying ? "retrying" : "first auth");
-
-  if (retrying)
-    return;
-
-  data = (MountAuthData *) user_data;
-
-  if (soup_auth_is_for_proxy (auth))
-    info = &data->proxy_auth;
-  else
-    info = &data->server_auth;
-
-  soup_auth_authenticate (auth, info->username, info->password);
-}
-
-static void
-soup_authenticate_interactive (SoupSession *session,
-                               SoupMessage *msg,
-                               SoupAuth    *auth,
-                               gboolean     retrying,
-                               gpointer     user_data)
+static gboolean
+soup_authenticate (SoupMessage *msg,
+                   SoupAuth    *auth,
+                   gboolean     retrying,
+                   gpointer     user_data)
 {
   MountAuthData     *data;
   AuthInfo          *info;
@@ -1512,9 +1570,28 @@ soup_authenticate_interactive (SoupSession *session,
 
   data = (MountAuthData *) user_data;
 
-  retrying = (retrying || data->retrying_after_403);
+  is_proxy = soup_auth_is_for_proxy (auth);
+
+  if (is_proxy)
+    info = &(data->proxy_auth);
+  else
+    info = &(data->server_auth);
+
+  if (!data->interactive)
+    {
+      g_debug ("+ soup_authenticate (%s) \n",
+               retrying ? "retrying" : "first auth");
+
+      if (!retrying)
+        soup_auth_authenticate (auth, info->username, info->password);
+
+      return FALSE;
+    }
 
-  g_debug ("+ soup_authenticate_interactive (%s) \n",
+  if (data->retrying_after_403)
+    retrying = TRUE;
+
+  g_debug ("+ soup_authenticate (interactive, %s) \n",
            retrying ? "retrying" : "first auth");
 
   new_username = NULL;
@@ -1522,43 +1599,53 @@ soup_authenticate_interactive (SoupSession *session,
   realm        = NULL;
   pw_ask_flags = G_ASK_PASSWORD_NEED_PASSWORD;
 
-  is_proxy = soup_auth_is_for_proxy (auth);
   realm    = soup_auth_get_realm (auth);
 
-  if (is_proxy)
-    info = &(data->proxy_auth);
-  else
-    info = &(data->server_auth);
-
   if (realm && info->realm == NULL)
     info->realm = g_strdup (realm);
   else if (realm && info->realm && !g_str_equal (realm, info->realm))
-    return;
+    return FALSE;
 
   have_auth = info->username && info->password;
 
   if (have_auth == FALSE && g_vfs_keyring_is_available ())
     {
-      SoupURI *uri; 
-      SoupURI *uri_free = NULL;
+      const char *host;
+      gchar *hostp = NULL;
+      gint port;
 
       pw_ask_flags |= G_ASK_PASSWORD_SAVING_SUPPORTED;
 
       if (is_proxy)
         {
-          g_object_get (session, SOUP_SESSION_PROXY_URI, &uri_free, NULL);
-          uri = uri_free;
+          gboolean ret;
+          gchar *urip;
+
+          urip = g_strdup_printf ("http://%s";, soup_auth_get_authority (auth));
+          ret = g_uri_split_network (urip, G_URI_FLAGS_NONE,
+                                     NULL, &hostp, &port, NULL);
+          g_free (urip);
+
+          if (!ret)
+            return FALSE;
+
+          host = hostp;
         }
       else
-        uri = soup_message_get_uri (msg);
+        {
+          GUri *uri = soup_message_get_uri (msg);
+
+          host = g_uri_get_host (uri);
+          port = g_uri_get_port (uri);
+        }
 
       res = g_vfs_keyring_lookup_password (info->username,
-                                           uri->host,
+                                           host,
                                            NULL,
                                            "http",
                                            realm,
                                            is_proxy ? "proxy" : "basic",
-                                           uri->port,
+                                           port,
                                            &new_username,
                                            NULL,
                                            &new_password);
@@ -1572,14 +1659,14 @@ soup_authenticate_interactive (SoupSession *session,
           info->password = new_password;
         }
 
-      if (uri_free)
-        soup_uri_free (uri_free);
+      if (hostp)
+        g_free (hostp);
     }
 
   if (retrying == FALSE && have_auth)
     {
       soup_auth_authenticate (auth, info->username, info->password);
-      return;
+      return FALSE;
     }
 
   if (is_proxy == FALSE)
@@ -1624,41 +1711,46 @@ soup_authenticate_interactive (SoupSession *session,
       info->pw_save  = pw_save;
     }
   else
-    soup_session_cancel_message (session, msg, SOUP_STATUS_CANCELLED);
+    soup_auth_cancel (auth);
 
   g_debug ("- soup_authenticate \n");
   g_free (prompt);
+
+  return !res || aborted;
 }
 
 static void
 keyring_save_authinfo (AuthInfo *info,
-                       SoupURI  *uri,
+                       GUri     *uri,
                        gboolean  is_proxy)
 {
   const char *type = is_proxy ? "proxy" : "basic";
 
   g_vfs_keyring_save_password (info->username,
-                               uri->host,
+                               g_uri_get_host (uri),
                                NULL,
                                "http",
                                info->realm,
                                type,
-                               uri->port,
+                               g_uri_get_port (uri),
                                info->password,
                                info->pw_save);
 }
 
 /* ************************************************************************* */
 
-static SoupURI *
+static GUri *
 g_mount_spec_to_dav_uri (GMountSpec *spec)
 {
-  SoupURI        *uri;
+  GUri           *uri;
   const char     *host;
   const char     *user;
   const char     *port;
   const char     *ssl;
   const char     *path;
+  const char     *scheme;
+  char           *host_str;
+  char           *path_str;
   gint            port_num;
 
   host = g_mount_spec_get (spec, "host");
@@ -1670,37 +1762,51 @@ g_mount_spec_to_dav_uri (GMountSpec *spec)
   if (host == NULL || *host == 0)
     return NULL;
 
-  uri = soup_uri_new (NULL);
-
   if (ssl != NULL && (strcmp (ssl, "true") == 0))
-    soup_uri_set_scheme (uri, SOUP_URI_SCHEME_HTTPS);
+    scheme = "https";
   else
-    soup_uri_set_scheme (uri, SOUP_URI_SCHEME_HTTP);
+    scheme = "http";
 
-  soup_uri_set_user (uri, user);
+  port_num = -1;
+
+  /* always a valid number if set */
+  if (port != NULL)
+    port_num = atoi (port);
 
   /* IPv6 host does not include brackets in SoupURI, but GMountSpec host does */
   if (gvfs_is_ipv6 (host))
-    uri->host = g_strndup (host + 1, strlen (host) - 2);
+    host_str = g_strndup (host + 1, strlen (host) - 2);
   else
-    soup_uri_set_host (uri, host);
+    host_str = g_strdup (host);
 
-  if (port && (port_num = atoi (port)))
-    soup_uri_set_port (uri, port_num);
+  path_str = dav_uri_encode (path);
 
-  g_free (uri->path);
-  uri->path = dav_uri_encode (path);
+  uri = g_uri_build_with_user (SOUP_HTTP_URI_FLAGS,
+                               scheme,
+                               user,
+                               NULL,
+                               NULL,
+                               host_str,
+                               port_num,
+                               path_str,
+                               NULL,
+                               NULL);
+
+  g_free (host_str);
+  g_free (path_str);
 
   return uri;
 }
 
 static GMountSpec *
 g_mount_spec_from_dav_uri (GVfsBackendDav *dav_backend,
-                           SoupURI *uri)
+                           GUri *uri)
 {
   GMountSpec *spec;
-  const char *ssl;
-  char       *local_path;
+  char *local_path;
+  gboolean ssl;
+  const gchar *user;
+  gint port_num;
 
 #ifdef HAVE_AVAHI
   if (dav_backend->resolver != NULL)
@@ -1724,36 +1830,35 @@ g_mount_spec_from_dav_uri (GVfsBackendDav *dav_backend,
 
   spec = g_mount_spec_new ("dav");
 
-  /* IPv6 host does not include brackets in SoupURI, but GMountSpec host does */
-  if (strchr (uri->host, ':'))
+  /* IPv6 host does not include brackets in GUri, but GMountSpec host does */
+  if (strchr (g_uri_get_host (uri), ':'))
     {
-      char *host = g_strdup_printf ("[%s]", uri->host);
+      char *host = g_strdup_printf ("[%s]", g_uri_get_host (uri));
       g_mount_spec_set (spec, "host", host);
       g_free (host);
     }
   else
-    g_mount_spec_set (spec, "host", uri->host);
+    g_mount_spec_set (spec, "host", g_uri_get_host (uri));
 
-  if (uri->scheme == SOUP_URI_SCHEME_HTTPS)
-    ssl = "true";
-  else
-    ssl = "false";
+  ssl = !strcmp (g_uri_get_scheme (uri), "https");
 
-  g_mount_spec_set (spec, "ssl", ssl);
+  g_mount_spec_set (spec, "ssl", ssl ? "true" : "false");
 
-  if (uri->user)
-    g_mount_spec_set (spec, "user", uri->user);
+  user = g_uri_get_user (uri);
+  if (user != NULL)
+    g_mount_spec_set (spec, "user", user);
 
-  if (! soup_uri_uses_default_port (uri))
+  port_num = g_uri_get_port (uri);
+  if (port_num > 0 && port_num != (ssl ? 443 : 80))
     {
-      char *port = g_strdup_printf ("%u", uri->port);
+      char *port = g_strdup_printf ("%d", port_num);
       g_mount_spec_set (spec, "port", port);
       g_free (port);
     }
 
   /* There must not be any illegal characters in the
      URL at this point */
-  local_path = g_uri_unescape_string (uri->path, "/");
+  local_path = g_uri_unescape_string (g_uri_get_path (uri), "/");
   g_mount_spec_set_mount_prefix (spec, local_path);
   g_free (local_path);
 
@@ -1761,15 +1866,17 @@ g_mount_spec_from_dav_uri (GVfsBackendDav *dav_backend,
 }
 
 #ifdef HAVE_AVAHI
-static SoupURI *
+static GUri *
 dav_uri_from_dns_sd_resolver (GVfsBackendDav *dav_backend)
 {
-  SoupURI    *uri;
+  GUri       *uri;
   char       *user;
   char       *path;
   char       *address;
+  char       *host;
   gchar      *interface;
   const char *service_type;
+  const char *scheme;
   guint       port;
 
   service_type = g_vfs_dns_sd_resolver_get_service_type (dav_backend->resolver);
@@ -1783,42 +1890,42 @@ dav_uri_from_dns_sd_resolver (GVfsBackendDav *dav_backend)
    * there's also a TXT record "p" for password. Handle this.
    */
 
-  uri = soup_uri_new (NULL);
-
   if (strcmp (service_type, "_webdavs._tcp") == 0)
-    soup_uri_set_scheme (uri, SOUP_URI_SCHEME_HTTPS);
+    scheme = "https";
   else
-    soup_uri_set_scheme (uri, SOUP_URI_SCHEME_HTTP);
-
-  soup_uri_set_user (uri, user);
-
-  soup_uri_set_port (uri, port);
+    scheme = "http";
 
-  /* IPv6 host does not include brackets in SoupURI, but GVfsDnsSdResolver host does */
+  /* IPv6 host does not include brackets in GUri, but GVfsDnsSdResolver host does */
   if (gvfs_is_ipv6 (address))
     {
       /* Link-local addresses require interface to be specified. */
       if (g_str_has_prefix (address, "[fe80:") && interface != NULL)
         {
-          uri->host = g_strconcat (address + 1, interface, NULL);
-          uri->host[strlen (address) - 2] = '%';
+          host = g_strconcat (address + 1, interface, NULL);
+          host[strlen (address) - 2] = '%';
         }
       else
-        uri->host = g_strndup (address + 1, strlen (address) - 2);
+        host = g_strndup (address + 1, strlen (address) - 2);
     }
   else
-    soup_uri_set_host (uri, address);
-
-  if (path != NULL)
-    soup_uri_set_path (uri, path);
-  else
-    soup_uri_set_path (uri, "/");
+    host = g_strdup (address);
 
+  uri = g_uri_build_with_user (SOUP_HTTP_URI_FLAGS,
+                               scheme,
+                               user,
+                               NULL,
+                               NULL,
+                               host,
+                               port,
+                               path,
+                               NULL,
+                               NULL);
 
   g_free (address);
   g_free (interface);
   g_free (user);
   g_free (path);
+  g_free (host);
 
   return uri;
 }
@@ -1849,13 +1956,15 @@ do_mount (GVfsBackend  *backend,
   SoupSession    *session;
   SoupMessage    *msg_opts;
   SoupMessage    *msg_stat;
-  SoupURI        *mount_base;
-  gulong          signal_id;
+  GUri           *mount_base;
+  GUri           *tmp;
+  GError         *error = NULL;
   guint           status;
   gboolean        is_success;
   gboolean        is_webdav;
   gboolean        is_collection;
-  gboolean        auth_interactive;
+  gboolean        sig_opts = TRUE;
+  gboolean        sig_stat = TRUE;
   gboolean        res;
   char           *last_good_path;
   const char     *host;
@@ -1870,11 +1979,8 @@ do_mount (GVfsBackend  *backend,
   /* resolve DNS-SD style URIs */
   if ((strcmp (type, "dav+sd") == 0 || strcmp (type, "davs+sd") == 0) && host != NULL)
     {
-      GError *error;
-
       dav_backend->resolver = g_vfs_dns_sd_resolver_new_for_encoded_triple (host, "u");
 
-      error = NULL;
       if (!g_vfs_dns_sd_resolver_resolve_sync (dav_backend->resolver,
                                                NULL,
                                                &error))
@@ -1905,28 +2011,17 @@ do_mount (GVfsBackend  *backend,
     }
 
   session = G_VFS_BACKEND_HTTP (backend)->session;
-  G_VFS_BACKEND_HTTP (backend)->mount_base = mount_base; 
+  G_VFS_BACKEND_HTTP (backend)->mount_base = mount_base;
 
   soup_session_add_feature_by_type (session, SOUP_TYPE_AUTH_NEGOTIATE);
   soup_session_add_feature_by_type (session, SOUP_TYPE_AUTH_NTLM);
 
-  /* Override the HTTP backend's default. */
-  g_object_set (session,
-                "ssl-strict", TRUE,
-                SOUP_SESSION_MAX_CONNS_PER_HOST, MAX_CONNS,
-                SOUP_SESSION_MAX_CONNS, MAX_CONNS,
-                NULL);
-
   data = &(G_VFS_BACKEND_DAV (backend)->auth_info); 
   data->mount_source = g_object_ref (mount_source);
-  data->server_auth.username = g_strdup (mount_base->user);
+  data->server_auth.username = g_strdup (g_uri_get_user (mount_base));
   data->server_auth.pw_save = G_PASSWORD_SAVE_NEVER;
   data->proxy_auth.pw_save = G_PASSWORD_SAVE_NEVER;
-
-  signal_id = g_signal_connect (session, "authenticate",
-                                G_CALLBACK (soup_authenticate_interactive),
-                                data);
-  auth_interactive = TRUE;
+  data->interactive = TRUE;
 
   last_good_path = NULL;
   msg_opts = soup_message_new_from_uri (SOUP_METHOD_OPTIONS, mount_base);
@@ -1936,12 +2031,16 @@ do_mount (GVfsBackend  *backend,
   msg_stat = stat_location_begin (mount_base, TRUE);
 
   do {
+    GInputStream *body;
     GFileType file_type;
-    SoupURI *cur_uri;
+    GUri *cur_uri;
+    char *new_path;
 
     res = TRUE;
-    status = g_vfs_backend_dav_send_message (backend, msg_opts);
-    is_success = SOUP_STATUS_IS_SUCCESSFUL (status);
+    body = g_vfs_backend_dav_send (backend, msg_opts, sig_opts, &error);
+    sig_opts = FALSE;
+    status = body ? soup_message_get_status (msg_opts) : SOUP_STATUS_NONE;
+    is_success = body && SOUP_STATUS_IS_SUCCESSFUL (status);
     is_webdav = sm_has_header (msg_opts, "DAV");
 
     /* Workaround for servers which response with 403 instead of 401 in case of
@@ -1956,7 +2055,7 @@ do_mount (GVfsBackend  *backend,
         data->retrying_after_403 = TRUE;
 
         g_clear_pointer (&data->server_auth.username, g_free);
-        data->server_auth.username = g_strdup (mount_base->user);
+        data->server_auth.username = g_strdup (g_uri_get_user (mount_base));
         g_clear_pointer (&data->server_auth.password, g_free);
         g_clear_pointer (&data->proxy_auth.password, g_free);
 
@@ -1975,23 +2074,26 @@ do_mount (GVfsBackend  *backend,
      * gets a chance to override it. If they do, ssl-strict is disabled but
      * the certificate is stored, and checked on each subsequent connection to
      * ensure that it hasn't changed. */
-    if (status == SOUP_STATUS_SSL_FAILED &&
+    if (g_error_matches (error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE) &&
         !dav_backend->certificate_errors)
       {
         GTlsCertificate *certificate;
         GTlsCertificateFlags errors;
 
-        soup_message_get_https_status (msg_opts, &certificate, &errors);
-
+        certificate = soup_message_get_tls_peer_certificate (msg_opts);
+        errors = soup_message_get_tls_peer_certificate_errors (msg_opts);
         if (gvfs_accept_certificate (mount_source, certificate, errors))
           {
-            g_object_set (session, "ssl-strict", FALSE, NULL);
+            g_clear_error (&error);
             dav_backend->certificate = g_object_ref (certificate);
             dav_backend->certificate_errors = errors;
             continue;
           }
         else
           {
+            /* break the loop, if last_good_path is NULL then the error is
+             * propagated, otherwise it is cleared later by the else branch
+             */
             break;
           }
       }
@@ -1999,46 +2101,61 @@ do_mount (GVfsBackend  *backend,
     if (!is_success || !is_webdav)
       break;
 
-    soup_message_headers_clear (msg_opts->response_headers);
-    soup_message_body_truncate (msg_opts->response_body);
+    if (!g_vfs_backend_dav_stream_skip (body, &error))
+      {
+        g_object_unref (body);
+        break;
+      }
+
+    g_object_unref (body);
+
+    soup_message_headers_clear (soup_message_get_response_headers (msg_opts));
 
     cur_uri = soup_message_get_uri (msg_opts);
     soup_message_set_uri (msg_stat, cur_uri);
 
-    g_vfs_backend_dav_send_message (backend, msg_stat);
-    res = stat_location_finish (msg_stat, &file_type, NULL, NULL);
+    body = g_vfs_backend_dav_send (backend, msg_stat, sig_stat, NULL);
+    sig_stat = FALSE;
+    res = stat_location_finish (msg_stat, body, &file_type, NULL, NULL);
     is_collection = res && file_type == G_FILE_TYPE_DIRECTORY;
 
+    if (body && !g_vfs_backend_dav_stream_skip (body, &error))
+      {
+        g_object_unref (body);
+        break;
+      }
+
+    g_clear_object (&body);
+
+    soup_message_headers_clear (soup_message_get_response_headers (msg_stat));
+
     g_debug (" [%s] webdav: %d, collection %d [res: %d]\n",
-              mount_base->path, is_webdav, is_collection, res);
+             g_uri_get_path (mount_base), is_webdav, is_collection, res);
 
     if (is_collection == FALSE)
       break;
 
     /* we have found a new good root, try the parent ... */
     g_free (last_good_path);
-    last_good_path = mount_base->path;
-    mount_base->path = path_get_parent_dir (mount_base->path);
+    last_good_path = g_strdup (g_uri_get_path (mount_base));
+    new_path = path_get_parent_dir (last_good_path);
+
+    tmp = mount_base;
+    mount_base = dav_uri_dup_with (mount_base, new_path, NULL);
+    g_uri_unref (tmp);
+    G_VFS_BACKEND_HTTP (backend)->mount_base = mount_base;
+
+    g_free (new_path);
+
     soup_message_set_uri (msg_opts, mount_base);
 
-    if (auth_interactive)
-      {
-         /* if we have found a root that is good then we assume
-            that we also have obtained to correct credentials
-            and we switch the auth handler. This will prevent us
-            from asking for *different* credentials *again* if the
-            server should response with 401 for some of the parent
-            collections. See also bug #677753 */
-
-         g_signal_handler_disconnect (session, signal_id);
-         g_signal_connect (session, "authenticate",
-                           G_CALLBACK (soup_authenticate_from_data),
-                           data);
-         auth_interactive = FALSE;
-       }
-
-    soup_message_headers_clear (msg_stat->response_headers);
-    soup_message_body_truncate (msg_stat->response_body);
+    /* if we have found a root that is good then we assume
+       that we also have obtained to correct credentials
+       and we switch the auth handler. This will prevent us
+       from asking for *different* credentials *again* if the
+       server should response with 401 for some of the parent
+       collections. See also bug #677753 */
+    data->interactive = FALSE;
 
   } while (g_strcmp0 (last_good_path, "/") != 0);
 
@@ -2049,8 +2166,13 @@ do_mount (GVfsBackend  *backend,
   /* check if we at all have a good path */
   if (last_good_path == NULL)
     {
-      if ((is_success && !is_webdav) ||
-          msg_opts->status_code == SOUP_STATUS_METHOD_NOT_ALLOWED)
+      if (error)
+        {
+          g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
+          g_error_free (error);
+        }
+      else if ((is_success && !is_webdav) ||
+               soup_message_get_status (msg_opts) == SOUP_STATUS_METHOD_NOT_ALLOWED)
         {
           /* This means the either: a) OPTIONS request succeeded
              (which should be the case even for non-existent
@@ -2068,14 +2190,12 @@ do_mount (GVfsBackend  *backend,
           /* Either the OPTIONS request (is_success) or the PROPFIND
              request (res) failed. */
           SoupMessage *target = !is_success ? msg_opts : msg_stat;
-          int error_code = http_error_code_from_status (target->status_code);
-
-          if (error_code == G_IO_ERROR_CANCELLED)
-            error_code = G_IO_ERROR_FAILED_HANDLED;
+          int error_code = http_error_code_from_status (soup_message_get_status (target));
 
           g_vfs_job_failed (G_VFS_JOB (job),
                             G_IO_ERROR, error_code,
-                            _("HTTP Error: %s"), target->reason_phrase);
+                            _("HTTP Error: %s"),
+                            soup_message_get_reason_phrase (target));
         }
       else
         {
@@ -2091,6 +2211,8 @@ do_mount (GVfsBackend  *backend,
 
       return;
     }
+  else if (error)
+    g_error_free (error);
 
   /* Success! We are mounted */        
   /* Save the auth info in the keyring */
@@ -2099,8 +2221,12 @@ do_mount (GVfsBackend  *backend,
   /* TODO: save proxy auth */
 
   /* Set the working path in mount path */
-  g_free (mount_base->path);
-  mount_base->path = last_good_path;
+  tmp = mount_base;
+  mount_base = dav_uri_dup_with (mount_base, last_good_path, NULL);
+  g_uri_unref (tmp);
+  g_clear_pointer (&G_VFS_BACKEND_HTTP (backend)->mount_base, g_uri_unref);
+  G_VFS_BACKEND_HTTP (backend)->mount_base = mount_base;
+  g_free (last_good_path);
 
   /* dup the mountspec, but only copy known fields */
   mount_spec = g_mount_spec_from_dav_uri (dav_backend, mount_base);
@@ -2141,39 +2267,35 @@ do_query_info (GVfsBackend           *backend,
                GFileAttributeMatcher *matcher)
 {
   SoupMessage *msg;
-  Multistatus  ms;
-  xmlNodeIter  iter;
-  gboolean     res;
-  GError      *error;
-
-  error   = NULL;
+  GInputStream *body;
+  Multistatus ms;
+  xmlNodeIter iter;
+  gboolean res;
+  GError *error = NULL;
 
   g_debug ("Query info %s\n", filename);
 
   msg = propfind_request_new (backend, filename, 0, ls_propnames);
-
   if (msg == NULL)
     {
       g_vfs_job_failed (G_VFS_JOB (job),
                         G_IO_ERROR, G_IO_ERROR_FAILED,
                         _("Could not create request"));
-      
       return;
     }
 
   message_add_redirect_header (msg, flags);
 
-  g_vfs_backend_dav_send_message (backend, msg);
+  body = g_vfs_backend_dav_send (backend, msg, TRUE, &error);
+
+  if (!body)
+    goto error;
 
-  res = multistatus_parse (msg, &ms, &error);
+  res = multistatus_parse (msg, body, &ms, &error);
+  g_object_unref (body);
 
   if (res == FALSE)
-    {
-      g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
-      g_error_free (error);
-      g_object_unref (msg);
-      return;
-    }
+    goto error;
 
   res = FALSE;
   multistatus_get_response_iter (&ms, &iter);
@@ -2203,7 +2325,12 @@ do_query_info (GVfsBackend           *backend,
     g_vfs_job_failed (G_VFS_JOB (job),
                       G_IO_ERROR, G_IO_ERROR_FAILED,
                       _("Response invalid"));
+  return;
 
+ error:
+  g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
+  g_error_free (error);
+  g_object_unref (msg);
 }
 
 static PropName fs_info_propnames[] = {
@@ -2220,10 +2347,11 @@ do_query_fs_info (GVfsBackend           *backend,
                   GFileAttributeMatcher *attribute_matcher)
 {
   SoupMessage *msg;
-  Multistatus  ms;
-  xmlNodeIter  iter;
-  gboolean     res;
-  GError      *error;
+  GInputStream *body;
+  Multistatus ms;
+  xmlNodeIter iter;
+  gboolean res;
+  GError *error = NULL;
 
   g_file_info_set_attribute_string (info,
                                     G_FILE_ATTRIBUTE_FILESYSTEM_TYPE,
@@ -2247,7 +2375,6 @@ do_query_fs_info (GVfsBackend           *backend,
     }
 
   msg = propfind_request_new (backend, filename, 0, fs_info_propnames);
-
   if (msg == NULL)
     {
       g_vfs_job_failed (G_VFS_JOB (job),
@@ -2257,18 +2384,16 @@ do_query_fs_info (GVfsBackend           *backend,
       return;
     }
 
-  g_vfs_backend_dav_send_message (backend, msg);
+  body = g_vfs_backend_dav_send (backend, msg, TRUE, &error);
+
+  if (!body)
+    goto error;
 
-  error = NULL;
-  res = multistatus_parse (msg, &ms, &error);
+  res = multistatus_parse (msg, body, &ms, &error);
+  g_object_unref (body);
 
   if (res == FALSE)
-    {
-      g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
-      g_error_free (error);
-      g_object_unref (msg);
-      return;
-    }
+    goto error;
 
   res = FALSE;
   multistatus_get_response_iter (&ms, &iter);
@@ -2298,7 +2423,12 @@ do_query_fs_info (GVfsBackend           *backend,
     g_vfs_job_failed (G_VFS_JOB (job),
                       G_IO_ERROR, G_IO_ERROR_FAILED,
                       _("Response invalid"));
+  return;
 
+ error:
+  g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
+  g_error_free (error);
+  g_object_unref (msg);
 }
 
 /* *** enumerate *** */
@@ -2310,17 +2440,15 @@ do_enumerate (GVfsBackend           *backend,
               GFileQueryInfoFlags    flags)
 {
   SoupMessage *msg;
-  Multistatus  ms;
-  xmlNodeIter  iter;
-  gboolean     res;
-  GError      *error;
- 
-  error = NULL;
+  GInputStream *body;
+  Multistatus ms;
+  xmlNodeIter iter;
+  gboolean res;
+  GError *error = NULL;
 
   g_debug ("+ do_enumerate: %s\n", filename);
 
   msg = propfind_request_new (backend, filename, 1, ls_propnames);
-
   if (msg == NULL)
     {
       g_vfs_job_failed (G_VFS_JOB (job),
@@ -2332,17 +2460,17 @@ do_enumerate (GVfsBackend           *backend,
 
   message_add_redirect_header (msg, flags);
 
-  g_vfs_backend_dav_send_message (backend, msg);
+  body = g_vfs_backend_dav_send (backend, msg, TRUE, &error);
+
+  if (!body)
+    goto error;
 
-  res = multistatus_parse (msg, &ms, &error);
+  res = multistatus_parse (msg, body, &ms, &error);
+  g_object_unref (body);
 
   if (res == FALSE)
-    {
-      g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
-      g_error_free (error);
-      g_object_unref (msg);
-      return;
-    }
+    goto error;
+
   g_vfs_job_succeeded (G_VFS_JOB (job));
 
   multistatus_get_response_iter (&ms, &iter);
@@ -2370,6 +2498,12 @@ do_enumerate (GVfsBackend           *backend,
   g_object_unref (msg);
 
   g_vfs_job_enumerate_done (G_VFS_JOB_ENUMERATE (job));
+  return;
+
+ error:
+  g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
+  g_error_free (error);
+  g_object_unref (msg);
 }
 
 /* ************************************************************************* */
@@ -2377,37 +2511,51 @@ do_enumerate (GVfsBackend           *backend,
 
 /* *** open () *** */
 static void
-try_open_stat_done (SoupSession *session,
-                   SoupMessage *msg,
-                   gpointer     user_data)
+try_open_stat_done (GObject      *source,
+                    GAsyncResult *result,
+                    gpointer      user_data)
 {
-  GVfsJob         *job = G_VFS_JOB (user_data);
-  GVfsBackend     *backend = job->backend_data;
-  GFileType        target_type;
-  SoupURI         *uri;
-  gboolean         res;
+  GInputStream *body;
+  SoupSession *session = SOUP_SESSION (source);
+  SoupMessage *msg;
+  GVfsJob *job = G_VFS_JOB (user_data);
+  GVfsBackend *backend = job->backend_data;
+  GError *error = NULL;
+  GUri *uri;
+  GFileType target_type;
+  gboolean res;
 
-  if (msg->status_code != 207)
+  msg = soup_session_get_async_result_message (session, result);
+  if (soup_message_get_status (msg) != SOUP_STATUS_MULTI_STATUS)
     {
       http_job_failed (job, msg);
       return;
     }
 
-  res = stat_location_finish (msg, &target_type, NULL, NULL);
+  body = soup_session_send_finish (session, result, &error);
+  if (!body)
+    {
+      g_vfs_job_failed_from_error (job, error);
+      g_error_free (error);
+      return;
+    }
+
+  res = stat_location_finish (msg, body, &target_type, NULL, NULL);
+  g_object_unref (body);
 
   if (res == FALSE)
     {
       g_vfs_job_failed (job,
-                       G_IO_ERROR, G_IO_ERROR_FAILED,
-                       _("Response invalid"));
+                        G_IO_ERROR, G_IO_ERROR_FAILED,
+                        _("Response invalid"));
       return;
     }
 
   if (target_type == G_FILE_TYPE_DIRECTORY)
     {
       g_vfs_job_failed (job,
-                       G_IO_ERROR, G_IO_ERROR_IS_DIRECTORY,
-                       _("File is directory"));
+                        G_IO_ERROR, G_IO_ERROR_IS_DIRECTORY,
+                        _("File is directory"));
       return;
     }
 
@@ -2422,12 +2570,12 @@ try_open_for_read (GVfsBackend        *backend,
                    GVfsJobOpenForRead *job,
                    const char         *filename)
 {
-  SoupMessage     *msg;
-  SoupURI         *uri;
+  SoupMessage *msg;
+  GUri *uri;
 
   uri = g_vfs_backend_dav_uri_for_path (backend, filename, FALSE);
   msg = stat_location_begin (uri, FALSE);
-  soup_uri_free (uri);
+  g_uri_unref (uri);
 
   if (msg == NULL)
     {
@@ -2439,7 +2587,7 @@ try_open_for_read (GVfsBackend        *backend,
     }
 
   g_vfs_job_set_backend_data (G_VFS_JOB (job), backend, NULL);
-  g_vfs_backend_dav_queue_message (backend, msg, try_open_stat_done, job);
+  g_vfs_backend_dav_send_async (backend, msg, TRUE, try_open_stat_done, job);
 
   return TRUE;
 }
@@ -2449,16 +2597,29 @@ try_open_for_read (GVfsBackend        *backend,
 
 /* *** create () *** */
 static void
-try_create_tested_existence (SoupSession *session, SoupMessage *msg,
+try_create_tested_existence (GObject *source,
+                             GAsyncResult *result,
                              gpointer user_data)
 {
   GVfsJob *job = G_VFS_JOB (user_data);
-  GOutputStream   *stream;
-  SoupMessage     *put_msg;
-  SoupURI         *uri;
+  GOutputStream *stream;
+  GInputStream *body;
+  SoupMessage *msg = job->backend_data;
+  SoupMessage *put_msg;
+  GError *error = NULL;
+  GUri *uri;
 
-  if (SOUP_STATUS_IS_SUCCESSFUL (msg->status_code))
+  body = soup_session_send_finish (SOUP_SESSION (source), result, &error);
+  if (!body)
     {
+      g_vfs_job_failed_from_error (job, error);
+      g_error_free (error);
+      return;
+    }
+
+  if (SOUP_STATUS_IS_SUCCESSFUL (soup_message_get_status (msg)))
+    {
+      g_object_unref (body);
       g_vfs_job_failed (job,
                         G_IO_ERROR,
                         G_IO_ERROR_EXISTS,
@@ -2467,12 +2628,14 @@ try_create_tested_existence (SoupSession *session, SoupMessage *msg,
     }
   /* TODO: other errors */
 
+  g_object_unref (body);
+
   uri = soup_message_get_uri (msg);
   put_msg = soup_message_new_from_uri (SOUP_METHOD_PUT, uri);
 
   /* 
    * Doesn't work with apache > 2.2.9
-   * soup_message_headers_append (put_msg->request_headers, "If-None-Match", "*");
+   * soup_message_headers_append (soup_message_get_request_headers (put_msg), "If-None-Match", "*");
    */
   stream = g_memory_output_stream_new (NULL, 0, g_try_realloc, g_free);
   g_object_set_data_full (G_OBJECT (stream), "-gvfs-stream-msg", put_msg, g_object_unref);
@@ -2492,25 +2655,28 @@ try_create (GVfsBackend *backend,
             GFileCreateFlags flags)
 {
   SoupMessage *msg;
-  SoupURI     *uri;
+  GUri *uri;
 
   /* TODO: if we supported chunked requests, we could
    * use a PUT with "If-None-Match: *" and "Expect: 100-continue"
    */
   uri = g_vfs_backend_dav_uri_for_path (backend, filename, FALSE);
   msg = soup_message_new_from_uri (SOUP_METHOD_HEAD, uri);
-  soup_uri_free (uri);
+  g_uri_unref (uri);
 
-  g_vfs_job_set_backend_data (G_VFS_JOB (job), backend, NULL);
+  g_vfs_job_set_backend_data (G_VFS_JOB (job), msg, NULL);
+
+  g_vfs_backend_dav_send_async (backend, msg, TRUE, try_create_tested_existence, job);
 
-  g_vfs_backend_dav_queue_message (backend, msg, try_create_tested_existence, job);
   return TRUE;
 }
 
 /* *** replace () *** */
 static void
-open_for_replace_succeeded (GVfsBackendHttp *op_backend, GVfsJob *job,
-                            SoupURI *uri, const char *etag)
+open_for_replace_succeeded (GVfsBackendHttp *op_backend,
+                            GVfsJob         *job,
+                            GUri            *uri,
+                            const char      *etag)
 {
   SoupMessage     *put_msg;
   GOutputStream   *stream;
@@ -2518,7 +2684,9 @@ open_for_replace_succeeded (GVfsBackendHttp *op_backend, GVfsJob *job,
   put_msg = soup_message_new_from_uri (SOUP_METHOD_PUT, uri);
 
   if (etag)
-    soup_message_headers_append (put_msg->request_headers, "If-Match", etag);
+    soup_message_headers_append (soup_message_get_request_headers (put_msg),
+                                 "If-Match",
+                                 etag);
 
   stream = g_memory_output_stream_new (NULL, 0, g_try_realloc, g_free);
   g_object_set_data_full (G_OBJECT (stream), "-gvfs-stream-msg", put_msg, g_object_unref);
@@ -2532,14 +2700,29 @@ open_for_replace_succeeded (GVfsBackendHttp *op_backend, GVfsJob *job,
 }
 
 static void
-try_replace_checked_etag (SoupSession *session, SoupMessage *msg,
-                          gpointer user_data)
+try_replace_checked_etag (GObject      *source,
+                          GAsyncResult *result,
+                          gpointer      user_data)
 {
   GVfsJob *job = G_VFS_JOB (user_data);
   GVfsBackendHttp *op_backend = job->backend_data;
+  GInputStream *body;
+  SoupSession *session = SOUP_SESSION (source);
+  SoupMessage *msg;
+  GError *error;
 
-  if (msg->status_code == SOUP_STATUS_PRECONDITION_FAILED)
+  msg = soup_session_get_async_result_message (session, result);
+  body = soup_session_send_finish (session, result, &error);
+  if (!body)
     {
+      g_vfs_job_failed_from_error (job, error);
+      g_error_free (error);
+      return;
+    }
+
+  if (soup_message_get_status (msg) == SOUP_STATUS_PRECONDITION_FAILED)
+    {
+      g_object_unref (body);
       g_vfs_job_failed (G_VFS_JOB (job),
                         G_IO_ERROR,
                         G_IO_ERROR_WRONG_ETAG,
@@ -2548,8 +2731,11 @@ try_replace_checked_etag (SoupSession *session, SoupMessage *msg,
     }
   /* TODO: other errors */
 
+  g_object_unref (body);
+
   open_for_replace_succeeded (op_backend, job, soup_message_get_uri (msg),
-                              soup_message_headers_get_one (msg->request_headers, "If-Match"));
+                              soup_message_headers_get_one (soup_message_get_request_headers (msg),
+                                                            "If-Match"));
 }  
 
 static gboolean
@@ -2561,7 +2747,7 @@ try_replace (GVfsBackend *backend,
              GFileCreateFlags flags)
 {
   GVfsBackendHttp *op_backend;
-  SoupURI         *uri;
+  GUri *uri;
 
   /* TODO: if SoupOutputStream supported chunked requests, we could
    * use a PUT with "If-Match: ..." and "Expect: 100-continue"
@@ -2587,17 +2773,21 @@ try_replace (GVfsBackend *backend,
       SoupMessage *msg;
 
       msg = soup_message_new_from_uri (SOUP_METHOD_HEAD, uri);
-      soup_uri_free (uri);
-      soup_message_headers_append (msg->request_headers, "If-Match", etag);
+      g_uri_unref (uri);
+
+      soup_message_headers_append (soup_message_get_request_headers (msg),
+                                   "If-Match", etag);
 
       g_vfs_job_set_backend_data (G_VFS_JOB (job), op_backend, NULL);
-      g_vfs_backend_dav_queue_message (backend, msg,
-                                       try_replace_checked_etag, job);
+      g_vfs_backend_dav_send_async (backend, msg, TRUE,
+                                    try_replace_checked_etag, job);
+
       return TRUE;
     }
 
   open_for_replace_succeeded (op_backend, G_VFS_JOB (job), uri, NULL);
-  soup_uri_free (uri);
+  g_uri_unref (uri);
+
   return TRUE;
 }
 
@@ -2698,14 +2888,27 @@ do_truncate (GVfsBackend *backend,
 
 /* *** close_write () *** */
 static void
-try_close_write_sent (SoupSession *session,
-                     SoupMessage *msg,
-                     gpointer     user_data)
+try_close_write_sent (GObject      *source,
+                      GAsyncResult *result,
+                      gpointer      user_data)
 {
-  GVfsJob *job;
+  GInputStream *body;
+  GVfsJob *job = G_VFS_JOB (user_data);
+  SoupSession *session = SOUP_SESSION (source);
+  SoupMessage *msg = soup_session_get_async_result_message (session, result);
+  GError *error;
 
-  job = G_VFS_JOB (user_data);
-  if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code))
+  body = soup_session_send_finish (session, result, &error);
+  if (!body)
+    {
+      g_vfs_job_failed_from_error (job, error);
+      g_error_free (error);
+      return;
+    }
+
+  g_object_unref (body);
+
+  if (!SOUP_STATUS_IS_SUCCESSFUL (soup_message_get_status (msg)))
     http_job_failed (job, msg);
   else
     g_vfs_job_succeeded (job);
@@ -2718,8 +2921,7 @@ try_close_write (GVfsBackend *backend,
 {
   GOutputStream *stream;
   SoupMessage *msg;
-  gsize length;
-  gchar *data;
+  GBytes *bytes;
 
   stream = G_OUTPUT_STREAM (handle);
 
@@ -2728,13 +2930,13 @@ try_close_write (GVfsBackend *backend,
   g_object_set_data (G_OBJECT (stream), "-gvfs-stream-msg", NULL);
 
   g_output_stream_close (stream, NULL, NULL);
-  length = g_memory_output_stream_get_data_size (G_MEMORY_OUTPUT_STREAM (stream));
-  data = g_memory_output_stream_steal_data (G_MEMORY_OUTPUT_STREAM (stream));
+  bytes = g_memory_output_stream_steal_as_bytes (G_MEMORY_OUTPUT_STREAM (stream));
   g_object_unref (stream);
 
-  soup_message_body_append (msg->request_body, SOUP_MEMORY_TAKE, data, length);
-  g_vfs_backend_dav_queue_message (backend, msg,
-                                   try_close_write_sent, job);
+  soup_message_set_request_body_from_bytes (msg, NULL, bytes);
+  g_vfs_backend_dav_send_async (backend, msg, TRUE,
+                                try_close_write_sent, job);
+  g_bytes_unref (bytes);
 
   return TRUE;
 }
@@ -2744,15 +2946,26 @@ do_make_directory (GVfsBackend          *backend,
                    GVfsJobMakeDirectory *job,
                    const char           *filename)
 {
+  GInputStream *body;
   SoupMessage *msg;
-  SoupURI     *uri;
-  guint        status;
+  GUri *uri;
+  GError *error = NULL;
+  guint status;
 
   uri = g_vfs_backend_dav_uri_for_path (backend, filename, TRUE);
   msg = soup_message_new_from_uri (SOUP_METHOD_MKCOL, uri);
-  soup_uri_free (uri);
+  g_uri_unref (uri);
+
+  body = g_vfs_backend_dav_send (backend, msg, TRUE, &error);
+  if (!body)
+    {
+      g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
+      g_error_free (error);
+      g_object_unref (msg);
+      return;
+    }
 
-  status = g_vfs_backend_dav_send_message (backend, msg);
+  status = soup_message_get_status (msg);
 
   if (! SOUP_STATUS_IS_SUCCESSFUL (status))
     if (status == SOUP_STATUS_METHOD_NOT_ALLOWED)
@@ -2764,6 +2977,7 @@ do_make_directory (GVfsBackend          *backend,
   else
     g_vfs_job_succeeded (G_VFS_JOB (job));
 
+  g_object_unref (body);
   g_object_unref (msg);
 }
 
@@ -2772,24 +2986,22 @@ do_delete (GVfsBackend   *backend,
            GVfsJobDelete *job,
            const char    *filename)
 {
+  GInputStream *body;
   SoupMessage *msg;
-  SoupURI     *uri;
-  GFileType    file_type;
-  gboolean     res;
-  guint        num_children;
-  guint        status;
-  GError      *error;
-
-  error = NULL;
+  GUri *uri;
+  GFileType file_type;
+  gboolean res;
+  guint num_children;
+  guint status;
+  GError *error = NULL;
 
   uri = g_vfs_backend_dav_uri_for_path (backend, filename, FALSE);
   res = stat_location (backend, uri, &file_type, NULL, &num_children, &error);
-
   if (res == FALSE)
     {
       g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
       g_error_free (error);
-      soup_uri_free (uri);
+      g_uri_unref (uri);
       return;
     }
 
@@ -2798,21 +3010,30 @@ do_delete (GVfsBackend   *backend,
       g_vfs_job_failed (G_VFS_JOB (job),
                         G_IO_ERROR, G_IO_ERROR_NOT_EMPTY,
                         _("Directory not empty"));
-      soup_uri_free (uri);
+      g_uri_unref (uri);
       return;
     }
 
   msg = soup_message_new_from_uri (SOUP_METHOD_DELETE, uri);
+  body = g_vfs_backend_dav_send (backend, msg, TRUE, &error);
+  if (!body)
+    {
+      g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
+      g_error_free (error);
+      g_object_unref (msg);
+      g_uri_unref (uri);
+      return;
+    }
 
-  status = g_vfs_backend_dav_send_message (backend, msg);
-
+  status = soup_message_get_status (msg);
   if (!SOUP_STATUS_IS_SUCCESSFUL (status))
     http_job_failed (G_VFS_JOB (job), msg);
   else
     g_vfs_job_succeeded (G_VFS_JOB (job));
 
-  soup_uri_free (uri);
+  g_uri_unref (uri);
   g_object_unref (msg);
+  g_object_unref (body);
 }
 
 static void
@@ -2821,12 +3042,14 @@ do_set_display_name (GVfsBackend           *backend,
                      const char            *filename,
                      const char            *display_name)
 {
+  GInputStream *body;
   SoupMessage *msg;
-  SoupURI     *source;
-  SoupURI     *target;
-  char        *target_path;
-  char        *dirname;
-  guint        status;
+  GUri *source;
+  GUri *target;
+  char *target_path;
+  char *dirname;
+  GError *error = NULL;
+  guint status;
 
   source = g_vfs_backend_dav_uri_for_path (backend, filename, FALSE);
   msg = soup_message_new_from_uri (SOUP_METHOD_MOVE, source);
@@ -2838,7 +3061,14 @@ do_set_display_name (GVfsBackend           *backend,
   message_add_destination_header (msg, target);
   message_add_overwrite_header (msg, FALSE);
 
-  status = g_vfs_backend_dav_send_message (backend, msg);
+  body = g_vfs_backend_dav_send (backend, msg, TRUE, &error);
+  if (!body)
+    {
+      http_job_failed (G_VFS_JOB (job), msg);
+      goto error;
+    }
+
+  status = soup_message_get_status (msg);
 
   /*
    * The precondition of SOUP_STATUS_PRECONDITION_FAILED (412) in
@@ -2870,11 +3100,14 @@ do_set_display_name (GVfsBackend           *backend,
   else
     http_job_failed (G_VFS_JOB (job), msg);
 
+  g_object_unref (body);
+
+ error:
   g_object_unref (msg);
   g_free (dirname);
   g_free (target_path);
-  soup_uri_free (target);
-  soup_uri_free (source);
+  g_uri_unref (target);
+  g_uri_unref (source);
 }
 
 static void
@@ -2886,9 +3119,10 @@ do_move (GVfsBackend *backend,
          GFileProgressCallback progress_callback,
          gpointer progress_callback_data)
 {
+  GInputStream *body = NULL;
   SoupMessage *msg;
-  SoupURI *source_uri;
-  SoupURI *target_uri;
+  GUri *source_uri;
+  GUri *target_uri;
   guint status;
   GFileType source_ft, target_ft;
   GError *error = NULL;
@@ -2958,14 +3192,20 @@ do_move (GVfsBackend *backend,
 
                   msg = soup_message_new_from_uri (SOUP_METHOD_DELETE,
                                                    target_uri);
-                  status = g_vfs_backend_dav_send_message (backend, msg);
+                  body = g_vfs_backend_dav_send (backend, msg, TRUE, &error);
+                  if (!body)
+                    {
+                      g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
+                      goto error;
+                    }
 
+                  status = soup_message_get_status (msg);
                   if (!SOUP_STATUS_IS_SUCCESSFUL (status))
                     {
                       http_job_failed (G_VFS_JOB (job), msg);
-                      g_object_unref (msg);
                       goto error;
                     }
+                  g_object_unref (body);
                   g_object_unref (msg);
                 }
             }
@@ -2988,11 +3228,16 @@ do_move (GVfsBackend *backend,
   message_add_destination_header (msg, target_uri);
   message_add_overwrite_header (msg, flags & G_FILE_COPY_OVERWRITE);
 
-  status = g_vfs_backend_dav_send_message (backend, msg);
+  body = g_vfs_backend_dav_send (backend, msg, TRUE, &error);
+  if (!body)
+    {
+      g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
+      goto error;
+    }
 
   /* See do_set_display_name () for the explanation of the PRECONDITION_FAILED
    * and IS_REDIRECTION handling below. */
-
+  status = soup_message_get_status (msg);
   if (SOUP_STATUS_IS_SUCCESSFUL (status))
     {
       if (stat_res && progress_callback)
@@ -3007,11 +3252,12 @@ do_move (GVfsBackend *backend,
   else
     http_job_failed (G_VFS_JOB (job), msg);
 
-error:
+ error:
+  g_clear_object (&body);
   g_object_unref (msg);
   g_clear_error (&error);
-  soup_uri_free (source_uri);
-  soup_uri_free (target_uri);
+  g_uri_unref (source_uri);
+  g_uri_unref (target_uri);
 }
 
 static void
@@ -3023,9 +3269,10 @@ do_copy (GVfsBackend *backend,
          GFileProgressCallback progress_callback,
          gpointer progress_callback_data)
 {
+  GInputStream *body;
   SoupMessage *msg;
-  SoupURI *source_uri;
-  SoupURI *target_uri;
+  GUri *source_uri;
+  GUri *target_uri;
   guint status;
   GFileType source_ft, target_ft;
   GError *error = NULL;
@@ -3102,11 +3349,17 @@ do_copy (GVfsBackend *backend,
   message_add_destination_header (msg, target_uri);
   message_add_overwrite_header (msg, flags & G_FILE_COPY_OVERWRITE);
 
-  status = g_vfs_backend_dav_send_message (backend, msg);
+  body = g_vfs_backend_dav_send (backend, msg, TRUE, &error);
+  if (!body)
+    {
+      g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
+      g_object_unref (msg);
+      goto error;
+    }
 
   /* See do_set_display_name () for the explanation of the PRECONDITION_FAILED
    * and IS_REDIRECTION handling below. */
-
+  status = soup_message_get_status (msg);
   if (SOUP_STATUS_IS_SUCCESSFUL (status))
     {
       if (progress_callback)
@@ -3121,24 +3374,17 @@ do_copy (GVfsBackend *backend,
   else
     http_job_failed (G_VFS_JOB (job), msg);
 
+  g_object_unref (body);
   g_object_unref (msg);
 
 error:
   g_clear_error (&error);
-  soup_uri_free (source_uri);
-  soup_uri_free (target_uri);
+  g_uri_unref (source_uri);
+  g_uri_unref (target_uri);
 }
 
 #define CHUNK_SIZE 65536
 
-/* Used to keep track of the state of reads in flight when the restarted signal
- * is received. */
-typedef enum {
-  PUSH_READ_STATUS_NONE,
-  PUSH_READ_STATUS_RESET,
-  PUSH_READ_STATUS_DEFERRED,
-} PushReadStatus;
-
 typedef struct {
   /* Job details */
   GVfsBackend *backend;
@@ -3147,20 +3393,14 @@ typedef struct {
 
   /* Local file */
   GInputStream *in;
-  unsigned char *buf;
   goffset size;
-  goffset n_read;
-  PushReadStatus read_status;
 
   /* Remote file */
-  SoupURI *uri;
+  GUri *uri;
   SoupMessage *msg;
   goffset n_written;
 } PushHandle;
 
-static void
-push_write_next_chunk (SoupMessage *msg, gpointer user_data);
-
 static void
 push_handle_free (PushHandle *handle)
 {
@@ -3171,121 +3411,20 @@ push_handle_free (PushHandle *handle)
     }
   g_object_unref (handle->backend);
   g_object_unref (handle->job);
-  soup_uri_free (handle->uri);
-  g_slice_free (PushHandle, handle);
-}
+  g_object_unref (handle->msg);
+  g_uri_unref (handle->uri);
 
-static void
-push_read_cb (GObject *source, GAsyncResult *res, gpointer user_data)
-{
-  PushHandle *handle = user_data;
-  GError *error = NULL;
-  gssize n;
-
-  n = g_input_stream_read_finish (handle->in, res, &error);
-
-  /* Ignore this read if we've subsequently been restarted. */
-  if (handle->read_status != PUSH_READ_STATUS_NONE)
-    {
-      g_free (handle->buf);
-      handle->buf = NULL;
-
-      /* Queue another read if we've been subsequently restarted and
-       * push_write_next_chunk () was called in the meantime. */
-      if (handle->read_status == PUSH_READ_STATUS_DEFERRED)
-        push_write_next_chunk (handle->msg, handle);
-
-      return;
-    }
-
-  if (n > 0)
-    {
-      soup_message_body_append_take (handle->msg->request_body, handle->buf, n);
-      handle->buf = NULL;
-      handle->n_read += n;
-      soup_session_unpause_message (G_VFS_BACKEND_HTTP (handle->backend)->session,
-                                    handle->msg);
-    }
-  else if (n == 0)
-    {
-      g_free (handle->buf);
-      handle->buf = NULL;
-
-      if (handle->n_read != handle->size)
-        {
-          g_vfs_job_failed_literal (handle->job,
-                                    G_IO_ERROR,
-                                    G_IO_ERROR_FAILED,
-                                    _("File length changed during transfer"));
-
-          soup_session_cancel_message (G_VFS_BACKEND_HTTP (handle->backend)->session,
-                                       handle->msg,
-                                       SOUP_STATUS_CANCELLED);
-        }
-    }
-  else
-    {
-      g_free (handle->buf);
-      handle->buf = NULL;
-      g_vfs_job_failed_from_error (handle->job, error);
-      g_error_free (error);
-      soup_session_cancel_message (G_VFS_BACKEND_HTTP (handle->backend)->session,
-                                   handle->msg,
-                                   SOUP_STATUS_CANCELLED);
-    }
-}
-
-static void
-push_write_next_chunk (SoupMessage *msg, gpointer user_data)
-{
-  PushHandle *handle = user_data;
-
-  /* If we've been restarted, seek to the beginning of the file. */
-  if (handle->read_status == PUSH_READ_STATUS_RESET)
-    {
-      GError *error = NULL;
-
-      /* We've been restarted but there's still a read in flight, so defer. */
-      if (handle->buf)
-        {
-          handle->read_status = PUSH_READ_STATUS_DEFERRED;
-          return;
-        }
-
-      handle->n_read = 0;
-      handle->n_written = 0;
-      handle->read_status = PUSH_READ_STATUS_NONE;
-
-      if (!g_seekable_seek (G_SEEKABLE (handle->in),
-                            0, G_SEEK_SET,
-                            handle->job->cancellable, &error))
-        {
-          g_vfs_job_failed_from_error (handle->job, error);
-          g_error_free (error);
-          soup_session_cancel_message (G_VFS_BACKEND_HTTP (handle->backend)->session,
-                                       handle->msg,
-                                       SOUP_STATUS_CANCELLED);
-          return;
-        }
-    }
-
-  handle->buf = g_malloc (CHUNK_SIZE);
-  g_input_stream_read_async (handle->in,
-                             handle->buf, CHUNK_SIZE,
-                             0, handle->job->cancellable,
-                             push_read_cb, handle);
+  g_slice_free (PushHandle, handle);
 }
 
 static void
 push_setup_message (PushHandle *handle)
 {
-  soup_message_set_flags (handle->msg, SOUP_MESSAGE_CAN_REBUILD);
-  soup_message_body_set_accumulate (handle->msg->request_body, FALSE);
   message_add_overwrite_header (handle->msg,
                                 handle->op_job->flags & G_FILE_COPY_OVERWRITE);
-  soup_message_headers_set_encoding (handle->msg->request_headers,
+  soup_message_headers_set_encoding (soup_message_get_request_headers (handle->msg),
                                      SOUP_ENCODING_CONTENT_LENGTH);
-  soup_message_headers_set_content_length (handle->msg->request_headers,
+  soup_message_headers_set_content_length (soup_message_get_request_headers (handle->msg),
                                            handle->size);
 }
 
@@ -3294,28 +3433,31 @@ push_restarted (SoupMessage *msg, gpointer user_data)
 {
   PushHandle *handle = user_data;
 
-  handle->read_status = PUSH_READ_STATUS_RESET;
-       msg->method = SOUP_METHOD_PUT;
+  handle->n_written = 0;
+
+  g_object_set (msg, "method", SOUP_METHOD_PUT, NULL);
   push_setup_message (handle);
+
+  soup_message_set_request_body (handle->msg, NULL, handle->in, handle->size);
 }
 
 static void
-push_wrote_body_data (SoupMessage *msg, SoupBuffer *chunk, gpointer user_data)
+push_wrote_body_data (SoupMessage *msg, guint chunk_size, gpointer user_data)
 {
   PushHandle *handle = user_data;
 
-  handle->n_written += chunk->length;
+  handle->n_written += chunk_size;
   g_vfs_job_progress_callback (handle->n_written, handle->size, handle->job);
 }
 
 static void
-push_done (SoupSession *session, SoupMessage *msg, gpointer user_data)
+push_finished (SoupMessage *msg, gpointer user_data)
 {
   PushHandle *handle = user_data;
 
   if (g_vfs_job_is_finished (handle->job))
     ; /* We got an error so we finished the job and cancelled msg. */
-  else if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code))
+  else if (!SOUP_STATUS_IS_SUCCESSFUL (soup_message_get_status (msg)))
     http_job_failed (handle->job, msg);
   else
     {
@@ -3329,15 +3471,43 @@ push_done (SoupSession *session, SoupMessage *msg, gpointer user_data)
 }
 
 static void
-push_stat_dest_cb (SoupSession *session, SoupMessage *msg, gpointer user_data)
+push_done (GObject *source, GAsyncResult *result, gpointer user_data)
+{
+  GInputStream *body;
+  GVfsJob *job = G_VFS_JOB (user_data);;
+  GError *error = NULL;
+
+  body = soup_session_send_finish (SOUP_SESSION (source), result, &error);
+  if (!body)
+    {
+      g_vfs_job_failed_from_error (job, error);
+      g_error_free (error);
+    }
+  else
+    g_object_unref (body);
+}
+
+static void
+push_stat_dest_cb (GObject *source, GAsyncResult *result, gpointer user_data)
 {
+  GInputStream *body;
   PushHandle *handle = user_data;
   GFileType type;
+  GError *error = NULL;
 
-  if (stat_location_finish (msg, &type, NULL, NULL))
+  body = soup_session_send_finish (SOUP_SESSION (source), result, &error);
+  if (!body)
+    {
+      g_vfs_job_failed_from_error (handle->job, error);
+      g_error_free (error);
+      return;
+    }
+
+  if (stat_location_finish (handle->msg, body, &type, NULL, NULL))
     {
       if (!(handle->op_job->flags & G_FILE_COPY_OVERWRITE))
         {
+          g_object_unref (body);
           g_vfs_job_failed (handle->job,
                             G_IO_ERROR,
                             G_IO_ERROR_EXISTS,
@@ -3347,6 +3517,7 @@ push_stat_dest_cb (SoupSession *session, SoupMessage *msg, gpointer user_data)
         }
       if (type == G_FILE_TYPE_DIRECTORY)
         {
+          g_object_unref (body);
           g_vfs_job_failed (handle->job,
                             G_IO_ERROR,
                             G_IO_ERROR_IS_DIRECTORY,
@@ -3356,20 +3527,23 @@ push_stat_dest_cb (SoupSession *session, SoupMessage *msg, gpointer user_data)
         }
     }
 
+  g_object_unref (body);
+  g_object_unref (handle->msg);
+
   handle->msg = soup_message_new_from_uri (SOUP_METHOD_PUT, handle->uri);
   push_setup_message (handle);
 
+  soup_message_set_request_body (handle->msg, NULL, handle->in, handle->size);
+
   g_signal_connect (handle->msg, "restarted",
                     G_CALLBACK (push_restarted), handle);
-  g_signal_connect (handle->msg, "wrote_headers",
-                    G_CALLBACK (push_write_next_chunk), handle);
-  g_signal_connect (handle->msg, "wrote_chunk",
-                    G_CALLBACK (push_write_next_chunk), handle);
   g_signal_connect (handle->msg, "wrote-body-data",
                     G_CALLBACK (push_wrote_body_data), handle);
+  g_signal_connect (handle->msg, "finished",
+                    G_CALLBACK (push_finished), handle);
 
-  g_vfs_backend_dav_queue_message (handle->backend, handle->msg,
-                                   push_done, handle);
+  g_vfs_backend_dav_send_async (handle->backend, handle->msg, TRUE,
+                                push_done, handle->job);
 }
 
 static void
@@ -3383,14 +3557,12 @@ push_source_fstat_cb (GObject *source, GAsyncResult *res, gpointer user_data)
   info = g_file_input_stream_query_info_finish (fin, res, &error);
   if (info)
     {
-      SoupMessage *msg;
-
       handle->size = g_file_info_get_size (info);
       g_object_unref (info);
 
-      msg = stat_location_begin (handle->uri, FALSE);
-      g_vfs_backend_dav_queue_message (handle->backend, msg,
-                                       push_stat_dest_cb, handle);
+      handle->msg = stat_location_begin (handle->uri, FALSE);
+      g_vfs_backend_dav_send_async (handle->backend, handle->msg, TRUE,
+                                    push_stat_dest_cb, handle);
     }
   else
     {
@@ -3538,4 +3710,10 @@ g_vfs_backend_dav_class_init (GVfsBackendDavClass *klass)
   backend_class->move              = do_move;
   backend_class->copy              = do_copy;
   backend_class->try_push          = try_push;
+
+  /* override the maximum number of connections, since the libsoup defaults
+   * of 10 and 2 respectively are too low and may cause backend lockups when
+   * a lot of files are opened at the same time
+   */
+  http_try_init_session (32, 32);
 }
diff --git a/daemon/gvfsbackendhttp.c b/daemon/gvfsbackendhttp.c
index 1120d2f0..0f01d213 100644
--- a/daemon/gvfsbackendhttp.c
+++ b/daemon/gvfsbackendhttp.c
@@ -1,6 +1,7 @@
 /* GIO - GLib Input, Output and Streaming Library
  *
  * Copyright (C) 2008 Red Hat, Inc.
+ * Copyright (C) 2021 Igalia S.L.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -51,7 +52,7 @@
 #include "gvfsdaemonprotocol.h"
 #include "gvfsdaemonutils.h"
 
-static SoupSession *the_session;
+static SoupSession *the_session = NULL;
 
 G_DEFINE_TYPE (GVfsBackendHttp, g_vfs_backend_http, G_VFS_TYPE_BACKEND)
 
@@ -63,7 +64,7 @@ g_vfs_backend_http_finalize (GObject *object)
   backend = G_VFS_BACKEND_HTTP (object);
 
   if (backend->mount_base)
-    soup_uri_free (backend->mount_base);
+    g_uri_unref (backend->mount_base);
 
   g_object_unref (backend->session);
 
@@ -77,18 +78,89 @@ g_vfs_backend_http_init (GVfsBackendHttp *backend)
 {
   g_vfs_backend_set_user_visible (G_VFS_BACKEND (backend), FALSE);
 
-  backend->session = g_object_ref (the_session);
+  /* attempt to use libsoup's default values */
+  backend->session = g_object_ref (http_try_init_session (-1, -1));
 }
 
 /* ************************************************************************* */
 /* public utility functions */
 
-SoupURI *
+GUri *
 http_backend_get_mount_base (GVfsBackend *backend)
 {
   return  G_VFS_BACKEND_HTTP (backend)->mount_base;
 }
 
+#define DEBUG_MAX_BODY_SIZE (100 * 1024 * 1024)
+
+/* initializes the session singleton; if max_conns is lower than 0, the
+ * libsoup defaults are used for max-conns and max-conns-per-host, this
+ * is called in the instance constructor, so if they are to be overridden,
+ * all one has to do is make sure to call it with the desired values before
+ * any instance is created (most likely in the class constructor of the
+ * derived class, see dav backend)
+ */
+SoupSession *
+http_try_init_session (gint max_conns, gint max_conns_per_host)
+{
+  const char *debug;
+  SoupSessionFeature *cookie_jar;
+
+  if (the_session)
+    return the_session;
+
+  /* Initialize the SoupSession, common to all backend instances */
+  if (max_conns < 0)
+    the_session = soup_session_new_with_options ("user-agent",
+                                                 "gvfs/" VERSION, NULL);
+  else
+    the_session = soup_session_new_with_options ("user-agent",
+                                                 "gvfs/" VERSION,
+                                                 "max-conns",
+                                                 max_conns,
+                                                 "max-conns-per-host",
+                                                 max_conns_per_host,
+                                                 NULL);
+
+  /* Cookie handling - stored temporarlly in memory, mostly useful for
+   * authentication in WebDAV. */
+  cookie_jar = g_object_new (SOUP_TYPE_COOKIE_JAR, NULL);
+  soup_session_add_feature (the_session, cookie_jar);
+  g_object_unref (cookie_jar);
+
+  /* Send Accept-Language header (see bug 166795) */
+  soup_session_set_accept_language_auto (the_session, TRUE);
+
+  /* Prevent connection timeouts during long operations like COPY. */
+  soup_session_set_timeout (the_session, 0);
+
+  /* Logging */
+  debug = g_getenv ("GVFS_HTTP_DEBUG");
+  if (debug)
+    {
+      SoupLogger *logger;
+      SoupLoggerLogLevel level;
+
+      if (g_ascii_strcasecmp (debug, "all") == 0 ||
+          g_ascii_strcasecmp (debug, "body") == 0)
+        level = SOUP_LOGGER_LOG_BODY;
+      else if (g_ascii_strcasecmp (debug, "header") == 0)
+        level = SOUP_LOGGER_LOG_HEADERS;
+      else
+        level = SOUP_LOGGER_LOG_MINIMAL;
+
+      logger = soup_logger_new (level);
+      g_object_set (G_OBJECT (logger),
+                    "max-body-size",
+                    DEBUG_MAX_BODY_SIZE,
+                    NULL);
+      soup_session_add_feature (the_session, SOUP_SESSION_FEATURE (logger));
+      g_object_unref (logger);
+    }
+
+  return the_session;
+}
+
 char *
 http_path_get_basename (const char *path)
 {
@@ -138,7 +210,7 @@ http_uri_get_basename (const char *uri_str)
 
   basename = http_path_get_basename (uri_str);
 
-  decoded = soup_uri_decode (basename);
+  decoded = g_uri_unescape_string (basename, NULL);
   g_free (basename);
 
   return decoded;
@@ -149,13 +221,6 @@ http_error_code_from_status (guint status)
 {
   switch (status) {
 
-  case SOUP_STATUS_CANT_RESOLVE:
-  case SOUP_STATUS_CANT_RESOLVE_PROXY:
-    return G_IO_ERROR_HOST_NOT_FOUND;
-
-  case SOUP_STATUS_CANCELLED:
-    return G_IO_ERROR_CANCELLED;
-
   case SOUP_STATUS_UNAUTHORIZED:
   case SOUP_STATUS_PAYMENT_REQUIRED:
   case SOUP_STATUS_FORBIDDEN:
@@ -184,45 +249,27 @@ http_error_code_from_status (guint status)
 void
 http_job_failed (GVfsJob *job, SoupMessage *msg)
 {
-  switch (msg->status_code) {
+  switch (soup_message_get_status(msg)) {
 
   case SOUP_STATUS_NOT_FOUND:
     g_vfs_job_failed_literal (job, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
-                              msg->reason_phrase);
+                              soup_message_get_reason_phrase(msg));
     break;
 
   case SOUP_STATUS_UNAUTHORIZED:
   case SOUP_STATUS_PAYMENT_REQUIRED:
   case SOUP_STATUS_FORBIDDEN:
     g_vfs_job_failed (job, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
-                      _("HTTP Client Error: %s"), msg->reason_phrase);
+                      _("HTTP Client Error: %s"),
+                      soup_message_get_reason_phrase(msg));
     break;
   default:
     g_vfs_job_failed (job, G_IO_ERROR, G_IO_ERROR_FAILED,
-                      _("HTTP Error: %s"), msg->reason_phrase);
+                      _("HTTP Error: %s"),
+                      soup_message_get_reason_phrase(msg));
   }
 }
 
-guint
-http_backend_send_message (GVfsBackend *backend,
-                           SoupMessage *msg)
-{
-  GVfsBackendHttp *op_backend = G_VFS_BACKEND_HTTP (backend);
-
-  return soup_session_send_message (op_backend->session, msg);
-}
-
-void
-http_backend_queue_message (GVfsBackend         *backend,
-                            SoupMessage         *msg,
-                            SoupSessionCallback  callback,
-                            gpointer             user_data)
-{
-  GVfsBackendHttp *op_backend = G_VFS_BACKEND_HTTP (backend);
-
-  soup_session_queue_message (op_backend->session, msg,
-                              callback, user_data);
-}
 /* ************************************************************************* */
 /* virtual functions overrides */
 
@@ -235,8 +282,8 @@ try_mount (GVfsBackend  *backend,
 {
   GVfsBackendHttp *op_backend;
   const char      *uri_str;
-  char            *path;
-  SoupURI         *uri;
+  const char      *path;
+  GUri            *uri;
   GMountSpec      *real_mount_spec;
 
   op_backend = G_VFS_BACKEND_HTTP (backend);
@@ -245,7 +292,7 @@ try_mount (GVfsBackend  *backend,
   uri_str = g_mount_spec_get (mount_spec, "uri");
 
   if (uri_str)
-    uri = soup_uri_new (uri_str);
+    uri = g_uri_parse (uri_str, SOUP_HTTP_URI_FLAGS, NULL);
 
   g_debug ("+ try_mount: %s\n", uri_str ? uri_str : "(null)");
 
@@ -260,12 +307,11 @@ try_mount (GVfsBackend  *backend,
   real_mount_spec = g_mount_spec_new ("http");
   g_mount_spec_set (real_mount_spec, "uri", uri_str);
 
-  if (uri->path != NULL)
+  path = g_uri_get_path (uri);
+  if (path[0])
     {
-      path = g_uri_unescape_string (uri->path, "/");
       g_free (real_mount_spec->mount_prefix);
       real_mount_spec->mount_prefix = g_mount_spec_canonicalize_path (path);
-      g_free (path);
     }
 
   g_vfs_backend_set_mount_spec (backend, real_mount_spec);
@@ -309,7 +355,7 @@ open_for_read_ready (GObject      *source_object,
     }
 
   msg = g_vfs_http_input_stream_get_message (stream);
-  if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code))
+  if (!SOUP_STATUS_IS_SUCCESSFUL (soup_message_get_status (msg)))
     {
       http_job_failed (G_VFS_JOB (job), msg);
       g_object_unref (msg);
@@ -330,7 +376,7 @@ try_open_for_read (GVfsBackend        *backend,
                    GVfsJobOpenForRead *job,
                    const char         *filename)
 {
-  SoupURI *uri;
+  GUri *uri;
 
   uri = http_backend_get_mount_base (backend);
   http_backend_open_for_read (backend, G_VFS_JOB (job), uri);
@@ -341,7 +387,7 @@ try_open_for_read (GVfsBackend        *backend,
 void
 http_backend_open_for_read (GVfsBackend *backend,
                            GVfsJob     *job,
-                           SoupURI     *uri)
+                           GUri        *uri)
 {
   GVfsBackendHttp *op_backend;
   GInputStream    *stream;
@@ -507,7 +553,7 @@ file_info_from_message (SoupMessage *msg,
 
   /* prefer the filename from the Content-Disposition (rfc2183) header
      if one if present. See bug 551298. */
-  if (soup_message_headers_get_content_disposition (msg->response_headers,
+  if (soup_message_headers_get_content_disposition (soup_message_get_response_headers (msg),
                                                     NULL, &params))
     {
       const char *name = g_hash_table_lookup (params, "filename");
@@ -520,10 +566,10 @@ file_info_from_message (SoupMessage *msg,
 
   if (basename == NULL)
     {
-      const SoupURI *uri;
+      GUri *uri;
 
       uri = soup_message_get_uri (msg);
-      basename = http_uri_get_basename (uri->path);
+      basename = http_uri_get_basename (g_uri_get_path (uri));
     }
 
   g_debug ("basename:%s\n", basename);
@@ -540,12 +586,12 @@ file_info_from_message (SoupMessage *msg,
   g_free (basename);
   g_free (ed_name);
 
-  if (soup_message_headers_get_encoding (msg->response_headers) == SOUP_ENCODING_CONTENT_LENGTH)
+  if (soup_message_headers_get_encoding (soup_message_get_response_headers (msg)) == 
SOUP_ENCODING_CONTENT_LENGTH)
     {
       goffset start, end, length;
       gboolean ret;
 
-      ret = soup_message_headers_get_content_range (msg->response_headers,
+      ret = soup_message_headers_get_content_range (soup_message_get_response_headers (msg),
                                                     &start, &end, &length);
       if (ret && length != -1)
         {
@@ -553,14 +599,14 @@ file_info_from_message (SoupMessage *msg,
         }
       else if (!ret)
         {
-          length = soup_message_headers_get_content_length (msg->response_headers);
+          length = soup_message_headers_get_content_length (soup_message_get_response_headers (msg));
           g_file_info_set_size (info, length);
         }
     }
 
   g_file_info_set_file_type (info, G_FILE_TYPE_REGULAR);
 
-  text = soup_message_headers_get_content_type (msg->response_headers, NULL);
+  text = soup_message_headers_get_content_type (soup_message_get_response_headers (msg), NULL);
   if (text)
     {
       GIcon *icon;
@@ -578,23 +624,25 @@ file_info_from_message (SoupMessage *msg,
     }
 
 
-  text = soup_message_headers_get_one (msg->response_headers,
+  text = soup_message_headers_get_one (soup_message_get_response_headers (msg),
                                        "Last-Modified");
   if (text)
     {
-      SoupDate *sd;
+      GDateTime *gd;
 
-      sd = soup_date_new_from_string(text);
-      if (sd)
+      gd = soup_date_time_new_from_http_string (text);
+      if (gd)
         {
-          g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_MODIFIED, soup_date_to_time_t (sd));
+          g_file_info_set_attribute_uint64 (info,
+                                            G_FILE_ATTRIBUTE_TIME_MODIFIED,
+                                            g_date_time_to_unix (gd));
           g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC, 0);
-          soup_date_free (sd);
+          g_date_time_unref (gd);
         }
     }
 
 
-  text = soup_message_headers_get_one (msg->response_headers,
+  text = soup_message_headers_get_one (soup_message_get_response_headers (msg),
                                        "ETag");
   if (text)
     {
@@ -605,19 +653,25 @@ file_info_from_message (SoupMessage *msg,
 }
 
 static void
-query_info_ready (SoupSession *session,
-                  SoupMessage *msg,
-                  gpointer     user_data)
+query_info_ready (GObject      *object,
+                  GAsyncResult *result,
+                  gpointer      user_data)
 {
-  GFileAttributeMatcher *matcher;
-  GVfsJobQueryInfo      *job;
-  GFileInfo             *info;
-
-  job     = G_VFS_JOB_QUERY_INFO (user_data);
-  info    = job->file_info;
-  matcher = job->attribute_matcher;
+  GVfsJobQueryInfo *job = G_VFS_JOB_QUERY_INFO (user_data);
+  GFileAttributeMatcher *matcher = job->attribute_matcher;
+  GFileInfo *info = job->file_info;
+  GInputStream *res;
+  GError *error = NULL;
+  SoupMessage *msg = G_VFS_JOB (job)->backend_data;
+
+  res = soup_session_send_finish (SOUP_SESSION (object), result, &error);
+  if (!res)
+    {
+      g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
+      return;
+    }
 
-  if (! SOUP_STATUS_IS_SUCCESSFUL (msg->status_code))
+  if (!SOUP_STATUS_IS_SUCCESSFUL (soup_message_get_status (msg)))
     {
       http_job_failed (G_VFS_JOB (job), msg);
       return;
@@ -625,10 +679,11 @@ query_info_ready (SoupSession *session,
 
   file_info_from_message (msg, info, matcher);
 
+  g_object_unref (res);
+
   g_vfs_job_succeeded (G_VFS_JOB (job));
 }
 
-
 static gboolean
 try_query_info (GVfsBackend           *backend,
                 GVfsJobQueryInfo      *job,
@@ -637,8 +692,9 @@ try_query_info (GVfsBackend           *backend,
                 GFileInfo             *info,
                 GFileAttributeMatcher *attribute_matcher)
 {
+  GVfsBackendHttp *op_backend = G_VFS_BACKEND_HTTP (backend);
   SoupMessage *msg;
-  SoupURI     *uri;
+  GUri *uri;
 
   if (g_file_attribute_matcher_matches_only (attribute_matcher,
                                              G_FILE_ATTRIBUTE_THUMBNAIL_PATH))
@@ -650,7 +706,10 @@ try_query_info (GVfsBackend           *backend,
   uri = http_backend_get_mount_base (backend);
   msg = soup_message_new_from_uri (SOUP_METHOD_HEAD, uri);
 
-  http_backend_queue_message (backend, msg, query_info_ready, job);
+  g_vfs_job_set_backend_data (G_VFS_JOB (job), msg, NULL);
+
+  soup_session_send_async (op_backend->session, msg, G_PRIORITY_DEFAULT,
+                           NULL, query_info_ready, job);
 
   return TRUE;
 }
@@ -687,15 +746,9 @@ try_query_fs_info (GVfsBackend *backend,
   return TRUE;
 }
 
-
-#define DEBUG_MAX_BODY_SIZE (100 * 1024 * 1024)
-
 static void
 g_vfs_backend_http_class_init (GVfsBackendHttpClass *klass)
 {
-  const char         *debug;
-  SoupSessionFeature *cookie_jar;
-
   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
   GVfsBackendClass *backend_class;
 
@@ -711,43 +764,4 @@ g_vfs_backend_http_class_init (GVfsBackendHttpClass *klass)
   backend_class->try_query_info         = try_query_info;
   backend_class->try_query_info_on_read = try_query_info_on_read;
   backend_class->try_query_fs_info      = try_query_fs_info;
-
-  /* Initialize the SoupSession, common to all backend instances */
-  the_session = soup_session_new_with_options ("user-agent",
-                                               "gvfs/" VERSION,
-                                               NULL);
-
-  g_object_set (the_session, "ssl-strict", FALSE, NULL);
-
-  /* Cookie handling - stored temporarlly in memory, mostly useful for
-   * authentication in WebDAV. */
-  cookie_jar = g_object_new (SOUP_TYPE_COOKIE_JAR, NULL);
-  soup_session_add_feature (the_session, cookie_jar);
-  g_object_unref (cookie_jar);
-
-  /* Send Accept-Language header (see bug 166795) */
-  g_object_set (the_session, "accept-language-auto", TRUE, NULL);
-
-  /* Prevent connection timeouts during long operations like COPY. */
-  g_object_set (the_session, "timeout", 0, NULL);
-
-  /* Logging */
-  debug = g_getenv ("GVFS_HTTP_DEBUG");
-  if (debug)
-    {
-      SoupLogger         *logger;
-      SoupLoggerLogLevel  level;
-
-      if (g_ascii_strcasecmp (debug, "all") == 0 ||
-          g_ascii_strcasecmp (debug, "body") == 0)
-        level = SOUP_LOGGER_LOG_BODY;
-      else if (g_ascii_strcasecmp (debug, "header") == 0)
-        level = SOUP_LOGGER_LOG_HEADERS;
-      else
-        level = SOUP_LOGGER_LOG_MINIMAL;
-
-      logger = soup_logger_new (level, DEBUG_MAX_BODY_SIZE);
-      soup_session_add_feature (the_session, SOUP_SESSION_FEATURE (logger));
-      g_object_unref (logger);
-    }
 }
diff --git a/daemon/gvfsbackendhttp.h b/daemon/gvfsbackendhttp.h
index f132c568..f05e92a3 100644
--- a/daemon/gvfsbackendhttp.h
+++ b/daemon/gvfsbackendhttp.h
@@ -1,6 +1,7 @@
 /* GIO - GLib Input, Output and Streaming Library
  * 
  * Copyright (C) 2008 Red Hat, Inc.
+ * Copyright (C) 2021 Igalia S.L.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -49,7 +50,7 @@ struct _GVfsBackendHttp
 {
   GVfsBackend parent_instance;
 
-  SoupURI     *mount_base;
+  GUri        *mount_base;
   SoupSession *session;
 };
 
@@ -61,19 +62,14 @@ char *        http_path_get_basename         (const char *path_str);
 
 int           http_error_code_from_status    (guint status);
 
-SoupURI *     http_backend_get_mount_base    (GVfsBackend *backend);
+SoupSession * http_try_init_session          (gint max_conns,
+                                              gint max_conns_per_host);
 
-guint         http_backend_send_message      (GVfsBackend *backend,
-                                              SoupMessage *msg);
-
-void          http_backend_queue_message     (GVfsBackend         *backend,
-                                              SoupMessage         *msg,
-                                              SoupSessionCallback  callback,
-                                              gpointer             user_data);
+GUri *        http_backend_get_mount_base    (GVfsBackend *backend);
 
 void          http_backend_open_for_read     (GVfsBackend         *backend,
                                              GVfsJob             *job,
-                                             SoupURI             *uri);
+                                             GUri                *uri);
 
 void          http_job_failed                (GVfsJob             *job,
                                              SoupMessage         *msg);
diff --git a/daemon/gvfshttpinputstream.c b/daemon/gvfshttpinputstream.c
index 82f9164d..5a3f6d7c 100644
--- a/daemon/gvfshttpinputstream.c
+++ b/daemon/gvfshttpinputstream.c
@@ -1,6 +1,7 @@
 /* gvfshttpinputstream.c: seekable wrapper around SoupRequestHTTP
  *
  * Copyright (C) 2006, 2007, 2012 Red Hat, Inc.
+ * Copyright (C) 2021 Igalia S.L.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -29,13 +30,13 @@
 #include <libsoup/soup.h>
 
 #include "gvfshttpinputstream.h"
+#include "gvfsbackendhttp.h"
 
 static void g_vfs_http_input_stream_seekable_iface_init (GSeekableIface *seekable_iface);
 
 struct GVfsHttpInputStreamPrivate {
-  SoupURI *uri;
+  GUri *uri;
   SoupSession *session;
-  SoupRequest *req;
   SoupMessage *msg;
   GInputStream *stream;
 
@@ -61,9 +62,8 @@ g_vfs_http_input_stream_finalize (GObject *object)
   GVfsHttpInputStream *stream = G_VFS_HTTP_INPUT_STREAM (object);
   GVfsHttpInputStreamPrivate *priv = stream->priv;
 
-  g_clear_pointer (&priv->uri, soup_uri_free);
+  g_clear_pointer (&priv->uri, g_uri_unref);
   g_clear_object (&priv->session);
-  g_clear_object (&priv->req);
   g_clear_object (&priv->msg);
   g_clear_object (&priv->stream);
   g_free (priv->range);
@@ -74,7 +74,7 @@ g_vfs_http_input_stream_finalize (GObject *object)
 /**
  * g_vfs_http_input_stream_new:
  * @session: a #SoupSession
- * @uri: a #SoupURI
+ * @uri: a #GUri
  * 
  * Prepares to send a GET request for @uri on @session, and returns a
  * #GInputStream that can be used to read the response.
@@ -89,7 +89,7 @@ g_vfs_http_input_stream_finalize (GObject *object)
  **/
 GInputStream *
 g_vfs_http_input_stream_new (SoupSession *session,
-                            SoupURI     *uri)
+                            GUri     *uri)
 {
   GVfsHttpInputStream *stream;
   GVfsHttpInputStreamPrivate *priv;
@@ -98,30 +98,27 @@ g_vfs_http_input_stream_new (SoupSession *session,
   priv = stream->priv;
 
   priv->session = g_object_ref (session);
-  priv->uri = soup_uri_copy (uri);
+  priv->uri = g_uri_ref (uri);
 
   return G_INPUT_STREAM (stream);
 }
 
-static SoupRequest *
-g_vfs_http_input_stream_ensure_request (GInputStream *stream)
+static SoupMessage *
+g_vfs_http_input_stream_ensure_msg (GInputStream *stream)
 {
   GVfsHttpInputStreamPrivate *priv = G_VFS_HTTP_INPUT_STREAM (stream)->priv;
 
-  if (!priv->req)
+  if (!priv->msg)
     {
-      GError *error = NULL;
-
-      priv->req = soup_session_request_uri (priv->session, priv->uri, &error);
-      g_assert_no_error (error);
-      priv->msg = soup_request_http_get_message (SOUP_REQUEST_HTTP (priv->req));
+      priv->msg = soup_message_new_from_uri (SOUP_METHOD_GET, priv->uri);
       priv->offset = 0;
     }
 
   if (priv->range)
-    soup_message_headers_replace (priv->msg->request_headers, "Range", priv->range);
+    soup_message_headers_replace (soup_message_get_request_headers (priv->msg),
+                                  "Range", priv->range);
 
-  return priv->req;
+  return priv->msg;
 }
 
 static void
@@ -136,7 +133,7 @@ send_callback (GObject      *object,
 
   g_input_stream_clear_pending (http_stream);
 
-  priv->stream = soup_request_send_finish (SOUP_REQUEST (object), result, &error);
+  priv->stream = soup_session_send_finish (SOUP_SESSION (object), result, &error);
   if (priv->stream)
     g_task_return_boolean (task, TRUE);
   else
@@ -188,9 +185,9 @@ g_vfs_http_input_stream_send_async (GInputStream        *stream,
       return;
     }
 
-  g_vfs_http_input_stream_ensure_request (stream);
-  soup_request_send_async (priv->req, cancellable,
-                          send_callback, task);
+  g_vfs_http_input_stream_ensure_msg (stream);
+  soup_session_send_async (priv->session, priv->msg, G_PRIORITY_DEFAULT,
+                           cancellable, send_callback, task);
 }
 
 /**
@@ -253,16 +250,16 @@ read_send_callback (GObject      *object,
   ReadAfterSendData *rasd = g_task_get_task_data (task);
   GError *error = NULL;
 
-  priv->stream = soup_request_send_finish (SOUP_REQUEST (object), result, &error);
+  priv->stream = soup_session_send_finish (SOUP_SESSION (object), result, &error);
   if (!priv->stream)
     {
       g_task_return_error (task, error);
       g_object_unref (task);
       return;
     }
-  if (!SOUP_STATUS_IS_SUCCESSFUL (priv->msg->status_code))
+  if (!SOUP_STATUS_IS_SUCCESSFUL (soup_message_get_status (priv->msg)))
     {
-      if (priv->msg->status_code == SOUP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE)
+      if (soup_message_get_status (priv->msg) == SOUP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE)
         {
           g_input_stream_close (priv->stream, NULL, NULL);
           g_task_return_int (task, 0);
@@ -271,9 +268,9 @@ read_send_callback (GObject      *object,
           return;
         }
       g_task_return_new_error (task,
-                              SOUP_HTTP_ERROR,
-                              priv->msg->status_code,
-                              "%s", priv->msg->reason_phrase);
+                               G_IO_ERROR,
+                               http_error_code_from_status (soup_message_get_status (priv->msg)),
+                               _("HTTP Error: %s"), soup_message_get_reason_phrase (priv->msg));
       g_object_unref (task);
       return;
     }
@@ -282,7 +279,7 @@ read_send_callback (GObject      *object,
       gboolean status;
       goffset start, end;
 
-      status = soup_message_headers_get_content_range (priv->msg->response_headers,
+      status = soup_message_headers_get_content_range (soup_message_get_response_headers (priv->msg),
                                                        &start, &end, NULL);
       if (!status || start != priv->request_offset)
       {
@@ -325,9 +322,9 @@ g_vfs_http_input_stream_read_async (GInputStream        *stream,
       rasd->count = count;
       g_task_set_task_data (task, rasd, g_free);
 
-      g_vfs_http_input_stream_ensure_request (stream);
-      soup_request_send_async (priv->req, cancellable,
-                              read_send_callback, task);
+      g_vfs_http_input_stream_ensure_msg (stream);
+      soup_session_send_async (priv->session, priv->msg, G_PRIORITY_DEFAULT,
+                               cancellable, read_send_callback, task);
       return;
     }
 
@@ -419,7 +416,7 @@ g_vfs_http_input_stream_seek (GSeekable     *seekable,
 
   if (type == G_SEEK_END && priv->msg)
     {
-      goffset content_length = soup_message_headers_get_content_length (priv->msg->response_headers);
+      goffset content_length = soup_message_headers_get_content_length (soup_message_get_response_headers 
(priv->msg));
 
       if (content_length)
        {
@@ -498,7 +495,7 @@ g_vfs_http_input_stream_get_message (GInputStream *stream)
 {
   GVfsHttpInputStreamPrivate *priv = G_VFS_HTTP_INPUT_STREAM (stream)->priv;
 
-  g_vfs_http_input_stream_ensure_request (stream);
+  g_vfs_http_input_stream_ensure_msg (stream);
   return g_object_ref (priv->msg);
 }
 
diff --git a/daemon/gvfshttpinputstream.h b/daemon/gvfshttpinputstream.h
index 93f919ee..e5f9c45b 100644
--- a/daemon/gvfshttpinputstream.h
+++ b/daemon/gvfshttpinputstream.h
@@ -1,4 +1,5 @@
 /* Copyright (C) 2006, 2007, 2012 Red Hat, Inc.
+ * Copyright (C) 2021 Igalia S.L.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -57,7 +58,7 @@ struct GVfsHttpInputStreamClass
 GType g_vfs_http_input_stream_get_type (void) G_GNUC_CONST;
 
 GInputStream *g_vfs_http_input_stream_new         (SoupSession          *session,
-                                                  SoupURI              *uri);
+                                                   GUri                 *uri);
 
 void          g_vfs_http_input_stream_send_async  (GInputStream         *stream,
                                                   int                   io_priority,
diff --git a/meson.build b/meson.build
index 557eef83..9b771ffa 100644
--- a/meson.build
+++ b/meson.build
@@ -310,7 +310,7 @@ endif
 enable_http = get_option('http')
 if enable_http
   assert(have_libxml, 'http required but libxml-2.0 not found')
-  libsoup_dep = dependency('libsoup-2.4', version: '>= 2.58.0')
+  libsoup_dep = dependency('libsoup-3.0', version: '>= 3.0.0')
 endif
 
 # *** Check if we should build with DNS-SD backend ***


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