You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by am...@apache.org on 2011/02/25 03:39:28 UTC

svn commit: r1074382 - in /trafficserver/traffic/trunk: lib/tsconfig/TsBuffer.h proxy/CacheControl.cc proxy/ControlBase.cc proxy/ControlBase.h proxy/ControlMatcher.cc proxy/Makefile.am proxy/ParentSelection.cc

Author: amc
Date: Fri Feb 25 02:39:27 2011
New Revision: 1074382

URL: http://svn.apache.org/viewvc?rev=1074382&view=rev
Log:
TS-674

Modified:
    trafficserver/traffic/trunk/lib/tsconfig/TsBuffer.h
    trafficserver/traffic/trunk/proxy/CacheControl.cc
    trafficserver/traffic/trunk/proxy/ControlBase.cc
    trafficserver/traffic/trunk/proxy/ControlBase.h
    trafficserver/traffic/trunk/proxy/ControlMatcher.cc
    trafficserver/traffic/trunk/proxy/Makefile.am
    trafficserver/traffic/trunk/proxy/ParentSelection.cc

Modified: trafficserver/traffic/trunk/lib/tsconfig/TsBuffer.h
URL: http://svn.apache.org/viewvc/trafficserver/traffic/trunk/lib/tsconfig/TsBuffer.h?rev=1074382&r1=1074381&r2=1074382&view=diff
==============================================================================
--- trafficserver/traffic/trunk/lib/tsconfig/TsBuffer.h (original)
+++ trafficserver/traffic/trunk/lib/tsconfig/TsBuffer.h Fri Feb 25 02:39:27 2011
@@ -71,6 +71,14 @@ namespace ts {
      */
     bool operator != (ConstBuffer const& that) const;
 
+    /// @name Accessors.
+    //@{
+    /// Get the data in the buffer.
+    char* data() const;
+    /// Get the size of the buffer.
+    size_t size() const;
+    //@}
+
     /// Set the chunk.
     /// Any previous values are discarded.
     /// @return @c this object.
@@ -130,6 +138,14 @@ namespace ts {
         Buffer const& that ///< Source buffer.
     );
 
+    /// @name Accessors.
+    //@{
+    /// Get the data in the buffer.
+    char const * data() const;
+    /// Get the size of the buffer.
+    size_t size() const;
+    //@}
+
     /// Set the chunk.
     /// Any previous values are discarded.
     /// @return @c this object.
@@ -156,6 +172,8 @@ namespace ts {
   inline bool Buffer::operator == (ConstBuffer const& that) const {
       return _size == that._size && 0 == memcmp(_ptr, that._ptr, _size);
   }
+  inline char * Buffer::data() const { return _ptr; }
+  inline size_t Buffer::size() const { return _size; }
 
   inline ConstBuffer::ConstBuffer() { }
   inline ConstBuffer::ConstBuffer(char const* ptr, size_t n) : _ptr(ptr), _size(n) { }
@@ -171,6 +189,8 @@ namespace ts {
   inline bool ConstBuffer::operator == (Buffer const& that) const {
       return _size == that._size && 0 == memcmp(_ptr, that._ptr, _size);
   }
+  inline char const * ConstBuffer::data() const { return _ptr; }
+  inline size_t ConstBuffer::size() const { return _size; }
 }
 
 # endif // TS_BUFFER_HEADER

Modified: trafficserver/traffic/trunk/proxy/CacheControl.cc
URL: http://svn.apache.org/viewvc/trafficserver/traffic/trunk/proxy/CacheControl.cc?rev=1074382&r1=1074381&r2=1074382&view=diff
==============================================================================
--- trafficserver/traffic/trunk/proxy/CacheControl.cc (original)
+++ trafficserver/traffic/trunk/proxy/CacheControl.cc Fri Feb 25 02:39:27 2011
@@ -234,8 +234,8 @@ CacheControlRecord::Print()
   case CC_STANDARD_CACHE:
   case CC_IGNORE_NO_CACHE:
  // case CC_CACHE_AUTH_CONTENT:
-  //  printf("\t\tDirective: %s\n", CC_directive_str[this->directive]);
-  //  break;
+    printf("\t\tDirective: %s\n", CC_directive_str[this->directive]);
+    break;
   case CC_INVALID:
   case CC_NUM_TYPES:
     printf("\t\tDirective: INVALID\n");

Modified: trafficserver/traffic/trunk/proxy/ControlBase.cc
URL: http://svn.apache.org/viewvc/trafficserver/traffic/trunk/proxy/ControlBase.cc?rev=1074382&r1=1074381&r2=1074382&view=diff
==============================================================================
--- trafficserver/traffic/trunk/proxy/ControlBase.cc (original)
+++ trafficserver/traffic/trunk/proxy/ControlBase.cc Fri Feb 25 02:39:27 2011
@@ -44,554 +44,575 @@
 #include "ControlMatcher.h"
 #include "HdrUtils.h"
 
-// iPort added
-static const char *ModTypeStrings[] = {
-  "Modifier Invalid",
-  "Port",
-  "Scheme",
-  "Prefix",
-  "Suffix",
-  "Method",
-  "TimeOfDay",
-  "SrcIP",
-  "iPort",
-  "Tag"
-};
+#include "tsconfig/TsBuffer.h"
 
-struct timeMod
-{
+/** Used for printing IP address.
+    @code
+    uint32_t addr; // IP address.
+    printf("IP address = " TS_IP_PRINTF_CODE,TS_IP_OCTETS(addr));
+    @endcode
+    @internal Need to move these to a common header.
+ */
+# define TS_IP_OCTETS(x) \
+  reinterpret_cast<unsigned char const*>(&(x))[0],   \
+    reinterpret_cast<unsigned char const*>(&(x))[1], \
+    reinterpret_cast<unsigned char const*>(&(x))[2], \
+    reinterpret_cast<unsigned char const*>(&(x))[3]
+
+// ----------
+ControlBase::Modifier::~Modifier() {}
+ControlBase::Modifier::Type ControlBase::Modifier::type() const { return MOD_INVALID; }
+// --------------------------
+namespace {
+// ----------
+struct TimeMod : public ControlBase::Modifier {
   time_t start_time;
   time_t end_time;
-};
 
-struct ipMod
-{
-  ip_addr_t start_addr;
-  ip_addr_t end_addr;
+  static char const * const NAME;
+
+  virtual Type type() const;
+  virtual char const * name() const;
+  virtual bool check(HttpRequestData* req) const;
+  virtual void print(FILE* f) const;
+  static TimeMod* make(char * value, char const ** error);
+  static const char* timeOfDayToSeconds(const char *time_str, time_t * seconds);
 };
 
-struct portMod
-{
+char const * const TimeMod::NAME = "Time";
+ControlBase::Modifier::Type TimeMod::type() const { return MOD_TIME; }
+char const * TimeMod::name() const { return NAME; }
+
+void TimeMod::print(FILE* f) const {
+  fprintf(f, "%s=%ld-%ld  ", this->name(), start_time, end_time);
+}
+bool TimeMod::check(HttpRequestData* req) const {
+  struct tm cur_time;
+  time_t timeOfDay = req->xact_start;
+  // Use this to account for daylight savings time.
+  ink_localtime_r(&timeOfDay, &cur_time);
+  timeOfDay = cur_time.tm_hour*(60 * 60) + cur_time.tm_min*60 + cur_time.tm_sec;
+  return start_time <= timeOfDay && timeOfDay <= end_time;
+}
+
+TimeMod*
+TimeMod::make(char * value, char const ** error) {
+  Tokenizer rangeTok("-");
+  TimeMod* mod = 0;
+  TimeMod tmp;
+  int num_tok;
+
+  num_tok = rangeTok.Initialize(value, SHARE_TOKS);
+  if (num_tok == 1) {
+    *error = "End time not specified";
+  } else if (num_tok > 2) {
+    *error = "Malformed time range";
+  } else if (
+    0 == (*error = timeOfDayToSeconds(rangeTok[0], &tmp.start_time))
+    && 0 == (*error = timeOfDayToSeconds(rangeTok[1], &tmp.end_time))
+  ) {
+    mod = new TimeMod(tmp);
+  }
+  return mod;
+}
+/**   Converts TimeOfDay (TOD) to second value.
+      @a *seconds is set to number of seconds since midnight
+      represented by @a time_str.
+
+      @return 0 on success, static error string on failure.
+*/
+const char *
+TimeMod::timeOfDayToSeconds(const char *time_str, time_t * seconds) {
+  int hour = 0;
+  int min = 0;
+  int sec = 0;
+  time_t tmp = 0;
+
+  // coverity[secure_coding]
+  if (sscanf(time_str, "%d:%d:%d", &hour, &min, &sec) != 3) {
+    // coverity[secure_coding]
+    if (sscanf(time_str, "%d:%d", &hour, &min) != 2) {
+      return "Malformed time specified";
+    }
+  }
+
+  if (!(hour >= 0 && hour <= 23)) return "Illegal hour specification";
+
+  tmp = hour * 60;
+
+  if (!(min >= 0 && min <= 59)) return "Illegal minute specification";
+
+  tmp = (tmp + min) * 60;
+
+  if (!(sec >= 0 && sec <= 59)) return "Illegal second specification";
+
+  tmp += sec;
+
+  *seconds = tmp;
+  return 0;
+}
+
+// ----------
+struct PortMod : public ControlBase::Modifier {
   int start_port;
   int end_port;
+
+  static char const * const NAME;
+
+  virtual char const * name() const;
+  virtual bool check(HttpRequestData* req) const;
+  virtual void print(FILE* f) const;
+
+  static PortMod* make(char* value, char const **error);
 };
 
-ControlBase::~ControlBase()
-{
-  int num_el;
-
-  if (mod_elements != NULL) {
-
-    // Free all Prefix/Postfix strings and
-    //   SrcIP, Port, Time Of Day Structures
-    num_el = (*mod_elements).length() + 1;
-    for (intptr_t i = 0; i < num_el; i++) {
-      modifier_el & cur_el = (*mod_elements)[i];
-      if (cur_el.type == MOD_PREFIX ||
-          cur_el.type == MOD_SUFFIX ||
-          cur_el.type == MOD_TIME || cur_el.type == MOD_PORT || cur_el.type == MOD_SRC_IP || cur_el.type == MOD_TAG) {
-        xfree(cur_el.opaque_data);
-      }
-    }
+char const * const PortMod::NAME = "Port";
+char const * PortMod::name() const { return NAME; }
+
+void PortMod::print(FILE* f) const {
+  fprintf(f, "%s=%d-%d  ", this->name(), start_port, end_port);
+}
+
+bool PortMod::check(HttpRequestData* req) const {
+  int port = req->hdr->port_get();
+  return start_port <= port && port <= end_port;
+}
 
-    delete mod_elements;
+PortMod*
+PortMod::make(char* value, char const ** error) {
+  Tokenizer rangeTok("-");
+  PortMod tmp;
+  int num_tok = rangeTok.Initialize(value, SHARE_TOKS);
+
+  *error = 0;
+  if (num_tok > 2) {
+    *error = "Malformed Range";
+    // coverity[secure_coding]
+  } else if (sscanf(rangeTok[0], "%d", &tmp.start_port) != 1) {
+    *error = "Invalid start port";
+  } else if (num_tok == 2) {
+    // coverity[secure_coding]
+    if (sscanf(rangeTok[1], "%d", &tmp.end_port) != 1)
+      *error = "Invalid end port";
+    else if (tmp.end_port < tmp.start_port)
+      *error = "Malformed Range: end port < start port";
+  } else {
+    tmp.end_port = tmp.start_port;
   }
+
+  // If there's an error message, return null.
+  // Otherwise create a new item and return it.
+  return *error ? 0 : new PortMod(tmp);
 }
 
-static const modifier_el default_el = { MOD_INVALID, NULL };
+// ----------
+struct IPortMod : public ControlBase::Modifier {
+  int _port;
+
+  static char const * const NAME;
+
+  IPortMod(int port);
+
+  virtual char const * name() const;
+  virtual bool check(HttpRequestData* req) const;
+  virtual void print(FILE* f) const;
+  static IPortMod* make(char* value, char const ** error);
+};
 
-void
-ControlBase::Print()
-{
-  int num_el;
-  struct in_addr a;
-  int port;
+char const * const IPortMod::NAME = "IPort";
+IPortMod::IPortMod(int port) : _port(port) {}
+char const * IPortMod::name() const { return NAME; }
 
-  if (mod_elements == NULL) {
-    return;
+void IPortMod::print(FILE* f) const {
+  fprintf(f, "%s=%d  ", this->name(), _port);
+}
+bool IPortMod::check(HttpRequestData* req) const {
+  return req->incoming_port == _port;
+}
+
+IPortMod*
+IPortMod::make(char* value, char const ** error) {
+  IPortMod* zret = 0;
+  int port;
+  // coverity[secure_coding]
+  if (sscanf(value, "%u", &port) == 1) {
+    zret = new IPortMod(port);
+  } else {
+    *error = "Invalid incoming port";
   }
+  return zret;
+}
+// ----------
+struct SrcIPMod : public ControlBase::Modifier {
+  // Stored in host order because that's how they are compared.
+  ip_addr_t start_addr; ///< Start address in HOST order.
+  ip_addr_t end_addr; ///< End address in HOST order.
+
+  static char const * const NAME;
+
+  virtual Type type() const;
+  virtual char const * name() const;
+  virtual bool check(HttpRequestData* req) const;
+  virtual void print(FILE* f) const;
+  static SrcIPMod* make(char * value, char const ** error);
+};
+
+char const * const SrcIPMod::NAME = "SrcIP";
+ControlBase::Modifier::Type SrcIPMod::type() const { return MOD_SRC_IP; }
+char const * SrcIPMod::name() const { return NAME; }
+
+void SrcIPMod::print(FILE* f) const {
+  ip_addr_t a1 = htonl(start_addr);
+  ip_addr_t a2 = htonl(end_addr);
+  fprintf(f, "%s=%d.%d.%d.%d-%d.%d.%d.%d  ",
+    this->name(), TS_IP_OCTETS(a1), TS_IP_OCTETS(a2)
+  );
+}
+bool SrcIPMod::check(HttpRequestData* req) const {
+  // Compare in host order
+  uint32_t addr = ntohl(req->src_ip);
+  return start_addr <= addr && addr <= end_addr;
+}
+SrcIPMod*
+SrcIPMod::make(char * value, char const ** error ) {
+  SrcIPMod tmp;
+  SrcIPMod* zret = 0;
+  *error = ExtractIpRange(value, &tmp.start_addr, &tmp.end_addr);
 
-  num_el = (*mod_elements).length();
-  if (num_el <= 0) {
-    return;
+  if (!*error) zret = new SrcIPMod(tmp);
+  return zret;
+}
+// ----------
+struct SchemeMod : public ControlBase::Modifier {
+  int _scheme; ///< Tokenized scheme.
+
+  static char const * const NAME;
+
+  SchemeMod(int scheme);
+
+  virtual Type type() const;
+  virtual char const * name() const;
+  virtual bool check(HttpRequestData* req) const;
+  virtual void print(FILE* f) const;
+
+  char const* getWksText() const;
+
+  static SchemeMod* make(char * value, char const ** error);
+};
+
+char const * const SchemeMod::NAME = "Scheme";
+
+SchemeMod::SchemeMod(int scheme) : _scheme(scheme) {}
+
+ControlBase::Modifier::Type SchemeMod::type() const { return MOD_SCHEME; }
+char const * SchemeMod::name() const { return NAME; }
+char const *
+SchemeMod::getWksText() const {
+  return hdrtoken_index_to_wks(_scheme);
+}
+
+bool SchemeMod::check(HttpRequestData* req) const {
+  return req->hdr->url_get()->scheme_get_wksidx() == _scheme;
+}
+void SchemeMod::print(FILE* f) const {
+  fprintf(f, "%s=%s  ", this->name(), hdrtoken_index_to_wks(_scheme));
+}
+SchemeMod*
+SchemeMod::make(char * value, char const ** error) {
+  SchemeMod* zret = 0;
+  int scheme = hdrtoken_tokenize(value, strlen(value));
+  if (scheme < 0) {
+    *error = "Unknown scheme";
+  } else {
+    zret = new SchemeMod(scheme);
   }
+  return zret;
+}
+// ----------
+// This is a base class for all of the mods that have a
+// text string.
+struct TextMod : public ControlBase::Modifier {
+  ts::Buffer text;
+
+  TextMod();
+  ~TextMod();
+
+  // Calls name() which the subclass must provide.
+  virtual void print(FILE* f) const;
+};
+void TextMod::print(FILE* f) const {
+  fprintf(f, "%s=%*s  ", this->name(), static_cast<int>(text.size()), text.data());
+}
+
+TextMod::TextMod() : text(0,0) {}
+TextMod::~TextMod() {
+  if (text.data()) free(text.data());
+}
+
+// ----------
+struct MethodMod : public TextMod {
+  static char const * const NAME;
+
+  virtual Type type() const;
+  virtual char const * name() const;
+  virtual bool check(HttpRequestData* req) const;
+
+  static MethodMod* make(char * value, char const ** error);
+};
+char const * const MethodMod::NAME = "Method";
+ControlBase::Modifier::Type MethodMod::type() const { return MOD_METHOD; }
+char const * MethodMod::name() const { return NAME; }
+bool MethodMod::check(HttpRequestData* req) const {
+  int method_len;
+  char const* method = req->hdr->method_get(&method_len);
+  return method_len >= static_cast<int>(text.size())
+    && 0 == strncasecmp(method, text.data(), text.size())
+    ;
+}
+MethodMod*
+MethodMod::make(char * value, char const **) {
+  MethodMod* mod = new MethodMod;
+  mod->text.set(xstrdup(value), strlen(value));
+  return mod;
+}
+
+// ----------
+struct PrefixMod : public TextMod {
+  static char const * const NAME;
+
+  virtual Type type() const;
+  virtual char const * name() const;
+  virtual bool check(HttpRequestData* req) const;
+  static PrefixMod* make(char * value, char const ** error);
+};
+
+char const * const PrefixMod::NAME = "Prefix";
+ControlBase::Modifier::Type PrefixMod::type() const { return MOD_PREFIX; }
+char const * PrefixMod::name() const { return NAME; }
+bool PrefixMod::check(HttpRequestData* req) const {
+  int path_len;
+  char const* path = req->hdr->url_get()->path_get(&path_len);
+  bool zret = path_len >= static_cast<int>(text.size())
+    && 0 == memcmp(path, text.data(), text.size())
+    ;
+/*
+  Debug("cache_control", "Prefix check: URL=%0.*s Mod=%0.*s Z=%s",
+    path_len, path, text.size(), text.data(),
+    zret ? "Match" : "Fail"
+  );
+*/
+  return zret;
+}
+PrefixMod*
+PrefixMod::make(char * value, char const ** error ) {
+  PrefixMod* mod = new PrefixMod;
+  // strip leading slashes because get_path which is used later
+  // doesn't include them from the URL.
+  while ('/' == *value) ++value;
+  mod->text.set(xstrdup(value), strlen(value));
+  return mod;
+}
+// ----------
+struct SuffixMod : public TextMod {
+  static char const * const NAME;
+
+  virtual Type type() const;
+  virtual char const * name() const;
+  virtual bool check(HttpRequestData* req) const;
+  static SuffixMod* make(char * value, char const ** error);
+};
+char const * const SuffixMod::NAME = "Suffix";
+ControlBase::Modifier::Type SuffixMod::type() const { return MOD_SUFFIX; }
+char const * SuffixMod::name() const { return NAME; }
+bool SuffixMod::check(HttpRequestData* req) const {
+  int path_len;
+  char const* path = req->hdr->url_get()->path_get(&path_len);
+  return path_len >= static_cast<int>(text.size())
+    && 0 == strncasecmp(path + path_len - text.size(), text.data(), text.size())
+    ;
+}
+SuffixMod*
+SuffixMod::make(char * value, char const ** error ) {
+  SuffixMod* mod = new SuffixMod;
+  mod->text.set(xstrdup(value), strlen(value));
+  return mod;
+}
+
+// ----------
+struct TagMod : public TextMod {
+  static char const * const NAME;
+
+  virtual Type type() const;
+  virtual char const * name() const;
+  virtual bool check(HttpRequestData* req) const;
+  static TagMod* make(char * value, char const ** error);
+};
+char const * const TagMod::NAME = "Tag";
+ControlBase::Modifier::Type TagMod::type() const { return MOD_TAG; }
+char const * TagMod::name() const { return NAME; }
+bool TagMod::check(HttpRequestData* req) const {
+  return 0 == strcmp(req->tag, text.data());
+}
+TagMod*
+TagMod::make(char * value, char const ** error ) {
+  TagMod* mod = new TagMod;
+  mod->text.set(xstrdup(value), strlen(value));
+  return mod;
+}
+// ----------
+} // anon name space
+// ------------------------------------------------
+ControlBase::~ControlBase() {
+  this->clear();
+}
+
+void
+ControlBase::clear() {
+  line_num = 0;
+  for ( Array::iterator spot = _mods.begin(), limit = _mods.end()
+      ; spot != limit
+      ; ++spot
+  )
+    delete *spot;
+  _mods.clear();
+}
+
+// static const modifier_el default_el = { MOD_INVALID, NULL };
+
+void
+ControlBase::Print() {
+  int n = _mods.size();
+
+  if (0 >= n) return;
 
   printf("\t\t\t");
-  for (intptr_t i = 0; i < num_el; i++) {
-    modifier_el & cur_el = (*mod_elements)[i];
-    switch (cur_el.type) {
-    case MOD_INVALID:
-      printf("%s  ", ModTypeStrings[MOD_INVALID]);
-      break;
-    case MOD_PORT:
-      port = ((portMod *) cur_el.opaque_data)->start_port;
-      printf("%s=%d-", ModTypeStrings[MOD_PORT], port);
-      port = ((portMod *) cur_el.opaque_data)->end_port;
-      printf("%d  ", port);
-      break;
-    case MOD_IPORT:
-      printf("%s=%d  ", ModTypeStrings[MOD_IPORT], (int) (long) cur_el.opaque_data);
-      break;
-    case MOD_SCHEME:
-      printf("%s=%s  ", ModTypeStrings[MOD_SCHEME], (char *) cur_el.opaque_data);
-      break;
-    case MOD_PREFIX:
-      printf("%s=%s  ", ModTypeStrings[MOD_PREFIX], (char *) cur_el.opaque_data);
-      break;
-    case MOD_SUFFIX:
-      printf("%s=%s  ", ModTypeStrings[MOD_SUFFIX], (char *) cur_el.opaque_data);
-      break;
-    case MOD_METHOD:
-      printf("%s=%s  ", ModTypeStrings[MOD_METHOD], (char *) cur_el.opaque_data);
-      break;
-    case MOD_TAG:
-      printf("%s=%s  ", ModTypeStrings[MOD_TAG], (char *) cur_el.opaque_data);
-      break;
-    case MOD_SRC_IP:
-      a.s_addr = ((ipMod *) cur_el.opaque_data)->start_addr;
-      printf("%s=%s-", ModTypeStrings[MOD_SRC_IP], inet_ntoa(a));
-      a.s_addr = ((ipMod *) cur_el.opaque_data)->end_addr;
-      printf("%s  ", inet_ntoa(a));
-      break;
-    case MOD_TIME:
-      printf("%s=%d-%d  ", ModTypeStrings[MOD_TIME],
-             (int) ((timeMod *) cur_el.opaque_data)->start_time, (int) ((timeMod *) cur_el.opaque_data)->end_time);
-      break;
-    }
+  for (intptr_t i = 0; i < n; ++i) {
+    Modifier* cur_mod = _mods[i];
+    if (!cur_mod) printf("INVALID  ");
+    else cur_mod->print(stdout);
   }
   printf("\n");
 }
 
+char const *
+ControlBase::getSchemeModText() const {
+  char const* zret = 0;
+  Modifier* mod = this->findModOfType(Modifier::MOD_SCHEME);
+  if (mod) zret = static_cast<SchemeMod*>(mod)->getWksText();
+  return zret;
+}
+
 bool
-ControlBase::CheckModifiers(HttpRequestData * request_data)
-{
+ControlBase::CheckModifiers(HttpRequestData * request_data) {
   if (!request_data->hdr) {
     //we use the same request_data for Socks as well (only IpMatcher)
     //we just return false here
     return true;
   }
-  const char *data;
-  const char *path;
-  const char *method;
-  ipMod *ipRange;
-  portMod *portRange;
-  timeMod *timeRange;
-  time_t timeOfDay;
-  URL *request_url = request_data->hdr->url_get();
-  int data_len, path_len, scheme_len, method_len;
-  char *tag, *request_tag;
-  ip_addr_t src_ip;
-  int port;
 
   // If the incoming request has no tag but the entry does, or both
   // have tags that do not match, then we do NOT have a match.
-  request_tag = request_data->tag;
-  if (!request_tag && mod_elements != NULL && getModElem(MOD_TAG) != NULL)
+  if (!request_data->tag && findModOfType(Modifier::MOD_TAG))
     return false;
 
-  // If there are no modifiers, then of course we match them
-  if (mod_elements == NULL) {
-    return true;
-  }
-
-  for (intptr_t i = 0; i < mod_elements->length(); i++) {
-    modifier_el & cur_el = (*mod_elements)[i];
-
-    switch (cur_el.type) {
-    case MOD_PORT:
-      port = request_url->port_get();
-      portRange = (portMod *) cur_el.opaque_data;
-      if (port < portRange->start_port || port > portRange->end_port) {
-        return false;
-      }
-      break;
-    case MOD_IPORT:
-      if (request_data->incoming_port != (long) cur_el.opaque_data) {
-        return false;
-      }
-      break;
-    case MOD_SCHEME:
-      if (request_url->scheme_get(&scheme_len) != (char *) cur_el.opaque_data) {
-        return false;
-      }
-      break;
-    case MOD_PREFIX:
-      // INKqa07820
-      // The problem is that path_get() returns the URL's path
-      // without the leading '/'.
-      // E.g., If URL is http://inktomi/foo/bar,
-      // then path_get() returns "foo/bar" but not "/foo/bar".
-      // A simple solution is to skip the leading '/' in data.
-      data = (char *) cur_el.opaque_data;
-      if (*data == '/')
-        data++;
-      path = request_url->path_get(&path_len);
-      if (ptr_len_ncmp(path, path_len, data, strlen(data)) != 0) {
-        return false;
-      }
-      break;
-    case MOD_SUFFIX:
-      data = (char *) cur_el.opaque_data;
-      data_len = strlen(data);
-      ink_assert(data_len > 0);
-      path = request_url->path_get(&path_len);
-      // Suffix matching is case-insentive b/c it's
-      //   mainly used for file type matching and
-      //   jpeg, JPEG, Jpeg all mean the same thing
-      //   (INKqa04363)
-      if (path_len < data_len || strncasecmp(path + (path_len - data_len), data, data_len) != 0) {
-        return false;
-      }
-      break;
-    case MOD_METHOD:
-      method = request_data->hdr->method_get(&method_len);
-      if (ptr_len_casecmp(method, method_len, (char *) cur_el.opaque_data) != 0) {
-        return false;
-      }
-      break;
-    case MOD_TIME:
-      timeRange = (timeMod *) cur_el.opaque_data;
-      // INKqa11534
-      // daylight saving time is not taken into consideration
-      // so use ink_localtime_r() instead.
-      // timeOfDay = (request_data->xact_start - ink_timezone()) % secondsInDay;
-      {
-        struct tm cur_tm;
-        timeOfDay = request_data->xact_start;
-        ink_localtime_r(&timeOfDay, &cur_tm);
-        timeOfDay = cur_tm.tm_hour * (60 * 60)
-          + cur_tm.tm_min * 60 + cur_tm.tm_sec;
-      }
-      if (timeOfDay < timeRange->start_time || timeOfDay > timeRange->end_time) {
-        return false;
-      }
-      break;
-    case MOD_SRC_IP:
-      src_ip = htonl(request_data->src_ip);
-      ipRange = (ipMod *) cur_el.opaque_data;
-      if (src_ip < ipRange->start_addr || src_ip > ipRange->end_addr) {
-        return false;
-      }
-      break;
-    case MOD_TAG:
-      // Check for a tag match.
-      tag = (char *) cur_el.opaque_data;
-      ink_assert(tag);
-      if (request_tag && strcmp(request_tag, tag) != 0) {
-        return false;
-      }
-      break;
-    case MOD_INVALID:
-      // Fall Through
-    default:
-      // Should never get here
-      ink_assert(0);
-      break;
-    }
+  for (int i = 0, n = _mods.size() ; i < n; ++i) {
+    Modifier* cur_mod = _mods[i];
+    if (cur_mod && ! cur_mod->check(request_data)) return false;
   }
 
   return true;
 }
 
-enum mod_errors
-{ ME_UNKNOWN, ME_PARSE_FAILED,
-  ME_BAD_SCHEME, ME_BAD_METHOD, ME_BAD_MOD,
-  ME_CALLEE_GENERATED, ME_BAD_IPORT
+enum mod_errors {
+  ME_UNKNOWN,
+  ME_PARSE_FAILED,
+  ME_BAD_MOD,
+  ME_CALLEE_GENERATED
 };
 
 static const char *errorFormats[] = {
   "Unknown error parsing modifier",
   "Unable to parse modifier",
-  "Unknown scheme",
-  "Unknown method",
   "Unknown modifier",
   "Callee Generated",
-  "Bad incoming port"
 };
 
-const void *
-ControlBase::getModElem(ModifierTypes t)
-{
-  for (int i = 0; i < mod_elements->length(); i++) {
-    modifier_el & cur_el = (*mod_elements) (i);
-    if (cur_el.type == t) {
-      return cur_el.opaque_data;
-    }
+ControlBase::Modifier*
+ControlBase::findModOfType(Modifier::Type t) const {
+  for (int i = 0, n = _mods.size(); i < n; ++i) {
+      Modifier* m = _mods[i];
+      if (m && t == m->type()) return m;
   }
-  return NULL;
+  return 0;
 }
 
 const char *
-ControlBase::ProcessModifiers(matcher_line * line_info)
-{
-
+ControlBase::ProcessModifiers(matcher_line * line_info) {
   // Variables for error processing
   const char *errBuf = NULL;
   mod_errors err = ME_UNKNOWN;
 
-  int num = 0;
-  char *label;
-  char *val;
-  unsigned int tmp;
-  int num_mod_elements;
-  const char *tmp_scheme = NULL;
-
-  // Set up the array to handle the modifier
-  num_mod_elements = (line_info->num_el > 0) ? line_info->num_el : 1;
-  mod_elements = new DynArray<modifier_el> (&default_el, num_mod_elements);
-
-
-  for (int i = 0; i < MATCHER_MAX_TOKENS; i++) {
-
-    label = line_info->line[0][i];
-    val = line_info->line[1][i];
-
-    // Skip NULL tags
-    if (label == NULL) {
-      continue;
-    }
+  int n_elts = line_info->num_el; // Element count for line.
 
-    modifier_el & cur_el = (*mod_elements) (num);
-    num++;
+  // No elements -> no modifiers.
+  if (0 >= n_elts) return 0;
+  // Can't have more modifiers than elements, so reasonable upper bound.
+  _mods.clear();
+  _mods.reserve(n_elts);
+
+  // As elements are consumed, the labels are nulled out and the element
+  // count decremented. So we have to scan the entire array to be sure of
+  // finding all the elements. We'll track the element count so we can
+  // escape if we've found all of the elements.
+  for (int i = 0; n_elts && ME_UNKNOWN == err && i < MATCHER_MAX_TOKENS; ++i) {
+    Modifier* mod = 0;
 
-    // Make sure we have a value
-    if (val == NULL) {
+    char * label = line_info->line[0][i];
+    char * value = line_info->line[1][i];
+
+    if (!label) continue; // Already use.
+    if (!value) {
       err = ME_PARSE_FAILED;
-      goto error;
+      break;
     }
 
     if (strcasecmp(label, "port") == 0) {
-      cur_el.type = MOD_PORT;
-      errBuf = ProcessPort(val, &cur_el.opaque_data);
-      if (errBuf != NULL) {
-        err = ME_CALLEE_GENERATED;
-        goto error;
-      }
+      mod = PortMod::make(value, &errBuf);
     } else if (strcasecmp(label, "iport") == 0) {
-      // coverity[secure_coding]
-      if (sscanf(val, "%u", &tmp) == 1) {
-        cur_el.type = MOD_IPORT;
-        cur_el.opaque_data = (void *)(uintptr_t)tmp;
-      } else {
-        err = ME_BAD_IPORT;
-        goto error;
-      }
-
+      mod = IPortMod::make(value, &errBuf);
     } else if (strcasecmp(label, "scheme") == 0) {
-      tmp_scheme = hdrtoken_string_to_wks(val);
-      if (!tmp_scheme) {
-        err = ME_BAD_SCHEME;
-        goto error;
-      }
-      cur_el.type = MOD_SCHEME;
-      cur_el.opaque_data = (void *) tmp_scheme;
-
+      mod = SchemeMod::make(value, &errBuf);
     } else if (strcasecmp(label, "method") == 0) {
-      cur_el.type = MOD_METHOD;
-      cur_el.opaque_data = (void *) xstrdup(val);
-
+      mod = MethodMod::make(value, &errBuf);
     } else if (strcasecmp(label, "prefix") == 0) {
-      cur_el.type = MOD_PREFIX;
-      cur_el.opaque_data = (void *) xstrdup(val);
-
+      mod = PrefixMod::make(value, &errBuf);
     } else if (strcasecmp(label, "suffix") == 0) {
-      cur_el.type = MOD_SUFFIX;
-      cur_el.opaque_data = (void *) xstrdup(val);
+      mod = SuffixMod::make(value, &errBuf);
     } else if (strcasecmp(label, "src_ip") == 0) {
-      cur_el.type = MOD_SRC_IP;
-      errBuf = ProcessSrcIp(val, &cur_el.opaque_data);
-      if (errBuf != NULL) {
-        err = ME_CALLEE_GENERATED;
-        goto error;
-      }
+      mod = SrcIPMod::make(value, &errBuf);
     } else if (strcasecmp(label, "time") == 0) {
-      cur_el.type = MOD_TIME;
-      errBuf = ProcessTimeOfDay(val, &cur_el.opaque_data);
-      if (errBuf != NULL) {
-        err = ME_CALLEE_GENERATED;
-        goto error;
-      }
+      mod = TimeMod::make(value, &errBuf);
     } else if (strcasecmp(label, "tag") == 0) {
-      cur_el.type = MOD_TAG;
-      cur_el.opaque_data = (void *) xstrdup(val);
+      mod = TagMod::make(value, &errBuf);
     } else {
       err = ME_BAD_MOD;
-      goto error;
-
     }
-  }
-
-  return NULL;
-
-error:
-  delete mod_elements;
-  mod_elements = NULL;
-  if (err == ME_CALLEE_GENERATED) {
-    return errBuf;
-  } else {
-    return errorFormats[err];
-  }
-}
 
-// const char* ControlBase::ProcessSrcIp(char* val, void** opaque_ptr)
-//
-//   Wrapper to Parse out the src ip range
-//
-//   On success, sets *opaque_ptr to a malloc allocated ipMod
-//      structure and returns NULL
-//   On failure, returns a static error string
-//
-const char *
-ControlBase::ProcessSrcIp(char *val, void **opaque_ptr)
-{
-  ipMod *range = (ipMod *) xmalloc(sizeof(ipMod));
-  const char *errBuf = ExtractIpRange(val, &range->start_addr,
-                                      &range->end_addr);
-
-  if (errBuf == NULL) {
-    *opaque_ptr = range;
-    return NULL;
-  } else {
-    *opaque_ptr = NULL;
-    xfree(range);
-    return errBuf;
-  }
-}
+    if (errBuf) err = ME_CALLEE_GENERATED; // Mod make failed.
 
-// const char* TODtoSeconds(const char* time_str, time_t* seconds) {
-//
-//   Convents a TimeOfDay (TOD) to a second value
-//
-//   On success, sets *seconds to number of seconds since midnight
-//      represented by time_str and returns NULL
-//
-//   On failure, returns a static error string
-//
-const char *
-TODtoSeconds(const char *time_str, time_t * seconds)
-{
-  int hour = 0;
-  int min = 0;
-  int sec = 0;
-  time_t tmp = 0;
-
-  // coverity[secure_coding]
-  if (sscanf(time_str, "%d:%d:%d", &hour, &min, &sec) != 3) {
-    // coverity[secure_coding]
-    if (sscanf(time_str, "%d:%d", &hour, &min) != 2) {
-      return "Malformed time specified";
+    // If nothing went wrong, add the mod and bump the element count.
+    if (ME_UNKNOWN == err) {
+      _mods.push_back(mod);
+      --n_elts;
     }
   }
 
-  if (!(hour >= 0 && hour <= 23)) {
-    return "Illegal hour specification";
-  }
-  tmp = hour * 60;
-
-  if (!(min >= 0 && min <= 59)) {
-    return "Illegal minute specification";
-  }
-  tmp = (tmp + min) * 60;
-
-  if (!(sec >= 0 && sec <= 59)) {
-    return "Illegal second specification";
-  }
-  tmp += sec;
-
-  *seconds = tmp;
-  return NULL;
-}
-
-// const char* ControlBase::ProcessTimeOfDay(char* val, void** opaque_ptr)
-//
-//   Parse out a time of day range.
-//
-//   On success, sets *opaque_ptr to a malloc allocated timeMod
-//      structure and returns NULL
-//   On failure, returns a static error string
-//
-const char *
-ControlBase::ProcessTimeOfDay(char *val, void **opaque_ptr)
-{
-  Tokenizer rangeTok("-");
-  timeMod *t_mod = NULL;
-  int num_tok;
-  const char *errBuf;
-
-  *opaque_ptr = NULL;
-
-  num_tok = rangeTok.Initialize(val, SHARE_TOKS);
-  if (num_tok == 1) {
-    return "End time not specified";
-  } else if (num_tok > 2) {
-    return "Malformed Range";
-  }
-
-  t_mod = (timeMod *) xmalloc(sizeof(timeMod));
-
-  errBuf = TODtoSeconds(rangeTok[0], &t_mod->start_time);
-
-  if (errBuf != NULL) {
-    xfree(t_mod);
-    return errBuf;
-  }
-
-  errBuf = TODtoSeconds(rangeTok[1], &t_mod->end_time);
-
-  if (errBuf != NULL) {
-    xfree(t_mod);
-    return errBuf;
-  }
-
-  *opaque_ptr = t_mod;
-  return NULL;
-}
-
-
-// const char* ControlBase::ProcessPort(char* val, void** opaque_ptr)
-//
-//   Parse out a port range.
-//
-//   On success, sets *opaque_ptr to a malloc allocated portMod
-//      structure and returns NULL
-//   On failure, returns a static error string
-//
-const char *
-ControlBase::ProcessPort(char *val, void **opaque_ptr)
-{
-  Tokenizer rangeTok("-");
-  portMod *p_mod = NULL;
-  int num_tok;
-
-  *opaque_ptr = NULL;
-
-  num_tok = rangeTok.Initialize(val, SHARE_TOKS);
-  if (num_tok > 2) {
-    return "Malformed Range";
-  }
-
-  p_mod = (portMod *) xmalloc(sizeof(portMod));
-
-  // coverity[secure_coding]
-  if (sscanf(rangeTok[0], "%d", &p_mod->start_port) != 1) {
-    xfree(p_mod);
-    return "Invalid start port";
-  }
-
-  if (num_tok == 2) {
-    // coverity[secure_coding]
-    if (sscanf(rangeTok[1], "%d", &p_mod->end_port) != 1) {
-      xfree(p_mod);
-      return "Invalid end port";
-    }
-    if (p_mod->end_port < p_mod->start_port) {
-      xfree(p_mod);
-      return "Malformed Range: end port < start port";
+  if (err != ME_UNKNOWN) {
+    this->clear();
+    if (err != ME_CALLEE_GENERATED) {
+      errBuf = errorFormats[err];
     }
-  } else {
-    p_mod->end_port = p_mod->start_port;
   }
 
-  *opaque_ptr = p_mod;
-  return NULL;
+  return errBuf;
 }

Modified: trafficserver/traffic/trunk/proxy/ControlBase.h
URL: http://svn.apache.org/viewvc/trafficserver/traffic/trunk/proxy/ControlBase.h?rev=1074382&r1=1074381&r2=1074382&view=diff
==============================================================================
--- trafficserver/traffic/trunk/proxy/ControlBase.h (original)
+++ trafficserver/traffic/trunk/proxy/ControlBase.h Fri Feb 25 02:39:27 2011
@@ -34,27 +34,44 @@
 #define _CONTROL_BASE_H_
 
 #include "libts.h"
-#include "DynArray.h"
+#include <vector>
 class HttpRequestData;
 class Tokenizer;
 struct matcher_line;
 
-// MOD_IPORT added
-enum ModifierTypes
-{ MOD_INVALID, MOD_PORT, MOD_SCHEME, MOD_PREFIX,
-  MOD_SUFFIX, MOD_METHOD, MOD_TIME, MOD_SRC_IP,
-  MOD_IPORT, MOD_TAG
-};
-
-struct modifier_el
-{
-  ModifierTypes type;
-  void *opaque_data;
-};
-
-class ControlBase
-{
+class ControlBase {
 public:
+  struct Modifier {
+    enum Type {
+      MOD_INVALID,
+      MOD_PORT,
+      MOD_SCHEME,
+      MOD_PREFIX,
+      MOD_SUFFIX,
+      MOD_METHOD,
+      MOD_TIME,
+      MOD_SRC_IP,
+      MOD_IPORT,
+      MOD_TAG
+    };
+    /// Destructor - force virtual.
+    virtual ~Modifier();
+    /// Return the modifier type.
+    virtual Type type() const;
+    /// Return the name for the modifier type.
+    virtual char const* name() const = 0;
+    /** Test if the modifier matches the request.
+        @return @c true if the request is matched, @c false if not.
+    */
+    virtual bool check(
+      HttpRequestData* req ///< Request to check.
+    ) const = 0;
+    /// Print the mod information.
+    virtual void print(
+      FILE* f ///< Output stream.
+    ) const = 0;
+  };
+
   ControlBase();
   ~ControlBase();
   const char *ProcessModifiers(matcher_line * line_info);
@@ -62,29 +79,33 @@ public:
   bool CheckForMatch(HttpRequestData * request_data, int last_number);
   void Print();
   int line_num;
-  const void *getModElem(ModifierTypes t);
+  Modifier* findModOfType(Modifier::Type t) const;
+protected:
+  /// Get the text for the Scheme modifier, if any.
+  /// @return The text if present, 0 otherwise.
+  /// @internal Ugly but it's the only place external access is needed.
+  char const* getSchemeModText() const;
 private:
-    DynArray<modifier_el> *mod_elements;
+  typedef std::vector<Modifier*> Array;
+  Array _mods;
   const char *ProcessSrcIp(char *val, void **opaque_ptr);
   const char *ProcessTimeOfDay(char *val, void **opaque_ptr);
   const char *ProcessPort(char *val, void **opaque_ptr);
+
+  // Reset to default constructed state, free all allocations.
+  void clear();
 };
 
 inline
-ControlBase::ControlBase():
-line_num(0),
-mod_elements(NULL)
-{
+ControlBase::ControlBase()
+  : line_num(0) {
 }
 
 inline bool
-ControlBase::CheckForMatch(HttpRequestData * request_data, int last_number)
-{
-  if ((last_number<0 || last_number> this->line_num) && this->CheckModifiers(request_data)) {
-    return true;
-  } else {
-    return false;
-  }
+ControlBase::CheckForMatch(HttpRequestData * request_data, int last_number) {
+  return (last_number<0 || last_number> this->line_num)
+    && this->CheckModifiers(request_data)
+    ;
 }
 
 #endif

Modified: trafficserver/traffic/trunk/proxy/ControlMatcher.cc
URL: http://svn.apache.org/viewvc/trafficserver/traffic/trunk/proxy/ControlMatcher.cc?rev=1074382&r1=1074381&r2=1074382&view=diff
==============================================================================
--- trafficserver/traffic/trunk/proxy/ControlMatcher.cc (original)
+++ trafficserver/traffic/trunk/proxy/ControlMatcher.cc Fri Feb 25 02:39:27 2011
@@ -203,7 +203,7 @@ template<class Data, class Result> char 
   ink_assert(match_data != NULL);
 
   // Remove our consumed label from the parsed line
-  line_info->line[0][line_info->dest_entry - 1] = NULL; // XXX
+  line_info->line[0][line_info->dest_entry] = 0;
   line_info->num_el--;
 
   // Fill in the parameter info
@@ -319,7 +319,7 @@ template<class Data, class Result> char 
   re_str[num_el] = xstrdup(pattern);
 
   // Remove our consumed label from the parsed line
-  line_info->line[0][line_info->dest_entry - 1] = NULL; // XXX
+  line_info->line[0][line_info->dest_entry] = 0;
   line_info->num_el--;
 
   // Fill in the parameter info

Modified: trafficserver/traffic/trunk/proxy/Makefile.am
URL: http://svn.apache.org/viewvc/trafficserver/traffic/trunk/proxy/Makefile.am?rev=1074382&r1=1074381&r2=1074382&view=diff
==============================================================================
--- trafficserver/traffic/trunk/proxy/Makefile.am (original)
+++ trafficserver/traffic/trunk/proxy/Makefile.am Fri Feb 25 02:39:27 2011
@@ -41,7 +41,8 @@ AM_CPPFLAGS = \
   -I$(top_srcdir)/mgmt \
   -I$(top_srcdir)/mgmt/preparse \
   -I$(top_srcdir)/mgmt/utils \
-  -I$(srcdir)/api/ts
+  -I$(srcdir)/api/ts \
+  -I$(top_srcdir)/lib
 
 noinst_HEADERS = \
   ConfigParse.h \

Modified: trafficserver/traffic/trunk/proxy/ParentSelection.cc
URL: http://svn.apache.org/viewvc/trafficserver/traffic/trunk/proxy/ParentSelection.cc?rev=1074382&r1=1074381&r2=1074382&view=diff
==============================================================================
--- trafficserver/traffic/trunk/proxy/ParentSelection.cc (original)
+++ trafficserver/traffic/trunk/proxy/ParentSelection.cc Fri Feb 25 02:39:27 2011
@@ -830,7 +830,7 @@ ParentRecord::Init(matcher_line * line_i
     }
     // record SCHEME modifier if present.
     // NULL if not present
-    this->scheme = (const char *) getModElem(MOD_SCHEME);
+    this->scheme = this->getSchemeModText();
     if (this->scheme != NULL) {
       // update parent entries' schemes
       for (int j = 0; j < num_parents; j++) {