Home | History | Annotate | Download | only in spdyshark
      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 (at) google.com>
      8  *
      9  * $Id$
     10  *
     11  * Wireshark - Network traffic analyzer
     12  * By Gerald Combs <gerald (at) 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 }
   1533