2b54277a38d308d9139f668faf252f0fc72a0a89
[collectd.git] / src / libping / http.c
1 /**
2  * HTTP/HTTPS protocol support 
3  *
4  * Copyright (C) 2000, 2001, 2002 by
5  * Jeffrey Fulmer - <jdfulmer@armstrong.com>
6  * This file is distributed as part of Libping
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 <sock.h>
28 #include <http.h>
29 #include <util.h>
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <errno.h>
33 #include <string.h>
34 #include <setup.h>
35
36 #include "memory.h"
37
38 #define MAXFILE 10240
39
40 int
41 myhttp( HTTPDATA *H )
42 {
43   CONN    *C;    /* threadsafe connection */
44   URL     U;     /* defined in url.h      */
45   HEADERS *head; /* HTTP header structure */ 
46   int     bytes; /* bytes read from srv.  */
47   char    *tmp;  /* tmp storage for url   */
48   struct  timeval mytime; 
49
50   tmp = strdup( H->url ); 
51   U = add_url( tmp );
52  
53   C = (CONN*)xmalloc( sizeof( CONN ));
54   C->port    = U.port;
55   C->timeout = ( H->timeout == 0 )?60:H->timeout;
56
57   (void) gettimeofday( &mytime, (struct timezone *)NULL);
58  
59   if(( C->sock = JOEsocket( C, U.hostname )) <= 0 ){
60     return -1;
61   }
62
63   JOEhttp_send( C, U.hostname, U.pathname );
64   head  = JOEhttp_read_headers( C, U.hostname );
65   if( !head ){ 
66     JOEclose( C ); 
67     free( C ); 
68     return -1; 
69   }
70   
71   bytes =  JOEhttp_read( C, 0 );
72   if( bytes < 1 ){ 
73     JOEclose( C ); 
74     free( C ); 
75     free( head ); 
76     return -1; 
77   }
78   
79   JOEclose( C );
80
81   H->rtt = elapsed_time( &mytime ); 
82  
83   if( head->code > 499 ){ return -1; }
84   else                  { return  1; } 
85 }
86
87 /**
88  * returns int, ( < 0 == error )
89  * formats and sends an HTTP/1.0 request
90  */
91 void
92 JOEhttp_send( CONN *C, char *host, char *path )
93 {
94   int rlen;
95   char *protocol; 
96   char *keepalive;
97   char request[1024]; 
98   char fullpath[2048];
99
100   sprintf( fullpath, "%s", path );
101
102   memset( request, 0, sizeof( request ));
103
104   /* HTTP protocol string */
105   protocol  = "HTTP/1.0";
106   keepalive = "close";
107   
108   rlen=snprintf(
109     request, sizeof( request ),
110     "GET %s %s\015\012"
111     "Host: %s\015\012"
112     "Accept: */*\015\012"
113     "Accept-Encoding: * \015\012"
114     "User-Agent: JoeDog 1.00 [libping]\015\012"
115     "Connection: %s\015\012\015\012",
116     fullpath, protocol, host, keepalive
117   );
118   
119   if( rlen < 0 || rlen > sizeof(request)  ){ 
120     perror("http_send: request buffer overrun!"); 
121     exit( 1 ); 
122   }
123
124   if(( JOEsocket_check( C, WRITE )) < 0 ){
125     perror( "JOEsocket: not writeable" );
126     return;
127   } 
128
129   JOEsocket_write( C, request, rlen );
130
131   return;
132 }
133
134 /**
135  * returns int, ( < 0 == error )
136  * formats and sends an HTTP/1.0 request
137  */
138 void
139 JOEhttp_post( CONN *C, char *host, char *path, char *data, size_t len )
140 {
141   int  rlen;
142   char request[1024]; 
143   char *protocol; 
144   char *keepalive;
145   char fullpath[2048];
146   
147   sprintf( fullpath, "%s", path );
148
149   memset( request, 0, sizeof( request ));
150
151   /* HTTP protocol string */
152   protocol  = "HTTP/1.0";
153   keepalive = "close";
154     
155   rlen=snprintf(
156     request, sizeof( request ),
157     "POST %s %s\015\012"
158     "Host: %s\015\012"
159     "Accept: */*\015\012"
160     "Accept-Encoding: * \015\012"
161     "User-Agent: JoeDog 1.00 [libping]\015\012"
162     "Connection: %s\015\012"
163     "Content-type: application/x-www-form-urlencoded\015\012"
164     "Content-length: %d\015\012\015\012"
165     "%*.*s\015\012",
166     fullpath, protocol, host, keepalive, len, len, len, data
167   );
168
169   if( rlen < 0 || rlen > sizeof(request) ){ 
170     perror("http_post: request buffer overrun!"); 
171     exit( 1 ); 
172   }
173
174   if(( JOEsocket_check( C, WRITE )) < 0 ){
175     perror( "JOEsocket: not writeable" );
176     return;
177   } 
178
179   JOEsocket_write( C, request, rlen );
180
181   return;
182 }
183
184 /**
185  * returns HEADERS struct
186  * reads from http/https socket and parses
187  * header information into the struct.
188  */
189 HEADERS *
190 JOEhttp_read_headers( CONN *C, char *host )
191
192   int  x;           /* while loop index      */
193   int  n;           /* assign socket_read    */
194   char c;           /* assign char read      */
195   char line[512];   /* assign chars read     */
196   HEADERS *h;       /* struct to hold it all */
197   h = (HEADERS*)malloc( sizeof(HEADERS));
198   memset( h, 0, sizeof( HEADERS ));
199   
200   if(( JOEsocket_check( C, READ )) < 0 ){
201     perror( "JOEsocket: not readable" );
202     return NULL;
203   } 
204
205   h->redirection[0]=0;
206
207   while( TRUE ){
208     x = 0;
209     memset( &line, 0, sizeof( line ));
210     while(( n = JOEsocket_read( C, &c, 1 )) == 1 ){
211       line[x] = c; 
212       if(( line[0] == '\n' ) || ( line[1] == '\n' )){ 
213         return h;
214       }
215       if( line[x] == '\n' ) break;
216       x ++;
217     }
218     line[x]=0;
219     /* strip trailing CR */
220     if (x > 0 && line[x-1] == '\r') line[x-1]=0;
221     if( strncasecmp( line, "http", 4 ) == 0 ){
222       strncpy( h->head, line, 8 );
223       h->code = atoi( line + 9 ); 
224     }
225     if( strncasecmp( line, "content-length: ", 16 ) == 0 ){ 
226       h->length = atol( line + 16 ); 
227     }
228     if( strncasecmp( line, "connection: ", 12 ) == 0 ){
229       if ( strncasecmp( line+12, "keep-alive", 10 ) == 0 ){
230         h->keepalive = 1;
231       }
232       else if( strncasecmp( line+12, "close", 5 ) == 0 ){
233         h->keepalive = 0;
234       }
235     }
236
237     if( strncasecmp(line, "location: ", 10) == 0) {
238       if (strlen(line) - 10 > sizeof(h->redirection) - 1) {
239         perror( "redirection URL too long, ignored");
240       }
241       else {
242         strcpy(h->redirection, line+10);
243       }  
244     }
245
246     if( n <  0 ){ 
247       perror("JOEhttp_read_headers"); 
248       return( NULL ); 
249     } /* socket closed */
250   } /* end of while TRUE */
251
252   return h;
253 }
254
255 /**
256  * returns int
257  * reads a http/https socket
258  * ( you know what I mean :)
259  */
260 ssize_t
261 JOEhttp_read( CONN *C, int len )
262
263   int  n;
264   size_t bytes=0;
265   char body[MAXFILE];
266
267   if(( JOEsocket_check( C, READ )) < 0 ){
268     perror( "JOEsocket: not readable" );
269     return -1;
270   } 
271
272   memset( &body, 0, MAXFILE );  
273   while( TRUE ){
274     if(( n = JOEsocket_read( C, body, MAXFILE)) == 0 ){
275       break;
276     } 
277     /* IGV: should be accumulating bytes read, not just 
278        recording those in the last packet */
279     bytes += n;
280   }
281   return( bytes );
282 }
283
284 int
285 pinghttp( char *hostname )
286 {
287   HTTPDATA *H;
288  
289   H = (HTTPDATA*)xmalloc( sizeof( HTTPDATA ));
290   H->url     = (char*)strdup( hostname );
291   H->timeout = 0;
292  
293   return( myhttp( H )); 
294 }
295  
296 int
297 pingthttp( char *hostname, int t )
298 {
299   HTTPDATA *H;
300  
301   H = (HTTPDATA*)xmalloc( sizeof( HTTPDATA ));
302   H->url     = (char*)strdup( hostname );
303   H->timeout = t;
304  
305   return( myhttp( H )); 
306 }
307  
308 int
309 tpinghttp( char *hostname )
310 {
311   HTTPDATA *H;
312   int ret;
313  
314   H = (HTTPDATA*)xmalloc( sizeof( HTTPDATA ));
315   H->url     = (char*)strdup( hostname );
316   H->timeout = 0;
317  
318   ret = myhttp( H ); 
319
320   if( ret > 0 ){ return H->rtt; }
321   else         { return ret; }
322 }
323  
324 int
325 tpingthttp( char *hostname, int t )
326 {
327   HTTPDATA *H;
328   int ret;
329  
330   H = (HTTPDATA*)xmalloc( sizeof( HTTPDATA ));
331   H->url     = (char*)strdup( hostname );
332   H->timeout = t;
333  
334   ret = myhttp( H );
335
336   if( ret > 0 ){ return H->rtt; }
337   else         { return ret;    }
338
339
340