/* * HPACK stream decoder. Takes a series of hex codes on stdin using one line * per HEADERS frame. Spaces, tabs, CR, '-' and ',' are silently skipped. * e.g. : * echo 82864188f439ce75c875fa5784 | dev/hpack/decode * * The DHT size may optionally be changed in argv[1]. * * Build like this : * gcc -I../../include -O0 -g -fno-strict-aliasing -fwrapv \ * -o decode decode.c */ #define HPACK_STANDALONE #include #include #include #include #include #include #include #define MAX_RQ_SIZE 65536 #define MAX_HDR_NUM 1000 char hex[MAX_RQ_SIZE*3+3]; // enough for "[ XX]* \0" uint8_t buf[MAX_RQ_SIZE]; char trash_buf[MAX_RQ_SIZE]; char tmp_buf[MAX_RQ_SIZE]; THREAD_LOCAL struct buffer trash = { .area = trash_buf, .data = 0, .size = sizeof(trash_buf) }; struct buffer tmp = { .area = tmp_buf, .data = 0, .size = sizeof(tmp_buf) }; /* displays a long memory block at , assuming first byte of * has address . String may be placed as a prefix in front of * each line. It may be NULL if unused. The output is emitted to file . */ 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); } } /* enable DEBUG_HPACK to show each individual hpack code */ #define DEBUG_HPACK #include "../src/hpack-huff.c" #include "../src/hpack-tbl.c" #include "../src/hpack-dec.c" /* display the message and exit with the code */ __attribute__((noreturn)) void die(int code, const char *format, ...) { va_list args; if (format) { va_start(args, format); vfprintf(stderr, format, args); va_end(args); } exit(code); } /* reads and stops at the first LF, '#' or \0. Converts from hex to * binary, ignoring spaces, tabs, CR, "-" and ','. The output is sent into * for no more than bytes. The number of bytes placed there is * returned, or a negative value in case of parsing error. */ 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; } int main(int argc, char **argv) { struct hpack_dht *dht; struct http_hdr list[MAX_HDR_NUM]; struct pool_head pool; int outlen; int dht_size = 4096; int len, idx; int line; /* first arg: dht size */ if (argc > 1) { dht_size = atoi(argv[1]); argv++; argc--; } pool.size = dht_size; pool_head_hpack_tbl = &pool; dht = hpack_dht_alloc(); if (!dht) { die(1, "cannot initialize dht\n"); return 1; } for (line = 1; fgets(hex, sizeof(hex), stdin); line++) { len = hex2bin(hex, buf, sizeof(buf)); if (len <= 0) continue; printf("###### line %d : frame len=%d #######\n", line, len); debug_hexdump(stdout, " ", (const char *)buf, 0, len); outlen = hpack_decode_frame(dht, buf, len, list, sizeof(list)/sizeof(list[0]), &tmp); if (outlen <= 0) { printf(" HPACK decoding failed: %d\n", outlen); continue; } printf("<<< Found %d headers :\n", outlen); for (idx = 0; idx < outlen - 1; idx++) { //printf(" \e[1;34m%s\e[0m: ", // list[idx].n.ptr ? istpad(trash.str, list[idx].n).ptr : h2_phdr_to_str(list[idx].n.len)); //printf("\e[1;35m%s\e[0m\n", istpad(trash.str, list[idx].v).ptr); printf(" %s: ", list[idx].n.ptr ? istpad(trash.area, list[idx].n).ptr : h2_phdr_to_str(list[idx].n.len)); printf("%s [n=(%p,%d) v=(%p,%d)]\n", istpad(trash.area, list[idx].v).ptr, list[idx].n.ptr, (int)list[idx].n.len, list[idx].v.ptr, (int)list[idx].v.len); } puts(">>>"); #ifdef DEBUG_HPACK printf("<<=== DHT dump [ptr=%p]:\n", dht); hpack_dht_dump(stdout, dht); puts("===>>"); #endif } return 0; }