+/*
+ * DEBUG: section 84 Helper process maintenance
+ * AUTHOR: Amos Jeffries
+ */
#include "squid.h"
#include "HelperReply.h"
#include "helper.h"
+#include "SquidString.h"
-#if 0
-HelperReply::HelperReply(const HelperReply &r) :
- result(r.result)
- other_(r.other()),
-{
-}
-#endif
-
-HelperReply::HelperReply(const char *buf, size_t len) :
+HelperReply::HelperReply(const char *buf, size_t len, bool urlQuoting) :
result(HelperReply::Unknown),
whichServer(NULL)
{
// NULL-terminate so the helper callback handlers do not buffer-overrun
other_.terminate();
+
+ bool found;
+ do {
+ found = false;
+ found |= parseKeyValue("tag=", 4, tag);
+ found |= parseKeyValue("user=", 5, user);
+ found |= parseKeyValue("password=", 9, password);
+ found |= parseKeyValue("message=", 8, message);
+ found |= parseKeyValue("log=", 8, log);
+ } while(found);
+
+ if (urlQuoting) {
+ // unescape the reply values
+ if (tag.hasContent())
+ rfc1738_unescape(tag.buf());
+ if (user.hasContent())
+ rfc1738_unescape(user.buf());
+ if (password.hasContent())
+ rfc1738_unescape(password.buf());
+ if (message.hasContent())
+ rfc1738_unescape(message.buf());
+ if (log.hasContent())
+ rfc1738_unescape(log.buf());
+ }
+}
+
+bool
+HelperReply::parseKeyValue(const char *key, size_t key_len, MemBuf &value)
+{
+ if (other().contentSize() > static_cast<mb_size_t>(key_len) && memcmp(other().content(), key, key_len) == 0) {
+ // parse the value out of the string. may be double-quoted
+ char *tmp = modifiableOther().content() + key_len;
+ const char *token = strwordtok(NULL, &tmp);
+ value.reset();
+ value.append(token,strlen(token));
+ const mb_size_t keyPairSize = tmp - other().content();
+ modifiableOther().consume(keyPairSize);
+ modifiableOther().consumeWhitespace();
+ return true;
+ }
+ return false;
}
std::ostream &
break;
case HelperReply::Error:
os << "ERR";
- break;
+ break;
case HelperReply::BrokenHelper:
os << "BH";
break;
public:
// create/parse details from the msg buffer provided
- HelperReply(const char *buf, size_t len);
+ HelperReply(const char *buf, size_t len, bool urlQuoting = false);
~HelperReply() {}
const MemBuf &other() const { return other_; }
/// and by token blob/arg parsing in Negotiate auth handler
MemBuf &modifiableOther() const { return *const_cast<MemBuf*>(&other_); }
+ bool parseKeyValue(const char *key, size_t key_len, MemBuf &);
+
public:
/// The helper response 'result' field.
enum Result_ {
NA
} result;
-// TODO other key=pair values. when the callbacks actually use this object.
+ // some pre-determined keys
+ MemBuf tag;
+ MemBuf user;
+ MemBuf password;
+ MemBuf message;
+ MemBuf log;
+
+// TODO other (custom) key=pair values. when the callbacks actually use this object.
// for now they retain their own parsing routines handling other()
/// for stateful replies the responding helper 'server' needs to be preserved across callbacks
entryData.result = ACCESS_ALLOWED;
// XXX: handle other non-DENIED results better
+ if (reply.tag.hasContent())
+ entryData.tag = reply.tag;
+ if (reply.message.hasContent())
+ entryData.message = reply.message;
+ if (reply.log.hasContent())
+ entryData.log = reply.log;
+#if USE_AUTH
+ if (reply.user.hasContent())
+ entryData.user = reply.user;
+ if (reply.password.hasContent())
+ entryData.password = reply.password;
+#endif
+
+ // legacy reply parser
if (reply.other().hasContent()) {
char *temp = reply.modifiableOther().content();
char *token = strwordtok(temp, &t);
while ((token = strwordtok(NULL, &t))) {
+ debugs(82, DBG_IMPORTANT, "WARNING: key '" << token << "' is not supported by this Squid.");
char *value = strchr(token, '=');
if (value) {
if (state->def->quote == external_acl::QUOTE_METHOD_URL)
rfc1738_unescape(value);
- if (strcmp(token, "message") == 0)
- entryData.message = value;
- else if (strcmp(token, "error") == 0)
+ if (strcmp(token, "error") == 0) {
entryData.message = value;
- else if (strcmp(token, "tag") == 0)
- entryData.tag = value;
- else if (strcmp(token, "log") == 0)
- entryData.log = value;
#if USE_AUTH
- else if (strcmp(token, "user") == 0)
- entryData.user = value;
- else if (strcmp(token, "password") == 0)
- entryData.password = value;
- else if (strcmp(token, "passwd") == 0)
+ } else if (strcmp(token, "passwd") == 0) {
entryData.password = value;
- else if (strcmp(token, "login") == 0)
+ } else if (strcmp(token, "login") == 0) {
entryData.user = value;
#endif
+ }
}
}
}
p->theHelper->addr = p->local_addr;
+ if (p->quote == external_acl::QUOTE_METHOD_URL)
+ p->theHelper->url_quoting = true;
+
helperOpenServers(p->theHelper);
}
void *cbdata = NULL;
if (cbdataReferenceValidDone(r->data, &cbdata))
- callback(cbdata, HelperReply(msg, (msg_end-msg)));
+ callback(cbdata, HelperReply(msg, (msg_end-msg), hlp->url_quoting));
-- srv->stats.pending;
class helper
{
public:
- inline helper(const char *name) : cmdline(NULL), id_name(name), eom('\n') {}
+ inline helper(const char *name) : cmdline(NULL), id_name(name), eom('\n'), url_quoting(false) {}
~helper();
public:
time_t last_queue_warn;
time_t last_restart;
char eom; ///< The char which marks the end of (response) message, normally '\n'
+ bool url_quoting;
struct _stats {
int requests;