2 * Copyright (C) 1996-2017 The Squid Software Foundation and contributors
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
10 #include "AccessLogEntry.h"
11 #include "client_side.h"
12 #include "comm/Connection.h"
13 #include "err_detail_type.h"
14 #include "errorpage.h"
16 #include "format/Format.h"
17 #include "format/Quoting.h"
18 #include "format/Token.h"
19 #include "fqdncache.h"
20 #include "http/Stream.h"
21 #include "HttpRequest.h"
24 #include "sbuf/StringConvert.h"
25 #include "security/CertError.h"
26 #include "security/NegotiationHistory.h"
27 #include "SquidTime.h"
32 #include "ssl/ErrorDetail.h"
33 #include "ssl/ServerBump.h"
36 /// Convert a string to NULL pointer if it is ""
37 #define strOrNull(s) ((s)==NULL||(s)[0]=='\0'?NULL:(s))
39 const SBuf
Format::Dash("-");
41 Format::Format::Format(const char *n
) :
48 Format::Format::~Format()
50 // erase the list without consuming stack space
52 // unlink the next entry for deletion
65 Format::Format::parse(const char *def
)
67 const char *cur
, *eos
;
68 Token
*new_lt
, *last_lt
;
69 enum Quoting quote
= LOG_QUOTE_NONE
;
71 debugs(46, 2, HERE
<< "got definition '" << def
<< "'");
74 debugs(46, DBG_IMPORTANT
, "WARNING: existing format for '" << name
<< " " << def
<< "'");
78 /* very inefficent parser, but who cares, this needs to be simple */
79 /* First off, let's tokenize, we'll optimize in a second pass.
80 * A token can either be a %-prefixed sequence (usually a dynamic
81 * token but it can be an escaped sequence), or a string. */
83 eos
= def
+ strlen(def
);
84 format
= new_lt
= last_lt
= new Token
;
85 cur
+= new_lt
->parse(cur
, "e
);
89 last_lt
->next
= new_lt
;
91 cur
+= new_lt
->parse(cur
, "e
);
98 Format::Format::dump(StoreEntry
* entry
, const char *directiveName
, bool eol
) const
102 // loop rather than recursing to conserve stack space.
103 for (const Format
*fmt
= this; fmt
; fmt
= fmt
->next
) {
104 debugs(46, 3, HERE
<< "Dumping format definition for " << fmt
->name
);
106 storeAppendPrintf(entry
, "%s %s ", directiveName
, fmt
->name
);
108 for (Token
*t
= fmt
->format
; t
; t
= t
->next
) {
109 if (t
->type
== LFT_STRING
)
110 storeAppendPrintf(entry
, "%s", t
->data
.string
);
114 ByteCode_t type
= t
->type
;
122 case LFT_ADAPTATION_LAST_HEADER_ELEM
:
125 case LFT_ICAP_REQ_HEADER_ELEM
:
126 case LFT_ICAP_REP_HEADER_ELEM
:
128 case LFT_REQUEST_HEADER_ELEM
:
129 case LFT_ADAPTED_REQUEST_HEADER_ELEM
:
130 case LFT_REPLY_HEADER_ELEM
:
132 if (t
->data
.header
.separator
!= ',')
133 snprintf(argbuf
, sizeof(argbuf
), "%s:%c%s", t
->data
.header
.header
, t
->data
.header
.separator
, t
->data
.header
.element
);
135 snprintf(argbuf
, sizeof(argbuf
), "%s:%s", t
->data
.header
.header
, t
->data
.header
.element
);
140 case LFT_REQUEST_HEADER_ELEM
:
141 type
= LFT_REQUEST_HEADER_ELEM
; // XXX: remove _ELEM?
143 case LFT_ADAPTED_REQUEST_HEADER_ELEM
:
144 type
= LFT_ADAPTED_REQUEST_HEADER_ELEM
; // XXX: remove _ELEM?
146 case LFT_REPLY_HEADER_ELEM
:
147 type
= LFT_REPLY_HEADER_ELEM
; // XXX: remove _ELEM?
150 case LFT_ADAPTATION_LAST_HEADER_ELEM
:
151 type
= LFT_ADAPTATION_LAST_HEADER
;
155 case LFT_ICAP_REQ_HEADER_ELEM
:
156 type
= LFT_ICAP_REQ_HEADER
;
158 case LFT_ICAP_REP_HEADER_ELEM
:
159 type
= LFT_ICAP_REP_HEADER
;
168 case LFT_REQUEST_ALL_HEADERS
:
169 case LFT_ADAPTED_REQUEST_ALL_HEADERS
:
170 case LFT_REPLY_ALL_HEADERS
:
173 case LFT_ADAPTATION_LAST_ALL_HEADERS
:
176 case LFT_ICAP_REQ_ALL_HEADERS
:
177 case LFT_ICAP_REP_ALL_HEADERS
:
181 case LFT_REQUEST_ALL_HEADERS
:
182 type
= LFT_REQUEST_HEADER
;
184 case LFT_ADAPTED_REQUEST_ALL_HEADERS
:
185 type
= LFT_ADAPTED_REQUEST_HEADER
;
187 case LFT_REPLY_ALL_HEADERS
:
188 type
= LFT_REPLY_HEADER
;
191 case LFT_ADAPTATION_LAST_ALL_HEADERS
:
192 type
= LFT_ADAPTATION_LAST_HEADER
;
196 case LFT_ICAP_REQ_ALL_HEADERS
:
197 type
= LFT_ICAP_REQ_HEADER
;
199 case LFT_ICAP_REP_ALL_HEADERS
:
200 type
= LFT_ICAP_REP_HEADER
;
211 arg
= t
->data
.string
;
216 entry
->append("%", 1);
220 case LOG_QUOTE_QUOTES
:
221 entry
->append("\"", 1);
224 case LOG_QUOTE_MIMEBLOB
:
225 entry
->append("[", 1);
229 entry
->append("#", 1);
233 entry
->append("'", 1);
236 case LOG_QUOTE_SHELL
:
237 entry
->append("/", 1);
245 entry
->append("-", 1);
248 entry
->append("0", 1);
250 if (t
->widthMin
>= 0)
251 storeAppendPrintf(entry
, "%d", t
->widthMin
);
253 if (t
->widthMax
>= 0)
254 storeAppendPrintf(entry
, ".%d", t
->widthMax
);
257 storeAppendPrintf(entry
, "{%s}", arg
);
259 storeAppendPrintf(entry
, "%s", t
->label
);
262 entry
->append(" ", 1);
267 entry
->append("\n", 1);
273 log_quoted_string(const char *str
, char *out
)
278 int l
= strcspn(str
, "\"\\\r\n\t");
327 sslErrorName(Security::ErrorCode err
, char *buf
, size_t size
)
329 snprintf(buf
, size
, "SSL_ERR=%d", err
);
334 /// XXX: Misnamed. TODO: Split <h (and this function) to distinguish received
335 /// headers from sent headers rather than failing to distinguish requests from responses.
336 /// \retval HttpReply sent to the HTTP client (access.log and default context).
337 /// \retval HttpReply received (encapsulated) from the ICAP server (icap.log context).
338 /// \retval HttpRequest received (encapsulated) from the ICAP server (icap.log context).
339 static const Http::Message
*
340 actualReplyHeader(const AccessLogEntry::Pointer
&al
)
342 const Http::Message
*msg
= al
->reply
;
344 // al->icap.reqMethod is methodNone in access.log context
345 if (!msg
&& al
->icap
.reqMethod
== Adaptation::methodReqmod
)
346 msg
= al
->adapted_request
;
351 /// XXX: Misnamed. See actualReplyHeader().
352 /// \return HttpRequest or HttpReply for %http::>h.
353 static const Http::Message
*
354 actualRequestHeader(const AccessLogEntry::Pointer
&al
)
357 // al->icap.reqMethod is methodNone in access.log context
358 if (al
->icap
.reqMethod
== Adaptation::methodRespmod
) {
359 // XXX: for now AccessLogEntry lacks virgin response headers
367 Format::Format::assemble(MemBuf
&mb
, const AccessLogEntry::Pointer
&al
, int logSequenceNumber
) const
369 static char tmp
[1024];
372 for (Token
*fmt
= format
; fmt
; fmt
= fmt
->next
) { /* for each token */
373 const char *out
= nullptr;
380 struct timeval outtv
= {0, 0};
391 out
= fmt
->data
.string
;
394 case LFT_CLIENT_IP_ADDRESS
:
395 al
->getLogClientIp(tmp
, sizeof(tmp
));
399 case LFT_CLIENT_FQDN
:
400 if (al
->cache
.caddr
.isAnyAddr()) // e.g., ICAP OPTIONS lack client
403 out
= fqdncache_gethostbyaddr(al
->cache
.caddr
, FQDN_LOOKUP_IF_MISS
);
406 out
= al
->cache
.caddr
.toStr(tmp
, sizeof(tmp
));
410 case LFT_CLIENT_PORT
:
412 outint
= al
->request
->client_addr
.port();
414 } else if (al
->tcpClient
) {
415 outint
= al
->tcpClient
->remote
.port();
422 // TODO make the ACL checklist have a direct link to any TCP details.
423 if (al
->request
&& al
->request
->clientConnectionManager
.valid() &&
424 al
->request
->clientConnectionManager
->clientConnection
) {
425 const auto &conn
= al
->request
->clientConnectionManager
->clientConnection
;
426 if (conn
->remote
.isIPv4())
427 conn
->remoteEui48
.encode(tmp
, sizeof(tmp
));
429 conn
->remoteEui64
.encode(tmp
, sizeof(tmp
));
435 case LFT_EXT_ACL_CLIENT_EUI48
:
437 if (al
->request
&& al
->request
->clientConnectionManager
.valid() &&
438 al
->request
->clientConnectionManager
->clientConnection
&&
439 al
->request
->clientConnectionManager
->clientConnection
->remote
.isIPv4()) {
440 al
->request
->clientConnectionManager
->clientConnection
->remoteEui48
.encode(tmp
, sizeof(tmp
));
446 case LFT_EXT_ACL_CLIENT_EUI64
:
448 if (al
->request
&& al
->request
->clientConnectionManager
.valid() &&
449 al
->request
->clientConnectionManager
->clientConnection
&&
450 !al
->request
->clientConnectionManager
->clientConnection
->remote
.isIPv4()) {
451 al
->request
->clientConnectionManager
->clientConnection
->remoteEui64
.encode(tmp
, sizeof(tmp
));
457 case LFT_SERVER_IP_ADDRESS
:
458 if (al
->hier
.tcpServer
)
459 out
= al
->hier
.tcpServer
->remote
.toStr(tmp
, sizeof(tmp
));
462 case LFT_SERVER_FQDN_OR_PEER_NAME
:
466 case LFT_SERVER_PORT
:
467 if (al
->hier
.tcpServer
) {
468 outint
= al
->hier
.tcpServer
->remote
.port();
473 case LFT_LOCAL_LISTENING_IP
: {
474 // avoid logging a dash if we have reliable info
475 const bool interceptedAtKnownPort
= al
->request
?
476 (al
->request
->flags
.interceptTproxy
||
477 al
->request
->flags
.intercepted
) && al
->cache
.port
:
479 if (interceptedAtKnownPort
) {
480 const bool portAddressConfigured
= !al
->cache
.port
->s
.isAnyAddr();
481 if (portAddressConfigured
)
482 out
= al
->cache
.port
->s
.toStr(tmp
, sizeof(tmp
));
483 } else if (al
->tcpClient
)
484 out
= al
->tcpClient
->local
.toStr(tmp
, sizeof(tmp
));
488 case LFT_CLIENT_LOCAL_IP
:
490 out
= al
->tcpClient
->local
.toStr(tmp
, sizeof(tmp
));
493 case LFT_CLIENT_LOCAL_TOS
:
495 sb
.appendf("0x%x", static_cast<uint32_t>(al
->tcpClient
->tos
));
500 case LFT_CLIENT_LOCAL_NFMARK
:
502 sb
.appendf("0x%x", al
->tcpClient
->nfmark
);
507 case LFT_LOCAL_LISTENING_PORT
:
508 if (al
->cache
.port
) {
509 outint
= al
->cache
.port
->s
.port();
511 } else if (al
->request
) {
512 outint
= al
->request
->my_addr
.port();
517 case LFT_CLIENT_LOCAL_PORT
:
519 outint
= al
->tcpClient
->local
.port();
524 case LFT_SERVER_LOCAL_IP_OLD_27
:
525 case LFT_SERVER_LOCAL_IP
:
526 if (al
->hier
.tcpServer
)
527 out
= al
->hier
.tcpServer
->local
.toStr(tmp
, sizeof(tmp
));
530 case LFT_SERVER_LOCAL_PORT
:
531 if (al
->hier
.tcpServer
) {
532 outint
= al
->hier
.tcpServer
->local
.port();
537 case LFT_SERVER_LOCAL_TOS
:
538 if (al
->hier
.tcpServer
) {
539 sb
.appendf("0x%x", static_cast<uint32_t>(al
->hier
.tcpServer
->tos
));
544 case LFT_SERVER_LOCAL_NFMARK
:
545 if (al
->hier
.tcpServer
) {
546 sb
.appendf("0x%x", al
->hier
.tcpServer
->nfmark
);
551 case LFT_TIME_SECONDS_SINCE_EPOCH
:
552 // some platforms store time in 32-bit, some 64-bit...
553 outoff
= static_cast<int64_t>(current_time
.tv_sec
);
557 case LFT_TIME_SUBSECOND
:
558 outint
= current_time
.tv_usec
/ fmt
->divisor
;
562 case LFT_TIME_LOCALTIME
:
566 spec
= fmt
->data
.string
;
568 if (fmt
->type
== LFT_TIME_LOCALTIME
) {
570 spec
= "%d/%b/%Y:%H:%M:%S %z";
571 t
= localtime(&squid_curtime
);
574 spec
= "%d/%b/%Y:%H:%M:%S";
576 t
= gmtime(&squid_curtime
);
579 strftime(tmp
, sizeof(tmp
), spec
, t
);
585 outtv
= al
->cache
.start_time
;
589 case LFT_TIME_TO_HANDLE_REQUEST
:
590 outtv
= al
->cache
.trTime
;
594 case LFT_PEER_RESPONSE_TIME
:
595 if (al
->hier
.peer_response_time
.tv_sec
!= -1) {
596 outtv
= al
->hier
.peer_response_time
;
601 case LFT_TOTAL_SERVER_SIDE_RESPONSE_TIME
: {
602 timeval total_response_time
;
603 al
->hier
.totalResponseTime(total_response_time
);
604 if (total_response_time
.tv_sec
!= -1) {
605 outtv
= total_response_time
;
611 case LFT_DNS_WAIT_TIME
:
612 if (al
->request
&& al
->request
->dnsWait
>= 0) {
613 // TODO: microsecond precision for dns wait time.
614 // Convert miliseconds to timeval struct:
615 outtv
.tv_sec
= al
->request
->dnsWait
/ 1000;
616 outtv
.tv_usec
= (al
->request
->dnsWait
% 1000) * 1000;
621 case LFT_REQUEST_HEADER
:
622 if (const Http::Message
*msg
= actualRequestHeader(al
)) {
623 sb
= StringToSBuf(msg
->header
.getByName(fmt
->data
.header
.header
));
629 case LFT_ADAPTED_REQUEST_HEADER
:
630 if (al
->adapted_request
) {
631 sb
= StringToSBuf(al
->adapted_request
->header
.getByName(fmt
->data
.header
.header
));
637 case LFT_REPLY_HEADER
:
638 if (const Http::Message
*msg
= actualReplyHeader(al
)) {
639 sb
= StringToSBuf(msg
->header
.getByName(fmt
->data
.header
.header
));
646 case LFT_ADAPTATION_SUM_XACT_TIMES
:
648 Adaptation::History::Pointer ah
= al
->request
->adaptHistory();
650 ah
->sumLogString(fmt
->data
.string
, sb
);
656 case LFT_ADAPTATION_ALL_XACT_TIMES
:
658 Adaptation::History::Pointer ah
= al
->request
->adaptHistory();
660 ah
->allLogString(fmt
->data
.string
, sb
);
666 case LFT_ADAPTATION_LAST_HEADER
:
668 const Adaptation::History::Pointer ah
= al
->request
->adaptHistory();
669 if (ah
) { // XXX: add adapt::<all_h but use lastMeta here
670 sb
= StringToSBuf(ah
->allMeta
.getByName(fmt
->data
.header
.header
));
677 case LFT_ADAPTATION_LAST_HEADER_ELEM
:
679 const Adaptation::History::Pointer ah
= al
->request
->adaptHistory();
680 if (ah
) { // XXX: add adapt::<all_h but use lastMeta here
681 sb
= StringToSBuf(ah
->allMeta
.getByNameListMember(fmt
->data
.header
.header
, fmt
->data
.header
.element
, fmt
->data
.header
.separator
));
688 case LFT_ADAPTATION_LAST_ALL_HEADERS
:
689 out
= al
->adapt
.last_meta
;
696 out
= al
->icap
.hostAddr
.toStr(tmp
, sizeof(tmp
));
699 case LFT_ICAP_SERV_NAME
:
700 out
= al
->icap
.serviceName
.termedBuf();
703 case LFT_ICAP_REQUEST_URI
:
704 out
= al
->icap
.reqUri
.termedBuf();
707 case LFT_ICAP_REQUEST_METHOD
:
708 out
= Adaptation::Icap::ICAP::methodStr(al
->icap
.reqMethod
);
711 case LFT_ICAP_BYTES_SENT
:
712 outoff
= al
->icap
.bytesSent
;
716 case LFT_ICAP_BYTES_READ
:
717 outoff
= al
->icap
.bytesRead
;
721 case LFT_ICAP_BODY_BYTES_READ
:
722 if (al
->icap
.bodyBytesRead
>= 0) {
723 outoff
= al
->icap
.bodyBytesRead
;
726 // else if icap.bodyBytesRead < 0, we do not have any http data,
727 // so just print a "-" (204 responses etc)
730 case LFT_ICAP_REQ_HEADER
:
731 if (al
->icap
.request
) {
732 sb
= StringToSBuf(al
->icap
.request
->header
.getByName(fmt
->data
.header
.header
));
738 case LFT_ICAP_REQ_HEADER_ELEM
:
739 if (al
->icap
.request
) {
740 sb
= StringToSBuf(al
->icap
.request
->header
.getByNameListMember(fmt
->data
.header
.header
, fmt
->data
.header
.element
, fmt
->data
.header
.separator
));
746 case LFT_ICAP_REQ_ALL_HEADERS
:
747 if (al
->icap
.request
) {
748 HttpHeaderPos pos
= HttpHeaderInitPos
;
749 while (const HttpHeaderEntry
*e
= al
->icap
.request
->header
.getEntry(&pos
)) {
752 sb
.append(StringToSBuf(e
->value
));
760 case LFT_ICAP_REP_HEADER
:
761 if (al
->icap
.reply
) {
762 sb
= StringToSBuf(al
->icap
.reply
->header
.getByName(fmt
->data
.header
.header
));
768 case LFT_ICAP_REP_HEADER_ELEM
:
769 if (al
->icap
.reply
) {
770 sb
= StringToSBuf(al
->icap
.reply
->header
.getByNameListMember(fmt
->data
.header
.header
, fmt
->data
.header
.element
, fmt
->data
.header
.separator
));
776 case LFT_ICAP_REP_ALL_HEADERS
:
777 if (al
->icap
.reply
) {
778 HttpHeaderPos pos
= HttpHeaderInitPos
;
779 while (const HttpHeaderEntry
*e
= al
->icap
.reply
->header
.getEntry(&pos
)) {
782 sb
.append(StringToSBuf(e
->value
));
790 case LFT_ICAP_TR_RESPONSE_TIME
:
791 outtv
= al
->icap
.trTime
;
795 case LFT_ICAP_IO_TIME
:
796 outtv
= al
->icap
.ioTime
;
800 case LFT_ICAP_STATUS_CODE
:
801 outint
= al
->icap
.resStatus
;
805 case LFT_ICAP_OUTCOME
:
806 out
= al
->icap
.outcome
;
809 case LFT_ICAP_TOTAL_TIME
:
810 outtv
= al
->icap
.processingTime
;
814 case LFT_REQUEST_HEADER_ELEM
:
815 if (const Http::Message
*msg
= actualRequestHeader(al
)) {
816 sb
= StringToSBuf(msg
->header
.getByNameListMember(fmt
->data
.header
.header
, fmt
->data
.header
.element
, fmt
->data
.header
.separator
));
822 case LFT_ADAPTED_REQUEST_HEADER_ELEM
:
823 if (al
->adapted_request
) {
824 sb
= StringToSBuf(al
->adapted_request
->header
.getByNameListMember(fmt
->data
.header
.header
, fmt
->data
.header
.element
, fmt
->data
.header
.separator
));
830 case LFT_REPLY_HEADER_ELEM
:
831 if (const Http::Message
*msg
= actualReplyHeader(al
)) {
832 sb
= StringToSBuf(msg
->header
.getByNameListMember(fmt
->data
.header
.header
, fmt
->data
.header
.element
, fmt
->data
.header
.separator
));
838 case LFT_REQUEST_ALL_HEADERS
:
840 if (al
->icap
.reqMethod
== Adaptation::methodRespmod
) {
841 // XXX: since AccessLogEntry::Headers lacks virgin response
842 // headers, do nothing for now
847 out
= al
->headers
.request
;
852 case LFT_ADAPTED_REQUEST_ALL_HEADERS
:
853 out
= al
->headers
.adapted_request
;
857 case LFT_REPLY_ALL_HEADERS
:
858 out
= al
->headers
.reply
;
860 if (!out
&& al
->icap
.reqMethod
== Adaptation::methodReqmod
)
861 out
= al
->headers
.adapted_request
;
868 if (al
->request
&& al
->request
->auth_user_request
)
869 out
= strOrNull(al
->request
->auth_user_request
->username());
871 if (!out
&& al
->request
&& al
->request
->extacl_user
.size()) {
872 if (const char *t
= al
->request
->extacl_user
.termedBuf())
876 out
= strOrNull(al
->cache
.extuser
);
879 out
= strOrNull(al
->cache
.ssluser
);
882 out
= strOrNull(al
->cache
.rfc931
);
887 if (al
->request
&& al
->request
->auth_user_request
)
888 out
= strOrNull(al
->request
->auth_user_request
->username());
893 out
= strOrNull(al
->cache
.rfc931
);
896 case LFT_USER_EXTERNAL
:
897 if (al
->request
&& al
->request
->extacl_user
.size()) {
898 if (const char *t
= al
->request
->extacl_user
.termedBuf())
903 out
= strOrNull(al
->cache
.extuser
);
906 /* case LFT_USER_REALM: */
907 /* case LFT_USER_SCHEME: */
909 // the fmt->type can not be LFT_HTTP_SENT_STATUS_CODE_OLD_30
910 // but compiler complains if ommited
911 case LFT_HTTP_SENT_STATUS_CODE_OLD_30
:
912 case LFT_HTTP_SENT_STATUS_CODE
:
913 outint
= al
->http
.code
;
917 case LFT_HTTP_RECEIVED_STATUS_CODE
:
918 if (al
->hier
.peer_reply_status
!= Http::scNone
) {
919 outint
= al
->hier
.peer_reply_status
;
923 /* case LFT_HTTP_STATUS:
924 * out = statusline->text;
928 case LFT_HTTP_BODY_BYTES_READ
:
929 if (al
->hier
.bodyBytesRead
>= 0) {
930 outoff
= al
->hier
.bodyBytesRead
;
933 // else if hier.bodyBytesRead < 0 we did not have any data exchange with
934 // a peer server so just print a "-" (eg requests served from cache,
935 // or internal error messages).
938 case LFT_SQUID_STATUS
:
939 out
= al
->cache
.code
.c_str();
942 case LFT_SQUID_ERROR
:
943 if (al
->request
&& al
->request
->errType
!= ERR_NONE
)
944 out
= errorPageName(al
->request
->errType
);
947 case LFT_SQUID_ERROR_DETAIL
:
949 if (al
->request
&& al
->request
->errType
== ERR_SECURE_CONNECT_FAIL
) {
950 out
= Ssl::GetErrorName(al
->request
->errDetail
);
952 out
= sslErrorName(al
->request
->errDetail
, tmp
, sizeof(tmp
));
955 if (al
->request
&& al
->request
->errDetail
!= ERR_DETAIL_NONE
) {
956 if (al
->request
->errDetail
> ERR_DETAIL_START
&& al
->request
->errDetail
< ERR_DETAIL_MAX
)
957 out
= errorDetailName(al
->request
->errDetail
);
959 if (al
->request
->errDetail
>= ERR_DETAIL_EXCEPTION_START
)
960 sb
.appendf("%s=0x%X",
961 errorDetailName(al
->request
->errDetail
), (uint32_t) al
->request
->errDetail
);
964 errorDetailName(al
->request
->errDetail
), al
->request
->errDetail
);
970 case LFT_SQUID_HIERARCHY
:
971 if (al
->hier
.ping
.timedout
)
972 mb
.append("TIMEOUT_", 8);
973 out
= hier_code_str
[al
->hier
.code
];
977 out
= al
->http
.content_type
;
980 case LFT_CLIENT_REQ_METHOD
:
982 sb
= al
->request
->method
.image();
988 case LFT_CLIENT_REQ_URI
:
989 // original client URI
991 sb
= al
->request
->effectiveRequestUri();
997 case LFT_CLIENT_REQ_URLSCHEME
:
999 sb
= al
->request
->url
.getScheme().image();
1005 case LFT_CLIENT_REQ_URLDOMAIN
:
1007 out
= al
->request
->url
.host();
1012 case LFT_CLIENT_REQ_URLPORT
:
1014 outint
= al
->request
->url
.port();
1019 case LFT_REQUEST_URLPATH_OLD_31
:
1020 case LFT_CLIENT_REQ_URLPATH
:
1022 sb
= al
->request
->url
.path();
1028 case LFT_CLIENT_REQ_VERSION
:
1030 sb
.appendf("%u.%u", al
->request
->http_ver
.major
, al
->request
->http_ver
.minor
);
1035 case LFT_REQUEST_METHOD
:
1036 sb
= al
->getLogMethod();
1041 case LFT_REQUEST_URI
:
1042 if (!al
->url
.isEmpty()) {
1048 case LFT_REQUEST_VERSION_OLD_2X
:
1049 case LFT_REQUEST_VERSION
:
1050 sb
.appendf("%u.%u", al
->http
.version
.major
, al
->http
.version
.minor
);
1054 case LFT_SERVER_REQ_METHOD
:
1055 if (al
->adapted_request
) {
1056 sb
= al
->adapted_request
->method
.image();
1062 case LFT_SERVER_REQ_URI
:
1063 // adapted request URI sent to server/peer
1064 if (al
->adapted_request
) {
1065 sb
= al
->adapted_request
->effectiveRequestUri();
1071 case LFT_SERVER_REQ_URLSCHEME
:
1072 if (al
->adapted_request
) {
1073 sb
= al
->adapted_request
->url
.getScheme().image();
1079 case LFT_SERVER_REQ_URLDOMAIN
:
1080 if (al
->adapted_request
) {
1081 out
= al
->adapted_request
->url
.host();
1086 case LFT_SERVER_REQ_URLPORT
:
1087 if (al
->adapted_request
) {
1088 outint
= al
->adapted_request
->url
.port();
1093 case LFT_SERVER_REQ_URLPATH
:
1094 if (al
->adapted_request
) {
1095 sb
= al
->adapted_request
->url
.path();
1101 case LFT_SERVER_REQ_VERSION
:
1102 if (al
->adapted_request
) {
1104 al
->adapted_request
->http_ver
.major
,
1105 al
->adapted_request
->http_ver
.minor
);
1110 case LFT_CLIENT_REQUEST_SIZE_TOTAL
:
1111 outoff
= al
->http
.clientRequestSz
.messageTotal();
1115 case LFT_CLIENT_REQUEST_SIZE_HEADERS
:
1116 outoff
= al
->http
.clientRequestSz
.header
;
1120 /*case LFT_REQUEST_SIZE_BODY: */
1121 /*case LFT_REQUEST_SIZE_BODY_NO_TE: */
1123 case LFT_ADAPTED_REPLY_SIZE_TOTAL
:
1124 outoff
= al
->http
.clientReplySz
.messageTotal();
1128 case LFT_REPLY_HIGHOFFSET
:
1129 outoff
= al
->cache
.highOffset
;
1133 case LFT_REPLY_OBJECTSIZE
:
1134 outoff
= al
->cache
.objectSize
;
1138 case LFT_ADAPTED_REPLY_SIZE_HEADERS
:
1139 outint
= al
->http
.clientReplySz
.header
;
1143 /*case LFT_REPLY_SIZE_BODY: */
1144 /*case LFT_REPLY_SIZE_BODY_NO_TE: */
1146 case LFT_CLIENT_IO_SIZE_TOTAL
:
1147 outint
= al
->http
.clientRequestSz
.messageTotal() + al
->http
.clientReplySz
.messageTotal();
1150 /*case LFT_SERVER_IO_SIZE_TOTAL: */
1154 out
= al
->request
->tag
.termedBuf();
1161 out
= al
->request
->extacl_log
.termedBuf();
1166 case LFT_SEQUENCE_NUMBER
:
1167 outoff
= logSequenceNumber
;
1172 case LFT_SSL_BUMP_MODE
: {
1173 const Ssl::BumpMode mode
= static_cast<Ssl::BumpMode
>(al
->ssl
.bumpMode
);
1174 // for Ssl::bumpEnd, Ssl::bumpMode() returns NULL and we log '-'
1175 out
= Ssl::bumpMode(mode
);
1179 case LFT_EXT_ACL_USER_CERT_RAW
:
1181 ConnStateData
*conn
= al
->request
->clientConnectionManager
.get();
1182 if (conn
&& Comm::IsConnOpen(conn
->clientConnection
)) {
1183 if (auto ssl
= fd_table
[conn
->clientConnection
->fd
].ssl
.get())
1184 out
= sslGetUserCertificatePEM(ssl
);
1189 case LFT_EXT_ACL_USER_CERTCHAIN_RAW
:
1191 ConnStateData
*conn
= al
->request
->clientConnectionManager
.get();
1192 if (conn
&& Comm::IsConnOpen(conn
->clientConnection
)) {
1193 if (auto ssl
= fd_table
[conn
->clientConnection
->fd
].ssl
.get())
1194 out
= sslGetUserCertificatePEM(ssl
);
1199 case LFT_EXT_ACL_USER_CERT
:
1201 ConnStateData
*conn
= al
->request
->clientConnectionManager
.get();
1202 if (conn
&& Comm::IsConnOpen(conn
->clientConnection
)) {
1203 if (auto ssl
= fd_table
[conn
->clientConnection
->fd
].ssl
.get())
1204 out
= sslGetUserAttribute(ssl
, format
->data
.header
.header
);
1209 case LFT_EXT_ACL_USER_CA_CERT
:
1211 ConnStateData
*conn
= al
->request
->clientConnectionManager
.get();
1212 if (conn
&& Comm::IsConnOpen(conn
->clientConnection
)) {
1213 if (auto ssl
= fd_table
[conn
->clientConnection
->fd
].ssl
.get())
1214 out
= sslGetCAAttribute(ssl
, format
->data
.header
.header
);
1219 case LFT_SSL_USER_CERT_SUBJECT
:
1220 if (X509
*cert
= al
->cache
.sslClientCert
.get()) {
1221 if (X509_NAME
*subject
= X509_get_subject_name(cert
)) {
1222 X509_NAME_oneline(subject
, tmp
, sizeof(tmp
));
1228 case LFT_SSL_USER_CERT_ISSUER
:
1229 if (X509
*cert
= al
->cache
.sslClientCert
.get()) {
1230 if (X509_NAME
*issuer
= X509_get_issuer_name(cert
)) {
1231 X509_NAME_oneline(issuer
, tmp
, sizeof(tmp
));
1237 case LFT_SSL_CLIENT_SNI
:
1238 if (al
->request
&& al
->request
->clientConnectionManager
.valid()) {
1239 if (Ssl::ServerBump
* srvBump
= al
->request
->clientConnectionManager
->serverBump()) {
1240 if (!srvBump
->clientSni
.isEmpty())
1241 out
= srvBump
->clientSni
.c_str();
1246 case LFT_SSL_SERVER_CERT_ERRORS
:
1247 if (al
->request
&& al
->request
->clientConnectionManager
.valid()) {
1248 if (Ssl::ServerBump
* srvBump
= al
->request
->clientConnectionManager
->serverBump()) {
1249 const char *separator
= fmt
->data
.string
? fmt
->data
.string
: ":";
1250 for (const Security::CertErrors
*sslError
= srvBump
->sslErrors(); sslError
; sslError
= sslError
->next
) {
1252 sb
.append(separator
);
1253 if (const char *errorName
= Ssl::GetErrorName(sslError
->element
.code
))
1254 sb
.append(errorName
);
1256 sb
.append(sslErrorName(sslError
->element
.code
, tmp
, sizeof(tmp
)));
1257 if (sslError
->element
.depth
>= 0)
1258 sb
.appendf("@depth=%d", sslError
->element
.depth
);
1266 case LFT_SSL_SERVER_CERT_ISSUER
:
1267 case LFT_SSL_SERVER_CERT_SUBJECT
:
1268 if (al
->request
&& al
->request
->clientConnectionManager
.valid()) {
1269 if (Ssl::ServerBump
* srvBump
= al
->request
->clientConnectionManager
->serverBump()) {
1270 if (X509
*serverCert
= srvBump
->serverCert
.get()) {
1271 if (fmt
->type
== LFT_SSL_SERVER_CERT_SUBJECT
)
1272 out
= Ssl::GetX509UserAttribute(serverCert
, "DN");
1274 out
= Ssl::GetX509CAAttribute(serverCert
, "DN");
1280 case LFT_TLS_CLIENT_NEGOTIATED_VERSION
:
1281 if (al
->tcpClient
&& al
->tcpClient
->hasTlsNegotiations())
1282 out
= al
->tcpClient
->hasTlsNegotiations()->negotiatedVersion();
1285 case LFT_TLS_SERVER_NEGOTIATED_VERSION
:
1286 if (al
->hier
.tcpServer
&& al
->hier
.tcpServer
->hasTlsNegotiations())
1287 out
= al
->hier
.tcpServer
->hasTlsNegotiations()->negotiatedVersion();
1290 case LFT_TLS_CLIENT_RECEIVED_HELLO_VERSION
:
1291 if (al
->tcpClient
&& al
->tcpClient
->hasTlsNegotiations())
1292 out
= al
->tcpClient
->hasTlsNegotiations()->helloVersion();
1295 case LFT_TLS_SERVER_RECEIVED_HELLO_VERSION
:
1296 if (al
->hier
.tcpServer
&& al
->hier
.tcpServer
->hasTlsNegotiations())
1297 out
= al
->hier
.tcpServer
->hasTlsNegotiations()->helloVersion();
1300 case LFT_TLS_CLIENT_SUPPORTED_VERSION
:
1301 if (al
->tcpClient
&& al
->tcpClient
->hasTlsNegotiations())
1302 out
= al
->tcpClient
->hasTlsNegotiations()->supportedVersion();
1305 case LFT_TLS_SERVER_SUPPORTED_VERSION
:
1306 if (al
->hier
.tcpServer
&& al
->hier
.tcpServer
->hasTlsNegotiations())
1307 out
= al
->hier
.tcpServer
->hasTlsNegotiations()->supportedVersion();
1310 case LFT_TLS_CLIENT_NEGOTIATED_CIPHER
:
1311 if (al
->tcpClient
&& al
->tcpClient
->hasTlsNegotiations())
1312 out
= al
->tcpClient
->hasTlsNegotiations()->cipherName();
1315 case LFT_TLS_SERVER_NEGOTIATED_CIPHER
:
1316 if (al
->hier
.tcpServer
&& al
->hier
.tcpServer
->hasTlsNegotiations())
1317 out
= al
->hier
.tcpServer
->hasTlsNegotiations()->cipherName();
1321 case LFT_REQUEST_URLGROUP_OLD_2X
:
1322 assert(LFT_REQUEST_URLGROUP_OLD_2X
== 0); // should never happen.
1325 tmp
[0] = fmt
->data
.header
.separator
;
1327 if (fmt
->data
.header
.header
&& *fmt
->data
.header
.header
) {
1328 const char *separator
= tmp
;
1331 Adaptation::History::Pointer ah
= al
->request
? al
->request
->adaptHistory() : Adaptation::History::Pointer();
1332 if (ah
&& ah
->metaHeaders
) {
1333 if (ah
->metaHeaders
->find(note
, fmt
->data
.header
.header
, separator
))
1338 if (al
->notes
->find(note
, fmt
->data
.header
.header
, separator
)) {
1340 sb
.append(separator
);
1347 // if no argument given use default "\r\n" as notes separator
1348 const char *separator
= fmt
->data
.string
? tmp
: "\r\n";
1350 Adaptation::History::Pointer ah
= al
->request
? al
->request
->adaptHistory() : Adaptation::History::Pointer();
1351 if (ah
&& ah
->metaHeaders
&& !ah
->metaHeaders
->empty())
1352 sb
.append(ah
->metaHeaders
->toString(separator
));
1354 if (al
->notes
&& !al
->notes
->empty())
1355 sb
.append(al
->notes
->toString(separator
));
1362 case LFT_CREDENTIALS
:
1364 if (al
->request
&& al
->request
->auth_user_request
)
1365 out
= strOrNull(al
->request
->auth_user_request
->credentialsStr());
1373 case LFT_EXT_ACL_NAME
:
1374 out
= al
->lastAclName
;
1377 case LFT_EXT_ACL_DATA
:
1378 if (!al
->lastAclData
.isEmpty())
1379 out
= al
->lastAclData
.c_str();
1384 sb
.appendf("%0*" PRId64
, fmt
->zero
&& fmt
->widthMin
>= 0 ? fmt
->widthMin
: 0, outoff
);
1388 sb
.appendf("%0*ld", fmt
->zero
&& fmt
->widthMin
>= 0 ? fmt
->widthMin
: 0, outint
);
1390 } else if (doMsec
) {
1391 if (fmt
->widthMax
< 0) {
1392 sb
.appendf("%0*ld", fmt
->widthMin
, tvToMsec(outtv
));
1394 int precision
= fmt
->widthMax
;
1395 sb
.appendf("%0*" PRId64
".%0*" PRId64
"", fmt
->zero
&& (fmt
->widthMin
- precision
- 1 >= 0) ? fmt
->widthMin
- precision
- 1 : 0, static_cast<int64_t>(outtv
.tv_sec
* 1000 + outtv
.tv_usec
/ 1000), precision
, static_cast<int64_t>((outtv
.tv_usec
% 1000 )* (1000 / fmt
->divisor
)));
1399 int precision
= fmt
->widthMax
>=0 ? fmt
->widthMax
:3;
1400 sb
.appendf("%0*" PRId64
".%0*d", fmt
->zero
&& (fmt
->widthMin
- precision
- 1 >= 0) ? fmt
->widthMin
- precision
- 1 : 0, static_cast<int64_t>(outtv
.tv_sec
), precision
, (int)(outtv
.tv_usec
/ fmt
->divisor
));
1405 if (quote
|| fmt
->quote
!= LOG_QUOTE_NONE
) {
1406 // Do not write to the tmp buffer because it may contain the to-be-quoted value.
1407 static char quotedOut
[2 * sizeof(tmp
)];
1408 static_assert(sizeof(quotedOut
) > 0, "quotedOut has zero length");
1409 quotedOut
[0] = '\0';
1411 char *newout
= NULL
;
1414 switch (fmt
->quote
) {
1416 case LOG_QUOTE_NONE
:
1417 newout
= rfc1738_escape_unescaped(out
);
1420 case LOG_QUOTE_QUOTES
: {
1421 size_t out_len
= static_cast<size_t>(strlen(out
)) * 2 + 1;
1422 if (out_len
>= sizeof(tmp
)) {
1423 newout
= (char *)xmalloc(out_len
);
1427 log_quoted_string(out
, newout
);
1431 case LOG_QUOTE_MIMEBLOB
:
1432 newout
= QuoteMimeBlob(out
);
1437 newout
= rfc1738_escape(out
);
1440 case LOG_QUOTE_SHELL
: {
1443 strwordquote(&mbq
, out
);
1444 newout
= mbq
.content();
1464 // enforce width limits if configured
1465 const bool haveMaxWidth
= fmt
->widthMax
>=0 && !doint
&& !dooff
&& !doMsec
&& !doSec
;
1466 if (haveMaxWidth
|| fmt
->widthMin
) {
1467 const int minWidth
= fmt
->widthMin
>= 0 ?
1469 const int maxWidth
= haveMaxWidth
?
1470 fmt
->widthMax
: strlen(out
);
1473 mb
.appendf("%-*.*s", minWidth
, maxWidth
, out
);
1475 mb
.appendf("%*.*s", minWidth
, maxWidth
, out
);
1477 mb
.append(out
, strlen(out
));