From Jerry Talkington:

- Helper functions for uncompressing compressed tvbuffers.

	- Compressed content coding dissection in HTTP.

svn path=/trunk/; revision=10799
This commit is contained in:
Olivier Biot 2004-05-05 06:55:09 +00:00
parent ed22e7941f
commit 659ac78357
4 changed files with 335 additions and 22 deletions

View File

@ -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

View 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>
*
@ -41,6 +41,10 @@
#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

View 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__ */

View 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;
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);
if (http_decompress_body &&
(strcasecmp(headers.content_encoding, "gzip") == 0 ||
strcasecmp(headers.content_encoding, "deflate")
== 0)) {
goto body_dissected;
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 {
proto_item *e_ti = NULL;
proto_tree *e_tree = NULL;
if (chunks_decoded > 1) {
tvb_set_child_real_data_tvbuff(tvb,
next_tvb);
add_new_data_source(pinfo, next_tvb,
"Entity body");
}
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);