]> git.ipfire.org Git - thirdparty/squid.git/blame - src/adaptation/ecap/ServiceRep.cc
Renamed squid.h to squid-old.h and config.h to squid.h
[thirdparty/squid.git] / src / adaptation / ecap / ServiceRep.cc
CommitLineData
b510f3a1
AJ
1/*
2 * DEBUG: section 93 eCAP Interface
3 */
f7f3304a 4#include "squid-old.h"
76fc7e57 5#include <list>
fdc96a39 6#include <libecap/adapter/service.h>
22fff3bf 7#include <libecap/common/options.h>
e1e90d26
AR
8#include <libecap/common/name.h>
9#include <libecap/common/named_values.h>
10#include "adaptation/ecap/Config.h"
22fff3bf 11#include "adaptation/ecap/Host.h"
1f3c65fc
AR
12#include "adaptation/ecap/ServiceRep.h"
13#include "adaptation/ecap/XactionRep.h"
3d93a84d 14#include "base/TextException.h"
fdc96a39 15
76fc7e57
AJ
16// configured eCAP service wrappers
17static std::list<Adaptation::Ecap::ServiceRep::AdapterService> TheServices;
18
22fff3bf
AR
19namespace Adaptation
20{
21namespace Ecap
22{
23
e1e90d26 24/// wraps Adaptation::Ecap::ServiceConfig to allow eCAP visitors
22fff3bf 25class ConfigRep: public libecap::Options
e1e90d26
AR
26{
27public:
28 typedef Adaptation::Ecap::ServiceConfig Master;
29 typedef libecap::Name Name;
30 typedef libecap::Area Area;
31
22fff3bf 32 ConfigRep(const Master &aMaster);
e1e90d26 33
22fff3bf
AR
34 // libecap::Options API
35 virtual const libecap::Area option(const libecap::Name &name) const;
36 virtual void visitEachOption(libecap::NamedValueVisitor &visitor) const;
e1e90d26
AR
37
38 const Master &master; ///< the configuration being wrapped
39};
40
22fff3bf
AR
41} // namespace Ecap
42} // namespace Adaptation
43
44
45Adaptation::Ecap::ConfigRep::ConfigRep(const Master &aMaster): master(aMaster)
46{
47}
48
49const libecap::Area
50Adaptation::Ecap::ConfigRep::option(const libecap::Name &name) const
51{
52 // we may supply the params we know about, but only when names have host ID
53 if (name == metaBypassable)
54 return Area(master.bypass ? "1" : "0", 1);
55
56 // TODO: We could build a by-name index, but is it worth it? Good adapters
57 // should use visitEachOption() instead, to check for name typos/errors.
58 typedef Master::Extensions::const_iterator MECI;
59 for (MECI i = master.extensions.begin(); i != master.extensions.end(); ++i) {
60 if (name == i->first)
61 return Area(i->second.data(), i->second.size());
62 }
63
64 return Area();
65}
66
e1e90d26 67void
22fff3bf 68Adaptation::Ecap::ConfigRep::visitEachOption(libecap::NamedValueVisitor &visitor) const
e1e90d26
AR
69{
70 // we may supply the params we know about too, but only if we set host ID
22fff3bf 71 visitor.visit(metaBypassable, Area(master.bypass ? "1" : "0", 1));
e1e90d26
AR
72
73 // visit adapter-specific options (i.e., those not recognized by Squid)
74 typedef Master::Extensions::const_iterator MECI;
75 for (MECI i = master.extensions.begin(); i != master.extensions.end(); ++i)
76 visitor.visit(Name(i->first), Area::FromTempString(i->second));
77}
78
79
80
6666da11 81Adaptation::Ecap::ServiceRep::ServiceRep(const ServiceConfigPointer &cfg):
76fc7e57
AJ
82 /*AsyncJob("Adaptation::Ecap::ServiceRep"),*/ Adaptation::Service(cfg),
83 isDetached(false)
fdc96a39
AR
84{
85}
86
574b508c 87Adaptation::Ecap::ServiceRep::~ServiceRep()
fdc96a39
AR
88{
89}
90
574b508c 91void Adaptation::Ecap::ServiceRep::noteFailure()
26ac0430
AJ
92{
93 assert(false); // XXX: should this be ICAP-specific?
fdc96a39
AR
94}
95
96void
574b508c 97Adaptation::Ecap::ServiceRep::finalize()
fdc96a39 98{
26ac0430 99 Adaptation::Service::finalize();
76fc7e57 100 theService = FindAdapterService(cfg().uri);
e1d1bd27 101 if (theService) {
45d2da8b
AR
102 try {
103 tryConfigureAndStart();
104 Must(up());
aa420fc9 105 } catch (const std::exception &e) { // standardized exceptions
45d2da8b
AR
106 if (!handleFinalizeFailure(e.what()))
107 throw; // rethrow for upper layers to handle
aa420fc9 108 } catch (...) { // all other exceptions
45d2da8b
AR
109 if (!handleFinalizeFailure("unrecognized exception"))
110 throw; // rethrow for upper layers to handle
111 }
112 return; // success or handled exception
e1d1bd27 113 } else {
1159e19b 114 debugs(93,DBG_IMPORTANT, "WARNING: configured ecap_service was not loaded: " << cfg().uri);
26ac0430 115 }
fdc96a39
AR
116}
117
45d2da8b
AR
118/// attempts to configure and start eCAP service; the caller handles exceptions
119void
120Adaptation::Ecap::ServiceRep::tryConfigureAndStart()
121{
122 debugs(93,2, HERE << "configuring eCAP service: " << theService->uri());
123 const ConfigRep cfgRep(dynamic_cast<const ServiceConfig&>(cfg()));
124 theService->configure(cfgRep);
125
126 debugs(93,DBG_IMPORTANT, "Starting eCAP service: " << theService->uri());
127 theService->start();
128}
129
130/// handles failures while configuring or starting an eCAP service;
131/// returns false if the error must be propagated to higher levels
132bool
133Adaptation::Ecap::ServiceRep::handleFinalizeFailure(const char *error)
134{
135 const bool salvage = cfg().bypass;
aa420fc9 136 const int level = salvage ? DBG_IMPORTANT :DBG_CRITICAL;
45d2da8b
AR
137 const char *kind = salvage ? "optional" : "essential";
138 debugs(93, level, "ERROR: failed to start " << kind << " eCAP service: " <<
139 cfg().uri << ":\n" << error);
140
141 if (!salvage)
142 return false; // we cannot handle the problem; the caller may escalate
143
144 // make up() false, preventing new adaptation requests and enabling bypass
145 theService.reset();
146 debugs(93, level, "WARNING: " << kind << " eCAP service is " <<
147 "down after initialization failure: " << cfg().uri);
148
aa420fc9 149 return true; // tell the caller to ignore the problem because we handled it
45d2da8b
AR
150}
151
574b508c 152bool Adaptation::Ecap::ServiceRep::probed() const
fdc96a39
AR
153{
154 return true; // we "probe" the adapter in finalize().
155}
156
574b508c 157bool Adaptation::Ecap::ServiceRep::up() const
fdc96a39
AR
158{
159 return theService != NULL;
160}
161
574b508c 162bool Adaptation::Ecap::ServiceRep::wantsUrl(const String &urlPath) const
fdc96a39
AR
163{
164 Must(up());
c1945e7d 165 return theService->wantsUrl(urlPath.termedBuf());
fdc96a39
AR
166}
167
168Adaptation::Initiate *
4299f876 169Adaptation::Ecap::ServiceRep::makeXactLauncher(HttpMsg *virgin,
4cb2536f 170 HttpRequest *cause)
fdc96a39 171{
26ac0430 172 Must(up());
4299f876 173 XactionRep *rep = new XactionRep(virgin, cause, Pointer(this));
26ac0430 174 XactionRep::AdapterXaction x(theService->makeXaction(rep));
fdc96a39
AR
175 rep->master(x);
176 return rep;
177}
178
179// returns a temporary string depicting service status, for debugging
574b508c 180const char *Adaptation::Ecap::ServiceRep::status() const
fdc96a39 181{
76fc7e57
AJ
182 // TODO: move generic stuff from eCAP and ICAP to Adaptation
183 static MemBuf buf;
184
185 buf.reset();
186 buf.append("[", 1);
187
188 if (up())
189 buf.append("up", 2);
190 else
191 buf.append("down", 4);
192
193 if (detached())
194 buf.append(",detached", 9);
195
196 buf.append("]", 1);
197 buf.terminate();
198
199 return buf.content();
200}
201
202void Adaptation::Ecap::ServiceRep::detach()
203{
204 isDetached = true;
205}
d090e020 206
76fc7e57
AJ
207bool Adaptation::Ecap::ServiceRep::detached() const
208{
209 return isDetached;
210}
211
212Adaptation::Ecap::ServiceRep::AdapterService
213Adaptation::Ecap::FindAdapterService(const String& serviceUri)
214{
215 typedef std::list<ServiceRep::AdapterService>::const_iterator ASCI;
216 for (ASCI s = TheServices.begin(); s != TheServices.end(); ++s) {
217 Must(*s);
218 if (serviceUri == (*s)->uri().c_str())
219 return *s;
220 }
221 return ServiceRep::AdapterService();
222}
223
224void
225Adaptation::Ecap::RegisterAdapterService(const Adaptation::Ecap::ServiceRep::AdapterService& adapterService)
226{
227 typedef std::list<ServiceRep::AdapterService>::iterator ASI;
228 for (ASI s = TheServices.begin(); s != TheServices.end(); ++s) {
229 Must(*s);
230 if (adapterService->uri() == (*s)->uri()) {
231 *s = adapterService;
232 debugs(93, 3, "updated eCAP module service: " <<
d090e020 233 adapterService->uri());
76fc7e57
AJ
234 return;
235 }
236 }
237 TheServices.push_back(adapterService);
238 debugs(93, 3, "registered eCAP module service: " << adapterService->uri());
239}
240
241void
242Adaptation::Ecap::UnregisterAdapterService(const String& serviceUri)
243{
244 typedef std::list<ServiceRep::AdapterService>::iterator ASI;
245 for (ASI s = TheServices.begin(); s != TheServices.end(); ++s) {
246 if (serviceUri == (*s)->uri().c_str()) {
247 TheServices.erase(s);
248 debugs(93, 3, "unregistered eCAP module service: " << serviceUri);
249 return;
250 }
251 }
252 debugs(93, 3, "failed to unregister eCAP module service: " << serviceUri);
253}
254
255void
256Adaptation::Ecap::CheckUnusedAdapterServices(const Adaptation::Services& cfgs)
257{
258 typedef std::list<ServiceRep::AdapterService>::const_iterator ASCI;
259 for (ASCI loaded = TheServices.begin(); loaded != TheServices.end();
d090e020 260 ++loaded) {
76fc7e57
AJ
261 bool found = false;
262 for (Services::const_iterator cfged = cfgs.begin();
d090e020 263 cfged != cfgs.end() && !found; ++cfged) {
76fc7e57
AJ
264 found = (*cfged)->cfg().uri == (*loaded)->uri().c_str();
265 }
266 if (!found)
267 debugs(93, 1, "Warning: loaded eCAP service has no matching " <<
d090e020 268 "ecap_service config option: " << (*loaded)->uri());
76fc7e57 269 }
fdc96a39 270}