note option This patch adds note option to squid.conf. It is similar to adaptation_meta but is applied after all adaptation and before logging. Values of key/value pair notes can be logged using %{key}note macros. note key value acl ... logformat myFormat ... %{key}note ... This option may be initially used to log custom information about the master transaction. For example, an admin may configure Squid to log which "user group" the transaction belongs to, where "user group" will be determined based on a set of ACLs and not [just] authentication information. From user point of view, adaptation_header sets/implies meta (i.e., setting adaptation_meta is sufficient to be able to log it using %note) but the note option itself (if any) is evaluated later, so it has no effect on ICAP headers. This is a Measurement Factory project === modified file 'src/AccessLogEntry.h' --- src/AccessLogEntry.h 2012-09-21 14:57:30 +0000 +++ src/AccessLogEntry.h 2012-10-22 08:03:05 +0000 @@ -15,49 +15,51 @@ * 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) 2003, Robert Collins */ #ifndef SQUID_HTTPACCESSLOGENTRY_H #define SQUID_HTTPACCESSLOGENTRY_H #include "anyp/PortCfg.h" #include "comm/Connection.h" +#include "HttpHeader.h" #include "HttpVersion.h" #include "HttpRequestMethod.h" #include "HierarchyLogEntry.h" #include "icp_opcode.h" #include "ip/Address.h" #include "HttpRequestMethod.h" #if ICAP_CLIENT #include "adaptation/icap/Elements.h" #endif +#include "Notes.h" #include "RefCount.h" #if USE_SSL #include "ssl/gadgets.h" #endif /* forward decls */ class HttpReply; class HttpRequest; class CustomLog; class AccessLogEntry: public RefCountable { public: typedef RefCount Pointer; AccessLogEntry() : url(NULL), tcpClient(), reply(NULL), request(NULL), adapted_request(NULL) {} ~AccessLogEntry(); @@ -212,40 +214,42 @@ /// image of the last ICAP response header or eCAP meta received char *last_meta; } adapt; #endif // Why is this a sub-class and not a set of real "private:" fields? // It looks like its duplicating HTTPRequestMethod anyway! // TODO: shuffle this to the relevant protocol section OR replace with request->method class Private { public: Private() : method_str(NULL) {} const char *method_str; } _private; HierarchyLogEntry hier; HttpReply *reply; HttpRequest *request; //< virgin HTTP request HttpRequest *adapted_request; //< HTTP request after adaptation and redirection + /// key:value pairs set by note and adaptation_meta + NotePairs notes; #if ICAP_CLIENT /** \brief This subclass holds log info for ICAP part of request * \todo Inner class declarations should be moved outside */ class IcapLogEntry { public: IcapLogEntry():bodyBytesRead(-1),request(NULL),reply(NULL),outcome(Adaptation::Icap::xoUnknown),trTime(0),ioTime(0),resStatus(HTTP_STATUS_NONE) {} Ip::Address hostAddr; ///< ICAP server IP address String serviceName; ///< ICAP service name String reqUri; ///< ICAP Request-URI Adaptation::Icap::ICAP::Method reqMethod; ///< ICAP request method int64_t bytesSent; ///< number of bytes sent to ICAP server so far int64_t bytesRead; ///< number of bytes read from ICAP server so far /** * number of ICAP body bytes read from ICAP server or -1 for no encapsulated * message data in ICAP reply (eg 204 responses) */ === modified file 'src/HttpHeader.h' --- src/HttpHeader.h 2012-09-25 16:38:36 +0000 +++ src/HttpHeader.h 2012-10-22 07:56:13 +0000 @@ -158,40 +158,41 @@ ftDate_1123, ftETag, ftPCc, ftPContRange, ftPRange, ftPSc, ftDate_1123_or_ETag } field_type; /** Possible owners of http header */ typedef enum { hoNone =0, #if USE_HTCP hoHtcpReply, #endif hoRequest, hoReply, #if USE_SSL hoErrorDetail, #endif + hoNote, hoEnd } http_hdr_owner_type; // currently a POD class HttpHeaderFieldAttrs { public: const char *name; http_hdr_type id; field_type type; }; /** Iteration for headers; use HttpHeaderPos as opaque type, do not interpret */ typedef ssize_t HttpHeaderPos; /* use this and only this to initialize HttpHeaderPos */ #define HttpHeaderInitPos (-1) class HttpHeaderEntry { === modified file 'src/HttpHeaderTools.cc' --- src/HttpHeaderTools.cc 2012-09-21 13:27:44 +0000 +++ src/HttpHeaderTools.cc 2012-10-21 17:06:00 +0000 @@ -14,46 +14,48 @@ * 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. * */ #include "squid.h" +#include "globals.h" #include "acl/FilledChecklist.h" #include "acl/Gadgets.h" #include "client_side_request.h" #include "client_side.h" #include "comm/Connection.h" #include "compat/strtoll.h" +#include "ConfigParser.h" #include "fde.h" #include "HttpHdrContRange.h" #include "HttpHeader.h" #include "HttpHeaderFieldInfo.h" #include "HttpHeaderTools.h" #include "HttpRequest.h" #include "MemBuf.h" #include "SquidConfig.h" #include "Store.h" #include "StrList.h" #if USE_SSL #include "ssl/support.h" #endif #include #include #if HAVE_ERRNO_H #include #endif === modified file 'src/Makefile.am' --- src/Makefile.am 2012-10-13 21:31:34 +0000 +++ src/Makefile.am 2012-10-21 22:09:02 +0000 @@ -423,40 +423,42 @@ SquidList.h \ SquidList.cc \ lookup_t.h \ main.cc \ Mem.h \ mem.cc \ mem_node.cc \ mem_node.h \ Mem.h \ MemBuf.cc \ MemObject.cc \ MemObject.h \ mime.h \ mime.cc \ mime_header.h \ mime_header.cc \ multicast.h \ multicast.cc \ neighbors.h \ neighbors.cc \ + Notes.cc \ + Notes.h \ Packer.cc \ Packer.h \ Parsing.cc \ Parsing.h \ $(XPROF_STATS_SOURCE) \ pconn.cc \ pconn.h \ PeerDigest.h \ peer_digest.cc \ peer_proxy_negotiate_auth.h \ peer_proxy_negotiate_auth.cc \ peer_select.cc \ peer_sourcehash.h \ peer_sourcehash.cc \ peer_userhash.h \ peer_userhash.cc \ PeerSelectState.h \ PingData.h \ protos.h \ redirect.h \ @@ -1100,40 +1102,41 @@ #tests_testX_SOURCES=\ # tests/testX.h \ # tests/testX.cc \ # tests/testMain.cc \ # X.h \ # X.cc #nodist_tests_testX_SOURCES=\ # $(TESTSOURCES) #tests_testX_LDFLAGS = $(LIBADD_DL) #tests_testX_LDADD=\ # $(SQUID_CPPUNIT_LIBS) \ # $(SQUID_CPPUNIT_LA) \ # $(COMPAT_LIB) \ #tests_testX_DEPENDENCIES= $(SQUID_CPPUNIT_LA) # - add other component .(h|cc) files needed to link and run tests tests_testHttpReply_SOURCES=\ cbdata.cc \ cbdata.h \ + ConfigParser.cc \ ETag.cc \ fatal.h \ tests/stub_fatal.cc \ HttpBody.h \ HttpBody.cc \ HttpHeaderFieldStat.h \ HttpHdrCc.h \ HttpHdrCc.cc \ HttpHdrCc.cci \ HttpHdrContRange.cc \ HttpHdrContRange.h \ HttpHdrRange.cc \ HttpHdrSc.cc \ HttpHdrSc.h \ HttpHdrScTarget.cc \ HttpHdrScTarget.h \ HttpHeader.h \ HttpHeader.cc \ HttpHeaderMask.h \ HttpHeaderFieldInfo.h \ @@ -1472,40 +1475,42 @@ icp_v3.cc \ $(IPC_SOURCE) \ ipcache.cc \ int.h \ int.cc \ internal.h \ internal.cc \ SquidList.h \ SquidList.cc \ multicast.h \ multicast.cc \ mem_node.cc \ MemBuf.cc \ MemObject.cc \ mime.h \ mime.cc \ mime_header.h \ mime_header.cc \ neighbors.h \ neighbors.cc \ + Notes.cc \ + Notes.h \ Packer.cc \ Parsing.cc \ pconn.cc \ peer_digest.cc \ peer_proxy_negotiate_auth.h \ peer_proxy_negotiate_auth.cc \ peer_select.cc \ peer_sourcehash.h \ peer_sourcehash.cc \ peer_userhash.h \ peer_userhash.cc \ redirect.h \ redirect.cc \ refresh.h \ refresh.cc \ RemovalPolicy.cc \ Server.cc \ $(SNMP_SOURCE) \ SquidMath.h \ SquidMath.cc \ @@ -1882,40 +1887,42 @@ ipcache.cc \ int.h \ int.cc \ internal.h \ internal.cc \ SquidList.h \ SquidList.cc \ Mem.h \ mem.cc \ mem_node.cc \ MemBuf.cc \ MemObject.cc \ mime.h \ mime.cc \ mime_header.h \ mime_header.cc \ multicast.h \ multicast.cc \ neighbors.h \ neighbors.cc \ + Notes.cc \ + Notes.h \ Packer.cc \ Parsing.cc \ pconn.cc \ peer_digest.cc \ peer_proxy_negotiate_auth.h \ peer_proxy_negotiate_auth.cc \ peer_select.cc \ peer_sourcehash.h \ peer_sourcehash.cc \ peer_userhash.h \ peer_userhash.cc \ redirect.h \ redirect.cc \ refresh.h \ refresh.cc \ RemovalPolicy.cc \ Server.cc \ StrList.h \ StrList.cc \ $(SNMP_SOURCE) \ @@ -2124,40 +2131,42 @@ ipcache.cc \ int.h \ int.cc \ internal.h \ internal.cc \ SquidList.h \ SquidList.cc \ MemBuf.cc \ MemObject.cc \ Mem.h \ mem.cc \ mem_node.cc \ mime.h \ mime.cc \ mime_header.h \ mime_header.cc \ multicast.h \ multicast.cc \ neighbors.h \ neighbors.cc \ + Notes.cc \ + Notes.h \ Packer.cc \ Parsing.cc \ pconn.cc \ peer_digest.cc \ peer_proxy_negotiate_auth.h \ peer_proxy_negotiate_auth.cc \ peer_select.cc \ peer_sourcehash.h \ peer_sourcehash.cc \ peer_userhash.h \ peer_userhash.cc \ RemovalPolicy.cc \ redirect.h \ redirect.cc \ refresh.h \ refresh.cc \ Server.cc \ $(SNMP_SOURCE) \ SquidMath.h \ SquidMath.cc \ @@ -2363,40 +2372,42 @@ int.cc \ internal.h \ internal.cc \ $(IPC_SOURCE) \ ipcache.cc \ SquidList.h \ SquidList.cc \ MemBuf.cc \ MemObject.cc \ Mem.h \ mem.cc \ mem_node.cc \ mime.h \ mime.cc \ mime_header.h \ mime_header.cc \ multicast.h \ multicast.cc \ neighbors.h \ neighbors.cc \ + Notes.cc \ + Notes.h \ Packer.cc \ Parsing.cc \ peer_digest.cc \ peer_proxy_negotiate_auth.h \ peer_proxy_negotiate_auth.cc \ peer_select.cc \ peer_sourcehash.h \ peer_sourcehash.cc \ peer_userhash.h \ peer_userhash.cc \ pconn.cc \ redirect.h \ redirect.cc \ refresh.h \ refresh.cc \ RemovalPolicy.cc \ Server.cc \ $(SNMP_SOURCE) \ SquidMath.h \ SquidMath.cc \ @@ -2643,40 +2654,42 @@ icp_v3.cc \ $(IPC_SOURCE) \ ipcache.cc \ int.h \ int.cc \ internal.h \ internal.cc \ SquidList.h \ SquidList.cc \ multicast.h \ multicast.cc \ mem_node.cc \ MemBuf.cc \ MemObject.cc \ mime.h \ mime.cc \ mime_header.h \ mime_header.cc \ neighbors.h \ neighbors.cc \ + Notes.cc \ + Notes.h \ Packer.cc \ Parsing.cc \ pconn.cc \ peer_digest.cc \ peer_proxy_negotiate_auth.h \ peer_proxy_negotiate_auth.cc \ peer_select.cc \ peer_sourcehash.h \ peer_sourcehash.cc \ peer_userhash.h \ peer_userhash.cc \ redirect.h \ redirect.cc \ refresh.h \ refresh.cc \ RemovalPolicy.cc \ Server.cc \ $(SNMP_SOURCE) \ SquidMath.h \ SquidMath.cc \ @@ -3732,40 +3745,42 @@ ipcache.cc \ int.h \ int.cc \ internal.h \ internal.cc \ SquidList.h \ SquidList.cc \ multicast.h \ multicast.cc \ Mem.h \ mem.cc \ mem_node.cc \ MemBuf.cc \ MemObject.cc \ mime.h \ mime.cc \ mime_header.h \ mime_header.cc \ neighbors.h \ neighbors.cc \ + Notes.cc \ + Notes.h \ Packer.cc \ Parsing.cc \ pconn.cc \ peer_digest.cc \ peer_proxy_negotiate_auth.h \ peer_proxy_negotiate_auth.cc \ peer_select.cc \ peer_sourcehash.h \ peer_sourcehash.cc \ peer_userhash.h \ peer_userhash.cc \ redirect.h \ redirect.cc \ refresh.h \ refresh.cc \ RemovalPolicy.cc \ Server.cc \ $(SNMP_SOURCE) \ SquidMath.h \ SquidMath.cc \ === added file 'src/Notes.cc' --- src/Notes.cc 1970-01-01 00:00:00 +0000 +++ src/Notes.cc 2012-10-21 21:49:02 +0000 @@ -0,0 +1,131 @@ +/* + * 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. + * + */ + +#include "squid.h" +#include "globals.h" +#include "acl/FilledChecklist.h" +#include "acl/Gadgets.h" +#include "ConfigParser.h" +#include "HttpRequest.h" +#include "HttpReply.h" +#include "SquidConfig.h" +#include "Store.h" + +#include +#include + +Note::Value::~Value() +{ + aclDestroyAclList(&aclList); +} + +Note::Value::Pointer +Note::addValue(const String &value) +{ + Value::Pointer v = new Value(value); + values.push_back(v); + return v; +} + +const char * +Note::match(HttpRequest *request, HttpReply *reply) +{ + + typedef Values::iterator VLI; + ACLFilledChecklist ch(NULL, request, NULL); + if (reply) + ch.reply = HTTPMSGLOCK(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(); + } + return NULL; +} + +Note::Pointer +Notes::add(const String ¬eKey) +{ + typedef Notes::NotesList::iterator AMLI; + for (AMLI i = notes.begin(); i != notes.end(); ++i) { + if ((*i)->key == noteKey) + return (*i); + } + + Note::Pointer note = new Note(noteKey); + notes.push_back(note); + return note; +} + +Note::Pointer +Notes::parse(ConfigParser &parser) +{ + String key, value; + ConfigParser::ParseString(&key); + ConfigParser::ParseQuotedString(&value); + Note::Pointer note = add(key); + Note::Value::Pointer noteValue = note->addValue(value); + aclParseAclList(parser, ¬eValue->aclList); + + if (blacklisted) { + for (int i = 0; blacklisted[i] != NULL; ++i) { + if (note->key.caseCmp(blacklisted[i]) == 0) { + fatalf("%s:%d: meta key \"%s\" is a reserved %s name", + cfg_filename, config_lineno, note->key.termedBuf(), + descr ? descr : ""); + } + } + } + + return note; +} + +void +Notes::dump(StoreEntry *entry, const char *key) +{ + typedef Notes::NotesList::iterator AMLI; + for (AMLI m = notes.begin(); m != notes.end(); ++m) { + typedef Note::Values::iterator VLI; + for (VLI v =(*m)->values.begin(); v != (*m)->values.end(); ++v ) { + storeAppendPrintf(entry, "%s " SQUIDSTRINGPH " %s", + key, SQUIDSTRINGPRINT((*m)->key), ConfigParser::QuoteString((*v)->value)); + dump_acl_list(entry, (*v)->aclList); + storeAppendPrintf(entry, "\n"); + } + } +} + +void +Notes::clean() +{ + notes.clean(); +} === added file 'src/Notes.h' --- src/Notes.h 1970-01-01 00:00:00 +0000 +++ src/Notes.h 2012-10-22 08:01:54 +0000 @@ -0,0 +1,103 @@ +#ifndef SQUID_NOTES_H +#define SQUID_NOTES_H + +#include "HttpHeader.h" +#include "HttpHeaderTools.h" +#include "typedefs.h" + +#if HAVE_STRING +#include +#endif + + +class HttpRequest; +class HttpReply; + +/** + * Used to store notes. The notes are custom key:value pairs + * ICAP request headers or ECAP options used to pass + * custom transaction-state related meta information to squid + * internal subsystems or to addaptation services. + */ +class Note: public RefCountable +{ +public: + typedef RefCount Pointer; + /// Stores a value for the note. + class Value: public RefCountable + { + public: + typedef RefCount Pointer; + String value; ///< a note value + ACLList *aclList; ///< The access list used to determine if this value is valid for a request + explicit Value(const String &aVal) : value(aVal), aclList(NULL) {} + ~Value(); + }; + typedef Vector Values; + + explicit Note(const String &aKey): key(aKey) {} + + /** + * Adds a value to the note and returns a pointer to the + * related Value object. + */ + Value::Pointer addValue(const String &value); + + /** + * Walks through the possible values list of the note and selects + * the first value which matches the given HttpRequest and HttpReply + * or NULL if none matches. + */ + const char *match(HttpRequest *request, HttpReply *reply); + String key; ///< The note key + Values values; ///< The possible values list for the note +}; + +class ConfigParser; +/** + * Used to store a notes list. + */ +class Notes { +public: + typedef Vector NotesList; + typedef NotesList::iterator iterator; ///< iterates over the notes list + + Notes(const char *aDescr, const char **metasBlacklist): descr(aDescr), blacklisted(metasBlacklist) {} + Notes(): descr(NULL), blacklisted(NULL) {} + ~Notes() { notes.clean(); } + /** + * Parse a notes line and returns a pointer to the + * parsed Note object. + */ + Note::Pointer parse(ConfigParser &parser); + /** + * Dump the notes list to the given StoreEntry object. + */ + void dump(StoreEntry *entry, const char *name); + void clean(); /// clean the notes list + + /// points to the first argument + iterator begin() { return notes.begin(); } + /// points to the end of list + iterator end() { return notes.end(); } + /// return true if the notes list is empty + bool empty() { return notes.empty(); } + + NotesList notes; ///< The Note::Pointer objects array list + const char *descr; ///< A short description for notes list + const char **blacklisted; ///< Null terminated list of blacklisted note keys +private: + /** + * Adds a note to the notes list and returns a pointer to the + * related Note object. If the note key already exists in list, + * returns a pointer to the existing object. + */ + Note::Pointer add(const String ¬eKey); +}; + +class NotePairs : public HttpHeader { +public: + NotePairs() : HttpHeader(hoNote) {} +}; + +#endif === modified file 'src/SquidConfig.h' --- src/SquidConfig.h 2012-10-09 23:15:44 +0000 +++ src/SquidConfig.h 2012-10-21 21:36:28 +0000 @@ -19,40 +19,41 @@ * (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. * */ #include "acl/AclAddress.h" #include "ClientDelayConfig.h" #include "DelayConfig.h" #include "HelperChildConfig.h" #include "HttpHeaderTools.h" #include "icmp/IcmpConfig.h" #include "ip/Address.h" +#include "Notes.h" #include "RefCount.h" #include "YesNoNone.h" #if USE_SSL #include class sslproxy_cert_sign; class sslproxy_cert_adapt; #endif class acl_access; class AclSizeLimit; class AclDenyInfoList; namespace Mgr { class ActionPasswordList; } // namespace Mgr class CustomLog; class CpuAffinityMap; class external_acl; class HeaderManglers; @@ -459,40 +460,42 @@ int max_open_disk_fds; int uri_whitespace; AclSizeLimit *rangeOffsetLimit; #if MULTICAST_MISS_STREAM struct { Ip::Address addr; int ttl; unsigned short port; char *encode_key; } mcast_miss; #endif /// request_header_access and request_header_replace HeaderManglers *request_header_access; /// reply_header_access and reply_header_replace HeaderManglers *reply_header_access; ///request_header_add access list HeaderWithAclList *request_header_add; + ///note + Notes notes; char *coredump_dir; char *chroot_dir; #if USE_CACHE_DIGESTS struct { int bits_per_entry; time_t rebuild_period; time_t rewrite_period; size_t swapout_chunk_size; int rebuild_chunk_percentage; } digest; #endif #if USE_SSL struct { int unclean_shutdown; char *ssl_engine; } SSL; #endif === modified file 'src/adaptation/Config.cc' --- src/adaptation/Config.cc 2012-09-23 09:04:21 +0000 +++ src/adaptation/Config.cc 2012-10-21 14:35:35 +0000 @@ -32,87 +32,58 @@ #include "acl/FilledChecklist.h" #include "acl/Gadgets.h" #include "adaptation/AccessRule.h" #include "adaptation/Config.h" #include "adaptation/History.h" #include "adaptation/Service.h" #include "adaptation/ServiceGroups.h" #include "Array.h" #include "ConfigParser.h" #include "globals.h" #include "HttpReply.h" #include "HttpRequest.h" #include "Store.h" bool Adaptation::Config::Enabled = false; char *Adaptation::Config::masterx_shared_name = NULL; int Adaptation::Config::service_iteration_limit = 16; int Adaptation::Config::send_client_ip = false; int Adaptation::Config::send_username = false; int Adaptation::Config::use_indirect_client = true; -Adaptation::Config::MetaHeaders Adaptation::Config::metaHeaders; - -Adaptation::Config::MetaHeader::Value::~Value() -{ - aclDestroyAclList(&aclList); -} - -Adaptation::Config::MetaHeader::Value::Pointer -Adaptation::Config::MetaHeader::addValue(const String &value) -{ - Value::Pointer v = new Value(value); - values.push_back(v); - return v; -} - -const char * -Adaptation::Config::MetaHeader::match(HttpRequest *request, HttpReply *reply) -{ - - typedef Values::iterator VLI; - ACLFilledChecklist ch(NULL, request, NULL); - if (reply) - ch.reply = HTTPMSGLOCK(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: " << name << ": " << (*i)->value - <<", HttpRequest: " << request << " HttpReply: " << reply << " matched: " << ret); - if (ret == ACCESS_ALLOWED) - return (*i)->value.termedBuf(); - } - return NULL; -} - -Adaptation::Config::MetaHeader::Pointer -Adaptation::Config::addMetaHeader(const String &headerName) -{ - typedef MetaHeaders::iterator AMLI; - for (AMLI i = metaHeaders.begin(); i != metaHeaders.end(); ++i) { - if ((*i)->name == headerName) - return (*i); - } - - MetaHeader::Pointer meta = new MetaHeader(headerName); - metaHeaders.push_back(meta); - return meta; -} +const char *metasBlacklist[] = { + "Methods", + "Service", + "ISTag", + "Encapsulated", + "Opt-body-type", + "Max-Connections", + "Options-TTL", + "Date", + "Service-ID", + "Allow", + "Preview", + "Transfer-Preview", + "Transfer-Ignore", + "Transfer-Complete", + NULL +}; +Notes Adaptation::Config::metaHeaders("ICAP header", metasBlacklist); Adaptation::ServiceConfig* Adaptation::Config::newServiceConfig() const { return new ServiceConfig(); } void Adaptation::Config::removeService(const String& service) { removeRule(service); const Groups& groups = AllGroups(); for (unsigned int i = 0; i < groups.size(); ) { const ServiceGroupPointer group = groups[i]; const ServiceGroup::Store& services = group->services; typedef ServiceGroup::Store::const_iterator SGSI; for (SGSI it = services.begin(); it != services.end(); ++it) { if (*it == service) { group->removedServices.push_back(service); group->services.prune(service); @@ -163,42 +134,40 @@ void Adaptation::Config::parseService() { ServiceConfigPointer cfg = newServiceConfig(); if (!cfg->parse()) { fatalf("%s:%d: malformed adaptation service configuration", cfg_filename, config_lineno); } serviceConfigs.push_back(cfg); } void Adaptation::Config::freeService() { FreeAccess(); FreeServiceGroups(); DetachServices(); serviceConfigs.clean(); - - FreeMetaHeader(); } void Adaptation::Config::dumpService(StoreEntry *entry, const char *name) const { typedef Services::iterator SCI; for (SCI i = AllServices().begin(); i != AllServices().end(); ++i) { const ServiceConfig &cfg = (*i)->cfg(); storeAppendPrintf(entry, "%s " SQUIDSTRINGPH "_%s %s %d " SQUIDSTRINGPH "\n", name, SQUIDSTRINGPRINT(cfg.key), cfg.methodStr(), cfg.vectPointStr(), cfg.bypass, SQUIDSTRINGPRINT(cfg.uri)); } } bool Adaptation::Config::finalize() { if (!onoff) { @@ -239,98 +208,40 @@ { typedef typename Collection::iterator CI; for (CI i = collection.begin(); i != collection.end(); ++i) (*i)->finalize(); debugs(93,2, HERE << "Initialized " << collection.size() << ' ' << label); } void Adaptation::Config::Finalize(bool enabled) { Enabled = enabled; debugs(93, DBG_IMPORTANT, "Adaptation support is " << (Enabled ? "on" : "off.")); FinalizeEach(AllServices(), "message adaptation services"); FinalizeEach(AllGroups(), "message adaptation service groups"); FinalizeEach(AllRules(), "message adaptation access rules"); } void -Adaptation::Config::ParseMetaHeader(ConfigParser &parser) -{ - String name, value; - const char *warnFor[] = { - "Methods", - "Service", - "ISTag", - "Encapsulated", - "Opt-body-type", - "Max-Connections", - "Options-TTL", - "Date", - "Service-ID", - "Allow", - "Preview", - "Transfer-Preview", - "Transfer-Ignore", - "Transfer-Complete", - NULL - }; - ConfigParser::ParseString(&name); - ConfigParser::ParseQuotedString(&value); - - // TODO: Find a way to move this check to ICAP - for (int i = 0; warnFor[i] != NULL; ++i) { - if (name.caseCmp(warnFor[i]) == 0) { - fatalf("%s:%d: meta name \"%s\" is a reserved ICAP header name", - cfg_filename, config_lineno, name.termedBuf()); - } - } - - MetaHeader::Pointer meta = addMetaHeader(name); - MetaHeader::Value::Pointer headValue = meta->addValue(value); - aclParseAclList(parser, &headValue->aclList); -} - -void -Adaptation::Config::DumpMetaHeader(StoreEntry *entry, const char *name) -{ - typedef MetaHeaders::iterator AMLI; - for (AMLI m = metaHeaders.begin(); m != metaHeaders.end(); ++m) { - typedef MetaHeader::Values::iterator VLI; - for (VLI v =(*m)->values.begin(); v != (*m)->values.end(); ++v ) { - storeAppendPrintf(entry, "%s " SQUIDSTRINGPH " %s", - name, SQUIDSTRINGPRINT((*m)->name), ConfigParser::QuoteString((*v)->value)); - dump_acl_list(entry, (*v)->aclList); - storeAppendPrintf(entry, "\n"); - } - } -} - -void -Adaptation::Config::FreeMetaHeader() -{ - metaHeaders.clean(); -} - -void Adaptation::Config::ParseServiceSet() { Adaptation::Config::ParseServiceGroup(new ServiceSet); } void Adaptation::Config::ParseServiceChain() { Adaptation::Config::ParseServiceGroup(new ServiceChain); } void Adaptation::Config::ParseServiceGroup(ServiceGroupPointer g) { assert(g != NULL); g->parse(); AllGroups().push_back(g); } void === modified file 'src/adaptation/Config.h' --- src/adaptation/Config.h 2012-08-14 11:53:07 +0000 +++ src/adaptation/Config.h 2012-10-21 21:39:04 +0000 @@ -1,119 +1,71 @@ #ifndef SQUID_ADAPTATION__CONFIG_H #define SQUID_ADAPTATION__CONFIG_H #include "event.h" #include "acl/Gadgets.h" #include "base/AsyncCall.h" #include "adaptation/forward.h" #include "adaptation/Elements.h" +#include "Notes.h" #include "SquidString.h" class acl_access; class ConfigParser; class HttpRequest; class HttpReply; namespace Adaptation { class Config { public: static void Finalize(bool enable); static void ParseServiceSet(void); static void ParseServiceChain(void); - static void ParseMetaHeader(ConfigParser &parser); - static void FreeMetaHeader(); - static void DumpMetaHeader(StoreEntry *, const char *); static void ParseAccess(ConfigParser &parser); static void FreeAccess(void); static void DumpAccess(StoreEntry *, const char *); friend class AccessCheck; public: static bool Enabled; // true if at least one adaptation mechanism is // these are global squid.conf options, documented elsewhere static char *masterx_shared_name; // global TODO: do we need TheConfig? static int service_iteration_limit; static int send_client_ip; static int send_username; static int use_indirect_client; // Options below are accessed via Icap::TheConfig or Ecap::TheConfig // TODO: move ICAP-specific options to Icap::Config and add TheConfig int onoff; int service_failure_limit; time_t oldest_service_failure; int service_revival_delay; - /** - * Used to store meta headers. The meta headers are custom - * ICAP request headers or ECAP options used to pass custom - * transaction-state related meta information to a service. - */ - class MetaHeader: public RefCountable - { - public: - typedef RefCount Pointer; - /// Stores a value for the meta header. - class Value: public RefCountable - { - public: - typedef RefCount Pointer; - String value; ///< a header value - ACLList *aclList; ///< The access list used to determine if this value is valid for a request - explicit Value(const String &aVal) : value(aVal), aclList(NULL) {} - ~Value(); - }; - typedef Vector Values; - - explicit MetaHeader(const String &aName): name(aName) {} - - /** - * Adds a value to the meta header and returns a pointer to the - * related Value object. - */ - Value::Pointer addValue(const String &value); - - /** - * Walks through the possible values list of the meta and selects - * the first value which matches the given HttpRequest and HttpReply - * or NULL if none matches. - */ - const char *match(HttpRequest *request, HttpReply *reply); - String name; ///< The meta header name - Values values; ///< The possible values list for the meta header - }; - typedef Vector MetaHeaders; - static MetaHeaders metaHeaders; ///< The list of configured meta headers - - /** - * Adds a header to the meta headers list and returns a pointer to the - * related metaHeaders object. If the header name already exists in list, - * returns a pointer to the existing object. - */ - static MetaHeader::Pointer addMetaHeader(const String &header); + static Notes metaHeaders; ///< The list of configured meta headers typedef Vector ServiceConfigs; ServiceConfigs serviceConfigs; Config(); virtual ~Config(); void parseService(void); void freeService(void); void dumpService(StoreEntry *, const char *) const; ServicePointer findService(const String&); /** * Creates and starts the adaptation services. In the case the adaptation * mechanism is disabled then removes any reference to the services from * access rules and service groups, and returns false. * \return true if the services are ready and running, false otherwise */ virtual bool finalize(); === modified file 'src/adaptation/History.h' --- src/adaptation/History.h 2012-08-28 13:00:30 +0000 +++ src/adaptation/History.h 2012-10-22 09:05:24 +0000 @@ -1,26 +1,27 @@ #ifndef SQUID_ADAPT_HISTORY_H #define SQUID_ADAPT_HISTORY_H #include "adaptation/DynamicGroupCfg.h" #include "Array.h" #include "HttpHeader.h" +#include "Notes.h" #include "RefCount.h" #include "SquidString.h" namespace Adaptation { /// collects information about adaptations related to a master transaction class History: public RefCountable { public: typedef RefCount Pointer; History(); /// record the start of a xact, return xact history ID int recordXactStart(const String &serviceId, const timeval &when, bool retrying); /// record the end of a xact identified by its history ID void recordXactFinish(int hid); @@ -33,40 +34,43 @@ /// sets or resets a cross-transactional database record void updateXxRecord(const char *name, const String &value); /// returns true and fills the record fields iff there is a db record bool getXxRecord(String &name, String &value) const; /// sets or resets next services for the Adaptation::Iterator to notice void updateNextServices(const String &services); /// returns true, fills the value, and resets iff next services were set bool extractNextServices(String &value); /// store the last meta header fields received from the adaptation service void recordMeta(const HttpHeader *lm); public: /// Last received meta header (REQMOD or RESPMOD, whichever comes last). HttpHeader lastMeta; /// All REQMOD and RESPMOD meta headers merged. Last field wins conflicts. HttpHeader allMeta; + /// key:value pairs set by adaptation_meta, to be added to + /// AccessLogEntry::notes when ALE becomes available + NotePairs metaHeaders; /// sets future services for the Adaptation::AccessCheck to notice void setFutureServices(const DynamicGroupCfg &services); /// returns true, fills the value, and resets iff future services were set bool extractFutureServices(DynamicGroupCfg &services); private: /// single Xaction stats (i.e., a historical record entry) class Entry { public: Entry(const String &serviceId, const timeval &when); Entry(); // required by Vector<> void stop(); ///< updates stats on transaction end int rptm(); ///< returns response time [msec], calculates it if needed String service; ///< adaptation service ID timeval start; ///< when the xaction was started === modified file 'src/adaptation/ecap/XactionRep.cc' --- src/adaptation/ecap/XactionRep.cc 2012-08-28 13:00:30 +0000 +++ src/adaptation/ecap/XactionRep.cc 2012-10-22 09:08:40 +0000 @@ -160,88 +160,98 @@ if (name.known()) { // must check to avoid empty names matching unset cfg Adaptation::History::Pointer ah = request->adaptHistory(false); if (ah != NULL) { String name, value; if (ah->getXxRecord(name, value)) return libecap::Area::FromTempBuffer(value.rawBuf(), value.size()); } } return libecap::Area(); } const libecap::Area Adaptation::Ecap::XactionRep::metaValue(const libecap::Name &name) const { HttpRequest *request = dynamic_cast(theCauseRep ? theCauseRep->raw().header : theVirginRep.raw().header); Must(request); HttpReply *reply = dynamic_cast(theVirginRep.raw().header); if (name.known()) { // must check to avoid empty names matching unset cfg - typedef Adaptation::Config::MetaHeaders::iterator ACAMLI; + typedef Notes::iterator ACAMLI; for (ACAMLI i = Adaptation::Config::metaHeaders.begin(); i != Adaptation::Config::metaHeaders.end(); ++i) { - if (name == (*i)->name.termedBuf()) { + if (name == (*i)->key.termedBuf()) { if (const char *value = (*i)->match(request, reply)) return libecap::Area::FromTempString(value); else return libecap::Area(); } } } return libecap::Area(); } void Adaptation::Ecap::XactionRep::visitEachMetaHeader(libecap::NamedValueVisitor &visitor) const { HttpRequest *request = dynamic_cast(theCauseRep ? theCauseRep->raw().header : theVirginRep.raw().header); Must(request); HttpReply *reply = dynamic_cast(theVirginRep.raw().header); - typedef Adaptation::Config::MetaHeaders::iterator ACAMLI; + typedef Notes::iterator ACAMLI; for (ACAMLI i = Adaptation::Config::metaHeaders.begin(); i != Adaptation::Config::metaHeaders.end(); ++i) { const char *v = (*i)->match(request, reply); if (v) { - const libecap::Name name((*i)->name.termedBuf()); + const libecap::Name name((*i)->key.termedBuf()); const libecap::Area value = libecap::Area::FromTempString(v); visitor.visit(name, value); } } } void Adaptation::Ecap::XactionRep::start() { Must(theMaster); if (!theVirginRep.raw().body_pipe) makingVb = opNever; // there is nothing to deliver - const HttpRequest *request = dynamic_cast (theCauseRep ? + HttpRequest *request = dynamic_cast (theCauseRep ? theCauseRep->raw().header : theVirginRep.raw().header); Must(request); + + HttpReply *reply = dynamic_cast(theVirginRep.raw().header); + Adaptation::History::Pointer ah = request->adaptLogHistory(); if (ah != NULL) { // retrying=false because ecap never retries transactions adaptHistoryId = ah->recordXactStart(service().cfg().key, current_time, false); + typedef Notes::iterator ACAMLI; + for (ACAMLI i = Adaptation::Config::metaHeaders.begin(); i != Adaptation::Config::metaHeaders.end(); ++i) { + const char *v = (*i)->match(request, reply); + if (v && !ah->metaHeaders.hasByNameListMember((*i)->key.termedBuf(), v, ',')) { + ah->metaHeaders.addEntry(new HttpHeaderEntry(HDR_OTHER, (*i)->key.termedBuf(), v)); + } + } } theMaster->start(); } void Adaptation::Ecap::XactionRep::swanSong() { // clear body_pipes, if any // this code does not maintain proxying* and canAccessVb states; should it? if (theAnswerRep != NULL) { BodyPipe::Pointer body_pipe = answer().body_pipe; if (body_pipe != NULL) { Must(body_pipe->stillProducing(this)); stopProducingFor(body_pipe, false); } } BodyPipe::Pointer &body_pipe = theVirginRep.raw().body_pipe; === modified file 'src/adaptation/icap/ModXact.cc' --- src/adaptation/icap/ModXact.cc 2012-08-31 16:57:39 +0000 +++ src/adaptation/icap/ModXact.cc 2012-10-21 16:50:14 +0000 @@ -1403,50 +1403,54 @@ } makeAllowHeader(buf); if (TheConfig.send_client_ip && request) { Ip::Address client_addr; #if FOLLOW_X_FORWARDED_FOR if (TheConfig.use_indirect_client) { client_addr = request->indirect_client_addr; } else #endif client_addr = request->client_addr; if (!client_addr.IsAnyAddr() && !client_addr.IsNoAddr()) buf.Printf("X-Client-IP: %s\r\n", client_addr.NtoA(ntoabuf,MAX_IPSTRLEN)); } if (TheConfig.send_username && request) makeUsernameHeader(request, buf); // Adaptation::Config::metaHeaders - typedef Adaptation::Config::MetaHeaders::iterator ACAMLI; + typedef Notes::iterator ACAMLI; for (ACAMLI i = Adaptation::Config::metaHeaders.begin(); i != Adaptation::Config::metaHeaders.end(); ++i) { HttpRequest *r = virgin.cause ? virgin.cause : dynamic_cast(virgin.header); Must(r); HttpReply *reply = dynamic_cast(virgin.header); - if (const char *value = (*i)->match(r, reply)) - buf.Printf("%s: %s\r\n", (*i)->name.termedBuf(), value); + if (const char *value = (*i)->match(r, reply)) { + buf.Printf("%s: %s\r\n", (*i)->key.termedBuf(), value); + Adaptation::History::Pointer ah = request->adaptHistory(false); + if (ah != NULL && !ah->metaHeaders.hasByNameListMember((*i)->key.termedBuf(), value, ',')) + ah->metaHeaders.addEntry(new HttpHeaderEntry(HDR_OTHER, (*i)->key.termedBuf(), value)); + } } // fprintf(stderr, "%s\n", buf.content()); buf.append(ICAP::crlf, 2); // terminate ICAP header // fill icapRequest for logging Must(icapRequest->parseCharBuf(buf.content(), buf.contentSize())); // start ICAP request body with encapsulated HTTP headers buf.append(httpBuf.content(), httpBuf.contentSize()); httpBuf.clean(); } // decides which Allow values to write and updates the request buffer void Adaptation::Icap::ModXact::makeAllowHeader(MemBuf &buf) { const bool allow204in = preview.enabled(); // TODO: add shouldAllow204in() const bool allow204out = state.allowedPostview204 = shouldAllow204(); === modified file 'src/cache_cf.cc' --- src/cache_cf.cc 2012-10-20 08:01:32 +0000 +++ src/cache_cf.cc 2012-10-21 14:36:37 +0000 @@ -117,43 +117,40 @@ #include #endif #if HAVE_PWD_H #include #endif #if HAVE_GRP_H #include #endif #if HAVE_SYS_STAT_H #include #endif #if USE_SSL #include "ssl/gadgets.h" #endif #if USE_ADAPTATION static void parse_adaptation_service_set_type(); static void parse_adaptation_service_chain_type(); static void parse_adaptation_access_type(); -static void parse_adaptation_meta_type(Adaptation::Config::MetaHeaders *); -static void dump_adaptation_meta_type(StoreEntry *, const char *, Adaptation::Config::MetaHeaders &); -static void free_adaptation_meta_type(Adaptation::Config::MetaHeaders *); #endif #if ICAP_CLIENT static void parse_icap_service_type(Adaptation::Icap::Config *); static void dump_icap_service_type(StoreEntry *, const char *, const Adaptation::Icap::Config &); static void free_icap_service_type(Adaptation::Icap::Config *); static void parse_icap_class_type(); static void parse_icap_access_type(); static void parse_icap_service_failure_limit(Adaptation::Icap::Config *); static void dump_icap_service_failure_limit(StoreEntry *, const char *, const Adaptation::Icap::Config &); static void free_icap_service_failure_limit(Adaptation::Icap::Config *); #endif #if USE_ECAP static void parse_ecap_service_type(Adaptation::Ecap::Config *); static void dump_ecap_service_type(StoreEntry *, const char *, const Adaptation::Ecap::Config &); static void free_ecap_service_type(Adaptation::Ecap::Config *); #endif @@ -202,40 +199,43 @@ #endif #if !USE_DNSHELPER static void parseBytesLineSigned(ssize_t * bptr, const char *units); #endif static size_t parseBytesUnits(const char *unit); static void free_all(void); void requirePathnameExists(const char *name, const char *path); static OBJH dump_config; #if USE_HTTP_VIOLATIONS static void free_HeaderManglers(HeaderManglers **pm); static void dump_http_header_access(StoreEntry * entry, const char *name, const HeaderManglers *manglers); static void parse_http_header_access(HeaderManglers **manglers); #define free_http_header_access free_HeaderManglers static void dump_http_header_replace(StoreEntry * entry, const char *name, const HeaderManglers *manglers); static void parse_http_header_replace(HeaderManglers **manglers); #define free_http_header_replace free_HeaderManglers #endif static void dump_HeaderWithAclList(StoreEntry * entry, const char *name, HeaderWithAclList *headers); static void parse_HeaderWithAclList(HeaderWithAclList **header); static void free_HeaderWithAclList(HeaderWithAclList **header); +static void parse_note(Notes *); +static void dump_note(StoreEntry *, const char *, Notes &); +static void free_note(Notes *); static void parse_denyinfo(AclDenyInfoList ** var); static void dump_denyinfo(StoreEntry * entry, const char *name, AclDenyInfoList * var); static void free_denyinfo(AclDenyInfoList ** var); #if USE_WCCPv2 static void parse_IpAddress_list(Ip::Address_list **); static void dump_IpAddress_list(StoreEntry *, const char *, const Ip::Address_list *); static void free_IpAddress_list(Ip::Address_list **); #if CURRENTLY_UNUSED static int check_null_IpAddress_list(const Ip::Address_list *); #endif /* CURRENTLY_UNUSED */ #endif /* USE_WCCPv2 */ static void parsePortCfg(AnyP::PortCfg **, const char *protocol); #define parse_PortCfg(l) parsePortCfg((l), token) static void dump_PortCfg(StoreEntry *, const char *, const AnyP::PortCfg *); static void free_PortCfg(AnyP::PortCfg **); #if USE_SSL static void parse_sslproxy_cert_sign(sslproxy_cert_sign **cert_sign); @@ -4195,58 +4195,40 @@ #if USE_ADAPTATION static void parse_adaptation_service_set_type() { Adaptation::Config::ParseServiceSet(); } static void parse_adaptation_service_chain_type() { Adaptation::Config::ParseServiceChain(); } static void parse_adaptation_access_type() { Adaptation::Config::ParseAccess(LegacyParser); } - -static void -parse_adaptation_meta_type(Adaptation::Config::MetaHeaders *) -{ - Adaptation::Config::ParseMetaHeader(LegacyParser); -} - -static void -dump_adaptation_meta_type(StoreEntry *entry, const char *name, Adaptation::Config::MetaHeaders &) -{ - Adaptation::Config::DumpMetaHeader(entry, name); -} - -static void -free_adaptation_meta_type(Adaptation::Config::MetaHeaders *) -{ - // Nothing to do, it is released inside Adaptation::Config::freeService() -} #endif /* USE_ADAPTATION */ #if ICAP_CLIENT static void parse_icap_service_type(Adaptation::Icap::Config * cfg) { cfg->parseService(); } static void free_icap_service_type(Adaptation::Icap::Config * cfg) { cfg->freeService(); } static void dump_icap_service_type(StoreEntry * entry, const char *name, const Adaptation::Icap::Config &cfg) { cfg.dumpService(entry, name); @@ -4644,20 +4626,36 @@ (*headers)->push_back(hwa); } static void free_HeaderWithAclList(HeaderWithAclList **header) { if (!(*header)) return; for (HeaderWithAclList::iterator hwa = (*header)->begin(); hwa != (*header)->end(); ++hwa) { if (hwa->aclList) aclDestroyAclList(&hwa->aclList); if (hwa->valueFormat) { delete hwa->valueFormat; hwa->valueFormat = NULL; } } delete *header; *header = NULL; } + +static void parse_note(Notes *notes) +{ + assert(notes); + notes->parse(LegacyParser); +} + +static void dump_note(StoreEntry *entry, const char *name, Notes ¬es) +{ + notes.dump(entry, name); +} + +static void free_note(Notes *notes) +{ + notes->clean(); +} === modified file 'src/cf.data.depend' --- src/cf.data.depend 2012-07-18 16:21:47 +0000 +++ src/cf.data.depend 2012-10-21 14:16:54 +0000 @@ -18,52 +18,52 @@ debug delay_pool_access acl delay_class delay_pool_class delay_pools delay_pool_count delay_pool_rates delay_class client_delay_pool_access acl client_delay_pool_count client_delay_pool_rates denyinfo acl eol externalAclHelper auth_param HelperChildConfig hostdomain cache_peer hostdomaintype cache_peer http_header_access acl http_header_replace HeaderWithAclList acl adaptation_access_type adaptation_service_set adaptation_service_chain acl icap_service icap_class adaptation_service_set_type icap_service ecap_service adaptation_service_chain_type icap_service ecap_service -adaptation_meta_type acl icap_access_type icap_class acl icap_class_type icap_service icap_service_type icap_service_failure_limit ecap_service_type int kb_int64_t kb_size_t logformat YesNoNone memcachemode +note acl obsolete onoff peer peer_access cache_peer acl PortCfg QosConfig refreshpattern removalpolicy size_t IpAddress_list string string time_msec time_t tristate uri_whitespace u_short wccp2_method wccp2_amethod wccp2_service === modified file 'src/cf.data.pre' --- src/cf.data.pre 2012-10-20 08:01:32 +0000 +++ src/cf.data.pre 2012-10-22 09:32:01 +0000 @@ -3256,40 +3256,44 @@ [ output in squid text log format as used by log_mime_hdrs # output in URL quoted format ' output as-is - left aligned width minimum and/or maximum field width: [width_min][.width_max] When minimum starts with 0, the field is zero-padded. String values exceeding maximum width are truncated. {arg} argument such as header name etc Format codes: % a literal % character sn Unique sequence number per log line entry err_code The ID of an error response served by Squid or a similar internal error identifier. err_detail Additional err_code-dependent error information. + note The meta header specified by the argument. Also + logs the adaptation meta headers set by the + adaptation_meta configuration parameter. + If no argument given all meta headers logged. Connection related format codes: >a Client source IP address >A Client FQDN >p Client source port >eui Client source EUI (MAC address, EUI-48 or EUI-64 identifier) >la Local IP address the client connected to >lp Local port number the client connected to la Local listening IP address the client connection was connected to. lp Local listening port number the client connection was connected to. headers.adapted_request = xstrdup(mb.buf); // the virgin request is saved to aLogEntry->request if (aLogEntry->request) { packerClean(&p); mb.reset(); packerToMemInit(&p, &mb); aLogEntry->request->header.packInto(&p); aLogEntry->headers.request = xstrdup(mb.buf); } #if USE_ADAPTATION const Adaptation::History::Pointer ah = request->adaptLogHistory(); if (ah != NULL) { packerClean(&p); mb.reset(); packerToMemInit(&p, &mb); ah->lastMeta.packInto(&p); aLogEntry->adapt.last_meta = xstrdup(mb.buf); + aLogEntry->notes.append(&ah->metaHeaders); } #endif packerClean(&p); mb.clean(); } #if ICAP_CLIENT const Adaptation::Icap::History::Pointer ih = request->icapHistory(); if (ih != NULL) aLogEntry->icap.processingTime = ih->processingTime(); #endif aLogEntry->http.method = request->method; aLogEntry->http.version = request->http_ver; aLogEntry->hier = request->hier; if (request->content_length > 0) // negative when no body or unknown length aLogEntry->cache.requestSize += request->content_length; aLogEntry->cache.extuser = request->extacl_user.termedBuf(); @@ -676,40 +677,49 @@ al->cache.code = logType; al->cache.msec = tvSubMsec(start_time, current_time); if (request) prepareLogWithRequestDetails(request, al); if (getConn() != NULL && getConn()->clientConnection != NULL && getConn()->clientConnection->rfc931[0]) al->cache.rfc931 = getConn()->clientConnection->rfc931; #if USE_SSL && 0 /* This is broken. Fails if the connection has been closed. Needs * to snarf the ssl details some place earlier.. */ if (getConn() != NULL) al->cache.ssluser = sslGetUserEmail(fd_table[getConn()->fd].ssl); #endif + /*Add meta headers*/ + typedef Notes::iterator ACAMLI; + for (ACAMLI i = Config.notes.begin(); i != Config.notes.end(); ++i) { + if (const char *value = (*i)->match(request, al->reply)) { + al->notes.addEntry(new HttpHeaderEntry(HDR_OTHER, (*i)->key.termedBuf(), value)); + debugs(33, 3, HERE << (*i)->key.termedBuf() << " " << value); + } + } + ACLFilledChecklist *checklist = clientAclChecklistCreate(Config.accessList.log, this); if (al->reply) checklist->reply = HTTPMSGLOCK(al->reply); if (!Config.accessList.log || checklist->fastCheck() == ACCESS_ALLOWED) { if (request) al->adapted_request = HTTPMSGLOCK(request); accessLogLog(al, checklist); updateCounters(); if (getConn() != NULL && getConn()->clientConnection != NULL) clientdbUpdate(getConn()->clientConnection->remote, logType, AnyP::PROTO_HTTP, out.size); } delete checklist; } void ClientHttpRequest::freeResources() === modified file 'src/format/ByteCode.h' --- src/format/ByteCode.h 2012-07-18 16:21:47 +0000 +++ src/format/ByteCode.h 2012-10-22 09:36:16 +0000 @@ -179,37 +179,38 @@ LFT_ICAP_REQ_HEADER, LFT_ICAP_REQ_HEADER_ELEM, LFT_ICAP_REQ_ALL_HEADERS, LFT_ICAP_REP_HEADER, LFT_ICAP_REP_HEADER_ELEM, LFT_ICAP_REP_ALL_HEADERS, LFT_ICAP_TR_RESPONSE_TIME, LFT_ICAP_IO_TIME, LFT_ICAP_OUTCOME, LFT_ICAP_STATUS_CODE, #endif #if USE_SSL LFT_SSL_BUMP_MODE, LFT_SSL_USER_CERT_SUBJECT, LFT_SSL_USER_CERT_ISSUER, #endif + LFT_NOTE, LFT_PERCENT /* special string cases for escaped chars */ } ByteCode_t; /// Quoting style for a format output. enum Quoting { LOG_QUOTE_NONE = 0, LOG_QUOTE_QUOTES, LOG_QUOTE_MIMEBLOB, LOG_QUOTE_URL, LOG_QUOTE_RAW }; extern const char *log_tags[]; } // namespace Format #endif /* _SQUID_FMT_BYTECODE_H */ === modified file 'src/format/Format.cc' --- src/format/Format.cc 2012-09-19 17:16:56 +0000 +++ src/format/Format.cc 2012-10-22 09:36:03 +0000 @@ -1023,40 +1023,57 @@ } case LFT_SSL_USER_CERT_SUBJECT: if (X509 *cert = al->cache.sslClientCert.get()) { if (X509_NAME *subject = X509_get_subject_name(cert)) { X509_NAME_oneline(subject, tmp, sizeof(tmp)); out = tmp; } } break; case LFT_SSL_USER_CERT_ISSUER: if (X509 *cert = al->cache.sslClientCert.get()) { if (X509_NAME *issuer = X509_get_issuer_name(cert)) { X509_NAME_oneline(issuer, tmp, sizeof(tmp)); out = tmp; } } break; #endif + case LFT_NOTE: + if (fmt->data.string) { + sb = al->notes.getByName(fmt->data.string); + out = sb.termedBuf(); + quote = 1; + } else { + HttpHeaderPos pos = HttpHeaderInitPos; + while (const HttpHeaderEntry *e = al->notes.getEntry(&pos)) { + sb.append(e->name); + sb.append(": "); + sb.append(e->value); + sb.append("\r\n"); + } + out = sb.termedBuf(); + quote = 1; + } + break; case LFT_PERCENT: out = "%"; break; } if (dooff) { snprintf(tmp, sizeof(tmp), "%0*" PRId64, fmt->zero && fmt->widthMin >= 0 ? fmt->widthMin : 0, outoff); out = tmp; } else if (doint) { snprintf(tmp, sizeof(tmp), "%0*ld", fmt->zero && fmt->widthMin >= 0 ? fmt->widthMin : 0, outint); out = tmp; } if (out && *out) { if (quote || fmt->quote != LOG_QUOTE_NONE) { char *newout = NULL; int newfree = 0; === modified file 'src/format/Token.cc' --- src/format/Token.cc 2012-10-07 05:00:02 +0000 +++ src/format/Token.cc 2012-10-22 09:36:03 +0000 @@ -133,40 +133,41 @@ {"2 byte tokens static TokenTableEntry TokenTableMisc[] = { {">eui", LFT_CLIENT_EUI}, {"err_code", LFT_SQUID_ERROR }, {"err_detail", LFT_SQUID_ERROR_DETAIL }, + {"note", LFT_NOTE }, {NULL, LFT_NONE} /* this must be last */ }; #if USE_ADAPTATION static TokenTableEntry TokenTableAdapt[] = { {"all_trs", LFT_ADAPTATION_ALL_XACT_TIMES}, {"sum_trs", LFT_ADAPTATION_SUM_XACT_TIMES}, {"next) { if (log->type == Log::Format::CLF_NONE) continue; log->logfile = logfileOpen(log->filename, MAX_URL << 2, 1); LogfileStatus = LOG_ENABLE; #if USE_ADAPTATION for (Format::Token * curr_token = (log->logFormat?log->logFormat->format:NULL); curr_token; curr_token = curr_token->next) { if (curr_token->type == Format::LFT_ADAPTATION_SUM_XACT_TIMES || curr_token->type == Format::LFT_ADAPTATION_ALL_XACT_TIMES || curr_token->type == Format::LFT_ADAPTATION_LAST_HEADER || curr_token->type == Format::LFT_ADAPTATION_LAST_HEADER_ELEM || - curr_token->type == Format::LFT_ADAPTATION_LAST_ALL_HEADERS) { + curr_token->type == Format::LFT_ADAPTATION_LAST_ALL_HEADERS|| + (curr_token->type == Format::LFT_NOTE && !Adaptation::Config::metaHeaders.empty())) { Log::TheConfig.hasAdaptToken = true; } #if ICAP_CLIENT if (curr_token->type == Format::LFT_ICAP_TOTAL_TIME) { Log::TheConfig.hasIcapToken = true; } #endif } #endif } #if HEADERS_LOG headerslog = logfileOpen("/usr/local/squid/logs/headers.log", 512); assert(NULL != headerslog); #endif #if MULTICAST_MISS_STREAM === modified file 'src/tests/stub_cache_cf.cc' --- src/tests/stub_cache_cf.cc 2012-09-17 15:12:01 +0000 +++ src/tests/stub_cache_cf.cc 2012-10-21 14:35:35 +0000 @@ -31,22 +31,24 @@ */ #include "squid.h" #include "acl/Acl.h" #include "ConfigParser.h" #include "wordlist.h" #include "YesNoNone.h" #define STUB_API "cache_cf.cc" #include "tests/STUB.h" void self_destruct(void) STUB void parse_int(int *var) STUB void parse_onoff(int *var) STUB void parse_eol(char *volatile *var) STUB void parse_wordlist(wordlist ** list) STUB void requirePathnameExists(const char *name, const char *path) STUB_NOP void parse_time_t(time_t * var) STUB char * strtokFile(void) STUB_RETVAL(NULL) void ConfigParser::ParseUShort(unsigned short *var) STUB +void ConfigParser::ParseString(String*) STUB void dump_acl_access(StoreEntry * entry, const char *name, acl_access * head) STUB +void dump_acl_list(StoreEntry*, ACLList*) STUB YesNoNone::operator void*() const { STUB_NOP; return NULL; } === modified file 'src/tests/testHttpReply.cc' --- src/tests/testHttpReply.cc 2012-09-04 09:10:20 +0000 +++ src/tests/testHttpReply.cc 2012-10-21 14:35:35 +0000 @@ -6,46 +6,40 @@ #include "HttpHeader.h" #include "HttpReply.h" #include "Mem.h" #include "mime_header.h" #include "SquidConfig.h" CPPUNIT_TEST_SUITE_REGISTRATION( testHttpReply ); class SquidConfig Config; /* stub functions to link successfully */ #include "MemObject.h" int64_t MemObject::endOffset() const { return 0; } #include "ConfigParser.h" -void -ConfigParser::destruct() -{ -// CALLED as shutdown no-op -// fatal("ConfigParser::destruct. Not implemented."); -} void eventAdd(const char *name, EVH * func, void *arg, double when, int, bool cbdata) { // CALLED as setUp no-op // fatal("eventAdd. Not implemented."); } /* end */ void testHttpReply::setUp() { Mem::Init(); httpHeaderInitModule(); } void testHttpReply::testSanityCheckFirstLine() {