2 * Copyright (C) 1996-2025 The Squid Software Foundation and contributors
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.
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"
18 #include "ConfigParser.h"
19 #include "debug/Messages.h"
21 #include "HttpReply.h"
22 #include "HttpRequest.h"
27 bool Adaptation::Config::Enabled
= false;
28 char *Adaptation::Config::masterx_shared_name
= nullptr;
29 int Adaptation::Config::service_iteration_limit
= 16;
30 int Adaptation::Config::send_client_ip
= false;
31 int Adaptation::Config::send_username
= false;
32 int Adaptation::Config::use_indirect_client
= true;
35 Adaptation::Config::metaHeaders()
37 static const auto protectedFieldNamesRaw
= {
53 static const Notes::Keys
protectedFieldNames(std::begin(protectedFieldNamesRaw
), std::end(protectedFieldNamesRaw
));
54 static const auto metaHeaders
= new Notes("ICAP header", &protectedFieldNames
);
57 bool Adaptation::Config::needHistory
= false;
59 Adaptation::ServiceConfig
*
60 Adaptation::Config::newServiceConfig() const
62 return new ServiceConfig();
66 Adaptation::Config::removeService(const String
& 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
) {
76 group
->removedServices
.push_back(service
);
77 ServiceGroup::Store::iterator newend
;
78 newend
= std::remove(group
->services
.begin(), group
->services
.end(), service
);
79 group
->services
.resize(newend
-group
->services
.begin());
80 debugs(93, 5, "adaptation service " << service
<<
81 " removed from group " << group
->id
);
85 if (services
.empty()) {
86 removeRule(group
->id
);
87 Groups::iterator newend
;
88 newend
= std::remove(AllGroups().begin(), AllGroups().end(), group
);
89 AllGroups().resize(newend
-AllGroups().begin());
96 Adaptation::ServiceConfigPointer
97 Adaptation::Config::findServiceConfig(const String
&service
)
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
)
109 Adaptation::Config::removeRule(const String
& id
)
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
) {
116 debugs(93, 5, "removing access rules for:" << id
);
117 AccessRules::iterator newend
;
118 newend
= std::remove(AllRules().begin(), AllRules().end(), rule
);
119 AllRules().resize(newend
-AllRules().begin());
127 Adaptation::Config::clear()
129 debugs(93, 3, "rules: " << AllRules().size() << ", groups: " <<
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
);
135 serviceConfigs
.clear();
136 debugs(93, 3, "rules: " << AllRules().size() << ", groups: " <<
137 AllGroups().size() << ", services: " << serviceConfigs
.size());
141 Adaptation::Config::parseService()
143 ServiceConfigPointer cfg
= newServiceConfig();
145 fatalf("%s:%d: malformed adaptation service configuration",
146 cfg_filename
, config_lineno
);
148 serviceConfigs
.push_back(cfg
);
152 Adaptation::Config::freeService()
159 serviceConfigs
.clear();
163 Adaptation::Config::dumpService(StoreEntry
*entry
, const char *name
) const
165 typedef Services::iterator SCI
;
166 for (SCI i
= AllServices().begin(); i
!= AllServices().end(); ++i
) {
167 const ServiceConfig
&cfg
= (*i
)->cfg();
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";
179 storeAppendPrintf(entry
, "%s " SQUIDSTRINGPH
" %s_%s %d " SQUIDSTRINGPH
"%s\n",
181 SQUIDSTRINGPRINT(cfg
.key
),
182 cfg
.methodStr(), cfg
.vectPointStr(), cfg
.bypass
,
183 SQUIDSTRINGPRINT(cfg
.uri
),
185 optConnectionEncryption
);
190 Adaptation::Config::finalize()
197 // create service reps from service configs
200 typedef ServiceConfigs::const_iterator VISCI
;
201 const ServiceConfigs
&configs
= serviceConfigs
;
202 for (VISCI i
= configs
.begin(); i
!= configs
.end(); ++i
) {
203 const ServiceConfigPointer cfg
= *i
;
204 if (FindService(cfg
->key
) != nullptr) {
205 debugs(93, DBG_CRITICAL
, "ERROR: Duplicate adaptation service name: " <<
207 continue; // TODO: make fatal
209 ServicePointer s
= createService(cfg
);
211 AllServices().push_back(s
);
216 debugs(93,3, "Created " << created
<< " adaptation services");
218 // services remember their configs; we do not have to
219 serviceConfigs
.clear();
224 template <class Collection
>
226 FinalizeEach(Collection
&collection
, const char *label
)
228 typedef typename
Collection::iterator CI
;
229 for (CI i
= collection
.begin(); i
!= collection
.end(); ++i
)
232 debugs(93,2, "Initialized " << collection
.size() << ' ' << label
);
236 Adaptation::Config::Finalize(bool enabled
)
239 debugs(93, Important(11), "Adaptation support is " << (Enabled
? "on" : "off."));
241 FinalizeEach(AllServices(), "message adaptation services");
242 FinalizeEach(AllGroups(), "message adaptation service groups");
243 FinalizeEach(AllRules(), "message adaptation access rules");
247 Adaptation::Config::ParseServiceSet()
249 Adaptation::Config::ParseServiceGroup(new ServiceSet
);
253 Adaptation::Config::ParseServiceChain()
255 Adaptation::Config::ParseServiceGroup(new ServiceChain
);
259 Adaptation::Config::ParseServiceGroup(ServiceGroupPointer g
)
261 assert(g
!= nullptr);
263 AllGroups().push_back(g
);
267 Adaptation::Config::FreeServiceGroups()
269 while (!AllGroups().empty()) {
270 // groups are refcounted so we do not explicitly delete them
271 AllGroups().pop_back();
276 Adaptation::Config::DumpServiceGroups(StoreEntry
*entry
, const char *name
)
278 typedef Groups::iterator GI
;
279 for (GI i
= AllGroups().begin(); i
!= AllGroups().end(); ++i
)
280 storeAppendPrintf(entry
, "%s " SQUIDSTRINGPH
"\n", name
, SQUIDSTRINGPRINT((*i
)->id
));
284 Adaptation::Config::ParseAccess(ConfigParser
&parser
)
286 String groupId
= ConfigParser::NextToken();
288 if (!(r
=FindRuleByGroupId(groupId
))) {
289 r
= new AccessRule(groupId
);
290 AllRules().push_back(r
);
296 Adaptation::Config::FreeAccess()
298 while (!AllRules().empty()) {
299 delete AllRules().back();
300 AllRules().pop_back();
305 Adaptation::Config::DumpAccess(StoreEntry
*entry
, const char *name
)
307 LOCAL_ARRAY(char, nom
, 64);
309 typedef AccessRules::iterator CI
;
310 for (CI i
= AllRules().begin(); i
!= AllRules().end(); ++i
) {
311 snprintf(nom
, 64, "%s " SQUIDSTRINGPH
, name
, SQUIDSTRINGPRINT((*i
)->groupId
));
312 dump_acl_access(entry
, nom
, (*i
)->acl
);
316 Adaptation::Config::Config() :
317 onoff(0), service_failure_limit(0), oldest_service_failure(0),
318 service_revival_delay(0)
321 // XXX: this is called for ICAP and eCAP configs, but deals mostly
322 // with global arrays shared by those individual configs
323 Adaptation::Config::~Config()