Copied missing files from the subversion repository.
[collectd.git] / src / libping / url.c
1 /**
2  * URL Processing
3  *
4  * Copyright (C) 2000, 2001, 2002 by
5  * Jeffrey Fulmer - <jdfulmer@armstrong.com>
6  * This file is distributed as part of Siege 
7  *
8  * This program 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.
12  *
13  * This program 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.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
21  *
22  */
23 #ifdef  HAVE_CONFIG_H
24 # include <config.h>
25 #endif/*HAVE_CONFIG_H*/
26  
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <ctype.h>
30 #ifdef STDC_HEADERS
31 # include <string.h>
32 #else
33 # ifndef HAVE_STRCHR
34 #  define strchr index
35 #  define strrchr rindex
36 # endif
37 char *strchr (), *strrchr ();
38 # ifndef HAVE_MEMCPY
39 #  define memcpy(d, s, n) bcopy ((s), (d), (n))
40 #  define memmove(d, s, n) bcopy ((s), (d), (n))
41 # endif
42 #endif
43 #include <errno.h>
44 #include <url.h>
45 #include <util.h>
46 #include <setup.h>
47
48 /*HARDCODED ALERT*/
49 #define PLENGTH 84  /* length of the *prot[] array */
50
51 /** 
52  * ALERT: using hardcoded array lengths below,
53  * if you change this array, then redefine PLENGTH
54  * 
55  * Currently http(prot[25]) and https(prot[26]) are 
56  * the only supported protocols.  But all w3c supported 
57  * protocols are listed for URL evaluation.
58  */  
59 static char *prot[] = {
60   "about:",      "addrbook:",  "acap:",      "afp:",
61   "afs:",        "callto:",    "chttp:",     "cid:",
62   "clsid:",      "data:",      "date:",      "DAV:",
63   "dns:",        "eid:",       "fax:",       "file:",
64   "finger:",     "freenet:",   "ftp:",       "gopher:",
65   "gsm:",        "h323:",      "h324:",      "hdl:",
66   "hnews:",      "http:",      "https:",     "iioploc:",
67   "ilu:",        "imap:",      "IOR:",       "irc:",
68   "isbn:",       "java:",      "JavaRMI:",   "javascript:",
69   "jdbc:",       "ldap:",      "lid:",       "lifn:",
70   "livescript:", "lrq:",       "mailto:",    "mailserver:",
71   "md5:",        "mid:",       "mocha:",     "modem:",
72   "news:",       "nfs:",       "nntp:",      "opaquelocktoken:"
73   "path:",       "phone:",     "pop:",       "pop3:",
74   "printer:",    "prospero:",  "res:",       "rtsp:",
75   "rvp:",        "rwhois:",    "rx:",        "sdp:",
76   "sip:",        "shttp:",     "snews:",     "STANF:",
77   "t120:",       "tel:",       "telephone:", "telnet:",
78   "tip:",        "tn3270:",    "tv:",        "uuid:",
79   "urn:",        "vemmi:",     "videotex:",  "view:",
80   "wais:",       "whois++:",   "whodp:",     "z39.50r:",
81   "z39.50s:"
82   
83 };
84
85 /**
86  * int value of the length of the protocol 
87  * string passed to the function.
88  */     
89 int
90 protocol_length( char *url )
91 {
92   int x;
93   /** 
94    * hardcoded protocol length!! see explanation above...
95    */
96   for( x = 0; x < PLENGTH; x ++ ){ 
97     if( strncasecmp( url, prot[x], strlen( prot[x] )) == 0 )
98       return strlen( prot[x] );
99   } 
100   return 0;     
101 }
102
103 /**
104  * If a person edits an html file on the
105  * Microsoft platform and copies it to a 
106  * UNIX server, we are left to deal with 
107  * ^M chars messing with our minds...
108  */
109 char *
110 trim( char *str )
111 {
112   char *s=str;
113  
114   if( str == NULL ) return NULL;
115  
116   /* advance the ptr */
117   while( *s ) s++;
118  
119   /* chomp the white space */
120   while( str < s && isspace( *( s-1 )))
121     *s-- = '\0';
122  
123   *s = '\0';
124  
125   return str; /* UNIX friendly */
126
127
128 /**
129  * boolean, returns true if the protocol is 
130  * supported by siege, false if it is not.
131  */ 
132 int
133 is_supported( char* url )
134 {
135   if( strncasecmp( url, prot[25], strlen( prot[25] )) == 0 )
136     return TRUE;
137   if( strncasecmp( url, prot[26], strlen( prot[26] )) == 0 )
138     #ifdef HAVE_SSL
139       return TRUE;
140     #else
141       return FALSE;
142     #endif /* HAVE_SSL */
143   else
144     return FALSE;
145 }
146
147 /**
148  * get_protocol
149  * returns protocol char*
150  */
151 PROTOCOL
152 get_protocol( const char *url )
153 {
154   if( strncasecmp( url, prot[25], strlen( prot[25] )) == 0 )
155     return HTTP;
156   if( strncasecmp( url, prot[26], strlen( prot[26] )) == 0 )
157     #ifdef HAVE_SSL
158       return HTTPS;
159     #else
160       return HTTP;
161     #endif /* HAVE_SSL */
162   else
163     return UNSPRTD;
164 }
165
166 /**
167  * get_default_port
168  */
169 int
170 get_default_port( PROTOCOL p )
171 {
172   if( p == HTTP )
173     return 80;
174   if( p == HTTPS )
175     #ifdef HAVE_SSL
176       return 443;
177     #else
178       return 80;
179     #endif /* HAVE_SSL */
180   else
181     return 80; 
182 }
183
184 char *
185 url_encode( char *str )
186 {
187   int size = 0;
188   char *ch, *bk;
189   char *p, *buf;
190   static char unsafe[]     = "<>{}#%|\"\\^~[]`@:\033";
191   static char char2hex[16] = "0123456789ABCDEF";
192
193   bk = ch  = str;
194   do{
195     if( strchr( unsafe, *ch ))
196       size += 2;
197     ch++; size ++;
198   } while( *ch );
199
200   buf = (char*)malloc( size +1 );
201   p   = buf;
202   ch  = bk;
203   do{
204     if( strchr( unsafe, *ch )){
205       const char c = *ch;
206       *p++ = '%';
207       *p++ = char2hex[(c >> 4) & 0xf];
208       *p++ = char2hex[c & 0xf];
209     }
210     else{
211       *p++ = *ch;
212     }
213     ch ++;
214   } while( *ch );
215
216   *p = '\0';
217   return( buf );
218 }
219
220 /**
221  * process_post_data
222  * populates URL->postdata with POST information
223  * returns int
224  */
225 char *
226 process_post_data( char *datap )
227 {
228   for( ; isspace(*datap); datap++ ){
229     /* Advance past white space */
230   }
231   if( *datap == '<' ){
232     /* Get Data from file */
233     return NULL;
234   }
235   else{
236     return datap;
237   }
238 }
239
240 URL
241 build_url( char *url )
242 {
243   URL U;                   /* defined in setup.h  */
244   int one, two, thr, fou;  /* placement counters. */ 
245   char *post_cmd=NULL;     /* POST directive for server */
246   char *tmp;
247
248   post_cmd = strstr( url, " POST" ); 
249   if( post_cmd != NULL ){
250     /* How do we deal with handling the multi-headed url_t arrays */
251     U.calltype = URL_POST;
252     *post_cmd = 0;
253     post_cmd += 5;
254     U.postdata = (char*)strdup( process_post_data( post_cmd ));
255     U.postlen  = strlen( U.postdata );
256   }
257   else{
258     U.calltype   = URL_GET;
259     U.postdata   = NULL;
260     U.posttemp   = NULL;
261     U.postlen    = 0;
262   }
263   if(( one = protocol_length( url )) > 0 && is_supported( url ) == TRUE ){
264     one += 2;
265   }
266   else if(( one = protocol_length( url )) > 0 && is_supported( url ) == FALSE ){
267     U.protocol = UNSPRTD;
268     one += 2;
269     perror( "unsupported protocol" );
270   }
271   else{
272     /* we are dealing with who knows what */
273     tmp = (char*)strstr( url, "://" );
274     if( tmp != NULL ){
275       one = (strlen(url) - (strlen(tmp) - 3 ));
276     }
277     else{
278       one = 0;  /* no specified protocol, assuming http: */
279     }
280   }
281
282   two = one;
283   while( url[two] && url[two] != ':' && url[two] != '/' ) two++; 
284
285   if( url[two] == ':' ){
286     fou = two;
287     while( url[two] && url[two] != '/' ){
288       two++;
289     }
290   }
291   else{ fou = two; }
292   if( url[two] == '/' ){ thr = two; }
293   else                 { thr = strlen( url ); } 
294
295   /* here we piece it all together */
296   if( one == 0 ){
297     U.protocol = HTTP;
298   }
299   else{
300     U.protocol = get_protocol( url );
301   }
302   U.hostname   = (char*)strdup(substring( url, one, ( fou - one )));
303   if( fou == two ){
304     U.port = get_default_port( U.protocol );
305   }
306   else{
307     U.port = atoi(substring( url, fou+1, (thr-(fou+1))));
308   }
309   if(( U.pathname = (char *)strdup(substring( url, thr, strlen( url )))) == NULL ){
310     U.pathname = (char *)strdup( "/" ); 
311   }
312   U.pathname = (strlen(U.pathname)==0)?strcpy(U.pathname, "/"):U.pathname; 
313   trim( U.pathname );
314
315   free( url ); 
316   return( U );
317 }
318
319 /**
320  * add_url
321  * parses char * then populates and 
322  * returns a URL with appropriate data.
323  */
324 URL
325 add_url( char *url )
326 {
327
328   return build_url( url );
329 }
330
331