ICAPServiceRep to Adaptation::ServiceConfig so that eCAP services can use it.
#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),
}
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;
}
}
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;
}
while (iter != theOptions->methods.end()) {
- if (*iter == method) {
+ if (*iter == cfg().method) {
method_found = true;
break;
}
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());
}
}
// 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());
}
}
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);
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);
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.
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
{
#include "cbdata.h"
#include "adaptation/Service.h"
-#include "ICAPInitiator.h"
+#include "adaptation/forward.h"
+#include "adaptation/Initiator.h"
#include "ICAPElements.h"
class ICAPOptions;
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
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
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;
*/
#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;
}
#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 */
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+#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 */