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:
|
clang-format:
|
||||||
CLANGFORMAT=`git config --get clangformat.binary`; \
|
CLANGFORMAT=`git config --get clangformat.binary`; \
|
||||||
test -z $${CLANGFORMAT} && CLANGFORMAT="clang-format"; \
|
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} \
|
src/*.{c,cc,h} src/includes/nghttp2/*.h examples/*.{c,cc} \
|
||||||
tests/*.{c,h}
|
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) {
|
for (i = 0; i < srclen; ++i) {
|
||||||
const nghttp2_huff_decode *t;
|
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) {
|
if (t->flags & NGHTTP2_HUFF_FAIL) {
|
||||||
return NGHTTP2_ERR_HEADER_COMP;
|
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 */
|
/* 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx->state = t->state;
|
ctx->state = t->state;
|
||||||
|
|
|
@ -35,10 +35,12 @@ typedef enum {
|
||||||
/* FSA accepts this state as the end of huffman encoding
|
/* FSA accepts this state as the end of huffman encoding
|
||||||
sequence. */
|
sequence. */
|
||||||
NGHTTP2_HUFF_ACCEPTED = 1,
|
NGHTTP2_HUFF_ACCEPTED = 1,
|
||||||
/* This state emits symbol */
|
/* This state emits 1st symbol */
|
||||||
NGHTTP2_HUFF_SYM = (1 << 1),
|
NGHTTP2_HUFF_SYM1 = (1 << 1),
|
||||||
|
/* This state emits 2nd symbol */
|
||||||
|
NGHTTP2_HUFF_SYM2 = (1 << 2),
|
||||||
/* If state machine reaches this state, decoding fails. */
|
/* If state machine reaches this state, decoding fails. */
|
||||||
NGHTTP2_HUFF_FAIL = (1 << 2)
|
NGHTTP2_HUFF_FAIL = (1 << 3)
|
||||||
} nghttp2_huff_decode_flag;
|
} nghttp2_huff_decode_flag;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -49,11 +51,15 @@ typedef struct {
|
||||||
uint8_t state;
|
uint8_t state;
|
||||||
/* bitwise OR of zero or more of the nghttp2_huff_decode_flag */
|
/* bitwise OR of zero or more of the nghttp2_huff_decode_flag */
|
||||||
uint8_t flags;
|
uint8_t flags;
|
||||||
/* symbol if NGHTTP2_HUFF_SYM flag set */
|
/* symbols if NGHTTP2_HUFF_SYM1 and optionally NGHTTP2_HUFF_SYM2
|
||||||
uint8_t sym;
|
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;
|
} nghttp2_huff_decode;
|
||||||
|
|
||||||
typedef nghttp2_huff_decode huff_decode_table_type[16];
|
typedef nghttp2_huff_decode huff_decode_table_type[256];
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
/* Current huffman decoding state. We stripped leaf nodes, so the
|
/* Current huffman decoding state. We stripped leaf nodes, so the
|
||||||
|
@ -72,6 +78,6 @@ typedef struct {
|
||||||
} nghttp2_huff_sym;
|
} nghttp2_huff_sym;
|
||||||
|
|
||||||
extern const nghttp2_huff_sym huff_sym_table[];
|
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 */
|
#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):
|
def huffman_tree_set_node_id(ctx):
|
||||||
_set_node_id(ctx, ctx.root, [])
|
_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 left == 0:
|
||||||
if sym == 256:
|
if syms and syms[0] == 256:
|
||||||
sym = None
|
syms = []
|
||||||
node = None
|
node = None
|
||||||
start_node.trans.append((node, sym))
|
start_node.trans.append((node, syms))
|
||||||
return
|
return
|
||||||
|
|
||||||
if node.term is not None:
|
if node.term is not None:
|
||||||
|
@ -337,12 +337,12 @@ def _traverse(node, sym, start_node, root, left):
|
||||||
|
|
||||||
def go(node):
|
def go(node):
|
||||||
if node.term is not None:
|
if node.term is not None:
|
||||||
assert sym is None
|
assert len(syms) <= 1
|
||||||
nsym = node.term
|
nsyms = syms + [node.term]
|
||||||
else:
|
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.left)
|
||||||
go(node.right)
|
go(node.right)
|
||||||
|
@ -350,7 +350,7 @@ def _traverse(node, sym, start_node, root, left):
|
||||||
def _build_transition_table(ctx, node):
|
def _build_transition_table(ctx, node):
|
||||||
if node is None:
|
if node is None:
|
||||||
return
|
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.left)
|
||||||
_build_transition_table(ctx, node.right)
|
_build_transition_table(ctx, node.right)
|
||||||
|
|
||||||
|
@ -358,21 +358,26 @@ def huffman_tree_build_transition_table(ctx):
|
||||||
_build_transition_table(ctx, ctx.root)
|
_build_transition_table(ctx, ctx.root)
|
||||||
|
|
||||||
NGHTTP2_HUFF_ACCEPTED = 1
|
NGHTTP2_HUFF_ACCEPTED = 1
|
||||||
NGHTTP2_HUFF_SYM = 1 << 1
|
NGHTTP2_HUFF_SYM1 = 1 << 1
|
||||||
NGHTTP2_HUFF_FAIL = 1 << 2
|
NGHTTP2_HUFF_SYM2 = 1 << 2
|
||||||
|
NGHTTP2_HUFF_FAIL = 1 << 3
|
||||||
|
|
||||||
def _print_transition_table(node):
|
def _print_transition_table(node):
|
||||||
if node.term is not None:
|
if node.term is not None:
|
||||||
return
|
return
|
||||||
print '/* {} */'.format(node.id)
|
print ' /* {} */'.format(node.id)
|
||||||
print '{'
|
print ' {'
|
||||||
for nd, sym in node.trans:
|
for nd, syms in node.trans:
|
||||||
flags = 0
|
flags = 0
|
||||||
if sym is None:
|
if len(syms) == 0:
|
||||||
out = 0
|
out = [0, 0]
|
||||||
else:
|
else:
|
||||||
out = sym
|
out = syms
|
||||||
flags |= NGHTTP2_HUFF_SYM
|
flags |= NGHTTP2_HUFF_SYM1
|
||||||
|
if len(out) == 2:
|
||||||
|
flags |= NGHTTP2_HUFF_SYM2
|
||||||
|
else:
|
||||||
|
out = out + [0]
|
||||||
if nd is None:
|
if nd is None:
|
||||||
id = 0
|
id = 0
|
||||||
flags |= NGHTTP2_HUFF_FAIL
|
flags |= NGHTTP2_HUFF_FAIL
|
||||||
|
@ -384,8 +389,8 @@ def _print_transition_table(node):
|
||||||
flags |= NGHTTP2_HUFF_ACCEPTED
|
flags |= NGHTTP2_HUFF_ACCEPTED
|
||||||
elif nd.accept:
|
elif nd.accept:
|
||||||
flags |= NGHTTP2_HUFF_ACCEPTED
|
flags |= NGHTTP2_HUFF_ACCEPTED
|
||||||
print ' {{{}, 0x{:02x}, {}}},'.format(id, flags, out)
|
print ''' {{{}, 0x{:02x}, {{{}, {}}}}},'''.format(id, flags, out[0], out[1])
|
||||||
print '},'
|
print ' },'
|
||||||
_print_transition_table(node.left)
|
_print_transition_table(node.left)
|
||||||
_print_transition_table(node.right)
|
_print_transition_table(node.right)
|
||||||
|
|
||||||
|
@ -432,20 +437,21 @@ const nghttp2_huff_sym huff_sym_table[] = {'''
|
||||||
print '''\
|
print '''\
|
||||||
enum {{
|
enum {{
|
||||||
NGHTTP2_HUFF_ACCEPTED = {},
|
NGHTTP2_HUFF_ACCEPTED = {},
|
||||||
NGHTTP2_HUFF_SYM = {},
|
NGHTTP2_HUFF_SYM1 = {},
|
||||||
|
NGHTTP2_HUFF_SYM2 = {},
|
||||||
NGHTTP2_HUFF_FAIL = {},
|
NGHTTP2_HUFF_FAIL = {},
|
||||||
}} nghttp2_huff_decode_flag;
|
}} 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 '''\
|
print '''\
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t state;
|
uint8_t state;
|
||||||
uint8_t flags;
|
uint8_t flags;
|
||||||
uint8_t sym;
|
uint8_t sym[2];
|
||||||
} nghttp2_huff_decode;
|
} nghttp2_huff_decode;
|
||||||
'''
|
'''
|
||||||
|
|
||||||
print '''\
|
print '''\
|
||||||
const nghttp2_huff_decode huff_decode_table[][16] = {'''
|
const nghttp2_huff_decode huff_decode_table[][256] = {'''
|
||||||
huffman_tree_print_transition_table(ctx)
|
huffman_tree_print_transition_table(ctx)
|
||||||
print '};'
|
print '};'
|
||||||
|
|
Loading…
Reference in New Issue