Message ID | 20200805164957.86494-1-george@nsup.org |
---|---|
State | Accepted |
Headers | show |
Series | [FFmpeg-devel,v2,1/2] lavf/url: add ff_url_decompose(). | expand |
Context | Check | Description |
---|---|---|
andriy/default | pending | |
andriy/make | fail | Make failed |
On Wed, 5 Aug 2020, Nicolas George wrote: > Signed-off-by: Nicolas George <george@nsup.org> > --- > libavformat/tests/url.c | 34 ++++++++++++++++++++ > libavformat/url.c | 70 +++++++++++++++++++++++++++++++++++++++++ > libavformat/url.h | 41 ++++++++++++++++++++++++ > tests/ref/fate/url | 45 ++++++++++++++++++++++++++ > 4 files changed, 190 insertions(+) LGTM with the assert include added, thanks. Regards. Marton > > 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..abdae49070 100644 > --- a/libavformat/url.c > +++ b/libavformat/url.c > @@ -78,6 +78,76 @@ 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; > + > + av_assert0(url); > + 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; > + } else { > + cur = find_delim(":", cur, aend); > + } > + > + /* port */ > + uc->port = cur; > + cur = aend; > + } else { > + uc->userinfo = uc->host = uc->port = cur; > + } > + > + /* path */ > + uc->path = cur; > + cur = find_delim("?#", cur, end); > + > + /* query */ > + uc->query = cur; > + if (*cur == '?') > + cur = find_delim("#", cur, end); > + > + /* fragment */ > + uc->fragment = cur; > + > + uc->end = end; > + return 0; > +} > + > static void trim_double_dot_url(char *buf, const char *rel, int size) > { > const char *p = rel; > diff --git a/libavformat/url.h b/libavformat/url.h > index de0d30aca0..ae27da5c73 100644 > --- a/libavformat/url.h > +++ b/libavformat/url.h > @@ -344,4 +344,45 @@ const AVClass *ff_urlcontext_child_class_iterate(void **iter); > const URLProtocol **ffurl_get_protocols(const char *whitelist, > const char *blacklist); > > +typedef struct URLComponents { > + const char *url; /**< whole URL, for reference */ > + const char *scheme; /**< possibly including lavf-specific options */ > + const char *authority; /**< "//" if it is a real URL */ > + const char *userinfo; /**< including final '@' if present */ > + const char *host; > + const char *port; /**< including initial ':' if present */ > + const char *path; > + const char *query; /**< including initial '?' if present */ > + const char *fragment; /**< including initial '#' if present */ > + const char *end; > +} URLComponents; > + > +#define url_component_end_scheme authority > +#define url_component_end_authority userinfo > +#define url_component_end_userinfo host > +#define url_component_end_host port > +#define url_component_end_port path > +#define url_component_end_path query > +#define url_component_end_query fragment > +#define url_component_end_fragment end > +#define url_component_end_authority_full path > + > +#define URL_COMPONENT_HAVE(uc, component) \ > + ((uc).url_component_end_##component > (uc).component) > + > +/** > + * Parse an URL to find the components. > + * > + * Each component runs until the start of the next component, > + * possibly including a mandatory delimiter. > + * > + * @param uc structure to fill with pointers to the components. > + * @param url URL to parse. > + * @param end end of the URL, or NULL to parse to the end of string. > + * > + * @return >= 0 for success or an AVERROR code, especially if the URL is > + * malformed. > + */ > +int ff_url_decompose(URLComponents *uc, const char *url, const char *end); > + > #endif /* AVFORMAT_URL_H */ > diff --git a/tests/ref/fate/url b/tests/ref/fate/url > index 533ba2cb1e..84cf85abdd 100644 > --- a/tests/ref/fate/url > +++ b/tests/ref/fate/url > @@ -1,3 +1,48 @@ > +Testing ff_url_decompose: > + > +http://user:pass@ffmpeg:8080/dir/file?query#fragment => > + scheme: http: > + authority: // > + userinfo: user:pass@ > + host: ffmpeg > + port: :8080 > + path: /dir/file > + query: ?query > + fragment: #fragment > + > +http://ffmpeg/dir/file => > + scheme: http: > + authority: // > + host: ffmpeg > + path: /dir/file > + > +file:///dev/null => > + scheme: file: > + authority: // > + path: /dev/null > + > +file:/dev/null => > + scheme: file: > + path: /dev/null > + > +http://[::1]/dev/null => > + scheme: http: > + authority: // > + host: [::1] > + path: /dev/null > + > +http://[::1]:8080/dev/null => > + scheme: http: > + authority: // > + host: [::1] > + port: :8080 > + path: /dev/null > + > +//ffmpeg/dev/null => > + authority: // > + host: ffmpeg > + path: /dev/null > + > Testing ff_make_absolute_url: > (null) baz => baz > /foo/bar baz => /foo/baz > -- > 2.27.0 > > _______________________________________________ > ffmpeg-devel mailing list > ffmpeg-devel@ffmpeg.org > https://ffmpeg.org/mailman/listinfo/ffmpeg-devel > > To unsubscribe, visit link above, or email > ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
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..abdae49070 100644 --- a/libavformat/url.c +++ b/libavformat/url.c @@ -78,6 +78,76 @@ 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; + + av_assert0(url); + 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; + } else { + cur = find_delim(":", cur, aend); + } + + /* port */ + uc->port = cur; + cur = aend; + } else { + uc->userinfo = uc->host = uc->port = cur; + } + + /* path */ + uc->path = cur; + cur = find_delim("?#", cur, end); + + /* query */ + uc->query = cur; + if (*cur == '?') + cur = find_delim("#", cur, end); + + /* fragment */ + uc->fragment = cur; + + uc->end = end; + return 0; +} + static void trim_double_dot_url(char *buf, const char *rel, int size) { const char *p = rel; diff --git a/libavformat/url.h b/libavformat/url.h index de0d30aca0..ae27da5c73 100644 --- a/libavformat/url.h +++ b/libavformat/url.h @@ -344,4 +344,45 @@ const AVClass *ff_urlcontext_child_class_iterate(void **iter); const URLProtocol **ffurl_get_protocols(const char *whitelist, const char *blacklist); +typedef struct URLComponents { + const char *url; /**< whole URL, for reference */ + const char *scheme; /**< possibly including lavf-specific options */ + const char *authority; /**< "//" if it is a real URL */ + const char *userinfo; /**< including final '@' if present */ + const char *host; + const char *port; /**< including initial ':' if present */ + const char *path; + const char *query; /**< including initial '?' if present */ + const char *fragment; /**< including initial '#' if present */ + const char *end; +} URLComponents; + +#define url_component_end_scheme authority +#define url_component_end_authority userinfo +#define url_component_end_userinfo host +#define url_component_end_host port +#define url_component_end_port path +#define url_component_end_path query +#define url_component_end_query fragment +#define url_component_end_fragment end +#define url_component_end_authority_full path + +#define URL_COMPONENT_HAVE(uc, component) \ + ((uc).url_component_end_##component > (uc).component) + +/** + * Parse an URL to find the components. + * + * Each component runs until the start of the next component, + * possibly including a mandatory delimiter. + * + * @param uc structure to fill with pointers to the components. + * @param url URL to parse. + * @param end end of the URL, or NULL to parse to the end of string. + * + * @return >= 0 for success or an AVERROR code, especially if the URL is + * malformed. + */ +int ff_url_decompose(URLComponents *uc, const char *url, const char *end); + #endif /* AVFORMAT_URL_H */ diff --git a/tests/ref/fate/url b/tests/ref/fate/url index 533ba2cb1e..84cf85abdd 100644 --- a/tests/ref/fate/url +++ b/tests/ref/fate/url @@ -1,3 +1,48 @@ +Testing ff_url_decompose: + +http://user:pass@ffmpeg:8080/dir/file?query#fragment => + scheme: http: + authority: // + userinfo: user:pass@ + host: ffmpeg + port: :8080 + path: /dir/file + query: ?query + fragment: #fragment + +http://ffmpeg/dir/file => + scheme: http: + authority: // + host: ffmpeg + path: /dir/file + +file:///dev/null => + scheme: file: + authority: // + path: /dev/null + +file:/dev/null => + scheme: file: + path: /dev/null + +http://[::1]/dev/null => + scheme: http: + authority: // + host: [::1] + path: /dev/null + +http://[::1]:8080/dev/null => + scheme: http: + authority: // + host: [::1] + port: :8080 + path: /dev/null + +//ffmpeg/dev/null => + authority: // + host: ffmpeg + path: /dev/null + Testing ff_make_absolute_url: (null) baz => baz /foo/bar baz => /foo/baz
Signed-off-by: Nicolas George <george@nsup.org> --- libavformat/tests/url.c | 34 ++++++++++++++++++++ libavformat/url.c | 70 +++++++++++++++++++++++++++++++++++++++++ libavformat/url.h | 41 ++++++++++++++++++++++++ tests/ref/fate/url | 45 ++++++++++++++++++++++++++ 4 files changed, 190 insertions(+)