e03101c5905e542a7eafe7c2c9ffae6faa7ba92e
[obnox/wireshark/wip.git] / tap-httpstat.c
1 /* tap-httpstat.c
2  * tap-httpstat   2003 Jean-Michel FAYARD
3  *
4  * $Id: tap-httpstat.c,v 1.1 2003/09/02 22:47:58 guy Exp $
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@ethereal.com>
8  * Copyright 1998 Gerald Combs
9  * 
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  * 
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  * 
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23  */
24
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28
29 #include <stdio.h>
30
31 #include "epan/packet_info.h"
32 #include "epan/value_string.h"
33 #include "tap.h"
34 #include "register.h"
35 #include "packet-http.h"
36 #include <string.h>
37
38         
39 /* used to keep track of the statictics for an entire program interface */
40 typedef struct _http_stats_t {
41         char            *filter;
42         GHashTable      *hash_responses;
43         GHashTable      *hash_requests;
44 } httpstat_t;
45
46 /* used to keep track of the stats for a specific response code
47  * for example it can be { 3, 404, "Not Found" ,...}
48  * which means we captured 3 reply http/1.1 404 Not Found */
49 typedef struct _http_response_methode_t {
50         guint32          packets;               /* 3 */
51         guint            response_method;       /* 404 */
52         gchar           *name;                  /* Not Found */
53         httpstat_t      *sp;
54 } http_response_methode_t;
55 /* used to keep track of the stats for a specific request string */
56 typedef struct _http_request_methode_t {
57         gchar           *response;      /* eg. : GET */
58         guint32          packets;
59         httpstat_t      *sp;
60 } http_request_methode_t;
61
62
63 static const value_string vals_status_code[] = {
64         { 100, "Continue" },
65         { 101, "Switching Protocols" },
66         { 199, "Informational - Others" },
67
68         { 200, "OK"},
69         { 201, "Created"},
70         { 202, "Accepted"},
71         { 203, "Non-authoritative Information"},
72         { 204, "No Content"},
73         { 205, "Reset Content"},
74         { 206, "Partial Content"},
75         { 299, "Success - Others"},     /* used to keep track of others Success packets */
76
77         { 300, "Multiple Choices"},
78         { 301, "Moved Permanently"},
79         { 302, "Moved Temporarily"},
80         { 303, "See Other"},
81         { 304, "Not Modified"},
82         { 305, "Use Proxy"},
83         { 399, "Redirection - Others"},
84
85         { 400, "Bad Request"},
86         { 401, "Unauthorized"},
87         { 402, "Payment Required"},
88         { 403, "Forbidden"},
89         { 404, "Not Found"},
90         { 405, "Method Not Allowed"},
91         { 406, "Not Acceptable"},
92         { 407, "Proxy Authentication Required"},
93         { 408, "Request Time-out"},
94         { 409, "Conflict"},
95         { 410, "Gone"},
96         { 411, "Length Required"},
97         { 412, "Precondition Failed"},
98         { 413, "Request Entity Too Large"},
99         { 414, "Request-URI Too Large"},
100         { 415, "Unsupported Media Type"},
101         { 499, "Client Error - Others"},
102         
103         { 500, "Internal Server Error"},
104         { 501, "Not Implemented"},
105         { 502, "Bad Gateway"},
106         { 503, "Service Unavailable"},
107         { 504, "Gateway Time-out"},
108         { 505, "HTTP Version not supported"},
109         { 599, "Server Error - Others"},
110
111         { 0,    NULL}
112 } ;
113
114 /* insert some entries */
115 static void
116 http_init_hash( httpstat_t *sp)
117 {
118         int i;
119
120         sp->hash_responses = g_hash_table_new( g_int_hash, g_int_equal);                
121                         
122         for (i=0 ; vals_status_code[i].strptr ; i++ )
123         {
124                 gint *key = g_malloc (sizeof(gint));
125                 http_response_methode_t *sc = g_malloc (sizeof(http_response_methode_t));
126                 *key = vals_status_code[i].value;
127                 sc->packets=0;
128                 sc->response_method =  *key;
129                 sc->name=vals_status_code[i].strptr;
130                 sc->sp = sp;
131                 g_hash_table_insert( sc->sp->hash_responses, key, sc);
132         }
133         sp->hash_requests = g_hash_table_new( g_str_hash, g_str_equal);
134 }
135 static void
136 http_draw_hash_requests( gchar *key _U_ , http_request_methode_t *data, gchar * format)
137 {
138         if (data->packets==0)
139                 return;
140         printf( format, data->response, data->packets);                 
141 }
142
143 static void
144 http_draw_hash_responses( gint * key _U_ , http_response_methode_t *data, char * format)
145 {
146         if (data==NULL){
147                 g_warning("C'est quoi ce borderl key=%d\n", *key);
148                 exit(EXIT_FAILURE);
149         }
150         if (data->packets==0)
151                 return;
152         /* "     HTTP %3d %-35s %9d packets", */
153         printf(format,  data->response_method, data->name, data->packets );
154 }
155                 
156
157                 
158 /* NOT USED at this moment */
159 /*
160 static void
161 http_free_hash( gpointer key, gpointer value, gpointer user_data _U_ )
162 {
163         g_free(key);
164         g_free(value);
165 }
166 */
167 static void
168 http_reset_hash_responses(gchar *key _U_ , http_response_methode_t *data, gpointer ptr _U_ ) 
169 {       
170         data->packets = 0;
171 }
172 static void
173 http_reset_hash_requests(gchar *key _U_ , http_request_methode_t *data, gpointer ptr _U_ ) 
174 {       
175         data->packets = 0;
176 }
177
178 static void
179 httpstat_reset(void *psp  )
180 {
181         httpstat_t *sp=psp;
182         if (!sp) {
183                 g_hash_table_foreach( sp->hash_responses, (GHFunc)http_reset_hash_responses, NULL);
184                 g_hash_table_foreach( sp->hash_responses, (GHFunc)http_reset_hash_requests, NULL);
185         }
186 }
187
188 static int
189 httpstat_packet(void *psp , packet_info *pinfo _U_, epan_dissect_t *edt _U_, void *pri)
190 {
191         http_info_value_t *value=pri;
192         httpstat_t *sp=(httpstat_t *) psp;
193
194         /* We are only interested in reply packets with a status code */
195         /* Request or reply packets ? */
196         if (value->response_method!=0) {
197                 guint *key=g_malloc( sizeof(guint) );
198                 http_response_methode_t *sc;
199                 
200                 *key=value->response_method ;
201                 sc =  g_hash_table_lookup( 
202                                 sp->hash_responses, 
203                                 key);
204                 if (sc==NULL){
205                         /* non standard status code ; we classify it as others
206                          * in the relevant category (Informational,Success,Redirection,Client Error,Server Error)
207                          */
208                         int i = value->response_method;
209                         if ((i<100) || (i>=600)) {
210                                 return 0;
211                         }
212                         else if (i<200){
213                                 *key=199;       /* Hopefully, this status code will never be used */
214                         }
215                         else if (i<300){
216                                 *key=299;
217                         }
218                         else if (i<400){
219                                 *key=399;
220                         }
221                         else if (i<500){
222                                 *key=499;
223                         }
224                         else{
225                                 *key=599;
226                         }
227                         sc =  g_hash_table_lookup( 
228                                 sp->hash_responses, 
229                                 key);
230                         if (sc==NULL)
231                                 return 0;
232                 }
233                 sc->packets++;
234         } 
235         else if (value->request_method){
236                 http_request_methode_t *sc;
237
238                 sc =  g_hash_table_lookup( 
239                                 sp->hash_requests, 
240                                 value->request_method);
241                 if (sc==NULL){
242                         sc=g_malloc( sizeof(http_request_methode_t) );
243                         sc->response=g_strdup( value->request_method );
244                         sc->packets=1;
245                         sc->sp = sp;
246                         g_hash_table_insert( sp->hash_requests, sc->response, sc);
247                 } else {
248                         sc->packets++;
249                 }
250         } else {
251                 return 0;
252         }
253         return 1;
254 }
255
256
257
258 static void
259 httpstat_draw(void *psp  )
260 {
261         httpstat_t *sp=psp;
262         printf("\n");
263         printf("===================================================================\n");
264         if (! sp->filter[0])
265                 printf("HTTP Statistics\n");
266         else
267                 printf("HTTP Statistics with filter %s\n", sp->filter);
268
269         printf( "* HTTP Status Codes in reply packets\n");
270         g_hash_table_foreach( sp->hash_responses, (GHFunc)http_draw_hash_responses, 
271                 "    HTTP %3d %s\n");
272         printf("* List of HTTP Request methods\n");
273         g_hash_table_foreach( sp->hash_requests,  (GHFunc)http_draw_hash_requests, 
274                 "    %9s %d \n");
275         printf("===================================================================\n");
276 }
277
278
279
280 /* When called, this function will create a new instance of gtk_httpstat.
281  */
282 static void
283 gtk_httpstat_init(char *optarg)
284 {
285         httpstat_t *sp;
286         char *filter=NULL;
287         GString         *error_string;
288         
289         if (!strncmp (optarg, "http,stat,", 10)){
290                 filter=optarg+10;
291         } else {
292                 filter=NULL;
293         }
294         
295         sp = g_malloc( sizeof(httpstat_t) );
296         if(filter){
297                 sp->filter=g_malloc(strlen(filter)+1);
298                 strcpy(sp->filter,filter);
299         } else {
300                 sp->filter=NULL;
301         }
302         /*g_hash_table_foreach( http_status, (GHFunc)http_reset_hash_responses, NULL);*/
303
304
305         error_string = register_tap_listener( 
306                         "http",
307                         sp,
308                         filter,
309                         httpstat_reset,
310                         httpstat_packet,
311                         httpstat_draw);
312         if (error_string){
313                 /* error, we failed to attach to the tap. clean up */
314                 g_free(sp->filter);
315                 g_free(sp);
316                 fprintf (stderr, "tethereal: Coulnd't register http,stat tap: %s\n",
317                                 error_string->str);
318                 g_string_free(error_string, TRUE);
319                 exit(1);
320         }
321
322         http_init_hash(sp);
323 }
324
325 void
326 register_tap_listener_gtkhttpstat(void)
327 {
328         register_ethereal_tap("http,stat,", gtk_httpstat_init);
329 }