]> git.ipfire.org Git - thirdparty/squid.git/blame - src/format/Format.cc
Minor edits after audit
[thirdparty/squid.git] / src / format / Format.cc
CommitLineData
bbc27441 1/*
bde978a6 2 * Copyright (C) 1996-2015 The Squid Software Foundation and contributors
bbc27441
AJ
3 *
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.
7 */
8
f7f3304a 9#include "squid.h"
38e16f92 10#include "AccessLogEntry.h"
582c2af2 11#include "client_side.h"
38e16f92
AJ
12#include "comm/Connection.h"
13#include "err_detail_type.h"
14#include "errorpage.h"
f4698e0b 15#include "fde.h"
38e16f92
AJ
16#include "format/Format.h"
17#include "format/Quoting.h"
31971e6a 18#include "format/Token.h"
95e6d864 19#include "fqdncache.h"
38e16f92
AJ
20#include "HttpRequest.h"
21#include "MemBuf.h"
22#include "rfc1738.h"
23#include "SquidTime.h"
24#include "Store.h"
95d78f10 25#include "tools.h"
b1bd952a 26#include "URL.h"
cb4f4424 27#if USE_OPENSSL
2f3e52b5 28#include "ssl/ErrorDetail.h"
cedca6e7 29#include "ssl/ServerBump.h"
2f3e52b5
CT
30#endif
31
bd85ea1f
AJ
32/// Convert a string to NULL pointer if it is ""
33#define strOrNull(s) ((s)==NULL||(s)[0]=='\0'?NULL:(s))
38e16f92
AJ
34
35Format::Format::Format(const char *n) :
f53969cc
SM
36 format(NULL),
37 next(NULL)
38e16f92
AJ
38{
39 name = xstrdup(n);
40}
41
42Format::Format::~Format()
43{
44 // erase the list without consuming stack space
45 while (next) {
46 // unlink the next entry for deletion
47 Format *temp = next;
48 next = temp->next;
49 temp->next = NULL;
50 delete temp;
51 }
52
53 // remove locals
54 xfree(name);
55 delete format;
56}
57
58bool
f4698e0b 59Format::Format::parse(const char *def)
38e16f92 60{
f4698e0b 61 const char *cur, *eos;
38e16f92
AJ
62 Token *new_lt, *last_lt;
63 enum Quoting quote = LOG_QUOTE_NONE;
64
65 debugs(46, 2, HERE << "got definition '" << def << "'");
66
67 if (format) {
68 debugs(46, DBG_IMPORTANT, "WARNING: existing format for '" << name << " " << def << "'");
69 return false;
70 }
71
72 /* very inefficent parser, but who cares, this needs to be simple */
73 /* First off, let's tokenize, we'll optimize in a second pass.
74 * A token can either be a %-prefixed sequence (usually a dynamic
75 * token but it can be an escaped sequence), or a string. */
76 cur = def;
77 eos = def + strlen(def);
78 format = new_lt = last_lt = new Token;
79 cur += new_lt->parse(cur, &quote);
80
81 while (cur < eos) {
82 new_lt = new Token;
83 last_lt->next = new_lt;
84 last_lt = new_lt;
85 cur += new_lt->parse(cur, &quote);
86 }
87
88 return true;
89}
90
91void
4e56d7f6 92Format::Format::dump(StoreEntry * entry, const char *directiveName, bool eol) const
38e16f92
AJ
93{
94 debugs(46, 4, HERE);
95
96 // loop rather than recursing to conserve stack space.
4e56d7f6 97 for (const Format *fmt = this; fmt; fmt = fmt->next) {
5f621cd0 98 debugs(46, 3, HERE << "Dumping format definition for " << fmt->name);
4e56d7f6
AJ
99 if (directiveName)
100 storeAppendPrintf(entry, "%s %s ", directiveName, fmt->name);
38e16f92 101
5f621cd0 102 for (Token *t = fmt->format; t; t = t->next) {
38e16f92
AJ
103 if (t->type == LFT_STRING)
104 storeAppendPrintf(entry, "%s", t->data.string);
105 else {
106 char argbuf[256];
107 char *arg = NULL;
108 ByteCode_t type = t->type;
109
110 switch (type) {
f53969cc 111 /* special cases */
38e16f92
AJ
112
113 case LFT_STRING:
114 break;
115#if USE_ADAPTATION
116 case LFT_ADAPTATION_LAST_HEADER_ELEM:
117#endif
118#if ICAP_CLIENT
119 case LFT_ICAP_REQ_HEADER_ELEM:
120 case LFT_ICAP_REP_HEADER_ELEM:
121#endif
122 case LFT_REQUEST_HEADER_ELEM:
123 case LFT_ADAPTED_REQUEST_HEADER_ELEM:
124 case LFT_REPLY_HEADER_ELEM:
125
126 if (t->data.header.separator != ',')
127 snprintf(argbuf, sizeof(argbuf), "%s:%c%s", t->data.header.header, t->data.header.separator, t->data.header.element);
128 else
129 snprintf(argbuf, sizeof(argbuf), "%s:%s", t->data.header.header, t->data.header.element);
130
131 arg = argbuf;
132
133 switch (type) {
134 case LFT_REQUEST_HEADER_ELEM:
135 type = LFT_REQUEST_HEADER_ELEM; // XXX: remove _ELEM?
136 break;
137 case LFT_ADAPTED_REQUEST_HEADER_ELEM:
138 type = LFT_ADAPTED_REQUEST_HEADER_ELEM; // XXX: remove _ELEM?
139 break;
140 case LFT_REPLY_HEADER_ELEM:
141 type = LFT_REPLY_HEADER_ELEM; // XXX: remove _ELEM?
142 break;
143#if USE_ADAPTATION
144 case LFT_ADAPTATION_LAST_HEADER_ELEM:
145 type = LFT_ADAPTATION_LAST_HEADER;
146 break;
147#endif
148#if ICAP_CLIENT
149 case LFT_ICAP_REQ_HEADER_ELEM:
150 type = LFT_ICAP_REQ_HEADER;
151 break;
152 case LFT_ICAP_REP_HEADER_ELEM:
153 type = LFT_ICAP_REP_HEADER;
154 break;
155#endif
156 default:
157 break;
158 }
159
160 break;
161
162 case LFT_REQUEST_ALL_HEADERS:
163 case LFT_ADAPTED_REQUEST_ALL_HEADERS:
164 case LFT_REPLY_ALL_HEADERS:
165
166#if USE_ADAPTATION
167 case LFT_ADAPTATION_LAST_ALL_HEADERS:
168#endif
169#if ICAP_CLIENT
170 case LFT_ICAP_REQ_ALL_HEADERS:
171 case LFT_ICAP_REP_ALL_HEADERS:
172#endif
173
174 switch (type) {
175 case LFT_REQUEST_ALL_HEADERS:
176 type = LFT_REQUEST_HEADER;
177 break;
178 case LFT_ADAPTED_REQUEST_ALL_HEADERS:
179 type = LFT_ADAPTED_REQUEST_HEADER;
180 break;
181 case LFT_REPLY_ALL_HEADERS:
182 type = LFT_REPLY_HEADER;
183 break;
184#if USE_ADAPTATION
185 case LFT_ADAPTATION_LAST_ALL_HEADERS:
186 type = LFT_ADAPTATION_LAST_HEADER;
187 break;
188#endif
189#if ICAP_CLIENT
190 case LFT_ICAP_REQ_ALL_HEADERS:
191 type = LFT_ICAP_REQ_HEADER;
192 break;
193 case LFT_ICAP_REP_ALL_HEADERS:
194 type = LFT_ICAP_REP_HEADER;
195 break;
196#endif
197 default:
198 break;
199 }
200
201 break;
202
203 default:
204 if (t->data.string)
205 arg = t->data.string;
206
207 break;
208 }
209
210 entry->append("%", 1);
211
212 switch (t->quote) {
213
214 case LOG_QUOTE_QUOTES:
215 entry->append("\"", 1);
216 break;
217
218 case LOG_QUOTE_MIMEBLOB:
219 entry->append("[", 1);
220 break;
221
222 case LOG_QUOTE_URL:
223 entry->append("#", 1);
224 break;
225
226 case LOG_QUOTE_RAW:
227 entry->append("'", 1);
228 break;
229
95d78f10
AJ
230 case LOG_QUOTE_SHELL:
231 entry->append("/", 1);
232 break;
233
38e16f92
AJ
234 case LOG_QUOTE_NONE:
235 break;
236 }
237
238 if (t->left)
239 entry->append("-", 1);
240
241 if (t->zero)
242 entry->append("0", 1);
243
8846a2b4
CT
244 if (t->widthMin >= 0)
245 storeAppendPrintf(entry, "%d", t->widthMin);
38e16f92 246
8846a2b4
CT
247 if (t->widthMax >= 0)
248 storeAppendPrintf(entry, ".%d", t->widthMax);
38e16f92
AJ
249
250 if (arg)
251 storeAppendPrintf(entry, "{%s}", arg);
252
aa99e35e 253 storeAppendPrintf(entry, "%s", t->label);
38e16f92
AJ
254
255 if (t->space)
256 entry->append(" ", 1);
257 }
258 }
259
4e56d7f6
AJ
260 if (eol)
261 entry->append("\n", 1);
38e16f92
AJ
262 }
263
264}
265
266static void
267log_quoted_string(const char *str, char *out)
268{
269 char *p = out;
270
271 while (*str) {
272 int l = strcspn(str, "\"\\\r\n\t");
273 memcpy(p, str, l);
274 str += l;
275 p += l;
276
277 switch (*str) {
278
279 case '\0':
280 break;
281
282 case '\r':
a38ec4b1
FC
283 *p = '\\';
284 ++p;
285 *p = 'r';
286 ++p;
cb4185f1 287 ++str;
38e16f92
AJ
288 break;
289
290 case '\n':
a38ec4b1
FC
291 *p = '\\';
292 ++p;
293 *p = 'n';
294 ++p;
cb4185f1 295 ++str;
38e16f92
AJ
296 break;
297
298 case '\t':
a38ec4b1
FC
299 *p = '\\';
300 ++p;
301 *p = 't';
302 ++p;
cb4185f1 303 ++str;
38e16f92
AJ
304 break;
305
306 default:
a38ec4b1
FC
307 *p = '\\';
308 ++p;
309 *p = *str;
310 ++p;
cb4185f1 311 ++str;
38e16f92
AJ
312 break;
313 }
314 }
315
cb4185f1 316 *p = '\0';
38e16f92
AJ
317}
318
319void
f4698e0b 320Format::Format::assemble(MemBuf &mb, const AccessLogEntry::Pointer &al, int logSequenceNumber) const
38e16f92
AJ
321{
322 char tmp[1024];
323 String sb;
324
f53969cc 325 for (Token *fmt = format; fmt != NULL; fmt = fmt->next) { /* for each token */
38e16f92
AJ
326 const char *out = NULL;
327 int quote = 0;
328 long int outint = 0;
329 int doint = 0;
330 int dofree = 0;
331 int64_t outoff = 0;
332 int dooff = 0;
01bd87d8
CT
333 struct timeval outtv = {0, 0};
334 int doMsec = 0;
335 int doSec = 0;
38e16f92
AJ
336
337 switch (fmt->type) {
338
339 case LFT_NONE:
340 out = "";
341 break;
342
343 case LFT_STRING:
344 out = fmt->data.string;
345 break;
346
347 case LFT_CLIENT_IP_ADDRESS:
d4204018
AJ
348 al->getLogClientIp(tmp, sizeof(tmp));
349 out = tmp;
38e16f92
AJ
350 break;
351
352 case LFT_CLIENT_FQDN:
4dd643d5 353 if (al->cache.caddr.isAnyAddr()) // e.g., ICAP OPTIONS lack client
38e16f92
AJ
354 out = "-";
355 else
356 out = fqdncache_gethostbyaddr(al->cache.caddr, FQDN_LOOKUP_IF_MISS);
357 if (!out) {
4dd643d5 358 out = al->cache.caddr.toStr(tmp,1024);
38e16f92
AJ
359 }
360
361 break;
362
363 case LFT_CLIENT_PORT:
364 if (al->request) {
4dd643d5 365 outint = al->request->client_addr.port();
38e16f92
AJ
366 doint = 1;
367 }
368 break;
369
38e16f92 370 case LFT_CLIENT_EUI:
8652f8e7 371#if USE_SQUID_EUI
38e16f92
AJ
372 // TODO make the ACL checklist have a direct link to any TCP details.
373 if (al->request && al->request->clientConnectionManager.valid() && al->request->clientConnectionManager->clientConnection != NULL) {
4dd643d5 374 if (al->request->clientConnectionManager->clientConnection->remote.isIPv4())
38e16f92
AJ
375 al->request->clientConnectionManager->clientConnection->remoteEui48.encode(tmp, 1024);
376 else
377 al->request->clientConnectionManager->clientConnection->remoteEui64.encode(tmp, 1024);
378 out = tmp;
379 }
38e16f92 380#endif
8652f8e7 381 break;
38e16f92 382
4e56d7f6 383 case LFT_EXT_ACL_CLIENT_EUI48:
38d7fa02 384#if USE_SQUID_EUI
4e56d7f6
AJ
385 if (al->request && al->request->clientConnectionManager.valid() &&
386 al->request->clientConnectionManager->clientConnection != NULL &&
387 al->request->clientConnectionManager->clientConnection->remote.isIPv4()) {
388 al->request->clientConnectionManager->clientConnection->remoteEui48.encode(tmp, 1024);
389 out = tmp;
390 }
38d7fa02 391#endif
4e56d7f6
AJ
392 break;
393
394 case LFT_EXT_ACL_CLIENT_EUI64:
38d7fa02 395#if USE_SQUID_EUI
4e56d7f6
AJ
396 if (al->request && al->request->clientConnectionManager.valid() &&
397 al->request->clientConnectionManager->clientConnection != NULL &&
398 !al->request->clientConnectionManager->clientConnection->remote.isIPv4()) {
399 al->request->clientConnectionManager->clientConnection->remoteEui64.encode(tmp, 1024);
400 out = tmp;
401 }
4e56d7f6 402#endif
38d7fa02 403 break;
4e56d7f6 404
8652f8e7
AJ
405 case LFT_SERVER_IP_ADDRESS:
406 if (al->hier.tcpServer != NULL) {
4dd643d5 407 out = al->hier.tcpServer->remote.toStr(tmp,sizeof(tmp));
8652f8e7
AJ
408 }
409 break;
38e16f92 410
8652f8e7 411 case LFT_SERVER_FQDN_OR_PEER_NAME:
38e16f92 412 out = al->hier.host;
38e16f92
AJ
413 break;
414
8652f8e7
AJ
415 case LFT_SERVER_PORT:
416 if (al->hier.tcpServer != NULL) {
4dd643d5 417 outint = al->hier.tcpServer->remote.port();
8652f8e7
AJ
418 doint = 1;
419 }
420 break;
38e16f92 421
28417506
CT
422 case LFT_LOCAL_LISTENING_IP: {
423 // avoid logging a dash if we have reliable info
47176c0b 424 const bool interceptedAtKnownPort = al->request ?
0d901ef4 425 (al->request->flags.interceptTproxy ||
fa720bfb 426 al->request->flags.intercepted) && al->cache.port != NULL :
47176c0b 427 false;
28417506 428 if (interceptedAtKnownPort) {
4dd643d5 429 const bool portAddressConfigured = !al->cache.port->s.isAnyAddr();
28417506 430 if (portAddressConfigured)
4dd643d5 431 out = al->cache.port->s.toStr(tmp, sizeof(tmp));
28417506 432 } else if (al->tcpClient != NULL)
4dd643d5 433 out = al->tcpClient->local.toStr(tmp, sizeof(tmp));
28417506
CT
434 }
435 break;
436
8652f8e7 437 case LFT_CLIENT_LOCAL_IP:
a14f38d0 438 if (al->tcpClient != NULL) {
4dd643d5 439 out = al->tcpClient->local.toStr(tmp,sizeof(tmp));
38e16f92 440 }
38e16f92
AJ
441 break;
442
f123f5e9
CT
443 case LFT_CLIENT_LOCAL_TOS:
444 if (al->tcpClient != NULL) {
445 snprintf(tmp, sizeof(tmp), "0x%x", (uint32_t)al->tcpClient->tos);
446 out = tmp;
447 }
448 break;
449
450 case LFT_CLIENT_LOCAL_NFMARK:
451 if (al->tcpClient != NULL) {
452 snprintf(tmp, sizeof(tmp), "0x%x", al->tcpClient->nfmark);
453 out = tmp;
454 }
455 break;
456
28417506 457 case LFT_LOCAL_LISTENING_PORT:
fa720bfb 458 if (al->cache.port != NULL) {
4dd643d5 459 outint = al->cache.port->s.port();
28417506
CT
460 doint = 1;
461 }
462 break;
463
8652f8e7 464 case LFT_CLIENT_LOCAL_PORT:
a14f38d0 465 if (al->tcpClient != NULL) {
4dd643d5 466 outint = al->tcpClient->local.port();
38e16f92
AJ
467 doint = 1;
468 }
38e16f92
AJ
469 break;
470
8652f8e7
AJ
471 case LFT_SERVER_LOCAL_IP_OLD_27:
472 case LFT_SERVER_LOCAL_IP:
a14f38d0 473 if (al->hier.tcpServer != NULL) {
4dd643d5 474 out = al->hier.tcpServer->local.toStr(tmp,sizeof(tmp));
38e16f92
AJ
475 }
476 break;
477
8652f8e7 478 case LFT_SERVER_LOCAL_PORT:
a14f38d0 479 if (al->hier.tcpServer != NULL) {
4dd643d5 480 outint = al->hier.tcpServer->local.port();
38e16f92
AJ
481 doint = 1;
482 }
483
484 break;
485
f123f5e9
CT
486 case LFT_SERVER_LOCAL_TOS:
487 if (al->hier.tcpServer != NULL) {
488 snprintf(tmp, sizeof(tmp), "0x%x", (uint32_t)al->hier.tcpServer->tos);
489 out = tmp;
490 }
491 break;
492
493 case LFT_SERVER_LOCAL_NFMARK:
494 if (al->hier.tcpServer != NULL) {
495 snprintf(tmp, sizeof(tmp), "0x%x", al->hier.tcpServer->nfmark);
496 out = tmp;
497 }
498 break;
499
38e16f92
AJ
500 case LFT_TIME_SECONDS_SINCE_EPOCH:
501 // some platforms store time in 32-bit, some 64-bit...
502 outoff = static_cast<int64_t>(current_time.tv_sec);
503 dooff = 1;
504 break;
505
506 case LFT_TIME_SUBSECOND:
507 outint = current_time.tv_usec / fmt->divisor;
508 doint = 1;
509 break;
510
38e16f92
AJ
511 case LFT_TIME_LOCALTIME:
512
513 case LFT_TIME_GMT: {
514 const char *spec;
515
516 struct tm *t;
b22c1ad3 517 spec = fmt->data.string;
38e16f92
AJ
518
519 if (fmt->type == LFT_TIME_LOCALTIME) {
520 if (!spec)
521 spec = "%d/%b/%Y:%H:%M:%S %z";
522 t = localtime(&squid_curtime);
523 } else {
524 if (!spec)
525 spec = "%d/%b/%Y:%H:%M:%S";
526
527 t = gmtime(&squid_curtime);
528 }
529
530 strftime(tmp, sizeof(tmp), spec, t);
531
532 out = tmp;
533 }
534
535 break;
536
01bd87d8
CT
537 case LFT_TIME_START:
538 outtv = al->cache.start_time;
539 doSec = 1;
f53969cc 540 break;
af0ded40 541
38e16f92 542 case LFT_TIME_TO_HANDLE_REQUEST:
01bd87d8
CT
543 outtv = al->cache.trTime;
544 doMsec = 1;
38e16f92
AJ
545 break;
546
547 case LFT_PEER_RESPONSE_TIME:
01bd87d8 548 if (al->hier.peer_response_time.tv_sec == -1) {
38e16f92
AJ
549 out = "-";
550 } else {
01bd87d8
CT
551 outtv = al->hier.peer_response_time;
552 doMsec = 1;
38e16f92
AJ
553 }
554 break;
555
16b70e2a 556 case LFT_TOTAL_SERVER_SIDE_RESPONSE_TIME: {
01bd87d8
CT
557 timeval total_response_time;
558 al->hier.totalResponseTime(total_response_time);
559 if (total_response_time.tv_sec == -1) {
38e16f92
AJ
560 out = "-";
561 } else {
01bd87d8
CT
562 outtv = total_response_time;
563 doMsec = 1;
38e16f92 564 }
16b70e2a
CT
565 }
566 break;
38e16f92
AJ
567
568 case LFT_DNS_WAIT_TIME:
569 if (al->request && al->request->dnsWait >= 0) {
01bd87d8
CT
570 // TODO: microsecond precision for dns wait time.
571 // Convert miliseconds to timeval struct:
572 outtv.tv_sec = al->request->dnsWait / 1000;
573 outtv.tv_usec = (al->request->dnsWait % 1000) * 1000;
574 doMsec = 1;
38e16f92
AJ
575 }
576 break;
577
578 case LFT_REQUEST_HEADER:
579
580 if (al->request)
581 sb = al->request->header.getByName(fmt->data.header.header);
582
583 out = sb.termedBuf();
584
585 quote = 1;
586
587 break;
588
589 case LFT_ADAPTED_REQUEST_HEADER:
590
38d92afa 591 if (al->adapted_request)
38e16f92
AJ
592 sb = al->adapted_request->header.getByName(fmt->data.header.header);
593
594 out = sb.termedBuf();
595
596 quote = 1;
597
598 break;
599
600 case LFT_REPLY_HEADER:
601 if (al->reply)
602 sb = al->reply->header.getByName(fmt->data.header.header);
603
604 out = sb.termedBuf();
605
606 quote = 1;
607
608 break;
609
610#if USE_ADAPTATION
31971e6a 611 case LFT_ADAPTATION_SUM_XACT_TIMES:
38e16f92
AJ
612 if (al->request) {
613 Adaptation::History::Pointer ah = al->request->adaptHistory();
614 if (ah != NULL)
615 ah->sumLogString(fmt->data.string, sb);
616 out = sb.termedBuf();
617 }
618 break;
619
31971e6a 620 case LFT_ADAPTATION_ALL_XACT_TIMES:
38e16f92
AJ
621 if (al->request) {
622 Adaptation::History::Pointer ah = al->request->adaptHistory();
623 if (ah != NULL)
624 ah->allLogString(fmt->data.string, sb);
625 out = sb.termedBuf();
626 }
627 break;
628
629 case LFT_ADAPTATION_LAST_HEADER:
630 if (al->request) {
631 const Adaptation::History::Pointer ah = al->request->adaptHistory();
632 if (ah != NULL) // XXX: add adapt::<all_h but use lastMeta here
633 sb = ah->allMeta.getByName(fmt->data.header.header);
634 }
635
636 // XXX: here and elsewhere: move such code inside the if guard
637 out = sb.termedBuf();
638
639 quote = 1;
640
641 break;
642
643 case LFT_ADAPTATION_LAST_HEADER_ELEM:
644 if (al->request) {
645 const Adaptation::History::Pointer ah = al->request->adaptHistory();
646 if (ah != NULL) // XXX: add adapt::<all_h but use lastMeta here
647 sb = ah->allMeta.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator);
648 }
649
650 out = sb.termedBuf();
651
652 quote = 1;
653
654 break;
655
656 case LFT_ADAPTATION_LAST_ALL_HEADERS:
657 out = al->adapt.last_meta;
658
659 quote = 1;
660
661 break;
662#endif
663
664#if ICAP_CLIENT
665 case LFT_ICAP_ADDR:
666 if (!out)
4dd643d5 667 out = al->icap.hostAddr.toStr(tmp,1024);
38e16f92
AJ
668 break;
669
670 case LFT_ICAP_SERV_NAME:
671 out = al->icap.serviceName.termedBuf();
672 break;
673
674 case LFT_ICAP_REQUEST_URI:
675 out = al->icap.reqUri.termedBuf();
676 break;
677
678 case LFT_ICAP_REQUEST_METHOD:
679 out = Adaptation::Icap::ICAP::methodStr(al->icap.reqMethod);
680 break;
681
682 case LFT_ICAP_BYTES_SENT:
683 outoff = al->icap.bytesSent;
684 dooff = 1;
685 break;
686
687 case LFT_ICAP_BYTES_READ:
688 outoff = al->icap.bytesRead;
689 dooff = 1;
690 break;
691
692 case LFT_ICAP_BODY_BYTES_READ:
693 if (al->icap.bodyBytesRead >= 0) {
694 outoff = al->icap.bodyBytesRead;
695 dooff = 1;
696 }
697 // else if icap.bodyBytesRead < 0, we do not have any http data,
698 // so just print a "-" (204 responses etc)
699 break;
700
701 case LFT_ICAP_REQ_HEADER:
702 if (NULL != al->icap.request) {
703 sb = al->icap.request->header.getByName(fmt->data.header.header);
704 out = sb.termedBuf();
705 quote = 1;
706 }
707 break;
708
709 case LFT_ICAP_REQ_HEADER_ELEM:
7f0ceafc 710 if (al->icap.request)
38e16f92
AJ
711 sb = al->icap.request->header.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator);
712
713 out = sb.termedBuf();
714
715 quote = 1;
716
717 break;
718
719 case LFT_ICAP_REQ_ALL_HEADERS:
720 if (al->icap.request) {
721 HttpHeaderPos pos = HttpHeaderInitPos;
722 while (const HttpHeaderEntry *e = al->icap.request->header.getEntry(&pos)) {
723 sb.append(e->name);
724 sb.append(": ");
725 sb.append(e->value);
726 sb.append("\r\n");
727 }
728 out = sb.termedBuf();
729 quote = 1;
730 }
731 break;
732
733 case LFT_ICAP_REP_HEADER:
734 if (NULL != al->icap.reply) {
735 sb = al->icap.reply->header.getByName(fmt->data.header.header);
736 out = sb.termedBuf();
737 quote = 1;
738 }
739 break;
740
741 case LFT_ICAP_REP_HEADER_ELEM:
742 if (NULL != al->icap.reply)
743 sb = al->icap.reply->header.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator);
744
745 out = sb.termedBuf();
746
747 quote = 1;
748
749 break;
750
751 case LFT_ICAP_REP_ALL_HEADERS:
752 if (al->icap.reply) {
753 HttpHeaderPos pos = HttpHeaderInitPos;
754 while (const HttpHeaderEntry *e = al->icap.reply->header.getEntry(&pos)) {
755 sb.append(e->name);
756 sb.append(": ");
757 sb.append(e->value);
758 sb.append("\r\n");
759 }
760 out = sb.termedBuf();
761 quote = 1;
762 }
763 break;
764
765 case LFT_ICAP_TR_RESPONSE_TIME:
01bd87d8
CT
766 outtv = al->icap.trTime;
767 doMsec = 1;
38e16f92
AJ
768 break;
769
770 case LFT_ICAP_IO_TIME:
01bd87d8
CT
771 outtv = al->icap.ioTime;
772 doMsec = 1;
38e16f92
AJ
773 break;
774
775 case LFT_ICAP_STATUS_CODE:
776 outint = al->icap.resStatus;
777 doint = 1;
778 break;
779
780 case LFT_ICAP_OUTCOME:
781 out = al->icap.outcome;
782 break;
783
784 case LFT_ICAP_TOTAL_TIME:
01bd87d8
CT
785 outtv = al->icap.processingTime;
786 doMsec = 1;
38e16f92
AJ
787 break;
788#endif
789 case LFT_REQUEST_HEADER_ELEM:
790 if (al->request)
791 sb = al->request->header.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator);
792
793 out = sb.termedBuf();
794
795 quote = 1;
796
797 break;
798
799 case LFT_ADAPTED_REQUEST_HEADER_ELEM:
800 if (al->adapted_request)
801 sb = al->adapted_request->header.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator);
802
803 out = sb.termedBuf();
804
805 quote = 1;
806
807 break;
808
809 case LFT_REPLY_HEADER_ELEM:
810 if (al->reply)
811 sb = al->reply->header.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator);
812
813 out = sb.termedBuf();
814
815 quote = 1;
816
817 break;
818
819 case LFT_REQUEST_ALL_HEADERS:
820 out = al->headers.request;
821
822 quote = 1;
823
824 break;
825
826 case LFT_ADAPTED_REQUEST_ALL_HEADERS:
827 out = al->headers.adapted_request;
828
829 quote = 1;
830
831 break;
832
833 case LFT_REPLY_ALL_HEADERS:
834 out = al->headers.reply;
835
836 quote = 1;
837
838 break;
839
840 case LFT_USER_NAME:
c0e8c76f
AJ
841#if USE_AUTH
842 if (al->request && al->request->auth_user_request != NULL)
843 out = strOrNull(al->request->auth_user_request->username());
844#endif
38e16f92 845 if (!out)
bd85ea1f 846 out = strOrNull(al->cache.extuser);
cb4f4424 847#if USE_OPENSSL
38e16f92 848 if (!out)
bd85ea1f 849 out = strOrNull(al->cache.ssluser);
38e16f92 850#endif
38e16f92 851 if (!out)
bd85ea1f 852 out = strOrNull(al->cache.rfc931);
38e16f92
AJ
853 break;
854
855 case LFT_USER_LOGIN:
c0e8c76f
AJ
856#if USE_AUTH
857 if (al->request && al->request->auth_user_request != NULL)
858 out = strOrNull(al->request->auth_user_request->username());
859#endif
38e16f92
AJ
860 break;
861
862 case LFT_USER_IDENT:
bd85ea1f 863 out = strOrNull(al->cache.rfc931);
38e16f92
AJ
864 break;
865
866 case LFT_USER_EXTERNAL:
4e56d7f6
AJ
867 if (al->request && al->request->extacl_user.size())
868 out = al->request->extacl_user.termedBuf();
869
870 if (!out)
871 out = strOrNull(al->cache.extuser);
38e16f92
AJ
872 break;
873
f53969cc
SM
874 /* case LFT_USER_REALM: */
875 /* case LFT_USER_SCHEME: */
38e16f92 876
f53969cc
SM
877 // the fmt->type can not be LFT_HTTP_SENT_STATUS_CODE_OLD_30
878 // but compiler complains if ommited
38e16f92
AJ
879 case LFT_HTTP_SENT_STATUS_CODE_OLD_30:
880 case LFT_HTTP_SENT_STATUS_CODE:
881 outint = al->http.code;
882
883 doint = 1;
884
885 break;
886
887 case LFT_HTTP_RECEIVED_STATUS_CODE:
955394ce 888 if (al->hier.peer_reply_status == Http::scNone) {
38e16f92
AJ
889 out = "-";
890 } else {
891 outint = al->hier.peer_reply_status;
892 doint = 1;
893 }
894 break;
f53969cc
SM
895 /* case LFT_HTTP_STATUS:
896 * out = statusline->text;
897 * quote = 1;
898 * break;
899 */
38e16f92
AJ
900 case LFT_HTTP_BODY_BYTES_READ:
901 if (al->hier.bodyBytesRead >= 0) {
902 outoff = al->hier.bodyBytesRead;
903 dooff = 1;
904 }
905 // else if hier.bodyBytesRead < 0 we did not have any data exchange with
906 // a peer server so just print a "-" (eg requests served from cache,
907 // or internal error messages).
908 break;
909
910 case LFT_SQUID_STATUS:
a981b360 911 out = al->cache.code.c_str();
38e16f92
AJ
912 break;
913
914 case LFT_SQUID_ERROR:
915 if (al->request && al->request->errType != ERR_NONE)
916 out = errorPageName(al->request->errType);
917 break;
918
919 case LFT_SQUID_ERROR_DETAIL:
cb4f4424 920#if USE_OPENSSL
2f3e52b5
CT
921 if (al->request && al->request->errType == ERR_SECURE_CONNECT_FAIL) {
922 if (! (out = Ssl::GetErrorName(al->request->errDetail))) {
923 snprintf(tmp, sizeof(tmp), "SSL_ERR=%d", al->request->errDetail);
924 out = tmp;
925 }
e83cdc25 926 } else
2f3e52b5 927#endif
e83cdc25 928 if (al->request && al->request->errDetail != ERR_DETAIL_NONE) {
4e56d7f6 929 if (al->request->errDetail > ERR_DETAIL_START && al->request->errDetail < ERR_DETAIL_MAX)
e83cdc25
A
930 out = errorDetailName(al->request->errDetail);
931 else {
932 if (al->request->errDetail >= ERR_DETAIL_EXCEPTION_START)
933 snprintf(tmp, sizeof(tmp), "%s=0x%X",
934 errorDetailName(al->request->errDetail), (uint32_t) al->request->errDetail);
935 else
936 snprintf(tmp, sizeof(tmp), "%s=%d",
937 errorDetailName(al->request->errDetail), al->request->errDetail);
938 out = tmp;
939 }
38e16f92 940 }
38e16f92
AJ
941 break;
942
943 case LFT_SQUID_HIERARCHY:
944 if (al->hier.ping.timedout)
945 mb.append("TIMEOUT_", 8);
946
947 out = hier_code_str[al->hier.code];
948
949 break;
950
951 case LFT_MIME_TYPE:
952 out = al->http.content_type;
953
954 break;
955
956 case LFT_CLIENT_REQ_METHOD:
957 if (al->request) {
7f06a3d8
AJ
958 const SBuf &s = al->request->method.image();
959 sb.append(s.rawContent(), s.length());
960 out = sb.termedBuf();
38e16f92
AJ
961 quote = 1;
962 }
963 break;
964
965 case LFT_CLIENT_REQ_URI:
966 // original client URI
967 if (al->request) {
851feda6
AJ
968 const SBuf &s = al->request->effectiveRequestUri();
969 sb.append(s.rawContent(), s.length());
970 out = sb.termedBuf();
38e16f92
AJ
971 quote = 1;
972 }
973 break;
974
5aca9cf2
AJ
975 case LFT_CLIENT_REQ_URLSCHEME:
976 if (al->request) {
977 out = al->request->url.getScheme().c_str();
978 quote = 1;
979 }
980 break;
981
fa450988
AJ
982 case LFT_CLIENT_REQ_URLDOMAIN:
983 if (al->request) {
5c51bffb 984 out = al->request->url.host();
fa450988
AJ
985 quote = 1;
986 }
987 break;
988
5aca9cf2
AJ
989 case LFT_CLIENT_REQ_URLPORT:
990 if (al->request) {
5c51bffb 991 outint = al->request->url.port();
5aca9cf2
AJ
992 doint = 1;
993 }
994 break;
995
38e16f92
AJ
996 case LFT_REQUEST_URLPATH_OLD_31:
997 case LFT_CLIENT_REQ_URLPATH:
998 if (al->request) {
51b5dcf5
AJ
999 SBuf s = al->request->url.path();
1000 out = s.c_str();
38e16f92
AJ
1001 quote = 1;
1002 }
1003 break;
1004
1005 case LFT_CLIENT_REQ_VERSION:
1006 if (al->request) {
1007 snprintf(tmp, sizeof(tmp), "%d.%d", (int) al->request->http_ver.major, (int) al->request->http_ver.minor);
1008 out = tmp;
1009 }
1010 break;
1011
1012 case LFT_REQUEST_METHOD:
7f06a3d8
AJ
1013 if (al->_private.method_str) // ICP, HTCP method code
1014 out = al->_private.method_str;
1015 else {
1016 const SBuf &s = al->http.method.image();
1017 sb.append(s.rawContent(), s.length());
1018 out = sb.termedBuf();
1019 quote = 1;
1020 }
38e16f92
AJ
1021 break;
1022
1023 case LFT_REQUEST_URI:
1024 out = al->url;
1025 break;
1026
1027 case LFT_REQUEST_VERSION_OLD_2X:
1028 case LFT_REQUEST_VERSION:
1029 snprintf(tmp, sizeof(tmp), "%d.%d", (int) al->http.version.major, (int) al->http.version.minor);
1030 out = tmp;
1031 break;
1032
1033 case LFT_SERVER_REQ_METHOD:
1034 if (al->adapted_request) {
7f06a3d8
AJ
1035 const SBuf &s = al->adapted_request->method.image();
1036 sb.append(s.rawContent(), s.length());
1037 out = sb.termedBuf();
38e16f92
AJ
1038 quote = 1;
1039 }
1040 break;
1041
1042 case LFT_SERVER_REQ_URI:
1043 // adapted request URI sent to server/peer
1044 if (al->adapted_request) {
851feda6
AJ
1045 const SBuf &s = al->adapted_request->effectiveRequestUri();
1046 sb.append(s.rawContent(), s.length());
1047 out = sb.termedBuf();
38e16f92
AJ
1048 quote = 1;
1049 }
1050 break;
1051
5aca9cf2
AJ
1052 case LFT_SERVER_REQ_URLSCHEME:
1053 if (al->adapted_request) {
1054 out = al->adapted_request->url.getScheme().c_str();
1055 quote = 1;
1056 }
1057 break;
1058
1059 case LFT_SERVER_REQ_URLDOMAIN:
1060 if (al->adapted_request) {
5c51bffb 1061 out = al->adapted_request->url.host();
5aca9cf2
AJ
1062 quote = 1;
1063 }
1064 break;
1065
1066 case LFT_SERVER_REQ_URLPORT:
1067 if (al->adapted_request) {
5c51bffb 1068 outint = al->adapted_request->url.port();
5aca9cf2
AJ
1069 doint = 1;
1070 }
1071 break;
1072
38e16f92
AJ
1073 case LFT_SERVER_REQ_URLPATH:
1074 if (al->adapted_request) {
51b5dcf5
AJ
1075 SBuf s = al->adapted_request->url.path();
1076 out = s.c_str();
38e16f92
AJ
1077 quote = 1;
1078 }
1079 break;
1080
1081 case LFT_SERVER_REQ_VERSION:
1082 if (al->adapted_request) {
1083 snprintf(tmp, sizeof(tmp), "%d.%d",
1084 (int) al->adapted_request->http_ver.major,
1085 (int) al->adapted_request->http_ver.minor);
1086 out = tmp;
1087 }
1088 break;
1089
d6df21d2 1090 case LFT_CLIENT_REQUEST_SIZE_TOTAL:
cc0ca3b9 1091 outoff = al->http.clientRequestSz.messageTotal();
38e16f92
AJ
1092 dooff = 1;
1093 break;
1094
d6df21d2 1095 case LFT_CLIENT_REQUEST_SIZE_HEADERS:
cc0ca3b9 1096 outoff = al->http.clientRequestSz.header;
38e16f92
AJ
1097 dooff =1;
1098 break;
d6df21d2 1099
f53969cc
SM
1100 /*case LFT_REQUEST_SIZE_BODY: */
1101 /*case LFT_REQUEST_SIZE_BODY_NO_TE: */
38e16f92 1102
d6df21d2 1103 case LFT_ADAPTED_REPLY_SIZE_TOTAL:
cc0ca3b9 1104 outoff = al->http.clientReplySz.messageTotal();
38e16f92
AJ
1105 dooff = 1;
1106 break;
1107
1108 case LFT_REPLY_HIGHOFFSET:
1109 outoff = al->cache.highOffset;
1110
1111 dooff = 1;
1112
1113 break;
1114
1115 case LFT_REPLY_OBJECTSIZE:
1116 outoff = al->cache.objectSize;
1117
1118 dooff = 1;
1119
1120 break;
1121
d6df21d2 1122 case LFT_ADAPTED_REPLY_SIZE_HEADERS:
cc0ca3b9 1123 outint = al->http.clientReplySz.header;
38e16f92
AJ
1124 doint = 1;
1125 break;
d6df21d2 1126
f53969cc
SM
1127 /*case LFT_REPLY_SIZE_BODY: */
1128 /*case LFT_REPLY_SIZE_BODY_NO_TE: */
38e16f92 1129
d6df21d2 1130 case LFT_CLIENT_IO_SIZE_TOTAL:
cc0ca3b9 1131 outint = al->http.clientRequestSz.messageTotal() + al->http.clientReplySz.messageTotal();
d6df21d2
AJ
1132 doint = 1;
1133 break;
f53969cc 1134 /*case LFT_SERVER_IO_SIZE_TOTAL: */
d6df21d2 1135
38e16f92
AJ
1136 case LFT_TAG:
1137 if (al->request)
1138 out = al->request->tag.termedBuf();
1139
1140 quote = 1;
1141
1142 break;
1143
38e16f92
AJ
1144 case LFT_EXT_LOG:
1145 if (al->request)
1146 out = al->request->extacl_log.termedBuf();
1147
1148 quote = 1;
1149
1150 break;
1151
1152 case LFT_SEQUENCE_NUMBER:
1153 outoff = logSequenceNumber;
1154 dooff = 1;
1155 break;
1156
cb4f4424 1157#if USE_OPENSSL
08097970
AR
1158 case LFT_SSL_BUMP_MODE: {
1159 const Ssl::BumpMode mode = static_cast<Ssl::BumpMode>(al->ssl.bumpMode);
1160 // for Ssl::bumpEnd, Ssl::bumpMode() returns NULL and we log '-'
1161 out = Ssl::bumpMode(mode);
08097970 1162 }
4e56d7f6
AJ
1163 break;
1164
1165 case LFT_EXT_ACL_USER_CERT_RAW:
1166 if (al->request) {
1167 ConnStateData *conn = al->request->clientConnectionManager.get();
1168 if (conn != NULL && Comm::IsConnOpen(conn->clientConnection)) {
1169 if (SSL *ssl = fd_table[conn->clientConnection->fd].ssl)
1170 out = sslGetUserCertificatePEM(ssl);
1171 }
1172 }
1173 break;
1174
1175 case LFT_EXT_ACL_USER_CERTCHAIN_RAW:
1176 if (al->request) {
1177 ConnStateData *conn = al->request->clientConnectionManager.get();
1178 if (conn != NULL && Comm::IsConnOpen(conn->clientConnection)) {
1179 if (SSL *ssl = fd_table[conn->clientConnection->fd].ssl)
1180 out = sslGetUserCertificatePEM(ssl);
1181 }
1182 }
1183 break;
1184
1185 case LFT_EXT_ACL_USER_CERT:
1186 if (al->request) {
1187 ConnStateData *conn = al->request->clientConnectionManager.get();
1188 if (conn != NULL && Comm::IsConnOpen(conn->clientConnection)) {
1189 if (SSL *ssl = fd_table[conn->clientConnection->fd].ssl)
1190 out = sslGetUserAttribute(ssl, format->data.header.header);
1191 }
1192 }
1193 break;
1194
1195 case LFT_EXT_ACL_USER_CA_CERT:
1196 if (al->request) {
1197 ConnStateData *conn = al->request->clientConnectionManager.get();
1198 if (conn != NULL && Comm::IsConnOpen(conn->clientConnection)) {
1199 if (SSL *ssl = fd_table[conn->clientConnection->fd].ssl)
1200 out = sslGetCAAttribute(ssl, format->data.header.header);
1201 }
1202 }
1203 break;
71cae389 1204
f4698e0b
CT
1205 case LFT_SSL_USER_CERT_SUBJECT:
1206 if (X509 *cert = al->cache.sslClientCert.get()) {
1207 if (X509_NAME *subject = X509_get_subject_name(cert)) {
1208 X509_NAME_oneline(subject, tmp, sizeof(tmp));
1209 out = tmp;
1210 }
1211 }
1212 break;
1213
1214 case LFT_SSL_USER_CERT_ISSUER:
1215 if (X509 *cert = al->cache.sslClientCert.get()) {
1216 if (X509_NAME *issuer = X509_get_issuer_name(cert)) {
1217 X509_NAME_oneline(issuer, tmp, sizeof(tmp));
1218 out = tmp;
1219 }
1220 }
1221 break;
4e56d7f6 1222
cedca6e7
CT
1223 case LFT_SSL_CLIENT_SNI:
1224 if (al->request && al->request->clientConnectionManager.valid()) {
1225 if (Ssl::ServerBump * srvBump = al->request->clientConnectionManager->serverBump()) {
1226 if (!srvBump->clientSni.isEmpty())
1227 out = srvBump->clientSni.c_str();
1228 }
1229 }
1230 break;
789dda8d
CT
1231
1232 case LFT_SSL_SERVER_CERT_ISSUER:
1233 case LFT_SSL_SERVER_CERT_SUBJECT:
1234 // Not implemented
1235 break;
08097970 1236#endif
f123f5e9 1237
d074f918
TT
1238 case LFT_REQUEST_URLGROUP_OLD_2X:
1239 assert(LFT_REQUEST_URLGROUP_OLD_2X == 0); // should never happen.
1240
d7f4a0b7 1241 case LFT_NOTE:
c7bcf010
CT
1242 tmp[0] = fmt->data.header.separator;
1243 tmp[1] = '\0';
1244 if (fmt->data.header.header && *fmt->data.header.header) {
1245 const char *separator = tmp;
cf9f0261 1246#if USE_ADAPTATION
7f0ceafc 1247 Adaptation::History::Pointer ah = al->request ? al->request->adaptHistory() : Adaptation::History::Pointer();
cf9f0261 1248 if (ah != NULL && ah->metaHeaders != NULL) {
c7bcf010 1249 if (const char *meta = ah->metaHeaders->find(fmt->data.header.header, separator))
cf9f0261
CT
1250 sb.append(meta);
1251 }
1252#endif
f4f55a21 1253 if (al->notes != NULL) {
c7bcf010 1254 if (const char *note = al->notes->find(fmt->data.header.header, separator)) {
cf9f0261 1255 if (sb.size())
c7bcf010 1256 sb.append(separator);
cf9f0261
CT
1257 sb.append(note);
1258 }
1259 }
d7f4a0b7
CT
1260 out = sb.termedBuf();
1261 quote = 1;
1262 } else {
c7bcf010
CT
1263 // if no argument given use default "\r\n" as notes separator
1264 const char *separator = fmt->data.string ? tmp : "\r\n";
cf9f0261 1265#if USE_ADAPTATION
7f0ceafc 1266 Adaptation::History::Pointer ah = al->request ? al->request->adaptHistory() : Adaptation::History::Pointer();
cf9f0261 1267 if (ah != NULL && ah->metaHeaders != NULL && !ah->metaHeaders->empty())
c7bcf010 1268 sb.append(ah->metaHeaders->toString(separator));
cf9f0261 1269#endif
f4f55a21 1270 if (al->notes != NULL && !al->notes->empty())
c7bcf010 1271 sb.append(al->notes->toString(separator));
f4f55a21 1272
d7f4a0b7
CT
1273 out = sb.termedBuf();
1274 quote = 1;
1275 }
1276 break;
08097970 1277
d4806c91
CT
1278 case LFT_CREDENTIALS:
1279#if USE_AUTH
1280 if (al->request && al->request->auth_user_request != NULL)
1281 out = strOrNull(al->request->auth_user_request->credentialsStr());
1282#endif
1283
1284 break;
1285
38e16f92
AJ
1286 case LFT_PERCENT:
1287 out = "%";
5aca9cf2 1288 break;
38e16f92 1289
5aca9cf2 1290 case LFT_EXT_ACL_NAME:
4ff6370b 1291 out = al->lastAclName;
4e56d7f6
AJ
1292 break;
1293
5aca9cf2 1294 case LFT_EXT_ACL_DATA:
4ff6370b 1295 out = al->lastAclData;
38e16f92
AJ
1296 break;
1297 }
1298
1299 if (dooff) {
8846a2b4 1300 snprintf(tmp, sizeof(tmp), "%0*" PRId64, fmt->zero && fmt->widthMin >= 0 ? fmt->widthMin : 0, outoff);
38e16f92
AJ
1301 out = tmp;
1302
1303 } else if (doint) {
8846a2b4 1304 snprintf(tmp, sizeof(tmp), "%0*ld", fmt->zero && fmt->widthMin >= 0 ? fmt->widthMin : 0, outint);
38e16f92 1305 out = tmp;
01bd87d8
CT
1306 } else if (doMsec) {
1307 if (fmt->widthMax < 0) {
1308 snprintf(tmp, sizeof(tmp), "%0*ld", fmt->widthMin , tvToMsec(outtv));
1309 } else {
1310 int precision = fmt->widthMax;
1311 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)));
1312 }
1313 out = tmp;
1314 } else if (doSec) {
1315 int precision = fmt->widthMax >=0 ? fmt->widthMax :3;
1316 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));
1317 out = tmp;
38e16f92
AJ
1318 }
1319
1320 if (out && *out) {
1321 if (quote || fmt->quote != LOG_QUOTE_NONE) {
1322 char *newout = NULL;
1323 int newfree = 0;
1324
1325 switch (fmt->quote) {
1326
1327 case LOG_QUOTE_NONE:
1328 newout = rfc1738_escape_unescaped(out);
1329 break;
1330
1331 case LOG_QUOTE_QUOTES: {
1332 size_t out_len = static_cast<size_t>(strlen(out)) * 2 + 1;
1333 if (out_len >= sizeof(tmp)) {
1334 newout = (char *)xmalloc(out_len);
1335 newfree = 1;
1336 } else
1337 newout = tmp;
1338 log_quoted_string(out, newout);
1339 }
1340 break;
1341
1342 case LOG_QUOTE_MIMEBLOB:
1343 newout = QuoteMimeBlob(out);
1344 newfree = 1;
1345 break;
1346
1347 case LOG_QUOTE_URL:
1348 newout = rfc1738_escape(out);
1349 break;
1350
95d78f10
AJ
1351 case LOG_QUOTE_SHELL: {
1352 MemBuf mbq;
1353 mbq.init();
1354 strwordquote(&mbq, out);
1355 newout = mbq.content();
1356 mbq.stolen = 1;
1357 newfree = 1;
1358 } break;
1359
38e16f92
AJ
1360 case LOG_QUOTE_RAW:
1361 break;
1362 }
1363
1364 if (newout) {
1365 if (dofree)
1366 safe_free(out);
1367
1368 out = newout;
1369
1370 dofree = newfree;
1371 }
1372 }
1373
c32c6db7 1374 // enforce width limits if configured
01bd87d8 1375 const bool haveMaxWidth = fmt->widthMax >=0 && !doint && !dooff && !doMsec && !doSec;
8846a2b4
CT
1376 if (haveMaxWidth || fmt->widthMin) {
1377 const int minWidth = fmt->widthMin >= 0 ?
b8ad91f5 1378 fmt->widthMin :0;
c32c6db7 1379 const int maxWidth = haveMaxWidth ?
8846a2b4 1380 fmt->widthMax : strlen(out);
c32c6db7 1381
38e16f92 1382 if (fmt->left)
4391cd15 1383 mb.appendf("%-*.*s", minWidth, maxWidth, out);
38e16f92 1384 else
4391cd15 1385 mb.appendf("%*.*s", minWidth, maxWidth, out);
38e16f92
AJ
1386 } else
1387 mb.append(out, strlen(out));
1388 } else {
1389 mb.append("-", 1);
1390 }
1391
1392 if (fmt->space)
1393 mb.append(" ", 1);
1394
1395 sb.clean();
1396
1397 if (dofree)
1398 safe_free(out);
1399 }
1400}
f53969cc 1401