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