You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by zw...@apache.org on 2010/11/04 22:52:27 UTC

svn commit: r1031274 - in /trafficserver/plugins/header_filter: ./ header_filter.cc lulu.h rules.cc rules.h

Author: zwoop
Date: Thu Nov  4 21:52:26 2010
New Revision: 1031274

URL: http://svn.apache.org/viewvc?rev=1031274&view=rev
Log:
Plugin to delete filters in various hook, or as a remap plugin

Added:
    trafficserver/plugins/header_filter/
    trafficserver/plugins/header_filter/header_filter.cc
    trafficserver/plugins/header_filter/lulu.h
    trafficserver/plugins/header_filter/rules.cc
    trafficserver/plugins/header_filter/rules.h

Added: trafficserver/plugins/header_filter/header_filter.cc
URL: http://svn.apache.org/viewvc/trafficserver/plugins/header_filter/header_filter.cc?rev=1031274&view=auto
==============================================================================
--- trafficserver/plugins/header_filter/header_filter.cc (added)
+++ trafficserver/plugins/header_filter/header_filter.cc Thu Nov  4 21:52:26 2010
@@ -0,0 +1,198 @@
+//////////////////////////////////////////////////////////////////////////////////////////////
+// 
+// Main entry points for the plugin hooks etc.
+//
+#include <ts/ts.h>
+#include <ts/remap.h>
+#include <stdio.h>
+
+#include "rules.h"
+
+using namespace ::HeaderFilter;
+
+// Global plugin rules
+Rules global;
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Continuation
+//
+static int
+cont_header_filter(INKCont contp, INKEvent event, void *edata)
+{
+  INKHttpTxn txnp = (INKHttpTxn) edata;
+  INKHttpHookID hook = INK_HTTP_LAST_HOOK;
+  INKMBuffer reqp;
+  INKMLoc hdr_loc;
+
+  // Get the resources necessary to process this event
+  switch (event) {
+  case INK_EVENT_HTTP_READ_REQUEST_HDR:
+    if (INKHttpTxnClientReqGet(txnp, &reqp, &hdr_loc))
+      hook = INK_HTTP_READ_REQUEST_HDR_HOOK;
+    break;
+  case INK_EVENT_HTTP_SEND_REQUEST_HDR:
+    if (INKHttpTxnServerReqGet(txnp, &reqp, &hdr_loc))
+      hook = INK_HTTP_SEND_REQUEST_HDR_HOOK;
+    break;
+  case INK_EVENT_HTTP_READ_RESPONSE_HDR:
+    if (INKHttpTxnServerRespGet(txnp, &reqp, &hdr_loc))
+      hook = INK_HTTP_READ_RESPONSE_HDR_HOOK;
+    break;
+  case INK_EVENT_HTTP_SEND_RESPONSE_HDR:
+    if (INKHttpTxnClientRespGet(txnp, &reqp, &hdr_loc))
+      hook = INK_HTTP_SEND_RESPONSE_HDR_HOOK;
+    break;
+  default:
+    INKError("header_rewrite: unknown event for this plugin");
+    INKDebug(PLUGIN_NAME, "unknown event for this plugin");
+    break;
+  }
+
+  if (hook != INK_HTTP_LAST_HOOK) {
+    Rules* from_remap;
+
+    global.execute(reqp, hdr_loc, hook);
+
+    if (INK_HTTP_READ_REQUEST_HDR_HOOK != hook) { // Don't run the hook handled by remap plugin
+      if (INK_SUCCESS == INKHttpTxnGetArg(txnp, 0, (void**)(&from_remap)) && from_remap)
+        from_remap->execute(reqp, hdr_loc, hook);
+    }
+
+    INKHandleMLocRelease(reqp, INK_NULL_MLOC, hdr_loc);
+  }
+
+  INKHttpTxnReenable(txnp, INK_EVENT_HTTP_CONTINUE);
+  return 0;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Initialize the InkAPI plugin for the global hooks we support.
+//
+void
+INKPluginInit(int argc, const char *argv[])
+{
+  INKPluginRegistrationInfo info;
+
+  info.plugin_name = const_cast<char*>(PLUGIN_NAME);
+  info.vendor_name = const_cast<char*>("Apache");
+  info.support_email = const_cast<char*>("users@trafficserver.apache.org");
+
+  if (!INKPluginRegister(INK_SDK_VERSION_2_0 , &info)) {
+    INKError("header_rewrite: plugin registration failed.\n"); 
+  }
+
+  if (argc != 2) {
+    INKError("usage: %s <config-file>\n", argv[0] );
+  }
+
+  // Parse the rules file
+  if (global.parse_file(argv[1])) {
+    INKCont cont = INKContCreate(cont_header_filter, NULL);
+
+    for (int i=INK_HTTP_READ_REQUEST_HDR_HOOK; i < INK_HTTP_LAST_HOOK; ++i) {
+      if (global.supported_hook(static_cast<INKHttpHookID>(i))) {
+        INKHttpHookAdd(static_cast<INKHttpHookID>(i), cont);
+      }
+    }
+  } else {
+    INKError("header_rewrite: failed to parse configuration file");
+  }
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Initialize the plugin as a remap plugin.
+//
+int
+tsremap_init(TSRemapInterface* api_info, char *errbuf, int errbuf_size)
+{
+  if (!api_info) {
+    strncpy(errbuf, "[tsremap_init] - Invalid TSRemapInterface argument", errbuf_size - 1);
+    return -1;
+  }
+
+  if (api_info->size < sizeof(TSRemapInterface)) {
+    strncpy(errbuf, "[tsremap_init] - Incorrect size of TSRemapInterface structure", errbuf_size - 1);
+    return -2;
+  }
+
+  if (api_info->tsremap_version < TSREMAP_VERSION) {
+    snprintf(errbuf, errbuf_size - 1, "[tsremap_init] - Incorrect API version %ld.%ld",
+             api_info->tsremap_version >> 16, (api_info->tsremap_version & 0xffff));
+    return -3;
+  }
+
+  INKDebug(PLUGIN_NAME, "remap plugin is succesfully initialized");
+  return 0;                     /* success */
+}
+
+
+int
+tsremap_new_instance(int argc, char* argv[], ihandle* ih, char* errbuf, int errbuf_size)
+{
+  if (argc < 3) {
+    INKError("Unable to create remap instance, need rules file");
+    return -1;
+  } else {
+    Rules* conf = new(Rules);
+
+    // TODO: Should deal with "inline" parameters here (in remap.config), e.g.
+    // @plugin=header_filter.so @pparam=READ_REQUEST_HDR @pparam=X-From-Me @pparam=X-From-Someone ...
+    conf->parse_file(argv[2]);
+    *ih = static_cast<ihandle>(conf);
+  }
+
+  return 0;
+}
+
+void
+tsremap_delete_instance(ihandle ih)
+{
+  Rules* conf = static_cast<Rules*>(ih);
+
+  delete conf;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Main entry point when used as a remap plugin.
+//
+int
+tsremap_remap(ihandle ih, rhandle rh, TSRemapRequestInfo *rri)
+{
+  if (NULL == ih) {
+    INKDebug(PLUGIN_NAME, "No Rules configured, falling back to default mapping rule");
+    return 0;
+  } else {
+    Rules* confp = static_cast<Rules*>(ih);
+    INKHttpTxn txnp = static_cast<INKHttpTxn>(rh);
+    INKMBuffer reqp;
+    INKMLoc hdr_loc;
+
+    INKHttpTxnSetArg(txnp, 0, static_cast<void*>(ih)); // Save for later hooks
+    if (INKHttpTxnClientReqGet(txnp, &reqp, &hdr_loc)) {
+      confp->execute(reqp, hdr_loc, INK_HTTP_READ_REQUEST_HDR_HOOK);
+      INKHandleMLocRelease(reqp, INK_NULL_MLOC, hdr_loc);
+    }
+  }
+
+  return 1;
+}
+
+
+/*
+  local variables:
+  mode: C++
+  indent-tabs-mode: nil
+  c-basic-offset: 2
+  c-comment-only-line-offset: 0
+  c-file-offsets: ((statement-block-intro . +)
+  (label . 0)
+  (statement-cont . +)
+  (innamespace . 0))
+  end:
+
+  Indent with: /usr/bin/indent -ncs -nut -npcs -l 120 logstats.cc
+*/

Added: trafficserver/plugins/header_filter/lulu.h
URL: http://svn.apache.org/viewvc/trafficserver/plugins/header_filter/lulu.h?rev=1031274&view=auto
==============================================================================
--- trafficserver/plugins/header_filter/lulu.h (added)
+++ trafficserver/plugins/header_filter/lulu.h Thu Nov  4 21:52:26 2010
@@ -0,0 +1,89 @@
+//////////////////////////////////////////////////////////////////////////////////////////////
+// 
+// Implement the classes for the various types of hash keys we support.
+//
+#ifndef __LULU_H__
+#define __LULU_H__ 1
+
+// Define UNUSED properly.
+#if ((__GNUC__ >= 3) || ((__GNUC__ == 2) && (__GNUC_MINOR__ >= 7)))
+#define UNUSED __attribute__ ((unused))
+#else
+#define UNUSED
+#endif /* #if ((__GNUC__ >= 3) || ((__GNUC__ == 2) && (__GNUC_MINOR__ >= 7))) */
+
+#include <sys/types.h>
+
+// Memory barriers on i386 / linux / gcc
+#if defined(__i386__)
+#define mb()  __asm__ __volatile__ ( "lock; addl $0,0(%%esp)" : : : "memory" )
+#define rmb() __asm__ __volatile__ ( "lock; addl $0,0(%%esp)" : : : "memory" )
+#define wmb() __asm__ __volatile__ ( "" : : : "memory")
+#elif defined(__x86_64__)
+#define mb()  __asm__ __volatile__ ( "mfence" : : : "memory")
+#define rmb() __asm__ __volatile__ ( "lfence" : : : "memory")
+#define wmb() __asm__ __volatile__ ( "" : : : "memory")
+#else
+#error "Define barriers"
+#endif
+
+// Used for Debug etc.
+static const char* PLUGIN_NAME = "header_filter";
+static const char* PLUGIN_NAME_DBG = "header_filter_dbg";
+
+
+// From the atomic portions of ATS
+typedef int int32;
+typedef unsigned int intu32;
+typedef long long int64;
+typedef unsigned long long intu64;
+
+typedef volatile int32 vint32;
+typedef volatile int64 vint64;
+typedef volatile void *vvoidp;
+typedef vint32 *pvint32;
+typedef vint64 *pvint64;
+typedef vvoidp *pvvoidp;
+
+#if defined(__GNUC__) && (__GNUC__ >= 4) && (__GNUC_MINOR__ >= 1)
+
+/* see http://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Atomic-Builtins.html */
+static inline int32 ink_atomic_swap(pvint32 mem, int32 value) { return __sync_lock_test_and_set(mem, value); }
+static inline int64 ink_atomic_swap64(pvint64 mem, int64 value) { return __sync_lock_test_and_set(mem, value); }
+static inline void *ink_atomic_swap_ptr(vvoidp mem, void *value) { return __sync_lock_test_and_set((void**)mem, value); }
+static inline int ink_atomic_cas(pvint32 mem, int old, int new_value) { return __sync_bool_compare_and_swap(mem, old, new_value); }
+static inline int64 ink_atomic_cas64(pvint64 mem, int64 old, int64 new_value) { return __sync_bool_compare_and_swap(mem, old, new_value); }
+static inline int ink_atomic_cas_ptr(pvvoidp mem, void* old, void* new_value) { return __sync_bool_compare_and_swap(mem, old, new_value); }
+static inline int ink_atomic_increment(pvint32 mem, int value) { return __sync_fetch_and_add(mem, value); }
+static inline int64 ink_atomic_increment64(pvint64 mem, int64 value) { return __sync_fetch_and_add(mem, value); }
+static inline void *ink_atomic_increment_ptr(pvvoidp mem, intptr_t value) { return __sync_fetch_and_add((void**)mem, value); }
+#else
+// TODO: Deal with this case?
+#failure
+#endif
+
+
+// From google styleguide: http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml
+#define DISALLOW_COPY_AND_ASSIGN(TypeName)      \
+  TypeName(const TypeName&);                    \
+  void operator=(const TypeName&)
+
+
+#endif // __LULU_H__
+
+
+
+/*
+  local variables:
+  mode: C++
+  indent-tabs-mode: nil
+  c-basic-offset: 2
+  c-comment-only-line-offset: 0
+  c-file-offsets: ((statement-block-intro . +)
+  (label . 0)
+  (statement-cont . +)
+  (innamespace . 0))
+  end:
+
+  Indent with: /usr/bin/indent -ncs -nut -npcs -l 120 logstats.cc
+*/

Added: trafficserver/plugins/header_filter/rules.cc
URL: http://svn.apache.org/viewvc/trafficserver/plugins/header_filter/rules.cc?rev=1031274&view=auto
==============================================================================
--- trafficserver/plugins/header_filter/rules.cc (added)
+++ trafficserver/plugins/header_filter/rules.cc Thu Nov  4 21:52:26 2010
@@ -0,0 +1,139 @@
+//////////////////////////////////////////////////////////////////////////////////////////////
+// 
+// Implemenation details for the rules class.
+//
+#include <fstream>
+#include <ts/ts.h>
+
+#include "rules.h"
+
+namespace HeaderFilter {
+
+// RulesEntry implementations
+void
+RulesEntry::append(RulesEntry* entry)
+{
+  RulesEntry* n = this;
+
+  while (NULL != n->_next)
+    n = n->_next;
+  n->_next = entry;
+}
+
+void
+RulesEntry::execute(INKMBuffer& reqp, INKMLoc& hdr_loc)
+{
+  INKMLoc field, tmp;
+  RulesEntry* n = this;
+
+  while (n) {
+    field = INKMimeHdrFieldFind(reqp, hdr_loc, n->_header, n->_len);
+    while (field) {
+      INKDebug(PLUGIN_NAME, "\tDeleting header %.*s", n->_len, n->_header);
+      tmp = INKMimeHdrFieldNextDup(reqp, hdr_loc, field);
+      INKMimeHdrFieldDestroy(reqp, hdr_loc, field);
+      INKHandleMLocRelease(reqp, hdr_loc, field);
+      field = tmp;
+    }
+    n = n->_next;
+  }
+}
+
+
+// Rules class implementations
+Rules::~Rules()
+{
+  INKDebug(PLUGIN_NAME_DBG, "Calling DTOR for Rules");
+
+  for (int i = 0; i < INK_HTTP_LAST_HOOK; ++i) {
+    if (_entries[i])
+      delete _entries[i];
+  }
+}
+
+RulesEntry*
+Rules::add_entry(const INKHttpHookID hook, const std::string& s)
+{
+  RulesEntry* e = new(RulesEntry)(s);
+
+  INKAssert(supported_hook(hook));
+  if (NULL == _entries[hook]) {
+    _entries[hook] = e;
+  } else {
+    _entries[hook]->append(e);
+  }
+  
+  return e;
+}
+
+bool
+Rules::parse_file(const char* filename)
+{
+  std::ifstream f;
+  INKHttpHookID hook = INK_HTTP_READ_REQUEST_HDR_HOOK;
+  int lineno = 0;
+
+  // TODO: Should we support a 'default' prefix here for the ruless?
+  f.open(filename, std::ios::in);
+  if (!f.is_open()) {
+    INKError("unable to open %s", filename);
+    return false;
+  }
+  INKDebug(PLUGIN_NAME, "Parsing config file %s", filename);
+  while (!f.eof()) {
+    std::string line, word;
+    std::string::size_type pos1, pos2;
+
+    getline(f, line);
+    ++lineno;
+    if (line.empty())
+      continue;
+
+    pos1 = line.find_first_not_of(" \t\n");
+    if (pos1 != std::string::npos) {
+      if (line[pos1] == '#') {
+        continue; // Skip comments
+      } else {
+        pos2 = line.find_first_of("# \t\n", pos1); // End of line
+        if (pos2 == std::string::npos)
+          pos2 = line.length();
+        word = line.substr(pos1, pos2-pos1);
+
+        if (word == "READ_REQUEST_HDR:") {
+          hook = INK_HTTP_READ_REQUEST_HDR_HOOK;
+        } else if (word == "SEND_REQUEST_HDR:") {
+          hook = INK_HTTP_SEND_REQUEST_HDR_HOOK;
+        } else if (word == "READ_RESPONSE_HDR:") {
+          hook = INK_HTTP_READ_RESPONSE_HDR_HOOK;
+        } else if (word == "SEND_RESPONSE_HDR:") {
+          hook = INK_HTTP_SEND_RESPONSE_HDR_HOOK;
+        } else { // Assume it's a header name for everything else
+          if (!word.empty()) {
+            INKDebug(PLUGIN_NAME, "Adding %s to hook %d", word.c_str(), hook);
+            add_entry(hook, word);
+          }
+        }
+      }
+    }
+  }
+
+  return true;
+}
+
+} // End of namespace ::HeaderFilter
+
+
+/*
+  local variables:
+  mode: C++
+  indent-tabs-mode: nil
+  c-basic-offset: 2
+  c-comment-only-line-offset: 0
+  c-file-offsets: ((statement-block-intro . +)
+  (label . 0)
+  (statement-cont . +)
+  (innamespace . 0))
+  end:
+
+  Indent with: /usr/bin/indent -ncs -nut -npcs -l 120 logstats.cc
+*/

Added: trafficserver/plugins/header_filter/rules.h
URL: http://svn.apache.org/viewvc/trafficserver/plugins/header_filter/rules.h?rev=1031274&view=auto
==============================================================================
--- trafficserver/plugins/header_filter/rules.h (added)
+++ trafficserver/plugins/header_filter/rules.h Thu Nov  4 21:52:26 2010
@@ -0,0 +1,103 @@
+//////////////////////////////////////////////////////////////////////////////////////////////
+// 
+// Class for holding a set of configurations. There would be one global configuration, used
+// by all hooks / requests, and one optional configuration for each remap rule.
+//
+#ifndef __RULES_H__
+#define __RULES_H__ 1
+
+#include <string>
+#include <string.h>
+#include <ts/ts.h>
+#include "lulu.h"
+
+namespace HeaderFilter {
+
+class RulesEntry
+{
+public:
+  RulesEntry(const std::string& s)
+    : _header(NULL), _len(0), _next(NULL)
+  {
+    _header = INKstrdup(s.c_str());
+    _len = s.length();
+    INKDebug(PLUGIN_NAME_DBG, "Calling CTOR for RulesEntry, header is %s", _header);
+  }
+
+  ~RulesEntry()
+  {
+    INKDebug(PLUGIN_NAME_DBG, "Calling DTOR for RulesEntry");
+    if (_next)
+      delete _next; // Potentially "deep" recursion, but should be OK.
+    if (_header)
+      INKfree(_header);
+  }
+
+  void append(RulesEntry* entry);
+  void execute(INKMBuffer& reqp, INKMLoc& hdr_loc); // This is really the meat of the app
+
+private:
+  DISALLOW_COPY_AND_ASSIGN(RulesEntry);
+
+  char* _header;
+  size_t _len;
+  RulesEntry* _next;
+};
+
+
+class Rules
+{
+public:
+  Rules()
+  {
+    INKDebug(PLUGIN_NAME_DBG, "Calling CTOR for Rules");
+    memset(_entries, 0, sizeof(_entries));
+  }
+
+  virtual ~Rules();
+
+  RulesEntry* add_entry(const INKHttpHookID hook, const std::string& s);
+  bool parse_file(const char* filename);
+
+  bool supported_hook(const INKHttpHookID hook)
+  {
+    return ((hook == INK_HTTP_READ_REQUEST_HDR_HOOK) ||
+	    (hook == INK_HTTP_SEND_REQUEST_HDR_HOOK) ||
+	    (hook == INK_HTTP_READ_RESPONSE_HDR_HOOK) ||
+	    (hook == INK_HTTP_SEND_RESPONSE_HDR_HOOK));
+  }
+
+  void execute(INKMBuffer& reqp, INKMLoc& hdr_loc, const INKHttpHookID hook)
+  {
+    INKAssert(supported_hook(hook));
+    INKDebug(PLUGIN_NAME, "Executing rules(s) for hook %d", hook);
+    _entries[hook]->execute(reqp, hdr_loc);
+  }
+
+private:
+  DISALLOW_COPY_AND_ASSIGN(Rules);
+
+  RulesEntry* _entries[INK_HTTP_LAST_HOOK]; // One possible set of entries for each hook
+};
+
+} // End of namespace ::HeaderFilter
+
+
+#endif // __RULES_H__
+
+
+
+/*
+  local variables:
+  mode: C++
+  indent-tabs-mode: nil
+  c-basic-offset: 2
+  c-comment-only-line-offset: 0
+  c-file-offsets: ((statement-block-intro . +)
+  (label . 0)
+  (statement-cont . +)
+  (innamespace . 0))
+  end:
+
+  Indent with: /usr/bin/indent -ncs -nut -npcs -l 120 logstats.cc
+*/