]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Moved adaptation-method-independent service-configuration code from
authorAlex Rousskov <rousskov@measurement-factory.com>
Sun, 30 Mar 2008 18:47:14 +0000 (12:47 -0600)
committerAlex Rousskov <rousskov@measurement-factory.com>
Sun, 30 Mar 2008 18:47:14 +0000 (12:47 -0600)
ICAPServiceRep to Adaptation::ServiceConfig so that eCAP services can use it.

src/ICAP/ICAPServiceRep.cc
src/ICAP/ICAPServiceRep.h
src/adaptation/Service.cc
src/adaptation/Service.h
src/adaptation/ServiceConfig.cc [new file with mode: 0644]
src/adaptation/ServiceConfig.h [new file with mode: 0644]

index 36dc0fef4ff4d8571be1bcd00abcff85f3ab7c88..b16e00f999c7f8724c69208cf587cdc23ecd55d0 100644 (file)
 #include "ICAPOptXact.h"
 #include "ConfigParser.h"
 #include "ICAPConfig.h"
+#include "ICAPModXact.h"
 #include "SquidTime.h"
 
 CBDATA_CLASS_INIT(ICAPServiceRep);
 
-ICAPServiceRep::ICAPServiceRep(): AsyncJob("ICAPServiceRep"),
+ICAPServiceRep::ICAPServiceRep(const Adaptation::ServiceConfig &cfg):
+        AsyncJob("ICAPServiceRep"), Adaptation::Service(cfg),
         theOptions(NULL), theOptionsFetcher(0), theLastUpdate(0),
         theSessionFailures(0), isSuspended(0), notifying(false),
         updateScheduled(false), self(NULL),
@@ -28,23 +30,23 @@ ICAPServiceRep::~ICAPServiceRep()
 }
 
 bool
-ICAPServiceRep::configure(Pointer &aSelf)
+ICAPServiceRep::finalize(Pointer &aSelf)
 {
     assert(!self && aSelf != NULL);
     self = aSelf;
 
-       if (!Adaptation::Service::configure())
+       if (!Adaptation::Service::finalize())
         return false;
 
     // use /etc/services or default port if needed
-       const bool have_port = port >= 0;
+       const bool have_port = cfg().port >= 0;
     if (!have_port) {
         struct servent *serv = getservbyname("icap", "tcp");
 
         if (serv) {
-            port = htons(serv->s_port);
+            writeableCfg().port = htons(serv->s_port);
         } else {
-            port = 1344;
+            writeableCfg().port = 1344;
         }
     }
 
@@ -248,7 +250,7 @@ void ICAPServiceRep::checkOptions()
 
     if (!theOptions->valid()) {
         debugs(93,1, "WARNING: Squid got an invalid ICAP OPTIONS response " <<
-            "from service " << uri << "; error: " << theOptions->error);
+            "from service " << cfg().uri << "; error: " << theOptions->error);
         return;
     }
 
@@ -264,7 +266,7 @@ void ICAPServiceRep::checkOptions()
 
         while (iter != theOptions->methods.end()) {
 
-            if (*iter == method) {
+            if (*iter == cfg().method) {
                 method_found = true;
                 break;
             }
@@ -276,8 +278,8 @@ void ICAPServiceRep::checkOptions()
 
         if (!method_found) {
             debugs(93,1, "WARNING: Squid is configured to use ICAP method " <<
-                   ICAP::methodStr(method) <<
-                   " for service " << uri.buf() <<
+                   cfg().methodStr() <<
+                   " for service " << cfg().uri.buf() <<
                    " but OPTIONS response declares the methods are " << method_list.buf());
         }
     }
@@ -291,7 +293,7 @@ void ICAPServiceRep::checkOptions()
         // TODO: If skew is negative, the option will be considered down
         // because of stale options. We should probably change this.
         debugs(93, 1, "ICAP service's clock is skewed by " << skew <<
-            " seconds: " << uri.buf());
+            " seconds: " << cfg().uri.buf());
     }
 }
 
@@ -300,20 +302,20 @@ void ICAPServiceRep::announceStatusChange(const char *downPhrase, bool important
     if (wasAnnouncedUp == up()) // no significant changes to announce
         return;
 
-    const char *what = bypass ? "optional" : "essential";
+    const char *what = cfg().bypass ? "optional" : "essential";
     const char *state = wasAnnouncedUp ? downPhrase : "up";
     const int level = important ? 1 : 2;
-    debugs(93,level, what << " ICAP service is " << state << ": " << uri <<
-        ' ' << status());
+    debugs(93,level, what << " ICAP service is " << state << ": " <<
+        cfg().uri << ' ' << status());
 
     wasAnnouncedUp = !wasAnnouncedUp;
 }
 
 // we are receiving ICAP OPTIONS response headers here or NULL on failures
-void ICAPServiceRep::noteIcapAnswer(HttpMsg *msg)
+void ICAPServiceRep::noteAdaptationAnswer(HttpMsg *msg)
 {
     Must(theOptionsFetcher);
-    clearIcap(theOptionsFetcher);
+    clearAdaptation(theOptionsFetcher);
 
     Must(msg);
 
@@ -330,9 +332,9 @@ void ICAPServiceRep::noteIcapAnswer(HttpMsg *msg)
     handleNewOptions(newOptions);
 }
 
-void ICAPServiceRep::noteIcapQueryAbort(bool) {
+void ICAPServiceRep::noteAdaptationQueryAbort(bool) {
     Must(theOptionsFetcher);
-    clearIcap(theOptionsFetcher);
+    clearAdaptation(theOptionsFetcher);
 
     debugs(93,3, "ICAPService failed to fetch options " << status());
     handleNewOptions(0);
@@ -354,7 +356,8 @@ void ICAPServiceRep::startGettingOptions()
     Must(!theOptionsFetcher);
     debugs(93,6, "ICAPService will get new options " << status());
 
-    theOptionsFetcher = initiateIcap(new ICAPOptXactLauncher(this, self));
+    // XXX: check whether it is safe to use self as "this"
+    theOptionsFetcher = initiateAdaptation(new ICAPOptXactLauncher(this, this));
     Must(theOptionsFetcher);
     // TODO: timeout in case ICAPOptXact never calls us back?
     // Such a timeout should probably be a generic AsyncStart feature.
@@ -421,6 +424,13 @@ ICAPServiceRep::optionsFetchTime() const
     return squid_curtime + TheICAPConfig.service_revival_delay;
 }
 
+Adaptation::Initiate *
+ICAPServiceRep::makeXactLauncher(Adaptation::Initiator *initiator,
+    HttpMsg *virgin, HttpRequest *cause)
+{
+    return new ICAPModXactLauncher(initiator, virgin, cause, this);
+}
+
 // returns a temporary string depicting service status, for debugging
 const char *ICAPServiceRep::status() const
 {
index e0f045ffe4918dd5e1499c756614de757824126f..6f1d54f94d178a64c21a15eee12eece38ac5c1a3 100644 (file)
@@ -36,7 +36,8 @@
 
 #include "cbdata.h"
 #include "adaptation/Service.h"
-#include "ICAPInitiator.h"
+#include "adaptation/forward.h"
+#include "adaptation/Initiator.h"
 #include "ICAPElements.h"
 
 class ICAPOptions;
@@ -72,23 +73,25 @@ class ICAPOptXact;
 
 
 class ICAPServiceRep : public RefCountable, public Adaptation::Service,
-    public ICAPInitiator
+    public Adaptation::Initiator
 {
 
 public:
     typedef RefCount<ICAPServiceRep> Pointer;
 
 public:
-    ICAPServiceRep();
+    ICAPServiceRep(const Adaptation::ServiceConfig &config);
     virtual ~ICAPServiceRep();
 
-    bool configure(Pointer &aSelf); // needs self pointer for ICAPOptXact
+    bool finalize(Pointer &aSelf); // needs self pointer for ICAPOptXact
     void invalidate(); // call when the service is no longer needed or valid
 
     bool probed() const; // see comments above
     bool broken() const; // see comments above
     bool up() const; // see comments above
 
+    virtual Adaptation::Initiate *makeXactLauncher(Adaptation::Initiator *, HttpMsg *virginHeader, HttpRequest *virginCause);
+
     void callWhenReady(AsyncCall::Pointer &cb);
 
     // the methods below can only be called on an up() service
@@ -99,15 +102,15 @@ public:
     void noteFailure(); // called by transactions to report service failure
     
     //AsyncJob virtual methods
-    virtual bool doneAll() const { return ICAPInitiator::doneAll() && false;}
+    virtual bool doneAll() const { return Adaptation::Initiator::doneAll() && false;}
 
 public: // treat these as private, they are for callbacks only
     void noteTimeToUpdate();
     void noteTimeToNotify();
 
     // receive either an ICAP OPTIONS response header or an abort message
-    virtual void noteIcapAnswer(HttpMsg *msg);
-    virtual void noteIcapQueryAbort(bool);
+    virtual void noteAdaptationAnswer(HttpMsg *msg);
+    virtual void noteAdaptationQueryAbort(bool);
 
 private:
     // stores Prepare() callback info
@@ -122,7 +125,7 @@ private:
     Clients theClients; // all clients waiting for a call back
 
     ICAPOptions *theOptions;
-    ICAPInitiate *theOptionsFetcher; // pending ICAP OPTIONS transaction
+    Adaptation::Initiate *theOptionsFetcher; // pending ICAP OPTIONS transaction
     time_t theLastUpdate; // time the options were last updated
 
     static const int TheSessionFailureLimit;
index c2dc19f7bc356d6d2d8739d82a169c3e25d06f01..3d44f171f700d828994966b822f616969bac8fdf 100644 (file)
  */
 
 #include "squid.h"
-#include "ConfigParser.h"
 #include "adaptation/Service.h"
 
-Adaptation::Service::Service(): 
-    port(-1), method(methodNone), point(pointNone), bypass(false)
+Adaptation::Service::Service(const ServiceConfig &aConfig): theConfig(aConfig)
 {}
 
 Adaptation::Service::~Service()
 {}
 
-const char *
-Adaptation::Service::methodStr() const
-{
-    return Adaptation::methodStr(method);
-}
-
-const char *
-Adaptation::Service::vectPointStr() const
-{
-    return Adaptation::vectPointStr(point);
-}
-
-Adaptation::Method
-Adaptation::Service::parseMethod(const char *str) const
-{
-    if (!strncasecmp(str, "REQMOD", 6))
-        return Adaptation::methodReqmod;
-
-    if (!strncasecmp(str, "RESPMOD", 7))
-        return Adaptation::methodRespmod;
-
-    return Adaptation::methodNone;
-}
-
-Adaptation::VectPoint
-Adaptation::Service::parseVectPoint(const char *service) const
-{
-    const char *t = service;
-    const char *q = strchr(t, '_');
-
-    if (q)
-        t = q + 1;
-
-    if (!strcasecmp(t, "precache"))
-        return Adaptation::pointPreCache;
-
-    if (!strcasecmp(t, "postcache"))
-        return Adaptation::pointPostCache;
-
-    return Adaptation::pointNone;
-}
-
 bool
-Adaptation::Service::configure()
+Adaptation::Service::finalize()
 {
-    char *service_type = NULL;
-
-    ConfigParser::ParseString(&key);
-    ConfigParser::ParseString(&service_type);
-    ConfigParser::ParseBool(&bypass);
-    ConfigParser::ParseString(&uri);
-
-    debugs(3, 5, HERE << cfg_filename << ':' << config_lineno << ": " <<
-        key.buf() << " " << service_type << " " << bypass);
-
-    method = parseMethod(service_type);
-    point = parseVectPoint(service_type);
-
-    debugs(3, 5, HERE << cfg_filename << ':' << config_lineno << ": " <<
-        "service is " << methodStr() << "_" << vectPointStr());
-
-    // TODO: find core code that parses URLs and extracts various parts
-
-    // extract scheme and use it as the service protocol
-    const char *schemeSuffix = "://";
-    if (const char *schemeEnd = uri.pos(schemeSuffix))
-               protocol.limitInit(uri.buf(), schemeEnd - uri.buf());
-       debugs(3, 5, HERE << cfg_filename << ':' << config_lineno << ": " <<
-               "service protocol is " << protocol);
-       if (!protocol.size())
-               return false;
-
-    const char *s = uri.buf() + protocol.size() + sizeof(schemeSuffix);
-
-    const char *e;
-
-    bool have_port = false;
-
-    if ((e = strchr(s, ':')) != NULL) {
-        have_port = true;
-    } else if ((e = strchr(s, '/')) != NULL) {
-        have_port = false;
-    } else {
-        return false;
-    }
-
-    int len = e - s;
-    host.limitInit(s, len);
-    s = e;
-
-       port = -1;
-    if (have_port) {
-        s++;
-
-        if ((e = strchr(s, '/')) != NULL) {
-            char *t;
-                       const unsigned long p = strtoul(s, &t, 0);
-
-                       if (p > 65535) // port value is too high
-                               return false;
-
-            port = static_cast<int>(p);
-
-            if (t != e) // extras after the port
-                return false;
-
-            s = e;
-
-            if (s[0] != '/')
-                return false;
-        }
-    }
-
-    // if no port, the caller may use services or supply the default if neeeded
-
-    s++;
-    e = strchr(s, '\0');
-    len = e - s;
-
-    if (len > 1024) {
-        debugs(3, 0, HERE << cfg_filename << ':' << config_lineno << ": " <<
-            "long resource name (>1024), probably wrong");
-    }
-
-    resource.limitInit(s, len + 1);
-
-    if ((bypass != 0) && (bypass != 1)) {
-        debugs(3, 0, HERE << cfg_filename << ':' << config_lineno << ": " <<
-            "wrong bypass value; 0 or 1 expected: " << bypass);
-        return false;
-    }
-
     return true;
 }
index e21f9245c938a4e8a11599c02f370aaa2284144d..2e1d3af53d6a8305d43d1a9396da3dd95fd6c485 100644 (file)
@@ -2,41 +2,59 @@
 #define SQUID_ADAPTATION__SERVICE_H
 
 #include "SquidString.h"
+#include "RefCount.h"
+#include "adaptation/forward.h"
 #include "adaptation/Elements.h"
+#include "adaptation/ServiceConfig.h"
+
+// TODO: Move src/ICAP/ICAPServiceRep.h API comments here and update them
+
+class HttpMsg;
+class HttpRequest;
 
 namespace Adaptation {
 
 // manages adaptation service configuration in squid.conf
 // specific adaptation mechanisms extend this class
-class Service
+class Service: public RefCountable
 {
 public:
-    Service();
+    typedef RefCount<Service> Pointer;
+
+public:
+    Service(const ServiceConfig &aConfig);
     virtual ~Service();
 
-    const char *methodStr() const;
-    const char *vectPointStr() const;
+    // call when the service is no longer needed or valid
+    virtual void invalidate() = 0;
 
-public:
-    String key;    // service name in the configuration file
-    String uri;    // service URI
+    virtual bool probed() const = 0; // see comments above
+    virtual bool broken() const = 0; // see comments above
+    virtual bool up() const = 0; // see comments above
 
-    // service URI components
-    String protocol;
-    String host;
-    String resource;
-    int port;
+    virtual Initiate *makeXactLauncher(Initiator *, HttpMsg *virginHeader, HttpRequest *virginCause) = 0;
 
-    Method method;   // what is being adapted (REQMOD vs RESPMOD)
-    VectPoint point; // where the adaptation happens (pre- or post-cache)
-    bool bypass;
+    typedef void Callback(void *data, Pointer &service);
+    void callWhenReady(Callback *cb, void *data);
+
+    // the methods below can only be called on an up() service
+    virtual bool wantsUrl(const String &urlPath) const = 0;
+
+    // called by transactions to report service failure
+    virtual void noteFailure() = 0;
+
+    const ServiceConfig &cfg() const { return theConfig; }
 
 protected:
-    bool configure();
-    Method parseMethod(const char *str) const;
-    VectPoint parseVectPoint(const char *service) const;
+    bool finalize(); // called after creation
+    ServiceConfig &writeableCfg() { return theConfig; }
+
+private:
+    ServiceConfig theConfig;
 };
 
+typedef Service::Pointer ServicePointer;
+
 } // namespace Adaptation
 
 #endif /* SQUID_ADAPTATION__SERVICE_H */
diff --git a/src/adaptation/ServiceConfig.cc b/src/adaptation/ServiceConfig.cc
new file mode 100644 (file)
index 0000000..118affb
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * DEBUG: section XXX
+ */
+
+#include "squid.h"
+#include "ConfigParser.h"
+#include "adaptation/ServiceConfig.h"
+
+Adaptation::ServiceConfig::ServiceConfig(): 
+    port(-1), method(methodNone), point(pointNone), bypass(false)
+{}
+
+const char *
+Adaptation::ServiceConfig::methodStr() const
+{
+    return Adaptation::methodStr(method);
+}
+
+const char *
+Adaptation::ServiceConfig::vectPointStr() const
+{
+    return Adaptation::vectPointStr(point);
+}
+
+Adaptation::Method
+Adaptation::ServiceConfig::parseMethod(const char *str) const
+{
+    if (!strncasecmp(str, "REQMOD", 6))
+        return Adaptation::methodReqmod;
+
+    if (!strncasecmp(str, "RESPMOD", 7))
+        return Adaptation::methodRespmod;
+
+    return Adaptation::methodNone;
+}
+
+Adaptation::VectPoint
+Adaptation::ServiceConfig::parseVectPoint(const char *service_configConfig) const
+{
+    const char *t = service_configConfig;
+    const char *q = strchr(t, '_');
+
+    if (q)
+        t = q + 1;
+
+    if (!strcasecmp(t, "precache"))
+        return Adaptation::pointPreCache;
+
+    if (!strcasecmp(t, "postcache"))
+        return Adaptation::pointPostCache;
+
+    return Adaptation::pointNone;
+}
+
+bool
+Adaptation::ServiceConfig::parse()
+{
+    char *method_point = NULL;
+
+    ConfigParser::ParseString(&key);
+    ConfigParser::ParseString(&method_point);
+    ConfigParser::ParseBool(&bypass);
+    ConfigParser::ParseString(&uri);
+
+    debugs(3, 5, HERE << cfg_filename << ':' << config_lineno << ": " <<
+        key.buf() << " " << method_point << " " << bypass);
+
+    method = parseMethod(method_point);
+    point = parseVectPoint(method_point);
+
+    debugs(3, 5, HERE << cfg_filename << ':' << config_lineno << ": " <<
+        "service_configConfig is " << methodStr() << "_" << vectPointStr());
+
+    // TODO: find core code that parses URLs and extracts various parts
+
+    // extract scheme and use it as the service_configConfig protocol
+    const char *schemeSuffix = "://";
+    if (const char *schemeEnd = uri.pos(schemeSuffix))
+               protocol.limitInit(uri.buf(), schemeEnd - uri.buf());
+       debugs(3, 5, HERE << cfg_filename << ':' << config_lineno << ": " <<
+               "service protocol is " << protocol);
+       if (!protocol.size())
+               return false;
+
+    // skip scheme
+    const char *s = uri.buf() + protocol.size() + strlen(schemeSuffix);
+
+    const char *e;
+
+    bool have_port = false;
+
+    if ((e = strchr(s, ':')) != NULL) {
+        have_port = true;
+    } else if ((e = strchr(s, '/')) != NULL) {
+        have_port = false;
+    } else {
+        return false;
+    }
+
+    int len = e - s;
+    host.limitInit(s, len);
+    s = e;
+
+       port = -1;
+    if (have_port) {
+        s++;
+
+        if ((e = strchr(s, '/')) != NULL) {
+            char *t;
+                       const unsigned long p = strtoul(s, &t, 0);
+
+                       if (p > 65535) // port value is too high
+                               return false;
+
+            port = static_cast<int>(p);
+
+            if (t != e) // extras after the port
+                return false;
+
+            s = e;
+
+            if (s[0] != '/')
+                return false;
+        }
+    }
+
+    // if no port, the caller may use service_configConfigs or supply the default if neeeded
+
+    s++;
+    e = strchr(s, '\0');
+    len = e - s;
+
+    if (len > 1024) {
+        debugs(3, 0, HERE << cfg_filename << ':' << config_lineno << ": " <<
+            "long resource name (>1024), probably wrong");
+    }
+
+    resource.limitInit(s, len + 1);
+
+    if ((bypass != 0) && (bypass != 1)) {
+        debugs(3, 0, HERE << cfg_filename << ':' << config_lineno << ": " <<
+            "wrong bypass value; 0 or 1 expected: " << bypass);
+        return false;
+    }
+
+    return true;
+}
diff --git a/src/adaptation/ServiceConfig.h b/src/adaptation/ServiceConfig.h
new file mode 100644 (file)
index 0000000..a71f336
--- /dev/null
@@ -0,0 +1,42 @@
+#ifndef SQUID_ADAPTATION__SERVICE_CONFIG_H
+#define SQUID_ADAPTATION__SERVICE_CONFIG_H
+
+#include "SquidString.h"
+#include "RefCount.h"
+#include "adaptation/Elements.h"
+
+namespace Adaptation {
+
+// manages adaptation service configuration in squid.conf
+class ServiceConfig
+{
+public:
+    ServiceConfig();
+
+    const char *methodStr() const;
+    const char *vectPointStr() const;
+
+    bool parse();
+
+public:
+    String key;    // service_configConfig name in the configuration file
+    String uri;    // service_configConfig URI
+
+    // service_configConfig URI components
+    String protocol;
+    String host;
+    String resource;
+    int port;
+
+    Method method;   // what is being adapted (REQMOD vs RESPMOD)
+    VectPoint point; // where the adaptation happens (pre- or post-cache)
+    bool bypass;
+
+protected:
+    Method parseMethod(const char *buf) const;
+    VectPoint parseVectPoint(const char *buf) const;
+};
+
+} // namespace Adaptation
+
+#endif /* SQUID_ADAPTATION__SERVICE_CONFIG_H */