You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

309 lines
8.2KB

  1. /*
  2. * URL utility functions
  3. * Copyright (c) 2000, 2001, 2002 Fabrice Bellard
  4. *
  5. * This file is part of FFmpeg.
  6. *
  7. * FFmpeg is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU Lesser General Public
  9. * License as published by the Free Software Foundation; either
  10. * version 2.1 of the License, or (at your option) any later version.
  11. *
  12. * FFmpeg is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public
  18. * License along with FFmpeg; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  20. */
  21. #include "avformat.h"
  22. #include "internal.h"
  23. #include "config.h"
  24. #include "url.h"
  25. #if CONFIG_NETWORK
  26. #include "network.h"
  27. #endif
  28. #include "libavutil/avassert.h"
  29. #include "libavutil/avstring.h"
  30. /**
  31. * @file
  32. * URL utility functions.
  33. */
  34. int ff_url_join(char *str, int size, const char *proto,
  35. const char *authorization, const char *hostname,
  36. int port, const char *fmt, ...)
  37. {
  38. #if CONFIG_NETWORK
  39. struct addrinfo hints = { 0 }, *ai;
  40. #endif
  41. str[0] = '\0';
  42. if (proto)
  43. av_strlcatf(str, size, "%s://", proto);
  44. if (authorization && authorization[0])
  45. av_strlcatf(str, size, "%s@", authorization);
  46. #if CONFIG_NETWORK && defined(AF_INET6)
  47. /* Determine if hostname is a numerical IPv6 address,
  48. * properly escape it within [] in that case. */
  49. hints.ai_flags = AI_NUMERICHOST;
  50. if (!getaddrinfo(hostname, NULL, &hints, &ai)) {
  51. if (ai->ai_family == AF_INET6) {
  52. av_strlcat(str, "[", size);
  53. av_strlcat(str, hostname, size);
  54. av_strlcat(str, "]", size);
  55. } else {
  56. av_strlcat(str, hostname, size);
  57. }
  58. freeaddrinfo(ai);
  59. } else
  60. #endif
  61. /* Not an IPv6 address, just output the plain string. */
  62. av_strlcat(str, hostname, size);
  63. if (port >= 0)
  64. av_strlcatf(str, size, ":%d", port);
  65. if (fmt) {
  66. va_list vl;
  67. size_t len = strlen(str);
  68. va_start(vl, fmt);
  69. vsnprintf(str + len, size > len ? size - len : 0, fmt, vl);
  70. va_end(vl);
  71. }
  72. return strlen(str);
  73. }
  74. static const char *find_delim(const char *delim, const char *cur, const char *end)
  75. {
  76. while (cur < end && !strchr(delim, *cur))
  77. cur++;
  78. return cur;
  79. }
  80. int ff_url_decompose(URLComponents *uc, const char *url, const char *end)
  81. {
  82. const char *cur, *aend, *p;
  83. av_assert0(url);
  84. if (!end)
  85. end = url + strlen(url);
  86. cur = uc->url = url;
  87. /* scheme */
  88. uc->scheme = cur;
  89. p = find_delim(":/", cur, end); /* lavf "schemes" can contain options */
  90. if (*p == ':')
  91. cur = p + 1;
  92. /* authority */
  93. uc->authority = cur;
  94. if (end - cur >= 2 && cur[0] == '/' && cur[1] == '/') {
  95. cur += 2;
  96. aend = find_delim("/?#", cur, end);
  97. /* userinfo */
  98. uc->userinfo = cur;
  99. p = find_delim("@", cur, aend);
  100. if (*p == '@')
  101. cur = p + 1;
  102. /* host */
  103. uc->host = cur;
  104. if (*cur == '[') { /* hello IPv6, thanks for using colons! */
  105. p = find_delim("]", cur, aend);
  106. if (*p != ']')
  107. return AVERROR(EINVAL);
  108. if (p + 1 < aend && p[1] != ':')
  109. return AVERROR(EINVAL);
  110. cur = p + 1;
  111. } else {
  112. cur = find_delim(":", cur, aend);
  113. }
  114. /* port */
  115. uc->port = cur;
  116. cur = aend;
  117. } else {
  118. uc->userinfo = uc->host = uc->port = cur;
  119. }
  120. /* path */
  121. uc->path = cur;
  122. cur = find_delim("?#", cur, end);
  123. /* query */
  124. uc->query = cur;
  125. if (*cur == '?')
  126. cur = find_delim("#", cur, end);
  127. /* fragment */
  128. uc->fragment = cur;
  129. uc->end = end;
  130. return 0;
  131. }
  132. static void trim_double_dot_url(char *buf, const char *rel, int size)
  133. {
  134. const char *p = rel;
  135. const char *root = rel;
  136. char tmp_path[MAX_URL_SIZE] = {0, };
  137. char *sep;
  138. char *node;
  139. /* Get the path root of the url which start by "://" */
  140. if (p && (sep = strstr(p, "://"))) {
  141. sep += 3;
  142. root = strchr(sep, '/');
  143. if (!root)
  144. return;
  145. }
  146. /* set new current position if the root node is changed */
  147. p = root;
  148. while (p && (node = strstr(p, ".."))) {
  149. av_strlcat(tmp_path, p, node - p + strlen(tmp_path));
  150. p = node + 3;
  151. sep = strrchr(tmp_path, '/');
  152. if (sep)
  153. sep[0] = '\0';
  154. else
  155. tmp_path[0] = '\0';
  156. }
  157. if (!av_stristart(p, "/", NULL) && root != rel)
  158. av_strlcat(tmp_path, "/", size);
  159. av_strlcat(tmp_path, p, size);
  160. /* start set buf after temp path process. */
  161. av_strlcpy(buf, rel, root - rel + 1);
  162. if (!av_stristart(tmp_path, "/", NULL) && root != rel)
  163. av_strlcat(buf, "/", size);
  164. av_strlcat(buf, tmp_path, size);
  165. }
  166. void ff_make_absolute_url(char *buf, int size, const char *base,
  167. const char *rel)
  168. {
  169. char *sep, *path_query;
  170. char *root, *p;
  171. char tmp_path[MAX_URL_SIZE];
  172. memset(tmp_path, 0, sizeof(tmp_path));
  173. /* Absolute path, relative to the current server */
  174. if (base && strstr(base, "://") && rel[0] == '/') {
  175. if (base != buf)
  176. av_strlcpy(buf, base, size);
  177. sep = strstr(buf, "://");
  178. if (sep) {
  179. /* Take scheme from base url */
  180. if (rel[1] == '/') {
  181. sep[1] = '\0';
  182. } else {
  183. /* Take scheme and host from base url */
  184. sep += 3;
  185. sep = strchr(sep, '/');
  186. if (sep)
  187. *sep = '\0';
  188. }
  189. }
  190. av_strlcat(buf, rel, size);
  191. trim_double_dot_url(tmp_path, buf, size);
  192. memset(buf, 0, size);
  193. av_strlcpy(buf, tmp_path, size);
  194. return;
  195. }
  196. /* If rel actually is an absolute url, just copy it */
  197. if (!base || strstr(rel, "://") || rel[0] == '/') {
  198. memset(buf, 0, size);
  199. trim_double_dot_url(buf, rel, size);
  200. return;
  201. }
  202. if (base != buf)
  203. av_strlcpy(buf, base, size);
  204. /* Strip off any query string from base */
  205. path_query = strchr(buf, '?');
  206. if (path_query)
  207. *path_query = '\0';
  208. /* Is relative path just a new query part? */
  209. if (rel[0] == '?') {
  210. av_strlcat(buf, rel, size);
  211. trim_double_dot_url(tmp_path, buf, size);
  212. memset(buf, 0, size);
  213. av_strlcpy(buf, tmp_path, size);
  214. return;
  215. }
  216. root = p = buf;
  217. /* Get the path root of the url which start by "://" */
  218. if (p && strstr(p, "://")) {
  219. sep = strstr(p, "://");
  220. if (sep) {
  221. sep += 3;
  222. root = strchr(sep, '/');
  223. if (!root)
  224. return;
  225. }
  226. }
  227. /* Remove the file name from the base url */
  228. sep = strrchr(buf, '/');
  229. if (sep && sep <= root)
  230. sep = root;
  231. if (sep)
  232. sep[1] = '\0';
  233. else
  234. buf[0] = '\0';
  235. while (av_strstart(rel, "..", NULL) && sep) {
  236. /* Remove the path delimiter at the end */
  237. if (sep > root) {
  238. sep[0] = '\0';
  239. sep = strrchr(buf, '/');
  240. }
  241. /* If the next directory name to pop off is "..", break here */
  242. if (!strcmp(sep ? &sep[1] : buf, "..")) {
  243. /* Readd the slash we just removed */
  244. av_strlcat(buf, "/", size);
  245. break;
  246. }
  247. /* Cut off the directory name */
  248. if (sep)
  249. sep[1] = '\0';
  250. else
  251. buf[0] = '\0';
  252. rel += 3;
  253. }
  254. av_strlcat(buf, rel, size);
  255. trim_double_dot_url(tmp_path, buf, size);
  256. memset(buf, 0, size);
  257. av_strlcpy(buf, tmp_path, size);
  258. }
  259. AVIODirEntry *ff_alloc_dir_entry(void)
  260. {
  261. AVIODirEntry *entry = av_mallocz(sizeof(AVIODirEntry));
  262. if (entry) {
  263. entry->type = AVIO_ENTRY_UNKNOWN;
  264. entry->size = -1;
  265. entry->modification_timestamp = -1;
  266. entry->access_timestamp = -1;
  267. entry->status_change_timestamp = -1;
  268. entry->user_id = -1;
  269. entry->group_id = -1;
  270. entry->filemode = -1;
  271. }
  272. return entry;
  273. }