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