You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by zw...@apache.org on 2013/10/27 22:36:26 UTC

[01/50] [abbrv] git commit: DOC: Large update of cache architure.

Updated Branches:
  refs/heads/5.0.x 15d4fb8d5 -> 44b3fb92b


DOC: Large update of cache architure.


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

Branch: refs/heads/5.0.x
Commit: 5c39d024cd6bdd3aaa1b224904d23368b7d3d614
Parents: 30fcc2b
Author: Alan M. Carroll <am...@network-geographics.com>
Authored: Mon Oct 14 09:44:51 2013 -0500
Committer: Alan M. Carroll <am...@network-geographics.com>
Committed: Mon Oct 14 20:49:07 2013 -0500

----------------------------------------------------------------------
 doc/arch/cache/cache-arch.en.rst                | 378 +++++++++++++++----
 doc/arch/cache/cache-data-structures.en.rst     |  10 +-
 .../images/ats-cache-doc-layout-pre-3-2-0.png   | Bin 7731 -> 0 bytes
 doc/arch/cache/images/ats-cache-doc-layout.png  | Bin 9470 -> 0 bytes
 doc/arch/cache/images/ats-cache-layout.jpg      | Bin 55045 -> 0 bytes
 .../cache/images/ats-cache-storage-units.png    | Bin 6190 -> 0 bytes
 .../cache/images/cache-directory-structure.png  | Bin 0 -> 28553 bytes
 .../cache/images/cache-doc-layout-3-2-0.png     | Bin 0 -> 7357 bytes
 .../cache/images/cache-doc-layout-4-0-1.png     | Bin 0 -> 8524 bytes
 doc/arch/cache/images/cache-multi-fragment.png  | Bin 0 -> 47782 bytes
 doc/arch/cache/images/cache-span-layout.png     | Bin 0 -> 8533 bytes
 doc/arch/cache/images/cache-spans.png           | Bin 0 -> 5085 bytes
 doc/arch/cache/images/cache-stripe-layout.png   | Bin 0 -> 11594 bytes
 doc/glossary.en.rst                             |  13 +-
 14 files changed, 314 insertions(+), 87 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/trafficserver/blob/5c39d024/doc/arch/cache/cache-arch.en.rst
----------------------------------------------------------------------
diff --git a/doc/arch/cache/cache-arch.en.rst b/doc/arch/cache/cache-arch.en.rst
index e249604..cc7395a 100755
--- a/doc/arch/cache/cache-arch.en.rst
+++ b/doc/arch/cache/cache-arch.en.rst
@@ -1,19 +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
- 
+   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.
+
+   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.
 
 Cache Architecture
 ******************
@@ -23,9 +23,20 @@ Cache Architecture
 Introduction
 ~~~~~~~~~~~~
 
-In addition to an HTTP proxy, |ATS| is also an HTTP cache. |TS| can cache any octet stream although it currently supports only those octet streams delivered by the HTTP protocol. When such a stream is cached it is termed an *object* in the cache. The server from which the content was retrieved is called the *origin server*. A stored object contains the octet stream content and the HTTP request and response headers. Each object is identified by a globally unique value called a *cache key*. By default this is generated by taking the `MD5 hash <http://www.openssl.org/docs/crypto/md5.html>`_ of the URI used to retrieve the content from the origin server.
+In addition to an HTTP proxy, |ATS| is also an HTTP cache. |TS| can cache any octet stream although it currently
+supports only those octet streams delivered by the HTTP protocol. When such a stream is cached (along with the HTTP
+protocol headers) it is termed an *object* in the cache. Each object is identified by a globally unique value called a
+*cache key*. By default this is generated by taking the `MD5 hash <http://www.openssl.org/docs/crypto/md5.html>`_ of the
+URI used to retrieve the content from the origin server.
+
+The purpose of this document is to describe the basic structure and implementation details of the |TS| cache.
+Configuration of the cache will be discussed only to the extent needed to understand the internal mechanisms. This
+document will be useful primarily to |TS| developers working on the |TS| codebase or plugins for |TS|. It is assumed the
+reader is already familiar with the :ref:`admin-guide` and specifically with :ref:`http-proxy-caching` and
+:ref:`configuring-the-cache` along with the associated configuration files and values.
 
-The purpose of this document is to provide implementation details of the |TS| cache. Configuration of the cache will be discussed only to the extent needed to understand the internal mechanisms. This documeint will be useful primarily to |TS| developers working on the |TS| codebase or plugins for |TS|. It is assumed the reader is already familiar with the :ref:`admin-guide` and specifically with :ref:`http-proxy-caching` and :ref:`configuring-the-cache`, along with the associated configuration files and values.
+Unfortunately the internal terminology is not particularly consistent so this document will frequently use terms in
+different ways than they are used in the code in an attempt to create some consistency.
 
 Cache Layout
 ~~~~~~~~~~~~
@@ -35,107 +46,221 @@ The first step in understanding cache operations is to understand the data struc
 Cache storage
 =============
 
-The raw storage for the |TS| cache is configured in :file:`storage.config`. This defines the "storage units" used by the cache. The storage units are treated as undifferentiated byte ranges.
+The raw storage for the |TS| cache is configured in :file:`storage.config`. Each line in the file defines a :term:`cache span` which is treated as an undifferentiated unit of storage.
 
-.. figure:: images/ats-cache-storage-units.png
+.. figure:: images/cache-spans.png
    :align: center
 
-   Example cache storage units
+   Two cache spans
 
-This storage is used by defining *volumes* in :file:`volume.config`. Volumes can be defined by a percentage of the total storage or an absolute amount of storage. Each volume is striped across the storage units so that every volume will be on every storage unit for robustness and performance.
+This storage organized in to a set of :term:`cache volume`\ s which are defined in :file:`volume.config`. Cache volumes
+can be defined by a percentage of the total storage or an absolute amount of storage. By default each cache volume is spread across all of the cache spans for robustness. The intersection of a cache volume and a cache span is a :term:`cache stripe`. Each cache span is divided in to cache stripes and each cache volume is a collection of those stripes.
 
-If the volumes for the example storage units were defined as
+If the cache volumes for the example cache spans were defined as
 
 .. image:: images/ats-cache-volume-definition.png
    :align: center
 
 then the actual layout would look like
 
-.. image:: images/ats-cache-volume-layout.png
+.. image:: images/cache-span-layout.png
    :align: center
 
-A cached object is stored entirely in a single volume and a single storage unit, objects are never split across volumes. The storage that holds a single object is called a *document*. Objects are assigned to volumes automatically based on a hash of the URI used to retrieve the object from the origin server. It is possible to configure this to a limited extent in :file:`hosting.config` which supports content from specific host or domain to be stored on specific volumes.
+A cached object is stored entirely in a single stripe, and therefore in a single cache span - objects are never split
+across cache volumes. Objects are assigned to a stripe (and hence to a cache volume) automatically based on a hash of
+the URI used to retrieve the object from the origin server. It is possible to configure this to a limited extent in
+:file:`hosting.config` which supports content from specific host or domain to be stored on specific volumes. In
+addition, as of version 4.0.1 it is possible to control which cache spans (and hence, which cache stripes) are contained
+in a specific cache volume.
 
-Volume Structure
+The layout and structure of the cache spans, the cache volumes, and the cache stripes that compose them are derived
+entirely from the :file:`storage.config` and :file:`cache.config` and is recomputed from scratch when the
+:process:`traffic_server` is started. Therefore any change to those files can (and almost always will) invalidate the
+existing cache in its entirety.
+
+Stripe Structure
 ================
 
-Volumes are treated as an undifferentiated span of bytes. Internally each stripe on each storage unit is treated almost entirely independently. The data structures described in this section are duplicated for each volume stripe, the part of a volume that resides in a single storage unit. This is how the term "volume" and :cpp:class:`Vol` are used inside the code. What a user thinks of as a volume of the cache is stored in the little used :cpp:class:`CacheVol`.
+|TS| treats the storage associated with a cache stripe as an undifferentiated span of bytes. Internally each stripe is
+treated almost entirely independently. The data structures described in this section are duplicated for each stripe.
+Interally the term "volume" is used for these stripes and implemented primarily in :cpp:class:`Vol`. What a user thinks
+of as a volume (what this document calls a "cache volume") is represented by :cpp:class:`CacheVol`.
 
-.. index: write cursor
-.. _write-cursor:
+.. note::
 
-Each storage unit in a volume is divided in to two areas -- content and directory. The directory area is used to maintain disk backups of the :ref:`in memory directory <volume-directory>`. The content area stores the actual objects and is used as a circular buffer where new documents overwrite the least recently cached documents. In particular no operating system file structure is present inside a cache volume. The location in a volume where new cache data is written is called the *write cursor*. This means that objects can be de facto evicted from cache even if they have not expired if the data is overwritten by the write cursor.
+   Stripe assignment must be done before working with an object because the directory is local to the stripe. Any cached
+   objects for which the stripe assignment is changed are effectively lost as their directory data will not be found in
+   the new stripe.
 
-.. figure:: images/ats-cache-write-cursor.png
+.. index:: cache directory
+.. _cache-directory:
+
+Cache Directory
+---------------
+
+.. index:: directory entry
+.. index:: fragment
+.. index:: cache ID
+
+.. _fragment:
+
+Content in a stripe is tracked via a directory. We call each element of the directory a "directory entry" and each is
+represented by :cpp:class:`Dir`. Each entry refers to a chunk of contiguous storage in the cache. These are referred to
+variously as "fragments", "segments", "docs" / "documents", and a few other things. This document will use the term
+"fragment" as that is the most common reference in the code. Overall the directory is treated as a hash with a "cache
+ID" as the key. A cache ID is a 128 value generated in various ways depending on context. This key is reduced and used
+as an index in to the directory to locate an entry in the standard way.
+
+The directory is used as a memory resident structure which means a directory entry is as small as possible (currently 10
+bytes). This forces some compromises on the data that can be stored there. On the hand this means that most cache misses
+do not require disk I/O which has a large performance benefit.
+
+An additional point is the directory is always fully sized. Once a stripe is initialized the directory size is
+fixed and is never changed. This size is related (roughly linearly) to the size of the stripe. It is for this reason the
+memory footprint of |TS| depends strongly on the size of the disk cache. Because the directory size does not change,
+neither does this memory requirement so |TS| does not consume more memory as more content is stored in the cache. If
+there is enough memory to run |TS| with an empty cache there is enough to run it with a full cache.
+
+.. figure:: images/cache-directory-structure.png
    :align: center
 
-   The write cursor and documents in the cache.
+Each entry stores the cache ID as the key, along with an offset in to the stripe and a size. The size stored in the
+directory entry is an :ref:`approximate size <dir-size>` which is at least as big as the actual data. Exact size data is
+stored in the fragment on disk.
 
-.. index:: volume directory
-.. _volume-directory:
+.. note::
 
-To find objects each volume has a directory of all documents in that volume. This directory is kept memory resident which means cache misses do not cause disk I/O. A side effect of this is that increasing the size of the cache (not storing more objects) increases the memory footprint of Traffic Server. Every document consumes at least one directory entry, although larger documents can require more entries.
+   Data in HTTP headers cannot be examined without disk I/O. This includes the original URL for the object. The original
+   source of the cache ID is not stored anywhere.
 
-.. index:: cache key
-.. _cache-key:
+The entries in a directory are grouped. The first level grouping is a *bucket*. This is a fixed number (currently 4 -
+defined a ``DIR_DEPTH``) of entries. The index generated from a cache ID is used as a bucket index (not an entry index).
+Buckets are grouped in to *segments*. All segments in a stripe have the same number of buckets. The number of segments
+in a stripe is chosen so that each segment has as many buckets as possible without exceeeding 65535 entries in a
+segment. Note that all segments in the same stripe will have the same number of buckets.
 
-The directory is a hash table with a 128 bit key. This kind of key is referred to as a *cache key*. The cache key for an object is used to locate the corresponding directory entry after volume assignment [#]_. This entry in turn references a span in the volume content area which contains the object header and possibly the object as well. The size stored in the directory entry is an :ref:`approximate size <dir-size>` which is at least as big as the actual data on disk. The document header on disk contains metadata for the document including the exact size of the entire document, and the HTTP headers associated with the object.
+Each entry has a previous and next index value which is used to link the entries in the same segment. The index size is
+16 bits which suffices to index any entry in the same segment. The stripe header contains an array of entry indices
+which are used as the roots of a free list. When a stripe is initialized all entries in a segment are put in the
+corresponding free list rooted in the stripe header. Entries are removed from this list when used and returned when no
+longer in use. Entries are allocated from the bucket indexed by a cache key if possible. The entries in the bucket are
+searched first and if any are on the free list, that entry is used. If none are available than the first entry on the
+segment free list is used. This entry is attached to the bucket via the same next and previous indices used for the free
+list so that it can be found when doing a lookup of a cache ID.
 
-.. note:: Data in HTTP headers cannot be examined without disk I/O. This includes the original URL for the object, as only the cache key (possibly) derived from it is stored in memory.
+Storage Layout
+--------------
 
-For persistence the directory is stored on disk in copies (A and B), one of which is "clean" and the other of which is being written from memory. These are stored in the directory section of the volume.
+The storage layout is the stripe metadata followed by cached content. The metadata consists of three parts - the stripe
+header, the directory, and the stripe footer. The metadata is stored twice. The header and the footer are instances of
+:cpp:class:`VolHeaderFooter`. This is a stub structure which can have a trailing variable sized array. This array is
+used as the segment free lists in the directory. Each contains the segment index of the first element of the free list
+for the segment. The footer is a copy of the header without the segment free lists. This makes the size of the header
+dependent on the directory but not the footer.
 
-.. figure:: images/ats-cache-volume-directory.png
+.. figure:: images/cache-stripe-layout.png
    :align: center
 
-   Volume directory structure
+Each stripe has several values that describe its basic layout.
+
+skip
+   The start of stripe data. This represents either space reserved at the start of a physical device to avoid problems
+   with the host operating system, or an offset representing use of space in the cache span by other stripes.
 
-The total size of the directory (the number of entries) is computed by taking the size of the volume and dividing by the average object size. The directory always consumes this amount of memory which has the effect that if cache size is increased so is the memory requirement for |TS|. The average object size defaults to 8000 bytes but can be configured using the value::
+start
+   The offset for the start of the content, after the stripe metadata.
+
+length
+   Total number of bytes in the stripe. :cpp:member:`Vol::len`.
+
+data length
+   Total number of blocks in the stripe available for content storage. :cpp:member:`Vol::data_blocks`.
+
+.. note:: Great care must be taken with sizes and lengths in the cache code because there are at least three different metrics (bytes, cache blocks, store blocks) used in various places.
+
+The total size of the directory (the number of entries) is computed by taking the size of the stripe and dividing by the
+average object size. The directory always consumes this amount of memory which has the effect that if cache size is
+increased so is the memory requirement for |TS|. The average object size defaults to 8000 bytes but can be configured
+using the value::
 
    proxy.config.cache.min_average_object_size
 
-in :file:`records.config`. Increasing the average object size will reduce the memory footprint of the directory at the expense of reducing the number of distinct objects that can be stored in the cache [#]_.
+in :file:`records.config`. Increasing the average object size will reduce the memory footprint of the directory at the
+expense of reducing the number of distinct objects that can be stored in the cache [#]_.
 
-.. note:: Cache data on disk is never updated.
+.. index: write cursor
+.. _write-cursor:
+
+The content area stores the actual objects and is used as a circular buffer where new objects overwrite the least
+recently cached objects. The location in a volume where new cache data is written is called the *write cursor*. This
+means that objects can be de facto evicted from cache even if they have not expired if the data is overwritten by the
+write cursor. If an object is overwritten this is not detected at that time and the directory is not updated. Instead it
+will be noted if the object is accessed in the future and the disk read of the fragment fails.
+
+.. figure:: images/ats-cache-write-cursor.png
+   :align: center
 
-This is a key thing to keep in mind. What appear to be updates (such as doing a refresh on stale content and getting back a 304) are actually new copies of data being written at the write cursor. The originals are left as "dead" space which will be consumed when the write cursor arrives at that disk location. Once the volume directory is updated (in memory!) the original object in the cache is effectively destroyed. This is the general space management techinque used in other cases as well. If an object needs to removed from cache, only its volume directory entry is changed. No other work (and *particulary* no disk I/O) needs to be done.
+   The write cursor and documents in the cache.
 
-.. [#] Because each storage unit in each volume has a separate directory, the assignment must be done before the directory lookup.
+.. note:: Cache data on disk is never updated.
 
-.. [#] An interesting potential optimization would be configuring average object size per cache volume.
+This is a key thing to keep in mind. What appear to be updates (such as doing a refresh on stale content and getting
+back a 304) are actually new copies of data being written at the write cursor. The originals are left as "dead" space
+which will be consumed when the write cursor arrives at that disk location. Once the stripe directory is updated (in
+memory!) the original fragment in the cache is effectively destroyed. This is the general space management techinque
+used in other cases as well. If an object needs to removed from cache, only the directory needs to be changed. No other
+work (and *particularly* no disk I/O) needs to be done.
 
 Object Structure
 ================
 
-Objects are stored as two types of data, metadata and content data. Metadata is all the data about the object and the content and includes the HTTP headers.  The content data is the content of the object, the actual data delivered to the client as the object.
+Objects are stored as two types of data, metadata and content data. Metadata is all the data about the object and the
+content and includes the HTTP headers. The content data is the content of the object, the octet stream delivered to the
+client as the object.
 
-Objects are rooted in a :cpp:class:Doc structure stored in the cache. This is termed the "first ``Doc``" and always contains the metadata. It is always accessed first for any object. This ``Doc`` is located by doing a lookup of the corresponding cache key in the volume directory which specifies the location and approximate size of the ``Doc``. The ``Doc`` itself has fully accurate size data of both that specific ``Doc`` and the object.
+Objects are rooted in a :cpp:class:`Doc` structure stored in the cache. :cpp:class:`Doc` serves as the header data for a
+fragment and is contained at the start of every fragment. The first fragment for an object is termed the "first ``Doc``"
+and always contains the object metadata. Any operation on the object will read this fragment first. The fragment is
+located by converting the cache key for the object to a cache ID and then doing a lookup for a directory entry with that
+key. The directory entry has the offset and approximate size of the first fragment which is then read from the disk. This fragment will contain the request header and response along with overall object properties (such as content length).
 
 .. index:: alternate
 
-|TS| supports `varying content <http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.44>`_ for objects. These are called *alternates*. All metadata for all alternates is stored in the first ``Doc`` including the set of alternates and the HTTP headers for them. This enables `alternate selection <http://trafficserver.apache.org/docs/trunk/sdk/http-hooks-and-transactions/http-alternate-selection.en.html>`_ to be done after the initial read from disk. An object that has more than one alternate will have the alternate content stored separately from the first ``Doc``. For objects with only one alternate the content may or may not be in the same (first) fragment as the metadata. Each separate alternate content is allocated a volume directory entry and the key for that entry is stored in the first ``Doc`` metadata.
+|TS| supports `varying content <http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.44>`_ for objects. These
+are called *alternates*. All metadata for all alternates is stored in the first fragment including the set of alternates
+and the HTTP headers for them. This enables `alternate selection
+<http://trafficserver.apache.org/docs/trunk/sdk/http-hooks-and-transactions/http-alternate-selection.en.html>`_ to be
+done after the initial read from disk. An object that has more than one alternate will have the alternate content stored
+separately from the first fragment. For objects with only one alternate the content may or may not be in the same (first)
+fragment as the metadata. Each separate alternate content is allocated a directory entry and the key for that
+entry is stored in the first fragment metadata.
 
-Prior to version 3.2.0 only the header data (not the fragment data) was stored in the :cpp:class:`CacheHTTPInfoVector` class which was marshaled to a variable length area of the on disk image.
+Prior to version 4.0.1 the header data was stored in the :cpp:class:`CacheHTTPInfoVector` class which was marshaled to a variable length area of the on disk image, followed by information about additional fragments if needed to store the object.
 
-.. figure:: images/ats-cache-doc-layout-pre-3-2-0.png
+.. figure:: images/cache-doc-layout-3-2-0.png
    :align: center
 
-   ``Doc`` layout, pre 3.2.0
+   ``Doc`` layout 3.2.0
 
-This had the problem that with only one fragment table it could not be reliable accurate for objects with more than one alternate [#]_. Therefore the fragment data was moved from being a separate variable length section of the metadata to being directly incorporated in to the :cpp:class:`CacheHTTPInfoVector` along with the header data, yielding a layout of the following form.
+This had the problem that with only one fragment table it could not be reliable for objects with more than one alternate
+[#]_. Therefore the fragment data was moved from being a separate variable length section of the metadata to being
+directly incorporated in to the :cpp:class:`CacheHTTPInfoVector`, yielding a layout of the following form.
 
-.. figure:: images/ats-cache-doc-layout.png
+.. figure:: images/cache-doc-layout-4-0-1.png
    :align: center
 
-   ``Doc`` layout, 3.2.0
+   ``Doc`` layout 4.0.1
+
+Each element in the vector contains for each alternate, in addition to the HTTP headers and the fragment table (if any), a cache key. This cache key identifies a directory entry that is referred to as the "earliest ``Doc``". This is the location where the content for the alternate begins.
 
-Each element in the vector contains for each alternate, in addition to the HTTP headers and the fragment table (if any), a cache key. This cache key identifies a volume directory entry that is referred to as the "earliest ``Doc``". This is the location where the content for the alternate begins.
+When the object is first cached, it will have a single alternate and that will be stored (if not too large) in first ``Doc``. This is termed a *resident alternate* in the code. This can only happen on the initial store of the object. If the metadata is updated (such as a ``304`` response to an ``If-Modified-Since`` request) then unless the object is small, the object data will be left in the original fragment and a new fragment written as the first fragment, making the alternate non-resident. "Small" is defined as less than the value :ts:cv:`proxy.config.cache.alt_rewrite_max_size`.
 
-When the object is first cached, it will have a single alternate and that will be stored (if not too large) in first ``Doc``. This is termed a *resident alternate* in the code. Resident alternates are not linked and the next time the header information is updated the object content will be separated.
+.. note::
 
-.. note:: The :cpp:class:`CacheHTTPInfoVector` is stored only in the first ``Doc``. Subsequent ``Doc`` instances will have an ``hlen`` of zero.
+   The :cpp:class:`CacheHTTPInfoVector` is stored only in the first ``Doc``. Subsequent ``Doc`` instances for the
+   object, including the earliest ``Doc``, should have an ``hlen`` of zero and if not, it is ignored.
 
-Large objects are split in to *fragments* when written to the cache. Each fragment has its own entry in the volume directory. This is indicated by a total document length that is longer than the content in first ``Doc`` or an earliest ``Doc``. In such a case a fragment offset table is stored. This contains the byte offset in the object content of the first byte of content data for each fragment past the first (as the offset for the first is always zero). This allows range requests to be serviced much more efficiently for large objects, as intermediate fragments can be skipped the first fragment with relevant data loaded next after the first/earliest ``Doc``.  The last fragment in the sequence is detected by the fragment size and offset reaching the end of the total size of the object, there is no explicit end mark. Each fragment is computationally chained from the previous in that the cache key for fragment N is computed by::
+Large objects are split in to multiple fragments when written to the cache. This is indicated by a total document length that is longer than the content in first ``Doc`` or an earliest ``Doc``. In such a case a fragment offset table is stored. This contains the byte offset in the object content of the first byte of content data for each fragment past the first (as the offset for the first is always zero). This allows range requests to be serviced much more efficiently for large objects, as intermediate fragments can be skipped the first fragment with relevant data loaded next after the first/earliest ``Doc``.  The last fragment in the sequence is detected by the fragment size and offset reaching the end of the total size of the object, there is no explicit end mark. Each fragment is computationally chained from the previous in that the cache key for fragment N is computed by::
 
    key_for_N_plus_one = next_key(key_for_N);
 
@@ -143,15 +268,23 @@ where ``next_key`` is a global function that deterministically computes a new ca
 
 Objects with multiple fragments are laid out such that the data fragments (including the earliest ``Doc``) are written first and the first ``Doc`` is written last. When read from disk, both the first and earliest ``Doc`` are validated (tested to ensure that they haven't been overwritten by the write cursor) to verify that the entire document is present on disk (as they bookend the other fragments - the write cursor cannot overwrite them without overwriting at leastone of the verified ``Doc`` instances). Note that while the fragments of a single object are ordered they are not necessarily contiguous as data from different objects are interleaved as the data arrives in |TS|.
 
-.. index:: pinned
+.. figure:: images/cache-multi-fragment.png
+   :align: center
 
-Documents which are "pinned" into the cache must not be overwritten so they are "evacuated" from in front of the write cursor. Each fragment is read and rewritten. There is a special lookup mechanism for objects that are being evacuated so that they can be found in memory rather than the potentially unreliable disk regions. The cache scans ahead of the write cursor to discover pinned objects as there is a dead zone immediately before the write cursor from which data cannot be evacuated. Evacuated data is read from disk and placed in the write queue and written as its turn comes up.
+   Multi-alternate and multi-fragment object storage
 
-It appears that objects can only be pinned via the :file:`cache.config` file and if the value::
+.. index:: pinned
 
-   proxy.config.cache.permit.pinning
+Documents which are "pinned" into the cache must not be overwritten so they are "evacuated" from in front of the write
+cursor. Each fragment is read and rewritten. There is a special lookup mechanism for objects that are being evacuated so
+that they can be found in memory rather than the potentially unreliable disk regions. The cache scans ahead of the write
+cursor to discover pinned objects as there is a dead zone immediately before the write cursor from which data cannot be
+evacuated. Evacuated data is read from disk and placed in the write queue and written as its turn comes up.
 
-is set to non-zero (it is zero by default). Objects which are in use when the write cursor is near use the same underlying evacuation mechanism but are handled automatically and not via the explicit ``pinned`` bit in :cpp:class:`Dir`.
+It appears that objects can only be pinned via the :file:`cache.config` file and if the
+:ts:cv:`proxy.config.cache.permit.pinning` is set to non-zero (it is zero by default). Objects which are in use when the
+write cursor is near use the same underlying evacuation mechanism but are handled automatically and not via the explicit
+``pinned`` bit in :cpp:class:`Dir`.
 
 .. [#] It could, under certain circumstances, be accurate for none of the alternates.
 
@@ -381,22 +514,44 @@ If this is zero then the built caclulations are used which compare the freshness
 
 If the object is not stale then it is served to the client. If stale the client request may be changed to an ``If Modified Since`` request to revalidate.
 
-The request is served using a standard virtual connection tunnel (``HttpTunnel``) with the :cpp:class:`CacheVC` acting as the producer and the client ``NetVC`` acting as the sink. If the request is a range request this can be modified with a transform to select the appropriate parts of the object or, if the request contains a single range, it can use the range acceleration.
+The request is served using a standard virtual connection tunnel (``HttpTunnel``) with the :cpp:class:`CacheVC` acting
+as the producer and the client ``NetVC`` acting as the sink. If the request is a range request this can be modified with
+a transform to select the appropriate parts of the object or, if the request contains a single range, it can use the
+range acceleration.
 
-Range acceleration is done by consulting a fragment offset table attached to the earliest ``Doc`` which contains offsets for all fragments past the first. This allows loading the fragment containing the first requested byte immediately rather than performing reads on the intermediate fragments.
+Range acceleration is done by consulting a fragment offset table attached to the earliest ``Doc`` which contains offsets
+for all fragments past the first. This allows loading the fragment containing the first requested byte immediately
+rather than performing reads on the intermediate fragments.
 
 Cache Write
 ===========
 
-Writing to cache is handled by an instance of the class :cpp:class:`CacheVC`. This is a virtual connection which receives data and writes it to cache, acting as a sink. For a standard transaction data transfers between virtual connections (*VConns*) are handled by :ccp:class:HttpTunnel. Writing to cache is done by attaching a ``CacheVC`` instance as a tunnel consumer. It therefore operates in parallel with the virtual connection that transfers data to the client. The data does not flow to the cache and then to the client, it is split and goes both directions in parallel. This avoids any data synchronization issues between the two.
+Writing to cache is handled by an instance of the class :cpp:class:`CacheVC`. This is a virtual connection which
+receives data and writes it to cache, acting as a sink. For a standard transaction data transfers between virtual
+connections (*VConns*) are handled by :cpp:class:HttpTunnel. Writing to cache is done by attaching a ``CacheVC``
+instance as a tunnel consumer. It therefore operates in parallel with the virtual connection that transfers data to the
+client. The data does not flow to the cache and then to the client, it is split and goes both directions in parallel.
+This avoids any data synchronization issues between the two.
 
 .. sidebar:: Writing to disk
 
-   The actual write to disk is handled in a separate thread dedicated to I/O operations, the AIO threads. The cache logic marshals the data and then hands the operation off to the AIO thread which signals back once the operation completes.
+   The actual write to disk is handled in a separate thread dedicated to I/O operations, the AIO threads. The cache
+   logic marshals the data and then hands the operation off to the AIO thread which signals back once the operation
+   completes.
 
-While each ``CacheVC`` handles its transactions independently, they do interact at the volume level as each ``CacheVC`` makes calls to the volume object to write its data to the volume content. The ``CacheVC`` accumulates data internally until either the transaction is complete or the amount of data to write exceeds the target fragment size. In the former case the entire object is submitted to the volume to be written. In the latter case a target fragment size amount of data is submitted and the ``CacheVC`` continues to operate on subsequent data. The volume in turn places these write requests in an holding area called the `aggregation buffer`_.
+While each ``CacheVC`` handles its transactions independently, they do interact at the volume level as each ``CacheVC``
+makes calls to the volume object to write its data to the volume content. The ``CacheVC`` accumulates data internally
+until either the transaction is complete or the amount of data to write exceeds the target fragment size. In the former
+case the entire object is submitted to the volume to be written. In the latter case a target fragment size amount of
+data is submitted and the ``CacheVC`` continues to operate on subsequent data. The volume in turn places these write
+requests in an holding area called the `aggregation buffer`_.
 
-For objects under the target fragment size there is no consideration of order, the object is simply written to the volume content. For larger objects the earliest ``Doc`` is written first and the first ``Doc`` written last. This provides some detection ability should the object be overwritten. Because of the nature of the write cursor no fragment after the first fragment (in the earliest ``Doc``) can be overwritten without also overwriting that first fragment (since we know at the time the object was finalized in the cache the write cursor was at the position of the first ``Doc``).
+For objects under the target fragment size there is no consideration of order, the object is simply written to the
+volume content. For larger objects the earliest ``Doc`` is written first and the first ``Doc`` written last. This
+provides some detection ability should the object be overwritten. Because of the nature of the write cursor no fragment
+after the first fragment (in the earliest ``Doc``) can be overwritten without also overwriting that first fragment
+(since we know at the time the object was finalized in the cache the write cursor was at the position of the first
+``Doc``).
 
 .. note:: It is the responsibility of the ``CacheVC`` to not submit writes that exceed the target fragment size.
 
@@ -411,31 +566,94 @@ Cache write also covers the case where an existing object in the cache is modifi
 * An alternate of the object is retrieved from an origin server and added to the object.
 * An alternate of the object is removed (e.g., due to a ``DELETE`` request).
 
-In every case the metadata for the object must be modified. Because |TS| never updates data already in the cache this means the first ``Doc`` will be written to the cache again and the volume directory entry updated. Because a client request has already been processed the first ``Doc`` has been read from cache and is in memory. The alternate vector is updated as appropriate (an entry added or removed, or changed to contain the new HTTP headers), and then written to disk. It is possible for multiple alternates to be updated by different ``CacheVC`` instances at the same time. The only contention is the first ``Doc``, the rest of the data for each alternate is completely independent.
+In every case the metadata for the object must be modified. Because |TS| never updates data already in the cache this
+means the first ``Doc`` will be written to the cache again and the volume directory entry updated. Because a client
+request has already been processed the first ``Doc`` has been read from cache and is in memory. The alternate vector is
+updated as appropriate (an entry added or removed, or changed to contain the new HTTP headers), and then written to
+disk. It is possible for multiple alternates to be updated by different ``CacheVC`` instances at the same time. The only
+contention is the first ``Doc``, the rest of the data for each alternate is completely independent.
 
 .. _aggregation-buffer:
 
 Aggregation Buffer
 ------------------
 
-Disk writes to cache are handled through an *aggregation buffer*. There is one for each :cpp:class:`Vol` instance.
-To minimize the number of system calls data is written to disk in units of roughly :ref:`target fragment size <target-fragment-size>` bytes. The algorithm used is simple - data is piled up in the aggregation buffer until no more will fit without going over the target fragment size, at which point the buffer is written to disk and the volume directory entries for objects with data in the buffer are updated with the actual disk locations for those objects (which are determined by the write to disk action). After the buffer is written it is cleared and process repeats. There is a special lookup table for the aggregation buffer so that object lookup can find cache data in that memory.
+Disk writes to cache are handled through an *aggregation buffer*. There is one for each :cpp:class:`Vol` instance. To
+minimize the number of system calls data is written to disk in units of roughly :ref:`target fragment size
+<target-fragment-size>` bytes. The algorithm used is simple - data is piled up in the aggregation buffer until no more
+will fit without going over the targer fragment size, at which point the buffer is written to disk and the volume
+directory entries for objects with data in the buffer are updated with the actual disk locations for those objects
+(which are determined by the write to disk action). After the buffer is written it is cleared and process repeats. There
+is a special lookup table for the aggregation buffer so that object lookup can find cache data in that memory.
 
-Because data in the aggregation buffer is visible to other parts of the cache, particularly `cache lookup`_, there is no need to push a partial filled aggregation buffer to disk. In effect any such data is effectively memory cached until enough additional cache content arrives to fill the buffer.
+Because data in the aggregation buffer is visible to other parts of the cache, particularly `cache lookup`_, there is no
+need to push a partial filled aggregation buffer to disk. In effect any such data is effectively memory cached until
+enough additional cache content arrives to fill the buffer.
 
-The target fragment size has little effect on small objects because the fragmen size is used only to parcel out disk write operations. For larger objects the effect very significant as it causes those objects to be broken up in to fragments at different locations on in the volume. Each fragment write has its own entry in the volume directory which are computationally chained (each cache key is computed from the previous one). If possible a fragment table is accumulated in the first ``Doc`` which has the offsets of the first byte for each fragment.
+The target fragment size has little effect on small objects because the fragment sized is used only to parcel out disk
+write operations. For larger objects the effect very significant as it causes those objects to be broken up in to
+fragments at different locations on in the volume. Each fragment write has its own entry in the volume directory which
+are computational chained (each cache key is computed from the previous one). If possible a fragment table is
+accumulated in the earliest ``Doc`` which has the offsets of the first byte for each fragment.
 
 Evacuation
 ----------
 
-By default the write cursor will overwrite (de facto evict from cache) objects as it proceeds once it has gone around the volume content at least once. In some cases this is not acceptable and the object is *evacuated* by reading it from the cache and then writing it back to cache which moves the physical storage of the object from in front of the write cursor to behind the write cursor. Objects that are evacuated are those that are active in either a read or write operation, or objects that are pinned [#]_.
-
-Evacuation starts by dividing up the volume content in to a set of regions of ``EVACUATION_BUCKET_SIZE`` bytes. The :cpp:member:`Vol::evacuate` member is an array with an element for each region. Each element is a doubly linked list of :cpp:class:`EvacuationBlock` instances. Each instance contains a :cpp:class:`Dir` that specifies the document to evacuate. Objects to be evacuated are described in an ``EvacuationBlock`` which is put into an evacuation bucket based on the offset of the storage location.
-
-There are two types of evacuations, reader based and forced. The ``EvacuationBlock`` has a reader count to track this. If the reader count is zero, then it is a forced evacuation and the target, if it exists, will be evacuated when the write cursor gets close. If the reader value is non-zero then it is a count of entities that are currently expecting to be able to read the object. Readers increment the count when they require read access to the object, or create the ``EvacuationBlock`` with a count of 1. When a reader is finished with the object it decrements the count and removes the ``EvacuationBlock`` if the count goes to zero. If the ``EvacuationBlock`` already exists with a count of zero, the count is not modified and the number of readers is not tracked, so the evacuation be valid as long as the object exists.
+By default the write cursor will overwrite (de facto evict from cache) objects as it proceeds once it has gone around
+the volume content at least once. In some cases this is not acceptable and the object is *evacuated* by reading it from
+the cache and then writing it back to cache which moves the physical storage of the object from in front of the write
+cursor to behind the write cursor. Objects that are evacuated are those that are active in either a read or write
+operation, or objects that are pinned [#]_.
+
+Evacuation starts by dividing up the volume content in to a set of regions of ``EVACUATION_BUCKET_SIZE`` bytes. The
+:cpp:member:`Vol::evacuate` member is an array with an element for each region. Each element is a doubly linked list of
+:cpp:class:`EvacuationBlock` instances. Each instance contains a :cpp:class:`Dir` that specifies the document to
+evacuate. Objects to be evacuated are descrinbed in an ``EvacuationBlock`` which is put in to an evacuation bucket based
+on the offset of the storage location.
+
+There are two types of evacuations, reader based and forced. The ``EvacuationBlock`` has a reader count to track this.
+If the reader count is zero, then it is a forced evacuation and the the target, if it exists, will be evacuated when the
+write cursor gets close. If the reader value is non-zero then it is a count of entities that are currently expecting to
+be able to read the object. Readers increment the count when they require read access to the object, or create the
+``EvacuationBlock`` with a count of 1. When a reader is finished with the object it decrements the count and removes the
+``EvacuationBlock`` if the count goes to zero. If the ``EvacuationBlock`` already exists with a count of zero, the count
+is not modified and the number of readers is not tracked, so the evacuation be valid as long as the object exists.
 
 Objects are evacuated as the write cursor approaches. The volume calculates the current amount of
 
 Before doing a write, the method :cpp:func:`Vol::evac_range()` is called to start an evacuation. If an eva
 
-.. [#] `Work is under way <https://issues.apache.org/jira/browse/TS-2020>`_ on extending this to include objects that are in the ram cache.
+Initialization
+==============
+
+Initialization starts with an instance of :cpp:class:`Store` reading the storage configuration file, by default
+:file:`storage.config`. For each valid element in the file an instance of :cpp:class:`Span` is created. These are of
+basically four types,
+
+* File
+* Directory
+* Disk
+* Raw device
+
+After setting all the `Span` instances they are grouped by device id to internal linked lists attached to the
+:cpp:member:`Store::disk` array [#]_. Spans that refer to the same directory, disk, or raw device are coalesced in to a
+single span. Spans that refer to the same file with overlapping offsets are also coalesced [#]_. This is all done in :c:func:`ink_cache_init()` called during startup.
+
+After configuration initialization the cache processor is started by calling :ccp:func:`CacheProcessor::start()`. This
+does a number of things.
+
+For each valid span, an instance of :cpp:class:`CacheDisk` is created. This class is a continuation and so can be used
+to perform potentially blocking operations on the span. This what is passed to the AIO threads to be called when an I/O
+operation completes. These are then dispatched to AIO threads to perform storage unit initialization. After all of those
+have completed, the resulting storage is distributed across the volumes in :c:func:`cplist_reconfigure`. The :cpp:class:`CacheVol` instances are created at this time.
+
+.. rubric:: Footnotes
+
+.. [#] `Work is under way <https://issues.apache.org/jira/browse/TS-2020>`_ on extending this to include objects that
+   are in the ram cache.
+
+.. [#] This linked list is mostly ignored in later processing, causing all but one file or directory storage units on
+   the same device to be ignored. See `TS-1869 <https://issues.apache.org/jira/browse/TS-1869>`_.
+
+.. [#] It is unclear to me how that can happen, as the offsets are computed later and should all be zero at the time the
+   spans are coalesced, and as far as I can tell the sort / coalesce is only done during initialization.

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/5c39d024/doc/arch/cache/cache-data-structures.en.rst
----------------------------------------------------------------------
diff --git a/doc/arch/cache/cache-data-structures.en.rst b/doc/arch/cache/cache-data-structures.en.rst
index 6c93ebf..6ce9bc8 100755
--- a/doc/arch/cache/cache-data-structures.en.rst
+++ b/doc/arch/cache/cache-data-structures.en.rst
@@ -5,9 +5,9 @@
   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
@@ -89,6 +89,10 @@ Cache Data Structures
 
       Array of of :cpp:class:`EvacuationBlock` buckets. This is sized so there is one bucket for every evacuation span.
 
+   .. cpp:member:: off_t len
+
+      Length of stripe in bytes.
+
 .. cpp:function:: int Vol::evac_range(off_t low, off_t high, int evac_phase)
 
    Start an evacuation if there is any :cpp:class:`EvacuationBlock` in the range from *low* to *high*. Return 0 if no evacuation was started, non-zero otherwise.
@@ -153,6 +157,8 @@ Cache Data Structures
 
       Unknown. (A checksum of some sort)
 
+.. cpp:class:: VolHeaderFooter
+
 .. rubric:: Footnotes
 
 .. [#] Changed in version 3.2.0. This previously resided in the first ``Doc`` but that caused different alternates to share the same fragment table.

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/5c39d024/doc/arch/cache/images/ats-cache-doc-layout-pre-3-2-0.png
----------------------------------------------------------------------
diff --git a/doc/arch/cache/images/ats-cache-doc-layout-pre-3-2-0.png b/doc/arch/cache/images/ats-cache-doc-layout-pre-3-2-0.png
deleted file mode 100755
index d7b2c4f..0000000
Binary files a/doc/arch/cache/images/ats-cache-doc-layout-pre-3-2-0.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/5c39d024/doc/arch/cache/images/ats-cache-doc-layout.png
----------------------------------------------------------------------
diff --git a/doc/arch/cache/images/ats-cache-doc-layout.png b/doc/arch/cache/images/ats-cache-doc-layout.png
deleted file mode 100755
index 438ed77..0000000
Binary files a/doc/arch/cache/images/ats-cache-doc-layout.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/5c39d024/doc/arch/cache/images/ats-cache-layout.jpg
----------------------------------------------------------------------
diff --git a/doc/arch/cache/images/ats-cache-layout.jpg b/doc/arch/cache/images/ats-cache-layout.jpg
deleted file mode 100644
index 3c13487..0000000
Binary files a/doc/arch/cache/images/ats-cache-layout.jpg and /dev/null differ

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/5c39d024/doc/arch/cache/images/ats-cache-storage-units.png
----------------------------------------------------------------------
diff --git a/doc/arch/cache/images/ats-cache-storage-units.png b/doc/arch/cache/images/ats-cache-storage-units.png
deleted file mode 100644
index 47e1bda..0000000
Binary files a/doc/arch/cache/images/ats-cache-storage-units.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/5c39d024/doc/arch/cache/images/cache-directory-structure.png
----------------------------------------------------------------------
diff --git a/doc/arch/cache/images/cache-directory-structure.png b/doc/arch/cache/images/cache-directory-structure.png
new file mode 100755
index 0000000..8719d1e
Binary files /dev/null and b/doc/arch/cache/images/cache-directory-structure.png differ

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/5c39d024/doc/arch/cache/images/cache-doc-layout-3-2-0.png
----------------------------------------------------------------------
diff --git a/doc/arch/cache/images/cache-doc-layout-3-2-0.png b/doc/arch/cache/images/cache-doc-layout-3-2-0.png
new file mode 100755
index 0000000..d758342
Binary files /dev/null and b/doc/arch/cache/images/cache-doc-layout-3-2-0.png differ

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/5c39d024/doc/arch/cache/images/cache-doc-layout-4-0-1.png
----------------------------------------------------------------------
diff --git a/doc/arch/cache/images/cache-doc-layout-4-0-1.png b/doc/arch/cache/images/cache-doc-layout-4-0-1.png
new file mode 100755
index 0000000..d97b154
Binary files /dev/null and b/doc/arch/cache/images/cache-doc-layout-4-0-1.png differ

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/5c39d024/doc/arch/cache/images/cache-multi-fragment.png
----------------------------------------------------------------------
diff --git a/doc/arch/cache/images/cache-multi-fragment.png b/doc/arch/cache/images/cache-multi-fragment.png
new file mode 100755
index 0000000..164d7d6
Binary files /dev/null and b/doc/arch/cache/images/cache-multi-fragment.png differ

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/5c39d024/doc/arch/cache/images/cache-span-layout.png
----------------------------------------------------------------------
diff --git a/doc/arch/cache/images/cache-span-layout.png b/doc/arch/cache/images/cache-span-layout.png
new file mode 100644
index 0000000..317d69a
Binary files /dev/null and b/doc/arch/cache/images/cache-span-layout.png differ

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/5c39d024/doc/arch/cache/images/cache-spans.png
----------------------------------------------------------------------
diff --git a/doc/arch/cache/images/cache-spans.png b/doc/arch/cache/images/cache-spans.png
new file mode 100644
index 0000000..6a5e5f8
Binary files /dev/null and b/doc/arch/cache/images/cache-spans.png differ

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/5c39d024/doc/arch/cache/images/cache-stripe-layout.png
----------------------------------------------------------------------
diff --git a/doc/arch/cache/images/cache-stripe-layout.png b/doc/arch/cache/images/cache-stripe-layout.png
new file mode 100755
index 0000000..73b4140
Binary files /dev/null and b/doc/arch/cache/images/cache-stripe-layout.png differ

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/5c39d024/doc/glossary.en.rst
----------------------------------------------------------------------
diff --git a/doc/glossary.en.rst b/doc/glossary.en.rst
index 0970090..a3180f6 100644
--- a/doc/glossary.en.rst
+++ b/doc/glossary.en.rst
@@ -40,20 +40,23 @@ Glossary
    cache volume
       Persistent storage for the cache, defined and manipulable by the user.
       Cache volumes are defined in :file:`volume.config`. A cache volume is
-      spread across :term:`storage unit`\ s to increase performance through
+      spread across :term:`cache span`\ s to increase performance through
       parallel I/O. Storage units can be split across cache volumes. Each
-      such part of a storage unit in a cache volume is a :term:`volume`.
+      such part of a storage unit in a cache volume is a :term:`cache stripe`.
 
-   volume
+   cache stripe
       A homogenous persistent store for the cache. A volume always resides
       entirely on a single physical device and is treated as an
       undifferentiated span of bytes.
 
-      See also :term:`storage unit`, :term:`cache volume`
+      See also :term:`cache span`, :term:`cache volume`
 
-   storage unit
+   cache span
       The physical storage described by a single line in :file:`storage.config`.
 
+   storage unit
+      Obsolete term for :term:`cache span`.
+
    revalidation
       Verifying that a currently cached object is still valid. This is usually done using an `If-Modified-Since
       <http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.25>`_ request which allows the origin server to


[16/50] [abbrv] initial atscppapi commit

Posted by zw...@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") };
+


[31/50] [abbrv] git commit: Added docs for proxy.config.http.cache.allow_empty_doc.

Posted by zw...@apache.org.
Added docs for proxy.config.http.cache.allow_empty_doc.


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

Branch: refs/heads/5.0.x
Commit: bb5f909639fa488c7cc890ee1f60c129acd66c67
Parents: 6c5955a
Author: Leif Hedstrom <zw...@apache.org>
Authored: Tue Oct 22 08:39:09 2013 -0600
Committer: Leif Hedstrom <zw...@apache.org>
Committed: Tue Oct 22 08:39:24 2013 -0600

----------------------------------------------------------------------
 doc/reference/configuration/records.config.en.rst | 8 ++++++++
 1 file changed, 8 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/trafficserver/blob/bb5f9096/doc/reference/configuration/records.config.en.rst
----------------------------------------------------------------------
diff --git a/doc/reference/configuration/records.config.en.rst b/doc/reference/configuration/records.config.en.rst
index f2f0497..f1f0c0c 100644
--- a/doc/reference/configuration/records.config.en.rst
+++ b/doc/reference/configuration/records.config.en.rst
@@ -959,6 +959,14 @@ Cache Control
 
    Enables (``1``) or disables (``0``) caching of HTTP requests.
 
+.. ts:cv:: CONFIG proxy.config.http.cache.allow_empty_doc INT 0
+   :reloadable:
+
+   Enables (``1``) or disables (``0``) caching objects that have an empty
+   response body. This is particularly useful for caching 301 or 302 responses
+   with a ``Location`` header but no document body. This only works if the
+   origin response also has a ``Content-Length`` header.
+
 .. ts:cv:: CONFIG proxy.config.http.cache.ignore_client_no_cache INT 0
    :reloadable:
 


[25/50] [abbrv] git commit: TS-1988 Unscrew cquuc and cquup

Posted by zw...@apache.org.
TS-1988 Unscrew cquuc and cquup

Here's what happens, and this is the same problem as with cquuh,
which I'll fix in a separate commit:

When producing log entries, we call the marshal function twice:

     first to calculate the final length of the string
     a second time to actually write the string

This two-phased behavior is controlled via the "buf" parameter. With
a NULL value, it means to only calculate the length. With the changes
made to cquuc/cquup, the lenghts were not properly calculate, which
is exactly the problem with cquuh as well.

So, it's important to always calculate the correct length, and
return that. Which is confusing, since the buf parameter seems
to have been in place to make sure we don't write to a NULL buf.


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

Branch: refs/heads/5.0.x
Commit: ea35372ef072724783c3c963917ea57790a8adae
Parents: 8f13ff5
Author: Leif Hedstrom <zw...@apache.org>
Authored: Mon Oct 21 16:53:11 2013 -0600
Committer: Leif Hedstrom <zw...@apache.org>
Committed: Mon Oct 21 16:58:01 2013 -0600

----------------------------------------------------------------------
 proxy/logging/LogAccessHttp.cc | 34 ++++++++++++++++++----------------
 1 file changed, 18 insertions(+), 16 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/trafficserver/blob/ea35372e/proxy/logging/LogAccessHttp.cc
----------------------------------------------------------------------
diff --git a/proxy/logging/LogAccessHttp.cc b/proxy/logging/LogAccessHttp.cc
index b2bfb58..ddc5c7d 100644
--- a/proxy/logging/LogAccessHttp.cc
+++ b/proxy/logging/LogAccessHttp.cc
@@ -315,18 +315,19 @@ LogAccessHttp::marshal_client_req_unmapped_url_canon(char *buf)
 {
   int len = INK_MIN_ALIGN;
 
-  if (buf) {
-    validate_unmapped_url();
-    if (0 == m_client_req_unmapped_url_canon_len) {
-      // If the unmapped URL isn't populated, we'll fall back to the original
-      // client URL. This helps for example server intercepts to continue to
-      // log the requests, even when there is no remap rule for it.
-      len = marshal_client_req_url_canon(buf);
-    } else {
-      len = round_strlen(m_client_req_unmapped_url_canon_len + 1);      // +1 for eos
+  validate_unmapped_url();
+  if (0 == m_client_req_unmapped_url_canon_len) {
+    // If the unmapped URL isn't populated, we'll fall back to the original
+    // client URL. This helps for example server intercepts to continue to
+    // log the requests, even when there is no remap rule for it.
+    len = marshal_client_req_url_canon(buf);
+  } else {
+    len = round_strlen(m_client_req_unmapped_url_canon_len + 1);      // +1 for eos
+    if (buf) {
       marshal_mem(buf, m_client_req_unmapped_url_canon_str, m_client_req_unmapped_url_canon_len, len);
     }
   }
+
   return len;
 }
 
@@ -338,13 +339,14 @@ LogAccessHttp::marshal_client_req_unmapped_url_path(char *buf)
 {
   int len = INK_MIN_ALIGN;
 
-  if (buf) {
-    validate_unmapped_url();
-    validate_unmapped_url_path();
-    if (0 == m_client_req_unmapped_url_path_len) {
-      len = marshal_client_req_url_path(buf);
-    } else {
-      len = round_strlen(m_client_req_unmapped_url_path_len + 1);   // +1 for eos
+  validate_unmapped_url();
+  validate_unmapped_url_path();
+
+  if (0 == m_client_req_unmapped_url_path_len) {
+    len = marshal_client_req_url_path(buf);
+  } else {
+    len = round_strlen(m_client_req_unmapped_url_path_len + 1);   // +1 for eos
+    if (buf) {
       marshal_mem(buf, m_client_req_unmapped_url_path_str, m_client_req_unmapped_url_path_len, len);
     }
   }


[43/50] [abbrv] git commit: automake 1.14 need subdir-objects

Posted by zw...@apache.org.
automake 1.14 need subdir-objects


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

Branch: refs/heads/5.0.x
Commit: 2482196f95da58e8b82e17ea8be4435dd648c4e7
Parents: 9dcd00b
Author: Zhao Yongming <mi...@gmail.com>
Authored: Fri Oct 25 11:17:08 2013 +0800
Committer: Zhao Yongming <mi...@gmail.com>
Committed: Fri Oct 25 11:17:08 2013 +0800

----------------------------------------------------------------------
 configure.ac | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/trafficserver/blob/2482196f/configure.ac
----------------------------------------------------------------------
diff --git a/configure.ac b/configure.ac
index b4fda1b..5efb1aa 100644
--- a/configure.ac
+++ b/configure.ac
@@ -40,7 +40,7 @@ AC_PREREQ([2.59])
 AC_CONFIG_AUX_DIR([build/aux])
 AC_CONFIG_SRCDIR([proxy/Main.cc])
 AC_CONFIG_MACRO_DIR([build])
-AM_INIT_AUTOMAKE([-Wall -Werror tar-ustar foreign no-installinfo no-installman 1.9.2])
+AM_INIT_AUTOMAKE([-Wall -Werror tar-ustar foreign no-installinfo no-installman subdir-objects 1.9.2])
 AC_CONFIG_HEADERS([lib/ts/ink_autoconf.h])
 
 # Configure with --disable-silent-rules to get verbose output. For more info, see


[50/50] [abbrv] git commit: Merge branch 'master' into 5.0.x

Posted by zw...@apache.org.
Merge branch 'master' into 5.0.x


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

Branch: refs/heads/5.0.x
Commit: 44b3fb92bb1f4b6cdb193f32eff43190e9b0aa9f
Parents: 15d4fb8 8d461ea
Author: Leif Hedstrom <zw...@apache.org>
Authored: Sun Oct 27 15:36:02 2013 -0600
Committer: Leif Hedstrom <zw...@apache.org>
Committed: Sun Oct 27 15:36:02 2013 -0600

----------------------------------------------------------------------
 CHANGES                                         |  65 +-
 Makefile.am                                     |   4 +
 NOTICE                                          |  11 +
 Vagrantfile                                     |   3 +
 ci/jenkins/jobs.yaml                            |  65 +-
 ci/regression                                   |   1 -
 configure.ac                                    |  78 +-
 doc/admin/cluster-howto.en.rst                  |  13 +-
 doc/admin/event-logging-formats.en.rst          |  13 +-
 doc/admin/http-proxy-caching.en.rst             |  29 +-
 doc/admin/security-options.en.rst               |  23 +-
 doc/arch/cache/cache-arch.en.rst                | 378 ++++++--
 doc/arch/cache/cache-data-structures.en.rst     |  10 +-
 .../images/ats-cache-doc-layout-pre-3-2-0.png   | Bin 7731 -> 0 bytes
 doc/arch/cache/images/ats-cache-doc-layout.png  | Bin 9470 -> 0 bytes
 doc/arch/cache/images/ats-cache-layout.jpg      | Bin 55045 -> 0 bytes
 .../cache/images/ats-cache-storage-units.png    | Bin 6190 -> 0 bytes
 .../cache/images/cache-directory-structure.png  | Bin 0 -> 28553 bytes
 .../cache/images/cache-doc-layout-3-2-0.png     | Bin 0 -> 7357 bytes
 .../cache/images/cache-doc-layout-4-0-1.png     | Bin 0 -> 8524 bytes
 doc/arch/cache/images/cache-multi-fragment.png  | Bin 0 -> 47782 bytes
 doc/arch/cache/images/cache-span-layout.png     | Bin 0 -> 8533 bytes
 doc/arch/cache/images/cache-spans.png           | Bin 0 -> 5085 bytes
 doc/arch/cache/images/cache-stripe-layout.png   | Bin 0 -> 11594 bytes
 doc/arch/cache/tier-storage.en.rst              |  68 +-
 doc/arch/index.en.rst                           |   8 +-
 doc/arch/proposals/hostdb.en.rst                | 168 ++++
 doc/glossary.en.rst                             |  13 +-
 doc/reference/configuration/cache.config.en.rst |   3 +
 .../configuration/records.config.en.rst         |  46 +-
 iocore/cache/Cache.cc                           | 298 ++++++-
 iocore/cache/CacheDir.cc                        |  44 +-
 iocore/cache/CacheLink.cc                       |   4 +-
 iocore/cache/CacheRead.cc                       |  10 +-
 iocore/cache/CacheVol.cc                        |   2 +-
 iocore/cache/CacheWrite.cc                      |   9 +-
 iocore/cache/I_Cache.h                          |   2 +-
 iocore/cache/P_CacheDir.h                       |   3 +
 iocore/cache/P_CacheInternal.h                  |  11 +-
 iocore/cache/P_CacheVol.h                       |  65 +-
 iocore/cache/Store.cc                           |  46 +-
 iocore/eventsystem/I_EventProcessor.h           |   2 +-
 lib/Makefile.am                                 |   6 +-
 lib/atscppapi/Makefile.am                       |  18 +
 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  |  29 +
 .../examples/clientredirect/ClientRedirect.cc   |  76 ++
 .../examples/clientredirect/Makefile.am         |  28 +
 .../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 |  28 +
 .../examples/data_caching/data_caching.cc       |  98 +++
 .../examples/detachedrequest/DetachedRequest.cc |  69 ++
 .../examples/detachedrequest/Makefile.am        |  30 +
 .../examples/globalhook/GlobalHookPlugin.cc     |  41 +
 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      |  28 +
 .../MultipleTransactionHookPlugins.cc           | 100 +++
 .../null_transformation_plugin/Makefile.am      |  30 +
 .../NullTransformationPlugin.cc                 |  77 ++
 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        |  29 +
 .../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               |  79 ++
 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                     | 215 +++++
 lib/atscppapi/src/Makefile.am                   |  85 ++
 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             | 244 +++++
 lib/cpp11api/Makefile.am                        |  37 -
 lib/cpp11api/cpp11api.cc                        | 880 -------------------
 lib/cpp11api/ts-cpp11-headers.h                 | 120 ---
 lib/cpp11api/ts-cpp11.h                         | 126 ---
 lib/records/I_RecHttp.h                         |   8 +-
 lib/records/RecHttp.cc                          |   5 +
 lib/ts/ParseRules.cc                            | 131 +++
 lib/ts/ParseRules.h                             | 206 +----
 lib/ts/Ptr.h                                    |   2 +
 lib/ts/ink_atomic.h                             |   2 +-
 lib/ts/ink_file.h                               |  18 +-
 lib/ts/ink_inet.cc                              |  60 +-
 mgmt/ProxyConfig.cc                             | 115 ++-
 mgmt/ProxyConfig.h                              |  18 +-
 mgmt/RecordsConfig.cc                           |   2 +-
 plugins/cacheurl/cacheurl.c                     |   4 +-
 plugins/experimental/Makefile.am                |   3 +-
 plugins/experimental/authproxy/authproxy.cc     |   4 +-
 .../experimental/buffer_upload/buffer_upload.cc |   8 +-
 .../experimental/channel_stats/channel_stats.cc |   4 +-
 .../custom_redirect/custom_redirect.cc          |   4 +-
 plugins/experimental/esi/combo_handler.cc       |   1 +
 .../esi/fetcher/HttpDataFetcherImpl.cc          |   1 +
 plugins/experimental/esi/lib/gzip.cc            |  11 +-
 plugins/experimental/lua/plugin.cc              |   2 +-
 .../memcached_remap/memcached_remap.cc          |   2 +-
 plugins/experimental/metalink/metalink.cc       |   4 +-
 plugins/experimental/mysql_remap/mysql_remap.cc |   2 +-
 plugins/experimental/remap_stats/Makefile.am    |  25 +
 plugins/experimental/remap_stats/remap_stats.c  | 329 +++++++
 plugins/experimental/rfc5861/rfc5861.c          | 266 +++---
 plugins/experimental/spdy/spdy.cc               |   4 +-
 plugins/gzip/misc.cc                            |   2 +-
 plugins/header_filter/header_filter.cc          |   4 +-
 plugins/header_rewrite/README                   |  75 +-
 plugins/header_rewrite/condition.cc             |   2 +-
 plugins/header_rewrite/conditions.cc            |   2 +-
 plugins/header_rewrite/factory.cc               |   8 +-
 plugins/header_rewrite/header_rewrite.cc        | 177 ++--
 plugins/header_rewrite/operator.cc              |  13 +
 plugins/header_rewrite/operator.h               |  24 +
 plugins/header_rewrite/operators.cc             | 237 +++--
 plugins/header_rewrite/operators.h              |  92 +-
 plugins/header_rewrite/parser.cc                |   4 +-
 plugins/header_rewrite/resources.h              |   2 +-
 plugins/header_rewrite/ruleset.cc               |   4 +-
 plugins/header_rewrite/value.h                  |   9 +-
 plugins/libloader/libloader.c                   |   2 +-
 plugins/regex_remap/regex_remap.cc              |   5 +-
 plugins/stats_over_http/stats_over_http.c       |   2 +-
 proxy/InkAPI.cc                                 |  19 +-
 proxy/Main.cc                                   |   2 +-
 proxy/api/ts/experimental.h                     |  16 +
 proxy/http/HttpConfig.cc                        |  21 -
 proxy/http/HttpConfig.h                         |  10 -
 proxy/http/HttpProxyServerMain.cc               |   2 +-
 proxy/http/HttpSM.cc                            |  16 +-
 proxy/http/HttpTransact.cc                      |  45 +-
 proxy/logging/Log.cc                            |  21 -
 proxy/logging/LogAccess.cc                      |  27 -
 proxy/logging/LogAccess.h                       |   3 -
 proxy/logging/LogAccessHttp.cc                  |  68 +-
 proxy/logging/LogAccessHttp.h                   |   1 +
 proxy/logging/LogConfig.cc                      |  36 +-
 proxy/logging/LogFile.cc                        |   3 +
 206 files changed, 11876 insertions(+), 2223 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/trafficserver/blob/44b3fb92/CHANGES
----------------------------------------------------------------------
diff --cc CHANGES
index 4e60198,1034fa0..7ec4706
--- a/CHANGES
+++ b/CHANGES
@@@ -1,14 -1,71 +1,77 @@@
                                                           -*- coding: utf-8 -*-
 +Changes with Apache Traffic Server 5.0.0
 +
 +  *) [TS-1919] Eliminate CacheLookupHttpConfig. This breaks cluster
 +   compatibility, so all cluster nodes should be upgraded simultaneously.
 +
 +
  Changes with Apache Traffic Server 4.1.0
  
+ 
+   *) [TS-2301] Replace the CACHE_READY macro with CacheProcessor::IsCacheReady.
+ 
+   *) [TS-2300] Remove the HIT_EVACUATE build option.
+ 
+   *) [TS-2227] Allow for multiple config files for a header_rewrite plugin
+    invocation (be it in remap.config or plugin.config).
+ 
+   *) [TS-2230] header_rewrite should support the same hook-management that
+   header_filter does for remap rules. This allows per-remap rules that
+   triggers in hooks other than the remap phase.
+ 
+   *) [TS-2228] Add a set-config operator for header_rewrite plugin.
+ 
+   *) [TS-2226] Add a set-header operator for header_rewrite plugin.
+ 
+   *) [TS-2296] improve ConfigProcessor reference counting.
+ 
+   *) [ TS-2295] update statvfs usage.
+ 
+   *) [TS-2139] Fix PURGE twice to remove object in cache if
+    enable-interim-cache.
+ 
+   *) [TS-2216] Fix cquuh log tag, which does not calculate the right
+    string length.
+ 
+   *) [TS-2275] fix interim cache lossing data if the server process crash.
+    Author: Gang Li.
+ 
+   *) [TS-2291] Add remap_stats plugin to experimental.
+ 
+   *) [TS-2242] Update core plugins' support_email and vendor_name for
+    consistency.
+ 
+   *) [TS-1988] cquuc and cquup log tags can have no values.
+ 
+   *) [TS-2159] Force first log rotation at proxy.config.log.rolling_size_mb.
+ 
+   *) [TS-2138] Fix the bug that restarting ats cause cache data loss if
+   enable the native-aio.
+ 
+   *) [TS-2197] Use HttpSM::main_handler to handle the client request stuff.
+ 
+   *) [TS-2254] On ARM arch, ink_atomic_increment returns wrong value.
+    Author: Yu Qing.
+ 
+   *) [TS-2269] regex_remap plugin does not deal with empty path's properly.
+    Author: Kit Chan.
+ 
+   *) [TS-2270] ESI Plugin can have infinite loop while doing gunzip on
+    responses. Author: Kit Chan.
+ 
+   *) [TS-2268] Add support for opening protocol traffic sockets through the 
+    traffic_manager. Added TSPluginDescriptorAccept into expiremental API.
+ 
+   *) [TS-2266] Add a "make rat" Makefile target, to create a RAT report. This
+    is used for verifying licensing compliance on the entire source tree.
+ 
+   *) [TS-2212] Implement the <fsiz> log tag for HTTP requests. This also does
+    a small refactoring of the "atoi" functions in lib/ts, such that we now
+    consistently have both prototypes for all types (with and without a
+    string length parameter).
+ 
    *) [TS-2261] Add config option to restore/elevate access to reading files by
-    root when loading plugins
+    root when loading plugins.
  
    *) [TS-2257] Healthcheck plugin can stop watching some events.
  

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/44b3fb92/iocore/cache/Cache.cc
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/44b3fb92/iocore/cache/CacheRead.cc
----------------------------------------------------------------------
diff --cc iocore/cache/CacheRead.cc
index 6b8e897,f11aee4..5dda33b
--- a/iocore/cache/CacheRead.cc
+++ b/iocore/cache/CacheRead.cc
@@@ -90,10 -90,10 +90,10 @@@ Lcallreturn
  #ifdef HTTP_CACHE
  Action *
  Cache::open_read(Continuation * cont, CacheKey * key, CacheHTTPHdr * request,
 -                 CacheLookupHttpConfig * params, CacheFragType type, char *hostname, int host_len)
 +                 void * context, CacheFragType type, char *hostname, int host_len)
  {
  
-   if (!CACHE_READY(type)) {
+   if (!CacheProcessor::IsCacheReady(type)) {
      cont->handleEvent(CACHE_EVENT_OPEN_READ_FAILED, (void *) -ECACHE_NOT_READY);
      return ACTION_RESULT_DONE;
    }

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/44b3fb92/iocore/cache/I_Cache.h
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/44b3fb92/iocore/cache/P_CacheInternal.h
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/44b3fb92/proxy/http/HttpSM.cc
----------------------------------------------------------------------


[28/50] [abbrv] git commit: Merge branch 'master' of https://git-wip-us.apache.org/repos/asf/trafficserver

Posted by zw...@apache.org.
Merge branch 'master' of https://git-wip-us.apache.org/repos/asf/trafficserver


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

Branch: refs/heads/5.0.x
Commit: 199b6b846a970d40b4146c55c65e11b2b59d6db7
Parents: e6e999e 3775c86
Author: Brian Geffon <br...@apache.org>
Authored: Mon Oct 21 17:56:21 2013 -0700
Committer: Brian Geffon <br...@apache.org>
Committed: Mon Oct 21 17:56:21 2013 -0700

----------------------------------------------------------------------
 CHANGES                                        |  3 ++
 plugins/experimental/remap_stats/remap_stats.c |  6 +--
 proxy/logging/LogAccessHttp.cc                 | 42 +++++++++++----------
 3 files changed, 28 insertions(+), 23 deletions(-)
----------------------------------------------------------------------



[12/50] [abbrv] git commit: TS-2243 document exec_thread.affinity

Posted by zw...@apache.org.
TS-2243 document exec_thread.affinity

document proxy.config.exec_thread.affinity, according to the code in
ocore/eventsystem/UnixEventProcessor.cc 160+

n.b.: I'm not documenting the default case, that treats every value that
is not 0, 2, or 3 as `1`. I couldn't find the words.

IMO, we should error out here, rather than potentially mis-interpreting
an admin's intent.


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

Branch: refs/heads/5.0.x
Commit: cc25667caedd450fc1e0d44f740be1084b30253a
Parents: 36db28d
Author: Igor Galić <i....@brainsware.org>
Authored: Fri Oct 18 11:34:33 2013 +0200
Committer: Igor Galić <i....@brainsware.org>
Committed: Fri Oct 18 11:34:33 2013 +0200

----------------------------------------------------------------------
 doc/reference/configuration/records.config.en.rst | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/trafficserver/blob/cc25667c/doc/reference/configuration/records.config.en.rst
----------------------------------------------------------------------
diff --git a/doc/reference/configuration/records.config.en.rst b/doc/reference/configuration/records.config.en.rst
index ea329e2..f2f0497 100644
--- a/doc/reference/configuration/records.config.en.rst
+++ b/doc/reference/configuration/records.config.en.rst
@@ -225,6 +225,23 @@ A value of ``0`` means no signal will be sent.
 
    The new default thread stack size, for all threads. The original default is set at 1 MB.
 
+.. ts:cv: CONFIG proxy.config.exec_thread.affinity INT 0
+
+   Bind threads to specific CPUs or CPU cores.
+
+===== ====================
+Value Effect
+===== ====================
+1     assign threads to sockets
+2     assign threads to real cores
+3     assign threads to logical cores
+0     don't assign threads to any cores
+===== ====================
+
+.. note::
+
+   This option only has an affect when Traffic Server has been compiled with ``--enable-hwloc``.
+
 Network
 =======
 


[13/50] [abbrv] initial atscppapi commit

Posted by zw...@apache.org.
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_ */


[22/50] [abbrv] git commit: TS-2275: fix interim cache lossing data if the server process crash

Posted by zw...@apache.org.
TS-2275: fix interim cache lossing data if the server process crash

we have disable the permanent storage on the interim cache device
due to consistence. that is why I point out this is #1 problem of
the current implement in
  https://blog.zymlinux.net/index.php/archives/555
as: loss data if the server process crash

after this patch, we can declare the interim cache stable


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

Branch: refs/heads/5.0.x
Commit: 64b5a6fca3a58bdd6010ad8d9ad08456a4f21ad5
Parents: 40deb91
Author: Gang Li <qu...@taobao.com>
Authored: Mon Oct 21 00:33:13 2013 +0800
Committer: Zhao Yongming <mi...@gmail.com>
Committed: Mon Oct 21 15:13:21 2013 +0800

----------------------------------------------------------------------
 CHANGES                    |   3 +
 iocore/cache/Cache.cc      | 276 ++++++++++++++++++++++++++++++++++++++--
 iocore/cache/CacheDir.cc   |  40 +++++-
 iocore/cache/CacheWrite.cc |   5 +-
 iocore/cache/P_CacheDir.h  |   3 +
 iocore/cache/P_CacheVol.h  |  65 +++++++---
 6 files changed, 361 insertions(+), 31 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/trafficserver/blob/64b5a6fc/CHANGES
----------------------------------------------------------------------
diff --git a/CHANGES b/CHANGES
index e0c3452..0a1ded9 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,9 @@
                                                          -*- coding: utf-8 -*-
 Changes with Apache Traffic Server 4.1.0
 
+  *) [TS-2275] fix interim cache lossing data if the server process crash
+   Author: Gang Li.
+
   *) [TS-2291] Add remap_stats plugin to experimental.
 
   *) [TS-2242] Update core plugins' support_email and vendor_name for

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/64b5a6fc/iocore/cache/Cache.cc
----------------------------------------------------------------------
diff --git a/iocore/cache/Cache.cc b/iocore/cache/Cache.cc
index ffd69b7..9256ea5 100644
--- a/iocore/cache/Cache.cc
+++ b/iocore/cache/Cache.cc
@@ -1163,6 +1163,24 @@ vol_init_dir(Vol *d)
   }
 }
 
+#if TS_USE_INTERIM_CACHE == 1
+void
+interimvol_clear_init(InterimCacheVol *d)
+{
+  memset(d->header, 0, sizeof(InterimVolHeaderFooter));
+  d->header->magic = VOL_MAGIC;
+  d->header->version.ink_major = CACHE_DB_MAJOR_VERSION;
+  d->header->version.ink_minor = CACHE_DB_MINOR_VERSION;
+  d->header->agg_pos = d->header->write_pos = d->start;
+  d->header->last_write_pos = d->header->write_pos;
+  d->header->phase = 0;
+  d->header->cycle = 0;
+  d->header->create_time = time(NULL);
+  d->header->dirty = 0;
+  d->sector_size = d->header->sector_size = d->disk->hw_sector_size;
+}
+#endif
+
 void
 vol_clear_init(Vol *d)
 {
@@ -1180,6 +1198,12 @@ vol_clear_init(Vol *d)
   d->header->dirty = 0;
   d->sector_size = d->header->sector_size = d->disk->hw_sector_size;
   *d->footer = *d->header;
+
+#if TS_USE_INTERIM_CACHE == 1
+  for (int i = 0; i < d->num_interim_vols; i++) {
+    interimvol_clear_init(&(d->interim_vols[i]));
+  }
+#endif
 }
 
 int
@@ -1251,11 +1275,6 @@ Vol::init(char *s, off_t blocks, off_t dir_skip, bool clear)
   header = (VolHeaderFooter *) raw_dir;
   footer = (VolHeaderFooter *) (raw_dir + vol_dirlen(this) - ROUND_TO_STORE_BLOCK(sizeof(VolHeaderFooter)));
 
-  if (clear) {
-    Note("clearing cache directory '%s'", hash_id);
-    return clear_dir();
-  }
-
 #if TS_USE_INTERIM_CACHE == 1
   num_interim_vols = good_interim_disks;
   ink_assert(num_interim_vols >= 0 && num_interim_vols <= 8);
@@ -1264,11 +1283,16 @@ Vol::init(char *s, off_t blocks, off_t dir_skip, bool clear)
     off_t vlen = off_t (r * g_interim_disks[i]->len * STORE_BLOCK_SIZE);
     vlen = (vlen / STORE_BLOCK_SIZE) * STORE_BLOCK_SIZE;
     off_t start = ink_atomic_increment(&g_interim_disks[i]->skip, vlen);
-    interim_vols[i].init(start, vlen, g_interim_disks[i], this);
+    interim_vols[i].init(start, vlen, g_interim_disks[i], this, &(this->header->interim_header[i]));
     ink_assert(interim_vols[i].start + interim_vols[i].len <= g_interim_disks[i]->len * STORE_BLOCK_SIZE);
   }
 #endif
 
+  if (clear) {
+    Note("clearing cache directory '%s'", hash_id);
+    return clear_dir();
+  }
+
   init_info = new VolInitInfo();
   int footerlen = ROUND_TO_STORE_BLOCK(sizeof(VolHeaderFooter));
   off_t footer_offset = vol_dirlen(this) - footerlen;
@@ -1349,11 +1373,30 @@ Vol::handle_dir_read(int event, void *data)
     return EVENT_DONE;
   }
   CHECK_DIR(this);
+
+  sector_size = header->sector_size;
+
 #if TS_USE_INTERIM_CACHE == 1
-  if (gn_interim_disks > 0)
-    clear_interim_dir(this);
+  if (num_interim_vols > 0) {
+    interim_done = 0;
+    for (int i = 0; i < num_interim_vols; i++) {
+      interim_vols[i].recover_data();
+    }
+  } else {
 #endif
-  sector_size = header->sector_size;
+
+  return this->recover_data();
+
+#if TS_USE_INTERIM_CACHE == 1
+  }
+#endif
+
+  return EVENT_CONT;
+}
+
+int
+Vol::recover_data()
+{
   SET_HANDLER(&Vol::handle_recover_from_data);
   return handle_recover_from_data(EVENT_IMMEDIATE, 0);
 }
@@ -1732,6 +1775,221 @@ Vol::dir_init_done(int /* event ATS_UNUSED */, void * /* data ATS_UNUSED */ )
   }
 }
 
+#if TS_USE_INTERIM_CACHE == 1
+int
+InterimCacheVol::recover_data()
+{
+  io.aiocb.aio_fildes = fd;
+  io.action = this;
+  io.thread = AIO_CALLBACK_THREAD_ANY;
+  io.then = 0;
+
+  SET_HANDLER(&InterimCacheVol::handle_recover_from_data);
+  return handle_recover_from_data(EVENT_IMMEDIATE, 0);
+}
+
+int
+InterimCacheVol::handle_recover_from_data(int event, void *data)
+{
+  (void)data;
+  uint32_t got_len = 0;
+  uint32_t max_sync_serial = header->sync_serial;
+  char *s, *e;
+  int ndone, offset;
+
+  if (event == EVENT_IMMEDIATE) {
+    if (header->magic != VOL_MAGIC || header->version.ink_major != CACHE_DB_MAJOR_VERSION) {
+      Warning("bad header in cache directory for '%s', clearing", hash_id);
+      goto Lclear;
+    } else if (header->sync_serial == 0) {
+      io.aiocb.aio_buf = NULL;
+      goto Lfinish;
+    }
+
+    // initialize
+    recover_wrapped = 0;
+    last_sync_serial = 0;
+    last_write_serial = 0;
+    recover_pos = header->last_write_pos;
+    if (recover_pos >= skip + len) {
+      recover_wrapped = 1;
+      recover_pos = start;
+    }
+
+    io.aiocb.aio_buf = (char *)ats_memalign(sysconf(_SC_PAGESIZE), RECOVERY_SIZE);
+    io.aiocb.aio_nbytes = RECOVERY_SIZE;
+    if ((off_t)(recover_pos + io.aiocb.aio_nbytes) > (off_t)(skip + len))
+      io.aiocb.aio_nbytes = (skip + len) - recover_pos;
+
+  } else if (event == AIO_EVENT_DONE) {
+    if ((size_t) io.aiocb.aio_nbytes != (size_t) io.aio_result) {
+      Warning("disk read error on recover '%s', clearing", hash_id);
+      goto Lclear;
+    }
+
+    if (io.aiocb.aio_offset == header->last_write_pos) {
+      uint32_t to_check = header->write_pos - header->last_write_pos;
+      ink_assert(to_check && to_check < (uint32_t)io.aiocb.aio_nbytes);
+      uint32_t done = 0;
+      s = (char *) io.aiocb.aio_buf;
+      while (done < to_check) {
+        Doc *doc = (Doc *) (s + done);
+        if (doc->magic != DOC_MAGIC || doc->write_serial > header->write_serial) {
+          Warning("no valid directory found while recovering '%s', clearing", hash_id);
+          goto Lclear;
+        }
+        done += round_to_approx_size(doc->len);
+        if (doc->sync_serial > last_write_serial)
+          last_sync_serial = doc->sync_serial;
+      }
+      ink_assert(done == to_check);
+
+      got_len = io.aiocb.aio_nbytes - done;
+      recover_pos += io.aiocb.aio_nbytes;
+      s = (char *) io.aiocb.aio_buf + done;
+      e = s + got_len;
+    } else {
+      got_len = io.aiocb.aio_nbytes;
+      recover_pos += io.aiocb.aio_nbytes;
+      s = (char *) io.aiocb.aio_buf;
+      e = s + got_len;
+    }
+  }
+
+  // examine what we got
+  if (got_len) {
+
+    Doc *doc = NULL;
+
+    if (recover_wrapped && start == io.aiocb.aio_offset) {
+      doc = (Doc *) s;
+      if (doc->magic != DOC_MAGIC || doc->write_serial < last_write_serial) {
+        recover_pos = skip + len - EVACUATION_SIZE;
+        goto Ldone;
+      }
+    }
+
+    while (s < e) {
+      doc = (Doc *) s;
+
+      if (doc->magic != DOC_MAGIC || doc->sync_serial != last_sync_serial) {
+
+        if (doc->magic == DOC_MAGIC) {
+          if (doc->sync_serial > header->sync_serial)
+            max_sync_serial = doc->sync_serial;
+
+          if (doc->sync_serial > last_sync_serial && doc->sync_serial <= header->sync_serial + 1) {
+            last_sync_serial = doc->sync_serial;
+            s += round_to_approx_size(doc->len);
+            continue;
+
+          } else if (recover_pos - (e - s) > (skip + len) - AGG_SIZE) {
+            recover_wrapped = 1;
+            recover_pos = start;
+            io.aiocb.aio_nbytes = RECOVERY_SIZE;
+            break;
+          }
+
+          recover_pos -= e - s;
+          goto Ldone;
+
+        } else {
+          recover_pos -= e - s;
+          if (recover_pos > (skip + len) - AGG_SIZE) {
+            recover_wrapped = 1;
+            recover_pos = start;
+            io.aiocb.aio_nbytes = RECOVERY_SIZE;
+            break;
+          }
+
+          goto Ldone;
+        }
+      }
+
+      last_write_serial = doc->write_serial;
+      s += round_to_approx_size(doc->len);
+    }
+
+    if (s >= e) {
+
+      if (s > e)
+        s -= round_to_approx_size(doc->len);
+
+      recover_pos -= e - s;
+      if (recover_pos >= skip + len)
+        recover_pos = start;
+
+      io.aiocb.aio_nbytes = RECOVERY_SIZE;
+      if ((off_t)(recover_pos + io.aiocb.aio_nbytes) > (off_t)(skip + len))
+        io.aiocb.aio_nbytes = (skip + len) - recover_pos;
+    }
+  }
+
+  if (recover_pos == prev_recover_pos)
+    goto Lclear;
+
+  prev_recover_pos = recover_pos;
+  io.aiocb.aio_offset = recover_pos;
+  ink_assert(ink_aio_read(&io));
+  return EVENT_CONT;
+
+Ldone: {
+
+    if (recover_pos == header->write_pos && recover_wrapped) {
+      goto Lfinish;
+    }
+
+    recover_pos += EVACUATION_SIZE;
+    if (recover_pos < header->write_pos && (recover_pos + EVACUATION_SIZE >= header->write_pos)) {
+      Debug("cache_init", "Head Pos: %" PRIu64 ", Rec Pos: %" PRIu64 ", Wrapped:%d", header->write_pos, recover_pos, recover_wrapped);
+      Warning("no valid directory found while recovering '%s', clearing", hash_id);
+      goto Lclear;
+    }
+
+    if (recover_pos > skip + len)
+      recover_pos -= skip + len;
+
+    uint32_t next_sync_serial = max_sync_serial + 1;
+    if (!(header->sync_serial & 1) == !(next_sync_serial & 1))
+      next_sync_serial++;
+
+    off_t clear_start = offset_to_vol_offset(this, header->write_pos);
+    off_t clear_end = offset_to_vol_offset(this, recover_pos);
+
+    if (clear_start <= clear_end)
+      dir_clean_range_interimvol(clear_start, clear_end, this);
+    else {
+      dir_clean_range_interimvol(clear_end, DIR_OFFSET_MAX, this);
+      dir_clean_range_interimvol(1, clear_start, this);
+    }
+
+    header->sync_serial = next_sync_serial;
+
+    goto Lfinish;
+  }
+
+Lclear:
+
+  interimvol_clear_init(this);
+  offset = this - vol->interim_vols;
+  clear_interimvol_dir(vol, offset);          // remove this interimvol dir
+
+Lfinish:
+
+  free((char*)io.aiocb.aio_buf);
+  io.aiocb.aio_buf = NULL;
+
+  set_io_not_in_progress();
+
+  ndone = ink_atomic_increment(&vol->interim_done, 1);
+  if (ndone == vol->num_interim_vols - 1) {         // all interim finished
+    return vol->recover_data();
+  }
+
+  return EVENT_CONT;
+}
+#endif
+
 // explicit pair for random table in build_vol_hash_table
 struct rtable_pair {
   unsigned int rval;

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/64b5a6fc/iocore/cache/CacheDir.cc
----------------------------------------------------------------------
diff --git a/iocore/cache/CacheDir.cc b/iocore/cache/CacheDir.cc
index 055e7fd..2ac5305 100644
--- a/iocore/cache/CacheDir.cc
+++ b/iocore/cache/CacheDir.cc
@@ -373,12 +373,12 @@ dir_clean_vol(Vol *d)
 
 #if TS_USE_INTERIM_CACHE == 1
 static inline void
-interim_dir_clean_bucket(Dir *b, int s, Vol *vol)
+interim_dir_clean_bucket(Dir *b, int s, Vol *vol, int offset)
 {
   Dir *e = b, *p = NULL;
   Dir *seg = dir_segment(s, vol);
   do {
-    if (dir_ininterim(e)) {
+    if (dir_ininterim(e) && dir_get_index(e) == offset) {
       e = dir_delete_entry(e, p, s, vol);
       continue;
     }
@@ -388,12 +388,12 @@ interim_dir_clean_bucket(Dir *b, int s, Vol *vol)
 }
 
 void
-clear_interim_dir(Vol *v)
+clear_interimvol_dir(Vol *v, int offset)
 {
   for (int i = 0; i < v->segments; i++) {
     Dir *seg = dir_segment(i, v);
     for (int j = 0; j < v->buckets; j++) {
-      interim_dir_clean_bucket(dir_bucket(j, seg), i, v);
+      interim_dir_clean_bucket(dir_bucket(j, seg), i, v, offset);
     }
   }
 }
@@ -437,13 +437,30 @@ dir_clean_segment(int s, InterimCacheVol *d)
   }
 }
 void
-clean_interimvol(InterimCacheVol *d)
+dir_clean_interimvol(InterimCacheVol *d)
 {
-  Warning("Note: clean interim");
   for (int i = 0; i < d->vol->segments; i++)
     dir_clean_segment(i, d);
   CHECK_DIR(d);
 }
+
+void
+dir_clean_range_interimvol(off_t start, off_t end, InterimCacheVol *svol)
+{
+  Vol *vol = svol->vol;
+  int offset = svol - vol->interim_vols;
+
+  for (int i = 0; i < vol->buckets * DIR_DEPTH * vol->segments; i++) {
+    Dir *e = dir_index(vol, i);
+    if (dir_ininterim(e) && dir_get_index(e) == offset && !dir_token(e) &&
+            dir_offset(e) >= (int64_t)start && dir_offset(e) < (int64_t)end) {
+      CACHE_DEC_DIR_USED(vol->mutex);
+      dir_set_offset(e, 0);     // delete
+    }
+  }
+
+  dir_clean_interimvol(svol);
+}
 #endif
 
 void
@@ -1068,6 +1085,12 @@ sync_cache_dir_on_shutdown(void)
       Debug("cache_dir_sync", "Periodic dir sync in progress -- overwriting");
     }
     d->footer->sync_serial = d->header->sync_serial;
+
+#if TS_USE_INTERIM_CACHE == 1
+    for (int j = 0; j < d->num_interim_vols; j++) {
+      d->interim_vols[j].header->sync_serial = d->header->sync_serial;
+    }
+#endif
     CHECK_DIR(d);
     memcpy(buf, d->raw_dir, dirlen);
     size_t B = d->header->sync_serial & 1;
@@ -1172,6 +1195,11 @@ Lrestart:
       }
       d->header->sync_serial++;
       d->footer->sync_serial = d->header->sync_serial;
+#if TS_USE_INTERIM_CACHE == 1
+      for (int j = 0; j < d->num_interim_vols; j++) {
+          d->interim_vols[j].header->sync_serial = d->header->sync_serial;
+      }
+#endif
       CHECK_DIR(d);
       memcpy(buf, d->raw_dir, dirlen);
       d->dir_sync_in_progress = 1;

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/64b5a6fc/iocore/cache/CacheWrite.cc
----------------------------------------------------------------------
diff --git a/iocore/cache/CacheWrite.cc b/iocore/cache/CacheWrite.cc
index 210e84f..841bcbf 100644
--- a/iocore/cache/CacheWrite.cc
+++ b/iocore/cache/CacheWrite.cc
@@ -1834,6 +1834,9 @@ Lagain:
     if (!mts->notMigrate) {
       old_off = dir_get_offset(&mts->dir);
       Dir old_dir = mts->dir;
+      doc->sync_serial = header->sync_serial;
+      doc->write_serial = header->write_serial;
+
       memcpy(agg_buffer + agg_buf_pos, doc, doc->len);
       off_t o = header->write_pos + agg_buf_pos;
       dir_set_offset(&mts->dir, offset_to_vol_offset(this, o));
@@ -1876,7 +1879,7 @@ Lagain:
 
       header->cycle++;
       header->agg_pos = header->write_pos;
-      clean_interimvol(this);
+      dir_clean_interimvol(this);
       goto Lagain;
     }
     return EVENT_CONT;

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/64b5a6fc/iocore/cache/P_CacheDir.h
----------------------------------------------------------------------
diff --git a/iocore/cache/P_CacheDir.h b/iocore/cache/P_CacheDir.h
index d862d51..013698a 100644
--- a/iocore/cache/P_CacheDir.h
+++ b/iocore/cache/P_CacheDir.h
@@ -28,6 +28,7 @@
 #include "P_CacheHttp.h"
 
 struct Vol;
+struct InterimCacheVol;
 struct CacheVC;
 
 /*
@@ -191,6 +192,8 @@ struct FreeDir
                           (((uint64_t)(_e)->w[4]) << 24)))
 
 void clear_interim_dir(Vol *v);
+void clear_interimvol_dir(Vol *v, int offset);
+void dir_clean_range_interimvol(off_t start, off_t end, InterimCacheVol *svol);
 
 #else
 #define dir_offset(_e) ((int64_t)                                         \

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/64b5a6fc/iocore/cache/P_CacheVol.h
----------------------------------------------------------------------
diff --git a/iocore/cache/P_CacheVol.h b/iocore/cache/P_CacheVol.h
index ba328a5..ecf2d41 100644
--- a/iocore/cache/P_CacheVol.h
+++ b/iocore/cache/P_CacheVol.h
@@ -71,6 +71,26 @@
 
 #define sizeofDoc (((uint32_t)(uintptr_t)&((Doc*)0)->checksum)+(uint32_t)sizeof(uint32_t))
 
+#if TS_USE_INTERIM_CACHE == 1
+struct InterimVolHeaderFooter
+{
+  unsigned int magic;
+  VersionNumber version;
+  time_t create_time;
+  off_t write_pos;
+  off_t last_write_pos;
+  off_t agg_pos;
+  uint32_t generation;            // token generation (vary), this cannot be 0
+  uint32_t phase;
+  uint32_t cycle;
+  uint32_t sync_serial;
+  uint32_t write_serial;
+  uint32_t dirty;
+  uint32_t sector_size;
+  int32_t unused;                // pad out to 8 byte boundary
+};
+#endif
+
 struct Cache;
 struct Vol;
 struct CacheDisk;
@@ -94,6 +114,9 @@ struct VolHeaderFooter
   uint32_t dirty;
   uint32_t sector_size;
   uint32_t unused;                // pad out to 8 byte boundary
+#if TS_USE_INTERIM_CACHE == 1
+  InterimVolHeaderFooter interim_header[8];
+#endif
   uint16_t freelist[1];
 };
 
@@ -133,6 +156,7 @@ struct EvacuationBlock
 extern int migrate_threshold;
 extern int good_interim_disks;
 
+
 union AccessEntry {
   uintptr_t v[2];
   struct {
@@ -313,8 +337,15 @@ struct MigrateToInterimCache
 
 struct InterimCacheVol: public Continuation
 {
-  VolHeaderFooter hh;
-  VolHeaderFooter *header;
+  char *hash_id;
+  InterimVolHeaderFooter *header;
+
+  off_t recover_pos;
+  off_t prev_recover_pos;
+  uint32_t last_sync_serial;
+  uint32_t last_write_serial;
+  bool recover_wrapped;
+
   off_t scan_pos;
   off_t skip; // start of headers
   off_t start; // start of data
@@ -335,6 +366,9 @@ struct InterimCacheVol: public Continuation
     return io.aiocb.aio_fildes != AIO_NOT_IN_PROGRESS;
   }
 
+  int recover_data();
+  int handle_recover_from_data(int event, void *data);
+
   void set_io_not_in_progress() {
     io.aiocb.aio_fildes = AIO_NOT_IN_PROGRESS;
   }
@@ -346,7 +380,11 @@ struct InterimCacheVol: public Continuation
     return INK_ALIGN(ll, disk->hw_sector_size);
   }
 
-  void init(off_t s, off_t l, CacheDisk *interim, Vol *v) {
+  void init(off_t s, off_t l, CacheDisk *interim, Vol *v, InterimVolHeaderFooter *hptr) {
+    const size_t hash_id_size = strlen(interim->path) + 32;
+    hash_id = (char *)ats_malloc(hash_id_size);
+    snprintf(hash_id, hash_id_size, "%s %" PRIu64 ":%" PRIu64 "", interim->path, s, l);
+
     skip = start = s;
     len = l;
     disk = interim;
@@ -355,17 +393,7 @@ struct InterimCacheVol: public Continuation
     transistor_range_threshold = len / 5; // 20% storage size for transistor
     sync = false;
 
-    header = &hh;
-    header->magic = VOL_MAGIC;
-    header->version.ink_major = CACHE_DB_MAJOR_VERSION;
-    header->version.ink_minor = CACHE_DB_MINOR_VERSION;
-    header->agg_pos = header->write_pos = start;
-    header->last_write_pos = header->write_pos;
-    header->phase = 0;
-    header->cycle = 0;
-    header->create_time = time(NULL);
-    header->dirty = 0;
-    sector_size = header->sector_size = disk->hw_sector_size;
+    header = hptr;
 
     agg_todo_size = 0;
     agg_buf_pos = 0;
@@ -379,7 +407,7 @@ struct InterimCacheVol: public Continuation
 
 void dir_clean_bucket(Dir *b, int s, InterimCacheVol *d);
 void dir_clean_segment(int s, InterimCacheVol *d);
-void clean_interimvol(InterimCacheVol *d);
+void dir_clean_interimvol(InterimCacheVol *d);
 
 #endif
 
@@ -445,6 +473,7 @@ struct Vol: public Continuation
   AccessHistory history;
   uint32_t interim_index;
   Queue<MigrateToInterimCache, MigrateToInterimCache::Link_hash_link> mig_hash[MIGRATE_BUCKETS];
+  volatile int interim_done;
 
 
   bool migrate_probe(CacheKey *key, MigrateToInterimCache **result) {
@@ -477,6 +506,8 @@ struct Vol: public Continuation
 
   void cancel_trigger();
 
+  int recover_data();
+
   int open_write(CacheVC *cont, int allow_if_writers, int max_writers);
   int open_write_lock(CacheVC *cont, int allow_if_writers, int max_writers);
   int close_write(CacheVC *cont);
@@ -500,6 +531,10 @@ struct Vol: public Continuation
   int handle_recover_write_dir(int event, void *data);
   int handle_header_read(int event, void *data);
 
+#if TS_USE_INTERIM_CACHE == 1
+  int recover_interim_vol();
+#endif
+
   int dir_init_done(int event, void *data);
 
   int dir_check(bool fix);


[46/50] [abbrv] git commit: Add OS X jenkins slave

Posted by zw...@apache.org.
Add OS X jenkins slave

Move git checkout to $WORKSPACE/src becaue we were creating an
install directory which collided with the INSTALL file on a
case-insensitive filesystem. Build the 5.0.x branch on OS X.


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

Branch: refs/heads/5.0.x
Commit: 3eb3995dfa4e0c7b233db5e7452bbaf8dbd4b634
Parents: b30aef3
Author: James Peach <jp...@apache.org>
Authored: Tue Oct 22 15:20:17 2013 -0700
Committer: James Peach <jp...@apache.org>
Committed: Fri Oct 25 18:57:40 2013 -0700

----------------------------------------------------------------------
 ci/jenkins/jobs.yaml | 65 ++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 53 insertions(+), 12 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/trafficserver/blob/3eb3995d/ci/jenkins/jobs.yaml
----------------------------------------------------------------------
diff --git a/ci/jenkins/jobs.yaml b/ci/jenkins/jobs.yaml
index 6db5bde..2047c7e 100644
--- a/ci/jenkins/jobs.yaml
+++ b/ci/jenkins/jobs.yaml
@@ -28,14 +28,13 @@
     name: linux-regression
     builders:
         - shell: |
-            git clean -d -f -x -q
             mkdir -p "${WORKSPACE}/build/${JOB_NAME}.${BUILD_NUMBER}"
             mkdir -p "${WORKSPACE}/install/${JOB_NAME}.${BUILD_NUMBER}"
-            autoreconf -fi
+            ( cd "${WORKSPACE}/src" && git clean -dfxq  && autoreconf -fi )
         - shell: |
             cd "${WORKSPACE}/build/${JOB_NAME}.${BUILD_NUMBER}"
             export DEB_BUILD_HARDENING
-            "${WORKSPACE}"/configure --prefix="${WORKSPACE}/install/${JOB_NAME}.${BUILD_NUMBER}" --enable-experimental-plugins $ENABLE_WCCP $ENABLE_DEBUG $ENABLE_EXPERIMENTAL
+            "${WORKSPACE}"/src/configure --prefix="${WORKSPACE}/install/${JOB_NAME}.${BUILD_NUMBER}" --enable-experimental-plugins $ENABLE_WCCP $ENABLE_DEBUG $ENABLE_EXPERIMENTAL
             make -j2 V=1
             make check
             make install
@@ -49,17 +48,16 @@
     name: linux-clang-regression
     builders:
         - shell: |
-            git clean -d -f -x -q
             mkdir -p "${WORKSPACE}/build/${JOB_NAME}.${BUILD_NUMBER}"
             mkdir -p "${WORKSPACE}/install/${JOB_NAME}.${BUILD_NUMBER}"
-            autoreconf -fi
+            ( cd "${WORKSPACE}/src" && git clean -dfxq  && autoreconf -fi )
         - shell: |
             cd "${WORKSPACE}/build/${JOB_NAME}.${BUILD_NUMBER}"
             export CC=clang
             export CXX=clang++
             export CXXFLAGS="-Qunused-arguments -std=c++11"
             export WITH_LIBCPLUSPLUS=yes
-            "${WORKSPACE}"/configure --prefix="${WORKSPACE}/install/${JOB_NAME}.${BUILD_NUMBER}" --enable-experimental-plugins $ENABLE_WCCP $ENABLE_DEBUG $ENABLE_EXPERIMENTAL
+            "${WORKSPACE}"/src/configure --prefix="${WORKSPACE}/install/${JOB_NAME}.${BUILD_NUMBER}" --enable-experimental-plugins $ENABLE_WCCP $ENABLE_DEBUG $ENABLE_EXPERIMENTAL
             make -j2 V=1
             make check
             make install
@@ -75,13 +73,12 @@
     name: bsd-regression
     builders:
         - shell: |
-            git clean -d -f -x -q
             mkdir -p "${WORKSPACE}/install/${JOB_NAME}.${BUILD_NUMBER}"
             mkdir -p "${WORKSPACE}/build/${JOB_NAME}.${BUILD_NUMBER}"
-            autoreconf -fi
+            ( cd "${WORKSPACE}/src" && git clean -dfxq  && autoreconf -fi )
         - shell: |
             cd "${WORKSPACE}/build/${JOB_NAME}.${BUILD_NUMBER}"
-            "${WORKSPACE}"/configure --prefix="${WORKSPACE}/install/${JOB_NAME}.${BUILD_NUMBER}" --enable-experimental-plugins $ENABLE_DEBUG
+            "${WORKSPACE}"/src/configure --prefix="${WORKSPACE}/install/${JOB_NAME}.${BUILD_NUMBER}" --enable-experimental-plugins $ENABLE_DEBUG
             gmake -j2 V=1
             gmake check
             gmake install
@@ -95,10 +92,9 @@
     name: 'omnios-regression'
     builders:
         - shell: |
-            git clean -d -f -x -q
             mkdir -p "${WORKSPACE}/install/${JOB_NAME}.${BUILD_NUMBER}"
             mkdir -p "${WORKSPACE}/build/${JOB_NAME}.${BUILD_NUMBER}"
-            autoreconf -fi
+            ( cd "${WORKSPACE}/src" && git clean -dfxq  && autoreconf -fi )
         - shell: |
             cd "${WORKSPACE}/build/${JOB_NAME}.${BUILD_NUMBER}"
             export PATH=/sbin:~/bin:/usr/local/bin:/usr/sbin:/usr/bin:/opt/omni/bin:/opt/gcc-4.6.3/bin/:/usr/ucb:/usr/ccs/bin:/usr/sfw/bin:/usr/dt/bin:/usr/openwin/bin
@@ -109,7 +105,7 @@
             export CXXFLAGS=-m64
             export CPPFLAGS=-I/opt/omni/include
             export LDFLAGS="-L/opt/omni/lib/amd64 -R/opt/omni/lib/amd64"
-            "${WORKSPACE}"/configure --prefix="${WORKSPACE}/install/${JOB_NAME}.${BUILD_NUMBER}"  --with-tcl=/opt/omni/lib/amd64 --enable-experimental-plugins $ENABLE_DEBUG $ENABLE_EXPERIMENTAL
+            "${WORKSPACE}"/src/configure --prefix="${WORKSPACE}/install/${JOB_NAME}.${BUILD_NUMBER}"  --with-tcl=/opt/omni/lib/amd64 --enable-experimental-plugins $ENABLE_DEBUG $ENABLE_EXPERIMENTAL
             gmake -j2 V=1
             gmake check
             gmake install
@@ -145,6 +141,7 @@
     scm:
         - git:
             url: '{repo}'
+            basedir: 'src'
             branches:
                 - '{branch}'
     builders:
@@ -176,6 +173,7 @@
     scm:
         - git:
             url: '{repo}'
+            basedir: 'src'
             branches:
                 - '{branch}'
     builders:
@@ -778,4 +776,47 @@
             debug: --enable-debug
             repo: file:///home/jenkins/git/trafficserver_4.0
 
+- project:
+    name: mac-os-x
+    node: mac_os_x
+    builder: linux
+    tag: normal
+    wccp: --enable-wccp
+    debug: --disable-debug
+    hardening: '0'
+    experimental: ''
+    jobs:
+        - '{node}-{branch}-{tag}-regression':
+            branch: master
+            tag: debug
+            debug: --enable-debug
+            repo: file:///Users/jenkins/git/trafficserver
+        - '{node}-{branch}-{tag}-regression':
+            branch: master
+            repo: file:///Users/jenkins/git/trafficserver
+        - '{node}-{branch}-{tag}-regression':
+            branch: 3.2.x
+            repo: file:///Users/jenkins/git/trafficserver_3.2
+        - '{node}-{branch}-{tag}-regression':
+            branch: 3.2.x
+            tag: debug
+            debug: --enable-debug
+            repo: file:///Users/jenkins/git/trafficserver_3.2
+        - '{node}-{branch}-{tag}-regression':
+            branch: 4.0.x
+            repo: file:///Users/jenkins/git/trafficserver_4.0
+        - '{node}-{branch}-{tag}-regression':
+            branch: 4.0.x
+            tag: debug
+            debug: --enable-debug
+            repo: file:///Users/jenkins/git/trafficserver_4.0
+        - '{node}-{branch}-{tag}-regression':
+            branch: 5.0.x
+            repo: file:///Users/jenkins/git/trafficserver_5.0
+        - '{node}-{branch}-{tag}-regression':
+            branch: 5.0.x
+            tag: debug
+            debug: --enable-debug
+            repo: file:///Users/jenkins/git/trafficserver_5.0
+
 # vim: sw=4 ts=4 et ft=yaml :


[24/50] [abbrv] git commit: TS-2291: Fix compiler warning about unused variable.

Posted by zw...@apache.org.
TS-2291: Fix compiler warning about unused variable.


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

Branch: refs/heads/5.0.x
Commit: 8f13ff5b51896e56838ea7c69f7030effd10f114
Parents: 1f829e2
Author: Phil Sorber <so...@apache.org>
Authored: Mon Oct 21 13:06:25 2013 -0600
Committer: Phil Sorber <so...@apache.org>
Committed: Mon Oct 21 13:06:25 2013 -0600

----------------------------------------------------------------------
 plugins/experimental/remap_stats/remap_stats.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/trafficserver/blob/8f13ff5b/plugins/experimental/remap_stats/remap_stats.c
----------------------------------------------------------------------
diff --git a/plugins/experimental/remap_stats/remap_stats.c b/plugins/experimental/remap_stats/remap_stats.c
index 23c93cd..9922ea8 100644
--- a/plugins/experimental/remap_stats/remap_stats.c
+++ b/plugins/experimental/remap_stats/remap_stats.c
@@ -131,7 +131,7 @@ create_stat_name(char *hostname, char *basename)
 }
 
 static int
-handle_read_req_hdr(TSCont cont, TSEvent event, void *edata)
+handle_read_req_hdr(TSCont cont, TSEvent event ATS_UNUSED, void *edata)
 {
     TSHttpTxn txn = (TSHttpTxn) edata;
     config_t *config;
@@ -149,7 +149,7 @@ handle_read_req_hdr(TSCont cont, TSEvent event, void *edata)
 }
 
 static int
-handle_post_remap(TSCont cont, TSEvent event, void *edata)
+handle_post_remap(TSCont cont, TSEvent event ATS_UNUSED, void *edata)
 {
     TSHttpTxn txn = (TSHttpTxn) edata;
     config_t *config;
@@ -176,7 +176,7 @@ handle_post_remap(TSCont cont, TSEvent event, void *edata)
 }
 
 static int
-handle_txn_close(TSCont cont, TSEvent event, void *edata)
+handle_txn_close(TSCont cont, TSEvent event ATS_UNUSED, void *edata)
 {
     TSHttpTxn txn = (TSHttpTxn) edata;
     config_t *config;


[36/50] [abbrv] git commit: Add simple unit tests for ats_ip_parse()

Posted by zw...@apache.org.
Add simple unit tests for ats_ip_parse()


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

Branch: refs/heads/5.0.x
Commit: 5460ce5b5b490053ab7ed747531ffa3eb74e52fa
Parents: a3d1208
Author: James Peach <jp...@apache.org>
Authored: Fri Sep 20 16:05:39 2013 -0700
Committer: James Peach <jp...@apache.org>
Committed: Tue Oct 22 20:47:22 2013 -0700

----------------------------------------------------------------------
 lib/ts/ink_inet.cc | 60 +++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 48 insertions(+), 12 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/trafficserver/blob/5460ce5b/lib/ts/ink_inet.cc
----------------------------------------------------------------------
diff --git a/lib/ts/ink_inet.cc b/lib/ts/ink_inet.cc
index 7ec7c6a..397e7da 100644
--- a/lib/ts/ink_inet.cc
+++ b/lib/ts/ink_inet.cc
@@ -473,6 +473,9 @@ ats_ip_check_characters(ts::ConstBuffer text) {
     ;
 }
 
+// Need to declare this type globally so gcc 4.4 can use it in the countof() template ...
+struct ip_parse_spec { const char * hostspec; const char * host; const char * port; };
+
 REGRESSION_TEST(Ink_Inet) (RegressionTest * t, int /* atype */, int * pstatus) {
   TestBox box(t, pstatus);
   IpEndpoint  ep;
@@ -480,18 +483,51 @@ REGRESSION_TEST(Ink_Inet) (RegressionTest * t, int /* atype */, int * pstatus) {
 
   box = REGRESSION_TEST_PASSED;
 
-  box.check(ats_ip_pton("76.14.64.156", &ep.sa) == 0, "ats_ip_pton()");
-  box.check(addr.load("76.14.64.156") == 0, "IpAddr::load()");
-  box.check(addr.family() == ep.family(), "mismatched address family");
+  // Test ats_ip_parse() ...
+  {
+    struct ip_parse_spec names[] = {
+      { "::", "::", NULL },
+      { "[::1]:99", "::1", "99" },
+      { "127.0.0.1:8080", "127.0.0.1", "8080" },
+      { "foo.example.com", "foo.example.com", NULL },
+      { "foo.example.com:99", "foo.example.com", "99" },
+    };
+
+    for (unsigned i = 0; i < countof(names); ++i) {
+      ts::ConstBuffer addr, port;
+
+      box.check(ats_ip_parse(ts::ConstBuffer(names[i].hostspec, strlen(names[i].hostspec)), &addr, &port) == 0,
+          "ats_ip_parse(%s)", names[i].hostspec);
+      box.check(strncmp(addr.data(), names[i].host, addr.size()) ==  0,
+          "ats_ip_parse(%s) gave addr '%.*s'", names[i].hostspec, addr.size(), addr.data());
+      if (names[i].port) {
+        box.check(strncmp(port.data(), names[i].port, port.size()) ==  0,
+          "ats_ip_parse(%s) gave port '%.*s'", names[i].hostspec, port.size(), port.data());
+      } else {
+        box.check(port.size() == 0,
+          "ats_ip_parse(%s) gave port '%.*s'", names[i].hostspec, port.size(), port.data());
+      }
 
-  switch (addr.family()) {
-  case AF_INET:
-    box.check(ep.sin.sin_addr.s_addr == addr._addr._ip4, "IPv4 address mismatch");
-    break;
-  case AF_INET6:
-    box.check(memcmp(&ep.sin6.sin6_addr, &addr._addr._ip6, sizeof(in6_addr)) == 0, "IPv6 address mismatch");
-    break;
-  default:
-    ;
+    }
   }
+
+  // Test ats_ip_pton() ...
+  {
+    box.check(ats_ip_pton("76.14.64.156", &ep.sa) == 0, "ats_ip_pton()");
+    box.check(addr.load("76.14.64.156") == 0, "IpAddr::load()");
+    box.check(addr.family() == ep.family(), "mismatched address family");
+
+    switch (addr.family()) {
+    case AF_INET:
+      box.check(ep.sin.sin_addr.s_addr == addr._addr._ip4, "IPv4 address mismatch");
+      break;
+    case AF_INET6:
+      box.check(memcmp(&ep.sin6.sin6_addr, &addr._addr._ip6, sizeof(in6_addr)) == 0, "IPv6 address mismatch");
+      break;
+    default:
+      ;
+    }
+  }
+
+
 }


[27/50] [abbrv] git commit: Fixing build for os x

Posted by zw...@apache.org.
Fixing build for os x


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

Branch: refs/heads/5.0.x
Commit: e6e999e782f0b8c43deafb0befbfabe324670f9f
Parents: 1f829e2
Author: Brian Geffon <br...@apache.org>
Authored: Mon Oct 21 17:55:53 2013 -0700
Committer: Brian Geffon <br...@apache.org>
Committed: Mon Oct 21 17:55:53 2013 -0700

----------------------------------------------------------------------
 lib/atscppapi/Makefile.am     |  1 -
 lib/atscppapi/src/Makefile.am | 14 +++++++++++---
 2 files changed, 11 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/trafficserver/blob/e6e999e7/lib/atscppapi/Makefile.am
----------------------------------------------------------------------
diff --git a/lib/atscppapi/Makefile.am b/lib/atscppapi/Makefile.am
index 028d09c..166edb9 100644
--- a/lib/atscppapi/Makefile.am
+++ b/lib/atscppapi/Makefile.am
@@ -14,6 +14,5 @@
 #  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/e6e999e7/lib/atscppapi/src/Makefile.am
----------------------------------------------------------------------
diff --git a/lib/atscppapi/src/Makefile.am b/lib/atscppapi/src/Makefile.am
index 52085d0..4e7d204 100644
--- a/lib/atscppapi/src/Makefile.am
+++ b/lib/atscppapi/src/Makefile.am
@@ -15,11 +15,19 @@
 #  See the License for the specific language governing permissions and
 #  limitations under the License.
 
-AM_CXXFLAGS = -Iinclude
+TS_PLUGIN_CPPFLAGS = \
+  -D__STDC_LIMIT_MACROS=1 \
+  -D__STDC_FORMAT_MACROS=1 \
+  -I$(top_builddir)/proxy/api \
+  -I$(top_srcdir)/proxy/api \
+  -I$(top_builddir)/lib/ts \
+  -I$(top_srcdir)/lib/ts
+
+AM_CXXFLAGS = -Iinclude $(TS_PLUGIN_CPPFLAGS)
 
 # build the library
 lib_LTLIBRARIES = libatscppapi.la
-libatscppapi_la_LDFLAGS=-lz -lpthread -lrt -version-info @TS_LIBTOOL_VERSION@
+libatscppapi_la_LDFLAGS=-lz -lpthread -version-info @TS_LIBTOOL_VERSION@
 
 libatscppapi_la_SOURCES = GlobalPlugin.cc \
 			  Plugin.cc \
@@ -74,4 +82,4 @@ library_include_HEADERS = $(base_include_folder)/GlobalPlugin.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
+			  $(base_include_folder)/AsyncTimer.h


[23/50] [abbrv] git commit: Fix g++ compiler warnings

Posted by zw...@apache.org.
Fix g++ compiler warnings


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

Branch: refs/heads/5.0.x
Commit: 1f829e268620ae0181c7542d6e7b253b71a40ddc
Parents: 64b5a6f
Author: Brian Geffon <br...@apache.org>
Authored: Mon Oct 21 11:54:36 2013 -0700
Committer: Brian Geffon <br...@apache.org>
Committed: Mon Oct 21 11:54:36 2013 -0700

----------------------------------------------------------------------
 lib/atscppapi/src/AsyncHttpFetch.cc            |  2 +-
 lib/atscppapi/src/GlobalPlugin.cc              |  3 ++-
 lib/atscppapi/src/GzipDeflateTransformation.cc | 14 +++++++-------
 lib/atscppapi/src/GzipInflateTransformation.cc |  4 ++--
 lib/atscppapi/src/Headers.cc                   |  6 +++---
 lib/atscppapi/src/Logger.cc                    |  6 ++++--
 lib/atscppapi/src/TransformationPlugin.cc      | 16 ++++++++--------
 lib/atscppapi/src/utils_internal.cc            |  4 +---
 8 files changed, 28 insertions(+), 27 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/trafficserver/blob/1f829e26/lib/atscppapi/src/AsyncHttpFetch.cc
----------------------------------------------------------------------
diff --git a/lib/atscppapi/src/AsyncHttpFetch.cc b/lib/atscppapi/src/AsyncHttpFetch.cc
index 51ca95d..3fd798d 100644
--- a/lib/atscppapi/src/AsyncHttpFetch.cc
+++ b/lib/atscppapi/src/AsyncHttpFetch.cc
@@ -82,7 +82,7 @@ static int handleFetchEvents(TSCont cont, TSEvent event, void *edata) {
       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_);
+      LOG_DEBUG("Fetch result had a status code of %d with a body length of %ld", status, state->body_size_);
     } else {
       LOG_ERROR("Unable to parse response; Request URL [%s]; transaction %p",
                 state->request_.getUrl().getUrlString().c_str(), txn);

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/1f829e26/lib/atscppapi/src/GlobalPlugin.cc
----------------------------------------------------------------------
diff --git a/lib/atscppapi/src/GlobalPlugin.cc b/lib/atscppapi/src/GlobalPlugin.cc
index 40cd9e8..b2d8581 100644
--- a/lib/atscppapi/src/GlobalPlugin.cc
+++ b/lib/atscppapi/src/GlobalPlugin.cc
@@ -34,8 +34,9 @@ using namespace atscppapi;
  */
 struct atscppapi::GlobalPluginState : noncopyable {
   TSCont cont_;
-  bool ignore_internal_transactions_;
   GlobalPlugin *global_plugin_;
+  bool ignore_internal_transactions_;
+
   GlobalPluginState(GlobalPlugin *global_plugin, bool ignore_internal_transactions)
     : global_plugin_(global_plugin), ignore_internal_transactions_(ignore_internal_transactions) { }
 };

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/1f829e26/lib/atscppapi/src/GzipDeflateTransformation.cc
----------------------------------------------------------------------
diff --git a/lib/atscppapi/src/GzipDeflateTransformation.cc b/lib/atscppapi/src/GzipDeflateTransformation.cc
index 5d701c8..40d0d94 100644
--- a/lib/atscppapi/src/GzipDeflateTransformation.cc
+++ b/lib/atscppapi/src/GzipDeflateTransformation.cc
@@ -43,8 +43,8 @@ const int ONE_KB = 1024;
 struct atscppapi::transformations::GzipDeflateTransformationState: noncopyable {
   z_stream z_stream_;
   bool z_stream_initialized_;
-  int64_t bytes_produced_;
   TransformationPlugin::Type transformation_type_;
+  int64_t bytes_produced_;
 
   GzipDeflateTransformationState(TransformationPlugin::Type type) :
         z_stream_initialized_(false), transformation_type_(type), bytes_produced_(0) {
@@ -93,29 +93,29 @@ void GzipDeflateTransformation::consume(const string &data) {
 
   // 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();
+  unsigned long buffer_size = data.length() < static_cast<string::size_type>(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());
+    LOG_DEBUG("Iteration %d: Deflate will compress %ld 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);
+      LOG_ERROR("Iteration %d: Deflate failed to compress %ld 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);
+    LOG_DEBUG("Iteration %d: Deflate compressed %ld 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);
+    LOG_ERROR("Inflate finished with data still remaining in the buffer of size '%u'", state_->z_stream_.avail_in);
   }
 }
 
@@ -148,7 +148,7 @@ void GzipDeflateTransformation::handleInputComplete() {
 
   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);
+    LOG_ERROR("Gzip bytes produced sanity check failed, deflated bytes = %ld != written bytes = %ld", state_->bytes_produced_, bytes_written);
   }
 }
 

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/1f829e26/lib/atscppapi/src/GzipInflateTransformation.cc
----------------------------------------------------------------------
diff --git a/lib/atscppapi/src/GzipInflateTransformation.cc b/lib/atscppapi/src/GzipInflateTransformation.cc
index 931e6e8..1962e97 100644
--- a/lib/atscppapi/src/GzipInflateTransformation.cc
+++ b/lib/atscppapi/src/GzipInflateTransformation.cc
@@ -47,7 +47,7 @@ struct atscppapi::transformations::GzipInflateTransformationState: noncopyable {
   TransformationPlugin::Type transformation_type_;
 
   GzipInflateTransformationState(TransformationPlugin::Type type) :
-        z_stream_initialized_(false), transformation_type_(type), bytes_produced_(0) {
+        z_stream_initialized_(false), bytes_produced_(0), transformation_type_(type) {
 
     memset(&z_stream_, 0, sizeof(z_stream_));
 
@@ -122,7 +122,7 @@ void GzipInflateTransformation::consume(const string &data) {
 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);
+    LOG_ERROR("Gzip bytes produced sanity check failed, inflated bytes = %ld != written bytes = %ld", state_->bytes_produced_, bytes_written);
   }
 }
 

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/1f829e26/lib/atscppapi/src/Headers.cc
----------------------------------------------------------------------
diff --git a/lib/atscppapi/src/Headers.cc b/lib/atscppapi/src/Headers.cc
index c4da326..0c07923 100644
--- a/lib/atscppapi/src/Headers.cc
+++ b/lib/atscppapi/src/Headers.cc
@@ -122,8 +122,8 @@ bool Headers::checkAndInitHeaders() const {
   }
   state_->name_values_map_.getValueRef().clear();
   string key;
-  const char *name, *value;
-  int name_len, num_values, value_len;
+  const char *name;
+  int name_len;
   pair<NameValuesMap::iterator, bool> insert_result;
   TSMLoc field_loc = TSMimeHdrFieldGet(state_->hdr_buf_, state_->hdr_loc_, FIRST_INDEX);
   while (field_loc) {
@@ -455,7 +455,7 @@ bool Headers::addCookie(const ResponseCookie &response_cookie) {
     return false;
   }
   if (!checkAndInitHeaders()) {
-    false;
+    return false;
   }
   // @TODO Do logic here
   return true;

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/1f829e26/lib/atscppapi/src/Logger.cc
----------------------------------------------------------------------
diff --git a/lib/atscppapi/src/Logger.cc b/lib/atscppapi/src/Logger.cc
index a7c18d5..c08202a 100644
--- a/lib/atscppapi/src/Logger.cc
+++ b/lib/atscppapi/src/Logger.cc
@@ -175,6 +175,8 @@ void Logger::flush() {
 namespace {
 const int DEFAULT_BUFFER_SIZE_FOR_VARARGS = 8*1024;
 
+// We use a macro here because varargs would be a pain to forward via a helper
+// function
 #define TS_TEXT_LOG_OBJECT_WRITE(level) \
     char buffer[DEFAULT_BUFFER_SIZE_FOR_VARARGS]; \
     int n; \
@@ -183,11 +185,11 @@ const int DEFAULT_BUFFER_SIZE_FOR_VARARGS = 8*1024;
      va_start(ap, fmt); \
      n = vsnprintf (&buffer[0], sizeof(buffer), fmt, ap); \
      va_end(ap); \
-     if (n > -1 && n < sizeof(buffer)) { \
+     if (n > -1 && n < static_cast<int>(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)); \
+       LOG_ERROR("Unable to log " level " message to '%s' due to size exceeding %lud bytes.", state_->filename_.c_str(), sizeof(buffer)); \
      } \
      return; \
     }

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/1f829e26/lib/atscppapi/src/TransformationPlugin.cc
----------------------------------------------------------------------
diff --git a/lib/atscppapi/src/TransformationPlugin.cc b/lib/atscppapi/src/TransformationPlugin.cc
index 2fcb899..75a6706 100644
--- a/lib/atscppapi/src/TransformationPlugin.cc
+++ b/lib/atscppapi/src/TransformationPlugin.cc
@@ -91,7 +91,7 @@ int handleTransformationPluginRead(TSCont contp, TransformationPluginState *stat
   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);
+    LOG_DEBUG("Transformation contp=%p write_vio=%p, to_read=%ld", contp, write_vio, to_read);
 
     if (to_read > 0) {
       /*
@@ -99,11 +99,11 @@ int handleTransformationPluginRead(TSCont contp, TransformationPluginState *stat
        * 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);
+      LOG_DEBUG("Transformation contp=%p write_vio=%p, to_read=%ld, buffer reader avail=%ld", 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);
+        LOG_DEBUG("Transformation contp=%p write_vio=%p, to read > avail, fixing to_read to be equal to avail. to_read=%ld, buffer reader avail=%ld", contp, write_vio, to_read, avail);
       }
 
       if (to_read > 0) {
@@ -122,7 +122,7 @@ int handleTransformationPluginRead(TSCont contp, TransformationPluginState *stat
         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());
+        LOG_DEBUG("Transformation contp=%p write_vio=%p consumed %ld bytes from bufferreader", contp, write_vio, in_data.length());
 
         /* Clean up the buffer and reader */
         TSIOBufferReaderFree(input_reader);
@@ -232,7 +232,7 @@ TransformationPlugin::~TransformationPlugin() {
 }
 
 size_t TransformationPlugin::produce(const std::string &data) {
-  LOG_DEBUG("TransformationPlugin=%p tshttptxn=%p producing output with length=%d", this, state_->txn_, data.length());
+  LOG_DEBUG("TransformationPlugin=%p tshttptxn=%p producing output with length=%ld", this, state_->txn_, data.length());
   int64_t write_length = static_cast<int64_t>(data.length());
   if (!write_length) {
     return 0;
@@ -261,11 +261,11 @@ size_t TransformationPlugin::produce(const std::string &data) {
   // 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_);
+  LOG_DEBUG("TransformationPlugin=%p tshttptxn=%p write to TSIOBuffer %ld bytes total bytes written %ld", 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);
+    LOG_ERROR("TransformationPlugin=%p tshttptxn=%p bytes written < expected. bytes_written=%ld write_length=%ld", this, state_->txn_, bytes_written, write_length);
   }
 
   int connection_closed = TSVConnClosedGet(state_->vconn_);
@@ -282,7 +282,7 @@ size_t TransformationPlugin::produce(const std::string &data) {
 
 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_);
+  LOG_DEBUG("OutputComplete TransformationPlugin=%p tshttptxn=%p vconn=%p connection_closed=%d, total bytes written=%ld", 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_);

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/1f829e26/lib/atscppapi/src/utils_internal.cc
----------------------------------------------------------------------
diff --git a/lib/atscppapi/src/utils_internal.cc b/lib/atscppapi/src/utils_internal.cc
index b153a49..01920d2 100644
--- a/lib/atscppapi/src/utils_internal.cc
+++ b/lib/atscppapi/src/utils_internal.cc
@@ -50,8 +50,7 @@ int handleTransactionEvents(TSCont cont, TSEvent event, void *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();
@@ -170,7 +169,6 @@ TSHttpHookID utils::internal::convertInternalHookToTsHook(Plugin::HookType hookt
 }
 
 TSHttpHookID utils::internal::convertInternalTransformationTypeToTsHook(TransformationPlugin::Type type) {
-  TSHttpHookID hook_id;
   switch (type) {
     case TransformationPlugin::RESPONSE_TRANSFORMATION:
       return TS_HTTP_RESPONSE_TRANSFORM_HOOK;


[48/50] [abbrv] git commit: TS-2301: replace CACHE_READY with CacheProcessor::IsCacheReady

Posted by zw...@apache.org.
TS-2301: replace CACHE_READY with CacheProcessor::IsCacheReady


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

Branch: refs/heads/5.0.x
Commit: 3b17595794e5a13e705a54f01ca9f8d201d5cc05
Parents: 7afc91b
Author: James Peach <jp...@apache.org>
Authored: Thu Oct 24 16:07:54 2013 -0700
Committer: James Peach <jp...@apache.org>
Committed: Fri Oct 25 19:11:26 2013 -0700

----------------------------------------------------------------------
 CHANGES                        | 2 ++
 ci/regression                  | 1 -
 iocore/cache/Cache.cc          | 4 ++--
 iocore/cache/CacheLink.cc      | 4 ++--
 iocore/cache/CacheRead.cc      | 4 ++--
 iocore/cache/CacheVol.cc       | 2 +-
 iocore/cache/CacheWrite.cc     | 4 ++--
 iocore/cache/I_Cache.h         | 2 +-
 iocore/cache/P_CacheInternal.h | 6 ++----
 9 files changed, 14 insertions(+), 15 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/trafficserver/blob/3b175957/CHANGES
----------------------------------------------------------------------
diff --git a/CHANGES b/CHANGES
index 7255533..1034fa0 100644
--- a/CHANGES
+++ b/CHANGES
@@ -2,6 +2,8 @@
 Changes with Apache Traffic Server 4.1.0
 
 
+  *) [TS-2301] Replace the CACHE_READY macro with CacheProcessor::IsCacheReady.
+
   *) [TS-2300] Remove the HIT_EVACUATE build option.
 
   *) [TS-2227] Allow for multiple config files for a header_rewrite plugin

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/3b175957/ci/regression
----------------------------------------------------------------------
diff --git a/ci/regression b/ci/regression
index 9303955..495b380 100755
--- a/ci/regression
+++ b/ci/regression
@@ -87,7 +87,6 @@ configure() {
     $SRCROOT/configure \
       --prefix=$DSTROOT \
       --enable-debug \
-      --enable-wccp \
       --enable-experimental-plugins \
       $(extras) \
       CC="$CC" \

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/3b175957/iocore/cache/Cache.cc
----------------------------------------------------------------------
diff --git a/iocore/cache/Cache.cc b/iocore/cache/Cache.cc
index 8eba0cd..e903a90 100644
--- a/iocore/cache/Cache.cc
+++ b/iocore/cache/Cache.cc
@@ -2623,7 +2623,7 @@ LmemHit:
 Action *
 Cache::lookup(Continuation *cont, CacheKey *key, CacheFragType type, char *hostname, int host_len)
 {
-  if (!CACHE_READY(type)) {
+  if (!CacheProcessor::IsCacheReady(type)) {
     cont->handleEvent(CACHE_EVENT_LOOKUP_FAILED, 0);
     return ACTION_RESULT_DONE;
   }
@@ -2746,7 +2746,7 @@ Action *
 Cache::remove(Continuation *cont, CacheKey *key, CacheFragType type, bool /* user_agents ATS_UNUSED */,
               bool /* link ATS_UNUSED */, char *hostname, int host_len)
 {
-  if (!CACHE_READY(type)) {
+  if (!CacheProcessor::IsCacheReady(type)) {
     if (cont)
       cont->handleEvent(CACHE_EVENT_REMOVE_FAILED, 0);
     return ACTION_RESULT_DONE;

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/3b175957/iocore/cache/CacheLink.cc
----------------------------------------------------------------------
diff --git a/iocore/cache/CacheLink.cc b/iocore/cache/CacheLink.cc
index 9766d64..30f05b8 100644
--- a/iocore/cache/CacheLink.cc
+++ b/iocore/cache/CacheLink.cc
@@ -27,7 +27,7 @@ Action *
 Cache::link(Continuation * cont, CacheKey * from, CacheKey * to, CacheFragType type, char *hostname, int host_len)
 {
 
-  if (!CACHE_READY(type)) {
+  if (!CacheProcessor::IsCacheReady(type)) {
     cont->handleEvent(CACHE_EVENT_LINK_FAILED, 0);
     return ACTION_RESULT_DONE;
   }
@@ -75,7 +75,7 @@ Action *
 Cache::deref(Continuation * cont, CacheKey * key, CacheFragType type, char *hostname, int host_len)
 {
 
-  if (!CACHE_READY(type)) {
+  if (!CacheProcessor::IsCacheReady(type)) {
     cont->handleEvent(CACHE_EVENT_DEREF_FAILED, 0);
     return ACTION_RESULT_DONE;
   }

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/3b175957/iocore/cache/CacheRead.cc
----------------------------------------------------------------------
diff --git a/iocore/cache/CacheRead.cc b/iocore/cache/CacheRead.cc
index 48de9c1..f11aee4 100644
--- a/iocore/cache/CacheRead.cc
+++ b/iocore/cache/CacheRead.cc
@@ -32,7 +32,7 @@
 Action *
 Cache::open_read(Continuation * cont, CacheKey * key, CacheFragType type, char *hostname, int host_len)
 {
-  if (!CACHE_READY(type)) {
+  if (!CacheProcessor::IsCacheReady(type)) {
     cont->handleEvent(CACHE_EVENT_OPEN_READ_FAILED, (void *) -ECACHE_NOT_READY);
     return ACTION_RESULT_DONE;
   }
@@ -93,7 +93,7 @@ Cache::open_read(Continuation * cont, CacheKey * key, CacheHTTPHdr * request,
                  CacheLookupHttpConfig * params, CacheFragType type, char *hostname, int host_len)
 {
 
-  if (!CACHE_READY(type)) {
+  if (!CacheProcessor::IsCacheReady(type)) {
     cont->handleEvent(CACHE_EVENT_OPEN_READ_FAILED, (void *) -ECACHE_NOT_READY);
     return ACTION_RESULT_DONE;
   }

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/3b175957/iocore/cache/CacheVol.cc
----------------------------------------------------------------------
diff --git a/iocore/cache/CacheVol.cc b/iocore/cache/CacheVol.cc
index 8ce0361..9fb690c 100644
--- a/iocore/cache/CacheVol.cc
+++ b/iocore/cache/CacheVol.cc
@@ -32,7 +32,7 @@ Action *
 Cache::scan(Continuation * cont, char *hostname, int host_len, int KB_per_second)
 {
   Debug("cache_scan_truss", "inside scan");
-  if (!CACHE_READY(CACHE_FRAG_TYPE_HTTP)) {
+  if (!CacheProcessor::IsCacheReady(CACHE_FRAG_TYPE_HTTP)) {
     cont->handleEvent(CACHE_EVENT_SCAN_FAILED, 0);
     return ACTION_RESULT_DONE;
   }

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/3b175957/iocore/cache/CacheWrite.cc
----------------------------------------------------------------------
diff --git a/iocore/cache/CacheWrite.cc b/iocore/cache/CacheWrite.cc
index 841bcbf..1a35b3f 100644
--- a/iocore/cache/CacheWrite.cc
+++ b/iocore/cache/CacheWrite.cc
@@ -1613,7 +1613,7 @@ Cache::open_write(Continuation *cont, CacheKey *key, CacheFragType frag_type,
                   int options, time_t apin_in_cache, char *hostname, int host_len)
 {
 
-  if (!CACHE_READY(frag_type)) {
+  if (!CacheProcessor::IsCacheReady(frag_type)) {
     cont->handleEvent(CACHE_EVENT_OPEN_WRITE_FAILED, (void *) -ECACHE_NOT_READY);
     return ACTION_RESULT_DONE;
   }
@@ -1681,7 +1681,7 @@ Action *
 Cache::open_write(Continuation *cont, CacheKey *key, CacheHTTPInfo *info, time_t apin_in_cache,
                   CacheKey */* key1 ATS_UNUSED */, CacheFragType type, char *hostname, int host_len)
 {
-  if (!CACHE_READY(type)) {
+  if (!CacheProcessor::IsCacheReady(type)) {
     cont->handleEvent(CACHE_EVENT_OPEN_WRITE_FAILED, (void *) -ECACHE_NOT_READY);
     return ACTION_RESULT_DONE;
   }

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/3b175957/iocore/cache/I_Cache.h
----------------------------------------------------------------------
diff --git a/iocore/cache/I_Cache.h b/iocore/cache/I_Cache.h
index 00e4791..b89357f 100644
--- a/iocore/cache/I_Cache.h
+++ b/iocore/cache/I_Cache.h
@@ -134,7 +134,7 @@ struct CacheProcessor:public Processor
                 CacheFragType frag_type = CACHE_FRAG_TYPE_HTTP, char *hostname = 0, int host_len = 0);
   static int IsCacheEnabled();
 
-  static unsigned int IsCacheReady(CacheFragType type);
+  static bool IsCacheReady(CacheFragType type);
 
   /// Type for callback function.
   typedef void (*CALLBACK_FUNC)();

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/3b175957/iocore/cache/P_CacheInternal.h
----------------------------------------------------------------------
diff --git a/iocore/cache/P_CacheInternal.h b/iocore/cache/P_CacheInternal.h
index 02bf78d..3c180ac 100644
--- a/iocore/cache/P_CacheInternal.h
+++ b/iocore/cache/P_CacheInternal.h
@@ -60,8 +60,6 @@ struct EvacuationBlock;
 // retry read from writer delay
 #define WRITER_RETRY_DELAY  HRTIME_MSECONDS(50)
 
-#define CACHE_READY(_x) (CacheProcessor::cache_ready & (1 << (_x)))
-
 #ifndef CACHE_LOCK_FAIL_RATE
 #define CACHE_TRY_LOCK(_l, _m, _t) MUTEX_TRY_LOCK(_l, _m, _t)
 #else
@@ -1382,12 +1380,12 @@ CacheProcessor::IsCacheEnabled()
   return CacheProcessor::initialized;
 }
 
-TS_INLINE unsigned int
+TS_INLINE bool
 CacheProcessor::IsCacheReady(CacheFragType type)
 {
   if (IsCacheEnabled() != CACHE_INITIALIZED)
     return 0;
-  return (cache_ready & (1 << type));
+  return (bool)(cache_ready & (1 << type));
 }
 
 TS_INLINE Cache *


[05/50] [abbrv] git commit: TS-2159: Force first log rotation at proxy.config.log.rolling_size_mb

Posted by zw...@apache.org.
TS-2159: Force first log rotation at proxy.config.log.rolling_size_mb


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

Branch: refs/heads/5.0.x
Commit: b942f3b942ea2a46279fda3a2d22e6f3c618780a
Parents: 64b01e0
Author: Zhao Yongming <mi...@gmail.com>
Authored: Wed Oct 16 18:06:23 2013 +0800
Committer: Zhao Yongming <mi...@gmail.com>
Committed: Wed Oct 16 23:40:44 2013 +0800

----------------------------------------------------------------------
 CHANGES                  | 2 ++
 proxy/logging/LogFile.cc | 3 +++
 2 files changed, 5 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/trafficserver/blob/b942f3b9/CHANGES
----------------------------------------------------------------------
diff --git a/CHANGES b/CHANGES
index f892b2e..111c913 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,8 @@
                                                          -*- coding: utf-8 -*-
 Changes with Apache Traffic Server 4.1.0
 
+  *) [TS-2159] Force first log rotation at proxy.config.log.rolling_size_mb
+
   *) [TS-2138] Fix the bug that restarting ats cause cache data loss if
   enable the native-aio.
 

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/b942f3b9/proxy/logging/LogFile.cc
----------------------------------------------------------------------
diff --git a/proxy/logging/LogFile.cc b/proxy/logging/LogFile.cc
index 55fe900..a567b93 100644
--- a/proxy/logging/LogFile.cc
+++ b/proxy/logging/LogFile.cc
@@ -261,6 +261,9 @@ LogFile::open_file()
     return LOG_FILE_FILESYSTEM_CHECKS_FAILED;
   }
 
+  // set m_bytes_written to force the rolling based on filesize.
+  m_bytes_written = lseek( m_fd, 0, SEEK_CUR );
+
   Debug("log-file", "LogFile %s is now open (fd=%d)", m_name, m_fd);
 
   //


[26/50] [abbrv] git commit: TS-2216 Fix cquuh log tag, which does not calculate the right string length. Also see TS-1988.

Posted by zw...@apache.org.
TS-2216 Fix cquuh log tag, which does not calculate the right
string length. Also see TS-1988.


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

Branch: refs/heads/5.0.x
Commit: 3775c866cca2c2cb42703ab30fda52a80ffbea26
Parents: ea35372
Author: Leif Hedstrom <zw...@apache.org>
Authored: Mon Oct 21 17:27:17 2013 -0600
Committer: Leif Hedstrom <zw...@apache.org>
Committed: Mon Oct 21 17:27:17 2013 -0600

----------------------------------------------------------------------
 CHANGES                        | 3 +++
 proxy/logging/LogAccessHttp.cc | 8 ++++----
 2 files changed, 7 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/trafficserver/blob/3775c866/CHANGES
----------------------------------------------------------------------
diff --git a/CHANGES b/CHANGES
index 0a1ded9..a626df1 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,9 @@
                                                          -*- coding: utf-8 -*-
 Changes with Apache Traffic Server 4.1.0
 
+  *) [TS-2216] Fix cquuh log tag, which does not calculate the right
+   string length.
+
   *) [TS-2275] fix interim cache lossing data if the server process crash
    Author: Gang Li.
 

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/3775c866/proxy/logging/LogAccessHttp.cc
----------------------------------------------------------------------
diff --git a/proxy/logging/LogAccessHttp.cc b/proxy/logging/LogAccessHttp.cc
index ddc5c7d..cc89abc 100644
--- a/proxy/logging/LogAccessHttp.cc
+++ b/proxy/logging/LogAccessHttp.cc
@@ -361,11 +361,11 @@ LogAccessHttp::marshal_client_req_unmapped_url_host(char *buf)
 {
   int len = INK_MIN_ALIGN;
 
-  if (buf) {
-    validate_unmapped_url();
-    validate_unmapped_url_path();
+  validate_unmapped_url();
+  validate_unmapped_url_path();
 
-    len = round_strlen(m_client_req_unmapped_url_host_len + 1);      // +1 for eos
+  len = round_strlen(m_client_req_unmapped_url_host_len + 1);      // +1 for eos
+  if (buf) {
     marshal_mem(buf, m_client_req_unmapped_url_host_str, m_client_req_unmapped_url_host_len, len);
   }
   return len;


[18/50] [abbrv] git commit: Fixing license and updating notice

Posted by zw...@apache.org.
Fixing license and updating notice


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

Branch: refs/heads/5.0.x
Commit: 6958d056469698a4850d7019259912bec6eb23cb
Parents: 7b2ea5f
Author: Brian Geffon <br...@apache.org>
Authored: Fri Oct 18 14:54:08 2013 -0700
Committer: Brian Geffon <br...@apache.org>
Committed: Fri Oct 18 14:54:08 2013 -0700

----------------------------------------------------------------------
 NOTICE                                          |  5 ++
 configure.ac                                    | 58 ++++++++++++++++----
 lib/Makefile.am                                 |  6 +-
 .../NullTransformationPlugin.cc                 | 26 +++++----
 4 files changed, 72 insertions(+), 23 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/trafficserver/blob/6958d056/NOTICE
----------------------------------------------------------------------
diff --git a/NOTICE b/NOTICE
index 849f001..b486b5e 100644
--- a/NOTICE
+++ b/NOTICE
@@ -38,3 +38,8 @@ Copyright (C) 2012 Oregon Health & Science University
 
 healthcheck Plugin developed by GoDaddy.
 Copyright (C) 2012 GoDaddy.
+
+~~~
+
+lib/atscppapi developed by LinkedIn
+Copyright (c) 2013 LinkedIn
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/6958d056/configure.ac
----------------------------------------------------------------------
diff --git a/configure.ac b/configure.ac
index 8023755..bb2f373 100644
--- a/configure.ac
+++ b/configure.ac
@@ -480,6 +480,19 @@ AC_ARG_ENABLE([experimental-plugins],
 AC_MSG_RESULT([$enable_experimental_plugins])
 AM_CONDITIONAL([BUILD_EXPERIMENTAL_PLUGINS], [ test "x${enable_experimental_plugins}" = "xyes" ])
 
+
+#
+# build c++ api
+#
+AC_MSG_CHECKING([whether to build c++ api])
+AC_ARG_ENABLE([cppapi],
+  [AS_HELP_STRING([--enable-cppapi],[Build the c++ api])],
+  [],
+  [enable_cppapi="no"]
+)
+AC_MSG_RESULT([$enable_cppapi])
+AM_CONDITIONAL([ENABLE_CPPAPI], [ test "x${enable_cppapi}" = "xyes" ])
+
 #
 # Installation directories
 # For each var the following is evaluated
@@ -996,15 +1009,17 @@ AC_MSG_NOTICE([Build for host OS: $host_os, arch: $host_cpu, optimization: $host
 
 #
 # CPP 11 API
-#
-AC_MSG_CHECKING([whether to enable c++11 api])
-AC_ARG_WITH([cpp11api],
-  [AS_HELP_STRING([--with-cpp11api],[enable support for cpp11api [default=auto]])],
-  [cpp11api=$withval],
-  [cpp11api=$enable_cxx_11_support]
-)
-AC_MSG_RESULT([$cpp11api])
-AM_CONDITIONAL([BUILD_CPP11API], [test "$cpp11api" = yes])
+# TODO: briang, this needs to be translated to a define
+# that can be used in the c++ api to enable c++11 api features.
+#
+#AC_MSG_CHECKING([whether to enable c++11 api])
+#AC_ARG_WITH([cpp11api],
+#  [AS_HELP_STRING([--with-cpp11api],[enable support for cpp11api [default=auto]])],
+#  [cpp11api=$withval],
+#  [cpp11api=$enable_cxx_11_support]
+#)
+#AC_MSG_RESULT([$cpp11api])
+#AM_CONDITIONAL([BUILD_CPP11API], [test "$cpp11api" = yes])
 
 # Check for ccache (if explicitly enabled)
 if test "x$enable_ccache" = "xyes"; then
@@ -1825,11 +1840,34 @@ AC_CONFIG_FILES([
   iocore/net/Makefile
   iocore/utils/Makefile
   lib/Makefile
-  lib/cpp11api/Makefile
   lib/records/Makefile
   lib/ts/Makefile
   lib/ts/ink_config.h
   lib/tsconfig/Makefile
+  lib/atscppapi/Makefile
+  lib/atscppapi/src/Makefile
+  lib/atscppapi/examples/Makefile
+  lib/atscppapi/examples/helloworld/Makefile
+  lib/atscppapi/examples/globalhook/Makefile
+  lib/atscppapi/examples/transactionhook/Makefile
+  lib/atscppapi/examples/multiple_transaction_hooks/Makefile
+  lib/atscppapi/examples/clientrequest/Makefile
+  lib/atscppapi/examples/data_caching/Makefile
+  lib/atscppapi/examples/serverresponse/Makefile
+  lib/atscppapi/examples/clientredirect/Makefile
+  lib/atscppapi/examples/customresponse/Makefile
+  lib/atscppapi/examples/null_transformation_plugin/Makefile
+  lib/atscppapi/examples/post_buffer/Makefile
+  lib/atscppapi/examples/logger_example/Makefile
+  lib/atscppapi/examples/detachedrequest/Makefile
+  lib/atscppapi/examples/stat_example/Makefile
+  lib/atscppapi/examples/async_http_fetch/Makefile
+  lib/atscppapi/examples/remap_plugin/Makefile
+  lib/atscppapi/examples/gzip_transformation/Makefile
+  lib/atscppapi/examples/timeout_example/Makefile
+  lib/atscppapi/examples/internal_transaction_handling/Makefile
+  lib/atscppapi/examples/async_timer/Makefile
+  lib/atscppapi/examples/request_cookies/Makefile
   lib/wccp/Makefile
   lib/perl/Makefile
   mgmt/Makefile

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/6958d056/lib/Makefile.am
----------------------------------------------------------------------
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 8be7aa8..9664374 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -27,6 +27,6 @@ if BUILD_WCCP
 SUBDIRS += tsconfig wccp
 endif
 
-if BUILD_CPP11API
-SUBDIRS += cpp11api
-endif
+if ENABLE_CPPAPI
+SUBDIRS += atscppapi
+endif
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/6958d056/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
index b226290..c23971e 100644
--- a/lib/atscppapi/examples/null_transformation_plugin/NullTransformationPlugin.cc
+++ b/lib/atscppapi/examples/null_transformation_plugin/NullTransformationPlugin.cc
@@ -1,13 +1,19 @@
-/*
- * 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.
- *
+/**
+  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>


[39/50] [abbrv] git commit: TS-2291: Make configure.ac cleaner for remap_stats checks

Posted by zw...@apache.org.
TS-2291: Make configure.ac cleaner for remap_stats checks


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

Branch: refs/heads/5.0.x
Commit: 22e33c53fc968062554ffb785b7956315dfab5b6
Parents: 6da424f
Author: Phil Sorber <so...@apache.org>
Authored: Wed Oct 23 11:26:43 2013 -0600
Committer: Phil Sorber <so...@apache.org>
Committed: Wed Oct 23 11:26:43 2013 -0600

----------------------------------------------------------------------
 configure.ac | 19 ++++++++++++-------
 1 file changed, 12 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/trafficserver/blob/22e33c53/configure.ac
----------------------------------------------------------------------
diff --git a/configure.ac b/configure.ac
index b25a6fb..b4fda1b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1788,13 +1788,18 @@ AC_CHECK_TYPE([struct tcp_info],
 )
 AM_CONDITIONAL([BUILD_TCPINFO_PLUGIN], [ test "x${enable_tcpinfo_plugin}" != "xno" ])
 
-AC_SEARCH_LIBS([hcreate_r],
-  [],
-  [enable_remap_stats_plugin=yes],
-  [enable_remap_stats_plugin=no],
-  []
-)
-AM_CONDITIONAL([BUILD_REMAP_STATS_PLUGIN], [ test "x${enable_remap_stats_plugin}" != "xno" ])
+# See if we can build the remap_stats plugin
+AS_IF([test "x$enable_experimental_plugins" = xyes],
+  [
+    AC_CHECK_HEADERS([search.h])
+    AS_IF([test "x$ac_cv_header_search_h" = "xyes"],
+      [
+        AC_CHECK_TYPE([struct hsearch_data],[],[],[[#include <search.h>]])
+        AC_CHECK_FUNCS([hcreate_r hsearch_r])
+      ])
+  ])
+AM_CONDITIONAL([BUILD_REMAP_STATS_PLUGIN],
+  [ test "x$enable_experimental_plugins" = "xyes" -a "x$ac_cv_header_search_h" = "xyes" -a "x$ac_cv_type_struct_hsearch_data" = "xyes" -a "x$ac_cv_func_hcreate_r" = "xyes" -a "x$ac_cv_func_hsearch_r" = "xyes" ])
 
 #
 # use modular IOCORE


[32/50] [abbrv] git commit: fixing minor build issues with examples

Posted by zw...@apache.org.
fixing minor build issues with examples


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

Branch: refs/heads/5.0.x
Commit: 9c918b68cc1720228b2d2370f01187d7ae182bf6
Parents: 6c5955a
Author: Brian Geffon <br...@apache.org>
Authored: Tue Oct 22 14:21:33 2013 -0700
Committer: Brian Geffon <br...@apache.org>
Committed: Tue Oct 22 14:21:33 2013 -0700

----------------------------------------------------------------------
 lib/atscppapi/examples/async_http_fetch/Makefile.am             | 4 ++--
 lib/atscppapi/examples/async_timer/Makefile.am                  | 5 ++---
 lib/atscppapi/examples/clientredirect/Makefile.am               | 5 ++---
 lib/atscppapi/examples/clientrequest/Makefile.am                | 4 ++--
 lib/atscppapi/examples/customresponse/Makefile.am               | 4 ++--
 lib/atscppapi/examples/data_caching/Makefile.am                 | 5 ++---
 lib/atscppapi/examples/detachedrequest/Makefile.am              | 4 ++--
 lib/atscppapi/examples/globalhook/GlobalHookPlugin.cc           | 5 +----
 lib/atscppapi/examples/globalhook/Makefile.am                   | 4 ++--
 lib/atscppapi/examples/gzip_transformation/Makefile.am          | 4 ++--
 lib/atscppapi/examples/helloworld/Makefile.am                   | 4 ++--
 .../examples/internal_transaction_handling/Makefile.am          | 4 ++--
 lib/atscppapi/examples/logger_example/Makefile.am               | 4 ++--
 lib/atscppapi/examples/multiple_transaction_hooks/Makefile.am   | 5 ++---
 lib/atscppapi/examples/null_transformation_plugin/Makefile.am   | 4 ++--
 lib/atscppapi/examples/post_buffer/Makefile.am                  | 4 ++--
 lib/atscppapi/examples/remap_plugin/Makefile.am                 | 4 ++--
 lib/atscppapi/examples/request_cookies/Makefile.am              | 5 ++---
 lib/atscppapi/examples/serverresponse/Makefile.am               | 4 ++--
 lib/atscppapi/examples/stat_example/Makefile.am                 | 4 ++--
 lib/atscppapi/examples/timeout_example/Makefile.am              | 4 ++--
 lib/atscppapi/examples/transactionhook/Makefile.am              | 4 ++--
 22 files changed, 43 insertions(+), 51 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/trafficserver/blob/9c918b68/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
index dd1dd94..8dbb281 100644
--- a/lib/atscppapi/examples/async_http_fetch/Makefile.am
+++ b/lib/atscppapi/examples/async_http_fetch/Makefile.am
@@ -15,13 +15,13 @@
 #  See the License for the specific language governing permissions and
 #  limitations under the License.
 
-AM_CPPFLAGS = -I$(top_srcdir)/src/include
+AM_CPPFLAGS = -I$(top_srcdir)/lib/atscppapi/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
+AsyncHttpFetch_la_LDFLAGS = -module -avoid-version -shared -L$(top_srcdir)/lib/atscppapi/src/ -latscppapi
 
 all:
 	ln -sf .libs/$(target)

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/9c918b68/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
index 577d8d7..1a48970 100644
--- a/lib/atscppapi/examples/async_timer/Makefile.am
+++ b/lib/atscppapi/examples/async_timer/Makefile.am
@@ -15,13 +15,12 @@
 #  See the License for the specific language governing permissions and
 #  limitations under the License.
 
-AM_CPPFLAGS = -I$(top_srcdir)/src/include
-
+AM_CPPFLAGS = -I$(top_srcdir)/lib/atscppapi/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
+AsyncTimer_la_LDFLAGS =  -module -avoid-version -shared -L$(top_srcdir)/lib/atscppapi/src/ -latscppapi
 
 all:
 	ln -sf .libs/$(target)

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/9c918b68/lib/atscppapi/examples/clientredirect/Makefile.am
----------------------------------------------------------------------
diff --git a/lib/atscppapi/examples/clientredirect/Makefile.am b/lib/atscppapi/examples/clientredirect/Makefile.am
index ec1629c..dde30ef 100644
--- a/lib/atscppapi/examples/clientredirect/Makefile.am
+++ b/lib/atscppapi/examples/clientredirect/Makefile.am
@@ -14,13 +14,12 @@
 #  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
-
+AM_CPPFLAGS = -I$(top_srcdir)/lib/atscppapi/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
+ClientRedirect_la_LDFLAGS =  -module -avoid-version -shared -L$(top_srcdir)/lib/atscppapi/src/ -latscppapi
 
 all:
 	ln -sf .libs/$(target)

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/9c918b68/lib/atscppapi/examples/clientrequest/Makefile.am
----------------------------------------------------------------------
diff --git a/lib/atscppapi/examples/clientrequest/Makefile.am b/lib/atscppapi/examples/clientrequest/Makefile.am
index 9041577..2c69b0c 100644
--- a/lib/atscppapi/examples/clientrequest/Makefile.am
+++ b/lib/atscppapi/examples/clientrequest/Makefile.am
@@ -15,13 +15,13 @@
 #  See the License for the specific language governing permissions and
 #  limitations under the License.
 
-AM_CPPFLAGS = -I$(top_srcdir)/src/include
+AM_CPPFLAGS = -I$(top_srcdir)/lib/atscppapi/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
+ClientRequest_la_LDFLAGS =  -module -avoid-version -shared -L$(top_srcdir)/lib/atscppapi/src/ -latscppapi
 
 all:
 	ln -sf .libs/$(target)

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/9c918b68/lib/atscppapi/examples/customresponse/Makefile.am
----------------------------------------------------------------------
diff --git a/lib/atscppapi/examples/customresponse/Makefile.am b/lib/atscppapi/examples/customresponse/Makefile.am
index 1e7093a..8a242a6 100644
--- a/lib/atscppapi/examples/customresponse/Makefile.am
+++ b/lib/atscppapi/examples/customresponse/Makefile.am
@@ -14,13 +14,13 @@
 #  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
+AM_CPPFLAGS = -I$(top_srcdir)/lib/atscppapi/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
+CustomResponse_la_LDFLAGS =  -module -avoid-version -shared -L$(top_srcdir)/lib/atscppapi/src/ -latscppapi
 
 all:
 	ln -sf .libs/$(target)

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/9c918b68/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
index 818e965..8272e03 100644
--- a/lib/atscppapi/examples/data_caching/Makefile.am
+++ b/lib/atscppapi/examples/data_caching/Makefile.am
@@ -14,13 +14,12 @@
 #  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
-
+AM_CPPFLAGS = -I$(top_srcdir)/lib/atscppapi/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
+data_caching_la_LDFLAGS = -module -avoid-version -shared -L$(top_srcdir)/lib/atscppapi/src/ -latscppapi
 
 all:
 	ln -sf .libs/$(target)

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/9c918b68/lib/atscppapi/examples/detachedrequest/Makefile.am
----------------------------------------------------------------------
diff --git a/lib/atscppapi/examples/detachedrequest/Makefile.am b/lib/atscppapi/examples/detachedrequest/Makefile.am
index afe0199..dfda99d 100644
--- a/lib/atscppapi/examples/detachedrequest/Makefile.am
+++ b/lib/atscppapi/examples/detachedrequest/Makefile.am
@@ -15,13 +15,13 @@
 #  See the License for the specific language governing permissions and
 #  limitations under the License.
 
-AM_CPPFLAGS = -I$(top_srcdir)/src/include
+AM_CPPFLAGS = -I$(top_srcdir)/lib/atscppapi/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
+DetachedRequest_la_LDFLAGS = -module -avoid-version -shared -L$(top_srcdir)/lib/atscppapi/src/ -latscppapi
 
 all:
 	ln -sf .libs/$(target)

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/9c918b68/lib/atscppapi/examples/globalhook/GlobalHookPlugin.cc
----------------------------------------------------------------------
diff --git a/lib/atscppapi/examples/globalhook/GlobalHookPlugin.cc b/lib/atscppapi/examples/globalhook/GlobalHookPlugin.cc
index 68ceebf..629c2e6 100644
--- a/lib/atscppapi/examples/globalhook/GlobalHookPlugin.cc
+++ b/lib/atscppapi/examples/globalhook/GlobalHookPlugin.cc
@@ -25,10 +25,7 @@ using namespace atscppapi;
 class GlobalHookPlugin : public GlobalPlugin {
 public:
   GlobalHookPlugin() {
-    registerHook(HOOK_READ_REQUEST_HEADERS_PRE_REMAP, [](Transaction &t) {
-
-    });
-
+    registerHook(HOOK_READ_REQUEST_HEADERS_PRE_REMAP);
   }
 
   virtual void handleReadRequestHeadersPreRemap(Transaction &transaction) {

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/9c918b68/lib/atscppapi/examples/globalhook/Makefile.am
----------------------------------------------------------------------
diff --git a/lib/atscppapi/examples/globalhook/Makefile.am b/lib/atscppapi/examples/globalhook/Makefile.am
index 9269312..71ba649 100644
--- a/lib/atscppapi/examples/globalhook/Makefile.am
+++ b/lib/atscppapi/examples/globalhook/Makefile.am
@@ -14,13 +14,13 @@
 #  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
+AM_CPPFLAGS = -I$(top_srcdir)/lib/atscppapi/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
+GlobalHookPlugin_la_LDFLAGS = -module -avoid-version -shared -L$(top_srcdir)/lib/atscppapi/src/ -latscppapi
 
 all:
 	ln -sf .libs/$(target)

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/9c918b68/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
index bfaaae1..655c867 100644
--- a/lib/atscppapi/examples/gzip_transformation/Makefile.am
+++ b/lib/atscppapi/examples/gzip_transformation/Makefile.am
@@ -15,13 +15,13 @@
 #  See the License for the specific language governing permissions and
 #  limitations under the License.
 
-AM_CPPFLAGS = -I$(top_srcdir)/src/include
+AM_CPPFLAGS = -I$(top_srcdir)/lib/atscppapi/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
+GzipTransformationPlugin_la_LDFLAGS = -module -avoid-version -shared -L$(top_srcdir)/lib/atscppapi/src/ -latscppapi
 
 all:
 	ln -sf .libs/$(target)

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/9c918b68/lib/atscppapi/examples/helloworld/Makefile.am
----------------------------------------------------------------------
diff --git a/lib/atscppapi/examples/helloworld/Makefile.am b/lib/atscppapi/examples/helloworld/Makefile.am
index ebdd7d1..615f3eb 100644
--- a/lib/atscppapi/examples/helloworld/Makefile.am
+++ b/lib/atscppapi/examples/helloworld/Makefile.am
@@ -14,13 +14,13 @@
 #  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
+AM_CPPFLAGS = -I$(top_srcdir)/lib/atscppapi/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
+HelloWorldPlugin_la_LDFLAGS = -module -avoid-version -shared -L$(top_srcdir)/lib/atscppapi/src/ -latscppapi
 
 all:
 	ln -sf .libs/$(target)

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/9c918b68/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
index 447c943..9035fff 100644
--- a/lib/atscppapi/examples/internal_transaction_handling/Makefile.am
+++ b/lib/atscppapi/examples/internal_transaction_handling/Makefile.am
@@ -14,13 +14,13 @@
 #  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
+AM_CPPFLAGS = -I$(top_srcdir)/lib/atscppapi/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
+InternalTransactionHandling_la_LDFLAGS = -module -avoid-version -shared -L$(top_srcdir)/lib/atscppapi/src/ -latscppapi
 
 all:
 	ln -sf .libs/$(target)

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/9c918b68/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
index 404dd8c..9b88ed2 100644
--- a/lib/atscppapi/examples/logger_example/Makefile.am
+++ b/lib/atscppapi/examples/logger_example/Makefile.am
@@ -15,13 +15,13 @@
 #  See the License for the specific language governing permissions and
 #  limitations under the License.
 
-AM_CPPFLAGS = -I$(top_srcdir)/src/include
+AM_CPPFLAGS = -I$(top_srcdir)/lib/atscppapi/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
+LoggerExample_la_LDFLAGS = -module -avoid-version -shared -L$(top_srcdir)/lib/atscppapi/src/ -latscppapi
 
 all:
 	ln -sf .libs/$(target)

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/9c918b68/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
index d56c921..76f9a66 100644
--- a/lib/atscppapi/examples/multiple_transaction_hooks/Makefile.am
+++ b/lib/atscppapi/examples/multiple_transaction_hooks/Makefile.am
@@ -14,13 +14,12 @@
 #  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
-
+AM_CPPFLAGS = -I$(top_srcdir)/lib/atscppapi/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
+MultipleTransactionHookPlugins_la_LDFLAGS = -module -avoid-version -shared -L$(top_srcdir)/lib/atscppapi/src/ -latscppapi
 
 all:
 	ln -sf .libs/$(target)

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/9c918b68/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
index f41c64c..b82f525 100644
--- a/lib/atscppapi/examples/null_transformation_plugin/Makefile.am
+++ b/lib/atscppapi/examples/null_transformation_plugin/Makefile.am
@@ -15,13 +15,13 @@
 #  See the License for the specific language governing permissions and
 #  limitations under the License.
 
-AM_CPPFLAGS = -I$(top_srcdir)/src/include
+AM_CPPFLAGS = -I$(top_srcdir)/lib/atscppapi/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
+NullTransformationPlugin_la_LDFLAGS = -module -avoid-version -shared -L$(top_srcdir)/lib/atscppapi/src/ -latscppapi
 
 all:
 	ln -sf .libs/$(target)

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/9c918b68/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
index e893f5e..fcf20e7 100644
--- a/lib/atscppapi/examples/post_buffer/Makefile.am
+++ b/lib/atscppapi/examples/post_buffer/Makefile.am
@@ -14,13 +14,13 @@
 #  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
+AM_CPPFLAGS = -I$(top_srcdir)/lib/atscppapi/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
+PostBuffer_la_LDFLAGS = -module -avoid-version -shared -L$(top_srcdir)/lib/atscppapi/src/ -latscppapi
 
 all:
 	ln -sf .libs/$(target)

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/9c918b68/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
index 5926f6a..cec18e5 100644
--- a/lib/atscppapi/examples/remap_plugin/Makefile.am
+++ b/lib/atscppapi/examples/remap_plugin/Makefile.am
@@ -15,13 +15,13 @@
 #  See the License for the specific language governing permissions and
 #  limitations under the License.
 
-AM_CPPFLAGS = -I$(top_srcdir)/src/include
+AM_CPPFLAGS = -I$(top_srcdir)/lib/atscppapi/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
+RemapPlugin_la_LDFLAGS = -module -avoid-version -shared -L$(top_srcdir)/lib/atscppapi/src/ -latscppapi
 
 all:
 	ln -sf .libs/$(target)

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/9c918b68/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
index dd315cb..03c8040 100644
--- a/lib/atscppapi/examples/request_cookies/Makefile.am
+++ b/lib/atscppapi/examples/request_cookies/Makefile.am
@@ -15,13 +15,12 @@
 #  See the License for the specific language governing permissions and
 #  limitations under the License.
 
-AM_CPPFLAGS = -I$(top_srcdir)/src/include
-
+AM_CPPFLAGS = -I$(top_srcdir)/lib/atscppapi/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
+RequestCookies_la_LDFLAGS = -module -avoid-version -shared -L$(top_srcdir)/lib/atscppapi/src/ -latscppapi
 
 all:
 	ln -sf .libs/$(target)

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/9c918b68/lib/atscppapi/examples/serverresponse/Makefile.am
----------------------------------------------------------------------
diff --git a/lib/atscppapi/examples/serverresponse/Makefile.am b/lib/atscppapi/examples/serverresponse/Makefile.am
index 9f8f4c7..014a65e 100644
--- a/lib/atscppapi/examples/serverresponse/Makefile.am
+++ b/lib/atscppapi/examples/serverresponse/Makefile.am
@@ -14,13 +14,13 @@
 #  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
+AM_CPPFLAGS = -I$(top_srcdir)/lib/atscppapi/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
+ServerResponse_la_LDFLAGS = -module -avoid-version -shared -L$(top_srcdir)/lib/atscppapi/src/ -latscppapi
 
 all:
 	ln -sf .libs/$(target)

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/9c918b68/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
index 3e49f79..29b7caf 100644
--- a/lib/atscppapi/examples/stat_example/Makefile.am
+++ b/lib/atscppapi/examples/stat_example/Makefile.am
@@ -15,13 +15,13 @@
 #  See the License for the specific language governing permissions and
 #  limitations under the License.
 
-AM_CPPFLAGS = -I$(top_srcdir)/src/include
+AM_CPPFLAGS = -I$(top_srcdir)/lib/atscppapi/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
+StatExample_la_LDFLAGS = -module -avoid-version -shared -L$(top_srcdir)/lib/atscppapi/src/ -latscppapi
 
 all:
 	ln -sf .libs/$(target)

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/9c918b68/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
index 7583476..94d6e7b 100644
--- a/lib/atscppapi/examples/timeout_example/Makefile.am
+++ b/lib/atscppapi/examples/timeout_example/Makefile.am
@@ -15,13 +15,13 @@
 #  See the License for the specific language governing permissions and
 #  limitations under the License.
 
-AM_CPPFLAGS = -I$(top_srcdir)/src/include
+AM_CPPFLAGS = -I$(top_srcdir)/lib/atscppapi/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
+TimeoutExamplePlugin_la_LDFLAGS = -module -avoid-version -shared -L$(top_srcdir)/lib/atscppapi/src/ -latscppapi
 
 all:
 	ln -sf .libs/$(target)

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/9c918b68/lib/atscppapi/examples/transactionhook/Makefile.am
----------------------------------------------------------------------
diff --git a/lib/atscppapi/examples/transactionhook/Makefile.am b/lib/atscppapi/examples/transactionhook/Makefile.am
index 1c145cd..c604875 100644
--- a/lib/atscppapi/examples/transactionhook/Makefile.am
+++ b/lib/atscppapi/examples/transactionhook/Makefile.am
@@ -15,13 +15,13 @@
 #  See the License for the specific language governing permissions and
 #  limitations under the License.
 
-AM_CPPFLAGS = -I$(top_srcdir)/src/include
+AM_CPPFLAGS = -I$(top_srcdir)/lib/atscppapi/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
+TransactionHookPlugin_la_LDFLAGS = -module -avoid-version -shared -L$(top_srcdir)/lib/atscppapi/src/ -latscppapi
 
 all:
 	ln -sf .libs/$(target)


[33/50] [abbrv] git commit: Merge branch 'master' of https://git-wip-us.apache.org/repos/asf/trafficserver

Posted by zw...@apache.org.
Merge branch 'master' of https://git-wip-us.apache.org/repos/asf/trafficserver


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

Branch: refs/heads/5.0.x
Commit: e265ff890ad49bd1dd58984fd8ff982125f5487e
Parents: 9c918b6 bb5f909
Author: Brian Geffon <br...@apache.org>
Authored: Tue Oct 22 14:22:21 2013 -0700
Committer: Brian Geffon <br...@apache.org>
Committed: Tue Oct 22 14:22:21 2013 -0700

----------------------------------------------------------------------
 doc/reference/configuration/records.config.en.rst | 8 ++++++++
 1 file changed, 8 insertions(+)
----------------------------------------------------------------------



[19/50] [abbrv] git commit: TS-2242: Update core plugins' support_email and vendor_name for consistency.

Posted by zw...@apache.org.
TS-2242: Update core plugins' support_email and vendor_name for consistency.


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

Branch: refs/heads/5.0.x
Commit: 2c3f7c5e96a3cb1e42ef98545a151189ab8d08ee
Parents: 6958d05
Author: Phil Sorber <so...@apache.org>
Authored: Sun Oct 20 13:05:05 2013 -0600
Committer: Phil Sorber <so...@apache.org>
Committed: Sun Oct 20 13:05:05 2013 -0600

----------------------------------------------------------------------
 CHANGES                                                 | 3 +++
 plugins/cacheurl/cacheurl.c                             | 4 ++--
 plugins/experimental/authproxy/authproxy.cc             | 4 ++--
 plugins/experimental/buffer_upload/buffer_upload.cc     | 4 ++--
 plugins/experimental/channel_stats/channel_stats.cc     | 4 ++--
 plugins/experimental/custom_redirect/custom_redirect.cc | 4 ++--
 plugins/experimental/lua/plugin.cc                      | 2 +-
 plugins/experimental/memcached_remap/memcached_remap.cc | 2 +-
 plugins/experimental/metalink/metalink.cc               | 4 ++--
 plugins/experimental/mysql_remap/mysql_remap.cc         | 2 +-
 plugins/experimental/rfc5861/rfc5861.c                  | 4 ++--
 plugins/experimental/spdy/spdy.cc                       | 4 ++--
 plugins/gzip/misc.cc                                    | 2 +-
 plugins/header_filter/header_filter.cc                  | 4 ++--
 plugins/header_rewrite/header_rewrite.cc                | 4 ++--
 plugins/libloader/libloader.c                           | 2 +-
 plugins/stats_over_http/stats_over_http.c               | 2 +-
 17 files changed, 29 insertions(+), 26 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/trafficserver/blob/2c3f7c5e/CHANGES
----------------------------------------------------------------------
diff --git a/CHANGES b/CHANGES
index c9695ee..1446547 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,9 @@
                                                          -*- coding: utf-8 -*-
 Changes with Apache Traffic Server 4.1.0
 
+  *) [TS-2242] Update core plugins' support_email and vendor_name for
+   consistency.
+
   *) [TS-1988] cquuc and cquup log tags can have no values.
 
   *) [TS-2159] Force first log rotation at proxy.config.log.rolling_size_mb

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/2c3f7c5e/plugins/cacheurl/cacheurl.c
----------------------------------------------------------------------
diff --git a/plugins/cacheurl/cacheurl.c b/plugins/cacheurl/cacheurl.c
index 7b28d7d..1779bae 100644
--- a/plugins/cacheurl/cacheurl.c
+++ b/plugins/cacheurl/cacheurl.c
@@ -445,8 +445,8 @@ void TSPluginInit(int argc, const char *argv[]) {
     pr_list *prl;
 
     info.plugin_name = PLUGIN_NAME;
-    info.vendor_name = "OmniTI";
-    info.support_email = "sa@omniti.com";
+    info.vendor_name = "Apache Software Foundation";
+    info.support_email = "dev@trafficserver.apache.org";
 
     if (TSPluginRegister(TS_SDK_VERSION_3_0, &info) != TS_SUCCESS) {
         initialization_error("Plugin registration failed.");

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/2c3f7c5e/plugins/experimental/authproxy/authproxy.cc
----------------------------------------------------------------------
diff --git a/plugins/experimental/authproxy/authproxy.cc b/plugins/experimental/authproxy/authproxy.cc
index c4c939d..c11d1bf 100644
--- a/plugins/experimental/authproxy/authproxy.cc
+++ b/plugins/experimental/authproxy/authproxy.cc
@@ -809,8 +809,8 @@ TSPluginInit(int argc, const char *argv[])
     TSPluginRegistrationInfo info;
 
     info.plugin_name = (char *)"AuthProxy";
-    info.vendor_name = (char *)"James Peach";
-    info.support_email = (char *)"jamespeach@me.com";
+    info.vendor_name = (char *)"Apache Software Foundation";
+    info.support_email = (char *)"dev@trafficserver.apache.org";
 
     if (TSPluginRegister(TS_SDK_VERSION_3_0, &info) != TS_SUCCESS) {
         AuthLogError("plugin registration failed");

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/2c3f7c5e/plugins/experimental/buffer_upload/buffer_upload.cc
----------------------------------------------------------------------
diff --git a/plugins/experimental/buffer_upload/buffer_upload.cc b/plugins/experimental/buffer_upload/buffer_upload.cc
index 3101de8..9dda144 100644
--- a/plugins/experimental/buffer_upload/buffer_upload.cc
+++ b/plugins/experimental/buffer_upload/buffer_upload.cc
@@ -1242,8 +1242,8 @@ TSPluginInit(int argc, const char *argv[])
   }
 
   info.plugin_name = const_cast<char*>("buffer_upload");
-  info.vendor_name = const_cast<char*>("");
-  info.support_email = const_cast<char*>("");
+  info.vendor_name = const_cast<char*>("Apache Software Foundation");
+  info.support_email = const_cast<char*>("dev@trafficserver.apache.org");
 
   if (uconfig->use_disk_buffer && !create_directory()) {
     TSError("Directory creation failed.");

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/2c3f7c5e/plugins/experimental/channel_stats/channel_stats.cc
----------------------------------------------------------------------
diff --git a/plugins/experimental/channel_stats/channel_stats.cc b/plugins/experimental/channel_stats/channel_stats.cc
index 5766bd0..d2ee228 100644
--- a/plugins/experimental/channel_stats/channel_stats.cc
+++ b/plugins/experimental/channel_stats/channel_stats.cc
@@ -807,8 +807,8 @@ TSPluginInit(int argc, const char *argv[])
   TSPluginRegistrationInfo info;
 
   info.plugin_name = (char *)PLUGIN_NAME;
-  info.vendor_name = (char *)"wkl";
-  info.support_email = (char *)"conanmind@gmail.com";
+  info.vendor_name = (char *)"Apache Software Foundation";
+  info.support_email = (char *)"dev@trafficserver.apache.org";
 
   if (TSPluginRegister(TS_SDK_VERSION_3_0, &info) != TS_SUCCESS) {
     fatal("plugin registration failed.");

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/2c3f7c5e/plugins/experimental/custom_redirect/custom_redirect.cc
----------------------------------------------------------------------
diff --git a/plugins/experimental/custom_redirect/custom_redirect.cc b/plugins/experimental/custom_redirect/custom_redirect.cc
index 6baf1a6..ea02333 100644
--- a/plugins/experimental/custom_redirect/custom_redirect.cc
+++ b/plugins/experimental/custom_redirect/custom_redirect.cc
@@ -130,8 +130,8 @@ TSPluginInit (int argc, const char *argv[])
 
 /*
     info.plugin_name = (char*)"";
-    info.vendor_name = (char*)"";
-    info.support_email = (char*)"";
+    info.vendor_name = (char*)"Apache Software Foundation";
+    info.support_email = (char*)"dev@trafficserver.apache.org";
 */ 
     /* This plugin supports following types of url redirect here:
      * 

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/2c3f7c5e/plugins/experimental/lua/plugin.cc
----------------------------------------------------------------------
diff --git a/plugins/experimental/lua/plugin.cc b/plugins/experimental/lua/plugin.cc
index 65b61a3..1c96e3b 100644
--- a/plugins/experimental/lua/plugin.cc
+++ b/plugins/experimental/lua/plugin.cc
@@ -28,7 +28,7 @@ TSPluginInit(int argc, const char * argv[])
   instanceid_t              instanceid;
 
   info.plugin_name = (char *)"lua";
-  info.vendor_name = (char *)"Apache Traffic Server";
+  info.vendor_name = (char *)"Apache Software Foundation";
   info.support_email = (char *)"dev@trafficserver.apache.org";
 
   if (TSPluginRegister(TS_SDK_VERSION_3_0, &info) != TS_SUCCESS) {

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/2c3f7c5e/plugins/experimental/memcached_remap/memcached_remap.cc
----------------------------------------------------------------------
diff --git a/plugins/experimental/memcached_remap/memcached_remap.cc b/plugins/experimental/memcached_remap/memcached_remap.cc
index 1816864..7e63812 100644
--- a/plugins/experimental/memcached_remap/memcached_remap.cc
+++ b/plugins/experimental/memcached_remap/memcached_remap.cc
@@ -184,7 +184,7 @@ void TSPluginInit(int argc, const char *argv[])
 
     info.plugin_name = const_cast < char *>(PLUGIN_NAME);
     info.vendor_name = const_cast < char *>("Apache Software Foundation");
-    info.support_email = const_cast < char *>("eric@ericbalsa.com");
+    info.support_email = const_cast < char *>("dev@trafficserver.apache.org");
 
     TSDebug(PLUGIN_NAME, "about to init memcached\n");
     if (TSPluginRegister(TS_SDK_VERSION_2_0, &info) != TS_SUCCESS) {

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/2c3f7c5e/plugins/experimental/metalink/metalink.cc
----------------------------------------------------------------------
diff --git a/plugins/experimental/metalink/metalink.cc b/plugins/experimental/metalink/metalink.cc
index 55e88c8..86747ef 100644
--- a/plugins/experimental/metalink/metalink.cc
+++ b/plugins/experimental/metalink/metalink.cc
@@ -654,8 +654,8 @@ TSPluginInit(int /* argc ATS_UNUSED */, const char */* argv ATS_UNUSED */[])
   TSPluginRegistrationInfo info;
 
   info.plugin_name = const_cast<char*>("metalink");
-  info.vendor_name = const_cast<char*>("Jack Bates");
-  info.support_email = const_cast<char*>("jack@nottheoilrig.com");
+  info.vendor_name = const_cast<char*>("Apache Software Foundation");
+  info.support_email = const_cast<char*>("dev@trafficserver.apache.org");
 
   if (TSPluginRegister(TS_SDK_VERSION_3_0, &info) != TS_SUCCESS) {
     TSError("Plugin registration failed");

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/2c3f7c5e/plugins/experimental/mysql_remap/mysql_remap.cc
----------------------------------------------------------------------
diff --git a/plugins/experimental/mysql_remap/mysql_remap.cc b/plugins/experimental/mysql_remap/mysql_remap.cc
index 4e2e2af..848537d 100644
--- a/plugins/experimental/mysql_remap/mysql_remap.cc
+++ b/plugins/experimental/mysql_remap/mysql_remap.cc
@@ -190,7 +190,7 @@ TSPluginInit(int argc, const char *argv[]) {
   
   info.plugin_name   = const_cast<char*>(PLUGIN_NAME);
   info.vendor_name   = const_cast<char*>("Apache Software Foundation");
-  info.support_email = const_cast<char*>("eric@ericbalsa.com");
+  info.support_email = const_cast<char*>("dev@trafficserver.apache.org");
 
   if (TSPluginRegister(TS_SDK_VERSION_2_0 , &info) != TS_SUCCESS) {
     TSError("mysql_remap: plugin registration failed.\n"); 

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/2c3f7c5e/plugins/experimental/rfc5861/rfc5861.c
----------------------------------------------------------------------
diff --git a/plugins/experimental/rfc5861/rfc5861.c b/plugins/experimental/rfc5861/rfc5861.c
index b5f9dbf..f1f6c5d 100644
--- a/plugins/experimental/rfc5861/rfc5861.c
+++ b/plugins/experimental/rfc5861/rfc5861.c
@@ -669,8 +669,8 @@ TSPluginInit (int argc, const char *argv[])
     TSCont main_cont;
 
     info.plugin_name = PLUGIN_NAME;
-    info.vendor_name = "OmniTI Computer Consulting on behalf of Oregon Health & Science University";
-    info.support_email = "phil@omniti.com";
+    info.vendor_name = "Apache Software Foundation";
+    info.support_email = "dev@trafficserver.apache.org";
 
     if (TSPluginRegister(TS_SDK_VERSION_3_0 , &info) != TS_SUCCESS)
     {

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/2c3f7c5e/plugins/experimental/spdy/spdy.cc
----------------------------------------------------------------------
diff --git a/plugins/experimental/spdy/spdy.cc b/plugins/experimental/spdy/spdy.cc
index 1a83e2a..e81a080 100644
--- a/plugins/experimental/spdy/spdy.cc
+++ b/plugins/experimental/spdy/spdy.cc
@@ -367,8 +367,8 @@ TSPluginInit(int argc, const char * argv[])
     TSPluginRegistrationInfo info;
 
     info.plugin_name = (char *)"spdy";
-    info.vendor_name = (char *)"James Peach";
-    info.support_email = (char *)"jamespeach@me.com";
+    info.vendor_name = (char *)"Apache Software Foundation";
+    info.support_email = (char *)"dev@trafficserver.apache.org";
 
     if (TSPluginRegister(TS_SDK_VERSION_3_0, &info) != TS_SUCCESS) {
         TSError("[spdy] Plugin registration failed");

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/2c3f7c5e/plugins/gzip/misc.cc
----------------------------------------------------------------------
diff --git a/plugins/gzip/misc.cc b/plugins/gzip/misc.cc
index 13f9d39..aeb6f30 100644
--- a/plugins/gzip/misc.cc
+++ b/plugins/gzip/misc.cc
@@ -145,7 +145,7 @@ register_plugin()
   TSPluginRegistrationInfo info;
 
   info.plugin_name = (char*)"gzip";
-  info.vendor_name = (char*)"Apache";
+  info.vendor_name = (char*)"Apache Software Foundation";
   info.support_email = (char*)"dev@trafficserver.apache.org";
 
   if (TSPluginRegister(TS_SDK_VERSION_3_0, &info) != TS_SUCCESS) {

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/2c3f7c5e/plugins/header_filter/header_filter.cc
----------------------------------------------------------------------
diff --git a/plugins/header_filter/header_filter.cc b/plugins/header_filter/header_filter.cc
index 33713e9..9a9f690 100644
--- a/plugins/header_filter/header_filter.cc
+++ b/plugins/header_filter/header_filter.cc
@@ -101,8 +101,8 @@ TSPluginInit(int argc, const char *argv[])
   TSPluginRegistrationInfo info;
 
   info.plugin_name = const_cast<char*>(PLUGIN_NAME);
-  info.vendor_name = const_cast<char*>("Apache");
-  info.support_email = const_cast<char*>("users@trafficserver.apache.org");
+  info.vendor_name = const_cast<char*>("Apache Software Foundation");
+  info.support_email = const_cast<char*>("dev@trafficserver.apache.org");
 
   if (TSPluginRegister(TS_SDK_VERSION_3_0 , &info) != TS_SUCCESS) {
     TSError("header_filter: plugin registration failed.\n"); 

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/2c3f7c5e/plugins/header_rewrite/header_rewrite.cc
----------------------------------------------------------------------
diff --git a/plugins/header_rewrite/header_rewrite.cc b/plugins/header_rewrite/header_rewrite.cc
index 1300742..20fd387 100644
--- a/plugins/header_rewrite/header_rewrite.cc
+++ b/plugins/header_rewrite/header_rewrite.cc
@@ -217,8 +217,8 @@ TSPluginInit(int argc, const char *argv[])
   TSPluginRegistrationInfo info;
 
   info.plugin_name = (char*)PLUGIN_NAME;
-  info.vendor_name = (char*)"";
-  info.support_email = (char*)"";
+  info.vendor_name = (char*)"Apache Software Foundation";
+  info.support_email = (char*)"dev@trafficserver.apache.org";
 
   if (TS_SUCCESS != TSPluginRegister(TS_SDK_VERSION_3_0 , &info)) {
     TSError("header_rewrite: plugin registration failed.\n"); 

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/2c3f7c5e/plugins/libloader/libloader.c
----------------------------------------------------------------------
diff --git a/plugins/libloader/libloader.c b/plugins/libloader/libloader.c
index ef84c2f..5cf990e 100644
--- a/plugins/libloader/libloader.c
+++ b/plugins/libloader/libloader.c
@@ -58,7 +58,7 @@ void TSPluginInit(int argc, const char *argv[])
 
     info.plugin_name = (char *)"libloader";
     info.vendor_name = (char *)"Apache Software Foundation";
-    info.support_email = (char *)"users@trafficserver.apache.org";
+    info.support_email = (char *)"dev@trafficserver.apache.org";
 
     if (TSPluginRegister(TS_SDK_VERSION_3_0, &info) != TS_SUCCESS) {
         TSError("[libloader] Plugin registration failed.\n");

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/2c3f7c5e/plugins/stats_over_http/stats_over_http.c
----------------------------------------------------------------------
diff --git a/plugins/stats_over_http/stats_over_http.c b/plugins/stats_over_http/stats_over_http.c
index 89a13af..d1f0af7 100644
--- a/plugins/stats_over_http/stats_over_http.c
+++ b/plugins/stats_over_http/stats_over_http.c
@@ -256,7 +256,7 @@ TSPluginInit(int argc, const char *argv[])
 
   info.plugin_name = "stats";
   info.vendor_name = "Apache Software Foundation";
-  info.support_email = "jesus@omniti.com";
+  info.support_email = "dev@trafficserver.apache.org";
 
   if (TSPluginRegister(TS_SDK_VERSION_2_0, &info) != TS_SUCCESS)
     TSError("Plugin registration failed. \n");


[42/50] [abbrv] git commit: TS-2230 header_rewrite should support the same hook-management that header_filter does for remap rules.

Posted by zw...@apache.org.
TS-2230 header_rewrite should support the same hook-management that
        header_filter does for remap rules.

This allows for injecting hook / rules from remap.config into hooks
outside of the remap phase itself. This is particularly useful for
doing header filtering on responses from an origin, based on which
remap rule triggered. With this, a remap.config instance can do e.g.

cond %{READ_RESPONSE_HDR_HOOK}
cond %{STATUS} >199    [AND]
cond %{STATUS} <299
rm-header Cache-Control
add-header Cache-Control "max-age=3600"

(we should add a set-header, but that's a different bug).

TS-2227 This commit also allows for multiple configs per line

This allows a remap.config file to have multiple @pparam's with
configs (such that you can e.g. share one across mulitple rules).
This also works for the global config(s) in plugin.config.

I accidentally merged the two patches, hence just one commit.


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

Branch: refs/heads/5.0.x
Commit: 9dcd00b8f82ec0a2678ae11ae739f68d0a496191
Parents: a3b07f9
Author: Leif Hedstrom <zw...@apache.org>
Authored: Fri Oct 18 15:32:15 2013 -0600
Committer: Leif Hedstrom <zw...@apache.org>
Committed: Wed Oct 23 16:09:35 2013 -0600

----------------------------------------------------------------------
 CHANGES                                  |   6 +
 plugins/header_rewrite/README            |  22 ++++
 plugins/header_rewrite/header_rewrite.cc | 163 ++++++++++++++++----------
 plugins/header_rewrite/resources.h       |   2 +-
 4 files changed, 132 insertions(+), 61 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/trafficserver/blob/9dcd00b8/CHANGES
----------------------------------------------------------------------
diff --git a/CHANGES b/CHANGES
index 67976e1..c14aee9 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,12 @@
                                                          -*- coding: utf-8 -*-
 Changes with Apache Traffic Server 4.1.0
 
+  *) [TS-2227] Allow for multiple config files for a header_rewrite plugin
+   invocation (be it in remap.config or plugin.config).
+
+  *) [TS-2230] header_rewrite should support the same hook-management that
+  header_filter does for remap rules. This allows per-remap rules that
+  triggers in hooks other than the remap phase.
 
   *) [TS-2228] Add a set-config operator for header_rewrite plugin.
 

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/9dcd00b8/plugins/header_rewrite/README
----------------------------------------------------------------------
diff --git a/plugins/header_rewrite/README b/plugins/header_rewrite/README
index 4244e4a..6b5f535 100644
--- a/plugins/header_rewrite/README
+++ b/plugins/header_rewrite/README
@@ -7,6 +7,24 @@ this rolling asap.
 Note that currently only static string "values" are supported. We'll add
 advanced features to allow for expansions in a future release.
 
+Using the plugin
+----------------
+
+This plugin can be used as both a global plugin, enabled in plugin.config:
+
+  header_rewrite.so config_file_1.conf config_file_2.conf ...
+
+These are global rules, which would apply to all requests. Another option is
+to use per remap rules in remap.config
+
+  map http://a http://b @plugin=header_rewrite.so @pparam=rules1.conf ...
+
+
+In the second example, hooks which are not to be executed during the remap
+phase (the default) causes a transaction hook to be instantiated and used
+at a later time. This allows you to setup e.g. a rule that gets executed
+during the origin response header parsing, using READ_RESPONSE_HDR_HOOK.
+
 
 Operators
 ---------
@@ -78,6 +96,10 @@ each rule. This implies that a new hook condition starts a new rule as well.
   cond %{SEND_REQUEST_HDR_HOOK}
   cond %{SEND_RESPONSE_HDR_HOOK}
 
+For remap.config plugin instanations, the default hook is named
+REMAP_PSEUDO_HOOK. This can be useful if you are mixing other hooks in a
+configuration, but being the default it is also optional.
+
 
 Condition flags
 ---------------

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/9dcd00b8/plugins/header_rewrite/header_rewrite.cc
----------------------------------------------------------------------
diff --git a/plugins/header_rewrite/header_rewrite.cc b/plugins/header_rewrite/header_rewrite.cc
index 9d3dde0..3bcb21d 100644
--- a/plugins/header_rewrite/header_rewrite.cc
+++ b/plugins/header_rewrite/header_rewrite.cc
@@ -15,11 +15,6 @@
   See the License for the specific language governing permissions and
   limitations under the License.
 */
-//////////////////////////////////////////////////////////////////////////////////////////////
-// header_rewrite: YTS plugin to do header rewrites
-// --------------
-//
-//
 #include <fstream>
 #include <string>
 #include <boost/algorithm/string.hpp>
@@ -31,26 +26,41 @@
 #include "ruleset.h"
 #include "resources.h"
 
-// "Defines"
+// Debugs
 const char* PLUGIN_NAME = "header_rewrite";
 const char* PLUGIN_NAME_DBG = "header_rewrite_dbg";
 
 static const char* DEFAULT_CONF_PATH = "/usr/local/etc/header_rewrite/";
 
+// Simple wrapper around a configuration file / set. This is useful such that
+// we can reuse most of the code for both global and per-remap rule sets.
+struct RulesConfig
+{
+  RulesConfig()
+  {
+    memset(rules, 0, sizeof(rules));
+    memset(resids, 0, sizeof(resids));
+  }
+
+  ~RulesConfig()
+  {
+    for (int i=TS_HTTP_READ_REQUEST_HDR_HOOK; i<TS_HTTP_LAST_HOOK; ++i)
+      delete rules[i];
+  }
 
-// Global holding the rulesets and resource IDs
-static RuleSet* all_rules[TS_HTTP_LAST_HOOK+1];
-static ResourceIDs all_resids[TS_HTTP_LAST_HOOK+1];
+  RuleSet* rules[TS_HTTP_LAST_HOOK+1];
+  ResourceIDs resids[TS_HTTP_LAST_HOOK+1];
+};
 
 // Helper function to add a rule to the rulesets
 static bool
-add_rule(RuleSet* rule) {
+add_rule(RuleSet* rule, RulesConfig *conf) {
   if (rule && rule->has_operator()) {
     TSDebug(PLUGIN_NAME, "Adding rule to hook=%d\n", rule->get_hook());
-    if (NULL == all_rules[rule->get_hook()]) {
-      all_rules[rule->get_hook()] = rule;
+    if (NULL == conf->rules[rule->get_hook()]) {
+      conf->rules[rule->get_hook()] = rule;
     } else {
-      all_rules[rule->get_hook()]->append(rule);
+      conf->rules[rule->get_hook()]->append(rule);
     }
     return true;
   }
@@ -60,14 +70,13 @@ add_rule(RuleSet* rule) {
 
 
 ///////////////////////////////////////////////////////////////////////////////
-// Simple "config" parser, this modifies the global above. ToDo: What happens
-// on a "config" reload?
+// Config parser, use to parse both the global, and per-remap, configurations.
 //
 // Note that this isn't particularly efficient, but it's a startup time cost
 // anyways (or reload for remap.config), so not really in the critical path.
 //
 bool
-parse_config(const std::string fname, TSHttpHookID default_hook)
+parse_config(const std::string fname, TSHttpHookID default_hook, RulesConfig *conf)
 {
   RuleSet* rule = NULL;
   std::string filename = fname;
@@ -93,7 +102,7 @@ parse_config(const std::string fname, TSHttpHookID default_hook)
 
     getline(f, line);
     ++lineno; // ToDo: we should probably use this for error messages ...
-    TSDebug(PLUGIN_NAME, "Reading line: %d: %s", lineno, line.c_str());
+    TSDebug(PLUGIN_NAME_DBG, "Reading line: %d: %s", lineno, line.c_str());
 
     boost::trim(line);
     if (line.empty() || (line[0] == '#'))
@@ -104,7 +113,7 @@ parse_config(const std::string fname, TSHttpHookID default_hook)
       continue;
 
     // If we are at the beginning of a new condition, save away the previous rule (but only if it has operators).
-    if (p.is_cond() && add_rule(rule))
+    if (p.is_cond() && add_rule(rule, conf))
       rule = NULL;
 
     if (NULL == rule) {
@@ -128,6 +137,9 @@ parse_config(const std::string fname, TSHttpHookID default_hook)
       } else if (p.cond_op_is("SEND_RESPONSE_HDR_HOOK")) {
         rule->set_hook(TS_HTTP_SEND_RESPONSE_HDR_HOOK);
         continue;
+      } else if (p.cond_op_is("REMAP_PSEUDO_HOOK")) {
+        rule->set_hook(TS_REMAP_PSEUDO_HOOK);
+        continue;
       }
     }
 
@@ -139,12 +151,14 @@ parse_config(const std::string fname, TSHttpHookID default_hook)
   }
 
   // Add the last rule (possibly the only rule)
-  add_rule(rule);
+  add_rule(rule, conf);
 
   // Collect all resource IDs that we need
-  for (int i=TS_HTTP_READ_REQUEST_HDR_HOOK; i<TS_HTTP_LAST_HOOK; ++i)
-    if (all_rules[i])
-      all_resids[i] = all_rules[i]->get_all_resource_ids();
+  for (int i=TS_HTTP_READ_REQUEST_HDR_HOOK; i<TS_HTTP_LAST_HOOK; ++i) {
+    if (conf->rules[i]) {
+      conf->resids[i] = conf->rules[i]->get_all_resource_ids();
+    }
+  }
 
   return true;
 }
@@ -156,12 +170,9 @@ parse_config(const std::string fname, TSHttpHookID default_hook)
 static int
 cont_rewrite_headers(TSCont contp, TSEvent event, void *edata)
 {
-  TSDebug(PLUGIN_NAME, "plugin: %d", event);
-
-  TSHttpTxn txnp = (TSHttpTxn) edata;
-  Resources res(txnp, contp);
-  const RuleSet* rule = NULL;
+  TSHttpTxn txnp = static_cast<TSHttpTxn>(edata);
   TSHttpHookID hook = TS_HTTP_LAST_HOOK;
+  RulesConfig* conf = static_cast<RulesConfig*>(TSContDataGet(contp));
 
   // Get the resources necessary to process this event
   switch (event) {
@@ -187,10 +198,12 @@ cont_rewrite_headers(TSCont contp, TSEvent event, void *edata)
   }
 
   if (hook != TS_HTTP_LAST_HOOK) {
-    res.gather(all_resids[hook], hook);
-    rule = all_rules[hook];
+    const RuleSet* rule = conf->rules[hook];
+    Resources res(txnp, contp);
+
+    res.gather(conf->resids[hook], hook);
 
-    // Evaluation
+    // Evaluation of all rules. This code is sort of duplicate in DoRemap as well.
     while (rule) {
       if (rule->eval(res)) {
         OperModifiers rt = rule->exec(res);
@@ -223,29 +236,37 @@ TSPluginInit(int argc, const char *argv[])
   if (TS_SUCCESS != TSPluginRegister(TS_SDK_VERSION_3_0 , &info)) {
     TSError("%s: plugin registration failed.\n", PLUGIN_NAME);
   }
-
   TSDebug(PLUGIN_NAME, "number of arguments: %d", argc);
-  if (argc != 2) {
-    TSError("%s usage: %s <config-file> ... \n", PLUGIN_NAME, argv[0]);
-    assert(argc == 2);
-  }
 
-  // Initialize the globals
-  for (int i=TS_HTTP_READ_REQUEST_HDR_HOOK; i<TS_HTTP_LAST_HOOK; ++i) {
-    all_rules[i] = NULL;
-    all_resids[i] = RSRC_NONE;
+  // Parse the global config file(s). All rules are just appended
+  // to the "global" Rules configuration.
+  RulesConfig* conf = new RulesConfig;
+  bool got_config = false;
+
+  for (int i=1; i < argc; ++i) {
+    // Parse the config file(s). Note that multiple config files are
+    // just appended to the configurations.
+    if (!parse_config(argv[i], TS_HTTP_READ_RESPONSE_HDR_HOOK, conf)) {
+      TSError("header_rewrite: failed to parse configuration file %s", argv[argc]);
+    } else {
+      got_config = true;
+    }
   }
 
-  // Parse the config file
-  if (parse_config(argv[1], TS_HTTP_READ_RESPONSE_HDR_HOOK)) {
+  if (got_config) {
+    TSCont contp = TSContCreate(cont_rewrite_headers, NULL);
+    TSContDataSet(contp, conf);
+
     for (int i=TS_HTTP_READ_REQUEST_HDR_HOOK; i<TS_HTTP_LAST_HOOK; ++i) {
-      if (all_rules[i]) {
+      if (conf->rules[i]) {
         TSDebug(PLUGIN_NAME, "adding hook: %d", i);
-        TSHttpHookAdd(static_cast<TSHttpHookID>(i), TSContCreate(cont_rewrite_headers, NULL));
+        TSHttpHookAdd(static_cast<TSHttpHookID>(i), contp);
       }
     }
   } else {
+    // Didn't get anything, nuke it.
     TSError("%s: failed to parse configuration file", PLUGIN_NAME);
+    delete conf;
   }
 }
 
@@ -287,27 +308,27 @@ TSRemapNewInstance(int argc, char *argv[], void **ih, char * /* errbuf ATS_UNUSE
     return TS_ERROR;
   }
 
-  // TODO: this is a big ugly, we use a pseudo hook for parsing the config for a 
-  // remap instantiation.
-  all_rules[TS_REMAP_PSEUDO_HOOK] = NULL;
-  if (!parse_config(argv[2], TS_REMAP_PSEUDO_HOOK)) {
-    TSError("%s: Unable to create remap instance", PLUGIN_NAME);
-    return TS_ERROR;
+  RulesConfig* conf = new RulesConfig;
+
+  for (int i=2; i < argc; ++i) {
+    if (!parse_config(argv[i], TS_REMAP_PSEUDO_HOOK, conf)) {
+      TSError("%s: Unable to create remap instance", PLUGIN_NAME);
+      return TS_ERROR;
+    }
   }
 
-  *ih = all_rules[TS_REMAP_PSEUDO_HOOK];
-  all_rules[TS_REMAP_PSEUDO_HOOK] = NULL;
+  *ih = conf;
+  TSDebug(PLUGIN_NAME, "added header_rewrite remap rule set");
 
-  TSDebug(PLUGIN_NAME, "successfully initialize the header_rewrite plugin");
   return TS_SUCCESS;
 }
 
 void
 TSRemapDeleteInstance(void *ih)
 {
-  RuleSet* rule = static_cast<RuleSet*>(ih);
+  RulesConfig* conf = static_cast<RulesConfig*>(ih);
 
-  delete rule;
+  delete conf;
 }
 
 
@@ -323,17 +344,40 @@ TSRemapDoRemap(void *ih, TSHttpTxn rh, TSRemapRequestInfo *rri)
     TSDebug(PLUGIN_NAME, "No Rules configured, falling back to default");
     return rval;
   } else {
-    RuleSet* rule = (RuleSet*)ih;
-    Resources res((TSHttpTxn)rh, rri);
+    RulesConfig* conf = static_cast<RulesConfig*>(ih);
+
+    // ToDo: Would it be faster / better to register the global hook for all
+    // hooks, as we do in header_filter, regardless if there's a known config
+    // for that hook? For now, we assume it's cheaper / faster to create a
+    // TXN hook when necessary.
+
+    // Go through all hooks we support, and setup the txn hook(s) as necessary
+    for (int i=TS_HTTP_READ_REQUEST_HDR_HOOK; i<TS_HTTP_LAST_HOOK; ++i) {
+      TSCont contp = NULL;
+
+      if (conf->rules[i]) {
+        if (NULL == contp) {
+          contp = TSContCreate(cont_rewrite_headers, NULL);
+          TSContDataSet(contp, conf);
+        }
+        TSHttpTxnHookAdd(rh, static_cast<TSHttpHookID>(i), contp);
+        TSDebug(PLUGIN_NAME, "activated transaction hook via remap.config: new hook=%d", i);
+      }
+    }
+
+    // Now handle the remap specific rules for the "remap hook" (which is not a real hook).
+    // This avoids scheduling an additional continuation for a very common case.
+    RuleSet* rule = conf->rules[TS_REMAP_PSEUDO_HOOK];
+    Resources res(rh, rri);
 
-    // TODO: This might be suboptimal, do we always need the client request
-    // headers in a remap plugin?
+    // res.gather(conf->resids[TS_REMAP_PSEUDO_HOOK], TS_REMAP_PSEUDO_HOOK);
     res.gather(RSRC_CLIENT_REQUEST_HEADERS, TS_REMAP_PSEUDO_HOOK);
 
-    // Evaluation
+    // Evaluation. This code is duplicated sort of, should we merge with the continuation evaluator ?
     while (rule) {
       if (rule->eval(res)) {
         OperModifiers rt = rule->exec(res);
+
         if (res.changed_url == true)
           rval = TSREMAP_DID_REMAP;
 
@@ -343,7 +387,6 @@ TSRemapDoRemap(void *ih, TSHttpTxn rh, TSRemapRequestInfo *rri)
       }
       rule = rule->next;
     }
-
   }
 
   TSDebug(PLUGIN_NAME, "returing with status: %d", rval);

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/9dcd00b8/plugins/header_rewrite/resources.h
----------------------------------------------------------------------
diff --git a/plugins/header_rewrite/resources.h b/plugins/header_rewrite/resources.h
index d2ce9f5..d63b4e7 100644
--- a/plugins/header_rewrite/resources.h
+++ b/plugins/header_rewrite/resources.h
@@ -57,7 +57,7 @@ public:
   Resources(TSHttpTxn txnptr, TSRemapRequestInfo *rri) :
     txnp(txnptr), contp(NULL),
     bufp(NULL), hdr_loc(NULL), client_bufp(NULL), client_hdr_loc(NULL), resp_status(TS_HTTP_STATUS_NONE),
-    _rri(rri), _ready(false)
+      _rri(rri), changed_url(false), _ready(false)
   {
     TSDebug(PLUGIN_NAME_DBG, "Calling CTOR for Resources (RemapAPI)");
     TSDebug(PLUGIN_NAME, "rri: %p", _rri);


[44/50] [abbrv] git commit: Fixed formatting.

Posted by zw...@apache.org.
Fixed formatting.


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

Branch: refs/heads/5.0.x
Commit: 0c29d7358a7785d0d9878941bfdc31cb8843beef
Parents: 2482196
Author: Leif Hedstrom <zw...@apache.org>
Authored: Thu Oct 24 21:38:10 2013 -0600
Committer: Leif Hedstrom <zw...@apache.org>
Committed: Fri Oct 25 00:33:02 2013 -0600

----------------------------------------------------------------------
 CHANGES | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/trafficserver/blob/0c29d735/CHANGES
----------------------------------------------------------------------
diff --git a/CHANGES b/CHANGES
index c14aee9..729d765 100644
--- a/CHANGES
+++ b/CHANGES
@@ -12,16 +12,17 @@ Changes with Apache Traffic Server 4.1.0
 
   *) [TS-2226] Add a set-header operator for header_rewrite plugin.
 
-  *) [TS-2296] improve ConfigProcessor reference counting
+  *) [TS-2296] improve ConfigProcessor reference counting.
 
-  *) [ TS-2295] update statvfs usage
+  *) [ TS-2295] update statvfs usage.
 
-  *) [TS-2139] Fix PURGE twice to remove object in cache if enable-interim-cache
+  *) [TS-2139] Fix PURGE twice to remove object in cache if
+   enable-interim-cache.
 
   *) [TS-2216] Fix cquuh log tag, which does not calculate the right
    string length.
 
-  *) [TS-2275] fix interim cache lossing data if the server process crash
+  *) [TS-2275] fix interim cache lossing data if the server process crash.
    Author: Gang Li.
 
   *) [TS-2291] Add remap_stats plugin to experimental.
@@ -31,7 +32,7 @@ Changes with Apache Traffic Server 4.1.0
 
   *) [TS-1988] cquuc and cquup log tags can have no values.
 
-  *) [TS-2159] Force first log rotation at proxy.config.log.rolling_size_mb
+  *) [TS-2159] Force first log rotation at proxy.config.log.rolling_size_mb.
 
   *) [TS-2138] Fix the bug that restarting ats cause cache data loss if
   enable the native-aio.
@@ -59,7 +60,7 @@ Changes with Apache Traffic Server 4.1.0
    string length parameter).
 
   *) [TS-2261] Add config option to restore/elevate access to reading files by
-   root when loading plugins
+   root when loading plugins.
 
   *) [TS-2257] Healthcheck plugin can stop watching some events.
 


[38/50] [abbrv] git commit: TS-2296: improve ConfigProcessor reference counting

Posted by zw...@apache.org.
TS-2296: improve ConfigProcessor reference counting

Use the standard RefCountObj reference counting of ConfigInfo
objects. Add regression tests so that we can understand how this
is supposed to work better.


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

Branch: refs/heads/5.0.x
Commit: 6da424faa886e12b658dbe426aad9d19512065c6
Parents: f760dac
Author: James Peach <jp...@apache.org>
Authored: Mon Oct 7 16:08:36 2013 -0700
Committer: James Peach <jp...@apache.org>
Committed: Wed Oct 23 09:20:20 2013 -0700

----------------------------------------------------------------------
 CHANGES             |   2 +
 lib/ts/Ptr.h        |   2 +
 mgmt/ProxyConfig.cc | 115 ++++++++++++++++++++++++++++++++++++++++++-----
 mgmt/ProxyConfig.h  |  18 ++++----
 4 files changed, 115 insertions(+), 22 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/trafficserver/blob/6da424fa/CHANGES
----------------------------------------------------------------------
diff --git a/CHANGES b/CHANGES
index c66e53e..84b8e1b 100644
--- a/CHANGES
+++ b/CHANGES
@@ -2,6 +2,8 @@
 Changes with Apache Traffic Server 4.1.0
 
 
+  *) [TS-2296] improve ConfigProcessor reference counting
+
   *) [ TS-2295] update statvfs usage
 
   *) [TS-2139] Fix PURGE twice to remove object in cache if enable-interim-cache

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/6da424fa/lib/ts/Ptr.h
----------------------------------------------------------------------
diff --git a/lib/ts/Ptr.h b/lib/ts/Ptr.h
index c14759a..7cea36c 100644
--- a/lib/ts/Ptr.h
+++ b/lib/ts/Ptr.h
@@ -272,6 +272,7 @@ public:
   volatile int m_refcount;
 };
 
+// Increment the reference count, returning the new count.
 inline int
 RefCountObj::refcount_inc()
 {
@@ -280,6 +281,7 @@ RefCountObj::refcount_inc()
 
 #define REF_COUNT_OBJ_REFCOUNT_INC(_x) (_x)->refcount_inc()
 
+// Decrement the reference count, returning the new count.
 inline int
 RefCountObj::refcount_dec()
 {

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/6da424fa/mgmt/ProxyConfig.cc
----------------------------------------------------------------------
diff --git a/mgmt/ProxyConfig.cc b/mgmt/ProxyConfig.cc
index e236897..2c6f7be 100644
--- a/mgmt/ProxyConfig.cc
+++ b/mgmt/ProxyConfig.cc
@@ -24,6 +24,7 @@
 #include "libts.h"
 #include "ProxyConfig.h"
 #include "P_EventSystem.h"
+#include "ts/TestBox.h"
 
 ConfigProcessor configProcessor;
 
@@ -124,7 +125,7 @@ ConfigProcessor::ConfigProcessor()
 }
 
 unsigned int
-ConfigProcessor::set(unsigned int id, ConfigInfo * info)
+ConfigProcessor::set(unsigned int id, ConfigInfo * info, unsigned timeout_secs)
 {
   ConfigInfo *old_info;
   int idx;
@@ -135,7 +136,13 @@ ConfigProcessor::set(unsigned int id, ConfigInfo * info)
     ink_assert(id <= MAX_CONFIGS);
   }
 
-  info->m_refcount = 1;
+  // Don't be an idiot and use a zero timeout ...
+  ink_assert(timeout_secs > 0);
+
+  // New objects *must* start with a zero refcount. The config
+  // processor holds it's own refcount. We should be the only
+  // refcount holder at this point.
+  ink_release_assert(info->refcount_inc() == 1);
 
   if (id > MAX_CONFIGS) {
     // invalid index
@@ -146,11 +153,14 @@ ConfigProcessor::set(unsigned int id, ConfigInfo * info)
   idx = id - 1;
 
   do {
-    old_info = (ConfigInfo *) infos[idx];
-  } while (!ink_atomic_cas( & infos[idx], old_info, info));
+    old_info = infos[idx];
+  } while (!ink_atomic_cas(&infos[idx], old_info, info));
 
   if (old_info) {
-    eventProcessor.schedule_in(NEW(new ConfigInfoReleaser(id, old_info)), HRTIME_SECONDS(60));
+    // The ConfigInfoReleaser now takes our refcount, but
+    // someother thread might also have one ...
+    ink_assert(old_info->refcount() > 0);
+    eventProcessor.schedule_in(NEW(new ConfigInfoReleaser(id, old_info)), HRTIME_SECONDS(timeout_secs));
   }
 
   return id;
@@ -171,18 +181,17 @@ ConfigProcessor::get(unsigned int id)
   }
 
   idx = id - 1;
-  info = (ConfigInfo *) infos[idx];
-  if (ink_atomic_increment((int *) &info->m_refcount, 1) < 0) {
-    ink_assert(!"not reached");
-  }
+  info = infos[idx];
 
+  // Hand out a refcount to the caller. We should still have out
+  // own refcount, so it should be at least 2.
+  ink_release_assert(info->refcount_inc() > 1);
   return info;
 }
 
 void
 ConfigProcessor::release(unsigned int id, ConfigInfo * info)
 {
-  int val;
   int idx;
 
   ink_assert(id != 0);
@@ -194,9 +203,91 @@ ConfigProcessor::release(unsigned int id, ConfigInfo * info)
   }
 
   idx = id - 1;
-  val = ink_atomic_increment((int *) &info->m_refcount, -1);
 
-  if ((infos[idx] != info) && (val == 1)) {
+  if (info->refcount_dec() == 0) {
+    // When we release, we should already have replaced this object in the index.
+    ink_release_assert(info != this->infos[idx]);
     delete info;
   }
 }
+
+#if TS_HAS_TESTS
+
+enum {
+  REGRESSION_CONFIG_FIRST   = 1,   // last config in a sequence
+  REGRESSION_CONFIG_LAST    = 2,   // last config in a sequence
+  REGRESSION_CONFIG_SINGLE  = 4, // single-owner config
+};
+
+struct RegressionConfig : public ConfigInfo
+{
+
+  RegressionConfig(RegressionTest * r, int * ps, unsigned f)
+      : test(r), pstatus(ps), flags(f) {
+    if (this->flags & REGRESSION_CONFIG_SINGLE) {
+      TestBox box(this->test, this->pstatus);
+      box.check(this->refcount() == 1, "invalid refcount %d (should be 1)", this->refcount());
+    }
+  }
+
+  ~RegressionConfig() {
+    TestBox box(this->test, this->pstatus);
+
+    box.check(this->refcount() == 0, "invalid refcount %d (should be 0)", this->refcount());
+
+    // If we are the last config to be scheduled, pass the test.
+    // Otherwise, verify that the test is still running ...
+    if (REGRESSION_CONFIG_LAST & flags) {
+      *this->pstatus = REGRESSION_TEST_PASSED;
+    } else {
+      box.check(*this->pstatus == REGRESSION_TEST_INPROGRESS, "intermediate config out of sequence");
+    }
+  }
+
+  RegressionTest * test;
+  int *     pstatus;
+  unsigned  flags;
+};
+
+// Test that ConfigProcessor::set() correctly releases the old ConfigInfo after a timeout.
+REGRESSION_TEST(ProxyConfig_Set)(RegressionTest * test, int /* atype ATS_UNUSED */, int * pstatus)
+{
+  int configid = 0;
+  *pstatus = REGRESSION_TEST_INPROGRESS;
+  configid = configProcessor.set(configid, new RegressionConfig(test, pstatus, REGRESSION_CONFIG_FIRST), 1);
+  configid = configProcessor.set(configid, new RegressionConfig(test, pstatus, REGRESSION_CONFIG_FIRST), 1);
+  configid = configProcessor.set(configid, new RegressionConfig(test, pstatus, REGRESSION_CONFIG_FIRST), 1);
+  configid = configProcessor.set(configid, new RegressionConfig(test, pstatus, REGRESSION_CONFIG_LAST), 2);
+
+  // Push one more RegressionConfig to force the tagged one to
+  // get destroyed.
+  configid = configProcessor.set(configid, new RegressionConfig(test, pstatus, 0), 4);
+
+  return;
+}
+
+// Test that ConfigProcessor::release() correctly releases the old ConfigInfo across an implicit
+// release timeout.
+REGRESSION_TEST(ProxyConfig_Release)(RegressionTest * test, int /* atype ATS_UNUSED */, int * pstatus)
+{
+  int configid = 0;
+  RegressionConfig * config;
+
+  *pstatus = REGRESSION_TEST_INPROGRESS;
+
+  // Set an initial config, then get it back to hold a reference count.
+  configid = configProcessor.set(configid, new RegressionConfig(test, pstatus, REGRESSION_CONFIG_LAST), 1);
+  config = (RegressionConfig *)configProcessor.get(configid);
+
+  // Now update the config a few times.
+  configid = configProcessor.set(configid, new RegressionConfig(test, pstatus, REGRESSION_CONFIG_FIRST), 1);
+  configid = configProcessor.set(configid, new RegressionConfig(test, pstatus, REGRESSION_CONFIG_FIRST), 1);
+  configid = configProcessor.set(configid, new RegressionConfig(test, pstatus, REGRESSION_CONFIG_FIRST), 1);
+
+  sleep(2);
+
+  // Release the reference count. Since we were keeping this alive, it should be the last to die.
+  configProcessor.release(configid, config);
+}
+
+#endif /* TS_HAS_TESTS */

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/6da424fa/mgmt/ProxyConfig.h
----------------------------------------------------------------------
diff --git a/mgmt/ProxyConfig.h b/mgmt/ProxyConfig.h
index 8fd6aa9..bb55f1b 100644
--- a/mgmt/ProxyConfig.h
+++ b/mgmt/ProxyConfig.h
@@ -54,21 +54,19 @@ pmgmt->registerMgmtCallback(_signal,_fn,_data)
 
 #define MAX_CONFIGS  100
 
-struct ConfigInfo
-{
-  volatile int m_refcount;
-
-  virtual ~ ConfigInfo()
-  {
-  }
-};
-
+typedef RefCountObj ConfigInfo;
 
 class ConfigProcessor
 {
 public:
   ConfigProcessor();
 
+  enum {
+    // The number of seconds to wait before garbage collecting stale ConfigInfo objects. There's
+    // no good reason to tune this, outside of regression tests, so don't.
+    CONFIG_PROCESSOR_RELEASE_SECS = 60
+  };
+
   template <typename ClassType, typename ConfigType>
   struct scoped_config {
     scoped_config() : ptr(ClassType::acquire()) {}
@@ -82,7 +80,7 @@ public:
     ConfigType * ptr;
   };
 
-  unsigned int set(unsigned int id, ConfigInfo * info);
+  unsigned int set(unsigned int id, ConfigInfo * info, unsigned timeout_secs = CONFIG_PROCESSOR_RELEASE_SECS);
   ConfigInfo *get(unsigned int id);
   void release(unsigned int id, ConfigInfo * data);
 


[15/50] [abbrv] initial atscppapi commit

Posted by zw...@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


[37/50] [abbrv] git commit: TS-2295: update statvfs usage

Posted by zw...@apache.org.
TS-2295: update statvfs usage

Use statvfs(2) everywhere. Clean up headers so that ink_file.h has
enough includes to use statvfs(2).


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

Branch: refs/heads/5.0.x
Commit: f760dac42f6cbdba37259a2f57e37f55e8cb2228
Parents: 5460ce5
Author: James Peach <jp...@apache.org>
Authored: Tue Sep 24 21:40:31 2013 -0700
Committer: James Peach <jp...@apache.org>
Committed: Tue Oct 22 21:33:25 2013 -0700

----------------------------------------------------------------------
 CHANGES                    |  3 +++
 configure.ac               |  4 +++-
 iocore/cache/Store.cc      | 46 +++++++++++++++--------------------------
 lib/ts/ink_file.h          | 18 ++++++++++++++--
 proxy/logging/LogConfig.cc | 36 ++++----------------------------
 5 files changed, 43 insertions(+), 64 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/trafficserver/blob/f760dac4/CHANGES
----------------------------------------------------------------------
diff --git a/CHANGES b/CHANGES
index 77a834f..c66e53e 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,9 @@
                                                          -*- coding: utf-8 -*-
 Changes with Apache Traffic Server 4.1.0
 
+
+  *) [ TS-2295] update statvfs usage
+
   *) [TS-2139] Fix PURGE twice to remove object in cache if enable-interim-cache
 
   *) [TS-2216] Fix cquuh log tag, which does not calculate the right

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/f760dac4/configure.ac
----------------------------------------------------------------------
diff --git a/configure.ac b/configure.ac
index bb23933..b25a6fb 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1419,7 +1419,7 @@ AM_CONDITIONAL([BUILD_HTTP_LOAD], [test x"$ac_cv_func_epoll_ctl" = x"yes"])
 # -----------------------------------------------------------------------------
 # 5. CHECK FOR HEADER FILES
 
-AC_CHECK_HEADERS([sys/types.h sys/mman.h])
+TS_FLAG_HEADERS([sys/types.h sys/mman.h])
 TS_FLAG_HEADERS([sys/epoll.h \
                   sys/event.h \
                   sys/param.h \
@@ -1504,6 +1504,8 @@ AC_SUBST(net_ppp_defsh)
 AC_SUBST(ifaddrsh)
 AC_SUBST(readline_readlineh)
 
+TS_FLAG_HEADERS([sys/statfs.h sys/statvfs.h sys/disk.h sys/disklabel.h])
+
 TS_FLAG_HEADERS([sys/sysctl.h], [], [],
                  [[#ifdef HAVE_SYS_PARAM_H
                     #include <sys/param.h>

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/f760dac4/iocore/cache/Store.cc
----------------------------------------------------------------------
diff --git a/iocore/cache/Store.cc b/iocore/cache/Store.cc
index 55c35b7..bd13bfd 100644
--- a/iocore/cache/Store.cc
+++ b/iocore/cache/Store.cc
@@ -25,6 +25,18 @@
 #include "P_Cache.h"
 #include "I_Layout.h"
 
+#if HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#if HAVE_SYS_DISK_H
+#include <sys/disk.h>
+#endif
+
+#if HAVE_SYS_DISKLABEL_H
+#include <sys/disklabel.h>
+#endif
+
 // Global
 Store theStore;
 
@@ -449,19 +461,6 @@ Store::write_config_data(int fd)
 }
 
 #if defined(freebsd) || defined(darwin) || defined(openbsd)
-// TODO: Those are probably already included from the ink_platform.h
-#include <ctype.h>
-#include <sys/types.h>
-#include <sys/param.h>
-#include <sys/mount.h>
-#if defined(freebsd)
-#include <sys/disk.h>
-#include <sys/disklabel.h>
-#elif defined(darwin)
-#include <sys/disk.h>
-#include <sys/statvfs.h>
-#endif
-#include <string.h>
 
 const char *
 Span::init(char *an, int64_t size)
@@ -511,11 +510,11 @@ Span::init(char *an, int64_t size)
     return "unable to open";
   }
 
-  struct statfs fs;
-  if ((ret = fstatfs(fd, &fs)) < 0) {
-    Warning("unable to statfs '%s': %d %d, %s", n, ret, errno, strerror(errno));
+  struct statvfs fs;
+  if ((ret = fstatvfs(fd, &fs)) < 0) {
+    Warning("unable to statvfs '%s': %d %d, %s", n, ret, errno, strerror(errno));
     socketManager.close(fd);
-    return "unable to statfs";
+    return "unable to statvfs";
   }
 
   hw_sector_size = fs.f_bsize;
@@ -581,17 +580,10 @@ Lfail:
   socketManager.close(fd);
   return err;
 }
+
 #endif
 
 #if defined(solaris)
-// TODO: Those are probably already included from the ink_platform.h
-#include <ctype.h>
-#include <sys/types.h>
-#include <sys/param.h>
-#include <sys/mount.h>
-#include <sys/stat.h>
-#include <sys/statvfs.h>
-#include <string.h>
 
 const char *
 Span::init(char *filename, int64_t size)
@@ -679,10 +671,6 @@ Lfail:
 #endif
 
 #if defined(linux)
-// TODO: Axe extra includes
-#include <stdlib.h>
-#include <stdio.h>
-#include <fcntl.h>
 #include <unistd.h>             /* for close() */
 #include <sys/ioctl.h>
 #include <linux/hdreg.h>        /* for struct hd_geometry */

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/f760dac4/lib/ts/ink_file.h
----------------------------------------------------------------------
diff --git a/lib/ts/ink_file.h b/lib/ts/ink_file.h
index 5aa08bf..a22e33d 100644
--- a/lib/ts/ink_file.h
+++ b/lib/ts/ink_file.h
@@ -32,8 +32,24 @@
 #ifndef _ink_file_h_
 #define	_ink_file_h_
 
+#include "ink_config.h"
+
 #include <stdio.h>
 #include <sys/types.h>
+#include <dirent.h>
+
+#if HAVE_SYS_STATFS_H
+#include <sys/statfs.h>
+#endif
+
+#if HAVE_SYS_STATVFS_H
+#include <sys/statvfs.h>
+#endif
+
+// Darwin keeps statafs(2) in <sys/mount.h> ...
+#if HAVE_SYS_MOUNT_H
+#include <sys/mount.h>
+#endif
 
 /*===========================================================================*
 
@@ -41,8 +57,6 @@
 
  *===========================================================================*/
 
-#include <dirent.h>
-
 // Cause ink_filepath_merge to fail if addpath is above rootpath
 //
 #define INK_FILEPATH_NOTABOVEROOT   0x01

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/f760dac4/proxy/logging/LogConfig.cc
----------------------------------------------------------------------
diff --git a/proxy/logging/LogConfig.cc b/proxy/logging/LogConfig.cc
index 40e0069..aa874d5 100644
--- a/proxy/logging/LogConfig.cc
+++ b/proxy/logging/LogConfig.cc
@@ -27,22 +27,9 @@
 #ifdef HAVE_SYS_PARAM_H
 #include <sys/param.h>
 #endif
-#ifdef HAVE_SYS_MOUNT_H
-#include <sys/mount.h>
-#endif
-
-#include <dirent.h>
-
-#if defined(linux)
-#include <sys/statfs.h>
-#elif defined(solaris)
-#include <sys/statfs.h>
-#include <sys/statvfs.h>
-#elif !defined(freebsd)
-#include <sys/statvfs.h>
-#endif  // linux
 
 #include "ink_platform.h"
+#include "ink_file.h"
 
 #include "Main.h"
 #include "List.h"
@@ -65,15 +52,6 @@
 #include "LogCollationAccept.h"
 #endif
 
-#if defined(linux)
-#include <sys/vfs.h>
-#else
-extern "C"
-{
-  int statvfs(const char *, struct statvfs *);
-}
-#endif
-
 #define DISK_IS_CONFIG_FULL_MESSAGE \
     "Access logging to local log directory suspended - " \
     "configured space allocation exhausted."
@@ -1550,16 +1528,10 @@ LogConfig::update_space_used()
   // Now check the partition to see if there is enough *actual* space.
   //
   partition_space_left = m_partition_space_left;
-#if defined(solaris)
+
   struct statvfs fs;
-  ::memset(&fs, 0, sizeof(fs));
-  int ret =::statvfs(logfile_dir, &fs);
-#else
-  struct statfs fs;
-  ::memset(&fs, 0, sizeof(fs));
-  int ret =::statfs(logfile_dir, &fs);
-#endif
-  if (ret >= 0) {
+
+  if (::statvfs(logfile_dir, &fs) >= 0) {
     partition_space_left = (int64_t) fs.f_bavail * (int64_t) fs.f_bsize;
   }
 


[30/50] [abbrv] git commit: TS-2280 Fix OS X build on atscppapi (missed two)

Posted by zw...@apache.org.
TS-2280 Fix OS X build on atscppapi (missed two)


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

Branch: refs/heads/5.0.x
Commit: 6c5955a9eabce806ec9dba30a67dbb557c3edbad
Parents: 739a9c4
Author: Brian Geffon <br...@apache.org>
Authored: Mon Oct 21 18:27:05 2013 -0700
Committer: Brian Geffon <br...@apache.org>
Committed: Mon Oct 21 18:27:05 2013 -0700

----------------------------------------------------------------------
 lib/atscppapi/src/include/atscppapi/Transaction.h       | 2 +-
 lib/atscppapi/src/include/atscppapi/TransactionPlugin.h | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/trafficserver/blob/6c5955a9/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
index 3610d1b..13def37 100644
--- a/lib/atscppapi/src/include/atscppapi/Transaction.h
+++ b/lib/atscppapi/src/include/atscppapi/Transaction.h
@@ -35,7 +35,7 @@ namespace atscppapi {
 
 // forward declarations
 class TransactionPlugin;
-class TransactionState;
+struct TransactionState;
 namespace utils { class internal; }
 
 /**

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/6c5955a9/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
index d473827..3987927 100644
--- a/lib/atscppapi/src/include/atscppapi/TransactionPlugin.h
+++ b/lib/atscppapi/src/include/atscppapi/TransactionPlugin.h
@@ -38,7 +38,7 @@ namespace utils {
 /**
  * @private
  */
-class TransactionPluginState;
+struct TransactionPluginState;
 
 /**
  * @brief The interface used when creating a TransactionPlugin.


[34/50] [abbrv] git commit: TS-2291: Disable remap_stats plugin compile on platforms that do not have a reentrant hsearch implementation

Posted by zw...@apache.org.
TS-2291: Disable remap_stats plugin compile on platforms that do
not have a reentrant hsearch implementation

This means this plugin will not build on FreeBSD or OmniOS.


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

Branch: refs/heads/5.0.x
Commit: a2809d1874ea69a78e44e2fdf916217db1d37100
Parents: e265ff8
Author: Phil Sorber <so...@apache.org>
Authored: Tue Oct 22 19:30:06 2013 -0600
Committer: Phil Sorber <so...@apache.org>
Committed: Tue Oct 22 19:31:58 2013 -0600

----------------------------------------------------------------------
 configure.ac                                 | 8 ++++++++
 plugins/experimental/remap_stats/Makefile.am | 4 ++++
 2 files changed, 12 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/trafficserver/blob/a2809d18/configure.ac
----------------------------------------------------------------------
diff --git a/configure.ac b/configure.ac
index 439a6e1..bb23933 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1786,6 +1786,14 @@ AC_CHECK_TYPE([struct tcp_info],
 )
 AM_CONDITIONAL([BUILD_TCPINFO_PLUGIN], [ test "x${enable_tcpinfo_plugin}" != "xno" ])
 
+AC_SEARCH_LIBS([hcreate_r],
+  [],
+  [enable_remap_stats_plugin=yes],
+  [enable_remap_stats_plugin=no],
+  []
+)
+AM_CONDITIONAL([BUILD_REMAP_STATS_PLUGIN], [ test "x${enable_remap_stats_plugin}" != "xno" ])
+
 #
 # use modular IOCORE
 #

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/a2809d18/plugins/experimental/remap_stats/Makefile.am
----------------------------------------------------------------------
diff --git a/plugins/experimental/remap_stats/Makefile.am b/plugins/experimental/remap_stats/Makefile.am
index 4033fa4..a817bb8 100644
--- a/plugins/experimental/remap_stats/Makefile.am
+++ b/plugins/experimental/remap_stats/Makefile.am
@@ -16,6 +16,10 @@
 
 include $(top_srcdir)/build/plugins.mk
 
+if BUILD_REMAP_STATS_PLUGIN
+
 pkglib_LTLIBRARIES = remap_stats.la
 remap_stats_la_SOURCES = remap_stats.c
 remap_stats_la_LDFLAGS = $(TS_PLUGIN_LDFLAGS)
+
+endif


[07/50] [abbrv] git commit: Quiet a benign compiler warning on OSX

Posted by zw...@apache.org.
Quiet a benign compiler warning on OSX


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

Branch: refs/heads/5.0.x
Commit: 0d886aabb968a312dc9f96194858aefceee69a72
Parents: 0542b2a
Author: Leif Hedstrom <zw...@apache.org>
Authored: Tue Oct 15 11:48:58 2013 -0600
Committer: Leif Hedstrom <zw...@apache.org>
Committed: Wed Oct 16 22:38:40 2013 -0700

----------------------------------------------------------------------
 plugins/experimental/buffer_upload/buffer_upload.cc | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/trafficserver/blob/0d886aab/plugins/experimental/buffer_upload/buffer_upload.cc
----------------------------------------------------------------------
diff --git a/plugins/experimental/buffer_upload/buffer_upload.cc b/plugins/experimental/buffer_upload/buffer_upload.cc
index fc496e4..3101de8 100644
--- a/plugins/experimental/buffer_upload/buffer_upload.cc
+++ b/plugins/experimental/buffer_upload/buffer_upload.cc
@@ -59,8 +59,8 @@
     return TS_ERROR;				\
   }
 
-#define VALID_PTR(X) (X != NULL)
-#define NOT_VALID_PTR(X) (X == NULL)
+#define VALID_PTR(X) (NULL != X)
+#define NOT_VALID_PTR(X) (NULL == X)
 
 struct upload_config_t
 {


[40/50] [abbrv] git commit: TS-2226 Add support for a set-header operator.

Posted by zw...@apache.org.
TS-2226 Add support for a set-header operator.

This is an optimization over the old pattern of doing

     rm-header Foo
     add-header Foo "bar"

This also reorganizes the code a bit, to avoid so much
duplication.


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

Branch: refs/heads/5.0.x
Commit: 4bf36c8fdfcb36a037289909c073a451b78aeeea
Parents: 22e33c5
Author: Leif Hedstrom <zw...@apache.org>
Authored: Sat Oct 19 16:00:01 2013 -0600
Committer: Leif Hedstrom <zw...@apache.org>
Committed: Wed Oct 23 15:16:38 2013 -0600

----------------------------------------------------------------------
 CHANGES                             |   2 +
 plugins/header_rewrite/factory.cc   |   2 +
 plugins/header_rewrite/operator.cc  |  13 ++
 plugins/header_rewrite/operator.h   |  24 ++++
 plugins/header_rewrite/operators.cc | 212 ++++++++++++++++++-------------
 plugins/header_rewrite/operators.h  |  96 ++++++++------
 6 files changed, 222 insertions(+), 127 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/trafficserver/blob/4bf36c8f/CHANGES
----------------------------------------------------------------------
diff --git a/CHANGES b/CHANGES
index 84b8e1b..c538af5 100644
--- a/CHANGES
+++ b/CHANGES
@@ -2,6 +2,8 @@
 Changes with Apache Traffic Server 4.1.0
 
 
+  *) [TS-2226] Add a set-header operator for header_rewrite plugin.
+
   *) [TS-2296] improve ConfigProcessor reference counting
 
   *) [ TS-2295] update statvfs usage

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/4bf36c8f/plugins/header_rewrite/factory.cc
----------------------------------------------------------------------
diff --git a/plugins/header_rewrite/factory.cc b/plugins/header_rewrite/factory.cc
index d20fa40..6c2cd9a 100644
--- a/plugins/header_rewrite/factory.cc
+++ b/plugins/header_rewrite/factory.cc
@@ -35,6 +35,8 @@ operator_factory(const std::string& op)
 
   if (op == "rm-header") {
     o = new OperatorRMHeader();
+  } else if (op == "set-header") {
+    o = new OperatorSetHeader();
   } else if (op == "add-header") {
     o = new OperatorAddHeader();
   } else if (op == "set-status") {

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/4bf36c8f/plugins/header_rewrite/operator.cc
----------------------------------------------------------------------
diff --git a/plugins/header_rewrite/operator.cc b/plugins/header_rewrite/operator.cc
index a5dffdd..77adbfd 100644
--- a/plugins/header_rewrite/operator.cc
+++ b/plugins/header_rewrite/operator.cc
@@ -15,6 +15,7 @@
   See the License for the specific language governing permissions and
   limitations under the License.
 */
+
 //////////////////////////////////////////////////////////////////////////////////////////////
 // operator.cc: Implementation of the operator base class
 //
@@ -43,3 +44,15 @@ Operator::initialize(Parser& p) {
   }
 
 }
+
+void
+OperatorHeaders::initialize(Parser& p) {
+  Operator::initialize(p);
+
+  _header = p.get_arg();
+
+  require_resources(RSRC_SERVER_RESPONSE_HEADERS);
+  require_resources(RSRC_SERVER_REQUEST_HEADERS);
+  require_resources(RSRC_CLIENT_REQUEST_HEADERS);
+  require_resources(RSRC_CLIENT_RESPONSE_HEADERS);
+}

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/4bf36c8f/plugins/header_rewrite/operator.h
----------------------------------------------------------------------
diff --git a/plugins/header_rewrite/operator.h b/plugins/header_rewrite/operator.h
index f136290..6ef2e73 100644
--- a/plugins/header_rewrite/operator.h
+++ b/plugins/header_rewrite/operator.h
@@ -70,4 +70,28 @@ private:
   OperModifiers _mods;
 };
 
+
+///////////////////////////////////////////////////////////////////////////////
+// Base class for all Header based Operators, this is obviously also an
+// Operator interface.
+//
+class OperatorHeaders : public Operator
+{
+public:
+  OperatorHeaders()
+    : _header("")
+  {
+    TSDebug(PLUGIN_NAME_DBG, "Calling CTOR for OperatorHeaders");
+  }
+
+  void initialize(Parser& p);
+
+protected:
+  std::string _header;
+
+private:
+  DISALLOW_COPY_AND_ASSIGN(OperatorHeaders);
+};
+
+
 #endif // __OPERATOR_H

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/4bf36c8f/plugins/header_rewrite/operators.cc
----------------------------------------------------------------------
diff --git a/plugins/header_rewrite/operators.cc b/plugins/header_rewrite/operators.cc
index 3775166..54c00d8 100644
--- a/plugins/header_rewrite/operators.cc
+++ b/plugins/header_rewrite/operators.cc
@@ -25,42 +25,10 @@
 
 #include "operators.h"
 
-// OperatorRMHeader
-void
-OperatorRMHeader::initialize(Parser& p) {
-  Operator::initialize(p);
-
-  _header = p.get_arg();
-
-  require_resources(RSRC_SERVER_RESPONSE_HEADERS);
-  require_resources(RSRC_SERVER_REQUEST_HEADERS);
-  require_resources(RSRC_CLIENT_REQUEST_HEADERS);
-  require_resources(RSRC_CLIENT_RESPONSE_HEADERS);
-}
-
-
-void
-OperatorRMHeader::exec(const Resources& res) const
-{
-  TSMLoc field_loc, tmp;
-
-  if (res.bufp && res.hdr_loc) {
-    TSDebug(PLUGIN_NAME, "OperatorRMHeader::exec() invoked on header %s", _header.c_str());
-    field_loc = TSMimeHdrFieldFind(res.bufp, res.hdr_loc, _header.c_str(), _header.size());
-    while (field_loc) {
-      TSDebug(PLUGIN_NAME, "\tdeleting header %s", _header.c_str());
-      tmp = TSMimeHdrFieldNextDup(res.bufp, res.hdr_loc, field_loc);
-      TSMimeHdrFieldDestroy(res.bufp, res.hdr_loc, field_loc);
-      TSHandleMLocRelease(res.bufp, res.hdr_loc, field_loc);
-      field_loc = tmp;
-    }
-  }
-}
-
-
 // OperatorSetStatus
 void
-OperatorSetStatus::initialize(Parser& p) {
+OperatorSetStatus::initialize(Parser& p)
+{
   Operator::initialize(p);
 
   _status.set_value(p.get_arg());
@@ -79,7 +47,8 @@ OperatorSetStatus::initialize(Parser& p) {
 
 
 void
-OperatorSetStatus::initialize_hooks() {
+OperatorSetStatus::initialize_hooks()
+{
   add_allowed_hook(TS_HTTP_READ_RESPONSE_HDR_HOOK);
   add_allowed_hook(TS_HTTP_SEND_RESPONSE_HDR_HOOK);
 }
@@ -98,7 +67,8 @@ OperatorSetStatus::exec(const Resources& res) const
 
 // OperatorSetStatusReason
 void
-OperatorSetStatusReason::initialize(Parser& p) {
+OperatorSetStatusReason::initialize(Parser& p)
+{
   Operator::initialize(p);
 
   _reason.set_value(p.get_arg());
@@ -127,57 +97,11 @@ OperatorSetStatusReason::exec(const Resources& res) const {
 }
 
 
-// OperatorAddHeader
-void
-OperatorAddHeader::initialize(Parser& p) {
-  Operator::initialize(p);
-
-  _header = p.get_arg();
-  _value.set_value(p.get_value());
-  
-  require_resources(RSRC_SERVER_RESPONSE_HEADERS);
-  require_resources(RSRC_SERVER_REQUEST_HEADERS);
-  require_resources(RSRC_CLIENT_REQUEST_HEADERS);
-  require_resources(RSRC_CLIENT_RESPONSE_HEADERS);
-}
-
-
-void
-OperatorAddHeader::exec(const Resources& res) const
-{
-//  int IP = TSHttpTxnServerIPGet(res.txnp);
-//  inet_ntop(AF_INET, &IP, buf, sizeof(buf));
-  std::string value;
-
-  _value.append_value(value, res);
-
-  // Never set an empty header (I don't think that ever makes sense?)
-  if (value.empty()) {
-    TSDebug(PLUGIN_NAME, "Would set header %s to an empty value, skipping", _header.c_str());
-    return;
-  }
-  
-  if (res.bufp && res.hdr_loc) {
-    TSDebug(PLUGIN_NAME, "OperatorAddHeader::exec() invoked on header %s: %s", _header.c_str(), value.c_str());
-    TSMLoc field_loc;
-    
-    if (TS_SUCCESS == TSMimeHdrFieldCreateNamed(res.bufp, res.hdr_loc, _header.c_str(), _header.size(), &field_loc)) {
-      if (TS_SUCCESS == TSMimeHdrFieldValueStringInsert(res.bufp, res.hdr_loc, field_loc, -1, value.c_str(), value.size())) {
-        TSDebug(PLUGIN_NAME, "   adding header %s", _header.c_str());
-        //INKHttpHdrPrint(res.bufp, res.hdr_loc, reqBuff);
-        TSMimeHdrFieldAppend(res.bufp, res.hdr_loc, field_loc);
-      }
-      TSHandleMLocRelease(res.bufp, res.hdr_loc, field_loc);
-    }
-      
-  }
-}
-
-
 /// TODO and XXX: These currently only support when running as remap plugin.
 // OperatorSetDestination
 void
-OperatorSetDestination::initialize(Parser& p) {
+OperatorSetDestination::initialize(Parser& p)
+{
   Operator::initialize(p);
 
   _url_qual = parse_url_qualifier(p.get_arg());
@@ -262,7 +186,8 @@ OperatorSetDestination::exec(const Resources& res) const
 /// TODO and XXX: These currently only support when running as remap plugin.
 // OperatorSetRedirect
 void
-OperatorSetRedirect::initialize(Parser& p) {
+OperatorSetRedirect::initialize(Parser& p)
+{
   Operator::initialize(p);
 
   _status.set_value(p.get_arg());
@@ -328,7 +253,8 @@ OperatorSetRedirect::exec(const Resources& res) const
 
 // OperatorSetTimeoutOut
 void
-OperatorSetTimeoutOut::initialize(Parser& p) {
+OperatorSetTimeoutOut::initialize(Parser& p)
+{
   Operator::initialize(p);
 
   if (p.get_arg() == "active") {
@@ -377,3 +303,117 @@ OperatorSetTimeoutOut::exec(const Resources& res) const
   }
 }
 
+
+// OperatorRMHeader
+void
+OperatorRMHeader::exec(const Resources& res) const
+{
+  TSMLoc field_loc, tmp;
+
+  if (res.bufp && res.hdr_loc) {
+    TSDebug(PLUGIN_NAME, "OperatorRMHeader::exec() invoked on header %s", _header.c_str());
+    field_loc = TSMimeHdrFieldFind(res.bufp, res.hdr_loc, _header.c_str(), _header.size());
+    while (field_loc) {
+      TSDebug(PLUGIN_NAME, "\tdeleting header %s", _header.c_str());
+      tmp = TSMimeHdrFieldNextDup(res.bufp, res.hdr_loc, field_loc);
+      TSMimeHdrFieldDestroy(res.bufp, res.hdr_loc, field_loc);
+      TSHandleMLocRelease(res.bufp, res.hdr_loc, field_loc);
+      field_loc = tmp;
+    }
+  }
+}
+
+
+// OperatorAddHeader
+void
+OperatorAddHeader::initialize(Parser& p)
+{
+  OperatorHeaders::initialize(p);
+
+  _value.set_value(p.get_value());
+}
+
+void
+OperatorAddHeader::exec(const Resources& res) const
+{
+  std::string value;
+
+  _value.append_value(value, res);
+
+  // Never set an empty header (I don't think that ever makes sense?)
+  if (value.empty()) {
+    TSDebug(PLUGIN_NAME, "Would set header %s to an empty value, skipping", _header.c_str());
+    return;
+  }
+
+  if (res.bufp && res.hdr_loc) {
+    TSDebug(PLUGIN_NAME, "OperatorAddHeader::exec() invoked on header %s: %s", _header.c_str(), value.c_str());
+    TSMLoc field_loc;
+
+    if (TS_SUCCESS == TSMimeHdrFieldCreateNamed(res.bufp, res.hdr_loc, _header.c_str(), _header.size(), &field_loc)) {
+      if (TS_SUCCESS == TSMimeHdrFieldValueStringSet(res.bufp, res.hdr_loc, field_loc, -1, value.c_str(), value.size())) {
+        TSDebug(PLUGIN_NAME, "   adding header %s", _header.c_str());
+        TSMimeHdrFieldAppend(res.bufp, res.hdr_loc, field_loc);
+      }
+      TSHandleMLocRelease(res.bufp, res.hdr_loc, field_loc);
+    }
+  }
+}
+
+
+// OperatorSetHeader
+void
+OperatorSetHeader::initialize(Parser& p)
+{
+  OperatorHeaders::initialize(p);
+
+  _value.set_value(p.get_value());
+}
+
+void
+OperatorSetHeader::exec(const Resources& res) const
+{
+  std::string value;
+
+  _value.append_value(value, res);
+
+  // Never set an empty header (I don't think that ever makes sense?)
+  if (value.empty()) {
+    TSDebug(PLUGIN_NAME, "Would set header %s to an empty value, skipping", _header.c_str());
+    return;
+  }
+
+  if (res.bufp && res.hdr_loc) {
+    TSMLoc field_loc = TSMimeHdrFieldFind(res.bufp, res.hdr_loc, _header.c_str(), _header.size());
+
+    TSDebug(PLUGIN_NAME, "OperatorSetHeader::exec() invoked on header %s: %s", _header.c_str(), value.c_str());
+
+    if (!field_loc) {
+      // No existing header, so create one
+      if (TS_SUCCESS == TSMimeHdrFieldCreateNamed(res.bufp, res.hdr_loc, _header.c_str(), _header.size(), &field_loc)) {
+        if (TS_SUCCESS == TSMimeHdrFieldValueStringSet(res.bufp, res.hdr_loc, field_loc, -1, value.c_str(), value.size())) {
+          TSDebug(PLUGIN_NAME, "   adding header %s", _header.c_str());
+          TSMimeHdrFieldAppend(res.bufp, res.hdr_loc, field_loc);
+        }
+        TSHandleMLocRelease(res.bufp, res.hdr_loc, field_loc);
+      }
+    } else {
+      TSMLoc tmp = NULL;
+      bool first = true;
+
+      while (field_loc) {
+        if (first) {
+          first = false;
+          if (TS_SUCCESS == TSMimeHdrFieldValueStringSet(res.bufp, res.hdr_loc, field_loc, -1, value.c_str(), value.size())) {
+            TSDebug(PLUGIN_NAME, "   overwriting header %s", _header.c_str());
+          }
+        } else {
+          TSMimeHdrFieldDestroy(res.bufp, res.hdr_loc, field_loc);
+        }
+        tmp = TSMimeHdrFieldNextDup(res.bufp, res.hdr_loc, field_loc);
+        TSHandleMLocRelease(res.bufp, res.hdr_loc, field_loc);
+        field_loc = tmp;
+      }
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/4bf36c8f/plugins/header_rewrite/operators.h
----------------------------------------------------------------------
diff --git a/plugins/header_rewrite/operators.h b/plugins/header_rewrite/operators.h
index f43858f..a424f23 100644
--- a/plugins/header_rewrite/operators.h
+++ b/plugins/header_rewrite/operators.h
@@ -33,26 +33,6 @@
 ///////////////////////////////////////////////////////////////////////////////
 // Operator declarations.
 //
-class OperatorRMHeader : public Operator
-{
-public:
-  OperatorRMHeader()
-    : _header("")
-  {
-    TSDebug(PLUGIN_NAME_DBG, "Calling CTOR for OperatorRMHeader");
-  }
-  void initialize(Parser& p);
-
-protected:
-  void exec(const Resources& res) const;
-
-private:
-  DISALLOW_COPY_AND_ASSIGN(OperatorRMHeader);
-
-  std::string _header;
-};
-
-
 class OperatorSetStatus : public Operator
 {
 public:
@@ -96,27 +76,6 @@ private:
 };
 
 
-class OperatorAddHeader : public Operator
-{
-public:
-  OperatorAddHeader()
-    : _header("")
-  {
-    TSDebug(PLUGIN_NAME_DBG, "Calling CTOR for OperatorAddHeader");
-  }
-  void initialize(Parser& p);
-
-protected:
-  void exec(const Resources& res) const;
-
-private:
-  DISALLOW_COPY_AND_ASSIGN(OperatorAddHeader);
-
-  std::string _header;
-  Value _value;
-};
-
-
 class OperatorSetDestination : public Operator
 {
 public:
@@ -203,4 +162,59 @@ private:
 };
 
 
+// All the header operators share a base class
+class OperatorRMHeader : public OperatorHeaders
+{
+public:
+  OperatorRMHeader()
+  {
+    TSDebug(PLUGIN_NAME_DBG, "Calling CTOR for OperatorRMHeader");
+  }
+
+protected:
+  void exec(const Resources& res) const;
+
+private:
+  DISALLOW_COPY_AND_ASSIGN(OperatorRMHeader);
+};
+
+
+class OperatorAddHeader : public OperatorHeaders
+{
+public:
+  OperatorAddHeader()
+  {
+    TSDebug(PLUGIN_NAME_DBG, "Calling CTOR for OperatorAddHeader");
+  }
+  void initialize(Parser& p);
+
+protected:
+  void exec(const Resources& res) const;
+
+private:
+  DISALLOW_COPY_AND_ASSIGN(OperatorAddHeader);
+
+  Value _value;
+};
+
+
+class OperatorSetHeader : public OperatorHeaders
+{
+public:
+  OperatorSetHeader()
+  {
+    TSDebug(PLUGIN_NAME_DBG, "Calling CTOR for OperatorSetHeader");
+  }
+  void initialize(Parser& p);
+
+protected:
+  void exec(const Resources& res) const;
+
+private:
+  DISALLOW_COPY_AND_ASSIGN(OperatorSetHeader);
+
+  Value _value;
+};
+
+
 #endif // __OPERATORS_H


[14/50] [abbrv] initial atscppapi commit

Posted by zw...@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_ */


[35/50] [abbrv] git commit: TS-2139 fix the bug of purge twice to remove the doc if enable-interim-cache

Posted by zw...@apache.org.
TS-2139 fix the bug of purge twice to remove the doc if enable-interim-cache


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

Branch: refs/heads/5.0.x
Commit: a3d1208777c7a232250df65d4409aae1aa58afca
Parents: a2809d1
Author: weijin <ta...@taobao.com>
Authored: Wed Oct 23 11:00:30 2013 +0800
Committer: weijin <ta...@taobao.com>
Committed: Wed Oct 23 11:06:31 2013 +0800

----------------------------------------------------------------------
 CHANGES               | 2 ++
 iocore/cache/Cache.cc | 7 +++++++
 2 files changed, 9 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/trafficserver/blob/a3d12087/CHANGES
----------------------------------------------------------------------
diff --git a/CHANGES b/CHANGES
index a626df1..77a834f 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,8 @@
                                                          -*- coding: utf-8 -*-
 Changes with Apache Traffic Server 4.1.0
 
+  *) [TS-2139] Fix PURGE twice to remove object in cache if enable-interim-cache
+
   *) [TS-2216] Fix cquuh log tag, which does not calculate the right
    string length.
 

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/a3d12087/iocore/cache/Cache.cc
----------------------------------------------------------------------
diff --git a/iocore/cache/Cache.cc b/iocore/cache/Cache.cc
index 9256ea5..e417ab8 100644
--- a/iocore/cache/Cache.cc
+++ b/iocore/cache/Cache.cc
@@ -2720,6 +2720,13 @@ CacheVC::removeEvent(int /* event ATS_UNUSED */, Event * /* e ATS_UNUSED */)
   Lcollision:
     // check for collision
     if (dir_probe(&key, vol, &dir, &last_collision) > 0) {
+#if TS_USE_INTERIM_CACHE == 1
+      if (dir_ininterim(&dir)) {
+        dir_delete(&key, vol, &dir);
+        last_collision = NULL;
+        goto Lcollision;
+      }
+#endif
       int ret = do_read_call(&key);
       if (ret == EVENT_RETURN)
         goto Lread;


[21/50] [abbrv] git commit: Fixed typo

Posted by zw...@apache.org.
Fixed typo


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

Branch: refs/heads/5.0.x
Commit: 40deb91b089d93eca0ebf0b4ac22838c22652f23
Parents: c351856
Author: Phil Sorber <so...@apache.org>
Authored: Sun Oct 20 13:23:53 2013 -0600
Committer: Phil Sorber <so...@apache.org>
Committed: Sun Oct 20 13:23:53 2013 -0600

----------------------------------------------------------------------
 CHANGES | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/trafficserver/blob/40deb91b/CHANGES
----------------------------------------------------------------------
diff --git a/CHANGES b/CHANGES
index 30c1354..e0c3452 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,7 +1,7 @@
                                                          -*- coding: utf-8 -*-
 Changes with Apache Traffic Server 4.1.0
 
-  *) [TS-2291] Add remap_state plugin to experimental.
+  *) [TS-2291] Add remap_stats plugin to experimental.
 
   *) [TS-2242] Update core plugins' support_email and vendor_name for
    consistency.


[04/50] [abbrv] git commit: TS-2138 fix the bug that restarting ATS cause cache data loss if enable native-AIO.

Posted by zw...@apache.org.
TS-2138 fix the bug that restarting ATS cause cache data loss if enable
native-AIO.


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

Branch: refs/heads/5.0.x
Commit: 64b01e091a94a050fd24aa3591da56ed3a7ad7f6
Parents: 458a1a7
Author: weijin <ta...@taobao.com>
Authored: Wed Oct 16 18:26:26 2013 +0800
Committer: weijin <ta...@taobao.com>
Committed: Wed Oct 16 18:30:52 2013 +0800

----------------------------------------------------------------------
 CHANGES               | 3 +++
 iocore/cache/Cache.cc | 3 ++-
 2 files changed, 5 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/trafficserver/blob/64b01e09/CHANGES
----------------------------------------------------------------------
diff --git a/CHANGES b/CHANGES
index 7376d7e..f892b2e 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,9 @@
                                                          -*- coding: utf-8 -*-
 Changes with Apache Traffic Server 4.1.0
 
+  *) [TS-2138] Fix the bug that restarting ats cause cache data loss if
+  enable the native-aio.
+
   *) [TS-2197] Use HttpSM::main_handler to handle the client request stuff.
 
   *) [TS-2254] On ARM arch, ink_atomic_increment returns wrong value.

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/64b01e09/iocore/cache/Cache.cc
----------------------------------------------------------------------
diff --git a/iocore/cache/Cache.cc b/iocore/cache/Cache.cc
index 66f2b70..ffd69b7 100644
--- a/iocore/cache/Cache.cc
+++ b/iocore/cache/Cache.cc
@@ -197,13 +197,14 @@ struct DiskInit : public Continuation
 
   int mainEvent(int /* event ATS_UNUSED */, Event * /* e ATS_UNUSED */) {
     disk->open(s, blocks, askip, ahw_sector_size, fildes, clear);
+    ats_free(s);
     mutex.clear();
     delete this;
     return EVENT_DONE;
   }
 
   DiskInit(CacheDisk *d, char *str, off_t b, off_t skip, int sector, int f, bool c) : Continuation(d->mutex),
-      disk(d), s(str), blocks(b), askip(skip), ahw_sector_size(sector), fildes(f), clear(c) {
+      disk(d), s(ats_strdup(str)), blocks(b), askip(skip), ahw_sector_size(sector), fildes(f), clear(c) {
     SET_HANDLER(&DiskInit::mainEvent);
   }
 };


[10/50] [abbrv] git commit: TS-1988 cquuc and cquup can have no values

Posted by zw...@apache.org.
TS-1988 cquuc and cquup can have no values

When there is no remap phase, the unmapped URL does not get
populated. This means that cquuc and cquup can have no value,
so a "-" is logged. This happens, for example, with server
intercept plugins that do not pass through a remap phase.

This patch falls back on the original client URL in these
situations.


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

Branch: refs/heads/5.0.x
Commit: 25598f2e8e8bef8e60ab42e65143fc553f53c1f8
Parents: 275e254
Author: Leif Hedstrom <zw...@apache.org>
Authored: Thu Oct 10 15:49:40 2013 -0600
Committer: Leif Hedstrom <zw...@apache.org>
Committed: Thu Oct 17 11:38:00 2013 -0600

----------------------------------------------------------------------
 proxy/logging/LogAccessHttp.cc | 41 ++++++++++++++++++++++---------------
 1 file changed, 25 insertions(+), 16 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/trafficserver/blob/25598f2e/proxy/logging/LogAccessHttp.cc
----------------------------------------------------------------------
diff --git a/proxy/logging/LogAccessHttp.cc b/proxy/logging/LogAccessHttp.cc
index 7e72399..b2bfb58 100644
--- a/proxy/logging/LogAccessHttp.cc
+++ b/proxy/logging/LogAccessHttp.cc
@@ -313,13 +313,19 @@ LogAccessHttp::marshal_client_req_url_canon(char *buf)
 int
 LogAccessHttp::marshal_client_req_unmapped_url_canon(char *buf)
 {
-
-  validate_unmapped_url();
-
-  int len = round_strlen(m_client_req_unmapped_url_canon_len + 1);      // +1 for eos
+  int len = INK_MIN_ALIGN;
 
   if (buf) {
-    marshal_mem(buf, m_client_req_unmapped_url_canon_str, m_client_req_unmapped_url_canon_len, len);
+    validate_unmapped_url();
+    if (0 == m_client_req_unmapped_url_canon_len) {
+      // If the unmapped URL isn't populated, we'll fall back to the original
+      // client URL. This helps for example server intercepts to continue to
+      // log the requests, even when there is no remap rule for it.
+      len = marshal_client_req_url_canon(buf);
+    } else {
+      len = round_strlen(m_client_req_unmapped_url_canon_len + 1);      // +1 for eos
+      marshal_mem(buf, m_client_req_unmapped_url_canon_str, m_client_req_unmapped_url_canon_len, len);
+    }
   }
   return len;
 }
@@ -330,15 +336,17 @@ LogAccessHttp::marshal_client_req_unmapped_url_canon(char *buf)
 int
 LogAccessHttp::marshal_client_req_unmapped_url_path(char *buf)
 {
-  int len;
-
-  validate_unmapped_url();
-
-  validate_unmapped_url_path();
+  int len = INK_MIN_ALIGN;
 
-  len = round_strlen(m_client_req_unmapped_url_path_len + 1);   // +1 for eos
   if (buf) {
-    marshal_mem(buf, m_client_req_unmapped_url_path_str, m_client_req_unmapped_url_path_len, len);
+    validate_unmapped_url();
+    validate_unmapped_url_path();
+    if (0 == m_client_req_unmapped_url_path_len) {
+      len = marshal_client_req_url_path(buf);
+    } else {
+      len = round_strlen(m_client_req_unmapped_url_path_len + 1);   // +1 for eos
+      marshal_mem(buf, m_client_req_unmapped_url_path_str, m_client_req_unmapped_url_path_len, len);
+    }
   }
   return len;
 }
@@ -349,12 +357,13 @@ LogAccessHttp::marshal_client_req_unmapped_url_path(char *buf)
 int
 LogAccessHttp::marshal_client_req_unmapped_url_host(char *buf)
 {
-  validate_unmapped_url();
-  validate_unmapped_url_path();
-
-  int len = round_strlen(m_client_req_unmapped_url_host_len + 1);      // +1 for eos
+  int len = INK_MIN_ALIGN;
 
   if (buf) {
+    validate_unmapped_url();
+    validate_unmapped_url_path();
+
+    len = round_strlen(m_client_req_unmapped_url_host_len + 1);      // +1 for eos
     marshal_mem(buf, m_client_req_unmapped_url_host_str, m_client_req_unmapped_url_host_len, len);
   }
   return len;


[17/50] [abbrv] git commit: initial atscppapi commit

Posted by zw...@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/5.0.x
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)


[45/50] [abbrv] git commit: Fix missing headers for OS X build

Posted by zw...@apache.org.
Fix missing headers for OS X build


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

Branch: refs/heads/5.0.x
Commit: b30aef3175e9e6b313568a00fe57c77cbf41328b
Parents: 0c29d73
Author: James Peach <jp...@apache.org>
Authored: Fri Oct 25 14:21:32 2013 -0700
Committer: James Peach <jp...@apache.org>
Committed: Fri Oct 25 14:21:32 2013 -0700

----------------------------------------------------------------------
 plugins/experimental/esi/combo_handler.cc               | 1 +
 plugins/experimental/esi/fetcher/HttpDataFetcherImpl.cc | 1 +
 2 files changed, 2 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/trafficserver/blob/b30aef31/plugins/experimental/esi/combo_handler.cc
----------------------------------------------------------------------
diff --git a/plugins/experimental/esi/combo_handler.cc b/plugins/experimental/esi/combo_handler.cc
index 47f0095..e14c04c 100644
--- a/plugins/experimental/esi/combo_handler.cc
+++ b/plugins/experimental/esi/combo_handler.cc
@@ -24,6 +24,7 @@
 #include <list>
 #include <string>
 #include <time.h>
+#include <pthread.h>
 #include <arpa/inet.h>
 
 #include "ts/ts.h"

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/b30aef31/plugins/experimental/esi/fetcher/HttpDataFetcherImpl.cc
----------------------------------------------------------------------
diff --git a/plugins/experimental/esi/fetcher/HttpDataFetcherImpl.cc b/plugins/experimental/esi/fetcher/HttpDataFetcherImpl.cc
index 427437d..fe1fae0 100644
--- a/plugins/experimental/esi/fetcher/HttpDataFetcherImpl.cc
+++ b/plugins/experimental/esi/fetcher/HttpDataFetcherImpl.cc
@@ -25,6 +25,7 @@
 #include "lib/Utils.h"
 #include "lib/gzip.h"
 
+#include <stdlib.h>
 #include <arpa/inet.h>
 
 using std::string;


[06/50] [abbrv] git commit: Add missing line feed on warning message.

Posted by zw...@apache.org.
Add missing line feed on warning message.


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

Branch: refs/heads/5.0.x
Commit: 0542b2abe6cddb802056942b2bfaa3ce1a703072
Parents: b942f3b
Author: Theo Schlossnagle <je...@omniti.com>
Authored: Wed Oct 16 16:10:44 2013 -0700
Committer: Theo Schlossnagle <je...@omniti.com>
Committed: Wed Oct 16 16:10:44 2013 -0700

----------------------------------------------------------------------
 proxy/Main.cc | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/trafficserver/blob/0542b2ab/proxy/Main.cc
----------------------------------------------------------------------
diff --git a/proxy/Main.cc b/proxy/Main.cc
index 3c063ad..2d34d5c 100644
--- a/proxy/Main.cc
+++ b/proxy/Main.cc
@@ -1224,7 +1224,7 @@ change_uid_gid(const char *user)
     // Not root so can't change user ID. Logging isn't operational yet so
     // we have to write directly to stderr. Perhaps this should be fatal?
     fprintf(stderr,
-          "Can't change user to '%s' because running with effective uid=%d",
+          "Can't change user to '%s' because running with effective uid=%d\n",
           user, geteuid());
   }
   else {


[08/50] [abbrv] git commit: small change to make eclipse happy

Posted by zw...@apache.org.
small change to make eclipse happy


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

Branch: refs/heads/5.0.x
Commit: a263d384d4f70ddc65d9c0ee21950ef2f4c79d0e
Parents: 0d886aa
Author: Zhao Yongming <mi...@gmail.com>
Authored: Thu Oct 17 17:52:58 2013 +0800
Committer: Zhao Yongming <mi...@gmail.com>
Committed: Thu Oct 17 17:52:58 2013 +0800

----------------------------------------------------------------------
 iocore/eventsystem/I_EventProcessor.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/trafficserver/blob/a263d384/iocore/eventsystem/I_EventProcessor.h
----------------------------------------------------------------------
diff --git a/iocore/eventsystem/I_EventProcessor.h b/iocore/eventsystem/I_EventProcessor.h
index 40d8e94..2820e9b 100644
--- a/iocore/eventsystem/I_EventProcessor.h
+++ b/iocore/eventsystem/I_EventProcessor.h
@@ -112,7 +112,7 @@ public:
     @return event object representing the start of the thread.
 
   */
-  Event *spawn_thread(Continuation * cont, const char *thr_name, size_t stacksize, ink_sem * sem = NULL);
+  Event *spawn_thread(Continuation * cont, const char *thr_name, size_t stacksize = 0, ink_sem * sem = NULL);
 
   /**
     Spawns a group of threads for an event type. Spawns the number of


[49/50] [abbrv] git commit: TS-2265 Remove 3 unused log tags.

Posted by zw...@apache.org.
TS-2265 Remove 3 unused log tags.

These have no meaning or purpose after we cleaned out all the
old streaming protocols etc. This avoids confusion where someone
might think that these 3 tags will do something.

    prob
    prcb
    cgid


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

Branch: refs/heads/5.0.x
Commit: 8d461ead973da66d92daa3c3300e3c19c40d9b7d
Parents: 3b17595
Author: Leif Hedstrom <zw...@apache.org>
Authored: Sun Oct 20 15:26:46 2013 -0600
Committer: Leif Hedstrom <zw...@apache.org>
Committed: Sun Oct 27 15:25:36 2013 -0600

----------------------------------------------------------------------
 doc/admin/event-logging-formats.en.rst | 13 +++----------
 proxy/logging/Log.cc                   | 21 ---------------------
 proxy/logging/LogAccess.cc             | 27 ---------------------------
 proxy/logging/LogAccess.h              |  3 ---
 4 files changed, 3 insertions(+), 61 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/trafficserver/blob/8d461ead/doc/admin/event-logging-formats.en.rst
----------------------------------------------------------------------
diff --git a/doc/admin/event-logging-formats.en.rst b/doc/admin/event-logging-formats.en.rst
index c4d1727..e7e3261 100644
--- a/doc/admin/event-logging-formats.en.rst
+++ b/doc/admin/event-logging-formats.en.rst
@@ -189,7 +189,7 @@ The following list describes Traffic Server custom logging fields.
     Server.
 
 ``cwr``
-    The cache write result (``-``, ``FIN``, ``ERR`` and so on)
+    The cache write result (``-``, ``WL_MISS``, ``INTR```, ``ERR`` or ``FIN``)
 
 ``cwtr``
     The cache write transform result
@@ -199,8 +199,8 @@ The following list describes Traffic Server custom logging fields.
 
 ``pfsc``
     The proxy finish status code; specifies whether the Traffic Server
-    request to the origin server was successfully completed (``FIN``) or
-    interrupted (``INTR``).
+    request to the origin server was successfully completed (``FIN``),
+    interrupted (``INTR``) or timed out (``TIMEOUT``).
 
 ``phn``
     The hostname of the Traffic Server that generated the log entry in
@@ -230,13 +230,6 @@ The following list describes Traffic Server custom logging fields.
     The proxy request server name; the name of the server that fulfilled
     the request.
 
-``prcb``
-    The number of proxy response bytes to the client from the cache.
-
-``prob``
-    The number of proxy response bytes to the client from the origin
-    server.
-
 ``pscl``
     The length of the Traffic Server response to the client (in bytes).
 

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/8d461ead/proxy/logging/Log.cc
----------------------------------------------------------------------
diff --git a/proxy/logging/Log.cc b/proxy/logging/Log.cc
index ce15131..411e67b 100644
--- a/proxy/logging/Log.cc
+++ b/proxy/logging/Log.cc
@@ -530,13 +530,6 @@ Log::init_fields()
   global_field_list.add(field, false);
   ink_hash_table_insert(field_symbol_hash, "cfsc", field);
 
-  field = NEW(new LogField("client_gid", "cgid",
-                           LogField::STRING,
-                           &LogAccess::marshal_client_gid,
-                           &LogAccess::unmarshal_str));
-  global_field_list.add(field, false);
-  ink_hash_table_insert(field_symbol_hash, "cgid", field);
-
   // proxy -> client fields
   field = NEW(new LogField("proxy_resp_content_type", "psct",
                            LogField::STRING,
@@ -648,20 +641,6 @@ Log::init_fields()
   global_field_list.add(field, false);
   ink_hash_table_insert(field_symbol_hash, "crc", field);
 
-  field = NEW(new LogField("proxy_resp_origin_bytes", "prob",
-                           LogField::sINT,
-                           &LogAccess::marshal_proxy_resp_origin_bytes,
-                           &LogAccess::unmarshal_int_to_str));
-  global_field_list.add(field, false);
-  ink_hash_table_insert(field_symbol_hash, "prob", field);
-
-  field = NEW(new LogField("proxy_resp_cache_bytes", "prcb",
-                           LogField::sINT,
-                           &LogAccess::marshal_proxy_resp_cache_bytes,
-                           &LogAccess::unmarshal_int_to_str));
-  global_field_list.add(field, false);
-  ink_hash_table_insert(field_symbol_hash, "prcb", field);
-
   // proxy -> server fields
   field = NEW(new LogField("proxy_req_header_len", "pqhl",
                            LogField::sINT,

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/8d461ead/proxy/logging/LogAccess.cc
----------------------------------------------------------------------
diff --git a/proxy/logging/LogAccess.cc b/proxy/logging/LogAccess.cc
index 7cecced..c6f6eda 100644
--- a/proxy/logging/LogAccess.cc
+++ b/proxy/logging/LogAccess.cc
@@ -217,15 +217,6 @@ LogAccess::marshal_client_finish_status_code(char *buf)
   -------------------------------------------------------------------------*/
 
 int
-LogAccess::marshal_client_gid(char *buf)
-{
-  DEFAULT_STR_FIELD;
-}
-
-/*-------------------------------------------------------------------------
-  -------------------------------------------------------------------------*/
-
-int
 LogAccess::marshal_client_accelerator_id(char *buf)
 {
   DEFAULT_STR_FIELD;
@@ -280,24 +271,6 @@ LogAccess::marshal_proxy_resp_header_len(char *buf)
   -------------------------------------------------------------------------*/
 
 int
-LogAccess::marshal_proxy_resp_origin_bytes(char *buf)
-{
-  DEFAULT_INT_FIELD;
-}
-
-/*-------------------------------------------------------------------------
-  -------------------------------------------------------------------------*/
-
-int
-LogAccess::marshal_proxy_resp_cache_bytes(char *buf)
-{
-  DEFAULT_INT_FIELD;
-}
-
-/*-------------------------------------------------------------------------
-  -------------------------------------------------------------------------*/
-
-int
 LogAccess::marshal_proxy_finish_status_code(char *buf)
 {
   DEFAULT_INT_FIELD;

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/8d461ead/proxy/logging/LogAccess.h
----------------------------------------------------------------------
diff --git a/proxy/logging/LogAccess.h b/proxy/logging/LogAccess.h
index c54cf93..e0a27b3 100644
--- a/proxy/logging/LogAccess.h
+++ b/proxy/logging/LogAccess.h
@@ -184,7 +184,6 @@ public:
   inkcoreapi virtual int marshal_client_req_header_len(char *); // INT
   inkcoreapi virtual int marshal_client_req_body_len(char *);   // INT
   inkcoreapi virtual int marshal_client_finish_status_code(char *);     // INT
-  inkcoreapi virtual int marshal_client_gid(char *);    // INT
   inkcoreapi virtual int marshal_client_accelerator_id(char *); // INT
 
   //
@@ -195,8 +194,6 @@ public:
   inkcoreapi virtual int marshal_proxy_resp_content_len(char *);        // INT
   inkcoreapi virtual int marshal_proxy_resp_status_code(char *);        // INT
   inkcoreapi virtual int marshal_proxy_resp_header_len(char *); // INT
-  inkcoreapi virtual int marshal_proxy_resp_origin_bytes(char *);       // INT
-  inkcoreapi virtual int marshal_proxy_resp_cache_bytes(char *);        // INT
   inkcoreapi virtual int marshal_proxy_finish_status_code(char *);      // INT
   inkcoreapi virtual int marshal_cache_result_code(char *);     // INT
 


[20/50] [abbrv] git commit: TS-2291: Add remap_state plugin to experimental.

Posted by zw...@apache.org.
TS-2291: Add remap_state plugin to experimental.


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

Branch: refs/heads/5.0.x
Commit: c3518560e3ca80b870cd24a99b1bb54179cfa980
Parents: 2c3f7c5
Author: Phil Sorber <so...@apache.org>
Authored: Sun Oct 20 13:22:56 2013 -0600
Committer: Phil Sorber <so...@apache.org>
Committed: Sun Oct 20 13:22:56 2013 -0600

----------------------------------------------------------------------
 CHANGES                                        |   2 +
 NOTICE                                         |   8 +-
 configure.ac                                   |   1 +
 plugins/experimental/Makefile.am               |   3 +-
 plugins/experimental/remap_stats/Makefile.am   |  21 ++
 plugins/experimental/remap_stats/remap_stats.c | 329 ++++++++++++++++++++
 6 files changed, 362 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/trafficserver/blob/c3518560/CHANGES
----------------------------------------------------------------------
diff --git a/CHANGES b/CHANGES
index 1446547..30c1354 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,8 @@
                                                          -*- coding: utf-8 -*-
 Changes with Apache Traffic Server 4.1.0
 
+  *) [TS-2291] Add remap_state plugin to experimental.
+
   *) [TS-2242] Update core plugins' support_email and vendor_name for
    consistency.
 

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/c3518560/NOTICE
----------------------------------------------------------------------
diff --git a/NOTICE b/NOTICE
index b486b5e..55084b6 100644
--- a/NOTICE
+++ b/NOTICE
@@ -6,6 +6,7 @@ This product includes software developed at
   - Yahoo! Inc
   - Network Geographics (http://network-geographics.com)
   - OmniTI
+  - Comcast
 
 ~~~
 
@@ -42,4 +43,9 @@ Copyright (C) 2012 GoDaddy.
 ~~~
 
 lib/atscppapi developed by LinkedIn
-Copyright (c) 2013 LinkedIn
\ No newline at end of file
+Copyright (c) 2013 LinkedIn
+
+~~~
+
+remap_stats plugin developed by Comcast.
+Copyright (C) 2013 Comcast

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/c3518560/configure.ac
----------------------------------------------------------------------
diff --git a/configure.ac b/configure.ac
index bb2f373..439a6e1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1896,6 +1896,7 @@ AC_CONFIG_FILES([
   plugins/experimental/spdy/Makefile
   plugins/experimental/tcp_info/Makefile
   plugins/experimental/healthchecks/Makefile
+  plugins/experimental/remap_stats/Makefile
   plugins/gzip/Makefile
   plugins/libloader/Makefile
   plugins/header_filter/Makefile

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/c3518560/plugins/experimental/Makefile.am
----------------------------------------------------------------------
diff --git a/plugins/experimental/Makefile.am b/plugins/experimental/Makefile.am
index bb97af1..eb807f8 100644
--- a/plugins/experimental/Makefile.am
+++ b/plugins/experimental/Makefile.am
@@ -27,5 +27,6 @@ SUBDIRS = \
  channel_stats \
  authproxy \
  geoip_acl \
- healthchecks
+ healthchecks \
+ remap_stats
 endif

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/c3518560/plugins/experimental/remap_stats/Makefile.am
----------------------------------------------------------------------
diff --git a/plugins/experimental/remap_stats/Makefile.am b/plugins/experimental/remap_stats/Makefile.am
new file mode 100644
index 0000000..4033fa4
--- /dev/null
+++ b/plugins/experimental/remap_stats/Makefile.am
@@ -0,0 +1,21 @@
+#  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 $(top_srcdir)/build/plugins.mk
+
+pkglib_LTLIBRARIES = remap_stats.la
+remap_stats_la_SOURCES = remap_stats.c
+remap_stats_la_LDFLAGS = $(TS_PLUGIN_LDFLAGS)

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/c3518560/plugins/experimental/remap_stats/remap_stats.c
----------------------------------------------------------------------
diff --git a/plugins/experimental/remap_stats/remap_stats.c b/plugins/experimental/remap_stats/remap_stats.c
new file mode 100644
index 0000000..23c93cd
--- /dev/null
+++ b/plugins/experimental/remap_stats/remap_stats.c
@@ -0,0 +1,329 @@
+/** @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 "ink_config.h"
+#include "ink_defs.h"
+
+#include "ts/ts.h"
+#include <stdbool.h>
+#include <string.h>
+#include <stdio.h>
+#include <getopt.h>
+#include <search.h>
+
+#define PLUGIN_NAME "remap_stats"
+#define DEBUG_TAG PLUGIN_NAME
+
+typedef struct
+{
+    bool post_remap_host;
+    int txn_slot;
+    TSStatPersistence persist_type;
+    TSMutex stat_creation_mutex;
+} config_t;
+
+typedef struct
+{
+    char *hostname;
+    bool remap_success;
+} txn_data_t;
+
+static void
+stat_add(char *name, TSMgmtInt amount, TSStatPersistence persist_type, TSMutex create_mutex)
+{
+    int stat_id = -1, *statp;
+    ENTRY search, *result = NULL;
+    static __thread struct hsearch_data stat_cache;
+    static __thread bool hash_init = false;
+
+    if (unlikely(!hash_init))
+    {
+        hcreate_r(TS_MAX_API_STATS << 1, &stat_cache);
+        hash_init = true;
+        TSDebug(DEBUG_TAG, "stat cache hash init");
+    }
+
+    search.key = name;
+    hsearch_r(search, FIND, &result, &stat_cache);
+
+    if (unlikely(result == NULL))
+    {
+        // This is an unlikely path because we most likely have the stat cached
+        // so this mutex won't be much overhead and it fixes a race condition
+        // in the RecCore. Hopefully this can be removed in the future.
+        TSMutexLock(create_mutex);
+        if (TS_ERROR == TSStatFindName((const char *) name, &stat_id))
+        {
+            stat_id = TSStatCreate((const char *) name, TS_RECORDDATATYPE_INT, persist_type, TS_STAT_SYNC_SUM);
+            if (stat_id == TS_ERROR)
+                TSDebug(DEBUG_TAG, "Error creating stat_name: %s", name);
+            else
+                TSDebug(DEBUG_TAG, "Created stat_name: %s stat_id: %d", name, stat_id);
+        }
+        TSMutexUnlock(create_mutex);
+
+        search.key = TSstrdup(name);
+        statp = TSmalloc(sizeof(int));
+        *statp = stat_id;
+        search.data = (void *) statp;
+        hsearch_r(search, ENTER, &result, &stat_cache);
+        TSDebug(DEBUG_TAG, "Cached stat_name: %s stat_id: %d", name, stat_id);
+    }
+    else
+        stat_id = *((int *) result->data);
+
+    if (likely(stat_id >= 0))
+        TSStatIntIncrement(stat_id, amount);
+    else
+        TSDebug(DEBUG_TAG, "stat error! stat_name: %s stat_id: %d", name, stat_id);
+}
+
+static char *
+get_effective_host(TSHttpTxn txn)
+{
+    char *effective_url, *tmp;
+    const char *host;
+    int len;
+    TSMBuffer buf;
+    TSMLoc url_loc;
+
+    effective_url = TSHttpTxnEffectiveUrlStringGet(txn, &len);
+    buf = TSMBufferCreate();
+    TSUrlCreate(buf, &url_loc);
+    tmp = effective_url;
+    TSUrlParse(buf, url_loc, (const char **) (&tmp), (const char *) (effective_url + len));
+    TSfree(effective_url);
+    host = TSUrlHostGet(buf, url_loc, &len);
+    tmp = TSstrndup(host, len);
+    TSHandleMLocRelease(buf, TS_NULL_MLOC, url_loc);
+    TSMBufferDestroy(buf);
+    return tmp;
+}
+
+static char *
+create_stat_name(char *hostname, char *basename)
+{
+    char *stat_name;
+    size_t stat_len;
+
+    stat_len = strlen(hostname) + strlen(basename) + strlen(PLUGIN_NAME) + 3 + strlen("plugin.");
+    stat_name = TSmalloc(stat_len * sizeof(char));
+    snprintf(stat_name, stat_len, "plugin.%s.%s.%s", PLUGIN_NAME, hostname, basename);
+    return stat_name;
+}
+
+static int
+handle_read_req_hdr(TSCont cont, TSEvent event, void *edata)
+{
+    TSHttpTxn txn = (TSHttpTxn) edata;
+    config_t *config;
+    txn_data_t *txnd;
+
+    config = (config_t *) TSContDataGet(cont);
+    txnd = TSmalloc(sizeof(txn_data_t));
+    txnd->remap_success = false;
+    txnd->hostname = get_effective_host(txn);
+    TSHttpTxnArgSet(txn, config->txn_slot, (void *) txnd);
+
+    TSHttpTxnReenable(txn, TS_EVENT_HTTP_CONTINUE);
+    TSDebug(DEBUG_TAG, "Read Req Handler Finished");
+    return 0;
+}
+
+static int
+handle_post_remap(TSCont cont, TSEvent event, void *edata)
+{
+    TSHttpTxn txn = (TSHttpTxn) edata;
+    config_t *config;
+    txn_data_t *txnd;
+
+    config = (config_t *) TSContDataGet(cont);
+
+    if (config->post_remap_host)
+    {
+        txnd = TSmalloc(sizeof(txn_data_t));
+        txnd->remap_success = true;
+        txnd->hostname = NULL;
+        TSHttpTxnArgSet(txn, config->txn_slot, (void *) txnd);
+    }
+    else
+    {
+        txnd = (txn_data_t *) TSHttpTxnArgGet(txn, config->txn_slot);
+        txnd->remap_success = true;
+    }
+
+    TSHttpTxnReenable(txn, TS_EVENT_HTTP_CONTINUE);
+    TSDebug(DEBUG_TAG, "Post Remap Handler Finished");
+    return 0;
+}
+
+static int
+handle_txn_close(TSCont cont, TSEvent event, void *edata)
+{
+    TSHttpTxn txn = (TSHttpTxn) edata;
+    config_t *config;
+    txn_data_t *txnd;
+    TSHttpStatus status_code = 0;
+    TSMBuffer buf;
+    TSMLoc hdr_loc;
+    uint64_t out_bytes, in_bytes;
+    char *remap, *stat_name;
+
+    config = (config_t *) TSContDataGet(cont);
+    txnd = (txn_data_t *) TSHttpTxnArgGet(txn, config->txn_slot);
+
+    if (txnd)
+    {
+        if (txnd->remap_success)
+        {
+            if (!config->post_remap_host)
+                remap = txnd->hostname;
+            else
+                remap = get_effective_host(txn);
+
+            if (!remap)
+                remap = TSstrdup("unknown");
+
+            in_bytes = TSHttpTxnClientReqHdrBytesGet(txn);
+            in_bytes += TSHttpTxnClientReqBodyBytesGet(txn);
+
+            stat_name = create_stat_name(remap, "in_bytes");
+            stat_add(stat_name, (TSMgmtInt) in_bytes, config->persist_type, config->stat_creation_mutex);
+            TSfree(stat_name);
+
+            out_bytes = TSHttpTxnClientRespHdrBytesGet(txn);
+            out_bytes += TSHttpTxnClientRespBodyBytesGet(txn);
+
+            stat_name = create_stat_name(remap, "out_bytes");
+            stat_add(stat_name, (TSMgmtInt) out_bytes, config->persist_type, config->stat_creation_mutex);
+            TSfree(stat_name);
+
+            if (TSHttpTxnClientRespGet(txn, &buf, &hdr_loc) == TS_SUCCESS)
+            {
+                status_code = TSHttpHdrStatusGet(buf, hdr_loc);
+                TSHandleMLocRelease(buf, TS_NULL_MLOC, hdr_loc);
+
+                if ((status_code >= 200) && (status_code <= 299))
+                    stat_name = create_stat_name(remap, "status_2xx");
+                else if ((status_code >= 300) && (status_code <= 399))
+                    stat_name = create_stat_name(remap, "status_3xx");
+                else if ((status_code >= 400) && (status_code <= 499))
+                    stat_name = create_stat_name(remap, "status_4xx");
+                else if ((status_code >= 500) && (status_code <= 599))
+                    stat_name = create_stat_name(remap, "status_5xx");
+                else
+                    stat_name = create_stat_name(remap, "status_other");
+
+                stat_add(stat_name, 1, config->persist_type, config->stat_creation_mutex);
+                TSfree(stat_name);
+            }
+            else
+            {
+                stat_name = create_stat_name(remap, "status_unknown");
+                stat_add(stat_name, 1, config->persist_type, config->stat_creation_mutex);
+                TSfree(stat_name);
+            }
+
+            TSfree(remap);
+
+        }
+        else if (txnd->hostname)
+            TSfree(txnd->hostname);
+
+        TSfree(txnd);
+    }
+
+    TSHttpTxnReenable(txn, TS_EVENT_HTTP_CONTINUE);
+    TSDebug(DEBUG_TAG, "Handler Finished");
+    return 0;
+}
+
+void
+TSPluginInit (int argc, const char *argv[])
+{
+    TSPluginRegistrationInfo info;
+    TSCont pre_remap_cont, post_remap_cont, global_cont;
+    config_t *config;
+
+    info.plugin_name = PLUGIN_NAME;
+    info.vendor_name = "Apache Software Foundation";
+    info.support_email = "dev@trafficserver.apache.org";
+
+    if (TSPluginRegister(TS_SDK_VERSION_3_0 , &info) != TS_SUCCESS)
+    {
+        TSError("Plugin registration failed.");
+        return;
+    }
+    else
+        TSDebug(DEBUG_TAG, "Plugin registration succeeded.");
+
+    config = TSmalloc(sizeof(config_t));
+    config->post_remap_host = false;
+    config->persist_type = TS_STAT_NON_PERSISTENT;
+    config->stat_creation_mutex = TSMutexCreate();
+
+    if (argc > 1)
+    {
+        int c;
+        optind = 1;
+        static const struct option longopts[] = {
+                { "post-remap-host", no_argument, NULL, 'P' },
+                { "persistent", no_argument, NULL, 'p' },
+                { NULL, 0, NULL, 0 }
+            };
+
+        while ((c = getopt_long(argc, (char * const*) argv, "Pp", longopts, NULL)) != -1)
+        {
+            switch (c)
+            {
+                case 'P':
+                    config->post_remap_host = true;
+                    TSDebug(DEBUG_TAG, "Using post remap hostname");
+                    break;
+                case 'p':
+                    config->persist_type = TS_STAT_PERSISTENT;
+                    TSDebug(DEBUG_TAG, "Using persistent stats");
+                    break;
+                default:
+                    break;
+            }
+        }
+    }
+
+    TSHttpArgIndexReserve(PLUGIN_NAME, "txn data", &(config->txn_slot));
+
+    if (!config->post_remap_host)
+    {
+        pre_remap_cont = TSContCreate(handle_read_req_hdr, NULL);
+        TSContDataSet(pre_remap_cont, (void *) config);
+        TSHttpHookAdd(TS_HTTP_READ_REQUEST_HDR_HOOK, pre_remap_cont);
+    }
+
+    post_remap_cont = TSContCreate(handle_post_remap, NULL);
+    TSContDataSet(post_remap_cont, (void *) config);
+    TSHttpHookAdd(TS_HTTP_POST_REMAP_HOOK, post_remap_cont);
+
+    global_cont = TSContCreate(handle_txn_close, NULL);
+    TSContDataSet(global_cont, (void *) config);
+    TSHttpHookAdd(TS_HTTP_TXN_CLOSE_HOOK, global_cont);
+
+    TSDebug(DEBUG_TAG, "Init complete");
+}


[09/50] [abbrv] git commit: TS-2278: Cleanup of rfc5861 plugin

Posted by zw...@apache.org.
TS-2278: Cleanup of rfc5861 plugin


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

Branch: refs/heads/5.0.x
Commit: 275e254fc5e9109981b2b126426f529ac6da9e28
Parents: a263d38
Author: Phil Sorber <so...@apache.org>
Authored: Thu Oct 17 11:09:10 2013 -0600
Committer: Phil Sorber <so...@apache.org>
Committed: Thu Oct 17 11:09:27 2013 -0600

----------------------------------------------------------------------
 plugins/experimental/rfc5861/rfc5861.c | 262 ++++++++++++----------------
 1 file changed, 115 insertions(+), 147 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/trafficserver/blob/275e254f/plugins/experimental/rfc5861/rfc5861.c
----------------------------------------------------------------------
diff --git a/plugins/experimental/rfc5861/rfc5861.c b/plugins/experimental/rfc5861/rfc5861.c
index 7983690..b5f9dbf 100644
--- a/plugins/experimental/rfc5861/rfc5861.c
+++ b/plugins/experimental/rfc5861/rfc5861.c
@@ -28,32 +28,33 @@
 #include <stdbool.h>
 #include <search.h>
 #include <getopt.h>
-//#include <sys/socket.h>
-//#include <netinet/in.h>
 #include <arpa/inet.h>
 
 #include "ink_defs.h"
 #include "ts/ts.h"
 #include "ts/experimental.h"
 
-#define LOG_PREFIX "rfc5861"
-
-//#define ENABLE_SAVE_ORIGINAL_REQUEST
+#define PLUGIN_NAME "rfc5861"
 
 static const char HTTP_VALUE_STALE_WHILE_REVALIDATE[] = "stale-while-revalidate";
 static const char HTTP_VALUE_STALE_IF_ERROR[] = "stale-if-error";
 static const char HTTP_VALUE_STALE_WARNING[] = "110 Response is stale";
 
-void *troot = NULL;
-TSMutex troot_mutex;
-int txn_slot;
-
-struct
+typedef struct
 {
     TSTextLogObject object;
     bool all, stale_if_error, stale_while_revalidate;
     char* filename;
-} log_info = {NULL,false,false,false,"rfc5861"};
+} log_info_t;
+
+typedef struct
+{
+    void *troot;
+    TSMutex troot_mutex;
+    int txn_slot;
+    time_t stale_if_error_override;
+    log_info_t log_info;
+} config_t;
 
 typedef struct
 {
@@ -89,6 +90,7 @@ typedef struct
     RequestInfo *req_info;
     ResponseInfo *resp_info;
     time_t txn_start;
+    config_t *plugin_config;
 } StateInfo;
 
 static ResponseInfo*
@@ -96,8 +98,6 @@ create_response_info(void)
 {
     ResponseInfo *resp_info;
 
-    TSDebug(LOG_PREFIX, "Entering create_response_info");
-
     resp_info = (ResponseInfo *) TSmalloc(sizeof(ResponseInfo));
 
     resp_info->buf = TSMBufferCreate();
@@ -105,22 +105,16 @@ create_response_info(void)
     resp_info->parser = TSHttpParserCreate();
     resp_info->parsed = false;
 
-    TSDebug(LOG_PREFIX, "Leaving create_reseponse_info");
-
     return resp_info;
 }
 
 static void
 free_response_info(ResponseInfo *resp_info)
 {
-    TSDebug(LOG_PREFIX, "Entering free_response_info");
-
     TSHandleMLocRelease(resp_info->buf, TS_NULL_MLOC, resp_info->http_hdr_loc);
     TSMBufferDestroy(resp_info->buf);
     TSHttpParserDestroy(resp_info->parser);
     TSfree(resp_info);
-
-    TSDebug(LOG_PREFIX, "Leaving free_response_info");
 }
 
 static RequestInfo*
@@ -132,14 +126,11 @@ create_request_info(TSHttpTxn txn)
     TSMBuffer buf;
     TSMLoc loc;
 
-    TSDebug(LOG_PREFIX, "Entering create_request_info");
-
     req_info = (RequestInfo *) TSmalloc(sizeof(RequestInfo));
 
     url = TSHttpTxnEffectiveUrlStringGet(txn, &url_len);
     req_info->effective_url = TSstrndup(url, url_len);
     TSfree(url);
-    //TSDebug(LOG_PREFIX, "URL: %s", req_info->effective_url);
 
     TSHttpTxnClientReqGet(txn, &buf, &loc);
     req_info->buf = TSMBufferCreate();
@@ -149,28 +140,17 @@ create_request_info(TSHttpTxn txn)
     req_info->client_addr = TSmalloc(sizeof(struct sockaddr));
     memmove((void *) req_info->client_addr, (void *) TSHttpTxnClientAddrGet(txn), sizeof(struct sockaddr));
 
-    TSDebug(LOG_PREFIX, "Leaving create_request_info");
-
     return req_info;
 }
 
 static void
 free_request_info(RequestInfo *req_info)
 {
-    TSDebug(LOG_PREFIX, "Entering free_request_info");
-    TSDebug(LOG_PREFIX, "Free effective URL");
-    //TSDebug(LOG_PREFIX, "URL: %s", req_info->effective_url);
     TSfree(req_info->effective_url);
-    TSDebug(LOG_PREFIX, "Release Http Header");
     TSHandleMLocRelease(req_info->buf, TS_NULL_MLOC, req_info->http_hdr_loc);
-    TSDebug(LOG_PREFIX, "Destroy Buffer");
     TSMBufferDestroy(req_info->buf);
-    TSDebug(LOG_PREFIX, "Free Client Addr");
     TSfree(req_info->client_addr);
-    TSDebug(LOG_PREFIX, "Free Request Info");
     TSfree(req_info);
-
-    TSDebug(LOG_PREFIX, "Leaving free_request_info");
 }
 
 static CachedHeaderInfo*
@@ -188,14 +168,12 @@ get_cached_header_info(TSHttpTxn txn)
     chi->stale_while_revalidate = 0;
     chi->stale_on_error = 0;
 
-    TSDebug(LOG_PREFIX, "Inside get_cached_header_info");
-
     if (TSHttpTxnCachedRespGet(txn, &cr_buf, &cr_hdr_loc) == TS_SUCCESS)
     {
         cr_date_loc = TSMimeHdrFieldFind(cr_buf, cr_hdr_loc, TS_MIME_FIELD_DATE, TS_MIME_LEN_DATE);
         if (cr_date_loc != TS_NULL_MLOC)
         {
-            TSDebug(LOG_PREFIX, "Found a date");
+            TSDebug(PLUGIN_NAME, "Found a date");
             chi->date = TSMimeHdrFieldValueDateGet(cr_buf, cr_hdr_loc, cr_date_loc);
             TSHandleMLocRelease(cr_buf, cr_hdr_loc, cr_date_loc);
         }
@@ -204,7 +182,7 @@ get_cached_header_info(TSHttpTxn txn)
 
         while(cr_cache_control_loc != TS_NULL_MLOC)
         {
-            TSDebug(LOG_PREFIX, "Found cache-control");
+            TSDebug(PLUGIN_NAME, "Found cache-control");
             cr_cache_control_count = TSMimeHdrFieldValuesCount(cr_buf, cr_hdr_loc, cr_cache_control_loc);
 
             for (i = 0; i < cr_cache_control_count; i++)
@@ -214,7 +192,7 @@ get_cached_header_info(TSHttpTxn txn)
 
                 if (strncmp(value, TS_HTTP_VALUE_MAX_AGE, TS_HTTP_LEN_MAX_AGE) == 0)
                 {
-                    TSDebug(LOG_PREFIX, "Found max-age");
+                    TSDebug(PLUGIN_NAME, "Found max-age");
                     ptr += TS_HTTP_LEN_MAX_AGE;
                     if (*ptr == '=')
                     {
@@ -224,13 +202,13 @@ get_cached_header_info(TSHttpTxn txn)
                     else
                     {
                         ptr = TSstrndup(value, TS_HTTP_LEN_MAX_AGE + 2);
-                        TSDebug(LOG_PREFIX, "This is what I found: %s", ptr);
+                        TSDebug(PLUGIN_NAME, "This is what I found: %s", ptr);
                         TSfree(ptr);
                     }
                 }
                 else if (strncmp(value, HTTP_VALUE_STALE_WHILE_REVALIDATE, strlen(HTTP_VALUE_STALE_WHILE_REVALIDATE)) == 0)
                 {
-                    TSDebug(LOG_PREFIX, "Found stale-while-revalidate");
+                    TSDebug(PLUGIN_NAME, "Found stale-while-revalidate");
                     ptr += strlen(HTTP_VALUE_STALE_WHILE_REVALIDATE);
                     if (*ptr == '=')
                     {
@@ -240,7 +218,7 @@ get_cached_header_info(TSHttpTxn txn)
                 }
                 else if (strncmp(value, HTTP_VALUE_STALE_IF_ERROR, strlen(HTTP_VALUE_STALE_IF_ERROR)) == 0)
                 {
-                    TSDebug(LOG_PREFIX, "Found stale-on-error");
+                    TSDebug(PLUGIN_NAME, "Found stale-on-error");
                     ptr += strlen(HTTP_VALUE_STALE_IF_ERROR);
                     if (*ptr == '=')
                     {
@@ -250,7 +228,7 @@ get_cached_header_info(TSHttpTxn txn)
                 }
                 else
                 {
-                    TSDebug(LOG_PREFIX, "Unknown field value");
+                    TSDebug(PLUGIN_NAME, "Unknown field value");
                 }
             }
 
@@ -261,7 +239,6 @@ get_cached_header_info(TSHttpTxn txn)
         TSHandleMLocRelease(cr_buf, TS_NULL_MLOC, cr_hdr_loc);
     }
 
-    TSDebug(LOG_PREFIX, "Leaving get_cached_header_info");
     return chi;
 }
 
@@ -279,8 +256,6 @@ parse_response(StateInfo *state)
     int64_t avail;
     char *start;
 
-    TSDebug(LOG_PREFIX, "Entering parse_response");
-
     block = TSIOBufferReaderStart(state->resp_io_buf_reader);
 
     while ((pr == TS_PARSE_CONT) && (block != NULL))
@@ -297,10 +272,8 @@ parse_response(StateInfo *state)
     {
         state->resp_info->status = TSHttpHdrStatusGet(state->resp_info->buf, state->resp_info->http_hdr_loc);
         state->resp_info->parsed = true;
-        TSDebug(LOG_PREFIX, "HTTP Status: %d", state->resp_info->status);
+        TSDebug(PLUGIN_NAME, "HTTP Status: %d", state->resp_info->status);
     }
-
-    TSDebug(LOG_PREFIX, "Leaving parse_response");
 }
 
 static int
@@ -312,8 +285,6 @@ consume_resource(TSCont cont, TSEvent event ATS_UNUSED, void *edata ATS_UNUSED)
     TSMLoc url_loc;
     int lookup_count;
 
-    TSDebug(LOG_PREFIX, "Entering consume_resource");
-
     vconn = (TSVConn) edata;
     state = (StateInfo *) TSContDataGet(cont);
 
@@ -321,15 +292,15 @@ consume_resource(TSCont cont, TSEvent event ATS_UNUSED, void *edata ATS_UNUSED)
     {
         case TS_EVENT_VCONN_WRITE_READY:
             // We shouldn't get here because we specify the exact size of the buffer.
-            TSDebug(LOG_PREFIX, "Write Ready");
+            TSDebug(PLUGIN_NAME, "Write Ready");
         case TS_EVENT_VCONN_WRITE_COMPLETE:
-            TSDebug(LOG_PREFIX, "Write Complete");
-            //TSDebug(LOG_PREFIX, "TSVConnShutdown()");
+            TSDebug(PLUGIN_NAME, "Write Complete");
+            //TSDebug(PLUGIN_NAME, "TSVConnShutdown()");
             //TSVConnShutdown(state->vconn, 0, 1);
             //TSVIOReenable(state->w_vio);
             break;
         case TS_EVENT_VCONN_READ_READY:
-            TSDebug(LOG_PREFIX, "Read Ready");
+            TSDebug(PLUGIN_NAME, "Read Ready");
 
             avail = TSIOBufferReaderAvail(state->resp_io_buf_reader);
 
@@ -349,21 +320,19 @@ consume_resource(TSCont cont, TSEvent event ATS_UNUSED, void *edata ATS_UNUSED)
         case TS_EVENT_VCONN_INACTIVITY_TIMEOUT:
             if (event == TS_EVENT_VCONN_INACTIVITY_TIMEOUT)
             {
-                TSDebug(LOG_PREFIX, "Inactivity Timeout");
-                TSDebug(LOG_PREFIX, "TSVConnAbort()");
+                TSDebug(PLUGIN_NAME, "Inactivity Timeout");
                 TSVConnAbort(vconn, TS_VC_CLOSE_ABORT);
             }
             else
             {
                 if (event == TS_EVENT_VCONN_READ_COMPLETE)
                 {
-                    TSDebug(LOG_PREFIX, "Read Complete");
+                    TSDebug(PLUGIN_NAME, "Read Complete");
                 }
                 else if (event == TS_EVENT_VCONN_EOS)
                 {
-                    TSDebug(LOG_PREFIX, "EOS");
+                    TSDebug(PLUGIN_NAME, "EOS");
                 }
-                TSDebug(LOG_PREFIX, "TSVConnClose()");
                 TSVConnClose(state->vconn);
             }
 
@@ -380,22 +349,22 @@ consume_resource(TSCont cont, TSEvent event ATS_UNUSED, void *edata ATS_UNUSED)
             TSVIONDoneSet(state->r_vio, TSVIONDoneGet(state->r_vio) + avail);
             if (state->async_req)
             {
-                TSDebug(LOG_PREFIX, "Unlock URL");
-                TSMutexLock(troot_mutex);
-                tdelete(state->req_info->effective_url, &troot, xstrcmp);
-                TSMutexUnlock(troot_mutex);
+                TSDebug(PLUGIN_NAME, "Unlock URL");
+                TSMutexLock(state->plugin_config->troot_mutex);
+                tdelete(state->req_info->effective_url, &(state->plugin_config->troot), xstrcmp);
+                TSMutexUnlock(state->plugin_config->troot_mutex);
             }
             else
             {
-                TSDebug(LOG_PREFIX, "In sync path. setting fresh and re-enabling");
+                TSDebug(PLUGIN_NAME, "In sync path. setting fresh and re-enabling");
                 TSHttpTxnCacheLookupCountGet(state->txn, &lookup_count);
                 if ((state->resp_info->status == 500) || ((state->resp_info->status >= 502) && (state->resp_info->status <= 504)) || lookup_count > 2)
                 {
-                    TSDebug(LOG_PREFIX, "Sending stale data as fresh");
-                    if (log_info.object && (log_info.all || log_info.stale_if_error))
+                    TSDebug(PLUGIN_NAME, "Sending stale data as fresh");
+                    if (state->plugin_config->log_info.object && (state->plugin_config->log_info.all || state->plugin_config->log_info.stale_if_error))
                     {
                         CachedHeaderInfo *chi = get_cached_header_info(state->txn);
-                        TSTextLogObjectWrite(log_info.object, "stale-if-error: %d - %d < %d + %d %s", (int) state->txn_start, (int) chi->date, (int) chi->max_age, (int) chi->stale_on_error, state->req_info->effective_url);
+                        TSTextLogObjectWrite(state->plugin_config->log_info.object, "stale-if-error: %d - %d < %d + %d %s", (int) state->txn_start, (int) chi->date, (int) chi->max_age, (int) chi->stale_on_error, state->req_info->effective_url);
                         TSfree(chi);
                     }
                     TSHttpTxnHookAdd(state->txn, TS_HTTP_SEND_RESPONSE_HDR_HOOK, state->main_cont);
@@ -403,7 +372,7 @@ consume_resource(TSCont cont, TSEvent event ATS_UNUSED, void *edata ATS_UNUSED)
                 }
                 else
                 {
-                    TSDebug(LOG_PREFIX, "Attempting new cache lookup");
+                    TSDebug(PLUGIN_NAME, "Attempting new cache lookup");
                     TSHttpHdrUrlGet(state->req_info->buf, state->req_info->http_hdr_loc, &url_loc);
                     TSHttpTxnNewCacheLookupDo(state->txn, state->req_info->buf, url_loc);
                     TSHandleMLocRelease(state->req_info->buf, state->req_info->http_hdr_loc, url_loc);
@@ -422,7 +391,6 @@ consume_resource(TSCont cont, TSEvent event ATS_UNUSED, void *edata ATS_UNUSED)
             TSIOBufferReaderFree(state->resp_io_buf_reader);
             TSIOBufferDestroy(state->resp_io_buf);
             TSfree(state);
-            TSDebug(LOG_PREFIX, "Destroying Cont");
             TSContDestroy(cont);
             break;
         default:
@@ -430,7 +398,6 @@ consume_resource(TSCont cont, TSEvent event ATS_UNUSED, void *edata ATS_UNUSED)
             break;
     }
 
-    TSDebug(LOG_PREFIX, "Leaving consume_resource");
     return 0;
 }
 
@@ -442,33 +409,33 @@ fetch_resource(TSCont cont, TSEvent event ATS_UNUSED, void *edata ATS_UNUSED)
     //struct sockaddr_in client_addr;
     TSMLoc connection_hdr_loc, connection_hdr_dup_loc;
 
-    TSDebug(LOG_PREFIX, "Entering fetch_resource");
-
     state = (StateInfo *) TSContDataGet(cont);
 
-    TSDebug(LOG_PREFIX, "state: %p", state);
-
     //li = (RequestInfo *) edata;
-    TSMutexLock(troot_mutex);
-    // If already doing async lookup lets just close shop and go home
-    if (state->async_req && (tfind(state->req_info->effective_url, &troot, xstrcmp) != NULL))
+    if (state->async_req)
     {
-        TSDebug(LOG_PREFIX, "Looks like an async is already in progress");
-        TSMutexUnlock(troot_mutex);
-        free_request_info(state->req_info);
-        TSfree(state);
-    }
-    // Otherwise lets do the lookup!
-    else
-    {
-        TSDebug(LOG_PREFIX, "Lets do the lookup");
-        if (state->async_req)
+        TSMutexLock(state->plugin_config->troot_mutex);
+        // If already doing async lookup lets just close shop and go home
+        if (tfind(state->req_info->effective_url, &(state->plugin_config->troot), xstrcmp) != NULL)
+        {
+            TSDebug(PLUGIN_NAME, "Looks like an async is already in progress");
+            TSMutexUnlock(state->plugin_config->troot_mutex);
+            free_request_info(state->req_info);
+            TSfree(state);
+        }
+        // Otherwise lets do the lookup!
+        else
         {
             // Lock in tree
-            TSDebug(LOG_PREFIX, "Locking URL");
-            tsearch(state->req_info->effective_url, &troot, xstrcmp);
+            TSDebug(PLUGIN_NAME, "Locking URL");
+            tsearch(state->req_info->effective_url, &(state->plugin_config->troot), xstrcmp);
+            TSMutexUnlock(state->plugin_config->troot_mutex);
         }
-        TSMutexUnlock(troot_mutex);
+    }
+
+    if (state)
+    {
+        TSDebug(PLUGIN_NAME, "Lets do the lookup");
         consume_cont = TSContCreate(consume_resource, NULL);
         TSContDataSet(consume_cont, (void *) state);
 
@@ -481,12 +448,12 @@ fetch_resource(TSCont cont, TSEvent event ATS_UNUSED, void *edata ATS_UNUSED)
             state->resp_info = create_response_info();
         }
 
-        TSDebug(LOG_PREFIX, "Set Connection: close");
+        TSDebug(PLUGIN_NAME, "Set Connection: close");
         connection_hdr_loc = TSMimeHdrFieldFind(state->req_info->buf, state->req_info->http_hdr_loc, TS_MIME_FIELD_CONNECTION, TS_MIME_LEN_CONNECTION);
 
         while(connection_hdr_loc != TS_NULL_MLOC)
         {
-            TSDebug(LOG_PREFIX, "Found old Connection hdr");
+            TSDebug(PLUGIN_NAME, "Found old Connection hdr");
 
             connection_hdr_dup_loc = TSMimeHdrFieldNextDup(state->req_info->buf, state->req_info->http_hdr_loc, connection_hdr_loc);
             TSMimeHdrFieldRemove(state->req_info->buf, state->req_info->http_hdr_loc, connection_hdr_loc);
@@ -496,43 +463,38 @@ fetch_resource(TSCont cont, TSEvent event ATS_UNUSED, void *edata ATS_UNUSED)
         }
 
         // This seems to have little effect
-        TSDebug(LOG_PREFIX, "Creating Connection hdr");
+        TSDebug(PLUGIN_NAME, "Creating Connection hdr");
         TSMimeHdrFieldCreateNamed(state->req_info->buf, state->req_info->http_hdr_loc, TS_MIME_FIELD_CONNECTION, TS_MIME_LEN_CONNECTION, &connection_hdr_loc);
         TSMimeHdrFieldValueStringInsert(state->req_info->buf, state->req_info->http_hdr_loc, connection_hdr_loc, -1, TS_HTTP_VALUE_CLOSE, TS_HTTP_LEN_CLOSE);
         TSMimeHdrFieldAppend(state->req_info->buf, state->req_info->http_hdr_loc, connection_hdr_loc);
         TSHandleMLocRelease(state->req_info->buf, state->req_info->http_hdr_loc, connection_hdr_loc);
 
         /*
-        TSDebug(LOG_PREFIX, "Creating @RFC5861 header");
+        TSDebug(PLUGIN_NAME, "Creating @RFC5861 header");
         TSMimeHdrFieldCreateNamed(state->req_info->buf, state->req_info->http_hdr_loc, TS_MIME_FIELD_CONNECTION, TS_MIME_LEN_CONNECTION, &connection_hdr_loc);
         TSMimeHdrFieldValueStringInsert(state->req_info->buf, state->req_info->http_hdr_loc, connection_hdr_loc, -1, TS_HTTP_VALUE_CLOSE, TS_HTTP_LEN_CLOSE);
         TSMimeHdrFieldAppend(state->req_info->buf, state->req_info->http_hdr_loc, connection_hdr_loc);
         TSHandleMLocRelease(state->req_info->buf, state->req_info->http_hdr_loc, connection_hdr_loc);
         */
 
-        TSDebug(LOG_PREFIX, "Create Buffers");
+        TSDebug(PLUGIN_NAME, "Create Buffers");
         state->req_io_buf = TSIOBufferCreate();
         state->req_io_buf_reader = TSIOBufferReaderAlloc(state->req_io_buf);
         state->resp_io_buf = TSIOBufferCreate();
         state->resp_io_buf_reader = TSIOBufferReaderAlloc(state->resp_io_buf);
 
-        TSDebug(LOG_PREFIX, "HdrPrint()");
         TSHttpHdrPrint(state->req_info->buf, state->req_info->http_hdr_loc, state->req_io_buf);
         TSIOBufferWrite(state->req_io_buf, "\r\n", 2);
 
-        TSDebug(LOG_PREFIX, "TSHttpConnect()");
         //memmove((void *) &client_addr, (void *) state->req_info->client_addr, sizeof(struct sockaddr));
-        //TSDebug(LOG_PREFIX, "client_addr: %s:%d", inet_ntoa(client_addr.sin_addr), client_addr.sin_port);
+        //TSDebug(PLUGIN_NAME, "client_addr: %s:%d", inet_ntoa(client_addr.sin_addr), client_addr.sin_port);
         state->vconn = TSHttpConnect((struct sockaddr const *) state->req_info->client_addr);
 
-        TSDebug(LOG_PREFIX, "TSVConnRead()");
         state->r_vio = TSVConnRead(state->vconn, consume_cont, state->resp_io_buf, INT64_MAX);
-        TSDebug(LOG_PREFIX, "TSVConnWrite()");
         state->w_vio = TSVConnWrite(state->vconn, consume_cont, state->req_io_buf_reader, TSIOBufferReaderAvail(state->req_io_buf_reader));
     }
 
     TSContDestroy(cont);
-    TSDebug(LOG_PREFIX, "Leaving fetch_resource");
 
     return 0;
 }
@@ -548,27 +510,27 @@ rfc5861_plugin(TSCont cont, TSEvent event, void *edata)
     TSMBuffer buf;
     TSMLoc loc,warn_loc;
     TSHttpStatus http_status;
+    config_t *plugin_config;
 
-    TSDebug(LOG_PREFIX, "Entering rfc5861_plugin");
     switch (event)
     {
         // Is this the proper event?
         case TS_EVENT_HTTP_READ_REQUEST_HDR:
-            TSDebug(LOG_PREFIX, "Event: TS_EVENT_HTTP_READ_REQUEST_HDR");
 
             if (TSHttpIsInternalRequest(txn) != TS_SUCCESS)
             {
-                TSDebug(LOG_PREFIX, "External Request");
+                TSDebug(PLUGIN_NAME, "External Request");
+                plugin_config = (config_t *) TSContDataGet(cont);
                 state = TSmalloc(sizeof(StateInfo));
+                state->plugin_config = plugin_config;
                 time(&state->txn_start);
                 state->req_info = create_request_info(txn);
-                TSDebug(LOG_PREFIX, "state after TSmalloc: %p", state);
-                TSHttpTxnArgSet(txn, txn_slot, (void *) state);
+                TSHttpTxnArgSet(txn, state->plugin_config->txn_slot, (void *) state);
                 TSHttpTxnHookAdd(txn, TS_HTTP_CACHE_LOOKUP_COMPLETE_HOOK, cont);
             }
             else
             {
-                TSDebug(LOG_PREFIX, "Internal Request"); // This is insufficient if there are other plugins using TSHttpConnect
+                TSDebug(PLUGIN_NAME, "Internal Request"); // This is insufficient if there are other plugins using TSHttpConnect
                 TSHttpTxnConfigIntSet(txn, TS_CONFIG_HTTP_SHARE_SERVER_SESSIONS, 1);
                 //TSHttpTxnHookAdd(txn, TS_HTTP_CACHE_LOOKUP_COMPLETE_HOOK, cont);
                 TSHttpTxnHookAdd(txn, TS_HTTP_READ_RESPONSE_HDR_HOOK, cont);
@@ -578,27 +540,28 @@ rfc5861_plugin(TSCont cont, TSEvent event, void *edata)
             }
 
             TSHttpTxnReenable(txn, TS_EVENT_HTTP_CONTINUE);
-            TSDebug(LOG_PREFIX, "TS_EVENT_HTTP_READ_REQUEST_HDR Event Handler End");
             break;
         case TS_EVENT_HTTP_CACHE_LOOKUP_COMPLETE:
-            TSDebug(LOG_PREFIX, "Event: TS_EVENT_HTTP_CACHE_LOOKUP_COMPLETE");
-            state = (StateInfo *) TSHttpTxnArgGet(txn, txn_slot);
+            plugin_config = (config_t *) TSContDataGet(cont);
+            state = (StateInfo *) TSHttpTxnArgGet(txn, plugin_config->txn_slot);
             TSHttpTxnCacheLookupCountGet(txn, &lookup_count);
-            TSDebug(LOG_PREFIX, "state after arg get: %p", state);
             if (TSHttpTxnCacheLookupStatusGet(txn, &status) == TS_SUCCESS)
             {
                 // Are we stale?
                 if (status == TS_CACHE_LOOKUP_HIT_STALE)
                 {
-                    TSDebug(LOG_PREFIX, "CacheLookupStatus is STALE");
+                    TSDebug(PLUGIN_NAME, "CacheLookupStatus is STALE");
                     // Get headers
                     chi = get_cached_header_info(txn);
 
+                    if (state->plugin_config->stale_if_error_override > chi->stale_on_error)
+                        chi->stale_on_error = state->plugin_config->stale_if_error_override;
+
                     if ((state->txn_start - chi->date) < (chi->max_age + chi->stale_while_revalidate))
                     {
-                        TSDebug(LOG_PREFIX, "Looks like we can return fresh info and validate in the background");
-                        if (log_info.object && (log_info.all || log_info.stale_while_revalidate))
-                            TSTextLogObjectWrite(log_info.object, "stale-while-revalidate: %d - %d < %d + %d %s", (int) state->txn_start, (int) chi->date, (int) chi->max_age, (int) chi->stale_while_revalidate, state->req_info->effective_url);
+                        TSDebug(PLUGIN_NAME, "Looks like we can return fresh info and validate in the background");
+                        if (state->plugin_config->log_info.object && (state->plugin_config->log_info.all || state->plugin_config->log_info.stale_while_revalidate))
+                            TSTextLogObjectWrite(state->plugin_config->log_info.object, "stale-while-revalidate: %d - %d < %d + %d %s", (int) state->txn_start, (int) chi->date, (int) chi->max_age, (int) chi->stale_while_revalidate, state->req_info->effective_url);
                         // lookup async
 
 #if (TS_VERSION_NUMBER >= 3003000)
@@ -607,23 +570,18 @@ rfc5861_plugin(TSCont cont, TSEvent event, void *edata)
                         // Set warning header
                         TSHttpTxnHookAdd(txn, TS_HTTP_SEND_RESPONSE_HDR_HOOK, cont);
 
-                        TSDebug(LOG_PREFIX, "set state as async");
+                        TSDebug(PLUGIN_NAME, "set state as async");
                         state->async_req = true;
-                        TSDebug(LOG_PREFIX, "TSHttpTxnCacheLookupStatusSet()");
                         TSHttpTxnCacheLookupStatusSet(txn, TS_CACHE_LOOKUP_HIT_FRESH);
                         //TSHttpTxnReenable(txn, TS_EVENT_HTTP_CONTINUE);
-                        TSDebug(LOG_PREFIX, "TSContCreate()");
                         fetch_cont = TSContCreate(fetch_resource, NULL);
-                        TSDebug(LOG_PREFIX, "TSContDataSet()");
                         TSContDataSet(fetch_cont, (void *) state);
-                        TSDebug(LOG_PREFIX, "state: %p", state);
                         TSContSchedule(fetch_cont, 0, TS_THREAD_POOL_TASK);
-                        TSDebug(LOG_PREFIX, "TSHttpTxnReenable()");
                         TSHttpTxnReenable(txn, TS_EVENT_HTTP_CONTINUE);
                     }
                     else if ((state->txn_start - chi->date) < (chi->max_age + chi->stale_on_error))
                     {
-                        TSDebug(LOG_PREFIX, "Looks like we can return fresh data on 500 error");
+                        TSDebug(PLUGIN_NAME, "Looks like we can return fresh data on 500 error");
 #if (TS_VERSION_NUMBER >= 3003000)
                         TSHttpTxnConfigIntSet(txn, TS_CONFIG_HTTP_INSERT_AGE_IN_RESPONSE, 1);
 #endif
@@ -633,11 +591,11 @@ rfc5861_plugin(TSCont cont, TSEvent event, void *edata)
                         state->main_cont = cont; // we need this for the warning header callback. not sure i like it, but it works.
                         fetch_cont = TSContCreate(fetch_resource, NULL);
                         TSContDataSet(fetch_cont, (void *) state);
-                        TSContSchedule(fetch_cont, 0, TS_THREAD_POOL_TASK);
+                        TSContSchedule(fetch_cont, 0, TS_THREAD_POOL_NET);
                     }
                     else
                     {
-                        TSDebug(LOG_PREFIX, "No love? now: %d date: %d max-age: %d swr: %d soe: %d", (int) state->txn_start, (int) chi->date, (int) chi->max_age, (int) chi->stale_while_revalidate, (int) chi->stale_on_error);
+                        TSDebug(PLUGIN_NAME, "No love? now: %d date: %d max-age: %d swr: %d soe: %d", (int) state->txn_start, (int) chi->date, (int) chi->max_age, (int) chi->stale_while_revalidate, (int) chi->stale_on_error);
                         if (lookup_count == 1)
                         {
                             free_request_info(state->req_info);
@@ -650,7 +608,7 @@ rfc5861_plugin(TSCont cont, TSEvent event, void *edata)
                 }
                 else
                 {
-                    TSDebug(LOG_PREFIX, "Not Stale!");
+                    TSDebug(PLUGIN_NAME, "Not Stale!");
                     if (lookup_count == 1)
                     {
                         free_request_info(state->req_info);
@@ -661,7 +619,7 @@ rfc5861_plugin(TSCont cont, TSEvent event, void *edata)
             }
             else
             {
-                TSDebug(LOG_PREFIX, "Could not get CacheLookupStatus");
+                TSDebug(PLUGIN_NAME, "Could not get CacheLookupStatus");
                 if (lookup_count == 1)
                 {
                     free_request_info(state->req_info);
@@ -669,15 +627,13 @@ rfc5861_plugin(TSCont cont, TSEvent event, void *edata)
                 }
                 TSHttpTxnReenable(txn, TS_EVENT_HTTP_CONTINUE);
             }
-            TSDebug(LOG_PREFIX, "TS_EVENT_HTTP_CACHE_LOOKUP_COMPLETE Event Handler End");
             break;
         case TS_EVENT_HTTP_READ_RESPONSE_HDR:
-            TSDebug(LOG_PREFIX, "Event: TS_EVENT_HTTP_READ_RESPONSE_HDR");
             TSHttpTxnServerRespGet(txn, &buf, &loc);
             http_status = TSHttpHdrStatusGet(buf, loc);
             if ((http_status == 500) || ((http_status >= 502) && (http_status <= 504))) // 500, 502, 503, or 504
             {
-                TSDebug(LOG_PREFIX, "Set non-cachable");
+                TSDebug(PLUGIN_NAME, "Set non-cachable");
 #if (TS_VERSION_NUMBER >= 3003000)
                 TSHttpTxnServerRespNoStoreSet(txn,1);
 #else
@@ -686,11 +642,9 @@ rfc5861_plugin(TSCont cont, TSEvent event, void *edata)
             }
             TSHandleMLocRelease(buf, TS_NULL_MLOC, loc);
             TSHttpTxnReenable(txn, TS_EVENT_HTTP_CONTINUE);
-            TSDebug(LOG_PREFIX, "TS_EVENT_HTTP_READ_RESPONSE_HDR Event Handler End");
             break;
         case TS_EVENT_HTTP_SEND_RESPONSE_HDR:
-            TSDebug(LOG_PREFIX, "Event: TS_EVENT_HTTP_SEND_RESPONSE_HDR");
-            TSDebug(LOG_PREFIX, "set warning header");
+            TSDebug(PLUGIN_NAME, "set warning header");
             TSHttpTxnClientRespGet(txn, &buf, &loc);
             TSMimeHdrFieldCreateNamed(buf, loc, TS_MIME_FIELD_WARNING, TS_MIME_LEN_WARNING, &warn_loc);
             TSMimeHdrFieldValueStringInsert(buf, loc, warn_loc, -1, HTTP_VALUE_STALE_WARNING, strlen(HTTP_VALUE_STALE_WARNING));
@@ -698,25 +652,23 @@ rfc5861_plugin(TSCont cont, TSEvent event, void *edata)
             TSHandleMLocRelease(buf, loc, warn_loc);
             TSHandleMLocRelease(buf, TS_NULL_MLOC, loc);
             TSHttpTxnReenable(txn, TS_EVENT_HTTP_CONTINUE);
-            TSDebug(LOG_PREFIX, "TS_EVENT_HTTP_SEND_RESPONSE_HDR Event Handler End");
             break;
         default:
             TSHttpTxnReenable(txn, TS_EVENT_HTTP_CONTINUE);
             break;
     }
 
-    TSDebug(LOG_PREFIX, "Leaving rfc5861_plugin");
-
     return 0;
 }
 
 void
 TSPluginInit (int argc, const char *argv[])
 {
+    config_t *plugin_config;
     TSPluginRegistrationInfo info;
     TSCont main_cont;
 
-    info.plugin_name = "rfc5861";
+    info.plugin_name = PLUGIN_NAME;
     info.vendor_name = "OmniTI Computer Consulting on behalf of Oregon Health & Science University";
     info.support_email = "phil@omniti.com";
 
@@ -727,50 +679,66 @@ TSPluginInit (int argc, const char *argv[])
     }
     else
     {
-        TSDebug(LOG_PREFIX, "Plugin registration succeeded.\n");
+        TSDebug(PLUGIN_NAME, "Plugin registration succeeded.\n");
     }
 
+    plugin_config = TSmalloc(sizeof(config_t));
+
+    plugin_config->troot = NULL;
+    plugin_config->troot_mutex = TSMutexCreate();
+    plugin_config->stale_if_error_override = 0;
+    plugin_config->log_info.object = NULL;
+    plugin_config->log_info.all = false;
+    plugin_config->log_info.stale_if_error = false;
+    plugin_config->log_info.stale_while_revalidate = false;
+    plugin_config->log_info.filename = PLUGIN_NAME;
+
     if (argc > 1)
     {
         int c;
+        optind = 1;
         static const struct option longopts[] = {
                 { "log-all", no_argument, NULL, 'a' },
                 { "log-stale-while-revalidate", no_argument, NULL, 'r' },
                 { "log-stale-if-error", no_argument, NULL, 'e' },
                 { "log-filename", required_argument, NULL, 'f' },
+                { "force-stale-if-error", required_argument, NULL, 'E' },
                 { NULL, 0, NULL, 0 }
             };
 
-        while ((c = getopt_long(argc, (char * const*) argv, "aref:", longopts, NULL)) != -1)
+        while ((c = getopt_long(argc, (char * const*) argv, "aref:E:", longopts, NULL)) != -1)
         {
             switch (c)
             {
                 case 'a':
-                    log_info.all = true;
+                    plugin_config->log_info.all = true;
                     break;
                 case 'r':
-                    log_info.stale_while_revalidate = true;
+                    plugin_config->log_info.stale_while_revalidate = true;
                     break;
                 case 'e':
-                    log_info.stale_if_error = true;
+                    plugin_config->log_info.stale_if_error = true;
                     break;
                 case 'f':
-                    log_info.filename = strdup(optarg);
+                    plugin_config->log_info.filename = strdup(optarg);
+                    break;
+                case 'E':
+                    plugin_config->stale_if_error_override = atoi(optarg);
                     break;
                 default:
                     break;
             }
         }
 
-        if (log_info.all || log_info.stale_while_revalidate || log_info.stale_if_error)
-            TSTextLogObjectCreate(log_info.filename, TS_LOG_MODE_ADD_TIMESTAMP, &log_info.object);
+        if (plugin_config->log_info.all || plugin_config->log_info.stale_while_revalidate || plugin_config->log_info.stale_if_error)
+            TSTextLogObjectCreate(plugin_config->log_info.filename, TS_LOG_MODE_ADD_TIMESTAMP, &(plugin_config->log_info.object));
     }
 
     // proxy.config.http.insert_age_in_response
-    TSHttpArgIndexReserve("rfc5861_state", "txn state info for rfc5861", &txn_slot);
-    troot_mutex = TSMutexCreate();
+    TSHttpArgIndexReserve(PLUGIN_NAME, "txn state info", &(plugin_config->txn_slot));
     main_cont = TSContCreate(rfc5861_plugin, NULL);
+    TSContDataSet(main_cont, (void *) plugin_config);
     TSHttpHookAdd(TS_HTTP_READ_REQUEST_HDR_HOOK, main_cont);
 
-    TSDebug(LOG_PREFIX, "Plugin Init Complete.\n");
+    TSDebug(PLUGIN_NAME, "Plugin Init Complete.\n");
 }


[29/50] [abbrv] git commit: TS-2280 Fix OS X build on atscppapi

Posted by zw...@apache.org.
TS-2280 Fix OS X build on atscppapi


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

Branch: refs/heads/5.0.x
Commit: 739a9c42e2185180035f49a641b2556b6a7c64f5
Parents: 199b6b8
Author: Brian Geffon <br...@apache.org>
Authored: Mon Oct 21 18:23:13 2013 -0700
Committer: Brian Geffon <br...@apache.org>
Committed: Mon Oct 21 18:23:13 2013 -0700

----------------------------------------------------------------------
 lib/atscppapi/src/include/atscppapi/AsyncHttpFetch.h      |  2 +-
 lib/atscppapi/src/include/atscppapi/AsyncTimer.h          |  2 +-
 lib/atscppapi/src/include/atscppapi/GlobalPlugin.h        |  2 +-
 .../src/include/atscppapi/GzipDeflateTransformation.h     |  2 +-
 .../src/include/atscppapi/GzipInflateTransformation.h     |  2 +-
 lib/atscppapi/src/include/atscppapi/Logger.h              |  2 +-
 .../src/include/atscppapi/TransformationPlugin.h          |  2 +-
 lib/atscppapi/src/include/atscppapi/Url.h                 | 10 +++++-----
 8 files changed, 12 insertions(+), 12 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/trafficserver/blob/739a9c42/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
index cb05ca6..5355e41 100644
--- a/lib/atscppapi/src/include/atscppapi/AsyncHttpFetch.h
+++ b/lib/atscppapi/src/include/atscppapi/AsyncHttpFetch.h
@@ -33,7 +33,7 @@
 namespace atscppapi {
 
 // forward declarations
-class AsyncHttpFetchState;
+struct AsyncHttpFetchState;
 namespace utils { class internal; }
 
 /**

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/739a9c42/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
index b076eda..d0a756d 100644
--- a/lib/atscppapi/src/include/atscppapi/AsyncTimer.h
+++ b/lib/atscppapi/src/include/atscppapi/AsyncTimer.h
@@ -33,7 +33,7 @@
 namespace atscppapi {
 
 // forward declarations
-class AsyncTimerState;
+struct AsyncTimerState;
 
 /**
  * @brief This class provides an implementation of AsyncProvider that

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/739a9c42/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
index cff431d..2c77769 100644
--- a/lib/atscppapi/src/include/atscppapi/GlobalPlugin.h
+++ b/lib/atscppapi/src/include/atscppapi/GlobalPlugin.h
@@ -29,7 +29,7 @@
 
 namespace atscppapi {
 
-class GlobalPluginState;
+struct GlobalPluginState;
 
 /**
  * @brief The interface used when creating a GlobalPlugin.

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/739a9c42/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
index a7e6923..6a6443f 100644
--- a/lib/atscppapi/src/include/atscppapi/GzipDeflateTransformation.h
+++ b/lib/atscppapi/src/include/atscppapi/GzipDeflateTransformation.h
@@ -36,7 +36,7 @@ namespace transformations {
  * Internal state for Deflate Transformations
  * @private
  */
-class GzipDeflateTransformationState;
+struct GzipDeflateTransformationState;
 
 /**
  * @brief A TransformationPlugin to easily add gzip deflate to your TransformationPlugin chain.

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/739a9c42/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
index 412af91..1c32663 100644
--- a/lib/atscppapi/src/include/atscppapi/GzipInflateTransformation.h
+++ b/lib/atscppapi/src/include/atscppapi/GzipInflateTransformation.h
@@ -36,7 +36,7 @@ namespace transformations {
  * Internal state for Inflate Transformations
  * @private
  */
-class GzipInflateTransformationState;
+struct GzipInflateTransformationState;
 
 /**
  * @brief A TransformationPlugin to easily add gzip inflate to your TransformationPlugin chain.

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/739a9c42/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
index ef6e3a6..f5227d0 100644
--- a/lib/atscppapi/src/include/atscppapi/Logger.h
+++ b/lib/atscppapi/src/include/atscppapi/Logger.h
@@ -127,7 +127,7 @@ extern "C" void TSError(const char *fmt, ...) ATSCPPAPI_PRINTFLIKE(1,2);
 
 namespace atscppapi {
 
-class LoggerState;
+struct LoggerState;
 
 /**
  * @brief Create log files that are automatically rolled and cleaned up as space is required.

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/739a9c42/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
index c4df942..ef934c3 100644
--- a/lib/atscppapi/src/include/atscppapi/TransformationPlugin.h
+++ b/lib/atscppapi/src/include/atscppapi/TransformationPlugin.h
@@ -30,7 +30,7 @@
 
 namespace atscppapi {
 
-class TransformationPluginState;
+struct TransformationPluginState;
 
 /**
  * @brief The interface used when you wish to transform Request or Response body content.

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/739a9c42/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
index e056d03..29d1ed5 100644
--- a/lib/atscppapi/src/include/atscppapi/Url.h
+++ b/lib/atscppapi/src/include/atscppapi/Url.h
@@ -29,7 +29,7 @@
 
 namespace atscppapi {
 
-class UrlState;
+struct UrlState;
 
 /**
  * @brief This class contains all properties of a Url.
@@ -68,17 +68,17 @@ public:
   ~Url();
 
   /**
-   * @return The full url as a string, such a url might be http://www.linkedin.com/profile/view?id=2941
+   * @return The full url as a string, such a url might be http://trafficserver.apache.org/search?q=blah
    */
   const std::string &getUrlString() const;
 
   /**
-   * @return The path only portion of the url, such as /profile/view
+   * @return The path only portion of the url, such as /search
    */
   const std::string &getPath() const;
 
   /**
-   * @return The query only portion of the url, which might be id=1234
+   * @return The query only portion of the url, which might be q=blah
    */
   const std::string &getQuery() const;
 
@@ -88,7 +88,7 @@ public:
   const std::string &getScheme() const;
 
   /**
-   * @return The host only of the url, this might be www.linkedin.com
+   * @return The host only of the url, this might be www.google.com
    */
   const std::string &getHost() const;
 


[41/50] [abbrv] git commit: TS-2228 Add a set-config operator

Posted by zw...@apache.org.
TS-2228 Add a set-config operator

This will allow a header_rewrite config to modify any of
the overridable records.config settings.


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

Branch: refs/heads/5.0.x
Commit: a3b07f9d4c69bcbe5dab834a6a201184a097d39a
Parents: 4bf36c8
Author: Leif Hedstrom <zw...@apache.org>
Authored: Sat Oct 19 20:28:32 2013 -0600
Committer: Leif Hedstrom <zw...@apache.org>
Committed: Wed Oct 23 15:41:09 2013 -0600

----------------------------------------------------------------------
 CHANGES                                  |  2 +
 plugins/header_rewrite/README            | 53 ++++++++++++++-------------
 plugins/header_rewrite/condition.cc      |  2 +-
 plugins/header_rewrite/conditions.cc     |  2 +-
 plugins/header_rewrite/factory.cc        |  6 ++-
 plugins/header_rewrite/header_rewrite.cc | 14 +++----
 plugins/header_rewrite/operators.cc      | 51 ++++++++++++++++++++++++--
 plugins/header_rewrite/operators.h       | 24 ++++++++++++
 plugins/header_rewrite/parser.cc         |  4 +-
 plugins/header_rewrite/ruleset.cc        |  4 +-
 plugins/header_rewrite/value.h           |  9 ++++-
 11 files changed, 124 insertions(+), 47 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/trafficserver/blob/a3b07f9d/CHANGES
----------------------------------------------------------------------
diff --git a/CHANGES b/CHANGES
index c538af5..67976e1 100644
--- a/CHANGES
+++ b/CHANGES
@@ -2,6 +2,8 @@
 Changes with Apache Traffic Server 4.1.0
 
 
+  *) [TS-2228] Add a set-config operator for header_rewrite plugin.
+
   *) [TS-2226] Add a set-header operator for header_rewrite plugin.
 
   *) [TS-2296] improve ConfigProcessor reference counting

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/a3b07f9d/plugins/header_rewrite/README
----------------------------------------------------------------------
diff --git a/plugins/header_rewrite/README b/plugins/header_rewrite/README
index ed6eeb0..4244e4a 100644
--- a/plugins/header_rewrite/README
+++ b/plugins/header_rewrite/README
@@ -12,11 +12,12 @@ Operators
 ---------
 The following operators are available: 
 
-  rm-header header-name			[flags]
-  add-header header <value>		[flags]
-  set-status <status-code>		[flags]
-  set-status-reason <value>		[flags]
-  no-op		    			[flags]
+  rm-header header-name                 [flags]
+  add-header header <value>             [flags]
+  set-status <status-code>              [flags]
+  set-status-reason <value>             [flags]
+  set-config config <value>             [flags]
+  no-op                                 [flags]
 
 The following operator(s) currently only works when instantiating the
 plugin as a remap plugin:
@@ -38,7 +39,7 @@ For example (as a remap rule):
 
 Operator flags
 --------------
-  [L]	Last rule, do not continue
+  [L]   Last rule, do not continue
 
 
 Conditions
@@ -46,22 +47,22 @@ Conditions
 The conditions are used as qualifiers: The operators specified will
 only be evaluated if the condition(s) are met.
 
-  cond %{STATUS} operand			[flags]
-  cond %{RANDOM:nn} operand			[flags]
-  cond %{ACCESS:file}				[flags]
-  cond %{TRUE}					[flags]
-  cond %{FALSE}					[flags]
-  cond %{HEADER:header-name} operand		[flags]
-  cond %{CLIENT-HEADER:header-name} operand	[flags]
-  cond %{METHOD} operand			[flags]
-  cond %{PROTOCOL} operand			[flags]
-  cond %{PORT} operand				[flags]
-  cond %{HOST} operand				[flags]
-  cond %{TOHOST} operand			[false]
-  cond %{FROMHOST} operand			[false]
-  cond %{PATH} operand				[false]
-  cond %{PARAMS} operand			[false]
-  cond %{QUERY} operand				[false]
+  cond %{STATUS} operand                        [flags]
+  cond %{RANDOM:nn} operand                     [flags]
+  cond %{ACCESS:file}                           [flags]
+  cond %{TRUE}                                  [flags]
+  cond %{FALSE}                                 [flags]
+  cond %{HEADER:header-name} operand            [flags]
+  cond %{CLIENT-HEADER:header-name} operand     [flags]
+  cond %{METHOD} operand                        [flags]
+  cond %{PROTOCOL} operand                      [flags]
+  cond %{PORT} operand                          [flags]
+  cond %{HOST} operand                          [flags]
+  cond %{TOHOST} operand                        [false]
+  cond %{FROMHOST} operand                      [false]
+  cond %{PATH} operand                          [false]
+  cond %{PARAMS} operand                        [false]
+  cond %{QUERY} operand                         [false]
 
 
 The difference between HEADER and CLIENT-HEADER is that HEADER adapts to the
@@ -81,9 +82,9 @@ each rule. This implies that a new hook condition starts a new rule as well.
 Condition flags
 ---------------
   [NC]  Not ase sensitive condition (when applicable)
-  [AND]	AND with next condition (default)
-  [OR]	OR with next condition
-  [NOT]	Invert this condition
+  [AND] AND with next condition (default)
+  [OR]  OR with next condition
+  [NOT] Invert this condition
 
 
 Operands to conditions
@@ -112,7 +113,7 @@ Examples
 cond %{HEADER:X-Y-Foobar}
 cond %{METHOD} =GET [OR]
 cond %{METHOD} =POST
-set-header X-Y-Fiefum %{HEADER:X-Y-Foobar}
+add-header X-Y-Fiefum %{HEADER:X-Y-Foobar}
 rm-header X-Y-Foobar
 rm-header Set-Cookie
 

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/a3b07f9d/plugins/header_rewrite/condition.cc
----------------------------------------------------------------------
diff --git a/plugins/header_rewrite/condition.cc b/plugins/header_rewrite/condition.cc
index 5180962..d7c05eb 100644
--- a/plugins/header_rewrite/condition.cc
+++ b/plugins/header_rewrite/condition.cc
@@ -60,7 +60,7 @@ Condition::initialize(Parser& p)
 
   if (p.mod_exist("OR")) {
     if (p.mod_exist("AND")) {
-      TSError("header_rewrite: Can't have both AND and OR in mods");
+      TSError("%s: Can't have both AND and OR in mods", PLUGIN_NAME);
     } else {
       _mods = static_cast<CondModifiers>(_mods | COND_OR);
     }

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/a3b07f9d/plugins/header_rewrite/conditions.cc
----------------------------------------------------------------------
diff --git a/plugins/header_rewrite/conditions.cc b/plugins/header_rewrite/conditions.cc
index 84ad1f0..6faac6f 100644
--- a/plugins/header_rewrite/conditions.cc
+++ b/plugins/header_rewrite/conditions.cc
@@ -332,7 +332,7 @@ ConditionDBM::initialize(Parser& p)
     //   TSError("Failed to open DBM file: %s", _file.c_str());
     // }
   } else {
-    TSError("Malformed DBM condition");
+    TSError("%s: Malformed DBM condition", PLUGIN_NAME);
   }
 }
 

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/a3b07f9d/plugins/header_rewrite/factory.cc
----------------------------------------------------------------------
diff --git a/plugins/header_rewrite/factory.cc b/plugins/header_rewrite/factory.cc
index 6c2cd9a..d7f0d6d 100644
--- a/plugins/header_rewrite/factory.cc
+++ b/plugins/header_rewrite/factory.cc
@@ -39,6 +39,8 @@ operator_factory(const std::string& op)
     o = new OperatorSetHeader();
   } else if (op == "add-header") {
     o = new OperatorAddHeader();
+  } else if (op == "set-config") {
+    o = new OperatorSetConfig();
   } else if (op == "set-status") {
     o = new OperatorSetStatus();
   } else if (op == "set-status-reason") {
@@ -52,7 +54,7 @@ operator_factory(const std::string& op)
   } else if (op == "no-op") {
     o = new OperatorNoOp();
   } else {
-    TSError("header_rewrite: unknown operator in header_rewrite: %s", op.c_str());
+    TSError("%s:unknown operator in header_rewrite: %s", PLUGIN_NAME, op.c_str());
     return NULL;
   }
 
@@ -100,7 +102,7 @@ condition_factory(const std::string& cond)
   } else if (c_name == "DBM") {
     c = new ConditionDBM();
   } else {
-    TSError("header_rewrite: unknown condition in header_rewrite: %s",c_name.c_str());
+    TSError("%s: unknown condition in header_rewrite: %s", PLUGIN_NAME, c_name.c_str());
     return NULL;
   }
 

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/a3b07f9d/plugins/header_rewrite/header_rewrite.cc
----------------------------------------------------------------------
diff --git a/plugins/header_rewrite/header_rewrite.cc b/plugins/header_rewrite/header_rewrite.cc
index 20fd387..9d3dde0 100644
--- a/plugins/header_rewrite/header_rewrite.cc
+++ b/plugins/header_rewrite/header_rewrite.cc
@@ -82,7 +82,7 @@ parse_config(const std::string fname, TSHttpHookID default_hook)
 
   f.open(filename.c_str(), std::ios::in);
   if (!f.is_open()) {
-    TSError("header_rewrite: unable to open %s", filename.c_str());
+    TSError("%s: unable to open %s", PLUGIN_NAME, filename.c_str());
     return false;
   }
 
@@ -181,7 +181,7 @@ cont_rewrite_headers(TSCont contp, TSEvent event, void *edata)
     hook = TS_HTTP_SEND_RESPONSE_HDR_HOOK;
     break;
   default:
-    TSError("header_rewrite: unknown event for this plugin");
+    TSError("%s: unknown event for this plugin", PLUGIN_NAME);
     TSDebug(PLUGIN_NAME, "unknown event for this plugin");
     break;
   }
@@ -221,12 +221,12 @@ TSPluginInit(int argc, const char *argv[])
   info.support_email = (char*)"dev@trafficserver.apache.org";
 
   if (TS_SUCCESS != TSPluginRegister(TS_SDK_VERSION_3_0 , &info)) {
-    TSError("header_rewrite: plugin registration failed.\n"); 
+    TSError("%s: plugin registration failed.\n", PLUGIN_NAME);
   }
 
   TSDebug(PLUGIN_NAME, "number of arguments: %d", argc);
   if (argc != 2) {
-    TSError("usage: %s <config-file>\n", argv[0] );
+    TSError("%s usage: %s <config-file> ... \n", PLUGIN_NAME, argv[0]);
     assert(argc == 2);
   }
 
@@ -245,7 +245,7 @@ TSPluginInit(int argc, const char *argv[])
       }
     }
   } else {
-    TSError("header_rewrite: failed to parse configuration file");
+    TSError("%s: failed to parse configuration file", PLUGIN_NAME);
   }
 }
 
@@ -283,7 +283,7 @@ TSRemapNewInstance(int argc, char *argv[], void **ih, char * /* errbuf ATS_UNUSE
   TSDebug(PLUGIN_NAME, "initializing the remap plugin header_rewrite");
 
   if (argc < 3) {
-    TSError("Unable to create remap instance, need config file");
+    TSError("%s: Unable to create remap instance, need config file", PLUGIN_NAME);
     return TS_ERROR;
   }
 
@@ -291,7 +291,7 @@ TSRemapNewInstance(int argc, char *argv[], void **ih, char * /* errbuf ATS_UNUSE
   // remap instantiation.
   all_rules[TS_REMAP_PSEUDO_HOOK] = NULL;
   if (!parse_config(argv[2], TS_REMAP_PSEUDO_HOOK)) {
-    TSError("Unable to create remap instance");
+    TSError("%s: Unable to create remap instance", PLUGIN_NAME);
     return TS_ERROR;
   }
 

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/a3b07f9d/plugins/header_rewrite/operators.cc
----------------------------------------------------------------------
diff --git a/plugins/header_rewrite/operators.cc b/plugins/header_rewrite/operators.cc
index 54c00d8..54ac221 100644
--- a/plugins/header_rewrite/operators.cc
+++ b/plugins/header_rewrite/operators.cc
@@ -25,6 +25,49 @@
 
 #include "operators.h"
 
+// OperatorConfig
+void
+OperatorSetConfig::initialize(Parser& p) {
+  Operator::initialize(p);
+  _config = p.get_arg();
+
+  if (TS_SUCCESS == TSHttpTxnConfigFind(_config.c_str(), _config.size(), &_key, &_type)) {
+    _value.set_value(p.get_value());
+  } else {
+    _key = TS_CONFIG_NULL;
+    TSError("%s: no such records config: %s", PLUGIN_NAME, _config.c_str());
+  }
+}
+
+
+void
+OperatorSetConfig::exec(const Resources& res) const
+{
+  if (TS_CONFIG_NULL != _key) {
+    switch (_type) {
+    case TS_RECORDDATATYPE_INT:
+      if (TS_SUCCESS == TSHttpTxnConfigIntSet(res.txnp, _key, _value.get_int_value())) {
+        TSDebug(PLUGIN_NAME, "OperatorSetConfig::exec() invoked on %s=%d", _config.c_str(), _value.get_int_value());
+      }
+      break;
+    case TS_RECORDDATATYPE_FLOAT:
+      if (TS_SUCCESS == TSHttpTxnConfigFloatSet(res.txnp, _key, _value.get_float_value())) {
+        TSDebug(PLUGIN_NAME, "OperatorSetConfig::exec() invoked on %s=%f", _config.c_str(), _value.get_float_value());
+      }
+      break;
+    case TS_RECORDDATATYPE_STRING:
+      if (TS_SUCCESS == TSHttpTxnConfigStringSet(res.txnp, _key, _value.get_value().c_str(), _value.size())) {
+        TSDebug(PLUGIN_NAME, "OperatorSetConfig::exec() invoked on %s=%s", _config.c_str(), _value.get_value().c_str());
+      }
+      break;
+    default:
+      TSError("%s: unknown data type, whut?", PLUGIN_NAME);
+      break;
+    }
+  }
+}
+
+
 // OperatorSetStatus
 void
 OperatorSetStatus::initialize(Parser& p)
@@ -34,7 +77,7 @@ OperatorSetStatus::initialize(Parser& p)
   _status.set_value(p.get_arg());
 
   if (NULL == (_reason = TSHttpHdrReasonLookup((TSHttpStatus)_status.get_int_value()))) {
-    TSError("header_rewrite: unknown status %d", _status.get_int_value());
+    TSError("%s: unknown status %d", PLUGIN_NAME, _status.get_int_value());
     _reason_len = 0;
   } else {
     _reason_len = strlen(_reason);
@@ -195,7 +238,7 @@ OperatorSetRedirect::initialize(Parser& p)
 
   if ((_status.get_int_value() != (int)TS_HTTP_STATUS_MOVED_PERMANENTLY) &&
       (_status.get_int_value() != (int)TS_HTTP_STATUS_MOVED_TEMPORARILY)) {
-    TSError("header_rewrite: unsupported redirect status %d", _status.get_int_value());
+    TSError("%s: unsupported redirect status %d", PLUGIN_NAME, _status.get_int_value());
   }
 
   require_resources(RSRC_SERVER_RESPONSE_HEADERS);
@@ -267,7 +310,7 @@ OperatorSetTimeoutOut::initialize(Parser& p)
     _type = TO_OUT_DNS;
   } else {
     _type = TO_OUT_UNDEFINED;
-    TSError("header_rewrite: unsupported timeout qualifier: %s", p.get_arg().c_str());
+    TSError("%s: unsupported timeout qualifier: %s", PLUGIN_NAME, p.get_arg().c_str());
   }
 
   _timeout.set_value(p.get_value());
@@ -298,7 +341,7 @@ OperatorSetTimeoutOut::exec(const Resources& res) const
     TSHttpTxnDNSTimeoutSet(res.txnp, _timeout.get_int_value());
     break;
   default:
-    TSError("header_rewrite: unsupported timeout");
+    TSError("%s: unsupported timeout", PLUGIN_NAME);
     break;
   }
 }

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/a3b07f9d/plugins/header_rewrite/operators.h
----------------------------------------------------------------------
diff --git a/plugins/header_rewrite/operators.h b/plugins/header_rewrite/operators.h
index a424f23..925b23e 100644
--- a/plugins/header_rewrite/operators.h
+++ b/plugins/header_rewrite/operators.h
@@ -33,6 +33,30 @@
 ///////////////////////////////////////////////////////////////////////////////
 // Operator declarations.
 //
+class OperatorSetConfig : public Operator
+{
+public:
+  OperatorSetConfig()
+    : _key(TS_CONFIG_NULL), _type(TS_RECORDDATATYPE_NULL)
+  {
+    TSDebug(PLUGIN_NAME_DBG, "Calling CTOR for OperatorSetConfig");
+  }
+  void initialize(Parser& p);
+
+protected:
+  void exec(const Resources& res) const;
+
+private:
+  DISALLOW_COPY_AND_ASSIGN(OperatorSetConfig);
+
+  TSOverridableConfigKey _key;
+  TSRecordDataType _type;
+
+  std::string _config;
+  Value _value;
+};
+
+
 class OperatorSetStatus : public Operator
 {
 public:

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/a3b07f9d/plugins/header_rewrite/parser.cc
----------------------------------------------------------------------
diff --git a/plugins/header_rewrite/parser.cc b/plugins/header_rewrite/parser.cc
index f354422..cdff4ee 100644
--- a/plugins/header_rewrite/parser.cc
+++ b/plugins/header_rewrite/parser.cc
@@ -54,7 +54,7 @@ Parser::preprocess(std::vector<std::string>& tokens)
       else
         _arg = "";
     } else {
-      TSError("header_rewrite: conditions must be embraced in %%{}");
+      TSError("%s: conditions must be embraced in %%{}", PLUGIN_NAME);
       return;
     }
   } else {
@@ -87,7 +87,7 @@ Parser::preprocess(std::vector<std::string>& tokens)
         }
       } else {
         // Syntax error
-        TSError("header_rewrite: mods have to be embraced in []");
+        TSError("%s: mods have to be embraced in []", PLUGIN_NAME);
         return;
       }
     }

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/a3b07f9d/plugins/header_rewrite/ruleset.cc
----------------------------------------------------------------------
diff --git a/plugins/header_rewrite/ruleset.cc b/plugins/header_rewrite/ruleset.cc
index 9b2d688..4a32c8b 100644
--- a/plugins/header_rewrite/ruleset.cc
+++ b/plugins/header_rewrite/ruleset.cc
@@ -48,7 +48,7 @@ RuleSet::add_condition(Parser& p) {
     TSDebug(PLUGIN_NAME, "Adding condition: %%{%s} with arg: %s\n", p.get_op().c_str(), p.get_arg().c_str());
     c->initialize(p);
     if (!c->set_hook(_hook)) {
-      TSError("header_rewrite: can't use this condition in this hook");
+      TSError("%s: can't use this condition in this hook", PLUGIN_NAME);
       return;
     }
     if (NULL == _cond) {
@@ -73,7 +73,7 @@ RuleSet::add_operator(Parser& p) {
     TSDebug(PLUGIN_NAME, "Adding operator: %s(%s)\n", p.get_op().c_str(), p.get_arg().c_str());
     o->initialize(p);
     if (!o->set_hook(_hook)) {
-      TSError("header_rewrite: can't use this operator in this hook");
+      TSError("%s: can't use this operator in this hook", PLUGIN_NAME);
       return;
     }
     if (NULL == _oper) {

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/a3b07f9d/plugins/header_rewrite/value.h
----------------------------------------------------------------------
diff --git a/plugins/header_rewrite/value.h b/plugins/header_rewrite/value.h
index 0c318fc..ef8c401 100644
--- a/plugins/header_rewrite/value.h
+++ b/plugins/header_rewrite/value.h
@@ -42,7 +42,7 @@ class Value : Statement
 {
 public:
   Value()
-    : _value(""), _int_value(-1), _cond_val(NULL)
+    : _value(""), _int_value(0), _float_value(0.0), _cond_val(NULL)
   {
     TSDebug(PLUGIN_NAME_DBG, "Calling CTOR for Value");
   };
@@ -58,8 +58,10 @@ public:
       if (_cond_val) {
         _cond_val->initialize(parser);
       }
+    } else {
+      _int_value = strtol(_value.c_str(), NULL, 10);
+      _float_value = strtod(_value.c_str(), NULL);
     }
-    _int_value = strtol(_value.c_str(), NULL, 10);
   }
 
   void
@@ -72,7 +74,9 @@ public:
   }
 
   const std::string& get_value() const { return _value; }
+  size_t size() const { return _value.size(); }
   int get_int_value() const { return _int_value; }
+  double get_float_value() const { return _float_value; }
 
   bool empty() const { return _value.empty(); }
 
@@ -81,6 +85,7 @@ private:
 
   std::string _value;
   int _int_value;
+  double _float_value;
   Condition* _cond_val;
 };
 


[47/50] [abbrv] git commit: TS-2300: remove the HIT_EVACUATE build option

Posted by zw...@apache.org.
TS-2300: remove the HIT_EVACUATE build option

HIT_EVACUATE is always on, so there's no need for a build option.


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

Branch: refs/heads/5.0.x
Commit: 7afc91bf5bcdb8e3d605a0111badf09a3534316c
Parents: 3eb3995
Author: James Peach <jp...@apache.org>
Authored: Thu Oct 24 10:25:56 2013 -0700
Committer: James Peach <jp...@apache.org>
Committed: Fri Oct 25 19:05:53 2013 -0700

----------------------------------------------------------------------
 CHANGES                        | 3 +++
 iocore/cache/Cache.cc          | 8 +-------
 iocore/cache/CacheDir.cc       | 4 ----
 iocore/cache/CacheRead.cc      | 6 ------
 iocore/cache/P_CacheInternal.h | 5 -----
 mgmt/RecordsConfig.cc          | 2 +-
 6 files changed, 5 insertions(+), 23 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7afc91bf/CHANGES
----------------------------------------------------------------------
diff --git a/CHANGES b/CHANGES
index 729d765..7255533 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,9 @@
                                                          -*- coding: utf-8 -*-
 Changes with Apache Traffic Server 4.1.0
 
+
+  *) [TS-2300] Remove the HIT_EVACUATE build option.
+
   *) [TS-2227] Allow for multiple config files for a header_rewrite plugin
    invocation (be it in remap.config or plugin.config).
 

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7afc91bf/iocore/cache/Cache.cc
----------------------------------------------------------------------
diff --git a/iocore/cache/Cache.cc b/iocore/cache/Cache.cc
index e417ab8..8eba0cd 100644
--- a/iocore/cache/Cache.cc
+++ b/iocore/cache/Cache.cc
@@ -69,10 +69,8 @@ int cache_config_max_doc_size = 0;
 int cache_config_min_average_object_size = ESTIMATED_OBJECT_SIZE;
 int64_t cache_config_ram_cache_cutoff = AGG_SIZE;
 int cache_config_max_disk_errors = 5;
-#ifdef HIT_EVACUATE
 int cache_config_hit_evacuate_percent = 10;
 int cache_config_hit_evacuate_size_limit = 0;
-#endif
 int cache_config_force_sector_size = 0;
 int cache_config_target_fragment_size = DEFAULT_TARGET_FRAGMENT_SIZE;
 int cache_config_agg_write_backlog = AGG_SIZE * 2;
@@ -1259,9 +1257,7 @@ Vol::init(char *s, off_t blocks, off_t dir_skip, bool clear)
   start = dir_skip;
   vol_init_data(this);
   data_blocks = (len - (start - skip)) / STORE_BLOCK_SIZE;
-#ifdef HIT_EVACUATE
   hit_evacuate_window = (data_blocks * cache_config_hit_evacuate_percent) / 100;
-#endif
 
   evacuate_size = (int) (len / EVACUATION_BUCKET_SIZE) + 2;
   int evac_len = (int) evacuate_size * sizeof(DLL<EvacuationBlock>);
@@ -3382,14 +3378,12 @@ ink_cache_init(ModuleVersion v)
       _exit(1);
     }
   }
-  // TODO: These are left here, since they are only registered if HIT_EVACUATE is enabled.
-#ifdef HIT_EVACUATE
+
   REC_EstablishStaticConfigInt32(cache_config_hit_evacuate_percent, "proxy.config.cache.hit_evacuate_percent");
   Debug("cache_init", "proxy.config.cache.hit_evacuate_percent = %d", cache_config_hit_evacuate_percent);
 
   REC_EstablishStaticConfigInt32(cache_config_hit_evacuate_size_limit, "proxy.config.cache.hit_evacuate_size_limit");
   Debug("cache_init", "proxy.config.cache.hit_evacuate_size_limit = %d", cache_config_hit_evacuate_size_limit);
-#endif
 
   REC_EstablishStaticConfigInt32(cache_config_force_sector_size, "proxy.config.cache.force_sector_size");
   REC_EstablishStaticConfigInt32(cache_config_target_fragment_size, "proxy.config.cache.target_fragment_size");

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7afc91bf/iocore/cache/CacheDir.cc
----------------------------------------------------------------------
diff --git a/iocore/cache/CacheDir.cc b/iocore/cache/CacheDir.cc
index 2ac5305..e00930e 100644
--- a/iocore/cache/CacheDir.cc
+++ b/iocore/cache/CacheDir.cc
@@ -1023,10 +1023,8 @@ sync_cache_dir_on_shutdown(void)
       Debug("cache_dir_sync", "Dir %s: ignoring -- not dirty", d->hash_id);
       continue;
     }
-#ifdef HIT_EVACUATE
     // recompute hit_evacuate_window
     d->hit_evacuate_window = (d->data_blocks * cache_config_hit_evacuate_percent) / 100;
-#endif
 
 
     // check if we have data in the agg buffer
@@ -1147,10 +1145,8 @@ Lrestart:
     }
     Vol *d = gvol[vol];
 
-#ifdef HIT_EVACUATE
     // recompute hit_evacuate_window
     d->hit_evacuate_window = (d->data_blocks * cache_config_hit_evacuate_percent) / 100;
-#endif
 
     if (DISK_BAD(d->disk))
       goto Ldone;

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7afc91bf/iocore/cache/CacheRead.cc
----------------------------------------------------------------------
diff --git a/iocore/cache/CacheRead.cc b/iocore/cache/CacheRead.cc
index 3c97305..48de9c1 100644
--- a/iocore/cache/CacheRead.cc
+++ b/iocore/cache/CacheRead.cc
@@ -510,7 +510,6 @@ CacheVC::openReadClose(int event, Event * /* e ATS_UNUSED */)
   CACHE_TRY_LOCK(lock, vol->mutex, mutex->thread_holding);
   if (!lock)
     VC_SCHED_LOCK_RETRY();
-#ifdef HIT_EVACUATE
   if (f.hit_evacuate && dir_valid(vol, &first_dir) && closed > 0) {
     if (f.single_fragment)
       vol->force_evacuate_head(&first_dir, dir_pinned(&first_dir));
@@ -519,7 +518,6 @@ CacheVC::openReadClose(int event, Event * /* e ATS_UNUSED */)
       vol->force_evacuate_head(&earliest_dir, dir_pinned(&earliest_dir));
     }
   }
-#endif
   vol->close_read(this);
   return free_CacheVC(this);
 }
@@ -836,7 +834,6 @@ CacheVC::openReadStartEarliest(int /* event ATS_UNUSED */, Event * /* e ATS_UNUS
     doc_pos = doc->prefix_len();
     next_CacheKey(&key, &doc->key);
     vol->begin_read(this);
-#ifdef HIT_EVACUATE
     if (vol->within_hit_evacuate_window(&earliest_dir) &&
         (!cache_config_hit_evacuate_size_limit || doc_len <= (uint64_t)cache_config_hit_evacuate_size_limit)
 #if TS_USE_INTERIM_CACHE == 1
@@ -847,7 +844,6 @@ CacheVC::openReadStartEarliest(int /* event ATS_UNUSED */, Event * /* e ATS_UNUS
             dir_offset(&earliest_dir), offset_to_vol_offset(vol, vol->header->write_pos), vol->header->phase);
       f.hit_evacuate = 1;
     }
-#endif
     goto Lsuccess;
 Lread:
     if (dir_probe(&key, vol, &earliest_dir, &last_collision) ||
@@ -1134,7 +1130,6 @@ CacheVC::openReadStartHead(int event, Event * e)
     if (!f.single_fragment)
       goto Learliest;
 
-#ifdef HIT_EVACUATE
     if (vol->within_hit_evacuate_window(&dir) &&
         (!cache_config_hit_evacuate_size_limit || doc_len <= (uint64_t)cache_config_hit_evacuate_size_limit)
 #if TS_USE_INTERIM_CACHE == 1
@@ -1145,7 +1140,6 @@ CacheVC::openReadStartHead(int event, Event * e)
             dir_offset(&dir), offset_to_vol_offset(vol, vol->header->write_pos), vol->header->phase);
       f.hit_evacuate = 1;
     }
-#endif
 
     first_buf = buf;
     vol->begin_read(this);

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7afc91bf/iocore/cache/P_CacheInternal.h
----------------------------------------------------------------------
diff --git a/iocore/cache/P_CacheInternal.h b/iocore/cache/P_CacheInternal.h
index 4f33fdc..02bf78d 100644
--- a/iocore/cache/P_CacheInternal.h
+++ b/iocore/cache/P_CacheInternal.h
@@ -36,7 +36,6 @@ struct EvacuationBlock;
 
 // Compilation Options
 
-#define HIT_EVACUATE                    1
 #define ALTERNATES                      1
 // #define CACHE_LOCK_FAIL_RATE         0.001
 // #define CACHE_AGG_FAIL_RATE          0.005
@@ -228,10 +227,8 @@ extern int cache_config_agg_write_backlog;
 extern int cache_config_ram_cache_compress;
 extern int cache_config_ram_cache_compress_percent;
 extern int cache_config_ram_cache_use_seen_filter;
-#ifdef HIT_EVACUATE
 extern int cache_config_hit_evacuate_percent;
 extern int cache_config_hit_evacuate_size_limit;
-#endif
 extern int cache_config_force_sector_size;
 extern int cache_config_target_fragment_size;
 extern int cache_config_mutex_retry_delay;
@@ -493,9 +490,7 @@ struct CacheVC: public CacheVConnection
       unsigned int rewrite_resident_alt:1;
       unsigned int readers:1;
       unsigned int doc_from_ram_cache:1;
-#ifdef HIT_EVACUATE
       unsigned int hit_evacuate:1;
-#endif
 #if TS_USE_INTERIM_CACHE == 1
       unsigned int read_from_interim:1;
       unsigned int write_into_interim:1;

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/7afc91bf/mgmt/RecordsConfig.cc
----------------------------------------------------------------------
diff --git a/mgmt/RecordsConfig.cc b/mgmt/RecordsConfig.cc
index 647174f..b5e87bc 100644
--- a/mgmt/RecordsConfig.cc
+++ b/mgmt/RecordsConfig.cc
@@ -862,7 +862,7 @@ RecordElement RecordsConfig[] = {
   ,
   //##############################################################################
   //#
-  //# HIT_EVACUATE
+  //# Hit Evacuation
   //#
   //##############################################################################
   {RECT_CONFIG, "proxy.config.cache.hit_evacuate_percent", RECD_INT, "0", RECU_RESTART_TS, RR_NULL, RECC_NULL, NULL, RECA_NULL}


[02/50] [abbrv] git commit: doc: update cluster howto to for connections

Posted by zw...@apache.org.
doc: update cluster howto to for connections


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

Branch: refs/heads/5.0.x
Commit: 200aafb33509263c883db8cf3d48fe949793fbc7
Parents: 5c39d02
Author: Zhao Yongming <mi...@gmail.com>
Authored: Tue Aug 20 18:24:31 2013 +0800
Committer: Zhao Yongming <mi...@gmail.com>
Committed: Tue Oct 15 16:00:08 2013 +0800

----------------------------------------------------------------------
 doc/admin/cluster-howto.en.rst | 13 ++++---------
 1 file changed, 4 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/trafficserver/blob/200aafb3/doc/admin/cluster-howto.en.rst
----------------------------------------------------------------------
diff --git a/doc/admin/cluster-howto.en.rst b/doc/admin/cluster-howto.en.rst
index 612db32..3b01019 100644
--- a/doc/admin/cluster-howto.en.rst
+++ b/doc/admin/cluster-howto.en.rst
@@ -135,8 +135,8 @@ Performance tweak for busy Cluster
 ==================================
 
 Starting from v3.2.0, Apache Traffic Server can handle multiple internal
-cluster connections, and we can tweak for the Cluster threads and
-connections:
+cluster connections, and we can tweak for the Cluster threads and each of
+the thread will keep one connection to all of the cluster machines:
 
 -  Increasing Cluster threads:
 
@@ -147,13 +147,8 @@ connections:
 
 .. XXX::  ET_NET and ET_CLUSTER should be documented some place. Right now, this means nothing to me.
 
--  Setup the Cluster connections:
-
-   In the Cluster, the internal connections is TCP and limited by
-   ET_CLUSTER threads and network performance, we can increase the
-   connections to archive better performance.::
-
-       traffic_line -s proxy.config.cluster.num_of_cluster_connections -v 10
+   ::
+       traffic_line -s proxy.config.cluster.threads -v 10
 
 with these tweaks, we can archive about 10gbps traffic for the internal
 cluster transfer speed.


[11/50] [abbrv] git commit: Added TS-1988

Posted by zw...@apache.org.
Added TS-1988


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

Branch: refs/heads/5.0.x
Commit: 36db28de2423a31edb29cf08f8c2a2528298f654
Parents: 25598f2
Author: Leif Hedstrom <zw...@apache.org>
Authored: Thu Oct 17 11:39:02 2013 -0600
Committer: Leif Hedstrom <zw...@apache.org>
Committed: Thu Oct 17 11:39:02 2013 -0600

----------------------------------------------------------------------
 CHANGES | 2 ++
 1 file changed, 2 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/trafficserver/blob/36db28de/CHANGES
----------------------------------------------------------------------
diff --git a/CHANGES b/CHANGES
index 111c913..c9695ee 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,8 @@
                                                          -*- coding: utf-8 -*-
 Changes with Apache Traffic Server 4.1.0
 
+  *) [TS-1988] cquuc and cquup log tags can have no values.
+
   *) [TS-2159] Force first log rotation at proxy.config.log.rolling_size_mb
 
   *) [TS-2138] Fix the bug that restarting ats cause cache data loss if


[03/50] [abbrv] git commit: Always forward SSH keys to VMs.

Posted by zw...@apache.org.
Always forward SSH keys to VMs.


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

Branch: refs/heads/5.0.x
Commit: 458a1a78fc64d727f0f3014e21683327cdb03cb1
Parents: 200aafb
Author: Phil Sorber <so...@apache.org>
Authored: Tue Oct 15 15:53:52 2013 -0600
Committer: Phil Sorber <so...@apache.org>
Committed: Tue Oct 15 15:53:52 2013 -0600

----------------------------------------------------------------------
 Vagrantfile | 3 +++
 1 file changed, 3 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/trafficserver/blob/458a1a78/Vagrantfile
----------------------------------------------------------------------
diff --git a/Vagrantfile b/Vagrantfile
index d36dea0..3da6359 100644
--- a/Vagrantfile
+++ b/Vagrantfile
@@ -78,6 +78,9 @@ Vagrant.configure("2") do |config|
   # because it's faster and vboxfs doesn't support links.
   config.vm.synced_folder ".", "/opt/src/trafficserver.git", :nfs => true
 
+  # Always forward SSH keys to VMs.
+  config.ssh.forward_agent = true
+
   # Ubuntu 13.04 (Raring Ringtail)
   # Ubuntu 12.10 (Quantal Quetzal)
   # Ubuntu 12.04 LTS (Precise Pangolin)