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