| /** @file | |
| This class extends the logging system interface as implemented by the | |
| HttpStateMachineGet class. | |
| @section license License | |
| Licensed to the Apache Software Foundation (ASF) under one | |
| or more contributor license agreements. See the NOTICE file | |
| distributed with this work for additional information | |
| regarding copyright ownership. The ASF licenses this file | |
| to you under the Apache License, Version 2.0 (the | |
| "License"); you may not use this file except in compliance | |
| with the License. You may obtain a copy of the License at | |
| http://www.apache.org/licenses/LICENSE-2.0 | |
| Unless required by applicable law or agreed to in writing, software | |
| distributed under the License is distributed on an "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| See the License for the specific language governing permissions and | |
| limitations under the License. | |
| */ | |
| #pragma once | |
| #include "tscore/ink_align.h" | |
| #include "proxy/Milestones.h" | |
| #include "proxy/hdrs/HTTP.h" | |
| #include "proxy/logging/LogField.h" | |
| class TransactionLogData; | |
| class IpClass; | |
| union IpEndpoint; | |
| #include <string> | |
| /*------------------------------------------------------------------------- | |
| LogAccess | |
| This class defines the logging system interface for extracting | |
| information required to process a log entry. This accessor is | |
| implemented as an abstract base class with functions for | |
| accessing the data based on the derived class. | |
| Each function has the ability to marshal its data into a buffer that is | |
| provided, and return the number of bytes that were marshalled. In the | |
| absence of a marshalling buffer, the routines will simply return the | |
| number of bytes that would be needed to marshal. This allows for the | |
| same functions to be used for both buffer length computations and data | |
| movement. | |
| Logging deals with values of just two possible data types: integers | |
| (including enum) and strings. Because the integers are multi-byte | |
| values that might need special alignment needs when being marshalled, | |
| this base class provides a static member function called marshal_int() | |
| that handles this (including checking for a NULL buffer). The template | |
| for implementing integer and enum marshalling routines is: | |
| int marshal_some_int_value (char *buf) | |
| { | |
| if (buf) { | |
| int64_t val = what_the_value_should_be; | |
| marshal_int (buf, val); | |
| } | |
| return INK_MIN_ALIGN; | |
| } | |
| String values don't need byte swapping, but we do want to ensure things | |
| like trailing NULLS and padding. The best way to do this is to provide a | |
| marshalling routine that takes a source buffer, a string, and its length, | |
| and makes sure the string is copied into the source buffer with a | |
| trailing NULL. We've also provided our own strlen() function within the | |
| class to adjust for trailing NULL as well. So, here is how it would look | |
| to actually use these functions for marshalling a string value: | |
| int marshal_some_string_value (char *buf) | |
| { | |
| char *str = compute_or_locate_string_value (); | |
| int len = LogAccess::strlen (str); | |
| if (buf) { | |
| marshal_str (buf, str, len); | |
| } | |
| return len; | |
| } | |
| -------------------------------------------------------------------------*/ | |
| // DEFAULT_STR_LEN MUST be less than INK_MIN_ALIGN | |
| #define DEFAULT_STR "-" | |
| #define DEFAULT_STR_LEN 1 | |
| extern char INVALID_STR[]; | |
| enum LogEntryType { | |
| LOG_ENTRY_HTTP = 0, | |
| N_LOG_ENTRY_TYPES, | |
| }; | |
| enum LogFinishCodeType { | |
| LOG_FINISH_FIN = 0, | |
| LOG_FINISH_INTR, | |
| LOG_FINISH_TIMEOUT, | |
| N_LOG_FINISH_CODE_TYPES, | |
| }; | |
| enum LogCacheWriteCodeType { | |
| LOG_CACHE_WRITE_NONE = 0, | |
| LOG_CACHE_WRITE_LOCK_MISSED, | |
| LOG_CACHE_WRITE_LOCK_ABORTED, | |
| LOG_CACHE_WRITE_ERROR, | |
| LOG_CACHE_WRITE_COMPLETE, | |
| N_LOG_CACHE_WRITE_TYPES | |
| }; | |
| class LogAccess | |
| { | |
| public: | |
| LogAccess() = delete; | |
| /** Construct from a TransactionLogData instance. | |
| * | |
| * The caller retains ownership of @a data, which must outlive the | |
| * synchronous Log::access() call that marshals this entry. | |
| * | |
| * @param[in] data Populated TransactionLogData for an HttpSM-backed or | |
| * non-HttpSM entry. | |
| */ | |
| explicit LogAccess(TransactionLogData &data); | |
| ~LogAccess() {} | |
| void init(); | |
| // | |
| // client -> proxy fields | |
| // | |
| int marshal_client_host_ip(char *); // STR | |
| int marshal_host_interface_ip(char *); // STR | |
| int marshal_client_host_ip_verified(char *); // STR | |
| int marshal_client_host_port(char *); // INT | |
| int marshal_remote_host_ip(char *); // STR | |
| int marshal_remote_host_port(char *); // STR | |
| int marshal_client_auth_user_name(char *); // STR | |
| int marshal_client_req_timestamp_sec(char *); // INT | |
| int marshal_client_req_timestamp_ms(char *); // INT | |
| int marshal_client_req_text(char *); // STR | |
| int marshal_client_req_http_method(char *); // STR | |
| int marshal_client_req_url(char *); // STR | |
| int marshal_client_req_url_canon(char *); // STR | |
| int marshal_client_req_unmapped_url_canon(char *); // STR | |
| int marshal_client_req_unmapped_url_path(char *); // STR | |
| int marshal_client_req_unmapped_url_host(char *); // STR | |
| int marshal_client_req_url_path(char *); // STR | |
| int marshal_client_req_url_scheme(char *); // STR | |
| int marshal_client_req_http_version(char *); // INT | |
| int marshal_client_req_protocol_version(char *); // STR | |
| int marshal_server_req_protocol_version(char *); // STR | |
| int marshal_client_req_squid_len(char *); // INT | |
| int marshal_client_req_squid_len_tls(char *); // INT | |
| int marshal_client_req_header_len(char *); // INT | |
| int marshal_client_req_content_len(char *); // INT | |
| int marshal_client_req_tcp_reused(char *); // INT | |
| int marshal_client_req_is_ssl(char *); // INT | |
| int marshal_client_req_ssl_reused(char *); // INT | |
| int marshal_client_ssl_resumption_type(char *); // INT | |
| int marshal_client_req_is_internal(char *); // INT | |
| int marshal_client_req_mptcp_state(char *); // INT | |
| int marshal_client_security_protocol(char *); // STR | |
| int marshal_client_security_cipher_suite(char *); // STR | |
| int marshal_client_security_curve(char *); // STR | |
| int marshal_client_security_group(char *); // STR | |
| int marshal_client_security_alpn(char *); // STR | |
| int marshal_client_finish_status_code(char *); // INT | |
| int marshal_client_req_id(char *); // INT | |
| int marshal_client_req_uuid(char *); // STR | |
| int marshal_client_rx_error_code(char *); // STR | |
| int marshal_client_tx_error_code(char *); // STR | |
| int marshal_client_tls_handshake_bytes_rx(char *); // INT | |
| int marshal_client_tls_handshake_bytes_tx(char *); // INT | |
| int marshal_client_tls_handshake_bytes(char *); // INT | |
| int marshal_client_req_all_header_fields(char *); // STR | |
| // | |
| // proxy -> client fields | |
| // | |
| int marshal_proxy_resp_content_type(char *); // STR | |
| int marshal_proxy_resp_reason_phrase(char *); // STR | |
| int marshal_proxy_resp_squid_len(char *); // INT | |
| int marshal_proxy_resp_squid_len_tls(char *); // INT | |
| int marshal_proxy_resp_content_len(char *); // INT | |
| int marshal_proxy_resp_status_code(char *); // INT | |
| int marshal_status_plugin_entry(char *); // STR | |
| int marshal_proxy_resp_header_len(char *); // INT | |
| int marshal_proxy_finish_status_code(char *); // INT | |
| int marshal_cache_result_code(char *); // INT | |
| int marshal_cache_result_subcode(char *); // INT | |
| int marshal_proxy_host_port(char *); // INT | |
| int marshal_cache_hit_miss(char *); // INT | |
| int marshal_proxy_resp_all_header_fields(char *); // STR | |
| // | |
| // proxy -> server fields | |
| // | |
| int marshal_proxy_req_header_len(char *); // INT | |
| int marshal_proxy_req_squid_len(char *); // INT | |
| int marshal_proxy_req_content_len(char *); // INT | |
| int marshal_proxy_req_server_ip(char *); // INT | |
| int marshal_proxy_req_server_port(char *); // INT | |
| int marshal_proxy_hierarchy_route(char *); // INT | |
| int marshal_next_hop_ip(char *); // STR | |
| int marshal_next_hop_port(char *); // INT | |
| int marshal_proxy_host_name(char *); // STR | |
| int marshal_proxy_host_ip(char *); // STR | |
| int marshal_proxy_req_is_ssl(char *); // INT | |
| int marshal_proxy_req_ssl_reused(char *); // INT | |
| int marshal_proxy_req_all_header_fields(char *); // STR | |
| // | |
| // server -> proxy fields | |
| // | |
| int marshal_server_host_ip(char *); // INT | |
| int marshal_server_host_name(char *); // STR | |
| int marshal_server_resp_status_code(char *); // INT | |
| int marshal_server_resp_squid_len(char *); // INT | |
| int marshal_server_resp_content_len(char *); // INT | |
| int marshal_server_resp_header_len(char *); // INT | |
| int marshal_server_resp_http_version(char *); // STR | |
| int marshal_server_resp_time_ms(char *); // INT | |
| int marshal_server_resp_time_s(char *); // INT | |
| int marshal_server_transact_count(char *); // INT | |
| int marshal_server_simple_retry_count(char *); // INT | |
| int marshal_server_unavailable_retry_count(char *); // INT | |
| int marshal_server_connect_attempts(char *); // INT | |
| int marshal_server_resp_all_header_fields(char *); // STR | |
| // | |
| // cache -> client fields | |
| // | |
| int marshal_cache_resp_status_code(char *); // INT | |
| int marshal_cache_resp_squid_len(char *); // INT | |
| int marshal_cache_resp_content_len(char *); // INT | |
| int marshal_cache_resp_header_len(char *); // INT | |
| int marshal_cache_resp_http_version(char *); // STR | |
| int marshal_cache_resp_all_header_fields(char *); // STR | |
| void set_client_req_url(char *, int); // STR | |
| void set_client_req_url_canon(char *, int); // STR | |
| void set_client_req_unmapped_url_canon(char *, int); // STR | |
| void set_client_req_unmapped_url_path(char *, int); // STR | |
| void set_client_req_unmapped_url_host(char *, int); // STR | |
| void set_client_req_url_path(char *, int); // STR | |
| // | |
| // congestion control -- client_retry_after_time | |
| // | |
| int marshal_client_retry_after_time(char *); // INT | |
| // | |
| // cache write fields | |
| // | |
| int marshal_cache_write_code(char *); // INT | |
| int marshal_cache_write_transform_code(char *); // INT | |
| int marshal_cache_key_hash(char *); // STR | |
| // other fields | |
| // | |
| int marshal_transfer_time_ms(char *); // INT | |
| int marshal_transfer_time_s(char *); // INT | |
| int marshal_file_size(char *); // INT | |
| int marshal_plugin_identity_id(char *); // INT | |
| int marshal_plugin_identity_tag(char *); // STR | |
| int marshal_process_uuid(char *); // STR | |
| int marshal_process_sfid(char *); // STR | |
| int marshal_client_http_connection_id(char *); // INT | |
| int marshal_client_http_transaction_id(char *); // INT | |
| int marshal_client_http_transaction_priority_weight(char *); // INT | |
| int marshal_client_http_transaction_priority_dependence(char *); // INT | |
| int marshal_cache_lookup_url_canon(char *); // STR | |
| int marshal_client_sni_server_name(char *); // STR | |
| int marshal_client_provided_cert(char *); // INT | |
| int marshal_proxy_provided_cert(char *); // INT | |
| int marshal_version_build_number(char *); // STR | |
| int marshal_version_string(char *); // STR | |
| int marshal_cache_read_retries(char *); // INT | |
| int marshal_cache_write_retries(char *); // INT | |
| int marshal_cache_collapsed_connection_success(char *); // INT | |
| int marshal_proxy_protocol_version(char *); // STR | |
| int marshal_proxy_protocol_src_ip(char *); // STR | |
| int marshal_proxy_protocol_dst_ip(char *); // STR | |
| int marshal_proxy_protocol_authority(char *); // STR | |
| int marshal_proxy_protocol_tls_cipher(char *); // STR | |
| int marshal_proxy_protocol_tls_version(char *); // STR | |
| int marshal_proxy_protocol_tls_group(char *); // STR | |
| // named fields from within a http header | |
| // | |
| int marshal_http_header_field(LogField::Container container, char *field, char *buf); | |
| int marshal_http_header_field_escapify(LogField::Container container, char *field, char *buf); | |
| // | |
| // named records.yaml int variables | |
| // | |
| int marshal_config_int_var(char *config_var, char *buf); | |
| // | |
| // named records.yaml string variables | |
| // | |
| int marshal_config_str_var(char *config_var, char *buf); | |
| // | |
| // generic record access | |
| // | |
| int marshal_record(char *record, char *buf); | |
| // | |
| // milestones access | |
| // | |
| int marshal_milestone(TSMilestonesType ms, char *buf); | |
| int marshal_milestone_fmt_sec(TSMilestonesType ms, char *buf); | |
| int marshal_milestone_fmt_ms(TSMilestonesType ms, char *buf); | |
| int marshal_milestone_diff(TSMilestonesType ms1, TSMilestonesType ms2, char *buf); | |
| int marshal_milestones_csv(char *buf); | |
| bool has_http_header_field(LogField::Container container, const char *field) const; | |
| void set_http_header_field(LogField::Container container, char *field, char *buf, int len); | |
| // Plugin | |
| int marshal_custom_field(char *buf, LogField::Type type, const LogField::CustomMarshalFunc &plugin_marshal_func); | |
| // | |
| // unmarshalling routines | |
| // | |
| // They used to return a string; now they unmarshal directly into the | |
| // destination buffer supplied. | |
| // | |
| static int64_t unmarshal_int(char **buf); | |
| static int unmarshal_itoa(int64_t val, char *dest, int field_width = 0, char leading_char = ' '); | |
| static int unmarshal_itox(int64_t val, char *dest, int field_width = 0, char leading_char = ' '); | |
| static int unmarshal_int_to_str(char **buf, char *dest, int len); | |
| static int unmarshal_int_to_str_hex(char **buf, char *dest, int len); | |
| static int unmarshal_milestone_diff(char **buf, char *dest, int len); | |
| static int unmarshal_str(char **buf, char *dest, int len, LogSlice *slice, LogEscapeType escape_type); | |
| static int unmarshal_ttmsf(char **buf, char *dest, int len); | |
| static int unmarshal_int_to_date_str(char **buf, char *dest, int len); | |
| static int unmarshal_int_to_time_str(char **buf, char *dest, int len); | |
| static int unmarshal_int_to_netscape_str(char **buf, char *dest, int len); | |
| static int unmarshal_http_version(char **buf, char *dest, int len); | |
| static int unmarshal_http_status(char **buf, char *dest, int len); | |
| static int unmarshal_ip(char **buf, IpEndpoint *dest); | |
| static int unmarshal_ip_to_str(char **buf, char *dest, int len); | |
| static int unmarshal_ip_to_hex(char **buf, char *dest, int len); | |
| static int unmarshal_hierarchy(char **buf, char *dest, int len, const Ptr<LogFieldAliasMap> &map); | |
| static int unmarshal_finish_status(char **buf, char *dest, int len, const Ptr<LogFieldAliasMap> &map); | |
| static int unmarshal_cache_code(char **buf, char *dest, int len, const Ptr<LogFieldAliasMap> &map); | |
| static int unmarshal_cache_hit_miss(char **buf, char *dest, int len, const Ptr<LogFieldAliasMap> &map); | |
| static int unmarshal_cache_write_code(char **buf, char *dest, int len, const Ptr<LogFieldAliasMap> &map); | |
| static int unmarshal_with_map(int64_t code, char *dest, int len, const Ptr<LogFieldAliasMap> &map, const char *msg = nullptr); | |
| static int unmarshal_record(char **buf, char *dest, int len); | |
| /** Find the padded length of a given value for alignment purposes. | |
| * @param[in] len The length from which to calculate the padded length. | |
| * @return The padded length on an even int64_t boundary. | |
| */ | |
| static int padded_length(int len); | |
| /** strlen wrapped in @a padded_length for calculaing padded string lengths. | |
| * | |
| * This is our own version of strlen which takes into account nullptr input | |
| * for DEFAULT_STR and adds space for the null terminator. After accounting | |
| * for these, it passes the result to @a padded_length to ensure space for | |
| * alignment. This function is useful, for example, when calculating the | |
| * length for @a marshal_str. | |
| * | |
| * @param[in] str The string from which to calculate the padded length. | |
| * @return The padded length for the string on an even int64_t boundary. | |
| */ | |
| static int padded_strlen(const char *str); | |
| public: | |
| static void marshal_int(char *dest, int64_t source); | |
| static void marshal_str(char *dest, const char *source, int padded_len); | |
| static void marshal_mem(char *dest, const char *source, int actual_len, int padded_len); | |
| static int marshal_ip(char *dest, sockaddr const *ip); | |
| // noncopyable | |
| // -- member functions that are not allowed -- | |
| LogAccess(const LogAccess &rhs) = delete; // no copies | |
| LogAccess &operator=(LogAccess &rhs) = delete; // or assignment | |
| private: | |
| TransactionLogData *m_data = nullptr; | |
| Arena m_arena; | |
| HTTPHdr *m_client_request = nullptr; | |
| HTTPHdr *m_proxy_response = nullptr; | |
| HTTPHdr *m_proxy_request = nullptr; | |
| HTTPHdr *m_server_response = nullptr; | |
| HTTPHdr *m_cache_response = nullptr; | |
| char *m_client_req_url_str = nullptr; | |
| int m_client_req_url_len = 0; | |
| char *m_client_req_url_canon_str = nullptr; | |
| int m_client_req_url_canon_len = 0; | |
| char *m_client_req_unmapped_url_canon_str = nullptr; | |
| int m_client_req_unmapped_url_canon_len = 0; | |
| char *m_client_req_unmapped_url_path_str = nullptr; | |
| int m_client_req_unmapped_url_path_len = 0; | |
| char *m_client_req_unmapped_url_host_str = nullptr; | |
| int m_client_req_unmapped_url_host_len = 0; | |
| char const *m_client_req_url_path_str = nullptr; | |
| int m_client_req_url_path_len = 0; | |
| char *m_proxy_resp_content_type_str = nullptr; | |
| int m_proxy_resp_content_type_len = 0; | |
| char *m_proxy_resp_reason_phrase_str = nullptr; | |
| int m_proxy_resp_reason_phrase_len = 0; | |
| char *m_cache_lookup_url_canon_str = nullptr; | |
| int m_cache_lookup_url_canon_len = 0; | |
| HTTPHdr *header_for_container(LogField::Container container) const; | |
| void validate_unmapped_url(); | |
| void validate_unmapped_url_path(); | |
| void validate_lookup_url(); | |
| }; | |
| inline int | |
| LogAccess::padded_length(int len) | |
| { | |
| return INK_ALIGN_DEFAULT(len); | |
| } | |
| /*------------------------------------------------------------------------- | |
| LogAccess::padded_strlen | |
| Take trailing null and alignment padding into account. This makes sure | |
| that strings in the LogBuffer are laid out properly. | |
| -------------------------------------------------------------------------*/ | |
| inline int | |
| LogAccess::padded_strlen(const char *str) | |
| { | |
| if (str == nullptr || str[0] == 0) { | |
| return padded_length(sizeof(DEFAULT_STR)); | |
| } else { | |
| return (int)(padded_length(((int)::strlen(str) + 1))); // actual bytes for string | |
| } | |
| } | |
| inline void | |
| LogAccess::marshal_int(char *dest, int64_t source) | |
| { | |
| // TODO: This used to do htonl on the source. TS-1156 | |
| *((int64_t *)dest) = source; | |
| } | |
| /*------------------------------------------------------------------------- | |
| resolve_logfield_string | |
| This external function takes a format string and a LogAccess context and | |
| resolves any known fields to return a new, resolved string. | |
| -------------------------------------------------------------------------*/ | |
| char *resolve_logfield_string(LogAccess *context, const char *format_str); |