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