[ 
https://issues.apache.org/jira/browse/TS-4755?focusedWorklogId=26619&page=com.atlassian.jira.plugin.system.issuetabpanels:worklog-tabpanel#worklog-26619
 ]

ASF GitHub Bot logged work on TS-4755:
--------------------------------------

                Author: ASF GitHub Bot
            Created on: 18/Aug/16 23:53
            Start Date: 18/Aug/16 23:53
    Worklog Time Spent: 10m 
      Work Description: Github user SolidWallOfCode commented on a diff in the 
pull request:

    https://github.com/apache/trafficserver/pull/877#discussion_r75409617
  
    --- Diff: plugins/experimental/header_freq/header_freq.cc ---
    @@ -0,0 +1,260 @@
    +/** @file
    +
    +  This plugin counts the number of times every header has appeared.
    +  Maintains separate counts for client and origin headers.
    +
    +  @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 <iostream>
    +#include <map>
    +#include <sstream>
    +#include <stdlib.h>
    +#include <string.h>
    +#include <string>
    +#include <ts/ts.h>
    +
    +
    +// plugin registration info
    +static char plugin_name[]   = "header_freq";
    +static char vendor_name[]   = "Apache Software Foundation";
    +static char support_email[] = "[email protected]";
    +
    +// debug messages during one-time initialization
    +static const char DEBUG_TAG_INIT[] = "header_freq.init";
    +
    +// debug messages in continuation callbacks
    +static const char DEBUG_TAG_HOOK[] = "header_freq.hook";
    +
    +// maps from header name to # of times encountered
    +static std::map<std::string, unsigned int> client_freq;
    +static std::map<std::string, unsigned int> origin_freq;
    +
    +// for traffic_ctl, name is a convenient identifier
    +static const char *ctl_tag = plugin_name;
    +static const char *ctl_log = "log"; // log all data
    +
    +static TSMutex freq_mutex;          // lock on global data
    +static const int retry_time = 10;   // spin after TSMutexLockTry failures
    +
    +static const char *log_name = plugin_name;
    +static TSTextLogObject log;
    +
    +static bool
    +freq_lock_try(TSCont contp)
    +{
    +  if (TSMutexLockTry(freq_mutex) != TS_SUCCESS) {
    +    TSDebug(DEBUG_TAG_HOOK, "Unable to acquire lock. Retrying in %d "
    +                            "milliseconds", retry_time);
    +    TSContSchedule(contp, retry_time, TS_THREAD_POOL_DEFAULT);
    +    return false;
    +  }
    +  return true;
    +}
    +
    +/**
    + * Logs the data collected, first the client, and then
    + * the origin headers.
    + */
    +static void
    +log_frequencies()
    +{
    +  std::stringstream ss("");
    +
    +  ss << std::endl << std::string(100, '+') << std::endl;
    +
    +  ss << "CLIENT HEADERS" << std::endl;
    +  for (auto &elem: client_freq) {
    +    ss << elem.first << ": " << elem.second << std::endl;
    +  }
    +
    +  ss << std::endl;
    +
    +  ss << "ORIGIN HEADERS" << std::endl;
    +  for (auto &elem: origin_freq) {
    +    ss << elem.first << ": " << elem.second << std::endl;
    +  }
    +
    +  ss << std::string(100, '+') << std::endl;
    +  TSTextLogObjectWrite(log, "%s", ss.str().c_str());
    +}
    +
    +/**
    + * Records all headers found in the buffer in the map provided. Comparison
    + * against existing entries is case-insensitive.
    + */
    +static void
    +count_all_headers(TSMBuffer &bufp, TSMLoc &hdr_loc, std::map<std::string, 
unsigned int> &map)
    +{
    +  TSMLoc hdr, next_hdr;
    +  hdr = TSMimeHdrFieldGet(bufp, hdr_loc, 0);
    +  int n_headers = TSMimeHdrFieldsCount(bufp, hdr_loc);
    +  TSDebug(DEBUG_TAG_HOOK, "%d headers found", n_headers);
    +
    +  // iterate through all headers
    +  for (int i = 0; i < n_headers; ++i) {
    +    if (hdr == NULL)
    +      break;
    +    next_hdr = TSMimeHdrFieldNext(bufp, hdr_loc, hdr);
    +    int hdr_len;
    +    const char *hdr_name = TSMimeHdrFieldNameGet(bufp, hdr_loc, hdr, 
&hdr_len);
    +
    +    std::string str = std::string(hdr_name, hdr_len);
    +
    +    // make case-insensitive by converting to lowercase
    +    for (auto &c: str) {
    +      c = tolower(c);
    +    }
    +
    +    // count the header
    +    if (map.find(str) == map.end()) {
    +      // Not found.
    +      map[str] = 1;
    +     } else {
    +      // Found.
    +      ++map[str];
    +    }
    +
    +    TSHandleMLocRelease(bufp, hdr_loc, hdr);
    +    hdr = next_hdr;
    +  }
    +
    +  TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
    +}
    +
    +/**
    + * Continuation callback. Invoked to count headers on READ_REQUEST_HDR and
    + * SEND_RESPONSE_HDR hooks and to log through traffic_ctl's LIFECYCLE_MSG.
    + */
    +static int
    +handle_hook(TSCont contp, TSEvent event, void *edata)
    +{
    +  TSHttpTxn txnp;
    +  TSMBuffer bufp;
    +  TSMLoc hdr_loc;
    +  int ret_val = 0;
    +
    +  // Treats the handler as a critical section because all events touch 
global
    +  // data
    +  if (!freq_lock_try(contp)) {
    +    ret_val = -1;
    +    return ret_val;
    +  }
    +
    +  switch(event){
    +  case TS_EVENT_HTTP_READ_REQUEST_HDR: // count client headers
    +    {
    +      TSDebug(DEBUG_TAG_HOOK, "event TS_EVENT_HTTP_READ_REQUEST_HDR");
    +      txnp = reinterpret_cast<TSHttpTxn>(edata);
    +      // get the client request so we can loop through the headers
    +      if (TSHttpTxnClientReqGet(txnp, &bufp, &hdr_loc) != TS_SUCCESS) {
    +        TSError("(%s) could not get request headers", plugin_name);
    +        TSHttpTxnReenable(txnp, TS_EVENT_HTTP_ERROR);
    +        ret_val = -2;
    +        break;
    +      }
    +      count_all_headers(bufp, hdr_loc, client_freq);
    +      TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
    +    }
    +    break;
    +  case TS_EVENT_HTTP_SEND_RESPONSE_HDR: // count origin headers
    +    {
    +      TSDebug(DEBUG_TAG_HOOK, "event TS_EVENT_HTTP_SEND_RESPONSE_HDR");
    +      // get the response so we can loop through the headers
    +      txnp = reinterpret_cast<TSHttpTxn>(edata);
    +      if (TSHttpTxnClientRespGet(txnp, &bufp, &hdr_loc) != TS_SUCCESS) {
    +        TSError("(%s) could not get response headers", plugin_name);
    +        TSHttpTxnReenable(txnp, TS_EVENT_HTTP_ERROR);
    +        ret_val = -3;
    +        break;
    +      }
    +      count_all_headers(bufp, hdr_loc, origin_freq);
    +      TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
    +    }
    +    break;
    +  case TS_EVENT_LIFECYCLE_MSG:
    +    {
    +      TSDebug(DEBUG_TAG_HOOK, "event TS_EVENT_LIFECYCLE_MSG");
    +      TSPluginMsg* msgp = reinterpret_cast<TSPluginMsg*>(edata);
    +
    +      if (strcmp(ctl_tag, msgp->tag))
    +        {
    +          TSDebug(DEBUG_TAG_HOOK, "tag %s does not concern us", msgp->tag);
    +          break;
    +        }
    +
    +      // identify the command
    +      if (strncmp(ctl_log, reinterpret_cast<const char*>(msgp->data),
    +          strlen(ctl_log)) == 0) {
    +        log_frequencies();
    +      }
    +
    +    }
    +    break;
    +  // do nothing in any of the other states
    +  default:
    +    break;
    +  }
    +
    +  TSMutexUnlock(freq_mutex);
    +  return ret_val;
    +}
    +
    +/**
    + * Entry point for the plugin.
    + */
    +void
    +TSPluginInit(int argc, const char *argv[])
    +{
    +  TSDebug(DEBUG_TAG_INIT, "initializing plugin");
    +
    +  TSPluginRegistrationInfo info;
    +
    +  info.plugin_name = plugin_name;
    +  info.vendor_name = vendor_name;
    +  info.support_email = support_email;
    +
    +  if (TSPluginRegister(&info) != TS_SUCCESS) {
    +    TSError("[%s](%s) Plugin registration failed. \n", plugin_name,
    +    __FUNCTION__);
    +  }
    +  
    +  TSDebug(DEBUG_TAG_INIT, "initializing log with name %s", log_name);
    +  if (TSTextLogObjectCreate(log_name, TS_LOG_MODE_ADD_TIMESTAMP, &log) !=
    +      TS_SUCCESS) {
    +    // Log initialization failed. Unrecoverable, report and exit.
    +    TSError("(%s)[%s] could not initialize log with name %s", plugin_name,
    +            __FUNCTION__, log_name);
    +    abort();
    --- End diff --
    
    Probably shouldn't abort - just generate the warning.


Issue Time Tracking
-------------------

    Worklog Id:     (was: 26619)
    Time Spent: 1h 10m  (was: 1h)

> Create a plugin that would count the frequency of headers
> ---------------------------------------------------------
>
>                 Key: TS-4755
>                 URL: https://issues.apache.org/jira/browse/TS-4755
>             Project: Traffic Server
>          Issue Type: Improvement
>          Components: Plugins
>            Reporter: Bryan Call
>            Assignee: Petar Penkov
>             Fix For: 7.2.0
>
>          Time Spent: 1h 10m
>  Remaining Estimate: 0h
>
> Create a plugin that would count the frequency of headers.  Have separate 
> frequency counters for origin and client.



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)

Reply via email to