]>
Commit | Line | Data |
---|---|---|
c8f4eac4 | 1 | /* |
bf95c10a | 2 | * Copyright (C) 1996-2022 The Squid Software Foundation and contributors |
c8f4eac4 | 3 | * |
bbc27441 AJ |
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. | |
c8f4eac4 | 7 | */ |
8 | ||
bbc27441 AJ |
9 | /* DEBUG: section 03 Configuration File Parsing */ |
10 | ||
f7f3304a | 11 | #include "squid.h" |
8a01b99e | 12 | #include "cache_cf.h" |
27bc2077 | 13 | #include "compat/strtoll.h" |
079a8480 | 14 | #include "ConfigParser.h" |
675b8408 | 15 | #include "debug/Stream.h" |
602d9612 A |
16 | #include "globals.h" |
17 | #include "Parsing.h" | |
c59baaa8 | 18 | #include "sbuf/Stream.h" |
c8f4eac4 | 19 | |
20 | /* | |
21 | * These functions is the same as atoi/l/f, except that they check for errors | |
22 | */ | |
23 | ||
0e656b69 | 24 | double |
25 | xatof(const char *token) | |
c8f4eac4 | 26 | { |
aee3523a | 27 | char *end = nullptr; |
0e656b69 | 28 | double ret = strtod(token, &end); |
c8f4eac4 | 29 | |
54a063a2 TX |
30 | if (ret == 0 && end == token) { |
31 | debugs(0, DBG_PARSE_NOTE(DBG_IMPORTANT), "ERROR: No digits were found in the input value '" << token << "'."); | |
c8f4eac4 | 32 | self_destruct(); |
54a063a2 TX |
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 | } | |
c8f4eac4 | 39 | |
40 | return ret; | |
41 | } | |
42 | ||
43 | int | |
44 | xatoi(const char *token) | |
45 | { | |
54a063a2 TX |
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 | |
e398d16e | 58 | xatoui(const char *token, char eov) |
54a063a2 | 59 | { |
e398d16e | 60 | int64_t input = xatoll(token, 10, eov); |
c59baaa8 EB |
61 | if (input < 0) |
62 | throw TextException(ToSBuf("the input value '", token, "' cannot be less than 0"), Here()); | |
54a063a2 TX |
63 | |
64 | unsigned int ret = (unsigned int) input; | |
c59baaa8 EB |
65 | if (input != static_cast<int64_t>(ret)) |
66 | throw TextException(ToSBuf("the value '", token, "' is larger than the type 'unsigned int'"), Here()); | |
54a063a2 TX |
67 | |
68 | return ret; | |
c8f4eac4 | 69 | } |
70 | ||
0e656b69 | 71 | long |
72 | xatol(const char *token) | |
73 | { | |
54a063a2 TX |
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 | |
e398d16e | 86 | xatoll(const char *token, int base, char eov) |
54a063a2 | 87 | { |
aee3523a | 88 | char *end = nullptr; |
54a063a2 | 89 | int64_t ret = strtoll(token, &end, base); |
0e656b69 | 90 | |
54a063a2 TX |
91 | if (end == token) { |
92 | debugs(0, DBG_PARSE_NOTE(DBG_IMPORTANT), "ERROR: No digits were found in the input value '" << token << "'."); | |
0e656b69 | 93 | self_destruct(); |
54a063a2 TX |
94 | } |
95 | ||
e398d16e | 96 | if (*end != eov) { |
54a063a2 TX |
97 | debugs(0, DBG_PARSE_NOTE(DBG_IMPORTANT), "ERROR: Invalid value: '" << token << "' is supposed to be a number."); |
98 | self_destruct(); | |
99 | } | |
0e656b69 | 100 | |
101 | return ret; | |
102 | } | |
103 | ||
c59baaa8 EB |
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 | ||
0e656b69 | 113 | unsigned short |
114 | xatos(const char *token) | |
115 | { | |
116 | long port = xatol(token); | |
117 | ||
54a063a2 TX |
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'."); | |
0e656b69 | 125 | self_destruct(); |
54a063a2 | 126 | } |
0e656b69 | 127 | |
128 | return port; | |
129 | } | |
130 | ||
b1fb3348 AJ |
131 | int64_t |
132 | GetInteger64(void) | |
133 | { | |
2eceb328 | 134 | char *token = ConfigParser::NextToken(); |
b9e4cf09 | 135 | if (!token) { |
b1fb3348 | 136 | self_destruct(); |
b9e4cf09 AJ |
137 | return -1; // not reachable |
138 | } | |
b1fb3348 | 139 | |
54a063a2 | 140 | return xatoll(token, 10); |
b1fb3348 AJ |
141 | } |
142 | ||
54a063a2 TX |
143 | /* |
144 | * This function is different from others (e.g., GetInteger64, GetShort) | |
145 | * because it supports octal and hexadecimal numbers | |
146 | */ | |
c8f4eac4 | 147 | int |
148 | GetInteger(void) | |
149 | { | |
2eceb328 | 150 | char *token = ConfigParser::NextToken(); |
c8f4eac4 | 151 | int i; |
152 | ||
b9e4cf09 | 153 | if (!token) { |
c8f4eac4 | 154 | self_destruct(); |
b9e4cf09 AJ |
155 | return -1; // not reachable |
156 | } | |
c8f4eac4 | 157 | |
54a063a2 TX |
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'."); | |
c8f4eac4 | 164 | self_destruct(); |
54a063a2 | 165 | } |
c8f4eac4 | 166 | |
167 | return i; | |
168 | } | |
169 | ||
54a063a2 TX |
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 | |
1454480a | 175 | * unless the limit parameter is set to false. |
54a063a2 | 176 | */ |
1454480a AJ |
177 | double |
178 | GetPercentage(bool limit) | |
54a063a2 | 179 | { |
223d18cd | 180 | char *token = ConfigParser::NextToken(); |
54a063a2 | 181 | |
f5bc7b15 | 182 | if (!token) { |
1454480a | 183 | debugs(3, DBG_CRITICAL, "FATAL: A percentage value is missing."); |
f5bc7b15 | 184 | self_destruct(); |
b9e4cf09 | 185 | return 0.0; // not reachable |
f5bc7b15 AJ |
186 | } |
187 | ||
54a063a2 TX |
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 | ||
223d18cd | 194 | int p = xatoi(token); |
54a063a2 | 195 | |
1454480a AJ |
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]."); | |
54a063a2 TX |
198 | self_destruct(); |
199 | } | |
200 | ||
1454480a | 201 | return static_cast<double>(p) / 100.0; |
54a063a2 TX |
202 | } |
203 | ||
f45dd259 | 204 | unsigned short |
0e656b69 | 205 | GetShort(void) |
206 | { | |
2eceb328 | 207 | char *token = ConfigParser::NextToken(); |
b9e4cf09 | 208 | if (!token) { |
0e656b69 | 209 | self_destruct(); |
b9e4cf09 AJ |
210 | return 0; // not reachable |
211 | } | |
0e656b69 | 212 | |
213 | return xatos(token); | |
214 | } | |
215 | ||
053b1f59 | 216 | bool |
217 | StringToInt(const char *s, int &result, const char **p, int base) | |
218 | { | |
219 | if (s) { | |
aee3523a | 220 | char *ptr = nullptr; |
053b1f59 | 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 | } | |
47f6e231 | 235 | |
236 | bool | |
237 | StringToInt64(const char *s, int64_t &result, const char **p, int base) | |
238 | { | |
239 | if (s) { | |
aee3523a | 240 | char *ptr = nullptr; |
47f6e231 | 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 | } | |
82b7abe3 AJ |
255 | |
256 | bool | |
b7ac5457 | 257 | GetHostWithPort(char *token, Ip::Address *ipa) |
82b7abe3 AJ |
258 | { |
259 | char *t; | |
260 | char *host; | |
261 | char *tmp; | |
262 | unsigned short port; | |
263 | ||
aee3523a | 264 | host = nullptr; |
82b7abe3 AJ |
265 | port = 0; |
266 | ||
82b7abe3 AJ |
267 | if (*token == '[') { |
268 | /* [host]:port */ | |
269 | host = token + 1; | |
270 | t = strchr(host, ']'); | |
271 | if (!t) | |
272 | return false; | |
f412b2d6 FC |
273 | *t = '\0'; |
274 | ++t; | |
82b7abe3 AJ |
275 | if (*t != ':') |
276 | return false; | |
277 | port = xatos(t + 1); | |
055421ee AJ |
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; | |
54a063a2 TX |
286 | } else if (strtol(token, &tmp, 10) && !*tmp) { |
287 | port = xatos(token); | |
055421ee AJ |
288 | } else { |
289 | host = token; | |
290 | port = 0; | |
291 | } | |
82b7abe3 | 292 | |
aee3523a | 293 | if (nullptr == host) |
4dd643d5 | 294 | ipa->setAnyAddr(); |
61beade2 | 295 | else if (ipa->GetHostByName(host)) /* do not use ipcache. Accept either FQDN or IPA. */ |
82b7abe3 AJ |
296 | (void) 0; |
297 | else | |
298 | return false; | |
299 | ||
300 | /* port MUST be set after the IPA lookup/conversion is performed. */ | |
4dd643d5 | 301 | ipa->port(port); |
82b7abe3 AJ |
302 | |
303 | return true; | |
304 | } | |
f53969cc | 305 |