- add sources.
[platform/framework/web/crosswalk.git] / src / net / tools / spdyshark / packet-spdy.c
1 /* packet-spdy.c
2  * Routines for SPDY packet disassembly
3  * For now, the protocol spec can be found at
4  * http://dev.chromium.org/spdy/spdy-protocol
5  *
6  * Copyright 2010, Google Inc.
7  * Eric Shienbrood <ers@google.com>
8  *
9  * $Id$
10  *
11  * Wireshark - Network traffic analyzer
12  * By Gerald Combs <gerald@wireshark.org>
13  * Copyright 1998 Gerald Combs
14  *
15  * Originally based on packet-http.c
16  *
17  * This program is free software; you can redistribute it and/or
18  * modify it under the terms of the GNU General Public License
19  * as published by the Free Software Foundation; either version 2
20  * of the License, or (at your option) any later version.
21  *
22  * This program is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25  * GNU General Public License for more details.
26  *
27  * You should have received a copy of the GNU General Public License
28  * along with this program; if not, write to the Free Software
29  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
30  */
31
32 #ifdef HAVE_CONFIG_H
33 #include "config.h"
34 #endif
35
36 #include <string.h>
37 #include <ctype.h>
38
39 #include <glib.h>
40 #include <epan/conversation.h>
41 #include <epan/packet.h>
42 #include <epan/strutil.h>
43 #include <epan/base64.h>
44 #include <epan/emem.h>
45 #include <epan/stats_tree.h>
46
47 #include <epan/req_resp_hdrs.h>
48 #include "packet-spdy.h"
49 #include <epan/dissectors/packet-tcp.h>
50 #include <epan/dissectors/packet-ssl.h>
51 #include <epan/prefs.h>
52 #include <epan/expert.h>
53 #include <epan/uat.h>
54
55 #define SPDY_FIN  0x01
56
57 /* The types of SPDY control frames */
58 typedef enum _spdy_type {
59         SPDY_DATA,
60         SPDY_SYN_STREAM,
61         SPDY_SYN_REPLY,
62         SPDY_FIN_STREAM,
63         SPDY_HELLO,
64         SPDY_NOOP,
65         SPDY_PING,
66         SPDY_INVALID
67 } spdy_frame_type_t;
68
69 static const char *frame_type_names[] = {
70   "DATA", "SYN_STREAM", "SYN_REPLY", "FIN_STREAM", "HELLO", "NOOP",
71   "PING", "INVALID"
72 };
73
74 /*
75  * This structure will be tied to each SPDY frame.
76  * Note that there may be multiple SPDY frames
77  * in one packet.
78  */
79 typedef struct _spdy_frame_info_t {
80     guint32 stream_id;
81     guint8 *header_block;
82     guint   header_block_len;
83     guint16 frame_type;
84 } spdy_frame_info_t;
85
86 /*
87  * This structures keeps track of all the data frames
88  * associated with a stream, so that they can be
89  * reassembled into a single chunk.
90  */
91 typedef struct _spdy_data_frame_t {
92     guint8 *data;
93     guint32 length;
94     guint32 framenum;
95 } spdy_data_frame_t;
96
97 typedef struct _spdy_stream_info_t {
98     gchar *content_type;
99     gchar *content_type_parameters;
100     gchar *content_encoding;
101     GSList *data_frames;
102     tvbuff_t *assembled_data;
103     guint num_data_frames;
104 } spdy_stream_info_t;
105
106 #include <epan/tap.h>
107
108
109 static int spdy_tap = -1;
110 static int spdy_eo_tap = -1;
111
112 static int proto_spdy = -1;
113 static int hf_spdy_syn_stream = -1;
114 static int hf_spdy_syn_reply = -1;
115 static int hf_spdy_control_bit = -1;
116 static int hf_spdy_version = -1;
117 static int hf_spdy_type = -1;
118 static int hf_spdy_flags = -1;
119 static int hf_spdy_flags_fin = -1;
120 static int hf_spdy_length = -1;
121 static int hf_spdy_header = -1;
122 static int hf_spdy_header_name = -1;
123 static int hf_spdy_header_name_text = -1;
124 static int hf_spdy_header_value = -1;
125 static int hf_spdy_header_value_text = -1;
126 static int hf_spdy_streamid = -1;
127 static int hf_spdy_associated_streamid = -1;
128 static int hf_spdy_priority = -1;
129 static int hf_spdy_num_headers = -1;
130 static int hf_spdy_num_headers_string = -1;
131
132 static gint ett_spdy = -1;
133 static gint ett_spdy_syn_stream = -1;
134 static gint ett_spdy_syn_reply = -1;
135 static gint ett_spdy_fin_stream = -1;
136 static gint ett_spdy_flags = -1;
137 static gint ett_spdy_header = -1;
138 static gint ett_spdy_header_name = -1;
139 static gint ett_spdy_header_value = -1;
140
141 static gint ett_spdy_encoded_entity = -1;
142
143 static dissector_handle_t data_handle;
144 static dissector_handle_t media_handle;
145 static dissector_handle_t spdy_handle;
146
147 /* Stuff for generation/handling of fields for custom HTTP headers */
148 typedef struct _header_field_t {
149         gchar* header_name;
150         gchar* header_desc;
151 } header_field_t;
152
153 /*
154  * desegmentation of SPDY control frames
155  * (when we are over TCP or another protocol providing the desegmentation API)
156  */
157 static gboolean spdy_desegment_control_frames = TRUE;
158
159 /*
160  * desegmentation of SPDY data frames bodies
161  * (when we are over TCP or another protocol providing the desegmentation API)
162  * TODO let the user filter on content-type the bodies he wants desegmented
163  */
164 static gboolean spdy_desegment_data_frames = TRUE;
165
166 static gboolean spdy_assemble_entity_bodies = TRUE;
167
168 /*
169  * Decompression of zlib encoded entities.
170  */
171 #ifdef HAVE_LIBZ
172 static gboolean spdy_decompress_body = TRUE;
173 static gboolean spdy_decompress_headers = TRUE;
174 #else
175 static gboolean spdy_decompress_body = FALSE;
176 static gboolean spdy_decompress_headers = FALSE;
177 #endif
178 static gboolean spdy_debug = FALSE;
179
180 #define TCP_PORT_DAAP                   3689
181
182 /*
183  * SSDP is implemented atop HTTP (yes, it really *does* run over UDP).
184  */
185 #define TCP_PORT_SSDP                   1900
186 #define UDP_PORT_SSDP                   1900
187
188 /*
189  * tcp and ssl ports
190  */
191
192 #define TCP_DEFAULT_RANGE "80,8080"
193 #define SSL_DEFAULT_RANGE "443"
194
195 static range_t *global_spdy_tcp_range = NULL;
196 static range_t *global_spdy_ssl_range = NULL;
197
198 static range_t *spdy_tcp_range = NULL;
199 static range_t *spdy_ssl_range = NULL;
200
201 static const value_string vals_status_code[] = {
202         { 100, "Continue" },
203         { 101, "Switching Protocols" },
204         { 102, "Processing" },
205         { 199, "Informational - Others" },
206
207         { 200, "OK"},
208         { 201, "Created"},
209         { 202, "Accepted"},
210         { 203, "Non-authoritative Information"},
211         { 204, "No Content"},
212         { 205, "Reset Content"},
213         { 206, "Partial Content"},
214         { 207, "Multi-Status"},
215         { 299, "Success - Others"},
216
217         { 300, "Multiple Choices"},
218         { 301, "Moved Permanently"},
219         { 302, "Found"},
220         { 303, "See Other"},
221         { 304, "Not Modified"},
222         { 305, "Use Proxy"},
223         { 307, "Temporary Redirect"},
224         { 399, "Redirection - Others"},
225
226         { 400, "Bad Request"},
227         { 401, "Unauthorized"},
228         { 402, "Payment Required"},
229         { 403, "Forbidden"},
230         { 404, "Not Found"},
231         { 405, "Method Not Allowed"},
232         { 406, "Not Acceptable"},
233         { 407, "Proxy Authentication Required"},
234         { 408, "Request Time-out"},
235         { 409, "Conflict"},
236         { 410, "Gone"},
237         { 411, "Length Required"},
238         { 412, "Precondition Failed"},
239         { 413, "Request Entity Too Large"},
240         { 414, "Request-URI Too Long"},
241         { 415, "Unsupported Media Type"},
242         { 416, "Requested Range Not Satisfiable"},
243         { 417, "Expectation Failed"},
244         { 418, "I'm a teapot"},         /* RFC 2324 */
245         { 422, "Unprocessable Entity"},
246         { 423, "Locked"},
247         { 424, "Failed Dependency"},
248         { 499, "Client Error - Others"},
249
250         { 500, "Internal Server Error"},
251         { 501, "Not Implemented"},
252         { 502, "Bad Gateway"},
253         { 503, "Service Unavailable"},
254         { 504, "Gateway Time-out"},
255         { 505, "HTTP Version not supported"},
256         { 507, "Insufficient Storage"},
257         { 599, "Server Error - Others"},
258
259         { 0,    NULL}
260 };
261
262 static const char spdy_dictionary[] =
263   "optionsgetheadpostputdeletetraceacceptaccept-charsetaccept-encodingaccept-"
264   "languageauthorizationexpectfromhostif-modified-sinceif-matchif-none-matchi"
265   "f-rangeif-unmodifiedsincemax-forwardsproxy-authorizationrangerefererteuser"
266   "-agent10010120020120220320420520630030130230330430530630740040140240340440"
267   "5406407408409410411412413414415416417500501502503504505accept-rangesageeta"
268   "glocationproxy-authenticatepublicretry-afterservervarywarningwww-authentic"
269   "ateallowcontent-basecontent-encodingcache-controlconnectiondatetrailertran"
270   "sfer-encodingupgradeviawarningcontent-languagecontent-lengthcontent-locati"
271   "oncontent-md5content-rangecontent-typeetagexpireslast-modifiedset-cookieMo"
272   "ndayTuesdayWednesdayThursdayFridaySaturdaySundayJanFebMarAprMayJunJulAugSe"
273   "pOctNovDecchunkedtext/htmlimage/pngimage/jpgimage/gifapplication/xmlapplic"
274   "ation/xhtmltext/plainpublicmax-agecharset=iso-8859-1utf-8gzipdeflateHTTP/1"
275   ".1statusversionurl";
276
277 static void reset_decompressors(void)
278 {
279     if (spdy_debug) printf("Should reset SPDY decompressors\n");
280 }
281
282 static spdy_conv_t *
283 get_spdy_conversation_data(packet_info *pinfo)
284 {
285     conversation_t  *conversation;
286     spdy_conv_t *conv_data;
287     int retcode;
288
289     conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
290     if (spdy_debug) {
291         printf("\n===========================================\n\n");
292         printf("Conversation for frame #%d is %p\n", pinfo->fd->num, conversation);
293         if (conversation)
294             printf("  conv_data=%p\n", conversation_get_proto_data(conversation, proto_spdy));
295     }
296
297     if(!conversation)  /* Conversation does not exist yet - create it */
298         conversation = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
299
300     /* Retrieve information from conversation
301     */
302     conv_data = conversation_get_proto_data(conversation, proto_spdy);
303     if(!conv_data) {
304         /* Setup the conversation structure itself */
305         conv_data = se_alloc0(sizeof(spdy_conv_t));
306
307         conv_data->streams = NULL;
308         if (spdy_decompress_headers) {
309             conv_data->rqst_decompressor = se_alloc0(sizeof(z_stream));
310             conv_data->rply_decompressor = se_alloc0(sizeof(z_stream));
311             retcode = inflateInit(conv_data->rqst_decompressor);
312             if (retcode == Z_OK)
313                 retcode = inflateInit(conv_data->rply_decompressor);
314             if (retcode != Z_OK)
315                 printf("frame #%d: inflateInit() failed: %d\n", pinfo->fd->num, retcode);
316             else if (spdy_debug)
317                 printf("created decompressor\n");
318             conv_data->dictionary_id = adler32(0L, Z_NULL, 0);
319             conv_data->dictionary_id = adler32(conv_data->dictionary_id,
320                                                spdy_dictionary,
321                                                sizeof(spdy_dictionary));
322         }
323
324         conversation_add_proto_data(conversation, proto_spdy, conv_data);
325         register_postseq_cleanup_routine(reset_decompressors);
326     }
327     return conv_data;
328 }
329
330 static void
331 spdy_save_stream_info(spdy_conv_t *conv_data,
332                       guint32 stream_id,
333                       gchar *content_type,
334                       gchar *content_type_params,
335                       gchar *content_encoding)
336 {
337     spdy_stream_info_t *si;
338
339     if (conv_data->streams == NULL)
340         conv_data->streams = g_array_new(FALSE, TRUE, sizeof(spdy_stream_info_t *));
341     if (stream_id < conv_data->streams->len)
342         DISSECTOR_ASSERT(g_array_index(conv_data->streams, spdy_stream_info_t*, stream_id) == NULL);
343     else
344         g_array_set_size(conv_data->streams, stream_id+1);
345     si = se_alloc(sizeof(spdy_stream_info_t));
346     si->content_type = content_type;
347     si->content_type_parameters = content_type_params;
348     si->content_encoding = content_encoding;
349     si->data_frames = NULL;
350     si->num_data_frames = 0;
351     si->assembled_data = NULL;
352     g_array_index(conv_data->streams, spdy_stream_info_t*, stream_id) = si;
353     if (spdy_debug)
354         printf("Saved stream info for ID %u, content type %s\n", stream_id, content_type);
355 }
356
357 static spdy_stream_info_t *
358 spdy_get_stream_info(spdy_conv_t *conv_data, guint32 stream_id)
359 {
360     if (conv_data->streams == NULL || stream_id >= conv_data->streams->len)
361         return NULL;
362     else
363         return g_array_index(conv_data->streams, spdy_stream_info_t*, stream_id);
364 }
365
366 static void
367 spdy_add_data_chunk(spdy_conv_t *conv_data, guint32 stream_id, guint32 frame,
368                     guint8 *data, guint32 length)
369 {
370     spdy_stream_info_t *si = spdy_get_stream_info(conv_data, stream_id);
371
372     if (si == NULL) {
373         if (spdy_debug) printf("No stream_info found for stream %d\n", stream_id);
374     } else {
375         spdy_data_frame_t *df = g_malloc(sizeof(spdy_data_frame_t));
376         df->data = data;
377         df->length = length;
378         df->framenum = frame;
379         si->data_frames = g_slist_append(si->data_frames, df);
380         ++si->num_data_frames;
381         if (spdy_debug)
382             printf("Saved %u bytes of data for stream %u frame %u\n",
383                     length, stream_id, df->framenum);
384     }
385 }
386
387 static void
388 spdy_increment_data_chunk_count(spdy_conv_t *conv_data, guint32 stream_id)
389 {
390     spdy_stream_info_t *si = spdy_get_stream_info(conv_data, stream_id);
391     if (si != NULL)
392         ++si->num_data_frames;
393 }
394
395 /*
396  * Return the number of data frames saved so far for the specified stream.
397  */
398 static guint
399 spdy_get_num_data_frames(spdy_conv_t *conv_data, guint32 stream_id)
400 {
401     spdy_stream_info_t *si = spdy_get_stream_info(conv_data, stream_id);
402
403     return si == NULL ? 0 : si->num_data_frames;
404 }
405
406 static spdy_stream_info_t *
407 spdy_assemble_data_frames(spdy_conv_t *conv_data, guint32 stream_id)
408 {
409     spdy_stream_info_t *si = spdy_get_stream_info(conv_data, stream_id);
410     tvbuff_t *tvb;
411
412     if (si == NULL)
413         return NULL;
414
415     /*
416      * Compute the total amount of data and concatenate the
417      * data chunks, if it hasn't already been done.
418      */
419     if (si->assembled_data == NULL) {
420         spdy_data_frame_t *df;
421         guint8 *data;
422         guint32 datalen;
423         guint32 offset;
424         guint32 framenum;
425         GSList *dflist = si->data_frames;
426         if (dflist == NULL)
427             return si;
428         dflist = si->data_frames;
429         datalen = 0;
430         /*
431          * I'd like to use a composite tvbuff here, but since
432          * only a real-data tvbuff can be the child of another
433          * tvb, I can't. It would be nice if this limitation
434          * could be fixed.
435          */
436         while (dflist != NULL) {
437             df = dflist->data;
438             datalen += df->length;
439             dflist = g_slist_next(dflist);
440         }
441         if (datalen != 0) {
442             data = se_alloc(datalen);
443             dflist = si->data_frames;
444             offset = 0;
445             framenum = 0;
446             while (dflist != NULL) {
447                 df = dflist->data;
448                 memcpy(data+offset, df->data, df->length);
449                 offset += df->length;
450                 dflist = g_slist_next(dflist);
451             }
452             tvb = tvb_new_real_data(data, datalen, datalen);
453             si->assembled_data = tvb;
454         }
455     }
456     return si;
457 }
458
459 static void
460 spdy_discard_data_frames(spdy_stream_info_t *si)
461 {
462     GSList *dflist = si->data_frames;
463     spdy_data_frame_t *df;
464
465     if (dflist == NULL)
466         return;
467     while (dflist != NULL) {
468         df = dflist->data;
469         if (df->data != NULL) {
470             g_free(df->data);
471             df->data = NULL;
472         }
473         dflist = g_slist_next(dflist);
474     }
475     /*g_slist_free(si->data_frames);
476     si->data_frames = NULL; */
477 }
478
479 // TODO(cbentzel): tvb_child_uncompress should be exported by wireshark.
480 static tvbuff_t* spdy_tvb_child_uncompress(tvbuff_t *parent _U_, tvbuff_t *tvb,
481                                            int offset, int comprlen)
482 {
483         tvbuff_t *new_tvb = tvb_uncompress(tvb, offset, comprlen);
484         if (new_tvb)
485                 tvb_set_child_real_data_tvbuff (parent, new_tvb);
486         return new_tvb;
487 }
488
489 static int
490 dissect_spdy_data_frame(tvbuff_t *tvb, int offset,
491                         packet_info *pinfo,
492                         proto_tree *top_level_tree,
493                         proto_tree *spdy_tree,
494                         proto_item *spdy_proto,
495                         spdy_conv_t *conv_data)
496 {
497     guint32     stream_id;
498     guint8      flags;
499     guint32     frame_length;
500     proto_item  *ti;
501     proto_tree  *flags_tree;
502     guint32     reported_datalen;
503     guint32     datalen;
504     dissector_table_t media_type_subdissector_table;
505     dissector_table_t port_subdissector_table;
506     dissector_handle_t handle;
507     guint       num_data_frames;
508     gboolean    dissected;
509
510     stream_id = tvb_get_bits32(tvb, (offset << 3) + 1, 31, FALSE);
511     flags = tvb_get_guint8(tvb, offset+4);
512     frame_length = tvb_get_ntoh24(tvb, offset+5);
513
514     if (spdy_debug)
515         printf("Data frame [stream_id=%u flags=0x%x length=%d]\n",
516                 stream_id, flags, frame_length);
517     if (spdy_tree) proto_item_append_text(spdy_tree, ", data frame");
518     col_add_fstr(pinfo->cinfo, COL_INFO, "DATA[%u] length=%d",
519             stream_id, frame_length);
520
521     proto_item_append_text(spdy_proto, ":%s stream=%d length=%d",
522             flags & SPDY_FIN ? " [FIN]" : "",
523             stream_id, frame_length);
524
525     proto_tree_add_boolean(spdy_tree, hf_spdy_control_bit, tvb, offset, 1, 0);
526     proto_tree_add_uint(spdy_tree, hf_spdy_streamid, tvb, offset, 4, stream_id);
527     ti = proto_tree_add_uint_format(spdy_tree, hf_spdy_flags, tvb, offset+4, 1, flags,
528             "Flags: 0x%02x%s", flags, flags&SPDY_FIN ? " (FIN)" : "");
529
530     flags_tree = proto_item_add_subtree(ti, ett_spdy_flags);
531     proto_tree_add_boolean(flags_tree, hf_spdy_flags_fin, tvb, offset+4, 1, flags);
532     proto_tree_add_uint(spdy_tree, hf_spdy_length, tvb, offset+5, 3, frame_length);
533
534     datalen = tvb_length_remaining(tvb, offset);
535     if (datalen > frame_length)
536         datalen = frame_length;
537
538     reported_datalen = tvb_reported_length_remaining(tvb, offset);
539     if (reported_datalen > frame_length)
540         reported_datalen = frame_length;
541
542     num_data_frames = spdy_get_num_data_frames(conv_data, stream_id);
543     if (datalen != 0 || num_data_frames != 0) {
544         /*
545          * There's stuff left over; process it.
546          */
547         tvbuff_t *next_tvb = NULL;
548         tvbuff_t    *data_tvb = NULL;
549         spdy_stream_info_t *si = NULL;
550         void *save_private_data = NULL;
551         guint8 *copied_data;
552         gboolean private_data_changed = FALSE;
553         gboolean is_single_chunk = FALSE;
554         gboolean have_entire_body;
555
556         /*
557          * Create a tvbuff for the payload.
558          */
559         if (datalen != 0) {
560             next_tvb = tvb_new_subset(tvb, offset+8, datalen,
561                                       reported_datalen);
562             is_single_chunk = num_data_frames == 0 && (flags & SPDY_FIN) != 0;
563             if (!pinfo->fd->flags.visited) {
564                 if (!is_single_chunk) {
565                     if (spdy_assemble_entity_bodies) {
566                         copied_data = tvb_memdup(next_tvb, 0, datalen);
567                         spdy_add_data_chunk(conv_data, stream_id, pinfo->fd->num,
568                                 copied_data, datalen);
569                     } else
570                         spdy_increment_data_chunk_count(conv_data, stream_id);
571                 }
572             }
573         } else
574             is_single_chunk = (num_data_frames == 1);
575
576         if (!(flags & SPDY_FIN)) {
577             col_set_fence(pinfo->cinfo, COL_INFO);
578             col_add_fstr(pinfo->cinfo, COL_INFO, " (partial entity)");
579             proto_item_append_text(spdy_proto, " (partial entity body)");
580             /* would like the proto item to say */
581             /* " (entity body fragment N of M)" */
582             goto body_dissected;
583         }
584         have_entire_body = is_single_chunk;
585         /*
586          * On seeing the last data frame in a stream, we can
587          * reassemble the frames into one data block.
588          */
589         si = spdy_assemble_data_frames(conv_data, stream_id);
590         if (si == NULL)
591             goto body_dissected;
592         data_tvb = si->assembled_data;
593         if (spdy_assemble_entity_bodies)
594             have_entire_body = TRUE;
595
596         if (!have_entire_body)
597             goto body_dissected;
598
599         if (data_tvb == NULL)
600             data_tvb = next_tvb;
601         else
602             add_new_data_source(pinfo, data_tvb, "Assembled entity body");
603
604         if (have_entire_body && si->content_encoding != NULL &&
605             g_ascii_strcasecmp(si->content_encoding, "identity") != 0) {
606             /*
607              * We currently can't handle, for example, "compress";
608              * just handle them as data for now.
609              *
610              * After July 7, 2004 the LZW patent expires, so support
611              * might be added then.  However, I don't think that
612              * anybody ever really implemented "compress", due to
613              * the aforementioned patent.
614              */
615             tvbuff_t *uncomp_tvb = NULL;
616             proto_item *e_ti = NULL;
617             proto_item *ce_ti = NULL;
618             proto_tree *e_tree = NULL;
619
620             if (spdy_decompress_body &&
621                     (g_ascii_strcasecmp(si->content_encoding, "gzip") == 0 ||
622                      g_ascii_strcasecmp(si->content_encoding, "deflate")
623                      == 0)) {
624               uncomp_tvb = spdy_tvb_child_uncompress(tvb, data_tvb, 0,
625                                                      tvb_length(data_tvb));
626             }
627             /*
628              * Add the encoded entity to the protocol tree
629              */
630             e_ti = proto_tree_add_text(top_level_tree, data_tvb,
631                     0, tvb_length(data_tvb),
632                     "Content-encoded entity body (%s): %u bytes",
633                     si->content_encoding,
634                     tvb_length(data_tvb));
635             e_tree = proto_item_add_subtree(e_ti, ett_spdy_encoded_entity);
636             if (si->num_data_frames > 1) {
637                 GSList *dflist;
638                 spdy_data_frame_t *df;
639                 guint32 framenum;
640                 ce_ti = proto_tree_add_text(e_tree, data_tvb, 0,
641                         tvb_length(data_tvb),
642                         "Assembled from %d frames in packet(s)", si->num_data_frames);
643                 dflist = si->data_frames;
644                 framenum = 0;
645                 while (dflist != NULL) {
646                     df = dflist->data;
647                     if (framenum != df->framenum) {
648                         proto_item_append_text(ce_ti, " #%u", df->framenum);
649                         framenum = df->framenum;
650                     }
651                     dflist = g_slist_next(dflist);
652                   }
653             }
654
655             if (uncomp_tvb != NULL) {
656                 /*
657                  * Decompression worked
658                  */
659
660                 /* XXX - Don't free this, since it's possible
661                  * that the data was only partially
662                  * decompressed, such as when desegmentation
663                  * isn't enabled.
664                  *
665                  tvb_free(next_tvb);
666                  */
667                 proto_item_append_text(e_ti, " -> %u bytes", tvb_length(uncomp_tvb));
668                 data_tvb = uncomp_tvb;
669                 add_new_data_source(pinfo, data_tvb, "Uncompressed entity body");
670             } else {
671                 if (spdy_decompress_body)
672                     proto_item_append_text(e_ti, " [Error: Decompression failed]");
673                 call_dissector(data_handle, data_tvb, pinfo, e_tree);
674
675                 goto body_dissected;
676             }
677         }
678         if (si != NULL)
679             spdy_discard_data_frames(si);
680         /*
681          * Do subdissector checks.
682          *
683          * First, check whether some subdissector asked that they
684          * be called if something was on some particular port.
685          */
686
687         port_subdissector_table = find_dissector_table("http.port");
688         media_type_subdissector_table = find_dissector_table("media_type");
689         if (have_entire_body && port_subdissector_table != NULL)
690             handle = dissector_get_port_handle(port_subdissector_table,
691                     pinfo->match_port);
692         else
693             handle = NULL;
694         if (handle == NULL && have_entire_body && si->content_type != NULL &&
695                 media_type_subdissector_table != NULL) {
696             /*
697              * We didn't find any subdissector that
698              * registered for the port, and we have a
699              * Content-Type value.  Is there any subdissector
700              * for that content type?
701              */
702             save_private_data = pinfo->private_data;
703             private_data_changed = TRUE;
704
705             if (si->content_type_parameters)
706                 pinfo->private_data = ep_strdup(si->content_type_parameters);
707             else
708                 pinfo->private_data = NULL;
709             /*
710              * Calling the string handle for the media type
711              * dissector table will set pinfo->match_string
712              * to si->content_type for us.
713              */
714             pinfo->match_string = si->content_type;
715             handle = dissector_get_string_handle(
716                     media_type_subdissector_table,
717                     si->content_type);
718         }
719         if (handle != NULL) {
720             /*
721              * We have a subdissector - call it.
722              */
723             dissected = call_dissector(handle, data_tvb, pinfo, top_level_tree);
724         } else
725             dissected = FALSE;
726
727         if (dissected) {
728             /*
729              * The subdissector dissected the body.
730              * Fix up the top-level item so that it doesn't
731              * include the stuff for that protocol.
732              */
733             if (ti != NULL)
734                 proto_item_set_len(ti, offset);
735         } else if (have_entire_body && si->content_type != NULL) {
736             /*
737              * Calling the default media handle if there is a content-type that
738              * wasn't handled above.
739              */
740             call_dissector(media_handle, next_tvb, pinfo, top_level_tree);
741         } else {
742             /* Call the default data dissector */
743             call_dissector(data_handle, next_tvb, pinfo, top_level_tree);
744         }
745
746 body_dissected:
747         /*
748          * Do *not* attempt at freeing the private data;
749          * it may be in use by subdissectors.
750          */
751         if (private_data_changed) /*restore even NULL value*/
752             pinfo->private_data = save_private_data;
753         /*
754          * We've processed "datalen" bytes worth of data
755          * (which may be no data at all); advance the
756          * offset past whatever data we've processed.
757          */
758     }
759     return frame_length + 8;
760 }
761
762 static guint8 *
763 spdy_decompress_header_block(tvbuff_t *tvb, z_streamp decomp,
764                              guint32 dictionary_id, int offset,
765                              guint32 length, guint *uncomp_length)
766 {
767     int retcode;
768     size_t bufsize = 16384;
769     const guint8 *hptr = tvb_get_ptr(tvb, offset, length);
770     guint8 *uncomp_block = ep_alloc(bufsize);
771     decomp->next_in = (Bytef *)hptr;
772     decomp->avail_in = length;
773     decomp->next_out = uncomp_block;
774     decomp->avail_out = bufsize;
775     retcode = inflate(decomp, Z_SYNC_FLUSH);
776     if (retcode == Z_NEED_DICT) {
777         if (decomp->adler != dictionary_id) {
778             printf("decompressor wants dictionary %#x, but we have %#x\n",
779                    (guint)decomp->adler, dictionary_id);
780         } else {
781             retcode = inflateSetDictionary(decomp,
782                                            spdy_dictionary,
783                                            sizeof(spdy_dictionary));
784             if (retcode == Z_OK)
785                 retcode = inflate(decomp, Z_SYNC_FLUSH);
786         }
787     }
788
789     if (retcode != Z_OK) {
790         return NULL;
791     } else {
792         *uncomp_length = bufsize - decomp->avail_out;
793         if (spdy_debug)
794             printf("Inflation SUCCEEDED. uncompressed size=%d\n", *uncomp_length);
795         if (decomp->avail_in != 0)
796             if (spdy_debug)
797                 printf("  but there were %d input bytes left over\n", decomp->avail_in);
798     }
799     return se_memdup(uncomp_block, *uncomp_length);
800 }
801
802 /*
803  * Try to determine heuristically whether the header block is
804  * compressed. For an uncompressed block, the first two bytes
805  * gives the number of headers. Each header name and value is
806  * a two-byte length followed by ASCII characters.
807  */
808 static gboolean
809 spdy_check_header_compression(tvbuff_t *tvb,
810                                        int offset,
811                                        guint32 frame_length)
812 {
813     guint16 length;
814     if (!tvb_bytes_exist(tvb, offset, 6))
815         return 1;
816     length = tvb_get_ntohs(tvb, offset);
817     if (length > frame_length)
818         return 1;
819     length = tvb_get_ntohs(tvb, offset+2);
820     if (length > frame_length)
821         return 1;
822     if (spdy_debug) printf("Looks like the header block is not compressed\n");
823     return 0;
824 }
825
826 // TODO(cbentzel): Change wireshark to export p_remove_proto_data, rather
827 // than duplicating code here.
828 typedef struct _spdy_frame_proto_data {
829   int proto;
830   void *proto_data;
831 } spdy_frame_proto_data;
832
833 static gint spdy_p_compare(gconstpointer a, gconstpointer b)
834 {
835   const spdy_frame_proto_data *ap = (const spdy_frame_proto_data *)a;
836   const spdy_frame_proto_data *bp = (const spdy_frame_proto_data *)b;
837
838   if (ap -> proto > bp -> proto)
839     return 1;
840   else if (ap -> proto == bp -> proto)
841     return 0;
842   else
843     return -1;
844
845 }
846
847 static void spdy_p_remove_proto_data(frame_data *fd, int proto)
848 {
849   spdy_frame_proto_data temp;
850   GSList *item;
851
852   temp.proto = proto;
853   temp.proto_data = NULL;
854
855   item = g_slist_find_custom(fd->pfd, (gpointer *)&temp, spdy_p_compare);
856
857   if (item) {
858     fd->pfd = g_slist_remove(fd->pfd, item->data);
859   }
860 }
861
862 static spdy_frame_info_t *
863 spdy_save_header_block(frame_data *fd,
864         guint32 stream_id,
865         guint frame_type,
866         guint8 *header,
867         guint length)
868 {
869     GSList *filist = p_get_proto_data(fd, proto_spdy);
870     spdy_frame_info_t *frame_info = se_alloc(sizeof(spdy_frame_info_t));
871     if (filist != NULL)
872       spdy_p_remove_proto_data(fd, proto_spdy);
873     frame_info->stream_id = stream_id;
874     frame_info->header_block = header;
875     frame_info->header_block_len = length;
876     frame_info->frame_type = frame_type;
877     filist = g_slist_append(filist, frame_info);
878     p_add_proto_data(fd, proto_spdy, filist);
879     return frame_info;
880     /* TODO(ers) these need to get deleted when no longer needed */
881 }
882
883 static spdy_frame_info_t *
884 spdy_find_saved_header_block(frame_data *fd,
885                              guint32 stream_id,
886                              guint16 frame_type)
887 {
888     GSList *filist = p_get_proto_data(fd, proto_spdy);
889     while (filist != NULL) {
890         spdy_frame_info_t *fi = filist->data;
891         if (fi->stream_id == stream_id && fi->frame_type == frame_type)
892             return fi;
893         filist = g_slist_next(filist);
894     }
895     return NULL;
896 }
897
898 /*
899  * Given a content type string that may contain optional parameters,
900  * return the parameter string, if any, otherwise return NULL. This
901  * also has the side effect of null terminating the content type
902  * part of the original string.
903  */
904 static gchar *
905 spdy_parse_content_type(gchar *content_type)
906 {
907     gchar *cp = content_type;
908
909     while (*cp != '\0' && *cp != ';' && !isspace(*cp)) {
910         *cp = tolower(*cp);
911         ++cp;
912     }
913     if (*cp == '\0')
914         cp = NULL;
915
916     if (cp != NULL) {
917         *cp++ = '\0';
918         while (*cp == ';' || isspace(*cp))
919             ++cp;
920         if (*cp != '\0')
921             return cp;
922     }
923     return NULL;
924 }
925
926 static int
927 dissect_spdy_message(tvbuff_t *tvb, int offset, packet_info *pinfo,
928                      proto_tree *tree, spdy_conv_t *conv_data)
929 {
930     guint8              control_bit;
931     guint16             version;
932     guint16             frame_type;
933     guint8              flags;
934     guint32             frame_length;
935     guint32             stream_id;
936     guint32             associated_stream_id;
937     gint                priority;
938     guint16             num_headers;
939     guint32             fin_status;
940     guint8              *frame_header;
941     const char          *proto_tag;
942     const char          *frame_type_name;
943     proto_tree          *spdy_tree = NULL;
944     proto_item          *ti = NULL;
945     proto_item          *spdy_proto = NULL;
946     int                 orig_offset;
947     int                 hoffset;
948     int                 hdr_offset = 0;
949     spdy_frame_type_t   spdy_type;
950     proto_tree          *sub_tree;
951     proto_tree          *flags_tree;
952     tvbuff_t            *header_tvb = NULL;
953     gboolean            headers_compressed;
954     gchar               *hdr_verb = NULL;
955     gchar               *hdr_url = NULL;
956     gchar               *hdr_version = NULL;
957     gchar               *content_type = NULL;
958     gchar               *content_encoding = NULL;
959
960     /*
961      * Minimum size for a SPDY frame is 8 bytes.
962      */
963     if (tvb_reported_length_remaining(tvb, offset) < 8)
964         return -1;
965
966     proto_tag = "SPDY";
967
968     if (check_col(pinfo->cinfo, COL_PROTOCOL))
969         col_set_str(pinfo->cinfo, COL_PROTOCOL, proto_tag);
970
971     /*
972      * Is this a control frame or a data frame?
973      */
974     orig_offset = offset;
975     control_bit = tvb_get_bits8(tvb, offset << 3, 1);
976     if (control_bit) {
977         version = tvb_get_bits16(tvb, (offset << 3) + 1, 15, FALSE);
978         frame_type = tvb_get_ntohs(tvb, offset+2);
979         if (frame_type >= SPDY_INVALID) {
980             return -1;
981         }
982         frame_header = ep_tvb_memdup(tvb, offset, 16);
983     } else {
984         version = 1;  /* avoid gcc warning */
985         frame_type = SPDY_DATA;
986         frame_header = NULL;    /* avoid gcc warning */
987     }
988     frame_type_name = frame_type_names[frame_type];
989     offset += 4;
990     flags = tvb_get_guint8(tvb, offset);
991     frame_length = tvb_get_ntoh24(tvb, offset+1);
992     offset += 4;
993     /*
994      * Make sure there's as much data as the frame header says there is.
995      */
996     if ((guint)tvb_reported_length_remaining(tvb, offset) < frame_length) {
997         if (spdy_debug)
998             printf("Not enough header data: %d vs. %d\n",
999                     frame_length, tvb_reported_length_remaining(tvb, offset));
1000         return -1;
1001     }
1002     if (tree) {
1003         spdy_proto = proto_tree_add_item(tree, proto_spdy, tvb, orig_offset, frame_length+8, FALSE);
1004         spdy_tree = proto_item_add_subtree(spdy_proto, ett_spdy);
1005     }
1006
1007     if (control_bit) {
1008         if (spdy_debug)
1009             printf("Control frame [version=%d type=%d flags=0x%x length=%d]\n",
1010                     version, frame_type, flags, frame_length);
1011         if (tree) proto_item_append_text(spdy_tree, ", control frame");
1012     } else {
1013         return dissect_spdy_data_frame(tvb, orig_offset, pinfo, tree,
1014                                 spdy_tree, spdy_proto, conv_data);
1015     }
1016     num_headers = 0;
1017     sub_tree = NULL;    /* avoid gcc warning */
1018     switch (frame_type) {
1019         case SPDY_SYN_STREAM:
1020         case SPDY_SYN_REPLY:
1021             if (tree) {
1022                 int hf;
1023                 hf = frame_type == SPDY_SYN_STREAM ? hf_spdy_syn_stream : hf_spdy_syn_reply;
1024                 ti = proto_tree_add_bytes(spdy_tree, hf, tvb,
1025                                           orig_offset, 16, frame_header);
1026                 sub_tree = proto_item_add_subtree(ti, ett_spdy_syn_stream);
1027             }
1028             stream_id = tvb_get_bits32(tvb, (offset << 3) + 1, 31, FALSE);
1029             offset += 4;
1030             if (frame_type == SPDY_SYN_STREAM) {
1031                 associated_stream_id = tvb_get_bits32(tvb, (offset << 3) + 1, 31, FALSE);
1032                 offset += 4;
1033                 priority = tvb_get_bits8(tvb, offset << 3, 2);
1034                 offset += 2;
1035             } else {
1036                 // The next two bytes have no meaning in SYN_REPLY
1037                 offset += 2;
1038             }
1039             if (tree) {
1040                 proto_tree_add_boolean(sub_tree, hf_spdy_control_bit, tvb, orig_offset, 1, control_bit);
1041                 proto_tree_add_uint(sub_tree, hf_spdy_version, tvb, orig_offset, 2, version);
1042                 proto_tree_add_uint(sub_tree, hf_spdy_type, tvb, orig_offset+2, 2, frame_type);
1043                 ti = proto_tree_add_uint_format(sub_tree, hf_spdy_flags, tvb, orig_offset+4, 1, flags,
1044                                                 "Flags: 0x%02x%s", flags, flags&SPDY_FIN ? " (FIN)" : "");
1045                 flags_tree = proto_item_add_subtree(ti, ett_spdy_flags);
1046                 proto_tree_add_boolean(flags_tree, hf_spdy_flags_fin, tvb, orig_offset+4, 1, flags);
1047                 proto_tree_add_uint(sub_tree, hf_spdy_length, tvb, orig_offset+5, 3, frame_length);
1048                 proto_tree_add_uint(sub_tree, hf_spdy_streamid, tvb, orig_offset+8, 4, stream_id);
1049                 if (frame_type == SPDY_SYN_STREAM) {
1050                      proto_tree_add_uint(sub_tree, hf_spdy_associated_streamid, tvb, orig_offset+12, 4, associated_stream_id);
1051                      proto_tree_add_uint(sub_tree, hf_spdy_priority, tvb, orig_offset+16, 1, priority);
1052                 }
1053                 proto_item_append_text(spdy_proto, ": %s%s stream=%d length=%d",
1054                                        frame_type_name,
1055                                        flags & SPDY_FIN ? " [FIN]" : "",
1056                                        stream_id, frame_length);
1057                 if (spdy_debug)
1058                     printf("  stream ID=%u priority=%d\n", stream_id, priority);
1059             }
1060             break;
1061
1062         case SPDY_FIN_STREAM:
1063             stream_id = tvb_get_bits32(tvb, (offset << 3) + 1, 31, FALSE);
1064             fin_status = tvb_get_ntohl(tvb, offset);
1065             // TODO(ers) fill in tree and summary
1066             offset += 8;
1067             break;
1068
1069         case SPDY_HELLO:
1070             // TODO(ers) fill in tree and summary
1071             stream_id = 0;      /* avoid gcc warning */
1072             break;
1073
1074         default:
1075             stream_id = 0;      /* avoid gcc warning */
1076             return -1;
1077             break;
1078     }
1079
1080     /*
1081      * Process the name-value pairs one at a time, after possibly
1082      * decompressing the header block.
1083      */
1084     if (frame_type == SPDY_SYN_STREAM || frame_type == SPDY_SYN_REPLY) {
1085         headers_compressed = spdy_check_header_compression(tvb, offset, frame_length);
1086         if (!spdy_decompress_headers || !headers_compressed) {
1087             header_tvb = tvb;
1088             hdr_offset = offset;
1089         } else {
1090             spdy_frame_info_t *per_frame_info =
1091                     spdy_find_saved_header_block(pinfo->fd,
1092                                                  stream_id,
1093                                                  frame_type == SPDY_SYN_REPLY);
1094             if (per_frame_info == NULL) {
1095                 guint uncomp_length;
1096                 z_streamp decomp = frame_type == SPDY_SYN_STREAM ?
1097                         conv_data->rqst_decompressor : conv_data->rply_decompressor;
1098                 guint8 *uncomp_ptr =
1099                         spdy_decompress_header_block(tvb, decomp,
1100                                                      conv_data->dictionary_id,
1101                                                      offset,
1102                                                      frame_length + 8 - (offset - orig_offset),
1103                                                      &uncomp_length);
1104                 if (uncomp_ptr == NULL) {         /* decompression failed */
1105                     if (spdy_debug)
1106                         printf("Frame #%d: Inflation failed\n", pinfo->fd->num);
1107                     proto_item_append_text(spdy_proto, " [Error: Header decompression failed]");
1108                     // Should we just bail here?
1109                 } else {
1110                     if (spdy_debug)
1111                         printf("Saving %u bytes of uncomp hdr\n", uncomp_length);
1112                     per_frame_info =
1113                         spdy_save_header_block(pinfo->fd, stream_id, frame_type == SPDY_SYN_REPLY,
1114                                 uncomp_ptr, uncomp_length);
1115                 }
1116             } else if (spdy_debug) {
1117                 printf("Found uncompressed header block len %u for stream %u frame_type=%d\n",
1118                        per_frame_info->header_block_len,
1119                        per_frame_info->stream_id,
1120                        per_frame_info->frame_type);
1121             }
1122             if (per_frame_info != NULL) {
1123                 header_tvb = tvb_new_child_real_data(tvb,
1124                                                  per_frame_info->header_block,
1125                                                  per_frame_info->header_block_len,
1126                                                  per_frame_info->header_block_len);
1127                 add_new_data_source(pinfo, header_tvb, "Uncompressed headers");
1128                 hdr_offset = 0;
1129             }
1130         }
1131         offset = orig_offset + 8 + frame_length;
1132         num_headers = tvb_get_ntohs(header_tvb, hdr_offset);
1133         hdr_offset += 2;
1134         if (header_tvb == NULL ||
1135                 (headers_compressed && !spdy_decompress_headers)) {
1136             num_headers = 0;
1137             ti = proto_tree_add_string(sub_tree, hf_spdy_num_headers_string,
1138                                   tvb, 
1139                                   frame_type == SPDY_SYN_STREAM ? orig_offset+18 : orig_offset + 14, 
1140                                   2,
1141                                   "Unknown (header block is compressed)");
1142         } else
1143             ti = proto_tree_add_uint(sub_tree, hf_spdy_num_headers,
1144                                 tvb, 
1145                                 frame_type == SPDY_SYN_STREAM ? orig_offset+18 : orig_offset +14, 
1146                                 2, num_headers);
1147     }
1148     spdy_type = SPDY_INVALID;           /* type not known yet */
1149     if (spdy_debug)
1150         printf("  %d Headers:\n", num_headers);
1151     if (num_headers > frame_length) {
1152         printf("Number of headers is greater than frame length!\n");
1153         proto_item_append_text(ti, " [Error: Number of headers is larger than frame length]");
1154         col_add_fstr(pinfo->cinfo, COL_INFO, "%s[%d]", frame_type_name, stream_id);
1155         return frame_length+8;
1156     }
1157     hdr_verb = hdr_url = hdr_version = content_type = content_encoding = NULL;
1158     while (num_headers-- && tvb_reported_length_remaining(header_tvb, hdr_offset) != 0) {
1159         gchar *header_name;
1160         gchar *header_value;
1161         proto_tree *header_tree;
1162         proto_tree *name_tree;
1163         proto_tree *value_tree;
1164         proto_item *header;
1165         gint16 length;
1166         gint header_length = 0;
1167
1168         hoffset = hdr_offset;
1169
1170         header = proto_tree_add_item(spdy_tree, hf_spdy_header, header_tvb,
1171                                  hdr_offset, frame_length, FALSE);
1172         header_tree = proto_item_add_subtree(header, ett_spdy_header);
1173
1174         length = tvb_get_ntohs(header_tvb, hdr_offset);
1175         hdr_offset += 2;
1176         header_name = (gchar *)tvb_get_ephemeral_string(header_tvb, hdr_offset, length);
1177         hdr_offset += length;
1178         header_length += hdr_offset - hoffset;
1179         if (tree) {
1180             ti = proto_tree_add_text(header_tree, header_tvb, hoffset, length+2, "Name: %s", 
1181                                      header_name);
1182             name_tree = proto_item_add_subtree(ti, ett_spdy_header_name);
1183             proto_tree_add_uint(name_tree, hf_spdy_length, header_tvb, hoffset, 2, length);
1184             proto_tree_add_string_format(name_tree, hf_spdy_header_name_text, header_tvb, hoffset+2, length,
1185                                          header_name, "Text: %s", format_text(header_name, length));
1186         }
1187
1188         hoffset = hdr_offset;
1189         length = tvb_get_ntohs(header_tvb, hdr_offset);
1190         hdr_offset += 2;
1191         header_value = (gchar *)tvb_get_ephemeral_string(header_tvb, hdr_offset, length);
1192         hdr_offset += length;
1193         header_length += hdr_offset - hoffset;
1194         if (tree) {
1195             ti = proto_tree_add_text(header_tree, header_tvb, hoffset, length+2, "Value: %s", 
1196                                      header_value);
1197             value_tree = proto_item_add_subtree(ti, ett_spdy_header_value);
1198             proto_tree_add_uint(value_tree, hf_spdy_length, header_tvb, hoffset, 2, length);
1199             proto_tree_add_string_format(value_tree, hf_spdy_header_value_text, header_tvb, hoffset+2, length,
1200                                          header_value, "Text: %s", format_text(header_value, length));
1201             proto_item_append_text(header, ": %s: %s", header_name, header_value);
1202             proto_item_set_len(header, header_length);
1203         }
1204         if (spdy_debug) printf("    %s: %s\n", header_name, header_value);
1205         /*
1206          * TODO(ers) check that the header name contains only legal characters.
1207          */
1208         if (g_ascii_strcasecmp(header_name, "method") == 0 ||
1209             g_ascii_strcasecmp(header_name, "status") == 0) {
1210             hdr_verb = header_value;
1211         } else if (g_ascii_strcasecmp(header_name, "url") == 0) {
1212             hdr_url = header_value;
1213         } else if (g_ascii_strcasecmp(header_name, "version") == 0) {
1214             hdr_version = header_value;
1215         } else if (g_ascii_strcasecmp(header_name, "content-type") == 0) {
1216             content_type = se_strdup(header_value);
1217         } else if (g_ascii_strcasecmp(header_name, "content-encoding") == 0) {
1218             content_encoding = se_strdup(header_value);
1219         }
1220     }
1221     if (hdr_version != NULL) {
1222         if (hdr_url != NULL) {
1223             col_add_fstr(pinfo->cinfo, COL_INFO, "%s[%d]: %s %s %s",
1224                          frame_type_name, stream_id, hdr_verb, hdr_url, hdr_version);
1225         } else {
1226             col_add_fstr(pinfo->cinfo, COL_INFO, "%s[%d]: %s %s",
1227                          frame_type_name, stream_id, hdr_verb, hdr_version);
1228         }
1229     } else {
1230         col_add_fstr(pinfo->cinfo, COL_INFO, "%s[%d]", frame_type_name, stream_id);
1231     }
1232     /*
1233      * If we expect data on this stream, we need to remember the content
1234      * type and content encoding.
1235      */
1236     if (content_type != NULL && !pinfo->fd->flags.visited) {
1237         gchar *content_type_params = spdy_parse_content_type(content_type);
1238         spdy_save_stream_info(conv_data, stream_id, content_type,
1239                               content_type_params, content_encoding);
1240     }
1241
1242     return offset - orig_offset;
1243 }
1244
1245 static int
1246 dissect_spdy(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1247 {
1248     spdy_conv_t *conv_data;
1249     int         offset = 0;
1250     int         len;
1251     int         firstpkt = 1;
1252
1253     /*
1254      * The first byte of a SPDY packet must be either 0 or
1255      * 0x80. If it's not, assume that this is not SPDY.
1256      * (In theory, a data frame could have a stream ID
1257      * >= 2^24, in which case it won't have 0 for a first
1258      * byte, but this is a pretty reliable heuristic for
1259      * now.)
1260      */
1261     guint8 first_byte = tvb_get_guint8(tvb, 0);
1262     if (first_byte != 0x80 && first_byte != 0x0)
1263           return 0;
1264
1265     conv_data = get_spdy_conversation_data(pinfo);
1266
1267     while (tvb_reported_length_remaining(tvb, offset) != 0) {
1268         if (!firstpkt) {
1269             col_add_fstr(pinfo->cinfo, COL_INFO, " >> ");
1270             col_set_fence(pinfo->cinfo, COL_INFO);
1271         }
1272         len = dissect_spdy_message(tvb, offset, pinfo, tree, conv_data);
1273         if (len <= 0)
1274             return 0;
1275         offset += len;
1276         /*
1277          * OK, we've set the Protocol and Info columns for the
1278          * first SPDY message; set a fence so that subsequent
1279          * SPDY messages don't overwrite the Info column.
1280          */
1281         col_set_fence(pinfo->cinfo, COL_INFO);
1282         firstpkt = 0;
1283     }
1284     return 1;
1285 }
1286
1287 static gboolean
1288 dissect_spdy_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1289 {
1290     if (!value_is_in_range(global_spdy_tcp_range, pinfo->destport) &&
1291             !value_is_in_range(global_spdy_tcp_range, pinfo->srcport))
1292         return FALSE;
1293     return dissect_spdy(tvb, pinfo, tree) != 0;
1294 }
1295
1296 static void reinit_spdy(void)
1297 {
1298 }
1299
1300 // NMAKE complains about flags_set_truth not being constant. Duplicate
1301 // the values inside of it.
1302 static const true_false_string tfs_spdy_set_notset = { "Set", "Not set" };
1303
1304 void
1305 proto_register_spdy(void)
1306 {
1307     static hf_register_info hf[] = {
1308         { &hf_spdy_syn_stream,
1309             { "Syn Stream",     "spdy.syn_stream",
1310                 FT_BYTES, BASE_NONE, NULL, 0x0,
1311                 "", HFILL }},
1312         { &hf_spdy_syn_reply,
1313             { "Syn Reply",      "spdy.syn_reply",
1314                 FT_BYTES, BASE_NONE, NULL, 0x0,
1315                 "", HFILL }},
1316         { &hf_spdy_control_bit,
1317             { "Control bit",    "spdy.control_bit",
1318                 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1319                 "TRUE if SPDY control frame", HFILL }},
1320         { &hf_spdy_version,
1321             { "Version",        "spdy.version",
1322                 FT_UINT16, BASE_DEC, NULL, 0x0,
1323                 "", HFILL }},
1324         { &hf_spdy_type,
1325             { "Type",           "spdy.type",
1326                 FT_UINT16, BASE_DEC, NULL, 0x0,
1327                 "", HFILL }},
1328         { &hf_spdy_flags,
1329             { "Flags",          "spdy.flags",
1330                 FT_UINT8, BASE_HEX, NULL, 0x0,
1331                 "", HFILL }},
1332         { &hf_spdy_flags_fin,
1333             { "Fin",            "spdy.flags.fin",
1334                 FT_BOOLEAN, 8, TFS(&tfs_spdy_set_notset),
1335                 SPDY_FIN, "", HFILL }},
1336         { &hf_spdy_length,
1337             { "Length",         "spdy.length",
1338                 FT_UINT24, BASE_DEC, NULL, 0x0,
1339                 "", HFILL }},
1340         { &hf_spdy_header,
1341             { "Header",         "spdy.header",
1342                 FT_NONE, BASE_NONE, NULL, 0x0,
1343                 "", HFILL }},
1344         { &hf_spdy_header_name,
1345             { "Name",           "spdy.header.name",
1346                 FT_NONE, BASE_NONE, NULL, 0x0,
1347                 "", HFILL }},
1348         { &hf_spdy_header_name_text,
1349             { "Text",           "spdy.header.name.text",
1350                 FT_STRING, BASE_NONE, NULL, 0x0,
1351                 "", HFILL }},
1352         { &hf_spdy_header_value,
1353             { "Value",          "spdy.header.value",
1354                 FT_NONE, BASE_NONE, NULL, 0x0,
1355                 "", HFILL }},
1356         { &hf_spdy_header_value_text,
1357             { "Text",           "spdy.header.value.text",
1358                 FT_STRING, BASE_NONE, NULL, 0x0,
1359                 "", HFILL }},
1360         { &hf_spdy_streamid,
1361             { "Stream ID",      "spdy.streamid",
1362                 FT_UINT32, BASE_DEC, NULL, 0x0,
1363                 "", HFILL }},
1364         { &hf_spdy_associated_streamid,
1365             { "Associated Stream ID",   "spdy.associated.streamid",
1366                 FT_UINT32, BASE_DEC, NULL, 0x0,
1367                 "", HFILL }},
1368         { &hf_spdy_priority,
1369             { "Priority",       "spdy.priority",
1370                 FT_UINT8, BASE_DEC, NULL, 0x0,
1371                 "", HFILL }},
1372         { &hf_spdy_num_headers,
1373             { "Number of headers", "spdy.numheaders",
1374                 FT_UINT16, BASE_DEC, NULL, 0x0,
1375                 "", HFILL }},
1376         { &hf_spdy_num_headers_string,
1377             { "Number of headers", "spdy.numheaders",
1378                 FT_STRING, BASE_NONE, NULL, 0x0,
1379                 "", HFILL }},
1380     };
1381     static gint *ett[] = {
1382         &ett_spdy,
1383         &ett_spdy_syn_stream,
1384         &ett_spdy_syn_reply,
1385         &ett_spdy_fin_stream,
1386         &ett_spdy_flags,
1387         &ett_spdy_header,
1388         &ett_spdy_header_name,
1389         &ett_spdy_header_value,
1390         &ett_spdy_encoded_entity,
1391     };
1392
1393     module_t *spdy_module;
1394
1395     proto_spdy = proto_register_protocol("SPDY", "SPDY", "spdy");
1396     proto_register_field_array(proto_spdy, hf, array_length(hf));
1397     proto_register_subtree_array(ett, array_length(ett));
1398     new_register_dissector("spdy", dissect_spdy, proto_spdy);
1399     spdy_module = prefs_register_protocol(proto_spdy, reinit_spdy);
1400     prefs_register_bool_preference(spdy_module, "desegment_headers",
1401                                    "Reassemble SPDY control frames spanning multiple TCP segments",
1402                                    "Whether the SPDY dissector should reassemble control frames "
1403                                    "spanning multiple TCP segments. "
1404                                    "To use this option, you must also enable "
1405                                    "\"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
1406                                    &spdy_desegment_control_frames);
1407     prefs_register_bool_preference(spdy_module, "desegment_body",
1408                                    "Reassemble SPDY bodies spanning multiple TCP segments",
1409                                    "Whether the SPDY dissector should reassemble "
1410                                    "data frames spanning multiple TCP segments. "
1411                                    "To use this option, you must also enable "
1412                                    "\"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
1413                                    &spdy_desegment_data_frames);
1414     prefs_register_bool_preference(spdy_module, "assemble_data_frames",
1415                                    "Assemble SPDY bodies that consist of multiple DATA frames",
1416                                    "Whether the SPDY dissector should reassemble multiple "
1417                                    "data frames into an entity body.",
1418                                    &spdy_assemble_entity_bodies);
1419 #ifdef HAVE_LIBZ
1420     prefs_register_bool_preference(spdy_module, "decompress_headers",
1421                                    "Uncompress SPDY headers",
1422                                    "Whether to uncompress SPDY headers.",
1423                                    &spdy_decompress_headers);
1424     prefs_register_bool_preference(spdy_module, "decompress_body",
1425                                    "Uncompress entity bodies",
1426                                    "Whether to uncompress entity bodies that are compressed "
1427                                    "using \"Content-Encoding: \"",
1428                                    &spdy_decompress_body);
1429 #endif
1430     prefs_register_bool_preference(spdy_module, "debug_output",
1431                                    "Print debug info on stdout",
1432                                    "Print debug info on stdout",
1433                                    &spdy_debug);
1434 #if 0
1435     prefs_register_string_preference(ssl_module, "debug_file", "SPDY debug file",
1436                                      "Redirect SPDY debug to file name; "
1437                                      "leave empty to disable debugging, "
1438                                      "or use \"" SPDY_DEBUG_USE_STDOUT "\""
1439                                      " to redirect output to stdout\n",
1440                                      (const gchar **)&sdpy_debug_file_name);
1441 #endif
1442     prefs_register_obsolete_preference(spdy_module, "tcp_alternate_port");
1443
1444     range_convert_str(&global_spdy_tcp_range, TCP_DEFAULT_RANGE, 65535);
1445     spdy_tcp_range = range_empty();
1446     prefs_register_range_preference(spdy_module, "tcp.port", "TCP Ports",
1447                                     "TCP Ports range",
1448                                     &global_spdy_tcp_range, 65535);
1449
1450     range_convert_str(&global_spdy_ssl_range, SSL_DEFAULT_RANGE, 65535);
1451     spdy_ssl_range = range_empty();
1452     prefs_register_range_preference(spdy_module, "ssl.port", "SSL/TLS Ports",
1453                                     "SSL/TLS Ports range",
1454                                     &global_spdy_ssl_range, 65535);
1455
1456     spdy_handle = new_create_dissector_handle(dissect_spdy, proto_spdy);
1457     /*
1458      * Register for tapping
1459      */
1460     spdy_tap = register_tap("spdy"); /* SPDY statistics tap */
1461     spdy_eo_tap = register_tap("spdy_eo"); /* SPDY Export Object tap */
1462 }
1463
1464 void
1465 proto_reg_handoff_spdy(void)
1466 {
1467     data_handle = find_dissector("data");
1468     media_handle = find_dissector("media");
1469     heur_dissector_add("tcp", dissect_spdy_heur, proto_spdy);
1470 }
1471
1472 /*
1473  * Content-Type: message/http
1474  */
1475
1476 static gint proto_message_spdy = -1;
1477 static gint ett_message_spdy = -1;
1478
1479 static void
1480 dissect_message_spdy(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1481 {
1482         proto_tree      *subtree;
1483         proto_item      *ti;
1484         gint            offset = 0, next_offset;
1485         gint            len;
1486
1487         if (check_col(pinfo->cinfo, COL_INFO))
1488                 col_append_str(pinfo->cinfo, COL_INFO, " (message/spdy)");
1489         if (tree) {
1490                 ti = proto_tree_add_item(tree, proto_message_spdy,
1491                                 tvb, 0, -1, FALSE);
1492                 subtree = proto_item_add_subtree(ti, ett_message_spdy);
1493                 while (tvb_reported_length_remaining(tvb, offset) != 0) {
1494                         len = tvb_find_line_end(tvb, offset,
1495                                         tvb_ensure_length_remaining(tvb, offset),
1496                                         &next_offset, FALSE);
1497                         if (len == -1)
1498                                 break;
1499                         proto_tree_add_text(subtree, tvb, offset, next_offset - offset,
1500                                         "%s", tvb_format_text(tvb, offset, len));
1501                         offset = next_offset;
1502                 }
1503         }
1504 }
1505
1506 void
1507 proto_register_message_spdy(void)
1508 {
1509         static gint *ett[] = {
1510                 &ett_message_spdy,
1511         };
1512
1513         proto_message_spdy = proto_register_protocol(
1514                         "Media Type: message/spdy",
1515                         "message/spdy",
1516                         "message-spdy"
1517         );
1518         proto_register_subtree_array(ett, array_length(ett));
1519 }
1520
1521 void
1522 proto_reg_handoff_message_spdy(void)
1523 {
1524         dissector_handle_t message_spdy_handle;
1525
1526         message_spdy_handle = create_dissector_handle(dissect_message_spdy,
1527                         proto_message_spdy);
1528
1529         dissector_add_string("media_type", "message/spdy", message_spdy_handle);
1530
1531         reinit_spdy();
1532 }