Commit 240a4057 authored by Tatsuhiro Tsujikawa's avatar Tatsuhiro Tsujikawa

HPACK huffman decode: Process 8 bits at a time

parent c3a5fe71
...@@ -43,6 +43,8 @@ EXTRA_DIST = nghttpx.conf.sample proxy.pac.sample android-config android-make \ ...@@ -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, ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 */
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -324,12 +324,12 @@ def _set_node_id(ctx, node, prefix): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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[] = {''' ...@@ -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 '};'
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment