2 * Copyright (C) 1996-2015 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 "HttpRequest.h"
23 #include "SquidTime.h"
27 #include "ssl/ErrorDetail.h"
28 #include "ssl/ServerBump.h"
31 /// Convert a string to NULL pointer if it is ""
32 #define strOrNull(s) ((s)==NULL||(s)[0]=='\0'?NULL:(s))
34 Format::Format::Format(const char *n
) :
41 Format::Format::~Format()
43 // erase the list without consuming stack space
45 // unlink the next entry for deletion
58 Format::Format::parse(const char *def
)
60 const char *cur
, *eos
;
61 Token
*new_lt
, *last_lt
;
62 enum Quoting quote
= LOG_QUOTE_NONE
;
64 debugs(46, 2, HERE
<< "got definition '" << def
<< "'");
67 debugs(46, DBG_IMPORTANT
, "WARNING: existing format for '" << name
<< " " << def
<< "'");
71 /* very inefficent parser, but who cares, this needs to be simple */
72 /* First off, let's tokenize, we'll optimize in a second pass.
73 * A token can either be a %-prefixed sequence (usually a dynamic
74 * token but it can be an escaped sequence), or a string. */
76 eos
= def
+ strlen(def
);
77 format
= new_lt
= last_lt
= new Token
;
78 cur
+= new_lt
->parse(cur
, "e
);
82 last_lt
->next
= new_lt
;
84 cur
+= new_lt
->parse(cur
, "e
);
91 Format::Format::dump(StoreEntry
* entry
, const char *directiveName
)
95 // loop rather than recursing to conserve stack space.
96 for (Format
*fmt
= this; fmt
; fmt
= fmt
->next
) {
97 debugs(46, 3, HERE
<< "Dumping format definition for " << fmt
->name
);
98 storeAppendPrintf(entry
, "%s %s ", directiveName
, fmt
->name
);
100 for (Token
*t
= fmt
->format
; t
; t
= t
->next
) {
101 if (t
->type
== LFT_STRING
)
102 storeAppendPrintf(entry
, "%s", t
->data
.string
);
106 ByteCode_t type
= t
->type
;
114 case LFT_ADAPTATION_LAST_HEADER_ELEM
:
117 case LFT_ICAP_REQ_HEADER_ELEM
:
118 case LFT_ICAP_REP_HEADER_ELEM
:
120 case LFT_REQUEST_HEADER_ELEM
:
121 case LFT_ADAPTED_REQUEST_HEADER_ELEM
:
122 case LFT_REPLY_HEADER_ELEM
:
124 if (t
->data
.header
.separator
!= ',')
125 snprintf(argbuf
, sizeof(argbuf
), "%s:%c%s", t
->data
.header
.header
, t
->data
.header
.separator
, t
->data
.header
.element
);
127 snprintf(argbuf
, sizeof(argbuf
), "%s:%s", t
->data
.header
.header
, t
->data
.header
.element
);
132 case LFT_REQUEST_HEADER_ELEM
:
133 type
= LFT_REQUEST_HEADER_ELEM
; // XXX: remove _ELEM?
135 case LFT_ADAPTED_REQUEST_HEADER_ELEM
:
136 type
= LFT_ADAPTED_REQUEST_HEADER_ELEM
; // XXX: remove _ELEM?
138 case LFT_REPLY_HEADER_ELEM
:
139 type
= LFT_REPLY_HEADER_ELEM
; // XXX: remove _ELEM?
142 case LFT_ADAPTATION_LAST_HEADER_ELEM
:
143 type
= LFT_ADAPTATION_LAST_HEADER
;
147 case LFT_ICAP_REQ_HEADER_ELEM
:
148 type
= LFT_ICAP_REQ_HEADER
;
150 case LFT_ICAP_REP_HEADER_ELEM
:
151 type
= LFT_ICAP_REP_HEADER
;
160 case LFT_REQUEST_ALL_HEADERS
:
161 case LFT_ADAPTED_REQUEST_ALL_HEADERS
:
162 case LFT_REPLY_ALL_HEADERS
:
165 case LFT_ADAPTATION_LAST_ALL_HEADERS
:
168 case LFT_ICAP_REQ_ALL_HEADERS
:
169 case LFT_ICAP_REP_ALL_HEADERS
:
173 case LFT_REQUEST_ALL_HEADERS
:
174 type
= LFT_REQUEST_HEADER
;
176 case LFT_ADAPTED_REQUEST_ALL_HEADERS
:
177 type
= LFT_ADAPTED_REQUEST_HEADER
;
179 case LFT_REPLY_ALL_HEADERS
:
180 type
= LFT_REPLY_HEADER
;
183 case LFT_ADAPTATION_LAST_ALL_HEADERS
:
184 type
= LFT_ADAPTATION_LAST_HEADER
;
188 case LFT_ICAP_REQ_ALL_HEADERS
:
189 type
= LFT_ICAP_REQ_HEADER
;
191 case LFT_ICAP_REP_ALL_HEADERS
:
192 type
= LFT_ICAP_REP_HEADER
;
203 arg
= t
->data
.string
;
208 entry
->append("%", 1);
212 case LOG_QUOTE_QUOTES
:
213 entry
->append("\"", 1);
216 case LOG_QUOTE_MIMEBLOB
:
217 entry
->append("[", 1);
221 entry
->append("#", 1);
225 entry
->append("'", 1);
233 entry
->append("-", 1);
236 entry
->append("0", 1);
238 if (t
->widthMin
>= 0)
239 storeAppendPrintf(entry
, "%d", t
->widthMin
);
241 if (t
->widthMax
>= 0)
242 storeAppendPrintf(entry
, ".%d", t
->widthMax
);
245 storeAppendPrintf(entry
, "{%s}", arg
);
247 storeAppendPrintf(entry
, "%s", t
->label
);
250 entry
->append(" ", 1);
254 entry
->append("\n", 1);
260 log_quoted_string(const char *str
, char *out
)
265 int l
= strcspn(str
, "\"\\\r\n\t");
314 sslErrorName(Ssl::ssl_error_t err
, char *buf
, size_t size
)
316 snprintf(buf
, size
, "SSL_ERR=%d", err
);
322 Format::Format::assemble(MemBuf
&mb
, const AccessLogEntry::Pointer
&al
, int logSequenceNumber
) const
327 for (Token
*fmt
= format
; fmt
!= NULL
; fmt
= fmt
->next
) { /* for each token */
328 const char *out
= NULL
;
335 struct timeval outtv
= {0, 0};
346 out
= fmt
->data
.string
;
349 case LFT_CLIENT_IP_ADDRESS
:
350 al
->getLogClientIp(tmp
, sizeof(tmp
));
354 case LFT_CLIENT_FQDN
:
355 if (al
->cache
.caddr
.isAnyAddr()) // e.g., ICAP OPTIONS lack client
358 out
= fqdncache_gethostbyaddr(al
->cache
.caddr
, FQDN_LOOKUP_IF_MISS
);
360 out
= al
->cache
.caddr
.toStr(tmp
,1024);
365 case LFT_CLIENT_PORT
:
367 outint
= al
->request
->client_addr
.port();
374 // TODO make the ACL checklist have a direct link to any TCP details.
375 if (al
->request
&& al
->request
->clientConnectionManager
.valid() && al
->request
->clientConnectionManager
->clientConnection
!= NULL
) {
376 if (al
->request
->clientConnectionManager
->clientConnection
->remote
.isIPv4())
377 al
->request
->clientConnectionManager
->clientConnection
->remoteEui48
.encode(tmp
, 1024);
379 al
->request
->clientConnectionManager
->clientConnection
->remoteEui64
.encode(tmp
, 1024);
387 case LFT_SERVER_IP_ADDRESS
:
388 if (al
->hier
.tcpServer
!= NULL
) {
389 out
= al
->hier
.tcpServer
->remote
.toStr(tmp
,sizeof(tmp
));
393 case LFT_SERVER_FQDN_OR_PEER_NAME
:
397 case LFT_SERVER_PORT
:
398 if (al
->hier
.tcpServer
!= NULL
) {
399 outint
= al
->hier
.tcpServer
->remote
.port();
404 case LFT_LOCAL_LISTENING_IP
: {
405 // avoid logging a dash if we have reliable info
406 const bool interceptedAtKnownPort
= al
->request
?
407 (al
->request
->flags
.interceptTproxy
||
408 al
->request
->flags
.intercepted
) && al
->cache
.port
!= NULL
:
410 if (interceptedAtKnownPort
) {
411 const bool portAddressConfigured
= !al
->cache
.port
->s
.isAnyAddr();
412 if (portAddressConfigured
)
413 out
= al
->cache
.port
->s
.toStr(tmp
, sizeof(tmp
));
414 } else if (al
->tcpClient
!= NULL
)
415 out
= al
->tcpClient
->local
.toStr(tmp
, sizeof(tmp
));
419 case LFT_CLIENT_LOCAL_IP
:
420 if (al
->tcpClient
!= NULL
) {
421 out
= al
->tcpClient
->local
.toStr(tmp
,sizeof(tmp
));
425 case LFT_CLIENT_LOCAL_TOS
:
426 if (al
->tcpClient
!= NULL
) {
427 snprintf(tmp
, sizeof(tmp
), "0x%x", (uint32_t)al
->tcpClient
->tos
);
432 case LFT_CLIENT_LOCAL_NFMARK
:
433 if (al
->tcpClient
!= NULL
) {
434 snprintf(tmp
, sizeof(tmp
), "0x%x", al
->tcpClient
->nfmark
);
439 case LFT_LOCAL_LISTENING_PORT
:
440 if (al
->cache
.port
!= NULL
) {
441 outint
= al
->cache
.port
->s
.port();
446 case LFT_CLIENT_LOCAL_PORT
:
447 if (al
->tcpClient
!= NULL
) {
448 outint
= al
->tcpClient
->local
.port();
453 case LFT_SERVER_LOCAL_IP_OLD_27
:
454 case LFT_SERVER_LOCAL_IP
:
455 if (al
->hier
.tcpServer
!= NULL
) {
456 out
= al
->hier
.tcpServer
->local
.toStr(tmp
,sizeof(tmp
));
460 case LFT_SERVER_LOCAL_PORT
:
461 if (al
->hier
.tcpServer
!= NULL
) {
462 outint
= al
->hier
.tcpServer
->local
.port();
468 case LFT_SERVER_LOCAL_TOS
:
469 if (al
->hier
.tcpServer
!= NULL
) {
470 snprintf(tmp
, sizeof(tmp
), "0x%x", (uint32_t)al
->hier
.tcpServer
->tos
);
475 case LFT_SERVER_LOCAL_NFMARK
:
476 if (al
->hier
.tcpServer
!= NULL
) {
477 snprintf(tmp
, sizeof(tmp
), "0x%x", al
->hier
.tcpServer
->nfmark
);
482 case LFT_TIME_SECONDS_SINCE_EPOCH
:
483 // some platforms store time in 32-bit, some 64-bit...
484 outoff
= static_cast<int64_t>(current_time
.tv_sec
);
488 case LFT_TIME_SUBSECOND
:
489 outint
= current_time
.tv_usec
/ fmt
->divisor
;
493 case LFT_TIME_LOCALTIME
:
499 spec
= fmt
->data
.string
;
501 if (fmt
->type
== LFT_TIME_LOCALTIME
) {
503 spec
= "%d/%b/%Y:%H:%M:%S %z";
504 t
= localtime(&squid_curtime
);
507 spec
= "%d/%b/%Y:%H:%M:%S";
509 t
= gmtime(&squid_curtime
);
512 strftime(tmp
, sizeof(tmp
), spec
, t
);
520 outtv
= al
->cache
.start_time
;
524 case LFT_TIME_TO_HANDLE_REQUEST
:
525 outtv
= al
->cache
.trTime
;
529 case LFT_PEER_RESPONSE_TIME
:
530 if (al
->hier
.peer_response_time
.tv_sec
== -1) {
533 outtv
= al
->hier
.peer_response_time
;
538 case LFT_TOTAL_SERVER_SIDE_RESPONSE_TIME
: {
539 timeval total_response_time
;
540 al
->hier
.totalResponseTime(total_response_time
);
541 if (total_response_time
.tv_sec
== -1) {
544 outtv
= total_response_time
;
550 case LFT_DNS_WAIT_TIME
:
551 if (al
->request
&& al
->request
->dnsWait
>= 0) {
552 // TODO: microsecond precision for dns wait time.
553 // Convert miliseconds to timeval struct:
554 outtv
.tv_sec
= al
->request
->dnsWait
/ 1000;
555 outtv
.tv_usec
= (al
->request
->dnsWait
% 1000) * 1000;
560 case LFT_REQUEST_HEADER
:
563 sb
= al
->request
->header
.getByName(fmt
->data
.header
.header
);
565 out
= sb
.termedBuf();
571 case LFT_ADAPTED_REQUEST_HEADER
:
573 if (al
->adapted_request
)
574 sb
= al
->adapted_request
->header
.getByName(fmt
->data
.header
.header
);
576 out
= sb
.termedBuf();
582 case LFT_REPLY_HEADER
:
584 sb
= al
->reply
->header
.getByName(fmt
->data
.header
.header
);
586 out
= sb
.termedBuf();
593 case LFT_ADAPTATION_SUM_XACT_TIMES
:
595 Adaptation::History::Pointer ah
= al
->request
->adaptHistory();
597 ah
->sumLogString(fmt
->data
.string
, sb
);
598 out
= sb
.termedBuf();
602 case LFT_ADAPTATION_ALL_XACT_TIMES
:
604 Adaptation::History::Pointer ah
= al
->request
->adaptHistory();
606 ah
->allLogString(fmt
->data
.string
, sb
);
607 out
= sb
.termedBuf();
611 case LFT_ADAPTATION_LAST_HEADER
:
613 const Adaptation::History::Pointer ah
= al
->request
->adaptHistory();
614 if (ah
!= NULL
) // XXX: add adapt::<all_h but use lastMeta here
615 sb
= ah
->allMeta
.getByName(fmt
->data
.header
.header
);
618 // XXX: here and elsewhere: move such code inside the if guard
619 out
= sb
.termedBuf();
625 case LFT_ADAPTATION_LAST_HEADER_ELEM
:
627 const Adaptation::History::Pointer ah
= al
->request
->adaptHistory();
628 if (ah
!= NULL
) // XXX: add adapt::<all_h but use lastMeta here
629 sb
= ah
->allMeta
.getByNameListMember(fmt
->data
.header
.header
, fmt
->data
.header
.element
, fmt
->data
.header
.separator
);
632 out
= sb
.termedBuf();
638 case LFT_ADAPTATION_LAST_ALL_HEADERS
:
639 out
= al
->adapt
.last_meta
;
649 out
= al
->icap
.hostAddr
.toStr(tmp
,1024);
652 case LFT_ICAP_SERV_NAME
:
653 out
= al
->icap
.serviceName
.termedBuf();
656 case LFT_ICAP_REQUEST_URI
:
657 out
= al
->icap
.reqUri
.termedBuf();
660 case LFT_ICAP_REQUEST_METHOD
:
661 out
= Adaptation::Icap::ICAP::methodStr(al
->icap
.reqMethod
);
664 case LFT_ICAP_BYTES_SENT
:
665 outoff
= al
->icap
.bytesSent
;
669 case LFT_ICAP_BYTES_READ
:
670 outoff
= al
->icap
.bytesRead
;
674 case LFT_ICAP_BODY_BYTES_READ
:
675 if (al
->icap
.bodyBytesRead
>= 0) {
676 outoff
= al
->icap
.bodyBytesRead
;
679 // else if icap.bodyBytesRead < 0, we do not have any http data,
680 // so just print a "-" (204 responses etc)
683 case LFT_ICAP_REQ_HEADER
:
684 if (NULL
!= al
->icap
.request
) {
685 sb
= al
->icap
.request
->header
.getByName(fmt
->data
.header
.header
);
686 out
= sb
.termedBuf();
691 case LFT_ICAP_REQ_HEADER_ELEM
:
692 if (al
->icap
.request
)
693 sb
= al
->icap
.request
->header
.getByNameListMember(fmt
->data
.header
.header
, fmt
->data
.header
.element
, fmt
->data
.header
.separator
);
695 out
= sb
.termedBuf();
701 case LFT_ICAP_REQ_ALL_HEADERS
:
702 if (al
->icap
.request
) {
703 HttpHeaderPos pos
= HttpHeaderInitPos
;
704 while (const HttpHeaderEntry
*e
= al
->icap
.request
->header
.getEntry(&pos
)) {
710 out
= sb
.termedBuf();
715 case LFT_ICAP_REP_HEADER
:
716 if (NULL
!= al
->icap
.reply
) {
717 sb
= al
->icap
.reply
->header
.getByName(fmt
->data
.header
.header
);
718 out
= sb
.termedBuf();
723 case LFT_ICAP_REP_HEADER_ELEM
:
724 if (NULL
!= al
->icap
.reply
)
725 sb
= al
->icap
.reply
->header
.getByNameListMember(fmt
->data
.header
.header
, fmt
->data
.header
.element
, fmt
->data
.header
.separator
);
727 out
= sb
.termedBuf();
733 case LFT_ICAP_REP_ALL_HEADERS
:
734 if (al
->icap
.reply
) {
735 HttpHeaderPos pos
= HttpHeaderInitPos
;
736 while (const HttpHeaderEntry
*e
= al
->icap
.reply
->header
.getEntry(&pos
)) {
742 out
= sb
.termedBuf();
747 case LFT_ICAP_TR_RESPONSE_TIME
:
748 outtv
= al
->icap
.trTime
;
752 case LFT_ICAP_IO_TIME
:
753 outtv
= al
->icap
.ioTime
;
757 case LFT_ICAP_STATUS_CODE
:
758 outint
= al
->icap
.resStatus
;
762 case LFT_ICAP_OUTCOME
:
763 out
= al
->icap
.outcome
;
766 case LFT_ICAP_TOTAL_TIME
:
767 outtv
= al
->icap
.processingTime
;
771 case LFT_REQUEST_HEADER_ELEM
:
773 sb
= al
->request
->header
.getByNameListMember(fmt
->data
.header
.header
, fmt
->data
.header
.element
, fmt
->data
.header
.separator
);
775 out
= sb
.termedBuf();
781 case LFT_ADAPTED_REQUEST_HEADER_ELEM
:
782 if (al
->adapted_request
)
783 sb
= al
->adapted_request
->header
.getByNameListMember(fmt
->data
.header
.header
, fmt
->data
.header
.element
, fmt
->data
.header
.separator
);
785 out
= sb
.termedBuf();
791 case LFT_REPLY_HEADER_ELEM
:
793 sb
= al
->reply
->header
.getByNameListMember(fmt
->data
.header
.header
, fmt
->data
.header
.element
, fmt
->data
.header
.separator
);
795 out
= sb
.termedBuf();
801 case LFT_REQUEST_ALL_HEADERS
:
802 out
= al
->headers
.request
;
808 case LFT_ADAPTED_REQUEST_ALL_HEADERS
:
809 out
= al
->headers
.adapted_request
;
815 case LFT_REPLY_ALL_HEADERS
:
816 out
= al
->headers
.reply
;
824 if (al
->request
&& al
->request
->auth_user_request
!= NULL
)
825 out
= strOrNull(al
->request
->auth_user_request
->username());
828 out
= strOrNull(al
->cache
.extuser
);
831 out
= strOrNull(al
->cache
.ssluser
);
834 out
= strOrNull(al
->cache
.rfc931
);
839 if (al
->request
&& al
->request
->auth_user_request
!= NULL
)
840 out
= strOrNull(al
->request
->auth_user_request
->username());
845 out
= strOrNull(al
->cache
.rfc931
);
848 case LFT_USER_EXTERNAL
:
849 out
= strOrNull(al
->cache
.extuser
);
852 /* case LFT_USER_REALM: */
853 /* case LFT_USER_SCHEME: */
855 // the fmt->type can not be LFT_HTTP_SENT_STATUS_CODE_OLD_30
856 // but compiler complains if ommited
857 case LFT_HTTP_SENT_STATUS_CODE_OLD_30
:
858 case LFT_HTTP_SENT_STATUS_CODE
:
859 outint
= al
->http
.code
;
865 case LFT_HTTP_RECEIVED_STATUS_CODE
:
866 if (al
->hier
.peer_reply_status
== Http::scNone
) {
869 outint
= al
->hier
.peer_reply_status
;
873 /* case LFT_HTTP_STATUS:
874 * out = statusline->text;
878 case LFT_HTTP_BODY_BYTES_READ
:
879 if (al
->hier
.bodyBytesRead
>= 0) {
880 outoff
= al
->hier
.bodyBytesRead
;
883 // else if hier.bodyBytesRead < 0 we did not have any data exchange with
884 // a peer server so just print a "-" (eg requests served from cache,
885 // or internal error messages).
888 case LFT_SQUID_STATUS
:
889 out
= al
->cache
.code
.c_str();
892 case LFT_SQUID_ERROR
:
893 if (al
->request
&& al
->request
->errType
!= ERR_NONE
)
894 out
= errorPageName(al
->request
->errType
);
897 case LFT_SQUID_ERROR_DETAIL
:
899 if (al
->request
&& al
->request
->errType
== ERR_SECURE_CONNECT_FAIL
) {
900 if (! (out
= Ssl::GetErrorName(al
->request
->errDetail
)))
901 out
= sslErrorName(al
->request
->errDetail
, tmp
, sizeof(tmp
));
904 if (al
->request
&& al
->request
->errDetail
!= ERR_DETAIL_NONE
) {
905 if (al
->request
->errDetail
> ERR_DETAIL_START
&&
906 al
->request
->errDetail
< ERR_DETAIL_MAX
)
907 out
= errorDetailName(al
->request
->errDetail
);
909 if (al
->request
->errDetail
>= ERR_DETAIL_EXCEPTION_START
)
910 snprintf(tmp
, sizeof(tmp
), "%s=0x%X",
911 errorDetailName(al
->request
->errDetail
), (uint32_t) al
->request
->errDetail
);
913 snprintf(tmp
, sizeof(tmp
), "%s=%d",
914 errorDetailName(al
->request
->errDetail
), al
->request
->errDetail
);
920 case LFT_SQUID_HIERARCHY
:
921 if (al
->hier
.ping
.timedout
)
922 mb
.append("TIMEOUT_", 8);
924 out
= hier_code_str
[al
->hier
.code
];
929 out
= al
->http
.content_type
;
933 case LFT_CLIENT_REQ_METHOD
:
935 const SBuf
&s
= al
->request
->method
.image();
936 sb
.append(s
.rawContent(), s
.length());
937 out
= sb
.termedBuf();
942 case LFT_CLIENT_REQ_URI
:
943 // original client URI
945 const SBuf
&s
= al
->request
->effectiveRequestUri();
946 sb
.append(s
.rawContent(), s
.length());
947 out
= sb
.termedBuf();
952 case LFT_CLIENT_REQ_URLSCHEME
:
954 out
= al
->request
->url
.getScheme().c_str();
959 case LFT_CLIENT_REQ_URLDOMAIN
:
961 out
= al
->request
->url
.host();
966 case LFT_CLIENT_REQ_URLPORT
:
968 outint
= al
->request
->url
.port();
973 case LFT_REQUEST_URLPATH_OLD_31
:
974 case LFT_CLIENT_REQ_URLPATH
:
976 SBuf s
= al
->request
->url
.path();
982 case LFT_CLIENT_REQ_VERSION
:
984 snprintf(tmp
, sizeof(tmp
), "%d.%d", (int) al
->request
->http_ver
.major
, (int) al
->request
->http_ver
.minor
);
989 case LFT_REQUEST_METHOD
:
990 if (al
->_private
.method_str
) // ICP, HTCP method code
991 out
= al
->_private
.method_str
;
993 const SBuf
&s
= al
->http
.method
.image();
994 sb
.append(s
.rawContent(), s
.length());
995 out
= sb
.termedBuf();
1000 case LFT_REQUEST_URI
:
1004 case LFT_REQUEST_VERSION_OLD_2X
:
1005 case LFT_REQUEST_VERSION
:
1006 snprintf(tmp
, sizeof(tmp
), "%d.%d", (int) al
->http
.version
.major
, (int) al
->http
.version
.minor
);
1010 case LFT_SERVER_REQ_METHOD
:
1011 if (al
->adapted_request
) {
1012 const SBuf
&s
= al
->adapted_request
->method
.image();
1013 sb
.append(s
.rawContent(), s
.length());
1014 out
= sb
.termedBuf();
1019 case LFT_SERVER_REQ_URI
:
1020 // adapted request URI sent to server/peer
1021 if (al
->adapted_request
) {
1022 const SBuf
&s
= al
->adapted_request
->effectiveRequestUri();
1023 sb
.append(s
.rawContent(), s
.length());
1024 out
= sb
.termedBuf();
1029 case LFT_SERVER_REQ_URLSCHEME
:
1030 if (al
->adapted_request
) {
1031 out
= al
->adapted_request
->url
.getScheme().c_str();
1036 case LFT_SERVER_REQ_URLDOMAIN
:
1037 if (al
->adapted_request
) {
1038 out
= al
->adapted_request
->url
.host();
1043 case LFT_SERVER_REQ_URLPORT
:
1044 if (al
->adapted_request
) {
1045 outint
= al
->adapted_request
->url
.port();
1050 case LFT_SERVER_REQ_URLPATH
:
1051 if (al
->adapted_request
) {
1052 SBuf s
= al
->adapted_request
->url
.path();
1058 case LFT_SERVER_REQ_VERSION
:
1059 if (al
->adapted_request
) {
1060 snprintf(tmp
, sizeof(tmp
), "%d.%d",
1061 (int) al
->adapted_request
->http_ver
.major
,
1062 (int) al
->adapted_request
->http_ver
.minor
);
1067 case LFT_CLIENT_REQUEST_SIZE_TOTAL
:
1068 outoff
= al
->http
.clientRequestSz
.messageTotal();
1072 case LFT_CLIENT_REQUEST_SIZE_HEADERS
:
1073 outoff
= al
->http
.clientRequestSz
.header
;
1077 /*case LFT_REQUEST_SIZE_BODY: */
1078 /*case LFT_REQUEST_SIZE_BODY_NO_TE: */
1080 case LFT_ADAPTED_REPLY_SIZE_TOTAL
:
1081 outoff
= al
->http
.clientReplySz
.messageTotal();
1085 case LFT_REPLY_HIGHOFFSET
:
1086 outoff
= al
->cache
.highOffset
;
1092 case LFT_REPLY_OBJECTSIZE
:
1093 outoff
= al
->cache
.objectSize
;
1099 case LFT_ADAPTED_REPLY_SIZE_HEADERS
:
1100 outint
= al
->http
.clientReplySz
.header
;
1104 /*case LFT_REPLY_SIZE_BODY: */
1105 /*case LFT_REPLY_SIZE_BODY_NO_TE: */
1107 case LFT_CLIENT_IO_SIZE_TOTAL
:
1108 outint
= al
->http
.clientRequestSz
.messageTotal() + al
->http
.clientReplySz
.messageTotal();
1111 /*case LFT_SERVER_IO_SIZE_TOTAL: */
1115 out
= al
->request
->tag
.termedBuf();
1123 out
= al
->request
->extacl_log
.termedBuf();
1129 case LFT_SEQUENCE_NUMBER
:
1130 outoff
= logSequenceNumber
;
1135 case LFT_SSL_BUMP_MODE
: {
1136 const Ssl::BumpMode mode
= static_cast<Ssl::BumpMode
>(al
->ssl
.bumpMode
);
1137 // for Ssl::bumpEnd, Ssl::bumpMode() returns NULL and we log '-'
1138 out
= Ssl::bumpMode(mode
);
1142 case LFT_SSL_USER_CERT_SUBJECT
:
1143 if (X509
*cert
= al
->cache
.sslClientCert
.get()) {
1144 if (X509_NAME
*subject
= X509_get_subject_name(cert
)) {
1145 X509_NAME_oneline(subject
, tmp
, sizeof(tmp
));
1151 case LFT_SSL_USER_CERT_ISSUER
:
1152 if (X509
*cert
= al
->cache
.sslClientCert
.get()) {
1153 if (X509_NAME
*issuer
= X509_get_issuer_name(cert
)) {
1154 X509_NAME_oneline(issuer
, tmp
, sizeof(tmp
));
1159 case LFT_SSL_CLIENT_SNI
:
1160 if (al
->request
&& al
->request
->clientConnectionManager
.valid()) {
1161 if (Ssl::ServerBump
* srvBump
= al
->request
->clientConnectionManager
->serverBump()) {
1162 if (!srvBump
->clientSni
.isEmpty())
1163 out
= srvBump
->clientSni
.c_str();
1168 case LFT_SSL_SERVER_CERT_ERRORS
:
1169 if (al
->request
&& al
->request
->clientConnectionManager
.valid()) {
1170 if (Ssl::ServerBump
* srvBump
= al
->request
->clientConnectionManager
->serverBump()) {
1171 const char *separator
= fmt
->data
.string
? fmt
->data
.string
: ":";
1172 for (Ssl::CertErrors
*sslError
= srvBump
->sslErrors
; sslError
!= NULL
; sslError
= sslError
->next
) {
1174 sb
.append(separator
);
1175 if (const char *errorName
= Ssl::GetErrorName(sslError
->element
.code
))
1176 sb
.append(errorName
);
1178 sb
.append(sslErrorName(sslError
->element
.code
, tmp
, sizeof(tmp
)));
1181 out
= sb
.termedBuf();
1186 case LFT_SSL_SERVER_CERT_ISSUER
:
1187 case LFT_SSL_SERVER_CERT_SUBJECT
:
1192 case LFT_REQUEST_URLGROUP_OLD_2X
:
1193 assert(LFT_REQUEST_URLGROUP_OLD_2X
== 0); // should never happen.
1196 tmp
[0] = fmt
->data
.header
.separator
;
1198 if (fmt
->data
.header
.header
&& *fmt
->data
.header
.header
) {
1199 const char *separator
= tmp
;
1201 Adaptation::History::Pointer ah
= al
->request
? al
->request
->adaptHistory() : Adaptation::History::Pointer();
1202 if (ah
!= NULL
&& ah
->metaHeaders
!= NULL
) {
1203 if (const char *meta
= ah
->metaHeaders
->find(fmt
->data
.header
.header
, separator
))
1207 if (al
->notes
!= NULL
) {
1208 if (const char *note
= al
->notes
->find(fmt
->data
.header
.header
, separator
)) {
1210 sb
.append(separator
);
1214 out
= sb
.termedBuf();
1217 // if no argument given use default "\r\n" as notes separator
1218 const char *separator
= fmt
->data
.string
? tmp
: "\r\n";
1220 Adaptation::History::Pointer ah
= al
->request
? al
->request
->adaptHistory() : Adaptation::History::Pointer();
1221 if (ah
!= NULL
&& ah
->metaHeaders
!= NULL
&& !ah
->metaHeaders
->empty())
1222 sb
.append(ah
->metaHeaders
->toString(separator
));
1224 if (al
->notes
!= NULL
&& !al
->notes
->empty())
1225 sb
.append(al
->notes
->toString(separator
));
1227 out
= sb
.termedBuf();
1232 case LFT_CREDENTIALS
:
1234 if (al
->request
&& al
->request
->auth_user_request
!= NULL
)
1235 out
= strOrNull(al
->request
->auth_user_request
->credentialsStr());
1244 // XXX: external_acl_type format tokens which are not output by logformat.
1245 // They are listed here because the switch requires
1246 // every ByteCode_t to be explicitly enumerated.
1247 // But do not output due to lack of access to the values.
1248 case LFT_EXT_ACL_USER_CERT_RAW
:
1249 case LFT_EXT_ACL_USER_CERTCHAIN_RAW
:
1250 case LFT_EXT_ACL_USER_CERT
:
1251 case LFT_EXT_ACL_USER_CA_CERT
:
1252 case LFT_EXT_ACL_CLIENT_EUI48
:
1253 case LFT_EXT_ACL_CLIENT_EUI64
:
1254 case LFT_EXT_ACL_NAME
:
1255 case LFT_EXT_ACL_DATA
:
1260 snprintf(tmp
, sizeof(tmp
), "%0*" PRId64
, fmt
->zero
&& fmt
->widthMin
>= 0 ? fmt
->widthMin
: 0, outoff
);
1264 snprintf(tmp
, sizeof(tmp
), "%0*ld", fmt
->zero
&& fmt
->widthMin
>= 0 ? fmt
->widthMin
: 0, outint
);
1266 } else if (doMsec
) {
1267 if (fmt
->widthMax
< 0) {
1268 snprintf(tmp
, sizeof(tmp
), "%0*ld", fmt
->widthMin
, tvToMsec(outtv
));
1270 int precision
= fmt
->widthMax
;
1271 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
)));
1275 int precision
= fmt
->widthMax
>=0 ? fmt
->widthMax
:3;
1276 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
));
1281 if (quote
|| fmt
->quote
!= LOG_QUOTE_NONE
) {
1282 char *newout
= NULL
;
1285 switch (fmt
->quote
) {
1287 case LOG_QUOTE_NONE
:
1288 newout
= rfc1738_escape_unescaped(out
);
1291 case LOG_QUOTE_QUOTES
: {
1292 size_t out_len
= static_cast<size_t>(strlen(out
)) * 2 + 1;
1293 if (out_len
>= sizeof(tmp
)) {
1294 newout
= (char *)xmalloc(out_len
);
1298 log_quoted_string(out
, newout
);
1302 case LOG_QUOTE_MIMEBLOB
:
1303 newout
= QuoteMimeBlob(out
);
1308 newout
= rfc1738_escape(out
);
1325 // enforce width limits if configured
1326 const bool haveMaxWidth
= fmt
->widthMax
>=0 && !doint
&& !dooff
&& !doMsec
&& !doSec
;
1327 if (haveMaxWidth
|| fmt
->widthMin
) {
1328 const int minWidth
= fmt
->widthMin
>= 0 ?
1330 const int maxWidth
= haveMaxWidth
?
1331 fmt
->widthMax
: strlen(out
);
1334 mb
.appendf("%-*.*s", minWidth
, maxWidth
, out
);
1336 mb
.appendf("%*.*s", minWidth
, maxWidth
, out
);
1338 mb
.append(out
, strlen(out
));