/*
- * SQUID Web Proxy Cache http://www.squid-cache.org/
- * ----------------------------------------------------------
- *
- * Squid is the result of efforts by numerous individuals from
- * the Internet community; see the CONTRIBUTORS file for full
- * details. Many organizations have provided support for Squid's
- * development; see the SPONSORS file for full details. Squid is
- * Copyrighted (C) 2001 by the Regents of the University of
- * California; see the COPYRIGHT file for full details. Squid
- * incorporates software developed and/or copyrighted by other
- * sources; see the CREDITS file for full details.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ * Copyright (C) 1996-2015 The Squid Software Foundation and contributors
*
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
*/
#include "squid.h"
-#include "globals.h"
+#include "AccessLogEntry.h"
#include "acl/FilledChecklist.h"
#include "acl/Gadgets.h"
+#include "client_side.h"
#include "ConfigParser.h"
-#include "HttpRequest.h"
+#include "globals.h"
#include "HttpReply.h"
+#include "HttpRequest.h"
#include "SquidConfig.h"
#include "Store.h"
+#include "StrList.h"
#include <algorithm>
#include <string>
}
const char *
-Note::match(HttpRequest *request, HttpReply *reply)
+Note::match(HttpRequest *request, HttpReply *reply, const AccessLogEntry::Pointer &al)
{
typedef Values::iterator VLI;
ACLFilledChecklist ch(NULL, request, NULL);
+ ch.reply = reply;
if (reply)
- ch.reply = HTTPMSGLOCK(reply);
+ HTTPMSGLOCK(ch.reply);
for (VLI i = values.begin(); i != values.end(); ++i ) {
const int ret= ch.fastCheck((*i)->aclList);
debugs(93, 5, HERE << "Check for header name: " << key << ": " << (*i)->value
<<", HttpRequest: " << request << " HttpReply: " << reply << " matched: " << ret);
- if (ret == ACCESS_ALLOWED)
- return (*i)->value.termedBuf();
+ if (ret == ACCESS_ALLOWED) {
+ if (al != NULL && (*i)->valueFormat != NULL) {
+ static MemBuf mb;
+ mb.reset();
+ (*i)->valueFormat->assemble(mb, al, 0);
+ return mb.content();
+ } else
+ return (*i)->value.termedBuf();
+ }
}
return NULL;
}
Note::Pointer
-Notes::find(const String ¬eKey) const
+Notes::add(const String ¬eKey)
{
- typedef Notes::NotesList::const_iterator AMLI;
+ typedef Notes::NotesList::iterator AMLI;
for (AMLI i = notes.begin(); i != notes.end(); ++i) {
if ((*i)->key == noteKey)
return (*i);
}
- return Note::Pointer();
-}
-
-void
-Notes::add(const String ¬eKey, const String ¬eValue)
-{
- Note::Pointer key = add(noteKey);
- key->addValue(noteValue);
-}
-
-Note::Pointer
-Notes::add(const String ¬eKey)
-{
- Note::Pointer note = find(noteKey);
- if (note == NULL) {
- note = new Note(noteKey);
- notes.push_back(note);
- }
+ Note::Pointer note = new Note(noteKey);
+ notes.push_back(note);
return note;
}
-void
-Notes::add(const Notes &src)
-{
- typedef Notes::NotesList::const_iterator AMLI;
- typedef Note::Values::iterator VLI;
-
- for (AMLI i = src.notes.begin(); i != src.notes.end(); ++i) {
-
- // ensure we have a key by that name to fill out values for...
- // NP: not sharing pointers at the key level since merging other helpers
- // details later would affect this src objects keys, which is a bad idea.
- Note::Pointer ourKey = add((*i)->key);
-
- // known key names, merge the values lists...
- for (VLI v = (*i)->values.begin(); v != (*i)->values.end(); ++v ) {
- // 2012-11-29: values are read-only and Pointer can safely be shared
- // for now we share pointers to save memory and gain speed.
- // If that ever ceases to be true, convert this to a full copy.
- ourKey->values.push_back(*v);
- // TODO: prune/skip duplicates ?
- }
- }
-}
-
Note::Pointer
Notes::parse(ConfigParser &parser)
{
- String key, value;
- ConfigParser::ParseString(&key);
- ConfigParser::ParseQuotedString(&value);
+ String key = ConfigParser::NextToken();
+ ConfigParser::EnableMacros();
+ String value = ConfigParser::NextQuotedToken();
+ ConfigParser::DisableMacros();
+ bool valueWasQuoted = ConfigParser::LastTokenWasQuoted();
Note::Pointer note = add(key);
Note::Value::Pointer noteValue = note->addValue(value);
- aclParseAclList(parser, ¬eValue->aclList);
+ String label(key);
+ label.append('=');
+ label.append(value);
+ aclParseAclList(parser, ¬eValue->aclList, label.termedBuf());
+ if (formattedValues && valueWasQuoted) {
+ noteValue->valueFormat = new Format::Format(descr ? descr : "Notes");
+ noteValue->valueFormat->parse(value.termedBuf());
+ }
if (blacklisted) {
for (int i = 0; blacklisted[i] != NULL; ++i) {
if (note->key.caseCmp(blacklisted[i]) == 0) {
void
Notes::clean()
{
- notes.clean();
+ notes.clear();
}
+
+NotePairs::~NotePairs()
+{
+ while (!entries.empty()) {
+ delete entries.back();
+ entries.pop_back();
+ }
+}
+
+const char *
+NotePairs::find(const char *noteKey, const char *sep) const
+{
+ static String value;
+ value.clean();
+ for (std::vector<NotePairs::Entry *>::const_iterator i = entries.begin(); i != entries.end(); ++i) {
+ if ((*i)->name.cmp(noteKey) == 0) {
+ if (value.size())
+ value.append(sep);
+ value.append((*i)->value);
+ }
+ }
+ return value.size() ? value.termedBuf() : NULL;
+}
+
+const char *
+NotePairs::toString(const char *sep) const
+{
+ static String value;
+ value.clean();
+ for (std::vector<NotePairs::Entry *>::const_iterator i = entries.begin(); i != entries.end(); ++i) {
+ value.append((*i)->name);
+ value.append(": ");
+ value.append((*i)->value);
+ value.append(sep);
+ }
+ return value.size() ? value.termedBuf() : NULL;
+}
+
+const char *
+NotePairs::findFirst(const char *noteKey) const
+{
+ for (std::vector<NotePairs::Entry *>::const_iterator i = entries.begin(); i != entries.end(); ++i) {
+ if ((*i)->name.cmp(noteKey) == 0)
+ return (*i)->value.termedBuf();
+ }
+ return NULL;
+}
+
+void
+NotePairs::add(const char *key, const char *note)
+{
+ entries.push_back(new NotePairs::Entry(key, note));
+}
+
+void
+NotePairs::remove(const char *key)
+{
+ std::vector<NotePairs::Entry *>::iterator i = entries.begin();
+ while (i != entries.end()) {
+ if ((*i)->name.cmp(key) == 0) {
+ delete *i;
+ i = entries.erase(i);
+ } else {
+ ++i;
+ }
+ }
+}
+
+void
+NotePairs::addStrList(const char *key, const char *values)
+{
+ String strValues(values);
+ const char *item;
+ const char *pos = NULL;
+ int ilen = 0;
+ while (strListGetItem(&strValues, ',', &item, &ilen, &pos)) {
+ String v;
+ v.append(item, ilen);
+ entries.push_back(new NotePairs::Entry(key, v.termedBuf()));
+ }
+}
+
+bool
+NotePairs::hasPair(const char *key, const char *value) const
+{
+ for (std::vector<NotePairs::Entry *>::const_iterator i = entries.begin(); i != entries.end(); ++i) {
+ if ((*i)->name.cmp(key) == 0 && (*i)->value.cmp(value) == 0)
+ return true;
+ }
+ return false;
+}
+
+void
+NotePairs::append(const NotePairs *src)
+{
+ for (std::vector<NotePairs::Entry *>::const_iterator i = src->entries.begin(); i != src->entries.end(); ++i) {
+ entries.push_back(new NotePairs::Entry((*i)->name.termedBuf(), (*i)->value.termedBuf()));
+ }
+}
+
+void
+NotePairs::appendNewOnly(const NotePairs *src)
+{
+ for (std::vector<NotePairs::Entry *>::const_iterator i = src->entries.begin(); i != src->entries.end(); ++i) {
+ if (!hasPair((*i)->name.termedBuf(), (*i)->value.termedBuf()))
+ entries.push_back(new NotePairs::Entry((*i)->name.termedBuf(), (*i)->value.termedBuf()));
+ }
+}
+
+void
+NotePairs::replaceOrAdd(const NotePairs *src)
+{
+ for (std::vector<NotePairs::Entry *>::const_iterator i = src->entries.begin(); i != src->entries.end(); ++i) {
+ remove((*i)->name.termedBuf());
+ }
+ append(src);
+}
+
+NotePairs &
+SyncNotes(AccessLogEntry &ale, HttpRequest &request)
+{
+ // XXX: auth code only has access to HttpRequest being authenticated
+ // so we must handle the case where HttpRequest is set without ALE being set.
+
+ if (!ale.notes) {
+ if (!request.notes)
+ request.notes = new NotePairs;
+ ale.notes = request.notes;
+ } else {
+ assert(ale.notes == request.notes);
+ }
+ return *ale.notes;
+}
+
+void
+UpdateRequestNotes(ConnStateData *csd, HttpRequest &request, NotePairs const &helperNotes)
+{
+ // Tag client connection if the helper responded with clt_conn_tag=tag.
+ if (const char *connTag = helperNotes.findFirst("clt_conn_tag")) {
+ if (csd)
+ csd->connectionTag(connTag);
+ }
+ if (!request.notes)
+ request.notes = new NotePairs;
+ request.notes->replaceOrAdd(&helperNotes);
+}
+