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