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 "packet-ssl.h"
53 #include <epan/prefs.h>
54 #include <epan/expert.h>
56 typedef enum _http_type {
65 #ifdef NEED_G_ASCII_STRCASECMP_H
66 #include "g_ascii_strcasecmp.h"
69 static int http_tap = -1;
70 static int http_eo_tap = -1;
72 static int proto_http = -1;
73 static int hf_http_notification = -1;
74 static int hf_http_response = -1;
75 static int hf_http_request = -1;
76 static int hf_http_basic = -1;
77 static int hf_http_request_method = -1;
78 static int hf_http_request_uri = -1;
79 static int hf_http_version = -1;
80 static int hf_http_response_code = -1;
81 static int hf_http_authorization = -1;
82 static int hf_http_proxy_authenticate = -1;
83 static int hf_http_proxy_authorization = -1;
84 static int hf_http_proxy_connect_host = -1;
85 static int hf_http_proxy_connect_port = -1;
86 static int hf_http_www_authenticate = -1;
87 static int hf_http_content_type = -1;
88 static int hf_http_content_length = -1;
89 static int hf_http_content_encoding = -1;
90 static int hf_http_transfer_encoding = -1;
91 static int hf_http_user_agent = -1;
92 static int hf_http_host = -1;
93 static int hf_http_connection = -1;
94 static int hf_http_cookie = -1;
95 static int hf_http_accept = -1;
96 static int hf_http_referer = -1;
97 static int hf_http_accept_language = -1;
98 static int hf_http_accept_encoding = -1;
99 static int hf_http_date = -1;
100 static int hf_http_cache_control = -1;
101 static int hf_http_server = -1;
102 static int hf_http_location = -1;
103 static int hf_http_set_cookie = -1;
104 static int hf_http_last_modified = -1;
105 static int hf_http_x_forwarded_for = -1;
107 static gint ett_http = -1;
108 static gint ett_http_ntlmssp = -1;
109 static gint ett_http_request = -1;
110 static gint ett_http_chunked_response = -1;
111 static gint ett_http_chunk_data = -1;
112 static gint ett_http_encoded_entity = -1;
114 static dissector_handle_t data_handle;
115 static dissector_handle_t media_handle;
116 static dissector_handle_t http_handle;
119 * desegmentation of HTTP headers
120 * (when we are over TCP or another protocol providing the desegmentation API)
122 static gboolean http_desegment_headers = TRUE;
125 * desegmentation of HTTP bodies
126 * (when we are over TCP or another protocol providing the desegmentation API)
127 * TODO let the user filter on content-type the bodies he wants desegmented
129 static gboolean http_desegment_body = TRUE;
132 * De-chunking of content-encoding: chunk entity bodies.
134 static gboolean http_dechunk_body = TRUE;
137 * Decompression of zlib encoded entities.
140 static gboolean http_decompress_body = TRUE;
142 static gboolean http_decompress_body = FALSE;
145 #define TCP_PORT_HTTP 80
146 #define TCP_PORT_PROXY_HTTP 3128
147 #define TCP_PORT_PROXY_ADMIN_HTTP 3132
148 #define TCP_ALT_PORT_HTTP 8080
149 #define TCP_RADAN_HTTP 8088
150 #define TCP_PORT_HKP 11371
151 #define TCP_PORT_DAAP 3689
154 * SSDP is implemented atop HTTP (yes, it really *does* run over UDP).
156 #define TCP_PORT_SSDP 1900
157 #define UDP_PORT_SSDP 1900
163 #define TCP_DEFAULT_RANGE "80,3128,3132,8080,8088,11371,3689,1900"
164 #define SSL_DEFAULT_RANGE "443"
166 static range_t *global_http_tcp_range = NULL;
167 static range_t *global_http_ssl_range = NULL;
169 static range_t *http_tcp_range = NULL;
170 static range_t *http_ssl_range = NULL;
174 * Protocols implemented atop HTTP.
177 PROTO_HTTP, /* just HTTP */
178 PROTO_SSDP, /* Simple Service Discovery Protocol */
179 PROTO_DAAP /* Digital Audio Access Protocol */
182 typedef void (*ReqRespDissector)(tvbuff_t*, proto_tree*, int, const guchar*,
183 const guchar*, http_conv_t *);
186 * Structure holding information from headers needed by main
187 * HTTP dissector code.
191 char *content_type_parameters;
192 gboolean have_content_length;
193 long content_length; /* XXX - make it 64-bit? */
194 char *content_encoding;
195 char *transfer_encoding;
198 static int is_http_request_or_reply(const gchar *data, int linelen,
199 http_type_t *type, ReqRespDissector
200 *reqresp_dissector, http_conv_t *conv_data);
201 static int chunked_encoding_dissector(tvbuff_t **tvb_ptr, packet_info *pinfo,
202 proto_tree *tree, int offset);
203 static void http_payload_subdissector(tvbuff_t *next_tvb, proto_tree *tree,
204 proto_tree *sub_tree, packet_info *pinfo,
205 http_conv_t *conv_data);
206 static void process_header(tvbuff_t *tvb, int offset, int next_offset,
207 const guchar *line, int linelen, int colon_offset, packet_info *pinfo,
208 proto_tree *tree, headers_t *eh_ptr, http_conv_t *conv_data);
209 static gint find_header_hf_value(tvbuff_t *tvb, int offset, guint header_len);
210 static gboolean check_auth_ntlmssp(proto_item *hdr_item, tvbuff_t *tvb,
211 packet_info *pinfo, gchar *value);
212 static gboolean check_auth_basic(proto_item *hdr_item, tvbuff_t *tvb,
215 static dissector_table_t port_subdissector_table;
216 static dissector_table_t media_type_subdissector_table;
217 static heur_dissector_list_t heur_subdissector_list;
219 static dissector_handle_t ntlmssp_handle=NULL;
220 static dissector_handle_t gssapi_handle=NULL;
222 static const value_string vals_status_code[] = {
224 { 101, "Switching Protocols" },
225 { 102, "Processing" },
226 { 199, "Informational - Others" },
231 { 203, "Non-authoritative Information"},
232 { 204, "No Content"},
233 { 205, "Reset Content"},
234 { 206, "Partial Content"},
235 { 207, "Multi-Status"},
236 { 299, "Success - Others"},
238 { 300, "Multiple Choices"},
239 { 301, "Moved Permanently"},
242 { 304, "Not Modified"},
244 { 307, "Temporary Redirect"},
245 { 399, "Redirection - Others"},
247 { 400, "Bad Request"},
248 { 401, "Unauthorized"},
249 { 402, "Payment Required"},
252 { 405, "Method Not Allowed"},
253 { 406, "Not Acceptable"},
254 { 407, "Proxy Authentication Required"},
255 { 408, "Request Time-out"},
258 { 411, "Length Required"},
259 { 412, "Precondition Failed"},
260 { 413, "Request Entity Too Large"},
261 { 414, "Request-URI Too Long"},
262 { 415, "Unsupported Media Type"},
263 { 416, "Requested Range Not Satisfiable"},
264 { 417, "Expectation Failed"},
265 { 422, "Unprocessable Entity"},
267 { 424, "Failed Dependency"},
268 { 499, "Client Error - Others"},
270 { 500, "Internal Server Error"},
271 { 501, "Not Implemented"},
272 { 502, "Bad Gateway"},
273 { 503, "Service Unavailable"},
274 { 504, "Gateway Time-out"},
275 { 505, "HTTP Version not supported"},
276 { 507, "Insufficient Storage"},
277 { 599, "Server Error - Others"},
282 static const gchar* st_str_reqs = "HTTP Requests by Server";
283 static const gchar* st_str_reqs_by_srv_addr = "HTTP Requests by Server Address";
284 static const gchar* st_str_reqs_by_http_host = "HTTP Requests by HTTP Host";
285 static const gchar* st_str_resps_by_srv_addr = "HTTP Responses by Server Address";
287 static int st_node_reqs = -1;
288 static int st_node_reqs_by_srv_addr = -1;
289 static int st_node_reqs_by_http_host = -1;
290 static int st_node_resps_by_srv_addr = -1;
292 /* HTTP/Load Distribution stats init function */
293 static void http_reqs_stats_tree_init(stats_tree* st) {
294 st_node_reqs = stats_tree_create_node(st, st_str_reqs, 0, TRUE);
295 st_node_reqs_by_srv_addr = stats_tree_create_node(st, st_str_reqs_by_srv_addr, st_node_reqs, TRUE);
296 st_node_reqs_by_http_host = stats_tree_create_node(st, st_str_reqs_by_http_host, st_node_reqs, TRUE);
297 st_node_resps_by_srv_addr = stats_tree_create_node(st, st_str_resps_by_srv_addr, 0, TRUE);
300 /* HTTP/Load Distribution stats packet function */
301 static int http_reqs_stats_tree_packet(stats_tree* st, packet_info* pinfo, epan_dissect_t* edt _U_, const void* p) {
302 const http_info_value_t* v = p;
303 int reqs_by_this_host;
304 int reqs_by_this_addr;
305 int resps_by_this_addr;
306 int i = v->response_code;
307 static gchar ip_str[256];
310 if (v->request_method) {
311 g_snprintf(ip_str,sizeof(ip_str),"%s",address_to_str(&pinfo->dst));
313 tick_stat_node(st, st_str_reqs, 0, FALSE);
314 tick_stat_node(st, st_str_reqs_by_srv_addr, st_node_reqs, TRUE);
315 tick_stat_node(st, st_str_reqs_by_http_host, st_node_reqs, TRUE);
316 reqs_by_this_addr = tick_stat_node(st, ip_str, st_node_reqs_by_srv_addr, TRUE);
319 reqs_by_this_host = tick_stat_node(st, v->http_host, st_node_reqs_by_http_host, TRUE);
320 tick_stat_node(st, ip_str, reqs_by_this_host, FALSE);
322 tick_stat_node(st, v->http_host, reqs_by_this_addr, FALSE);
328 g_snprintf(ip_str,sizeof(ip_str),"%s",address_to_str(&pinfo->src));
330 tick_stat_node(st, st_str_resps_by_srv_addr, 0, FALSE);
331 resps_by_this_addr = tick_stat_node(st, ip_str, st_node_resps_by_srv_addr, TRUE);
333 if ( (i>100)&&(i<400) ) {
334 tick_stat_node(st, "OK", resps_by_this_addr, FALSE);
336 tick_stat_node(st, "KO", resps_by_this_addr, FALSE);
346 static int st_node_requests_by_host = -1;
347 static const guint8* st_str_requests_by_host = "HTTP Requests by HTTP Host";
349 /* HTTP/Requests stats init function */
350 static void http_req_stats_tree_init(stats_tree* st) {
351 st_node_requests_by_host = stats_tree_create_node(st, st_str_requests_by_host, 0, TRUE);
354 /* HTTP/Requests stats packet function */
355 static int http_req_stats_tree_packet(stats_tree* st, packet_info* pinfo _U_, epan_dissect_t* edt _U_, const void* p) {
356 const http_info_value_t* v = p;
357 int reqs_by_this_host;
359 if (v->request_method) {
360 tick_stat_node(st, st_str_requests_by_host, 0, FALSE);
363 reqs_by_this_host = tick_stat_node(st, v->http_host, st_node_requests_by_host, TRUE);
365 if (v->request_uri) {
366 tick_stat_node(st, v->request_uri, reqs_by_this_host, TRUE);
376 static const guint8* st_str_packets = "Total HTTP Packets";
377 static const guint8* st_str_requests = "HTTP Request Packets";
378 static const guint8* st_str_responses = "HTTP Response Packets";
379 static const guint8* st_str_resp_broken = "???: broken";
380 static const guint8* st_str_resp_100 = "1xx: Informational";
381 static const guint8* st_str_resp_200 = "2xx: Success";
382 static const guint8* st_str_resp_300 = "3xx: Redirection";
383 static const guint8* st_str_resp_400 = "4xx: Client Error";
384 static const guint8* st_str_resp_500 = "5xx: Server Error";
385 static const guint8* st_str_other = "Other HTTP Packets";
387 static int st_node_packets = -1;
388 static int st_node_requests = -1;
389 static int st_node_responses = -1;
390 static int st_node_resp_broken = -1;
391 static int st_node_resp_100 = -1;
392 static int st_node_resp_200 = -1;
393 static int st_node_resp_300 = -1;
394 static int st_node_resp_400 = -1;
395 static int st_node_resp_500 = -1;
396 static int st_node_other = -1;
399 /* HTTP/Packet Counter stats init function */
400 static void http_stats_tree_init(stats_tree* st) {
401 st_node_packets = stats_tree_create_node(st, st_str_packets, 0, TRUE);
402 st_node_requests = stats_tree_create_pivot(st, st_str_requests, st_node_packets);
403 st_node_responses = stats_tree_create_node(st, st_str_responses, st_node_packets, TRUE);
404 st_node_resp_broken = stats_tree_create_node(st, st_str_resp_broken, st_node_responses, TRUE);
405 st_node_resp_100 = stats_tree_create_node(st, st_str_resp_100, st_node_responses, TRUE);
406 st_node_resp_200 = stats_tree_create_node(st, st_str_resp_200, st_node_responses, TRUE);
407 st_node_resp_300 = stats_tree_create_node(st, st_str_resp_300, st_node_responses, TRUE);
408 st_node_resp_400 = stats_tree_create_node(st, st_str_resp_400, st_node_responses, TRUE);
409 st_node_resp_500 = stats_tree_create_node(st, st_str_resp_500, st_node_responses, TRUE);
410 st_node_other = stats_tree_create_node(st, st_str_other, st_node_packets,FALSE);
413 /* HTTP/Packet Counter stats packet function */
414 static int http_stats_tree_packet(stats_tree* st, packet_info* pinfo _U_, epan_dissect_t* edt _U_, const void* p) {
415 const http_info_value_t* v = p;
416 guint i = v->response_code;
418 const guint8* resp_str;
419 static gchar str[64];
421 tick_stat_node(st, st_str_packets, 0, FALSE);
424 tick_stat_node(st, st_str_responses, st_node_packets, FALSE);
426 if ( (i<100)||(i>=600) ) {
427 resp_grp = st_node_resp_broken;
428 resp_str = st_str_resp_broken;
430 resp_grp = st_node_resp_100;
431 resp_str = st_str_resp_100;
433 resp_grp = st_node_resp_200;
434 resp_str = st_str_resp_200;
436 resp_grp = st_node_resp_300;
437 resp_str = st_str_resp_300;
439 resp_grp = st_node_resp_400;
440 resp_str = st_str_resp_400;
442 resp_grp = st_node_resp_500;
443 resp_str = st_str_resp_500;
446 tick_stat_node(st, resp_str, st_node_responses, FALSE);
448 g_snprintf(str, sizeof(str),"%u %s",i,match_strval(i,vals_status_code));
449 tick_stat_node(st, str, resp_grp, FALSE);
450 } else if (v->request_method) {
451 stats_tree_tick_pivot(st,st_node_requests,v->request_method);
453 tick_stat_node(st, st_str_other, st_node_packets, FALSE);
459 /* Return a tvb that contains the binary representation of a base64
463 base64_to_tvb(const char *base64)
466 char *data = g_strdup(base64);
469 len = epan_base64_decode(data);
470 tvb = tvb_new_real_data((const guint8 *)data, len, len);
472 tvb_set_free_cb(tvb, g_free);
478 dissect_http_ntlmssp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
481 tvbuff_t *ntlmssp_tvb;
483 ntlmssp_tvb = base64_to_tvb(line);
484 tvb_set_child_real_data_tvbuff(tvb, ntlmssp_tvb);
485 add_new_data_source(pinfo, ntlmssp_tvb, "NTLMSSP / GSSAPI Data");
486 if (tvb_strneql(ntlmssp_tvb, 0, "NTLMSSP", 7) == 0)
487 call_dissector(ntlmssp_handle, ntlmssp_tvb, pinfo, tree);
489 call_dissector(gssapi_handle, ntlmssp_tvb, pinfo, tree);
493 * TODO: remove this ugly global variable.
494 * XXX: do we really want to have to pass this from one function to another?
496 static http_info_value_t *stat_info;
499 dissect_http_message(tvbuff_t *tvb, int offset, packet_info *pinfo,
503 const char *proto_tag;
504 proto_tree *http_tree = NULL;
505 proto_item *ti = NULL;
508 const guchar *linep, *lineend;
510 int first_linelen, linelen;
511 gboolean is_request_or_reply;
512 gboolean saw_req_resp_or_header;
514 http_type_t http_type;
515 proto_item *hdr_item = NULL;
516 ReqRespDissector reqresp_dissector;
517 proto_tree *req_tree;
521 int reported_datalen = -1;
522 dissector_handle_t handle;
525 /*http_info_value_t *si;*/
526 conversation_t *conversation;
527 http_conv_t *conv_data;
530 conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
532 if(!conversation) { /* Conversation does not exist yet - create it */
533 conversation = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
536 /* Retrieve information from conversation
537 * or add it if it isn't there yet
540 conv_data = conversation_get_proto_data(conversation, proto_http);
542 /* Setup the conversation structure itself */
543 conv_data = se_alloc(sizeof(http_conv_t));
545 conv_data->response_code = 0;
546 conv_data->request_method = NULL;
547 conv_data->request_uri = NULL;
549 conversation_add_proto_data(conversation, proto_http,
554 * Is this a request or response?
556 * Note that "tvb_find_line_end()" will return a value that
557 * is not longer than what's in the buffer, so the
558 * "tvb_get_ptr()" call won't throw an exception.
560 first_linelen = tvb_find_line_end(tvb, offset,
561 tvb_ensure_length_remaining(tvb, offset), &next_offset,
564 * Is the first line a request or response?
566 line = tvb_get_ptr(tvb, offset, first_linelen);
567 http_type = HTTP_OTHERS; /* type not known yet */
568 is_request_or_reply = is_http_request_or_reply((const gchar *)line,
569 first_linelen, &http_type, NULL, conv_data);
570 if (is_request_or_reply) {
572 * Yes, it's a request or response.
573 * Do header desegmentation if we've been told to,
574 * and do body desegmentation if we've been told to and
575 * we find a Content-Length header.
577 if (!req_resp_hdrs_do_reassembly(tvb, offset, pinfo,
578 http_desegment_headers, http_desegment_body)) {
580 * More data needed for desegmentation.
586 stat_info = ep_alloc(sizeof(http_info_value_t));
587 stat_info->framenum = pinfo->fd->num;
588 stat_info->response_code = 0;
589 stat_info->request_method = NULL;
590 stat_info->request_uri = NULL;
591 stat_info->http_host = NULL;
593 switch (pinfo->match_port) {
595 case TCP_PORT_SSDP: /* TCP_PORT_SSDP = UDP_PORT_SSDP */
611 if (check_col(pinfo->cinfo, COL_PROTOCOL))
612 col_set_str(pinfo->cinfo, COL_PROTOCOL, proto_tag);
613 if (check_col(pinfo->cinfo, COL_INFO)) {
615 * Put the first line from the buffer into the summary
616 * if it's an HTTP request or reply (but leave out the
618 * Otherwise, just call it a continuation.
620 * Note that "tvb_find_line_end()" will return a value that
621 * is not longer than what's in the buffer, so the
622 * "tvb_get_ptr()" call won't throw an exception.
624 if (is_request_or_reply) {
625 line = tvb_get_ptr(tvb, offset, first_linelen);
626 col_add_str(pinfo->cinfo, COL_INFO, format_text(line, first_linelen));
629 col_set_str(pinfo->cinfo, COL_INFO, "Continuation or non-HTTP traffic");
632 orig_offset = offset;
634 ti = proto_tree_add_item(tree, proto_http, tvb, offset, -1,
636 http_tree = proto_item_add_subtree(ti, ett_http);
640 * Process the packet data, a line at a time.
642 http_type = HTTP_OTHERS; /* type not known yet */
643 headers.content_type = NULL; /* content type not known yet */
644 headers.content_type_parameters = NULL; /* content type parameters too */
645 headers.have_content_length = FALSE; /* content length not known yet */
646 headers.content_length = 0; /* content length set to 0 (avoid a gcc warning) */
647 headers.content_encoding = NULL; /* content encoding not known yet */
648 headers.transfer_encoding = NULL; /* transfer encoding not known yet */
649 saw_req_resp_or_header = FALSE; /* haven't seen anything yet */
650 while (tvb_reported_length_remaining(tvb, offset) != 0) {
652 * Find the end of the line.
653 * XXX - what if we don't find it because the packet
654 * is cut short by a snapshot length or the header is
655 * split across TCP segments? How much dissection should
658 linelen = tvb_find_line_end(tvb, offset,
659 tvb_ensure_length_remaining(tvb, offset), &next_offset,
665 * Get a buffer that refers to the line.
667 line = tvb_get_ptr(tvb, offset, linelen);
668 lineend = line + linelen;
672 * OK, does it look like an HTTP request or response?
674 reqresp_dissector = NULL;
675 is_request_or_reply =
676 is_http_request_or_reply((const gchar *)line,
677 linelen, &http_type, &reqresp_dissector, conv_data);
678 if (is_request_or_reply)
682 * No. Does it look like a blank line (as would appear
683 * at the end of an HTTP request)?
686 goto is_http; /* Yes. */
689 * No. Does it look like a header?
692 colon_offset = offset;
693 while (linep < lineend) {
697 * This must be a CHAR to be part of a token; that
698 * means it must be ASCII.
701 break; /* not ASCII, thus not a CHAR */
704 * This mustn't be a CTL to be part of a token.
706 * XXX - what about leading LWS on continuation
710 break; /* CTL, not part of a header */
713 * This mustn't be a SEP to be part of a token;
714 * a ':' ends the token, everything else is an
715 * indication that this isn't a header.
737 * It's a separator, so it's not part of a
738 * token, so it's not a field name for the
739 * beginning of a header.
741 * (We don't have to check for HT; that's
742 * already been ruled out by "iscntrl()".)
748 * This ends the token; we consider this
760 * We haven't seen the colon, but everything else looks
761 * OK for a header line.
763 * If we've already seen an HTTP request or response
764 * line, or a header line, and we're at the end of
765 * the tvbuff, we assume this is an incomplete header
766 * line. (We quit this loop after seeing a blank line,
767 * so if we've seen a request or response line, or a
768 * header line, this is probably more of the request
769 * or response we're presumably seeing. There is some
770 * risk of false positives, but the same applies for
771 * full request or response lines or header lines,
772 * although that's less likely.)
774 * We throw an exception in that case, by checking for
775 * the existence of the next byte after the last one
776 * in the line. If it exists, "tvb_ensure_bytes_exist()"
777 * throws no exception, and we fall through to the
778 * "not HTTP" case. If it doesn't exist,
779 * "tvb_ensure_bytes_exist()" will throw the appropriate
782 if (saw_req_resp_or_header)
783 tvb_ensure_bytes_exist(tvb, offset, linelen + 1);
787 * We don't consider this part of an HTTP request or
788 * reply, so we don't display it.
789 * (Yeah, that means we don't display, say, a text/http
790 * page, but you can get that from the data pane.)
800 * This is a blank line, which means that
801 * whatever follows it isn't part of this
804 proto_tree_add_text(http_tree, tvb, offset,
805 next_offset - offset, "%s",
806 tvb_format_text(tvb, offset, next_offset - offset));
807 offset = next_offset;
812 * Not a blank line - either a request, a reply, or a header
815 saw_req_resp_or_header = TRUE;
816 if (is_request_or_reply) {
817 char *text = tvb_format_text(tvb, offset, next_offset - offset);
819 hdr_item = proto_tree_add_text(http_tree, tvb,
820 offset, next_offset - offset, "%s", text);
822 expert_add_info_format(pinfo, hdr_item, PI_SEQUENCE, PI_CHAT, "%s", text);
823 if (reqresp_dissector) {
824 if (tree) req_tree = proto_item_add_subtree(hdr_item, ett_http_request);
825 else req_tree = NULL;
827 reqresp_dissector(tvb, req_tree, offset, line,
835 process_header(tvb, offset, next_offset, line, linelen,
836 colon_offset, pinfo, http_tree, &headers, conv_data);
838 offset = next_offset;
844 case HTTP_NOTIFICATION:
845 proto_tree_add_boolean_hidden(http_tree,
846 hf_http_notification, tvb, 0, 0, 1);
850 proto_tree_add_boolean_hidden(http_tree,
851 hf_http_response, tvb, 0, 0, 1);
855 proto_tree_add_boolean_hidden(http_tree,
856 hf_http_request, tvb, 0, 0, 1);
866 * If a content length was supplied, the amount of data to be
867 * processed as HTTP payload is the minimum of the content
868 * length and the amount of data remaining in the frame.
870 * If no content length was supplied (or if a bad content length
871 * was supplied), the amount of data to be processed is the amount
872 * of data remaining in the frame.
874 * If there was no Content-Length entity header, we should
875 * accumulate all data until the end of the connection.
876 * That'd require that the TCP dissector call subdissectors
877 * for all frames with FIN, even if they contain no data,
878 * which would require subdissectors to deal intelligently
879 * with empty segments.
881 * Acccording to RFC 2616, however, 1xx responses, 204 responses,
882 * and 304 responses MUST NOT include a message body; if no
883 * content length is specified for them, we don't attempt to
886 * XXX - it says the same about responses to HEAD requests;
887 * unless there's a way to determine from the response
888 * whether it's a response to a HEAD request, we have to
889 * keep information about the request and associate that with
890 * the response in order to handle that.
892 datalen = tvb_length_remaining(tvb, offset);
893 if (headers.have_content_length && headers.content_length != -1) {
894 if (datalen > headers.content_length)
895 datalen = headers.content_length;
898 * XXX - limit the reported length in the tvbuff we'll
899 * hand to a subdissector to be no greater than the
902 * We really need both unreassembled and "how long it'd
903 * be if it were reassembled" lengths for tvbuffs, so
904 * that we throw the appropriate exceptions for
905 * "not enough data captured" (running past the length),
906 * "packet needed reassembly" (within the length but
907 * running past the unreassembled length), and
908 * "packet is malformed" (running past the reassembled
911 reported_datalen = tvb_reported_length_remaining(tvb, offset);
912 if (reported_datalen > headers.content_length)
913 reported_datalen = headers.content_length;
919 * Requests have no content if there's no
920 * Content-Length header and no Transfer-Encoding
923 if (headers.transfer_encoding == NULL)
926 reported_datalen = -1;
930 if ((stat_info->response_code/100) == 1 ||
931 stat_info->response_code == 204 ||
932 stat_info->response_code == 304)
933 datalen = 0; /* no content! */
936 * XXX - responses to HEAD requests,
937 * and possibly other responses,
938 * "MUST NOT" include a
941 reported_datalen = -1;
947 * XXX - what about HTTP_NOTIFICATION?
949 reported_datalen = -1;
956 * There's stuff left over; process it.
959 void *save_private_data = NULL;
960 gint chunks_decoded = 0;
963 * Create a tvbuff for the payload.
965 * The amount of data to be processed that's
966 * available in the tvbuff is "datalen", which
967 * is the minimum of the amount of data left in
968 * the tvbuff and any specified content length.
970 * The amount of data to be processed that's in
971 * this frame, regardless of whether it was
972 * captured or not, is "reported_datalen",
973 * which, if no content length was specified,
974 * is -1, i.e. "to the end of the frame.
976 next_tvb = tvb_new_subset(tvb, offset, datalen,
979 * BEWARE - next_tvb is a subset of another tvb,
980 * so we MUST NOT attempt tvb_free(next_tvb);
984 * Handle *transfer* encodings other than "identity".
986 if (headers.transfer_encoding != NULL &&
987 g_ascii_strcasecmp(headers.transfer_encoding, "identity") != 0) {
988 if (http_dechunk_body &&
989 (g_ascii_strncasecmp(headers.transfer_encoding, "chunked", 7)
992 chunks_decoded = chunked_encoding_dissector(
993 &next_tvb, pinfo, http_tree, 0);
995 if (chunks_decoded <= 0) {
997 * The chunks weren't reassembled,
998 * or there was a single zero
1001 goto body_dissected;
1004 * Add a new data source for the
1007 tvb_set_child_real_data_tvbuff(tvb,
1009 add_new_data_source(pinfo, next_tvb,
1010 "De-chunked entity body");
1014 * We currently can't handle, for example,
1015 * "gzip", "compress", or "deflate" as
1016 * *transfer* encodings; just handle them
1019 call_dissector(data_handle, next_tvb, pinfo,
1021 goto body_dissected;
1025 * At this point, any chunked *transfer* coding has been removed
1026 * (the entity body has been dechunked) so it can be presented
1027 * for the following operation (*content* encoding), or it has
1028 * been been handed off to the data dissector.
1030 * Handle *content* encodings other than "identity" (which
1031 * shouldn't appear in a Content-Encoding header, but
1032 * we handle it in any case).
1034 if (headers.content_encoding != NULL &&
1035 g_ascii_strcasecmp(headers.content_encoding, "identity") != 0) {
1037 * We currently can't handle, for example, "compress";
1038 * just handle them as data for now.
1040 * After July 7, 2004 the LZW patent expires, so support
1041 * might be added then. However, I don't think that
1042 * anybody ever really implemented "compress", due to
1043 * the aforementioned patent.
1045 tvbuff_t *uncomp_tvb = NULL;
1046 proto_item *e_ti = NULL;
1047 proto_tree *e_tree = NULL;
1049 if (http_decompress_body &&
1050 (g_ascii_strcasecmp(headers.content_encoding, "gzip") == 0 ||
1051 g_ascii_strcasecmp(headers.content_encoding, "deflate")
1054 uncomp_tvb = tvb_uncompress(next_tvb, 0,
1055 tvb_length(next_tvb));
1059 * Add the encoded entity to the protocol tree
1061 e_ti = proto_tree_add_text(http_tree, next_tvb,
1062 0, tvb_length(next_tvb),
1063 "Content-encoded entity body (%s): %u bytes",
1064 headers.content_encoding,
1065 tvb_length(next_tvb));
1066 e_tree = proto_item_add_subtree(e_ti,
1067 ett_http_encoded_entity);
1069 if (uncomp_tvb != NULL) {
1071 * Decompression worked
1074 /* XXX - Don't free this, since it's possible
1075 * that the data was only partially
1076 * decompressed, such as when desegmentation
1081 proto_item_append_text(e_ti, " -> %u bytes", tvb_length(uncomp_tvb));
1082 next_tvb = uncomp_tvb;
1083 tvb_set_child_real_data_tvbuff(tvb, next_tvb);
1084 add_new_data_source(pinfo, next_tvb,
1085 "Uncompressed entity body");
1087 call_dissector(data_handle, next_tvb, pinfo,
1090 goto body_dissected;
1094 * Note that a new data source is added for the entity body
1095 * only if it was content-encoded and/or transfer-encoded.
1098 /* Save values for the Export Object GUI feature if we have
1099 * an active listener to process it (which happens when
1100 * the export object window is open). */
1101 if(have_tap_listener(http_eo_tap)) {
1102 eo_info = ep_alloc(sizeof(http_eo_t));
1104 eo_info->hostname = conv_data->http_host;
1105 eo_info->filename = conv_data->request_uri;
1106 eo_info->content_type = headers.content_type;
1107 eo_info->payload_len = next_tvb->length;
1108 eo_info->payload_data = next_tvb->real_data;
1110 tap_queue_packet(http_eo_tap, pinfo, eo_info);
1114 * Do subdissector checks.
1116 * First, check whether some subdissector asked that they
1117 * be called if something was on some particular port.
1120 handle = dissector_get_port_handle(port_subdissector_table,
1122 if (handle == NULL && headers.content_type != NULL) {
1124 * We didn't find any subdissector that
1125 * registered for the port, and we have a
1126 * Content-Type value. Is there any subdissector
1127 * for that content type?
1129 save_private_data = pinfo->private_data;
1131 if (headers.content_type_parameters)
1132 pinfo->private_data = ep_strdup(headers.content_type_parameters);
1134 pinfo->private_data = NULL;
1136 * Calling the string handle for the media type
1137 * dissector table will set pinfo->match_string
1138 * to headers.content_type for us.
1140 pinfo->match_string = headers.content_type;
1141 handle = dissector_get_string_handle(
1142 media_type_subdissector_table,
1143 headers.content_type);
1145 if (handle != NULL) {
1147 * We have a subdissector - call it.
1149 dissected = call_dissector(handle, next_tvb, pinfo,
1153 * We don't have a subdissector - try the heuristic
1156 dissected = dissector_try_heuristic(
1157 heur_subdissector_list, next_tvb, pinfo, tree);
1161 * The subdissector dissected the body.
1162 * Fix up the top-level item so that it doesn't
1163 * include the stuff for that protocol.
1166 proto_item_set_len(ti, offset);
1168 if (headers.content_type != NULL) {
1170 * Calling the default media handle if there is a content-type that
1171 * wasn't handled above.
1173 call_dissector(media_handle, next_tvb, pinfo, tree);
1175 /* Call the subdissector (defaults to data), otherwise. */
1176 http_payload_subdissector(next_tvb, tree,
1184 * Do *not* attempt at freeing the private data;
1185 * it may be in use by subdissectors.
1187 if (save_private_data)
1188 pinfo->private_data = save_private_data;
1190 * We've processed "datalen" bytes worth of data
1191 * (which may be no data at all); advance the
1192 * offset past whatever data we've processed.
1197 tap_queue_packet(http_tap, pinfo, stat_info);
1199 return offset - orig_offset;
1202 /* This can be used to dissect an HTTP request until such time
1203 * that a more complete dissector is written for that HTTP request.
1204 * This simple dissector only puts the request method, URI, and
1205 * protocol version into a sub-tree.
1208 basic_request_dissector(tvbuff_t *tvb, proto_tree *tree, int offset,
1209 const guchar *line, const guchar *lineend,
1210 http_conv_t *conv_data)
1212 const guchar *next_token;
1216 /* The first token is the method. */
1217 tokenlen = get_token_len(line, lineend, &next_token);
1220 proto_tree_add_item(tree, hf_http_request_method, tvb, offset, tokenlen,
1222 offset += next_token - line;
1225 /* The next token is the URI. */
1226 tokenlen = get_token_len(line, lineend, &next_token);
1230 /* Save the request URI for various later uses */
1231 request_uri = (gchar *)tvb_get_ephemeral_string(tvb, offset, tokenlen);
1232 stat_info->request_uri = ep_strdup(request_uri);
1233 conv_data->request_uri = se_strdup(request_uri);
1235 proto_tree_add_string(tree, hf_http_request_uri, tvb, offset, tokenlen,
1237 offset += next_token - line;
1240 /* Everything to the end of the line is the version. */
1241 tokenlen = lineend - line;
1244 proto_tree_add_item(tree, hf_http_version, tvb, offset, tokenlen,
1249 basic_response_dissector(tvbuff_t *tvb, proto_tree *tree, int offset,
1250 const guchar *line, const guchar *lineend,
1251 http_conv_t *conv_data _U_)
1253 const guchar *next_token;
1255 gchar response_chars[4];
1257 /* The first token is the version. */
1258 tokenlen = get_token_len(line, lineend, &next_token);
1261 proto_tree_add_item(tree, hf_http_version, tvb, offset, tokenlen,
1263 offset += next_token - line;
1266 /* The next token is the status code. */
1267 tokenlen = get_token_len(line, lineend, &next_token);
1270 memcpy(response_chars, line, 3);
1271 response_chars[3] = '\0';
1273 stat_info->response_code = conv_data->response_code =
1274 strtoul(response_chars, NULL, 10);
1276 proto_tree_add_uint(tree, hf_http_response_code, tvb, offset, 3,
1277 stat_info->response_code);
1281 * Dissect the http data chunks and add them to the tree.
1284 chunked_encoding_dissector(tvbuff_t **tvb_ptr, packet_info *pinfo,
1285 proto_tree *tree, int offset)
1287 guint8 *chunk_string = NULL;
1288 guint32 chunk_size = 0;
1289 gint chunk_offset = 0;
1290 guint32 datalen = 0;
1292 gint chunks_decoded = 0;
1293 tvbuff_t *tvb = NULL;
1294 tvbuff_t *new_tvb = NULL;
1295 gint chunked_data_size = 0;
1296 proto_tree *subtree = NULL;
1297 proto_item *ti = NULL;
1299 if (tvb_ptr == NULL || *tvb_ptr == NULL) {
1305 datalen = tvb_reported_length_remaining(tvb, offset);
1308 ti = proto_tree_add_text(tree, tvb, offset, datalen,
1309 "HTTP chunked response");
1310 subtree = proto_item_add_subtree(ti, ett_http_chunked_response);
1314 while (datalen != 0) {
1315 proto_item *chunk_ti = NULL;
1316 proto_tree *chunk_subtree = NULL;
1317 tvbuff_t *data_tvb = NULL;
1322 linelen = tvb_find_line_end(tvb, offset, -1, &chunk_offset, TRUE);
1325 /* Can't get the chunk size line */
1329 chunk_string = tvb_get_ephemeral_string(tvb, offset, linelen);
1331 if (chunk_string == NULL) {
1332 /* Can't get the chunk size line */
1336 c = (gchar*) chunk_string;
1339 * We don't care about the extensions.
1341 if ((c = strchr(c, ';'))) {
1345 chunk_size = strtol((gchar*)chunk_string, NULL, 16);
1347 if (chunk_size > datalen) {
1349 * The chunk size is more than what's in the tvbuff,
1350 * so either the user hasn't enabled decoding, or all
1351 * of the segments weren't captured.
1353 chunk_size = datalen;
1356 else if (new_tvb == NULL) {
1357 new_tvb = tvb_new_composite();
1362 if (new_tvb != NULL && chunk_size != 0) {
1363 tvbuff_t *chunk_tvb = NULL;
1365 chunk_tvb = tvb_new_subset(tvb, chunk_offset,
1366 chunk_size, datalen);
1368 tvb_composite_append(new_tvb, chunk_tvb);
1373 chunked_data_size += chunk_size;
1375 raw_data = g_malloc(chunked_data_size);
1378 if (new_tvb != NULL) {
1379 raw_len = tvb_length_remaining(new_tvb, 0);
1380 tvb_memcpy(new_tvb, raw_data, 0, raw_len);
1385 tvb_memcpy(tvb, (guint8 *)(raw_data + raw_len),
1386 chunk_offset, chunk_size);
1388 /* Don't create a new tvb if we have a single chunk with
1389 * a size of zero (meaning it is the end of the chunks). */
1390 if(chunked_data_size > 0) {
1391 new_tvb = tvb_new_real_data(raw_data,
1392 chunked_data_size, chunked_data_size);
1393 tvb_set_free_cb(new_tvb, g_free);
1398 if(chunk_size == 0) {
1399 chunk_ti = proto_tree_add_text(subtree, tvb,
1401 chunk_offset - offset + chunk_size + 2,
1402 "End of chunked encoding");
1404 chunk_ti = proto_tree_add_text(subtree, tvb,
1406 chunk_offset - offset + chunk_size + 2,
1407 "Data chunk (%u octets)", chunk_size);
1410 chunk_subtree = proto_item_add_subtree(chunk_ti,
1411 ett_http_chunk_data);
1413 proto_tree_add_text(chunk_subtree, tvb, offset,
1414 chunk_offset - offset, "Chunk size: %u octets",
1417 data_tvb = tvb_new_subset(tvb, chunk_offset, chunk_size,
1422 * XXX - just use "proto_tree_add_text()"?
1423 * This means that, in TShark, you get
1424 * the entire chunk dumped out in hex,
1425 * in addition to whatever dissection is
1426 * done on the reassembled data.
1428 call_dissector(data_handle, data_tvb, pinfo,
1431 proto_tree_add_text(chunk_subtree, tvb, chunk_offset +
1432 chunk_size, 2, "Chunk boundary");
1436 offset = chunk_offset + chunk_size + 2;
1437 datalen = tvb_reported_length_remaining(tvb, offset);
1440 if (new_tvb != NULL) {
1442 /* Placeholder for the day that composite tvbuffer's will work.
1443 tvb_composite_finalize(new_tvb);
1444 / * tvb_set_reported_length(new_tvb, chunked_data_size); * /
1448 * XXX - Don't free this, since the tvbuffer that was passed
1449 * may be used if the data spans multiple frames and reassembly
1458 * We didn't create a new tvb, so don't allow sub dissectors
1459 * try to decode the non-existant entity body.
1461 chunks_decoded = -1;
1464 return chunks_decoded;
1469 http_payload_subdissector(tvbuff_t *next_tvb, proto_tree *tree,
1470 proto_tree *sub_tree, packet_info *pinfo,
1471 http_conv_t *conv_data)
1473 /* tree = the main protocol tree that the subdissector would be listed in
1474 * sub_tree = the http protocol tree
1477 struct tcpinfo *tcpinfo = pinfo->private_data;
1478 struct tcp_analysis *tcpd=NULL;
1479 gchar **strings; /* An array for splitting the request URI into hostname and port */
1482 /* Response code 200 means "OK" and strncmp() == 0 means the strings match exactly */
1483 if(conv_data->response_code == 200 &&
1484 conv_data->request_method &&
1485 strncmp(conv_data->request_method, "CONNECT", 7) == 0 &&
1486 conv_data->request_uri) {
1488 /* Call a subdissector to handle HTTP CONNECT's traffic */
1489 tcpd=get_tcp_conversation_data(pinfo);
1491 /* Grab the destination port number from the request URI to find the right subdissector */
1492 strings = g_strsplit(conv_data->request_uri, ":", 2);
1494 if(strings[0] != NULL && strings[1] != NULL) { /* The string was successfuly split in two */
1496 item = proto_tree_add_string(sub_tree, hf_http_proxy_connect_host,
1497 next_tvb, 0, 0, strings[0]);
1498 PROTO_ITEM_SET_GENERATED(item);
1500 item = proto_tree_add_uint(sub_tree, hf_http_proxy_connect_port,
1501 next_tvb, 0, 0, strtol(strings[1], NULL, 10) );
1502 PROTO_ITEM_SET_GENERATED(item);
1504 /* We're going to get stuck in a loop if we let dissect_tcp_payload call
1505 us, so call the data dissector instead for proxy connections to http ports. */
1506 dissect_as = (int)strtol(strings[1], NULL, 10); /* Convert string to a base-10 integer */
1508 if (value_is_in_range(http_tcp_range, dissect_as)) {
1509 call_dissector(data_handle, next_tvb, pinfo, tree);
1511 if (value_is_in_range(http_tcp_range, pinfo->destport))
1512 dissect_tcp_payload(next_tvb, pinfo, 0, tcpinfo->seq, /* 0 = offset */
1513 tcpinfo->nxtseq, pinfo->srcport, dissect_as, tree, tree, tcpd);
1515 dissect_tcp_payload(next_tvb, pinfo, 0, tcpinfo->seq, /* 0 = offset */
1516 tcpinfo->nxtseq, dissect_as, pinfo->destport, tree, tree, tcpd);
1520 g_strfreev(strings); /* Free the result of g_strsplit() above */
1523 /* Call the default data dissector */
1524 call_dissector(data_handle, next_tvb, pinfo, sub_tree);
1531 * XXX - this won't handle HTTP 0.9 replies, but they're all data
1535 is_http_request_or_reply(const gchar *data, int linelen, http_type_t *type,
1536 ReqRespDissector *reqresp_dissector,
1537 http_conv_t *conv_data)
1539 int isHttpRequestOrReply = FALSE;
1543 * From RFC 2774 - An HTTP Extension Framework
1545 * Support the command prefix that identifies the presence of
1546 * a "mandatory" header.
1548 if (linelen >= 2 && strncmp(data, "M-", 2) == 0) {
1555 * From draft-cohen-gena-client-01.txt, available from the uPnP forum:
1556 * NOTIFY, SUBSCRIBE, UNSUBSCRIBE
1558 * From draft-ietf-dasl-protocol-00.txt, a now vanished Microsoft draft:
1561 if (linelen >= 5 && strncmp(data, "HTTP/", 5) == 0) {
1562 *type = HTTP_RESPONSE;
1563 isHttpRequestOrReply = TRUE; /* response */
1564 if (reqresp_dissector)
1565 *reqresp_dissector = basic_response_dissector;
1567 const guchar * ptr = (const guchar *)data;
1570 /* Look for the space following the Method */
1571 while (index < linelen) {
1580 /* Check the methods that have same length */
1584 if (strncmp(data, "GET", index) == 0 ||
1585 strncmp(data, "PUT", index) == 0) {
1586 *type = HTTP_REQUEST;
1587 isHttpRequestOrReply = TRUE;
1589 else if (strncmp(data, "ICY", index) == 0) {
1590 *type = HTTP_RESPONSE;
1591 isHttpRequestOrReply = TRUE;
1596 if (strncmp(data, "COPY", index) == 0 ||
1597 strncmp(data, "HEAD", index) == 0 ||
1598 strncmp(data, "LOCK", index) == 0 ||
1599 strncmp(data, "MOVE", index) == 0 ||
1600 strncmp(data, "POLL", index) == 0 ||
1601 strncmp(data, "POST", index) == 0) {
1602 *type = HTTP_REQUEST;
1603 isHttpRequestOrReply = TRUE;
1608 if (strncmp(data, "BCOPY", index) == 0 ||
1609 strncmp(data, "BMOVE", index) == 0 ||
1610 strncmp(data, "MKCOL", index) == 0 ||
1611 strncmp(data, "TRACE", index) == 0 ||
1612 strncmp(data, "LABEL", index) == 0 || /* RFC 3253 8.2 */
1613 strncmp(data, "MERGE", index) == 0) { /* RFC 3253 11.2 */
1614 *type = HTTP_REQUEST;
1615 isHttpRequestOrReply = TRUE;
1620 if (strncmp(data, "DELETE", index) == 0 ||
1621 strncmp(data, "SEARCH", index) == 0 ||
1622 strncmp(data, "UNLOCK", index) == 0 ||
1623 strncmp(data, "REPORT", index) == 0 || /* RFC 3253 3.6 */
1624 strncmp(data, "UPDATE", index) == 0) { /* RFC 3253 7.1 */
1625 *type = HTTP_REQUEST;
1626 isHttpRequestOrReply = TRUE;
1628 else if (strncmp(data, "NOTIFY", index) == 0) {
1629 *type = HTTP_NOTIFICATION;
1630 isHttpRequestOrReply = TRUE;
1635 if (strncmp(data, "BDELETE", index) == 0 ||
1636 strncmp(data, "CONNECT", index) == 0 ||
1637 strncmp(data, "OPTIONS", index) == 0 ||
1638 strncmp(data, "CHECKIN", index) == 0) { /* RFC 3253 4.4, 9.4 */
1639 *type = HTTP_REQUEST;
1640 isHttpRequestOrReply = TRUE;
1645 if (strncmp(data, "PROPFIND", index) == 0 ||
1646 strncmp(data, "CHECKOUT", index) == 0 || /* RFC 3253 4.3, 9.3 */
1647 strncmp(data, "CCM_POST", index) == 0) {
1648 *type = HTTP_REQUEST;
1649 isHttpRequestOrReply = TRUE;
1654 if (strncmp(data, "SUBSCRIBE", index) == 0) {
1655 *type = HTTP_NOTIFICATION;
1656 isHttpRequestOrReply = TRUE;
1657 } else if (strncmp(data, "PROPPATCH", index) == 0 ||
1658 strncmp(data, "BPROPFIND", index) == 0) {
1659 *type = HTTP_REQUEST;
1660 isHttpRequestOrReply = TRUE;
1665 if (strncmp(data, "BPROPPATCH", index) == 0 ||
1666 strncmp(data, "UNCHECKOUT", index) == 0 || /* RFC 3253 4.5 */
1667 strncmp(data, "MKACTIVITY", index) == 0) { /* RFC 3253 13.5 */
1668 *type = HTTP_REQUEST;
1669 isHttpRequestOrReply = TRUE;
1674 if (strncmp(data, "MKWORKSPACE", index) == 0) { /* RFC 3253 6.3 */
1675 *type = HTTP_REQUEST;
1676 isHttpRequestOrReply = TRUE;
1677 } else if (strncmp(data, "UNSUBSCRIBE", index) == 0) {
1678 *type = HTTP_NOTIFICATION;
1679 isHttpRequestOrReply = TRUE;
1680 } else if (strncmp(data, "RPC_CONNECT", index) == 0) {
1681 *type = HTTP_REQUEST;
1682 isHttpRequestOrReply = TRUE;
1687 if (strncmp(data, "VERSION-CONTROL", index) == 0) { /* RFC 3253 3.5 */
1688 *type = HTTP_REQUEST;
1689 isHttpRequestOrReply = TRUE;
1694 if (strncmp(data, "BASELINE-CONTROL", index) == 0) { /* RFC 3253 12.6 */
1695 *type = HTTP_REQUEST;
1696 isHttpRequestOrReply = TRUE;
1704 if (isHttpRequestOrReply && reqresp_dissector) {
1705 *reqresp_dissector = basic_request_dissector;
1707 stat_info->request_method = ep_strndup(data, index+1);
1708 conv_data->request_method = se_strndup(data, index+1);
1715 return isHttpRequestOrReply;
1727 #define HDR_NO_SPECIAL 0
1728 #define HDR_AUTHORIZATION 1
1729 #define HDR_AUTHENTICATE 2
1730 #define HDR_CONTENT_TYPE 3
1731 #define HDR_CONTENT_LENGTH 4
1732 #define HDR_CONTENT_ENCODING 5
1733 #define HDR_TRANSFER_ENCODING 6
1736 static const header_info headers[] = {
1737 { "Authorization", &hf_http_authorization, HDR_AUTHORIZATION },
1738 { "Proxy-Authorization", &hf_http_proxy_authorization, HDR_AUTHORIZATION },
1739 { "Proxy-Authenticate", &hf_http_proxy_authenticate, HDR_AUTHENTICATE },
1740 { "WWW-Authenticate", &hf_http_www_authenticate, HDR_AUTHENTICATE },
1741 { "Content-Type", &hf_http_content_type, HDR_CONTENT_TYPE },
1742 { "Content-Length", &hf_http_content_length, HDR_CONTENT_LENGTH },
1743 { "Content-Encoding", &hf_http_content_encoding, HDR_CONTENT_ENCODING },
1744 { "Transfer-Encoding", &hf_http_transfer_encoding, HDR_TRANSFER_ENCODING },
1745 { "User-Agent", &hf_http_user_agent, HDR_NO_SPECIAL },
1746 { "Host", &hf_http_host, HDR_HOST },
1747 { "Connection", &hf_http_connection, HDR_NO_SPECIAL },
1748 { "Cookie", &hf_http_cookie, HDR_NO_SPECIAL },
1749 { "Accept", &hf_http_accept, HDR_NO_SPECIAL },
1750 { "Referer", &hf_http_referer, HDR_NO_SPECIAL },
1751 { "Accept-Language", &hf_http_accept_language, HDR_NO_SPECIAL },
1752 { "Accept-Encoding", &hf_http_accept_encoding, HDR_NO_SPECIAL },
1753 { "Date", &hf_http_date, HDR_NO_SPECIAL },
1754 { "Cache-Control", &hf_http_cache_control, HDR_NO_SPECIAL },
1755 { "Server", &hf_http_server, HDR_NO_SPECIAL },
1756 { "Location", &hf_http_location, HDR_NO_SPECIAL },
1757 { "Set-Cookie", &hf_http_set_cookie, HDR_NO_SPECIAL },
1758 { "Last-Modified", &hf_http_last_modified, HDR_NO_SPECIAL },
1759 { "X-Forwarded-For", &hf_http_x_forwarded_for, HDR_NO_SPECIAL },
1763 process_header(tvbuff_t *tvb, int offset, int next_offset,
1764 const guchar *line, int linelen, int colon_offset,
1765 packet_info *pinfo, proto_tree *tree, headers_t *eh_ptr,
1766 http_conv_t *conv_data)
1769 int line_end_offset;
1778 proto_item *hdr_item;
1781 len = next_offset - offset;
1782 line_end_offset = offset + linelen;
1783 header_len = colon_offset - offset;
1784 hf_index = find_header_hf_value(tvb, offset, header_len);
1786 if (hf_index == -1) {
1788 * Not a header we know anything about. Just put it into
1792 proto_tree_add_text(tree, tvb, offset, len,
1793 "%s", format_text(line, len));
1797 * Skip whitespace after the colon.
1799 value_offset = colon_offset + 1;
1800 while (value_offset < line_end_offset
1801 && ((c = line[value_offset - offset]) == ' ' || c == '\t'))
1807 value_len = line_end_offset - value_offset;
1808 value = ep_strndup(&line[value_offset - offset], value_len);
1811 * Add it to the protocol tree as a particular field,
1812 * but display the line as is.
1815 header_field_info *hfinfo;
1818 hfinfo = proto_registrar_get_nth(*headers[hf_index].hf);
1819 switch(hfinfo->type){
1828 tmp=strtol(value, NULL, 10);
1829 hdr_item = proto_tree_add_uint(tree, *headers[hf_index].hf, tvb, offset, len, tmp);
1832 hdr_item = proto_tree_add_string_format(tree,
1833 *headers[hf_index].hf, tvb, offset, len,
1834 value, "%s", format_text(line, len));
1840 * Do any special processing that particular headers
1843 switch (headers[hf_index].special) {
1845 case HDR_AUTHORIZATION:
1846 if (check_auth_ntlmssp(hdr_item, tvb, pinfo, value))
1847 break; /* dissected NTLMSSP */
1848 check_auth_basic(hdr_item, tvb, value);
1851 case HDR_AUTHENTICATE:
1852 check_auth_ntlmssp(hdr_item, tvb, pinfo, value);
1855 case HDR_CONTENT_TYPE:
1856 eh_ptr->content_type = (gchar*) ep_memdup((guint8*)value,value_len + 1);
1858 for (i = 0; i < value_len; i++) {
1860 if (c == ';' || isspace(c)) {
1862 * End of subtype - either
1863 * white space or a ";"
1864 * separating the subtype from
1871 * Map the character to lower case;
1872 * content types are case-insensitive.
1874 eh_ptr->content_type[i] = tolower(eh_ptr->content_type[i]);
1876 eh_ptr->content_type[i] = '\0';
1878 * Now find the start of the optional parameters;
1879 * skip the optional white space and the semicolon
1880 * if this has not been done before.
1883 while (i < value_len) {
1884 c = eh_ptr->content_type[i];
1885 if (c == ';' || isspace(c))
1886 /* Skip till start of parameters */
1892 eh_ptr->content_type_parameters = eh_ptr->content_type + i;
1894 eh_ptr->content_type_parameters = NULL;
1897 case HDR_CONTENT_LENGTH:
1898 eh_ptr->content_length = strtol(value, &p, 10);
1900 if (eh_ptr->content_length < 0 || p == value ||
1901 (*up != '\0' && !isspace(*up))) {
1903 * Content length not valid; pretend
1906 eh_ptr->have_content_length = FALSE;
1909 * We do have a valid content length.
1911 eh_ptr->have_content_length = TRUE;
1915 case HDR_CONTENT_ENCODING:
1916 eh_ptr->content_encoding = ep_strndup(value, value_len);
1919 case HDR_TRANSFER_ENCODING:
1920 eh_ptr->transfer_encoding = ep_strndup(value, value_len);
1924 stat_info->http_host = ep_strndup(value, value_len);
1925 conv_data->http_host = se_strndup(value, value_len);
1932 /* Returns index of header tag in headers */
1934 find_header_hf_value(tvbuff_t *tvb, int offset, guint header_len)
1938 for (i = 0; i < array_length(headers); i++) {
1939 if (header_len == strlen(headers[i].name) &&
1940 tvb_strncaseeql(tvb, offset,
1941 headers[i].name, header_len) == 0)
1949 * Dissect Microsoft's abomination called NTLMSSP over HTTP.
1952 check_auth_ntlmssp(proto_item *hdr_item, tvbuff_t *tvb, packet_info *pinfo,
1955 static const char *ntlm_headers[] = {
1960 const char **header;
1962 proto_tree *hdr_tree;
1965 * Check for NTLM credentials and challenge; those can
1966 * occur with WWW-Authenticate.
1968 for (header = &ntlm_headers[0]; *header != NULL; header++) {
1969 hdrlen = strlen(*header);
1970 if (strncmp(value, *header, hdrlen) == 0) {
1971 if (hdr_item != NULL) {
1972 hdr_tree = proto_item_add_subtree(hdr_item,
1977 dissect_http_ntlmssp(tvb, pinfo, hdr_tree, value);
1985 * Dissect HTTP Basic authorization.
1988 check_auth_basic(proto_item *hdr_item, tvbuff_t *tvb, gchar *value)
1990 static const char *basic_headers[] = {
1994 const char **header;
1996 proto_tree *hdr_tree;
1999 for (header = &basic_headers[0]; *header != NULL; header++) {
2000 hdrlen = strlen(*header);
2001 if (strncmp(value, *header, hdrlen) == 0) {
2002 if (hdr_item != NULL) {
2003 hdr_tree = proto_item_add_subtree(hdr_item,
2009 len = epan_base64_decode(value);
2011 proto_tree_add_string(hdr_tree, hf_http_basic, tvb,
2021 dissect_http(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2026 while (tvb_reported_length_remaining(tvb, offset) != 0) {
2027 len = dissect_http_message(tvb, offset, pinfo, tree);
2033 * OK, we've set the Protocol and Info columns for the
2034 * first HTTP message; make the columns non-writable,
2035 * so that we don't change it for subsequent HTTP messages.
2037 col_set_writable(pinfo->cinfo, FALSE);
2042 dissect_http_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2044 dissect_http_message(tvb, 0, pinfo, tree);
2047 static void range_delete_http_tcp_callback(guint32 port) {
2048 dissector_delete("tcp.port", port, http_handle);
2051 static void range_add_http_tcp_callback(guint32 port) {
2052 dissector_add("tcp.port", port, http_handle);
2055 static void range_delete_http_ssl_callback(guint32 port) {
2056 ssl_dissector_delete(port, "http", TRUE);
2059 static void range_add_http_ssl_callback(guint32 port) {
2060 ssl_dissector_add(port, "http", TRUE);
2063 static void reinit_http(void) {
2064 range_foreach(http_tcp_range, range_delete_http_tcp_callback);
2065 g_free(http_tcp_range);
2066 http_tcp_range = range_copy(global_http_tcp_range);
2067 range_foreach(http_tcp_range, range_add_http_tcp_callback);
2069 range_foreach(http_ssl_range, range_delete_http_ssl_callback);
2070 g_free(http_ssl_range);
2071 http_ssl_range = range_copy(global_http_ssl_range);
2072 range_foreach(http_ssl_range, range_add_http_ssl_callback);
2076 proto_register_http(void)
2078 static hf_register_info hf[] = {
2079 { &hf_http_notification,
2080 { "Notification", "http.notification",
2081 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2082 "TRUE if HTTP notification", HFILL }},
2083 { &hf_http_response,
2084 { "Response", "http.response",
2085 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2086 "TRUE if HTTP response", HFILL }},
2088 { "Request", "http.request",
2089 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2090 "TRUE if HTTP request", HFILL }},
2092 { "Credentials", "http.authbasic",
2093 FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
2094 { &hf_http_request_method,
2095 { "Request Method", "http.request.method",
2096 FT_STRING, BASE_NONE, NULL, 0x0,
2097 "HTTP Request Method", HFILL }},
2098 { &hf_http_request_uri,
2099 { "Request URI", "http.request.uri",
2100 FT_STRING, BASE_NONE, NULL, 0x0,
2101 "HTTP Request-URI", HFILL }},
2103 { "Request Version", "http.request.version",
2104 FT_STRING, BASE_NONE, NULL, 0x0,
2105 "HTTP Request HTTP-Version", HFILL }},
2106 { &hf_http_response_code,
2107 { "Response Code", "http.response.code",
2108 FT_UINT16, BASE_DEC, NULL, 0x0,
2109 "HTTP Response Code", HFILL }},
2110 { &hf_http_authorization,
2111 { "Authorization", "http.authorization",
2112 FT_STRING, BASE_NONE, NULL, 0x0,
2113 "HTTP Authorization header", HFILL }},
2114 { &hf_http_proxy_authenticate,
2115 { "Proxy-Authenticate", "http.proxy_authenticate",
2116 FT_STRING, BASE_NONE, NULL, 0x0,
2117 "HTTP Proxy-Authenticate header", HFILL }},
2118 { &hf_http_proxy_authorization,
2119 { "Proxy-Authorization", "http.proxy_authorization",
2120 FT_STRING, BASE_NONE, NULL, 0x0,
2121 "HTTP Proxy-Authorization header", HFILL }},
2122 { &hf_http_proxy_connect_host,
2123 { "Proxy-Connect-Hostname", "http.proxy_connect_host",
2124 FT_STRING, BASE_NONE, NULL, 0x0,
2125 "HTTP Proxy Connect Hostname", HFILL }},
2126 { &hf_http_proxy_connect_port,
2127 { "Proxy-Connect-Port", "http.proxy_connect_port",
2128 FT_UINT16, BASE_DEC, NULL, 0x0,
2129 "HTTP Proxy Connect Port", HFILL }},
2130 { &hf_http_www_authenticate,
2131 { "WWW-Authenticate", "http.www_authenticate",
2132 FT_STRING, BASE_NONE, NULL, 0x0,
2133 "HTTP WWW-Authenticate header", HFILL }},
2134 { &hf_http_content_type,
2135 { "Content-Type", "http.content_type",
2136 FT_STRING, BASE_NONE, NULL, 0x0,
2137 "HTTP Content-Type header", HFILL }},
2138 { &hf_http_content_length,
2139 { "Content-Length", "http.content_length",
2140 FT_UINT32, BASE_DEC, NULL, 0x0,
2141 "HTTP Content-Length header", HFILL }},
2142 { &hf_http_content_encoding,
2143 { "Content-Encoding", "http.content_encoding",
2144 FT_STRING, BASE_NONE, NULL, 0x0,
2145 "HTTP Content-Encoding header", HFILL }},
2146 { &hf_http_transfer_encoding,
2147 { "Transfer-Encoding", "http.transfer_encoding",
2148 FT_STRING, BASE_NONE, NULL, 0x0,
2149 "HTTP Transfer-Encoding header", HFILL }},
2150 { &hf_http_user_agent,
2151 { "User-Agent", "http.user_agent",
2152 FT_STRING, BASE_NONE, NULL, 0x0,
2153 "HTTP User-Agent header", HFILL }},
2155 { "Host", "http.host",
2156 FT_STRING, BASE_NONE, NULL, 0x0,
2157 "HTTP Host", HFILL }},
2158 { &hf_http_connection,
2159 { "Connection", "http.connection",
2160 FT_STRING, BASE_NONE, NULL, 0x0,
2161 "HTTP Connection", HFILL }},
2163 { "Cookie", "http.cookie",
2164 FT_STRING, BASE_NONE, NULL, 0x0,
2165 "HTTP Cookie", HFILL }},
2167 { "Accept", "http.accept",
2168 FT_STRING, BASE_NONE, NULL, 0x0,
2169 "HTTP Accept", HFILL }},
2171 { "Referer", "http.referer",
2172 FT_STRING, BASE_NONE, NULL, 0x0,
2173 "HTTP Referer", HFILL }},
2174 { &hf_http_accept_language,
2175 { "Accept-Language", "http.accept_language",
2176 FT_STRING, BASE_NONE, NULL, 0x0,
2177 "HTTP Accept Language", HFILL }},
2178 { &hf_http_accept_encoding,
2179 { "Accept Encoding", "http.accept_encoding",
2180 FT_STRING, BASE_NONE, NULL, 0x0,
2181 "HTTP Accept Encoding", HFILL }},
2183 { "Date", "http.date",
2184 FT_STRING, BASE_NONE, NULL, 0x0,
2185 "HTTP Date", HFILL }},
2186 { &hf_http_cache_control,
2187 { "Cache-Control", "http.cache_control",
2188 FT_STRING, BASE_NONE, NULL, 0x0,
2189 "HTTP Cache Control", HFILL }},
2191 { "Server", "http.server",
2192 FT_STRING, BASE_NONE, NULL, 0x0,
2193 "HTTP Server", HFILL }},
2194 { &hf_http_location,
2195 { "Location", "http.location",
2196 FT_STRING, BASE_NONE, NULL, 0x0,
2197 "HTTP Location", HFILL }},
2198 { &hf_http_set_cookie,
2199 { "Set-Cookie", "http.set_cookie",
2200 FT_STRING, BASE_NONE, NULL, 0x0,
2201 "HTTP Set Cookie", HFILL }},
2202 { &hf_http_last_modified,
2203 { "Last-Modified", "http.last_modified",
2204 FT_STRING, BASE_NONE, NULL, 0x0,
2205 "HTTP Last Modified", HFILL }},
2206 { &hf_http_x_forwarded_for,
2207 { "X-Forwarded-For", "http.x_forwarded_for",
2208 FT_STRING, BASE_NONE, NULL, 0x0,
2209 "HTTP X-Forwarded-For", HFILL }},
2211 static gint *ett[] = {
2215 &ett_http_chunked_response,
2216 &ett_http_chunk_data,
2217 &ett_http_encoded_entity,
2219 module_t *http_module;
2221 proto_http = proto_register_protocol("Hypertext Transfer Protocol",
2223 proto_register_field_array(proto_http, hf, array_length(hf));
2224 proto_register_subtree_array(ett, array_length(ett));
2225 register_dissector("http", dissect_http, proto_http);
2226 http_module = prefs_register_protocol(proto_http, reinit_http);
2227 prefs_register_bool_preference(http_module, "desegment_headers",
2228 "Reassemble HTTP headers spanning multiple TCP segments",
2229 "Whether the HTTP dissector should reassemble headers "
2230 "of a request spanning multiple TCP segments. "
2231 "To use this option, you must also enable "
2232 "\"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
2233 &http_desegment_headers);
2234 prefs_register_bool_preference(http_module, "desegment_body",
2235 "Reassemble HTTP bodies spanning multiple TCP segments",
2236 "Whether the HTTP dissector should use the "
2237 "\"Content-length:\" value, if present, to reassemble "
2238 "the body of a request spanning multiple TCP segments, "
2239 "and reassemble chunked data spanning multiple TCP segments. "
2240 "To use this option, you must also enable "
2241 "\"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
2242 &http_desegment_body);
2243 prefs_register_bool_preference(http_module, "dechunk_body",
2244 "Reassemble chunked transfer-coded bodies",
2245 "Whether to reassemble bodies of entities that are transfered "
2246 "using the \"Transfer-Encoding: chunked\" method",
2247 &http_dechunk_body);
2249 prefs_register_bool_preference(http_module, "decompress_body",
2250 "Uncompress entity bodies",
2251 "Whether to uncompress entity bodies that are compressed "
2252 "using \"Content-Encoding: \"",
2253 &http_decompress_body);
2255 prefs_register_obsolete_preference(http_module, "tcp_alternate_port");
2257 range_convert_str(&global_http_tcp_range, TCP_DEFAULT_RANGE, 65535);
2258 http_tcp_range = range_empty();
2259 prefs_register_range_preference(http_module, "tcp.port", "TCP Ports",
2261 &global_http_tcp_range, 65535);
2263 range_convert_str(&global_http_ssl_range, SSL_DEFAULT_RANGE, 65535);
2264 http_ssl_range = range_empty();
2265 prefs_register_range_preference(http_module, "ssl.port", "SSL/TLS Ports",
2266 "SSL/TLS Ports range",
2267 &global_http_ssl_range, 65535);
2269 http_handle = create_dissector_handle(dissect_http, proto_http);
2272 * Dissectors shouldn't register themselves in this table;
2273 * instead, they should call "http_dissector_add()", and
2274 * we'll register the port number they specify as a port
2275 * for HTTP, and register them in our subdissector table.
2277 * This only works for protocols such as IPP that run over
2278 * HTTP on a specific non-HTTP port.
2280 port_subdissector_table = register_dissector_table("http.port",
2281 "TCP port for protocols using HTTP", FT_UINT16, BASE_DEC);
2284 * Dissectors can register themselves in this table.
2285 * It's just "media_type", not "http.content_type", because
2286 * it's an Internet media type, usable by other protocols as well.
2288 media_type_subdissector_table =
2289 register_dissector_table("media_type",
2290 "Internet media type", FT_STRING, BASE_NONE);
2293 * Heuristic dissectors SHOULD register themselves in
2294 * this table using the standard heur_dissector_add()
2297 register_heur_dissector_list("http", &heur_subdissector_list);
2300 * Register for tapping
2302 http_tap = register_tap("http"); /* HTTP statistics tap */
2303 http_eo_tap = register_tap("http_eo"); /* HTTP Export Object tap */
2307 * Called by dissectors for protocols that run atop HTTP/TCP.
2310 http_dissector_add(guint32 port, dissector_handle_t handle)
2313 * Register ourselves as the handler for that port number
2316 dissector_add("tcp.port", port, http_handle);
2319 * And register them in *our* table for that port.
2321 dissector_add("http.port", port, handle);
2325 proto_reg_handoff_http(void)
2327 dissector_handle_t http_udp_handle;
2329 data_handle = find_dissector("data");
2330 media_handle = find_dissector("media");
2333 * XXX - is there anything to dissect in the body of an SSDP
2334 * request or reply? I.e., should there be an SSDP dissector?
2336 http_udp_handle = create_dissector_handle(dissect_http_udp, proto_http);
2337 dissector_add("udp.port", UDP_PORT_SSDP, http_udp_handle);
2339 ntlmssp_handle = find_dissector("ntlmssp");
2340 gssapi_handle = find_dissector("gssapi");
2342 stats_tree_register("http","http","HTTP/Packet Counter", http_stats_tree_packet, http_stats_tree_init, NULL );
2343 stats_tree_register("http","http_req","HTTP/Requests", http_req_stats_tree_packet, http_req_stats_tree_init, NULL );
2344 stats_tree_register("http","http_srv","HTTP/Load Distribution",http_reqs_stats_tree_packet,http_reqs_stats_tree_init, NULL );
2349 * Content-Type: message/http
2352 static gint proto_message_http = -1;
2353 static gint ett_message_http = -1;
2354 static dissector_handle_t message_http_handle;
2357 dissect_message_http(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2359 proto_tree *subtree;
2361 gint offset = 0, next_offset;
2364 if (check_col(pinfo->cinfo, COL_INFO))
2365 col_append_str(pinfo->cinfo, COL_INFO, " (message/http)");
2367 ti = proto_tree_add_item(tree, proto_message_http,
2369 subtree = proto_item_add_subtree(ti, ett_message_http);
2370 while (tvb_reported_length_remaining(tvb, offset) != 0) {
2371 len = tvb_find_line_end(tvb, offset,
2372 tvb_ensure_length_remaining(tvb, offset),
2373 &next_offset, FALSE);
2376 proto_tree_add_text(subtree, tvb, offset, next_offset - offset,
2377 "%s", tvb_format_text(tvb, offset, len));
2378 offset = next_offset;
2384 proto_register_message_http(void)
2386 static gint *ett[] = {
2390 proto_message_http = proto_register_protocol(
2391 "Media Type: message/http",
2395 proto_register_subtree_array(ett, array_length(ett));
2399 proto_reg_handoff_message_http(void)
2401 message_http_handle = create_dissector_handle(dissect_message_http,
2402 proto_message_http);
2404 dissector_add_string("media_type", "message/http", message_http_handle);