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.

148 lines
4.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 "config.h"
  23. #include "url.h"
  24. #if CONFIG_NETWORK
  25. #include "network.h"
  26. #endif
  27. #include "libavutil/avstring.h"
  28. /**
  29. * @file
  30. * URL utility functions.
  31. */
  32. int ff_url_join(char *str, int size, const char *proto,
  33. const char *authorization, const char *hostname,
  34. int port, const char *fmt, ...)
  35. {
  36. #if CONFIG_NETWORK
  37. struct addrinfo hints = { 0 }, *ai;
  38. #endif
  39. str[0] = '\0';
  40. if (proto)
  41. av_strlcatf(str, size, "%s://", proto);
  42. if (authorization && authorization[0])
  43. av_strlcatf(str, size, "%s@", authorization);
  44. #if CONFIG_NETWORK && defined(AF_INET6)
  45. /* Determine if hostname is a numerical IPv6 address,
  46. * properly escape it within [] in that case. */
  47. hints.ai_flags = AI_NUMERICHOST;
  48. if (!getaddrinfo(hostname, NULL, &hints, &ai)) {
  49. if (ai->ai_family == AF_INET6) {
  50. av_strlcat(str, "[", size);
  51. av_strlcat(str, hostname, size);
  52. av_strlcat(str, "]", size);
  53. } else {
  54. av_strlcat(str, hostname, size);
  55. }
  56. freeaddrinfo(ai);
  57. } else
  58. #endif
  59. /* Not an IPv6 address, just output the plain string. */
  60. av_strlcat(str, hostname, size);
  61. if (port >= 0)
  62. av_strlcatf(str, size, ":%d", port);
  63. if (fmt) {
  64. va_list vl;
  65. int len = strlen(str);
  66. va_start(vl, fmt);
  67. vsnprintf(str + len, size > len ? size - len : 0, fmt, vl);
  68. va_end(vl);
  69. }
  70. return strlen(str);
  71. }
  72. void ff_make_absolute_url(char *buf, int size, const char *base,
  73. const char *rel)
  74. {
  75. char *sep, *path_query;
  76. /* Absolute path, relative to the current server */
  77. if (base && strstr(base, "://") && rel[0] == '/') {
  78. if (base != buf)
  79. av_strlcpy(buf, base, size);
  80. sep = strstr(buf, "://");
  81. if (sep) {
  82. /* Take scheme from base url */
  83. if (rel[1] == '/') {
  84. sep[1] = '\0';
  85. } else {
  86. /* Take scheme and host from base url */
  87. sep += 3;
  88. sep = strchr(sep, '/');
  89. if (sep)
  90. *sep = '\0';
  91. }
  92. }
  93. av_strlcat(buf, rel, size);
  94. return;
  95. }
  96. /* If rel actually is an absolute url, just copy it */
  97. if (!base || strstr(rel, "://") || rel[0] == '/') {
  98. av_strlcpy(buf, rel, size);
  99. return;
  100. }
  101. if (base != buf)
  102. av_strlcpy(buf, base, size);
  103. /* Strip off any query string from base */
  104. path_query = strchr(buf, '?');
  105. if (path_query != NULL)
  106. *path_query = '\0';
  107. /* Is relative path just a new query part? */
  108. if (rel[0] == '?') {
  109. av_strlcat(buf, rel, size);
  110. return;
  111. }
  112. /* Remove the file name from the base url */
  113. sep = strrchr(buf, '/');
  114. if (sep)
  115. sep[1] = '\0';
  116. else
  117. buf[0] = '\0';
  118. while (av_strstart(rel, "../", NULL) && sep) {
  119. /* Remove the path delimiter at the end */
  120. sep[0] = '\0';
  121. sep = strrchr(buf, '/');
  122. /* If the next directory name to pop off is "..", break here */
  123. if (!strcmp(sep ? &sep[1] : buf, "..")) {
  124. /* Readd the slash we just removed */
  125. av_strlcat(buf, "/", size);
  126. break;
  127. }
  128. /* Cut off the directory name */
  129. if (sep)
  130. sep[1] = '\0';
  131. else
  132. buf[0] = '\0';
  133. rel += 3;
  134. }
  135. av_strlcat(buf, rel, size);
  136. }