]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * Copyright (C) 1996-2025 The Squid Software Foundation and contributors | |
3 | * | |
4 | * Squid software is distributed under GPLv2+ license and includes | |
5 | * contributions from numerous individuals and organizations. | |
6 | * Please see the COPYING and CONTRIBUTORS files for details. | |
7 | */ | |
8 | ||
9 | /* DEBUG: section 03 Configuration File Parsing */ | |
10 | ||
11 | #include "squid.h" | |
12 | #include "cache_cf.h" | |
13 | #include "compat/strtoll.h" | |
14 | #include "ConfigParser.h" | |
15 | #include "debug/Stream.h" | |
16 | #include "globals.h" | |
17 | #include "Parsing.h" | |
18 | #include "sbuf/Stream.h" | |
19 | ||
20 | /* | |
21 | * These functions is the same as atoi/l/f, except that they check for errors | |
22 | */ | |
23 | ||
24 | double | |
25 | xatof(const char *token) | |
26 | { | |
27 | char *end = nullptr; | |
28 | double ret = strtod(token, &end); | |
29 | ||
30 | if (ret == 0 && end == token) { | |
31 | debugs(0, DBG_PARSE_NOTE(DBG_IMPORTANT), "ERROR: No digits were found in the input value '" << token << "'."); | |
32 | self_destruct(); | |
33 | } | |
34 | ||
35 | if (*end) { | |
36 | debugs(0, DBG_PARSE_NOTE(DBG_IMPORTANT), "ERROR: Invalid value: '" << token << "' is supposed to be a number."); | |
37 | self_destruct(); | |
38 | } | |
39 | ||
40 | return ret; | |
41 | } | |
42 | ||
43 | int | |
44 | xatoi(const char *token) | |
45 | { | |
46 | int64_t input = xatoll(token, 10); | |
47 | int ret = (int) input; | |
48 | ||
49 | if (input != static_cast<int64_t>(ret)) { | |
50 | debugs(0, DBG_PARSE_NOTE(DBG_IMPORTANT), "ERROR: The value '" << token << "' is larger than the type 'int'."); | |
51 | self_destruct(); | |
52 | } | |
53 | ||
54 | return ret; | |
55 | } | |
56 | ||
57 | unsigned int | |
58 | xatoui(const char *token, char eov) | |
59 | { | |
60 | int64_t input = xatoll(token, 10, eov); | |
61 | if (input < 0) | |
62 | throw TextException(ToSBuf("the input value '", token, "' cannot be less than 0"), Here()); | |
63 | ||
64 | unsigned int ret = (unsigned int) input; | |
65 | if (input != static_cast<int64_t>(ret)) | |
66 | throw TextException(ToSBuf("the value '", token, "' is larger than the type 'unsigned int'"), Here()); | |
67 | ||
68 | return ret; | |
69 | } | |
70 | ||
71 | long | |
72 | xatol(const char *token) | |
73 | { | |
74 | int64_t input = xatoll(token, 10); | |
75 | long ret = (long) input; | |
76 | ||
77 | if (input != static_cast<int64_t>(ret)) { | |
78 | debugs(0, DBG_PARSE_NOTE(DBG_IMPORTANT), "ERROR: The value '" << token << "' is larger than the type 'long'."); | |
79 | self_destruct(); | |
80 | } | |
81 | ||
82 | return ret; | |
83 | } | |
84 | ||
85 | int64_t | |
86 | xatoll(const char *token, int base, char eov) | |
87 | { | |
88 | char *end = nullptr; | |
89 | int64_t ret = strtoll(token, &end, base); | |
90 | ||
91 | if (end == token) { | |
92 | debugs(0, DBG_PARSE_NOTE(DBG_IMPORTANT), "ERROR: No digits were found in the input value '" << token << "'."); | |
93 | self_destruct(); | |
94 | } | |
95 | ||
96 | if (*end != eov) { | |
97 | debugs(0, DBG_PARSE_NOTE(DBG_IMPORTANT), "ERROR: Invalid value: '" << token << "' is supposed to be a number."); | |
98 | self_destruct(); | |
99 | } | |
100 | ||
101 | return ret; | |
102 | } | |
103 | ||
104 | uint64_t | |
105 | xatoull(const char *token, int base, char eov) | |
106 | { | |
107 | const auto number = xatoll(token, base, eov); | |
108 | if (number < 0) | |
109 | throw TextException(ToSBuf("the input value '", token, "' cannot be less than 0"), Here()); | |
110 | return static_cast<uint64_t>(number); | |
111 | } | |
112 | ||
113 | unsigned short | |
114 | xatos(const char *token) | |
115 | { | |
116 | long port = xatol(token); | |
117 | ||
118 | if (port < 0) { | |
119 | debugs(0, DBG_PARSE_NOTE(DBG_IMPORTANT), "ERROR: The value '" << token << "' cannot be less than 0."); | |
120 | self_destruct(); | |
121 | } | |
122 | ||
123 | if (port & ~0xFFFF) { | |
124 | debugs(0, DBG_PARSE_NOTE(DBG_IMPORTANT), "ERROR: The value '" << token << "' is larger than the type 'short'."); | |
125 | self_destruct(); | |
126 | } | |
127 | ||
128 | return port; | |
129 | } | |
130 | ||
131 | int64_t | |
132 | GetInteger64(void) | |
133 | { | |
134 | char *token = ConfigParser::NextToken(); | |
135 | if (!token) { | |
136 | self_destruct(); | |
137 | return -1; // not reachable | |
138 | } | |
139 | ||
140 | return xatoll(token, 10); | |
141 | } | |
142 | ||
143 | /* | |
144 | * This function is different from others (e.g., GetInteger64, GetShort) | |
145 | * because it supports octal and hexadecimal numbers | |
146 | */ | |
147 | int | |
148 | GetInteger(void) | |
149 | { | |
150 | char *token = ConfigParser::NextToken(); | |
151 | int i; | |
152 | ||
153 | if (!token) { | |
154 | self_destruct(); | |
155 | return -1; // not reachable | |
156 | } | |
157 | ||
158 | // The conversion must honor 0 and 0x prefixes, which are important for things like umask | |
159 | int64_t ret = xatoll(token, 0); | |
160 | ||
161 | i = (int) ret; | |
162 | if (ret != static_cast<int64_t>(i)) { | |
163 | debugs(0, DBG_PARSE_NOTE(DBG_IMPORTANT), "ERROR: The value '" << token << "' is larger than the type 'int'."); | |
164 | self_destruct(); | |
165 | } | |
166 | ||
167 | return i; | |
168 | } | |
169 | ||
170 | /* | |
171 | * This function is similar as GetInteger() but the token might contain | |
172 | * the percentage symbol (%) and we check whether the value is in the range | |
173 | * of [0, 100] | |
174 | * So, we accept two types of input: 1. XX% or 2. XX , 0<=XX<=100 | |
175 | * unless the limit parameter is set to false. | |
176 | */ | |
177 | double | |
178 | GetPercentage(bool limit) | |
179 | { | |
180 | char *token = ConfigParser::NextToken(); | |
181 | ||
182 | if (!token) { | |
183 | debugs(3, DBG_CRITICAL, "FATAL: A percentage value is missing."); | |
184 | self_destruct(); | |
185 | return 0.0; // not reachable | |
186 | } | |
187 | ||
188 | //if there is a % in the end of the digits, we remove it and go on. | |
189 | char* end = &token[strlen(token)-1]; | |
190 | if (*end == '%') { | |
191 | *end = '\0'; | |
192 | } | |
193 | ||
194 | int p = xatoi(token); | |
195 | ||
196 | if (p < 0 || (limit && p > 100)) { | |
197 | debugs(3, DBG_CRITICAL, "FATAL: The value '" << token << "' is out of range. A percentage should be within [0, 100]."); | |
198 | self_destruct(); | |
199 | } | |
200 | ||
201 | return static_cast<double>(p) / 100.0; | |
202 | } | |
203 | ||
204 | unsigned short | |
205 | GetShort(void) | |
206 | { | |
207 | char *token = ConfigParser::NextToken(); | |
208 | if (!token) { | |
209 | self_destruct(); | |
210 | return 0; // not reachable | |
211 | } | |
212 | ||
213 | return xatos(token); | |
214 | } | |
215 | ||
216 | bool | |
217 | StringToInt(const char *s, int &result, const char **p, int base) | |
218 | { | |
219 | if (s) { | |
220 | char *ptr = nullptr; | |
221 | const int h = (int) strtol(s, &ptr, base); | |
222 | ||
223 | if (ptr != s && ptr) { | |
224 | result = h; | |
225 | ||
226 | if (p) | |
227 | *p = ptr; | |
228 | ||
229 | return true; | |
230 | } | |
231 | } | |
232 | ||
233 | return false; | |
234 | } | |
235 | ||
236 | bool | |
237 | StringToInt64(const char *s, int64_t &result, const char **p, int base) | |
238 | { | |
239 | if (s) { | |
240 | char *ptr = nullptr; | |
241 | const int64_t h = (int64_t) strtoll(s, &ptr, base); | |
242 | ||
243 | if (ptr != s && ptr) { | |
244 | result = h; | |
245 | ||
246 | if (p) | |
247 | *p = ptr; | |
248 | ||
249 | return true; | |
250 | } | |
251 | } | |
252 | ||
253 | return false; | |
254 | } | |
255 | ||
256 | bool | |
257 | GetHostWithPort(char *token, Ip::Address *ipa) | |
258 | { | |
259 | char *t; | |
260 | char *host; | |
261 | char *tmp; | |
262 | unsigned short port; | |
263 | ||
264 | host = nullptr; | |
265 | port = 0; | |
266 | ||
267 | if (*token == '[') { | |
268 | /* [host]:port */ | |
269 | host = token + 1; | |
270 | t = strchr(host, ']'); | |
271 | if (!t) | |
272 | return false; | |
273 | *t = '\0'; | |
274 | ++t; | |
275 | if (*t != ':') | |
276 | return false; | |
277 | port = xatos(t + 1); | |
278 | } else if ((t = strchr(token, ':'))) { | |
279 | /* host:port */ | |
280 | host = token; | |
281 | *t = '\0'; | |
282 | port = xatos(t + 1); | |
283 | ||
284 | if (0 == port) | |
285 | return false; | |
286 | } else if (strtol(token, &tmp, 10) && !*tmp) { | |
287 | port = xatos(token); | |
288 | } else { | |
289 | host = token; | |
290 | port = 0; | |
291 | } | |
292 | ||
293 | if (nullptr == host) | |
294 | ipa->setAnyAddr(); | |
295 | else if (ipa->GetHostByName(host)) /* do not use ipcache. Accept either FQDN or IPA. */ | |
296 | (void) 0; | |
297 | else | |
298 | return false; | |
299 | ||
300 | /* port MUST be set after the IPA lookup/conversion is performed. */ | |
301 | ipa->port(port); | |
302 | ||
303 | return true; | |
304 | } | |
305 |