On 10/06/2011 12:51 AM, Amos Jeffries wrote:
On Wed, 05 Oct 2011 11:32:39 +0300, Tsantilas Christos wrote:
Currently using URIs which include "=" is not supported by
ecap_service/icap_service configuration parameters. Also the squid.conf
documentation about ecap_service is outdated.

This patch
- Fixes the [e|i]cap_service line parser to allow URIs with "="
- Changes the [e|i]cap_service configuration parameter to use the
following syntax:
ecap_service id vectoring_point uri [name=value ...]
- Check for duplicated options
- Fixes the related documentation
- Also the older [e|i]cap_service syntax forms are supported:
ecap_service id vectoring_point [1|0] uri
ecap_service id vectoring_point [name=value ...] uri
- The "uri" options is not documented but supported.

This is a Measurement Factory project.


Since you alter the way the 0/1 backward compatibility is parsed please
take the opportunity to add a debugs() "UPGRADE: " message at level
"(opt_parse_cfg_only?0:1)" to the cases. Stating that option format has
changed and what it should be upgraded to.

Done


In the duplicate warning message:
- s/Douplicate/Duplicate/
- s/ataptation/adaptation/
done


Amos



Bug 3349: Bad support for adaptation service URIs with '=' 

Currently using URIs  which  include "=" is not supported by 
ecap_service/icap_service configuration parameters. Also the squid.conf
documentation about ecap_service is outdated.

This patch 
- Fixes the [e|i]cap_service line parser to allow URIs with "="
- Changes the [e|i]cap_service configuration parameter to use the following syntax:
   ecap_service id vectoring_point uri [name=value ...]
- Check for duplicated options
- Fixes the related documentation 
- Also the older [e|i]cap_service syntax forms are supported:
   ecap_service id vectoring_point [1|0] uri 
   ecap_service id vectoring_point [name=value ...] uri 
- The "uri" options is not documented but supported.

This is a Measurement Factory project.

=== modified file 'src/adaptation/ServiceConfig.cc'
--- src/adaptation/ServiceConfig.cc	2011-05-24 22:26:21 +0000
+++ src/adaptation/ServiceConfig.cc	2011-10-06 09:10:48 +0000
@@ -1,28 +1,29 @@
 /*
  * DEBUG: section 93    Adaptation
  */
 
 #include "squid.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), maxConn(-1), onOverload(srvWait),
         routing(false), ipv6(false)
 {}
 
 const char *
 Adaptation::ServiceConfig::methodStr() const
 {
     return Adaptation::methodStr(method);
 }
 
 const char *
 Adaptation::ServiceConfig::vectPointStr() const
 {
     return Adaptation::vectPointStr(point);
 }
 
 Adaptation::Method
@@ -52,98 +53,106 @@
     if (!strcasecmp(t, "postcache"))
         return Adaptation::pointPostCache;
 
     return Adaptation::pointNone;
 }
 
 bool
 Adaptation::ServiceConfig::parse()
 {
     String method_point;
 
     ConfigParser::ParseString(&key);
     ConfigParser::ParseString(&method_point);
     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
-    const char *lastOption = NULL;
     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
-            bypass = false;
-            continue;
-        }
-        if (strcmp(option, "1") == 0) { // backward compatibility
-            bypass = true;
-            continue;
+            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 '='
+            }
         }
 
-        const char *name = option;
-        char *value = strstr(option, "=");
-        if (!value) {
-            lastOption = option;
-            break;
+        // 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;
         }
-        *value = '\0'; // terminate option name
-        ++value; // skip '='
+        options.insert(name);
 
-        // TODO: warn if option is set twice?
         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;
     }
 
     // set default on-overload value if needed
     if (!onOverloadSet)
         onOverload = bypass ? srvBypass : srvWait;
 
-    // what is left must be the service URI
-    if (!grokkedUri && !grokUri(lastOption))
-        return false;
-
-    // there should be nothing else left
-    if (const char *tail = strtok(NULL, w_space)) {
-        debugs(3, 0, cfg_filename << ':' << config_lineno << ": " <<
-               "garbage after adaptation service URI: " << tail);
+    // 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 << ": " <<

=== modified file 'src/cf.data.pre'
--- src/cf.data.pre	2011-09-22 00:46:26 +0000
+++ src/cf.data.pre	2011-10-06 08:42:00 +0000
@@ -6579,51 +6579,53 @@
 DOC_END
 
 NAME: icap_client_username_encode
 TYPE: onoff
 IFDEF: ICAP_CLIENT
 COMMENT: on|off
 LOC: Adaptation::Icap::TheConfig.client_username_encode
 DEFAULT: off
 DOC_START
 	Whether to base64 encode the authenticated client username.
 DOC_END
 
 NAME: icap_service
 TYPE: icap_service_type
 IFDEF: ICAP_CLIENT
 LOC: Adaptation::Icap::TheConfig
 DEFAULT: none
 DOC_START
 	Defines a single ICAP service using the following format:
 
-	icap_service service_name vectoring_point [options] service_url
+	icap_service id vectoring_point uri [option ...]
 
-	service_name: ID
-		an opaque identifier which must be unique in squid.conf
+	id: ID
+		an opaque identifier or name which is used to direct traffic to
+		this specific service. Must be unique among all adaptation
+		services in squid.conf.
 
 	vectoring_point: reqmod_precache|reqmod_postcache|respmod_precache|respmod_postcache
 		This specifies at which point of transaction processing the
 		ICAP service should be activated. *_postcache vectoring points
 		are not yet supported.
 
-	service_url: icap://servername:port/servicepath
+	uri: icap://servername:port/servicepath
 		ICAP server and service location.
 
 	ICAP does not allow a single service to handle both REQMOD and RESPMOD
 	transactions. Squid does not enforce that requirement. You can specify
 	services with the same service_url and different vectoring_points. You
 	can even specify multiple identical services as long as their
 	service_names differ.
 
 
 	Service options are separated by white space. ICAP services support
 	the following name=value options:
 
 	bypass=on|off|1|0
 		If set to 'on' or '1', the ICAP service is treated as
 		optional. If the service cannot be reached or malfunctions,
 		Squid will try to ignore any errors and process the message as
 		if the service was not enabled. No all ICAP errors can be
 		bypassed.  If set to 0, the ICAP service is treated as
 		essential and all ICAP errors will result in an error page
 		returned to the HTTP client.
@@ -6658,42 +6660,42 @@
 		  * bypass: ignore the "over-connected" ICAP service
 		  * wait:   wait (in a FIFO queue) for an ICAP connection slot
 		  * force:  proceed, ignoring the Max-Connections limit 
 
 		In SMP mode with N workers, each worker assumes the service
 		connection limit is Max-Connections/N, even though not all
 		workers may use a given service.
 
 		The default value is "bypass" if service is bypassable,
 		otherwise it is set to "wait".
 		
 
 	max-conn=number
 		Use the given number as the Max-Connections limit, regardless
 		of the Max-Connections value given by the service, if any.
 
 	Older icap_service format without optional named parameters is
 	deprecated but supported for backward compatibility.
 
 Example:
-icap_service svcBlocker reqmod_precache bypass=0 icap://icap1.mydomain.net:1344/reqmod
-icap_service svcLogger reqmod_precache routing=on icap://icap2.mydomain.net:1344/respmod
+icap_service svcBlocker reqmod_precache icap://icap1.mydomain.net:1344/reqmod bypass=0
+icap_service svcLogger reqmod_precache icap://icap2.mydomain.net:1344/respmod routing=on
 DOC_END
 
 NAME: icap_class
 TYPE: icap_class_type
 IFDEF: ICAP_CLIENT
 LOC: none
 DEFAULT: none
 DOC_START
 	This deprecated option was documented to define an ICAP service
 	chain, even though it actually defined a set of similar, redundant
 	services, and the chains were not supported. 
 
 	To define a set of redundant services, please use the
 	adaptation_service_set directive. For service chains, use
 	adaptation_service_chain.
 DOC_END
 
 NAME: icap_access
 TYPE: icap_access_type
 IFDEF: ICAP_CLIENT
@@ -6711,59 +6713,90 @@
 COMMENT_END
 
 NAME: ecap_enable
 TYPE: onoff
 IFDEF: USE_ECAP
 COMMENT: on|off
 LOC: Adaptation::Ecap::TheConfig.onoff
 DEFAULT: off
 DOC_START
 	Controls whether eCAP support is enabled.
 DOC_END
 
 NAME: ecap_service
 TYPE: ecap_service_type
 IFDEF: USE_ECAP
 LOC: Adaptation::Ecap::TheConfig
 DEFAULT: none
 DOC_START
 	Defines a single eCAP service
 
-	ecap_service servicename vectoring_point bypass service_url
+	ecap_service id vectoring_point uri [option ...]
 
-	vectoring_point = reqmod_precache|reqmod_postcache|respmod_precache|respmod_postcache
+        id: ID
+		an opaque identifier or name which is used to direct traffic to
+		this specific service. Must be unique among all adaptation
+		services in squid.conf.
+
+	vectoring_point: reqmod_precache|reqmod_postcache|respmod_precache|respmod_postcache
 		This specifies at which point of transaction processing the
 		eCAP service should be activated. *_postcache vectoring points
 		are not yet supported.
-	bypass = 1|0
-		If set to 1, the eCAP service is treated as optional. If the
-		service cannot be reached or malfunctions, Squid will try to
-		ignore any errors and process the message as if the service
+
+	uri: ecap://vendor/service_name?custom&cgi=style&parameters=optional
+		Squid uses the eCAP service URI to match this configuration
+		line with one of the dynamically loaded services. Each loaded
+		eCAP service must have a unique URI. Obtain the right URI from
+		the service provider.
+
+
+	Service options are separated by white space. eCAP services support
+	the following name=value options:
+
+	bypass=on|off|1|0
+		If set to 'on' or '1', the eCAP service is treated as optional.
+		If the service cannot be reached or malfunctions, Squid will try
+		to ignore any errors and process the message as if the service
 		was not enabled. No all eCAP errors can be bypassed.
-		If set to 0, the eCAP service is treated as essential and all
-		eCAP errors will result in an error page returned to the
+		If set to 'off' or '0', the eCAP service is treated as essential
+		and all eCAP errors will result in an error page returned to the
 		HTTP client.
-	service_url = ecap://vendor/service_name?custom&cgi=style&parameters=optional
+
+                Bypass is off by default: services are treated as essential.
+
+	routing=on|off|1|0
+		If set to 'on' or '1', the eCAP service is allowed to
+		dynamically change the current message adaptation plan by
+		returning a chain of services to be used next.
+
+		Dynamic adaptation plan may cross or cover multiple supported
+		vectoring points in their natural processing order.
+
+		Routing is not allowed by default.
+
+	Older ecap_service format without optional named parameters is
+	deprecated but supported for backward compatibility.
+
 
 Example:
-ecap_service service_1 reqmod_precache 0 ecap://filters-R-us/leakDetector?on_error=block
-ecap_service service_2 respmod_precache 1 icap://filters-R-us/virusFilter?config=/etc/vf.cfg
+ecap_service s1 reqmod_precache ecap://filters.R.us/leakDetector?on_error=block bypass=off
+ecap_service s2 respmod_precache ecap://filters.R.us/virusFilter config=/etc/vf.cfg bypass=on
 DOC_END
 
 NAME: loadable_modules
 TYPE: wordlist
 IFDEF: USE_LOADABLE_MODULES
 LOC: Config.loadable_module_names
 DEFAULT: none
 DOC_START
 	Instructs Squid to load the specified dynamic module(s) or activate
 	preloaded module(s).
 Example:
 loadable_modules @DEFAULT_PREFIX@/lib/MinimalAdapter.so
 DOC_END
 
 COMMENT_START
  MESSAGE ADAPTATION OPTIONS
  -----------------------------------------------------------------------------
 COMMENT_END
 
 NAME: adaptation_service_set

Reply via email to