1 /*
2 * Copyright (c) 2023, Emna Rekik
3 * Copyright (c) 2024 Nordic Semiconductor ASA
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7 #include <errno.h>
8 #include <string.h>
9
10 #include <zephyr/logging/log.h>
11 #include <zephyr/net/http/hpack.h>
12 #include <zephyr/net/net_core.h>
13
14 LOG_MODULE_DECLARE(net_http_server, CONFIG_NET_HTTP_SERVER_LOG_LEVEL);
15
http_hpack_key_is_static(uint32_t key)16 static inline bool http_hpack_key_is_static(uint32_t key)
17 {
18 return key > HTTP_SERVER_HPACK_INVALID && key <= HTTP_SERVER_HPACK_WWW_AUTHENTICATE;
19 }
20
http_hpack_key_is_dynamic(uint32_t key)21 static inline bool http_hpack_key_is_dynamic(uint32_t key)
22 {
23 return key > HTTP_SERVER_HPACK_WWW_AUTHENTICATE;
24 }
25
26 struct hpack_table_entry {
27 const char *name;
28 const char *value;
29 };
30
31 static const struct hpack_table_entry http_hpack_table_static[] = {
32 [HTTP_SERVER_HPACK_AUTHORITY] = { ":authority", NULL },
33 [HTTP_SERVER_HPACK_METHOD_GET] = { ":method", "GET" },
34 [HTTP_SERVER_HPACK_METHOD_POST] = { ":method", "POST" },
35 [HTTP_SERVER_HPACK_PATH_ROOT] = { ":path", "/" },
36 [HTTP_SERVER_HPACK_PATH_INDEX] = { ":path", "/index.html" },
37 [HTTP_SERVER_HPACK_SCHEME_HTTP] = { ":scheme", "http" },
38 [HTTP_SERVER_HPACK_SCHEME_HTTPS] = { ":scheme", "https" },
39 [HTTP_SERVER_HPACK_STATUS_200] = { ":status", "200" },
40 [HTTP_SERVER_HPACK_STATUS_204] = { ":status", "204" },
41 [HTTP_SERVER_HPACK_STATUS_206] = { ":status", "206" },
42 [HTTP_SERVER_HPACK_STATUS_304] = { ":status", "304" },
43 [HTTP_SERVER_HPACK_STATUS_400] = { ":status", "400" },
44 [HTTP_SERVER_HPACK_STATUS_404] = { ":status", "404" },
45 [HTTP_SERVER_HPACK_STATUS_500] = { ":status", "500" },
46 [HTTP_SERVER_HPACK_ACCEPT_CHARSET] = { "accept-charset", NULL },
47 [HTTP_SERVER_HPACK_ACCEPT_ENCODING] = { "accept-encoding", "gzip, deflate" },
48 [HTTP_SERVER_HPACK_ACCEPT_LANGUAGE] = { "accept-language", NULL },
49 [HTTP_SERVER_HPACK_ACCEPT_RANGES] = { "accept-ranges", NULL },
50 [HTTP_SERVER_HPACK_ACCEPT] = { "accept", NULL },
51 [HTTP_SERVER_HPACK_ACCESS_CONTROL_ALLOW_ORIGIN] = { "access-control-allow-origin", NULL },
52 [HTTP_SERVER_HPACK_AGE] = { "age", NULL },
53 [HTTP_SERVER_HPACK_ALLOW] = { "allow", NULL },
54 [HTTP_SERVER_HPACK_AUTHORIZATION] = { "authorization", NULL },
55 [HTTP_SERVER_HPACK_CACHE_CONTROL] = { "cache-control", NULL },
56 [HTTP_SERVER_HPACK_CONTENT_DISPOSITION] = { "content-disposition", NULL },
57 [HTTP_SERVER_HPACK_CONTENT_ENCODING] = { "content-encoding", NULL },
58 [HTTP_SERVER_HPACK_CONTENT_LANGUAGE] = { "content-language", NULL },
59 [HTTP_SERVER_HPACK_CONTENT_LENGTH] = { "content-length", NULL },
60 [HTTP_SERVER_HPACK_CONTENT_LOCATION] = { "content-location", NULL },
61 [HTTP_SERVER_HPACK_CONTENT_RANGE] = { "content-range", NULL },
62 [HTTP_SERVER_HPACK_CONTENT_TYPE] = { "content-type", NULL },
63 [HTTP_SERVER_HPACK_COOKIE] = { "cookie", NULL },
64 [HTTP_SERVER_HPACK_DATE] = { "date", NULL },
65 [HTTP_SERVER_HPACK_ETAG] = { "etag", NULL },
66 [HTTP_SERVER_HPACK_EXPECT] = { "expect", NULL },
67 [HTTP_SERVER_HPACK_EXPIRES] = { "expires", NULL },
68 [HTTP_SERVER_HPACK_FROM] = { "from", NULL },
69 [HTTP_SERVER_HPACK_HOST] = { "host", NULL },
70 [HTTP_SERVER_HPACK_IF_MATCH] = { "if-match", NULL },
71 [HTTP_SERVER_HPACK_IF_MODIFIED_SINCE] = { "if-modified-since", NULL },
72 [HTTP_SERVER_HPACK_IF_NONE_MATCH] = { "if-none-match", NULL },
73 [HTTP_SERVER_HPACK_IF_RANGE] = { "if-range", NULL },
74 [HTTP_SERVER_HPACK_IF_UNMODIFIED_SINCE] = { "if-unmodified-since", NULL },
75 [HTTP_SERVER_HPACK_LAST_MODIFIED] = { "last-modified", NULL },
76 [HTTP_SERVER_HPACK_LINK] = { "link", NULL },
77 [HTTP_SERVER_HPACK_LOCATION] = { "location", NULL },
78 [HTTP_SERVER_HPACK_MAX_FORWARDS] = { "max-forwards", NULL },
79 [HTTP_SERVER_HPACK_PROXY_AUTHENTICATE] = { "proxy-authenticate", NULL },
80 [HTTP_SERVER_HPACK_PROXY_AUTHORIZATION] = { "proxy-authorization", NULL },
81 [HTTP_SERVER_HPACK_RANGE] = { "range", NULL },
82 [HTTP_SERVER_HPACK_REFERER] = { "referer", NULL },
83 [HTTP_SERVER_HPACK_REFRESH] = { "refresh", NULL },
84 [HTTP_SERVER_HPACK_RETRY_AFTER] = { "retry-after", NULL },
85 [HTTP_SERVER_HPACK_SERVER] = { "server", NULL },
86 [HTTP_SERVER_HPACK_SET_COOKIE] = { "set-cookie", NULL },
87 [HTTP_SERVER_HPACK_STRICT_TRANSPORT_SECURITY] = { "strict-transport-security", NULL },
88 [HTTP_SERVER_HPACK_TRANSFER_ENCODING] = { "transfer-encoding", NULL },
89 [HTTP_SERVER_HPACK_USER_AGENT] = { "user-agent", NULL },
90 [HTTP_SERVER_HPACK_VARY] = { "vary", NULL },
91 [HTTP_SERVER_HPACK_VIA] = { "via", NULL },
92 [HTTP_SERVER_HPACK_WWW_AUTHENTICATE] = { "www-authenticate", NULL },
93 };
94
http_hpack_table_get(uint32_t key)95 const struct hpack_table_entry *http_hpack_table_get(uint32_t key)
96 {
97 if (!http_hpack_key_is_static(key)) {
98 return NULL;
99 }
100
101 return &http_hpack_table_static[key];
102 }
103
http_hpack_find_index(struct http_hpack_header_buf * header,bool * name_only)104 static int http_hpack_find_index(struct http_hpack_header_buf *header,
105 bool *name_only)
106 {
107 const struct hpack_table_entry *entry;
108 int candidate = -1;
109
110 for (int i = HTTP_SERVER_HPACK_AUTHORITY;
111 i <= HTTP_SERVER_HPACK_WWW_AUTHENTICATE; i++) {
112 entry = &http_hpack_table_static[i];
113
114 if (entry->name != NULL &&
115 strlen(entry->name) == header->name_len &&
116 memcmp(entry->name, header->name, header->name_len) == 0) {
117 if (entry->value != NULL &&
118 strlen(entry->value) == header->value_len &&
119 memcmp(entry->value, header->value, header->value_len) == 0) {
120 /* Got exact match. */
121 *name_only = false;
122 return i;
123 }
124
125 if (candidate < 0) {
126 candidate = i;
127 }
128 }
129 }
130
131 if (candidate > 0) {
132 /* Matched name only. */
133 *name_only = true;
134 return candidate;
135 }
136
137 return -ENOENT;
138 }
139
140 #define HPACK_INTEGER_CONTINUATION_FLAG 0x80
141 #define HPACK_STRING_HUFFMAN_FLAG 0x80
142 #define HPACK_STRING_PREFIX_LEN 7
143
144 #define HPACK_PREFIX_INDEXED_MASK 0x80
145 #define HPACK_PREFIX_INDEXED 0x80
146 #define HPACK_PREFIX_LEN_INDEXED 7
147
148 #define HPACK_PREFIX_LITERAL_INDEXING_MASK 0xC0
149 #define HPACK_PREFIX_LITERAL_INDEXING 0x40
150 #define HPACK_PREFIX_LEN_LITERAL_INDEXING 6
151
152 #define HPACK_PREFIX_LITERAL_NO_INDEXING_MASK 0xF0
153 #define HPACK_PREFIX_LITERAL_NO_INDEXING 0x00
154 #define HPACK_PREFIX_LEN_LITERAL_NO_INDEXING 4
155
156 #define HPACK_PREFIX_LITERAL_NEVER_INDEXED_MASK 0xF0
157 #define HPACK_PREFIX_LITERAL_NEVER_INDEXED 0x10
158 #define HPACK_PREFIX_LEN_LITERAL_NEVER_INDEXED 4
159
160 #define HPACK_PREFIX_DYNAMIC_TABLE_SIZE_MASK 0xE0
161 #define HPACK_PREFIX_DYNAMIC_TABLE_SIZE_UPDATE 0x20
162 #define HPACK_PREFIX_LEN_DYNAMIC_TABLE_SIZE_UPDATE 5
163
hpack_integer_decode(const uint8_t * buf,size_t datalen,uint8_t n,uint32_t * value)164 static int hpack_integer_decode(const uint8_t *buf, size_t datalen,
165 uint8_t n, uint32_t *value)
166 {
167 int len = 0;
168 uint8_t m = 0;
169 uint8_t value_mask = (1 << n) - 1;
170
171 NET_ASSERT(n < 8);
172
173 if (datalen == 0) {
174 return -EAGAIN;
175 }
176
177 /* Based on RFC7541, ch 5.1. */
178 len++;
179 *value = *buf & value_mask;
180 if (*value < value_mask) {
181 return len;
182 }
183
184 do {
185 buf++;
186 len++;
187
188 if (--datalen == 0) {
189 return -EAGAIN;
190 }
191
192 if (m > sizeof(uint32_t) * 8) {
193 /* Can't handle integer that large. */
194 return -EBADMSG;
195 }
196
197 *value += (*buf & ~HPACK_INTEGER_CONTINUATION_FLAG) * (1 << m);
198 m += 7;
199
200 } while (*buf & HPACK_INTEGER_CONTINUATION_FLAG);
201
202 return len;
203 }
204
205 enum hpack_string_type {
206 HPACK_HEADER_NAME,
207 HPACK_HEADER_VALUE,
208 };
209
hpack_huffman_decode(const uint8_t * encoded_buf,size_t encoded_len,enum hpack_string_type type,struct http_hpack_header_buf * header)210 static int hpack_huffman_decode(const uint8_t *encoded_buf, size_t encoded_len,
211 enum hpack_string_type type,
212 struct http_hpack_header_buf *header)
213 {
214 uint8_t *buf = header->buf + header->datalen;
215 size_t buflen = sizeof(header->buf) - header->datalen;
216 int ret;
217
218 NET_ASSERT(type == HPACK_HEADER_NAME || type == HPACK_HEADER_VALUE);
219
220 ret = http_hpack_huffman_decode(encoded_buf, encoded_len, buf, buflen);
221 if (ret < 0) {
222 return ret;
223 }
224
225 if (type == HPACK_HEADER_NAME) {
226 header->name = buf;
227 header->name_len = ret;
228 } else if (type == HPACK_HEADER_VALUE) {
229 header->value = buf;
230 header->value_len = ret;
231 }
232
233 header->datalen += ret;
234
235 return 0;
236 }
237
hpack_string_decode(const uint8_t * buf,size_t datalen,enum hpack_string_type type,struct http_hpack_header_buf * header)238 static int hpack_string_decode(const uint8_t *buf, size_t datalen,
239 enum hpack_string_type type,
240 struct http_hpack_header_buf *header)
241 {
242 uint32_t str_len;
243 bool huffman;
244 int len = 0;
245 int ret;
246
247 NET_ASSERT(type == HPACK_HEADER_NAME || type == HPACK_HEADER_VALUE);
248
249 if (datalen == 0) {
250 return -EAGAIN;
251 }
252
253 huffman = *buf & HPACK_STRING_HUFFMAN_FLAG;
254
255 ret = hpack_integer_decode(buf, datalen, HPACK_STRING_PREFIX_LEN,
256 &str_len);
257 if (ret < 0) {
258 return ret;
259 }
260
261 len += ret;
262 datalen -= ret;
263 buf += ret;
264
265 if (str_len > datalen) {
266 return -EAGAIN;
267 }
268
269 if (huffman) {
270 ret = hpack_huffman_decode(buf, str_len, type, header);
271 if (ret < 0) {
272 return ret;
273 }
274 } else {
275 if (type == HPACK_HEADER_NAME) {
276 header->name = buf;
277 header->name_len = str_len;
278 } else if (type == HPACK_HEADER_VALUE) {
279 header->value = buf;
280 header->value_len = str_len;
281 }
282 }
283
284 len += str_len;
285
286 return len;
287 }
288
hpack_handle_indexed(const uint8_t * buf,size_t datalen,struct http_hpack_header_buf * header)289 static int hpack_handle_indexed(const uint8_t *buf, size_t datalen,
290 struct http_hpack_header_buf *header)
291 {
292 const struct hpack_table_entry *entry;
293 uint32_t index;
294 int ret;
295
296 ret = hpack_integer_decode(buf, datalen, HPACK_PREFIX_LEN_INDEXED,
297 &index);
298 if (ret < 0) {
299 return ret;
300 }
301
302 if (index == 0) {
303 return -EBADMSG;
304 }
305
306 entry = http_hpack_table_get(index);
307 if (entry == NULL) {
308 return -EBADMSG;
309 }
310
311 if (entry->name == NULL || entry->value == NULL) {
312 return -EBADMSG;
313 }
314
315 header->name = entry->name;
316 header->name_len = strlen(entry->name);
317 header->value = entry->value;
318 header->value_len = strlen(entry->value);
319
320 return ret;
321 }
322
hpack_handle_literal(const uint8_t * buf,size_t datalen,struct http_hpack_header_buf * header,uint8_t prefix_len)323 static int hpack_handle_literal(const uint8_t *buf, size_t datalen,
324 struct http_hpack_header_buf *header,
325 uint8_t prefix_len)
326 {
327 uint32_t index;
328 int ret, len;
329
330 header->datalen = 0;
331
332 ret = hpack_integer_decode(buf, datalen, prefix_len, &index);
333 if (ret < 0) {
334 return ret;
335 }
336
337 len = ret;
338 buf += ret;
339 datalen -= ret;
340
341 if (index == 0) {
342 /* Literal name. */
343 ret = hpack_string_decode(buf, datalen, HPACK_HEADER_NAME,
344 header);
345 if (ret < 0) {
346 return ret;
347 }
348
349 len += ret;
350 buf += ret;
351 datalen -= ret;
352 } else {
353 /* Indexed name. */
354 const struct hpack_table_entry *entry;
355
356 entry = http_hpack_table_get(index);
357 if (entry == NULL) {
358 return -EBADMSG;
359 }
360
361 if (entry->name == NULL) {
362 return -EBADMSG;
363 }
364
365 header->name = entry->name;
366 header->name_len = strlen(entry->name);
367 }
368
369 ret = hpack_string_decode(buf, datalen, HPACK_HEADER_VALUE, header);
370 if (ret < 0) {
371 return ret;
372 }
373
374 len += ret;
375
376 return len;
377 }
378
hpack_handle_literal_index(const uint8_t * buf,size_t datalen,struct http_hpack_header_buf * header)379 static int hpack_handle_literal_index(const uint8_t *buf, size_t datalen,
380 struct http_hpack_header_buf *header)
381 {
382 /* TODO Add dynamic table support, if needed. */
383
384 return hpack_handle_literal(buf, datalen, header,
385 HPACK_PREFIX_LEN_LITERAL_INDEXING);
386 }
387
hpack_handle_literal_no_index(const uint8_t * buf,size_t datalen,struct http_hpack_header_buf * header)388 static int hpack_handle_literal_no_index(const uint8_t *buf, size_t datalen,
389 struct http_hpack_header_buf *header)
390 {
391 return hpack_handle_literal(buf, datalen, header,
392 HPACK_PREFIX_LEN_LITERAL_NO_INDEXING);
393 }
394
hpack_handle_dynamic_size_update(const uint8_t * buf,size_t datalen)395 static int hpack_handle_dynamic_size_update(const uint8_t *buf, size_t datalen)
396 {
397 uint32_t max_size;
398 int ret;
399
400 ret = hpack_integer_decode(
401 buf, datalen, HPACK_PREFIX_LEN_DYNAMIC_TABLE_SIZE_UPDATE, &max_size);
402 if (ret < 0) {
403 return ret;
404 }
405
406 /* TODO Add dynamic table support, if needed. */
407
408 return ret;
409 }
410
http_hpack_decode_header(const uint8_t * buf,size_t datalen,struct http_hpack_header_buf * header)411 int http_hpack_decode_header(const uint8_t *buf, size_t datalen,
412 struct http_hpack_header_buf *header)
413 {
414 uint8_t prefix;
415 int ret;
416
417 if (buf == NULL || header == NULL) {
418 return -EINVAL;
419 }
420
421 if (datalen == 0) {
422 return -EAGAIN;
423 }
424
425 prefix = *buf;
426
427 if ((prefix & HPACK_PREFIX_INDEXED_MASK) == HPACK_PREFIX_INDEXED) {
428 ret = hpack_handle_indexed(buf, datalen, header);
429 } else if ((prefix & HPACK_PREFIX_LITERAL_INDEXING_MASK) ==
430 HPACK_PREFIX_LITERAL_INDEXING) {
431 ret = hpack_handle_literal_index(buf, datalen, header);
432 } else if (((prefix & HPACK_PREFIX_LITERAL_NO_INDEXING_MASK) ==
433 HPACK_PREFIX_LITERAL_NO_INDEXING) ||
434 ((prefix & HPACK_PREFIX_LITERAL_NEVER_INDEXED_MASK) ==
435 HPACK_PREFIX_LITERAL_NEVER_INDEXED)) {
436 ret = hpack_handle_literal_no_index(buf, datalen, header);
437 } else if ((prefix & HPACK_PREFIX_DYNAMIC_TABLE_SIZE_MASK) ==
438 HPACK_PREFIX_DYNAMIC_TABLE_SIZE_UPDATE) {
439 ret = hpack_handle_dynamic_size_update(buf, datalen);
440 } else {
441 ret = -EINVAL;
442 }
443
444 return ret;
445 }
446
hpack_integer_encode(uint8_t * buf,size_t buflen,int value,uint8_t prefix,uint8_t n)447 static int hpack_integer_encode(uint8_t *buf, size_t buflen, int value,
448 uint8_t prefix, uint8_t n)
449 {
450 uint8_t limit = (1 << n) - 1;
451 int len = 0;
452
453 if (buflen == 0) {
454 return -ENOBUFS;
455 }
456
457 /* Based on RFC7541, ch 5.1. */
458 if (value < limit) {
459 *buf = prefix | (uint8_t)value;
460
461 return 1;
462 }
463
464 *buf++ = prefix | limit;
465 len++;
466 value -= limit;
467
468 while (value >= 128) {
469 if (len >= buflen) {
470 return -ENOBUFS;
471 }
472
473 *buf = (uint8_t)((value % 128) + 128);
474 len++;
475 value /= 128;
476 }
477
478 if (len >= buflen) {
479 return -ENOBUFS;
480 }
481
482 *buf = (uint8_t)value;
483 len++;
484
485 return len;
486 }
487
hpack_string_encode(uint8_t * buf,size_t buflen,enum hpack_string_type type,struct http_hpack_header_buf * header)488 static int hpack_string_encode(uint8_t *buf, size_t buflen,
489 enum hpack_string_type type,
490 struct http_hpack_header_buf *header)
491 {
492 int ret, len = 0;
493 const char *str;
494 size_t str_len;
495 uint8_t prefix = 0;
496
497 if (type == HPACK_HEADER_NAME) {
498 str = header->name;
499 str_len = header->name_len;
500 } else {
501 str = header->value;
502 str_len = header->value_len;
503 }
504
505 /* Try to encode string into intermediate buffer. */
506 ret = http_hpack_huffman_encode(str, str_len, header->buf,
507 sizeof(header->buf));
508 if (ret > 0 && ret < str_len) {
509 /* Use Huffman encoded string only if smaller than the original. */
510 str = header->buf;
511 str_len = ret;
512 prefix = HPACK_STRING_HUFFMAN_FLAG;
513 }
514
515 /* Encode string length. */
516 ret = hpack_integer_encode(buf, buflen, str_len, prefix,
517 HPACK_STRING_PREFIX_LEN);
518 if (ret < 0) {
519 return ret;
520 }
521
522 buf += ret;
523 buflen -= ret;
524 len += ret;
525
526 /* Copy string. */
527 if (str_len > buflen) {
528 return -ENOBUFS;
529 }
530
531 memcpy(buf, str, str_len);
532 len += str_len;
533
534 return len;
535 }
536
hpack_encode_literal(uint8_t * buf,size_t buflen,struct http_hpack_header_buf * header)537 static int hpack_encode_literal(uint8_t *buf, size_t buflen,
538 struct http_hpack_header_buf *header)
539 {
540 int ret, len = 0;
541
542 ret = hpack_integer_encode(buf, buflen, 0,
543 HPACK_PREFIX_LITERAL_NEVER_INDEXED,
544 HPACK_PREFIX_LEN_LITERAL_NEVER_INDEXED);
545 if (ret < 0) {
546 return ret;
547 }
548
549 buf += ret;
550 buflen -= ret;
551 len += ret;
552
553 ret = hpack_string_encode(buf, buflen, HPACK_HEADER_NAME, header);
554 if (ret < 0) {
555 return ret;
556 }
557
558 buf += ret;
559 buflen -= ret;
560 len += ret;
561
562 ret = hpack_string_encode(buf, buflen, HPACK_HEADER_VALUE, header);
563 if (ret < 0) {
564 return ret;
565 }
566
567 len += ret;
568
569 return len;
570 }
571
hpack_encode_literal_value(uint8_t * buf,size_t buflen,int index,struct http_hpack_header_buf * header)572 static int hpack_encode_literal_value(uint8_t *buf, size_t buflen, int index,
573 struct http_hpack_header_buf *header)
574 {
575 int ret, len = 0;
576
577 ret = hpack_integer_encode(buf, buflen, index,
578 HPACK_PREFIX_LITERAL_NEVER_INDEXED,
579 HPACK_PREFIX_LEN_LITERAL_NEVER_INDEXED);
580 if (ret < 0) {
581 return ret;
582 }
583
584 buf += ret;
585 buflen -= ret;
586 len += ret;
587
588 ret = hpack_string_encode(buf, buflen, HPACK_HEADER_VALUE, header);
589 if (ret < 0) {
590 return ret;
591 }
592
593 len += ret;
594
595 return len;
596 }
597
hpack_encode_indexed(uint8_t * buf,size_t buflen,int index)598 static int hpack_encode_indexed(uint8_t *buf, size_t buflen, int index)
599 {
600 return hpack_integer_encode(buf, buflen, index, HPACK_PREFIX_INDEXED,
601 HPACK_PREFIX_LEN_INDEXED);
602 }
603
http_hpack_encode_header(uint8_t * buf,size_t buflen,struct http_hpack_header_buf * header)604 int http_hpack_encode_header(uint8_t *buf, size_t buflen,
605 struct http_hpack_header_buf *header)
606 {
607 int ret, len = 0;
608 bool name_only;
609
610 if (buf == NULL || header == NULL ||
611 header->name == NULL || header->name_len == 0 ||
612 header->value == NULL || header->value_len == 0) {
613 return -EINVAL;
614 }
615
616 if (buflen == 0) {
617 return -ENOBUFS;
618 }
619
620 ret = http_hpack_find_index(header, &name_only);
621 if (ret < 0) {
622 /* All literal */
623 len = hpack_encode_literal(buf, buflen, header);
624 } else if (name_only) {
625 /* Literal value */
626 len = hpack_encode_literal_value(buf, buflen, ret, header);
627 } else {
628 /* Indexed */
629 len = hpack_encode_indexed(buf, buflen, ret);
630 }
631
632 return len;
633 }
634