You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@trafficserver.apache.org by danobi <gi...@git.apache.org> on 2016/11/07 22:58:47 UTC

[GitHub] trafficserver pull request #1210: Create log_requests plugin

GitHub user danobi opened a pull request:

    https://github.com/apache/trafficserver/pull/1210

    Create log_requests plugin

    This plugin records status line & headers for all 4xx/5xx response
    transactions. Also included is a blacklist feature to omit any
    specific response code transactions. eg. you can choose to not
    log transactions with response code 415.
    
    See included README for instructions.
    
    Next steps:
    - Include plugin flag to also log proxy request/responses
    - Use more robust option parsing

You can merge this pull request into a Git repository by running:

    $ git pull https://github.com/danobi/trafficserver log_requests

Alternatively you can review and apply these changes as the patch at:

    https://github.com/apache/trafficserver/pull/1210.patch

To close this pull request, make a commit to your master/trunk branch
with (at least) the following in the commit message:

    This closes #1210
    
----
commit 44ea7eca11f043f24be3c75dab9aa9c391efc2bc
Author: Daniel Xu <dl...@yahoo.com>
Date:   2016-11-07T22:54:41Z

    Create log_requests plugin
    
    This plugin records status line & headers for all 4xx/5xx response
    transactions. Also included is a blacklist feature to omit any
    specific response code transactions. eg. you can choose to not
    log transactions with response code 415.
    
    See included README for instructions.

----


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] trafficserver pull request #1210: Create log_requests plugin

Posted by danobi <gi...@git.apache.org>.
Github user danobi commented on a diff in the pull request:

    https://github.com/apache/trafficserver/pull/1210#discussion_r89882819
  
    --- Diff: plugins/experimental/log_requests/log_requests.cc ---
    @@ -0,0 +1,352 @@
    +/** @file
    +
    +  Logs full request/response headers on an error response code (4xx/5xx)
    +
    +  @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.
    + */
    +
    +#include <stdio.h>
    +#include <string.h>
    +#include <ctype.h>
    +
    +#include <vector>
    +#include <algorithm>
    +#include <string>
    +
    +#include "ts/ts.h"
    +#include "ts/ink_defs.h"
    +#include "ts/ink_args.h"
    +#include "ts/I_Version.h"
    +
    +#define PLUGIN_NAME "log_requests"
    +#define B_PLUGIN_NAME "[" PLUGIN_NAME "]"
    +
    +static char arg_blacklist[2048]             = "";
    +static bool log_proxy                       = false;
    +ArgumentDescription argument_descriptions[] = {
    +  {"no-log", '-', "Comma-separated list of status codes to blacklist", "S2047", arg_blacklist, nullptr, nullptr},
    +  {"log-proxy", 'p', "Also log proxy request and proxy response transaction", "F", &log_proxy, nullptr, nullptr},
    +};
    +
    +// we log the set of errors in {errors} - {blacklist}
    +static std::vector<TSHttpStatus> blacklist;
    +static std::vector<TSHttpStatus> errors({TS_HTTP_STATUS_BAD_REQUEST,
    +                                         TS_HTTP_STATUS_UNAUTHORIZED,
    +                                         TS_HTTP_STATUS_PAYMENT_REQUIRED,
    +                                         TS_HTTP_STATUS_FORBIDDEN,
    +                                         TS_HTTP_STATUS_NOT_FOUND,
    +                                         TS_HTTP_STATUS_METHOD_NOT_ALLOWED,
    +                                         TS_HTTP_STATUS_NOT_ACCEPTABLE,
    +                                         TS_HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED,
    +                                         TS_HTTP_STATUS_REQUEST_TIMEOUT,
    +                                         TS_HTTP_STATUS_CONFLICT,
    +                                         TS_HTTP_STATUS_GONE,
    +                                         TS_HTTP_STATUS_LENGTH_REQUIRED,
    +                                         TS_HTTP_STATUS_PRECONDITION_FAILED,
    +                                         TS_HTTP_STATUS_REQUEST_ENTITY_TOO_LARGE,
    +                                         TS_HTTP_STATUS_REQUEST_URI_TOO_LONG,
    +                                         TS_HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE,
    +                                         TS_HTTP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE,
    +                                         TS_HTTP_STATUS_EXPECTATION_FAILED,
    +                                         TS_HTTP_STATUS_UNPROCESSABLE_ENTITY,
    +                                         TS_HTTP_STATUS_LOCKED,
    +                                         TS_HTTP_STATUS_FAILED_DEPENDENCY,
    +                                         TS_HTTP_STATUS_UPGRADE_REQUIRED,
    +                                         TS_HTTP_STATUS_PRECONDITION_REQUIRED,
    +                                         TS_HTTP_STATUS_TOO_MANY_REQUESTS,
    +                                         TS_HTTP_STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE,
    +                                         TS_HTTP_STATUS_INTERNAL_SERVER_ERROR,
    +                                         TS_HTTP_STATUS_NOT_IMPLEMENTED,
    +                                         TS_HTTP_STATUS_BAD_GATEWAY,
    +                                         TS_HTTP_STATUS_SERVICE_UNAVAILABLE,
    +                                         TS_HTTP_STATUS_GATEWAY_TIMEOUT,
    +                                         TS_HTTP_STATUS_HTTPVER_NOT_SUPPORTED,
    +                                         TS_HTTP_STATUS_VARIANT_ALSO_NEGOTIATES,
    +                                         TS_HTTP_STATUS_INSUFFICIENT_STORAGE,
    +                                         TS_HTTP_STATUS_LOOP_DETECTED,
    +                                         TS_HTTP_STATUS_NOT_EXTENDED,
    +                                         TS_HTTP_STATUS_NETWORK_AUTHENTICATION_REQUIRED});
    +
    +static bool should_log(TSHttpTxn txnp);
    +static const std::string convert_http_version(const int version);
    +static void log_request_line(TSMBuffer bufp, TSMLoc loc, std::string output_header);
    +static void log_response_status_line(TSMBuffer bufp, TSMLoc loc, std::string output_header);
    +static void log_headers(TSMBuffer bufp, TSMLoc loc, std::string output_header);
    +static void log_full_transaction(TSHttpTxn txnp);
    +static int log_requests_plugin(TSCont contp ATS_UNUSED, TSEvent event, void *edata);
    +static std::vector<std::string> split(const std::string &str, const std::string &delim);
    +
    +static std::vector<std::string>
    +split(const std::string &str, const std::string &delim)
    +{
    +  std::vector<std::string> tokens;
    +  size_t prev = 0, pos = 0;
    +  do {
    +    pos = str.find(delim, prev);
    +    if (pos == std::string::npos)
    +      pos = str.length();
    +
    +    std::string token = str.substr(prev, pos - prev);
    +    if (!token.empty())
    +      tokens.push_back(token);
    +
    +    prev = pos + delim.length();
    +  } while (pos < str.length() && prev < str.length());
    +
    +  return tokens;
    +}
    +
    +static bool
    +should_log(TSHttpTxn txnp)
    +{
    +  TSMBuffer txn_resp_bufp;
    +  TSMLoc txn_resp_loc;
    +  TSHttpStatus resp_status;
    +
    +  if (TSHttpTxnClientRespGet(txnp, &txn_resp_bufp, &txn_resp_loc) != TS_SUCCESS) {
    +    TSError(B_PLUGIN_NAME " Couldn't retrieve server response header.");
    +    return false;
    +  }
    +
    +  // get the transaction response status code
    +  resp_status = TSHttpHdrStatusGet(txn_resp_bufp, txn_resp_loc);
    +
    +  // if resp_status is blacklisted, don't log
    +  if (std::any_of(blacklist.begin(), blacklist.end(), [=](TSHttpStatus code) { return code == resp_status; }))
    +    return false;
    +
    +  // else, if resp_status is in errors, log it
    +  if (std::any_of(errors.begin(), errors.end(), [=](TSHttpStatus error) { return error == resp_status; }))
    +    return true;
    +
    +  // fall through
    +  return false;
    +}
    +
    +static const std::string
    +convert_http_version(const int version)
    +{
    +  if (version == TS_HTTP_VERSION(1, 0))
    +    return "HTTP/1.0";
    +  else if (version == TS_HTTP_VERSION(1, 1))
    +    return "HTTP/1.1";
    +  else if (version == TS_HTTP_VERSION(1, 2))
    +    return "HTTP/1.2";
    +  else if (version == TS_HTTP_VERSION(2, 0))
    +    return "HTTP/2.0";
    +  else {
    +    return "(Unknown HTTP version)";
    +  }
    +}
    +
    +static void
    +log_request_line(TSMBuffer bufp, TSMLoc loc, std::string output_header)
    +{
    +  int method_len;
    +  int url_len;
    +  const char *method;
    +  const char *url;
    +  TSMLoc url_loc;
    +
    +  // parse method
    +  method = TSHttpHdrMethodGet(bufp, loc, &method_len);
    +
    +  // parse version
    +  const std::string version = convert_http_version(TSHttpHdrVersionGet(bufp, loc));
    +
    +  // parse request line URL
    +  TSHttpHdrUrlGet(bufp, loc, &url_loc);
    +  url = TSUrlStringGet(bufp, url_loc, &url_len);
    +
    +  // get rid of the preceeding http:// on the request URI
    +  for (int i = 0; i < 7; ++i)
    +    url++;
    +  url_len -= 7;
    +
    +  TSError(B_PLUGIN_NAME " [%s] request line is:\n%.*s %.*s %s\n", output_header.c_str(), method_len, method, url_len, url,
    +          version.c_str());
    +}
    +
    +static void
    +log_response_status_line(TSMBuffer bufp, TSMLoc loc, std::string output_header)
    +{
    +  TSHttpStatus status_code;
    +  const char *explanation;
    +  int explanation_len;
    +
    +  // parse version
    +  const std::string version = convert_http_version(TSHttpHdrVersionGet(bufp, loc));
    +
    +  // parse status code
    +  status_code = TSHttpHdrStatusGet(bufp, loc);
    +
    +  // get explanation
    +  explanation = TSHttpHdrReasonGet(bufp, loc, &explanation_len);
    +
    +  TSError(B_PLUGIN_NAME " [%s] response status line is:\n%s %d %.*s\n", output_header.c_str(), version.c_str(), status_code,
    +          explanation_len, explanation);
    +}
    +
    +static void
    +log_headers(TSMBuffer bufp, TSMLoc loc, std::string output_header)
    +{
    +  TSIOBuffer output_buffer;
    +  TSIOBufferReader reader;
    +  TSIOBufferBlock block;
    +  const char *block_start;
    +  int64_t block_avail;
    +
    +  output_buffer = TSIOBufferCreate();
    +  reader        = TSIOBufferReaderAlloc(output_buffer);
    +
    +  // This will print just MIMEFields and not the http request line
    +  TSMimeHdrPrint(bufp, loc, output_buffer);
    +
    +  // We need to loop over all the buffer blocks, there can be more than 1
    +  block = TSIOBufferReaderStart(reader);
    +  do {
    --- End diff --
    
    So you're saying only we only need to call `TSIOBufferReaderConsume` once?
    
    Also, any specific reason to `alloca`? Couldn't we blow the stack with a potentially large # of headers?


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] trafficserver pull request #1210: Create log_requests plugin

Posted by danobi <gi...@git.apache.org>.
Github user danobi closed the pull request at:

    https://github.com/apache/trafficserver/pull/1210


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] trafficserver pull request #1210: Create log_requests plugin

Posted by danobi <gi...@git.apache.org>.
Github user danobi commented on a diff in the pull request:

    https://github.com/apache/trafficserver/pull/1210#discussion_r87227079
  
    --- Diff: plugins/experimental/log_requests/log_requests.c ---
    @@ -0,0 +1,301 @@
    +/** @file
    +
    +  Logs full request/response headers on an error response code (4xx/5xx)
    +
    +  @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.
    + */
    +
    +#include <stdio.h>
    +#include <string.h>
    +#include <ctype.h>
    +
    +#include "ts/ts.h"
    +#include "ts/ink_defs.h"
    +
    +#define PLUGIN_NAME log_requests
    +
    +// we log the set of errors in {errors} - {blacklist}
    +static TSHttpStatus *blacklist;
    +static int blacklist_size; // number of entries in blacklist
    +static TSHttpStatus errors[] = {TS_HTTP_STATUS_BAD_REQUEST,
    +                                TS_HTTP_STATUS_UNAUTHORIZED,
    +                                TS_HTTP_STATUS_PAYMENT_REQUIRED,
    +                                TS_HTTP_STATUS_FORBIDDEN,
    +                                TS_HTTP_STATUS_NOT_FOUND,
    +                                TS_HTTP_STATUS_METHOD_NOT_ALLOWED,
    +                                TS_HTTP_STATUS_NOT_ACCEPTABLE,
    +                                TS_HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED,
    +                                TS_HTTP_STATUS_REQUEST_TIMEOUT,
    +                                TS_HTTP_STATUS_CONFLICT,
    +                                TS_HTTP_STATUS_GONE,
    +                                TS_HTTP_STATUS_LENGTH_REQUIRED,
    +                                TS_HTTP_STATUS_PRECONDITION_FAILED,
    +                                TS_HTTP_STATUS_REQUEST_ENTITY_TOO_LARGE,
    +                                TS_HTTP_STATUS_REQUEST_URI_TOO_LONG,
    +                                TS_HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE,
    +                                TS_HTTP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE,
    +                                TS_HTTP_STATUS_EXPECTATION_FAILED,
    +                                TS_HTTP_STATUS_UNPROCESSABLE_ENTITY,
    +                                TS_HTTP_STATUS_LOCKED,
    +                                TS_HTTP_STATUS_FAILED_DEPENDENCY,
    +                                TS_HTTP_STATUS_UPGRADE_REQUIRED,
    +                                TS_HTTP_STATUS_PRECONDITION_REQUIRED,
    +                                TS_HTTP_STATUS_TOO_MANY_REQUESTS,
    +                                TS_HTTP_STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE,
    +                                TS_HTTP_STATUS_INTERNAL_SERVER_ERROR,
    +                                TS_HTTP_STATUS_NOT_IMPLEMENTED,
    +                                TS_HTTP_STATUS_BAD_GATEWAY,
    +                                TS_HTTP_STATUS_SERVICE_UNAVAILABLE,
    +                                TS_HTTP_STATUS_GATEWAY_TIMEOUT,
    +                                TS_HTTP_STATUS_HTTPVER_NOT_SUPPORTED,
    +                                TS_HTTP_STATUS_VARIANT_ALSO_NEGOTIATES,
    +                                TS_HTTP_STATUS_INSUFFICIENT_STORAGE,
    +                                TS_HTTP_STATUS_LOOP_DETECTED,
    +                                TS_HTTP_STATUS_NOT_EXTENDED,
    +                                TS_HTTP_STATUS_NETWORK_AUTHENTICATION_REQUIRED};
    +
    +static bool should_log(TSHttpTxn txnp);
    +static void log_request_line(TSMBuffer bufp, TSMLoc loc, const char *output_header);
    +static void log_response_status_line(TSMBuffer bufp, TSMLoc loc, const char *output_header);
    +static void log_headers(TSMBuffer bufp, TSMLoc loc, const char *output_header);
    +static void log_full_transaction(TSHttpTxn txnp);
    +static int log_requests_plugin(TSCont contp ATS_UNUSED, TSEvent event, void *edata);
    +
    +static bool
    +should_log(TSHttpTxn txnp)
    +{
    +  TSMBuffer txn_resp_bufp;
    +  TSMLoc txn_resp_loc;
    +  TSHttpStatus resp_status;
    +
    +  if (TSHttpTxnClientRespGet(txnp, &txn_resp_bufp, &txn_resp_loc) != TS_SUCCESS) {
    +    TSError("[log_requests] Couldn't retrieve server response header.");
    +    return false;
    +  }
    +
    +  // if resp_status is blacklisted, don't log
    +  resp_status = TSHttpHdrStatusGet(txn_resp_bufp, txn_resp_loc);
    +  for (int i = 0; i < blacklist_size; ++i) {
    +    if (resp_status == blacklist[i])
    +      return false;
    +  }
    --- End diff --
    
    This is a C plugin. I couldn't figure out how to use the cppapi :)


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] trafficserver pull request #1210: Create log_requests plugin

Posted by zwoop <gi...@git.apache.org>.
Github user zwoop commented on a diff in the pull request:

    https://github.com/apache/trafficserver/pull/1210#discussion_r86890566
  
    --- Diff: plugins/experimental/log_requests/log_requests.c ---
    @@ -0,0 +1,301 @@
    +/** @file
    +
    +  Logs full request/response headers on an error response code (4xx/5xx)
    +
    +  @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.
    + */
    +
    +#include <stdio.h>
    +#include <string.h>
    +#include <ctype.h>
    +
    +#include "ts/ts.h"
    +#include "ts/ink_defs.h"
    +
    +#define PLUGIN_NAME log_requests
    +
    +// we log the set of errors in {errors} - {blacklist}
    +static TSHttpStatus *blacklist;
    +static int blacklist_size; // number of entries in blacklist
    +static TSHttpStatus errors[] = {TS_HTTP_STATUS_BAD_REQUEST,
    +                                TS_HTTP_STATUS_UNAUTHORIZED,
    +                                TS_HTTP_STATUS_PAYMENT_REQUIRED,
    +                                TS_HTTP_STATUS_FORBIDDEN,
    +                                TS_HTTP_STATUS_NOT_FOUND,
    +                                TS_HTTP_STATUS_METHOD_NOT_ALLOWED,
    +                                TS_HTTP_STATUS_NOT_ACCEPTABLE,
    +                                TS_HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED,
    +                                TS_HTTP_STATUS_REQUEST_TIMEOUT,
    +                                TS_HTTP_STATUS_CONFLICT,
    +                                TS_HTTP_STATUS_GONE,
    +                                TS_HTTP_STATUS_LENGTH_REQUIRED,
    +                                TS_HTTP_STATUS_PRECONDITION_FAILED,
    +                                TS_HTTP_STATUS_REQUEST_ENTITY_TOO_LARGE,
    +                                TS_HTTP_STATUS_REQUEST_URI_TOO_LONG,
    +                                TS_HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE,
    +                                TS_HTTP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE,
    +                                TS_HTTP_STATUS_EXPECTATION_FAILED,
    +                                TS_HTTP_STATUS_UNPROCESSABLE_ENTITY,
    +                                TS_HTTP_STATUS_LOCKED,
    +                                TS_HTTP_STATUS_FAILED_DEPENDENCY,
    +                                TS_HTTP_STATUS_UPGRADE_REQUIRED,
    +                                TS_HTTP_STATUS_PRECONDITION_REQUIRED,
    +                                TS_HTTP_STATUS_TOO_MANY_REQUESTS,
    +                                TS_HTTP_STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE,
    +                                TS_HTTP_STATUS_INTERNAL_SERVER_ERROR,
    +                                TS_HTTP_STATUS_NOT_IMPLEMENTED,
    +                                TS_HTTP_STATUS_BAD_GATEWAY,
    +                                TS_HTTP_STATUS_SERVICE_UNAVAILABLE,
    +                                TS_HTTP_STATUS_GATEWAY_TIMEOUT,
    +                                TS_HTTP_STATUS_HTTPVER_NOT_SUPPORTED,
    +                                TS_HTTP_STATUS_VARIANT_ALSO_NEGOTIATES,
    +                                TS_HTTP_STATUS_INSUFFICIENT_STORAGE,
    +                                TS_HTTP_STATUS_LOOP_DETECTED,
    +                                TS_HTTP_STATUS_NOT_EXTENDED,
    +                                TS_HTTP_STATUS_NETWORK_AUTHENTICATION_REQUIRED};
    +
    +static bool should_log(TSHttpTxn txnp);
    +static void log_request_line(TSMBuffer bufp, TSMLoc loc, const char *output_header);
    +static void log_response_status_line(TSMBuffer bufp, TSMLoc loc, const char *output_header);
    +static void log_headers(TSMBuffer bufp, TSMLoc loc, const char *output_header);
    +static void log_full_transaction(TSHttpTxn txnp);
    +static int log_requests_plugin(TSCont contp ATS_UNUSED, TSEvent event, void *edata);
    +
    +static bool
    +should_log(TSHttpTxn txnp)
    +{
    +  TSMBuffer txn_resp_bufp;
    +  TSMLoc txn_resp_loc;
    +  TSHttpStatus resp_status;
    +
    +  if (TSHttpTxnClientRespGet(txnp, &txn_resp_bufp, &txn_resp_loc) != TS_SUCCESS) {
    +    TSError("[log_requests] Couldn't retrieve server response header.");
    +    return false;
    +  }
    +
    +  // if resp_status is blacklisted, don't log
    +  resp_status = TSHttpHdrStatusGet(txn_resp_bufp, txn_resp_loc);
    +  for (int i = 0; i < blacklist_size; ++i) {
    +    if (resp_status == blacklist[i])
    +      return false;
    +  }
    +
    +  // else, if resp_status is in errors, log it
    +  for (int i = 0; i < (int)(sizeof(errors) / sizeof(TSHttpStatus)); ++i) {
    +    if (resp_status == errors[i]) {
    +      return true;
    +    }
    +  }
    +
    +  // fall through
    +  return false;
    +}
    +
    +const char *
    +convert_http_version(const int version)
    +{
    +  char *ret;
    +  if (version == TS_HTTP_VERSION(1, 0))
    +    ret = "HTTP/1.0";
    +  else if (version == TS_HTTP_VERSION(1, 1))
    +    ret = "HTTP/1.1";
    +  else if (version == TS_HTTP_VERSION(1, 2))
    +    ret = "HTTP/1.2";
    +  else if (version == TS_HTTP_VERSION(2, 0))
    +    ret = "HTTP/2.0";
    +  else {
    +    ret = "(Unknown HTTP version)";
    +  }
    +
    +  return ret;
    +}
    +
    +static void
    +log_request_line(TSMBuffer bufp, TSMLoc loc, const char *output_header)
    +{
    +  int method_len;
    +  int url_len;
    +  const char *version;
    +  TSMLoc url_loc;
    +
    +  // parse method
    +  const char *method = TSHttpHdrMethodGet(bufp, loc, &method_len);
    +
    +  // parse version
    +  version = convert_http_version(TSHttpHdrVersionGet(bufp, loc));
    +
    +  // parse request line URL
    +  TSHttpHdrUrlGet(bufp, loc, &url_loc);
    +  const char *url = TSUrlStringGet(bufp, url_loc, &url_len);
    +
    +  // null terminate these strings so we can printf them
    +  char *dup_method   = TSstrndup(method, method_len);
    +  char *dup_url      = TSstrndup(url, url_len);
    +  char *dup_url_orig = dup_url;
    +
    +  // get rid of the preceeding http:// on the request URI
    +  for (int i = 0; i < 7; ++i) {
    +    dup_url++;
    +  }
    +
    +  TSError("[log_requests] %s request line='%s %s %s'", output_header, dup_method, dup_url, version);
    +
    +  TSfree(dup_method);
    +  TSfree(dup_url_orig);
    +}
    +
    +static void
    +log_response_status_line(TSMBuffer bufp, TSMLoc loc, const char *output_header)
    +{
    +  const char *version;
    +  TSHttpStatus status_code;
    +  const char *explanation;
    +  int explanation_len;
    +
    +  // parse version
    +  version = convert_http_version(TSHttpHdrVersionGet(bufp, loc));
    +
    +  // parse status code
    +  status_code = TSHttpHdrStatusGet(bufp, loc);
    +
    +  // get explanation
    +  explanation           = TSHttpHdrReasonGet(bufp, loc, &explanation_len);
    +  char *explanation_dup = TSstrndup(explanation, explanation_len);
    +
    +  TSError("[log_requests] %s response status line='%s %d %s'", output_header, version, status_code, explanation_dup);
    +
    +  TSfree(explanation_dup);
    +}
    +
    +static void
    +log_headers(TSMBuffer bufp, TSMLoc loc, const char *output_header)
    +{
    +  // parse out request headers
    +  TSMLoc field_loc = TSMimeHdrFieldGet(bufp, loc, 0);
    +  while (field_loc) {
    +    TSMLoc next_field_loc;
    +    const char *name;
    +    int name_len;
    +
    +    // grab the header name
    +    name = TSMimeHdrFieldNameGet(bufp, loc, field_loc, &name_len);
    +
    +    if (name) {
    +      char *dup_name = TSstrndup(name, name_len);
    +      TSError("[log_requests] %s Header=%s", output_header, dup_name);
    +      TSfree(dup_name);
    +
    +      // get the header value(s)
    +      int n_values;
    +      n_values = TSMimeHdrFieldValuesCount(bufp, loc, field_loc);
    +      if (n_values && (n_values != TS_ERROR)) {
    +        const char *value = NULL;
    +        int value_len     = 0;
    +
    +        for (int i = 0; i < n_values; ++i) {
    +          value = TSMimeHdrFieldValueStringGet(bufp, loc, field_loc, i, &value_len);
    +          if (value != NULL || value_len) {
    +            char *dup_value = TSstrndup(value, value_len);
    --- End diff --
    
    See above.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] trafficserver pull request #1210: Create log_requests plugin

Posted by SolidWallOfCode <gi...@git.apache.org>.
Github user SolidWallOfCode commented on a diff in the pull request:

    https://github.com/apache/trafficserver/pull/1210#discussion_r89521162
  
    --- Diff: plugins/experimental/log_requests/log_requests.cc ---
    @@ -0,0 +1,352 @@
    +/** @file
    +
    +  Logs full request/response headers on an error response code (4xx/5xx)
    +
    +  @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.
    + */
    +
    +#include <stdio.h>
    +#include <string.h>
    +#include <ctype.h>
    +
    +#include <vector>
    +#include <algorithm>
    +#include <string>
    +
    +#include "ts/ts.h"
    +#include "ts/ink_defs.h"
    +#include "ts/ink_args.h"
    +#include "ts/I_Version.h"
    +
    +#define PLUGIN_NAME "log_requests"
    +#define B_PLUGIN_NAME "[" PLUGIN_NAME "]"
    +
    +static char arg_blacklist[2048]             = "";
    +static bool log_proxy                       = false;
    +ArgumentDescription argument_descriptions[] = {
    +  {"no-log", '-', "Comma-separated list of status codes to blacklist", "S2047", arg_blacklist, nullptr, nullptr},
    +  {"log-proxy", 'p', "Also log proxy request and proxy response transaction", "F", &log_proxy, nullptr, nullptr},
    +};
    +
    +// we log the set of errors in {errors} - {blacklist}
    +static std::vector<TSHttpStatus> blacklist;
    +static std::vector<TSHttpStatus> errors({TS_HTTP_STATUS_BAD_REQUEST,
    +                                         TS_HTTP_STATUS_UNAUTHORIZED,
    +                                         TS_HTTP_STATUS_PAYMENT_REQUIRED,
    +                                         TS_HTTP_STATUS_FORBIDDEN,
    +                                         TS_HTTP_STATUS_NOT_FOUND,
    +                                         TS_HTTP_STATUS_METHOD_NOT_ALLOWED,
    +                                         TS_HTTP_STATUS_NOT_ACCEPTABLE,
    +                                         TS_HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED,
    +                                         TS_HTTP_STATUS_REQUEST_TIMEOUT,
    +                                         TS_HTTP_STATUS_CONFLICT,
    +                                         TS_HTTP_STATUS_GONE,
    +                                         TS_HTTP_STATUS_LENGTH_REQUIRED,
    +                                         TS_HTTP_STATUS_PRECONDITION_FAILED,
    +                                         TS_HTTP_STATUS_REQUEST_ENTITY_TOO_LARGE,
    +                                         TS_HTTP_STATUS_REQUEST_URI_TOO_LONG,
    +                                         TS_HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE,
    +                                         TS_HTTP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE,
    +                                         TS_HTTP_STATUS_EXPECTATION_FAILED,
    +                                         TS_HTTP_STATUS_UNPROCESSABLE_ENTITY,
    +                                         TS_HTTP_STATUS_LOCKED,
    +                                         TS_HTTP_STATUS_FAILED_DEPENDENCY,
    +                                         TS_HTTP_STATUS_UPGRADE_REQUIRED,
    +                                         TS_HTTP_STATUS_PRECONDITION_REQUIRED,
    +                                         TS_HTTP_STATUS_TOO_MANY_REQUESTS,
    +                                         TS_HTTP_STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE,
    +                                         TS_HTTP_STATUS_INTERNAL_SERVER_ERROR,
    +                                         TS_HTTP_STATUS_NOT_IMPLEMENTED,
    +                                         TS_HTTP_STATUS_BAD_GATEWAY,
    +                                         TS_HTTP_STATUS_SERVICE_UNAVAILABLE,
    +                                         TS_HTTP_STATUS_GATEWAY_TIMEOUT,
    +                                         TS_HTTP_STATUS_HTTPVER_NOT_SUPPORTED,
    +                                         TS_HTTP_STATUS_VARIANT_ALSO_NEGOTIATES,
    +                                         TS_HTTP_STATUS_INSUFFICIENT_STORAGE,
    +                                         TS_HTTP_STATUS_LOOP_DETECTED,
    +                                         TS_HTTP_STATUS_NOT_EXTENDED,
    +                                         TS_HTTP_STATUS_NETWORK_AUTHENTICATION_REQUIRED});
    +
    +static bool should_log(TSHttpTxn txnp);
    +static const std::string convert_http_version(const int version);
    +static void log_request_line(TSMBuffer bufp, TSMLoc loc, std::string output_header);
    +static void log_response_status_line(TSMBuffer bufp, TSMLoc loc, std::string output_header);
    +static void log_headers(TSMBuffer bufp, TSMLoc loc, std::string output_header);
    +static void log_full_transaction(TSHttpTxn txnp);
    +static int log_requests_plugin(TSCont contp ATS_UNUSED, TSEvent event, void *edata);
    +static std::vector<std::string> split(const std::string &str, const std::string &delim);
    +
    +static std::vector<std::string>
    +split(const std::string &str, const std::string &delim)
    +{
    +  std::vector<std::string> tokens;
    +  size_t prev = 0, pos = 0;
    +  do {
    +    pos = str.find(delim, prev);
    +    if (pos == std::string::npos)
    +      pos = str.length();
    +
    +    std::string token = str.substr(prev, pos - prev);
    +    if (!token.empty())
    +      tokens.push_back(token);
    +
    +    prev = pos + delim.length();
    +  } while (pos < str.length() && prev < str.length());
    +
    +  return tokens;
    +}
    +
    +static bool
    +should_log(TSHttpTxn txnp)
    +{
    +  TSMBuffer txn_resp_bufp;
    +  TSMLoc txn_resp_loc;
    +  TSHttpStatus resp_status;
    +
    +  if (TSHttpTxnClientRespGet(txnp, &txn_resp_bufp, &txn_resp_loc) != TS_SUCCESS) {
    +    TSError(B_PLUGIN_NAME " Couldn't retrieve server response header.");
    +    return false;
    +  }
    +
    +  // get the transaction response status code
    +  resp_status = TSHttpHdrStatusGet(txn_resp_bufp, txn_resp_loc);
    +
    +  // if resp_status is blacklisted, don't log
    +  if (std::any_of(blacklist.begin(), blacklist.end(), [=](TSHttpStatus code) { return code == resp_status; }))
    +    return false;
    +
    +  // else, if resp_status is in errors, log it
    +  if (std::any_of(errors.begin(), errors.end(), [=](TSHttpStatus error) { return error == resp_status; }))
    +    return true;
    +
    +  // fall through
    +  return false;
    +}
    +
    +static const std::string
    +convert_http_version(const int version)
    +{
    +  if (version == TS_HTTP_VERSION(1, 0))
    +    return "HTTP/1.0";
    +  else if (version == TS_HTTP_VERSION(1, 1))
    +    return "HTTP/1.1";
    +  else if (version == TS_HTTP_VERSION(1, 2))
    +    return "HTTP/1.2";
    +  else if (version == TS_HTTP_VERSION(2, 0))
    +    return "HTTP/2.0";
    +  else {
    +    return "(Unknown HTTP version)";
    +  }
    +}
    +
    +static void
    +log_request_line(TSMBuffer bufp, TSMLoc loc, std::string output_header)
    +{
    +  int method_len;
    +  int url_len;
    +  const char *method;
    +  const char *url;
    +  TSMLoc url_loc;
    +
    +  // parse method
    +  method = TSHttpHdrMethodGet(bufp, loc, &method_len);
    +
    +  // parse version
    +  const std::string version = convert_http_version(TSHttpHdrVersionGet(bufp, loc));
    +
    +  // parse request line URL
    +  TSHttpHdrUrlGet(bufp, loc, &url_loc);
    +  url = TSUrlStringGet(bufp, url_loc, &url_len);
    +
    +  // get rid of the preceeding http:// on the request URI
    +  for (int i = 0; i < 7; ++i)
    +    url++;
    +  url_len -= 7;
    +
    +  TSError(B_PLUGIN_NAME " [%s] request line is:\n%.*s %.*s %s\n", output_header.c_str(), method_len, method, url_len, url,
    +          version.c_str());
    +}
    +
    +static void
    +log_response_status_line(TSMBuffer bufp, TSMLoc loc, std::string output_header)
    +{
    +  TSHttpStatus status_code;
    +  const char *explanation;
    +  int explanation_len;
    +
    +  // parse version
    +  const std::string version = convert_http_version(TSHttpHdrVersionGet(bufp, loc));
    +
    +  // parse status code
    +  status_code = TSHttpHdrStatusGet(bufp, loc);
    +
    +  // get explanation
    +  explanation = TSHttpHdrReasonGet(bufp, loc, &explanation_len);
    +
    +  TSError(B_PLUGIN_NAME " [%s] response status line is:\n%s %d %.*s\n", output_header.c_str(), version.c_str(), status_code,
    +          explanation_len, explanation);
    +}
    +
    +static void
    +log_headers(TSMBuffer bufp, TSMLoc loc, std::string output_header)
    +{
    +  TSIOBuffer output_buffer;
    +  TSIOBufferReader reader;
    +  TSIOBufferBlock block;
    +  const char *block_start;
    +  int64_t block_avail;
    +
    +  output_buffer = TSIOBufferCreate();
    +  reader        = TSIOBufferReaderAlloc(output_buffer);
    +
    +  // This will print just MIMEFields and not the http request line
    +  TSMimeHdrPrint(bufp, loc, output_buffer);
    +
    +  // We need to loop over all the buffer blocks, there can be more than 1
    +  block = TSIOBufferReaderStart(reader);
    +  do {
    --- End diff --
    
    I think this got obsoleted by the IOBUffer related changes.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] trafficserver pull request #1210: Create log_requests plugin

Posted by SolidWallOfCode <gi...@git.apache.org>.
Github user SolidWallOfCode commented on a diff in the pull request:

    https://github.com/apache/trafficserver/pull/1210#discussion_r87405728
  
    --- Diff: plugins/experimental/log_requests/log_requests.cc ---
    @@ -0,0 +1,352 @@
    +/** @file
    +
    +  Logs full request/response headers on an error response code (4xx/5xx)
    +
    +  @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.
    + */
    +
    +#include <stdio.h>
    +#include <string.h>
    +#include <ctype.h>
    +
    +#include <vector>
    +#include <algorithm>
    +#include <string>
    +
    +#include "ts/ts.h"
    +#include "ts/ink_defs.h"
    +#include "ts/ink_args.h"
    +#include "ts/I_Version.h"
    +
    +#define PLUGIN_NAME "log_requests"
    +#define B_PLUGIN_NAME "[" PLUGIN_NAME "]"
    +
    +static char arg_blacklist[2048]             = "";
    +static bool log_proxy                       = false;
    +ArgumentDescription argument_descriptions[] = {
    +  {"no-log", '-', "Comma-separated list of status codes to blacklist", "S2047", arg_blacklist, nullptr, nullptr},
    +  {"log-proxy", 'p', "Also log proxy request and proxy response transaction", "F", &log_proxy, nullptr, nullptr},
    +};
    +
    +// we log the set of errors in {errors} - {blacklist}
    +static std::vector<TSHttpStatus> blacklist;
    +static std::vector<TSHttpStatus> errors({TS_HTTP_STATUS_BAD_REQUEST,
    +                                         TS_HTTP_STATUS_UNAUTHORIZED,
    +                                         TS_HTTP_STATUS_PAYMENT_REQUIRED,
    +                                         TS_HTTP_STATUS_FORBIDDEN,
    +                                         TS_HTTP_STATUS_NOT_FOUND,
    +                                         TS_HTTP_STATUS_METHOD_NOT_ALLOWED,
    +                                         TS_HTTP_STATUS_NOT_ACCEPTABLE,
    +                                         TS_HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED,
    +                                         TS_HTTP_STATUS_REQUEST_TIMEOUT,
    +                                         TS_HTTP_STATUS_CONFLICT,
    +                                         TS_HTTP_STATUS_GONE,
    +                                         TS_HTTP_STATUS_LENGTH_REQUIRED,
    +                                         TS_HTTP_STATUS_PRECONDITION_FAILED,
    +                                         TS_HTTP_STATUS_REQUEST_ENTITY_TOO_LARGE,
    +                                         TS_HTTP_STATUS_REQUEST_URI_TOO_LONG,
    +                                         TS_HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE,
    +                                         TS_HTTP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE,
    +                                         TS_HTTP_STATUS_EXPECTATION_FAILED,
    +                                         TS_HTTP_STATUS_UNPROCESSABLE_ENTITY,
    +                                         TS_HTTP_STATUS_LOCKED,
    +                                         TS_HTTP_STATUS_FAILED_DEPENDENCY,
    +                                         TS_HTTP_STATUS_UPGRADE_REQUIRED,
    +                                         TS_HTTP_STATUS_PRECONDITION_REQUIRED,
    +                                         TS_HTTP_STATUS_TOO_MANY_REQUESTS,
    +                                         TS_HTTP_STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE,
    +                                         TS_HTTP_STATUS_INTERNAL_SERVER_ERROR,
    +                                         TS_HTTP_STATUS_NOT_IMPLEMENTED,
    +                                         TS_HTTP_STATUS_BAD_GATEWAY,
    +                                         TS_HTTP_STATUS_SERVICE_UNAVAILABLE,
    +                                         TS_HTTP_STATUS_GATEWAY_TIMEOUT,
    +                                         TS_HTTP_STATUS_HTTPVER_NOT_SUPPORTED,
    +                                         TS_HTTP_STATUS_VARIANT_ALSO_NEGOTIATES,
    +                                         TS_HTTP_STATUS_INSUFFICIENT_STORAGE,
    +                                         TS_HTTP_STATUS_LOOP_DETECTED,
    +                                         TS_HTTP_STATUS_NOT_EXTENDED,
    +                                         TS_HTTP_STATUS_NETWORK_AUTHENTICATION_REQUIRED});
    +
    +static bool should_log(TSHttpTxn txnp);
    +static const std::string convert_http_version(const int version);
    +static void log_request_line(TSMBuffer bufp, TSMLoc loc, std::string output_header);
    +static void log_response_status_line(TSMBuffer bufp, TSMLoc loc, std::string output_header);
    +static void log_headers(TSMBuffer bufp, TSMLoc loc, std::string output_header);
    +static void log_full_transaction(TSHttpTxn txnp);
    +static int log_requests_plugin(TSCont contp ATS_UNUSED, TSEvent event, void *edata);
    +static std::vector<std::string> split(const std::string &str, const std::string &delim);
    +
    +static std::vector<std::string>
    +split(const std::string &str, const std::string &delim)
    +{
    +  std::vector<std::string> tokens;
    +  size_t prev = 0, pos = 0;
    +  do {
    +    pos = str.find(delim, prev);
    +    if (pos == std::string::npos)
    +      pos = str.length();
    +
    +    std::string token = str.substr(prev, pos - prev);
    +    if (!token.empty())
    +      tokens.push_back(token);
    +
    +    prev = pos + delim.length();
    +  } while (pos < str.length() && prev < str.length());
    +
    +  return tokens;
    +}
    +
    +static bool
    +should_log(TSHttpTxn txnp)
    +{
    +  TSMBuffer txn_resp_bufp;
    +  TSMLoc txn_resp_loc;
    +  TSHttpStatus resp_status;
    +
    +  if (TSHttpTxnClientRespGet(txnp, &txn_resp_bufp, &txn_resp_loc) != TS_SUCCESS) {
    +    TSError(B_PLUGIN_NAME " Couldn't retrieve server response header.");
    +    return false;
    +  }
    +
    +  // get the transaction response status code
    +  resp_status = TSHttpHdrStatusGet(txn_resp_bufp, txn_resp_loc);
    +
    +  // if resp_status is blacklisted, don't log
    +  if (std::any_of(blacklist.begin(), blacklist.end(), [=](TSHttpStatus code) { return code == resp_status; }))
    +    return false;
    +
    +  // else, if resp_status is in errors, log it
    +  if (std::any_of(errors.begin(), errors.end(), [=](TSHttpStatus error) { return error == resp_status; }))
    +    return true;
    +
    +  // fall through
    +  return false;
    +}
    +
    +static const std::string
    +convert_http_version(const int version)
    +{
    +  if (version == TS_HTTP_VERSION(1, 0))
    +    return "HTTP/1.0";
    +  else if (version == TS_HTTP_VERSION(1, 1))
    +    return "HTTP/1.1";
    +  else if (version == TS_HTTP_VERSION(1, 2))
    +    return "HTTP/1.2";
    +  else if (version == TS_HTTP_VERSION(2, 0))
    +    return "HTTP/2.0";
    +  else {
    +    return "(Unknown HTTP version)";
    +  }
    +}
    +
    +static void
    +log_request_line(TSMBuffer bufp, TSMLoc loc, std::string output_header)
    +{
    +  int method_len;
    +  int url_len;
    +  const char *method;
    +  const char *url;
    +  TSMLoc url_loc;
    +
    +  // parse method
    +  method = TSHttpHdrMethodGet(bufp, loc, &method_len);
    +
    +  // parse version
    +  const std::string version = convert_http_version(TSHttpHdrVersionGet(bufp, loc));
    +
    +  // parse request line URL
    +  TSHttpHdrUrlGet(bufp, loc, &url_loc);
    +  url = TSUrlStringGet(bufp, url_loc, &url_len);
    +
    +  // get rid of the preceeding http:// on the request URI
    --- End diff --
    
    How do you know it's `http://` and not say `https://`? I would recommend using the URL component API instead, e.g. `TSUrlPathGet`.



---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] trafficserver pull request #1210: Create log_requests plugin

Posted by SolidWallOfCode <gi...@git.apache.org>.
Github user SolidWallOfCode commented on a diff in the pull request:

    https://github.com/apache/trafficserver/pull/1210#discussion_r87406306
  
    --- Diff: plugins/experimental/log_requests/log_requests.cc ---
    @@ -0,0 +1,352 @@
    +/** @file
    +
    +  Logs full request/response headers on an error response code (4xx/5xx)
    +
    +  @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.
    + */
    +
    +#include <stdio.h>
    +#include <string.h>
    +#include <ctype.h>
    +
    +#include <vector>
    +#include <algorithm>
    +#include <string>
    +
    +#include "ts/ts.h"
    +#include "ts/ink_defs.h"
    +#include "ts/ink_args.h"
    +#include "ts/I_Version.h"
    +
    +#define PLUGIN_NAME "log_requests"
    +#define B_PLUGIN_NAME "[" PLUGIN_NAME "]"
    +
    +static char arg_blacklist[2048]             = "";
    +static bool log_proxy                       = false;
    +ArgumentDescription argument_descriptions[] = {
    +  {"no-log", '-', "Comma-separated list of status codes to blacklist", "S2047", arg_blacklist, nullptr, nullptr},
    +  {"log-proxy", 'p', "Also log proxy request and proxy response transaction", "F", &log_proxy, nullptr, nullptr},
    +};
    +
    +// we log the set of errors in {errors} - {blacklist}
    +static std::vector<TSHttpStatus> blacklist;
    +static std::vector<TSHttpStatus> errors({TS_HTTP_STATUS_BAD_REQUEST,
    +                                         TS_HTTP_STATUS_UNAUTHORIZED,
    +                                         TS_HTTP_STATUS_PAYMENT_REQUIRED,
    +                                         TS_HTTP_STATUS_FORBIDDEN,
    +                                         TS_HTTP_STATUS_NOT_FOUND,
    +                                         TS_HTTP_STATUS_METHOD_NOT_ALLOWED,
    +                                         TS_HTTP_STATUS_NOT_ACCEPTABLE,
    +                                         TS_HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED,
    +                                         TS_HTTP_STATUS_REQUEST_TIMEOUT,
    +                                         TS_HTTP_STATUS_CONFLICT,
    +                                         TS_HTTP_STATUS_GONE,
    +                                         TS_HTTP_STATUS_LENGTH_REQUIRED,
    +                                         TS_HTTP_STATUS_PRECONDITION_FAILED,
    +                                         TS_HTTP_STATUS_REQUEST_ENTITY_TOO_LARGE,
    +                                         TS_HTTP_STATUS_REQUEST_URI_TOO_LONG,
    +                                         TS_HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE,
    +                                         TS_HTTP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE,
    +                                         TS_HTTP_STATUS_EXPECTATION_FAILED,
    +                                         TS_HTTP_STATUS_UNPROCESSABLE_ENTITY,
    +                                         TS_HTTP_STATUS_LOCKED,
    +                                         TS_HTTP_STATUS_FAILED_DEPENDENCY,
    +                                         TS_HTTP_STATUS_UPGRADE_REQUIRED,
    +                                         TS_HTTP_STATUS_PRECONDITION_REQUIRED,
    +                                         TS_HTTP_STATUS_TOO_MANY_REQUESTS,
    +                                         TS_HTTP_STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE,
    +                                         TS_HTTP_STATUS_INTERNAL_SERVER_ERROR,
    +                                         TS_HTTP_STATUS_NOT_IMPLEMENTED,
    +                                         TS_HTTP_STATUS_BAD_GATEWAY,
    +                                         TS_HTTP_STATUS_SERVICE_UNAVAILABLE,
    +                                         TS_HTTP_STATUS_GATEWAY_TIMEOUT,
    +                                         TS_HTTP_STATUS_HTTPVER_NOT_SUPPORTED,
    +                                         TS_HTTP_STATUS_VARIANT_ALSO_NEGOTIATES,
    +                                         TS_HTTP_STATUS_INSUFFICIENT_STORAGE,
    +                                         TS_HTTP_STATUS_LOOP_DETECTED,
    +                                         TS_HTTP_STATUS_NOT_EXTENDED,
    +                                         TS_HTTP_STATUS_NETWORK_AUTHENTICATION_REQUIRED});
    +
    +static bool should_log(TSHttpTxn txnp);
    +static const std::string convert_http_version(const int version);
    +static void log_request_line(TSMBuffer bufp, TSMLoc loc, std::string output_header);
    +static void log_response_status_line(TSMBuffer bufp, TSMLoc loc, std::string output_header);
    +static void log_headers(TSMBuffer bufp, TSMLoc loc, std::string output_header);
    +static void log_full_transaction(TSHttpTxn txnp);
    +static int log_requests_plugin(TSCont contp ATS_UNUSED, TSEvent event, void *edata);
    +static std::vector<std::string> split(const std::string &str, const std::string &delim);
    +
    +static std::vector<std::string>
    +split(const std::string &str, const std::string &delim)
    +{
    +  std::vector<std::string> tokens;
    +  size_t prev = 0, pos = 0;
    +  do {
    +    pos = str.find(delim, prev);
    +    if (pos == std::string::npos)
    +      pos = str.length();
    +
    +    std::string token = str.substr(prev, pos - prev);
    +    if (!token.empty())
    +      tokens.push_back(token);
    +
    +    prev = pos + delim.length();
    +  } while (pos < str.length() && prev < str.length());
    +
    +  return tokens;
    +}
    +
    +static bool
    +should_log(TSHttpTxn txnp)
    +{
    +  TSMBuffer txn_resp_bufp;
    +  TSMLoc txn_resp_loc;
    +  TSHttpStatus resp_status;
    +
    +  if (TSHttpTxnClientRespGet(txnp, &txn_resp_bufp, &txn_resp_loc) != TS_SUCCESS) {
    +    TSError(B_PLUGIN_NAME " Couldn't retrieve server response header.");
    +    return false;
    +  }
    +
    +  // get the transaction response status code
    +  resp_status = TSHttpHdrStatusGet(txn_resp_bufp, txn_resp_loc);
    +
    +  // if resp_status is blacklisted, don't log
    +  if (std::any_of(blacklist.begin(), blacklist.end(), [=](TSHttpStatus code) { return code == resp_status; }))
    +    return false;
    +
    +  // else, if resp_status is in errors, log it
    +  if (std::any_of(errors.begin(), errors.end(), [=](TSHttpStatus error) { return error == resp_status; }))
    +    return true;
    +
    +  // fall through
    +  return false;
    +}
    +
    +static const std::string
    +convert_http_version(const int version)
    +{
    +  if (version == TS_HTTP_VERSION(1, 0))
    +    return "HTTP/1.0";
    +  else if (version == TS_HTTP_VERSION(1, 1))
    +    return "HTTP/1.1";
    +  else if (version == TS_HTTP_VERSION(1, 2))
    +    return "HTTP/1.2";
    +  else if (version == TS_HTTP_VERSION(2, 0))
    +    return "HTTP/2.0";
    +  else {
    +    return "(Unknown HTTP version)";
    +  }
    +}
    +
    +static void
    +log_request_line(TSMBuffer bufp, TSMLoc loc, std::string output_header)
    +{
    +  int method_len;
    +  int url_len;
    +  const char *method;
    +  const char *url;
    +  TSMLoc url_loc;
    +
    +  // parse method
    +  method = TSHttpHdrMethodGet(bufp, loc, &method_len);
    +
    +  // parse version
    +  const std::string version = convert_http_version(TSHttpHdrVersionGet(bufp, loc));
    +
    +  // parse request line URL
    +  TSHttpHdrUrlGet(bufp, loc, &url_loc);
    +  url = TSUrlStringGet(bufp, url_loc, &url_len);
    +
    +  // get rid of the preceeding http:// on the request URI
    +  for (int i = 0; i < 7; ++i)
    +    url++;
    +  url_len -= 7;
    +
    +  TSError(B_PLUGIN_NAME " [%s] request line is:\n%.*s %.*s %s\n", output_header.c_str(), method_len, method, url_len, url,
    +          version.c_str());
    +}
    +
    +static void
    +log_response_status_line(TSMBuffer bufp, TSMLoc loc, std::string output_header)
    +{
    +  TSHttpStatus status_code;
    +  const char *explanation;
    +  int explanation_len;
    +
    +  // parse version
    +  const std::string version = convert_http_version(TSHttpHdrVersionGet(bufp, loc));
    +
    +  // parse status code
    +  status_code = TSHttpHdrStatusGet(bufp, loc);
    +
    +  // get explanation
    +  explanation = TSHttpHdrReasonGet(bufp, loc, &explanation_len);
    +
    +  TSError(B_PLUGIN_NAME " [%s] response status line is:\n%s %d %.*s\n", output_header.c_str(), version.c_str(), status_code,
    +          explanation_len, explanation);
    +}
    +
    +static void
    +log_headers(TSMBuffer bufp, TSMLoc loc, std::string output_header)
    +{
    +  TSIOBuffer output_buffer;
    +  TSIOBufferReader reader;
    +  TSIOBufferBlock block;
    +  const char *block_start;
    +  int64_t block_avail;
    +
    +  output_buffer = TSIOBufferCreate();
    +  reader        = TSIOBufferReaderAlloc(output_buffer);
    +
    +  // This will print just MIMEFields and not the http request line
    +  TSMimeHdrPrint(bufp, loc, output_buffer);
    +
    +  // We need to loop over all the buffer blocks, there can be more than 1
    +  block = TSIOBufferReaderStart(reader);
    +  do {
    --- End diff --
    
    Could we do better by checking read avail and then `_alloca` a single buffer to print?



---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] trafficserver pull request #1210: Create log_requests plugin

Posted by danobi <gi...@git.apache.org>.
Github user danobi commented on a diff in the pull request:

    https://github.com/apache/trafficserver/pull/1210#discussion_r89883222
  
    --- Diff: plugins/experimental/log_requests/log_requests.cc ---
    @@ -0,0 +1,352 @@
    +/** @file
    +
    +  Logs full request/response headers on an error response code (4xx/5xx)
    +
    +  @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.
    + */
    +
    +#include <stdio.h>
    +#include <string.h>
    +#include <ctype.h>
    +
    +#include <vector>
    +#include <algorithm>
    +#include <string>
    +
    +#include "ts/ts.h"
    +#include "ts/ink_defs.h"
    +#include "ts/ink_args.h"
    +#include "ts/I_Version.h"
    +
    +#define PLUGIN_NAME "log_requests"
    +#define B_PLUGIN_NAME "[" PLUGIN_NAME "]"
    +
    +static char arg_blacklist[2048]             = "";
    +static bool log_proxy                       = false;
    +ArgumentDescription argument_descriptions[] = {
    +  {"no-log", '-', "Comma-separated list of status codes to blacklist", "S2047", arg_blacklist, nullptr, nullptr},
    +  {"log-proxy", 'p', "Also log proxy request and proxy response transaction", "F", &log_proxy, nullptr, nullptr},
    +};
    +
    +// we log the set of errors in {errors} - {blacklist}
    +static std::vector<TSHttpStatus> blacklist;
    +static std::vector<TSHttpStatus> errors({TS_HTTP_STATUS_BAD_REQUEST,
    +                                         TS_HTTP_STATUS_UNAUTHORIZED,
    +                                         TS_HTTP_STATUS_PAYMENT_REQUIRED,
    +                                         TS_HTTP_STATUS_FORBIDDEN,
    +                                         TS_HTTP_STATUS_NOT_FOUND,
    +                                         TS_HTTP_STATUS_METHOD_NOT_ALLOWED,
    +                                         TS_HTTP_STATUS_NOT_ACCEPTABLE,
    +                                         TS_HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED,
    +                                         TS_HTTP_STATUS_REQUEST_TIMEOUT,
    +                                         TS_HTTP_STATUS_CONFLICT,
    +                                         TS_HTTP_STATUS_GONE,
    +                                         TS_HTTP_STATUS_LENGTH_REQUIRED,
    +                                         TS_HTTP_STATUS_PRECONDITION_FAILED,
    +                                         TS_HTTP_STATUS_REQUEST_ENTITY_TOO_LARGE,
    +                                         TS_HTTP_STATUS_REQUEST_URI_TOO_LONG,
    +                                         TS_HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE,
    +                                         TS_HTTP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE,
    +                                         TS_HTTP_STATUS_EXPECTATION_FAILED,
    +                                         TS_HTTP_STATUS_UNPROCESSABLE_ENTITY,
    +                                         TS_HTTP_STATUS_LOCKED,
    +                                         TS_HTTP_STATUS_FAILED_DEPENDENCY,
    +                                         TS_HTTP_STATUS_UPGRADE_REQUIRED,
    +                                         TS_HTTP_STATUS_PRECONDITION_REQUIRED,
    +                                         TS_HTTP_STATUS_TOO_MANY_REQUESTS,
    +                                         TS_HTTP_STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE,
    +                                         TS_HTTP_STATUS_INTERNAL_SERVER_ERROR,
    +                                         TS_HTTP_STATUS_NOT_IMPLEMENTED,
    +                                         TS_HTTP_STATUS_BAD_GATEWAY,
    +                                         TS_HTTP_STATUS_SERVICE_UNAVAILABLE,
    +                                         TS_HTTP_STATUS_GATEWAY_TIMEOUT,
    +                                         TS_HTTP_STATUS_HTTPVER_NOT_SUPPORTED,
    +                                         TS_HTTP_STATUS_VARIANT_ALSO_NEGOTIATES,
    +                                         TS_HTTP_STATUS_INSUFFICIENT_STORAGE,
    +                                         TS_HTTP_STATUS_LOOP_DETECTED,
    +                                         TS_HTTP_STATUS_NOT_EXTENDED,
    +                                         TS_HTTP_STATUS_NETWORK_AUTHENTICATION_REQUIRED});
    +
    +static bool should_log(TSHttpTxn txnp);
    +static const std::string convert_http_version(const int version);
    +static void log_request_line(TSMBuffer bufp, TSMLoc loc, std::string output_header);
    +static void log_response_status_line(TSMBuffer bufp, TSMLoc loc, std::string output_header);
    +static void log_headers(TSMBuffer bufp, TSMLoc loc, std::string output_header);
    +static void log_full_transaction(TSHttpTxn txnp);
    +static int log_requests_plugin(TSCont contp ATS_UNUSED, TSEvent event, void *edata);
    +static std::vector<std::string> split(const std::string &str, const std::string &delim);
    +
    +static std::vector<std::string>
    +split(const std::string &str, const std::string &delim)
    +{
    +  std::vector<std::string> tokens;
    +  size_t prev = 0, pos = 0;
    +  do {
    +    pos = str.find(delim, prev);
    +    if (pos == std::string::npos)
    +      pos = str.length();
    +
    +    std::string token = str.substr(prev, pos - prev);
    +    if (!token.empty())
    +      tokens.push_back(token);
    +
    +    prev = pos + delim.length();
    +  } while (pos < str.length() && prev < str.length());
    +
    +  return tokens;
    +}
    +
    +static bool
    +should_log(TSHttpTxn txnp)
    +{
    +  TSMBuffer txn_resp_bufp;
    +  TSMLoc txn_resp_loc;
    +  TSHttpStatus resp_status;
    +
    +  if (TSHttpTxnClientRespGet(txnp, &txn_resp_bufp, &txn_resp_loc) != TS_SUCCESS) {
    +    TSError(B_PLUGIN_NAME " Couldn't retrieve server response header.");
    +    return false;
    +  }
    +
    +  // get the transaction response status code
    +  resp_status = TSHttpHdrStatusGet(txn_resp_bufp, txn_resp_loc);
    +
    +  // if resp_status is blacklisted, don't log
    +  if (std::any_of(blacklist.begin(), blacklist.end(), [=](TSHttpStatus code) { return code == resp_status; }))
    +    return false;
    +
    +  // else, if resp_status is in errors, log it
    +  if (std::any_of(errors.begin(), errors.end(), [=](TSHttpStatus error) { return error == resp_status; }))
    +    return true;
    +
    +  // fall through
    +  return false;
    +}
    +
    +static const std::string
    +convert_http_version(const int version)
    +{
    +  if (version == TS_HTTP_VERSION(1, 0))
    +    return "HTTP/1.0";
    +  else if (version == TS_HTTP_VERSION(1, 1))
    +    return "HTTP/1.1";
    +  else if (version == TS_HTTP_VERSION(1, 2))
    +    return "HTTP/1.2";
    +  else if (version == TS_HTTP_VERSION(2, 0))
    +    return "HTTP/2.0";
    +  else {
    +    return "(Unknown HTTP version)";
    +  }
    +}
    +
    +static void
    +log_request_line(TSMBuffer bufp, TSMLoc loc, std::string output_header)
    +{
    +  int method_len;
    +  int url_len;
    +  const char *method;
    +  const char *url;
    +  TSMLoc url_loc;
    +
    +  // parse method
    +  method = TSHttpHdrMethodGet(bufp, loc, &method_len);
    +
    +  // parse version
    +  const std::string version = convert_http_version(TSHttpHdrVersionGet(bufp, loc));
    +
    +  // parse request line URL
    +  TSHttpHdrUrlGet(bufp, loc, &url_loc);
    +  url = TSUrlStringGet(bufp, url_loc, &url_len);
    +
    +  // get rid of the preceeding http:// on the request URI
    +  for (int i = 0; i < 7; ++i)
    +    url++;
    +  url_len -= 7;
    +
    +  TSError(B_PLUGIN_NAME " [%s] request line is:\n%.*s %.*s %s\n", output_header.c_str(), method_len, method, url_len, url,
    +          version.c_str());
    +}
    +
    +static void
    +log_response_status_line(TSMBuffer bufp, TSMLoc loc, std::string output_header)
    +{
    +  TSHttpStatus status_code;
    +  const char *explanation;
    +  int explanation_len;
    +
    +  // parse version
    +  const std::string version = convert_http_version(TSHttpHdrVersionGet(bufp, loc));
    +
    +  // parse status code
    +  status_code = TSHttpHdrStatusGet(bufp, loc);
    +
    +  // get explanation
    +  explanation = TSHttpHdrReasonGet(bufp, loc, &explanation_len);
    +
    +  TSError(B_PLUGIN_NAME " [%s] response status line is:\n%s %d %.*s\n", output_header.c_str(), version.c_str(), status_code,
    +          explanation_len, explanation);
    +}
    +
    +static void
    +log_headers(TSMBuffer bufp, TSMLoc loc, std::string output_header)
    +{
    +  TSIOBuffer output_buffer;
    +  TSIOBufferReader reader;
    +  TSIOBufferBlock block;
    +  const char *block_start;
    +  int64_t block_avail;
    +
    +  output_buffer = TSIOBufferCreate();
    +  reader        = TSIOBufferReaderAlloc(output_buffer);
    +
    +  // This will print just MIMEFields and not the http request line
    +  TSMimeHdrPrint(bufp, loc, output_buffer);
    +
    +  // We need to loop over all the buffer blocks, there can be more than 1
    +  block = TSIOBufferReaderStart(reader);
    +  do {
    +    block_start = TSIOBufferBlockReadStart(block, reader, &block_avail);
    +    if (block_avail > 0) {
    +      TSError(B_PLUGIN_NAME " Headers are:\n%.*s", static_cast<int>(block_avail), block_start);
    +    }
    +    TSIOBufferReaderConsume(reader, block_avail);
    +    block = TSIOBufferReaderStart(reader);
    +  } while (block && block_avail != 0);
    +
    +  // Free up the TSIOBuffer that we used to print out the header
    +  TSIOBufferReaderFree(reader);
    +  TSIOBufferDestroy(output_buffer);
    +}
    +
    +/*
    + * TODO: There are resource leaks if calls to TSHttpTxnClientReqGet() & TSHttpTxnClientRespGet()
    + * fail. Likewise for the ...ServerReqGet() & ...ServerRespGet() calls. Need to do work with
    + * some goto's to fix.
    --- End diff --
    
    I'm unsure how to use a smart pointer w/ a stack allocated pointer like `TSMBuffer`. I think I found another workaround anyways.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] trafficserver pull request #1210: Create log_requests plugin

Posted by SolidWallOfCode <gi...@git.apache.org>.
Github user SolidWallOfCode commented on a diff in the pull request:

    https://github.com/apache/trafficserver/pull/1210#discussion_r87406006
  
    --- Diff: plugins/experimental/log_requests/log_requests.cc ---
    @@ -0,0 +1,352 @@
    +/** @file
    +
    +  Logs full request/response headers on an error response code (4xx/5xx)
    +
    +  @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.
    + */
    +
    +#include <stdio.h>
    +#include <string.h>
    +#include <ctype.h>
    +
    +#include <vector>
    +#include <algorithm>
    +#include <string>
    +
    +#include "ts/ts.h"
    +#include "ts/ink_defs.h"
    +#include "ts/ink_args.h"
    +#include "ts/I_Version.h"
    +
    +#define PLUGIN_NAME "log_requests"
    +#define B_PLUGIN_NAME "[" PLUGIN_NAME "]"
    +
    +static char arg_blacklist[2048]             = "";
    +static bool log_proxy                       = false;
    +ArgumentDescription argument_descriptions[] = {
    +  {"no-log", '-', "Comma-separated list of status codes to blacklist", "S2047", arg_blacklist, nullptr, nullptr},
    +  {"log-proxy", 'p', "Also log proxy request and proxy response transaction", "F", &log_proxy, nullptr, nullptr},
    +};
    +
    +// we log the set of errors in {errors} - {blacklist}
    +static std::vector<TSHttpStatus> blacklist;
    +static std::vector<TSHttpStatus> errors({TS_HTTP_STATUS_BAD_REQUEST,
    +                                         TS_HTTP_STATUS_UNAUTHORIZED,
    +                                         TS_HTTP_STATUS_PAYMENT_REQUIRED,
    +                                         TS_HTTP_STATUS_FORBIDDEN,
    +                                         TS_HTTP_STATUS_NOT_FOUND,
    +                                         TS_HTTP_STATUS_METHOD_NOT_ALLOWED,
    +                                         TS_HTTP_STATUS_NOT_ACCEPTABLE,
    +                                         TS_HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED,
    +                                         TS_HTTP_STATUS_REQUEST_TIMEOUT,
    +                                         TS_HTTP_STATUS_CONFLICT,
    +                                         TS_HTTP_STATUS_GONE,
    +                                         TS_HTTP_STATUS_LENGTH_REQUIRED,
    +                                         TS_HTTP_STATUS_PRECONDITION_FAILED,
    +                                         TS_HTTP_STATUS_REQUEST_ENTITY_TOO_LARGE,
    +                                         TS_HTTP_STATUS_REQUEST_URI_TOO_LONG,
    +                                         TS_HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE,
    +                                         TS_HTTP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE,
    +                                         TS_HTTP_STATUS_EXPECTATION_FAILED,
    +                                         TS_HTTP_STATUS_UNPROCESSABLE_ENTITY,
    +                                         TS_HTTP_STATUS_LOCKED,
    +                                         TS_HTTP_STATUS_FAILED_DEPENDENCY,
    +                                         TS_HTTP_STATUS_UPGRADE_REQUIRED,
    +                                         TS_HTTP_STATUS_PRECONDITION_REQUIRED,
    +                                         TS_HTTP_STATUS_TOO_MANY_REQUESTS,
    +                                         TS_HTTP_STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE,
    +                                         TS_HTTP_STATUS_INTERNAL_SERVER_ERROR,
    +                                         TS_HTTP_STATUS_NOT_IMPLEMENTED,
    +                                         TS_HTTP_STATUS_BAD_GATEWAY,
    +                                         TS_HTTP_STATUS_SERVICE_UNAVAILABLE,
    +                                         TS_HTTP_STATUS_GATEWAY_TIMEOUT,
    +                                         TS_HTTP_STATUS_HTTPVER_NOT_SUPPORTED,
    +                                         TS_HTTP_STATUS_VARIANT_ALSO_NEGOTIATES,
    +                                         TS_HTTP_STATUS_INSUFFICIENT_STORAGE,
    +                                         TS_HTTP_STATUS_LOOP_DETECTED,
    +                                         TS_HTTP_STATUS_NOT_EXTENDED,
    +                                         TS_HTTP_STATUS_NETWORK_AUTHENTICATION_REQUIRED});
    +
    +static bool should_log(TSHttpTxn txnp);
    +static const std::string convert_http_version(const int version);
    +static void log_request_line(TSMBuffer bufp, TSMLoc loc, std::string output_header);
    +static void log_response_status_line(TSMBuffer bufp, TSMLoc loc, std::string output_header);
    +static void log_headers(TSMBuffer bufp, TSMLoc loc, std::string output_header);
    +static void log_full_transaction(TSHttpTxn txnp);
    +static int log_requests_plugin(TSCont contp ATS_UNUSED, TSEvent event, void *edata);
    +static std::vector<std::string> split(const std::string &str, const std::string &delim);
    +
    +static std::vector<std::string>
    +split(const std::string &str, const std::string &delim)
    +{
    +  std::vector<std::string> tokens;
    +  size_t prev = 0, pos = 0;
    +  do {
    +    pos = str.find(delim, prev);
    +    if (pos == std::string::npos)
    +      pos = str.length();
    +
    +    std::string token = str.substr(prev, pos - prev);
    +    if (!token.empty())
    +      tokens.push_back(token);
    +
    +    prev = pos + delim.length();
    +  } while (pos < str.length() && prev < str.length());
    +
    +  return tokens;
    +}
    +
    +static bool
    +should_log(TSHttpTxn txnp)
    +{
    +  TSMBuffer txn_resp_bufp;
    +  TSMLoc txn_resp_loc;
    +  TSHttpStatus resp_status;
    +
    +  if (TSHttpTxnClientRespGet(txnp, &txn_resp_bufp, &txn_resp_loc) != TS_SUCCESS) {
    +    TSError(B_PLUGIN_NAME " Couldn't retrieve server response header.");
    +    return false;
    +  }
    +
    +  // get the transaction response status code
    +  resp_status = TSHttpHdrStatusGet(txn_resp_bufp, txn_resp_loc);
    +
    +  // if resp_status is blacklisted, don't log
    +  if (std::any_of(blacklist.begin(), blacklist.end(), [=](TSHttpStatus code) { return code == resp_status; }))
    +    return false;
    +
    +  // else, if resp_status is in errors, log it
    +  if (std::any_of(errors.begin(), errors.end(), [=](TSHttpStatus error) { return error == resp_status; }))
    +    return true;
    +
    +  // fall through
    +  return false;
    +}
    +
    +static const std::string
    +convert_http_version(const int version)
    +{
    +  if (version == TS_HTTP_VERSION(1, 0))
    +    return "HTTP/1.0";
    +  else if (version == TS_HTTP_VERSION(1, 1))
    +    return "HTTP/1.1";
    +  else if (version == TS_HTTP_VERSION(1, 2))
    +    return "HTTP/1.2";
    +  else if (version == TS_HTTP_VERSION(2, 0))
    +    return "HTTP/2.0";
    +  else {
    +    return "(Unknown HTTP version)";
    +  }
    +}
    +
    +static void
    +log_request_line(TSMBuffer bufp, TSMLoc loc, std::string output_header)
    +{
    +  int method_len;
    +  int url_len;
    +  const char *method;
    +  const char *url;
    +  TSMLoc url_loc;
    +
    +  // parse method
    +  method = TSHttpHdrMethodGet(bufp, loc, &method_len);
    +
    +  // parse version
    +  const std::string version = convert_http_version(TSHttpHdrVersionGet(bufp, loc));
    +
    +  // parse request line URL
    +  TSHttpHdrUrlGet(bufp, loc, &url_loc);
    +  url = TSUrlStringGet(bufp, url_loc, &url_len);
    +
    +  // get rid of the preceeding http:// on the request URI
    +  for (int i = 0; i < 7; ++i)
    +    url++;
    +  url_len -= 7;
    +
    +  TSError(B_PLUGIN_NAME " [%s] request line is:\n%.*s %.*s %s\n", output_header.c_str(), method_len, method, url_len, url,
    +          version.c_str());
    +}
    +
    +static void
    +log_response_status_line(TSMBuffer bufp, TSMLoc loc, std::string output_header)
    +{
    +  TSHttpStatus status_code;
    +  const char *explanation;
    +  int explanation_len;
    +
    +  // parse version
    +  const std::string version = convert_http_version(TSHttpHdrVersionGet(bufp, loc));
    +
    +  // parse status code
    +  status_code = TSHttpHdrStatusGet(bufp, loc);
    +
    +  // get explanation
    +  explanation = TSHttpHdrReasonGet(bufp, loc, &explanation_len);
    +
    +  TSError(B_PLUGIN_NAME " [%s] response status line is:\n%s %d %.*s\n", output_header.c_str(), version.c_str(), status_code,
    --- End diff --
    
    As an option to `c_str` you can do `"%.*s", s.data(), s.length()`.



---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] trafficserver pull request #1210: Create log_requests plugin

Posted by danobi <gi...@git.apache.org>.
Github user danobi commented on a diff in the pull request:

    https://github.com/apache/trafficserver/pull/1210#discussion_r89884095
  
    --- Diff: plugins/experimental/log_requests/log_requests.cc ---
    @@ -0,0 +1,352 @@
    +/** @file
    +
    +  Logs full request/response headers on an error response code (4xx/5xx)
    +
    +  @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.
    + */
    +
    +#include <stdio.h>
    +#include <string.h>
    +#include <ctype.h>
    +
    +#include <vector>
    +#include <algorithm>
    +#include <string>
    +
    +#include "ts/ts.h"
    +#include "ts/ink_defs.h"
    +#include "ts/ink_args.h"
    +#include "ts/I_Version.h"
    +
    +#define PLUGIN_NAME "log_requests"
    +#define B_PLUGIN_NAME "[" PLUGIN_NAME "]"
    +
    +static char arg_blacklist[2048]             = "";
    +static bool log_proxy                       = false;
    +ArgumentDescription argument_descriptions[] = {
    +  {"no-log", '-', "Comma-separated list of status codes to blacklist", "S2047", arg_blacklist, nullptr, nullptr},
    +  {"log-proxy", 'p', "Also log proxy request and proxy response transaction", "F", &log_proxy, nullptr, nullptr},
    +};
    +
    +// we log the set of errors in {errors} - {blacklist}
    +static std::vector<TSHttpStatus> blacklist;
    +static std::vector<TSHttpStatus> errors({TS_HTTP_STATUS_BAD_REQUEST,
    +                                         TS_HTTP_STATUS_UNAUTHORIZED,
    +                                         TS_HTTP_STATUS_PAYMENT_REQUIRED,
    +                                         TS_HTTP_STATUS_FORBIDDEN,
    +                                         TS_HTTP_STATUS_NOT_FOUND,
    +                                         TS_HTTP_STATUS_METHOD_NOT_ALLOWED,
    +                                         TS_HTTP_STATUS_NOT_ACCEPTABLE,
    +                                         TS_HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED,
    +                                         TS_HTTP_STATUS_REQUEST_TIMEOUT,
    +                                         TS_HTTP_STATUS_CONFLICT,
    +                                         TS_HTTP_STATUS_GONE,
    +                                         TS_HTTP_STATUS_LENGTH_REQUIRED,
    +                                         TS_HTTP_STATUS_PRECONDITION_FAILED,
    +                                         TS_HTTP_STATUS_REQUEST_ENTITY_TOO_LARGE,
    +                                         TS_HTTP_STATUS_REQUEST_URI_TOO_LONG,
    +                                         TS_HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE,
    +                                         TS_HTTP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE,
    +                                         TS_HTTP_STATUS_EXPECTATION_FAILED,
    +                                         TS_HTTP_STATUS_UNPROCESSABLE_ENTITY,
    +                                         TS_HTTP_STATUS_LOCKED,
    +                                         TS_HTTP_STATUS_FAILED_DEPENDENCY,
    +                                         TS_HTTP_STATUS_UPGRADE_REQUIRED,
    +                                         TS_HTTP_STATUS_PRECONDITION_REQUIRED,
    +                                         TS_HTTP_STATUS_TOO_MANY_REQUESTS,
    +                                         TS_HTTP_STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE,
    +                                         TS_HTTP_STATUS_INTERNAL_SERVER_ERROR,
    +                                         TS_HTTP_STATUS_NOT_IMPLEMENTED,
    +                                         TS_HTTP_STATUS_BAD_GATEWAY,
    +                                         TS_HTTP_STATUS_SERVICE_UNAVAILABLE,
    +                                         TS_HTTP_STATUS_GATEWAY_TIMEOUT,
    +                                         TS_HTTP_STATUS_HTTPVER_NOT_SUPPORTED,
    +                                         TS_HTTP_STATUS_VARIANT_ALSO_NEGOTIATES,
    +                                         TS_HTTP_STATUS_INSUFFICIENT_STORAGE,
    +                                         TS_HTTP_STATUS_LOOP_DETECTED,
    +                                         TS_HTTP_STATUS_NOT_EXTENDED,
    +                                         TS_HTTP_STATUS_NETWORK_AUTHENTICATION_REQUIRED});
    +
    +static bool should_log(TSHttpTxn txnp);
    +static const std::string convert_http_version(const int version);
    +static void log_request_line(TSMBuffer bufp, TSMLoc loc, std::string output_header);
    +static void log_response_status_line(TSMBuffer bufp, TSMLoc loc, std::string output_header);
    +static void log_headers(TSMBuffer bufp, TSMLoc loc, std::string output_header);
    +static void log_full_transaction(TSHttpTxn txnp);
    +static int log_requests_plugin(TSCont contp ATS_UNUSED, TSEvent event, void *edata);
    +static std::vector<std::string> split(const std::string &str, const std::string &delim);
    +
    +static std::vector<std::string>
    +split(const std::string &str, const std::string &delim)
    +{
    +  std::vector<std::string> tokens;
    +  size_t prev = 0, pos = 0;
    +  do {
    +    pos = str.find(delim, prev);
    +    if (pos == std::string::npos)
    +      pos = str.length();
    +
    +    std::string token = str.substr(prev, pos - prev);
    +    if (!token.empty())
    +      tokens.push_back(token);
    +
    +    prev = pos + delim.length();
    +  } while (pos < str.length() && prev < str.length());
    +
    +  return tokens;
    +}
    +
    +static bool
    +should_log(TSHttpTxn txnp)
    +{
    +  TSMBuffer txn_resp_bufp;
    +  TSMLoc txn_resp_loc;
    +  TSHttpStatus resp_status;
    +
    +  if (TSHttpTxnClientRespGet(txnp, &txn_resp_bufp, &txn_resp_loc) != TS_SUCCESS) {
    +    TSError(B_PLUGIN_NAME " Couldn't retrieve server response header.");
    +    return false;
    +  }
    +
    +  // get the transaction response status code
    +  resp_status = TSHttpHdrStatusGet(txn_resp_bufp, txn_resp_loc);
    +
    +  // if resp_status is blacklisted, don't log
    +  if (std::any_of(blacklist.begin(), blacklist.end(), [=](TSHttpStatus code) { return code == resp_status; }))
    +    return false;
    +
    +  // else, if resp_status is in errors, log it
    +  if (std::any_of(errors.begin(), errors.end(), [=](TSHttpStatus error) { return error == resp_status; }))
    +    return true;
    +
    +  // fall through
    +  return false;
    +}
    +
    +static const std::string
    +convert_http_version(const int version)
    +{
    +  if (version == TS_HTTP_VERSION(1, 0))
    +    return "HTTP/1.0";
    +  else if (version == TS_HTTP_VERSION(1, 1))
    +    return "HTTP/1.1";
    +  else if (version == TS_HTTP_VERSION(1, 2))
    +    return "HTTP/1.2";
    +  else if (version == TS_HTTP_VERSION(2, 0))
    +    return "HTTP/2.0";
    +  else {
    +    return "(Unknown HTTP version)";
    +  }
    +}
    +
    +static void
    +log_request_line(TSMBuffer bufp, TSMLoc loc, std::string output_header)
    +{
    +  int method_len;
    +  int url_len;
    +  const char *method;
    +  const char *url;
    +  TSMLoc url_loc;
    +
    +  // parse method
    +  method = TSHttpHdrMethodGet(bufp, loc, &method_len);
    +
    +  // parse version
    +  const std::string version = convert_http_version(TSHttpHdrVersionGet(bufp, loc));
    +
    +  // parse request line URL
    +  TSHttpHdrUrlGet(bufp, loc, &url_loc);
    +  url = TSUrlStringGet(bufp, url_loc, &url_len);
    +
    +  // get rid of the preceeding http:// on the request URI
    +  for (int i = 0; i < 7; ++i)
    +    url++;
    +  url_len -= 7;
    +
    +  TSError(B_PLUGIN_NAME " [%s] request line is:\n%.*s %.*s %s\n", output_header.c_str(), method_len, method, url_len, url,
    +          version.c_str());
    +}
    +
    +static void
    +log_response_status_line(TSMBuffer bufp, TSMLoc loc, std::string output_header)
    +{
    +  TSHttpStatus status_code;
    +  const char *explanation;
    +  int explanation_len;
    +
    +  // parse version
    +  const std::string version = convert_http_version(TSHttpHdrVersionGet(bufp, loc));
    +
    +  // parse status code
    +  status_code = TSHttpHdrStatusGet(bufp, loc);
    +
    +  // get explanation
    +  explanation = TSHttpHdrReasonGet(bufp, loc, &explanation_len);
    +
    +  TSError(B_PLUGIN_NAME " [%s] response status line is:\n%s %d %.*s\n", output_header.c_str(), version.c_str(), status_code,
    --- End diff --
    
    I'm not sure I see the advantage. C++11 guarantees `c_str` to be a pointer to the internal `std::string` buffer anyways.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] trafficserver issue #1210: Create log_requests plugin

Posted by SolidWallOfCode <gi...@git.apache.org>.
Github user SolidWallOfCode commented on the issue:

    https://github.com/apache/trafficserver/pull/1210
  
    I have to agree with @jpeach that `log_requests` is a bad name. `error_header_log` maybe? I don't much like any alternatives I can think up. There's also the possibility of putting this functionality in `kitchen_sink`, I mean `header_rewrite` although that has some ugly as well.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] trafficserver pull request #1210: Create log_requests plugin

Posted by zwoop <gi...@git.apache.org>.
Github user zwoop commented on a diff in the pull request:

    https://github.com/apache/trafficserver/pull/1210#discussion_r86891158
  
    --- Diff: plugins/experimental/log_requests/log_requests.c ---
    @@ -0,0 +1,301 @@
    +/** @file
    +
    +  Logs full request/response headers on an error response code (4xx/5xx)
    +
    +  @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.
    + */
    +
    +#include <stdio.h>
    +#include <string.h>
    +#include <ctype.h>
    +
    +#include "ts/ts.h"
    +#include "ts/ink_defs.h"
    +
    +#define PLUGIN_NAME log_requests
    +
    +// we log the set of errors in {errors} - {blacklist}
    +static TSHttpStatus *blacklist;
    +static int blacklist_size; // number of entries in blacklist
    +static TSHttpStatus errors[] = {TS_HTTP_STATUS_BAD_REQUEST,
    +                                TS_HTTP_STATUS_UNAUTHORIZED,
    +                                TS_HTTP_STATUS_PAYMENT_REQUIRED,
    +                                TS_HTTP_STATUS_FORBIDDEN,
    +                                TS_HTTP_STATUS_NOT_FOUND,
    +                                TS_HTTP_STATUS_METHOD_NOT_ALLOWED,
    +                                TS_HTTP_STATUS_NOT_ACCEPTABLE,
    +                                TS_HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED,
    +                                TS_HTTP_STATUS_REQUEST_TIMEOUT,
    +                                TS_HTTP_STATUS_CONFLICT,
    +                                TS_HTTP_STATUS_GONE,
    +                                TS_HTTP_STATUS_LENGTH_REQUIRED,
    +                                TS_HTTP_STATUS_PRECONDITION_FAILED,
    +                                TS_HTTP_STATUS_REQUEST_ENTITY_TOO_LARGE,
    +                                TS_HTTP_STATUS_REQUEST_URI_TOO_LONG,
    +                                TS_HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE,
    +                                TS_HTTP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE,
    +                                TS_HTTP_STATUS_EXPECTATION_FAILED,
    +                                TS_HTTP_STATUS_UNPROCESSABLE_ENTITY,
    +                                TS_HTTP_STATUS_LOCKED,
    +                                TS_HTTP_STATUS_FAILED_DEPENDENCY,
    +                                TS_HTTP_STATUS_UPGRADE_REQUIRED,
    +                                TS_HTTP_STATUS_PRECONDITION_REQUIRED,
    +                                TS_HTTP_STATUS_TOO_MANY_REQUESTS,
    +                                TS_HTTP_STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE,
    +                                TS_HTTP_STATUS_INTERNAL_SERVER_ERROR,
    +                                TS_HTTP_STATUS_NOT_IMPLEMENTED,
    +                                TS_HTTP_STATUS_BAD_GATEWAY,
    +                                TS_HTTP_STATUS_SERVICE_UNAVAILABLE,
    +                                TS_HTTP_STATUS_GATEWAY_TIMEOUT,
    +                                TS_HTTP_STATUS_HTTPVER_NOT_SUPPORTED,
    +                                TS_HTTP_STATUS_VARIANT_ALSO_NEGOTIATES,
    +                                TS_HTTP_STATUS_INSUFFICIENT_STORAGE,
    +                                TS_HTTP_STATUS_LOOP_DETECTED,
    +                                TS_HTTP_STATUS_NOT_EXTENDED,
    +                                TS_HTTP_STATUS_NETWORK_AUTHENTICATION_REQUIRED};
    +
    +static bool should_log(TSHttpTxn txnp);
    +static void log_request_line(TSMBuffer bufp, TSMLoc loc, const char *output_header);
    +static void log_response_status_line(TSMBuffer bufp, TSMLoc loc, const char *output_header);
    +static void log_headers(TSMBuffer bufp, TSMLoc loc, const char *output_header);
    +static void log_full_transaction(TSHttpTxn txnp);
    +static int log_requests_plugin(TSCont contp ATS_UNUSED, TSEvent event, void *edata);
    +
    +static bool
    +should_log(TSHttpTxn txnp)
    +{
    +  TSMBuffer txn_resp_bufp;
    +  TSMLoc txn_resp_loc;
    +  TSHttpStatus resp_status;
    +
    +  if (TSHttpTxnClientRespGet(txnp, &txn_resp_bufp, &txn_resp_loc) != TS_SUCCESS) {
    +    TSError("[log_requests] Couldn't retrieve server response header.");
    +    return false;
    +  }
    +
    +  // if resp_status is blacklisted, don't log
    +  resp_status = TSHttpHdrStatusGet(txn_resp_bufp, txn_resp_loc);
    +  for (int i = 0; i < blacklist_size; ++i) {
    +    if (resp_status == blacklist[i])
    +      return false;
    +  }
    +
    +  // else, if resp_status is in errors, log it
    +  for (int i = 0; i < (int)(sizeof(errors) / sizeof(TSHttpStatus)); ++i) {
    +    if (resp_status == errors[i]) {
    +      return true;
    +    }
    +  }
    +
    +  // fall through
    +  return false;
    +}
    +
    +const char *
    +convert_http_version(const int version)
    +{
    +  char *ret;
    +  if (version == TS_HTTP_VERSION(1, 0))
    +    ret = "HTTP/1.0";
    +  else if (version == TS_HTTP_VERSION(1, 1))
    +    ret = "HTTP/1.1";
    +  else if (version == TS_HTTP_VERSION(1, 2))
    +    ret = "HTTP/1.2";
    +  else if (version == TS_HTTP_VERSION(2, 0))
    +    ret = "HTTP/2.0";
    +  else {
    +    ret = "(Unknown HTTP version)";
    +  }
    +
    +  return ret;
    +}
    +
    +static void
    +log_request_line(TSMBuffer bufp, TSMLoc loc, const char *output_header)
    +{
    +  int method_len;
    +  int url_len;
    +  const char *version;
    +  TSMLoc url_loc;
    +
    +  // parse method
    +  const char *method = TSHttpHdrMethodGet(bufp, loc, &method_len);
    +
    +  // parse version
    +  version = convert_http_version(TSHttpHdrVersionGet(bufp, loc));
    +
    +  // parse request line URL
    +  TSHttpHdrUrlGet(bufp, loc, &url_loc);
    +  const char *url = TSUrlStringGet(bufp, url_loc, &url_len);
    +
    +  // null terminate these strings so we can printf them
    --- End diff --
    
    I think I see why you strdup these, you really don't have to. You should do a pattern like
    ```C
    TSError([log_requests] %s request line='%.*s %.*s %s'", output_header, method_len, method, url_len, url, version);
    ```


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] trafficserver issue #1210: Create log_requests plugin

Posted by danobi <gi...@git.apache.org>.
Github user danobi commented on the issue:

    https://github.com/apache/trafficserver/pull/1210
  
    I'm just going to start adding ideas of names to this comment as I come up with them.
    
    `dump_errors`, `log_bad`, `log_errors`


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] trafficserver pull request #1210: Create log_requests plugin

Posted by zwoop <gi...@git.apache.org>.
Github user zwoop commented on a diff in the pull request:

    https://github.com/apache/trafficserver/pull/1210#discussion_r86890910
  
    --- Diff: plugins/experimental/log_requests/log_requests.c ---
    @@ -0,0 +1,301 @@
    +/** @file
    +
    +  Logs full request/response headers on an error response code (4xx/5xx)
    +
    +  @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.
    + */
    +
    +#include <stdio.h>
    +#include <string.h>
    +#include <ctype.h>
    +
    +#include "ts/ts.h"
    +#include "ts/ink_defs.h"
    +
    +#define PLUGIN_NAME log_requests
    +
    +// we log the set of errors in {errors} - {blacklist}
    +static TSHttpStatus *blacklist;
    +static int blacklist_size; // number of entries in blacklist
    +static TSHttpStatus errors[] = {TS_HTTP_STATUS_BAD_REQUEST,
    +                                TS_HTTP_STATUS_UNAUTHORIZED,
    +                                TS_HTTP_STATUS_PAYMENT_REQUIRED,
    +                                TS_HTTP_STATUS_FORBIDDEN,
    +                                TS_HTTP_STATUS_NOT_FOUND,
    +                                TS_HTTP_STATUS_METHOD_NOT_ALLOWED,
    +                                TS_HTTP_STATUS_NOT_ACCEPTABLE,
    +                                TS_HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED,
    +                                TS_HTTP_STATUS_REQUEST_TIMEOUT,
    +                                TS_HTTP_STATUS_CONFLICT,
    +                                TS_HTTP_STATUS_GONE,
    +                                TS_HTTP_STATUS_LENGTH_REQUIRED,
    +                                TS_HTTP_STATUS_PRECONDITION_FAILED,
    +                                TS_HTTP_STATUS_REQUEST_ENTITY_TOO_LARGE,
    +                                TS_HTTP_STATUS_REQUEST_URI_TOO_LONG,
    +                                TS_HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE,
    +                                TS_HTTP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE,
    +                                TS_HTTP_STATUS_EXPECTATION_FAILED,
    +                                TS_HTTP_STATUS_UNPROCESSABLE_ENTITY,
    +                                TS_HTTP_STATUS_LOCKED,
    +                                TS_HTTP_STATUS_FAILED_DEPENDENCY,
    +                                TS_HTTP_STATUS_UPGRADE_REQUIRED,
    +                                TS_HTTP_STATUS_PRECONDITION_REQUIRED,
    +                                TS_HTTP_STATUS_TOO_MANY_REQUESTS,
    +                                TS_HTTP_STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE,
    +                                TS_HTTP_STATUS_INTERNAL_SERVER_ERROR,
    +                                TS_HTTP_STATUS_NOT_IMPLEMENTED,
    +                                TS_HTTP_STATUS_BAD_GATEWAY,
    +                                TS_HTTP_STATUS_SERVICE_UNAVAILABLE,
    +                                TS_HTTP_STATUS_GATEWAY_TIMEOUT,
    +                                TS_HTTP_STATUS_HTTPVER_NOT_SUPPORTED,
    +                                TS_HTTP_STATUS_VARIANT_ALSO_NEGOTIATES,
    +                                TS_HTTP_STATUS_INSUFFICIENT_STORAGE,
    +                                TS_HTTP_STATUS_LOOP_DETECTED,
    +                                TS_HTTP_STATUS_NOT_EXTENDED,
    +                                TS_HTTP_STATUS_NETWORK_AUTHENTICATION_REQUIRED};
    +
    +static bool should_log(TSHttpTxn txnp);
    +static void log_request_line(TSMBuffer bufp, TSMLoc loc, const char *output_header);
    +static void log_response_status_line(TSMBuffer bufp, TSMLoc loc, const char *output_header);
    +static void log_headers(TSMBuffer bufp, TSMLoc loc, const char *output_header);
    +static void log_full_transaction(TSHttpTxn txnp);
    +static int log_requests_plugin(TSCont contp ATS_UNUSED, TSEvent event, void *edata);
    +
    +static bool
    +should_log(TSHttpTxn txnp)
    +{
    +  TSMBuffer txn_resp_bufp;
    +  TSMLoc txn_resp_loc;
    +  TSHttpStatus resp_status;
    +
    +  if (TSHttpTxnClientRespGet(txnp, &txn_resp_bufp, &txn_resp_loc) != TS_SUCCESS) {
    +    TSError("[log_requests] Couldn't retrieve server response header.");
    +    return false;
    +  }
    +
    +  // if resp_status is blacklisted, don't log
    +  resp_status = TSHttpHdrStatusGet(txn_resp_bufp, txn_resp_loc);
    +  for (int i = 0; i < blacklist_size; ++i) {
    +    if (resp_status == blacklist[i])
    +      return false;
    +  }
    +
    +  // else, if resp_status is in errors, log it
    +  for (int i = 0; i < (int)(sizeof(errors) / sizeof(TSHttpStatus)); ++i) {
    +    if (resp_status == errors[i]) {
    +      return true;
    +    }
    +  }
    +
    +  // fall through
    +  return false;
    +}
    +
    +const char *
    +convert_http_version(const int version)
    +{
    +  char *ret;
    +  if (version == TS_HTTP_VERSION(1, 0))
    +    ret = "HTTP/1.0";
    +  else if (version == TS_HTTP_VERSION(1, 1))
    +    ret = "HTTP/1.1";
    +  else if (version == TS_HTTP_VERSION(1, 2))
    +    ret = "HTTP/1.2";
    +  else if (version == TS_HTTP_VERSION(2, 0))
    +    ret = "HTTP/2.0";
    +  else {
    +    ret = "(Unknown HTTP version)";
    +  }
    +
    +  return ret;
    +}
    +
    +static void
    +log_request_line(TSMBuffer bufp, TSMLoc loc, const char *output_header)
    +{
    +  int method_len;
    +  int url_len;
    +  const char *version;
    +  TSMLoc url_loc;
    +
    +  // parse method
    +  const char *method = TSHttpHdrMethodGet(bufp, loc, &method_len);
    +
    +  // parse version
    +  version = convert_http_version(TSHttpHdrVersionGet(bufp, loc));
    +
    +  // parse request line URL
    +  TSHttpHdrUrlGet(bufp, loc, &url_loc);
    +  const char *url = TSUrlStringGet(bufp, url_loc, &url_len);
    +
    +  // null terminate these strings so we can printf them
    +  char *dup_method   = TSstrndup(method, method_len);
    +  char *dup_url      = TSstrndup(url, url_len);
    +  char *dup_url_orig = dup_url;
    +
    +  // get rid of the preceeding http:// on the request URI
    +  for (int i = 0; i < 7; ++i) {
    +    dup_url++;
    +  }
    +
    +  TSError("[log_requests] %s request line='%s %s %s'", output_header, dup_method, dup_url, version);
    +
    +  TSfree(dup_method);
    +  TSfree(dup_url_orig);
    +}
    +
    +static void
    +log_response_status_line(TSMBuffer bufp, TSMLoc loc, const char *output_header)
    +{
    +  const char *version;
    +  TSHttpStatus status_code;
    +  const char *explanation;
    +  int explanation_len;
    +
    +  // parse version
    +  version = convert_http_version(TSHttpHdrVersionGet(bufp, loc));
    +
    +  // parse status code
    +  status_code = TSHttpHdrStatusGet(bufp, loc);
    +
    +  // get explanation
    +  explanation           = TSHttpHdrReasonGet(bufp, loc, &explanation_len);
    +  char *explanation_dup = TSstrndup(explanation, explanation_len);
    +
    +  TSError("[log_requests] %s response status line='%s %d %s'", output_header, version, status_code, explanation_dup);
    +
    +  TSfree(explanation_dup);
    +}
    +
    +static void
    +log_headers(TSMBuffer bufp, TSMLoc loc, const char *output_header)
    +{
    +  // parse out request headers
    +  TSMLoc field_loc = TSMimeHdrFieldGet(bufp, loc, 0);
    +  while (field_loc) {
    +    TSMLoc next_field_loc;
    +    const char *name;
    +    int name_len;
    +
    +    // grab the header name
    +    name = TSMimeHdrFieldNameGet(bufp, loc, field_loc, &name_len);
    +
    +    if (name) {
    +      char *dup_name = TSstrndup(name, name_len);
    --- End diff --
    
    See above.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] trafficserver pull request #1210: Create log_requests plugin

Posted by SolidWallOfCode <gi...@git.apache.org>.
Github user SolidWallOfCode commented on a diff in the pull request:

    https://github.com/apache/trafficserver/pull/1210#discussion_r87404920
  
    --- Diff: plugins/experimental/log_requests/README ---
    @@ -0,0 +1,37 @@
    +log_requests
    +==============
    +
    +This plugin is used to help debug errored out transactions. 
    +We define errored out as any transaction returning a 4xx/5xx 
    +response code. By default, all transactions that return a 
    +4xx/5xx response code to the client will get its 
    +request/response headers logged into error.log.
    +
    +We also provide a blacklist flag via the plugin arguments. Take 
    +for example this config in plugin.config:
    +
    +    log_requests.so --no-log 414 502
    --- End diff --
    
    Meh. I think it would be better to have a comma separated list like `--no-log 414,502`. Otherwise I don't see how additional argument can be added later (although I suppose  you could check for leading dashes on subsequent arguments).



---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] trafficserver pull request #1210: Create log_requests plugin

Posted by SolidWallOfCode <gi...@git.apache.org>.
Github user SolidWallOfCode commented on a diff in the pull request:

    https://github.com/apache/trafficserver/pull/1210#discussion_r87404997
  
    --- Diff: plugins/experimental/log_requests/README ---
    @@ -0,0 +1,37 @@
    +log_requests
    +==============
    +
    +This plugin is used to help debug errored out transactions. 
    +We define errored out as any transaction returning a 4xx/5xx 
    +response code. By default, all transactions that return a 
    +4xx/5xx response code to the client will get its 
    +request/response headers logged into error.log.
    +
    +We also provide a blacklist flag via the plugin arguments. Take 
    +for example this config in plugin.config:
    +
    +    log_requests.so --no-log 414 502
    +
    +Then log_requests would log every 4xx/5xx response code transaction
    +EXCEPT for 414 and 502.
    +
    +
    +Usage
    +------
    +When compiling ATS, run configure with the following flags:
    +
    +    ./configure --enable-experimental-plugins
    +
    +
    +Then in plugin.config:
    +    
    +    log_requests.so [--log-proxy] [--no-log [error code 1[,error code 2[,...]]]]
    +
    +    In other words, the --log-proxy and --no-log flags are optional. 
    +    --no-log should be followed with a comma separated list of error
    +    codes to blacklist.
    +
    +    Note: There is an interesting bug where if you want to enable 
    +    --log-proxy, it has to come before the --no-log flag. I'm not
    +    sure why this happens, but you'll have to just live with it
    +    until I figure it out.
    --- End diff --
    
    See previous comment ^



---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] trafficserver issue #1210: Create log_requests plugin

Posted by zwoop <gi...@git.apache.org>.
Github user zwoop commented on the issue:

    https://github.com/apache/trafficserver/pull/1210
  
    Not sure what happened with my final review message, but I'd suggest looking at dump_headers() in e.g. plugins/background_fetch/headers.cc. It cleanly dumps all headers into a buffer, which you can then do whatever you want with (including dumping with TSError()).


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] trafficserver pull request #1210: Create log_requests plugin

Posted by SolidWallOfCode <gi...@git.apache.org>.
Github user SolidWallOfCode commented on a diff in the pull request:

    https://github.com/apache/trafficserver/pull/1210#discussion_r87405081
  
    --- Diff: plugins/experimental/log_requests/log_requests.cc ---
    @@ -0,0 +1,352 @@
    +/** @file
    +
    +  Logs full request/response headers on an error response code (4xx/5xx)
    +
    +  @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.
    + */
    +
    +#include <stdio.h>
    +#include <string.h>
    +#include <ctype.h>
    +
    +#include <vector>
    +#include <algorithm>
    +#include <string>
    +
    +#include "ts/ts.h"
    +#include "ts/ink_defs.h"
    +#include "ts/ink_args.h"
    +#include "ts/I_Version.h"
    +
    +#define PLUGIN_NAME "log_requests"
    +#define B_PLUGIN_NAME "[" PLUGIN_NAME "]"
    +
    +static char arg_blacklist[2048]             = "";
    +static bool log_proxy                       = false;
    +ArgumentDescription argument_descriptions[] = {
    +  {"no-log", '-', "Comma-separated list of status codes to blacklist", "S2047", arg_blacklist, nullptr, nullptr},
    +  {"log-proxy", 'p', "Also log proxy request and proxy response transaction", "F", &log_proxy, nullptr, nullptr},
    +};
    +
    +// we log the set of errors in {errors} - {blacklist}
    +static std::vector<TSHttpStatus> blacklist;
    +static std::vector<TSHttpStatus> errors({TS_HTTP_STATUS_BAD_REQUEST,
    --- End diff --
    
    Remove this, just check for `400 <= response_code < 600`.



---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] trafficserver pull request #1210: Create log_requests plugin

Posted by SolidWallOfCode <gi...@git.apache.org>.
Github user SolidWallOfCode commented on a diff in the pull request:

    https://github.com/apache/trafficserver/pull/1210#discussion_r87406451
  
    --- Diff: plugins/experimental/log_requests/log_requests.cc ---
    @@ -0,0 +1,352 @@
    +/** @file
    +
    +  Logs full request/response headers on an error response code (4xx/5xx)
    +
    +  @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.
    + */
    +
    +#include <stdio.h>
    +#include <string.h>
    +#include <ctype.h>
    +
    +#include <vector>
    +#include <algorithm>
    +#include <string>
    +
    +#include "ts/ts.h"
    +#include "ts/ink_defs.h"
    +#include "ts/ink_args.h"
    +#include "ts/I_Version.h"
    +
    +#define PLUGIN_NAME "log_requests"
    +#define B_PLUGIN_NAME "[" PLUGIN_NAME "]"
    +
    +static char arg_blacklist[2048]             = "";
    +static bool log_proxy                       = false;
    +ArgumentDescription argument_descriptions[] = {
    +  {"no-log", '-', "Comma-separated list of status codes to blacklist", "S2047", arg_blacklist, nullptr, nullptr},
    +  {"log-proxy", 'p', "Also log proxy request and proxy response transaction", "F", &log_proxy, nullptr, nullptr},
    +};
    +
    +// we log the set of errors in {errors} - {blacklist}
    +static std::vector<TSHttpStatus> blacklist;
    +static std::vector<TSHttpStatus> errors({TS_HTTP_STATUS_BAD_REQUEST,
    +                                         TS_HTTP_STATUS_UNAUTHORIZED,
    +                                         TS_HTTP_STATUS_PAYMENT_REQUIRED,
    +                                         TS_HTTP_STATUS_FORBIDDEN,
    +                                         TS_HTTP_STATUS_NOT_FOUND,
    +                                         TS_HTTP_STATUS_METHOD_NOT_ALLOWED,
    +                                         TS_HTTP_STATUS_NOT_ACCEPTABLE,
    +                                         TS_HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED,
    +                                         TS_HTTP_STATUS_REQUEST_TIMEOUT,
    +                                         TS_HTTP_STATUS_CONFLICT,
    +                                         TS_HTTP_STATUS_GONE,
    +                                         TS_HTTP_STATUS_LENGTH_REQUIRED,
    +                                         TS_HTTP_STATUS_PRECONDITION_FAILED,
    +                                         TS_HTTP_STATUS_REQUEST_ENTITY_TOO_LARGE,
    +                                         TS_HTTP_STATUS_REQUEST_URI_TOO_LONG,
    +                                         TS_HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE,
    +                                         TS_HTTP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE,
    +                                         TS_HTTP_STATUS_EXPECTATION_FAILED,
    +                                         TS_HTTP_STATUS_UNPROCESSABLE_ENTITY,
    +                                         TS_HTTP_STATUS_LOCKED,
    +                                         TS_HTTP_STATUS_FAILED_DEPENDENCY,
    +                                         TS_HTTP_STATUS_UPGRADE_REQUIRED,
    +                                         TS_HTTP_STATUS_PRECONDITION_REQUIRED,
    +                                         TS_HTTP_STATUS_TOO_MANY_REQUESTS,
    +                                         TS_HTTP_STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE,
    +                                         TS_HTTP_STATUS_INTERNAL_SERVER_ERROR,
    +                                         TS_HTTP_STATUS_NOT_IMPLEMENTED,
    +                                         TS_HTTP_STATUS_BAD_GATEWAY,
    +                                         TS_HTTP_STATUS_SERVICE_UNAVAILABLE,
    +                                         TS_HTTP_STATUS_GATEWAY_TIMEOUT,
    +                                         TS_HTTP_STATUS_HTTPVER_NOT_SUPPORTED,
    +                                         TS_HTTP_STATUS_VARIANT_ALSO_NEGOTIATES,
    +                                         TS_HTTP_STATUS_INSUFFICIENT_STORAGE,
    +                                         TS_HTTP_STATUS_LOOP_DETECTED,
    +                                         TS_HTTP_STATUS_NOT_EXTENDED,
    +                                         TS_HTTP_STATUS_NETWORK_AUTHENTICATION_REQUIRED});
    +
    +static bool should_log(TSHttpTxn txnp);
    +static const std::string convert_http_version(const int version);
    +static void log_request_line(TSMBuffer bufp, TSMLoc loc, std::string output_header);
    +static void log_response_status_line(TSMBuffer bufp, TSMLoc loc, std::string output_header);
    +static void log_headers(TSMBuffer bufp, TSMLoc loc, std::string output_header);
    +static void log_full_transaction(TSHttpTxn txnp);
    +static int log_requests_plugin(TSCont contp ATS_UNUSED, TSEvent event, void *edata);
    +static std::vector<std::string> split(const std::string &str, const std::string &delim);
    +
    +static std::vector<std::string>
    +split(const std::string &str, const std::string &delim)
    +{
    +  std::vector<std::string> tokens;
    +  size_t prev = 0, pos = 0;
    +  do {
    +    pos = str.find(delim, prev);
    +    if (pos == std::string::npos)
    +      pos = str.length();
    +
    +    std::string token = str.substr(prev, pos - prev);
    +    if (!token.empty())
    +      tokens.push_back(token);
    +
    +    prev = pos + delim.length();
    +  } while (pos < str.length() && prev < str.length());
    +
    +  return tokens;
    +}
    +
    +static bool
    +should_log(TSHttpTxn txnp)
    +{
    +  TSMBuffer txn_resp_bufp;
    +  TSMLoc txn_resp_loc;
    +  TSHttpStatus resp_status;
    +
    +  if (TSHttpTxnClientRespGet(txnp, &txn_resp_bufp, &txn_resp_loc) != TS_SUCCESS) {
    +    TSError(B_PLUGIN_NAME " Couldn't retrieve server response header.");
    +    return false;
    +  }
    +
    +  // get the transaction response status code
    +  resp_status = TSHttpHdrStatusGet(txn_resp_bufp, txn_resp_loc);
    +
    +  // if resp_status is blacklisted, don't log
    +  if (std::any_of(blacklist.begin(), blacklist.end(), [=](TSHttpStatus code) { return code == resp_status; }))
    +    return false;
    +
    +  // else, if resp_status is in errors, log it
    +  if (std::any_of(errors.begin(), errors.end(), [=](TSHttpStatus error) { return error == resp_status; }))
    +    return true;
    +
    +  // fall through
    +  return false;
    +}
    +
    +static const std::string
    +convert_http_version(const int version)
    +{
    +  if (version == TS_HTTP_VERSION(1, 0))
    +    return "HTTP/1.0";
    +  else if (version == TS_HTTP_VERSION(1, 1))
    +    return "HTTP/1.1";
    +  else if (version == TS_HTTP_VERSION(1, 2))
    +    return "HTTP/1.2";
    +  else if (version == TS_HTTP_VERSION(2, 0))
    +    return "HTTP/2.0";
    +  else {
    +    return "(Unknown HTTP version)";
    +  }
    +}
    +
    +static void
    +log_request_line(TSMBuffer bufp, TSMLoc loc, std::string output_header)
    +{
    +  int method_len;
    +  int url_len;
    +  const char *method;
    +  const char *url;
    +  TSMLoc url_loc;
    +
    +  // parse method
    +  method = TSHttpHdrMethodGet(bufp, loc, &method_len);
    +
    +  // parse version
    +  const std::string version = convert_http_version(TSHttpHdrVersionGet(bufp, loc));
    +
    +  // parse request line URL
    +  TSHttpHdrUrlGet(bufp, loc, &url_loc);
    +  url = TSUrlStringGet(bufp, url_loc, &url_len);
    +
    +  // get rid of the preceeding http:// on the request URI
    +  for (int i = 0; i < 7; ++i)
    +    url++;
    +  url_len -= 7;
    +
    +  TSError(B_PLUGIN_NAME " [%s] request line is:\n%.*s %.*s %s\n", output_header.c_str(), method_len, method, url_len, url,
    +          version.c_str());
    +}
    +
    +static void
    +log_response_status_line(TSMBuffer bufp, TSMLoc loc, std::string output_header)
    +{
    +  TSHttpStatus status_code;
    +  const char *explanation;
    +  int explanation_len;
    +
    +  // parse version
    +  const std::string version = convert_http_version(TSHttpHdrVersionGet(bufp, loc));
    +
    +  // parse status code
    +  status_code = TSHttpHdrStatusGet(bufp, loc);
    +
    +  // get explanation
    +  explanation = TSHttpHdrReasonGet(bufp, loc, &explanation_len);
    +
    +  TSError(B_PLUGIN_NAME " [%s] response status line is:\n%s %d %.*s\n", output_header.c_str(), version.c_str(), status_code,
    +          explanation_len, explanation);
    +}
    +
    +static void
    +log_headers(TSMBuffer bufp, TSMLoc loc, std::string output_header)
    +{
    +  TSIOBuffer output_buffer;
    +  TSIOBufferReader reader;
    +  TSIOBufferBlock block;
    +  const char *block_start;
    +  int64_t block_avail;
    +
    +  output_buffer = TSIOBufferCreate();
    +  reader        = TSIOBufferReaderAlloc(output_buffer);
    +
    +  // This will print just MIMEFields and not the http request line
    +  TSMimeHdrPrint(bufp, loc, output_buffer);
    +
    +  // We need to loop over all the buffer blocks, there can be more than 1
    +  block = TSIOBufferReaderStart(reader);
    +  do {
    +    block_start = TSIOBufferBlockReadStart(block, reader, &block_avail);
    +    if (block_avail > 0) {
    +      TSError(B_PLUGIN_NAME " Headers are:\n%.*s", static_cast<int>(block_avail), block_start);
    +    }
    +    TSIOBufferReaderConsume(reader, block_avail);
    +    block = TSIOBufferReaderStart(reader);
    +  } while (block && block_avail != 0);
    +
    +  // Free up the TSIOBuffer that we used to print out the header
    +  TSIOBufferReaderFree(reader);
    +  TSIOBufferDestroy(output_buffer);
    +}
    +
    +/*
    + * TODO: There are resource leaks if calls to TSHttpTxnClientReqGet() & TSHttpTxnClientRespGet()
    + * fail. Likewise for the ...ServerReqGet() & ...ServerRespGet() calls. Need to do work with
    + * some goto's to fix.
    --- End diff --
    
    No `goto`! Bad Dan! `std::unique_ptr` was made to handle this problem.



---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] trafficserver issue #1210: Create log_requests plugin

Posted by danobi <gi...@git.apache.org>.
Github user danobi commented on the issue:

    https://github.com/apache/trafficserver/pull/1210
  
    Closing. I'm in the process of creating new log fields to do the same thing here.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] trafficserver issue #1210: Create log_requests plugin

Posted by danobi <gi...@git.apache.org>.
Github user danobi commented on the issue:

    https://github.com/apache/trafficserver/pull/1210
  
    Created under @SolidWallOfCode 's orders.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] trafficserver pull request #1210: Create log_requests plugin

Posted by SolidWallOfCode <gi...@git.apache.org>.
Github user SolidWallOfCode commented on a diff in the pull request:

    https://github.com/apache/trafficserver/pull/1210#discussion_r87219292
  
    --- Diff: plugins/experimental/log_requests/log_requests.c ---
    @@ -0,0 +1,301 @@
    +/** @file
    +
    +  Logs full request/response headers on an error response code (4xx/5xx)
    +
    +  @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.
    + */
    +
    +#include <stdio.h>
    +#include <string.h>
    +#include <ctype.h>
    +
    +#include "ts/ts.h"
    +#include "ts/ink_defs.h"
    +
    +#define PLUGIN_NAME log_requests
    +
    +// we log the set of errors in {errors} - {blacklist}
    +static TSHttpStatus *blacklist;
    +static int blacklist_size; // number of entries in blacklist
    +static TSHttpStatus errors[] = {TS_HTTP_STATUS_BAD_REQUEST,
    +                                TS_HTTP_STATUS_UNAUTHORIZED,
    +                                TS_HTTP_STATUS_PAYMENT_REQUIRED,
    +                                TS_HTTP_STATUS_FORBIDDEN,
    +                                TS_HTTP_STATUS_NOT_FOUND,
    +                                TS_HTTP_STATUS_METHOD_NOT_ALLOWED,
    +                                TS_HTTP_STATUS_NOT_ACCEPTABLE,
    +                                TS_HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED,
    +                                TS_HTTP_STATUS_REQUEST_TIMEOUT,
    +                                TS_HTTP_STATUS_CONFLICT,
    +                                TS_HTTP_STATUS_GONE,
    +                                TS_HTTP_STATUS_LENGTH_REQUIRED,
    +                                TS_HTTP_STATUS_PRECONDITION_FAILED,
    +                                TS_HTTP_STATUS_REQUEST_ENTITY_TOO_LARGE,
    +                                TS_HTTP_STATUS_REQUEST_URI_TOO_LONG,
    +                                TS_HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE,
    +                                TS_HTTP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE,
    +                                TS_HTTP_STATUS_EXPECTATION_FAILED,
    +                                TS_HTTP_STATUS_UNPROCESSABLE_ENTITY,
    +                                TS_HTTP_STATUS_LOCKED,
    +                                TS_HTTP_STATUS_FAILED_DEPENDENCY,
    +                                TS_HTTP_STATUS_UPGRADE_REQUIRED,
    +                                TS_HTTP_STATUS_PRECONDITION_REQUIRED,
    +                                TS_HTTP_STATUS_TOO_MANY_REQUESTS,
    +                                TS_HTTP_STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE,
    +                                TS_HTTP_STATUS_INTERNAL_SERVER_ERROR,
    +                                TS_HTTP_STATUS_NOT_IMPLEMENTED,
    +                                TS_HTTP_STATUS_BAD_GATEWAY,
    +                                TS_HTTP_STATUS_SERVICE_UNAVAILABLE,
    +                                TS_HTTP_STATUS_GATEWAY_TIMEOUT,
    +                                TS_HTTP_STATUS_HTTPVER_NOT_SUPPORTED,
    +                                TS_HTTP_STATUS_VARIANT_ALSO_NEGOTIATES,
    +                                TS_HTTP_STATUS_INSUFFICIENT_STORAGE,
    +                                TS_HTTP_STATUS_LOOP_DETECTED,
    +                                TS_HTTP_STATUS_NOT_EXTENDED,
    +                                TS_HTTP_STATUS_NETWORK_AUTHENTICATION_REQUIRED};
    +
    +static bool should_log(TSHttpTxn txnp);
    +static void log_request_line(TSMBuffer bufp, TSMLoc loc, const char *output_header);
    +static void log_response_status_line(TSMBuffer bufp, TSMLoc loc, const char *output_header);
    +static void log_headers(TSMBuffer bufp, TSMLoc loc, const char *output_header);
    +static void log_full_transaction(TSHttpTxn txnp);
    +static int log_requests_plugin(TSCont contp ATS_UNUSED, TSEvent event, void *edata);
    +
    +static bool
    +should_log(TSHttpTxn txnp)
    +{
    +  TSMBuffer txn_resp_bufp;
    +  TSMLoc txn_resp_loc;
    +  TSHttpStatus resp_status;
    +
    +  if (TSHttpTxnClientRespGet(txnp, &txn_resp_bufp, &txn_resp_loc) != TS_SUCCESS) {
    +    TSError("[log_requests] Couldn't retrieve server response header.");
    +    return false;
    +  }
    +
    +  // if resp_status is blacklisted, don't log
    +  resp_status = TSHttpHdrStatusGet(txn_resp_bufp, txn_resp_loc);
    +  for (int i = 0; i < blacklist_size; ++i) {
    +    if (resp_status == blacklist[i])
    +      return false;
    +  }
    --- End diff --
    
    Instead of the `for` loop this might be a bit cleaner. Although you should be using `std::vector` instead of raw int arrays.
    ```
    if (std::any_of(blacklist, blacklist+blacklist_size, [=] (int code) { return code == resp_status; }))
      return false;
    ```


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---