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