summaryrefslogtreecommitdiff
path: root/daemon/gvfsbackendhttp.c
diff options
context:
space:
mode:
authorDaniel Kolesa <dkolesa@igalia.com>2021-02-11 22:43:53 +0100
committerDaniel Kolesa <dkolesa@igalia.com>2022-02-01 20:55:46 +0100
commitbeaaf78b72640f8231f49fdfc1b6dcfc3d14f149 (patch)
tree0fbfd0f22d48fac0cd68e4e76cf00f0e99d9f978 /daemon/gvfsbackendhttp.c
parent2cadf5d4864f2df7e999b634070bffa8590d4f26 (diff)
downloadgvfs-beaaf78b72640f8231f49fdfc1b6dcfc3d14f149.tar.gz
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
Diffstat (limited to 'daemon/gvfsbackendhttp.c')
-rw-r--r--daemon/gvfsbackendhttp.c250
1 files changed, 132 insertions, 118 deletions
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);
- }
}