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 */
58typedef 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
69static 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 */
79typedef 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 */
91typedef struct _spdy_data_frame_t {
92    guint8 *data;
93    guint32 length;
94    guint32 framenum;
95} spdy_data_frame_t;
96
97typedef 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
109static int spdy_tap = -1;
110static int spdy_eo_tap = -1;
111
112static int proto_spdy = -1;
113static int hf_spdy_syn_stream = -1;
114static int hf_spdy_syn_reply = -1;
115static int hf_spdy_control_bit = -1;
116static int hf_spdy_version = -1;
117static int hf_spdy_type = -1;
118static int hf_spdy_flags = -1;
119static int hf_spdy_flags_fin = -1;
120static int hf_spdy_length = -1;
121static int hf_spdy_header = -1;
122static int hf_spdy_header_name = -1;
123static int hf_spdy_header_name_text = -1;
124static int hf_spdy_header_value = -1;
125static int hf_spdy_header_value_text = -1;
126static int hf_spdy_streamid = -1;
127static int hf_spdy_associated_streamid = -1;
128static int hf_spdy_priority = -1;
129static int hf_spdy_num_headers = -1;
130static int hf_spdy_num_headers_string = -1;
131
132static gint ett_spdy = -1;
133static gint ett_spdy_syn_stream = -1;
134static gint ett_spdy_syn_reply = -1;
135static gint ett_spdy_fin_stream = -1;
136static gint ett_spdy_flags = -1;
137static gint ett_spdy_header = -1;
138static gint ett_spdy_header_name = -1;
139static gint ett_spdy_header_value = -1;
140
141static gint ett_spdy_encoded_entity = -1;
142
143static dissector_handle_t data_handle;
144static dissector_handle_t media_handle;
145static dissector_handle_t spdy_handle;
146
147/* Stuff for generation/handling of fields for custom HTTP headers */
148typedef 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 */
157static 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 */
164static gboolean spdy_desegment_data_frames = TRUE;
165
166static gboolean spdy_assemble_entity_bodies = TRUE;
167
168/*
169 * Decompression of zlib encoded entities.
170 */
171#ifdef HAVE_LIBZ
172static gboolean spdy_decompress_body = TRUE;
173static gboolean spdy_decompress_headers = TRUE;
174#else
175static gboolean spdy_decompress_body = FALSE;
176static gboolean spdy_decompress_headers = FALSE;
177#endif
178static 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
195static range_t *global_spdy_tcp_range = NULL;
196static range_t *global_spdy_ssl_range = NULL;
197
198static range_t *spdy_tcp_range = NULL;
199static range_t *spdy_ssl_range = NULL;
200
201static 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
262static 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
277static void reset_decompressors(void)
278{
279    if (spdy_debug) printf("Should reset SPDY decompressors\n");
280}
281
282static spdy_conv_t *
283get_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
330static void
331spdy_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
357static spdy_stream_info_t *
358spdy_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
366static void
367spdy_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
387static void
388spdy_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 */
398static guint
399spdy_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
406static spdy_stream_info_t *
407spdy_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
459static void
460spdy_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.
480static 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
489static int
490dissect_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
746body_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
762static guint8 *
763spdy_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 */
808static gboolean
809spdy_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.
828typedef struct _spdy_frame_proto_data {
829  int proto;
830  void *proto_data;
831} spdy_frame_proto_data;
832
833static 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
847static 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
862static spdy_frame_info_t *
863spdy_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
883static spdy_frame_info_t *
884spdy_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 */
904static gchar *
905spdy_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
926static int
927dissect_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
1245static int
1246dissect_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
1287static gboolean
1288dissect_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
1296static void reinit_spdy(void)
1297{
1298}
1299
1300// NMAKE complains about flags_set_truth not being constant. Duplicate
1301// the values inside of it.
1302static const true_false_string tfs_spdy_set_notset = { "Set", "Not set" };
1303
1304void
1305proto_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
1464void
1465proto_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
1476static gint proto_message_spdy = -1;
1477static gint ett_message_spdy = -1;
1478
1479static void
1480dissect_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
1506void
1507proto_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
1521void
1522proto_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