]> git.ipfire.org Git - thirdparty/squid.git/blob - src/cache_cf.cc
Renamed squid.h to squid-old.h and config.h to squid.h
[thirdparty/squid.git] / src / cache_cf.cc
1 /*
2 * $Id$
3 *
4 * DEBUG: section 03 Configuration File Parsing
5 * AUTHOR: Harvest Derived
6 *
7 * SQUID Web Proxy Cache http://www.squid-cache.org/
8 * ----------------------------------------------------------
9 *
10 * Squid is the result of efforts by numerous individuals from
11 * the Internet community; see the CONTRIBUTORS file for full
12 * details. Many organizations have provided support for Squid's
13 * development; see the SPONSORS file for full details. Squid is
14 * Copyrighted (C) 2001 by the Regents of the University of
15 * California; see the COPYRIGHT file for full details. Squid
16 * incorporates software developed and/or copyrighted by other
17 * sources; see the CREDITS file for full details.
18 *
19 * This program is free software; you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License as published by
21 * the Free Software Foundation; either version 2 of the License, or
22 * (at your option) any later version.
23 *
24 * This program is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 * GNU General Public License for more details.
28 *
29 * You should have received a copy of the GNU General Public License
30 * along with this program; if not, write to the Free Software
31 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
32 *
33 */
34
35 #include "squid-old.h"
36
37 #include "acl/Acl.h"
38 #include "acl/Gadgets.h"
39 #include "acl/MethodData.h"
40 #if USE_ADAPTATION
41 #include "adaptation/Config.h"
42 #endif
43 #if ICAP_CLIENT
44 #include "adaptation/icap/Config.h"
45 #endif
46 #if USE_ECAP
47 #include "adaptation/ecap/Config.h"
48 #endif
49 #if USE_SSL
50 #include "ssl/support.h"
51 #include "ssl/Config.h"
52 #endif
53 #if USE_AUTH
54 #include "auth/Config.h"
55 #include "auth/Scheme.h"
56 #endif
57 #include "ConfigParser.h"
58 #include "CpuAffinityMap.h"
59 #include "DiskIO/DiskIOModule.h"
60 #include "eui/Config.h"
61 #if USE_SQUID_ESI
62 #include "esi/Parser.h"
63 #endif
64 #include "format/Format.h"
65 #include "HttpRequestMethod.h"
66 #include "ident/Config.h"
67 #include "ip/Intercept.h"
68 #include "ip/QosConfig.h"
69 #include "ip/tools.h"
70 #include "log/Config.h"
71 #include "MemBuf.h"
72 #include "mgr/Registration.h"
73 #include "Parsing.h"
74 #include "ProtoPort.h"
75 #include "rfc1738.h"
76 #if SQUID_SNMP
77 #include "snmp.h"
78 #endif
79 #include "Store.h"
80 #include "StoreFileSystem.h"
81 #include "SwapDir.h"
82 #include "wordlist.h"
83 #include "ipc/Kids.h"
84
85 #if HAVE_GLOB_H
86 #include <glob.h>
87 #endif
88
89 #if HAVE_LIMITS_H
90 #include <limits>
91 #endif
92
93 #if USE_SSL
94 #include "ssl/gadgets.h"
95 #endif
96
97 #if USE_ADAPTATION
98 static void parse_adaptation_service_set_type();
99 static void parse_adaptation_service_chain_type();
100 static void parse_adaptation_access_type();
101 static void parse_adaptation_meta_type(Adaptation::Config::MetaHeaders *);
102 static void dump_adaptation_meta_type(StoreEntry *, const char *, Adaptation::Config::MetaHeaders &);
103 static void free_adaptation_meta_type(Adaptation::Config::MetaHeaders *);
104 #endif
105
106 #if ICAP_CLIENT
107 static void parse_icap_service_type(Adaptation::Icap::Config *);
108 static void dump_icap_service_type(StoreEntry *, const char *, const Adaptation::Icap::Config &);
109 static void free_icap_service_type(Adaptation::Icap::Config *);
110 static void parse_icap_class_type();
111 static void parse_icap_access_type();
112
113 static void parse_icap_service_failure_limit(Adaptation::Icap::Config *);
114 static void dump_icap_service_failure_limit(StoreEntry *, const char *, const Adaptation::Icap::Config &);
115 static void free_icap_service_failure_limit(Adaptation::Icap::Config *);
116 #endif
117
118 #if USE_ECAP
119 static void parse_ecap_service_type(Adaptation::Ecap::Config *);
120 static void dump_ecap_service_type(StoreEntry *, const char *, const Adaptation::Ecap::Config &);
121 static void free_ecap_service_type(Adaptation::Ecap::Config *);
122 #endif
123
124 CBDATA_TYPE(peer);
125
126 static const char *const T_MILLISECOND_STR = "millisecond";
127 static const char *const T_SECOND_STR = "second";
128 static const char *const T_MINUTE_STR = "minute";
129 static const char *const T_HOUR_STR = "hour";
130 static const char *const T_DAY_STR = "day";
131 static const char *const T_WEEK_STR = "week";
132 static const char *const T_FORTNIGHT_STR = "fortnight";
133 static const char *const T_MONTH_STR = "month";
134 static const char *const T_YEAR_STR = "year";
135 static const char *const T_DECADE_STR = "decade";
136
137 static const char *const B_BYTES_STR = "bytes";
138 static const char *const B_KBYTES_STR = "KB";
139 static const char *const B_MBYTES_STR = "MB";
140 static const char *const B_GBYTES_STR = "GB";
141
142 static const char *const list_sep = ", \t\n\r";
143
144 static void parse_access_log(customlog ** customlog_definitions);
145 static int check_null_access_log(customlog *customlog_definitions);
146 static void dump_access_log(StoreEntry * entry, const char *name, customlog * definitions);
147 static void free_access_log(customlog ** definitions);
148
149 static void update_maxobjsize(void);
150 static void configDoConfigure(void);
151 static void parse_refreshpattern(refresh_t **);
152 static uint64_t parseTimeUnits(const char *unit, bool allowMsec);
153 static void parseTimeLine(time_msec_t * tptr, const char *units, bool allowMsec);
154 static void parse_u_short(unsigned short * var);
155 static void parse_string(char **);
156 static void default_all(void);
157 static void defaults_if_none(void);
158 static int parse_line(char *);
159 static void parse_obsolete(const char *);
160 static void parseBytesLine(size_t * bptr, const char *units);
161 #if USE_SSL
162 static void parseBytesOptionValue(size_t * bptr, const char *units, char const * value);
163 #endif
164 #if !USE_DNSHELPER
165 static void parseBytesLineSigned(ssize_t * bptr, const char *units);
166 #endif
167 static size_t parseBytesUnits(const char *unit);
168 static void free_all(void);
169 void requirePathnameExists(const char *name, const char *path);
170 static OBJH dump_config;
171 #if USE_HTTP_VIOLATIONS
172 static void dump_http_header_access(StoreEntry * entry, const char *name, header_mangler header[]);
173 static void parse_http_header_access(header_mangler header[]);
174 static void free_http_header_access(header_mangler header[]);
175 static void dump_http_header_replace(StoreEntry * entry, const char *name, header_mangler header[]);
176 static void parse_http_header_replace(header_mangler * header);
177 static void free_http_header_replace(header_mangler * header);
178 #endif
179 static void parse_denyinfo(acl_deny_info_list ** var);
180 static void dump_denyinfo(StoreEntry * entry, const char *name, acl_deny_info_list * var);
181 static void free_denyinfo(acl_deny_info_list ** var);
182
183 #if USE_WCCPv2
184 static void parse_IpAddress_list(Ip::Address_list **);
185 static void dump_IpAddress_list(StoreEntry *, const char *, const Ip::Address_list *);
186 static void free_IpAddress_list(Ip::Address_list **);
187 #if CURRENTLY_UNUSED
188 static int check_null_IpAddress_list(const Ip::Address_list *);
189 #endif /* CURRENTLY_UNUSED */
190 #endif /* USE_WCCPv2 */
191
192 static void parsePortList(http_port_list **, const char *protocol);
193 #define parse_http_port_list(l) parsePortList((l),"http")
194 static void dump_http_port_list(StoreEntry *, const char *, const http_port_list *);
195 static void free_http_port_list(http_port_list **);
196
197 #if USE_SSL
198 #define parse_https_port_list(l) parsePortList((l),"https")
199 #define dump_https_port_list(e,n,l) dump_http_port_list((e),(n),(l))
200 #define free_https_port_list(l) free_http_port_list((l))
201 #define check_null_https_port_list(l) check_null_http_port_list((l))
202 #endif /* USE_SSL */
203
204 static void parse_b_size_t(size_t * var);
205 static void parse_b_int64_t(int64_t * var);
206
207 static bool parseNamedIntList(const char *data, const String &name, Vector<int> &list);
208
209 static void parse_CpuAffinityMap(CpuAffinityMap **const cpuAffinityMap);
210 static void dump_CpuAffinityMap(StoreEntry *const entry, const char *const name, const CpuAffinityMap *const cpuAffinityMap);
211 static void free_CpuAffinityMap(CpuAffinityMap **const cpuAffinityMap);
212
213 static int parseOneConfigFile(const char *file_name, unsigned int depth);
214
215 /*
216 * LegacyParser is a parser for legacy code that uses the global
217 * approach. This is static so that it is only exposed to cache_cf.
218 * Other modules needing access to a ConfigParser should have it
219 * provided to them in their parserFOO methods.
220 */
221 static ConfigParser LegacyParser = ConfigParser();
222
223 void
224 self_destruct(void)
225 {
226 LegacyParser.destruct();
227 }
228
229 static void
230 update_maxobjsize(void)
231 {
232 int i;
233 int64_t ms = -1;
234
235 for (i = 0; i < Config.cacheSwap.n_configured; i++) {
236 assert (Config.cacheSwap.swapDirs[i].getRaw());
237
238 if (dynamic_cast<SwapDir *>(Config.cacheSwap.swapDirs[i].getRaw())->
239 max_objsize > ms)
240 ms = dynamic_cast<SwapDir *>(Config.cacheSwap.swapDirs[i].getRaw())->max_objsize;
241 }
242 store_maxobjsize = ms;
243 }
244
245 static void
246 SetConfigFilename(char const *file_name, bool is_pipe)
247 {
248 cfg_filename = file_name;
249
250 char const *token;
251
252 if (is_pipe)
253 cfg_filename = file_name + 1;
254 else if ((token = strrchr(cfg_filename, '/')))
255 cfg_filename = token + 1;
256 }
257
258 static const char*
259 skip_ws(const char* s)
260 {
261 while (xisspace(*s))
262 ++s;
263
264 return s;
265 }
266
267 static int
268 parseManyConfigFiles(char* files, int depth)
269 {
270 int error_count = 0;
271 char* saveptr = NULL;
272 #if HAVE_GLOB
273 char *path;
274 glob_t globbuf;
275 int i;
276 memset(&globbuf, 0, sizeof(globbuf));
277 for (path = strwordtok(files, &saveptr); path; path = strwordtok(NULL, &saveptr)) {
278 if (glob(path, globbuf.gl_pathc ? GLOB_APPEND : 0, NULL, &globbuf) != 0) {
279 fatalf("Unable to find configuration file: %s: %s",
280 path, xstrerror());
281 }
282 }
283 for (i = 0; i < (int)globbuf.gl_pathc; i++) {
284 error_count += parseOneConfigFile(globbuf.gl_pathv[i], depth);
285 }
286 globfree(&globbuf);
287 #else
288 char* file = strwordtok(files, &saveptr);
289 while (file != NULL) {
290 error_count += parseOneConfigFile(file, depth);
291 file = strwordtok(NULL, &saveptr);
292 }
293 #endif /* HAVE_GLOB */
294 return error_count;
295 }
296
297 static void
298 ReplaceSubstr(char*& str, int& len, unsigned substrIdx, unsigned substrLen, const char* newSubstr)
299 {
300 assert(str != NULL);
301 assert(newSubstr != NULL);
302
303 unsigned newSubstrLen = strlen(newSubstr);
304 if (newSubstrLen > substrLen)
305 str = (char*)realloc(str, len - substrLen + newSubstrLen + 1);
306
307 // move tail part including zero
308 memmove(str + substrIdx + newSubstrLen, str + substrIdx + substrLen, len - substrIdx - substrLen + 1);
309 // copy new substring in place
310 memcpy(str + substrIdx, newSubstr, newSubstrLen);
311
312 len = strlen(str);
313 }
314
315 static void
316 SubstituteMacro(char*& line, int& len, const char* macroName, const char* substStr)
317 {
318 assert(line != NULL);
319 assert(macroName != NULL);
320 assert(substStr != NULL);
321 unsigned macroNameLen = strlen(macroName);
322 while (const char* macroPos = strstr(line, macroName)) // we would replace all occurrences
323 ReplaceSubstr(line, len, macroPos - line, macroNameLen, substStr);
324 }
325
326 static void
327 ProcessMacros(char*& line, int& len)
328 {
329 SubstituteMacro(line, len, "${process_name}", TheKidName);
330 SubstituteMacro(line, len, "${process_number}", xitoa(KidIdentifier));
331 }
332
333 static void
334 trim_trailing_ws(char* str)
335 {
336 assert(str != NULL);
337 unsigned i = strlen(str);
338 while ((i > 0) && xisspace(str[i - 1]))
339 --i;
340 str[i] = '\0';
341 }
342
343 static const char*
344 FindStatement(const char* line, const char* statement)
345 {
346 assert(line != NULL);
347 assert(statement != NULL);
348
349 const char* str = skip_ws(line);
350 unsigned len = strlen(statement);
351 if (strncmp(str, statement, len) == 0) {
352 str += len;
353 if (*str == '\0')
354 return str;
355 else if (xisspace(*str))
356 return skip_ws(str);
357 }
358
359 return NULL;
360 }
361
362 static bool
363 StrToInt(const char* str, long& number)
364 {
365 assert(str != NULL);
366
367 char* end;
368 number = strtol(str, &end, 0);
369
370 return (end != str) && (*end == '\0'); // returns true if string contains nothing except number
371 }
372
373 static bool
374 EvalBoolExpr(const char* expr)
375 {
376 assert(expr != NULL);
377 if (strcmp(expr, "true") == 0) {
378 return true;
379 } else if (strcmp(expr, "false") == 0) {
380 return false;
381 } else if (const char* equation = strchr(expr, '=')) {
382 const char* rvalue = skip_ws(equation + 1);
383 char* lvalue = (char*)xmalloc(equation - expr + 1);
384 xstrncpy(lvalue, expr, equation - expr + 1);
385 trim_trailing_ws(lvalue);
386
387 long number1;
388 if (!StrToInt(lvalue, number1))
389 fatalf("String is not a integer number: '%s'\n", lvalue);
390 long number2;
391 if (!StrToInt(rvalue, number2))
392 fatalf("String is not a integer number: '%s'\n", rvalue);
393
394 xfree(lvalue);
395 return number1 == number2;
396 }
397 fatalf("Unable to evaluate expression '%s'\n", expr);
398 return false; // this place cannot be reached
399 }
400
401 static int
402 parseOneConfigFile(const char *file_name, unsigned int depth)
403 {
404 FILE *fp = NULL;
405 const char *orig_cfg_filename = cfg_filename;
406 const int orig_config_lineno = config_lineno;
407 char *token = NULL;
408 char *tmp_line = NULL;
409 int tmp_line_len = 0;
410 int err_count = 0;
411 int is_pipe = 0;
412
413 debugs(3, 1, "Processing Configuration File: " << file_name << " (depth " << depth << ")");
414 if (depth > 16) {
415 fatalf("WARNING: can't include %s: includes are nested too deeply (>16)!\n", file_name);
416 return 1;
417 }
418
419 if (file_name[0] == '!' || file_name[0] == '|') {
420 fp = popen(file_name + 1, "r");
421 is_pipe = 1;
422 } else {
423 fp = fopen(file_name, "r");
424 }
425
426 if (fp == NULL)
427 fatalf("Unable to open configuration file: %s: %s", file_name, xstrerror());
428
429 #if _SQUID_WINDOWS_
430 setmode(fileno(fp), O_TEXT);
431 #endif
432
433 SetConfigFilename(file_name, bool(is_pipe));
434
435 memset(config_input_line, '\0', BUFSIZ);
436
437 config_lineno = 0;
438
439 Vector<bool> if_states;
440 while (fgets(config_input_line, BUFSIZ, fp)) {
441 config_lineno++;
442
443 if ((token = strchr(config_input_line, '\n')))
444 *token = '\0';
445
446 if ((token = strchr(config_input_line, '\r')))
447 *token = '\0';
448
449 // strip any prefix whitespace off the line.
450 const char *p = skip_ws(config_input_line);
451 if (config_input_line != p)
452 memmove(config_input_line, p, strlen(p)+1);
453
454 if (strncmp(config_input_line, "#line ", 6) == 0) {
455 static char new_file_name[1024];
456 static char *file;
457 static char new_lineno;
458 token = config_input_line + 6;
459 new_lineno = strtol(token, &file, 0) - 1;
460
461 if (file == token)
462 continue; /* Not a valid #line directive, may be a comment */
463
464 while (*file && xisspace((unsigned char) *file))
465 file++;
466
467 if (*file) {
468 if (*file != '"')
469 continue; /* Not a valid #line directive, may be a comment */
470
471 xstrncpy(new_file_name, file + 1, sizeof(new_file_name));
472
473 if ((token = strchr(new_file_name, '"')))
474 *token = '\0';
475
476 cfg_filename = new_file_name;
477 }
478
479 config_lineno = new_lineno;
480 }
481
482 if (config_input_line[0] == '#')
483 continue;
484
485 if (config_input_line[0] == '\0')
486 continue;
487
488 const char* append = tmp_line_len ? skip_ws(config_input_line) : config_input_line;
489
490 size_t append_len = strlen(append);
491
492 tmp_line = (char*)xrealloc(tmp_line, tmp_line_len + append_len + 1);
493
494 strcpy(tmp_line + tmp_line_len, append);
495
496 tmp_line_len += append_len;
497
498 if (tmp_line[tmp_line_len-1] == '\\') {
499 debugs(3, 5, "parseConfigFile: tmp_line='" << tmp_line << "'");
500 tmp_line[--tmp_line_len] = '\0';
501 continue;
502 }
503
504 trim_trailing_ws(tmp_line);
505 ProcessMacros(tmp_line, tmp_line_len);
506 debugs(3, (opt_parse_cfg_only?1:5), "Processing: " << tmp_line);
507
508 if (const char* expr = FindStatement(tmp_line, "if")) {
509 if_states.push_back(EvalBoolExpr(expr)); // store last if-statement meaning
510 } else if (FindStatement(tmp_line, "endif")) {
511 if (!if_states.empty())
512 if_states.pop_back(); // remove last if-statement meaning
513 else
514 fatalf("'endif' without 'if'\n");
515 } else if (FindStatement(tmp_line, "else")) {
516 if (!if_states.empty())
517 if_states.back() = !if_states.back();
518 else
519 fatalf("'else' without 'if'\n");
520 } else if (if_states.empty() || if_states.back()) { // test last if-statement meaning if present
521 /* Handle includes here */
522 if (tmp_line_len >= 9 && strncmp(tmp_line, "include", 7) == 0 && xisspace(tmp_line[7])) {
523 err_count += parseManyConfigFiles(tmp_line + 8, depth + 1);
524 } else if (!parse_line(tmp_line)) {
525 debugs(3, 0, HERE << cfg_filename << ":" << config_lineno << " unrecognized: '" << tmp_line << "'");
526 err_count++;
527 }
528 }
529
530 safe_free(tmp_line);
531 tmp_line_len = 0;
532
533 }
534 if (!if_states.empty())
535 fatalf("if-statement without 'endif'\n");
536
537 if (is_pipe) {
538 int ret = pclose(fp);
539
540 if (ret != 0)
541 fatalf("parseConfigFile: '%s' failed with exit code %d\n", file_name, ret);
542 } else {
543 fclose(fp);
544 }
545
546 cfg_filename = orig_cfg_filename;
547 config_lineno = orig_config_lineno;
548
549 return err_count;
550 }
551
552 int
553 parseConfigFile(const char *file_name)
554 {
555 int err_count = 0;
556
557 debugs(5, 4, HERE);
558
559 configFreeMemory();
560
561 ACLMethodData::ThePurgeCount = 0;
562 default_all();
563
564 err_count = parseOneConfigFile(file_name, 0);
565
566 defaults_if_none();
567
568 /*
569 * We must call configDoConfigure() before leave_suid() because
570 * configDoConfigure() is where we turn username strings into
571 * uid values.
572 */
573 configDoConfigure();
574
575 if (!Config.chroot_dir) {
576 leave_suid();
577 setUmask(Config.umask);
578 _db_init(Debug::cache_log, Debug::debugOptions);
579 enter_suid();
580 }
581
582 if (opt_send_signal == -1) {
583 Mgr::RegisterAction("config",
584 "Current Squid Configuration",
585 dump_config,
586 1, 1);
587 }
588
589 return err_count;
590 }
591
592
593 static void
594 configDoConfigure(void)
595 {
596 memset(&Config2, '\0', sizeof(SquidConfig2));
597 /* init memory as early as possible */
598 memConfigure();
599 /* Sanity checks */
600
601 if (Config.cacheSwap.swapDirs == NULL) {
602 /* Memory-only cache probably in effect. */
603 /* turn off the cache rebuild delays... */
604 StoreController::store_dirs_rebuilding = 0;
605 } else if (InDaemonMode()) { // no diskers in non-daemon mode
606 for (int i = 0; i < Config.cacheSwap.n_configured; ++i) {
607 const RefCount<SwapDir> sd = Config.cacheSwap.swapDirs[i];
608 if (sd->needsDiskStrand())
609 sd->disker = Config.workers + (++Config.cacheSwap.n_strands);
610 }
611 }
612
613 if (Debug::rotateNumber < 0) {
614 Debug::rotateNumber = Config.Log.rotateNumber;
615 }
616
617 #if SIZEOF_OFF_T <= 4
618 if (Config.Store.maxObjectSize > 0x7FFF0000) {
619 debugs(3, 0, "WARNING: This Squid binary can not handle files larger than 2GB. Limiting maximum_object_size to just below 2GB");
620 Config.Store.maxObjectSize = 0x7FFF0000;
621 }
622 #endif
623 if (0 == Store::Root().maxSize())
624 /* people might want a zero-sized cache on purpose */
625 (void) 0;
626 else if (Store::Root().maxSize() < Config.memMaxSize)
627 /* This is bogus. folk with NULL caches will want this */
628 debugs(3, 0, "WARNING cache_mem is larger than total disk cache space!");
629
630 if (Config.Announce.period > 0) {
631 Config.onoff.announce = 1;
632 } else if (Config.Announce.period < 1) {
633 Config.Announce.period = 86400 * 365; /* one year */
634 Config.onoff.announce = 0;
635 }
636
637 if (Config.onoff.httpd_suppress_version_string)
638 visible_appname_string = (char *)appname_string;
639 else
640 visible_appname_string = (char const *)APP_FULLNAME;
641
642 #if USE_DNSHELPER
643 if (Config.dnsChildren.n_max < 1)
644 fatal("No DNS helpers allocated");
645 #endif
646
647 if (Config.Program.redirect) {
648 if (Config.redirectChildren.n_max < 1) {
649 Config.redirectChildren.n_max = 0;
650 wordlistDestroy(&Config.Program.redirect);
651 }
652 }
653
654 if (Config.appendDomain)
655 if (*Config.appendDomain != '.')
656 fatal("append_domain must begin with a '.'");
657
658 if (Config.errHtmlText == NULL)
659 Config.errHtmlText = xstrdup(null_string);
660
661 #if !HAVE_SETRLIMIT || !defined(RLIMIT_NOFILE)
662 if (Config.max_filedescriptors > 0) {
663 debugs(0, DBG_IMPORTANT, "WARNING: max_filedescriptors disabled. Operating System setrlimit(RLIMIT_NOFILE) is missing.");
664 }
665 #elif USE_SELECT || USE_SELECT_WIN32
666 if (Config.max_filedescriptors > FD_SETSIZE) {
667 debugs(0, DBG_IMPORTANT, "WARNING: max_filedescriptors limited to " << FD_SETSIZE << " by select() algorithm.");
668 }
669 #endif
670
671 storeConfigure();
672
673 snprintf(ThisCache, sizeof(ThisCache), "%s (%s)",
674 uniqueHostname(),
675 visible_appname_string);
676
677 /*
678 * the extra space is for loop detection in client_side.c -- we search
679 * for substrings in the Via header.
680 */
681 snprintf(ThisCache2, sizeof(ThisCache), " %s (%s)",
682 uniqueHostname(),
683 visible_appname_string);
684
685 /* Use visible_hostname as default surrogate_id */
686 if (!Config.Accel.surrogate_id) {
687 const char *t = getMyHostname();
688 Config.Accel.surrogate_id = xstrdup( (t?t:"unset-id") );
689 }
690
691 if (!Config.udpMaxHitObjsz || Config.udpMaxHitObjsz > SQUID_UDP_SO_SNDBUF)
692 Config.udpMaxHitObjsz = SQUID_UDP_SO_SNDBUF;
693
694 if (Config.appendDomain)
695 Config.appendDomainLen = strlen(Config.appendDomain);
696 else
697 Config.appendDomainLen = 0;
698
699 if (Config.connect_retries > 10) {
700 debugs(0,DBG_CRITICAL, "WARNING: connect_retries cannot be larger than 10. Resetting to 10.");
701 Config.connect_retries = 10;
702 }
703
704 requirePathnameExists("MIME Config Table", Config.mimeTablePathname);
705 #if USE_DNSHELPER
706 requirePathnameExists("cache_dns_program", Config.Program.dnsserver);
707 #endif
708 #if USE_UNLINKD
709
710 requirePathnameExists("unlinkd_program", Config.Program.unlinkd);
711 #endif
712 requirePathnameExists("logfile_daemon", Log::TheConfig.logfile_daemon);
713 if (Config.Program.redirect)
714 requirePathnameExists("redirect_program", Config.Program.redirect->key);
715
716 requirePathnameExists("Icon Directory", Config.icons.directory);
717
718 if (Config.errorDirectory)
719 requirePathnameExists("Error Directory", Config.errorDirectory);
720
721 #if USE_HTTP_VIOLATIONS
722
723 {
724 const refresh_t *R;
725
726 for (R = Config.Refresh; R; R = R->next) {
727 if (!R->flags.override_expire)
728 continue;
729
730 debugs(22, 1, "WARNING: use of 'override-expire' in 'refresh_pattern' violates HTTP");
731
732 break;
733 }
734
735 for (R = Config.Refresh; R; R = R->next) {
736 if (!R->flags.override_lastmod)
737 continue;
738
739 debugs(22, 1, "WARNING: use of 'override-lastmod' in 'refresh_pattern' violates HTTP");
740
741 break;
742 }
743
744 for (R = Config.Refresh; R; R = R->next) {
745 if (!R->flags.reload_into_ims)
746 continue;
747
748 debugs(22, 1, "WARNING: use of 'reload-into-ims' in 'refresh_pattern' violates HTTP");
749
750 break;
751 }
752
753 for (R = Config.Refresh; R; R = R->next) {
754 if (!R->flags.ignore_reload)
755 continue;
756
757 debugs(22, 1, "WARNING: use of 'ignore-reload' in 'refresh_pattern' violates HTTP");
758
759 break;
760 }
761
762 for (R = Config.Refresh; R; R = R->next) {
763 if (!R->flags.ignore_no_cache)
764 continue;
765
766 debugs(22, 1, "WARNING: use of 'ignore-no-cache' in 'refresh_pattern' violates HTTP");
767
768 break;
769 }
770
771 for (R = Config.Refresh; R; R = R->next) {
772 if (!R->flags.ignore_no_store)
773 continue;
774
775 debugs(22, 1, "WARNING: use of 'ignore-no-store' in 'refresh_pattern' violates HTTP");
776
777 break;
778 }
779
780 for (R = Config.Refresh; R; R = R->next) {
781 if (!R->flags.ignore_must_revalidate)
782 continue;
783 debugs(22, 1, "WARNING: use of 'ignore-must-revalidate' in 'refresh_pattern' violates HTTP");
784 break;
785 }
786
787 for (R = Config.Refresh; R; R = R->next) {
788 if (!R->flags.ignore_private)
789 continue;
790
791 debugs(22, 1, "WARNING: use of 'ignore-private' in 'refresh_pattern' violates HTTP");
792
793 break;
794 }
795
796 for (R = Config.Refresh; R; R = R->next) {
797 if (!R->flags.ignore_auth)
798 continue;
799
800 debugs(22, 1, "WARNING: use of 'ignore-auth' in 'refresh_pattern' violates HTTP");
801
802 break;
803 }
804
805 }
806 #endif
807 #if !USE_HTTP_VIOLATIONS
808 Config.onoff.via = 1;
809 #else
810
811 if (!Config.onoff.via)
812 debugs(22, 1, "WARNING: HTTP requires the use of Via");
813
814 #endif
815
816 // we enable runtime PURGE checks if there is at least one PURGE method ACL
817 // TODO: replace with a dedicated "purge" ACL option?
818 Config2.onoff.enable_purge = (ACLMethodData::ThePurgeCount > 0);
819
820 Config2.onoff.mangle_request_headers = httpReqHdrManglersConfigured();
821
822 if (geteuid() == 0) {
823 if (NULL != Config.effectiveUser) {
824
825 struct passwd *pwd = getpwnam(Config.effectiveUser);
826
827 if (NULL == pwd) {
828 /*
829 * Andres Kroonmaa <andre@online.ee>:
830 * Some getpwnam() implementations (Solaris?) require
831 * an available FD < 256 for opening a FILE* to the
832 * passwd file.
833 * DW:
834 * This should be safe at startup, but might still fail
835 * during reconfigure.
836 */
837 fatalf("getpwnam failed to find userid for effective user '%s'",
838 Config.effectiveUser);
839 return;
840 }
841
842 Config2.effectiveUserID = pwd->pw_uid;
843
844 Config2.effectiveGroupID = pwd->pw_gid;
845
846 #if HAVE_PUTENV
847
848 if (pwd->pw_dir && *pwd->pw_dir) {
849 int len;
850 char *env_str = (char *)xcalloc((len = strlen(pwd->pw_dir) + 6), 1);
851 snprintf(env_str, len, "HOME=%s", pwd->pw_dir);
852 putenv(env_str);
853 }
854
855 #endif
856
857 }
858 } else {
859 Config2.effectiveUserID = geteuid();
860 Config2.effectiveGroupID = getegid();
861 }
862
863 if (NULL != Config.effectiveGroup) {
864
865 struct group *grp = getgrnam(Config.effectiveGroup);
866
867 if (NULL == grp) {
868 fatalf("getgrnam failed to find groupid for effective group '%s'",
869 Config.effectiveGroup);
870 return;
871 }
872
873 Config2.effectiveGroupID = grp->gr_gid;
874 }
875
876 HttpRequestMethod::Configure(Config);
877 #if USE_SSL
878
879 debugs(3, 1, "Initializing https proxy context");
880
881 Config.ssl_client.sslContext = sslCreateClientContext(Config.ssl_client.cert, Config.ssl_client.key, Config.ssl_client.version, Config.ssl_client.cipher, Config.ssl_client.options, Config.ssl_client.flags, Config.ssl_client.cafile, Config.ssl_client.capath, Config.ssl_client.crlfile);
882
883 {
884
885 peer *p;
886
887 for (p = Config.peers; p != NULL; p = p->next) {
888 if (p->use_ssl) {
889 debugs(3, 1, "Initializing cache_peer " << p->name << " SSL context");
890 p->sslContext = sslCreateClientContext(p->sslcert, p->sslkey, p->sslversion, p->sslcipher, p->ssloptions, p->sslflags, p->sslcafile, p->sslcapath, p->sslcrlfile);
891 }
892 }
893 }
894
895 {
896
897 http_port_list *s;
898
899 for (s = Config.Sockaddr.http; s != NULL; s = (http_port_list *) s->next) {
900 if (!s->cert && !s->key)
901 continue;
902
903 debugs(3, 1, "Initializing http_port " << s->s << " SSL context");
904
905 s->staticSslContext.reset(
906 sslCreateServerContext(s->cert, s->key,
907 s->version, s->cipher, s->options, s->sslflags, s->clientca,
908 s->cafile, s->capath, s->crlfile, s->dhfile,
909 s->sslContextSessionId));
910
911 Ssl::readCertChainAndPrivateKeyFromFiles(s->signingCert, s->signPkey, s->certsToChain, s->cert, s->key);
912 }
913 }
914
915 {
916
917 http_port_list *s;
918
919 for (s = Config.Sockaddr.https; s != NULL; s = s->next) {
920 debugs(3, 1, "Initializing https_port " << s->s << " SSL context");
921
922 s->staticSslContext.reset(
923 sslCreateServerContext(s->cert, s->key,
924 s->version, s->cipher, s->options, s->sslflags, s->clientca,
925 s->cafile, s->capath, s->crlfile, s->dhfile,
926 s->sslContextSessionId));
927 }
928 }
929
930 #endif
931
932 // prevent infinite fetch loops in the request parser
933 // due to buffer full but not enough data recived to finish parse
934 if (Config.maxRequestBufferSize <= Config.maxRequestHeaderSize) {
935 fatalf("Client request buffer of %u bytes cannot hold a request with %u bytes of headers." \
936 " Change client_request_buffer_max or request_header_max_size limits.",
937 (uint32_t)Config.maxRequestBufferSize, (uint32_t)Config.maxRequestHeaderSize);
938 }
939
940 #if USE_AUTH
941 /*
942 * disable client side request pipelining. There is a race with
943 * Negotiate and NTLM when the client sends a second request on an
944 * connection before the authenticate challenge is sent. With
945 * pipelining OFF, the client may fail to authenticate, but squid's
946 * state will be preserved.
947 */
948 if (Config.onoff.pipeline_prefetch) {
949 Auth::Config *nego = Auth::Config::Find("Negotiate");
950 Auth::Config *ntlm = Auth::Config::Find("NTLM");
951 if ((nego && nego->active()) || (ntlm && ntlm->active())) {
952 debugs(3, DBG_IMPORTANT, "WARNING: pipeline_prefetch breaks NTLM and Negotiate authentication. Forced OFF.");
953 Config.onoff.pipeline_prefetch = 0;
954 }
955 }
956 #endif
957 }
958
959 /** Parse a line containing an obsolete directive.
960 * To upgrade it where possible instead of just "Bungled config" for
961 * directives which cannot be marked as simply aliases of the some name.
962 * For example if the parameter order and content has changed.
963 * Or if the directive has been completely removed.
964 */
965 void
966 parse_obsolete(const char *name)
967 {
968 // Directives which have been radically changed rather than removed
969 if (!strcmp(name, "url_rewrite_concurrency")) {
970 int cval;
971 parse_int(&cval);
972 debugs(3, DBG_CRITICAL, "WARNING: url_rewrite_concurrency upgrade overriding url_rewrite_children settings.");
973 Config.redirectChildren.concurrency = cval;
974 }
975 }
976
977 /* Parse a time specification from the config file. Store the
978 * result in 'tptr', after converting it to 'units' */
979 static void
980 parseTimeLine(time_msec_t * tptr, const char *units, bool allowMsec)
981 {
982 char *token;
983 double d;
984 time_msec_t m;
985 time_msec_t u;
986
987 if ((u = parseTimeUnits(units, allowMsec)) == 0)
988 self_destruct();
989
990 if ((token = strtok(NULL, w_space)) == NULL)
991 self_destruct();
992
993 d = xatof(token);
994
995 m = u; /* default to 'units' if none specified */
996
997 if (0 == d)
998 (void) 0;
999 else if ((token = strtok(NULL, w_space)) == NULL)
1000 debugs(3, 0, "WARNING: No units on '" <<
1001 config_input_line << "', assuming " <<
1002 d << " " << units );
1003 else if ((m = parseTimeUnits(token, allowMsec)) == 0)
1004 self_destruct();
1005
1006 *tptr = static_cast<time_msec_t>(m * d);
1007 }
1008
1009 static uint64_t
1010 parseTimeUnits(const char *unit, bool allowMsec)
1011 {
1012 if (allowMsec && !strncasecmp(unit, T_MILLISECOND_STR, strlen(T_MILLISECOND_STR)))
1013 return 1;
1014
1015 if (!strncasecmp(unit, T_SECOND_STR, strlen(T_SECOND_STR)))
1016 return 1000;
1017
1018 if (!strncasecmp(unit, T_MINUTE_STR, strlen(T_MINUTE_STR)))
1019 return 60 * 1000;
1020
1021 if (!strncasecmp(unit, T_HOUR_STR, strlen(T_HOUR_STR)))
1022 return 3600 * 1000;
1023
1024 if (!strncasecmp(unit, T_DAY_STR, strlen(T_DAY_STR)))
1025 return 86400 * 1000;
1026
1027 if (!strncasecmp(unit, T_WEEK_STR, strlen(T_WEEK_STR)))
1028 return 86400 * 7 * 1000;
1029
1030 if (!strncasecmp(unit, T_FORTNIGHT_STR, strlen(T_FORTNIGHT_STR)))
1031 return 86400 * 14 * 1000;
1032
1033 if (!strncasecmp(unit, T_MONTH_STR, strlen(T_MONTH_STR)))
1034 return static_cast<uint64_t>(86400) * 30 * 1000;
1035
1036 if (!strncasecmp(unit, T_YEAR_STR, strlen(T_YEAR_STR)))
1037 return static_cast<uint64_t>(86400 * 1000 * 365.2522);
1038
1039 if (!strncasecmp(unit, T_DECADE_STR, strlen(T_DECADE_STR)))
1040 return static_cast<uint64_t>(86400 * 1000 * 365.2522 * 10);
1041
1042 debugs(3, 1, "parseTimeUnits: unknown time unit '" << unit << "'");
1043
1044 return 0;
1045 }
1046
1047 static void
1048 parseBytesLine64(int64_t * bptr, const char *units)
1049 {
1050 char *token;
1051 double d;
1052 int64_t m;
1053 int64_t u;
1054
1055 if ((u = parseBytesUnits(units)) == 0) {
1056 self_destruct();
1057 return;
1058 }
1059
1060 if ((token = strtok(NULL, w_space)) == NULL) {
1061 self_destruct();
1062 return;
1063 }
1064
1065 if (strcmp(token, "none") == 0 || strcmp(token, "-1") == 0) {
1066 *bptr = -1;
1067 return;
1068 }
1069
1070 d = xatof(token);
1071
1072 m = u; /* default to 'units' if none specified */
1073
1074 if (0.0 == d)
1075 (void) 0;
1076 else if ((token = strtok(NULL, w_space)) == NULL)
1077 debugs(3, 0, "WARNING: No units on '" <<
1078 config_input_line << "', assuming " <<
1079 d << " " << units );
1080 else if ((m = parseBytesUnits(token)) == 0) {
1081 self_destruct();
1082 return;
1083 }
1084
1085 *bptr = static_cast<int64_t>(m * d / u);
1086
1087 if (static_cast<double>(*bptr) * 2 != m * d / u * 2)
1088 self_destruct();
1089 }
1090
1091
1092 static void
1093 parseBytesLine(size_t * bptr, const char *units)
1094 {
1095 char *token;
1096 double d;
1097 int m;
1098 int u;
1099
1100 if ((u = parseBytesUnits(units)) == 0) {
1101 self_destruct();
1102 return;
1103 }
1104
1105 if ((token = strtok(NULL, w_space)) == NULL) {
1106 self_destruct();
1107 return;
1108 }
1109
1110 if (strcmp(token, "none") == 0 || strcmp(token, "-1") == 0) {
1111 *bptr = static_cast<size_t>(-1);
1112 return;
1113 }
1114
1115 d = xatof(token);
1116
1117 m = u; /* default to 'units' if none specified */
1118
1119 if (0.0 == d)
1120 (void) 0;
1121 else if ((token = strtok(NULL, w_space)) == NULL)
1122 debugs(3, 0, "WARNING: No units on '" <<
1123 config_input_line << "', assuming " <<
1124 d << " " << units );
1125 else if ((m = parseBytesUnits(token)) == 0) {
1126 self_destruct();
1127 return;
1128 }
1129
1130 *bptr = static_cast<size_t>(m * d / u);
1131
1132 if (static_cast<double>(*bptr) * 2 != m * d / u * 2)
1133 self_destruct();
1134 }
1135
1136 #if !USE_DNSHELPER
1137 static void
1138 parseBytesLineSigned(ssize_t * bptr, const char *units)
1139 {
1140 char *token;
1141 double d;
1142 int m;
1143 int u;
1144
1145 if ((u = parseBytesUnits(units)) == 0) {
1146 self_destruct();
1147 return;
1148 }
1149
1150 if ((token = strtok(NULL, w_space)) == NULL) {
1151 self_destruct();
1152 return;
1153 }
1154
1155 if (strcmp(token, "none") == 0 || token[0] == '-' /* -N */) {
1156 *bptr = -1;
1157 return;
1158 }
1159
1160 d = xatof(token);
1161
1162 m = u; /* default to 'units' if none specified */
1163
1164 if (0.0 == d)
1165 (void) 0;
1166 else if ((token = strtok(NULL, w_space)) == NULL)
1167 debugs(3, 0, "WARNING: No units on '" <<
1168 config_input_line << "', assuming " <<
1169 d << " " << units );
1170 else if ((m = parseBytesUnits(token)) == 0) {
1171 self_destruct();
1172 return;
1173 }
1174
1175 *bptr = static_cast<size_t>(m * d / u);
1176
1177 if (static_cast<double>(*bptr) * 2 != m * d / u * 2)
1178 self_destruct();
1179 }
1180 #endif
1181
1182 #if USE_SSL
1183 /**
1184 * Parse bytes from a string.
1185 * Similar to the parseBytesLine function but parses the string value instead of
1186 * the current token value.
1187 */
1188 static void parseBytesOptionValue(size_t * bptr, const char *units, char const * value)
1189 {
1190 int u;
1191 if ((u = parseBytesUnits(units)) == 0) {
1192 self_destruct();
1193 return;
1194 }
1195
1196 // Find number from string beginning.
1197 char const * number_begin = value;
1198 char const * number_end = value;
1199
1200 while ((*number_end >= '0' && *number_end <= '9')) {
1201 number_end++;
1202 }
1203
1204 String number;
1205 number.limitInit(number_begin, number_end - number_begin);
1206
1207 int d = xatoi(number.termedBuf());
1208 int m;
1209 if ((m = parseBytesUnits(number_end)) == 0) {
1210 self_destruct();
1211 return;
1212 }
1213
1214 *bptr = static_cast<size_t>(m * d / u);
1215 if (static_cast<double>(*bptr) * 2 != m * d / u * 2)
1216 self_destruct();
1217 }
1218 #endif
1219
1220 static size_t
1221 parseBytesUnits(const char *unit)
1222 {
1223 if (!strncasecmp(unit, B_BYTES_STR, strlen(B_BYTES_STR)))
1224 return 1;
1225
1226 if (!strncasecmp(unit, B_KBYTES_STR, strlen(B_KBYTES_STR)))
1227 return 1 << 10;
1228
1229 if (!strncasecmp(unit, B_MBYTES_STR, strlen(B_MBYTES_STR)))
1230 return 1 << 20;
1231
1232 if (!strncasecmp(unit, B_GBYTES_STR, strlen(B_GBYTES_STR)))
1233 return 1 << 30;
1234
1235 debugs(3, DBG_CRITICAL, "WARNING: Unknown bytes unit '" << unit << "'");
1236
1237 return 0;
1238 }
1239
1240 /*****************************************************************************
1241 * Max
1242 *****************************************************************************/
1243
1244 static void
1245 dump_acl(StoreEntry * entry, const char *name, ACL * ae)
1246 {
1247 wordlist *w;
1248 wordlist *v;
1249
1250 while (ae != NULL) {
1251 debugs(3, 3, "dump_acl: " << name << " " << ae->name);
1252 storeAppendPrintf(entry, "%s %s %s ",
1253 name,
1254 ae->name,
1255 ae->typeString());
1256 v = w = ae->dump();
1257
1258 while (v != NULL) {
1259 debugs(3, 3, "dump_acl: " << name << " " << ae->name << " " << v->key);
1260 storeAppendPrintf(entry, "%s ", v->key);
1261 v = v->next;
1262 }
1263
1264 storeAppendPrintf(entry, "\n");
1265 wordlistDestroy(&w);
1266 ae = ae->next;
1267 }
1268 }
1269
1270 static void
1271 parse_acl(ACL ** ae)
1272 {
1273 ACL::ParseAclLine(LegacyParser, ae);
1274 }
1275
1276 static void
1277 free_acl(ACL ** ae)
1278 {
1279 aclDestroyAcls(ae);
1280 }
1281
1282 void
1283 dump_acl_list(StoreEntry * entry, ACLList * head)
1284 {
1285 ACLList *l;
1286
1287 for (l = head; l; l = l->next) {
1288 storeAppendPrintf(entry, " %s%s",
1289 l->op ? null_string : "!",
1290 l->_acl->name);
1291 }
1292 }
1293
1294 void
1295 dump_acl_access(StoreEntry * entry, const char *name, acl_access * head)
1296 {
1297 acl_access *l;
1298
1299 for (l = head; l; l = l->next) {
1300 storeAppendPrintf(entry, "%s %s",
1301 name,
1302 l->allow ? "Allow" : "Deny");
1303 dump_acl_list(entry, l->aclList);
1304 storeAppendPrintf(entry, "\n");
1305 }
1306 }
1307
1308 static void
1309 parse_acl_access(acl_access ** head)
1310 {
1311 aclParseAccessLine(LegacyParser, head);
1312 }
1313
1314 static void
1315 free_acl_access(acl_access ** head)
1316 {
1317 aclDestroyAccessList(head);
1318 }
1319
1320 static void
1321 dump_address(StoreEntry * entry, const char *name, Ip::Address &addr)
1322 {
1323 char buf[MAX_IPSTRLEN];
1324 storeAppendPrintf(entry, "%s %s\n", name, addr.NtoA(buf,MAX_IPSTRLEN) );
1325 }
1326
1327 static void
1328 parse_address(Ip::Address *addr)
1329 {
1330 char *token = strtok(NULL, w_space);
1331
1332 if (!token) {
1333 self_destruct();
1334 return;
1335 }
1336
1337 if (!strcmp(token,"any_addr")) {
1338 addr->SetAnyAddr();
1339 (void) 0;
1340 } else if ( (!strcmp(token,"no_addr")) || (!strcmp(token,"full_mask")) ) {
1341 addr->SetNoAddr();
1342 (void) 0;
1343 } else
1344 *addr = token;
1345 }
1346
1347 static void
1348 free_address(Ip::Address *addr)
1349 {
1350 addr->SetEmpty();
1351 }
1352
1353 CBDATA_TYPE(acl_address);
1354
1355 static void
1356 dump_acl_address(StoreEntry * entry, const char *name, acl_address * head)
1357 {
1358 char buf[MAX_IPSTRLEN];
1359 acl_address *l;
1360
1361 for (l = head; l; l = l->next) {
1362 if (!l->addr.IsAnyAddr())
1363 storeAppendPrintf(entry, "%s %s", name, l->addr.NtoA(buf,MAX_IPSTRLEN));
1364 else
1365 storeAppendPrintf(entry, "%s autoselect", name);
1366
1367 dump_acl_list(entry, l->aclList);
1368
1369 storeAppendPrintf(entry, "\n");
1370 }
1371 }
1372
1373 static void
1374 freed_acl_address(void *data)
1375 {
1376 acl_address *l = static_cast<acl_address *>(data);
1377 aclDestroyAclList(&l->aclList);
1378 }
1379
1380 static void
1381 parse_acl_address(acl_address ** head)
1382 {
1383 acl_address *l;
1384 acl_address **tail = head; /* sane name below */
1385 CBDATA_INIT_TYPE_FREECB(acl_address, freed_acl_address);
1386 l = cbdataAlloc(acl_address);
1387 parse_address(&l->addr);
1388 aclParseAclList(LegacyParser, &l->aclList);
1389
1390 while (*tail)
1391 tail = &(*tail)->next;
1392
1393 *tail = l;
1394 }
1395
1396 static void
1397 free_acl_address(acl_address ** head)
1398 {
1399 while (*head) {
1400 acl_address *l = *head;
1401 *head = l->next;
1402 cbdataFree(l);
1403 }
1404 }
1405
1406 CBDATA_TYPE(acl_tos);
1407
1408 static void
1409 dump_acl_tos(StoreEntry * entry, const char *name, acl_tos * head)
1410 {
1411 acl_tos *l;
1412
1413 for (l = head; l; l = l->next) {
1414 if (l->tos > 0)
1415 storeAppendPrintf(entry, "%s 0x%02X", name, l->tos);
1416 else
1417 storeAppendPrintf(entry, "%s none", name);
1418
1419 dump_acl_list(entry, l->aclList);
1420
1421 storeAppendPrintf(entry, "\n");
1422 }
1423 }
1424
1425 static void
1426 freed_acl_tos(void *data)
1427 {
1428 acl_tos *l = static_cast<acl_tos *>(data);
1429 aclDestroyAclList(&l->aclList);
1430 }
1431
1432 static void
1433 parse_acl_tos(acl_tos ** head)
1434 {
1435 acl_tos *l;
1436 acl_tos **tail = head; /* sane name below */
1437 unsigned int tos; /* Initially uint for strtoui. Casted to tos_t before return */
1438 char *token = strtok(NULL, w_space);
1439
1440 if (!token) {
1441 self_destruct();
1442 return;
1443 }
1444
1445 if (!xstrtoui(token, NULL, &tos, 0, std::numeric_limits<tos_t>::max())) {
1446 self_destruct();
1447 return;
1448 }
1449
1450 CBDATA_INIT_TYPE_FREECB(acl_tos, freed_acl_tos);
1451
1452 l = cbdataAlloc(acl_tos);
1453
1454 l->tos = (tos_t)tos;
1455
1456 aclParseAclList(LegacyParser, &l->aclList);
1457
1458 while (*tail)
1459 tail = &(*tail)->next;
1460
1461 *tail = l;
1462 }
1463
1464 static void
1465 free_acl_tos(acl_tos ** head)
1466 {
1467 while (*head) {
1468 acl_tos *l = *head;
1469 *head = l->next;
1470 l->next = NULL;
1471 cbdataFree(l);
1472 }
1473 }
1474
1475 #if SO_MARK && USE_LIBCAP
1476
1477 CBDATA_TYPE(acl_nfmark);
1478
1479 static void
1480 dump_acl_nfmark(StoreEntry * entry, const char *name, acl_nfmark * head)
1481 {
1482 acl_nfmark *l;
1483
1484 for (l = head; l; l = l->next) {
1485 if (l->nfmark > 0)
1486 storeAppendPrintf(entry, "%s 0x%02X", name, l->nfmark);
1487 else
1488 storeAppendPrintf(entry, "%s none", name);
1489
1490 dump_acl_list(entry, l->aclList);
1491
1492 storeAppendPrintf(entry, "\n");
1493 }
1494 }
1495
1496 static void
1497 freed_acl_nfmark(void *data)
1498 {
1499 acl_nfmark *l = static_cast<acl_nfmark *>(data);
1500 aclDestroyAclList(&l->aclList);
1501 }
1502
1503 static void
1504 parse_acl_nfmark(acl_nfmark ** head)
1505 {
1506 acl_nfmark *l;
1507 acl_nfmark **tail = head; /* sane name below */
1508 nfmark_t mark;
1509 char *token = strtok(NULL, w_space);
1510
1511 if (!token) {
1512 self_destruct();
1513 return;
1514 }
1515
1516 if (!xstrtoui(token, NULL, &mark, 0, std::numeric_limits<nfmark_t>::max())) {
1517 self_destruct();
1518 return;
1519 }
1520
1521 CBDATA_INIT_TYPE_FREECB(acl_nfmark, freed_acl_nfmark);
1522
1523 l = cbdataAlloc(acl_nfmark);
1524
1525 l->nfmark = mark;
1526
1527 aclParseAclList(LegacyParser, &l->aclList);
1528
1529 while (*tail)
1530 tail = &(*tail)->next;
1531
1532 *tail = l;
1533 }
1534
1535 static void
1536 free_acl_nfmark(acl_nfmark ** head)
1537 {
1538 while (*head) {
1539 acl_nfmark *l = *head;
1540 *head = l->next;
1541 l->next = NULL;
1542 cbdataFree(l);
1543 }
1544 }
1545 #endif /* SO_MARK */
1546
1547 CBDATA_TYPE(acl_size_t);
1548
1549 static void
1550 dump_acl_b_size_t(StoreEntry * entry, const char *name, acl_size_t * head)
1551 {
1552 acl_size_t *l;
1553
1554 for (l = head; l; l = l->next) {
1555 if (l->size != -1)
1556 storeAppendPrintf(entry, "%s %d %s\n", name, (int) l->size, B_BYTES_STR);
1557 else
1558 storeAppendPrintf(entry, "%s none", name);
1559
1560 dump_acl_list(entry, l->aclList);
1561
1562 storeAppendPrintf(entry, "\n");
1563 }
1564 }
1565
1566 static void
1567 freed_acl_b_size_t(void *data)
1568 {
1569 acl_size_t *l = static_cast<acl_size_t *>(data);
1570 aclDestroyAclList(&l->aclList);
1571 }
1572
1573 static void
1574 parse_acl_b_size_t(acl_size_t ** head)
1575 {
1576 acl_size_t *l;
1577 acl_size_t **tail = head; /* sane name below */
1578
1579 CBDATA_INIT_TYPE_FREECB(acl_size_t, freed_acl_b_size_t);
1580
1581 l = cbdataAlloc(acl_size_t);
1582
1583 parse_b_int64_t(&l->size);
1584
1585 aclParseAclList(LegacyParser, &l->aclList);
1586
1587 while (*tail)
1588 tail = &(*tail)->next;
1589
1590 *tail = l;
1591 }
1592
1593 static void
1594 free_acl_b_size_t(acl_size_t ** head)
1595 {
1596 while (*head) {
1597 acl_size_t *l = *head;
1598 *head = l->next;
1599 l->next = NULL;
1600 cbdataFree(l);
1601 }
1602 }
1603
1604 #if USE_DELAY_POOLS
1605
1606 #include "DelayPools.h"
1607 #include "DelayConfig.h"
1608 /* do nothing - free_delay_pool_count is the magic free function.
1609 * this is why delay_pool_count isn't just marked TYPE: u_short
1610 */
1611 #define free_delay_pool_class(X)
1612 #define free_delay_pool_access(X)
1613 #define free_delay_pool_rates(X)
1614 #define dump_delay_pool_class(X, Y, Z)
1615 #define dump_delay_pool_access(X, Y, Z)
1616 #define dump_delay_pool_rates(X, Y, Z)
1617
1618 static void
1619 free_delay_pool_count(DelayConfig * cfg)
1620 {
1621 cfg->freePoolCount();
1622 }
1623
1624 static void
1625 dump_delay_pool_count(StoreEntry * entry, const char *name, DelayConfig &cfg)
1626 {
1627 cfg.dumpPoolCount (entry, name);
1628 }
1629
1630 static void
1631 parse_delay_pool_count(DelayConfig * cfg)
1632 {
1633 cfg->parsePoolCount();
1634 }
1635
1636 static void
1637 parse_delay_pool_class(DelayConfig * cfg)
1638 {
1639 cfg->parsePoolClass();
1640 }
1641
1642 static void
1643 parse_delay_pool_rates(DelayConfig * cfg)
1644 {
1645 cfg->parsePoolRates();
1646 }
1647
1648 static void
1649 parse_delay_pool_access(DelayConfig * cfg)
1650 {
1651 cfg->parsePoolAccess(LegacyParser);
1652 }
1653
1654 #endif
1655
1656 #if USE_DELAY_POOLS
1657 #include "ClientDelayConfig.h"
1658 /* do nothing - free_client_delay_pool_count is the magic free function.
1659 * this is why client_delay_pool_count isn't just marked TYPE: u_short
1660 */
1661
1662 #define free_client_delay_pool_access(X)
1663 #define free_client_delay_pool_rates(X)
1664 #define dump_client_delay_pool_access(X, Y, Z)
1665 #define dump_client_delay_pool_rates(X, Y, Z)
1666
1667 static void
1668 free_client_delay_pool_count(ClientDelayConfig * cfg)
1669 {
1670 cfg->freePoolCount();
1671 }
1672
1673 static void
1674 dump_client_delay_pool_count(StoreEntry * entry, const char *name, ClientDelayConfig &cfg)
1675 {
1676 cfg.dumpPoolCount (entry, name);
1677 }
1678
1679 static void
1680 parse_client_delay_pool_count(ClientDelayConfig * cfg)
1681 {
1682 cfg->parsePoolCount();
1683 }
1684
1685 static void
1686 parse_client_delay_pool_rates(ClientDelayConfig * cfg)
1687 {
1688 cfg->parsePoolRates();
1689 }
1690
1691 static void
1692 parse_client_delay_pool_access(ClientDelayConfig * cfg)
1693 {
1694 cfg->parsePoolAccess(LegacyParser);
1695 }
1696 #endif
1697
1698 #if USE_HTTP_VIOLATIONS
1699 static void
1700 dump_http_header_access(StoreEntry * entry, const char *name, header_mangler header[])
1701 {
1702 int i;
1703
1704 for (i = 0; i < HDR_ENUM_END; i++) {
1705 if (header[i].access_list != NULL) {
1706 storeAppendPrintf(entry, "%s ", name);
1707 dump_acl_access(entry, httpHeaderNameById(i),
1708 header[i].access_list);
1709 }
1710 }
1711 }
1712
1713 static void
1714 parse_http_header_access(header_mangler header[])
1715 {
1716 int id, i;
1717 char *t = NULL;
1718
1719 if ((t = strtok(NULL, w_space)) == NULL) {
1720 debugs(3, 0, "" << cfg_filename << " line " << config_lineno << ": " << config_input_line);
1721 debugs(3, 0, "parse_http_header_access: missing header name.");
1722 return;
1723 }
1724
1725 /* Now lookup index of header. */
1726 id = httpHeaderIdByNameDef(t, strlen(t));
1727
1728 if (strcmp(t, "All") == 0)
1729 id = HDR_ENUM_END;
1730 else if (strcmp(t, "Other") == 0)
1731 id = HDR_OTHER;
1732 else if (id == -1) {
1733 debugs(3, 0, "" << cfg_filename << " line " << config_lineno << ": " << config_input_line);
1734 debugs(3, 0, "parse_http_header_access: unknown header name '" << t << "'");
1735 return;
1736 }
1737
1738 if (id != HDR_ENUM_END) {
1739 parse_acl_access(&header[id].access_list);
1740 } else {
1741 char *next_string = t + strlen(t) - 1;
1742 *next_string = 'A';
1743 *(next_string + 1) = ' ';
1744
1745 for (i = 0; i < HDR_ENUM_END; i++) {
1746 char *new_string = xstrdup(next_string);
1747 strtok(new_string, w_space);
1748 parse_acl_access(&header[i].access_list);
1749 safe_free(new_string);
1750 }
1751 }
1752 }
1753
1754 static void
1755 free_http_header_access(header_mangler header[])
1756 {
1757 int i;
1758
1759 for (i = 0; i < HDR_ENUM_END; i++) {
1760 free_acl_access(&header[i].access_list);
1761 }
1762 }
1763
1764 static void
1765 dump_http_header_replace(StoreEntry * entry, const char *name, header_mangler
1766 header[])
1767 {
1768 int i;
1769
1770 for (i = 0; i < HDR_ENUM_END; i++) {
1771 if (NULL == header[i].replacement)
1772 continue;
1773
1774 storeAppendPrintf(entry, "%s %s %s\n", name, httpHeaderNameById(i),
1775 header[i].replacement);
1776 }
1777 }
1778
1779 static void
1780 parse_http_header_replace(header_mangler header[])
1781 {
1782 int id, i;
1783 char *t = NULL;
1784
1785 if ((t = strtok(NULL, w_space)) == NULL) {
1786 debugs(3, 0, "" << cfg_filename << " line " << config_lineno << ": " << config_input_line);
1787 debugs(3, 0, "parse_http_header_replace: missing header name.");
1788 return;
1789 }
1790
1791 /* Now lookup index of header. */
1792 id = httpHeaderIdByNameDef(t, strlen(t));
1793
1794 if (strcmp(t, "All") == 0)
1795 id = HDR_ENUM_END;
1796 else if (strcmp(t, "Other") == 0)
1797 id = HDR_OTHER;
1798 else if (id == -1) {
1799 debugs(3, 0, "" << cfg_filename << " line " << config_lineno << ": " << config_input_line);
1800 debugs(3, 0, "parse_http_header_replace: unknown header name " << t << ".");
1801
1802 return;
1803 }
1804
1805 if (id != HDR_ENUM_END) {
1806 if (header[id].replacement != NULL)
1807 safe_free(header[id].replacement);
1808
1809 header[id].replacement = xstrdup(t + strlen(t) + 1);
1810 } else {
1811 for (i = 0; i < HDR_ENUM_END; i++) {
1812 if (header[i].replacement != NULL)
1813 safe_free(header[i].replacement);
1814
1815 header[i].replacement = xstrdup(t + strlen(t) + 1);
1816 }
1817 }
1818 }
1819
1820 static void
1821 free_http_header_replace(header_mangler header[])
1822 {
1823 int i;
1824
1825 for (i = 0; i < HDR_ENUM_END; i++) {
1826 if (header[i].replacement != NULL)
1827 safe_free(header[i].replacement);
1828 }
1829 }
1830
1831 #endif
1832
1833 static void
1834 dump_cachedir(StoreEntry * entry, const char *name, SquidConfig::_cacheSwap swap)
1835 {
1836 SwapDir *s;
1837 int i;
1838 assert (entry);
1839
1840 for (i = 0; i < swap.n_configured; i++) {
1841 s = dynamic_cast<SwapDir *>(swap.swapDirs[i].getRaw());
1842 if (!s) continue;
1843 storeAppendPrintf(entry, "%s %s %s", name, s->type(), s->path);
1844 s->dump(*entry);
1845 storeAppendPrintf(entry, "\n");
1846 }
1847 }
1848
1849 static int
1850 check_null_string(char *s)
1851 {
1852 return s == NULL;
1853 }
1854
1855 #if USE_AUTH
1856 static void
1857 parse_authparam(Auth::ConfigVector * config)
1858 {
1859 char *type_str;
1860 char *param_str;
1861
1862 if ((type_str = strtok(NULL, w_space)) == NULL)
1863 self_destruct();
1864
1865 if ((param_str = strtok(NULL, w_space)) == NULL)
1866 self_destruct();
1867
1868 /* find a configuration for the scheme in the currently parsed configs... */
1869 Auth::Config *schemeCfg = Auth::Config::Find(type_str);
1870
1871 if (schemeCfg == NULL) {
1872 /* Create a configuration based on the scheme info */
1873 Auth::Scheme::Pointer theScheme = Auth::Scheme::Find(type_str);
1874
1875 if (theScheme == NULL) {
1876 debugs(3, DBG_CRITICAL, "Parsing Config File: Unknown authentication scheme '" << type_str << "'.");
1877 self_destruct();
1878 }
1879
1880 config->push_back(theScheme->createConfig());
1881 schemeCfg = Auth::Config::Find(type_str);
1882 if (schemeCfg == NULL) {
1883 debugs(3, DBG_CRITICAL, "Parsing Config File: Corruption configuring authentication scheme '" << type_str << "'.");
1884 self_destruct();
1885 }
1886 }
1887
1888 schemeCfg->parse(schemeCfg, config->size(), param_str);
1889 }
1890
1891 static void
1892 free_authparam(Auth::ConfigVector * cfg)
1893 {
1894 /* Wipe the Auth globals and Detach/Destruct component config + state. */
1895 cfg->clean();
1896
1897 /* remove our pointers to the probably-dead sub-configs */
1898 while (cfg->size()) {
1899 cfg->pop_back();
1900 }
1901
1902 /* on reconfigure initialize new auth schemes for the new config. */
1903 if (reconfiguring) {
1904 Auth::Init();
1905 }
1906 }
1907
1908 static void
1909 dump_authparam(StoreEntry * entry, const char *name, Auth::ConfigVector cfg)
1910 {
1911 for (Auth::ConfigVector::iterator i = cfg.begin(); i != cfg.end(); ++i)
1912 (*i)->dump(entry, name, (*i));
1913 }
1914 #endif /* USE_AUTH */
1915
1916 /* TODO: just return the object, the # is irrelevant */
1917 static int
1918 find_fstype(char *type)
1919 {
1920 for (size_t i = 0; i < StoreFileSystem::FileSystems().size(); ++i)
1921 if (strcasecmp(type, StoreFileSystem::FileSystems().items[i]->type()) == 0)
1922 return (int)i;
1923
1924 return (-1);
1925 }
1926
1927 static void
1928 parse_cachedir(SquidConfig::_cacheSwap * swap)
1929 {
1930 char *type_str;
1931 char *path_str;
1932 RefCount<SwapDir> sd;
1933 int i;
1934 int fs;
1935
1936 if ((type_str = strtok(NULL, w_space)) == NULL)
1937 self_destruct();
1938
1939 if ((path_str = strtok(NULL, w_space)) == NULL)
1940 self_destruct();
1941
1942 fs = find_fstype(type_str);
1943
1944 if (fs < 0)
1945 self_destruct();
1946
1947 /* reconfigure existing dir */
1948
1949 for (i = 0; i < swap->n_configured; i++) {
1950 assert (swap->swapDirs[i].getRaw());
1951
1952 if ((strcasecmp(path_str, dynamic_cast<SwapDir *>(swap->swapDirs[i].getRaw())->path)) == 0) {
1953 /* this is specific to on-fs Stores. The right
1954 * way to handle this is probably to have a mapping
1955 * from paths to stores, and have on-fs stores
1956 * register with that, and lookip in that in their
1957 * own setup logic. RBC 20041225. TODO.
1958 */
1959
1960 sd = dynamic_cast<SwapDir *>(swap->swapDirs[i].getRaw());
1961
1962 if (strcmp(sd->type(), StoreFileSystem::FileSystems().items[fs]->type()) != 0) {
1963 debugs(3, 0, "ERROR: Can't change type of existing cache_dir " <<
1964 sd->type() << " " << sd->path << " to " << type_str << ". Restart required");
1965 return;
1966 }
1967
1968 sd->reconfigure();
1969
1970 update_maxobjsize();
1971
1972 return;
1973 }
1974 }
1975
1976 /* new cache_dir */
1977 if (swap->n_configured > 63) {
1978 /* 7 bits, signed */
1979 debugs(3, DBG_CRITICAL, "WARNING: There is a fixed maximum of 63 cache_dir entries Squid can handle.");
1980 debugs(3, DBG_CRITICAL, "WARNING: '" << path_str << "' is one to many.");
1981 self_destruct();
1982 return;
1983 }
1984
1985 allocate_new_swapdir(swap);
1986
1987 swap->swapDirs[swap->n_configured] = StoreFileSystem::FileSystems().items[fs]->createSwapDir();
1988
1989 sd = dynamic_cast<SwapDir *>(swap->swapDirs[swap->n_configured].getRaw());
1990
1991 /* parse the FS parameters and options */
1992 sd->parse(swap->n_configured, path_str);
1993
1994 ++swap->n_configured;
1995
1996 /* Update the max object size */
1997 update_maxobjsize();
1998 }
1999
2000 static const char *
2001 peer_type_str(const peer_t type)
2002 {
2003 const char * result;
2004
2005 switch (type) {
2006
2007 case PEER_PARENT:
2008 result = "parent";
2009 break;
2010
2011 case PEER_SIBLING:
2012 result = "sibling";
2013 break;
2014
2015 case PEER_MULTICAST:
2016 result = "multicast";
2017 break;
2018
2019 default:
2020 result = "unknown";
2021 break;
2022 }
2023
2024 return result;
2025 }
2026
2027 static void
2028 dump_peer(StoreEntry * entry, const char *name, peer * p)
2029 {
2030 domain_ping *d;
2031 domain_type *t;
2032 LOCAL_ARRAY(char, xname, 128);
2033
2034 while (p != NULL) {
2035 storeAppendPrintf(entry, "%s %s %s %d %d name=%s",
2036 name,
2037 p->host,
2038 neighborTypeStr(p),
2039 p->http_port,
2040 p->icp.port,
2041 p->name);
2042 dump_peer_options(entry, p);
2043
2044 for (d = p->peer_domain; d; d = d->next) {
2045 storeAppendPrintf(entry, "cache_peer_domain %s %s%s\n",
2046 p->host,
2047 d->do_ping ? null_string : "!",
2048 d->domain);
2049 }
2050
2051 if (p->access) {
2052 snprintf(xname, 128, "cache_peer_access %s", p->name);
2053 dump_acl_access(entry, xname, p->access);
2054 }
2055
2056 for (t = p->typelist; t; t = t->next) {
2057 storeAppendPrintf(entry, "neighbor_type_domain %s %s %s\n",
2058 p->host,
2059 peer_type_str(t->type),
2060 t->domain);
2061 }
2062
2063 p = p->next;
2064 }
2065 }
2066
2067 /**
2068 * utility function to prevent getservbyname() being called with a numeric value
2069 * on Windows at least it returns garage results.
2070 */
2071 static bool
2072 isUnsignedNumeric(const char *str, size_t len)
2073 {
2074 if (len < 1) return false;
2075
2076 for (; len >0 && *str; str++, len--) {
2077 if (! isdigit(*str))
2078 return false;
2079 }
2080 return true;
2081 }
2082
2083 /**
2084 \param proto 'tcp' or 'udp' for protocol
2085 \returns Port the named service is supposed to be listening on.
2086 */
2087 static unsigned short
2088 GetService(const char *proto)
2089 {
2090 struct servent *port = NULL;
2091 /** Parses a port number or service name from the squid.conf */
2092 char *token = strtok(NULL, w_space);
2093 if (token == NULL) {
2094 self_destruct();
2095 return 0; /* NEVER REACHED */
2096 }
2097 /** Returns either the service port number from /etc/services */
2098 if ( !isUnsignedNumeric(token, strlen(token)) )
2099 port = getservbyname(token, proto);
2100 if (port != NULL) {
2101 return ntohs((unsigned short)port->s_port);
2102 }
2103 /** Or a numeric translation of the config text. */
2104 return xatos(token);
2105 }
2106
2107 /**
2108 \returns Port the named TCP service is supposed to be listening on.
2109 \copydoc GetService(const char *proto)
2110 */
2111 inline unsigned short
2112 GetTcpService(void)
2113 {
2114 return GetService("tcp");
2115 }
2116
2117 /**
2118 \returns Port the named UDP service is supposed to be listening on.
2119 \copydoc GetService(const char *proto)
2120 */
2121 inline unsigned short
2122 GetUdpService(void)
2123 {
2124 return GetService("udp");
2125 }
2126
2127 static void
2128 parse_peer(peer ** head)
2129 {
2130 char *token = NULL;
2131 peer *p;
2132 CBDATA_INIT_TYPE_FREECB(peer, peerDestroy);
2133 p = cbdataAlloc(peer);
2134 p->http_port = CACHE_HTTP_PORT;
2135 p->icp.port = CACHE_ICP_PORT;
2136 p->weight = 1;
2137 p->basetime = 0;
2138 p->stats.logged_state = PEER_ALIVE;
2139
2140 if ((token = strtok(NULL, w_space)) == NULL)
2141 self_destruct();
2142
2143 p->host = xstrdup(token);
2144
2145 p->name = xstrdup(token);
2146
2147 if ((token = strtok(NULL, w_space)) == NULL)
2148 self_destruct();
2149
2150 p->type = parseNeighborType(token);
2151
2152 if (p->type == PEER_MULTICAST) {
2153 p->options.no_digest = 1;
2154 p->options.no_netdb_exchange = 1;
2155 }
2156
2157 p->http_port = GetTcpService();
2158
2159 if (!p->http_port)
2160 self_destruct();
2161
2162 p->icp.port = GetUdpService();
2163 p->connection_auth = 2; /* auto */
2164
2165 while ((token = strtok(NULL, w_space))) {
2166 if (!strcasecmp(token, "proxy-only")) {
2167 p->options.proxy_only = 1;
2168 } else if (!strcasecmp(token, "no-query")) {
2169 p->options.no_query = 1;
2170 } else if (!strcasecmp(token, "background-ping")) {
2171 p->options.background_ping = 1;
2172 } else if (!strcasecmp(token, "no-digest")) {
2173 p->options.no_digest = 1;
2174 } else if (!strcasecmp(token, "no-tproxy")) {
2175 p->options.no_tproxy = 1;
2176 } else if (!strcasecmp(token, "multicast-responder")) {
2177 p->options.mcast_responder = 1;
2178 #if PEER_MULTICAST_SIBLINGS
2179 } else if (!strcasecmp(token, "multicast-siblings")) {
2180 p->options.mcast_siblings = 1;
2181 #endif
2182 } else if (!strncasecmp(token, "weight=", 7)) {
2183 p->weight = xatoi(token + 7);
2184 } else if (!strncasecmp(token, "basetime=", 9)) {
2185 p->basetime = xatoi(token + 9);
2186 } else if (!strcasecmp(token, "closest-only")) {
2187 p->options.closest_only = 1;
2188 } else if (!strncasecmp(token, "ttl=", 4)) {
2189 p->mcast.ttl = xatoi(token + 4);
2190
2191 if (p->mcast.ttl < 0)
2192 p->mcast.ttl = 0;
2193
2194 if (p->mcast.ttl > 128)
2195 p->mcast.ttl = 128;
2196 } else if (!strcasecmp(token, "default")) {
2197 p->options.default_parent = 1;
2198 } else if (!strcasecmp(token, "round-robin")) {
2199 p->options.roundrobin = 1;
2200 } else if (!strcasecmp(token, "weighted-round-robin")) {
2201 p->options.weighted_roundrobin = 1;
2202 #if USE_HTCP
2203 } else if (!strcasecmp(token, "htcp")) {
2204 p->options.htcp = 1;
2205 } else if (!strncasecmp(token, "htcp=", 5) || !strncasecmp(token, "htcp-", 5)) {
2206 /* Note: The htcp- form is deprecated, replaced by htcp= */
2207 p->options.htcp = 1;
2208 char *tmp = xstrdup(token+5);
2209 char *mode, *nextmode;
2210 for (mode = nextmode = tmp; mode; mode = nextmode) {
2211 nextmode = strchr(mode, ',');
2212 if (nextmode)
2213 *nextmode++ = '\0';
2214 if (!strcasecmp(mode, "no-clr")) {
2215 if (p->options.htcp_only_clr)
2216 fatalf("parse_peer: can't set htcp-no-clr and htcp-only-clr simultaneously");
2217 p->options.htcp_no_clr = 1;
2218 } else if (!strcasecmp(mode, "no-purge-clr")) {
2219 p->options.htcp_no_purge_clr = 1;
2220 } else if (!strcasecmp(mode, "only-clr")) {
2221 if (p->options.htcp_no_clr)
2222 fatalf("parse_peer: can't set htcp no-clr and only-clr simultaneously");
2223 p->options.htcp_only_clr = 1;
2224 } else if (!strcasecmp(mode, "forward-clr")) {
2225 p->options.htcp_forward_clr = 1;
2226 } else if (!strcasecmp(mode, "oldsquid")) {
2227 p->options.htcp_oldsquid = 1;
2228 } else {
2229 fatalf("invalid HTCP mode '%s'", mode);
2230 }
2231 }
2232 safe_free(tmp);
2233 #endif
2234 } else if (!strcasecmp(token, "no-netdb-exchange")) {
2235 p->options.no_netdb_exchange = 1;
2236
2237 } else if (!strcasecmp(token, "carp")) {
2238 if (p->type != PEER_PARENT)
2239 fatalf("parse_peer: non-parent carp peer %s/%d\n", p->host, p->http_port);
2240
2241 p->options.carp = 1;
2242 } else if (!strncasecmp(token, "carp-key=", 9)) {
2243 if (p->options.carp != 1)
2244 fatalf("parse_peer: carp-key specified on non-carp peer %s/%d\n", p->host, p->http_port);
2245 p->options.carp_key.set=1;
2246 char *nextkey=token+strlen("carp-key="), *key=nextkey;
2247 for (; key; key = nextkey) {
2248 nextkey=strchr(key,',');
2249 if (nextkey) ++nextkey; // skip the comma, any
2250 if (0==strncasecmp(key,"scheme",6)) {
2251 p->options.carp_key.scheme=1;
2252 } else if (0==strncasecmp(key,"host",4)) {
2253 p->options.carp_key.host=1;
2254 } else if (0==strncasecmp(key,"port",4)) {
2255 p->options.carp_key.port=1;
2256 } else if (0==strncasecmp(key,"path",4)) {
2257 p->options.carp_key.path=1;
2258 } else if (0==strncasecmp(key,"params",6)) {
2259 p->options.carp_key.params=1;
2260 } else {
2261 fatalf("invalid carp-key '%s'",key);
2262 }
2263 }
2264 } else if (!strcasecmp(token, "userhash")) {
2265 #if USE_AUTH
2266 if (p->type != PEER_PARENT)
2267 fatalf("parse_peer: non-parent userhash peer %s/%d\n", p->host, p->http_port);
2268
2269 p->options.userhash = 1;
2270 #else
2271 fatalf("parse_peer: userhash requires authentication. peer %s/%d\n", p->host, p->http_port);
2272 #endif
2273 } else if (!strcasecmp(token, "sourcehash")) {
2274 if (p->type != PEER_PARENT)
2275 fatalf("parse_peer: non-parent sourcehash peer %s/%d\n", p->host, p->http_port);
2276
2277 p->options.sourcehash = 1;
2278
2279 } else if (!strcasecmp(token, "no-delay")) {
2280 #if USE_DELAY_POOLS
2281 p->options.no_delay = 1;
2282 #else
2283 debugs(0, DBG_CRITICAL, "WARNING: cache_peer option 'no-delay' requires --enable-delay-pools");
2284 #endif
2285 } else if (!strncasecmp(token, "login=", 6)) {
2286 p->login = xstrdup(token + 6);
2287 rfc1738_unescape(p->login);
2288 } else if (!strncasecmp(token, "connect-timeout=", 16)) {
2289 p->connect_timeout = xatoi(token + 16);
2290 } else if (!strncasecmp(token, "connect-fail-limit=", 19)) {
2291 p->connect_fail_limit = xatoi(token + 19);
2292 #if USE_CACHE_DIGESTS
2293 } else if (!strncasecmp(token, "digest-url=", 11)) {
2294 p->digest_url = xstrdup(token + 11);
2295 #endif
2296
2297 } else if (!strcasecmp(token, "allow-miss")) {
2298 p->options.allow_miss = 1;
2299 } else if (!strncasecmp(token, "max-conn=", 9)) {
2300 p->max_conn = xatoi(token + 9);
2301 } else if (!strcasecmp(token, "originserver")) {
2302 p->options.originserver = 1;
2303 } else if (!strncasecmp(token, "name=", 5)) {
2304 safe_free(p->name);
2305
2306 if (token[5])
2307 p->name = xstrdup(token + 5);
2308 } else if (!strncasecmp(token, "forceddomain=", 13)) {
2309 safe_free(p->domain);
2310
2311 if (token[13])
2312 p->domain = xstrdup(token + 13);
2313
2314 #if USE_SSL
2315
2316 } else if (strcmp(token, "ssl") == 0) {
2317 p->use_ssl = 1;
2318 } else if (strncmp(token, "sslcert=", 8) == 0) {
2319 safe_free(p->sslcert);
2320 p->sslcert = xstrdup(token + 8);
2321 } else if (strncmp(token, "sslkey=", 7) == 0) {
2322 safe_free(p->sslkey);
2323 p->sslkey = xstrdup(token + 7);
2324 } else if (strncmp(token, "sslversion=", 11) == 0) {
2325 p->sslversion = atoi(token + 11);
2326 } else if (strncmp(token, "ssloptions=", 11) == 0) {
2327 safe_free(p->ssloptions);
2328 p->ssloptions = xstrdup(token + 11);
2329 } else if (strncmp(token, "sslcipher=", 10) == 0) {
2330 safe_free(p->sslcipher);
2331 p->sslcipher = xstrdup(token + 10);
2332 } else if (strncmp(token, "sslcafile=", 10) == 0) {
2333 safe_free(p->sslcafile);
2334 p->sslcafile = xstrdup(token + 10);
2335 } else if (strncmp(token, "sslcapath=", 10) == 0) {
2336 safe_free(p->sslcapath);
2337 p->sslcapath = xstrdup(token + 10);
2338 } else if (strncmp(token, "sslcrlfile=", 11) == 0) {
2339 safe_free(p->sslcrlfile);
2340 p->sslcapath = xstrdup(token + 10);
2341 } else if (strncmp(token, "sslflags=", 9) == 0) {
2342 safe_free(p->sslflags);
2343 p->sslflags = xstrdup(token + 9);
2344 } else if (strncmp(token, "ssldomain=", 10) == 0) {
2345 safe_free(p->ssldomain);
2346 p->ssldomain = xstrdup(token + 10);
2347 #endif
2348
2349 } else if (strcmp(token, "front-end-https") == 0) {
2350 p->front_end_https = 1;
2351 } else if (strcmp(token, "front-end-https=on") == 0) {
2352 p->front_end_https = 1;
2353 } else if (strcmp(token, "front-end-https=auto") == 0) {
2354 p->front_end_https = 2;
2355 } else if (strcmp(token, "connection-auth=off") == 0) {
2356 p->connection_auth = 0;
2357 } else if (strcmp(token, "connection-auth") == 0) {
2358 p->connection_auth = 1;
2359 } else if (strcmp(token, "connection-auth=on") == 0) {
2360 p->connection_auth = 1;
2361 } else if (strcmp(token, "connection-auth=auto") == 0) {
2362 p->connection_auth = 2;
2363 } else {
2364 debugs(3, 0, "parse_peer: token='" << token << "'");
2365 self_destruct();
2366 }
2367 }
2368
2369 if (peerFindByName(p->name))
2370 fatalf("ERROR: cache_peer %s specified twice\n", p->name);
2371
2372 if (p->weight < 1)
2373 p->weight = 1;
2374
2375 if (p->connect_fail_limit < 1)
2376 p->connect_fail_limit = 10;
2377
2378 p->icp.version = ICP_VERSION_CURRENT;
2379
2380 p->testing_now = false;
2381
2382 #if USE_CACHE_DIGESTS
2383
2384 if (!p->options.no_digest) {
2385 /* XXX This looks odd.. who has the original pointer
2386 * then?
2387 */
2388 PeerDigest *pd = peerDigestCreate(p);
2389 p->digest = cbdataReference(pd);
2390 }
2391
2392 #endif
2393
2394 p->index = ++Config.npeers;
2395
2396 while (*head != NULL)
2397 head = &(*head)->next;
2398
2399 *head = p;
2400
2401 peerClearRRStart();
2402 }
2403
2404 static void
2405 free_peer(peer ** P)
2406 {
2407 peer *p;
2408
2409 while ((p = *P) != NULL) {
2410 *P = p->next;
2411 #if USE_CACHE_DIGESTS
2412
2413 cbdataReferenceDone(p->digest);
2414 #endif
2415
2416 cbdataFree(p);
2417 }
2418
2419 Config.npeers = 0;
2420 }
2421
2422 static void
2423 dump_cachemgrpasswd(StoreEntry * entry, const char *name, cachemgr_passwd * list)
2424 {
2425 wordlist *w;
2426
2427 while (list != NULL) {
2428 if (strcmp(list->passwd, "none") && strcmp(list->passwd, "disable"))
2429 storeAppendPrintf(entry, "%s XXXXXXXXXX", name);
2430 else
2431 storeAppendPrintf(entry, "%s %s", name, list->passwd);
2432
2433 for (w = list->actions; w != NULL; w = w->next) {
2434 storeAppendPrintf(entry, " %s", w->key);
2435 }
2436
2437 storeAppendPrintf(entry, "\n");
2438 list = list->next;
2439 }
2440 }
2441
2442 static void
2443 parse_cachemgrpasswd(cachemgr_passwd ** head)
2444 {
2445 char *passwd = NULL;
2446 wordlist *actions = NULL;
2447 cachemgr_passwd *p;
2448 cachemgr_passwd **P;
2449 parse_string(&passwd);
2450 parse_wordlist(&actions);
2451 p = static_cast<cachemgr_passwd *>(xcalloc(1, sizeof(cachemgr_passwd)));
2452 p->passwd = passwd;
2453 p->actions = actions;
2454
2455 for (P = head; *P; P = &(*P)->next) {
2456 /*
2457 * See if any of the actions from this line already have a
2458 * password from previous lines. The password checking
2459 * routines in cache_manager.c take the the password from
2460 * the first cachemgr_passwd struct that contains the
2461 * requested action. Thus, we should warn users who might
2462 * think they can have two passwords for the same action.
2463 */
2464 wordlist *w;
2465 wordlist *u;
2466
2467 for (w = (*P)->actions; w; w = w->next) {
2468 for (u = actions; u; u = u->next) {
2469 if (strcmp(w->key, u->key))
2470 continue;
2471
2472 debugs(0, 0, "WARNING: action '" << u->key << "' (line " << config_lineno << ") already has a password");
2473 }
2474 }
2475 }
2476
2477 *P = p;
2478 }
2479
2480 static void
2481 free_cachemgrpasswd(cachemgr_passwd ** head)
2482 {
2483 cachemgr_passwd *p;
2484
2485 while ((p = *head) != NULL) {
2486 *head = p->next;
2487 xfree(p->passwd);
2488 wordlistDestroy(&p->actions);
2489 xfree(p);
2490 }
2491 }
2492
2493 static void
2494 dump_denyinfo(StoreEntry * entry, const char *name, acl_deny_info_list * var)
2495 {
2496 acl_name_list *a;
2497
2498 while (var != NULL) {
2499 storeAppendPrintf(entry, "%s %s", name, var->err_page_name);
2500
2501 for (a = var->acl_list; a != NULL; a = a->next)
2502 storeAppendPrintf(entry, " %s", a->name);
2503
2504 storeAppendPrintf(entry, "\n");
2505
2506 var = var->next;
2507 }
2508 }
2509
2510 static void
2511 parse_denyinfo(acl_deny_info_list ** var)
2512 {
2513 aclParseDenyInfoLine(var);
2514 }
2515
2516 void
2517 free_denyinfo(acl_deny_info_list ** list)
2518 {
2519 acl_deny_info_list *a = NULL;
2520 acl_deny_info_list *a_next = NULL;
2521 acl_name_list *l = NULL;
2522 acl_name_list *l_next = NULL;
2523
2524 for (a = *list; a; a = a_next) {
2525 for (l = a->acl_list; l; l = l_next) {
2526 l_next = l->next;
2527 memFree(l, MEM_ACL_NAME_LIST);
2528 l = NULL;
2529 }
2530
2531 a_next = a->next;
2532 memFree(a, MEM_ACL_DENY_INFO_LIST);
2533 a = NULL;
2534 }
2535
2536 *list = NULL;
2537 }
2538
2539 static void
2540 parse_peer_access(void)
2541 {
2542 char *host = NULL;
2543 peer *p;
2544
2545 if (!(host = strtok(NULL, w_space)))
2546 self_destruct();
2547
2548 if ((p = peerFindByName(host)) == NULL) {
2549 debugs(15, 0, "" << cfg_filename << ", line " << config_lineno << ": No cache_peer '" << host << "'");
2550 return;
2551 }
2552
2553 aclParseAccessLine(LegacyParser, &p->access);
2554 }
2555
2556 static void
2557 parse_hostdomain(void)
2558 {
2559 char *host = NULL;
2560 char *domain = NULL;
2561
2562 if (!(host = strtok(NULL, w_space)))
2563 self_destruct();
2564
2565 while ((domain = strtok(NULL, list_sep))) {
2566 domain_ping *l = NULL;
2567 domain_ping **L = NULL;
2568 peer *p;
2569
2570 if ((p = peerFindByName(host)) == NULL) {
2571 debugs(15, 0, "" << cfg_filename << ", line " << config_lineno << ": No cache_peer '" << host << "'");
2572 continue;
2573 }
2574
2575 l = static_cast<domain_ping *>(xcalloc(1, sizeof(domain_ping)));
2576 l->do_ping = 1;
2577
2578 if (*domain == '!') { /* check for !.edu */
2579 l->do_ping = 0;
2580 domain++;
2581 }
2582
2583 l->domain = xstrdup(domain);
2584
2585 for (L = &(p->peer_domain); *L; L = &((*L)->next));
2586 *L = l;
2587 }
2588 }
2589
2590 static void
2591 parse_hostdomaintype(void)
2592 {
2593 char *host = NULL;
2594 char *type = NULL;
2595 char *domain = NULL;
2596
2597 if (!(host = strtok(NULL, w_space)))
2598 self_destruct();
2599
2600 if (!(type = strtok(NULL, w_space)))
2601 self_destruct();
2602
2603 while ((domain = strtok(NULL, list_sep))) {
2604 domain_type *l = NULL;
2605 domain_type **L = NULL;
2606 peer *p;
2607
2608 if ((p = peerFindByName(host)) == NULL) {
2609 debugs(15, 0, "" << cfg_filename << ", line " << config_lineno << ": No cache_peer '" << host << "'");
2610 return;
2611 }
2612
2613 l = static_cast<domain_type *>(xcalloc(1, sizeof(domain_type)));
2614 l->type = parseNeighborType(type);
2615 l->domain = xstrdup(domain);
2616
2617 for (L = &(p->typelist); *L; L = &((*L)->next));
2618 *L = l;
2619 }
2620 }
2621
2622 static void
2623 dump_int(StoreEntry * entry, const char *name, int var)
2624 {
2625 storeAppendPrintf(entry, "%s %d\n", name, var);
2626 }
2627
2628 void
2629 parse_int(int *var)
2630 {
2631 int i;
2632 i = GetInteger();
2633 *var = i;
2634 }
2635
2636 static void
2637 free_int(int *var)
2638 {
2639 *var = 0;
2640 }
2641
2642 static void
2643 dump_onoff(StoreEntry * entry, const char *name, int var)
2644 {
2645 storeAppendPrintf(entry, "%s %s\n", name, var ? "on" : "off");
2646 }
2647
2648 void
2649 parse_onoff(int *var)
2650 {
2651 char *token = strtok(NULL, w_space);
2652
2653 if (token == NULL)
2654 self_destruct();
2655
2656 if (!strcasecmp(token, "on") || !strcasecmp(token, "enable"))
2657 *var = 1;
2658 else
2659 *var = 0;
2660 }
2661
2662 #define free_onoff free_int
2663
2664 static void
2665 dump_tristate(StoreEntry * entry, const char *name, int var)
2666 {
2667 const char *state;
2668
2669 if (var > 0)
2670 state = "on";
2671 else if (var < 0)
2672 state = "warn";
2673 else
2674 state = "off";
2675
2676 storeAppendPrintf(entry, "%s %s\n", name, state);
2677 }
2678
2679 static void
2680 parse_tristate(int *var)
2681 {
2682 char *token = strtok(NULL, w_space);
2683
2684 if (token == NULL)
2685 self_destruct();
2686
2687 if (!strcasecmp(token, "on") || !strcasecmp(token, "enable"))
2688 *var = 1;
2689 else if (!strcasecmp(token, "warn"))
2690 *var = -1;
2691 else
2692 *var = 0;
2693 }
2694
2695 #define free_tristate free_int
2696
2697 static void
2698 dump_refreshpattern(StoreEntry * entry, const char *name, refresh_t * head)
2699 {
2700 while (head != NULL) {
2701 storeAppendPrintf(entry, "%s%s %s %d %d%% %d",
2702 name,
2703 head->flags.icase ? " -i" : null_string,
2704 head->pattern,
2705 (int) head->min / 60,
2706 (int) (100.0 * head->pct + 0.5),
2707 (int) head->max / 60);
2708
2709 if (head->max_stale >= 0)
2710 storeAppendPrintf(entry, " max-stale=%d", head->max_stale);
2711
2712 if (head->flags.refresh_ims)
2713 storeAppendPrintf(entry, " refresh-ims");
2714
2715 if (head->flags.store_stale)
2716 storeAppendPrintf(entry, " store-stale");
2717
2718 #if USE_HTTP_VIOLATIONS
2719
2720 if (head->flags.override_expire)
2721 storeAppendPrintf(entry, " override-expire");
2722
2723 if (head->flags.override_lastmod)
2724 storeAppendPrintf(entry, " override-lastmod");
2725
2726 if (head->flags.reload_into_ims)
2727 storeAppendPrintf(entry, " reload-into-ims");
2728
2729 if (head->flags.ignore_reload)
2730 storeAppendPrintf(entry, " ignore-reload");
2731
2732 if (head->flags.ignore_no_cache)
2733 storeAppendPrintf(entry, " ignore-no-cache");
2734
2735 if (head->flags.ignore_no_store)
2736 storeAppendPrintf(entry, " ignore-no-store");
2737
2738 if (head->flags.ignore_must_revalidate)
2739 storeAppendPrintf(entry, " ignore-must-revalidate");
2740
2741 if (head->flags.ignore_private)
2742 storeAppendPrintf(entry, " ignore-private");
2743
2744 if (head->flags.ignore_auth)
2745 storeAppendPrintf(entry, " ignore-auth");
2746
2747 #endif
2748
2749 storeAppendPrintf(entry, "\n");
2750
2751 head = head->next;
2752 }
2753 }
2754
2755 static void
2756 parse_refreshpattern(refresh_t ** head)
2757 {
2758 char *token;
2759 char *pattern;
2760 time_t min = 0;
2761 double pct = 0.0;
2762 time_t max = 0;
2763 int refresh_ims = 0;
2764 int store_stale = 0;
2765 int max_stale = -1;
2766
2767 #if USE_HTTP_VIOLATIONS
2768
2769 int override_expire = 0;
2770 int override_lastmod = 0;
2771 int reload_into_ims = 0;
2772 int ignore_reload = 0;
2773 int ignore_no_cache = 0;
2774 int ignore_no_store = 0;
2775 int ignore_must_revalidate = 0;
2776 int ignore_private = 0;
2777 int ignore_auth = 0;
2778 #endif
2779
2780 int i;
2781 refresh_t *t;
2782 regex_t comp;
2783 int errcode;
2784 int flags = REG_EXTENDED | REG_NOSUB;
2785
2786 if ((token = strtok(NULL, w_space)) == NULL) {
2787 self_destruct();
2788 return;
2789 }
2790
2791 if (strcmp(token, "-i") == 0) {
2792 flags |= REG_ICASE;
2793 token = strtok(NULL, w_space);
2794 } else if (strcmp(token, "+i") == 0) {
2795 flags &= ~REG_ICASE;
2796 token = strtok(NULL, w_space);
2797 }
2798
2799 if (token == NULL) {
2800 self_destruct();
2801 return;
2802 }
2803
2804 pattern = xstrdup(token);
2805
2806 i = GetInteger(); /* token: min */
2807
2808 /* catch negative and insanely huge values close to 32-bit wrap */
2809 if (i < 0) {
2810 debugs(3, DBG_IMPORTANT, "WARNING: refresh_pattern minimum age negative. Cropped back to zero.");
2811 i = 0;
2812 }
2813 if (i > 60*24*365) {
2814 debugs(3, DBG_IMPORTANT, "WARNING: refresh_pattern minimum age too high. Cropped back to 1 year.");
2815 i = 60*24*365;
2816 }
2817
2818 min = (time_t) (i * 60); /* convert minutes to seconds */
2819
2820 i = GetInteger(); /* token: pct */
2821
2822 pct = (double) i / 100.0;
2823
2824 i = GetInteger(); /* token: max */
2825
2826 /* catch negative and insanely huge values close to 32-bit wrap */
2827 if (i < 0) {
2828 debugs(3, DBG_IMPORTANT, "WARNING: refresh_pattern maximum age negative. Cropped back to zero.");
2829 i = 0;
2830 }
2831 if (i > 60*24*365) {
2832 debugs(3, DBG_IMPORTANT, "WARNING: refresh_pattern maximum age too high. Cropped back to 1 year.");
2833 i = 60*24*365;
2834 }
2835
2836 max = (time_t) (i * 60); /* convert minutes to seconds */
2837
2838 /* Options */
2839 while ((token = strtok(NULL, w_space)) != NULL) {
2840 if (!strcmp(token, "refresh-ims")) {
2841 refresh_ims = 1;
2842 } else if (!strcmp(token, "store-stale")) {
2843 store_stale = 1;
2844 } else if (!strncmp(token, "max-stale=", 10)) {
2845 max_stale = atoi(token + 10);
2846 #if USE_HTTP_VIOLATIONS
2847
2848 } else if (!strcmp(token, "override-expire"))
2849 override_expire = 1;
2850 else if (!strcmp(token, "override-lastmod"))
2851 override_lastmod = 1;
2852 else if (!strcmp(token, "ignore-no-cache"))
2853 ignore_no_cache = 1;
2854 else if (!strcmp(token, "ignore-no-store"))
2855 ignore_no_store = 1;
2856 else if (!strcmp(token, "ignore-must-revalidate"))
2857 ignore_must_revalidate = 1;
2858 else if (!strcmp(token, "ignore-private"))
2859 ignore_private = 1;
2860 else if (!strcmp(token, "ignore-auth"))
2861 ignore_auth = 1;
2862 else if (!strcmp(token, "reload-into-ims")) {
2863 reload_into_ims = 1;
2864 refresh_nocache_hack = 1;
2865 /* tell client_side.c that this is used */
2866 } else if (!strcmp(token, "ignore-reload")) {
2867 ignore_reload = 1;
2868 refresh_nocache_hack = 1;
2869 /* tell client_side.c that this is used */
2870 #endif
2871
2872 } else
2873 debugs(22, 0, "refreshAddToList: Unknown option '" << pattern << "': " << token);
2874 }
2875
2876 if ((errcode = regcomp(&comp, pattern, flags)) != 0) {
2877 char errbuf[256];
2878 regerror(errcode, &comp, errbuf, sizeof errbuf);
2879 debugs(22, 0, "" << cfg_filename << " line " << config_lineno << ": " << config_input_line);
2880 debugs(22, 0, "refreshAddToList: Invalid regular expression '" << pattern << "': " << errbuf);
2881 return;
2882 }
2883
2884 pct = pct < 0.0 ? 0.0 : pct;
2885 max = max < 0 ? 0 : max;
2886 t = static_cast<refresh_t *>(xcalloc(1, sizeof(refresh_t)));
2887 t->pattern = (char *) xstrdup(pattern);
2888 t->compiled_pattern = comp;
2889 t->min = min;
2890 t->pct = pct;
2891 t->max = max;
2892
2893 if (flags & REG_ICASE)
2894 t->flags.icase = 1;
2895
2896 if (refresh_ims)
2897 t->flags.refresh_ims = 1;
2898
2899 if (store_stale)
2900 t->flags.store_stale = 1;
2901
2902 t->max_stale = max_stale;
2903
2904 #if USE_HTTP_VIOLATIONS
2905
2906 if (override_expire)
2907 t->flags.override_expire = 1;
2908
2909 if (override_lastmod)
2910 t->flags.override_lastmod = 1;
2911
2912 if (reload_into_ims)
2913 t->flags.reload_into_ims = 1;
2914
2915 if (ignore_reload)
2916 t->flags.ignore_reload = 1;
2917
2918 if (ignore_no_cache)
2919 t->flags.ignore_no_cache = 1;
2920
2921 if (ignore_no_store)
2922 t->flags.ignore_no_store = 1;
2923
2924 if (ignore_must_revalidate)
2925 t->flags.ignore_must_revalidate = 1;
2926
2927 if (ignore_private)
2928 t->flags.ignore_private = 1;
2929
2930 if (ignore_auth)
2931 t->flags.ignore_auth = 1;
2932
2933 #endif
2934
2935 t->next = NULL;
2936
2937 while (*head)
2938 head = &(*head)->next;
2939
2940 *head = t;
2941
2942 safe_free(pattern);
2943 }
2944
2945 static void
2946 free_refreshpattern(refresh_t ** head)
2947 {
2948 refresh_t *t;
2949
2950 while ((t = *head) != NULL) {
2951 *head = t->next;
2952 safe_free(t->pattern);
2953 regfree(&t->compiled_pattern);
2954 safe_free(t);
2955 }
2956
2957 #if USE_HTTP_VIOLATIONS
2958 refresh_nocache_hack = 0;
2959
2960 #endif
2961 }
2962
2963 static void
2964 dump_string(StoreEntry * entry, const char *name, char *var)
2965 {
2966 if (var != NULL)
2967 storeAppendPrintf(entry, "%s %s\n", name, var);
2968 }
2969
2970 static void
2971 parse_string(char **var)
2972 {
2973 char *token = strtok(NULL, w_space);
2974 safe_free(*var);
2975
2976 if (token == NULL)
2977 self_destruct();
2978
2979 *var = xstrdup(token);
2980 }
2981
2982 void
2983 ConfigParser::ParseString(char **var)
2984 {
2985 parse_string(var);
2986 }
2987
2988 void
2989 ConfigParser::ParseString(String *var)
2990 {
2991 char *token = strtok(NULL, w_space);
2992
2993 if (token == NULL)
2994 self_destruct();
2995
2996 var->reset(token);
2997 }
2998
2999 static void
3000 free_string(char **var)
3001 {
3002 safe_free(*var);
3003 }
3004
3005 void
3006 parse_eol(char *volatile *var)
3007 {
3008 if (!var) {
3009 self_destruct();
3010 return;
3011 }
3012
3013 unsigned char *token = (unsigned char *) strtok(NULL, null_string);
3014 safe_free(*var);
3015
3016 if (!token) {
3017 self_destruct();
3018 return;
3019 }
3020
3021 while (*token && xisspace(*token))
3022 token++;
3023
3024 if (!*token) {
3025 self_destruct();
3026 return;
3027 }
3028
3029 *var = xstrdup((char *) token);
3030 }
3031
3032 #define dump_eol dump_string
3033 #define free_eol free_string
3034
3035 static void
3036 dump_time_t(StoreEntry * entry, const char *name, time_t var)
3037 {
3038 storeAppendPrintf(entry, "%s %d seconds\n", name, (int) var);
3039 }
3040
3041 void
3042 parse_time_t(time_t * var)
3043 {
3044 time_msec_t tval;
3045 parseTimeLine(&tval, T_SECOND_STR, false);
3046 *var = static_cast<time_t>(tval/1000);
3047 }
3048
3049 static void
3050 free_time_t(time_t * var)
3051 {
3052 *var = 0;
3053 }
3054
3055 #if !USE_DNSHELPER
3056 static void
3057 dump_time_msec(StoreEntry * entry, const char *name, time_msec_t var)
3058 {
3059 if (var % 1000)
3060 storeAppendPrintf(entry, "%s %"PRId64" milliseconds\n", name, var);
3061 else
3062 storeAppendPrintf(entry, "%s %d seconds\n", name, (int)(var/1000) );
3063 }
3064
3065 void
3066 parse_time_msec(time_msec_t * var)
3067 {
3068 parseTimeLine(var, T_SECOND_STR, true);
3069 }
3070
3071 static void
3072 free_time_msec(time_msec_t * var)
3073 {
3074 *var = 0;
3075 }
3076 #endif
3077
3078 #if UNUSED_CODE
3079 static void
3080 dump_size_t(StoreEntry * entry, const char *name, size_t var)
3081 {
3082 storeAppendPrintf(entry, "%s %d\n", name, (int) var);
3083 }
3084 #endif
3085
3086 static void
3087 dump_b_size_t(StoreEntry * entry, const char *name, size_t var)
3088 {
3089 storeAppendPrintf(entry, "%s %d %s\n", name, (int) var, B_BYTES_STR);
3090 }
3091
3092 #if !USE_DNSHELPER
3093 static void
3094 dump_b_ssize_t(StoreEntry * entry, const char *name, ssize_t var)
3095 {
3096 storeAppendPrintf(entry, "%s %d %s\n", name, (int) var, B_BYTES_STR);
3097 }
3098 #endif
3099
3100 #if UNUSED_CODE
3101 static void
3102 dump_kb_size_t(StoreEntry * entry, const char *name, size_t var)
3103 {
3104 storeAppendPrintf(entry, "%s %d %s\n", name, (int) var, B_KBYTES_STR);
3105 }
3106 #endif
3107
3108 static void
3109 dump_b_int64_t(StoreEntry * entry, const char *name, int64_t var)
3110 {
3111 storeAppendPrintf(entry, "%s %"PRId64" %s\n", name, var, B_BYTES_STR);
3112 }
3113
3114 static void
3115 dump_kb_int64_t(StoreEntry * entry, const char *name, int64_t var)
3116 {
3117 storeAppendPrintf(entry, "%s %"PRId64" %s\n", name, var, B_KBYTES_STR);
3118 }
3119
3120 #if UNUSED_CODE
3121 static void
3122 parse_size_t(size_t * var)
3123 {
3124 int i;
3125 i = GetInteger();
3126 *var = (size_t) i;
3127 }
3128 #endif
3129
3130 static void
3131 parse_b_size_t(size_t * var)
3132 {
3133 parseBytesLine(var, B_BYTES_STR);
3134 }
3135
3136 #if !USE_DNSHELPER
3137 static void
3138 parse_b_ssize_t(ssize_t * var)
3139 {
3140 parseBytesLineSigned(var, B_BYTES_STR);
3141 }
3142 #endif
3143
3144 #if UNUSED_CODE
3145 static void
3146 parse_kb_size_t(size_t * var)
3147 {
3148 parseBytesLine(var, B_KBYTES_STR);
3149 }
3150 #endif
3151
3152 static void
3153 parse_b_int64_t(int64_t * var)
3154 {
3155 parseBytesLine64(var, B_BYTES_STR);
3156 }
3157
3158 static void
3159 parse_kb_int64_t(int64_t * var)
3160 {
3161 parseBytesLine64(var, B_KBYTES_STR);
3162 }
3163
3164 static void
3165 free_size_t(size_t * var)
3166 {
3167 *var = 0;
3168 }
3169
3170 #if !USE_DNSHELPER
3171 static void
3172 free_ssize_t(ssize_t * var)
3173 {
3174 *var = 0;
3175 }
3176 #endif
3177
3178 static void
3179 free_b_int64_t(int64_t * var)
3180 {
3181 *var = 0;
3182 }
3183
3184 #define free_b_size_t free_size_t
3185 #define free_b_ssize_t free_ssize_t
3186 #define free_kb_size_t free_size_t
3187 #define free_mb_size_t free_size_t
3188 #define free_gb_size_t free_size_t
3189 #define free_kb_int64_t free_b_int64_t
3190
3191 static void
3192 dump_u_short(StoreEntry * entry, const char *name, unsigned short var)
3193 {
3194 storeAppendPrintf(entry, "%s %d\n", name, var);
3195 }
3196
3197 static void
3198 free_u_short(unsigned short * u)
3199 {
3200 *u = 0;
3201 }
3202
3203 static void
3204 parse_u_short(unsigned short * var)
3205 {
3206 ConfigParser::ParseUShort(var);
3207 }
3208
3209 void
3210 ConfigParser::ParseUShort(unsigned short *var)
3211 {
3212 *var = GetShort();
3213 }
3214
3215 void
3216 ConfigParser::ParseBool(bool *var)
3217 {
3218 int i = GetInteger();
3219
3220 if (0 == i)
3221 *var = false;
3222 else if (1 == i)
3223 *var = true;
3224 else
3225 self_destruct();
3226 }
3227
3228 static void
3229 dump_wordlist(StoreEntry * entry, const char *name, wordlist * list)
3230 {
3231 while (list != NULL) {
3232 storeAppendPrintf(entry, "%s %s\n", name, list->key);
3233 list = list->next;
3234 }
3235 }
3236
3237 void
3238 ConfigParser::ParseWordList(wordlist ** list)
3239 {
3240 parse_wordlist(list);
3241 }
3242
3243 void
3244 parse_wordlist(wordlist ** list)
3245 {
3246 char *token;
3247 char *t = strtok(NULL, "");
3248
3249 while ((token = strwordtok(NULL, &t)))
3250 wordlistAdd(list, token);
3251 }
3252
3253 #if 0 /* now unused */
3254 static int
3255 check_null_wordlist(wordlist * w)
3256 {
3257 return w == NULL;
3258 }
3259 #endif
3260
3261 static int
3262 check_null_acl_access(acl_access * a)
3263 {
3264 return a == NULL;
3265 }
3266
3267 #define free_wordlist wordlistDestroy
3268
3269 #define free_uri_whitespace free_int
3270
3271 static void
3272 parse_uri_whitespace(int *var)
3273 {
3274 char *token = strtok(NULL, w_space);
3275
3276 if (token == NULL)
3277 self_destruct();
3278
3279 if (!strcasecmp(token, "strip"))
3280 *var = URI_WHITESPACE_STRIP;
3281 else if (!strcasecmp(token, "deny"))
3282 *var = URI_WHITESPACE_DENY;
3283 else if (!strcasecmp(token, "allow"))
3284 *var = URI_WHITESPACE_ALLOW;
3285 else if (!strcasecmp(token, "encode"))
3286 *var = URI_WHITESPACE_ENCODE;
3287 else if (!strcasecmp(token, "chop"))
3288 *var = URI_WHITESPACE_CHOP;
3289 else
3290 self_destruct();
3291 }
3292
3293 static void
3294 dump_uri_whitespace(StoreEntry * entry, const char *name, int var)
3295 {
3296 const char *s;
3297
3298 if (var == URI_WHITESPACE_ALLOW)
3299 s = "allow";
3300 else if (var == URI_WHITESPACE_ENCODE)
3301 s = "encode";
3302 else if (var == URI_WHITESPACE_CHOP)
3303 s = "chop";
3304 else if (var == URI_WHITESPACE_DENY)
3305 s = "deny";
3306 else
3307 s = "strip";
3308
3309 storeAppendPrintf(entry, "%s %s\n", name, s);
3310 }
3311
3312 static void
3313 free_removalpolicy(RemovalPolicySettings ** settings)
3314 {
3315 if (!*settings)
3316 return;
3317
3318 free_string(&(*settings)->type);
3319
3320 free_wordlist(&(*settings)->args);
3321
3322 delete *settings;
3323
3324 *settings = NULL;
3325 }
3326
3327 static void
3328 parse_removalpolicy(RemovalPolicySettings ** settings)
3329 {
3330 if (*settings)
3331 free_removalpolicy(settings);
3332
3333 *settings = new RemovalPolicySettings;
3334
3335 parse_string(&(*settings)->type);
3336
3337 parse_wordlist(&(*settings)->args);
3338 }
3339
3340 static void
3341 dump_removalpolicy(StoreEntry * entry, const char *name, RemovalPolicySettings * settings)
3342 {
3343 wordlist *args;
3344 storeAppendPrintf(entry, "%s %s", name, settings->type);
3345 args = settings->args;
3346
3347 while (args) {
3348 storeAppendPrintf(entry, " %s", args->key);
3349 args = args->next;
3350 }
3351
3352 storeAppendPrintf(entry, "\n");
3353 }
3354
3355 void
3356 YesNoNone::configure(bool beSet)
3357 {
3358 option = beSet ? +1 : -1;
3359 }
3360
3361 YesNoNone::operator void*() const
3362 {
3363 assert(option != 0); // must call configure() first
3364 return option > 0 ? (void*)this : NULL;
3365 }
3366
3367
3368 inline void
3369 free_YesNoNone(YesNoNone *)
3370 {
3371 // do nothing: no explicit cleanup is required
3372 }
3373
3374 static void
3375 parse_YesNoNone(YesNoNone *option)
3376 {
3377 int value = 0;
3378 parse_onoff(&value);
3379 option->configure(value > 0);
3380 }
3381
3382 static void
3383 dump_YesNoNone(StoreEntry * entry, const char *name, YesNoNone &option)
3384 {
3385 if (option.configured())
3386 dump_onoff(entry, name, option ? 1 : 0);
3387 }
3388
3389 static void
3390 free_memcachemode(SquidConfig * config)
3391 {
3392 return;
3393 }
3394
3395 static void
3396 parse_memcachemode(SquidConfig * config)
3397 {
3398 char *token = strtok(NULL, w_space);
3399 if (!token)
3400 self_destruct();
3401
3402 if (strcmp(token, "always") == 0) {
3403 Config.onoff.memory_cache_first = 1;
3404 Config.onoff.memory_cache_disk = 1;
3405 } else if (strcmp(token, "disk") == 0) {
3406 Config.onoff.memory_cache_first = 0;
3407 Config.onoff.memory_cache_disk = 1;
3408 } else if (strncmp(token, "net", 3) == 0) {
3409 Config.onoff.memory_cache_first = 1;
3410 Config.onoff.memory_cache_disk = 0;
3411 } else if (strcmp(token, "never") == 0) {
3412 Config.onoff.memory_cache_first = 0;
3413 Config.onoff.memory_cache_disk = 0;
3414 } else
3415 self_destruct();
3416 }
3417
3418 static void
3419 dump_memcachemode(StoreEntry * entry, const char *name, SquidConfig &config)
3420 {
3421 storeAppendPrintf(entry, "%s ", name);
3422 if (Config.onoff.memory_cache_first && Config.onoff.memory_cache_disk)
3423 storeAppendPrintf(entry, "always");
3424 else if (!Config.onoff.memory_cache_first && Config.onoff.memory_cache_disk)
3425 storeAppendPrintf(entry, "disk");
3426 else if (Config.onoff.memory_cache_first && !Config.onoff.memory_cache_disk)
3427 storeAppendPrintf(entry, "network");
3428 else if (!Config.onoff.memory_cache_first && !Config.onoff.memory_cache_disk)
3429 storeAppendPrintf(entry, "none");
3430 storeAppendPrintf(entry, "\n");
3431 }
3432
3433 #include "cf_parser.cci"
3434
3435 peer_t
3436 parseNeighborType(const char *s)
3437 {
3438 if (!strcasecmp(s, "parent"))
3439 return PEER_PARENT;
3440
3441 if (!strcasecmp(s, "neighbor"))
3442 return PEER_SIBLING;
3443
3444 if (!strcasecmp(s, "neighbour"))
3445 return PEER_SIBLING;
3446
3447 if (!strcasecmp(s, "sibling"))
3448 return PEER_SIBLING;
3449
3450 if (!strcasecmp(s, "multicast"))
3451 return PEER_MULTICAST;
3452
3453 debugs(15, 0, "WARNING: Unknown neighbor type: " << s);
3454
3455 return PEER_SIBLING;
3456 }
3457
3458 #if USE_WCCPv2
3459 static void
3460 parse_IpAddress_list(Ip::Address_list ** head)
3461 {
3462 char *token;
3463 Ip::Address_list *s;
3464 Ip::Address ipa;
3465
3466 while ((token = strtok(NULL, w_space))) {
3467 if (GetHostWithPort(token, &ipa)) {
3468
3469 while (*head)
3470 head = &(*head)->next;
3471
3472 s = static_cast<Ip::Address_list *>(xcalloc(1, sizeof(*s)));
3473 s->s = ipa;
3474
3475 *head = s;
3476 } else
3477 self_destruct();
3478 }
3479 }
3480
3481 static void
3482 dump_IpAddress_list(StoreEntry * e, const char *n, const Ip::Address_list * s)
3483 {
3484 char ntoabuf[MAX_IPSTRLEN];
3485
3486 while (s) {
3487 storeAppendPrintf(e, "%s %s\n",
3488 n,
3489 s->s.NtoA(ntoabuf,MAX_IPSTRLEN));
3490 s = s->next;
3491 }
3492 }
3493
3494 static void
3495 free_IpAddress_list(Ip::Address_list ** head)
3496 {
3497 if (*head) delete *head;
3498 *head = NULL;
3499 }
3500
3501 #if CURRENTLY_UNUSED
3502 /* This code was previously used by http_port. Left as it really should
3503 * be used by icp_port and htcp_port
3504 */
3505 static int
3506 check_null_IpAddress_list(const Ip::Address_list * s)
3507 {
3508 return NULL == s;
3509 }
3510
3511 #endif /* CURRENTLY_UNUSED */
3512 #endif /* USE_WCCPv2 */
3513
3514 CBDATA_CLASS_INIT(http_port_list);
3515
3516 static void
3517 parsePortSpecification(http_port_list * s, char *token)
3518 {
3519 char *host = NULL;
3520 unsigned short port = 0;
3521 char *t = NULL;
3522 char *junk = NULL;
3523
3524 s->disable_pmtu_discovery = DISABLE_PMTU_OFF;
3525 s->name = xstrdup(token);
3526 s->connection_auth_disabled = false;
3527
3528 if (*token == '[') {
3529 /* [ipv6]:port */
3530 host = token + 1;
3531 t = strchr(host, ']');
3532 if (!t) {
3533 debugs(3, DBG_CRITICAL, s->protocol << "_port: missing ']' on IPv6 address: " << token);
3534 self_destruct();
3535 }
3536 *t++ = '\0';
3537 if (*t != ':') {
3538 debugs(3, DBG_CRITICAL, s->protocol << "_port: missing Port in: " << token);
3539 self_destruct();
3540 }
3541 if (!Ip::EnableIpv6) {
3542 debugs(3, DBG_CRITICAL, "FATAL: " << s->protocol << "_port: IPv6 is not available.");
3543 self_destruct();
3544 }
3545 port = xatos(t + 1);
3546 } else if ((t = strchr(token, ':'))) {
3547 /* host:port */
3548 /* ipv4:port */
3549 host = token;
3550 *t = '\0';
3551 port = xatos(t + 1);
3552
3553 } else if ((port = strtol(token, &junk, 10)), !*junk) {
3554 /* port */
3555 debugs(3, 3, s->protocol << "_port: found Listen on Port: " << port);
3556 } else {
3557 debugs(3, DBG_CRITICAL, s->protocol << "_port: missing Port: " << token);
3558 self_destruct();
3559 }
3560
3561 if (port == 0 && host != NULL) {
3562 debugs(3, DBG_CRITICAL, s->protocol << "_port: Port cannot be 0: " << token);
3563 self_destruct();
3564 }
3565
3566 if (NULL == host) {
3567 s->s.SetAnyAddr();
3568 s->s.SetPort(port);
3569 if (!Ip::EnableIpv6)
3570 s->s.SetIPv4();
3571 debugs(3, 3, s->protocol << "_port: found Listen on wildcard address: *:" << s->s.GetPort() );
3572 } else if ( (s->s = host) ) { /* check/parse numeric IPA */
3573 s->s.SetPort(port);
3574 if (!Ip::EnableIpv6)
3575 s->s.SetIPv4();
3576 debugs(3, 3, s->protocol << "_port: Listen on Host/IP: " << host << " --> " << s->s);
3577 } else if ( s->s.GetHostByName(host) ) { /* check/parse for FQDN */
3578 /* dont use ipcache */
3579 s->defaultsite = xstrdup(host);
3580 s->s.SetPort(port);
3581 if (!Ip::EnableIpv6)
3582 s->s.SetIPv4();
3583 debugs(3, 3, s->protocol << "_port: found Listen as Host " << s->defaultsite << " on IP: " << s->s);
3584 } else {
3585 debugs(3, DBG_CRITICAL, s->protocol << "_port: failed to resolve Host/IP: " << host);
3586 self_destruct();
3587 }
3588 }
3589
3590 static void
3591 parse_http_port_option(http_port_list * s, char *token)
3592 {
3593 /* modes first */
3594
3595 if (strcmp(token, "accel") == 0) {
3596 if (s->intercepted || s->spoof_client_ip) {
3597 debugs(3, DBG_CRITICAL, "FATAL: http(s)_port: Accelerator mode requires its own port. It cannot be shared with other modes.");
3598 self_destruct();
3599 }
3600 s->accel = s->vhost = 1;
3601 } else if (strcmp(token, "transparent") == 0 || strcmp(token, "intercept") == 0) {
3602 if (s->accel || s->spoof_client_ip) {
3603 debugs(3, DBG_CRITICAL, "FATAL: http(s)_port: Intercept mode requires its own interception port. It cannot be shared with other modes.");
3604 self_destruct();
3605 }
3606 s->intercepted = 1;
3607 Ip::Interceptor.StartInterception();
3608 /* Log information regarding the port modes under interception. */
3609 debugs(3, DBG_IMPORTANT, "Starting Authentication on port " << s->s);
3610 debugs(3, DBG_IMPORTANT, "Disabling Authentication on port " << s->s << " (interception enabled)");
3611
3612 /* INET6: until transparent REDIRECT works on IPv6 SOCKET, force wildcard to IPv4 */
3613 if (Ip::EnableIpv6)
3614 debugs(3, DBG_IMPORTANT, "Disabling IPv6 on port " << s->s << " (interception enabled)");
3615 if ( !s->s.SetIPv4() ) {
3616 debugs(3, DBG_CRITICAL, "FATAL: http(s)_port: IPv6 addresses cannot NAT intercept (protocol does not provide NAT)" << s->s );
3617 self_destruct();
3618 }
3619 } else if (strcmp(token, "tproxy") == 0) {
3620 if (s->intercepted || s->accel) {
3621 debugs(3,DBG_CRITICAL, "FATAL: http(s)_port: TPROXY option requires its own interception port. It cannot be shared with other modes.");
3622 self_destruct();
3623 }
3624 s->spoof_client_ip = 1;
3625 Ip::Interceptor.StartTransparency();
3626 /* Log information regarding the port modes under transparency. */
3627 debugs(3, DBG_IMPORTANT, "Starting IP Spoofing on port " << s->s);
3628 debugs(3, DBG_IMPORTANT, "Disabling Authentication on port " << s->s << " (IP spoofing enabled)");
3629
3630 if (!Ip::Interceptor.ProbeForTproxy(s->s)) {
3631 debugs(3, DBG_CRITICAL, "FATAL: http(s)_port: TPROXY support in the system does not work.");
3632 self_destruct();
3633 }
3634
3635 } else if (strncmp(token, "defaultsite=", 12) == 0) {
3636 if (!s->accel) {
3637 debugs(3, DBG_CRITICAL, "FATAL: http(s)_port: defaultsite option requires Acceleration mode flag.");
3638 self_destruct();
3639 }
3640 safe_free(s->defaultsite);
3641 s->defaultsite = xstrdup(token + 12);
3642 } else if (strcmp(token, "vhost") == 0) {
3643 if (!s->accel) {
3644 debugs(3, DBG_CRITICAL, "WARNING: http(s)_port: vhost option is deprecated. Use 'accel' mode flag instead.");
3645 }
3646 s->accel = s->vhost = 1;
3647 } else if (strcmp(token, "no-vhost") == 0) {
3648 if (!s->accel) {
3649 debugs(3, DBG_IMPORTANT, "ERROR: http(s)_port: no-vhost option requires Acceleration mode flag.");
3650 }
3651 s->vhost = 0;
3652 } else if (strcmp(token, "vport") == 0) {
3653 if (!s->accel) {
3654 debugs(3, DBG_CRITICAL, "FATAL: http(s)_port: vport option requires Acceleration mode flag.");
3655 self_destruct();
3656 }
3657 s->vport = -1;
3658 } else if (strncmp(token, "vport=", 6) == 0) {
3659 if (!s->accel) {
3660 debugs(3, DBG_CRITICAL, "FATAL: http(s)_port: vport option requires Acceleration mode flag.");
3661 self_destruct();
3662 }
3663 s->vport = xatos(token + 6);
3664 } else if (strncmp(token, "protocol=", 9) == 0) {
3665 if (!s->accel) {
3666 debugs(3, DBG_CRITICAL, "FATAL: http(s)_port: protocol option requires Acceleration mode flag.");
3667 self_destruct();
3668 }
3669 s->protocol = xstrdup(token + 9);
3670 } else if (strcmp(token, "allow-direct") == 0) {
3671 if (!s->accel) {
3672 debugs(3, DBG_CRITICAL, "FATAL: http(s)_port: allow-direct option requires Acceleration mode flag.");
3673 self_destruct();
3674 }
3675 s->allow_direct = 1;
3676 } else if (strcmp(token, "act-as-origin") == 0) {
3677 if (!s->accel) {
3678 debugs(3, DBG_IMPORTANT, "ERROR: http(s)_port: act-as-origin option requires Acceleration mode flag.");
3679 } else
3680 s->actAsOrigin = 1;
3681 } else if (strcmp(token, "ignore-cc") == 0) {
3682 #if !USE_HTTP_VIOLATIONS
3683 if (!s->accel) {
3684 debugs(3, DBG_CRITICAL, "FATAL: http(s)_port: ignore-cc option requires Scceleration mode flag.");
3685 self_destruct();
3686 }
3687 #endif
3688 s->ignore_cc = 1;
3689 } else if (strncmp(token, "name=", 5) == 0) {
3690 safe_free(s->name);
3691 s->name = xstrdup(token + 5);
3692 } else if (strcmp(token, "no-connection-auth") == 0) {
3693 s->connection_auth_disabled = true;
3694 } else if (strcmp(token, "connection-auth=off") == 0) {
3695 s->connection_auth_disabled = true;
3696 } else if (strcmp(token, "connection-auth") == 0) {
3697 s->connection_auth_disabled = false;
3698 } else if (strcmp(token, "connection-auth=on") == 0) {
3699 s->connection_auth_disabled = false;
3700 } else if (strncmp(token, "disable-pmtu-discovery=", 23) == 0) {
3701 if (!strcasecmp(token + 23, "off"))
3702 s->disable_pmtu_discovery = DISABLE_PMTU_OFF;
3703 else if (!strcasecmp(token + 23, "transparent"))
3704 s->disable_pmtu_discovery = DISABLE_PMTU_TRANSPARENT;
3705 else if (!strcasecmp(token + 23, "always"))
3706 s->disable_pmtu_discovery = DISABLE_PMTU_ALWAYS;
3707 else
3708 self_destruct();
3709 } else if (strcmp(token, "ipv4") == 0) {
3710 if ( !s->s.SetIPv4() ) {
3711 debugs(3, DBG_CRITICAL, "FATAL: http(s)_port: IPv6 addresses cannot be used as IPv4-Only. " << s->s );
3712 self_destruct();
3713 }
3714 } else if (strcmp(token, "tcpkeepalive") == 0) {
3715 s->tcp_keepalive.enabled = 1;
3716 } else if (strncmp(token, "tcpkeepalive=", 13) == 0) {
3717 char *t = token + 13;
3718 s->tcp_keepalive.enabled = 1;
3719 s->tcp_keepalive.idle = atoi(t);
3720 t = strchr(t, ',');
3721 if (t) {
3722 t++;
3723 s->tcp_keepalive.interval = atoi(t);
3724 t = strchr(t, ',');
3725 }
3726 if (t) {
3727 t++;
3728 s->tcp_keepalive.timeout = atoi(t);
3729 t = strchr(t, ',');
3730 }
3731 #if USE_SSL
3732 } else if (strcasecmp(token, "sslBump") == 0) {
3733 debugs(3, DBG_CRITICAL, "WARNING: '" << token << "' is deprecated " <<
3734 "in http_port. Use 'ssl-bump' instead.");
3735 s->sslBump = 1; // accelerated when bumped, otherwise not
3736 } else if (strcmp(token, "ssl-bump") == 0) {
3737 s->sslBump = 1; // accelerated when bumped, otherwise not
3738 } else if (strncmp(token, "cert=", 5) == 0) {
3739 safe_free(s->cert);
3740 s->cert = xstrdup(token + 5);
3741 } else if (strncmp(token, "key=", 4) == 0) {
3742 safe_free(s->key);
3743 s->key = xstrdup(token + 4);
3744 } else if (strncmp(token, "version=", 8) == 0) {
3745 s->version = xatoi(token + 8);
3746 if (s->version < 1 || s->version > 4)
3747 self_destruct();
3748 } else if (strncmp(token, "options=", 8) == 0) {
3749 safe_free(s->options);
3750 s->options = xstrdup(token + 8);
3751 } else if (strncmp(token, "cipher=", 7) == 0) {
3752 safe_free(s->cipher);
3753 s->cipher = xstrdup(token + 7);
3754 } else if (strncmp(token, "clientca=", 9) == 0) {
3755 safe_free(s->clientca);
3756 s->clientca = xstrdup(token + 9);
3757 } else if (strncmp(token, "cafile=", 7) == 0) {
3758 safe_free(s->cafile);
3759 s->cafile = xstrdup(token + 7);
3760 } else if (strncmp(token, "capath=", 7) == 0) {
3761 safe_free(s->capath);
3762 s->capath = xstrdup(token + 7);
3763 } else if (strncmp(token, "crlfile=", 8) == 0) {
3764 safe_free(s->crlfile);
3765 s->crlfile = xstrdup(token + 8);
3766 } else if (strncmp(token, "dhparams=", 9) == 0) {
3767 safe_free(s->dhfile);
3768 s->dhfile = xstrdup(token + 9);
3769 } else if (strncmp(token, "sslflags=", 9) == 0) {
3770 safe_free(s->sslflags);
3771 s->sslflags = xstrdup(token + 9);
3772 } else if (strncmp(token, "sslcontext=", 11) == 0) {
3773 safe_free(s->sslContextSessionId);
3774 s->sslContextSessionId = xstrdup(token + 11);
3775 } else if (strcmp(token, "generate-host-certificates") == 0) {
3776 s->generateHostCertificates = true;
3777 } else if (strcmp(token, "generate-host-certificates=on") == 0) {
3778 s->generateHostCertificates = true;
3779 } else if (strcmp(token, "generate-host-certificates=off") == 0) {
3780 s->generateHostCertificates = false;
3781 } else if (strncmp(token, "dynamic_cert_mem_cache_size=", 28) == 0) {
3782 parseBytesOptionValue(&s->dynamicCertMemCacheSize, B_BYTES_STR, token + 28);
3783 #endif
3784 } else {
3785 self_destruct();
3786 }
3787 }
3788
3789 void
3790 add_http_port(char *portspec)
3791 {
3792 http_port_list *s = new http_port_list("http");
3793 parsePortSpecification(s, portspec);
3794 // we may need to merge better of the above returns a list with clones
3795 assert(s->next == NULL);
3796 s->next = Config.Sockaddr.http;
3797 Config.Sockaddr.http = s;
3798 }
3799
3800 http_port_list *
3801 clone_http_port_list(http_port_list *a)
3802 {
3803 http_port_list *b = new http_port_list(a->protocol);
3804
3805 b->s = a->s;
3806 if (a->name)
3807 b->name = xstrdup(a->name);
3808 if (a->defaultsite)
3809 b->defaultsite = xstrdup(a->defaultsite);
3810
3811 b->intercepted = a->intercepted;
3812 b->spoof_client_ip = a->spoof_client_ip;
3813 b->accel = a->accel;
3814 b->allow_direct = a->allow_direct;
3815 b->vhost = a->vhost;
3816 b->sslBump = a->sslBump;
3817 b->vport = a->vport;
3818 b->connection_auth_disabled = a->connection_auth_disabled;
3819 b->disable_pmtu_discovery = a->disable_pmtu_discovery;
3820
3821 memcpy( &(b->tcp_keepalive), &(a->tcp_keepalive), sizeof(a->tcp_keepalive));
3822
3823 #if 0
3824 // AYJ: 2009-07-18: for now SSL does not clone. Configure separate ports with IPs and SSL settings
3825
3826 #if USE_SSL
3827 // XXX: temporary hack to ease move of SSL options to http_port
3828 http_port_list &http;
3829
3830 char *cert;
3831 char *key;
3832 int version;
3833 char *cipher;
3834 char *options;
3835 char *clientca;
3836 char *cafile;
3837 char *capath;
3838 char *crlfile;
3839 char *dhfile;
3840 char *sslflags;
3841 char *sslContextSessionId;
3842 SSL_CTX *sslContext;
3843 #endif
3844
3845 #endif /*0*/
3846
3847 return b;
3848 }
3849
3850 static void
3851 parsePortList(http_port_list ** head, const char *protocol)
3852 {
3853 char *token = strtok(NULL, w_space);
3854
3855 if (!token) {
3856 self_destruct();
3857 return;
3858 }
3859
3860 http_port_list *s = new http_port_list(protocol);
3861 parsePortSpecification(s, token);
3862
3863 /* parse options ... */
3864 while ((token = strtok(NULL, w_space))) {
3865 parse_http_port_option(s, token);
3866 }
3867
3868 if (Ip::EnableIpv6&IPV6_SPECIAL_SPLITSTACK && s->s.IsAnyAddr()) {
3869 // clone the port options from *s to *(s->next)
3870 s->next = clone_http_port_list(s);
3871 s->next->s.SetIPv4();
3872 debugs(3, 3, protocol << "_port: clone wildcard address for split-stack: " << s->s << " and " << s->next->s);
3873 }
3874
3875 while (*head)
3876 head = &(*head)->next;
3877
3878 *head = s;
3879 }
3880
3881 static void
3882 dump_generic_http_port(StoreEntry * e, const char *n, const http_port_list * s)
3883 {
3884 char buf[MAX_IPSTRLEN];
3885
3886 storeAppendPrintf(e, "%s %s",
3887 n,
3888 s->s.ToURL(buf,MAX_IPSTRLEN));
3889
3890 // MODES and specific sub-options.
3891 if (s->intercepted)
3892 storeAppendPrintf(e, " intercept");
3893
3894 else if (s->spoof_client_ip)
3895 storeAppendPrintf(e, " tproxy");
3896
3897 else if (s->accel) {
3898 storeAppendPrintf(e, " accel");
3899
3900 if (s->vhost)
3901 storeAppendPrintf(e, " vhost");
3902
3903 if (s->vport < 0)
3904 storeAppendPrintf(e, " vport");
3905 else if (s->vport > 0)
3906 storeAppendPrintf(e, " vport=%d", s->vport);
3907
3908 if (s->defaultsite)
3909 storeAppendPrintf(e, " defaultsite=%s", s->defaultsite);
3910
3911 if (s->protocol && strcmp(s->protocol,"http") != 0)
3912 storeAppendPrintf(e, " protocol=%s", s->protocol);
3913
3914 if (s->allow_direct)
3915 storeAppendPrintf(e, " allow-direct");
3916
3917 if (s->ignore_cc)
3918 storeAppendPrintf(e, " ignore-cc");
3919
3920 }
3921
3922 // Generic independent options
3923
3924 if (s->name)
3925 storeAppendPrintf(e, " name=%s", s->name);
3926
3927 #if USE_HTTP_VIOLATIONS
3928 if (!s->accel && s->ignore_cc)
3929 storeAppendPrintf(e, " ignore-cc");
3930 #endif
3931
3932 if (s->connection_auth_disabled)
3933 storeAppendPrintf(e, " connection-auth=off");
3934 else
3935 storeAppendPrintf(e, " connection-auth=on");
3936
3937 if (s->disable_pmtu_discovery != DISABLE_PMTU_OFF) {
3938 const char *pmtu;
3939
3940 if (s->disable_pmtu_discovery == DISABLE_PMTU_ALWAYS)
3941 pmtu = "always";
3942 else
3943 pmtu = "transparent";
3944
3945 storeAppendPrintf(e, " disable-pmtu-discovery=%s", pmtu);
3946 }
3947
3948 if (s->s.IsAnyAddr() && !s->s.IsIPv6())
3949 storeAppendPrintf(e, " ipv4");
3950
3951 if (s->tcp_keepalive.enabled) {
3952 if (s->tcp_keepalive.idle || s->tcp_keepalive.interval || s->tcp_keepalive.timeout) {
3953 storeAppendPrintf(e, " tcpkeepalive=%d,%d,%d", s->tcp_keepalive.idle, s->tcp_keepalive.interval, s->tcp_keepalive.timeout);
3954 } else {
3955 storeAppendPrintf(e, " tcpkeepalive");
3956 }
3957 }
3958
3959 #if USE_SSL
3960 if (s->sslBump)
3961 storeAppendPrintf(e, " ssl-bump");
3962
3963 if (s->cert)
3964 storeAppendPrintf(e, " cert=%s", s->cert);
3965
3966 if (s->key)
3967 storeAppendPrintf(e, " key=%s", s->key);
3968
3969 if (s->version)
3970 storeAppendPrintf(e, " version=%d", s->version);
3971
3972 if (s->options)
3973 storeAppendPrintf(e, " options=%s", s->options);
3974
3975 if (s->cipher)
3976 storeAppendPrintf(e, " cipher=%s", s->cipher);
3977
3978 if (s->cafile)
3979 storeAppendPrintf(e, " cafile=%s", s->cafile);
3980
3981 if (s->capath)
3982 storeAppendPrintf(e, " capath=%s", s->capath);
3983
3984 if (s->crlfile)
3985 storeAppendPrintf(e, " crlfile=%s", s->crlfile);
3986
3987 if (s->dhfile)
3988 storeAppendPrintf(e, " dhparams=%s", s->dhfile);
3989
3990 if (s->sslflags)
3991 storeAppendPrintf(e, " sslflags=%s", s->sslflags);
3992
3993 if (s->sslContextSessionId)
3994 storeAppendPrintf(e, " sslcontext=%s", s->sslContextSessionId);
3995
3996 if (s->generateHostCertificates)
3997 storeAppendPrintf(e, " generate-host-certificates");
3998
3999 if (s->dynamicCertMemCacheSize != std::numeric_limits<size_t>::max())
4000 storeAppendPrintf(e, "dynamic_cert_mem_cache_size=%lu%s\n", (unsigned long)s->dynamicCertMemCacheSize, B_BYTES_STR);
4001 #endif
4002 }
4003
4004 static void
4005 dump_http_port_list(StoreEntry * e, const char *n, const http_port_list * s)
4006 {
4007 while (s) {
4008 dump_generic_http_port(e, n, s);
4009 storeAppendPrintf(e, "\n");
4010 s = s->next;
4011 }
4012 }
4013
4014 static void
4015 free_http_port_list(http_port_list ** head)
4016 {
4017 http_port_list *s;
4018
4019 while ((s = *head) != NULL) {
4020 *head = s->next;
4021 delete s;
4022 }
4023 }
4024
4025 void
4026 configFreeMemory(void)
4027 {
4028 free_all();
4029 #if USE_SSL
4030 SSL_CTX_free(Config.ssl_client.sslContext);
4031 #endif
4032 }
4033
4034 void
4035 requirePathnameExists(const char *name, const char *path)
4036 {
4037
4038 struct stat sb;
4039 char pathbuf[BUFSIZ];
4040 assert(path != NULL);
4041
4042 if (Config.chroot_dir && (geteuid() == 0)) {
4043 snprintf(pathbuf, BUFSIZ, "%s/%s", Config.chroot_dir, path);
4044 path = pathbuf;
4045 }
4046
4047 if (stat(path, &sb) < 0) {
4048 debugs(0, DBG_CRITICAL, (opt_parse_cfg_only?"FATAL ":"") << "ERROR: " << name << " " << path << ": " << xstrerror());
4049 // keep going to find more issues if we are only checking the config file with "-k parse"
4050 if (opt_parse_cfg_only)
4051 return;
4052 // this is fatal if it is found during startup or reconfigure
4053 if (opt_send_signal == -1 || opt_send_signal == SIGHUP)
4054 fatalf("%s %s: %s", name, path, xstrerror());
4055 }
4056 }
4057
4058 char *
4059 strtokFile(void)
4060 {
4061 return ConfigParser::strtokFile();
4062 }
4063
4064 #include "AccessLogEntry.h"
4065
4066 static void
4067 parse_access_log(customlog ** logs)
4068 {
4069 const char *filename, *logdef_name;
4070
4071 customlog *cl = (customlog *)xcalloc(1, sizeof(*cl));
4072
4073 if ((filename = strtok(NULL, w_space)) == NULL) {
4074 self_destruct();
4075 return;
4076 }
4077
4078 if (strcmp(filename, "none") == 0) {
4079 cl->type = Log::Format::CLF_NONE;
4080 aclParseAclList(LegacyParser, &cl->aclList);
4081 while (*logs)
4082 logs = &(*logs)->next;
4083 *logs = cl;
4084 return;
4085 }
4086
4087 if ((logdef_name = strtok(NULL, w_space)) == NULL)
4088 logdef_name = "squid";
4089
4090 debugs(3, 9, "Log definition name '" << logdef_name << "' file '" << filename << "'");
4091
4092 cl->filename = xstrdup(filename);
4093
4094 /* look for the definition pointer corresponding to this name */
4095 Format::Format *lf = Log::TheConfig.logformats;
4096
4097 while (lf != NULL) {
4098 debugs(3, 9, "Comparing against '" << lf->name << "'");
4099
4100 if (strcmp(lf->name, logdef_name) == 0)
4101 break;
4102
4103 lf = lf->next;
4104 }
4105
4106 if (lf != NULL) {
4107 cl->type = Log::Format::CLF_CUSTOM;
4108 cl->logFormat = lf;
4109 } else if (strcmp(logdef_name, "auto") == 0) {
4110 debugs(0,0, "WARNING: Log format 'auto' no longer exists. Using 'squid' instead.");
4111 cl->type = Log::Format::CLF_SQUID;
4112 } else if (strcmp(logdef_name, "squid") == 0) {
4113 cl->type = Log::Format::CLF_SQUID;
4114 } else if (strcmp(logdef_name, "common") == 0) {
4115 cl->type = Log::Format::CLF_COMMON;
4116 } else if (strcmp(logdef_name, "combined") == 0) {
4117 cl->type = Log::Format::CLF_COMBINED;
4118 #if ICAP_CLIENT
4119 } else if (strcmp(logdef_name, "icap_squid") == 0) {
4120 cl->type = Log::Format::CLF_ICAP_SQUID;
4121 #endif
4122 } else if (strcmp(logdef_name, "useragent") == 0) {
4123 cl->type = Log::Format::CLF_USERAGENT;
4124 } else if (strcmp(logdef_name, "referrer") == 0) {
4125 cl->type = Log::Format::CLF_REFERER;
4126 } else {
4127 debugs(3, 0, "Log format '" << logdef_name << "' is not defined");
4128 self_destruct();
4129 return;
4130 }
4131
4132 aclParseAclList(LegacyParser, &cl->aclList);
4133
4134 while (*logs)
4135 logs = &(*logs)->next;
4136
4137 *logs = cl;
4138 }
4139
4140 static int
4141 check_null_access_log(customlog *customlog_definitions)
4142 {
4143 return customlog_definitions == NULL;
4144 }
4145
4146 static void
4147 dump_access_log(StoreEntry * entry, const char *name, customlog * logs)
4148 {
4149 customlog *log;
4150
4151 for (log = logs; log; log = log->next) {
4152 storeAppendPrintf(entry, "%s ", name);
4153
4154 switch (log->type) {
4155
4156 case Log::Format::CLF_CUSTOM:
4157 storeAppendPrintf(entry, "%s %s", log->filename, log->logFormat->name);
4158 break;
4159
4160 case Log::Format::CLF_NONE:
4161 storeAppendPrintf(entry, "none");
4162 break;
4163
4164 case Log::Format::CLF_SQUID:
4165 storeAppendPrintf(entry, "%s squid", log->filename);
4166 break;
4167
4168 case Log::Format::CLF_COMBINED:
4169 storeAppendPrintf(entry, "%s combined", log->filename);
4170 break;
4171
4172 case Log::Format::CLF_COMMON:
4173 storeAppendPrintf(entry, "%s common", log->filename);
4174 break;
4175
4176 #if ICAP_CLIENT
4177 case Log::Format::CLF_ICAP_SQUID:
4178 storeAppendPrintf(entry, "%s icap_squid", log->filename);
4179 break;
4180 #endif
4181 case Log::Format::CLF_USERAGENT:
4182 storeAppendPrintf(entry, "%s useragent", log->filename);
4183 break;
4184
4185 case Log::Format::CLF_REFERER:
4186 storeAppendPrintf(entry, "%s referrer", log->filename);
4187 break;
4188
4189 case Log::Format::CLF_UNKNOWN:
4190 break;
4191 }
4192
4193 if (log->aclList)
4194 dump_acl_list(entry, log->aclList);
4195
4196 storeAppendPrintf(entry, "\n");
4197 }
4198 }
4199
4200 static void
4201 free_access_log(customlog ** definitions)
4202 {
4203 while (*definitions) {
4204 customlog *log = *definitions;
4205 *definitions = log->next;
4206
4207 log->logFormat = NULL;
4208 log->type = Log::Format::CLF_UNKNOWN;
4209
4210 if (log->aclList)
4211 aclDestroyAclList(&log->aclList);
4212
4213 safe_free(log->filename);
4214
4215 xfree(log);
4216 }
4217 }
4218
4219 /// parses list of integers form name=N1,N2,N3,...
4220 static bool
4221 parseNamedIntList(const char *data, const String &name, Vector<int> &list)
4222 {
4223 if (data && (strncmp(data, name.rawBuf(), name.size()) == 0)) {
4224 data += name.size();
4225 if (*data == '=') {
4226 while (true) {
4227 ++data;
4228 int value = 0;
4229 if (!StringToInt(data, value, &data, 10))
4230 break;
4231 list.push_back(value);
4232 if (*data == '\0' || *data != ',')
4233 break;
4234 }
4235 }
4236 }
4237 return data && *data == '\0';
4238 }
4239
4240 static void
4241 parse_CpuAffinityMap(CpuAffinityMap **const cpuAffinityMap)
4242 {
4243 #if !HAVE_CPU_AFFINITY
4244 debugs(3, DBG_CRITICAL, "FATAL: Squid built with no CPU affinity " <<
4245 "support, do not set 'cpu_affinity_map'");
4246 self_destruct();
4247 #endif /* HAVE_CPU_AFFINITY */
4248
4249 if (!*cpuAffinityMap)
4250 *cpuAffinityMap = new CpuAffinityMap;
4251
4252 const char *const pToken = strtok(NULL, w_space);
4253 const char *const cToken = strtok(NULL, w_space);
4254 Vector<int> processes, cores;
4255 if (!parseNamedIntList(pToken, "process_numbers", processes)) {
4256 debugs(3, DBG_CRITICAL, "FATAL: bad 'process_numbers' parameter " <<
4257 "in 'cpu_affinity_map'");
4258 self_destruct();
4259 } else if (!parseNamedIntList(cToken, "cores", cores)) {
4260 debugs(3, DBG_CRITICAL, "FATAL: bad 'cores' parameter in " <<
4261 "'cpu_affinity_map'");
4262 self_destruct();
4263 } else if (!(*cpuAffinityMap)->add(processes, cores)) {
4264 debugs(3, DBG_CRITICAL, "FATAL: bad 'cpu_affinity_map'; " <<
4265 "process_numbers and cores lists differ in length or " <<
4266 "contain numbers <= 0");
4267 self_destruct();
4268 }
4269 }
4270
4271 static void
4272 dump_CpuAffinityMap(StoreEntry *const entry, const char *const name, const CpuAffinityMap *const cpuAffinityMap)
4273 {
4274 if (cpuAffinityMap) {
4275 storeAppendPrintf(entry, "%s process_numbers=", name);
4276 for (size_t i = 0; i < cpuAffinityMap->processes().size(); ++i) {
4277 storeAppendPrintf(entry, "%s%i", (i ? "," : ""),
4278 cpuAffinityMap->processes()[i]);
4279 }
4280 storeAppendPrintf(entry, " cores=");
4281 for (size_t i = 0; i < cpuAffinityMap->processes().size(); ++i) {
4282 storeAppendPrintf(entry, "%s%i", (i ? "," : ""),
4283 cpuAffinityMap->cores()[i]);
4284 }
4285 storeAppendPrintf(entry, "\n");
4286 }
4287 }
4288
4289 static void
4290 free_CpuAffinityMap(CpuAffinityMap **const cpuAffinityMap)
4291 {
4292 delete *cpuAffinityMap;
4293 *cpuAffinityMap = NULL;
4294 }
4295
4296 #if USE_ADAPTATION
4297
4298 static void
4299 parse_adaptation_service_set_type()
4300 {
4301 Adaptation::Config::ParseServiceSet();
4302 }
4303
4304 static void
4305 parse_adaptation_service_chain_type()
4306 {
4307 Adaptation::Config::ParseServiceChain();
4308 }
4309
4310 static void
4311 parse_adaptation_access_type()
4312 {
4313 Adaptation::Config::ParseAccess(LegacyParser);
4314 }
4315
4316 static void
4317 parse_adaptation_meta_type(Adaptation::Config::MetaHeaders *)
4318 {
4319 Adaptation::Config::ParseMetaHeader(LegacyParser);
4320 }
4321
4322 static void
4323 dump_adaptation_meta_type(StoreEntry *entry, const char *name, Adaptation::Config::MetaHeaders &)
4324 {
4325 Adaptation::Config::DumpMetaHeader(entry, name);
4326 }
4327
4328 static void
4329 free_adaptation_meta_type(Adaptation::Config::MetaHeaders *)
4330 {
4331 // Nothing to do, it is released inside Adaptation::Config::freeService()
4332 }
4333 #endif /* USE_ADAPTATION */
4334
4335
4336 #if ICAP_CLIENT
4337
4338 static void
4339 parse_icap_service_type(Adaptation::Icap::Config * cfg)
4340 {
4341 cfg->parseService();
4342 }
4343
4344 static void
4345 free_icap_service_type(Adaptation::Icap::Config * cfg)
4346 {
4347 cfg->freeService();
4348 }
4349
4350 static void
4351 dump_icap_service_type(StoreEntry * entry, const char *name, const Adaptation::Icap::Config &cfg)
4352 {
4353 cfg.dumpService(entry, name);
4354 }
4355
4356 static void
4357 parse_icap_class_type()
4358 {
4359 debugs(93, 0, "WARNING: 'icap_class' is depricated. " <<
4360 "Use 'adaptation_service_set' instead");
4361 Adaptation::Config::ParseServiceSet();
4362 }
4363
4364 static void
4365 parse_icap_access_type()
4366 {
4367 debugs(93, 0, "WARNING: 'icap_access' is depricated. " <<
4368 "Use 'adaptation_access' instead");
4369 Adaptation::Config::ParseAccess(LegacyParser);
4370 }
4371
4372 #endif
4373
4374
4375 #if USE_ECAP
4376
4377 static void
4378 parse_ecap_service_type(Adaptation::Ecap::Config * cfg)
4379 {
4380 cfg->parseService();
4381 }
4382
4383 static void
4384 free_ecap_service_type(Adaptation::Ecap::Config * cfg)
4385 {
4386 cfg->freeService();
4387 }
4388
4389 static void
4390 dump_ecap_service_type(StoreEntry * entry, const char *name, const Adaptation::Ecap::Config &cfg)
4391 {
4392 cfg.dumpService(entry, name);
4393 }
4394
4395 #endif /* USE_ECAP */
4396
4397 #if ICAP_CLIENT
4398 static void parse_icap_service_failure_limit(Adaptation::Icap::Config *cfg)
4399 {
4400 char *token;
4401 time_t d;
4402 time_t m;
4403 cfg->service_failure_limit = GetInteger();
4404
4405 if ((token = strtok(NULL, w_space)) == NULL)
4406 return;
4407
4408 if (strcmp(token,"in") != 0) {
4409 debugs(3, 0, "expecting 'in' on'" << config_input_line << "'");
4410 self_destruct();
4411 }
4412
4413 if ((token = strtok(NULL, w_space)) == NULL) {
4414 self_destruct();
4415 }
4416
4417 d = static_cast<time_t> (xatoi(token));
4418
4419 m = static_cast<time_t> (1);
4420
4421 if (0 == d)
4422 (void) 0;
4423 else if ((token = strtok(NULL, w_space)) == NULL) {
4424 debugs(3, 0, "No time-units on '" << config_input_line << "'");
4425 self_destruct();
4426 } else if ((m = parseTimeUnits(token, false)) == 0)
4427 self_destruct();
4428
4429 cfg->oldest_service_failure = (m * d);
4430 }
4431
4432 static void dump_icap_service_failure_limit(StoreEntry *entry, const char *name, const Adaptation::Icap::Config &cfg)
4433 {
4434 storeAppendPrintf(entry, "%s %d", name, cfg.service_failure_limit);
4435 if (cfg.oldest_service_failure > 0) {
4436 storeAppendPrintf(entry, " in %d seconds", (int)cfg.oldest_service_failure);
4437 }
4438 storeAppendPrintf(entry, "\n");
4439 }
4440
4441 static void free_icap_service_failure_limit(Adaptation::Icap::Config *cfg)
4442 {
4443 cfg->oldest_service_failure = 0;
4444 cfg->service_failure_limit = 0;
4445 }
4446
4447 #endif