2 * Routines for HTTP packet disassembly
4 * Guy Harris <guy@alum.mit.edu>
6 * Copyright 2002, Tim Potter <tpot@samba.org>
7 * Copyright 1999, Andrew Tridgell <tridge@samba.org>
9 * $Id: packet-http.c,v 1.95 2004/02/21 01:31:56 guy Exp $
11 * Ethereal - Network traffic analyzer
12 * By Gerald Combs <gerald@ethereal.com>
13 * Copyright 1998 Gerald Combs
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
38 #include <epan/packet.h>
39 #include <epan/strutil.h>
42 #include "req_resp_hdrs.h"
43 #include "packet-http.h"
46 typedef enum _http_type {
55 static int http_tap = -1;
57 static int proto_http = -1;
58 static int hf_http_notification = -1;
59 static int hf_http_response = -1;
60 static int hf_http_request = -1;
61 static int hf_http_basic = -1;
62 static int hf_http_request_method = -1;
63 static int hf_http_response_code = -1;
64 static int hf_http_authorization = -1;
65 static int hf_http_proxy_authenticate = -1;
66 static int hf_http_proxy_authorization = -1;
67 static int hf_http_www_authenticate = -1;
68 static int hf_http_content_type = -1;
69 static int hf_http_content_length = -1;
70 static int hf_http_content_encoding = -1;
71 static int hf_http_transfer_encoding = -1;
73 static gint ett_http = -1;
74 static gint ett_http_ntlmssp = -1;
75 static gint ett_http_request = -1;
77 static dissector_handle_t data_handle;
78 static dissector_handle_t http_handle;
81 * desegmentation of HTTP headers
82 * (when we are over TCP or another protocol providing the desegmentation API)
84 static gboolean http_desegment_headers = FALSE;
87 * desegmentation of HTTP bodies
88 * (when we are over TCP or another protocol providing the desegmentation API)
89 * TODO let the user filter on content-type the bodies he wants desegmented
91 static gboolean http_desegment_body = FALSE;
93 #define TCP_PORT_HTTP 80
94 #define TCP_PORT_PROXY_HTTP 3128
95 #define TCP_PORT_PROXY_ADMIN_HTTP 3132
96 #define TCP_ALT_PORT_HTTP 8080
99 * SSDP is implemented atop HTTP (yes, it really *does* run over UDP).
101 #define TCP_PORT_SSDP 1900
102 #define UDP_PORT_SSDP 1900
105 * Protocols implemented atop HTTP.
108 PROTO_HTTP, /* just HTTP */
109 PROTO_SSDP /* Simple Service Discovery Protocol */
112 typedef void (*RequestDissector)(tvbuff_t*, proto_tree*, int);
115 * Structure holding information from headers needed by main
116 * HTTP dissector code.
120 char *content_type_parameters;
121 long content_length; /* XXX - make it 64-bit? */
122 char *content_encoding;
123 char *transfer_encoding;
126 static int is_http_request_or_reply(const gchar *data, int linelen, http_type_t *type,
127 RequestDissector *req_dissector, int *req_strlen);
128 static void process_header(tvbuff_t *tvb, int offset, int next_offset,
129 const guchar *line, int linelen, int colon_offset, packet_info *pinfo,
130 proto_tree *tree, headers_t *eh_ptr);
131 static gint find_header_hf_value(tvbuff_t *tvb, int offset, guint header_len);
132 static gboolean check_auth_ntlmssp(proto_item *hdr_item, tvbuff_t *tvb,
133 packet_info *pinfo, gchar *value);
134 static gboolean check_auth_basic(proto_item *hdr_item, tvbuff_t *tvb,
137 static dissector_table_t port_subdissector_table;
138 static dissector_table_t media_type_subdissector_table;
139 static heur_dissector_list_t heur_subdissector_list;
141 static dissector_handle_t ntlmssp_handle=NULL;
144 /* Return a tvb that contains the binary representation of a base64
148 base64_to_tvb(const char *base64)
151 char *data = g_strdup(base64);
154 len = base64_decode(data);
155 tvb = tvb_new_real_data((const guint8 *)data, len, len);
157 tvb_set_free_cb(tvb, g_free);
163 dissect_http_ntlmssp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
166 tvbuff_t *ntlmssp_tvb;
168 ntlmssp_tvb = base64_to_tvb(line);
169 tvb_set_child_real_data_tvbuff(tvb, ntlmssp_tvb);
170 add_new_data_source(pinfo, ntlmssp_tvb, "NTLMSSP Data");
172 call_dissector(ntlmssp_handle, ntlmssp_tvb, pinfo, tree);
176 cleanup_headers(void *arg)
178 headers_t *headers = arg;
180 if (headers->content_type != NULL)
181 g_free(headers->content_type);
183 * The content_type_parameters field actually points into the
184 * content_type headers, so don't free it, as that'll double-free
187 if (headers->content_encoding != NULL)
188 g_free(headers->content_encoding);
189 if (headers->transfer_encoding != NULL)
190 g_free(headers->transfer_encoding);
194 * TODO: remove this ugly global variable.
196 * XXX - we leak "http_info_value_t" structures.
197 * XXX - this gets overwritten if there's more than one HTTP request or
198 * reply in the tvbuff.
200 static http_info_value_t *stat_info;
203 dissect_http_message(tvbuff_t *tvb, int offset, packet_info *pinfo,
208 proto_tree *http_tree = NULL;
209 proto_item *ti = NULL;
212 const guchar *linep, *lineend;
214 int first_linelen, linelen;
215 gboolean is_request_or_reply;
216 gboolean saw_req_resp_or_header;
218 http_type_t http_type;
219 proto_item *hdr_item;
220 RequestDissector req_dissector;
222 proto_tree *req_tree;
226 int reported_datalen;
227 dissector_handle_t handle;
231 * Is this a request or response?
233 * Note that "tvb_find_line_end()" will return a value that
234 * is not longer than what's in the buffer, so the
235 * "tvb_get_ptr()" call won't throw an exception.
237 first_linelen = tvb_find_line_end(tvb, offset,
238 tvb_ensure_length_remaining(tvb, offset), &next_offset,
241 * Is the first line a request or response?
243 line = tvb_get_ptr(tvb, offset, first_linelen);
244 http_type = HTTP_OTHERS; /* type not known yet */
245 is_request_or_reply = is_http_request_or_reply((const gchar *)line,
246 first_linelen, &http_type, NULL, NULL);
247 if (is_request_or_reply) {
249 * Yes, it's a request or response.
250 * Do header desegmentation if we've been told to,
251 * and do body desegmentation if we've been told to and
252 * we find a Content-Length header.
254 if (!req_resp_hdrs_do_reassembly(tvb, pinfo,
255 http_desegment_headers, http_desegment_body)) {
257 * More data needed for desegmentation.
263 stat_info = g_malloc(sizeof(http_info_value_t));
264 stat_info->response_code = 0;
265 stat_info->request_method = NULL;
267 switch (pinfo->match_port) {
269 case TCP_PORT_SSDP: /* TCP_PORT_SSDP = UDP_PORT_SSDP */
280 if (check_col(pinfo->cinfo, COL_PROTOCOL))
281 col_set_str(pinfo->cinfo, COL_PROTOCOL, proto_tag);
282 if (check_col(pinfo->cinfo, COL_INFO)) {
284 * Put the first line from the buffer into the summary
285 * if it's an HTTP request or reply (but leave out the
287 * Otherwise, just call it a continuation.
289 * Note that "tvb_find_line_end()" will return a value that
290 * is not longer than what's in the buffer, so the
291 * "tvb_get_ptr()" call won't throw an exception.
293 line = tvb_get_ptr(tvb, offset, first_linelen);
294 if (is_request_or_reply)
295 col_add_str(pinfo->cinfo, COL_INFO,
296 format_text(line, first_linelen));
298 col_set_str(pinfo->cinfo, COL_INFO, "Continuation");
301 orig_offset = offset;
303 ti = proto_tree_add_item(tree, proto_http, tvb, offset, -1,
305 http_tree = proto_item_add_subtree(ti, ett_http);
309 * Process the packet data, a line at a time.
311 http_type = HTTP_OTHERS; /* type not known yet */
312 headers.content_type = NULL; /* content type not known yet */
313 headers.content_type_parameters = NULL; /* content type parameters too */
314 headers.content_length = -1; /* content length not known yet */
315 headers.content_encoding = NULL; /* content encoding not known yet */
316 headers.transfer_encoding = NULL; /* transfer encoding not known yet */
317 saw_req_resp_or_header = FALSE; /* haven't seen anything yet */
318 CLEANUP_PUSH(cleanup_headers, &headers);
319 while (tvb_reported_length_remaining(tvb, offset) != 0) {
321 * Find the end of the line.
323 linelen = tvb_find_line_end(tvb, offset,
324 tvb_ensure_length_remaining(tvb, offset), &next_offset,
330 * Get a buffer that refers to the line.
332 line = tvb_get_ptr(tvb, offset, linelen);
333 lineend = line + linelen;
337 * OK, does it look like an HTTP request or response?
339 req_dissector = NULL;
340 is_request_or_reply = is_http_request_or_reply((const gchar *)line,
341 linelen, &http_type, &req_dissector, &req_strlen);
342 if (is_request_or_reply)
346 * No. Does it look like a blank line (as would appear
347 * at the end of an HTTP request)?
350 goto is_http; /* Yes. */
353 * No. Does it look like a header?
356 colon_offset = offset;
357 while (linep < lineend) {
361 * This must be a CHAR to be part of a token; that
362 * means it must be ASCII.
365 break; /* not ASCII, thus not a CHAR */
368 * This mustn't be a CTL to be part of a token;
369 * that means it must be printable.
371 * XXX - what about leading LWS on continuation
375 break; /* not printable, not a header */
378 * This mustn't be a SEP to be part of a token;
379 * a ':' ends the token, everything else is an
380 * indication that this isn't a header.
402 * It's a separator, so it's not part of a
403 * token, so it's not a field name for the
404 * beginning of a header.
406 * (We don't have to check for HT; that's
407 * already been ruled out by "isprint()".)
413 * This ends the token; we consider this
425 * We haven't seen the colon, but everything else looks
426 * OK for a header line.
428 * If we've already seen an HTTP request or response
429 * line, or a header line, and we're at the end of
430 * the tvbuff, we assume this is an incomplete header
431 * line. (We quit this loop after seeing a blank line,
432 * so if we've seen a request or response line, or a
433 * header line, this is probably more of the request
434 * or response we're presumably seeing. There is some
435 * risk of false positives, but the same applies for
436 * full request or response lines or header lines,
437 * although that's less likely.)
439 * We throw an exception in that case, by checking for
440 * the existence of the next byte after the last one
441 * in the line. If it exists, "tvb_ensure_bytes_exist()"
442 * throws no exception, and we fall through to the
443 * "not HTTP" case. If it doesn't exist,
444 * "tvb_ensure_bytes_exist()" will throw the appropriate
447 if (saw_req_resp_or_header)
448 tvb_ensure_bytes_exist(tvb, offset, linelen + 1);
452 * We don't consider this part of an HTTP request or
453 * reply, so we don't display it.
454 * (Yeah, that means we don't display, say, a text/http
455 * page, but you can get that from the data pane.)
465 * This is a blank line, which means that
466 * whatever follows it isn't part of this
469 proto_tree_add_text(http_tree, tvb, offset,
470 next_offset - offset, "%s",
471 tvb_format_text(tvb, offset, next_offset - offset));
472 offset = next_offset;
477 * Not a blank line - either a request, a reply, or a header
480 saw_req_resp_or_header = TRUE;
481 if (is_request_or_reply) {
483 hdr_item = proto_tree_add_text(http_tree, tvb,
484 offset, next_offset - offset, "%s",
485 tvb_format_text(tvb, offset,
486 next_offset - offset));
488 req_tree = proto_item_add_subtree(
489 hdr_item, ett_http_request);
490 req_dissector(tvb, req_tree,
498 process_header(tvb, offset, next_offset, line, linelen,
499 colon_offset, pinfo, http_tree, &headers);
501 offset = next_offset;
507 case HTTP_NOTIFICATION:
508 proto_tree_add_boolean_hidden(http_tree,
509 hf_http_notification, tvb, 0, 0, 1);
513 proto_tree_add_boolean_hidden(http_tree,
514 hf_http_response, tvb, 0, 0, 1);
518 proto_tree_add_boolean_hidden(http_tree,
519 hf_http_request, tvb, 0, 0, 1);
529 * If a content length was supplied, the amount of data to be
530 * processed as HTTP payload is the minimum of the content
531 * length and the amount of data remaining in the frame.
533 * If no content length was supplied (or if a bad content length
534 * was supplied), the amount of data to be processed is the amount
535 * of data remaining in the frame.
537 * If there was no Content-Length entity header, we should
538 * accumulate all data until the end of the connection.
539 * That'd require that the TCP dissector call subdissectors
540 * for all frames with FIN, even if they contain no data,
541 * which would require subdissectors to deal intelligently
542 * with empty segments.
544 * Acccording to RFC 2616, however, 1xx responses, 204 responses,
545 * and 304 responses MUST NOT include a message body; if no
546 * content length is specified for them, we don't attempt to
549 * XXX - it says the same about responses to HEAD requests;
550 * unless there's a way to determine from the response
551 * whether it's a response to a HEAD request, we have to
552 * keep information about the request and associate that with
553 * the response in order to handle that.
555 datalen = tvb_length_remaining(tvb, offset);
556 if (headers.content_length != -1) {
557 if (datalen > headers.content_length)
558 datalen = headers.content_length;
561 * XXX - limit the reported length in the tvbuff we'll
562 * hand to a subdissector to be no greater than the
565 * We really need both unreassembled and "how long it'd
566 * be if it were reassembled" lengths for tvbuffs, so
567 * that we throw the appropriate exceptions for
568 * "not enough data captured" (running past the length),
569 * "packet needed reassembly" (within the length but
570 * running past the unreassembled length), and
571 * "packet is malformed" (running past the reassembled
574 reported_datalen = tvb_reported_length_remaining(tvb, offset);
575 if (reported_datalen > headers.content_length)
576 reported_datalen = headers.content_length;
578 if ((stat_info->response_code/100) == 1 ||
579 stat_info->response_code == 204 ||
580 stat_info->response_code == 304)
581 datalen = 0; /* no content! */
583 reported_datalen = -1;
588 * There's stuff left over; process it.
591 void *save_private_data = NULL;
594 * Create a tvbuff for the payload.
596 * The amount of data to be processed that's
597 * available in the tvbuff is "datalen", which
598 * is the minimum of the amount of data left in
599 * the tvbuff and any specified content length.
601 * The amount of data to be processed that's in
602 * this frame, regardless of whether it was
603 * captured or not, is "reported_datalen",
604 * which, if no content length was specified,
605 * is -1, i.e. "to the end of the frame.
607 next_tvb = tvb_new_subset(tvb, offset, datalen,
611 * Handle content encodings other than "identity" (which
612 * shouldn't appear in a Content-Encoding header, but
613 * we handle it in any case).
615 if (headers.content_encoding != NULL &&
616 strcasecmp(headers.content_encoding, "identity") != 0) {
618 * We currently can't handle, for example, "gzip",
619 * "compress", or "deflate"; just handle them as
622 call_dissector(data_handle, next_tvb, pinfo,
628 * Handle transfer encodings other than "identity".
630 if (headers.transfer_encoding != NULL &&
631 strcasecmp(headers.transfer_encoding, "identity") != 0) {
633 * We currently can't handle, for example, "chunked",
634 * "gzip", "compress", or "deflate"; just handle them
637 call_dissector(data_handle, next_tvb, pinfo,
643 * Do subdissector checks.
645 * First, check whether some subdissector asked that they
646 * be called if something was on some particular port.
648 handle = dissector_get_port_handle(port_subdissector_table,
650 if (handle == NULL && headers.content_type != NULL) {
652 * We didn't find any subdissector that
653 * registered for the port, and we have a
654 * Content-Type value. Is there any subdissector
655 * for that content type?
657 save_private_data = pinfo->private_data;
658 if (headers.content_type_parameters)
659 pinfo->private_data = g_strdup(headers.content_type_parameters);
661 pinfo->private_data = NULL;
663 * Calling the string handle for the media type
664 * dissector table will set pinfo->match_string
665 * to headers.content_type for us.
667 pinfo->match_string = headers.content_type;
668 handle = dissector_get_string_handle(
669 media_type_subdissector_table,
670 headers.content_type);
672 if (handle != NULL) {
674 * We have a subdissector - call it.
676 dissected = call_dissector(handle, next_tvb, pinfo,
680 * We don't have a subdissector - try the heuristic
683 dissected = dissector_try_heuristic(
684 heur_subdissector_list, next_tvb, pinfo, tree);
688 * The subdissector dissected the body.
689 * Fix up the top-level item so that it doesn't
690 * include the stuff for that protocol.
693 proto_item_set_len(ti, offset);
695 call_dissector(data_handle, next_tvb, pinfo,
701 * Do *not* attempt at freeing the private data;
702 * it may be in use by subdissectors.
704 if (save_private_data)
705 pinfo->private_data = save_private_data;
707 * We've processed "datalen" bytes worth of data
708 * (which may be no data at all); advance the
709 * offset past whatever data we've processed.
715 * Clean up any header stuff, by calling and popping the cleanup
718 CLEANUP_CALL_AND_POP;
720 tap_queue_packet(http_tap, pinfo, stat_info);
722 return offset - orig_offset;
725 /* This can be used to dissect an HTTP request until such time
726 * that a more complete dissector is written for that HTTP request.
727 * This simple dissectory only puts http.request_method into a sub-tree.
730 basic_request_dissector(tvbuff_t *tvb, proto_tree *tree, int req_strlen)
732 proto_tree_add_item(tree, hf_http_request_method, tvb, 0, req_strlen, FALSE);
736 basic_response_dissector(tvbuff_t *tvb, proto_tree *tree, int req_strlen _U_)
739 int minor, major, status_code;
741 data = tvb_get_ptr(tvb, 5, 12);
742 if (sscanf((const gchar *)data, "%d.%d %d", &minor, &major, &status_code) == 3) {
743 proto_tree_add_uint(tree, hf_http_response_code, tvb, 9, 3, status_code);
744 stat_info->response_code = status_code;
749 * XXX - this won't handle HTTP 0.9 replies, but they're all data
753 is_http_request_or_reply(const gchar *data, int linelen, http_type_t *type,
754 RequestDissector *req_dissector, int *req_strlen)
756 int isHttpRequestOrReply = FALSE;
760 * From RFC 2774 - An HTTP Extension Framework
762 * Support the command prefix that identifies the presence of
763 * a "mandatory" header.
765 if (linelen >= 2 && strncmp(data, "M-", 2) == 0) {
772 * From draft-cohen-gena-client-01.txt, available from the uPnP forum:
773 * NOTIFY, SUBSCRIBE, UNSUBSCRIBE
775 * From draft-ietf-dasl-protocol-00.txt, a now vanished Microsoft draft:
778 if (linelen >= 5 && strncmp(data, "HTTP/", 5) == 0) {
779 *type = HTTP_RESPONSE;
780 isHttpRequestOrReply = TRUE; /* response */
782 *req_dissector = basic_response_dissector;
783 *req_strlen = linelen - 5;
786 const guchar * ptr = (const guchar *)data;
789 /* Look for the space following the Method */
790 while (index < linelen) {
799 /* Check the methods that have same length */
803 if (strncmp(data, "GET", index) == 0 ||
804 strncmp(data, "PUT", index) == 0) {
805 *type = HTTP_REQUEST;
806 isHttpRequestOrReply = TRUE;
808 else if (strncmp(data, "ICY", index) == 0) {
809 *type = HTTP_RESPONSE;
810 isHttpRequestOrReply = TRUE;
815 if (strncmp(data, "COPY", index) == 0 ||
816 strncmp(data, "HEAD", index) == 0 ||
817 strncmp(data, "LOCK", index) == 0 ||
818 strncmp(data, "MOVE", index) == 0 ||
819 strncmp(data, "POLL", index) == 0 ||
820 strncmp(data, "POST", index) == 0) {
821 *type = HTTP_REQUEST;
822 isHttpRequestOrReply = TRUE;
827 if (strncmp(data, "BCOPY", index) == 0 ||
828 strncmp(data, "BMOVE", index) == 0 ||
829 strncmp(data, "MKCOL", index) == 0 ||
830 strncmp(data, "TRACE", index) == 0) {
831 *type = HTTP_REQUEST;
832 isHttpRequestOrReply = TRUE;
837 if (strncmp(data, "DELETE", index) == 0 ||
838 strncmp(data, "SEARCH", index) == 0 ||
839 strncmp(data, "UNLOCK", index) == 0) {
840 *type = HTTP_REQUEST;
841 isHttpRequestOrReply = TRUE;
843 else if (strncmp(data, "NOTIFY", index) == 0) {
844 *type = HTTP_NOTIFICATION;
845 isHttpRequestOrReply = TRUE;
850 if (strncmp(data, "BDELETE", index) == 0 ||
851 strncmp(data, "CONNECT", index) == 0 ||
852 strncmp(data, "OPTIONS", index) == 0) {
853 *type = HTTP_REQUEST;
854 isHttpRequestOrReply = TRUE;
859 if (strncmp(data, "PROPFIND", index) == 0) {
860 *type = HTTP_REQUEST;
861 isHttpRequestOrReply = TRUE;
866 if (strncmp(data, "SUBSCRIBE", index) == 0) {
867 *type = HTTP_NOTIFICATION;
868 isHttpRequestOrReply = TRUE;
869 } else if (strncmp(data, "PROPPATCH", index) == 0 ||
870 strncmp(data, "BPROPFIND", index) == 0) {
871 *type = HTTP_REQUEST;
872 isHttpRequestOrReply = TRUE;
877 if (strncmp(data, "BPROPPATCH", index) == 0) {
878 *type = HTTP_REQUEST;
879 isHttpRequestOrReply = TRUE;
884 if (strncmp(data, "UNSUBSCRIBE", index) == 0) {
885 *type = HTTP_NOTIFICATION;
886 isHttpRequestOrReply = TRUE;
894 if (isHttpRequestOrReply && req_dissector) {
895 *req_dissector = basic_request_dissector;
896 *req_strlen = index + prefix_len;
898 if (isHttpRequestOrReply && req_dissector) {
899 if (!stat_info->request_method)
900 stat_info->request_method = g_malloc( index+1 );
901 strncpy( stat_info->request_method, data, index);
902 stat_info->request_method[index] = '\0';
906 return isHttpRequestOrReply;
918 #define HDR_NO_SPECIAL 0
919 #define HDR_AUTHORIZATION 1
920 #define HDR_AUTHENTICATE 2
921 #define HDR_CONTENT_TYPE 3
922 #define HDR_CONTENT_LENGTH 4
923 #define HDR_CONTENT_ENCODING 5
924 #define HDR_TRANSFER_ENCODING 6
926 static const header_info headers[] = {
927 { "Authorization", &hf_http_authorization, HDR_AUTHORIZATION },
928 { "Proxy-Authorization", &hf_http_proxy_authorization, HDR_AUTHORIZATION },
929 { "Proxy-Authenticate", &hf_http_proxy_authenticate, HDR_AUTHENTICATE },
930 { "WWW-Authenticate", &hf_http_www_authenticate, HDR_AUTHENTICATE },
931 { "Content-Type", &hf_http_content_type, HDR_CONTENT_TYPE },
932 { "Content-Length", &hf_http_content_length, HDR_CONTENT_LENGTH },
933 { "Content-Encoding", &hf_http_content_encoding, HDR_CONTENT_ENCODING },
934 { "Transfer-Encoding", &hf_http_transfer_encoding, HDR_TRANSFER_ENCODING },
938 process_header(tvbuff_t *tvb, int offset, int next_offset,
939 const guchar *line, int linelen, int colon_offset,
940 packet_info *pinfo, proto_tree *tree, headers_t *eh_ptr)
952 proto_item *hdr_item;
955 len = next_offset - offset;
956 line_end_offset = offset + linelen;
957 header_len = colon_offset - offset;
958 hf_index = find_header_hf_value(tvb, offset, header_len);
960 if (hf_index == -1) {
962 * Not a header we know anything about. Just put it into
966 proto_tree_add_text(tree, tvb, offset, len,
967 "%s", format_text(line, len));
971 * Skip whitespace after the colon.
973 value_offset = colon_offset + 1;
974 while (value_offset < line_end_offset
975 && ((c = line[value_offset - offset]) == ' ' || c == '\t'))
981 value_len = line_end_offset - value_offset;
982 value = g_malloc(value_len + 1);
983 memcpy(value, &line[value_offset - offset], value_len);
984 value[value_len] = '\0';
985 CLEANUP_PUSH(g_free, value);
988 * Add it to the protocol tree as a particular field,
989 * but display the line as is.
992 hdr_item = proto_tree_add_string_format(tree,
993 *headers[hf_index].hf, tvb, offset, len,
994 value, "%s", format_text(line, len));
999 * Do any special processing that particular headers
1002 switch (headers[hf_index].special) {
1004 case HDR_AUTHORIZATION:
1005 if (check_auth_ntlmssp(hdr_item, tvb, pinfo, value))
1006 break; /* dissected NTLMSSP */
1007 check_auth_basic(hdr_item, tvb, value);
1010 case HDR_AUTHENTICATE:
1011 check_auth_ntlmssp(hdr_item, tvb, pinfo, value);
1014 case HDR_CONTENT_TYPE:
1015 if (eh_ptr->content_type != NULL)
1016 g_free(eh_ptr->content_type);
1017 eh_ptr->content_type = g_malloc(value_len + 1);
1018 for (i = 0; i < value_len; i++) {
1020 if (c == ';' || isspace(c)) {
1022 * End of subtype - either
1023 * white space or a ";"
1024 * separating the subtype from
1031 * Map the character to lower case;
1032 * content types are case-insensitive.
1034 eh_ptr->content_type[i] = tolower(c);
1036 eh_ptr->content_type[i] = '\0';
1038 * Now find the start of the optional parameters;
1039 * skip the optional white space and the semicolon
1040 * if this has not been done before.
1043 while (i < value_len) {
1045 if (c == ';' || isspace(c))
1046 /* Skip till start of parameters */
1052 eh_ptr->content_type_parameters = value + i;
1054 eh_ptr->content_type_parameters = NULL;
1057 case HDR_CONTENT_LENGTH:
1058 eh_ptr->content_length = strtol(value, &p, 10);
1060 if (eh_ptr->content_length < 0 || p == value ||
1061 (*up != '\0' && !isspace(*up)))
1062 eh_ptr->content_length = -1; /* not valid */
1065 case HDR_CONTENT_ENCODING:
1066 if (eh_ptr->content_encoding != NULL)
1067 g_free(eh_ptr->content_encoding);
1068 eh_ptr->content_encoding = g_malloc(value_len + 1);
1069 memcpy(eh_ptr->content_encoding, value, value_len);
1070 eh_ptr->content_encoding[value_len] = '\0';
1073 case HDR_TRANSFER_ENCODING:
1074 if (eh_ptr->transfer_encoding != NULL)
1075 g_free(eh_ptr->transfer_encoding);
1076 eh_ptr->transfer_encoding = g_malloc(value_len + 1);
1077 memcpy(eh_ptr->transfer_encoding, value, value_len);
1078 eh_ptr->transfer_encoding[value_len] = '\0';
1083 * Free the value, by calling and popping the cleanup
1086 CLEANUP_CALL_AND_POP;
1090 /* Returns index of header tag in headers */
1092 find_header_hf_value(tvbuff_t *tvb, int offset, guint header_len)
1096 for (i = 0; i < array_length(headers); i++) {
1097 if (header_len == strlen(headers[i].name) &&
1098 tvb_strncaseeql(tvb, offset,
1099 headers[i].name, header_len) == 0)
1107 * Dissect Microsoft's abomination called NTLMSSP over HTTP.
1110 check_auth_ntlmssp(proto_item *hdr_item, tvbuff_t *tvb, packet_info *pinfo,
1113 static const char *ntlm_headers[] = {
1118 const char **header;
1120 proto_tree *hdr_tree;
1123 * Check for NTLM credentials and challenge; those can
1124 * occur with WWW-Authenticate.
1126 for (header = &ntlm_headers[0]; *header != NULL; header++) {
1127 hdrlen = strlen(*header);
1128 if (strncmp(value, *header, hdrlen) == 0) {
1129 if (hdr_item != NULL) {
1130 hdr_tree = proto_item_add_subtree(hdr_item,
1135 dissect_http_ntlmssp(tvb, pinfo, hdr_tree, value);
1143 * Dissect HTTP Basic authorization.
1146 check_auth_basic(proto_item *hdr_item, tvbuff_t *tvb, gchar *value)
1148 static const char *basic_headers[] = {
1152 const char **header;
1154 proto_tree *hdr_tree;
1157 for (header = &basic_headers[0]; *header != NULL; header++) {
1158 hdrlen = strlen(*header);
1159 if (strncmp(value, *header, hdrlen) == 0) {
1160 if (hdr_item != NULL) {
1161 hdr_tree = proto_item_add_subtree(hdr_item,
1167 len = base64_decode(value);
1169 proto_tree_add_string(hdr_tree, hf_http_basic, tvb,
1179 dissect_http(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1184 while (tvb_reported_length_remaining(tvb, offset) != 0) {
1185 len = dissect_http_message(tvb, offset, pinfo, tree);
1191 * OK, we've set the Protocol and Info columns for the
1192 * first HTTP message; make the columns non-writable,
1193 * so that we don't change it for subsequent HTTP messages.
1195 col_set_writable(pinfo->cinfo, FALSE);
1200 dissect_http_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1202 dissect_http_message(tvb, 0, pinfo, tree);
1206 proto_register_http(void)
1208 static hf_register_info hf[] = {
1209 { &hf_http_notification,
1210 { "Notification", "http.notification",
1211 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1212 "TRUE if HTTP notification", HFILL }},
1213 { &hf_http_response,
1214 { "Response", "http.response",
1215 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1216 "TRUE if HTTP response", HFILL }},
1218 { "Request", "http.request",
1219 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1220 "TRUE if HTTP request", HFILL }},
1222 { "Credentials", "http.authbasic",
1223 FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
1224 { &hf_http_request_method,
1225 { "Request Method", "http.request.method",
1226 FT_STRING, BASE_NONE, NULL, 0x0,
1227 "HTTP Request Method", HFILL }},
1228 { &hf_http_response_code,
1229 { "Response Code", "http.response.code",
1230 FT_UINT16, BASE_DEC, NULL, 0x0,
1231 "HTTP Response Code", HFILL }},
1232 { &hf_http_authorization,
1233 { "Authorization", "http.authorization",
1234 FT_STRING, BASE_NONE, NULL, 0x0,
1235 "HTTP Authorization header", HFILL }},
1236 { &hf_http_proxy_authenticate,
1237 { "Proxy-Authenticate", "http.proxy_authenticate",
1238 FT_STRING, BASE_NONE, NULL, 0x0,
1239 "HTTP Proxy-Authenticate header", HFILL }},
1240 { &hf_http_proxy_authorization,
1241 { "Proxy-Authorization", "http.proxy_authorization",
1242 FT_STRING, BASE_NONE, NULL, 0x0,
1243 "HTTP Proxy-Authorization header", HFILL }},
1244 { &hf_http_www_authenticate,
1245 { "WWW-Authenticate", "http.www_authenticate",
1246 FT_STRING, BASE_NONE, NULL, 0x0,
1247 "HTTP WWW-Authenticate header", HFILL }},
1248 { &hf_http_content_type,
1249 { "Content-Type", "http.content_type",
1250 FT_STRING, BASE_NONE, NULL, 0x0,
1251 "HTTP Content-Type header", HFILL }},
1252 { &hf_http_content_length,
1253 { "Content-Length", "http.content_length",
1254 FT_STRING, BASE_NONE, NULL, 0x0,
1255 "HTTP Content-Length header", HFILL }},
1256 { &hf_http_content_encoding,
1257 { "Content-Encoding", "http.content_encoding",
1258 FT_STRING, BASE_NONE, NULL, 0x0,
1259 "HTTP Content-Encoding header", HFILL }},
1260 { &hf_http_transfer_encoding,
1261 { "Transfer-Encoding", "http.transfer_encoding",
1262 FT_STRING, BASE_NONE, NULL, 0x0,
1263 "HTTP Transfer-Encoding header", HFILL }},
1265 static gint *ett[] = {
1270 module_t *http_module;
1272 proto_http = proto_register_protocol("Hypertext Transfer Protocol",
1274 proto_register_field_array(proto_http, hf, array_length(hf));
1275 proto_register_subtree_array(ett, array_length(ett));
1276 http_module = prefs_register_protocol(proto_http, NULL);
1277 prefs_register_bool_preference(http_module, "desegment_headers",
1278 "Desegment all HTTP headers spanning multiple TCP segments",
1279 "Whether the HTTP dissector should desegment all headers "
1280 "of a request spanning multiple TCP segments",
1281 &http_desegment_headers);
1282 prefs_register_bool_preference(http_module, "desegment_body",
1283 "Trust the \"Content-length:\" header and desegment HTTP "
1284 "bodies\nspanning multiple TCP segments",
1285 "Whether the HTTP dissector should use the "
1286 "\"Content-length:\" value to desegment the body "
1287 "of a request spanning multiple TCP segments",
1288 &http_desegment_body);
1290 http_handle = create_dissector_handle(dissect_http, proto_http);
1293 * Dissectors shouldn't register themselves in this table;
1294 * instead, they should call "http_dissector_add()", and
1295 * we'll register the port number they specify as a port
1296 * for HTTP, and register them in our subdissector table.
1298 * This only works for protocols such as IPP that run over
1299 * HTTP on a specific non-HTTP port.
1301 port_subdissector_table = register_dissector_table("http.port",
1302 "TCP port for protocols using HTTP", FT_UINT16, BASE_DEC);
1305 * Dissectors can register themselves in this table.
1306 * It's just "media_type", not "http.content_type", because
1307 * it's an Internet media type, usable by other protocols as well.
1309 media_type_subdissector_table =
1310 register_dissector_table("media_type",
1311 "Internet media type", FT_STRING, BASE_NONE);
1314 * Heuristic dissectors SHOULD register themselves in
1315 * this table using the standard heur_dissector_add()
1318 register_heur_dissector_list("http", &heur_subdissector_list);
1321 * Register for tapping
1323 http_tap = register_tap("http");
1327 * Called by dissectors for protocols that run atop HTTP/TCP.
1330 http_dissector_add(guint32 port, dissector_handle_t handle)
1333 * Register ourselves as the handler for that port number
1336 dissector_add("tcp.port", port, http_handle);
1339 * And register them in *our* table for that port.
1341 dissector_add("http.port", port, handle);
1345 proto_reg_handoff_http(void)
1347 dissector_handle_t http_udp_handle;
1349 data_handle = find_dissector("data");
1351 dissector_add("tcp.port", TCP_PORT_HTTP, http_handle);
1352 dissector_add("tcp.port", TCP_ALT_PORT_HTTP, http_handle);
1353 dissector_add("tcp.port", TCP_PORT_PROXY_HTTP, http_handle);
1354 dissector_add("tcp.port", TCP_PORT_PROXY_ADMIN_HTTP, http_handle);
1357 * XXX - is there anything to dissect in the body of an SSDP
1358 * request or reply? I.e., should there be an SSDP dissector?
1360 dissector_add("tcp.port", TCP_PORT_SSDP, http_handle);
1361 http_udp_handle = create_dissector_handle(dissect_http_udp, proto_http);
1362 dissector_add("udp.port", UDP_PORT_SSDP, http_udp_handle);
1364 ntlmssp_handle = find_dissector("ntlmssp");
1368 * Content-Type: message/http
1371 static gint proto_message_http = -1;
1372 static gint ett_message_http = -1;
1373 static dissector_handle_t message_http_handle;
1376 dissect_message_http(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1378 proto_tree *subtree;
1380 gint offset = 0, next_offset;
1383 if (check_col(pinfo->cinfo, COL_INFO))
1384 col_append_str(pinfo->cinfo, COL_INFO, " (message/http)");
1386 ti = proto_tree_add_item(tree, proto_message_http,
1388 subtree = proto_item_add_subtree(ti, ett_message_http);
1389 while (tvb_reported_length_remaining(tvb, offset) != 0) {
1390 len = tvb_find_line_end(tvb, offset,
1391 tvb_ensure_length_remaining(tvb, offset),
1392 &next_offset, FALSE);
1395 proto_tree_add_text(subtree, tvb, offset, next_offset - offset,
1396 "%s", tvb_format_text(tvb, offset, len));
1397 offset = next_offset;
1403 proto_register_message_http(void)
1405 static gint *ett[] = {
1409 proto_message_http = proto_register_protocol(
1410 "Media Type: message/http",
1414 proto_register_subtree_array(ett, array_length(ett));
1415 message_http_handle = create_dissector_handle(dissect_message_http,
1416 proto_message_http);
1420 proto_reg_handoff_message_http(void)
1422 message_http_handle = create_dissector_handle(dissect_message_http,
1423 proto_message_http);
1425 dissector_add_string("media_type", "message/http", message_http_handle);