]> git.ipfire.org Git - thirdparty/squid.git/blobdiff - src/adaptation/ServiceConfig.cc
Renamed squid.h to squid-old.h and config.h to squid.h
[thirdparty/squid.git] / src / adaptation / ServiceConfig.cc
index 64dd78696bb195c9a8cd60319c065faba7c262bc..ecffe2e19a37387538c0b98aa8df4fc4f7b5889a 100644 (file)
@@ -1,13 +1,17 @@
 /*
- * DEBUG: section XXX
+ * DEBUG: section 93    Adaptation
  */
 
-#include "squid.h"
+#include "squid-old.h"
 #include "ConfigParser.h"
 #include "adaptation/ServiceConfig.h"
+#include "ip/tools.h"
+#include <set>
 
 Adaptation::ServiceConfig::ServiceConfig():
-        port(-1), method(methodNone), point(pointNone), bypass(false)
+        port(-1), method(methodNone), point(pointNone),
+        bypass(false), maxConn(-1), onOverload(srvWait),
+        routing(false), ipv6(false)
 {}
 
 const char *
@@ -55,27 +59,113 @@ Adaptation::ServiceConfig::parseVectPoint(const char *service_configConfig) cons
 bool
 Adaptation::ServiceConfig::parse()
 {
-    char *method_point = NULL;
+    String method_point;
 
     ConfigParser::ParseString(&key);
     ConfigParser::ParseString(&method_point);
-    ConfigParser::ParseBool(&bypass);
-    ConfigParser::ParseString(&uri);
+    method = parseMethod(method_point.termedBuf());
+    point = parseVectPoint(method_point.termedBuf());
+
+    // reset optional parameters in case we are reconfiguring
+    bypass = routing = false;
+
+    // handle optional service name=value parameters
+    bool grokkedUri = false;
+    bool onOverloadSet = false;
+    std::set<std::string> options;
+
+    while (char *option = strtok(NULL, w_space)) {
+        const char *name = option;
+        const char *value = "";
+        if (strcmp(option, "0") == 0) { // backward compatibility
+            name = "bypass";
+            value = "off";
+            debugs(3, opt_parse_cfg_only?0:1, "UPGRADE: Please use 'bypass=off' option to disable service bypass");
+        }  else if (strcmp(option, "1") == 0) { // backward compatibility
+            name = "bypass";
+            value = "on";
+            debugs(3, opt_parse_cfg_only?0:1, "UPGRADE: Please use 'bypass=on' option to enable service bypass");
+        } else {
+            char *eq = strstr(option, "=");
+            const char *sffx = strstr(option, "://");
+            if (!eq || (sffx && sffx < eq)) { //no "=" or has the form "icap://host?arg=val"
+                name = "uri";
+                value = option;
+            }  else { // a normal name=value option
+                *eq = '\0'; // terminate option name
+                value = eq + 1; // skip '='
+            }
+        }
 
-    debugs(3, 5, HERE << cfg_filename << ':' << config_lineno << ": " <<
-           key << " " << method_point << " " << bypass);
+        // Check if option is set twice
+        if (options.find(name) != options.end()) {
+            debugs(3, DBG_CRITICAL, cfg_filename << ':' << config_lineno << ": " <<
+                   "Duplicate option \"" << name << "\" in adaptation service definition");
+            return false;
+        }
+        options.insert(name);
+
+        bool grokked = false;
+        if (strcmp(name, "bypass") == 0) {
+            grokked = grokBool(bypass, name, value);
+        } else if (strcmp(name, "routing") == 0)
+            grokked = grokBool(routing, name, value);
+        else if (strcmp(name, "uri") == 0)
+            grokked = grokkedUri = grokUri(value);
+        else if (strcmp(name, "ipv6") == 0) {
+            grokked = grokBool(ipv6, name, value);
+            if (grokked && ipv6 && !Ip::EnableIpv6)
+                debugs(3, DBG_IMPORTANT, "WARNING: IPv6 is disabled. ICAP service option ignored.");
+        } else if (strcmp(name, "max-conn") == 0)
+            grokked = grokLong(maxConn, name, value);
+        else if (strcmp(name, "on-overload") == 0) {
+            grokked = grokOnOverload(onOverload, value);
+            onOverloadSet = true;
+        } else
+            grokked = grokExtension(name, value);
+
+        if (!grokked)
+            return false;
+    }
 
-    method = parseMethod(method_point);
-    point = parseVectPoint(method_point);
+    // set default on-overload value if needed
+    if (!onOverloadSet)
+        onOverload = bypass ? srvBypass : srvWait;
 
-    debugs(3, 5, HERE << cfg_filename << ':' << config_lineno << ": " <<
-           "service_configConfig is " << methodStr() << "_" << vectPointStr());
+    // is the service URI set?
+    if (!grokkedUri) {
+        debugs(3, DBG_CRITICAL, cfg_filename << ':' << config_lineno << ": " <<
+               "No \"uri\" option in adaptation service definition");
+        return false;
+    }
+
+    debugs(3,5, cfg_filename << ':' << config_lineno << ": " <<
+           "adaptation_service " << key << ' ' <<
+           methodStr() << "_" << vectPointStr() << ' ' <<
+           bypass << routing << ' ' <<
+           uri);
+
+    return true;
+}
 
+bool
+Adaptation::ServiceConfig::grokUri(const char *value)
+{
     // TODO: find core code that parses URLs and extracts various parts
+    // AYJ: most of this is duplicate of urlParse() in src/url.cc
+
+    if (!value || !*value) {
+        debugs(3, 0, HERE << cfg_filename << ':' << config_lineno << ": " <<
+               "empty adaptation service URI");
+        return false;
+    }
+
+    uri = value;
 
     // extract scheme and use it as the service_configConfig protocol
     const char *schemeSuffix = "://";
-    if (const String::size_type schemeEnd=uri.find(schemeSuffix))
+    const String::size_type schemeEnd = uri.find(schemeSuffix);
+    if (schemeEnd != String::npos)
         protocol=uri.substr(0,schemeEnd);
 
     debugs(3, 5, HERE << cfg_filename << ':' << config_lineno << ": " <<
@@ -91,15 +181,32 @@ Adaptation::ServiceConfig::parse()
 
     bool have_port = false;
 
-    if ((e = strchr(s, ':')) != NULL) {
-        have_port = true;
-    } else if ((e = strchr(s, '/')) != NULL) {
-        have_port = false;
+    int len = 0;
+    if (*s == '[') {
+        const char *t;
+        if ((t = strchr(s, ']')) == NULL)
+            return false;
+
+        s++;
+        len = t - s;
+        if ((e = strchr(t, ':')) != NULL) {
+            have_port = true;
+        } else if ((e = strchr(t, '/')) != NULL) {
+            have_port = false;
+        } else {
+            return false;
+        }
     } else {
-        return false;
+        if ((e = strchr(s, ':')) != NULL) {
+            have_port = true;
+        } else if ((e = strchr(s, '/')) != NULL) {
+            have_port = false;
+        } else {
+            return false;
+        }
+        len = e - s;
     }
 
-    int len = e - s;
     host.limitInit(s, len);
     s = e;
 
@@ -138,12 +245,68 @@ Adaptation::ServiceConfig::parse()
     }
 
     resource.limitInit(s, len + 1);
+    return true;
+}
+
 
-    if ((bypass != 0) && (bypass != 1)) {
+bool
+Adaptation::ServiceConfig::grokBool(bool &var, const char *name, const char *value)
+{
+    if (!strcmp(value, "0") || !strcmp(value, "off"))
+        var = false;
+    else if (!strcmp(value, "1") || !strcmp(value, "on"))
+        var = true;
+    else {
         debugs(3, 0, HERE << cfg_filename << ':' << config_lineno << ": " <<
-               "wrong bypass value; 0 or 1 expected: " << bypass);
+               "wrong value for boolean " << name << "; " <<
+               "'0', '1', 'on', or 'off' expected but got: " << value);
         return false;
     }
 
     return true;
 }
+
+bool
+Adaptation::ServiceConfig::grokLong(long &var, const char *name, const char *value)
+{
+    char *bad = NULL;
+    const long p = strtol(value, &bad, 0);
+    if (p < 0 || bad == value) {
+        debugs(3, DBG_CRITICAL, "ERROR: " << cfg_filename << ':' <<
+               config_lineno << ": " << "wrong value for " << name << "; " <<
+               "a non-negative integer expected but got: " << value);
+        return false;
+    }
+    var = p;
+    return true;
+}
+
+bool
+Adaptation::ServiceConfig::grokOnOverload(SrvBehaviour &var, const char *value)
+{
+    if (strcmp(value, "block") == 0)
+        var = srvBlock;
+    else if (strcmp(value, "bypass") == 0)
+        var = srvBypass;
+    else if (strcmp(value, "wait") == 0)
+        var = srvWait;
+    else if (strcmp(value, "force") == 0)
+        var = srvForce;
+    else {
+        debugs(3, DBG_CRITICAL, "ERROR: " << cfg_filename << ':' <<
+               config_lineno << ": " << "wrong value for on-overload; " <<
+               "'block', 'bypass', 'wait' or 'force' expected but got: " << value);
+        return false;
+    }
+    return true;
+}
+
+bool
+Adaptation::ServiceConfig::grokExtension(const char *name, const char *value)
+{
+    // we do not accept extensions by default
+    debugs(3, DBG_CRITICAL, cfg_filename << ':' << config_lineno << ": " <<
+           "ERROR: unknown adaptation service option: " <<
+           name << '=' << value);
+    return false;
+}