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