| 2101 | } |
| 2102 | |
| 2103 | static void write_accept_language(struct strbuf *buf) |
| 2104 | { |
| 2105 | /* |
| 2106 | * MAX_DECIMAL_PLACES must not be larger than 3. If it is larger than |
| 2107 | * that, q-value will be smaller than 0.001, the minimum q-value the |
| 2108 | * HTTP specification allows. See |
| 2109 | * https://datatracker.ietf.org/doc/html/rfc7231#section-5.3.1 for q-value. |
| 2110 | */ |
| 2111 | const int MAX_DECIMAL_PLACES = 3; |
| 2112 | const int MAX_LANGUAGE_TAGS = 1000; |
| 2113 | const int MAX_ACCEPT_LANGUAGE_HEADER_SIZE = 4000; |
| 2114 | char **language_tags = NULL; |
| 2115 | int num_langs = 0; |
| 2116 | const char *s = get_preferred_languages(); |
| 2117 | int i; |
| 2118 | struct strbuf tag = STRBUF_INIT; |
| 2119 | |
| 2120 | /* Don't add Accept-Language header if no language is preferred. */ |
| 2121 | if (!s) |
| 2122 | return; |
| 2123 | |
| 2124 | /* |
| 2125 | * Split the colon-separated string of preferred languages into |
| 2126 | * language_tags array. |
| 2127 | */ |
| 2128 | do { |
| 2129 | /* collect language tag */ |
| 2130 | for (; *s && (isalnum(*s) || *s == '_'); s++) |
| 2131 | strbuf_addch(&tag, *s == '_' ? '-' : *s); |
| 2132 | |
| 2133 | /* skip .codeset, @modifier and any other unnecessary parts */ |
| 2134 | while (*s && *s != ':') |
| 2135 | s++; |
| 2136 | |
| 2137 | if (tag.len) { |
| 2138 | num_langs++; |
| 2139 | REALLOC_ARRAY(language_tags, num_langs); |
| 2140 | language_tags[num_langs - 1] = strbuf_detach(&tag, NULL); |
| 2141 | if (num_langs >= MAX_LANGUAGE_TAGS - 1) /* -1 for '*' */ |
| 2142 | break; |
| 2143 | } |
| 2144 | } while (*s++); |
| 2145 | |
| 2146 | /* write Accept-Language header into buf */ |
| 2147 | if (num_langs) { |
| 2148 | int last_buf_len = 0; |
| 2149 | int max_q; |
| 2150 | int decimal_places; |
| 2151 | char q_format[32]; |
| 2152 | |
| 2153 | /* add '*' */ |
| 2154 | REALLOC_ARRAY(language_tags, num_langs + 1); |
| 2155 | language_tags[num_langs++] = xstrdup("*"); |
| 2156 | |
| 2157 | /* compute decimal_places */ |
| 2158 | for (max_q = 1, decimal_places = 0; |
| 2159 | max_q < num_langs && decimal_places <= MAX_DECIMAL_PLACES; |
| 2160 | decimal_places++, max_q *= 10) |
no test coverage detected