]> git.ipfire.org Git - thirdparty/squid.git/blob - src/Parsing.cc
cache_log_message directive (#775)
[thirdparty/squid.git] / src / Parsing.cc
1 /*
2 * Copyright (C) 1996-2021 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.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 = NULL;
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 = NULL;
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 = 0;
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 = 0;
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 = NULL;
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 (NULL == 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