You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by br...@apache.org on 2013/10/18 23:51:08 UTC

[1/5] initial atscppapi commit

Updated Branches:
  refs/heads/master cc25667ca -> 7b2ea5f89


http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/src/include/atscppapi/noncopyable.h
----------------------------------------------------------------------
diff --git a/lib/atscppapi/src/include/atscppapi/noncopyable.h b/lib/atscppapi/src/include/atscppapi/noncopyable.h
new file mode 100644
index 0000000..6c1c5f4
--- /dev/null
+++ b/lib/atscppapi/src/include/atscppapi/noncopyable.h
@@ -0,0 +1,64 @@
+/**
+  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.
+ */
+
+/**
+ * @file noncopyable.h
+ * @brief A base class used to prevent dervied classes from being copyable, this effectively
+ * eliminates the copy constructor and assignment operator.
+ */
+
+#pragma once
+#ifndef ATSCPPAPI_NONCOPYABLE_H_
+#define ATSCPPAPI_NONCOPYABLE_H_
+
+namespace atscppapi {
+
+/**
+ * @brief noncopyable is a base class that will prevent derived classes from being copied.
+ *
+ * @private Prevent Doxygen from showing this class in the inheritance diagrams.
+ *
+ * To use noncopyable you only need to inherit from this class and you're derived class
+ * will become uncopyable
+ *
+ * \code
+ * class myClass : uncopyable {
+ * public:
+ *  int test_;
+ * }
+ *
+ * // The following will fail:
+ * myClass a;
+ * myClass b(a); // fails
+ * myClass c = a; // fails
+ * \endcode
+ */
+class noncopyable
+{
+protected:
+  noncopyable() {}
+  ~noncopyable() {}
+private:
+  noncopyable(const noncopyable&);
+  const noncopyable& operator=(const noncopyable&);
+};
+
+} /* atscppapi */
+
+
+#endif /* ATSCPPAPI_NONCOPYABLE_H_ */

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/src/include/atscppapi/shared_ptr.h
----------------------------------------------------------------------
diff --git a/lib/atscppapi/src/include/atscppapi/shared_ptr.h b/lib/atscppapi/src/include/atscppapi/shared_ptr.h
new file mode 100644
index 0000000..3207405
--- /dev/null
+++ b/lib/atscppapi/src/include/atscppapi/shared_ptr.h
@@ -0,0 +1,41 @@
+/**
+  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.
+ */
+/**
+ * @file shared_ptr.h
+ *
+ * Shared pointer declaration.
+ */
+
+#pragma once
+#ifndef ASTCPPAPI_SHARED_PTR_H_
+#define ASTCPPAPI_SHARED_PTR_H_
+
+#include <tr1/memory>
+
+namespace atscppapi {
+
+/**
+ * Force the use of std::tr1::shared_ptr
+ * \todo Consider adding a simple macro to check if c++0x/11 is enabled
+ * and if so change it to std::shared_ptr and #include <memory>s
+ */
+using std::tr1::shared_ptr;
+
+} /* atscppapi */
+
+#endif /* SHARED_PTR_H_ */

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/src/include/atscppapi/utils.h
----------------------------------------------------------------------
diff --git a/lib/atscppapi/src/include/atscppapi/utils.h b/lib/atscppapi/src/include/atscppapi/utils.h
new file mode 100644
index 0000000..85b8c9e
--- /dev/null
+++ b/lib/atscppapi/src/include/atscppapi/utils.h
@@ -0,0 +1,69 @@
+/**
+  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.
+ */
+
+/**
+ * @file utils.h
+ * @brief Contains utility functions available to users of the api.
+ *
+ */
+
+#pragma once
+#ifndef ATSCPPAPI_UTILS_H_
+#define ATSCPPAPI_UTILS_H_
+
+#include <string>
+#include <arpa/inet.h>
+#include <stdint.h>
+
+namespace atscppapi {
+namespace utils {
+
+/**
+ * @brief Returns a pretty printed string of a sockaddr *
+ *
+ * @param sockaddr* A pointer to a sockaddr *
+ * @return a string which is the pretty printed address
+ */
+std::string getIpString(const sockaddr *);
+
+/**
+ * @brief Returns just the port portion of the sockaddr *
+ *
+ * @param sockaddr* A pointer to a sockaddr *
+ * @return a uint16_t which is the port from the sockaddr *
+ */
+uint16_t getPort(const sockaddr *);
+
+/**
+ * @brief Returns a pretty printed string of a sockaddr * including port
+ *
+ * @param sockaddr* A pointer to a sockaddr *
+ * @return a string which is the pretty printed address including port
+ */
+std::string getIpPortString(const sockaddr *);
+
+/**
+ * @brief This is the environment variable that disables caching in all
+ * types including InitializableValue.
+ */
+extern const std::string DISABLE_DATA_CACHING_ENV_FLAG;
+
+}
+}
+
+#endif /* ATSCPPAPI_UTILS_H_ */

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/src/include/logging_internal.h
----------------------------------------------------------------------
diff --git a/lib/atscppapi/src/include/logging_internal.h b/lib/atscppapi/src/include/logging_internal.h
new file mode 100644
index 0000000..7a6ac27
--- /dev/null
+++ b/lib/atscppapi/src/include/logging_internal.h
@@ -0,0 +1,44 @@
+/**
+  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.
+ */
+
+/**
+ * @file logging_internal.h
+ *
+ *
+ * @brief logging used inside the atscppapi library.
+ */
+
+#pragma once
+#ifndef ATSCPPAPI_LOGGING_INTERNAL_H_
+#define ATSCPPAPI_LOGGING_INTERNAL_H_
+
+#include "atscppapi/Logger.h"
+
+// Because we have the helper in Logger.h with the same name.
+#ifdef LOG_DEBUG
+#undef LOG_DEBUG
+#endif
+
+#ifdef LOG_ERROR
+#undef LOG_ERROR
+#endif
+
+#define LOG_DEBUG(fmt, ...) TS_DEBUG("atscppapi", fmt, ## __VA_ARGS__)
+#define LOG_ERROR(fmt, ...) TS_ERROR("atscppapi", fmt, ## __VA_ARGS__)
+
+#endif /* ATSCPPAPI_LOGGING_INTERNAL_H_ */

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/src/include/utils_internal.h
----------------------------------------------------------------------
diff --git a/lib/atscppapi/src/include/utils_internal.h b/lib/atscppapi/src/include/utils_internal.h
new file mode 100644
index 0000000..0eb499e
--- /dev/null
+++ b/lib/atscppapi/src/include/utils_internal.h
@@ -0,0 +1,89 @@
+/**
+  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.
+ */
+
+/**
+ * @file atsutils.h
+ *
+ *
+ * @brief internal utilities for atscppapi
+ */
+
+#pragma once
+#ifndef ATSCPPAPI_ATSUTILS_H_
+#define ATSCPPAPI_ATSUTILS_H_
+
+#include <ts/ts.h>
+#include <string>
+#include "atscppapi/GlobalPlugin.h"
+#include "atscppapi/TransactionPlugin.h"
+#include "atscppapi/TransformationPlugin.h"
+#include "atscppapi/Plugin.h"
+#include "atscppapi/HttpVersion.h"
+#include "atscppapi/utils.h"
+#include "atscppapi/AsyncHttpFetch.h"
+#include "atscppapi/Transaction.h"
+
+namespace atscppapi {
+
+namespace utils {
+
+/**
+ * @private
+ */
+class internal {
+public:
+  static TSHttpHookID convertInternalHookToTsHook(Plugin::HookType);
+  static TSHttpHookID convertInternalTransformationTypeToTsHook(TransformationPlugin::Type type);
+  static void invokePluginForEvent(TransactionPlugin *, TSHttpTxn, TSEvent);
+  static void invokePluginForEvent(GlobalPlugin *, TSHttpTxn, TSEvent);
+  static HttpVersion getHttpVersion(TSMBuffer hdr_buf, TSMLoc hdr_loc);
+  static void initTransactionManagement();
+  static std::string consumeFromTSIOBufferReader(TSIOBufferReader);
+  static shared_ptr<Mutex> getTransactionPluginMutex(TransactionPlugin &);
+  static Transaction &getTransaction(TSHttpTxn);
+
+  static AsyncHttpFetchState *getAsyncHttpFetchState(AsyncHttpFetch &async_http_fetch) {
+    return async_http_fetch.state_;
+  }
+
+  static void initResponse(Response &response, TSMBuffer hdr_buf, TSMLoc hdr_loc) {
+    response.init(hdr_buf, hdr_loc);
+  }
+
+  static void initTransactionServerRequest(Transaction &transaction) {
+    transaction.initServerRequest();
+  }
+
+  static void initTransactionServerResponse(Transaction &transaction) {
+    transaction.initServerResponse();
+  }
+
+  static void initTransactionClientResponse(Transaction &transaction) {
+    transaction.initClientResponse();
+  }
+
+  static const std::list<TransactionPlugin *> &getTransactionPlugins(const Transaction &transaction) {
+    return transaction.getPlugins();
+  }
+}; /* internal */
+
+} /* utils */
+
+}
+
+#endif /* ATSCPPAPI_ATSUTILS_H_ */

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/src/utils.cc
----------------------------------------------------------------------
diff --git a/lib/atscppapi/src/utils.cc b/lib/atscppapi/src/utils.cc
new file mode 100644
index 0000000..d547bb2
--- /dev/null
+++ b/lib/atscppapi/src/utils.cc
@@ -0,0 +1,79 @@
+/**
+  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.
+ */
+
+/**
+ * @file utils.cc
+ */
+
+#include "atscppapi/utils.h"
+#include <sstream>
+#include <arpa/inet.h>
+#include <ts/ts.h>
+#include "logging_internal.h"
+
+const std::string atscppapi::utils::DISABLE_DATA_CACHING_ENV_FLAG("ATSCPPAPI_DISABLE_TRANSACTION_DATA_CACHING");
+
+std::string atscppapi::utils::getIpString(const sockaddr *sockaddress) {
+  if (sockaddress == NULL) {
+    LOG_ERROR("Cannot work on NULL sockaddress");
+   return std::string();
+  }
+
+  char buf[INET6_ADDRSTRLEN];
+
+  switch (sockaddress->sa_family) {
+  case AF_INET:
+    inet_ntop(AF_INET, &(((struct sockaddr_in *) sockaddress)->sin_addr), buf, INET_ADDRSTRLEN);
+    return std::string(buf);
+  case AF_INET6:
+    inet_ntop(AF_INET6, &(((struct sockaddr_in6 *) sockaddress)->sin6_addr), buf, INET6_ADDRSTRLEN);
+    return std::string(buf);
+  default:
+    LOG_ERROR("Unknown Address Family %d", static_cast<int>(sockaddress->sa_family));
+    return std::string();
+  }
+}
+
+uint16_t atscppapi::utils::getPort(const sockaddr *sockaddress) {
+  if (sockaddress == NULL) {
+    LOG_ERROR("Cannot work on NULL sockaddress");
+    return 0;
+  }
+
+  if (sockaddress->sa_family == AF_INET) {
+    return ntohs((((struct sockaddr_in*) sockaddress)->sin_port));
+  } else if (sockaddress->sa_family == AF_INET6) {
+    return ntohs((((struct sockaddr_in6*) sockaddress)->sin6_port));
+  } else {
+    LOG_ERROR("Unknown Address Family %d", static_cast<int>(sockaddress->sa_family));
+    return 0;
+  }
+}
+
+std::string atscppapi::utils::getIpPortString(const sockaddr *sockaddress) {
+  if (sockaddress == NULL) {
+    LOG_ERROR("Cannot work on NULL sockaddress");
+    return std::string();
+  }
+
+  std::ostringstream oss;
+  oss << getIpString(sockaddress);
+  oss << ":";
+  oss << getPort(sockaddress);
+  return oss.str();
+}

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/src/utils_internal.cc
----------------------------------------------------------------------
diff --git a/lib/atscppapi/src/utils_internal.cc b/lib/atscppapi/src/utils_internal.cc
new file mode 100644
index 0000000..b153a49
--- /dev/null
+++ b/lib/atscppapi/src/utils_internal.cc
@@ -0,0 +1,246 @@
+/**
+  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.
+ */
+
+/**
+ * @file utils_internal.cc
+ */
+#include "utils_internal.h"
+#include <cassert>
+#include <ts/ts.h>
+#include <pthread.h>
+#include <cstdlib>
+#include <cassert>
+#include <cstddef>
+#include "atscppapi/Plugin.h"
+#include "atscppapi/GlobalPlugin.h"
+#include "atscppapi/Transaction.h"
+#include "atscppapi/TransactionPlugin.h"
+#include "atscppapi/TransformationPlugin.h"
+#include "InitializableValue.h"
+#include "atscppapi/utils.h"
+#include "logging_internal.h"
+
+using namespace atscppapi;
+
+namespace {
+
+// This is the highest txn arg that can be used, we choose this
+// value to minimize the likelihood of it causing any problems.
+const int MAX_TXN_ARG = 15;
+const int TRANSACTION_STORAGE_INDEX = MAX_TXN_ARG;
+
+int handleTransactionEvents(TSCont cont, TSEvent event, void *edata) {
+  // This function is only here to clean up Transaction objects
+  TSHttpTxn ats_txn_handle = static_cast<TSHttpTxn>(edata);
+  Transaction &transaction = utils::internal::getTransaction(ats_txn_handle);
+  LOG_DEBUG("Got event %d on continuation %p for transaction (ats pointer %p, object %p)", event, cont,
+            ats_txn_handle, &transaction);
+  TSMBuffer hdr_buf;
+  TSMLoc hdr_loc;
+  switch (event) {
+  case TS_EVENT_HTTP_POST_REMAP:
+    transaction.getClientRequest().getUrl().reset();
+    break;
+  case TS_EVENT_HTTP_SEND_REQUEST_HDR:
+    utils::internal::initTransactionServerRequest(transaction);
+    break;
+  case TS_EVENT_HTTP_READ_RESPONSE_HDR:
+    utils::internal::initTransactionServerResponse(transaction);
+    break;
+  case TS_EVENT_HTTP_SEND_RESPONSE_HDR:
+    utils::internal::initTransactionClientResponse(transaction);
+    break;
+  case TS_EVENT_HTTP_TXN_CLOSE:
+    { // opening scope to declare plugins variable below 
+      const std::list<TransactionPlugin *> &plugins = utils::internal::getTransactionPlugins(transaction);
+      for (std::list<TransactionPlugin *>::const_iterator iter = plugins.begin(), end = plugins.end();
+           iter != end; ++iter) {
+        shared_ptr<Mutex> trans_mutex = utils::internal::getTransactionPluginMutex(**iter);
+        LOG_DEBUG("Locking TransacitonPlugin mutex to delete transaction plugin at %p", *iter);
+        trans_mutex->lock();
+        LOG_DEBUG("Locked Mutex...Deleting transaction plugin at %p", *iter);
+        delete *iter;
+        trans_mutex->unlock();
+      }
+      delete &transaction;
+    }
+    break;
+  default:
+    assert(false); /* we should never get here */
+    break;
+  }    
+  TSHttpTxnReenable(ats_txn_handle, TS_EVENT_HTTP_CONTINUE);
+  return 0;
+}
+
+void setupTransactionManagement() {
+  // We must always have a cleanup handler available
+  TSMutex mutex = NULL;
+  TSCont cont = TSContCreate(handleTransactionEvents, mutex);
+  TSHttpHookAdd(TS_HTTP_POST_REMAP_HOOK, cont);
+  TSHttpHookAdd(TS_HTTP_SEND_REQUEST_HDR_HOOK, cont);
+  TSHttpHookAdd(TS_HTTP_READ_RESPONSE_HDR_HOOK, cont);
+  TSHttpHookAdd(TS_HTTP_SEND_RESPONSE_HDR_HOOK, cont);
+  TSHttpHookAdd(TS_HTTP_TXN_CLOSE_HOOK, cont);
+#ifndef DISABLE_TRANSACTION_DATA_CACHING
+  transaction_data_caching_enabled = (getenv(utils::DISABLE_DATA_CACHING_ENV_FLAG.c_str()) == NULL);
+#endif
+  LOG_DEBUG("Initialized transaction management with data caching %s",
+            (transaction_data_caching_enabled ? "enabled" : "disabled"));
+  // TODO is existence of env variable enough or should we expect a specific value?
+}
+
+void inline invokePluginForEvent(Plugin *plugin, TSHttpTxn ats_txn_handle, TSEvent event) {
+  Transaction &transaction = utils::internal::getTransaction(ats_txn_handle);
+  switch (event) {
+  case TS_EVENT_HTTP_PRE_REMAP:
+    plugin->handleReadRequestHeadersPreRemap(transaction);
+    break;
+  case TS_EVENT_HTTP_POST_REMAP:
+    plugin->handleReadRequestHeadersPostRemap(transaction);
+    break;
+  case TS_EVENT_HTTP_SEND_REQUEST_HDR:
+    plugin->handleSendRequestHeaders(transaction);
+    break;
+  case TS_EVENT_HTTP_READ_RESPONSE_HDR:
+    plugin->handleReadResponseHeaders(transaction);
+    break;
+  case TS_EVENT_HTTP_SEND_RESPONSE_HDR:
+    plugin->handleSendResponseHeaders(transaction);
+    break;
+  case TS_EVENT_HTTP_OS_DNS:
+    plugin->handleOsDns(transaction);
+    break;
+  default:
+    assert(false); /* we should never get here */
+    break;
+  }
+}
+
+} /* anonymous namespace */
+
+Transaction &utils::internal::getTransaction(TSHttpTxn ats_txn_handle) {
+  Transaction *transaction = static_cast<Transaction *>(TSHttpTxnArgGet(ats_txn_handle, TRANSACTION_STORAGE_INDEX));
+  if (!transaction) {
+    transaction = new Transaction(static_cast<void *>(ats_txn_handle));
+    LOG_DEBUG("Created new transaction object at %p for ats pointer %p", transaction, ats_txn_handle);
+    TSHttpTxnArgSet(ats_txn_handle, TRANSACTION_STORAGE_INDEX, transaction);
+  }
+  return *transaction;
+}
+
+shared_ptr<Mutex> utils::internal::getTransactionPluginMutex(TransactionPlugin &transaction_plugin) {
+  return transaction_plugin.getMutex();
+}
+
+TSHttpHookID utils::internal::convertInternalHookToTsHook(Plugin::HookType hooktype) {
+  switch (hooktype) {
+  case Plugin::HOOK_READ_REQUEST_HEADERS_POST_REMAP:
+    return TS_HTTP_POST_REMAP_HOOK;
+  case Plugin::HOOK_READ_REQUEST_HEADERS_PRE_REMAP:
+    return TS_HTTP_PRE_REMAP_HOOK;
+  case Plugin::HOOK_READ_RESPONSE_HEADERS:
+    return TS_HTTP_READ_RESPONSE_HDR_HOOK;
+  case Plugin::HOOK_SEND_REQUEST_HEADERS:
+    return TS_HTTP_SEND_REQUEST_HDR_HOOK;
+  case Plugin::HOOK_SEND_RESPONSE_HEADERS:
+    return TS_HTTP_SEND_RESPONSE_HDR_HOOK;
+  case Plugin::HOOK_OS_DNS:
+    return TS_HTTP_OS_DNS_HOOK;
+  default:
+    assert(false); // shouldn't happen, let's catch it early
+    break;
+  }
+  return static_cast<TSHttpHookID>(-1);
+}
+
+TSHttpHookID utils::internal::convertInternalTransformationTypeToTsHook(TransformationPlugin::Type type) {
+  TSHttpHookID hook_id;
+  switch (type) {
+    case TransformationPlugin::RESPONSE_TRANSFORMATION:
+      return TS_HTTP_RESPONSE_TRANSFORM_HOOK;
+    case TransformationPlugin::REQUEST_TRANSFORMATION:
+      return TS_HTTP_REQUEST_TRANSFORM_HOOK;
+    default:
+      assert(false); // shouldn't happen, let's catch it early
+      break;
+  }
+  return static_cast<TSHttpHookID>(-1);
+}
+
+void utils::internal::invokePluginForEvent(TransactionPlugin *plugin, TSHttpTxn ats_txn_handle, TSEvent event) {
+  ScopedSharedMutexLock scopedLock(plugin->getMutex());
+  ::invokePluginForEvent(static_cast<Plugin *>(plugin), ats_txn_handle, event);
+}
+
+void utils::internal::invokePluginForEvent(GlobalPlugin *plugin, TSHttpTxn ats_txn_handle, TSEvent event) {
+  ::invokePluginForEvent(static_cast<Plugin *>(plugin), ats_txn_handle, event);
+}
+
+std::string utils::internal::consumeFromTSIOBufferReader(TSIOBufferReader reader) {
+  std::string str;
+  int avail = TSIOBufferReaderAvail(reader);
+
+  if (avail != TS_ERROR) {
+    int consumed = 0;
+    if (avail > 0) {
+      str.reserve(avail + 1);
+
+      int64_t data_len;
+      const char *char_data;
+      TSIOBufferBlock block = TSIOBufferReaderStart(reader);
+      while (block != NULL) {
+        char_data = TSIOBufferBlockReadStart(block, reader, &data_len);
+        str.append(char_data, data_len);
+        consumed += data_len;
+        block = TSIOBufferBlockNext(block);
+      }
+    }
+    TSIOBufferReaderConsume(reader, consumed);
+  } else {
+    LOG_ERROR("TSIOBufferReaderAvail returned error code %d for reader %p", avail, reader);
+  }
+
+  return str;
+}
+
+
+HttpVersion utils::internal::getHttpVersion(TSMBuffer hdr_buf, TSMLoc hdr_loc) {
+  int version = TSHttpHdrVersionGet(hdr_buf, hdr_loc);
+  if (version != TS_ERROR) {
+    if ((TS_HTTP_MAJOR(version) == 0) && (TS_HTTP_MINOR(version) == 0)) {
+      return HTTP_VERSION_0_9;
+    }
+    if ((TS_HTTP_MAJOR(version) == 1) && (TS_HTTP_MINOR(version) == 0)) {
+      return HTTP_VERSION_1_0;
+    }
+    if ((TS_HTTP_MAJOR(version) == 1) && (TS_HTTP_MINOR(version) == 1)) {
+      return HTTP_VERSION_1_1;
+    } else {
+      LOG_ERROR("Unrecognized version %d", version);
+    }
+  } else {
+    LOG_ERROR("Could not get version; hdr_buf %p, hdr_loc %p", hdr_buf, hdr_loc);
+  }
+  return HTTP_VERSION_UNKNOWN;
+}
+
+void utils::internal::initTransactionManagement() {
+  static pthread_once_t setup_pthread_once_control = PTHREAD_ONCE_INIT;
+  pthread_once(&setup_pthread_once_control, setupTransactionManagement);
+}

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/cpp11api/Makefile.am
----------------------------------------------------------------------
diff --git a/lib/cpp11api/Makefile.am b/lib/cpp11api/Makefile.am
deleted file mode 100644
index 0aab9ed..0000000
--- a/lib/cpp11api/Makefile.am
+++ /dev/null
@@ -1,37 +0,0 @@
-# Makefile.am for C++11 API
-#
-#  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.
-
-includedir=$(prefix)/include/ts
-
-AM_CPPFLAGS = -I$(top_builddir)/proxy/api/ts
-  
-if BUILD_HAVE_CXX_11
-
-if BUILD_HAVE_LIBCXX
-AM_CXXFLAGS += -stdlib=libc++
-endif
-
-lib_LTLIBRARIES = libatscpp11api.la
-
-libatscpp11api_la_SOURCES = \
-  cpp11api.cc
-  
-include_HEADERS = \
-  ts-cpp11.h ts-cpp11-headers.h
-
-endif # BUILD_HAVE_CXX_11

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/cpp11api/cpp11api.cc
----------------------------------------------------------------------
diff --git a/lib/cpp11api/cpp11api.cc b/lib/cpp11api/cpp11api.cc
deleted file mode 100644
index e29fea2..0000000
--- a/lib/cpp11api/cpp11api.cc
+++ /dev/null
@@ -1,880 +0,0 @@
-/** @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 <arpa/inet.h>
-#include <ts.h>
-#include <algorithm>
-#include "ts-cpp11.h"
-#include "ts-cpp11-headers.h"
-
-using namespace ats::api;
-
-TSHttpHookID TSHookIDFromHookType(HookType hook);
-
-class HookContinuationData {
-public:
-  GlobalHookCallback callback;
-  HookType hooktype;
-  TSHttpHookID ts_hook_id;
-};
-
-class ats::api::Transaction {
-public:
-  TSHttpTxn ts_http_txn_ = NULL;
-  TSCont ts_contp_ = NULL;
-};
-
-extern "C" void TSPluginInit(int argc, const char *argv[]) {
-
-  TSPluginRegistrationInfo registration_info;
-
-  const char *api_version_string = "cpp11api";
-
-  registration_info.plugin_name = const_cast<char*>(api_version_string);
-  registration_info.vendor_name = const_cast<char*>(api_version_string);
-  registration_info.support_email = const_cast<char*>(api_version_string);
-
-  if (TSPluginRegister(TS_SDK_VERSION_3_0, &registration_info) != TS_SUCCESS) {
-    return;
-  }
-
-  StringVector arguments;
-  for (int i = 0; i < argc; ++i) {
-    arguments.push_back(std::string(argv[i]));
-  }
-
-  // Finally we will call the wrapper API registration point
-  PluginRegister(arguments);
-}
-
-TSHttpHookID TSHookIDFromHookType(HookType hook) {
-  switch (hook) {
-  case ats::api::HookType::HOOK_PRE_REMAP:
-    return TS_HTTP_PRE_REMAP_HOOK;
-    break;
-  case ats::api::HookType::HOOK_POST_REMAP:
-    return TS_HTTP_POST_REMAP_HOOK;
-    break;
-  case ats::api::HookType::HOOK_READ_REQUEST_HEADERS:
-    return TS_HTTP_READ_REQUEST_HDR_HOOK;
-    break;
-  case ats::api::HookType::HOOK_READ_RESPONSE_HEADERS:
-    return TS_HTTP_READ_RESPONSE_HDR_HOOK;
-    break;
-  case ats::api::HookType::HOOK_SEND_RESPONSE_HEADERS:
-    return TS_HTTP_SEND_RESPONSE_HDR_HOOK;
-    break;
-  case ats::api::HookType::HOOK_TRANSACTION_START:
-    return TS_HTTP_TXN_START_HOOK;
-    break;
-  case ats::api::HookType::HOOK_TRANSACTION_END:
-    return TS_HTTP_TXN_CLOSE_HOOK;
-    break;
-  }
-
-  return TS_HTTP_PRE_REMAP_HOOK;
-}
-
-void inline ReenableBasedOnNextState(TSHttpTxn txnp, NextState ns) {
-  switch (ns) {
-  case NextState::HTTP_DONT_CONTINUE:
-    return;
-    break;
-  case NextState::HTTP_ERROR:
-    TSHttpTxnReenable(txnp, static_cast<TSEvent>(TS_EVENT_HTTP_ERROR));
-    break;
-  case NextState::HTTP_CONTINUE:
-  default:
-    TSHttpTxnReenable(txnp, static_cast<TSEvent>(TS_EVENT_HTTP_CONTINUE));
-    break;
-  }
-}
-
-std::string printable_sockaddr_ip(sockaddr const * s_sockaddr) {
-  const struct sockaddr_in * s_sockaddr_in =
-      reinterpret_cast<const struct sockaddr_in *>(s_sockaddr);
-
-  char res[INET_ADDRSTRLEN];
-  inet_ntop(AF_INET, &s_sockaddr_in->sin_addr, res, INET_ADDRSTRLEN);
-
-  return std::string(res);
-}
-
-std::string ats::api::GetPristineRequestUrl(Transaction &t) {
-  TSMBuffer bufp;
-  TSMLoc url_loc;
-
-  if (TSHttpTxnPristineUrlGet(t.ts_http_txn_, &bufp, &url_loc) != TS_SUCCESS)
-    return std::string();
-
-  int url_len;
-  char *urlp = TSUrlStringGet(bufp, url_loc, &url_len);
-  std::string url(urlp, url_len);
-
-  TSfree(urlp);
-
-  TSHandleMLocRelease(bufp, TS_NULL_MLOC, url_loc);
-
-  return url;
-}
-
-std::string ats::api::GetRequestUrl(Transaction &t) {
-  TSMBuffer bufp;
-  TSMLoc hdr_loc;
-  TSMLoc url_loc;
-
-  if (TSHttpTxnClientReqGet(t.ts_http_txn_, &bufp, &hdr_loc) != TS_SUCCESS)
-    return std::string();
-
-  TSHttpHdrUrlGet(bufp, hdr_loc, &url_loc);
-
-  int url_len;
-  char *urlp = TSUrlStringGet(bufp, url_loc, &url_len);
-  std::string url(urlp, url_len);
-
-  TSfree(urlp);
-
-  TSHandleMLocRelease(bufp, hdr_loc, url_loc);
-  TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
-
-  return url;
-}
-
-std::string ats::api::GetRequestUrlScheme(Transaction &t) {
-  TSMBuffer bufp;
-  TSMLoc hdr_loc;
-  TSMLoc url_loc;
-
-  if (TSHttpTxnClientReqGet(t.ts_http_txn_, &bufp, &hdr_loc) != TS_SUCCESS)
-    return std::string();
-
-  TSHttpHdrUrlGet(bufp, hdr_loc, &url_loc);
-
-  int scheme_length;
-  const char *scheme = TSUrlSchemeGet(bufp, url_loc, &scheme_length);
-
-  std::string ret(scheme, scheme_length);
-
-  TSHandleMLocRelease(bufp, hdr_loc, url_loc);
-  TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
-
-  return ret;
-}
-
-
-std::string ats::api::GetPristineRequestUrlScheme(Transaction &t) {
-  TSMBuffer bufp;
-  TSMLoc url_loc;
-
-  TSHttpTxnPristineUrlGet(t.ts_http_txn_, &bufp, &url_loc);
-
-  int length;
-  const char *scheme = TSUrlHostGet(bufp, url_loc, &length);
-
-  std::string ret(scheme, length);
-
-  TSHandleMLocRelease(bufp, TS_NULL_MLOC, url_loc);
-
-  return ret;
-}
-
-void ats::api::SetRequestUrlScheme(Transaction &t, const std::string &scheme) {
-  TSMBuffer bufp;
-  TSMLoc hdr_loc;
-  TSMLoc url_loc;
-
-  TSHttpTxnClientReqGet(t.ts_http_txn_, &bufp, &hdr_loc);
-  TSHttpHdrUrlGet(bufp, hdr_loc, &url_loc);
-
-  TSUrlHostSet(bufp, url_loc, scheme.c_str(), scheme.length());
-
-  TSHandleMLocRelease(bufp, hdr_loc, url_loc);
-  TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
-}
-
-
-std::string ats::api::GetRequestUrlQuery(Transaction &t) {
-  TSMBuffer bufp;
-  TSMLoc hdr_loc;
-  TSMLoc url_loc;
-
-  if (TSHttpTxnClientReqGet(t.ts_http_txn_, &bufp, &hdr_loc) != TS_SUCCESS)
-    return std::string();
-
-  TSHttpHdrUrlGet(bufp, hdr_loc, &url_loc);
-
-  int query_length;
-  const char *query = TSUrlHttpQueryGet(bufp, url_loc, &query_length);
-
-  std::string ret(query, query_length);
-
-  TSHandleMLocRelease(bufp, hdr_loc, url_loc);
-  TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
-
-  return ret;
-}
-
-std::string ats::api::GetPristineRequestUrlQuery(Transaction &t) {
-  TSMBuffer bufp;
-  TSMLoc url_loc;
-
-  TSHttpTxnPristineUrlGet(t.ts_http_txn_, &bufp, &url_loc);
-
-  int query_length;
-  const char *query = TSUrlHostGet(bufp, url_loc, &query_length);
-
-  std::string ret(query, query_length);
-
-  TSHandleMLocRelease(bufp, TS_NULL_MLOC, url_loc);
-
-  return ret;
-}
-
-void ats::api::SetRequestUrlQuery(Transaction &t, const std::string &query) {
-  TSMBuffer bufp;
-  TSMLoc hdr_loc;
-  TSMLoc url_loc;
-
-  TSHttpTxnClientReqGet(t.ts_http_txn_, &bufp, &hdr_loc);
-  TSHttpHdrUrlGet(bufp, hdr_loc, &url_loc);
-
-  TSUrlHostSet(bufp, url_loc, query.c_str(), query.length());
-
-  TSHandleMLocRelease(bufp, hdr_loc, url_loc);
-  TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
-}
-
-std::string ats::api::GetRequestUrlHost(Transaction &t) {
-  TSMBuffer bufp;
-  TSMLoc hdr_loc;
-  TSMLoc url_loc;
-
-  if (TSHttpTxnClientReqGet(t.ts_http_txn_, &bufp, &hdr_loc) != TS_SUCCESS)
-    return std::string();
-
-  TSHttpHdrUrlGet(bufp, hdr_loc, &url_loc);
-
-  int host_length;
-  const char *host = TSUrlHostGet(bufp, url_loc, &host_length);
-
-  std::string ret(host, host_length);
-
-  TSHandleMLocRelease(bufp, hdr_loc, url_loc);
-  TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
-
-  return ret;
-}
-
-std::string ats::api::GetPristineRequestUrlHost(Transaction &t) {
-  TSMBuffer bufp;
-  TSMLoc url_loc;
-
-  TSHttpTxnPristineUrlGet(t.ts_http_txn_, &bufp, &url_loc);
-
-  int host_length;
-  const char *host = TSUrlHostGet(bufp, url_loc, &host_length);
-
-  std::string ret(host, host_length);
-
-  TSHandleMLocRelease(bufp, TS_NULL_MLOC, url_loc);
-
-  return ret;
-}
-
-void ats::api::SetRequestUrlHost(Transaction &t, const std::string &host) {
-  TSMBuffer bufp;
-  TSMLoc hdr_loc;
-  TSMLoc url_loc;
-
-  TSHttpTxnClientReqGet(t.ts_http_txn_, &bufp, &hdr_loc);
-  TSHttpHdrUrlGet(bufp, hdr_loc, &url_loc);
-
-  TSUrlHostSet(bufp, url_loc, host.c_str(), host.length());
-
-
-  TSHandleMLocRelease(bufp, hdr_loc, url_loc);
-  TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
-}
-
-std::string ats::api::GetRequestUrlPath(Transaction &t) {
-  TSMBuffer bufp;
-  TSMLoc hdr_loc;
-  TSMLoc url_loc;
-
-  if (TSHttpTxnClientReqGet(t.ts_http_txn_, &bufp, &hdr_loc) != TS_SUCCESS)
-    return std::string();
-
-  TSHttpHdrUrlGet(bufp, hdr_loc, &url_loc);
-
-  int path_length;
-  const char *path = TSUrlPathGet(bufp, url_loc, &path_length);
-
-  std::string ret(path, path_length);
-
-  TSHandleMLocRelease(bufp, hdr_loc, url_loc);
-  TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
-
-  return ret;
-}
-
-unsigned int ats::api::GetRequestUrlPort(Transaction &t) {
-  TSMBuffer bufp;
-  TSMLoc hdr_loc;
-  TSMLoc url_loc;
-
-  TSHttpTxnClientReqGet(t.ts_http_txn_, &bufp, &hdr_loc);
-  TSHttpHdrUrlGet(bufp, hdr_loc, &url_loc);
-  int port = TSUrlPortGet(bufp, url_loc);
-
-  TSHandleMLocRelease(bufp, hdr_loc, url_loc);
-  TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
-
-  return port;
-}
-
-unsigned int ats::api::GetPristineRequestUrlPort(Transaction &t) {
-  TSMBuffer bufp;
-  TSMLoc url_loc;
-
-  TSHttpTxnPristineUrlGet(t.ts_http_txn_, &bufp, &url_loc);
-  int port = TSUrlPortGet(bufp, url_loc);
-  TSHandleMLocRelease(bufp, TS_NULL_MLOC, url_loc); // TODO: is this wrong?
-
-  return port;
-}
-
-void ats::api::SetRequestUrlPort(Transaction &t, unsigned int port) {
-  TSMBuffer bufp;
-  TSMLoc hdr_loc;
-  TSMLoc url_loc;
-
-  TSHttpTxnClientReqGet(t.ts_http_txn_, &bufp, &hdr_loc);
-  TSHttpHdrUrlGet(bufp, hdr_loc, &url_loc);
-
-  TSUrlPortSet(bufp, url_loc, port);
-
-  TSHandleMLocRelease(bufp, hdr_loc, url_loc);
-  TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
-}
-
-std::string ats::api::GetPristineRequestUrlPath(Transaction &t) {
-  TSMBuffer bufp;
-  TSMLoc url_loc;
-
-  TSHttpTxnPristineUrlGet(t.ts_http_txn_, &bufp, &url_loc);
-
-  int path_length;
-  const char *path = TSUrlPathGet(bufp, url_loc, &path_length);
-
-  std::string ret(path, path_length);
-
-  TSHandleMLocRelease(bufp, TS_NULL_MLOC, url_loc);
-
-  return ret;
-}
-
-void ats::api::SetRequestUrlPath(Transaction &t, const std::string &path) {
-  TSMBuffer bufp;
-  TSMLoc hdr_loc;
-  TSMLoc url_loc;
-
-  TSHttpTxnClientReqGet(t.ts_http_txn_, &bufp, &hdr_loc);
-  TSHttpHdrUrlGet(bufp, hdr_loc, &url_loc);
-
-  TSUrlPathSet(bufp, url_loc, path.c_str(), path.length());
-
-  TSHandleMLocRelease(bufp, hdr_loc, url_loc);
-  TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
-}
-
-static int GlobalContinuationHandler(TSCont contp, TSEvent /* event ATS_UNUSED */, void *edata) {
-  TSHttpTxn txnp = static_cast<TSHttpTxn>(edata);
-
-  Transaction transaction;
-  transaction.ts_http_txn_ = txnp;
-  transaction.ts_contp_ = contp;
-
-  HookContinuationData *data = static_cast<HookContinuationData*>(TSContDataGet(
-      contp));
-
-  ats::api::NextState ns = data->callback(transaction);
-  ReenableBasedOnNextState(txnp, ns);
-
-  return 0;
-}
-
-std::string ats::api::GetClientIP(Transaction &t) {
-  return printable_sockaddr_ip(TSHttpTxnClientAddrGet(t.ts_http_txn_));
-}
-
-unsigned int ats::api::GetClientPort(Transaction &t) {
-  const struct sockaddr_in * client_sockaddr =
-      reinterpret_cast<const struct sockaddr_in *>(TSHttpTxnClientAddrGet(
-          t.ts_http_txn_));
-
-  return static_cast<unsigned int>(ntohs(client_sockaddr->sin_port));
-}
-
-std::string ats::api::GetServerIncomingIP(Transaction &t) {
-  return printable_sockaddr_ip(TSHttpTxnIncomingAddrGet(t.ts_http_txn_));
-}
-
-unsigned int ats::api::GetServerIncomingPort(Transaction &t) {
-  const struct sockaddr_in * client_sockaddr =
-      reinterpret_cast<const struct sockaddr_in *>(TSHttpTxnIncomingAddrGet(
-          t.ts_http_txn_));
-
-  return static_cast<unsigned int>(ntohs(client_sockaddr->sin_port));
-}
-
-bool ats::api::IsInternalRequest(Transaction &t) {
-  return TSHttpIsInternalRequest(t.ts_http_txn_) == TS_SUCCESS;
-}
-
-int ats::api::GetServerResponseStatusCode(Transaction &t) {
-  TSMBuffer bufp;
-  TSMLoc hdr_loc;
-
-  TSHttpTxnServerRespGet(t.ts_http_txn_, &bufp, &hdr_loc);
-  int status = TSHttpHdrStatusGet(bufp, hdr_loc);
-
-  TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
-
-  return status;
-}
-
-std::string ats::api::GetRequestMethod(Transaction &t) {
-
-  TSMBuffer bufp;
-  TSMLoc hdr_loc;
-
-  TSHttpTxnClientReqGet(t.ts_http_txn_, &bufp, &hdr_loc);
-
-  int method_len;
-  const char *methodp = TSHttpHdrMethodGet(bufp, hdr_loc, &method_len);
-  std::string method(methodp, method_len);
-
-  TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
-
-  return method;
-}
-
-void ats::api::SetRequestMethod(Transaction &t, const std::string &method) {
-  TSMBuffer bufp;
-  TSMLoc hdr_loc;
-
-  TSHttpTxnClientReqGet(t.ts_http_txn_, &bufp, &hdr_loc);
-
-  TSHttpHdrMethodSet(bufp, hdr_loc, method.c_str(), method.length());
-
-  TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
-}
-
-void ats::api::ReenableTransaction(Transaction &t, NextState ns) {
-  ReenableBasedOnNextState(t.ts_http_txn_, ns);
-}
-
-static int TransactionContinuationHandler(TSCont contp, TSEvent event,
-    void *edata) {
-  TSHttpTxn txnp = static_cast<TSHttpTxn>(edata);
-
-  Transaction transaction;
-  transaction.ts_http_txn_ = txnp;
-  transaction.ts_contp_ = contp;
-
-  NextState ns = NextState::HTTP_CONTINUE;
-  HookContinuationData *data = static_cast<HookContinuationData*>(TSContDataGet(
-      contp));
-  if (event != TS_EVENT_HTTP_TXN_CLOSE
-      || (event == TS_EVENT_HTTP_TXN_CLOSE
-          && data->ts_hook_id == TS_HTTP_TXN_CLOSE_HOOK)) {
-    ns = data->callback(transaction);
-  }
-
-  // We must free the HookContinuationData structure and continuation
-  // If this transaction is complete
-  if (event == TS_EVENT_HTTP_TXN_CLOSE) {
-    delete data;
-    TSContDestroy(contp);
-  }
-
-  ReenableBasedOnNextState(txnp, ns);
-  return 0;
-}
-
-void* ats::api::GetTransactionIdentifier(Transaction &t) {
-  return reinterpret_cast<void *>(t.ts_http_txn_);
-}
-
-void ats::api::CreateTransactionHook(Transaction &txn,HookType hook,
-    GlobalHookCallback callback) {
-  TSHttpHookID ts_hook_id = TSHookIDFromHookType(hook);
-  TSCont contp = TSContCreate(TransactionContinuationHandler, NULL);
-
-  HookContinuationData *data = new HookContinuationData();
-  data->callback = callback;
-  data->hooktype = hook;
-  data->ts_hook_id = ts_hook_id;
-
-  TSContDataSet(contp, static_cast<void*>(data));
-  TSHttpTxnHookAdd(txn.ts_http_txn_, ts_hook_id, contp);
-
-  if (ts_hook_id != TS_HTTP_TXN_CLOSE_HOOK) {
-    TSHttpTxnHookAdd(txn.ts_http_txn_, TS_HTTP_TXN_CLOSE_HOOK, contp);
-  }
-}
-
-void ats::api::CreateGlobalHook(HookType hook, GlobalHookCallback callback) {
-
-  TSHttpHookID ts_hook_id = TSHookIDFromHookType(hook);
-  TSCont contp = TSContCreate(GlobalContinuationHandler, NULL);
-
-  HookContinuationData *data = new HookContinuationData();
-  data->callback = callback;
-  data->hooktype = hook;
-
-  TSContDataSet(contp, static_cast<void*>(data));
-  TSHttpHookAdd(ts_hook_id, contp);
-}
-
-/*
- * Header code
- */
-
-void SetHeader(TSMBuffer bufp, TSMLoc hdr_loc, const std::string &name,
-    const std::vector<std::string> &values) {
-
-  TSMLoc field_loc;
-
-  field_loc = TSMimeHdrFieldFind(bufp, hdr_loc, name.c_str(), name.length());
-
-  // if the field already existed, let's just blow it away.
-  if (field_loc) {
-    TSMimeHdrFieldDestroy(bufp, hdr_loc, field_loc);
-    TSHandleMLocRelease(bufp, hdr_loc, field_loc);
-  }
-
-  // Now it definitely doesn't exist, so add it.
-  TSMimeHdrFieldCreate(bufp, hdr_loc, &field_loc);
-  TSMimeHdrFieldNameSet(bufp, hdr_loc, field_loc, name.c_str(), name.length());
-
-  for (unsigned int i = 0; i < values.size(); ++i) {
-    TSMimeHdrFieldValueStringInsert(bufp, hdr_loc, field_loc, 0, values[i].c_str(),
-        values[i].length());
-    TSMimeHdrFieldAppend(bufp, hdr_loc, field_loc);
-  }
-
-  TSHandleMLocRelease(bufp, hdr_loc, field_loc);
-}
-
-void AppendHeader(TSMBuffer bufp, TSMLoc hdr_loc, const std::string &name,
-    const std::vector<std::string> &values) {
-
-  TSMLoc field_loc;
-
-  TSMimeHdrFieldCreate(bufp, hdr_loc, &field_loc);
-  TSMimeHdrFieldNameSet(bufp, hdr_loc, field_loc, name.c_str(), name.length());
-
-  for (unsigned int i = 0; i < values.size(); ++i) {
-    TSMimeHdrFieldValueStringInsert(bufp, hdr_loc, field_loc, 0, values[i].c_str(),
-        values[i].length());
-    TSMimeHdrFieldAppend(bufp, hdr_loc, field_loc);
-  }
-
-  TSHandleMLocRelease(bufp, hdr_loc, field_loc);
-}
-
-void DeleteHeader(TSMBuffer bufp, TSMLoc hdr_loc, const std::string &name) {
-  TSMLoc field_loc;
-
-  field_loc = TSMimeHdrFieldFind(bufp, hdr_loc, name.c_str(), name.length());
-
-  if (field_loc) {
-    TSMimeHdrFieldDestroy(bufp, hdr_loc, field_loc);
-    TSHandleMLocRelease(bufp, hdr_loc, field_loc);
-  }
-}
-
-/*
- * Obviously this should be optimized to either fill in a passed vector
- * or just returned a shared_ptr to the build vector, this is an exercise
- * left to the reader.
- */
-ats::api::headers::HeaderVector GetHeaders(TSMBuffer bufp, TSMLoc hdr_loc) {
-
-  TSMLoc field_loc;
-
-  ats::api::headers::HeaderVector hv;
-
-  field_loc = TSMimeHdrFieldGet(bufp, hdr_loc, 0);
-  while (field_loc) {
-    /* copy the header to a more friedly data structure */
-    int name_length;
-    const char *fieldName = TSMimeHdrFieldNameGet(bufp, hdr_loc, field_loc, &name_length);
-
-    ats::api::headers::Header hdr;
-    hdr.assignName(fieldName, name_length);
-
-    /* now we have to walk all the values and add them */
-    int numValues = TSMimeHdrFieldValuesCount(bufp, hdr_loc, field_loc);
-    for (int indx = 0; indx < numValues; ++indx) {
-      int val_length;
-      const char *value = TSMimeHdrFieldValueStringGet(bufp, hdr_loc, field_loc, indx, &val_length);
-      hdr.addNewValue(value, val_length);
-    }
-
-    hv.push_back(hdr);
-
-    /* Get the next field and release the current one */
-    TSMLoc next_field_loc = TSMimeHdrFieldNext(bufp, hdr_loc, field_loc);
-    TSHandleMLocRelease(bufp, hdr_loc, field_loc);
-    field_loc = next_field_loc;
-  }
-
-  return hv;
-}
-
-/*
- * TODO: All of these can be improved by caching and then invalidating the
- * header cache when a delete, append, or set occurs.
- */
-
-void ats::api::headers::DeleteClientRequestHeader(Transaction &t, const std::string &name) {
-  TSMBuffer bufp;
-  TSMLoc hdr_loc;
-
-  if (TSHttpTxnClientReqGet(t.ts_http_txn_, &bufp, &hdr_loc) != TS_SUCCESS)
-    return;
-
-  DeleteHeader(bufp, hdr_loc, name);
-  TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
-}
-
-void ats::api::headers::DeleteClientResponseHeader(Transaction &t, const std::string &name) {
-  TSMBuffer bufp;
-  TSMLoc hdr_loc;
-
-  if (TSHttpTxnClientRespGet(t.ts_http_txn_, &bufp, &hdr_loc) != TS_SUCCESS)
-    return;
-
-  DeleteHeader(bufp, hdr_loc, name);
-  TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
-}
-
-void ats::api::headers::DeleteServerResponseHeader(Transaction &t, const std::string &name) {
-  TSMBuffer bufp;
-  TSMLoc hdr_loc;
-
-  if (TSHttpTxnServerRespGet(t.ts_http_txn_, &bufp, &hdr_loc) != TS_SUCCESS)
-    return;
-
-  DeleteHeader(bufp, hdr_loc, name);
-  TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
-}
-
-void ats::api::headers::SetClientRequestHeader(Transaction &t, const std::string &name,
-    const std::vector<std::string> &vals) {
-  TSMBuffer bufp;
-  TSMLoc hdr_loc;
-
-  if (TSHttpTxnClientReqGet(t.ts_http_txn_, &bufp, &hdr_loc) != TS_SUCCESS)
-    return;
-
-  SetHeader(bufp, hdr_loc, name, vals);
-  TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
-}
-
-void ats::api::headers::SetClientRequestHeader(Transaction &t, const std::string &name, const std::string &val) {
-
-  std::vector<std::string> vals;
-  vals.push_back(val);
-  SetClientRequestHeader(t, name, vals);
-}
-
-void ats::api::headers::SetClientResponseHeader(Transaction &t, const std::string &name,
-    const std::vector<std::string> &vals) {
-  TSMBuffer bufp;
-  TSMLoc hdr_loc;
-
-  if (TSHttpTxnClientRespGet(t.ts_http_txn_, &bufp, &hdr_loc) != TS_SUCCESS)
-    return;
-
-  SetHeader(bufp, hdr_loc, name, vals);
-  TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
-}
-
-void ats::api::headers::SetClientResponseHeader(Transaction &t, const std::string &name, const std::string &val) {
-
-  std::vector<std::string> vals;
-  vals.push_back(val);
-  SetClientResponseHeader(t, name, vals);
-}
-
-void ats::api::headers::SetServerResponseHeader(Transaction &t, const std::string &name,
-    const std::vector<std::string> &vals) {
-  TSMBuffer bufp;
-  TSMLoc hdr_loc;
-
-  if (TSHttpTxnServerRespGet(t.ts_http_txn_, &bufp, &hdr_loc) != TS_SUCCESS)
-    return;
-
-  SetHeader(bufp, hdr_loc, name, vals);
-  TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
-}
-
-void ats::api::headers::SetServerResponseHeader(Transaction &t, const std::string &name, const std::string &val) {
-
-  std::vector<std::string> vals;
-  vals.push_back(val);
-  SetServerResponseHeader(t, name, vals);
-}
-
-void ats::api::headers::AppendServerResponseHeader(Transaction &t, const std::string &name,
-    const std::vector<std::string> &vals) {
-  TSMBuffer bufp;
-  TSMLoc hdr_loc;
-
-  if (TSHttpTxnServerRespGet(t.ts_http_txn_, &bufp, &hdr_loc) != TS_SUCCESS)
-    return;
-
-  AppendHeader(bufp, hdr_loc, name, vals);
-  TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
-}
-
-void ats::api::headers::AppendServerResponseHeader(Transaction &t, const std::string &name,
-    const std::string &val) {
-
-  std::vector<std::string> vals;
-  vals.push_back(val);
-  AppendServerResponseHeader(t, name, vals);
-}
-
-void ats::api::headers::AppendClientRequestHeader(Transaction &t, const std::string &name,
-    const std::vector<std::string> &vals) {
-
-  TSMBuffer bufp;
-  TSMLoc hdr_loc;
-
-  if (TSHttpTxnClientReqGet(t.ts_http_txn_, &bufp, &hdr_loc) != TS_SUCCESS)
-    return;
-
-  AppendHeader(bufp, hdr_loc, name, vals);
-  TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
-}
-
-void ats::api::headers::AppendClientRequestHeader(Transaction &t, const std::string &name,
-    const std::string &val) {
-
-  std::vector<std::string> vals;
-  vals.push_back(val);
-  AppendClientRequestHeader(t, name, vals);
-}
-
-void ats::api::headers::AppendClientResponseHeader(Transaction &t, const std::string &name,
-    const std::vector<std::string> &vals) {
-
-  TSMBuffer bufp;
-  TSMLoc hdr_loc;
-
-  if (TSHttpTxnClientRespGet(t.ts_http_txn_, &bufp, &hdr_loc) != TS_SUCCESS)
-    return;
-
-  AppendHeader(bufp, hdr_loc, name, vals);
-  TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
-}
-
-void ats::api::headers::AppendClientResponseHeader(Transaction &t, const std::string &name,
-    const std::string &val) {
-
-  std::vector<std::string> vals;
-  vals.push_back(val);
-  AppendClientResponseHeader(t, name, vals);
-}
-
-ats::api::headers::HeaderVector ats::api::headers::GetClientRequestHeaders(Transaction &t) {
-  TSMBuffer bufp;
-  TSMLoc hdr_loc;
-
-  HeaderVector hv;
-
-  if (TSHttpTxnClientReqGet(t.ts_http_txn_, &bufp, &hdr_loc) != TS_SUCCESS)
-    return hv;
-
-  hv = GetHeaders(bufp, hdr_loc);
-  TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
-
-  return hv;
-}
-
-ats::api::headers::HeaderVector ats::api::headers::GetClientResponseHeaders(Transaction &t) {
-  TSMBuffer bufp;
-  TSMLoc hdr_loc;
-
-  HeaderVector hv;
-
-  if (TSHttpTxnClientRespGet(t.ts_http_txn_, &bufp, &hdr_loc) != TS_SUCCESS)
-    return hv;
-
-  hv = GetHeaders(bufp, hdr_loc);
-  TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
-
-  return hv;
-}
-
-ats::api::headers::HeaderVector ats::api::headers::GetServerResponseHeaders(Transaction &t) {
-  TSMBuffer bufp;
-  TSMLoc hdr_loc;
-
-  HeaderVector hv;
-
-  if (TSHttpTxnServerRespGet(t.ts_http_txn_, &bufp, &hdr_loc) != TS_SUCCESS)
-    return hv;
-
-  hv = GetHeaders(bufp, hdr_loc);
-  TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
-
-  return hv;
-}
-
-inline ats::api::headers::Header GetHeader(Transaction & /* t ATS_UNUSED */, const std::string& hdr_name,
-                                           const ats::api::headers::HeaderVector &hdrs) {
-
-  ats::api::headers::Header hdr;
-  ats::api::headers::HeaderVector::const_iterator ii = std::find_if(hdrs.begin(), hdrs.end(),
-                                                                    ats::api::headers::HeaderName(hdr_name));
-
-  if (ii != hdrs.end()) {
-    hdr = *ii;
-  }
-
-  return hdr;
-}
-
-ats::api::headers::Header ats::api::headers::GetClientRequestHeader(Transaction &t, const std::string& hdr_name) {
-  return GetHeader(t, hdr_name, GetClientRequestHeaders(t));
-}
-
-ats::api::headers::Header ats::api::headers::GetClientResponseHeader(Transaction &t, const std::string& hdr_name) {
-  return GetHeader(t, hdr_name, GetClientResponseHeaders(t));
-}
-
-ats::api::headers::Header ats::api::headers::GetServerResponseHeader(Transaction &t, const std::string& hdr_name) {
-  return GetHeader(t, hdr_name, GetServerResponseHeaders(t));
-}

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/cpp11api/ts-cpp11-headers.h
----------------------------------------------------------------------
diff --git a/lib/cpp11api/ts-cpp11-headers.h b/lib/cpp11api/ts-cpp11-headers.h
deleted file mode 100644
index cfe94bc..0000000
--- a/lib/cpp11api/ts-cpp11-headers.h
+++ /dev/null
@@ -1,120 +0,0 @@
-/** @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 TS_CPP11_HEADERS_H_
-#define TS_CPP11_HEADERS_H_
-#include <functional>
-#include <string>
-#include <vector>
-#include <memory>
-
-namespace ats {
-namespace api {
-namespace headers {
-
-class Header;
-typedef typename std::vector<Header> HeaderVector;
-
-class Header {
-private:
-  std::string name_;
-  std::vector<std::string> field_values_;
-public:
-  Header() {
-  }
-  Header(const std::string &name, const std::string &value) {
-    name_ = name;
-    addNewValue(value);
-  }
-
-  Header(std::string name, const std::vector<std::string> & values) {
-    name_ = name;
-    field_values_ = values;
-  }
-
-  void assignName(const std::string & name) {
-    name_ = name;
-  }
-
-  void assignName(const char *buf, size_t len) {
-    name_.assign(buf, len);
-  }
-
-  void addNewValue(const char *buf, size_t len) {
-    std::string newVal(buf, len);
-    field_values_.push_back(newVal);
-  }
-
-  void addNewValue(std::string value) {
-    field_values_.push_back(value);
-  }
-
-  int getNumValues() const {
-    return field_values_.size();
-  }
-
-  std::string getValue(int valueindx) const{
-    return field_values_[valueindx];
-  }
-
-  std::string getName() const {
-    return name_;
-  }
-
-  std::string getJoinedValues() const {
-    std::string ret;
-
-    for (std::vector<std::string>::size_type i = 0; i < field_values_.size();
-        ++i) {
-      if (i > 0)
-        ret.append(",");
-      ret.append(field_values_[i]);
-    }
-    return ret;
-  }
-
-  std::vector<std::string> getValues() const {
-    return field_values_;
-  }
-};
-
-
-
-/*
- *  predicates
- */
-class HeaderName: public std::unary_function<Header, bool> { // could probably be replaced with mem_ptr_fun()..
-private:
-  std::string name_;
-public:
-  HeaderName(std::string name) :
-      name_(name) {
-  }
-
-  bool operator()(const Header &field) const {
-    return (field.getName() == name_);
-  }
-};
-
-}
-}
-}
-
-#endif /* TS_CPP11_HEADERS_H_ */

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/cpp11api/ts-cpp11.h
----------------------------------------------------------------------
diff --git a/lib/cpp11api/ts-cpp11.h b/lib/cpp11api/ts-cpp11.h
deleted file mode 100644
index b1e2a48..0000000
--- a/lib/cpp11api/ts-cpp11.h
+++ /dev/null
@@ -1,126 +0,0 @@
-/** @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 TS_CPP11_H_
-#define TS_CPP11_H_
-
-#ifndef __GXX_EXPERIMENTAL_CXX0X__
-#error The C++ Apache Traffic Server API wrapper requires C++11 support.
-#endif
-
-#include <functional>
-#include <string>
-#include <vector>
-#include "ts-cpp11-headers.h"
-
-namespace ats {
-namespace api {
-typedef std::vector<std::string> StringVector;
-
-enum class HookType {
-  HOOK_PRE_REMAP = 100,
-  HOOK_POST_REMAP,
-  HOOK_READ_RESPONSE_HEADERS,
-  HOOK_READ_REQUEST_HEADERS,
-  HOOK_SEND_RESPONSE_HEADERS,
-  HOOK_TRANSACTION_START,
-  HOOK_TRANSACTION_END
-};
-
-enum class NextState {
-  HTTP_CONTINUE = 200, HTTP_ERROR, HTTP_DONT_CONTINUE
-};
-
-class Transaction;
-
-/*
- * This is the type our global hook callbacks will take
- */
-typedef std::function<NextState(Transaction &)> GlobalHookCallback;
-
-/*
- * Create a new hook
- */
-void CreateGlobalHook(HookType, GlobalHookCallback);
-void CreateTransactionHook(Transaction &, HookType, GlobalHookCallback);
-
-std::string GetRequestUrl(Transaction &);
-std::string GetPristineRequestUrl(Transaction &);
-std::string GetRequestUrlPath(Transaction &);
-std::string GetPristineRequestUrlPath(Transaction &);
-void SetRequestUrlPath(Transaction &, const std::string &);
-std::string GetRequestUrlQuery(Transaction &);
-std::string GetPristineRequestUrlQuery(Transaction &);
-void SetRequestUrlQuery(Transaction &, const std::string &);
-std::string GetRequestUrlHost(Transaction &);
-std::string GetPristineRequestUrlHost(Transaction &);
-void SetRequestUrlHost(Transaction &, const std::string &);
-std::string GetRequestUrlScheme(Transaction &);
-std::string GetPristineRequestUrlScheme(Transaction &);
-void SetRequestUrlScheme(Transaction &, const std::string &);
-unsigned int GetRequestUrlPort(Transaction &);
-unsigned int GetPristineRequestUrlPort(Transaction &);
-void SetRequestUrlPort(Transaction &, unsigned int);
-std::string GetClientIP(Transaction &);
-unsigned int GetClientPort(Transaction &);
-std::string GetServerIncomingIP(Transaction &);
-unsigned int GetServerIncomingPort(Transaction &);
-std::string GetRequestMethod(Transaction &t);
-void SetRequestMethod(Transaction &t, const std::string &);
-int GetServerResponseStatusCode(Transaction &t);
-bool IsInternalRequest(Transaction &);
-void* GetTransactionIdentifier(Transaction &);
-void ReenableTransaction(Transaction &, NextState);
-
-/* headers */
-// TODO: Switch these out to deal with shared_ptrs to a HeaderVector
-namespace headers {
-HeaderVector GetClientRequestHeaders(Transaction &);
-HeaderVector GetClientResponseHeaders(Transaction &);
-HeaderVector GetServerResponseHeaders(Transaction &);
-Header GetClientRequestHeader(Transaction &, const std::string &);
-Header GetClientResponseHeader(Transaction &, const std::string &);
-Header GetServerResponseHeader(Transaction &, const std::string &);
-void DeleteClientRequestHeader(Transaction &, const std::string &);
-void DeleteClientResponseHeader(Transaction &, const std::string &);
-void DeleteServerResponseHeader(Transaction &, const std::string &);
-void SetClientRequestHeader(Transaction &, const std::string &, const std::vector<std::string> &);
-void SetClientResponseHeader(Transaction &, const std::string &, const std::vector<std::string> &);
-void SetServerResponseHeader(Transaction &, const std::string &, const std::vector<std::string> &);
-void SetClientRequestHeader(Transaction &, const std::string &, const std::string &);
-void SetClientResponseHeader(Transaction &, const std::string &, const std::string &);
-void SetServerResponseHeader(Transaction &, const std::string &, const std::string &);
-void AppendClientRequestHeader(Transaction &, const std::string &, const std::vector<std::string> &);
-void AppendClientResponseHeader(Transaction &, const std::string &, const std::vector<std::string> &);
-void AppendServerResponseHeader(Transaction &, const std::string &, const std::vector<std::string> &);
-void AppendClientRequestHeader(Transaction &, const std::string &, const std::string &);
-void AppendClientResponseHeader(Transaction &, const std::string &, const std::string &);
-void AppendServerResponseHeader(Transaction &, const std::string &, const std::string &);
-} /* headers */
-
-} /* api */
-} /* ats */
-
-/*
- * Every plugin must have a simple entry point
- */
-void PluginRegister(const ats::api::StringVector &);
-
-#endif /* TS_CPP11_H_ */


[5/5] git commit: initial atscppapi commit

Posted by br...@apache.org.
initial atscppapi commit


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

Branch: refs/heads/master
Commit: 7b2ea5f899dcc58d05d8681ba8332b90b5cc8f55
Parents: cc25667
Author: Brian Geffon <br...@apache.org>
Authored: Fri Oct 18 14:50:54 2013 -0700
Committer: Brian Geffon <br...@apache.org>
Committed: Fri Oct 18 14:50:54 2013 -0700

----------------------------------------------------------------------
 lib/atscppapi/Makefile.am                       |  19 +
 lib/atscppapi/examples/Makefile.am              |  38 +
 .../examples/async_http_fetch/AsyncHttpFetch.cc | 144 +++
 .../examples/async_http_fetch/Makefile.am       |  30 +
 .../examples/async_timer/AsyncTimer.cc          |  75 ++
 lib/atscppapi/examples/async_timer/Makefile.am  |  30 +
 .../examples/clientredirect/ClientRedirect.cc   |  76 ++
 .../examples/clientredirect/Makefile.am         |  29 +
 .../examples/clientrequest/ClientRequest.cc     | 133 +++
 .../examples/clientrequest/Makefile.am          |  30 +
 .../examples/customresponse/CustomResponse.cc   |  82 ++
 .../examples/customresponse/Makefile.am         |  29 +
 lib/atscppapi/examples/data_caching/Makefile.am |  29 +
 .../examples/data_caching/data_caching.cc       |  98 +++
 .../examples/detachedrequest/DetachedRequest.cc |  69 ++
 .../examples/detachedrequest/Makefile.am        |  30 +
 .../examples/globalhook/GlobalHookPlugin.cc     |  44 +
 lib/atscppapi/examples/globalhook/Makefile.am   |  29 +
 .../GzipTransformationPlugin.cc                 | 170 ++++
 .../examples/gzip_transformation/Makefile.am    |  30 +
 .../examples/helloworld/HelloWorldPlugin.cc     |  36 +
 lib/atscppapi/examples/helloworld/Makefile.am   |  29 +
 .../InternalTransactionHandling.cc              |  65 ++
 .../internal_transaction_handling/Makefile.am   |  29 +
 .../examples/logger_example/LoggerExample.cc    | 132 +++
 .../examples/logger_example/Makefile.am         |  30 +
 .../multiple_transaction_hooks/Makefile.am      |  29 +
 .../MultipleTransactionHookPlugins.cc           | 100 +++
 .../null_transformation_plugin/Makefile.am      |  30 +
 .../NullTransformationPlugin.cc                 |  71 ++
 lib/atscppapi/examples/post_buffer/Makefile.am  |  29 +
 .../examples/post_buffer/PostBuffer.cc          |  75 ++
 lib/atscppapi/examples/remap_plugin/Makefile.am |  30 +
 .../examples/remap_plugin/RemapPlugin.cc        |  86 ++
 .../examples/request_cookies/Makefile.am        |  30 +
 .../examples/request_cookies/RequestCookies.cc  |  67 ++
 .../examples/serverresponse/Makefile.am         |  29 +
 .../examples/serverresponse/ServerResponse.cc   | 105 +++
 lib/atscppapi/examples/stat_example/Makefile.am |  30 +
 .../examples/stat_example/StatExample.cc        |  71 ++
 .../examples/timeout_example/Makefile.am        |  30 +
 .../timeout_example/TimeoutExamplePlugin.cc     |  56 ++
 .../examples/transactionhook/Makefile.am        |  30 +
 .../transactionhook/TransactionHookPlugin.cc    |  60 ++
 lib/atscppapi/src/AsyncHttpFetch.cc             | 170 ++++
 lib/atscppapi/src/AsyncTimer.cc                 | 106 +++
 .../src/CaseInsensitiveStringComparator.cc      |  70 ++
 lib/atscppapi/src/ClientRequest.cc              |  75 ++
 lib/atscppapi/src/GlobalPlugin.cc               |  78 ++
 lib/atscppapi/src/GzipDeflateTransformation.cc  | 156 ++++
 lib/atscppapi/src/GzipInflateTransformation.cc  | 130 +++
 lib/atscppapi/src/Headers.cc                    | 532 +++++++++++
 lib/atscppapi/src/HttpMethod.cc                 |  36 +
 lib/atscppapi/src/HttpVersion.cc                |  29 +
 lib/atscppapi/src/InitializableValue.cc         |  29 +
 lib/atscppapi/src/Logger.cc                     | 213 +++++
 lib/atscppapi/src/Makefile.am                   |  77 ++
 lib/atscppapi/src/Plugin.cc                     |  31 +
 lib/atscppapi/src/RemapPlugin.cc                |  66 ++
 lib/atscppapi/src/Request.cc                    | 167 ++++
 lib/atscppapi/src/Response.cc                   | 126 +++
 lib/atscppapi/src/Stat.cc                       |  96 ++
 lib/atscppapi/src/Transaction.cc                | 300 +++++++
 lib/atscppapi/src/TransactionPlugin.cc          |  83 ++
 lib/atscppapi/src/TransformationPlugin.cc       | 319 +++++++
 lib/atscppapi/src/Url.cc                        | 218 +++++
 lib/atscppapi/src/include/InitializableValue.h  |  90 ++
 lib/atscppapi/src/include/atscppapi/Async.h     | 187 ++++
 .../src/include/atscppapi/AsyncHttpFetch.h      | 102 +++
 .../src/include/atscppapi/AsyncTimer.h          |  78 ++
 .../atscppapi/CaseInsensitiveStringComparator.h |  51 ++
 .../src/include/atscppapi/ClientRequest.h       |  59 ++
 .../src/include/atscppapi/GlobalPlugin.h        |  90 ++
 .../atscppapi/GzipDeflateTransformation.h       |  91 ++
 .../atscppapi/GzipInflateTransformation.h       |  92 ++
 lib/atscppapi/src/include/atscppapi/Headers.h   | 246 ++++++
 .../src/include/atscppapi/HttpMethod.h          |  58 ++
 .../src/include/atscppapi/HttpStatus.h          | 104 +++
 .../src/include/atscppapi/HttpVersion.h         |  52 ++
 lib/atscppapi/src/include/atscppapi/Logger.h    | 268 ++++++
 lib/atscppapi/src/include/atscppapi/Mutex.h     | 250 ++++++
 lib/atscppapi/src/include/atscppapi/Plugin.h    | 106 +++
 .../src/include/atscppapi/PluginInit.h          |  55 ++
 .../src/include/atscppapi/RemapPlugin.h         |  69 ++
 lib/atscppapi/src/include/atscppapi/Request.h   |  72 ++
 lib/atscppapi/src/include/atscppapi/Response.h  |  71 ++
 lib/atscppapi/src/include/atscppapi/Stat.h      | 106 +++
 .../src/include/atscppapi/Transaction.h         | 314 +++++++
 .../src/include/atscppapi/TransactionPlugin.h   | 113 +++
 .../include/atscppapi/TransformationPlugin.h    | 129 +++
 lib/atscppapi/src/include/atscppapi/Url.h       | 149 ++++
 .../src/include/atscppapi/noncopyable.h         |  64 ++
 .../src/include/atscppapi/shared_ptr.h          |  41 +
 lib/atscppapi/src/include/atscppapi/utils.h     |  69 ++
 lib/atscppapi/src/include/logging_internal.h    |  44 +
 lib/atscppapi/src/include/utils_internal.h      |  89 ++
 lib/atscppapi/src/utils.cc                      |  79 ++
 lib/atscppapi/src/utils_internal.cc             | 246 ++++++
 lib/cpp11api/Makefile.am                        |  37 -
 lib/cpp11api/cpp11api.cc                        | 880 -------------------
 lib/cpp11api/ts-cpp11-headers.h                 | 120 ---
 lib/cpp11api/ts-cpp11.h                         | 126 ---
 102 files changed, 9234 insertions(+), 1163 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/Makefile.am
----------------------------------------------------------------------
diff --git a/lib/atscppapi/Makefile.am b/lib/atscppapi/Makefile.am
new file mode 100644
index 0000000..028d09c
--- /dev/null
+++ b/lib/atscppapi/Makefile.am
@@ -0,0 +1,19 @@
+#
+#  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.
+includedir=$(prefix)/include/ts
+
+SUBDIRS = src

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/examples/Makefile.am
----------------------------------------------------------------------
diff --git a/lib/atscppapi/examples/Makefile.am b/lib/atscppapi/examples/Makefile.am
new file mode 100644
index 0000000..7a48ad0
--- /dev/null
+++ b/lib/atscppapi/examples/Makefile.am
@@ -0,0 +1,38 @@
+#
+#  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.
+
+SUBDIRS = helloworld \
+	  globalhook \
+      transactionhook \
+	  multiple_transaction_hooks \
+	  data_caching \
+	  clientrequest \
+	  serverresponse \
+	  clientredirect \
+	  customresponse \
+	  null_transformation_plugin \
+	  post_buffer \
+	  logger_example \
+      detachedrequest \
+	  stat_example \
+      remap_plugin \
+	  async_http_fetch \
+	  gzip_transformation \
+	  timeout_example \
+      internal_transaction_handling \
+      async_timer \
+      request_cookies
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/examples/async_http_fetch/AsyncHttpFetch.cc
----------------------------------------------------------------------
diff --git a/lib/atscppapi/examples/async_http_fetch/AsyncHttpFetch.cc b/lib/atscppapi/examples/async_http_fetch/AsyncHttpFetch.cc
new file mode 100644
index 0000000..c98e658
--- /dev/null
+++ b/lib/atscppapi/examples/async_http_fetch/AsyncHttpFetch.cc
@@ -0,0 +1,144 @@
+/**
+  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 <atscppapi/GlobalPlugin.h>
+#include <atscppapi/TransactionPlugin.h>
+#include <atscppapi/Logger.h>
+#include <atscppapi/Async.h>
+#include <atscppapi/AsyncHttpFetch.h>
+#include <atscppapi/PluginInit.h>
+#include <cstring>
+#include <cassert>
+
+using namespace atscppapi;
+using std::string;
+
+// This is for the -T tag debugging
+// To view the debug messages ./traffic_server -T "async_http_fetch_example.*"
+#define TAG "async_http_fetch_example"
+
+class AsyncHttpFetch2 : public AsyncHttpFetch {
+public:
+  AsyncHttpFetch2(string request) : AsyncHttpFetch(request) { };
+};
+
+class AsyncHttpFetch3 : public AsyncHttpFetch {
+public:
+  AsyncHttpFetch3(string request, HttpMethod method) : AsyncHttpFetch(request, method) { };
+};
+
+class TransactionHookPlugin : public TransactionPlugin, public AsyncReceiver<AsyncHttpFetch>,
+                              public AsyncReceiver<AsyncHttpFetch2>, public AsyncReceiver<AsyncHttpFetch3> {
+public:
+  TransactionHookPlugin(Transaction &transaction) :
+    TransactionPlugin(transaction), transaction_(transaction), num_fetches_pending_(0) {
+    TS_DEBUG(TAG, "Constructed TransactionHookPlugin, saved a reference to this transaction.");
+    registerHook(HOOK_SEND_REQUEST_HEADERS);
+  }
+
+  void handleSendRequestHeaders(Transaction &transaction) {
+    Async::execute<AsyncHttpFetch>(this, new AsyncHttpFetch("http://127.0.0.1/"), getMutex());
+    ++num_fetches_pending_;
+
+    // we'll add some custom headers for this request
+    AsyncHttpFetch2 *provider2 = new AsyncHttpFetch2("http://127.0.0.1/");
+    Headers &request_headers = provider2->getRequestHeaders();
+    request_headers.set("Header1", "Value1");
+    request_headers.set("Header2", "Value2");
+    Async::execute<AsyncHttpFetch2>(this, provider2, getMutex());
+    ++num_fetches_pending_;
+  }
+
+  void handleAsyncComplete(AsyncHttpFetch &async_http_fetch) {
+    // This will be called when our async event is complete.
+    TS_DEBUG(TAG, "AsyncHttpFetch completed");
+    handleAnyAsyncComplete(async_http_fetch);
+  }
+
+  void handleAsyncComplete(AsyncHttpFetch2 &async_http_fetch) {
+    // This will be called when our async event is complete.
+    TS_DEBUG(TAG, "AsyncHttpFetch2 completed");
+    handleAnyAsyncComplete(async_http_fetch);
+  }
+
+  virtual ~TransactionHookPlugin() {
+    TS_DEBUG(TAG, "Destroyed TransactionHookPlugin!");
+    // since we die right away, we should not receive the callback for this (using POST request this time)
+    Async::execute<AsyncHttpFetch3>(this, new AsyncHttpFetch3("http://127.0.0.1/", HTTP_METHOD_POST), getMutex());
+  }
+
+  void handleAsyncComplete(AsyncHttpFetch3 &async_http_fetch) {
+    assert(!"AsyncHttpFetch3 shouldn't have completed!");
+  }
+
+private:
+  Transaction &transaction_;
+  int num_fetches_pending_;
+
+  void handleAnyAsyncComplete(AsyncHttpFetch &async_http_fetch) {
+    // This will be called when our async event is complete.
+    const Response &response = async_http_fetch.getResponse();
+    if (async_http_fetch.getResult() == AsyncHttpFetch::RESULT_SUCCESS) {
+      TS_DEBUG(TAG, "Response version is [%s], status code %d, reason phrase [%s]",
+               HTTP_VERSION_STRINGS[response.getVersion()].c_str(), response.getStatusCode(), 
+               response.getReasonPhrase().c_str());
+      for (Headers::const_iterator iter = response.getHeaders().begin(), end = response.getHeaders().end();
+           iter != end; ++iter) {
+        TS_DEBUG(TAG, "*************** Response header: name [%s], values [%s]", iter->first.c_str(), 
+                 Headers::getJoinedValues(iter->second).c_str());;
+      }
+      const void *body;
+      size_t body_size;
+      async_http_fetch.getResponseBody(body, body_size);
+      TS_DEBUG(TAG, "Response body is [%.*s]", body_size, body);
+    } else {
+      TS_ERROR(TAG, "Fetch did not complete successfully; Result %d",
+               static_cast<int>(async_http_fetch.getResult()));
+    }
+    if (--num_fetches_pending_ == 0) {
+      TS_DEBUG(TAG, "Reenabling transaction");
+      transaction_.resume();
+    }
+  }
+
+};
+
+class GlobalHookPlugin : public GlobalPlugin {
+public:
+  GlobalHookPlugin() {
+    TS_DEBUG(TAG, "Registering a global hook HOOK_READ_REQUEST_HEADERS_POST_REMAP");
+    registerHook(HOOK_READ_REQUEST_HEADERS_POST_REMAP);
+  }
+
+  virtual void handleReadRequestHeadersPostRemap(Transaction &transaction) {
+    TS_DEBUG(TAG, "Received a request in handleReadRequestHeadersPostRemap.");
+
+    // If we don't make sure to check if it's an internal request we can get ourselves into an infinite loop!
+    if (!transaction.isInternalRequest()) {
+      transaction.addPlugin(new TransactionHookPlugin(transaction));
+    }
+    transaction.resume();
+  }
+};
+
+void TSPluginInit(int argc, const char *argv[]) {
+  TS_DEBUG(TAG, "Loaded async_http_fetch_example plugin");
+  GlobalPlugin *instance = new GlobalHookPlugin();
+}
+

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/examples/async_http_fetch/Makefile.am
----------------------------------------------------------------------
diff --git a/lib/atscppapi/examples/async_http_fetch/Makefile.am b/lib/atscppapi/examples/async_http_fetch/Makefile.am
new file mode 100644
index 0000000..dd1dd94
--- /dev/null
+++ b/lib/atscppapi/examples/async_http_fetch/Makefile.am
@@ -0,0 +1,30 @@
+#
+#  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.
+
+AM_CPPFLAGS = -I$(top_srcdir)/src/include
+
+target=AsyncHttpFetch.so
+pkglibdir = ${pkglibexecdir}
+pkglib_LTLIBRARIES = AsyncHttpFetch.la
+AsyncHttpFetch_la_SOURCES = AsyncHttpFetch.cc
+AsyncHttpFetch_la_LDFLAGS = -module -avoid-version -shared -L$(top_srcdir) -latscppapi
+
+all:
+	ln -sf .libs/$(target)
+
+clean-local:
+	rm -f $(target)

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/examples/async_timer/AsyncTimer.cc
----------------------------------------------------------------------
diff --git a/lib/atscppapi/examples/async_timer/AsyncTimer.cc b/lib/atscppapi/examples/async_timer/AsyncTimer.cc
new file mode 100644
index 0000000..296d815
--- /dev/null
+++ b/lib/atscppapi/examples/async_timer/AsyncTimer.cc
@@ -0,0 +1,75 @@
+/**
+  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 <atscppapi/Logger.h>
+#include <atscppapi/PluginInit.h>
+#include <atscppapi/AsyncTimer.h>
+#include <atscppapi/GlobalPlugin.h>
+
+using namespace atscppapi;
+using std::string;
+
+#define TAG "async_timer"
+
+class TimerEventReceiver : public AsyncReceiver<AsyncTimer> {
+public:
+  TimerEventReceiver(AsyncTimer::Type type, int period_in_ms, int initial_period_in_ms = 0, int max_instances = 0)
+    : max_instances_(max_instances), instance_count_(0), type_(type) {
+    timer_ = new AsyncTimer(type, period_in_ms, initial_period_in_ms);
+    Async::execute<AsyncTimer>(this, timer_, shared_ptr<Mutex>()); // letting the system create the mutex
+  }
+
+  void handleAsyncComplete(AsyncTimer &timer) {
+    TS_DEBUG(TAG, "Got timer event in object %p!", this);
+    if ((type_ == AsyncTimer::TYPE_ONE_OFF) || (max_instances_ && (++instance_count_ == max_instances_))) {
+      TS_DEBUG(TAG, "Stopping timer in object %p!", this);
+      delete this;
+    }
+  }
+
+  ~TimerEventReceiver() {
+    delete timer_;
+  }
+
+private:
+  int max_instances_;
+  int instance_count_;
+  AsyncTimer::Type type_;
+  AsyncTimer *timer_;
+};
+
+void TSPluginInit(int argc, const char *argv[]) {
+  int period_in_ms = 1000;
+  TimerEventReceiver *timer1 = new TimerEventReceiver(AsyncTimer::TYPE_PERIODIC, period_in_ms);
+  TS_DEBUG(TAG, "Created periodic timer %p with initial period 0, regular period %d and max instances 0", timer1,
+           period_in_ms);
+  int initial_period_in_ms = 100;
+  TimerEventReceiver *timer2 = new TimerEventReceiver(AsyncTimer::TYPE_PERIODIC, period_in_ms,
+                                                      initial_period_in_ms);
+  TS_DEBUG(TAG, "Created periodic timer %p with initial period %d, regular period %d and max instances 0", timer2,
+           initial_period_in_ms, period_in_ms);
+  initial_period_in_ms = 200;
+  int max_instances = 10;
+  TimerEventReceiver *timer3 = new TimerEventReceiver(AsyncTimer::TYPE_PERIODIC, period_in_ms, initial_period_in_ms,
+                                                      max_instances);
+  TS_DEBUG(TAG, "Created periodic timer %p with initial period %d, regular period %d and max instances %d", timer3,
+           initial_period_in_ms, period_in_ms, max_instances);
+
+  TimerEventReceiver *timer4 = new TimerEventReceiver(AsyncTimer::TYPE_ONE_OFF, period_in_ms);
+  TS_DEBUG(TAG, "Created one-off timer %p with period %d", timer4, period_in_ms);
+}

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/examples/async_timer/Makefile.am
----------------------------------------------------------------------
diff --git a/lib/atscppapi/examples/async_timer/Makefile.am b/lib/atscppapi/examples/async_timer/Makefile.am
new file mode 100644
index 0000000..577d8d7
--- /dev/null
+++ b/lib/atscppapi/examples/async_timer/Makefile.am
@@ -0,0 +1,30 @@
+#
+#  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.
+
+AM_CPPFLAGS = -I$(top_srcdir)/src/include
+
+target=AsyncTimer.so
+pkglibdir = ${pkglibexecdir}
+pkglib_LTLIBRARIES = AsyncTimer.la
+AsyncTimer_la_SOURCES = AsyncTimer.cc
+AsyncTimer_la_LDFLAGS = -module -avoid-version -shared -L$(top_srcdir) -latscppapi
+
+all:
+	ln -sf .libs/$(target)
+
+clean-local:
+	rm -f $(target)

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/examples/clientredirect/ClientRedirect.cc
----------------------------------------------------------------------
diff --git a/lib/atscppapi/examples/clientredirect/ClientRedirect.cc b/lib/atscppapi/examples/clientredirect/ClientRedirect.cc
new file mode 100644
index 0000000..1da6533
--- /dev/null
+++ b/lib/atscppapi/examples/clientredirect/ClientRedirect.cc
@@ -0,0 +1,76 @@
+/**
+  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 <iostream>
+#include <atscppapi/GlobalPlugin.h>
+#include <atscppapi/TransactionPlugin.h>
+#include <atscppapi/PluginInit.h>
+
+using namespace atscppapi;
+
+using std::cout;
+using std::endl;
+using std::list;
+using std::string;
+
+
+class ClientRedirectTransactionPlugin : public atscppapi::TransactionPlugin {
+public:
+  ClientRedirectTransactionPlugin(Transaction &transaction, const string &location)
+     : TransactionPlugin(transaction), location_(location) {
+
+    //
+    // We will set this transaction to jump to error state and then we will setup
+    // the redirect on SEND_RESPONSE_HEADERS
+    //
+    TransactionPlugin::registerHook(HOOK_SEND_RESPONSE_HEADERS);
+    transaction.error();
+  }
+
+  void handleSendResponseHeaders(Transaction &transaction) {
+    transaction.getClientResponse().setStatusCode(HTTP_STATUS_MOVED_TEMPORARILY);
+    transaction.getClientResponse().setReasonPhrase("Moved Temporarily");
+    transaction.getClientResponse().getHeaders().set("Location", location_);
+    transaction.resume();
+  }
+
+  virtual ~ClientRedirectTransactionPlugin() { }
+private:
+  string location_;
+};
+
+
+class ClientRedirectGlobalPlugin : public GlobalPlugin {
+public:
+  ClientRedirectGlobalPlugin() {
+    registerHook(HOOK_SEND_REQUEST_HEADERS);
+  }
+
+  void handleSendRequestHeaders(Transaction &transaction) {
+    if(transaction.getClientRequest().getUrl().getQuery().find("redirect=1") != string::npos) {
+      transaction.addPlugin(new ClientRedirectTransactionPlugin(transaction, "http://www.linkedin.com/"));
+      return;
+    }
+    transaction.resume();
+  }
+
+};
+
+void TSPluginInit(int argc, const char *argv[]) {
+  GlobalPlugin *instance = new ClientRedirectGlobalPlugin();
+}

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/examples/clientredirect/Makefile.am
----------------------------------------------------------------------
diff --git a/lib/atscppapi/examples/clientredirect/Makefile.am b/lib/atscppapi/examples/clientredirect/Makefile.am
new file mode 100644
index 0000000..ec1629c
--- /dev/null
+++ b/lib/atscppapi/examples/clientredirect/Makefile.am
@@ -0,0 +1,29 @@
+#
+#  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.
+AM_CPPFLAGS = -I$(top_srcdir)/src/include
+
+target=ClientRedirect.so
+pkglibdir = ${pkglibexecdir}
+pkglib_LTLIBRARIES = ClientRedirect.la
+ClientRedirect_la_SOURCES = ClientRedirect.cc
+ClientRedirect_la_LDFLAGS = -module -avoid-version -shared -L$(top_srcdir) -latscppapi
+
+all:
+	ln -sf .libs/$(target)
+
+clean-local:
+	rm -f $(target)

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/examples/clientrequest/ClientRequest.cc
----------------------------------------------------------------------
diff --git a/lib/atscppapi/examples/clientrequest/ClientRequest.cc b/lib/atscppapi/examples/clientrequest/ClientRequest.cc
new file mode 100644
index 0000000..b143374
--- /dev/null
+++ b/lib/atscppapi/examples/clientrequest/ClientRequest.cc
@@ -0,0 +1,133 @@
+/**
+  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 <iostream>
+#include <atscppapi/GlobalPlugin.h>
+#include <atscppapi/PluginInit.h>
+#include <atscppapi/utils.h>
+
+using namespace atscppapi;
+
+using std::cout;
+using std::endl;
+using std::list;
+using std::string;
+
+class GlobalHookPlugin : public GlobalPlugin {
+public:
+  GlobalHookPlugin() {
+    registerHook(HOOK_READ_REQUEST_HEADERS_PRE_REMAP);
+    registerHook(HOOK_READ_REQUEST_HEADERS_POST_REMAP);
+    registerHook(HOOK_SEND_REQUEST_HEADERS);
+  }
+
+
+  void handleReadRequestHeadersPreRemap(Transaction &transaction) {
+    cout << "Hello from handleReadRequesHeadersPreRemap!" << endl;
+
+    ClientRequest &client_request = transaction.getClientRequest();
+    Url &request_url = client_request.getUrl();
+    const Url &pristine_request_url = client_request.getPristineUrl();
+
+    cout << "Method is " << HTTP_METHOD_STRINGS[client_request.getMethod()] << endl;
+    cout << "Version is " << HTTP_VERSION_STRINGS[client_request.getVersion()] << endl;
+    cout << "---------------------------------------------------" << endl;
+    cout << "URL is " << request_url.getUrlString() << endl;
+    cout << "Path is " << request_url.getPath() << endl;
+    cout << "Query is " << request_url.getQuery() << endl;
+    cout << "Host is " << request_url.getHost() << endl;
+    cout << "Port is " << request_url.getPort() << endl;
+    cout << "Scheme is " << request_url.getScheme() << endl;
+    cout << "---------------------------------------------------" << endl;
+    if (request_url.getPath() == "remap_me") {
+      request_url.setPath("index.html");
+    }
+
+    transaction.resume();
+  }
+
+
+  void handleReadRequestHeadersPostRemap(Transaction &transaction) {
+    cout << "Hello from handleReadRequesHeadersPostRemap!" << endl;
+
+    ClientRequest &client_request = transaction.getClientRequest();
+    Url &request_url = client_request.getUrl();
+    const Url &pristine_request_url = client_request.getPristineUrl();
+
+    cout << "--------------------PRISTINE-----------------------" << endl;
+    cout << "URL is " << pristine_request_url.getUrlString() << endl;
+    cout << "Path is " << pristine_request_url.getPath() << endl;
+    cout << "--------------------POST REMAP---------------------" << endl;
+    cout << "URL is " << request_url.getUrlString() << endl;
+    cout << "Path is " << request_url.getPath() << endl;
+    cout << "---------------------------------------------------" << endl;
+
+    Headers &client_request_headers = client_request.getHeaders();
+
+    Headers::const_iterator ii = client_request_headers.find("AccepT-EncodinG");
+    if(ii != client_request_headers.end()) {
+      cout << "Deleting accept-encoding header" << endl;
+      client_request_headers.erase("AccepT-EnCoDing"); // Case Insensitive
+    }
+
+    // These will be split back up into a list of three values automatically (see header output below).
+    cout << "Adding back Accept-Encoding." << endl;
+    client_request_headers.set("accept-encoding", "gzip, identity, my_special_format");
+
+    cout << "Adding a new accept type accept header" << endl;
+    client_request_headers.append("accept", "text/blah");
+
+    for (Headers::const_iterator header_iter = client_request_headers.begin(),
+           header_end = client_request_headers.end(); header_iter != header_end; ++header_iter) {
+      const string &name = header_iter->first;
+      const list<string> &value_list = header_iter->second;
+      cout << "Header. " << name <<  ": " << endl;
+      for (list<string>::const_iterator value_iter = value_list.begin(), value_end = value_list.end();
+           value_iter != value_end; ++value_iter) {
+        cout << "\t" << *value_iter << endl;
+      }
+    }
+
+    /*
+     * These will output:
+     * Joining on a non-existant header gives:
+     * Joining the accept encoding header gives: gzip,identity,my_special_format
+     * Joining the accept encoding header with space gives: gzip identity my_special_format
+     */
+    cout << "Joining on a non-existant header gives: " << client_request_headers.getJoinedValues("i_dont_exist") << endl;
+    cout << "Joining the accept encoding header gives: " << client_request_headers.getJoinedValues("accept-encoding") << endl;
+    cout << "Joining the accept encoding header with space gives: " << client_request_headers.getJoinedValues("accept-encoding", ' ') << endl;
+
+    transaction.resume();
+  }
+
+  void handleSendRequestHeaders(Transaction &transaction) {
+    cout << "Hello from handleSendRequestHeaders!" << endl;
+    cout << "---------------------IP INFORMATION-----------------" << endl;
+    cout << "Server Address: " << utils::getIpPortString(transaction.getServerAddress()) << endl;
+    cout << "Incoming Address: " << utils::getIpPortString(transaction.getIncomingAddress()) << endl;
+    cout << "Client Address: " << utils::getIpPortString(transaction.getClientAddress()) << endl;
+    cout << "Next Hop Address: " << utils::getIpPortString(transaction.getNextHopAddress()) << endl;
+    transaction.resume();
+  }
+
+};
+
+void TSPluginInit(int argc, const char *argv[]) {
+  GlobalPlugin *instance = new GlobalHookPlugin();
+}

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/examples/clientrequest/Makefile.am
----------------------------------------------------------------------
diff --git a/lib/atscppapi/examples/clientrequest/Makefile.am b/lib/atscppapi/examples/clientrequest/Makefile.am
new file mode 100644
index 0000000..9041577
--- /dev/null
+++ b/lib/atscppapi/examples/clientrequest/Makefile.am
@@ -0,0 +1,30 @@
+#
+#  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.
+
+AM_CPPFLAGS = -I$(top_srcdir)/src/include
+
+target=ClientRequest.so
+pkglibdir = ${pkglibexecdir}
+pkglib_LTLIBRARIES = ClientRequest.la
+ClientRequest_la_SOURCES = ClientRequest.cc
+ClientRequest_la_LDFLAGS = -module -avoid-version -shared -L$(top_srcdir) -latscppapi
+
+all:
+	ln -sf .libs/$(target)
+
+clean-local:
+	rm -f $(target)

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/examples/customresponse/CustomResponse.cc
----------------------------------------------------------------------
diff --git a/lib/atscppapi/examples/customresponse/CustomResponse.cc b/lib/atscppapi/examples/customresponse/CustomResponse.cc
new file mode 100644
index 0000000..870a838
--- /dev/null
+++ b/lib/atscppapi/examples/customresponse/CustomResponse.cc
@@ -0,0 +1,82 @@
+/**
+  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 <iostream>
+#include <string>
+#include <atscppapi/GlobalPlugin.h>
+#include <atscppapi/TransactionPlugin.h>
+#include <atscppapi/PluginInit.h>
+
+using namespace atscppapi;
+
+using std::cout;
+using std::endl;
+using std::string;
+
+/*
+ *
+ * This example demonstrates how you can exploit .error() to send
+ * any response from any state by forcing the state machine to
+ * jump to the error state. You will then send your custom
+ * response in sendResponseHeaders() rather than the error page.
+ *
+ */
+
+class CustomResponseTransactionPlugin : public atscppapi::TransactionPlugin {
+public:
+  CustomResponseTransactionPlugin(Transaction &transaction, HttpStatus status, const string &reason, const string &body)
+     : TransactionPlugin(transaction), status_(status), reason_(reason), body_(body) {
+    TransactionPlugin::registerHook(HOOK_SEND_RESPONSE_HEADERS);
+    transaction.error(body_); // Set the error body now, and change the status and reason later.
+  }
+
+  void handleSendResponseHeaders(Transaction &transaction) {
+    transaction.getClientResponse().setStatusCode(status_);
+    transaction.getClientResponse().setReasonPhrase(reason_);
+    transaction.resume();
+  }
+
+  virtual ~CustomResponseTransactionPlugin() { }
+private:
+  HttpStatus status_;
+  string reason_;
+  string body_;
+};
+
+
+class ClientRedirectGlobalPlugin : public GlobalPlugin {
+public:
+  ClientRedirectGlobalPlugin() {
+    registerHook(HOOK_SEND_REQUEST_HEADERS);
+  }
+
+  void handleSendRequestHeaders(Transaction &transaction) {
+    if(transaction.getClientRequest().getUrl().getQuery().find("custom=1") != string::npos) {
+      transaction.addPlugin(new CustomResponseTransactionPlugin(transaction, HTTP_STATUS_OK, "Ok",
+                                                                "Hello! This is a custom response without making "
+                                                                "an origin request and no server intercept."));
+      return; // dont forget to return since the CustomResponse call will call .error().
+    }
+    transaction.resume();
+  }
+
+};
+
+void TSPluginInit(int argc, const char *argv[]) {
+  GlobalPlugin *instance = new ClientRedirectGlobalPlugin();
+}

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/examples/customresponse/Makefile.am
----------------------------------------------------------------------
diff --git a/lib/atscppapi/examples/customresponse/Makefile.am b/lib/atscppapi/examples/customresponse/Makefile.am
new file mode 100644
index 0000000..1e7093a
--- /dev/null
+++ b/lib/atscppapi/examples/customresponse/Makefile.am
@@ -0,0 +1,29 @@
+#
+#  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.
+AM_CPPFLAGS = -I$(top_srcdir)/src/include
+
+target=CustomResponse.so
+pkglibdir = ${pkglibexecdir}
+pkglib_LTLIBRARIES = CustomResponse.la
+CustomResponse_la_SOURCES = CustomResponse.cc
+CustomResponse_la_LDFLAGS = -module -avoid-version -shared -L$(top_srcdir) -latscppapi
+
+all:
+	ln -sf .libs/$(target)
+
+clean-local:
+	rm -f $(target)

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/examples/data_caching/Makefile.am
----------------------------------------------------------------------
diff --git a/lib/atscppapi/examples/data_caching/Makefile.am b/lib/atscppapi/examples/data_caching/Makefile.am
new file mode 100644
index 0000000..818e965
--- /dev/null
+++ b/lib/atscppapi/examples/data_caching/Makefile.am
@@ -0,0 +1,29 @@
+#
+#  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.
+AM_CPPFLAGS = -I$(top_srcdir)/src/include
+
+target=data_caching.so
+pkglibdir = ${pkglibexecdir}
+pkglib_LTLIBRARIES = data_caching.la
+data_caching_la_SOURCES = data_caching.cc
+data_caching_la_LDFLAGS = -module -avoid-version -shared -L$(top_srcdir) -latscppapi
+
+all:
+	ln -sf .libs/$(target)
+
+clean-local:
+	rm -f $(target)

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/examples/data_caching/data_caching.cc
----------------------------------------------------------------------
diff --git a/lib/atscppapi/examples/data_caching/data_caching.cc b/lib/atscppapi/examples/data_caching/data_caching.cc
new file mode 100644
index 0000000..64ae4ee
--- /dev/null
+++ b/lib/atscppapi/examples/data_caching/data_caching.cc
@@ -0,0 +1,98 @@
+/**
+  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 <iostream>
+#include <cstdlib>
+#include <atscppapi/GlobalPlugin.h>
+#include <atscppapi/ClientRequest.h>
+#include <atscppapi/utils.h>
+
+#include <ts/ts.h>
+
+using namespace atscppapi;
+using namespace std;
+
+namespace {
+
+const string SPECIAL_HEADER("Special-Header");
+
+}
+
+class GlobalHookPlugin : public GlobalPlugin {
+public:
+  GlobalHookPlugin() {
+    registerHook(HOOK_READ_REQUEST_HEADERS_PRE_REMAP);
+    registerHook(HOOK_SEND_RESPONSE_HEADERS);
+  }
+
+  virtual void handleReadRequestHeadersPreRemap(Transaction &transaction) {
+    cout << "Hello from handleReadRequesHeadersPreRemap!" << endl;
+    checkForSpecialHeader(transaction.getClientRequest().getHeaders());
+    transaction.resume();
+  }
+
+  virtual void handleSendResponseHeaders(Transaction &transaction) {
+    cout << "Hello from handleSendResponseHeaders!" << endl;
+    checkForSpecialHeader(transaction.getClientRequest().getHeaders());
+    transaction.resume();
+  }
+
+private:
+  void checkForSpecialHeader(const Headers &headers) {
+    Headers::const_iterator iter = headers.find(SPECIAL_HEADER);
+    if (iter == headers.end()) {
+      cout << "Special header is absent" << endl;
+    } else {
+      cout << "Special header is present with value " << iter->second.front() << endl;
+    }
+  }
+};
+
+namespace {
+
+int handlePostRemap(TSCont cont, TSEvent event, void *edata) {
+  TSHttpTxn txn = static_cast<TSHttpTxn>(edata);
+  TSMBuffer hdr_buf;
+  TSMLoc hdr_loc, field_loc;
+  TSHttpTxnClientReqGet(txn, &hdr_buf, &hdr_loc);
+  int nullTerminatedStringLength = -1;
+  TSMimeHdrFieldCreateNamed(hdr_buf, hdr_loc, SPECIAL_HEADER.c_str(), nullTerminatedStringLength, &field_loc);
+  const char *value = "foo";
+  int insertAtBeginningIndex = 0;
+  TSMimeHdrFieldValueStringInsert(hdr_buf, hdr_loc, field_loc, insertAtBeginningIndex, value,
+                                  nullTerminatedStringLength);
+  TSMimeHdrFieldAppend(hdr_buf, hdr_loc, field_loc);
+  TSHandleMLocRelease(hdr_buf, hdr_loc, field_loc);
+  TSMLoc hdr_loc_null_parent = NULL;
+  TSHandleMLocRelease(hdr_buf, hdr_loc_null_parent, hdr_loc);
+  TSHttpTxnReenable(txn, TS_EVENT_HTTP_CONTINUE);
+  return 0;
+}
+
+}
+
+void TSPluginInit(int argc, const char *argv[]) {
+  int do_overwrite = 1;
+  setenv(utils::DISABLE_DATA_CACHING_ENV_FLAG.c_str(), "true", do_overwrite);
+
+  GlobalPlugin *instance = new GlobalHookPlugin();
+
+  TSMutex nullMutex = NULL;
+  TSCont globalCont = TSContCreate(handlePostRemap, nullMutex);
+  TSHttpHookAdd(TS_HTTP_POST_REMAP_HOOK, globalCont);
+}

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/examples/detachedrequest/DetachedRequest.cc
----------------------------------------------------------------------
diff --git a/lib/atscppapi/examples/detachedrequest/DetachedRequest.cc b/lib/atscppapi/examples/detachedrequest/DetachedRequest.cc
new file mode 100644
index 0000000..ee95118
--- /dev/null
+++ b/lib/atscppapi/examples/detachedrequest/DetachedRequest.cc
@@ -0,0 +1,69 @@
+/**
+  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 <atscppapi/GlobalPlugin.h>
+#include <atscppapi/PluginInit.h>
+#include <atscppapi/Logger.h>
+
+using namespace std;
+using namespace atscppapi;
+
+#define LOG_TAG "detachedrequest"
+
+class GlobalHookPlugin : public GlobalPlugin {
+public:
+  GlobalHookPlugin() {
+    registerHook(HOOK_READ_REQUEST_HEADERS_PRE_REMAP);
+  }
+  void handleReadRequestHeadersPreRemap(Transaction &transaction) {
+    string url_str("http://www.linkedin.com/");
+    Request detached_request(url_str);
+    Url &url = detached_request.getUrl();
+    TS_DEBUG(LOG_TAG, "Method is [%s], url is [%s], version is [%s]",
+             HTTP_METHOD_STRINGS[detached_request.getMethod()].c_str(),
+             detached_request.getUrl().getUrlString().c_str(),
+             HTTP_VERSION_STRINGS[detached_request.getVersion()].c_str());
+
+    Headers &detached_request_headers = detached_request.getHeaders();
+    TS_DEBUG(LOG_TAG, "Headers before adds");
+    printHeaders(detached_request_headers);
+
+    detached_request_headers.set("Header1", "value1");
+    detached_request_headers.append("Header1", "value2");
+    detached_request_headers.set("Header2", "value1");
+    TS_DEBUG(LOG_TAG, "Headers after adds");
+    printHeaders(detached_request_headers);
+
+    detached_request_headers.erase("Header1");
+    TS_DEBUG(LOG_TAG, "Headers after erase");
+    printHeaders(detached_request_headers);
+
+    transaction.resume();
+  }
+private:
+  void printHeaders(const Headers &headers) {
+    for (Headers::const_iterator iter = headers.begin(), end = headers.end(); iter != end; ++iter) {
+      TS_DEBUG(LOG_TAG, "Header [%s] has values [%s]", iter->first.c_str(),
+               Headers::getJoinedValues(iter->second).c_str());
+    }
+  }
+};
+
+void TSPluginInit(int argc, const char *argv[]) {
+  GlobalPlugin *instance = new GlobalHookPlugin();
+}

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/examples/detachedrequest/Makefile.am
----------------------------------------------------------------------
diff --git a/lib/atscppapi/examples/detachedrequest/Makefile.am b/lib/atscppapi/examples/detachedrequest/Makefile.am
new file mode 100644
index 0000000..afe0199
--- /dev/null
+++ b/lib/atscppapi/examples/detachedrequest/Makefile.am
@@ -0,0 +1,30 @@
+#
+#  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.
+
+AM_CPPFLAGS = -I$(top_srcdir)/src/include
+
+target=DetachedRequest.so
+pkglibdir = ${pkglibexecdir}
+pkglib_LTLIBRARIES = DetachedRequest.la
+DetachedRequest_la_SOURCES = DetachedRequest.cc
+DetachedRequest_la_LDFLAGS = -module -avoid-version -shared -L$(top_srcdir) -latscppapi
+
+all:
+	ln -sf .libs/$(target)
+
+clean-local:
+	rm -f $(target)

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/examples/globalhook/GlobalHookPlugin.cc
----------------------------------------------------------------------
diff --git a/lib/atscppapi/examples/globalhook/GlobalHookPlugin.cc b/lib/atscppapi/examples/globalhook/GlobalHookPlugin.cc
new file mode 100644
index 0000000..68ceebf
--- /dev/null
+++ b/lib/atscppapi/examples/globalhook/GlobalHookPlugin.cc
@@ -0,0 +1,44 @@
+/**
+  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 <iostream>
+#include <atscppapi/GlobalPlugin.h>
+#include <atscppapi/PluginInit.h>
+
+using namespace atscppapi;
+
+class GlobalHookPlugin : public GlobalPlugin {
+public:
+  GlobalHookPlugin() {
+    registerHook(HOOK_READ_REQUEST_HEADERS_PRE_REMAP, [](Transaction &t) {
+
+    });
+
+  }
+
+  virtual void handleReadRequestHeadersPreRemap(Transaction &transaction) {
+    std::cout << "Hello from handleReadRequesHeadersPreRemap!" << std::endl;
+    transaction.resume();
+  }
+};
+
+void TSPluginInit(int argc, const char *argv[]) {
+  GlobalPlugin *instance = new GlobalHookPlugin();
+}
+
+

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/examples/globalhook/Makefile.am
----------------------------------------------------------------------
diff --git a/lib/atscppapi/examples/globalhook/Makefile.am b/lib/atscppapi/examples/globalhook/Makefile.am
new file mode 100644
index 0000000..9269312
--- /dev/null
+++ b/lib/atscppapi/examples/globalhook/Makefile.am
@@ -0,0 +1,29 @@
+#
+#  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.
+AM_CPPFLAGS = -I$(top_srcdir)/src/include
+
+target=GlobalHookPlugin.so
+pkglibdir = ${pkglibexecdir}
+pkglib_LTLIBRARIES = GlobalHookPlugin.la
+GlobalHookPlugin_la_SOURCES = GlobalHookPlugin.cc
+GlobalHookPlugin_la_LDFLAGS = -module -avoid-version -shared -L$(top_srcdir) -latscppapi
+
+all:
+	ln -sf .libs/$(target)
+
+clean-local:
+	rm -f $(target)

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/examples/gzip_transformation/GzipTransformationPlugin.cc
----------------------------------------------------------------------
diff --git a/lib/atscppapi/examples/gzip_transformation/GzipTransformationPlugin.cc b/lib/atscppapi/examples/gzip_transformation/GzipTransformationPlugin.cc
new file mode 100644
index 0000000..176870f
--- /dev/null
+++ b/lib/atscppapi/examples/gzip_transformation/GzipTransformationPlugin.cc
@@ -0,0 +1,170 @@
+/**
+  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 <iostream>
+#include <atscppapi/GlobalPlugin.h>
+#include <atscppapi/TransactionPlugin.h>
+#include <atscppapi/TransformationPlugin.h>
+#include <atscppapi/GzipInflateTransformation.h>
+#include <atscppapi/GzipDeflateTransformation.h>
+#include <atscppapi/PluginInit.h>
+#include <atscppapi/Logger.h>
+
+using namespace atscppapi;
+using namespace atscppapi::transformations;
+using std::string;
+
+#define TAG "gzip_transformation"
+
+/*
+ * Note, the GzipInflateTransformation and GzipDeflateTransformation do not
+ * check headers to determine if the content was gziped and it doesn't check
+ * headers to make sure the client supports gzip, this is entirely up to the plugin
+ * to verify that the content-encoding is gzipped, it's also up to the client
+ * to make sure the user's accept-encoding supports gzip.
+ *
+ * Read this example very carefully, in this example we modify the Accept-Encoding
+ * header to the origin to ensure that we will be returned gzipped or identity encoding
+ * content. If we receive gzipped content we will inflate it, we will apply our transformation
+ * and if the client supports gzip we will deflate the content that we transformed. Finally,
+ * if the user supported gzip (then they got gzip) and we must make sure the content-encoding
+ * header is correctly set on the way out.
+ */
+
+class Helpers {
+public:
+  static bool clientAcceptsGzip(Transaction &transaction) {
+    return transaction.getClientRequest().getHeaders().getJoinedValues("Accept-Encoding").find("gzip") != string::npos;
+  }
+
+  static bool serverReturnedGzip(Transaction &transaction) {
+    return transaction.getServerResponse().getHeaders().getJoinedValues("Content-Encoding").find("gzip") != string::npos;
+  }
+
+  enum ContentType { UNKNOWN = 0, TEXT_HTML  = 1, TEXT_PLAIN = 2 };
+
+  static ContentType getContentType(Transaction &transaction) {
+    if (transaction.getServerResponse().getHeaders().getJoinedValues("Content-Type").find("text/html") != string::npos) {
+      return TEXT_HTML;
+    } else if (transaction.getServerResponse().getHeaders().getJoinedValues("Content-Type").find("text/plain") != string::npos) {
+      return TEXT_PLAIN;
+    } else {
+      return UNKNOWN;
+    }
+  }
+};
+
+class SomeTransformationPlugin : public TransformationPlugin {
+public:
+  SomeTransformationPlugin(Transaction &transaction)
+    : TransformationPlugin(transaction, RESPONSE_TRANSFORMATION), transaction_(transaction) {
+    registerHook(HOOK_SEND_RESPONSE_HEADERS);
+  }
+
+  void handleSendResponseHeaders(Transaction &transaction) {
+    TS_DEBUG(TAG, "Added X-Content-Transformed header");
+    transaction.getClientResponse().getHeaders().set("X-Content-Transformed", "1");
+    transaction.resume();
+  }
+
+  void consume(const string &data) {
+    produce(data);
+  }
+
+  void handleInputComplete() {
+    Helpers::ContentType content_type = Helpers::getContentType(transaction_);
+    if (content_type == Helpers::TEXT_HTML) {
+      TS_DEBUG(TAG, "Adding an HTML comment at the end of the page");
+      produce("\n<br /><!-- Gzip Transformation Plugin Was Here -->");
+    } else if (content_type == Helpers::TEXT_PLAIN) {
+      TS_DEBUG(TAG, "Adding a text comment at the end of the page");
+      produce("\nGzip Transformation Plugin Was Here");
+    } else {
+      TS_DEBUG(TAG, "Unable to add TEXT or HTML comment because content type was not text/html or text/plain.");
+    }
+    setOutputComplete();
+  }
+
+  virtual ~SomeTransformationPlugin() { }
+private:
+  Transaction &transaction_;
+};
+
+class GlobalHookPlugin : public GlobalPlugin {
+public:
+  GlobalHookPlugin() {
+    registerHook(HOOK_SEND_REQUEST_HEADERS);
+    registerHook(HOOK_READ_RESPONSE_HEADERS);
+    registerHook(HOOK_SEND_RESPONSE_HEADERS);
+  }
+
+  virtual void handleSendRequestHeaders(Transaction &transaction) {
+    // Since we can only decompress gzip we will change the accept encoding header
+    // to gzip, even if the user cannot accept gziped content we will return to them
+    // uncompressed content in that case since we have to be able to transform the content.
+    string original_accept_encoding = transaction.getServerRequest().getHeaders().getJoinedValues("Accept-Encoding");
+
+    // Make sure it's done on the server request to avoid clobbering the clients original accept encoding header.
+    transaction.getServerRequest().getHeaders().set("Accept-Encoding", "gzip");
+    TS_DEBUG(TAG, "Changed the servers request accept encoding header from \"%s\" to gzip", original_accept_encoding.c_str());
+
+    transaction.resume();
+  }
+
+  virtual void handleReadResponseHeaders(Transaction &transaction) {
+    TS_DEBUG(TAG, "Determining if we need to add an inflate transformation or a deflate transformation..");
+    // We're guaranteed to have been returned either gzipped content or Identity.
+
+    if (Helpers::serverReturnedGzip(transaction)) {
+      // If the returned content was gziped we will inflate it so we can transform it.
+      TS_DEBUG(TAG,"Creating Inflate Transformation because the server returned gziped content");
+      transaction.addPlugin(new GzipInflateTransformation(transaction,
+                                                          TransformationPlugin::RESPONSE_TRANSFORMATION));
+    }
+
+    transaction.addPlugin(new SomeTransformationPlugin(transaction));
+
+    // Even if the server didn't return gziped content, if the user supports it we will gzip it.
+    if (Helpers::clientAcceptsGzip(transaction)) {
+      TS_DEBUG(TAG,"The client supports gzip so we will deflate the content on the way out.");
+      transaction.addPlugin(new GzipDeflateTransformation(transaction,
+                                                          TransformationPlugin::RESPONSE_TRANSFORMATION));
+    }
+    transaction.resume();
+  }
+
+  virtual void handleSendResponseHeaders(Transaction &transaction) {
+    // If the client supported gzip then we can guarantee they are receiving gzip since regardless of the
+    // origins content-encoding we returned gzip, so let's make sure the content-encoding header is correctly
+    // set to gzip or identity.
+    if (Helpers::clientAcceptsGzip(transaction)) {
+      TS_DEBUG(TAG,"Setting the client response content-encoding to gzip since the user supported it, that's what they got.");
+      transaction.getClientResponse().getHeaders().set("Content-Encoding", "gzip");
+    } else {
+      TS_DEBUG(TAG,"Setting the client response content-encoding to identity since the user didn't support gzip");
+      transaction.getClientResponse().getHeaders().set("Content-Encoding", "identity");
+    }
+    transaction.resume();
+  }
+
+};
+
+void TSPluginInit(int argc, const char *argv[]) {
+  TS_DEBUG(TAG, "TSPluginInit");
+  GlobalPlugin *instance = new GlobalHookPlugin();
+}

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/examples/gzip_transformation/Makefile.am
----------------------------------------------------------------------
diff --git a/lib/atscppapi/examples/gzip_transformation/Makefile.am b/lib/atscppapi/examples/gzip_transformation/Makefile.am
new file mode 100644
index 0000000..bfaaae1
--- /dev/null
+++ b/lib/atscppapi/examples/gzip_transformation/Makefile.am
@@ -0,0 +1,30 @@
+#
+#  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.
+
+AM_CPPFLAGS = -I$(top_srcdir)/src/include
+
+target=GzipTransformationPlugin.so
+pkglibdir = ${pkglibexecdir}
+pkglib_LTLIBRARIES = GzipTransformationPlugin.la
+GzipTransformationPlugin_la_SOURCES = GzipTransformationPlugin.cc
+GzipTransformationPlugin_la_LDFLAGS = -module -avoid-version -shared -L$(top_srcdir) -latscppapi
+
+all:
+	ln -sf .libs/$(target)
+
+clean-local:
+	rm -f $(target)

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/examples/helloworld/HelloWorldPlugin.cc
----------------------------------------------------------------------
diff --git a/lib/atscppapi/examples/helloworld/HelloWorldPlugin.cc b/lib/atscppapi/examples/helloworld/HelloWorldPlugin.cc
new file mode 100644
index 0000000..6c73cda
--- /dev/null
+++ b/lib/atscppapi/examples/helloworld/HelloWorldPlugin.cc
@@ -0,0 +1,36 @@
+/**
+  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 <iostream>
+#include <atscppapi/GlobalPlugin.h>
+#include <atscppapi/PluginInit.h>
+
+class HelloWorldPlugin : public atscppapi::GlobalPlugin {
+public:
+  HelloWorldPlugin() {
+    std::cout << "Hello World!" << std::endl;
+  }
+};
+
+void TSPluginInit(int argc, const char *argv[]) {
+  std::cout << "Hello from " << argv[0] << std::endl;
+  atscppapi::GlobalPlugin *instance = new HelloWorldPlugin();
+}
+
+

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/examples/helloworld/Makefile.am
----------------------------------------------------------------------
diff --git a/lib/atscppapi/examples/helloworld/Makefile.am b/lib/atscppapi/examples/helloworld/Makefile.am
new file mode 100644
index 0000000..ebdd7d1
--- /dev/null
+++ b/lib/atscppapi/examples/helloworld/Makefile.am
@@ -0,0 +1,29 @@
+#
+#  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.
+AM_CPPFLAGS = -I$(top_srcdir)/src/include
+
+target=HelloWorldPlugin.so
+pkglibdir = ${pkglibexecdir}
+pkglib_LTLIBRARIES = HelloWorldPlugin.la
+HelloWorldPlugin_la_SOURCES = HelloWorldPlugin.cc
+HelloWorldPlugin_la_LDFLAGS = -module -avoid-version -shared -L$(top_srcdir) -latscppapi
+
+all:
+	ln -sf .libs/$(target)
+
+clean-local:
+	rm -f $(target)

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/examples/internal_transaction_handling/InternalTransactionHandling.cc
----------------------------------------------------------------------
diff --git a/lib/atscppapi/examples/internal_transaction_handling/InternalTransactionHandling.cc b/lib/atscppapi/examples/internal_transaction_handling/InternalTransactionHandling.cc
new file mode 100644
index 0000000..566acce
--- /dev/null
+++ b/lib/atscppapi/examples/internal_transaction_handling/InternalTransactionHandling.cc
@@ -0,0 +1,65 @@
+/**
+  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 <atscppapi/GlobalPlugin.h>
+#include <atscppapi/Logger.h>
+#include <atscppapi/PluginInit.h>
+#include <atscppapi/AsyncHttpFetch.h>
+
+using namespace atscppapi;
+using std::string;
+
+#define TAG "internal_transaction_handling"
+
+class AllTransactionsGlobalPlugin : public GlobalPlugin {
+public:
+  AllTransactionsGlobalPlugin() : GlobalPlugin() {
+    TS_DEBUG(TAG, "Registering a global hook HOOK_READ_REQUEST_HEADERS_POST_REMAP");
+    registerHook(HOOK_READ_REQUEST_HEADERS_POST_REMAP);
+  }
+
+  virtual void handleReadRequestHeadersPostRemap(Transaction &transaction) {
+    TS_DEBUG(TAG, "Received a request in handleReadRequestHeadersPostRemap.");
+    transaction.resume();
+  }
+};
+
+class NoInternalTransactionsGlobalPlugin : public GlobalPlugin, public AsyncReceiver<AsyncHttpFetch> {
+public:
+  NoInternalTransactionsGlobalPlugin() : GlobalPlugin(true) {
+    TS_DEBUG(TAG, "Registering a global hook HOOK_READ_REQUEST_HEADERS_POST_REMAP");
+    registerHook(HOOK_READ_REQUEST_HEADERS_POST_REMAP);
+  }
+
+  virtual void handleReadRequestHeadersPostRemap(Transaction &transaction) {
+    TS_DEBUG(TAG, "Received a request in handleReadRequestHeadersPostRemap.");
+    shared_ptr<Mutex> mutex(new Mutex()); // required for async operation
+    Async::execute<AsyncHttpFetch>(this, new AsyncHttpFetch("http://127.0.0.1/"), mutex); // internal transaction
+    transaction.resume();
+  }
+
+  void handleAsyncComplete(AsyncHttpFetch &provider) {
+  }
+};
+
+void TSPluginInit(int argc, const char *argv[]) {
+  TS_DEBUG(TAG, "Loaded async_http_fetch_example plugin");
+  AllTransactionsGlobalPlugin *instance1 = new AllTransactionsGlobalPlugin();
+  NoInternalTransactionsGlobalPlugin *instance2 = new NoInternalTransactionsGlobalPlugin();
+}

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/examples/internal_transaction_handling/Makefile.am
----------------------------------------------------------------------
diff --git a/lib/atscppapi/examples/internal_transaction_handling/Makefile.am b/lib/atscppapi/examples/internal_transaction_handling/Makefile.am
new file mode 100644
index 0000000..447c943
--- /dev/null
+++ b/lib/atscppapi/examples/internal_transaction_handling/Makefile.am
@@ -0,0 +1,29 @@
+#
+#  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.
+AM_CPPFLAGS = -I$(top_srcdir)/src/include
+
+target=InternalTransactionHandling.so
+pkglibdir = ${pkglibexecdir}
+pkglib_LTLIBRARIES = InternalTransactionHandling.la
+InternalTransactionHandling_la_SOURCES = InternalTransactionHandling.cc
+InternalTransactionHandling_la_LDFLAGS = -module -avoid-version -shared -L$(top_srcdir) -latscppapi
+
+all:
+	ln -sf .libs/$(target)
+
+clean-local:
+	rm -f $(target)

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/examples/logger_example/LoggerExample.cc
----------------------------------------------------------------------
diff --git a/lib/atscppapi/examples/logger_example/LoggerExample.cc b/lib/atscppapi/examples/logger_example/LoggerExample.cc
new file mode 100644
index 0000000..4538c41
--- /dev/null
+++ b/lib/atscppapi/examples/logger_example/LoggerExample.cc
@@ -0,0 +1,132 @@
+/**
+  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.
+ */
+
+
+/**
+ * @warning log rolling doesn't work correctly in 3.2.x, see:
+ *   https://issues.apache.org/jira/browse/TS-1813, Apply the patch in
+ *   TS-1813 to correct log rolling in 3.2.x
+ */
+
+#include <atscppapi/GlobalPlugin.h>
+#include <atscppapi/TransactionPlugin.h>
+#include <atscppapi/Logger.h>
+#include <atscppapi/PluginInit.h>
+#include <cstring>
+
+using namespace atscppapi;
+using std::string;
+
+namespace {
+Logger log;
+}
+
+/*
+ * You should always take advantage of the LOG_DEBUG, LOG_INFO, and LOG_ERROR
+ * macros available in Logger.h, they are easy to use as you can see below
+ * and will provide detailed information about the logging site such as
+ * filename, function name, and line number of the message
+ */
+
+class GlobalHookPlugin : public GlobalPlugin {
+public:
+  GlobalHookPlugin() {
+    memset(big_buffer_6kb_,'a', sizeof(big_buffer_6kb_));
+    big_buffer_6kb_[sizeof(big_buffer_6kb_) - 1] = '\0';
+
+    memset(big_buffer_14kb_,'a', sizeof(big_buffer_14kb_));
+    big_buffer_14kb_[sizeof(big_buffer_14kb_) - 1] = '\0';
+
+    registerHook(HOOK_READ_REQUEST_HEADERS_POST_REMAP);
+  }
+
+  virtual void handleReadRequestHeadersPostRemap(Transaction &transaction) {
+    LOG_DEBUG(log, "handleReadRequestHeadersPostRemap.\n"
+        "\tRequest URL: %s\n"
+        "\tRequest Path: %s\n"
+        "\tRequest Query: %s\n"
+        "\tRequest Method: %s", transaction.getClientRequest().getUrl().getUrlString().c_str(),
+                                transaction.getClientRequest().getUrl().getPath().c_str(),
+                                transaction.getClientRequest().getUrl().getQuery().c_str(),
+                                HTTP_METHOD_STRINGS[transaction.getClientRequest().getMethod()].c_str()
+                               );
+
+    // Next, to demonstrate how you can change logging levels:
+    if (transaction.getClientRequest().getUrl().getPath() == "change_log_level") {
+      if (transaction.getClientRequest().getUrl().getQuery().find("level=debug") != string::npos) {
+        log.setLogLevel(Logger::LOG_LEVEL_DEBUG);
+        LOG_DEBUG(log, "Changed log level to DEBUG");
+      } else if (transaction.getClientRequest().getUrl().getQuery().find("level=info") != string::npos) {
+        log.setLogLevel(Logger::LOG_LEVEL_INFO);
+        LOG_INFO(log, "Changed log level to INFO");
+      } else if (transaction.getClientRequest().getUrl().getQuery().find("level=error") != string::npos) {
+        log.setLogLevel(Logger::LOG_LEVEL_ERROR);
+        LOG_ERROR(log, "Changed log level to ERROR");
+      }
+    }
+
+    // One drawback to usign the Traffic Server Text Loggers is that you're limited in the size of the log
+    // lines, this limit is now set at 8kb for atscppapi, but this limit might be removed in the future.
+    LOG_INFO(log, "This message will be dropped (see error.log) because it's just too big: %s", big_buffer_14kb_);
+
+    // This should work though:
+    LOG_INFO(log, "%s", big_buffer_6kb_);
+
+    transaction.resume();
+  }
+private:
+  char big_buffer_6kb_[6*1024];
+  char big_buffer_14kb_[14*1024];
+};
+
+void TSPluginInit(int argc, const char *argv[]) {
+  // Create a new logger
+  // This will create a log file with the name logger_example.log (since we left off
+  //    the extension it will automatically add .log)
+  //
+  // The second argument is timestamp, which will force a timestamp on every log message
+  //  this is enabled by default.
+  // The third argument is renaming enabled, which means if a log already exists with that
+  //  name it will try logger_example.1 and so on, this is enabled by default.
+  // The fourth argument is the initial logging level this can always be changed with log.setLogLevel().
+  //  the default log level is LOG_LEVEL_INFO.
+  // The fifth argument is to enable log rolling, this is enabled by default.
+  // The sixth argument is the freuqency in which we will roll the logs, 300 seconds is very low,
+  //  the default for this argument is 3600.
+  log.init("logger_example", true, true, Logger::LOG_LEVEL_DEBUG, true, 300);
+
+  // Now that we've initialized a logger we can do all kinds of fun things on it:
+  log.setRollingEnabled(true); // already done via log.init, just an example.
+  log.setRollingIntervalSeconds(300); // already done via log.init
+
+  // You have two ways to log to a logger, you can log directly on the object itself:
+  log.logInfo("Hello World from: %s", argv[0]);
+
+  // Alternatively you can take advantage of the super helper macros for logging
+  // that will include the file, function, and line number automatically as part
+  // of the log message:
+  LOG_INFO(log, "Hello World with more info from: %s", argv[0]);
+
+  // This will hurt performance, but it's an option that's always available to you
+  // to force flush the logs. Otherwise TrafficServer will flush the logs around
+  // once every second. You should really avoid flushing the log unless it's really necessary.
+  log.flush();
+
+  GlobalPlugin *instance = new GlobalHookPlugin();
+}
+

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/examples/logger_example/Makefile.am
----------------------------------------------------------------------
diff --git a/lib/atscppapi/examples/logger_example/Makefile.am b/lib/atscppapi/examples/logger_example/Makefile.am
new file mode 100644
index 0000000..404dd8c
--- /dev/null
+++ b/lib/atscppapi/examples/logger_example/Makefile.am
@@ -0,0 +1,30 @@
+#
+#  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.
+
+AM_CPPFLAGS = -I$(top_srcdir)/src/include
+
+target=LoggerExample.so
+pkglibdir = ${pkglibexecdir}
+pkglib_LTLIBRARIES = LoggerExample.la
+LoggerExample_la_SOURCES = LoggerExample.cc
+LoggerExample_la_LDFLAGS = -module -avoid-version -shared -L$(top_srcdir) -latscppapi
+
+all:
+	ln -sf .libs/$(target)
+
+clean-local:
+	rm -f $(target)

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/examples/multiple_transaction_hooks/Makefile.am
----------------------------------------------------------------------
diff --git a/lib/atscppapi/examples/multiple_transaction_hooks/Makefile.am b/lib/atscppapi/examples/multiple_transaction_hooks/Makefile.am
new file mode 100644
index 0000000..d56c921
--- /dev/null
+++ b/lib/atscppapi/examples/multiple_transaction_hooks/Makefile.am
@@ -0,0 +1,29 @@
+#
+#  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.
+AM_CPPFLAGS = -I$(top_srcdir)/src/include
+
+target=MultipleTransactionHookPlugins.so
+pkglibdir = ${pkglibexecdir}
+pkglib_LTLIBRARIES = MultipleTransactionHookPlugins.la
+MultipleTransactionHookPlugins_la_SOURCES = MultipleTransactionHookPlugins.cc
+MultipleTransactionHookPlugins_la_LDFLAGS = -module -avoid-version -shared -L$(top_srcdir) -latscppapi
+
+all:
+	ln -sf .libs/$(target)
+
+clean-local:
+	rm -f $(target)

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/examples/multiple_transaction_hooks/MultipleTransactionHookPlugins.cc
----------------------------------------------------------------------
diff --git a/lib/atscppapi/examples/multiple_transaction_hooks/MultipleTransactionHookPlugins.cc b/lib/atscppapi/examples/multiple_transaction_hooks/MultipleTransactionHookPlugins.cc
new file mode 100644
index 0000000..ce9db4d
--- /dev/null
+++ b/lib/atscppapi/examples/multiple_transaction_hooks/MultipleTransactionHookPlugins.cc
@@ -0,0 +1,100 @@
+/**
+  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 <iostream>
+#include <vector>
+#include <atscppapi/GlobalPlugin.h>
+#include <atscppapi/TransactionPlugin.h>
+#include <atscppapi/PluginInit.h>
+
+using namespace atscppapi;
+
+class MultipleTransactionHookPluginsOne : public atscppapi::TransactionPlugin {
+public:
+  MultipleTransactionHookPluginsOne(Transaction &transaction) : TransactionPlugin(transaction) {
+    TransactionPlugin::registerHook(HOOK_SEND_RESPONSE_HEADERS);
+    std::cout << "Constructed MultipleTransactionHookPluginsOne!" << std::endl;
+  }
+
+  virtual ~MultipleTransactionHookPluginsOne() {
+    std::cout << "Destroyed MultipleTransactionHookPluginsOne!" << std::endl;
+  }
+
+  void handleSendResponseHeaders(Transaction &transaction) {
+    std::cerr << "MultipleTransactionHookPluginsOne -- Send response headers!" << std::endl;
+    transaction.resume();
+  }
+};
+
+class MultipleTransactionHookPluginsTwo : public atscppapi::TransactionPlugin {
+public:
+  MultipleTransactionHookPluginsTwo(Transaction &transaction) : TransactionPlugin(transaction) {
+    TransactionPlugin::registerHook(HOOK_SEND_REQUEST_HEADERS);
+    TransactionPlugin::registerHook(HOOK_SEND_RESPONSE_HEADERS);
+    std::cout << "Constructed MultipleTransactionHookPluginsTwo!" << std::endl;
+  }
+
+  virtual ~MultipleTransactionHookPluginsTwo() {
+    std::cout << "Destroyed MultipleTransactionHookPluginsTwo!" << std::endl;
+  }
+
+  void handleSendRequestHeaders(Transaction &transaction) {
+    std::cout << "MultipleTransactionHookPluginsTwo -- Send request headers!" << std::endl;
+    some_container_.push_back("We have transaction scoped storage in Transaction Hooks!");
+    transaction.resume();
+  }
+
+  void handleSendResponseHeaders(Transaction &transaction) {
+     std::cout << "MultipleTransactionHookPluginsTwo -- Send response headers!" << std::endl;
+
+     // Demonstrate the concept of transaction scoped storage.
+     if(some_container_.size()) {
+       std::cout << some_container_.back() << std::endl;
+     }
+
+     transaction.resume();
+   }
+
+private:
+  std::vector<std::string> some_container_;
+};
+
+class GlobalHookPlugin : public atscppapi::GlobalPlugin {
+public:
+  GlobalHookPlugin() {
+    GlobalPlugin::registerHook(HOOK_READ_REQUEST_HEADERS_PRE_REMAP);
+  }
+
+  virtual void handleReadRequestHeadersPreRemap(Transaction &transaction) {
+    std::cout << "Hello from handleReadRequesHeadersPreRemap!" << std::endl;
+
+    // We need not store the addresses of the transaction plugins
+    // because they will be cleaned up automatically when the transaction
+    // closes.
+
+    transaction.addPlugin(new MultipleTransactionHookPluginsOne(transaction));
+    transaction.addPlugin(new MultipleTransactionHookPluginsTwo(transaction));
+
+    transaction.resume();
+  }
+};
+
+void TSPluginInit(int argc, const char *argv[]) {
+  atscppapi::GlobalPlugin *instance = new GlobalHookPlugin();
+}

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/examples/null_transformation_plugin/Makefile.am
----------------------------------------------------------------------
diff --git a/lib/atscppapi/examples/null_transformation_plugin/Makefile.am b/lib/atscppapi/examples/null_transformation_plugin/Makefile.am
new file mode 100644
index 0000000..f41c64c
--- /dev/null
+++ b/lib/atscppapi/examples/null_transformation_plugin/Makefile.am
@@ -0,0 +1,30 @@
+#
+#  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.
+
+AM_CPPFLAGS = -I$(top_srcdir)/src/include
+
+target=NullTransformationPlugin.so
+pkglibdir = ${pkglibexecdir}
+pkglib_LTLIBRARIES = NullTransformationPlugin.la
+NullTransformationPlugin_la_SOURCES = NullTransformationPlugin.cc
+NullTransformationPlugin_la_LDFLAGS = -module -avoid-version -shared -L$(top_srcdir) -latscppapi
+
+all:
+	ln -sf .libs/$(target)
+
+clean-local:
+	rm -f $(target)


[4/5] initial atscppapi commit

Posted by br...@apache.org.
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/examples/null_transformation_plugin/NullTransformationPlugin.cc
----------------------------------------------------------------------
diff --git a/lib/atscppapi/examples/null_transformation_plugin/NullTransformationPlugin.cc b/lib/atscppapi/examples/null_transformation_plugin/NullTransformationPlugin.cc
new file mode 100644
index 0000000..b226290
--- /dev/null
+++ b/lib/atscppapi/examples/null_transformation_plugin/NullTransformationPlugin.cc
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2013 LinkedIn Corp. All rights reserved.
+ * Licensed 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.
+ *
+ */
+
+#include <iostream>
+#include <atscppapi/GlobalPlugin.h>
+#include <atscppapi/TransactionPlugin.h>
+#include <atscppapi/TransformationPlugin.h>
+#include <atscppapi/PluginInit.h>
+#include <atscppapi/Logger.h>
+
+using namespace atscppapi;
+using std::string;
+
+namespace {
+atscppapi::Logger *log;
+#define TAG "null_transformation"
+}
+
+class NullTransformationPlugin : public TransformationPlugin {
+public:
+  NullTransformationPlugin(Transaction &transaction)
+    : TransformationPlugin(transaction, RESPONSE_TRANSFORMATION) {
+    registerHook(HOOK_SEND_RESPONSE_HEADERS);
+  }
+
+  void handleSendResponseHeaders(Transaction &transaction) {
+    transaction.getClientResponse().getHeaders().set("X-Content-Transformed", "1");
+    transaction.resume();
+  }
+
+  void consume(const string &data) {
+    produce(data);
+  }
+
+  void handleInputComplete() {
+    setOutputComplete();
+  }
+
+  virtual ~NullTransformationPlugin() {
+
+  }
+
+private:
+};
+
+class GlobalHookPlugin : public GlobalPlugin {
+public:
+  GlobalHookPlugin() {
+    registerHook(HOOK_READ_RESPONSE_HEADERS);
+  }
+
+  virtual void handleReadResponseHeaders(Transaction &transaction) {
+    transaction.addPlugin(new NullTransformationPlugin(transaction));
+    transaction.resume();
+  }
+
+};
+
+void TSPluginInit(int argc, const char *argv[]) {
+  TS_DEBUG(TAG, "TSPluginInit");
+  GlobalPlugin *instance = new GlobalHookPlugin();
+}

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/examples/post_buffer/Makefile.am
----------------------------------------------------------------------
diff --git a/lib/atscppapi/examples/post_buffer/Makefile.am b/lib/atscppapi/examples/post_buffer/Makefile.am
new file mode 100644
index 0000000..e893f5e
--- /dev/null
+++ b/lib/atscppapi/examples/post_buffer/Makefile.am
@@ -0,0 +1,29 @@
+#
+#  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.
+AM_CPPFLAGS = -I$(top_srcdir)/src/include
+
+target=PostBuffer.so
+pkglibdir = ${pkglibexecdir}
+pkglib_LTLIBRARIES = PostBuffer.la
+PostBuffer_la_SOURCES = PostBuffer.cc
+PostBuffer_la_LDFLAGS = -module -avoid-version -shared -L$(top_srcdir) -latscppapi
+
+all:
+	ln -sf .libs/$(target)
+
+clean-local:
+	rm -f $(target)

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/examples/post_buffer/PostBuffer.cc
----------------------------------------------------------------------
diff --git a/lib/atscppapi/examples/post_buffer/PostBuffer.cc b/lib/atscppapi/examples/post_buffer/PostBuffer.cc
new file mode 100644
index 0000000..2c3f132
--- /dev/null
+++ b/lib/atscppapi/examples/post_buffer/PostBuffer.cc
@@ -0,0 +1,75 @@
+/**
+  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 <iostream>
+#include <atscppapi/GlobalPlugin.h>
+#include <atscppapi/TransactionPlugin.h>
+#include <atscppapi/TransformationPlugin.h>
+#include <atscppapi/PluginInit.h>
+
+using namespace atscppapi;
+using std::cerr;
+using std::endl;
+using std::string;
+
+class PostBufferTransformationPlugin : public TransformationPlugin {
+public:
+  PostBufferTransformationPlugin(Transaction &transaction)
+    : TransformationPlugin(transaction, REQUEST_TRANSFORMATION), transaction_(transaction) {
+    buffer_.reserve(1024); // not required, this is an optimization to start the buffer at a slightly higher value.
+  }
+
+  void consume(const string &data) {
+    buffer_.append(data);
+  }
+
+  void handleInputComplete() {
+    produce(buffer_);
+    setOutputComplete();
+  }
+
+  virtual ~PostBufferTransformationPlugin() { }
+
+private:
+  Transaction &transaction_;
+  string buffer_;
+};
+
+class GlobalHookPlugin : public GlobalPlugin {
+public:
+  GlobalHookPlugin() {
+    registerHook(HOOK_READ_REQUEST_HEADERS_POST_REMAP);
+  }
+
+  virtual void handleReadRequestHeadersPostRemap(Transaction &transaction) {
+    cerr << "Read Request Headers Post Remap" << endl;
+    cerr << "Path: " << transaction.getClientRequest().getUrl().getPath() << endl;
+    cerr << "Method: " << HTTP_METHOD_STRINGS[transaction.getClientRequest().getMethod()] << endl;
+    if (transaction.getClientRequest().getMethod() == HTTP_METHOD_POST) {
+      transaction.addPlugin(new PostBufferTransformationPlugin(transaction));
+    }
+
+    transaction.resume();
+  }
+};
+
+void TSPluginInit(int argc, const char *argv[]) {
+  GlobalPlugin *instance = new GlobalHookPlugin();
+}
+

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/examples/remap_plugin/Makefile.am
----------------------------------------------------------------------
diff --git a/lib/atscppapi/examples/remap_plugin/Makefile.am b/lib/atscppapi/examples/remap_plugin/Makefile.am
new file mode 100644
index 0000000..5926f6a
--- /dev/null
+++ b/lib/atscppapi/examples/remap_plugin/Makefile.am
@@ -0,0 +1,30 @@
+#
+#  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.
+
+AM_CPPFLAGS = -I$(top_srcdir)/src/include
+
+target=RemapPlugin.so
+pkglibdir = ${pkglibexecdir}
+pkglib_LTLIBRARIES = RemapPlugin.la
+RemapPlugin_la_SOURCES = RemapPlugin.cc
+RemapPlugin_la_LDFLAGS = -module -avoid-version -shared -L$(top_srcdir) -latscppapi
+
+all:
+	ln -sf .libs/$(target)
+
+clean-local:
+	rm -f $(target)

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/examples/remap_plugin/RemapPlugin.cc
----------------------------------------------------------------------
diff --git a/lib/atscppapi/examples/remap_plugin/RemapPlugin.cc b/lib/atscppapi/examples/remap_plugin/RemapPlugin.cc
new file mode 100644
index 0000000..8e06cec
--- /dev/null
+++ b/lib/atscppapi/examples/remap_plugin/RemapPlugin.cc
@@ -0,0 +1,86 @@
+/**
+  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 <atscppapi/RemapPlugin.h>
+#include <atscppapi/PluginInit.h>
+#include <atscppapi/Logger.h>
+#include <vector>
+#include <sstream>
+
+using namespace std;
+using namespace atscppapi;
+
+#define LOG_TAG "remapplugin"
+
+class MyRemapPlugin : public RemapPlugin {
+public:
+  MyRemapPlugin(void **instance_handle) : RemapPlugin(instance_handle) { }
+
+  Result doRemap(const Url &map_from_url, const Url &map_to_url, Transaction &transaction, bool &redirect) {
+    Url &request_url = transaction.getClientRequest().getUrl();
+    TS_DEBUG(LOG_TAG, "from URL is [%s], to URL is [%s], request URL is [%s]", map_from_url.getUrlString().c_str(),
+             map_to_url.getUrlString().c_str(), request_url.getUrlString().c_str());
+    const string &query = request_url.getQuery();
+    string query_param_raw;
+    map<string, string> query_params;
+    std::istringstream iss(query);
+    while (std::getline(iss, query_param_raw, '&')) {
+      size_t equals_pos = query_param_raw.find('=');
+      if (equals_pos && (equals_pos < (query_param_raw.size() - 1))) {
+        query_params[string(query_param_raw, 0, equals_pos)] = 
+          string(query_param_raw, equals_pos + 1, query_param_raw.size() - equals_pos - 1);
+      }
+    }
+    if (query_params.count("error")) {
+      return RESULT_ERROR;
+    }
+    const string &remap = query_params["remap"];
+    bool stop = (query_params["stop"] == "true");
+    Result result = stop ? RESULT_NO_REMAP_STOP : RESULT_NO_REMAP;
+    if (remap == "true") {
+      const string &path = query_params["path"];
+      if (path.size()) {
+        request_url.setPath(path);
+      }
+      const string &host = query_params["host"];
+      if (host.size()) {
+        request_url.setHost(host);
+      }
+      const string &port_str = query_params["port"];
+      if (port_str.size()) {
+        uint16_t port;
+        iss.str(port_str);
+        iss >> port;
+        request_url.setPort(port);
+      }
+      if (query_params.count("redirect")) {
+        redirect = true;
+      }
+      result = stop ? RESULT_DID_REMAP_STOP : RESULT_DID_REMAP;
+    }
+    request_url.setQuery("");
+    TS_DEBUG(LOG_TAG, "Request URL is now [%s]", request_url.getUrlString().c_str());
+    return result;
+  }
+};
+
+TsReturnCode TSRemapNewInstance(int argc, char *argv[], void **instance_handle, char *errbuf, int errbuf_size) {
+  MyRemapPlugin *new_remap_plugin = new MyRemapPlugin(instance_handle);
+  return TS_SUCCESS;
+}

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/examples/request_cookies/Makefile.am
----------------------------------------------------------------------
diff --git a/lib/atscppapi/examples/request_cookies/Makefile.am b/lib/atscppapi/examples/request_cookies/Makefile.am
new file mode 100644
index 0000000..dd315cb
--- /dev/null
+++ b/lib/atscppapi/examples/request_cookies/Makefile.am
@@ -0,0 +1,30 @@
+#
+#  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.
+
+AM_CPPFLAGS = -I$(top_srcdir)/src/include
+
+target=RequestCookies.so
+pkglibdir = ${pkglibexecdir}
+pkglib_LTLIBRARIES = RequestCookies.la
+RequestCookies_la_SOURCES = RequestCookies.cc
+RequestCookies_la_LDFLAGS = -module -avoid-version -shared -L$(top_srcdir) -latscppapi
+
+all:
+	ln -sf .libs/$(target)
+
+clean-local:
+	rm -f $(target)

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/examples/request_cookies/RequestCookies.cc
----------------------------------------------------------------------
diff --git a/lib/atscppapi/examples/request_cookies/RequestCookies.cc b/lib/atscppapi/examples/request_cookies/RequestCookies.cc
new file mode 100644
index 0000000..ebdfdc1
--- /dev/null
+++ b/lib/atscppapi/examples/request_cookies/RequestCookies.cc
@@ -0,0 +1,67 @@
+/**
+  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 <atscppapi/PluginInit.h>
+#include <atscppapi/GlobalPlugin.h>
+#include <atscppapi/Logger.h>
+
+using namespace atscppapi;
+using std::string;
+
+#define LOG_TAG "request_cookies"
+
+class MyGlobalPlugin : GlobalPlugin {
+public:
+  MyGlobalPlugin() {
+    GlobalPlugin::registerHook(Plugin::HOOK_READ_REQUEST_HEADERS_PRE_REMAP);
+  }
+private:
+  void handleReadRequestHeadersPreRemap(Transaction &transaction) {
+    Headers &headers = transaction.getClientRequest().getHeaders();
+    TS_DEBUG(LOG_TAG, "Read request");
+    logRequestCookies(headers);
+    headers.addCookie("gen-c1", "gen-v2");
+    TS_DEBUG(LOG_TAG, "Added cookie");
+    logRequestCookies(headers);
+    headers.setCookie("c1", "correctv");
+    TS_DEBUG(LOG_TAG, "Set cookie");
+    logRequestCookies(headers);
+    headers.deleteCookie("gen-c1");
+    TS_DEBUG(LOG_TAG, "Deleted cookie");
+    logRequestCookies(headers);
+    transaction.resume();
+  }
+
+  void logRequestCookies(Headers &headers) {
+    TS_DEBUG(LOG_TAG, "Cookie header is [%s]", headers.getJoinedValues("Cookie").c_str());
+    string map_str;
+    const Headers::RequestCookieMap &cookie_map = headers.getRequestCookies();
+    for (Headers::RequestCookieMap::const_iterator cookie_iter = cookie_map.begin(), cookie_end = cookie_map.end();
+         cookie_iter != cookie_end; ++cookie_iter) {
+      map_str += cookie_iter->first;
+      map_str += ": ";
+      map_str += Headers::getJoinedValues(cookie_iter->second);
+      map_str += "\n";
+    }
+    TS_DEBUG(LOG_TAG, "Cookie map is\n%s", map_str.c_str());
+  }
+};
+
+void TSPluginInit(int argc, const char *argv[]) {
+  new MyGlobalPlugin();
+}

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/examples/serverresponse/Makefile.am
----------------------------------------------------------------------
diff --git a/lib/atscppapi/examples/serverresponse/Makefile.am b/lib/atscppapi/examples/serverresponse/Makefile.am
new file mode 100644
index 0000000..9f8f4c7
--- /dev/null
+++ b/lib/atscppapi/examples/serverresponse/Makefile.am
@@ -0,0 +1,29 @@
+#
+#  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.
+AM_CPPFLAGS = -I$(top_srcdir)/src/include
+
+target=ServerResponse.so
+pkglibdir = ${pkglibexecdir}
+pkglib_LTLIBRARIES = ServerResponse.la
+ServerResponse_la_SOURCES = ServerResponse.cc
+ServerResponse_la_LDFLAGS = -module -avoid-version -shared -L$(top_srcdir) -latscppapi
+
+all:
+	ln -sf .libs/$(target)
+
+clean-local:
+	rm -f $(target)

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/examples/serverresponse/ServerResponse.cc
----------------------------------------------------------------------
diff --git a/lib/atscppapi/examples/serverresponse/ServerResponse.cc b/lib/atscppapi/examples/serverresponse/ServerResponse.cc
new file mode 100644
index 0000000..d1b7a69
--- /dev/null
+++ b/lib/atscppapi/examples/serverresponse/ServerResponse.cc
@@ -0,0 +1,105 @@
+/**
+  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 <iostream>
+#include <atscppapi/GlobalPlugin.h>
+#include <atscppapi/PluginInit.h>
+#include <atscppapi/utils.h>
+
+using namespace atscppapi;
+
+using std::cout;
+using std::endl;
+using std::list;
+using std::string;
+
+class ServerResponsePlugin : public GlobalPlugin {
+public:
+  ServerResponsePlugin() {
+    registerHook(HOOK_SEND_REQUEST_HEADERS);
+    registerHook(HOOK_READ_RESPONSE_HEADERS);
+    registerHook(HOOK_SEND_RESPONSE_HEADERS);
+  }
+
+  void handleSendRequestHeaders(Transaction &transaction) {
+    // Here we can decide to abort the request to the origin (we can do this earlier too)
+    // and just send the user an error page.
+    if(transaction.getClientRequest().getUrl().getQuery().find("error=1") != string::npos) {
+      // Give this user an error page and don't make a request to an origin.
+      cout << "Sending this request an error page" << endl;
+      transaction.error("This is the error response, but the response code is 500."
+                        "In this example no request was made to the orgin.");
+      // HTTP/1.1 500 INKApi Error
+    } else {
+      transaction.resume();
+    }
+    cout << "Server request headers are" << endl;
+    printHeaders(transaction.getServerRequest().getHeaders());
+  }
+
+  void handleReadResponseHeaders(Transaction &transaction) {
+    cout << "Hello from handleReadResponseHeaders!" << endl;
+    cout << "Server response headers are" << endl;
+    Response &server_response = transaction.getServerResponse();
+    cout << "Reason phrase is " << server_response.getReasonPhrase() << endl;
+    printHeaders(server_response.getHeaders());
+    transaction.resume();
+  }
+
+  void handleSendResponseHeaders(Transaction &transaction) {
+    cout << "Hello from handleSendResponseHeaders!" << endl;
+    cout << "Client response headers are" << endl;
+    printHeaders(transaction.getClientResponse().getHeaders());
+
+    //
+    // If the url contains a query parameter redirect=1 we will send the
+    // user to to somewhere else. Obviously this is a silly example
+    // since we should technically detect this long before the origin
+    // request and prevent the origin request in the first place.
+    //
+
+    if(transaction.getClientRequest().getUrl().getQuery().find("redirect=1") != string::npos) {
+      cout << "Sending this guy to google." << endl;
+      transaction.getClientResponse().getHeaders().set("Location", "http://www.google.com");
+      transaction.getClientResponse().setStatusCode(HTTP_STATUS_MOVED_TEMPORARILY);
+      transaction.getClientResponse().setReasonPhrase("Come Back Later");
+      // HTTP/1.1 302 Come Back Later
+    }
+
+    transaction.resume();
+  }
+
+private:
+  void printHeaders(const Headers &headers) {
+    for (Headers::const_iterator header_iter = headers.begin(), header_end = headers.end();
+         header_iter != header_end; ++header_iter) {
+      const string &name = header_iter->first;
+      const list<string> &value_list = header_iter->second;
+      cout << "Header. " << name <<  ": " << endl;
+      for (list<string>::const_iterator value_iter = value_list.begin(), value_end = value_list.end();
+           value_iter != value_end; ++value_iter) {
+        cout << "\t" << *value_iter << endl;
+      }
+    }
+    cout << endl;
+  }
+};
+
+void TSPluginInit(int argc, const char *argv[]) {
+  GlobalPlugin *instance = new ServerResponsePlugin();
+}

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/examples/stat_example/Makefile.am
----------------------------------------------------------------------
diff --git a/lib/atscppapi/examples/stat_example/Makefile.am b/lib/atscppapi/examples/stat_example/Makefile.am
new file mode 100644
index 0000000..3e49f79
--- /dev/null
+++ b/lib/atscppapi/examples/stat_example/Makefile.am
@@ -0,0 +1,30 @@
+#
+#  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.
+
+AM_CPPFLAGS = -I$(top_srcdir)/src/include
+
+target=StatExample.so
+pkglibdir = ${pkglibexecdir}
+pkglib_LTLIBRARIES = StatExample.la
+StatExample_la_SOURCES = StatExample.cc
+StatExample_la_LDFLAGS = -module -avoid-version -shared -L$(top_srcdir) -latscppapi
+
+all:
+	ln -sf .libs/$(target)
+
+clean-local:
+	rm -f $(target)

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/examples/stat_example/StatExample.cc
----------------------------------------------------------------------
diff --git a/lib/atscppapi/examples/stat_example/StatExample.cc b/lib/atscppapi/examples/stat_example/StatExample.cc
new file mode 100644
index 0000000..49e91a7
--- /dev/null
+++ b/lib/atscppapi/examples/stat_example/StatExample.cc
@@ -0,0 +1,71 @@
+/**
+  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 <atscppapi/GlobalPlugin.h>
+#include <atscppapi/Logger.h>
+#include <atscppapi/Stat.h>
+#include <atscppapi/PluginInit.h>
+#include <cstring>
+
+using namespace atscppapi;
+using std::string;
+
+namespace {
+// This is for the -T tag debugging
+// To view the debug messages ./traffic_server -T "stat_example.*"
+#define TAG "stat_example"
+
+// This will be the actual stat name
+// You can view it using traffic_line -r stat_example
+const string STAT_NAME = "stat_example";
+
+// This is the stat we'll be using, you can view it's value
+// using traffic_line -r stat_example
+Stat stat;
+}
+
+/*
+ * This is a simple plugin that will increment a counter
+ * everytime a request comes in.
+ */
+class GlobalHookPlugin : public GlobalPlugin {
+public:
+  GlobalHookPlugin() {
+    TS_DEBUG(TAG, "Registering a global hook HOOK_READ_REQUEST_HEADERS_POST_REMAP");
+    registerHook(HOOK_READ_REQUEST_HEADERS_POST_REMAP);
+  }
+
+  virtual void handleReadRequestHeadersPostRemap(Transaction &transaction) {
+    TS_DEBUG(TAG, "Received a request, incrementing the counter.");
+    stat.increment();
+    TS_DEBUG(TAG, "Stat '%s' value = %lld", STAT_NAME.c_str(), stat.get());
+    transaction.resume();
+  }
+};
+
+void TSPluginInit(int argc, const char *argv[]) {
+  TS_DEBUG(TAG, "Loaded stat_example plugin");
+
+  // Since this stat is not persistent it will be initialized to 0.
+  stat.init(STAT_NAME, Stat::SYNC_COUNT, true);
+  stat.set(0);
+
+  GlobalPlugin *instance = new GlobalHookPlugin();
+}
+

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/examples/timeout_example/Makefile.am
----------------------------------------------------------------------
diff --git a/lib/atscppapi/examples/timeout_example/Makefile.am b/lib/atscppapi/examples/timeout_example/Makefile.am
new file mode 100644
index 0000000..7583476
--- /dev/null
+++ b/lib/atscppapi/examples/timeout_example/Makefile.am
@@ -0,0 +1,30 @@
+#
+#  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.
+
+AM_CPPFLAGS = -I$(top_srcdir)/src/include
+
+target=TimeoutExamplePlugin.so
+pkglibdir = ${pkglibexecdir}
+pkglib_LTLIBRARIES = TimeoutExamplePlugin.la
+TimeoutExamplePlugin_la_SOURCES = TimeoutExamplePlugin.cc
+TimeoutExamplePlugin_la_LDFLAGS = -module -avoid-version -shared -L$(top_srcdir) -latscppapi
+
+all:
+	ln -sf .libs/$(target)
+
+clean-local:
+	rm -f $(target)

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/examples/timeout_example/TimeoutExamplePlugin.cc
----------------------------------------------------------------------
diff --git a/lib/atscppapi/examples/timeout_example/TimeoutExamplePlugin.cc b/lib/atscppapi/examples/timeout_example/TimeoutExamplePlugin.cc
new file mode 100644
index 0000000..fb2fe83
--- /dev/null
+++ b/lib/atscppapi/examples/timeout_example/TimeoutExamplePlugin.cc
@@ -0,0 +1,56 @@
+/**
+  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 <iostream>
+#include <atscppapi/GlobalPlugin.h>
+#include <atscppapi/Logger.h>
+#include <atscppapi/PluginInit.h>
+
+using namespace atscppapi;
+
+#define TAG "timeout_example_plugin"
+
+class TimeoutExamplePlugin : public GlobalPlugin {
+public:
+  TimeoutExamplePlugin() {
+    registerHook(HOOK_READ_REQUEST_HEADERS_PRE_REMAP);
+    registerHook(HOOK_SEND_RESPONSE_HEADERS);
+  }
+
+  virtual void handleSendResponseHeaders(Transaction &transaction) {
+    TS_DEBUG(TAG, "Sending response headers to the client, status=%d", transaction.getClientResponse().getStatusCode());
+    transaction.resume();
+  }
+
+  virtual void handleReadRequestHeadersPreRemap(Transaction &transaction) {
+    TS_DEBUG(TAG, "Setting all timeouts to 1ms, this will likely cause the transaction to receive a 504.");
+    transaction.setTimeout(Transaction::TIMEOUT_CONNECT, 1);
+    transaction.setTimeout(Transaction::TIMEOUT_ACTIVE, 1);
+    transaction.setTimeout(Transaction::TIMEOUT_DNS, 1);
+    transaction.setTimeout(Transaction::TIMEOUT_NO_ACTIVITY, 1);
+    transaction.resume();
+  }
+};
+
+void TSPluginInit(int argc, const char *argv[]) {
+  TS_DEBUG(TAG, "TSPluginInit");
+  GlobalPlugin *instance = new TimeoutExamplePlugin();
+}
+
+

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/examples/transactionhook/Makefile.am
----------------------------------------------------------------------
diff --git a/lib/atscppapi/examples/transactionhook/Makefile.am b/lib/atscppapi/examples/transactionhook/Makefile.am
new file mode 100644
index 0000000..1c145cd
--- /dev/null
+++ b/lib/atscppapi/examples/transactionhook/Makefile.am
@@ -0,0 +1,30 @@
+#
+#  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.
+
+AM_CPPFLAGS = -I$(top_srcdir)/src/include
+
+target=TransactionHookPlugin.so
+pkglibdir = ${pkglibexecdir}
+pkglib_LTLIBRARIES = TransactionHookPlugin.la
+TransactionHookPlugin_la_SOURCES = TransactionHookPlugin.cc
+TransactionHookPlugin_la_LDFLAGS = -module -avoid-version -shared -L$(top_srcdir) -latscppapi
+
+all:
+	ln -sf .libs/$(target)
+
+clean-local:
+	rm -f $(target)

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/examples/transactionhook/TransactionHookPlugin.cc
----------------------------------------------------------------------
diff --git a/lib/atscppapi/examples/transactionhook/TransactionHookPlugin.cc b/lib/atscppapi/examples/transactionhook/TransactionHookPlugin.cc
new file mode 100644
index 0000000..b84f300
--- /dev/null
+++ b/lib/atscppapi/examples/transactionhook/TransactionHookPlugin.cc
@@ -0,0 +1,60 @@
+/**
+  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 <iostream>
+#include <atscppapi/GlobalPlugin.h>
+#include <atscppapi/TransactionPlugin.h>
+#include <atscppapi/PluginInit.h>
+
+using namespace atscppapi;
+
+class TransactionHookPlugin : public atscppapi::TransactionPlugin {
+public:
+  TransactionHookPlugin(Transaction &transaction) : TransactionPlugin(transaction) {
+    char_ptr_ = new char[100];
+    TransactionPlugin::registerHook(HOOK_SEND_RESPONSE_HEADERS);
+    std::cout << "Constructed!" << std::endl;
+  }
+  virtual ~TransactionHookPlugin() {
+    delete[] char_ptr_; // cleanup
+    std::cout << "Destroyed!" << std::endl;
+  }
+  void handleSendResponseHeaders(Transaction &transaction) {
+    std::cout << "Send response headers!" << std::endl;
+    transaction.resume();
+  }
+private:
+  char *char_ptr_;
+};
+
+class GlobalHookPlugin : public atscppapi::GlobalPlugin {
+public:
+  GlobalHookPlugin() {
+    GlobalPlugin::registerHook(HOOK_READ_REQUEST_HEADERS_PRE_REMAP);
+  }
+  virtual void handleReadRequestHeadersPreRemap(Transaction &transaction) {
+    std::cout << "Hello from handleReadRequesHeadersPreRemap!" << std::endl;
+    transaction.addPlugin(new TransactionHookPlugin(transaction));
+    transaction.resume();
+  }
+};
+
+void TSPluginInit(int argc, const char *argv[]) {
+  atscppapi::GlobalPlugin *instance = new GlobalHookPlugin();
+}

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/src/AsyncHttpFetch.cc
----------------------------------------------------------------------
diff --git a/lib/atscppapi/src/AsyncHttpFetch.cc b/lib/atscppapi/src/AsyncHttpFetch.cc
new file mode 100644
index 0000000..51ca95d
--- /dev/null
+++ b/lib/atscppapi/src/AsyncHttpFetch.cc
@@ -0,0 +1,170 @@
+/**
+  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.
+ */
+
+/**
+ * @file AsyncHttpFetch.cc
+ */
+
+#include "atscppapi/AsyncHttpFetch.h"
+#include <ts/ts.h>
+#include <arpa/inet.h>
+#include "logging_internal.h"
+#include "utils_internal.h"
+
+using namespace atscppapi;
+using std::string;
+
+/**
+ * @private
+ */
+struct atscppapi::AsyncHttpFetchState : noncopyable {
+  Request request_;
+  Response response_;
+  AsyncHttpFetch::Result result_;
+  const void *body_;
+  size_t body_size_;
+  TSMBuffer hdr_buf_;
+  TSMLoc hdr_loc_;
+  shared_ptr<AsyncDispatchControllerBase> dispatch_controller_;
+
+  AsyncHttpFetchState(const string &url_str, HttpMethod http_method)
+    : request_(url_str, http_method, HTTP_VERSION_1_0), result_(AsyncHttpFetch::RESULT_FAILURE), body_(NULL),
+      body_size_(0), hdr_buf_(NULL), hdr_loc_(NULL) { }
+  
+  ~AsyncHttpFetchState() {
+    if (hdr_loc_) {
+      TSMLoc null_parent_loc = NULL;
+      TSHandleMLocRelease(hdr_buf_, null_parent_loc, hdr_loc_);
+    }
+    if (hdr_buf_) {
+      TSMBufferDestroy(hdr_buf_);
+    }
+  }
+};
+
+namespace {
+
+const unsigned int LOCAL_IP_ADDRESS = 0x0100007f;
+const int LOCAL_PORT = 8080;
+
+static int handleFetchEvents(TSCont cont, TSEvent event, void *edata) {
+  LOG_DEBUG("Fetch result returned event = %d, edata = %p", event, edata);
+  AsyncHttpFetch *fetch_provider = static_cast<AsyncHttpFetch *>(TSContDataGet(cont));
+  AsyncHttpFetchState *state = utils::internal::getAsyncHttpFetchState(*fetch_provider);
+  
+  if (event == static_cast<int>(AsyncHttpFetch::RESULT_SUCCESS)) {
+    TSHttpTxn txn = static_cast<TSHttpTxn>(edata);
+    int data_len;
+    const char *data_start = TSFetchRespGet(txn, &data_len);
+    const char *data_end = data_start + data_len;
+    
+    TSHttpParser parser = TSHttpParserCreate();
+    state->hdr_buf_ = TSMBufferCreate();
+    state->hdr_loc_ = TSHttpHdrCreate(state->hdr_buf_);
+    TSHttpHdrTypeSet(state->hdr_buf_, state->hdr_loc_, TS_HTTP_TYPE_RESPONSE);
+    if (TSHttpHdrParseResp(parser, state->hdr_buf_, state->hdr_loc_, &data_start, data_end) == TS_PARSE_DONE) {
+      TSHttpStatus status = TSHttpHdrStatusGet(state->hdr_buf_, state->hdr_loc_);
+      state->body_ = data_start; // data_start will now be pointing to body
+      state->body_size_ = data_end - data_start;
+      utils::internal::initResponse(state->response_, state->hdr_buf_, state->hdr_loc_);
+      LOG_DEBUG("Fetch result had a status code of %d with a body length of %d", status, state->body_size_);
+    } else {
+      LOG_ERROR("Unable to parse response; Request URL [%s]; transaction %p",
+                state->request_.getUrl().getUrlString().c_str(), txn);
+      event = static_cast<TSEvent>(AsyncHttpFetch::RESULT_FAILURE);
+    }
+    TSHttpParserDestroy(parser);
+  }
+  state->result_ = static_cast<AsyncHttpFetch::Result>(event);
+  if (!state->dispatch_controller_->dispatch()) {
+    LOG_DEBUG("Unable to dispatch result from AsyncFetch because promise has died.");
+  }
+
+  delete fetch_provider; // we must always be sure to clean up the provider when we're done with it.
+  TSContDestroy(cont);
+  return 0;
+}
+
+}
+
+AsyncHttpFetch::AsyncHttpFetch(const std::string &url_str, HttpMethod http_method) {
+  LOG_DEBUG("Created new AsyncHttpFetch object %p", this);
+  state_ = new AsyncHttpFetchState(url_str, http_method);
+}
+
+void AsyncHttpFetch::run(shared_ptr<AsyncDispatchControllerBase> sender) {
+  state_->dispatch_controller_ = sender;
+
+  TSCont fetchCont = TSContCreate(handleFetchEvents, TSMutexCreate());
+  TSContDataSet(fetchCont, static_cast<void *>(this)); // Providers have to clean themselves up when they are done.
+
+  TSFetchEvent event_ids;
+  event_ids.success_event_id = RESULT_SUCCESS;
+  event_ids.failure_event_id = RESULT_FAILURE;
+  event_ids.timeout_event_id = RESULT_TIMEOUT;
+
+  struct sockaddr_in addr;
+  addr.sin_family = AF_INET;
+  addr.sin_addr.s_addr = LOCAL_IP_ADDRESS;
+  addr.sin_port = LOCAL_PORT;
+
+  string request_str(HTTP_METHOD_STRINGS[state_->request_.getMethod()]);
+  request_str += ' ';
+  request_str += state_->request_.getUrl().getUrlString();
+  request_str += ' ';
+  request_str += HTTP_VERSION_STRINGS[state_->request_.getVersion()];
+  request_str += "\r\n";
+
+  for (Headers::const_iterator iter = state_->request_.getHeaders().begin(),
+         end = state_->request_.getHeaders().end(); iter != end; ++iter) {
+    request_str += iter->first;
+    request_str += ": ";
+    request_str += Headers::getJoinedValues(iter->second);
+    request_str += "\r\n";
+  }
+  request_str += "\r\n";
+
+  LOG_DEBUG("Issing TSFetchUrl with request\n[%s]", request_str.c_str());
+  TSFetchUrl(request_str.c_str(), request_str.size(), reinterpret_cast<struct sockaddr const *>(&addr), fetchCont,
+             AFTER_BODY, event_ids);
+}
+
+Headers &AsyncHttpFetch::getRequestHeaders() {
+  return state_->request_.getHeaders();
+}
+
+AsyncHttpFetch::Result AsyncHttpFetch::getResult() const {
+  return state_->result_;
+}
+
+const Url &AsyncHttpFetch::getRequestUrl() const {
+  return state_->request_.getUrl();
+}
+
+const Response &AsyncHttpFetch::getResponse() const {
+  return state_->response_;
+}
+
+void AsyncHttpFetch::getResponseBody(const void *&body, size_t &body_size) const {
+  body = state_->body_;
+  body_size = state_->body_size_;
+}
+
+AsyncHttpFetch::~AsyncHttpFetch() {
+  delete state_;
+}

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/src/AsyncTimer.cc
----------------------------------------------------------------------
diff --git a/lib/atscppapi/src/AsyncTimer.cc b/lib/atscppapi/src/AsyncTimer.cc
new file mode 100644
index 0000000..975af3c
--- /dev/null
+++ b/lib/atscppapi/src/AsyncTimer.cc
@@ -0,0 +1,106 @@
+/**
+  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.
+ */
+
+/**
+ * @file AsyncTimer.cc
+ */
+#include "atscppapi/AsyncTimer.h"
+#include <ts/ts.h>
+#include "logging_internal.h"
+
+using namespace atscppapi;
+
+struct atscppapi::AsyncTimerState {
+  TSCont cont_;
+  AsyncTimer::Type type_;
+  int period_in_ms_;
+  int initial_period_in_ms_;
+  TSAction initial_timer_action_;
+  TSAction periodic_timer_action_;
+  AsyncTimer *timer_;
+  shared_ptr<AsyncDispatchControllerBase> dispatch_controller_;
+  AsyncTimerState(AsyncTimer::Type type, int period_in_ms, int initial_period_in_ms, AsyncTimer *timer)
+    : type_(type), period_in_ms_(period_in_ms), initial_period_in_ms_(initial_period_in_ms),
+      initial_timer_action_(NULL), periodic_timer_action_(NULL), timer_(timer) { }
+};
+
+namespace {
+
+int handleTimerEvent(TSCont cont, TSEvent event, void *edata) {
+  AsyncTimerState *state = static_cast<AsyncTimerState *>(TSContDataGet(cont));
+  if (state->initial_timer_action_) {
+    LOG_DEBUG("Received initial timer event.");
+    state->initial_timer_action_ = NULL; // mark it so that it won't be canceled in the destructor
+    if (state->type_ == AsyncTimer::TYPE_PERIODIC) {
+      LOG_DEBUG("Scheduling periodic event now");
+      state->periodic_timer_action_ = TSContScheduleEvery(state->cont_, state->period_in_ms_,
+                                                          TS_THREAD_POOL_DEFAULT);
+    }
+  }
+  if (!state->dispatch_controller_->dispatch()) {
+    LOG_DEBUG("Receiver has died. Destroying timer");
+    delete state->timer_; // auto-destruct only in this case
+  }
+  return 0;
+}
+
+}
+
+AsyncTimer::AsyncTimer(Type type, int period_in_ms, int initial_period_in_ms) {
+  state_ = new AsyncTimerState(type, period_in_ms, initial_period_in_ms, this);
+  TSMutex null_mutex = NULL;
+  state_->cont_ = TSContCreate(handleTimerEvent, null_mutex);
+  TSContDataSet(state_->cont_, static_cast<void *>(state_));
+}
+
+void AsyncTimer::run(shared_ptr<AsyncDispatchControllerBase> dispatch_controller) {
+  int one_off_timeout_in_ms = 0;
+  int regular_timeout_in_ms = 0;
+  if (state_->type_ == AsyncTimer::TYPE_ONE_OFF) {
+    one_off_timeout_in_ms = state_->period_in_ms_;
+  }
+  else {
+    one_off_timeout_in_ms = state_->initial_period_in_ms_;
+    regular_timeout_in_ms = state_->period_in_ms_;
+  }
+  if (one_off_timeout_in_ms) {
+    LOG_DEBUG("Scheduling initial/one-off event");
+    state_->initial_timer_action_ = TSContSchedule(state_->cont_, one_off_timeout_in_ms,
+                                                   TS_THREAD_POOL_DEFAULT);
+  }
+  else if (regular_timeout_in_ms) {
+    LOG_DEBUG("Scheduling regular timer events");
+    state_->periodic_timer_action_ = TSContScheduleEvery(state_->cont_, regular_timeout_in_ms,
+                                                         TS_THREAD_POOL_DEFAULT);
+  }
+  state_->dispatch_controller_ = dispatch_controller;
+}
+
+AsyncTimer::~AsyncTimer() {
+  if (state_->initial_timer_action_) {
+    LOG_DEBUG("Canceling initial timer action");
+    TSActionCancel(state_->initial_timer_action_);
+  }
+  if (state_->periodic_timer_action_) {
+    LOG_DEBUG("Canceling periodic timer action");
+    TSActionCancel(state_->periodic_timer_action_);
+  }
+  LOG_DEBUG("Destroying cont");
+  TSContDestroy(state_->cont_);
+  delete state_;
+}

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/src/CaseInsensitiveStringComparator.cc
----------------------------------------------------------------------
diff --git a/lib/atscppapi/src/CaseInsensitiveStringComparator.cc b/lib/atscppapi/src/CaseInsensitiveStringComparator.cc
new file mode 100644
index 0000000..2d8b77b
--- /dev/null
+++ b/lib/atscppapi/src/CaseInsensitiveStringComparator.cc
@@ -0,0 +1,70 @@
+/**
+  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.
+ */
+
+/**
+ * @file CaseInsensitiveStringComparator.cc
+ */
+
+#include "atscppapi/CaseInsensitiveStringComparator.h"
+
+namespace {
+  static char NORMALIZED_CHARACTERS[256];
+  static volatile bool normalizer_initialized(false);
+}
+
+using atscppapi::CaseInsensitiveStringComparator;
+using std::string;
+
+bool CaseInsensitiveStringComparator::operator()(const string &lhs, const string &rhs) const {
+  return (compare(lhs, rhs) < 0);
+}
+
+int CaseInsensitiveStringComparator::compare(const string &lhs, const string &rhs) const {
+  if (!normalizer_initialized) {
+    // this initialization is safe to execute in concurrent threads - hence no locking
+    for (int i = 0; i < 256; ++i) {
+      NORMALIZED_CHARACTERS[i] = static_cast<unsigned char>(i);
+    }
+    for (unsigned char i = 'A'; i < 'Z'; ++i) {
+      NORMALIZED_CHARACTERS[i] = 'a' + (i - 'A');
+    }
+    normalizer_initialized = true;
+  }
+  size_t lhs_size = lhs.size();
+  size_t rhs_size = rhs.size();
+  if ((lhs_size > 0) && (rhs_size > 0)) { 
+    size_t num_chars_to_compare = (lhs_size < rhs_size) ? lhs_size : rhs_size;
+    for (size_t i = 0; i < num_chars_to_compare; ++i) {
+      unsigned char normalized_lhs_char = NORMALIZED_CHARACTERS[static_cast<const unsigned char>(lhs[i])]; 
+      unsigned char normalized_rhs_char = NORMALIZED_CHARACTERS[static_cast<const unsigned char>(rhs[i])]; 
+      if (normalized_lhs_char < normalized_rhs_char) {
+        return -1;
+      }
+      if (normalized_lhs_char > normalized_rhs_char) {
+        return 1;
+      }
+    }
+  }
+  if (lhs_size < rhs_size) {
+    return -1;
+  }
+  if (lhs_size > rhs_size) {
+    return 1;
+  }
+  return 0; // both strings are equal
+}

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/src/ClientRequest.cc
----------------------------------------------------------------------
diff --git a/lib/atscppapi/src/ClientRequest.cc b/lib/atscppapi/src/ClientRequest.cc
new file mode 100644
index 0000000..8f2e602
--- /dev/null
+++ b/lib/atscppapi/src/ClientRequest.cc
@@ -0,0 +1,75 @@
+/**
+  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.
+ */
+
+/**
+ * @file ClientRequest.cc
+ */
+
+#include "atscppapi/ClientRequest.h"
+#include <cstdlib>
+#include <ts/ts.h>
+#include "atscppapi/noncopyable.h"
+#include "InitializableValue.h"
+#include "logging_internal.h"
+
+using namespace atscppapi;
+
+/**
+ * @private
+ */
+struct atscppapi::ClientRequestState: noncopyable {
+  TSHttpTxn txn_;
+  TSMBuffer pristine_hdr_buf_;
+  TSMLoc pristine_url_loc_;
+  Url pristine_url_;
+  ClientRequestState(TSHttpTxn txn) : txn_(txn), pristine_hdr_buf_(NULL), pristine_url_loc_(NULL) { }
+};
+
+atscppapi::ClientRequest::ClientRequest(void *ats_txn_handle, void *hdr_buf, void *hdr_loc) :
+    Request(hdr_buf, hdr_loc) {
+  state_ = new ClientRequestState(static_cast<TSHttpTxn>(ats_txn_handle));
+}
+
+atscppapi::ClientRequest::~ClientRequest() {
+  if (state_->pristine_url_loc_ && state_->pristine_hdr_buf_) {
+    TSMLoc null_parent_loc = NULL;
+    LOG_DEBUG("Releasing pristine url loc for transaction %p; hdr_buf %p, url_loc %p", state_->txn_,
+              state_->pristine_hdr_buf_, state_->pristine_url_loc_);
+    TSHandleMLocRelease(state_->pristine_hdr_buf_, null_parent_loc, state_->pristine_url_loc_);
+  }
+
+  delete state_;
+}
+
+const Url &atscppapi::ClientRequest::getPristineUrl() const {
+  if (!state_->pristine_url_loc_) {
+    TSHttpTxnPristineUrlGet(state_->txn_, &state_->pristine_hdr_buf_, &state_->pristine_url_loc_);
+
+    if ((state_->pristine_hdr_buf_ != NULL) && (state_->pristine_url_loc_ != NULL)) {
+      state_->pristine_url_.init(state_->pristine_hdr_buf_, state_->pristine_url_loc_);
+      LOG_DEBUG("Pristine URL initialized");
+    } else {
+      LOG_ERROR("Failed to get pristine URL for transaction %p; hdr_buf %p, url_loc %p", state_->txn_,
+                state_->pristine_hdr_buf_, state_->pristine_url_loc_);
+    }
+  } else {
+    LOG_DEBUG("Pristine URL already initialized");
+  }
+
+  return state_->pristine_url_;
+}

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/src/GlobalPlugin.cc
----------------------------------------------------------------------
diff --git a/lib/atscppapi/src/GlobalPlugin.cc b/lib/atscppapi/src/GlobalPlugin.cc
new file mode 100644
index 0000000..40cd9e8
--- /dev/null
+++ b/lib/atscppapi/src/GlobalPlugin.cc
@@ -0,0 +1,78 @@
+/**
+  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.
+ */
+
+/**
+ * @file GlobalPlugin.cc
+ */
+#include "atscppapi/GlobalPlugin.h"
+#include <ts/ts.h>
+#include <cstddef>
+#include <cassert>
+#include "atscppapi/noncopyable.h"
+#include "utils_internal.h"
+#include "logging_internal.h"
+
+using namespace atscppapi;
+
+/**
+ * @private
+ */
+struct atscppapi::GlobalPluginState : noncopyable {
+  TSCont cont_;
+  bool ignore_internal_transactions_;
+  GlobalPlugin *global_plugin_;
+  GlobalPluginState(GlobalPlugin *global_plugin, bool ignore_internal_transactions)
+    : global_plugin_(global_plugin), ignore_internal_transactions_(ignore_internal_transactions) { }
+};
+
+namespace {
+
+static int handleGlobalPluginEvents(TSCont cont, TSEvent event, void *edata) {
+  TSHttpTxn txn = static_cast<TSHttpTxn>(edata);
+  GlobalPluginState *state = static_cast<GlobalPluginState *>(TSContDataGet(cont));
+  if (state->ignore_internal_transactions_ && (TSHttpIsInternalRequest(txn) == TS_SUCCESS)) {
+    LOG_DEBUG("Ignoring event %d on internal transaction %p for global plugin %p", event, txn,
+              state->global_plugin_);
+    TSHttpTxnReenable(txn, TS_EVENT_HTTP_CONTINUE);
+  } else {
+    LOG_DEBUG("Invoking global plugin %p for event %d on transaction %p", state->global_plugin_, event, txn);
+    utils::internal::invokePluginForEvent(state->global_plugin_, txn, event);
+  }
+  return 0;
+}
+
+} /* anonymous namespace */
+
+GlobalPlugin::GlobalPlugin(bool ignore_internal_transactions) {
+  utils::internal::initTransactionManagement();
+  state_ = new GlobalPluginState(this, ignore_internal_transactions);
+  TSMutex mutex = NULL;
+  state_->cont_ = TSContCreate(handleGlobalPluginEvents, mutex);
+  TSContDataSet(state_->cont_, static_cast<void *>(state_));
+}
+
+GlobalPlugin::~GlobalPlugin() {
+  TSContDestroy(state_->cont_);
+  delete state_;
+}
+
+void GlobalPlugin::registerHook(Plugin::HookType hook_type) {
+  TSHttpHookID hook_id = utils::internal::convertInternalHookToTsHook(hook_type);
+  TSHttpHookAdd(hook_id, state_->cont_);
+  LOG_DEBUG("Registered global plugin %p for hook %s", this, HOOK_TYPE_STRINGS[hook_type].c_str());
+}

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/src/GzipDeflateTransformation.cc
----------------------------------------------------------------------
diff --git a/lib/atscppapi/src/GzipDeflateTransformation.cc b/lib/atscppapi/src/GzipDeflateTransformation.cc
new file mode 100644
index 0000000..5d701c8
--- /dev/null
+++ b/lib/atscppapi/src/GzipDeflateTransformation.cc
@@ -0,0 +1,156 @@
+/**
+  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.
+ */
+/**
+ * @file GzipDeflateTransformation.cc
+ */
+
+#include <string>
+#include <cstring>
+#include <vector>
+#include <zlib.h>
+#include "atscppapi/TransformationPlugin.h"
+#include "atscppapi/GzipDeflateTransformation.h"
+#include "logging_internal.h"
+
+using namespace atscppapi::transformations;
+using std::string;
+using std::vector;
+
+namespace {
+const int GZIP_MEM_LEVEL = 8;
+const int WINDOW_BITS = 31; // Always use 31 for gzip.
+const int ONE_KB = 1024;
+}
+
+/**
+ * @private
+ */
+struct atscppapi::transformations::GzipDeflateTransformationState: noncopyable {
+  z_stream z_stream_;
+  bool z_stream_initialized_;
+  int64_t bytes_produced_;
+  TransformationPlugin::Type transformation_type_;
+
+  GzipDeflateTransformationState(TransformationPlugin::Type type) :
+        z_stream_initialized_(false), transformation_type_(type), bytes_produced_(0) {
+
+    memset(&z_stream_, 0, sizeof(z_stream_));
+    int err =
+        deflateInit2(&z_stream_, Z_DEFAULT_COMPRESSION, Z_DEFLATED, WINDOW_BITS , GZIP_MEM_LEVEL, Z_DEFAULT_STRATEGY);
+
+    if (Z_OK != err) {
+      LOG_ERROR("deflateInit2 failed with error code '%d'.", err);
+    } else {
+      z_stream_initialized_ = true;
+    }
+  };
+
+  ~GzipDeflateTransformationState() {
+    if (z_stream_initialized_) {
+      deflateEnd(&z_stream_);
+    }
+  };
+};
+
+
+GzipDeflateTransformation::GzipDeflateTransformation(Transaction &transaction, TransformationPlugin::Type type) : TransformationPlugin(transaction, type) {
+  state_ = new GzipDeflateTransformationState(type);
+}
+
+GzipDeflateTransformation::~GzipDeflateTransformation() {
+  delete state_;
+}
+
+void GzipDeflateTransformation::consume(const string &data) {
+  if (data.size() == 0) {
+    return;
+  }
+
+  if (!state_->z_stream_initialized_) {
+    LOG_ERROR("Unable to deflate output because the z_stream was not initialized.");
+    return;
+  }
+
+  int iteration = 0;
+  state_->z_stream_.data_type = Z_ASCII;
+  state_->z_stream_.next_in = reinterpret_cast<unsigned char *>(const_cast<char *>(data.c_str()));
+  state_->z_stream_.avail_in = data.length();
+
+  // For small payloads the size can actually be greater than the original input
+  // so we'll use twice the original size to avoid needless repeated calls to deflate.
+  unsigned long buffer_size = data.length() < ONE_KB ? 2 * ONE_KB : data.length();
+  vector<unsigned char> buffer(buffer_size);
+
+  do {
+    LOG_DEBUG("Iteration %d: Deflate will compress %d bytes", ++iteration, data.size());
+    state_->z_stream_.avail_out = buffer_size;
+    state_->z_stream_.next_out = &buffer[0];
+
+    int err = deflate(&state_->z_stream_, Z_SYNC_FLUSH);
+    if (Z_OK != err) {
+      LOG_ERROR("Iteration %d: Deflate failed to compress %d bytes with error code '%d'", iteration, data.size(), err);
+      return;
+    }
+
+    int bytes_to_write = buffer_size - state_->z_stream_.avail_out;
+    state_->bytes_produced_ += bytes_to_write;
+
+    LOG_DEBUG("Iteration %d: Deflate compressed %d bytes to %d bytes, producing output...", iteration, data.size(), bytes_to_write);
+    produce(string(reinterpret_cast<char *>(&buffer[0]), static_cast<size_t>(bytes_to_write)));
+  } while (state_->z_stream_.avail_out == 0);
+
+  if (state_->z_stream_.avail_in != 0) {
+    LOG_ERROR("Inflate finished with data still remaining in the buffer of size '%d'", state_->z_stream_.avail_in);
+  }
+}
+
+void GzipDeflateTransformation::handleInputComplete() {
+  // We will flush out anything that's remaining in the gzip buffer
+  int status = Z_OK;
+  int iteration = 0;
+  const int buffer_size = 1024; // 1024 bytes is usually more than enough for the epilouge
+  unsigned char buffer[buffer_size];
+
+  /* Deflate remaining data */
+  do {
+    LOG_DEBUG("Iteration %d: Gzip deflate finalizing.", ++iteration);
+    state_->z_stream_.data_type = Z_ASCII;
+    state_->z_stream_.avail_out = buffer_size;
+    state_->z_stream_.next_out = buffer;
+
+    status = deflate(&state_->z_stream_, Z_FINISH);
+
+    int bytes_to_write = buffer_size - state_->z_stream_.avail_out;
+    state_->bytes_produced_ += bytes_to_write;
+
+    if (status == Z_OK || status == Z_STREAM_END) {
+      LOG_DEBUG("Iteration %d: Gzip deflate finalize had an extra %d bytes to process, status '%d'. Producing output...", iteration, bytes_to_write, status);
+      produce(string(reinterpret_cast<char *>(buffer), static_cast<size_t>(bytes_to_write)));
+    } else if (status != Z_STREAM_END) {
+      LOG_ERROR("Iteration %d: Gzip deflinate finalize produced an error '%d'", iteration, status);
+    }
+  } while (status == Z_OK);
+
+  int64_t bytes_written = setOutputComplete();
+  if (state_->bytes_produced_ != bytes_written) {
+    LOG_ERROR("Gzip bytes produced sanity check failed, deflated bytes = %d != written bytes = %d", state_->bytes_produced_, bytes_written);
+  }
+}
+
+
+

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/src/GzipInflateTransformation.cc
----------------------------------------------------------------------
diff --git a/lib/atscppapi/src/GzipInflateTransformation.cc b/lib/atscppapi/src/GzipInflateTransformation.cc
new file mode 100644
index 0000000..931e6e8
--- /dev/null
+++ b/lib/atscppapi/src/GzipInflateTransformation.cc
@@ -0,0 +1,130 @@
+/**
+  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.
+ */
+
+/**
+ * @file GzipInflateTransformation.cc
+ */
+
+#include <string>
+#include <cstring>
+#include <vector>
+#include <zlib.h>
+#include "atscppapi/TransformationPlugin.h"
+#include "atscppapi/GzipInflateTransformation.h"
+#include "logging_internal.h"
+
+using namespace atscppapi::transformations;
+using std::string;
+using std::vector;
+
+namespace {
+const int WINDOW_BITS = 31; // Always use 31 for gzip.
+unsigned int INFLATE_SCALE_FACTOR = 6;
+}
+
+/**
+ * @private
+ */
+struct atscppapi::transformations::GzipInflateTransformationState: noncopyable {
+  z_stream z_stream_;
+  bool z_stream_initialized_;
+  int64_t bytes_produced_;
+  TransformationPlugin::Type transformation_type_;
+
+  GzipInflateTransformationState(TransformationPlugin::Type type) :
+        z_stream_initialized_(false), transformation_type_(type), bytes_produced_(0) {
+
+    memset(&z_stream_, 0, sizeof(z_stream_));
+
+    int err = inflateInit2(&z_stream_, WINDOW_BITS);
+    if (Z_OK != err) {
+      LOG_ERROR("inflateInit2 failed with error code '%d'.", err);
+    } else {
+      z_stream_initialized_ = true;
+    }
+  };
+
+  ~GzipInflateTransformationState() {
+    if (z_stream_initialized_) {
+      int err = inflateEnd(&z_stream_);
+      if (Z_OK != err && Z_STREAM_END != err) {
+        LOG_ERROR("Unable to inflateEnd(), returned error code '%d'", err);
+      }
+    }
+  };
+};
+
+
+GzipInflateTransformation::GzipInflateTransformation(Transaction &transaction, TransformationPlugin::Type type) : TransformationPlugin(transaction, type) {
+  state_ = new GzipInflateTransformationState(type);
+}
+
+GzipInflateTransformation::~GzipInflateTransformation() {
+  delete state_;
+}
+
+void GzipInflateTransformation::consume(const string &data) {
+  if (data.size() == 0) {
+    return;
+  }
+
+  if (!state_->z_stream_initialized_) {
+    LOG_ERROR("Unable to inflate output because the z_stream was not initialized.");
+    return;
+  }
+
+  int err = Z_OK;
+  int iteration = 0;
+  int inflate_block_size = INFLATE_SCALE_FACTOR * data.size();
+  vector<char> buffer(inflate_block_size);
+
+  // Setup the compressed input
+  state_->z_stream_.next_in = reinterpret_cast<unsigned char *>(const_cast<char *>(data.c_str()));
+  state_->z_stream_.avail_in = data.length();
+
+  // Loop while we have more data to inflate
+  while (state_->z_stream_.avail_in > 0 && err != Z_STREAM_END) {
+    LOG_DEBUG("Iteration %d: Gzip has %d bytes to inflate", ++iteration, state_->z_stream_.avail_in);
+
+    // Setup where the decompressed output will go.
+    state_->z_stream_.next_out = reinterpret_cast<unsigned char *>(&buffer[0]);
+    state_->z_stream_.avail_out = inflate_block_size;
+
+    /* Uncompress */
+    err = inflate(&state_->z_stream_, Z_SYNC_FLUSH);
+
+    if (err != Z_OK && err != Z_STREAM_END) {
+     LOG_ERROR("Iteration %d: Inflate failed with error '%d'", iteration, err);
+     return;
+    }
+
+    LOG_DEBUG("Iteration %d: Gzip inflated a total of %d bytes, producingOutput...", iteration, (inflate_block_size - state_->z_stream_.avail_out));
+    produce(string(&buffer[0], (inflate_block_size - state_->z_stream_.avail_out)));
+    state_->bytes_produced_ += (inflate_block_size - state_->z_stream_.avail_out);
+  }
+}
+
+void GzipInflateTransformation::handleInputComplete() {
+  int64_t bytes_written = setOutputComplete();
+  if (state_->bytes_produced_ != bytes_written) {
+    LOG_ERROR("Gzip bytes produced sanity check failed, inflated bytes = %d != written bytes = %d", state_->bytes_produced_, bytes_written);
+  }
+}
+
+
+

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/src/Headers.cc
----------------------------------------------------------------------
diff --git a/lib/atscppapi/src/Headers.cc b/lib/atscppapi/src/Headers.cc
new file mode 100644
index 0000000..c4da326
--- /dev/null
+++ b/lib/atscppapi/src/Headers.cc
@@ -0,0 +1,532 @@
+/**
+  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.
+ */
+
+/**
+ * @file Headers.cc
+ */
+#include "atscppapi/Headers.h"
+#include "InitializableValue.h"
+#include "logging_internal.h"
+#include <ts/ts.h>
+#include "atscppapi/noncopyable.h"
+#include <cctype>
+
+using atscppapi::Headers;
+using std::string;
+using std::list;
+using std::pair;
+using std::make_pair;
+using std::ostringstream;
+using std::map;
+
+namespace atscppapi {
+
+namespace {
+  const int APPEND_INDEX = -1;
+  const list<string> EMPTY_VALUE_LIST;
+  const int FIRST_INDEX = 0;
+}
+
+/**
+ * @private
+ */
+struct HeadersState: noncopyable {
+  Headers::Type type_;
+  TSMBuffer hdr_buf_;
+  TSMLoc hdr_loc_;
+  InitializableValue<Headers::NameValuesMap> name_values_map_;
+  bool detached_;
+  InitializableValue<Headers::RequestCookieMap> request_cookies_;
+  InitializableValue<list<Headers::ResponseCookie> > response_cookies_;
+  HeadersState(Headers::Type type) : type_(type), hdr_buf_(NULL), hdr_loc_(NULL), detached_(false) { }
+};
+
+}
+
+Headers::Headers(Type type) {
+  state_ = new HeadersState(type);
+}
+
+Headers::Type Headers::getType() const {
+  return state_->type_;
+}
+
+void Headers::setType(Type type) {
+  state_->type_ = type;
+}
+
+void Headers::init(void *hdr_buf, void *hdr_loc) {
+  if (state_->hdr_buf_ || state_->hdr_loc_ || state_->detached_) {
+    LOG_ERROR("Cannot reinitialize; hdr_buf %p, hdr_loc %p, detached %s", state_->hdr_buf_, state_->hdr_loc_,
+              (state_->detached_ ? "true" : "false"));
+    return;
+  }
+  state_->hdr_buf_ = static_cast<TSMBuffer>(hdr_buf);
+  state_->hdr_loc_ = static_cast<TSMLoc>(hdr_loc);
+}
+
+void Headers::initDetached() {
+  if (state_->hdr_buf_ || state_->hdr_loc_ || state_->detached_) {
+    LOG_ERROR("Cannot reinitialize; hdr_buf %p, hdr_loc %p, detached %s", state_->hdr_buf_, state_->hdr_loc_,
+              (state_->detached_ ? "true" : "false"));
+    return;
+  }
+  state_->detached_ = true;
+  state_->name_values_map_.setInitialized();
+}
+
+namespace {
+
+void extractHeaderFieldValues(TSMBuffer hdr_buf, TSMLoc hdr_loc, TSMLoc field_loc, const string &header_name,
+                              list<string> &value_list) {
+  int num_values = TSMimeHdrFieldValuesCount(hdr_buf, hdr_loc, field_loc);
+  LOG_DEBUG("Got %d values for header [%s]", num_values, header_name.c_str());
+  if (!num_values) {
+    LOG_DEBUG("Header [%s] has no values; Adding empty string", header_name.c_str());
+    value_list.push_back(string());
+    return;
+  }
+  const char *value;
+  int value_len;
+  for (int i = 0; i < num_values; ++i) {
+    value = TSMimeHdrFieldValueStringGet(hdr_buf, hdr_loc, field_loc, i, &value_len);
+    value_list.push_back((value && value_len) ? string(value, value_len) : string());
+    LOG_DEBUG("Added value [%.*s] to header [%s]", value_len, value, header_name.c_str());
+  }
+}
+
+}
+
+bool Headers::checkAndInitHeaders() const {
+  if (state_->name_values_map_.isInitialized()) {
+    return true;
+  } else if ((state_->hdr_buf_ == NULL) || (state_->hdr_loc_ == NULL)) {
+    LOG_ERROR("Failed to initialize! TS header handles not set; hdr_buf %p, hdr_loc %p", state_->hdr_buf_, 
+              state_->hdr_loc_);
+    return false;
+  }
+  state_->name_values_map_.getValueRef().clear();
+  string key;
+  const char *name, *value;
+  int name_len, num_values, value_len;
+  pair<NameValuesMap::iterator, bool> insert_result;
+  TSMLoc field_loc = TSMimeHdrFieldGet(state_->hdr_buf_, state_->hdr_loc_, FIRST_INDEX);
+  while (field_loc) {
+    name = TSMimeHdrFieldNameGet(state_->hdr_buf_, state_->hdr_loc_, field_loc, &name_len);
+    if (name && (name_len > 0)) {
+      key.assign(name, name_len);
+      insert_result = state_->name_values_map_.getValueRef().insert(
+        NameValuesMap::value_type(key, EMPTY_VALUE_LIST));
+      NameValuesMap::iterator &inserted_element = insert_result.first;
+      list<string> &value_list = inserted_element->second;
+      extractHeaderFieldValues(state_->hdr_buf_, state_->hdr_loc_, field_loc, key, value_list);
+    } else {
+      LOG_ERROR("Failed to get name of header; hdr_buf %p, hdr_loc %p", state_->hdr_buf_, state_->hdr_loc_);
+    }
+    TSMLoc next_field_loc = TSMimeHdrFieldNext(state_->hdr_buf_, state_->hdr_loc_, field_loc);
+    TSHandleMLocRelease(state_->hdr_buf_, state_->hdr_loc_, field_loc);
+    field_loc = next_field_loc;
+  }
+  state_->name_values_map_.setInitialized();
+  LOG_DEBUG("Initialized headers map");
+  return true;
+}
+
+Headers::~Headers() {
+  delete state_;
+}
+
+Headers::size_type Headers::erase(const string &k) {
+  if (!checkAndInitHeaders()) {
+    return 0;
+  }
+  if ((state_->type_ == TYPE_REQUEST) && (CaseInsensitiveStringComparator()(k, "Cookie") == 0)) {
+    state_->request_cookies_.getValueRef().clear();
+    state_->request_cookies_.setInitialized(false);
+  } else if ((state_->type_ == TYPE_RESPONSE) && (CaseInsensitiveStringComparator()(k, "Set-Cookie") == 0)) {
+    state_->response_cookies_.getValueRef().clear();
+    state_->response_cookies_.setInitialized(false);
+  }
+  LOG_DEBUG("Erasing header [%s]", k.c_str());
+  return doBasicErase(k);
+}
+
+Headers::size_type Headers::doBasicErase(const string &k) {
+  if (!state_->detached_) {
+    TSMLoc field_loc = TSMimeHdrFieldFind(state_->hdr_buf_, state_->hdr_loc_, k.c_str(), k.length());
+    while (field_loc) {
+      TSMLoc next_field_loc = TSMimeHdrFieldNextDup(state_->hdr_buf_, state_->hdr_loc_, field_loc);
+      TSMimeHdrFieldDestroy(state_->hdr_buf_, state_->hdr_loc_, field_loc);
+      TSHandleMLocRelease(state_->hdr_buf_, state_->hdr_loc_, field_loc);
+      field_loc = next_field_loc;
+    }
+  }
+  return state_->name_values_map_.getValueRef().erase(k);
+}
+
+Headers::const_iterator Headers::set(const pair<string, list<string> > &pair) {
+  erase(pair.first);
+  return append(pair);
+}
+
+
+Headers::const_iterator Headers::set(const string &key, const list<string> &val) {
+  return set(make_pair(key,val));
+}
+
+Headers::const_iterator Headers::set(const string &key, const string &val) {
+  list<string> values;
+  values.push_back(val);
+  return set(make_pair(key,values));
+}
+
+Headers::const_iterator Headers::append(const pair<string, list<string> > &pair) {
+  if (!checkAndInitHeaders()) {
+    return state_->name_values_map_.getValueRef().end();
+  }
+  if ((state_->type_ == TYPE_REQUEST) && (CaseInsensitiveStringComparator()(pair.first, "Cookie") == 0)) {
+    state_->request_cookies_.getValueRef().clear();
+    state_->request_cookies_.setInitialized(false);
+  } else if ((state_->type_ == TYPE_RESPONSE) &&
+             (CaseInsensitiveStringComparator()(pair.first, "Set-Cookie") == 0)) {
+    state_->response_cookies_.getValueRef().clear();
+    state_->response_cookies_.setInitialized(false);
+  }
+  return doBasicAppend(pair);
+}
+
+Headers::const_iterator Headers::doBasicAppend(const pair<string, list<string> > &pair) {
+  const string &header_name = pair.first; // handy references
+  const list<string> &new_values = pair.second;
+
+  std::pair<NameValuesMap::iterator, bool> insert_result;
+  if (state_->detached_) {
+    insert_result = state_->name_values_map_.getValueRef().insert(make_pair(header_name, EMPTY_VALUE_LIST));
+    list<string> &value_list = insert_result.first->second; // existing or newly inserted
+    for (list<string>::const_iterator iter = new_values.begin(), end = new_values.end(); iter != end; ++iter) {
+      value_list.push_back(*iter);
+      LOG_DEBUG("Appended value [%s] to header [%s]", iter->c_str(), header_name.c_str());
+    }
+  } else {
+    TSMLoc field_loc =
+      TSMimeHdrFieldFind(state_->hdr_buf_, state_->hdr_loc_, header_name.c_str(), header_name.length());
+    
+    if (!field_loc) {
+      TSMimeHdrFieldCreate(state_->hdr_buf_, state_->hdr_loc_, &field_loc);
+      TSMimeHdrFieldNameSet(state_->hdr_buf_, state_->hdr_loc_, field_loc, header_name.c_str(), header_name.length());
+      TSMimeHdrFieldAppend(state_->hdr_buf_, state_->hdr_loc_, field_loc);
+      LOG_DEBUG("Created new structure for header [%s]", header_name.c_str());
+    }
+    for(list<string>::const_iterator ii = new_values.begin(); ii != new_values.end(); ++ii) {
+      TSMimeHdrFieldValueStringInsert(state_->hdr_buf_, state_->hdr_loc_, field_loc, APPEND_INDEX, (*ii).c_str(),
+                                      (*ii).length());
+    }
+
+    insert_result = state_->name_values_map_.getValueRef().insert(make_pair(header_name, EMPTY_VALUE_LIST));
+    list<string> &value_list = insert_result.first->second; // existing or newly inserted
+
+    //
+    // Now because TSMimeHdrFieldValueStringInsert will (possibly) parse each value for commas, that is,
+    // if you insert a list of three elements "Foo", "Bar,Baz", "Blah", this would become
+    // four elements in the marshal buffer and we need to update our own map to reflect that.
+    //
+    // Rather than inserting the list<strings> directly into our map, we will actually rebuild it using the
+    // Traffic Server HDR Marshal Buffer so we're 100% consistent with the internal representation.
+    //
+    if (!insert_result.second) {
+      value_list.clear();
+    }
+    extractHeaderFieldValues(state_->hdr_buf_, state_->hdr_loc_, field_loc, header_name, value_list);
+    TSHandleMLocRelease(state_->hdr_buf_, state_->hdr_loc_, field_loc);
+    LOG_DEBUG("Header [%s] has value(s) [%s]", header_name.c_str(), getJoinedValues(value_list).c_str());
+  }
+  return insert_result.first;
+}
+
+string Headers::getJoinedValues(const string &key, char value_delimiter) {
+  checkAndInitHeaders();
+
+  string ret;
+  Headers::NameValuesMap::iterator key_iter = state_->name_values_map_.getValueRef().find(key);
+  if (key_iter == state_->name_values_map_.getValueRef().end()) {
+    LOG_DEBUG("Header [%s] not present", key.c_str());
+    return ret;
+  }
+  return getJoinedValues(key_iter->second);
+}
+
+string Headers::getJoinedValues(const list<string> &values, char delimiter) {
+  string ret;
+  ret.reserve(128);
+  for (list<string>::const_iterator vals_iter = values.begin(), vals_end = values.end(); vals_iter != vals_end;
+       ++vals_iter) {
+    if (!ret.empty()) {
+      ret += delimiter;
+    }
+    ret.append(*vals_iter);
+  }
+  return ret;
+}
+
+Headers::const_iterator Headers::append(const string &key, const list<string> &val) {
+  return append(make_pair(key,val));
+}
+
+Headers::const_iterator Headers::append(const string &key, const string &val) {
+  list<string> values;
+  values.push_back(val);
+  return append(make_pair(key,values));
+}
+
+Headers::const_iterator Headers::begin() const {
+  checkAndInitHeaders();
+  return state_->name_values_map_.getValueRef().begin();
+}
+
+Headers::const_iterator Headers::end() const {
+  return state_->name_values_map_.getValueRef().end();
+}
+
+Headers::const_reverse_iterator Headers::rbegin() const {
+  checkAndInitHeaders();
+  return state_->name_values_map_.getValueRef().rbegin();
+}
+
+Headers::const_reverse_iterator Headers::rend() const {
+  return state_->name_values_map_.getValueRef().rend();
+}
+
+Headers::const_iterator Headers::find(const string &k) const {
+  checkAndInitHeaders();
+  return state_->name_values_map_.getValueRef().find(k);
+}
+
+Headers::size_type Headers::count(const string &key) const {
+  checkAndInitHeaders();
+  return state_->name_values_map_.getValueRef().count(key);
+}
+
+bool Headers::empty() const {
+  checkAndInitHeaders();
+  return state_->name_values_map_.getValueRef().empty();
+}
+
+Headers::size_type Headers::max_size() const {
+  return state_->name_values_map_.getValueRef().max_size();
+}
+
+Headers::size_type Headers::size() const {
+  checkAndInitHeaders();
+  return state_->name_values_map_.getValueRef().size();
+}
+
+namespace {
+
+const list<string> EMPTY_REQUEST_COOKIE_VALUE_LIST;
+
+void stripEnclosingWhitespace(string &token) {
+  size_t token_size = token.size(), i;
+  for (i = 0; (i < token_size) && std::isspace(token[i]); ++i);
+  if (i) {
+    token.erase(0, i);
+    token_size -= i;
+  }
+  // can't use >= 0 here as we size_t will never go negative
+  for (i = token_size; (i > 0) && std::isspace(token[i - 1]); --i);
+  if (token_size - i) {
+    token.resize(i);
+  }
+}
+
+void addCookieToMap(Headers::RequestCookieMap &cookie_map, const string &name, const string &value) {
+  Headers::RequestCookieMap::value_type element_to_insert(name, EMPTY_REQUEST_COOKIE_VALUE_LIST);
+  list<string> &value_list = (cookie_map.insert(element_to_insert)).first->second;
+  if (!value_list.empty()) { // log duplicates
+    LOG_DEBUG("Cookie [%s] has multiple instances", name.c_str());
+  }
+  value_list.push_back(value);
+  LOG_DEBUG("Added cookie [%s] with value [%s]", name.c_str(), value.c_str());
+}
+
+}
+
+const Headers::RequestCookieMap &Headers::getRequestCookies() const {
+  if (state_->type_ != Headers::TYPE_REQUEST) {
+    LOG_ERROR("Object is not of type request. Returning empty map");
+    return state_->request_cookies_;
+  }
+  if (state_->request_cookies_.isInitialized() || !checkAndInitHeaders()) {
+    return state_->request_cookies_;
+  }
+  state_->request_cookies_.setInitialized();
+  const_iterator iter = find("Cookie");
+  if (iter != end()) {
+    const list<string> &cookie_kvs = iter->second; // cookie key-value pairs
+    string name, value;
+    for (list<string>::const_iterator cookie_kv_iter = cookie_kvs.begin(), cookie_kv_end = cookie_kvs.end();
+         cookie_kv_iter != cookie_kv_end; ++cookie_kv_iter) {
+      const string &cookie_kv = *cookie_kv_iter;
+      size_t cookie_kv_size = cookie_kv.size();
+      size_t start_pos, end_pos, length;
+        
+      for (size_t i = 0; i < cookie_kv_size; ) {
+        start_pos = i;
+        for (end_pos = start_pos;
+             (end_pos < cookie_kv_size) && (cookie_kv[end_pos] != '=') && (cookie_kv[end_pos] != ';'); ++end_pos);
+        if ((end_pos == cookie_kv_size) || (cookie_kv[end_pos] == ';')) {
+          LOG_DEBUG("Unexpected end in cookie key value string [%s]", cookie_kv.c_str());
+          return state_->request_cookies_;
+        }
+        length = end_pos - start_pos;
+        name.assign(cookie_kv, start_pos, length);
+        stripEnclosingWhitespace(name);
+        if (name.empty()) {
+          LOG_DEBUG("Empty cookie name in key value string [%s]", cookie_kv.c_str());
+          return state_->request_cookies_;
+        }
+        start_pos = ++end_pos; // value should start here
+        if (start_pos == cookie_kv_size)  {
+          LOG_DEBUG("Cookie [%s] has no value in key value string [%s]", name.c_str(), cookie_kv.c_str());
+          return state_->request_cookies_;
+        }
+        bool within_quotes = false;
+        for (end_pos = start_pos; end_pos < cookie_kv_size; ++end_pos) {
+          if (cookie_kv[end_pos] == '"') {
+            within_quotes = !within_quotes;
+          } else if ((cookie_kv[end_pos] == ';') && !within_quotes) {
+            break;
+          }
+        }
+        length = end_pos - start_pos;
+        value.assign(cookie_kv, start_pos, length);
+        stripEnclosingWhitespace(value);
+        addCookieToMap(state_->request_cookies_, name ,value);
+        i = ++end_pos; // next name should start here
+      }
+    }
+  }
+  return state_->request_cookies_;
+}
+
+const list<Headers::ResponseCookie> &Headers::getResponseCookies() const {
+  if (state_->type_ != Headers::TYPE_RESPONSE) {
+    LOG_ERROR("Object is not of type response. Returning empty list");
+    return state_->response_cookies_;
+  }
+  if (state_->response_cookies_.isInitialized() || !checkAndInitHeaders()) {
+    return state_->response_cookies_;
+  }
+  state_->response_cookies_.setInitialized();
+  // @TODO Parse Set-Cookie headers here
+  return state_->response_cookies_;
+}
+
+bool Headers::addCookie(const string &name, const string &value) {
+  if (state_->type_ != Headers::TYPE_REQUEST) {
+    LOG_ERROR("Cannot add request cookie to response headers");
+    return false;
+  }
+  if (!checkAndInitHeaders()) {
+    return false;
+  }
+  addCookieToMap(state_->request_cookies_, name, value);
+  updateRequestCookieHeaderFromMap();
+  return true;
+}
+
+bool Headers::addCookie(const ResponseCookie &response_cookie) {
+  if (state_->type_ != Headers::TYPE_RESPONSE) {
+    LOG_ERROR("Cannot add response cookie to object not of type response");
+    return false;
+  }
+  if (!checkAndInitHeaders()) {
+    false;
+  }
+  // @TODO Do logic here
+  return true;
+}
+  
+bool Headers::setCookie(const string &name, const string &value) {
+  if (state_->type_ != Headers::TYPE_REQUEST) {
+    LOG_ERROR("Cannot set request cookie to response headers");
+    return false;
+  }
+  if (!checkAndInitHeaders()) {
+    return false;
+  }
+  getRequestCookies();
+  state_->request_cookies_.getValueRef().erase(name);
+  return addCookie(name, value);
+}
+
+bool Headers::setCookie(const ResponseCookie &response_cookie) {
+  if (state_->type_ != Headers::TYPE_RESPONSE) {
+    LOG_ERROR("Cannot set response cookie to request headers");
+    return false;
+  }
+  if (!checkAndInitHeaders()) {
+    return false;
+  }
+  // @TODO Do logic here
+  return true;
+}
+
+bool Headers::deleteCookie(const string &name) {
+  if (!checkAndInitHeaders()) {
+    return false;
+  }
+  if (state_->type_ == TYPE_REQUEST) {
+    getRequestCookies();
+    RequestCookieMap::iterator iter = state_->request_cookies_.getValueRef().find(name);
+    if (iter == state_->request_cookies_.getValueRef().end()) {
+      LOG_DEBUG("Cookie [%s] doesn't exist", name.c_str());
+      return true;
+    }
+    state_->request_cookies_.getValueRef().erase(iter);
+    updateRequestCookieHeaderFromMap();
+    return true;
+  }
+  getResponseCookies();
+  // @TODO Do logic here
+  return true;
+}
+
+void Headers::updateRequestCookieHeaderFromMap() {
+  string cookie_header;
+  for (RequestCookieMap::iterator cookie_iter = state_->request_cookies_.getValueRef().begin(), 
+         cookie_end = state_->request_cookies_.getValueRef().end(); cookie_iter != cookie_end; ++cookie_iter) {
+    for (list<string>::iterator value_iter = cookie_iter->second.begin(), value_end = cookie_iter->second.end();
+         value_iter != value_end; ++value_iter) {
+      cookie_header += cookie_iter->first;
+      cookie_header += '=';
+      cookie_header += *value_iter;
+      cookie_header += "; ";
+    }
+  }
+  if (!cookie_header.empty()) {
+    cookie_header.erase(cookie_header.size() - 2, 2); // erase trailing '; '
+  }
+
+  // we could have called set(), but set() invalidates the cookie map
+  // indirectly by calling append(). But our map is up to date. So we
+  // do put the set() logic here explicitly.
+  doBasicErase("Cookie");
+  list<string> values;
+  values.push_back(cookie_header);
+  doBasicAppend(pair<string, list<string> >("Cookie", values));
+}

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/src/HttpMethod.cc
----------------------------------------------------------------------
diff --git a/lib/atscppapi/src/HttpMethod.cc b/lib/atscppapi/src/HttpMethod.cc
new file mode 100644
index 0000000..c8a6051
--- /dev/null
+++ b/lib/atscppapi/src/HttpMethod.cc
@@ -0,0 +1,36 @@
+/**
+  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.
+ */
+
+/**
+ * @file HttpMethod.cc
+ */
+
+#include "atscppapi/HttpMethod.h"
+
+const std::string atscppapi::HTTP_METHOD_STRINGS[] = { std::string("UNKNOWN"),
+                                                       std::string("GET"),
+                                                       std::string("POST"),
+                                                       std::string("HEAD"),
+                                                       std::string("CONNECT"),
+                                                       std::string("DELETE"),
+                                                       std::string("ICP_QUERY"),
+                                                       std::string("OPTIONS"),
+                                                       std::string("PURGE"),
+                                                       std::string("PUT"),
+                                                       std::string("TRACE") };
+


[3/5] initial atscppapi commit

Posted by br...@apache.org.
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/src/HttpVersion.cc
----------------------------------------------------------------------
diff --git a/lib/atscppapi/src/HttpVersion.cc b/lib/atscppapi/src/HttpVersion.cc
new file mode 100644
index 0000000..7a1e3d5
--- /dev/null
+++ b/lib/atscppapi/src/HttpVersion.cc
@@ -0,0 +1,29 @@
+/**
+  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.
+ */
+
+/**
+ * @file HttpVersion.cc
+ */
+
+#include "atscppapi/HttpVersion.h"
+
+const std::string atscppapi::HTTP_VERSION_STRINGS[] = { std::string("UNKNOWN"),
+                                                        std::string("HTTP/0.9"),
+                                                        std::string("HTTP/1.0"),
+                                                        std::string("HTTP/1.1") };
+

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/src/InitializableValue.cc
----------------------------------------------------------------------
diff --git a/lib/atscppapi/src/InitializableValue.cc b/lib/atscppapi/src/InitializableValue.cc
new file mode 100644
index 0000000..a0d87af
--- /dev/null
+++ b/lib/atscppapi/src/InitializableValue.cc
@@ -0,0 +1,29 @@
+/**
+  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.
+ */
+
+/**
+ * @file InitializableValue.cc
+ */
+
+#include "InitializableValue.h"
+
+#ifdef DISABLE_TRANSACTION_DATA_CACHING
+bool atscppapi::transaction_data_caching_enabled = false;
+#else
+bool atscppapi::transaction_data_caching_enabled = true;
+#endif

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/src/Logger.cc
----------------------------------------------------------------------
diff --git a/lib/atscppapi/src/Logger.cc b/lib/atscppapi/src/Logger.cc
new file mode 100644
index 0000000..a7c18d5
--- /dev/null
+++ b/lib/atscppapi/src/Logger.cc
@@ -0,0 +1,213 @@
+/**
+  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.
+ */
+/**
+ * @file Logger.cc
+ * @warning log rolling doesn't work correctly in 3.2.x see:
+ *   https://issues.apache.org/jira/browse/TS-1813
+ *   Apply the patch in TS-1813 to correct log rolling in 3.2.x
+ */
+
+#include "atscppapi/Logger.h"
+#include <cstdarg>
+#include <vector>
+#include <cstdio>
+#include <string>
+#include <cstring>
+#include <ts/ts.h>
+#include "atscppapi/noncopyable.h"
+#include "logging_internal.h"
+
+using std::vector;
+using std::string;
+
+using atscppapi::Logger;
+
+/**
+ * @private
+ */
+struct atscppapi::LoggerState: noncopyable  {
+  std::string filename_;
+  bool add_timestamp_;
+  bool rename_file_;
+  volatile Logger::LogLevel level_;
+  bool rolling_enabled_;
+  int rolling_interval_seconds_;
+  TSTextLogObject text_log_obj_;
+  bool initialized_;
+
+  LoggerState() : add_timestamp_(false), rename_file_(false), level_(Logger::LOG_LEVEL_NO_LOG), rolling_enabled_(false),
+                  rolling_interval_seconds_(-1), text_log_obj_(NULL), initialized_(false) { };
+  ~LoggerState() { };
+};
+
+namespace {
+// Since the TSTextLog API doesn't support override the log file sizes (I will add this to TS api at some point)
+// we will use the roll size specified by default in records.config.
+const int ROLL_ON_TIME = 1; // See RollingEnabledValues in LogConfig.h
+}
+
+
+/*
+ * These have default values specified for add_timestamp and rename_file in Logger.h
+ */
+Logger::Logger() {
+  state_ = new LoggerState();
+}
+
+Logger::~Logger() {
+  if (state_->initialized_ && state_->text_log_obj_) {
+    TSTextLogObjectDestroy(state_->text_log_obj_);
+  }
+
+  delete state_;
+}
+
+/*
+ * These have default values specified for rolling_enabled and rolling_interval_seconds in Logger.h
+ */
+bool Logger::init(const string &file, bool add_timestamp, bool rename_file, LogLevel level, bool rolling_enabled, int rolling_interval_seconds) {
+  if (state_->initialized_) {
+    LOG_ERROR("Attempt to reinitialize a logger named '%s' that's already been initialized to '%s'.", file.c_str(), state_->filename_.c_str());
+    return false;
+  }
+  state_->filename_ = file;
+  state_->add_timestamp_ = add_timestamp;
+  state_->rename_file_ = rename_file;
+  state_->level_ = level;
+  state_->rolling_enabled_ = rolling_enabled;
+  state_->rolling_interval_seconds_ = rolling_interval_seconds;
+  state_->initialized_ = true; // set this to true always - we are not providing re-init() after a failed init()
+
+  int mode = 0;
+  if (state_->add_timestamp_) {
+    mode |= TS_LOG_MODE_ADD_TIMESTAMP;
+  }
+
+  if (!state_->rename_file_) {
+    mode |= TS_LOG_MODE_DO_NOT_RENAME;
+  }
+
+  TSReturnCode result = TSTextLogObjectCreate(state_->filename_.c_str(), mode, &state_->text_log_obj_);
+
+  if (result == TS_SUCCESS) {
+    TSTextLogObjectRollingEnabledSet(state_->text_log_obj_, state_->rolling_enabled_ ? ROLL_ON_TIME : 0);
+    TSTextLogObjectRollingIntervalSecSet(state_->text_log_obj_, state_->rolling_interval_seconds_);
+    LOG_DEBUG("Initialized log [%s]", state_->filename_.c_str());
+  } else {
+    state_->level_ = LOG_LEVEL_NO_LOG;
+    LOG_ERROR("Failed to initialize for log [%s]", state_->filename_.c_str());
+  }
+
+  return result == TS_SUCCESS;
+}
+
+void Logger::setLogLevel(Logger::LogLevel level) {
+  if (state_->initialized_) {
+    state_->level_ = level;
+    LOG_DEBUG("Set log level to %d for log [%s]", level, state_->filename_.c_str());
+  }
+}
+
+Logger::LogLevel Logger::getLogLevel() const {
+  if (!state_->initialized_) {
+    LOG_ERROR("Not initialized");
+  }
+  return state_->level_;
+}
+
+void Logger::setRollingIntervalSeconds(int seconds) {
+  if (state_->initialized_) {
+    state_->rolling_interval_seconds_ = seconds;
+    TSTextLogObjectRollingIntervalSecSet(state_->text_log_obj_, seconds);
+    LOG_DEBUG("Set rolling interval for log [%s] to %d seconds", state_->filename_.c_str(), seconds);
+  } else {
+    LOG_ERROR("Not initialized!");
+  }
+}
+
+int Logger::getRollingIntervalSeconds() const {
+  if (!state_->initialized_) {
+    LOG_ERROR("Not initialized");
+  }
+  return state_->rolling_interval_seconds_;
+}
+
+void Logger::setRollingEnabled(bool enabled) {
+  if (state_->initialized_) {
+    state_->rolling_enabled_ = enabled;
+    TSTextLogObjectRollingEnabledSet(state_->text_log_obj_, enabled ? ROLL_ON_TIME : 0);
+    LOG_DEBUG("Rolling for log [%s] is now %s", state_->filename_.c_str(), (enabled ? "true" : "false"));
+  } else {
+    LOG_ERROR("Not initialized!");
+  }
+}
+
+bool Logger::isRollingEnabled() const {
+  if (!state_->initialized_) {
+    LOG_ERROR("Not initialized!");
+  }
+  return state_->rolling_enabled_;
+}
+
+void Logger::flush() {
+  if (state_->initialized_) {
+    TSTextLogObjectFlush(state_->text_log_obj_);
+  } else {
+    LOG_ERROR("Not initialized!");
+  }
+}
+
+namespace {
+const int DEFAULT_BUFFER_SIZE_FOR_VARARGS = 8*1024;
+
+#define TS_TEXT_LOG_OBJECT_WRITE(level) \
+    char buffer[DEFAULT_BUFFER_SIZE_FOR_VARARGS]; \
+    int n; \
+    va_list ap; \
+    while (true) { \
+     va_start(ap, fmt); \
+     n = vsnprintf (&buffer[0], sizeof(buffer), fmt, ap); \
+     va_end(ap); \
+     if (n > -1 && n < sizeof(buffer)) { \
+       LOG_DEBUG("logging a " level " to '%s' with length %d", state_->filename_.c_str(), n); \
+       TSTextLogObjectWrite(state_->text_log_obj_, const_cast<char*>("[" level "] %s"), buffer); \
+     } else { \
+       LOG_ERROR("Unable to log " level " message to '%s' due to size exceeding %d bytes.", state_->filename_.c_str(), sizeof(buffer)); \
+     } \
+     return; \
+    }
+
+} /* end anonymous namespace */
+
+void Logger::logDebug(const char *fmt, ...) {
+  if (state_->level_ <= LOG_LEVEL_DEBUG) {
+    TS_TEXT_LOG_OBJECT_WRITE("DEBUG");
+  }
+}
+
+void Logger::logInfo(const char *fmt, ...) {
+  if (state_->level_ <= LOG_LEVEL_INFO) {
+    TS_TEXT_LOG_OBJECT_WRITE("INFO");
+  }
+}
+
+void Logger::logError(const char *fmt, ...) {
+  if (state_->level_ <= LOG_LEVEL_ERROR) {
+    TS_TEXT_LOG_OBJECT_WRITE("ERROR");
+  }
+}

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/src/Makefile.am
----------------------------------------------------------------------
diff --git a/lib/atscppapi/src/Makefile.am b/lib/atscppapi/src/Makefile.am
new file mode 100644
index 0000000..52085d0
--- /dev/null
+++ b/lib/atscppapi/src/Makefile.am
@@ -0,0 +1,77 @@
+#
+#  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.
+
+AM_CXXFLAGS = -Iinclude
+
+# build the library
+lib_LTLIBRARIES = libatscppapi.la
+libatscppapi_la_LDFLAGS=-lz -lpthread -lrt -version-info @TS_LIBTOOL_VERSION@
+
+libatscppapi_la_SOURCES = GlobalPlugin.cc \
+			  Plugin.cc \
+			  utils.cc \
+			  utils_internal.cc \
+			  Transaction.cc \
+			  TransactionPlugin.cc \
+			  Headers.cc \
+			  Request.cc \
+			  CaseInsensitiveStringComparator.cc \
+			  ClientRequest.cc \
+			  Url.cc \
+			  HttpVersion.cc \
+			  HttpMethod.cc \
+			  InitializableValue.cc \
+			  Response.cc \
+			  TransformationPlugin.cc \
+			  Logger.cc \
+			  Stat.cc \
+			  AsyncHttpFetch.cc \
+			  RemapPlugin.cc \
+			  GzipDeflateTransformation.cc \
+			  GzipInflateTransformation.cc \
+			  AsyncTimer.cc
+
+library_includedir=$(includedir)/atscppapi
+base_include_folder = include/atscppapi/
+
+library_include_HEADERS = $(base_include_folder)/GlobalPlugin.h \
+			  $(base_include_folder)/Plugin.h \
+			  $(base_include_folder)/PluginInit.h \
+			  $(base_include_folder)/Transaction.h \
+			  $(base_include_folder)/TransactionPlugin.h \
+			  $(base_include_folder)/HttpMethod.h \
+			  $(base_include_folder)/HttpStatus.h \
+			  $(base_include_folder)/HttpVersion.h \
+			  $(base_include_folder)/Headers.h \
+			  $(base_include_folder)/Request.h \
+			  $(base_include_folder)/CaseInsensitiveStringComparator.h \
+			  $(base_include_folder)/ClientRequest.h \
+	 		  $(base_include_folder)/Url.h \
+		 	  $(base_include_folder)/Response.h \
+			  $(base_include_folder)/utils.h \
+			  $(base_include_folder)/TransformationPlugin.h \
+			  $(base_include_folder)/Logger.h \
+			  $(base_include_folder)/noncopyable.h \
+			  $(base_include_folder)/Stat.h \
+			  $(base_include_folder)/Mutex.h \
+			  $(base_include_folder)/RemapPlugin.h \
+			  $(base_include_folder)/shared_ptr.h \
+			  $(base_include_folder)/Async.h \
+			  $(base_include_folder)/AsyncHttpFetch.h \
+			  $(base_include_folder)/GzipDeflateTransformation.h \
+			  $(base_include_folder)/GzipInflateTransformation.h \
+			  $(base_include_folder)/AsyncTimer.h
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/src/Plugin.cc
----------------------------------------------------------------------
diff --git a/lib/atscppapi/src/Plugin.cc b/lib/atscppapi/src/Plugin.cc
new file mode 100644
index 0000000..dd8d603
--- /dev/null
+++ b/lib/atscppapi/src/Plugin.cc
@@ -0,0 +1,31 @@
+/**
+  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.
+ */
+
+/**
+ * @file Plugin.cc
+ */
+#include "atscppapi/Plugin.h"
+
+const std::string atscppapi::HOOK_TYPE_STRINGS[] = { std::string("HOOK_READ_REQUEST_HEADERS_PRE_REMAP"),
+                                                     std::string("HOOK_READ_REQUEST_HEADERS_POST_REMAP"),
+                                                     std::string("HOOK_SEND_REQUEST_HEADERS"),
+                                                     std::string("HOOK_READ_RESPONSE_HEADERS"),
+                                                     std::string("HOOK_SEND_RESPONSE_HEADERS"),
+                                                     std::string("HOOK_OS_DNS")
+                                                      };
+

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/src/RemapPlugin.cc
----------------------------------------------------------------------
diff --git a/lib/atscppapi/src/RemapPlugin.cc b/lib/atscppapi/src/RemapPlugin.cc
new file mode 100644
index 0000000..9ff07b6
--- /dev/null
+++ b/lib/atscppapi/src/RemapPlugin.cc
@@ -0,0 +1,66 @@
+/**
+  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.
+ */
+/**
+ * @file RemapPlugin.cc
+ */
+
+#include "atscppapi/RemapPlugin.h"
+#include "logging_internal.h"
+#include "utils_internal.h"
+#include <assert.h>
+#include <ts/remap.h>
+
+using namespace atscppapi;
+
+TSRemapStatus TSRemapDoRemap(void* ih, TSHttpTxn rh, TSRemapRequestInfo* rri) {
+  RemapPlugin *remap_plugin = static_cast<RemapPlugin *>(ih);
+  Url map_from_url(rri->requestBufp, rri->mapFromUrl), map_to_url(rri->requestBufp, rri->mapToUrl);
+  Transaction &transaction = utils::internal::getTransaction(rh);
+  bool redirect = false;
+  RemapPlugin::Result result = remap_plugin->doRemap(map_from_url, map_to_url, transaction, redirect);
+  rri->redirect = redirect ? 1 : 0;
+  switch (result) {
+  case RemapPlugin::RESULT_ERROR:
+    return TSREMAP_ERROR;
+  case RemapPlugin::RESULT_NO_REMAP:
+    return TSREMAP_NO_REMAP;
+  case RemapPlugin::RESULT_DID_REMAP:
+    return TSREMAP_DID_REMAP;
+  case RemapPlugin::RESULT_NO_REMAP_STOP:
+    return TSREMAP_NO_REMAP_STOP;
+  case RemapPlugin::RESULT_DID_REMAP_STOP:
+    return TSREMAP_DID_REMAP_STOP;
+  default:
+    assert(!"Unhandled result");
+    return TSREMAP_ERROR;
+  }
+}
+
+void TSRemapDeleteInstance(void *ih) {
+  RemapPlugin *remap_plugin = static_cast<RemapPlugin *>(ih);
+  delete remap_plugin;
+}
+
+TSReturnCode TSRemapInit(TSRemapInterface *api_info, char *errbuf, int errbuf_size) {
+  return TS_SUCCESS;
+}
+
+RemapPlugin::RemapPlugin(void **instance_handle) {
+  *instance_handle = static_cast<void *>(this);
+}
+

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/src/Request.cc
----------------------------------------------------------------------
diff --git a/lib/atscppapi/src/Request.cc b/lib/atscppapi/src/Request.cc
new file mode 100644
index 0000000..b7cb4c2
--- /dev/null
+++ b/lib/atscppapi/src/Request.cc
@@ -0,0 +1,167 @@
+/**
+  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.
+ */
+/**
+ * @file Request.cc
+ */
+
+#include "atscppapi/Request.h"
+#include <ts/ts.h>
+#include "atscppapi/noncopyable.h"
+#include "InitializableValue.h"
+#include "utils_internal.h"
+#include "logging_internal.h"
+
+using namespace atscppapi;
+using std::string;
+
+/**
+ * @private
+ */
+struct atscppapi::RequestState: noncopyable  {
+  TSMBuffer hdr_buf_;
+  TSMLoc hdr_loc_;
+  TSMLoc url_loc_;
+  Url url_;
+  Headers headers_;
+  InitializableValue<HttpMethod> method_;
+  InitializableValue<HttpVersion> version_;
+  bool destroy_buf_;
+  RequestState() : hdr_buf_(NULL), hdr_loc_(NULL), url_loc_(NULL), method_(HTTP_METHOD_UNKNOWN, false),
+                   version_(HTTP_VERSION_UNKNOWN, false), destroy_buf_(false) { }
+};
+
+Request::Request() {
+  state_ = new RequestState();
+}
+
+Request::Request(void *hdr_buf, void *hdr_loc) {
+  state_ = new RequestState();
+  init(hdr_buf, hdr_loc);
+  LOG_DEBUG("Initialized request object %p with hdr_buf=%p and hdr_loc=%p", this, hdr_buf, hdr_loc);
+}
+
+Request::Request(const string &url_str, HttpMethod method, HttpVersion version) {
+  state_ = new RequestState();
+  state_->method_.setValue(method);
+  state_->version_.setValue(version);
+  state_->destroy_buf_ = true;
+  state_->hdr_buf_ = TSMBufferCreate();
+  state_->headers_.initDetached();
+  if (TSUrlCreate(state_->hdr_buf_, &state_->url_loc_) == TS_SUCCESS) {
+    const char *url_str_start = url_str.c_str();
+    const char *url_str_end = url_str_start + url_str.size();
+    if (TSUrlParse(state_->hdr_buf_, state_->url_loc_, &url_str_start, url_str_end) != TS_PARSE_DONE) {
+      LOG_ERROR("[%s] does not represent a valid url", url_str.c_str());
+    }
+    else {
+      state_->url_.init(state_->hdr_buf_, state_->url_loc_);
+    }
+  }
+  else {
+    state_->url_loc_ = NULL;
+    LOG_ERROR("Could not create URL field; hdr_buf %p", state_->hdr_buf_); 
+  }
+}
+
+void Request::init(void *hdr_buf, void *hdr_loc) {
+  if (state_->hdr_buf_ || state_->hdr_loc_) {
+    LOG_ERROR("Reinitialization; (hdr_buf, hdr_loc) current(%p, %p), attempted(%p, %p)", state_->hdr_buf_,
+              state_->hdr_loc_, hdr_buf, hdr_loc);
+    return;
+  }
+  state_->hdr_buf_ = static_cast<TSMBuffer>(hdr_buf);
+  state_->hdr_loc_ = static_cast<TSMLoc>(hdr_loc);
+  state_->headers_.init(state_->hdr_buf_, state_->hdr_loc_);
+  state_->url_loc_ = NULL;
+  TSHttpHdrUrlGet(state_->hdr_buf_, state_->hdr_loc_, &state_->url_loc_);
+  if (!state_->url_loc_) {
+    LOG_ERROR("TSHttpHdrUrlGet returned a null url loc, hdr_buf=%p, hdr_loc=%p", state_->hdr_buf_, state_->hdr_loc_);
+  }
+  else {
+    state_->url_.init(state_->hdr_buf_, state_->url_loc_);
+    LOG_DEBUG("Initialized url");
+  }
+}
+
+HttpMethod Request::getMethod() const {
+  if (!state_->method_.isInitialized() && state_->hdr_buf_ && state_->hdr_loc_) {
+    int method_len;
+    const char *method_str = TSHttpHdrMethodGet(state_->hdr_buf_, state_->hdr_loc_, &method_len);
+    if (method_str && method_len) {
+      if (method_str == TS_HTTP_METHOD_GET) {
+        state_->method_ = HTTP_METHOD_GET;
+      } else if (method_str == TS_HTTP_METHOD_POST) {
+        state_->method_ = HTTP_METHOD_POST;
+      } else if (method_str == TS_HTTP_METHOD_HEAD) {
+        state_->method_ = HTTP_METHOD_HEAD;
+      } else if (method_str == TS_HTTP_METHOD_CONNECT) {
+        state_->method_ = HTTP_METHOD_CONNECT;
+      } else if (method_str == TS_HTTP_METHOD_DELETE) {
+        state_->method_ = HTTP_METHOD_DELETE;
+      } else if (method_str == TS_HTTP_METHOD_ICP_QUERY) {
+        state_->method_ = HTTP_METHOD_ICP_QUERY;
+      } else if (method_str == TS_HTTP_METHOD_OPTIONS) {
+        state_->method_ = HTTP_METHOD_OPTIONS;
+      } else if (method_str == TS_HTTP_METHOD_PURGE) {
+        state_->method_ = HTTP_METHOD_PURGE;
+      } else if (method_str == TS_HTTP_METHOD_PUT) {
+        state_->method_ = HTTP_METHOD_PUT;
+      } else if (method_str == TS_HTTP_METHOD_TRACE) {
+        state_->method_ = HTTP_METHOD_TRACE;
+      }
+    } else {
+      LOG_ERROR("TSHttpHdrMethodGet returned null string or it was zero length, hdr_buf=%p, hdr_loc=%p, method str=%p, method_len=%d",
+          state_->hdr_buf_, state_->hdr_loc_, method_str, method_len);
+    }
+  }
+  return state_->method_;
+}
+
+Url &Request::getUrl() {
+  return state_->url_;
+}
+
+atscppapi::HttpVersion Request::getVersion() const {
+  if (!state_->version_.isInitialized() && state_->hdr_buf_ && state_->hdr_loc_) {
+    state_->version_ = utils::internal::getHttpVersion(state_->hdr_buf_, state_->hdr_loc_);
+    LOG_DEBUG("Initializing request version=%d [%s] on hdr_buf=%p, hdr_loc=%p",
+        state_->version_.getValue(), HTTP_VERSION_STRINGS[state_->version_.getValue()].c_str(), state_->hdr_buf_, state_->hdr_loc_);
+  }
+  return state_->version_;
+}
+
+atscppapi::Headers &Request::getHeaders() const {
+  return state_->headers_;
+}
+
+Request::~Request() {
+  if (state_->url_loc_) {
+    if (state_->destroy_buf_) {
+      // usually, hdr_loc is the parent of url_loc, but we created this url_loc "directly" in hdr_buf, 
+      // so we use null as parent loc in this case
+      TSMLoc null_parent_loc = NULL;
+      TSHandleMLocRelease(state_->hdr_buf_, null_parent_loc, state_->url_loc_);
+      TSMBufferDestroy(state_->hdr_buf_);
+    } else {
+      LOG_DEBUG("Destroying request object on hdr_buf=%p, hdr_loc=%p, url_loc=%p", state_->hdr_buf_,
+                state_->hdr_loc_, state_->url_loc_);
+      TSHandleMLocRelease(state_->hdr_buf_, state_->hdr_loc_, state_->url_loc_);
+    }
+  }
+  delete state_;
+}

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/src/Response.cc
----------------------------------------------------------------------
diff --git a/lib/atscppapi/src/Response.cc b/lib/atscppapi/src/Response.cc
new file mode 100644
index 0000000..999aad6
--- /dev/null
+++ b/lib/atscppapi/src/Response.cc
@@ -0,0 +1,126 @@
+/**
+  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.
+ */
+/**
+ * @file Response.cc
+ */
+#include "atscppapi/Response.h"
+#include "InitializableValue.h"
+#include "atscppapi/noncopyable.h"
+#include "utils_internal.h"
+#include "logging_internal.h"
+
+using namespace atscppapi;
+using std::string;
+
+namespace atscppapi {
+
+/**
+ * @private
+ */
+struct ResponseState: noncopyable {
+  TSMBuffer hdr_buf_;
+  TSMLoc hdr_loc_;
+  InitializableValue<HttpVersion> version_;
+  InitializableValue<HttpStatus> status_code_;
+  InitializableValue<string> reason_phrase_;
+  Headers headers_;
+  ResponseState() : hdr_buf_(NULL), hdr_loc_(NULL), version_(HTTP_VERSION_UNKNOWN, false), status_code_(HTTP_STATUS_UNKNOWN, false) { }
+};
+
+}
+
+Response::Response() {
+  state_ = new ResponseState();
+  state_->headers_.setType(Headers::TYPE_RESPONSE);
+}
+
+void Response::init(void *hdr_buf, void *hdr_loc) {
+  state_->hdr_buf_ = static_cast<TSMBuffer>(hdr_buf);
+  state_->hdr_loc_ = static_cast<TSMLoc>(hdr_loc);
+  state_->headers_.init(state_->hdr_buf_, state_->hdr_loc_);
+  LOG_DEBUG("Initializing response %p with hdr_buf=%p and hdr_loc=%p", this, state_->hdr_buf_, state_->hdr_loc_);
+}
+
+HttpVersion Response::getVersion() const {
+  if (state_->version_.isInitialized()) {
+    return state_->version_;
+  }
+  if (state_->hdr_buf_ && state_->hdr_loc_) {
+    state_->version_ = utils::internal::getHttpVersion(state_->hdr_buf_, state_->hdr_loc_);
+    LOG_DEBUG("Initializing response version to %d [%s] with hdr_buf=%p and hdr_loc=%p",
+        state_->version_.getValue(), HTTP_VERSION_STRINGS[state_->version_.getValue()].c_str(), state_->hdr_buf_, state_->hdr_loc_);
+    return state_->version_;
+  }
+  return HTTP_VERSION_UNKNOWN;
+}
+
+HttpStatus Response::getStatusCode() const {
+  if (state_->status_code_.isInitialized()) {
+    return state_->status_code_;
+  }
+  if (state_->hdr_buf_ && state_->hdr_loc_) {
+    state_->status_code_ = static_cast<HttpStatus>(TSHttpHdrStatusGet(state_->hdr_buf_, state_->hdr_loc_));
+    LOG_DEBUG("Initializing response status code to %d with hdr_buf=%p and hdr_loc=%p",
+        state_->status_code_.getValue(), state_->hdr_buf_, state_->hdr_loc_);
+    return state_->status_code_;
+  }
+
+  return HTTP_STATUS_UNKNOWN;
+}
+
+void Response::setStatusCode(HttpStatus code) {
+  if (state_->hdr_buf_ && state_->hdr_loc_) {
+    TSHttpHdrStatusSet(state_->hdr_buf_, state_->hdr_loc_, static_cast<TSHttpStatus>(code));
+    state_->status_code_ = code;
+    LOG_DEBUG("Changing response status code to %d with hdr_buf=%p and hdr_loc=%p",
+        state_->status_code_.getValue(), state_->hdr_buf_, state_->hdr_loc_);
+  }
+}
+
+const string &Response::getReasonPhrase() const {
+  if (!state_->reason_phrase_.isInitialized() && state_->hdr_buf_ && state_->hdr_loc_) {
+    int length;
+    const char *str = TSHttpHdrReasonGet(state_->hdr_buf_, state_->hdr_loc_, &length);
+    if (str && length) {
+      state_->reason_phrase_.getValueRef().assign(str, length);
+      LOG_DEBUG("Initializing response reason phrase to '%s' with hdr_buf=%p and hdr_loc=%p",
+          state_->reason_phrase_.getValueRef().c_str(), state_->hdr_buf_, state_->hdr_loc_);
+    } else {
+      LOG_ERROR("TSHttpHdrReasonGet returned null string or zero length. str=%p, length=%d, hdr_buf=%p, hdr_loc=%p",
+          str, length, state_->hdr_buf_, state_->hdr_loc_);
+    }
+  }
+  return state_->reason_phrase_; // if not initialized, we will just return an empty string
+}
+
+void Response::setReasonPhrase(const string &phrase) {
+  if (state_->hdr_buf_ && state_->hdr_loc_) {
+    TSHttpHdrReasonSet(state_->hdr_buf_, state_->hdr_loc_, phrase.c_str(), phrase.length());
+    state_->reason_phrase_ = phrase;
+    LOG_DEBUG("Changing response reason phrase to '%s' with hdr_buf=%p and hdr_loc=%p",
+        phrase.c_str(), state_->hdr_buf_, state_->hdr_loc_);
+  }
+}
+
+Headers &Response::getHeaders() const {
+  return state_->headers_;  // if not initialized, we will just return an empty object
+}
+
+Response::~Response() {
+  delete state_;
+}

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/src/Stat.cc
----------------------------------------------------------------------
diff --git a/lib/atscppapi/src/Stat.cc b/lib/atscppapi/src/Stat.cc
new file mode 100644
index 0000000..b10082b
--- /dev/null
+++ b/lib/atscppapi/src/Stat.cc
@@ -0,0 +1,96 @@
+/**
+  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.
+ */
+/**
+ * @file Stat.cc
+ */
+
+#include "atscppapi/Stat.h"
+#include <string>
+#include <stdint.h>
+#include <ts/ts.h>
+#include "logging_internal.h"
+
+using namespace atscppapi;
+using std::string;
+
+Stat::Stat() : stat_id_(TS_ERROR) {
+// ATS Guarantees that stat ids will always be > 0. So we can use stat_id_ > 0 to
+// verify that this stat has been properly initialized.
+}
+
+Stat::~Stat() {
+// we really dont have any cleanup since ATS doesn't expose a method to destroy stats
+}
+
+bool Stat::init(string name, Stat::SyncType type, bool persistent) {
+  // TS_RECORDDATATYPE_INT is the only type currently supported
+  // so that's why this api doesn't expose other types, TSStatSync is equivalent to StatSyncType
+  stat_id_ = TSStatCreate(name.c_str(), TS_RECORDDATATYPE_INT, persistent ?  TS_STAT_PERSISTENT : TS_STAT_NON_PERSISTENT, static_cast<TSStatSync>(type));
+  if (stat_id_ != TS_ERROR) {
+    LOG_DEBUG("Created new stat named '%s' with stat_id = %d", name.c_str(), stat_id_);
+  } else {
+    LOG_ERROR("Unable to create stat named '%s'.", name.c_str());
+  }
+
+  if (stat_id_ == TS_ERROR) {
+    return false;
+  }
+
+  if (!persistent) {
+    set(0);
+  }
+
+  return true;
+}
+
+void Stat::set(int64_t value) {
+  if (stat_id_ == TS_ERROR) {
+    return;
+  }
+
+  TSStatIntSet(stat_id_, value);
+}
+
+int64_t Stat::get() const {
+  if (stat_id_ == TS_ERROR) {
+    return 0;
+  }
+
+  return TSStatIntGet(stat_id_);
+}
+
+void Stat::increment(int64_t amount) {
+  if (stat_id_ == TS_ERROR) {
+    return;
+  }
+
+  TSStatIntIncrement(stat_id_, amount);
+}
+
+void Stat::decrement(int64_t amount) {
+  if (stat_id_ == TS_ERROR) {
+    return;
+  }
+
+  TSStatIntDecrement(stat_id_, amount);
+}
+
+
+
+
+

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/src/Transaction.cc
----------------------------------------------------------------------
diff --git a/lib/atscppapi/src/Transaction.cc b/lib/atscppapi/src/Transaction.cc
new file mode 100644
index 0000000..e3be20f
--- /dev/null
+++ b/lib/atscppapi/src/Transaction.cc
@@ -0,0 +1,300 @@
+/**
+  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.
+ */
+
+/**
+ * @file Transaction.cc
+ */
+
+#include "atscppapi/Transaction.h"
+#include <cstdlib>
+#include <cstring>
+#include <map>
+#include <string>
+#include <ts/ts.h>
+#include "atscppapi/shared_ptr.h"
+#include "logging_internal.h"
+#include "utils_internal.h"
+#include "InitializableValue.h"
+#include "atscppapi/noncopyable.h"
+
+using std::map;
+using std::string;
+using namespace atscppapi;
+
+/**
+ * @private
+ */
+struct atscppapi::TransactionState: noncopyable {
+  TSHttpTxn txn_;
+  std::list<TransactionPlugin *> plugins_;
+  TSMBuffer client_request_hdr_buf_;
+  TSMLoc client_request_hdr_loc_;
+  ClientRequest client_request_;
+  TSMBuffer server_request_hdr_buf_;
+  TSMLoc server_request_hdr_loc_;
+  Request server_request_;
+  TSMBuffer server_response_hdr_buf_;
+  TSMLoc server_response_hdr_loc_;
+  Response server_response_;
+  TSMBuffer client_response_hdr_buf_;
+  TSMLoc client_response_hdr_loc_;
+  Response client_response_;
+  map<string, shared_ptr<Transaction::ContextValue> > context_values_;
+
+  TransactionState(TSHttpTxn txn, TSMBuffer client_request_hdr_buf, TSMLoc client_request_hdr_loc)
+    : txn_(txn), client_request_hdr_buf_(client_request_hdr_buf), client_request_hdr_loc_(client_request_hdr_loc),
+      client_request_(txn, client_request_hdr_buf, client_request_hdr_loc),
+      server_request_hdr_buf_(NULL), server_request_hdr_loc_(NULL),
+      server_response_hdr_buf_(NULL), server_response_hdr_loc_(NULL),
+      client_response_hdr_buf_(NULL), client_response_hdr_loc_(NULL)
+  { };
+};
+
+Transaction::Transaction(void *raw_txn) {
+  TSHttpTxn txn = static_cast<TSHttpTxn>(raw_txn);
+  TSMBuffer hdr_buf;
+  TSMLoc hdr_loc;
+  TSHttpTxnClientReqGet(txn, &hdr_buf, &hdr_loc);
+  if (!hdr_buf || !hdr_loc) {
+    LOG_ERROR("TSHttpTxnClientReqGet tshttptxn=%p returned a null hdr_buf=%p or hdr_loc=%p.", txn, hdr_buf, hdr_loc);
+  }
+
+  state_ = new TransactionState(txn, hdr_buf, hdr_loc);
+  LOG_DEBUG("Transaction tshttptxn=%p constructing Transaction object %p, client req hdr_buf=%p, client req hdr_loc=%p",
+      txn, this, hdr_buf, hdr_loc);
+}
+
+Transaction::~Transaction() {
+  LOG_DEBUG("Transaction tshttptxn=%p destroying Transaction object %p", state_->txn_, this);
+  static const TSMLoc NULL_PARENT_LOC = NULL;
+  TSHandleMLocRelease(state_->client_request_hdr_buf_, NULL_PARENT_LOC, state_->client_request_hdr_loc_);
+  if (state_->server_request_hdr_buf_ && state_->server_request_hdr_loc_) {
+    LOG_DEBUG("Releasing server request");
+    TSHandleMLocRelease(state_->server_request_hdr_buf_, NULL_PARENT_LOC, state_->server_request_hdr_loc_);
+  }
+  if (state_->server_response_hdr_buf_ && state_->server_response_hdr_loc_) {
+    LOG_DEBUG("Releasing server response");
+    TSHandleMLocRelease(state_->server_response_hdr_buf_, NULL_PARENT_LOC, state_->server_response_hdr_loc_);
+  }
+  if (state_->client_response_hdr_buf_ && state_->client_response_hdr_loc_) {
+    LOG_DEBUG("Releasing client response");
+    TSHandleMLocRelease(state_->client_response_hdr_buf_, NULL_PARENT_LOC, state_->client_response_hdr_loc_);
+  }
+  delete state_;
+}
+
+void Transaction::resume() {
+  TSHttpTxnReenable(state_->txn_, static_cast<TSEvent>(TS_EVENT_HTTP_CONTINUE));
+}
+
+void Transaction::error() {
+  LOG_DEBUG("Transaction tshttptxn=%p reenabling to error state", state_->txn_);
+  TSHttpTxnReenable(state_->txn_, static_cast<TSEvent>(TS_EVENT_HTTP_ERROR));
+}
+
+void Transaction::error(const std::string &page) {
+  setErrorBody(page);
+  error(); // finally, reenable with HTTP_ERROR
+}
+
+void Transaction::setErrorBody(const std::string &page) {
+  LOG_DEBUG("Transaction tshttptxn=%p setting error body page: %s", state_->txn_, page.c_str());
+  char *res_bdy = static_cast<char*>(TSmalloc(page.length() + 1));
+  strncpy(res_bdy, page.c_str(), page.length());
+  res_bdy[page.length()] = '\0';
+
+  std::string str_content_type = "text/html";
+  char *content_type = static_cast<char*>(TSmalloc(str_content_type.length() + 1));
+  strncpy(content_type, str_content_type.c_str(), str_content_type.length());
+  content_type[str_content_type.length()] = '\0';
+
+  TSHttpTxnErrorBodySet(state_->txn_, res_bdy, page.length(), content_type);
+}
+
+bool Transaction::isInternalRequest() const {
+  return TSHttpIsInternalRequest(state_->txn_) == TS_SUCCESS;
+}
+
+void *Transaction::getAtsHandle() const {
+  return static_cast<void *>(state_->txn_);
+}
+
+const std::list<atscppapi::TransactionPlugin *> &Transaction::getPlugins() const {
+  return state_->plugins_;
+}
+
+void Transaction::addPlugin(TransactionPlugin *plugin) {
+  LOG_DEBUG("Transaction tshttptxn=%p registering new TransactionPlugin %p.", state_->txn_, plugin);
+  state_->plugins_.push_back(plugin);
+}
+
+shared_ptr<Transaction::ContextValue> Transaction::getContextValue(const std::string &key) {
+  shared_ptr<Transaction::ContextValue> return_context_value;
+  map<string, shared_ptr<Transaction::ContextValue> >::iterator iter = state_->context_values_.find(key);
+  if (iter != state_->context_values_.end()) {
+    return_context_value = iter->second;
+  }
+
+  return return_context_value;
+}
+
+void Transaction::setContextValue(const std::string &key, shared_ptr<Transaction::ContextValue> value) {
+  state_->context_values_[key] = value;
+}
+
+ClientRequest &Transaction::getClientRequest() {
+  return state_->client_request_;
+}
+
+Request &Transaction::getServerRequest() {
+  return state_->server_request_;
+}
+
+Response &Transaction::getServerResponse() {
+  return state_->server_response_;
+}
+
+Response &Transaction::getClientResponse() {
+  return state_->client_response_;
+}
+
+string Transaction::getEffectiveUrl() {
+	string ret_val;
+	int length = 0;
+	char *buf = TSHttpTxnEffectiveUrlStringGet(state_->txn_, &length);
+	if (buf && length) {
+		ret_val.assign(buf, length);
+	}
+
+	if (buf)
+		TSfree(buf);
+
+	return ret_val;
+}
+
+bool Transaction::setCacheUrl(const string &cache_url) {
+	TSReturnCode res = TSCacheUrlSet(state_->txn_, cache_url.c_str(), cache_url.length());
+    return (res == TS_SUCCESS);
+}
+
+const sockaddr *Transaction::getIncomingAddress() const {
+  return TSHttpTxnIncomingAddrGet(state_->txn_);
+}
+
+const sockaddr *Transaction::getClientAddress() const {
+  return TSHttpTxnClientAddrGet(state_->txn_);
+}
+
+const sockaddr *Transaction::getNextHopAddress() const {
+  return TSHttpTxnNextHopAddrGet(state_->txn_);
+}
+
+const sockaddr *Transaction::getServerAddress() const {
+  return TSHttpTxnServerAddrGet(state_->txn_);
+}
+
+bool Transaction::setServerAddress(const sockaddr *sockaddress) {
+  return TSHttpTxnServerAddrSet(state_->txn_,sockaddress) == TS_SUCCESS;
+}
+
+bool Transaction::setIncomingPort(uint16_t port) {
+  TSHttpTxnClientIncomingPortSet(state_->txn_, port);
+  return true; // In reality TSHttpTxnClientIncomingPortSet should return SUCCESS or ERROR.
+}
+
+void Transaction::setTimeout(Transaction::TimeoutType type, int time_ms) {
+  switch (type) {
+    case TIMEOUT_DNS:
+      TSHttpTxnDNSTimeoutSet(state_->txn_, time_ms);
+      break;
+    case TIMEOUT_CONNECT:
+      TSHttpTxnConnectTimeoutSet(state_->txn_, time_ms);
+      break;
+    case TIMEOUT_NO_ACTIVITY:
+      TSHttpTxnNoActivityTimeoutSet(state_->txn_, time_ms);
+      break;
+    case TIMEOUT_ACTIVE:
+      TSHttpTxnActiveTimeoutSet(state_->txn_, time_ms);
+      break;
+    default:
+      break;
+  }
+}
+
+namespace {
+
+/**
+ * initializeHandles is a convinience functor that takes a pointer to a TS Function that
+ * will return the TSMBuffer and TSMLoc for a given server request/response or client/request response
+ *
+ * @param constructor takes a function pointer of type GetterFunction
+ * @param txn a TSHttpTxn
+ * @param hdr_buf the address where the hdr buf will be stored
+ * @param hdr_loc the address where the mem loc will be storeds
+ * @param name name of the entity - used for logging
+ */
+class initializeHandles {
+public:
+  typedef TSReturnCode (*GetterFunction)(TSHttpTxn, TSMBuffer *, TSMLoc *);
+  initializeHandles(GetterFunction getter) : getter_(getter) { }
+  bool operator()(TSHttpTxn txn, TSMBuffer &hdr_buf, TSMLoc &hdr_loc, const char *handles_name) {
+    if (!hdr_buf && !hdr_loc) {
+      if (getter_(txn, &hdr_buf, &hdr_loc) == TS_SUCCESS) {
+        return true;
+      }
+      else {
+        LOG_ERROR("Could not get %s", handles_name);
+      }
+    }
+    else {
+      LOG_ERROR("%s already initialized", handles_name);
+    }
+    return false;
+  }
+private:
+  GetterFunction getter_;
+};
+
+} // anonymous namespace
+
+void Transaction::initServerRequest() {
+  static initializeHandles initializeServerRequestHandles(TSHttpTxnServerReqGet);
+  if (initializeServerRequestHandles(state_->txn_, state_->server_request_hdr_buf_,
+                                     state_->server_request_hdr_loc_, "server request")) {
+    LOG_DEBUG("Initializing server request");
+    state_->server_request_.init(state_->server_request_hdr_buf_, state_->server_request_hdr_loc_);
+  }
+}
+
+void Transaction::initServerResponse() {
+  static initializeHandles initializeServerResponseHandles(TSHttpTxnServerRespGet);
+  if (initializeServerResponseHandles(state_->txn_, state_->server_response_hdr_buf_,
+                                      state_->server_response_hdr_loc_, "server response")) {
+    LOG_DEBUG("Initializing server response");
+    state_->server_response_.init(state_->server_response_hdr_buf_, state_->server_response_hdr_loc_);
+  }
+}
+
+void Transaction::initClientResponse() {
+  static initializeHandles initializeClientResponseHandles(TSHttpTxnClientRespGet);
+  if (initializeClientResponseHandles(state_->txn_, state_->client_response_hdr_buf_,
+                                      state_->client_response_hdr_loc_, "client response")) {
+    LOG_DEBUG("Initializing client response");
+    state_->client_response_.init(state_->client_response_hdr_buf_, state_->client_response_hdr_loc_);
+  }
+}

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/src/TransactionPlugin.cc
----------------------------------------------------------------------
diff --git a/lib/atscppapi/src/TransactionPlugin.cc b/lib/atscppapi/src/TransactionPlugin.cc
new file mode 100644
index 0000000..52af478
--- /dev/null
+++ b/lib/atscppapi/src/TransactionPlugin.cc
@@ -0,0 +1,83 @@
+/**
+  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.
+ */
+
+/**
+ * @file TransactionPlugin.cc
+ */
+
+#include "atscppapi/TransactionPlugin.h"
+#include <ts/ts.h>
+#include <cstddef>
+#include <cassert>
+#include "atscppapi/Mutex.h"
+#include "atscppapi/shared_ptr.h"
+#include "utils_internal.h"
+#include "atscppapi/noncopyable.h"
+#include "logging_internal.h"
+
+using namespace atscppapi;
+using atscppapi::TransactionPlugin;
+
+/**
+ * @private
+ */
+struct atscppapi::TransactionPluginState: noncopyable {
+  TSCont cont_;
+  TSHttpTxn ats_txn_handle_;
+  shared_ptr<Mutex> mutex_;
+  TransactionPluginState(TSHttpTxn ats_txn_handle) : ats_txn_handle_(ats_txn_handle),
+                                                     mutex_(new Mutex(Mutex::TYPE_RECURSIVE)) { }
+};
+
+namespace {
+
+static int handleTransactionPluginEvents(TSCont cont, TSEvent event, void *edata) {
+  TSHttpTxn txn = static_cast<TSHttpTxn>(edata);
+  TransactionPlugin *plugin = static_cast<TransactionPlugin *>(TSContDataGet(cont));
+  LOG_DEBUG("cont=%p, event=%d, tshttptxn=%p, plugin=%p", cont, event, edata, plugin);
+  atscppapi::utils::internal::invokePluginForEvent(plugin, txn, event);
+  return 0;
+}
+
+} /* anonymous namespace */
+
+TransactionPlugin::TransactionPlugin(Transaction &transaction) {
+  state_ = new TransactionPluginState(static_cast<TSHttpTxn>(transaction.getAtsHandle()));
+  TSMutex mutex = NULL;
+  state_->cont_ = TSContCreate(handleTransactionPluginEvents, mutex);
+  TSContDataSet(state_->cont_, static_cast<void *>(this));
+  LOG_DEBUG("Creating new TransactionPlugin=%p tshttptxn=%p, cont=%p", this, state_->ats_txn_handle_,
+            state_->cont_);
+}
+
+shared_ptr<Mutex> TransactionPlugin::getMutex() {
+  return state_->mutex_;
+}
+
+TransactionPlugin::~TransactionPlugin() {
+  LOG_DEBUG("Destroying TransactionPlugin=%p", this);
+  TSContDestroy(state_->cont_);
+  delete state_;
+}
+
+void TransactionPlugin::registerHook(Plugin::HookType hook_type) {
+  LOG_DEBUG("TransactionPlugin=%p tshttptxn=%p registering hook_type=%d [%s]", this, state_->ats_txn_handle_,
+            hook_type, HOOK_TYPE_STRINGS[hook_type].c_str());
+  TSHttpHookID hook_id = atscppapi::utils::internal::convertInternalHookToTsHook(hook_type);
+  TSHttpTxnHookAdd(state_->ats_txn_handle_, hook_id, state_->cont_);
+}

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/src/TransformationPlugin.cc
----------------------------------------------------------------------
diff --git a/lib/atscppapi/src/TransformationPlugin.cc b/lib/atscppapi/src/TransformationPlugin.cc
new file mode 100644
index 0000000..2fcb899
--- /dev/null
+++ b/lib/atscppapi/src/TransformationPlugin.cc
@@ -0,0 +1,319 @@
+/**
+  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.
+ */
+
+/**
+ * @file TransformationPlugin.cc
+ */
+
+#include "atscppapi/TransformationPlugin.h"
+
+#include <ts/ts.h>
+#include <cstddef>
+#include "utils_internal.h"
+#include "logging_internal.h"
+#include "atscppapi/noncopyable.h"
+
+#ifndef INT64_MAX
+#define INT64_MAX (9223372036854775807LL)
+#endif
+
+using namespace atscppapi;
+using atscppapi::TransformationPlugin;
+
+/**
+ * @private
+ */
+struct atscppapi::TransformationPluginState: noncopyable {
+  TSVConn vconn_;
+  Transaction &transaction_;
+  TransformationPlugin &transformation_plugin_;
+  TransformationPlugin::Type type_;
+  TSVIO output_vio_; // this gets initialized on an output().
+  TSHttpTxn txn_;
+  TSIOBuffer output_buffer_;
+  TSIOBufferReader output_buffer_reader_;
+  int64_t bytes_written_;
+
+  // We can only send a single WRITE_COMPLETE even though
+  // we may receive an immediate event after we've sent a
+  // write complete, so we'll keep track of whether or not we've
+  // sent the input end our write complte.
+  bool input_complete_dispatched_;
+
+  TransformationPluginState(atscppapi::Transaction &transaction, TransformationPlugin &transformation_plugin,
+      TransformationPlugin::Type type, TSHttpTxn txn)
+    : vconn_(NULL), transaction_(transaction), transformation_plugin_(transformation_plugin), type_(type),
+      output_vio_(NULL), txn_(txn), output_buffer_(NULL), output_buffer_reader_(NULL), bytes_written_(0),
+      input_complete_dispatched_(false) {
+    output_buffer_ = TSIOBufferCreate();
+    output_buffer_reader_ = TSIOBufferReaderAlloc(output_buffer_);
+  };
+
+  ~TransformationPluginState() {
+    if (output_buffer_reader_) {
+      TSIOBufferReaderFree(output_buffer_reader_);
+      output_buffer_reader_ = NULL;
+    }
+
+    if (output_buffer_) {
+      TSIOBufferDestroy(output_buffer_);
+      output_buffer_ = NULL;
+    }
+  }
+};
+
+namespace {
+
+void cleanupTransformation(TSCont contp) {
+  LOG_DEBUG("Destroying transformation contp=%p", contp);
+  TSContDataSet(contp, reinterpret_cast<void *>(0xDEADDEAD));
+  TSContDestroy(contp);
+}
+
+int handleTransformationPluginRead(TSCont contp, TransformationPluginState *state) {
+  // Traffic Server naming is quite confusing, in this context the write_vio
+  // is actually the vio we read from.
+  TSVIO write_vio = TSVConnWriteVIOGet(contp);
+  if (write_vio) {
+    int64_t to_read = TSVIONTodoGet(write_vio);
+    LOG_DEBUG("Transformation contp=%p write_vio=%p, to_read=%d", contp, write_vio, to_read);
+
+    if (to_read > 0) {
+      /*
+       * The amount of data left to read needs to be truncated by
+       * the amount of data actually in the read buffer.
+       **/
+      int64_t avail = TSIOBufferReaderAvail(TSVIOReaderGet(write_vio));
+      LOG_DEBUG("Transformation contp=%p write_vio=%p, to_read=%d, buffer reader avail=%d", contp, write_vio, to_read, avail);
+
+      if (to_read > avail) {
+        to_read = avail;
+        LOG_DEBUG("Transformation contp=%p write_vio=%p, to read > avail, fixing to_read to be equal to avail. to_read=%d, buffer reader avail=%d", contp, write_vio, to_read, avail);
+      }
+
+      if (to_read > 0) {
+        /* Create a buffer and a buffer reader */
+        TSIOBuffer input_buffer = TSIOBufferCreate();
+        TSIOBufferReader input_reader = TSIOBufferReaderAlloc(input_buffer);
+
+        /* Copy the data from the read buffer to the input buffer. */
+        TSIOBufferCopy(input_buffer, TSVIOReaderGet(write_vio), to_read, 0);
+
+        /* Tell the read buffer that we have read the data and are no
+         longer interested in it. */
+        TSIOBufferReaderConsume(TSVIOReaderGet(write_vio), to_read);
+
+        /* Modify the read VIO to reflect how much data we've completed. */
+        TSVIONDoneSet(write_vio, TSVIONDoneGet(write_vio) + to_read);
+
+        std::string in_data = utils::internal::consumeFromTSIOBufferReader(input_reader);
+        LOG_DEBUG("Transformation contp=%p write_vio=%p consumed %d bytes from bufferreader", contp, write_vio, in_data.length());
+
+        /* Clean up the buffer and reader */
+        TSIOBufferReaderFree(input_reader);
+        TSIOBufferDestroy(input_buffer);
+
+        /* Now call the client to tell them about data */
+        if (in_data.length() > 0) {
+           state->transformation_plugin_.consume(in_data);
+        }
+      }
+
+      /* now that we've finished reading we will check if there is anything left to read. */
+      TSCont vio_cont = TSVIOContGet(write_vio); // for some reason this can occasionally be null
+
+      if (TSVIONTodoGet(write_vio) > 0) {
+        LOG_DEBUG("Transformation contp=%p write_vio=%p, vio_cont=%p still has bytes left to process, todo > 0.", contp, write_vio, vio_cont);
+
+        if (to_read > 0) {
+          TSVIOReenable(write_vio);
+
+          /* Call back the read VIO continuation to let it know that we are ready for more data. */
+          if (vio_cont) {
+            TSContCall(vio_cont, static_cast<TSEvent>(TS_EVENT_VCONN_WRITE_READY), write_vio);
+          }
+        }
+      } else {
+        LOG_DEBUG("Transformation contp=%p write_vio=%p, vio_cont=%p has no bytes left to process, will send WRITE_COMPLETE.", contp, write_vio, vio_cont);
+
+        /* Call back the write VIO continuation to let it know that we have completed the write operation. */
+        if (!state->input_complete_dispatched_) {
+         state->transformation_plugin_.handleInputComplete();
+         state->input_complete_dispatched_ = true;
+         if (vio_cont) {
+           TSContCall(vio_cont, static_cast<TSEvent>(TS_EVENT_VCONN_WRITE_COMPLETE), write_vio);
+         }
+        }
+      }
+    } else {
+      TSCont vio_cont = TSVIOContGet(write_vio); // for some reason this can occasionally be null?
+      LOG_DEBUG("Transformation contp=%p write_vio=%p, vio_cont=%p has no bytes left to process.", contp, write_vio, vio_cont);
+
+      /* Call back the write VIO continuation to let it know that we have completed the write operation. */
+      if (!state->input_complete_dispatched_) {
+       state->transformation_plugin_.handleInputComplete();
+       state->input_complete_dispatched_ = true;
+       if (vio_cont) {
+         TSContCall(vio_cont, static_cast<TSEvent>(TS_EVENT_VCONN_WRITE_COMPLETE), write_vio);
+       }
+      }
+    }
+  } else {
+    LOG_ERROR("Transformation contp=%p write_vio=%p was NULL!", contp, write_vio);
+  }
+  return 0;
+}
+
+int handleTransformationPluginEvents(TSCont contp, TSEvent event, void *edata) {
+  TransformationPluginState *state = static_cast<TransformationPluginState *>(TSContDataGet(contp));
+  LOG_DEBUG("Transformation contp=%p event=%d edata=%p tshttptxn=%p", contp, event, edata, state->txn_);
+
+  // The first thing you always do is check if the VConn is closed.
+  int connection_closed = TSVConnClosedGet(state->vconn_);
+  if (connection_closed) {
+    LOG_DEBUG("Transformation contp=%p tshttptxn=%p is closed connection_closed=%d ", contp, state->txn_, connection_closed);
+    // we'll do the cleanupTransformation in the TransformationPlugin destructor.
+    return 0;
+  }
+
+  if (event == TS_EVENT_VCONN_WRITE_COMPLETE) {
+    TSVConn output_vconn = TSTransformOutputVConnGet(state->vconn_);
+    LOG_DEBUG("Transformation contp=%p tshttptxn=%p received WRITE_COMPLETE, shutting down outputvconn=%p ", contp, state->txn_, output_vconn);
+    TSVConnShutdown(output_vconn, 0, 1);  // The other end is done reading our output
+    return 0;
+  } else if (event == TS_EVENT_ERROR) {
+    TSVIO write_vio;
+    /* Get the write VIO for the write operation that was
+     performed on ourself. This VIO contains the continuation of
+     our parent transformation. */
+    write_vio = TSVConnWriteVIOGet(state->vconn_);
+    TSCont vio_cont = TSVIOContGet(write_vio);
+    LOG_ERROR("Transformation contp=%p tshttptxn=%p received EVENT_ERROR forwarding to write_vio=%p viocont=%p", contp, state->txn_, write_vio, vio_cont);
+    if (vio_cont) {
+      TSContCall(vio_cont, TS_EVENT_ERROR, write_vio);
+    }
+    return 0;
+  }
+
+  // All other events includign WRITE_READY will just attempt to transform more data.
+  return handleTransformationPluginRead(state->vconn_, state);
+}
+
+} /* anonymous namespace */
+
+TransformationPlugin::TransformationPlugin(Transaction &transaction, TransformationPlugin::Type type)
+  : TransactionPlugin(transaction) {
+  state_ = new TransformationPluginState(transaction, *this, type, static_cast<TSHttpTxn>(transaction.getAtsHandle()));
+  state_->vconn_ = TSTransformCreate(handleTransformationPluginEvents, state_->txn_);
+  TSContDataSet(state_->vconn_, static_cast<void *>(state_)); // edata in a TransformationHandler is NOT a TSHttpTxn.
+  LOG_DEBUG("Creating TransformationPlugin=%p (vconn)contp=%p tshttptxn=%p transformation_type=%d", this, state_->vconn_, state_->txn_, type);
+  TSHttpTxnHookAdd(state_->txn_, utils::internal::convertInternalTransformationTypeToTsHook(type), state_->vconn_);
+}
+
+TransformationPlugin::~TransformationPlugin() {
+  LOG_DEBUG("Destroying TransformationPlugin=%p", this);
+  cleanupTransformation(state_->vconn_);
+  delete state_;
+}
+
+size_t TransformationPlugin::produce(const std::string &data) {
+  LOG_DEBUG("TransformationPlugin=%p tshttptxn=%p producing output with length=%d", this, state_->txn_, data.length());
+  int64_t write_length = static_cast<int64_t>(data.length());
+  if (!write_length) {
+    return 0;
+  }
+
+  if (!state_->output_vio_) {
+    TSVConn output_vconn = TSTransformOutputVConnGet(state_->vconn_);
+    LOG_DEBUG("TransformationPlugin=%p tshttptxn=%p will issue a TSVConnWrite, output_vconn=%p.", this, state_->txn_, output_vconn);
+    if (output_vconn) {
+      // If you're confused about the following reference the traffic server transformation docs.
+      // You always write INT64_MAX, this basically says you're not sure how much data you're going to write
+      state_->output_vio_ = TSVConnWrite(output_vconn, state_->vconn_, state_->output_buffer_reader_, INT64_MAX);
+    } else {
+      LOG_ERROR("TransformationPlugin=%p tshttptxn=%p output_vconn=%p cannot issue TSVConnWrite due to null output vconn.",
+          this, state_->txn_, output_vconn);
+      return 0;
+    }
+
+    if (!state_->output_vio_) {
+      LOG_ERROR("TransformationPlugin=%p tshttptxn=%p state_->output_vio=%p, TSVConnWrite failed.",
+          this, state_->txn_, state_->output_vio_);
+      return 0;
+    }
+  }
+
+  // Finally we can copy this data into the output_buffer
+  int64_t bytes_written = TSIOBufferWrite(state_->output_buffer_, data.c_str(), write_length);
+  state_->bytes_written_ += bytes_written; // So we can set BytesDone on outputComplete().
+  LOG_DEBUG("TransformationPlugin=%p tshttptxn=%p write to TSIOBuffer %d bytes total bytes written %d", this, state_->txn_, bytes_written, state_->bytes_written_);
+
+  // Sanity Checks
+  if (bytes_written != write_length) {
+    LOG_ERROR("TransformationPlugin=%p tshttptxn=%p bytes written < expected. bytes_written=%d write_length=%d", this, state_->txn_, bytes_written, write_length);
+  }
+
+  int connection_closed = TSVConnClosedGet(state_->vconn_);
+  LOG_DEBUG("TransformationPlugin=%p tshttptxn=%p vconn=%p connection_closed=%d", this, state_->txn_, state_->vconn_, connection_closed);
+
+  if (!connection_closed) {
+    TSVIOReenable(state_->output_vio_); // Wake up the downstream vio
+  } else {
+    LOG_ERROR("TransformationPlugin=%p tshttptxn=%p output_vio=%p connection_closed=%d : Couldn't reenable output vio (connection closed).", this, state_->txn_, state_->output_vio_, connection_closed);
+  }
+
+  return static_cast<size_t>(bytes_written);
+}
+
+size_t TransformationPlugin::setOutputComplete() {
+  int connection_closed = TSVConnClosedGet(state_->vconn_);
+  LOG_DEBUG("OutputComplete TransformationPlugin=%p tshttptxn=%p vconn=%p connection_closed=%d, total bytes written=%d", this, state_->txn_, state_->vconn_, connection_closed,state_->bytes_written_);
+
+  if (!connection_closed && !state_->output_vio_) {
+      LOG_DEBUG("TransformationPlugin=%p tshttptxn=%p output complete without writing any data, initiating write of 0 bytes.", this, state_->txn_);
+
+      // We're done without ever outputting anything, to correctly
+      // clean up we'll initiate a write then immeidately set it to 0 bytes done.
+      state_->output_vio_ = TSVConnWrite(TSTransformOutputVConnGet(state_->vconn_), state_->vconn_, state_->output_buffer_reader_, 0);
+
+      if (state_->output_vio_) {
+        TSVIONDoneSet(state_->output_vio_, 0);
+        TSVIOReenable(state_->output_vio_); // Wake up the downstream vio
+      } else {
+        LOG_ERROR("TransformationPlugin=%p tshttptxn=%p unable to reenable output_vio=%p because VConnWrite failed.", this, state_->txn_, state_->output_vio_);
+      }
+
+      return 0;
+  }
+
+  if (!connection_closed) {
+    // So there is a possible race condition here, if we wake up a dead
+    // VIO it can cause a segfault, so we must check that the VCONN is not dead.
+    int connection_closed = TSVConnClosedGet(state_->vconn_);
+    if (!connection_closed) {
+      TSVIONBytesSet(state_->output_vio_, state_->bytes_written_);
+      TSVIOReenable(state_->output_vio_); // Wake up the downstream vio
+    } else {
+      LOG_ERROR("TransformationPlugin=%p tshttptxn=%p unable to reenable output_vio=%p connection was closed=%d.", this, state_->txn_, state_->output_vio_, connection_closed);
+    }
+  } else {
+    LOG_ERROR("TransformationPlugin=%p tshttptxn=%p unable to reenable output_vio=%p connection was closed=%d.", this, state_->txn_, state_->output_vio_, connection_closed);
+  }
+
+  return state_->bytes_written_;
+}

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/src/Url.cc
----------------------------------------------------------------------
diff --git a/lib/atscppapi/src/Url.cc b/lib/atscppapi/src/Url.cc
new file mode 100644
index 0000000..2dce493
--- /dev/null
+++ b/lib/atscppapi/src/Url.cc
@@ -0,0 +1,218 @@
+/**
+  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.
+ */
+
+/**
+ * @file Url.cc
+ */
+#include "atscppapi/Url.h"
+#include <ts/ts.h>
+#include "atscppapi/noncopyable.h"
+#include "InitializableValue.h"
+#include "logging_internal.h"
+
+using namespace atscppapi;
+using std::string;
+
+/**
+ * @private
+ */
+struct atscppapi::UrlState: noncopyable {
+  TSMBuffer hdr_buf_;
+  TSMLoc url_loc_;
+  InitializableValue<string> url_string_;
+  InitializableValue<string> path_;
+  InitializableValue<string> query_;
+  InitializableValue<string> host_;
+  InitializableValue<string> scheme_;
+  InitializableValue<uint16_t> port_;
+  UrlState(TSMBuffer hdr_buf, TSMLoc url_loc) :
+      hdr_buf_(hdr_buf), url_loc_(url_loc) {
+  }
+};
+
+Url::Url() {
+  state_ = new UrlState(static_cast<TSMBuffer>(NULL), static_cast<TSMLoc>(NULL));
+}
+
+Url::Url(void *hdr_buf, void *url_loc) {
+  state_ = new UrlState(static_cast<TSMBuffer>(hdr_buf), static_cast<TSMLoc>(url_loc));
+}
+
+void Url::init(void *hdr_buf, void *url_loc) {
+  state_->hdr_buf_ = static_cast<TSMBuffer>(hdr_buf);
+  state_->url_loc_ = static_cast<TSMLoc>(url_loc);
+}
+
+Url::~Url() {
+  delete state_;
+}
+
+bool inline Url::isInitialized() const {
+  return state_->hdr_buf_ && state_->url_loc_;
+}
+
+void Url::reset() {
+  state_->url_string_.setInitialized(false);
+  state_->path_.setInitialized(false);
+  state_->query_.setInitialized(false);
+  state_->host_.setInitialized(false);
+  state_->scheme_.setInitialized(false);
+  state_->port_.setInitialized(false);
+}
+
+const std::string &Url::getUrlString() const {
+  if (isInitialized() && !state_->url_string_.isInitialized()) {
+    int length;
+    char *memptr = TSUrlStringGet(state_->hdr_buf_, state_->url_loc_, &length);
+    if (memptr && length) {
+      state_->url_string_ = std::string(memptr, length);
+      TSfree(memptr);
+      LOG_DEBUG("Got URL [%s]", state_->url_string_.getValue().c_str());
+    } else {
+      LOG_ERROR("Got null/zero-length URL string; hdr_buf %p, url_loc %p, ptr %p, length %d", state_->hdr_buf_,
+                state_->url_loc_, memptr, length);
+    }
+  }
+  return state_->url_string_;
+}
+
+const std::string &Url::getPath() const {
+  if (isInitialized() && !state_->path_.isInitialized()) {
+    int length;
+    const char *memptr = TSUrlPathGet(state_->hdr_buf_, state_->url_loc_, &length);
+    if (memptr && length) {
+      state_->path_ = std::string(memptr, length);
+    }
+    LOG_DEBUG("Using path [%s]", state_->path_.getValue().c_str());
+  }
+  return state_->path_;
+}
+
+const std::string &Url::getQuery() const {
+  if (isInitialized() && !state_->query_.isInitialized()) {
+    int length;
+    const char *memptr = TSUrlHttpQueryGet(state_->hdr_buf_, state_->url_loc_, &length);
+    if (memptr && length) {
+      state_->query_ = std::string(memptr, length);
+    }
+    LOG_DEBUG("Using query [%s]", state_->query_.getValue().c_str());
+  }
+  return state_->query_;
+}
+
+const std::string &Url::getScheme() const {
+  if (isInitialized() && !state_->scheme_.isInitialized()) {
+    int length;
+    const char *memptr = TSUrlSchemeGet(state_->hdr_buf_, state_->url_loc_, &length);
+    if (memptr && length) {
+      state_->scheme_ = std::string(memptr, length);
+    }
+    LOG_DEBUG("Using scheme [%s]", state_->scheme_.getValue().c_str());
+  }
+  return state_->scheme_;
+}
+
+const std::string &Url::getHost() const {
+  if (isInitialized() && !state_->host_.isInitialized()) {
+    int length;
+    const char *memptr = TSUrlHostGet(state_->hdr_buf_, state_->url_loc_, &length);
+    if (memptr && length) {
+      state_->host_ = std::string(memptr, length);
+    }
+    LOG_DEBUG("Using host [%s]", state_->host_.getValue().c_str());
+  }
+  return state_->host_;
+}
+
+uint16_t Url::getPort() const {
+  if (isInitialized() && !state_->port_.isInitialized()) {
+    state_->port_ = TSUrlPortGet(state_->hdr_buf_, state_->url_loc_);
+    LOG_DEBUG("Got port %d", state_->port_.getValue());
+  }
+  return state_->port_;
+}
+
+void Url::setPath(const std::string &path) {
+  if (!isInitialized()) {
+    LOG_ERROR("Not initialized");
+    return;
+  }
+  state_->url_string_.setInitialized(false);
+  if (TSUrlPathSet(state_->hdr_buf_, state_->url_loc_, path.c_str(), path.length()) == TS_SUCCESS) {
+    state_->path_ = path;
+    LOG_DEBUG("Set path to [%s]", path.c_str());
+  } else {
+    LOG_ERROR("Could not set path; hdr_buf %p, url_loc %p", state_->hdr_buf_, state_->url_loc_);
+  }
+}
+
+void Url::setQuery(const std::string &query) {
+  if (!isInitialized()) {
+    LOG_ERROR("Not initialized");
+    return;
+  }
+  state_->url_string_.setInitialized(false);
+  if (TSUrlHttpQuerySet(state_->hdr_buf_, state_->url_loc_, query.c_str(), query.length()) == TS_SUCCESS) {
+    state_->query_ = query;
+    LOG_DEBUG("Set query to [%s]", query.c_str());
+  } else {
+    LOG_ERROR("Could not set query; hdr_buf %p, url_loc %p", state_->hdr_buf_, state_->url_loc_);
+  }
+}
+
+void Url::setScheme(const std::string &scheme) {
+  if (!isInitialized()) {
+    LOG_ERROR("Not initialized");
+    return;
+  }
+  state_->url_string_.setInitialized(false);
+  if (TSUrlSchemeSet(state_->hdr_buf_, state_->url_loc_, scheme.c_str(), scheme.length()) == TS_SUCCESS) {
+    state_->scheme_ = scheme;
+    LOG_DEBUG("Set scheme to [%s]", scheme.c_str());
+  } else {
+    LOG_ERROR("Could not set scheme; hdr_buf %p, url_loc %p", state_->hdr_buf_, state_->url_loc_);
+  }
+}
+
+void Url::setHost(const std::string &host) {
+  if (!isInitialized()) {
+    LOG_ERROR("Not initialized");
+    return;
+  }
+  state_->url_string_.setInitialized(false);
+  if (TSUrlHostSet(state_->hdr_buf_, state_->url_loc_, host.c_str(), host.length()) == TS_SUCCESS) {
+    state_->host_ = host;
+    LOG_DEBUG("Set host to [%s]", host.c_str());
+  } else {
+    LOG_ERROR("Could not set host; hdr_buf %p, url_loc %p", state_->hdr_buf_, state_->url_loc_);
+  }
+}
+
+void Url::setPort(const uint16_t port) {
+  if (!isInitialized()) {
+    LOG_ERROR("Not initialized");
+    return;
+  }
+  state_->url_string_.setInitialized(false);
+  if (TSUrlPortSet(state_->hdr_buf_, state_->url_loc_, port) == TS_SUCCESS) {
+    state_->port_ = port;
+    LOG_DEBUG("Set port to %d", port);
+  } else {
+    LOG_ERROR("Could not set port; hdr_buf %p, url_loc %p", state_->hdr_buf_, state_->url_loc_);
+  }
+}

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/src/include/InitializableValue.h
----------------------------------------------------------------------
diff --git a/lib/atscppapi/src/include/InitializableValue.h b/lib/atscppapi/src/include/InitializableValue.h
new file mode 100644
index 0000000..8d20320
--- /dev/null
+++ b/lib/atscppapi/src/include/InitializableValue.h
@@ -0,0 +1,90 @@
+/**
+  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.
+ */
+
+/**
+ * @file InitializableValue.h
+ */
+
+#pragma once
+#ifndef ATSCPPAPI_INITIALIZABLEVALUE_H_
+#define ATSCPPAPI_INITIALIZABLEVALUE_H_
+
+namespace atscppapi {
+
+// cannot be static as InitializableValue is a template and a static
+// member of that would be instantiated once for every type the
+// template is instantiated
+extern bool transaction_data_caching_enabled;
+
+/**
+ * @private
+ */
+template <typename Type> class InitializableValue {
+public:
+  InitializableValue() : initialized_(false) { }
+  explicit InitializableValue(Type value, bool initialized = true) : value_(value), initialized_(initialized) { }
+
+  inline void setValue(const Type &value) {
+    value_ = value;
+    initialized_ = true;
+  }
+
+  inline bool isInitialized() const {
+#ifdef DISABLE_TRANSACTION_DATA_CACHING
+    return false;
+#endif
+    return transaction_data_caching_enabled && initialized_;
+  }
+
+  inline Type &getValueRef() {
+    return value_;
+  }
+
+  inline Type getValue() {
+    return value_;
+  }
+
+  inline const Type &getValueRef() const {
+    return value_;
+  }
+
+  inline void setInitialized(bool initialized = true) {
+    initialized_ = initialized;
+  }
+
+  inline operator Type&() {
+    return value_;
+  }
+
+  inline operator const Type&() const {
+    return value_;
+  }
+
+  inline InitializableValue<Type> &operator=(const Type& value) {
+    setValue(value);
+    return *this;
+  }
+
+private:
+  Type value_;
+  bool initialized_;
+};
+
+}
+
+#endif /* ATSCPPAPI_INITIALIZABLEVALUE_H_ */

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/src/include/atscppapi/Async.h
----------------------------------------------------------------------
diff --git a/lib/atscppapi/src/include/atscppapi/Async.h b/lib/atscppapi/src/include/atscppapi/Async.h
new file mode 100644
index 0000000..39a24d0
--- /dev/null
+++ b/lib/atscppapi/src/include/atscppapi/Async.h
@@ -0,0 +1,187 @@
+/**
+  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.
+ */
+
+/**
+ * @file Async.h
+ * @brief Provides constructs to perform async operations.
+ */
+
+#pragma once
+#ifndef ATSCPPAPI_ASYNC_H_
+#define ATSCPPAPI_ASYNC_H_
+#include <list>
+#include <atscppapi/Mutex.h>
+#include <atscppapi/noncopyable.h>
+#include <atscppapi/shared_ptr.h>
+
+namespace atscppapi {
+
+/**
+ * @private
+ *
+ * @brief This class represents the interface of a dispatch controller. A dispatch controller
+ * is used to dispatch an event to a receiver. This interface exists so that the types in this
+ * header file can be defined.
+ */
+class AsyncDispatchControllerBase : noncopyable {
+public:
+  /**
+   * Dispatches an async event to a receiver.
+   *
+   * @return True if the receiver was still alive.
+   */
+  virtual bool dispatch() = 0;
+  virtual ~AsyncDispatchControllerBase() { }
+};
+
+/**
+ * @brief AsyncProvider is the interface that providers of async operations must implement. 
+ * The system allows decoupling of the lifetime/scope of provider and receiver objects. The 
+ * receiver object might have expired before the async operation is complete and the system
+ * handles this case. Because of this decoupling, it is the responsibility of the provider
+ * to manage it's expiration - self-destruct on completion is a good option.
+ */
+class AsyncProvider {
+public:
+  /**
+   * This method is invoked when the async operation is requested. This call should be used
+   * to just start the async operation and *not* block this thread.
+   *
+   * @param dispatch_controller provides a way to dispatch an "async complete" event to the
+   *                            requester.
+   */
+  virtual void run(shared_ptr<AsyncDispatchControllerBase> dispatch_controller) = 0;
+  virtual ~AsyncProvider() { }
+};
+
+/**
+ * @private
+ *
+ * @brief Dispatch controller implementation. When invoking the receiver, it verifies that the
+ * receiver is still alive, locks the mutex and then invokes handleAsyncComplete().
+ */
+template<typename AsyncEventReceiverType, typename AsyncProviderType>
+class AsyncDispatchController : public AsyncDispatchControllerBase {
+public:
+  bool dispatch() {
+    bool ret = false;
+    ScopedSharedMutexLock scopedLock(dispatch_mutex_);
+    if (event_receiver_) {
+      event_receiver_->handleAsyncComplete(static_cast<AsyncProviderType &>(*provider_));
+      ret = true;
+    }
+    return ret;
+  }
+
+  /**
+   * Constructor
+   *
+   * @param event_receiver The async complete event will be dispatched to this receiver.
+   * @param provider Async operation provider that is passed to the receiver on dispatch.
+   * @param mutex Mutex of the receiver that is locked during the dispatch
+   */
+  AsyncDispatchController(AsyncEventReceiverType *event_receiver, AsyncProviderType *provider, shared_ptr<Mutex> mutex) :
+    event_receiver_(event_receiver), dispatch_mutex_(mutex), provider_(provider) {
+  }
+
+  virtual ~AsyncDispatchController() { }
+public:
+  AsyncEventReceiverType *event_receiver_;
+  shared_ptr<Mutex> dispatch_mutex_;
+private:
+  AsyncProviderType *provider_;
+};
+
+/**
+ * @private
+ * 
+ * @brief A promise is used to let the dispatch controller know if the receiver is still
+ * alive to receive the async complete dispatch. When the receiver dies, this promise is
+ * broken and it automatically updates the dispatch controller.
+ */
+template<typename AsyncEventReceiverType, typename AsyncProviderType>
+class AsyncReceiverPromise : noncopyable {
+public:
+  AsyncReceiverPromise(shared_ptr<AsyncDispatchController<AsyncEventReceiverType, AsyncProviderType> > dispatch_controller) :
+    dispatch_controller_(dispatch_controller) { }
+
+  ~AsyncReceiverPromise() {
+    ScopedSharedMutexLock scopedLock(dispatch_controller_->dispatch_mutex_);
+    dispatch_controller_->event_receiver_ = NULL;
+  }
+protected:
+  shared_ptr<AsyncDispatchController<AsyncEventReceiverType, AsyncProviderType> > dispatch_controller_;
+};
+
+/**
+ * @brief AsyncReceiver is the interface that receivers of async operations must implement. It is
+ * templated on the type of the async operation provider.
+ */
+template<typename AsyncProviderType>
+class AsyncReceiver : noncopyable {
+public:
+  /**
+   * This method is invoked when the async operation is completed. The
+   * mutex provided during the creation of the async operation will be
+   * automatically locked during the invocation of this method.
+   *
+   * @param provider A reference to the provider which completed the async operation.
+   */
+  virtual void handleAsyncComplete(AsyncProviderType &provider) = 0;
+  virtual ~AsyncReceiver() { }
+protected:
+  AsyncReceiver() { }
+  friend class Async;
+private:
+  mutable std::list<shared_ptr<AsyncReceiverPromise<AsyncReceiver<AsyncProviderType>, AsyncProviderType> > > receiver_promises_;
+};
+
+/**
+ * @brief This class provides a method to create an async operation.
+ */
+class Async : noncopyable {
+public:
+  /**
+   * This method sets up the dispatch controller to link the async operation provider and 
+   * receiver and then initiates the operation by invoking the provider. 
+   *
+   * @param event_receiver The receiver of the async complete dispatch.
+   * @param provider The provider of the async operation.
+   * @param mutex The mutex that is locked during the dispatch of the async event complete.
+   *              One will be created if nothing is passed in. Transaction plugins should use 
+   *              TransactionPlugin::getMutex() here and global plugins can pass an appropriate
+   *              or NULL mutex.
+   */
+  template<typename AsyncProviderType>
+  static void execute(AsyncReceiver<AsyncProviderType> *event_receiver, AsyncProviderType *provider, shared_ptr<Mutex> mutex) {
+    if (!mutex.get()) {
+      mutex.reset(new Mutex(Mutex::TYPE_RECURSIVE));
+    }
+    shared_ptr<AsyncDispatchController<AsyncReceiver<AsyncProviderType>, AsyncProviderType > > dispatcher(
+      new AsyncDispatchController<AsyncReceiver<AsyncProviderType>, AsyncProviderType >(event_receiver, provider, mutex));
+    shared_ptr<AsyncReceiverPromise<AsyncReceiver<AsyncProviderType>, AsyncProviderType > > receiver_promise(
+      new AsyncReceiverPromise<AsyncReceiver<AsyncProviderType>, AsyncProviderType >(dispatcher));
+    event_receiver->receiver_promises_.push_back(receiver_promise); // now if the event receiver dies, we're safe.
+    provider->run(dispatcher);
+  }
+};
+
+}
+
+
+#endif /* ATSCPPAPI_ASYNC_H_ */

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/src/include/atscppapi/AsyncHttpFetch.h
----------------------------------------------------------------------
diff --git a/lib/atscppapi/src/include/atscppapi/AsyncHttpFetch.h b/lib/atscppapi/src/include/atscppapi/AsyncHttpFetch.h
new file mode 100644
index 0000000..cb05ca6
--- /dev/null
+++ b/lib/atscppapi/src/include/atscppapi/AsyncHttpFetch.h
@@ -0,0 +1,102 @@
+/**
+  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.
+ */
+
+/**
+ * @file AsyncHttpFetch.h
+ */
+
+#pragma once
+#ifndef ATSCPPAPI_ASYNCHTTPFETCH_H_
+#define ATSCPPAPI_ASYNCHTTPFETCH_H_
+
+#include <string>
+#include <atscppapi/shared_ptr.h>
+#include <atscppapi/Async.h>
+#include <atscppapi/Request.h>
+#include <atscppapi/Response.h>
+
+namespace atscppapi {
+
+// forward declarations
+class AsyncHttpFetchState;
+namespace utils { class internal; }
+
+/**
+ * @brief This class provides an implementation of AsyncProvider that
+ * makes HTTP requests asynchronously. This provider automatically
+ * self-destructs after the completion of the request.
+ *
+ * See example async_http_fetch for sample usage.
+ */
+class AsyncHttpFetch : public AsyncProvider {
+public:
+  AsyncHttpFetch(const std::string &url_str, HttpMethod http_method = HTTP_METHOD_GET);
+
+  /**
+   * Used to manipulate the headers of the request to be made.
+   *
+   * @return A reference to mutable headers.
+   */
+  Headers &getRequestHeaders();
+
+  enum Result { RESULT_SUCCESS = 10000, RESULT_TIMEOUT, RESULT_FAILURE };
+
+  /**
+   * Used to extract the response after request completion. 
+   *
+   * @return Result of the operation
+   */
+  Result getResult() const;
+
+  /**
+   * @return Non-mutable reference to the request URL.
+   */
+  const Url &getRequestUrl() const;
+
+  /**
+   * Used to extract the response after request completion. 
+   *
+   * @return Non-mutable reference to the response.
+   */
+  const Response &getResponse() const;
+
+  /**
+   * Used to extract the body of the response after request completion. On
+   * unsuccessful completion, values (NULL, 0) are set.
+   *
+   * @param body Output argument; will point to the body
+   * @param body_size Output argument; will contain the size of the body 
+   * 
+   */
+  void getResponseBody(const void *&body, size_t &body_size) const;
+
+  virtual ~AsyncHttpFetch();
+
+  /**
+   * Starts a HTTP fetch of the Request contained.
+   */  
+  virtual void run(shared_ptr<AsyncDispatchControllerBase> dispatch_controller);
+
+private:
+  AsyncHttpFetchState *state_;
+  friend class utils::internal;
+};
+
+} /* atscppapi */
+
+#endif /* ATSCPPAPI_ASYNCHTTPFETCH_H_ */

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/src/include/atscppapi/AsyncTimer.h
----------------------------------------------------------------------
diff --git a/lib/atscppapi/src/include/atscppapi/AsyncTimer.h b/lib/atscppapi/src/include/atscppapi/AsyncTimer.h
new file mode 100644
index 0000000..b076eda
--- /dev/null
+++ b/lib/atscppapi/src/include/atscppapi/AsyncTimer.h
@@ -0,0 +1,78 @@
+/**
+  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.
+ */
+
+/**
+ * @file AsyncTimer.h
+ */
+
+#pragma once
+#ifndef ATSCPPAPI_ASYNCTIMER_H_
+#define ATSCPPAPI_ASYNCTIMER_H_
+
+#include <string>
+#include <atscppapi/shared_ptr.h>
+#include <atscppapi/Async.h>
+#include <atscppapi/Request.h>
+#include <atscppapi/Response.h>
+
+namespace atscppapi {
+
+// forward declarations
+class AsyncTimerState;
+
+/**
+ * @brief This class provides an implementation of AsyncProvider that
+ * acts as a timer. It sends events at the set frequency. Calling the
+ * destructor will stop the events. A one-off timer just sends one
+ * event. Calling the destructor before this event will cancel the timer.
+ * 
+ * For either type, user must delete the timer.
+ *
+ * See example async_timer for sample usage.
+ */
+class AsyncTimer : public AsyncProvider {
+public:
+
+  enum Type { TYPE_ONE_OFF = 0, TYPE_PERIODIC };
+
+  /**
+   * Constructor.
+   * 
+   * @param type A one-off timer fires only once and a periodic timer fires periodically.
+   * @param period_in_ms The receiver will receive an event every this many milliseconds.
+   * @param initial_period_in_ms The first event will arrive after this many milliseconds. Subsequent
+   *                             events will have "regular" cadence. This is useful if the timer is
+   *                             set for a long period of time (1hr etc.), but an initial event is
+   *                             required. Value of 0 (default) indicates no initial event is desired.
+   */
+  AsyncTimer(Type type, int period_in_ms, int initial_period_in_ms = 0);
+
+  ~AsyncTimer();
+
+  /**
+   * Starts the timer.
+   */  
+  void run(shared_ptr<AsyncDispatchControllerBase> dispatch_controller);
+
+private:
+  AsyncTimerState *state_;
+};
+
+} /* atscppapi */
+
+#endif /* ATSCPPAPI_ASYNCTIMER_H_ */

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/src/include/atscppapi/CaseInsensitiveStringComparator.h
----------------------------------------------------------------------
diff --git a/lib/atscppapi/src/include/atscppapi/CaseInsensitiveStringComparator.h b/lib/atscppapi/src/include/atscppapi/CaseInsensitiveStringComparator.h
new file mode 100644
index 0000000..a47462a
--- /dev/null
+++ b/lib/atscppapi/src/include/atscppapi/CaseInsensitiveStringComparator.h
@@ -0,0 +1,51 @@
+/**
+  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.
+ */
+/**
+ * @file CaseInsensitiveStringComparator.h
+ * @brief A case insensitive comparator that can be used with STL containers.
+ */
+
+#pragma once
+#ifndef ATSCPPAPI_CASE_INSENSITIVE_STRING_COMPARATOR_H_
+#define ATSCPPAPI_CASE_INSENSITIVE_STRING_COMPARATOR_H_
+
+#include <string>
+
+namespace atscppapi {
+
+/**
+ * @brief A case insensitive comparator that can be used with standard library containers.
+ *
+ * The primary use for this class is to make all Headers case insensitive.
+ */
+class CaseInsensitiveStringComparator {
+public:
+  /**
+   * @return true if lhs is lexicographically "less-than" rhs; meant for use in std::map or other standard library containers.
+   */
+  bool operator()(const std::string &lhs, const std::string &rhs) const;
+
+  /**
+   * @return numerical value of lexicographical comparison a la strcmp
+   */
+  int compare(const std::string &lhs, const std::string &rhs) const;
+};
+
+}
+
+#endif


[2/5] initial atscppapi commit

Posted by br...@apache.org.
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/src/include/atscppapi/ClientRequest.h
----------------------------------------------------------------------
diff --git a/lib/atscppapi/src/include/atscppapi/ClientRequest.h b/lib/atscppapi/src/include/atscppapi/ClientRequest.h
new file mode 100644
index 0000000..2da61c5
--- /dev/null
+++ b/lib/atscppapi/src/include/atscppapi/ClientRequest.h
@@ -0,0 +1,59 @@
+/**
+  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.
+ */
+
+/**
+ * @file ClientRequest.h
+ */
+
+#pragma once
+#ifndef ATSCPPAPI_CLIENTREQUEST_H_
+#define ATSCPPAPI_CLIENTREQUEST_H_
+
+#include <atscppapi/Request.h>
+
+namespace atscppapi {
+
+struct ClientRequestState;
+
+/**
+ * @brief Encapsulates a client request. A client request is different from a
+ * server request as it has two URLs - the pristine URL sent by the client 
+ * and a remapped URL created by the server.
+ */
+class ClientRequest : public Request {
+public:
+  /**
+   * @private
+   */
+  ClientRequest(void *raw_txn, void *hdr_buf, void *hdr_loc);
+
+  /**
+   * Returns the pristine (pre-remap) client request URL 
+   *
+   * @return Url Reference to non-mutable pristine URL.
+   */
+  const Url &getPristineUrl() const;
+
+  ~ClientRequest();
+private:
+  ClientRequestState *state_;
+};
+
+}
+
+#endif /* ATSCPPAPI_CLIENTREQUEST_H_ */

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/src/include/atscppapi/GlobalPlugin.h
----------------------------------------------------------------------
diff --git a/lib/atscppapi/src/include/atscppapi/GlobalPlugin.h b/lib/atscppapi/src/include/atscppapi/GlobalPlugin.h
new file mode 100644
index 0000000..cff431d
--- /dev/null
+++ b/lib/atscppapi/src/include/atscppapi/GlobalPlugin.h
@@ -0,0 +1,90 @@
+/**
+  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.
+ */
+
+/**
+ * @file GlobalPlugin.h
+ * @brief Contains the interface used in creating Global plugins.
+ */
+
+#pragma once
+#ifndef ATSCPPAPI_GLOBALPLUGIN_H_
+#define ATSCPPAPI_GLOBALPLUGIN_H_
+
+#include <atscppapi/Plugin.h>
+
+namespace atscppapi {
+
+class GlobalPluginState;
+
+/**
+ * @brief The interface used when creating a GlobalPlugin.
+ *
+ * A GlobalPlugin is a Plugin that will fire for a given hook on all Transactions.
+ * In otherwords, a GlobalPlugin is not tied to a specific plugin, a Transaction
+ * specific plugin would be a TransactionPlugin.
+ *
+ * Depending on the
+ * type of hook you choose to build you will implement one or more callback methods.
+ * Here is a simple example of a GlobalPlugin:
+ *
+ * \code
+ * class GlobalHookPlugin : public GlobalPlugin {
+ * public:
+ *  GlobalHookPlugin() {
+ *   registerHook(HOOK_READ_REQUEST_HEADERS_PRE_REMAP);
+ *  }
+ *  virtual void handleReadRequestHeadersPreRemap(Transaction &transaction) {
+ *    std::cout << "Hello from handleReadRequesHeadersPreRemap!" << std::endl;
+ *    transaction.resume();
+ *  }
+ * };
+ * \endcode
+ * @see Plugin
+ */
+class GlobalPlugin : public Plugin {
+public:
+  /**
+   * registerHook is the mechanism used to attach a global hook.
+   *
+   * \note Whenever you register a hook you must have the appropriate callback definied in your GlobalPlugin
+   *  see HookType and Plugin for the correspond HookTypes and callback methods. If you fail to implement the
+   *  callback, a default implmentation will be used that will only resume the Transaction.
+   *
+   * @param HookType the type of hook you wish to register
+   * @see HookType
+   * @see Plugin
+   */
+  void registerHook(Plugin::HookType);
+  virtual ~GlobalPlugin();
+protected:
+  /**
+   * Constructor.
+   *
+   * @param ignore_internal_transactions When true, all hooks registered by this plugin are ignored
+   *                                     for internal transactions (internal transactions are created
+   *                                     when other plugins create requests). Defaults to false.
+   */
+  GlobalPlugin(bool ignore_internal_transactions = false);
+private:
+  GlobalPluginState *state_; /**< Internal state tied to a GlobalPlugin */
+};
+
+} /* atscppapi */
+
+
+#endif /* ATSCPPAPI_GLOBALPLUGIN_H_ */

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/src/include/atscppapi/GzipDeflateTransformation.h
----------------------------------------------------------------------
diff --git a/lib/atscppapi/src/include/atscppapi/GzipDeflateTransformation.h b/lib/atscppapi/src/include/atscppapi/GzipDeflateTransformation.h
new file mode 100644
index 0000000..a7e6923
--- /dev/null
+++ b/lib/atscppapi/src/include/atscppapi/GzipDeflateTransformation.h
@@ -0,0 +1,91 @@
+/**
+  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.
+ */
+
+/**
+ * @file GzipDeflateTransformation.h
+ * @brief Gzip Deflate Transformation can be used to compress content.
+ */
+
+#pragma once
+#ifndef ATSCPPAPI_GZIPDEFLATETRANSFORMATION_H_
+#define ATSCPPAPI_GZIPDEFLATETRANSFORMATION_H_
+
+#include <string>
+#include "atscppapi/TransformationPlugin.h"
+
+namespace atscppapi {
+
+namespace transformations {
+
+/**
+ * Internal state for Deflate Transformations
+ * @private
+ */
+class GzipDeflateTransformationState;
+
+/**
+ * @brief A TransformationPlugin to easily add gzip deflate to your TransformationPlugin chain.
+ *
+ * The GzipDeflateTransformation is a helper transformation that can be used
+ * to easily compress content. For a full example of GzipDeflateTransformation
+ * and GzipInflateTransformation see examples/gzip_transformation/.
+ *
+ * @note GzipDeflateTransformation DOES NOT set Content-Encoding headers, it is the
+ * users responsibility to set any applicable headers.
+ *
+ * @see GzipInflateTransformation
+ */
+class GzipDeflateTransformation : public TransformationPlugin {
+public:
+  /**
+   * A full example of how to use GzipDeflateTransformation and GzipInflateTransformation is available
+   * in examples/gzip_tranformation/
+   *
+   * @param transaction As with any TransformationPlugin you must pass in the transaction
+   * @param type because the GzipDeflateTransformation can be used with both requests and responses
+   *  you must specify the Type.
+   *
+   * @see TransformationPlugin::Type
+   */
+  GzipDeflateTransformation(Transaction &transaction, TransformationPlugin::Type type);
+
+  /**
+   * Any TransformationPlugin must implement consume(), this method will take content
+   * from the transformation chain and gzip compress it.
+   *
+   * @param data the input data to compress
+   */
+  void consume(const std::string &data);
+
+  /**
+   * Any TransformationPlugin must implement handleInputComplete(), this method will
+   * finalize the gzip compression and flush any remaining data and the epilouge.
+   */
+  void handleInputComplete();
+
+  virtual ~GzipDeflateTransformation();
+private:
+  GzipDeflateTransformationState *state_; /** Internal state for Gzip Deflate Transformations */
+};
+
+}
+
+}
+
+
+#endif /* ATSCPPAPI_GZIPDEFLATETRANSFORMATION_H_ */

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/src/include/atscppapi/GzipInflateTransformation.h
----------------------------------------------------------------------
diff --git a/lib/atscppapi/src/include/atscppapi/GzipInflateTransformation.h b/lib/atscppapi/src/include/atscppapi/GzipInflateTransformation.h
new file mode 100644
index 0000000..412af91
--- /dev/null
+++ b/lib/atscppapi/src/include/atscppapi/GzipInflateTransformation.h
@@ -0,0 +1,92 @@
+/**
+  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.
+ */
+
+/**
+ * @file GzipInflateTransformation.h
+ * @brief Gzip Inflate Transformation can be used to decompress gzipped content.
+ */
+
+#pragma once
+#ifndef ATSCPPAPI_GZIPINFLATETRANSFORMATION_H_
+#define ATSCPPAPI_GZIPINFLATETRANSFORMATION_H_
+
+#include <string>
+#include "atscppapi/TransformationPlugin.h"
+
+namespace atscppapi {
+
+namespace transformations {
+
+/**
+ * Internal state for Inflate Transformations
+ * @private
+ */
+class GzipInflateTransformationState;
+
+/**
+ * @brief A TransformationPlugin to easily add gzip inflate to your TransformationPlugin chain.
+ *
+ * The GzipInflateTransformation is a helper transformation that can be used
+ * to easily decompress gzipped content. For a full example of GzipInflateTransformation
+ * and GzipDeflateTransformation see examples/gzip_transformation/.
+ *
+ * @note GzipDeflateTransformation DOES NOT set or check Content-Encoding headers, it is the
+ * users responsibility to set any applicable headers and check that the content is acctually
+ * gzipped by checking the Content-Encoding header before creating a GzipInflateTransformation,
+ * see examples/gzip_transformation/ for a full example.
+ *
+ * @see GzipDeflateTransformation
+ */
+class GzipInflateTransformation : public TransformationPlugin {
+public:
+  /**
+   * A full example of how to use GzipInflateTransformation and GzipDeflateTransformation is available
+   * in examples/gzip_tranformation/
+   *
+   * @param transaction As with any TransformationPlugin you must pass in the transaction
+   * @param type because the GzipInflateTransformation can be used with both requests and responses
+   *  you must specify the Type.
+   *
+   * @see TransformationPlugin::Type
+   */
+  GzipInflateTransformation(Transaction &transaction, TransformationPlugin::Type type);
+
+  /**
+   * Any TransformationPlugin must implement consume(), this method will take content
+   * from the transformation chain and gzip decompress it.
+   *
+   * @param data the input data to decompress
+   */
+  void consume(const std::string &);
+
+  /**
+   * Any TransformationPlugin must implement handleInputComplete(), this method will
+   * finalize the gzip decompression.
+   */
+  void handleInputComplete();
+
+  virtual ~GzipInflateTransformation();
+private:
+  GzipInflateTransformationState *state_; /** Internal state for Gzip Deflate Transformations */
+};
+
+} /* transformations */
+
+} /* atscppapi */
+
+#endif /* ATSCPPAPI_GZIPINFLATETRANSFORMATION_H_ */

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/src/include/atscppapi/Headers.h
----------------------------------------------------------------------
diff --git a/lib/atscppapi/src/include/atscppapi/Headers.h b/lib/atscppapi/src/include/atscppapi/Headers.h
new file mode 100644
index 0000000..af02707
--- /dev/null
+++ b/lib/atscppapi/src/include/atscppapi/Headers.h
@@ -0,0 +1,246 @@
+/**
+  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.
+ */
+
+/**
+ * @file Headers.h
+ */
+
+#pragma once
+#ifndef ATSCPPAPI_HEADERS_H_
+#define ATSCPPAPI_HEADERS_H_
+
+#include <map>
+#include <list>
+#include <atscppapi/CaseInsensitiveStringComparator.h>
+#include <atscppapi/noncopyable.h>
+
+namespace atscppapi {
+
+struct HeadersState;
+class Request;
+class ClientRequest;
+class Response;
+
+/**
+ * @brief Encapsulates the headers portion of a request or response.
+ */
+class Headers: noncopyable {
+public:
+  
+  enum Type { TYPE_REQUEST, TYPE_RESPONSE };
+
+  Headers(Type type = TYPE_REQUEST);
+
+  Type getType() const;
+
+  typedef std::map<std::string, std::list<std::string>, CaseInsensitiveStringComparator> NameValuesMap;
+
+  typedef NameValuesMap::size_type size_type;
+  typedef NameValuesMap::const_iterator const_iterator;
+  typedef NameValuesMap::const_reverse_iterator const_reverse_iterator;
+
+  /**
+   * @return Iterator to first header.
+   */
+  const_iterator begin() const;
+
+  /**
+   * @return Iterator to end of headers.
+   */
+  const_iterator end() const;
+
+  /**
+   * @return Iterator to last header.
+   */
+  const_reverse_iterator rbegin() const;
+
+  /**
+   * @return Iterator to "reverse end"
+   */
+  const_reverse_iterator rend() const;
+
+  /**
+   * @param key Name of header
+   * @return Iterator to header if exists, else end()
+   */
+  const_iterator find(const std::string &key) const;
+
+  /**
+   * @param key Name of header
+   * @return 1 if header exists, 0 if not. 
+   */
+  size_type count(const std::string &key) const;
+
+  /**
+   * Erases header with given name.
+   *
+   * @param key Name of header
+   * @return 1 if header was erased, 0 if not. 
+   */
+  size_type erase(const std::string &key);
+
+  /**
+   * Sets the given header and values. If a header of same name existed, that is
+   * deleted. Else header is appended.
+   * 
+   * @param pair Contains the name and list of values.
+   *
+   * @return Iterator to header set. 
+   */
+  const_iterator set(const std::pair<std::string, std::list<std::string> > &pair);
+
+  /**
+   * Sets the given header and values. If a header of same name existed, that is
+   * deleted. Else header is appended.
+   *
+   * @param key Name of header
+   * @param val List of values
+   * 
+   * @return Iterator to header set. 
+   */
+  const_iterator set(const std::string &key, const std::list<std::string> &val);
+
+  /**
+   * Sets the given header and values. If a header of same name existed, that is
+   * deleted. Else header is appended.
+   *
+   * @param key Name of header
+   * @param val Value
+   * 
+   * @return Iterator to header set. 
+   */
+  const_iterator set(const std::string &key, const std::string &val);
+
+  /**
+   * Appends a new header. If a header of the same name exists, value(s) is tacked
+   * on that the end of current value(s). 
+   * 
+   * @param pair Contains the name and list of values.
+   *
+   * @return Iterator to header appended. 
+   */
+  const_iterator append(const std::pair<std::string, std::list<std::string> > &pair);
+
+  /**
+   * Appends a new header. If a header of the same name exists, value(s) is tacked
+   * on that the end of current value(s). 
+   * 
+   * @param key Name of header
+   * @param val List of values
+   * 
+   * @return Iterator to header appended. 
+   */
+  const_iterator append(const std::string &key, const std::list<std::string> &val);
+
+  /**
+   * Appends a new header. If a header of the same name exists, value(s) is tacked
+   * on that the end of current value(s). 
+   * 
+   * @param key Name of header
+   * @param val Value
+   * 
+   * @return Iterator to header appended. 
+   */
+  const_iterator append(const std::string &key, const std::string &val);
+
+  /**
+   * Joins provided list of values with delimiter (defaulting to ',').
+   *
+   * @return Composite string
+   */
+  static std::string getJoinedValues(const std::list<std::string> &values, char delimiter = ',');
+
+  /**
+   * Joins values of provided header with delimiter (defaulting to ',').
+   *
+   * @return Composite string if header exists, else empty strings.
+   */
+  std::string getJoinedValues(const std::string &key, char value_delimiter = ',');
+
+  /**
+   * @return True if there are no headers.
+   */
+  bool empty() const;
+
+  /**
+   * @return Largest possible size of underlying map.
+   */
+  size_type max_size() const;
+
+  /**
+   * @return Number of headers currently stored.
+   */
+  size_type size() const;
+
+  typedef std::map<std::string, std::list<std::string> > RequestCookieMap;
+
+  /**
+   * @return Cookies in the "Cookie" headers of a request object.
+   */
+  const RequestCookieMap &getRequestCookies() const;
+
+  struct ResponseCookie {
+    std::string name_;
+    std::string value_;
+    std::string comment_;
+    std::string domain_;
+    int max_age_;
+    std::string path_;
+    bool secure_;
+    int version_;
+    ResponseCookie() : max_age_(0), secure_(false), version_(0) { };
+  };
+
+  /**
+   * @return Cookies in the "Set-Cookie" headers of a response object.
+   */
+  const std::list<ResponseCookie> &getResponseCookies() const;
+
+  /** Adds a request cookie */
+  bool addCookie(const std::string &name, const std::string &value);
+
+  /** Adds a response cookie */
+  bool addCookie(const ResponseCookie &response_cookie);
+  
+  /** Sets, i.e., clears current value and adds new value, of a request cookie */
+  bool setCookie(const std::string &name, const std::string &value);
+
+  /** Sets, i.e., clears current value and adds new value, of a response cookie */
+  bool setCookie(const ResponseCookie &response_cookie);
+
+  /** Deletes a cookie */
+  bool deleteCookie(const std::string &name);
+
+  ~Headers();
+private:
+  HeadersState *state_;
+  bool checkAndInitHeaders() const;
+  void init(void *hdr_buf, void *hdr_loc);
+  void initDetached();
+  void setType(Type type);
+  void updateRequestCookieHeaderFromMap();
+  const_iterator doBasicAppend(const std::pair<std::string, std::list<std::string> > &pair);
+  size_type doBasicErase(const std::string &key);
+  friend class Request;
+  friend class ClientRequest;
+  friend class Response;
+};
+
+}
+
+#endif

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/src/include/atscppapi/HttpMethod.h
----------------------------------------------------------------------
diff --git a/lib/atscppapi/src/include/atscppapi/HttpMethod.h b/lib/atscppapi/src/include/atscppapi/HttpMethod.h
new file mode 100644
index 0000000..c07c673
--- /dev/null
+++ b/lib/atscppapi/src/include/atscppapi/HttpMethod.h
@@ -0,0 +1,58 @@
+/**
+  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.
+ */
+
+/**
+ * @file HttpMethod.h
+ * @brief Contains an enumeration and printable strings for Http Methods.
+ */
+#pragma once
+#ifndef ATSCPPAPI_HTTP_METHOD_H_
+#define ATSCPPAPI_HTTP_METHOD_H_
+
+#include <string>
+
+namespace atscppapi {
+
+/**
+ * An enumeration of all available Http Methods.
+ */
+enum HttpMethod {
+  HTTP_METHOD_UNKNOWN = 0,
+  HTTP_METHOD_GET,
+  HTTP_METHOD_POST,
+  HTTP_METHOD_HEAD,
+  HTTP_METHOD_CONNECT,
+  HTTP_METHOD_DELETE,
+  HTTP_METHOD_ICP_QUERY,
+  HTTP_METHOD_OPTIONS,
+  HTTP_METHOD_PURGE,
+  HTTP_METHOD_PUT,
+  HTTP_METHOD_TRACE
+};
+
+/**
+ * An array of printable strings representing of the HttpMethod
+ * \code
+ * cout << HTTP_METHOD_STRINGS[HTTP_METHOD_GET] << endl;
+ * \endcode
+ */
+extern const std::string HTTP_METHOD_STRINGS[];
+
+}
+
+#endif

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/src/include/atscppapi/HttpStatus.h
----------------------------------------------------------------------
diff --git a/lib/atscppapi/src/include/atscppapi/HttpStatus.h b/lib/atscppapi/src/include/atscppapi/HttpStatus.h
new file mode 100644
index 0000000..e1ba25b
--- /dev/null
+++ b/lib/atscppapi/src/include/atscppapi/HttpStatus.h
@@ -0,0 +1,104 @@
+/**
+  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.
+ */
+
+/**
+ * @file HttpStatus.h
+ * @brief Contains an enumeration and printable strings for Http Status codes.
+ */
+
+#pragma once
+#ifndef ATSCPPAPI_HTTP_STATUS_H_
+#define ATSCPPAPI_HTTP_STATUS_H_
+
+#include <string>
+
+namespace atscppapi {
+
+/**
+ * An enumeration of all available Http Status Codes.
+ */
+enum HttpStatus
+{
+  HTTP_STATUS_UNKNOWN = 0,
+
+  HTTP_STATUS_CONTINUE = 100,
+  HTTP_STATUS_SWITCHING_PROTOCOL = 101,
+
+  HTTP_STATUS_OK = 200,
+  HTTP_STATUS_CREATED = 201,
+  HTTP_STATUS_ACCEPTED = 202,
+  HTTP_STATUS_NON_AUTHORITATIVE_INFORMATION = 203,
+  HTTP_STATUS_NO_CONTENT = 204,
+  HTTP_STATUS_RESET_CONTENT = 205,
+  HTTP_STATUS_PARTIAL_CONTENT = 206,
+  HTTP_STATUS_MULTI_STATUS = 207,
+  HTTP_STATUS_ALREADY_REPORTED = 208,
+  HTTP_STATUS_IM_USED = 211,
+
+  HTTP_STATUS_MULTIPLE_CHOICES = 300,
+  HTTP_STATUS_MOVED_PERMANENTLY = 301,
+  HTTP_STATUS_MOVED_TEMPORARILY = 302,
+  HTTP_STATUS_SEE_OTHER = 303,
+  HTTP_STATUS_NOT_MODIFIED = 304,
+  HTTP_STATUS_USE_PROXY = 305,
+  HTTP_STATUS_TEMPORARY_REDIRECT = 307,
+  HTTP_STATUS_PERMANENT_REDIRECT = 308,
+
+  HTTP_STATUS_BAD_REQUEST = 400,
+  HTTP_STATUS_UNAUTHORIZED = 401,
+  HTTP_STATUS_PAYMENT_REQUIRED = 402,
+  HTTP_STATUS_FORBIDDEN = 403,
+  HTTP_STATUS_NOT_FOUND = 404,
+  HTTP_STATUS_METHOD_NOT_ALLOWED = 405,
+  HTTP_STATUS_NOT_ACCEPTABLE = 406,
+  HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED = 407,
+  HTTP_STATUS_REQUEST_TIMEOUT = 408,
+  HTTP_STATUS_CONFLICT = 409,
+  HTTP_STATUS_GONE = 410,
+  HTTP_STATUS_LENGTH_REQUIRED = 411,
+  HTTP_STATUS_PRECONDITION_FAILED = 412,
+  HTTP_STATUS_REQUEST_ENTITY_TOO_LARGE = 413,
+  HTTP_STATUS_REQUEST_URI_TOO_LONG = 414,
+  HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE = 415,
+  HTTP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE = 416,
+  HTTP_STATUS_EXPECTATION_FAILED = 417,
+  HTTP_STATUS_UNPROCESSABLE_ENTITY = 422,
+  HTTP_STATUS_LOCKED = 423,
+  HTTP_STATUS_FAILED_DEPENDENCY = 424,
+  HTTP_STATUS_UPGRADE_REQUIRED = 426,
+  HTTP_STATUS_PRECONDITION_REQUIRED = 428,
+  HTTP_STATUS_TOO_MANY_REQUESTS = 429,
+  HTTP_STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE = 431,
+
+  HTTP_STATUS_INTERNAL_SERVER_ERROR = 500,
+  HTTP_STATUS_NOT_IMPLEMENTED = 501,
+  HTTP_STATUS_BAD_GATEWAY = 502,
+  HTTP_STATUS_SERVICE_UNAVAILABLE = 503,
+  HTTP_STATUS_GATEWAY_TIMEOUT = 504,
+  HTTP_STATUS_HTTPVER_NOT_SUPPORTED = 505,
+  HTTP_STATUS_VARIANT_ALSO_NEGOTIATES = 506,
+  HTTP_STATUS_INSUFFICIENT_STORAGE = 507,
+  HTTP_STATUS_LOOP_DETECTED = 508,
+  HTTP_STATUS_NOT_EXTENDED = 510,
+  HTTP_STATUS_NETWORK_AUTHENTICATION_REQUIRED = 511
+
+};
+
+}
+
+#endif

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/src/include/atscppapi/HttpVersion.h
----------------------------------------------------------------------
diff --git a/lib/atscppapi/src/include/atscppapi/HttpVersion.h b/lib/atscppapi/src/include/atscppapi/HttpVersion.h
new file mode 100644
index 0000000..fdbd639
--- /dev/null
+++ b/lib/atscppapi/src/include/atscppapi/HttpVersion.h
@@ -0,0 +1,52 @@
+/**
+  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.
+ */
+
+/**
+ * @file HttpVersion.h
+ * @brief Contains an enumeration and printable strings for Http Versions.
+ */
+
+#pragma once
+#ifndef ATSCPPAPI_HTTP_VERSION_H_
+#define ATSCPPAPI_HTTP_VERSION_H_
+
+#include <string>
+
+namespace atscppapi {
+
+/**
+ * An enumeration of all available Http Versions.
+ */
+enum HttpVersion {
+  HTTP_VERSION_UNKNOWN = 0,
+  HTTP_VERSION_0_9,
+  HTTP_VERSION_1_0,
+  HTTP_VERSION_1_1,
+};
+
+/**
+ * An array of printable strings representing of the HttpVersion
+ * \code
+ * cout << HTTP_VERSION_STRINGS[HTTP_VERSION_1_1] << endl;
+ * \endcode
+ */
+extern const std::string HTTP_VERSION_STRINGS[];
+
+}
+
+#endif

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/src/include/atscppapi/Logger.h
----------------------------------------------------------------------
diff --git a/lib/atscppapi/src/include/atscppapi/Logger.h b/lib/atscppapi/src/include/atscppapi/Logger.h
new file mode 100644
index 0000000..ef6e3a6
--- /dev/null
+++ b/lib/atscppapi/src/include/atscppapi/Logger.h
@@ -0,0 +1,268 @@
+/**
+  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.
+ */
+
+/**
+ * @file Logger.h
+ * @brief Helpers and Classes related to Logging
+ *
+ * @warning Log rolling doesn't work correctly in 3.2.x see:
+ *   https://issues.apache.org/jira/browse/TS-1813
+ *   Apply the patch in TS-1813 to correct log rolling in 3.2.x
+ *
+ */
+
+#pragma once
+#ifndef ATSCPPAPI_LOGGER_H_
+#define ATSCPPAPI_LOGGER_H_
+
+#include <string>
+#include <atscppapi/noncopyable.h>
+
+#if !defined(ATSCPPAPI_PRINTFLIKE)
+#if defined(__GNUC__) || defined(__clang__)
+/**
+ * This macro will tell GCC that the function takes printf like arugments
+ * this is helpful because it can produce better warning and error messages
+ * when a user doesn't use the methods correctly.
+ *
+ * @private
+ */
+#define ATSCPPAPI_PRINTFLIKE(fmt, arg) __attribute__((format(printf, fmt, arg)))
+#else
+#define ATSCPPAPI_PRINTFLIKE(fmt, arg)
+#endif
+#endif
+
+/**
+ * A helper macro for Logger objects that allows you to easily add a debug level message
+ * which will include file, line, and function name with the message. It's very easy to use:
+ * \code
+ *  // Suppose you have already created a Logger named logger:
+ *  LOG_DEBUG(logger, "This is a test DEBUG message: %s", "hello");
+ *  // Outputs [file.cc:125, function()] [DEBUG] This is a test DEBUG message: hello.
+ * \endcode
+ */
+#define LOG_DEBUG(log, fmt, ...) \
+  do { \
+    (log).logDebug("[%s:%d, %s()] " fmt, __FILE__, __LINE__, __FUNCTION__, ## __VA_ARGS__); \
+  } while (false)
+
+/**
+ * A helper macro for Logger objects that allows you to easily add a info level message
+ * which will include file, line, and function name with the message. See example in LOG_DEBUG
+ */
+#define LOG_INFO(log, fmt, ...) \
+  do { \
+    (log).logInfo("[%s:%d, %s()] " fmt, __FILE__, __LINE__, __FUNCTION__, ## __VA_ARGS__); \
+  } while (false)
+
+/**
+ * A helper macro for Logger objects that allows you to easily add a error level message
+ * which will include file, line, and function name with the message.  See example in LOG_DEBUG
+ */
+#define LOG_ERROR(log, fmt, ...) \
+  do { \
+    (log).logError("[%s:%d, %s()] " fmt, __FILE__, __LINE__, __FUNCTION__, ## __VA_ARGS__); \
+  } while (false)
+
+/**
+ * We forward declare this because if we didn't we end up writing our
+ * own version to do the vsnprintf just to call TSDebug and have it do
+ * an unncessary vsnprintf.
+ *
+ * @private
+ */
+extern "C" void TSDebug(const char *tag, const char *fmt, ...) ATSCPPAPI_PRINTFLIKE(2,3);
+
+/**
+ * We forward declare this because if we didn't we end up writing our
+ * own version to do the vsnprintf just to call TSError and have it do
+ * an unncessary vsnprintf.
+ *
+ * @private
+ */
+extern "C" void TSError(const char *fmt, ...) ATSCPPAPI_PRINTFLIKE(1,2);
+
+// This is weird, but see the following:
+//   http://stackoverflow.com/questions/5641427/how-to-make-preprocessor-generate-a-string-for-line-keyword
+#define STRINGIFY0(x) #x
+#define STRINGIFY(x) STRINGIFY0(x)
+#define LINE_NO STRINGIFY(__LINE__)
+
+/**
+ * A helper macro to get access to the Diag messages available in traffic server. These can be enabled
+ * via traffic_server -T "tag.*" or since this macro includes the file can you further refine to an
+ * individual file or even a particular line! This can also be enabled via records.config.
+ */
+#define TS_DEBUG(tag, fmt, ...) \
+  do { \
+    TSDebug(tag "." __FILE__ ":" LINE_NO , "[%s()] " fmt, __FUNCTION__, ## __VA_ARGS__); \
+  } while (false)
+
+/**
+ * A helper macro to get access to the error.log messages available in traffic server. This
+ * will also output a DEBUG message visible via traffic_server -T "tag.*", or by enabling the
+ * tag in records.config.
+ */
+#define TS_ERROR(tag, fmt, ...) \
+  do { \
+    TS_DEBUG(tag, "[ERROR] " fmt, ## __VA_ARGS__); \
+    TSError("[%s] [%s:%d, %s()] " fmt, tag, __FILE__, __LINE__, __FUNCTION__, ## __VA_ARGS__); \
+  } while (false)
+
+namespace atscppapi {
+
+class LoggerState;
+
+/**
+ * @brief Create log files that are automatically rolled and cleaned up as space is required.
+ *
+ * Log files created using the Logger class will be placed in the same directory as
+ * other log files, that directory is specified in records.config. All of the logging
+ * configuration such as max space available for all logs includes any logs created
+ * using the Logger class.
+ *
+ * Loggers are very easy to use and a full example is available in examples/logger_example/,
+ * a simple example is:
+ * \code
+ * // See Logger::init() for an explanation of the init() parameters.
+ * log.init("logger_example", true, true, Logger::LOG_LEVEL_DEBUG);
+ * // You have two ways to log to a logger, you can log directly on the object itself:
+ * log.logInfo("Hello World from: %s", argv[0]);
+ * // Alternatively you can take advantage of the super helper macros for logging
+ * // that will include the file, function, and line number automatically as part
+ * // of the log message:
+ * LOG_INFO(log, "Hello World with more info from: %s", argv[0]);
+ * \endcode
+ *
+ * @warning Log rolling doesn't work correctly in 3.2.x see:
+ *   https://issues.apache.org/jira/browse/TS-1813
+ *   Apply the patch in TS-1813 to correct log rolling in 3.2.x
+ *
+ */
+class Logger : noncopyable {
+public:
+
+  /**
+   * The available log levels
+   */
+  enum LogLevel {
+    LOG_LEVEL_NO_LOG = 128, /**< This log level is used to disable all logging */
+    LOG_LEVEL_DEBUG = 1, /**< This log level is used for DEBUG level logging (DEBUG + INFO + ERROR) */
+    LOG_LEVEL_INFO = 2, /**< This log level is used for INFO level logging (INFO + ERROR) */
+    LOG_LEVEL_ERROR = 4 /**< This log level is used for ERROR level logging (ERROR ONLY) */
+  };
+
+  Logger();
+  ~Logger();
+
+  /**
+   * You must always init() a Logger before you begin logging. If you do not call init() nothing will
+   * happen.
+   *
+   * @param file The name of the file to create in the logging directory, if you do not specify an extension .log will be used.
+   * @param add_timestamp Prepend a timestamp to the log lines, the default value is true.
+   * @param rename_file If a file already exists by the same name it will attempt to rename using a scheme that appends .1, .2, and so on,
+   *   the default value for this argument is true.
+   * @param level the default log level to use when creating the logger, this is set to LOG_LEVEL_INFO by default.
+   * @param rolling_enabled if set to true this will enable log rolling on a periodic basis, this is enabled by default.
+   * @param rolling_interval_seconds how frequently to roll the longs in seconds, this is set to 3600 by default (one hour).
+   * @return returns true if the logger was successfully created and initialized.
+   * @see LogLevel
+   */
+  bool init(const std::string &file, bool add_timestamp = true, bool rename_file = true,
+      LogLevel level = LOG_LEVEL_INFO, bool rolling_enabled = true, int rolling_interval_seconds = 3600);
+
+  /**
+   * Allows you to change the rolling interval in seconds
+   * @param seconds the number of seconds between rolls
+   */
+  void setRollingIntervalSeconds(int seconds);
+
+  /**
+   * @return the number of seconds between log rolls.
+   */
+  int getRollingIntervalSeconds() const;
+
+  /**
+   * Enables or disables log rolling
+   * @param enabled true to enable log rolling, false to disable it.
+   */
+  void setRollingEnabled(bool enabled);
+
+  /**
+   * @return A boolean value which represents whether rolling is enabled or disabled.
+   */
+  bool isRollingEnabled() const;
+
+  /**
+   * Change the log level
+   *
+   * @param level the new log level to use
+   * @see LogLevel
+   */
+  void setLogLevel(Logger::LogLevel level);
+
+  /**
+   * @return The current log level.
+   * @see LogLevel
+   */
+  Logger::LogLevel getLogLevel() const;
+
+  /**
+   * This method allows you to flush any log lines that might have been buffered.
+   * @warning This method can cause serious performance degredation so you should only
+   * use it when absolutely necessary.
+   */
+  void flush();
+
+  /**
+   * This method writes a DEBUG level message to the log file, the LOG_DEBUG
+   * macro in Logger.h should be used in favor of these when possible because it
+   * will produce a much more rich debug message.
+   *
+   * Sample usage:
+   * \code
+   * log.logDebug("Hello you are %d years old", 27);
+   * \endcode
+   */
+  void logDebug(const char *fmt, ...) ATSCPPAPI_PRINTFLIKE(2,3);
+
+  /**
+   * This method writes an INFO level message to the log file, the LOG_INFO
+   * macro in Logger.h should be used in favor of these when possible because it
+   * will produce a much more rich info message.
+   */
+  void logInfo(const char *fmt, ...) ATSCPPAPI_PRINTFLIKE(2,3);
+
+  /**
+   * This method writes an ERROR level message to the log file, the LOG_ERROR
+   * macro in Logger.h should be used in favor of these when possible because it
+   * will produce a much more rich error message.
+   */
+  void logError(const char *fmt, ...) ATSCPPAPI_PRINTFLIKE(2,3);
+private:
+  LoggerState *state_; /**< Internal state for the Logger */
+};
+
+} /* atscppapi */
+
+
+
+
+#endif /* ATSCPPAPI_LOGGER_H_ */

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/src/include/atscppapi/Mutex.h
----------------------------------------------------------------------
diff --git a/lib/atscppapi/src/include/atscppapi/Mutex.h b/lib/atscppapi/src/include/atscppapi/Mutex.h
new file mode 100644
index 0000000..6044477
--- /dev/null
+++ b/lib/atscppapi/src/include/atscppapi/Mutex.h
@@ -0,0 +1,250 @@
+/**
+  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.
+ */
+
+/**
+ * @file Mutex.h
+ * @brief Contains Mutex related classes for creating a Mutex and locking a Mutex in a specific scope.
+ */
+
+#pragma once
+#ifndef ATSCPPAPI_MUTEX_H_
+#define ATSCPPAPI_MUTEX_H_
+
+#include <pthread.h>
+#include <atscppapi/noncopyable.h>
+#include <atscppapi/shared_ptr.h>
+
+namespace atscppapi {
+
+/**
+ * @brief A mutex is mutual exclusion: a blocking lock.
+ *
+ * The Mutex class uses pthreads for its implmentation.
+ *
+ * @see ScopedMutexLock
+ * @see ScopedMutexTryLock
+ * @see ScopedSharedMutexLock
+ * @see ScopedSharedMutexTryLock
+ */
+class Mutex: noncopyable {
+public:
+
+  /**
+   * The available types of Mutexes.
+   */
+  enum Type {
+    TYPE_NORMAL = 0, /**< This type of Mutex will deadlock if locked by a thread already holding the lock */
+    TYPE_RECURSIVE, /**< This type of Mutex will allow a thread holding the lock to lock it again; however, it must be unlocked the same number of times */
+    TYPE_ERROR_CHECK /**< This type of Mutex will return errno = EDEADLCK if a thread would deadlock by taking the lock after it already holds it */
+  };
+
+  /**
+   * Create a mutex
+   *
+   * @param type The Type of Mutex to create, the default is TYPE_NORMAL.
+   * @see Type
+   */
+  Mutex(Type type = TYPE_NORMAL) {
+    pthread_mutexattr_t attr;
+    pthread_mutexattr_init(&attr);
+
+    switch(type) {
+    case TYPE_RECURSIVE:
+     pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+     break;
+    case TYPE_ERROR_CHECK:
+     pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
+     break;
+    case TYPE_NORMAL:
+    default:
+     pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
+     break;
+    }
+
+    pthread_mutex_init(&mutex, &attr);
+  }
+
+  ~Mutex() {
+    pthread_mutex_destroy(&mutex);
+  }
+
+  /**
+   * Try to take the lock, this call will NOT block if the mutex cannot be taken.
+   * @return Returns true if the lock was taken, false if it was not. This call obviously will not block.
+   */
+  bool tryLock() {
+    return !pthread_mutex_trylock(&mutex);
+  }
+
+  /**
+   * Block until the lock is taken, when this call returns the thread will be holding the lock.
+   */
+  void lock() {
+    pthread_mutex_lock(&mutex);
+  }
+
+  /**
+   * Unlock the lock, this call is nonblocking.
+   */
+  void unlock() {
+    pthread_mutex_unlock(&mutex);
+  }
+private:
+  pthread_mutex_t mutex; /**< Internal mutex identifier */
+};
+
+/**
+ * @brief Take a Mutex reference and lock inside a scope and unlock when the scope is exited.
+ *
+ * This is an RAII implementation which will lock a mutex at the start of the
+ * scope and unlock it when the scope is exited.
+ *
+ * @see Mutex
+ */
+class ScopedMutexLock: noncopyable {
+public:
+  /**
+   * Create the scoped mutex lock, once this object is constructed the lock will be held by the thread.
+   * @param mutex a reference to a Mutex.
+   */
+  explicit ScopedMutexLock(Mutex &mutex) :
+      mutex_(mutex) {
+    mutex_.lock();
+  }
+
+  /**
+   * Unlock the mutex.
+   */
+  ~ScopedMutexLock() {
+    mutex_.unlock();
+  }
+private:
+  Mutex &mutex_;
+};
+
+/**
+ * @brief Take a shared_ptr to a Mutex and lock inside a scope and unlock when the scope is exited.
+ *
+ * This is an RAII implementation which will lock a mutex at the start of the
+ * scope and unlock it when the scope is exited.
+ *
+ * @see Mutex
+ */
+class ScopedSharedMutexLock: noncopyable {
+public:
+  /**
+   * Create the scoped mutex lock, once this object is constructed the lock will be held by the thread.
+   * @param mutex a shared pointer to a Mutex.
+   */
+  explicit ScopedSharedMutexLock(shared_ptr<Mutex> mutex) :
+      mutex_(mutex) {
+    mutex_->lock();
+  }
+
+  /**
+   * Unlock the mutex.
+   */
+  ~ScopedSharedMutexLock() {
+    mutex_->unlock();
+  }
+private:
+  shared_ptr<Mutex> mutex_;
+};
+
+/**
+ * @brief Take a Mutex reference and try to lock inside a scope and unlock when the scope is exited (if the lock was taken).
+ *
+ * This is an RAII implementation which will lock a mutex at the start of the
+ * scope and unlock it when the scope is exited if the lock was taken.
+ *
+ * @see Mutex
+ */
+class ScopedMutexTryLock: noncopyable {
+public:
+  /**
+   * Try to create the scoped mutex lock, if you should check hasLock() to determine if this object was successfully able to take the lock.
+   * @param mutex a shared pointer to a Mutex.
+   */
+  explicit ScopedMutexTryLock(Mutex &mutex) :
+      mutex_(mutex), has_lock_(false) {
+    has_lock_ = mutex_.tryLock();
+  }
+
+  /**
+   * Unlock the mutex (if we hold the lock)
+   */
+  ~ScopedMutexTryLock() {
+    if (has_lock_) {
+      mutex_.unlock();
+    }
+  }
+
+  /**
+   * @return True if the lock was taken, False if it was not taken.
+   */
+  bool hasLock() {
+    return has_lock_;
+  }
+private:
+  Mutex &mutex_;
+  bool has_lock_;
+};
+
+/**
+ * @brief Take a shared_ptr to a Mutex and try to lock inside a scope and unlock when the scope is exited (if the lock was taken).
+ *
+ * This is an RAII implementation which will lock a mutex at the start of the
+ * scope and unlock it when the scope is exited if the lock was taken.
+ *
+ * @see Mutex
+ */
+class ScopedSharedMutexTryLock: noncopyable {
+public:
+  /**
+   * Try to create the scoped mutex lock, if you should check hasLock() to determine if this object was successfully able to take the lock.
+   * @param mutex a shared pointer to a Mutex.
+   */
+  explicit ScopedSharedMutexTryLock(shared_ptr<Mutex> mutex) :
+      mutex_(mutex), has_lock_(false) {
+    has_lock_ = mutex_->tryLock();
+  }
+
+  /**
+   * Unlock the mutex (if we hold the lock)
+   */
+  ~ScopedSharedMutexTryLock() {
+    if (has_lock_) {
+      mutex_->unlock();
+    }
+  }
+
+  /**
+   * @return True if the lock was taken, False if it was not taken.
+   */
+  bool hasLock() {
+    return has_lock_;
+  }
+private:
+  shared_ptr<Mutex> mutex_;
+  bool has_lock_;
+};
+
+} /* atscppapi */
+
+
+#endif /* ATSCPPAPI_MUTEX_H_ */

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/src/include/atscppapi/Plugin.h
----------------------------------------------------------------------
diff --git a/lib/atscppapi/src/include/atscppapi/Plugin.h b/lib/atscppapi/src/include/atscppapi/Plugin.h
new file mode 100644
index 0000000..677a3bd
--- /dev/null
+++ b/lib/atscppapi/src/include/atscppapi/Plugin.h
@@ -0,0 +1,106 @@
+/**
+  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.
+ */
+/**
+ * @file Plugin.h
+ *
+ * @brief Contains the base interface used in creating Global and Transaciton plugins.
+ * \note This interface can never be implemented directly, it should be implemented
+ *   through extending GlobalPlugin, TransactionPlugin, or TransformationPlugin.
+ */
+
+#pragma once
+#ifndef ATSCPPAPI_PLUGIN_H_
+#define ATSCPPAPI_PLUGIN_H_
+
+#include <atscppapi/Transaction.h>
+#include <atscppapi/noncopyable.h>
+
+namespace atscppapi {
+
+/**
+ * @brief The base interface used when creating a Plugin.
+ *
+ * \note This interface can never be implemented directly, it should be implemented
+ *   through extending GlobalPlugin, TransactionPlugin, or TransformationPlugin.
+ *
+ * @see TransactionPlugin
+ * @see GlobalPlugin
+ * @see TransformationPlugin
+ */
+class Plugin: noncopyable {
+public:
+  /**
+   * A enumeration of the available types of Hooks. These are used with GlobalPlugin::registerHook()
+   * and TransactionPlugin::registerHook().
+   */
+  enum HookType {
+    HOOK_READ_REQUEST_HEADERS_PRE_REMAP = 0, /**< This hook will be fired before remap has occured. */
+    HOOK_READ_REQUEST_HEADERS_POST_REMAP, /**< This hook will be fired directly after remap has occured. */
+    HOOK_SEND_REQUEST_HEADERS, /**< This hook will be fired right before request headers are sent to the origin */
+    HOOK_READ_RESPONSE_HEADERS, /**< This hook will be fired right after response headers have been read from the origin */
+    HOOK_SEND_RESPONSE_HEADERS, /**< This hook will be fired right before the response headers are sent to the client */
+    HOOK_OS_DNS /**< This hook will be fired right after the OS DNS lookup */
+  };
+
+  /**
+   * This method must be implemented when you hook HOOK_READ_REQUEST_HEADERS_PRE_REMAP
+   */
+  virtual void handleReadRequestHeadersPreRemap(Transaction &transaction) { transaction.resume(); };
+
+  /**
+   * This method must be implemented when you hook HOOK_READ_REQUEST_HEADERS_POST_REMAP
+   */
+  virtual void handleReadRequestHeadersPostRemap(Transaction &transaction) { transaction.resume(); };
+
+  /**
+   * This method must be implemented when you hook HOOK_SEND_REQUEST_HEADERS
+   */
+  virtual void handleSendRequestHeaders(Transaction &transaction) { transaction.resume(); };
+
+  /**
+   * This method must be implemented when you hook HOOK_READ_RESPONSE_HEADERS
+   */
+  virtual void handleReadResponseHeaders(Transaction &transaction) { transaction.resume(); };
+
+  /**
+   * This method must be implemented when you hook HOOK_SEND_RESPONSE_HEADERS
+   */
+  virtual void handleSendResponseHeaders(Transaction &transaction) { transaction.resume(); };
+
+  /**
+   * This method must be implemented when you hook HOOK_OS_DNS
+   */
+  virtual void handleOsDns(Transaction &transaction) { transaction.resume(); };
+
+  virtual ~Plugin() { };
+protected:
+  /**
+  * \note This interface can never be implemented directly, it should be implemented
+  *   through extending GlobalPlugin, TransactionPlugin, or TransformationPlugin.
+  *
+  * @private
+  */
+  Plugin() { };
+};
+
+/**< Human readable strings for each HookType, you can access them as HOOK_TYPE_STRINGS[HOOK_OS_DNS] for example. */
+extern const std::string HOOK_TYPE_STRINGS[];
+
+} /* atscppapi */
+
+#endif /* ATSCPPAPI_GLOBALPLUGIN_H_ */

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/src/include/atscppapi/PluginInit.h
----------------------------------------------------------------------
diff --git a/lib/atscppapi/src/include/atscppapi/PluginInit.h b/lib/atscppapi/src/include/atscppapi/PluginInit.h
new file mode 100644
index 0000000..ecd72e4
--- /dev/null
+++ b/lib/atscppapi/src/include/atscppapi/PluginInit.h
@@ -0,0 +1,55 @@
+/**
+  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.
+ */
+/**
+ * @file PluginInit.h
+ * @brief Provides hooks that plugins have to implement. ATS will invoke these when loading the plugin .so files.
+ */
+
+#pragma once
+#ifndef ATSCPPAPI_PLUGININIT_H_
+#define ATSCPPAPI_PLUGININIT_H_
+
+extern "C" {
+
+/** 
+ * Invoked for "general" plugins - listed in plugin.config. The arguments in the
+ * plugin.config line are provided in this invocation.
+ *
+ * @param argc Count of arguments
+ * @param argv Array of pointers pointing to arguments
+ */
+void TSPluginInit(int argc, const char *argv[]);
+
+enum TsReturnCode { TS_ERROR = -1, TS_SUCCESS = 0 };
+
+/** 
+ * Invoked for remap plugins - listed in remap.config. The arguments provided as @pparam
+ * in the remap.config line are provided in this invocation.
+ *
+ * @param argc Count of arguments
+ * @param argv Array of pointers pointing to arguments
+ * @param instance_handle Should be passed to the RemapPlugin constructor
+ * @param errbuf Not used
+ * @param errbuf_size Not used
+ */
+TsReturnCode TSRemapNewInstance(int argc, char *argv[], void **instance_handle, char *errbuf, int errbuf_size);
+
+}
+
+
+#endif /* ATSCPPAPI_PLUGININIT_H_ */

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/src/include/atscppapi/RemapPlugin.h
----------------------------------------------------------------------
diff --git a/lib/atscppapi/src/include/atscppapi/RemapPlugin.h b/lib/atscppapi/src/include/atscppapi/RemapPlugin.h
new file mode 100644
index 0000000..2a80291
--- /dev/null
+++ b/lib/atscppapi/src/include/atscppapi/RemapPlugin.h
@@ -0,0 +1,69 @@
+/**
+  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.
+ */
+
+/**
+ * @file RemapPlugin.h
+ */
+
+#pragma once
+#ifndef ATSCPPAPI_REMAP_PLUGIN_H_
+#define ATSCPPAPI_REMAP_PLUGIN_H_
+
+#include "atscppapi/Transaction.h"
+#include "atscppapi/Url.h"
+
+namespace atscppapi {
+
+/** 
+ * @brief Base class that remap plugins should extend.
+ */
+class RemapPlugin {
+public:
+  /**
+   * Constructor
+   * 
+   * @param instance_handle The instance_handle argument received in TSRemapInit() should be passed here.
+   */
+  RemapPlugin(void **instance_handle);
+
+  enum Result { RESULT_ERROR = 0, RESULT_NO_REMAP, RESULT_DID_REMAP, RESULT_NO_REMAP_STOP,
+                RESULT_DID_REMAP_STOP };
+
+  /** 
+   * Invoked when a request matches the remap.config line - implementation should perform the
+   * remap. The client's URL is in the transaction and that's where it should be modified.
+   * 
+   * @param map_from_url The map from URL specified in the remap.config line.
+   * @param map_to_url The map to URL specified in the remap.config line.
+   * @param transaction Transaction
+   * @param redirect Output argument that should be set to true if the (new) url should be used
+   *                 as a redirect. 
+   *
+   * @return Result of the remap - will dictate futher processing by the system.
+   */
+  virtual Result doRemap(const Url &map_from_url, const Url &map_to_url, Transaction &transaction,
+                         bool &redirect) {
+    return RESULT_NO_REMAP;
+  }
+
+  virtual ~RemapPlugin() { }
+};
+
+}
+
+#endif

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/src/include/atscppapi/Request.h
----------------------------------------------------------------------
diff --git a/lib/atscppapi/src/include/atscppapi/Request.h b/lib/atscppapi/src/include/atscppapi/Request.h
new file mode 100644
index 0000000..8831725
--- /dev/null
+++ b/lib/atscppapi/src/include/atscppapi/Request.h
@@ -0,0 +1,72 @@
+/**
+  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.
+ */
+/**
+ * @file Request.h
+ */
+
+#pragma once
+#ifndef ATSCPPAPI_REQUEST_H_
+#define ATSCPPAPI_REQUEST_H_
+
+#include <atscppapi/Headers.h>
+#include <atscppapi/HttpVersion.h>
+#include <atscppapi/HttpMethod.h>
+#include <atscppapi/Url.h>
+#include <atscppapi/noncopyable.h>
+
+namespace atscppapi {
+
+class Transaction;
+struct RequestState;
+
+/**
+ * @brief Encapsulates a request.
+ */
+class Request: noncopyable {
+public:
+  Request();
+
+  /**
+   * Constructed with an initial URL.
+   */
+  Request(const std::string &url, HttpMethod method = HTTP_METHOD_GET, HttpVersion version = HTTP_VERSION_1_1); 
+
+  /** @return HTTP method of the request */
+  HttpMethod getMethod() const;
+
+  /** @return URL of the request */
+  Url &getUrl();
+
+  /** @return HTTP version of the request */
+  HttpVersion getVersion() const;
+
+  /** @return Headers of the request */
+  Headers &getHeaders() const;
+
+  ~Request();
+private:
+  Request(void *hdr_buf, void *hdr_loc);
+  RequestState *state_;
+  void init(void *hdr_buf, void *hdr_loc);
+  friend class Transaction;
+  friend class ClientRequest;
+};
+
+}
+
+#endif

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/src/include/atscppapi/Response.h
----------------------------------------------------------------------
diff --git a/lib/atscppapi/src/include/atscppapi/Response.h b/lib/atscppapi/src/include/atscppapi/Response.h
new file mode 100644
index 0000000..f309bc1
--- /dev/null
+++ b/lib/atscppapi/src/include/atscppapi/Response.h
@@ -0,0 +1,71 @@
+/**
+  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.
+ */
+/**
+ * @file Response.h
+ */
+
+#pragma once
+#ifndef ATSCPPAPI_RESPONSE_H_
+#define ATSCPPAPI_RESPONSE_H_
+
+#include <atscppapi/Headers.h>
+#include <atscppapi/HttpVersion.h>
+#include <atscppapi/HttpStatus.h>
+
+namespace atscppapi {
+
+// forward declarations
+struct ResponseState;
+namespace utils { class internal; }
+
+/**
+ * @brief Encapsulates a response.
+ */
+class Response: noncopyable {
+public:
+  Response();
+
+  /** @return HTTP version of the response */
+  HttpVersion getVersion() const;
+
+  /** @return Status code of the response */
+  HttpStatus getStatusCode() const;
+
+  /** @param New status code to set */
+  void setStatusCode(HttpStatus);
+
+  /** @return Reason phrase of the response */
+  const std::string &getReasonPhrase() const;
+
+  /** @param New reason phrase to set */
+  void setReasonPhrase(const std::string &);
+
+  /** @return Headers of the response */
+  Headers &getHeaders() const;
+
+  ~Response();
+private:
+  ResponseState *state_;
+  void init(void *hdr_buf, void *hdr_loc);
+  friend class Transaction;
+  friend class utils::internal;
+};
+
+}
+
+#endif

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/src/include/atscppapi/Stat.h
----------------------------------------------------------------------
diff --git a/lib/atscppapi/src/include/atscppapi/Stat.h b/lib/atscppapi/src/include/atscppapi/Stat.h
new file mode 100644
index 0000000..d665d1a
--- /dev/null
+++ b/lib/atscppapi/src/include/atscppapi/Stat.h
@@ -0,0 +1,106 @@
+/**
+  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.
+ */
+/**
+ * @file Stat.h
+ */
+
+#pragma once
+#ifndef ATSCPPAPI_STAT_H_
+#define ATSCPPAPI_STAT_H_
+
+#include <atscppapi/noncopyable.h>
+#include <stdint.h>
+#include <string>
+
+namespace atscppapi {
+
+/**
+ * @brief A Stat is an atomic variable that can be used to store counters, averages, time averages, or summations.
+ *
+ * All stats are exposed through the traffic_line program included with Apache Traffic Server. Additionally,
+ * if you've enabled HttpStats all Stats you define will be displayed there. Stats can be read via
+ * traffic_line -r stat_name.
+ *
+ * Stats are very easy to use, here is a simple example of how you can create a counter and increment its
+ * value:
+ * \code
+ *  Stat stat;
+ *  stat.init("stat_name");
+    stat.inc();
+ * \endcode
+ *
+ * A full example is available in examples/stat_example/.
+ */
+class Stat : noncopyable {
+public:
+  /**
+   * The available Stat types.
+   */
+  enum SyncType {
+    SYNC_SUM = 0, /**< The stat will sum all values from a stat.inc(VAL) */
+    SYNC_COUNT, /**< The stat will count all calls to stat.inc(VAL) */
+    SYNC_AVG, /**< The stat will keep an average after call calls to stat.inc(VAL) */
+    SYNC_TIMEAVG /**< The stat will keep a time average of all calls to stat.inc(VAL) */
+  };
+
+  Stat();
+  ~Stat();
+
+  /**
+   * You must initialize your Stat with a call to this init() method.
+   *
+   * @param name The string name of the stat, this will be visbible via traffic_line -r, or through http stats.
+   * @param type The SyncType of the Stat, this decides how TrafficServer will treat your inputs. The default
+   *   value is SYNC_COUNT.
+   * @param persistent This determines if your Stats will persist, the default value is false.
+   * @return True if the stat was successfully created and false otherwise.
+   *
+   * @see SyncType
+   */
+  bool init(std::string name, Stat::SyncType type = SYNC_COUNT, bool persistent = false);
+
+  /**
+   * This method allows you to increment a stat by a certain amount.
+   * @param amount the amount to increment the stat by the default value is 1.
+   */
+  void increment(int64_t amount = 1);
+
+  /**
+   * This method allows you to decrement a stat by a certain amount.
+   * @param amount the amount to decrement the stat by the default value is 1.
+   */
+  void decrement(int64_t amount = 1);
+
+  /**
+   * This method returns the current value of the stat.
+   * @return The value of the stat.
+   */
+  int64_t get() const;
+
+  /** This method sets the value of the stat.
+   * @param value the value to set the stat to.
+   */
+  void set(int64_t value);
+private:
+  int stat_id_; /**< The internal stat ID */
+};
+
+} /* atscppapi */
+
+
+#endif /* ATSCPPAPI_STAT_H_ */

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/src/include/atscppapi/Transaction.h
----------------------------------------------------------------------
diff --git a/lib/atscppapi/src/include/atscppapi/Transaction.h b/lib/atscppapi/src/include/atscppapi/Transaction.h
new file mode 100644
index 0000000..3610d1b
--- /dev/null
+++ b/lib/atscppapi/src/include/atscppapi/Transaction.h
@@ -0,0 +1,314 @@
+/**
+  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.
+ */
+/**
+ * @file Transaction.h
+ */
+
+#pragma once
+#ifndef ATSCPPAPI_TRANSACTION_H_
+#define ATSCPPAPI_TRANSACTION_H_
+
+#include <sys/socket.h>
+#include <stdint.h>
+#include <list>
+#include "atscppapi/Request.h"
+#include "atscppapi/shared_ptr.h"
+#include "atscppapi/ClientRequest.h"
+#include "atscppapi/Response.h"
+
+namespace atscppapi {
+
+// forward declarations
+class TransactionPlugin;
+class TransactionState;
+namespace utils { class internal; }
+
+/**
+ * @brief Transactions are the object containing all the state related to a HTTP Transaction
+ *
+ * @warning Transactions should never be directly created by the user, they will always be automatically
+ * created and destroyed as they are needed. Transactions should never be saved beyond the
+ * scope of the function in which they are delivered otherwise undefined behaviour will result.
+ */
+class Transaction: noncopyable {
+public:
+  /**
+   * @brief ContextValues are a mechanism to share data between plugins using the atscppapi.
+   *
+   * Any data can be shared so long as it extends ContextValue, a simple example might
+   * be:
+   *
+   * \code
+   *     struct mydata : ContextValue {
+   *       int id_;
+   *       string foo_;
+   *       mydata(int id, string foo) : id_(id), foo_(foo) { }
+   *     }
+   *
+   *     Transaction.setContextValue("some-key", shared_ptr(new mydata(12, "hello")));
+   *
+   *     // From another plugin you'll have access to this contextual data:
+   *     shared_ptr<Transaction.getContextValue("some-key")
+   *
+   * \endcode
+   *
+   * Because getContextValue() and setContextValue()
+   * take shared pointers you dont have to worry about the cleanup as that will happen automatically so long
+   * as you dont have shared_ptrs that cannot go out of scope.
+   */
+  class ContextValue {
+  public:
+    virtual ~ContextValue() { }
+  };
+
+  ~Transaction();
+
+  /**
+   * Context Values are a way to share data between plugins, the key is always a string
+   * and the value can be a shared_ptr to any type that extends ContextValue.
+   * @param key the key to search for.
+   * @return Shared pointer that is correctly initialized if the
+   *         value existed. It should be checked with .get() != NULL before use.
+   */
+  shared_ptr<ContextValue> getContextValue(const std::string &key);
+
+  /**
+   * Context Values are a way to share data between plugins, the key is always a string
+   * and the value can be a shared_ptr to any type that extends ContextValue.
+   * @param key the key to insert.
+   * @param value a shared pointer to a class that extends ContextValue.
+   */
+  void setContextValue(const std::string &key, shared_ptr<ContextValue> value);
+
+  /**
+   * Causes the Transaction to continue on to other states in the HTTP state machine
+   * If you do not call resume() on a Transaction it will remain in that state until
+   * it's advanced out by a call to resume() or error().
+   */
+  void resume();
+
+  /**
+   * Causes the Transaction to advance to the error state in the HTTP state machine.
+   * @see error(const std::string &)
+   */
+  void error();
+
+  /**
+   * Causes the Transaction to advance to the error state in the HTTP state machine with
+   * a specific error message displayed. This is functionally equivalent to the following:
+   *
+   * \code
+   * setErrorBody(content);
+   * error();
+   * \endcode
+   *
+   * @param content the error page body.
+   */
+  void error(const std::string &content);
+
+  /**
+   * Sets the error body page but this method does not advance the state machine to the error state.
+   * To do that you must explicitally call error().
+   *
+   * @param content the error page content.
+   */
+  void setErrorBody(const std::string &content);
+
+  /**
+   * Get the clients address
+   * @return The sockaddr structure representing the client's address
+   * @see atscppapi::utils::getIpString() in atscppapi/utils.h
+   * @see atscppapi::utils::getPort() in atscppapi/utils.h
+   * @see atscppapi::utils::getIpPortString in atscppapi/utils.h
+   */
+  const sockaddr *getClientAddress() const;
+
+  /**
+   * Get the incoming address
+   * @return The sockaddr structure representing the incoming address
+   * @see atscppapi::utils::getIpString() in atscppapi/utils.h
+   * @see atscppapi::utils::getPort() in atscppapi/utils.h
+   * @see atscppapi::utils::getIpPortString in atscppapi/utils.h
+   */
+  const sockaddr *getIncomingAddress() const;
+
+  /**
+   * Get the server address
+   * @return The sockaddr structure representing the server's address
+   * @see atscppapi::utils::getIpString() in atscppapi/utils.h
+   * @see atscppapi::utils::getPort() in atscppapi/utils.h
+   * @see atscppapi::utils::getIpPortString in atscppapi/utils.h
+   */
+  const sockaddr *getServerAddress() const;
+
+  /**
+   * Get the next hop address
+   * @return The sockaddr structure representing the next hop's address
+   * @see atscppapi::utils::getIpString() in atscppapi/utils.h
+   * @see atscppapi::utils::getPort() in atscppapi/utils.h
+   * @see atscppapi::utils::getIpPortString in atscppapi/utils.h
+   */
+  const sockaddr *getNextHopAddress() const;
+
+
+  /**
+   * Set the incoming port on the Transaction
+   *
+   * @param port is the port to set as the incoming port on the transaction
+   */
+  bool setIncomingPort(uint16_t port);
+
+  /**
+   * Sets the server address on the Transaction to a populated sockaddr *
+   *
+   * @param sockaddr* the sockaddr structure populated as the server address.
+   */
+  bool setServerAddress(const sockaddr *);
+
+  /**
+   * Returns a boolean value if the request is an internal request.
+   * A request is an internal request if it originates from within traffic server.
+   * An example would be using TSFetchUrl (or the atscppapi equivalent of AsyncHttpFetch)
+   * to make another request along with the original request. The secondary request
+   * originated within traffic server and is an internal request.
+   *
+   * @return boolean value specifying if the request was an internal request.
+   */
+  bool isInternalRequest() const;
+
+  /**
+   * Returns the ClientRequest object for the incoming request from the client.
+   *
+   * @return ClientRequest object that can be used to manipulate the incoming request from the client.
+   */
+  ClientRequest &getClientRequest();
+
+  /**
+   * Returns a Request object which is the request from Traffic Server to the origin server.
+   *
+   * @return Request object that can be used to manipulate the outgoing request to the origin server.
+   */
+  Request &getServerRequest();
+
+  /**
+   * Returns a Response object which is the response coming from the origin server
+   *
+   * @return Response object that can be used to manipulate the incoming response from the origin server.
+   */
+  Response &getServerResponse();
+
+  /**
+   * Returns a Response object which is the response going to the client
+   *
+   * @return Response object that can be used to manipulate the outgoing response from the client.
+   */
+  Response &getClientResponse();
+
+  /**
+   * Returns the Effective URL for this transaction taking into account host.
+   */
+  std::string getEffectiveUrl();
+
+  /**
+   * Sets the url used by the ATS cache for a specific transaction.
+   * @param url is the url to use in the cache.
+   */
+  bool setCacheUrl(const std::string &);
+
+  /**
+   * The available types of timeouts you can set on a Transaction.
+   */
+  enum TimeoutType {
+    TIMEOUT_DNS = 0, /**< Timeout on DNS */
+    TIMEOUT_CONNECT, /**< Timeout on Connect */
+    TIMEOUT_NO_ACTIVITY, /**< Timeout on No Activity */
+    TIMEOUT_ACTIVE /**< Timeout with Activity */
+  };
+
+  /**
+   * Allows you to set various types of timeouts on a Transaction
+   *
+   * @param type The type of timeout
+   * @param time_ms The timeout time in milliseconds
+   * @see TimeoutType
+   */
+  void setTimeout(TimeoutType type, int time_ms);
+
+  /**
+   * Returns the TSHttpTxn related to the current Transaction
+   *
+   * @return a void * which can be cast back to a TSHttpTxn.
+   */
+  void *getAtsHandle() const;
+
+  /**
+   * Adds a TransactionPlugin to the current Transaction. This effectively transfers ownership and the
+   * Transaction is now responsible for cleaning it up.
+   *
+   * @param TransactionPlugin* the TransactionPlugin that will be now bound to the current Transaction.
+   */
+  void addPlugin(TransactionPlugin *);
+
+private:
+  TransactionState *state_; //!< The internal TransactionState object tied to the current Transaction
+  friend class TransactionPlugin; //!< TransactionPlugin is a friend so it can call addPlugin()
+  friend class TransformationPlugin; //!< TransformationPlugin is a friend so it can call addPlugin()
+
+  /**
+   * @private
+   *
+   * @param raw_txn a void pointer that represents a TSHttpTxn
+   */
+  Transaction(void *);
+
+  /**
+   * Used to initialize the Request object for the Server.
+   *
+   * @private
+   */
+  void initServerRequest();
+
+  /**
+   * Used to initialize the Response object for the Server.
+   *
+   * @private
+   */
+  void initServerResponse();
+
+  /**
+   * Used to initialize the Response object for the Client.
+   *
+   * @private
+   */
+  void initClientResponse();
+
+  /**
+   * Returns a list of TransactionPlugin pointers bound to the current Transaction
+   *
+   * @private
+   *
+   * @return a std::list<TransactionPlugin *> which represents all TransactionPlugin bound to the current Transaction.
+   */
+  const std::list<TransactionPlugin *> &getPlugins() const;
+
+  friend class utils::internal;
+};
+
+} /* atscppapi */
+
+#endif /* ATSCPPAPI_TRANSACTION_H_ */

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/src/include/atscppapi/TransactionPlugin.h
----------------------------------------------------------------------
diff --git a/lib/atscppapi/src/include/atscppapi/TransactionPlugin.h b/lib/atscppapi/src/include/atscppapi/TransactionPlugin.h
new file mode 100644
index 0000000..d473827
--- /dev/null
+++ b/lib/atscppapi/src/include/atscppapi/TransactionPlugin.h
@@ -0,0 +1,113 @@
+/**
+  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.
+ */
+/**
+ * @file TransactionPlugin.h
+ * @brief Contains the interface used in creating Transaciton plugins.
+ */
+
+#pragma once
+#ifndef ATSCPPAPI_TRANSACTIONPLUGIN_H_
+#define ATSCPPAPI_TRANSACTIONPLUGIN_H_
+
+#include <atscppapi/Plugin.h>
+#include <atscppapi/Transaction.h>
+#include <atscppapi/shared_ptr.h>
+#include <atscppapi/Mutex.h>
+
+namespace atscppapi {
+
+namespace utils {
+ class internal;
+} /* utils */
+
+/**
+ * @private
+ */
+class TransactionPluginState;
+
+/**
+ * @brief The interface used when creating a TransactionPlugin.
+ *
+ * A Transaction Plugin is a plugin that will fire only for the specific Transaction it
+ * was bound to. When you create a TransactionPlugin you call the parent constructor with
+ * the associated Transaction and it will become automatically bound. This means that your
+ * TransactionPlugin will automatically be destroyed when the Transaction dies.
+ *
+ * Implications of this are that you can easily add Transaction scoped storage by adding
+ * a member to a TransactionPlugin since the destructor will be called of your TransactionPlugin
+ * any cleanup that needs to happen can happen in your destructor as you normally would.
+ *
+ * You must always be sure to implement the appropriate callback for the type of hook you register.
+ *
+ * \code
+ * // For a more detailed example see examples/transactionhook/
+ * class TransactionHookPlugin : publicTransactionPlugin {
+ * public:
+ *   TransactionHookPlugin(Transaction &transaction) : TransactionPlugin(transaction) {
+ *     char_ptr_ = new char[100]; // Transaction scoped storage
+ *     registerHook(HOOK_SEND_RESPONSE_HEADERS);
+ *   }
+ *   virtual ~TransactionHookPlugin() {
+ *     delete[] char_ptr_; // cleanup
+ *   }
+ *   void handleSendResponseHeaders(Transaction &transaction) {
+ *     transaction.resume();
+ *   }
+ * private:
+ *   char *char_ptr_;
+ * };
+ * \endcode
+ *
+ * @see Plugin
+ * @see HookType
+ */
+class TransactionPlugin : public Plugin {
+public:
+  /**
+   * registerHook is the mechanism used to attach a transaction hook.
+   *
+   * \note Whenever you register a hook you must have the appropriate callback definied in your TransactionPlugin
+   *  see HookType and Plugin for the correspond HookTypes and callback methods. If you fail to implement the
+   *  callback, a default implmentation will be used that will only resume the Transaction.
+   *
+   * @param HookType the type of hook you wish to register
+   * @see HookType
+   * @see Plugin
+   */
+  void registerHook(Plugin::HookType hook_type);
+  virtual ~TransactionPlugin();
+protected:
+  TransactionPlugin(Transaction &transaction);
+
+  /**
+   * This method will return a shared_ptr to a Mutex that can be used for AsyncProvider and AsyncReceiver operations.
+   *
+   * If another thread wanted to stop this transaction from dispatching an event it could be passed
+   * this mutex and it would be able to lock it and prevent another thread from dispatching back into this
+   * TransactionPlugin.
+   */
+  shared_ptr<Mutex> getMutex();
+private:
+  TransactionPluginState *state_; /**< The internal state for a TransactionPlugin */
+  friend class utils::internal;
+};
+
+} /* atscppapi */
+
+
+#endif /* ATSCPPAPI_TRANSACTIONPLUGIN_H_ */

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/src/include/atscppapi/TransformationPlugin.h
----------------------------------------------------------------------
diff --git a/lib/atscppapi/src/include/atscppapi/TransformationPlugin.h b/lib/atscppapi/src/include/atscppapi/TransformationPlugin.h
new file mode 100644
index 0000000..c4df942
--- /dev/null
+++ b/lib/atscppapi/src/include/atscppapi/TransformationPlugin.h
@@ -0,0 +1,129 @@
+/**
+  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.
+ */
+
+/**
+ * @file TransformationPlugin.h
+ */
+
+#pragma once
+#ifndef ATSCPPAPI_TRANSFORMATIONPLUGIN_H_
+#define ATSCPPAPI_TRANSFORMATIONPLUGIN_H_
+
+#include <string>
+#include <atscppapi/Transaction.h>
+#include <atscppapi/TransactionPlugin.h>
+
+namespace atscppapi {
+
+class TransformationPluginState;
+
+/**
+ * @brief The interface used when you wish to transform Request or Response body content.
+ *
+ * Transformations are deceptively simple, transformations are chained so the output
+ * of one TransformationPlugin becomes the input of another TransformationPlugin. As
+ * data arrives it will fire a consume() and when all the data has been sent
+ * you will receive a handleInputComplete(). Data can be sent to the next TransformationPlugin
+ * in the chain by calling produce() and when the transformation has no data left to send
+ * it will fire a setOutputCompete().
+ *
+ * Since a TransformationPlugin is a type of TransactionPlugin you can call registerHook() and
+ * establish any hook for a Transaction also; however, remember that you must implement
+ * the appropriate callback for any hooks you register.
+ *
+ * A simple example of how to use the TransformationPlugin interface follows, this is an example
+ * of a Response transformation, the avialable options are REQUEST_TRANSFORMATION and RESPONSE_TRANSFORMATION
+ * which are defined in Type.
+ *
+ * This example is a Null Transformation, meaning it will just spit out the content it receives without
+ * actually doing any work on it.
+ *
+ * \code
+ * class NullTransformationPlugin : public TransformationPlugin {
+ * public:
+ *   NullTransformationPlugin(Transaction &transaction)
+ *     : TransformationPlugin(transaction, RESPONSE_TRANSFORMATION) {
+ *     registerHook(HOOK_SEND_RESPONSE_HEADERS);
+ *   }
+ *   void handleSendResponseHeaders(Transaction &transaction) {
+ *     transaction.getClientResponse().getHeaders().set("X-Content-Transformed", "1");
+ *     transaction.resume();
+ *   }
+ *   void consume(const string &data) {
+ *     produce(data);
+ *   }
+ *   void handleInputComplete() {
+ *     setOutputComplete();
+ *   }
+ * };
+ * \endcode
+ *
+ * @see Plugin
+ * @see TransactionPlugin
+ * @see Type
+ * @see HookType
+ */
+class TransformationPlugin : public TransactionPlugin {
+public:
+  /**
+   * The available types of Transformations.
+   */
+  enum Type {
+    REQUEST_TRANSFORMATION = 0, /**< Transform the Request body content */
+    RESPONSE_TRANSFORMATION /**< Transform the Response body content */
+  };
+
+  /**
+   * A method that you must implement when writing a TransformationPlugin, this method will be
+   * fired whenever an upstream TransformationPlugin has produced output.
+   */
+  virtual void consume(const std::string &data) = 0;
+
+  /**
+   * A method that you must implement when writing a TransformationPlugin, this method
+   * will be fired whenever the upstream TransformationPlugin has completed writing data.
+   */
+  virtual void handleInputComplete() = 0;
+
+  virtual ~TransformationPlugin(); /**< Destructor for a TransformationPlugin */
+protected:
+
+  /**
+   * This method is how a TransformationPlugin will produce output for the downstream
+   * transformation plugin, if you need to produce binary data this can still be
+   * done with strings by a call to string::assign() or by constructing a string
+   * with string::string(char *, size_t).
+   */
+  size_t produce(const std::string &);
+
+  /**
+   * This is the method that you must call when you're done producing output for
+   * the downstream TranformationPlugin.
+   */
+  size_t setOutputComplete();
+
+  /** a TransformationPlugin must implement this interface, it cannot be constructed directly */
+  TransformationPlugin(Transaction &transaction, Type type);
+private:
+  TransformationPluginState *state_; /** Internal state for a TransformationPlugin */
+};
+
+} /* atscppapi */
+
+
+#endif /* ATSCPPAPI_TRANSFORMATIONPLUGIN_H_ */

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7b2ea5f8/lib/atscppapi/src/include/atscppapi/Url.h
----------------------------------------------------------------------
diff --git a/lib/atscppapi/src/include/atscppapi/Url.h b/lib/atscppapi/src/include/atscppapi/Url.h
new file mode 100644
index 0000000..e056d03
--- /dev/null
+++ b/lib/atscppapi/src/include/atscppapi/Url.h
@@ -0,0 +1,149 @@
+/**
+  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.
+ */
+/**
+ * @file Url.h
+ */
+
+#pragma once
+#ifndef ATSCPPAPI_URL_H_
+#define ATSCPPAPI_URL_H_
+
+#include <string>
+#include <stdint.h>
+#include <atscppapi/noncopyable.h>
+
+namespace atscppapi {
+
+class UrlState;
+
+/**
+ * @brief This class contains all properties of a Url.
+ *
+ * You can use a Url object to get and set any property of a url.
+ *
+ * @warning Url objects should never be constructed by the user.
+ * If a user needs to create an unbound Url then they should create a Request
+ * object using Request::Request(string) which will construct a Url object for them
+ * and it can be retrieved via Request::getUrl(). A full example of this
+ * is available in examples/detachedrequest/.
+ */
+class Url: noncopyable {
+public:
+  /**
+   * @warning Url objects should never be constructed by the user.
+   * If a user needs to create an unbound Url then they should create a Request
+   * object using Request::Request(string) which will construct a Url object for them
+   * and it can be retrieved via Request::getUrl(). A full example of this
+   * is available in examples/detachedrequest/.
+   *
+   * @private
+   */
+  Url();
+
+  /**
+   * @warning Url objects should never be constructed by the user.
+   * If a user needs to create an unbound Url then they should create a Request
+   * object using Request::Request(string) which will construct a Url object for them
+   * and it can be retrieved via Request::getUrl(). A full example of this
+   * is available in examples/detachedrequest/.
+   *
+   * @private
+   */
+  Url(void *hdr_buf, void *url_loc);
+  ~Url();
+
+  /**
+   * @return The full url as a string, such a url might be http://www.linkedin.com/profile/view?id=2941
+   */
+  const std::string &getUrlString() const;
+
+  /**
+   * @return The path only portion of the url, such as /profile/view
+   */
+  const std::string &getPath() const;
+
+  /**
+   * @return The query only portion of the url, which might be id=1234
+   */
+  const std::string &getQuery() const;
+
+  /**
+   * @return The scheme of the url, this will be either http or https.
+   */
+  const std::string &getScheme() const;
+
+  /**
+   * @return The host only of the url, this might be www.linkedin.com
+   */
+  const std::string &getHost() const;
+
+  /**
+   * @return The port only portion of the url, this will likely be 80 or 443.
+   */
+  uint16_t getPort() const;
+
+  /**
+   * Set the path of the url.
+   * @param path the path portion of the url to set, this might be something like /foo/bar
+   */
+  void setPath(const std::string &);
+
+  /**
+   * Set the query param of the url.
+   * @param query the query portion of the url, this might be something like foo=bar&blah=baz.
+   */
+  void setQuery(const std::string &);
+
+  /**
+   * Set the scheme of the url
+   * @param scheme this might be either http or https.
+   */
+  void setScheme(const std::string &);
+
+  /**
+   * Set the host of the url
+   * @param host this might be something such as www.linkedin.com or www.apache.org
+   */
+  void setHost(const std::string &);
+
+  /**
+   * Set the port portion of the url.
+   * @param port this is a uint16_t which represents the port (in host order, there is no need to conver to network order). You
+   * might use a value such as 80 or 8080.
+   */
+  void setPort(const uint16_t);
+
+  /**
+   * This method allows you to reset the url, this will force the Url to fully re-read all cached values.
+   * If this method is used on a Detached Requests' Url object it will completely destroy the values.
+   *
+   * \note This method should rarely be used.
+   */
+  void reset();
+private:
+  bool isInitialized() const;
+  void init(void *hdr_buf, void *url_loc);
+  UrlState *state_;
+  friend class Request;
+  friend class ClientRequest;
+  friend class RemapPlugin;
+};
+
+}
+
+#endif /* ATSCPPAPI_URL_H_ */