From c003f501226758dfdd83a12e662ef23c21d83cc3 Mon Sep 17 00:00:00 2001 From: Amaury Denoyelle Date: Tue, 14 Jun 2022 16:35:41 +0200 Subject: [PATCH] MINOR: qpack: implement standalone decoder tool Implement a standalone binary to be able to easily a hex-string QPACK stream. The binary must be compiled via the Makefile. Hex-strings are specified on stdin. --- .gitignore | 1 + Makefile | 4 ++ dev/qpack/decode.c | 171 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 176 insertions(+) create mode 100644 dev/qpack/decode.c diff --git a/.gitignore b/.gitignore index d588b0751e202..a2776883ee04e 100644 --- a/.gitignore +++ b/.gitignore @@ -49,6 +49,7 @@ dev/poll/poll dev/tcploop/tcploop dev/hpack/decode dev/hpack/gen-rht +dev/qpack/decode /src/dlmalloc.c /tests/test_hashes doc/lua-api/_build diff --git a/Makefile b/Makefile index c852d9d6fbe78..b248acccfa45d 100644 --- a/Makefile +++ b/Makefile @@ -1018,6 +1018,9 @@ dev/hpack/%: dev/hpack/%.o dev/poll/poll: $(Q)$(MAKE) -C dev/poll poll CC='$(cmd_CC)' OPTIMIZE='$(COPTS)' +dev/qpack/decode: dev/qpack/decode.o + $(cmd_LD) $(LDFLAGS) -o $@ $^ $(LDOPTS) + dev/tcploop/tcploop: $(Q)$(MAKE) -C dev/tcploop tcploop CC='$(cmd_CC)' OPTIMIZE='$(COPTS)' @@ -1088,6 +1091,7 @@ clean: $(Q)rm -f dev/*/*.[oas] $(Q)rm -f dev/flags/flags dev/poll/poll dev/tcploop/tcploop $(Q)rm -f dev/hpack/decode dev/hpack/gen-enc dev/hpack/gen-rht + $(Q)rm -f dev/qpack/decode tags: $(Q)find src include \( -name '*.c' -o -name '*.h' \) -print0 | \ diff --git a/dev/qpack/decode.c b/dev/qpack/decode.c new file mode 100644 index 0000000000000..b2d233ad9688a --- /dev/null +++ b/dev/qpack/decode.c @@ -0,0 +1,171 @@ +/* + * QPACK stream decoder. Decode a series of hex codes on stdin using one line + * per H3 HEADERS frame. Silently skip spaces, tabs, CR, '-' and ','. + * + * Compilation via Makefile + * + * Example run: + * echo 0000d1d7508b089d5c0b8170dc101a699fc15f5085ed6989397f | ./dev/qpack/decode + */ + +#include +#include +#include +#include + +#define MAX_RQ_SIZE 65536 +#define MAX_HDR_NUM 1000 + +#define QPACK_STANDALONE + +#define USE_OPENSSL +#define USE_QUIC + +#include +#include +#include +#include + +char line[MAX_RQ_SIZE * 3 + 3]; +uint8_t bin[MAX_RQ_SIZE]; + +char tmp_buf[MAX_RQ_SIZE]; +struct buffer buf = { .area = tmp_buf, .data = 0, .size = sizeof(tmp_buf) }; + +#define DEBUG_QPACK +#include "../src/hpack-huff.c" +#include "../src/qpack-dec.c" +#include "../src/qpack-tbl.c" + +/* define to compile with BUG_ON/ABORT_NOW statements */ +void ha_backtrace_to_stderr(void) +{ +} + +/* taken from dev/hpack/decode.c */ +int hex2bin(const char *hex, uint8_t *bin, int size) +{ + int a, b, c; + uint8_t code; + int len = 0; + + a = b = -1; + + for (; *hex; hex++) { + c = *hex; + if (c == ' ' || c == '\t' || c == '\r' || + c == '-' || c == ',') + continue; + + if (c == '\n' || c == '#') + break; + + if (c >= '0' && c <= '9') + c -= '0'; + else if (c >= 'a' && c <= 'f') + c -= 'a' - 10; + else if (c >= 'A' && c <= 'F') + c -= 'A' - 10; + else + return -1; + + if (a == -1) + a = c; + else + b = c; + + if (b == -1) + continue; + + code = (a << 4) | b; + a = b = -1; + if (len >= size) + return -2; + + bin[len] = code; + len++; + } + if (a >= 0 || b >= 0) + return -3; + return len; +} + +/* taken from src/tools.c */ +void debug_hexdump(FILE *out, const char *pfx, const char *buf, + unsigned int baseaddr, int len) +{ + unsigned int i; + int b, j; + + for (i = 0; i < (len + (baseaddr & 15)); i += 16) { + b = i - (baseaddr & 15); + fprintf(out, "%s%08x: ", pfx ? pfx : "", i + (baseaddr & ~15)); + for (j = 0; j < 8; j++) { + if (b + j >= 0 && b + j < len) + fprintf(out, "%02x ", (unsigned char)buf[b + j]); + else + fprintf(out, " "); + } + + if (b + j >= 0 && b + j < len) + fputc('-', out); + else + fputc(' ', out); + + for (j = 8; j < 16; j++) { + if (b + j >= 0 && b + j < len) + fprintf(out, " %02x", (unsigned char)buf[b + j]); + else + fprintf(out, " "); + } + + fprintf(out, " "); + for (j = 0; j < 16; j++) { + if (b + j >= 0 && b + j < len) { + if (isprint((unsigned char)buf[b + j])) + fputc((unsigned char)buf[b + j], out); + else + fputc('.', out); + } + else + fputc(' ', out); + } + fputc('\n', out); + } +} + +int main(int argc, char **argv) +{ + struct http_hdr hdrs[MAX_HDR_NUM]; + int len, outlen, hdr_idx; + + do { + if (!fgets(line, sizeof(line), stdin)) + break; + + if ((len = hex2bin(line, bin, MAX_RQ_SIZE)) < 0) + break; + + outlen = qpack_decode_fs(bin, len, &buf, hdrs, + sizeof(hdrs) / sizeof(hdrs[0])); + if (outlen < 0) { + fprintf(stderr, "QPACK decoding failed: %d\n", outlen); + continue; + } + + hdr_idx = 0; + fprintf(stderr, "<<< Found %d headers:\n", outlen); + while (1) { + if (isteq(hdrs[hdr_idx].n, ist(""))) + break; + + fprintf(stderr, "%.*s: %.*s\n", + (int)hdrs[hdr_idx].n.len, hdrs[hdr_idx].n.ptr, + (int)hdrs[hdr_idx].v.len, hdrs[hdr_idx].v.ptr); + + ++hdr_idx; + } + } while (1); + + return EXIT_SUCCESS; +}