]> git.ipfire.org Git - thirdparty/squid.git/blame - src/adaptation/ServiceConfig.cc
Bug 4446: undefined reference to 'libecap::Name::Name'
[thirdparty/squid.git] / src / adaptation / ServiceConfig.cc
CommitLineData
d81a31f1 1/*
ef57eb7b 2 * Copyright (C) 1996-2016 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 19Adaptation::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
25const char *
26Adaptation::ServiceConfig::methodStr() const
27{
28 return Adaptation::methodStr(method);
29}
30
31const char *
32Adaptation::ServiceConfig::vectPointStr() const
33{
34 return Adaptation::vectPointStr(point);
35}
36
37Adaptation::Method
38Adaptation::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
49Adaptation::VectPoint
50Adaptation::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
67bool
68Adaptation::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;
88df846b
CT
130 } else if (strcmp(name, "connection-encryption") == 0) {
131 bool encrypt;
132 grokked = grokBool(encrypt, name, value);
133 connectionEncryption.configure(encrypt);
1b091aec
CT
134 } else if (strncmp(name, "ssl", 3) == 0 || strncmp(name, "tls-", 4) == 0) {
135#if !USE_OPENSSL
2f32154e 136 debugs(3, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: adaptation option '" << name << "' requires --with-openssl. ICAP service option ignored.");
1b091aec
CT
137#else
138 // name prefix is "ssl" or "tls-"
139 std::string tmp = name + (name[0] == 's' ? 3 : 4);
140 tmp += "=";
141 tmp += value;
142 secure.parse(tmp.c_str());
1b091aec
CT
143 grokked = true;
144#endif
e1e90d26
AR
145 } else
146 grokked = grokExtension(name, value);
147
a22e6cd3
AR
148 if (!grokked)
149 return false;
150 }
151
2dba5b8e
CT
152 // set default on-overload value if needed
153 if (!onOverloadSet)
154 onOverload = bypass ? srvBypass : srvWait;
155
b05d749d
AJ
156 // disable the TLS NPN extension if encrypted.
157 // Squid advertises "http/1.1", which is wrong for ICAPS.
158 if (secure.encryptTransport)
159 secure.parse("no-npn");
160
c25c2836
CT
161 // is the service URI set?
162 if (!grokkedUri) {
e29ccb57 163 debugs(3, DBG_CRITICAL, cfg_filename << ':' << config_lineno << ": " <<
c25c2836 164 "No \"uri\" option in adaptation service definition");
a22e6cd3
AR
165 return false;
166 }
d81a31f1 167
a22e6cd3 168 debugs(3,5, cfg_filename << ':' << config_lineno << ": " <<
e1381638
AJ
169 "adaptation_service " << key << ' ' <<
170 methodStr() << "_" << vectPointStr() << ' ' <<
171 bypass << routing << ' ' <<
172 uri);
a22e6cd3
AR
173
174 return true;
175}
176
177bool
178Adaptation::ServiceConfig::grokUri(const char *value)
179{
d81a31f1 180 // TODO: find core code that parses URLs and extracts various parts
5957a4c9 181 // AYJ: most of this is duplicate of urlParse() in src/url.cc
d81a31f1 182
a22e6cd3 183 if (!value || !*value) {
fa84c01d 184 debugs(3, DBG_CRITICAL, HERE << cfg_filename << ':' << config_lineno << ": " <<
a22e6cd3
AR
185 "empty adaptation service URI");
186 return false;
187 }
188
189 uri = value;
190
d81a31f1
AR
191 // extract scheme and use it as the service_configConfig protocol
192 const char *schemeSuffix = "://";
a22e6cd3
AR
193 const String::size_type schemeEnd = uri.find(schemeSuffix);
194 if (schemeEnd != String::npos)
b2f458b7 195 protocol=uri.substr(0,schemeEnd);
826a1fed 196
26ac0430
AJ
197 debugs(3, 5, HERE << cfg_filename << ':' << config_lineno << ": " <<
198 "service protocol is " << protocol);
826a1fed
FC
199
200 if (protocol.size() == 0)
26ac0430 201 return false;
d81a31f1
AR
202
203 // skip scheme
c1945e7d 204 const char *s = uri.termedBuf() + protocol.size() + strlen(schemeSuffix);
d81a31f1
AR
205
206 const char *e;
207
208 bool have_port = false;
209
5957a4c9
AJ
210 int len = 0;
211 if (*s == '[') {
212 const char *t;
213 if ((t = strchr(s, ']')) == NULL)
214 return false;
215
742a021b 216 ++s;
5957a4c9
AJ
217 len = t - s;
218 if ((e = strchr(t, ':')) != NULL) {
219 have_port = true;
220 } else if ((e = strchr(t, '/')) != NULL) {
221 have_port = false;
222 } else {
223 return false;
224 }
792beadc 225 } else {
5957a4c9
AJ
226 if ((e = strchr(s, ':')) != NULL) {
227 have_port = true;
228 } else if ((e = strchr(s, '/')) != NULL) {
229 have_port = false;
230 } else {
231 return false;
232 }
233 len = e - s;
d81a31f1
AR
234 }
235
d81a31f1 236 host.limitInit(s, len);
1b091aec
CT
237#if USE_OPENSSL
238 if (secure.sslDomain.isEmpty())
239 secure.sslDomain.assign(host.rawBuf(), host.size());
240#endif
d81a31f1
AR
241 s = e;
242
26ac0430 243 port = -1;
d81a31f1 244 if (have_port) {
742a021b 245 ++s;
d81a31f1
AR
246
247 if ((e = strchr(s, '/')) != NULL) {
248 char *t;
26ac0430 249 const unsigned long p = strtoul(s, &t, 0);
d81a31f1 250
26ac0430
AJ
251 if (p > 65535) // port value is too high
252 return false;
d81a31f1
AR
253
254 port = static_cast<int>(p);
255
256 if (t != e) // extras after the port
257 return false;
258
259 s = e;
260
261 if (s[0] != '/')
262 return false;
263 }
264 }
265
266 // if no port, the caller may use service_configConfigs or supply the default if neeeded
267
742a021b 268 ++s;
d81a31f1
AR
269 e = strchr(s, '\0');
270 len = e - s;
271
272 if (len > 1024) {
fa84c01d 273 debugs(3, DBG_CRITICAL, HERE << cfg_filename << ':' << config_lineno << ": " <<
26ac0430 274 "long resource name (>1024), probably wrong");
d81a31f1
AR
275 }
276
277 resource.limitInit(s, len + 1);
a22e6cd3
AR
278 return true;
279}
280
a22e6cd3
AR
281bool
282Adaptation::ServiceConfig::grokBool(bool &var, const char *name, const char *value)
283{
284 if (!strcmp(value, "0") || !strcmp(value, "off"))
285 var = false;
e1381638 286 else if (!strcmp(value, "1") || !strcmp(value, "on"))
a22e6cd3
AR
287 var = true;
288 else {
fa84c01d 289 debugs(3, DBG_CRITICAL, HERE << cfg_filename << ':' << config_lineno << ": " <<
a22e6cd3
AR
290 "wrong value for boolean " << name << "; " <<
291 "'0', '1', 'on', or 'off' expected but got: " << value);
d81a31f1
AR
292 return false;
293 }
294
295 return true;
296}
e1e90d26 297
2dba5b8e
CT
298bool
299Adaptation::ServiceConfig::grokLong(long &var, const char *name, const char *value)
300{
301 char *bad = NULL;
302 const long p = strtol(value, &bad, 0);
303 if (p < 0 || bad == value) {
304 debugs(3, DBG_CRITICAL, "ERROR: " << cfg_filename << ':' <<
305 config_lineno << ": " << "wrong value for " << name << "; " <<
306 "a non-negative integer expected but got: " << value);
307 return false;
308 }
309 var = p;
310 return true;
311}
312
313bool
314Adaptation::ServiceConfig::grokOnOverload(SrvBehaviour &var, const char *value)
315{
316 if (strcmp(value, "block") == 0)
317 var = srvBlock;
318 else if (strcmp(value, "bypass") == 0)
319 var = srvBypass;
320 else if (strcmp(value, "wait") == 0)
321 var = srvWait;
322 else if (strcmp(value, "force") == 0)
323 var = srvForce;
324 else {
325 debugs(3, DBG_CRITICAL, "ERROR: " << cfg_filename << ':' <<
326 config_lineno << ": " << "wrong value for on-overload; " <<
327 "'block', 'bypass', 'wait' or 'force' expected but got: " << value);
328 return false;
329 }
330 return true;
331}
332
e1e90d26
AR
333bool
334Adaptation::ServiceConfig::grokExtension(const char *name, const char *value)
335{
336 // we do not accept extensions by default
6666da11
AR
337 debugs(3, DBG_CRITICAL, cfg_filename << ':' << config_lineno << ": " <<
338 "ERROR: unknown adaptation service option: " <<
339 name << '=' << value);
e1e90d26
AR
340 return false;
341}
f53969cc 342