| /** @file |
| |
| A brief file description |
| |
| @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. |
| */ |
| |
| /*************************************************************************** |
| LogAccessHttp.cc |
| |
| This file defines the Http implementation of a LogAccess object, and |
| implements the accessor functions using information about an Http state |
| machine. |
| |
| |
| ***************************************************************************/ |
| #include "libts.h" |
| #include "Error.h" |
| #include "LogAccessHttp.h" |
| #include "http/HttpSM.h" |
| #include "MIME.h" |
| #include "HTTP.h" |
| #include "LogUtils.h" |
| #include "LogObject.h" |
| #include "LogConfig.h" |
| #include "Log.h" |
| |
| /*------------------------------------------------------------------------- |
| LogAccessHttp |
| |
| Initialize the private data members and assert that we got a valid state |
| machine pointer. |
| -------------------------------------------------------------------------*/ |
| |
| LogAccessHttp::LogAccessHttp(HttpSM * sm) |
| : m_http_sm(sm), m_arena(), m_client_request(NULL), m_proxy_response(NULL), m_proxy_request(NULL), |
| m_server_response(NULL), m_cache_response(NULL), m_client_req_url_str(NULL), m_client_req_url_len(0), |
| m_client_req_url_canon_str(NULL), m_client_req_url_canon_len(0), m_client_req_unmapped_url_canon_str(NULL), |
| m_client_req_unmapped_url_canon_len(-1), m_client_req_unmapped_url_path_str(NULL), |
| m_client_req_unmapped_url_path_len(-1), m_client_req_unmapped_url_host_str(NULL), |
| m_client_req_unmapped_url_host_len(-1), m_client_req_url_path_str(NULL), m_client_req_url_path_len(0), |
| m_proxy_resp_content_type_str(NULL), m_proxy_resp_content_type_len(0) |
| { |
| ink_assert(m_http_sm != NULL); |
| } |
| |
| /*------------------------------------------------------------------------- |
| LogAccessHttp::~LogAccessHttp |
| |
| Deallocate space for any strings allocated in the init routine. |
| -------------------------------------------------------------------------*/ |
| |
| LogAccessHttp::~LogAccessHttp() |
| { |
| } |
| |
| /*------------------------------------------------------------------------- |
| LogAccessHttp::init |
| |
| Build some strings that will come in handy for processing later, such as |
| URL. This saves us from having to build the strings twice: once to |
| compute their length and a second time to actually marshal them. We also |
| initialize local pointers to each of the 4 http headers. However, there |
| is no guarantee that these headers will all be valid, so we must always |
| check the validity of these pointers before using them. |
| -------------------------------------------------------------------------*/ |
| |
| #define HIDDEN_CONTENT_TYPE "@Content-Type" |
| #define HIDDEN_CONTENT_TYPE_LEN 13 |
| |
| void |
| LogAccessHttp::init() |
| { |
| HttpTransact::HeaderInfo * hdr = &(m_http_sm->t_state.hdr_info); |
| |
| if (hdr->client_request.valid()) { |
| m_client_request = &(hdr->client_request); |
| m_client_req_url_str = m_client_request->url_string_get_ref(&m_client_req_url_len); |
| m_client_req_url_canon_str = LogUtils::escapify_url(&m_arena, m_client_req_url_str, m_client_req_url_len, |
| &m_client_req_url_canon_len); |
| m_client_req_url_path_str = m_client_request->path_get(&m_client_req_url_path_len); |
| } |
| |
| if (hdr->client_response.valid()) { |
| m_proxy_response = &(hdr->client_response); |
| MIMEField *field = m_proxy_response->field_find(MIME_FIELD_CONTENT_TYPE, MIME_LEN_CONTENT_TYPE); |
| if (field) { |
| m_proxy_resp_content_type_str = (char *) field->value_get(&m_proxy_resp_content_type_len); |
| // |
| // here is the assert |
| // |
| //assert (m_proxy_resp_content_type_str[0] >= 'A' && m_proxy_resp_content_type_str[0] <= 'z'); |
| LogUtils::remove_content_type_attributes(m_proxy_resp_content_type_str, &m_proxy_resp_content_type_len); |
| } else { |
| // If Content-Type field is missing, check for @Content-Type |
| field = m_proxy_response->field_find(HIDDEN_CONTENT_TYPE, HIDDEN_CONTENT_TYPE_LEN); |
| if (field) { |
| m_proxy_resp_content_type_str = (char *) field->value_get(&m_proxy_resp_content_type_len); |
| LogUtils::remove_content_type_attributes(m_proxy_resp_content_type_str, &m_proxy_resp_content_type_len); |
| } |
| } |
| } |
| if (hdr->server_request.valid()) { |
| m_proxy_request = &(hdr->server_request); |
| } |
| if (hdr->server_response.valid()) { |
| m_server_response = &(hdr->server_response); |
| } |
| if (hdr->cache_response.valid()) { |
| m_cache_response = &(hdr->cache_response); |
| } |
| } |
| |
| /*------------------------------------------------------------------------- |
| The marshalling routines ... |
| |
| We know that m_http_sm is a valid pointer (we assert so in the ctor), but |
| we still need to check the other header pointers before using them in the |
| routines. |
| -------------------------------------------------------------------------*/ |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccessHttp::marshal_client_host_ip(char *buf) |
| { |
| return marshal_ip(buf, &m_http_sm->t_state.client_info.addr.sa); |
| } |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccessHttp::marshal_client_host_port(char *buf) |
| { |
| if (buf) { |
| uint16_t port = ntohs(m_http_sm->t_state.client_info.addr.port()); |
| marshal_int(buf, port); |
| } |
| return INK_MIN_ALIGN; |
| } |
| |
| /*------------------------------------------------------------------------- |
| user authenticated to the proxy (RFC931) |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccessHttp::marshal_client_auth_user_name(char *buf) |
| { |
| char *str = NULL; |
| int len = INK_MIN_ALIGN; |
| |
| // Jira TS-40: |
| // NOTE: Authentication related code and modules were removed/disabled. |
| // Uncomment code path below when re-added/enabled. |
| /*if (m_http_sm->t_state.auth_params.user_name) { |
| str = m_http_sm->t_state.auth_params.user_name; |
| len = LogAccess::strlen(str); |
| } */ |
| if (buf) { |
| marshal_str(buf, str, len); |
| } |
| return len; |
| } |
| |
| |
| /*------------------------------------------------------------------------- |
| Private utility function to validate m_client_req_unmapped_url_canon_str & |
| m_client_req_unmapped_url_canon_len fields. |
| -------------------------------------------------------------------------*/ |
| |
| void |
| LogAccessHttp::validate_unmapped_url(void) |
| { |
| if (m_client_req_unmapped_url_canon_len < 0) { |
| if (m_http_sm->t_state.pristine_url.valid()) { |
| int unmapped_url_len; |
| char *unmapped_url = m_http_sm->t_state.pristine_url.string_get_ref(&unmapped_url_len); |
| |
| if (unmapped_url && unmapped_url[0] != 0) { |
| m_client_req_unmapped_url_canon_str = |
| LogUtils::escapify_url(&m_arena, unmapped_url, unmapped_url_len, &m_client_req_unmapped_url_canon_len); |
| } |
| } else { |
| m_client_req_unmapped_url_canon_len = 0; |
| } |
| } |
| } |
| |
| /*------------------------------------------------------------------------- |
| Private utility function to validate m_client_req_unmapped_url_path_str & |
| m_client_req_unmapped_url_path_len fields. |
| -------------------------------------------------------------------------*/ |
| |
| void |
| LogAccessHttp::validate_unmapped_url_path(void) |
| { |
| int len; |
| char *c; |
| |
| if (m_client_req_unmapped_url_path_len < 0 && m_client_req_unmapped_url_host_len < 0) { |
| // Use unmapped canonical URL as default |
| m_client_req_unmapped_url_path_str = m_client_req_unmapped_url_canon_str; |
| m_client_req_unmapped_url_path_len = m_client_req_unmapped_url_canon_len; |
| |
| if (m_client_req_unmapped_url_path_len >= 6) { // xxx:// - minimum schema size |
| c = (char *) memchr((void *) m_client_req_unmapped_url_path_str, ':', m_client_req_unmapped_url_path_len - 1); |
| if (c && (len = (int) (c - m_client_req_unmapped_url_path_str)) <= 5) { // 5 - max schema size |
| if (len + 2 <= m_client_req_unmapped_url_canon_len && c[1] == '/' && c[2] == '/') { |
| len += 3; // Skip "://" |
| m_client_req_unmapped_url_host_str = &m_client_req_unmapped_url_canon_str[len]; |
| m_client_req_unmapped_url_host_len = m_client_req_unmapped_url_path_len - len; |
| // Attempt to find first '/' in the path |
| if (m_client_req_unmapped_url_host_len > 0 && |
| (c = |
| (char *) memchr((void *) m_client_req_unmapped_url_host_str, '/', |
| m_client_req_unmapped_url_path_len)) != 0) { |
| m_client_req_unmapped_url_host_len = (int) (c - m_client_req_unmapped_url_host_str); |
| m_client_req_unmapped_url_path_str = &m_client_req_unmapped_url_host_str[m_client_req_unmapped_url_host_len]; |
| m_client_req_unmapped_url_path_len = m_client_req_unmapped_url_path_len - len - m_client_req_unmapped_url_host_len; |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| |
| /*------------------------------------------------------------------------- |
| This is the method, url, and version all rolled into one. Use the |
| respective marshalling routines to do the job. |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccessHttp::marshal_client_req_text(char *buf) |
| { |
| int len = marshal_client_req_http_method(NULL) + marshal_client_req_url(NULL) + marshal_client_req_http_version(NULL); |
| |
| if (buf) { |
| int offset = 0; |
| offset += marshal_client_req_http_method(&buf[offset]); |
| offset += marshal_client_req_url(&buf[offset]); |
| offset += marshal_client_req_http_version(&buf[offset]); |
| len = offset; |
| } |
| return len; |
| } |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccessHttp::marshal_client_req_http_method(char *buf) |
| { |
| char *str = NULL; |
| int alen = 0; |
| int plen = INK_MIN_ALIGN; |
| |
| if (m_client_request) { |
| str = (char *) m_client_request->method_get(&alen); |
| |
| // calculate the the padded length only if the actual length |
| // is not zero. We don't want the padded length to be zero |
| // because marshal_mem should write the DEFAULT_STR to the |
| // buffer if str is nil, and we need room for this. |
| // |
| if (alen) { |
| plen = round_strlen(alen + 1); // +1 for trailing 0 |
| } |
| } |
| |
| if (buf) |
| marshal_mem(buf, str, alen, plen); |
| return plen; |
| } |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccessHttp::marshal_client_req_url(char *buf) |
| { |
| int len = round_strlen(m_client_req_url_len + 1); // +1 for trailing 0 |
| |
| if (buf) { |
| marshal_mem(buf, m_client_req_url_str, m_client_req_url_len, len); |
| } |
| return len; |
| } |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccessHttp::marshal_client_req_url_canon(char *buf) |
| { |
| int len = round_strlen(m_client_req_url_canon_len + 1); |
| |
| if (buf) { |
| marshal_mem(buf, m_client_req_url_canon_str, m_client_req_url_canon_len, len); |
| } |
| return len; |
| } |
| |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccessHttp::marshal_client_req_unmapped_url_canon(char *buf) |
| { |
| int len = INK_MIN_ALIGN; |
| |
| validate_unmapped_url(); |
| if (0 == m_client_req_unmapped_url_canon_len) { |
| // If the unmapped URL isn't populated, we'll fall back to the original |
| // client URL. This helps for example server intercepts to continue to |
| // log the requests, even when there is no remap rule for it. |
| len = marshal_client_req_url_canon(buf); |
| } else { |
| len = round_strlen(m_client_req_unmapped_url_canon_len + 1); // +1 for eos |
| if (buf) { |
| marshal_mem(buf, m_client_req_unmapped_url_canon_str, m_client_req_unmapped_url_canon_len, len); |
| } |
| } |
| |
| return len; |
| } |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccessHttp::marshal_client_req_unmapped_url_path(char *buf) |
| { |
| int len = INK_MIN_ALIGN; |
| |
| validate_unmapped_url(); |
| validate_unmapped_url_path(); |
| |
| if (0 == m_client_req_unmapped_url_path_len) { |
| len = marshal_client_req_url_path(buf); |
| } else { |
| len = round_strlen(m_client_req_unmapped_url_path_len + 1); // +1 for eos |
| if (buf) { |
| marshal_mem(buf, m_client_req_unmapped_url_path_str, m_client_req_unmapped_url_path_len, len); |
| } |
| } |
| return len; |
| } |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccessHttp::marshal_client_req_unmapped_url_host(char *buf) |
| { |
| int len = INK_MIN_ALIGN; |
| |
| validate_unmapped_url(); |
| validate_unmapped_url_path(); |
| |
| len = round_strlen(m_client_req_unmapped_url_host_len + 1); // +1 for eos |
| if (buf) { |
| marshal_mem(buf, m_client_req_unmapped_url_host_str, m_client_req_unmapped_url_host_len, len); |
| } |
| return len; |
| } |
| |
| int |
| LogAccessHttp::marshal_client_req_url_path(char *buf) |
| { |
| int len = round_strlen(m_client_req_url_path_len + 1); |
| if (buf) { |
| marshal_mem(buf, m_client_req_url_path_str, m_client_req_url_path_len, len); |
| } |
| return len; |
| } |
| |
| int |
| LogAccessHttp::marshal_client_req_url_scheme(char *buf) |
| { |
| char *str = NULL; |
| int alen = 0; |
| int plen = INK_MIN_ALIGN; |
| |
| str = (char *) m_client_request->scheme_get(&alen); |
| |
| // calculate the the padded length only if the actual length |
| // is not zero. We don't want the padded length to be zero |
| // because marshal_mem should write the DEFAULT_STR to the |
| // buffer if str is nil, and we need room for this. |
| // |
| if (alen) { |
| plen = round_strlen(alen + 1); // +1 for trailing 0 |
| } |
| |
| if (buf) { |
| marshal_mem(buf, str, alen, plen); |
| } |
| |
| return plen; |
| } |
| |
| /*------------------------------------------------------------------------- |
| For this one we're going to marshal two INTs, one the first representing |
| the major number and the second representing the minor. |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccessHttp::marshal_client_req_http_version(char *buf) |
| { |
| if (buf) { |
| int64_t major = 0; |
| int64_t minor = 0; |
| if (m_client_request) { |
| HTTPVersion versionObject = m_client_request->version_get(); |
| major = HTTP_MAJOR(versionObject.m_version); |
| minor = HTTP_MINOR(versionObject.m_version); |
| } |
| marshal_int(buf, major); |
| marshal_int((buf + INK_MIN_ALIGN), minor); |
| } |
| return (2 * INK_MIN_ALIGN); |
| } |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccessHttp::marshal_client_req_header_len(char *buf) |
| { |
| if (buf) { |
| int64_t len = 0; |
| if (m_client_request) { |
| len = m_client_request->length_get(); |
| } |
| marshal_int(buf, len); |
| } |
| return INK_MIN_ALIGN; |
| } |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccessHttp::marshal_client_req_body_len(char *buf) |
| { |
| if (buf) { |
| int64_t len = 0; |
| if (m_client_request) { |
| len = m_http_sm->client_request_body_bytes; |
| } |
| marshal_int(buf, len); |
| } |
| return INK_MIN_ALIGN; |
| } |
| |
| int |
| LogAccessHttp::marshal_client_finish_status_code(char *buf) |
| { |
| if (buf) { |
| int code = LOG_FINISH_FIN; |
| HttpTransact::AbortState_t cl_abort_state = m_http_sm->t_state.client_info.abort; |
| if (cl_abort_state == HttpTransact::ABORTED) { |
| |
| // Check to see if the abort is due to a timeout |
| if (m_http_sm->t_state.client_info.state == HttpTransact::ACTIVE_TIMEOUT || |
| m_http_sm->t_state.client_info.state == HttpTransact::INACTIVE_TIMEOUT) { |
| code = LOG_FINISH_TIMEOUT; |
| } else { |
| code = LOG_FINISH_INTR; |
| } |
| } |
| marshal_int(buf, code); |
| } |
| return INK_MIN_ALIGN; |
| } |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccessHttp::marshal_proxy_resp_content_type(char *buf) |
| { |
| int len = round_strlen(m_proxy_resp_content_type_len + 1); |
| if (buf) { |
| marshal_mem(buf, m_proxy_resp_content_type_str, m_proxy_resp_content_type_len, len); |
| } |
| return len; |
| } |
| |
| /*------------------------------------------------------------------------- |
| Squid returns the content-length + header length as the total length. |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccessHttp::marshal_proxy_resp_squid_len(char *buf) |
| { |
| if (buf) { |
| int64_t val = m_http_sm->client_response_hdr_bytes + m_http_sm->client_response_body_bytes; |
| marshal_int(buf, val); |
| } |
| return INK_MIN_ALIGN; |
| } |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccessHttp::marshal_proxy_resp_content_len(char *buf) |
| { |
| if (buf) { |
| int64_t val = m_http_sm->client_response_body_bytes; |
| marshal_int(buf, val); |
| } |
| return INK_MIN_ALIGN; |
| } |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccessHttp::marshal_proxy_resp_status_code(char *buf) |
| { |
| if (buf) { |
| HTTPStatus status; |
| if (m_proxy_response && m_client_request) { |
| if (m_client_request->version_get() >= HTTPVersion(1, 0)) { |
| status = m_proxy_response->status_get(); |
| } |
| // INKqa10788 |
| // For bad/incomplete request, the request version may be 0.9. |
| // However, we can still log the status code if there is one. |
| else if (m_proxy_response->valid()) { |
| status = m_proxy_response->status_get(); |
| } else { |
| status = HTTP_STATUS_OK; |
| } |
| } else { |
| status = HTTP_STATUS_NONE; |
| } |
| marshal_int(buf, (int64_t) status); |
| } |
| return INK_MIN_ALIGN; |
| } |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccessHttp::marshal_proxy_resp_header_len(char *buf) |
| { |
| if (buf) { |
| int64_t val = 0; |
| if (m_proxy_response) { |
| val = m_proxy_response->length_get(); |
| } |
| marshal_int(buf, val); |
| } |
| return INK_MIN_ALIGN; |
| } |
| |
| int |
| LogAccessHttp::marshal_proxy_finish_status_code(char *buf) |
| { |
| /* FIXME: Should there be no server transaction code if |
| the result comes out of the cache. Right now we default |
| to FIN */ |
| if (buf) { |
| int code = LOG_FINISH_FIN; |
| if (m_http_sm->t_state.current.server) { |
| switch (m_http_sm->t_state.current.server->state) { |
| case HttpTransact::ACTIVE_TIMEOUT: |
| case HttpTransact::INACTIVE_TIMEOUT: |
| code = LOG_FINISH_TIMEOUT; |
| break; |
| case HttpTransact::CONNECTION_ERROR: |
| code = LOG_FINISH_INTR; |
| break; |
| default: |
| if (m_http_sm->t_state.current.server->abort == HttpTransact::ABORTED) { |
| code = LOG_FINISH_INTR; |
| } |
| break; |
| } |
| } |
| |
| marshal_int(buf, code); |
| } |
| |
| return INK_MIN_ALIGN; |
| } |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccessHttp::marshal_cache_result_code(char *buf) |
| { |
| if (buf) { |
| SquidLogCode code = m_http_sm->t_state.squid_codes.log_code; |
| marshal_int(buf, (int64_t) code); |
| } |
| return INK_MIN_ALIGN; |
| } |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccessHttp::marshal_proxy_req_header_len(char *buf) |
| { |
| if (buf) { |
| int64_t val = 0; |
| if (m_proxy_request) { |
| val = m_proxy_request->length_get(); |
| } |
| marshal_int(buf, val); |
| } |
| return INK_MIN_ALIGN; |
| } |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccessHttp::marshal_proxy_req_body_len(char *buf) |
| { |
| if (buf) { |
| int64_t val = 0; |
| if (m_proxy_request) { |
| val = m_http_sm->server_request_body_bytes; |
| } |
| marshal_int(buf, val); |
| } |
| return INK_MIN_ALIGN; |
| } |
| |
| int |
| LogAccessHttp::marshal_proxy_req_server_name(char *buf) |
| { |
| char *str = NULL; |
| int len = INK_MIN_ALIGN; |
| |
| if (m_http_sm->t_state.current.server) { |
| str = m_http_sm->t_state.current.server->name; |
| len = LogAccess::strlen(str); |
| } |
| |
| if (buf) { |
| marshal_str(buf, str, len); |
| } |
| return len; |
| } |
| |
| // TODO: Change marshalling code to support both IPv4 and IPv6 addresses. |
| int |
| LogAccessHttp::marshal_proxy_req_server_ip(char *buf) |
| { |
| return marshal_ip(buf, m_http_sm->t_state.current.server != NULL ? &m_http_sm->t_state.current.server->addr.sa : 0); |
| } |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccessHttp::marshal_proxy_hierarchy_route(char *buf) |
| { |
| if (buf) { |
| SquidHierarchyCode code = m_http_sm->t_state.squid_codes.hier_code; |
| marshal_int(buf, (int64_t) code); |
| } |
| return INK_MIN_ALIGN; |
| } |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| // TODO: Change marshalling code to support both IPv4 and IPv6 addresses. |
| int |
| LogAccessHttp::marshal_server_host_ip(char *buf) |
| { |
| sockaddr const* ip = 0; |
| ip = &m_http_sm->t_state.server_info.addr.sa; |
| if (! ats_is_ip(ip)) { |
| if (m_http_sm->t_state.current.server) { |
| ip = &m_http_sm->t_state.current.server->addr.sa; |
| if (! ats_is_ip(ip)) ip = 0; |
| } else { |
| ip = 0; |
| } |
| } |
| return marshal_ip(buf, ip); |
| } |
| |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccessHttp::marshal_server_host_name(char *buf) |
| { |
| char const* str = NULL; |
| int padded_len = INK_MIN_ALIGN; |
| int actual_len = 0; |
| |
| if (m_client_request) { |
| str = m_client_request->host_get(&actual_len); |
| |
| if (str) |
| padded_len = round_strlen(actual_len + 1); // +1 for trailing 0 |
| } |
| if (buf) { |
| marshal_mem(buf, str, actual_len, padded_len); |
| } |
| return padded_len; |
| } |
| |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccessHttp::marshal_client_accelerator_id(char *buf) |
| { |
| char *str = NULL; |
| int padded_len = INK_MIN_ALIGN; |
| int actual_len = 0; |
| |
| if (Log::config->xuid_logging_enabled) { |
| if (m_client_request) { |
| MIMEField *field = m_client_request->field_find(MIME_FIELD_X_ID, MIME_LEN_X_ID); |
| |
| if (field) { |
| str = (char *) field->value_get(&actual_len); |
| /* Ugly subtlety here. marshal_mem, despite the name, adds a |
| terminating nul. It does this at the index actual_len and |
| so requires paddedlen > actual_len (why it can't do the |
| padding calculation escapes me - are there instances where |
| that's different? |
| */ |
| padded_len = round_strlen(actual_len+1); |
| } |
| } |
| } |
| |
| if (buf) { |
| marshal_mem(buf, str, actual_len, padded_len); |
| } |
| return padded_len; |
| } |
| |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccessHttp::marshal_server_resp_status_code(char *buf) |
| { |
| if (buf) { |
| HTTPStatus status; |
| if (m_server_response) { |
| status = m_server_response->status_get(); |
| } else { |
| status = HTTP_STATUS_NONE; |
| } |
| marshal_int(buf, (int64_t) status); |
| } |
| return INK_MIN_ALIGN; |
| } |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccessHttp::marshal_server_resp_content_len(char *buf) |
| { |
| if (buf) { |
| int64_t val = 0; |
| if (m_server_response) { |
| val = m_http_sm->server_response_body_bytes; |
| } |
| marshal_int(buf, val); |
| } |
| return INK_MIN_ALIGN; |
| } |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccessHttp::marshal_server_resp_header_len(char *buf) |
| { |
| if (buf) { |
| int64_t val = 0; |
| if (m_server_response) { |
| val = m_server_response->length_get(); |
| } |
| marshal_int(buf, val); |
| } |
| return INK_MIN_ALIGN; |
| } |
| |
| int |
| LogAccessHttp::marshal_server_resp_http_version(char *buf) |
| { |
| if (buf) { |
| int64_t major = 0; |
| int64_t minor = 0; |
| if (m_server_response) { |
| major = HTTP_MAJOR(m_server_response->version_get().m_version); |
| minor = HTTP_MINOR(m_server_response->version_get().m_version); |
| } |
| marshal_int(buf, major); |
| marshal_int((buf + INK_MIN_ALIGN), minor); |
| } |
| return (2 * INK_MIN_ALIGN); |
| } |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccessHttp::marshal_cache_resp_status_code(char *buf) |
| { |
| if (buf) { |
| HTTPStatus status; |
| if (m_cache_response) { |
| status = m_cache_response->status_get(); |
| } else { |
| status = HTTP_STATUS_NONE; |
| } |
| marshal_int(buf, (int64_t) status); |
| } |
| return INK_MIN_ALIGN; |
| } |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccessHttp::marshal_cache_resp_content_len(char *buf) |
| { |
| if (buf) { |
| int64_t val = 0; |
| if (m_cache_response) { |
| val = m_http_sm->cache_response_body_bytes; |
| } |
| marshal_int(buf, val); |
| } |
| return INK_MIN_ALIGN; |
| } |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccessHttp::marshal_cache_resp_header_len(char *buf) |
| { |
| if (buf) { |
| int64_t val = 0; |
| if (m_cache_response) { |
| val = m_http_sm->cache_response_hdr_bytes; |
| } |
| marshal_int(buf, val); |
| } |
| return INK_MIN_ALIGN; |
| } |
| |
| int |
| LogAccessHttp::marshal_cache_resp_http_version(char *buf) |
| { |
| if (buf) { |
| int64_t major = 0; |
| int64_t minor = 0; |
| if (m_cache_response) { |
| major = HTTP_MAJOR(m_cache_response->version_get().m_version); |
| minor = HTTP_MINOR(m_cache_response->version_get().m_version); |
| } |
| marshal_int(buf, major); |
| marshal_int((buf + INK_MIN_ALIGN), minor); |
| } |
| return (2 * INK_MIN_ALIGN); |
| } |
| |
| |
| int |
| LogAccessHttp::marshal_client_retry_after_time(char *buf) |
| { |
| if (buf) { |
| int64_t crat = m_http_sm->t_state.congestion_control_crat; |
| marshal_int(buf, crat); |
| } |
| return INK_MIN_ALIGN; |
| } |
| |
| static LogCacheWriteCodeType |
| convert_cache_write_code(HttpTransact::CacheWriteStatus_t t) |
| { |
| |
| LogCacheWriteCodeType code; |
| switch (t) { |
| case HttpTransact::NO_CACHE_WRITE: |
| code = LOG_CACHE_WRITE_NONE; |
| break; |
| case HttpTransact::CACHE_WRITE_LOCK_MISS: |
| code = LOG_CACHE_WRITE_LOCK_MISSED; |
| break; |
| case HttpTransact::CACHE_WRITE_IN_PROGRESS: |
| // Hack - the HttpSM doesn't record |
| // cache write aborts currently so |
| // if it's not complete declare it |
| // aborted |
| code = LOG_CACHE_WRITE_LOCK_ABORTED; |
| break; |
| case HttpTransact::CACHE_WRITE_ERROR: |
| code = LOG_CACHE_WRITE_ERROR; |
| break; |
| case HttpTransact::CACHE_WRITE_COMPLETE: |
| code = LOG_CACHE_WRITE_COMPLETE; |
| break; |
| default: |
| ink_assert(!"bad cache write code"); |
| code = LOG_CACHE_WRITE_NONE; |
| break; |
| } |
| |
| return code; |
| } |
| |
| |
| int |
| LogAccessHttp::marshal_cache_write_code(char *buf) |
| { |
| |
| if (buf) { |
| int code = convert_cache_write_code(m_http_sm->t_state.cache_info.write_status); |
| marshal_int(buf, code); |
| } |
| |
| return INK_MIN_ALIGN; |
| } |
| |
| int |
| LogAccessHttp::marshal_cache_write_transform_code(char *buf) |
| { |
| |
| if (buf) { |
| int code = convert_cache_write_code(m_http_sm->t_state.cache_info.transform_write_status); |
| marshal_int(buf, code); |
| } |
| |
| return INK_MIN_ALIGN; |
| } |
| |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccessHttp::marshal_transfer_time_ms(char *buf) |
| { |
| if (buf) { |
| ink_hrtime elapsed = m_http_sm->milestones.sm_finish - m_http_sm->milestones.sm_start; |
| elapsed /= HRTIME_MSECOND; |
| int64_t val = (int64_t) elapsed; |
| marshal_int(buf, val); |
| } |
| return INK_MIN_ALIGN; |
| } |
| |
| int |
| LogAccessHttp::marshal_transfer_time_s(char *buf) |
| { |
| if (buf) { |
| ink_hrtime elapsed = m_http_sm->milestones.sm_finish - m_http_sm->milestones.sm_start; |
| elapsed /= HRTIME_SECOND; |
| int64_t val = (int64_t) elapsed; |
| marshal_int(buf, val); |
| } |
| return INK_MIN_ALIGN; |
| } |
| |
| /*------------------------------------------------------------------------- |
| Figure out the size of the object *on origin*. This is somewhat tricky |
| since there are many variations on how this can be calculated. |
| -------------------------------------------------------------------------*/ |
| int |
| LogAccessHttp::marshal_file_size(char *buf) |
| { |
| if (buf) { |
| MIMEField *fld; |
| HTTPHdr *hdr = m_server_response ? m_server_response : m_cache_response; |
| |
| if (hdr && (fld = hdr->field_find(MIME_FIELD_CONTENT_RANGE, MIME_LEN_CONTENT_RANGE))) { |
| int len; |
| char *str = (char*)fld->value_get(&len); |
| char *pos = (char*)memchr(str, '/', len); // Find the / |
| |
| // If the size is not /* (which means unknown) use it as the file_size. |
| if (pos && !memchr(pos+1, '*', len - (pos + 1 - str))) { |
| marshal_int(buf, ink_atoi64(pos+1, len - (pos + 1 - str))); |
| } |
| } else { |
| // This is semi-broken when we serveq zero length objects. See TS-2213 |
| if (m_http_sm->server_response_body_bytes > 0) |
| marshal_int(buf, m_http_sm->server_response_body_bytes); |
| else if (m_http_sm->cache_response_body_bytes > 0) |
| marshal_int(buf, m_http_sm->cache_response_body_bytes); |
| } |
| } |
| // Else, we don't set the value at all (so, -) |
| |
| return INK_MIN_ALIGN; |
| } |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccessHttp::marshal_http_header_field(LogField::Container container, char *field, char *buf) |
| { |
| char *str = NULL; |
| int padded_len = INK_MIN_ALIGN; |
| int actual_len = 0; |
| bool valid_field = false; |
| HTTPHdr *header; |
| |
| switch (container) { |
| case LogField::CQH: |
| header = m_client_request; |
| break; |
| |
| case LogField::PSH: |
| header = m_proxy_response; |
| break; |
| |
| case LogField::PQH: |
| header = m_proxy_request; |
| break; |
| |
| case LogField::SSH: |
| header = m_server_response; |
| break; |
| |
| case LogField::CSSH: |
| header = m_cache_response; |
| break; |
| |
| default: |
| header = NULL; |
| break; |
| } |
| |
| if (header) { |
| MIMEField *fld = header->field_find(field, (int)::strlen(field)); |
| if (fld) { |
| valid_field = true; |
| |
| // Loop over dups, marshalling each one into the buffer and |
| // summing up their length |
| // |
| int running_len = 0; |
| while (fld) { |
| str = (char *) fld->value_get(&actual_len); |
| if (buf) { |
| memcpy(buf, str, actual_len); |
| buf += actual_len; |
| } |
| running_len += actual_len; |
| fld = fld->m_next_dup; |
| |
| // Dups need to be comma separated. So if there's another |
| // dup, then add a comma and a space ... |
| // |
| if (fld != NULL) { |
| if (buf) { |
| memcpy(buf, ", ", 2); |
| buf += 2; |
| } |
| running_len += 2; |
| } |
| } |
| |
| // Done with all dups. Ensure that the string is terminated |
| // and that the running_len is padded. |
| // |
| if (buf) { |
| *buf = '\0'; |
| buf++; |
| } |
| running_len += 1; |
| padded_len = round_strlen(running_len); |
| |
| // Note: marshal_string fills the padding to |
| // prevent purify UMRs so we do it here too |
| // since we always pass the unpadded length on |
| // our calls to marshal string |
| #ifdef DEBUG |
| if (buf) { |
| int pad_len = padded_len - running_len; |
| for (int i = 0; i < pad_len; i++) { |
| *buf = '$'; |
| buf++; |
| } |
| } |
| #endif |
| } |
| } |
| |
| if (valid_field == false) { |
| padded_len = INK_MIN_ALIGN; |
| if (buf) { |
| marshal_str(buf, NULL, padded_len); |
| } |
| } |
| |
| return (padded_len); |
| } |
| |
| int |
| LogAccessHttp::marshal_http_header_field_escapify(LogField::Container container, char *field, char *buf) |
| { |
| char *str = NULL, *new_str = NULL; |
| int padded_len = INK_MIN_ALIGN; |
| int actual_len = 0, new_len = 0; |
| bool valid_field = false; |
| HTTPHdr *header; |
| |
| switch (container) { |
| case LogField::ECQH: |
| header = m_client_request; |
| break; |
| |
| case LogField::EPSH: |
| header = m_proxy_response; |
| break; |
| |
| case LogField::EPQH: |
| header = m_proxy_request; |
| break; |
| |
| case LogField::ESSH: |
| header = m_server_response; |
| break; |
| |
| case LogField::ECSSH: |
| header = m_cache_response; |
| break; |
| |
| default: |
| header = NULL; |
| break; |
| } |
| |
| if (header) { |
| MIMEField *fld = header->field_find(field, (int)::strlen(field)); |
| if (fld) { |
| valid_field = true; |
| |
| // Loop over dups, marshalling each one into the buffer and |
| // summing up their length |
| // |
| int running_len = 0; |
| while (fld) { |
| str = (char *) fld->value_get(&actual_len); |
| new_str = LogUtils::escapify_url(&m_arena, str, actual_len, &new_len); |
| if (buf) { |
| memcpy(buf, new_str, new_len); |
| buf += new_len; |
| } |
| running_len += new_len; |
| fld = fld->m_next_dup; |
| |
| // Dups need to be comma separated. So if there's another |
| // dup, then add a comma and a space ... |
| // |
| if (fld != NULL) { |
| if (buf) { |
| memcpy(buf, ", ", 2); |
| buf += 2; |
| } |
| running_len += 2; |
| } |
| } |
| |
| // Done with all dups. Ensure that the string is terminated |
| // and that the running_len is padded. |
| // |
| if (buf) { |
| *buf = '\0'; |
| buf++; |
| } |
| running_len += 1; |
| padded_len = round_strlen(running_len); |
| |
| // Note: marshal_string fills the padding to |
| // prevent purify UMRs so we do it here too |
| // since we always pass the unpadded length on |
| // our calls to marshal string |
| #ifdef DEBUG |
| if (buf) { |
| int pad_len = padded_len - running_len; |
| for (int i = 0; i < pad_len; i++) { |
| *buf = '$'; |
| buf++; |
| } |
| } |
| #endif |
| } |
| } |
| |
| if (valid_field == false) { |
| padded_len = INK_MIN_ALIGN; |
| if (buf) { |
| marshal_str(buf, NULL, padded_len); |
| } |
| } |
| |
| return (padded_len); |
| } |