]> git.ipfire.org Git - thirdparty/squid.git/blob - src/adaptation/Config.cc
cache_log_message directive (#775)
[thirdparty/squid.git] / src / adaptation / Config.cc
1 /*
2 * Copyright (C) 1996-2021 The Squid Software Foundation and contributors
3 *
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
7 */
8
9 #include "squid.h"
10 #include "acl/FilledChecklist.h"
11 #include "acl/Gadgets.h"
12 #include "adaptation/AccessRule.h"
13 #include "adaptation/Config.h"
14 #include "adaptation/History.h"
15 #include "adaptation/Service.h"
16 #include "adaptation/ServiceGroups.h"
17 #include "ConfigParser.h"
18 #include "DebugMessages.h"
19 #include "globals.h"
20 #include "HttpReply.h"
21 #include "HttpRequest.h"
22 #include "Store.h"
23
24 #include <algorithm>
25
26 bool Adaptation::Config::Enabled = false;
27 char *Adaptation::Config::masterx_shared_name = NULL;
28 int Adaptation::Config::service_iteration_limit = 16;
29 int Adaptation::Config::send_client_ip = false;
30 int Adaptation::Config::send_username = false;
31 int Adaptation::Config::use_indirect_client = true;
32 static const char *protectedFieldNamesRaw[] = {
33 "Allow",
34 "Date",
35 "Encapsulated",
36 "ISTag",
37 "Max-Connections",
38 "Methods",
39 "Opt-body-type",
40 "Options-TTL",
41 "Preview",
42 "Service",
43 "Service-ID",
44 "Transfer-Complete",
45 "Transfer-Ignore",
46 "Transfer-Preview"
47 };
48 static const Notes::Keys protectedFieldNames(std::begin(protectedFieldNamesRaw), std::end(protectedFieldNamesRaw));
49 Notes Adaptation::Config::metaHeaders("ICAP header", &protectedFieldNames);
50 bool Adaptation::Config::needHistory = false;
51
52 Adaptation::ServiceConfig*
53 Adaptation::Config::newServiceConfig() const
54 {
55 return new ServiceConfig();
56 }
57
58 void
59 Adaptation::Config::removeService(const String& service)
60 {
61 removeRule(service);
62 const Groups& groups = AllGroups();
63 for (unsigned int i = 0; i < groups.size(); ) {
64 const ServiceGroupPointer group = groups[i];
65 const ServiceGroup::Store& services = group->services;
66 typedef ServiceGroup::Store::const_iterator SGSI;
67 for (SGSI it = services.begin(); it != services.end(); ++it) {
68 if (*it == service) {
69 group->removedServices.push_back(service);
70 ServiceGroup::Store::iterator newend;
71 newend = std::remove(group->services.begin(), group->services.end(), service);
72 group->services.resize(newend-group->services.begin());
73 debugs(93, 5, "adaptation service " << service <<
74 " removed from group " << group->id);
75 break;
76 }
77 }
78 if (services.empty()) {
79 removeRule(group->id);
80 Groups::iterator newend;
81 newend = std::remove(AllGroups().begin(), AllGroups().end(), group);
82 AllGroups().resize(newend-AllGroups().begin());
83 } else {
84 ++i;
85 }
86 }
87 }
88
89 Adaptation::ServiceConfigPointer
90 Adaptation::Config::findServiceConfig(const String &service)
91 {
92 typedef ServiceConfigs::const_iterator SCI;
93 const ServiceConfigs& configs = serviceConfigs;
94 for (SCI cfg = configs.begin(); cfg != configs.end(); ++cfg) {
95 if ((*cfg)->key == service)
96 return *cfg;
97 }
98 return NULL;
99 }
100
101 void
102 Adaptation::Config::removeRule(const String& id)
103 {
104 typedef AccessRules::const_iterator ARI;
105 const AccessRules& rules = AllRules();
106 for (ARI it = rules.begin(); it != rules.end(); ++it) {
107 AccessRule* rule = *it;
108 if (rule->groupId == id) {
109 debugs(93, 5, "removing access rules for:" << id);
110 AccessRules::iterator newend;
111 newend = std::remove(AllRules().begin(), AllRules().end(), rule);
112 AllRules().resize(newend-AllRules().begin());
113 delete (rule);
114 break;
115 }
116 }
117 }
118
119 void
120 Adaptation::Config::clear()
121 {
122 debugs(93, 3, HERE << "rules: " << AllRules().size() << ", groups: " <<
123 AllGroups().size() << ", services: " << serviceConfigs.size());
124 typedef ServiceConfigs::const_iterator SCI;
125 const ServiceConfigs& configs = serviceConfigs;
126 for (SCI cfg = configs.begin(); cfg != configs.end(); ++cfg)
127 removeService((*cfg)->key);
128 serviceConfigs.clear();
129 debugs(93, 3, HERE << "rules: " << AllRules().size() << ", groups: " <<
130 AllGroups().size() << ", services: " << serviceConfigs.size());
131 }
132
133 void
134 Adaptation::Config::parseService()
135 {
136 ServiceConfigPointer cfg = newServiceConfig();
137 if (!cfg->parse()) {
138 fatalf("%s:%d: malformed adaptation service configuration",
139 cfg_filename, config_lineno);
140 }
141 serviceConfigs.push_back(cfg);
142 }
143
144 void
145 Adaptation::Config::freeService()
146 {
147 FreeAccess();
148 FreeServiceGroups();
149
150 DetachServices();
151
152 serviceConfigs.clear();
153 }
154
155 void
156 Adaptation::Config::dumpService(StoreEntry *entry, const char *name) const
157 {
158 typedef Services::iterator SCI;
159 for (SCI i = AllServices().begin(); i != AllServices().end(); ++i) {
160 const ServiceConfig &cfg = (*i)->cfg();
161 bool isEcap = cfg.protocol.caseCmp("ecap") == 0;
162 bool isIcap = !isEcap;
163 const char *optConnectionEncryption = "";
164 // Print connections_encrypted option if no default value is used
165 if (cfg.secure.encryptTransport && !cfg.connectionEncryption)
166 optConnectionEncryption = " connection-encryption=off";
167 else if (isEcap && !cfg.connectionEncryption)
168 optConnectionEncryption = " connection-encryption=off";
169 else if (isIcap && !cfg.secure.encryptTransport && cfg.connectionEncryption)
170 optConnectionEncryption = " connection-encryption=on";
171
172 storeAppendPrintf(entry, "%s " SQUIDSTRINGPH " %s_%s %d " SQUIDSTRINGPH "%s\n",
173 name,
174 SQUIDSTRINGPRINT(cfg.key),
175 cfg.methodStr(), cfg.vectPointStr(), cfg.bypass,
176 SQUIDSTRINGPRINT(cfg.uri),
177
178 optConnectionEncryption);
179 }
180 }
181
182 bool
183 Adaptation::Config::finalize()
184 {
185 if (!onoff) {
186 clear();
187 return false;
188 }
189
190 // create service reps from service configs
191 int created = 0;
192
193 typedef ServiceConfigs::const_iterator VISCI;
194 const ServiceConfigs &configs = serviceConfigs;
195 for (VISCI i = configs.begin(); i != configs.end(); ++i) {
196 const ServiceConfigPointer cfg = *i;
197 if (FindService(cfg->key) != NULL) {
198 debugs(93, DBG_CRITICAL, "ERROR: Duplicate adaptation service name: " <<
199 cfg->key);
200 continue; // TODO: make fatal
201 }
202 ServicePointer s = createService(cfg);
203 if (s != NULL) {
204 AllServices().push_back(s);
205 ++created;
206 }
207 }
208
209 debugs(93,3, HERE << "Created " << created << " adaptation services");
210
211 // services remember their configs; we do not have to
212 serviceConfigs.clear();
213 return true;
214 }
215
216 // poor man for_each
217 template <class Collection>
218 static void
219 FinalizeEach(Collection &collection, const char *label)
220 {
221 typedef typename Collection::iterator CI;
222 for (CI i = collection.begin(); i != collection.end(); ++i)
223 (*i)->finalize();
224
225 debugs(93,2, HERE << "Initialized " << collection.size() << ' ' << label);
226 }
227
228 void
229 Adaptation::Config::Finalize(bool enabled)
230 {
231 Enabled = enabled;
232 debugs(93, Important(11), "Adaptation support is " << (Enabled ? "on" : "off."));
233
234 FinalizeEach(AllServices(), "message adaptation services");
235 FinalizeEach(AllGroups(), "message adaptation service groups");
236 FinalizeEach(AllRules(), "message adaptation access rules");
237 }
238
239 void
240 Adaptation::Config::ParseServiceSet()
241 {
242 Adaptation::Config::ParseServiceGroup(new ServiceSet);
243 }
244
245 void
246 Adaptation::Config::ParseServiceChain()
247 {
248 Adaptation::Config::ParseServiceGroup(new ServiceChain);
249 }
250
251 void
252 Adaptation::Config::ParseServiceGroup(ServiceGroupPointer g)
253 {
254 assert(g != NULL);
255 g->parse();
256 AllGroups().push_back(g);
257 }
258
259 void
260 Adaptation::Config::FreeServiceGroups()
261 {
262 while (!AllGroups().empty()) {
263 // groups are refcounted so we do not explicitly delete them
264 AllGroups().pop_back();
265 }
266 }
267
268 void
269 Adaptation::Config::DumpServiceGroups(StoreEntry *entry, const char *name)
270 {
271 typedef Groups::iterator GI;
272 for (GI i = AllGroups().begin(); i != AllGroups().end(); ++i)
273 storeAppendPrintf(entry, "%s " SQUIDSTRINGPH "\n", name, SQUIDSTRINGPRINT((*i)->id));
274 }
275
276 void
277 Adaptation::Config::ParseAccess(ConfigParser &parser)
278 {
279 String groupId = ConfigParser::NextToken();
280 AccessRule *r;
281 if (!(r=FindRuleByGroupId(groupId))) {
282 r = new AccessRule(groupId);
283 AllRules().push_back(r);
284 }
285 r->parse(parser);
286 }
287
288 void
289 Adaptation::Config::FreeAccess()
290 {
291 while (!AllRules().empty()) {
292 delete AllRules().back();
293 AllRules().pop_back();
294 }
295 }
296
297 void
298 Adaptation::Config::DumpAccess(StoreEntry *entry, const char *name)
299 {
300 LOCAL_ARRAY(char, nom, 64);
301
302 typedef AccessRules::iterator CI;
303 for (CI i = AllRules().begin(); i != AllRules().end(); ++i) {
304 snprintf(nom, 64, "%s " SQUIDSTRINGPH, name, SQUIDSTRINGPRINT((*i)->groupId));
305 dump_acl_access(entry, nom, (*i)->acl);
306 }
307 }
308
309 Adaptation::Config::Config() :
310 onoff(0), service_failure_limit(0), oldest_service_failure(0),
311 service_revival_delay(0)
312 {}
313
314 // XXX: this is called for ICAP and eCAP configs, but deals mostly
315 // with global arrays shared by those individual configs
316 Adaptation::Config::~Config()
317 {
318 freeService();
319 }
320