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 "security/CertError.h"
25 #include "security/NegotiationHistory.h"
26 #include "SquidTime.h"
31 #include "ssl/ErrorDetail.h"
32 #include "ssl/ServerBump.h"
35 /// Convert a string to NULL pointer if it is ""
36 #define strOrNull(s) ((s)==NULL||(s)[0]=='\0'?NULL:(s))
38 const SBuf
Format::Dash("-");
40 Format::Format::Format(const char *n
) :
47 Format::Format::~Format()
49 // erase the list without consuming stack space
51 // unlink the next entry for deletion
64 Format::Format::parse(const char *def
)
66 const char *cur
, *eos
;
67 Token
*new_lt
, *last_lt
;
68 enum Quoting quote
= LOG_QUOTE_NONE
;
70 debugs(46, 2, HERE
<< "got definition '" << def
<< "'");
73 debugs(46, DBG_IMPORTANT
, "WARNING: existing format for '" << name
<< " " << def
<< "'");
77 /* very inefficent parser, but who cares, this needs to be simple */
78 /* First off, let's tokenize, we'll optimize in a second pass.
79 * A token can either be a %-prefixed sequence (usually a dynamic
80 * token but it can be an escaped sequence), or a string. */
82 eos
= def
+ strlen(def
);
83 format
= new_lt
= last_lt
= new Token
;
84 cur
+= new_lt
->parse(cur
, "e
);
88 last_lt
->next
= new_lt
;
90 cur
+= new_lt
->parse(cur
, "e
);
97 Format::Format::dump(StoreEntry
* entry
, const char *directiveName
, bool eol
) const
101 // loop rather than recursing to conserve stack space.
102 for (const Format
*fmt
= this; fmt
; fmt
= fmt
->next
) {
103 debugs(46, 3, HERE
<< "Dumping format definition for " << fmt
->name
);
105 storeAppendPrintf(entry
, "%s %s ", directiveName
, fmt
->name
);
107 for (Token
*t
= fmt
->format
; t
; t
= t
->next
) {
108 if (t
->type
== LFT_STRING
)
109 storeAppendPrintf(entry
, "%s", t
->data
.string
);
113 ByteCode_t type
= t
->type
;
121 case LFT_ADAPTATION_LAST_HEADER_ELEM
:
124 case LFT_ICAP_REQ_HEADER_ELEM
:
125 case LFT_ICAP_REP_HEADER_ELEM
:
127 case LFT_REQUEST_HEADER_ELEM
:
128 case LFT_ADAPTED_REQUEST_HEADER_ELEM
:
129 case LFT_REPLY_HEADER_ELEM
:
131 if (t
->data
.header
.separator
!= ',')
132 snprintf(argbuf
, sizeof(argbuf
), "%s:%c%s", t
->data
.header
.header
, t
->data
.header
.separator
, t
->data
.header
.element
);
134 snprintf(argbuf
, sizeof(argbuf
), "%s:%s", t
->data
.header
.header
, t
->data
.header
.element
);
139 case LFT_REQUEST_HEADER_ELEM
:
140 type
= LFT_REQUEST_HEADER_ELEM
; // XXX: remove _ELEM?
142 case LFT_ADAPTED_REQUEST_HEADER_ELEM
:
143 type
= LFT_ADAPTED_REQUEST_HEADER_ELEM
; // XXX: remove _ELEM?
145 case LFT_REPLY_HEADER_ELEM
:
146 type
= LFT_REPLY_HEADER_ELEM
; // XXX: remove _ELEM?
149 case LFT_ADAPTATION_LAST_HEADER_ELEM
:
150 type
= LFT_ADAPTATION_LAST_HEADER
;
154 case LFT_ICAP_REQ_HEADER_ELEM
:
155 type
= LFT_ICAP_REQ_HEADER
;
157 case LFT_ICAP_REP_HEADER_ELEM
:
158 type
= LFT_ICAP_REP_HEADER
;
167 case LFT_REQUEST_ALL_HEADERS
:
168 case LFT_ADAPTED_REQUEST_ALL_HEADERS
:
169 case LFT_REPLY_ALL_HEADERS
:
172 case LFT_ADAPTATION_LAST_ALL_HEADERS
:
175 case LFT_ICAP_REQ_ALL_HEADERS
:
176 case LFT_ICAP_REP_ALL_HEADERS
:
180 case LFT_REQUEST_ALL_HEADERS
:
181 type
= LFT_REQUEST_HEADER
;
183 case LFT_ADAPTED_REQUEST_ALL_HEADERS
:
184 type
= LFT_ADAPTED_REQUEST_HEADER
;
186 case LFT_REPLY_ALL_HEADERS
:
187 type
= LFT_REPLY_HEADER
;
190 case LFT_ADAPTATION_LAST_ALL_HEADERS
:
191 type
= LFT_ADAPTATION_LAST_HEADER
;
195 case LFT_ICAP_REQ_ALL_HEADERS
:
196 type
= LFT_ICAP_REQ_HEADER
;
198 case LFT_ICAP_REP_ALL_HEADERS
:
199 type
= LFT_ICAP_REP_HEADER
;
210 arg
= t
->data
.string
;
215 entry
->append("%", 1);
219 case LOG_QUOTE_QUOTES
:
220 entry
->append("\"", 1);
223 case LOG_QUOTE_MIMEBLOB
:
224 entry
->append("[", 1);
228 entry
->append("#", 1);
232 entry
->append("'", 1);
235 case LOG_QUOTE_SHELL
:
236 entry
->append("/", 1);
244 entry
->append("-", 1);
247 entry
->append("0", 1);
249 if (t
->widthMin
>= 0)
250 storeAppendPrintf(entry
, "%d", t
->widthMin
);
252 if (t
->widthMax
>= 0)
253 storeAppendPrintf(entry
, ".%d", t
->widthMax
);
256 storeAppendPrintf(entry
, "{%s}", arg
);
258 storeAppendPrintf(entry
, "%s", t
->label
);
261 entry
->append(" ", 1);
266 entry
->append("\n", 1);
272 log_quoted_string(const char *str
, char *out
)
277 int l
= strcspn(str
, "\"\\\r\n\t");
326 sslErrorName(Security::ErrorCode err
, char *buf
, size_t size
)
328 snprintf(buf
, size
, "SSL_ERR=%d", err
);
333 /// XXX: Misnamed. TODO: Split <h (and this function) to distinguish received
334 /// headers from sent headers rather than failing to distinguish requests from responses.
335 /// \retval HttpReply sent to the HTTP client (access.log and default context).
336 /// \retval HttpReply received (encapsulated) from the ICAP server (icap.log context).
337 /// \retval HttpRequest received (encapsulated) from the ICAP server (icap.log context).
338 static const Http::Message
*
339 actualReplyHeader(const AccessLogEntry::Pointer
&al
)
341 const Http::Message
*msg
= al
->reply
;
343 // al->icap.reqMethod is methodNone in access.log context
344 if (!msg
&& al
->icap
.reqMethod
== Adaptation::methodReqmod
)
345 msg
= al
->adapted_request
;
350 /// XXX: Misnamed. See actualReplyHeader().
351 /// \return HttpRequest or HttpReply for %http::>h.
352 static const Http::Message
*
353 actualRequestHeader(const AccessLogEntry::Pointer
&al
)
356 // al->icap.reqMethod is methodNone in access.log context
357 if (al
->icap
.reqMethod
== Adaptation::methodRespmod
) {
358 // XXX: for now AccessLogEntry lacks virgin response headers
366 Format::Format::assemble(MemBuf
&mb
, const AccessLogEntry::Pointer
&al
, int logSequenceNumber
) const
371 for (Token
*fmt
= format
; fmt
!= NULL
; fmt
= fmt
->next
) { /* for each token */
372 const char *out
= NULL
;
379 struct timeval outtv
= {0, 0};
390 out
= fmt
->data
.string
;
393 case LFT_CLIENT_IP_ADDRESS
:
394 al
->getLogClientIp(tmp
, sizeof(tmp
));
398 case LFT_CLIENT_FQDN
:
399 if (al
->cache
.caddr
.isAnyAddr()) // e.g., ICAP OPTIONS lack client
402 out
= fqdncache_gethostbyaddr(al
->cache
.caddr
, FQDN_LOOKUP_IF_MISS
);
404 out
= al
->cache
.caddr
.toStr(tmp
,1024);
409 case LFT_CLIENT_PORT
:
411 outint
= al
->request
->client_addr
.port();
413 } else if (al
->tcpClient
) {
414 outint
= al
->tcpClient
->remote
.port();
421 // TODO make the ACL checklist have a direct link to any TCP details.
422 if (al
->request
&& al
->request
->clientConnectionManager
.valid() && al
->request
->clientConnectionManager
->clientConnection
!= NULL
) {
423 if (al
->request
->clientConnectionManager
->clientConnection
->remote
.isIPv4())
424 al
->request
->clientConnectionManager
->clientConnection
->remoteEui48
.encode(tmp
, 1024);
426 al
->request
->clientConnectionManager
->clientConnection
->remoteEui64
.encode(tmp
, 1024);
432 case LFT_EXT_ACL_CLIENT_EUI48
:
434 if (al
->request
&& al
->request
->clientConnectionManager
.valid() &&
435 al
->request
->clientConnectionManager
->clientConnection
!= NULL
&&
436 al
->request
->clientConnectionManager
->clientConnection
->remote
.isIPv4()) {
437 al
->request
->clientConnectionManager
->clientConnection
->remoteEui48
.encode(tmp
, 1024);
443 case LFT_EXT_ACL_CLIENT_EUI64
:
445 if (al
->request
&& al
->request
->clientConnectionManager
.valid() &&
446 al
->request
->clientConnectionManager
->clientConnection
!= NULL
&&
447 !al
->request
->clientConnectionManager
->clientConnection
->remote
.isIPv4()) {
448 al
->request
->clientConnectionManager
->clientConnection
->remoteEui64
.encode(tmp
, 1024);
454 case LFT_SERVER_IP_ADDRESS
:
455 if (al
->hier
.tcpServer
!= NULL
) {
456 out
= al
->hier
.tcpServer
->remote
.toStr(tmp
,sizeof(tmp
));
460 case LFT_SERVER_FQDN_OR_PEER_NAME
:
464 case LFT_SERVER_PORT
:
465 if (al
->hier
.tcpServer
!= NULL
) {
466 outint
= al
->hier
.tcpServer
->remote
.port();
471 case LFT_LOCAL_LISTENING_IP
: {
472 // avoid logging a dash if we have reliable info
473 const bool interceptedAtKnownPort
= al
->request
?
474 (al
->request
->flags
.interceptTproxy
||
475 al
->request
->flags
.intercepted
) && al
->cache
.port
!= NULL
:
477 if (interceptedAtKnownPort
) {
478 const bool portAddressConfigured
= !al
->cache
.port
->s
.isAnyAddr();
479 if (portAddressConfigured
)
480 out
= al
->cache
.port
->s
.toStr(tmp
, sizeof(tmp
));
481 } else if (al
->tcpClient
!= NULL
)
482 out
= al
->tcpClient
->local
.toStr(tmp
, sizeof(tmp
));
486 case LFT_CLIENT_LOCAL_IP
:
487 if (al
->tcpClient
!= NULL
) {
488 out
= al
->tcpClient
->local
.toStr(tmp
,sizeof(tmp
));
492 case LFT_CLIENT_LOCAL_TOS
:
493 if (al
->tcpClient
!= NULL
) {
494 snprintf(tmp
, sizeof(tmp
), "0x%x", (uint32_t)al
->tcpClient
->tos
);
499 case LFT_CLIENT_LOCAL_NFMARK
:
500 if (al
->tcpClient
!= NULL
) {
501 snprintf(tmp
, sizeof(tmp
), "0x%x", al
->tcpClient
->nfmark
);
506 case LFT_LOCAL_LISTENING_PORT
:
507 if (al
->cache
.port
!= NULL
) {
508 outint
= al
->cache
.port
->s
.port();
510 } else if (al
->request
) {
511 outint
= al
->request
->my_addr
.port();
516 case LFT_CLIENT_LOCAL_PORT
:
517 if (al
->tcpClient
!= NULL
) {
518 outint
= al
->tcpClient
->local
.port();
523 case LFT_SERVER_LOCAL_IP_OLD_27
:
524 case LFT_SERVER_LOCAL_IP
:
525 if (al
->hier
.tcpServer
!= NULL
) {
526 out
= al
->hier
.tcpServer
->local
.toStr(tmp
,sizeof(tmp
));
530 case LFT_SERVER_LOCAL_PORT
:
531 if (al
->hier
.tcpServer
!= NULL
) {
532 outint
= al
->hier
.tcpServer
->local
.port();
538 case LFT_SERVER_LOCAL_TOS
:
539 if (al
->hier
.tcpServer
!= NULL
) {
540 snprintf(tmp
, sizeof(tmp
), "0x%x", (uint32_t)al
->hier
.tcpServer
->tos
);
545 case LFT_SERVER_LOCAL_NFMARK
:
546 if (al
->hier
.tcpServer
!= NULL
) {
547 snprintf(tmp
, sizeof(tmp
), "0x%x", al
->hier
.tcpServer
->nfmark
);
552 case LFT_TIME_SECONDS_SINCE_EPOCH
:
553 // some platforms store time in 32-bit, some 64-bit...
554 outoff
= static_cast<int64_t>(current_time
.tv_sec
);
558 case LFT_TIME_SUBSECOND
:
559 outint
= current_time
.tv_usec
/ fmt
->divisor
;
563 case LFT_TIME_LOCALTIME
:
569 spec
= fmt
->data
.string
;
571 if (fmt
->type
== LFT_TIME_LOCALTIME
) {
573 spec
= "%d/%b/%Y:%H:%M:%S %z";
574 t
= localtime(&squid_curtime
);
577 spec
= "%d/%b/%Y:%H:%M:%S";
579 t
= gmtime(&squid_curtime
);
582 strftime(tmp
, sizeof(tmp
), spec
, t
);
590 outtv
= al
->cache
.start_time
;
594 case LFT_TIME_TO_HANDLE_REQUEST
:
595 outtv
= al
->cache
.trTime
;
599 case LFT_PEER_RESPONSE_TIME
:
600 if (al
->hier
.peer_response_time
.tv_sec
== -1) {
603 outtv
= al
->hier
.peer_response_time
;
608 case LFT_TOTAL_SERVER_SIDE_RESPONSE_TIME
: {
609 timeval total_response_time
;
610 al
->hier
.totalResponseTime(total_response_time
);
611 if (total_response_time
.tv_sec
== -1) {
614 outtv
= total_response_time
;
620 case LFT_DNS_WAIT_TIME
:
621 if (al
->request
&& al
->request
->dnsWait
>= 0) {
622 // TODO: microsecond precision for dns wait time.
623 // Convert miliseconds to timeval struct:
624 outtv
.tv_sec
= al
->request
->dnsWait
/ 1000;
625 outtv
.tv_usec
= (al
->request
->dnsWait
% 1000) * 1000;
630 case LFT_REQUEST_HEADER
:
631 if (const Http::Message
*msg
= actualRequestHeader(al
))
632 sb
= msg
->header
.getByName(fmt
->data
.header
.header
);
634 out
= sb
.termedBuf();
640 case LFT_ADAPTED_REQUEST_HEADER
:
642 if (al
->adapted_request
)
643 sb
= al
->adapted_request
->header
.getByName(fmt
->data
.header
.header
);
645 out
= sb
.termedBuf();
651 case LFT_REPLY_HEADER
: {
652 if (const Http::Message
*msg
= actualReplyHeader(al
))
653 sb
= msg
->header
.getByName(fmt
->data
.header
.header
);
655 out
= sb
.termedBuf();
662 case LFT_ADAPTATION_SUM_XACT_TIMES
:
664 Adaptation::History::Pointer ah
= al
->request
->adaptHistory();
666 ah
->sumLogString(fmt
->data
.string
, sb
);
667 out
= sb
.termedBuf();
671 case LFT_ADAPTATION_ALL_XACT_TIMES
:
673 Adaptation::History::Pointer ah
= al
->request
->adaptHistory();
675 ah
->allLogString(fmt
->data
.string
, sb
);
676 out
= sb
.termedBuf();
680 case LFT_ADAPTATION_LAST_HEADER
:
682 const Adaptation::History::Pointer ah
= al
->request
->adaptHistory();
683 if (ah
!= NULL
) // XXX: add adapt::<all_h but use lastMeta here
684 sb
= ah
->allMeta
.getByName(fmt
->data
.header
.header
);
687 // XXX: here and elsewhere: move such code inside the if guard
688 out
= sb
.termedBuf();
694 case LFT_ADAPTATION_LAST_HEADER_ELEM
:
696 const Adaptation::History::Pointer ah
= al
->request
->adaptHistory();
697 if (ah
!= NULL
) // XXX: add adapt::<all_h but use lastMeta here
698 sb
= ah
->allMeta
.getByNameListMember(fmt
->data
.header
.header
, fmt
->data
.header
.element
, fmt
->data
.header
.separator
);
701 out
= sb
.termedBuf();
707 case LFT_ADAPTATION_LAST_ALL_HEADERS
:
708 out
= al
->adapt
.last_meta
;
718 out
= al
->icap
.hostAddr
.toStr(tmp
,1024);
721 case LFT_ICAP_SERV_NAME
:
722 out
= al
->icap
.serviceName
.termedBuf();
725 case LFT_ICAP_REQUEST_URI
:
726 out
= al
->icap
.reqUri
.termedBuf();
729 case LFT_ICAP_REQUEST_METHOD
:
730 out
= Adaptation::Icap::ICAP::methodStr(al
->icap
.reqMethod
);
733 case LFT_ICAP_BYTES_SENT
:
734 outoff
= al
->icap
.bytesSent
;
738 case LFT_ICAP_BYTES_READ
:
739 outoff
= al
->icap
.bytesRead
;
743 case LFT_ICAP_BODY_BYTES_READ
:
744 if (al
->icap
.bodyBytesRead
>= 0) {
745 outoff
= al
->icap
.bodyBytesRead
;
748 // else if icap.bodyBytesRead < 0, we do not have any http data,
749 // so just print a "-" (204 responses etc)
752 case LFT_ICAP_REQ_HEADER
:
753 if (NULL
!= al
->icap
.request
) {
754 sb
= al
->icap
.request
->header
.getByName(fmt
->data
.header
.header
);
755 out
= sb
.termedBuf();
760 case LFT_ICAP_REQ_HEADER_ELEM
:
761 if (al
->icap
.request
)
762 sb
= al
->icap
.request
->header
.getByNameListMember(fmt
->data
.header
.header
, fmt
->data
.header
.element
, fmt
->data
.header
.separator
);
764 out
= sb
.termedBuf();
770 case LFT_ICAP_REQ_ALL_HEADERS
:
771 if (al
->icap
.request
) {
772 HttpHeaderPos pos
= HttpHeaderInitPos
;
773 while (const HttpHeaderEntry
*e
= al
->icap
.request
->header
.getEntry(&pos
)) {
779 out
= sb
.termedBuf();
784 case LFT_ICAP_REP_HEADER
:
785 if (NULL
!= al
->icap
.reply
) {
786 sb
= al
->icap
.reply
->header
.getByName(fmt
->data
.header
.header
);
787 out
= sb
.termedBuf();
792 case LFT_ICAP_REP_HEADER_ELEM
:
793 if (NULL
!= al
->icap
.reply
)
794 sb
= al
->icap
.reply
->header
.getByNameListMember(fmt
->data
.header
.header
, fmt
->data
.header
.element
, fmt
->data
.header
.separator
);
796 out
= sb
.termedBuf();
802 case LFT_ICAP_REP_ALL_HEADERS
:
803 if (al
->icap
.reply
) {
804 HttpHeaderPos pos
= HttpHeaderInitPos
;
805 while (const HttpHeaderEntry
*e
= al
->icap
.reply
->header
.getEntry(&pos
)) {
811 out
= sb
.termedBuf();
816 case LFT_ICAP_TR_RESPONSE_TIME
:
817 outtv
= al
->icap
.trTime
;
821 case LFT_ICAP_IO_TIME
:
822 outtv
= al
->icap
.ioTime
;
826 case LFT_ICAP_STATUS_CODE
:
827 outint
= al
->icap
.resStatus
;
831 case LFT_ICAP_OUTCOME
:
832 out
= al
->icap
.outcome
;
835 case LFT_ICAP_TOTAL_TIME
:
836 outtv
= al
->icap
.processingTime
;
840 case LFT_REQUEST_HEADER_ELEM
:
841 if (const Http::Message
*msg
= actualRequestHeader(al
))
842 sb
= msg
->header
.getByNameListMember(fmt
->data
.header
.header
, fmt
->data
.header
.element
, fmt
->data
.header
.separator
);
844 out
= sb
.termedBuf();
850 case LFT_ADAPTED_REQUEST_HEADER_ELEM
:
851 if (al
->adapted_request
)
852 sb
= al
->adapted_request
->header
.getByNameListMember(fmt
->data
.header
.header
, fmt
->data
.header
.element
, fmt
->data
.header
.separator
);
854 out
= sb
.termedBuf();
860 case LFT_REPLY_HEADER_ELEM
: {
861 if (const Http::Message
*msg
= actualReplyHeader(al
))
862 sb
= msg
->header
.getByNameListMember(fmt
->data
.header
.header
, fmt
->data
.header
.element
, fmt
->data
.header
.separator
);
864 out
= sb
.termedBuf();
870 case LFT_REQUEST_ALL_HEADERS
:
872 if (al
->icap
.reqMethod
== Adaptation::methodRespmod
) {
873 // XXX: since AccessLogEntry::Headers lacks virgin response
874 // headers, do nothing for now
879 out
= al
->headers
.request
;
886 case LFT_ADAPTED_REQUEST_ALL_HEADERS
:
887 out
= al
->headers
.adapted_request
;
893 case LFT_REPLY_ALL_HEADERS
:
894 out
= al
->headers
.reply
;
896 if (!out
&& al
->icap
.reqMethod
== Adaptation::methodReqmod
)
897 out
= al
->headers
.adapted_request
;
906 if (al
->request
&& al
->request
->auth_user_request
!= NULL
)
907 out
= strOrNull(al
->request
->auth_user_request
->username());
909 if (!out
&& al
->request
&& al
->request
->extacl_user
.size()) {
910 if (const char *t
= al
->request
->extacl_user
.termedBuf())
915 out
= strOrNull(al
->cache
.extuser
);
919 out
= strOrNull(al
->cache
.ssluser
);
922 out
= strOrNull(al
->cache
.rfc931
);
927 if (al
->request
&& al
->request
->auth_user_request
!= NULL
)
928 out
= strOrNull(al
->request
->auth_user_request
->username());
933 out
= strOrNull(al
->cache
.rfc931
);
936 case LFT_USER_EXTERNAL
:
937 if (al
->request
&& al
->request
->extacl_user
.size()) {
938 if (const char *t
= al
->request
->extacl_user
.termedBuf())
943 out
= strOrNull(al
->cache
.extuser
);
946 /* case LFT_USER_REALM: */
947 /* case LFT_USER_SCHEME: */
949 // the fmt->type can not be LFT_HTTP_SENT_STATUS_CODE_OLD_30
950 // but compiler complains if ommited
951 case LFT_HTTP_SENT_STATUS_CODE_OLD_30
:
952 case LFT_HTTP_SENT_STATUS_CODE
:
953 outint
= al
->http
.code
;
959 case LFT_HTTP_RECEIVED_STATUS_CODE
:
960 if (al
->hier
.peer_reply_status
== Http::scNone
) {
963 outint
= al
->hier
.peer_reply_status
;
967 /* case LFT_HTTP_STATUS:
968 * out = statusline->text;
972 case LFT_HTTP_BODY_BYTES_READ
:
973 if (al
->hier
.bodyBytesRead
>= 0) {
974 outoff
= al
->hier
.bodyBytesRead
;
977 // else if hier.bodyBytesRead < 0 we did not have any data exchange with
978 // a peer server so just print a "-" (eg requests served from cache,
979 // or internal error messages).
982 case LFT_SQUID_STATUS
:
983 out
= al
->cache
.code
.c_str();
986 case LFT_SQUID_ERROR
:
987 if (al
->request
&& al
->request
->errType
!= ERR_NONE
)
988 out
= errorPageName(al
->request
->errType
);
991 case LFT_SQUID_ERROR_DETAIL
:
993 if (al
->request
&& al
->request
->errType
== ERR_SECURE_CONNECT_FAIL
) {
994 if (! (out
= Ssl::GetErrorName(al
->request
->errDetail
)))
995 out
= sslErrorName(al
->request
->errDetail
, tmp
, sizeof(tmp
));
998 if (al
->request
&& al
->request
->errDetail
!= ERR_DETAIL_NONE
) {
999 if (al
->request
->errDetail
> ERR_DETAIL_START
&& al
->request
->errDetail
< ERR_DETAIL_MAX
)
1000 out
= errorDetailName(al
->request
->errDetail
);
1002 if (al
->request
->errDetail
>= ERR_DETAIL_EXCEPTION_START
)
1003 snprintf(tmp
, sizeof(tmp
), "%s=0x%X",
1004 errorDetailName(al
->request
->errDetail
), (uint32_t) al
->request
->errDetail
);
1006 snprintf(tmp
, sizeof(tmp
), "%s=%d",
1007 errorDetailName(al
->request
->errDetail
), al
->request
->errDetail
);
1013 case LFT_SQUID_HIERARCHY
:
1014 if (al
->hier
.ping
.timedout
)
1015 mb
.append("TIMEOUT_", 8);
1017 out
= hier_code_str
[al
->hier
.code
];
1022 out
= al
->http
.content_type
;
1026 case LFT_CLIENT_REQ_METHOD
:
1028 const SBuf
&s
= al
->request
->method
.image();
1029 sb
.append(s
.rawContent(), s
.length());
1030 out
= sb
.termedBuf();
1035 case LFT_CLIENT_REQ_URI
:
1036 // original client URI
1038 const SBuf
&s
= al
->request
->effectiveRequestUri();
1039 sb
.append(s
.rawContent(), s
.length());
1040 out
= sb
.termedBuf();
1045 case LFT_CLIENT_REQ_URLSCHEME
:
1047 const SBuf
s(al
->request
->url
.getScheme().image());
1048 sb
.append(s
.rawContent(), s
.length());
1049 out
= sb
.termedBuf();
1054 case LFT_CLIENT_REQ_URLDOMAIN
:
1056 out
= al
->request
->url
.host();
1061 case LFT_CLIENT_REQ_URLPORT
:
1063 outint
= al
->request
->url
.port();
1068 case LFT_REQUEST_URLPATH_OLD_31
:
1069 case LFT_CLIENT_REQ_URLPATH
:
1071 SBuf s
= al
->request
->url
.path();
1077 case LFT_CLIENT_REQ_VERSION
:
1079 snprintf(tmp
, sizeof(tmp
), "%d.%d", (int) al
->request
->http_ver
.major
, (int) al
->request
->http_ver
.minor
);
1084 case LFT_REQUEST_METHOD
:
1086 const SBuf
s(al
->getLogMethod());
1087 sb
.append(s
.rawContent(), s
.length());
1088 out
= sb
.termedBuf();
1093 case LFT_REQUEST_URI
:
1094 if (!al
->url
.isEmpty()) {
1095 const SBuf
&s
= al
->url
;
1096 sb
.append(s
.rawContent(), s
.length());
1097 out
= sb
.termedBuf();
1101 case LFT_REQUEST_VERSION_OLD_2X
:
1102 case LFT_REQUEST_VERSION
:
1103 snprintf(tmp
, sizeof(tmp
), "%d.%d", (int) al
->http
.version
.major
, (int) al
->http
.version
.minor
);
1107 case LFT_SERVER_REQ_METHOD
:
1108 if (al
->adapted_request
) {
1109 const SBuf
&s
= al
->adapted_request
->method
.image();
1110 sb
.append(s
.rawContent(), s
.length());
1111 out
= sb
.termedBuf();
1116 case LFT_SERVER_REQ_URI
:
1117 // adapted request URI sent to server/peer
1118 if (al
->adapted_request
) {
1119 const SBuf
&s
= al
->adapted_request
->effectiveRequestUri();
1120 sb
.append(s
.rawContent(), s
.length());
1121 out
= sb
.termedBuf();
1126 case LFT_SERVER_REQ_URLSCHEME
:
1127 if (al
->adapted_request
) {
1128 const SBuf
s(al
->adapted_request
->url
.getScheme().image());
1129 sb
.append(s
.rawContent(), s
.length());
1130 out
= sb
.termedBuf();
1135 case LFT_SERVER_REQ_URLDOMAIN
:
1136 if (al
->adapted_request
) {
1137 out
= al
->adapted_request
->url
.host();
1142 case LFT_SERVER_REQ_URLPORT
:
1143 if (al
->adapted_request
) {
1144 outint
= al
->adapted_request
->url
.port();
1149 case LFT_SERVER_REQ_URLPATH
:
1150 if (al
->adapted_request
) {
1151 SBuf s
= al
->adapted_request
->url
.path();
1157 case LFT_SERVER_REQ_VERSION
:
1158 if (al
->adapted_request
) {
1159 snprintf(tmp
, sizeof(tmp
), "%d.%d",
1160 (int) al
->adapted_request
->http_ver
.major
,
1161 (int) al
->adapted_request
->http_ver
.minor
);
1166 case LFT_CLIENT_REQUEST_SIZE_TOTAL
:
1167 outoff
= al
->http
.clientRequestSz
.messageTotal();
1171 case LFT_CLIENT_REQUEST_SIZE_HEADERS
:
1172 outoff
= al
->http
.clientRequestSz
.header
;
1176 /*case LFT_REQUEST_SIZE_BODY: */
1177 /*case LFT_REQUEST_SIZE_BODY_NO_TE: */
1179 case LFT_ADAPTED_REPLY_SIZE_TOTAL
:
1180 outoff
= al
->http
.clientReplySz
.messageTotal();
1184 case LFT_REPLY_HIGHOFFSET
:
1185 outoff
= al
->cache
.highOffset
;
1191 case LFT_REPLY_OBJECTSIZE
:
1192 outoff
= al
->cache
.objectSize
;
1198 case LFT_ADAPTED_REPLY_SIZE_HEADERS
:
1199 outint
= al
->http
.clientReplySz
.header
;
1203 /*case LFT_REPLY_SIZE_BODY: */
1204 /*case LFT_REPLY_SIZE_BODY_NO_TE: */
1206 case LFT_CLIENT_IO_SIZE_TOTAL
:
1207 outint
= al
->http
.clientRequestSz
.messageTotal() + al
->http
.clientReplySz
.messageTotal();
1210 /*case LFT_SERVER_IO_SIZE_TOTAL: */
1214 out
= al
->request
->tag
.termedBuf();
1222 out
= al
->request
->extacl_log
.termedBuf();
1228 case LFT_SEQUENCE_NUMBER
:
1229 outoff
= logSequenceNumber
;
1234 case LFT_SSL_BUMP_MODE
: {
1235 const Ssl::BumpMode mode
= static_cast<Ssl::BumpMode
>(al
->ssl
.bumpMode
);
1236 // for Ssl::bumpEnd, Ssl::bumpMode() returns NULL and we log '-'
1237 out
= Ssl::bumpMode(mode
);
1241 case LFT_EXT_ACL_USER_CERT_RAW
:
1243 ConnStateData
*conn
= al
->request
->clientConnectionManager
.get();
1244 if (conn
&& Comm::IsConnOpen(conn
->clientConnection
)) {
1245 if (auto ssl
= fd_table
[conn
->clientConnection
->fd
].ssl
.get())
1246 out
= sslGetUserCertificatePEM(ssl
);
1251 case LFT_EXT_ACL_USER_CERTCHAIN_RAW
:
1253 ConnStateData
*conn
= al
->request
->clientConnectionManager
.get();
1254 if (conn
&& Comm::IsConnOpen(conn
->clientConnection
)) {
1255 if (auto ssl
= fd_table
[conn
->clientConnection
->fd
].ssl
.get())
1256 out
= sslGetUserCertificatePEM(ssl
);
1261 case LFT_EXT_ACL_USER_CERT
:
1263 ConnStateData
*conn
= al
->request
->clientConnectionManager
.get();
1264 if (conn
&& Comm::IsConnOpen(conn
->clientConnection
)) {
1265 if (auto ssl
= fd_table
[conn
->clientConnection
->fd
].ssl
.get())
1266 out
= sslGetUserAttribute(ssl
, format
->data
.header
.header
);
1271 case LFT_EXT_ACL_USER_CA_CERT
:
1273 ConnStateData
*conn
= al
->request
->clientConnectionManager
.get();
1274 if (conn
&& Comm::IsConnOpen(conn
->clientConnection
)) {
1275 if (auto ssl
= fd_table
[conn
->clientConnection
->fd
].ssl
.get())
1276 out
= sslGetCAAttribute(ssl
, format
->data
.header
.header
);
1281 case LFT_SSL_USER_CERT_SUBJECT
:
1282 if (X509
*cert
= al
->cache
.sslClientCert
.get()) {
1283 if (X509_NAME
*subject
= X509_get_subject_name(cert
)) {
1284 X509_NAME_oneline(subject
, tmp
, sizeof(tmp
));
1290 case LFT_SSL_USER_CERT_ISSUER
:
1291 if (X509
*cert
= al
->cache
.sslClientCert
.get()) {
1292 if (X509_NAME
*issuer
= X509_get_issuer_name(cert
)) {
1293 X509_NAME_oneline(issuer
, tmp
, sizeof(tmp
));
1299 case LFT_SSL_CLIENT_SNI
:
1300 if (al
->request
&& al
->request
->clientConnectionManager
.valid()) {
1301 if (Ssl::ServerBump
* srvBump
= al
->request
->clientConnectionManager
->serverBump()) {
1302 if (!srvBump
->clientSni
.isEmpty())
1303 out
= srvBump
->clientSni
.c_str();
1308 case LFT_SSL_SERVER_CERT_ERRORS
:
1309 if (al
->request
&& al
->request
->clientConnectionManager
.valid()) {
1310 if (Ssl::ServerBump
* srvBump
= al
->request
->clientConnectionManager
->serverBump()) {
1311 const char *separator
= fmt
->data
.string
? fmt
->data
.string
: ":";
1312 for (const Security::CertErrors
*sslError
= srvBump
->sslErrors(); sslError
!= nullptr; sslError
= sslError
->next
) {
1314 sb
.append(separator
);
1315 if (const char *errorName
= Ssl::GetErrorName(sslError
->element
.code
))
1316 sb
.append(errorName
);
1318 sb
.append(sslErrorName(sslError
->element
.code
, tmp
, sizeof(tmp
)));
1319 if (sslError
->element
.depth
>= 0) {
1320 snprintf(tmp
, sizeof(tmp
), "@depth=%d", sslError
->element
.depth
);
1325 out
= sb
.termedBuf();
1330 case LFT_SSL_SERVER_CERT_ISSUER
:
1331 case LFT_SSL_SERVER_CERT_SUBJECT
:
1332 if (al
->request
&& al
->request
->clientConnectionManager
.valid()) {
1333 if (Ssl::ServerBump
* srvBump
= al
->request
->clientConnectionManager
->serverBump()) {
1334 if (X509
*serverCert
= srvBump
->serverCert
.get()) {
1335 if (fmt
->type
== LFT_SSL_SERVER_CERT_SUBJECT
)
1336 out
= Ssl::GetX509UserAttribute(serverCert
, "DN");
1338 out
= Ssl::GetX509CAAttribute(serverCert
, "DN");
1344 case LFT_TLS_CLIENT_NEGOTIATED_VERSION
:
1345 if (al
->tcpClient
!= nullptr && al
->tcpClient
->hasTlsNegotiations())
1346 out
= al
->tcpClient
->hasTlsNegotiations()->negotiatedVersion();
1349 case LFT_TLS_SERVER_NEGOTIATED_VERSION
:
1350 if (al
->hier
.tcpServer
!= nullptr && al
->hier
.tcpServer
->hasTlsNegotiations())
1351 out
= al
->hier
.tcpServer
->hasTlsNegotiations()->negotiatedVersion();
1354 case LFT_TLS_CLIENT_RECEIVED_HELLO_VERSION
:
1355 if (al
->tcpClient
!= nullptr && al
->tcpClient
->hasTlsNegotiations())
1356 out
= al
->tcpClient
->hasTlsNegotiations()->helloVersion();
1359 case LFT_TLS_SERVER_RECEIVED_HELLO_VERSION
:
1360 if (al
->hier
.tcpServer
!= nullptr && al
->hier
.tcpServer
->hasTlsNegotiations())
1361 out
= al
->hier
.tcpServer
->hasTlsNegotiations()->helloVersion();
1364 case LFT_TLS_CLIENT_SUPPORTED_VERSION
:
1365 if (al
->tcpClient
!= nullptr && al
->tcpClient
->hasTlsNegotiations())
1366 out
= al
->tcpClient
->hasTlsNegotiations()->supportedVersion();
1369 case LFT_TLS_SERVER_SUPPORTED_VERSION
:
1370 if (al
->hier
.tcpServer
!= nullptr && al
->hier
.tcpServer
->hasTlsNegotiations())
1371 out
= al
->hier
.tcpServer
->hasTlsNegotiations()->supportedVersion();
1374 case LFT_TLS_CLIENT_NEGOTIATED_CIPHER
:
1375 if (al
->tcpClient
!= nullptr && al
->tcpClient
->hasTlsNegotiations())
1376 out
= al
->tcpClient
->hasTlsNegotiations()->cipherName();
1379 case LFT_TLS_SERVER_NEGOTIATED_CIPHER
:
1380 if (al
->hier
.tcpServer
!= nullptr && al
->hier
.tcpServer
->hasTlsNegotiations())
1381 out
= al
->hier
.tcpServer
->hasTlsNegotiations()->cipherName();
1385 case LFT_REQUEST_URLGROUP_OLD_2X
:
1386 assert(LFT_REQUEST_URLGROUP_OLD_2X
== 0); // should never happen.
1389 tmp
[0] = fmt
->data
.header
.separator
;
1391 if (fmt
->data
.header
.header
&& *fmt
->data
.header
.header
) {
1392 const char *separator
= tmp
;
1395 Adaptation::History::Pointer ah
= al
->request
? al
->request
->adaptHistory() : Adaptation::History::Pointer();
1396 if (ah
!= NULL
&& ah
->metaHeaders
!= NULL
) {
1397 if (ah
->metaHeaders
->find(note
, fmt
->data
.header
.header
, separator
))
1398 sb
.append(note
.c_str());
1401 if (al
->notes
!= NULL
) {
1402 if (al
->notes
->find(note
, fmt
->data
.header
.header
, separator
)) {
1404 sb
.append(separator
);
1405 sb
.append(note
.c_str());
1408 out
= sb
.termedBuf();
1411 // if no argument given use default "\r\n" as notes separator
1412 const char *separator
= fmt
->data
.string
? tmp
: "\r\n";
1414 Adaptation::History::Pointer ah
= al
->request
? al
->request
->adaptHistory() : Adaptation::History::Pointer();
1415 if (ah
!= NULL
&& ah
->metaHeaders
!= NULL
&& !ah
->metaHeaders
->empty())
1416 sb
.append(ah
->metaHeaders
->toString(separator
));
1418 if (al
->notes
!= NULL
&& !al
->notes
->empty())
1419 sb
.append(al
->notes
->toString(separator
));
1421 out
= sb
.termedBuf();
1426 case LFT_CREDENTIALS
:
1428 if (al
->request
&& al
->request
->auth_user_request
!= NULL
)
1429 out
= strOrNull(al
->request
->auth_user_request
->credentialsStr());
1438 case LFT_EXT_ACL_NAME
:
1439 out
= al
->lastAclName
;
1442 case LFT_EXT_ACL_DATA
:
1443 if (!al
->lastAclData
.isEmpty())
1444 out
= al
->lastAclData
.c_str();
1449 snprintf(tmp
, sizeof(tmp
), "%0*" PRId64
, fmt
->zero
&& fmt
->widthMin
>= 0 ? fmt
->widthMin
: 0, outoff
);
1453 snprintf(tmp
, sizeof(tmp
), "%0*ld", fmt
->zero
&& fmt
->widthMin
>= 0 ? fmt
->widthMin
: 0, outint
);
1455 } else if (doMsec
) {
1456 if (fmt
->widthMax
< 0) {
1457 snprintf(tmp
, sizeof(tmp
), "%0*ld", fmt
->widthMin
, tvToMsec(outtv
));
1459 int precision
= fmt
->widthMax
;
1460 snprintf(tmp
, sizeof(tmp
), "%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
)));
1464 int precision
= fmt
->widthMax
>=0 ? fmt
->widthMax
:3;
1465 snprintf(tmp
, sizeof(tmp
), "%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
));
1470 if (quote
|| fmt
->quote
!= LOG_QUOTE_NONE
) {
1471 // Do not write to the tmp buffer because it may contain the to-be-quoted value.
1472 static char quotedOut
[2 * sizeof(tmp
)];
1473 static_assert(sizeof(quotedOut
) > 0, "quotedOut has zero length");
1474 quotedOut
[0] = '\0';
1476 char *newout
= NULL
;
1479 switch (fmt
->quote
) {
1481 case LOG_QUOTE_NONE
:
1482 newout
= rfc1738_escape_unescaped(out
);
1485 case LOG_QUOTE_QUOTES
: {
1486 size_t out_len
= static_cast<size_t>(strlen(out
)) * 2 + 1;
1487 if (out_len
>= sizeof(tmp
)) {
1488 newout
= (char *)xmalloc(out_len
);
1492 log_quoted_string(out
, newout
);
1496 case LOG_QUOTE_MIMEBLOB
:
1497 newout
= QuoteMimeBlob(out
);
1502 newout
= rfc1738_escape(out
);
1505 case LOG_QUOTE_SHELL
: {
1508 strwordquote(&mbq
, out
);
1509 newout
= mbq
.content();
1529 // enforce width limits if configured
1530 const bool haveMaxWidth
= fmt
->widthMax
>=0 && !doint
&& !dooff
&& !doMsec
&& !doSec
;
1531 if (haveMaxWidth
|| fmt
->widthMin
) {
1532 const int minWidth
= fmt
->widthMin
>= 0 ?
1534 const int maxWidth
= haveMaxWidth
?
1535 fmt
->widthMax
: strlen(out
);
1538 mb
.appendf("%-*.*s", minWidth
, maxWidth
, out
);
1540 mb
.appendf("%*.*s", minWidth
, maxWidth
, out
);
1542 mb
.append(out
, strlen(out
));