CONTRIB: hpack: add an hpack decoder
This decoder takes a series of hex codes on stdin using one line per HEADERS frame and shows the decoded headers.
This commit is contained in:
parent
c775f8372b
commit
4576424174
|
@ -1,5 +1,5 @@
|
|||
CFLAGS = -O2 -W -Wall -Wextra -g
|
||||
OBJS = gen-rht
|
||||
CFLAGS = -O2 -Wall -g -I../../include -I../../ebtree -fwrapv -fno-strict-aliasing
|
||||
OBJS = gen-rht decode
|
||||
|
||||
all: $(OBJS)
|
||||
|
||||
|
|
|
@ -0,0 +1,210 @@
|
|||
/*
|
||||
* 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 | contrib/hpack/decode
|
||||
*
|
||||
* The DHT size may optionally be changed in argv[1].
|
||||
*
|
||||
* Build like this :
|
||||
* gcc -I../../include -I../../ebtree -O0 -g -fno-strict-aliasing -fwrapv \
|
||||
* -o decode decode.c
|
||||
*/
|
||||
#include <ctype.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <common/chunk.h>
|
||||
#include <common/hpack-dec.h>
|
||||
#include <common/mini-clist.h>
|
||||
#include <proto/h1.h>
|
||||
|
||||
#define MAX_RQ_SIZE 65536
|
||||
#define MAX_HDR_NUM 1000
|
||||
|
||||
char hex[MAX_RQ_SIZE*3+3]; // enough for "[ XX]* <CR> <LF> \0"
|
||||
uint8_t buf[MAX_RQ_SIZE];
|
||||
|
||||
char trash_buf[MAX_RQ_SIZE];
|
||||
char tmp_buf[MAX_RQ_SIZE];
|
||||
|
||||
struct chunk trash = { .str = trash_buf, .len = 0, .size = sizeof(trash_buf) };
|
||||
struct chunk tmp = { .str = tmp_buf, .len = 0, .size = sizeof(tmp_buf) };
|
||||
|
||||
/* displays a <len> long memory block at <buf>, assuming first byte of <buf>
|
||||
* has address <baseaddr>. String <pfx> may be placed as a prefix in front of
|
||||
* each line. It may be NULL if unused. The output is emitted to file <out>.
|
||||
*/
|
||||
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 <hex> and stops at the first LF, '#' or \0. Converts from hex to
|
||||
* binary, ignoring spaces, tabs, CR, "-" and ','. The output is sent into
|
||||
* <bin> for no more than <size> 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];
|
||||
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--;
|
||||
}
|
||||
|
||||
dht = hpack_dht_alloc(dht_size);
|
||||
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.str, list[idx].n).ptr :
|
||||
h2_phdr_to_str(list[idx].n.len));
|
||||
|
||||
printf("%s [n=(%p,%d) v=(%p,%d)]\n", istpad(trash.str, 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;
|
||||
}
|
Loading…
Reference in New Issue