[FFmpeg-devel] [PATCH 1/2] lavf/file: Add proper support for authority in file URIs.

Andrey Semashev andrey.semashev at gmail.com
Thu Nov 29 20:18:17 EET 2018


Previously, URIs with authority field were incorrectly interpreted as if
the authority was part of the path. This commit adds more complete file URI
parsing according to https://tools.ietf.org/html/rfc8089. In particular, the
file backend now recognizes URIs with authority field and ensures that it is
either empty or contains the special value "localhost". The file backend will
return EINVAL if the user attempts to use it with a URI referring to
a remote host.

Also, enable file_delete() on Windows as it provides equivalents of unlink()
and rmdir(). The compatibility glue is already provided by os_support.h.
---
 libavformat/file.c | 55 ++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 48 insertions(+), 7 deletions(-)

diff --git a/libavformat/file.c b/libavformat/file.c
index 1d321c4205..040197d50d 100644
--- a/libavformat/file.c
+++ b/libavformat/file.c
@@ -19,6 +19,8 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
+#include "libavutil/log.h"
+#include "libavutil/error.h"
 #include "libavutil/avstring.h"
 #include "libavutil/internal.h"
 #include "libavutil/opt.h"
@@ -104,6 +106,31 @@ static const AVClass pipe_class = {
     .version    = LIBAVUTIL_VERSION_INT,
 };
 
+static int file_get_path(const char* filename, const char** ppath)
+{
+    const char* path = filename;
+    // Check if the filename is a file URI. https://tools.ietf.org/html/rfc8089#section-2
+    if (av_strncasecmp(path, "file:", sizeof("file:") - 1) == 0) {
+        path += sizeof("file:") - 1;
+        if (path[0] == '/' && path[1] == '/') {
+            // The URI may have an authority part. Check that the authority does not contain
+            // a remote host name. We cannot access filesystem on a different host.
+            path += 2;
+            if (path[0] != '/') {
+                if (strncmp(path, "localhost/", sizeof("localhost/") - 1) == 0) {
+                    path += sizeof("localhost") - 1;
+                } else {
+                    av_log(NULL, AV_LOG_ERROR, "File URIs referencing a remote host are not supported: %s\n", filename);
+                    return AVERROR(EINVAL);
+                }
+            }
+        }
+    }
+
+    *ppath = path;
+    return 0;
+}
+
 static int file_read(URLContext *h, unsigned char *buf, int size)
 {
     FileContext *c = h->priv_data;
@@ -136,7 +163,9 @@ static int file_check(URLContext *h, int mask)
 {
     int ret = 0;
     const char *filename = h->filename;
-    av_strstart(filename, "file:", &filename);
+    ret = file_get_path(filename, &filename);
+    if (ret < 0)
+        return ret;
 
     {
 #if HAVE_ACCESS && defined(R_OK)
@@ -167,10 +196,12 @@ static int file_check(URLContext *h, int mask)
 
 static int file_delete(URLContext *h)
 {
-#if HAVE_UNISTD_H
+#if HAVE_UNISTD_H || defined(_WIN32)
     int ret;
     const char *filename = h->filename;
-    av_strstart(filename, "file:", &filename);
+    ret = file_get_path(filename, &filename);
+    if (ret < 0)
+        return ret;
 
     ret = rmdir(filename);
     if (ret < 0 && errno == ENOTDIR)
@@ -188,8 +219,12 @@ static int file_move(URLContext *h_src, URLContext *h_dst)
 {
     const char *filename_src = h_src->filename;
     const char *filename_dst = h_dst->filename;
-    av_strstart(filename_src, "file:", &filename_src);
-    av_strstart(filename_dst, "file:", &filename_dst);
+    int ret = file_get_path(filename_src, &filename_src);
+    if (ret < 0)
+        return ret;
+    ret = file_get_path(filename_dst, &filename_dst);
+    if (ret < 0)
+        return ret;
 
     if (rename(filename_src, filename_dst) < 0)
         return AVERROR(errno);
@@ -206,7 +241,9 @@ static int file_open(URLContext *h, const char *filename, int flags)
     int fd;
     struct stat st;
 
-    av_strstart(filename, "file:", &filename);
+    int ret = file_get_path(filename, &filename);
+    if (ret < 0)
+        return ret;
 
     if (flags & AVIO_FLAG_WRITE && flags & AVIO_FLAG_READ) {
         access = O_CREAT | O_RDWR;
@@ -264,8 +301,12 @@ static int file_open_dir(URLContext *h)
 {
 #if HAVE_LSTAT
     FileContext *c = h->priv_data;
+    const char* dirname = h->filename;
+    int ret = file_get_path(dirname, &dirname);
+    if (ret < 0)
+        return ret;
 
-    c->dir = opendir(h->filename);
+    c->dir = opendir(dirname);
     if (!c->dir)
         return AVERROR(errno);
 
-- 
2.19.1



More information about the ffmpeg-devel mailing list