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