Put the "Find Frame" and "Go To Frame" menu items under "Edit"; leave
[obnox/wireshark/wip.git] / packet-http.c
1 /* packet-http.c
2  * Routines for HTTP packet disassembly
3  *
4  * Guy Harris <guy@netapp.com>
5  *
6  * $Id: packet-http.c,v 1.12 1999/12/06 20:27:19 guy Exp $
7  *
8  * Ethereal - Network traffic analyzer
9  * By Gerald Combs <gerald@zing.org>
10  * Copyright 1998 Gerald Combs
11  *
12  * 
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  * 
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  * 
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
26  *
27  *
28  */
29
30 #ifdef HAVE_CONFIG_H
31 #include "config.h"
32 #endif
33
34 #ifdef HAVE_SYS_TYPES_H
35 #include <sys/types.h>
36 #endif
37
38 #include <string.h>
39 #include <ctype.h>
40
41 #include <glib.h>
42 #include "packet.h"
43
44 static int proto_http = -1;
45 static int hf_http_response = -1;
46 static int hf_http_request = -1;
47
48 static gint ett_http = -1;
49
50 static proto_tree *http_tree;
51
52 static int is_http_request_or_reply(const u_char *data, int linelen);
53
54 void dissect_http(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
55 {
56         gboolean        is_ipp = (pi.srcport == 631 || pi.destport == 631);
57         proto_item      *ti;
58         const u_char    *data, *dataend;
59         const u_char    *linep, *lineend, *eol;
60         int             linelen;
61         u_char          c;
62
63         data = &pd[offset];
64         dataend = data + END_OF_FRAME;
65
66         if (check_col(fd, COL_PROTOCOL))
67                 col_add_str(fd, COL_PROTOCOL, is_ipp ? "IPP" : "HTTP");
68         if (check_col(fd, COL_INFO)) {
69                 /*
70                  * Put the first line from the buffer into the summary,
71                  * if it's an HTTP request or reply.
72                  * Otherwise, just call it a continuation.
73                  */
74                 lineend = find_line_end(data, dataend, &eol);
75                 linelen = lineend - data;
76                 if (is_http_request_or_reply(data, linelen))
77                         col_add_str(fd, COL_INFO, format_text(data, linelen));
78                 else
79                         col_add_str(fd, COL_INFO, "Continuation");
80         }
81
82         if (tree) {
83                 ti = proto_tree_add_item(tree, proto_http, offset, END_OF_FRAME, NULL);
84                 http_tree = proto_item_add_subtree(ti, ett_http);
85
86                 while (data < dataend) {
87                         /*
88                          * Find the end of the line.
89                          */
90                         lineend = find_line_end(data, dataend, &eol);
91                         linelen = lineend - data;
92
93                         /*
94                          * OK, does it look like an HTTP request or
95                          * response?
96                          */
97                         if (is_http_request_or_reply(data, linelen))
98                                 goto is_http;
99
100                         /*
101                          * No.  Does it look like a blank line (as would
102                          * appear at the end of an HTTP request)?
103                          */
104                         if (linelen == 1) {
105                                 if (*data == '\n')
106                                         goto is_http;
107                         }
108                         if (linelen == 2) {
109                                 if (strncmp(data, "\r\n", 2) == 0 ||
110                                     strncmp(data, "\n\r", 2) == 0)
111                                         goto is_http;
112                         }
113
114                         /*
115                          * No.  Does it look like a MIME header?
116                          */
117                         linep = data;
118                         while (linep < lineend) {
119                                 c = *linep++;
120                                 if (!isprint(c))
121                                         break;  /* not printable, not a MIME header */
122                                 switch (c) {
123
124                                 case '(':
125                                 case ')':
126                                 case '<':
127                                 case '>':
128                                 case '@':
129                                 case ',':
130                                 case ';':
131                                 case '\\':
132                                 case '"':
133                                 case '/':
134                                 case '[':
135                                 case ']':
136                                 case '?':
137                                 case '=':
138                                 case '{':
139                                 case '}':
140                                         /*
141                                          * It's a tspecial, so it's not
142                                          * part of a token, so it's not
143                                          * a field name for the beginning
144                                          * of a MIME header.
145                                          */
146                                         goto not_http;
147
148                                 case ':':
149                                         /*
150                                          * This ends the token; we consider
151                                          * this to be a MIME header.
152                                          */
153                                         goto is_http;
154                                 }
155                         }
156
157                 not_http:
158                         /*
159                          * We don't consider this part of an HTTP request or
160                          * reply, so we don't display it.
161                          * (Yeah, that means we don't display, say, a
162                          * text/http page, but you can get that from the
163                          * data pane.)
164                          */
165                         break;
166
167                 is_http:
168                         /*
169                          * Put this line.
170                          */
171                         proto_tree_add_text(http_tree, offset, linelen, "%s",
172                             format_text(data, linelen));
173                         offset += linelen;
174                         data = lineend;
175                 }
176
177                 if (data < dataend) {
178                         if (is_ipp)
179                                 dissect_ipp(pd, offset, fd, tree);
180                         else
181                                 dissect_data(&pd[offset], offset, fd, http_tree);
182                 }
183         }
184 }
185
186 /*
187  * XXX - this won't handle HTTP 0.9 replies, but they're all data
188  * anyway.
189  */
190 static int
191 is_http_request_or_reply(const u_char *data, int linelen)
192 {
193         if (linelen >= 3) {
194                 if (strncasecmp(data, "GET", 3) == 0 ||
195                     strncasecmp(data, "PUT", 3) == 0) {
196                         proto_tree_add_item_hidden(http_tree, 
197                                                    hf_http_request, 0, 0, 1);
198                         return TRUE;
199                 }
200         }
201         if (linelen >= 4) {
202                 if (strncasecmp(data, "HEAD", 4) == 0 ||
203                     strncasecmp(data, "POST", 4) == 0) {
204                         proto_tree_add_item_hidden(http_tree, 
205                                                    hf_http_request, 0, 0, 1);
206                         return TRUE;
207                 }
208         }
209         if (linelen >= 5) {
210                 if (strncasecmp(data, "TRACE", 5) == 0)
211                         return TRUE;
212                 if (strncasecmp(data, "HTTP/", 5) == 0) {
213                         proto_tree_add_item_hidden(http_tree, 
214                                                    hf_http_response, 0, 0, 1);
215                         return TRUE;    /* response */
216                 }
217         }
218         if (linelen >= 6) {
219                 if (strncasecmp(data, "DELETE", 6) == 0) {
220                         proto_tree_add_item_hidden(http_tree, 
221                                                    hf_http_request, 0, 0, 1);
222                         return TRUE;
223                 }
224         }
225         if (linelen >= 7) {
226                 if (strncasecmp(data, "OPTIONS", 7) == 0) {
227                         proto_tree_add_item_hidden(http_tree, 
228                                                    hf_http_request, 0, 0, 1);
229                         return TRUE;
230                 }
231         }
232         if (linelen >= 7) {
233                 if (strncasecmp(data, "CONNECT", 7) == 0) {
234                         proto_tree_add_item_hidden(http_tree, 
235                                                    hf_http_request, 0, 0, 1);
236                         return TRUE;
237                 }
238         }
239         return FALSE;
240 }
241
242 void
243 proto_register_http(void)
244 {
245
246   static hf_register_info hf[] = {
247     { &hf_http_response,
248       { "Response",             "http.response",  
249         FT_BOOLEAN, BASE_NONE, NULL, 0x0,
250         "TRUE if HTTP response" }},
251     { &hf_http_request,
252       { "Request",              "http.request",
253         FT_BOOLEAN, BASE_NONE, NULL, 0x0,
254         "TRUE if HTTP request (GET, PUT, HEAD, POST)" }},
255   };
256   static gint *ett[] = {
257     &ett_http,
258   };
259
260   proto_http = proto_register_protocol("Hypertext Transfer Protocol", "http");
261   proto_register_field_array(proto_http, hf, array_length(hf));
262   proto_register_subtree_array(ett, array_length(ett));
263 }