22#define HPACK_BYTES PC_HPACK_TABLE_BYTES
23#define HPACK_ENTS PC_HPACK_MAX_ENTRIES
26const char *
const STATIC[62][2] = {
32 {
":path",
"/index.html"},
42 {
"accept-charset",
""},
43 {
"accept-encoding",
"gzip, deflate"},
44 {
"accept-language",
""},
45 {
"accept-ranges",
""},
47 {
"access-control-allow-origin",
""},
50 {
"authorization",
""},
51 {
"cache-control",
""},
52 {
"content-disposition",
""},
53 {
"content-encoding",
""},
54 {
"content-language",
""},
55 {
"content-length",
""},
56 {
"content-location",
""},
57 {
"content-range",
""},
67 {
"if-modified-since",
""},
68 {
"if-none-match",
""},
70 {
"if-unmodified-since",
""},
71 {
"last-modified",
""},
75 {
"proxy-authenticate",
""},
76 {
"proxy-authorization",
""},
83 {
"strict-transport-security",
""},
84 {
"transfer-encoding",
""},
88 {
"www-authenticate",
""},
93void ring_write(HpackDynTable *t, uint16_t pos,
const char *src,
size_t n)
95 for (
size_t i = 0; i < n; i++)
97 t->ring[(pos + i) % HPACK_BYTES] = src[i];
100void ring_read(
const HpackDynTable *t, uint16_t pos,
char *dst,
size_t n)
102 for (
size_t i = 0; i < n; i++)
104 dst[i] = t->ring[(pos + i) % HPACK_BYTES];
111const HpackEntry *dyn_entry(
const HpackDynTable *t, uint32_t k)
113 if (k < 1 || k > t->ecount)
117 uint16_t di = (uint16_t)((t->ehead + HPACK_ENTS - k) % HPACK_ENTS);
122void dyn_evict_oldest(HpackDynTable *t)
128 uint16_t oi = (uint16_t)((t->ehead + HPACK_ENTS - t->ecount) % HPACK_ENTS);
129 const HpackEntry *e = &t->ent[oi];
130 uint16_t bytes = (uint16_t)(e->name_len + e->val_len);
131 t->rtail = (uint16_t)((t->rtail + bytes) % HPACK_BYTES);
132 t->rused = (uint16_t)(t->rused - bytes);
133 t->used -= (uint32_t)e->name_len + e->val_len + 32;
137void dyn_set_max(HpackDynTable *t, uint32_t new_max)
139 if (new_max > HPACK_BYTES)
141 new_max = HPACK_BYTES;
143 t->max_size = new_max;
146 while (t->used > t->max_size && t->ecount > 0)
152void dyn_insert(HpackDynTable *t,
const char *name,
size_t nlen,
const char *val,
size_t vlen)
154 uint32_t entry_size = (uint32_t)nlen + (uint32_t)vlen + 32;
155 if (entry_size > t->max_size)
168 while ((t->used + entry_size > t->max_size || t->ecount >= HPACK_ENTS) && t->ecount > 0)
172 uint16_t rpos = (uint16_t)((t->rtail + t->rused) % HPACK_BYTES);
173 HpackEntry *e = &t->ent[t->ehead];
174 e->name_len = (uint16_t)nlen;
175 e->val_len = (uint16_t)vlen;
177 ring_write(t, rpos, name, nlen);
178 ring_write(t, (uint16_t)((rpos + nlen) % HPACK_BYTES), val, vlen);
179 t->rused = (uint16_t)(t->rused + nlen + vlen);
180 t->ehead = (uint16_t)((t->ehead + 1) % HPACK_ENTS);
182 t->used += entry_size;
188bool resolve_name(
const HpackDynTable *t, uint32_t idx,
char *out,
size_t cap,
size_t *out_len)
190 if (idx >= 1 && idx <= 61)
192 size_t nl = strnlen(STATIC[idx][0], cap + 1);
197 memcpy(out, STATIC[idx][0], nl);
201 const HpackEntry *e = dyn_entry(t, idx - 61);
202 if (!e || e->name_len > cap)
206 ring_read(t, e->ring_pos, out, e->name_len);
207 *out_len = e->name_len;
214bool emit_indexed(HpackDynTable *t, uint32_t idx,
char *scratch,
size_t cap, HpackEmitFn emit,
void *ctx)
218 if (idx >= 1 && idx <= 61)
220 nl = strnlen(STATIC[idx][0], cap + 1);
221 vl = strnlen(STATIC[idx][1], cap + 1);
226 memcpy(scratch, STATIC[idx][0], nl);
227 memcpy(scratch + nl, STATIC[idx][1], vl);
231 const HpackEntry *e = dyn_entry(t, idx - 61);
242 ring_read(t, e->ring_pos, scratch, nl);
243 ring_read(t, (uint16_t)((e->ring_pos + nl) % HPACK_BYTES), scratch + nl, vl);
245 return emit(ctx, scratch, nl, scratch + nl, vl);
249bool decode_literal(HpackDynTable *t,
const uint8_t *block,
size_t len,
size_t *pos, uint8_t prefix_bits,
bool do_index,
250 char *scratch,
size_t cap, HpackEmitFn emit,
void *ctx)
253 uint32_t name_idx = 0;
254 if (!pc_hpack_decode_int(block + *pos, len - *pos, prefix_bits, &c, &name_idx))
262 if (!pc_hpack_decode_str(block, len, pos, scratch, cap, &name_len))
267 else if (!resolve_name(t, name_idx, scratch, cap, &name_len))
272 if (!pc_hpack_decode_str(block, len, pos, scratch + name_len, cap - name_len, &val_len))
278 dyn_insert(t, scratch, name_len, scratch + name_len, val_len);
280 return emit(ctx, scratch, name_len, scratch + name_len, val_len);
287void pc_hpack_dyn_init(HpackDynTable *t, uint32_t max_bytes)
289 memset(t, 0,
sizeof(*t));
290 t->max_size = max_bytes ? max_bytes : (uint32_t)HPACK_BYTES;
291 if (t->max_size > HPACK_BYTES)
293 t->max_size = HPACK_BYTES;
297bool pc_hpack_decode(HpackDynTable *t,
const uint8_t *block,
size_t len,
char *scratch,
size_t scratch_cap,
298 HpackEmitFn emit,
void *ctx)
303 uint8_t b = block[pos];
308 if (!pc_hpack_decode_int(block + pos, len - pos, 7, &c, &idx) || idx == 0)
313 if (!emit_indexed(t, idx, scratch, scratch_cap, emit, ctx))
320 if (!decode_literal(t, block, len, &pos, 6,
true, scratch, scratch_cap, emit, ctx))
325 else if ((b & 0xE0) == 0x20)
329 if (!pc_hpack_decode_int(block + pos, len - pos, 5, &c, &nm))
338 if (!decode_literal(t, block, len, &pos, 4,
false, scratch, scratch_cap, emit, ctx))
347size_t pc_hpack_encode_header(uint8_t *out,
size_t cap,
const char *name,
size_t name_len,
const char *value,
352 for (
int i = 1; i <= 61; i++)
354 if (strnlen(STATIC[i][0], name_len + 1) == name_len && memcmp(STATIC[i][0], name, name_len) == 0)
360 if (strnlen(STATIC[i][1], value_len + 1) == value_len && memcmp(STATIC[i][1], value, value_len) == 0)
369 return pc_hpack_encode_int(out, cap, 7, 0x80, (uint32_t)full_idx);
372 size_t o = pc_hpack_encode_int(out, cap, 4, 0x00, (uint32_t)name_idx);
379 size_t ns = pc_hpack_encode_str(out + o, cap - o, name, name_len);
386 size_t vs = pc_hpack_encode_str(out + o, cap - o, value, value_len);
HPACK header compression for HTTP/2 (RFC 7541).