From: Alex Rousskov Date: Sun, 30 Mar 2008 18:47:14 +0000 (-0600) Subject: Moved adaptation-method-independent service-configuration code from X-Git-Tag: SQUID_3_1_0_1~49^2~302^2~30 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=d81a31f1d653548de9a86b4409f7829f8268eb38;p=thirdparty%2Fsquid.git Moved adaptation-method-independent service-configuration code from ICAPServiceRep to Adaptation::ServiceConfig so that eCAP services can use it. --- diff --git a/src/ICAP/ICAPServiceRep.cc b/src/ICAP/ICAPServiceRep.cc index 36dc0fef4f..b16e00f999 100644 --- a/src/ICAP/ICAPServiceRep.cc +++ b/src/ICAP/ICAPServiceRep.cc @@ -10,11 +10,13 @@ #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 { diff --git a/src/ICAP/ICAPServiceRep.h b/src/ICAP/ICAPServiceRep.h index e0f045ffe4..6f1d54f94d 100644 --- a/src/ICAP/ICAPServiceRep.h +++ b/src/ICAP/ICAPServiceRep.h @@ -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 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; diff --git a/src/adaptation/Service.cc b/src/adaptation/Service.cc index c2dc19f7bc..3d44f171f7 100644 --- a/src/adaptation/Service.cc +++ b/src/adaptation/Service.cc @@ -3,147 +3,16 @@ */ #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(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; } diff --git a/src/adaptation/Service.h b/src/adaptation/Service.h index e21f9245c9..2e1d3af53d 100644 --- a/src/adaptation/Service.h +++ b/src/adaptation/Service.h @@ -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 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 index 0000000000..118affb064 --- /dev/null +++ b/src/adaptation/ServiceConfig.cc @@ -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(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 index 0000000000..a71f3369f1 --- /dev/null +++ b/src/adaptation/ServiceConfig.h @@ -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 */