summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilip Withnall <philip@tecnocode.co.uk>2023-07-28 12:52:36 +0000
committerPhilip Withnall <philip@tecnocode.co.uk>2023-07-28 12:52:36 +0000
commit39864716d6404766c325caf18c6bef722dc060cd (patch)
tree58fd5974563437cbbf45aeae258869e54502086f
parent67eb8f112fc7a6a63e69ff1c81b97d51456f2721 (diff)
parentb504cc0841b38dc15e526554373d4aec2ccde04e (diff)
Merge branch 'fix_3050' into 'main'
Strip query sections from file: URIs Closes #3050 See merge request GNOME/glib!3502
-rw-r--r--gio/glocalvfs.c14
-rw-r--r--gio/tests/file.c34
-rw-r--r--glib/gconvert.c56
-rw-r--r--glib/tests/convert.c34
-rw-r--r--glib/tests/uri.c3
5 files changed, 117 insertions, 24 deletions
diff --git a/gio/glocalvfs.c b/gio/glocalvfs.c
index a830cc350..00fec8e2b 100644
--- a/gio/glocalvfs.c
+++ b/gio/glocalvfs.c
@@ -94,14 +94,24 @@ g_local_vfs_get_file_for_uri (GVfs *vfs,
{
char *path;
GFile *file;
- char *stripped_uri, *hash;
-
+ char *stripped_uri, *hash, *question_mark;
+
+ /* As per https://url.spec.whatwg.org/#file-state, file: URIs can contain
+ * query and fragment sections. We ignore them in order to get only the file
+ * path. Compliance to this part of the WhatWG spec doesn’t necessarily mean
+ * we comply with the entire spec. */
if (strchr (uri, '#') != NULL)
{
stripped_uri = g_strdup (uri);
hash = strchr (stripped_uri, '#');
*hash = 0;
}
+ else if (strchr (uri, '?') != NULL)
+ {
+ stripped_uri = g_strdup (uri);
+ question_mark = strchr (stripped_uri, '?');
+ *question_mark = 0;
+ }
else
stripped_uri = (char *)uri;
diff --git a/gio/tests/file.c b/gio/tests/file.c
index 69c25ff69..310981b5d 100644
--- a/gio/tests/file.c
+++ b/gio/tests/file.c
@@ -3935,6 +3935,38 @@ test_enumerator_cancellation (void)
g_object_unref (dir);
}
+static void
+test_from_uri_ignores_fragment (void)
+{
+ GFile *file;
+ gchar *path;
+ file = g_file_new_for_uri ("file:///tmp/foo#bar");
+ path = g_file_get_path (file);
+#ifdef G_OS_WIN32
+ g_assert_cmpstr (path, ==, "\\tmp\\foo");
+#else
+ g_assert_cmpstr (path, ==, "/tmp/foo");
+#endif
+ g_free (path);
+ g_object_unref (file);
+}
+
+static void
+test_from_uri_ignores_query_string (void)
+{
+ GFile *file;
+ gchar *path;
+ file = g_file_new_for_uri ("file:///tmp/foo?bar");
+ path = g_file_get_path (file);
+#ifdef G_OS_WIN32
+ g_assert_cmpstr (path, ==, "\\tmp\\foo");
+#else
+ g_assert_cmpstr (path, ==, "/tmp/foo");
+#endif
+ g_free (path);
+ g_object_unref (file);
+}
+
int
main (int argc, char *argv[])
{
@@ -3990,6 +4022,8 @@ main (int argc, char *argv[])
g_test_add_func ("/file/query-default-handler-uri", test_query_default_handler_uri);
g_test_add_func ("/file/query-default-handler-uri-async", test_query_default_handler_uri_async);
g_test_add_func ("/file/enumerator-cancellation", test_enumerator_cancellation);
+ g_test_add_func ("/file/from-uri/ignores-query-string", test_from_uri_ignores_query_string);
+ g_test_add_func ("/file/from-uri/ignores-fragment", test_from_uri_ignores_fragment);
return g_test_run ();
}
diff --git a/glib/gconvert.c b/glib/gconvert.c
index 5e3d781df..69bcc2f97 100644
--- a/glib/gconvert.c
+++ b/glib/gconvert.c
@@ -1662,7 +1662,12 @@ hostname_validate (const char *hostname)
* errors. Any of the errors in #GConvertError may occur.
*
* Converts an escaped ASCII-encoded URI to a local filename in the
- * encoding used for filenames.
+ * encoding used for filenames.
+ *
+ * Since GLib 2.78, the query string and fragment can be present in the URI,
+ * but are not part of the resulting filename.
+ * We take inspiration from https://url.spec.whatwg.org/#file-state,
+ * but we don't support the entire standard.
*
* Returns: (type filename): a newly-allocated string holding
* the resulting filename, or %NULL on an error.
@@ -1672,11 +1677,13 @@ g_filename_from_uri (const gchar *uri,
gchar **hostname,
GError **error)
{
- const char *path_part;
+ const char *past_scheme;
const char *host_part;
char *unescaped_hostname;
char *result;
char *filename;
+ char *past_path;
+ char *temp_uri;
int offs;
#ifdef G_OS_WIN32
char *p, *slash;
@@ -1692,40 +1699,44 @@ g_filename_from_uri (const gchar *uri,
uri);
return NULL;
}
+
+ temp_uri = g_strdup (uri);
+
+ past_scheme = temp_uri + strlen ("file:");
- path_part = uri + strlen ("file:");
-
- if (strchr (path_part, '#') != NULL)
- {
- g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_BAD_URI,
- _("The local file URI “%s” may not include a “#”"),
- uri);
- return NULL;
- }
-
- if (has_case_prefix (path_part, "///"))
- path_part += 2;
- else if (has_case_prefix (path_part, "//"))
+ past_path = strchr (past_scheme, '?');
+ if (past_path != NULL)
+ *past_path = '\0';
+
+ past_path = strchr (past_scheme, '#');
+ if (past_path != NULL)
+ *past_path = '\0';
+
+ if (has_case_prefix (past_scheme, "///"))
+ past_scheme += 2;
+ else if (has_case_prefix (past_scheme, "//"))
{
- path_part += 2;
- host_part = path_part;
+ past_scheme += 2;
+ host_part = past_scheme;
- path_part = strchr (path_part, '/');
+ past_scheme = strchr (past_scheme, '/');
- if (path_part == NULL)
+ if (past_scheme == NULL)
{
+ g_free (temp_uri);
g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_BAD_URI,
_("The URI “%s” is invalid"),
uri);
return NULL;
}
- unescaped_hostname = g_unescape_uri_string (host_part, path_part - host_part, "", TRUE);
+ unescaped_hostname = g_unescape_uri_string (host_part, past_scheme - host_part, "", TRUE);
if (unescaped_hostname == NULL ||
!hostname_validate (unescaped_hostname))
{
g_free (unescaped_hostname);
+ g_free (temp_uri);
g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_BAD_URI,
_("The hostname of the URI “%s” is invalid"),
uri);
@@ -1738,10 +1749,11 @@ g_filename_from_uri (const gchar *uri,
g_free (unescaped_hostname);
}
- filename = g_unescape_uri_string (path_part, -1, "/", FALSE);
+ filename = g_unescape_uri_string (past_scheme, -1, "/", FALSE);
if (filename == NULL)
{
+ g_free (temp_uri);
g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_BAD_URI,
_("The URI “%s” contains invalidly escaped characters"),
uri);
@@ -1785,6 +1797,8 @@ g_filename_from_uri (const gchar *uri,
result = g_strdup (filename + offs);
g_free (filename);
+ g_free (temp_uri);
+
return result;
}
diff --git a/glib/tests/convert.c b/glib/tests/convert.c
index 6daeec237..6a7bfaf72 100644
--- a/glib/tests/convert.c
+++ b/glib/tests/convert.c
@@ -949,6 +949,38 @@ test_no_conv (void)
g_error_free (error);
}
+static void
+test_filename_from_uri_query_is_ignored (void)
+{
+ gchar *filename;
+ GError *error = NULL;
+
+ filename = g_filename_from_uri ("file:///tmp/foo?bar", NULL, &error);
+ g_assert_no_error (error);
+#ifdef G_OS_WIN32
+ g_assert_cmpstr (filename, ==, "\\tmp\\foo");
+#else
+ g_assert_cmpstr (filename, ==, "/tmp/foo");
+#endif
+ g_free (filename);
+}
+
+static void
+test_filename_from_uri_fragment_is_ignored (void)
+{
+ gchar *filename;
+ GError *error = NULL;
+
+ filename = g_filename_from_uri ("file:///tmp/foo#bar", NULL, &error);
+ g_assert_no_error (error);
+#ifdef G_OS_WIN32
+ g_assert_cmpstr (filename, ==, "\\tmp\\foo");
+#else
+ g_assert_cmpstr (filename, ==, "/tmp/foo");
+#endif
+ g_free (filename);
+}
+
int
main (int argc, char *argv[])
{
@@ -974,6 +1006,8 @@ main (int argc, char *argv[])
g_test_add_func ("/conversion/filename-from-utf8/embedded-nul", test_filename_from_utf8_embedded_nul);
g_test_add_func ("/conversion/filename-from-utf8/embedded-nul/subprocess/utf8", test_filename_from_utf8_embedded_nul_utf8);
g_test_add_func ("/conversion/filename-from-utf8/embedded-nul/subprocess/iconv", test_filename_from_utf8_embedded_nul_iconv);
+ g_test_add_func ("/conversion/filename-from-uri/query-is-ignored", test_filename_from_uri_query_is_ignored);
+ g_test_add_func ("/conversion/filename-from-uri/fragment-is-ignored", test_filename_from_uri_fragment_is_ignored);
return g_test_run ();
}
diff --git a/glib/tests/uri.c b/glib/tests/uri.c
index 0f32888d2..94a0d5dac 100644
--- a/glib/tests/uri.c
+++ b/glib/tests/uri.c
@@ -130,7 +130,8 @@ file_from_uri_tests[] = {
{ "file:////etc/%C3%B6%C3%C3%C3%A5", "//etc/\xc3\xb6\xc3\xc3\xc3\xa5", NULL, 0 },
{ "file://\xE5\xE4\xF6/etc", NULL, NULL, G_CONVERT_ERROR_BAD_URI},
{ "file://%E5%E4%F6/etc", NULL, NULL, G_CONVERT_ERROR_BAD_URI},
- { "file:///some/file#bad", NULL, NULL, G_CONVERT_ERROR_BAD_URI},
+ { "file:///some/file?query", "/some/file", NULL, 0 },
+ { "file:///some/file#bad", "/some/file", NULL, 0 },
{ "file://some", NULL, NULL, G_CONVERT_ERROR_BAD_URI},
{ "", NULL, NULL, G_CONVERT_ERROR_BAD_URI},
{ "file:test", NULL, NULL, G_CONVERT_ERROR_BAD_URI},