4 * Copyright (C) 2001 Bertrand Baudet <bertrand_baudet@yahoo.com>
6 * This file is part of MPlayer.
8 * MPlayer is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * MPlayer is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License along
19 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
33 #define SIZE_MAX ((size_t)-1)
36 URL_t
*url_redirect(URL_t
**url
, const char *redir
) {
39 if (!strchr(redir
, '/') || *redir
== '/') {
41 char *newurl
= malloc(strlen(u
->url
) + strlen(redir
) + 1);
42 strcpy(newurl
, u
->url
);
45 tmp
= strstr(newurl
, "://");
46 if (tmp
) tmp
= strchr(tmp
+ 3, '/');
48 tmp
= strrchr(newurl
, '/');
50 strcat(newurl
, redir
);
51 res
= url_new(newurl
);
60 static int make_noauth_url(URL_t
*url
, char *dst
, int dst_size
)
63 return snprintf(dst
, dst_size
, "%s://%s:%d%s", url
->protocol
,
64 url
->hostname
, url
->port
, url
->file
);
66 return snprintf(dst
, dst_size
, "%s://%s%s", url
->protocol
,
67 url
->hostname
, url
->file
);
70 int make_http_proxy_url(URL_t
*proxy
, const char *host_url
, char *dst
,
74 return snprintf(dst
, dst_size
, "http_proxy://%s:%s@%s:%d/%s",
76 proxy
->password
? proxy
->password
: "",
77 proxy
->hostname
, proxy
->port
, host_url
);
79 return snprintf(dst
, dst_size
, "http_proxy://%s:%d/%s",
80 proxy
->hostname
, proxy
->port
, host_url
);
84 url_new(const char* url
) {
85 int pos1
, pos2
,v6addr
= 0, noauth_len
;
87 char *escfilename
=NULL
;
88 char *ptr1
=NULL
, *ptr2
=NULL
, *ptr3
=NULL
, *ptr4
=NULL
;
91 if( url
==NULL
) return NULL
;
93 if (strlen(url
) > (SIZE_MAX
/ 3 - 1)) {
94 mp_tmsg(MSGT_NETWORK
,MSGL_FATAL
,"Memory allocation failed.\n");
97 escfilename
=malloc(strlen(url
)*3+1);
99 mp_tmsg(MSGT_NETWORK
,MSGL_FATAL
,"Memory allocation failed.\n");
103 // Create the URL container
104 Curl
= calloc(1, sizeof(*Curl
));
106 mp_tmsg(MSGT_NETWORK
,MSGL_FATAL
,"Memory allocation failed.\n");
110 url_escape_string(escfilename
,url
);
112 // Copy the url in the URL container
113 Curl
->url
= strdup(escfilename
);
114 if( Curl
->url
==NULL
) {
115 mp_tmsg(MSGT_NETWORK
,MSGL_FATAL
,"Memory allocation failed.\n");
118 mp_msg(MSGT_OPEN
,MSGL_V
,"Filename for url is now %s\n",escfilename
);
120 // extract the protocol
121 ptr1
= strstr(escfilename
, "://");
123 // Check for a special case: "sip:" (without "//"):
124 if (strstr(escfilename
, "sip:") == escfilename
) {
125 ptr1
= (char *)&url
[3]; // points to ':'
128 mp_msg(MSGT_NETWORK
,MSGL_V
,"Not an URL!\n");
132 pos1
= ptr1
-escfilename
;
133 Curl
->protocol
= malloc(pos1
+1);
134 if( Curl
->protocol
==NULL
) {
135 mp_tmsg(MSGT_NETWORK
,MSGL_FATAL
,"Memory allocation failed.\n");
138 strncpy(Curl
->protocol
, escfilename
, pos1
);
139 Curl
->protocol
[pos1
] = '\0';
145 // check if a username:password is given
146 ptr2
= strstr(ptr1
, "@");
147 ptr3
= strstr(ptr1
, "/");
148 if( ptr3
!=NULL
&& ptr3
<ptr2
) {
149 // it isn't really a username but rather a part of the path
153 // We got something, at least a username...
155 Curl
->username
= malloc(len
+1);
156 if( Curl
->username
==NULL
) {
157 mp_tmsg(MSGT_NETWORK
,MSGL_FATAL
,"Memory allocation failed.\n");
160 strncpy(Curl
->username
, ptr1
, len
);
161 Curl
->username
[len
] = '\0';
163 ptr3
= strstr(ptr1
, ":");
164 if( ptr3
!=NULL
&& ptr3
<ptr2
) {
165 // We also have a password
166 int len2
= ptr2
-ptr3
-1;
167 Curl
->username
[ptr3
-ptr1
]='\0';
168 Curl
->password
= malloc(len2
+1);
169 if( Curl
->password
==NULL
) {
170 mp_tmsg(MSGT_NETWORK
,MSGL_FATAL
,"Memory allocation failed.\n");
173 strncpy( Curl
->password
, ptr3
+1, len2
);
174 Curl
->password
[len2
]='\0';
175 url_unescape_string(Curl
->password
, Curl
->password
);
177 url_unescape_string(Curl
->username
, Curl
->username
);
179 pos1
= ptr1
-escfilename
;
182 // before looking for a port number check if we have an IPv6 type numeric address
183 // in IPv6 URL the numeric address should be inside square braces.
184 ptr2
= strstr(ptr1
, "[");
185 ptr3
= strstr(ptr1
, "]");
186 ptr4
= strstr(ptr1
, "/");
187 if( ptr2
!=NULL
&& ptr3
!=NULL
&& ptr2
< ptr3
&& (!ptr4
|| ptr4
> ptr3
)) {
188 // we have an IPv6 numeric address
198 // look if the port is given
199 ptr2
= strstr(ptr2
, ":");
200 // If the : is after the first / it isn't the port
201 ptr3
= strstr(ptr1
, "/");
202 if(ptr3
&& ptr3
- ptr2
< 0) ptr2
= NULL
;
205 // Look if a path is given
208 // So we have an URL like http://www.hostname.com
209 pos2
= strlen(escfilename
);
211 // We have an URL like http://www.hostname.com/file.txt
212 pos2
= ptr3
-escfilename
;
215 // We have an URL beginning like http://www.hostname.com:1212
216 // Get the port number
217 Curl
->port
= atoi(ptr2
+1);
218 pos2
= ptr2
-escfilename
;
221 // copy the hostname in the URL container
222 Curl
->hostname
= malloc(pos2
-pos1
+1);
223 if( Curl
->hostname
==NULL
) {
224 mp_tmsg(MSGT_NETWORK
,MSGL_FATAL
,"Memory allocation failed.\n");
227 strncpy(Curl
->hostname
, ptr1
, pos2
-pos1
);
228 Curl
->hostname
[pos2
-pos1
] = '\0';
230 // Look if a path is given
231 ptr2
= strstr(ptr1
, "/");
233 // A path/filename is given
234 // check if it's not a trailing '/'
235 if( strlen(ptr2
)>1 ) {
236 // copy the path/filename in the URL container
237 Curl
->file
= strdup(ptr2
);
238 if( Curl
->file
==NULL
) {
239 mp_tmsg(MSGT_NETWORK
,MSGL_FATAL
,"Memory allocation failed.\n");
244 // Check if a filename was given or set, else set it with '/'
245 if( Curl
->file
==NULL
) {
246 Curl
->file
= malloc(2);
247 if( Curl
->file
==NULL
) {
248 mp_tmsg(MSGT_NETWORK
,MSGL_FATAL
,"Memory allocation failed.\n");
251 strcpy(Curl
->file
, "/");
254 noauth_len
= make_noauth_url(Curl
, NULL
, 0);
255 if (noauth_len
> 0) {
257 Curl
->noauth_url
= malloc(noauth_len
);
258 if (!Curl
->noauth_url
) {
259 mp_msg(MSGT_NETWORK
, MSGL_FATAL
, "Memory allocation failed.\n");
262 make_noauth_url(Curl
, Curl
->noauth_url
, noauth_len
);
269 if (Curl
) url_free(Curl
);
274 url_free(URL_t
* url
) {
286 /* Replace escape sequences in an URL (or a part of an URL) */
287 /* works like strcpy(), but without return argument,
288 except that outbuf == inbuf is allowed */
290 url_unescape_string(char *outbuf
, const char *inbuf
)
292 unsigned char c
,c1
,c2
;
293 int i
,len
=strlen(inbuf
);
296 if (c
== '%' && i
<len
-2) { //must have 2 more chars
297 c1
= toupper(inbuf
[i
+1]); // we need uppercase characters
298 c2
= toupper(inbuf
[i
+2]);
299 if ( ((c1
>='0' && c1
<='9') || (c1
>='A' && c1
<='F')) &&
300 ((c2
>='0' && c2
<='9') || (c2
>='A' && c2
<='F')) ) {
301 if (c1
>='0' && c1
<='9') c1
-='0';
303 if (c2
>='0' && c2
<='9') c2
-='0';
306 i
=i
+2; //only skip next 2 chars if valid esc
311 *outbuf
++='\0'; //add nullterm to string
315 url_escape_string_part(char *outbuf
, const char *inbuf
) {
316 unsigned char c
,c1
,c2
;
317 int i
,len
=strlen(inbuf
);
319 for (i
=0;i
<len
;i
++) {
321 if ((c
=='%') && i
<len
-2 ) { //need 2 more characters
322 c1
=toupper(inbuf
[i
+1]); c2
=toupper(inbuf
[i
+2]); // need uppercase chars
324 c1
=129; c2
=129; //not escape chars
327 if( (c
>= 'A' && c
<= 'Z') ||
328 (c
>= 'a' && c
<= 'z') ||
329 (c
>= '0' && c
<= '9')) {
331 } else if ( c
=='%' && ((c1
>= '0' && c1
<= '9') || (c1
>= 'A' && c1
<= 'F')) &&
332 ((c2
>= '0' && c2
<= '9') || (c2
>= 'A' && c2
<= 'F'))) {
333 // check if part of an escape sequence
334 *outbuf
++=c
; // already
337 mp_tmsg(MSGT_NETWORK
,MSGL_ERR
,"String appears to be already escaped in url_escape %c%c1%c2\n",c
,c1
,c2
);
338 // error as this should not happen against RFC 2396
339 // to escape a string twice
341 /* all others will be escaped */
342 c1
= ((c
& 0xf0) >> 4);
344 if (c1
< 10) c1
+='0';
346 if (c2
< 10) c2
+='0';
356 /* Replace specific characters in the URL string by an escape sequence */
357 /* works like strcpy(), but without return argument */
359 url_escape_string(char *outbuf
, const char *inbuf
) {
361 int i
= 0,j
,len
= strlen(inbuf
);
362 char* tmp
,*unesc
= NULL
, *in
;
364 // Look if we have an ip6 address, if so skip it there is
365 // no need to escape anything in there.
366 tmp
= strstr(inbuf
,"://[");
368 tmp
= strchr(tmp
+4,']');
369 if(tmp
&& (tmp
[1] == '/' || tmp
[1] == ':' ||
372 strncpy(outbuf
,inbuf
,i
);
380 // look for the next char that must be kept
381 for (j
=i
;j
<len
;j
++) {
383 if(c
=='-' || c
=='_' || c
=='.' || c
=='!' || c
=='~' || /* mark characters */
384 c
=='*' || c
=='\'' || c
=='(' || c
==')' || /* do not touch escape character */
385 c
==';' || c
=='/' || c
=='?' || c
==':' || c
=='@' || /* reserved characters */
386 c
=='&' || c
=='=' || c
=='+' || c
=='$' || c
==',') /* see RFC 2396 */
389 // we are on a reserved char, write it out
395 // we found one, take that part of the string
397 if(!tmp
) tmp
= malloc(len
+1);
398 strncpy(tmp
,inbuf
+i
,j
-i
);
401 } else // take the rest of the string
404 if(!unesc
) unesc
= malloc(len
+1);
405 // unescape first to avoid escaping escape
406 url_unescape_string(unesc
,in
);
407 // then escape, including mark and other reserved chars
408 // that can come from escape sequences
409 url_escape_string_part(outbuf
,unesc
);
410 outbuf
+= strlen(outbuf
);
420 url_debug(const URL_t
*url
) {
422 printf("URL pointer NULL\n");
425 if( url
->url
!=NULL
) {
426 printf("url=%s\n", url
->url
);
428 if( url
->protocol
!=NULL
) {
429 printf("protocol=%s\n", url
->protocol
);
431 if( url
->hostname
!=NULL
) {
432 printf("hostname=%s\n", url
->hostname
);
434 printf("port=%d\n", url
->port
);
435 if( url
->file
!=NULL
) {
436 printf("file=%s\n", url
->file
);
438 if( url
->username
!=NULL
) {
439 printf("username=%s\n", url
->username
);
441 if( url
->password
!=NULL
) {
442 printf("password=%s\n", url
->password
);
445 #endif /* URL_DEBUG */