1 /** @file
2 * @brief HTTP compression handling functions
3 *
4 * Helper functions to handle compression formats
5 */
6
7 /*
8 * Copyright (c) 2025 Endress+Hauser
9 *
10 * SPDX-License-Identifier: Apache-2.0
11 */
12 #include <stdbool.h>
13 #include <string.h>
14 #include <strings.h>
15
16 #include <zephyr/net/http/server.h>
17 #include <zephyr/sys/__assert.h>
18 #include <zephyr/sys/util.h>
19
20 #include "headers/server_internal.h"
21
22 static int http_compression_match(enum http_compression *compression, const char *text,
23 enum http_compression expected);
24
http_compression_parse_accept_encoding(const char * accept_encoding,size_t len,uint8_t * supported_compression)25 void http_compression_parse_accept_encoding(const char *accept_encoding, size_t len,
26 uint8_t *supported_compression)
27 {
28 enum http_compression detected_compression;
29 char strbuf[HTTP_COMPRESSION_MAX_STRING_LEN + 1] = {0};
30 const char *start = accept_encoding;
31 const char *end = NULL;
32 bool priority_string = false;
33
34 *supported_compression = HTTP_NONE;
35 for (size_t i = 0; i < len; i++) {
36 if (accept_encoding[i] == 0) {
37 break;
38 } else if (accept_encoding[i] == ' ') {
39 start = &accept_encoding[i + 1];
40 continue;
41 } else if (accept_encoding[i] == ';') {
42 end = &accept_encoding[i];
43 priority_string = true;
44 } else if (accept_encoding[i] == ',') {
45 if (!priority_string) {
46 end = &accept_encoding[i];
47 }
48 priority_string = false;
49 } else if (i + 1 == len) {
50 end = &accept_encoding[i + 1];
51 }
52
53 if (end == NULL) {
54 continue;
55 }
56
57 if (end - start > HTTP_COMPRESSION_MAX_STRING_LEN) {
58 end = NULL;
59 start = end + 1;
60 continue;
61 }
62
63 memcpy(strbuf, start, end - start);
64 strbuf[end - start] = 0;
65
66 if (http_compression_from_text(&detected_compression, strbuf) == 0) {
67 WRITE_BIT(*supported_compression, detected_compression, true);
68 }
69
70 end = NULL;
71 start = end + 1;
72 }
73 }
74
http_compression_text(enum http_compression compression)75 const char *http_compression_text(enum http_compression compression)
76 {
77 switch (compression) {
78 case HTTP_NONE:
79 return "";
80 case HTTP_GZIP:
81 return "gzip";
82 case HTTP_COMPRESS:
83 return "compress";
84 case HTTP_DEFLATE:
85 return "deflate";
86 case HTTP_BR:
87 return "br";
88 case HTTP_ZSTD:
89 return "zstd";
90 }
91 return "";
92 }
93
http_compression_from_text(enum http_compression * compression,const char * text)94 int http_compression_from_text(enum http_compression *compression, const char *text)
95 {
96 __ASSERT_NO_MSG(compression);
97 __ASSERT_NO_MSG(text);
98
99 for (enum http_compression i = 0; compression_value_is_valid(i); ++i) {
100 if (http_compression_match(compression, text, i) == 0) {
101 return 0;
102 }
103 }
104 return 1;
105 }
106
compression_value_is_valid(enum http_compression compression)107 bool compression_value_is_valid(enum http_compression compression)
108 {
109 switch (compression) {
110 case HTTP_NONE:
111 case HTTP_GZIP:
112 case HTTP_COMPRESS:
113 case HTTP_DEFLATE:
114 case HTTP_BR:
115 case HTTP_ZSTD:
116 return true;
117 }
118 return false;
119 }
120
http_compression_match(enum http_compression * compression,const char * text,enum http_compression expected)121 static int http_compression_match(enum http_compression *compression, const char *text,
122 enum http_compression expected)
123 {
124 __ASSERT_NO_MSG(compression);
125 __ASSERT_NO_MSG(text);
126
127 if (strcasecmp(http_compression_text(expected), text) == 0) {
128 *compression = expected;
129 return 0;
130 } else {
131 return 1;
132 }
133 }
134