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