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, µ_ts_version) != 3)
-- {
-- return false;
-- }
-+ if (sscanf(ts_version, "%d.%d.%d", &major_ts_version, &minor_ts_version, µ_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>