2 * Routines for HTTP packet disassembly
6 * Guy Harris <guy@alum.mit.edu>
8 * Copyright 2004, Jerry Talkington <jtalkington@users.sourceforge.net>
9 * Copyright 2002, Tim Potter <tpot@samba.org>
10 * Copyright 1999, Andrew Tridgell <tridge@samba.org>
14 * Wireshark - Network traffic analyzer
15 * By Gerald Combs <gerald@wireshark.org>
16 * Copyright 1998 Gerald Combs
18 * This program is free software; you can redistribute it and/or
19 * modify it under the terms of the GNU General Public License
20 * as published by the Free Software Foundation; either version 2
21 * of the License, or (at your option) any later version.
23 * This program is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
28 * You should have received a copy of the GNU General Public License
29 * along with this program; if not, write to the Free Software
30 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
41 #include <epan/conversation.h>
42 #include <epan/packet.h>
43 #include <epan/strutil.h>
44 #include <epan/base64.h>
45 #include <epan/emem.h>
46 #include <epan/stats_tree.h>
47 #include <epan/ws_strsplit.h>
49 #include <epan/req_resp_hdrs.h>
50 #include "packet-http.h"
51 #include "packet-tcp.h"
52 #include <epan/prefs.h>
53 #include <epan/expert.h>
55 typedef enum _http_type {
64 static int http_tap = -1;
66 static int proto_http = -1;
67 static int hf_http_notification = -1;
68 static int hf_http_response = -1;
69 static int hf_http_request = -1;
70 static int hf_http_basic = -1;
71 static int hf_http_request_method = -1;
72 static int hf_http_request_uri = -1;
73 static int hf_http_version = -1;
74 static int hf_http_response_code = -1;
75 static int hf_http_authorization = -1;
76 static int hf_http_proxy_authenticate = -1;
77 static int hf_http_proxy_authorization = -1;
78 static int hf_http_www_authenticate = -1;
79 static int hf_http_content_type = -1;
80 static int hf_http_content_length = -1;
81 static int hf_http_content_encoding = -1;
82 static int hf_http_transfer_encoding = -1;
83 static int hf_http_user_agent = -1;
84 static int hf_http_host = -1;
85 static int hf_http_connection = -1;
86 static int hf_http_cookie = -1;
87 static int hf_http_accept = -1;
88 static int hf_http_referer = -1;
89 static int hf_http_accept_language = -1;
90 static int hf_http_accept_encoding = -1;
91 static int hf_http_date = -1;
92 static int hf_http_cache_control = -1;
93 static int hf_http_server = -1;
94 static int hf_http_location = -1;
95 static int hf_http_set_cookie = -1;
96 static int hf_http_last_modified = -1;
97 static int hf_http_x_forwarded_for = -1;
99 static gint ett_http = -1;
100 static gint ett_http_ntlmssp = -1;
101 static gint ett_http_request = -1;
102 static gint ett_http_chunked_response = -1;
103 static gint ett_http_chunk_data = -1;
104 static gint ett_http_encoded_entity = -1;
106 static dissector_handle_t data_handle;
107 static dissector_handle_t media_handle;
108 static dissector_handle_t http_handle;
111 * desegmentation of HTTP headers
112 * (when we are over TCP or another protocol providing the desegmentation API)
114 static gboolean http_desegment_headers = TRUE;
117 * desegmentation of HTTP bodies
118 * (when we are over TCP or another protocol providing the desegmentation API)
119 * TODO let the user filter on content-type the bodies he wants desegmented
121 static gboolean http_desegment_body = TRUE;
124 * De-chunking of content-encoding: chunk entity bodies.
126 static gboolean http_dechunk_body = TRUE;
129 * Decompression of zlib encoded entities.
132 static gboolean http_decompress_body = TRUE;
134 static gboolean http_decompress_body = FALSE;
138 #define TCP_PORT_HTTP 80
139 #define TCP_PORT_PROXY_HTTP 3128
140 #define TCP_PORT_PROXY_ADMIN_HTTP 3132
141 #define TCP_ALT_PORT_HTTP 8080
142 #define TCP_RADAN_HTTP 8088
143 #define TCP_PORT_HKP 11371
144 #define TCP_PORT_DAAP 3689
147 * SSDP is implemented atop HTTP (yes, it really *does* run over UDP).
149 #define TCP_PORT_SSDP 1900
150 #define UDP_PORT_SSDP 1900
155 static guint http_alternate_tcp_port = 0;
156 static guint alternate_tcp_port = 0;
159 * Protocols implemented atop HTTP.
162 PROTO_HTTP, /* just HTTP */
163 PROTO_SSDP, /* Simple Service Discovery Protocol */
164 PROTO_DAAP /* Digital Audio Access Protocol */
167 typedef void (*ReqRespDissector)(tvbuff_t*, proto_tree*, int, const guchar*,
171 * Structure holding information from headers needed by main
172 * HTTP dissector code.
176 char *content_type_parameters;
177 gboolean have_content_length;
178 long content_length; /* XXX - make it 64-bit? */
179 char *content_encoding;
180 char *transfer_encoding;
183 static int is_http_request_or_reply(const gchar *data, int linelen,
184 http_type_t *type, ReqRespDissector *reqresp_dissector);
185 static int chunked_encoding_dissector(tvbuff_t **tvb_ptr, packet_info *pinfo,
186 proto_tree *tree, int offset);
187 static void http_payload_subdissector(tvbuff_t *next_tvb, proto_tree *tree, proto_tree *sub_tree, packet_info *pinfo);
188 static void process_header(tvbuff_t *tvb, int offset, int next_offset,
189 const guchar *line, int linelen, int colon_offset, packet_info *pinfo,
190 proto_tree *tree, headers_t *eh_ptr);
191 static gint find_header_hf_value(tvbuff_t *tvb, int offset, guint header_len);
192 static gboolean check_auth_ntlmssp(proto_item *hdr_item, tvbuff_t *tvb,
193 packet_info *pinfo, gchar *value);
194 static gboolean check_auth_basic(proto_item *hdr_item, tvbuff_t *tvb,
197 static dissector_table_t port_subdissector_table;
198 static dissector_table_t media_type_subdissector_table;
199 static heur_dissector_list_t heur_subdissector_list;
201 static dissector_handle_t ntlmssp_handle=NULL;
202 static dissector_handle_t gssapi_handle=NULL;
204 static const value_string vals_status_code[] = {
206 { 101, "Switching Protocols" },
207 { 102, "Processing" },
208 { 199, "Informational - Others" },
213 { 203, "Non-authoritative Information"},
214 { 204, "No Content"},
215 { 205, "Reset Content"},
216 { 206, "Partial Content"},
217 { 207, "Multi-Status"},
218 { 299, "Success - Others"},
220 { 300, "Multiple Choices"},
221 { 301, "Moved Permanently"},
224 { 304, "Not Modified"},
226 { 307, "Temporary Redirect"},
227 { 399, "Redirection - Others"},
229 { 400, "Bad Request"},
230 { 401, "Unauthorized"},
231 { 402, "Payment Required"},
234 { 405, "Method Not Allowed"},
235 { 406, "Not Acceptable"},
236 { 407, "Proxy Authentication Required"},
237 { 408, "Request Time-out"},
240 { 411, "Length Required"},
241 { 412, "Precondition Failed"},
242 { 413, "Request Entity Too Large"},
243 { 414, "Request-URI Too Long"},
244 { 415, "Unsupported Media Type"},
245 { 416, "Requested Range Not Satisfiable"},
246 { 417, "Expectation Failed"},
247 { 422, "Unprocessable Entity"},
249 { 424, "Failed Dependency"},
250 { 499, "Client Error - Others"},
252 { 500, "Internal Server Error"},
253 { 501, "Not Implemented"},
254 { 502, "Bad Gateway"},
255 { 503, "Service Unavailable"},
256 { 504, "Gateway Time-out"},
257 { 505, "HTTP Version not supported"},
258 { 507, "Insufficient Storage"},
259 { 599, "Server Error - Others"},
264 static const gchar* st_str_reqs = "HTTP Requests by Server";
265 static const gchar* st_str_reqs_by_srv_addr = "HTTP Requests by Server Address";
266 static const gchar* st_str_reqs_by_http_host = "HTTP Requests by HTTP Host";
267 static const gchar* st_str_resps_by_srv_addr = "HTTP Responses by Server Address";
269 static int st_node_reqs = -1;
270 static int st_node_reqs_by_srv_addr = -1;
271 static int st_node_reqs_by_http_host = -1;
272 static int st_node_resps_by_srv_addr = -1;
274 /* HTTP/Load Distribution stats init function */
275 static void http_reqs_stats_tree_init(stats_tree* st) {
276 st_node_reqs = stats_tree_create_node(st, st_str_reqs, 0, TRUE);
277 st_node_reqs_by_srv_addr = stats_tree_create_node(st, st_str_reqs_by_srv_addr, st_node_reqs, TRUE);
278 st_node_reqs_by_http_host = stats_tree_create_node(st, st_str_reqs_by_http_host, st_node_reqs, TRUE);
279 st_node_resps_by_srv_addr = stats_tree_create_node(st, st_str_resps_by_srv_addr, 0, TRUE);
282 /* HTTP/Load Distribution stats packet function */
283 static int http_reqs_stats_tree_packet(stats_tree* st, packet_info* pinfo, epan_dissect_t* edt _U_, const void* p) {
284 const http_info_value_t* v = p;
285 int reqs_by_this_host;
286 int reqs_by_this_addr;
287 int resps_by_this_addr;
288 int i = v->response_code;
289 static gchar ip_str[256];
292 if (v->request_method) {
293 g_snprintf(ip_str,sizeof(ip_str),"%s",address_to_str(&pinfo->dst));
295 tick_stat_node(st, st_str_reqs, 0, FALSE);
296 tick_stat_node(st, st_str_reqs_by_srv_addr, st_node_reqs, TRUE);
297 tick_stat_node(st, st_str_reqs_by_http_host, st_node_reqs, TRUE);
298 reqs_by_this_addr = tick_stat_node(st, ip_str, st_node_reqs_by_srv_addr, TRUE);
301 reqs_by_this_host = tick_stat_node(st, v->http_host, st_node_reqs_by_http_host, TRUE);
302 tick_stat_node(st, ip_str, reqs_by_this_host, FALSE);
304 tick_stat_node(st, v->http_host, reqs_by_this_addr, FALSE);
310 g_snprintf(ip_str,sizeof(ip_str),"%s",address_to_str(&pinfo->src));
312 tick_stat_node(st, st_str_resps_by_srv_addr, 0, FALSE);
313 resps_by_this_addr = tick_stat_node(st, ip_str, st_node_resps_by_srv_addr, TRUE);
315 if ( (i>100)&&(i<400) ) {
316 tick_stat_node(st, "OK", resps_by_this_addr, FALSE);
318 tick_stat_node(st, "KO", resps_by_this_addr, FALSE);
328 static int st_node_requests_by_host = -1;
329 static const guint8* st_str_requests_by_host = "HTTP Requests by HTTP Host";
331 /* HTTP/Requests stats init function */
332 static void http_req_stats_tree_init(stats_tree* st) {
333 st_node_requests_by_host = stats_tree_create_node(st, st_str_requests_by_host, 0, TRUE);
336 /* HTTP/Requests stats packet function */
337 static int http_req_stats_tree_packet(stats_tree* st, packet_info* pinfo _U_, epan_dissect_t* edt _U_, const void* p) {
338 const http_info_value_t* v = p;
339 int reqs_by_this_host;
341 if (v->request_method) {
342 tick_stat_node(st, st_str_requests_by_host, 0, FALSE);
345 reqs_by_this_host = tick_stat_node(st, v->http_host, st_node_requests_by_host, TRUE);
347 if (v->request_uri) {
348 tick_stat_node(st, v->request_uri, reqs_by_this_host, TRUE);
358 static const guint8* st_str_packets = "Total HTTP Packets";
359 static const guint8* st_str_requests = "HTTP Request Packets";
360 static const guint8* st_str_responses = "HTTP Response Packets";
361 static const guint8* st_str_resp_broken = "???: broken";
362 static const guint8* st_str_resp_100 = "1xx: Informational";
363 static const guint8* st_str_resp_200 = "2xx: Success";
364 static const guint8* st_str_resp_300 = "3xx: Redirection";
365 static const guint8* st_str_resp_400 = "4xx: Client Error";
366 static const guint8* st_str_resp_500 = "5xx: Server Error";
367 static const guint8* st_str_other = "Other HTTP Packets";
369 static int st_node_packets = -1;
370 static int st_node_requests = -1;
371 static int st_node_responses = -1;
372 static int st_node_resp_broken = -1;
373 static int st_node_resp_100 = -1;
374 static int st_node_resp_200 = -1;
375 static int st_node_resp_300 = -1;
376 static int st_node_resp_400 = -1;
377 static int st_node_resp_500 = -1;
378 static int st_node_other = -1;
381 /* HTTP/Packet Counter stats init function */
382 static void http_stats_tree_init(stats_tree* st) {
383 st_node_packets = stats_tree_create_node(st, st_str_packets, 0, TRUE);
384 st_node_requests = stats_tree_create_pivot(st, st_str_requests, st_node_packets);
385 st_node_responses = stats_tree_create_node(st, st_str_responses, st_node_packets, TRUE);
386 st_node_resp_broken = stats_tree_create_node(st, st_str_resp_broken, st_node_responses, TRUE);
387 st_node_resp_100 = stats_tree_create_node(st, st_str_resp_100, st_node_responses, TRUE);
388 st_node_resp_200 = stats_tree_create_node(st, st_str_resp_200, st_node_responses, TRUE);
389 st_node_resp_300 = stats_tree_create_node(st, st_str_resp_300, st_node_responses, TRUE);
390 st_node_resp_400 = stats_tree_create_node(st, st_str_resp_400, st_node_responses, TRUE);
391 st_node_resp_500 = stats_tree_create_node(st, st_str_resp_500, st_node_responses, TRUE);
392 st_node_other = stats_tree_create_node(st, st_str_other, st_node_packets,FALSE);
395 /* HTTP/Packet Counter stats packet function */
396 static int http_stats_tree_packet(stats_tree* st, packet_info* pinfo _U_, epan_dissect_t* edt _U_, const void* p) {
397 const http_info_value_t* v = p;
398 guint i = v->response_code;
400 const guint8* resp_str;
401 static gchar str[64];
403 tick_stat_node(st, st_str_packets, 0, FALSE);
406 tick_stat_node(st, st_str_responses, st_node_packets, FALSE);
408 if ( (i<100)||(i>=600) ) {
409 resp_grp = st_node_resp_broken;
410 resp_str = st_str_resp_broken;
412 resp_grp = st_node_resp_100;
413 resp_str = st_str_resp_100;
415 resp_grp = st_node_resp_200;
416 resp_str = st_str_resp_200;
418 resp_grp = st_node_resp_300;
419 resp_str = st_str_resp_300;
421 resp_grp = st_node_resp_400;
422 resp_str = st_str_resp_400;
424 resp_grp = st_node_resp_500;
425 resp_str = st_str_resp_500;
428 tick_stat_node(st, resp_str, st_node_responses, FALSE);
430 g_snprintf(str, sizeof(str),"%u %s",i,match_strval(i,vals_status_code));
431 tick_stat_node(st, str, resp_grp, FALSE);
432 } else if (v->request_method) {
433 stats_tree_tick_pivot(st,st_node_requests,v->request_method);
435 tick_stat_node(st, st_str_other, st_node_packets, FALSE);
441 /* Return a tvb that contains the binary representation of a base64
445 base64_to_tvb(const char *base64)
448 char *data = g_strdup(base64);
451 len = epan_base64_decode(data);
452 tvb = tvb_new_real_data((const guint8 *)data, len, len);
454 tvb_set_free_cb(tvb, g_free);
460 dissect_http_ntlmssp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
463 tvbuff_t *ntlmssp_tvb;
465 ntlmssp_tvb = base64_to_tvb(line);
466 tvb_set_child_real_data_tvbuff(tvb, ntlmssp_tvb);
467 add_new_data_source(pinfo, ntlmssp_tvb, "NTLMSSP / GSSAPI Data");
468 if (tvb_strneql(ntlmssp_tvb, 0, "NTLMSSP", 7) == 0)
469 call_dissector(ntlmssp_handle, ntlmssp_tvb, pinfo, tree);
471 call_dissector(gssapi_handle, ntlmssp_tvb, pinfo, tree);
475 * TODO: remove this ugly global variable.
476 * XXX: do we really want to have to pass this from one function to another?
478 static http_info_value_t *stat_info;
481 dissect_http_message(tvbuff_t *tvb, int offset, packet_info *pinfo,
485 const char *proto_tag;
486 proto_tree *http_tree = NULL;
487 proto_item *ti = NULL;
490 const guchar *linep, *lineend;
492 int first_linelen, linelen;
493 gboolean is_request_or_reply;
494 gboolean saw_req_resp_or_header;
496 http_type_t http_type;
497 proto_item *hdr_item = NULL;
498 ReqRespDissector reqresp_dissector;
499 proto_tree *req_tree;
503 int reported_datalen = -1;
504 dissector_handle_t handle;
507 /*http_info_value_t *si;*/
508 conversation_t *conversation;
511 * Is this a request or response?
513 * Note that "tvb_find_line_end()" will return a value that
514 * is not longer than what's in the buffer, so the
515 * "tvb_get_ptr()" call won't throw an exception.
517 first_linelen = tvb_find_line_end(tvb, offset,
518 tvb_ensure_length_remaining(tvb, offset), &next_offset,
521 * Is the first line a request or response?
523 line = tvb_get_ptr(tvb, offset, first_linelen);
524 http_type = HTTP_OTHERS; /* type not known yet */
525 is_request_or_reply = is_http_request_or_reply((const gchar *)line,
526 first_linelen, &http_type, NULL);
527 if (is_request_or_reply) {
529 * Yes, it's a request or response.
530 * Do header desegmentation if we've been told to,
531 * and do body desegmentation if we've been told to and
532 * we find a Content-Length header.
534 if (!req_resp_hdrs_do_reassembly(tvb, offset, pinfo,
535 http_desegment_headers, http_desegment_body)) {
537 * More data needed for desegmentation.
543 conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
545 if(!conversation) { /* Conversation does not exist yet - create it */
546 conversation = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
549 /* Retrieve information from conversation
550 * or add it if it isn't there yet
552 stat_info = conversation_get_proto_data(conversation, proto_http);
554 stat_info = se_alloc(sizeof(http_info_value_t));
555 stat_info->response_code = 0;
556 stat_info->request_method = NULL;
557 stat_info->request_uri = NULL;
558 stat_info->http_host = NULL;
560 conversation_add_proto_data(conversation, proto_http, stat_info);
563 switch (pinfo->match_port) {
565 case TCP_PORT_SSDP: /* TCP_PORT_SSDP = UDP_PORT_SSDP */
581 if (check_col(pinfo->cinfo, COL_PROTOCOL))
582 col_set_str(pinfo->cinfo, COL_PROTOCOL, proto_tag);
583 if (check_col(pinfo->cinfo, COL_INFO)) {
585 * Put the first line from the buffer into the summary
586 * if it's an HTTP request or reply (but leave out the
588 * Otherwise, just call it a continuation.
590 * Note that "tvb_find_line_end()" will return a value that
591 * is not longer than what's in the buffer, so the
592 * "tvb_get_ptr()" call won't throw an exception.
594 line = tvb_get_ptr(tvb, offset, first_linelen);
595 if (is_request_or_reply)
596 col_add_str(pinfo->cinfo, COL_INFO,
597 format_text(line, first_linelen));
599 col_set_str(pinfo->cinfo, COL_INFO, "Continuation or non-HTTP traffic");
602 orig_offset = offset;
604 ti = proto_tree_add_item(tree, proto_http, tvb, offset, -1,
606 http_tree = proto_item_add_subtree(ti, ett_http);
610 * Process the packet data, a line at a time.
612 http_type = HTTP_OTHERS; /* type not known yet */
613 headers.content_type = NULL; /* content type not known yet */
614 stat_info->content_type = NULL; /* Reset for each packet */
615 headers.content_type_parameters = NULL; /* content type parameters too */
616 headers.have_content_length = FALSE; /* content length not known yet */
617 headers.content_encoding = NULL; /* content encoding not known yet */
618 headers.transfer_encoding = NULL; /* transfer encoding not known yet */
619 saw_req_resp_or_header = FALSE; /* haven't seen anything yet */
620 while (tvb_reported_length_remaining(tvb, offset) != 0) {
622 * Find the end of the line.
623 * XXX - what if we don't find it because the packet
624 * is cut short by a snapshot length or the header is
625 * split across TCP segments? How much dissection should
628 linelen = tvb_find_line_end(tvb, offset,
629 tvb_ensure_length_remaining(tvb, offset), &next_offset,
635 * Get a buffer that refers to the line.
637 line = tvb_get_ptr(tvb, offset, linelen);
638 lineend = line + linelen;
642 * OK, does it look like an HTTP request or response?
644 reqresp_dissector = NULL;
645 is_request_or_reply =
646 is_http_request_or_reply((const gchar *)line,
647 linelen, &http_type, &reqresp_dissector);
648 if (is_request_or_reply)
652 * No. Does it look like a blank line (as would appear
653 * at the end of an HTTP request)?
656 goto is_http; /* Yes. */
659 * No. Does it look like a header?
662 colon_offset = offset;
663 while (linep < lineend) {
667 * This must be a CHAR to be part of a token; that
668 * means it must be ASCII.
671 break; /* not ASCII, thus not a CHAR */
674 * This mustn't be a CTL to be part of a token.
676 * XXX - what about leading LWS on continuation
680 break; /* CTL, not part of a header */
683 * This mustn't be a SEP to be part of a token;
684 * a ':' ends the token, everything else is an
685 * indication that this isn't a header.
707 * It's a separator, so it's not part of a
708 * token, so it's not a field name for the
709 * beginning of a header.
711 * (We don't have to check for HT; that's
712 * already been ruled out by "iscntrl()".)
718 * This ends the token; we consider this
730 * We haven't seen the colon, but everything else looks
731 * OK for a header line.
733 * If we've already seen an HTTP request or response
734 * line, or a header line, and we're at the end of
735 * the tvbuff, we assume this is an incomplete header
736 * line. (We quit this loop after seeing a blank line,
737 * so if we've seen a request or response line, or a
738 * header line, this is probably more of the request
739 * or response we're presumably seeing. There is some
740 * risk of false positives, but the same applies for
741 * full request or response lines or header lines,
742 * although that's less likely.)
744 * We throw an exception in that case, by checking for
745 * the existence of the next byte after the last one
746 * in the line. If it exists, "tvb_ensure_bytes_exist()"
747 * throws no exception, and we fall through to the
748 * "not HTTP" case. If it doesn't exist,
749 * "tvb_ensure_bytes_exist()" will throw the appropriate
752 if (saw_req_resp_or_header)
753 tvb_ensure_bytes_exist(tvb, offset, linelen + 1);
757 * We don't consider this part of an HTTP request or
758 * reply, so we don't display it.
759 * (Yeah, that means we don't display, say, a text/http
760 * page, but you can get that from the data pane.)
770 * This is a blank line, which means that
771 * whatever follows it isn't part of this
774 proto_tree_add_text(http_tree, tvb, offset,
775 next_offset - offset, "%s",
776 tvb_format_text(tvb, offset, next_offset - offset));
777 offset = next_offset;
782 * Not a blank line - either a request, a reply, or a header
785 saw_req_resp_or_header = TRUE;
786 if (is_request_or_reply) {
788 hdr_item = proto_tree_add_text(http_tree, tvb,
789 offset, next_offset - offset, "%s",
790 tvb_format_text(tvb, offset,
791 next_offset - offset));
793 expert_add_info_format(pinfo, hdr_item, PI_SEQUENCE, PI_CHAT,
795 tvb_format_text(tvb, offset, next_offset - offset));
796 if (reqresp_dissector) {
797 if (tree) req_tree = proto_item_add_subtree(hdr_item, ett_http_request);
798 else req_tree = NULL;
800 reqresp_dissector(tvb, req_tree, offset, line, lineend);
806 process_header(tvb, offset, next_offset, line, linelen,
807 colon_offset, pinfo, http_tree, &headers);
809 offset = next_offset;
815 case HTTP_NOTIFICATION:
816 proto_tree_add_boolean_hidden(http_tree,
817 hf_http_notification, tvb, 0, 0, 1);
821 proto_tree_add_boolean_hidden(http_tree,
822 hf_http_response, tvb, 0, 0, 1);
826 proto_tree_add_boolean_hidden(http_tree,
827 hf_http_request, tvb, 0, 0, 1);
837 * If a content length was supplied, the amount of data to be
838 * processed as HTTP payload is the minimum of the content
839 * length and the amount of data remaining in the frame.
841 * If no content length was supplied (or if a bad content length
842 * was supplied), the amount of data to be processed is the amount
843 * of data remaining in the frame.
845 * If there was no Content-Length entity header, we should
846 * accumulate all data until the end of the connection.
847 * That'd require that the TCP dissector call subdissectors
848 * for all frames with FIN, even if they contain no data,
849 * which would require subdissectors to deal intelligently
850 * with empty segments.
852 * Acccording to RFC 2616, however, 1xx responses, 204 responses,
853 * and 304 responses MUST NOT include a message body; if no
854 * content length is specified for them, we don't attempt to
857 * XXX - it says the same about responses to HEAD requests;
858 * unless there's a way to determine from the response
859 * whether it's a response to a HEAD request, we have to
860 * keep information about the request and associate that with
861 * the response in order to handle that.
863 datalen = tvb_length_remaining(tvb, offset);
864 if (headers.have_content_length && headers.content_length != -1) {
865 if (datalen > headers.content_length)
866 datalen = headers.content_length;
869 * XXX - limit the reported length in the tvbuff we'll
870 * hand to a subdissector to be no greater than the
873 * We really need both unreassembled and "how long it'd
874 * be if it were reassembled" lengths for tvbuffs, so
875 * that we throw the appropriate exceptions for
876 * "not enough data captured" (running past the length),
877 * "packet needed reassembly" (within the length but
878 * running past the unreassembled length), and
879 * "packet is malformed" (running past the reassembled
882 reported_datalen = tvb_reported_length_remaining(tvb, offset);
883 if (reported_datalen > headers.content_length)
884 reported_datalen = headers.content_length;
890 * Requests have no content if there's no
891 * Content-Length header and no Transfer-Encoding
894 if (headers.transfer_encoding == NULL)
897 reported_datalen = -1;
901 if ((stat_info->response_code/100) == 1 ||
902 stat_info->response_code == 204 ||
903 stat_info->response_code == 304)
904 datalen = 0; /* no content! */
907 * XXX - responses to HEAD requests,
908 * and possibly other responses,
909 * "MUST NOT" include a
912 reported_datalen = -1;
918 * XXX - what about HTTP_NOTIFICATION?
920 reported_datalen = -1;
927 * There's stuff left over; process it.
930 void *save_private_data = NULL;
931 gint chunks_decoded = 0;
934 * Create a tvbuff for the payload.
936 * The amount of data to be processed that's
937 * available in the tvbuff is "datalen", which
938 * is the minimum of the amount of data left in
939 * the tvbuff and any specified content length.
941 * The amount of data to be processed that's in
942 * this frame, regardless of whether it was
943 * captured or not, is "reported_datalen",
944 * which, if no content length was specified,
945 * is -1, i.e. "to the end of the frame.
947 next_tvb = tvb_new_subset(tvb, offset, datalen,
950 * BEWARE - next_tvb is a subset of another tvb,
951 * so we MUST NOT attempt tvb_free(next_tvb);
955 * Handle *transfer* encodings other than "identity".
957 if (headers.transfer_encoding != NULL &&
958 strcasecmp(headers.transfer_encoding, "identity") != 0) {
959 if (http_dechunk_body &&
960 (strncasecmp(headers.transfer_encoding, "chunked", 7)
963 chunks_decoded = chunked_encoding_dissector(
964 &next_tvb, pinfo, http_tree, 0);
966 if (chunks_decoded <= 0) {
968 * The chunks weren't reassembled,
969 * or there was a single zero
975 * Add a new data source for the
978 tvb_set_child_real_data_tvbuff(tvb,
980 add_new_data_source(pinfo, next_tvb,
981 "De-chunked entity body");
985 * We currently can't handle, for example,
986 * "gzip", "compress", or "deflate" as
987 * *transfer* encodings; just handle them
990 call_dissector(data_handle, next_tvb, pinfo,
996 * At this point, any chunked *transfer* coding has been removed
997 * (the entity body has been dechunked) so it can be presented
998 * for the following operation (*content* encoding), or it has
999 * been been handed off to the data dissector.
1001 * Handle *content* encodings other than "identity" (which
1002 * shouldn't appear in a Content-Encoding header, but
1003 * we handle it in any case).
1005 if (headers.content_encoding != NULL &&
1006 strcasecmp(headers.content_encoding, "identity") != 0) {
1008 * We currently can't handle, for example, "compress";
1009 * just handle them as data for now.
1011 * After July 7, 2004 the LZW patent expires, so support
1012 * might be added then. However, I don't think that
1013 * anybody ever really implemented "compress", due to
1014 * the aforementioned patent.
1016 tvbuff_t *uncomp_tvb = NULL;
1017 proto_item *e_ti = NULL;
1018 proto_tree *e_tree = NULL;
1020 if (http_decompress_body &&
1021 (strcasecmp(headers.content_encoding, "gzip") == 0 ||
1022 strcasecmp(headers.content_encoding, "deflate")
1025 uncomp_tvb = tvb_uncompress(next_tvb, 0,
1026 tvb_length(next_tvb));
1030 * Add the encoded entity to the protocol tree
1032 e_ti = proto_tree_add_text(http_tree, next_tvb,
1033 0, tvb_length(next_tvb),
1034 "Content-encoded entity body (%s): %u bytes",
1035 headers.content_encoding,
1036 tvb_length(next_tvb));
1037 e_tree = proto_item_add_subtree(e_ti,
1038 ett_http_encoded_entity);
1040 if (uncomp_tvb != NULL) {
1042 * Decompression worked
1045 /* XXX - Don't free this, since it's possible
1046 * that the data was only partially
1047 * decompressed, such as when desegmentation
1052 proto_item_append_text(e_ti, " -> %u bytes", tvb_length(uncomp_tvb));
1053 next_tvb = uncomp_tvb;
1054 tvb_set_child_real_data_tvbuff(tvb, next_tvb);
1055 add_new_data_source(pinfo, next_tvb,
1056 "Uncompressed entity body");
1058 if (chunks_decoded > 1) {
1059 tvb_set_child_real_data_tvbuff(tvb,
1061 add_new_data_source(pinfo, next_tvb,
1062 "Compressed entity body");
1064 call_dissector(data_handle, next_tvb, pinfo,
1067 goto body_dissected;
1071 * Note that a new data source is added for the entity body
1072 * only if it was content-encoded and/or transfer-encoded.
1076 * Do subdissector checks.
1078 * First, check whether some subdissector asked that they
1079 * be called if something was on some particular port.
1082 /* Save values for Content List -> HTTP GUI feature */
1083 stat_info->content_type = se_strdup(headers.content_type);
1084 stat_info->payload_len = next_tvb->length;
1085 stat_info->payload_data = se_memdup(next_tvb->real_data,
1088 handle = dissector_get_port_handle(port_subdissector_table,
1090 if (handle == NULL && headers.content_type != NULL) {
1092 * We didn't find any subdissector that
1093 * registered for the port, and we have a
1094 * Content-Type value. Is there any subdissector
1095 * for that content type?
1097 save_private_data = pinfo->private_data;
1099 if (headers.content_type_parameters)
1100 pinfo->private_data = ep_strdup(headers.content_type_parameters);
1102 pinfo->private_data = NULL;
1104 * Calling the string handle for the media type
1105 * dissector table will set pinfo->match_string
1106 * to headers.content_type for us.
1108 pinfo->match_string = headers.content_type;
1109 handle = dissector_get_string_handle(
1110 media_type_subdissector_table,
1111 headers.content_type);
1113 if (handle != NULL) {
1115 * We have a subdissector - call it.
1117 dissected = call_dissector(handle, next_tvb, pinfo,
1121 * We don't have a subdissector - try the heuristic
1124 dissected = dissector_try_heuristic(
1125 heur_subdissector_list, next_tvb, pinfo, tree);
1129 * The subdissector dissected the body.
1130 * Fix up the top-level item so that it doesn't
1131 * include the stuff for that protocol.
1134 proto_item_set_len(ti, offset);
1136 if (headers.content_type != NULL) {
1138 * Calling the default media handle if there is a content-type that
1139 * wasn't handled above.
1141 call_dissector(media_handle, next_tvb, pinfo, tree);
1143 /* Call the subdissector (defaults to data), otherwise. */
1144 http_payload_subdissector(next_tvb, tree, http_tree, pinfo);
1150 * Do *not* attempt at freeing the private data;
1151 * it may be in use by subdissectors.
1153 if (save_private_data)
1154 pinfo->private_data = save_private_data;
1156 * We've processed "datalen" bytes worth of data
1157 * (which may be no data at all); advance the
1158 * offset past whatever data we've processed.
1163 tap_queue_packet(http_tap, pinfo, stat_info);
1165 return offset - orig_offset;
1168 /* This can be used to dissect an HTTP request until such time
1169 * that a more complete dissector is written for that HTTP request.
1170 * This simple dissector only puts the request method, URI, and
1171 * protocol version into a sub-tree.
1174 basic_request_dissector(tvbuff_t *tvb, proto_tree *tree, int offset,
1175 const guchar *line, const guchar *lineend)
1177 const guchar *next_token;
1180 /* The first token is the method. */
1181 tokenlen = get_token_len(line, lineend, &next_token);
1184 proto_tree_add_item(tree, hf_http_request_method, tvb, offset, tokenlen,
1186 offset += next_token - line;
1189 /* The next token is the URI. */
1190 tokenlen = get_token_len(line, lineend, &next_token);
1193 stat_info->request_uri = se_strdup((gchar*) tvb_get_ephemeral_string(tvb, offset, tokenlen));
1194 proto_tree_add_string(tree, hf_http_request_uri, tvb, offset, tokenlen,
1195 stat_info->request_uri);
1196 offset += next_token - line;
1199 /* Everything to the end of the line is the version. */
1200 tokenlen = lineend - line;
1203 proto_tree_add_item(tree, hf_http_version, tvb, offset, tokenlen,
1208 basic_response_dissector(tvbuff_t *tvb, proto_tree *tree, int offset,
1209 const guchar *line, const guchar *lineend)
1211 const guchar *next_token;
1213 gchar response_chars[4];
1215 /* The first token is the version. */
1216 tokenlen = get_token_len(line, lineend, &next_token);
1219 proto_tree_add_item(tree, hf_http_version, tvb, offset, tokenlen,
1221 offset += next_token - line;
1224 /* The next token is the status code. */
1225 tokenlen = get_token_len(line, lineend, &next_token);
1228 memcpy(response_chars, line, 3);
1229 response_chars[3] = '\0';
1231 stat_info->response_code = strtoul(response_chars,NULL,10);
1233 proto_tree_add_uint(tree, hf_http_response_code, tvb, offset, 3,
1234 stat_info->response_code);
1238 * Dissect the http data chunks and add them to the tree.
1241 chunked_encoding_dissector(tvbuff_t **tvb_ptr, packet_info *pinfo,
1242 proto_tree *tree, int offset)
1244 guint8 *chunk_string = NULL;
1245 guint32 chunk_size = 0;
1246 gint chunk_offset = 0;
1247 guint32 datalen = 0;
1249 gint chunks_decoded = 0;
1250 tvbuff_t *tvb = NULL;
1251 tvbuff_t *new_tvb = NULL;
1252 gint chunked_data_size = 0;
1253 proto_tree *subtree = NULL;
1254 proto_item *ti = NULL;
1256 if (tvb_ptr == NULL || *tvb_ptr == NULL) {
1262 datalen = tvb_reported_length_remaining(tvb, offset);
1265 ti = proto_tree_add_text(tree, tvb, offset, datalen,
1266 "HTTP chunked response");
1267 subtree = proto_item_add_subtree(ti, ett_http_chunked_response);
1271 while (datalen != 0) {
1272 proto_item *chunk_ti = NULL;
1273 proto_tree *chunk_subtree = NULL;
1274 tvbuff_t *data_tvb = NULL;
1279 linelen = tvb_find_line_end(tvb, offset, -1, &chunk_offset, TRUE);
1282 /* Can't get the chunk size line */
1286 chunk_string = tvb_get_ephemeral_string(tvb, offset, linelen);
1288 if (chunk_string == NULL) {
1289 /* Can't get the chunk size line */
1293 c = (gchar*) chunk_string;
1296 * We don't care about the extensions.
1298 if ((c = strchr(c, ';'))) {
1302 chunk_size = strtol((gchar*)chunk_string, NULL, 16);
1304 if (chunk_size > datalen) {
1306 * The chunk size is more than what's in the tvbuff,
1307 * so either the user hasn't enabled decoding, or all
1308 * of the segments weren't captured.
1310 chunk_size = datalen;
1313 else if (new_tvb == NULL) {
1314 new_tvb = tvb_new_composite();
1319 if (new_tvb != NULL && chunk_size != 0) {
1320 tvbuff_t *chunk_tvb = NULL;
1322 chunk_tvb = tvb_new_subset(tvb, chunk_offset,
1323 chunk_size, datalen);
1325 tvb_composite_append(new_tvb, chunk_tvb);
1330 chunked_data_size += chunk_size;
1332 raw_data = g_malloc(chunked_data_size);
1335 if (new_tvb != NULL) {
1336 raw_len = tvb_length_remaining(new_tvb, 0);
1337 tvb_memcpy(new_tvb, raw_data, 0, raw_len);
1342 tvb_memcpy(tvb, (guint8 *)(raw_data + raw_len),
1343 chunk_offset, chunk_size);
1345 new_tvb = tvb_new_real_data(raw_data,
1346 chunked_data_size, chunked_data_size);
1347 tvb_set_free_cb(new_tvb, g_free);
1351 if(chunk_size == 0) {
1352 chunk_ti = proto_tree_add_text(subtree, tvb,
1354 chunk_offset - offset + chunk_size + 2,
1355 "End of chunked encoding");
1357 chunk_ti = proto_tree_add_text(subtree, tvb,
1359 chunk_offset - offset + chunk_size + 2,
1360 "Data chunk (%u octets)", chunk_size);
1363 chunk_subtree = proto_item_add_subtree(chunk_ti,
1364 ett_http_chunk_data);
1366 proto_tree_add_text(chunk_subtree, tvb, offset,
1367 chunk_offset - offset, "Chunk size: %u octets",
1370 data_tvb = tvb_new_subset(tvb, chunk_offset, chunk_size,
1375 * XXX - just use "proto_tree_add_text()"?
1376 * This means that, in TShark, you get
1377 * the entire chunk dumped out in hex,
1378 * in addition to whatever dissection is
1379 * done on the reassembled data.
1381 call_dissector(data_handle, data_tvb, pinfo,
1384 proto_tree_add_text(chunk_subtree, tvb, chunk_offset +
1385 chunk_size, 2, "Chunk boundary");
1389 offset = chunk_offset + chunk_size + 2;
1390 datalen = tvb_reported_length_remaining(tvb, offset);
1393 if (new_tvb != NULL) {
1395 /* Placeholder for the day that composite tvbuffer's will work.
1396 tvb_composite_finalize(new_tvb);
1397 / * tvb_set_reported_length(new_tvb, chunked_data_size); * /
1401 * XXX - Don't free this, since the tvbuffer that was passed
1402 * may be used if the data spans multiple frames and reassembly
1411 * We didn't create a new tvb, so don't allow sub dissectors
1412 * try to decode the non-existant entity body.
1414 chunks_decoded = -1;
1417 return chunks_decoded;
1422 http_payload_subdissector(tvbuff_t *next_tvb, proto_tree *tree, proto_tree *sub_tree, packet_info *pinfo)
1424 /* tree = the main protocol tree that the subdissector would be listed in
1425 * sub_tree = the http protocol tree
1428 struct tcpinfo *tcpinfo = pinfo->private_data;
1429 struct tcp_analysis *tcpd=NULL;
1430 gchar **strings; /* An array for splitting the request URI into hostname and port */
1432 /* Response code 200 means "OK" and strncmp() == 0 means the strings match exactly */
1433 if(stat_info->request_uri && stat_info->response_code == 200 &&
1434 stat_info->request_method && strncmp(stat_info->request_method, "CONNECT", 7) == 0) {
1436 /* Call a subdissector to handle HTTP CONNECT's traffic */
1437 tcpd=get_tcp_conversation_data(pinfo);
1439 /* Grab the destination port number from the request URI to find the right subdissector */
1440 strings = g_strsplit(stat_info->request_uri, ":", 2);
1442 if(strings[0] != NULL && strings[1] != NULL) { /* The string was successfuly split in two */
1443 proto_tree_add_text(sub_tree, next_tvb, 0, 0, "Proxy connect hostname: %s", strings[0]);
1444 proto_tree_add_text(sub_tree, next_tvb, 0, 0, "Proxy connect port: %s", strings[1]);
1446 /* Replaces the pinfo->destport or srcport with the port the http connect was done to by
1447 * checking to see which is the http port. */
1448 if (pinfo->destport == TCP_PORT_HTTP || pinfo->destport == TCP_PORT_PROXY_HTTP ||
1449 pinfo->destport == TCP_PORT_PROXY_ADMIN_HTTP || pinfo->destport == TCP_ALT_PORT_HTTP ||
1450 pinfo->destport == TCP_RADAN_HTTP || pinfo->destport == TCP_PORT_HKP ||
1451 pinfo->destport == TCP_PORT_DAAP || pinfo->destport == http_alternate_tcp_port)
1452 ptr = &pinfo->destport;
1454 ptr = &pinfo->srcport;
1456 *ptr = (int)strtol(strings[1], NULL, 10); /* Convert string to a base-10 integer */
1458 /* We're going to get stuck in a loop if we call let dissect_tcp_payload call
1459 us, so call the data dissector instead for proxy connections to http ports. */
1460 if(*ptr == TCP_PORT_HTTP || *ptr == TCP_PORT_PROXY_HTTP ||
1461 *ptr == TCP_PORT_PROXY_ADMIN_HTTP || *ptr == TCP_ALT_PORT_HTTP ||
1462 *ptr == TCP_RADAN_HTTP || *ptr == TCP_PORT_HKP ||
1463 *ptr == TCP_PORT_DAAP || *ptr == http_alternate_tcp_port) {
1464 call_dissector(data_handle, next_tvb, pinfo, tree);
1466 dissect_tcp_payload(next_tvb, pinfo, 0, tcpinfo->seq, /* 0 = offset */
1467 tcpinfo->nxtseq, pinfo->srcport, pinfo->destport,
1472 g_strfreev(strings); /* Free the result of g_strsplit() above */
1475 /* Call the default data dissector */
1476 call_dissector(data_handle, next_tvb, pinfo, sub_tree);
1483 * XXX - this won't handle HTTP 0.9 replies, but they're all data
1487 is_http_request_or_reply(const gchar *data, int linelen, http_type_t *type,
1488 ReqRespDissector *reqresp_dissector)
1490 int isHttpRequestOrReply = FALSE;
1494 * From RFC 2774 - An HTTP Extension Framework
1496 * Support the command prefix that identifies the presence of
1497 * a "mandatory" header.
1499 if (linelen >= 2 && strncmp(data, "M-", 2) == 0) {
1506 * From draft-cohen-gena-client-01.txt, available from the uPnP forum:
1507 * NOTIFY, SUBSCRIBE, UNSUBSCRIBE
1509 * From draft-ietf-dasl-protocol-00.txt, a now vanished Microsoft draft:
1512 if (linelen >= 5 && strncmp(data, "HTTP/", 5) == 0) {
1513 *type = HTTP_RESPONSE;
1514 isHttpRequestOrReply = TRUE; /* response */
1515 if (reqresp_dissector)
1516 *reqresp_dissector = basic_response_dissector;
1518 const guchar * ptr = (const guchar *)data;
1521 /* Look for the space following the Method */
1522 while (index < linelen) {
1531 /* Check the methods that have same length */
1535 if (strncmp(data, "GET", index) == 0 ||
1536 strncmp(data, "PUT", index) == 0) {
1537 *type = HTTP_REQUEST;
1538 isHttpRequestOrReply = TRUE;
1540 else if (strncmp(data, "ICY", index) == 0) {
1541 *type = HTTP_RESPONSE;
1542 isHttpRequestOrReply = TRUE;
1547 if (strncmp(data, "COPY", index) == 0 ||
1548 strncmp(data, "HEAD", index) == 0 ||
1549 strncmp(data, "LOCK", index) == 0 ||
1550 strncmp(data, "MOVE", index) == 0 ||
1551 strncmp(data, "POLL", index) == 0 ||
1552 strncmp(data, "POST", index) == 0) {
1553 *type = HTTP_REQUEST;
1554 isHttpRequestOrReply = TRUE;
1559 if (strncmp(data, "BCOPY", index) == 0 ||
1560 strncmp(data, "BMOVE", index) == 0 ||
1561 strncmp(data, "MKCOL", index) == 0 ||
1562 strncmp(data, "TRACE", index) == 0 ||
1563 strncmp(data, "LABEL", index) == 0 || /* RFC 3253 8.2 */
1564 strncmp(data, "MERGE", index) == 0) { /* RFC 3253 11.2 */
1565 *type = HTTP_REQUEST;
1566 isHttpRequestOrReply = TRUE;
1571 if (strncmp(data, "DELETE", index) == 0 ||
1572 strncmp(data, "SEARCH", index) == 0 ||
1573 strncmp(data, "UNLOCK", index) == 0 ||
1574 strncmp(data, "REPORT", index) == 0 || /* RFC 3253 3.6 */
1575 strncmp(data, "UPDATE", index) == 0) { /* RFC 3253 7.1 */
1576 *type = HTTP_REQUEST;
1577 isHttpRequestOrReply = TRUE;
1579 else if (strncmp(data, "NOTIFY", index) == 0) {
1580 *type = HTTP_NOTIFICATION;
1581 isHttpRequestOrReply = TRUE;
1586 if (strncmp(data, "BDELETE", index) == 0 ||
1587 strncmp(data, "CONNECT", index) == 0 ||
1588 strncmp(data, "OPTIONS", index) == 0 ||
1589 strncmp(data, "CHECKIN", index) == 0) { /* RFC 3253 4.4, 9.4 */
1590 *type = HTTP_REQUEST;
1591 isHttpRequestOrReply = TRUE;
1596 if (strncmp(data, "PROPFIND", index) == 0 ||
1597 strncmp(data, "CHECKOUT", index) == 0 || /* RFC 3253 4.3, 9.3 */
1598 strncmp(data, "CCM_POST", index) == 0) {
1599 *type = HTTP_REQUEST;
1600 isHttpRequestOrReply = TRUE;
1605 if (strncmp(data, "SUBSCRIBE", index) == 0) {
1606 *type = HTTP_NOTIFICATION;
1607 isHttpRequestOrReply = TRUE;
1608 } else if (strncmp(data, "PROPPATCH", index) == 0 ||
1609 strncmp(data, "BPROPFIND", index) == 0) {
1610 *type = HTTP_REQUEST;
1611 isHttpRequestOrReply = TRUE;
1616 if (strncmp(data, "BPROPPATCH", index) == 0 ||
1617 strncmp(data, "UNCHECKOUT", index) == 0 || /* RFC 3253 4.5 */
1618 strncmp(data, "MKACTIVITY", index) == 0) { /* RFC 3253 13.5 */
1619 *type = HTTP_REQUEST;
1620 isHttpRequestOrReply = TRUE;
1625 if (strncmp(data, "MKWORKSPACE", index) == 0) { /* RFC 3253 6.3 */
1626 *type = HTTP_REQUEST;
1627 isHttpRequestOrReply = TRUE;
1628 } else if (strncmp(data, "UNSUBSCRIBE", index) == 0) {
1629 *type = HTTP_NOTIFICATION;
1630 isHttpRequestOrReply = TRUE;
1631 } else if (strncmp(data, "RPC_CONNECT", index) == 0) {
1632 *type = HTTP_REQUEST;
1633 isHttpRequestOrReply = TRUE;
1638 if (strncmp(data, "VERSION-CONTROL", index) == 0) { /* RFC 3253 3.5 */
1639 *type = HTTP_REQUEST;
1640 isHttpRequestOrReply = TRUE;
1645 if (strncmp(data, "BASELINE-CONTROL", index) == 0) { /* RFC 3253 12.6 */
1646 *type = HTTP_REQUEST;
1647 isHttpRequestOrReply = TRUE;
1655 if (isHttpRequestOrReply && reqresp_dissector) {
1656 *reqresp_dissector = basic_request_dissector;
1657 if (!stat_info->request_method)
1658 stat_info->request_method = se_strndup(data, index+1);
1662 return isHttpRequestOrReply;
1674 #define HDR_NO_SPECIAL 0
1675 #define HDR_AUTHORIZATION 1
1676 #define HDR_AUTHENTICATE 2
1677 #define HDR_CONTENT_TYPE 3
1678 #define HDR_CONTENT_LENGTH 4
1679 #define HDR_CONTENT_ENCODING 5
1680 #define HDR_TRANSFER_ENCODING 6
1683 static const header_info headers[] = {
1684 { "Authorization", &hf_http_authorization, HDR_AUTHORIZATION },
1685 { "Proxy-Authorization", &hf_http_proxy_authorization, HDR_AUTHORIZATION },
1686 { "Proxy-Authenticate", &hf_http_proxy_authenticate, HDR_AUTHENTICATE },
1687 { "WWW-Authenticate", &hf_http_www_authenticate, HDR_AUTHENTICATE },
1688 { "Content-Type", &hf_http_content_type, HDR_CONTENT_TYPE },
1689 { "Content-Length", &hf_http_content_length, HDR_CONTENT_LENGTH },
1690 { "Content-Encoding", &hf_http_content_encoding, HDR_CONTENT_ENCODING },
1691 { "Transfer-Encoding", &hf_http_transfer_encoding, HDR_TRANSFER_ENCODING },
1692 { "User-Agent", &hf_http_user_agent, HDR_NO_SPECIAL },
1693 { "Host", &hf_http_host, HDR_HOST },
1694 { "Connection", &hf_http_connection, HDR_NO_SPECIAL },
1695 { "Cookie", &hf_http_cookie, HDR_NO_SPECIAL },
1696 { "Accept", &hf_http_accept, HDR_NO_SPECIAL },
1697 { "Referer", &hf_http_referer, HDR_NO_SPECIAL },
1698 { "Accept-Language", &hf_http_accept_language, HDR_NO_SPECIAL },
1699 { "Accept-Encoding", &hf_http_accept_encoding, HDR_NO_SPECIAL },
1700 { "Date", &hf_http_date, HDR_NO_SPECIAL },
1701 { "Cache-Control", &hf_http_cache_control, HDR_NO_SPECIAL },
1702 { "Server", &hf_http_server, HDR_NO_SPECIAL },
1703 { "Location", &hf_http_location, HDR_NO_SPECIAL },
1704 { "Set-Cookie", &hf_http_set_cookie, HDR_NO_SPECIAL },
1705 { "Last-Modified", &hf_http_last_modified, HDR_NO_SPECIAL },
1706 { "X-Forwarded-For", &hf_http_x_forwarded_for, HDR_NO_SPECIAL },
1710 process_header(tvbuff_t *tvb, int offset, int next_offset,
1711 const guchar *line, int linelen, int colon_offset,
1712 packet_info *pinfo, proto_tree *tree, headers_t *eh_ptr)
1715 int line_end_offset;
1724 proto_item *hdr_item;
1727 len = next_offset - offset;
1728 line_end_offset = offset + linelen;
1729 header_len = colon_offset - offset;
1730 hf_index = find_header_hf_value(tvb, offset, header_len);
1732 if (hf_index == -1) {
1734 * Not a header we know anything about. Just put it into
1738 proto_tree_add_text(tree, tvb, offset, len,
1739 "%s", format_text(line, len));
1743 * Skip whitespace after the colon.
1745 value_offset = colon_offset + 1;
1746 while (value_offset < line_end_offset
1747 && ((c = line[value_offset - offset]) == ' ' || c == '\t'))
1753 value_len = line_end_offset - value_offset;
1754 value = ep_strndup(&line[value_offset - offset], value_len);
1757 * Add it to the protocol tree as a particular field,
1758 * but display the line as is.
1761 header_field_info *hfinfo;
1764 hfinfo = proto_registrar_get_nth(*headers[hf_index].hf);
1765 switch(hfinfo->type){
1774 tmp=strtol(value, NULL, 10);
1775 hdr_item = proto_tree_add_uint(tree, *headers[hf_index].hf, tvb, offset, len, tmp);
1778 hdr_item = proto_tree_add_string_format(tree,
1779 *headers[hf_index].hf, tvb, offset, len,
1780 value, "%s", format_text(line, len));
1786 * Do any special processing that particular headers
1789 switch (headers[hf_index].special) {
1791 case HDR_AUTHORIZATION:
1792 if (check_auth_ntlmssp(hdr_item, tvb, pinfo, value))
1793 break; /* dissected NTLMSSP */
1794 check_auth_basic(hdr_item, tvb, value);
1797 case HDR_AUTHENTICATE:
1798 check_auth_ntlmssp(hdr_item, tvb, pinfo, value);
1801 case HDR_CONTENT_TYPE:
1802 eh_ptr->content_type = (gchar*) ep_memdup((guint8*)value,value_len + 1);
1804 for (i = 0; i < value_len; i++) {
1806 if (c == ';' || isspace(c)) {
1808 * End of subtype - either
1809 * white space or a ";"
1810 * separating the subtype from
1817 * Map the character to lower case;
1818 * content types are case-insensitive.
1820 eh_ptr->content_type[i] = tolower(eh_ptr->content_type[i]);
1822 eh_ptr->content_type[i] = '\0';
1824 * Now find the start of the optional parameters;
1825 * skip the optional white space and the semicolon
1826 * if this has not been done before.
1829 while (i < value_len) {
1830 c = eh_ptr->content_type[i];
1831 if (c == ';' || isspace(c))
1832 /* Skip till start of parameters */
1838 eh_ptr->content_type_parameters = eh_ptr->content_type + i;
1840 eh_ptr->content_type_parameters = NULL;
1843 case HDR_CONTENT_LENGTH:
1844 eh_ptr->content_length = strtol(value, &p, 10);
1846 if (eh_ptr->content_length < 0 || p == value ||
1847 (*up != '\0' && !isspace(*up))) {
1849 * Content length not valid; pretend
1852 eh_ptr->have_content_length = FALSE;
1855 * We do have a valid content length.
1857 eh_ptr->have_content_length = TRUE;
1861 case HDR_CONTENT_ENCODING:
1862 eh_ptr->content_encoding = ep_strndup(value, value_len);
1865 case HDR_TRANSFER_ENCODING:
1866 eh_ptr->transfer_encoding = ep_strndup(value, value_len);
1870 stat_info->http_host = se_strndup(value, value_len);
1877 /* Returns index of header tag in headers */
1879 find_header_hf_value(tvbuff_t *tvb, int offset, guint header_len)
1883 for (i = 0; i < array_length(headers); i++) {
1884 if (header_len == strlen(headers[i].name) &&
1885 tvb_strncaseeql(tvb, offset,
1886 headers[i].name, header_len) == 0)
1894 * Dissect Microsoft's abomination called NTLMSSP over HTTP.
1897 check_auth_ntlmssp(proto_item *hdr_item, tvbuff_t *tvb, packet_info *pinfo,
1900 static const char *ntlm_headers[] = {
1905 const char **header;
1907 proto_tree *hdr_tree;
1910 * Check for NTLM credentials and challenge; those can
1911 * occur with WWW-Authenticate.
1913 for (header = &ntlm_headers[0]; *header != NULL; header++) {
1914 hdrlen = strlen(*header);
1915 if (strncmp(value, *header, hdrlen) == 0) {
1916 if (hdr_item != NULL) {
1917 hdr_tree = proto_item_add_subtree(hdr_item,
1922 dissect_http_ntlmssp(tvb, pinfo, hdr_tree, value);
1930 * Dissect HTTP Basic authorization.
1933 check_auth_basic(proto_item *hdr_item, tvbuff_t *tvb, gchar *value)
1935 static const char *basic_headers[] = {
1939 const char **header;
1941 proto_tree *hdr_tree;
1944 for (header = &basic_headers[0]; *header != NULL; header++) {
1945 hdrlen = strlen(*header);
1946 if (strncmp(value, *header, hdrlen) == 0) {
1947 if (hdr_item != NULL) {
1948 hdr_tree = proto_item_add_subtree(hdr_item,
1954 len = epan_base64_decode(value);
1956 proto_tree_add_string(hdr_tree, hf_http_basic, tvb,
1966 dissect_http(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1971 while (tvb_reported_length_remaining(tvb, offset) != 0) {
1972 len = dissect_http_message(tvb, offset, pinfo, tree);
1978 * OK, we've set the Protocol and Info columns for the
1979 * first HTTP message; make the columns non-writable,
1980 * so that we don't change it for subsequent HTTP messages.
1982 col_set_writable(pinfo->cinfo, FALSE);
1987 dissect_http_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1989 dissect_http_message(tvb, 0, pinfo, tree);
1992 static void reinit_http(void) {
1993 if ( http_alternate_tcp_port != alternate_tcp_port ) {
1995 if (alternate_tcp_port)
1996 dissector_delete("tcp.port", alternate_tcp_port, http_handle );
1998 if (http_alternate_tcp_port)
1999 dissector_add("tcp.port", http_alternate_tcp_port, http_handle);
2001 alternate_tcp_port = http_alternate_tcp_port;
2006 proto_register_http(void)
2008 static hf_register_info hf[] = {
2009 { &hf_http_notification,
2010 { "Notification", "http.notification",
2011 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2012 "TRUE if HTTP notification", HFILL }},
2013 { &hf_http_response,
2014 { "Response", "http.response",
2015 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2016 "TRUE if HTTP response", HFILL }},
2018 { "Request", "http.request",
2019 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2020 "TRUE if HTTP request", HFILL }},
2022 { "Credentials", "http.authbasic",
2023 FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
2024 { &hf_http_request_method,
2025 { "Request Method", "http.request.method",
2026 FT_STRING, BASE_NONE, NULL, 0x0,
2027 "HTTP Request Method", HFILL }},
2028 { &hf_http_request_uri,
2029 { "Request URI", "http.request.uri",
2030 FT_STRING, BASE_NONE, NULL, 0x0,
2031 "HTTP Request-URI", HFILL }},
2033 { "Request Version", "http.request.version",
2034 FT_STRING, BASE_NONE, NULL, 0x0,
2035 "HTTP Request HTTP-Version", HFILL }},
2036 { &hf_http_response_code,
2037 { "Response Code", "http.response.code",
2038 FT_UINT16, BASE_DEC, NULL, 0x0,
2039 "HTTP Response Code", HFILL }},
2040 { &hf_http_authorization,
2041 { "Authorization", "http.authorization",
2042 FT_STRING, BASE_NONE, NULL, 0x0,
2043 "HTTP Authorization header", HFILL }},
2044 { &hf_http_proxy_authenticate,
2045 { "Proxy-Authenticate", "http.proxy_authenticate",
2046 FT_STRING, BASE_NONE, NULL, 0x0,
2047 "HTTP Proxy-Authenticate header", HFILL }},
2048 { &hf_http_proxy_authorization,
2049 { "Proxy-Authorization", "http.proxy_authorization",
2050 FT_STRING, BASE_NONE, NULL, 0x0,
2051 "HTTP Proxy-Authorization header", HFILL }},
2052 { &hf_http_www_authenticate,
2053 { "WWW-Authenticate", "http.www_authenticate",
2054 FT_STRING, BASE_NONE, NULL, 0x0,
2055 "HTTP WWW-Authenticate header", HFILL }},
2056 { &hf_http_content_type,
2057 { "Content-Type", "http.content_type",
2058 FT_STRING, BASE_NONE, NULL, 0x0,
2059 "HTTP Content-Type header", HFILL }},
2060 { &hf_http_content_length,
2061 { "Content-Length", "http.content_length",
2062 FT_UINT32, BASE_DEC, NULL, 0x0,
2063 "HTTP Content-Length header", HFILL }},
2064 { &hf_http_content_encoding,
2065 { "Content-Encoding", "http.content_encoding",
2066 FT_STRING, BASE_NONE, NULL, 0x0,
2067 "HTTP Content-Encoding header", HFILL }},
2068 { &hf_http_transfer_encoding,
2069 { "Transfer-Encoding", "http.transfer_encoding",
2070 FT_STRING, BASE_NONE, NULL, 0x0,
2071 "HTTP Transfer-Encoding header", HFILL }},
2072 { &hf_http_user_agent,
2073 { "User-Agent", "http.user_agent",
2074 FT_STRING, BASE_NONE, NULL, 0x0,
2075 "HTTP User-Agent header", HFILL }},
2077 { "Host", "http.host",
2078 FT_STRING, BASE_NONE, NULL, 0x0,
2079 "HTTP Host", HFILL }},
2080 { &hf_http_connection,
2081 { "Connection", "http.connection",
2082 FT_STRING, BASE_NONE, NULL, 0x0,
2083 "HTTP Connection", HFILL }},
2085 { "Cookie", "http.cookie",
2086 FT_STRING, BASE_NONE, NULL, 0x0,
2087 "HTTP Cookie", HFILL }},
2089 { "Accept", "http.accept",
2090 FT_STRING, BASE_NONE, NULL, 0x0,
2091 "HTTP Accept", HFILL }},
2093 { "Referer", "http.referer",
2094 FT_STRING, BASE_NONE, NULL, 0x0,
2095 "HTTP Referer", HFILL }},
2096 { &hf_http_accept_language,
2097 { "Accept-Language", "http.accept_language",
2098 FT_STRING, BASE_NONE, NULL, 0x0,
2099 "HTTP Accept Language", HFILL }},
2100 { &hf_http_accept_encoding,
2101 { "Accept Encoding", "http.accept_encoding",
2102 FT_STRING, BASE_NONE, NULL, 0x0,
2103 "HTTP Accept Encoding", HFILL }},
2105 { "Date", "http.date",
2106 FT_STRING, BASE_NONE, NULL, 0x0,
2107 "HTTP Date", HFILL }},
2108 { &hf_http_cache_control,
2109 { "Cache-Control", "http.cache_control",
2110 FT_STRING, BASE_NONE, NULL, 0x0,
2111 "HTTP Cache Control", HFILL }},
2113 { "Server", "http.server",
2114 FT_STRING, BASE_NONE, NULL, 0x0,
2115 "HTTP Server", HFILL }},
2116 { &hf_http_location,
2117 { "Location", "http.location",
2118 FT_STRING, BASE_NONE, NULL, 0x0,
2119 "HTTP Location", HFILL }},
2120 { &hf_http_set_cookie,
2121 { "Set-Cookie", "http.set_cookie",
2122 FT_STRING, BASE_NONE, NULL, 0x0,
2123 "HTTP Set Cookie", HFILL }},
2124 { &hf_http_last_modified,
2125 { "Last-Modified", "http.last_modified",
2126 FT_STRING, BASE_NONE, NULL, 0x0,
2127 "HTTP Last Modified", HFILL }},
2128 { &hf_http_x_forwarded_for,
2129 { "X-Forwarded-For", "http.x_forwarded_for",
2130 FT_STRING, BASE_NONE, NULL, 0x0,
2131 "HTTP X-Forwarded-For", HFILL }},
2133 static gint *ett[] = {
2137 &ett_http_chunked_response,
2138 &ett_http_chunk_data,
2139 &ett_http_encoded_entity,
2141 module_t *http_module;
2143 proto_http = proto_register_protocol("Hypertext Transfer Protocol",
2145 proto_register_field_array(proto_http, hf, array_length(hf));
2146 proto_register_subtree_array(ett, array_length(ett));
2147 register_dissector("http", dissect_http, proto_http);
2148 http_module = prefs_register_protocol(proto_http, reinit_http);
2149 prefs_register_bool_preference(http_module, "desegment_headers",
2150 "Reassemble HTTP headers spanning multiple TCP segments",
2151 "Whether the HTTP dissector should reassemble headers "
2152 "of a request spanning multiple TCP segments. "
2153 "To use this option, you must also enable "
2154 "\"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
2155 &http_desegment_headers);
2156 prefs_register_bool_preference(http_module, "desegment_body",
2157 "Reassemble HTTP bodies spanning multiple TCP segments",
2158 "Whether the HTTP dissector should use the "
2159 "\"Content-length:\" value, if present, to reassemble "
2160 "the body of a request spanning multiple TCP segments, "
2161 "and reassemble chunked data spanning multiple TCP segments. "
2162 "To use this option, you must also enable "
2163 "\"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
2164 &http_desegment_body);
2165 prefs_register_bool_preference(http_module, "dechunk_body",
2166 "Reassemble chunked transfer-coded bodies",
2167 "Whether to reassemble bodies of entities that are transfered "
2168 "using the \"Transfer-Encoding: chunked\" method",
2169 &http_dechunk_body);
2171 prefs_register_bool_preference(http_module, "decompress_body",
2172 "Uncompress entity bodies",
2173 "Whether to uncompress entity bodies that are compressed "
2174 "using \"Content-Encoding: \"",
2175 &http_decompress_body);
2177 prefs_register_uint_preference(http_module, "tcp_alternate_port",
2178 "Alternate TCP port",
2179 "Decode packets on this TCP port as HTTP",
2180 10,&http_alternate_tcp_port);
2182 http_handle = create_dissector_handle(dissect_http, proto_http);
2185 * Dissectors shouldn't register themselves in this table;
2186 * instead, they should call "http_dissector_add()", and
2187 * we'll register the port number they specify as a port
2188 * for HTTP, and register them in our subdissector table.
2190 * This only works for protocols such as IPP that run over
2191 * HTTP on a specific non-HTTP port.
2193 port_subdissector_table = register_dissector_table("http.port",
2194 "TCP port for protocols using HTTP", FT_UINT16, BASE_DEC);
2197 * Dissectors can register themselves in this table.
2198 * It's just "media_type", not "http.content_type", because
2199 * it's an Internet media type, usable by other protocols as well.
2201 media_type_subdissector_table =
2202 register_dissector_table("media_type",
2203 "Internet media type", FT_STRING, BASE_NONE);
2206 * Heuristic dissectors SHOULD register themselves in
2207 * this table using the standard heur_dissector_add()
2210 register_heur_dissector_list("http", &heur_subdissector_list);
2213 * Register for tapping
2215 http_tap = register_tap("http");
2219 * Called by dissectors for protocols that run atop HTTP/TCP.
2222 http_dissector_add(guint32 port, dissector_handle_t handle)
2225 * Register ourselves as the handler for that port number
2228 dissector_add("tcp.port", port, http_handle);
2231 * And register them in *our* table for that port.
2233 dissector_add("http.port", port, handle);
2237 proto_reg_handoff_http(void)
2239 dissector_handle_t http_udp_handle;
2241 data_handle = find_dissector("data");
2242 media_handle = find_dissector("media");
2244 dissector_add("tcp.port", TCP_PORT_HTTP, http_handle);
2245 dissector_add("tcp.port", TCP_PORT_PROXY_HTTP, http_handle);
2246 dissector_add("tcp.port", TCP_ALT_PORT_HTTP, http_handle);
2247 dissector_add("tcp.port", TCP_RADAN_HTTP, http_handle);
2248 dissector_add("tcp.port", TCP_PORT_PROXY_ADMIN_HTTP, http_handle);
2249 dissector_add("tcp.port", TCP_PORT_HKP, http_handle);
2252 * XXX - is there anything to dissect in the body of an SSDP
2253 * request or reply? I.e., should there be an SSDP dissector?
2255 dissector_add("tcp.port", TCP_PORT_SSDP, http_handle);
2256 http_udp_handle = create_dissector_handle(dissect_http_udp, proto_http);
2257 dissector_add("udp.port", UDP_PORT_SSDP, http_udp_handle);
2259 ntlmssp_handle = find_dissector("ntlmssp");
2260 gssapi_handle = find_dissector("gssapi");
2262 stats_tree_register("http","http","HTTP/Packet Counter", http_stats_tree_packet, http_stats_tree_init, NULL );
2263 stats_tree_register("http","http_req","HTTP/Requests", http_req_stats_tree_packet, http_req_stats_tree_init, NULL );
2264 stats_tree_register("http","http_srv","HTTP/Load Distribution",http_reqs_stats_tree_packet,http_reqs_stats_tree_init, NULL );
2269 * Content-Type: message/http
2272 static gint proto_message_http = -1;
2273 static gint ett_message_http = -1;
2274 static dissector_handle_t message_http_handle;
2277 dissect_message_http(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2279 proto_tree *subtree;
2281 gint offset = 0, next_offset;
2284 if (check_col(pinfo->cinfo, COL_INFO))
2285 col_append_str(pinfo->cinfo, COL_INFO, " (message/http)");
2287 ti = proto_tree_add_item(tree, proto_message_http,
2289 subtree = proto_item_add_subtree(ti, ett_message_http);
2290 while (tvb_reported_length_remaining(tvb, offset) != 0) {
2291 len = tvb_find_line_end(tvb, offset,
2292 tvb_ensure_length_remaining(tvb, offset),
2293 &next_offset, FALSE);
2296 proto_tree_add_text(subtree, tvb, offset, next_offset - offset,
2297 "%s", tvb_format_text(tvb, offset, len));
2298 offset = next_offset;
2304 proto_register_message_http(void)
2306 static gint *ett[] = {
2310 proto_message_http = proto_register_protocol(
2311 "Media Type: message/http",
2315 proto_register_subtree_array(ett, array_length(ett));
2319 proto_reg_handoff_message_http(void)
2321 message_http_handle = create_dissector_handle(dissect_message_http,
2322 proto_message_http);
2324 dissector_add_string("media_type", "message/http", message_http_handle);