trafficserver-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From bc...@apache.org
Subject [1/2] git commit: open sourcing the header rewrite plugin from yahoo
Date Fri, 08 Jun 2012 20:47:20 GMT
Updated Branches:
  refs/heads/master a17158a3f -> e1f38ceb8


open sourcing the header rewrite plugin from yahoo


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

Branch: refs/heads/master
Commit: e1f38ceb84ba0536750fe3e44db2cda7c7ed66bd
Parents: a17158a
Author: Bryan Call <bcall@apache.org>
Authored: Fri Jun 8 12:14:12 2012 -0700
Committer: Bryan Call <bcall@apache.org>
Committed: Fri Jun 8 12:14:12 2012 -0700

----------------------------------------------------------------------
 header_rewrite/Examples/Force-close  |    4 +
 header_rewrite/Examples/Regression   |   15 ++
 header_rewrite/Examples/YCS-EC       |   19 ++
 header_rewrite/LICENSE               |  212 +++++++++++++++++
 header_rewrite/Makefile              |   14 +
 header_rewrite/README                |  168 +++++++++++++
 header_rewrite/TODO                  |   29 +++
 header_rewrite/condition.cc          |   67 ++++++
 header_rewrite/condition.h           |  101 ++++++++
 header_rewrite/conditions.cc         |  354 ++++++++++++++++++++++++++++
 header_rewrite/conditions.h          |  270 +++++++++++++++++++++
 header_rewrite/factory.cc            |   95 ++++++++
 header_rewrite/factory.h             |   20 ++
 header_rewrite/header_rewrite.cc     |  331 ++++++++++++++++++++++++++
 header_rewrite/header_rewrite.config |   77 ++++++
 header_rewrite/lulu.h                |   42 ++++
 header_rewrite/matcher.cc            |   12 +
 header_rewrite/matcher.h             |  159 +++++++++++++
 header_rewrite/operator.cc           |   32 +++
 header_rewrite/operator.h            |   59 +++++
 header_rewrite/operators.cc          |  366 +++++++++++++++++++++++++++++
 header_rewrite/operators.h           |  192 +++++++++++++++
 header_rewrite/parser.cc             |  107 +++++++++
 header_rewrite/parser.h              |   53 ++++
 header_rewrite/regex_helper.cc       |   52 ++++
 header_rewrite/regex_helper.h        |   44 ++++
 header_rewrite/resources.cc          |  110 +++++++++
 header_rewrite/resources.h           |   75 ++++++
 header_rewrite/ruleset.cc            |   75 ++++++
 header_rewrite/ruleset.h             |   81 +++++++
 header_rewrite/statement.cc          |   84 +++++++
 header_rewrite/statement.h           |   92 +++++++
 header_rewrite/value.h               |   74 ++++++
 33 files changed, 3485 insertions(+), 0 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/trafficserver-plugins/blob/e1f38ceb/header_rewrite/Examples/Force-close
----------------------------------------------------------------------
diff --git a/header_rewrite/Examples/Force-close b/header_rewrite/Examples/Force-close
new file mode 100644
index 0000000..f6e0ab6
--- /dev/null
+++ b/header_rewrite/Examples/Force-close
@@ -0,0 +1,4 @@
+cond %{READ_REQUEST_HDR_HOOK}     [AND]
+cond %{ACCESS:/url/local/www/html/status.html}    [NOT,OR]
+cond %{RANDOM:1000} =42
+add-header Connection "close"

http://git-wip-us.apache.org/repos/asf/trafficserver-plugins/blob/e1f38ceb/header_rewrite/Examples/Regression
----------------------------------------------------------------------
diff --git a/header_rewrite/Examples/Regression b/header_rewrite/Examples/Regression
new file mode 100644
index 0000000..86c8d0f
--- /dev/null
+++ b/header_rewrite/Examples/Regression
@@ -0,0 +1,15 @@
+cond %{STATUS} =201
+set-status 999
+set-status-reason "YDoDed again ..."
+
+cond %{READ_REQUEST_HDR_HOOK}
+rm-header Set-Cookie
+rm-header WWW-Authenticate
+rm-header Connection
+add-header Connection "close"
+
+cond %{RANDOM:10} =4
+set-status 789
+
+cond %{ACCESS:/tmp/foobar} [NOT]
+set-status 666

http://git-wip-us.apache.org/repos/asf/trafficserver-plugins/blob/e1f38ceb/header_rewrite/Examples/YCS-EC
----------------------------------------------------------------------
diff --git a/header_rewrite/Examples/YCS-EC b/header_rewrite/Examples/YCS-EC
new file mode 100644
index 0000000..90c3aaa
--- /dev/null
+++ b/header_rewrite/Examples/YCS-EC
@@ -0,0 +1,19 @@
+# The default hook is INK_HTTP_READ_RESPONSE_HDR_HOOK, so need to specify that
+# Remove any cookie/authentication headers from the origin server response
+rm-header Set-Cookie
+rm-header WWW-Authenticate
+
+# This technically violates RFC 2616, but allows us to calculate proper age / freshness
+# in YTS, even when the origin (*caugh* wikimedia) shows odd Date and Age responses.
+rm-header Date
+rm-header Age
+
+# If the origin responds with an HTTP status in the 400 range, normalize to a 404
+cond %{STATUS} >399 [AND]
+cond %{STATUS} <499
+set-status 404
+
+# Don't send these headers to the Origin server
+cond %{SEND_REQUEST_HDR_HOOK}
+rm-header Cache-Control
+rm-header Pragma

http://git-wip-us.apache.org/repos/asf/trafficserver-plugins/blob/e1f38ceb/header_rewrite/LICENSE
----------------------------------------------------------------------
diff --git a/header_rewrite/LICENSE b/header_rewrite/LICENSE
new file mode 100644
index 0000000..d64337f
--- /dev/null
+++ b/header_rewrite/LICENSE
@@ -0,0 +1,212 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   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.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+~~~
+
+Copyright (C) 2009 Yahoo! Inc.
+
+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

http://git-wip-us.apache.org/repos/asf/trafficserver-plugins/blob/e1f38ceb/header_rewrite/Makefile
----------------------------------------------------------------------
diff --git a/header_rewrite/Makefile b/header_rewrite/Makefile
new file mode 100644
index 0000000..d0e2162
--- /dev/null
+++ b/header_rewrite/Makefile
@@ -0,0 +1,14 @@
+TSXS?=tsxs
+
+all: condition.cc  conditions.cc  header_rewrite.cc  matcher.cc  operator.cc  operators.cc parser.cc  resources.cc  ruleset.cc  statement.cc factory.cc regex_helper.cc
+	export CPPFLAGS=$(CPPFLAGS) && \
+	export LDFLAGS=$(LDFLAGS) && \
+	$(TSXS) -v -C $? -o header_rewrite.so
+
+install:
+	$(TSXS) -i -o header_rewrite.so
+
+clean:
+	rm -f *.lo *.so *.bz2 *.asc *.md5 *.sha1
+
+

http://git-wip-us.apache.org/repos/asf/trafficserver-plugins/blob/e1f38ceb/header_rewrite/README
----------------------------------------------------------------------
diff --git a/header_rewrite/README b/header_rewrite/README
new file mode 100644
index 0000000..420a095
--- /dev/null
+++ b/header_rewrite/README
@@ -0,0 +1,168 @@
+Apache Traffic Server Rewrite Header Plugin
+This is a plugin for ATS (Apache Traffic Server), that allows you to
+perform various header "rewrite" rules (operations) on a request or
+response. Currently, only one operation is supported, since we had to get
+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.
+
+
+Operations
+----------
+
+  rm-header header-name			[flags]
+  add-header header "string"		[flags]
+  set-status status-code		[flags]
+  set-status-reason reason-string	[flags]
+  no-op		    			[flags]
+
+
+The following operator(s) currently only works when instantiating the
+plugin as a remap plugin:
+
+  set-destination [qual] value
+
+Where qual is one of the support URL qualifiers
+
+  HOST
+  PORT
+  PATH
+  QUERY
+
+For example (as a remap rule):
+
+  cond %{HEADER:X-Mobile} = "foo"
+  set-destination HOST foo.mobile.bar.com [L]
+
+
+
+Operation flags
+---------------
+  [L]	Last rule, do not continue
+
+
+Conditions
+----------
+
+  cond %{STATUS} operand	[flags]
+  cond %{RANDOM:nn} operand	[flags]
+  cond %{ACCESS:file}		[flags]
+  cond %{TRUE}			[flags]
+  cond %{FALSE}			[flags]
+  cond %{HEADER:header-name}	[flags]
+
+
+These conditions have to be first in a ruleset, and you can only have one:
+
+  cond %{READ_RESPONSE_HDR_HOOK}   (this is the default hook)
+  cond %{READ_REQUEST_HDR_HOOK}
+  cond %{SEND_REQUEST_HDR_HOOK}
+  cond %{SEND_RESPONSE_HDR_HOOK}
+
+
+Condition flags
+---------------
+  [AND]	AND with next condition (default)
+  [OR]	OR with next condition
+  [NOT]	Invert this condition
+
+
+Operands to conditions
+----------------------
+  =val	Lexically equal
+  <val	Lexically less then
+  >val	Lexically greater then   
+
+
+
+RELEASES
+--------
+Version 1.7.3 (12/01/11,sambani)
+-- changed mdbm locks to mutex
+
+Version 1.7.2 (10/18/11,cdoshi)
+-- check for url redirect length
+
+Version 1.7.1 (10/18/11,cdoshi)
+-- use size_t instead of unsigned
+
+Version 1.7.0 (10/17/11,cdoshi)
+ - Support for %{PATH}
+
+Version 1.6.9 (10,17,11,cdoshi)
+ - Support for PATH condition
+
+Version 1.6.8 (10/17/11,cdoshi)
+ -  Replace the INKHttpHdrStatusSet with INKHttptxnSetHttpRetStatus 
+
+Version 1.6.7 (07/21/11, bcall)
+  - [bug 4699620] - Removed some extra printf()'s
+
+Version 1.6.6 (cdoshi)
+  - when Host adder is added setHostChange will be called 
+
+Version 1.6.5 (cdoshi)
+  - fix QSA for set-destination
+
+Version 1.6.4 (cdoshi)
+  - support QSA for set-destination
+
+Version 1.6.3 (cdoshi)
+  - support the query,fix the remap stuff
+
+Version 1.6.2 (cdoshi)
+  - Support for regex matcher
+
+Version 1.6.1 (09/15/10, leif)
+  - [bug 3985913] 
+
+Version 1.6.0 (07/14/10, leif)
+  - Added support for the timeout-out operator.
+  - Added support for the set-redirect operator.
+  - Added support for INK_HTTP_READ_REQUEST_PRE_REMAP_HOOK (this means we
+  now require YTS 1.18.1 or later).
+
+Version 1.5.0 (06/02/10, leif)
+  - Add support for running as a remap plugin.
+  - Add support for set-destination operator (this currently only works in
+  a remap plugin).
+
+Version 1.4.1 (02/09/10, leif)
+  - Cleanup of error messages.
+  - Changed name from MDBM to DBM.
+
+Version 1.4 (01/20/10, leif)
+  - Added support for CLIENT-HEADER condition.
+  - Cleanup in flags handling and features.
+  - Support MDBM as a condition.
+
+Version 1.3.1 (12/22/09, leif)
+  - Fixed package to support MDBM v2.x and v3.x.
+
+Version 1.3 (12/22/09, leif)
+  - Refactored to allow conditions to be used as values.
+  - Added condition for HEADER.
+  - Added condition for MDBM lookups.
+  - Fixed consistency problems on HOOK names.
+
+Version 1.2 (10/28/09, leif)
+  - Added support for SEND_RESPONSE_HDR_HOOK.
+
+Version 1.1 (10/08/09, leif)
+  - Added support for SEND_REQUEST_HDR_HOOK.
+
+Version 1.0 (9/24/09, leif)
+  - Added support for two hooks.
+  - Added "add-header". Remember to "rm-header" the header first if you
+  want to assure there's only one version.
+  - Added support for %{RANDOM:NN} condition
+  - Added support for %{ACCESS:file} condition
+  - Lots of more code cleanup.
+
+Version 0.2 (7/24/09, leif)
+  - Added support for some basic conditions.
+  - Added support for setting the return status code and reason.
+
+Version 0.1 (7/13/09, leif)
+  - Initial version.

http://git-wip-us.apache.org/repos/asf/trafficserver-plugins/blob/e1f38ceb/header_rewrite/TODO
----------------------------------------------------------------------
diff --git a/header_rewrite/TODO b/header_rewrite/TODO
new file mode 100644
index 0000000..d71e1d4
--- /dev/null
+++ b/header_rewrite/TODO
@@ -0,0 +1,29 @@
+* Add a new base class for extracting values (extractor)
+* Implement extractors for various values
+* Make the statement base class virtual inherited
+* In conditions / values, we can get the value by using the << or >> operator
+* Mark which conditions and operators work in what hooks
+* Better debugging on conditions.
+* Add descriptions to conditions and operators.
+* Support configurable timeouts
+* Support "super-conditions", or nested conditions (if (A) if (b) else if (c) )
+
+
+Conditions to add
+
+%{REQUEST-HEADER:<hdr>}
+%{RESPONSE-HEADER:<hdr>}
+
+%{CLIENT-URL}
+%{CLIENT-URL:HOST}
+%{CLIENT-URL:PORT}
+%{CLIENT-URL:PATH}
+%{CLIENT-URL:QUERY}
+%{CLIENT-URL:PARAMS}
+
+%{SERVER-URL}
+%{SERVER-URL:HOST}
+%{SERVER-URL:PORT}
+%{SERVER-URL:PATH}
+%{SERVER-URL:QUERY}
+%{SERVER-URL:PARAMS}

http://git-wip-us.apache.org/repos/asf/trafficserver-plugins/blob/e1f38ceb/header_rewrite/condition.cc
----------------------------------------------------------------------
diff --git a/header_rewrite/condition.cc b/header_rewrite/condition.cc
new file mode 100644
index 0000000..518345a
--- /dev/null
+++ b/header_rewrite/condition.cc
@@ -0,0 +1,67 @@
+//////////////////////////////////////////////////////////////////////////////////////////////
+// condition.cc: Implementation of the condition base class
+//
+//
+
+#define UNUSED __attribute__ ((unused))
+static char UNUSED rcsId__condition_cc[] = "@(#) $Id$ built on " __DATE__ " " __TIME__;
+
+#include <ts/ts.h>
+#include <string>
+
+#include "condition.h"
+
+
+static MatcherOps
+parse_matcher_op(std::string& arg)
+{
+  switch (arg[0]) {
+  case '=':
+    arg.erase(0,1);
+    return MATCH_EQUAL;
+    break;
+  case '<':
+    arg.erase(0,1);
+    return MATCH_LESS_THEN;
+    break;
+  case '>':
+    arg.erase(0,1);
+    return MATCH_GREATER_THEN;
+    break;
+  case '/':
+    arg.erase(0,1);
+    arg.erase(arg.length() -1 , arg.length());
+    return MATCH_REGULAR_EXPRESSION;
+    break;
+  default:
+    return MATCH_EQUAL;
+    break;
+  }
+}
+
+
+void
+Condition::initialize(Parser& p)
+{
+  Statement::initialize(p);
+
+  if (p.mod_exist("OR")) {
+    if (p.mod_exist("AND")) {
+      TSError("header_rewrite: Can't have both AND and OR in mods");
+    } else {
+      _mods = static_cast<CondModifiers>(_mods | COND_OR);
+    }
+  } else if (p.mod_exist("AND")) {
+    _mods = static_cast<CondModifiers>(_mods | COND_AND);
+  }
+
+  if (p.mod_exist("NOT")) {
+    _mods = static_cast<CondModifiers>(_mods | COND_NOT);
+  }
+
+  if (p.mod_exist("L")) {
+    _mods = static_cast<CondModifiers>(_mods | COND_LAST);
+  }
+
+  _cond_op = parse_matcher_op(p.get_arg());
+}

http://git-wip-us.apache.org/repos/asf/trafficserver-plugins/blob/e1f38ceb/header_rewrite/condition.h
----------------------------------------------------------------------
diff --git a/header_rewrite/condition.h b/header_rewrite/condition.h
new file mode 100644
index 0000000..149642c
--- /dev/null
+++ b/header_rewrite/condition.h
@@ -0,0 +1,101 @@
+//////////////////////////////////////////////////////////////////////////////////////////////
+// 
+// Implement the classes for the various types of hash keys we support.
+//
+#ifndef __CONDITION_H__
+#define __CONDITION_H__ 1
+
+#define UNUSED __attribute__ ((unused))
+static char UNUSED rcsId__condition_h[] = "@(#) $Id$ built on " __DATE__ " " __TIME__;
+
+#include <string>
+#include <ts/ts.h>
+
+#include "resources.h"
+#include "statement.h"
+#include "matcher.h"
+#include "parser.h"
+
+
+// Condition modifiers
+enum CondModifiers {
+  COND_NONE = 0,
+  COND_OR = 1,
+  COND_AND = 2,
+  COND_NOT = 4,
+  COND_NOCASE = 8,
+  COND_LAST = 16,
+  COND_CHAIN = 32
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Base class for all Conditions (this is also the interface)
+//
+class Condition : public Statement
+{
+public:
+  Condition()
+    : _qualifier(""), _cond_op(MATCH_EQUAL), _matcher(NULL), _mods(COND_NONE)
+  {
+    TSDebug(PLUGIN_NAME_DBG, "Calling CTOR for Condition");
+  }
+
+  // Inline this, it's critical for speed (and only used twice)
+  bool do_eval(const Resources& res)
+  {
+    bool rt = eval(res);
+
+    if (_mods & COND_NOT)
+      rt = !rt;
+
+    if (_next) {
+      if (_mods & COND_OR) {
+        return rt || (static_cast<Condition*>(_next)->do_eval(res));
+      } else { // AND is the default
+        // Short circuit if we're an AND and the first condition is FALSE.
+        if (rt)
+          return static_cast<Condition*>(_next)->do_eval(res);
+        else
+          return false;
+      }
+    } else {
+      return rt;
+    }
+
+    return false; // Shouldn't happen.
+  }
+
+  bool last() const {
+    return _mods & COND_LAST;
+  }
+
+  // Setters
+  virtual void set_qualifier(const std::string& q) { _qualifier = q; }
+
+  // Some getters
+  const Matcher* get_matcher() const { return _matcher; }
+  const MatcherOps get_cond_op() const { return _cond_op; }
+  const std::string get_qualifier() const { return _qualifier; }
+
+  // Virtual methods, has to be implemented by each conditional;
+  virtual void initialize(Parser& p);
+  virtual void append_value(std::string& s, const Resources& res) = 0;
+
+protected:
+  // Evaluate the condition
+  virtual bool eval(const Resources& res) = 0;
+
+  std::string _qualifier;
+  MatcherOps _cond_op;
+  Matcher* _matcher;
+
+private:
+  DISALLOW_COPY_AND_ASSIGN(Condition);
+
+  CondModifiers _mods;
+};
+
+
+#endif // __CONDITION_H
+

http://git-wip-us.apache.org/repos/asf/trafficserver-plugins/blob/e1f38ceb/header_rewrite/conditions.cc
----------------------------------------------------------------------
diff --git a/header_rewrite/conditions.cc b/header_rewrite/conditions.cc
new file mode 100644
index 0000000..f05d8ec
--- /dev/null
+++ b/header_rewrite/conditions.cc
@@ -0,0 +1,354 @@
+//////////////////////////////////////////////////////////////////////////////////////////////
+// conditions.cc: Implementation of the condition classes
+//
+//
+
+#define UNUSED __attribute__ ((unused))
+static char UNUSED rcsId__conditions_cc[] = "@(#) $Id$ built on " __DATE__ " " __TIME__;
+
+#include <unistd.h>
+#include <ts/ts.h>
+
+#include "conditions.h"
+#include "lulu.h"
+
+#include <sys/time.h>
+
+
+// ConditionStatus
+void
+ConditionStatus::initialize(Parser& p)
+{
+  Condition::initialize(p);
+
+  Matchers<TSHttpStatus>* match = new Matchers<TSHttpStatus>(_cond_op);
+
+  match->set(static_cast<TSHttpStatus>(strtol(p.get_arg().c_str(), NULL, 10)));
+  _matcher = match;
+
+  require_resources(RSRC_SERVER_RESPONSE_HEADERS);
+  require_resources(RSRC_CLIENT_RESPONSE_HEADERS);
+  require_resources(RSRC_RESPONSE_STATUS);
+}
+
+
+void
+ConditionStatus::initialize_hooks() {
+  add_allowed_hook(TS_HTTP_READ_RESPONSE_HDR_HOOK);
+  add_allowed_hook(TS_HTTP_SEND_RESPONSE_HDR_HOOK);
+}
+
+
+bool
+ConditionStatus::eval(const Resources& res) {
+  TSDebug(PLUGIN_NAME, "Evaluating STATUS()"); // TODO: It'd be nice to get the args here ...
+  return static_cast<const Matchers<TSHttpStatus>*>(_matcher)->test(res.resp_status);
+}
+
+
+void
+ConditionStatus::append_value(std::string& s, const Resources& res) {
+  s += boost::lexical_cast<std::string>(res.resp_status);
+  TSDebug(PLUGIN_NAME, "Appending STATUS(%d) to evaluation value -> %s", res.resp_status, s.c_str());
+}
+
+
+// ConditionRandom: random 0 to (N-1)
+void
+ConditionRandom::initialize(Parser& p)
+{
+  struct timeval tv;
+
+  Condition::initialize(p);
+
+  gettimeofday(&tv, NULL);
+
+  Matchers<unsigned int>* match = new Matchers<unsigned int>(_cond_op);
+  _seed = getpid()* tv.tv_usec;
+  _max = strtol(_qualifier.c_str(), NULL, 10);
+
+  match->set(static_cast<unsigned int>(strtol(p.get_arg().c_str(), NULL, 10)));
+  _matcher = match;
+}
+
+
+bool
+ConditionRandom::eval(const Resources& res) {
+  TSDebug(PLUGIN_NAME, "Evaluating RANDOM(%d)", _max);
+  return static_cast<const Matchers<unsigned int>*>(_matcher)->test(rand_r(&_seed) % _max);
+}
+
+
+void
+ConditionRandom::append_value(std::string& s, const Resources& res)
+{
+  s += boost::lexical_cast<std::string>(rand_r(&_seed) % _max);
+  TSDebug(PLUGIN_NAME, "Appending RANDOM(%d) to evaluation value -> %s", _max, s.c_str());
+}
+
+
+// ConditionAccess: access(file)
+void
+ConditionAccess::initialize(Parser& p)
+{
+  struct timeval tv;
+
+  Condition::initialize(p);
+
+  gettimeofday(&tv, NULL);
+
+  _next = tv.tv_sec + 2;
+  _last = !access(_qualifier.c_str(), R_OK);
+}
+
+
+void
+ConditionAccess::append_value(std::string& s, const Resources& res)
+{
+  if (eval(res)) {
+    s += "OK";
+  } else {
+    s += "NOT OK";
+  }
+}
+
+
+bool
+ConditionAccess::eval(const Resources& res)
+{
+  struct timeval tv;
+
+  gettimeofday(&tv, NULL);
+
+  TSDebug(PLUGIN_NAME, "Evaluating ACCESS(%s)", _qualifier.c_str());
+  if (tv.tv_sec > _next) {
+    // There is a small "race" here, where we could end up calling access() a few times extra. I think
+    // that is OK, and not worth protecting with a lock.
+    bool check = !access(_qualifier.c_str(), R_OK);
+
+    tv.tv_sec += 2;
+    mb();
+    _next = tv.tv_sec; // I hope this is an atomic "set"...
+    _last = check; // This sure ought to be
+  }
+
+  return _last;
+}
+
+
+// ConditionHeader: request or response header
+void
+ConditionHeader::initialize(Parser& p)
+{
+  Condition::initialize(p);
+
+  Matchers<std::string>* match = new Matchers<std::string>(_cond_op);
+  match->set(p.get_arg());
+
+  _matcher = match;
+
+  require_resources(RSRC_CLIENT_REQUEST_HEADERS);
+  require_resources(RSRC_CLIENT_RESPONSE_HEADERS);
+  require_resources(RSRC_SERVER_REQUEST_HEADERS);
+  require_resources(RSRC_SERVER_RESPONSE_HEADERS);
+}
+
+
+void
+ConditionHeader::append_value(std::string& s, const Resources& res)
+{
+  TSMBuffer bufp;
+  TSMLoc hdr_loc;
+  TSMLoc field_loc;
+  const char* value;
+  int len;
+
+  if (_client) {
+    bufp = res.client_bufp;
+    hdr_loc = res.client_hdr_loc;
+  } else {
+    bufp = res.bufp;
+    hdr_loc = res.hdr_loc;
+  }
+
+  if (bufp && hdr_loc) {
+    field_loc = TSMimeHdrFieldFind(bufp, hdr_loc, _qualifier.c_str(), _qualifier.size());
+    if (field_loc) {
+      value = TSMimeHdrFieldValueStringGet(res.bufp, res.hdr_loc, field_loc, 0, &len);
+      TSDebug(PLUGIN_NAME, "Appending HEADER(%s) to evaluation value -> %.*s", _qualifier.c_str(), len, value);
+      s.append(value, len);
+      TSHandleMLocRelease(res.bufp, res.hdr_loc, field_loc);
+    }
+  }
+}
+
+
+bool
+ConditionHeader::eval(const Resources& res)
+{
+  std::string s;
+
+  append_value(s, res);
+  bool rval = static_cast<const Matchers<std::string>*>(_matcher)->test(s);
+  TSDebug(PLUGIN_NAME, "Evaluating HEADER(): %s - rval: %d", s.c_str(), rval);
+  return rval;
+}
+
+// ConditionPath
+void
+ConditionPath::initialize(Parser& p)
+{
+  Condition::initialize(p);
+
+  Matchers<std::string>* match = new Matchers<std::string>(_cond_op);
+  match->set(p.get_arg());
+
+  _matcher = match;
+}
+
+void
+ConditionPath::append_value(std::string& s, const Resources& res)
+{ 
+  int path_len = 0;
+  const char *path = TSUrlPathGet(res._rri->requestBufp, res._rri->requestUrl, &path_len);
+  TSDebug(PLUGIN_NAME, "Appending PATH to evaluation value: %.*s", path_len, path);
+  s.append(path, path_len);
+}
+
+bool
+ConditionPath::eval(const Resources& res)
+{
+  std::string s;
+
+  append_value(s, res);
+  TSDebug(PLUGIN_NAME, "Evaluating PATH");
+
+  return static_cast<const Matchers<std::string>*>(_matcher)->test(s);
+}
+
+// ConditionQuery
+void
+ConditionQuery::initialize(Parser& p)
+{
+  Condition::initialize(p);
+
+  Matchers<std::string>* match = new Matchers<std::string>(_cond_op);
+  match->set(p.get_arg());
+  _matcher = match;
+
+}
+
+void
+ConditionQuery::append_value(std::string& s, const Resources& res)
+{
+  int query_len = 0;
+  const char *query = TSUrlHttpQueryGet(res._rri->requestBufp, res._rri->requestUrl, &query_len);
+  TSDebug(PLUGIN_NAME, "Appending QUERY to evaluation value: %.*s", query_len, query);
+  s.append(query, query_len);
+}
+
+bool
+ConditionQuery::eval(const Resources& res)
+{
+  std::string s;
+
+  append_value(s, res);
+  TSDebug(PLUGIN_NAME, "Evaluating QUERY - %s", s.c_str());
+  return static_cast<const Matchers<std::string>*>(_matcher)->test(s);
+}
+
+
+// ConditionUrl: request or response header. TODO: This is not finished, at all!!!
+void
+ConditionUrl::initialize(Parser& p)
+{
+}
+
+
+void
+ConditionUrl::set_qualifier(const std::string& q) {
+  Condition::set_qualifier(q);
+
+  _url_qual = parse_url_qualifier(q);
+}
+
+
+void
+ConditionUrl::append_value(std::string& s, const Resources& res)
+{
+}
+
+
+bool
+ConditionUrl::eval(const Resources& res)
+{
+  bool ret = false;
+
+  return ret;
+}
+
+
+// ConditionDBM: do a lookup against a DBM
+void
+ConditionDBM::initialize(Parser& p)
+{
+  Condition::initialize(p);
+
+  Matchers<std::string>* match = new Matchers<std::string>(_cond_op);
+  match->set(p.get_arg());
+  _matcher = match;
+
+  std::string::size_type pos = _qualifier.find_first_of(',');
+
+  if (pos != std::string::npos) {
+    _file = _qualifier.substr(0, pos);
+    //_dbm = mdbm_open(_file.c_str(), O_RDONLY, 0, 0, 0);
+    // if (NULL != _dbm) {
+    //   TSDebug(PLUGIN_NAME, "Opened DBM file %s\n", _file.c_str());
+    //   _key.set_value(_qualifier.substr(pos + 1));
+    // } else {
+    //   TSError("Failed to open DBM file: %s", _file.c_str());
+    // }
+  } else {
+    TSError("Malformed DBM condition");
+  }
+}
+
+
+void
+ConditionDBM::append_value(std::string& s, const Resources& res)
+{
+  // std::string key;
+
+  // if (!_dbm)
+  //   return;
+
+  // _key.append_value(key, res);
+  // if (key.size() > 0) {
+  //   datum k, v;
+
+  //   TSDebug(PLUGIN_NAME, "Looking up DBM(\"%s\")", key.c_str());
+  //   k.dptr = const_cast<char*>(key.c_str());
+  //   k.dsize = key.size();
+
+  //   TSMutexLock(_mutex);
+  //   //v = mdbm_fetch(_dbm, k);
+  //   TSMutexUnlock(_mutex);
+  //   if (v.dsize > 0) {
+  //     TSDebug(PLUGIN_NAME, "Appending DBM(%.*s) to evaluation value -> %.*s", k.dsize, k.dptr, v.dsize, v.dptr);
+  //     s.append(v.dptr, v.dsize);
+  //   }
+  // }
+}
+
+
+bool
+ConditionDBM::eval(const Resources& res)
+{
+  std::string s;
+
+  append_value(s, res);
+  TSDebug(PLUGIN_NAME, "Evaluating DBM(%s, \"%s\")", _file.c_str(), s.c_str());
+
+  return static_cast<const Matchers<std::string>*>(_matcher)->test(s);
+}

http://git-wip-us.apache.org/repos/asf/trafficserver-plugins/blob/e1f38ceb/header_rewrite/conditions.h
----------------------------------------------------------------------
diff --git a/header_rewrite/conditions.h b/header_rewrite/conditions.h
new file mode 100644
index 0000000..25975fb
--- /dev/null
+++ b/header_rewrite/conditions.h
@@ -0,0 +1,270 @@
+//////////////////////////////////////////////////////////////////////////////////////////////
+// 
+// Declarations for all conditionals / conditional values we support.
+//
+#ifndef __CONDITIONS_H__
+#define __CONDITIONS_H__ 1
+
+#define UNUSED __attribute__ ((unused))
+static char UNUSED rcsId__conditions_h[] = "@(#) $Id$ built on " __DATE__ " " __TIME__;
+
+#include <string>
+#include <ts/ts.h>
+#include <boost/lexical_cast.hpp>
+
+#include "condition.h"
+#include "matcher.h"
+#include "value.h"
+#include "lulu.h"
+//#include <mdbm.h>
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Condition declarations.
+//
+
+// Always true
+class ConditionTrue : public Condition
+{
+public:
+  ConditionTrue()
+  {
+    TSDebug(PLUGIN_NAME_DBG, "Calling CTOR for ConditionTrue");
+  }
+
+  void append_value(std::string& s, const Resources& res) { s += "TRUE";  }
+
+protected:
+  bool eval(const Resources& res) {
+    TSDebug(PLUGIN_NAME, "Evaluating TRUE()");
+    return true;
+  }
+
+private:
+  DISALLOW_COPY_AND_ASSIGN(ConditionTrue);
+};
+
+
+// Always false
+class ConditionFalse : public Condition
+{
+public:
+  ConditionFalse()
+  {
+    TSDebug(PLUGIN_NAME_DBG, "Calling CTOR for ConditionFalse");
+  }
+  void append_value(std::string& s, const Resources& res) { s += "FALSE"; }
+
+protected:
+  bool eval(const Resources& res) {
+    TSDebug(PLUGIN_NAME, "Evaluating FALSE()");
+    return false;
+  }
+
+private:
+  DISALLOW_COPY_AND_ASSIGN(ConditionFalse);
+};
+
+
+// Check the HTTP return status
+class ConditionStatus : public Condition
+{
+public:
+  ConditionStatus()
+  {
+    TSDebug(PLUGIN_NAME_DBG, "Calling CTOR for ConditionStatus");
+  }
+  void initialize(Parser& p);
+  void append_value(std::string& s, const Resources& res);
+
+protected:
+  bool eval(const Resources& res);
+  void initialize_hooks(); // Return status only valid in certain hooks
+
+private:
+  DISALLOW_COPY_AND_ASSIGN(ConditionStatus);
+};
+
+
+// Random 0 to (N-1)
+class ConditionRandom : public Condition
+{
+public:
+  ConditionRandom()
+    : _seed(0), _max(0)
+  {
+    TSDebug(PLUGIN_NAME_DBG, "Calling CTOR for ConditionRandom");
+  }
+  void initialize(Parser& p);
+  void append_value(std::string& s, const Resources& res);
+
+protected:
+  bool eval(const Resources& res);
+
+private:
+  DISALLOW_COPY_AND_ASSIGN(ConditionRandom);
+
+  unsigned int _seed;
+  unsigned int _max;
+};
+
+
+// access(file)
+class ConditionAccess : public Condition
+{
+public:
+  ConditionAccess()
+    : _next(0), _last(false)
+  {
+    TSDebug(PLUGIN_NAME_DBG, "Calling CTOR for ConditionAccess");
+  }
+  void initialize(Parser& p);
+  void append_value(std::string& s, const Resources& res);
+
+protected:
+  bool eval(const Resources& res);
+
+private:
+  DISALLOW_COPY_AND_ASSIGN(ConditionAccess);
+
+  time_t _next;
+  bool _last;
+};
+
+
+// header
+class ConditionHeader : public Condition
+{
+public:
+  explicit ConditionHeader(bool client = false)
+    : _client(client)
+  {
+    TSDebug(PLUGIN_NAME_DBG, "Calling CTOR for ConditionHeader");
+  };
+
+  void initialize(Parser& p);
+  void append_value(std::string& s, const Resources& res);
+
+protected:
+  bool eval(const Resources& res);
+
+private:
+  DISALLOW_COPY_AND_ASSIGN(ConditionHeader);
+
+  bool _client;
+};
+
+// path 
+class ConditionPath : public Condition
+{
+public:
+  explicit ConditionPath()
+  {
+    TSDebug(PLUGIN_NAME_DBG, "Calling CTOR for ConditionPath");
+  };
+
+  void initialize(Parser& p);
+  void append_value(std::string& s, const Resources& res);
+
+protected:
+  bool eval(const Resources& res);
+
+private:
+  DISALLOW_COPY_AND_ASSIGN(ConditionPath);
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+class ConditionQuery : public Condition
+{
+public:
+  explicit ConditionQuery()
+  {
+    TSDebug(PLUGIN_NAME_DBG, "Calling CTOR for ConditionQuery");
+  };
+
+  void initialize(Parser& p);
+  void append_value(std::string& s, const Resources& res);
+
+protected:
+  bool eval(const Resources& res);
+
+private:
+  DISALLOW_COPY_AND_ASSIGN(ConditionQuery);
+
+};
+
+
+// url
+class ConditionUrl : public Condition
+{
+public:
+  explicit ConditionUrl(bool client = false)
+    : _url_qual(URL_QUAL_NONE), _client(client)
+  {
+    TSDebug(PLUGIN_NAME_DBG, "Calling CTOR for ConditionUrl");
+  };
+
+  void initialize(Parser& p);
+  void set_qualifier(const std::string& q);
+  void append_value(std::string& s, const Resources& res);
+
+protected:
+  bool eval(const Resources& res);
+
+private:
+  DISALLOW_COPY_AND_ASSIGN(ConditionUrl);
+
+  UrlQualifiers _url_qual;
+  bool _client;
+};
+
+
+// DBM lookups
+class ConditionDBM : public Condition
+{
+public:
+  ConditionDBM()
+    : 
+    //_dbm(NULL),
+      _file("")
+  {
+    _mutex = TSMutexCreate();
+    TSDebug(PLUGIN_NAME_DBG, "Calling CTOR for ConditionDBM");
+  }
+
+  ~ConditionDBM() {
+    // if (_dbm) {
+    //   mdbm_close(_dbm);
+    //   _dbm = NULL;
+    // }
+  }
+
+  void initialize(Parser& p);
+  void append_value(std::string& s, const Resources& res);
+
+protected:
+  bool eval(const Resources& res);
+
+private:
+  DISALLOW_COPY_AND_ASSIGN(ConditionDBM);
+
+  //MDBM* _dbm;
+  std::string _file;
+  Value _key;
+  TSMutex _mutex;
+};
+
+#endif // __CONDITIONS_H

http://git-wip-us.apache.org/repos/asf/trafficserver-plugins/blob/e1f38ceb/header_rewrite/factory.cc
----------------------------------------------------------------------
diff --git a/header_rewrite/factory.cc b/header_rewrite/factory.cc
new file mode 100644
index 0000000..0a89728
--- /dev/null
+++ b/header_rewrite/factory.cc
@@ -0,0 +1,95 @@
+//////////////////////////////////////////////////////////////////////////////////////////////
+// factory.cc: Factory functions for operators, conditions and condition variables.
+//
+//
+#define UNUSED __attribute__ ((unused))
+static char UNUSED rcsId__factory_cc[] = "@(#) $Id$ built on " __DATE__ " " __TIME__;
+
+#include <string>
+
+#include "operators.h"
+#include "conditions.h"
+
+
+///////////////////////////////////////////////////////////////////////////////
+// "Factory" functions, processing the parsed lines
+//
+Operator*
+operator_factory(const std::string& op)
+{
+  Operator* o = NULL;
+
+  if (op == "rm-header") {
+    o = new OperatorRMHeader();
+  } else if (op == "add-header") {
+    o = new OperatorAddHeader();
+  } else if (op == "set-status") {
+    o = new OperatorSetStatus();
+  } else if (op == "set-status-reason") {
+    o = new OperatorSetStatusReason();
+  } else if (op == "set-destination") {
+    o = new OperatorSetDestination();
+  } else if (op == "set-redirect") {
+    o = new OperatorSetRedirect();
+  } else if (op == "timeout-out") {
+    o = new OperatorSetTimeoutOut();
+  } else if (op == "no-op") {
+    o = new OperatorNoOp();
+  } else {
+    TSError("header_rewrite: unknown operator in header_rewrite: %s", op.c_str());
+    return NULL;
+  }
+
+  return o;
+}
+
+
+Condition*
+condition_factory(const std::string& cond)
+{
+  Condition* c = NULL;
+  std::string c_name, c_qual;
+  std::string::size_type pos = cond.find_first_of(':');
+
+  if (pos != std::string::npos) {
+    c_name = cond.substr(0, pos);
+    c_qual = cond.substr(pos + 1);
+  } else {
+    c_name = cond;
+    c_qual = "";
+  }
+
+  if (c_name == "TRUE") {
+    c = new ConditionTrue();
+  } else if (c_name == "FALSE") {
+    c = new ConditionFalse();
+  } else if (c_name == "STATUS") {
+    c = new ConditionStatus();
+  } else if (c_name == "RANDOM") {
+    c = new ConditionRandom();
+  } else if (c_name == "ACCESS") {
+    c = new ConditionAccess();
+  } else if (c_name == "HEADER") { // This condition adapts to the hook
+    c = new ConditionHeader();
+  }else if (c_name == "PATH"){
+      c= new ConditionPath();
+  } else if (c_name == "CLIENT-HEADER") {
+    c = new ConditionHeader(true);
+ } else if (c_name == "QUERY") {
+     c = new ConditionQuery();
+ } else if (c_name == "URL") { // This condition adapts to the hook
+    c = new ConditionUrl();
+  } else if (c_name == "CLIENT-URL") {
+    c = new ConditionUrl(true);
+  } else if (c_name == "DBM") {
+    c = new ConditionDBM();
+  } else {
+    TSError("header_rewrite: unknown condition in header_rewrite: %s",c_name.c_str());
+    return NULL;
+  }
+
+  if (c_qual != "")
+    c->set_qualifier(c_qual);
+
+  return c;
+}

http://git-wip-us.apache.org/repos/asf/trafficserver-plugins/blob/e1f38ceb/header_rewrite/factory.h
----------------------------------------------------------------------
diff --git a/header_rewrite/factory.h b/header_rewrite/factory.h
new file mode 100644
index 0000000..3301ce3
--- /dev/null
+++ b/header_rewrite/factory.h
@@ -0,0 +1,20 @@
+//////////////////////////////////////////////////////////////////////////////////////////////
+// 
+// Implement the classes for the various types of hash keys we support.
+//
+#ifndef __FACTORY_H__
+#define __FACTORY_H__ 1
+
+#define UNUSED __attribute__ ((unused))
+static char UNUSED rcsId__factory_h[] = "@(#) $Id$ built on " __DATE__ " " __TIME__;
+
+#include <string>
+
+#include "operator.h"
+#include "condition.h"
+
+Operator* operator_factory(const std::string& op);
+Condition* condition_factory(const std::string& cond);
+
+
+#endif

http://git-wip-us.apache.org/repos/asf/trafficserver-plugins/blob/e1f38ceb/header_rewrite/header_rewrite.cc
----------------------------------------------------------------------
diff --git a/header_rewrite/header_rewrite.cc b/header_rewrite/header_rewrite.cc
new file mode 100644
index 0000000..aba03ef
--- /dev/null
+++ b/header_rewrite/header_rewrite.cc
@@ -0,0 +1,331 @@
+//////////////////////////////////////////////////////////////////////////////////////////////
+// header_rewrite: YTS plugin to do header rewrites
+// --------------
+//
+//
+#define UNUSED __attribute__ ((unused))
+static char UNUSED rcsId__header_rewrite_cc[] = "@(#) $Id$ built on " __DATE__ " " __TIME__;
+
+#include <fstream>
+#include <string>
+#include <boost/algorithm/string.hpp>
+
+#include <ts/ts.h>
+#include <ts/remap.h>
+
+#include "parser.h"
+#include "ruleset.h"
+#include "resources.h"
+
+// "Defines"
+static const char* DEFAULT_CONF_PATH = "/usr/local/etc/header_rewrite/";
+
+
+// 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];
+
+// Helper function to add a rule to the rulesets
+static bool
+add_rule(RuleSet* rule) {
+  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;
+    } else {
+      all_rules[rule->get_hook()]->append(rule);
+    }
+    return true;
+  }
+
+  return false;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Simple "config" parser, this modifies the global above. ToDo: What happens
+// on a "config" reload?
+//
+// 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)
+{
+  RuleSet* rule = NULL;
+  std::string filename = fname;
+  std::ifstream f;
+  int lineno = 0;
+
+  // Try appending the default conf path if the fname doesn't exist.
+  if (0 != access(filename.c_str(), R_OK)) {
+    filename = DEFAULT_CONF_PATH;
+    filename += fname;
+  }
+
+  f.open(filename.c_str(), std::ios::in);
+  if (!f.is_open()) {
+    TSError("header_rewrite: unable to open %s", filename.c_str());
+    return false;
+  }
+
+  TSDebug(PLUGIN_NAME, "Loading header_rewrite config from %s", filename.c_str());
+
+  while (!f.eof()) {
+    std::string line;
+
+    getline(f, line);
+    ++lineno; // ToDo: we should probably use this for error messages ...
+
+    boost::trim(line);
+    if (line.empty() || (line[0] == '#'))
+      continue;
+
+    Parser p(line);  // Tokenize and parse this line
+    if (p.empty())
+      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))
+      rule = NULL;
+
+    if (NULL == rule) {
+      rule = new RuleSet();
+      rule->set_hook(default_hook);
+
+      // Special case for specifying the HOOK this rule applies to.
+      // These can only be at the beginning of a rule, and have an implicit [AND].
+      if (p.cond_op_is("READ_RESPONSE_HDR_HOOK")) {
+        rule->set_hook(TS_HTTP_READ_RESPONSE_HDR_HOOK);
+        continue;
+      } else if (p.cond_op_is("READ_REQUEST_HDR_HOOK")) {
+        rule->set_hook(TS_HTTP_READ_REQUEST_HDR_HOOK);
+        continue;
+      } else if (p.cond_op_is("READ_REQUEST_PRE_REMAP_HOOK")) {
+        rule->set_hook(TS_HTTP_READ_REQUEST_PRE_REMAP_HOOK);
+        continue;
+      } else if (p.cond_op_is("SEND_REQUEST_HDR_HOOK")) {
+        rule->set_hook(TS_HTTP_SEND_REQUEST_HDR_HOOK);
+        continue;
+      } else if (p.cond_op_is("SEND_RESPONSE_HDR_HOOK")) {
+        rule->set_hook(TS_HTTP_SEND_RESPONSE_HDR_HOOK);
+        continue;
+      }
+    }
+
+    if (p.is_cond()) {
+      rule->add_condition(p);
+    } else {
+      rule->add_operator(p);
+    }
+  }
+
+  // Add the last rule (possibly the only rule)
+  add_rule(rule);
+
+  // 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();
+
+  return true;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Continuation
+//
+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;
+  TSHttpHookID hook = TS_HTTP_LAST_HOOK;
+
+  // Get the resources necessary to process this event
+  switch (event) {
+  case TS_EVENT_HTTP_READ_RESPONSE_HDR:
+    hook = TS_HTTP_READ_RESPONSE_HDR_HOOK;
+    break;
+  case TS_EVENT_HTTP_READ_REQUEST_HDR:
+    hook = TS_HTTP_READ_REQUEST_HDR_HOOK;
+    break;
+  case TS_EVENT_HTTP_READ_REQUEST_PRE_REMAP:
+    hook = TS_HTTP_READ_REQUEST_PRE_REMAP_HOOK;
+    break;
+  case TS_EVENT_HTTP_SEND_REQUEST_HDR:
+    hook = TS_HTTP_SEND_REQUEST_HDR_HOOK;
+    break;
+  case TS_EVENT_HTTP_SEND_RESPONSE_HDR:
+    hook = TS_HTTP_SEND_RESPONSE_HDR_HOOK;
+    break;
+  default:
+    TSError("header_rewrite: unknown event for this plugin");
+    TSDebug(PLUGIN_NAME, "unknown event for this plugin");
+    break;
+  }
+
+  if (hook != TS_HTTP_LAST_HOOK) {
+    res.gather(all_resids[hook], hook);
+    rule = all_rules[hook];
+
+    // Evaluation
+    while (rule) {
+      if (rule->eval(res)) {
+        OperModifiers rt = rule->exec(res);
+
+        if (rule->last() || (rt & OPER_LAST)) {
+          break; // Conditional break, force a break with [L]
+        }
+      }
+      rule = rule->next;
+    }
+  }
+
+  TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
+  return 0;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Initialize the InkAPI plugin for the global hooks we support.
+//
+void
+TSPluginInit(int argc, const char *argv[])
+{
+  TSPluginRegistrationInfo info;
+
+  info.plugin_name = (char*)PLUGIN_NAME;
+  info.vendor_name = (char*)"";
+  info.support_email = (char*)"";
+
+  if (TS_SUCCESS != TSPluginRegister(TS_SDK_VERSION_3_0 , &info)) {
+    TSError("header_rewrite: plugin registration failed.\n"); 
+  }
+
+  if (argc != 2) {
+    TSError("usage: %s <config-file>\n", argv[0] );
+  }
+
+  // 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 config file
+  if (parse_config(argv[1], TS_HTTP_READ_RESPONSE_HDR_HOOK)) {
+    for (int i=TS_HTTP_READ_REQUEST_HDR_HOOK; i<TS_HTTP_LAST_HOOK; ++i) {
+      if (all_rules[i]) {
+        TSDebug(PLUGIN_NAME, "adding hook: %d", i);
+        TSHttpHookAdd(static_cast<TSHttpHookID>(i), TSContCreate(cont_rewrite_headers, NULL));
+      }
+    }
+  } else {
+    TSError("header_rewrite: failed to parse configuration file");
+  }
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Initialize the plugin as a remap plugin.
+//
+TSReturnCode
+TSRemapInit(TSRemapInterface *api_info, char *errbuf, int errbuf_size)
+{
+  if (!api_info) {
+    strncpy(errbuf, "[TSRemapInit] - Invalid TSRemapInterface argument", errbuf_size - 1);
+    return TS_ERROR;
+  }
+
+  if (api_info->size < sizeof(TSRemapInterface)) {
+    strncpy(errbuf, "[TSRemapInit] - Incorrect size of TSRemapInterface structure", errbuf_size - 1);
+    return TS_ERROR;
+  }
+
+  if (api_info->tsremap_version < TSREMAP_VERSION) {
+    snprintf(errbuf, errbuf_size - 1, "[TSRemapInit] - Incorrect API version %ld.%ld",
+             api_info->tsremap_version >> 16, (api_info->tsremap_version & 0xffff));
+    return TS_ERROR;
+  }
+
+  TSDebug(PLUGIN_NAME, "remap plugin is succesfully initialized");
+  return TS_SUCCESS;
+}
+
+
+TSReturnCode
+TSRemapNewInstance(int argc, char *argv[], void **ih, char *errbuf, int errbuf_size)
+{
+  TSDebug(PLUGIN_NAME, "initializing the remap plugin header_rewrite");
+
+  if (argc < 3) {
+    TSError("Unable to create remap instance, need config file");
+    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("Unable to create remap instance");
+    return TS_ERROR;
+  }
+
+  *ih = all_rules[TS_REMAP_PSEUDO_HOOK];
+  all_rules[TS_REMAP_PSEUDO_HOOK] = NULL;
+
+  TSDebug(PLUGIN_NAME, "successfully initialize the header_rewrite plugin");
+  return TS_SUCCESS;
+}
+
+void
+TSRemapDeleteInstance(void *ih)
+{
+  RuleSet* rule = static_cast<RuleSet*>(ih);
+
+  delete rule;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// This is the main "entry" point for the plugin, called for every request.
+//
+TSRemapStatus
+TSRemapDoRemap(void *ih, TSHttpTxn rh, TSRemapRequestInfo *rri)
+{
+  TSRemapStatus rval = TSREMAP_NO_REMAP;
+
+  if (NULL == ih) {
+    TSDebug(PLUGIN_NAME, "No Rules configured, falling back to default");
+    return rval;
+  } else {
+    RuleSet* rule = (RuleSet*)ih;
+    Resources res((TSHttpTxn)rh, rri);
+
+    // TODO: This might be suboptimal, do we always need the client request
+    // headers in a remap plugin?
+    res.gather(RSRC_CLIENT_REQUEST_HEADERS, TS_REMAP_PSEUDO_HOOK);
+
+    // Evaluation
+    while (rule) {
+      if (rule->eval(res)) {
+        OperModifiers rt = rule->exec(res);
+        if (res.changed_url == true)
+          rval = TSREMAP_DID_REMAP;
+
+        if (rule->last() || (rt & OPER_LAST)) {
+          break; // Conditional break, force a break with [L]
+        }
+      }
+      rule = rule->next;
+    }
+
+  }
+
+  return rval;
+}
+

http://git-wip-us.apache.org/repos/asf/trafficserver-plugins/blob/e1f38ceb/header_rewrite/header_rewrite.config
----------------------------------------------------------------------
diff --git a/header_rewrite/header_rewrite.config b/header_rewrite/header_rewrite.config
new file mode 100644
index 0000000..8be269a
--- /dev/null
+++ b/header_rewrite/header_rewrite.config
@@ -0,0 +1,77 @@
+Operators
+---------
+rm-header Header matcher
+add-header Header value
+set-header Header value
+
+set-status value
+set-status-reason value
+
+
+Conditions
+-----------
+%{TRUE}  # Default condition if none specified
+%{FALSE}
+%{HEADER:string}
+%{YCOOKIE:id}
+%{METHOD}
+%{PROTOCOL}
+%{PORT}
+%{HOST}
+%{TOHOST}
+%{FROMHOST}
+%{PATH}
+%{PARAMS}
+%{QUERY}
+%{STATUS}
+
+# These can only be used as the first condition of a new ruleset,
+# and have no run-time evaluation effects (only config parse time).
+%{READ_RESPONSE_HDR_HOOK} # Default
+%{READ_REQUEST_HDR_HOOK}
+
+
+Operator Flags
+--------------
+L    # Last rule (stop evaluations)
+
+
+Cond Flags
+----------
+NC   # Not case sensitive condition (when applicable)
+NOT  # Negate the cond
+OR   # Local OR between conds
+AND  # Logical AND betwen conds
+
+
+Matcher
+--------
+
+/string/  # regular expression
+<string   # lexically lower
+>string   # lexically greater
+=string   # lexically equal
+
+(The absense of a "matcher" means value exists).
+
+
+Values
+------
+
+Any of the cond definitions, that extracts a value from the request
+$N 0 <= N <= 9, as grouped in a regular expression
+string (which can contain the above)
+null
+
+
+Examples
+--------
+
+cond %{HEADER:X-Y-Foobar}
+cond %{METHOD} =GET [OR]
+cond %{METHOD} =POST
+set-header X-Y-Fiefum %{HEADER:X-Y-Foobar}
+rm-header X-Y-Foobar
+rm-header Set-Cookie
+
+cond %{HEADER:X-Y-Foobar} "Some string" [AND,NC]

http://git-wip-us.apache.org/repos/asf/trafficserver-plugins/blob/e1f38ceb/header_rewrite/lulu.h
----------------------------------------------------------------------
diff --git a/header_rewrite/lulu.h b/header_rewrite/lulu.h
new file mode 100644
index 0000000..7452e49
--- /dev/null
+++ b/header_rewrite/lulu.h
@@ -0,0 +1,42 @@
+//////////////////////////////////////////////////////////////////////////////////////////////
+// 
+// Implement the classes for the various types of hash keys we support.
+//
+#ifndef __LULU_H__
+#define __LULU_H__ 1
+
+// Define UNUSED properly.
+#if ((__GNUC__ >= 3) || ((__GNUC__ == 2) && (__GNUC_MINOR__ >= 7)))
+#define UNUSED __attribute__ ((unused))
+#else
+#define UNUSED
+#endif /* #if ((__GNUC__ >= 3) || ((__GNUC__ == 2) && (__GNUC_MINOR__ >= 7))) */
+
+static char UNUSED rcsId__lulu_h[] = "@(#) $Id$ built on " __DATE__ " " __TIME__;
+
+#include <sys/types.h>
+
+// Memory barriers on i386 / linux / gcc
+#if defined(__i386__)
+#define mb()  __asm__ __volatile__ ( "lock; addl $0,0(%%esp)" : : : "memory" )
+#define rmb() __asm__ __volatile__ ( "lock; addl $0,0(%%esp)" : : : "memory" )
+#define wmb() __asm__ __volatile__ ( "" : : : "memory")
+#elif defined(__x86_64__)
+#define mb()  __asm__ __volatile__ ( "mfence" : : : "memory")
+#define rmb() __asm__ __volatile__ ( "lfence" : : : "memory")
+#define wmb() __asm__ __volatile__ ( "" : : : "memory")
+#else
+#error "Define barriers"
+#endif
+
+static const char* PLUGIN_NAME UNUSED = "header_rewrite";
+static const char* PLUGIN_NAME_DBG UNUSED = "header_rewrite_dbg";
+
+
+// From google styleguide: http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml
+#define DISALLOW_COPY_AND_ASSIGN(TypeName)      \
+  TypeName(const TypeName&);                    \
+  void operator=(const TypeName&)
+
+
+#endif // __LULU_H__

http://git-wip-us.apache.org/repos/asf/trafficserver-plugins/blob/e1f38ceb/header_rewrite/matcher.cc
----------------------------------------------------------------------
diff --git a/header_rewrite/matcher.cc b/header_rewrite/matcher.cc
new file mode 100644
index 0000000..b520ab7
--- /dev/null
+++ b/header_rewrite/matcher.cc
@@ -0,0 +1,12 @@
+//////////////////////////////////////////////////////////////////////////////////////////////
+// matcher.cc: Implementation of the condition classes
+//
+//
+
+#define UNUSED __attribute__ ((unused))
+static char UNUSED rcsId__matcher_cc[] = "@(#) $Id$ built on " __DATE__ " " __TIME__;
+
+#include <string>
+#include <ts/ts.h>
+
+#include "matcher.h"

http://git-wip-us.apache.org/repos/asf/trafficserver-plugins/blob/e1f38ceb/header_rewrite/matcher.h
----------------------------------------------------------------------
diff --git a/header_rewrite/matcher.h b/header_rewrite/matcher.h
new file mode 100644
index 0000000..3676a52
--- /dev/null
+++ b/header_rewrite/matcher.h
@@ -0,0 +1,159 @@
+//////////////////////////////////////////////////////////////////////////////////////////////
+// 
+// Implement the classes for the various types of hash keys we support.
+//
+#ifndef __MATCHER_H__
+#define __MATCHER_H__ 1
+
+
+#define UNUSED __attribute__ ((unused))
+static char UNUSED rcsId__matcher_h[] = "@(#) $Id$ built on " __DATE__ " " __TIME__;
+
+#include <string>
+#include <ts/ts.h>
+#include "regex_helper.h"
+#include <iostream> // For debugging
+
+#include "lulu.h"
+
+
+// Possible operators that we support (at least partially)
+enum MatcherOps {
+  MATCH_EQUAL,
+  MATCH_LESS_THEN,
+  MATCH_GREATER_THEN,
+  MATCH_REGULAR_EXPRESSION
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Base class for all Matchers (this is also the interface)
+//
+class Matcher
+{
+public:
+  explicit Matcher(const MatcherOps op)
+    : _pdata(NULL), _op(op)
+  {
+    TSDebug(PLUGIN_NAME_DBG, "Calling CTOR for Matcher");
+  }
+
+  virtual ~Matcher() {
+    TSDebug(PLUGIN_NAME_DBG, "Calling DTOR for Matcher");
+    free_pdata();
+  }
+
+  void set_pdata(void* pdata) { _pdata = pdata; }
+  void* get_pdata() const { return _pdata; }
+  virtual void free_pdata() { TSfree(_pdata); _pdata = NULL; }
+
+protected:
+  void* _pdata;
+  const MatcherOps _op;
+
+private:
+  DISALLOW_COPY_AND_ASSIGN(Matcher);
+};
+
+// Template class to match on various types of data
+template<class T>
+class Matchers : public Matcher
+{
+public:
+  explicit Matchers<T>(const MatcherOps op)
+    : Matcher(op)
+  { }
+
+  // Getters / setters
+  const T get() const { return _data; };
+ 
+ void setRegex(const std::string data)
+ {
+     if(!helper.setRegexMatch(_data))
+     {
+         std::cout<<"Invalid regex:failed to precompile"<<std::endl;
+         abort();
+     }
+     TSDebug(PLUGIN_NAME,"Regex precompiled successfully");
+
+ }
+
+ void setRegex(const unsigned int t)
+ {
+     return;
+ }
+
+ void setRegex(const TSHttpStatus t)
+ {
+     return;
+ }
+
+  void set (const T d)
+  { 
+      _data = d;
+      if(_op == MATCH_REGULAR_EXPRESSION)
+        setRegex(d);
+  }
+
+  // Evaluate this matcher
+  bool
+  test(const T t) const {
+    switch (_op) {
+    case MATCH_EQUAL:
+      return test_eq(t);
+      break;
+    case MATCH_LESS_THEN:
+      return test_lt(t);
+      break;
+    case MATCH_GREATER_THEN:
+      return test_gt(t);
+      break;
+    case MATCH_REGULAR_EXPRESSION:
+      return test_reg(t);
+      break;
+    default:
+      // ToDo: error
+      break;
+    }
+    return false;
+  }
+
+private:
+  // For basic types
+  bool test_eq(const T t) const {
+    // std::cout << "Testing: " << t << " == " << _data << std::endl;
+    return t == _data;
+  }
+  bool test_lt(const T t) const {
+    // std::cout << "Testing: " << t << " < " << _data << std::endl;
+    return t < _data;
+  }
+  bool test_gt(const T t) const {
+    // std::cout << "Testing: " << t << " > " << _data << std::endl;
+    return t > _data;
+  }
+
+ bool test_reg(const unsigned int t) const {
+    // Not support
+    return false;
+  }
+
+  bool test_reg(const TSHttpStatus t) const {
+    // Not support
+    return false;
+  }
+  
+  bool test_reg(const std::string t) const {
+      TSDebug(PLUGIN_NAME, "Test regular expression %s : %s", _data.c_str(), t.c_str());
+          int ovector[OVECCOUNT];
+          if (helper.regexMatch(t.c_str(), t.length(), ovector) > 0) {
+              TSDebug(PLUGIN_NAME, "Successfully found regular expression match");
+              return true;
+    }
+      return false;
+  }
+  T _data;
+  regexHelper helper;
+};
+
+#endif // __MATCHER_H

http://git-wip-us.apache.org/repos/asf/trafficserver-plugins/blob/e1f38ceb/header_rewrite/operator.cc
----------------------------------------------------------------------
diff --git a/header_rewrite/operator.cc b/header_rewrite/operator.cc
new file mode 100644
index 0000000..d68cab3
--- /dev/null
+++ b/header_rewrite/operator.cc
@@ -0,0 +1,32 @@
+//////////////////////////////////////////////////////////////////////////////////////////////
+// operator.cc: Implementation of the operator base class
+//
+//
+
+#define UNUSED __attribute__ ((unused))
+static char UNUSED rcsId__operator_cc[] = "@(#) $Id$ built on " __DATE__ " " __TIME__;
+
+#include <ts/ts.h>
+#include "operator.h"
+
+const OperModifiers
+Operator::get_oper_modifiers() const {
+  if (_next)
+    return static_cast<OperModifiers>(_mods | static_cast<Operator*>(_next)->get_oper_modifiers());
+
+  return _mods;
+}
+
+void
+Operator::initialize(Parser& p) {
+  Statement::initialize(p);
+
+  if (p.mod_exist("L")) {
+    _mods = static_cast<OperModifiers>(_mods | OPER_LAST);
+  }
+
+  if (p.mod_exist("QSA")) {
+    _mods = static_cast<OperModifiers>(_mods | OPER_QSA);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/trafficserver-plugins/blob/e1f38ceb/header_rewrite/operator.h
----------------------------------------------------------------------
diff --git a/header_rewrite/operator.h b/header_rewrite/operator.h
new file mode 100644
index 0000000..4323f15
--- /dev/null
+++ b/header_rewrite/operator.h
@@ -0,0 +1,59 @@
+//////////////////////////////////////////////////////////////////////////////////////////////
+// Public interface for creating all operators. Don't user the operator.h interface
+// directly!
+//
+#ifndef __OPERATOR_H__
+#define __OPERATOR_H__ 1
+
+#define UNUSED __attribute__ ((unused))
+static char UNUSED rcsId__operator_h[] = "@(#) $Id$ built on " __DATE__ " " __TIME__;
+
+#include <string>
+#include <ts/ts.h>
+
+#include "resources.h"
+#include "statement.h"
+#include "parser.h"
+
+
+// Operator modifiers
+enum OperModifiers {
+  OPER_NONE = 0,
+  OPER_LAST = 1,
+  OPER_NEXT = 2,
+  OPER_QSA=4
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Base class for all Operators (this is also the interface)
+//
+class Operator : public Statement
+{
+public:
+  Operator()
+    : _mods(OPER_NONE)
+  {
+    TSDebug(PLUGIN_NAME_DBG, "Calling CTOR for Operator");
+  }
+
+  void do_exec(const Resources& res) const {
+    exec(res);
+    if (NULL != _next)
+      static_cast<Operator*>(_next)->do_exec(res);
+  }
+
+  const OperModifiers get_oper_modifiers() const;
+
+  virtual void initialize(Parser& p);
+
+protected:
+  virtual void exec(const Resources& res) const = 0;
+
+private:
+  DISALLOW_COPY_AND_ASSIGN(Operator);
+
+  OperModifiers _mods;
+};
+
+#endif // __OPERATOR_H

http://git-wip-us.apache.org/repos/asf/trafficserver-plugins/blob/e1f38ceb/header_rewrite/operators.cc
----------------------------------------------------------------------
diff --git a/header_rewrite/operators.cc b/header_rewrite/operators.cc
new file mode 100644
index 0000000..c5db93a
--- /dev/null
+++ b/header_rewrite/operators.cc
@@ -0,0 +1,366 @@
+//////////////////////////////////////////////////////////////////////////////////////////////
+// operators.cc: implementation of the operator classes
+//
+//
+
+#define UNUSED __attribute__ ((unused))
+static char UNUSED rcsId__operators_cc[] = "@(#) $Id$ built on " __DATE__ " " __TIME__;
+
+#include <arpa/inet.h>
+#include <ts/ts.h>
+#include <string.h>
+
+#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) {
+  Operator::initialize(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());
+    _reason_len = 0;
+  } else {
+    _reason_len = strlen(_reason);
+  }
+
+  require_resources(RSRC_SERVER_RESPONSE_HEADERS);
+  require_resources(RSRC_CLIENT_RESPONSE_HEADERS);
+  require_resources(RSRC_RESPONSE_STATUS);
+}
+
+
+void
+OperatorSetStatus::initialize_hooks() {
+  add_allowed_hook(TS_HTTP_READ_RESPONSE_HDR_HOOK);
+  add_allowed_hook(TS_HTTP_SEND_RESPONSE_HDR_HOOK);
+}
+
+
+void
+OperatorSetStatus::exec(const Resources& res) const
+{
+  if (res.bufp && res.hdr_loc) {
+    TSHttpHdrStatusSet(res.bufp, res.hdr_loc, (TSHttpStatus)_status.get_int_value());
+    if (_reason && _reason_len > 0)
+      TSHttpHdrReasonSet(res.bufp, res.hdr_loc, _reason, _reason_len);
+  }
+}
+
+
+// OperatorSetStatusReason
+void
+OperatorSetStatusReason::initialize(Parser& p) {
+  Operator::initialize(p);
+
+  _reason.set_value(p.get_arg());
+  require_resources(RSRC_CLIENT_RESPONSE_HEADERS);
+  require_resources(RSRC_SERVER_RESPONSE_HEADERS);
+}
+
+
+void
+OperatorSetStatusReason::initialize_hooks() {
+  add_allowed_hook(TS_HTTP_READ_RESPONSE_HDR_HOOK);
+  add_allowed_hook(TS_HTTP_SEND_RESPONSE_HDR_HOOK);
+}
+
+void
+OperatorSetStatusReason::exec(const Resources& res) const {
+  if (res.bufp && res.hdr_loc) {
+    std::string reason;
+
+    _reason.append_value(reason, res);
+    if (reason.size() > 0) {
+      TSDebug(PLUGIN_NAME, "Setting Status Reason to %s", reason.c_str());
+      TSHttpHdrReasonSet(res.bufp, res.hdr_loc, reason.c_str(), reason.size());
+    }
+  }
+}
+
+
+// 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) {
+  Operator::initialize(p);
+
+  _url_qual = parse_url_qualifier(p.get_arg());
+  _value.set_value(p.get_value());
+  // TODO: What resources would we require here?
+}
+
+
+void
+OperatorSetDestination::exec(const Resources& res) const
+{
+  if (res._rri) {
+    std::string value;
+
+    // Never set an empty destination value (I don't think that ever makes sense?)
+    switch (_url_qual) {
+
+    case URL_QUAL_HOST:
+      _value.append_value(value, res);
+      if (value.empty()) {
+        TSDebug(PLUGIN_NAME, "Would set destination HOST to an empty value, skipping");
+      } else {
+        const_cast<Resources&>(res).changed_url = true;
+        TSUrlHostSet(res._rri->requestBufp, res._rri->requestUrl, value.c_str(), value.size());
+        TSDebug(PLUGIN_NAME, "OperatorSetHost::exec() invoked with HOST: %s", value.c_str());
+      }
+      break;
+
+    case URL_QUAL_PATH:
+      _value.append_value(value, res);
+      if (value.empty()) {
+        TSDebug(PLUGIN_NAME, "Would set destination PATH to an empty value, skipping");
+      } else {
+        const_cast<Resources&>(res).changed_url = true;
+        TSUrlHostSet(res._rri->requestBufp, res._rri->requestUrl, value.c_str(), value.size());
+        TSDebug(PLUGIN_NAME, "OperatorSetHost::exec() invoked with PATH: %s", value.c_str());
+      }
+      break;
+
+    case URL_QUAL_QUERY:
+      _value.append_value(value, res);
+      if (value.empty()) {
+        TSDebug(PLUGIN_NAME, "Would set destination QUERY to an empty value, skipping");
+      } else {
+        //1.6.4--Support for preserving QSA in case of set-destination
+        if (get_oper_modifiers() & OPER_QSA) {
+          int query_len = 0;
+          const char* query = TSUrlHttpQueryGet(res._rri->requestBufp, res._rri->requestUrl, &query_len);
+          TSDebug(PLUGIN_NAME, "QSA mode, append original query string: %.*s", query_len, query);
+          //std::string connector = (value.find("?") == std::string::npos)? "?" : "&";
+          value.append("&");
+          value.append(query, query_len);
+        }
+
+        const_cast<Resources&>(res).changed_url = true;
+        TSUrlHttpQuerySet(res._rri->requestBufp, res._rri->requestUrl, value.c_str(), value.size());
+        TSDebug(PLUGIN_NAME, "OperatorSetHost::exec() invoked with QUERY: %s", value.c_str());
+      }
+      break;
+
+    case URL_QUAL_PORT:
+      if (_value.get_int_value() <= 0) {
+        TSDebug(PLUGIN_NAME, "Would set destination PORT to an invalid range, skipping");
+      } else {
+        const_cast<Resources&>(res).changed_url = true;
+        TSUrlPortSet(res._rri->requestBufp, res._rri->requestUrl, _value.get_int_value());
+        TSDebug(PLUGIN_NAME, "OperatorSetHost::exec() invoked with PORT: %d", _value.get_int_value());
+      }
+      break;
+    case URL_QUAL_URL:
+      // TODO: Implement URL parser.
+      break;
+    default:
+      break;
+    }
+  } else {
+    // TODO: Handle the non-remap case here (InkAPI hooks)
+  }
+}
+
+
+/// TODO and XXX: These currently only support when running as remap plugin.
+// OperatorSetRedirect
+void
+OperatorSetRedirect::initialize(Parser& p) {
+  Operator::initialize(p);
+
+  _status.set_value(p.get_arg());
+  _location.set_value(p.get_value());
+
+  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());
+  }
+
+  require_resources(RSRC_SERVER_RESPONSE_HEADERS);
+  require_resources(RSRC_CLIENT_RESPONSE_HEADERS);
+  require_resources(RSRC_RESPONSE_STATUS);
+}
+
+
+void
+OperatorSetRedirect::exec(const Resources& res) const
+{
+  if (res._rri) {
+    if (res.bufp && res.hdr_loc) {
+      std::string value;
+
+      _location.append_value(value, res);
+         
+      // Replace %{PATH} to original path
+      size_t pos_path = 0;
+      
+      if ((pos_path = value.find("%{PATH}")) != std::string::npos) {
+          value.erase(pos_path, 7); // erase %{PATH} from the rewritten to url
+          int path_len = 0;
+          const char *path = TSUrlPathGet(res._rri->requestBufp, res._rri->requestUrl, &path_len);
+          if (path_len > 0) {
+            TSDebug(PLUGIN_NAME, "Find %%{PATH} in redirect url, replace it with: %.*s", path_len, path);
+            value.insert(pos_path, path, path_len);
+          }
+      }
+       
+      // Append the original query string
+      int query_len = 0;
+      const char *query = TSUrlHttpQueryGet(res._rri->requestBufp, res._rri->requestUrl, &query_len);
+      if ((get_oper_modifiers() & OPER_QSA) && (query_len > 0)) {
+          TSDebug(PLUGIN_NAME, "QSA mode, append original query string: %.*s", query_len, query);
+          std::string connector = (value.find("?") == std::string::npos)? "?" : "&";
+          value.append(connector);
+          value.append(query, query_len);
+      }
+
+      TSHttpTxnSetHttpRetStatus(res.txnp,(TSHttpStatus)_status.get_int_value());
+      //TSHttpHdrStatusSet(res.bufp, res.hdr_loc, (TSHttpStatus)_status.get_int_value());
+      const char *start = value.c_str();
+      const char *end = value.size() + start;
+      TSUrlParse(res._rri->requestBufp, res._rri->requestUrl, &start, end);
+      TSDebug(PLUGIN_NAME, "OperatorSetRedirect::exec() invoked with destination=%s and status code=%d", 
+              value.c_str(), _status.get_int_value());
+    }
+    
+  } else {
+    // TODO: Handle the non-remap case here (InkAPI hooks)
+  }
+}
+
+
+// OperatorSetTimeoutOut
+void
+OperatorSetTimeoutOut::initialize(Parser& p) {
+  Operator::initialize(p);
+
+  if (p.get_arg() == "active") {
+    _type = TO_OUT_ACTIVE;
+  } else if (p.get_arg() == "inactive") {
+    _type = TO_OUT_INACTIVE;
+  } else if (p.get_arg() == "connect") {
+    _type = TO_OUT_CONNECT;
+  } else if (p.get_arg() == "dns") {
+    _type = TO_OUT_DNS;
+  } else {
+    _type = TO_OUT_UNDEFINED;
+    TSError("header_rewrite: unsupported timeout qualifier: %s", p.get_arg().c_str());
+  }
+
+  _timeout.set_value(p.get_value());
+}
+
+
+void
+OperatorSetTimeoutOut::exec(const Resources& res) const
+{
+  switch (_type) {
+  case TO_OUT_ACTIVE:
+    TSDebug(PLUGIN_NAME, "OperatorSetTimeoutOut::exec(active, %d)", _timeout.get_int_value());
+    TSHttpTxnActiveTimeoutSet(res.txnp, _timeout.get_int_value());
+    break;
+
+  case TO_OUT_INACTIVE:
+    TSDebug(PLUGIN_NAME, "OperatorSetTimeoutOut::exec(inactive, %d)", _timeout.get_int_value());
+    TSHttpTxnNoActivityTimeoutSet(res.txnp, _timeout.get_int_value());
+    break;
+
+  case TO_OUT_CONNECT:
+    TSDebug(PLUGIN_NAME, "OperatorSetTimeoutOut::exec(connect, %d)", _timeout.get_int_value());
+    TSHttpTxnConnectTimeoutSet(res.txnp, _timeout.get_int_value());
+    break;
+
+  case TO_OUT_DNS:
+    TSDebug(PLUGIN_NAME, "OperatorSetTimeoutOut::exec(dns, %d)", _timeout.get_int_value());
+    TSHttpTxnDNSTimeoutSet(res.txnp, _timeout.get_int_value());
+    break;
+  default:
+    TSError("header_rewrite: unsupported timeout");
+    break;
+  }
+}
+

http://git-wip-us.apache.org/repos/asf/trafficserver-plugins/blob/e1f38ceb/header_rewrite/operators.h
----------------------------------------------------------------------
diff --git a/header_rewrite/operators.h b/header_rewrite/operators.h
new file mode 100644
index 0000000..f85112c
--- /dev/null
+++ b/header_rewrite/operators.h
@@ -0,0 +1,192 @@
+//////////////////////////////////////////////////////////////////////////////////////////////
+// 
+// Implement the classes for the various types of hash keys we support.
+//
+#ifndef __OPERATORS_H__
+#define __OPERATORS_H__ 1
+
+#define UNUSED __attribute__ ((unused))
+static char UNUSED rcsId__operators_h[] = "@(#) $Id$ built on " __DATE__ " " __TIME__;
+
+#include <string>
+#include <ts/ts.h>
+
+#include "operator.h"
+#include "resources.h"
+#include "value.h"
+
+
+///////////////////////////////////////////////////////////////////////////////
+// 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:
+  OperatorSetStatus()
+    : _reason(NULL), _reason_len(0)
+  {
+    TSDebug(PLUGIN_NAME_DBG, "Calling CTOR for OperatorSetStatus");
+  }
+  void initialize(Parser& p);
+
+protected:
+  void initialize_hooks();
+  void exec(const Resources& res) const;
+
+private:
+  DISALLOW_COPY_AND_ASSIGN(OperatorSetStatus);
+
+  Value _status;
+  const char* _reason;
+  int _reason_len;
+};
+
+
+class OperatorSetStatusReason : public Operator
+{
+public:
+  OperatorSetStatusReason()
+  {
+    TSDebug(PLUGIN_NAME_DBG, "Calling CTOR for OperatorSetStatusReason");
+  }
+  void initialize(Parser& p);
+
+protected:
+  void initialize_hooks();
+  void exec(const Resources& res) const;
+
+private:
+  DISALLOW_COPY_AND_ASSIGN(OperatorSetStatusReason);
+
+  Value _reason;
+};
+
+
+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:
+  OperatorSetDestination()
+    : _url_qual(URL_QUAL_NONE)
+  {
+    TSDebug(PLUGIN_NAME_DBG, "Calling CTOR for OperatorSetDestination");
+  }
+  void initialize(Parser& p);
+
+protected:
+  void exec(const Resources& res) const;
+
+private:
+  DISALLOW_COPY_AND_ASSIGN(OperatorSetDestination);
+
+  UrlQualifiers _url_qual;
+  Value _value;
+};
+
+
+class OperatorSetRedirect : public Operator
+{
+public:
+  OperatorSetRedirect()
+  {
+    TSDebug(PLUGIN_NAME_DBG, "Calling CTOR for OperatorSetRedirect");
+  }
+  void initialize(Parser& p);
+
+protected:
+  void exec(const Resources& res) const;
+
+private:
+  DISALLOW_COPY_AND_ASSIGN(OperatorSetRedirect);
+
+  Value _status;
+  Value _location;
+};
+
+
+class OperatorNoOp : public Operator
+{
+public:
+  OperatorNoOp()
+  {
+    TSDebug(PLUGIN_NAME_DBG, "Calling CTOR for OperatorNoOp");
+  }
+
+protected:
+  void exec(const Resources& res) const { };
+
+private:
+  DISALLOW_COPY_AND_ASSIGN(OperatorNoOp);
+};
+
+
+class OperatorSetTimeoutOut : public Operator
+{
+public:
+  OperatorSetTimeoutOut()
+    : _type(TO_OUT_UNDEFINED)
+  {
+    TSDebug(PLUGIN_NAME_DBG, "Calling CTOR for OperatorSetTimeoutOut");
+  }
+  void initialize(Parser& p);
+
+protected:
+  void exec(const Resources& res) const;
+
+private:
+  DISALLOW_COPY_AND_ASSIGN(OperatorSetTimeoutOut);
+
+  enum TimeoutOutType {
+    TO_OUT_UNDEFINED,
+    TO_OUT_ACTIVE,
+    TO_OUT_INACTIVE,
+    TO_OUT_CONNECT,
+    TO_OUT_DNS
+  };
+
+  TimeoutOutType _type;
+  Value _timeout;
+};
+
+
+#endif // __OPERATORS_H

http://git-wip-us.apache.org/repos/asf/trafficserver-plugins/blob/e1f38ceb/header_rewrite/parser.cc
----------------------------------------------------------------------
diff --git a/header_rewrite/parser.cc b/header_rewrite/parser.cc
new file mode 100644
index 0000000..b0289d6
--- /dev/null
+++ b/header_rewrite/parser.cc
@@ -0,0 +1,107 @@
+//////////////////////////////////////////////////////////////////////////////////////////////
+// parser.cc: implementation of the config parser
+//
+//
+#define UNUSED __attribute__ ((unused))
+static char UNUSED rcsId__parser_cc[] = "@(#) $Id$ built on " __DATE__ " " __TIME__;
+
+#include <utility>
+#include <boost/tokenizer.hpp>
+
+#include <ts/ts.h>
+
+#include "parser.h"
+
+// Tokenizer separators
+static boost::escaped_list_separator<char> token_sep('\\', ' ', '\"');
+static boost::char_separator<char> comma_sep(",");
+
+
+// This is the core "parser", parsing rule sets
+void
+Parser::preprocess(std::vector<std::string>& tokens)
+{
+  // Special case for "conditional" values
+  if (tokens[0].substr(0, 2) == "%{") {
+    _cond = true;
+  } else if (tokens[0] == "cond") {
+    _cond = true;
+    tokens.erase(tokens.begin());
+  }
+
+  // Is it a condition or operator?
+  if (_cond) {
+    if ((tokens[0].substr(0, 2) == "%{") && (tokens[0][tokens[0].size() - 1] == '}')) {
+      std::string s = tokens[0].substr(2, tokens[0].size() - 3);
+
+      _op = s;
+      if (tokens.size() > 1)
+        _arg = tokens[1];
+      else
+        _arg = "";
+    } else {
+      TSError("header_rewrite: conditions must be embraced in %%{}");
+      return;
+    }
+  } else {
+    // Operator has no qualifiers, but could take an optional second argumetn
+    _op = tokens[0];
+    if (tokens.size() > 1) {
+      _arg = tokens[1];
+      if (tokens.size() > 2)
+        _val = tokens[2];
+      else
+        _val = "";
+    } else {
+      _arg = "";
+      _val = "";
+    }
+  }
+
+  // The last token might be the "flags" section
+  if (tokens.size() > 0) {
+    std::string m  = tokens[tokens.size() - 1];
+
+    if (!m.empty() && (m[0] == '[')) {
+      if (m[m.size() - 1] == ']') {
+        m = m.substr(1, m.size() - 2);
+        if (m.find_first_of(',') != std::string::npos) {
+          boost::tokenizer<boost::char_separator<char> > mods(m, comma_sep);
+          std::copy(mods.begin(), mods.end(), std::back_inserter(_mods));
+        } else {
+          _mods.push_back(m);
+        }
+      } else {
+        // Syntax error
+        TSError("header_rewrite: mods have to be embraced in []");
+        return;
+      }
+    }
+  }
+}
+
+
+Parser::Parser(const std::string& line) :
+  _cond(false), _empty(false)
+{
+  TSDebug("header_rewrite_dbg", "Calling CTOR for Parser");
+
+  if (line[0] == '#') {
+    _empty = true;
+  } else {
+    boost::tokenizer<boost::escaped_list_separator<char> > elem(line, token_sep);
+    std::vector<std::string> tokens;
+
+    for (boost::tokenizer<boost::escaped_list_separator<char> >::iterator it = elem.begin(); it != elem.end(); it++) {
+      // Skip "empty" tokens (tokenizer is a little brain dead IMO)
+      if ((*it) != "")
+        tokens.push_back(*it);
+    }
+
+    if (tokens.empty()) {
+      _empty = true;
+    } else {
+      preprocess(tokens);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/trafficserver-plugins/blob/e1f38ceb/header_rewrite/parser.h
----------------------------------------------------------------------
diff --git a/header_rewrite/parser.h b/header_rewrite/parser.h
new file mode 100644
index 0000000..0d0aa46
--- /dev/null
+++ b/header_rewrite/parser.h
@@ -0,0 +1,53 @@
+//////////////////////////////////////////////////////////////////////////////////////////////
+// 
+// Interface for the config line parser
+//
+#ifndef __PARSER_H__
+#define __PARSER_H__ 1
+
+
+#define UNUSED __attribute__ ((unused))
+static char UNUSED rcsId__parser_h[] = "@(#) $Id$ built on " __DATE__ " " __TIME__;
+
+#include <string>
+#include <vector>
+#include <algorithm>
+
+#include "lulu.h"
+
+
+///////////////////////////////////////////////////////////////////////////////
+//
+class Parser
+{
+public:
+  explicit Parser(const std::string& line);
+
+  bool empty() const { return _empty; }
+  bool is_cond() const { return _cond; }
+
+  bool cond_op_is(const std::string s) const { return _cond && (_op == s); }
+  bool oper_op_is(const std::string s) const { return !_cond && (_op == s); }
+
+  const std::string& get_op() const { return _op; }
+  std::string& get_arg() { return _arg; }
+  const std::string& get_value() const { return _val; }
+
+  bool mod_exist(const std::string m) const {
+    return (std::find(_mods.begin(), _mods.end(), m) != _mods.end());
+  }
+
+private:
+  void preprocess(std::vector<std::string>& tokens);
+  DISALLOW_COPY_AND_ASSIGN(Parser);
+
+  bool _cond;
+  bool _empty;
+  std::vector<std::string> _mods;
+  std::string _op;
+  std::string _arg;
+  std::string _val;
+};
+
+
+#endif // __PARSER_H


Mime
View raw message