]>
Commit | Line | Data |
---|---|---|
d81a31f1 | 1 | /* |
bde978a6 | 2 | * Copyright (C) 1996-2015 The Squid Software Foundation and contributors |
bbc27441 AJ |
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. | |
d81a31f1 AR |
7 | */ |
8 | ||
bbc27441 AJ |
9 | /* DEBUG: section 93 Adaptation */ |
10 | ||
582c2af2 | 11 | #include "squid.h" |
d81a31f1 | 12 | #include "adaptation/ServiceConfig.h" |
582c2af2 FC |
13 | #include "ConfigParser.h" |
14 | #include "Debug.h" | |
15 | #include "globals.h" | |
3496b53a | 16 | #include "ip/tools.h" |
c25c2836 | 17 | #include <set> |
d81a31f1 | 18 | |
26ac0430 | 19 | Adaptation::ServiceConfig::ServiceConfig(): |
f53969cc SM |
20 | port(-1), method(methodNone), point(pointNone), |
21 | bypass(false), maxConn(-1), onOverload(srvWait), | |
22 | routing(false), ipv6(false) | |
d81a31f1 AR |
23 | {} |
24 | ||
25 | const char * | |
26 | Adaptation::ServiceConfig::methodStr() const | |
27 | { | |
28 | return Adaptation::methodStr(method); | |
29 | } | |
30 | ||
31 | const char * | |
32 | Adaptation::ServiceConfig::vectPointStr() const | |
33 | { | |
34 | return Adaptation::vectPointStr(point); | |
35 | } | |
36 | ||
37 | Adaptation::Method | |
38 | Adaptation::ServiceConfig::parseMethod(const char *str) const | |
39 | { | |
40 | if (!strncasecmp(str, "REQMOD", 6)) | |
41 | return Adaptation::methodReqmod; | |
42 | ||
43 | if (!strncasecmp(str, "RESPMOD", 7)) | |
44 | return Adaptation::methodRespmod; | |
45 | ||
46 | return Adaptation::methodNone; | |
47 | } | |
48 | ||
49 | Adaptation::VectPoint | |
50 | Adaptation::ServiceConfig::parseVectPoint(const char *service_configConfig) const | |
51 | { | |
52 | const char *t = service_configConfig; | |
53 | const char *q = strchr(t, '_'); | |
54 | ||
55 | if (q) | |
56 | t = q + 1; | |
57 | ||
a37d6070 | 58 | if (!strcmp(t, "precache")) |
d81a31f1 AR |
59 | return Adaptation::pointPreCache; |
60 | ||
a37d6070 | 61 | if (!strcmp(t, "postcache")) |
d81a31f1 AR |
62 | return Adaptation::pointPostCache; |
63 | ||
64 | return Adaptation::pointNone; | |
65 | } | |
66 | ||
67 | bool | |
68 | Adaptation::ServiceConfig::parse() | |
69 | { | |
2eceb328 CT |
70 | key = ConfigParser::NextToken(); |
71 | String method_point = ConfigParser::NextToken(); | |
29bf4910 CT |
72 | method = parseMethod(method_point.termedBuf()); |
73 | point = parseVectPoint(method_point.termedBuf()); | |
d81a31f1 | 74 | |
a22e6cd3 AR |
75 | // reset optional parameters in case we are reconfiguring |
76 | bypass = routing = false; | |
77 | ||
78 | // handle optional service name=value parameters | |
8e2fb579 | 79 | bool grokkedUri = false; |
2dba5b8e | 80 | bool onOverloadSet = false; |
c25c2836 | 81 | std::set<std::string> options; |
e29ccb57 | 82 | |
2eceb328 | 83 | while (char *option = ConfigParser::NextToken()) { |
c25c2836 CT |
84 | const char *name = option; |
85 | const char *value = ""; | |
a22e6cd3 | 86 | if (strcmp(option, "0") == 0) { // backward compatibility |
c25c2836 CT |
87 | name = "bypass"; |
88 | value = "off"; | |
aa7e2b35 | 89 | debugs(3, DBG_PARSE_NOTE(DBG_IMPORTANT), "UPGRADE: Please use 'bypass=off' option to disable service bypass"); |
c25c2836 CT |
90 | } else if (strcmp(option, "1") == 0) { // backward compatibility |
91 | name = "bypass"; | |
92 | value = "on"; | |
aa7e2b35 | 93 | debugs(3, DBG_PARSE_NOTE(DBG_IMPORTANT), "UPGRADE: Please use 'bypass=on' option to enable service bypass"); |
c25c2836 CT |
94 | } else { |
95 | char *eq = strstr(option, "="); | |
96 | const char *sffx = strstr(option, "://"); | |
97 | if (!eq || (sffx && sffx < eq)) { //no "=" or has the form "icap://host?arg=val" | |
98 | name = "uri"; | |
99 | value = option; | |
100 | } else { // a normal name=value option | |
101 | *eq = '\0'; // terminate option name | |
102 | value = eq + 1; // skip '=' | |
103 | } | |
a22e6cd3 AR |
104 | } |
105 | ||
c25c2836 CT |
106 | // Check if option is set twice |
107 | if (options.find(name) != options.end()) { | |
e29ccb57 | 108 | debugs(3, DBG_CRITICAL, cfg_filename << ':' << config_lineno << ": " << |
c25c2836 CT |
109 | "Duplicate option \"" << name << "\" in adaptation service definition"); |
110 | return false; | |
a22e6cd3 | 111 | } |
c25c2836 | 112 | options.insert(name); |
a22e6cd3 | 113 | |
a22e6cd3 | 114 | bool grokked = false; |
2dba5b8e | 115 | if (strcmp(name, "bypass") == 0) { |
a22e6cd3 | 116 | grokked = grokBool(bypass, name, value); |
2dba5b8e | 117 | } else if (strcmp(name, "routing") == 0) |
a22e6cd3 | 118 | grokked = grokBool(routing, name, value); |
8e2fb579 AR |
119 | else if (strcmp(name, "uri") == 0) |
120 | grokked = grokkedUri = grokUri(value); | |
3496b53a | 121 | else if (strcmp(name, "ipv6") == 0) { |
e6713f4e | 122 | grokked = grokBool(ipv6, name, value); |
3496b53a | 123 | if (grokked && ipv6 && !Ip::EnableIpv6) |
aa7e2b35 | 124 | debugs(3, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: IPv6 is disabled. ICAP service option ignored."); |
2dba5b8e CT |
125 | } else if (strcmp(name, "max-conn") == 0) |
126 | grokked = grokLong(maxConn, name, value); | |
127 | else if (strcmp(name, "on-overload") == 0) { | |
128 | grokked = grokOnOverload(onOverload, value); | |
129 | onOverloadSet = true; | |
1b091aec CT |
130 | } else if (strncmp(name, "ssl", 3) == 0 || strncmp(name, "tls-", 4) == 0) { |
131 | #if !USE_OPENSSL | |
2f32154e | 132 | debugs(3, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: adaptation option '" << name << "' requires --with-openssl. ICAP service option ignored."); |
1b091aec CT |
133 | #else |
134 | // name prefix is "ssl" or "tls-" | |
135 | std::string tmp = name + (name[0] == 's' ? 3 : 4); | |
136 | tmp += "="; | |
137 | tmp += value; | |
138 | secure.parse(tmp.c_str()); | |
1b091aec CT |
139 | grokked = true; |
140 | #endif | |
e1e90d26 AR |
141 | } else |
142 | grokked = grokExtension(name, value); | |
143 | ||
a22e6cd3 AR |
144 | if (!grokked) |
145 | return false; | |
146 | } | |
147 | ||
2dba5b8e CT |
148 | // set default on-overload value if needed |
149 | if (!onOverloadSet) | |
150 | onOverload = bypass ? srvBypass : srvWait; | |
151 | ||
c25c2836 CT |
152 | // is the service URI set? |
153 | if (!grokkedUri) { | |
e29ccb57 | 154 | debugs(3, DBG_CRITICAL, cfg_filename << ':' << config_lineno << ": " << |
c25c2836 | 155 | "No \"uri\" option in adaptation service definition"); |
a22e6cd3 AR |
156 | return false; |
157 | } | |
d81a31f1 | 158 | |
a22e6cd3 | 159 | debugs(3,5, cfg_filename << ':' << config_lineno << ": " << |
e1381638 AJ |
160 | "adaptation_service " << key << ' ' << |
161 | methodStr() << "_" << vectPointStr() << ' ' << | |
162 | bypass << routing << ' ' << | |
163 | uri); | |
a22e6cd3 AR |
164 | |
165 | return true; | |
166 | } | |
167 | ||
168 | bool | |
169 | Adaptation::ServiceConfig::grokUri(const char *value) | |
170 | { | |
d81a31f1 | 171 | // TODO: find core code that parses URLs and extracts various parts |
5957a4c9 | 172 | // AYJ: most of this is duplicate of urlParse() in src/url.cc |
d81a31f1 | 173 | |
a22e6cd3 | 174 | if (!value || !*value) { |
fa84c01d | 175 | debugs(3, DBG_CRITICAL, HERE << cfg_filename << ':' << config_lineno << ": " << |
a22e6cd3 AR |
176 | "empty adaptation service URI"); |
177 | return false; | |
178 | } | |
179 | ||
180 | uri = value; | |
181 | ||
d81a31f1 AR |
182 | // extract scheme and use it as the service_configConfig protocol |
183 | const char *schemeSuffix = "://"; | |
a22e6cd3 AR |
184 | const String::size_type schemeEnd = uri.find(schemeSuffix); |
185 | if (schemeEnd != String::npos) | |
b2f458b7 | 186 | protocol=uri.substr(0,schemeEnd); |
826a1fed | 187 | |
26ac0430 AJ |
188 | debugs(3, 5, HERE << cfg_filename << ':' << config_lineno << ": " << |
189 | "service protocol is " << protocol); | |
826a1fed FC |
190 | |
191 | if (protocol.size() == 0) | |
26ac0430 | 192 | return false; |
d81a31f1 AR |
193 | |
194 | // skip scheme | |
c1945e7d | 195 | const char *s = uri.termedBuf() + protocol.size() + strlen(schemeSuffix); |
d81a31f1 AR |
196 | |
197 | const char *e; | |
198 | ||
199 | bool have_port = false; | |
200 | ||
5957a4c9 AJ |
201 | int len = 0; |
202 | if (*s == '[') { | |
203 | const char *t; | |
204 | if ((t = strchr(s, ']')) == NULL) | |
205 | return false; | |
206 | ||
742a021b | 207 | ++s; |
5957a4c9 AJ |
208 | len = t - s; |
209 | if ((e = strchr(t, ':')) != NULL) { | |
210 | have_port = true; | |
211 | } else if ((e = strchr(t, '/')) != NULL) { | |
212 | have_port = false; | |
213 | } else { | |
214 | return false; | |
215 | } | |
792beadc | 216 | } else { |
5957a4c9 AJ |
217 | if ((e = strchr(s, ':')) != NULL) { |
218 | have_port = true; | |
219 | } else if ((e = strchr(s, '/')) != NULL) { | |
220 | have_port = false; | |
221 | } else { | |
222 | return false; | |
223 | } | |
224 | len = e - s; | |
d81a31f1 AR |
225 | } |
226 | ||
d81a31f1 | 227 | host.limitInit(s, len); |
1b091aec CT |
228 | #if USE_OPENSSL |
229 | if (secure.sslDomain.isEmpty()) | |
230 | secure.sslDomain.assign(host.rawBuf(), host.size()); | |
231 | #endif | |
d81a31f1 AR |
232 | s = e; |
233 | ||
26ac0430 | 234 | port = -1; |
d81a31f1 | 235 | if (have_port) { |
742a021b | 236 | ++s; |
d81a31f1 AR |
237 | |
238 | if ((e = strchr(s, '/')) != NULL) { | |
239 | char *t; | |
26ac0430 | 240 | const unsigned long p = strtoul(s, &t, 0); |
d81a31f1 | 241 | |
26ac0430 AJ |
242 | if (p > 65535) // port value is too high |
243 | return false; | |
d81a31f1 AR |
244 | |
245 | port = static_cast<int>(p); | |
246 | ||
247 | if (t != e) // extras after the port | |
248 | return false; | |
249 | ||
250 | s = e; | |
251 | ||
252 | if (s[0] != '/') | |
253 | return false; | |
254 | } | |
255 | } | |
256 | ||
257 | // if no port, the caller may use service_configConfigs or supply the default if neeeded | |
258 | ||
742a021b | 259 | ++s; |
d81a31f1 AR |
260 | e = strchr(s, '\0'); |
261 | len = e - s; | |
262 | ||
263 | if (len > 1024) { | |
fa84c01d | 264 | debugs(3, DBG_CRITICAL, HERE << cfg_filename << ':' << config_lineno << ": " << |
26ac0430 | 265 | "long resource name (>1024), probably wrong"); |
d81a31f1 AR |
266 | } |
267 | ||
268 | resource.limitInit(s, len + 1); | |
a22e6cd3 AR |
269 | return true; |
270 | } | |
271 | ||
a22e6cd3 AR |
272 | bool |
273 | Adaptation::ServiceConfig::grokBool(bool &var, const char *name, const char *value) | |
274 | { | |
275 | if (!strcmp(value, "0") || !strcmp(value, "off")) | |
276 | var = false; | |
e1381638 | 277 | else if (!strcmp(value, "1") || !strcmp(value, "on")) |
a22e6cd3 AR |
278 | var = true; |
279 | else { | |
fa84c01d | 280 | debugs(3, DBG_CRITICAL, HERE << cfg_filename << ':' << config_lineno << ": " << |
a22e6cd3 AR |
281 | "wrong value for boolean " << name << "; " << |
282 | "'0', '1', 'on', or 'off' expected but got: " << value); | |
d81a31f1 AR |
283 | return false; |
284 | } | |
285 | ||
286 | return true; | |
287 | } | |
e1e90d26 | 288 | |
2dba5b8e CT |
289 | bool |
290 | Adaptation::ServiceConfig::grokLong(long &var, const char *name, const char *value) | |
291 | { | |
292 | char *bad = NULL; | |
293 | const long p = strtol(value, &bad, 0); | |
294 | if (p < 0 || bad == value) { | |
295 | debugs(3, DBG_CRITICAL, "ERROR: " << cfg_filename << ':' << | |
296 | config_lineno << ": " << "wrong value for " << name << "; " << | |
297 | "a non-negative integer expected but got: " << value); | |
298 | return false; | |
299 | } | |
300 | var = p; | |
301 | return true; | |
302 | } | |
303 | ||
304 | bool | |
305 | Adaptation::ServiceConfig::grokOnOverload(SrvBehaviour &var, const char *value) | |
306 | { | |
307 | if (strcmp(value, "block") == 0) | |
308 | var = srvBlock; | |
309 | else if (strcmp(value, "bypass") == 0) | |
310 | var = srvBypass; | |
311 | else if (strcmp(value, "wait") == 0) | |
312 | var = srvWait; | |
313 | else if (strcmp(value, "force") == 0) | |
314 | var = srvForce; | |
315 | else { | |
316 | debugs(3, DBG_CRITICAL, "ERROR: " << cfg_filename << ':' << | |
317 | config_lineno << ": " << "wrong value for on-overload; " << | |
318 | "'block', 'bypass', 'wait' or 'force' expected but got: " << value); | |
319 | return false; | |
320 | } | |
321 | return true; | |
322 | } | |
323 | ||
e1e90d26 AR |
324 | bool |
325 | Adaptation::ServiceConfig::grokExtension(const char *name, const char *value) | |
326 | { | |
327 | // we do not accept extensions by default | |
6666da11 AR |
328 | debugs(3, DBG_CRITICAL, cfg_filename << ':' << config_lineno << ": " << |
329 | "ERROR: unknown adaptation service option: " << | |
330 | name << '=' << value); | |
e1e90d26 AR |
331 | return false; |
332 | } | |
f53969cc | 333 |