From 38e16f927fb0ac854e8a6bfec90f49af5ef1f6eb Mon Sep 17 00:00:00 2001 From: Amos Jeffries Date: Wed, 3 Aug 2011 21:21:06 -0600 Subject: [PATCH] SourceLayout: format namespace for custom tag-based formats Part 1 of enabling non-logging components to support custom formats in strings Shuffle the log custom format code into its own library separate from the logging functionality. One minor logic change removing redundant LogFileEnabled flag. TODO: - use MemBuf instead or as well as StoreEntry as the output buffer - separate from AccessLogEntry confusion - upgrade deny_info URL generation format - upgrade external_acl_type format - add custom helper formats --- configure.ac | 1 + doc/debug-sections.txt | 1 - src/AccessLogEntry.h | 4 - src/HttpRequest.cc | 8 +- src/HttpRequest.h | 9 - src/Makefile.am | 12 +- src/adaptation/History.cc | 1 - src/cache_cf.cc | 7 +- src/client_db.cc | 6 +- src/client_side_reply.cc | 4 +- src/client_side_request.cc | 4 +- src/format/Format.cc | 1067 +++++++++++++++++++++ src/format/Format.h | 51 + src/format/Makefile.am | 13 + src/{log/Gadgets.cc => format/Quoting.cc} | 6 +- src/{log/Gadgets.h => format/Quoting.h} | 14 +- src/format/Tokens.cc | 463 +++++++++ src/{log => format}/Tokens.h | 115 +-- src/helper.cc | 6 +- src/log/Config.cc | 7 +- src/log/Config.h | 14 +- src/log/FormatHttpdCombined.cc | 14 +- src/log/FormatHttpdCommon.cc | 14 +- src/log/FormatSquidCustom.cc | 838 +--------------- src/log/FormatSquidIcap.cc | 10 +- src/log/FormatSquidNative.cc | 18 +- src/log/Makefile.am | 6 +- src/log/Tokens.cc | 734 -------------- src/log/access_log.cc | 26 +- src/stat.cc | 4 +- src/store_log.cc | 2 +- src/structs.h | 4 +- 32 files changed, 1732 insertions(+), 1751 deletions(-) create mode 100644 src/format/Format.cc create mode 100644 src/format/Format.h create mode 100644 src/format/Makefile.am rename src/{log/Gadgets.cc => format/Quoting.cc} (97%) rename src/{log/Gadgets.h => format/Quoting.h} (50%) create mode 100644 src/format/Tokens.cc rename src/{log => format}/Tokens.h (55%) delete mode 100644 src/log/Tokens.cc diff --git a/configure.ac b/configure.ac index 5babed5700..39b0054eee 100644 --- a/configure.ac +++ b/configure.ac @@ -3420,6 +3420,7 @@ AC_CONFIG_FILES([\ src/comm/Makefile \ src/esi/Makefile \ src/eui/Makefile \ + src/format/Makefile \ src/icmp/Makefile \ src/ident/Makefile \ src/ip/Makefile \ diff --git a/doc/debug-sections.txt b/doc/debug-sections.txt index 0fc9d5f877..1166c0d594 100644 --- a/doc/debug-sections.txt +++ b/doc/debug-sections.txt @@ -85,7 +85,6 @@ section 46 Access Log - Squid ICAP Logging section 46 Access Log - Squid format section 46 Access Log - Squid referer format section 46 Access Log - Squid useragent format -section 46 Access Log Format Tokens section 47 Store COSS Directory Routines section 47 Store Directory Routines section 48 Persistent Connections diff --git a/src/AccessLogEntry.h b/src/AccessLogEntry.h index 84995c0391..d15604f2af 100644 --- a/src/AccessLogEntry.h +++ b/src/AccessLogEntry.h @@ -239,7 +239,6 @@ public: class ACLChecklist; class StoreEntry; -class logformat_token; /* Should be in 'AccessLog.h' as the driver */ extern void accessLogLogTo(customlog* log, AccessLogEntry* al, ACLChecklist* checklist = NULL); @@ -249,8 +248,5 @@ extern void accessLogClose(void); extern void accessLogInit(void); extern void accessLogFreeMemory(AccessLogEntry * aLogEntry); extern const char *accessLogTime(time_t); -extern int accessLogParseLogFormat(logformat_token ** fmt, char *def); -extern void accessLogDumpLogFormat(StoreEntry * entry, const char *name, logformat * definitions); -extern void accessLogFreeLogFormat(logformat_token ** fmt); #endif /* SQUID_HTTPACCESSLOGENTRY_H */ diff --git a/src/HttpRequest.cc b/src/HttpRequest.cc index 6fb9f410c6..3448d47b98 100644 --- a/src/HttpRequest.cc +++ b/src/HttpRequest.cc @@ -41,6 +41,7 @@ #include "auth/UserRequest.h" #endif #include "HttpHeaderRange.h" +#include "log/Config.h" #include "MemBuf.h" #include "Store.h" #if ICAP_CLIENT @@ -438,8 +439,7 @@ Adaptation::Icap::History::Pointer HttpRequest::icapHistory() const { if (!icapHistory_) { - if ((LogfileStatus == LOG_ENABLE && alLogformatHasIcapToken) || - IcapLogfileStatus == LOG_ENABLE) { + if (Log::TheConfig.hasIcapToken || IcapLogfileStatus == LOG_ENABLE) { icapHistory_ = new Adaptation::Icap::History(); debugs(93,4, HERE << "made " << icapHistory_ << " for " << this); } @@ -464,9 +464,7 @@ HttpRequest::adaptHistory(bool createIfNone) const Adaptation::History::Pointer HttpRequest::adaptLogHistory() const { - const bool loggingNeedsHistory = (LogfileStatus == LOG_ENABLE) && - alLogformatHasAdaptToken; // TODO: make global to remove this method? - return HttpRequest::adaptHistory(loggingNeedsHistory); + return HttpRequest::adaptHistory(Log::TheConfig.hasAdaptToken); } void diff --git a/src/HttpRequest.h b/src/HttpRequest.h index 8d8e1afda6..3de0af7cbb 100644 --- a/src/HttpRequest.h +++ b/src/HttpRequest.h @@ -53,15 +53,6 @@ //DEAD?: extern int httpRequestHdrAllowedByName(http_hdr_type id); extern void httpRequestPack(void *obj, Packer *p); -// TODO: Move these three to access_log.h or AccessLogEntry.h -#if USE_ADAPTATION -extern bool alLogformatHasAdaptToken; -#endif -#if ICAP_CLIENT -extern bool alLogformatHasIcapToken; -#endif -extern int LogfileStatus; - class HttpHdrRange; class DnsLookupDetails; diff --git a/src/Makefile.am b/src/Makefile.am index 6c152419ed..19110eba00 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -30,8 +30,8 @@ LOADABLE_MODULES_SOURCES = \ LoadableModules.h \ LoadableModules.cc -SUBDIRS = base anyp comm eui acl fs repl -DIST_SUBDIRS = base anyp comm eui acl fs repl +SUBDIRS = base anyp comm eui acl format fs repl +DIST_SUBDIRS = base anyp comm eui acl format fs repl if ENABLE_AUTH SUBDIRS += auth @@ -559,6 +559,7 @@ squid_LDADD = \ eui/libeui.la \ icmp/libicmp.la icmp/libicmp-core.la \ log/liblog.la \ + format/libformat.la \ $(XTRA_OBJS) \ $(DISK_LINKOBJS) \ $(REPL_OBJS) \ @@ -597,6 +598,7 @@ squid_DEPENDENCIES = \ libsquid.la \ ip/libip.la \ fs/libfs.la \ + format/libformat.la \ ipc/libipc.la \ mgr/libmgr.la @@ -1358,6 +1360,7 @@ tests_testCacheManager_LDADD = \ comm/libcomm.la \ icmp/libicmp.la icmp/libicmp-core.la \ log/liblog.la \ + format/libformat.la \ $(REPL_OBJS) \ $(ADAPTATION_LIBS) \ $(ESI_LIBS) \ @@ -1674,6 +1677,7 @@ tests_testEvent_LDADD = \ icmp/libicmp.la icmp/libicmp-core.la \ comm/libcomm.la \ log/liblog.la \ + format/libformat.la \ $(REPL_OBJS) \ $(ADAPTATION_LIBS) \ $(ESI_LIBS) \ @@ -1850,6 +1854,7 @@ tests_testEventLoop_LDADD = \ icmp/libicmp.la icmp/libicmp-core.la \ comm/libcomm.la \ log/liblog.la \ + format/libformat.la \ $(REPL_OBJS) \ $(ADAPTATION_LIBS) \ $(ESI_LIBS) \ @@ -2021,6 +2026,7 @@ tests_test_http_range_LDADD = \ icmp/libicmp.la icmp/libicmp-core.la \ comm/libcomm.la \ log/liblog.la \ + format/libformat.la \ $(REPL_OBJS) \ $(ADAPTATION_LIBS) \ $(ESI_LIBS) \ @@ -2227,6 +2233,7 @@ tests_testHttpRequest_LDADD = \ icmp/libicmp.la icmp/libicmp-core.la \ comm/libcomm.la \ log/liblog.la \ + format/libformat.la \ $(REPL_OBJS) \ $(ADAPTATION_LIBS) \ $(ESI_LIBS) \ @@ -2965,6 +2972,7 @@ tests_testURL_LDADD = \ icmp/libicmp.la icmp/libicmp-core.la \ comm/libcomm.la \ log/liblog.la \ + format/libformat.la \ $(REGEXLIB) \ $(REPL_OBJS) \ $(ADAPTATION_LIBS) \ diff --git a/src/adaptation/History.cc b/src/adaptation/History.cc index dd97cda398..97ea84bf5b 100644 --- a/src/adaptation/History.cc +++ b/src/adaptation/History.cc @@ -3,7 +3,6 @@ #include "adaptation/History.h" #include "base/TextException.h" #include "globals.h" -#include "HttpRequest.h" /* for alLogformatHasAdaptToken */ #include "SquidTime.h" /// impossible services value to identify unset theNextServices diff --git a/src/cache_cf.cc b/src/cache_cf.cc index 5e680a5e0f..7aa27ef049 100644 --- a/src/cache_cf.cc +++ b/src/cache_cf.cc @@ -60,6 +60,7 @@ #if USE_SQUID_ESI #include "esi/Parser.h" #endif +#include "format/Format.h" #include "HttpRequestMethod.h" #include "ident/Config.h" #include "ip/Intercept.h" @@ -4097,10 +4098,8 @@ static void parse_access_log(customlog ** logs) { const char *filename, *logdef_name; - customlog *cl; - logformat *lf; - cl = (customlog *)xcalloc(1, sizeof(*cl)); + customlog *cl = (customlog *)xcalloc(1, sizeof(*cl)); if ((filename = strtok(NULL, w_space)) == NULL) { self_destruct(); @@ -4120,7 +4119,7 @@ parse_access_log(customlog ** logs) cl->filename = xstrdup(filename); /* look for the definition pointer corresponding to this name */ - lf = Log::TheConfig.logformats; + Format::Format *lf = Log::TheConfig.logformats; while (lf != NULL) { debugs(3, 9, "Comparing against '" << lf->name << "'"); diff --git a/src/client_db.cc b/src/client_db.cc index 6d64c8410a..dd90241e4b 100644 --- a/src/client_db.cc +++ b/src/client_db.cc @@ -34,9 +34,9 @@ #include "squid.h" #include "event.h" +#include "format/Tokens.h" #include "ClientInfo.h" #include "ip/Address.h" -#include "log/Tokens.h" #include "mgr/Registration.h" #include "SquidMath.h" #include "SquidTime.h" @@ -310,7 +310,7 @@ clientdbDump(StoreEntry * sentry) if (LOG_UDP_HIT == l) icp_hits += c->Icp.result_hist[l]; - storeAppendPrintf(sentry, " %-20.20s %7d %3d%%\n",log_tags[l], c->Icp.result_hist[l], Math::intPercent(c->Icp.result_hist[l], c->Icp.n_requests)); + storeAppendPrintf(sentry, " %-20.20s %7d %3d%%\n",Format::log_tags[l], c->Icp.result_hist[l], Math::intPercent(c->Icp.result_hist[l], c->Icp.n_requests)); } storeAppendPrintf(sentry, " HTTP Requests %d\n", c->Http.n_requests); @@ -326,7 +326,7 @@ clientdbDump(StoreEntry * sentry) storeAppendPrintf(sentry, " %-20.20s %7d %3d%%\n", - log_tags[l], + Format::log_tags[l], c->Http.result_hist[l], Math::intPercent(c->Http.result_hist[l], c->Http.n_requests)); } diff --git a/src/client_side_reply.cc b/src/client_side_reply.cc index a69864dd9e..157cf7d021 100644 --- a/src/client_side_reply.cc +++ b/src/client_side_reply.cc @@ -55,11 +55,11 @@ #endif #include "fde.h" #include "forward.h" +#include "format/Tokens.h" #include "HttpReply.h" #include "HttpRequest.h" #include "ip/QosConfig.h" #include "ipcache.h" -#include "log/Tokens.h" #include "MemObject.h" #include "ProtoPort.h" #include "SquidTime.h" @@ -605,7 +605,7 @@ clientReplyContext::processMiss() if (http->storeEntry()) { if (EBIT_TEST(http->storeEntry()->flags, ENTRY_SPECIAL)) { debugs(88, 0, "clientProcessMiss: miss on a special object (" << url << ")."); - debugs(88, 0, "\tlog_type = " << log_tags[http->logType]); + debugs(88, 0, "\tlog_type = " << Format::log_tags[http->logType]); http->storeEntry()->dump(1); } diff --git a/src/client_side_request.cc b/src/client_side_request.cc index 7d9ba1f573..49615cfef9 100644 --- a/src/client_side_request.cc +++ b/src/client_side_request.cc @@ -66,10 +66,10 @@ #include "comm/Write.h" #include "compat/inet_pton.h" #include "fde.h" +#include "format/Tokens.h" #include "HttpReply.h" #include "HttpRequest.h" #include "ip/QosConfig.h" -#include "log/Tokens.h" #include "MemObject.h" #include "ProtoPort.h" #include "Store.h" @@ -1314,7 +1314,7 @@ ClientHttpRequest::httpStart() { PROF_start(httpStart); logType = LOG_TAG_NONE; - debugs(85, 4, "ClientHttpRequest::httpStart: " << log_tags[logType] << " for '" << uri << "'"); + debugs(85, 4, "ClientHttpRequest::httpStart: " << Format::log_tags[logType] << " for '" << uri << "'"); /* no one should have touched this */ assert(out.offset == 0); diff --git a/src/format/Format.cc b/src/format/Format.cc new file mode 100644 index 0000000000..8e611520cb --- /dev/null +++ b/src/format/Format.cc @@ -0,0 +1,1067 @@ +#include "config.h" +#include "AccessLogEntry.h" +#include "comm/Connection.h" +#include "err_detail_type.h" +#include "errorpage.h" +#include "format/Format.h" +#include "format/Quoting.h" +#include "format/Tokens.h" +#include "HttpRequest.h" +#include "MemBuf.h" +#include "rfc1738.h" +#include "SquidTime.h" +#include "Store.h" + + +Format::Format::Format(const char *n) : + format(NULL), + next(NULL) +{ + name = xstrdup(n); +} + +Format::Format::~Format() +{ + // erase the list without consuming stack space + while (next) { + // unlink the next entry for deletion + Format *temp = next; + next = temp->next; + temp->next = NULL; + delete temp; + } + + // remove locals + xfree(name); + delete format; +} + +bool +Format::Format::parse(char *def) +{ + char *cur, *eos; + Token *new_lt, *last_lt; + enum Quoting quote = LOG_QUOTE_NONE; + + debugs(46, 2, HERE << "got definition '" << def << "'"); + + if (format) { + debugs(46, DBG_IMPORTANT, "WARNING: existing format for '" << name << " " << def << "'"); + return false; + } + + /* very inefficent parser, but who cares, this needs to be simple */ + /* First off, let's tokenize, we'll optimize in a second pass. + * A token can either be a %-prefixed sequence (usually a dynamic + * token but it can be an escaped sequence), or a string. */ + cur = def; + eos = def + strlen(def); + format = new_lt = last_lt = new Token; + cur += new_lt->parse(cur, "e); + + while (cur < eos) { + new_lt = new Token; + last_lt->next = new_lt; + last_lt = new_lt; + cur += new_lt->parse(cur, "e); + } + + return true; +} + +void +Format::Format::dump(StoreEntry * entry, const char *name) +{ + debugs(46, 4, HERE); + + // loop rather than recursing to conserve stack space. + for (Format *format = this; format; format = format->next) { + debugs(46, 3, HERE << "Dumping format definition for " << format->name); + storeAppendPrintf(entry, "format %s ", format->name); + + for (Token *t = format->format; t; t = t->next) { + if (t->type == LFT_STRING) + storeAppendPrintf(entry, "%s", t->data.string); + else { + char argbuf[256]; + char *arg = NULL; + ByteCode_t type = t->type; + + switch (type) { + /* special cases */ + + case LFT_STRING: + break; +#if USE_ADAPTATION + case LFT_ADAPTATION_LAST_HEADER_ELEM: +#endif +#if ICAP_CLIENT + case LFT_ICAP_REQ_HEADER_ELEM: + case LFT_ICAP_REP_HEADER_ELEM: +#endif + case LFT_REQUEST_HEADER_ELEM: + case LFT_ADAPTED_REQUEST_HEADER_ELEM: + case LFT_REPLY_HEADER_ELEM: + + if (t->data.header.separator != ',') + snprintf(argbuf, sizeof(argbuf), "%s:%c%s", t->data.header.header, t->data.header.separator, t->data.header.element); + else + snprintf(argbuf, sizeof(argbuf), "%s:%s", t->data.header.header, t->data.header.element); + + arg = argbuf; + + switch (type) { + case LFT_REQUEST_HEADER_ELEM: + type = LFT_REQUEST_HEADER_ELEM; // XXX: remove _ELEM? + break; + case LFT_ADAPTED_REQUEST_HEADER_ELEM: + type = LFT_ADAPTED_REQUEST_HEADER_ELEM; // XXX: remove _ELEM? + break; + case LFT_REPLY_HEADER_ELEM: + type = LFT_REPLY_HEADER_ELEM; // XXX: remove _ELEM? + break; +#if USE_ADAPTATION + case LFT_ADAPTATION_LAST_HEADER_ELEM: + type = LFT_ADAPTATION_LAST_HEADER; + break; +#endif +#if ICAP_CLIENT + case LFT_ICAP_REQ_HEADER_ELEM: + type = LFT_ICAP_REQ_HEADER; + break; + case LFT_ICAP_REP_HEADER_ELEM: + type = LFT_ICAP_REP_HEADER; + break; +#endif + default: + break; + } + + break; + + case LFT_REQUEST_ALL_HEADERS: + case LFT_ADAPTED_REQUEST_ALL_HEADERS: + case LFT_REPLY_ALL_HEADERS: + +#if USE_ADAPTATION + case LFT_ADAPTATION_LAST_ALL_HEADERS: +#endif +#if ICAP_CLIENT + case LFT_ICAP_REQ_ALL_HEADERS: + case LFT_ICAP_REP_ALL_HEADERS: +#endif + + switch (type) { + case LFT_REQUEST_ALL_HEADERS: + type = LFT_REQUEST_HEADER; + break; + case LFT_ADAPTED_REQUEST_ALL_HEADERS: + type = LFT_ADAPTED_REQUEST_HEADER; + break; + case LFT_REPLY_ALL_HEADERS: + type = LFT_REPLY_HEADER; + break; +#if USE_ADAPTATION + case LFT_ADAPTATION_LAST_ALL_HEADERS: + type = LFT_ADAPTATION_LAST_HEADER; + break; +#endif +#if ICAP_CLIENT + case LFT_ICAP_REQ_ALL_HEADERS: + type = LFT_ICAP_REQ_HEADER; + break; + case LFT_ICAP_REP_ALL_HEADERS: + type = LFT_ICAP_REP_HEADER; + break; +#endif + default: + break; + } + + break; + + default: + if (t->data.string) + arg = t->data.string; + + break; + } + + entry->append("%", 1); + + switch (t->quote) { + + case LOG_QUOTE_QUOTES: + entry->append("\"", 1); + break; + + case LOG_QUOTE_MIMEBLOB: + entry->append("[", 1); + break; + + case LOG_QUOTE_URL: + entry->append("#", 1); + break; + + case LOG_QUOTE_RAW: + entry->append("'", 1); + break; + + case LOG_QUOTE_NONE: + break; + } + + if (t->left) + entry->append("-", 1); + + if (t->zero) + entry->append("0", 1); + + if (t->width) + storeAppendPrintf(entry, "%d", (int) t->width); + + if (t->precision) + storeAppendPrintf(entry, ".%d", (int) t->precision); + + if (arg) + storeAppendPrintf(entry, "{%s}", arg); + + for (struct TokenTableEntry *te = TokenTable; te->config != NULL; te++) { + if (te->token_type == type) { + storeAppendPrintf(entry, "%s", te->config); + break; + } + } + + if (t->space) + entry->append(" ", 1); + } + } + + entry->append("\n", 1); + } + +} + +static void +log_quoted_string(const char *str, char *out) +{ + char *p = out; + + while (*str) { + int l = strcspn(str, "\"\\\r\n\t"); + memcpy(p, str, l); + str += l; + p += l; + + switch (*str) { + + case '\0': + break; + + case '\r': + *p++ = '\\'; + *p++ = 'r'; + str++; + break; + + case '\n': + *p++ = '\\'; + *p++ = 'n'; + str++; + break; + + case '\t': + *p++ = '\\'; + *p++ = 't'; + str++; + break; + + default: + *p++ = '\\'; + *p++ = *str; + str++; + break; + } + } + + *p++ = '\0'; +} + +void +Format::Format::assemble(MemBuf &mb, AccessLogEntry *al, int logSequenceNumber) const +{ + char tmp[1024]; + String sb; + + for (Token *fmt = format; fmt != NULL; fmt = fmt->next) { /* for each token */ + const char *out = NULL; + int quote = 0; + long int outint = 0; + int doint = 0; + int dofree = 0; + int64_t outoff = 0; + int dooff = 0; + + switch (fmt->type) { + + case LFT_NONE: + out = ""; + break; + + case LFT_STRING: + out = fmt->data.string; + break; + + case LFT_CLIENT_IP_ADDRESS: + if (al->cache.caddr.IsNoAddr()) // e.g., ICAP OPTIONS lack client + out = "-"; + else + out = al->cache.caddr.NtoA(tmp,1024); + break; + + case LFT_CLIENT_FQDN: + if (al->cache.caddr.IsAnyAddr()) // e.g., ICAP OPTIONS lack client + out = "-"; + else + out = fqdncache_gethostbyaddr(al->cache.caddr, FQDN_LOOKUP_IF_MISS); + if (!out) { + out = al->cache.caddr.NtoA(tmp,1024); + } + + break; + + case LFT_CLIENT_PORT: + if (al->request) { + outint = al->request->client_addr.GetPort(); + doint = 1; + } + break; + +#if USE_SQUID_EUI + case LFT_CLIENT_EUI: + // TODO make the ACL checklist have a direct link to any TCP details. + if (al->request && al->request->clientConnectionManager.valid() && al->request->clientConnectionManager->clientConnection != NULL) { + if (al->request->clientConnectionManager->clientConnection->remote.IsIPv4()) + al->request->clientConnectionManager->clientConnection->remoteEui48.encode(tmp, 1024); + else + al->request->clientConnectionManager->clientConnection->remoteEui64.encode(tmp, 1024); + out = tmp; + } + break; +#endif + + /* case LFT_SERVER_IP_ADDRESS: */ + + case LFT_SERVER_IP_OR_PEER_NAME: + out = al->hier.host; + + break; + + /* case LFT_SERVER_PORT: */ + + case LFT_LOCAL_IP: + if (al->request) { + out = al->request->my_addr.NtoA(tmp,sizeof(tmp)); + } + + break; + + case LFT_LOCAL_PORT: + if (al->request) { + outint = al->request->my_addr.GetPort(); + doint = 1; + } + + break; + + // the fmt->type can not be LFT_PEER_LOCAL_IP_OLD_27 + // but compiler complains if ommited + case LFT_PEER_LOCAL_IP_OLD_27: + case LFT_PEER_LOCAL_IP: + if (!al->hier.peer_local_addr.IsAnyAddr()) { + out = al->hier.peer_local_addr.NtoA(tmp,sizeof(tmp)); + } + break; + + case LFT_PEER_LOCAL_PORT: + if ((outint = al->hier.peer_local_addr.GetPort())) { + doint = 1; + } + + break; + + case LFT_TIME_SECONDS_SINCE_EPOCH: + // some platforms store time in 32-bit, some 64-bit... + outoff = static_cast(current_time.tv_sec); + dooff = 1; + break; + + case LFT_TIME_SUBSECOND: + outint = current_time.tv_usec / fmt->divisor; + doint = 1; + break; + + + case LFT_TIME_LOCALTIME: + + case LFT_TIME_GMT: { + const char *spec; + + struct tm *t; + spec = fmt->data.timespec; + + if (fmt->type == LFT_TIME_LOCALTIME) { + if (!spec) + spec = "%d/%b/%Y:%H:%M:%S %z"; + t = localtime(&squid_curtime); + } else { + if (!spec) + spec = "%d/%b/%Y:%H:%M:%S"; + + t = gmtime(&squid_curtime); + } + + strftime(tmp, sizeof(tmp), spec, t); + + out = tmp; + } + + break; + + case LFT_TIME_TO_HANDLE_REQUEST: + outint = al->cache.msec; + doint = 1; + break; + + case LFT_PEER_RESPONSE_TIME: + if (al->hier.peer_response_time < 0) { + out = "-"; + } else { + outoff = al->hier.peer_response_time; + dooff = 1; + } + break; + + case LFT_TOTAL_SERVER_SIDE_RESPONSE_TIME: + if (al->hier.total_response_time < 0) { + out = "-"; + } else { + outoff = al->hier.total_response_time; + dooff = 1; + } + break; + + case LFT_DNS_WAIT_TIME: + if (al->request && al->request->dnsWait >= 0) { + outint = al->request->dnsWait; + doint = 1; + } + break; + + case LFT_REQUEST_HEADER: + + if (al->request) + sb = al->request->header.getByName(fmt->data.header.header); + + out = sb.termedBuf(); + + quote = 1; + + break; + + case LFT_ADAPTED_REQUEST_HEADER: + + if (al->request) + sb = al->adapted_request->header.getByName(fmt->data.header.header); + + out = sb.termedBuf(); + + quote = 1; + + break; + + case LFT_REPLY_HEADER: + if (al->reply) + sb = al->reply->header.getByName(fmt->data.header.header); + + out = sb.termedBuf(); + + quote = 1; + + break; + +#if USE_ADAPTATION + case LTF_ADAPTATION_SUM_XACT_TIMES: + if (al->request) { + Adaptation::History::Pointer ah = al->request->adaptHistory(); + if (ah != NULL) + ah->sumLogString(fmt->data.string, sb); + out = sb.termedBuf(); + } + break; + + case LTF_ADAPTATION_ALL_XACT_TIMES: + if (al->request) { + Adaptation::History::Pointer ah = al->request->adaptHistory(); + if (ah != NULL) + ah->allLogString(fmt->data.string, sb); + out = sb.termedBuf(); + } + break; + + case LFT_ADAPTATION_LAST_HEADER: + if (al->request) { + const Adaptation::History::Pointer ah = al->request->adaptHistory(); + if (ah != NULL) // XXX: add adapt::allMeta.getByName(fmt->data.header.header); + } + + // XXX: here and elsewhere: move such code inside the if guard + out = sb.termedBuf(); + + quote = 1; + + break; + + case LFT_ADAPTATION_LAST_HEADER_ELEM: + if (al->request) { + const Adaptation::History::Pointer ah = al->request->adaptHistory(); + if (ah != NULL) // XXX: add adapt::allMeta.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator); + } + + out = sb.termedBuf(); + + quote = 1; + + break; + + case LFT_ADAPTATION_LAST_ALL_HEADERS: + out = al->adapt.last_meta; + + quote = 1; + + break; +#endif + +#if ICAP_CLIENT + case LFT_ICAP_ADDR: + if (!out) + out = al->icap.hostAddr.NtoA(tmp,1024); + break; + + case LFT_ICAP_SERV_NAME: + out = al->icap.serviceName.termedBuf(); + break; + + case LFT_ICAP_REQUEST_URI: + out = al->icap.reqUri.termedBuf(); + break; + + case LFT_ICAP_REQUEST_METHOD: + out = Adaptation::Icap::ICAP::methodStr(al->icap.reqMethod); + break; + + case LFT_ICAP_BYTES_SENT: + outoff = al->icap.bytesSent; + dooff = 1; + break; + + case LFT_ICAP_BYTES_READ: + outoff = al->icap.bytesRead; + dooff = 1; + break; + + case LFT_ICAP_BODY_BYTES_READ: + if (al->icap.bodyBytesRead >= 0) { + outoff = al->icap.bodyBytesRead; + dooff = 1; + } + // else if icap.bodyBytesRead < 0, we do not have any http data, + // so just print a "-" (204 responses etc) + break; + + case LFT_ICAP_REQ_HEADER: + if (NULL != al->icap.request) { + sb = al->icap.request->header.getByName(fmt->data.header.header); + out = sb.termedBuf(); + quote = 1; + } + break; + + case LFT_ICAP_REQ_HEADER_ELEM: + if (al->request) + sb = al->icap.request->header.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator); + + out = sb.termedBuf(); + + quote = 1; + + break; + + case LFT_ICAP_REQ_ALL_HEADERS: + if (al->icap.request) { + HttpHeaderPos pos = HttpHeaderInitPos; + while (const HttpHeaderEntry *e = al->icap.request->header.getEntry(&pos)) { + sb.append(e->name); + sb.append(": "); + sb.append(e->value); + sb.append("\r\n"); + } + out = sb.termedBuf(); + quote = 1; + } + break; + + case LFT_ICAP_REP_HEADER: + if (NULL != al->icap.reply) { + sb = al->icap.reply->header.getByName(fmt->data.header.header); + out = sb.termedBuf(); + quote = 1; + } + break; + + case LFT_ICAP_REP_HEADER_ELEM: + if (NULL != al->icap.reply) + sb = al->icap.reply->header.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator); + + out = sb.termedBuf(); + + quote = 1; + + break; + + case LFT_ICAP_REP_ALL_HEADERS: + if (al->icap.reply) { + HttpHeaderPos pos = HttpHeaderInitPos; + while (const HttpHeaderEntry *e = al->icap.reply->header.getEntry(&pos)) { + sb.append(e->name); + sb.append(": "); + sb.append(e->value); + sb.append("\r\n"); + } + out = sb.termedBuf(); + quote = 1; + } + break; + + case LFT_ICAP_TR_RESPONSE_TIME: + outint = al->icap.trTime; + doint = 1; + break; + + case LFT_ICAP_IO_TIME: + outint = al->icap.ioTime; + doint = 1; + break; + + case LFT_ICAP_STATUS_CODE: + outint = al->icap.resStatus; + doint = 1; + break; + + case LFT_ICAP_OUTCOME: + out = al->icap.outcome; + break; + + case LFT_ICAP_TOTAL_TIME: + outint = al->icap.processingTime; + doint = 1; + break; +#endif + case LFT_REQUEST_HEADER_ELEM: + if (al->request) + sb = al->request->header.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator); + + out = sb.termedBuf(); + + quote = 1; + + break; + + case LFT_ADAPTED_REQUEST_HEADER_ELEM: + if (al->adapted_request) + sb = al->adapted_request->header.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator); + + out = sb.termedBuf(); + + quote = 1; + + break; + + case LFT_REPLY_HEADER_ELEM: + if (al->reply) + sb = al->reply->header.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator); + + out = sb.termedBuf(); + + quote = 1; + + break; + + case LFT_REQUEST_ALL_HEADERS: + out = al->headers.request; + + quote = 1; + + break; + + case LFT_ADAPTED_REQUEST_ALL_HEADERS: + out = al->headers.adapted_request; + + quote = 1; + + break; + + case LFT_REPLY_ALL_HEADERS: + out = al->headers.reply; + + quote = 1; + + break; + + case LFT_USER_NAME: + out = QuoteUrlEncodeUsername(al->cache.authuser); + + if (!out) + out = QuoteUrlEncodeUsername(al->cache.extuser); + +#if USE_SSL + + if (!out) + out = QuoteUrlEncodeUsername(al->cache.ssluser); + +#endif + + if (!out) + out = QuoteUrlEncodeUsername(al->cache.rfc931); + + dofree = 1; + + break; + + case LFT_USER_LOGIN: + out = QuoteUrlEncodeUsername(al->cache.authuser); + + dofree = 1; + + break; + + case LFT_USER_IDENT: + out = QuoteUrlEncodeUsername(al->cache.rfc931); + + dofree = 1; + + break; + + case LFT_USER_EXTERNAL: + out = QuoteUrlEncodeUsername(al->cache.extuser); + + dofree = 1; + + break; + + /* case LFT_USER_REALM: */ + /* case LFT_USER_SCHEME: */ + + // the fmt->type can not be LFT_HTTP_SENT_STATUS_CODE_OLD_30 + // but compiler complains if ommited + case LFT_HTTP_SENT_STATUS_CODE_OLD_30: + case LFT_HTTP_SENT_STATUS_CODE: + outint = al->http.code; + + doint = 1; + + break; + + case LFT_HTTP_RECEIVED_STATUS_CODE: + if (al->hier.peer_reply_status == HTTP_STATUS_NONE) { + out = "-"; + } else { + outint = al->hier.peer_reply_status; + doint = 1; + } + break; + /* case LFT_HTTP_STATUS: + * out = statusline->text; + * quote = 1; + * break; + */ + case LFT_HTTP_BODY_BYTES_READ: + if (al->hier.bodyBytesRead >= 0) { + outoff = al->hier.bodyBytesRead; + dooff = 1; + } + // else if hier.bodyBytesRead < 0 we did not have any data exchange with + // a peer server so just print a "-" (eg requests served from cache, + // or internal error messages). + break; + + case LFT_SQUID_STATUS: + if (al->http.timedout || al->http.aborted) { + snprintf(tmp, sizeof(tmp), "%s%s", log_tags[al->cache.code], + al->http.statusSfx()); + out = tmp; + } else { + out = log_tags[al->cache.code]; + } + + break; + + case LFT_SQUID_ERROR: + if (al->request && al->request->errType != ERR_NONE) + out = errorPageName(al->request->errType); + break; + + case LFT_SQUID_ERROR_DETAIL: + if (al->request && al->request->errDetail != ERR_DETAIL_NONE) { + if (al->request->errDetail > ERR_DETAIL_START && + al->request->errDetail < ERR_DETAIL_MAX) + out = errorDetailName(al->request->errDetail); + else { + if (al->request->errDetail >= ERR_DETAIL_EXCEPTION_START) + snprintf(tmp, sizeof(tmp), "%s=0x%X", + errorDetailName(al->request->errDetail), (uint32_t) al->request->errDetail); + else + snprintf(tmp, sizeof(tmp), "%s=%d", + errorDetailName(al->request->errDetail), al->request->errDetail); + out = tmp; + } + } + break; + + case LFT_SQUID_HIERARCHY: + if (al->hier.ping.timedout) + mb.append("TIMEOUT_", 8); + + out = hier_code_str[al->hier.code]; + + break; + + case LFT_MIME_TYPE: + out = al->http.content_type; + + break; + + case LFT_CLIENT_REQ_METHOD: + if (al->request) { + out = al->request->method.image(); + quote = 1; + } + break; + + case LFT_CLIENT_REQ_URI: + // original client URI + if (al->request) { + out = urlCanonical(al->request); + quote = 1; + } + break; + + case LFT_REQUEST_URLPATH_OLD_31: + case LFT_CLIENT_REQ_URLPATH: + if (al->request) { + out = al->request->urlpath.termedBuf(); + quote = 1; + } + break; + + case LFT_CLIENT_REQ_VERSION: + if (al->request) { + snprintf(tmp, sizeof(tmp), "%d.%d", (int) al->request->http_ver.major, (int) al->request->http_ver.minor); + out = tmp; + } + break; + + case LFT_REQUEST_METHOD: + out = al->_private.method_str; + break; + + case LFT_REQUEST_URI: + out = al->url; + break; + + case LFT_REQUEST_VERSION_OLD_2X: + case LFT_REQUEST_VERSION: + snprintf(tmp, sizeof(tmp), "%d.%d", (int) al->http.version.major, (int) al->http.version.minor); + out = tmp; + break; + + case LFT_SERVER_REQ_METHOD: + if (al->adapted_request) { + out = al->adapted_request->method.image(); + quote = 1; + } + break; + + case LFT_SERVER_REQ_URI: + // adapted request URI sent to server/peer + if (al->adapted_request) { + out = urlCanonical(al->adapted_request); + quote = 1; + } + break; + + case LFT_SERVER_REQ_URLPATH: + if (al->adapted_request) { + out = al->adapted_request->urlpath.termedBuf(); + quote = 1; + } + break; + + case LFT_SERVER_REQ_VERSION: + if (al->adapted_request) { + snprintf(tmp, sizeof(tmp), "%d.%d", + (int) al->adapted_request->http_ver.major, + (int) al->adapted_request->http_ver.minor); + out = tmp; + } + break; + + case LFT_REQUEST_SIZE_TOTAL: + outoff = al->cache.requestSize; + dooff = 1; + break; + + /*case LFT_REQUEST_SIZE_LINE: */ + case LFT_REQUEST_SIZE_HEADERS: + outoff = al->cache.requestHeadersSize; + dooff =1; + break; + /*case LFT_REQUEST_SIZE_BODY: */ + /*case LFT_REQUEST_SIZE_BODY_NO_TE: */ + + case LFT_REPLY_SIZE_TOTAL: + outoff = al->cache.replySize; + dooff = 1; + break; + + case LFT_REPLY_HIGHOFFSET: + outoff = al->cache.highOffset; + + dooff = 1; + + break; + + case LFT_REPLY_OBJECTSIZE: + outoff = al->cache.objectSize; + + dooff = 1; + + break; + + /*case LFT_REPLY_SIZE_LINE: */ + case LFT_REPLY_SIZE_HEADERS: + outint = al->cache.replyHeadersSize; + doint = 1; + break; + /*case LFT_REPLY_SIZE_BODY: */ + /*case LFT_REPLY_SIZE_BODY_NO_TE: */ + + case LFT_TAG: + if (al->request) + out = al->request->tag.termedBuf(); + + quote = 1; + + break; + + case LFT_IO_SIZE_TOTAL: + outint = al->cache.requestSize + al->cache.replySize; + doint = 1; + break; + + case LFT_EXT_LOG: + if (al->request) + out = al->request->extacl_log.termedBuf(); + + quote = 1; + + break; + + case LFT_SEQUENCE_NUMBER: + outoff = logSequenceNumber; + dooff = 1; + break; + + case LFT_PERCENT: + out = "%"; + + break; + } + + if (dooff) { + snprintf(tmp, sizeof(tmp), "%0*" PRId64, fmt->zero ? (int) fmt->width : 0, outoff); + out = tmp; + + } else if (doint) { + snprintf(tmp, sizeof(tmp), "%0*ld", fmt->zero ? (int) fmt->width : 0, outint); + out = tmp; + } + + if (out && *out) { + if (quote || fmt->quote != LOG_QUOTE_NONE) { + char *newout = NULL; + int newfree = 0; + + switch (fmt->quote) { + + case LOG_QUOTE_NONE: + newout = rfc1738_escape_unescaped(out); + break; + + case LOG_QUOTE_QUOTES: { + size_t out_len = static_cast(strlen(out)) * 2 + 1; + if (out_len >= sizeof(tmp)) { + newout = (char *)xmalloc(out_len); + newfree = 1; + } else + newout = tmp; + log_quoted_string(out, newout); + } + break; + + case LOG_QUOTE_MIMEBLOB: + newout = QuoteMimeBlob(out); + newfree = 1; + break; + + case LOG_QUOTE_URL: + newout = rfc1738_escape(out); + break; + + case LOG_QUOTE_RAW: + break; + } + + if (newout) { + if (dofree) + safe_free(out); + + out = newout; + + dofree = newfree; + } + } + + if (fmt->width) { + if (fmt->left) + mb.Printf("%-*s", (int) fmt->width, out); + else + mb.Printf("%*s", (int) fmt->width, out); + } else + mb.append(out, strlen(out)); + } else { + mb.append("-", 1); + } + + if (fmt->space) + mb.append(" ", 1); + + sb.clean(); + + if (dofree) + safe_free(out); + } +} diff --git a/src/format/Format.h b/src/format/Format.h new file mode 100644 index 0000000000..3c177569f1 --- /dev/null +++ b/src/format/Format.h @@ -0,0 +1,51 @@ +#ifndef _SQUID_FORMAT_FORMAT_H +#define _SQUID_FORMAT_FORMAT_H + +/* + * Squid configuration allows users to define custom formats in + * several components. + * - logging + * - external ACL input + * - deny page URL + * + * These enumerations and classes define the API for parsing of + * format directives to define these patterns. Along with output + * functionality to produce formatted buffers. + */ + +class AccessLogEntry; +class MemBuf; +class StoreEntry; + +namespace Format +{ + +class Token; + +// XXX: inherit from linked list +class Format +{ +public: + Format(const char *name); + ~Format(); + + /* very inefficent parser, but who cares, this needs to be simple */ + /* First off, let's tokenize, we'll optimize in a second pass. + * A token can either be a %-prefixed sequence (usually a dynamic + * token but it can be an escaped sequence), or a string. */ + bool parse(char *def); + + /// assemble the state information into a formatted line. + void assemble(MemBuf &mb, AccessLogEntry *al, int logSequenceNumber) const; + + /// dump this whole list of formats into the provided StoreEntry + void dump(StoreEntry * entry, const char *name); + + char *name; + Token *format; + Format *next; +}; + +} // namespace Format + +#endif /* _SQUID_FORMAT_FORMAT_H */ diff --git a/src/format/Makefile.am b/src/format/Makefile.am new file mode 100644 index 0000000000..cbf05deb11 --- /dev/null +++ b/src/format/Makefile.am @@ -0,0 +1,13 @@ +include $(top_srcdir)/src/Common.am +include $(top_srcdir)/src/TestHeaders.am + +noinst_LTLIBRARIES = libformat.la + +libformat_la_SOURCES = \ + Format.cc \ + Format.h \ + Quoting.cc \ + Quoting.h \ + Tokens.cc \ + Tokens.h + diff --git a/src/log/Gadgets.cc b/src/format/Quoting.cc similarity index 97% rename from src/log/Gadgets.cc rename to src/format/Quoting.cc index f188f813e7..badff8814b 100644 --- a/src/log/Gadgets.cc +++ b/src/format/Quoting.cc @@ -1,5 +1,5 @@ #include "config.h" -#include "log/Gadgets.h" +#include "format/Quoting.h" static const char c2x[] = "000102030405060708090a0b0c0d0e0f" @@ -70,7 +70,7 @@ username_quote(const char *header) #endif // DEAD char * -Log::FormatName(const char *name) +Format::QuoteUrlEncodeUsername(const char *name) { if (NULL == name) return NULL; @@ -83,7 +83,7 @@ Log::FormatName(const char *name) } char * -Log::QuoteMimeBlob(const char *header) +Format::QuoteMimeBlob(const char *header) { int c; int i; diff --git a/src/log/Gadgets.h b/src/format/Quoting.h similarity index 50% rename from src/log/Gadgets.h rename to src/format/Quoting.h index 9e5e1dd0d9..2b6e78d837 100644 --- a/src/log/Gadgets.h +++ b/src/format/Quoting.h @@ -1,19 +1,19 @@ -#ifndef _SQUID_LOG_GADGETS_H -#define _SQUID_LOG_GADGETS_H +#ifndef _SQUID_FORMAT_QUOTING_H +#define _SQUID_FORMAT_QUOTING_H -namespace Log +namespace Format { /// Safely URL-encode a username. /// Accepts NULL or empty strings. -char * FormatName(const char *name); +extern char * QuoteUrlEncodeUsername(const char *name); /** URL-style encoding on a MIME headers blob. * May accept NULL or empty strings. * \return A dynamically allocated string. recipient is responsible for free()'ing */ -char *QuoteMimeBlob(const char *header); +extern char *QuoteMimeBlob(const char *header); -}; // namespace Log +}; // namespace Format -#endif /* _SQUID_LOG_GADGETS_H */ +#endif /* _SQUID_FORMAT_QUOTING_H */ diff --git a/src/format/Tokens.cc b/src/format/Tokens.cc new file mode 100644 index 0000000000..9feed0efad --- /dev/null +++ b/src/format/Tokens.cc @@ -0,0 +1,463 @@ +#include "config.h" +#include "format/Tokens.h" +#include "Store.h" + +const char *Format::log_tags[] = { + "NONE", + "TCP_HIT", + "TCP_MISS", + "TCP_REFRESH_UNMODIFIED", + "TCP_REFRESH_FAIL", // same tag logged for LOG_TCP_REFRESH_FAIL_OLD and + "TCP_REFRESH_FAIL", // LOG_TCP_REFRESH_FAIL_ERR for backward-compatibility + "TCP_REFRESH_MODIFIED", + "TCP_CLIENT_REFRESH_MISS", + "TCP_IMS_HIT", + "TCP_SWAPFAIL_MISS", + "TCP_NEGATIVE_HIT", + "TCP_MEM_HIT", + "TCP_DENIED", + "TCP_DENIED_REPLY", + "TCP_OFFLINE_HIT", +#if LOG_TCP_REDIRECTS + "TCP_REDIRECT", +#endif + "UDP_HIT", + "UDP_MISS", + "UDP_DENIED", + "UDP_INVALID", + "UDP_MISS_NOFETCH", + "ICP_QUERY", + "LOG_TYPE_MAX" +}; + +struct Format::TokenTableEntry Format::TokenTable[] = { + + {">a", LFT_CLIENT_IP_ADDRESS}, + {">p", LFT_CLIENT_PORT}, + {">A", LFT_CLIENT_FQDN}, +#if USE_SQUID_EUI + {">eui", LFT_CLIENT_EUI}, +#endif + + /*{ "ha", LFT_ADAPTED_REQUEST_HEADER}, + {">ha", LFT_ADAPTED_REQUEST_ALL_HEADERS}, + {">h", LFT_REQUEST_HEADER}, + {">h", LFT_REQUEST_ALL_HEADERS}, + {"Hs", LFT_HTTP_SENT_STATUS_CODE}, + {"rm", LFT_CLIENT_REQ_METHOD}, + {">ru", LFT_CLIENT_REQ_URI}, + {">rp", LFT_CLIENT_REQ_URLPATH}, + /*{">rq", LFT_CLIENT_REQ_QUERY},*/ + {">rv", LFT_CLIENT_REQ_VERSION}, + + {"rm", LFT_REQUEST_METHOD}, + {"ru", LFT_REQUEST_URI}, /* doesn't include the query-string */ + {"rp", LFT_REQUEST_URLPATH_OLD_31}, + /* { "rq", LFT_REQUEST_QUERY }, * / / * the query-string, INCLUDING the leading ? */ + {">v", LFT_REQUEST_VERSION_OLD_2X}, + {"rv", LFT_REQUEST_VERSION}, + + {"st", LFT_REQUEST_SIZE_TOTAL }, + /*{ ">sl", LFT_REQUEST_SIZE_LINE }, * / / * the request line "GET ... " */ + { ">sh", LFT_REQUEST_SIZE_HEADERS }, + /*{ ">sb", LFT_REQUEST_SIZE_BODY }, */ + /*{ ">sB", LFT_REQUEST_SIZE_BODY_NO_TE }, */ + + {"st", LFT_ICAP_BYTES_SENT}, + {"icap::h", LFT_ICAP_REQ_HEADER}, + {"icap:: 0) { + char *cp; + /* it's a string for sure, until \0 or the next % */ + cp = (char *)xmalloc(l + 1); + xstrncpy(cp, cur, l + 1); + type = LFT_STRING; + data.string = cp; + + while (l > 0) { + switch (*cur) { + + case '"': + + if (*quoting == LOG_QUOTE_NONE) + *quoting = LOG_QUOTE_QUOTES; + else if (*quoting == LOG_QUOTE_QUOTES) + *quoting = LOG_QUOTE_NONE; + + break; + + case '[': + if (*quoting == LOG_QUOTE_NONE) + *quoting = LOG_QUOTE_MIMEBLOB; + + break; + + case ']': + if (*quoting == LOG_QUOTE_MIMEBLOB) + *quoting = LOG_QUOTE_NONE; + + break; + } + + cur++; + l--; + } + + goto done; + } + + if (!*cur) + goto done; + + cur++; + + // select quoting style for his particular token + switch (*cur) { + + case '"': + quote = LOG_QUOTE_QUOTES; + cur++; + break; + + case '\'': + quote = LOG_QUOTE_RAW; + cur++; + break; + + case '[': + quote = LOG_QUOTE_MIMEBLOB; + cur++; + break; + + case '#': + quote = LOG_QUOTE_URL; + cur++; + break; + + default: + quote = *quoting; + break; + } + + if (*cur == '-') { + left = 1; + cur++; + } + + if (*cur == '0') { + zero = 1; + cur++; + } + + if (xisdigit(*cur)) + width = strtol(cur, &cur, 10); + + if (*cur == '.') + precision = strtol(cur + 1, &cur, 10); + + if (*cur == '{') { + char *cp; + cur++; + l = strcspn(cur, "}"); + cp = (char *)xmalloc(l + 1); + xstrncpy(cp, cur, l + 1); + data.string = cp; + cur += l; + + if (*cur == '}') + cur++; + } + + // For upward compatibility, assume "http::" prefix as default prefix + // for all log access formating codes, except those starting + // from "icap::", "adapt::" and "%" + if (strncmp(cur,"http::", 6) == 0 && + strncmp(cur+6, "icap::", 6) != 0 && + strncmp(cur+6, "adapt::", 12) != 0 && *(cur+6) != '%' ) { + cur += 6; + } + + type = LFT_NONE; + + for (lte = TokenTable; lte->config != NULL; lte++) { + if (strncmp(lte->config, cur, strlen(lte->config)) == 0) { + type = lte->token_type; + cur += strlen(lte->config); + break; + } + } + + if (type == LFT_NONE) { + fatalf("Can't parse configuration token: '%s'\n", + def); + } + + if (*cur == ' ') { + space = 1; + cur++; + } + +done: + + switch (type) { + +#if USE_ADAPTATION + case LFT_ADAPTATION_LAST_HEADER: +#endif + +#if ICAP_CLIENT + case LFT_ICAP_REQ_HEADER: + + case LFT_ICAP_REP_HEADER: +#endif + + case LFT_ADAPTED_REQUEST_HEADER: + + case LFT_REQUEST_HEADER: + + case LFT_REPLY_HEADER: + + if (data.string) { + char *header = data.string; + char *cp = strchr(header, ':'); + + if (cp) { + *cp++ = '\0'; + + if (*cp == ',' || *cp == ';' || *cp == ':') + data.header.separator = *cp++; + else + data.header.separator = ','; + + data.header.element = cp; + + switch (type) { + case LFT_REQUEST_HEADER: + type = LFT_REQUEST_HEADER_ELEM; + break; + + case LFT_ADAPTED_REQUEST_HEADER: + type = LFT_ADAPTED_REQUEST_HEADER_ELEM; + break; + + case LFT_REPLY_HEADER: + type = LFT_REPLY_HEADER_ELEM; + break; +#if USE_ADAPTATION + case LFT_ADAPTATION_LAST_HEADER: + type = LFT_ADAPTATION_LAST_HEADER_ELEM; + break; +#endif +#if ICAP_CLIENT + case LFT_ICAP_REQ_HEADER: + type = LFT_ICAP_REQ_HEADER_ELEM; + break; + case LFT_ICAP_REP_HEADER: + type = LFT_ICAP_REP_HEADER_ELEM; + break; +#endif + default: + break; + } + } + + data.header.header = header; + } else { + switch (type) { + case LFT_REQUEST_HEADER: + type = LFT_REQUEST_ALL_HEADERS; + break; + + case LFT_ADAPTED_REQUEST_HEADER: + type = LFT_ADAPTED_REQUEST_ALL_HEADERS; + break; + + case LFT_REPLY_HEADER: + type = LFT_REPLY_ALL_HEADERS; + break; +#if USE_ADAPTATION + case LFT_ADAPTATION_LAST_HEADER: + type = LFT_ADAPTATION_LAST_ALL_HEADERS; + break; +#endif +#if ICAP_CLIENT + case LFT_ICAP_REQ_HEADER: + type = LFT_ICAP_REQ_ALL_HEADERS; + break; + case LFT_ICAP_REP_HEADER: + type = LFT_ICAP_REP_ALL_HEADERS; + break; +#endif + default: + break; + } + Config.onoff.log_mime_hdrs = 1; + } + + break; + + case LFT_CLIENT_FQDN: + Config.onoff.log_fqdn = 1; + break; + + case LFT_TIME_SUBSECOND: + divisor = 1000; + + if (precision) { + int i; + divisor = 1000000; + + for (i = precision; i > 1; i--) + divisor /= 10; + + if (!divisor) + divisor = 0; + } + + break; + + case LFT_HTTP_SENT_STATUS_CODE_OLD_30: + debugs(46, 0, "WARNING: The \"Hs\" formatting code is deprecated. Use the \">Hs\" instead."); + type = LFT_HTTP_SENT_STATUS_CODE; + break; + + case LFT_PEER_LOCAL_IP_OLD_27: + debugs(46, 0, "WARNING: The \"oa\" formatting code is deprecated. Use the \"rp\" instead."); + type = LFT_CLIENT_REQ_URLPATH; + break; + + case LFT_REQUEST_VERSION_OLD_2X: + debugs(46, 0, "WARNING: The \">v\" formatting code is deprecated. Use the \">rv\" instead."); + type = LFT_REQUEST_VERSION; + break; + + default: + break; + } + + return (cur - def); +} + +Format::Token::~Token() +{ + safe_free(data.string); + while (next) { + Token *tokens = next; + next = next->next; + tokens->next = NULL; + delete tokens; + } +} + diff --git a/src/log/Tokens.h b/src/format/Tokens.h similarity index 55% rename from src/log/Tokens.h rename to src/format/Tokens.h index 1571550a90..b37ec9187a 100644 --- a/src/log/Tokens.h +++ b/src/format/Tokens.h @@ -1,45 +1,25 @@ +#ifndef _SQUID_FMT_TOKENS_H +#define _SQUID_FMT_TOKENS_H + /* - * $Id$ - * - * DEBUG: section 46 Access Log - * AUTHOR: Duane Wessels - * - * 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. + * Squid configuration allows users to define custom formats in + * several components. + * - logging + * - external ACL input + * - deny page URL * + * These enumerations and classes define the API for parsing of + * format directives to define these patterns. Along with output + * functionality to produce formatted buffers. */ -#ifndef _SQUID_LOG_TOKENS_H -#define _SQUID_LOG_TOKENS_H -class StoreEntry; +namespace Format +{ #define LOG_BUF_SZ (MAX_URL<<2) /* - * Bytecodes for the configureable logformat stuff + * Bytecodes for the configureable format stuff */ typedef enum { LFT_NONE, /* dummy */ @@ -182,9 +162,10 @@ typedef enum { #endif LFT_PERCENT /* special string cases for escaped chars */ -} logformat_bcode_t; +} ByteCode_t; -enum log_quote { +/// Quoting style for a format output. +enum Quoting { LOG_QUOTE_NONE = 0, LOG_QUOTE_QUOTES, LOG_QUOTE_MIMEBLOB, @@ -192,11 +173,20 @@ enum log_quote { LOG_QUOTE_RAW }; -/* FIXME: public class so we can pre-define its type. */ -class logformat_token +// XXX: inherit from linked list +class Token { public: - logformat_bcode_t type; + Token() {}; + ~Token(); + + /** parses a single token. Returns the token length in characters, + * and fills in this item with the token information. + * def is for sure null-terminated. + */ + int parse(char *def, enum Quoting *quote); + + ByteCode_t type; union { char *string; @@ -209,56 +199,23 @@ public: } data; unsigned char width; unsigned char precision; - enum log_quote quote; + enum Quoting quote; unsigned int left:1; unsigned int space:1; unsigned int zero:1; int divisor; - logformat_token *next; /* todo: move from linked list to array */ + Token *next; /* todo: move from linked list to array */ }; -struct logformat_token_table_entry { +struct TokenTableEntry { const char *config; - logformat_bcode_t token_type; + ByteCode_t token_type; int options; }; -class logformat -{ -public: - logformat(const char *name); - ~logformat(); - - char *name; - logformat_token *format; - logformat *next; -}; - extern const char *log_tags[]; -extern struct logformat_token_table_entry logformat_token_table[]; - -#if USE_ADAPTATION -extern bool alLogformatHasAdaptToken; -#endif - -#if ICAP_CLIENT -extern bool alLogformatHasIcapToken; -#endif - -/* parses a single token. Returns the token length in characters, - * and fills in the lt item with the token information. - * def is for sure null-terminated - */ -int accessLogGetNewLogFormatToken(logformat_token * lt, char *def, enum log_quote *quote); - -/* very inefficent parser, but who cares, this needs to be simple */ -/* First off, let's tokenize, we'll optimize in a second pass. - * A token can either be a %-prefixed sequence (usually a dynamic - * token but it can be an escaped sequence), or a string. */ -int accessLogParseLogFormat(logformat_token ** fmt, char *def); - -void accessLogDumpLogFormat(StoreEntry * entry, const char *name, logformat * definitions); +extern struct TokenTableEntry TokenTable[]; -void accessLogFreeLogFormat(logformat_token ** tokens); +} // namespace Format -#endif /* _SQUID_LOG_TOKENS_H */ +#endif /* _SQUID_FMT_TOKENS_H */ diff --git a/src/helper.cc b/src/helper.cc index 9d385f6384..ae56fe7cb2 100644 --- a/src/helper.cc +++ b/src/helper.cc @@ -37,7 +37,7 @@ #include "comm/Connection.h" #include "comm/Write.h" #include "helper.h" -#include "log/Gadgets.h" +#include "format/Quoting.h" #include "MemBuf.h" #include "SquidMath.h" #include "SquidTime.h" @@ -507,7 +507,7 @@ helperStats(StoreEntry * sentry, helper * hlp, const char *label) srv->flags.shutdown ? 'S' : ' ', tt < 0.0 ? 0.0 : tt, (int) srv->roffset, - srv->requests[0] ? Log::QuoteMimeBlob(srv->requests[0]->buf) : "(none)"); + srv->requests[0] ? Format::QuoteMimeBlob(srv->requests[0]->buf) : "(none)"); } storeAppendPrintf(sentry, "\nFlags key:\n\n"); @@ -561,7 +561,7 @@ helperStatefulStats(StoreEntry * sentry, statefulhelper * hlp, const char *label srv->request ? (srv->request->placeholder ? 'P' : ' ') : ' ', tt < 0.0 ? 0.0 : tt, (int) srv->roffset, - srv->request ? Log::QuoteMimeBlob(srv->request->buf) : "(none)"); + srv->request ? Format::QuoteMimeBlob(srv->request->buf) : "(none)"); } storeAppendPrintf(sentry, "\nFlags key:\n\n"); diff --git a/src/log/Config.cc b/src/log/Config.cc index fd9a148eaf..02ba17f2d6 100644 --- a/src/log/Config.cc +++ b/src/log/Config.cc @@ -1,6 +1,5 @@ #include "config.h" #include "log/Config.h" -#include "log/Tokens.h" #include "protos.h" Log::LogConfig Log::TheConfig; @@ -18,11 +17,11 @@ Log::LogConfig::parseFormats() return; } - debugs(3, 2, "Logformat for '" << name << "' is '" << def << "'"); + debugs(3, 2, "Log Format for '" << name << "' is '" << def << "'"); - logformat *nlf = new logformat(name); + ::Format::Format *nlf = new ::Format::Format(name); - if (!accessLogParseLogFormat(&nlf->format, def)) { + if (!nlf->parse(def)) { self_destruct(); return; } diff --git a/src/log/Config.h b/src/log/Config.h index f46d4654d0..54176decd5 100644 --- a/src/log/Config.h +++ b/src/log/Config.h @@ -1,7 +1,7 @@ #ifndef SQUID_SRC_LOG_CONFIG_H #define SQUID_SRC_LOG_CONFIG_H -#include "log/Tokens.h" +#include "format/Format.h" class StoreEntry; @@ -13,14 +13,22 @@ class LogConfig public: void parseFormats(); void dumpFormats(StoreEntry *e, const char *name) { - accessLogDumpLogFormat(e, name, logformats); + logformats->dump(e, name); } /// File path to logging daemon executable char *logfile_daemon; /// Linked list of custom log formats - logformat *logformats; + ::Format::Format *logformats; + +#if USE_ADAPTATION + bool hasAdaptToken; +#endif + +#if ICAP_CLIENT + bool hasIcapToken; +#endif }; extern LogConfig TheConfig; diff --git a/src/log/FormatHttpdCombined.cc b/src/log/FormatHttpdCombined.cc index db4638957b..3283956126 100644 --- a/src/log/FormatHttpdCombined.cc +++ b/src/log/FormatHttpdCombined.cc @@ -34,11 +34,11 @@ #include "config.h" #include "AccessLogEntry.h" +#include "format/Tokens.h" +#include "format/Quoting.h" #include "HttpRequest.h" #include "log/File.h" #include "log/Formats.h" -#include "log/Gadgets.h" -#include "log/Tokens.h" #include "SquidTime.h" void @@ -46,9 +46,9 @@ Log::Format::HttpdCombined(AccessLogEntry * al, Logfile * logfile) { char clientip[MAX_IPSTRLEN]; - const char *user_ident = FormatName(al->cache.rfc931); + const char *user_ident = ::Format::QuoteUrlEncodeUsername(al->cache.rfc931); - const char *user_auth = FormatName(al->cache.authuser); + const char *user_auth = ::Format::QuoteUrlEncodeUsername(al->cache.authuser); const char *referer = al->request->header.getStr(HDR_REFERER); if (!referer || *referer == '\0') @@ -71,7 +71,7 @@ Log::Format::HttpdCombined(AccessLogEntry * al, Logfile * logfile) al->cache.replySize, referer, agent, - log_tags[al->cache.code], + ::Format::log_tags[al->cache.code], al->http.statusSfx(), hier_code_str[al->hier.code], (Config.onoff.log_mime_hdrs?"":"\n")); @@ -80,8 +80,8 @@ Log::Format::HttpdCombined(AccessLogEntry * al, Logfile * logfile) safe_free(user_auth); if (Config.onoff.log_mime_hdrs) { - char *ereq = QuoteMimeBlob(al->headers.request); - char *erep = QuoteMimeBlob(al->headers.reply); + char *ereq = ::Format::QuoteMimeBlob(al->headers.request); + char *erep = ::Format::QuoteMimeBlob(al->headers.reply); logfilePrintf(logfile, " [%s] [%s]\n", ereq, erep); safe_free(ereq); safe_free(erep); diff --git a/src/log/FormatHttpdCommon.cc b/src/log/FormatHttpdCommon.cc index 1f8ad8566f..a44d282f15 100644 --- a/src/log/FormatHttpdCommon.cc +++ b/src/log/FormatHttpdCommon.cc @@ -34,18 +34,18 @@ #include "config.h" #include "AccessLogEntry.h" +#include "format/Quoting.h" +#include "format/Tokens.h" #include "log/File.h" #include "log/Formats.h" -#include "log/Gadgets.h" -#include "log/Tokens.h" #include "SquidTime.h" void Log::Format::HttpdCommon(AccessLogEntry * al, Logfile * logfile) { char clientip[MAX_IPSTRLEN]; - const char *user_auth = FormatName(al->cache.authuser); - const char *user_ident = FormatName(al->cache.rfc931); + const char *user_auth = ::Format::QuoteUrlEncodeUsername(al->cache.authuser); + const char *user_ident = ::Format::QuoteUrlEncodeUsername(al->cache.rfc931); logfilePrintf(logfile, "%s %s %s [%s] \"%s %s %s/%d.%d\" %d %"PRId64" %s%s:%s%s", al->cache.caddr.NtoA(clientip,MAX_IPSTRLEN), @@ -58,7 +58,7 @@ Log::Format::HttpdCommon(AccessLogEntry * al, Logfile * logfile) al->http.version.major, al->http.version.minor, al->http.code, al->cache.replySize, - log_tags[al->cache.code], + ::Format::log_tags[al->cache.code], al->http.statusSfx(), hier_code_str[al->hier.code], (Config.onoff.log_mime_hdrs?"":"\n")); @@ -67,8 +67,8 @@ Log::Format::HttpdCommon(AccessLogEntry * al, Logfile * logfile) safe_free(user_ident); if (Config.onoff.log_mime_hdrs) { - char *ereq = QuoteMimeBlob(al->headers.request); - char *erep = QuoteMimeBlob(al->headers.reply); + char *ereq = ::Format::QuoteMimeBlob(al->headers.request); + char *erep = ::Format::QuoteMimeBlob(al->headers.reply); logfilePrintf(logfile, " [%s] [%s]\n", ereq, erep); safe_free(ereq); safe_free(erep); diff --git a/src/log/FormatSquidCustom.cc b/src/log/FormatSquidCustom.cc index 4530b33f3f..bf43fe0720 100644 --- a/src/log/FormatSquidCustom.cc +++ b/src/log/FormatSquidCustom.cc @@ -34,849 +34,19 @@ #include "config.h" #include "AccessLogEntry.h" -#include "comm/Connection.h" +#include "format/Tokens.h" #include "log/File.h" #include "log/Formats.h" -#include "log/Gadgets.h" -#include "log/Tokens.h" -#include "SquidTime.h" - #include "MemBuf.h" -#include "HttpRequest.h" -#include "rfc1738.h" -#include "err_detail_type.h" -#include "errorpage.h" - -static void -log_quoted_string(const char *str, char *out) -{ - char *p = out; - - while (*str) { - int l = strcspn(str, "\"\\\r\n\t"); - memcpy(p, str, l); - str += l; - p += l; - - switch (*str) { - - case '\0': - break; - - case '\r': - *p++ = '\\'; - *p++ = 'r'; - str++; - break; - - case '\n': - *p++ = '\\'; - *p++ = 'n'; - str++; - break; - - case '\t': - *p++ = '\\'; - *p++ = 't'; - str++; - break; - - default: - *p++ = '\\'; - *p++ = *str; - str++; - break; - } - } - - *p++ = '\0'; -} void Log::Format::SquidCustom(AccessLogEntry * al, customlog * log) { - logformat *lf; - Logfile *logfile; - logformat_token *fmt; static MemBuf mb; - char tmp[1024]; - String sb; - mb.reset(); - lf = log->logFormat; - logfile = log->logfile; - - for (fmt = lf->format; fmt != NULL; fmt = fmt->next) { /* for each token */ - const char *out = NULL; - int quote = 0; - long int outint = 0; - int doint = 0; - int dofree = 0; - int64_t outoff = 0; - int dooff = 0; - - switch (fmt->type) { - - case LFT_NONE: - out = ""; - break; - - case LFT_STRING: - out = fmt->data.string; - break; - - case LFT_CLIENT_IP_ADDRESS: - if (al->cache.caddr.IsNoAddr()) // e.g., ICAP OPTIONS lack client - out = "-"; - else - out = al->cache.caddr.NtoA(tmp,1024); - break; - - case LFT_CLIENT_FQDN: - if (al->cache.caddr.IsAnyAddr()) // e.g., ICAP OPTIONS lack client - out = "-"; - else - out = fqdncache_gethostbyaddr(al->cache.caddr, FQDN_LOOKUP_IF_MISS); - if (!out) { - out = al->cache.caddr.NtoA(tmp,1024); - } - - break; - - case LFT_CLIENT_PORT: - if (al->request) { - outint = al->request->client_addr.GetPort(); - doint = 1; - } - break; - -#if USE_SQUID_EUI - case LFT_CLIENT_EUI: - // TODO make the ACL checklist have a direct link to any TCP details. - if (al->request && al->request->clientConnectionManager.valid() && al->request->clientConnectionManager->clientConnection != NULL) { - if (al->request->clientConnectionManager->clientConnection->remote.IsIPv4()) - al->request->clientConnectionManager->clientConnection->remoteEui48.encode(tmp, 1024); - else - al->request->clientConnectionManager->clientConnection->remoteEui64.encode(tmp, 1024); - out = tmp; - } - break; -#endif - - /* case LFT_SERVER_IP_ADDRESS: */ - - case LFT_SERVER_IP_OR_PEER_NAME: - out = al->hier.host; - - break; - - /* case LFT_SERVER_PORT: */ - - case LFT_LOCAL_IP: - if (al->request) { - out = al->request->my_addr.NtoA(tmp,sizeof(tmp)); - } - - break; - - case LFT_LOCAL_PORT: - if (al->request) { - outint = al->request->my_addr.GetPort(); - doint = 1; - } - - break; - - // the fmt->type can not be LFT_PEER_LOCAL_IP_OLD_27 - // but compiler complains if ommited - case LFT_PEER_LOCAL_IP_OLD_27: - case LFT_PEER_LOCAL_IP: - if (!al->hier.peer_local_addr.IsAnyAddr()) { - out = al->hier.peer_local_addr.NtoA(tmp,sizeof(tmp)); - } - break; - - case LFT_PEER_LOCAL_PORT: - if ((outint = al->hier.peer_local_addr.GetPort())) { - doint = 1; - } - - break; - - case LFT_TIME_SECONDS_SINCE_EPOCH: - // some platforms store time in 32-bit, some 64-bit... - outoff = static_cast(current_time.tv_sec); - dooff = 1; - break; - - case LFT_TIME_SUBSECOND: - outint = current_time.tv_usec / fmt->divisor; - doint = 1; - break; - - - case LFT_TIME_LOCALTIME: - - case LFT_TIME_GMT: { - const char *spec; - - struct tm *t; - spec = fmt->data.timespec; - - if (fmt->type == LFT_TIME_LOCALTIME) { - if (!spec) - spec = "%d/%b/%Y:%H:%M:%S %z"; - t = localtime(&squid_curtime); - } else { - if (!spec) - spec = "%d/%b/%Y:%H:%M:%S"; - - t = gmtime(&squid_curtime); - } - - strftime(tmp, sizeof(tmp), spec, t); - - out = tmp; - } - - break; - - case LFT_TIME_TO_HANDLE_REQUEST: - outint = al->cache.msec; - doint = 1; - break; - - case LFT_PEER_RESPONSE_TIME: - if (al->hier.peer_response_time < 0) { - out = "-"; - } else { - outoff = al->hier.peer_response_time; - dooff = 1; - } - break; - - case LFT_TOTAL_SERVER_SIDE_RESPONSE_TIME: - if (al->hier.total_response_time < 0) { - out = "-"; - } else { - outoff = al->hier.total_response_time; - dooff = 1; - } - break; - - case LFT_DNS_WAIT_TIME: - if (al->request && al->request->dnsWait >= 0) { - outint = al->request->dnsWait; - doint = 1; - } - break; - - case LFT_REQUEST_HEADER: - - if (al->request) - sb = al->request->header.getByName(fmt->data.header.header); - - out = sb.termedBuf(); - - quote = 1; - - break; - - case LFT_ADAPTED_REQUEST_HEADER: - - if (al->request) - sb = al->adapted_request->header.getByName(fmt->data.header.header); - - out = sb.termedBuf(); - - quote = 1; - - break; - - case LFT_REPLY_HEADER: - if (al->reply) - sb = al->reply->header.getByName(fmt->data.header.header); - - out = sb.termedBuf(); - - quote = 1; - - break; - -#if USE_ADAPTATION - case LTF_ADAPTATION_SUM_XACT_TIMES: - if (al->request) { - Adaptation::History::Pointer ah = al->request->adaptHistory(); - if (ah != NULL) - ah->sumLogString(fmt->data.string, sb); - out = sb.termedBuf(); - } - break; - - case LTF_ADAPTATION_ALL_XACT_TIMES: - if (al->request) { - Adaptation::History::Pointer ah = al->request->adaptHistory(); - if (ah != NULL) - ah->allLogString(fmt->data.string, sb); - out = sb.termedBuf(); - } - break; - - case LFT_ADAPTATION_LAST_HEADER: - if (al->request) { - const Adaptation::History::Pointer ah = al->request->adaptHistory(); - if (ah != NULL) // XXX: add adapt::allMeta.getByName(fmt->data.header.header); - } - - // XXX: here and elsewhere: move such code inside the if guard - out = sb.termedBuf(); - - quote = 1; - - break; - - case LFT_ADAPTATION_LAST_HEADER_ELEM: - if (al->request) { - const Adaptation::History::Pointer ah = al->request->adaptHistory(); - if (ah != NULL) // XXX: add adapt::allMeta.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator); - } - - out = sb.termedBuf(); - - quote = 1; - - break; - - case LFT_ADAPTATION_LAST_ALL_HEADERS: - out = al->adapt.last_meta; - - quote = 1; - - break; -#endif - -#if ICAP_CLIENT - case LFT_ICAP_ADDR: - if (!out) - out = al->icap.hostAddr.NtoA(tmp,1024); - break; - - case LFT_ICAP_SERV_NAME: - out = al->icap.serviceName.termedBuf(); - break; - - case LFT_ICAP_REQUEST_URI: - out = al->icap.reqUri.termedBuf(); - break; - - case LFT_ICAP_REQUEST_METHOD: - out = Adaptation::Icap::ICAP::methodStr(al->icap.reqMethod); - break; - - case LFT_ICAP_BYTES_SENT: - outoff = al->icap.bytesSent; - dooff = 1; - break; - - case LFT_ICAP_BYTES_READ: - outoff = al->icap.bytesRead; - dooff = 1; - break; - - case LFT_ICAP_BODY_BYTES_READ: - if (al->icap.bodyBytesRead >= 0) { - outoff = al->icap.bodyBytesRead; - dooff = 1; - } - // else if icap.bodyBytesRead < 0, we do not have any http data, - // so just print a "-" (204 responses etc) - break; - - case LFT_ICAP_REQ_HEADER: - if (NULL != al->icap.request) { - sb = al->icap.request->header.getByName(fmt->data.header.header); - out = sb.termedBuf(); - quote = 1; - } - break; - - case LFT_ICAP_REQ_HEADER_ELEM: - if (al->request) - sb = al->icap.request->header.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator); - - out = sb.termedBuf(); - - quote = 1; - - break; - - case LFT_ICAP_REQ_ALL_HEADERS: - if (al->icap.request) { - HttpHeaderPos pos = HttpHeaderInitPos; - while (const HttpHeaderEntry *e = al->icap.request->header.getEntry(&pos)) { - sb.append(e->name); - sb.append(": "); - sb.append(e->value); - sb.append("\r\n"); - } - out = sb.termedBuf(); - quote = 1; - } - break; - - case LFT_ICAP_REP_HEADER: - if (NULL != al->icap.reply) { - sb = al->icap.reply->header.getByName(fmt->data.header.header); - out = sb.termedBuf(); - quote = 1; - } - break; - - case LFT_ICAP_REP_HEADER_ELEM: - if (NULL != al->icap.reply) - sb = al->icap.reply->header.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator); - - out = sb.termedBuf(); - - quote = 1; - - break; - - case LFT_ICAP_REP_ALL_HEADERS: - if (al->icap.reply) { - HttpHeaderPos pos = HttpHeaderInitPos; - while (const HttpHeaderEntry *e = al->icap.reply->header.getEntry(&pos)) { - sb.append(e->name); - sb.append(": "); - sb.append(e->value); - sb.append("\r\n"); - } - out = sb.termedBuf(); - quote = 1; - } - break; - - case LFT_ICAP_TR_RESPONSE_TIME: - outint = al->icap.trTime; - doint = 1; - break; - - case LFT_ICAP_IO_TIME: - outint = al->icap.ioTime; - doint = 1; - break; - - case LFT_ICAP_STATUS_CODE: - outint = al->icap.resStatus; - doint = 1; - break; - - case LFT_ICAP_OUTCOME: - out = al->icap.outcome; - break; - - case LFT_ICAP_TOTAL_TIME: - outint = al->icap.processingTime; - doint = 1; - break; -#endif - case LFT_REQUEST_HEADER_ELEM: - if (al->request) - sb = al->request->header.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator); - - out = sb.termedBuf(); - - quote = 1; - - break; - - case LFT_ADAPTED_REQUEST_HEADER_ELEM: - if (al->adapted_request) - sb = al->adapted_request->header.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator); - - out = sb.termedBuf(); - - quote = 1; - - break; - - case LFT_REPLY_HEADER_ELEM: - if (al->reply) - sb = al->reply->header.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator); - - out = sb.termedBuf(); - - quote = 1; - - break; - - case LFT_REQUEST_ALL_HEADERS: - out = al->headers.request; - - quote = 1; - - break; - - case LFT_ADAPTED_REQUEST_ALL_HEADERS: - out = al->headers.adapted_request; - - quote = 1; - - break; - - case LFT_REPLY_ALL_HEADERS: - out = al->headers.reply; - - quote = 1; - - break; - - case LFT_USER_NAME: - out = Log::FormatName(al->cache.authuser); - - if (!out) - out = Log::FormatName(al->cache.extuser); - -#if USE_SSL - - if (!out) - out = Log::FormatName(al->cache.ssluser); - -#endif - - if (!out) - out = Log::FormatName(al->cache.rfc931); - - dofree = 1; - - break; - - case LFT_USER_LOGIN: - out = Log::FormatName(al->cache.authuser); - - dofree = 1; - - break; - - case LFT_USER_IDENT: - out = Log::FormatName(al->cache.rfc931); - - dofree = 1; - - break; - - case LFT_USER_EXTERNAL: - out = Log::FormatName(al->cache.extuser); - - dofree = 1; - - break; - - /* case LFT_USER_REALM: */ - /* case LFT_USER_SCHEME: */ - - // the fmt->type can not be LFT_HTTP_SENT_STATUS_CODE_OLD_30 - // but compiler complains if ommited - case LFT_HTTP_SENT_STATUS_CODE_OLD_30: - case LFT_HTTP_SENT_STATUS_CODE: - outint = al->http.code; - - doint = 1; - - break; - - case LFT_HTTP_RECEIVED_STATUS_CODE: - if (al->hier.peer_reply_status == HTTP_STATUS_NONE) { - out = "-"; - } else { - outint = al->hier.peer_reply_status; - doint = 1; - } - break; - /* case LFT_HTTP_STATUS: - * out = statusline->text; - * quote = 1; - * break; - */ - case LFT_HTTP_BODY_BYTES_READ: - if (al->hier.bodyBytesRead >= 0) { - outoff = al->hier.bodyBytesRead; - dooff = 1; - } - // else if hier.bodyBytesRead < 0 we did not have any data exchange with - // a peer server so just print a "-" (eg requests served from cache, - // or internal error messages). - break; - - case LFT_SQUID_STATUS: - if (al->http.timedout || al->http.aborted) { - snprintf(tmp, sizeof(tmp), "%s%s", log_tags[al->cache.code], - al->http.statusSfx()); - out = tmp; - } else { - out = log_tags[al->cache.code]; - } - - break; - - case LFT_SQUID_ERROR: - if (al->request && al->request->errType != ERR_NONE) - out = errorPageName(al->request->errType); - break; - - case LFT_SQUID_ERROR_DETAIL: - if (al->request && al->request->errDetail != ERR_DETAIL_NONE) { - if (al->request->errDetail > ERR_DETAIL_START && - al->request->errDetail < ERR_DETAIL_MAX) - out = errorDetailName(al->request->errDetail); - else { - if (al->request->errDetail >= ERR_DETAIL_EXCEPTION_START) - snprintf(tmp, sizeof(tmp), "%s=0x%X", - errorDetailName(al->request->errDetail), (uint32_t) al->request->errDetail); - else - snprintf(tmp, sizeof(tmp), "%s=%d", - errorDetailName(al->request->errDetail), al->request->errDetail); - out = tmp; - } - } - break; - - case LFT_SQUID_HIERARCHY: - if (al->hier.ping.timedout) - mb.append("TIMEOUT_", 8); - - out = hier_code_str[al->hier.code]; - - break; - - case LFT_MIME_TYPE: - out = al->http.content_type; - - break; - - case LFT_CLIENT_REQ_METHOD: - if (al->request) { - out = al->request->method.image(); - quote = 1; - } - break; - - case LFT_CLIENT_REQ_URI: - // original client URI - if (al->request) { - out = urlCanonical(al->request); - quote = 1; - } - break; - - case LFT_REQUEST_URLPATH_OLD_31: - case LFT_CLIENT_REQ_URLPATH: - if (al->request) { - out = al->request->urlpath.termedBuf(); - quote = 1; - } - break; - - case LFT_CLIENT_REQ_VERSION: - if (al->request) { - snprintf(tmp, sizeof(tmp), "%d.%d", (int) al->request->http_ver.major, (int) al->request->http_ver.minor); - out = tmp; - } - break; - - case LFT_REQUEST_METHOD: - out = al->_private.method_str; - break; - - case LFT_REQUEST_URI: - out = al->url; - break; - - case LFT_REQUEST_VERSION_OLD_2X: - case LFT_REQUEST_VERSION: - snprintf(tmp, sizeof(tmp), "%d.%d", (int) al->http.version.major, (int) al->http.version.minor); - out = tmp; - break; - - case LFT_SERVER_REQ_METHOD: - if (al->adapted_request) { - out = al->adapted_request->method.image(); - quote = 1; - } - break; - - case LFT_SERVER_REQ_URI: - // adapted request URI sent to server/peer - if (al->adapted_request) { - out = urlCanonical(al->adapted_request); - quote = 1; - } - break; - - case LFT_SERVER_REQ_URLPATH: - if (al->adapted_request) { - out = al->adapted_request->urlpath.termedBuf(); - quote = 1; - } - break; - - case LFT_SERVER_REQ_VERSION: - if (al->adapted_request) { - snprintf(tmp, sizeof(tmp), "%d.%d", - (int) al->adapted_request->http_ver.major, - (int) al->adapted_request->http_ver.minor); - out = tmp; - } - break; - - case LFT_REQUEST_SIZE_TOTAL: - outoff = al->cache.requestSize; - dooff = 1; - break; - - /*case LFT_REQUEST_SIZE_LINE: */ - case LFT_REQUEST_SIZE_HEADERS: - outoff = al->cache.requestHeadersSize; - dooff =1; - break; - /*case LFT_REQUEST_SIZE_BODY: */ - /*case LFT_REQUEST_SIZE_BODY_NO_TE: */ - - case LFT_REPLY_SIZE_TOTAL: - outoff = al->cache.replySize; - dooff = 1; - break; - - case LFT_REPLY_HIGHOFFSET: - outoff = al->cache.highOffset; - - dooff = 1; - - break; - - case LFT_REPLY_OBJECTSIZE: - outoff = al->cache.objectSize; - - dooff = 1; - - break; - - /*case LFT_REPLY_SIZE_LINE: */ - case LFT_REPLY_SIZE_HEADERS: - outint = al->cache.replyHeadersSize; - doint = 1; - break; - /*case LFT_REPLY_SIZE_BODY: */ - /*case LFT_REPLY_SIZE_BODY_NO_TE: */ - - case LFT_TAG: - if (al->request) - out = al->request->tag.termedBuf(); - - quote = 1; - - break; - - case LFT_IO_SIZE_TOTAL: - outint = al->cache.requestSize + al->cache.replySize; - doint = 1; - break; - - case LFT_EXT_LOG: - if (al->request) - out = al->request->extacl_log.termedBuf(); - - quote = 1; - - break; - - case LFT_SEQUENCE_NUMBER: - outoff = logfile->sequence_number; - dooff = 1; - break; - - case LFT_PERCENT: - out = "%"; - - break; - } - - if (dooff) { - snprintf(tmp, sizeof(tmp), "%0*" PRId64, fmt->zero ? (int) fmt->width : 0, outoff); - out = tmp; - - } else if (doint) { - snprintf(tmp, sizeof(tmp), "%0*ld", fmt->zero ? (int) fmt->width : 0, outint); - out = tmp; - } - - if (out && *out) { - if (quote || fmt->quote != LOG_QUOTE_NONE) { - char *newout = NULL; - int newfree = 0; - - switch (fmt->quote) { - - case LOG_QUOTE_NONE: - newout = rfc1738_escape_unescaped(out); - break; - - case LOG_QUOTE_QUOTES: { - size_t out_len = static_cast(strlen(out)) * 2 + 1; - if (out_len >= sizeof(tmp)) { - newout = (char *)xmalloc(out_len); - newfree = 1; - } else - newout = tmp; - log_quoted_string(out, newout); - } - break; - - case LOG_QUOTE_MIMEBLOB: - newout = Log::QuoteMimeBlob(out); - newfree = 1; - break; - - case LOG_QUOTE_URL: - newout = rfc1738_escape(out); - break; - - case LOG_QUOTE_RAW: - break; - } - - if (newout) { - if (dofree) - safe_free(out); - - out = newout; - - dofree = newfree; - } - } - - if (fmt->width) { - if (fmt->left) - mb.Printf("%-*s", (int) fmt->width, out); - else - mb.Printf("%*s", (int) fmt->width, out); - } else - mb.append(out, strlen(out)); - } else { - mb.append("-", 1); - } - - if (fmt->space) - mb.append(" ", 1); - - sb.clean(); - - if (dofree) - safe_free(out); - } + // XXX: because we do not yet have a neutral form of transaction slab. use AccessLogEntry + log->logFormat->assemble(mb, al, log->logfile->sequence_number); - logfilePrintf(logfile, "%s\n", mb.buf); + logfilePrintf(log->logfile, "%s\n", mb.buf); } diff --git a/src/log/FormatSquidIcap.cc b/src/log/FormatSquidIcap.cc index 5fccc88f9e..5b41dc3298 100644 --- a/src/log/FormatSquidIcap.cc +++ b/src/log/FormatSquidIcap.cc @@ -37,10 +37,10 @@ #if ICAP_CLIENT #include "AccessLogEntry.h" +#include "format/Quoting.h" #include "HttpRequest.h" #include "log/File.h" #include "log/Formats.h" -#include "log/Gadgets.h" #include "SquidTime.h" void @@ -59,18 +59,18 @@ Log::Format::SquidIcap(AccessLogEntry * al, Logfile * logfile) client = al->cache.caddr.NtoA(clientbuf, MAX_IPSTRLEN); } - user = Log::FormatName(al->cache.authuser); + user = ::Format::QuoteUrlEncodeUsername(al->cache.authuser); if (!user) - user = Log::FormatName(al->cache.extuser); + user = ::Format::QuoteUrlEncodeUsername(al->cache.extuser); #if USE_SSL if (!user) - user = Log::FormatName(al->cache.ssluser); + user = ::Format::QuoteUrlEncodeUsername(al->cache.ssluser); #endif if (!user) - user = Log::FormatName(al->cache.rfc931); + user = ::Format::QuoteUrlEncodeUsername(al->cache.rfc931); if (user && !*user) safe_free(user); diff --git a/src/log/FormatSquidNative.cc b/src/log/FormatSquidNative.cc index d523c57f73..8325eaad5a 100644 --- a/src/log/FormatSquidNative.cc +++ b/src/log/FormatSquidNative.cc @@ -34,10 +34,10 @@ #include "config.h" #include "AccessLogEntry.h" +#include "format/Quoting.h" +#include "format/Tokens.h" #include "log/File.h" #include "log/Formats.h" -#include "log/Gadgets.h" -#include "log/Tokens.h" #include "SquidTime.h" void @@ -46,18 +46,18 @@ Log::Format::SquidNative(AccessLogEntry * al, Logfile * logfile) const char *user = NULL; char clientip[MAX_IPSTRLEN]; - user = FormatName(al->cache.authuser); + user = ::Format::QuoteUrlEncodeUsername(al->cache.authuser); if (!user) - user = FormatName(al->cache.extuser); + user = ::Format::QuoteUrlEncodeUsername(al->cache.extuser); #if USE_SSL if (!user) - user = FormatName(al->cache.ssluser); + user = ::Format::QuoteUrlEncodeUsername(al->cache.ssluser); #endif if (!user) - user = FormatName(al->cache.rfc931); + user = ::Format::QuoteUrlEncodeUsername(al->cache.rfc931); if (user && !*user) safe_free(user); @@ -67,7 +67,7 @@ Log::Format::SquidNative(AccessLogEntry * al, Logfile * logfile) (int) current_time.tv_usec / 1000, al->cache.msec, al->cache.caddr.NtoA(clientip, MAX_IPSTRLEN), - log_tags[al->cache.code], + ::Format::log_tags[al->cache.code], al->http.statusSfx(), al->http.code, al->cache.replySize, @@ -83,8 +83,8 @@ Log::Format::SquidNative(AccessLogEntry * al, Logfile * logfile) safe_free(user); if (Config.onoff.log_mime_hdrs) { - char *ereq = QuoteMimeBlob(al->headers.request); - char *erep = QuoteMimeBlob(al->headers.reply); + char *ereq = ::Format::QuoteMimeBlob(al->headers.request); + char *erep = ::Format::QuoteMimeBlob(al->headers.reply); logfilePrintf(logfile, " [%s] [%s]\n", ereq, erep); safe_free(ereq); safe_free(erep); diff --git a/src/log/Makefile.am b/src/log/Makefile.am index cab6f05580..48a083b603 100644 --- a/src/log/Makefile.am +++ b/src/log/Makefile.am @@ -17,8 +17,6 @@ liblog_la_SOURCES = \ FormatSquidNative.cc \ FormatSquidReferer.cc \ FormatSquidUseragent.cc \ - Gadgets.cc \ - Gadgets.h \ ModDaemon.cc \ ModDaemon.h \ ModStdio.cc \ @@ -28,7 +26,5 @@ liblog_la_SOURCES = \ ModTcp.cc \ ModTcp.h \ ModUdp.cc \ - ModUdp.h \ - Tokens.cc \ - Tokens.h + ModUdp.h diff --git a/src/log/Tokens.cc b/src/log/Tokens.cc deleted file mode 100644 index 76c2507e02..0000000000 --- a/src/log/Tokens.cc +++ /dev/null @@ -1,734 +0,0 @@ -/* - * $Id$ - * - * DEBUG: section 46 Access Log Format Tokens - * AUTHOR: Duane Wessels - * - * 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 "config.h" -#include "log/Tokens.h" -#include "Store.h" - -const char *log_tags[] = { - "NONE", - "TCP_HIT", - "TCP_MISS", - "TCP_REFRESH_UNMODIFIED", - "TCP_REFRESH_FAIL", // same tag logged for LOG_TCP_REFRESH_FAIL_OLD and - "TCP_REFRESH_FAIL", // LOG_TCP_REFRESH_FAIL_ERR for backward-compatibility - "TCP_REFRESH_MODIFIED", - "TCP_CLIENT_REFRESH_MISS", - "TCP_IMS_HIT", - "TCP_SWAPFAIL_MISS", - "TCP_NEGATIVE_HIT", - "TCP_MEM_HIT", - "TCP_DENIED", - "TCP_DENIED_REPLY", - "TCP_OFFLINE_HIT", -#if LOG_TCP_REDIRECTS - "TCP_REDIRECT", -#endif - "UDP_HIT", - "UDP_MISS", - "UDP_DENIED", - "UDP_INVALID", - "UDP_MISS_NOFETCH", - "ICP_QUERY", - "LOG_TYPE_MAX" -}; - -#if USE_ADAPTATION -bool alLogformatHasAdaptToken = false; -#endif - -#if ICAP_CLIENT -bool alLogformatHasIcapToken = false; -#endif - -struct logformat_token_table_entry logformat_token_table[] = { - - {">a", LFT_CLIENT_IP_ADDRESS}, - {">p", LFT_CLIENT_PORT}, - {">A", LFT_CLIENT_FQDN}, -#if USE_SQUID_EUI - {">eui", LFT_CLIENT_EUI}, -#endif - - /*{ "ha", LFT_ADAPTED_REQUEST_HEADER}, - {">ha", LFT_ADAPTED_REQUEST_ALL_HEADERS}, - {">h", LFT_REQUEST_HEADER}, - {">h", LFT_REQUEST_ALL_HEADERS}, - {"Hs", LFT_HTTP_SENT_STATUS_CODE}, - {"rm", LFT_CLIENT_REQ_METHOD}, - {">ru", LFT_CLIENT_REQ_URI}, - {">rp", LFT_CLIENT_REQ_URLPATH}, - /*{">rq", LFT_CLIENT_REQ_QUERY},*/ - {">rv", LFT_CLIENT_REQ_VERSION}, - - {"rm", LFT_REQUEST_METHOD}, - {"ru", LFT_REQUEST_URI}, /* doesn't include the query-string */ - {"rp", LFT_REQUEST_URLPATH_OLD_31}, - /* { "rq", LFT_REQUEST_QUERY }, * / / * the query-string, INCLUDING the leading ? */ - {">v", LFT_REQUEST_VERSION_OLD_2X}, - {"rv", LFT_REQUEST_VERSION}, - - {"st", LFT_REQUEST_SIZE_TOTAL }, - /*{ ">sl", LFT_REQUEST_SIZE_LINE }, * / / * the request line "GET ... " */ - { ">sh", LFT_REQUEST_SIZE_HEADERS }, - /*{ ">sb", LFT_REQUEST_SIZE_BODY }, */ - /*{ ">sB", LFT_REQUEST_SIZE_BODY_NO_TE }, */ - - {"st", LFT_ICAP_BYTES_SENT}, - {"icap::h", LFT_ICAP_REQ_HEADER}, - {"icap:: 0) { - char *cp; - /* it's a string for sure, until \0 or the next % */ - cp = (char *)xmalloc(l + 1); - xstrncpy(cp, cur, l + 1); - lt->type = LFT_STRING; - lt->data.string = cp; - - while (l > 0) { - switch (*cur) { - - case '"': - - if (*quote == LOG_QUOTE_NONE) - *quote = LOG_QUOTE_QUOTES; - else if (*quote == LOG_QUOTE_QUOTES) - *quote = LOG_QUOTE_NONE; - - break; - - case '[': - if (*quote == LOG_QUOTE_NONE) - *quote = LOG_QUOTE_MIMEBLOB; - - break; - - case ']': - if (*quote == LOG_QUOTE_MIMEBLOB) - *quote = LOG_QUOTE_NONE; - - break; - } - - cur++; - l--; - } - - goto done; - } - - if (!*cur) - goto done; - - cur++; - - switch (*cur) { - - case '"': - lt->quote = LOG_QUOTE_QUOTES; - cur++; - break; - - case '\'': - lt->quote = LOG_QUOTE_RAW; - cur++; - break; - - case '[': - lt->quote = LOG_QUOTE_MIMEBLOB; - cur++; - break; - - case '#': - lt->quote = LOG_QUOTE_URL; - cur++; - break; - - default: - lt->quote = *quote; - break; - } - - if (*cur == '-') { - lt->left = 1; - cur++; - } - - if (*cur == '0') { - lt->zero = 1; - cur++; - } - - if (xisdigit(*cur)) - lt->width = strtol(cur, &cur, 10); - - if (*cur == '.') - lt->precision = strtol(cur + 1, &cur, 10); - - if (*cur == '{') { - char *cp; - cur++; - l = strcspn(cur, "}"); - cp = (char *)xmalloc(l + 1); - xstrncpy(cp, cur, l + 1); - lt->data.string = cp; - cur += l; - - if (*cur == '}') - cur++; - } - - // For upward compatibility, assume "http::" prefix as default prefix - // for all log access formating codes, except those starting - // from "icap::", "adapt::" and "%" - if (strncmp(cur,"http::", 6) == 0 && - strncmp(cur+6, "icap::", 6) != 0 && - strncmp(cur+6, "adapt::", 12) != 0 && *(cur+6) != '%' ) { - cur += 6; - } - - lt->type = LFT_NONE; - - for (lte = logformat_token_table; lte->config != NULL; lte++) { - if (strncmp(lte->config, cur, strlen(lte->config)) == 0) { - lt->type = lte->token_type; - cur += strlen(lte->config); - break; - } - } - - if (lt->type == LFT_NONE) { - fatalf("Can't parse configuration token: '%s'\n", - def); - } - - if (*cur == ' ') { - lt->space = 1; - cur++; - } - -done: - - switch (lt->type) { - -#if USE_ADAPTATION - case LFT_ADAPTATION_LAST_HEADER: -#endif - -#if ICAP_CLIENT - case LFT_ICAP_REQ_HEADER: - - case LFT_ICAP_REP_HEADER: -#endif - - case LFT_ADAPTED_REQUEST_HEADER: - - case LFT_REQUEST_HEADER: - - case LFT_REPLY_HEADER: - - if (lt->data.string) { - char *header = lt->data.string; - char *cp = strchr(header, ':'); - - if (cp) { - *cp++ = '\0'; - - if (*cp == ',' || *cp == ';' || *cp == ':') - lt->data.header.separator = *cp++; - else - lt->data.header.separator = ','; - - lt->data.header.element = cp; - - switch (lt->type) { - case LFT_REQUEST_HEADER: - lt->type = LFT_REQUEST_HEADER_ELEM; - break; - - case LFT_ADAPTED_REQUEST_HEADER: - lt->type = LFT_ADAPTED_REQUEST_HEADER_ELEM; - break; - - case LFT_REPLY_HEADER: - lt->type = LFT_REPLY_HEADER_ELEM; - break; -#if USE_ADAPTATION - case LFT_ADAPTATION_LAST_HEADER: - lt->type = LFT_ADAPTATION_LAST_HEADER_ELEM; - break; -#endif -#if ICAP_CLIENT - case LFT_ICAP_REQ_HEADER: - lt->type = LFT_ICAP_REQ_HEADER_ELEM; - break; - case LFT_ICAP_REP_HEADER: - lt->type = LFT_ICAP_REP_HEADER_ELEM; - break; -#endif - default: - break; - } - } - - lt->data.header.header = header; - } else { - switch (lt->type) { - case LFT_REQUEST_HEADER: - lt->type = LFT_REQUEST_ALL_HEADERS; - break; - - case LFT_ADAPTED_REQUEST_HEADER: - lt->type = LFT_ADAPTED_REQUEST_ALL_HEADERS; - break; - - case LFT_REPLY_HEADER: - lt->type = LFT_REPLY_ALL_HEADERS; - break; -#if USE_ADAPTATION - case LFT_ADAPTATION_LAST_HEADER: - lt->type = LFT_ADAPTATION_LAST_ALL_HEADERS; - break; -#endif -#if ICAP_CLIENT - case LFT_ICAP_REQ_HEADER: - lt->type = LFT_ICAP_REQ_ALL_HEADERS; - break; - case LFT_ICAP_REP_HEADER: - lt->type = LFT_ICAP_REP_ALL_HEADERS; - break; -#endif - default: - break; - } - Config.onoff.log_mime_hdrs = 1; - } - - break; - - case LFT_CLIENT_FQDN: - Config.onoff.log_fqdn = 1; - break; - - case LFT_TIME_SUBSECOND: - lt->divisor = 1000; - - if (lt->precision) { - int i; - lt->divisor = 1000000; - - for (i = lt->precision; i > 1; i--) - lt->divisor /= 10; - - if (!lt->divisor) - lt->divisor = 0; - } - - break; - - case LFT_HTTP_SENT_STATUS_CODE_OLD_30: - debugs(46, 0, "WARNING: The \"Hs\" formatting code is deprecated. Use the \">Hs\" instead."); - lt->type = LFT_HTTP_SENT_STATUS_CODE; - break; - - case LFT_PEER_LOCAL_IP_OLD_27: - debugs(46, 0, "WARNING: The \"oa\" formatting code is deprecated. Use the \"type = LFT_PEER_LOCAL_IP; - break; - - case LFT_REQUEST_URLPATH_OLD_31: - debugs(46, 0, "WARNING: The \"rp\" formatting code is deprecated. Use the \">rp\" instead."); - lt->type = LFT_CLIENT_REQ_URLPATH; - break; - - case LFT_REQUEST_VERSION_OLD_2X: - debugs(46, 0, "WARNING: The \">v\" formatting code is deprecated. Use the \">rv\" instead."); - lt->type = LFT_REQUEST_VERSION; - break; - - default: - break; - } - - return (cur - def); -} - -int -accessLogParseLogFormat(logformat_token ** fmt, char *def) -{ - char *cur, *eos; - logformat_token *new_lt, *last_lt; - enum log_quote quote = LOG_QUOTE_NONE; - - debugs(46, 2, "accessLogParseLogFormat: got definition '" << def << "'"); - - /* very inefficent parser, but who cares, this needs to be simple */ - /* First off, let's tokenize, we'll optimize in a second pass. - * A token can either be a %-prefixed sequence (usually a dynamic - * token but it can be an escaped sequence), or a string. */ - cur = def; - eos = def + strlen(def); - *fmt = new_lt = last_lt = (logformat_token *)xmalloc(sizeof(logformat_token)); - cur += accessLogGetNewLogFormatToken(new_lt, cur, "e); - - while (cur < eos) { - new_lt = (logformat_token *)xmalloc(sizeof(logformat_token)); - last_lt->next = new_lt; - last_lt = new_lt; - cur += accessLogGetNewLogFormatToken(new_lt, cur, "e); - } - - return 1; -} - -void -accessLogDumpLogFormat(StoreEntry * entry, const char *name, logformat * definitions) -{ - logformat_token *t; - logformat *format; - - struct logformat_token_table_entry *te; - debugs(46, 4, "accessLogDumpLogFormat called"); - - for (format = definitions; format; format = format->next) { - debugs(46, 3, "Dumping logformat definition for " << format->name); - storeAppendPrintf(entry, "logformat %s ", format->name); - - for (t = format->format; t; t = t->next) { - if (t->type == LFT_STRING) - storeAppendPrintf(entry, "%s", t->data.string); - else { - char argbuf[256]; - char *arg = NULL; - logformat_bcode_t type = t->type; - - switch (type) { - /* special cases */ - - case LFT_STRING: - break; -#if USE_ADAPTATION - case LFT_ADAPTATION_LAST_HEADER_ELEM: -#endif -#if ICAP_CLIENT - case LFT_ICAP_REQ_HEADER_ELEM: - case LFT_ICAP_REP_HEADER_ELEM: -#endif - case LFT_REQUEST_HEADER_ELEM: - case LFT_ADAPTED_REQUEST_HEADER_ELEM: - case LFT_REPLY_HEADER_ELEM: - - if (t->data.header.separator != ',') - snprintf(argbuf, sizeof(argbuf), "%s:%c%s", t->data.header.header, t->data.header.separator, t->data.header.element); - else - snprintf(argbuf, sizeof(argbuf), "%s:%s", t->data.header.header, t->data.header.element); - - arg = argbuf; - - switch (type) { - case LFT_REQUEST_HEADER_ELEM: - type = LFT_REQUEST_HEADER_ELEM; // XXX: remove _ELEM? - break; - case LFT_ADAPTED_REQUEST_HEADER_ELEM: - type = LFT_ADAPTED_REQUEST_HEADER_ELEM; // XXX: remove _ELEM? - break; - case LFT_REPLY_HEADER_ELEM: - type = LFT_REPLY_HEADER_ELEM; // XXX: remove _ELEM? - break; -#if USE_ADAPTATION - case LFT_ADAPTATION_LAST_HEADER_ELEM: - type = LFT_ADAPTATION_LAST_HEADER; - break; -#endif -#if ICAP_CLIENT - case LFT_ICAP_REQ_HEADER_ELEM: - type = LFT_ICAP_REQ_HEADER; - break; - case LFT_ICAP_REP_HEADER_ELEM: - type = LFT_ICAP_REP_HEADER; - break; -#endif - default: - break; - } - - break; - - case LFT_REQUEST_ALL_HEADERS: - case LFT_ADAPTED_REQUEST_ALL_HEADERS: - case LFT_REPLY_ALL_HEADERS: - -#if USE_ADAPTATION - case LFT_ADAPTATION_LAST_ALL_HEADERS: -#endif -#if ICAP_CLIENT - case LFT_ICAP_REQ_ALL_HEADERS: - case LFT_ICAP_REP_ALL_HEADERS: -#endif - - switch (type) { - case LFT_REQUEST_ALL_HEADERS: - type = LFT_REQUEST_HEADER; - break; - case LFT_ADAPTED_REQUEST_ALL_HEADERS: - type = LFT_ADAPTED_REQUEST_HEADER; - break; - case LFT_REPLY_ALL_HEADERS: - type = LFT_REPLY_HEADER; - break; -#if USE_ADAPTATION - case LFT_ADAPTATION_LAST_ALL_HEADERS: - type = LFT_ADAPTATION_LAST_HEADER; - break; -#endif -#if ICAP_CLIENT - case LFT_ICAP_REQ_ALL_HEADERS: - type = LFT_ICAP_REQ_HEADER; - break; - case LFT_ICAP_REP_ALL_HEADERS: - type = LFT_ICAP_REP_HEADER; - break; -#endif - default: - break; - } - - break; - - default: - if (t->data.string) - arg = t->data.string; - - break; - } - - entry->append("%", 1); - - switch (t->quote) { - - case LOG_QUOTE_QUOTES: - entry->append("\"", 1); - break; - - case LOG_QUOTE_MIMEBLOB: - entry->append("[", 1); - break; - - case LOG_QUOTE_URL: - entry->append("#", 1); - break; - - case LOG_QUOTE_RAW: - entry->append("'", 1); - break; - - case LOG_QUOTE_NONE: - break; - } - - if (t->left) - entry->append("-", 1); - - if (t->zero) - entry->append("0", 1); - - if (t->width) - storeAppendPrintf(entry, "%d", (int) t->width); - - if (t->precision) - storeAppendPrintf(entry, ".%d", (int) t->precision); - - if (arg) - storeAppendPrintf(entry, "{%s}", arg); - - for (te = logformat_token_table; te->config != NULL; te++) { - if (te->token_type == type) { - storeAppendPrintf(entry, "%s", te->config); - break; - } - } - - if (t->space) - entry->append(" ", 1); - - assert(te->config != NULL); - } - } - - entry->append("\n", 1); - } - -} - -void -accessLogFreeLogFormat(logformat_token ** tokens) -{ - while (*tokens) { - logformat_token *token = *tokens; - *tokens = token->next; - safe_free(token->data.string); - xfree(token); - } -} - -logformat::logformat(const char *n) : - format(NULL), - next(NULL) -{ - name = xstrdup(n); -} - -logformat::~logformat() -{ - // erase the list without consuming stack space - while (next) { - // unlink the next entry for deletion - logformat *temp = next; - next = temp->next; - temp->next = NULL; - delete temp; - } - - // remove locals - xfree(name); - accessLogFreeLogFormat(&format); -} diff --git a/src/log/access_log.cc b/src/log/access_log.cc index e2f75ddffb..a1160e1fb5 100644 --- a/src/log/access_log.cc +++ b/src/log/access_log.cc @@ -47,13 +47,13 @@ #include "eui/Eui48.h" #include "eui/Eui64.h" #endif +#include "format/Tokens.h" #include "hier_code.h" #include "HttpReply.h" #include "HttpRequest.h" +#include "log/Config.h" #include "log/File.h" #include "log/Formats.h" -#include "log/Gadgets.h" -#include "log/Tokens.h" #include "MemBuf.h" #include "mgr/Registration.h" #include "rfc1738.h" @@ -297,10 +297,10 @@ accessLogInit(void) accessLogRegisterWithCacheManager(); #if USE_ADAPTATION - alLogformatHasAdaptToken = false; + Log::TheConfig.hasAdaptToken = false; #endif #if ICAP_CLIENT - alLogformatHasIcapToken = false; + Log::TheConfig.hasIcapToken = false; #endif for (log = Config.Log.accesslogs; log; log = log->next) { @@ -312,17 +312,17 @@ accessLogInit(void) LogfileStatus = LOG_ENABLE; #if USE_ADAPTATION - for (logformat_token * curr_token = (log->logFormat?log->logFormat->format:NULL); curr_token; curr_token = curr_token->next) { - if (curr_token->type == LTF_ADAPTATION_SUM_XACT_TIMES || - curr_token->type == LTF_ADAPTATION_ALL_XACT_TIMES || - curr_token->type == LFT_ADAPTATION_LAST_HEADER || - curr_token->type == LFT_ADAPTATION_LAST_HEADER_ELEM || - curr_token->type == LFT_ADAPTATION_LAST_ALL_HEADERS) { - alLogformatHasAdaptToken = true; + for (Format::Token * curr_token = (log->logFormat?log->logFormat->format:NULL); curr_token; curr_token = curr_token->next) { + if (curr_token->type == Format::LTF_ADAPTATION_SUM_XACT_TIMES || + curr_token->type == Format::LTF_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) { + Log::TheConfig.hasAdaptToken = true; } #if ICAP_CLIENT - if (curr_token->type == LFT_ICAP_TOTAL_TIME) { - alLogformatHasIcapToken = true; + if (curr_token->type == Format::LFT_ICAP_TOTAL_TIME) { + Log::TheConfig.hasIcapToken = true; } #endif } diff --git a/src/stat.cc b/src/stat.cc index f49f936f84..206d049f93 100644 --- a/src/stat.cc +++ b/src/stat.cc @@ -34,6 +34,7 @@ #include "squid.h" #include "event.h" +#include "format/Tokens.h" #include "StoreClient.h" #if USE_AUTH #include "auth/UserRequest.h" @@ -42,7 +43,6 @@ #include "mgr/Registration.h" #include "Store.h" #include "HttpRequest.h" -#include "log/Tokens.h" #include "MemObject.h" #include "fde.h" #include "mem_node.h" @@ -2038,7 +2038,7 @@ statClientRequests(StoreEntry * s) } storeAppendPrintf(s, "uri %s\n", http->uri); - storeAppendPrintf(s, "logType %s\n", log_tags[http->logType]); + storeAppendPrintf(s, "logType %s\n", Format::log_tags[http->logType]); storeAppendPrintf(s, "out.offset %ld, out.size %lu\n", (long int) http->out.offset, (unsigned long int) http->out.size); storeAppendPrintf(s, "req_sz %ld\n", (long int) http->req_sz); diff --git a/src/store_log.cc b/src/store_log.cc index 56bbcec8c2..c68c377162 100644 --- a/src/store_log.cc +++ b/src/store_log.cc @@ -33,9 +33,9 @@ */ #include "squid.h" +#include "format/Tokens.h" #include "HttpReply.h" #include "log/File.h" -#include "log/Tokens.h" #include "MemObject.h" #include "mgr/Registration.h" #include "Store.h" diff --git a/src/structs.h b/src/structs.h index 8598d08056..69d1a7ab0b 100644 --- a/src/structs.h +++ b/src/structs.h @@ -1289,13 +1289,13 @@ struct _store_rebuild_data { }; class Logfile; -class logformat; +#include "format/Format.h" #include "log/Formats.h" struct _customlog { char *filename; ACLList *aclList; - logformat *logFormat; + Format::Format *logFormat; Logfile *logfile; customlog *next; Log::Format::log_type type; -- 2.39.2