2 * Routines for HTTP packet disassembly
4 * Guy Harris <guy@alum.mit.edu>
6 * Copyright 2004, Jerry Talkington <jtalkington@users.sourceforge.net>
7 * Copyright 2002, Tim Potter <tpot@samba.org>
8 * Copyright 1999, Andrew Tridgell <tridge@samba.org>
10 * $Id: packet-http.c,v 1.102 2004/05/04 07:12:03 guy Exp $
12 * Ethereal - Network traffic analyzer
13 * By Gerald Combs <gerald@ethereal.com>
14 * Copyright 1998 Gerald Combs
16 * This program is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU General Public License
18 * as published by the Free Software Foundation; either version 2
19 * of the License, or (at your option) any later version.
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
39 #include <epan/packet.h>
40 #include <epan/strutil.h>
43 #include "req_resp_hdrs.h"
44 #include "packet-http.h"
47 typedef enum _http_type {
56 static int http_tap = -1;
58 static int proto_http = -1;
59 static int hf_http_notification = -1;
60 static int hf_http_response = -1;
61 static int hf_http_request = -1;
62 static int hf_http_basic = -1;
63 static int hf_http_request_method = -1;
64 static int hf_http_response_code = -1;
65 static int hf_http_authorization = -1;
66 static int hf_http_proxy_authenticate = -1;
67 static int hf_http_proxy_authorization = -1;
68 static int hf_http_www_authenticate = -1;
69 static int hf_http_content_type = -1;
70 static int hf_http_content_length = -1;
71 static int hf_http_content_encoding = -1;
72 static int hf_http_transfer_encoding = -1;
74 static gint ett_http = -1;
75 static gint ett_http_ntlmssp = -1;
76 static gint ett_http_request = -1;
77 static gint ett_http_chunked_response = -1;
78 static gint ett_http_chunk_data = -1;
79 static gint ett_http_encoded_entity = -1;
81 static dissector_handle_t data_handle;
82 static dissector_handle_t media_handle;
83 static dissector_handle_t http_handle;
86 * desegmentation of HTTP headers
87 * (when we are over TCP or another protocol providing the desegmentation API)
89 static gboolean http_desegment_headers = FALSE;
92 * desegmentation of HTTP bodies
93 * (when we are over TCP or another protocol providing the desegmentation API)
94 * TODO let the user filter on content-type the bodies he wants desegmented
96 static gboolean http_desegment_body = FALSE;
98 #define TCP_PORT_HTTP 80
99 #define TCP_PORT_PROXY_HTTP 3128
100 #define TCP_PORT_PROXY_ADMIN_HTTP 3132
101 #define TCP_ALT_PORT_HTTP 8080
104 * SSDP is implemented atop HTTP (yes, it really *does* run over UDP).
106 #define TCP_PORT_SSDP 1900
107 #define UDP_PORT_SSDP 1900
110 * Protocols implemented atop HTTP.
113 PROTO_HTTP, /* just HTTP */
114 PROTO_SSDP /* Simple Service Discovery Protocol */
117 typedef void (*RequestDissector)(tvbuff_t*, proto_tree*, int);
120 * Structure holding information from headers needed by main
121 * HTTP dissector code.
125 char *content_type_parameters;
126 long content_length; /* XXX - make it 64-bit? */
127 char *content_encoding;
128 char *transfer_encoding;
131 static int is_http_request_or_reply(const gchar *data, int linelen, http_type_t *type,
132 RequestDissector *req_dissector, int *req_strlen);
133 static int chunked_encoding_dissector(tvbuff_t **tvb_ptr, packet_info *pinfo,
134 proto_tree *tree, int offset);
135 static void process_header(tvbuff_t *tvb, int offset, int next_offset,
136 const guchar *line, int linelen, int colon_offset, packet_info *pinfo,
137 proto_tree *tree, headers_t *eh_ptr);
138 static gint find_header_hf_value(tvbuff_t *tvb, int offset, guint header_len);
139 static gboolean check_auth_ntlmssp(proto_item *hdr_item, tvbuff_t *tvb,
140 packet_info *pinfo, gchar *value);
141 static gboolean check_auth_basic(proto_item *hdr_item, tvbuff_t *tvb,
144 static dissector_table_t port_subdissector_table;
145 static dissector_table_t media_type_subdissector_table;
146 static heur_dissector_list_t heur_subdissector_list;
148 static dissector_handle_t ntlmssp_handle=NULL;
151 /* Return a tvb that contains the binary representation of a base64
155 base64_to_tvb(const char *base64)
158 char *data = g_strdup(base64);
161 len = base64_decode(data);
162 tvb = tvb_new_real_data((const guint8 *)data, len, len);
164 tvb_set_free_cb(tvb, g_free);
170 dissect_http_ntlmssp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
173 tvbuff_t *ntlmssp_tvb;
175 ntlmssp_tvb = base64_to_tvb(line);
176 tvb_set_child_real_data_tvbuff(tvb, ntlmssp_tvb);
177 add_new_data_source(pinfo, ntlmssp_tvb, "NTLMSSP Data");
179 call_dissector(ntlmssp_handle, ntlmssp_tvb, pinfo, tree);
183 cleanup_headers(void *arg)
185 headers_t *headers = arg;
187 if (headers->content_type != NULL)
188 g_free(headers->content_type);
190 * The content_type_parameters field actually points into the
191 * content_type headers, so don't free it, as that'll double-free
194 if (headers->content_encoding != NULL)
195 g_free(headers->content_encoding);
196 if (headers->transfer_encoding != NULL)
197 g_free(headers->transfer_encoding);
201 * TODO: remove this ugly global variable.
203 * XXX - we leak "http_info_value_t" structures.
204 * XXX - this gets overwritten if there's more than one HTTP request or
205 * reply in the tvbuff.
207 static http_info_value_t *stat_info;
210 dissect_http_message(tvbuff_t *tvb, int offset, packet_info *pinfo,
215 proto_tree *http_tree = NULL;
216 proto_item *ti = NULL;
219 const guchar *linep, *lineend;
221 int first_linelen, linelen;
222 gboolean is_request_or_reply;
223 gboolean saw_req_resp_or_header;
225 http_type_t http_type;
226 proto_item *hdr_item;
227 RequestDissector req_dissector;
229 proto_tree *req_tree;
233 int reported_datalen;
234 dissector_handle_t handle;
238 * Is this a request or response?
240 * Note that "tvb_find_line_end()" will return a value that
241 * is not longer than what's in the buffer, so the
242 * "tvb_get_ptr()" call won't throw an exception.
244 first_linelen = tvb_find_line_end(tvb, offset,
245 tvb_ensure_length_remaining(tvb, offset), &next_offset,
248 * Is the first line a request or response?
250 line = tvb_get_ptr(tvb, offset, first_linelen);
251 http_type = HTTP_OTHERS; /* type not known yet */
252 is_request_or_reply = is_http_request_or_reply((const gchar *)line,
253 first_linelen, &http_type, NULL, NULL);
254 if (is_request_or_reply) {
256 * Yes, it's a request or response.
257 * Do header desegmentation if we've been told to,
258 * and do body desegmentation if we've been told to and
259 * we find a Content-Length header.
261 if (!req_resp_hdrs_do_reassembly(tvb, pinfo,
262 http_desegment_headers, http_desegment_body)) {
264 * More data needed for desegmentation.
270 stat_info = g_malloc(sizeof(http_info_value_t));
271 stat_info->response_code = 0;
272 stat_info->request_method = NULL;
274 switch (pinfo->match_port) {
276 case TCP_PORT_SSDP: /* TCP_PORT_SSDP = UDP_PORT_SSDP */
287 if (check_col(pinfo->cinfo, COL_PROTOCOL))
288 col_set_str(pinfo->cinfo, COL_PROTOCOL, proto_tag);
289 if (check_col(pinfo->cinfo, COL_INFO)) {
291 * Put the first line from the buffer into the summary
292 * if it's an HTTP request or reply (but leave out the
294 * Otherwise, just call it a continuation.
296 * Note that "tvb_find_line_end()" will return a value that
297 * is not longer than what's in the buffer, so the
298 * "tvb_get_ptr()" call won't throw an exception.
300 line = tvb_get_ptr(tvb, offset, first_linelen);
301 if (is_request_or_reply)
302 col_add_str(pinfo->cinfo, COL_INFO,
303 format_text(line, first_linelen));
305 col_set_str(pinfo->cinfo, COL_INFO, "Continuation");
308 orig_offset = offset;
310 ti = proto_tree_add_item(tree, proto_http, tvb, offset, -1,
312 http_tree = proto_item_add_subtree(ti, ett_http);
316 * Process the packet data, a line at a time.
318 http_type = HTTP_OTHERS; /* type not known yet */
319 headers.content_type = NULL; /* content type not known yet */
320 headers.content_type_parameters = NULL; /* content type parameters too */
321 headers.content_length = -1; /* content length not known yet */
322 headers.content_encoding = NULL; /* content encoding not known yet */
323 headers.transfer_encoding = NULL; /* transfer encoding not known yet */
324 saw_req_resp_or_header = FALSE; /* haven't seen anything yet */
325 CLEANUP_PUSH(cleanup_headers, &headers);
326 while (tvb_reported_length_remaining(tvb, offset) != 0) {
328 * Find the end of the line.
330 linelen = tvb_find_line_end(tvb, offset,
331 tvb_ensure_length_remaining(tvb, offset), &next_offset,
337 * Get a buffer that refers to the line.
339 line = tvb_get_ptr(tvb, offset, linelen);
340 lineend = line + linelen;
344 * OK, does it look like an HTTP request or response?
346 req_dissector = NULL;
347 is_request_or_reply = is_http_request_or_reply((const gchar *)line,
348 linelen, &http_type, &req_dissector, &req_strlen);
349 if (is_request_or_reply)
353 * No. Does it look like a blank line (as would appear
354 * at the end of an HTTP request)?
357 goto is_http; /* Yes. */
360 * No. Does it look like a header?
363 colon_offset = offset;
364 while (linep < lineend) {
368 * This must be a CHAR to be part of a token; that
369 * means it must be ASCII.
372 break; /* not ASCII, thus not a CHAR */
375 * This mustn't be a CTL to be part of a token;
376 * that means it must be printable.
378 * XXX - what about leading LWS on continuation
382 break; /* not printable, not a header */
385 * This mustn't be a SEP to be part of a token;
386 * a ':' ends the token, everything else is an
387 * indication that this isn't a header.
409 * It's a separator, so it's not part of a
410 * token, so it's not a field name for the
411 * beginning of a header.
413 * (We don't have to check for HT; that's
414 * already been ruled out by "isprint()".)
420 * This ends the token; we consider this
432 * We haven't seen the colon, but everything else looks
433 * OK for a header line.
435 * If we've already seen an HTTP request or response
436 * line, or a header line, and we're at the end of
437 * the tvbuff, we assume this is an incomplete header
438 * line. (We quit this loop after seeing a blank line,
439 * so if we've seen a request or response line, or a
440 * header line, this is probably more of the request
441 * or response we're presumably seeing. There is some
442 * risk of false positives, but the same applies for
443 * full request or response lines or header lines,
444 * although that's less likely.)
446 * We throw an exception in that case, by checking for
447 * the existence of the next byte after the last one
448 * in the line. If it exists, "tvb_ensure_bytes_exist()"
449 * throws no exception, and we fall through to the
450 * "not HTTP" case. If it doesn't exist,
451 * "tvb_ensure_bytes_exist()" will throw the appropriate
454 if (saw_req_resp_or_header)
455 tvb_ensure_bytes_exist(tvb, offset, linelen + 1);
459 * We don't consider this part of an HTTP request or
460 * reply, so we don't display it.
461 * (Yeah, that means we don't display, say, a text/http
462 * page, but you can get that from the data pane.)
472 * This is a blank line, which means that
473 * whatever follows it isn't part of this
476 proto_tree_add_text(http_tree, tvb, offset,
477 next_offset - offset, "%s",
478 tvb_format_text(tvb, offset, next_offset - offset));
479 offset = next_offset;
484 * Not a blank line - either a request, a reply, or a header
487 saw_req_resp_or_header = TRUE;
488 if (is_request_or_reply) {
490 hdr_item = proto_tree_add_text(http_tree, tvb,
491 offset, next_offset - offset, "%s",
492 tvb_format_text(tvb, offset,
493 next_offset - offset));
495 req_tree = proto_item_add_subtree(
496 hdr_item, ett_http_request);
497 req_dissector(tvb, req_tree,
505 process_header(tvb, offset, next_offset, line, linelen,
506 colon_offset, pinfo, http_tree, &headers);
508 offset = next_offset;
514 case HTTP_NOTIFICATION:
515 proto_tree_add_boolean_hidden(http_tree,
516 hf_http_notification, tvb, 0, 0, 1);
520 proto_tree_add_boolean_hidden(http_tree,
521 hf_http_response, tvb, 0, 0, 1);
525 proto_tree_add_boolean_hidden(http_tree,
526 hf_http_request, tvb, 0, 0, 1);
536 * If a content length was supplied, the amount of data to be
537 * processed as HTTP payload is the minimum of the content
538 * length and the amount of data remaining in the frame.
540 * If no content length was supplied (or if a bad content length
541 * was supplied), the amount of data to be processed is the amount
542 * of data remaining in the frame.
544 * If there was no Content-Length entity header, we should
545 * accumulate all data until the end of the connection.
546 * That'd require that the TCP dissector call subdissectors
547 * for all frames with FIN, even if they contain no data,
548 * which would require subdissectors to deal intelligently
549 * with empty segments.
551 * Acccording to RFC 2616, however, 1xx responses, 204 responses,
552 * and 304 responses MUST NOT include a message body; if no
553 * content length is specified for them, we don't attempt to
556 * XXX - it says the same about responses to HEAD requests;
557 * unless there's a way to determine from the response
558 * whether it's a response to a HEAD request, we have to
559 * keep information about the request and associate that with
560 * the response in order to handle that.
562 datalen = tvb_length_remaining(tvb, offset);
563 if (headers.content_length != -1) {
564 if (datalen > headers.content_length)
565 datalen = headers.content_length;
568 * XXX - limit the reported length in the tvbuff we'll
569 * hand to a subdissector to be no greater than the
572 * We really need both unreassembled and "how long it'd
573 * be if it were reassembled" lengths for tvbuffs, so
574 * that we throw the appropriate exceptions for
575 * "not enough data captured" (running past the length),
576 * "packet needed reassembly" (within the length but
577 * running past the unreassembled length), and
578 * "packet is malformed" (running past the reassembled
581 reported_datalen = tvb_reported_length_remaining(tvb, offset);
582 if (reported_datalen > headers.content_length)
583 reported_datalen = headers.content_length;
585 if ((stat_info->response_code/100) == 1 ||
586 stat_info->response_code == 204 ||
587 stat_info->response_code == 304)
588 datalen = 0; /* no content! */
590 reported_datalen = -1;
595 * There's stuff left over; process it.
598 void *save_private_data = NULL;
599 gint chunks_decoded = 0;
602 * Create a tvbuff for the payload.
604 * The amount of data to be processed that's
605 * available in the tvbuff is "datalen", which
606 * is the minimum of the amount of data left in
607 * the tvbuff and any specified content length.
609 * The amount of data to be processed that's in
610 * this frame, regardless of whether it was
611 * captured or not, is "reported_datalen",
612 * which, if no content length was specified,
613 * is -1, i.e. "to the end of the frame.
615 next_tvb = tvb_new_subset(tvb, offset, datalen,
619 * Handle transfer encodings other than "identity".
621 if (headers.transfer_encoding != NULL &&
622 strcasecmp(headers.transfer_encoding, "identity") != 0) {
623 if (strcasecmp(headers.transfer_encoding, "chunked")
626 chunks_decoded = chunked_encoding_dissector(
627 &next_tvb, pinfo, http_tree, 0);
629 if (chunks_decoded <= 0) {
631 * The chunks weren't reassembled,
632 * or there was a single zero
640 * We currently can't handle, for example, "gzip",
641 * "compress", or "deflate"; just handle them
644 call_dissector(data_handle, next_tvb, pinfo,
651 * Handle content encodings other than "identity" (which
652 * shouldn't appear in a Content-Encoding header, but
653 * we handle it in any case).
655 if (headers.content_encoding != NULL &&
656 strcasecmp(headers.content_encoding, "identity") != 0) {
658 * We currently can't handle, for example, "gzip",
659 * "compress", or "deflate"; just handle them as
662 proto_item *e_ti = NULL;
663 proto_tree *e_tree = NULL;
665 e_ti = proto_tree_add_text(http_tree, next_tvb, 0,
666 tvb_length(next_tvb), "Encoded entity-body (%s)",
667 headers.content_encoding);
669 e_tree = proto_item_add_subtree(e_ti,
670 ett_http_encoded_entity);
672 call_dissector(data_handle, next_tvb, pinfo, e_tree);
678 * Do subdissector checks.
680 * First, check whether some subdissector asked that they
681 * be called if something was on some particular port.
683 handle = dissector_get_port_handle(port_subdissector_table,
685 if (handle == NULL && headers.content_type != NULL) {
687 * We didn't find any subdissector that
688 * registered for the port, and we have a
689 * Content-Type value. Is there any subdissector
690 * for that content type?
692 save_private_data = pinfo->private_data;
694 * XXX - this won't get freed if the subdissector
695 * throws an exception. Do we really need to
698 if (headers.content_type_parameters)
699 pinfo->private_data = g_strdup(headers.content_type_parameters);
701 pinfo->private_data = NULL;
703 * Calling the string handle for the media type
704 * dissector table will set pinfo->match_string
705 * to headers.content_type for us.
707 pinfo->match_string = headers.content_type;
708 handle = dissector_get_string_handle(
709 media_type_subdissector_table,
710 headers.content_type);
712 * Calling the default media handle otherwise
714 if (handle == NULL) {
715 handle = media_handle;
718 if (handle != NULL) {
720 * We have a subdissector - call it.
722 dissected = call_dissector(handle, next_tvb, pinfo,
726 * We don't have a subdissector - try the heuristic
729 dissected = dissector_try_heuristic(
730 heur_subdissector_list, next_tvb, pinfo, tree);
734 * The subdissector dissected the body.
735 * Fix up the top-level item so that it doesn't
736 * include the stuff for that protocol.
739 proto_item_set_len(ti, offset);
741 call_dissector(data_handle, next_tvb, pinfo,
747 * Do *not* attempt at freeing the private data;
748 * it may be in use by subdissectors.
750 if (save_private_data)
751 pinfo->private_data = save_private_data;
753 * We've processed "datalen" bytes worth of data
754 * (which may be no data at all); advance the
755 * offset past whatever data we've processed.
761 * Clean up any header stuff, by calling and popping the cleanup
764 CLEANUP_CALL_AND_POP;
766 tap_queue_packet(http_tap, pinfo, stat_info);
768 return offset - orig_offset;
771 /* This can be used to dissect an HTTP request until such time
772 * that a more complete dissector is written for that HTTP request.
773 * This simple dissectory only puts http.request_method into a sub-tree.
776 basic_request_dissector(tvbuff_t *tvb, proto_tree *tree, int req_strlen)
778 proto_tree_add_item(tree, hf_http_request_method, tvb, 0, req_strlen, FALSE);
782 basic_response_dissector(tvbuff_t *tvb, proto_tree *tree, int resp_strlen)
785 int minor, major, status_code;
787 /* BEWARE - sscanf() only operates on C strings.
788 * The pointer returned by tvb_get_ptr points into the real data,
789 * which is not necessarily NULL terminated. For this reason,
790 * the sscanf() call is only applied to a buffer guaranteed to
791 * only contain a NULL terminated string. */
792 data = g_strndup((const gchar *)tvb_get_ptr(tvb, 5, resp_strlen), resp_strlen);
793 if (sscanf((const gchar *)data, "%d.%d %d", &minor, &major, &status_code) == 3) {
794 proto_tree_add_uint(tree, hf_http_response_code, tvb, 9, 3, status_code);
795 stat_info->response_code = status_code;
801 * Dissect the http data chunks and add them to the tree.
804 chunked_encoding_dissector(tvbuff_t **tvb_ptr, packet_info *pinfo,
805 proto_tree *tree, int offset)
807 guint8 *chunk_string = NULL;
809 gint chunk_offset = 0;
812 gint chunks_decoded = 0;
813 tvbuff_t *tvb = NULL;
814 tvbuff_t *new_tvb = NULL;
815 gint chunked_data_size = 0;
816 proto_tree *subtree = NULL;
817 proto_item *ti = NULL;
819 if (tvb_ptr == NULL || *tvb_ptr == NULL) {
825 datalen = tvb_reported_length_remaining(tvb, offset);
828 ti = proto_tree_add_text(tree, tvb, offset, datalen,
829 "HTTP chunked response");
830 subtree = proto_item_add_subtree(ti, ett_http_chunked_response);
834 while (datalen != 0) {
835 proto_item *chunk_ti = NULL;
836 proto_tree *chunk_subtree = NULL;
837 tvbuff_t *data_tvb = NULL;
840 linelen = tvb_find_line_end(tvb, offset, -1, &chunk_offset, TRUE);
843 /* Can't get the chunk size line */
844 return chunks_decoded;
847 chunk_string = tvb_get_string(tvb, offset, linelen);
849 if (chunk_string == NULL) {
850 /* Can't get the chunk size line */
851 return chunks_decoded;
857 * We don't care about the extensions.
859 if ((c = strchr(c, ';'))) {
863 if (sscanf(chunk_string, "%x", &chunk_size) != 1) {
864 g_free(chunk_string);
865 return chunks_decoded;
868 g_free(chunk_string);
871 if (chunk_size > datalen) {
873 * The chunk size is more than what's in the tvbuff,
874 * so either the user hasn't enabled decoding, or all
875 * of the segments weren't captured.
877 chunk_size = datalen;
878 }/* else if (new_tvb == NULL) {
879 new_tvb = tvb_new_composite();
884 if (new_tvb != NULL && chunk_size != 0) {
885 tvbuff_t *chunk_tvb = NULL;
887 chunk_tvb = tvb_new_subset(tvb, chunk_offset,
888 chunk_size, datalen);
890 tvb_composite_append(new_tvb, chunk_tvb);
895 chunked_data_size += chunk_size;
897 if (chunk_size != 0) {
898 guint8 *raw_data = g_malloc(chunked_data_size);
901 if (new_tvb != NULL) {
902 raw_len = tvb_length_remaining(new_tvb, 0);
903 tvb_memcpy(new_tvb, raw_data, 0, raw_len);
908 tvb_memcpy(tvb, (guint8 *)(raw_data + raw_len),
909 chunk_offset, chunk_size);
911 new_tvb = tvb_new_real_data(raw_data,
912 chunked_data_size, chunked_data_size);
917 if (chunk_size == 0) {
918 chunk_ti = proto_tree_add_text(subtree, tvb,
920 chunk_offset - offset + chunk_size + 2,
921 "Data chunk (last chunk)");
923 chunk_ti = proto_tree_add_text(subtree, tvb,
925 chunk_offset - offset + chunk_size + 2,
926 "Data chunk (%u octets)", chunk_size);
929 chunk_subtree = proto_item_add_subtree(chunk_ti,
930 ett_http_chunk_data);
932 proto_tree_add_text(chunk_subtree, tvb, offset,
933 chunk_offset - offset, "Chunk size: %u octets",
936 data_tvb = tvb_new_subset(tvb, chunk_offset, chunk_size,
940 if (chunk_size > 0) {
941 call_dissector(data_handle, data_tvb, pinfo,
945 proto_tree_add_text(chunk_subtree, tvb, chunk_offset +
946 chunk_size, 2, "Chunk boundary");
950 offset = chunk_offset + chunk_size + 2;
951 datalen = tvb_reported_length_remaining(tvb, offset);
954 if (new_tvb != NULL) {
956 /* Placeholder for the day that composite tvbuffer's will work.
957 tvb_composite_finalize(new_tvb);
958 / * tvb_set_reported_length(new_tvb, chunked_data_size); * /
961 tvb_set_child_real_data_tvbuff(tvb, new_tvb);
962 add_new_data_source(pinfo, new_tvb, "De-chunked entity body");
969 * We didn't create a new tvb, so don't allow sub dissectors
970 * try to decode the non-existant entity body.
975 return chunks_decoded;
981 * XXX - this won't handle HTTP 0.9 replies, but they're all data
985 is_http_request_or_reply(const gchar *data, int linelen, http_type_t *type,
986 RequestDissector *req_dissector, int *req_strlen)
988 int isHttpRequestOrReply = FALSE;
992 * From RFC 2774 - An HTTP Extension Framework
994 * Support the command prefix that identifies the presence of
995 * a "mandatory" header.
997 if (linelen >= 2 && strncmp(data, "M-", 2) == 0) {
1004 * From draft-cohen-gena-client-01.txt, available from the uPnP forum:
1005 * NOTIFY, SUBSCRIBE, UNSUBSCRIBE
1007 * From draft-ietf-dasl-protocol-00.txt, a now vanished Microsoft draft:
1010 if (linelen >= 5 && strncmp(data, "HTTP/", 5) == 0) {
1011 *type = HTTP_RESPONSE;
1012 isHttpRequestOrReply = TRUE; /* response */
1013 if (req_dissector) {
1014 *req_dissector = basic_response_dissector;
1015 *req_strlen = linelen - 5;
1018 const guchar * ptr = (const guchar *)data;
1021 /* Look for the space following the Method */
1022 while (index < linelen) {
1031 /* Check the methods that have same length */
1035 if (strncmp(data, "GET", index) == 0 ||
1036 strncmp(data, "PUT", index) == 0) {
1037 *type = HTTP_REQUEST;
1038 isHttpRequestOrReply = TRUE;
1040 else if (strncmp(data, "ICY", index) == 0) {
1041 *type = HTTP_RESPONSE;
1042 isHttpRequestOrReply = TRUE;
1047 if (strncmp(data, "COPY", index) == 0 ||
1048 strncmp(data, "HEAD", index) == 0 ||
1049 strncmp(data, "LOCK", index) == 0 ||
1050 strncmp(data, "MOVE", index) == 0 ||
1051 strncmp(data, "POLL", index) == 0 ||
1052 strncmp(data, "POST", index) == 0) {
1053 *type = HTTP_REQUEST;
1054 isHttpRequestOrReply = TRUE;
1059 if (strncmp(data, "BCOPY", index) == 0 ||
1060 strncmp(data, "BMOVE", index) == 0 ||
1061 strncmp(data, "MKCOL", index) == 0 ||
1062 strncmp(data, "TRACE", index) == 0) {
1063 *type = HTTP_REQUEST;
1064 isHttpRequestOrReply = TRUE;
1069 if (strncmp(data, "DELETE", index) == 0 ||
1070 strncmp(data, "SEARCH", index) == 0 ||
1071 strncmp(data, "UNLOCK", index) == 0) {
1072 *type = HTTP_REQUEST;
1073 isHttpRequestOrReply = TRUE;
1075 else if (strncmp(data, "NOTIFY", index) == 0) {
1076 *type = HTTP_NOTIFICATION;
1077 isHttpRequestOrReply = TRUE;
1082 if (strncmp(data, "BDELETE", index) == 0 ||
1083 strncmp(data, "CONNECT", index) == 0 ||
1084 strncmp(data, "OPTIONS", index) == 0) {
1085 *type = HTTP_REQUEST;
1086 isHttpRequestOrReply = TRUE;
1091 if (strncmp(data, "PROPFIND", index) == 0) {
1092 *type = HTTP_REQUEST;
1093 isHttpRequestOrReply = TRUE;
1098 if (strncmp(data, "SUBSCRIBE", index) == 0) {
1099 *type = HTTP_NOTIFICATION;
1100 isHttpRequestOrReply = TRUE;
1101 } else if (strncmp(data, "PROPPATCH", index) == 0 ||
1102 strncmp(data, "BPROPFIND", index) == 0) {
1103 *type = HTTP_REQUEST;
1104 isHttpRequestOrReply = TRUE;
1109 if (strncmp(data, "BPROPPATCH", index) == 0) {
1110 *type = HTTP_REQUEST;
1111 isHttpRequestOrReply = TRUE;
1116 if (strncmp(data, "UNSUBSCRIBE", index) == 0) {
1117 *type = HTTP_NOTIFICATION;
1118 isHttpRequestOrReply = TRUE;
1126 if (isHttpRequestOrReply && req_dissector) {
1127 *req_dissector = basic_request_dissector;
1128 *req_strlen = index + prefix_len;
1130 if (isHttpRequestOrReply && req_dissector) {
1131 if (!stat_info->request_method)
1132 stat_info->request_method = g_malloc( index+1 );
1133 strncpy( stat_info->request_method, data, index);
1134 stat_info->request_method[index] = '\0';
1138 return isHttpRequestOrReply;
1150 #define HDR_NO_SPECIAL 0
1151 #define HDR_AUTHORIZATION 1
1152 #define HDR_AUTHENTICATE 2
1153 #define HDR_CONTENT_TYPE 3
1154 #define HDR_CONTENT_LENGTH 4
1155 #define HDR_CONTENT_ENCODING 5
1156 #define HDR_TRANSFER_ENCODING 6
1158 static const header_info headers[] = {
1159 { "Authorization", &hf_http_authorization, HDR_AUTHORIZATION },
1160 { "Proxy-Authorization", &hf_http_proxy_authorization, HDR_AUTHORIZATION },
1161 { "Proxy-Authenticate", &hf_http_proxy_authenticate, HDR_AUTHENTICATE },
1162 { "WWW-Authenticate", &hf_http_www_authenticate, HDR_AUTHENTICATE },
1163 { "Content-Type", &hf_http_content_type, HDR_CONTENT_TYPE },
1164 { "Content-Length", &hf_http_content_length, HDR_CONTENT_LENGTH },
1165 { "Content-Encoding", &hf_http_content_encoding, HDR_CONTENT_ENCODING },
1166 { "Transfer-Encoding", &hf_http_transfer_encoding, HDR_TRANSFER_ENCODING },
1170 process_header(tvbuff_t *tvb, int offset, int next_offset,
1171 const guchar *line, int linelen, int colon_offset,
1172 packet_info *pinfo, proto_tree *tree, headers_t *eh_ptr)
1175 int line_end_offset;
1184 proto_item *hdr_item;
1187 len = next_offset - offset;
1188 line_end_offset = offset + linelen;
1189 header_len = colon_offset - offset;
1190 hf_index = find_header_hf_value(tvb, offset, header_len);
1192 if (hf_index == -1) {
1194 * Not a header we know anything about. Just put it into
1198 proto_tree_add_text(tree, tvb, offset, len,
1199 "%s", format_text(line, len));
1203 * Skip whitespace after the colon.
1205 value_offset = colon_offset + 1;
1206 while (value_offset < line_end_offset
1207 && ((c = line[value_offset - offset]) == ' ' || c == '\t'))
1213 value_len = line_end_offset - value_offset;
1214 value = g_malloc(value_len + 1);
1215 memcpy(value, &line[value_offset - offset], value_len);
1216 value[value_len] = '\0';
1217 CLEANUP_PUSH(g_free, value);
1220 * Add it to the protocol tree as a particular field,
1221 * but display the line as is.
1224 hdr_item = proto_tree_add_string_format(tree,
1225 *headers[hf_index].hf, tvb, offset, len,
1226 value, "%s", format_text(line, len));
1231 * Do any special processing that particular headers
1234 switch (headers[hf_index].special) {
1236 case HDR_AUTHORIZATION:
1237 if (check_auth_ntlmssp(hdr_item, tvb, pinfo, value))
1238 break; /* dissected NTLMSSP */
1239 check_auth_basic(hdr_item, tvb, value);
1242 case HDR_AUTHENTICATE:
1243 check_auth_ntlmssp(hdr_item, tvb, pinfo, value);
1246 case HDR_CONTENT_TYPE:
1247 if (eh_ptr->content_type != NULL)
1248 g_free(eh_ptr->content_type);
1249 eh_ptr->content_type = g_malloc(value_len + 1);
1250 for (i = 0; i < value_len; i++) {
1252 if (c == ';' || isspace(c)) {
1254 * End of subtype - either
1255 * white space or a ";"
1256 * separating the subtype from
1263 * Map the character to lower case;
1264 * content types are case-insensitive.
1266 eh_ptr->content_type[i] = tolower(c);
1268 eh_ptr->content_type[i] = '\0';
1270 * Now find the start of the optional parameters;
1271 * skip the optional white space and the semicolon
1272 * if this has not been done before.
1275 while (i < value_len) {
1277 if (c == ';' || isspace(c))
1278 /* Skip till start of parameters */
1284 eh_ptr->content_type_parameters = value + i;
1286 eh_ptr->content_type_parameters = NULL;
1289 case HDR_CONTENT_LENGTH:
1290 eh_ptr->content_length = strtol(value, &p, 10);
1292 if (eh_ptr->content_length < 0 || p == value ||
1293 (*up != '\0' && !isspace(*up)))
1294 eh_ptr->content_length = -1; /* not valid */
1297 case HDR_CONTENT_ENCODING:
1298 if (eh_ptr->content_encoding != NULL)
1299 g_free(eh_ptr->content_encoding);
1300 eh_ptr->content_encoding = g_malloc(value_len + 1);
1301 memcpy(eh_ptr->content_encoding, value, value_len);
1302 eh_ptr->content_encoding[value_len] = '\0';
1305 case HDR_TRANSFER_ENCODING:
1306 if (eh_ptr->transfer_encoding != NULL)
1307 g_free(eh_ptr->transfer_encoding);
1308 eh_ptr->transfer_encoding = g_malloc(value_len + 1);
1309 memcpy(eh_ptr->transfer_encoding, value, value_len);
1310 eh_ptr->transfer_encoding[value_len] = '\0';
1315 * Free the value, by calling and popping the cleanup
1318 CLEANUP_CALL_AND_POP;
1322 /* Returns index of header tag in headers */
1324 find_header_hf_value(tvbuff_t *tvb, int offset, guint header_len)
1328 for (i = 0; i < array_length(headers); i++) {
1329 if (header_len == strlen(headers[i].name) &&
1330 tvb_strncaseeql(tvb, offset,
1331 headers[i].name, header_len) == 0)
1339 * Dissect Microsoft's abomination called NTLMSSP over HTTP.
1342 check_auth_ntlmssp(proto_item *hdr_item, tvbuff_t *tvb, packet_info *pinfo,
1345 static const char *ntlm_headers[] = {
1350 const char **header;
1352 proto_tree *hdr_tree;
1355 * Check for NTLM credentials and challenge; those can
1356 * occur with WWW-Authenticate.
1358 for (header = &ntlm_headers[0]; *header != NULL; header++) {
1359 hdrlen = strlen(*header);
1360 if (strncmp(value, *header, hdrlen) == 0) {
1361 if (hdr_item != NULL) {
1362 hdr_tree = proto_item_add_subtree(hdr_item,
1367 dissect_http_ntlmssp(tvb, pinfo, hdr_tree, value);
1375 * Dissect HTTP Basic authorization.
1378 check_auth_basic(proto_item *hdr_item, tvbuff_t *tvb, gchar *value)
1380 static const char *basic_headers[] = {
1384 const char **header;
1386 proto_tree *hdr_tree;
1389 for (header = &basic_headers[0]; *header != NULL; header++) {
1390 hdrlen = strlen(*header);
1391 if (strncmp(value, *header, hdrlen) == 0) {
1392 if (hdr_item != NULL) {
1393 hdr_tree = proto_item_add_subtree(hdr_item,
1399 len = base64_decode(value);
1401 proto_tree_add_string(hdr_tree, hf_http_basic, tvb,
1411 dissect_http(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1416 while (tvb_reported_length_remaining(tvb, offset) != 0) {
1417 len = dissect_http_message(tvb, offset, pinfo, tree);
1423 * OK, we've set the Protocol and Info columns for the
1424 * first HTTP message; make the columns non-writable,
1425 * so that we don't change it for subsequent HTTP messages.
1427 col_set_writable(pinfo->cinfo, FALSE);
1432 dissect_http_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1434 dissect_http_message(tvb, 0, pinfo, tree);
1438 proto_register_http(void)
1440 static hf_register_info hf[] = {
1441 { &hf_http_notification,
1442 { "Notification", "http.notification",
1443 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1444 "TRUE if HTTP notification", HFILL }},
1445 { &hf_http_response,
1446 { "Response", "http.response",
1447 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1448 "TRUE if HTTP response", HFILL }},
1450 { "Request", "http.request",
1451 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1452 "TRUE if HTTP request", HFILL }},
1454 { "Credentials", "http.authbasic",
1455 FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
1456 { &hf_http_request_method,
1457 { "Request Method", "http.request.method",
1458 FT_STRING, BASE_NONE, NULL, 0x0,
1459 "HTTP Request Method", HFILL }},
1460 { &hf_http_response_code,
1461 { "Response Code", "http.response.code",
1462 FT_UINT16, BASE_DEC, NULL, 0x0,
1463 "HTTP Response Code", HFILL }},
1464 { &hf_http_authorization,
1465 { "Authorization", "http.authorization",
1466 FT_STRING, BASE_NONE, NULL, 0x0,
1467 "HTTP Authorization header", HFILL }},
1468 { &hf_http_proxy_authenticate,
1469 { "Proxy-Authenticate", "http.proxy_authenticate",
1470 FT_STRING, BASE_NONE, NULL, 0x0,
1471 "HTTP Proxy-Authenticate header", HFILL }},
1472 { &hf_http_proxy_authorization,
1473 { "Proxy-Authorization", "http.proxy_authorization",
1474 FT_STRING, BASE_NONE, NULL, 0x0,
1475 "HTTP Proxy-Authorization header", HFILL }},
1476 { &hf_http_www_authenticate,
1477 { "WWW-Authenticate", "http.www_authenticate",
1478 FT_STRING, BASE_NONE, NULL, 0x0,
1479 "HTTP WWW-Authenticate header", HFILL }},
1480 { &hf_http_content_type,
1481 { "Content-Type", "http.content_type",
1482 FT_STRING, BASE_NONE, NULL, 0x0,
1483 "HTTP Content-Type header", HFILL }},
1484 { &hf_http_content_length,
1485 { "Content-Length", "http.content_length",
1486 FT_STRING, BASE_NONE, NULL, 0x0,
1487 "HTTP Content-Length header", HFILL }},
1488 { &hf_http_content_encoding,
1489 { "Content-Encoding", "http.content_encoding",
1490 FT_STRING, BASE_NONE, NULL, 0x0,
1491 "HTTP Content-Encoding header", HFILL }},
1492 { &hf_http_transfer_encoding,
1493 { "Transfer-Encoding", "http.transfer_encoding",
1494 FT_STRING, BASE_NONE, NULL, 0x0,
1495 "HTTP Transfer-Encoding header", HFILL }},
1497 static gint *ett[] = {
1501 &ett_http_chunked_response,
1502 &ett_http_chunk_data,
1503 &ett_http_encoded_entity,
1505 module_t *http_module;
1507 proto_http = proto_register_protocol("Hypertext Transfer Protocol",
1509 proto_register_field_array(proto_http, hf, array_length(hf));
1510 proto_register_subtree_array(ett, array_length(ett));
1511 http_module = prefs_register_protocol(proto_http, NULL);
1512 prefs_register_bool_preference(http_module, "desegment_headers",
1513 "Desegment all HTTP headers spanning multiple TCP segments",
1514 "Whether the HTTP dissector should desegment all headers "
1515 "of a request spanning multiple TCP segments",
1516 &http_desegment_headers);
1517 prefs_register_bool_preference(http_module, "desegment_body",
1518 "Desegment HTTP bodies spanning multiple TCP segments",
1519 "Whether the HTTP dissector should use the "
1520 "\"Content-length:\" value, if present, to desegment "
1521 "the body of a request spanning multiple TCP segments, "
1522 "and desegment chunked data spanning multiple TCP segments",
1523 &http_desegment_body);
1525 http_handle = create_dissector_handle(dissect_http, proto_http);
1528 * Dissectors shouldn't register themselves in this table;
1529 * instead, they should call "http_dissector_add()", and
1530 * we'll register the port number they specify as a port
1531 * for HTTP, and register them in our subdissector table.
1533 * This only works for protocols such as IPP that run over
1534 * HTTP on a specific non-HTTP port.
1536 port_subdissector_table = register_dissector_table("http.port",
1537 "TCP port for protocols using HTTP", FT_UINT16, BASE_DEC);
1540 * Dissectors can register themselves in this table.
1541 * It's just "media_type", not "http.content_type", because
1542 * it's an Internet media type, usable by other protocols as well.
1544 media_type_subdissector_table =
1545 register_dissector_table("media_type",
1546 "Internet media type", FT_STRING, BASE_NONE);
1549 * Heuristic dissectors SHOULD register themselves in
1550 * this table using the standard heur_dissector_add()
1553 register_heur_dissector_list("http", &heur_subdissector_list);
1556 * Register for tapping
1558 http_tap = register_tap("http");
1562 * Called by dissectors for protocols that run atop HTTP/TCP.
1565 http_dissector_add(guint32 port, dissector_handle_t handle)
1568 * Register ourselves as the handler for that port number
1571 dissector_add("tcp.port", port, http_handle);
1574 * And register them in *our* table for that port.
1576 dissector_add("http.port", port, handle);
1580 proto_reg_handoff_http(void)
1582 dissector_handle_t http_udp_handle;
1584 data_handle = find_dissector("data");
1585 media_handle = find_dissector("media");
1587 dissector_add("tcp.port", TCP_PORT_HTTP, http_handle);
1588 dissector_add("tcp.port", TCP_ALT_PORT_HTTP, http_handle);
1589 dissector_add("tcp.port", TCP_PORT_PROXY_HTTP, http_handle);
1590 dissector_add("tcp.port", TCP_PORT_PROXY_ADMIN_HTTP, http_handle);
1593 * XXX - is there anything to dissect in the body of an SSDP
1594 * request or reply? I.e., should there be an SSDP dissector?
1596 dissector_add("tcp.port", TCP_PORT_SSDP, http_handle);
1597 http_udp_handle = create_dissector_handle(dissect_http_udp, proto_http);
1598 dissector_add("udp.port", UDP_PORT_SSDP, http_udp_handle);
1600 ntlmssp_handle = find_dissector("ntlmssp");
1604 * Content-Type: message/http
1607 static gint proto_message_http = -1;
1608 static gint ett_message_http = -1;
1609 static dissector_handle_t message_http_handle;
1612 dissect_message_http(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1614 proto_tree *subtree;
1616 gint offset = 0, next_offset;
1619 if (check_col(pinfo->cinfo, COL_INFO))
1620 col_append_str(pinfo->cinfo, COL_INFO, " (message/http)");
1622 ti = proto_tree_add_item(tree, proto_message_http,
1624 subtree = proto_item_add_subtree(ti, ett_message_http);
1625 while (tvb_reported_length_remaining(tvb, offset) != 0) {
1626 len = tvb_find_line_end(tvb, offset,
1627 tvb_ensure_length_remaining(tvb, offset),
1628 &next_offset, FALSE);
1631 proto_tree_add_text(subtree, tvb, offset, next_offset - offset,
1632 "%s", tvb_format_text(tvb, offset, len));
1633 offset = next_offset;
1639 proto_register_message_http(void)
1641 static gint *ett[] = {
1645 proto_message_http = proto_register_protocol(
1646 "Media Type: message/http",
1650 proto_register_subtree_array(ett, array_length(ett));
1651 message_http_handle = create_dissector_handle(dissect_message_http,
1652 proto_message_http);
1656 proto_reg_handoff_message_http(void)
1658 message_http_handle = create_dissector_handle(dissect_message_http,
1659 proto_message_http);
1661 dissector_add_string("media_type", "message/http", message_http_handle);