2 * Copyright (C) 1996-2016 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/NegotiationHistory.h"
25 #include "SquidTime.h"
30 #include "ssl/ErrorDetail.h"
31 #include "ssl/ServerBump.h"
34 /// Convert a string to NULL pointer if it is ""
35 #define strOrNull(s) ((s)==NULL||(s)[0]=='\0'?NULL:(s))
37 const SBuf
Format::Dash("-");
39 Format::Format::Format(const char *n
) :
46 Format::Format::~Format()
48 // erase the list without consuming stack space
50 // unlink the next entry for deletion
63 Format::Format::parse(const char *def
)
65 const char *cur
, *eos
;
66 Token
*new_lt
, *last_lt
;
67 enum Quoting quote
= LOG_QUOTE_NONE
;
69 debugs(46, 2, HERE
<< "got definition '" << def
<< "'");
72 debugs(46, DBG_IMPORTANT
, "WARNING: existing format for '" << name
<< " " << def
<< "'");
76 /* very inefficent parser, but who cares, this needs to be simple */
77 /* First off, let's tokenize, we'll optimize in a second pass.
78 * A token can either be a %-prefixed sequence (usually a dynamic
79 * token but it can be an escaped sequence), or a string. */
81 eos
= def
+ strlen(def
);
82 format
= new_lt
= last_lt
= new Token
;
83 cur
+= new_lt
->parse(cur
, "e
);
87 last_lt
->next
= new_lt
;
89 cur
+= new_lt
->parse(cur
, "e
);
96 Format::Format::dump(StoreEntry
* entry
, const char *directiveName
, bool eol
) const
100 // loop rather than recursing to conserve stack space.
101 for (const Format
*fmt
= this; fmt
; fmt
= fmt
->next
) {
102 debugs(46, 3, HERE
<< "Dumping format definition for " << fmt
->name
);
104 storeAppendPrintf(entry
, "%s %s ", directiveName
, fmt
->name
);
106 for (Token
*t
= fmt
->format
; t
; t
= t
->next
) {
107 if (t
->type
== LFT_STRING
)
108 storeAppendPrintf(entry
, "%s", t
->data
.string
);
112 ByteCode_t type
= t
->type
;
120 case LFT_ADAPTATION_LAST_HEADER_ELEM
:
123 case LFT_ICAP_REQ_HEADER_ELEM
:
124 case LFT_ICAP_REP_HEADER_ELEM
:
126 case LFT_REQUEST_HEADER_ELEM
:
127 case LFT_ADAPTED_REQUEST_HEADER_ELEM
:
128 case LFT_REPLY_HEADER_ELEM
:
130 if (t
->data
.header
.separator
!= ',')
131 snprintf(argbuf
, sizeof(argbuf
), "%s:%c%s", t
->data
.header
.header
, t
->data
.header
.separator
, t
->data
.header
.element
);
133 snprintf(argbuf
, sizeof(argbuf
), "%s:%s", t
->data
.header
.header
, t
->data
.header
.element
);
138 case LFT_REQUEST_HEADER_ELEM
:
139 type
= LFT_REQUEST_HEADER_ELEM
; // XXX: remove _ELEM?
141 case LFT_ADAPTED_REQUEST_HEADER_ELEM
:
142 type
= LFT_ADAPTED_REQUEST_HEADER_ELEM
; // XXX: remove _ELEM?
144 case LFT_REPLY_HEADER_ELEM
:
145 type
= LFT_REPLY_HEADER_ELEM
; // XXX: remove _ELEM?
148 case LFT_ADAPTATION_LAST_HEADER_ELEM
:
149 type
= LFT_ADAPTATION_LAST_HEADER
;
153 case LFT_ICAP_REQ_HEADER_ELEM
:
154 type
= LFT_ICAP_REQ_HEADER
;
156 case LFT_ICAP_REP_HEADER_ELEM
:
157 type
= LFT_ICAP_REP_HEADER
;
166 case LFT_REQUEST_ALL_HEADERS
:
167 case LFT_ADAPTED_REQUEST_ALL_HEADERS
:
168 case LFT_REPLY_ALL_HEADERS
:
171 case LFT_ADAPTATION_LAST_ALL_HEADERS
:
174 case LFT_ICAP_REQ_ALL_HEADERS
:
175 case LFT_ICAP_REP_ALL_HEADERS
:
179 case LFT_REQUEST_ALL_HEADERS
:
180 type
= LFT_REQUEST_HEADER
;
182 case LFT_ADAPTED_REQUEST_ALL_HEADERS
:
183 type
= LFT_ADAPTED_REQUEST_HEADER
;
185 case LFT_REPLY_ALL_HEADERS
:
186 type
= LFT_REPLY_HEADER
;
189 case LFT_ADAPTATION_LAST_ALL_HEADERS
:
190 type
= LFT_ADAPTATION_LAST_HEADER
;
194 case LFT_ICAP_REQ_ALL_HEADERS
:
195 type
= LFT_ICAP_REQ_HEADER
;
197 case LFT_ICAP_REP_ALL_HEADERS
:
198 type
= LFT_ICAP_REP_HEADER
;
209 arg
= t
->data
.string
;
214 entry
->append("%", 1);
218 case LOG_QUOTE_QUOTES
:
219 entry
->append("\"", 1);
222 case LOG_QUOTE_MIMEBLOB
:
223 entry
->append("[", 1);
227 entry
->append("#", 1);
231 entry
->append("'", 1);
234 case LOG_QUOTE_SHELL
:
235 entry
->append("/", 1);
243 entry
->append("-", 1);
246 entry
->append("0", 1);
248 if (t
->widthMin
>= 0)
249 storeAppendPrintf(entry
, "%d", t
->widthMin
);
251 if (t
->widthMax
>= 0)
252 storeAppendPrintf(entry
, ".%d", t
->widthMax
);
255 storeAppendPrintf(entry
, "{%s}", arg
);
257 storeAppendPrintf(entry
, "%s", t
->label
);
260 entry
->append(" ", 1);
265 entry
->append("\n", 1);
271 log_quoted_string(const char *str
, char *out
)
276 int l
= strcspn(str
, "\"\\\r\n\t");
325 sslErrorName(Ssl::ssl_error_t err
, char *buf
, size_t size
)
327 snprintf(buf
, size
, "SSL_ERR=%d", err
);
333 Format::Format::assemble(MemBuf
&mb
, const AccessLogEntry::Pointer
&al
, int logSequenceNumber
) const
338 for (Token
*fmt
= format
; fmt
!= NULL
; fmt
= fmt
->next
) { /* for each token */
339 const char *out
= NULL
;
346 struct timeval outtv
= {0, 0};
357 out
= fmt
->data
.string
;
360 case LFT_CLIENT_IP_ADDRESS
:
361 al
->getLogClientIp(tmp
, sizeof(tmp
));
365 case LFT_CLIENT_FQDN
:
366 if (al
->cache
.caddr
.isAnyAddr()) // e.g., ICAP OPTIONS lack client
369 out
= fqdncache_gethostbyaddr(al
->cache
.caddr
, FQDN_LOOKUP_IF_MISS
);
371 out
= al
->cache
.caddr
.toStr(tmp
,1024);
376 case LFT_CLIENT_PORT
:
378 outint
= al
->request
->client_addr
.port();
385 // TODO make the ACL checklist have a direct link to any TCP details.
386 if (al
->request
&& al
->request
->clientConnectionManager
.valid() && al
->request
->clientConnectionManager
->clientConnection
!= NULL
) {
387 if (al
->request
->clientConnectionManager
->clientConnection
->remote
.isIPv4())
388 al
->request
->clientConnectionManager
->clientConnection
->remoteEui48
.encode(tmp
, 1024);
390 al
->request
->clientConnectionManager
->clientConnection
->remoteEui64
.encode(tmp
, 1024);
396 case LFT_EXT_ACL_CLIENT_EUI48
:
398 if (al
->request
&& al
->request
->clientConnectionManager
.valid() &&
399 al
->request
->clientConnectionManager
->clientConnection
!= NULL
&&
400 al
->request
->clientConnectionManager
->clientConnection
->remote
.isIPv4()) {
401 al
->request
->clientConnectionManager
->clientConnection
->remoteEui48
.encode(tmp
, 1024);
407 case LFT_EXT_ACL_CLIENT_EUI64
:
409 if (al
->request
&& al
->request
->clientConnectionManager
.valid() &&
410 al
->request
->clientConnectionManager
->clientConnection
!= NULL
&&
411 !al
->request
->clientConnectionManager
->clientConnection
->remote
.isIPv4()) {
412 al
->request
->clientConnectionManager
->clientConnection
->remoteEui64
.encode(tmp
, 1024);
418 case LFT_SERVER_IP_ADDRESS
:
419 if (al
->hier
.tcpServer
!= NULL
) {
420 out
= al
->hier
.tcpServer
->remote
.toStr(tmp
,sizeof(tmp
));
424 case LFT_SERVER_FQDN_OR_PEER_NAME
:
428 case LFT_SERVER_PORT
:
429 if (al
->hier
.tcpServer
!= NULL
) {
430 outint
= al
->hier
.tcpServer
->remote
.port();
435 case LFT_LOCAL_LISTENING_IP
: {
436 // avoid logging a dash if we have reliable info
437 const bool interceptedAtKnownPort
= al
->request
?
438 (al
->request
->flags
.interceptTproxy
||
439 al
->request
->flags
.intercepted
) && al
->cache
.port
!= NULL
:
441 if (interceptedAtKnownPort
) {
442 const bool portAddressConfigured
= !al
->cache
.port
->s
.isAnyAddr();
443 if (portAddressConfigured
)
444 out
= al
->cache
.port
->s
.toStr(tmp
, sizeof(tmp
));
445 } else if (al
->tcpClient
!= NULL
)
446 out
= al
->tcpClient
->local
.toStr(tmp
, sizeof(tmp
));
450 case LFT_CLIENT_LOCAL_IP
:
451 if (al
->tcpClient
!= NULL
) {
452 out
= al
->tcpClient
->local
.toStr(tmp
,sizeof(tmp
));
456 case LFT_CLIENT_LOCAL_TOS
:
457 if (al
->tcpClient
!= NULL
) {
458 snprintf(tmp
, sizeof(tmp
), "0x%x", (uint32_t)al
->tcpClient
->tos
);
463 case LFT_CLIENT_LOCAL_NFMARK
:
464 if (al
->tcpClient
!= NULL
) {
465 snprintf(tmp
, sizeof(tmp
), "0x%x", al
->tcpClient
->nfmark
);
470 case LFT_LOCAL_LISTENING_PORT
:
471 if (al
->cache
.port
!= NULL
) {
472 outint
= al
->cache
.port
->s
.port();
474 } else if (al
->request
) {
475 outint
= al
->request
->my_addr
.port();
480 case LFT_CLIENT_LOCAL_PORT
:
481 if (al
->tcpClient
!= NULL
) {
482 outint
= al
->tcpClient
->local
.port();
487 case LFT_SERVER_LOCAL_IP_OLD_27
:
488 case LFT_SERVER_LOCAL_IP
:
489 if (al
->hier
.tcpServer
!= NULL
) {
490 out
= al
->hier
.tcpServer
->local
.toStr(tmp
,sizeof(tmp
));
494 case LFT_SERVER_LOCAL_PORT
:
495 if (al
->hier
.tcpServer
!= NULL
) {
496 outint
= al
->hier
.tcpServer
->local
.port();
502 case LFT_SERVER_LOCAL_TOS
:
503 if (al
->hier
.tcpServer
!= NULL
) {
504 snprintf(tmp
, sizeof(tmp
), "0x%x", (uint32_t)al
->hier
.tcpServer
->tos
);
509 case LFT_SERVER_LOCAL_NFMARK
:
510 if (al
->hier
.tcpServer
!= NULL
) {
511 snprintf(tmp
, sizeof(tmp
), "0x%x", al
->hier
.tcpServer
->nfmark
);
516 case LFT_TIME_SECONDS_SINCE_EPOCH
:
517 // some platforms store time in 32-bit, some 64-bit...
518 outoff
= static_cast<int64_t>(current_time
.tv_sec
);
522 case LFT_TIME_SUBSECOND
:
523 outint
= current_time
.tv_usec
/ fmt
->divisor
;
527 case LFT_TIME_LOCALTIME
:
533 spec
= fmt
->data
.string
;
535 if (fmt
->type
== LFT_TIME_LOCALTIME
) {
537 spec
= "%d/%b/%Y:%H:%M:%S %z";
538 t
= localtime(&squid_curtime
);
541 spec
= "%d/%b/%Y:%H:%M:%S";
543 t
= gmtime(&squid_curtime
);
546 strftime(tmp
, sizeof(tmp
), spec
, t
);
554 outtv
= al
->cache
.start_time
;
558 case LFT_TIME_TO_HANDLE_REQUEST
:
559 outtv
= al
->cache
.trTime
;
563 case LFT_PEER_RESPONSE_TIME
:
564 if (al
->hier
.peer_response_time
.tv_sec
== -1) {
567 outtv
= al
->hier
.peer_response_time
;
572 case LFT_TOTAL_SERVER_SIDE_RESPONSE_TIME
: {
573 timeval total_response_time
;
574 al
->hier
.totalResponseTime(total_response_time
);
575 if (total_response_time
.tv_sec
== -1) {
578 outtv
= total_response_time
;
584 case LFT_DNS_WAIT_TIME
:
585 if (al
->request
&& al
->request
->dnsWait
>= 0) {
586 // TODO: microsecond precision for dns wait time.
587 // Convert miliseconds to timeval struct:
588 outtv
.tv_sec
= al
->request
->dnsWait
/ 1000;
589 outtv
.tv_usec
= (al
->request
->dnsWait
% 1000) * 1000;
594 case LFT_REQUEST_HEADER
:
597 sb
= al
->request
->header
.getByName(fmt
->data
.header
.header
);
599 out
= sb
.termedBuf();
605 case LFT_ADAPTED_REQUEST_HEADER
:
607 if (al
->adapted_request
)
608 sb
= al
->adapted_request
->header
.getByName(fmt
->data
.header
.header
);
610 out
= sb
.termedBuf();
616 case LFT_REPLY_HEADER
:
618 sb
= al
->reply
->header
.getByName(fmt
->data
.header
.header
);
620 out
= sb
.termedBuf();
627 case LFT_ADAPTATION_SUM_XACT_TIMES
:
629 Adaptation::History::Pointer ah
= al
->request
->adaptHistory();
631 ah
->sumLogString(fmt
->data
.string
, sb
);
632 out
= sb
.termedBuf();
636 case LFT_ADAPTATION_ALL_XACT_TIMES
:
638 Adaptation::History::Pointer ah
= al
->request
->adaptHistory();
640 ah
->allLogString(fmt
->data
.string
, sb
);
641 out
= sb
.termedBuf();
645 case LFT_ADAPTATION_LAST_HEADER
:
647 const Adaptation::History::Pointer ah
= al
->request
->adaptHistory();
648 if (ah
!= NULL
) // XXX: add adapt::<all_h but use lastMeta here
649 sb
= ah
->allMeta
.getByName(fmt
->data
.header
.header
);
652 // XXX: here and elsewhere: move such code inside the if guard
653 out
= sb
.termedBuf();
659 case LFT_ADAPTATION_LAST_HEADER_ELEM
:
661 const Adaptation::History::Pointer ah
= al
->request
->adaptHistory();
662 if (ah
!= NULL
) // XXX: add adapt::<all_h but use lastMeta here
663 sb
= ah
->allMeta
.getByNameListMember(fmt
->data
.header
.header
, fmt
->data
.header
.element
, fmt
->data
.header
.separator
);
666 out
= sb
.termedBuf();
672 case LFT_ADAPTATION_LAST_ALL_HEADERS
:
673 out
= al
->adapt
.last_meta
;
683 out
= al
->icap
.hostAddr
.toStr(tmp
,1024);
686 case LFT_ICAP_SERV_NAME
:
687 out
= al
->icap
.serviceName
.termedBuf();
690 case LFT_ICAP_REQUEST_URI
:
691 out
= al
->icap
.reqUri
.termedBuf();
694 case LFT_ICAP_REQUEST_METHOD
:
695 out
= Adaptation::Icap::ICAP::methodStr(al
->icap
.reqMethod
);
698 case LFT_ICAP_BYTES_SENT
:
699 outoff
= al
->icap
.bytesSent
;
703 case LFT_ICAP_BYTES_READ
:
704 outoff
= al
->icap
.bytesRead
;
708 case LFT_ICAP_BODY_BYTES_READ
:
709 if (al
->icap
.bodyBytesRead
>= 0) {
710 outoff
= al
->icap
.bodyBytesRead
;
713 // else if icap.bodyBytesRead < 0, we do not have any http data,
714 // so just print a "-" (204 responses etc)
717 case LFT_ICAP_REQ_HEADER
:
718 if (NULL
!= al
->icap
.request
) {
719 sb
= al
->icap
.request
->header
.getByName(fmt
->data
.header
.header
);
720 out
= sb
.termedBuf();
725 case LFT_ICAP_REQ_HEADER_ELEM
:
726 if (al
->icap
.request
)
727 sb
= al
->icap
.request
->header
.getByNameListMember(fmt
->data
.header
.header
, fmt
->data
.header
.element
, fmt
->data
.header
.separator
);
729 out
= sb
.termedBuf();
735 case LFT_ICAP_REQ_ALL_HEADERS
:
736 if (al
->icap
.request
) {
737 HttpHeaderPos pos
= HttpHeaderInitPos
;
738 while (const HttpHeaderEntry
*e
= al
->icap
.request
->header
.getEntry(&pos
)) {
744 out
= sb
.termedBuf();
749 case LFT_ICAP_REP_HEADER
:
750 if (NULL
!= al
->icap
.reply
) {
751 sb
= al
->icap
.reply
->header
.getByName(fmt
->data
.header
.header
);
752 out
= sb
.termedBuf();
757 case LFT_ICAP_REP_HEADER_ELEM
:
758 if (NULL
!= al
->icap
.reply
)
759 sb
= al
->icap
.reply
->header
.getByNameListMember(fmt
->data
.header
.header
, fmt
->data
.header
.element
, fmt
->data
.header
.separator
);
761 out
= sb
.termedBuf();
767 case LFT_ICAP_REP_ALL_HEADERS
:
768 if (al
->icap
.reply
) {
769 HttpHeaderPos pos
= HttpHeaderInitPos
;
770 while (const HttpHeaderEntry
*e
= al
->icap
.reply
->header
.getEntry(&pos
)) {
776 out
= sb
.termedBuf();
781 case LFT_ICAP_TR_RESPONSE_TIME
:
782 outtv
= al
->icap
.trTime
;
786 case LFT_ICAP_IO_TIME
:
787 outtv
= al
->icap
.ioTime
;
791 case LFT_ICAP_STATUS_CODE
:
792 outint
= al
->icap
.resStatus
;
796 case LFT_ICAP_OUTCOME
:
797 out
= al
->icap
.outcome
;
800 case LFT_ICAP_TOTAL_TIME
:
801 outtv
= al
->icap
.processingTime
;
805 case LFT_REQUEST_HEADER_ELEM
:
807 sb
= al
->request
->header
.getByNameListMember(fmt
->data
.header
.header
, fmt
->data
.header
.element
, fmt
->data
.header
.separator
);
809 out
= sb
.termedBuf();
815 case LFT_ADAPTED_REQUEST_HEADER_ELEM
:
816 if (al
->adapted_request
)
817 sb
= al
->adapted_request
->header
.getByNameListMember(fmt
->data
.header
.header
, fmt
->data
.header
.element
, fmt
->data
.header
.separator
);
819 out
= sb
.termedBuf();
825 case LFT_REPLY_HEADER_ELEM
:
827 sb
= al
->reply
->header
.getByNameListMember(fmt
->data
.header
.header
, fmt
->data
.header
.element
, fmt
->data
.header
.separator
);
829 out
= sb
.termedBuf();
835 case LFT_REQUEST_ALL_HEADERS
:
836 out
= al
->headers
.request
;
842 case LFT_ADAPTED_REQUEST_ALL_HEADERS
:
843 out
= al
->headers
.adapted_request
;
849 case LFT_REPLY_ALL_HEADERS
:
850 out
= al
->headers
.reply
;
858 if (al
->request
&& al
->request
->auth_user_request
!= NULL
)
859 out
= strOrNull(al
->request
->auth_user_request
->username());
861 if (!out
&& al
->request
&& al
->request
->extacl_user
.size()) {
862 if (const char *t
= al
->request
->extacl_user
.termedBuf())
867 out
= strOrNull(al
->cache
.extuser
);
871 out
= strOrNull(al
->cache
.ssluser
);
874 out
= strOrNull(al
->cache
.rfc931
);
879 if (al
->request
&& al
->request
->auth_user_request
!= NULL
)
880 out
= strOrNull(al
->request
->auth_user_request
->username());
885 out
= strOrNull(al
->cache
.rfc931
);
888 case LFT_USER_EXTERNAL
:
889 if (al
->request
&& al
->request
->extacl_user
.size()) {
890 if (const char *t
= al
->request
->extacl_user
.termedBuf())
895 out
= strOrNull(al
->cache
.extuser
);
898 /* case LFT_USER_REALM: */
899 /* case LFT_USER_SCHEME: */
901 // the fmt->type can not be LFT_HTTP_SENT_STATUS_CODE_OLD_30
902 // but compiler complains if ommited
903 case LFT_HTTP_SENT_STATUS_CODE_OLD_30
:
904 case LFT_HTTP_SENT_STATUS_CODE
:
905 outint
= al
->http
.code
;
911 case LFT_HTTP_RECEIVED_STATUS_CODE
:
912 if (al
->hier
.peer_reply_status
== Http::scNone
) {
915 outint
= al
->hier
.peer_reply_status
;
919 /* case LFT_HTTP_STATUS:
920 * out = statusline->text;
924 case LFT_HTTP_BODY_BYTES_READ
:
925 if (al
->hier
.bodyBytesRead
>= 0) {
926 outoff
= al
->hier
.bodyBytesRead
;
929 // else if hier.bodyBytesRead < 0 we did not have any data exchange with
930 // a peer server so just print a "-" (eg requests served from cache,
931 // or internal error messages).
934 case LFT_SQUID_STATUS
:
935 out
= al
->cache
.code
.c_str();
938 case LFT_SQUID_ERROR
:
939 if (al
->request
&& al
->request
->errType
!= ERR_NONE
)
940 out
= errorPageName(al
->request
->errType
);
943 case LFT_SQUID_ERROR_DETAIL
:
945 if (al
->request
&& al
->request
->errType
== ERR_SECURE_CONNECT_FAIL
) {
946 if (! (out
= Ssl::GetErrorName(al
->request
->errDetail
)))
947 out
= sslErrorName(al
->request
->errDetail
, tmp
, sizeof(tmp
));
950 if (al
->request
&& al
->request
->errDetail
!= ERR_DETAIL_NONE
) {
951 if (al
->request
->errDetail
> ERR_DETAIL_START
&& al
->request
->errDetail
< ERR_DETAIL_MAX
)
952 out
= errorDetailName(al
->request
->errDetail
);
954 if (al
->request
->errDetail
>= ERR_DETAIL_EXCEPTION_START
)
955 snprintf(tmp
, sizeof(tmp
), "%s=0x%X",
956 errorDetailName(al
->request
->errDetail
), (uint32_t) al
->request
->errDetail
);
958 snprintf(tmp
, sizeof(tmp
), "%s=%d",
959 errorDetailName(al
->request
->errDetail
), al
->request
->errDetail
);
965 case LFT_SQUID_HIERARCHY
:
966 if (al
->hier
.ping
.timedout
)
967 mb
.append("TIMEOUT_", 8);
969 out
= hier_code_str
[al
->hier
.code
];
974 out
= al
->http
.content_type
;
978 case LFT_CLIENT_REQ_METHOD
:
980 const SBuf
&s
= al
->request
->method
.image();
981 sb
.append(s
.rawContent(), s
.length());
982 out
= sb
.termedBuf();
987 case LFT_CLIENT_REQ_URI
:
988 // original client URI
990 const SBuf
&s
= al
->request
->effectiveRequestUri();
991 sb
.append(s
.rawContent(), s
.length());
992 out
= sb
.termedBuf();
997 case LFT_CLIENT_REQ_URLSCHEME
:
999 const SBuf
s(al
->request
->url
.getScheme().image());
1000 sb
.append(s
.rawContent(), s
.length());
1001 out
= sb
.termedBuf();
1006 case LFT_CLIENT_REQ_URLDOMAIN
:
1008 out
= al
->request
->url
.host();
1013 case LFT_CLIENT_REQ_URLPORT
:
1015 outint
= al
->request
->url
.port();
1020 case LFT_REQUEST_URLPATH_OLD_31
:
1021 case LFT_CLIENT_REQ_URLPATH
:
1023 SBuf s
= al
->request
->url
.path();
1029 case LFT_CLIENT_REQ_VERSION
:
1031 snprintf(tmp
, sizeof(tmp
), "%d.%d", (int) al
->request
->http_ver
.major
, (int) al
->request
->http_ver
.minor
);
1036 case LFT_REQUEST_METHOD
:
1038 const SBuf
s(al
->getLogMethod());
1039 sb
.append(s
.rawContent(), s
.length());
1040 out
= sb
.termedBuf();
1045 case LFT_REQUEST_URI
:
1046 if (!al
->url
.isEmpty()) {
1047 const SBuf
&s
= al
->url
;
1048 sb
.append(s
.rawContent(), s
.length());
1049 out
= sb
.termedBuf();
1053 case LFT_REQUEST_VERSION_OLD_2X
:
1054 case LFT_REQUEST_VERSION
:
1055 snprintf(tmp
, sizeof(tmp
), "%d.%d", (int) al
->http
.version
.major
, (int) al
->http
.version
.minor
);
1059 case LFT_SERVER_REQ_METHOD
:
1060 if (al
->adapted_request
) {
1061 const SBuf
&s
= al
->adapted_request
->method
.image();
1062 sb
.append(s
.rawContent(), s
.length());
1063 out
= sb
.termedBuf();
1068 case LFT_SERVER_REQ_URI
:
1069 // adapted request URI sent to server/peer
1070 if (al
->adapted_request
) {
1071 const SBuf
&s
= al
->adapted_request
->effectiveRequestUri();
1072 sb
.append(s
.rawContent(), s
.length());
1073 out
= sb
.termedBuf();
1078 case LFT_SERVER_REQ_URLSCHEME
:
1079 if (al
->adapted_request
) {
1080 const SBuf
s(al
->adapted_request
->url
.getScheme().image());
1081 sb
.append(s
.rawContent(), s
.length());
1082 out
= sb
.termedBuf();
1087 case LFT_SERVER_REQ_URLDOMAIN
:
1088 if (al
->adapted_request
) {
1089 out
= al
->adapted_request
->url
.host();
1094 case LFT_SERVER_REQ_URLPORT
:
1095 if (al
->adapted_request
) {
1096 outint
= al
->adapted_request
->url
.port();
1101 case LFT_SERVER_REQ_URLPATH
:
1102 if (al
->adapted_request
) {
1103 SBuf s
= al
->adapted_request
->url
.path();
1109 case LFT_SERVER_REQ_VERSION
:
1110 if (al
->adapted_request
) {
1111 snprintf(tmp
, sizeof(tmp
), "%d.%d",
1112 (int) al
->adapted_request
->http_ver
.major
,
1113 (int) al
->adapted_request
->http_ver
.minor
);
1118 case LFT_CLIENT_REQUEST_SIZE_TOTAL
:
1119 outoff
= al
->http
.clientRequestSz
.messageTotal();
1123 case LFT_CLIENT_REQUEST_SIZE_HEADERS
:
1124 outoff
= al
->http
.clientRequestSz
.header
;
1128 /*case LFT_REQUEST_SIZE_BODY: */
1129 /*case LFT_REQUEST_SIZE_BODY_NO_TE: */
1131 case LFT_ADAPTED_REPLY_SIZE_TOTAL
:
1132 outoff
= al
->http
.clientReplySz
.messageTotal();
1136 case LFT_REPLY_HIGHOFFSET
:
1137 outoff
= al
->cache
.highOffset
;
1143 case LFT_REPLY_OBJECTSIZE
:
1144 outoff
= al
->cache
.objectSize
;
1150 case LFT_ADAPTED_REPLY_SIZE_HEADERS
:
1151 outint
= al
->http
.clientReplySz
.header
;
1155 /*case LFT_REPLY_SIZE_BODY: */
1156 /*case LFT_REPLY_SIZE_BODY_NO_TE: */
1158 case LFT_CLIENT_IO_SIZE_TOTAL
:
1159 outint
= al
->http
.clientRequestSz
.messageTotal() + al
->http
.clientReplySz
.messageTotal();
1162 /*case LFT_SERVER_IO_SIZE_TOTAL: */
1166 out
= al
->request
->tag
.termedBuf();
1174 out
= al
->request
->extacl_log
.termedBuf();
1180 case LFT_SEQUENCE_NUMBER
:
1181 outoff
= logSequenceNumber
;
1186 case LFT_SSL_BUMP_MODE
: {
1187 const Ssl::BumpMode mode
= static_cast<Ssl::BumpMode
>(al
->ssl
.bumpMode
);
1188 // for Ssl::bumpEnd, Ssl::bumpMode() returns NULL and we log '-'
1189 out
= Ssl::bumpMode(mode
);
1193 case LFT_EXT_ACL_USER_CERT_RAW
:
1195 ConnStateData
*conn
= al
->request
->clientConnectionManager
.get();
1196 if (conn
&& Comm::IsConnOpen(conn
->clientConnection
)) {
1197 if (auto ssl
= fd_table
[conn
->clientConnection
->fd
].ssl
.get())
1198 out
= sslGetUserCertificatePEM(ssl
);
1203 case LFT_EXT_ACL_USER_CERTCHAIN_RAW
:
1205 ConnStateData
*conn
= al
->request
->clientConnectionManager
.get();
1206 if (conn
&& Comm::IsConnOpen(conn
->clientConnection
)) {
1207 if (auto ssl
= fd_table
[conn
->clientConnection
->fd
].ssl
.get())
1208 out
= sslGetUserCertificatePEM(ssl
);
1213 case LFT_EXT_ACL_USER_CERT
:
1215 ConnStateData
*conn
= al
->request
->clientConnectionManager
.get();
1216 if (conn
&& Comm::IsConnOpen(conn
->clientConnection
)) {
1217 if (auto ssl
= fd_table
[conn
->clientConnection
->fd
].ssl
.get())
1218 out
= sslGetUserAttribute(ssl
, format
->data
.header
.header
);
1223 case LFT_EXT_ACL_USER_CA_CERT
:
1225 ConnStateData
*conn
= al
->request
->clientConnectionManager
.get();
1226 if (conn
&& Comm::IsConnOpen(conn
->clientConnection
)) {
1227 if (auto ssl
= fd_table
[conn
->clientConnection
->fd
].ssl
.get())
1228 out
= sslGetCAAttribute(ssl
, format
->data
.header
.header
);
1233 case LFT_SSL_USER_CERT_SUBJECT
:
1234 if (X509
*cert
= al
->cache
.sslClientCert
.get()) {
1235 if (X509_NAME
*subject
= X509_get_subject_name(cert
)) {
1236 X509_NAME_oneline(subject
, tmp
, sizeof(tmp
));
1242 case LFT_SSL_USER_CERT_ISSUER
:
1243 if (X509
*cert
= al
->cache
.sslClientCert
.get()) {
1244 if (X509_NAME
*issuer
= X509_get_issuer_name(cert
)) {
1245 X509_NAME_oneline(issuer
, tmp
, sizeof(tmp
));
1251 case LFT_SSL_CLIENT_SNI
:
1252 if (al
->request
&& al
->request
->clientConnectionManager
.valid()) {
1253 if (Ssl::ServerBump
* srvBump
= al
->request
->clientConnectionManager
->serverBump()) {
1254 if (!srvBump
->clientSni
.isEmpty())
1255 out
= srvBump
->clientSni
.c_str();
1260 case LFT_SSL_SERVER_CERT_ERRORS
:
1261 if (al
->request
&& al
->request
->clientConnectionManager
.valid()) {
1262 if (Ssl::ServerBump
* srvBump
= al
->request
->clientConnectionManager
->serverBump()) {
1263 const char *separator
= fmt
->data
.string
? fmt
->data
.string
: ":";
1264 for (Ssl::CertErrors
const *sslError
= srvBump
->sslErrors(); sslError
!= NULL
; sslError
= sslError
->next
) {
1266 sb
.append(separator
);
1267 if (const char *errorName
= Ssl::GetErrorName(sslError
->element
.code
))
1268 sb
.append(errorName
);
1270 sb
.append(sslErrorName(sslError
->element
.code
, tmp
, sizeof(tmp
)));
1271 if (sslError
->element
.depth
>= 0) {
1272 snprintf(tmp
, sizeof(tmp
), "@depth=%d", sslError
->element
.depth
);
1277 out
= sb
.termedBuf();
1282 case LFT_SSL_SERVER_CERT_ISSUER
:
1283 case LFT_SSL_SERVER_CERT_SUBJECT
:
1284 if (al
->request
&& al
->request
->clientConnectionManager
.valid()) {
1285 if (Ssl::ServerBump
* srvBump
= al
->request
->clientConnectionManager
->serverBump()) {
1286 if (X509
*serverCert
= srvBump
->serverCert
.get()) {
1287 if (fmt
->type
== LFT_SSL_SERVER_CERT_SUBJECT
)
1288 out
= Ssl::GetX509UserAttribute(serverCert
, "DN");
1290 out
= Ssl::GetX509CAAttribute(serverCert
, "DN");
1296 case LFT_TLS_CLIENT_NEGOTIATED_VERSION
:
1297 if (al
->tcpClient
!= nullptr && al
->tcpClient
->hasTlsNegotiations())
1298 out
= al
->tcpClient
->hasTlsNegotiations()->negotiatedVersion();
1301 case LFT_TLS_SERVER_NEGOTIATED_VERSION
:
1302 if (al
->hier
.tcpServer
!= nullptr && al
->hier
.tcpServer
->hasTlsNegotiations())
1303 out
= al
->hier
.tcpServer
->hasTlsNegotiations()->negotiatedVersion();
1306 case LFT_TLS_CLIENT_RECEIVED_HELLO_VERSION
:
1307 if (al
->tcpClient
!= nullptr && al
->tcpClient
->hasTlsNegotiations())
1308 out
= al
->tcpClient
->hasTlsNegotiations()->helloVersion();
1311 case LFT_TLS_SERVER_RECEIVED_HELLO_VERSION
:
1312 if (al
->hier
.tcpServer
!= nullptr && al
->hier
.tcpServer
->hasTlsNegotiations())
1313 out
= al
->hier
.tcpServer
->hasTlsNegotiations()->helloVersion();
1316 case LFT_TLS_CLIENT_SUPPORTED_VERSION
:
1317 if (al
->tcpClient
!= nullptr && al
->tcpClient
->hasTlsNegotiations())
1318 out
= al
->tcpClient
->hasTlsNegotiations()->supportedVersion();
1321 case LFT_TLS_SERVER_SUPPORTED_VERSION
:
1322 if (al
->hier
.tcpServer
!= nullptr && al
->hier
.tcpServer
->hasTlsNegotiations())
1323 out
= al
->hier
.tcpServer
->hasTlsNegotiations()->supportedVersion();
1326 case LFT_TLS_CLIENT_NEGOTIATED_CIPHER
:
1327 if (al
->tcpClient
!= nullptr && al
->tcpClient
->hasTlsNegotiations())
1328 out
= al
->tcpClient
->hasTlsNegotiations()->cipherName();
1331 case LFT_TLS_SERVER_NEGOTIATED_CIPHER
:
1332 if (al
->hier
.tcpServer
!= nullptr && al
->hier
.tcpServer
->hasTlsNegotiations())
1333 out
= al
->hier
.tcpServer
->hasTlsNegotiations()->cipherName();
1337 case LFT_REQUEST_URLGROUP_OLD_2X
:
1338 assert(LFT_REQUEST_URLGROUP_OLD_2X
== 0); // should never happen.
1341 tmp
[0] = fmt
->data
.header
.separator
;
1343 if (fmt
->data
.header
.header
&& *fmt
->data
.header
.header
) {
1344 const char *separator
= tmp
;
1346 Adaptation::History::Pointer ah
= al
->request
? al
->request
->adaptHistory() : Adaptation::History::Pointer();
1347 if (ah
!= NULL
&& ah
->metaHeaders
!= NULL
) {
1348 if (const char *meta
= ah
->metaHeaders
->find(fmt
->data
.header
.header
, separator
))
1352 if (al
->notes
!= NULL
) {
1353 if (const char *note
= al
->notes
->find(fmt
->data
.header
.header
, separator
)) {
1355 sb
.append(separator
);
1359 out
= sb
.termedBuf();
1362 // if no argument given use default "\r\n" as notes separator
1363 const char *separator
= fmt
->data
.string
? tmp
: "\r\n";
1365 Adaptation::History::Pointer ah
= al
->request
? al
->request
->adaptHistory() : Adaptation::History::Pointer();
1366 if (ah
!= NULL
&& ah
->metaHeaders
!= NULL
&& !ah
->metaHeaders
->empty())
1367 sb
.append(ah
->metaHeaders
->toString(separator
));
1369 if (al
->notes
!= NULL
&& !al
->notes
->empty())
1370 sb
.append(al
->notes
->toString(separator
));
1372 out
= sb
.termedBuf();
1377 case LFT_CREDENTIALS
:
1379 if (al
->request
&& al
->request
->auth_user_request
!= NULL
)
1380 out
= strOrNull(al
->request
->auth_user_request
->credentialsStr());
1389 case LFT_EXT_ACL_NAME
:
1390 out
= al
->lastAclName
;
1393 case LFT_EXT_ACL_DATA
:
1394 if (!al
->lastAclData
.isEmpty())
1395 out
= al
->lastAclData
.c_str();
1400 snprintf(tmp
, sizeof(tmp
), "%0*" PRId64
, fmt
->zero
&& fmt
->widthMin
>= 0 ? fmt
->widthMin
: 0, outoff
);
1404 snprintf(tmp
, sizeof(tmp
), "%0*ld", fmt
->zero
&& fmt
->widthMin
>= 0 ? fmt
->widthMin
: 0, outint
);
1406 } else if (doMsec
) {
1407 if (fmt
->widthMax
< 0) {
1408 snprintf(tmp
, sizeof(tmp
), "%0*ld", fmt
->widthMin
, tvToMsec(outtv
));
1410 int precision
= fmt
->widthMax
;
1411 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
)));
1415 int precision
= fmt
->widthMax
>=0 ? fmt
->widthMax
:3;
1416 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
));
1421 if (quote
|| fmt
->quote
!= LOG_QUOTE_NONE
) {
1422 char *newout
= NULL
;
1425 switch (fmt
->quote
) {
1427 case LOG_QUOTE_NONE
:
1428 newout
= rfc1738_escape_unescaped(out
);
1431 case LOG_QUOTE_QUOTES
: {
1432 size_t out_len
= static_cast<size_t>(strlen(out
)) * 2 + 1;
1433 if (out_len
>= sizeof(tmp
)) {
1434 newout
= (char *)xmalloc(out_len
);
1438 log_quoted_string(out
, newout
);
1442 case LOG_QUOTE_MIMEBLOB
:
1443 newout
= QuoteMimeBlob(out
);
1448 newout
= rfc1738_escape(out
);
1451 case LOG_QUOTE_SHELL
: {
1454 strwordquote(&mbq
, out
);
1455 newout
= mbq
.content();
1475 // enforce width limits if configured
1476 const bool haveMaxWidth
= fmt
->widthMax
>=0 && !doint
&& !dooff
&& !doMsec
&& !doSec
;
1477 if (haveMaxWidth
|| fmt
->widthMin
) {
1478 const int minWidth
= fmt
->widthMin
>= 0 ?
1480 const int maxWidth
= haveMaxWidth
?
1481 fmt
->widthMax
: strlen(out
);
1484 mb
.appendf("%-*.*s", minWidth
, maxWidth
, out
);
1486 mb
.appendf("%*.*s", minWidth
, maxWidth
, out
);
1488 mb
.append(out
, strlen(out
));