3 * by Bertrand Baudet <bertrand_baudet@yahoo.com>
4 * (C) 2001, MPlayer team.
19 #define SIZE_MAX ((size_t)-1)
22 URL_t
*url_redirect(URL_t
**url
, const char *redir
) {
25 if (!strchr(redir
, '/') || *redir
== '/') {
27 char *newurl
= malloc(strlen(u
->url
) + strlen(redir
) + 1);
28 strcpy(newurl
, u
->url
);
31 tmp
= strstr(newurl
, "://");
32 if (tmp
) tmp
= strchr(tmp
+ 3, '/');
34 tmp
= strrchr(newurl
, '/');
36 strcat(newurl
, redir
);
37 res
= url_new(newurl
);
47 url_new(const char* url
) {
48 int pos1
, pos2
,v6addr
= 0;
50 char *escfilename
=NULL
;
51 char *ptr1
=NULL
, *ptr2
=NULL
, *ptr3
=NULL
, *ptr4
=NULL
;
54 if( url
==NULL
) return NULL
;
56 if (strlen(url
) > (SIZE_MAX
/ 3 - 1)) {
57 mp_msg(MSGT_NETWORK
,MSGL_FATAL
,MSGTR_MemAllocFailed
);
60 escfilename
=malloc(strlen(url
)*3+1);
62 mp_msg(MSGT_NETWORK
,MSGL_FATAL
,MSGTR_MemAllocFailed
);
66 // Create the URL container
67 Curl
= malloc(sizeof(URL_t
));
69 mp_msg(MSGT_NETWORK
,MSGL_FATAL
,MSGTR_MemAllocFailed
);
73 // Initialisation of the URL container members
74 memset( Curl
, 0, sizeof(URL_t
) );
76 url_escape_string(escfilename
,url
);
78 // Copy the url in the URL container
79 Curl
->url
= strdup(escfilename
);
80 if( Curl
->url
==NULL
) {
81 mp_msg(MSGT_NETWORK
,MSGL_FATAL
,MSGTR_MemAllocFailed
);
84 mp_msg(MSGT_OPEN
,MSGL_V
,"Filename for url is now %s\n",escfilename
);
86 // extract the protocol
87 ptr1
= strstr(escfilename
, "://");
89 // Check for a special case: "sip:" (without "//"):
90 if (strstr(escfilename
, "sip:") == escfilename
) {
91 ptr1
= (char *)&url
[3]; // points to ':'
94 mp_msg(MSGT_NETWORK
,MSGL_V
,"Not an URL!\n");
98 pos1
= ptr1
-escfilename
;
99 Curl
->protocol
= malloc(pos1
+1);
100 if( Curl
->protocol
==NULL
) {
101 mp_msg(MSGT_NETWORK
,MSGL_FATAL
,MSGTR_MemAllocFailed
);
104 strncpy(Curl
->protocol
, escfilename
, pos1
);
105 Curl
->protocol
[pos1
] = '\0';
111 // check if a username:password is given
112 ptr2
= strstr(ptr1
, "@");
113 ptr3
= strstr(ptr1
, "/");
114 if( ptr3
!=NULL
&& ptr3
<ptr2
) {
115 // it isn't really a username but rather a part of the path
119 // We got something, at least a username...
121 Curl
->username
= malloc(len
+1);
122 if( Curl
->username
==NULL
) {
123 mp_msg(MSGT_NETWORK
,MSGL_FATAL
,MSGTR_MemAllocFailed
);
126 strncpy(Curl
->username
, ptr1
, len
);
127 Curl
->username
[len
] = '\0';
129 ptr3
= strstr(ptr1
, ":");
130 if( ptr3
!=NULL
&& ptr3
<ptr2
) {
131 // We also have a password
132 int len2
= ptr2
-ptr3
-1;
133 Curl
->username
[ptr3
-ptr1
]='\0';
134 Curl
->password
= malloc(len2
+1);
135 if( Curl
->password
==NULL
) {
136 mp_msg(MSGT_NETWORK
,MSGL_FATAL
,MSGTR_MemAllocFailed
);
139 strncpy( Curl
->password
, ptr3
+1, len2
);
140 Curl
->password
[len2
]='\0';
143 pos1
= ptr1
-escfilename
;
146 // before looking for a port number check if we have an IPv6 type numeric address
147 // in IPv6 URL the numeric address should be inside square braces.
148 ptr2
= strstr(ptr1
, "[");
149 ptr3
= strstr(ptr1
, "]");
150 ptr4
= strstr(ptr1
, "/");
151 if( ptr2
!=NULL
&& ptr3
!=NULL
&& ptr2
< ptr3
&& (!ptr4
|| ptr4
> ptr3
)) {
152 // we have an IPv6 numeric address
162 // look if the port is given
163 ptr2
= strstr(ptr2
, ":");
164 // If the : is after the first / it isn't the port
165 ptr3
= strstr(ptr1
, "/");
166 if(ptr3
&& ptr3
- ptr2
< 0) ptr2
= NULL
;
169 // Look if a path is given
172 // So we have an URL like http://www.hostname.com
173 pos2
= strlen(escfilename
);
175 // We have an URL like http://www.hostname.com/file.txt
176 pos2
= ptr3
-escfilename
;
179 // We have an URL beginning like http://www.hostname.com:1212
180 // Get the port number
181 Curl
->port
= atoi(ptr2
+1);
182 pos2
= ptr2
-escfilename
;
185 // copy the hostname in the URL container
186 Curl
->hostname
= malloc(pos2
-pos1
+1);
187 if( Curl
->hostname
==NULL
) {
188 mp_msg(MSGT_NETWORK
,MSGL_FATAL
,MSGTR_MemAllocFailed
);
191 strncpy(Curl
->hostname
, ptr1
, pos2
-pos1
);
192 Curl
->hostname
[pos2
-pos1
] = '\0';
194 // Look if a path is given
195 ptr2
= strstr(ptr1
, "/");
197 // A path/filename is given
198 // check if it's not a trailing '/'
199 if( strlen(ptr2
)>1 ) {
200 // copy the path/filename in the URL container
201 Curl
->file
= strdup(ptr2
);
202 if( Curl
->file
==NULL
) {
203 mp_msg(MSGT_NETWORK
,MSGL_FATAL
,MSGTR_MemAllocFailed
);
208 // Check if a filename was given or set, else set it with '/'
209 if( Curl
->file
==NULL
) {
210 Curl
->file
= malloc(2);
211 if( Curl
->file
==NULL
) {
212 mp_msg(MSGT_NETWORK
,MSGL_FATAL
,MSGTR_MemAllocFailed
);
215 strcpy(Curl
->file
, "/");
221 if (escfilename
) free(escfilename
);
222 if (Curl
) url_free(Curl
);
227 url_free(URL_t
* url
) {
229 if(url
->url
) free(url
->url
);
230 if(url
->protocol
) free(url
->protocol
);
231 if(url
->hostname
) free(url
->hostname
);
232 if(url
->file
) free(url
->file
);
233 if(url
->username
) free(url
->username
);
234 if(url
->password
) free(url
->password
);
239 /* Replace escape sequences in an URL (or a part of an URL) */
240 /* works like strcpy(), but without return argument */
242 url_unescape_string(char *outbuf
, const char *inbuf
)
244 unsigned char c
,c1
,c2
;
245 int i
,len
=strlen(inbuf
);
248 if (c
== '%' && i
<len
-2) { //must have 2 more chars
249 c1
= toupper(inbuf
[i
+1]); // we need uppercase characters
250 c2
= toupper(inbuf
[i
+2]);
251 if ( ((c1
>='0' && c1
<='9') || (c1
>='A' && c1
<='F')) &&
252 ((c2
>='0' && c2
<='9') || (c2
>='A' && c2
<='F')) ) {
253 if (c1
>='0' && c1
<='9') c1
-='0';
255 if (c2
>='0' && c2
<='9') c2
-='0';
258 i
=i
+2; //only skip next 2 chars if valid esc
263 *outbuf
++='\0'; //add nullterm to string
267 url_escape_string_part(char *outbuf
, const char *inbuf
) {
268 unsigned char c
,c1
,c2
;
269 int i
,len
=strlen(inbuf
);
271 for (i
=0;i
<len
;i
++) {
273 if ((c
=='%') && i
<len
-2 ) { //need 2 more characters
274 c1
=toupper(inbuf
[i
+1]); c2
=toupper(inbuf
[i
+2]); // need uppercase chars
276 c1
=129; c2
=129; //not escape chars
279 if( (c
>= 'A' && c
<= 'Z') ||
280 (c
>= 'a' && c
<= 'z') ||
281 (c
>= '0' && c
<= '9') ||
284 } else if ( c
=='%' && ((c1
>= '0' && c1
<= '9') || (c1
>= 'A' && c1
<= 'F')) &&
285 ((c2
>= '0' && c2
<= '9') || (c2
>= 'A' && c2
<= 'F'))) {
286 // check if part of an escape sequence
287 *outbuf
++=c
; // already
290 mp_msg(MSGT_NETWORK
,MSGL_ERR
,MSGTR_MPDEMUX_URL_StringAlreadyEscaped
,c
,c1
,c2
);
291 // error as this should not happen against RFC 2396
292 // to escape a string twice
294 /* all others will be escaped */
295 c1
= ((c
& 0xf0) >> 4);
297 if (c1
< 10) c1
+='0';
299 if (c2
< 10) c2
+='0';
309 /* Replace specific characters in the URL string by an escape sequence */
310 /* works like strcpy(), but without return argument */
312 url_escape_string(char *outbuf
, const char *inbuf
) {
314 int i
= 0,j
,len
= strlen(inbuf
);
315 char* tmp
,*unesc
= NULL
, *in
;
317 // Look if we have an ip6 address, if so skip it there is
318 // no need to escape anything in there.
319 tmp
= strstr(inbuf
,"://[");
321 tmp
= strchr(tmp
+4,']');
322 if(tmp
&& (tmp
[1] == '/' || tmp
[1] == ':' ||
325 strncpy(outbuf
,inbuf
,i
);
333 // look for the next char that must be kept
334 for (j
=i
;j
<len
;j
++) {
336 if(c
=='-' || c
=='_' || c
=='.' || c
=='!' || c
=='~' || /* mark characters */
337 c
=='*' || c
=='\'' || c
=='(' || c
==')' || /* do not touch escape character */
338 c
==';' || c
=='/' || c
=='?' || c
==':' || c
=='@' || /* reserved characters */
339 c
=='&' || c
=='=' || c
=='+' || c
=='$' || c
==',') /* see RFC 2396 */
342 // we are on a reserved char, write it out
348 // we found one, take that part of the string
350 if(!tmp
) tmp
= malloc(len
+1);
351 strncpy(tmp
,inbuf
+i
,j
-i
);
354 } else // take the rest of the string
357 if(!unesc
) unesc
= malloc(len
+1);
358 // unescape first to avoid escaping escape
359 url_unescape_string(unesc
,in
);
360 // then escape, including mark and other reserved chars
361 // that can come from escape sequences
362 url_escape_string_part(outbuf
,unesc
);
363 outbuf
+= strlen(outbuf
);
368 if(unesc
) free(unesc
);
373 url_debug(const URL_t
*url
) {
375 printf("URL pointer NULL\n");
378 if( url
->url
!=NULL
) {
379 printf("url=%s\n", url
->url
);
381 if( url
->protocol
!=NULL
) {
382 printf("protocol=%s\n", url
->protocol
);
384 if( url
->hostname
!=NULL
) {
385 printf("hostname=%s\n", url
->hostname
);
387 printf("port=%d\n", url
->port
);
388 if( url
->file
!=NULL
) {
389 printf("file=%s\n", url
->file
);
391 if( url
->username
!=NULL
) {
392 printf("username=%s\n", url
->username
);
394 if( url
->password
!=NULL
) {
395 printf("password=%s\n", url
->password
);
398 #endif /* URL_DEBUG */