]>
Commit | Line | Data |
---|---|---|
64bdef96 AR |
1 | |
2 | /* | |
262a0e14 | 3 | * $Id$ |
64bdef96 AR |
4 | * |
5 | * SQUID Web Proxy Cache http://www.squid-cache.org/ | |
6 | * ---------------------------------------------------------- | |
7 | * | |
8 | * Squid is the result of efforts by numerous individuals from | |
9 | * the Internet community; see the CONTRIBUTORS file for full | |
10 | * details. Many organizations have provided support for Squid's | |
11 | * development; see the SPONSORS file for full details. Squid is | |
12 | * Copyrighted (C) 2001 by the Regents of the University of | |
13 | * California; see the COPYRIGHT file for full details. Squid | |
14 | * incorporates software developed and/or copyrighted by other | |
15 | * sources; see the CREDITS file for full details. | |
16 | * | |
17 | * This program is free software; you can redistribute it and/or modify | |
18 | * it under the terms of the GNU General Public License as published by | |
19 | * the Free Software Foundation; either version 2 of the License, or | |
20 | * (at your option) any later version. | |
26ac0430 | 21 | * |
64bdef96 AR |
22 | * This program is distributed in the hope that it will be useful, |
23 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
24 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
25 | * GNU General Public License for more details. | |
26ac0430 | 26 | * |
64bdef96 AR |
27 | * You should have received a copy of the GNU General Public License |
28 | * along with this program; if not, write to the Free Software | |
29 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. | |
30 | * | |
31 | */ | |
32 | ||
582c2af2 | 33 | #include "squid.h" |
71be37e0 | 34 | #include "acl/FilledChecklist.h" |
582c2af2 FC |
35 | #include "acl/Gadgets.h" |
36 | #include "adaptation/AccessRule.h" | |
64bdef96 | 37 | #include "adaptation/Config.h" |
582c2af2 | 38 | #include "adaptation/History.h" |
64bdef96 | 39 | #include "adaptation/Service.h" |
62c7f90e | 40 | #include "adaptation/ServiceGroups.h" |
582c2af2 FC |
41 | #include "Array.h" |
42 | #include "ConfigParser.h" | |
43 | #include "globals.h" | |
44 | #include "HttpReply.h" | |
71be37e0 | 45 | #include "HttpRequest.h" |
582c2af2 FC |
46 | #include "Store.h" |
47 | #include "structs.h" | |
64bdef96 | 48 | |
8f361c50 | 49 | bool Adaptation::Config::Enabled = false; |
3ff65596 | 50 | char *Adaptation::Config::masterx_shared_name = NULL; |
a22e6cd3 | 51 | int Adaptation::Config::service_iteration_limit = 16; |
22fff3bf AR |
52 | int Adaptation::Config::send_client_ip = false; |
53 | int Adaptation::Config::send_username = false; | |
54 | int Adaptation::Config::use_indirect_client = true; | |
71be37e0 CT |
55 | Adaptation::Config::MetaHeaders Adaptation::Config::metaHeaders; |
56 | ||
71be37e0 CT |
57 | Adaptation::Config::MetaHeader::Value::~Value() |
58 | { | |
59 | aclDestroyAclList(&aclList); | |
60 | } | |
61 | ||
71ee0835 | 62 | Adaptation::Config::MetaHeader::Value::Pointer |
71be37e0 CT |
63 | Adaptation::Config::MetaHeader::addValue(const String &value) |
64 | { | |
65 | Value::Pointer v = new Value(value); | |
66 | values.push_back(v); | |
67 | return v; | |
68 | } | |
69 | ||
70 | const char * | |
71 | Adaptation::Config::MetaHeader::match(HttpRequest *request, HttpReply *reply) | |
72 | { | |
73 | ||
74 | typedef Values::iterator VLI; | |
75 | ACLFilledChecklist ch(NULL, request, NULL); | |
76 | if (reply) | |
77 | ch.reply = HTTPMSGLOCK(reply); | |
78 | ||
79 | for (VLI i = values.begin(); i != values.end(); ++i ) { | |
71ee0835 | 80 | const int ret= ch.fastCheck((*i)->aclList); |
71be37e0 CT |
81 | debugs(93, 5, HERE << "Check for header name: " << name << ": " << (*i)->value |
82 | <<", HttpRequest: " << request << " HttpReply: " << reply << " matched: " << ret); | |
83 | if (ret == ACCESS_ALLOWED) | |
84 | return (*i)->value.termedBuf(); | |
85 | } | |
86 | return NULL; | |
87 | } | |
88 | ||
71ee0835 | 89 | Adaptation::Config::MetaHeader::Pointer |
71be37e0 CT |
90 | Adaptation::Config::addMetaHeader(const String &headerName) |
91 | { | |
92 | typedef MetaHeaders::iterator AMLI; | |
71ee0835 | 93 | for (AMLI i = metaHeaders.begin(); i != metaHeaders.end(); ++i) { |
71be37e0 CT |
94 | if ((*i)->name == headerName) |
95 | return (*i); | |
96 | } | |
97 | ||
98 | MetaHeader::Pointer meta = new MetaHeader(headerName); | |
99 | metaHeaders.push_back(meta); | |
100 | return meta; | |
101 | } | |
8f361c50 | 102 | |
e1e90d26 AR |
103 | Adaptation::ServiceConfig* |
104 | Adaptation::Config::newServiceConfig() const | |
105 | { | |
106 | return new ServiceConfig(); | |
107 | } | |
108 | ||
7e8c4ee9 CT |
109 | void |
110 | Adaptation::Config::removeService(const String& service) | |
111 | { | |
112 | removeRule(service); | |
113 | const Groups& groups = AllGroups(); | |
114 | for (unsigned int i = 0; i < groups.size(); ) { | |
115 | const ServiceGroupPointer group = groups[i]; | |
116 | const ServiceGroup::Store& services = group->services; | |
117 | typedef ServiceGroup::Store::const_iterator SGSI; | |
118 | for (SGSI it = services.begin(); it != services.end(); ++it) { | |
119 | if (*it == service) { | |
120 | group->removedServices.push_back(service); | |
121 | group->services.prune(service); | |
208c88d5 | 122 | debugs(93, 5, HERE << "adaptation service " << service << |
7e8c4ee9 CT |
123 | " removed from group " << group->id); |
124 | break; | |
125 | } | |
126 | } | |
127 | if (services.empty()) { | |
128 | removeRule(group->id); | |
129 | AllGroups().prune(group); | |
130 | } else { | |
131 | ++i; | |
132 | } | |
133 | } | |
134 | } | |
135 | ||
136 | void | |
137 | Adaptation::Config::removeRule(const String& id) | |
138 | { | |
139 | typedef AccessRules::const_iterator ARI; | |
140 | const AccessRules& rules = AllRules(); | |
141 | for (ARI it = rules.begin(); it != rules.end(); ++it) { | |
142 | AccessRule* rule = *it; | |
143 | if (rule->groupId == id) { | |
144 | debugs(93, 5, HERE << "removing access rules for:" << id); | |
145 | AllRules().prune(rule); | |
146 | delete (rule); | |
147 | break; | |
148 | } | |
149 | } | |
150 | } | |
151 | ||
152 | void | |
153 | Adaptation::Config::clear() | |
154 | { | |
155 | debugs(93, 3, HERE << "rules: " << AllRules().size() << ", groups: " << | |
156 | AllGroups().size() << ", services: " << serviceConfigs.size()); | |
157 | typedef ServiceConfigs::const_iterator SCI; | |
158 | const ServiceConfigs& configs = serviceConfigs; | |
159 | for (SCI cfg = configs.begin(); cfg != configs.end(); ++cfg) | |
160 | removeService((*cfg)->key); | |
161 | serviceConfigs.clean(); | |
162 | debugs(93, 3, HERE << "rules: " << AllRules().size() << ", groups: " << | |
163 | AllGroups().size() << ", services: " << serviceConfigs.size()); | |
164 | } | |
165 | ||
64bdef96 AR |
166 | void |
167 | Adaptation::Config::parseService() | |
168 | { | |
e1e90d26 | 169 | ServiceConfigPointer cfg = newServiceConfig(); |
a22e6cd3 AR |
170 | if (!cfg->parse()) { |
171 | fatalf("%s:%d: malformed adaptation service configuration", | |
e1381638 | 172 | cfg_filename, config_lineno); |
a22e6cd3 | 173 | } |
64bdef96 AR |
174 | serviceConfigs.push_back(cfg); |
175 | } | |
176 | ||
177 | void | |
178 | Adaptation::Config::freeService() | |
179 | { | |
76fc7e57 AJ |
180 | FreeAccess(); |
181 | FreeServiceGroups(); | |
182 | ||
183 | DetachServices(); | |
184 | ||
e1e90d26 | 185 | serviceConfigs.clean(); |
71be37e0 CT |
186 | |
187 | FreeMetaHeader(); | |
64bdef96 AR |
188 | } |
189 | ||
190 | void | |
191 | Adaptation::Config::dumpService(StoreEntry *entry, const char *name) const | |
192 | { | |
193 | typedef Services::iterator SCI; | |
194 | for (SCI i = AllServices().begin(); i != AllServices().end(); ++i) { | |
195 | const ServiceConfig &cfg = (*i)->cfg(); | |
b4197865 | 196 | storeAppendPrintf(entry, "%s " SQUIDSTRINGPH "_%s %s %d " SQUIDSTRINGPH "\n", |
af6a12ee AJ |
197 | name, |
198 | SQUIDSTRINGPRINT(cfg.key), | |
199 | cfg.methodStr(), cfg.vectPointStr(), cfg.bypass, | |
200 | SQUIDSTRINGPRINT(cfg.uri)); | |
64bdef96 AR |
201 | } |
202 | } | |
203 | ||
7e8c4ee9 | 204 | bool |
64bdef96 AR |
205 | Adaptation::Config::finalize() |
206 | { | |
7e8c4ee9 CT |
207 | if (!onoff) { |
208 | clear(); | |
209 | return false; | |
210 | } | |
211 | ||
64bdef96 | 212 | // create service reps from service configs |
e1e90d26 AR |
213 | int created = 0; |
214 | ||
215 | typedef ServiceConfigs::const_iterator VISCI; | |
216 | const ServiceConfigs &configs = serviceConfigs; | |
62c7f90e | 217 | for (VISCI i = configs.begin(); i != configs.end(); ++i) { |
e1e90d26 AR |
218 | const ServiceConfigPointer cfg = *i; |
219 | if (FindService(cfg->key) != NULL) { | |
fa84c01d | 220 | debugs(93, DBG_CRITICAL, "ERROR: Duplicate adaptation service name: " << |
e1e90d26 | 221 | cfg->key); |
26ac0430 AJ |
222 | continue; // TODO: make fatal |
223 | } | |
e1e90d26 AR |
224 | ServicePointer s = createService(cfg); |
225 | if (s != NULL) { | |
62c7f90e | 226 | AllServices().push_back(s); |
742a021b | 227 | ++created; |
e1e90d26 | 228 | } |
64bdef96 AR |
229 | } |
230 | ||
e1e90d26 AR |
231 | debugs(93,3, HERE << "Created " << created << " adaptation services"); |
232 | ||
233 | // services remember their configs; we do not have to | |
234 | serviceConfigs.clean(); | |
7e8c4ee9 | 235 | return true; |
64bdef96 AR |
236 | } |
237 | ||
62c7f90e AR |
238 | // poor man for_each |
239 | template <class Collection> | |
240 | static void | |
241 | FinalizeEach(Collection &collection, const char *label) | |
64bdef96 | 242 | { |
62c7f90e AR |
243 | typedef typename Collection::iterator CI; |
244 | for (CI i = collection.begin(); i != collection.end(); ++i) | |
245 | (*i)->finalize(); | |
64bdef96 | 246 | |
192378eb | 247 | debugs(93,2, HERE << "Initialized " << collection.size() << ' ' << label); |
64bdef96 AR |
248 | } |
249 | ||
250 | void | |
8f361c50 | 251 | Adaptation::Config::Finalize(bool enabled) |
64bdef96 | 252 | { |
8f361c50 | 253 | Enabled = enabled; |
e0236918 | 254 | debugs(93, DBG_IMPORTANT, "Adaptation support is " << (Enabled ? "on" : "off.")); |
8f361c50 | 255 | |
62c7f90e AR |
256 | FinalizeEach(AllServices(), "message adaptation services"); |
257 | FinalizeEach(AllGroups(), "message adaptation service groups"); | |
258 | FinalizeEach(AllRules(), "message adaptation access rules"); | |
259 | } | |
64bdef96 | 260 | |
71be37e0 CT |
261 | void |
262 | Adaptation::Config::ParseMetaHeader(ConfigParser &parser) | |
263 | { | |
264 | String name, value; | |
265 | const char *warnFor[] = { | |
266 | "Methods", | |
267 | "Service", | |
268 | "ISTag", | |
269 | "Encapsulated", | |
270 | "Opt-body-type", | |
271 | "Max-Connections", | |
272 | "Options-TTL", | |
273 | "Date", | |
274 | "Service-ID", | |
275 | "Allow", | |
276 | "Preview", | |
277 | "Transfer-Preview", | |
278 | "Transfer-Ignore", | |
279 | "Transfer-Complete", | |
280 | NULL | |
281 | }; | |
282 | ConfigParser::ParseString(&name); | |
283 | ConfigParser::ParseQuotedString(&value); | |
284 | ||
285 | // TODO: Find a way to move this check to ICAP | |
742a021b | 286 | for (int i = 0; warnFor[i] != NULL; ++i) { |
71be37e0 CT |
287 | if (name.caseCmp(warnFor[i]) == 0) { |
288 | fatalf("%s:%d: meta name \"%s\" is a reserved ICAP header name", | |
289 | cfg_filename, config_lineno, name.termedBuf()); | |
290 | } | |
291 | } | |
292 | ||
293 | MetaHeader::Pointer meta = addMetaHeader(name); | |
294 | MetaHeader::Value::Pointer headValue = meta->addValue(value); | |
295 | aclParseAclList(parser, &headValue->aclList); | |
296 | } | |
297 | ||
298 | void | |
299 | Adaptation::Config::DumpMetaHeader(StoreEntry *entry, const char *name) | |
300 | { | |
301 | typedef MetaHeaders::iterator AMLI; | |
71ee0835 | 302 | for (AMLI m = metaHeaders.begin(); m != metaHeaders.end(); ++m) { |
71be37e0 CT |
303 | typedef MetaHeader::Values::iterator VLI; |
304 | for (VLI v =(*m)->values.begin(); v != (*m)->values.end(); ++v ) { | |
71ee0835 | 305 | storeAppendPrintf(entry, "%s " SQUIDSTRINGPH " %s", |
71be37e0 CT |
306 | name, SQUIDSTRINGPRINT((*m)->name), ConfigParser::QuoteString((*v)->value)); |
307 | dump_acl_list(entry, (*v)->aclList); | |
308 | storeAppendPrintf(entry, "\n"); | |
71ee0835 A |
309 | } |
310 | } | |
71be37e0 CT |
311 | } |
312 | ||
71ee0835 | 313 | void |
71be37e0 CT |
314 | Adaptation::Config::FreeMetaHeader() |
315 | { | |
316 | metaHeaders.clean(); | |
317 | } | |
318 | ||
64bdef96 | 319 | void |
62c7f90e | 320 | Adaptation::Config::ParseServiceSet() |
64bdef96 | 321 | { |
a22e6cd3 AR |
322 | Adaptation::Config::ParseServiceGroup(new ServiceSet); |
323 | } | |
324 | ||
325 | void | |
326 | Adaptation::Config::ParseServiceChain() | |
327 | { | |
328 | Adaptation::Config::ParseServiceGroup(new ServiceChain); | |
329 | } | |
330 | ||
331 | void | |
332 | Adaptation::Config::ParseServiceGroup(ServiceGroupPointer g) | |
333 | { | |
334 | assert(g != NULL); | |
62c7f90e AR |
335 | g->parse(); |
336 | AllGroups().push_back(g); | |
64bdef96 AR |
337 | } |
338 | ||
339 | void | |
a22e6cd3 | 340 | Adaptation::Config::FreeServiceGroups() |
64bdef96 | 341 | { |
62c7f90e | 342 | while (!AllGroups().empty()) { |
a22e6cd3 | 343 | // groups are refcounted so we do not explicitly delete them |
b6b637eb AR |
344 | AllGroups().pop_back(); |
345 | } | |
64bdef96 AR |
346 | } |
347 | ||
348 | void | |
a22e6cd3 | 349 | Adaptation::Config::DumpServiceGroups(StoreEntry *entry, const char *name) |
64bdef96 | 350 | { |
62c7f90e AR |
351 | typedef Groups::iterator GI; |
352 | for (GI i = AllGroups().begin(); i != AllGroups().end(); ++i) | |
2c1fd837 | 353 | storeAppendPrintf(entry, "%s " SQUIDSTRINGPH "\n", name, SQUIDSTRINGPRINT((*i)->id)); |
62c7f90e | 354 | } |
64bdef96 | 355 | |
62c7f90e AR |
356 | void |
357 | Adaptation::Config::ParseAccess(ConfigParser &parser) | |
358 | { | |
287bbe9a CT |
359 | String groupId; |
360 | ConfigParser::ParseString(&groupId); | |
361 | AccessRule *r; | |
899fad67 | 362 | if (!(r=FindRuleByGroupId(groupId))) { |
af6a12ee AJ |
363 | r = new AccessRule(groupId); |
364 | AllRules().push_back(r); | |
899fad67 | 365 | } |
62c7f90e | 366 | r->parse(parser); |
62c7f90e | 367 | } |
64bdef96 AR |
368 | |
369 | void | |
62c7f90e | 370 | Adaptation::Config::FreeAccess() |
64bdef96 | 371 | { |
62c7f90e AR |
372 | while (!AllRules().empty()) { |
373 | delete AllRules().back(); | |
374 | AllRules().pop_back(); | |
b6b637eb | 375 | } |
64bdef96 AR |
376 | } |
377 | ||
378 | void | |
62c7f90e | 379 | Adaptation::Config::DumpAccess(StoreEntry *entry, const char *name) |
64bdef96 AR |
380 | { |
381 | LOCAL_ARRAY(char, nom, 64); | |
382 | ||
62c7f90e AR |
383 | typedef AccessRules::iterator CI; |
384 | for (CI i = AllRules().begin(); i != AllRules().end(); ++i) { | |
2c1fd837 | 385 | snprintf(nom, 64, "%s " SQUIDSTRINGPH, name, SQUIDSTRINGPRINT((*i)->groupId)); |
62c7f90e | 386 | dump_acl_access(entry, nom, (*i)->acl); |
b6b637eb | 387 | } |
64bdef96 AR |
388 | } |
389 | ||
390 | Adaptation::Config::Config() | |
391 | { | |
392 | // XXX: should we init members? | |
393 | } | |
394 | ||
26ac0430 | 395 | // XXX: this is called for ICAP and eCAP configs, but deals mostly |
62c7f90e | 396 | // with global arrays shared by those individual configs |
64bdef96 AR |
397 | Adaptation::Config::~Config() |
398 | { | |
62c7f90e | 399 | freeService(); |
64bdef96 | 400 | } |