=== 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 <robertc@squid-cache.org>
  */
 #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<AccessLogEntry> 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 <algorithm>
+#if HAVE_STRING
+#include <string>
+#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 <list>
+#endif
 #if HAVE_MAP
 #include <map>
 #endif
 #if HAVE_STRING
 #include <string>
 #endif
 
+class HeaderWithAcl;
+typedef std::list<HeaderWithAcl> 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<std::string, header_mangler> 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 <robertc@squid-cache.org>
  */
 
 #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<AccessLogEntry> AccessLogEntryPointer;
 
 class HttpRequest: public HttpMsg
 {
 
 public:
     typedef HttpMsgPointerT<HttpRequest> 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<HttpRequest*>(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<ConnStateData> 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<HttpRequest*>(adapted.header))) {
         request_ = (virgin.cause? virgin.cause: dynamic_cast<HttpRequest*>(virgin.header));
         reply_ = dynamic_cast<HttpReply*>(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<Launcher*>(theInitiator.get());
         // launcher may be nil if initiator is invalid
         CallJobHere1(91,5, CbcPointer<Launcher>(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<AccessLogEntry> 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 <glob.h>
 #endif
 
 #if HAVE_LIMITS_H
 #include <limits>
 #endif
 
+#if HAVE_LIST
+#include <list>
+#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 %<st %rm %ru %[un %Sh/%<a %mt
 logformat common     %>a %[ui %[un [%tl] "%rm %ru HTTP/%rv" %>Hs %<st %Ss:%Sh
 logformat combined   %>a %[ui %[un [%tl] "%rm %ru HTTP/%rv" %>Hs %<st "%{Referer}>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<clientReplyContext *>(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<ClientHttpRequest *>(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<ClientHttpRequest *>(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, &quote);
 
     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<AccessLogEntry> 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 @@
     {"<A",  LFT_ICAP_ADDR},
     {"<service_name",  LFT_ICAP_SERV_NAME},
     {"ru",  LFT_ICAP_REQUEST_URI},
     {"rm",  LFT_ICAP_REQUEST_METHOD},
     {">st", LFT_ICAP_BYTES_SENT},
     {"<st", LFT_ICAP_BYTES_READ},
     {"<bs", LFT_ICAP_BODY_BYTES_READ},
 
     {">h",  LFT_ICAP_REQ_HEADER},
     {"<h",  LFT_ICAP_REP_HEADER},
 
     {"tr",  LFT_ICAP_TR_RESPONSE_TIME},
     {"tio", LFT_ICAP_IO_TIME},
     {"to",  LFT_ICAP_OUTCOME},
     {"Hs",  LFT_ICAP_STATUS_CODE},
 
     {NULL, LFT_NONE}           /* this must be last */
 };
 #endif
 
+#if USE_SSL
+// SSL (ssl::) tokens
+static TokenTableEntry TokenTableSsl[] = {
+    {">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<TokenNamespace>::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 %<pt
     request->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<AccessLogEntry> 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
 


