From Jerry Talkington:
authorobiot <obiot@f5534014-38df-0310-8fa8-9805f1628bb7>
Wed, 5 May 2004 06:55:09 +0000 (06:55 +0000)
committerobiot <obiot@f5534014-38df-0310-8fa8-9805f1628bb7>
Wed, 5 May 2004 06:55:09 +0000 (06:55 +0000)
- Helper functions for uncompressing compressed tvbuffers.

- Compressed content coding dissection in HTTP.

git-svn-id: http://anonsvn.wireshark.org/wireshark/trunk@10799 f5534014-38df-0310-8fa8-9805f1628bb7

AUTHORS
epan/tvbuff.c
epan/tvbuff.h
packet-http.c

diff --git a/AUTHORS b/AUTHORS
index cffef98170878f244fd2663678c27187720f8d90..7918ce5a6b12bbe8ab1f3c204c1d36982701f6bc 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -286,6 +286,7 @@ Greg Hankins <gregh[AT]twoguys.org> {
 }
 
 Jerry Talkington <jtalkington[AT]users.sourceforge.net> {
+       tvb_uncompress()/HTTP Content-Encoding decompression
        HTTP chunked encoding dissection
        updates to HTTP support
        Filter selection/editing GUI improvements
index c3511c3ba0f5ed970ebc3659b198a139bcf7700b..c1ba9b806ef88cc95d7841442fd9dbfb1e11b833 100644 (file)
@@ -9,7 +9,7 @@
  *             the data of a backing tvbuff, or can be a composite of
  *             other tvbuffs.
  *
- * $Id: tvbuff.c,v 1.61 2004/03/23 18:06:29 guy Exp $
+ * $Id: tvbuff.c,v 1.62 2004/05/05 06:55:09 obiot Exp $
  *
  * Copyright (c) 2000 by Gilbert Ramirez <gram@alumni.rice.edu>
  *
 
 #include <string.h>
 
+#ifdef HAVE_LIBZ
+#include <zlib.h>
+#endif
+
 #include "pint.h"
 #include "tvbuff.h"
 #include "strutil.h"
@@ -2149,3 +2153,242 @@ tvb_find_tvb(tvbuff_t *haystack_tvb, tvbuff_t *needle_tvb, gint haystack_offset)
 
        return -1;
 }
+
+#ifdef HAVE_LIBZ
+/*
+ * Uncompresses a zlib compressed packet inside a message of tvb at offset with
+ * length comprlen.  Returns an uncompressed tvbuffer if uncompression
+ * succeeded or NULL if uncompression failed.
+ */
+#define TVB_Z_BUFSIZ 4096
+tvbuff_t *
+tvb_uncompress(tvbuff_t *tvb, int offset, int comprlen)
+{
+       
+
+       gint err = Z_OK;
+       gint bytes_out = 0;
+       guint8 *compr = NULL;
+       guint8 *uncompr = NULL;
+       tvbuff_t *uncompr_tvb = NULL;
+       z_streamp strm = NULL;
+       gchar strmbuf[TVB_Z_BUFSIZ];
+       gint inits_done = 0;
+       gint wbits = MAX_WBITS;
+       guint8 *next = NULL;
+
+       strm = g_malloc0(sizeof(z_stream));
+
+       if (strm == NULL) {
+               return NULL;
+       }
+
+       compr = tvb_memdup(tvb, offset, comprlen);
+
+       if (!compr) {
+               return NULL;
+       }
+
+       next = compr;
+
+       strm->next_in = next;
+       strm->avail_in = comprlen;
+
+       memset(&strmbuf, 0, TVB_Z_BUFSIZ);
+       strm->next_out = (Bytef *)&strmbuf;
+       strm->avail_out = TVB_Z_BUFSIZ;
+
+       err = inflateInit2(strm, wbits);
+       inits_done = 1;
+       if (err != Z_OK) {
+               g_free(strm);
+               g_free(compr);
+               return NULL;
+       }
+
+       while (1) {
+               memset(&strmbuf, 0, TVB_Z_BUFSIZ);
+               strm->next_out = (Bytef *)&strmbuf;
+               strm->avail_out = TVB_Z_BUFSIZ;
+
+               err = inflate(strm, Z_SYNC_FLUSH);
+
+               if (err == Z_OK || err == Z_STREAM_END) {
+                       guint bytes_pass = TVB_Z_BUFSIZ - strm->avail_out;
+
+                       if (uncompr == NULL) {
+                               uncompr = g_memdup(&strmbuf, bytes_pass);
+                       } else {
+                               guint8 *new_data = g_malloc0(bytes_out +
+                                   bytes_pass);
+
+                               if (new_data == NULL) {
+                                       g_free(strm);
+                                       g_free(compr);
+
+                                       if (uncompr != NULL) {
+                                               g_free(uncompr);
+                                       }
+                                       
+                                       return NULL;
+                               }
+                               
+                               g_memmove(new_data, uncompr, bytes_out);
+                               g_memmove((new_data + bytes_out), &strmbuf,
+                                   bytes_pass);
+
+                               g_free(uncompr);
+                               uncompr = new_data;
+                       }
+
+                       bytes_out += bytes_pass;
+
+                       if ( err == Z_STREAM_END) {
+                               inflateEnd(strm);
+                               g_free(strm);
+                               break;
+                       }
+               } else if (err == Z_BUF_ERROR) {
+                       /*
+                        * It's possible that not enough frames were captured
+                        * to decompress this fully, so return what we've done
+                        * so far, if any.
+                        */
+
+                       g_free(strm);
+
+                       if (uncompr != NULL) {
+                               break;
+                       } else {
+                               g_free(compr);
+                               return NULL;
+                       }
+                       
+               } else if (err == Z_DATA_ERROR && inits_done == 1
+                   && uncompr == NULL && (*compr  == 0x1f) &&
+                   (*(compr + 1) == 0x8b)) {
+                       /*
+                        * inflate() is supposed to handle both gzip and deflate
+                        * streams automatically, but in reality it doesn't
+                        * seem to handle either (at least not within the
+                        * context of an HTTP response.)  We have to try
+                        * several tweaks, depending on the type of data and
+                        * version of the library installed.
+                        */
+
+                       /*
+                        * Gzip file format.  Skip past the header, since the
+                        * fix to make it work (setting windowBits to 31)
+                        * doesn't work with all versions of the library.
+                        */
+                       Bytef *c = compr + 2;
+                       Bytef flags = 0;
+
+                       if (*c == Z_DEFLATED) {
+                               c++;
+                       } else {
+                               g_free(strm);
+                               g_free(compr);
+                               return NULL;
+                       }
+
+                       flags = *c;
+
+                       /* Skip past the MTIME, XFL, and OS fields. */
+                       c += 7;
+
+                       if (flags & 0x2) {
+                               /* An Extra field is present. */
+                               gint xsize = (gint)(*c |
+                                   (*(c + 1) << 8));
+
+                               c += xsize;
+                       }
+
+                       if (flags & 0x3) {
+                               /* A null terminated filename */
+
+                               while (*c != NULL) {
+                                       c++;
+                               }
+
+                               c++;
+                       }
+
+                       if (flags & 0x4) {
+                               /* A null terminated comment */
+                               
+                               while (*c != NULL) {
+                                       c++;
+                               }
+
+                               c++;
+                       }
+
+
+                       inflateReset(strm);
+                       next = c;
+                       strm->next_in = next;
+                       comprlen -= (c - compr);
+                       
+                       err = inflateInit2(strm, wbits);
+                       inits_done++;
+               } else if (err == Z_DATA_ERROR && uncompr == NULL &&
+                   inits_done <= 3) {
+                       
+                       /* 
+                        * Re-init the stream with a negative
+                        * MAX_WBITS. This is necessary due to
+                        * some servers (Apache) not sending
+                        * the deflate header with the
+                        * content-encoded response.
+                        */
+                       wbits = -MAX_WBITS;
+
+                       inflateReset(strm);
+
+                       strm->next_in = next;
+                       strm->avail_in = comprlen;
+
+                       memset(&strmbuf, 0, TVB_Z_BUFSIZ);
+                       strm->next_out = (Bytef *)&strmbuf;
+                       strm->avail_out = TVB_Z_BUFSIZ;
+
+                       err = inflateInit2(strm, wbits);
+                               
+                       inits_done++;
+                       
+                       if (err != Z_OK) {
+                               g_free(strm);
+                               g_free(compr);
+                               g_free(uncompr);
+
+                               return NULL;
+                       }
+               } else {
+                       g_free(strm);
+                       g_free(compr);
+
+                       if (uncompr == NULL) {
+                               return NULL;
+                       }
+
+                       break;
+               }
+       }
+       
+       if (uncompr != NULL) {
+               uncompr_tvb =  tvb_new_real_data((guint8*) uncompr, bytes_out,
+                   bytes_out);
+       }
+       g_free(compr);
+       return uncompr_tvb;
+}
+#else
+tvbuff_t *
+tvb_uncompress(tvbuff_t *tvb _U_, int offset _U_, int comprlen _U_)
+{
+       return NULL;
+}
+#endif
+
index bf9715dc32756950ecad7604049c210dd5534bf4..7fff54d325f40ef3db4b14106146887edeb0eb6d 100644 (file)
@@ -9,7 +9,7 @@
  *             the data of a backing tvbuff, or can be a composite of
  *             other tvbuffs.
  *
- * $Id: tvbuff.h,v 1.41 2004/03/23 18:06:29 guy Exp $
+ * $Id: tvbuff.h,v 1.42 2004/05/05 06:55:09 obiot Exp $
  *
  * Copyright (c) 2000 by Gilbert Ramirez <gram@alumni.rice.edu>
  *
@@ -513,6 +513,13 @@ extern gchar *tvb_bytes_to_str(tvbuff_t *tvb, gint offset, gint len);
 extern gint tvb_find_tvb(tvbuff_t *haystack_tvb, tvbuff_t *needle_tvb,
        gint haystack_offset);
 
+/*
+ * Uncompresses a zlib compressed packet inside a tvbuff at offset with
+ * length comprlen.  Returns an uncompressed tvbuffer if uncompression
+ * succeeded or NULL if uncompression failed.
+ */
+extern tvbuff_t* tvb_uncompress(tvbuff_t *tvb, int offset, int comprlen);
+
 /************** END OF ACCESSORS ****************/
 
 #endif /* __TVBUFF_H__ */
index da505dcab38a011f6cb43911dfd5a72f32cdd79e..8f61b592a02dca7bae9f824f1b092696e2f9a79c 100644 (file)
@@ -7,7 +7,7 @@
  * Copyright 2002, Tim Potter <tpot@samba.org>
  * Copyright 1999, Andrew Tridgell <tridge@samba.org>
  *
- * $Id: packet-http.c,v 1.102 2004/05/04 07:12:03 guy Exp $
+ * $Id: packet-http.c,v 1.103 2004/05/05 06:55:09 obiot Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@ethereal.com>
@@ -95,6 +95,21 @@ static gboolean http_desegment_headers = FALSE;
  */
 static gboolean http_desegment_body = FALSE;
 
+/*
+ * De-chunking of content-encoding: chunk entity bodies.
+ */
+static gboolean http_dechunk_body = TRUE;
+
+/*
+ * Decompression of zlib encoded entities.
+ */
+#ifdef HAVE_LIBZ
+static gboolean http_decompress_body = TRUE;
+#else
+static gboolean http_decompress_body = FALSE;
+#endif
+
+
 #define TCP_PORT_HTTP                  80
 #define TCP_PORT_PROXY_HTTP            3128
 #define TCP_PORT_PROXY_ADMIN_HTTP      3132
@@ -620,8 +635,9 @@ dissect_http_message(tvbuff_t *tvb, int offset, packet_info *pinfo,
                 */
                if (headers.transfer_encoding != NULL &&
                    strcasecmp(headers.transfer_encoding, "identity") != 0) {
-                       if (strcasecmp(headers.transfer_encoding, "chunked")
-                           == 0) {
+                       if (http_dechunk_body &&
+                           (strcasecmp(headers.transfer_encoding, "chunked")
+                           == 0)) {
 
                                chunks_decoded = chunked_encoding_dissector(
                                    &next_tvb, pinfo, http_tree, 0);
@@ -655,23 +671,60 @@ dissect_http_message(tvbuff_t *tvb, int offset, packet_info *pinfo,
                if (headers.content_encoding != NULL &&
                    strcasecmp(headers.content_encoding, "identity") != 0) {
                        /*
-                        * We currently can't handle, for example, "gzip",
-                        * "compress", or "deflate"; just handle them as
-                        * data for now.
+                        * We currently can't handle, for example, "compress";
+                        * just handle them as data for now.
+                        * 
+                        * After July 7, 2004 the LZW patent expires, so support
+                        * might be added then.  However, I don't think that
+                        * anybody ever really implemented "compress", due to
+                        * the aformentioned patent.
                         */
-                       proto_item *e_ti = NULL;
-                       proto_tree *e_tree = NULL;
+                       tvbuff_t *uncomp_tvb = NULL;
+
+                       if (http_decompress_body &&
+                           (strcasecmp(headers.content_encoding, "gzip") == 0 ||
+                           strcasecmp(headers.content_encoding, "deflate")
+                           == 0)) {
+                       
+                               uncomp_tvb = tvb_uncompress(next_tvb, 0,
+                                   tvb_length(next_tvb));
+                       }
+
+                       if (uncomp_tvb != NULL) {
+                               /*
+                                * Decompression worked
+                                */
+                               tvb_free(next_tvb);
+                               next_tvb = uncomp_tvb;
+                               
+                               tvb_set_child_real_data_tvbuff(tvb, next_tvb);
+                               add_new_data_source(pinfo, next_tvb, 
+                                   "Entity body");
+                       } else {
 
-                       e_ti = proto_tree_add_text(http_tree, next_tvb, 0,
-                           tvb_length(next_tvb), "Encoded entity-body (%s)",
-                           headers.content_encoding);
+                               proto_item *e_ti = NULL;
+                               proto_tree *e_tree = NULL;
 
-                       e_tree = proto_item_add_subtree(e_ti,
-                           ett_http_encoded_entity);
+                               if (chunks_decoded > 1) {
+                                       tvb_set_child_real_data_tvbuff(tvb,
+                                           next_tvb);
+                                       add_new_data_source(pinfo, next_tvb,
+                                           "Entity body");
+                               }
 
-                       call_dissector(data_handle, next_tvb, pinfo, e_tree);
-                       
-                       goto body_dissected;
+                               e_ti = proto_tree_add_text(http_tree,
+                                   next_tvb, 0, tvb_length(next_tvb),
+                                   "Encoded entity-body (%s)",
+                                   headers.content_encoding);
+
+                               e_tree = proto_item_add_subtree(e_ti,
+                                   ett_http_encoded_entity);
+
+                               call_dissector(data_handle, next_tvb, pinfo,
+                                   e_tree);
+                               
+                               goto body_dissected;
+                       }
                }
 
                /*
@@ -958,9 +1011,6 @@ chunked_encoding_dissector(tvbuff_t **tvb_ptr, packet_info *pinfo,
                / * tvb_set_reported_length(new_tvb, chunked_data_size); * /
                */
 
-               tvb_set_child_real_data_tvbuff(tvb, new_tvb);
-               add_new_data_source(pinfo, new_tvb, "De-chunked entity body");
-
                tvb_free(*tvb_ptr);
                *tvb_ptr = new_tvb;
                
@@ -1521,6 +1571,18 @@ proto_register_http(void)
            "the body of a request spanning multiple TCP segments, "
            "and desegment chunked data spanning multiple TCP segments",
            &http_desegment_body);
+       prefs_register_bool_preference(http_module, "dechunk_body",
+           "Reassemble chunked transfer-coded bodies",
+           "Whether to reassemble bodies of entities that are transfered "
+           "using the \"Transfer-Encoding: chunked\" method",
+           &http_dechunk_body);
+#ifdef HAVE_LIBZ
+       prefs_register_bool_preference(http_module, "decompress_body",
+           "Uncompress entity bodies",
+           "Whether to uncompress entity bodies that are compressed "
+           "using \"Content-Encoding: \"",
+           &http_decompress_body);
+#endif
 
        http_handle = create_dissector_handle(dissect_http, proto_http);