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.

233 lines
6.5KB

  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. }
  85. /* set new current position if the root node is changed */
  86. p = root;
  87. while (p && (node = strstr(p, ".."))) {
  88. av_strlcat(tmp_path, p, node - p + strlen(tmp_path));
  89. p = node + 3;
  90. sep = strrchr(tmp_path, '/');
  91. if (sep)
  92. sep[0] = '\0';
  93. else
  94. tmp_path[0] = '\0';
  95. }
  96. if (!av_stristart(p, "/", NULL) && root != rel)
  97. av_strlcat(tmp_path, "/", size);
  98. av_strlcat(tmp_path, p, size);
  99. /* start set buf after temp path process. */
  100. av_strlcpy(buf, rel, root - rel + 1);
  101. if (!av_stristart(tmp_path, "/", NULL) && root != rel)
  102. av_strlcat(buf, "/", size);
  103. av_strlcat(buf, tmp_path, size);
  104. }
  105. void ff_make_absolute_url(char *buf, int size, const char *base,
  106. const char *rel)
  107. {
  108. char *sep, *path_query;
  109. char *root, *p;
  110. char tmp_path[MAX_URL_SIZE];
  111. memset(tmp_path, 0, sizeof(tmp_path));
  112. /* Absolute path, relative to the current server */
  113. if (base && strstr(base, "://") && rel[0] == '/') {
  114. if (base != buf)
  115. av_strlcpy(buf, base, size);
  116. sep = strstr(buf, "://");
  117. if (sep) {
  118. /* Take scheme from base url */
  119. if (rel[1] == '/') {
  120. sep[1] = '\0';
  121. } else {
  122. /* Take scheme and host from base url */
  123. sep += 3;
  124. sep = strchr(sep, '/');
  125. if (sep)
  126. *sep = '\0';
  127. }
  128. }
  129. av_strlcat(buf, rel, size);
  130. trim_double_dot_url(tmp_path, buf, size);
  131. memset(buf, 0, size);
  132. av_strlcpy(buf, tmp_path, size);
  133. return;
  134. }
  135. /* If rel actually is an absolute url, just copy it */
  136. if (!base || strstr(rel, "://") || rel[0] == '/') {
  137. trim_double_dot_url(buf, rel, size);
  138. return;
  139. }
  140. if (base != buf)
  141. av_strlcpy(buf, base, size);
  142. /* Strip off any query string from base */
  143. path_query = strchr(buf, '?');
  144. if (path_query)
  145. *path_query = '\0';
  146. /* Is relative path just a new query part? */
  147. if (rel[0] == '?') {
  148. av_strlcat(buf, rel, size);
  149. trim_double_dot_url(tmp_path, buf, size);
  150. memset(buf, 0, size);
  151. av_strlcpy(buf, tmp_path, size);
  152. return;
  153. }
  154. root = p = buf;
  155. /* Get the path root of the url which start by "://" */
  156. if (p && strstr(p, "://")) {
  157. sep = strstr(p, "://");
  158. if (sep) {
  159. sep += 3;
  160. root = strchr(sep, '/');
  161. }
  162. }
  163. /* Remove the file name from the base url */
  164. sep = strrchr(buf, '/');
  165. if (sep && sep <= root)
  166. sep = root;
  167. if (sep)
  168. sep[1] = '\0';
  169. else
  170. buf[0] = '\0';
  171. while (av_strstart(rel, "..", NULL) && sep) {
  172. /* Remove the path delimiter at the end */
  173. if (sep > root) {
  174. sep[0] = '\0';
  175. sep = strrchr(buf, '/');
  176. }
  177. /* If the next directory name to pop off is "..", break here */
  178. if (!strcmp(sep ? &sep[1] : buf, "..")) {
  179. /* Readd the slash we just removed */
  180. av_strlcat(buf, "/", size);
  181. break;
  182. }
  183. /* Cut off the directory name */
  184. if (sep)
  185. sep[1] = '\0';
  186. else
  187. buf[0] = '\0';
  188. rel += 3;
  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. }
  195. AVIODirEntry *ff_alloc_dir_entry(void)
  196. {
  197. AVIODirEntry *entry = av_mallocz(sizeof(AVIODirEntry));
  198. if (entry) {
  199. entry->type = AVIO_ENTRY_UNKNOWN;
  200. entry->size = -1;
  201. entry->modification_timestamp = -1;
  202. entry->access_timestamp = -1;
  203. entry->status_change_timestamp = -1;
  204. entry->user_id = -1;
  205. entry->group_id = -1;
  206. entry->filemode = -1;
  207. }
  208. return entry;
  209. }