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