Fix incorrect URL encoding.
[mplayer/greg.git] / libmpdemux / url.c
blobd185e5c9e1bbf389df237d884a11cb9a5c3cdfcf
1 /*
2 * URL Helper
3 * by Bertrand Baudet <bertrand_baudet@yahoo.com>
4 * (C) 2001, MPlayer team.
6 */
8 #include <string.h>
9 #include <stdlib.h>
10 #include <stdio.h>
12 #include "url.h"
13 #include "mp_msg.h"
15 URL_t*
16 url_new(const char* url) {
17 int pos1, pos2;
18 URL_t* Curl;
19 char *ptr1=NULL, *ptr2=NULL, *ptr3=NULL;
21 if( url==NULL ) return NULL;
23 // Create the URL container
24 Curl = (URL_t*)malloc(sizeof(URL_t));
25 if( Curl==NULL ) {
26 mp_msg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed!\n");
27 return NULL;
29 // Initialisation of the URL container members
30 memset( Curl, 0, sizeof(URL_t) );
32 // Copy the url in the URL container
33 Curl->url = strdup(url);
34 if( Curl->url==NULL ) {
35 mp_msg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed!\n");
36 url_free(Curl);
37 return NULL;
40 // extract the protocol
41 ptr1 = strstr(url, "://");
42 if( ptr1==NULL ) {
43 mp_msg(MSGT_NETWORK,MSGL_V,"Not an URL!\n");
44 url_free(Curl);
45 return NULL;
47 pos1 = ptr1-url;
48 Curl->protocol = (char*)malloc(pos1+1);
49 strncpy(Curl->protocol, url, pos1);
50 if( Curl->protocol==NULL ) {
51 mp_msg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed!\n");
52 url_free(Curl);
53 return NULL;
55 Curl->protocol[pos1] = '\0';
57 // jump the "://"
58 ptr1 += 3;
59 pos1 += 3;
61 // check if a username:password is given
62 ptr2 = strstr(ptr1, "@");
63 ptr3 = strstr(ptr1, "/");
64 if( ptr3!=NULL && ptr3<ptr2 ) {
65 // it isn't really a username but rather a part of the path
66 ptr2 = NULL;
68 if( ptr2!=NULL ) {
69 // We got something, at least a username...
70 int len = ptr2-ptr1;
71 Curl->username = (char*)malloc(len+1);
72 if( Curl->username==NULL ) {
73 mp_msg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed!\n");
74 url_free(Curl);
75 return NULL;
77 strncpy(Curl->username, ptr1, len);
78 Curl->username[len] = '\0';
80 ptr3 = strstr(ptr1, ":");
81 if( ptr3!=NULL && ptr3<ptr2 ) {
82 // We also have a password
83 int len2 = ptr2-ptr3-1;
84 Curl->username[ptr3-ptr1]='\0';
85 Curl->password = (char*)malloc(len2+1);
86 if( Curl->password==NULL ) {
87 mp_msg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed!\n");
88 url_free(Curl);
89 return NULL;
91 strncpy( Curl->password, ptr3+1, len2);
92 Curl->password[len2]='\0';
94 ptr1 = ptr2+1;
95 pos1 = ptr1-url;
98 // before looking for a port number check if we have an IPv6 type numeric address
99 // in IPv6 URL the numeric address should be inside square braces.
100 ptr2 = strstr(ptr1, "[");
101 ptr3 = strstr(ptr1, "]");
102 if( ptr2!=NULL && ptr3!=NULL ) {
103 // we have an IPv6 numeric address
104 ptr1++;
105 pos1++;
106 ptr2 = ptr3;
107 } else {
108 ptr2 = ptr1;
112 // look if the port is given
113 ptr2 = strstr(ptr2, ":");
114 // If the : is after the first / it isn't the port
115 ptr3 = strstr(ptr1, "/");
116 if(ptr3 && ptr3 - ptr2 < 0) ptr2 = NULL;
117 if( ptr2==NULL ) {
118 // No port is given
119 // Look if a path is given
120 if( ptr3==NULL ) {
121 // No path/filename
122 // So we have an URL like http://www.hostname.com
123 pos2 = strlen(url);
124 } else {
125 // We have an URL like http://www.hostname.com/file.txt
126 pos2 = ptr3-url;
128 } else {
129 // We have an URL beginning like http://www.hostname.com:1212
130 // Get the port number
131 Curl->port = atoi(ptr2+1);
132 pos2 = ptr2-url;
134 if( strstr(ptr1, "]")!=NULL ) pos2--;
135 // copy the hostname in the URL container
136 Curl->hostname = (char*)malloc(pos2-pos1+1);
137 if( Curl->hostname==NULL ) {
138 mp_msg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed!\n");
139 url_free(Curl);
140 return NULL;
142 strncpy(Curl->hostname, ptr1, pos2-pos1);
143 Curl->hostname[pos2-pos1] = '\0';
145 // Look if a path is given
146 ptr2 = strstr(ptr1, "/");
147 if( ptr2!=NULL ) {
148 // A path/filename is given
149 // check if it's not a trailing '/'
150 if( strlen(ptr2)>1 ) {
151 // copy the path/filename in the URL container
152 Curl->file = strdup(ptr2);
153 if( Curl->file==NULL ) {
154 mp_msg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed!\n");
155 url_free(Curl);
156 return NULL;
160 // Check if a filename was given or set, else set it with '/'
161 if( Curl->file==NULL ) {
162 Curl->file = (char*)malloc(2);
163 if( Curl->file==NULL ) {
164 mp_msg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed!\n");
165 url_free(Curl);
166 return NULL;
168 strcpy(Curl->file, "/");
171 return Curl;
174 void
175 url_free(URL_t* url) {
176 if(!url) return;
177 if(url->url) free(url->url);
178 if(url->protocol) free(url->protocol);
179 if(url->hostname) free(url->hostname);
180 if(url->file) free(url->file);
181 if(url->username) free(url->username);
182 if(url->password) free(url->password);
183 free(url);
187 /* Replace escape sequences in an URL (or a part of an URL) */
188 /* works like strcpy(), but without return argument */
189 /* unescape_url_string comes from ASFRecorder */
190 void
191 url_unescape_string(char *outbuf, const char *inbuf)
193 unsigned char c;
194 do {
195 c = *inbuf++;
196 if (c == '%') {
197 unsigned char c1 = *inbuf++;
198 unsigned char c2 = *inbuf++;
199 if ( ((c1>='0' && c1<='9') || (c1>='A' && c1<='F')) &&
200 ((c2>='0' && c2<='9') || (c2>='A' && c2<='F')) ) {
201 if (c1>='0' && c1<='9') c1-='0';
202 else c1-='A';
203 if (c2>='0' && c2<='9') c2-='0';
204 else c2-='A';
205 c = (c1<<4) + c2;
208 *outbuf++ = c;
209 } while (c != '\0');
212 /* Replace specific characters in the URL string by an escape sequence */
213 /* works like strcpy(), but without return argument */
214 /* escape_url_string comes from ASFRecorder */
215 void
216 url_escape_string(char *outbuf, const char *inbuf) {
217 unsigned char c;
218 do {
219 c = *inbuf++;
220 if( (c >= 'A' && c <= 'Z') ||
221 (c >= 'a' && c <= 'z') ||
222 (c >= '0' && c <= '9') ||
223 (c >= 0x7f) || /* fareast languages(Chinese, Korean, Japanese) */
224 c=='-' || c=='_' || c=='.' || c=='!' || c=='~' || /* mark characters */
225 c=='*' || c=='\'' || c=='(' || c==')' || c=='%' || /* do not touch escape character */
226 c==';' || c=='/' || c=='?' || c==':' || c=='@' || /* reserved characters */
227 c=='&' || c=='=' || c=='+' || c=='$' || c==',' || /* see RFC 2396 */
228 c=='\0' ) {
229 *outbuf++ = c;
230 } else {
231 /* all others will be escaped */
232 unsigned char c1 = ((c & 0xf0) >> 4);
233 unsigned char c2 = (c & 0x0f);
234 if (c1 < 10) c1+='0';
235 else c1+='A'-10;
236 if (c2 < 10) c2+='0';
237 else c2+='A'-10;
238 *outbuf++ = '%';
239 *outbuf++ = c1;
240 *outbuf++ = c2;
242 } while (c != '\0');
245 #ifdef __URL_DEBUG
246 void
247 url_debug(const URL_t *url) {
248 if( url==NULL ) {
249 printf("URL pointer NULL\n");
250 return;
252 if( url->url!=NULL ) {
253 printf("url=%s\n", url->url );
255 if( url->protocol!=NULL ) {
256 printf("protocol=%s\n", url->protocol );
258 if( url->hostname!=NULL ) {
259 printf("hostname=%s\n", url->hostname );
261 printf("port=%d\n", url->port );
262 if( url->file!=NULL ) {
263 printf("file=%s\n", url->file );
265 if( url->username!=NULL ) {
266 printf("username=%s\n", url->username );
268 if( url->password!=NULL ) {
269 printf("password=%s\n", url->password );
272 #endif //__URL_DEBUG