HPACK huffman decode: Process 8 bits at a time

This commit is contained in:
Tatsuhiro Tsujikawa 2016-02-08 23:34:15 +09:00
parent c3a5fe7185
commit 240a4057f3
5 changed files with 65591 additions and 4141 deletions

View File

@ -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}

View File

@ -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;

View File

@ -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

View File

@ -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 '};'