blob: b2d233ad9688a63b5b89485b1c21a3299025308c [file] [log] [blame]
Amaury Denoyellec003f502022-06-14 16:35:41 +02001/*
2 * QPACK stream decoder. Decode a series of hex codes on stdin using one line
3 * per H3 HEADERS frame. Silently skip spaces, tabs, CR, '-' and ','.
4 *
5 * Compilation via Makefile
6 *
7 * Example run:
8 * echo 0000d1d7508b089d5c0b8170dc101a699fc15f5085ed6989397f | ./dev/qpack/decode
9 */
10
11#include <ctype.h>
12#include <inttypes.h>
13#include <stdio.h>
14#include <stdlib.h>
15
16#define MAX_RQ_SIZE 65536
17#define MAX_HDR_NUM 1000
18
19#define QPACK_STANDALONE
20
21#define USE_OPENSSL
22#define USE_QUIC
23
24#include <haproxy/buf-t.h>
25#include <haproxy/http-hdr-t.h>
26#include <haproxy/qpack-dec.h>
27#include <haproxy/qpack-tbl.h>
28
29char line[MAX_RQ_SIZE * 3 + 3];
30uint8_t bin[MAX_RQ_SIZE];
31
32char tmp_buf[MAX_RQ_SIZE];
33struct buffer buf = { .area = tmp_buf, .data = 0, .size = sizeof(tmp_buf) };
34
35#define DEBUG_QPACK
36#include "../src/hpack-huff.c"
37#include "../src/qpack-dec.c"
38#include "../src/qpack-tbl.c"
39
40/* define to compile with BUG_ON/ABORT_NOW statements */
41void ha_backtrace_to_stderr(void)
42{
43}
44
45/* taken from dev/hpack/decode.c */
46int hex2bin(const char *hex, uint8_t *bin, int size)
47{
48 int a, b, c;
49 uint8_t code;
50 int len = 0;
51
52 a = b = -1;
53
54 for (; *hex; hex++) {
55 c = *hex;
56 if (c == ' ' || c == '\t' || c == '\r' ||
57 c == '-' || c == ',')
58 continue;
59
60 if (c == '\n' || c == '#')
61 break;
62
63 if (c >= '0' && c <= '9')
64 c -= '0';
65 else if (c >= 'a' && c <= 'f')
66 c -= 'a' - 10;
67 else if (c >= 'A' && c <= 'F')
68 c -= 'A' - 10;
69 else
70 return -1;
71
72 if (a == -1)
73 a = c;
74 else
75 b = c;
76
77 if (b == -1)
78 continue;
79
80 code = (a << 4) | b;
81 a = b = -1;
82 if (len >= size)
83 return -2;
84
85 bin[len] = code;
86 len++;
87 }
88 if (a >= 0 || b >= 0)
89 return -3;
90 return len;
91}
92
93/* taken from src/tools.c */
94void debug_hexdump(FILE *out, const char *pfx, const char *buf,
95 unsigned int baseaddr, int len)
96{
97 unsigned int i;
98 int b, j;
99
100 for (i = 0; i < (len + (baseaddr & 15)); i += 16) {
101 b = i - (baseaddr & 15);
102 fprintf(out, "%s%08x: ", pfx ? pfx : "", i + (baseaddr & ~15));
103 for (j = 0; j < 8; j++) {
104 if (b + j >= 0 && b + j < len)
105 fprintf(out, "%02x ", (unsigned char)buf[b + j]);
106 else
107 fprintf(out, " ");
108 }
109
110 if (b + j >= 0 && b + j < len)
111 fputc('-', out);
112 else
113 fputc(' ', out);
114
115 for (j = 8; j < 16; j++) {
116 if (b + j >= 0 && b + j < len)
117 fprintf(out, " %02x", (unsigned char)buf[b + j]);
118 else
119 fprintf(out, " ");
120 }
121
122 fprintf(out, " ");
123 for (j = 0; j < 16; j++) {
124 if (b + j >= 0 && b + j < len) {
125 if (isprint((unsigned char)buf[b + j]))
126 fputc((unsigned char)buf[b + j], out);
127 else
128 fputc('.', out);
129 }
130 else
131 fputc(' ', out);
132 }
133 fputc('\n', out);
134 }
135}
136
137int main(int argc, char **argv)
138{
139 struct http_hdr hdrs[MAX_HDR_NUM];
140 int len, outlen, hdr_idx;
141
142 do {
143 if (!fgets(line, sizeof(line), stdin))
144 break;
145
146 if ((len = hex2bin(line, bin, MAX_RQ_SIZE)) < 0)
147 break;
148
149 outlen = qpack_decode_fs(bin, len, &buf, hdrs,
150 sizeof(hdrs) / sizeof(hdrs[0]));
151 if (outlen < 0) {
152 fprintf(stderr, "QPACK decoding failed: %d\n", outlen);
153 continue;
154 }
155
156 hdr_idx = 0;
157 fprintf(stderr, "<<< Found %d headers:\n", outlen);
158 while (1) {
159 if (isteq(hdrs[hdr_idx].n, ist("")))
160 break;
161
162 fprintf(stderr, "%.*s: %.*s\n",
163 (int)hdrs[hdr_idx].n.len, hdrs[hdr_idx].n.ptr,
164 (int)hdrs[hdr_idx].v.len, hdrs[hdr_idx].v.ptr);
165
166 ++hdr_idx;
167 }
168 } while (1);
169
170 return EXIT_SUCCESS;
171}