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.

238 lines
6.6KB

  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/avstring.h"
  29. /**
  30. * @file
  31. * URL utility functions.
  32. */
  33. int ff_url_join(char *str, int size, const char *proto,
  34. const char *authorization, const char *hostname,
  35. int port, const char *fmt, ...)
  36. {
  37. #if CONFIG_NETWORK
  38. struct addrinfo hints = { 0 }, *ai;
  39. #endif
  40. str[0] = '\0';
  41. if (proto)
  42. av_strlcatf(str, size, "%s://", proto);
  43. if (authorization && authorization[0])
  44. av_strlcatf(str, size, "%s@", authorization);
  45. #if CONFIG_NETWORK && defined(AF_INET6)
  46. /* Determine if hostname is a numerical IPv6 address,
  47. * properly escape it within [] in that case. */
  48. hints.ai_flags = AI_NUMERICHOST;
  49. if (!getaddrinfo(hostname, NULL, &hints, &ai)) {
  50. if (ai->ai_family == AF_INET6) {
  51. av_strlcat(str, "[", size);
  52. av_strlcat(str, hostname, size);
  53. av_strlcat(str, "]", size);
  54. } else {
  55. av_strlcat(str, hostname, size);
  56. }
  57. freeaddrinfo(ai);
  58. } else
  59. #endif
  60. /* Not an IPv6 address, just output the plain string. */
  61. av_strlcat(str, hostname, size);
  62. if (port >= 0)
  63. av_strlcatf(str, size, ":%d", port);
  64. if (fmt) {
  65. va_list vl;
  66. size_t len = strlen(str);
  67. va_start(vl, fmt);
  68. vsnprintf(str + len, size > len ? size - len : 0, fmt, vl);
  69. va_end(vl);
  70. }
  71. return strlen(str);
  72. }
  73. static void trim_double_dot_url(char *buf, const char *rel, int size)
  74. {
  75. const char *p = rel;
  76. const char *root = rel;
  77. char tmp_path[MAX_URL_SIZE] = {0, };
  78. char *sep;
  79. char *node;
  80. /* Get the path root of the url which start by "://" */
  81. if (p && (sep = strstr(p, "://"))) {
  82. sep += 3;
  83. root = strchr(sep, '/');
  84. if (!root)
  85. return;
  86. }
  87. /* set new current position if the root node is changed */
  88. p = root;
  89. while (p && (node = strstr(p, ".."))) {
  90. av_strlcat(tmp_path, p, node - p + strlen(tmp_path));
  91. p = node + 3;
  92. sep = strrchr(tmp_path, '/');
  93. if (sep)
  94. sep[0] = '\0';
  95. else
  96. tmp_path[0] = '\0';
  97. }
  98. if (!av_stristart(p, "/", NULL) && root != rel)
  99. av_strlcat(tmp_path, "/", size);
  100. av_strlcat(tmp_path, p, size);
  101. /* start set buf after temp path process. */
  102. av_strlcpy(buf, rel, root - rel + 1);
  103. if (!av_stristart(tmp_path, "/", NULL) && root != rel)
  104. av_strlcat(buf, "/", size);
  105. av_strlcat(buf, tmp_path, size);
  106. }
  107. void ff_make_absolute_url(char *buf, int size, const char *base,
  108. const char *rel)
  109. {
  110. char *sep, *path_query;
  111. char *root, *p;
  112. char tmp_path[MAX_URL_SIZE];
  113. memset(tmp_path, 0, sizeof(tmp_path));
  114. /* Absolute path, relative to the current server */
  115. if (base && strstr(base, "://") && rel[0] == '/') {
  116. if (base != buf)
  117. av_strlcpy(buf, base, size);
  118. sep = strstr(buf, "://");
  119. if (sep) {
  120. /* Take scheme from base url */
  121. if (rel[1] == '/') {
  122. sep[1] = '\0';
  123. } else {
  124. /* Take scheme and host from base url */
  125. sep += 3;
  126. sep = strchr(sep, '/');
  127. if (sep)
  128. *sep = '\0';
  129. }
  130. }
  131. av_strlcat(buf, rel, size);
  132. trim_double_dot_url(tmp_path, buf, size);
  133. memset(buf, 0, size);
  134. av_strlcpy(buf, tmp_path, size);
  135. return;
  136. }
  137. /* If rel actually is an absolute url, just copy it */
  138. if (!base || strstr(rel, "://") || rel[0] == '/') {
  139. memset(buf, 0, size);
  140. trim_double_dot_url(buf, rel, size);
  141. return;
  142. }
  143. if (base != buf)
  144. av_strlcpy(buf, base, size);
  145. /* Strip off any query string from base */
  146. path_query = strchr(buf, '?');
  147. if (path_query)
  148. *path_query = '\0';
  149. /* Is relative path just a new query part? */
  150. if (rel[0] == '?') {
  151. av_strlcat(buf, rel, size);
  152. trim_double_dot_url(tmp_path, buf, size);
  153. memset(buf, 0, size);
  154. av_strlcpy(buf, tmp_path, size);
  155. return;
  156. }
  157. root = p = buf;
  158. /* Get the path root of the url which start by "://" */
  159. if (p && strstr(p, "://")) {
  160. sep = strstr(p, "://");
  161. if (sep) {
  162. sep += 3;
  163. root = strchr(sep, '/');
  164. if (!root)
  165. return;
  166. }
  167. }
  168. /* Remove the file name from the base url */
  169. sep = strrchr(buf, '/');
  170. if (sep && sep <= root)
  171. sep = root;
  172. if (sep)
  173. sep[1] = '\0';
  174. else
  175. buf[0] = '\0';
  176. while (av_strstart(rel, "..", NULL) && sep) {
  177. /* Remove the path delimiter at the end */
  178. if (sep > root) {
  179. sep[0] = '\0';
  180. sep = strrchr(buf, '/');
  181. }
  182. /* If the next directory name to pop off is "..", break here */
  183. if (!strcmp(sep ? &sep[1] : buf, "..")) {
  184. /* Readd the slash we just removed */
  185. av_strlcat(buf, "/", size);
  186. break;
  187. }
  188. /* Cut off the directory name */
  189. if (sep)
  190. sep[1] = '\0';
  191. else
  192. buf[0] = '\0';
  193. rel += 3;
  194. }
  195. av_strlcat(buf, rel, size);
  196. trim_double_dot_url(tmp_path, buf, size);
  197. memset(buf, 0, size);
  198. av_strlcpy(buf, tmp_path, size);
  199. }
  200. AVIODirEntry *ff_alloc_dir_entry(void)
  201. {
  202. AVIODirEntry *entry = av_mallocz(sizeof(AVIODirEntry));
  203. if (entry) {
  204. entry->type = AVIO_ENTRY_UNKNOWN;
  205. entry->size = -1;
  206. entry->modification_timestamp = -1;
  207. entry->access_timestamp = -1;
  208. entry->status_change_timestamp = -1;
  209. entry->user_id = -1;
  210. entry->group_id = -1;
  211. entry->filemode = -1;
  212. }
  213. return entry;
  214. }