Nilorea Library
C utilities for networking, threading, graphics
Loading...
Searching...
No Matches
n_http2.c
Go to the documentation of this file.
1/*
2 * Nilorea Library
3 * Copyright (C) 2005-2026 Castagnier Mickael
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
14 * implied. See the License for the specific language governing
15 * permissions and limitations under the License.
16 *
17 * SPDX-License-Identifier: Apache-2.0
18 */
19
27#include "nilorea/n_http2.h"
28
29#include <stdlib.h>
30#include <string.h>
31
32int n_http2_frame_parse(const unsigned char* buf, size_t len, N_H2_FRAME* frame, size_t* consumed) {
33 uint32_t plen;
34 if (!buf || !frame || !consumed)
35 return -1;
36 if (len < N_H2_FRAME_HEADER_LEN)
37 return 0;
38 plen = ((uint32_t)buf[0] << 16) | ((uint32_t)buf[1] << 8) | (uint32_t)buf[2];
39 if (plen > N_H2_MAX_FRAME_PAYLOAD)
40 return -1;
41 if (len < (size_t)N_H2_FRAME_HEADER_LEN + plen)
42 return 0;
43 frame->length = plen;
44 frame->type = buf[3];
45 frame->flags = buf[4];
46 frame->stream_id = (((uint32_t)buf[5] & 0x7F) << 24) | ((uint32_t)buf[6] << 16) | ((uint32_t)buf[7] << 8) | (uint32_t)buf[8];
47 frame->payload = (plen > 0) ? (buf + N_H2_FRAME_HEADER_LEN) : NULL;
48 *consumed = (size_t)N_H2_FRAME_HEADER_LEN + plen;
49 return 1;
50}
51
52size_t n_http2_frame_build_header(unsigned char* out, size_t out_cap, uint32_t length, int type, int flags, uint32_t stream_id) {
53 if (!out || out_cap < N_H2_FRAME_HEADER_LEN)
54 return 0;
55 if (length > 0x00FFFFFFu)
56 return 0;
57 out[0] = (unsigned char)((length >> 16) & 0xFF);
58 out[1] = (unsigned char)((length >> 8) & 0xFF);
59 out[2] = (unsigned char)(length & 0xFF);
60 out[3] = (unsigned char)(type & 0xFF);
61 out[4] = (unsigned char)(flags & 0xFF);
62 /* the reserved top bit of the stream id is always sent as 0 */
63 out[5] = (unsigned char)((stream_id >> 24) & 0x7F);
64 out[6] = (unsigned char)((stream_id >> 16) & 0xFF);
65 out[7] = (unsigned char)((stream_id >> 8) & 0xFF);
66 out[8] = (unsigned char)(stream_id & 0xFF);
68}
69
70int n_http2_settings_parse(const unsigned char* payload, size_t len, N_H2_SETTING* out, size_t max, size_t* count) {
71 size_t i, n = 0;
72 if (count)
73 *count = 0;
74 if (len % 6 != 0)
75 return -1;
76 if (!payload && len > 0)
77 return -1;
78 for (i = 0; i + 6 <= len && n < max; i += 6) {
79 if (out) {
80 out[n].id = (uint16_t)(((uint16_t)payload[i] << 8) | (uint16_t)payload[i + 1]);
81 out[n].value = ((uint32_t)payload[i + 2] << 24) | ((uint32_t)payload[i + 3] << 16) | ((uint32_t)payload[i + 4] << 8) | (uint32_t)payload[i + 5];
82 }
83 n++;
84 }
85 if (count)
86 *count = n;
87 return 0;
88}
89
90/* ---- HPACK header compression (RFC 7541) ---- */
91
93static const char* const hpack_static_name[61] = {
94 ":authority", ":method", ":method", ":path", ":path", ":scheme", ":scheme",
95 ":status", ":status", ":status", ":status", ":status", ":status", ":status",
96 "accept-charset", "accept-encoding", "accept-language", "accept-ranges", "accept",
97 "access-control-allow-origin", "age", "allow", "authorization", "cache-control",
98 "content-disposition", "content-encoding", "content-language", "content-length",
99 "content-location", "content-range", "content-type", "cookie", "date", "etag",
100 "expect", "expires", "from", "host", "if-match", "if-modified-since", "if-none-match",
101 "if-range", "if-unmodified-since", "last-modified", "link", "location", "max-forwards",
102 "proxy-authenticate", "proxy-authorization", "range", "referer", "refresh", "retry-after",
103 "server", "set-cookie", "strict-transport-security", "transfer-encoding", "user-agent",
104 "vary", "via", "www-authenticate"};
105
107static const char* const hpack_static_value[61] = {
108 "", "GET", "POST", "/", "/index.html", "http", "https",
109 "200", "204", "206", "304", "400", "404", "500",
110 "", "gzip, deflate", "", "", "",
111 "", "", "", "", "",
112 "", "", "", "",
113 "", "", "", "", "", "",
114 "", "", "", "", "", "", "",
115 "", "", "", "", "", "",
116 "", "", "", "", "", "",
117 "", "", "", "", "",
118 "", "", ""};
119
121static const uint32_t hpack_huff_code[256] = {
122 0x1ff8, 0x7fffd8, 0xfffffe2, 0xfffffe3, 0xfffffe4, 0xfffffe5, 0xfffffe6, 0xfffffe7,
123 0xfffffe8, 0xffffea, 0x3ffffffc, 0xfffffe9, 0xfffffea, 0x3ffffffd, 0xfffffeb, 0xfffffec,
124 0xfffffed, 0xfffffee, 0xfffffef, 0xffffff0, 0xffffff1, 0xffffff2, 0x3ffffffe, 0xffffff3,
125 0xffffff4, 0xffffff5, 0xffffff6, 0xffffff7, 0xffffff8, 0xffffff9, 0xffffffa, 0xffffffb,
126 0x14, 0x3f8, 0x3f9, 0xffa, 0x1ff9, 0x15, 0xf8, 0x7fa,
127 0x3fa, 0x3fb, 0xf9, 0x7fb, 0xfa, 0x16, 0x17, 0x18,
128 0x0, 0x1, 0x2, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
129 0x1e, 0x1f, 0x5c, 0xfb, 0x7ffc, 0x20, 0xffb, 0x3fc,
130 0x1ffa, 0x21, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62,
131 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a,
132 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72,
133 0xfc, 0x73, 0xfd, 0x1ffb, 0x7fff0, 0x1ffc, 0x3ffc, 0x22,
134 0x7ffd, 0x3, 0x23, 0x4, 0x24, 0x5, 0x25, 0x26,
135 0x27, 0x6, 0x74, 0x75, 0x28, 0x29, 0x2a, 0x7,
136 0x2b, 0x76, 0x2c, 0x8, 0x9, 0x2d, 0x77, 0x78,
137 0x79, 0x7a, 0x7b, 0x7ffe, 0x7fc, 0x3ffd, 0x1ffd, 0xffffffc,
138 0xfffe6, 0x3fffd2, 0xfffe7, 0xfffe8, 0x3fffd3, 0x3fffd4, 0x3fffd5, 0x7fffd9,
139 0x3fffd6, 0x7fffda, 0x7fffdb, 0x7fffdc, 0x7fffdd, 0x7fffde, 0xffffeb, 0x7fffdf,
140 0xffffec, 0xffffed, 0x3fffd7, 0x7fffe0, 0xffffee, 0x7fffe1, 0x7fffe2, 0x7fffe3,
141 0x7fffe4, 0x1fffdc, 0x3fffd8, 0x7fffe5, 0x3fffd9, 0x7fffe6, 0x7fffe7, 0xffffef,
142 0x3fffda, 0x1fffdd, 0xfffe9, 0x3fffdb, 0x3fffdc, 0x7fffe8, 0x7fffe9, 0x1fffde,
143 0x7fffea, 0x3fffdd, 0x3fffde, 0xfffff0, 0x1fffdf, 0x3fffdf, 0x7fffeb, 0x7fffec,
144 0x1fffe0, 0x1fffe1, 0x3fffe0, 0x1fffe2, 0x7fffed, 0x3fffe1, 0x7fffee, 0x7fffef,
145 0xfffea, 0x3fffe2, 0x3fffe3, 0x3fffe4, 0x7ffff0, 0x3fffe5, 0x3fffe6, 0x7ffff1,
146 0x3ffffe0, 0x3ffffe1, 0xfffeb, 0x7fff1, 0x3fffe7, 0x7ffff2, 0x3fffe8, 0x1ffffec,
147 0x3ffffe2, 0x3ffffe3, 0x3ffffe4, 0x7ffffde, 0x7ffffdf, 0x3ffffe5, 0xfffff1, 0x1ffffed,
148 0x7fff2, 0x1fffe3, 0x3ffffe6, 0x7ffffe0, 0x7ffffe1, 0x3ffffe7, 0x7ffffe2, 0xfffff2,
149 0x1fffe4, 0x1fffe5, 0x3ffffe8, 0x3ffffe9, 0xffffffd, 0x7ffffe3, 0x7ffffe4, 0x7ffffe5,
150 0xfffec, 0xfffff3, 0xfffed, 0x1fffe6, 0x3fffe9, 0x1fffe7, 0x1fffe8, 0x7ffff3,
151 0x3fffea, 0x3fffeb, 0x1ffffee, 0x1ffffef, 0xfffff4, 0xfffff5, 0x3ffffea, 0x7ffff4,
152 0x3ffffeb, 0x7ffffe6, 0x3ffffec, 0x3ffffed, 0x7ffffe7, 0x7ffffe8, 0x7ffffe9, 0x7ffffea,
153 0x7ffffeb, 0xffffffe, 0x7ffffec, 0x7ffffed, 0x7ffffee, 0x7ffffef, 0x7fffff0, 0x3ffffee};
154
156static const uint8_t hpack_huff_len[256] = {
157 13, 23, 28, 28, 28, 28, 28, 28, 28, 24, 30, 28, 28, 30, 28, 28,
158 28, 28, 28, 28, 28, 28, 30, 28, 28, 28, 28, 28, 28, 28, 28, 28,
159 6, 10, 10, 12, 13, 6, 8, 11, 10, 10, 8, 11, 8, 6, 6, 6,
160 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 7, 8, 15, 6, 12, 10,
161 13, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
162 7, 7, 7, 7, 7, 7, 7, 7, 8, 7, 8, 13, 19, 13, 14, 6,
163 15, 5, 6, 5, 6, 5, 6, 6, 6, 5, 7, 7, 6, 6, 6, 5,
164 6, 7, 6, 5, 5, 6, 7, 7, 7, 7, 7, 15, 11, 14, 13, 28,
165 20, 22, 20, 20, 22, 22, 22, 23, 22, 23, 23, 23, 23, 23, 24, 23,
166 24, 24, 22, 23, 24, 23, 23, 23, 23, 21, 22, 23, 22, 23, 23, 24,
167 22, 21, 20, 22, 22, 23, 23, 21, 23, 22, 22, 24, 21, 22, 23, 23,
168 21, 21, 22, 21, 23, 22, 23, 23, 20, 22, 22, 22, 23, 22, 22, 23,
169 26, 26, 20, 19, 22, 23, 22, 25, 26, 26, 26, 27, 27, 26, 24, 25,
170 19, 21, 26, 27, 27, 26, 27, 24, 21, 21, 26, 26, 28, 27, 27, 27,
171 20, 24, 20, 21, 22, 21, 21, 23, 22, 22, 25, 25, 24, 24, 26, 23,
172 26, 27, 26, 26, 27, 27, 27, 27, 27, 28, 27, 27, 27, 27, 27, 26};
173
175typedef struct H2_DYN_ENTRY {
176 char* name;
177 char* value;
178 size_t size; /* name_len + value_len + 32 (RFC 7541 4.1) */
180
183 H2_DYN_ENTRY* ents; /* dynamic array, position 0 = newest = table index 62 */
184 size_t nents;
185 size_t cap;
186 size_t cur_size; /* sum of entry sizes */
187 size_t max_size; /* current effective size cap (<= limit) */
188 size_t limit; /* the advertised SETTINGS_HEADER_TABLE_SIZE upper bound */
189};
190
192static int hpack_huff_lookup(uint32_t code, int nbits) {
193 int i;
194 for (i = 0; i < 256; i++) {
195 if ((int)hpack_huff_len[i] == nbits && hpack_huff_code[i] == code)
196 return i;
197 }
198 return -1;
199}
200
202static int hpack_huff_decode(const unsigned char* s, size_t len, char** out) {
203 size_t cap = len * 2 + 16;
204 char* r = malloc(cap);
205 size_t rlen = 0;
206 uint32_t code = 0;
207 int nbits = 0;
208 size_t i;
209 if (!r)
210 return -1;
211 for (i = 0; i < len; i++) {
212 int bit;
213 for (bit = 7; bit >= 0; bit--) {
214 int sym;
215 code = (code << 1) | (uint32_t)((s[i] >> bit) & 1);
216 nbits++;
217 if (nbits > 30) {
218 free(r);
219 return -1;
220 }
221 sym = hpack_huff_lookup(code, nbits);
222 if (sym >= 0) {
223 if (rlen + 1 >= cap) {
224 char* nr;
225 cap = cap * 2 + 16;
226 nr = realloc(r, cap);
227 if (!nr) {
228 free(r);
229 return -1;
230 }
231 r = nr;
232 }
233 r[rlen++] = (char)sym;
234 code = 0;
235 nbits = 0;
236 }
237 }
238 }
239 /* the trailing padding must be fewer than 8 bits and all 1s (an EOS prefix) */
240 if (nbits > 7) {
241 free(r);
242 return -1;
243 }
244 if (nbits > 0) {
245 uint32_t mask = (uint32_t)((1u << nbits) - 1u);
246 if ((code & mask) != mask) {
247 free(r);
248 return -1;
249 }
250 }
251 r[rlen] = '\0';
252 *out = r;
253 return 0;
254}
255
257static int hpack_int_decode(const unsigned char* buf, size_t len, size_t* pos, int prefix_bits, uint64_t* out) {
258 uint64_t max_prefix = (uint64_t)((1u << prefix_bits) - 1u);
259 uint64_t val;
260 unsigned m = 0;
261 if (*pos >= len)
262 return -1;
263 val = (uint64_t)buf[*pos] & max_prefix;
264 (*pos)++;
265 if (val < max_prefix) {
266 *out = val;
267 return 0;
268 }
269 for (;;) {
270 unsigned char b;
271 if (*pos >= len)
272 return -1;
273 b = buf[*pos];
274 (*pos)++;
275 val += (uint64_t)(b & 0x7f) << m;
276 m += 7;
277 if (m > 63)
278 return -1; /* overflow guard */
279 if (!(b & 0x80))
280 break;
281 }
282 *out = val;
283 return 0;
284}
285
287static int hpack_str_decode(const unsigned char* buf, size_t len, size_t* pos, char** out) {
288 int huff;
289 uint64_t slen;
290 const unsigned char* s;
291 if (*pos >= len)
292 return -1;
293 huff = (buf[*pos] & 0x80) != 0;
294 if (hpack_int_decode(buf, len, pos, 7, &slen) != 0)
295 return -1;
296 if (slen > len || *pos + (size_t)slen > len)
297 return -1;
298 s = buf + *pos;
299 *pos += (size_t)slen;
300 if (huff)
301 return hpack_huff_decode(s, (size_t)slen, out);
302 {
303 char* r = malloc((size_t)slen + 1);
304 if (!r)
305 return -1;
306 if (slen > 0)
307 memcpy(r, s, (size_t)slen);
308 r[slen] = '\0';
309 *out = r;
310 return 0;
311 }
312}
313
315static size_t hpack_int_encode(unsigned char* out, size_t cap, int prefix_bits, unsigned char flags, uint64_t value) {
316 unsigned char max_prefix = (unsigned char)((1u << prefix_bits) - 1u);
317 size_t n = 0;
318 if (value < max_prefix) {
319 if (cap < 1)
320 return 0;
321 out[0] = (unsigned char)(flags | (unsigned char)value);
322 return 1;
323 }
324 if (cap < 1)
325 return 0;
326 out[n++] = (unsigned char)(flags | max_prefix);
327 value -= max_prefix;
328 while (value >= 128) {
329 if (n >= cap)
330 return 0;
331 out[n++] = (unsigned char)((value & 0x7f) | 0x80);
332 value >>= 7;
333 }
334 if (n >= cap)
335 return 0;
336 out[n++] = (unsigned char)value;
337 return n;
338}
339
341static size_t hpack_str_encode(unsigned char* out, size_t cap, const char* s) {
342 size_t slen = s ? strlen(s) : 0;
343 size_t n = hpack_int_encode(out, cap, 7, 0x00, (uint64_t)slen);
344 if (n == 0)
345 return 0;
346 if (n + slen > cap)
347 return 0;
348 if (slen > 0)
349 memcpy(out + n, s, slen);
350 return n + slen;
351}
352
353N_H2_HPACK* n_http2_hpack_new(size_t max_table_size) {
354 N_H2_HPACK* ctx = calloc(1, sizeof(*ctx));
355 if (!ctx)
356 return NULL;
357 if (max_table_size == 0)
358 max_table_size = N_H2_HPACK_DEFAULT_TABLE_SIZE;
359 ctx->max_size = max_table_size;
360 ctx->limit = max_table_size;
361 return ctx;
362}
363
365static void hpack_evict(N_H2_HPACK* ctx) {
366 while (ctx->cur_size > ctx->max_size && ctx->nents > 0) {
367 H2_DYN_ENTRY* e = &ctx->ents[ctx->nents - 1];
368 ctx->cur_size -= e->size;
369 free(e->name);
370 free(e->value);
371 ctx->nents--;
372 }
373}
374
376 N_H2_HPACK* ctx;
377 if (!pctx || !*pctx)
378 return;
379 ctx = *pctx;
380 while (ctx->nents > 0) {
381 ctx->nents--;
382 free(ctx->ents[ctx->nents].name);
383 free(ctx->ents[ctx->nents].value);
384 }
385 free(ctx->ents);
386 free(ctx);
387 *pctx = NULL;
388}
389
390void n_http2_hpack_set_max_size(N_H2_HPACK* ctx, size_t max_table_size) {
391 if (!ctx)
392 return;
393 ctx->limit = max_table_size;
394 if (ctx->max_size > max_table_size)
395 ctx->max_size = max_table_size;
396 hpack_evict(ctx);
397}
398
402static int hpack_dyn_add(N_H2_HPACK* ctx, const char* name, const char* value) {
403 size_t esize = strlen(name) + strlen(value) + 32;
404 H2_DYN_ENTRY e;
405 if (esize > ctx->max_size) {
406 /* evict everything; the entry is not added */
407 while (ctx->nents > 0) {
408 ctx->nents--;
409 free(ctx->ents[ctx->nents].name);
410 free(ctx->ents[ctx->nents].value);
411 }
412 ctx->cur_size = 0;
413 return 0;
414 }
415 ctx->cur_size += esize;
416 hpack_evict(ctx);
417 if (ctx->nents + 1 > ctx->cap) {
418 size_t nc = ctx->cap ? ctx->cap * 2 : 8;
419 H2_DYN_ENTRY* ne = realloc(ctx->ents, nc * sizeof(*ne));
420 if (!ne) {
421 ctx->cur_size -= esize;
422 return -1;
423 }
424 ctx->ents = ne;
425 ctx->cap = nc;
426 }
427 e.name = strdup(name);
428 e.value = strdup(value);
429 e.size = esize;
430 if (!e.name || !e.value) {
431 free(e.name);
432 free(e.value);
433 ctx->cur_size -= esize;
434 return -1;
435 }
436 memmove(&ctx->ents[1], &ctx->ents[0], ctx->nents * sizeof(ctx->ents[0]));
437 ctx->ents[0] = e;
438 ctx->nents++;
439 return 0;
440}
441
444static int hpack_lookup(const N_H2_HPACK* ctx, uint64_t idx, const char** name, const char** value) {
445 if (idx == 0)
446 return -1;
447 if (idx <= 61) {
448 *name = hpack_static_name[idx - 1];
449 *value = hpack_static_value[idx - 1];
450 return 0;
451 }
452 idx -= 62;
453 if (idx >= ctx->nents)
454 return -1;
455 *name = ctx->ents[idx].name;
456 *value = ctx->ents[idx].value;
457 return 0;
458}
459
460void n_http2_hpack_headers_free(N_H2_HEADER* headers, size_t n) {
461 size_t i;
462 if (!headers)
463 return;
464 for (i = 0; i < n; i++) {
465 free(headers[i].name);
466 free(headers[i].value);
467 headers[i].name = NULL;
468 headers[i].value = NULL;
469 }
470}
471
472int n_http2_hpack_decode(N_H2_HPACK* ctx, const unsigned char* block, size_t len, N_H2_HEADER* out, size_t max_out, size_t* count) {
473 size_t pos = 0, n = 0;
474 if (count)
475 *count = 0;
476 if (!ctx || !out || (!block && len > 0))
477 return -1;
478 while (pos < len) {
479 unsigned char b = block[pos];
480 char* name = NULL;
481 char* value = NULL;
482 if (b & 0x80) {
483 /* indexed header field (6.1) */
484 uint64_t idx;
485 const char *cn, *cv;
486 if (hpack_int_decode(block, len, &pos, 7, &idx) != 0)
487 goto fail;
488 if (hpack_lookup(ctx, idx, &cn, &cv) != 0)
489 goto fail;
490 name = strdup(cn);
491 value = strdup(cv);
492 } else if (b & 0x40) {
493 /* literal with incremental indexing (6.2.1) */
494 uint64_t idx;
495 if (hpack_int_decode(block, len, &pos, 6, &idx) != 0)
496 goto fail;
497 if (idx != 0) {
498 const char *cn, *cv;
499 if (hpack_lookup(ctx, idx, &cn, &cv) != 0)
500 goto fail;
501 name = strdup(cn);
502 } else if (hpack_str_decode(block, len, &pos, &name) != 0) {
503 goto fail;
504 }
505 if (hpack_str_decode(block, len, &pos, &value) != 0)
506 goto fail;
507 if (name && value)
508 hpack_dyn_add(ctx, name, value);
509 } else if (b & 0x20) {
510 /* dynamic table size update (6.3) */
511 uint64_t newsize;
512 if (hpack_int_decode(block, len, &pos, 5, &newsize) != 0)
513 goto fail;
514 if (newsize > ctx->limit)
515 goto fail;
516 ctx->max_size = (size_t)newsize;
517 hpack_evict(ctx);
518 continue; /* no header field produced */
519 } else {
520 /* literal without indexing (6.2.2) or never indexed (6.2.3), 4-bit prefix */
521 uint64_t idx;
522 if (hpack_int_decode(block, len, &pos, 4, &idx) != 0)
523 goto fail;
524 if (idx != 0) {
525 const char *cn, *cv;
526 if (hpack_lookup(ctx, idx, &cn, &cv) != 0)
527 goto fail;
528 name = strdup(cn);
529 } else if (hpack_str_decode(block, len, &pos, &name) != 0) {
530 goto fail;
531 }
532 if (hpack_str_decode(block, len, &pos, &value) != 0)
533 goto fail;
534 }
535 if (!name || !value)
536 goto fail;
537 if (n >= max_out)
538 goto fail; /* fail: frees the current name/value */
539 out[n].name = name;
540 out[n].value = value;
541 n++;
542 continue;
543 fail:
544 free(name);
545 free(value);
547 return -1;
548 }
549 if (count)
550 *count = n;
551 return 0;
552}
553
554size_t n_http2_hpack_encode(const N_H2_HEADER* headers, size_t n, unsigned char* out, size_t out_cap) {
555 size_t pos = 0, i;
556 if (!headers || !out)
557 return 0;
558 for (i = 0; i < n; i++) {
559 size_t w;
560 if (!headers[i].name)
561 return 0;
562 if (pos + 1 > out_cap)
563 return 0;
564 /* literal without indexing, new name: first byte 0x00 (4-bit index = 0) */
565 out[pos++] = 0x00;
566 w = hpack_str_encode(out + pos, out_cap - pos, headers[i].name);
567 if (w == 0)
568 return 0;
569 pos += w;
570 w = hpack_str_encode(out + pos, out_cap - pos, headers[i].value ? headers[i].value : "");
571 if (w == 0)
572 return 0;
573 pos += w;
574 }
575 return pos;
576}
H2_DYN_ENTRY * ents
Definition n_http2.c:183
int n_http2_hpack_decode(N_H2_HPACK *ctx, const unsigned char *block, size_t len, N_H2_HEADER *out, size_t max_out, size_t *count)
decode an HPACK header block into out[] (owned name/value strings).
Definition n_http2.c:472
size_t n_http2_hpack_encode(const N_H2_HEADER *headers, size_t n, unsigned char *out, size_t out_cap)
encode a header list into a block using literal representations without indexing and without Huffman ...
Definition n_http2.c:554
static int hpack_dyn_add(N_H2_HPACK *ctx, const char *name, const char *value)
insert (name, value) at the front of the dynamic table, evicting as needed; both strings are copied.
Definition n_http2.c:402
size_t max_size
Definition n_http2.c:187
static const uint32_t hpack_huff_code[256]
HPACK Huffman codes (RFC 7541 Appendix B), index = byte value 0..255.
Definition n_http2.c:121
char * name
Definition n_http2.c:176
static size_t hpack_int_encode(unsigned char *out, size_t cap, int prefix_bits, unsigned char flags, uint64_t value)
encode an HPACK integer with an N-bit prefix and high-bit flags
Definition n_http2.c:315
N_H2_HPACK * n_http2_hpack_new(size_t max_table_size)
create an HPACK codec context with the given dynamic table size limit (0 uses N_H2_HPACK_DEFAULT_TABL...
Definition n_http2.c:353
void n_http2_hpack_free(N_H2_HPACK **pctx)
free an HPACK codec context and NULL the caller's pointer
Definition n_http2.c:375
static const char *const hpack_static_name[61]
HPACK static table names (RFC 7541 Appendix A, index 1..61)
Definition n_http2.c:93
size_t size
Definition n_http2.c:178
void n_http2_hpack_headers_free(N_H2_HEADER *headers, size_t n)
free the owned name/value strings of a decoded header array (does not free the array itself)
Definition n_http2.c:460
int n_http2_settings_parse(const unsigned char *payload, size_t len, N_H2_SETTING *out, size_t max, size_t *count)
parse a SETTINGS frame payload (6-byte id/value entries) into out.
Definition n_http2.c:70
size_t limit
Definition n_http2.c:188
static int hpack_str_decode(const unsigned char *buf, size_t len, size_t *pos, char **out)
decode an HPACK string (Huffman or literal); allocates *out
Definition n_http2.c:287
size_t nents
Definition n_http2.c:184
static int hpack_huff_lookup(uint32_t code, int nbits)
find the Huffman symbol for an accumulated code of nbits bits, or -1
Definition n_http2.c:192
char * value
Definition n_http2.c:177
static int hpack_huff_decode(const unsigned char *s, size_t len, char **out)
decode a Huffman-coded string of len bytes into a fresh C string
Definition n_http2.c:202
static int hpack_lookup(const N_H2_HPACK *ctx, uint64_t idx, const char **name, const char **value)
resolve a table index to its name/value (const, not owned).
Definition n_http2.c:444
static int hpack_int_decode(const unsigned char *buf, size_t len, size_t *pos, int prefix_bits, uint64_t *out)
decode an HPACK integer with an N-bit prefix; advances *pos
Definition n_http2.c:257
size_t cur_size
Definition n_http2.c:186
int n_http2_frame_parse(const unsigned char *buf, size_t len, N_H2_FRAME *frame, size_t *consumed)
parse one HTTP/2 frame from a byte buffer (stateless).
Definition n_http2.c:32
size_t n_http2_frame_build_header(unsigned char *out, size_t out_cap, uint32_t length, int type, int flags, uint32_t stream_id)
write a 9-byte HTTP/2 frame header into out.
Definition n_http2.c:52
static void hpack_evict(N_H2_HPACK *ctx)
drop the oldest dynamic entries until the table fits max_size
Definition n_http2.c:365
static size_t hpack_str_encode(unsigned char *out, size_t cap, const char *s)
encode a literal (non-Huffman) string with its 7-bit length prefix
Definition n_http2.c:341
size_t cap
Definition n_http2.c:185
void n_http2_hpack_set_max_size(N_H2_HPACK *ctx, size_t max_table_size)
change the dynamic table size limit (a SETTINGS_HEADER_TABLE_SIZE change), evicting entries as needed...
Definition n_http2.c:390
static const char *const hpack_static_value[61]
HPACK static table values (empty where the entry has no value)
Definition n_http2.c:107
static const uint8_t hpack_huff_len[256]
HPACK Huffman code lengths in bits (RFC 7541 Appendix B)
Definition n_http2.c:156
one HPACK dynamic table entry (owned strings and its accounted size)
Definition n_http2.c:175
HPACK codec context: the dynamic table (index 0 = most recently added)
Definition n_http2.c:182
HTTP/2 (RFC 7540) wire framing plus HPACK header compression (RFC 7541)
char * value
header field value (owned after decode)
Definition n_http2.h:125
#define N_H2_FRAME_HEADER_LEN
length of the fixed frame header in bytes
Definition n_http2.h:53
uint32_t value
parameter value
Definition n_http2.h:102
char * name
header field name (owned after decode)
Definition n_http2.h:124
uint16_t id
parameter identifier (N_H2_SETTINGS_*)
Definition n_http2.h:101
#define N_H2_HPACK_DEFAULT_TABLE_SIZE
the default HPACK dynamic table size (SETTINGS_HEADER_TABLE_SIZE default)
Definition n_http2.h:120
uint32_t length
payload length (24-bit)
Definition n_http2.h:92
const unsigned char * payload
pointer into the input buffer (may be NULL when length is 0)
Definition n_http2.h:96
int type
frame type (N_H2_*)
Definition n_http2.h:93
int flags
frame flags
Definition n_http2.h:94
uint32_t stream_id
stream identifier (31-bit; the reserved bit is cleared)
Definition n_http2.h:95
#define N_H2_MAX_FRAME_PAYLOAD
largest frame payload the parser accepts (the default SETTINGS_MAX_FRAME_SIZE)
Definition n_http2.h:55
a parsed HTTP/2 frame; payload aliases the input buffer
Definition n_http2.h:91
one HPACK header field; after a decode both strings are owned (heap)
Definition n_http2.h:123
one SETTINGS parameter (identifier and value)
Definition n_http2.h:100