]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * Copyright (C) 1996-2015 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 "globals.h" | |
19 | #include "HttpReply.h" | |
20 | #include "HttpRequest.h" | |
21 | #include "Store.h" | |
22 | ||
23 | #include <algorithm> | |
24 | ||
25 | bool Adaptation::Config::Enabled = false; | |
26 | char *Adaptation::Config::masterx_shared_name = NULL; | |
27 | int Adaptation::Config::service_iteration_limit = 16; | |
28 | int Adaptation::Config::send_client_ip = false; | |
29 | int Adaptation::Config::send_username = false; | |
30 | int Adaptation::Config::use_indirect_client = true; | |
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 | }; | |
48 | Notes Adaptation::Config::metaHeaders("ICAP header", metasBlacklist, true); | |
49 | bool Adaptation::Config::needHistory = false; | |
50 | ||
51 | Adaptation::ServiceConfig* | |
52 | Adaptation::Config::newServiceConfig() const | |
53 | { | |
54 | return new ServiceConfig(); | |
55 | } | |
56 | ||
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); | |
69 | ServiceGroup::Store::iterator newend; | |
70 | newend = std::remove(group->services.begin(), group->services.end(), service); | |
71 | group->services.resize(newend-group->services.begin()); | |
72 | debugs(93, 5, "adaptation service " << service << | |
73 | " removed from group " << group->id); | |
74 | break; | |
75 | } | |
76 | } | |
77 | if (services.empty()) { | |
78 | removeRule(group->id); | |
79 | Groups::iterator newend; | |
80 | newend = std::remove(AllGroups().begin(), AllGroups().end(), group); | |
81 | AllGroups().resize(newend-AllGroups().begin()); | |
82 | } else { | |
83 | ++i; | |
84 | } | |
85 | } | |
86 | } | |
87 | ||
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 | ||
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) { | |
108 | debugs(93, 5, "removing access rules for:" << id); | |
109 | AccessRules::iterator newend; | |
110 | newend = std::remove(AllRules().begin(), AllRules().end(), rule); | |
111 | AllRules().resize(newend-AllRules().begin()); | |
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); | |
127 | serviceConfigs.clear(); | |
128 | debugs(93, 3, HERE << "rules: " << AllRules().size() << ", groups: " << | |
129 | AllGroups().size() << ", services: " << serviceConfigs.size()); | |
130 | } | |
131 | ||
132 | void | |
133 | Adaptation::Config::parseService() | |
134 | { | |
135 | ServiceConfigPointer cfg = newServiceConfig(); | |
136 | if (!cfg->parse()) { | |
137 | fatalf("%s:%d: malformed adaptation service configuration", | |
138 | cfg_filename, config_lineno); | |
139 | } | |
140 | serviceConfigs.push_back(cfg); | |
141 | } | |
142 | ||
143 | void | |
144 | Adaptation::Config::freeService() | |
145 | { | |
146 | FreeAccess(); | |
147 | FreeServiceGroups(); | |
148 | ||
149 | DetachServices(); | |
150 | ||
151 | serviceConfigs.clear(); | |
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(); | |
160 | storeAppendPrintf(entry, "%s " SQUIDSTRINGPH "_%s %s %d " SQUIDSTRINGPH "\n", | |
161 | name, | |
162 | SQUIDSTRINGPRINT(cfg.key), | |
163 | cfg.methodStr(), cfg.vectPointStr(), cfg.bypass, | |
164 | SQUIDSTRINGPRINT(cfg.uri)); | |
165 | } | |
166 | } | |
167 | ||
168 | bool | |
169 | Adaptation::Config::finalize() | |
170 | { | |
171 | if (!onoff) { | |
172 | clear(); | |
173 | return false; | |
174 | } | |
175 | ||
176 | // create service reps from service configs | |
177 | int created = 0; | |
178 | ||
179 | typedef ServiceConfigs::const_iterator VISCI; | |
180 | const ServiceConfigs &configs = serviceConfigs; | |
181 | for (VISCI i = configs.begin(); i != configs.end(); ++i) { | |
182 | const ServiceConfigPointer cfg = *i; | |
183 | if (FindService(cfg->key) != NULL) { | |
184 | debugs(93, DBG_CRITICAL, "ERROR: Duplicate adaptation service name: " << | |
185 | cfg->key); | |
186 | continue; // TODO: make fatal | |
187 | } | |
188 | ServicePointer s = createService(cfg); | |
189 | if (s != NULL) { | |
190 | AllServices().push_back(s); | |
191 | ++created; | |
192 | } | |
193 | } | |
194 | ||
195 | debugs(93,3, HERE << "Created " << created << " adaptation services"); | |
196 | ||
197 | // services remember their configs; we do not have to | |
198 | serviceConfigs.clear(); | |
199 | return true; | |
200 | } | |
201 | ||
202 | // poor man for_each | |
203 | template <class Collection> | |
204 | static void | |
205 | FinalizeEach(Collection &collection, const char *label) | |
206 | { | |
207 | typedef typename Collection::iterator CI; | |
208 | for (CI i = collection.begin(); i != collection.end(); ++i) | |
209 | (*i)->finalize(); | |
210 | ||
211 | debugs(93,2, HERE << "Initialized " << collection.size() << ' ' << label); | |
212 | } | |
213 | ||
214 | void | |
215 | Adaptation::Config::Finalize(bool enabled) | |
216 | { | |
217 | Enabled = enabled; | |
218 | debugs(93, DBG_IMPORTANT, "Adaptation support is " << (Enabled ? "on" : "off.")); | |
219 | ||
220 | FinalizeEach(AllServices(), "message adaptation services"); | |
221 | FinalizeEach(AllGroups(), "message adaptation service groups"); | |
222 | FinalizeEach(AllRules(), "message adaptation access rules"); | |
223 | } | |
224 | ||
225 | void | |
226 | Adaptation::Config::ParseServiceSet() | |
227 | { | |
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); | |
241 | g->parse(); | |
242 | AllGroups().push_back(g); | |
243 | } | |
244 | ||
245 | void | |
246 | Adaptation::Config::FreeServiceGroups() | |
247 | { | |
248 | while (!AllGroups().empty()) { | |
249 | // groups are refcounted so we do not explicitly delete them | |
250 | AllGroups().pop_back(); | |
251 | } | |
252 | } | |
253 | ||
254 | void | |
255 | Adaptation::Config::DumpServiceGroups(StoreEntry *entry, const char *name) | |
256 | { | |
257 | typedef Groups::iterator GI; | |
258 | for (GI i = AllGroups().begin(); i != AllGroups().end(); ++i) | |
259 | storeAppendPrintf(entry, "%s " SQUIDSTRINGPH "\n", name, SQUIDSTRINGPRINT((*i)->id)); | |
260 | } | |
261 | ||
262 | void | |
263 | Adaptation::Config::ParseAccess(ConfigParser &parser) | |
264 | { | |
265 | String groupId = ConfigParser::NextToken(); | |
266 | AccessRule *r; | |
267 | if (!(r=FindRuleByGroupId(groupId))) { | |
268 | r = new AccessRule(groupId); | |
269 | AllRules().push_back(r); | |
270 | } | |
271 | r->parse(parser); | |
272 | } | |
273 | ||
274 | void | |
275 | Adaptation::Config::FreeAccess() | |
276 | { | |
277 | while (!AllRules().empty()) { | |
278 | delete AllRules().back(); | |
279 | AllRules().pop_back(); | |
280 | } | |
281 | } | |
282 | ||
283 | void | |
284 | Adaptation::Config::DumpAccess(StoreEntry *entry, const char *name) | |
285 | { | |
286 | LOCAL_ARRAY(char, nom, 64); | |
287 | ||
288 | typedef AccessRules::iterator CI; | |
289 | for (CI i = AllRules().begin(); i != AllRules().end(); ++i) { | |
290 | snprintf(nom, 64, "%s " SQUIDSTRINGPH, name, SQUIDSTRINGPRINT((*i)->groupId)); | |
291 | dump_acl_access(entry, nom, (*i)->acl); | |
292 | } | |
293 | } | |
294 | ||
295 | Adaptation::Config::Config() : | |
296 | onoff(0), service_failure_limit(0), oldest_service_failure(0), | |
297 | service_revival_delay(0) | |
298 | {} | |
299 | ||
300 | // XXX: this is called for ICAP and eCAP configs, but deals mostly | |
301 | // with global arrays shared by those individual configs | |
302 | Adaptation::Config::~Config() | |
303 | { | |
304 | freeService(); | |
305 | } | |
306 |