ServiceConfig.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2023 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 93 Adaptation */
10 
11 #include "squid.h"
13 #include "cache_cf.h"
14 #include "ConfigParser.h"
15 #include "debug/Stream.h"
16 #include "globals.h"
17 #include "ip/tools.h"
18 #include <set>
19 
21  port(-1), method(methodNone), point(pointNone),
22  bypass(false), maxConn(-1), onOverload(srvWait),
23  routing(false), ipv6(false)
24 {}
25 
26 const char *
28 {
29  return Adaptation::methodStr(method);
30 }
31 
32 const char *
34 {
35  return Adaptation::vectPointStr(point);
36 }
37 
40 {
41  if (!strncasecmp(str, "REQMOD", 6))
43 
44  if (!strncasecmp(str, "RESPMOD", 7))
46 
48 }
49 
51 Adaptation::ServiceConfig::parseVectPoint(const char *service_configConfig) const
52 {
53  const char *t = service_configConfig;
54  const char *q = strchr(t, '_');
55 
56  if (q)
57  t = q + 1;
58 
59  if (!strcmp(t, "precache"))
61 
62  if (!strcmp(t, "postcache"))
64 
65  return Adaptation::pointNone;
66 }
67 
68 bool
70 {
72  String method_point = ConfigParser::NextToken();
73  if (!method_point.size()) {
74  debugs(3, DBG_CRITICAL, "ERROR: " << cfg_filename << ':' << config_lineno << ": " <<
75  "Missing vectoring point in adaptation service definition");
76  return false;
77  }
78 
79  method = parseMethod(method_point.termedBuf());
80  point = parseVectPoint(method_point.termedBuf());
81  if (method == Adaptation::methodNone && point == Adaptation::pointNone) {
82  debugs(3, DBG_CRITICAL, "ERROR: " << cfg_filename << ':' << config_lineno << ": " <<
83  "Unknown vectoring point '" << method_point << "' in adaptation service definition");
84  return false;
85  }
86 
87  // reset optional parameters in case we are reconfiguring
88  bypass = routing = false;
89 
90  // handle optional service name=value parameters
91  bool grokkedUri = false;
92  bool onOverloadSet = false;
93  std::set<std::string> options;
94 
95  while (char *option = ConfigParser::NextToken()) {
96  const char *name = option;
97  const char *value = "";
98  if (strcmp(option, "0") == 0) { // backward compatibility
99  name = "bypass";
100  value = "off";
101  debugs(3, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: UPGRADE: Please use 'bypass=off' option to disable service bypass");
102  } else if (strcmp(option, "1") == 0) { // backward compatibility
103  name = "bypass";
104  value = "on";
105  debugs(3, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: UPGRADE: Please use 'bypass=on' option to enable service bypass");
106  } else {
107  char *eq = strstr(option, "=");
108  const char *sffx = strstr(option, "://");
109  if (!eq || (sffx && sffx < eq)) { //no "=" or has the form "icap://host?arg=val"
110  name = "uri";
111  value = option;
112  } else { // a normal name=value option
113  *eq = '\0'; // terminate option name
114  value = eq + 1; // skip '='
115  }
116  }
117 
118  // Check if option is set twice
119  if (options.find(name) != options.end()) {
120  debugs(3, DBG_CRITICAL, "ERROR: " << cfg_filename << ':' << config_lineno << ": " <<
121  "Duplicate option \"" << name << "\" in adaptation service definition");
122  return false;
123  }
124  options.insert(name);
125 
126  bool grokked = false;
127  if (strcmp(name, "bypass") == 0) {
128  grokked = grokBool(bypass, name, value);
129  } else if (strcmp(name, "routing") == 0)
130  grokked = grokBool(routing, name, value);
131  else if (strcmp(name, "uri") == 0)
132  grokked = grokkedUri = grokUri(value);
133  else if (strcmp(name, "ipv6") == 0) {
134  grokked = grokBool(ipv6, name, value);
135  if (grokked && ipv6 && !Ip::EnableIpv6)
136  debugs(3, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: IPv6 is disabled. ICAP service option ignored.");
137  } else if (strcmp(name, "max-conn") == 0)
138  grokked = grokLong(maxConn, name, value);
139  else if (strcmp(name, "on-overload") == 0) {
140  grokked = grokOnOverload(onOverload, value);
141  onOverloadSet = true;
142  } else if (strcmp(name, "connection-encryption") == 0) {
143  bool encrypt = false;
144  grokked = grokBool(encrypt, name, value);
145  connectionEncryption.configure(encrypt);
146  } else if (strncmp(name, "ssl", 3) == 0 || strncmp(name, "tls-", 4) == 0) {
147 #if !USE_OPENSSL
148  debugs(3, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: adaptation option '" << name << "' requires --with-openssl. ICAP service option ignored.");
149 #else
150  // name prefix is "ssl" or "tls-"
151  std::string tmp = name + (name[0] == 's' ? 3 : 4);
152  tmp += "=";
153  tmp += value;
154  secure.parse(tmp.c_str());
155  grokked = true;
156 #endif
157  } else
158  grokked = grokExtension(name, value);
159 
160  if (!grokked)
161  return false;
162  }
163 
164  // set default on-overload value if needed
165  if (!onOverloadSet)
166  onOverload = bypass ? srvBypass : srvWait;
167 
168  // disable the TLS NPN extension if encrypted.
169  // Squid advertises "http/1.1", which is wrong for ICAPS.
170  if (secure.encryptTransport)
171  secure.parse("no-npn");
172 
173  // is the service URI set?
174  if (!grokkedUri) {
175  debugs(3, DBG_CRITICAL, "ERROR: " << cfg_filename << ':' << config_lineno << ": " <<
176  "No \"uri\" option in adaptation service definition");
177  return false;
178  }
179 
180  debugs(3,5, cfg_filename << ':' << config_lineno << ": " <<
181  "adaptation_service " << key << ' ' <<
182  methodStr() << "_" << vectPointStr() << ' ' <<
183  bypass << routing << ' ' <<
184  uri);
185 
186  return true;
187 }
188 
189 bool
191 {
192  // TODO: find core code that parses URLs and extracts various parts
193  // AYJ: most of this is duplicate of AnyP::Uri::parse()
194 
195  if (!value || !*value) {
196  debugs(3, DBG_CRITICAL, cfg_filename << ':' << config_lineno << ": " <<
197  "empty adaptation service URI");
198  return false;
199  }
200 
201  uri = value;
202 
203  // extract scheme and use it as the service_configConfig protocol
204  const char *schemeSuffix = "://";
205  const String::size_type schemeEnd = uri.find(schemeSuffix);
206  if (schemeEnd != String::npos)
207  protocol=uri.substr(0,schemeEnd);
208 
209  debugs(3, 5, cfg_filename << ':' << config_lineno << ": " <<
210  "service protocol is " << protocol);
211 
212  if (protocol.size() == 0)
213  return false;
214 
215  // skip scheme
216  const char *s = uri.termedBuf() + protocol.size() + strlen(schemeSuffix);
217 
218  const char *e;
219 
220  bool have_port = false;
221 
222  int len = 0;
223  if (*s == '[') {
224  const char *t;
225  if ((t = strchr(s, ']')) == nullptr)
226  return false;
227 
228  ++s;
229  len = t - s;
230  if ((e = strchr(t, ':')) != nullptr) {
231  have_port = true;
232  } else if ((e = strchr(t, '/')) != nullptr) {
233  have_port = false;
234  } else {
235  return false;
236  }
237  } else {
238  if ((e = strchr(s, ':')) != nullptr) {
239  have_port = true;
240  } else if ((e = strchr(s, '/')) != nullptr) {
241  have_port = false;
242  } else {
243  return false;
244  }
245  len = e - s;
246  }
247 
248  host.assign(s, len);
249 #if USE_OPENSSL
250  if (secure.sslDomain.isEmpty())
251  secure.sslDomain.assign(host.rawBuf(), host.size());
252 #endif
253  s = e;
254 
255  port = -1;
256  if (have_port) {
257  ++s;
258 
259  if ((e = strchr(s, '/')) != nullptr) {
260  char *t;
261  const unsigned long p = strtoul(s, &t, 0);
262 
263  if (p > 65535) // port value is too high
264  return false;
265 
266  port = static_cast<int>(p);
267 
268  if (t != e) // extras after the port
269  return false;
270 
271  s = e;
272 
273  if (s[0] != '/')
274  return false;
275  }
276  }
277 
278  // if no port, the caller may use service_configConfigs or supply the default if needed
279 
280  ++s;
281  e = strchr(s, '\0');
282  len = e - s;
283 
284  if (len > 1024) {
285  debugs(3, DBG_CRITICAL, cfg_filename << ':' << config_lineno << ": " <<
286  "long resource name (>1024), probably wrong");
287  }
288 
289  resource.assign(s, len + 1);
290  return true;
291 }
292 
293 bool
294 Adaptation::ServiceConfig::grokBool(bool &var, const char *name, const char *value)
295 {
296  if (!strcmp(value, "0") || !strcmp(value, "off"))
297  var = false;
298  else if (!strcmp(value, "1") || !strcmp(value, "on"))
299  var = true;
300  else {
301  debugs(3, DBG_CRITICAL, cfg_filename << ':' << config_lineno << ": " <<
302  "wrong value for boolean " << name << "; " <<
303  "'0', '1', 'on', or 'off' expected but got: " << value);
304  return false;
305  }
306 
307  return true;
308 }
309 
310 bool
311 Adaptation::ServiceConfig::grokLong(long &var, const char *name, const char *value)
312 {
313  char *bad = nullptr;
314  const long p = strtol(value, &bad, 0);
315  if (p < 0 || bad == value) {
316  debugs(3, DBG_CRITICAL, "ERROR: " << cfg_filename << ':' <<
317  config_lineno << ": " << "wrong value for " << name << "; " <<
318  "a non-negative integer expected but got: " << value);
319  return false;
320  }
321  var = p;
322  return true;
323 }
324 
325 bool
327 {
328  if (strcmp(value, "block") == 0)
329  var = srvBlock;
330  else if (strcmp(value, "bypass") == 0)
331  var = srvBypass;
332  else if (strcmp(value, "wait") == 0)
333  var = srvWait;
334  else if (strcmp(value, "force") == 0)
335  var = srvForce;
336  else {
337  debugs(3, DBG_CRITICAL, "ERROR: " << cfg_filename << ':' <<
338  config_lineno << ": " << "wrong value for on-overload; " <<
339  "'block', 'bypass', 'wait' or 'force' expected but got: " << value);
340  return false;
341  }
342  return true;
343 }
344 
345 bool
346 Adaptation::ServiceConfig::grokExtension(const char *name, const char *value)
347 {
348  // we do not accept extensions by default
349  debugs(3, DBG_CRITICAL, "ERROR: " << cfg_filename << ':' << config_lineno << ": " <<
350  "ERROR: unknown adaptation service option: " <<
351  name << '=' << value);
352  return false;
353 }
354 
bool grokUri(const char *value)
@ srvBlock
Definition: Elements.h:19
#define DBG_CRITICAL
Definition: Stream.h:37
virtual bool grokExtension(const char *name, const char *value)
handle name=value configuration option with name unknown to Squid
bool grokLong(long &var, const char *name, const char *value)
const char * vectPointStr(VectPoint)
Definition: Elements.cc:39
static int port
Definition: ldap_backend.cc:70
const static size_type npos
Definition: SquidString.h:39
#define DBG_PARSE_NOTE(x)
Definition: Stream.h:42
@ srvBypass
Definition: Elements.h:19
@ pointPostCache
Definition: Elements.h:18
const char * cfg_filename
Definition: cache_cf.cc:271
@ methodNone
Definition: Elements.h:17
const char * vectPointStr() const
int config_lineno
Definition: cache_cf.cc:272
const char * methodStr(Method)
Definition: Elements.cc:15
@ srvForce
Definition: Elements.h:19
void encrypt(char *nachr, int decr)
Definition: encrypt.c:188
static char * NextToken()
bool grokOnOverload(SrvBehaviour &var, const char *value)
handle on-overload configuration option
bool grokBool(bool &var, const char *name, const char *value)
interpret parsed values
size_t size_type
Definition: SquidString.h:38
@ pointPreCache
Definition: Elements.h:18
const char * termedBuf() const
Definition: SquidString.h:92
@ methodRespmod
Definition: Elements.h:17
size_type size() const
Definition: SquidString.h:73
@ pointNone
Definition: Elements.h:18
Method parseMethod(const char *buf) const
const char * methodStr() const
#define DBG_IMPORTANT
Definition: Stream.h:38
@ methodReqmod
Definition: Elements.h:17
VectPoint parseVectPoint(const char *buf) const
int EnableIpv6
Whether IPv6 is supported and type of support.
Definition: tools.h:25
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:192

 

Introduction

Documentation

Support

Miscellaneous