You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficcontrol.apache.org by da...@apache.org on 2017/01/13 18:42:26 UTC

[06/10] incubator-trafficcontrol git commit: Removed ATS patches.

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/0d874bf1/traffic_server/patches/trafficserver-5.2.0-791ddc4.patch
----------------------------------------------------------------------
diff --git a/traffic_server/patches/trafficserver-5.2.0-791ddc4.patch b/traffic_server/patches/trafficserver-5.2.0-791ddc4.patch
deleted file mode 100644
index 68b4673..0000000
--- a/traffic_server/patches/trafficserver-5.2.0-791ddc4.patch
+++ /dev/null
@@ -1,4315 +0,0 @@
-diff --git a/CHANGES b/CHANGES
-index b4019fe..6fa1115 100644
---- a/CHANGES
-+++ b/CHANGES
-@@ -1,6 +1,13 @@
-                                                          -*- coding: utf-8 -*-
- Changes with Apache Traffic Server 5.2.0
- 
-+  *) [TS-3504] Only read "proxy.config.cache.ram_cache.use_seen_filter" once.
-+    Do not set up a callback.
-+
-+  *) [TS-3304] Add NULL check to ink_inet_addr() input.
-+
-+  *) [TS-3349] Add DscpSet API's.
-+
-   *) [TS-3280] Segfault in new freelist bulk freeing (in debug mode).
- 
-   *) [TS-3276] Fix cache backwards compatibility issue.
-diff --git a/doc/reference/api/TSHttpOverridableConfig.en.rst b/doc/reference/api/TSHttpOverridableConfig.en.rst
-index 837df9f..009447b 100644
---- a/doc/reference/api/TSHttpOverridableConfig.en.rst
-+++ b/doc/reference/api/TSHttpOverridableConfig.en.rst
-@@ -100,6 +100,7 @@ The following configurations (from ``records.config``) are overridable: ::
-     proxy.config.http.keep_alive_no_activity_timeout_out
-     proxy.config.http.transaction_no_activity_timeout_in
-     proxy.config.http.transaction_no_activity_timeout_out
-+    proxy.config.http.transaction_active_timeout_in
-     proxy.config.http.transaction_active_timeout_out
-     proxy.config.http.origin_max_connections
-     proxy.config.http.connect_attempts_max_retries
-@@ -136,7 +137,6 @@ The following configurations (from ``records.config``) are overridable: ::
-     proxy.config.http.cache.range.write
-     proxy.config.http.global_user_agent_header
- 
--
- Examples
- ========
- 
-diff --git a/doc/reference/api/TSHttpTxnClientPacketDscpSet.en.rst b/doc/reference/api/TSHttpTxnClientPacketDscpSet.en.rst
-new file mode 100644
-index 0000000..eb3368c
---- /dev/null
-+++ b/doc/reference/api/TSHttpTxnClientPacketDscpSet.en.rst
-@@ -0,0 +1,45 @@
-+.. Licensed to the Apache Software Foundation (ASF) under one or more
-+   contributor license agreements.  See the NOTICE file distributed with
-+   this work for additional information regarding copyright ownership.
-+   The ASF licenses this file to you under the Apache License, Version
-+   2.0 (the "License"); you may not use this file except in compliance
-+   with the License.  You may obtain a copy of the License at
-+
-+     http://www.apache.org/licenses/LICENSE-2.0
-+
-+   Unless required by applicable law or agreed to in writing, software
-+   distributed under the License is distributed on an "AS IS" BASIS,
-+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-+   implied.  See the License for the specific language governing
-+   permissions and limitations under the License.
-+
-+
-+TSHttpTxnClientPacketDscpSet
-+============================
-+
-+Change packet DSCP for the client side connection.
-+
-+
-+Synopsis
-+--------
-+
-+`#include <ts/ts.h>`
-+
-+.. c:function:: TSReturnCode TSHttpTxnClientPacketDscpSet(TSHttpTxn txnp, int dscp)
-+
-+
-+Description
-+-----------
-+
-+.. note::
-+
-+   The change takes effect immediately
-+
-+
-+See Also
-+--------
-+
-+`Traffic Shaping`_
-+
-+.. _Traffic Shaping:
-+                 https://cwiki.apache.org/confluence/display/TS/Traffic+Shaping
-diff --git a/doc/reference/api/TSHttpTxnServerPacketDscpSet.en.rst b/doc/reference/api/TSHttpTxnServerPacketDscpSet.en.rst
-new file mode 100644
-index 0000000..a3f19fe
---- /dev/null
-+++ b/doc/reference/api/TSHttpTxnServerPacketDscpSet.en.rst
-@@ -0,0 +1,47 @@
-+.. Licensed to the Apache Software Foundation (ASF) under one or more
-+   contributor license agreements.  See the NOTICE file distributed with
-+   this work for additional information regarding copyright ownership.
-+   The ASF licenses this file to you under the Apache License, Version
-+   2.0 (the "License"); you may not use this file except in compliance
-+   with the License.  You may obtain a copy of the License at
-+
-+     http://www.apache.org/licenses/LICENSE-2.0
-+
-+   Unless required by applicable law or agreed to in writing, software
-+   distributed under the License is distributed on an "AS IS" BASIS,
-+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-+   implied.  See the License for the specific language governing
-+   permissions and limitations under the License.
-+
-+
-+TSHttpTxnServerPacketDscpSet
-+============================
-+
-+Change packet DSCP for the server side connection.
-+
-+
-+Synopsis
-+--------
-+
-+`#include <ts/ts.h>`
-+
-+.. c:function:: TSReturnCode TSHttpTxnServerPacketDscpSet(TSHttpTxn txnp, int dscp)
-+
-+
-+Description
-+-----------
-+
-+.. note::
-+
-+   The change takes effect immediately, if no OS connection has been
-+   made, then this sets the mark that will be used IF an OS connection
-+   is established
-+
-+
-+See Also
-+--------
-+
-+`Traffic Shaping`_
-+
-+.. _Traffic Shaping:
-+                 https://cwiki.apache.org/confluence/display/TS/Traffic+Shaping
-diff --git a/iocore/cache/Cache.cc b/iocore/cache/Cache.cc
-index 9aece93..93777fd 100644
---- a/iocore/cache/Cache.cc
-+++ b/iocore/cache/Cache.cc
-@@ -2185,7 +2185,7 @@ CacheProcessor::mark_storage_offline( CacheDisk* d ///< Target disk
-     Warning("All storage devices offline, cache disabled");
-     CacheProcessor::cache_ready = 0;
-   } else { // check cache types specifically
--    if (theCache && !theCache->hosttable->gen_host_rec.vol_hash_table) {
-+    if (theCache && !theCache->getHosttable(__func__)->gen_host_rec.vol_hash_table) {
-       unsigned int caches_ready = 0;
-       caches_ready = caches_ready | (1 << CACHE_FRAG_TYPE_HTTP);
-       caches_ready = caches_ready | (1 << CACHE_FRAG_TYPE_NONE);
-@@ -2193,7 +2193,7 @@ CacheProcessor::mark_storage_offline( CacheDisk* d ///< Target disk
-       CacheProcessor::cache_ready &= caches_ready;
-       Warning("all volumes for http cache are corrupt, http cache disabled");
-     }
--    if (theStreamCache && !theStreamCache->hosttable->gen_host_rec.vol_hash_table) {
-+    if (theStreamCache && !theStreamCache->getHosttable(__func__)->gen_host_rec.vol_hash_table) {
-       unsigned int caches_ready = 0;
-       caches_ready = caches_ready | (1 << CACHE_FRAG_TYPE_RTSP);
-       caches_ready = ~caches_ready;
-@@ -3368,9 +3368,10 @@ create_volume(int volume_number, off_t size_in_blocks, int scheme, CacheVol *cp)
- void
- rebuild_host_table(Cache *cache)
- {
--  build_vol_hash_table(&cache->hosttable->gen_host_rec);
--  if (cache->hosttable->m_numEntries != 0) {
--    CacheHostMatcher *hm = cache->hosttable->getHostMatcher();
-+  CacheHostTable* hosttable = cache->getHosttable(__func__);
-+  build_vol_hash_table(&hosttable->gen_host_rec);
-+  if (hosttable->m_numEntries != 0) {
-+    CacheHostMatcher *hm = hosttable->getHostMatcher();
-     CacheHostRecord *h_rec = hm->getDataArray();
-     int h_rec_len = hm->getNumElements();
-     int i;
-@@ -3385,8 +3386,9 @@ Vol *
- Cache::key_to_vol(CacheKey *key, char const* hostname, int host_len)
- {
-   uint32_t h = (key->slice32(2) >> DIR_TAG_WIDTH) % VOL_HASH_TABLE_SIZE;
-+  CacheHostTable* hosttable = getHosttable(__func__);
-   unsigned short *hash_table = hosttable->gen_host_rec.vol_hash_table;
--  CacheHostRecord *host_rec = &hosttable->gen_host_rec;
-+  CacheHostRecord *host_rec = &(hosttable->gen_host_rec);
- 
-   if (hosttable->m_numEntries > 0 && host_len) {
-     CacheHostResult res;
-@@ -3394,21 +3396,13 @@ Cache::key_to_vol(CacheKey *key, char const* hostname, int host_len)
-     if (res.record) {
-       unsigned short *host_hash_table = res.record->vol_hash_table;
-       if (host_hash_table) {
--        if (is_debug_tag_set("cache_hosting")) {
--          char format_str[50];
--          snprintf(format_str, sizeof(format_str), "Volume: %%xd for host: %%.%ds", host_len);
--          Debug("cache_hosting", format_str, res.record, hostname);
--        }
-+        Debug("cache_hosting", "Volume: %p for host: %.*s", res.record, host_len, hostname);
-         return res.record->vols[host_hash_table[h]];
-       }
-     }
-   }
-   if (hash_table) {
--    if (is_debug_tag_set("cache_hosting")) {
--      char format_str[50];
--      snprintf(format_str, sizeof(format_str), "Generic volume: %%xd for host: %%.%ds", host_len);
--      Debug("cache_hosting", format_str, host_rec, hostname);
--    }
-+    Debug("cache_hosting", "Generic volume: %p for host: %.*s", host_rec, host_len, hostname);
-     return host_rec->vols[hash_table[h]];
-   } else
-     return host_rec->vols[0];
-@@ -3494,7 +3488,7 @@ ink_cache_init(ModuleVersion v)
-   REC_EstablishStaticConfigInt32(cache_config_ram_cache_algorithm, "proxy.config.cache.ram_cache.algorithm");
-   REC_EstablishStaticConfigInt32(cache_config_ram_cache_compress, "proxy.config.cache.ram_cache.compress");
-   REC_EstablishStaticConfigInt32(cache_config_ram_cache_compress_percent, "proxy.config.cache.ram_cache.compress_percent");
--  REC_EstablishStaticConfigInt32(cache_config_ram_cache_use_seen_filter, "proxy.config.cache.ram_cache.use_seen_filter");
-+  REC_ReadConfigInt32(cache_config_ram_cache_use_seen_filter, "proxy.config.cache.ram_cache.use_seen_filter");
- 
-   REC_EstablishStaticConfigInt32(cache_config_http_max_alts, "proxy.config.cache.limits.http.max_alts");
-   Debug("cache_init", "proxy.config.cache.limits.http.max_alts = %d", cache_config_http_max_alts);
-diff --git a/iocore/cache/CacheVol.cc b/iocore/cache/CacheVol.cc
-index 7acbd95..cd5b82a 100644
---- a/iocore/cache/CacheVol.cc
-+++ b/iocore/cache/CacheVol.cc
-@@ -58,10 +58,11 @@ CacheVC::scanVol(int /* event ATS_UNUSED */, Event * /* e ATS_UNUSED */)
-   Debug("cache_scan_truss", "inside %p:scanVol", this);
-   if (_action.cancelled)
-     return free_CacheVC(this);
--  CacheHostRecord *rec = &theCache->hosttable->gen_host_rec;
-+  CacheHostTable* hosttable = theCache->getHosttable(__func__);
-+  CacheHostRecord *rec = &hosttable->gen_host_rec;
-   if (host_len) {
-     CacheHostResult res;
--    theCache->hosttable->Match(hostname, host_len, &res);
-+    hosttable->Match(hostname, host_len, &res);
-     if (res.record)
-       rec = res.record;
-   }
-diff --git a/iocore/cache/P_CacheHosting.h b/iocore/cache/P_CacheHosting.h
-index ce376cc..1ed306c 100644
---- a/iocore/cache/P_CacheHosting.h
-+++ b/iocore/cache/P_CacheHosting.h
-@@ -147,7 +147,8 @@ struct CacheHostTableConfig: public Continuation
-     (void) e;
-     (void) event;
-     CacheHostTable *t = new CacheHostTable((*ppt)->cache, (*ppt)->type);
--    CacheHostTable *old = (CacheHostTable *) ink_atomic_swap(&t, *ppt);
-+    CacheHostTable *old = (CacheHostTable *) ink_atomic_swap(ppt, t);
-+    Debug("cache_hosting", "swapped: old=%p, new=%p", old, t);
-     new_Deleter(old, CACHE_MEM_FREE_TIMEOUT);
-     return EVENT_DONE;
-   }
-diff --git a/iocore/cache/P_CacheInternal.h b/iocore/cache/P_CacheInternal.h
-index 57c5b0b..7db2436 100644
---- a/iocore/cache/P_CacheInternal.h
-+++ b/iocore/cache/P_CacheInternal.h
-@@ -1065,6 +1065,10 @@ struct Cache
-     : cache_read_done(0), total_good_nvol(0), total_nvol(0), ready(CACHE_INITIALIZING), cache_size(0),  // in store block size
-       hosttable(NULL), total_initialized_vol(0), scheme(CACHE_NONE_TYPE)
-     { }
-+  CacheHostTable* getHosttable(const char* callfunc) {
-+    Debug("cache_hosting", "getHosttable() from: %s", callfunc);
-+    return hosttable;
-+  }
- };
- 
- extern Cache *theCache;
-diff --git a/iocore/net/UnixConnection.cc b/iocore/net/UnixConnection.cc
-index 375ae98..9ea3c8a 100644
---- a/iocore/net/UnixConnection.cc
-+++ b/iocore/net/UnixConnection.cc
-@@ -386,7 +386,11 @@ Connection::apply_options(NetVCOptions const& opt)
- 
- #if TS_HAS_IP_TOS
-   uint32_t tos = opt.packet_tos;
--  safe_setsockopt(fd, IPPROTO_IP, IP_TOS, reinterpret_cast<char *>(&tos), sizeof(uint32_t));
-+  if (addr.isIp4()) {
-+    safe_setsockopt(fd, IPPROTO_IP, IP_TOS, reinterpret_cast<char *>(&tos), sizeof(uint32_t));
-+  } else if (addr.isIp6()) {
-+    safe_setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, reinterpret_cast<char *>(&tos), sizeof(uint32_t));
-+  }
- #endif
- 
- }
-diff --git a/iocore/net/UnixNetAccept.cc b/iocore/net/UnixNetAccept.cc
-index 5ba79fc..d10f74f 100644
---- a/iocore/net/UnixNetAccept.cc
-+++ b/iocore/net/UnixNetAccept.cc
-@@ -275,18 +275,6 @@ NetAccept::do_blocking_accept(EThread * t)
-       return -1;
-     }
- 
--#if TS_HAS_SO_MARK
--      if (packet_mark != 0) {
--        safe_setsockopt(con.fd, SOL_SOCKET, SO_MARK, reinterpret_cast<char *>(&packet_mark), sizeof(uint32_t));
--      }
--#endif
--
--#if TS_HAS_IP_TOS
--      if (packet_tos != 0) {
--        safe_setsockopt(con.fd, IPPROTO_IP, IP_TOS, reinterpret_cast<char *>(&packet_tos), sizeof(uint32_t));
--      }
--#endif
--
-     // Use 'NULL' to Bypass thread allocator
-     vc = (UnixNetVConnection *)this->getNetProcessor()->allocate_vc(NULL);
-     if (!vc) {
-@@ -294,6 +282,9 @@ NetAccept::do_blocking_accept(EThread * t)
-       return -1;
-     }
-     vc->con = con;
-+    vc->options.packet_mark = packet_mark;
-+    vc->options.packet_tos = packet_tos;
-+    vc->apply_options();
-     vc->from_accept_thread = true;
-     vc->id = net_next_connection_number();
-     alloc_cache = NULL;
-@@ -412,17 +403,6 @@ NetAccept::acceptFastEvent(int event, void *ep)
-         safe_setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, SOCKOPT_ON, sizeof(int));
-         Debug("socket", "::acceptFastEvent: setsockopt() SO_KEEPALIVE on socket");
-       }
--#if TS_HAS_SO_MARK
--      if (packet_mark != 0) {
--        safe_setsockopt(fd, SOL_SOCKET, SO_MARK, reinterpret_cast<char *>(&packet_mark), sizeof(uint32_t));
--      }
--#endif
--
--#if TS_HAS_IP_TOS
--      if (packet_tos != 0) {
--        safe_setsockopt(fd, IPPROTO_IP, IP_TOS, reinterpret_cast<char *>(&packet_tos), sizeof(uint32_t));
--      }
--#endif
-       do {
-         res = safe_nonblocking(fd);
-       } while (res < 0 && (errno == EAGAIN || errno == EINTR));
-@@ -435,6 +415,9 @@ NetAccept::acceptFastEvent(int event, void *ep)
- 
-       vc->con = con;
- 
-+      vc->options.packet_mark = packet_mark;
-+      vc->options.packet_tos = packet_tos;
-+      vc->apply_options();
-     } else {
-       res = fd;
-     }
-diff --git a/lib/ts/ConsistentHash.cc b/lib/ts/ConsistentHash.cc
-index e39edbd..0e33b0c 100644
---- a/lib/ts/ConsistentHash.cc
-+++ b/lib/ts/ConsistentHash.cc
-@@ -68,13 +68,19 @@ ATSConsistentHash::insert(ATSConsistentHashNode * node, float weight, ATSHash64
- }
- 
- ATSConsistentHashNode *
--ATSConsistentHash::lookup(const char *url, ATSConsistentHashIter *i, bool *w, ATSHash64 *h)
-+ATSConsistentHash::lookup(const char *url, size_t url_len, ATSConsistentHashIter *i, bool *w, ATSHash64 *h)
- {
-   uint64_t url_hash;
-   ATSConsistentHashIter NodeMapIterUp, *iter;
-   ATSHash64 *thash;
-   bool *wptr, wrapped = false;
- 
-+  if (url_len <= 0 && url) {
-+    url_len = strlen(url);
-+  } else {
-+    url_len = 0;
-+  }
-+
-   if (h) {
-     thash = h;
-   } else if (hash) {
-@@ -96,7 +102,7 @@ ATSConsistentHash::lookup(const char *url, ATSConsistentHashIter *i, bool *w, AT
-   }
- 
-   if (url) {
--    thash->update(url, strlen(url));
-+    thash->update(url, url_len);
-     thash->final();
-     url_hash = thash->get();
-     thash->clear();
-@@ -125,13 +131,19 @@ ATSConsistentHash::lookup(const char *url, ATSConsistentHashIter *i, bool *w, AT
- }
- 
- ATSConsistentHashNode *
--ATSConsistentHash::lookup_available(const char *url, ATSConsistentHashIter *i, bool *w, ATSHash64 *h)
-+ATSConsistentHash::lookup_available(const char *url, size_t url_len, ATSConsistentHashIter *i, bool *w, ATSHash64 *h)
- {
-   uint64_t url_hash;
-   ATSConsistentHashIter NodeMapIterUp, *iter;
-   ATSHash64 *thash;
-   bool *wptr, wrapped = false;
- 
-+  if (url_len <= 0 && url) {
-+    url_len = strlen(url);
-+  } else {
-+    url_len = 0;
-+  }
-+
-   if (h) {
-     thash = h;
-   } else if (hash) {
-@@ -153,7 +165,7 @@ ATSConsistentHash::lookup_available(const char *url, ATSConsistentHashIter *i, b
-   }
- 
-   if (url) {
--    thash->update(url, strlen(url));
-+    thash->update(url, url_len);
-     thash->final();
-     url_hash = thash->get();
-     thash->clear();
-@@ -180,6 +192,34 @@ ATSConsistentHash::lookup_available(const char *url, ATSConsistentHashIter *i, b
-   return (*iter)->second;
- }
- 
-+ATSConsistentHashNode *
-+ATSConsistentHash::lookup_by_hashval(uint64_t hashval, ATSConsistentHashIter *i, bool *w)
-+{
-+  ATSConsistentHashIter NodeMapIterUp, *iter;
-+  bool *wptr, wrapped = false;
-+
-+  if (w) {
-+    wptr = w;
-+  } else {
-+    wptr = &wrapped;
-+  }
-+
-+  if (i) {
-+    iter = i;
-+  } else {
-+    iter = &NodeMapIterUp;
-+  }
-+
-+  *iter = NodeMap.lower_bound(hashval);
-+
-+  if (*iter == NodeMap.end()) {
-+    *wptr = true;
-+    *iter = NodeMap.begin();
-+  }
-+
-+  return (*iter)->second;
-+}
-+
- ATSConsistentHash::~ATSConsistentHash()
- {
-   if (hash) {
-diff --git a/lib/ts/ConsistentHash.h b/lib/ts/ConsistentHash.h
-index 7704c7a..a201b92 100644
---- a/lib/ts/ConsistentHash.h
-+++ b/lib/ts/ConsistentHash.h
-@@ -52,8 +52,9 @@ struct ATSConsistentHash
- {
-   ATSConsistentHash(int r = 1024, ATSHash64 *h = NULL);
-   void insert(ATSConsistentHashNode *node, float weight = 1.0, ATSHash64 *h = NULL);
--  ATSConsistentHashNode *lookup(const char *url = NULL, ATSConsistentHashIter *i = NULL, bool *w = NULL, ATSHash64 *h = NULL);
--  ATSConsistentHashNode *lookup_available(const char *url = NULL, ATSConsistentHashIter *i = NULL, bool *w = NULL, ATSHash64 *h = NULL);
-+  ATSConsistentHashNode *lookup(const char *url = NULL, size_t url_len = 0, ATSConsistentHashIter *i = NULL, bool *w = NULL, ATSHash64 *h = NULL);
-+  ATSConsistentHashNode *lookup_available(const char *url = NULL, size_t url_len = 0, ATSConsistentHashIter *i = NULL, bool *w = NULL, ATSHash64 *h = NULL);
-+  ATSConsistentHashNode *lookup_by_hashval(uint64_t hashval, ATSConsistentHashIter *i = NULL, bool *w = NULL);
-   ~ATSConsistentHash();
- 
- private:
-diff --git a/lib/ts/Makefile.am b/lib/ts/Makefile.am
-index 150182d..ff6fcad 100644
---- a/lib/ts/Makefile.am
-+++ b/lib/ts/Makefile.am
-@@ -108,6 +108,8 @@ libtsutil_la_SOURCES = \
-   defalloc.h \
-   fastlz.c \
-   fastlz.h \
-+  hugepages.cc \
-+  hugepages.h \
-   ink_aiocb.h \
-   ink_align.h \
-   ink_apidefs.h \
-diff --git a/lib/ts/apidefs.h.in b/lib/ts/apidefs.h.in
-index 93f473f..d6e78bd 100644
---- a/lib/ts/apidefs.h.in
-+++ b/lib/ts/apidefs.h.in
-@@ -746,6 +746,7 @@ extern "C"
-     TS_CONFIG_HTTP_CACHE_RANGE_WRITE,
-     TS_CONFIG_HTTP_POST_CHECK_CONTENT_LENGTH_ENABLED,
-     TS_CONFIG_HTTP_GLOBAL_USER_AGENT_HEADER,
-+    TS_CONFIG_HTTP_TRANSACTION_ACTIVE_TIMEOUT_IN,
-     TS_CONFIG_LAST_ENTRY
-   } TSOverridableConfigKey;
- 
-diff --git a/lib/ts/hugepages.cc b/lib/ts/hugepages.cc
-new file mode 100644
-index 0000000..900c32d
---- /dev/null
-+++ b/lib/ts/hugepages.cc
-@@ -0,0 +1,127 @@
-+/** @file
-+
-+  @section license License
-+
-+  Licensed to the Apache Software Foundation (ASF) under one
-+  or more contributor license agreements.  See the NOTICE file
-+  distributed with this work for additional information
-+  regarding copyright ownership.  The ASF licenses this file
-+  to you under the Apache License, Version 2.0 (the
-+  "License"); you may not use this file except in compliance
-+  with the License.  You may obtain a copy of the License at
-+
-+      http://www.apache.org/licenses/LICENSE-2.0
-+
-+  Unless required by applicable law or agreed to in writing, software
-+  distributed under the License is distributed on an "AS IS" BASIS,
-+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-+  See the License for the specific language governing permissions and
-+  limitations under the License.
-+ */
-+
-+#include <cstdio>
-+#include <sys/mman.h>
-+#include "Diags.h"
-+#include "ink_align.h"
-+
-+#define DEBUG_TAG "hugepages"
-+#define MEMINFO_PATH "/proc/meminfo"
-+#define LINE_SIZE 256
-+#define TOKEN "Hugepagesize:"
-+#define TOKEN_SIZE (strlen(TOKEN))
-+
-+static int hugepage_size = -1;
-+static bool hugepage_enabled;
-+
-+size_t
-+ats_hugepage_size(void)
-+{
-+#ifdef MAP_HUGETLB
-+  return hugepage_size;
-+#else
-+  Debug(DEBUG_TAG, "MAP_HUGETLB not defined");
-+  return 0;
-+#endif
-+}
-+
-+bool
-+ats_hugepage_enabled(void)
-+{
-+#ifdef MAP_HUGETLB
-+  return hugepage_enabled;
-+#else
-+  return false;
-+#endif
-+}
-+
-+void
-+ats_hugepage_init(int enabled)
-+{
-+#ifdef MAP_HUGETLB
-+  FILE *fp;
-+  char line[LINE_SIZE];
-+  char *p, *ep;
-+
-+  hugepage_size = 0;
-+
-+  if (!enabled) {
-+    Debug(DEBUG_TAG, "hugepages not enabled");
-+    return;
-+  }
-+
-+  fp = fopen(MEMINFO_PATH, "r");
-+
-+  if (fp == NULL) {
-+    Debug(DEBUG_TAG, "Cannot open file %s", MEMINFO_PATH);
-+    return;
-+  }
-+
-+  while (fgets(line, sizeof(line), fp)) {
-+    if (strncmp(line, TOKEN, TOKEN_SIZE) == 0) {
-+      p = line + TOKEN_SIZE;
-+      while (*p == ' ') {
-+        p++;
-+      }
-+      hugepage_size = strtol(p, &ep, 10);
-+      // What other values can this be?
-+      if (strncmp(ep, " kB", 4)) {
-+        hugepage_size *= 1024;
-+      }
-+      break;
-+    }
-+  }
-+
-+  fclose(fp);
-+
-+  if (hugepage_size) {
-+    hugepage_enabled = true;
-+  }
-+
-+  Debug(DEBUG_TAG, "Hugepage size = %d", hugepage_size);
-+#else
-+  Debug(DEBUG_TAG, "MAP_HUGETLB not defined");
-+#endif
-+}
-+
-+void *
-+ats_alloc_hugepage(size_t s ATS_UNUSED)
-+{
-+#ifdef MAP_HUGETLB
-+  size_t size;
-+  void *mem;
-+
-+  size = INK_ALIGN(s, ats_hugepage_size());
-+
-+  mem = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB, -1, 0);
-+
-+  if (mem == NULL) {
-+    Debug(DEBUG_TAG, "Could not allocate hugepages size = %zu", size);
-+  }
-+
-+  return mem;
-+#else
-+  (void)s;
-+  Debug(DEBUG_TAG, "MAP_HUGETLB not defined");
-+  return NULL;
-+#endif
-+}
-diff --git a/lib/ts/hugepages.h b/lib/ts/hugepages.h
-new file mode 100644
-index 0000000..5217ca5
---- /dev/null
-+++ b/lib/ts/hugepages.h
-@@ -0,0 +1,31 @@
-+/** @file
-+
-+  @section license License
-+
-+  Licensed to the Apache Software Foundation (ASF) under one
-+  or more contributor license agreements.  See the NOTICE file
-+  distributed with this work for additional information
-+  regarding copyright ownership.  The ASF licenses this file
-+  to you under the Apache License, Version 2.0 (the
-+  "License"); you may not use this file except in compliance
-+  with the License.  You may obtain a copy of the License at
-+
-+      http://www.apache.org/licenses/LICENSE-2.0
-+
-+  Unless required by applicable law or agreed to in writing, software
-+  distributed under the License is distributed on an "AS IS" BASIS,
-+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-+  See the License for the specific language governing permissions and
-+  limitations under the License.
-+ */
-+#ifndef _hugepages_h_
-+#define _hugepages_h_
-+
-+#include <cstring>
-+
-+size_t ats_hugepage_size(void);
-+bool ats_hugepage_enabled(void);
-+void ats_hugepage_init(int);
-+void *ats_alloc_hugepage(size_t);
-+
-+#endif
-diff --git a/lib/ts/ink_inet.cc b/lib/ts/ink_inet.cc
-index a841a76..e920240 100644
---- a/lib/ts/ink_inet.cc
-+++ b/lib/ts/ink_inet.cc
-@@ -97,6 +97,10 @@ ink_inet_addr(const char *s)
-   int n = 0;
-   uint32_t base = 10;
- 
-+  if (NULL == s) {
-+    return htonl((uint32_t) - 1);
-+  }
-+
-   while (n < 4) {
- 
-     u[n] = 0;
-diff --git a/lib/ts/ink_queue.cc b/lib/ts/ink_queue.cc
-index 7847b2d..fbeedf3 100644
---- a/lib/ts/ink_queue.cc
-+++ b/lib/ts/ink_queue.cc
-@@ -50,6 +50,7 @@
- #include "ink_assert.h"
- #include "ink_queue_ext.h"
- #include "ink_align.h"
-+#include "hugepages.h"
- 
- inkcoreapi volatile int64_t fastalloc_mem_in_use = 0;
- inkcoreapi volatile int64_t fastalloc_mem_total = 0;
-@@ -102,9 +103,13 @@ ink_freelist_init(InkFreeList **fl, const char *name, uint32_t type_size,
-   /* quick test for power of 2 */
-   ink_assert(!(alignment & (alignment - 1)));
-   f->alignment = alignment;
--  f->chunk_size = chunk_size;
-   // Make sure we align *all* the objects in the allocation, not just the first one
-   f->type_size = INK_ALIGN(type_size, alignment);
-+  if (ats_hugepage_enabled()) {
-+    f->chunk_size = INK_ALIGN(chunk_size * f->type_size, ats_hugepage_size()) / f->type_size;
-+  } else {
-+    f->chunk_size = chunk_size;
-+  }
-   SET_FREELIST_POINTER_VERSION(f->head, FROM_PTR(0), 0);
- 
-   f->used = 0;
-@@ -161,10 +166,15 @@ ink_freelist_new(InkFreeList * f)
- #ifdef DEBUG
-       char *oldsbrk = (char *) sbrk(0), *newsbrk = NULL;
- #endif
--      if (f->alignment)
--        newp = ats_memalign(f->alignment, f->chunk_size * type_size);
--      else
--        newp = ats_malloc(f->chunk_size * type_size);
-+      if (ats_hugepage_enabled())
-+        newp = ats_alloc_hugepage(f->chunk_size * type_size);
-+
-+      if (newp == NULL) {
-+        if (f->alignment)
-+          newp = ats_memalign(f->alignment, f->chunk_size * type_size);
-+        else
-+          newp = ats_malloc(f->chunk_size * type_size);
-+      }
-       fl_memadd(f->chunk_size * type_size);
- #ifdef DEBUG
-       newsbrk = (char *) sbrk(0);
-diff --git a/lib/ts/libts.h b/lib/ts/libts.h
-index c7cbc5e..01712d5 100644
---- a/lib/ts/libts.h
-+++ b/lib/ts/libts.h
-@@ -41,6 +41,7 @@
- #define std *** _FIXME_REMOVE_DEPENDENCY_ON_THE_STL_ ***
- */
- 
-+#include "hugepages.h"
- #include "ink_config.h"
- #include "ink_platform.h"
- #include "ink_align.h"
-diff --git a/mgmt/RecordsConfig.cc b/mgmt/RecordsConfig.cc
-index 3fbbfdd..c28a21b 100644
---- a/mgmt/RecordsConfig.cc
-+++ b/mgmt/RecordsConfig.cc
-@@ -2030,6 +2030,8 @@ static const RecordElement RecordsConfig[] =
-   ,
-   {RECT_CONFIG, "proxy.config.allocator.debug_filter", RECD_INT, "0", RECU_NULL, RR_NULL, RECC_NULL, "[0-3]", RECA_NULL}
-   ,
-+  {RECT_CONFIG, "proxy.config.allocator.hugepages", RECD_INT, "0", RECU_NULL, RR_NULL, RECC_NULL, "[0-1]", RECA_NULL}
-+  ,
- 
-   //############
-   //#
-diff --git a/plugins/cacheurl/Makefile.am b/plugins/cacheurl/Makefile.am
-index f5907fe..68391cf 100644
---- a/plugins/cacheurl/Makefile.am
-+++ b/plugins/cacheurl/Makefile.am
-@@ -17,5 +17,7 @@
- include $(top_srcdir)/build/plugins.mk
- 
- pkglib_LTLIBRARIES = cacheurl.la
--cacheurl_la_SOURCES = cacheurl.cc
-+cacheurl_la_SOURCES = \
-+  pluginconfig.cc \
-+  cacheurl.cc
- cacheurl_la_LDFLAGS = $(TS_PLUGIN_LDFLAGS)
-diff --git a/plugins/cacheurl/cacheurl.cc b/plugins/cacheurl/cacheurl.cc
-index a1a01c3..5322075 100644
---- a/plugins/cacheurl/cacheurl.cc
-+++ b/plugins/cacheurl/cacheurl.cc
-@@ -31,6 +31,8 @@
- #include <string>
- #include <vector>
- 
-+#include "pluginconfig.h"
-+
- #ifdef HAVE_PCRE_PCRE_H
- #include <pcre/pcre.h>
- #else
-@@ -51,8 +53,9 @@ struct regex_info
-   int *tokenoffset;             /* Array of $x token offsets */
- };
- 
--struct pr_list
-+class pr_list : public PluginConfig
- {
-+public:
-   std::vector<regex_info*>pr;
- 
-   pr_list()
-@@ -68,7 +71,12 @@ struct pr_list
-       TSfree(*info);
-     }
-   }
-+
-+  virtual pr_list* load(TSFile fh);
- };
-+static pr_list* load_pr_list(TSFile fh);
-+
-+#define DEFAULT_CONFIG_NAME     "cacheurl.config"
- 
- static int
- regex_substitute(char **buf, char *str, regex_info * info)
-@@ -202,16 +210,8 @@ regex_compile(regex_info ** buf, char *pattern, char *replacement)
- static pr_list *
- load_config_file(const char *config_file)
- {
--  char buffer[1024];
-   std::string path;
-   TSFile fh;
--  pr_list *prl = new pr_list();
--
--  /* locations in a config file line, end of line, split start, split end */
--  char *eol, *spstart, *spend;
--  int lineno = 0;
--  int retval;
--  regex_info *info = 0;
- 
-   if (config_file == NULL) {
-     /* Default config file of plugins/cacheurl.config */
-@@ -232,59 +232,15 @@ load_config_file(const char *config_file)
- 
-   if (!fh) {
-     TSError("[%s] Unable to open %s. No patterns will be loaded\n", PLUGIN_NAME, path.c_str());
--    return prl;
-+    return new pr_list();
-   }
- 
--  while (TSfgets(fh, buffer, sizeof(buffer) - 1)) {
--    lineno++;
--    if (*buffer == '#') {
--      /* # Comments, only at line beginning */
--      continue;
--    }
--    eol = strstr(buffer, "\n");
--    if (eol) {
--      *eol = 0;                 /* Terminate string at newline */
--    } else {
--      /* Malformed line - skip */
--      continue;
--    }
--    /* Split line into two parts based on whitespace */
--    /* Find first whitespace */
--    spstart = strstr(buffer, " ");
--    if (!spstart) {
--      spstart = strstr(buffer, "\t");
--    }
--    if (!spstart) {
--      TSError("[%s] ERROR: Invalid format on line %d. Skipping\n", PLUGIN_NAME, lineno);
--      continue;
--    }
--    /* Find part of the line after any whitespace */
--    spend = spstart + 1;
--    while (*spend == ' ' || *spend == '\t') {
--      spend++;
--    }
--    if (*spend == 0) {
--      /* We reached the end of the string without any non-whitepace */
--      TSError("[%s] ERROR: Invalid format on line %d. Skipping\n", PLUGIN_NAME, lineno);
--      continue;
--    }
-+  pr_list* config = load_pr_list(fh);
- 
--    *spstart = 0;
--    /* We have the pattern/replacement, now do precompilation.
--     * buffer is the first part of the line. spend is the second part just
--     * after the whitespace */
--    TSDebug(PLUGIN_NAME, "Adding pattern/replacement pair: '%s' -> '%s'", buffer, spend);
--    retval = regex_compile(&info, buffer, spend);
--    if (!retval) {
--      TSError("[%s] Error precompiling regex/replacement. Skipping.\n", PLUGIN_NAME);
--    }
--
--    prl->pr.push_back(info);
--  }
-   TSfclose(fh);
- 
--  TSDebug(PLUGIN_NAME, "loaded %u regexes", (unsigned) prl->pr.size());
--  return prl;
-+  TSDebug(PLUGIN_NAME, "loaded %u regexes", (unsigned) config->pr.size());
-+  return config;
- }
- 
- static int
-@@ -312,8 +268,7 @@ rewrite_cacheurl(pr_list * prl, TSHttpTxn txnp)
-     }
-     if (newurl) {
-       TSDebug(PLUGIN_NAME, "Rewriting cache URL for %s to %s", url, newurl);
--      if (TSCacheUrlSet(txnp, newurl, strlen(newurl))
--          != TS_SUCCESS) {
-+      if (TSCacheUrlSet(txnp, newurl, strlen(newurl)) != TS_SUCCESS) {
-         TSError("[%s] Unable to modify cache url from " "%s to %s\n", PLUGIN_NAME, url, newurl);
-         ok = 0;
-       }
-@@ -336,7 +291,7 @@ handle_hook(TSCont contp, TSEvent event, void *edata)
-   pr_list *prl;
-   int ok = 1;
- 
--  prl = (pr_list *) TSContDataGet(contp);
-+  prl = (pr_list*)ConfigHolder::get_config(contp);
- 
-   switch (event) {
-   case TS_EVENT_HTTP_READ_REQUEST_HDR:
-@@ -375,7 +330,7 @@ TSRemapInit(TSRemapInterface * api_info, char *errbuf, int errbuf_size)
- 
-   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));
-+        api_info->tsremap_version >> 16, (api_info->tsremap_version & 0xffff));
-     return TS_ERROR;
-   }
- 
-@@ -390,7 +345,6 @@ TSRemapNewInstance(int argc, char *argv[], void **ih, char *errbuf ATS_UNUSED, i
-   return TS_SUCCESS;
- }
- 
--
- void
- TSRemapDeleteInstance(void *ih)
- {
-@@ -417,9 +371,13 @@ TSRemapDoRemap(void *ih, TSHttpTxn rh, TSRemapRequestInfo * rri ATS_UNUSED)
- void
- TSPluginInit(int argc, const char *argv[])
- {
-+  TSCont main_cont;
-+  ConfigHolder* config_holder;
-+  const char* path;
-+
-   TSPluginRegistrationInfo info;
--  TSCont contp;
--  pr_list *prl;
-+
-+  TSDebug(PLUGIN_NAME, "TSPluginInit");
- 
-   info.plugin_name = (char *) PLUGIN_NAME;
-   info.vendor_name = (char *) "Apache Software Foundation";
-@@ -430,10 +388,91 @@ TSPluginInit(int argc, const char *argv[])
-     return;
-   }
- 
--  prl = load_config_file(argc > 1 ? argv[1] : NULL);
-+  //  prl = load_config_file(argc > 1 ? argv[1] : NULL);
-+  path = argc > 1 ? argv[1] : NULL;
-+  config_holder = new ConfigHolder(new pr_list(), DEFAULT_CONFIG_NAME, PLUGIN_NAME);
-+  TSDebug(PLUGIN_NAME, "before init_config_holder");
-+  config_holder = config_holder->init(path);
-+  TSDebug(PLUGIN_NAME, "after init_config_holder");
- 
--  contp = TSContCreate((TSEventFunc) handle_hook, NULL);
-+  main_cont = TSContCreate((TSEventFunc) handle_hook, NULL);
-   /* Store the pattern replacement list in the continuation */
--  TSContDataSet(contp, prl);
--  TSHttpHookAdd(TS_HTTP_READ_REQUEST_HDR_HOOK, contp);
-+  TSContDataSet(main_cont, config_holder);
-+  TSHttpHookAdd(TS_HTTP_READ_REQUEST_HDR_HOOK, main_cont);
-+  // TODO make configurable TS_HTTP_POST_REMAP_HOOK / TS_HTTP_READ_REQUEST_HDR_HOOK
-+
-+  config_holder->addUpdateRegister();
-+
-+}
-+static pr_list* load_pr_list(TSFile fh) {
-+  char buffer[1024];
-+  /* locations in a config file line, end of line, split start, split end */
-+  char *eol, *spstart, *spend;
-+  int lineno = 0;
-+  int retval;
-+  regex_info *info = 0;
-+  pr_list *prl = new pr_list();
-+  TSDebug(PLUGIN_NAME, "new_config");
-+
-+  if(!fh) {
-+    TSDebug(PLUGIN_NAME, "No config, using defaults");
-+    return prl;
-+  }
-+
-+  TSDebug(PLUGIN_NAME, "new_config: before loop, fh=%p", fh);
-+  while (TSfgets(fh, buffer, sizeof(buffer) - 1)) {
-+    TSDebug(PLUGIN_NAME, "new_config: enter loop, lineno=%d", lineno);
-+    lineno++;
-+    if (*buffer == '#') {
-+      /* # Comments, only at line beginning */
-+      continue;
-+    }
-+    eol = strstr(buffer, "\n");
-+    if (eol) {
-+      *eol = 0;                 /* Terminate string at newline */
-+    } else {
-+      /* Malformed line - skip */
-+      continue;
-+    }
-+    /* Split line into two parts based on whitespace */
-+    /* Find first whitespace */
-+    spstart = strstr(buffer, " ");
-+    if (!spstart) {
-+      spstart = strstr(buffer, "\t");
-+    }
-+    if (!spstart) {
-+      TSError("[%s] ERROR: Invalid format on line %d. Skipping\n", PLUGIN_NAME, lineno);
-+      continue;
-+    }
-+    /* Find part of the line after any whitespace */
-+    spend = spstart + 1;
-+    while (*spend == ' ' || *spend == '\t') {
-+      spend++;
-+    }
-+    if (*spend == 0) {
-+      /* We reached the end of the string without any non-whitepace */
-+      TSError("[%s] ERROR: Invalid format on line %d. Skipping\n", PLUGIN_NAME, lineno);
-+      continue;
-+    }
-+
-+    *spstart = 0;
-+    /* We have the pattern/replacement, now do precompilation.
-+     * buffer is the first part of the line. spend is the second part just
-+     * after the whitespace */
-+    TSDebug(PLUGIN_NAME, "Adding pattern/replacement pair: '%s' -> '%s'", buffer, spend);
-+    retval = regex_compile(&info, buffer, spend);
-+    if (!retval) {
-+      TSError("[%s] Error precompiling regex/replacement. Skipping.\n", PLUGIN_NAME);
-+    }
-+
-+    prl->pr.push_back(info);
-+  }
-+
-+  return prl;
-+}
-+
-+pr_list* pr_list::load(TSFile fh) {
-+  TSDebug(PLUGIN_NAME, "pr_list::load(TSFile fh)");
-+  return load_pr_list(fh);
-+  //  return 0;
- }
-diff --git a/plugins/cacheurl/pluginconfig.cc b/plugins/cacheurl/pluginconfig.cc
-new file mode 100644
-index 0000000..b1ad203
---- /dev/null
-+++ b/plugins/cacheurl/pluginconfig.cc
-@@ -0,0 +1,147 @@
-+/** @file
-+
-+  A brief file description
-+
-+  @section license License
-+
-+  Licensed to the Apache Software Foundation (ASF) under one
-+  or more contributor license agreements.  See the NOTICE file
-+  distributed with this work for additional information
-+  regarding copyright ownership.  The ASF licenses this file
-+  to you under the Apache License, Version 2.0 (the
-+  "License"); you may not use this file except in compliance
-+  with the License.  You may obtain a copy of the License at
-+
-+      http://www.apache.org/licenses/LICENSE-2.0
-+
-+  Unless required by applicable law or agreed to in writing, software
-+  distributed under the License is distributed on an "AS IS" BASIS,
-+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-+  See the License for the specific language governing permissions and
-+  limitations under the License.
-+ */
-+
-+/*
-+ * pluginconfig.cc
-+ *
-+ *  Created on: Jul 15, 2014
-+ *      Author: jlaue
-+ */
-+
-+#include <sys/stat.h>
-+#include <time.h>
-+#include <stdio.h>
-+
-+#include "ink_defs.h"
-+#include "ts/ts.h"
-+#include "pluginconfig.h"
-+
-+#define FREE_TMOUT              300000
-+
-+
-+static int free_handler(TSCont cont, TSEvent event, void *edata);
-+
-+PluginConfig* ConfigHolder::get_config(TSCont cont) {
-+  ConfigHolder* configh = (ConfigHolder *) TSContDataGet(cont);
-+  if(!configh) {
-+      return 0;
-+  }
-+  return configh->config;
-+}
-+void ConfigHolder::load_config_file() {
-+  TSFile fh;
-+  struct stat s;
-+
-+  PluginConfig *newconfig, *oldconfig;
-+  TSCont free_cont;
-+
-+  TSDebug(pluginName, "load_config_file() here");
-+
-+  // check date
-+  if (stat(config_path, &s) < 0) {
-+      TSDebug(pluginName, "Could not stat %s", config_path);
-+      if(config) {
-+          return;
-+      }
-+  } else {
-+      TSDebug(pluginName, "s.st_mtime=%lu, last_load=%lu", s.st_mtime, last_load);
-+      if (s.st_mtime < last_load) {
-+          return;
-+      }
-+  }
-+
-+  TSDebug(pluginName, "Opening config file: %s", config_path);
-+  fh = TSfopen(config_path, "r");
-+
-+  if (!fh) {
-+      TSError("[%s] Unable to open config: %s.\n",
-+          pluginName, config_path);
-+      return;
-+  }
-+
-+  TSDebug(pluginName, "Calling new_config: %s / %p", config_path, config);
-+  newconfig = config->load(fh);
-+  TSDebug(pluginName, "after new_config: %s", config_path);
-+  if(newconfig) {
-+      last_load = time(NULL);
-+      PluginConfig ** confp = &(config);
-+      oldconfig = __sync_lock_test_and_set(confp, newconfig);
-+      if (oldconfig) {
-+          TSDebug(pluginName, "scheduling free: %p (%p)", oldconfig, newconfig);
-+          free_cont = TSContCreate(free_handler, NULL);
-+          TSContDataSet(free_cont, (void *) oldconfig);
-+          TSContSchedule(free_cont, FREE_TMOUT, TS_THREAD_POOL_TASK);
-+      }
-+  }
-+  if(fh)
-+    TSfclose(fh);
-+  TSDebug(pluginName, "load_config_file end");
-+  return;
-+}
-+ConfigHolder* ConfigHolder::init(const char* path) {
-+  char default_config_file[1024];
-+  //      TSmalloc(32);
-+  //
-+  if(path) {
-+      config_path = TSstrdup(path);
-+  } else {
-+      /* Default config file of plugins/cacheurl.config */
-+      //              sprintf(default_config_file, "%s/astats.config", TSPluginDirGet());
-+      sprintf(default_config_file, "%s/%s", TSConfigDirGet(), default_config_name);
-+      config_path = TSstrdup(default_config_file);
-+  }
-+  TSDebug(pluginName, "calling load_config_file()");
-+  load_config_file();
-+  return this;
-+}
-+
-+
-+static int free_handler(TSCont cont, TSEvent event, void *edata) {
-+  (void) event;
-+  (void) edata;
-+  PluginConfig *config;
-+
-+  TSDebug("free_handler", "Freeing old config");
-+  config = (PluginConfig *) TSContDataGet(cont);
-+  delete (config);
-+  TSContDestroy(cont);
-+  return 0;
-+}
-+int ConfigHolder::config_handler(TSCont cont, TSEvent event, void *edata) {
-+  (void) event;
-+  (void) edata;
-+  ConfigHolder *ch;
-+
-+  ch = (ConfigHolder *) TSContDataGet(cont);
-+  TSDebug(ch->getPluginName(), "In config Handler");
-+  ch->load_config_file();
-+  return 0;
-+}
-+
-+bool ConfigHolder::addUpdateRegister() {
-+  TSCont config_cont;
-+  config_cont = TSContCreate(config_handler, TSMutexCreate());
-+  TSContDataSet(config_cont, (void *) this);
-+  TSMgmtUpdateRegister(config_cont, uniqueID);
-+  return true;
-+}
-diff --git a/plugins/cacheurl/pluginconfig.h b/plugins/cacheurl/pluginconfig.h
-new file mode 100644
-index 0000000..4a8e0a2
---- /dev/null
-+++ b/plugins/cacheurl/pluginconfig.h
-@@ -0,0 +1,77 @@
-+/** @file
-+
-+  A brief file description
-+
-+  @section license License
-+
-+  Licensed to the Apache Software Foundation (ASF) under one
-+  or more contributor license agreements.  See the NOTICE file
-+  distributed with this work for additional information
-+  regarding copyright ownership.  The ASF licenses this file
-+  to you under the Apache License, Version 2.0 (the
-+  "License"); you may not use this file except in compliance
-+  with the License.  You may obtain a copy of the License at
-+
-+      http://www.apache.org/licenses/LICENSE-2.0
-+
-+  Unless required by applicable law or agreed to in writing, software
-+  distributed under the License is distributed on an "AS IS" BASIS,
-+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-+  See the License for the specific language governing permissions and
-+  limitations under the License.
-+ */
-+
-+/*
-+ * pluginconfig.h
-+ *
-+ *  Created on: Jul 15, 2014
-+ *      Author: jlaue
-+ */
-+
-+#define UID_LEN 32
-+
-+class PluginConfig {
-+public:
-+  PluginConfig() {};
-+  virtual ~PluginConfig() {};
-+
-+  virtual PluginConfig* load(TSFile) {
-+    return 0;
-+  }
-+
-+};
-+
-+class ConfigHolder {
-+public:
-+  ConfigHolder(PluginConfig* config, const char* defaultConfigName, const char* pluginName) :
-+    config(config), log(0), config_path(0), last_load(0),
-+    default_config_name(defaultConfigName), pluginName(pluginName) {
-+    snprintf(uniqueID, UID_LEN, "%p", this);
-+  }
-+  ~ConfigHolder() {
-+    delete config;
-+    if (config_path)
-+      TSfree(config_path);
-+    if (log)
-+      TSTextLogObjectDestroy(log);
-+  }
-+  const char* getPluginName() { return pluginName; }
-+  ConfigHolder* init(const char* path);
-+  bool addUpdateRegister();
-+
-+  static PluginConfig* get_config(TSCont cont);
-+
-+private:
-+  PluginConfig* config;
-+  TSTextLogObject log;
-+  char *config_path;
-+  volatile time_t last_load;
-+  const char* default_config_name;
-+  const char *pluginName;
-+  char uniqueID[UID_LEN];
-+
-+  void load_config_file();
-+
-+  static int config_handler(TSCont cont, TSEvent event, void *edata);
-+
-+};
-diff --git a/plugins/experimental/background_fetch/background_fetch.cc b/plugins/experimental/background_fetch/background_fetch.cc
-index 4b00179..10897d9 100644
---- a/plugins/experimental/background_fetch/background_fetch.cc
-+++ b/plugins/experimental/background_fetch/background_fetch.cc
-@@ -84,8 +84,13 @@ read_config(char* config_file, BgFetchRuleMap* ri)
-     snprintf(file_path, sizeof(file_path), "%s/%s", TSInstallDirGet(), config_file);
-     file = TSfopen(file_path, "r");
-     if (file == NULL) {
--      TSError("%s: invalid config file", PLUGIN_NAME);
--      return false;
-+      TSDebug(PLUGIN_NAME, "Failed to open config file %s, trying config path", config_file);
-+      snprintf(file_path, sizeof(file_path), "%s/%s", TSConfigDirGet(), config_file);
-+      file = TSfopen(file_path, "r");
-+      if (file == NULL) {
-+        TSError("%s: invalid config file", PLUGIN_NAME);
-+        return false;
-+      }
-     }
-   }
- 
-@@ -296,6 +301,8 @@ public:
-     }
-     TSMutexUnlock(_lock);
- 
-+    TSDebug (PLUGIN_NAME, "BGFetchConfig.acquire(): ret = %d, url = %s\n", ret, url.c_str());
-+
-     return ret;
-   }
- 
-@@ -334,14 +341,14 @@ static int cont_bg_fetch(TSCont contp, TSEvent event, void* edata);
- struct BGFetchData
- {
-   BGFetchData(BGFetchConfig* cfg=gConfig)
--    : hdr_loc(TS_NULL_MLOC), url_loc(TS_NULL_MLOC), vc(NULL), _bytes(0), _cont(NULL),  _config(cfg)
-+    : hdr_loc(TS_NULL_MLOC), url_loc(TS_NULL_MLOC), vc(NULL), _bytes(0), _cont(NULL),  _config(cfg), scheduled (0)
-   {
-     mbuf = TSMBufferCreate();
-   }
- 
-   ~BGFetchData()
-   {
--    release_url();
-+    if (scheduled) release_url();
- 
-     TSHandleMLocRelease(mbuf, TS_NULL_MLOC, hdr_loc);
-     TSHandleMLocRelease(mbuf, TS_NULL_MLOC, url_loc);
-@@ -391,6 +398,7 @@ private:
-   int64_t _bytes;
-   TSCont _cont;
-   BGFetchConfig* _config;
-+  bool scheduled;
- };
- 
- 
-@@ -477,6 +485,7 @@ BGFetchData::schedule()
- 
-   // Schedule
-   TSContSchedule(_cont, 0, TS_THREAD_POOL_NET);
-+  scheduled = true;
- }
- 
- 
-diff --git a/plugins/experimental/regex_revalidate/regex_revalidate.c b/plugins/experimental/regex_revalidate/regex_revalidate.c
-index fd86a22..74d4ba1 100644
---- a/plugins/experimental/regex_revalidate/regex_revalidate.c
-+++ b/plugins/experimental/regex_revalidate/regex_revalidate.c
-@@ -40,555 +40,596 @@
- #  include <pcre.h>
- #endif
- 
--#define LOG_PREFIX        "regex_revalidate"
--#define CONFIG_TMOUT      60000
--#define FREE_TMOUT        300000
--#define OVECTOR_SIZE      30
--#define LOG_ROLL_INTERVAL 86400
--#define LOG_ROLL_OFFSET   0
-+typedef struct invalidate_t
-+{
-+  const char *regex_text;
-+  pcre *regex;
-+  pcre_extra *regex_extra;
-+  time_t epoch;
-+  time_t expiry;
-+  struct invalidate_t * volatile next;
-+} invalidate_t;
-+
-+typedef invalidate_t config_t;
-+
-+typedef struct {
-+  char *config_path;
-+  volatile time_t last_load;
-+  config_t* config;
-+  TSTextLogObject log;
-+} config_holder_t;
-+
-+static int free_handler(TSCont cont, TSEvent event, void *edata);
-+static int config_handler(TSCont cont, TSEvent event, void *edata);
-+static config_t* get_config(TSCont cont);
-+static config_holder_t* new_config_holder();
-+static config_holder_t* init_config_holder(config_holder_t* config_holder, const char* path);
-+static void free_config_holder_t(config_holder_t *config_holder);
-+static void schedule_free_invalidate_t(invalidate_t * iptr);
-+
-+#define PLUGIN_TAG              "regex_revalidate"
-+#define DEFAULT_CONFIG_NAME     "regex_revalidate.config"
-+#define PRUNE_TMOUT             60000
-+#define FREE_TMOUT              300000
-+#define OVECTOR_SIZE            30
-+#define LOG_ROLL_INTERVAL       86400
-+#define LOG_ROLL_OFFSET         0
- 
- static inline void*
- ts_malloc(size_t s)
- {
--    return TSmalloc(s);
-+  return TSmalloc(s);
- }
- 
- static inline void
- ts_free(void *s)
- {
--    return TSfree(s);
-+  return TSfree(s);
- }
- 
--typedef struct invalidate_t
--{
--    const char *regex_text;
--    pcre *regex;
--    pcre_extra *regex_extra;
--    time_t epoch;
--    time_t expiry;
--    struct invalidate_t *next;
--} invalidate_t;
--
--typedef struct
--{
--    invalidate_t * volatile invalidate_list;
--    char *config_file;
--    volatile time_t last_load;
--    TSTextLogObject log;
--} plugin_state_t;
--
- static invalidate_t *
- init_invalidate_t(invalidate_t *i)
- {
--    i->regex_text = NULL;
--    i->regex = NULL;
--    i->regex_extra = NULL;
--    i->epoch = 0;
--    i->expiry = 0;
--    i->next = NULL;
--    return i;
-+  i->regex_text = NULL;
-+  i->regex = NULL;
-+  i->regex_extra = NULL;
-+  i->epoch = 0;
-+  i->expiry = 0;
-+  i->next = NULL;
-+  return i;
- }
- 
- static void
- free_invalidate_t(invalidate_t *i)
- {
--    if (i->regex_extra)
-+  if (i->regex_extra)
- #ifndef PCRE_STUDY_JIT_COMPILE
--        pcre_free(i->regex_extra);
-+    pcre_free(i->regex_extra);
- #else
--        pcre_free_study(i->regex_extra);
-+  pcre_free_study(i->regex_extra);
- #endif
--    if (i->regex)
--        pcre_free(i->regex);
--    if (i->regex_text)
--        pcre_free_substring(i->regex_text);
--    TSfree(i);
-+  if (i->regex)
-+    pcre_free(i->regex);
-+  if (i->regex_text)
-+    pcre_free_substring(i->regex_text);
-+  TSfree(i);
- }
- 
- static void
- free_invalidate_t_list(invalidate_t *i)
- {
--    if (i->next)
--        free_invalidate_t_list(i->next);
--    free_invalidate_t(i);
--}
--
--static plugin_state_t *
--init_plugin_state_t(plugin_state_t *pstate)
--{
--    pstate->invalidate_list = NULL;
--    pstate->config_file = NULL;
--    pstate->last_load = 0;
--    pstate->log = NULL;
--    return pstate;
--}
--
--static void
--free_plugin_state_t(plugin_state_t *pstate)
--{
--    if (pstate->invalidate_list)
--        free_invalidate_t_list(pstate->invalidate_list);
--    if (pstate->config_file)
--        TSfree(pstate->config_file);
--    if (pstate->log)
--        TSTextLogObjectDestroy(pstate->log);
--    TSfree(pstate);
--}
--
--static invalidate_t *
--copy_invalidate_t(invalidate_t *i)
--{
--    invalidate_t *iptr;
--    const char *errptr;
--    int erroffset;
--
--    iptr = (invalidate_t *) TSmalloc(sizeof(invalidate_t));
--    iptr->regex_text = TSstrdup(i->regex_text);
--    iptr->regex = pcre_compile(iptr->regex_text, 0, &errptr, &erroffset, NULL); // There is no pcre_copy :-(
--    iptr->regex_extra = pcre_study(iptr->regex, 0, &errptr);                    // Assuming no errors since this worked before :-/
--    iptr->epoch = i->epoch;
--    iptr->expiry = i->expiry;
--    iptr->next = NULL;
--    return iptr;
--}
--
--static invalidate_t *
--copy_config(invalidate_t *old_list)
--{
--    invalidate_t *new_list = NULL;
--    invalidate_t *iptr_old, *iptr_new;
--
--    if (old_list)
--    {
--        new_list = copy_invalidate_t(old_list);
--        iptr_old = old_list->next;
--        iptr_new = new_list;
--        while (iptr_old)
--        {
--            iptr_new->next = copy_invalidate_t(iptr_old);
--            iptr_new = iptr_new->next;
--            iptr_old = iptr_old->next;
--        }
--    }
--
--    return new_list;
-+  if (i->next)
-+    free_invalidate_t_list(i->next);
-+  free_invalidate_t(i);
- }
- 
- static bool
- prune_config(invalidate_t **i)
- {
--    invalidate_t *iptr, *ilast;
--    time_t now;
--    bool pruned = false;
-+  invalidate_t *iptr, *ilast;
-+  time_t now;
-+  bool pruned = false;
- 
--    now = time(NULL);
-+  now = time(NULL);
- 
--    if (*i)
-+  if (*i)
-+  {
-+    iptr = *i;
-+    ilast = NULL;
-+    while (iptr)
-     {
--        iptr = *i;
--        ilast = NULL;
--        while (iptr)
-+      if (difftime(iptr->expiry, now) < 0)
-+      {
-+        TSDebug(PLUGIN_TAG, "Removing %s expiry: %d now: %d", iptr->regex_text, (int) iptr->expiry, (int) now);
-+        TSError(PLUGIN_TAG " - Removing %s expiry: %d now: %d", iptr->regex_text, (int) iptr->expiry, (int) now);
-+        if (ilast)
-         {
--            if (difftime(iptr->expiry, now) < 0)
--            {
--                TSDebug(LOG_PREFIX, "Removing %s expiry: %d now: %d", iptr->regex_text, (int) iptr->expiry, (int) now);
--                if (ilast)
--                {
--                    ilast->next = iptr->next;
--                    free_invalidate_t(iptr);
--                    iptr = ilast->next;
--                }
--                else
--                {
--                    *i = iptr->next;
--                    free_invalidate_t(iptr);
--                    iptr = *i;
--                }
--                pruned = true;
--            }
--            else
--            {
--                ilast = iptr;
--                iptr = iptr->next;
--            }
--        }
--    }
--    return pruned;
--}
-+          // jlaue: TODO is this right?
-+          //                    iptr = __sync_val_compare_and_swap(&(ilast->next), ilast->next, iptr->next);
-+          ilast->next = iptr->next;
-+          //                    free_invalidate_t(iptr);
-+          schedule_free_invalidate_t(iptr);
-+          iptr = ilast->next;
- 
--static bool
--load_config(plugin_state_t *pstate, invalidate_t **ilist)
--{
--    FILE *fs;
--    struct stat s;
--    size_t path_len;
--    char *path;
--    char line[LINE_MAX];
--    time_t now;
--    pcre *config_re;
--    const char *errptr;
--    int erroffset, ovector[OVECTOR_SIZE], rc;
--    int ln = 0;
--    invalidate_t *iptr, *i;
--
--    if (pstate->config_file[0] != '/')
--    {
--        path_len = strlen(TSConfigDirGet()) + strlen(pstate->config_file) + 2;
--        path = alloca(path_len);
--        snprintf(path, path_len, "%s/%s", TSConfigDirGet(), pstate->config_file);
--    }
--    else
--        path = pstate->config_file;
--    if (stat(path, &s) < 0)
--    {
--        TSDebug(LOG_PREFIX, "Could not stat %s", path);
--        return false;
--    }
--    if (s.st_mtime > pstate->last_load)
--    {
--        now = time(NULL);
--        if (!(fs = fopen(path, "r")))
--        {
--            TSDebug(LOG_PREFIX, "Could not open %s for reading", path);
--            return false;
-         }
--        config_re = pcre_compile("^([^#].+?)\\s+(\\d+)\\s*$", 0, &errptr, &erroffset, NULL);
--        while (fgets(line, LINE_MAX, fs) != NULL)
-+        else
-         {
--            ln++;
--            TSDebug(LOG_PREFIX, "Processing: %d %s", ln, line);
--            rc = pcre_exec(config_re, NULL, line, strlen(line), 0, 0, ovector, OVECTOR_SIZE);
--            if (rc == 3)
--            {
--                i = (invalidate_t *) TSmalloc(sizeof(invalidate_t));
--                init_invalidate_t(i);
--                pcre_get_substring(line, ovector, rc, 1, &i->regex_text);
--                i->epoch = now;
--                i->expiry = atoi(line + ovector[4]);
--                i->regex = pcre_compile(i->regex_text, 0, &errptr, &erroffset, NULL);
--                if (i->expiry <= i->epoch)
--                {
--                    TSDebug(LOG_PREFIX, "Rule is already expired!");
--                    free_invalidate_t(i);
--                }
--                else if (i->regex == NULL)
--                {
--                    TSDebug(LOG_PREFIX, "%s did not compile", i->regex_text);
--                    free_invalidate_t(i);
--                }
--                else
--                {
--                    i->regex_extra = pcre_study(i->regex, 0, &errptr);
--                    if (!*ilist)
--                    {
--                        *ilist = i;
--                        TSDebug(LOG_PREFIX, "Created new list and Loaded %s %d %d", i->regex_text, (int) i->epoch, (int) i->expiry);
--                    }
--                    else
--                    {
--                        iptr = *ilist;
--                        while(1)
--                        {
--                            if (strcmp(i->regex_text, iptr->regex_text) == 0)
--                            {
--                                if (iptr->expiry != i->expiry)
--                                {
--                                    TSDebug(LOG_PREFIX, "Updating duplicate %s", i->regex_text);
--                                    iptr->epoch = i->epoch;
--                                    iptr->expiry = i->expiry;
--                                }
--                                free_invalidate_t(i);
--                                i = NULL;
--                                break;
--                            }
--                            else if (!iptr->next)
--                                break;
--                            else
--                                iptr = iptr->next;
--                        }
--                        if (i)
--                        {
--                            iptr->next = i;
--                            TSDebug(LOG_PREFIX, "Loaded %s %d %d", i->regex_text, (int) i->epoch, (int) i->expiry);
--                        }
--                    }
--                }
--            }
--            else
--                TSDebug(LOG_PREFIX, "Skipping line %d", ln);
-+          *i = iptr->next;
-+          //                    free_invalidate_t(iptr);
-+          schedule_free_invalidate_t(iptr);
-+          iptr = *i;
-         }
--        pcre_free(config_re);
--        fclose(fs);
--        pstate->last_load = s.st_mtime;
--        return true;
-+        pruned = true;
-+      }
-+      else
-+      {
-+        ilast = iptr;
-+        iptr = iptr->next;
-+      }
-     }
--    else
--        TSDebug(LOG_PREFIX, "File mod time is not newer: %d >= %d", (int) pstate->last_load, (int) s.st_mtime);
--    return false;
-+  }
-+  return pruned;
- }
- 
-+
- static void
--list_config(plugin_state_t *pstate, invalidate_t *i)
-+list_config(config_holder_t *config_holder, invalidate_t *i)
- {
--    invalidate_t *iptr;
--
--    TSDebug(LOG_PREFIX, "Current config:");
--    if (pstate->log)
--        TSTextLogObjectWrite(pstate->log, "Current config:");
--    if (i)
--    {
--        iptr = i;
--        while (iptr)
--        {
--            TSDebug(LOG_PREFIX, "%s epoch: %d expiry: %d", iptr->regex_text, (int) iptr->epoch, (int) iptr->expiry);
--            if (pstate->log)
--                TSTextLogObjectWrite(pstate->log, "%s epoch: %d expiry: %d", iptr->regex_text, (int) iptr->epoch, (int) iptr->expiry);
--            iptr = iptr->next;
--        }
--    }
--    else
-+  invalidate_t *iptr;
-+
-+  TSDebug(PLUGIN_TAG, "Current config:");
-+  if (config_holder->log)
-+    TSTextLogObjectWrite(config_holder->log, "Current config:");
-+  if (i)
-+  {
-+    iptr = i;
-+    while (iptr)
-     {
--        TSDebug(LOG_PREFIX, "EMPTY");
--        if (pstate->log)
--            TSTextLogObjectWrite(pstate->log, "EMPTY");
-+      TSDebug(PLUGIN_TAG, "%s epoch: %d expiry: %d", iptr->regex_text, (int) iptr->epoch, (int) iptr->expiry);
-+      if (config_holder->log)
-+        TSTextLogObjectWrite(config_holder->log, "%s epoch: %d expiry: %d", iptr->regex_text, (int) iptr->epoch, (int) iptr->expiry);
-+      iptr = iptr->next;
-     }
-+  }
-+  else
-+  {
-+    TSDebug(PLUGIN_TAG, "EMPTY");
-+    if (config_holder->log)
-+      TSTextLogObjectWrite(config_holder->log, "EMPTY");
-+  }
- }
- 
- static int
--free_handler(TSCont cont, TSEvent event ATS_UNUSED, void *edata ATS_UNUSED)
-+config_pruner(TSCont cont, TSEvent event ATS_UNUSED, void *edata ATS_UNUSED)
- {
--    invalidate_t *iptr;
-+  invalidate_t *i;
- 
--    TSDebug(LOG_PREFIX, "Freeing old config");
--    iptr = (invalidate_t *) TSContDataGet(cont);
--    free_invalidate_t_list(iptr);
--    TSContDestroy(cont);
--    return 0;
--}
--
--static int
--config_handler(TSCont cont, TSEvent event ATS_UNUSED, void *edata ATS_UNUSED)
--{
--    plugin_state_t *pstate;
--    invalidate_t *i, *iptr;
--    TSCont free_cont;
--    bool updated;
--
--    TSDebug(LOG_PREFIX, "In config Handler");
--    pstate = (plugin_state_t *) TSContDataGet(cont);
--    i = copy_config(pstate->invalidate_list);
-+  TSDebug(PLUGIN_TAG, "config_pruner");
-+  config_holder_t* configh = (config_holder_t *) TSContDataGet(cont);
-+  i = configh->config;
- 
--    updated = prune_config(&i);
--    updated = load_config(pstate, &i) || updated;
--
--    if (updated)
--    {
--        list_config(pstate, i);
--        iptr = __sync_val_compare_and_swap(&(pstate->invalidate_list), pstate->invalidate_list, i);
-+  prune_config(&i);
- 
--        if (iptr)
--        {
--            free_cont = TSContCreate(free_handler, NULL);
--            TSContDataSet(free_cont, (void *) iptr);
--            TSContSchedule(free_cont, FREE_TMOUT, TS_THREAD_POOL_TASK);
--        }
--    }
--    else
--    {
--        TSDebug(LOG_PREFIX, "No Changes");
--        if (i)
--            free_invalidate_t_list(i);
--    }
-+  configh->config = i;
- 
--    TSContSchedule(cont, CONFIG_TMOUT, TS_THREAD_POOL_TASK);
--    return 0;
-+  TSContSchedule(cont, PRUNE_TMOUT, TS_THREAD_POOL_TASK);
-+  return 0;
- }
- 
- static time_t
- get_date_from_cached_hdr(TSHttpTxn txn)
- {
--    TSMBuffer buf;
--    TSMLoc hdr_loc, date_loc;
--    time_t date = 0;
--
--    if (TSHttpTxnCachedRespGet(txn, &buf, &hdr_loc) == TS_SUCCESS)
-+  TSMBuffer buf;
-+  TSMLoc hdr_loc, date_loc;
-+  time_t date = 0;
-+
-+  if (TSHttpTxnCachedRespGet(txn, &buf, &hdr_loc) == TS_SUCCESS)
-+  {
-+    date_loc = TSMimeHdrFieldFind(buf, hdr_loc, TS_MIME_FIELD_DATE, TS_MIME_LEN_DATE);
-+    if (date_loc != TS_NULL_MLOC)
-     {
--        date_loc = TSMimeHdrFieldFind(buf, hdr_loc, TS_MIME_FIELD_DATE, TS_MIME_LEN_DATE);
--        if (date_loc != TS_NULL_MLOC)
--        {
--            date = TSMimeHdrFieldValueDateGet(buf, hdr_loc, date_loc);
--             TSHandleMLocRelease(buf, hdr_loc, date_loc);
--        }
--        TSHandleMLocRelease(buf, TS_NULL_MLOC, hdr_loc);
-+      date = TSMimeHdrFieldValueDateGet(buf, hdr_loc, date_loc);
-+      TSHandleMLocRelease(buf, hdr_loc, date_loc);
-     }
-+    TSHandleMLocRelease(buf, TS_NULL_MLOC, hdr_loc);
-+  }
- 
--    return date;
-+  return date;
- }
- 
- static int
- main_handler(TSCont cont, TSEvent event, void *edata)
- {
--    TSHttpTxn txn = (TSHttpTxn) edata;
--    int status;
--    invalidate_t *iptr;
--    plugin_state_t *pstate;
--
--    time_t date = 0, now = 0;
--    char *url = NULL;
--    int url_len = 0;
--
--    switch (event)
-+  TSHttpTxn txn = (TSHttpTxn) edata;
-+  int status;
-+  invalidate_t *iptr;
-+
-+  time_t date = 0, now = 0;
-+  char *url = NULL;
-+  int url_len = 0;
-+
-+  switch (event)
-+  {
-+  case TS_EVENT_HTTP_CACHE_LOOKUP_COMPLETE:
-+    if (TSHttpTxnCacheLookupStatusGet(txn, &status) == TS_SUCCESS)
-     {
--        case TS_EVENT_HTTP_CACHE_LOOKUP_COMPLETE:
--            if (TSHttpTxnCacheLookupStatusGet(txn, &status) == TS_SUCCESS)
-+      if (status == TS_CACHE_LOOKUP_HIT_FRESH)
-+      {
-+        iptr = get_config(cont);
-+        while (iptr)
-+        {
-+          if (!date)
-+          {
-+            date = get_date_from_cached_hdr(txn);
-+            now = time(NULL);
-+          }
-+          if ((difftime(iptr->epoch, date) >= 0) && (difftime(iptr->expiry, now) >= 0))
-+          {
-+            if (!url)
-+              url = TSHttpTxnEffectiveUrlStringGet(txn, &url_len);
-+            if (pcre_exec(iptr->regex, iptr->regex_extra, url, url_len, 0, 0, NULL, 0) >= 0)
-             {
--                if (status == TS_CACHE_LOOKUP_HIT_FRESH)
--                {
--                    pstate = (plugin_state_t *) TSContDataGet(cont);
--                    iptr = pstate->invalidate_list;
--                    while (iptr)
--                    {
--                        if (!date)
--                        {
--                            date = get_date_from_cached_hdr(txn);
--                            now = time(NULL);
--                        }
--                        if ((difftime(iptr->epoch, date) >= 0) && (difftime(iptr->expiry, now) >= 0))
--                        {
--                            if (!url)
--                                url = TSHttpTxnEffectiveUrlStringGet(txn, &url_len);
--                            if (pcre_exec(iptr->regex, iptr->regex_extra, url, url_len, 0, 0, NULL, 0) >= 0)
--                            {
--                                TSHttpTxnCacheLookupStatusSet(txn, TS_CACHE_LOOKUP_HIT_STALE);
--                                iptr = NULL;
--                                TSDebug(LOG_PREFIX, "Forced revalidate - %.*s", url_len, url);
--                            }
--                        }
--                        if (iptr)
--                            iptr = iptr->next;
--                    }
--                    if (url)
--                        TSfree(url);
--                }
-+              TSHttpTxnCacheLookupStatusSet(txn, TS_CACHE_LOOKUP_HIT_STALE);
-+              iptr = NULL;
-+              TSDebug(PLUGIN_TAG, "Forced revalidate - %.*s", url_len, url);
-             }
--            break;
--        default:
--            break;
-+          }
-+          if (iptr)
-+            iptr = iptr->next;
-+        }
-+        if (url)
-+          TSfree(url);
-+      }
-     }
-+    break;
-+  default:
-+    break;
-+  }
- 
--    TSHttpTxnReenable(txn, TS_EVENT_HTTP_CONTINUE);
--    return 0;
-+  TSHttpTxnReenable(txn, TS_EVENT_HTTP_CONTINUE);
-+  return 0;
- }
- 
- static bool
- check_ts_version()
- {
--    const char *ts_version = TSTrafficServerVersionGet();
-+  const char *ts_version = TSTrafficServerVersionGet();
- 
--    if (ts_version)
--    {
--        int major_ts_version = 0;
--        int minor_ts_version = 0;
--        int micro_ts_version = 0;
-+  if (ts_version)
-+  {
-+    int major_ts_version = 0;
-+    int minor_ts_version = 0;
-+    int micro_ts_version = 0;
- 
--        if (sscanf(ts_version, "%d.%d.%d", &major_ts_version, &minor_ts_version, &micro_ts_version) != 3)
--        {
--            return false;
--        }
-+    if (sscanf(ts_version, "%d.%d.%d", &major_ts_version, &minor_ts_version, &micro_ts_version) != 3)
-+    {
-+      return false;
-+    }
- 
--        if ((TS_VERSION_MAJOR == major_ts_version) && (TS_VERSION_MINOR == minor_ts_version) && (TS_VERSION_MICRO == micro_ts_version))
--        {
--            return true;
--        }
-+    if ((TS_VERSION_MAJOR == major_ts_version) && (TS_VERSION_MINOR == minor_ts_version) && (TS_VERSION_MICRO == micro_ts_version))
-+    {
-+      return true;
-     }
-+  }
- 
--    return false;
-+  return false;
- }
- 
- void
- TSPluginInit (int argc, const char *argv[])
- {
--    TSPluginRegistrationInfo info;
--    TSCont main_cont, config_cont;
--    plugin_state_t *pstate;
--    invalidate_t *iptr = NULL;
--
--    TSDebug(LOG_PREFIX, "Starting plugin init.");
--
--    pstate = (plugin_state_t *) TSmalloc(sizeof(plugin_state_t));
--    init_plugin_state_t(pstate);
--
--    int c;
--    optind = 1;
--    static const struct option longopts[] = {
--            { "config", required_argument, NULL, 'c' },
--            { "log", required_argument, NULL, 'l' },
--            { NULL, 0, NULL, 0 }
--        };
-+  TSPluginRegistrationInfo info;
-+  TSCont main_cont, config_cont;
-+  config_holder_t* config_holder;
-+  char* path = NULL;
-+
-+  TSDebug(PLUGIN_TAG, "Starting plugin init.");
-+
-+  config_holder = new_config_holder();
-+
-+  int c;
-+  optind = 1;
-+  static const struct option longopts[] = {
-+      { "config", required_argument, NULL, 'c' },
-+      { "log", required_argument, NULL, 'l' },
-+      { NULL, 0, NULL, 0 }
-+  };
-+
-+  while ((c = getopt_long(argc, (char * const*) argv, "c:l:", longopts, NULL)) != -1)
-+  {
-+    switch (c)
-+    {
-+    case 'c':
-+      path = TSstrdup(optarg);
-+      break;
-+    case 'l':
-+      TSTextLogObjectCreate(optarg, TS_LOG_MODE_ADD_TIMESTAMP, &config_holder->log);
-+      TSTextLogObjectRollingEnabledSet(config_holder->log, 1);
-+      TSTextLogObjectRollingIntervalSecSet(config_holder->log, LOG_ROLL_INTERVAL);
-+      TSTextLogObjectRollingOffsetHrSet(config_holder->log, LOG_ROLL_OFFSET);
-+      break;
-+    default:
-+      break;
-+    }
-+  }
-+  config_holder = init_config_holder(config_holder, path);
-+
-+  if (!config_holder->config_path)
-+  {
-+    TSError("Plugin requires a --config option along with a config file name.");
-+    free_config_holder_t(config_holder);
-+    return;
-+  }
-+
-+  //    if (!load_config(free_config_holder_t, &iptr))
-+  if(config_holder->config)
-+    TSDebug(PLUGIN_TAG, "Problem loading config from file %s", config_holder->config_path);
-+  else
-+  {
-+    //        config_holder->config = iptr;
-+    list_config(config_holder, config_holder->config);
-+  }
-+
-+  info.plugin_name = PLUGIN_TAG;
-+  info.vendor_name = "Apache Software Foundation";
-+  info.support_email = "dev@trafficserver.apache.org";
-+
-+  if (TSPluginRegister(TS_SDK_VERSION_3_0 , &info) != TS_SUCCESS)
-+  {
-+    TSError("Plugin registration failed.");
-+    free_config_holder_t(config_holder);
-+    return;
-+  }
-+  else
-+    TSDebug(PLUGIN_TAG, "Plugin registration succeeded.");
-+
-+  if (!check_ts_version())
-+  {
-+    TSError("Plugin requires Traffic Server %d.%d.%d", TS_VERSION_MAJOR, TS_VERSION_MINOR, TS_VERSION_MICRO);
-+    free_config_holder_t(config_holder);
-+    return;
-+  }
-+
-+  pcre_malloc = &ts_malloc;
-+  pcre_free = &ts_free;
-+
-+  main_cont = TSContCreate(main_handler, NULL);
-+  TSContDataSet(main_cont, (void *) config_holder);
-+  TSHttpHookAdd(TS_HTTP_CACHE_LOOKUP_COMPLETE_HOOK, main_cont);
-+
-+  config_cont = TSContCreate(config_pruner, TSMutexCreate());
-+  TSContDataSet(config_cont, (void *) config_holder);
-+  TSContSchedule(config_cont, PRUNE_TMOUT, TS_THREAD_POOL_TASK);
-+
-+  config_cont = TSContCreate(config_handler, TSMutexCreate());
-+  TSContDataSet(config_cont, (void *) config_holder);
-+  TSMgmtUpdateRegister(config_cont, PLUGIN_TAG);
-+
-+  TSDebug(PLUGIN_TAG, "Plugin Init Complete.");
-+}
- 
--    while ((c = getopt_long(argc, (char * const*) argv, "c:l:", longopts, NULL)) != -1)
-+static config_t*
-+new_config(TSFile fs) {
-+  char line[LINE_MAX];
-+  time_t now;
-+  pcre *config_re;
-+  const char *errptr;
-+  int erroffset, ovector[OVECTOR_SIZE], rc;
-+  int ln = 0;
-+  invalidate_t *iptr, *i, *config=0;
-+
-+  now = time(NULL);
-+
-+  config_re = pcre_compile("^([^#].+?)\\s+(\\d+)\\s*$", 0, &errptr, &erroffset, NULL);
-+  while (TSfgets(fs, line, LINE_MAX-1) != NULL)
-+  {
-+    ln++;
-+    TSDebug(PLUGIN_TAG, "Processing: %d %s", ln, line);
-+    rc = pcre_exec(config_re, NULL, line, strlen(line), 0, 0, ovector, OVECTOR_SIZE);
-+    if (rc == 3)
-     {
--        switch (c)
-+      i = (invalidate_t *) TSmalloc(sizeof(invalidate_t));
-+      init_invalidate_t(i);
-+      pcre_get_substring(line, ovector, rc, 1, &i->regex_text);
-+      i->epoch = now;
-+      i->expiry = atoi(line + ovector[4]);
-+      i->regex = pcre_compile(i->regex_text, 0, &errptr, &erroffset, NULL);
-+      if (i->expiry <= i->epoch)
-+      {
-+        TSDebug(PLUGIN_TAG, "NOT Loaded, already expired! %s %d %d", i->regex_text, (int) i->epoch, (int) i->expiry);
-+        TSError(PLUGIN_TAG " - NOT Loaded, already expired: %s %d %d", i->regex_text, (int) i->epoch, (int) i->expiry);
-+        free_invalidate_t(i);
-+      }
-+      else if (i->regex == NULL)
-+      {
-+        TSDebug(PLUGIN_TAG, "%s did not compile", i->regex_text);
-+        free_invalidate_t(i);
-+      }
-+      else
-+      {
-+        i->regex_extra = pcre_study(i->regex, 0, &errptr);
-+        if (!config)
-         {
--            case 'c':
--                pstate->config_file = TSstrdup(optarg);
--                break;
--            case 'l':
--                TSTextLogObjectCreate(optarg, TS_LOG_MODE_ADD_TIMESTAMP, &pstate->log);
--                TSTextLogObjectRollingEnabledSet(pstate->log, 1);
--                TSTextLogObjectRollingIntervalSecSet(pstate->log, LOG_ROLL_INTERVAL);
--                TSTextLogObjectRollingOffsetHrSet(pstate->log, LOG_ROLL_OFFSET);
--                break;
--            default:
--                break;
-+          config = i;
-+          TSDebug(PLUGIN_TAG, "Created new list and Loaded %s %d %d", i->regex_text, (int) i->epoch, (int) i->expiry);
-+          TSError(PLUGIN_TAG " - New Revalidate: %s %d %d", i->regex_text, (int) i->epoch, (int) i->expiry);
-+        }
-+        else
-+        {
-+          iptr = config;
-+          while(1)
-+          {
-+            if (strcmp(i->regex_text, iptr->regex_text) == 0)
-+            {
-+              if (iptr->expiry != i->expiry)
-+              {
-+                TSDebug(PLUGIN_TAG, "Updating duplicate %s", i->regex_text);
-+                iptr->epoch = i->epoch;
-+                iptr->expiry = i->expiry;
-+              }
-+              free_invalidate_t(i);
-+              i = NULL;
-+              break;
-+            }
-+            else if (!iptr->next)
-+              break;
-+            else
-+              iptr = iptr->next;
-+          }
-+          if (i)
-+          {
-+            iptr->next = i;
-+            TSDebug(PLUGIN_TAG, "Loaded %s %d %d", i->regex_text, (int) i->epoch, (int) i->expiry);
-+          }
-         }
-+      }
-     }
-+    else
-+      TSDebug(PLUGIN_TAG, "Skipping line %d", ln);
-+  }
-+  pcre_free(config_re);
- 
--    if (!pstate->config_file)
--    {
--        TSError("Plugin requires a --config option along with a config file name.");
--        free_plugin_state_t(pstate);
--        return;
--    }
-+  return config;
-+}
- 
--    if (!load_config(pstate, &iptr))
--        TSDebug(LOG_PREFIX, "Problem loading config from file %s", pstate->config_file);
--    else
--    {
--        pstate->invalidate_list = iptr;
--        list_config(pstate, iptr);
--    }
-+static void
-+delete_config(config_t* config) {
-+  TSDebug(PLUGIN_TAG, "Freeing config");
-+  free_invalidate_t_list(config);
-+}
- 
--    info.plugin_name = LOG_PREFIX;
--    info.vendor_name = "Apache Software Foundation";
--    info.support_email = "dev@trafficserver.apache.org";
-+static int
-+free_invalidate_handler(TSCont cont, TSEvent event ATS_UNUSED, void *edata ATS_UNUSED) {
-+  invalidate_t* i = (invalidate_t *) TSContDataGet(cont);
-+  free_invalidate_t(i);
-+  TSContDestroy(cont);
-+  return 0;
-+}
- 
--    if (TSPluginRegister(TS_SDK_VERSION_3_0 , &info) != TS_SUCCESS)
--    {
--        TSError("Plugin registration failed.");
--        free_plugin_state_t(pstate);
--        return;
--    }
--    else
--        TSDebug(LOG_PREFIX, "Plugin registration succeeded.");
-+static void
-+schedule_free_invalidate_t(invalidate_t * iptr) {
-+  TSCont free_cont;
-+  free_cont = TSContCreate(free_invalidate_handler, NULL);
-+  TSContDataSet(free_cont, (void *) iptr);
-+  TSContSchedule(free_cont, FREE_TMOUT, TS_THREAD_POOL_TASK);
-+  return;
-+}
- 
--    if (!check_ts_version())
--    {
--        TSError("Plugin requires Traffic Server %d.%d.%d", TS_VERSION_MAJOR, TS_VERSION_MINOR, TS_VERSION_MICRO);
--        free_plugin_state_t(pstate);
--        return;
-+static config_t*
-+get_config(TSCont cont) {
-+  config_holder_t* configh = (config_holder_t *) TSContDataGet(cont);
-+  if(!configh) {
-+    return 0;
-+  }
-+  return configh->config;
-+}
-+
-+static void
-+load_config_file(config_holder_t *config_holder) {
-+  TSFile fh;
-+  struct stat s;
-+
-+  config_t *newconfig, *oldconfig;
-+  TSCont free_cont;
-+
-+  // check date
-+  if (stat(config_holder->config_path, &s) < 0) {
-+    TSDebug(PLUGIN_TAG, "Could not stat %s", config_holder->config_path);
-+    if(config_holder->config) {
-+      return;
-+    }
-+  } else {
-+    TSDebug(PLUGIN_TAG, "s.st_mtime=%lu, last_load=%lu", s.st_mtime, config_holder->last_load);
-+    if (s.st_mtime < config_holder->last_load) {
-+      return;
-     }
-+  }
-+
-+  TSDebug(PLUGIN_TAG, "Opening config file: %s", config_holder->config_path);
-+  fh = TSfopen(config_holder->config_path, "r");
-+  TSError(PLUGIN_TAG " - Reading config: %s", config_holder->config_path);
-+
-+  if (!fh) {
-+    TSError("[%s] Unable to open config: %s.\n",
-+        PLUGIN_TAG, config_holder->config_path);
-+    return;
-+  }
-+
-+  newconfig = 0;
-+  newconfig = new_config(fh);
-+  if(newconfig) {
-+    config_holder->last_load = time(NULL);
-+    config_t ** confp = &(config_holder->config);
-+    oldconfig = __sync_lock_test_and_set(confp, newconfig);
-+    if (oldconfig) {
-+      TSDebug(PLUGIN_TAG, "scheduling free: %p (%p)", oldconfig, newconfig);
-+      free_cont = TSContCreate(free_handler, NULL);
-+      TSContDataSet(free_cont, (void *) oldconfig);
-+      TSContSchedule(free_cont, FREE_TMOUT, TS_THREAD_POOL_TASK);
-+    }
-+  }
-+  if(fh)
-+    TSfclose(fh);
-+  return;
-+}
- 
--    pcre_malloc = &ts_malloc;
--    pcre_free = &ts_free;
-+static config_holder_t*
-+new_config_holder(void) {
-+  config_holder_t* config_holder = TSmalloc(sizeof(config_holder_t));
-+  return config_holder;
-+}
- 
--    main_cont = TSContCreate(main_handler, NULL);
--    TSContDataSet(main_cont, (void *) pstate);
--    TSHttpHookAdd(TS_HTTP_CACHE_LOOKUP_COMPLETE_HOOK, main_cont);
-+static config_holder_t*
-+init_config_holder(config_holder_t* config_holder, const char* path) {
-+  int path_len = 0;
-+  config_holder->config_path = 0;
-+  config_holder->config = 0;
-+  config_holder->last_load = 0;
-+  config_holder->log = 0;
-+
-+  if(!path) path = DEFAULT_CONFIG_NAME;
-+  if (path[0] != '/')
-+  {
-+    path_len = strlen(TSConfigDirGet()) + strlen(path) + 2;
-+    config_holder->config_path = ts_malloc(path_len);
-+    snprintf(config_holder->config_path, path_len, "%s/%s", TSConfigDirGet(), path);
-+    TSDebug(PLUGIN_TAG, "path: '%s' len=%d", config_holder->config_path, path_len);
-+  } else
-+    config_holder->config_path = TSstrdup(path);
-+
-+  load_config_file(config_holder);
-+  return config_holder;
-+}
- 
--    config_cont = TSContCreate(config_handler, TSMutexCreate());
--    TSContDataSet(config_cont, (void *) pstate);
--    TSContSchedule(config_cont, CONFIG_TMOUT, TS_THREAD_POOL_TASK);
-+static void
-+free_config_holder_t(config_holder_t *config_holder)
-+{
-+  if (config_holder->config)
-+    free_invalidate_t_list(config_holder->config);
-+  if (config_holder->config_path)
-+    TSfree(config_holder->config_path);
-+  if (config_holder->log)
-+    TSTextLogObjectDestroy(config_holder->log);
-+  TSfree(config_holder);
-+}
-+
-+static int
-+free_handler(TSCont cont, TSEvent event ATS_UNUSED, void *edata ATS_UNUSED) {
-+  config_t *config;
-+
-+  TSDebug(PLUGIN_TAG, "Freeing old config");
-+  config = (config_t *) TSContDataGet(cont);
-+  delete_config(config);
-+  TSContDestroy(cont);
-+  return 0;
-+}
-+
-+static int
-+config_handler(TSCont cont, TSEvent event ATS_UNUSED, void *edata ATS_UNUSED) {
-+  config_holder_t *config_holder;
- 
--    TSDebug(LOG_PREFIX, "Plugin Init Complete.");
-+  TSDebug(PLUGIN_TAG, "In config Handler");
-+  config_holder = (config_holder_t *) TSContDataGet(cont);
-+  load_config_file(config_holder);
-+  return 0;
- }
-diff --git a/plugins/experimental/remap_stats/remap_stats.c b/plugins/experimental/remap_stats/remap_stats.c
-index 5efd52d..0d78bab 100644
---- a/plugins/experimental/remap_stats/remap_stats.c
-+++ b/plugins/experimental/remap_stats/remap_stats.c
-@@ -43,7 +43,6 @@ typedef struct
-   TSMutex stat_creation_mutex;
- } config_t;
- 
--
- static void
- stat_add(char *name, TSMgmtInt amount, TSStatPersistence persist_type, TSMutex create_mutex)
- {
-@@ -91,7 +90,6 @@ stat_add(char *name, TSMgmtInt amount, TSStatPersistence persist_type, TSMutex c
-     TSDebug(DEBUG_TAG, "stat error! stat_name: %s stat_id: %d", name, stat_id);
- }
- 
--
- static char *
- get_effective_host(TSHttpTxn txn)
- {
-@@ -114,7 +112,6 @@ get_effective_host(TSHttpTxn txn)
-   return tmp;
- }
- 
--
- static int
- handle_read_req_hdr(TSCont cont, TSEvent event ATS_UNUSED, void *edata)
- {
-@@ -131,7 +128,6 @@ handle_read_req_hdr(TSCont cont, TSEvent event ATS_UNUSED, void *edata)
-   return 0;
- }
- 
--
- static int
- handle_post_remap(TSCont cont, TSEvent event ATS_UNUSED, void *edata)
- {
-@@ -153,10 +149,8 @@ handle_post_remap(TSCont cont, TSEvent event ATS_UNUSED, void *edata)
-   return 0;
- }
- 
--
- #define CREATE_STAT_NAME(s,h,b) snprintf(s, MAX_STAT_LENGTH, "plugin.%s.%s.%s", PLUGIN_NAME, h, b)
- 
--
- static int
- handle_txn_close(TSCont cont, TSEvent event ATS_UNUSED, void *edata)
- {
-diff --git a/plugins/experimental/stale_while_revalidate/stale_while_revalidate.c b/plugins/experimental/stale_while_revalidate/stale_while_revalidate.c
-index 4b3ba98..2a4e363 100644
---- a/plugins/experimental/stale_while_revalidate/stale_while_revalidate.c
-+++ b/plugins/experimental/stale_while_revalidate/stale_while_revalidate.c
-@@ -293,6 +293,7 @@ consume_resource(TSCont cont, TSEvent event ATS_UNUSED, void *edata ATS_UNUSED)
-         case TS_EVENT_VCONN_WRITE_READY:
-             // We shouldn't get here because we specify the exact size of the buffer.
-             TSDebug(PLUGIN_NAME, "Write Ready");
-+            break;
-         case TS_EVENT_VCONN_WRITE_COMPLETE:
-             TSDebug(PLUGIN_NAME, "Write Complete");
-             //TSDebug(PLUGIN_NAME, "TSVConnShutdown()");
-@@ -509,6 +510,8 @@ main_plugin(TSCont cont, TSEvent event, void *edata)
-     TSHttpStatus http_status;
-     config_t *plugin_config;
- 
-+    TSDebug(PLUGIN_NAME, "main_plugin: %d", event);
-+
-     switch (event)
-     {
-         // Is this the proper event?
-@@ -651,6 +654,7 @@ main_plugin(TSCont cont, TSEvent event, void *edata)
-             TSHttpTxnReenable(txn, TS_EVENT_HTTP_CONTINUE);
-             break;
-         default:
-+            TSDebug(PLUGIN_NAME, "unknown event: %d", event);
-             TSHttpTxnReenable(txn, TS_EVENT_HTTP_CONTINUE);
-             break;
-     }
-@@ -674,10 +678,8 @@ TSPluginInit (int argc, const char *argv[])
-         TSError("Plugin registration failed.\n");
-         return;
-     }
--    else
--    {
--        TSDebug(PLUGIN_NAME, "Plugin registration succeeded.\n");
--    }
-+
-+    TSDebug(PLUGIN_NAME, "Plugin registration succeeded.\n");
- 
-     plugin_config = TSmalloc(sizeof(config_t));
- 
-@@ -736,6 +738,7 @@ TSPluginInit (int argc, const char *argv[])
-     main_cont = TSContCreate(main_plugin, NULL);
-     TSContDataSet(main_cont, (void *) plugin_config);
-     TSHttpHookAdd(TS_HTTP_READ_REQUEST_HDR_HOOK, main_cont);
-+//    TSHttpHookAdd(TS_HTTP_SELECT_ALT_HOOK, main_cont);
- 
-     TSDebug(PLUGIN_NAME, "Plugin Init Complete.\n");
- }
-diff --git a/plugins/experimental/url_sig/url_sig.c b/plugins/experimental/url_sig/url_sig.c
-index e063791..f5742bb 100644
---- a/plugins/experimental/url_sig/url_sig.c
-+++ b/plugins/experimental/url_sig/url_sig.c
-@@ -31,18 +31,24 @@
- #include <limits.h>
- #include <ctype.h>
- 
-+#ifdef HAVE_PCRE_PCRE_H
-+#include <pcre/pcre.h>
-+#else
-+#include <pcre.h>
-+#endif
-+
- #include <ts/ts.h>
- #include <ts/remap.h>
- 
--static const char *PLUGIN_NAME = "url_sig";
-+#define PLUGIN_NAME "url_sig"
- 
- struct config
- {
--  char *map_from;
--  char *map_to;
-   TSHttpStatus err_status;
-   char *err_url;
-   char keys[MAX_KEY_NUM][MAX_KEY_LEN];
-+  pcre *regex;
-+  pcre_extra *regex_extra;
- };
- 
- TSReturnCode
-@@ -68,25 +74,21 @@ TSReturnCode
- TSRemapNewInstance(int argc, char *argv[], void **ih, char *errbuf, int errbuf_size)
- {
-   char config_file[PATH_MAX];
-+  int i;
-   struct config *cfg;
- 
-   cfg = TSmalloc(sizeof(struct config));
-+  memset(cfg, 0, sizeof(struct config));
-   *ih = (void *) cfg;
- 
--  int i = 0;
--  for (i = 0; i < MAX_KEY_NUM; i++) {
--    cfg->keys[i][0] = '\0';
--  }
--
-   if (argc != 3) {
-     snprintf(errbuf, errbuf_size - 1,
-              "[TSRemapNewKeyInstance] - Argument count wrong (%d)... Need exactly two pparam= (config file name).",
-              argc);
-     return TS_ERROR;
-   }
-+
-   TSDebug(PLUGIN_NAME, "Initializing remap function of %s -> %s with config from %s", argv[0], argv[1], argv[2]);
--  cfg->map_from = TSstrndup(argv[0], strlen(argv[0]));
--  cfg->map_to = TSstrndup(argv[0], strlen(argv[1]));
- 
-   const char *install_dir = TSInstallDirGet();
-   snprintf(config_file, sizeof(config_file), "%s/%s/%s", install_dir, "etc/trafficserver", argv[2]);
-@@ -157,6 +159,25 @@ TSRemapNewInstance(int argc, char *argv[], void **ih, char *errbuf, int errbuf_s
-         cfg->err_url = TSstrndup(value, strlen(value));
-       else
-         cfg->err_url = NULL;
-+    } else if (strncmp(line, "excl_regex", 10) == 0) {
-+      // compile and study regex
-+      const char *errptr;
-+      int erroffset, options = 0;
-+
-+      if (cfg->regex) {
-+        TSDebug(PLUGIN_NAME, "Skipping duplicate excl_regex");
-+        continue;
-+      }
-+
-+      cfg->regex = pcre_compile(value, options, &errptr, &erroffset, NULL);
-+      if (cfg->regex == NULL) {
-+        TSDebug(PLUGIN_NAME, "Regex compilation failed with error (%s) at character %d.", errptr, erroffset);
-+      } else {
-+#ifdef PCRE_STUDY_JIT_COMPILE
-+        options = PCRE_STUDY_JIT_COMPILE;
-+#endif
-+        cfg->regex_extra = pcre_study(cfg->regex, options, &errptr); // We do not need to check the error here because we can still run without the studying?
-+      }
-     } else {
-       TSError("Error parsing line %d of file %s (%s).", line_no, config_file, line);
-     }
-@@ -199,13 +220,22 @@ TSRemapDeleteInstance(void *ih)
-   cfg = (struct config *) ih;
- 
-   TSError("Cleaning up...");
--  TSfree(cfg->map_from);
--  TSfree(cfg->map_to);
-   TSfree(cfg->err_url);
-+
-+  if (cfg->regex_extra)
-+#ifndef PCRE_STUDY_JIT_COMPILE
-+    pcre_free(cfg->regex_extra);
-+#else
-+    pcre_free_study(cfg->regex_extra);
-+#endif
-+
-+  if (cfg->regex)
-+        pcre_free(cfg->regex);
-+
-   TSfree(cfg);
- }
- 
--void
-+static void
- err_log(char *url, char *msg)
- {
-   if (msg && url) {
-@@ -262,6 +292,24 @@ TSRemapDoRemap(void *ih, TSHttpTxn txnp, TSRemapRequestInfo * rri)
-   TSDebug(PLUGIN_NAME, "%s", url);
- 
-   query = strstr(url, "?");
-+
-+  if (cfg->regex) {
-+    int offset = 0, options = 0;
-+    int ovector[30];
-+    int len = url_len;
-+    char *anchor = strstr(url, "#");
-+    if (query && !anchor) {
-+      len -= (query - url);
-+    } else if (anchor && !query) {
-+      len -= (anchor - url);
-+    } else if (anchor && query) {
-+      len -= ((query < anchor ? query : anchor) - url);
-+    }
-+    if (pcre_exec(cfg->regex, cfg->regex_extra, url, len, offset, options, ovector, 30) >= 0) {
-+      goto allow;
-+    }
-+  }
-+
-   if (query == NULL) {
-     err_log(url, "Has no query string.");
-     goto deny;
-diff --git a/plugins/header_rewrite/Examples/header_rewrite.config b/plugins/header_rewrite/Examples/header_rewrite.config
-new file mode 100644
-index 0000000..c1aa7a2
---- /dev/null
-+++ b/plugins/header_rewrite/Examples/header_rewrite.config
-@@ -0,0 +1,3 @@
-+include header_rewrite/Regression
-+include header_rewrite/YCS-EC
-+#include header_rewrite/Force-close
-diff --git a/plugins/header_rewrite/Makefile.am b/plugins/header_rewrite/Makefile.am
-index 4a6ca58..bd09044 100644
---- a/plugins/header_rewrite/Makefile.am
-+++ b/plugins/header_rewrite/Makefile.am
-@@ -28,6 +28,7 @@ header_rewrite_la_SOURCES = \
-   operator.cc \
-   operators.cc \
-   parser.cc \
-+  pluginconfig.cc \
-   regex_helper.cc \
-   resources.cc \
-   ruleset.cc \
-diff --git a/plugins/header_rewrite/conditions.cc b/plugins/header_rewrite/conditions.cc
-index be3d28b..04fb456 100644
---- a/plugins/header_rewrite/conditions.cc
-+++ b/plugins/header_rewrite/conditions.cc
-@@ -72,6 +72,49 @@ ConditionStatus::append_value(std::string& s, const Resources& res)
- }
- 
- 
-+// ConditionMethod
-+void
-+ConditionMethod::initialize(Parser& p)
-+{
-+  Condition::initialize(p);
-+
-+  Matchers<std::string>* match = new Matchers<std::string>(_cond_op);
-+  match->set(p.get_arg());
-+
-+  _matcher = match;
-+}
-+
-+bool
-+ConditionMethod::eval(const Resources& res)
-+{
-+  std::string s;
-+
-+  append_value(s, res);
-+  bool rval = static_cast<const Matchers<std::string>*>(_matcher)->test(s);
-+  TSDebug(PLUGIN_NAME, "Evaluating METHOD(): %s - rval: %d", s.c_str(), rval);
-+  return rval;
-+}
-+
-+
-+void
-+ConditionMethod::append_value(std::string& s, const Resources& res)
-+{
-+  TSMBuffer bufp;
-+  TSMLoc hdr_loc;
-+  const char* value;
-+  int len;
-+
-+  bufp = res.client_bufp;
-+  hdr_loc = res.client_hdr_loc;
-+
-+  if (bufp && hdr_loc) {
-+    value = TSHttpHdrMethodGet(bufp, hdr_loc, &len);
-+    TSDebug(PLUGIN_NAME, "Appending METHOD(%s) to evaluation value -> %.*s", _qualifier.c_str(), len, value);
-+    s.append(value, len);
-+  }
-+}
-+
-+
- // ConditionRandom: random 0 to (N-1)
- void
- ConditionRandom::initialize(Parser& p)
-diff --git a/plugins/header_rewrite/conditions.h b/plugins/header_rewrite/conditions.h
-index fbb843d..f540df1 100644
---- a/plugins/header_rewrite/conditions.h
-+++ b/plugins/header_rewrite/conditions.h
-@@ -101,6 +101,25 @@ private:
- };
- 
- 
-+// Check the HTTP method
-+class ConditionMethod : public Condition
-+{
-+public:
-+  ConditionMethod()
-+  {
-+    TSDebug(PLUGIN_NAME_DBG, "Calling CTOR for ConditionMethod");
-+  }
-+  void initialize(Parser& p);
-+  void append_value(std::string& s, const Resources& res);
-+
-+protected:
-+  bool eval(const Resources& res);
-+
-+private:
-+  DISALLOW_COPY_AND_ASSIGN(ConditionMethod);
-+};
-+
-+
- // Random 0 to (N-1)
- class ConditionRandom : public Condition
- {
-diff --git a/plugins/header_rewrite/factory.cc b/plugins/header_rewrite/factory.cc
-index eb44369..2db74df 100644
---- a/plugins/header_rewrite/factory.cc
-+++ b/plugins/header_rewrite/factory.cc
-@@ -59,6 +59,8 @@ operator_factory(const std::string& op)
-     o = new OperatorCounter();
-   } else if (op == "set-conn-dscp") {
-     o = new OperatorSetConnDSCP();
-+  } else if (op == "set-method") {
-+    o = new OperatorSetMethod();
-   } else {
-     TSError("%s: unknown operator: %s", PLUGIN_NAME, op.c_str());
-     return NULL;
-@@ -115,6 +117,8 @@ condition_factory(const std::string& cond)
-     c = new ConditionClientIp();
-   } else if (c_name == "INCOMING-PORT") {
-     c = new ConditionIncomingPort();
-+  } else if (c_name == "METHOD") {
-+    c = new ConditionMethod();
-   } else {
-     TSError("%s: unknown condition: %s", PLUGIN_NAME, c_name.c_str());
-     return NULL;
-diff --git a/plugins/header_rewrite/header_rewrite.cc b/plugins/header_rewrite/header_rewrite.cc
-index 1202545..f58cbd7 100644
---- a/plugins/header_rewrite/header_rewrite.cc
-+++ b/plugins/header_rewrite/header_rewrite.cc
-@@ -25,11 +25,14 @@
- #include "ruleset.h"
- #include "resources.h"
- 
-+#include "pluginconfig.h"
-+
- // Debugs
- const char PLUGIN_NAME[] = "header_rewrite";
- const char PLUGIN_NAME_DBG[] = "dbg_header_rewrite";
- 
- const char* HOOK_NAMES[] = {
-+  "TS_HTTP_TXN_START_HOOK",
-   "TS_HTTP_READ_REQUEST_HDR_HOOK",
-   "TS_HTTP_OS_DNS_HOOK",
-   "TS_HTTP_SEND_REQUEST_HDR_HOOK",
-@@ -47,26 +50,25 @@ const char* HOOK_NAMES[] = {
-   "TS_HTTP_PRE_REMAP_HOOK",
-   "TS_HTTP_POST_REMAP_HOOK",
-   "TS_HTTP_RESPONSE_CLIENT_HOOK",
-+  "TS_HTTP_TXN_CLOSE_HOOK",
-   "TS_HTTP_

<TRUNCATED>