HTTP3: Huffman decoding
Add Huffman decoding from libngttp2 library (MIT licensed), and use it in HTTP/3 to display the decoded QPACK bytes. (HTTP/2 and HTTP/3 use the same Huffman encoding.) These files are not part of the public libnghttp2 library but normally internal. Note that libnghttp3 does not supply a function to inflate headers like nghttp2_hd_inflate_h2. Related to #16761
This commit is contained in:
parent
c3c0fb7263
commit
79c6e9db9d
|
@ -107,6 +107,7 @@ set(LIBWIRESHARK_PUBLIC_HEADERS
|
|||
maxmind_db.h
|
||||
media_params.h
|
||||
next_tvb.h
|
||||
nghttp2_hd_huffman.h
|
||||
nlpid.h
|
||||
oids.h
|
||||
osi-utils.h
|
||||
|
@ -216,6 +217,7 @@ set(LIBWIRESHARK_NONGENERATED_FILES
|
|||
maxmind_db.c
|
||||
media_params.c
|
||||
next_tvb.c
|
||||
nghttp2_hd_huffman_data.c
|
||||
oids.c
|
||||
osi-utils.c
|
||||
packet.c
|
||||
|
@ -253,6 +255,7 @@ set(LIBWIRESHARK_NONGENERATED_FILES
|
|||
tvbuff_base64.c
|
||||
tvbuff_brotli.c
|
||||
tvbuff_composite.c
|
||||
tvbuff_hpackhuff.c
|
||||
tvbuff_real.c
|
||||
tvbuff_subset.c
|
||||
tvbuff_zlib.c
|
||||
|
|
|
@ -1606,6 +1606,7 @@ dissect_http3_qpack_encoder_stream(tvbuff_t *tvb, packet_info *pinfo _U_, proto_
|
|||
guint remaining;
|
||||
proto_item *opcode_ti;
|
||||
proto_tree *opcode_tree;
|
||||
tvbuff_t *decoded_tvb;
|
||||
guint decoded = 0;
|
||||
gint fin = 0, inc = 0;
|
||||
volatile bool can_continue = true;
|
||||
|
@ -1663,6 +1664,12 @@ dissect_http3_qpack_encoder_stream(tvbuff_t *tvb, packet_info *pinfo _U_, proto_
|
|||
if (value_huffman) {
|
||||
proto_tree_add_item(opcode_tree, hf_http3_qpack_encoder_opcode_insert_indexed_hval, tvb,
|
||||
val_bytes_offset, (guint32)val_bytes_len, ENC_NA);
|
||||
decoded_tvb = tvb_child_uncompress_hpack_huff(tvb, (int)val_bytes_offset, (int)val_bytes_len);
|
||||
if (decoded_tvb) {
|
||||
add_new_data_source(pinfo, decoded_tvb, "Decoded QPACK Value");
|
||||
proto_tree_add_item(opcode_tree, hf_http3_qpack_encoder_opcode_insert_indexed_val, decoded_tvb,
|
||||
0, tvb_captured_length(decoded_tvb), ENC_NA);
|
||||
}
|
||||
} else {
|
||||
proto_tree_add_item(opcode_tree, hf_http3_qpack_encoder_opcode_insert_indexed_val, tvb,
|
||||
val_bytes_offset, (guint32)val_bytes_len, ENC_NA);
|
||||
|
@ -1724,6 +1731,12 @@ dissect_http3_qpack_encoder_stream(tvbuff_t *tvb, packet_info *pinfo _U_, proto_
|
|||
if (name_huffman) {
|
||||
proto_tree_add_item(opcode_tree, hf_http3_qpack_encoder_opcode_insert_hname, tvb, name_bytes_offset,
|
||||
(guint32)name_bytes_len, ENC_NA);
|
||||
decoded_tvb = tvb_child_uncompress_hpack_huff(tvb, (int)name_bytes_offset, (int)name_bytes_len);
|
||||
if (decoded_tvb) {
|
||||
add_new_data_source(pinfo, decoded_tvb, "Decoded QPACK Name");
|
||||
proto_tree_add_item(opcode_tree, hf_http3_qpack_encoder_opcode_insert_name, decoded_tvb,
|
||||
0, tvb_captured_length(decoded_tvb), ENC_NA);
|
||||
}
|
||||
} else {
|
||||
proto_tree_add_item(opcode_tree, hf_http3_qpack_encoder_opcode_insert_name, tvb, name_bytes_offset,
|
||||
(guint32)name_bytes_len, ENC_NA);
|
||||
|
@ -1732,6 +1745,12 @@ dissect_http3_qpack_encoder_stream(tvbuff_t *tvb, packet_info *pinfo _U_, proto_
|
|||
if (value_huffman) {
|
||||
proto_tree_add_item(opcode_tree, hf_http3_qpack_encoder_opcode_insert_hval, tvb, val_bytes_offset,
|
||||
(guint32)val_bytes_len, ENC_NA);
|
||||
decoded_tvb = tvb_child_uncompress_hpack_huff(tvb, (int)val_bytes_offset, (int)val_bytes_len);
|
||||
if (decoded_tvb) {
|
||||
add_new_data_source(pinfo, decoded_tvb, "Decoded QPACK Value");
|
||||
proto_tree_add_item(opcode_tree, hf_http3_qpack_encoder_opcode_insert_val, decoded_tvb,
|
||||
0, tvb_captured_length(decoded_tvb), ENC_NA);
|
||||
}
|
||||
} else {
|
||||
proto_tree_add_item(opcode_tree, hf_http3_qpack_encoder_opcode_insert_val, tvb, val_bytes_offset,
|
||||
(guint32)val_bytes_len, ENC_NA);
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
/* @file
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2013 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
#ifndef NGHTTP2_HD_HUFFMAN_H
|
||||
#define NGHTTP2_HD_HUFFMAN_H
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef enum {
|
||||
/* FSA accepts this state as the end of huffman encoding
|
||||
sequence. */
|
||||
NGHTTP2_HUFF_ACCEPTED = 1 << 14,
|
||||
/* This state emits symbol */
|
||||
NGHTTP2_HUFF_SYM = 1 << 15,
|
||||
} nghttp2_huff_decode_flag;
|
||||
|
||||
typedef struct {
|
||||
/* fstate is the current huffman decoding state, which is actually
|
||||
the node ID of internal huffman tree with
|
||||
nghttp2_huff_decode_flag OR-ed. We have 257 leaf nodes, but they
|
||||
are identical to root node other than emitting a symbol, so we
|
||||
have 256 internal nodes [1..255], inclusive. The node ID 256 is
|
||||
a special node and it is a terminal state that means decoding
|
||||
failed. */
|
||||
uint16_t fstate;
|
||||
/* symbol if NGHTTP2_HUFF_SYM flag set */
|
||||
uint8_t sym;
|
||||
} nghttp2_huff_decode;
|
||||
|
||||
typedef nghttp2_huff_decode huff_decode_table_type[16];
|
||||
|
||||
typedef struct {
|
||||
/* fstate is the current huffman decoding state. */
|
||||
uint16_t fstate;
|
||||
} nghttp2_hd_huff_decode_context;
|
||||
|
||||
typedef struct {
|
||||
/* The number of bits in this code */
|
||||
uint32_t nbits;
|
||||
/* Huffman code aligned to LSB */
|
||||
uint32_t code;
|
||||
} nghttp2_huff_sym;
|
||||
|
||||
extern const nghttp2_huff_sym huff_sym_table[];
|
||||
extern const nghttp2_huff_decode huff_decode_table[][16];
|
||||
|
||||
#endif /* NGHTTP2_HD_HUFFMAN_H */
|
File diff suppressed because it is too large
Load Diff
|
@ -1226,6 +1226,15 @@ extern tvbuff_t* base64_to_tvb(tvbuff_t *parent, const char *base64);
|
|||
extern tvbuff_t* base64_tvb_to_new_tvb(tvbuff_t* parent, int offset, int length);
|
||||
|
||||
extern tvbuff_t* base64uri_tvb_to_new_tvb(tvbuff_t* parent, int offset, int length);
|
||||
|
||||
/* From tvbuff_hpackhuff.c */
|
||||
|
||||
WS_DLL_PUBLIC wmem_strbuf_t* tvb_get_hpack_huffman_strbuf(wmem_allocator_t *scope,
|
||||
tvbuff_t *tvb, const int offset, const int len);
|
||||
|
||||
WS_DLL_PUBLIC tvbuff_t* tvb_child_uncompress_hpack_huff(tvbuff_t *parent,
|
||||
int offset, int length);
|
||||
|
||||
/**
|
||||
* Extract a variable length integer from a tvbuff.
|
||||
* Each byte in a varint, except the last byte, has the most significant bit (msb)
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
/* @file
|
||||
* Decompression of the Huffman encoding used for HTTP fields in HPACK (HTTP/2)
|
||||
* and QPACK (HTTP/3)
|
||||
*
|
||||
* Wireshark - Network traffic analyzer
|
||||
* By Gerald Combs <gerald@wireshark.org>
|
||||
* Copyright 1998 Gerald Combs
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <epan/tvbuff.h>
|
||||
#include <epan/nghttp2_hd_huffman.h>
|
||||
|
||||
static wmem_strbuf_t *
|
||||
get_hpack_huffman_strbuf(wmem_allocator_t *scope, const uint8_t *ptr, size_t len)
|
||||
{
|
||||
wmem_strbuf_t *strbuf;
|
||||
strbuf = wmem_strbuf_new_sized(scope, len + 1);
|
||||
|
||||
nghttp2_huff_decode node = {0, 0};
|
||||
const nghttp2_huff_decode *nodep = &node;
|
||||
|
||||
while (len > 0) {
|
||||
uint8_t ch = *ptr++;
|
||||
|
||||
nodep = &huff_decode_table[nodep->fstate & 0x1ff][ch >> 4];
|
||||
if (nodep->fstate & NGHTTP2_HUFF_SYM) {
|
||||
wmem_strbuf_append_c(strbuf, nodep->sym);
|
||||
}
|
||||
|
||||
nodep = &huff_decode_table[nodep->fstate & 0x1ff][ch & 0xf];
|
||||
if (nodep->fstate & NGHTTP2_HUFF_SYM) {
|
||||
wmem_strbuf_append_c(strbuf, nodep->sym);
|
||||
}
|
||||
|
||||
len--;
|
||||
}
|
||||
|
||||
if (!(nodep->fstate & NGHTTP2_HUFF_ACCEPTED)) {
|
||||
wmem_strbuf_destroy(strbuf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return strbuf;
|
||||
}
|
||||
|
||||
wmem_strbuf_t *
|
||||
tvb_get_hpack_huffman_strbuf(wmem_allocator_t *scope, tvbuff_t *tvb, const int offset, const int len)
|
||||
{
|
||||
return get_hpack_huffman_strbuf(scope, tvb_get_ptr(tvb, offset, len), len);
|
||||
}
|
||||
|
||||
tvbuff_t*
|
||||
tvb_child_uncompress_hpack_huff(tvbuff_t* parent, int offset, int length)
|
||||
{
|
||||
tvbuff_t* tvb = NULL;
|
||||
wmem_strbuf_t *strbuf;
|
||||
char* data;
|
||||
gsize len;
|
||||
|
||||
strbuf = tvb_get_hpack_huffman_strbuf(NULL, parent, offset, length);
|
||||
|
||||
if (strbuf) {
|
||||
len = wmem_strbuf_get_len(strbuf);
|
||||
data = wmem_strbuf_finalize(strbuf);
|
||||
|
||||
tvb = tvb_new_child_real_data(parent, (const guint8*)data, (guint)len, (gint)len);
|
||||
|
||||
tvb_set_free_cb(tvb, g_free);
|
||||
}
|
||||
|
||||
return tvb;
|
||||
}
|
Loading…
Reference in New Issue