/*
- * Copyright (C) 1996-2018 The Squid Software Foundation and contributors
+ * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
*
* Squid software is distributed under GPLv2+ license and includes
* contributions from numerous individuals and organizations.
#include "auth/Config.h"
#include "auth/Scheme.h"
#include "AuthReg.h"
+#include "base/PackableStream.h"
#include "base/RunnersRegistry.h"
#include "cache_cf.h"
#include "CachePeer.h"
+#include "CachePeers.h"
+#include "ConfigOption.h"
#include "ConfigParser.h"
#include "CpuAffinityMap.h"
+#include "debug/Messages.h"
#include "DiskIO/DiskIOModule.h"
#include "eui/Config.h"
#include "ExternalACL.h"
#include "format/Format.h"
+#include "fqdncache.h"
#include "ftp/Elements.h"
#include "globals.h"
#include "HttpHeaderTools.h"
+#include "HttpUpgradeProtocolAccess.h"
#include "icmp/IcmpConfig.h"
#include "ident/Config.h"
#include "ip/Intercept.h"
#include "SquidString.h"
#include "ssl/ProxyCerts.h"
#include "Store.h"
-#include "store/Disk.h"
#include "store/Disks.h"
-#include "StoreFileSystem.h"
#include "tools.h"
#include "util.h"
#include "wordlist.h"
#if HAVE_GLOB_H
#include <glob.h>
#endif
+#include <chrono>
#include <limits>
#include <list>
#if HAVE_PWD_H
#if HAVE_GRP_H
#include <grp.h>
#endif
+#if HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
#if HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
static peer_t parseNeighborType(const char *s);
+static const char *const T_NANOSECOND_STR = "nanosecond";
+static const char *const T_MICROSECOND_STR = "microsecond";
static const char *const T_MILLISECOND_STR = "millisecond";
static const char *const T_SECOND_STR = "second";
static const char *const T_MINUTE_STR = "minute";
static const char *const B_MBYTES_STR = "MB";
static const char *const B_GBYTES_STR = "GB";
-static const char *const list_sep = ", \t\n\r";
+// std::chrono::years requires C++20. Do our own rough calculation for now.
+static const double HoursPerYear = 24*365.2522;
+
+static void parse_cache_log_message(DebugMessages **messages);
+static void dump_cache_log_message(StoreEntry *entry, const char *name, const DebugMessages *messages);
+static void free_cache_log_message(DebugMessages **messages);
static void parse_access_log(CustomLog ** customlog_definitions);
static int check_null_access_log(CustomLog *customlog_definitions);
static void dump_access_log(StoreEntry * entry, const char *name, CustomLog * definitions);
static void free_access_log(CustomLog ** definitions);
-static bool setLogformat(CustomLog *cl, const char *name, const bool dieWhenMissing);
static void configDoConfigure(void);
static void parse_refreshpattern(RefreshPattern **);
-static uint64_t parseTimeUnits(const char *unit, bool allowMsec);
static void parse_u_short(unsigned short * var);
static void parse_string(char **);
static void default_all(void);
static void parse_on_unsupported_protocol(acl_access **access);
static void dump_on_unsupported_protocol(StoreEntry *entry, const char *name, acl_access *access);
static void free_on_unsupported_protocol(acl_access **access);
-static void ParseAclWithAction(acl_access **access, const allow_t &action, const char *desc, ACL *acl = nullptr);
+static void ParseAclWithAction(acl_access **access, const Acl::Answer &action, const char *desc, ACL *acl = nullptr);
+static void parse_http_upgrade_request_protocols(HttpUpgradeProtocolAccess **protoGuards);
+static void dump_http_upgrade_request_protocols(StoreEntry *entry, const char *name, HttpUpgradeProtocolAccess *protoGuards);
+static void free_http_upgrade_request_protocols(HttpUpgradeProtocolAccess **protoGuards);
/*
* LegacyParser is a parser for legacy code that uses the global
*/
static ConfigParser LegacyParser = ConfigParser();
+const char *cfg_directive = nullptr;
+const char *cfg_filename = nullptr;
+int config_lineno = 0;
+char config_input_line[BUFSIZ] = {};
+
void
self_destruct(void)
{
parseManyConfigFiles(char* files, int depth)
{
int error_count = 0;
- char* saveptr = NULL;
+ char* saveptr = nullptr;
#if HAVE_GLOB
char *path;
glob_t globbuf;
int i;
memset(&globbuf, 0, sizeof(globbuf));
- for (path = strwordtok(files, &saveptr); path; path = strwordtok(NULL, &saveptr)) {
- if (glob(path, globbuf.gl_pathc ? GLOB_APPEND : 0, NULL, &globbuf) != 0) {
+ for (path = strwordtok(files, &saveptr); path; path = strwordtok(nullptr, &saveptr)) {
+ if (glob(path, globbuf.gl_pathc ? GLOB_APPEND : 0, nullptr, &globbuf) != 0) {
int xerrno = errno;
fatalf("Unable to find configuration file: %s: %s", path, xstrerr(xerrno));
}
char* file = strwordtok(files, &saveptr);
while (file != NULL) {
error_count += parseOneConfigFile(file, depth);
- file = strwordtok(NULL, &saveptr);
+ file = strwordtok(nullptr, &saveptr);
}
#endif /* HAVE_GLOB */
return error_count;
static void
ReplaceSubstr(char*& str, int& len, unsigned substrIdx, unsigned substrLen, const char* newSubstr)
{
- assert(str != NULL);
- assert(newSubstr != NULL);
+ assert(str != nullptr);
+ assert(newSubstr != nullptr);
unsigned newSubstrLen = strlen(newSubstr);
if (newSubstrLen > substrLen)
static void
SubstituteMacro(char*& line, int& len, const char* macroName, const char* substStr)
{
- assert(line != NULL);
- assert(macroName != NULL);
- assert(substStr != NULL);
+ assert(line != nullptr);
+ assert(macroName != nullptr);
+ assert(substStr != nullptr);
unsigned macroNameLen = strlen(macroName);
while (const char* macroPos = strstr(line, macroName)) // we would replace all occurrences
ReplaceSubstr(line, len, macroPos - line, macroNameLen, substStr);
static void
trim_trailing_ws(char* str)
{
- assert(str != NULL);
+ assert(str != nullptr);
unsigned i = strlen(str);
while ((i > 0) && xisspace(str[i - 1]))
--i;
static const char*
FindStatement(const char* line, const char* statement)
{
- assert(line != NULL);
- assert(statement != NULL);
+ assert(line != nullptr);
+ assert(statement != nullptr);
const char* str = skip_ws(line);
unsigned len = strlen(statement);
return skip_ws(str);
}
- return NULL;
+ return nullptr;
}
static bool
StrToInt(const char* str, long& number)
{
- assert(str != NULL);
+ assert(str != nullptr);
char* end;
number = strtol(str, &end, 0);
static bool
EvalBoolExpr(const char* expr)
{
- assert(expr != NULL);
+ assert(expr != nullptr);
if (strcmp(expr, "true") == 0) {
return true;
} else if (strcmp(expr, "false") == 0) {
static int
parseOneConfigFile(const char *file_name, unsigned int depth)
{
- FILE *fp = NULL;
+ FILE *fp = nullptr;
const char *orig_cfg_filename = cfg_filename;
const int orig_config_lineno = config_lineno;
- char *token = NULL;
- char *tmp_line = NULL;
+ char *token = nullptr;
+ char *tmp_line = nullptr;
int tmp_line_len = 0;
int err_count = 0;
int is_pipe = 0;
- debugs(3, DBG_IMPORTANT, "Processing Configuration File: " << file_name << " (depth " << depth << ")");
+ debugs(3, Important(68), "Processing Configuration File: " << file_name << " (depth " << depth << ")");
if (depth > 16) {
fatalf("WARNING: can't include %s: includes are nested too deeply (>16)!\n", file_name);
return 1;
/* Handle includes here */
if (tmp_line_len >= 9 && strncmp(tmp_line, "include", 7) == 0 && xisspace(tmp_line[7])) {
err_count += parseManyConfigFiles(tmp_line + 8, depth + 1);
- } else if (!parse_line(tmp_line)) {
- debugs(3, DBG_CRITICAL, HERE << cfg_filename << ":" << config_lineno << " unrecognized: '" << tmp_line << "'");
- ++err_count;
+ } else {
+ try {
+ if (!parse_line(tmp_line)) {
+ debugs(3, DBG_CRITICAL, ConfigParser::CurrentLocation() << ": unrecognized: '" << tmp_line << "'");
+ ++err_count;
+ }
+ } catch (...) {
+ // fatal for now
+ debugs(3, DBG_CRITICAL, "ERROR: configuration failure: " << CurrentException);
+ self_destruct();
+ }
}
}
{
int err_count = 0;
- debugs(5, 4, HERE);
+ debugs(5, 4, MYNAME);
configFreeMemory();
*/
configDoConfigure();
- if (!Config.chroot_dir) {
- leave_suid();
- setUmask(Config.umask);
- _db_init(Debug::cache_log, Debug::debugOptions);
- enter_suid();
- }
-
if (opt_send_signal == -1) {
Mgr::RegisterAction("config",
"Current Squid Configuration",
}
}
+/*
+ * The templated functions below are essentially ConfigParser methods. They are
+ * not implemented as such because our generated code calling them is the only
+ * code that can instantiate implementations for each T -- we cannot place these
+ * definitions into ConfigParser.cc unless cf_parser.cci is moved there.
+ */
+
+// TODO: When adding Ts incompatible with this trivial API and implementation,
+// replace both with a ConfigParser-maintained table of seen directives.
+/// whether we have seen (and, hence, configured) the given directive
+template <typename T>
+static bool
+SawDirective(const T &raw)
+{
+ return bool(raw);
+}
+
+/// Sets the given raw SquidConfig data member.
+/// Extracts and interprets parser's configuration tokens.
+template <typename T>
+static void
+ParseDirective(T &raw, ConfigParser &parser)
+{
+ if (SawDirective(raw))
+ parser.rejectDuplicateDirective();
+
+ // TODO: parser.openDirective(directiveName);
+ Must(!raw);
+ raw = Configuration::Component<T>::Parse(parser);
+ Must(raw);
+ parser.closeDirective();
+}
+
+/// reports raw SquidConfig data member configuration using squid.conf syntax
+/// \param name the name of the configuration directive being dumped
+template <typename T>
+static void
+DumpDirective(const T &raw, StoreEntry *entry, const char *name)
+{
+ if (!SawDirective(raw))
+ return; // not configured
+
+ entry->append(name, strlen(name));
+ SBufStream os;
+ Configuration::Component<T>::Print(os, raw);
+ const auto buf = os.buf();
+ if (buf.length()) {
+ entry->append(" ", 1);
+ entry->append(buf.rawContent(), buf.length());
+ }
+ entry->append("\n", 1);
+}
+
+/// frees any resources associated with the given raw SquidConfig data member
+template <typename T>
+static void
+FreeDirective(T &raw)
+{
+ Configuration::Component<T>::Free(raw);
+
+ // While the implementation may change, there is no way to avoid zeroing.
+ // Even migration to a proper SquidConfig class would not help: While
+ // ordinary destructors do not need to zero data members, a SquidConfig
+ // destructor would have to zero to protect any SquidConfig::x destruction
+ // code from accidentally dereferencing an already destroyed Config.y.
+ static_assert(std::is_trivial<T>::value, "SquidConfig member is trivial");
+ memset(&raw, 0, sizeof(raw));
+}
+
static void
configDoConfigure(void)
{
memConfigure();
/* Sanity checks */
- Config.cacheSwap.n_strands = 0; // no diskers by default
- if (Config.cacheSwap.swapDirs == NULL) {
- /* Memory-only cache probably in effect. */
- /* turn off the cache rebuild delays... */
- StoreController::store_dirs_rebuilding = 0;
- } else if (InDaemonMode()) { // no diskers in non-daemon mode
- for (int i = 0; i < Config.cacheSwap.n_configured; ++i) {
- const RefCount<SwapDir> sd = Config.cacheSwap.swapDirs[i];
- if (sd->needsDiskStrand())
- sd->disker = Config.workers + (++Config.cacheSwap.n_strands);
- }
- }
-
if (Debug::rotateNumber < 0) {
Debug::rotateNumber = Config.Log.rotateNumber;
}
}
#endif
- if (Config.Announce.period > 0) {
- Config.onoff.announce = 1;
- } else {
- Config.Announce.period = 86400 * 365; /* one year */
- Config.onoff.announce = 0;
- }
-
if (Config.onoff.httpd_suppress_version_string)
visible_appname_string = (char *)appname_string;
else
if (*Config.appendDomain != '.')
fatal("append_domain must begin with a '.'");
- if (Config.errHtmlText == NULL)
+ if (Config.errHtmlText == nullptr)
Config.errHtmlText = xstrdup(null_string);
#if !HAVE_SETRLIMIT || !defined(RLIMIT_NOFILE)
if (Config.max_filedescriptors > 0) {
debugs(0, DBG_IMPORTANT, "WARNING: max_filedescriptors disabled. Operating System setrlimit(RLIMIT_NOFILE) is missing.");
}
-#elif USE_SELECT || USE_SELECT_WIN32
+#elif USE_SELECT
if (Config.max_filedescriptors > FD_SETSIZE) {
debugs(0, DBG_IMPORTANT, "WARNING: max_filedescriptors limited to " << FD_SETSIZE << " by select() algorithm.");
}
* the extra space is for loop detection in client_side.c -- we search
* for substrings in the Via header.
*/
- snprintf(ThisCache2, sizeof(ThisCache), " %s (%s)",
+ snprintf(ThisCache2, sizeof(ThisCache2), " %s (%s)",
uniqueHostname(),
visible_appname_string);
Config2.onoff.enable_purge = (ACLMethodData::ThePurgeCount > 0);
if (geteuid() == 0) {
- if (NULL != Config.effectiveUser) {
+ if (nullptr != Config.effectiveUser) {
struct passwd *pwd = getpwnam(Config.effectiveUser);
- if (NULL == pwd) {
+ if (nullptr == pwd) {
/*
* Andres Kroonmaa <andre@online.ee>:
* Some getpwnam() implementations (Solaris?) require
Config2.effectiveGroupID = getegid();
}
- if (NULL != Config.effectiveGroup) {
+ if (nullptr != Config.effectiveGroup) {
struct group *grp = getgrnam(Config.effectiveGroup);
- if (NULL == grp) {
+ if (nullptr == grp) {
fatalf("getgrnam failed to find groupid for effective group '%s'",
Config.effectiveGroup);
return;
#endif
if (Security::ProxyOutgoingConfig.encryptTransport) {
- debugs(3, DBG_IMPORTANT, "Initializing https:// proxy context");
+ debugs(3, 2, "initializing https:// proxy context");
Config.ssl_client.sslContext = Security::ProxyOutgoingConfig.createClientContext(false);
if (!Config.ssl_client.sslContext) {
#if USE_OPENSSL
#endif
}
- for (CachePeer *p = Config.peers; p != NULL; p = p->next) {
+ for (const auto &p: CurrentCachePeers()) {
// default value for ssldomain= is the peer host/IP
if (p->secure.sslDomain.isEmpty())
p->secure.sslDomain = p->host;
if (p->secure.encryptTransport) {
- debugs(3, DBG_IMPORTANT, "Initializing cache_peer " << p->name << " TLS context");
+ debugs(3, 2, "initializing TLS context for cache_peer " << *p);
p->sslContext = p->secure.createClientContext(true);
if (!p->sslContext) {
- debugs(3, DBG_CRITICAL, "ERROR: Could not initialize cache_peer " << p->name << " TLS context");
+ debugs(3, DBG_CRITICAL, "ERROR: Could not initialize TLS context for cache_peer " << *p);
self_destruct();
return;
}
}
}
- for (AnyP::PortCfgPointer s = HttpPortList; s != NULL; s = s->next) {
+ for (AnyP::PortCfgPointer s = HttpPortList; s != nullptr; s = s->next) {
if (!s->secure.encryptTransport)
continue;
- debugs(3, DBG_IMPORTANT, "Initializing " << AnyP::UriScheme(s->transport.protocol) << "_port " << s->s << " TLS contexts");
+ debugs(3, 2, "initializing " << AnyP::UriScheme(s->transport.protocol) << "_port " << s->s << " TLS contexts");
s->secure.initServerContexts(*s);
}
// prevent infinite fetch loops in the request parser
- // due to buffer full but not enough data recived to finish parse
+ // due to buffer full but not enough data received to finish parse
if (Config.maxRequestBufferSize <= Config.maxRequestHeaderSize) {
fatalf("Client request buffer of %u bytes cannot hold a request with %u bytes of headers." \
" Change client_request_buffer_max or request_header_max_size limits.",
}
}
-/* Parse a time specification from the config file. Store the
- * result in 'tptr', after converting it to 'units' */
-static time_msec_t
-parseTimeLine(const char *units, bool allowMsec, bool expectMoreArguments = false)
-{
- time_msec_t u = parseTimeUnits(units, allowMsec);
- if (u == 0) {
- self_destruct();
- return 0;
- }
-
- char *token = ConfigParser::NextToken();
- if (!token) {
- self_destruct();
- return 0;
+template <class MinimalUnit>
+static const char *
+TimeUnitToString()
+{
+ const auto minUnit = MinimalUnit(1);
+ if(minUnit == std::chrono::nanoseconds(1))
+ return T_NANOSECOND_STR;
+ else if (minUnit == std::chrono::microseconds(1))
+ return T_MICROSECOND_STR;
+ else if (minUnit == std::chrono::milliseconds(1))
+ return T_MILLISECOND_STR;
+ else {
+ assert(minUnit >= std::chrono::seconds(1));
+ return T_SECOND_STR;
}
+}
- double d = xatof(token);
+/// Assigns 'ns' the number of nanoseconds corresponding to 'unitName'.
+/// \param MinimalUnit is a chrono duration type specifying the minimal
+/// allowed time unit.
+/// \returns true if unitName is correct and its time unit is not less
+/// than MinimalUnit.
+template <class MinimalUnit>
+static bool
+parseTimeUnit(const char *unitName, std::chrono::nanoseconds &ns)
+{
+ if (!unitName)
+ throw TexcHere("missing time unit");
+
+ if (!strncasecmp(unitName, T_NANOSECOND_STR, strlen(T_NANOSECOND_STR)))
+ ns = std::chrono::nanoseconds(1);
+ else if (!strncasecmp(unitName, T_MICROSECOND_STR, strlen(T_MICROSECOND_STR)))
+ ns = std::chrono::microseconds(1);
+ else if (!strncasecmp(unitName, T_MILLISECOND_STR, strlen(T_MILLISECOND_STR)))
+ ns = std::chrono::milliseconds(1);
+ else if (!strncasecmp(unitName, T_SECOND_STR, strlen(T_SECOND_STR)))
+ ns = std::chrono::seconds(1);
+ else if (!strncasecmp(unitName, T_MINUTE_STR, strlen(T_MINUTE_STR)))
+ ns = std::chrono::minutes(1);
+ else if (!strncasecmp(unitName, T_HOUR_STR, strlen(T_HOUR_STR)))
+ ns = std::chrono::hours(1);
+ else if (!strncasecmp(unitName, T_DAY_STR, strlen(T_DAY_STR)))
+ ns = std::chrono::hours(24);
+ else if (!strncasecmp(unitName, T_WEEK_STR, strlen(T_WEEK_STR)))
+ ns = std::chrono::hours(24 * 7);
+ else if (!strncasecmp(unitName, T_FORTNIGHT_STR, strlen(T_FORTNIGHT_STR)))
+ ns = std::chrono::hours(24 * 14);
+ else if (!strncasecmp(unitName, T_MONTH_STR, strlen(T_MONTH_STR)))
+ ns = std::chrono::hours(24 * 30);
+ else if (!strncasecmp(unitName, T_YEAR_STR, strlen(T_YEAR_STR)))
+ ns = std::chrono::hours(static_cast<std::chrono::hours::rep>(HoursPerYear));
+ else if (!strncasecmp(unitName, T_DECADE_STR, strlen(T_DECADE_STR)))
+ ns = std::chrono::hours(static_cast<std::chrono::hours::rep>(HoursPerYear * 10));
+ else
+ return false;
- time_msec_t m = u; /* default to 'units' if none specified */
+ if (ns < MinimalUnit(1)) {
+ throw TexcHere(ToSBuf("time unit '", unitName, "' is too small to be used in this context, the minimal unit is ",
+ TimeUnitToString<MinimalUnit>()));
+ }
- if (d) {
- if ((token = ConfigParser::PeekAtToken()) && (m = parseTimeUnits(token, allowMsec))) {
- (void)ConfigParser::NextToken();
+ return true;
+}
- } else if (!expectMoreArguments) {
- self_destruct();
- return 0;
+static std::chrono::nanoseconds
+ToNanoSeconds(const double value, const std::chrono::nanoseconds &unit)
+{
+ if (value < 0.0)
+ throw TexcHere("time must have a positive value");
- } else {
- token = NULL; // show default units if dying below
- debugs(3, DBG_CRITICAL, "WARNING: No units on '" << config_input_line << "', assuming " << d << " " << units);
- }
- } else
- token = NULL; // show default units if dying below.
+ if (value > (static_cast<double>(std::chrono::nanoseconds::max().count()) / unit.count())) {
+ const auto maxYears = std::chrono::duration_cast<std::chrono::hours>(std::chrono::nanoseconds::max()).count()/HoursPerYear;
+ throw TexcHere(ToSBuf("time values cannot exceed ", maxYears, " years"));
+ }
- const auto result = static_cast<time_msec_t>(m * d);
+ return std::chrono::duration_cast<std::chrono::nanoseconds>(unit * value);
+}
- if (static_cast<double>(result) * 2 != m * d * 2) {
- debugs(3, DBG_CRITICAL, "FATAL: Invalid value '" <<
- d << " " << (token ? token : units) << ": integer overflow (time_msec_t).");
- self_destruct();
+template <class TimeUnit>
+static TimeUnit
+FromNanoseconds(const std::chrono::nanoseconds &ns, const double parsedValue)
+{
+ const auto result = std::chrono::duration_cast<TimeUnit>(ns);
+ if (!result.count()) {
+ throw TexcHere(ToSBuf("time value '", parsedValue,
+ "' is too small to be used in this context, the minimal value is 1 ",
+ TimeUnitToString<TimeUnit>()));
}
return result;
}
-static uint64_t
-parseTimeUnits(const char *unit, bool allowMsec)
+/// Parses a time specification from the config file and
+/// returns the time as a chrono duration object of 'TimeUnit' type.
+template <class TimeUnit>
+static TimeUnit
+parseTimeLine()
{
- if (allowMsec && !strncasecmp(unit, T_MILLISECOND_STR, strlen(T_MILLISECOND_STR)))
- return 1;
-
- if (!strncasecmp(unit, T_SECOND_STR, strlen(T_SECOND_STR)))
- return 1000;
+ const auto valueToken = ConfigParser::NextToken();
+ if (!valueToken)
+ throw TexcHere("cannot read a time value");
- if (!strncasecmp(unit, T_MINUTE_STR, strlen(T_MINUTE_STR)))
- return 60 * 1000;
+ const auto parsedValue = xatof(valueToken);
- if (!strncasecmp(unit, T_HOUR_STR, strlen(T_HOUR_STR)))
- return 3600 * 1000;
+ if (parsedValue == 0)
+ return TimeUnit::zero();
- if (!strncasecmp(unit, T_DAY_STR, strlen(T_DAY_STR)))
- return 86400 * 1000;
+ std::chrono::nanoseconds parsedUnitDuration;
- if (!strncasecmp(unit, T_WEEK_STR, strlen(T_WEEK_STR)))
- return 86400 * 7 * 1000;
+ const auto token = ConfigParser::PeekAtToken();
- if (!strncasecmp(unit, T_FORTNIGHT_STR, strlen(T_FORTNIGHT_STR)))
- return 86400 * 14 * 1000;
+ if (!parseTimeUnit<TimeUnit>(token, parsedUnitDuration))
+ throw TexcHere(ToSBuf("unknown time unit '", token, "'"));
- if (!strncasecmp(unit, T_MONTH_STR, strlen(T_MONTH_STR)))
- return static_cast<uint64_t>(86400) * 30 * 1000;
+ (void)ConfigParser::NextToken();
- if (!strncasecmp(unit, T_YEAR_STR, strlen(T_YEAR_STR)))
- return static_cast<uint64_t>(86400 * 1000 * 365.2522);
+ const auto nanoseconds = ToNanoSeconds(parsedValue, parsedUnitDuration);
- if (!strncasecmp(unit, T_DECADE_STR, strlen(T_DECADE_STR)))
- return static_cast<uint64_t>(86400 * 1000 * 365.2522 * 10);
-
- debugs(3, DBG_IMPORTANT, "parseTimeUnits: unknown time unit '" << unit << "'");
+ // validate precisions (time-units-small only)
+ if (TimeUnit(1) <= std::chrono::microseconds(1)) {
+ if (0 < nanoseconds.count() && nanoseconds.count() < 3) {
+ debugs(3, DBG_PARSE_NOTE(DBG_IMPORTANT), ConfigParser::CurrentLocation() << ": WARNING: " <<
+ "Squid time measurement precision is likely to be far worse than " <<
+ "the nanosecond-level precision implied by the configured value: " << parsedValue << ' ' << token);
+ }
+ }
- return 0;
+ return FromNanoseconds<TimeUnit>(nanoseconds, parsedValue);
}
static void
return;
}
- if ((token = ConfigParser::NextToken()) == NULL) {
+ if ((token = ConfigParser::NextToken()) == nullptr) {
self_destruct();
return;
}
if (0.0 == d)
(void) 0;
- else if ((token = ConfigParser::NextToken()) == NULL)
+ else if ((token = ConfigParser::NextToken()) == nullptr)
debugs(3, DBG_CRITICAL, "WARNING: No units on '" <<
config_input_line << "', assuming " <<
d << " " << units );
return;
}
- if ((token = ConfigParser::NextToken()) == NULL) {
+ if ((token = ConfigParser::NextToken()) == nullptr) {
self_destruct();
return;
}
if (0.0 == d)
(void) 0;
- else if ((token = ConfigParser::NextToken()) == NULL)
+ else if ((token = ConfigParser::NextToken()) == nullptr)
debugs(3, DBG_CRITICAL, "WARNING: No units on '" <<
config_input_line << "', assuming " <<
d << " " << units );
return;
}
- if ((token = ConfigParser::NextToken()) == NULL) {
+ if ((token = ConfigParser::NextToken()) == nullptr) {
self_destruct();
return;
}
if (0.0 == d)
(void) 0;
- else if ((token = ConfigParser::NextToken()) == NULL)
+ else if ((token = ConfigParser::NextToken()) == nullptr)
debugs(3, DBG_CRITICAL, "WARNING: No units on '" <<
config_input_line << "', assuming " <<
d << " " << units );
}
String number;
- number.limitInit(number_begin, number_end - number_begin);
+ number.assign(number_begin, number_end - number_begin);
int d = xatoi(number.termedBuf());
int m;
static void
dump_acl(StoreEntry * entry, const char *name, ACL * ae)
{
- while (ae != NULL) {
+ while (ae != nullptr) {
debugs(3, 3, "dump_acl: " << name << " " << ae->name);
storeAppendPrintf(entry, "%s %s %s ",
name,
void
dump_acl_list(StoreEntry * entry, ACLList * head)
{
+ // XXX: Should dump ACL names like "foo !bar" but dumps parsing context like
+ // "(clientside_tos 0x11 line)".
dump_SBufList(entry, head->dump());
}
free_acl_address(Acl::Address ** head)
{
delete *head;
- *head = NULL;
+ *head = nullptr;
}
static void
return;
}
- if (!xstrtoui(token, NULL, &tos, 0, std::numeric_limits<tos_t>::max())) {
+ if (!xstrtoui(token, nullptr, &tos, 0, std::numeric_limits<tos_t>::max())) {
self_destruct();
return;
}
free_acl_tos(acl_tos ** head)
{
delete *head;
- *head = NULL;
+ *head = nullptr;
}
#if SO_MARK && USE_LIBCAP
free_acl_nfmark(acl_nfmark ** head)
{
delete *head;
- *head = NULL;
+ *head = nullptr;
}
#endif /* SO_MARK */
free_acl_b_size_t(AclSizeLimit ** head)
{
delete *head;
- *head = NULL;
+ *head = nullptr;
}
#if USE_DELAY_POOLS
static void
parse_http_header_access(HeaderManglers **pm)
{
- char *t = NULL;
+ char *t = nullptr;
- if ((t = ConfigParser::NextToken()) == NULL) {
+ if ((t = ConfigParser::NextToken()) == nullptr) {
debugs(3, DBG_CRITICAL, "" << cfg_filename << " line " << config_lineno << ": " << config_input_line);
- debugs(3, DBG_CRITICAL, "parse_http_header_access: missing header name.");
+ debugs(3, DBG_CRITICAL, "ERROR: parse_http_header_access: missing header name.");
return;
}
// we delete the entire http_header_* mangler configuration at once
if (const HeaderManglers *manglers = *pm) {
delete manglers;
- *pm = NULL;
+ *pm = nullptr;
}
}
static void
parse_http_header_replace(HeaderManglers **pm)
{
- char *t = NULL;
+ char *t = nullptr;
- if ((t = ConfigParser::NextToken()) == NULL) {
+ if ((t = ConfigParser::NextToken()) == nullptr) {
debugs(3, DBG_CRITICAL, "" << cfg_filename << " line " << config_lineno << ": " << config_input_line);
- debugs(3, DBG_CRITICAL, "parse_http_header_replace: missing header name.");
+ debugs(3, DBG_CRITICAL, "ERROR: parse_http_header_replace: missing header name.");
return;
}
static void
dump_cachedir(StoreEntry * entry, const char *name, const Store::DiskConfig &swap)
{
- SwapDir *s;
- int i;
- assert (entry);
-
- for (i = 0; i < swap.n_configured; ++i) {
- s = dynamic_cast<SwapDir *>(swap.swapDirs[i].getRaw());
- if (!s) continue;
- storeAppendPrintf(entry, "%s %s %s", name, s->type(), s->path);
- s->dump(*entry);
- storeAppendPrintf(entry, "\n");
- }
+ Store::Disks::Dump(swap, *entry, name);
}
static int
check_null_string(char *s)
{
- return s == NULL;
+ return s == nullptr;
}
#if USE_AUTH
/* find a configuration for the scheme in the currently parsed configs... */
Auth::SchemeConfig *schemeCfg = Auth::SchemeConfig::Find(type_str);
- if (schemeCfg == NULL) {
+ if (schemeCfg == nullptr) {
/* Create a configuration based on the scheme info */
Auth::Scheme::Pointer theScheme = Auth::Scheme::Find(type_str);
- if (theScheme == NULL) {
- debugs(3, DBG_CRITICAL, "Parsing Config File: Unknown authentication scheme '" << type_str << "'.");
+ if (theScheme == nullptr) {
+ debugs(3, DBG_CRITICAL, "ERROR: Failure while parsing Config File: Unknown authentication scheme '" << type_str << "'.");
self_destruct();
return;
}
config->push_back(theScheme->createConfig());
schemeCfg = Auth::SchemeConfig::Find(type_str);
- if (schemeCfg == NULL) {
+ if (schemeCfg == nullptr) {
debugs(3, DBG_CRITICAL, "Parsing Config File: Corruption configuring authentication scheme '" << type_str << "'.");
self_destruct();
return;
return;
}
Auth::TheConfig.schemeLists.emplace_back(tok, ConfigParser::LastTokenWasQuoted());
- const allow_t action = allow_t(ACCESS_ALLOWED, Auth::TheConfig.schemeLists.size() - 1);
+ const auto action = Acl::Answer(ACCESS_ALLOWED, Auth::TheConfig.schemeLists.size() - 1);
ParseAclWithAction(authSchemes, action, "auth_schemes");
}
dump_AuthSchemes(StoreEntry *entry, const char *name, acl_access *authSchemes)
{
if (authSchemes)
- dump_SBufList(entry, authSchemes->treeDump(name, [](const allow_t &action) {
+ dump_SBufList(entry, authSchemes->treeDump(name, [](const Acl::Answer &action) {
return Auth::TheConfig.schemeLists.at(action.kind).rawSchemes;
}));
}
#endif /* USE_AUTH */
static void
-ParseAclWithAction(acl_access **access, const allow_t &action, const char *desc, ACL *acl)
+ParseAclWithAction(acl_access **access, const Acl::Answer &action, const char *desc, ACL *acl)
{
assert(access);
SBuf name;
Acl::AndNode *rule = new Acl::AndNode;
name.Printf("(%s rule)", desc);
rule->context(name.c_str(), config_input_line);
- acl ? rule->add(acl) : rule->lineParse();
+ if (acl)
+ rule->add(acl);
+ else
+ rule->lineParse();
(*access)->add(rule, action);
}
-/* TODO: just return the object, the # is irrelevant */
-static int
-find_fstype(char *type)
-{
- for (size_t i = 0; i < StoreFileSystem::FileSystems().size(); ++i)
- if (strcasecmp(type, StoreFileSystem::FileSystems().at(i)->type()) == 0)
- return (int)i;
-
- return (-1);
-}
-
static void
parse_cachedir(Store::DiskConfig *swap)
{
- char *type_str = ConfigParser::NextToken();
- if (!type_str) {
- self_destruct();
- return;
- }
-
- char *path_str = ConfigParser::NextToken();
- if (!path_str) {
- self_destruct();
- return;
- }
-
- int fs = find_fstype(type_str);
- if (fs < 0) {
- debugs(3, DBG_PARSE_NOTE(DBG_IMPORTANT), "ERROR: This proxy does not support the '" << type_str << "' cache type. Ignoring.");
- return;
- }
-
- /* reconfigure existing dir */
-
- RefCount<SwapDir> sd;
- for (int i = 0; i < swap->n_configured; ++i) {
- assert (swap->swapDirs[i].getRaw());
-
- if ((strcasecmp(path_str, dynamic_cast<SwapDir *>(swap->swapDirs[i].getRaw())->path)) == 0) {
- /* this is specific to on-fs Stores. The right
- * way to handle this is probably to have a mapping
- * from paths to stores, and have on-fs stores
- * register with that, and lookip in that in their
- * own setup logic. RBC 20041225. TODO.
- */
-
- sd = dynamic_cast<SwapDir *>(swap->swapDirs[i].getRaw());
-
- if (strcmp(sd->type(), StoreFileSystem::FileSystems().at(fs)->type()) != 0) {
- debugs(3, DBG_CRITICAL, "ERROR: Can't change type of existing cache_dir " <<
- sd->type() << " " << sd->path << " to " << type_str << ". Restart required");
- return;
- }
-
- sd->reconfigure();
- return;
- }
- }
-
- /* new cache_dir */
- if (swap->n_configured > 63) {
- /* 7 bits, signed */
- debugs(3, DBG_CRITICAL, "WARNING: There is a fixed maximum of 63 cache_dir entries Squid can handle.");
- debugs(3, DBG_CRITICAL, "WARNING: '" << path_str << "' is one to many.");
- self_destruct();
- return;
- }
-
- allocate_new_swapdir(swap);
-
- swap->swapDirs[swap->n_configured] = StoreFileSystem::FileSystems().at(fs)->createSwapDir();
-
- sd = dynamic_cast<SwapDir *>(swap->swapDirs[swap->n_configured].getRaw());
-
- /* parse the FS parameters and options */
- sd->parse(swap->n_configured, path_str);
-
- ++swap->n_configured;
+ assert(swap);
+ Store::Disks::Parse(*swap);
}
static const char *
}
static void
-dump_peer(StoreEntry * entry, const char *name, CachePeer * p)
+dump_peer(StoreEntry * entry, const char *name, const CachePeers *peers)
{
+ if (!peers)
+ return;
+
NeighborTypeDomainList *t;
LOCAL_ARRAY(char, xname, 128);
- while (p != NULL) {
+ for (const auto &peer: *peers) {
+ const auto p = peer.get();
storeAppendPrintf(entry, "%s %s %s %d %d name=%s",
name,
p->host,
peer_type_str(t->type),
t->domain);
}
-
- p = p->next;
}
}
static unsigned short
GetService(const char *proto)
{
- struct servent *port = NULL;
+ struct servent *port = nullptr;
/** Parses a port number or service name from the squid.conf */
char *token = ConfigParser::NextToken();
- if (token == NULL) {
+ if (token == nullptr) {
self_destruct();
return 0; /* NEVER REACHED */
}
/** Returns either the service port number from /etc/services */
if ( !isUnsignedNumeric(token, strlen(token)) )
port = getservbyname(token, proto);
- if (port != NULL) {
+ if (port != nullptr) {
return ntohs((unsigned short)port->s_port);
}
/** Or a numeric translation of the config text. */
}
static void
-parse_peer(CachePeer ** head)
+parse_peer(CachePeers **peers)
{
char *host_str = ConfigParser::NextToken();
if (!host_str) {
return;
}
- CachePeer *p = new CachePeer;
- p->host = xstrdup(host_str);
- p->name = xstrdup(host_str);
+ const auto p = new CachePeer(host_str);
+
p->type = parseNeighborType(token);
if (p->type == PEER_MULTICAST) {
} else if (!strcmp(token, "carp")) {
if (p->type != PEER_PARENT)
- fatalf("parse_peer: non-parent carp peer %s/%d\n", p->host, p->http_port);
+ throw TextException(ToSBuf("non-parent carp cache_peer ", *p), Here());
p->options.carp = true;
} else if (!strncmp(token, "carp-key=", 9)) {
if (p->options.carp != true)
- fatalf("parse_peer: carp-key specified on non-carp peer %s/%d\n", p->host, p->http_port);
+ throw TextException(ToSBuf("carp-key specified on non-carp cache_peer ", *p), Here());
p->options.carp_key.set = true;
char *nextkey=token+strlen("carp-key="), *key=nextkey;
for (; key; key = nextkey) {
} else if (!strcmp(token, "userhash")) {
#if USE_AUTH
if (p->type != PEER_PARENT)
- fatalf("parse_peer: non-parent userhash peer %s/%d\n", p->host, p->http_port);
+ throw TextException(ToSBuf("non-parent userhash cache_peer ", *p), Here());
p->options.userhash = true;
#else
- fatalf("parse_peer: userhash requires authentication. peer %s/%d\n", p->host, p->http_port);
+ throw TextException(ToSBuf("missing authentication support; required for userhash cache_peer ", *p), Here());
#endif
} else if (!strcmp(token, "sourcehash")) {
if (p->type != PEER_PARENT)
- fatalf("parse_peer: non-parent sourcehash peer %s/%d\n", p->host, p->http_port);
+ throw TextException(ToSBuf("non-parent sourcehash cache_peer ", *p), Here());
p->options.sourcehash = true;
} else if (!strcmp(token, "originserver")) {
p->options.originserver = true;
} else if (!strncmp(token, "name=", 5)) {
- safe_free(p->name);
-
- if (token[5])
- p->name = xstrdup(token + 5);
+ p->rename(token + 5);
} else if (!strncmp(token, "forceddomain=", 13)) {
safe_free(p->domain);
if (token[13])
}
}
- if (peerFindByName(p->name))
- fatalf("ERROR: cache_peer %s specified twice\n", p->name);
+ if (findCachePeerByName(p->name))
+ throw TextException(ToSBuf("cache_peer ", *p, " specified twice"), Here());
if (p->max_conn > 0 && p->max_conn < p->standby.limit)
- fatalf("ERROR: cache_peer %s max-conn=%d is lower than its standby=%d\n", p->host, p->max_conn, p->standby.limit);
+ throw TextException(ToSBuf("cache_peer ", *p, " max-conn=", p->max_conn,
+ " is lower than its standby=", p->standby.limit), Here());
if (p->weight < 1)
p->weight = 1;
#if USE_CACHE_DIGESTS
if (!p->options.no_digest)
- peerDigestCreate(p);
+ p->digest = new PeerDigest(p);
#endif
- p->index = ++Config.npeers;
+ if (p->secure.encryptTransport)
+ p->secure.parseOptions();
- while (*head != NULL)
- head = &(*head)->next;
+ if (!*peers)
+ *peers = new CachePeers;
+
+ (*peers)->add(p);
- *head = p;
+ p->index = (*peers)->size();
peerClearRRStart();
}
static void
-free_peer(CachePeer ** P)
+free_peer(CachePeers ** const peers)
{
- delete *P;
- *P = NULL;
- Config.npeers = 0;
+ delete *peers;
+ *peers = nullptr;
}
static void
static void
dump_denyinfo(StoreEntry * entry, const char *name, AclDenyInfoList * var)
{
- while (var != NULL) {
+ while (var != nullptr) {
storeAppendPrintf(entry, "%s %s", name, var->err_page_name);
for (const auto &aclName: var->acl_list)
static void
parse_peer_access(void)
{
- char *host = ConfigParser::NextToken();
- if (!host) {
- self_destruct();
- return;
- }
-
- CachePeer *p = peerFindByName(host);
- if (!p) {
- debugs(15, DBG_CRITICAL, "ERROR: " << cfg_filename << ", line " << config_lineno << ": No cache_peer '" << host << "'");
- return;
- }
-
+ auto &p = LegacyParser.cachePeer("cache_peer_access peer-name");
std::string directive = "peer_access ";
- directive += host;
- aclParseAccessLine(directive.c_str(), LegacyParser, &p->access);
+ directive += p.name;
+ aclParseAccessLine(directive.c_str(), LegacyParser, &p.access);
}
static void
parse_hostdomaintype(void)
{
- char *host = ConfigParser::NextToken();
- if (!host) {
- self_destruct();
- return;
- }
+ auto &p = LegacyParser.cachePeer("neighbor_type_domain peer-name");
char *type = ConfigParser::NextToken();
if (!type) {
char *domain = nullptr;
while ((domain = ConfigParser::NextToken())) {
- CachePeer *p = peerFindByName(host);
- if (!p) {
- debugs(15, DBG_CRITICAL, "" << cfg_filename << ", line " << config_lineno << ": No cache_peer '" << host << "'");
- return;
- }
-
auto *l = static_cast<NeighborTypeDomainList *>(xcalloc(1, sizeof(NeighborTypeDomainList)));
l->type = parseNeighborType(type);
l->domain = xstrdup(domain);
NeighborTypeDomainList **L = nullptr;
- for (L = &(p->typelist); *L; L = &((*L)->next));
+ for (L = &p.typelist; *L; L = &((*L)->next));
*L = l;
}
}
storeAppendPrintf(entry, "%s %" PRId64 "\n", name, var);
}
-void
+static void
parse_int64_t(int64_t *var)
{
int64_t i;
#define free_tristate free_int
-void
+static void
parse_pipelinePrefetch(int *var)
{
char *token = ConfigParser::PeekAtToken();
static void
dump_refreshpattern(StoreEntry * entry, const char *name, RefreshPattern * head)
{
- while (head != NULL) {
- storeAppendPrintf(entry, "%s%s %s %d %d%% %d",
- name,
- head->pattern.flags®_ICASE ? " -i" : null_string,
- head->pattern.c_str(),
- (int) head->min / 60,
- (int) (100.0 * head->pct + 0.5),
- (int) head->max / 60);
+ while (head != nullptr) {
+ PackableStream os(*entry);
+ os << name << ' ';
+ head->printHead(os);
if (head->max_stale >= 0)
storeAppendPrintf(entry, " max-stale=%d", head->max_stale);
parse_refreshpattern(RefreshPattern ** head)
{
char *token;
- char *pattern;
time_t min = 0;
double pct = 0.0;
time_t max = 0;
int i;
RefreshPattern *t;
- regex_t comp;
- int errcode;
- int flags = REG_EXTENDED | REG_NOSUB;
-
- if ((token = ConfigParser::RegexPattern()) != NULL) {
-
- if (strcmp(token, "-i") == 0) {
- flags |= REG_ICASE;
- token = ConfigParser::RegexPattern();
- } else if (strcmp(token, "+i") == 0) {
- flags &= ~REG_ICASE;
- token = ConfigParser::RegexPattern();
- }
-
- }
-
- if (token == NULL) {
- debugs(3, DBG_CRITICAL, "FATAL: refresh_pattern missing the regex pattern parameter");
- self_destruct();
- return;
- }
- pattern = xstrdup(token);
+ auto regex = LegacyParser.regex("refresh_pattern regex");
i = GetInteger(); /* token: min */
max = (time_t) (i * 60); /* convert minutes to seconds */
/* Options */
- while ((token = ConfigParser::NextToken()) != NULL) {
+ while ((token = ConfigParser::NextToken()) != nullptr) {
if (!strcmp(token, "refresh-ims")) {
refresh_ims = 1;
} else if (!strcmp(token, "store-stale")) {
) {
debugs(22, DBG_PARSE_NOTE(2), "UPGRADE: refresh_pattern option '" << token << "' is obsolete. Remove it.");
} else
- debugs(22, DBG_CRITICAL, "refreshAddToList: Unknown option '" << pattern << "': " << token);
- }
-
- if ((errcode = regcomp(&comp, pattern, flags)) != 0) {
- char errbuf[256];
- regerror(errcode, &comp, errbuf, sizeof errbuf);
- debugs(22, DBG_CRITICAL, "" << cfg_filename << " line " << config_lineno << ": " << config_input_line);
- debugs(22, DBG_CRITICAL, "refreshAddToList: Invalid regular expression '" << pattern << "': " << errbuf);
- xfree(pattern);
- return;
+ debugs(22, DBG_CRITICAL, "ERROR: Unknown refresh_pattern option: " << token);
}
pct = pct < 0.0 ? 0.0 : pct;
max = max < 0 ? 0 : max;
- t = new RefreshPattern(pattern, flags);
- t->pattern.regex = comp;
+ t = new RefreshPattern(std::move(regex));
t->min = min;
t->pct = pct;
t->max = max;
t->flags.ignore_private = true;
#endif
- t->next = NULL;
+ t->next = nullptr;
while (*head)
head = &(*head)->next;
*head = t;
-
- xfree(pattern);
}
static void
static void
dump_string(StoreEntry * entry, const char *name, char *var)
{
- if (var != NULL)
+ if (var != nullptr)
storeAppendPrintf(entry, "%s %s\n", name, var);
}
void
parse_time_t(time_t * var)
{
- time_msec_t tval = parseTimeLine(T_SECOND_STR, false);
- *var = static_cast<time_t>(tval/1000);
+ const auto maxTime = std::numeric_limits<time_t>::max();
+ const auto seconds = parseTimeLine<std::chrono::seconds>();
+ if (maxTime < seconds.count())
+ throw TexcHere(ToSBuf("directive supports time values up to ", maxTime, " but is given ", seconds.count(), " seconds"));
+ *var = static_cast<time_t>(seconds.count());
}
static void
storeAppendPrintf(entry, "%s %d seconds\n", name, (int)(var/1000) );
}
-void
-parse_time_msec(time_msec_t * var)
+static void
+parse_time_msec(time_msec_t *var)
{
- *var = parseTimeLine(T_SECOND_STR, true);
+ *var = parseTimeLine<std::chrono::milliseconds>().count();
}
static void
*var = 0;
}
-#if UNUSED_CODE
static void
-dump_size_t(StoreEntry * entry, const char *name, size_t var)
+dump_time_nanoseconds(StoreEntry *entry, const char *name, const std::chrono::nanoseconds &var)
{
- storeAppendPrintf(entry, "%s %d\n", name, (int) var);
+ // std::chrono::nanoseconds::rep is unknown a priori so we cast to (and print) the largest supported integer
+ storeAppendPrintf(entry, "%s %jd nanoseconds\n", name, static_cast<intmax_t>(var.count()));
}
-#endif
static void
-dump_b_size_t(StoreEntry * entry, const char *name, size_t var)
+parse_time_nanoseconds(std::chrono::nanoseconds *var)
{
- storeAppendPrintf(entry, "%s %d %s\n", name, (int) var, B_BYTES_STR);
+ *var = parseTimeLine<std::chrono::nanoseconds>();
}
static void
-dump_b_ssize_t(StoreEntry * entry, const char *name, ssize_t var)
+free_time_nanoseconds(std::chrono::nanoseconds *var)
+{
+ *var = std::chrono::nanoseconds::zero();
+}
+
+static void
+dump_b_size_t(StoreEntry * entry, const char *name, size_t var)
{
storeAppendPrintf(entry, "%s %d %s\n", name, (int) var, B_BYTES_STR);
}
-#if UNUSED_CODE
static void
-dump_kb_size_t(StoreEntry * entry, const char *name, size_t var)
+dump_b_ssize_t(StoreEntry * entry, const char *name, ssize_t var)
{
- storeAppendPrintf(entry, "%s %d %s\n", name, (int) var, B_KBYTES_STR);
+ storeAppendPrintf(entry, "%s %d %s\n", name, (int) var, B_BYTES_STR);
}
-#endif
static void
dump_b_int64_t(StoreEntry * entry, const char *name, int64_t var)
storeAppendPrintf(entry, "%s %" PRId64 " %s\n", name, var, B_KBYTES_STR);
}
-#if UNUSED_CODE
-static void
-parse_size_t(size_t * var)
-{
- int i;
- i = GetInteger();
- *var = (size_t) i;
-}
-#endif
-
static void
parse_b_size_t(size_t * var)
{
parseBytesLineSigned(var, B_BYTES_STR);
}
-#if UNUSED_CODE
-static void
-parse_kb_size_t(size_t * var)
-{
- parseBytesLine(var, B_KBYTES_STR);
-}
-#endif
-
static void
parse_b_int64_t(int64_t * var)
{
static void
dump_wordlist(StoreEntry * entry, const char *name, wordlist * list)
{
- while (list != NULL) {
+ while (list != nullptr) {
storeAppendPrintf(entry, "%s %s\n", name, list->key);
list = list->next;
}
wordlistAdd(list, token);
}
-#if 0 /* now unused */
-static int
-check_null_wordlist(wordlist * w)
-{
- return w == NULL;
-}
-#endif
-
static int
check_null_acl_access(acl_access * a)
{
- return a == NULL;
+ return a == nullptr;
}
#define free_wordlist wordlistDestroy
delete *settings;
- *settings = NULL;
+ *settings = nullptr;
}
static void
free_IpAddress_list(Ip::Address_list ** head)
{
if (*head) delete *head;
- *head = NULL;
+ *head = nullptr;
}
#if CURRENTLY_UNUSED
static void
parsePortSpecification(const AnyP::PortCfgPointer &s, char *token)
{
- char *host = NULL;
+ char *host = nullptr;
unsigned short port = 0;
- char *t = NULL;
- char *junk = NULL;
+ char *t = nullptr;
+ char *junk = nullptr;
s->disable_pmtu_discovery = DISABLE_PMTU_OFF;
s->name = xstrdup(token);
return;
}
- if (port == 0 && host != NULL) {
+ if (port == 0 && host != nullptr) {
debugs(3, DBG_CRITICAL, "FATAL: " << portType << "_port: Port cannot be 0: " << token);
self_destruct();
return;
}
- if (NULL == host) {
+ if (nullptr == host) {
s->s.setAnyAddr();
s->s.port(port);
if (!Ip::EnableIpv6)
} else if (strncmp(token, "key=", 4) == 0) {
s->secure.parse(token);
} else if (strncmp(token, "version=", 8) == 0) {
- debugs(3, DBG_PARSE_NOTE(1), "UPGRADE WARNING: '" << token << "' is deprecated " <<
+ debugs(3, DBG_PARSE_NOTE(1), "WARNING: UPGRADE: '" << token << "' is deprecated " <<
"in " << cfg_directive << ". Use 'options=' instead.");
s->secure.parse(token);
} else if (strncmp(token, "options=", 8) == 0) {
} else if (strncmp(token, "clientca=", 9) == 0) {
s->secure.parse(token);
} else if (strncmp(token, "cafile=", 7) == 0) {
- debugs(3, DBG_PARSE_NOTE(1), "UPGRADE WARNING: '" << token << "' is deprecated " <<
+ debugs(3, DBG_PARSE_NOTE(1), "WARNING: UPGRADE: '" << token << "' is deprecated " <<
"in " << cfg_directive << ". Use 'tls-cafile=' instead.");
s->secure.parse(token);
} else if (strncmp(token, "capath=", 7) == 0) {
s->secure.parse(token+4);
} else if (strcmp(token, "ftp-track-dirs") == 0) {
s->ftp_track_dirs = true;
+ } else if (strcmp(token, "worker-queues") == 0) {
+#if !defined(SO_REUSEADDR)
+#error missing system #include that #defines SO_* constants
+#endif
+#if !defined(SO_REUSEPORT)
+ throw TexcHere(ToSBuf(cfg_directive, ' ', token, " option requires building Squid where SO_REUSEPORT is supported by the TCP stack"));
+#endif
+ s->workerQueues = true;
} else {
debugs(3, DBG_CRITICAL, "FATAL: Unknown " << cfg_directive << " option '" << token << "'.");
self_destruct();
s->transport = parsePortProtocol(SBuf("HTTP"));
parsePortSpecification(s, portspec);
// we may need to merge better if the above returns a list with clones
- assert(s->next == NULL);
+ assert(s->next == nullptr);
s->next = HttpPortList;
HttpPortList = s;
}
self_destruct();
return;
}
+ s->secure.parseOptions();
}
// *_port line should now be fully valid so we can clone it if necessary
if (Ip::EnableIpv6&IPV6_SPECIAL_SPLITSTACK && s->s.isAnyAddr()) {
- // clone the port options from *s to *(s->next)
- s->next = s->clone();
- s->next->s.setIPv4();
- debugs(3, 3, AnyP::UriScheme(s->transport.protocol).image() << "_port: clone wildcard address for split-stack: " << s->s << " and " << s->next->s);
+ s->next = s->ipV4clone();
}
- while (*head != NULL)
+ while (*head != nullptr)
head = &((*head)->next);
*head = s;
storeAppendPrintf(e, " ssl-bump");
#endif
- s->secure.dumpCfg(e, "tls-");
+ PackableStream os(*e);
+ s->secure.dumpCfg(os, "tls-");
}
static void
dump_PortCfg(StoreEntry * e, const char *n, const AnyP::PortCfgPointer &s)
{
- for (AnyP::PortCfgPointer p = s; p != NULL; p = p->next) {
+ for (AnyP::PortCfgPointer p = s; p != nullptr; p = p->next) {
dump_generic_port(e, n, p);
storeAppendPrintf(e, "\n");
}
configFreeMemory(void)
{
free_all();
+ Dns::ResolveClientAddressesAsap = false;
Config.ssl_client.sslContext.reset();
#if USE_OPENSSL
Ssl::unloadSquidUntrusted();
struct stat sb;
char pathbuf[BUFSIZ];
- assert(path != NULL);
+ assert(path != nullptr);
if (Config.chroot_dir && (geteuid() == 0)) {
snprintf(pathbuf, BUFSIZ, "%s/%s", Config.chroot_dir, path);
*
* #4: Configurable logging module with name=value options such as logformat=x:
* The first ACL name may not contain '='.
+ * Without any optional parts, directives using this style are indistinguishable
+ * from directives using style #1 until we start requiring the "module:" prefix.
* access_log module:place [option ...] [acl ...]
*
*/
return;
}
- CustomLog *cl = (CustomLog *)xcalloc(1, sizeof(*cl));
+ const auto cl = new CustomLog();
cl->filename = xstrdup(filename);
- // default buffer size and fatal settings
- cl->bufferSize = 8*MAX_URL;
- cl->fatal = true;
if (strcmp(filename, "none") == 0) {
cl->type = Log::Format::CLF_NONE;
return;
}
- cl->type = Log::Format::CLF_UNKNOWN;
- cl->rotateCount = -1; // default: use global logfile_rotate setting.
-
const char *token = ConfigParser::PeekAtToken();
- if (!token) { // style #1
- // no options to deal with
- } else if (!strchr(token, '=')) { // style #3
- // if logformat name is recognized,
- // pop the previewed token; Else it must be an ACL name
- if (setLogformat(cl, token, false))
- (void)ConfigParser::NextToken();
- } else { // style #4
- do {
- if (strncasecmp(token, "on-error=", 9) == 0) {
- if (strncasecmp(token+9, "die", 3) == 0) {
- cl->fatal = true;
- } else if (strncasecmp(token+9, "drop", 4) == 0) {
- cl->fatal = false;
- } else {
- debugs(3, DBG_CRITICAL, "Unknown value for on-error '" <<
- token << "' expected 'drop' or 'die'");
- xfree(cl->filename);
- xfree(cl);
- self_destruct();
- return;
- }
- } else if (strncasecmp(token, "buffer-size=", 12) == 0) {
- parseBytesOptionValue(&cl->bufferSize, B_BYTES_STR, token+12);
- } else if (strncasecmp(token, "rotate=", 7) == 0) {
- cl->rotateCount = xatoi(token + 7);
- } else if (strncasecmp(token, "logformat=", 10) == 0) {
- setLogformat(cl, token+10, true);
- } else if (!strchr(token, '=')) {
- // Do not pop the token; it must be an ACL name
- break; // done with name=value options, now to ACLs
- } else {
- debugs(3, DBG_CRITICAL, "Unknown access_log option " << token);
- xfree(cl->filename);
- xfree(cl);
- self_destruct();
- return;
- }
- // Pop the token, it was a valid "name=value" option
- (void)ConfigParser::NextToken();
- // Get next with preview ConfigParser::NextToken call.
- } while ((token = ConfigParser::PeekAtToken()) != NULL);
+ if (token && !strchr(token, '=')) { // style #3
+ // TODO: Deprecate this style to avoid this dangerous guessing.
+ if (Log::TheConfig.knownFormat(token)) {
+ cl->setLogformat(token);
+ (void)ConfigParser::NextToken(); // consume the token used above
+ } else {
+ // assume there is no explicit logformat name and use the default
+ cl->setLogformat("squid");
+ }
+ } else { // style #1 or style #4
+ // TODO: Drop deprecated style #1 support. We already warn about it, and
+ // its exceptional treatment makes detecting "module" typos impractical!
+ cl->parseOptions(LegacyParser, "squid");
}
-
- // set format if it has not been specified explicitly
- if (cl->type == Log::Format::CLF_UNKNOWN)
- setLogformat(cl, "squid", true);
+ assert(cl->type); // setLogformat() was called
aclParseAclList(LegacyParser, &cl->aclList, cl->filename);
*logs = cl;
}
-/// sets CustomLog::type and, if needed, CustomLog::lf
-/// returns false iff there is no named log format
-static bool
-setLogformat(CustomLog *cl, const char *logdef_name, const bool dieWhenMissing)
-{
- assert(cl);
- assert(logdef_name);
-
- debugs(3, 9, "possible " << cl->filename << " logformat: " << logdef_name);
-
- if (cl->type != Log::Format::CLF_UNKNOWN) {
- debugs(3, DBG_CRITICAL, "FATAL: Second logformat name in one access_log: " <<
- logdef_name << " " << cl->type << " ? " << Log::Format::CLF_NONE);
- self_destruct();
- return false;
- }
-
- /* look for the definition pointer corresponding to this name */
- Format::Format *lf = Log::TheConfig.logformats;
-
- while (lf != NULL) {
- debugs(3, 9, "Comparing against '" << lf->name << "'");
-
- if (strcmp(lf->name, logdef_name) == 0)
- break;
-
- lf = lf->next;
- }
-
- if (lf != NULL) {
- cl->type = Log::Format::CLF_CUSTOM;
- cl->logFormat = lf;
- } else if (strcmp(logdef_name, "auto") == 0) {
- debugs(0, DBG_CRITICAL, "WARNING: Log format 'auto' no longer exists. Using 'squid' instead.");
- cl->type = Log::Format::CLF_SQUID;
- } else if (strcmp(logdef_name, "squid") == 0) {
- cl->type = Log::Format::CLF_SQUID;
- } else if (strcmp(logdef_name, "common") == 0) {
- cl->type = Log::Format::CLF_COMMON;
- } else if (strcmp(logdef_name, "combined") == 0) {
- cl->type = Log::Format::CLF_COMBINED;
-#if ICAP_CLIENT
- } else if (strcmp(logdef_name, "icap_squid") == 0) {
- cl->type = Log::Format::CLF_ICAP_SQUID;
-#endif
- } else if (strcmp(logdef_name, "useragent") == 0) {
- cl->type = Log::Format::CLF_USERAGENT;
- } else if (strcmp(logdef_name, "referrer") == 0) {
- cl->type = Log::Format::CLF_REFERER;
- } else if (dieWhenMissing) {
- debugs(3, DBG_CRITICAL, "FATAL: Log format '" << logdef_name << "' is not defined");
- self_destruct();
- return false;
- } else {
- return false;
- }
-
- return true;
-}
-
static int
check_null_access_log(CustomLog *customlog_definitions)
{
- return customlog_definitions == NULL;
+ return customlog_definitions == nullptr;
}
static void
dump_access_log(StoreEntry * entry, const char *name, CustomLog * logs)
{
- CustomLog *log;
-
- for (log = logs; log; log = log->next) {
- storeAppendPrintf(entry, "%s ", name);
-
- switch (log->type) {
-
- case Log::Format::CLF_CUSTOM:
- storeAppendPrintf(entry, "%s logformat=%s", log->filename, log->logFormat->name);
- break;
-
- case Log::Format::CLF_NONE:
- storeAppendPrintf(entry, "logformat=none");
- break;
-
- case Log::Format::CLF_SQUID:
- // this is the default, no need to add to the dump
- //storeAppendPrintf(entry, "%s logformat=squid", log->filename);
- break;
-
- case Log::Format::CLF_COMBINED:
- storeAppendPrintf(entry, "%s logformat=combined", log->filename);
- break;
-
- case Log::Format::CLF_COMMON:
- storeAppendPrintf(entry, "%s logformat=common", log->filename);
- break;
-
-#if ICAP_CLIENT
- case Log::Format::CLF_ICAP_SQUID:
- storeAppendPrintf(entry, "%s logformat=icap_squid", log->filename);
- break;
-#endif
- case Log::Format::CLF_USERAGENT:
- storeAppendPrintf(entry, "%s logformat=useragent", log->filename);
- break;
-
- case Log::Format::CLF_REFERER:
- storeAppendPrintf(entry, "%s logformat=referrer", log->filename);
- break;
-
- case Log::Format::CLF_UNKNOWN:
- break;
+ assert(entry);
+ for (auto log = logs; log; log = log->next) {
+ {
+ PackableStream os(*entry);
+ os << name; // directive name
+ os << ' ' << log->filename; // including "none"
+ log->dumpOptions(os);
}
- // default is on-error=die
- if (!log->fatal)
- storeAppendPrintf(entry, " on-error=drop");
-
- // default: 64KB
- if (log->bufferSize != 64*1024)
- storeAppendPrintf(entry, " buffer-size=%" PRIuSIZE, log->bufferSize);
-
- if (log->rotateCount >= 0)
- storeAppendPrintf(entry, " rotate=%d", log->rotateCount);
-
if (log->aclList)
dump_acl_list(entry, log->aclList);
while (*definitions) {
CustomLog *log = *definitions;
*definitions = log->next;
-
- log->logFormat = NULL;
- log->type = Log::Format::CLF_UNKNOWN;
-
- if (log->aclList)
- aclDestroyAclList(&log->aclList);
-
- safe_free(log->filename);
-
- xfree(log);
+ delete log;
}
}
parse_CpuAffinityMap(CpuAffinityMap **const cpuAffinityMap)
{
#if !HAVE_CPU_AFFINITY
+ (void)cpuAffinityMap;
debugs(3, DBG_CRITICAL, "FATAL: Squid built with no CPU affinity " <<
"support, do not set 'cpu_affinity_map'");
self_destruct();
free_CpuAffinityMap(CpuAffinityMap **const cpuAffinityMap)
{
delete *cpuAffinityMap;
- *cpuAffinityMap = NULL;
+ *cpuAffinityMap = nullptr;
}
#if USE_ADAPTATION
static void parse_icap_service_failure_limit(Adaptation::Icap::Config *cfg)
{
char *token;
- time_t d;
- time_t m;
cfg->service_failure_limit = GetInteger();
- if ((token = ConfigParser::NextToken()) == NULL)
+ if ((token = ConfigParser::NextToken()) == nullptr)
return;
if (strcmp(token,"in") != 0) {
return;
}
- if ((token = ConfigParser::NextToken()) == NULL) {
- self_destruct();
- return;
- }
-
- d = static_cast<time_t> (xatoi(token));
-
- m = static_cast<time_t> (1);
-
- if (0 == d)
- (void) 0;
- else if ((token = ConfigParser::NextToken()) == NULL) {
- debugs(3, DBG_CRITICAL, "No time-units on '" << config_input_line << "'");
- self_destruct();
- return;
- } else if ((m = parseTimeUnits(token, false)) == 0) {
- self_destruct();
- return;
- }
-
- cfg->oldest_service_failure = (m * d);
+ parse_time_t(&cfg->oldest_service_failure);
}
static void dump_icap_service_failure_limit(StoreEntry *entry, const char *name, const Adaptation::Icap::Config &cfg)
#if USE_OPENSSL
static void parse_sslproxy_cert_adapt(sslproxy_cert_adapt **cert_adapt)
{
- char *al;
- sslproxy_cert_adapt *ca = (sslproxy_cert_adapt *) xcalloc(1, sizeof(sslproxy_cert_adapt));
- if ((al = ConfigParser::NextToken()) == NULL) {
- xfree(ca);
+ auto *al = ConfigParser::NextToken();
+ if (!al) {
self_destruct();
return;
}
param = s;
s = strchr(s, '}');
if (!s) {
- xfree(ca);
self_destruct();
return;
}
*s = '\0';
} else
- param = NULL;
+ param = nullptr;
+ std::unique_ptr<sslproxy_cert_adapt> ca(new sslproxy_cert_adapt);
if (strcmp(al, Ssl::CertAdaptAlgorithmStr[Ssl::algSetValidAfter]) == 0) {
ca->alg = Ssl::algSetValidAfter;
ca->param = xstrdup("on");
if (param) {
if (strlen(param) > 64) {
debugs(3, DBG_CRITICAL, "FATAL: sslproxy_cert_adapt: setCommonName{" <<param << "} : using common name longer than 64 bytes is not supported");
- xfree(ca);
self_destruct();
return;
}
}
} else {
debugs(3, DBG_CRITICAL, "FATAL: sslproxy_cert_adapt: unknown cert adaptation algorithm: " << al);
- xfree(ca);
self_destruct();
return;
}
while (*cert_adapt)
cert_adapt = &(*cert_adapt)->next;
- *cert_adapt = ca;
+ *cert_adapt = ca.release();
}
static void dump_sslproxy_cert_adapt(StoreEntry *entry, const char *name, sslproxy_cert_adapt *cert_adapt)
{
- for (sslproxy_cert_adapt *ca = cert_adapt; ca != NULL; ca = ca->next) {
+ for (const auto *ca = cert_adapt; ca; ca = ca->next) {
storeAppendPrintf(entry, "%s ", name);
storeAppendPrintf(entry, "%s{%s} ", Ssl::sslCertAdaptAlgoritm(ca->alg), ca->param);
if (ca->aclList)
static void free_sslproxy_cert_adapt(sslproxy_cert_adapt **cert_adapt)
{
- while (*cert_adapt) {
- sslproxy_cert_adapt *ca = *cert_adapt;
- *cert_adapt = ca->next;
- safe_free(ca->param);
-
- if (ca->aclList)
- aclDestroyAclList(&ca->aclList);
-
- safe_free(ca);
- }
+ delete *cert_adapt;
+ *cert_adapt = nullptr;
}
static void parse_sslproxy_cert_sign(sslproxy_cert_sign **cert_sign)
{
- char *al;
- sslproxy_cert_sign *cs = (sslproxy_cert_sign *) xcalloc(1, sizeof(sslproxy_cert_sign));
- if ((al = ConfigParser::NextToken()) == NULL) {
- xfree(cs);
+ const auto al = ConfigParser::NextToken();
+ if (!al) {
self_destruct();
return;
}
+ std::unique_ptr<sslproxy_cert_sign> cs(new sslproxy_cert_sign);
if (strcmp(al, Ssl::CertSignAlgorithmStr[Ssl::algSignTrusted]) == 0)
cs->alg = Ssl::algSignTrusted;
else if (strcmp(al, Ssl::CertSignAlgorithmStr[Ssl::algSignUntrusted]) == 0)
cs->alg = Ssl::algSignSelf;
else {
debugs(3, DBG_CRITICAL, "FATAL: sslproxy_cert_sign: unknown cert signing algorithm: " << al);
- xfree(cs);
self_destruct();
return;
}
while (*cert_sign)
cert_sign = &(*cert_sign)->next;
- *cert_sign = cs;
+ *cert_sign = cs.release();
}
static void dump_sslproxy_cert_sign(StoreEntry *entry, const char *name, sslproxy_cert_sign *cert_sign)
{
- sslproxy_cert_sign *cs;
- for (cs = cert_sign; cs != NULL; cs = cs->next) {
+ for (const auto *cs = cert_sign; cs; cs = cs->next) {
storeAppendPrintf(entry, "%s ", name);
storeAppendPrintf(entry, "%s ", Ssl::certSignAlgorithm(cs->alg));
if (cs->aclList)
static void free_sslproxy_cert_sign(sslproxy_cert_sign **cert_sign)
{
- while (*cert_sign) {
- sslproxy_cert_sign *cs = *cert_sign;
- *cert_sign = cs->next;
-
- if (cs->aclList)
- aclDestroyAclList(&cs->aclList);
-
- safe_free(cs);
- }
+ delete *cert_sign;
+ *cert_sign = nullptr;
}
class sslBumpCfgRr: public ::RegisteredRunner
public:
static Ssl::BumpMode lastDeprecatedRule;
/* RegisteredRunner API */
- virtual void finalizeConfig();
+ void finalizeConfig() override;
};
Ssl::BumpMode sslBumpCfgRr::lastDeprecatedRule = Ssl::bumpEnd;
-RunnerRegistrationEntry(sslBumpCfgRr);
+DefineRunnerRegistrator(sslBumpCfgRr);
void
sslBumpCfgRr::finalizeConfig()
static void parse_sslproxy_ssl_bump(acl_access **ssl_bump)
{
typedef const char *BumpCfgStyle;
- BumpCfgStyle bcsNone = NULL;
+ BumpCfgStyle bcsNone = nullptr;
BumpCfgStyle bcsNew = "new client/server-first/none";
BumpCfgStyle bcsOld = "deprecated allow/deny";
static BumpCfgStyle bumpCfgStyleLast = bcsNone;
BumpCfgStyle bumpCfgStyleNow = bcsNone;
char *bm;
- if ((bm = ConfigParser::NextToken()) == NULL) {
+ if ((bm = ConfigParser::NextToken()) == nullptr) {
self_destruct();
return;
}
- // if this is the first rule proccessed
- if (*ssl_bump == NULL) {
+ // if this is the first rule processed
+ if (*ssl_bump == nullptr) {
bumpCfgStyleLast = bcsNone;
sslBumpCfgRr::lastDeprecatedRule = Ssl::bumpEnd;
}
- allow_t action = allow_t(ACCESS_ALLOWED);
+ auto action = Acl::Answer(ACCESS_ALLOWED);
if (strcmp(bm, Ssl::BumpModeStr[Ssl::bumpClientFirst]) == 0) {
action.kind = Ssl::bumpClientFirst;
static void dump_sslproxy_ssl_bump(StoreEntry *entry, const char *name, acl_access *ssl_bump)
{
if (ssl_bump)
- dump_SBufList(entry, ssl_bump->treeDump(name, [](const allow_t &action) {
+ dump_SBufList(entry, ssl_bump->treeDump(name, [](const Acl::Answer &action) {
return Ssl::BumpModeStr.at(action.kind);
}));
}
if (!*headers) {
*headers = new HeaderWithAclList;
}
- if ((fn = ConfigParser::NextToken()) == NULL) {
+ if ((fn = ConfigParser::NextToken()) == nullptr) {
self_destruct();
return;
}
if (hwa->valueFormat) {
delete hwa->valueFormat;
- hwa->valueFormat = NULL;
+ hwa->valueFormat = nullptr;
}
}
delete *header;
- *header = NULL;
+ *header = nullptr;
}
static void parse_note(Notes *notes)
notes->clean();
}
+static DebugMessageId ParseDebugMessageId(const char *value, const char eov)
+{
+ const auto id = xatoui(value, eov);
+ if (!(0 < id && id < DebugMessageIdUpperBound))
+ throw TextException(ToSBuf("unknown cache_log_message ID: ", value), Here());
+ return static_cast<DebugMessageId>(id);
+}
+
+static void parse_cache_log_message(DebugMessages **debugMessages)
+{
+ DebugMessage msg;
+ DebugMessageId minId = 0;
+ DebugMessageId maxId = 0;
+
+ char *key = nullptr;
+ char *value = nullptr;
+ while (ConfigParser::NextKvPair(key, value)) {
+ if (strcmp(key, "id") == 0) {
+ if (minId > 0)
+ break;
+ minId = maxId = ParseDebugMessageId(value, '\0');
+ } else if (strcmp(key, "ids") == 0) {
+ if (minId > 0)
+ break;
+ const auto dash = strchr(value, '-');
+ if (!dash)
+ throw TextException(ToSBuf("malformed cache_log_message ID range: ", key, '=', value), Here());
+ minId = ParseDebugMessageId(value, '-');
+ maxId = ParseDebugMessageId(dash+1, '\0');
+ if (minId > maxId)
+ throw TextException(ToSBuf("invalid cache_log_message ID range: ", key, '=', value), Here());
+ } else if (strcmp(key, "level") == 0) {
+ if (msg.levelled())
+ break;
+ const auto level = xatoi(value);
+ if (level < 0)
+ throw TextException(ToSBuf("negative cache_log_message level: ", value), Here());
+ msg.level = level;
+ } else if (strcmp(key, "limit") == 0) {
+ if (msg.limited())
+ break;
+ msg.limit = xatoull(value, 10);
+ } else {
+ throw TextException(ToSBuf("unsupported cache_log_message option: ", key), Here());
+ }
+ key = value = nullptr;
+ }
+
+ if (key && value)
+ throw TextException(ToSBuf("repeated or conflicting cache_log_message option: ", key, '=', value), Here());
+
+ if (!minId)
+ throw TextException("cache_log_message is missing a required id=... or ids=... option", Here());
+
+ if (!(msg.levelled() || msg.limited()))
+ throw TextException("cache_log_message is missing a required level=... or limit=... option", Here());
+
+ assert(debugMessages);
+ if (!*debugMessages)
+ *debugMessages = new DebugMessages();
+
+ for (auto id = minId; id <= maxId; ++id) {
+ msg.id = id;
+ (*debugMessages)->messages.at(id) = msg;
+ }
+}
+
+static void dump_cache_log_message(StoreEntry *entry, const char *name, const DebugMessages *debugMessages)
+{
+ if (!debugMessages)
+ return;
+
+ SBufStream out;
+ for (const auto &msg: debugMessages->messages) {
+ if (!msg.configured())
+ continue;
+ out << name << " id=" << msg.id;
+ if (msg.levelled())
+ out << " level=" << msg.level;
+ if (msg.limited())
+ out << " limit=" << msg.limit;
+ out << "\n";
+ }
+ const auto buf = out.buf();
+ entry->append(buf.rawContent(), buf.length()); // may be empty
+}
+
+static void free_cache_log_message(DebugMessages **debugMessages)
+{
+ // clear old messages to avoid cumulative effect across (re)configurations
+ assert(debugMessages);
+ delete *debugMessages;
+ *debugMessages = nullptr;
+}
+
static bool FtpEspvDeprecated = false;
static void parse_ftp_epsv(acl_access **ftp_epsv)
{
- allow_t ftpEpsvDeprecatedAction;
+ Acl::Answer ftpEpsvDeprecatedAction;
bool ftpEpsvIsDeprecatedRule = false;
char *t = ConfigParser::PeekAtToken();
if (!strcmp(t, "off")) {
(void)ConfigParser::NextToken();
ftpEpsvIsDeprecatedRule = true;
- ftpEpsvDeprecatedAction = allow_t(ACCESS_DENIED);
+ ftpEpsvDeprecatedAction = Acl::Answer(ACCESS_DENIED);
} else if (!strcmp(t, "on")) {
(void)ConfigParser::NextToken();
ftpEpsvIsDeprecatedRule = true;
- ftpEpsvDeprecatedAction = allow_t(ACCESS_ALLOWED);
+ ftpEpsvDeprecatedAction = Acl::Answer(ACCESS_ALLOWED);
}
// Check for mixing "ftp_epsv on|off" and "ftp_epsv allow|deny .." rules:
// 2) if this line is "ftp_epsv on|off" and already exist rules of "ftp_epsv allow|deny ..."
// then abort
if ((!ftpEpsvIsDeprecatedRule && FtpEspvDeprecated) ||
- (ftpEpsvIsDeprecatedRule && !FtpEspvDeprecated && *ftp_epsv != NULL)) {
+ (ftpEpsvIsDeprecatedRule && !FtpEspvDeprecated && *ftp_epsv != nullptr)) {
debugs(3, DBG_CRITICAL, "FATAL: do not mix \"ftp_epsv on|off\" cfg lines with \"ftp_epsv allow|deny ...\" cfg lines. Update your ftp_epsv rules.");
self_destruct();
return;
delete *ftp_epsv;
*ftp_epsv = nullptr;
- if (ftpEpsvDeprecatedAction == allow_t(ACCESS_DENIED)) {
+ if (ftpEpsvDeprecatedAction == Acl::Answer(ACCESS_DENIED)) {
if (ACL *a = ACL::FindByName("all"))
ParseAclWithAction(ftp_epsv, ftpEpsvDeprecatedAction, "ftp_epsv", a);
else {
FtpEspvDeprecated = false;
}
+/// Like parseTimeLine() but does not require the timeunit to be specified.
+/// If missed, the default 'second' timeunit is assumed.
+static std::chrono::seconds
+ParseUrlRewriteTimeout()
+{
+ const auto timeValueToken = ConfigParser::NextToken();
+ if (!timeValueToken)
+ throw TexcHere("cannot read a time value");
+
+ using Seconds = std::chrono::seconds;
+
+ const auto parsedTimeValue = xatof(timeValueToken);
+
+ if (parsedTimeValue == 0)
+ return std::chrono::seconds::zero();
+
+ std::chrono::nanoseconds parsedUnitDuration;
+
+ const auto unitToken = ConfigParser::PeekAtToken();
+ if (parseTimeUnit<Seconds>(unitToken, parsedUnitDuration))
+ (void)ConfigParser::NextToken();
+ else {
+ const auto defaultParsed = parseTimeUnit<Seconds>(T_SECOND_STR, parsedUnitDuration);
+ assert(defaultParsed);
+ debugs(3, DBG_PARSE_NOTE(DBG_IMPORTANT), ConfigParser::CurrentLocation() <<
+ ": WARNING: missing time unit, using deprecated default '" << T_SECOND_STR << "'");
+ }
+
+ const auto nanoseconds = ToNanoSeconds(parsedTimeValue, parsedUnitDuration);
+
+ return FromNanoseconds<Seconds>(nanoseconds, parsedTimeValue);
+}
+
static void
parse_UrlHelperTimeout(SquidConfig::UrlHelperTimeout *config)
{
- const auto tval = parseTimeLine(T_SECOND_STR, false, true);
- Config.Timeout.urlRewrite = static_cast<time_t>(tval/1000);
+ // TODO: do not allow optional timeunit (as the documentation prescribes)
+ // and use parseTimeLine() instead.
+ Config.Timeout.urlRewrite = ParseUrlRewriteTimeout().count();
char *key, *value;
while(ConfigParser::NextKvPair(key, value)) {
parse_on_unsupported_protocol(acl_access **access)
{
char *tm;
- if ((tm = ConfigParser::NextToken()) == NULL) {
+ if ((tm = ConfigParser::NextToken()) == nullptr) {
self_destruct();
return;
}
- allow_t action = allow_t(ACCESS_ALLOWED);
+ auto action = Acl::Answer(ACCESS_ALLOWED);
if (strcmp(tm, "tunnel") == 0)
action.kind = 1;
else if (strcmp(tm, "respond") == 0)
"respond"
};
if (access) {
- SBufList lines = access->treeDump(name, [](const allow_t &action) {
+ SBufList lines = access->treeDump(name, [](const Acl::Answer &action) {
return onErrorTunnelMode.at(action.kind);
});
dump_SBufList(entry, lines);
free_acl_access(access);
}
+static void
+parse_http_upgrade_request_protocols(HttpUpgradeProtocolAccess **protoGuardsPtr)
+{
+ assert(protoGuardsPtr);
+ auto &protoGuards = *protoGuardsPtr;
+ if (!protoGuards)
+ protoGuards = new HttpUpgradeProtocolAccess();
+ protoGuards->configureGuard(LegacyParser);
+}
+
+static void
+dump_http_upgrade_request_protocols(StoreEntry *entry, const char *rawName, HttpUpgradeProtocolAccess *protoGuards)
+{
+ if (!protoGuards)
+ return;
+
+ const SBuf name(rawName);
+ protoGuards->forEach([entry,&name](const SBuf &proto, const acl_access *acls) {
+ SBufList line;
+ line.push_back(name);
+ line.push_back(proto);
+ const auto acld = acls->treeDump("", &Acl::AllowOrDeny);
+ line.insert(line.end(), acld.begin(), acld.end());
+ dump_SBufList(entry, line);
+ });
+}
+
+static void
+free_http_upgrade_request_protocols(HttpUpgradeProtocolAccess **protoGuardsPtr)
+{
+ assert(protoGuardsPtr);
+ auto &protoGuards = *protoGuardsPtr;
+ delete protoGuards;
+ protoGuards = nullptr;
+}
+