[FFmpeg-devel] [PATCH 1/2] lavf/url: add ff_url_decompose().
Marton Balint
cus at passwd.hu
Tue Aug 4 01:46:44 EEST 2020
On Thu, 30 Jul 2020, Nicolas George wrote:
> Signed-off-by: Nicolas George <george at nsup.org>
> ---
> libavformat/tests/url.c | 34 +++++++++++++++++++
> libavformat/url.c | 74 +++++++++++++++++++++++++++++++++++++++++
> libavformat/url.h | 41 +++++++++++++++++++++++
> tests/ref/fate/url | 45 +++++++++++++++++++++++++
> 4 files changed, 194 insertions(+)
>
>
> I chose to keep only pointers to the beginnings despite Marton's
> suggestion because I find it plays better with re-constructing the URL
> afterwards. The property that each char of the string belongs to one and
> only one part is a good invariant, and the delimiting characters are
> clearly documented and allow to check if the field is present.
Ok.
>
> Compared with the previous iteration, I added a few macros and the
> handling of NULL.
>
>
> diff --git a/libavformat/tests/url.c b/libavformat/tests/url.c
> index 1d961a1b43..e7d259ab7d 100644
> --- a/libavformat/tests/url.c
> +++ b/libavformat/tests/url.c
> @@ -21,6 +21,31 @@
> #include "libavformat/url.h"
> #include "libavformat/avformat.h"
>
> +static void test_decompose(const char *url)
> +{
> + URLComponents uc;
> + int len, ret;
> +
> + printf("%s =>\n", url);
> + ret = ff_url_decompose(&uc, url, NULL);
> + if (ret < 0) {
> + printf(" error: %s\n", av_err2str(ret));
> + return;
> + }
> +#define PRINT_COMPONENT(comp) \
> + len = uc.url_component_end_##comp - uc.comp; \
> + if (len) printf(" "#comp": %.*s\n", len, uc.comp);
> + PRINT_COMPONENT(scheme);
> + PRINT_COMPONENT(authority);
> + PRINT_COMPONENT(userinfo);
> + PRINT_COMPONENT(host);
> + PRINT_COMPONENT(port);
> + PRINT_COMPONENT(path);
> + PRINT_COMPONENT(query);
> + PRINT_COMPONENT(fragment);
> + printf("\n");
> +}
> +
> static void test(const char *base, const char *rel)
> {
> char buf[200], buf2[200];
> @@ -51,6 +76,15 @@ static void test2(const char *url)
>
> int main(void)
> {
> + printf("Testing ff_url_decompose:\n\n");
> + test_decompose("http://user:pass@ffmpeg:8080/dir/file?query#fragment");
> + test_decompose("http://ffmpeg/dir/file");
> + test_decompose("file:///dev/null");
> + test_decompose("file:/dev/null");
> + test_decompose("http://[::1]/dev/null");
> + test_decompose("http://[::1]:8080/dev/null");
> + test_decompose("//ffmpeg/dev/null");
> +
> printf("Testing ff_make_absolute_url:\n");
> test(NULL, "baz");
> test("/foo/bar", "baz");
> diff --git a/libavformat/url.c b/libavformat/url.c
> index 20463a6674..26aaab4019 100644
> --- a/libavformat/url.c
> +++ b/libavformat/url.c
> @@ -78,6 +78,80 @@ int ff_url_join(char *str, int size, const char *proto,
> return strlen(str);
> }
>
> +static const char *find_delim(const char *delim, const char *cur, const char *end)
> +{
> + while (cur < end && !strchr(delim, *cur))
> + cur++;
> + return cur;
> +}
> +
> +int ff_url_decompose(URLComponents *uc, const char *url, const char *end)
> +{
> + const char *cur, *aend, *p;
> +
> + if (!url) {
> + URLComponents nul = { 0 };
> + *uc = nul;
So you are returning NULL pointers here and success at the same time. This
does not look like a good idea, e.g. checking fields later on involves
arithmetic on NULL pointers, no? I don't really see it useful that we
handle NULL url here, we are better off with an assert IMHO.
> + return 0;
> + }
> + if (!end)
> + end = url + strlen(url);
> + cur = uc->url = url;
> +
> + /* scheme */
> + uc->scheme = cur;
> + p = find_delim(":/", cur, end); /* lavf "schemes" can contain options */
> + if (*p == ':')
> + cur = p + 1;
> +
> + /* authority */
> + uc->authority = cur;
> + if (end - cur >= 2 && cur[0] == '/' && cur[1] == '/') {
> + cur += 2;
> + aend = find_delim("/?#", cur, end);
> +
> + /* userinfo */
> + uc->userinfo = cur;
> + p = find_delim("@", cur, aend);
> + if (*p == '@')
> + cur = p + 1;
> +
> + /* host */
> + uc->host = cur;
> + if (*cur == '[') { /* hello IPv6, thanks for using colons! */
> + p = find_delim("]", cur, aend);
> + if (*p != ']')
> + return AVERROR(EINVAL);
> + if (p + 1 < aend && p[1] != ':')
> + return AVERROR(EINVAL);
> + cur = p + 1;
This is the only place where we might return failure. Maybe we could
convert this to void() function to simplify usage a bit, and either
- assume no port, if it is not paraseable or
- not split host and port, so we don't have to parse IPv6 mess here,
therefore the error can't happen.
Thanks,
Marton
More information about the ffmpeg-devel
mailing list