From f6d5ec36fc419bf0de0393421e38ebbd609edb75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Denis-Courmont?= <remi@remlab.net> Date: Tue, 26 Jul 2016 00:41:24 +0300 Subject: [PATCH] playlist: partly fix relative URL resolution --- modules/demux/playlist/playlist.c | 105 +++++++++++++++++------------- 1 file changed, 59 insertions(+), 46 deletions(-) diff --git a/modules/demux/playlist/playlist.c b/modules/demux/playlist/playlist.c index 75aeab16c2d4..bd99d50dc635 100644 --- a/modules/demux/playlist/playlist.c +++ b/modules/demux/playlist/playlist.c @@ -220,64 +220,77 @@ input_item_t * GetCurrentItem(demux_t *p_demux) } /** - * Find directory part of the path to the playlist file, in case of - * relative paths inside + * Computes the base URL. + * + * Rebuilds the base URL for the playlist. */ -char *FindPrefix( demux_t *p_demux ) +char *FindPrefix(demux_t *p_demux) { - char *psz_url; - - if( asprintf( &psz_url, "%s://%s", p_demux->psz_access, - p_demux->psz_location ) == -1 ) - return NULL; + char *url; - char *psz_file = strrchr( psz_url, '/' ); - assert( psz_file != NULL ); - psz_file[1] = '\0'; - - return psz_url; + if (unlikely(asprintf(&url, "%s://%s", p_demux->psz_access, + p_demux->psz_location) == -1)) + url = NULL; + return url; } /** - * Add the directory part of the playlist file to the start of the - * mrl, if the mrl is a relative file path + * Resolves a playlist location. + * + * Resolves a resource location within the playlist relative to the playlist + * base URL. */ -char *ProcessMRL( const char *psz_mrl, const char *psz_prefix ) +char *ProcessMRL(const char *str, const char *base) { - /* Check for a protocol name. - * for URL, we should look for "://" - * for MRL (Media Resource Locator) ([[<access>][/<demux>]:][<source>]), - * we should look for ":", so we end up looking simply for ":" - * PB: on some file systems, ':' are valid characters though */ - - /* Simple cases first */ - if( !psz_mrl || !*psz_mrl ) + if (str == NULL) return NULL; - /* Check if the line specifies an absolute path */ - /* FIXME: that's wrong if the playlist is not a local file */ - if( *psz_mrl == DIR_SEP_CHAR ) - goto uri; -#if defined( _WIN32 ) || defined( __OS2__ ) - /* Drive letter (this assumes URL scheme are not a single character) */ - if( isalpha((unsigned char)psz_mrl[0]) && psz_mrl[1] == ':' ) - goto uri; +#if (DIR_SEP_CHAR == '\\') + /* UNC path prefix? */ + if (strncmp(str, "\\\\", 2) == 0 + /* Drive letter prefix? */ + || (isalpha((unsigned char)str[0]) && str[1] == ':')) + /* Assume this an absolute file path - usually true */ + return vlc_path2uri(str, NULL); + /* TODO: drive-relative path: if (str[0] == '\\') */ #endif - if( strstr( psz_mrl, "://" ) ) - return strdup( psz_mrl ); - /* This a relative path, prepend the prefix */ - char *ret; - char *postfix = vlc_uri_encode( psz_mrl ); - /* FIXME: postfix may not be encoded correctly (esp. slashes) */ - if( postfix == NULL - || asprintf( &ret, "%s%s", psz_prefix, postfix ) == -1 ) - ret = NULL; - free( postfix ); - return ret; - -uri: - return vlc_path2uri( psz_mrl, NULL ); +#ifdef HAVE_OPEN_MEMSTREAM + /* The base URL is always an URL: it is the URL of the playlist. + * + * However it is not always known if the input string is a valid URL, a + * broken URL or a local file path. As a rule, if it looks like a valid + * URL, it must be treated as such, since most playlist formats use URLs. + * + * There are a few corner cases file paths that look like an URL but whose + * URL representation does not match, notably when they contain a + * percentage sign, a colon, a hash or a question mark. Luckily, they are + * rather exceptional (and can be encoded as URL to make the playlist + * work properly). + * + * If the input is not a valid URL, then we try to fix it up. It works in + * all cases for URLs with incorrectly encoded segments, such as URLs with + * white spaces or non-ASCII Unicode code points. It also works in most + * cases where the input is a Unix-style file path, but not all. + * It fails miserably if the playlist character encoding is misdetected. + */ + char *rel = vlc_uri_fixup(str); + if (rel != NULL) + str = rel; + + char *abs = vlc_uri_resolve(base, str); + free(rel); + return abs; +#else + const char *split = strrchr(base, '/'); + char *abs; + + assert(split != NULL); + + if (asprintf(&abs, "%.*s/%s", (int)(split - base), base, str) == -1) + abs = NULL; + return abs; +#endif } /** -- GitLab