2013-08-30 11:14:09 +00:00
/* packet-http2.c
* Routines for HTTP2 dissection
* Copyright 2013 , Alexis La Goutte < alexis . lagoutte @ gmail . com >
* Copyright 2013 , Stephen Ludin < sludin @ ludin . org >
2014-04-25 14:29:10 +00:00
* Copyright 2014 , Daniel Stenberg < daniel @ haxx . se >
2013-08-30 11:14:09 +00:00
*
* Wireshark - Network traffic analyzer
* By Gerald Combs < gerald @ wireshark . org >
* Copyright 1998 Gerald Combs
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License along
* with this program ; if not , write to the Free Software Foundation , Inc . ,
* 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA .
*/
/*
* The information used comes from :
2014-04-25 14:29:10 +00:00
* Hypertext Transfer Protocol version 2.0 draft - ietf - httpbis - http2 - 12
* HTTP Header Compression draft - ietf - httpbis - header - compression - 07
2013-08-30 11:14:09 +00:00
*
* TODO
* Support HTTP Header Compression ( draft - ietf - httpbis - header - compression )
* Enhance display of Data
* Reassembling of continuation frame ( and other frame )
* Add same tap and ping / pong time response
*/
# include "config.h"
2014-05-06 15:54:47 +00:00
# include <stdio.h>
2013-08-30 11:14:09 +00:00
# include <glib.h>
# include <epan/packet.h>
# include <epan/prefs.h>
# include <epan/expert.h>
2014-05-06 15:54:47 +00:00
# include <epan/conversation.h>
# include <epan/follow.h>
# include <wsutil/nghttp2/nghttp2/nghttp2.h>
2013-08-30 11:14:09 +00:00
# include "packet-tcp.h"
2014-05-06 15:54:47 +00:00
/* struct to hold data per HTTP/2 session */
typedef struct {
/* We need 2 inflater object for both client and server. Since
inflater object is symmetrical , we just want to know which
inflater is used for each TCP flow . The hd_inflater_first_flow
is used to select which one to use . Basically , we first record
fwd of tcp_analysis in hd_inflater_first_flow and if processing
packet_info has fwd of tcp_analysis equal to
hd_inflater_first_flow , we use hd_inflater [ 0 ] , otherwise 2 nd
one .
*/
nghttp2_hd_inflater * hd_inflater [ 2 ] ;
tcp_flow_t * hd_inflater_first_flow ;
} http2_session_t ;
typedef struct {
/* Hash table, associates TCP stream index to http2_session_t object */
wmem_map_t * sessions ;
} http2_data_t ;
2013-12-15 23:44:12 +00:00
void proto_register_http2 ( void ) ;
void proto_reg_handoff_http2 ( void ) ;
2013-08-30 11:14:09 +00:00
/* Packet Header */
static int proto_http2 = - 1 ;
static int hf_http2 = - 1 ;
static int hf_http2_length = - 1 ;
2013-12-15 19:07:40 +00:00
static int hf_http2_len_rsv = - 1 ;
2013-08-30 11:14:09 +00:00
static int hf_http2_type = - 1 ;
static int hf_http2_r = - 1 ;
static int hf_http2_streamid = - 1 ;
static int hf_http2_magic = - 1 ;
static int hf_http2_unknown = - 1 ;
/* Flags */
static int hf_http2_flags = - 1 ;
static int hf_http2_flags_end_stream = - 1 ;
2014-04-25 14:29:10 +00:00
static int hf_http2_flags_end_segment = - 1 ;
2013-08-30 11:14:09 +00:00
static int hf_http2_flags_end_headers = - 1 ;
2014-04-25 14:29:10 +00:00
static int hf_http2_flags_pad_low = - 1 ;
static int hf_http2_flags_pad_high = - 1 ;
2013-08-30 11:14:09 +00:00
static int hf_http2_flags_priority = - 1 ;
2014-04-25 14:29:10 +00:00
static int hf_http2_flags_compressed = - 1 ;
2013-12-15 19:07:40 +00:00
static int hf_http2_flags_settings_ack = - 1 ;
static int hf_http2_flags_ping_ack = - 1 ;
2014-05-12 07:00:52 +00:00
static int hf_http2_flags_unused = - 1 ;
static int hf_http2_flags_unused1 = - 1 ;
static int hf_http2_flags_unused3 = - 1 ;
static int hf_http2_flags_unused_data = - 1 ;
static int hf_http2_flags_unused6 = - 1 ;
2014-04-25 14:29:10 +00:00
/* generic */
static int hf_http2_pad_high = - 1 ;
static int hf_http2_pad_low = - 1 ;
2014-05-12 07:00:52 +00:00
static int hf_http2_pad_length = - 1 ;
2014-04-25 14:29:10 +00:00
static int hf_http2_weight = - 1 ;
2014-05-13 15:49:24 +00:00
static int hf_http2_weight_real = - 1 ;
2014-04-25 14:29:10 +00:00
static int hf_http2_stream_dependency = - 1 ;
static int hf_http2_excl_dependency = - 1 ;
/* Data */
static int hf_http2_data_data = - 1 ;
static int hf_http2_data_padding = - 1 ;
2013-08-30 11:14:09 +00:00
/* Headers */
2014-05-06 15:54:47 +00:00
static int hf_http2_headers = - 1 ;
2014-04-25 14:29:10 +00:00
static int hf_http2_headers_padding = - 1 ;
2014-05-06 15:54:47 +00:00
static int hf_http2_header = - 1 ;
static int hf_http2_header_length = - 1 ;
static int hf_http2_header_name_length = - 1 ;
static int hf_http2_header_name = - 1 ;
static int hf_http2_header_value_length = - 1 ;
static int hf_http2_header_value = - 1 ;
2013-08-30 11:14:09 +00:00
/* RST Stream */
static int hf_http2_rst_stream_error = - 1 ;
/* Settings */
static int hf_http2_settings = - 1 ;
static int hf_http2_settings_identifier = - 1 ;
2013-12-15 19:07:40 +00:00
static int hf_http2_settings_header_table_size = - 1 ;
static int hf_http2_settings_enable_push = - 1 ;
2013-08-30 11:14:09 +00:00
static int hf_http2_settings_max_concurrent_streams = - 1 ;
static int hf_http2_settings_initial_window_size = - 1 ;
2014-04-25 14:29:10 +00:00
static int hf_http2_settings_compress_data = - 1 ;
2013-08-30 11:14:09 +00:00
static int hf_http2_settings_unknown = - 1 ;
/* Push Promise */
static int hf_http2_push_promise_r = - 1 ;
static int hf_http2_push_promise_promised_stream_id = - 1 ;
static int hf_http2_push_promise_header = - 1 ;
2014-04-25 14:29:10 +00:00
static int hf_http2_push_promise_padding = - 1 ;
2013-08-30 11:14:09 +00:00
/* Ping */
static int hf_http2_ping = - 1 ;
static int hf_http2_pong = - 1 ;
2014-04-25 14:29:10 +00:00
/* Goaway */
2013-08-30 11:14:09 +00:00
static int hf_http2_goaway_r = - 1 ;
static int hf_http2_goaway_last_stream_id = - 1 ;
static int hf_http2_goaway_error = - 1 ;
static int hf_http2_goaway_addata = - 1 ;
/* Window Update */
static int hf_http2_window_update_r = - 1 ;
static int hf_http2_window_update_window_size_increment = - 1 ;
/* Continuation */
static int hf_http2_continuation_header = - 1 ;
2014-05-12 07:00:52 +00:00
static int hf_http2_continuation_padding = - 1 ;
2014-04-25 14:29:10 +00:00
/* Altsvc */
static int hf_http2_altsvc_maxage = - 1 ;
static int hf_http2_altsvc_port = - 1 ;
static int hf_http2_altsvc_res = - 1 ;
static int hf_http2_altsvc_proto_len = - 1 ;
static int hf_http2_altsvc_protocol = - 1 ;
static int hf_http2_altsvc_host_len = - 1 ;
static int hf_http2_altsvc_host = - 1 ;
static int hf_http2_altsvc_origin = - 1 ;
/* Blocked */
2013-08-30 11:14:09 +00:00
static gint ett_http2 = - 1 ;
static gint ett_http2_header = - 1 ;
2014-05-06 15:54:47 +00:00
static gint ett_http2_headers = - 1 ;
2013-08-30 11:14:09 +00:00
static gint ett_http2_flags = - 1 ;
static gint ett_http2_settings = - 1 ;
static dissector_handle_t data_handle ;
2013-12-15 19:07:40 +00:00
static dissector_handle_t http2_handle ;
2013-08-30 11:14:09 +00:00
# define FRAME_HEADER_LENGTH 8
# define MAGIC_FRAME_LENGTH 24
2014-04-25 14:29:10 +00:00
# define MASK_HTTP2_LENGTH 0X3FFF
# define MASK_HTTP2_LEN_RSV 0XC000
2013-08-30 11:14:09 +00:00
# define MASK_HTTP2_RESERVED 0x80000000
# define MASK_HTTP2_STREAMID 0X7FFFFFFF
# define MASK_HTTP2_PRIORITY 0X7FFFFFFF
/* Header Type Code */
# define HTTP2_DATA 0
# define HTTP2_HEADERS 1
# define HTTP2_PRIORITY 2
# define HTTP2_RST_STREAM 3
# define HTTP2_SETTINGS 4
# define HTTP2_PUSH_PROMISE 5
# define HTTP2_PING 6
# define HTTP2_GOAWAY 7
2014-04-25 14:29:10 +00:00
# define HTTP2_WINDOW_UPDATE 8
# define HTTP2_CONTINUATION 9
# define HTTP2_ALTSVC 0xA
# define HTTP2_BLOCKED 0xB
2013-08-30 11:14:09 +00:00
static const value_string http2_type_vals [ ] = {
{ HTTP2_DATA , " DATA " } ,
{ HTTP2_HEADERS , " HEADERS " } ,
{ HTTP2_PRIORITY , " PRIORITY " } ,
{ HTTP2_RST_STREAM , " RST_STREAM " } ,
{ HTTP2_SETTINGS , " SETTINGS " } ,
{ HTTP2_PUSH_PROMISE , " PUSH_PROMISE " } ,
{ HTTP2_PING , " PING " } ,
{ HTTP2_GOAWAY , " GOAWAY " } ,
{ HTTP2_WINDOW_UPDATE , " WINDOW_UPDATE " } ,
{ HTTP2_CONTINUATION , " CONTINUATION " } ,
2014-04-25 14:29:10 +00:00
{ HTTP2_ALTSVC , " ALTSVC " } ,
{ HTTP2_BLOCKED , " BLOCKED " } ,
2013-08-30 11:14:09 +00:00
{ 0 , NULL }
} ;
/* Flags */
2014-04-25 14:29:10 +00:00
# define HTTP2_FLAGS_ACK 0x01 /* for PING and SETTINGS */
# define HTTP2_FLAGS_END_STREAM 0x01
# define HTTP2_FLAGS_END_SEGMENT 0x02
# define HTTP2_FLAGS_END_HEADERS 0x04
# define HTTP2_FLAGS_PAD_LOW 0x08
# define HTTP2_FLAGS_PAD_HIGH 0x10
# define HTTP2_FLAGS_PRIORITY 0x20
# define HTTP2_FLAGS_COMPRESSED 0x20
2013-08-30 11:14:09 +00:00
# define HTTP2_FLAGS_R 0xFF
# define HTTP2_FLAGS_R1 0xFE
# define HTTP2_FLAGS_R2 0xFA
# define HTTP2_FLAGS_R4 0xFB
/* Magic Header : PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n */
static guint8 kMagicHello [ ] = {
0x50 , 0x52 , 0x49 , 0x20 , 0x2a , 0x20 , 0x48 , 0x54 ,
0x54 , 0x50 , 0x2f , 0x32 , 0x2e , 0x30 , 0x0d , 0x0a ,
0x0d , 0x0a , 0x53 , 0x4d , 0x0d , 0x0a , 0x0d , 0x0a
} ;
/* Error Codes */
# define EC_NO_ERROR 0
# define EC_PROTOCOL_ERROR 1
# define EC_INTERNAL_ERROR 2
2013-12-15 19:07:40 +00:00
# define EC_FLOW_CONTROL_ERROR 3
# define EC_SETTINGS_TIMEOUT 4
2013-08-30 11:14:09 +00:00
# define EC_STREAM_CLOSED 5
2013-12-15 19:07:40 +00:00
# define EC_FRAME_SIZE_ERROR 6
2013-08-30 11:14:09 +00:00
# define EC_REFUSED_STREAM 7
# define EC_CANCEL 8
# define EC_COMPRESSION_ERROR 9
2013-12-15 19:07:40 +00:00
# define EC_CONNECT_ERROR 10
# define EC_ENHANCE_YOUR_CALM 420
2013-08-30 11:14:09 +00:00
static const value_string http2_error_codes_vals [ ] = {
2014-04-25 14:29:10 +00:00
{ EC_NO_ERROR , " NO_ERROR " } ,
2013-08-30 11:14:09 +00:00
{ EC_PROTOCOL_ERROR , " PROTOCOL_ERROR " } ,
{ EC_INTERNAL_ERROR , " INTERNAL_ERROR " } ,
{ EC_FLOW_CONTROL_ERROR , " FLOW_CONTROL_ERROR " } ,
2013-12-15 19:07:40 +00:00
{ EC_SETTINGS_TIMEOUT , " SETTINGS_TIMEOUT " } ,
2013-08-30 11:14:09 +00:00
{ EC_STREAM_CLOSED , " STREAM_CLOSED " } ,
2013-12-15 19:07:40 +00:00
{ EC_FRAME_SIZE_ERROR , " FRAME_SIZE_ERROR " } ,
2013-08-30 11:14:09 +00:00
{ EC_REFUSED_STREAM , " REFUSED_STREAM " } ,
{ EC_CANCEL , " CANCEL " } ,
{ EC_COMPRESSION_ERROR , " COMPRESSION_ERROR " } ,
2013-12-15 19:07:40 +00:00
{ EC_CONNECT_ERROR , " CONNECT_ERROR " } ,
{ EC_ENHANCE_YOUR_CALM , " ENHANCE_YOUR_CALM " } ,
2013-08-30 11:14:09 +00:00
{ 0 , NULL }
} ;
/* Settings */
2013-12-15 19:07:40 +00:00
# define HTTP2_SETTINGS_HEADER_TABLE_SIZE 1
# define HTTP2_SETTINGS_ENABLE_PUSH 2
2014-04-25 14:29:10 +00:00
# define HTTP2_SETTINGS_MAX_CONCURRENT_STREAMS 3
# define HTTP2_SETTINGS_INITIAL_WINDOW_SIZE 4
# define HTTP2_SETTINGS_COMPRESS_DATA 5
2013-08-30 11:14:09 +00:00
static const value_string http2_settings_vals [ ] = {
2013-12-15 19:07:40 +00:00
{ HTTP2_SETTINGS_HEADER_TABLE_SIZE , " Header table size " } ,
{ HTTP2_SETTINGS_ENABLE_PUSH , " Enable PUSH " } ,
2013-08-30 11:14:09 +00:00
{ HTTP2_SETTINGS_MAX_CONCURRENT_STREAMS , " Max concurrent streams " } ,
{ HTTP2_SETTINGS_INITIAL_WINDOW_SIZE , " Initial Windows size " } ,
2014-04-25 14:29:10 +00:00
{ HTTP2_SETTINGS_COMPRESS_DATA , " Compress data " } ,
2013-08-30 11:14:09 +00:00
{ 0 , NULL }
} ;
2014-05-06 15:54:47 +00:00
static http2_session_t *
create_http2_session ( packet_info * pinfo )
{
conversation_t * conversation ;
http2_data_t * http2 ;
http2_session_t * h2session ;
struct tcp_analysis * tcpd ;
conversation = find_or_create_conversation ( pinfo ) ;
http2 = ( http2_data_t * ) conversation_get_proto_data ( conversation ,
proto_http2 ) ;
if ( http2 = = NULL ) {
http2 = wmem_new ( wmem_file_scope ( ) , http2_data_t ) ;
http2 - > sessions = wmem_map_new ( wmem_file_scope ( ) , g_direct_hash , g_direct_equal ) ;
conversation_add_proto_data ( conversation , proto_http2 , http2 ) ;
}
tcpd = get_tcp_conversation_data ( NULL , pinfo ) ;
h2session = wmem_new ( wmem_file_scope ( ) , http2_session_t ) ;
nghttp2_hd_inflate_new ( & h2session - > hd_inflater [ 0 ] ) ;
nghttp2_hd_inflate_new ( & h2session - > hd_inflater [ 1 ] ) ;
h2session - > hd_inflater_first_flow = tcpd - > fwd ;
wmem_map_insert ( http2 - > sessions , GUINT_TO_POINTER ( tcpd - > stream ) , h2session ) ;
return h2session ;
}
static http2_session_t *
get_http2_session ( packet_info * pinfo )
{
conversation_t * conversation ;
http2_data_t * http2 ;
http2_session_t * h2session ;
struct tcp_analysis * tcpd ;
conversation = find_or_create_conversation ( pinfo ) ;
http2 = ( http2_data_t * ) conversation_get_proto_data ( conversation ,
proto_http2 ) ;
if ( ! http2 ) {
return NULL ;
}
tcpd = get_tcp_conversation_data ( NULL , pinfo ) ;
h2session = ( http2_session_t * ) wmem_map_lookup ( http2 - > sessions , GUINT_TO_POINTER ( tcpd - > stream ) ) ;
return h2session ;
}
static nghttp2_hd_inflater *
select_http2_hd_inflater ( packet_info * pinfo , http2_session_t * h2session )
{
struct tcp_analysis * tcpd ;
tcpd = get_tcp_conversation_data ( NULL , pinfo ) ;
if ( tcpd - > fwd = = h2session - > hd_inflater_first_flow ) {
return h2session - > hd_inflater [ 0 ] ;
} else {
return h2session - > hd_inflater [ 1 ] ;
}
}
static void
inflate_http2_header_block ( tvbuff_t * tvb , packet_info * pinfo , guint offset ,
proto_tree * tree , size_t headlen ,
http2_session_t * h2session , guint8 flags )
{
guint8 * headbuf ;
proto_tree * header_tree ;
proto_item * header , * ti ;
int header_name_length ;
int header_value_length ;
const gchar * header_name ;
const gchar * header_value ;
int hoffset = 0 ;
nghttp2_hd_inflater * hd_inflater ;
tvbuff_t * header_tvb = tvb_new_composite ( ) ;
int rv ;
2014-05-31 18:58:16 +00:00
int header_len = 0 , len ;
2014-05-06 15:54:47 +00:00
int final ;
if ( ! h2session ) {
/* We may not be able to track all HTTP/2 session if we miss
first magic ( connection preface ) */
return ;
}
headbuf = ( guint8 * ) wmem_alloc ( wmem_packet_scope ( ) , headlen ) ;
tvb_memcpy ( tvb , headbuf , offset , headlen ) ;
hd_inflater = select_http2_hd_inflater ( pinfo , h2session ) ;
final = flags & HTTP2_FLAGS_END_HEADERS ;
for ( ; ; ) {
nghttp2_nv nv ;
int inflate_flags = 0 ;
2014-05-31 18:58:16 +00:00
rv = ( int ) nghttp2_hd_inflate_hd ( hd_inflater , & nv ,
& inflate_flags , headbuf , headlen , final ) ;
2014-05-06 15:54:47 +00:00
if ( rv < 0 ) {
break ;
}
headbuf + = rv ;
headlen - = rv ;
if ( inflate_flags & NGHTTP2_HD_INFLATE_EMIT ) {
tvbuff_t * next_tvb ;
char * str = ( char * ) g_malloc ( 4 + nv . namelen + 4 + nv . valuelen ) ;
/* Prepare tvb buffer... with the following format
name length ( uint32 )
name ( string )
value length ( uint32 )
value ( string )
*/
memcpy ( & str [ 0 ] , ( char * ) & nv . namelen , 4 ) ;
memcpy ( & str [ 4 ] , nv . name , nv . namelen ) ;
memcpy ( & str [ 4 + nv . namelen ] , ( char * ) & nv . valuelen , 4 ) ;
memcpy ( & str [ 4 + nv . namelen + 4 ] , nv . value , nv . valuelen ) ;
2014-05-31 18:58:16 +00:00
len = ( int ) ( 4 + nv . namelen + 4 + nv . valuelen ) ;
header_len + = len ;
2014-05-06 15:54:47 +00:00
2014-05-31 18:58:16 +00:00
/* Now setup the tvb buffer to have the new data */
next_tvb = tvb_new_child_real_data ( tvb , str , len , len ) ;
tvb_set_free_cb ( next_tvb , g_free ) ;
tvb_composite_append ( header_tvb , next_tvb ) ;
2014-05-06 15:54:47 +00:00
}
if ( inflate_flags & NGHTTP2_HD_INFLATE_FINAL ) {
nghttp2_hd_inflate_end_headers ( hd_inflater ) ;
break ;
}
if ( ( inflate_flags & NGHTTP2_HD_INFLATE_EMIT ) = = 0 & &
headlen = = 0 ) {
break ;
}
}
tvb_composite_finalize ( header_tvb ) ;
add_new_data_source ( pinfo , header_tvb , " Decompressed Header " ) ;
ti = proto_tree_add_uint ( tree , hf_http2_header_length , header_tvb , hoffset , 1 , header_len ) ;
PROTO_ITEM_SET_GENERATED ( ti ) ;
while ( tvb_reported_length_remaining ( header_tvb , hoffset ) > 0 ) {
/* Populate tree with header name/value details. */
/* Add 'Header' subtree with description. */
header = proto_tree_add_item ( tree , hf_http2_header , header_tvb , hoffset , - 1 , ENC_NA ) ;
header_tree = proto_item_add_subtree ( header , ett_http2_headers ) ;
/* header value length */
proto_tree_add_item ( header_tree , hf_http2_header_name_length , header_tvb , hoffset , 4 , ENC_LITTLE_ENDIAN ) ;
header_name_length = tvb_get_letohl ( header_tvb , hoffset ) ;
hoffset + = 4 ;
/* Add header name. */
proto_tree_add_item ( header_tree , hf_http2_header_name , header_tvb , hoffset , header_name_length , ENC_ASCII | ENC_NA ) ;
header_name = ( gchar * ) tvb_get_string_enc ( wmem_packet_scope ( ) , header_tvb , hoffset , header_name_length , ENC_ASCII | ENC_NA ) ;
hoffset + = header_name_length ;
/* header value length */
proto_tree_add_item ( header_tree , hf_http2_header_value_length , header_tvb , hoffset , 4 , ENC_LITTLE_ENDIAN ) ;
header_value_length = tvb_get_letohl ( header_tvb , hoffset ) ;
hoffset + = 4 ;
/* Add header value. */
proto_tree_add_item ( header_tree , hf_http2_header_value , header_tvb , hoffset , header_value_length , ENC_ASCII | ENC_NA ) ;
header_value = ( gchar * ) tvb_get_string_enc ( wmem_packet_scope ( ) , header_tvb , hoffset , header_value_length , ENC_ASCII | ENC_NA ) ;
hoffset + = header_value_length ;
proto_item_append_text ( header , " : %s: %s " , header_name , header_value ) ;
proto_item_set_len ( header , 4 + header_name_length + 4 + header_value_length ) ;
}
}
2013-08-30 11:14:09 +00:00
static guint8
2014-04-25 14:29:10 +00:00
dissect_http2_header_flags ( tvbuff_t * tvb , packet_info * pinfo _U_ , proto_tree * http2_tree , guint offset , guint8 type )
2013-08-30 11:14:09 +00:00
{
proto_item * ti_flags ;
proto_tree * flags_tree ;
guint8 flags ;
ti_flags = proto_tree_add_item ( http2_tree , hf_http2_flags , tvb , offset , 1 , ENC_NA ) ;
flags_tree = proto_item_add_subtree ( ti_flags , ett_http2_flags ) ;
flags = tvb_get_guint8 ( tvb , offset ) ;
switch ( type ) {
case HTTP2_DATA :
proto_tree_add_item ( flags_tree , hf_http2_flags_end_stream , tvb , offset , 1 , ENC_NA ) ;
2014-04-25 14:29:10 +00:00
proto_tree_add_item ( flags_tree , hf_http2_flags_end_segment , tvb , offset , 1 , ENC_NA ) ;
proto_tree_add_item ( flags_tree , hf_http2_flags_pad_low , tvb , offset , 1 , ENC_NA ) ;
proto_tree_add_item ( flags_tree , hf_http2_flags_pad_high , tvb , offset , 1 , ENC_NA ) ;
proto_tree_add_item ( flags_tree , hf_http2_flags_compressed , tvb , offset , 1 , ENC_NA ) ;
2014-05-12 07:00:52 +00:00
proto_tree_add_item ( flags_tree , hf_http2_flags_unused_data , tvb , offset , 1 , ENC_NA ) ;
2014-04-25 14:29:10 +00:00
break ;
2013-08-30 11:14:09 +00:00
case HTTP2_HEADERS :
proto_tree_add_item ( flags_tree , hf_http2_flags_end_stream , tvb , offset , 1 , ENC_NA ) ;
2014-04-25 14:29:10 +00:00
proto_tree_add_item ( flags_tree , hf_http2_flags_end_segment , tvb , offset , 1 , ENC_NA ) ;
2013-08-30 11:14:09 +00:00
proto_tree_add_item ( flags_tree , hf_http2_flags_end_headers , tvb , offset , 1 , ENC_NA ) ;
2014-04-25 14:29:10 +00:00
proto_tree_add_item ( flags_tree , hf_http2_flags_pad_low , tvb , offset , 1 , ENC_NA ) ;
proto_tree_add_item ( flags_tree , hf_http2_flags_pad_high , tvb , offset , 1 , ENC_NA ) ;
2013-08-30 11:14:09 +00:00
proto_tree_add_item ( flags_tree , hf_http2_flags_priority , tvb , offset , 1 , ENC_NA ) ;
2014-05-12 07:00:52 +00:00
proto_tree_add_item ( flags_tree , hf_http2_flags_unused6 , tvb , offset , 1 , ENC_NA ) ;
2014-04-25 14:29:10 +00:00
break ;
2013-08-30 11:14:09 +00:00
case HTTP2_SETTINGS :
2013-12-15 19:07:40 +00:00
proto_tree_add_item ( flags_tree , hf_http2_flags_settings_ack , tvb , offset , 1 , ENC_NA ) ;
2014-05-12 07:00:52 +00:00
proto_tree_add_item ( flags_tree , hf_http2_flags_unused1 , tvb , offset , 1 , ENC_NA ) ;
2014-04-25 14:29:10 +00:00
break ;
case HTTP2_PUSH_PROMISE :
case HTTP2_CONTINUATION :
proto_tree_add_item ( flags_tree , hf_http2_flags_end_headers , tvb , offset , 1 , ENC_NA ) ;
proto_tree_add_item ( flags_tree , hf_http2_flags_pad_low , tvb , offset , 1 , ENC_NA ) ;
proto_tree_add_item ( flags_tree , hf_http2_flags_pad_high , tvb , offset , 1 , ENC_NA ) ;
2014-05-12 07:00:52 +00:00
proto_tree_add_item ( flags_tree , hf_http2_flags_unused3 , tvb , offset , 1 , ENC_NA ) ;
2014-04-25 14:29:10 +00:00
break ;
case HTTP2_PING :
proto_tree_add_item ( flags_tree , hf_http2_flags_ping_ack , tvb , offset , 1 , ENC_NA ) ;
2014-05-12 07:00:52 +00:00
proto_tree_add_item ( flags_tree , hf_http2_flags_unused1 , tvb , offset , 1 , ENC_NA ) ;
2014-04-25 14:29:10 +00:00
break ;
2014-05-12 07:00:52 +00:00
case HTTP2_PRIORITY :
case HTTP2_RST_STREAM :
2013-08-30 11:14:09 +00:00
case HTTP2_GOAWAY :
case HTTP2_WINDOW_UPDATE :
2014-04-25 14:29:10 +00:00
case HTTP2_ALTSVC :
case HTTP2_BLOCKED :
2013-08-30 11:14:09 +00:00
default :
2014-05-12 07:00:52 +00:00
/* Does not define any flags */
proto_tree_add_item ( flags_tree , hf_http2_flags_unused , tvb , offset , 1 , ENC_NA ) ;
2014-04-25 14:29:10 +00:00
break ;
2013-08-30 11:14:09 +00:00
}
return flags ;
}
2014-04-25 14:29:10 +00:00
/* helper function to get the padding data for the frames that feature them */
static guint
dissect_frame_padding ( tvbuff_t * tvb , guint16 * padding , proto_tree * http2_tree ,
guint offset , guint8 flags )
2013-08-30 11:14:09 +00:00
{
2014-05-12 07:00:52 +00:00
proto_item * ti ;
guint pad_len = 0 ;
2014-04-25 14:29:10 +00:00
* padding = 0 ;
if ( flags & HTTP2_FLAGS_PAD_HIGH )
{
* padding = tvb_get_guint8 ( tvb , offset ) < < 8 ; /* read a single octet */
proto_tree_add_item ( http2_tree , hf_http2_pad_high , tvb , offset , 1 , ENC_NA ) ;
offset + + ;
2014-05-12 07:00:52 +00:00
pad_len + + ;
2014-04-25 14:29:10 +00:00
}
2013-08-30 11:14:09 +00:00
2014-04-25 14:29:10 +00:00
if ( flags & HTTP2_FLAGS_PAD_LOW )
2013-08-30 11:14:09 +00:00
{
2014-04-25 14:29:10 +00:00
* padding | = tvb_get_guint8 ( tvb , offset ) ; /* read a single octet */
proto_tree_add_item ( http2_tree , hf_http2_pad_low , tvb , offset , 1 , ENC_NA ) ;
offset + + ;
2014-05-12 07:00:52 +00:00
pad_len + + ;
2013-08-30 11:14:09 +00:00
}
2014-05-12 07:00:52 +00:00
ti = proto_tree_add_uint ( http2_tree , hf_http2_pad_length , tvb , offset - pad_len , pad_len , * padding ) ;
PROTO_ITEM_SET_GENERATED ( ti ) ;
2013-08-30 11:14:09 +00:00
return offset ;
}
2014-04-25 14:29:10 +00:00
/* helper function to get the priority dependence for the frames that feature them:
HEADERS and PRIORITY */
static guint
dissect_frame_prio ( tvbuff_t * tvb , proto_tree * http2_tree , guint offset , guint8 flags )
{
2014-05-13 15:49:24 +00:00
proto_tree * ti ;
guint8 weight ;
2014-04-25 14:29:10 +00:00
if ( flags & HTTP2_FLAGS_PRIORITY )
{
2014-05-13 15:49:24 +00:00
proto_tree_add_item ( http2_tree , hf_http2_excl_dependency , tvb , offset , 4 , ENC_NA ) ;
2014-04-25 14:29:10 +00:00
proto_tree_add_item ( http2_tree , hf_http2_stream_dependency , tvb , offset , 4 , ENC_NA ) ;
offset + = 4 ;
proto_tree_add_item ( http2_tree , hf_http2_weight , tvb , offset , 1 , ENC_NA ) ;
2014-05-13 15:49:24 +00:00
weight = tvb_get_guint8 ( tvb , offset ) ;
/* 6.2: Weight: An 8-bit weight for the stream; Add one to the value to obtain a weight between 1 and 256 */
ti = proto_tree_add_uint ( http2_tree , hf_http2_weight_real , tvb , offset , 1 , weight + 1 ) ;
PROTO_ITEM_SET_GENERATED ( ti ) ;
2014-04-25 14:29:10 +00:00
offset + + ;
}
return offset ;
}
/* Data (0) */
2013-08-30 11:14:09 +00:00
static int
2014-04-25 14:29:10 +00:00
dissect_http2_data ( tvbuff_t * tvb , packet_info * pinfo _U_ , proto_tree * http2_tree ,
guint offset , guint8 flags )
2013-08-30 11:14:09 +00:00
{
2014-04-25 14:29:10 +00:00
guint16 padding ;
2014-04-28 03:16:19 +00:00
gint datalen ;
2013-08-30 11:14:09 +00:00
2014-04-25 14:29:10 +00:00
offset = dissect_frame_padding ( tvb , & padding , http2_tree , offset , flags ) ;
datalen = tvb_reported_length_remaining ( tvb , offset ) - padding ;
proto_tree_add_item ( http2_tree , hf_http2_data_data , tvb , offset , datalen , ENC_ASCII | ENC_NA ) ;
offset + = datalen ;
2013-08-30 11:14:09 +00:00
2014-04-25 14:29:10 +00:00
proto_tree_add_item ( http2_tree , hf_http2_data_padding , tvb , offset , padding , ENC_NA ) ;
offset + = padding ;
return offset ;
}
/* Headers */
static int
dissect_http2_headers ( tvbuff_t * tvb , packet_info * pinfo _U_ , proto_tree * http2_tree ,
guint offset , guint8 flags )
{
guint16 padding ;
2014-04-28 03:16:19 +00:00
gint headlen ;
2014-05-06 15:54:47 +00:00
http2_session_t * h2session ;
h2session = get_http2_session ( pinfo ) ;
2014-04-25 14:29:10 +00:00
offset = dissect_frame_padding ( tvb , & padding , http2_tree , offset , flags ) ;
offset = dissect_frame_prio ( tvb , http2_tree , offset , flags ) ;
headlen = tvb_reported_length_remaining ( tvb , offset ) - padding ;
proto_tree_add_item ( http2_tree , hf_http2_headers , tvb , offset , headlen , ENC_ASCII | ENC_NA ) ;
2014-05-12 07:00:52 +00:00
2014-05-06 15:54:47 +00:00
/* decompress the header block */
inflate_http2_header_block ( tvb , pinfo , offset , http2_tree , headlen , h2session , flags ) ;
2014-04-25 14:29:10 +00:00
offset + = headlen ;
proto_tree_add_item ( http2_tree , hf_http2_headers_padding , tvb , offset , padding , ENC_NA ) ;
offset + = padding ;
return offset ;
}
/* Priority */
static int
dissect_http2_priority ( tvbuff_t * tvb , packet_info * pinfo _U_ , proto_tree * http2_tree ,
guint offset , guint8 flags )
{
/* we pretend the HTTP2_FLAGS_PRIORITY flag is set to share the dissect
function */
offset = dissect_frame_prio ( tvb , http2_tree , offset ,
flags | HTTP2_FLAGS_PRIORITY ) ;
2013-08-30 11:14:09 +00:00
return offset ;
}
/* RST Stream */
static int
dissect_http2_rst_stream ( tvbuff_t * tvb , packet_info * pinfo _U_ , proto_tree * http2_tree , guint offset , guint8 flags _U_ )
{
proto_tree_add_item ( http2_tree , hf_http2_rst_stream_error , tvb , offset , 4 , ENC_NA ) ;
offset + = 4 ;
return offset ;
}
/* Settings */
static int
dissect_http2_settings ( tvbuff_t * tvb , packet_info * pinfo _U_ , proto_tree * http2_tree , guint offset , guint8 flags _U_ )
{
guint32 settingsid ;
proto_item * ti_settings ;
proto_tree * settings_tree ;
2014-05-06 15:54:47 +00:00
/* FIXME: If we send SETTINGS_HEADER_TABLE_SIZE, after receiving
ACK from peer , we have to apply its value to HPACK decoder
using nghttp2_hd_inflate_change_table_size ( ) */
2013-08-30 11:14:09 +00:00
while ( tvb_reported_length_remaining ( tvb , offset ) > 0 ) {
2014-04-25 14:29:10 +00:00
ti_settings = proto_tree_add_item ( http2_tree , hf_http2_settings , tvb , offset , 5 , ENC_NA ) ;
2013-08-30 11:14:09 +00:00
settings_tree = proto_item_add_subtree ( ti_settings , ett_http2_settings ) ;
2014-04-25 14:29:10 +00:00
proto_tree_add_item ( settings_tree , hf_http2_settings_identifier , tvb , offset , 1 , ENC_NA ) ;
settingsid = tvb_get_guint8 ( tvb , offset ) ;
proto_item_append_text ( ti_settings , " - %s " ,
val_to_str ( settingsid , http2_settings_vals , " Unknown (%u) " ) ) ;
offset + + ;
2013-08-30 11:14:09 +00:00
switch ( settingsid ) {
2013-12-15 19:07:40 +00:00
case HTTP2_SETTINGS_HEADER_TABLE_SIZE :
proto_tree_add_item ( settings_tree , hf_http2_settings_header_table_size , tvb , offset , 4 , ENC_NA ) ;
break ;
case HTTP2_SETTINGS_ENABLE_PUSH :
proto_tree_add_item ( settings_tree , hf_http2_settings_enable_push , tvb , offset , 4 , ENC_NA ) ;
break ;
2013-08-30 11:14:09 +00:00
case HTTP2_SETTINGS_MAX_CONCURRENT_STREAMS :
proto_tree_add_item ( settings_tree , hf_http2_settings_max_concurrent_streams , tvb , offset , 4 , ENC_NA ) ;
break ;
case HTTP2_SETTINGS_INITIAL_WINDOW_SIZE :
proto_tree_add_item ( settings_tree , hf_http2_settings_initial_window_size , tvb , offset , 4 , ENC_NA ) ;
break ;
2014-04-25 14:29:10 +00:00
case HTTP2_SETTINGS_COMPRESS_DATA :
proto_tree_add_item ( settings_tree , hf_http2_settings_compress_data , tvb , offset , 4 , ENC_NA ) ;
2013-08-30 11:14:09 +00:00
break ;
default :
proto_tree_add_item ( settings_tree , hf_http2_settings_unknown , tvb , offset , 4 , ENC_NA ) ;
break ;
}
proto_item_append_text ( ti_settings , " : %u " , tvb_get_ntohl ( tvb , offset ) ) ;
offset + = 4 ;
}
return offset ;
}
/* Push Promise */
static int
2014-04-25 14:29:10 +00:00
dissect_http2_push_promise ( tvbuff_t * tvb , packet_info * pinfo _U_ , proto_tree * http2_tree ,
guint offset , guint8 flags _U_ )
2013-08-30 11:14:09 +00:00
{
2014-04-25 14:29:10 +00:00
guint16 padding ;
2014-05-12 07:00:52 +00:00
gint headlen ;
2014-05-06 15:54:47 +00:00
http2_session_t * h2session ;
h2session = get_http2_session ( pinfo ) ;
2013-08-30 11:14:09 +00:00
2014-04-25 14:29:10 +00:00
offset = dissect_frame_padding ( tvb , & padding , http2_tree , offset , flags ) ;
proto_tree_add_item ( http2_tree , hf_http2_push_promise_r , tvb , offset , 1 , ENC_NA ) ;
proto_tree_add_item ( http2_tree , hf_http2_push_promise_promised_stream_id , tvb ,
offset , 4 , ENC_NA ) ;
2013-08-30 11:14:09 +00:00
offset + = 4 ;
2014-05-12 07:00:52 +00:00
headlen = tvb_reported_length_remaining ( tvb , offset ) - padding ;
proto_tree_add_item ( http2_tree , hf_http2_push_promise_header , tvb , offset , headlen ,
2014-04-25 14:29:10 +00:00
ENC_ASCII | ENC_NA ) ;
2014-05-06 15:54:47 +00:00
inflate_http2_header_block ( tvb , pinfo , offset , http2_tree , headlen , h2session , flags ) ;
2014-05-12 07:00:52 +00:00
offset + = headlen ;
2014-04-25 14:29:10 +00:00
proto_tree_add_item ( http2_tree , hf_http2_push_promise_padding , tvb ,
offset , padding , ENC_NA ) ;
2013-08-30 11:14:09 +00:00
offset + = tvb_reported_length_remaining ( tvb , offset ) ;
return offset ;
}
/* Ping */
static int
2014-04-25 14:29:10 +00:00
dissect_http2_ping ( tvbuff_t * tvb , packet_info * pinfo _U_ , proto_tree * http2_tree ,
guint offset , guint8 flags )
2013-08-30 11:14:09 +00:00
{
/* TODO : Add Response time */
2013-12-15 19:07:40 +00:00
if ( flags & HTTP2_FLAGS_ACK )
2013-08-30 11:14:09 +00:00
{
proto_tree_add_item ( http2_tree , hf_http2_pong , tvb , offset , 8 , ENC_NA ) ;
} else {
proto_tree_add_item ( http2_tree , hf_http2_ping , tvb , offset , 8 , ENC_NA ) ;
}
offset + = 8 ;
return offset ;
}
/* Goaway */
static int
dissect_http2_goaway ( tvbuff_t * tvb , packet_info * pinfo _U_ , proto_tree * http2_tree , guint offset , guint8 flags _U_ )
{
proto_tree_add_item ( http2_tree , hf_http2_goaway_r , tvb , offset , 4 , ENC_NA ) ;
proto_tree_add_item ( http2_tree , hf_http2_goaway_last_stream_id , tvb , offset , 4 , ENC_NA ) ;
offset + = 4 ;
proto_tree_add_item ( http2_tree , hf_http2_goaway_error , tvb , offset , 4 , ENC_NA ) ;
offset + = 4 ;
if ( tvb_reported_length_remaining ( tvb , offset ) > 0 )
{
proto_tree_add_item ( http2_tree , hf_http2_goaway_addata , tvb , offset , - 1 , ENC_NA ) ;
offset + = tvb_reported_length_remaining ( tvb , offset ) ;
}
return offset ;
}
/* Window Update */
static int
dissect_http2_window_update ( tvbuff_t * tvb , packet_info * pinfo _U_ , proto_tree * http2_tree , guint offset , guint8 flags _U_ )
{
proto_tree_add_item ( http2_tree , hf_http2_window_update_r , tvb , offset , 4 , ENC_NA ) ;
proto_tree_add_item ( http2_tree , hf_http2_window_update_window_size_increment , tvb , offset , 4 , ENC_NA ) ;
offset + = 4 ;
return offset ;
}
static int
2014-05-12 07:00:52 +00:00
dissect_http2_continuation ( tvbuff_t * tvb , packet_info * pinfo _U_ , proto_tree * http2_tree , guint offset , guint8 flags )
2013-08-30 11:14:09 +00:00
{
2014-05-12 07:00:52 +00:00
guint16 padding ;
gint headlen ;
2014-05-06 15:54:47 +00:00
http2_session_t * h2session ;
h2session = get_http2_session ( pinfo ) ;
2014-05-12 07:00:52 +00:00
offset = dissect_frame_padding ( tvb , & padding , http2_tree , offset , flags ) ;
2013-08-30 11:14:09 +00:00
2014-05-12 07:00:52 +00:00
headlen = tvb_reported_length_remaining ( tvb , offset ) - padding ;
proto_tree_add_item ( http2_tree , hf_http2_continuation_header , tvb , offset , headlen , ENC_ASCII | ENC_NA ) ;
2014-05-06 15:54:47 +00:00
inflate_http2_header_block ( tvb , pinfo , offset , http2_tree , headlen , h2session , flags ) ;
2014-05-12 07:00:52 +00:00
offset + = headlen ;
proto_tree_add_item ( http2_tree , hf_http2_continuation_padding , tvb , offset , padding , ENC_NA ) ;
offset + = padding ;
2013-08-30 11:14:09 +00:00
return offset ;
}
2014-04-25 14:29:10 +00:00
/* Altsvc */
static int
dissect_http2_altsvc ( tvbuff_t * tvb , packet_info * pinfo _U_ , proto_tree * http2_tree ,
guint offset , guint8 flags _U_ , guint16 length )
{
guint8 pidlen ;
guint8 hostlen ;
int remain ;
proto_tree_add_item ( http2_tree , hf_http2_altsvc_maxage , tvb , offset , 4 , ENC_NA ) ;
offset + = 4 ;
proto_tree_add_item ( http2_tree , hf_http2_altsvc_port , tvb , offset , 2 , ENC_NA ) ;
offset + = 2 ;
proto_tree_add_item ( http2_tree , hf_http2_altsvc_res , tvb , offset , 1 , ENC_NA ) ;
offset + + ;
proto_tree_add_item ( http2_tree , hf_http2_altsvc_proto_len , tvb , offset , 1 , ENC_NA ) ;
pidlen = tvb_get_guint8 ( tvb , offset ) ;
offset + + ;
proto_tree_add_item ( http2_tree , hf_http2_altsvc_protocol , tvb , offset , pidlen , ENC_ASCII | ENC_NA ) ;
offset + = pidlen ;
proto_tree_add_item ( http2_tree , hf_http2_altsvc_host_len , tvb , offset , 1 , ENC_NA ) ;
hostlen = tvb_get_guint8 ( tvb , offset ) ;
offset + + ;
proto_tree_add_item ( http2_tree , hf_http2_altsvc_host , tvb , offset , hostlen , ENC_ASCII | ENC_NA ) ;
offset + = hostlen ;
remain = length - offset ;
if ( remain > - 8 ) {
/* 8 is the fixed size of the http2 frame header */
proto_tree_add_item ( http2_tree , hf_http2_altsvc_origin , tvb ,
offset , remain + 8 , ENC_ASCII | ENC_NA ) ;
offset + = remain ;
}
return offset ;
}
2013-11-09 17:46:28 +00:00
static int
dissect_http2_pdu ( tvbuff_t * tvb , packet_info * pinfo , proto_tree * tree , void * data _U_ )
2013-08-30 11:14:09 +00:00
{
proto_item * ti ;
proto_tree * http2_tree ;
guint offset = 0 ;
guint8 type , flags ;
guint16 length ;
guint32 streamid ;
/* 4.1 Frame Format
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - +
| Length ( 16 ) | Type ( 8 ) | Flags ( 8 ) |
+ - + - - - - - - - - - - - - - + - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| R | Stream Identifier ( 31 ) |
+ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| Frame Payload ( 0. . . ) . . .
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
*/
ti = proto_tree_add_item ( tree , hf_http2 , tvb , 0 , - 1 , ENC_NA ) ;
http2_tree = proto_item_add_subtree ( ti , ett_http2_header ) ;
/* 3.5 Connection Header
Upon establishment of a TCP connection and determination that
HTTP / 2.0 will be used by both peers , each endpoint MUST send a
connection header as a final confirmation and to establish the
initial settings for the HTTP / 2.0 connection .
*/
/* tvb_memeql makes certain there are enough bytes in the buffer.
* returns - 1 if there are not enough bytes or if there is not a
* match . Returns 0 on a match
*/
if ( tvb_memeql ( tvb , offset , kMagicHello , MAGIC_FRAME_LENGTH ) = = 0 )
{
col_append_sep_str ( pinfo - > cinfo , COL_INFO , " , " , " Magic " ) ;
proto_item_set_len ( ti , MAGIC_FRAME_LENGTH ) ;
proto_item_append_text ( ti , " : Magic " ) ;
proto_tree_add_item ( http2_tree , hf_http2_magic , tvb , offset , MAGIC_FRAME_LENGTH , ENC_ASCII | ENC_NA ) ;
2014-05-12 07:00:52 +00:00
2014-05-06 15:54:47 +00:00
create_http2_session ( pinfo ) ;
2013-11-09 17:46:28 +00:00
return MAGIC_FRAME_LENGTH ;
2013-08-30 11:14:09 +00:00
}
proto_tree_add_item ( http2_tree , hf_http2_length , tvb , offset , 2 , ENC_NA ) ;
2013-12-15 19:07:40 +00:00
proto_tree_add_item ( http2_tree , hf_http2_len_rsv , tvb , offset , 2 , ENC_NA ) ;
length = tvb_get_ntohs ( tvb , offset ) & MASK_HTTP2_LENGTH ;
2013-08-30 11:14:09 +00:00
offset + = 2 ;
proto_tree_add_item ( http2_tree , hf_http2_type , tvb , offset , 1 , ENC_NA ) ;
type = tvb_get_guint8 ( tvb , offset ) ;
col_append_sep_fstr ( pinfo - > cinfo , COL_INFO , " , " , " %s " , val_to_str ( type , http2_type_vals , " Unknown type (%d) " ) ) ;
offset + = 1 ;
flags = dissect_http2_header_flags ( tvb , pinfo , http2_tree , offset , type ) ;
offset + = 1 ;
proto_tree_add_item ( http2_tree , hf_http2_r , tvb , offset , 4 , ENC_NA ) ;
proto_tree_add_item ( http2_tree , hf_http2_streamid , tvb , offset , 4 , ENC_NA ) ;
streamid = tvb_get_ntohl ( tvb , offset ) & MASK_HTTP2_STREAMID ;
proto_item_append_text ( ti , " : %s, Stream ID: %u, Length %u " , val_to_str ( type , http2_type_vals , " Unknown type (%d) " ) , streamid , length ) ;
offset + = 4 ;
switch ( type ) {
case HTTP2_DATA : /* Data (0) */
2014-04-25 14:29:10 +00:00
dissect_http2_data ( tvb , pinfo , http2_tree , offset , flags ) ;
2013-08-30 11:14:09 +00:00
break ;
case HTTP2_HEADERS : /* Headers (1) */
dissect_http2_headers ( tvb , pinfo , http2_tree , offset , flags ) ;
break ;
case HTTP2_PRIORITY : /* Priority (2) */
dissect_http2_priority ( tvb , pinfo , http2_tree , offset , flags ) ;
break ;
case HTTP2_RST_STREAM : /* RST Stream (3) */
dissect_http2_rst_stream ( tvb , pinfo , http2_tree , offset , flags ) ;
break ;
case HTTP2_SETTINGS : /* Settings (4) */
dissect_http2_settings ( tvb , pinfo , http2_tree , offset , flags ) ;
break ;
case HTTP2_PUSH_PROMISE : /* PUSH Promise (5) */
dissect_http2_push_promise ( tvb , pinfo , http2_tree , offset , flags ) ;
break ;
case HTTP2_PING : /* Ping (6) */
dissect_http2_ping ( tvb , pinfo , http2_tree , offset , flags ) ;
break ;
case HTTP2_GOAWAY : /* Goaway (7) */
dissect_http2_goaway ( tvb , pinfo , http2_tree , offset , flags ) ;
break ;
2014-04-25 14:29:10 +00:00
case HTTP2_WINDOW_UPDATE : /* Window Update (8) */
2013-08-30 11:14:09 +00:00
dissect_http2_window_update ( tvb , pinfo , http2_tree , offset , flags ) ;
break ;
2014-04-25 14:29:10 +00:00
case HTTP2_CONTINUATION : /* Continuation (9) */
2013-08-30 11:14:09 +00:00
dissect_http2_continuation ( tvb , pinfo , http2_tree , offset , flags ) ;
break ;
2014-04-25 14:29:10 +00:00
case HTTP2_ALTSVC : /* ALTSVC (10) */
dissect_http2_altsvc ( tvb , pinfo , http2_tree , offset , flags , length ) ;
break ;
case HTTP2_BLOCKED : /* BLOCKED (11) */
/* no payload! */
break ;
2013-08-30 11:14:09 +00:00
default :
proto_tree_add_item ( http2_tree , hf_http2_unknown , tvb , offset , - 1 , ENC_NA ) ;
break ;
}
2014-05-06 15:54:47 +00:00
return tvb_captured_length ( tvb ) ;
2013-08-30 11:14:09 +00:00
}
static guint get_http2_message_len ( packet_info * pinfo _U_ , tvbuff_t * tvb , int offset )
{
if ( tvb_memeql ( tvb , offset , kMagicHello , MAGIC_FRAME_LENGTH ) = = 0 ) {
return MAGIC_FRAME_LENGTH ;
}
return ( guint ) tvb_get_ntohs ( tvb , offset ) + FRAME_HEADER_LENGTH ;
}
static int
dissect_http2 ( tvbuff_t * tvb , packet_info * pinfo , proto_tree * tree ,
2013-11-09 17:46:28 +00:00
void * data )
2013-08-30 11:14:09 +00:00
{
proto_item * ti ;
proto_tree * http2_tree ;
/* Check that there's enough data */
2014-05-06 15:54:47 +00:00
if ( tvb_captured_length ( tvb ) < FRAME_HEADER_LENGTH )
2013-08-30 11:14:09 +00:00
return 0 ;
col_set_str ( pinfo - > cinfo , COL_PROTOCOL , " HTTP2 " ) ;
col_clear ( pinfo - > cinfo , COL_INFO ) ;
ti = proto_tree_add_item ( tree , proto_http2 , tvb , 0 , - 1 , ENC_NA ) ;
2014-04-25 14:29:10 +00:00
proto_item_append_text ( ti , " (draft-12) " ) ;
2013-08-30 11:14:09 +00:00
http2_tree = proto_item_add_subtree ( ti , ett_http2 ) ;
tcp_dissect_pdus ( tvb , pinfo , http2_tree , TRUE , FRAME_HEADER_LENGTH ,
2013-11-09 17:46:28 +00:00
get_http2_message_len , dissect_http2_pdu , data ) ;
2013-08-30 11:14:09 +00:00
2014-05-06 15:54:47 +00:00
return tvb_captured_length ( tvb ) ;
2013-08-30 11:14:09 +00:00
}
2013-11-29 08:02:09 +00:00
static gboolean
dissect_http2_heur ( tvbuff_t * tvb , packet_info * pinfo , proto_tree * tree , void * data )
{
2013-12-23 09:42:10 +00:00
if ( tvb_memeql ( tvb , 0 , kMagicHello , MAGIC_FRAME_LENGTH ) ! = 0 ) {
/* we couldn't find the Magic Hello (PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n)
2014-06-02 14:57:41 +00:00
see if there ' s a valid frame type ( 0 - 11 are defined at the moment ) */
if ( tvb_reported_length ( tvb ) < 2 | | tvb_get_guint8 ( tvb , 2 ) > = HTTP2_BLOCKED )
2013-12-23 09:42:10 +00:00
return ( FALSE ) ;
}
2013-11-29 08:02:09 +00:00
dissect_http2 ( tvb , pinfo , tree , data ) ;
return ( TRUE ) ;
}
2013-08-30 11:14:09 +00:00
void
proto_register_http2 ( void )
{
static hf_register_info hf [ ] = {
/* Packet Header */
{ & hf_http2 ,
{ " Stream " , " http2 " ,
FT_NONE , BASE_NONE , NULL , 0x0 ,
NULL , HFILL }
} ,
{ & hf_http2_length ,
{ " Length " , " http2.length " ,
2013-12-15 19:07:40 +00:00
FT_UINT16 , BASE_DEC , NULL , MASK_HTTP2_LENGTH ,
" The length (14 bits) of the frame payload (The 8 octets of the frame header are not included) " , HFILL }
} ,
{ & hf_http2_len_rsv ,
{ " Reserved " , " http2.len.rsv " ,
FT_UINT16 , BASE_DEC , NULL , MASK_HTTP2_LEN_RSV ,
" Must be zero " , HFILL }
2013-08-30 11:14:09 +00:00
} ,
{ & hf_http2_type ,
{ " Type " , " http2.type " ,
FT_UINT8 , BASE_DEC , VALS ( http2_type_vals ) , 0x0 ,
" The frame type determines how the remainder of the frame header and payload are interpreted " , HFILL }
} ,
{ & hf_http2_r ,
{ " Reserved " , " http2.r " ,
FT_UINT32 , BASE_HEX , NULL , MASK_HTTP2_RESERVED ,
" The semantics of this bit are undefined and the bit MUST remain unset (0) when sending and MUST be ignored when receiving " , HFILL }
} ,
2014-04-25 14:29:10 +00:00
{ & hf_http2_weight ,
{ " Weight " , " http2.headers.weight " ,
FT_UINT8 , BASE_DEC , NULL , 0x0 ,
" An 8-bit weight for the identified priority " , HFILL }
} ,
2014-05-13 15:49:24 +00:00
{ & hf_http2_weight_real ,
{ " Weight real " , " http2.headers.weight_real " ,
FT_UINT8 , BASE_DEC , NULL , 0x0 ,
" Real Weight value (Add one to value) " , HFILL }
} ,
2013-08-30 11:14:09 +00:00
{ & hf_http2_streamid ,
{ " Stream Identifier " , " http2.streamid " ,
FT_UINT32 , BASE_DEC , NULL , MASK_HTTP2_STREAMID ,
" A 31-bit stream identifier " , HFILL }
} ,
{ & hf_http2_magic ,
{ " Magic " , " http2.magic " ,
FT_STRING , BASE_NONE , NULL , 0x0 ,
NULL , HFILL }
} ,
{ & hf_http2_unknown ,
{ " Unknown " , " http2.unknown " ,
FT_BYTES , BASE_NONE , NULL , 0x0 ,
NULL , HFILL }
} ,
/* Flags */
{ & hf_http2_flags ,
{ " Flags " , " http2.flags " ,
FT_UINT8 , BASE_HEX , NULL , 0x0 ,
" Flags are assigned semantics specific to the indicated frame type " , HFILL }
} ,
{ & hf_http2_flags_end_stream ,
2014-04-25 14:29:10 +00:00
{ " End Stream " , " http2.flags.end_stream " ,
FT_BOOLEAN , 8 , NULL , HTTP2_FLAGS_END_STREAM ,
2013-12-15 19:07:40 +00:00
" Indicates that this frame is the last that the endpoint will send for the identified stream " , HFILL }
2013-08-30 11:14:09 +00:00
} ,
2014-04-25 14:29:10 +00:00
{ & hf_http2_flags_end_segment ,
{ " End Segment " , " http2.flags.end_segment " ,
FT_BOOLEAN , 8 , NULL , HTTP2_FLAGS_END_SEGMENT ,
" Indicates that this frame is the last for the current segment " , HFILL }
} ,
2013-08-30 11:14:09 +00:00
{ & hf_http2_flags_end_headers ,
{ " End Headers " , " http2.flags.eh " ,
2014-04-25 14:29:10 +00:00
FT_BOOLEAN , 8 , NULL , HTTP2_FLAGS_END_HEADERS ,
2013-12-15 19:07:40 +00:00
" Indicates that this frame contains an entire header block and is not followed by any CONTINUATION frames. " , HFILL }
2013-08-30 11:14:09 +00:00
} ,
2014-04-25 14:29:10 +00:00
{ & hf_http2_flags_pad_low ,
{ " Pad Low " , " http2.flags.pad_low " ,
FT_BOOLEAN , 8 , NULL , HTTP2_FLAGS_PAD_LOW ,
" Indicates that the Pad Low field is present " , HFILL }
} ,
{ & hf_http2_flags_pad_high ,
{ " Pad High " , " http2.flags.pad_high " ,
FT_BOOLEAN , 8 , NULL , HTTP2_FLAGS_PAD_HIGH ,
" Indicates that the Pad High field is present " , HFILL }
} ,
2013-08-30 11:14:09 +00:00
{ & hf_http2_flags_priority ,
2014-04-25 14:29:10 +00:00
{ " Priority " , " http2.flags.priority " ,
FT_BOOLEAN , 8 , NULL , HTTP2_FLAGS_PRIORITY ,
" Indicates that the Exclusive Flag (E), Stream Dependency, and Weight fields are present " , HFILL }
2013-08-30 11:14:09 +00:00
} ,
2014-04-25 14:29:10 +00:00
{ & hf_http2_flags_compressed ,
{ " Compressed " , " http2.flags.compressed " ,
FT_BOOLEAN , 8 , NULL , HTTP2_FLAGS_COMPRESSED ,
" Indicates that the data in the frame has been compressed with GZIP compression " , HFILL }
2013-08-30 11:14:09 +00:00
} ,
2014-04-25 14:29:10 +00:00
2013-12-15 19:07:40 +00:00
{ & hf_http2_flags_ping_ack ,
{ " ACK " , " http2.flags.ack.ping " ,
FT_BOOLEAN , 8 , NULL , HTTP2_FLAGS_ACK ,
2013-08-30 11:14:09 +00:00
" Set indicates that this PING frame is a PING response " , HFILL }
} ,
2014-05-12 07:00:52 +00:00
{ & hf_http2_flags_unused ,
{ " Unused " , " http2.flags.unused " ,
FT_UINT8 , BASE_HEX , NULL , 0xFF ,
" Must be zero " , HFILL }
} ,
{ & hf_http2_flags_unused1 ,
{ " Unused " , " http2.flags.unused1 " ,
FT_UINT8 , BASE_HEX , NULL , 0xFE ,
" Must be zero " , HFILL }
} ,
{ & hf_http2_flags_unused3 ,
{ " Unused " , " http2.flags.unused3 " ,
FT_UINT8 , BASE_HEX , NULL , 0xF8 ,
" Must be zero " , HFILL }
} ,
{ & hf_http2_flags_unused_data ,
{ " Unused " , " http2.flags.unused_data " ,
FT_UINT8 , BASE_HEX , NULL , 0xC4 ,
" Must be zero " , HFILL }
} ,
{ & hf_http2_flags_unused6 ,
{ " Unused " , " http2.flags.unused6 " ,
FT_UINT8 , BASE_HEX , NULL , 0xC0 ,
" Must be zero " , HFILL }
} ,
2013-12-15 19:07:40 +00:00
{ & hf_http2_flags_settings_ack ,
{ " ACK " , " http2.flags.ack.settings " ,
FT_BOOLEAN , 8 , NULL , HTTP2_FLAGS_ACK ,
" Indicates that this frame acknowledges receipt and application of the peer's SETTINGS frame " , HFILL }
} ,
2014-04-25 14:29:10 +00:00
{ & hf_http2_pad_high ,
{ " Pad High " , " http2.pad_high " ,
FT_UINT8 , BASE_HEX , NULL , 0x0 ,
" Padding size high bits " , HFILL }
2013-08-30 11:14:09 +00:00
} ,
2014-04-25 14:29:10 +00:00
{ & hf_http2_pad_low ,
{ " Pad Low " , " http2.pad_low " ,
FT_UINT8 , BASE_HEX , NULL , 0x0 ,
" Padding size low bits " , HFILL }
2013-08-30 11:14:09 +00:00
} ,
2014-05-12 07:00:52 +00:00
{ & hf_http2_pad_length ,
{ " Pad Length " , " http2.pad_length " ,
FT_UINT16 , BASE_DEC , NULL , 0x0 ,
NULL , HFILL }
} ,
2014-04-25 14:29:10 +00:00
{ & hf_http2_excl_dependency ,
{ " Exclusive " , " http2.exclusive " ,
2014-05-13 15:49:24 +00:00
FT_BOOLEAN , 32 , NULL , 0x80000000 ,
2014-04-25 14:29:10 +00:00
" A single bit flag indicates that the stream dependency is exclusive " , HFILL }
2013-08-30 11:14:09 +00:00
} ,
2014-04-25 14:29:10 +00:00
{ & hf_http2_stream_dependency ,
{ " Stream Dependency " , " http2.stream_dependency " ,
2014-05-13 15:49:24 +00:00
FT_UINT32 , BASE_DEC , NULL , 0x7FFFFFFF ,
2014-04-25 14:29:10 +00:00
" An identifier for the stream that this stream depends on " , HFILL }
2013-08-30 11:14:09 +00:00
} ,
2014-04-25 14:29:10 +00:00
/* Data */
{ & hf_http2_data_data ,
{ " Data " , " http2.data.data " ,
FT_BYTES , BASE_NONE , NULL , 0x0 ,
" Application data " , HFILL }
2013-08-30 11:14:09 +00:00
} ,
2014-04-25 14:29:10 +00:00
{ & hf_http2_data_padding ,
{ " Padding " , " http2.data.padding " ,
FT_BYTES , BASE_NONE , NULL , 0x0 ,
" Padding octets " , HFILL }
} ,
/* Headers */
{ & hf_http2_headers ,
{ " Header Block Fragment " , " http2.headers " ,
FT_BYTES , BASE_NONE , NULL , 0x0 ,
" A header block fragment " , HFILL }
} ,
{ & hf_http2_headers_padding ,
{ " Padding " , " http2.headers.padding " ,
FT_BYTES , BASE_NONE , NULL , 0x0 ,
" Padding octets " , HFILL }
2013-08-30 11:14:09 +00:00
} ,
2014-05-06 15:54:47 +00:00
{ & hf_http2_header ,
{ " Header " , " http2.header " ,
FT_NONE , BASE_NONE , NULL , 0x0 ,
NULL , HFILL }
} ,
{ & hf_http2_header_length ,
{ " Header Length " , " http2.header.length " ,
FT_UINT32 , BASE_DEC , NULL , 0x0 ,
NULL , HFILL }
} ,
{ & hf_http2_header_name_length ,
{ " Name Length " , " http2.header.name.length " ,
FT_UINT32 , BASE_DEC , NULL , 0x0 ,
NULL , HFILL }
} ,
{ & hf_http2_header_name ,
{ " Name " , " http2.header.name " ,
FT_STRING , BASE_NONE , NULL , 0x0 ,
NULL , HFILL }
} ,
{ & hf_http2_header_value_length ,
{ " Value Length " , " http2.header.value.length " ,
FT_UINT32 , BASE_DEC , NULL , 0x0 ,
NULL , HFILL }
} ,
{ & hf_http2_header_value ,
{ " Value " , " http2.header.value " ,
FT_STRING , BASE_NONE , NULL , 0x0 ,
NULL , HFILL }
} ,
2013-08-30 11:14:09 +00:00
/* RST Stream */
{ & hf_http2_rst_stream_error ,
{ " Error " , " http2.rst_stream.error " ,
FT_UINT32 , BASE_DEC , VALS ( http2_error_codes_vals ) , 0x0 ,
" The error code indicates why the stream is being terminated " , HFILL }
} ,
/* Settings */
{ & hf_http2_settings ,
{ " Settings " , " http2.settings " ,
FT_NONE , BASE_NONE , NULL , 0x0 ,
NULL , HFILL }
} ,
{ & hf_http2_settings_identifier ,
{ " Settings Identifier " , " http2.settings.id " ,
2014-04-25 14:29:10 +00:00
FT_UINT8 , BASE_DEC , VALS ( http2_settings_vals ) , 0x0 ,
2013-08-30 11:14:09 +00:00
NULL , HFILL }
} ,
2013-12-15 19:07:40 +00:00
{ & hf_http2_settings_header_table_size ,
{ " Header table size " , " http2.settings.header_table_size " ,
FT_UINT32 , BASE_DEC , NULL , 0x0 ,
2014-04-25 14:29:10 +00:00
" Allows the sender to inform the remote endpoint of the size of the header compression table used to decode header blocks. The initial value is 4096 bytes " , HFILL }
2013-12-15 19:07:40 +00:00
} ,
{ & hf_http2_settings_enable_push ,
{ " Enable PUSH " , " http2.settings.enable_push " ,
FT_UINT32 , BASE_DEC , NULL , 0x0 ,
" The initial value is 1, which indicates that push is permitted " , HFILL }
} ,
2013-08-30 11:14:09 +00:00
{ & hf_http2_settings_max_concurrent_streams ,
{ " Max concurrent streams " , " http2.settings.max_concurrent_streams " ,
FT_UINT32 , BASE_DEC , NULL , 0x0 ,
" Indicates the maximum number of concurrent streams that the sender will allow " , HFILL }
} ,
{ & hf_http2_settings_initial_window_size ,
{ " Initial Windows Size " , " http2.settings.initial_window_size " ,
FT_UINT32 , BASE_DEC , NULL , 0x0 ,
" Indicates the sender's initial window size (in bytes) for stream level flow control " , HFILL }
} ,
2014-04-25 14:29:10 +00:00
{ & hf_http2_settings_compress_data ,
{ " Compress Data " , " http2.settings.compress_data " ,
2013-08-30 11:14:09 +00:00
FT_UINT32 , BASE_DEC , NULL , 0x0 ,
2014-04-25 14:29:10 +00:00
" Enables GZip compression of DATA frames. Values other than 0 or 1 are invalid " , HFILL }
2013-08-30 11:14:09 +00:00
} ,
{ & hf_http2_settings_unknown ,
{ " Unknown Settings " , " http2.settings.unknown " ,
FT_UINT32 , BASE_DEC , NULL , 0x0 ,
NULL , HFILL }
} ,
/* Push Promise */
{ & hf_http2_push_promise_r ,
{ " Reserved " , " http2.push_promise.r " ,
FT_UINT32 , BASE_HEX , NULL , MASK_HTTP2_RESERVED ,
" Must be zero " , HFILL }
} ,
2014-04-25 14:29:10 +00:00
2013-08-30 11:14:09 +00:00
{ & hf_http2_push_promise_promised_stream_id ,
{ " Promised-Stream-ID " , " http2.push_promise.promised_stream_id " ,
FT_UINT32 , BASE_DEC , NULL , MASK_HTTP2_PRIORITY ,
" Identifies the stream the endpoint intends to start sending frames for " , HFILL }
} ,
{ & hf_http2_push_promise_header ,
{ " Header " , " http2.push_promise.header " ,
FT_STRING , BASE_NONE , NULL , 0x0 ,
NULL , HFILL }
} ,
2014-04-25 14:29:10 +00:00
{ & hf_http2_push_promise_padding ,
{ " Padding " , " http2.push_promise.padding " ,
FT_BYTES , BASE_NONE , NULL , 0x0 ,
" Padding octets " , HFILL }
} ,
2013-08-30 11:14:09 +00:00
/* Ping / Pong */
{ & hf_http2_ping ,
{ " Ping " , " http2.ping " ,
FT_BYTES , BASE_NONE , NULL , 0x0 ,
NULL , HFILL }
} ,
{ & hf_http2_pong ,
{ " Pong " , " http2.pong " ,
FT_BYTES , BASE_NONE , NULL , 0x0 ,
NULL , HFILL }
} ,
/* Goaway */
{ & hf_http2_goaway_r ,
{ " Reserved " , " http2.goway.r " ,
FT_UINT32 , BASE_HEX , NULL , MASK_HTTP2_RESERVED ,
" Must be zero " , HFILL }
} ,
{ & hf_http2_goaway_last_stream_id ,
{ " Promised-Stream-ID " , " http2.goaway.last_stream_id " ,
FT_UINT32 , BASE_DEC , NULL , MASK_HTTP2_PRIORITY ,
" Contains the highest numbered stream identifier for which the sender of the GOAWAY frame has received frames on and might have taken some action on " , HFILL }
} ,
{ & hf_http2_goaway_error ,
{ " Error " , " http2.goaway.error " ,
FT_UINT32 , BASE_DEC , VALS ( http2_error_codes_vals ) , 0x0 ,
" The error code indicates the reason for closing the connection " , HFILL }
} ,
{ & hf_http2_goaway_addata ,
{ " Additional Debug Data " , " http2.goaway.addata " ,
FT_BYTES , BASE_NONE , NULL , 0x0 ,
NULL , HFILL }
} ,
/* Window Update */
{ & hf_http2_window_update_r ,
{ " Reserved " , " http2.window_update.r " ,
FT_UINT32 , BASE_HEX , NULL , MASK_HTTP2_RESERVED ,
" Must be zero " , HFILL }
} ,
{ & hf_http2_window_update_window_size_increment ,
{ " Window Size Increment " , " http2.window_update.window_size_increment " ,
FT_UINT32 , BASE_DEC , NULL , MASK_HTTP2_PRIORITY ,
" Indicating the number of bytes that the sender can transmit in addition to the existing flow control window " , HFILL }
} ,
/* Continuation */
{ & hf_http2_continuation_header ,
{ " Continuation Header " , " http2.continuation.header " ,
FT_STRING , BASE_NONE , NULL , 0x0 ,
" Contains a header block fragment " , HFILL }
} ,
2014-05-12 07:00:52 +00:00
{ & hf_http2_continuation_padding ,
{ " Padding " , " http2.continuation.padding " ,
FT_BYTES , BASE_NONE , NULL , 0x0 ,
" Padding octets " , HFILL }
} ,
2013-08-30 11:14:09 +00:00
2014-04-25 14:29:10 +00:00
/* Altsvc */
{ & hf_http2_altsvc_maxage ,
{ " Max-Age " , " http2.altsvc.max-age " ,
FT_UINT32 , BASE_DEC , NULL , 0x0 ,
" An unsigned, 32-bit integer indicating the freshness lifetime of the alternative service association " , HFILL }
} ,
{ & hf_http2_altsvc_port ,
{ " Port " , " http2.altsvc.port " ,
FT_UINT16 , BASE_DEC , NULL , 0x0 ,
" An unsigned, 16-bit integer indicating the port that the alternative service is available upon " , HFILL }
} ,
{ & hf_http2_altsvc_res ,
{ " Reserved " , " http2.altsvc.reserved " ,
FT_UINT8 , BASE_DEC , NULL , 0x0 ,
" For future use. " , HFILL }
} ,
{ & hf_http2_altsvc_proto_len ,
{ " Proto-Len " , " http2.altsvc.proto_len " ,
FT_UINT8 , BASE_DEC , NULL , 0x0 ,
" An unsigned, 8-bit integer indicating the length, in octets, of the PROTOCOL-ID field " , HFILL }
} ,
{ & hf_http2_altsvc_protocol ,
{ " Protocol-ID " , " http2.altsvc.protocol " ,
FT_STRING , BASE_NONE , NULL , 0x0 ,
" A sequence of bytes containing the ALPN protocol identifier " , HFILL }
} ,
{ & hf_http2_altsvc_host_len ,
{ " Host-Len " , " http2.altsvc.host_len " ,
FT_UINT8 , BASE_DEC , NULL , 0x0 ,
" An unsigned, 8-bit integer indicating the length, in octets, of the Host field " , HFILL }
} ,
{ & hf_http2_altsvc_host ,
{ " Host " , " http2.altsvc.host " ,
FT_STRING , BASE_NONE , NULL , 0x0 ,
" ASCII string indicating the host that the alternative service is available upon " , HFILL }
} ,
{ & hf_http2_altsvc_origin ,
{ " Origin " , " http2.altsvc.origin " ,
FT_STRING , BASE_NONE , NULL , 0x0 ,
" A sequence of characters containing ASCII serialisation of an "
" origin that the alternate service is applicable to. " , HFILL }
} ,
2013-08-30 11:14:09 +00:00
2014-04-25 14:29:10 +00:00
} ;
2013-08-30 11:14:09 +00:00
static gint * ett [ ] = {
& ett_http2 ,
& ett_http2_header ,
2014-05-06 15:54:47 +00:00
& ett_http2_headers ,
2013-08-30 11:14:09 +00:00
& ett_http2_flags ,
& ett_http2_settings
} ;
proto_http2 = proto_register_protocol ( " HyperText Transfer Protocol 2 " , " HTTP2 " , " http2 " ) ;
proto_register_field_array ( proto_http2 , hf , array_length ( hf ) ) ;
proto_register_subtree_array ( ett , array_length ( ett ) ) ;
new_register_dissector ( " http2 " , dissect_http2 , proto_http2 ) ;
}
void
proto_reg_handoff_http2 ( void )
{
data_handle = find_dissector ( " data " ) ;
2013-11-29 08:02:09 +00:00
2013-12-15 19:07:40 +00:00
http2_handle = new_create_dissector_handle ( dissect_http2 , proto_http2 ) ;
dissector_add_handle ( " tcp.port " , http2_handle ) ;
2013-11-29 08:02:09 +00:00
heur_dissector_add ( " ssl " , dissect_http2_heur , proto_http2 ) ;
2013-12-04 13:55:53 +00:00
heur_dissector_add ( " http " , dissect_http2_heur , proto_http2 ) ;
2013-08-30 11:14:09 +00:00
}
/*
* Editor modelines - http : //www.wireshark.org/tools/modelines.html
*
* Local variables :
* c - basic - offset : 4
* tab - width : 8
* indent - tabs - mode : nil
* End :
*
* vi : set shiftwidth = 4 tabstop = 8 expandtab :
* : indentSize = 4 : tabSize = 8 : noTabs = true :
*/