> On Oct 30, 2014, at 2:38 PM, sudhe...@apache.org wrote:
> 
> Repository: trafficserver
> Updated Branches:
>  refs/heads/master 35a71e919 -> e49344c15
> 
> 
> [TS-2683]: Enhance the bg fetch plugin to support specifyng various exclusion 
> criteria
> 
> 
> Project: http://git-wip-us.apache.org/repos/asf/trafficserver/repo
> Commit: http://git-wip-us.apache.org/repos/asf/trafficserver/commit/e49344c1
> Tree: http://git-wip-us.apache.org/repos/asf/trafficserver/tree/e49344c1
> Diff: http://git-wip-us.apache.org/repos/asf/trafficserver/diff/e49344c1
> 
> Branch: refs/heads/master
> Commit: e49344c152cd7ff7eb92c38f00f76c6f7179a8d1
> Parents: 35a71e9
> Author: Sudheer Vinukonda <sudhe...@yahoo-inc.com>
> Authored: Thu Oct 30 21:36:12 2014 +0000
> Committer: Sudheer Vinukonda <sudhe...@yahoo-inc.com>
> Committed: Thu Oct 30 21:36:12 2014 +0000
> 
> ----------------------------------------------------------------------
> doc/reference/plugins/background_fetch.en.rst   |  16 +-
> .../background_fetch/background_fetch.cc        | 183 ++++++++++++++++++-
> 2 files changed, 192 insertions(+), 7 deletions(-)
> ----------------------------------------------------------------------
> 
> 
> http://git-wip-us.apache.org/repos/asf/trafficserver/blob/e49344c1/doc/reference/plugins/background_fetch.en.rst
> ----------------------------------------------------------------------
> diff --git a/doc/reference/plugins/background_fetch.en.rst 
> b/doc/reference/plugins/background_fetch.en.rst
> index 3df7d3c..8465045 100644
> --- a/doc/reference/plugins/background_fetch.en.rst
> +++ b/doc/reference/plugins/background_fetch.en.rst
> @@ -58,6 +58,21 @@ original client request, which continues as normal.
> Only one background fetch per URL is ever performed, making sure we do not
> accidentally put pressure on the origin servers.
> 
> +The plugin now supports a config file that can specify exclusion of 
> background
> +fetch based on the below criteria:
> +1. Client-Ip
> +2. Content-Type
> +3. User-Agent
> +
> +To specify the exclusion criteria, the plugin needs to be activated as below:
> +
> +background_fetch.so --config <relative-path-to-install-dir/config-file>

A general comment ... "--config" implies a general plugin configuration, but 
this is actually a list of exclusions. Since that's the case, I suggest the 
option be called "--exclusions", or the config file format be modified to be 
able to express more than a single list.

> +
> +The contents of the config-file could be as below:
> +
> +Client-Ip 127.0.0.1

This should be Client-IP

> +User-Agent ABCDEF
> +Content-Type text
> 
> 
> Future additions
> @@ -66,7 +81,6 @@ Future additions
> The infrastructure is in place for providing global and per-remap
> configurations. This could include:
> 
> -- Limiting the background fetches to certain Content-Types
> - Limiting the background fetches to content of certain sizes
> 
> 
> 
> http://git-wip-us.apache.org/repos/asf/trafficserver/blob/e49344c1/plugins/experimental/background_fetch/background_fetch.cc
> ----------------------------------------------------------------------
> diff --git a/plugins/experimental/background_fetch/background_fetch.cc 
> b/plugins/experimental/background_fetch/background_fetch.cc
> index 4c18a4b..f6a3e0e 100644
> --- a/plugins/experimental/background_fetch/background_fetch.cc
> +++ b/plugins/experimental/background_fetch/background_fetch.cc
> @@ -34,6 +34,7 @@
> #include "ts/ts.h"
> #include "ts/remap.h"
> #include "ink_defs.h"
> +#include <set>
> 
> 
> // Some wonkiness around compiler version and the unordered map (hash)
> @@ -48,6 +49,80 @@
> // Constants
> const char PLUGIN_NAME[] = "background_fetch";
> 
> +typedef std::set<std::string> stringSet;
> +
> +static  stringSet contentTypeSet;
> +static  stringSet userAgentSet;
> +static  stringSet clientIpSet;
> +
> +static
> +bool read_config(char* config_file) {
> +  char file_path[1024];
> +  TSFile file;
> +  if (config_file == NULL) {
> +    TSError("invalid config file");
> +    return false;
> +  }
> +  snprintf(file_path, sizeof(file_path), "%s/%s", TSInstallDirGet(), 
> config_file);

This needs to test for an absolute path. An absolute path should be used 
directly; a relative path must be relative to TSConfigDirGet().

> +
> +  TSDebug(PLUGIN_NAME, "trying to open config file in this path: %s", 
> file_path);
> +
> +  file = TSfopen(file_path, "r");
> +  if (file == NULL) {
> +    TSError("Failed to open config file %s", config_file);
> +    return 0;

s/0/false/

> +  }
> +
> +  char buffer[1024];
> +  memset(buffer, 0, sizeof(buffer));
> +  while (TSfgets(file, buffer, sizeof(buffer) - 1) != NULL) {
> +    char *eol = 0;
> +    // make sure line was not bigger than buffer
> +    if ((eol = strchr(buffer, '\n')) == NULL && (eol = strstr(buffer, 
> "\r\n")) == NULL) {

Huh? DOS line endings?

> +      TSError("sni_proto_nego line too long, did not get a good line in cfg, 
> skipping, line: %s", buffer);
> +      memset(buffer, 0, sizeof(buffer));
> +      continue;
> +    }
> +    // make sure line has something useful on it
> +    if (eol - buffer < 2 || buffer[0] == '#') {
> +      memset(buffer, 0, sizeof(buffer));
> +      continue;
> +    }
> +    char* cfg = strtok(buffer, "\n\r\n");

This is just doing *eol = '\0', right?

> +
> +    if (cfg != NULL) {
> +        TSDebug(PLUGIN_NAME, "setting background_fetch exclusion criterion 
> based on string: %s", cfg);
> +
> +        char* cfg_type = strtok(buffer, " ");

strtok_r

> +
> +        char* cfg_value = NULL;
> +        if (cfg_type) {
> +          cfg_value = strtok(NULL, " ");
> +        }
> +
> +        if (cfg_type && cfg_value) {
> +          if (!strcmp(cfg_type, "Content-Type")) {
> +            TSDebug(PLUGIN_NAME, "adding content-type %s", cfg_value);
> +            contentTypeSet.insert(cfg_value);
> +          } else if (!strcmp(cfg_type, "User-Agent")) {
> +            TSDebug(PLUGIN_NAME, "adding user-agent %s", cfg_value);
> +            userAgentSet.insert(cfg_value);
> +          } else if (!strcmp(cfg_type, "Client-Ip")) {
> +            TSDebug(PLUGIN_NAME, "adding client-ip %s", cfg_value);
> +            clientIpSet.insert(cfg_value);
> +          }
> +        }
> +
> +        memset(buffer, 0, sizeof(buffer));
> +    }
> +  }
> +
> +  TSfclose(file);
> +
> +  TSDebug(PLUGIN_NAME, "Done parsing config");
> +
> +  return 1;

s/1/true/

> +}
> 
> ///////////////////////////////////////////////////////////////////////////
> // Remove a header (fully) from an TSMLoc / TSMBuffer. Return the number
> @@ -542,12 +617,106 @@ cont_check_cacheable(TSCont contp, TSEvent /* event 
> ATS_UNUSED */, void* edata)
>   return 0;
> }
> 
> +static bool
> +check_hdr_configured(TSMBuffer hdr_bufp, TSMLoc req_hdrs, const char* 
> field_type, int field_len, stringSet* cfg_set)
> +{
> +  bool hdr_found = false;
> +
> +  TSMLoc loc = TSMimeHdrFieldFind(hdr_bufp, req_hdrs, field_type, field_len);
> +
> +  if (TS_NULL_MLOC != loc) {
> +    int val_len = 0;
> +    const char *val_str = TSMimeHdrFieldValueStringGet(hdr_bufp, req_hdrs, 
> loc, 0, &val_len);
> +    if (!val_str || val_len <= 0) {
> +      TSDebug(PLUGIN_NAME,"invalid content type");
> +    } else {
> +      stringSet::iterator it = cfg_set->begin();
> +      while(it!=cfg_set->end()) {
> +        TSDebug(PLUGIN_NAME, "comparing with %s", (*it).c_str());
> +        if (NULL != strstr(val_str, (*it).c_str())) {
> +          TSDebug(PLUGIN_NAME,"excluding bg fetch for configured field %s", 
> (*it).c_str());
> +          hdr_found = true;
> +          break;
> +        }
> +        it++;
> +      }
> +      TSHandleMLocRelease(hdr_bufp, req_hdrs, loc);
> +    }
> +  } else {
> +    TSDebug(PLUGIN_NAME, "no field %s in request header", field_type);
> +  }
> +  return hdr_found;
> +}
> +
> +static bool
> +is_background_fetch_allowed(TSHttpTxn txnp)
> +{
> +  bool allow_bg_fetch = true;
> +  TSDebug(PLUGIN_NAME, "Testing: request is internal?");
> +  if (TSHttpIsInternalRequest(txnp) == TS_SUCCESS) {
> +    return false;
> +  }
> +
> +  const sockaddr* client_ip = TSHttpTxnClientAddrGet(txnp);
> +  char* ip_buf = NULL;
> +
> +  if(AF_INET == client_ip->sa_family) {
> +    ip_buf = (char *) TSmalloc(INET_ADDRSTRLEN);
> +    inet_ntop(AF_INET, &(reinterpret_cast<const 
> sockaddr_in*>(client_ip)->sin_addr), ip_buf, INET_ADDRSTRLEN);
> +  } else if(AF_INET6 == client_ip->sa_family) {
> +    ip_buf = (char *) TSmalloc(INET6_ADDRSTRLEN);
> +    inet_ntop(AF_INET6, &(reinterpret_cast<const 
> sockaddr_in6*>(client_ip)->sin6_addr), ip_buf, INET6_ADDRSTRLEN);
> +  }

Why do you malloc here? Just use a stack buffer of INET6_ADDRSTRLEN bytes ... 
Actually it would be better to reverse this by converting the config string to 
a sockaddr and just doing a sockaddr memcmp below ..

> +
> +  if (ip_buf) {
> +    TSDebug(PLUGIN_NAME,"client_ip %s", ip_buf);
> +    stringSet::iterator it = clientIpSet.begin();
> +    while(it!=clientIpSet.end()) {

What is wrong with a conventional for loop, like

        for (stringSet::iterator it = clientIpSet.begin(); 
it!=clientIpSet.end(); ++i)

> +      if (NULL != strstr(ip_buf, (*it).c_str())) {

Oh, you do strstr(). So if the config file had "Client-IP 17" and the client 
came from "120.0.0.17" or "168.19.17.1", this would exclude the background 
fetch?

> +        TSDebug(PLUGIN_NAME,"excluding bg fetch for ip %s, configured ip 
> %s", ip_buf, (*it).c_str());
> +        allow_bg_fetch = false;
> +        break;
> +      }
> +      it++;
> +    }
> +    TSfree(ip_buf);
> +    if (!allow_bg_fetch) {
> +      return false;
> +    }
> +  } else {
> +    TSError ("invalid client ip");
> +  }
> +
> +  TSMBuffer hdr_bufp;
> +  TSMLoc req_hdrs;
> +
> +  if (TSHttpTxnClientReqGet(txnp, &hdr_bufp, &req_hdrs) == TS_SUCCESS) {
> +    if (check_hdr_configured (hdr_bufp, req_hdrs, 
> TS_MIME_FIELD_CONTENT_TYPE, TS_MIME_LEN_CONTENT_TYPE, &contentTypeSet)) {
> +      TSDebug(PLUGIN_NAME, "found content-type match");
> +      allow_bg_fetch = false;
> +      goto done;
> +    }
> +    if (check_hdr_configured (hdr_bufp, req_hdrs, TS_MIME_FIELD_USER_AGENT, 
> TS_MIME_LEN_USER_AGENT, &userAgentSet)) {
> +      TSDebug(PLUGIN_NAME, "found user-agent match");
> +      allow_bg_fetch = false;
> +      goto done;
> +    }
> +  } else {
> +    // something wrong..
> +    TSError ("Failed to get req headers");

TSError messages should include the plugin name otherwise they are impossible 
to track down

> +    return false;
> +  }
> +
> +  done:
> +  TSHandleMLocRelease(hdr_bufp, TS_NULL_MLOC, req_hdrs);
> +  return allow_bg_fetch;
> +}
> 
> //////////////////////////////////////////////////////////////////////////////
> // Main "plugin", which is a global READ_RESPONSE_HDR hook. Before
> // initiating a background fetch, this checks:
> //
> -//     1. Is this an internal request? This avoid infinite loops...
> +//     1. Check if a background fetch is allowed for this request
> // and
> //     2. Is the response from origin a 206 (Partial)?
> //
> @@ -560,9 +729,7 @@ cont_handle_response(TSCont /* contp ATS_UNUSED */, 
> TSEvent /* event ATS_UNUSED
>   // ToDo: If we want to support per-remap configurations, we have to pass 
> along the data here
>   TSHttpTxn txnp = static_cast<TSHttpTxn>(edata);
> 
> -  // 1. Make sure it's not an internal request first.
> -  TSDebug(PLUGIN_NAME, "Testing: request is internal?");
> -  if (TSHttpIsInternalRequest(txnp) != TS_SUCCESS) {
> +  if (is_background_fetch_allowed(txnp)) {
>     TSMBuffer response;
>     TSMLoc resp_hdr;
> 
> @@ -597,6 +764,7 @@ TSPluginInit(int argc, const char* argv[])
>   TSPluginRegistrationInfo info;
>   static const struct option longopt[] = {
>     { const_cast<char *>("log"), required_argument, NULL, 'l' },
> +    { const_cast<char *>("config"), required_argument, NULL, 'c' },
>     { NULL, no_argument, NULL, '\0' }
>   };
> 
> @@ -612,12 +780,16 @@ TSPluginInit(int argc, const char* argv[])
>   optind = 1;
> 
>   while (true) {
> -    int opt = getopt_long(argc, (char * const *)argv, "l", longopt, NULL);
> +    int opt = getopt_long(argc, (char * const *)argv, "lc", longopt, NULL);
> 
>     switch (opt) {
>     case 'l':
>       gConfig->create_log(optarg);
>       break;
> +    case 'c':
> +      TSDebug(PLUGIN_NAME, "config file %s..", optarg);
> +      read_config(optarg);
> +      break;
>     }
> 
>     if (opt == -1) {
> @@ -625,7 +797,6 @@ TSPluginInit(int argc, const char* argv[])
>     }
>   }
> 
> -
>   TSDebug(PLUGIN_NAME, "Initialized");
>   TSHttpHookAdd(TS_HTTP_READ_RESPONSE_HDR_HOOK, 
> TSContCreate(cont_handle_response, NULL));
> }
> 

Reply via email to