Repository: trafficserver
Updated Branches:
  refs/heads/master 387bb9a5b -> 92bdda991


TS-2636: Enhance ATS custom logging to support WIPE_FIELD_VALUE filter action


Project: http://git-wip-us.apache.org/repos/asf/trafficserver/repo
Commit: http://git-wip-us.apache.org/repos/asf/trafficserver/commit/92bdda99
Tree: http://git-wip-us.apache.org/repos/asf/trafficserver/tree/92bdda99
Diff: http://git-wip-us.apache.org/repos/asf/trafficserver/diff/92bdda99

Branch: refs/heads/master
Commit: 92bdda99113cea13a6a70e08f5dd611dcae2ac8b
Parents: 387bb9a
Author: Sudheer Vinukonda <[email protected]>
Authored: Thu May 8 09:52:18 2014 -0700
Committer: Bryan Call <[email protected]>
Committed: Thu May 8 09:52:18 2014 -0700

----------------------------------------------------------------------
 proxy/logging/Log.cc           |  18 +++--
 proxy/logging/LogAccess.h      |   7 ++
 proxy/logging/LogAccessHttp.cc |  63 +++++++++++++++++
 proxy/logging/LogAccessHttp.h  |   7 ++
 proxy/logging/LogField.cc      |  23 ++++--
 proxy/logging/LogField.h       |  15 ++--
 proxy/logging/LogFilter.cc     | 135 +++++++++++++++++++++++++++++++++++-
 proxy/logging/LogFilter.h      | 131 ++++++++++++++++++++++++++++++++++
 proxy/logging/LogObject.cc     |   4 ++
 9 files changed, 383 insertions(+), 20 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/trafficserver/blob/92bdda99/proxy/logging/Log.cc
----------------------------------------------------------------------
diff --git a/proxy/logging/Log.cc b/proxy/logging/Log.cc
index 8107cb1..11f8311 100644
--- a/proxy/logging/Log.cc
+++ b/proxy/logging/Log.cc
@@ -444,35 +444,40 @@ Log::init_fields()
   field = NEW(new LogField("client_req_url", "cqu",
                            LogField::STRING,
                            &LogAccess::marshal_client_req_url,
-                           
(LogField::UnmarshalFunc)&LogAccess::unmarshal_str));
+                           (LogField::UnmarshalFunc)&LogAccess::unmarshal_str,
+                           &LogAccess::set_client_req_url));
   global_field_list.add(field, false);
   ink_hash_table_insert(field_symbol_hash, "cqu", field);
 
   field = NEW(new LogField("client_req_url_canonical", "cquc",
                            LogField::STRING,
                            &LogAccess::marshal_client_req_url_canon,
-                           
(LogField::UnmarshalFunc)&LogAccess::unmarshal_str));
+                           (LogField::UnmarshalFunc)&LogAccess::unmarshal_str,
+                           &LogAccess::set_client_req_url_canon));
   global_field_list.add(field, false);
   ink_hash_table_insert(field_symbol_hash, "cquc", field);
 
   field = NEW(new LogField("client_req_unmapped_url_canonical", "cquuc",
                            LogField::STRING,
                            &LogAccess::marshal_client_req_unmapped_url_canon,
-                           
(LogField::UnmarshalFunc)&LogAccess::unmarshal_str));
+                           (LogField::UnmarshalFunc)&LogAccess::unmarshal_str,
+                           &LogAccess::set_client_req_unmapped_url_canon));
   global_field_list.add(field, false);
   ink_hash_table_insert(field_symbol_hash, "cquuc", field);
 
   field = NEW(new LogField("client_req_unmapped_url_path", "cquup",
                            LogField::STRING,
                            &LogAccess::marshal_client_req_unmapped_url_path,
-                           
(LogField::UnmarshalFunc)&LogAccess::unmarshal_str));
+                           (LogField::UnmarshalFunc)&LogAccess::unmarshal_str,
+                           &LogAccess::set_client_req_unmapped_url_path));
   global_field_list.add(field, false);
   ink_hash_table_insert(field_symbol_hash, "cquup", field);
 
   field = NEW(new LogField("client_req_unmapped_url_host", "cquuh",
                            LogField::STRING,
                            &LogAccess::marshal_client_req_unmapped_url_host,
-                           
(LogField::UnmarshalFunc)&LogAccess::unmarshal_str));
+                           (LogField::UnmarshalFunc)&LogAccess::unmarshal_str,
+                           &LogAccess::set_client_req_unmapped_url_host));
   global_field_list.add(field, false);
   ink_hash_table_insert(field_symbol_hash, "cquuh", field);
 
@@ -486,7 +491,8 @@ Log::init_fields()
   field = NEW(new LogField("client_req_url_path", "cqup",
                            LogField::STRING,
                            &LogAccess::marshal_client_req_url_path,
-                           
(LogField::UnmarshalFunc)&LogAccess::unmarshal_str));
+                           (LogField::UnmarshalFunc)&LogAccess::unmarshal_str,
+                           &LogAccess::set_client_req_url_path));
   global_field_list.add(field, false);
   ink_hash_table_insert(field_symbol_hash, "cqup", field);
 

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/92bdda99/proxy/logging/LogAccess.h
----------------------------------------------------------------------
diff --git a/proxy/logging/LogAccess.h b/proxy/logging/LogAccess.h
index 35291aa..940145d 100644
--- a/proxy/logging/LogAccess.h
+++ b/proxy/logging/LogAccess.h
@@ -228,6 +228,13 @@ public:
   inkcoreapi virtual int marshal_cache_resp_http_version(char *); // INT
 
 
+  inkcoreapi virtual void set_client_req_url(char *, int) {};        // STR
+  inkcoreapi virtual void set_client_req_url_canon(char *, int) {};  // STR
+  inkcoreapi virtual void set_client_req_unmapped_url_canon(char *, int) {}; 
// STR
+  inkcoreapi virtual void set_client_req_unmapped_url_path(char *, int) {};  
// STR
+  inkcoreapi virtual void set_client_req_unmapped_url_host(char *, int) {};  
// STR
+  inkcoreapi virtual void set_client_req_url_path(char *, int) {};   // STR
+
   //
   // congestion control -- client_retry_after_time
   //

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/92bdda99/proxy/logging/LogAccessHttp.cc
----------------------------------------------------------------------
diff --git a/proxy/logging/LogAccessHttp.cc b/proxy/logging/LogAccessHttp.cc
index 5ad308b..d8250ab 100644
--- a/proxy/logging/LogAccessHttp.cc
+++ b/proxy/logging/LogAccessHttp.cc
@@ -128,6 +128,69 @@ LogAccessHttp::init()
 }
 
 /*-------------------------------------------------------------------------
+  The set routines ...
+
+  These routines are used by the WIPE_FIELD_VALUE filter to replace the 
original req url
+  strings with the WIPED req strings.
+  -------------------------------------------------------------------------*/
+
+void
+LogAccessHttp::set_client_req_url(char *buf, int len)
+{
+  if (buf) {
+    m_client_req_url_len = len;
+    ink_strlcpy(m_client_req_url_str, buf, m_client_req_url_len + 1);
+  }
+}
+
+void
+LogAccessHttp::set_client_req_url_canon(char *buf, int len)
+{
+  if (buf) {
+    m_client_req_url_canon_len = len;
+    ink_strlcpy(m_client_req_url_canon_str, buf, m_client_req_url_canon_len + 
1);
+  }
+}
+
+void
+LogAccessHttp::set_client_req_unmapped_url_canon(char *buf, int len)
+{
+  if (buf) {
+    m_client_req_unmapped_url_canon_len = len;
+    ink_strlcpy(m_client_req_unmapped_url_canon_str, buf, 
m_client_req_unmapped_url_canon_len + 1);
+  }
+}
+
+void
+LogAccessHttp::set_client_req_unmapped_url_path(char *buf, int len)
+{
+  if (buf) {
+    m_client_req_unmapped_url_path_len = len;
+    ink_strlcpy(m_client_req_unmapped_url_path_str, buf, 
m_client_req_unmapped_url_path_len + 1);
+  }
+}
+
+void
+LogAccessHttp::set_client_req_unmapped_url_host(char *buf, int len)
+{
+  if (buf) {
+    m_client_req_unmapped_url_host_len = len;
+    ink_strlcpy(m_client_req_unmapped_url_host_str, buf, 
m_client_req_unmapped_url_host_len + 1);
+  }
+}
+
+void
+LogAccessHttp::set_client_req_url_path(char *buf, int len)
+{
+  //?? use m_client_req_unmapped_url_path_str for now..may need to enhance 
later..
+  if (buf) {
+    m_client_req_url_path_len = len;
+    ink_strlcpy(m_client_req_unmapped_url_path_str, buf, 
m_client_req_url_path_len + 1);
+  }
+}
+
+
+/*-------------------------------------------------------------------------
   The marshalling routines ...
 
   We know that m_http_sm is a valid pointer (we assert so in the ctor), but

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/92bdda99/proxy/logging/LogAccessHttp.h
----------------------------------------------------------------------
diff --git a/proxy/logging/LogAccessHttp.h b/proxy/logging/LogAccessHttp.h
index 9235441..e487326 100644
--- a/proxy/logging/LogAccessHttp.h
+++ b/proxy/logging/LogAccessHttp.h
@@ -135,6 +135,13 @@ public:
   virtual int marshal_http_header_field(LogField::Container container, char 
*field, char *buf);
   virtual int marshal_http_header_field_escapify(LogField::Container 
container, char *field, char *buf);
 
+  virtual void set_client_req_url(char *, int);        // STR
+  virtual void set_client_req_url_canon(char *, int);  // STR
+  virtual void set_client_req_unmapped_url_canon(char *, int); // STR
+  virtual void set_client_req_unmapped_url_path(char *, int);  // STR
+  virtual void set_client_req_unmapped_url_host(char *, int);  // STR
+  virtual void set_client_req_url_path(char *, int);   // STR
+
 private:
   HttpSM * m_http_sm;
 

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/92bdda99/proxy/logging/LogField.cc
----------------------------------------------------------------------
diff --git a/proxy/logging/LogField.cc b/proxy/logging/LogField.cc
index 6bab383..add7b17 100644
--- a/proxy/logging/LogField.cc
+++ b/proxy/logging/LogField.cc
@@ -142,10 +142,10 @@ LogSlice::toStrOffset(int strlen, int *offset)
   -------------------------------------------------------------------------*/
 
 // Generic field ctor
-LogField::LogField(const char *name, const char *symbol, Type type, 
MarshalFunc marshal, UnmarshalFunc unmarshal)
+LogField::LogField(const char *name, const char *symbol, Type type, 
MarshalFunc marshal, UnmarshalFunc unmarshal, SetFunc _setfunc)
   : m_name(ats_strdup(name)), m_symbol(ats_strdup(symbol)), m_type(type), 
m_container(NO_CONTAINER), m_marshal_func(marshal),
     m_unmarshal_func(unmarshal), m_unmarshal_func_map(NULL), 
m_agg_op(NO_AGGREGATE), m_agg_cnt(0), m_agg_val(0),
-    m_time_field(false), m_alias_map(0)
+    m_time_field(false), m_alias_map(0), m_set_func(_setfunc)
 {
   ink_assert(m_name != NULL);
   ink_assert(m_symbol != NULL);
@@ -159,10 +159,10 @@ LogField::LogField(const char *name, const char *symbol, 
Type type, MarshalFunc
 }
 
 LogField::LogField(const char *name, const char *symbol, Type type,
-                   MarshalFunc marshal, UnmarshalFuncWithMap unmarshal, 
Ptr<LogFieldAliasMap> map)
+                   MarshalFunc marshal, UnmarshalFuncWithMap unmarshal, 
Ptr<LogFieldAliasMap> map, SetFunc _setfunc)
   : m_name(ats_strdup(name)), m_symbol(ats_strdup(symbol)), m_type(type), 
m_container(NO_CONTAINER), m_marshal_func(marshal),
     m_unmarshal_func(NULL), m_unmarshal_func_map(unmarshal), 
m_agg_op(NO_AGGREGATE), m_agg_cnt(0), m_agg_val(0),
-    m_time_field(false), m_alias_map(map)
+    m_time_field(false), m_alias_map(map), m_set_func(_setfunc)
 {
   ink_assert(m_name != NULL);
   ink_assert(m_symbol != NULL);
@@ -177,10 +177,10 @@ LogField::LogField(const char *name, const char *symbol, 
Type type,
 }
 
 // Container field ctor
-LogField::LogField(const char *field, Container container)
+LogField::LogField(const char *field, Container container, SetFunc _setfunc)
   : m_name(ats_strdup(field)), 
m_symbol(ats_strdup(container_names[container])), m_type(LogField::STRING),
     m_container(container), m_marshal_func(NULL), m_unmarshal_func(NULL), 
m_unmarshal_func_map(NULL),
-    m_agg_op(NO_AGGREGATE), m_agg_cnt(0), m_agg_val(0), m_time_field(false), 
m_alias_map(0)
+    m_agg_op(NO_AGGREGATE), m_agg_cnt(0), m_agg_val(0), m_time_field(false), 
m_alias_map(0), m_set_func(_setfunc)
 {
   ink_assert(m_name != NULL);
   ink_assert(m_symbol != NULL);
@@ -223,7 +223,7 @@ LogField::LogField(const char *field, Container container)
 LogField::LogField(const LogField &rhs)
   : m_name(ats_strdup(rhs.m_name)), m_symbol(ats_strdup(rhs.m_symbol)), 
m_type(rhs.m_type), m_container(rhs.m_container),
     m_marshal_func(rhs.m_marshal_func), 
m_unmarshal_func(rhs.m_unmarshal_func), 
m_unmarshal_func_map(rhs.m_unmarshal_func_map),
-    m_agg_op(rhs.m_agg_op), m_agg_cnt(0), m_agg_val(0), 
m_time_field(rhs.m_time_field), m_alias_map(rhs.m_alias_map)
+    m_agg_op(rhs.m_agg_op), m_agg_cnt(0), m_agg_val(0), 
m_time_field(rhs.m_time_field), m_alias_map(rhs.m_alias_map), 
m_set_func(rhs.m_set_func)
 {
   ink_assert(m_name != NULL);
   ink_assert(m_symbol != NULL);
@@ -282,6 +282,15 @@ LogField::marshal_len(LogAccess *lad)
   }
 }
 
+void
+LogField::updateField(LogAccess *lad, char *buf, int len)
+{
+  if (m_container == NO_CONTAINER) {
+    return (lad->*m_set_func) (buf, len);
+  }
+  // else...// future enhancement
+}
+
 /*-------------------------------------------------------------------------
   LogField::marshal
 

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/92bdda99/proxy/logging/LogField.h
----------------------------------------------------------------------
diff --git a/proxy/logging/LogField.h b/proxy/logging/LogField.h
index 1847daa..b1b0c64 100644
--- a/proxy/logging/LogField.h
+++ b/proxy/logging/LogField.h
@@ -78,6 +78,7 @@ public:
   typedef int (*UnmarshalFunc) (char **buf, char *dest, int len);
   typedef int (*UnmarshalFuncWithSlice) (char **buf, char *dest, int len, 
LogSlice *slice);
   typedef int (*UnmarshalFuncWithMap) (char **buf, char *dest, int len, 
Ptr<LogFieldAliasMap> map);
+  typedef void (LogAccess::*SetFunc) (char *buf, int len);
 
 
   enum Type
@@ -119,14 +120,14 @@ public:
     N_AGGREGATES
   };
 
-    LogField(const char *name, const char *symbol, Type type, MarshalFunc 
marshal, UnmarshalFunc unmarshal);
+  LogField(const char *name, const char *symbol, Type type, MarshalFunc 
marshal, UnmarshalFunc unmarshal, SetFunc _setFunc=NULL);
 
-    LogField(const char *name, const char *symbol, Type type,
-             MarshalFunc marshal, UnmarshalFuncWithMap unmarshal, 
Ptr<LogFieldAliasMap> map);
+  LogField(const char *name, const char *symbol, Type type,
+      MarshalFunc marshal, UnmarshalFuncWithMap unmarshal, 
Ptr<LogFieldAliasMap> map, SetFunc _setFunc=NULL);
 
-    LogField(const char *field, Container container);
-    LogField(const LogField & rhs);
-   ~LogField();
+  LogField(const char *field, Container container, SetFunc _setFunc=NULL);
+  LogField(const LogField & rhs);
+  ~LogField();
 
   unsigned marshal_len(LogAccess * lad);
   unsigned marshal(LogAccess * lad, char *buf);
@@ -134,6 +135,7 @@ public:
   unsigned unmarshal(char **buf, char *dest, int len);
   void display(FILE * fd = stdout);
   bool operator==(LogField & rhs);
+  void updateField(LogAccess * lad, char* val, int len);
 
   char *name()
   {
@@ -179,6 +181,7 @@ private:
   int64_t m_agg_val;
   bool m_time_field;
   Ptr<LogFieldAliasMap> m_alias_map; // map sINT <--> string
+  SetFunc m_set_func;
 
 public:
   LINK(LogField, link);

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/92bdda99/proxy/logging/LogFilter.cc
----------------------------------------------------------------------
diff --git a/proxy/logging/LogFilter.cc b/proxy/logging/LogFilter.cc
index aada40a..f0360a8 100644
--- a/proxy/logging/LogFilter.cc
+++ b/proxy/logging/LogFilter.cc
@@ -44,7 +44,7 @@
 #include "SimpleTokenizer.h"
 
 const char *LogFilter::OPERATOR_NAME[] = { "MATCH", 
"CASE_INSENSITIVE_MATCH","CONTAIN", "CASE_INSENSITIVE_CONTAIN" };
-const char *LogFilter::ACTION_NAME[] = { "REJECT", "ACCEPT" };
+const char *LogFilter::ACTION_NAME[] = { "REJECT", "ACCEPT", 
"WIPE_FIELD_VALUE" };
 
 /*-------------------------------------------------------------------------
   LogFilter::LogFilter
@@ -182,6 +182,85 @@ LogFilterString::operator==(LogFilterString & rhs)
 }
 
 /*-------------------------------------------------------------------------
+  LogFilterString::wipe_this_entry
+
+  For strings, we need to marshal the given string into a buffer so that we
+  can compare it with the filter value.  Most strings are snall, so we'll
+  only allocate space dynamically if the marshal_len is very large (eg,
+  URL).
+
+  The m_substr field tells us whether we can match based on substrings, or
+  whether we should compare the entire string.
+  -------------------------------------------------------------------------*/
+
+bool
+LogFilterString::wipe_this_entry(LogAccess * lad)
+{
+  if (m_num_values == 0 || m_field == NULL || lad == NULL || m_action != 
WIPE_FIELD_VALUE) {
+    return false;
+  }
+
+  static const unsigned BUFSIZE = 1024;
+  char small_buf[BUFSIZE];
+  char small_buf_upper[BUFSIZE];
+  char *big_buf = NULL;
+  char *big_buf_upper = NULL;
+  char *buf = small_buf;
+  char *buf_upper = small_buf_upper;
+  size_t marsh_len = m_field->marshal_len(lad);      // includes null 
termination
+
+  if (marsh_len > BUFSIZE) {
+    big_buf = (char *)ats_malloc((unsigned int) marsh_len);
+    buf = big_buf;
+  }
+
+  m_field->marshal(lad, buf);
+
+  bool cond_satisfied = false;
+  switch (m_operator) {
+  case MATCH:
+    // marsh_len is an upper bound on the length of the marshalled string
+    // because marsh_len counts padding and the eos. So for a MATCH
+    // operator, we use the DATA_LENGTH_LARGER length condition rather
+    // than DATA_LENGTH_EQUAL, which we would use if we had the actual
+    // length of the string. It is probably not worth computing the
+    // actual length, so we just use the fact that a MATCH is not possible
+    // when marsh_len <= (length of the filter string)
+    //
+    cond_satisfied = _checkConditionAndWipe(&strcmp, &buf, marsh_len, m_value, 
DATA_LENGTH_LARGER);
+    break;
+  case CASE_INSENSITIVE_MATCH:
+    cond_satisfied = _checkConditionAndWipe(&strcasecmp, &buf, marsh_len, 
m_value, DATA_LENGTH_LARGER);
+    break;
+  case CONTAIN:
+    cond_satisfied = _checkConditionAndWipe(&_isSubstring, &buf, marsh_len, 
m_value, DATA_LENGTH_LARGER);
+    break;
+  case CASE_INSENSITIVE_CONTAIN:
+    {
+      if (big_buf) {
+        big_buf_upper = (char *)ats_malloc((unsigned int) marsh_len);
+        buf_upper = big_buf_upper;
+      }
+      for (size_t i = 0; i < marsh_len; i++) {
+        buf_upper[i] = ParseRules::ink_toupper(buf[i]);
+      }
+      cond_satisfied = _checkConditionAndWipe(&_isSubstring, &buf_upper, 
marsh_len, m_value_uppercase, DATA_LENGTH_LARGER);
+      strcpy(buf, buf_upper);
+      break;
+    }
+  default:
+    ink_assert(!"INVALID FILTER OPERATOR");
+  }
+
+  ats_free(big_buf);
+  ats_free(big_buf_upper);
+
+  m_field->updateField(lad, buf, strlen(buf));
+  return cond_satisfied;
+}
+
+
+/*-------------------------------------------------------------------------
   LogFilterString::toss_this_entry
 
   For strings, we need to marshal the given string into a buffer so that we
@@ -438,6 +517,44 @@ bool LogFilterInt::operator==(LogFilterInt & rhs)
 }
 
 /*-------------------------------------------------------------------------
+  LogFilterInt::wipe_this_entry
+  -------------------------------------------------------------------------*/
+
+bool
+LogFilterInt::wipe_this_entry(LogAccess * lad)
+{
+  if (m_num_values == 0 || m_field == NULL || lad == NULL || m_action != 
WIPE_FIELD_VALUE) {
+    return false;
+  }
+
+  bool cond_satisfied = false;
+  int64_t value;
+
+  m_field->marshal(lad, (char *) &value);
+  // This used to do an ntohl() on value, but that breaks various filters.
+  // Long term we should move IPs to their own log type.
+
+  // we don't use m_operator because we consider all operators to be
+  // equivalent to "MATCH" for an integer field
+  //
+
+  // most common case is single value, speed it up a little bit by unrolling
+  //
+  if (m_num_values == 1) {
+    cond_satisfied = (value == *m_value);
+  } else {
+    for (size_t i = 0; i < m_num_values; ++i) {
+      if (value == m_value[i]) {
+        cond_satisfied = true;
+        break;
+      }
+    }
+  }
+
+  return cond_satisfied;
+}
+
+/*-------------------------------------------------------------------------
   LogFilterInt::toss_this_entry
   -------------------------------------------------------------------------*/
 
@@ -620,6 +737,22 @@ LogFilterList::add(LogFilter * filter, bool copy)
 /*-------------------------------------------------------------------------
   -------------------------------------------------------------------------*/
 
+bool
+LogFilterList::wipe_this_entry(LogAccess * lad)
+{
+  bool wipeFlag = false;
+    for (LogFilter * f = first(); f; f = next(f)) {
+      if (f->wipe_this_entry(lad)) {
+        wipeFlag = true;
+      }
+    }
+    return wipeFlag;
+}
+
+
+/*-------------------------------------------------------------------------
+  -------------------------------------------------------------------------*/
+
 bool LogFilterList::toss_this_entry(LogAccess * lad)
 {
   if (m_does_conjunction) {

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/92bdda99/proxy/logging/LogFilter.h
----------------------------------------------------------------------
diff --git a/proxy/logging/LogFilter.h b/proxy/logging/LogFilter.h
index a99e1d1..d754e0e 100644
--- a/proxy/logging/LogFilter.h
+++ b/proxy/logging/LogFilter.h
@@ -52,6 +52,7 @@ public:
   {
     REJECT = 0,
     ACCEPT,
+    WIPE_FIELD_VALUE,
     N_ACTIONS
   };
   static const char *ACTION_NAME[];
@@ -78,6 +79,7 @@ public:
   size_t get_num_values() const { return m_num_values; };
 
   virtual bool toss_this_entry(LogAccess * lad) = 0;
+  virtual bool wipe_this_entry(LogAccess * lad) = 0;
   virtual void display(FILE * fd = stdout) = 0;
   virtual void display_as_XML(FILE * fd = stdout) = 0;
 
@@ -116,6 +118,7 @@ public:
   bool operator==(LogFilterString & rhs);
 
   bool toss_this_entry(LogAccess * lad);
+  bool wipe_this_entry(LogAccess * lad);
   void display(FILE * fd = stdout);
   void display_as_XML(FILE * fd = stdout);
 
@@ -150,6 +153,9 @@ private:
   inline bool _checkCondition(OperatorFunction f,
                               const char *field_value, size_t 
field_value_length, char **val, LengthCondition lc);
 
+  inline bool _checkConditionAndWipe(OperatorFunction f, char **field_value, 
size_t field_value_length, char **val,
+                                     LengthCondition lc);
+
   // -- member functions that are not allowed --
   LogFilterString();
   LogFilterString & operator=(LogFilterString & rhs);
@@ -171,6 +177,7 @@ public:
   bool operator==(LogFilterInt & rhs);
 
   bool toss_this_entry(LogAccess * lad);
+  bool wipe_this_entry(LogAccess * lad);
   void display(FILE * fd = stdout);
   void display_as_XML(FILE * fd = stdout);
 
@@ -200,6 +207,7 @@ public:
 
   void add(LogFilter * filter, bool copy = true);
   bool toss_this_entry(LogAccess * lad);
+  bool wipe_this_entry(LogAccess * lad);
   LogFilter *find_by_name(char *name);
   void clear();
 
@@ -300,4 +308,127 @@ LogFilterString::_checkCondition(OperatorFunction f,
   return retVal;
 }
 
+/*---------------------------------------------------------------------------
+  wipeField : Given a dest buffer, wipe the first occurance of the value of the
+  field in the buffer.
+
+--------------------------------------------------------------------------*/
+static void
+wipeField(char** dest, char* field)
+{
+
+  char* buf_dest  = *dest;
+
+  if (buf_dest) {
+
+    char* query_param = strstr(buf_dest, "?");
+
+    if (!query_param) return;
+
+    char* p1 = strstr(query_param, field);
+
+    if (p1) {
+      char tmp_text[strlen(buf_dest) + 10];
+      char *temp_text = tmp_text;
+      memcpy(temp_text, buf_dest, (p1 - buf_dest));
+      temp_text += (p1 - buf_dest);
+      char* p2 = strstr(p1, "=");
+      if (p2) {
+        p2++;
+        memcpy(temp_text, p1, (p2 - p1));
+        temp_text += (p2 - p1);
+        char* p3 = strstr(p2, "&");
+        if (p3) {
+          for (int i=0; i<(p3 - p2); i++)
+            temp_text[i] = 'X';
+          temp_text += (p3 - p2);
+          memcpy(temp_text, p3, ((buf_dest+strlen(buf_dest)) - p3));
+        } else {
+          for (int i=0; i<((buf_dest+strlen(buf_dest)) - p2); i++)
+            temp_text[i] = 'X';
+        }
+      } else {
+        return;
+      }
+
+      tmp_text[strlen(buf_dest)] = '\0';
+      strcpy(*dest, tmp_text);
+    }
+  }
+}
+
+/*-------------------------------------------------------------------------
+  _checkConditionAndWipe
+
+  check all values for a matching condition and perform wipe action
+
+  the arguments to the function are:
+
+  - a function f of type OperatorFunction that determines if the
+    condition is true for a single filter value. Note that this function
+    must return 0 if the condition is true.
+  - the value of the field from the log record
+  - the length of this field
+  - the array of filter values to compare to note that we pass this as an
+    argument because it can be either m_value or m_value_uppercase
+  - a LengthCondition argument that determines if the length of the field value
+    must be equal or larger to the length of the filter value (this is to
+    compare strings only if really needed
+    ------------------------------------------------------------------------*/
+
+inline bool
+LogFilterString::_checkConditionAndWipe(OperatorFunction f, char 
**field_value, size_t field_value_length,
+                                        char **val, LengthCondition lc)
+{
+  bool retVal = false;
+
+  if (m_action != WIPE_FIELD_VALUE) return false;
+
+  // make single value case a little bit faster by taking it out of loop
+  //
+  if (m_num_values == 1) {
+    switch (lc) {
+    case DATA_LENGTH_EQUAL:
+      retVal = (field_value_length == *m_length ? ((*f) (*field_value, *val) 
== 0 ? true : false) : false);
+      if (retVal) {
+        wipeField(field_value, *val);
+      }
+      break;
+    case DATA_LENGTH_LARGER:
+      retVal = (field_value_length > *m_length ? ((*f) (*field_value, *val) == 
0 ? true : false) : false);
+      if (retVal) {
+        wipeField(field_value, *val);
+      }
+      break;
+    default:
+      ink_assert(!"LogFilterString::checkCondition " "unknown 
LengthCondition");
+    }
+  } else {
+    size_t i;
+    switch (lc) {
+    case DATA_LENGTH_EQUAL:
+      for (i = 0; i < m_num_values; ++i) {
+        // condition is satisfied if f returns zero
+        if (field_value_length == m_length[i] && (*f) (*field_value, val[i]) 
== 0) {
+          retVal = true;
+          wipeField(field_value, val[i]);
+        }
+      }
+      break;
+    case DATA_LENGTH_LARGER:
+      for (i = 0; i < m_num_values; ++i) {
+        // condition is satisfied if f returns zero
+        if (field_value_length > m_length[i] && (*f) (*field_value, val[i]) == 
0) {
+          retVal = true;
+          wipeField(field_value, val[i]);
+        }
+      }
+      break;
+    default:
+      ink_assert(!"LogFilterString::checkConditionAndWipe " "unknown 
LengthConditionAndWipe");
+    }
+  }
+  return retVal;
+}
+
 #endif

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/92bdda99/proxy/logging/LogObject.cc
----------------------------------------------------------------------
diff --git a/proxy/logging/LogObject.cc b/proxy/logging/LogObject.cc
index 52ace03..4dbc511 100644
--- a/proxy/logging/LogObject.cc
+++ b/proxy/logging/LogObject.cc
@@ -566,6 +566,10 @@ LogObject::log(LogAccess * lad, const char *text_entry)
     return Log::SKIP;
   }
 
+  if (lad && m_filter_list.wipe_this_entry(lad)) {
+    Debug("log", "entry wiped, ...");
+  }
+
   if (lad && m_format->is_aggregate()) {
     // marshal the field data into the temp space provided by the
     // LogFormat object for aggregate formats

Reply via email to