From: Alex Rousskov Date: Fri, 18 Feb 2011 23:58:13 +0000 (-0700) Subject: Merged from parent (trunk r11240, circa 3.2.0.5+) X-Git-Tag: take03 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=ed23106148e17198c6c7029e1feec1f3e6ab682d;p=thirdparty%2Fsquid.git Merged from parent (trunk r11240, circa 3.2.0.5+) --- ed23106148e17198c6c7029e1feec1f3e6ab682d diff --cc src/Makefile.am index 1402f4f106,97467ac1ad..10cc287185 --- a/src/Makefile.am +++ b/src/Makefile.am @@@ -49,6 -52,20 +52,20 @@@ SSL_LIBS = else SSL_LOCAL_LIBS = endif + DIST_SUBDIRS += ssl + + SNMP_ALL_SOURCE = \ + snmp_core.h \ + snmp_core.cc \ + snmp_agent.cc + if ENABLE_SNMP + SNMP_SOURCE = $(SNMP_ALL_SOURCE) + SUBDIRS += snmp -SNMP_LIBS = snmp/libsnmp.la ++SNMP_LIBS = snmp/libsnmp.la $(SNMPLIB) + else + SNMP_SOURCE = + endif + DIST_SUBDIRS += snmp if USE_ADAPTATION SUBDIRS += adaptation diff --cc src/adaptation/ecap/MessageRep.cc index 23a0833e5b,56281fef3a..eda4f17f60 --- a/src/adaptation/ecap/MessageRep.cc +++ b/src/adaptation/ecap/MessageRep.cc @@@ -59,19 -61,11 +62,22 @@@ Adaptation::Ecap::HeaderRep::removeAny( theHeader.delByName(name.image().c_str()); else theHeader.delById(squidId); + + if (squidId == HDR_CONTENT_LENGTH) + theMessage.content_length = theHeader.getInt64(HDR_CONTENT_LENGTH); } +void +Adaptation::Ecap::HeaderRep::visitEach(libecap::NamedValueVisitor &visitor) const +{ + HttpHeaderPos pos = HttpHeaderInitPos; + while (HttpHeaderEntry *e = theHeader.getEntry(&pos)) { + const Name name(e->name.termedBuf()); // optimize: find std Names + name.assignHostId(e->id); + visitor.visit(name, Value(e->value.rawBuf(), e->value.size())); + } +} + libecap::Area Adaptation::Ecap::HeaderRep::image() const { diff --cc src/log/FormatSquidCustom.cc index 0000000000,f1a031ceac..80db596c63 mode 000000,100644..100644 --- a/src/log/FormatSquidCustom.cc +++ b/src/log/FormatSquidCustom.cc @@@ -1,0 -1,818 +1,819 @@@ + /* + * $Id$ + * + * DEBUG: section 46 Access Log - Squid Custom format + * 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 "AccessLogEntry.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: + if (al->request) { + if (al->cache.caddr.IsIPv4()) + al->request->client_eui48.encode(tmp, 1024); + else + al->request->client_eui64.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,1024); + } + + break; + + case LFT_LOCAL_PORT: + if (al->request) { + outint = al->request->my_addr.GetPort(); + doint = 1; + } + + break; + + case LFT_PEER_LOCAL_PORT: + if (al->hier.peer_local_port) { + outint = al->hier.peer_local_port; + 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; -#endif + -#if ICAP_CLIENT - case LFT_ICAP_LAST_MATCHED_HEADER: ++ case LFT_ADAPTATION_LAST_HEADER: + if (al->request) { - Adaptation::Icap::History::Pointer ih = al->request->icapHistory(); - if (ih != NULL) - sb = ih->mergeOfIcapHeaders.getByName(fmt->data.header.header); ++ 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_ICAP_LAST_MATCHED_HEADER_ELEM: ++ case LFT_ADAPTATION_LAST_HEADER_ELEM: + if (al->request) { - Adaptation::Icap::History::Pointer ih = al->request->icapHistory(); - if (ih != NULL) - sb = ih->mergeOfIcapHeaders.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator); ++ 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_ICAP_LAST_MATCHED_ALL_HEADERS: - out = al->headers.icap; ++ case LFT_ADAPTATION_LAST_ALL_HEADERS: ++ out = al->headers.adapt_last; + + 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_REQUEST_METHOD: + out = al->_private.method_str; + + break; + + case LFT_REQUEST_URI: + out = al->url; + + break; + + case LFT_REQUEST_URLPATH: + if (al->request) { + out = al->request->urlpath.termedBuf(); + quote = 1; + } + break; + + 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_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); + } + + logfilePrintf(logfile, "%s\n", mb.buf); + } diff --cc src/log/Tokens.cc index 0000000000,4afb57b31f..0d5a179572 mode 000000,100644..100644 --- a/src/log/Tokens.cc +++ b/src/log/Tokens.cc @@@ -1,0 -1,690 +1,705 @@@ + /* + * $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}, + {"v", LFT_REQUEST_VERSION}, + {"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 ICAP_CLIENT - case LFT_ICAP_LAST_MATCHED_HEADER: ++#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 ICAP_CLIENT - case LFT_ICAP_LAST_MATCHED_HEADER: - lt->type = LFT_ICAP_LAST_MATCHED_HEADER_ELEM; ++#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 ICAP_CLIENT - case LFT_ICAP_LAST_MATCHED_HEADER: - lt->type = LFT_ICAP_LAST_MATCHED_ALL_HEADERS; ++#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\" formating code is deprecated use the \">Hs\" instead"); + lt->type = LFT_HTTP_SENT_STATUS_CODE; + 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_LAST_MATCHED_HEADER_ELEM: + 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; ++ type = LFT_REQUEST_HEADER_ELEM; // XXX: remove _ELEM? + break; + case LFT_ADAPTED_REQUEST_HEADER_ELEM: - type = 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; ++ type = LFT_REPLY_HEADER_ELEM; // XXX: remove _ELEM? + break; -#if ICAP_CLIENT - case LFT_ICAP_LAST_MATCHED_HEADER_ELEM: - type = LFT_ICAP_LAST_MATCHED_HEADER; ++#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_LAST_MATCHED_ALL_HEADERS: + 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 ICAP_CLIENT - case LFT_ICAP_LAST_MATCHED_ALL_HEADERS: - type = LFT_ICAP_LAST_MATCHED_HEADER; ++#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 --cc src/log/Tokens.h index 0000000000,36316d454e..54cffff0d0 mode 000000,100644..100644 --- a/src/log/Tokens.h +++ b/src/log/Tokens.h @@@ -1,0 -1,246 +1,246 @@@ + /* + * $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. + * + */ + #ifndef _SQUID_LOG_TOKENS_H + #define _SQUID_LOG_TOKENS_H + + class StoreEntry; + + #define LOG_BUF_SZ (MAX_URL<<2) + + /* + * Bytecodes for the configureable logformat stuff + */ + typedef enum { + LFT_NONE, /* dummy */ + LFT_STRING, + + LFT_CLIENT_IP_ADDRESS, + LFT_CLIENT_FQDN, + LFT_CLIENT_PORT, + #if USE_SQUID_EUI + LFT_CLIENT_EUI, + #endif + + /*LFT_SERVER_IP_ADDRESS, */ + LFT_SERVER_IP_OR_PEER_NAME, + /*LFT_SERVER_PORT, */ + + LFT_LOCAL_IP, + LFT_LOCAL_PORT, + /*LFT_LOCAL_NAME, */ + LFT_PEER_LOCAL_PORT, + + LFT_TIME_SECONDS_SINCE_EPOCH, + LFT_TIME_SUBSECOND, + LFT_TIME_LOCALTIME, + LFT_TIME_GMT, + LFT_TIME_TO_HANDLE_REQUEST, + + LFT_PEER_RESPONSE_TIME, + LFT_TOTAL_SERVER_SIDE_RESPONSE_TIME, + LFT_DNS_WAIT_TIME, + + LFT_REQUEST_HEADER, + LFT_REQUEST_HEADER_ELEM, + LFT_REQUEST_ALL_HEADERS, + + LFT_ADAPTED_REQUEST_HEADER, + LFT_ADAPTED_REQUEST_HEADER_ELEM, + LFT_ADAPTED_REQUEST_ALL_HEADERS, + + LFT_REPLY_HEADER, + LFT_REPLY_HEADER_ELEM, + LFT_REPLY_ALL_HEADERS, + + LFT_USER_NAME, + LFT_USER_LOGIN, + LFT_USER_IDENT, + /*LFT_USER_REALM, */ + /*LFT_USER_SCHEME, */ + LFT_USER_EXTERNAL, + + LFT_HTTP_SENT_STATUS_CODE_OLD_30, + LFT_HTTP_SENT_STATUS_CODE, + LFT_HTTP_RECEIVED_STATUS_CODE, + /*LFT_HTTP_STATUS, */ + LFT_HTTP_BODY_BYTES_READ, + + LFT_SQUID_STATUS, + LFT_SQUID_ERROR, + LFT_SQUID_ERROR_DETAIL, + LFT_SQUID_HIERARCHY, + + LFT_MIME_TYPE, + + LFT_REQUEST_METHOD, + LFT_REQUEST_URI, + LFT_REQUEST_URLPATH, + /*LFT_REQUEST_QUERY, * // * this is not needed. see strip_query_terms */ + LFT_REQUEST_VERSION, + + LFT_REQUEST_SIZE_TOTAL, + /*LFT_REQUEST_SIZE_LINE, */ + LFT_REQUEST_SIZE_HEADERS, + /*LFT_REQUEST_SIZE_BODY, */ + /*LFT_REQUEST_SIZE_BODY_NO_TE, */ + + LFT_REPLY_SIZE_TOTAL, + LFT_REPLY_HIGHOFFSET, + LFT_REPLY_OBJECTSIZE, + /*LFT_REPLY_SIZE_LINE, */ + LFT_REPLY_SIZE_HEADERS, + /*LFT_REPLY_SIZE_BODY, */ + /*LFT_REPLY_SIZE_BODY_NO_TE, */ + + LFT_TAG, + LFT_IO_SIZE_TOTAL, + LFT_EXT_LOG, + + LFT_SEQUENCE_NUMBER, + + #if USE_ADAPTATION + LTF_ADAPTATION_SUM_XACT_TIMES, + LTF_ADAPTATION_ALL_XACT_TIMES, ++ LFT_ADAPTATION_LAST_HEADER, ++ LFT_ADAPTATION_LAST_HEADER_ELEM, ++ LFT_ADAPTATION_LAST_ALL_HEADERS, + #endif + + #if ICAP_CLIENT + + LFT_ICAP_TOTAL_TIME, - LFT_ICAP_LAST_MATCHED_HEADER, - LFT_ICAP_LAST_MATCHED_HEADER_ELEM, - LFT_ICAP_LAST_MATCHED_ALL_HEADERS, + + LFT_ICAP_ADDR, + LFT_ICAP_SERV_NAME, + LFT_ICAP_REQUEST_URI, + LFT_ICAP_REQUEST_METHOD, + LFT_ICAP_BYTES_SENT, + LFT_ICAP_BYTES_READ, + LFT_ICAP_BODY_BYTES_READ, + + 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 + + LFT_PERCENT /* special string cases for escaped chars */ + } logformat_bcode_t; + + enum log_quote { + LOG_QUOTE_NONE = 0, + LOG_QUOTE_QUOTES, + LOG_QUOTE_MIMEBLOB, + LOG_QUOTE_URL, + LOG_QUOTE_RAW + }; + + /* FIXME: public class so we can pre-define its type. */ + class logformat_token + { + public: + logformat_bcode_t type; + union { + char *string; + + struct { + char *header; + char *element; + char separator; + } header; + char *timespec; + } data; + unsigned char width; + unsigned char precision; + enum log_quote 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 */ + }; + + struct logformat_token_table_entry { + const char *config; + logformat_bcode_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); + + void accessLogFreeLogFormat(logformat_token ** tokens); + + #endif /* _SQUID_LOG_TOKENS_H */