HPACK huffman decode: Process 8 bits at a time
This commit is contained in:
parent
c3a5fe7185
commit
240a4057f3
|
@ -43,6 +43,8 @@ EXTRA_DIST = nghttpx.conf.sample proxy.pac.sample android-config android-make \
|
|||
clang-format:
|
||||
CLANGFORMAT=`git config --get clangformat.binary`; \
|
||||
test -z $${CLANGFORMAT} && CLANGFORMAT="clang-format"; \
|
||||
$${CLANGFORMAT} -i lib/*.{c,h} lib/includes/nghttp2/*.h \
|
||||
$${CLANGFORMAT} -i \
|
||||
`ls lib/*.{c,h} | grep -v nghttp2_hd_huffman_data.c` \
|
||||
lib/includes/nghttp2/*.h \
|
||||
src/*.{c,cc,h} src/includes/nghttp2/*.h examples/*.{c,cc} \
|
||||
tests/*.{c,h}
|
||||
|
|
|
@ -197,22 +197,16 @@ ssize_t nghttp2_hd_huff_decode(nghttp2_hd_huff_decode_context *ctx,
|
|||
for (i = 0; i < srclen; ++i) {
|
||||
const nghttp2_huff_decode *t;
|
||||
|
||||
t = &huff_decode_table[ctx->state][src[i] >> 4];
|
||||
t = &huff_decode_table[ctx->state][src[i]];
|
||||
if (t->flags & NGHTTP2_HUFF_FAIL) {
|
||||
return NGHTTP2_ERR_HEADER_COMP;
|
||||
}
|
||||
if (t->flags & NGHTTP2_HUFF_SYM) {
|
||||
if (t->flags & NGHTTP2_HUFF_SYM1) {
|
||||
/* this is macro, and may return from this function on error */
|
||||
hd_huff_decode_sym_emit(bufs, t->sym, avail);
|
||||
}
|
||||
|
||||
t = &huff_decode_table[t->state][src[i] & 0xf];
|
||||
if (t->flags & NGHTTP2_HUFF_FAIL) {
|
||||
return NGHTTP2_ERR_HEADER_COMP;
|
||||
}
|
||||
if (t->flags & NGHTTP2_HUFF_SYM) {
|
||||
/* this is macro, and may return from this function on error */
|
||||
hd_huff_decode_sym_emit(bufs, t->sym, avail);
|
||||
hd_huff_decode_sym_emit(bufs, t->sym[0], avail);
|
||||
if (t->flags & NGHTTP2_HUFF_SYM2) {
|
||||
hd_huff_decode_sym_emit(bufs, t->sym[1], avail);
|
||||
}
|
||||
}
|
||||
|
||||
ctx->state = t->state;
|
||||
|
|
|
@ -35,10 +35,12 @@ typedef enum {
|
|||
/* FSA accepts this state as the end of huffman encoding
|
||||
sequence. */
|
||||
NGHTTP2_HUFF_ACCEPTED = 1,
|
||||
/* This state emits symbol */
|
||||
NGHTTP2_HUFF_SYM = (1 << 1),
|
||||
/* This state emits 1st symbol */
|
||||
NGHTTP2_HUFF_SYM1 = (1 << 1),
|
||||
/* This state emits 2nd symbol */
|
||||
NGHTTP2_HUFF_SYM2 = (1 << 2),
|
||||
/* If state machine reaches this state, decoding fails. */
|
||||
NGHTTP2_HUFF_FAIL = (1 << 2)
|
||||
NGHTTP2_HUFF_FAIL = (1 << 3)
|
||||
} nghttp2_huff_decode_flag;
|
||||
|
||||
typedef struct {
|
||||
|
@ -49,11 +51,15 @@ typedef struct {
|
|||
uint8_t state;
|
||||
/* bitwise OR of zero or more of the nghttp2_huff_decode_flag */
|
||||
uint8_t flags;
|
||||
/* symbol if NGHTTP2_HUFF_SYM flag set */
|
||||
uint8_t sym;
|
||||
/* symbols if NGHTTP2_HUFF_SYM1 and optionally NGHTTP2_HUFF_SYM2
|
||||
flag set. If NGHTTP2_HUFF_SYM1 is set, sym[0] has the 1st
|
||||
symbol. Additionally, NGHTTP2_HUFF_SYM2 is set, sym[1] has the
|
||||
2nd symbol. Since maximum huffman code is 5 bits, we may get at
|
||||
most 2 symbols in one transition. */
|
||||
uint8_t sym[2];
|
||||
} nghttp2_huff_decode;
|
||||
|
||||
typedef nghttp2_huff_decode huff_decode_table_type[16];
|
||||
typedef nghttp2_huff_decode huff_decode_table_type[256];
|
||||
|
||||
typedef struct {
|
||||
/* Current huffman decoding state. We stripped leaf nodes, so the
|
||||
|
@ -72,6 +78,6 @@ typedef struct {
|
|||
} nghttp2_huff_sym;
|
||||
|
||||
extern const nghttp2_huff_sym huff_sym_table[];
|
||||
extern const nghttp2_huff_decode huff_decode_table[][16];
|
||||
extern const nghttp2_huff_decode huff_decode_table[][256];
|
||||
|
||||
#endif /* NGHTTP2_HD_HUFFMAN_H */
|
||||
|
|
File diff suppressed because it is too large
Load Diff
54
mkhufftbl.py
54
mkhufftbl.py
|
@ -324,12 +324,12 @@ def _set_node_id(ctx, node, prefix):
|
|||
def huffman_tree_set_node_id(ctx):
|
||||
_set_node_id(ctx, ctx.root, [])
|
||||
|
||||
def _traverse(node, sym, start_node, root, left):
|
||||
def _traverse(node, syms, start_node, root, left):
|
||||
if left == 0:
|
||||
if sym == 256:
|
||||
sym = None
|
||||
if syms and syms[0] == 256:
|
||||
syms = []
|
||||
node = None
|
||||
start_node.trans.append((node, sym))
|
||||
start_node.trans.append((node, syms))
|
||||
return
|
||||
|
||||
if node.term is not None:
|
||||
|
@ -337,12 +337,12 @@ def _traverse(node, sym, start_node, root, left):
|
|||
|
||||
def go(node):
|
||||
if node.term is not None:
|
||||
assert sym is None
|
||||
nsym = node.term
|
||||
assert len(syms) <= 1
|
||||
nsyms = syms + [node.term]
|
||||
else:
|
||||
nsym = sym
|
||||
nsyms = syms
|
||||
|
||||
_traverse(node, nsym, start_node, root, left - 1)
|
||||
_traverse(node, nsyms, start_node, root, left - 1)
|
||||
|
||||
go(node.left)
|
||||
go(node.right)
|
||||
|
@ -350,7 +350,7 @@ def _traverse(node, sym, start_node, root, left):
|
|||
def _build_transition_table(ctx, node):
|
||||
if node is None:
|
||||
return
|
||||
_traverse(node, None, node, ctx.root, 4)
|
||||
_traverse(node, [], node, ctx.root, 8)
|
||||
_build_transition_table(ctx, node.left)
|
||||
_build_transition_table(ctx, node.right)
|
||||
|
||||
|
@ -358,21 +358,26 @@ def huffman_tree_build_transition_table(ctx):
|
|||
_build_transition_table(ctx, ctx.root)
|
||||
|
||||
NGHTTP2_HUFF_ACCEPTED = 1
|
||||
NGHTTP2_HUFF_SYM = 1 << 1
|
||||
NGHTTP2_HUFF_FAIL = 1 << 2
|
||||
NGHTTP2_HUFF_SYM1 = 1 << 1
|
||||
NGHTTP2_HUFF_SYM2 = 1 << 2
|
||||
NGHTTP2_HUFF_FAIL = 1 << 3
|
||||
|
||||
def _print_transition_table(node):
|
||||
if node.term is not None:
|
||||
return
|
||||
print '/* {} */'.format(node.id)
|
||||
print '{'
|
||||
for nd, sym in node.trans:
|
||||
print ' /* {} */'.format(node.id)
|
||||
print ' {'
|
||||
for nd, syms in node.trans:
|
||||
flags = 0
|
||||
if sym is None:
|
||||
out = 0
|
||||
if len(syms) == 0:
|
||||
out = [0, 0]
|
||||
else:
|
||||
out = sym
|
||||
flags |= NGHTTP2_HUFF_SYM
|
||||
out = syms
|
||||
flags |= NGHTTP2_HUFF_SYM1
|
||||
if len(out) == 2:
|
||||
flags |= NGHTTP2_HUFF_SYM2
|
||||
else:
|
||||
out = out + [0]
|
||||
if nd is None:
|
||||
id = 0
|
||||
flags |= NGHTTP2_HUFF_FAIL
|
||||
|
@ -384,8 +389,8 @@ def _print_transition_table(node):
|
|||
flags |= NGHTTP2_HUFF_ACCEPTED
|
||||
elif nd.accept:
|
||||
flags |= NGHTTP2_HUFF_ACCEPTED
|
||||
print ' {{{}, 0x{:02x}, {}}},'.format(id, flags, out)
|
||||
print '},'
|
||||
print ''' {{{}, 0x{:02x}, {{{}, {}}}}},'''.format(id, flags, out[0], out[1])
|
||||
print ' },'
|
||||
_print_transition_table(node.left)
|
||||
_print_transition_table(node.right)
|
||||
|
||||
|
@ -432,20 +437,21 @@ const nghttp2_huff_sym huff_sym_table[] = {'''
|
|||
print '''\
|
||||
enum {{
|
||||
NGHTTP2_HUFF_ACCEPTED = {},
|
||||
NGHTTP2_HUFF_SYM = {},
|
||||
NGHTTP2_HUFF_SYM1 = {},
|
||||
NGHTTP2_HUFF_SYM2 = {},
|
||||
NGHTTP2_HUFF_FAIL = {},
|
||||
}} nghttp2_huff_decode_flag;
|
||||
'''.format(NGHTTP2_HUFF_ACCEPTED, NGHTTP2_HUFF_SYM, NGHTTP2_HUFF_FAIL)
|
||||
'''.format(NGHTTP2_HUFF_ACCEPTED, NGHTTP2_HUFF_SYM1, NGHTTP2_HUFF_SYM2, NGHTTP2_HUFF_FAIL)
|
||||
|
||||
print '''\
|
||||
typedef struct {
|
||||
uint8_t state;
|
||||
uint8_t flags;
|
||||
uint8_t sym;
|
||||
uint8_t sym[2];
|
||||
} nghttp2_huff_decode;
|
||||
'''
|
||||
|
||||
print '''\
|
||||
const nghttp2_huff_decode huff_decode_table[][16] = {'''
|
||||
const nghttp2_huff_decode huff_decode_table[][256] = {'''
|
||||
huffman_tree_print_transition_table(ctx)
|
||||
print '};'
|
||||
|
|
Loading…
Reference in New Issue