EPL: Fix segmented transfer complete detection
[metze/wireshark/wip.git] / epan / tvbuff_zlib.c
1 /* tvbuff_zlib.c
2  *
3  * Copyright (c) 2000 by Gilbert Ramirez <gram@alumni.rice.edu>
4  *
5  * Wireshark - Network traffic analyzer
6  * By Gerald Combs <gerald@wireshark.org>
7  * Copyright 1998 Gerald Combs
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22  */
23
24 #include "config.h"
25
26 #include <glib.h>
27
28 #include <string.h>
29
30 #ifdef HAVE_LIBZ
31 #define ZLIB_CONST
32 #include <zlib.h>
33 #endif
34
35 #include "tvbuff.h"
36
37 #ifdef HAVE_LIBZ
38 /*
39  * Uncompresses a zlib compressed packet inside a message of tvb at offset with
40  * length comprlen.  Returns an uncompressed tvbuffer if uncompression
41  * succeeded or NULL if uncompression failed.
42  */
43 #define TVB_Z_MIN_BUFSIZ 32768
44 #define TVB_Z_MAX_BUFSIZ 1048576 * 10
45 /* #define TVB_Z_DEBUG 1 */
46 #undef TVB_Z_DEBUG
47
48 tvbuff_t *
49 tvb_uncompress(tvbuff_t *tvb, const int offset, int comprlen)
50 {
51         gint       err;
52         guint      bytes_out      = 0;
53         guint8    *compr;
54         guint8    *uncompr        = NULL;
55         tvbuff_t  *uncompr_tvb    = NULL;
56         z_streamp  strm;
57         Bytef     *strmbuf;
58         guint      inits_done     = 0;
59         gint       wbits          = MAX_WBITS;
60         guint8    *next;
61         guint      bufsiz;
62 #ifdef TVB_Z_DEBUG
63         guint      inflate_passes = 0;
64         guint      bytes_in       = tvb_captured_length_remaining(tvb, offset);
65 #endif
66
67         if (tvb == NULL) {
68                 return NULL;
69         }
70
71         compr = (guint8 *)tvb_memdup(NULL, tvb, offset, comprlen);
72
73         if (!compr)
74                 return NULL;
75
76         /*
77          * Assume that the uncompressed data is at least twice as big as
78          * the compressed size.
79          */
80         bufsiz = tvb_captured_length_remaining(tvb, offset) * 2;
81         bufsiz = CLAMP(bufsiz, TVB_Z_MIN_BUFSIZ, TVB_Z_MAX_BUFSIZ);
82
83 #ifdef TVB_Z_DEBUG
84         printf("bufsiz: %u bytes\n", bufsiz);
85 #endif
86
87         next = compr;
88
89         strm            = g_new0(z_stream, 1);
90         strm->next_in   = next;
91         strm->avail_in  = comprlen;
92
93         strmbuf         = (Bytef *)g_malloc0(bufsiz);
94         strm->next_out  = strmbuf;
95         strm->avail_out = bufsiz;
96
97         err = inflateInit2(strm, wbits);
98         inits_done = 1;
99         if (err != Z_OK) {
100                 inflateEnd(strm);
101                 g_free(strm);
102                 g_free(compr);
103                 g_free(strmbuf);
104                 return NULL;
105         }
106
107         while (1) {
108                 memset(strmbuf, '\0', bufsiz);
109                 strm->next_out  = strmbuf;
110                 strm->avail_out = bufsiz;
111
112                 err = inflate(strm, Z_SYNC_FLUSH);
113
114                 if (err == Z_OK || err == Z_STREAM_END) {
115                         guint bytes_pass = bufsiz - strm->avail_out;
116
117 #ifdef TVB_Z_DEBUG
118                         ++inflate_passes;
119 #endif
120
121                         if (uncompr == NULL) {
122                                 /*
123                                  * This is ugly workaround for bug #6480
124                                  * (https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=6480)
125                                  *
126                                  * g_memdup(..., 0) returns NULL (g_malloc(0) also)
127                                  * when uncompr is NULL logic below doesn't create tvb
128                                  * which is later interpreted as decompression failed.
129                                  */
130                                 uncompr = (guint8 *)((bytes_pass || err != Z_STREAM_END) ?
131                                                 g_memdup(strmbuf, bytes_pass) :
132                                                 g_strdup(""));
133                         } else {
134                                 guint8 *new_data = (guint8 *)g_malloc0(bytes_out + bytes_pass);
135
136                                 memcpy(new_data, uncompr, bytes_out);
137                                 memcpy(new_data + bytes_out, strmbuf, bytes_pass);
138
139                                 g_free(uncompr);
140                                 uncompr = new_data;
141                         }
142
143                         bytes_out += bytes_pass;
144
145                         if (err == Z_STREAM_END) {
146                                 inflateEnd(strm);
147                                 g_free(strm);
148                                 g_free(strmbuf);
149                                 break;
150                         }
151                 } else if (err == Z_BUF_ERROR) {
152                         /*
153                          * It's possible that not enough frames were captured
154                          * to decompress this fully, so return what we've done
155                          * so far, if any.
156                          */
157                         inflateEnd(strm);
158                         g_free(strm);
159                         g_free(strmbuf);
160
161                         if (uncompr != NULL) {
162                                 break;
163                         } else {
164                                 g_free(compr);
165                                 return NULL;
166                         }
167
168                 } else if (err == Z_DATA_ERROR && inits_done == 1
169                         && uncompr == NULL && comprlen >= 2 &&
170                         (*compr  == 0x1f) && (*(compr + 1) == 0x8b)) {
171                         /*
172                          * inflate() is supposed to handle both gzip and deflate
173                          * streams automatically, but in reality it doesn't
174                          * seem to handle either (at least not within the
175                          * context of an HTTP response.)  We have to try
176                          * several tweaks, depending on the type of data and
177                          * version of the library installed.
178                          */
179
180                         /*
181                          * Gzip file format.  Skip past the header, since the
182                          * fix to make it work (setting windowBits to 31)
183                          * doesn't work with all versions of the library.
184                          */
185                         Bytef *c = compr + 2;
186                         Bytef  flags = 0;
187
188                         /* we read two bytes already (0x1f, 0x8b) and
189                            need at least Z_DEFLATED, 1 byte flags, 4
190                            bytes MTIME, 1 byte XFL, 1 byte OS */
191                         if (comprlen < 10 || *c != Z_DEFLATED) {
192                                 inflateEnd(strm);
193                                 g_free(strm);
194                                 g_free(compr);
195                                 g_free(strmbuf);
196                                 return NULL;
197                         }
198
199                         c++;
200                         flags = *c;
201                         c++;
202
203                         /* Skip past the MTIME (4 bytes),
204                            XFL, and OS fields (1 byte each). */
205                         c += 6;
206
207                         if (flags & (1 << 2)) {
208                                 /* An Extra field is present. It
209                                    consists of 2 bytes xsize and xsize
210                                    bytes of data.
211                                    Read byte-by-byte (least significant
212                                    byte first) to make sure we abort
213                                    cleanly when the xsize is truncated
214                                    after the first byte. */
215                                 guint16 xsize = 0;
216
217                                 if (c-compr < comprlen) {
218                                         xsize += *c;
219                                         c++;
220                                 }
221                                 if (c-compr < comprlen) {
222                                         xsize += *c << 8;
223                                         c++;
224                                 }
225
226                                 c += xsize;
227                         }
228
229                         if (flags & (1 << 3)) {
230                                 /* A null terminated filename */
231
232                                 while ((c - compr) < comprlen && *c != '\0') {
233                                         c++;
234                                 }
235
236                                 c++;
237                         }
238
239                         if (flags & (1 << 4)) {
240                                 /* A null terminated comment */
241
242                                 while ((c - compr) < comprlen && *c != '\0') {
243                                         c++;
244                                 }
245
246                                 c++;
247                         }
248
249
250                         if (c - compr > comprlen) {
251                                 inflateEnd(strm);
252                                 g_free(strm);
253                                 g_free(compr);
254                                 g_free(strmbuf);
255                                 return NULL;
256                         }
257                         /* Drop gzip header */
258                         comprlen -= (int) (c - compr);
259                         next = c;
260
261                         inflateReset(strm);
262                         strm->next_in   = next;
263                         strm->avail_in  = comprlen;
264
265                         inflateEnd(strm);
266                         inflateInit2(strm, wbits);
267                         inits_done++;
268                 } else if (err == Z_DATA_ERROR && uncompr == NULL &&
269                         inits_done <= 3) {
270
271                         /*
272                          * Re-init the stream with a negative
273                          * MAX_WBITS. This is necessary due to
274                          * some servers (Apache) not sending
275                          * the deflate header with the
276                          * content-encoded response.
277                          */
278                         wbits = -MAX_WBITS;
279
280                         inflateReset(strm);
281
282                         strm->next_in   = next;
283                         strm->avail_in  = comprlen;
284
285                         inflateEnd(strm);
286                         memset(strmbuf, '\0', bufsiz);
287                         strm->next_out  = strmbuf;
288                         strm->avail_out = bufsiz;
289
290                         err = inflateInit2(strm, wbits);
291
292                         inits_done++;
293
294                         if (err != Z_OK) {
295                                 g_free(strm);
296                                 g_free(strmbuf);
297                                 g_free(compr);
298                                 g_free(uncompr);
299
300                                 return NULL;
301                         }
302                 } else {
303                         inflateEnd(strm);
304                         g_free(strm);
305                         g_free(strmbuf);
306
307                         if (uncompr == NULL) {
308                                 g_free(compr);
309                                 return NULL;
310                         }
311
312                         break;
313                 }
314         }
315
316 #ifdef TVB_Z_DEBUG
317         printf("inflate() total passes: %u\n", inflate_passes);
318         printf("bytes  in: %u\nbytes out: %u\n\n", bytes_in, bytes_out);
319 #endif
320
321         if (uncompr != NULL) {
322                 uncompr_tvb =  tvb_new_real_data((guint8*) uncompr, bytes_out, bytes_out);
323                 tvb_set_free_cb(uncompr_tvb, g_free);
324         }
325         g_free(compr);
326         return uncompr_tvb;
327 }
328 #else
329 tvbuff_t *
330 tvb_uncompress(tvbuff_t *tvb _U_, const int offset _U_, int comprlen _U_)
331 {
332         return NULL;
333 }
334 #endif
335
336 tvbuff_t *
337 tvb_child_uncompress(tvbuff_t *parent, tvbuff_t *tvb, const int offset, int comprlen)
338 {
339         tvbuff_t *new_tvb = tvb_uncompress(tvb, offset, comprlen);
340         if (new_tvb)
341                 tvb_set_child_real_data_tvbuff (parent, new_tvb);
342         return new_tvb;
343 }
344
345 /*
346  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
347  *
348  * Local variables:
349  * c-basic-offset: 8
350  * tab-width: 8
351  * indent-tabs-mode: t
352  * End:
353  *
354  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
355  * :indentSize=8:tabSize=8:noTabs=false:
356  */