/*
- * Copyright (C) 1996-2015 The Squid Software Foundation and contributors
+ * Copyright (C) 1996-2017 The Squid Software Foundation and contributors
*
* Squid software is distributed under GPLv2+ license and includes
* contributions from numerous individuals and organizations.
#include "format/Token.h"
#include "helper.h"
#include "helper/Reply.h"
+#include "http/Stream.h"
#include "HttpHeaderTools.h"
#include "HttpReply.h"
#include "HttpRequest.h"
bool require_auth;
#endif
- enum {
- QUOTE_METHOD_SHELL = 1,
- QUOTE_METHOD_URL
- } quote;
+ Format::Quoting quote; // default quoting to use, set by protocol= parameter
Ip::Address local_addr;
};
#if USE_AUTH
require_auth(0),
#endif
- quote(external_acl::QUOTE_METHOD_URL)
+ quote(Format::LOG_QUOTE_URL)
{
local_addr.setLocalhost();
}
void
parse_externalAclHelper(external_acl ** list)
{
- external_acl *a = new external_acl;
char *token = ConfigParser::NextToken();
- if (!token)
+ if (!token) {
self_destruct();
+ return;
+ }
+ external_acl *a = new external_acl;
a->name = xstrdup(token);
// Allow supported %macros inside quoted tokens
} else if (strncmp(token, "grace=", 6) == 0) {
a->grace = atoi(token + 6);
} else if (strcmp(token, "protocol=2.5") == 0) {
- a->quote = external_acl::QUOTE_METHOD_SHELL;
+ a->quote = Format::LOG_QUOTE_SHELL;
} else if (strcmp(token, "protocol=3.0") == 0) {
debugs(3, DBG_PARSE_NOTE(2), "WARNING: external_acl_type option protocol=3.0 is deprecated. Remove this from your config.");
- a->quote = external_acl::QUOTE_METHOD_URL;
+ a->quote = Format::LOG_QUOTE_URL;
} else if (strcmp(token, "quote=url") == 0) {
debugs(3, DBG_PARSE_NOTE(2), "WARNING: external_acl_type option quote=url is deprecated. Remove this from your config.");
- a->quote = external_acl::QUOTE_METHOD_URL;
+ a->quote = Format::LOG_QUOTE_URL;
} else if (strcmp(token, "quote=shell") == 0) {
debugs(3, DBG_PARSE_NOTE(2), "WARNING: external_acl_type option quote=shell is deprecated. Use protocol=2.5 if still needed.");
- a->quote = external_acl::QUOTE_METHOD_SHELL;
+ a->quote = Format::LOG_QUOTE_SHELL;
/* INET6: allow admin to configure some helpers explicitly to
bind to IPv4/v6 localhost port. */
*/
enum Format::Quoting quote = Format::LOG_QUOTE_NONE;
Format::Token **fmt = &a->format.format;
+ bool data_used = false;
while (token) {
/* stop on first non-% token found */
if (*token != '%')
break;
*fmt = new Format::Token;
+ // these tokens are whitespace delimited
+ (*fmt)->space = true;
+
+ // set the default encoding to match the protocol= config
+ // this will be overridden by explicit %macro attributes
+ (*fmt)->quote = a->quote;
// compatibility for old tokens incompatible with Format::Token syntax
#if USE_OPENSSL // dont bother if we dont have to.
a->require_auth = true;
#endif
+ if ((*fmt)->type == Format::LFT_EXT_ACL_DATA)
+ data_used = true;
+
fmt = &((*fmt)->next);
token = ConfigParser::NextToken();
}
/* There must be at least one format token */
- if (!a->format.format)
+ if (!a->format.format) {
+ delete a;
self_destruct();
+ return;
+ }
+
+ // format has implicit %DATA on the end if not used explicitly
+ if (!data_used) {
+ *fmt = new Format::Token;
+ (*fmt)->type = Format::LFT_EXT_ACL_DATA;
+ (*fmt)->quote = Format::LOG_QUOTE_NONE;
+ }
/* helper */
- if (!token)
+ if (!token) {
+ delete a;
self_destruct();
+ return;
+ }
wordlistAdd(&a->cmdline, token);
if (node->children.n_max != DEFAULT_EXTERNAL_ACL_CHILDREN)
storeAppendPrintf(sentry, " children-max=%d", node->children.n_max);
- if (node->children.n_startup != 1)
+ if (node->children.n_startup != 0) // sync with helper/ChildConfig.cc default
storeAppendPrintf(sentry, " children-startup=%d", node->children.n_startup);
- if (node->children.n_idle != (node->children.n_max + node->children.n_startup) )
+ if (node->children.n_idle != 1) // sync with helper/ChildConfig.cc default
storeAppendPrintf(sentry, " children-idle=%d", node->children.n_idle);
- if (node->children.concurrency)
+ if (node->children.concurrency != 0)
storeAppendPrintf(sentry, " concurrency=%d", node->children.concurrency);
if (node->cache)
storeAppendPrintf(sentry, " cache=%d", node->cache_size);
- if (node->quote == external_acl::QUOTE_METHOD_SHELL)
+ if (node->quote == Format::LOG_QUOTE_SHELL)
storeAppendPrintf(sentry, " protocol=2.5");
node->format.dump(sentry, NULL, false);
void
ACLExternal::parse()
{
- if (data)
+ if (data) {
self_destruct();
+ return;
+ }
char *token = ConfigParser::strtokFile();
- if (!token)
+ if (!token) {
self_destruct();
+ return;
+ }
data = new external_acl_data(find_externalAclHelper(token));
- if (!data->def)
+ if (!data->def) {
+ delete data;
self_destruct();
+ return;
+ }
// def->name is the name of the external_acl_type.
// this is the name of the 'acl' directive being tested
if (!entry) {
debugs(82, 2, HERE << acl->def->name << "(\"" << key << "\") = lookup needed");
- if (!acl->def->theHelper->queueFull()) {
+ // TODO: All other helpers allow temporary overload. Should not we?
+ if (!acl->def->theHelper->willOverload()) {
debugs(82, 2, HERE << "\"" << key << "\": queueing a call.");
if (!ch->goAsync(ExternalACLLookup::Instance()))
debugs(82, 2, "\"" << key << "\": no async support!");
} else {
if (!staleEntry) {
debugs(82, DBG_IMPORTANT, "WARNING: external ACL '" << acl->def->name <<
- "' queue overload. Request rejected '" << key << "'.");
+ "' queue full. Request rejected '" << key << "'.");
external_acl_message = "SYSTEM TOO BUSY, TRY AGAIN LATER";
return ACCESS_DUNNO;
} else {
debugs(82, DBG_IMPORTANT, "WARNING: external ACL '" << acl->def->name <<
- "' queue overload. Using stale result. '" << key << "'.");
+ "' queue full. Using stale result. '" << key << "'.");
entry = staleEntry;
/* Fall thru to processing below */
}
makeExternalAclKey(ACLFilledChecklist * ch, external_acl_data * acl_data)
{
static MemBuf mb;
+ mb.reset();
// check for special case tokens in the format
for (Format::Token *t = acl_data->def->format.format; t ; t = t->next) {
if (t->type == Format::LFT_EXT_ACL_NAME) {
// setup for %ACL
- safe_free(ch->al->_private.lastAclName);
- ch->al->_private.lastAclName = xstrdup(acl_data->name);
+ safe_free(ch->al->lastAclName);
+ ch->al->lastAclName = xstrdup(acl_data->name);
}
- if (t->type == Format::LFT_EXT_ACL_NAME) {
+ if (t->type == Format::LFT_EXT_ACL_DATA) {
// setup string for %DATA
SBuf sb;
- bool first = true;
for (auto arg = acl_data->arguments; arg; arg = arg->next) {
- if (!first)
+ if (sb.length())
sb.append(" ", 1);
- if (acl_data->def->quote == external_acl::QUOTE_METHOD_URL) {
+ if (acl_data->def->quote == Format::LOG_QUOTE_URL) {
const char *quoted = rfc1738_escape(arg->key);
sb.append(quoted, strlen(quoted));
} else {
sb.append(mb2.buf, mb2.size);
mb2.clean();
}
-
- first = false;
}
+
+ ch->al->lastAclData = sb;
}
+#if USE_IDENT
if (t->type == Format::LFT_USER_IDENT) {
- if (!ch->rfc931 || !*ch->rfc931) {
+ if (!*ch->rfc931) {
// if we fail to go async, we still return NULL and the caller
// will detect the failure in ACLExternal::match().
(void)ch->goAsync(IdentLookup::Instance());
return NULL;
}
}
+#endif
}
+ // assemble the full helper lookup string
acl_data->def->format.assemble(mb, ch->al, 0);
return mb.buf;