diff --git a/lib/nghttp2_hd_huffman.c b/lib/nghttp2_hd_huffman.c index 6c4b2b64..c8946ab0 100644 --- a/lib/nghttp2_hd_huffman.c +++ b/lib/nghttp2_hd_huffman.c @@ -168,6 +168,23 @@ void nghttp2_hd_huff_decode_context_init(nghttp2_hd_huff_decode_context *ctx) { ctx->accept = 1; } +/* Use macro to make the code simpler..., but error case is tricky. + We spent most of the CPU in decoding, so we are doing this + thing. */ +#define hd_huff_decode_sym_emit(bufs, sym, avail) \ + do { \ + if ((avail)) { \ + nghttp2_bufs_fast_addb((bufs), (sym)); \ + --(avail); \ + } else { \ + rv = nghttp2_bufs_addb((bufs), (sym)); \ + if (rv != 0) { \ + return rv; \ + } \ + (avail) = nghttp2_bufs_cur_avail((bufs)); \ + } \ + } while (0) + ssize_t nghttp2_hd_huff_decode(nghttp2_hd_huff_decode_context *ctx, nghttp2_bufs *bufs, const uint8_t *src, size_t srclen, int final) { @@ -180,30 +197,28 @@ ssize_t nghttp2_hd_huff_decode(nghttp2_hd_huff_decode_context *ctx, /* We use the decoding algorithm described in http://graphics.ics.uci.edu/pub/Prefix.pdf */ for (i = 0; i < srclen; ++i) { - uint8_t in = src[i] >> 4; - for (j = 0; j < 2; ++j) { - const nghttp2_huff_decode *t; + const nghttp2_huff_decode *t; - t = &huff_decode_table[ctx->state][in]; - if (t->flags & NGHTTP2_HUFF_FAIL) { - return NGHTTP2_ERR_HEADER_COMP; - } - if (t->flags & NGHTTP2_HUFF_SYM) { - if (avail) { - nghttp2_bufs_fast_addb(bufs, t->sym); - --avail; - } else { - rv = nghttp2_bufs_addb(bufs, t->sym); - if (rv != 0) { - return rv; - } - avail = nghttp2_bufs_cur_avail(bufs); - } - } - ctx->state = t->state; - ctx->accept = (t->flags & NGHTTP2_HUFF_ACCEPTED) != 0; - in = src[i] & 0xf; + t = &huff_decode_table[ctx->state][src[i] >> 4]; + 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); + } + + 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->accept = (t->flags & NGHTTP2_HUFF_ACCEPTED) != 0; } if (final && !ctx->accept) { return NGHTTP2_ERR_HEADER_COMP;