=== modified file 'src/AccessLogEntry.cc' --- src/AccessLogEntry.cc 2012-01-20 18:55:04 +0000 +++ src/AccessLogEntry.cc 2012-07-11 18:16:51 +0000 @@ -1,19 +1,42 @@ #include "squid.h" #include "AccessLogEntry.h" #include "HttpRequest.h" void AccessLogEntry::getLogClientIp(char *buf, size_t bufsz) const { #if FOLLOW_X_FORWARDED_FOR if (Config.onoff.log_uses_indirect_client && request) request->indirect_client_addr.NtoA(buf, bufsz); else #endif if (tcpClient != NULL) tcpClient->remote.NtoA(buf, bufsz); else if (cache.caddr.IsNoAddr()) // e.g., ICAP OPTIONS lack client strncpy(buf, "-", 1); else cache.caddr.NtoA(buf, bufsz); } + +AccessLogEntry::~AccessLogEntry() +{ + safe_free(headers.request); + +#if ICAP_CLIENT + safe_free(adapt.last_meta); +#endif + + safe_free(headers.reply); + safe_free(cache.authuser); + + safe_free(headers.adapted_request); + HTTPMSGUNLOCK(adapted_request); + + HTTPMSGUNLOCK(reply); + HTTPMSGUNLOCK(request); +#if ICAP_CLIENT + HTTPMSGUNLOCK(icap.reply); + HTTPMSGUNLOCK(icap.request); +#endif + cbdataReferenceDone(cache.port); +} === modified file 'src/AccessLogEntry.h' --- src/AccessLogEntry.h 2012-04-25 05:29:20 +0000 +++ src/AccessLogEntry.h 2012-07-11 15:53:15 +0000 @@ -23,51 +23,58 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. * * Copyright (c) 2003, Robert Collins */ #ifndef SQUID_HTTPACCESSLOGENTRY_H #define SQUID_HTTPACCESSLOGENTRY_H #include "anyp/PortCfg.h" #include "comm/Connection.h" #include "HttpVersion.h" #include "HttpRequestMethod.h" #include "HierarchyLogEntry.h" #include "ip/Address.h" #include "HttpRequestMethod.h" #if ICAP_CLIENT #include "adaptation/icap/Elements.h" #endif +#include "RefCount.h" +#if USE_SSL +#include "ssl/gadgets.h" +#endif /* forward decls */ class HttpReply; class HttpRequest; -class AccessLogEntry +class AccessLogEntry: public RefCountable { public: + typedef RefCount Pointer; + AccessLogEntry() : url(NULL), tcpClient(), reply(NULL), request(NULL), adapted_request(NULL) {} + ~AccessLogEntry(); /// Fetch the client IP log string into the given buffer. /// Knows about several alternate locations of the IP /// including indirect forwarded-for IP if configured to log that void getLogClientIp(char *buf, size_t bufsz) const; const char *url; /// TCP/IP level details about the client connection Comm::ConnectionPointer tcpClient; // TCP/IP level details about the server or peer connection // are stored in hier.tcpServer /** \brief This subclass holds log info for HTTP protocol * \todo Inner class declarations should be moved outside * \todo details of HTTP held in the parent class need moving into here. */ class HttpDetails { @@ -114,62 +121,64 @@ /** \brief This subclass holds log info for Squid internal stats * \todo Inner class declarations should be moved outside * \todo some details relevant to particular protocols need shuffling to other sub-classes * \todo this object field need renaming to 'squid' or something. */ class CacheDetails { public: CacheDetails() : caddr(), requestSize(0), replySize(0), requestHeadersSize(0), replyHeadersSize(0), highOffset(0), objectSize(0), code (LOG_TAG_NONE), msec(0), rfc931 (NULL), authuser (NULL), - extuser(NULL) + extuser(NULL), #if USE_SSL - ,ssluser(NULL) + ssluser(NULL), #endif + port(NULL) {; } Ip::Address caddr; int64_t requestSize; int64_t replySize; int requestHeadersSize; ///< received, including request line int replyHeadersSize; ///< sent, including status line int64_t highOffset; int64_t objectSize; log_type code; int msec; const char *rfc931; const char *authuser; const char *extuser; #if USE_SSL const char *ssluser; + Ssl::X509_Pointer sslClientCert; ///< cert received from the client #endif AnyP::PortCfg *port; } cache; /** \brief This subclass holds log info for various headers in raw format * \todo shuffle this to the relevant protocol section. */ class Headers { public: Headers() : request(NULL), adapted_request(NULL), reply(NULL) {} char *request; //< virgin HTTP request headers char *adapted_request; //< HTTP request headers after adaptation and redirection @@ -237,29 +246,28 @@ * is created and stops when the result of the transaction is logged */ int trTime; /** \brief Transaction I/O time. * The timer starts when the first ICAP request * byte is scheduled for sending and stops when the lastbyte of the * ICAP response is received. */ int ioTime; http_status resStatus; ///< ICAP response status code int processingTime; ///< total ICAP processing time in milliseconds } icap; #endif }; class ACLChecklist; class StoreEntry; /* Should be in 'AccessLog.h' as the driver */ -extern void accessLogLogTo(customlog* log, AccessLogEntry* al, ACLChecklist* checklist = NULL); -extern void accessLogLog(AccessLogEntry *, ACLChecklist * checklist); +extern void accessLogLogTo(customlog* log, AccessLogEntry::Pointer &al, ACLChecklist* checklist = NULL); +extern void accessLogLog(AccessLogEntry::Pointer &, ACLChecklist * checklist); extern void accessLogRotate(void); extern void accessLogClose(void); extern void accessLogInit(void); -extern void accessLogFreeMemory(AccessLogEntry * aLogEntry); extern const char *accessLogTime(time_t); #endif /* SQUID_HTTPACCESSLOGENTRY_H */ === modified file 'src/ConfigParser.cc' --- src/ConfigParser.cc 2012-01-20 18:55:04 +0000 +++ src/ConfigParser.cc 2012-07-11 13:32:41 +0000 @@ -99,60 +99,63 @@ t += strspn(buf, w_space); t2 = t + strcspn(t, w_space); t3 = t2 + strspn(t2, w_space); while (*t3 && *t3 != '#') { t2 = t3 + strcspn(t3, w_space); t3 = t2 + strspn(t2, w_space); } *t2 = '\0'; } /* skip comments */ /* skip blank lines */ } while ( *t == '#' || !*t ); return t; } void -ConfigParser::ParseQuotedString(char **var) +ConfigParser::ParseQuotedString(char **var, bool *wasQuoted) { String sVar; - ParseQuotedString(&sVar); + ParseQuotedString(&sVar, wasQuoted); *var = xstrdup(sVar.termedBuf()); } void -ConfigParser::ParseQuotedString(String *var) +ConfigParser::ParseQuotedString(String *var, bool *wasQuoted) { // Get all of the remaining string char *token = strtok(NULL, ""); if (token == NULL) self_destruct(); if (*token != '"') { token = strtok(token, w_space); var->reset(token); + if (wasQuoted) + *wasQuoted = false; return; - } + } else if (wasQuoted) + *wasQuoted = true; char *s = token + 1; /* scan until the end of the quoted string, unescaping " and \ */ while (*s && *s != '"') { if (*s == '\\') { const char * next = s+1; // may point to 0 memmove(s, next, strlen(next) + 1); } s++; } if (*s != '"') { debugs(3, DBG_CRITICAL, "ParseQuotedString: missing '\"' at the end of quoted string" ); self_destruct(); } strtok(s-1, "\""); /*Reset the strtok to point after the " */ *s = '\0'; var->reset(token+1); } === modified file 'src/ConfigParser.h' --- src/ConfigParser.h 2012-01-20 18:55:04 +0000 +++ src/ConfigParser.h 2012-06-29 17:00:49 +0000 @@ -50,30 +50,35 @@ /** * A configuration file Parser. Instances of this class track * parsing state and perform tokenisation. Syntax is currently * taken care of outside this class. * * One reason for this class is to allow testing of configuration * using modules without linking cache_cf.o in - because that drags * in all of squid by reference. Instead the tokeniser only is * brought in. */ class ConfigParser { public: void destruct(); static void ParseUShort(unsigned short *var); static void ParseBool(bool *var); static void ParseString(char **var); static void ParseString(String *var); - static void ParseQuotedString(char **var); - static void ParseQuotedString(String *var); + /// Parse an unquoted token (no spaces) or a "quoted string" that + /// may include spaces. In some contexts, quotes strings may also + /// include macros. Quoted strings may escape any character with + /// a backslash (\), which is currently only useful for inner + /// quotes. TODO: support quoted strings anywhere a token is accepted. + static void ParseQuotedString(char **var, bool *wasQuoted = NULL); + static void ParseQuotedString(String *var, bool *wasQuoted = NULL); static const char *QuoteString(String &var); static void ParseWordList(wordlist **list); static char * strtokFile(); }; extern int parseConfigFile(const char *file_name); #endif /* SQUID_CONFIGPARSER_H */ === modified file 'src/HttpHeaderTools.cc' --- src/HttpHeaderTools.cc 2012-06-29 16:36:58 +0000 +++ src/HttpHeaderTools.cc 2012-07-11 18:18:18 +0000 @@ -18,47 +18,58 @@ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. * */ #include "squid-old.h" #include "acl/FilledChecklist.h" #include "acl/Gadgets.h" +#include "client_side.h" +#include "client_side_request.h" +#include "comm/Connection.h" #include "compat/strtoll.h" +#include "fde.h" #include "HttpHdrContRange.h" #include "HttpHeader.h" #include "HttpHeaderTools.h" #include "HttpRequest.h" #include "MemBuf.h" +#if USE_SSL +#include "ssl/support.h" +#endif #include "Store.h" +#include +#if HAVE_STRING +#include +#endif static void httpHeaderPutStrvf(HttpHeader * hdr, http_hdr_type id, const char *fmt, va_list vargs); HttpHeaderFieldInfo * httpHeaderBuildFieldsInfo(const HttpHeaderFieldAttrs * attrs, int count) { int i; HttpHeaderFieldInfo *table = NULL; assert(attrs && count); /* allocate space */ table = new HttpHeaderFieldInfo[count]; for (i = 0; i < count; ++i) { const http_hdr_type id = attrs[i].id; HttpHeaderFieldInfo *info = table + id; /* sanity checks */ assert(id >= 0 && id < count); assert(attrs[i].name); @@ -600,20 +611,48 @@ // a custom header if (e.id == HDR_OTHER) { // does it have an ACL list configured? // Optimize: use a name type that we do not need to convert to here const ManglersByName::const_iterator i = custom.find(e.name.termedBuf()); if (i != custom.end()) return &i->second; } // Next-to-last resort: "Other" rules match any custom header if (e.id == HDR_OTHER && known[HDR_OTHER].access_list) return &known[HDR_OTHER]; // Last resort: "All" rules match any header if (all.access_list) return &all; return NULL; } +void +httpHdrAdd(HttpHeader *heads, HttpRequest *request, HeaderWithAclList &headersAdd) +{ + ACLFilledChecklist checklist(NULL, request, NULL); + + for (HeaderWithAclList::const_iterator hwa = headersAdd.begin(); hwa != headersAdd.end(); ++hwa) { + if (!hwa->aclList || checklist.fastCheck(hwa->aclList) == ACCESS_ALLOWED) { + const char *fieldValue = NULL; + MemBuf mb; + if (hwa->quoted) { + if (request->al != NULL) { + mb.init(); + hwa->valueFormat->assemble(mb, request->al, 0); + fieldValue = mb.content(); + } + } else { + fieldValue = hwa->fieldValue.c_str(); + } + + if (!fieldValue || fieldValue[0] == '\0') + fieldValue = "-"; + + HttpHeaderEntry *e = new HttpHeaderEntry(hwa->fieldId, hwa->fieldName.c_str(), + fieldValue); + heads->addEntry(e); + } + } +} === modified file 'src/HttpHeaderTools.h' --- src/HttpHeaderTools.h 2012-06-29 16:36:58 +0000 +++ src/HttpHeaderTools.h 2012-07-11 14:35:00 +0000 @@ -1,30 +1,38 @@ #ifndef SQUID_HTTPHEADERTOOLS_H #define SQUID_HTTPHEADERTOOLS_H +#include "format/Format.h" + +#if HAVE_LIST +#include +#endif #if HAVE_MAP #include #endif #if HAVE_STRING #include #endif +class HeaderWithAcl; +typedef std::list HeaderWithAclList; + class acl_access; struct _header_mangler { acl_access *access_list; char *replacement; }; typedef struct _header_mangler header_mangler; class StoreEntry; /// A collection of header_mangler objects for a given message kind. class HeaderManglers { public: HeaderManglers(); ~HeaderManglers(); /// returns a header mangler for field e or nil if none was specified const header_mangler *find(const HttpHeaderEntry &e) const; /// returns a mangler for the named header (known or custom) header_mangler *track(const char *name); @@ -38,21 +46,45 @@ void dumpReplacement(StoreEntry *entry, const char *optionName) const; private: /// a name:mangler map; optimize: use unordered map or some such typedef std::map ManglersByName; /// one mangler for each known header header_mangler known[HDR_ENUM_END]; /// one mangler for each custom header ManglersByName custom; /// configured if some mangling ACL applies to all header names header_mangler all; private: /* not implemented */ HeaderManglers(const HeaderManglers &); HeaderManglers &operator =(const HeaderManglers &); }; + +class ACLList; +class HeaderWithAcl { +public: +HeaderWithAcl() : aclList(NULL), fieldId (HDR_BAD_HDR), quoted(false) {} + + /// HTTP header field name + std::string fieldName; + + /// HTTP header field value, possibly with macros + std::string fieldValue; + + /// when the header field should be added (always if nil) + ACLList *aclList; + + /// compiled HTTP header field value (no macros) + Format::Format *valueFormat; + + /// internal ID for "known" headers or HDR_OTHER + http_hdr_type fieldId; + + /// whether fieldValue may contain macros + bool quoted; +}; #endif === modified file 'src/HttpRequest.cc' --- src/HttpRequest.cc 2012-02-03 04:07:36 +0000 +++ src/HttpRequest.cc 2012-07-11 15:38:54 +0000 @@ -18,40 +18,41 @@ * sources; see the CREDITS file for full details. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. * * Copyright (c) 2003, Robert Collins */ #include "squid-old.h" +#include "AccessLogEntry.h" #include "DnsLookupDetails.h" #include "HttpRequest.h" #include "HttpHdrCc.h" #if USE_AUTH #include "auth/UserRequest.h" #endif #include "HttpHeaderRange.h" #include "log/Config.h" #include "MemBuf.h" #include "Store.h" #if ICAP_CLIENT #include "adaptation/icap/icap_log.h" #endif #include "acl/FilledChecklist.h" #include "err_detail_type.h" HttpRequest::HttpRequest() : HttpMsg(hoRequest) { init(); } @@ -245,40 +246,42 @@ #if USE_ADAPTATION adaptHistory_ = aReq->adaptHistory(); #endif #if ICAP_CLIENT icapHistory_ = aReq->icapHistory(); #endif // This may be too conservative for the 204 No Content case // may eventually need cloneNullAdaptationImmune() for that. flags = aReq->flags.cloneAdaptationImmune(); errType = aReq->errType; errDetail = aReq->errDetail; #if USE_AUTH auth_user_request = aReq->auth_user_request; #endif // main property is which connection the request was received on (if any) clientConnectionManager = aReq->clientConnectionManager; + + al = aReq->al; return true; } /** * Checks the first line of an HTTP request is valid * currently just checks the request method is present. * * NP: Other errors are left for detection later in the parse. */ bool HttpRequest::sanityCheckStartLine(MemBuf *buf, const size_t hdr_len, http_status *error) { // content is long enough to possibly hold a reply // 2 being magic size of a 1-byte request method plus space delimiter if ( buf->contentSize() < 2 ) { // this is ony a real error if the headers apparently complete. if (hdr_len > 0) { debugs(58, 3, HERE << "Too large request header (" << hdr_len << " bytes)"); *error = HTTP_INVALID_HEADER; } === modified file 'src/HttpRequest.h' --- src/HttpRequest.h 2011-12-30 01:24:57 +0000 +++ src/HttpRequest.h 2012-07-11 15:50:57 +0000 @@ -38,40 +38,42 @@ #endif #if ICAP_CLIENT #include "adaptation/icap/History.h" #endif #include "base/CbcPointer.h" #include "client_side.h" #if USE_SQUID_EUI #include "eui/Eui48.h" #include "eui/Eui64.h" #endif #include "HierarchyLogEntry.h" #include "HttpMsg.h" #include "HttpRequestMethod.h" /* Http Request */ //DEAD?: extern int httpRequestHdrAllowedByName(http_hdr_type id); extern void httpRequestPack(void *obj, Packer *p); class HttpHdrRange; class DnsLookupDetails; +class AccessLogEntry; +typedef RefCount AccessLogEntryPointer; class HttpRequest: public HttpMsg { public: typedef HttpMsgPointerT Pointer; MEMPROXY_CLASS(HttpRequest); HttpRequest(); HttpRequest(const HttpRequestMethod& aMethod, AnyP::ProtocolType aProtocol, const char *aUrlpath); ~HttpRequest(); virtual void reset(); // use HTTPMSGLOCK() instead of calling this directly virtual HttpRequest *_lock() { return static_cast(HttpMsg::_lock()); }; void initHTTP(const HttpRequestMethod& aMethod, AnyP::ProtocolType aProtocol, const char *aUrlpath); @@ -222,40 +224,46 @@ static void httpRequestPack(void *obj, Packer *p); static HttpRequest * CreateFromUrlAndMethod(char * url, const HttpRequestMethod& method); static HttpRequest * CreateFromUrl(char * url); ConnStateData *pinnedConnection() { if (clientConnectionManager.valid() && clientConnectionManager->pinning.pinned) return clientConnectionManager.get(); return NULL; } /** * The client connection manager, if known; * Used for any response actions needed directly to the client. * ie 1xx forwarding or connection pinning state changes */ CbcPointer clientConnectionManager; + /** + * The AccessLogEntry for the current ClientHttpRequest/Server HttpRequest + * pair, if known; + */ + AccessLogEntryPointer al; + int64_t getRangeOffsetLimit(); /* the result of this function gets cached in rangeOffsetLimit */ private: const char *packableURI(bool full_uri) const; mutable int64_t rangeOffsetLimit; /* caches the result of getRangeOffsetLimit */ protected: virtual void packFirstLineInto(Packer * p, bool full_uri) const; virtual bool sanityCheckStartLine(MemBuf *buf, const size_t hdr_len, http_status *error); virtual void hdrCacheInit(); virtual bool inheritProperties(const HttpMsg *aMsg); }; MEMPROXY_CLASS_INLINE(HttpRequest); #endif /* SQUID_HTTPREQUEST_H */ === modified file 'src/adaptation/icap/ModXact.cc' --- src/adaptation/icap/ModXact.cc 2012-05-31 00:20:44 +0000 +++ src/adaptation/icap/ModXact.cc 2012-07-11 14:39:50 +0000 @@ -1232,41 +1232,41 @@ // internal cleanup void Adaptation::Icap::ModXact::swanSong() { debugs(93, 5, HERE << "swan sings" << status()); stopWriting(false); stopSending(false); if (theInitiator.set()) // we have not sent the answer to the initiator detailError(ERR_DETAIL_ICAP_XACT_OTHER); // update adaptation history if start was called and we reserved a slot Adaptation::History::Pointer ah = virginRequest().adaptLogHistory(); if (ah != NULL && adaptHistoryId >= 0) ah->recordXactFinish(adaptHistoryId); Adaptation::Icap::Xaction::swanSong(); } -void prepareLogWithRequestDetails(HttpRequest *, AccessLogEntry *); +void prepareLogWithRequestDetails(HttpRequest *, AccessLogEntry::Pointer &); void Adaptation::Icap::ModXact::finalizeLogInfo() { HttpRequest * request_ = NULL; HttpReply * reply_ = NULL; if (!(request_ = dynamic_cast(adapted.header))) { request_ = (virgin.cause? virgin.cause: dynamic_cast(virgin.header)); reply_ = dynamic_cast(adapted.header); } Adaptation::Icap::History::Pointer h = request_->icapHistory(); Must(h != NULL); // ICAPXaction::maybeLog calls only if there is a log al.icp.opcode = ICP_INVALID; al.url = h->log_uri.termedBuf(); const Adaptation::Icap::ServiceRep &s = service(); al.icap.reqMethod = s.cfg().method; al.cache.caddr = request_->client_addr; al.request = HTTPMSGLOCK(request_); @@ -1296,41 +1296,41 @@ al.http.code = reply_->sline.status; al.http.content_type = reply_->content_type.termedBuf(); if (replyHttpBodySize >= 0) { al.cache.replySize = replyHttpBodySize + reply_->hdr_sz; al.cache.highOffset = replyHttpBodySize; } //don't set al.cache.objectSize because it hasn't exist yet Packer p; MemBuf mb; mb.init(); packerToMemInit(&p, &mb); reply_->header.packInto(&p); al.headers.reply = xstrdup(mb.buf); packerClean(&p); mb.clean(); } - prepareLogWithRequestDetails(request_, &al); + prepareLogWithRequestDetails(request_, alep); Xaction::finalizeLogInfo(); } void Adaptation::Icap::ModXact::makeRequestHeaders(MemBuf &buf) { char ntoabuf[MAX_IPSTRLEN]; /* * XXX These should use HttpHdr interfaces instead of Printfs */ const Adaptation::ServiceConfig &s = service().cfg(); buf.Printf("%s " SQUIDSTRINGPH " ICAP/1.0\r\n", s.methodStr(), SQUIDSTRINGPRINT(s.uri)); buf.Printf("Host: " SQUIDSTRINGPH ":%d\r\n", SQUIDSTRINGPRINT(s.host), s.port); buf.Printf("Date: %s\r\n", mkrfc1123(squid_curtime)); if (!TheConfig.reuse_connections) buf.Printf("Connection: close\r\n"); const HttpRequest *request = &virginRequest(); === modified file 'src/adaptation/icap/Xaction.cc' --- src/adaptation/icap/Xaction.cc 2012-01-20 18:55:04 +0000 +++ src/adaptation/icap/Xaction.cc 2012-07-11 16:30:28 +0000 @@ -23,41 +23,43 @@ #include "SquidTime.h" #include "err_detail_type.h" //CBDATA_NAMESPACED_CLASS_INIT(Adaptation::Icap, Xaction); Adaptation::Icap::Xaction::Xaction(const char *aTypeName, Adaptation::Icap::ServiceRep::Pointer &aService): AsyncJob(aTypeName), Adaptation::Initiate(aTypeName), icapRequest(NULL), icapReply(NULL), attempts(0), connection(NULL), theService(aService), commBuf(NULL), commBufSize(0), commEof(false), reuseConnection(true), isRetriable(true), isRepeatable(true), ignoreLastWrite(false), - connector(NULL), reader(NULL), writer(NULL), closer(NULL) + connector(NULL), reader(NULL), writer(NULL), closer(NULL), + alep(new AccessLogEntry), + al(*alep) { debugs(93,3, typeName << " constructed, this=" << this << " [icapx" << id << ']'); // we should not call virtual status() here icapRequest = HTTPMSGLOCK(new HttpRequest); icap_tr_start = current_time; } Adaptation::Icap::Xaction::~Xaction() { debugs(93,3, typeName << " destructed, this=" << this << " [icapx" << id << ']'); // we should not call virtual status() here HTTPMSGUNLOCK(icapRequest); } Adaptation::Icap::ServiceRep & Adaptation::Icap::Xaction::service() { Must(theService != NULL); return *theService; } @@ -523,43 +525,42 @@ void Adaptation::Icap::Xaction::tellQueryAborted() { if (theInitiator.set()) { Adaptation::Icap::XactAbortInfo abortInfo(icapRequest, icapReply, retriable(), repeatable()); Launcher *launcher = dynamic_cast(theInitiator.get()); // launcher may be nil if initiator is invalid CallJobHere1(91,5, CbcPointer(launcher), Launcher, noteXactAbort, abortInfo); clearInitiator(); } } void Adaptation::Icap::Xaction::maybeLog() { if (IcapLogfileStatus == LOG_ENABLE) { ACLChecklist *checklist = new ACLFilledChecklist(::Config.accessList.icap, al.request, dash_str); if (!::Config.accessList.icap || checklist->fastCheck() == ACCESS_ALLOWED) { finalizeLogInfo(); - icapLogLog(&al, checklist); + icapLogLog(alep, checklist); } - accessLogFreeMemory(&al); delete checklist; } } void Adaptation::Icap::Xaction::finalizeLogInfo() { //prepare log data al.icp.opcode = ICP_INVALID; const Adaptation::Icap::ServiceRep &s = service(); al.icap.hostAddr = s.cfg().host.termedBuf(); al.icap.serviceName = s.cfg().key; al.icap.reqUri = s.cfg().uri; al.icap.ioTime = tvSubMsec(icap_tio_start, icap_tio_finish); al.icap.trTime = tvSubMsec(icap_tr_start, current_time); al.icap.request = HTTPMSGLOCK(icapRequest); if (icapReply) { al.icap.reply = HTTPMSGLOCK(icapReply); === modified file 'src/adaptation/icap/Xaction.h' --- src/adaptation/icap/Xaction.h 2011-07-12 19:02:48 +0000 +++ src/adaptation/icap/Xaction.h 2012-07-11 14:45:09 +0000 @@ -163,35 +163,36 @@ * the callback. If comm_read ever becomes MemBuf-aware, we * can eliminate commBuf and this extra buffer copy. */ MemBuf readBuf; char *commBuf; size_t commBufSize; bool commEof; bool reuseConnection; bool isRetriable; ///< can retry on persistent connection failures bool isRepeatable; ///< can repeat if no or unsatisfactory response bool ignoreLastWrite; const char *stopReason; // active (pending) comm callbacks for the ICAP server connection AsyncCall::Pointer connector; AsyncCall::Pointer reader; AsyncCall::Pointer writer; AsyncCall::Pointer closer; - AccessLogEntry al; + AccessLogEntry::Pointer alep; ///< icap.log entry + AccessLogEntry &al; ///< short for *alep timeval icap_tr_start; /*time when the ICAP transaction was created */ timeval icap_tio_start; /*time when the first ICAP request byte was scheduled for sending*/ timeval icap_tio_finish; /*time when the last byte of the ICAP responsewas received*/ private: //CBDATA_CLASS2(Xaction); }; } // namespace Icap } // namespace Adaptation #endif /* SQUID_ICAPXACTION_H */ === modified file 'src/adaptation/icap/icap_log.cc' --- src/adaptation/icap/icap_log.cc 2012-01-20 18:55:04 +0000 +++ src/adaptation/icap/icap_log.cc 2012-07-11 16:30:00 +0000 @@ -27,25 +27,25 @@ customlog *log; for (log = Config.Log.icaplogs; log; log = log->next) { if (log->logfile) { logfileClose(log->logfile); log->logfile = NULL; } } } void icapLogRotate() { for (customlog* log = Config.Log.icaplogs; log; log = log->next) { if (log->logfile) { logfileRotate(log->logfile); } } } -void icapLogLog(AccessLogEntry *al, ACLChecklist * checklist) +void icapLogLog(AccessLogEntry::Pointer &al, ACLChecklist * checklist) { if (IcapLogfileStatus == LOG_ENABLE) accessLogLogTo(Config.Log.icaplogs, al, checklist); } === modified file 'src/adaptation/icap/icap_log.h' --- src/adaptation/icap/icap_log.h 2009-07-12 22:56:47 +0000 +++ src/adaptation/icap/icap_log.h 2012-07-11 16:29:41 +0000 @@ -1,14 +1,17 @@ #ifndef ICAP_LOG_H_ #define ICAP_LOG_H_ +#include "RefCount.h" + +typedef RefCount AccessLogEntryPointer; class AccessLogEntry; class ACLChecklist; void icapLogClose(); void icapLogOpen(); void icapLogRotate(); -void icapLogLog(AccessLogEntry *al, ACLChecklist * checklist); +void icapLogLog(AccessLogEntryPointer &al, ACLChecklist * checklist); extern int IcapLogfileStatus; #endif /*ICAP_LOG_H_*/ === modified file 'src/cache_cf.cc' --- src/cache_cf.cc 2012-06-29 16:36:58 +0000 +++ src/cache_cf.cc 2012-07-05 18:35:30 +0000 @@ -73,40 +73,44 @@ #include "mgr/Registration.h" #include "Parsing.h" #include "rfc1738.h" #if SQUID_SNMP #include "snmp.h" #endif #include "Store.h" #include "StoreFileSystem.h" #include "SwapDir.h" #include "wordlist.h" #include "ipc/Kids.h" #if HAVE_GLOB_H #include #endif #if HAVE_LIMITS_H #include #endif +#if HAVE_LIST +#include +#endif + #if USE_SSL #include "ssl/gadgets.h" #endif #if USE_ADAPTATION static void parse_adaptation_service_set_type(); static void parse_adaptation_service_chain_type(); static void parse_adaptation_access_type(); static void parse_adaptation_meta_type(Adaptation::Config::MetaHeaders *); static void dump_adaptation_meta_type(StoreEntry *, const char *, Adaptation::Config::MetaHeaders &); static void free_adaptation_meta_type(Adaptation::Config::MetaHeaders *); #endif #if ICAP_CLIENT static void parse_icap_service_type(Adaptation::Icap::Config *); static void dump_icap_service_type(StoreEntry *, const char *, const Adaptation::Icap::Config &); static void free_icap_service_type(Adaptation::Icap::Config *); static void parse_icap_class_type(); static void parse_icap_access_type(); @@ -160,40 +164,43 @@ static void parseBytesLine(size_t * bptr, const char *units); #if USE_SSL static void parseBytesOptionValue(size_t * bptr, const char *units, char const * value); #endif #if !USE_DNSHELPER static void parseBytesLineSigned(ssize_t * bptr, const char *units); #endif static size_t parseBytesUnits(const char *unit); static void free_all(void); void requirePathnameExists(const char *name, const char *path); static OBJH dump_config; #if USE_HTTP_VIOLATIONS static void free_HeaderManglers(HeaderManglers **pm); static void dump_http_header_access(StoreEntry * entry, const char *name, const HeaderManglers *manglers); static void parse_http_header_access(HeaderManglers **manglers); #define free_http_header_access free_HeaderManglers static void dump_http_header_replace(StoreEntry * entry, const char *name, const HeaderManglers *manglers); static void parse_http_header_replace(HeaderManglers **manglers); #define free_http_header_replace free_HeaderManglers #endif +static void dump_HeaderWithAclList(StoreEntry * entry, const char *name, HeaderWithAclList *headers); +static void parse_HeaderWithAclList(HeaderWithAclList **header); +static void free_HeaderWithAclList(HeaderWithAclList **header); static void parse_denyinfo(acl_deny_info_list ** var); static void dump_denyinfo(StoreEntry * entry, const char *name, acl_deny_info_list * var); static void free_denyinfo(acl_deny_info_list ** var); #if USE_WCCPv2 static void parse_IpAddress_list(Ip::Address_list **); static void dump_IpAddress_list(StoreEntry *, const char *, const Ip::Address_list *); static void free_IpAddress_list(Ip::Address_list **); #if CURRENTLY_UNUSED static int check_null_IpAddress_list(const Ip::Address_list *); #endif /* CURRENTLY_UNUSED */ #endif /* USE_WCCPv2 */ static void parsePortCfg(AnyP::PortCfg **, const char *protocol); #define parse_PortCfg(l) parsePortCfg((l), token) static void dump_PortCfg(StoreEntry *, const char *, const AnyP::PortCfg *); static void free_PortCfg(AnyP::PortCfg **); static void parse_b_size_t(size_t * var); static void parse_b_int64_t(int64_t * var); @@ -4297,20 +4304,85 @@ cfg->oldest_service_failure = (m * d); } static void dump_icap_service_failure_limit(StoreEntry *entry, const char *name, const Adaptation::Icap::Config &cfg) { storeAppendPrintf(entry, "%s %d", name, cfg.service_failure_limit); if (cfg.oldest_service_failure > 0) { storeAppendPrintf(entry, " in %d seconds", (int)cfg.oldest_service_failure); } storeAppendPrintf(entry, "\n"); } static void free_icap_service_failure_limit(Adaptation::Icap::Config *cfg) { cfg->oldest_service_failure = 0; cfg->service_failure_limit = 0; } #endif + +static void dump_HeaderWithAclList(StoreEntry * entry, const char *name, HeaderWithAclList *headers) +{ + if (!headers) + return; + + for (HeaderWithAclList::iterator hwa = headers->begin(); hwa != headers->end(); ++hwa) { + storeAppendPrintf(entry, "%s ", hwa->fieldName.c_str()); + storeAppendPrintf(entry, "%s ", hwa->fieldValue.c_str()); + if (hwa->aclList) + dump_acl_list(entry, hwa->aclList); + storeAppendPrintf(entry, "\n"); + } +} + +static void parse_HeaderWithAclList(HeaderWithAclList **headers) +{ + char *fn; + if (!*headers) { + *headers = new HeaderWithAclList; + } + if ((fn = strtok(NULL, w_space)) == NULL) { + self_destruct(); + return; + } + HeaderWithAcl hwa; + hwa.fieldName = fn; + hwa.fieldId = httpHeaderIdByNameDef(fn, strlen(fn)); + if (hwa.fieldId == HDR_BAD_HDR) + hwa.fieldId = HDR_OTHER; + + String buf; + bool wasQuoted; + ConfigParser::ParseQuotedString(&buf, &wasQuoted); + hwa.fieldValue = buf.termedBuf(); + hwa.quoted = wasQuoted; + if (hwa.quoted) { + Format::Format *nlf = new ::Format::Format("hdrWithAcl"); + if (!nlf->parse(hwa.fieldValue.c_str())) { + self_destruct(); + return; + } + hwa.valueFormat = nlf; + } + aclParseAclList(LegacyParser, &hwa.aclList); + (*headers)->push_back(hwa); +} + +static void free_HeaderWithAclList(HeaderWithAclList **header) +{ + if (!(*header)) + return; + + for (HeaderWithAclList::iterator hwa = (*header)->begin(); hwa != (*header)->end(); ++hwa) { + if (hwa->aclList) + aclDestroyAclList(&hwa->aclList); + + if (hwa->valueFormat) { + delete hwa->valueFormat; + hwa->valueFormat = NULL; + } + } + delete *header; + *header = NULL; +} === modified file 'src/cf.data.depend' --- src/cf.data.depend 2012-04-25 05:29:20 +0000 +++ src/cf.data.depend 2012-06-29 16:54:08 +0000 @@ -14,40 +14,41 @@ cachedir cache_replacement_policy cachemgrpasswd ConfigAclTos CpuAffinityMap debug delay_pool_access acl delay_class delay_pool_class delay_pools delay_pool_count delay_pool_rates delay_class client_delay_pool_access acl client_delay_pool_count client_delay_pool_rates denyinfo acl eol externalAclHelper auth_param HelperChildConfig hostdomain cache_peer hostdomaintype cache_peer http_header_access acl http_header_replace +HeaderWithAclList acl adaptation_access_type adaptation_service_set adaptation_service_chain acl icap_service icap_class adaptation_service_set_type icap_service ecap_service adaptation_service_chain_type icap_service ecap_service adaptation_meta_type acl icap_access_type icap_class acl icap_class_type icap_service icap_service_type icap_service_failure_limit ecap_service_type int kb_int64_t kb_size_t logformat YesNoNone memcachemode obsolete onoff peer peer_access cache_peer acl PortCfg === modified file 'src/cf.data.pre' --- src/cf.data.pre 2012-06-29 16:36:58 +0000 +++ src/cf.data.pre 2012-07-11 18:21:55 +0000 @@ -3112,40 +3112,54 @@ the order of transaction start time. Each time value is recorded as an integer number, representing response time of one or more adaptation (ICAP or eCAP) transaction in milliseconds. When a failed transaction is being retried or repeated, its time is not logged individually but added to the replacement (next) transaction. See also: adapt::all_trs. adapt::all_trs All adaptation transaction response times. Same as adaptation_strs but response times of individual transactions are never added together. Instead, all transaction response times are recorded individually. You can prefix adapt::*_trs format codes with adaptation service name in curly braces to record response time(s) specific to that service. For example: %{my_service}adapt::sum_trs + If SSL is enabled, the following formating codes become available: + + %ssl::>cert_subject The Subject field of the received client + SSL certificate or a dash ('-') if Squid has + received an invalid/malformed certificate or + no certificate at all. Consider encoding the + logged value because Subject often has spaces. + + %ssl::>cert_issuer The Issuer field of the received client + SSL certificate or a dash ('-') if Squid has + received an invalid/malformed certificate or + no certificate at all. Consider encoding the + logged value because Issuer often has spaces. + The default formats available (which do not need re-defining) are: logformat squid %ts.%03tu %6tr %>a %Ss/%03>Hs %a %[ui %[un [%tl] "%rm %ru HTTP/%rv" %>Hs %a %[ui %[un [%tl] "%rm %ru HTTP/%rv" %>Hs %h" "%{User-Agent}>h" %Ss:%Sh logformat referrer %ts.%03tu %>a %{Referer}>h %ru logformat useragent %>a [%tl] "%{User-Agent}>h" NOTE: When the log_mime_hdrs directive is set to ON. The squid, common and combined formats have a safely encoded copy of the mime headers appended to each line within a pair of brackets. NOTE: The common and combined formats are not quite true to the Apache definition. The logs from Squid contain an extra status and hierarchy code appended. DOC_END NAME: access_log cache_access_log TYPE: access_log LOC: Config.Log.accesslogs @@ -4562,40 +4576,81 @@ DOC_END NAME: reply_header_replace IFDEF: USE_HTTP_VIOLATIONS TYPE: http_header_replace LOC: Config.reply_header_access DEFAULT: none DOC_START Usage: reply_header_replace header_name message Example: reply_header_replace Server Foo/1.0 This option allows you to change the contents of headers denied with reply_header_access above, by replacing them with some fixed string. This only applies to reply headers, not request headers. By default, headers are removed if denied. DOC_END +NAME: request_header_add +TYPE: HeaderWithAclList +LOC: Config.request_header_add +DEFAULT: none +DOC_START + Usage: request_header_add field-name field-value acl1 [acl2] ... + Example: request_header_add X-Client-CA "CA=%ssl::>cert_issuer" all + + This option adds header fields to outgoing HTTP requests (i.e., + request headers sent by Squid to the next HTTP hop such as a + cache peer or an origin server). The option has no effect during + cache hit detection. The equivalent adaptation vectoring point + in ICAP terminology is post-cache REQMOD. + + Field-name is a token specifying an HTTP header name. If a + standard HTTP header name is used, Squid does not check whether + the new header conflicts with any existing headers or violates + HTTP rules. If the request to be modified already contains a + field with the same name, the old field is preserved but the + header field values are not merged. + + Field-value is either a token or a quoted string. If quoted + string format is used, then the surrounding quotes are removed + while escape sequences and %macros are processed. + + In theory, all of the logformat codes can be used as %macros. + However, unlike logging (which happens at the very end of + transaction lifetime), the transaction may not yet have enough + information to expand a macro when the new header value is needed. + And some information may already be available to Squid but not yet + committed where the macro expansion code can access it (report + such instances!). The macro will be expanded into a single dash + ('-') in such cases. Not all macros have been tested. + + One or more Squid ACLs may be specified to restrict header + injection to matching requests. As always in squid.conf, all + ACLs in an option ACL list must be satisfied for the insertion + to happen. The request_header_add option supports fast ACLs + only. +DOC_END + NAME: relaxed_header_parser COMMENT: on|off|warn TYPE: tristate LOC: Config.onoff.relaxed_header_parser DEFAULT: on DOC_START In the default "on" setting Squid accepts certain forms of non-compliant HTTP messages where it is unambiguous what the sending application intended even if the message is not correctly formatted. The messages is then normalized to the correct form when forwarded by Squid. If set to "warn" then a warning will be emitted in cache.log each time such HTTP error is encountered. If set to "off" then such HTTP errors will cause the request or response to be rejected. DOC_END COMMENT_START === modified file 'src/client_side.cc' --- src/client_side.cc 2012-06-22 03:49:38 +0000 +++ src/client_side.cc 2012-07-11 16:34:18 +0000 @@ -197,41 +197,41 @@ static IOACB httpAccept; #if USE_SSL static IOACB httpsAccept; #endif static CTCB clientLifetimeTimeout; static ClientSocketContext *parseHttpRequestAbort(ConnStateData * conn, const char *uri); static ClientSocketContext *parseHttpRequest(ConnStateData *, HttpParser *, HttpRequestMethod *, HttpVersion *); #if USE_IDENT static IDCB clientIdentDone; #endif static CSCB clientSocketRecipient; static CSD clientSocketDetach; static void clientSetKeepaliveFlag(ClientHttpRequest *); static int clientIsContentLengthValid(HttpRequest * r); static int clientIsRequestBodyTooLargeForPolicy(int64_t bodyLength); static void clientUpdateStatHistCounters(log_type logType, int svc_time); static void clientUpdateStatCounters(log_type logType); static void clientUpdateHierCounters(HierarchyLogEntry *); static bool clientPingHasFinished(ping_data const *aPing); -void prepareLogWithRequestDetails(HttpRequest *, AccessLogEntry *); +void prepareLogWithRequestDetails(HttpRequest *, AccessLogEntry::Pointer &); #ifndef PURIFY static bool connIsUsable(ConnStateData * conn); #endif static int responseFinishedOrFailed(HttpReply * rep, StoreIOBuffer const &receivedData); static void ClientSocketContextPushDeferredIfNeeded(ClientSocketContext::Pointer deferredRequest, ConnStateData * conn); static void clientUpdateSocketStats(log_type logType, size_t size); char *skipLeadingSpace(char *aString); static void connNoteUseOfBuffer(ConnStateData* conn, size_t byteCount); static ConnStateData *connStateCreate(const Comm::ConnectionPointer &client, AnyP::PortCfg *port); clientStreamNode * ClientSocketContext::getTail() const { if (http->client_stream.tail) return (clientStreamNode *)http->client_stream.tail->data; return NULL; @@ -531,44 +531,44 @@ default: break; } } void ClientHttpRequest::updateCounters() { clientUpdateStatCounters(logType); if (request->errType != ERR_NONE) statCounter.client_http.errors++; clientUpdateStatHistCounters(logType, tvSubMsec(start_time, current_time)); clientUpdateHierCounters(&request->hier); } void -prepareLogWithRequestDetails(HttpRequest * request, AccessLogEntry * aLogEntry) +prepareLogWithRequestDetails(HttpRequest * request, AccessLogEntry::Pointer &aLogEntry) { assert(request); - assert(aLogEntry); + assert(aLogEntry != NULL); if (Config.onoff.log_mime_hdrs) { Packer p; MemBuf mb; mb.init(); packerToMemInit(&p, &mb); request->header.packInto(&p); //This is the request after adaptation or redirection aLogEntry->headers.adapted_request = xstrdup(mb.buf); // the virgin request is saved to aLogEntry->request if (aLogEntry->request) { packerClean(&p); mb.reset(); packerToMemInit(&p, &mb); aLogEntry->request->header.packInto(&p); aLogEntry->headers.request = xstrdup(mb.buf); } #if USE_ADAPTATION @@ -605,110 +605,108 @@ aLogEntry->cache.authuser = xstrdup(request->auth_user_request->username()); } #endif // Adapted request, if any, inherits and then collects all the stats, but // the virgin request gets logged instead; copy the stats to log them. // TODO: avoid losses by keeping these stats in a shared history object? if (aLogEntry->request) { aLogEntry->request->dnsWait = request->dnsWait; aLogEntry->request->errType = request->errType; aLogEntry->request->errDetail = request->errDetail; } } void ClientHttpRequest::logRequest() { if (!out.size && !logType) debugs(33, 5, HERE << "logging half-baked transaction: " << log_uri); - al.icp.opcode = ICP_INVALID; - al.url = log_uri; - debugs(33, 9, "clientLogRequest: al.url='" << al.url << "'"); - - if (al.reply) { - al.http.code = al.reply->sline.status; - al.http.content_type = al.reply->content_type.termedBuf(); + al->icp.opcode = ICP_INVALID; + al->url = log_uri; + debugs(33, 9, "clientLogRequest: al.url='" << al->url << "'"); + + if (al->reply) { + al->http.code = al->reply->sline.status; + al->http.content_type = al->reply->content_type.termedBuf(); } else if (loggingEntry() && loggingEntry()->mem_obj) { - al.http.code = loggingEntry()->mem_obj->getReply()->sline.status; - al.http.content_type = loggingEntry()->mem_obj->getReply()->content_type.termedBuf(); + al->http.code = loggingEntry()->mem_obj->getReply()->sline.status; + al->http.content_type = loggingEntry()->mem_obj->getReply()->content_type.termedBuf(); } - debugs(33, 9, "clientLogRequest: http.code='" << al.http.code << "'"); + debugs(33, 9, "clientLogRequest: http.code='" << al->http.code << "'"); if (loggingEntry() && loggingEntry()->mem_obj) - al.cache.objectSize = loggingEntry()->contentLen(); + al->cache.objectSize = loggingEntry()->contentLen(); - al.cache.caddr.SetNoAddr(); + al->cache.caddr.SetNoAddr(); if (getConn() != NULL) { - al.cache.caddr = getConn()->log_addr; - al.cache.port = cbdataReference(getConn()->port); + al->cache.caddr = getConn()->log_addr; + al->cache.port = cbdataReference(getConn()->port); } - al.cache.requestSize = req_sz; - al.cache.requestHeadersSize = req_sz; + al->cache.requestSize = req_sz; + al->cache.requestHeadersSize = req_sz; - al.cache.replySize = out.size; - al.cache.replyHeadersSize = out.headers_sz; + al->cache.replySize = out.size; + al->cache.replyHeadersSize = out.headers_sz; - al.cache.highOffset = out.offset; + al->cache.highOffset = out.offset; - al.cache.code = logType; + al->cache.code = logType; - al.cache.msec = tvSubMsec(start_time, current_time); + al->cache.msec = tvSubMsec(start_time, current_time); if (request) - prepareLogWithRequestDetails(request, &al); + prepareLogWithRequestDetails(request, al); if (getConn() != NULL && getConn()->clientConnection != NULL && getConn()->clientConnection->rfc931[0]) - al.cache.rfc931 = getConn()->clientConnection->rfc931; + al->cache.rfc931 = getConn()->clientConnection->rfc931; #if USE_SSL && 0 /* This is broken. Fails if the connection has been closed. Needs * to snarf the ssl details some place earlier.. */ if (getConn() != NULL) - al.cache.ssluser = sslGetUserEmail(fd_table[getConn()->fd].ssl); + al->cache.ssluser = sslGetUserEmail(fd_table[getConn()->fd].ssl); #endif ACLFilledChecklist *checklist = clientAclChecklistCreate(Config.accessList.log, this); - if (al.reply) - checklist->reply = HTTPMSGLOCK(al.reply); + if (al->reply) + checklist->reply = HTTPMSGLOCK(al->reply); if (!Config.accessList.log || checklist->fastCheck() == ACCESS_ALLOWED) { if (request) - al.adapted_request = HTTPMSGLOCK(request); - accessLogLog(&al, checklist); + al->adapted_request = HTTPMSGLOCK(request); + accessLogLog(al, checklist); updateCounters(); if (getConn() != NULL && getConn()->clientConnection != NULL) clientdbUpdate(getConn()->clientConnection->remote, logType, AnyP::PROTO_HTTP, out.size); } delete checklist; - - accessLogFreeMemory(&al); } void ClientHttpRequest::freeResources() { safe_free(uri); safe_free(log_uri); safe_free(redirect.location); range_iter.boundary.clean(); HTTPMSGUNLOCK(request); if (client_stream.tail) clientStreamAbort((clientStreamNode *)client_stream.tail->data, this); } void httpRequestFree(void *data) { ClientHttpRequest *http = (ClientHttpRequest *)data; assert(http != NULL); @@ -1424,41 +1422,41 @@ if (context != http->getConn()->getCurrentContext()) { context->deferRecipientForLater(node, rep, receivedData); PROF_stop(clientSocketRecipient); return; } // After sending Transfer-Encoding: chunked (at least), always send // the last-chunk if there was no error, ignoring responseFinishedOrFailed. const bool mustSendLastChunk = http->request->flags.chunked_reply && !http->request->flags.stream_error && !context->startOfOutput(); if (responseFinishedOrFailed(rep, receivedData) && !mustSendLastChunk) { context->writeComplete(context->clientConnection, NULL, 0, COMM_OK); PROF_stop(clientSocketRecipient); return; } if (!context->startOfOutput()) context->sendBody(rep, receivedData); else { assert(rep); - http->al.reply = HTTPMSGLOCK(rep); + http->al->reply = HTTPMSGLOCK(rep); context->sendStartOfMessage(rep, receivedData); } PROF_stop(clientSocketRecipient); } /** * Called when a downstream node is no longer interested in * our data. As we are a terminal node, this means on aborts * only */ void clientSocketDetach(clientStreamNode * node, ClientHttpRequest * http) { /* Test preconditions */ assert(node != NULL); /* TODO: handle this rather than asserting * - it should only ever happen if we cause an abort and * the callback chain loops back to here, so we can simply return. * However, that itself shouldn't happen, so it stays as an assert for now. @@ -1770,43 +1768,43 @@ return STREAM_NONE; } /** * A write has just completed to the client, or we have just realised there is * no more data to send. */ void clientWriteComplete(const Comm::ConnectionPointer &conn, char *bufnotused, size_t size, comm_err_t errflag, int xerrno, void *data) { ClientSocketContext *context = (ClientSocketContext *)data; context->writeComplete(conn, bufnotused, size, errflag); } /// remembers the abnormal connection termination for logging purposes void ClientSocketContext::noteIoError(const int xerrno) { if (http) { if (xerrno == ETIMEDOUT) - http->al.http.timedout = true; + http->al->http.timedout = true; else // even if xerrno is zero (which means read abort/eof) - http->al.http.aborted = true; + http->al->http.aborted = true; } } void ClientSocketContext::doClose() { clientConnection->close(); } /// called when we encounter a response-related error void ClientSocketContext::initiateClose(const char *reason) { http->getConn()->stopSending(reason); // closes ASAP } void ConnStateData::stopSending(const char *error) { @@ -2518,40 +2516,41 @@ } /* compile headers */ /* we should skip request line! */ /* XXX should actually know the damned buffer size here */ if (http_ver.major >= 1 && !request->parseHeader(HttpParserHdrBuf(hp), HttpParserHdrSz(hp))) { clientStreamNode *node = context->getClientReplyContext(); debugs(33, 5, "Failed to parse request headers:\n" << HttpParserHdrBuf(hp)); // setLogUri should called before repContext->setReplyToError setLogUri(http, http->uri, true); clientReplyContext *repContext = dynamic_cast(node->data.getRaw()); assert (repContext); repContext->setReplyToError(ERR_INVALID_REQ, HTTP_BAD_REQUEST, method, http->uri, conn->clientConnection->remote, NULL, NULL, NULL); assert(context->http->out.offset == 0); context->pullData(); conn->flags.readMore = false; goto finish; } request->clientConnectionManager = conn; + request->al = http->al; request->flags.accelerated = http->flags.accel; request->flags.sslBumped = conn->switchedToHttps(); request->flags.ignore_cc = conn->port->ignore_cc; request->flags.no_direct = request->flags.accelerated ? !conn->port->allow_direct : 0; #if USE_AUTH if (request->flags.sslBumped) { if (conn->auth_user_request != NULL) request->auth_user_request = conn->auth_user_request; } #endif /** \par * If transparent or interception mode is working clone the transparent and interception flags * from the port settings to the request. */ if (http->clientConnection != NULL) { request->flags.intercepted = ((http->clientConnection->flags & COMM_INTERCEPTION) != 0); request->flags.spoof_client_ip = ((http->clientConnection->flags & COMM_TRANSPARENT) != 0 ) ; } @@ -3124,41 +3123,41 @@ #else /* * Just close the connection to not confuse browsers * using persistent connections. Some browsers opens * an connection and then does not use it until much * later (presumeably because the request triggering * the open has already been completed on another * connection) */ debugs(33, 3, "requestTimeout: FD " << io.fd << ": lifetime is expired."); io.conn->close(); #endif } static void clientLifetimeTimeout(const CommTimeoutCbParams &io) { ClientHttpRequest *http = static_cast(io.data); debugs(33, DBG_IMPORTANT, "WARNING: Closing client connection due to lifetime timeout"); debugs(33, DBG_IMPORTANT, "\t" << http->uri); - http->al.http.timedout = true; + http->al->http.timedout = true; if (Comm::IsConnOpen(io.conn)) io.conn->close(); } ConnStateData * connStateCreate(const Comm::ConnectionPointer &client, AnyP::PortCfg *port) { ConnStateData *result = new ConnStateData; result->clientConnection = client; result->log_addr = client->remote; result->log_addr.ApplyMask(Config.Addrs.client_netmask); result->in.buf = (char *)memAllocBuf(CLIENT_REQ_BUF_SZ, &result->in.allocatedSize); result->port = cbdataReference(port); if (port->disable_pmtu_discovery != DISABLE_PMTU_OFF && (result->transparent() || port->disable_pmtu_discovery == DISABLE_PMTU_ALWAYS)) { #if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT) int i = IP_PMTUDISC_DONT; setsockopt(client->fd, SOL_IP, IP_MTU_DISCOVER, &i, sizeof i); === modified file 'src/client_side_reply.cc' --- src/client_side_reply.cc 2012-06-25 07:43:36 +0000 +++ src/client_side_reply.cc 2012-07-09 15:00:29 +0000 @@ -100,41 +100,41 @@ void clientReplyContext::setReplyToError( err_type err, http_status status, const HttpRequestMethod& method, char const *uri, Ip::Address &addr, HttpRequest * failedrequest, const char *unparsedrequest, #if USE_AUTH Auth::UserRequest::Pointer auth_user_request #else void* #endif ) { ErrorState *errstate = clientBuildError(err, status, uri, addr, failedrequest); if (unparsedrequest) errstate->request_hdrs = xstrdup(unparsedrequest); if (status == HTTP_NOT_IMPLEMENTED && http->request) /* prevent confusion over whether we default to persistent or not */ http->request->flags.proxy_keepalive = 0; - http->al.http.code = errstate->httpStatus; + http->al->http.code = errstate->httpStatus; createStoreEntry(method, request_flags()); #if USE_AUTH errstate->auth_user_request = auth_user_request; #endif assert(errstate->callback_data == NULL); errorAppendEntry(http->storeEntry(), errstate); /* Now the caller reads to get this */ } void clientReplyContext::removeStoreReference(store_client ** scp, StoreEntry ** ep) { StoreEntry *e; store_client *sc_tmp = *scp; if ((e = *ep) != NULL) { *ep = NULL; storeUnregister(sc_tmp, e, this); @@ -616,41 +616,41 @@ /** Check if its a PURGE request to be actioned. */ if (r->method == METHOD_PURGE) { purgeRequest(); return; } /** Check if its an 'OTHER' request. Purge all cached entries if so and continue. */ if (r->method == METHOD_OTHER) { purgeAllCached(); } /** Check if 'only-if-cached' flag is set. Action if so. */ if (http->onlyIfCached()) { processOnlyIfCachedMiss(); return; } /// Deny loops for accelerator and interceptor. TODO: deny in all modes? if (r->flags.loopdetect && (http->flags.accel || http->flags.intercepted)) { - http->al.http.code = HTTP_FORBIDDEN; + http->al->http.code = HTTP_FORBIDDEN; err = clientBuildError(ERR_ACCESS_DENIED, HTTP_FORBIDDEN, NULL, http->getConn()->clientConnection->remote, http->request); createStoreEntry(r->method, request_flags()); errorAppendEntry(http->storeEntry(), err); triggerInitialStoreRead(); return; } else { assert(http->out.offset == 0); createStoreEntry(r->method, r->flags); triggerInitialStoreRead(); if (http->redirect.status) { HttpReply *rep = new HttpReply; http->logType = LOG_TCP_REDIRECT; http->storeEntry()->releaseRequest(); rep->redirect(http->redirect.status, http->redirect.location); http->storeEntry()->replaceHttpReply(rep); http->storeEntry()->complete(); return; } @@ -660,41 +660,41 @@ assert(r->clientConnectionManager == http->getConn()); /** Start forwarding to get the new object from network */ Comm::ConnectionPointer conn = http->getConn() != NULL ? http->getConn()->clientConnection : NULL; FwdState::fwdStart(conn, http->storeEntry(), r); } } /** * client issued a request with an only-if-cached cache-control directive; * we did not find a cached object that can be returned without * contacting other servers; * respond with a 504 (Gateway Timeout) as suggested in [RFC 2068] */ void clientReplyContext::processOnlyIfCachedMiss() { debugs(88, 4, "clientProcessOnlyIfCachedMiss: '" << RequestMethodStr(http->request->method) << " " << http->uri << "'"); - http->al.http.code = HTTP_GATEWAY_TIMEOUT; + http->al->http.code = HTTP_GATEWAY_TIMEOUT; ErrorState *err = clientBuildError(ERR_ONLY_IF_CACHED_MISS, HTTP_GATEWAY_TIMEOUT, NULL, http->getConn()->clientConnection->remote, http->request); removeClientStoreReference(&sc, http); startError(err); } /// process conditional request from client void clientReplyContext::processConditional(StoreIOBuffer &result) { StoreEntry *const e = http->storeEntry(); if (e->getReply()->sline.status != HTTP_OK) { debugs(88, 4, "clientReplyContext::processConditional: Reply code " << e->getReply()->sline.status << " != 200"); http->logType = LOG_TCP_MISS; processMiss(); return; } @@ -2105,43 +2105,43 @@ reqsize = reqofs; if (errorInStream(result, reqofs)) { sendStreamError(result); return; } if (flags.headersSent) { pushStreamData (result, buf); return; } cloneReply(); /* handle headers */ if (Config.onoff.log_mime_hdrs) { size_t k; if ((k = headersEnd(buf, reqofs))) { - safe_free(http->al.headers.reply); - http->al.headers.reply = (char *)xcalloc(k + 1, 1); - xstrncpy(http->al.headers.reply, buf, k); + safe_free(http->al->headers.reply); + http->al->headers.reply = (char *)xcalloc(k + 1, 1); + xstrncpy(http->al->headers.reply, buf, k); } } holdingBuffer = result; processReplyAccess(); return; } /* Using this breaks the client layering just a little! */ void clientReplyContext::createStoreEntry(const HttpRequestMethod& m, request_flags reqFlags) { assert(http != NULL); /* * For erroneous requests, we might not have a h->request, * so make a fake one. */ === modified file 'src/client_side_request.cc' --- src/client_side_request.cc 2012-05-08 18:14:08 +0000 +++ src/client_side_request.cc 2012-07-11 10:42:43 +0000 @@ -159,41 +159,48 @@ CBDATA_INIT_TYPE(ClientHttpRequest); ClientHttpRequest *result = cbdataAlloc(ClientHttpRequest); return result; } void ClientHttpRequest::operator delete (void *address) { ClientHttpRequest *t = static_cast(address); cbdataFree(t); } ClientHttpRequest::ClientHttpRequest(ConnStateData * aConn) : #if USE_ADAPTATION AsyncJob("ClientHttpRequest"), #endif loggingEntry_(NULL) { start_time = current_time; setConn(aConn); - al.tcpClient = clientConnection = aConn->clientConnection; + al = new AccessLogEntry; + al->tcpClient = clientConnection = aConn->clientConnection; +#if USE_SSL + if (aConn->clientConnection != NULL && aConn->clientConnection->isOpen()) { + if (SSL *ssl = fd_table[aConn->clientConnection->fd].ssl) + al->cache.sslClientCert.reset(SSL_get_peer_certificate(ssl)); + } +#endif dlinkAdd(this, &active, &ClientActiveRequests); #if USE_ADAPTATION request_satisfaction_mode = false; #endif #if USE_SSL sslBumpNeed = needUnknown; #endif } /* * returns true if client specified that the object must come from the cache * without contacting origin server */ bool ClientHttpRequest::onlyIfCached()const { assert(request); return request->cache_control && request->cache_control->onlyIfCached(); } @@ -263,41 +270,41 @@ ClientHttpRequest::~ClientHttpRequest() { debugs(33, 3, "httpRequestFree: " << uri); PROF_start(httpRequestFree); // Even though freeResources() below may destroy the request, // we no longer set request->body_pipe to NULL here // because we did not initiate that pipe (ConnStateData did) /* the ICP check here was erroneous * - StoreEntry::releaseRequest was always called if entry was valid */ assert(logType < LOG_TYPE_MAX); logRequest(); loggingEntry(NULL); if (request) - checkFailureRatio(request->errType, al.hier.code); + checkFailureRatio(request->errType, al->hier.code); freeResources(); #if USE_ADAPTATION announceInitiatorAbort(virginHeadSource); if (adaptedBodySource != NULL) stopConsumingFrom(adaptedBodySource); #endif if (calloutContext) delete calloutContext; clientConnection = NULL; if (conn_) cbdataReferenceDone(conn_); /* moving to the next connection is handled by the context free */ dlinkDelete(&active, &ClientActiveRequests); @@ -1316,41 +1323,41 @@ /* * Identify requests that do not go through the store and client side stream * and forward them to the appropriate location. All other requests, request * them. */ void ClientHttpRequest::processRequest() { debugs(85, 4, "clientProcessRequest: " << RequestMethodStr(request->method) << " '" << uri << "'"); if (request->method == METHOD_CONNECT && !redirect.status) { #if USE_SSL if (sslBumpNeeded()) { sslBumpStart(); return; } #endif logType = LOG_TCP_MISS; getConn()->stopReading(); // tunnels read for themselves - tunnelStart(this, &out.size, &al.http.code); + tunnelStart(this, &out.size, &al->http.code); return; } httpStart(); } void ClientHttpRequest::httpStart() { PROF_start(httpStart); logType = LOG_TAG_NONE; debugs(85, 4, "ClientHttpRequest::httpStart: " << Format::log_tags[logType] << " for '" << uri << "'"); /* no one should have touched this */ assert(out.offset == 0); /* Use the Stream Luke */ clientStreamNode *node = (clientStreamNode *)client_stream.tail->data; clientStreamRead(node, this, node->readBuffer); PROF_stop(httpStart); } @@ -1475,42 +1482,42 @@ * to doCallouts(). * * If one of the callouts notices that ClientHttpRequest is no * longer valid, it should call cbdataReferenceDone() so that * ClientHttpRequest's reference count goes to zero and it will get * deleted. ClientHttpRequest will then delete ClientRequestContext. * * Note that we set the _done flags here before actually starting * the callout. This is strictly for convenience. */ extern tos_t aclMapTOS (acl_tos * head, ACLChecklist * ch); extern nfmark_t aclMapNfmark (acl_nfmark * head, ACLChecklist * ch); void ClientHttpRequest::doCallouts() { assert(calloutContext); /*Save the original request for logging purposes*/ - if (!calloutContext->http->al.request) - calloutContext->http->al.request = HTTPMSGLOCK(request); + if (!calloutContext->http->al->request) + calloutContext->http->al->request = HTTPMSGLOCK(request); // CVE-2009-0801: verify the Host: header is consistent with other known details. if (!calloutContext->host_header_verify_done) { debugs(83, 3, HERE << "Doing calloutContext->hostHeaderVerify()"); calloutContext->host_header_verify_done = true; calloutContext->hostHeaderVerify(); return; } if (!calloutContext->http_access_done) { debugs(83, 3, HERE << "Doing calloutContext->clientAccessCheck()"); calloutContext->http_access_done = true; calloutContext->clientAccessCheck(); return; } #if USE_ADAPTATION if (!calloutContext->adaptation_acl_check_done) { calloutContext->adaptation_acl_check_done = true; if (Adaptation::AccessCheck::Start( === modified file 'src/client_side_request.h' --- src/client_side_request.h 2012-01-20 18:55:04 +0000 +++ src/client_side_request.h 2012-07-11 14:45:45 +0000 @@ -99,41 +99,41 @@ /** Details of the client socket which produced us. * Treat as read-only for the lifetime of this HTTP request. */ Comm::ConnectionPointer clientConnection; HttpRequest *request; /* Parsed URL ... */ char *uri; char *log_uri; struct { int64_t offset; int64_t size; size_t headers_sz; } out; HttpHdrRangeIter range_iter; /* data for iterating thru range specs */ size_t req_sz; /* raw request size on input, not current request size */ log_type logType; struct timeval start_time; - AccessLogEntry al; + AccessLogEntry::Pointer al; ///< access.log entry struct { unsigned int accel:1; unsigned int intercepted:1; unsigned int spoof_client_ip:1; unsigned int internal:1; unsigned int done_copying:1; unsigned int purging:1; } flags; struct { http_status status; char *location; } redirect; dlink_node active; dlink_list client_stream; int mRangeCLen(); ClientRequestContext *calloutContext; === modified file 'src/format/ByteCode.h' --- src/format/ByteCode.h 2011-11-18 07:48:25 +0000 +++ src/format/ByteCode.h 2012-07-11 17:26:37 +0000 @@ -173,37 +173,42 @@ 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 +#if USE_SSL + LFT_SSL_USER_CERT_SUBJECT, + LFT_SSL_USER_CERT_ISSUER, +#endif + LFT_PERCENT /* special string cases for escaped chars */ } ByteCode_t; /// Quoting style for a format output. enum Quoting { LOG_QUOTE_NONE = 0, LOG_QUOTE_QUOTES, LOG_QUOTE_MIMEBLOB, LOG_QUOTE_URL, LOG_QUOTE_RAW }; extern const char *log_tags[]; } // namespace Format #endif /* _SQUID_FMT_BYTECODE_H */ === modified file 'src/format/Format.cc' --- src/format/Format.cc 2012-01-20 18:55:04 +0000 +++ src/format/Format.cc 2012-07-11 17:27:11 +0000 @@ -1,68 +1,69 @@ #include "squid.h" #include "AccessLogEntry.h" #include "comm/Connection.h" #include "err_detail_type.h" #include "errorpage.h" +#include "fde.h" #include "format/Format.h" #include "format/Quoting.h" #include "format/Token.h" #include "HttpRequest.h" #include "MemBuf.h" #include "rfc1738.h" #include "SquidTime.h" #include "Store.h" #if USE_SSL #include "ssl/ErrorDetail.h" #endif /// Convert a string to NULL pointer if it is "" #define strOrNull(s) ((s)==NULL||(s)[0]=='\0'?NULL:(s)) 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) +Format::Format::parse(const char *def) { - char *cur, *eos; + const 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) { @@ -273,41 +274,41 @@ 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 +Format::Format::assemble(MemBuf &mb, const AccessLogEntry::Pointer &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: @@ -987,40 +988,60 @@ 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; +#if USE_SSL + case LFT_SSL_USER_CERT_SUBJECT: + if (X509 *cert = al->cache.sslClientCert.get()) { + if (X509_NAME *subject = X509_get_subject_name(cert)) { + X509_NAME_oneline(subject, tmp, sizeof(tmp)); + out = tmp; + } + } + break; + + case LFT_SSL_USER_CERT_ISSUER: + if (X509 *cert = al->cache.sslClientCert.get()) { + if (X509_NAME *issuer = X509_get_issuer_name(cert)) { + X509_NAME_oneline(issuer, tmp, sizeof(tmp)); + out = tmp; + } + } + break; +#endif + case LFT_PERCENT: out = "%"; break; } if (dooff) { snprintf(tmp, sizeof(tmp), "%0*" PRId64, fmt->zero && fmt->widthMin >= 0 ? fmt->widthMin : 0, outoff); out = tmp; } else if (doint) { snprintf(tmp, sizeof(tmp), "%0*ld", fmt->zero && fmt->widthMin >= 0 ? fmt->widthMin : 0, outint); out = tmp; } if (out && *out) { if (quote || fmt->quote != LOG_QUOTE_NONE) { char *newout = NULL; int newfree = 0; === modified file 'src/format/Format.h' --- src/format/Format.h 2011-08-04 03:21:06 +0000 +++ src/format/Format.h 2012-07-11 16:02:21 +0000 @@ -1,51 +1,53 @@ #ifndef _SQUID_FORMAT_FORMAT_H #define _SQUID_FORMAT_FORMAT_H +#include "RefCount.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; +typedef RefCount AccessLogEntryPointer; 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); + bool parse(const char *def); /// assemble the state information into a formatted line. - void assemble(MemBuf &mb, AccessLogEntry *al, int logSequenceNumber) const; + void assemble(MemBuf &mb, const AccessLogEntryPointer &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 */ === modified file 'src/format/Token.cc' --- src/format/Token.cc 2012-05-12 03:21:00 +0000 +++ src/format/Token.cc 2012-07-11 17:26:56 +0000 @@ -169,84 +169,94 @@ {"st", LFT_ICAP_BYTES_SENT}, {"h", LFT_ICAP_REQ_HEADER}, {"cert_subject", LFT_SSL_USER_CERT_SUBJECT}, + {">cert_issuer", LFT_SSL_USER_CERT_ISSUER}, + {NULL, LFT_NONE} +}; +#endif } // namespace Format /// Register all components custom format tokens void Format::Token::Init() { // TODO standard log tokens // TODO external ACL fmt tokens #if USE_ADAPTATION TheConfig.registerTokens(String("adapt"),::Format::TokenTableAdapt); #endif #if ICAP_CLIENT TheConfig.registerTokens(String("icap"),::Format::TokenTableIcap); #endif - // TODO tokens for OpenSSL errors in "ssl::" +#if USE_SSL + TheConfig.registerTokens(String("ssl"),::Format::TokenTableSsl); +#endif } /// Scans a token table to see if the next token exists there /// returns a pointer to next unparsed byte and updates type member if found -char * -Format::Token::scanForToken(TokenTableEntry const table[], char *cur) +const char * +Format::Token::scanForToken(TokenTableEntry const table[], const char *cur) { for (TokenTableEntry const *lte = table; lte->configTag != NULL; lte++) { debugs(46, 8, HERE << "compare tokens '" << lte->configTag << "' with '" << cur << "'"); if (strncmp(lte->configTag, cur, strlen(lte->configTag)) == 0) { type = lte->tokenType; label = lte->configTag; debugs(46, 7, HERE << "Found token '" << label << "'"); return cur + strlen(lte->configTag); } } return cur; } /* 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 -Format::Token::parse(char *def, Quoting *quoting) +Format::Token::parse(const char *def, Quoting *quoting) { - char *cur = def; + const char *cur = def; int l; l = strcspn(cur, "%"); if (l > 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; @@ -301,45 +311,50 @@ 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)) - widthMin = strtol(cur, &cur, 10); + char *endp; + if (xisdigit(*cur)) { + widthMin = strtol(cur, &endp, 10); + cur = endp; + } - if (*cur == '.' && xisdigit(*(++cur))) - widthMax = strtol(cur, &cur, 10); + if (*cur == '.' && xisdigit(*(++cur))) { + widthMax = strtol(cur, &endp, 10); + cur = endp; + } 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++; } type = LFT_NONE; // Scan each registered token namespace debugs(46, 9, HERE << "check for token in " << TheConfig.tokens.size() << " namespaces."); for (std::list::const_iterator itr = TheConfig.tokens.begin(); itr != TheConfig.tokens.end(); itr++) { debugs(46, 7, HERE << "check for possible " << itr->prefix << ":: token"); === modified file 'src/format/Token.h' --- src/format/Token.h 2011-11-18 07:48:25 +0000 +++ src/format/Token.h 2012-07-05 17:58:26 +0000 @@ -31,52 +31,52 @@ label(NULL), widthMin(-1), widthMax(-1), quote(LOG_QUOTE_NONE), left(0), space(0), zero(0), divisor(0), next(NULL) { data.string = NULL; } ~Token(); /// Initialize the format token registrations static void Init(); /** 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); + int parse(const char *def, enum Quoting *quote); ByteCode_t type; const char *label; union { char *string; struct { char *header; char *element; char separator; } header; char *timespec; } data; int widthMin; ///< minimum field width int widthMax; ///< maximum field width enum Quoting quote; unsigned int left:1; unsigned int space:1; unsigned int zero:1; int divisor; Token *next; /* todo: move from linked list to array */ private: - char *scanForToken(TokenTableEntry const table[], char *cur); + const char *scanForToken(TokenTableEntry const table[], const char *cur); }; extern const char *log_tags[]; } // namespace Format #endif /* _SQUID_FORMAT_TOKEN_H */ === modified file 'src/htcp.cc' --- src/htcp.cc 2012-04-25 05:29:20 +0000 +++ src/htcp.cc 2012-07-11 16:41:56 +0000 @@ -1700,32 +1700,32 @@ */ assert(Comm::IsConnOpen(htcpOutgoingConn)); Comm::SetSelect(htcpOutgoingConn->fd, COMM_SELECT_READ, NULL, NULL, 0); } void htcpClosePorts(void) { htcpSocketShutdown(); if (htcpOutgoingConn != NULL) { debugs(12, DBG_IMPORTANT, "Stop sending HTCP from " << htcpOutgoingConn->local); htcpOutgoingConn = NULL; } } static void htcpLogHtcp(Ip::Address &caddr, int opcode, log_type logcode, const char *url) { - AccessLogEntry al; + AccessLogEntry::Pointer al = new AccessLogEntry; if (LOG_TAG_NONE == logcode) return; if (!Config.onoff.log_udp) return; - al.htcp.opcode = htcpOpcodeStr[opcode]; - al.url = url; - al.cache.caddr = caddr; - al.cache.code = logcode; - al.cache.msec = 0; - accessLogLog(&al, NULL); + al->htcp.opcode = htcpOpcodeStr[opcode]; + al->url = url; + al->cache.caddr = caddr; + al->cache.code = logcode; + al->cache.msec = 0; + accessLogLog(al, NULL); } === modified file 'src/http.cc' --- src/http.cc 2012-06-16 15:03:46 +0000 +++ src/http.cc 2012-06-29 16:57:43 +0000 @@ -71,40 +71,42 @@ #include "StatCounters.h" #include "Store.h" #define SQUID_ENTER_THROWING_CODE() try { #define SQUID_EXIT_THROWING_CODE(status) \ status = true; \ } \ catch (const std::exception &e) { \ debugs (11, 1, "Exception error:" << e.what()); \ status = false; \ } CBDATA_CLASS_INIT(HttpStateData); static const char *const crlf = "\r\n"; static void httpMaybeRemovePublic(StoreEntry *, http_status); static void copyOneHeaderFromClientsideRequestToUpstreamRequest(const HttpHeaderEntry *e, const String strConnection, const HttpRequest * request, HttpHeader * hdr_out, const int we_do_ranges, const http_state_flags); +//Declared in HttpHeaderTools.cc +void httpHdrAdd(HttpHeader *heads, HttpRequest *request, HeaderWithAclList &headers_add); HttpStateData::HttpStateData(FwdState *theFwdState) : AsyncJob("HttpStateData"), ServerStateData(theFwdState), lastChunk(0), header_bytes_read(0), reply_bytes_read(0), body_bytes_truncated(0), httpChunkDecoder(NULL) { debugs(11,5,HERE << "HttpStateData " << this << " created"); ignoreCacheControl = false; surrogateNoStore = false; serverConnection = fwd->serverConnection(); readBuf = new MemBuf; readBuf->init(16*1024, 256*1024); // reset peer response time stats for %hier.peer_http_request_sent.tv_sec = 0; request->hier.peer_http_request_sent.tv_usec = 0; if (fwd->serverConnection() != NULL) _peer = cbdataReference(fwd->serverConnection()->getPeer()); /* might be NULL */ if (_peer) { @@ -1768,40 +1770,43 @@ if (flags.keepalive) { hdr_out->putStr(HDR_CONNECTION, "keep-alive"); } /* append Front-End-Https */ if (flags.front_end_https) { if (flags.front_end_https == 1 || request->protocol == AnyP::PROTO_HTTPS) hdr_out->putStr(HDR_FRONT_END_HTTPS, "On"); } if (flags.chunked_request) { // Do not just copy the original value so that if the client-side // starts decode other encodings, this code may remain valid. hdr_out->putStr(HDR_TRANSFER_ENCODING, "chunked"); } /* Now mangle the headers. */ if (Config2.onoff.mangle_request_headers) httpHdrMangleList(hdr_out, request, ROR_REQUEST); + if (Config.request_header_add && !Config.request_header_add->empty()) + httpHdrAdd(hdr_out, request, *Config.request_header_add); + strConnection.clean(); } /** * Decides whether a particular header may be cloned from the received Clients request * to our outgoing fetch request. */ void copyOneHeaderFromClientsideRequestToUpstreamRequest(const HttpHeaderEntry *e, const String strConnection, const HttpRequest * request, HttpHeader * hdr_out, const int we_do_ranges, const http_state_flags flags) { debugs(11, 5, "httpBuildRequestHeader: " << e->name << ": " << e->value ); switch (e->id) { /** \par RFC 2616 sect 13.5.1 - Hop-by-Hop headers which Squid should not pass on. */ case HDR_PROXY_AUTHORIZATION: /** \par Proxy-Authorization: * Only pass on proxy authentication to peers for which * authentication forwarding is explicitly enabled === modified file 'src/icp_v2.cc' --- src/icp_v2.cc 2012-04-25 05:29:20 +0000 +++ src/icp_v2.cc 2012-07-11 16:43:48 +0000 @@ -169,66 +169,66 @@ #endif /* USE_ICMP */ if (icpGetCommonOpcode() != ICP_ERR) codeToSend = icpGetCommonOpcode(); else if (Config.onoff.test_reachability && rtt == 0) codeToSend = ICP_MISS_NOFETCH; else codeToSend = ICP_MISS; } icpCreateAndSend(codeToSend, flags, url, header.reqnum, src_rtt, fd, from); delete this; } /* End ICP2State */ /// \ingroup ServerProtocolICPInternal2 static void icpLogIcp(const Ip::Address &caddr, log_type logcode, int len, const char *url, int delay) { - AccessLogEntry al; + AccessLogEntry::Pointer al = new AccessLogEntry(); if (LOG_TAG_NONE == logcode) return; if (LOG_ICP_QUERY == logcode) return; clientdbUpdate(caddr, logcode, AnyP::PROTO_ICP, len); if (!Config.onoff.log_udp) return; - al.icp.opcode = ICP_QUERY; + al->icp.opcode = ICP_QUERY; - al.url = url; + al->url = url; - al.cache.caddr = caddr; + al->cache.caddr = caddr; - al.cache.replySize = len; + al->cache.replySize = len; - al.cache.code = logcode; + al->cache.code = logcode; - al.cache.msec = delay; + al->cache.msec = delay; - accessLogLog(&al, NULL); + accessLogLog(al, NULL); } /// \ingroup ServerProtocolICPInternal2 void icpUdpSendQueue(int fd, void *unused) { icpUdpData *q; while ((q = IcpQueueHead) != NULL) { int delay = tvSubUsec(q->queue_time, current_time); /* increment delay to prevent looping */ const int x = icpUdpSend(fd, q->address, (icp_common_t *) q->msg, q->logcode, ++delay); IcpQueueHead = q->next; xfree(q); if (x < 0) break; } } === modified file 'src/log/FormatHttpdCombined.cc' --- src/log/FormatHttpdCombined.cc 2012-06-22 03:49:38 +0000 +++ src/log/FormatHttpdCombined.cc 2012-07-11 16:11:26 +0000 @@ -25,50 +25,50 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. * */ #include "squid.h" #include "AccessLogEntry.h" #include "format/Token.h" #include "format/Quoting.h" #include "HttpRequest.h" #include "log/File.h" #include "log/Formats.h" #include "SquidTime.h" void -Log::Format::HttpdCombined(AccessLogEntry * al, Logfile * logfile) +Log::Format::HttpdCombined(const AccessLogEntry::Pointer &al, Logfile * logfile) { const char *user_ident = ::Format::QuoteUrlEncodeUsername(al->cache.rfc931); const char *user_auth = ::Format::QuoteUrlEncodeUsername(al->cache.authuser); const char *referer = NULL; const char *agent = NULL; - if (al && al->request) { + if (al->request) { referer = al->request->header.getStr(HDR_REFERER); agent = al->request->header.getStr(HDR_USER_AGENT); } if (!referer || *referer == '\0') referer = "-"; if (!agent || *agent == '\0') agent = "-"; char clientip[MAX_IPSTRLEN]; al->getLogClientIp(clientip, MAX_IPSTRLEN); logfilePrintf(logfile, "%s %s %s [%s] \"%s %s %s/%d.%d\" %d %" PRId64 " \"%s\" \"%s\" %s%s:%s%s", clientip, user_ident ? user_ident : dash_str, user_auth ? user_auth : dash_str, Time::FormatHttpd(squid_curtime), al->_private.method_str, al->url, === modified file 'src/log/FormatHttpdCommon.cc' --- src/log/FormatHttpdCommon.cc 2012-06-22 03:49:38 +0000 +++ src/log/FormatHttpdCommon.cc 2012-07-11 16:12:00 +0000 @@ -24,41 +24,41 @@ * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. * */ #include "squid.h" #include "AccessLogEntry.h" #include "format/Quoting.h" #include "format/Token.h" #include "log/File.h" #include "log/Formats.h" #include "SquidTime.h" void -Log::Format::HttpdCommon(AccessLogEntry * al, Logfile * logfile) +Log::Format::HttpdCommon(const AccessLogEntry::Pointer &al, Logfile * logfile) { const char *user_auth = ::Format::QuoteUrlEncodeUsername(al->cache.authuser); const char *user_ident = ::Format::QuoteUrlEncodeUsername(al->cache.rfc931); char clientip[MAX_IPSTRLEN]; al->getLogClientIp(clientip, MAX_IPSTRLEN); logfilePrintf(logfile, "%s %s %s [%s] \"%s %s %s/%d.%d\" %d %" PRId64 " %s%s:%s%s", clientip, user_ident ? user_ident : dash_str, user_auth ? user_auth : dash_str, Time::FormatHttpd(squid_curtime), al->_private.method_str, al->url, AnyP::ProtocolType_str[al->http.version.protocol], al->http.version.major, al->http.version.minor, al->http.code, al->cache.replySize, ::Format::log_tags[al->cache.code], al->http.statusSfx(), === modified file 'src/log/FormatSquidCustom.cc' --- src/log/FormatSquidCustom.cc 2012-01-20 18:55:04 +0000 +++ src/log/FormatSquidCustom.cc 2012-07-11 16:12:26 +0000 @@ -22,30 +22,30 @@ * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. * */ #include "squid.h" #include "AccessLogEntry.h" #include "log/File.h" #include "log/Formats.h" #include "MemBuf.h" void -Log::Format::SquidCustom(AccessLogEntry * al, customlog * log) +Log::Format::SquidCustom(const AccessLogEntry::Pointer &al, customlog * log) { static MemBuf mb; mb.reset(); // 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(log->logfile, "%s\n", mb.buf); } === modified file 'src/log/FormatSquidIcap.cc' --- src/log/FormatSquidIcap.cc 2012-06-22 03:49:38 +0000 +++ src/log/FormatSquidIcap.cc 2012-07-11 16:12:57 +0000 @@ -27,41 +27,41 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. * */ #include "squid.h" #if ICAP_CLIENT #include "AccessLogEntry.h" #include "format/Quoting.h" #include "HttpRequest.h" #include "log/File.h" #include "log/Formats.h" #include "SquidTime.h" void -Log::Format::SquidIcap(AccessLogEntry * al, Logfile * logfile) +Log::Format::SquidIcap(const AccessLogEntry::Pointer &al, Logfile * logfile) { const char *client = NULL; const char *user = NULL; char tmp[MAX_IPSTRLEN], clientbuf[MAX_IPSTRLEN]; if (al->cache.caddr.IsAnyAddr()) { // ICAP OPTIONS xactions lack client client = "-"; } else { if (Config.onoff.log_fqdn) client = fqdncache_gethostbyaddr(al->cache.caddr, FQDN_LOOKUP_IF_MISS); if (!client) client = al->cache.caddr.NtoA(clientbuf, MAX_IPSTRLEN); } user = ::Format::QuoteUrlEncodeUsername(al->cache.authuser); if (!user) user = ::Format::QuoteUrlEncodeUsername(al->cache.extuser); #if USE_SSL === modified file 'src/log/FormatSquidNative.cc' --- src/log/FormatSquidNative.cc 2012-06-22 03:49:38 +0000 +++ src/log/FormatSquidNative.cc 2012-07-11 16:13:34 +0000 @@ -24,41 +24,41 @@ * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. * */ #include "squid.h" #include "AccessLogEntry.h" #include "format/Quoting.h" #include "format/Token.h" #include "log/File.h" #include "log/Formats.h" #include "SquidTime.h" void -Log::Format::SquidNative(AccessLogEntry * al, Logfile * logfile) +Log::Format::SquidNative(const AccessLogEntry::Pointer &al, Logfile * logfile) { char hierHost[MAX_IPSTRLEN]; const char *user = ::Format::QuoteUrlEncodeUsername(al->cache.authuser); if (!user) user = ::Format::QuoteUrlEncodeUsername(al->cache.extuser); #if USE_SSL if (!user) user = ::Format::QuoteUrlEncodeUsername(al->cache.ssluser); #endif if (!user) user = ::Format::QuoteUrlEncodeUsername(al->cache.rfc931); if (user && !*user) safe_free(user); char clientip[MAX_IPSTRLEN]; === modified file 'src/log/FormatSquidReferer.cc' --- src/log/FormatSquidReferer.cc 2012-02-27 10:03:03 +0000 +++ src/log/FormatSquidReferer.cc 2012-07-11 16:14:30 +0000 @@ -24,39 +24,39 @@ * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. * */ #include "squid.h" #include "AccessLogEntry.h" #include "HttpRequest.h" #include "log/File.h" #include "log/Formats.h" #include "SquidTime.h" void -Log::Format::SquidReferer(AccessLogEntry *al, Logfile *logfile) +Log::Format::SquidReferer(const AccessLogEntry::Pointer &al, Logfile *logfile) { const char *referer = NULL; - if (al && al->request) + if (al->request) referer = al->request->header.getStr(HDR_REFERER); if (!referer || *referer == '\0') referer = "-"; char clientip[MAX_IPSTRLEN]; al->getLogClientIp(clientip, MAX_IPSTRLEN); logfilePrintf(logfile, "%9ld.%03d %s %s %s\n", (long int) current_time.tv_sec, (int) current_time.tv_usec / 1000, clientip, referer, al->url ? al->url : "-"); } === modified file 'src/log/FormatSquidUseragent.cc' --- src/log/FormatSquidUseragent.cc 2012-02-27 10:03:03 +0000 +++ src/log/FormatSquidUseragent.cc 2012-07-11 16:15:04 +0000 @@ -24,38 +24,38 @@ * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. * */ #include "squid.h" #include "AccessLogEntry.h" #include "HttpRequest.h" #include "log/File.h" #include "log/Formats.h" #include "SquidTime.h" void -Log::Format::SquidUserAgent(AccessLogEntry * al, Logfile * logfile) +Log::Format::SquidUserAgent(const AccessLogEntry::Pointer &al, Logfile * logfile) { const char *agent = NULL; - if (al && al->request) + if (al->request) agent = al->request->header.getStr(HDR_USER_AGENT); if (!agent || *agent == '\0') agent = "-"; char clientip[MAX_IPSTRLEN]; al->getLogClientIp(clientip, MAX_IPSTRLEN); logfilePrintf(logfile, "%s [%s] \"%s\"\n", clientip, Time::FormatHttpd(squid_curtime), agent); } === modified file 'src/log/Formats.h' --- src/log/Formats.h 2010-12-12 05:30:58 +0000 +++ src/log/Formats.h 2012-07-11 16:08:25 +0000 @@ -1,51 +1,54 @@ #ifndef _SQUID_LOG_FORMATS_H #define _SQUID_LOG_FORMATS_H +#include "RefCount.h" + +typedef RefCount AccessLogEntryPointer; class AccessLogEntry; class Logfile; namespace Log { namespace Format { typedef enum { CLF_UNKNOWN, CLF_COMBINED, CLF_COMMON, CLF_CUSTOM, #if ICAP_CLIENT CLF_ICAP_SQUID, #endif CLF_REFERER, CLF_SQUID, CLF_USERAGENT, CLF_NONE } log_type; /// Native Squid Format Display -void SquidNative(AccessLogEntry * al, Logfile * logfile); +void SquidNative(const AccessLogEntryPointer &al, Logfile * logfile); /// Display log details in Squid ICAP format. -void SquidIcap(AccessLogEntry * al, Logfile * logfile); +void SquidIcap(const AccessLogEntryPointer &al, Logfile * logfile); /// Display log details in useragent format. -void SquidUserAgent(AccessLogEntry * al, Logfile * logfile); +void SquidUserAgent(const AccessLogEntryPointer &al, Logfile * logfile); /// Display log details in Squid old refererlog format. -void SquidReferer(AccessLogEntry * al, Logfile * logfile); +void SquidReferer(const AccessLogEntryPointer &al, Logfile * logfile); /// Log with a local custom format -void SquidCustom(AccessLogEntry * al, customlog * log); +void SquidCustom(const AccessLogEntryPointer &al, customlog * log); /// Log with Apache httpd common format -void HttpdCommon(AccessLogEntry * al, Logfile * logfile); +void HttpdCommon(const AccessLogEntryPointer &al, Logfile * logfile); /// Log with Apache httpd combined format -void HttpdCombined(AccessLogEntry * al, Logfile * logfile); +void HttpdCombined(const AccessLogEntryPointer &al, Logfile * logfile); }; // namespace Format }; // namespace Log #endif /* _SQUID_LOG_FORMATS_H */ === modified file 'src/log/access_log.cc' --- src/log/access_log.cc 2012-01-20 18:55:04 +0000 +++ src/log/access_log.cc 2012-07-11 15:53:34 +0000 @@ -74,41 +74,41 @@ typedef struct { hash_link hash; int n; } fvdb_entry; static hash_table *via_table = NULL; static hash_table *forw_table = NULL; static void fvdbInit(); static void fvdbDumpTable(StoreEntry * e, hash_table * hash); static void fvdbCount(hash_table * hash, const char *key); static OBJH fvdbDumpVia; static OBJH fvdbDumpForw; static FREE fvdbFreeEntry; static void fvdbClear(void); static void fvdbRegisterWithCacheManager(); #endif int LogfileStatus = LOG_DISABLE; void -accessLogLogTo(customlog* log, AccessLogEntry * al, ACLChecklist * checklist) +accessLogLogTo(customlog* log, AccessLogEntry::Pointer &al, ACLChecklist * checklist) { if (al->url == NULL) al->url = dash_str; if (!al->http.content_type || *al->http.content_type == '\0') al->http.content_type = dash_str; if (al->icp.opcode) al->_private.method_str = icp_opcode_str[al->icp.opcode]; else if (al->htcp.opcode) al->_private.method_str = al->htcp.opcode; else al->_private.method_str = RequestMethodStr(al->http.method); if (al->hier.host[0] == '\0') xstrncpy(al->hier.host, dash_str, SQUIDHOSTNAMELEN); for (; log; log = log->next) { if (log->aclList && checklist && checklist->fastCheck(log->aclList) != ACCESS_ALLOWED) @@ -150,41 +150,41 @@ #endif case Log::Format::CLF_NONE: return; // abort! default: fatalf("Unknown log format %d\n", log->type); break; } logfileLineEnd(log->logfile); } // NP: WTF? if _any_ log line has no checklist ignore the following ones? if (!checklist) break; } } void -accessLogLog(AccessLogEntry * al, ACLChecklist * checklist) +accessLogLog(AccessLogEntry::Pointer &al, ACLChecklist * checklist) { if (LogfileStatus != LOG_ENABLE) return; accessLogLogTo(Config.Log.accesslogs, al, checklist); #if MULTICAST_MISS_STREAM if (al->cache.code != LOG_TCP_MISS) (void) 0; else if (al->http.method != METHOD_GET) (void) 0; else if (mcast_miss_fd < 0) (void) 0; else { unsigned int ibuf[365]; size_t isize; xstrncpy((char *) ibuf, al->url, 364 * sizeof(int)); isize = ((strlen(al->url) + 8) / 8) * 2; if (isize > 364) @@ -558,64 +558,40 @@ magic |= 0x5300; } magic = htons(magic); ccmask = htonl(ccmask); if (0 == pq) S = (unsigned short) rep->sline.status; else S = (unsigned short) HTTP_STATUS_NONE; logfileWrite(headerslog, &magic, sizeof(magic)); logfileWrite(headerslog, &M, sizeof(M)); logfileWrite(headerslog, &S, sizeof(S)); logfileWrite(headerslog, hmask, sizeof(HttpHeaderMask)); logfileWrite(headerslog, &ccmask, sizeof(int)); } #endif -void -accessLogFreeMemory(AccessLogEntry * aLogEntry) -{ - safe_free(aLogEntry->headers.request); - -#if ICAP_CLIENT - safe_free(aLogEntry->adapt.last_meta); -#endif - - safe_free(aLogEntry->headers.reply); - safe_free(aLogEntry->cache.authuser); - - safe_free(aLogEntry->headers.adapted_request); - HTTPMSGUNLOCK(aLogEntry->adapted_request); - - HTTPMSGUNLOCK(aLogEntry->reply); - HTTPMSGUNLOCK(aLogEntry->request); -#if ICAP_CLIENT - HTTPMSGUNLOCK(aLogEntry->icap.reply); - HTTPMSGUNLOCK(aLogEntry->icap.request); -#endif - cbdataReferenceDone(aLogEntry->cache.port); -} - int logTypeIsATcpHit(log_type code) { /* this should be a bitmap for better optimization */ if (code == LOG_TCP_HIT) return 1; if (code == LOG_TCP_IMS_HIT) return 1; if (code == LOG_TCP_REFRESH_FAIL_OLD) return 1; if (code == LOG_TCP_REFRESH_UNMODIFIED) return 1; if (code == LOG_TCP_NEGATIVE_HIT) return 1; === modified file 'src/structs.h' --- src/structs.h 2012-06-29 16:36:58 +0000 +++ src/structs.h 2012-06-29 16:58:28 +0000 @@ -557,40 +557,42 @@ } dns, udp, tcp; } comm_incoming; int max_open_disk_fds; int uri_whitespace; acl_size_t *rangeOffsetLimit; #if MULTICAST_MISS_STREAM struct { Ip::Address addr; int ttl; unsigned short port; char *encode_key; } mcast_miss; #endif /// request_header_access and request_header_replace HeaderManglers *request_header_access; /// reply_header_access and reply_header_replace HeaderManglers *reply_header_access; + ///request_header_add access list + HeaderWithAclList *request_header_add; char *coredump_dir; char *chroot_dir; #if USE_CACHE_DIGESTS struct { int bits_per_entry; time_t rebuild_period; time_t rewrite_period; size_t swapout_chunk_size; int rebuild_chunk_percentage; } digest; #endif #if USE_SSL struct { int unclean_shutdown; char *ssl_engine; } SSL; #endif