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