1 /** @file
2
3 This file implements the LogAccess class.
4
5 @section license License
6
7 Licensed to the Apache Software Foundation (ASF) under one
8 or more contributor license agreements. See the NOTICE file
9 distributed with this work for additional information
10 regarding copyright ownership. The ASF licenses this file
11 to you under the Apache License, Version 2.0 (the
12 "License"); you may not use this file except in compliance
13 with the License. You may obtain a copy of the License at
14
15 http://www.apache.org/licenses/LICENSE-2.0
16
17 Unless required by applicable law or agreed to in writing, software
18 distributed under the License is distributed on an "AS IS" BASIS,
19 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 See the License for the specific language governing permissions and
21 limitations under the License.
22
23 */
24
25 #include "LogAccess.h"
26
27 #include "http/HttpSM.h"
28 #include "MIME.h"
29 #include "I_Machine.h"
30 #include "LogFormat.h"
31 #include "LogBuffer.h"
32
33 extern AppVersionInfo appVersionInfo;
34
35 char INVALID_STR[] = "!INVALID_STR!";
36
37 #define HIDDEN_CONTENT_TYPE "@Content-Type"
38 #define HIDDEN_CONTENT_TYPE_LEN 13
39
40 // should be at least 22 bytes to always accommodate a converted
41 // MgmtInt, MgmtIntCounter or MgmtFloat. 22 bytes is enough for 64 bit
42 // ints + sign + eos, and enough for %e floating point representation
43 // + eos
44 //
45 #define MARSHAL_RECORD_LENGTH 32
46
47 /*-------------------------------------------------------------------------
48 LogAccess
49
50 Initialize the private data members and assert that we got a valid state
51 machine pointer.
52 -------------------------------------------------------------------------*/
53
LogAccess(HttpSM * sm)54 LogAccess::LogAccess(HttpSM *sm)
55 : m_http_sm(sm),
56 m_arena(),
57 m_client_request(nullptr),
58 m_proxy_response(nullptr),
59 m_proxy_request(nullptr),
60 m_server_response(nullptr),
61 m_cache_response(nullptr),
62 m_client_req_url_str(nullptr),
63 m_client_req_url_len(0),
64 m_client_req_url_canon_str(nullptr),
65 m_client_req_url_canon_len(0),
66 m_client_req_unmapped_url_canon_str(nullptr),
67 m_client_req_unmapped_url_canon_len(0),
68 m_client_req_unmapped_url_path_str(nullptr),
69 m_client_req_unmapped_url_path_len(0),
70 m_client_req_unmapped_url_host_str(nullptr),
71 m_client_req_unmapped_url_host_len(0),
72 m_client_req_url_path_str(nullptr),
73 m_client_req_url_path_len(0),
74 m_proxy_resp_content_type_str(nullptr),
75 m_proxy_resp_content_type_len(0),
76 m_proxy_resp_reason_phrase_str(nullptr),
77 m_proxy_resp_reason_phrase_len(0),
78 m_cache_lookup_url_canon_str(nullptr),
79 m_cache_lookup_url_canon_len(0)
80 {
81 ink_assert(m_http_sm != nullptr);
82 }
83
84 /*-------------------------------------------------------------------------
85 LogAccess::init
86 -------------------------------------------------------------------------*/
87
88 void
init()89 LogAccess::init()
90 {
91 HttpTransact::HeaderInfo *hdr = &(m_http_sm->t_state.hdr_info);
92
93 if (hdr->client_request.valid()) {
94 m_client_request = &(hdr->client_request);
95
96 // make a copy of the incoming url into the arena
97 const char *url_string_ref = m_client_request->url_string_get_ref(&m_client_req_url_len);
98 m_client_req_url_str = m_arena.str_alloc(m_client_req_url_len + 1);
99 memcpy(m_client_req_url_str, url_string_ref, m_client_req_url_len);
100 m_client_req_url_str[m_client_req_url_len] = '\0';
101
102 m_client_req_url_canon_str =
103 LogUtils::escapify_url(&m_arena, m_client_req_url_str, m_client_req_url_len, &m_client_req_url_canon_len);
104 m_client_req_url_path_str = m_client_request->path_get(&m_client_req_url_path_len);
105 }
106
107 if (hdr->client_response.valid()) {
108 m_proxy_response = &(hdr->client_response);
109 MIMEField *field = m_proxy_response->field_find(MIME_FIELD_CONTENT_TYPE, MIME_LEN_CONTENT_TYPE);
110 if (field) {
111 m_proxy_resp_content_type_str = const_cast<char *>(field->value_get(&m_proxy_resp_content_type_len));
112
113 LogUtils::remove_content_type_attributes(m_proxy_resp_content_type_str, &m_proxy_resp_content_type_len);
114 } else {
115 // If Content-Type field is missing, check for @Content-Type
116 field = m_proxy_response->field_find(HIDDEN_CONTENT_TYPE, HIDDEN_CONTENT_TYPE_LEN);
117 if (field) {
118 m_proxy_resp_content_type_str = const_cast<char *>(field->value_get(&m_proxy_resp_content_type_len));
119 LogUtils::remove_content_type_attributes(m_proxy_resp_content_type_str, &m_proxy_resp_content_type_len);
120 }
121 }
122 m_proxy_resp_reason_phrase_str = const_cast<char *>(m_proxy_response->reason_get(&m_proxy_resp_reason_phrase_len));
123 }
124 if (hdr->server_request.valid()) {
125 m_proxy_request = &(hdr->server_request);
126 }
127 if (hdr->server_response.valid()) {
128 m_server_response = &(hdr->server_response);
129 }
130 if (hdr->cache_response.valid()) {
131 m_cache_response = &(hdr->cache_response);
132 }
133 }
134
135 int
marshal_proxy_host_name(char * buf)136 LogAccess::marshal_proxy_host_name(char *buf)
137 {
138 char *str = nullptr;
139 int len = 0;
140 Machine *machine = Machine::instance();
141
142 if (machine) {
143 str = machine->hostname;
144 }
145
146 len = LogAccess::strlen(str);
147
148 if (buf) {
149 marshal_str(buf, str, len);
150 }
151
152 return len;
153 }
154
155 /*-------------------------------------------------------------------------
156 -------------------------------------------------------------------------*/
157
158 int
marshal_proxy_host_ip(char * buf)159 LogAccess::marshal_proxy_host_ip(char *buf)
160 {
161 return marshal_ip(buf, &Machine::instance()->ip.sa);
162 }
163
164 /*-------------------------------------------------------------------------
165 -------------------------------------------------------------------------*/
166 int
marshal_process_uuid(char * buf)167 LogAccess::marshal_process_uuid(char *buf)
168 {
169 int len = round_strlen(TS_UUID_STRING_LEN + 1);
170
171 if (buf) {
172 const char *str = const_cast<char *>(Machine::instance()->uuid.getString());
173 marshal_str(buf, str, len);
174 }
175 return len;
176 }
177
178 /*-------------------------------------------------------------------------
179 -------------------------------------------------------------------------*/
180
181 int
marshal_config_int_var(char * config_var,char * buf)182 LogAccess::marshal_config_int_var(char *config_var, char *buf)
183 {
184 if (buf) {
185 int64_t val = static_cast<int64_t>(REC_ConfigReadInteger(config_var));
186 marshal_int(buf, val);
187 }
188 return INK_MIN_ALIGN;
189 }
190
191 /*-------------------------------------------------------------------------
192 -------------------------------------------------------------------------*/
193
194 int
marshal_config_str_var(char * config_var,char * buf)195 LogAccess::marshal_config_str_var(char *config_var, char *buf)
196 {
197 char *str = nullptr;
198 str = REC_ConfigReadString(config_var);
199 int len = LogAccess::strlen(str);
200 if (buf) {
201 marshal_str(buf, str, len);
202 }
203 ats_free(str);
204 return len;
205 }
206
207 // To allow for a generic marshal_record function, rather than
208 // multiple functions (one per data type) we always marshal a record
209 // as a string of a fixed length. We use a fixed length because the
210 // marshal_record function can be called with a null *buf to request
211 // the length of the record, and later with a non-null *buf to
212 // actually request the record to be inserted in the buffer, and both
213 // calls should return the same number of characters. If we did not
214 // enforce a fixed size, this would not necessarily be the case
215 // because records --statistics in particular-- can potentially change
216 // between one call and the other.
217 //
218 int
marshal_record(char * record,char * buf)219 LogAccess::marshal_record(char *record, char *buf)
220 {
221 const unsigned int max_chars = MARSHAL_RECORD_LENGTH;
222
223 if (nullptr == buf) {
224 return max_chars;
225 }
226
227 const char *record_not_found_msg = "RECORD_NOT_FOUND";
228 const unsigned int record_not_found_chars = ::strlen(record_not_found_msg) + 1;
229
230 char ascii_buf[max_chars];
231 const char *out_buf;
232 unsigned int num_chars;
233
234 #define LOG_INTEGER RECD_INT
235 #define LOG_COUNTER RECD_COUNTER
236 #define LOG_FLOAT RECD_FLOAT
237 #define LOG_STRING RECD_STRING
238
239 RecDataT stype = RECD_NULL;
240 bool found = false;
241
242 if (RecGetRecordDataType(record, &stype) != REC_ERR_OKAY) {
243 out_buf = "INVALID_RECORD";
244 num_chars = ::strlen(out_buf) + 1;
245 } else {
246 if (LOG_INTEGER == stype || LOG_COUNTER == stype) {
247 // we assume MgmtInt and MgmtIntCounter are int64_t for the
248 // conversion below, if this ever changes we should modify
249 // accordingly
250 //
251 ink_assert(sizeof(int64_t) >= sizeof(RecInt) && sizeof(int64_t) >= sizeof(RecCounter));
252
253 // so that a 64 bit integer will fit (including sign and eos)
254 //
255 ink_assert(max_chars > 21);
256
257 int64_t val = static_cast<int64_t>(LOG_INTEGER == stype ? REC_readInteger(record, &found) : REC_readCounter(record, &found));
258
259 if (found) {
260 out_buf = int64_to_str(ascii_buf, max_chars, val, &num_chars);
261 ink_assert(out_buf);
262 } else {
263 out_buf = const_cast<char *>(record_not_found_msg);
264 num_chars = record_not_found_chars;
265 }
266 } else if (LOG_FLOAT == stype) {
267 // we assume MgmtFloat is at least a float for the conversion below
268 // (the conversion itself assumes a double because of the %e)
269 // if this ever changes we should modify accordingly
270 //
271 ink_assert(sizeof(double) >= sizeof(RecFloat));
272
273 RecFloat val = REC_readFloat(record, &found);
274
275 if (found) {
276 // snprintf does not support "%e" in the format
277 // and we want to use "%e" because it is the most concise
278 // notation
279
280 num_chars = snprintf(ascii_buf, sizeof(ascii_buf), "%e", val) + 1; // include eos
281
282 // the "%e" field above should take 13 characters at most
283 //
284 ink_assert(num_chars <= max_chars);
285
286 // the following should never be true
287 //
288 if (num_chars > max_chars) {
289 // data does not fit, output asterisks
290 out_buf = "***";
291 num_chars = ::strlen(out_buf) + 1;
292 } else {
293 out_buf = ascii_buf;
294 }
295 } else {
296 out_buf = const_cast<char *>(record_not_found_msg);
297 num_chars = record_not_found_chars;
298 }
299 } else if (LOG_STRING == stype) {
300 if (RecGetRecordString(record, ascii_buf, sizeof(ascii_buf)) == REC_ERR_OKAY) {
301 if (strlen(ascii_buf) > 0) {
302 num_chars = ::strlen(ascii_buf) + 1;
303 if (num_chars == max_chars) {
304 // truncate string and write ellipsis at the end
305 ascii_buf[max_chars - 1] = 0;
306 ascii_buf[max_chars - 2] = '.';
307 ascii_buf[max_chars - 3] = '.';
308 ascii_buf[max_chars - 4] = '.';
309 }
310 out_buf = ascii_buf;
311 } else {
312 out_buf = "NULL";
313 num_chars = ::strlen(out_buf) + 1;
314 }
315 } else {
316 out_buf = const_cast<char *>(record_not_found_msg);
317 num_chars = record_not_found_chars;
318 }
319 } else {
320 out_buf = "INVALID_MgmtType";
321 num_chars = ::strlen(out_buf) + 1;
322 ink_assert(!"invalid MgmtType for requested record");
323 }
324 }
325
326 ink_assert(num_chars <= max_chars);
327 memcpy(buf, out_buf, num_chars);
328
329 return max_chars;
330 }
331
332 /*-------------------------------------------------------------------------
333 LogAccess::marshal_str
334
335 Copy the given string to the destination buffer, including the trailing
336 NULL. For binary formatting, we need the NULL to distinguish the end of
337 the string, and we'll remove it for ascii formatting.
338 ASSUMES dest IS NOT NULL.
339 The array pointed to by dest must be at least padded_len in length.
340 -------------------------------------------------------------------------*/
341
342 void
marshal_str(char * dest,const char * source,int padded_len)343 LogAccess::marshal_str(char *dest, const char *source, int padded_len)
344 {
345 if (source == nullptr || source[0] == 0 || padded_len == 0) {
346 source = DEFAULT_STR;
347 }
348 ink_strlcpy(dest, source, padded_len);
349
350 #ifdef DEBUG
351 //
352 // what padded_len should be, if there is no padding, is strlen()+1.
353 // if not, then we needed to pad and should touch the intermediate
354 // bytes to avoid UMR errors when the buffer is written.
355 //
356 size_t real_len = (::strlen(source) + 1);
357 while (static_cast<int>(real_len) < padded_len) {
358 dest[real_len] = '$';
359 real_len++;
360 }
361 #endif
362 }
363
364 /*-------------------------------------------------------------------------
365 -------------------------------------------------------------------------*/
366
367 int
marshal_client_req_all_header_fields(char * buf)368 LogAccess::marshal_client_req_all_header_fields(char *buf)
369 {
370 return LogUtils::marshalMimeHdr(m_client_request, buf);
371 }
372
373 /*-------------------------------------------------------------------------
374 LogAccess::marshal_mem
375
376 This is a version of marshal_str that works with unterminated strings.
377 In this case, we'll copy the buffer and then add a trailing null that
378 the rest of the system assumes.
379 -------------------------------------------------------------------------*/
380
381 void
marshal_mem(char * dest,const char * source,int actual_len,int padded_len)382 LogAccess::marshal_mem(char *dest, const char *source, int actual_len, int padded_len)
383 {
384 if (source == nullptr || source[0] == 0 || actual_len == 0) {
385 source = DEFAULT_STR;
386 actual_len = DEFAULT_STR_LEN;
387 ink_assert(actual_len < padded_len);
388 }
389 memcpy(dest, source, actual_len);
390 dest[actual_len] = 0; // add terminating null
391
392 #ifdef DEBUG
393 //
394 // what len should be, if there is no padding, is strlen()+1.
395 // if not, then we needed to pad and should touch the intermediate
396 // bytes to avoid UMR errors when the buffer is written.
397 //
398 int real_len = actual_len + 1;
399 while (real_len < padded_len) {
400 dest[real_len] = '$';
401 real_len++;
402 }
403 #endif
404 }
405
406 /*-------------------------------------------------------------------------
407 LogAccess::marshal_ip
408
409 Marshal an IP address in a reasonably compact way. If the address isn't
410 valid (NULL or not IP) then marshal an invalid address record.
411 -------------------------------------------------------------------------*/
412
413 int
marshal_ip(char * dest,sockaddr const * ip)414 LogAccess::marshal_ip(char *dest, sockaddr const *ip)
415 {
416 LogFieldIpStorage data;
417 int len = sizeof(data._ip);
418 if (nullptr == ip) {
419 data._ip._family = AF_UNSPEC;
420 } else if (ats_is_ip4(ip)) {
421 if (dest) {
422 data._ip4._family = AF_INET;
423 data._ip4._addr = ats_ip4_addr_cast(ip);
424 }
425 len = sizeof(data._ip4);
426 } else if (ats_is_ip6(ip)) {
427 if (dest) {
428 data._ip6._family = AF_INET6;
429 data._ip6._addr = ats_ip6_addr_cast(ip);
430 }
431 len = sizeof(data._ip6);
432 } else {
433 data._ip._family = AF_UNSPEC;
434 }
435
436 if (dest) {
437 memcpy(dest, &data, len);
438 }
439 return INK_ALIGN_DEFAULT(len);
440 }
441
442 inline int
unmarshal_with_map(int64_t code,char * dest,int len,const Ptr<LogFieldAliasMap> & map,const char * msg)443 LogAccess::unmarshal_with_map(int64_t code, char *dest, int len, const Ptr<LogFieldAliasMap> &map, const char *msg)
444 {
445 long int codeStrLen = 0;
446
447 switch (map->asString(code, dest, len, reinterpret_cast<size_t *>(&codeStrLen))) {
448 case LogFieldAliasMap::INVALID_INT:
449 if (msg) {
450 const int bufSize = 64;
451 char invalidCodeMsg[bufSize];
452 codeStrLen = snprintf(invalidCodeMsg, 64, "%s(%" PRId64 ")", msg, code);
453 if (codeStrLen < bufSize && codeStrLen < len) {
454 ink_strlcpy(dest, invalidCodeMsg, len);
455 } else {
456 codeStrLen = -1;
457 }
458 } else {
459 codeStrLen = -1;
460 }
461 break;
462 case LogFieldAliasMap::BUFFER_TOO_SMALL:
463 codeStrLen = -1;
464 break;
465 }
466
467 return codeStrLen;
468 }
469
470 /*-------------------------------------------------------------------------
471 LogAccess::unmarshal_int
472
473 Return the integer pointed at by the buffer and advance the buffer
474 pointer past the int. The int will be converted back to host byte order.
475 -------------------------------------------------------------------------*/
476
477 int64_t
unmarshal_int(char ** buf)478 LogAccess::unmarshal_int(char **buf)
479 {
480 ink_assert(buf != nullptr);
481 ink_assert(*buf != nullptr);
482 int64_t val;
483
484 // TODO: this used to do nthol, do we need to worry? TS-1156.
485 val = *(reinterpret_cast<int64_t *>(*buf));
486 *buf += INK_MIN_ALIGN;
487 return val;
488 }
489
490 /*-------------------------------------------------------------------------
491 -------------------------------------------------------------------------*/
492
493 int
marshal_proxy_resp_all_header_fields(char * buf)494 LogAccess::marshal_proxy_resp_all_header_fields(char *buf)
495 {
496 return LogUtils::marshalMimeHdr(m_proxy_response, buf);
497 }
498
499 /*-------------------------------------------------------------------------
500 -------------------------------------------------------------------------*/
501
502 /*-------------------------------------------------------------------------
503 unmarshal_itoa
504
505 This routine provides a fast conversion from a binary int to a string.
506 It returns the number of characters formatted. "dest" must point to the
507 LAST character of an array large enough to store the complete formatted
508 number.
509 -------------------------------------------------------------------------*/
510
511 int
unmarshal_itoa(int64_t val,char * dest,int field_width,char leading_char)512 LogAccess::unmarshal_itoa(int64_t val, char *dest, int field_width, char leading_char)
513 {
514 ink_assert(dest != nullptr);
515
516 char *p = dest;
517 bool negative = false;
518
519 if (val < 0) {
520 negative = true;
521 val = -val;
522 }
523
524 do {
525 *p-- = '0' + (val % 10);
526 val /= 10;
527 } while (val);
528
529 while (dest - p < field_width) {
530 *p-- = leading_char;
531 }
532
533 if (negative) {
534 *p-- = '-';
535 }
536
537 return static_cast<int>(dest - p);
538 }
539
540 /*-------------------------------------------------------------------------
541 unmarshal_itox
542
543 This routine provides a fast conversion from a binary int to a hex string.
544 It returns the number of characters formatted. "dest" must point to the
545 LAST character of an array large enough to store the complete formatted
546 number.
547 -------------------------------------------------------------------------*/
548
549 int
unmarshal_itox(int64_t val,char * dest,int field_width,char leading_char)550 LogAccess::unmarshal_itox(int64_t val, char *dest, int field_width, char leading_char)
551 {
552 ink_assert(dest != nullptr);
553
554 char *p = dest;
555 static char table[] = "0123456789abcdef?";
556
557 for (int i = 0; i < static_cast<int>(sizeof(int64_t) * 2); i++) {
558 *p-- = table[val & 0xf];
559 val >>= 4;
560 }
561 while (dest - p < field_width) {
562 *p-- = leading_char;
563 }
564
565 return static_cast<int64_t>(dest - p);
566 }
567
568 /*-------------------------------------------------------------------------
569 LogAccess::unmarshal_int_to_str
570
571 Return the string representation of the integer pointed at by buf.
572 -------------------------------------------------------------------------*/
573
574 int
unmarshal_int_to_str(char ** buf,char * dest,int len)575 LogAccess::unmarshal_int_to_str(char **buf, char *dest, int len)
576 {
577 ink_assert(buf != nullptr);
578 ink_assert(*buf != nullptr);
579 ink_assert(dest != nullptr);
580
581 char val_buf[128];
582 int64_t val = unmarshal_int(buf);
583 int val_len = unmarshal_itoa(val, val_buf + 127);
584
585 if (val_len < len) {
586 memcpy(dest, val_buf + 128 - val_len, val_len);
587 return val_len;
588 }
589 return -1;
590 }
591
592 /*-------------------------------------------------------------------------
593 LogAccess::unmarshal_int_to_str_hex
594
595 Return the string representation (hexadecimal) of the integer pointed at by buf.
596 -------------------------------------------------------------------------*/
597
598 int
unmarshal_int_to_str_hex(char ** buf,char * dest,int len)599 LogAccess::unmarshal_int_to_str_hex(char **buf, char *dest, int len)
600 {
601 ink_assert(buf != nullptr);
602 ink_assert(*buf != nullptr);
603 ink_assert(dest != nullptr);
604
605 char val_buf[128];
606 int64_t val = unmarshal_int(buf);
607 int val_len = unmarshal_itox(val, val_buf + 127);
608
609 if (val_len < len) {
610 memcpy(dest, val_buf + 128 - val_len, val_len);
611 return val_len;
612 }
613 return -1;
614 }
615
616 /*-------------------------------------------------------------------------
617 -------------------------------------------------------------------------*/
618
619 int
marshal_proxy_req_all_header_fields(char * buf)620 LogAccess::marshal_proxy_req_all_header_fields(char *buf)
621 {
622 return LogUtils::marshalMimeHdr(m_proxy_request, buf);
623 }
624
625 /*-------------------------------------------------------------------------
626 -------------------------------------------------------------------------*/
627
628 /*-------------------------------------------------------------------------
629 LogAccess::unmarshal_str
630
631 Retrieve the string from the location pointed at by the buffer and
632 advance the pointer past the string. The local strlen function is used
633 to advance the pointer, thus matching the corresponding strlen that was
634 used to lay the string into the buffer.
635 -------------------------------------------------------------------------*/
636
637 int
unmarshal_str(char ** buf,char * dest,int len,LogSlice * slice)638 LogAccess::unmarshal_str(char **buf, char *dest, int len, LogSlice *slice)
639 {
640 ink_assert(buf != nullptr);
641 ink_assert(*buf != nullptr);
642 ink_assert(dest != nullptr);
643
644 char *val_buf = *buf;
645 int val_len = static_cast<int>(::strlen(val_buf));
646
647 *buf += LogAccess::strlen(val_buf); // this is how it was stored
648
649 if (slice && slice->m_enable) {
650 int offset, n;
651
652 n = slice->toStrOffset(val_len, &offset);
653 if (n <= 0) {
654 return 0;
655 }
656
657 if (n >= len) {
658 return -1;
659 }
660
661 memcpy(dest, (val_buf + offset), n);
662 return n;
663 }
664
665 if (val_len < len) {
666 memcpy(dest, val_buf, val_len);
667 return val_len;
668 }
669 return -1;
670 }
671
672 int
unmarshal_ttmsf(char ** buf,char * dest,int len)673 LogAccess::unmarshal_ttmsf(char **buf, char *dest, int len)
674 {
675 ink_assert(buf != nullptr);
676 ink_assert(*buf != nullptr);
677 ink_assert(dest != nullptr);
678
679 int64_t val = unmarshal_int(buf);
680 double secs = static_cast<double>(val) / 1000;
681 int val_len = snprintf(dest, len, "%.3f", secs);
682 return val_len;
683 }
684
685 int
unmarshal_int_to_date_str(char ** buf,char * dest,int len)686 LogAccess::unmarshal_int_to_date_str(char **buf, char *dest, int len)
687 {
688 ink_assert(buf != nullptr);
689 ink_assert(*buf != nullptr);
690 ink_assert(dest != nullptr);
691
692 int64_t value = unmarshal_int(buf);
693 char *strval = LogUtils::timestamp_to_date_str(value);
694 int strlen = static_cast<int>(::strlen(strval));
695
696 memcpy(dest, strval, strlen);
697 return strlen;
698 }
699
700 int
unmarshal_int_to_time_str(char ** buf,char * dest,int len)701 LogAccess::unmarshal_int_to_time_str(char **buf, char *dest, int len)
702 {
703 ink_assert(buf != nullptr);
704 ink_assert(*buf != nullptr);
705 ink_assert(dest != nullptr);
706
707 int64_t value = unmarshal_int(buf);
708 char *strval = LogUtils::timestamp_to_time_str(value);
709 int strlen = static_cast<int>(::strlen(strval));
710
711 memcpy(dest, strval, strlen);
712 return strlen;
713 }
714
715 /*-------------------------------------------------------------------------
716 -------------------------------------------------------------------------*/
717
718 int
marshal_server_resp_all_header_fields(char * buf)719 LogAccess::marshal_server_resp_all_header_fields(char *buf)
720 {
721 return LogUtils::marshalMimeHdr(m_server_response, buf);
722 }
723
724 /*-------------------------------------------------------------------------
725 -------------------------------------------------------------------------*/
726
727 int
unmarshal_int_to_netscape_str(char ** buf,char * dest,int len)728 LogAccess::unmarshal_int_to_netscape_str(char **buf, char *dest, int len)
729 {
730 ink_assert(buf != nullptr);
731 ink_assert(*buf != nullptr);
732 ink_assert(dest != nullptr);
733
734 int64_t value = unmarshal_int(buf);
735 char *strval = LogUtils::timestamp_to_netscape_str(value);
736 int strlen = static_cast<int>(::strlen(strval));
737
738 memcpy(dest, strval, strlen);
739 return strlen;
740 }
741
742 /*-------------------------------------------------------------------------
743 LogAccess::unmarshal_http_method
744
745 Retrieve the int pointed at by the buffer and treat as an HttpMethod
746 enumerated type. Then lookup the string representation for that enum and
747 return the string. Advance the buffer pointer past the enum.
748 -------------------------------------------------------------------------*/
749 /*
750 int
751 LogAccess::unmarshal_http_method (char **buf, char *dest, int len)
752 {
753 return unmarshal_str (buf, dest, len);
754 }
755 */
756
757 int
marshal_cache_resp_all_header_fields(char * buf)758 LogAccess::marshal_cache_resp_all_header_fields(char *buf)
759 {
760 return LogUtils::marshalMimeHdr(m_cache_response, buf);
761 }
762
763 /*-------------------------------------------------------------------------
764 LogAccess::unmarshal_http_version
765
766 The http version is marshalled as two consecutive integers, the first for
767 the major number and the second for the minor number. Retrieve both
768 numbers and return the result as "HTTP/major.minor".
769 -------------------------------------------------------------------------*/
770
771 int
unmarshal_http_version(char ** buf,char * dest,int len)772 LogAccess::unmarshal_http_version(char **buf, char *dest, int len)
773 {
774 ink_assert(buf != nullptr);
775 ink_assert(*buf != nullptr);
776 ink_assert(dest != nullptr);
777
778 static const char *http = "HTTP/";
779 static int http_len = static_cast<int>(::strlen(http));
780
781 char val_buf[128];
782 char *p = val_buf;
783
784 memcpy(p, http, http_len);
785 p += http_len;
786
787 int res1 = unmarshal_int_to_str(buf, p, 128 - http_len);
788 if (res1 < 0) {
789 return -1;
790 }
791 p += res1;
792 *p++ = '.';
793 int res2 = unmarshal_int_to_str(buf, p, 128 - http_len - res1 - 1);
794 if (res2 < 0) {
795 return -1;
796 }
797
798 int val_len = http_len + res1 + res2 + 1;
799 if (val_len < len) {
800 memcpy(dest, val_buf, val_len);
801 return val_len;
802 }
803 return -1;
804 }
805
806 /*-------------------------------------------------------------------------
807 LogAccess::unmarshal_http_text
808
809 The http text is simply the fields http_method (cqhm) + url (cqu) +
810 http_version (cqhv), all right next to each other, in that order.
811 -------------------------------------------------------------------------*/
812
813 int
unmarshal_http_text(char ** buf,char * dest,int len,LogSlice * slice)814 LogAccess::unmarshal_http_text(char **buf, char *dest, int len, LogSlice *slice)
815 {
816 ink_assert(buf != nullptr);
817 ink_assert(*buf != nullptr);
818 ink_assert(dest != nullptr);
819
820 char *p = dest;
821
822 // int res1 = unmarshal_http_method (buf, p, len);
823 int res1 = unmarshal_str(buf, p, len);
824 if (res1 < 0) {
825 return -1;
826 }
827 p += res1;
828 *p++ = ' ';
829 int res2 = unmarshal_str(buf, p, len - res1 - 1, slice);
830 if (res2 < 0) {
831 return -1;
832 }
833 p += res2;
834 *p++ = ' ';
835 int res3 = unmarshal_http_version(buf, p, len - res1 - res2 - 2);
836 if (res3 < 0) {
837 return -1;
838 }
839 return res1 + res2 + res3 + 2;
840 }
841
842 /*-------------------------------------------------------------------------
843 LogAccess::unmarshal_http_status
844
845 An http response status code (pssc,sssc) is just an INT, but it's always
846 formatted with three digits and leading zeros. So, we need a special
847 version of unmarshal_int_to_str that does this leading zero formatting.
848 -------------------------------------------------------------------------*/
849
850 int
unmarshal_http_status(char ** buf,char * dest,int len)851 LogAccess::unmarshal_http_status(char **buf, char *dest, int len)
852 {
853 ink_assert(buf != nullptr);
854 ink_assert(*buf != nullptr);
855 ink_assert(dest != nullptr);
856
857 char val_buf[128];
858 int64_t val = unmarshal_int(buf);
859 int val_len = unmarshal_itoa(val, val_buf + 127, 3, '0');
860 if (val_len < len) {
861 memcpy(dest, val_buf + 128 - val_len, val_len);
862 return val_len;
863 }
864 return -1;
865 }
866
867 /*-------------------------------------------------------------------------
868 LogAccess::unmarshal_ip
869
870 Retrieve an IP address directly.
871 -------------------------------------------------------------------------*/
872 int
unmarshal_ip(char ** buf,IpEndpoint * dest)873 LogAccess::unmarshal_ip(char **buf, IpEndpoint *dest)
874 {
875 int len = sizeof(LogFieldIp); // of object processed.
876
877 ink_assert(buf != nullptr);
878 ink_assert(*buf != nullptr);
879 ink_assert(dest != nullptr);
880
881 LogFieldIp *raw = reinterpret_cast<LogFieldIp *>(*buf);
882 if (AF_INET == raw->_family) {
883 LogFieldIp4 *ip4 = static_cast<LogFieldIp4 *>(raw);
884 ats_ip4_set(dest, ip4->_addr);
885 len = sizeof(*ip4);
886 } else if (AF_INET6 == raw->_family) {
887 LogFieldIp6 *ip6 = static_cast<LogFieldIp6 *>(raw);
888 ats_ip6_set(dest, ip6->_addr);
889 len = sizeof(*ip6);
890 } else {
891 ats_ip_invalidate(dest);
892 }
893 len = INK_ALIGN_DEFAULT(len);
894 *buf += len;
895 return len;
896 }
897
898 /*-------------------------------------------------------------------------
899 LogAccess::unmarshal_ip_to_str
900
901 Retrieve the IP addresspointed at by the buffer and convert to a
902 string in standard format. The string is written to @a dest and its
903 length (not including nul) is returned. @a *buf is advanced.
904 -------------------------------------------------------------------------*/
905
906 int
unmarshal_ip_to_str(char ** buf,char * dest,int len)907 LogAccess::unmarshal_ip_to_str(char **buf, char *dest, int len)
908 {
909 IpEndpoint ip;
910 int zret = -1;
911
912 if (len > 0) {
913 unmarshal_ip(buf, &ip);
914 if (!ats_is_ip(&ip)) {
915 *dest = '0';
916 zret = 1;
917 } else if (ats_ip_ntop(&ip, dest, len)) {
918 zret = static_cast<int>(::strlen(dest));
919 }
920 }
921 return zret;
922 }
923
924 /*-------------------------------------------------------------------------
925 LogAccess::unmarshal_ip_to_hex
926
927 Retrieve the int pointed at by the buffer and treat as an IP
928 address. Convert to a string in byte oriented hexadeciaml and
929 return the string. Advance the buffer pointer.
930 -------------------------------------------------------------------------*/
931
932 int
unmarshal_ip_to_hex(char ** buf,char * dest,int len)933 LogAccess::unmarshal_ip_to_hex(char **buf, char *dest, int len)
934 {
935 int zret = -1;
936 IpEndpoint ip;
937
938 if (len > 0) {
939 unmarshal_ip(buf, &ip);
940 if (!ats_is_ip(&ip)) {
941 *dest = '0';
942 zret = 1;
943 } else {
944 zret = ats_ip_to_hex(&ip.sa, dest, len);
945 }
946 }
947 return zret;
948 }
949
950 /*-------------------------------------------------------------------------
951 LogAccess::unmarshal_hierarchy
952
953 Retrieve the int pointed at by the buffer and treat as a
954 SquidHierarchyCode. Use this as an index into the local string
955 conversion tables and return the string equivalent to the enum.
956 Advance the buffer pointer.
957 -------------------------------------------------------------------------*/
958
959 int
unmarshal_hierarchy(char ** buf,char * dest,int len,const Ptr<LogFieldAliasMap> & map)960 LogAccess::unmarshal_hierarchy(char **buf, char *dest, int len, const Ptr<LogFieldAliasMap> &map)
961 {
962 ink_assert(buf != nullptr);
963 ink_assert(*buf != nullptr);
964 ink_assert(dest != nullptr);
965
966 return (LogAccess::unmarshal_with_map(unmarshal_int(buf), dest, len, map, "INVALID_CODE"));
967 }
968
969 /*-------------------------------------------------------------------------
970 LogAccess::unmarshal_finish_status
971
972 Retrieve the int pointed at by the buffer and treat as a finish code.
973 Use the enum as an index into a string table and return the string equiv
974 of the enum. Advance the pointer.
975 -------------------------------------------------------------------------*/
976
977 int
unmarshal_finish_status(char ** buf,char * dest,int len,const Ptr<LogFieldAliasMap> & map)978 LogAccess::unmarshal_finish_status(char **buf, char *dest, int len, const Ptr<LogFieldAliasMap> &map)
979 {
980 ink_assert(buf != nullptr);
981 ink_assert(*buf != nullptr);
982 ink_assert(dest != nullptr);
983
984 return (LogAccess::unmarshal_with_map(unmarshal_int(buf), dest, len, map, "UNKNOWN_FINISH_CODE"));
985 }
986
987 /*-------------------------------------------------------------------------
988 LogAccess::unmarshal_cache_code
989
990 Retrieve the int pointed at by the buffer and treat as a SquidLogCode.
991 Use this to index into the local string tables and return the string
992 equiv of the enum. Advance the pointer.
993 -------------------------------------------------------------------------*/
994
995 int
unmarshal_cache_code(char ** buf,char * dest,int len,const Ptr<LogFieldAliasMap> & map)996 LogAccess::unmarshal_cache_code(char **buf, char *dest, int len, const Ptr<LogFieldAliasMap> &map)
997 {
998 ink_assert(buf != nullptr);
999 ink_assert(*buf != nullptr);
1000 ink_assert(dest != nullptr);
1001
1002 return (LogAccess::unmarshal_with_map(unmarshal_int(buf), dest, len, map, "ERROR_UNKNOWN"));
1003 }
1004
1005 /*-------------------------------------------------------------------------
1006 LogAccess::unmarshal_cache_hit_miss
1007
1008 Retrieve the int pointed at by the buffer and treat as a SquidHitMissCode.
1009 Use this to index into the local string tables and return the string
1010 equiv of the enum. Advance the pointer.
1011 -------------------------------------------------------------------------*/
1012
1013 int
unmarshal_cache_hit_miss(char ** buf,char * dest,int len,const Ptr<LogFieldAliasMap> & map)1014 LogAccess::unmarshal_cache_hit_miss(char **buf, char *dest, int len, const Ptr<LogFieldAliasMap> &map)
1015 {
1016 ink_assert(buf != nullptr);
1017 ink_assert(*buf != nullptr);
1018 ink_assert(dest != nullptr);
1019
1020 return (LogAccess::unmarshal_with_map(unmarshal_int(buf), dest, len, map, "HIT_MISS_UNKNOWN"));
1021 }
1022
1023 int
unmarshal_cache_write_code(char ** buf,char * dest,int len,const Ptr<LogFieldAliasMap> & map)1024 LogAccess::unmarshal_cache_write_code(char **buf, char *dest, int len, const Ptr<LogFieldAliasMap> &map)
1025 {
1026 ink_assert(buf != nullptr);
1027 ink_assert(*buf != nullptr);
1028 ink_assert(dest != nullptr);
1029
1030 return (LogAccess::unmarshal_with_map(unmarshal_int(buf), dest, len, map, "UNKNOWN_CACHE_WRITE_CODE"));
1031 }
1032
1033 int
unmarshal_record(char ** buf,char * dest,int len)1034 LogAccess::unmarshal_record(char **buf, char *dest, int len)
1035 {
1036 ink_assert(buf != nullptr);
1037 ink_assert(*buf != nullptr);
1038 ink_assert(dest != nullptr);
1039
1040 char *val_buf = *buf;
1041 int val_len = static_cast<int>(::strlen(val_buf));
1042 *buf += MARSHAL_RECORD_LENGTH; // this is how it was stored
1043 if (val_len < len) {
1044 memcpy(dest, val_buf, val_len);
1045 return val_len;
1046 }
1047 return -1;
1048 }
1049
1050 /*-------------------------------------------------------------------------
1051 resolve_logfield_string
1052
1053 This function resolves the given custom log format string using the given
1054 LogAccess context and returns the resulting string, which is ats_malloc'd.
1055 The caller is responsible for ats_free'ing the return result. If there are
1056 any problems, NULL is returned.
1057 -------------------------------------------------------------------------*/
1058 char *
resolve_logfield_string(LogAccess * context,const char * format_str)1059 resolve_logfield_string(LogAccess *context, const char *format_str)
1060 {
1061 if (!context) {
1062 Debug("log-resolve", "No context to resolve?");
1063 return nullptr;
1064 }
1065
1066 if (!format_str) {
1067 Debug("log-resolve", "No format to resolve?");
1068 return nullptr;
1069 }
1070
1071 Debug("log-resolve", "Resolving: %s", format_str);
1072
1073 //
1074 // Divide the format string into two parts: one for the printf-style
1075 // string and one for the symbols.
1076 //
1077 char *printf_str = nullptr;
1078 char *fields_str = nullptr;
1079 int n_fields = LogFormat::parse_format_string(format_str, &printf_str, &fields_str);
1080
1081 //
1082 // Perhaps there were no fields to resolve? Then just return the
1083 // format_str. Nothing to free here either.
1084 //
1085 if (!n_fields) {
1086 Debug("log-resolve", "No fields found; returning copy of format_str");
1087 ats_free(printf_str);
1088 ats_free(fields_str);
1089 return ats_strdup(format_str);
1090 }
1091
1092 Debug("log-resolve", "%d fields: %s", n_fields, fields_str);
1093 Debug("log-resolve", "printf string: %s", printf_str);
1094
1095 LogFieldList fields;
1096 bool contains_aggregates;
1097 int field_count = LogFormat::parse_symbol_string(fields_str, &fields, &contains_aggregates);
1098
1099 if (field_count != n_fields) {
1100 Error("format_str contains %d invalid field symbols", n_fields - field_count);
1101 ats_free(printf_str);
1102 ats_free(fields_str);
1103 return nullptr;
1104 }
1105 //
1106 // Ok, now marshal the data out of the LogAccess object and into a
1107 // temporary storage buffer. Make sure the LogAccess context is
1108 // initialized first.
1109 //
1110 Debug("log-resolve", "Marshaling data from LogAccess into buffer ...");
1111 context->init();
1112 unsigned bytes_needed = fields.marshal_len(context);
1113 char *buf = static_cast<char *>(ats_malloc(bytes_needed));
1114 unsigned bytes_used = fields.marshal(context, buf);
1115
1116 ink_assert(bytes_needed == bytes_used);
1117 Debug("log-resolve", " %u bytes marshalled", bytes_used);
1118
1119 //
1120 // Now we can "unmarshal" the data from the buffer into a string,
1121 // combining it with the data from the printf string. The problem is,
1122 // we're not sure how much space it will take when it's unmarshalled.
1123 // So, we'll just guess.
1124 //
1125 char *result = static_cast<char *>(ats_malloc(8192));
1126 unsigned bytes_resolved =
1127 LogBuffer::resolve_custom_entry(&fields, printf_str, buf, result, 8191, LogUtils::timestamp(), 0, LOG_SEGMENT_VERSION);
1128 ink_assert(bytes_resolved < 8192);
1129
1130 if (!bytes_resolved) {
1131 ats_free(result);
1132 result = nullptr;
1133 } else {
1134 result[bytes_resolved] = 0; // NULL terminate
1135 }
1136
1137 ats_free(printf_str);
1138 ats_free(fields_str);
1139 ats_free(buf);
1140
1141 return result;
1142 }
1143 void
set_client_req_url(char * buf,int len)1144 LogAccess::set_client_req_url(char *buf, int len)
1145 {
1146 if (buf) {
1147 m_client_req_url_len = std::min(len, m_client_req_url_len);
1148 ink_strlcpy(m_client_req_url_str, buf, m_client_req_url_len + 1);
1149 }
1150 }
1151
1152 void
set_client_req_url_canon(char * buf,int len)1153 LogAccess::set_client_req_url_canon(char *buf, int len)
1154 {
1155 if (buf) {
1156 m_client_req_url_canon_len = std::min(len, m_client_req_url_canon_len);
1157 ink_strlcpy(m_client_req_url_canon_str, buf, m_client_req_url_canon_len + 1);
1158 }
1159 }
1160
1161 void
set_client_req_unmapped_url_canon(char * buf,int len)1162 LogAccess::set_client_req_unmapped_url_canon(char *buf, int len)
1163 {
1164 if (buf && m_client_req_unmapped_url_canon_str) {
1165 m_client_req_unmapped_url_canon_len = std::min(len, m_client_req_unmapped_url_canon_len);
1166 ink_strlcpy(m_client_req_unmapped_url_canon_str, buf, m_client_req_unmapped_url_canon_len + 1);
1167 }
1168 }
1169
1170 void
set_client_req_unmapped_url_path(char * buf,int len)1171 LogAccess::set_client_req_unmapped_url_path(char *buf, int len)
1172 {
1173 if (buf && m_client_req_unmapped_url_path_str) {
1174 m_client_req_unmapped_url_path_len = std::min(len, m_client_req_unmapped_url_path_len);
1175 ink_strlcpy(m_client_req_unmapped_url_path_str, buf, m_client_req_unmapped_url_path_len + 1);
1176 }
1177 }
1178
1179 void
set_client_req_unmapped_url_host(char * buf,int len)1180 LogAccess::set_client_req_unmapped_url_host(char *buf, int len)
1181 {
1182 if (buf && m_client_req_unmapped_url_host_str) {
1183 m_client_req_unmapped_url_host_len = std::min(len, m_client_req_unmapped_url_host_len);
1184 ink_strlcpy(m_client_req_unmapped_url_host_str, buf, m_client_req_unmapped_url_host_len + 1);
1185 }
1186 }
1187
1188 void
set_client_req_url_path(char * buf,int len)1189 LogAccess::set_client_req_url_path(char *buf, int len)
1190 {
1191 //?? use m_client_req_unmapped_url_path_str for now..may need to enhance later..
1192 if (buf && m_client_req_unmapped_url_path_str) {
1193 m_client_req_url_path_len = std::min(len, m_client_req_url_path_len);
1194 ink_strlcpy(m_client_req_unmapped_url_path_str, buf, m_client_req_url_path_len + 1);
1195 }
1196 }
1197
1198 /*-------------------------------------------------------------------------
1199 The marshalling routines ...
1200
1201 We know that m_http_sm is a valid pointer (we assert so in the ctor), but
1202 we still need to check the other header pointers before using them in the
1203 routines.
1204 -------------------------------------------------------------------------*/
1205
1206 /*-------------------------------------------------------------------------
1207 -------------------------------------------------------------------------*/
1208 int
marshal_plugin_identity_id(char * buf)1209 LogAccess::marshal_plugin_identity_id(char *buf)
1210 {
1211 if (buf) {
1212 marshal_int(buf, m_http_sm->plugin_id);
1213 }
1214 return INK_MIN_ALIGN;
1215 }
1216
1217 int
marshal_plugin_identity_tag(char * buf)1218 LogAccess::marshal_plugin_identity_tag(char *buf)
1219 {
1220 int len = INK_MIN_ALIGN;
1221 const char *tag = m_http_sm->plugin_tag;
1222
1223 if (!tag) {
1224 tag = "*";
1225 } else {
1226 len = LogAccess::strlen(tag);
1227 }
1228
1229 if (buf) {
1230 marshal_str(buf, tag, len);
1231 }
1232
1233 return len;
1234 }
1235
1236 int
marshal_client_host_ip(char * buf)1237 LogAccess::marshal_client_host_ip(char *buf)
1238 {
1239 return marshal_ip(buf, &m_http_sm->t_state.client_info.src_addr.sa);
1240 }
1241
1242 int
marshal_host_interface_ip(char * buf)1243 LogAccess::marshal_host_interface_ip(char *buf)
1244 {
1245 return marshal_ip(buf, &m_http_sm->t_state.client_info.dst_addr.sa);
1246 }
1247
1248 /*-------------------------------------------------------------------------
1249 -------------------------------------------------------------------------*/
1250 int
marshal_cache_lookup_url_canon(char * buf)1251 LogAccess::marshal_cache_lookup_url_canon(char *buf)
1252 {
1253 int len = INK_MIN_ALIGN;
1254
1255 validate_lookup_url();
1256 if (m_cache_lookup_url_canon_str == INVALID_STR) {
1257 // If the lookup URL isn't populated, we'll fall back to the request URL.
1258 len = marshal_client_req_url_canon(buf);
1259 } else {
1260 len = round_strlen(m_cache_lookup_url_canon_len + 1); // +1 for eos
1261 if (buf) {
1262 marshal_mem(buf, m_cache_lookup_url_canon_str, m_cache_lookup_url_canon_len, len);
1263 }
1264 }
1265
1266 return len;
1267 }
1268
1269 /*-------------------------------------------------------------------------
1270 -------------------------------------------------------------------------*/
1271 int
marshal_client_sni_server_name(char * buf)1272 LogAccess::marshal_client_sni_server_name(char *buf)
1273 {
1274 // NOTE: For this string_view, data() must always be nul-terminated, but the nul character must not be included in
1275 // the length.
1276 //
1277 std::string_view server_name = "";
1278
1279 if (m_http_sm) {
1280 auto txn = m_http_sm->get_ua_txn();
1281 if (txn) {
1282 auto ssn = txn->get_proxy_ssn();
1283 if (ssn) {
1284 auto ssl = ssn->ssl();
1285 if (ssl) {
1286 auto server_name_str = ssl->client_sni_server_name();
1287 if (server_name_str) {
1288 server_name = server_name_str;
1289 }
1290 }
1291 }
1292 }
1293 }
1294 int len = round_strlen(server_name.length() + 1);
1295 if (buf) {
1296 marshal_str(buf, server_name.data(), len);
1297 }
1298 return len;
1299 }
1300
1301 /*-------------------------------------------------------------------------
1302 -------------------------------------------------------------------------*/
1303 int
marshal_client_provided_cert(char * buf)1304 LogAccess::marshal_client_provided_cert(char *buf)
1305 {
1306 int provided_cert = 0;
1307 if (m_http_sm) {
1308 auto txn = m_http_sm->get_ua_txn();
1309 if (txn) {
1310 auto ssn = txn->get_proxy_ssn();
1311 if (ssn) {
1312 auto ssl = ssn->ssl();
1313 if (ssl) {
1314 provided_cert = ssl->client_provided_certificate();
1315 }
1316 }
1317 }
1318 }
1319 if (buf) {
1320 marshal_int(buf, provided_cert);
1321 }
1322 return INK_MIN_ALIGN;
1323 }
1324
1325 /*-------------------------------------------------------------------------
1326 -------------------------------------------------------------------------*/
1327 int
marshal_proxy_provided_cert(char * buf)1328 LogAccess::marshal_proxy_provided_cert(char *buf)
1329 {
1330 int provided_cert = 0;
1331 if (m_http_sm) {
1332 provided_cert = m_http_sm->server_connection_provided_cert;
1333 }
1334 if (buf) {
1335 marshal_int(buf, provided_cert);
1336 }
1337 return INK_MIN_ALIGN;
1338 }
1339 /*-------------------------------------------------------------------------
1340 -------------------------------------------------------------------------*/
1341
1342 int
marshal_version_build_number(char * buf)1343 LogAccess::marshal_version_build_number(char *buf)
1344 {
1345 int len = LogAccess::strlen(appVersionInfo.BldNumStr);
1346 if (buf) {
1347 marshal_str(buf, appVersionInfo.BldNumStr, len);
1348 }
1349 return len;
1350 }
1351
1352 /*-------------------------------------------------------------------------
1353 -------------------------------------------------------------------------*/
1354
1355 int
marshal_version_string(char * buf)1356 LogAccess::marshal_version_string(char *buf)
1357 {
1358 int len = LogAccess::strlen(appVersionInfo.VersionStr);
1359 if (buf) {
1360 marshal_str(buf, appVersionInfo.VersionStr, len);
1361 }
1362 return len;
1363 }
1364
1365 /*-------------------------------------------------------------------------
1366 -------------------------------------------------------------------------*/
1367
1368 int
marshal_proxy_protocol_version(char * buf)1369 LogAccess::marshal_proxy_protocol_version(char *buf)
1370 {
1371 const char *version_str = nullptr;
1372 int len = INK_MIN_ALIGN;
1373
1374 if (m_http_sm) {
1375 ProxyProtocolVersion ver = m_http_sm->t_state.pp_info.version;
1376 switch (ver) {
1377 case ProxyProtocolVersion::V1:
1378 version_str = "V1";
1379 break;
1380 case ProxyProtocolVersion::V2:
1381 version_str = "V2";
1382 break;
1383 case ProxyProtocolVersion::UNDEFINED:
1384 default:
1385 version_str = "-";
1386 break;
1387 }
1388 len = LogAccess::strlen(version_str);
1389 }
1390
1391 if (buf) {
1392 marshal_str(buf, version_str, len);
1393 }
1394 return len;
1395 }
1396
1397 /*-------------------------------------------------------------------------
1398 -------------------------------------------------------------------------*/
1399 int
marshal_proxy_protocol_src_ip(char * buf)1400 LogAccess::marshal_proxy_protocol_src_ip(char *buf)
1401 {
1402 sockaddr const *ip = nullptr;
1403 if (m_http_sm && m_http_sm->t_state.pp_info.version != ProxyProtocolVersion::UNDEFINED) {
1404 ip = &m_http_sm->t_state.pp_info.src_addr.sa;
1405 }
1406 return marshal_ip(buf, ip);
1407 }
1408
1409 /*-------------------------------------------------------------------------
1410 -------------------------------------------------------------------------*/
1411 int
marshal_proxy_protocol_dst_ip(char * buf)1412 LogAccess::marshal_proxy_protocol_dst_ip(char *buf)
1413 {
1414 sockaddr const *ip = nullptr;
1415 if (m_http_sm && m_http_sm->t_state.pp_info.version != ProxyProtocolVersion::UNDEFINED) {
1416 ip = &m_http_sm->t_state.pp_info.dst_addr.sa;
1417 }
1418 return marshal_ip(buf, ip);
1419 }
1420
1421 /*-------------------------------------------------------------------------
1422 -------------------------------------------------------------------------*/
1423 int
marshal_client_host_port(char * buf)1424 LogAccess::marshal_client_host_port(char *buf)
1425 {
1426 if (buf) {
1427 uint16_t port = ntohs(m_http_sm->t_state.client_info.src_addr.port());
1428 marshal_int(buf, port);
1429 }
1430 return INK_MIN_ALIGN;
1431 }
1432
1433 /*-------------------------------------------------------------------------
1434 user authenticated to the proxy (RFC931)
1435 -------------------------------------------------------------------------*/
1436
1437 int
marshal_client_auth_user_name(char * buf)1438 LogAccess::marshal_client_auth_user_name(char *buf)
1439 {
1440 char *str = nullptr;
1441 int len = INK_MIN_ALIGN;
1442
1443 // Jira TS-40:
1444 // NOTE: Authentication related code and modules were removed/disabled.
1445 // Uncomment code path below when re-added/enabled.
1446 /*if (m_http_sm->t_state.auth_params.user_name) {
1447 str = m_http_sm->t_state.auth_params.user_name;
1448 len = LogAccess::strlen(str);
1449 } */
1450 if (buf) {
1451 marshal_str(buf, str, len);
1452 }
1453 return len;
1454 }
1455
1456 /*-------------------------------------------------------------------------
1457 Private utility function to validate m_client_req_unmapped_url_canon_str &
1458 m_client_req_unmapped_url_canon_len fields.
1459 -------------------------------------------------------------------------*/
1460
1461 void
validate_unmapped_url()1462 LogAccess::validate_unmapped_url()
1463 {
1464 if (m_client_req_unmapped_url_canon_str == nullptr) {
1465 // prevent multiple validations
1466 m_client_req_unmapped_url_canon_str = INVALID_STR;
1467
1468 if (m_http_sm->t_state.unmapped_url.valid()) {
1469 int unmapped_url_len;
1470 char *unmapped_url = m_http_sm->t_state.unmapped_url.string_get_ref(&unmapped_url_len);
1471
1472 if (unmapped_url && unmapped_url[0] != 0) {
1473 m_client_req_unmapped_url_canon_str =
1474 LogUtils::escapify_url(&m_arena, unmapped_url, unmapped_url_len, &m_client_req_unmapped_url_canon_len);
1475 }
1476 }
1477 }
1478 }
1479
1480 /*-------------------------------------------------------------------------
1481 Private utility function to validate m_client_req_unmapped_url_path_str &
1482 m_client_req_unmapped_url_path_len fields.
1483 -------------------------------------------------------------------------*/
1484
1485 void
validate_unmapped_url_path()1486 LogAccess::validate_unmapped_url_path()
1487 {
1488 if (m_client_req_unmapped_url_path_str == nullptr && m_client_req_unmapped_url_host_str == nullptr) {
1489 // Use unmapped canonical URL as default
1490 m_client_req_unmapped_url_path_str = m_client_req_unmapped_url_canon_str;
1491 m_client_req_unmapped_url_path_len = m_client_req_unmapped_url_canon_len;
1492 // In case the code below fails, we prevent it from being used.
1493 m_client_req_unmapped_url_host_str = INVALID_STR;
1494
1495 if (m_client_req_unmapped_url_path_len >= 6) { // xxx:// - minimum schema size
1496 int len;
1497 char *c =
1498 static_cast<char *>(memchr((void *)m_client_req_unmapped_url_path_str, ':', m_client_req_unmapped_url_path_len - 1));
1499
1500 if (c && (len = static_cast<int>(c - m_client_req_unmapped_url_path_str)) <= 5) { // 5 - max schema size
1501 if (len + 2 <= m_client_req_unmapped_url_canon_len && c[1] == '/' && c[2] == '/') {
1502 len += 3; // Skip "://"
1503 m_client_req_unmapped_url_host_str = &m_client_req_unmapped_url_canon_str[len];
1504 m_client_req_unmapped_url_host_len = m_client_req_unmapped_url_path_len - len;
1505 // Attempt to find first '/' in the path
1506 if (m_client_req_unmapped_url_host_len > 0 &&
1507 (c = static_cast<char *>(
1508 memchr((void *)m_client_req_unmapped_url_host_str, '/', m_client_req_unmapped_url_path_len))) != nullptr) {
1509 m_client_req_unmapped_url_host_len = static_cast<int>(c - m_client_req_unmapped_url_host_str);
1510 m_client_req_unmapped_url_path_str = &m_client_req_unmapped_url_host_str[m_client_req_unmapped_url_host_len];
1511 m_client_req_unmapped_url_path_len = m_client_req_unmapped_url_path_len - len - m_client_req_unmapped_url_host_len;
1512 }
1513 }
1514 }
1515 }
1516 }
1517 }
1518
1519 /*-------------------------------------------------------------------------
1520 Private utility function to validate m_cache_lookup_url_canon_str &
1521 m_cache_lookup__url_canon_len fields.
1522 -------------------------------------------------------------------------*/
1523 void
validate_lookup_url()1524 LogAccess::validate_lookup_url()
1525 {
1526 if (m_cache_lookup_url_canon_str == nullptr) {
1527 // prevent multiple validations
1528 m_cache_lookup_url_canon_str = INVALID_STR;
1529
1530 if (m_http_sm->t_state.cache_info.lookup_url_storage.valid()) {
1531 int lookup_url_len;
1532 char *lookup_url = m_http_sm->t_state.cache_info.lookup_url_storage.string_get_ref(&lookup_url_len);
1533
1534 if (lookup_url && lookup_url[0] != 0) {
1535 m_cache_lookup_url_canon_str = LogUtils::escapify_url(&m_arena, lookup_url, lookup_url_len, &m_cache_lookup_url_canon_len);
1536 }
1537 }
1538 }
1539 }
1540
1541 /*-------------------------------------------------------------------------
1542 This is the method, url, and version all rolled into one. Use the
1543 respective marshalling routines to do the job.
1544 -------------------------------------------------------------------------*/
1545
1546 int
marshal_client_req_text(char * buf)1547 LogAccess::marshal_client_req_text(char *buf)
1548 {
1549 int len = marshal_client_req_http_method(nullptr) + marshal_client_req_url(nullptr) + marshal_client_req_http_version(nullptr);
1550
1551 if (buf) {
1552 int offset = 0;
1553 offset += marshal_client_req_http_method(&buf[offset]);
1554 offset += marshal_client_req_url(&buf[offset]);
1555 offset += marshal_client_req_http_version(&buf[offset]);
1556 len = offset;
1557 }
1558 return len;
1559 }
1560
1561 /*-------------------------------------------------------------------------
1562 -------------------------------------------------------------------------*/
1563
1564 int
marshal_client_req_timestamp_sec(char * buf)1565 LogAccess::marshal_client_req_timestamp_sec(char *buf)
1566 {
1567 return marshal_milestone_fmt_sec(TS_MILESTONE_UA_BEGIN, buf);
1568 }
1569
1570 /*-------------------------------------------------------------------------
1571 -------------------------------------------------------------------------*/
1572
1573 int
marshal_client_req_timestamp_ms(char * buf)1574 LogAccess::marshal_client_req_timestamp_ms(char *buf)
1575 {
1576 return marshal_milestone_fmt_ms(TS_MILESTONE_UA_BEGIN, buf);
1577 }
1578
1579 /*-------------------------------------------------------------------------
1580 -------------------------------------------------------------------------*/
1581
1582 int
marshal_client_req_http_method(char * buf)1583 LogAccess::marshal_client_req_http_method(char *buf)
1584 {
1585 char *str = nullptr;
1586 int alen = 0;
1587 int plen = INK_MIN_ALIGN;
1588
1589 if (m_client_request) {
1590 str = const_cast<char *>(m_client_request->method_get(&alen));
1591
1592 // calculate the the padded length only if the actual length
1593 // is not zero. We don't want the padded length to be zero
1594 // because marshal_mem should write the DEFAULT_STR to the
1595 // buffer if str is nil, and we need room for this.
1596 //
1597 if (alen) {
1598 plen = round_strlen(alen + 1); // +1 for trailing 0
1599 }
1600 }
1601
1602 if (buf) {
1603 marshal_mem(buf, str, alen, plen);
1604 }
1605 return plen;
1606 }
1607
1608 /*-------------------------------------------------------------------------
1609 -------------------------------------------------------------------------*/
1610
1611 int
marshal_client_req_url(char * buf)1612 LogAccess::marshal_client_req_url(char *buf)
1613 {
1614 int len = round_strlen(m_client_req_url_len + 1); // +1 for trailing 0
1615
1616 if (buf) {
1617 marshal_mem(buf, m_client_req_url_str, m_client_req_url_len, len);
1618 }
1619 return len;
1620 }
1621
1622 /*-------------------------------------------------------------------------
1623 -------------------------------------------------------------------------*/
1624
1625 int
marshal_client_req_url_canon(char * buf)1626 LogAccess::marshal_client_req_url_canon(char *buf)
1627 {
1628 int len = round_strlen(m_client_req_url_canon_len + 1);
1629
1630 if (buf) {
1631 marshal_mem(buf, m_client_req_url_canon_str, m_client_req_url_canon_len, len);
1632 }
1633 return len;
1634 }
1635
1636 /*-------------------------------------------------------------------------
1637 -------------------------------------------------------------------------*/
1638
1639 int
marshal_client_req_unmapped_url_canon(char * buf)1640 LogAccess::marshal_client_req_unmapped_url_canon(char *buf)
1641 {
1642 int len = INK_MIN_ALIGN;
1643
1644 validate_unmapped_url();
1645 if (m_client_req_unmapped_url_canon_str == INVALID_STR) {
1646 // If the unmapped URL isn't populated, we'll fall back to the original
1647 // client URL. This helps for example server intercepts to continue to
1648 // log the requests, even when there is no remap rule for it.
1649 len = marshal_client_req_url_canon(buf);
1650 } else {
1651 len = round_strlen(m_client_req_unmapped_url_canon_len + 1); // +1 for eos
1652 if (buf) {
1653 marshal_mem(buf, m_client_req_unmapped_url_canon_str, m_client_req_unmapped_url_canon_len, len);
1654 }
1655 }
1656
1657 return len;
1658 }
1659
1660 /*-------------------------------------------------------------------------
1661 -------------------------------------------------------------------------*/
1662
1663 int
marshal_client_req_unmapped_url_path(char * buf)1664 LogAccess::marshal_client_req_unmapped_url_path(char *buf)
1665 {
1666 int len = INK_MIN_ALIGN;
1667
1668 validate_unmapped_url();
1669 validate_unmapped_url_path();
1670
1671 if (m_client_req_unmapped_url_path_str == INVALID_STR) {
1672 len = marshal_client_req_url_path(buf);
1673 } else {
1674 len = round_strlen(m_client_req_unmapped_url_path_len + 1); // +1 for eos
1675 if (buf) {
1676 marshal_mem(buf, m_client_req_unmapped_url_path_str, m_client_req_unmapped_url_path_len, len);
1677 }
1678 }
1679 return len;
1680 }
1681
1682 /*-------------------------------------------------------------------------
1683 -------------------------------------------------------------------------*/
1684
1685 int
marshal_client_req_unmapped_url_host(char * buf)1686 LogAccess::marshal_client_req_unmapped_url_host(char *buf)
1687 {
1688 validate_unmapped_url();
1689 validate_unmapped_url_path();
1690
1691 int len = round_strlen(m_client_req_unmapped_url_host_len + 1); // +1 for eos
1692 if (buf) {
1693 marshal_mem(buf, m_client_req_unmapped_url_host_str, m_client_req_unmapped_url_host_len, len);
1694 }
1695
1696 return len;
1697 }
1698
1699 int
marshal_client_req_url_path(char * buf)1700 LogAccess::marshal_client_req_url_path(char *buf)
1701 {
1702 int len = round_strlen(m_client_req_url_path_len + 1);
1703 if (buf) {
1704 marshal_mem(buf, m_client_req_url_path_str, m_client_req_url_path_len, len);
1705 }
1706 return len;
1707 }
1708
1709 int
marshal_client_req_url_scheme(char * buf)1710 LogAccess::marshal_client_req_url_scheme(char *buf)
1711 {
1712 int scheme = m_http_sm->t_state.orig_scheme;
1713 const char *str = nullptr;
1714 int alen;
1715 int plen = INK_MIN_ALIGN;
1716
1717 // If the transaction aborts very early, the scheme may not be set, or so ASAN reports.
1718 if (scheme >= 0) {
1719 str = hdrtoken_index_to_wks(scheme);
1720 alen = hdrtoken_index_to_length(scheme);
1721 } else {
1722 str = "UNKNOWN";
1723 alen = strlen(str);
1724 }
1725
1726 // calculate the the padded length only if the actual length
1727 // is not zero. We don't want the padded length to be zero
1728 // because marshal_mem should write the DEFAULT_STR to the
1729 // buffer if str is nil, and we need room for this.
1730 //
1731 if (alen) {
1732 plen = round_strlen(alen + 1); // +1 for trailing 0
1733 }
1734
1735 if (buf) {
1736 marshal_mem(buf, str, alen, plen);
1737 }
1738
1739 return plen;
1740 }
1741
1742 /*-------------------------------------------------------------------------
1743 For this one we're going to marshal two INTs, one the first representing
1744 the major number and the second representing the minor.
1745 -------------------------------------------------------------------------*/
1746
1747 int
marshal_client_req_http_version(char * buf)1748 LogAccess::marshal_client_req_http_version(char *buf)
1749 {
1750 if (buf) {
1751 if (m_client_request) {
1752 HTTPVersion versionObject = m_client_request->version_get();
1753 marshal_int(buf, versionObject.get_major());
1754 marshal_int((buf + INK_MIN_ALIGN), versionObject.get_minor());
1755 } else {
1756 marshal_int(buf, 0);
1757 marshal_int((buf + INK_MIN_ALIGN), 0);
1758 }
1759 }
1760 return (2 * INK_MIN_ALIGN);
1761 }
1762
1763 /*-------------------------------------------------------------------------
1764 -------------------------------------------------------------------------*/
1765
1766 int
marshal_client_req_protocol_version(char * buf)1767 LogAccess::marshal_client_req_protocol_version(char *buf)
1768 {
1769 const char *protocol_str = m_http_sm->client_protocol;
1770 int len = LogAccess::strlen(protocol_str);
1771
1772 // Set major & minor versions when protocol_str is not "http/2".
1773 if (::strlen(protocol_str) == 4 && strncmp("http", protocol_str, 4) == 0) {
1774 if (m_client_request) {
1775 HTTPVersion versionObject = m_client_request->version_get();
1776 if (versionObject == HTTP_1_1) {
1777 protocol_str = "http/1.1";
1778 } else if (versionObject == HTTP_1_0) {
1779 protocol_str = "http/1.0";
1780 } // else invalid http version
1781 } else {
1782 protocol_str = "*";
1783 }
1784
1785 len = LogAccess::strlen(protocol_str);
1786 }
1787
1788 if (buf) {
1789 marshal_str(buf, protocol_str, len);
1790 }
1791
1792 return len;
1793 }
1794
1795 /*-------------------------------------------------------------------------
1796 -------------------------------------------------------------------------*/
1797
1798 int
marshal_server_req_protocol_version(char * buf)1799 LogAccess::marshal_server_req_protocol_version(char *buf)
1800 {
1801 const char *protocol_str = m_http_sm->server_protocol;
1802 int len = LogAccess::strlen(protocol_str);
1803
1804 // Set major & minor versions when protocol_str is not "http/2".
1805 if (::strlen(protocol_str) == 4 && strncmp("http", protocol_str, 4) == 0) {
1806 if (m_proxy_request) {
1807 HTTPVersion versionObject = m_proxy_request->version_get();
1808 if (versionObject == HTTP_1_1) {
1809 protocol_str = "http/1.1";
1810 } else if (versionObject == HTTP_1_0) {
1811 protocol_str = "http/1.0";
1812 } // else invalid http version
1813 } else {
1814 protocol_str = "*";
1815 }
1816
1817 len = LogAccess::strlen(protocol_str);
1818 }
1819
1820 if (buf) {
1821 marshal_str(buf, protocol_str, len);
1822 }
1823
1824 return len;
1825 }
1826
1827 /*-------------------------------------------------------------------------
1828 -------------------------------------------------------------------------*/
1829
1830 int
marshal_client_req_header_len(char * buf)1831 LogAccess::marshal_client_req_header_len(char *buf)
1832 {
1833 if (buf) {
1834 int64_t len = 0;
1835 if (m_client_request) {
1836 len = m_client_request->length_get();
1837 }
1838 marshal_int(buf, len);
1839 }
1840 return INK_MIN_ALIGN;
1841 }
1842
1843 /*-------------------------------------------------------------------------
1844 -------------------------------------------------------------------------*/
1845
1846 int
marshal_client_req_content_len(char * buf)1847 LogAccess::marshal_client_req_content_len(char *buf)
1848 {
1849 if (buf) {
1850 int64_t len = 0;
1851 if (m_client_request) {
1852 len = m_http_sm->client_request_body_bytes;
1853 }
1854 marshal_int(buf, len);
1855 }
1856 return INK_MIN_ALIGN;
1857 }
1858
1859 int
marshal_client_req_squid_len(char * buf)1860 LogAccess::marshal_client_req_squid_len(char *buf)
1861 {
1862 if (buf) {
1863 int64_t val = 0;
1864 if (m_client_request) {
1865 val = m_client_request->length_get() + m_http_sm->client_request_body_bytes;
1866 }
1867 marshal_int(buf, val);
1868 }
1869 return INK_MIN_ALIGN;
1870 }
1871
1872 /*-------------------------------------------------------------------------
1873 -------------------------------------------------------------------------*/
1874
1875 int
marshal_client_req_tcp_reused(char * buf)1876 LogAccess::marshal_client_req_tcp_reused(char *buf)
1877 {
1878 if (buf) {
1879 marshal_int(buf, m_http_sm->client_tcp_reused ? 1 : 0);
1880 }
1881 return INK_MIN_ALIGN;
1882 }
1883
1884 int
marshal_client_req_is_ssl(char * buf)1885 LogAccess::marshal_client_req_is_ssl(char *buf)
1886 {
1887 if (buf) {
1888 marshal_int(buf, m_http_sm->client_connection_is_ssl ? 1 : 0);
1889 }
1890 return INK_MIN_ALIGN;
1891 }
1892
1893 int
marshal_client_req_ssl_reused(char * buf)1894 LogAccess::marshal_client_req_ssl_reused(char *buf)
1895 {
1896 if (buf) {
1897 marshal_int(buf, m_http_sm->client_ssl_reused ? 1 : 0);
1898 }
1899 return INK_MIN_ALIGN;
1900 }
1901
1902 int
marshal_client_req_is_internal(char * buf)1903 LogAccess::marshal_client_req_is_internal(char *buf)
1904 {
1905 if (buf) {
1906 marshal_int(buf, m_http_sm->is_internal ? 1 : 0);
1907 }
1908 return INK_MIN_ALIGN;
1909 }
1910
1911 int
marshal_client_req_mptcp_state(char * buf)1912 LogAccess::marshal_client_req_mptcp_state(char *buf)
1913 {
1914 if (buf) {
1915 int val = -1;
1916
1917 if (m_http_sm->mptcp_state.has_value()) {
1918 val = m_http_sm->mptcp_state.value() ? 1 : 0;
1919 } else {
1920 }
1921 marshal_int(buf, val);
1922 }
1923 return INK_MIN_ALIGN;
1924 }
1925
1926 /*-------------------------------------------------------------------------
1927 -------------------------------------------------------------------------*/
1928
1929 int
marshal_client_finish_status_code(char * buf)1930 LogAccess::marshal_client_finish_status_code(char *buf)
1931 {
1932 if (buf) {
1933 int code = LOG_FINISH_FIN;
1934 HttpTransact::AbortState_t cl_abort_state = m_http_sm->t_state.client_info.abort;
1935 if (cl_abort_state == HttpTransact::ABORTED) {
1936 // Check to see if the abort is due to a timeout
1937 if (m_http_sm->t_state.client_info.state == HttpTransact::ACTIVE_TIMEOUT ||
1938 m_http_sm->t_state.client_info.state == HttpTransact::INACTIVE_TIMEOUT) {
1939 code = LOG_FINISH_TIMEOUT;
1940 } else {
1941 code = LOG_FINISH_INTR;
1942 }
1943 }
1944 marshal_int(buf, code);
1945 }
1946 return INK_MIN_ALIGN;
1947 }
1948
1949 /*-------------------------------------------------------------------------
1950 -------------------------------------------------------------------------*/
1951
1952 int
marshal_client_req_id(char * buf)1953 LogAccess::marshal_client_req_id(char *buf)
1954 {
1955 if (buf) {
1956 marshal_int(buf, m_http_sm->sm_id);
1957 }
1958 return INK_MIN_ALIGN;
1959 }
1960
1961 /*-------------------------------------------------------------------------
1962 -------------------------------------------------------------------------*/
1963
1964 int
marshal_client_req_uuid(char * buf)1965 LogAccess::marshal_client_req_uuid(char *buf)
1966 {
1967 char str[TS_CRUUID_STRING_LEN + 1];
1968 const char *uuid = Machine::instance()->uuid.getString();
1969 int len = snprintf(str, sizeof(str), "%s-%" PRId64 "", uuid, m_http_sm->sm_id);
1970
1971 ink_assert(len <= TS_CRUUID_STRING_LEN);
1972 len = round_strlen(len + 1);
1973
1974 if (buf) {
1975 marshal_str(buf, str, len); // This will pad the remaining bytes properly ...
1976 }
1977
1978 return len;
1979 }
1980
1981 /*-------------------------------------------------------------------------
1982 -------------------------------------------------------------------------*/
1983
1984 // 1 ('S'/'T' flag) + 8 (Error Code) + 1 ('\0')
1985 static constexpr size_t MAX_PROXY_ERROR_CODE_SIZE = 10;
1986
1987 int
marshal_client_rx_error_code(char * buf)1988 LogAccess::marshal_client_rx_error_code(char *buf)
1989 {
1990 char error_code[MAX_PROXY_ERROR_CODE_SIZE] = {0};
1991 m_http_sm->t_state.client_info.rx_error_code.str(error_code, sizeof(error_code));
1992 int round_len = LogAccess::strlen(error_code);
1993
1994 if (buf) {
1995 marshal_str(buf, error_code, round_len);
1996 }
1997
1998 return round_len;
1999 }
2000
2001 int
marshal_client_tx_error_code(char * buf)2002 LogAccess::marshal_client_tx_error_code(char *buf)
2003 {
2004 char error_code[MAX_PROXY_ERROR_CODE_SIZE] = {0};
2005 m_http_sm->t_state.client_info.tx_error_code.str(error_code, sizeof(error_code));
2006 int round_len = LogAccess::strlen(error_code);
2007
2008 if (buf) {
2009 marshal_str(buf, error_code, round_len);
2010 }
2011
2012 return round_len;
2013 }
2014
2015 /*-------------------------------------------------------------------------
2016 -------------------------------------------------------------------------*/
2017 int
marshal_client_security_protocol(char * buf)2018 LogAccess::marshal_client_security_protocol(char *buf)
2019 {
2020 const char *proto = m_http_sm->client_sec_protocol;
2021 int round_len = LogAccess::strlen(proto);
2022
2023 if (buf) {
2024 marshal_str(buf, proto, round_len);
2025 }
2026
2027 return round_len;
2028 }
2029
2030 int
marshal_client_security_cipher_suite(char * buf)2031 LogAccess::marshal_client_security_cipher_suite(char *buf)
2032 {
2033 const char *cipher = m_http_sm->client_cipher_suite;
2034 int round_len = LogAccess::strlen(cipher);
2035
2036 if (buf) {
2037 marshal_str(buf, cipher, round_len);
2038 }
2039
2040 return round_len;
2041 }
2042
2043 int
marshal_client_security_curve(char * buf)2044 LogAccess::marshal_client_security_curve(char *buf)
2045 {
2046 const char *curve = m_http_sm->client_curve;
2047 int round_len = LogAccess::strlen(curve);
2048
2049 if (buf) {
2050 marshal_str(buf, curve, round_len);
2051 }
2052
2053 return round_len;
2054 }
2055
2056 int
marshal_client_security_alpn(char * buf)2057 LogAccess::marshal_client_security_alpn(char *buf)
2058 {
2059 const char *alpn = "-";
2060 if (const int alpn_id = m_http_sm->client_alpn_id; alpn_id != SessionProtocolNameRegistry::INVALID) {
2061 ts::TextView client_sec_alpn = globalSessionProtocolNameRegistry.nameFor(alpn_id);
2062 alpn = client_sec_alpn.data();
2063 }
2064
2065 int round_len = LogAccess::strlen(alpn);
2066
2067 if (buf) {
2068 marshal_str(buf, alpn, round_len);
2069 }
2070
2071 return round_len;
2072 }
2073
2074 /*-------------------------------------------------------------------------
2075 -------------------------------------------------------------------------*/
2076
2077 int
marshal_proxy_resp_content_type(char * buf)2078 LogAccess::marshal_proxy_resp_content_type(char *buf)
2079 {
2080 int len = round_strlen(m_proxy_resp_content_type_len + 1);
2081 if (buf) {
2082 marshal_mem(buf, m_proxy_resp_content_type_str, m_proxy_resp_content_type_len, len);
2083 }
2084 return len;
2085 }
2086
2087 /*-------------------------------------------------------------------------
2088 -------------------------------------------------------------------------*/
2089
2090 int
marshal_proxy_resp_reason_phrase(char * buf)2091 LogAccess::marshal_proxy_resp_reason_phrase(char *buf)
2092 {
2093 int len = round_strlen(m_proxy_resp_reason_phrase_len + 1);
2094 if (buf) {
2095 marshal_mem(buf, m_proxy_resp_reason_phrase_str, m_proxy_resp_reason_phrase_len, len);
2096 }
2097 return len;
2098 }
2099
2100 /*-------------------------------------------------------------------------
2101 Squid returns the content-length + header length as the total length.
2102 -------------------------------------------------------------------------*/
2103
2104 int
marshal_proxy_resp_squid_len(char * buf)2105 LogAccess::marshal_proxy_resp_squid_len(char *buf)
2106 {
2107 if (buf) {
2108 int64_t val = m_http_sm->client_response_hdr_bytes + m_http_sm->client_response_body_bytes;
2109 marshal_int(buf, val);
2110 }
2111 return INK_MIN_ALIGN;
2112 }
2113
2114 /*-------------------------------------------------------------------------
2115 -------------------------------------------------------------------------*/
2116
2117 int
marshal_proxy_resp_content_len(char * buf)2118 LogAccess::marshal_proxy_resp_content_len(char *buf)
2119 {
2120 if (buf) {
2121 int64_t val = m_http_sm->client_response_body_bytes;
2122 marshal_int(buf, val);
2123 }
2124 return INK_MIN_ALIGN;
2125 }
2126
2127 /*-------------------------------------------------------------------------
2128 -------------------------------------------------------------------------*/
2129
2130 int
marshal_proxy_resp_status_code(char * buf)2131 LogAccess::marshal_proxy_resp_status_code(char *buf)
2132 {
2133 if (buf) {
2134 HTTPStatus status;
2135 if (m_proxy_response && m_client_request) {
2136 if (m_client_request->version_get() >= HTTPVersion(1, 0)) {
2137 status = m_proxy_response->status_get();
2138 }
2139 // INKqa10788
2140 // For bad/incomplete request, the request version may be 0.9.
2141 // However, we can still log the status code if there is one.
2142 else if (m_proxy_response->valid()) {
2143 status = m_proxy_response->status_get();
2144 } else {
2145 status = HTTP_STATUS_OK;
2146 }
2147 } else {
2148 status = HTTP_STATUS_NONE;
2149 }
2150 marshal_int(buf, static_cast<int64_t>(status));
2151 }
2152 return INK_MIN_ALIGN;
2153 }
2154
2155 /*-------------------------------------------------------------------------
2156 -------------------------------------------------------------------------*/
2157
2158 int
marshal_proxy_resp_header_len(char * buf)2159 LogAccess::marshal_proxy_resp_header_len(char *buf)
2160 {
2161 if (buf) {
2162 int64_t val = m_http_sm->client_response_hdr_bytes;
2163 marshal_int(buf, val);
2164 }
2165 return INK_MIN_ALIGN;
2166 }
2167
2168 int
marshal_proxy_finish_status_code(char * buf)2169 LogAccess::marshal_proxy_finish_status_code(char *buf)
2170 {
2171 /* FIXME: Should there be no server transaction code if
2172 the result comes out of the cache. Right now we default
2173 to FIN */
2174 if (buf) {
2175 int code = LOG_FINISH_FIN;
2176 if (m_http_sm->t_state.current.server) {
2177 switch (m_http_sm->t_state.current.server->state) {
2178 case HttpTransact::ACTIVE_TIMEOUT:
2179 case HttpTransact::INACTIVE_TIMEOUT:
2180 code = LOG_FINISH_TIMEOUT;
2181 break;
2182 case HttpTransact::CONNECTION_ERROR:
2183 code = LOG_FINISH_INTR;
2184 break;
2185 default:
2186 if (m_http_sm->t_state.current.server->abort == HttpTransact::ABORTED) {
2187 code = LOG_FINISH_INTR;
2188 }
2189 break;
2190 }
2191 }
2192
2193 marshal_int(buf, code);
2194 }
2195
2196 return INK_MIN_ALIGN;
2197 }
2198
2199 /*-------------------------------------------------------------------------
2200 -------------------------------------------------------------------------*/
2201 int
marshal_proxy_host_port(char * buf)2202 LogAccess::marshal_proxy_host_port(char *buf)
2203 {
2204 if (buf) {
2205 uint16_t port = m_http_sm->t_state.request_data.incoming_port;
2206 marshal_int(buf, port);
2207 }
2208 return INK_MIN_ALIGN;
2209 }
2210
2211 /*-------------------------------------------------------------------------
2212 -------------------------------------------------------------------------*/
2213
2214 int
marshal_cache_result_code(char * buf)2215 LogAccess::marshal_cache_result_code(char *buf)
2216 {
2217 if (buf) {
2218 SquidLogCode code = m_http_sm->t_state.squid_codes.log_code;
2219 marshal_int(buf, static_cast<int64_t>(code));
2220 }
2221 return INK_MIN_ALIGN;
2222 }
2223
2224 /*-------------------------------------------------------------------------
2225 -------------------------------------------------------------------------*/
2226
2227 int
marshal_cache_result_subcode(char * buf)2228 LogAccess::marshal_cache_result_subcode(char *buf)
2229 {
2230 if (buf) {
2231 SquidSubcode code = m_http_sm->t_state.squid_codes.subcode;
2232 marshal_int(buf, static_cast<int64_t>(code));
2233 }
2234 return INK_MIN_ALIGN;
2235 }
2236
2237 /*-------------------------------------------------------------------------
2238 -------------------------------------------------------------------------*/
2239
2240 int
marshal_cache_hit_miss(char * buf)2241 LogAccess::marshal_cache_hit_miss(char *buf)
2242 {
2243 if (buf) {
2244 SquidHitMissCode code = m_http_sm->t_state.squid_codes.hit_miss_code;
2245 marshal_int(buf, static_cast<int64_t>(code));
2246 }
2247 return INK_MIN_ALIGN;
2248 }
2249
2250 /*-------------------------------------------------------------------------
2251 -------------------------------------------------------------------------*/
2252
2253 int
marshal_proxy_req_header_len(char * buf)2254 LogAccess::marshal_proxy_req_header_len(char *buf)
2255 {
2256 if (buf) {
2257 int64_t val = 0;
2258 if (m_proxy_request) {
2259 val = m_proxy_request->length_get();
2260 }
2261 marshal_int(buf, val);
2262 }
2263 return INK_MIN_ALIGN;
2264 }
2265
2266 /*-------------------------------------------------------------------------
2267 -------------------------------------------------------------------------*/
2268
2269 int
marshal_proxy_req_content_len(char * buf)2270 LogAccess::marshal_proxy_req_content_len(char *buf)
2271 {
2272 if (buf) {
2273 int64_t val = 0;
2274 if (m_proxy_request) {
2275 val = m_http_sm->server_request_body_bytes;
2276 }
2277 marshal_int(buf, val);
2278 }
2279 return INK_MIN_ALIGN;
2280 }
2281
2282 int
marshal_proxy_req_squid_len(char * buf)2283 LogAccess::marshal_proxy_req_squid_len(char *buf)
2284 {
2285 if (buf) {
2286 int64_t val = 0;
2287 if (m_proxy_request) {
2288 val = m_proxy_request->length_get() + m_http_sm->server_request_body_bytes;
2289 }
2290 marshal_int(buf, val);
2291 }
2292 return INK_MIN_ALIGN;
2293 }
2294
2295 // TODO: Change marshalling code to support both IPv4 and IPv6 addresses.
2296 int
marshal_proxy_req_server_ip(char * buf)2297 LogAccess::marshal_proxy_req_server_ip(char *buf)
2298 {
2299 return marshal_ip(buf, m_http_sm->t_state.current.server != nullptr ? &m_http_sm->t_state.current.server->src_addr.sa : nullptr);
2300 }
2301
2302 int
marshal_proxy_req_server_port(char * buf)2303 LogAccess::marshal_proxy_req_server_port(char *buf)
2304 {
2305 if (buf) {
2306 uint16_t port = ntohs(m_http_sm->t_state.current.server != nullptr ? m_http_sm->t_state.current.server->src_addr.port() : 0);
2307 marshal_int(buf, port);
2308 }
2309 return INK_MIN_ALIGN;
2310 }
2311
2312 int
marshal_next_hop_ip(char * buf)2313 LogAccess::marshal_next_hop_ip(char *buf)
2314 {
2315 return marshal_ip(buf, m_http_sm->t_state.current.server != nullptr ? &m_http_sm->t_state.current.server->dst_addr.sa : nullptr);
2316 }
2317
2318 int
marshal_next_hop_port(char * buf)2319 LogAccess::marshal_next_hop_port(char *buf)
2320 {
2321 if (buf) {
2322 uint16_t port = ntohs(m_http_sm->t_state.current.server != nullptr ? m_http_sm->t_state.current.server->dst_addr.port() : 0);
2323 marshal_int(buf, port);
2324 }
2325 return INK_MIN_ALIGN;
2326 }
2327
2328 /*-------------------------------------------------------------------------
2329 -------------------------------------------------------------------------*/
2330
2331 int
marshal_proxy_req_is_ssl(char * buf)2332 LogAccess::marshal_proxy_req_is_ssl(char *buf)
2333 {
2334 if (buf) {
2335 int64_t is_ssl;
2336 is_ssl = m_http_sm->server_connection_is_ssl;
2337 marshal_int(buf, is_ssl);
2338 }
2339 return INK_MIN_ALIGN;
2340 }
2341
2342 /*-------------------------------------------------------------------------
2343 -------------------------------------------------------------------------*/
2344
2345 int
marshal_proxy_hierarchy_route(char * buf)2346 LogAccess::marshal_proxy_hierarchy_route(char *buf)
2347 {
2348 if (buf) {
2349 SquidHierarchyCode code = m_http_sm->t_state.squid_codes.hier_code;
2350 marshal_int(buf, static_cast<int64_t>(code));
2351 }
2352 return INK_MIN_ALIGN;
2353 }
2354
2355 /*-------------------------------------------------------------------------
2356 -------------------------------------------------------------------------*/
2357
2358 // TODO: Change marshalling code to support both IPv4 and IPv6 addresses.
2359 int
marshal_server_host_ip(char * buf)2360 LogAccess::marshal_server_host_ip(char *buf)
2361 {
2362 sockaddr const *ip = nullptr;
2363 ip = &m_http_sm->t_state.server_info.dst_addr.sa;
2364 if (!ats_is_ip(ip)) {
2365 if (m_http_sm->t_state.current.server) {
2366 ip = &m_http_sm->t_state.current.server->dst_addr.sa;
2367 if (!ats_is_ip(ip)) {
2368 ip = nullptr;
2369 }
2370 } else {
2371 ip = nullptr;
2372 }
2373 }
2374 return marshal_ip(buf, ip);
2375 }
2376
2377 /*-------------------------------------------------------------------------
2378 -------------------------------------------------------------------------*/
2379
2380 int
marshal_server_host_name(char * buf)2381 LogAccess::marshal_server_host_name(char *buf)
2382 {
2383 char *str = nullptr;
2384 int len = INK_MIN_ALIGN;
2385
2386 if (m_http_sm->t_state.current.server) {
2387 str = m_http_sm->t_state.current.server->name;
2388 len = LogAccess::strlen(str);
2389 }
2390
2391 if (buf) {
2392 marshal_str(buf, str, len);
2393 }
2394 return len;
2395 }
2396
2397 /*-------------------------------------------------------------------------
2398 -------------------------------------------------------------------------*/
2399
2400 int
marshal_server_resp_status_code(char * buf)2401 LogAccess::marshal_server_resp_status_code(char *buf)
2402 {
2403 if (buf) {
2404 HTTPStatus status;
2405 if (m_server_response) {
2406 status = m_server_response->status_get();
2407 } else {
2408 status = HTTP_STATUS_NONE;
2409 }
2410 marshal_int(buf, static_cast<int64_t>(status));
2411 }
2412 return INK_MIN_ALIGN;
2413 }
2414
2415 /*-------------------------------------------------------------------------
2416 -------------------------------------------------------------------------*/
2417
2418 int
marshal_server_resp_content_len(char * buf)2419 LogAccess::marshal_server_resp_content_len(char *buf)
2420 {
2421 if (buf) {
2422 int64_t val = 0;
2423 if (m_server_response) {
2424 val = m_http_sm->server_response_body_bytes;
2425 }
2426 marshal_int(buf, val);
2427 }
2428 return INK_MIN_ALIGN;
2429 }
2430
2431 /*-------------------------------------------------------------------------
2432 -------------------------------------------------------------------------*/
2433
2434 int
marshal_server_resp_header_len(char * buf)2435 LogAccess::marshal_server_resp_header_len(char *buf)
2436 {
2437 if (buf) {
2438 int64_t val = 0;
2439 if (m_server_response) {
2440 val = m_server_response->length_get();
2441 }
2442 marshal_int(buf, val);
2443 }
2444 return INK_MIN_ALIGN;
2445 }
2446
2447 int
marshal_server_resp_squid_len(char * buf)2448 LogAccess::marshal_server_resp_squid_len(char *buf)
2449 {
2450 if (buf) {
2451 int64_t val = 0;
2452 if (m_server_response) {
2453 val = m_server_response->length_get() + m_http_sm->server_response_body_bytes;
2454 }
2455 marshal_int(buf, val);
2456 }
2457 return INK_MIN_ALIGN;
2458 }
2459
2460 int
marshal_server_resp_http_version(char * buf)2461 LogAccess::marshal_server_resp_http_version(char *buf)
2462 {
2463 if (buf) {
2464 int64_t major = 0;
2465 int64_t minor = 0;
2466 if (m_server_response) {
2467 major = m_server_response->version_get().get_major();
2468 minor = m_server_response->version_get().get_minor();
2469 }
2470 marshal_int(buf, major);
2471 marshal_int((buf + INK_MIN_ALIGN), minor);
2472 }
2473 return (2 * INK_MIN_ALIGN);
2474 }
2475
2476 /*-------------------------------------------------------------------------
2477 -------------------------------------------------------------------------*/
2478 int
marshal_server_resp_time_ms(char * buf)2479 LogAccess::marshal_server_resp_time_ms(char *buf)
2480 {
2481 if (buf) {
2482 marshal_int(buf, m_http_sm->milestones.difference_msec(TS_MILESTONE_SERVER_CONNECT, TS_MILESTONE_SERVER_CLOSE));
2483 }
2484 return INK_MIN_ALIGN;
2485 }
2486
2487 int
marshal_server_resp_time_s(char * buf)2488 LogAccess::marshal_server_resp_time_s(char *buf)
2489 {
2490 if (buf) {
2491 marshal_int(buf,
2492 static_cast<int64_t>(m_http_sm->milestones.difference_sec(TS_MILESTONE_SERVER_CONNECT, TS_MILESTONE_SERVER_CLOSE)));
2493 }
2494 return INK_MIN_ALIGN;
2495 }
2496
2497 /*-------------------------------------------------------------------------
2498 -------------------------------------------------------------------------*/
2499
2500 int
marshal_server_transact_count(char * buf)2501 LogAccess::marshal_server_transact_count(char *buf)
2502 {
2503 if (buf) {
2504 int64_t count;
2505 count = m_http_sm->server_transact_count;
2506 marshal_int(buf, count);
2507 }
2508 return INK_MIN_ALIGN;
2509 }
2510
2511 /*-------------------------------------------------------------------------
2512 -------------------------------------------------------------------------*/
2513
2514 int
marshal_server_connect_attempts(char * buf)2515 LogAccess::marshal_server_connect_attempts(char *buf)
2516 {
2517 if (buf) {
2518 int64_t attempts = m_http_sm->t_state.current.attempts;
2519 marshal_int(buf, attempts);
2520 }
2521 return INK_MIN_ALIGN;
2522 }
2523
2524 /*-------------------------------------------------------------------------
2525 -------------------------------------------------------------------------*/
2526
2527 int
marshal_cache_resp_status_code(char * buf)2528 LogAccess::marshal_cache_resp_status_code(char *buf)
2529 {
2530 if (buf) {
2531 HTTPStatus status;
2532 if (m_cache_response) {
2533 status = m_cache_response->status_get();
2534 } else {
2535 status = HTTP_STATUS_NONE;
2536 }
2537 marshal_int(buf, static_cast<int64_t>(status));
2538 }
2539 return INK_MIN_ALIGN;
2540 }
2541
2542 /*-------------------------------------------------------------------------
2543 -------------------------------------------------------------------------*/
2544
2545 int
marshal_cache_resp_content_len(char * buf)2546 LogAccess::marshal_cache_resp_content_len(char *buf)
2547 {
2548 if (buf) {
2549 int64_t val = 0;
2550 if (m_cache_response) {
2551 val = m_http_sm->cache_response_body_bytes;
2552 }
2553 marshal_int(buf, val);
2554 }
2555 return INK_MIN_ALIGN;
2556 }
2557
2558 int
marshal_cache_resp_squid_len(char * buf)2559 LogAccess::marshal_cache_resp_squid_len(char *buf)
2560 {
2561 if (buf) {
2562 int64_t val = 0;
2563 if (m_cache_response) {
2564 val = m_cache_response->length_get() + m_http_sm->cache_response_body_bytes;
2565 }
2566 marshal_int(buf, val);
2567 }
2568 return INK_MIN_ALIGN;
2569 }
2570
2571 /*-------------------------------------------------------------------------
2572 -------------------------------------------------------------------------*/
2573
2574 int
marshal_cache_resp_header_len(char * buf)2575 LogAccess::marshal_cache_resp_header_len(char *buf)
2576 {
2577 if (buf) {
2578 int64_t val = 0;
2579 if (m_cache_response) {
2580 val = m_http_sm->cache_response_hdr_bytes;
2581 }
2582 marshal_int(buf, val);
2583 }
2584 return INK_MIN_ALIGN;
2585 }
2586
2587 int
marshal_cache_resp_http_version(char * buf)2588 LogAccess::marshal_cache_resp_http_version(char *buf)
2589 {
2590 if (buf) {
2591 int64_t major = 0;
2592 int64_t minor = 0;
2593 if (m_cache_response) {
2594 major = m_cache_response->version_get().get_major();
2595 minor = m_cache_response->version_get().get_minor();
2596 }
2597 marshal_int(buf, major);
2598 marshal_int((buf + INK_MIN_ALIGN), minor);
2599 }
2600 return (2 * INK_MIN_ALIGN);
2601 }
2602
2603 int
marshal_client_retry_after_time(char * buf)2604 LogAccess::marshal_client_retry_after_time(char *buf)
2605 {
2606 if (buf) {
2607 int64_t crat = m_http_sm->t_state.congestion_control_crat;
2608 marshal_int(buf, crat);
2609 }
2610 return INK_MIN_ALIGN;
2611 }
2612
2613 static LogCacheWriteCodeType
convert_cache_write_code(HttpTransact::CacheWriteStatus_t t)2614 convert_cache_write_code(HttpTransact::CacheWriteStatus_t t)
2615 {
2616 LogCacheWriteCodeType code;
2617 switch (t) {
2618 case HttpTransact::NO_CACHE_WRITE:
2619 code = LOG_CACHE_WRITE_NONE;
2620 break;
2621 case HttpTransact::CACHE_WRITE_LOCK_MISS:
2622 code = LOG_CACHE_WRITE_LOCK_MISSED;
2623 break;
2624 case HttpTransact::CACHE_WRITE_IN_PROGRESS:
2625 // Hack - the HttpSM doesn't record
2626 // cache write aborts currently so
2627 // if it's not complete declare it
2628 // aborted
2629 code = LOG_CACHE_WRITE_LOCK_ABORTED;
2630 break;
2631 case HttpTransact::CACHE_WRITE_ERROR:
2632 code = LOG_CACHE_WRITE_ERROR;
2633 break;
2634 case HttpTransact::CACHE_WRITE_COMPLETE:
2635 code = LOG_CACHE_WRITE_COMPLETE;
2636 break;
2637 default:
2638 ink_assert(!"bad cache write code");
2639 code = LOG_CACHE_WRITE_NONE;
2640 break;
2641 }
2642
2643 return code;
2644 }
2645
2646 int
marshal_cache_write_code(char * buf)2647 LogAccess::marshal_cache_write_code(char *buf)
2648 {
2649 if (buf) {
2650 int code = convert_cache_write_code(m_http_sm->t_state.cache_info.write_status);
2651 marshal_int(buf, code);
2652 }
2653
2654 return INK_MIN_ALIGN;
2655 }
2656
2657 int
marshal_cache_write_transform_code(char * buf)2658 LogAccess::marshal_cache_write_transform_code(char *buf)
2659 {
2660 if (buf) {
2661 int code = convert_cache_write_code(m_http_sm->t_state.cache_info.transform_write_status);
2662 marshal_int(buf, code);
2663 }
2664
2665 return INK_MIN_ALIGN;
2666 }
2667
2668 /*-------------------------------------------------------------------------
2669 -------------------------------------------------------------------------*/
2670
2671 int
marshal_transfer_time_ms(char * buf)2672 LogAccess::marshal_transfer_time_ms(char *buf)
2673 {
2674 if (buf) {
2675 marshal_int(buf, m_http_sm->milestones.difference_msec(TS_MILESTONE_SM_START, TS_MILESTONE_SM_FINISH));
2676 }
2677 return INK_MIN_ALIGN;
2678 }
2679
2680 int
marshal_transfer_time_s(char * buf)2681 LogAccess::marshal_transfer_time_s(char *buf)
2682 {
2683 if (buf) {
2684 marshal_int(buf, static_cast<int64_t>(m_http_sm->milestones.difference_sec(TS_MILESTONE_SM_START, TS_MILESTONE_SM_FINISH)));
2685 }
2686 return INK_MIN_ALIGN;
2687 }
2688
2689 /*-------------------------------------------------------------------------
2690 Figure out the size of the object *on origin*. This is somewhat tricky
2691 since there are many variations on how this can be calculated.
2692 -------------------------------------------------------------------------*/
2693 int
marshal_file_size(char * buf)2694 LogAccess::marshal_file_size(char *buf)
2695 {
2696 if (buf) {
2697 MIMEField *fld;
2698 HTTPHdr *hdr = m_server_response ? m_server_response : m_cache_response;
2699
2700 if (hdr && (fld = hdr->field_find(MIME_FIELD_CONTENT_RANGE, MIME_LEN_CONTENT_RANGE))) {
2701 int len;
2702 char *str = const_cast<char *>(fld->value_get(&len));
2703 char *pos = static_cast<char *>(memchr(str, '/', len)); // Find the /
2704
2705 // If the size is not /* (which means unknown) use it as the file_size.
2706 if (pos && !memchr(pos + 1, '*', len - (pos + 1 - str))) {
2707 marshal_int(buf, ink_atoi64(pos + 1, len - (pos + 1 - str)));
2708 }
2709 } else {
2710 // This is semi-broken when we serveq zero length objects. See TS-2213
2711 if (m_http_sm->server_response_body_bytes > 0) {
2712 marshal_int(buf, m_http_sm->server_response_body_bytes);
2713 } else if (m_http_sm->cache_response_body_bytes > 0) {
2714 marshal_int(buf, m_http_sm->cache_response_body_bytes);
2715 }
2716 }
2717 }
2718 // Else, we don't set the value at all (so, -)
2719
2720 return INK_MIN_ALIGN;
2721 }
2722
2723 /*-------------------------------------------------------------------------
2724 -------------------------------------------------------------------------*/
2725
2726 int
marshal_client_http_connection_id(char * buf)2727 LogAccess::marshal_client_http_connection_id(char *buf)
2728 {
2729 if (buf) {
2730 int64_t id = 0;
2731 if (m_http_sm) {
2732 id = m_http_sm->client_connection_id();
2733 }
2734 marshal_int(buf, id);
2735 }
2736 return INK_MIN_ALIGN;
2737 }
2738
2739 /*-------------------------------------------------------------------------
2740 -------------------------------------------------------------------------*/
2741
2742 int
marshal_client_http_transaction_id(char * buf)2743 LogAccess::marshal_client_http_transaction_id(char *buf)
2744 {
2745 if (buf) {
2746 int64_t id = 0;
2747 if (m_http_sm) {
2748 id = m_http_sm->client_transaction_id();
2749 }
2750 marshal_int(buf, id);
2751 }
2752 return INK_MIN_ALIGN;
2753 }
2754
2755 /*-------------------------------------------------------------------------
2756 -------------------------------------------------------------------------*/
2757
2758 int
marshal_client_http_transaction_priority_weight(char * buf)2759 LogAccess::marshal_client_http_transaction_priority_weight(char *buf)
2760 {
2761 if (buf) {
2762 int64_t id = 0;
2763 if (m_http_sm) {
2764 id = m_http_sm->client_transaction_priority_weight();
2765 }
2766 marshal_int(buf, id);
2767 }
2768 return INK_MIN_ALIGN;
2769 }
2770
2771 /*-------------------------------------------------------------------------
2772 -------------------------------------------------------------------------*/
2773
2774 int
marshal_client_http_transaction_priority_dependence(char * buf)2775 LogAccess::marshal_client_http_transaction_priority_dependence(char *buf)
2776 {
2777 if (buf) {
2778 int64_t id = 0;
2779 if (m_http_sm) {
2780 id = m_http_sm->client_transaction_priority_dependence();
2781 }
2782 marshal_int(buf, id);
2783 }
2784 return INK_MIN_ALIGN;
2785 }
2786
2787 /*-------------------------------------------------------------------------
2788 -------------------------------------------------------------------------*/
2789
2790 int
marshal_cache_read_retries(char * buf)2791 LogAccess::marshal_cache_read_retries(char *buf)
2792 {
2793 if (buf) {
2794 int64_t id = 0;
2795 if (m_http_sm) {
2796 id = m_http_sm->get_cache_sm().get_open_read_tries();
2797 }
2798 marshal_int(buf, id);
2799 }
2800 return INK_MIN_ALIGN;
2801 }
2802
2803 /*-------------------------------------------------------------------------
2804 -------------------------------------------------------------------------*/
2805
2806 int
marshal_cache_write_retries(char * buf)2807 LogAccess::marshal_cache_write_retries(char *buf)
2808 {
2809 if (buf) {
2810 int64_t id = 0;
2811 if (m_http_sm) {
2812 id = m_http_sm->get_cache_sm().get_open_write_tries();
2813 }
2814 marshal_int(buf, id);
2815 }
2816 return INK_MIN_ALIGN;
2817 }
2818
2819 int
marshal_cache_collapsed_connection_success(char * buf)2820 LogAccess::marshal_cache_collapsed_connection_success(char *buf)
2821 {
2822 if (buf) {
2823 int64_t id = 0; // default - no collapse attempt
2824 if (m_http_sm) {
2825 SquidLogCode code = m_http_sm->t_state.squid_codes.log_code;
2826
2827 // We increment open_write_tries beyond the max when we want to jump back to the read state for collapsing
2828 if ((m_http_sm->get_cache_sm().get_open_write_tries() > (m_http_sm->t_state.txn_conf->max_cache_open_write_retries)) &&
2829 ((code == SQUID_LOG_TCP_HIT) || (code == SQUID_LOG_TCP_MEM_HIT) || (code == SQUID_LOG_TCP_DISK_HIT))) {
2830 // Attempted collapsed connection and got a hit, success
2831 id = 1;
2832 } else if (m_http_sm->get_cache_sm().get_open_write_tries() > (m_http_sm->t_state.txn_conf->max_cache_open_write_retries)) {
2833 // Attempted collapsed connection with no hit, failure, we can also get +2 retries in a failure state
2834 id = -1;
2835 }
2836 }
2837
2838 marshal_int(buf, id);
2839 }
2840 return INK_MIN_ALIGN;
2841 }
2842 /*-------------------------------------------------------------------------
2843 -------------------------------------------------------------------------*/
2844
2845 int
marshal_http_header_field(LogField::Container container,char * field,char * buf)2846 LogAccess::marshal_http_header_field(LogField::Container container, char *field, char *buf)
2847 {
2848 char *str = nullptr;
2849 int padded_len = INK_MIN_ALIGN;
2850 int actual_len = 0;
2851 bool valid_field = false;
2852 HTTPHdr *header;
2853
2854 switch (container) {
2855 case LogField::CQH:
2856 header = m_client_request;
2857 break;
2858
2859 case LogField::PSH:
2860 header = m_proxy_response;
2861 break;
2862
2863 case LogField::PQH:
2864 header = m_proxy_request;
2865 break;
2866
2867 case LogField::SSH:
2868 header = m_server_response;
2869 break;
2870
2871 case LogField::CSSH:
2872 header = m_cache_response;
2873 break;
2874
2875 default:
2876 header = nullptr;
2877 break;
2878 }
2879
2880 if (header) {
2881 MIMEField *fld = header->field_find(field, static_cast<int>(::strlen(field)));
2882 if (fld) {
2883 valid_field = true;
2884
2885 // Loop over dups, marshalling each one into the buffer and
2886 // summing up their length
2887 //
2888 int running_len = 0;
2889 while (fld) {
2890 str = const_cast<char *>(fld->value_get(&actual_len));
2891 if (buf) {
2892 memcpy(buf, str, actual_len);
2893 buf += actual_len;
2894 }
2895 running_len += actual_len;
2896 fld = fld->m_next_dup;
2897
2898 // Dups need to be comma separated. So if there's another
2899 // dup, then add a comma and a space ...
2900 //
2901 if (fld != nullptr) {
2902 if (buf) {
2903 memcpy(buf, ", ", 2);
2904 buf += 2;
2905 }
2906 running_len += 2;
2907 }
2908 }
2909
2910 // Done with all dups. Ensure that the string is terminated
2911 // and that the running_len is padded.
2912 //
2913 if (buf) {
2914 *buf = '\0';
2915 buf++;
2916 }
2917 running_len += 1;
2918 padded_len = round_strlen(running_len);
2919
2920 // Note: marshal_string fills the padding to
2921 // prevent purify UMRs so we do it here too
2922 // since we always pass the unpadded length on
2923 // our calls to marshal string
2924 #ifdef DEBUG
2925 if (buf) {
2926 int pad_len = padded_len - running_len;
2927 for (int i = 0; i < pad_len; i++) {
2928 *buf = '$';
2929 buf++;
2930 }
2931 }
2932 #endif
2933 }
2934 }
2935
2936 if (valid_field == false) {
2937 padded_len = INK_MIN_ALIGN;
2938 if (buf) {
2939 marshal_str(buf, nullptr, padded_len);
2940 }
2941 }
2942
2943 return (padded_len);
2944 }
2945
2946 int
marshal_http_header_field_escapify(LogField::Container container,char * field,char * buf)2947 LogAccess::marshal_http_header_field_escapify(LogField::Container container, char *field, char *buf)
2948 {
2949 char *str = nullptr, *new_str = nullptr;
2950 int padded_len = INK_MIN_ALIGN;
2951 int actual_len = 0, new_len = 0;
2952 bool valid_field = false;
2953 HTTPHdr *header;
2954
2955 switch (container) {
2956 case LogField::ECQH:
2957 header = m_client_request;
2958 break;
2959
2960 case LogField::EPSH:
2961 header = m_proxy_response;
2962 break;
2963
2964 case LogField::EPQH:
2965 header = m_proxy_request;
2966 break;
2967
2968 case LogField::ESSH:
2969 header = m_server_response;
2970 break;
2971
2972 case LogField::ECSSH:
2973 header = m_cache_response;
2974 break;
2975
2976 default:
2977 header = nullptr;
2978 break;
2979 }
2980
2981 if (header) {
2982 MIMEField *fld = header->field_find(field, static_cast<int>(::strlen(field)));
2983 if (fld) {
2984 valid_field = true;
2985
2986 // Loop over dups, marshalling each one into the buffer and
2987 // summing up their length
2988 //
2989 int running_len = 0;
2990 while (fld) {
2991 str = const_cast<char *>(fld->value_get(&actual_len));
2992 new_str = LogUtils::escapify_url(&m_arena, str, actual_len, &new_len);
2993 if (buf) {
2994 memcpy(buf, new_str, new_len);
2995 buf += new_len;
2996 }
2997 running_len += new_len;
2998 fld = fld->m_next_dup;
2999
3000 // Dups need to be comma separated. So if there's another
3001 // dup, then add a comma and an escapified space ...
3002 constexpr const char SEP[] = ",%20";
3003 constexpr size_t SEP_LEN = sizeof(SEP) - 1;
3004 if (fld != nullptr) {
3005 if (buf) {
3006 memcpy(buf, SEP, SEP_LEN);
3007 buf += SEP_LEN;
3008 }
3009 running_len += SEP_LEN;
3010 }
3011 }
3012
3013 // Done with all dups. Ensure that the string is terminated
3014 // and that the running_len is padded.
3015 //
3016 if (buf) {
3017 *buf = '\0';
3018 buf++;
3019 }
3020 running_len += 1;
3021 padded_len = round_strlen(running_len);
3022
3023 // Note: marshal_string fills the padding to
3024 // prevent purify UMRs so we do it here too
3025 // since we always pass the unpadded length on
3026 // our calls to marshal string
3027 #ifdef DEBUG
3028 if (buf) {
3029 int pad_len = padded_len - running_len;
3030 for (int i = 0; i < pad_len; i++) {
3031 *buf = '$';
3032 buf++;
3033 }
3034 }
3035 #endif
3036 }
3037 }
3038
3039 if (valid_field == false) {
3040 padded_len = INK_MIN_ALIGN;
3041 if (buf) {
3042 marshal_str(buf, nullptr, padded_len);
3043 }
3044 }
3045
3046 return (padded_len);
3047 }
3048
3049 int
marshal_milestone(TSMilestonesType ms,char * buf)3050 LogAccess::marshal_milestone(TSMilestonesType ms, char *buf)
3051 {
3052 if (buf) {
3053 int64_t val = ink_hrtime_to_msec(m_http_sm->milestones[ms]);
3054 marshal_int(buf, val);
3055 }
3056 return INK_MIN_ALIGN;
3057 }
3058
3059 int
marshal_milestone_fmt_sec(TSMilestonesType type,char * buf)3060 LogAccess::marshal_milestone_fmt_sec(TSMilestonesType type, char *buf)
3061 {
3062 if (buf) {
3063 ink_hrtime tsec = ink_hrtime_to_sec(m_http_sm->milestones[type]);
3064 marshal_int(buf, tsec);
3065 }
3066 return INK_MIN_ALIGN;
3067 }
3068
3069 int
marshal_milestone_fmt_ms(TSMilestonesType type,char * buf)3070 LogAccess::marshal_milestone_fmt_ms(TSMilestonesType type, char *buf)
3071 {
3072 if (buf) {
3073 ink_hrtime tmsec = ink_hrtime_to_msec(m_http_sm->milestones[type]);
3074 marshal_int(buf, tmsec);
3075 }
3076 return INK_MIN_ALIGN;
3077 }
3078
3079 int
marshal_milestone_diff(TSMilestonesType ms1,TSMilestonesType ms2,char * buf)3080 LogAccess::marshal_milestone_diff(TSMilestonesType ms1, TSMilestonesType ms2, char *buf)
3081 {
3082 if (buf) {
3083 int64_t val = m_http_sm->milestones.difference_msec(ms2, ms1);
3084 marshal_int(buf, val);
3085 }
3086 return INK_MIN_ALIGN;
3087 }
3088
3089 void
set_http_header_field(LogField::Container container,char * field,char * buf,int len)3090 LogAccess::set_http_header_field(LogField::Container container, char *field, char *buf, int len)
3091 {
3092 HTTPHdr *header;
3093
3094 switch (container) {
3095 case LogField::CQH:
3096 case LogField::ECQH:
3097 header = m_client_request;
3098 break;
3099
3100 case LogField::PSH:
3101 case LogField::EPSH:
3102 header = m_proxy_response;
3103 break;
3104
3105 case LogField::PQH:
3106 case LogField::EPQH:
3107 header = m_proxy_request;
3108 break;
3109
3110 case LogField::SSH:
3111 case LogField::ESSH:
3112 header = m_server_response;
3113 break;
3114
3115 case LogField::CSSH:
3116 case LogField::ECSSH:
3117 header = m_cache_response;
3118 break;
3119
3120 default:
3121 header = nullptr;
3122 break;
3123 }
3124
3125 if (header && buf) {
3126 MIMEField *fld = header->field_find(field, static_cast<int>(::strlen(field)));
3127 if (fld) {
3128 // Loop over dups, update each of them
3129 //
3130 while (fld) {
3131 // make sure to reuse header heaps as otherwise
3132 // coalesce logic in header heap may free up
3133 // memory pointed to by cquuc or other log fields
3134 header->field_value_set(fld, buf, len, true);
3135 fld = fld->m_next_dup;
3136 }
3137 }
3138 }
3139 }
3140