[PATCH] avformat/url: treat bare paths without scheme as literal paths

yolocat-dev via ffmpeg-devel <[email protected]> Tue, 28 Jul 2026 19:58:06 +0000
Newsgroups gmane.comp.video.ffmpeg.devel
Message-ID <0102019faa4e4d87-15cac00e-6bf6-4a5d-9a53-761a0218a5c5-000000@eu-west-1.amazonses.com>
A bare path without a scheme is not a valid URI (RFC 3986) and should
not be parsed as one. This fix prevents a literal '?' and '#' character
in the path from being interpreted as a URL query/fragment delimeter, by
treating bare paths as a literal path.

For example, given the input file "/path/to/folder?/video.m3u8" and
relative file "init.mp4", ff_make_absolute_url previously produced
"/path/to/init.mp4" as it treated the '?' as a query separator, trimming
the "?/video.m3u8" and thus making the parsed path "/path/to/folder".
This fixes this behavior by treating these bare paths as a literal path,
without trimming and parsing query parameters and fragments. This has no
effect on RFC 3986-compliant URIs with a valid scheme.

Signed-off-by: yolocat-dev <[email protected]>
---
 libavformat/tests/url.c | 6 ++++++
 libavformat/url.c       | 2 ++
 tests/ref/fate/url      | 6 ++++++
 3 files changed, 14 insertions(+)

diff --git a/libavformat/tests/url.c b/libavformat/tests/url.c
index 8644a3e826..5798b9d38c 100644
--- a/libavformat/tests/url.c
+++ b/libavformat/tests/url.c
@@ -111,6 +111,12 @@ int main(void)
     test("/foo/bar", "../baz");
     test("/foo/bar", "/baz");
     test("/foo/bar", "../../../baz");
+    test("/foo/bar?/baz", "qux");
+    test("/foo/bar?/baz", "../qux");
+    test("/foo/bar?/baz/qux", "quux");
+    test("/foo/bar#/baz", "qux");
+    test("/foo/bar#/baz", "../qux");
+    test("/foo/bar#/baz/qux", "quux");
     test("http://server/foo/", "baz");
     test("http://server/foo/bar", "baz");
     test("http://server/foo/", "../baz");
diff --git a/libavformat/url.c b/libavformat/url.c
index d5dd6a4666..343c001e44 100644
--- a/libavformat/url.c
+++ b/libavformat/url.c
@@ -272,6 +272,8 @@ int ff_make_absolute_url2(char *buf, int size, const char *base,
         use_base_path = 0;
     if (use_base_path) {
         base_path_end = ub.url_component_end_path;
+        if (ub.path == ub.url)
+            base_path_end = ub.end;
         if (URL_COMPONENT_HAVE(uc, path))
             while (base_path_end > ub.path && !strchr(base_separators, base_path_end[-1]))
                 base_path_end--;
diff --git a/tests/ref/fate/url b/tests/ref/fate/url
index 8489d10968..590c65693c 100644
--- a/tests/ref/fate/url
+++ b/tests/ref/fate/url
@@ -57,6 +57,12 @@ Testing ff_make_absolute_url:
                                           /foo/bar ../baz               => /foo/../baz
                                           /foo/bar /baz                 => /baz
                                           /foo/bar ../../../baz         => /foo/../../../baz
+                                     /foo/bar?/baz qux                  => /foo/bar?/qux
+                                     /foo/bar?/baz ../qux               => /foo/bar?/../qux
+                                 /foo/bar?/baz/qux quux                 => /foo/bar?/baz/quux
+                                     /foo/bar#/baz qux                  => /foo/bar#/qux
+                                     /foo/bar#/baz ../qux               => /foo/bar#/../qux
+                                 /foo/bar#/baz/qux quux                 => /foo/bar#/baz/quux
                                 http://server/foo/ baz                  => http://server/foo/baz
                              http://server/foo/bar baz                  => http://server/foo/baz
                                 http://server/foo/ ../baz               => http://server/baz
-- 
2.51.0

_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]