trafficserver-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From bc...@apache.org
Subject svn commit: r1199388 [1/5] - in /trafficserver/plugins/trunk/esi: ./ fetcher/ lib/ test/ test_helper/
Date Tue, 08 Nov 2011 19:07:22 GMT
Author: bcall
Date: Tue Nov  8 19:07:20 2011
New Revision: 1199388

URL: http://svn.apache.org/viewvc?rev=1199388&view=rev
Log:
ESI plugin for traffic server.  Code came from Yahoo!.

Added:
    trafficserver/plugins/trunk/esi/
    trafficserver/plugins/trunk/esi/LICENSE
    trafficserver/plugins/trunk/esi/README
    trafficserver/plugins/trunk/esi/fetcher/
    trafficserver/plugins/trunk/esi/fetcher/FetchedDataProcessor.h
    trafficserver/plugins/trunk/esi/fetcher/HttpDataFetcher.h
    trafficserver/plugins/trunk/esi/fetcher/HttpDataFetcherImpl.cc
    trafficserver/plugins/trunk/esi/fetcher/HttpDataFetcherImpl.h
    trafficserver/plugins/trunk/esi/handlers.cfg
    trafficserver/plugins/trunk/esi/lib/
    trafficserver/plugins/trunk/esi/lib/Attribute.h
    trafficserver/plugins/trunk/esi/lib/ComponentBase.h
    trafficserver/plugins/trunk/esi/lib/DocNode.cc
    trafficserver/plugins/trunk/esi/lib/DocNode.h
    trafficserver/plugins/trunk/esi/lib/EsiParser.cc
    trafficserver/plugins/trunk/esi/lib/EsiParser.h
    trafficserver/plugins/trunk/esi/lib/EsiProcessor.cc
    trafficserver/plugins/trunk/esi/lib/EsiProcessor.h
    trafficserver/plugins/trunk/esi/lib/Expression.cc
    trafficserver/plugins/trunk/esi/lib/Expression.h
    trafficserver/plugins/trunk/esi/lib/FailureInfo.cc
    trafficserver/plugins/trunk/esi/lib/FailureInfo.h
    trafficserver/plugins/trunk/esi/lib/HandlerManager.cc
    trafficserver/plugins/trunk/esi/lib/HandlerManager.h
    trafficserver/plugins/trunk/esi/lib/HttpHeader.h
    trafficserver/plugins/trunk/esi/lib/IncludeHandlerFactory.h
    trafficserver/plugins/trunk/esi/lib/SpecialIncludeHandler.h
    trafficserver/plugins/trunk/esi/lib/Stats.cc
    trafficserver/plugins/trunk/esi/lib/Stats.h
    trafficserver/plugins/trunk/esi/lib/StringHash.h
    trafficserver/plugins/trunk/esi/lib/Utils.cc
    trafficserver/plugins/trunk/esi/lib/Utils.h
    trafficserver/plugins/trunk/esi/lib/Variables.cc
    trafficserver/plugins/trunk/esi/lib/Variables.h
    trafficserver/plugins/trunk/esi/lib/gzip.cc
    trafficserver/plugins/trunk/esi/lib/gzip.h
    trafficserver/plugins/trunk/esi/plugin.cc
    trafficserver/plugins/trunk/esi/serverIntercept.cc
    trafficserver/plugins/trunk/esi/serverIntercept.h
    trafficserver/plugins/trunk/esi/test/
    trafficserver/plugins/trunk/esi/test/HandlerManager.cc
    trafficserver/plugins/trunk/esi/test/HandlerMap.cc
    trafficserver/plugins/trunk/esi/test/HandlerMap.h
    trafficserver/plugins/trunk/esi/test/StubIncludeHandler.cc
    trafficserver/plugins/trunk/esi/test/StubIncludeHandler.h
    trafficserver/plugins/trunk/esi/test/TestHttpDataFetcher.h
    trafficserver/plugins/trunk/esi/test/docnode_test.cc
    trafficserver/plugins/trunk/esi/test/parser_test.cc
    trafficserver/plugins/trunk/esi/test/processor_test.cc
    trafficserver/plugins/trunk/esi/test/sampleProb.cc
    trafficserver/plugins/trunk/esi/test/utils_test.cc
    trafficserver/plugins/trunk/esi/test/vars_test.cc
    trafficserver/plugins/trunk/esi/test_helper/
    trafficserver/plugins/trunk/esi/test_helper/print_funcs.cc
    trafficserver/plugins/trunk/esi/test_helper/print_funcs.h

Added: trafficserver/plugins/trunk/esi/LICENSE
URL: http://svn.apache.org/viewvc/trafficserver/plugins/trunk/esi/LICENSE?rev=1199388&view=auto
==============================================================================
--- trafficserver/plugins/trunk/esi/LICENSE (added)
+++ trafficserver/plugins/trunk/esi/LICENSE Tue Nov  8 19:07:20 2011
@@ -0,0 +1,427 @@
+
+                                 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
+
+~~~
+
+Mersenne Twister License
+
+   Copyright (C) 2004, Makoto Matsumoto and Takuji Nishimura,
+   All rights reserved.                          
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+     1. Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+
+     2. Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+
+     3. The names of its contributors may not be used to endorse or promote 
+        products derived from this software without specific prior written 
+        permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+~~~
+
+TK 8.3 License
+
+This software is copyrighted by the Regents of the University of
+California, Sun Microsystems, Inc., and other parties.  The following
+terms apply to all files associated with the software unless explicitly
+disclaimed in individual files.
+
+The authors hereby grant permission to use, copy, modify, distribute,
+and license this software and its documentation for any purpose, provided
+that existing copyright notices are retained in all copies and that this
+notice is included verbatim in any distributions. No written agreement,
+license, or royalty fee is required for any of the authorized uses.
+Modifications to this software may be copyrighted by their authors
+and need not follow the licensing terms described here, provided that
+the new terms are clearly indicated on the first page of each file where
+they apply.
+
+IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
+FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
+DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE
+IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
+NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
+MODIFICATIONS.
+
+GOVERNMENT USE: If you are acquiring this software on behalf of the
+U.S. government, the Government shall have only "Restricted Rights"
+in the software and related documentation as defined in the Federal
+Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2).  If you
+are acquiring the software on behalf of the Department of Defense, the
+software shall be classified as "Commercial Computer Software" and the
+Government shall have only "Restricted Rights" as defined in Clause
+252.227-7013 (c) (1) of DFARs.  Notwithstanding the foregoing, the
+authors grant the U.S. Government and others acting in its behalf
+permission to use and distribute the software in accordance with the
+terms specified in this license.
+
+~~~
+
+BIND license
+
+Copyright (c) 1985, 1989, 1993
+   The Regents of the University of California.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. Neither the name of the University nor the names of its contributors
+   may be used to endorse or promote products derived from this software
+   without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+
+
+Portions Copyright (c) 1993 by Digital Equipment Corporation.
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies, and that
+the name of Digital Equipment Corporation not be used in advertising or
+publicity pertaining to distribution of the document or software without
+specific, written prior permission.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
+CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+
+
+Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+Portions Copyright (c) 1996-1999 by Internet Software Consortium.
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+~~~
+
+Copyright (c) 1994-2011 John Bradley Plevyak, All Rights Reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. The name of the author may be used to endorse or promote products derived
+   from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+~~~
+
+Copyright (C) 2007 Ariya Hidayat (ariya@kde.org)
+Copyright (C) 2006 Ariya Hidayat (ariya@kde.org)
+Copyright (C) 2005 Ariya Hidayat (ariya@kde.org)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+
+For the strlcat, strlcpy in inktomi++/ink_string.cc:
+
+Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+

Added: trafficserver/plugins/trunk/esi/README
URL: http://svn.apache.org/viewvc/trafficserver/plugins/trunk/esi/README?rev=1199388&view=auto
==============================================================================
--- trafficserver/plugins/trunk/esi/README (added)
+++ trafficserver/plugins/trunk/esi/README Tue Nov  8 19:07:20 2011
@@ -0,0 +1,76 @@
+ESI plugin
+--------------------
+
+This plugin implements the ESI specification.
+
+Version 1.3.0
+-------------
+- Upgrading to yts_esi_lib-1.3.0 and using yts_http_fetcher_impl-1.0.0
+
+Version 1.2.0
+-------------
+- Using INKVConnClose instead of INKVConnShutdown to avoid memory
+  leak
+- Upgrading to yts_esi_lib-1.2.0
+
+Version 1.1.1
+-------------
+- Suppressing non-200 status handling error message
+- Upgrading to yts_esi_lib-1.1.1
+
+Version 1.1.0
+-------------
+- Suppressing non-200 status handling error message
+- Upgrading to yts_esi_lib-1.1.0
+
+Version 1.0.1
+-------------
+- Added symlink from conf/yts/plugins for backward compatibility
+
+Version 1.0.0
+-------------
+- Upgrading to yts_esi_lib-0.0.6
+
+Version 0.0.6
+-------------
+- Removing X-Esi header from outbound client response
+
+Version 0.0.5_1
+---------------
+- Requiring correct version of yts_esi_lib (0.0.5)
+
+Version 0.0.5
+-------------
+- Using intercept solution to POST-back and cache serialized
+  form of document
+- Added basic stats
+
+Version 0.0.4_2
+---------------
+- Using yts_esi_lib-0.0.4
+
+Version 0.0.4_1
+---------------
+- Added conf/yts_plugin_esi directory and handlers.cfg
+
+Version 0.0.4
+-------------
+- Upgrading to yts_esi_lib{,_dev}-0.0.3
+- Special include handlers can now add 'footer' data
+- Dealing with gzip'ed data from OS and gzip'ing output if requested
+
+Version 0.0.3
+-------------
+- Conforming to API changes becase of ticket 3515300
+- Partial fix to bug 3503119 (ESI plugin should return error code
+  (4xx or 5xx) if it can not fetch include src url)
+
+
+Version 0.0.2 
+-------------
+- Upgraded to new fetch API, support for special includes
+
+Version 0.0.1
+-------------
+- Prototype implementation
+

Added: trafficserver/plugins/trunk/esi/fetcher/FetchedDataProcessor.h
URL: http://svn.apache.org/viewvc/trafficserver/plugins/trunk/esi/fetcher/FetchedDataProcessor.h?rev=1199388&view=auto
==============================================================================
--- trafficserver/plugins/trunk/esi/fetcher/FetchedDataProcessor.h (added)
+++ trafficserver/plugins/trunk/esi/fetcher/FetchedDataProcessor.h Tue Nov  8 19:07:20 2011
@@ -0,0 +1,18 @@
+#ifndef _FETCHED_DATA_PROCESSOR_H
+
+#define _FETCHED_DATA_PROCESSOR_H
+
+class FetchedDataProcessor { 
+
+public:
+
+  FetchedDataProcessor() { };
+
+  virtual void processData(const char *reqeust_url, int request_url_len, 
+                           const char *response_data, int response_data_len) = 0;
+
+  virtual ~FetchedDataProcessor() { };
+
+};
+
+#endif

Added: trafficserver/plugins/trunk/esi/fetcher/HttpDataFetcher.h
URL: http://svn.apache.org/viewvc/trafficserver/plugins/trunk/esi/fetcher/HttpDataFetcher.h?rev=1199388&view=auto
==============================================================================
--- trafficserver/plugins/trunk/esi/fetcher/HttpDataFetcher.h (added)
+++ trafficserver/plugins/trunk/esi/fetcher/HttpDataFetcher.h Tue Nov  8 19:07:20 2011
@@ -0,0 +1,51 @@
+#ifndef _HTTP_DATA_FETCHER_H
+#define _HTTP_DATA_FETCHER_H
+
+#include <string>
+
+#include "FetchedDataProcessor.h"
+
+enum DataStatus { STATUS_ERROR = -1, STATUS_DATA_AVAILABLE = 0, STATUS_DATA_PENDING = 1  };
+
+class HttpDataFetcher
+{
+
+public:
+
+  virtual bool addFetchRequest(const char *url, int url_len, FetchedDataProcessor *callback_obj = 0) {
+    return addFetchRequest(std::string(url, url_len), callback_obj);
+  }
+
+  virtual bool addFetchRequest(const char *url, FetchedDataProcessor *callback_obj = 0) {
+    return addFetchRequest(std::string(url), callback_obj);
+  }
+
+  virtual bool addFetchRequest(const std::string &url, FetchedDataProcessor *callback_obj = 0) = 0;
+
+  virtual DataStatus getRequestStatus(const char *url, int url_len) const {
+    return getRequestStatus(std::string(url, url_len));
+  }
+
+  virtual DataStatus getRequestStatus(const char *url) const {
+    return getRequestStatus(std::string(url));
+  }
+
+  virtual DataStatus getRequestStatus(const std::string &url) const = 0;
+
+  virtual int getNumPendingRequests() const = 0;
+
+  virtual bool getContent(const char *url, int url_len, const char *&content, int &content_len) const {
+    return getContent(std::string(url, url_len), content, content_len);
+  }
+
+  virtual bool getContent(const char *url, const char *&content, int &content_len) const {
+    return getContent(std::string(url), content, content_len);
+  }
+
+  virtual bool getContent(const std::string &url, const char *&content, int &content_len) const = 0;
+
+  virtual ~HttpDataFetcher() { };
+
+};
+
+#endif

Added: trafficserver/plugins/trunk/esi/fetcher/HttpDataFetcherImpl.cc
URL: http://svn.apache.org/viewvc/trafficserver/plugins/trunk/esi/fetcher/HttpDataFetcherImpl.cc?rev=1199388&view=auto
==============================================================================
--- trafficserver/plugins/trunk/esi/fetcher/HttpDataFetcherImpl.cc (added)
+++ trafficserver/plugins/trunk/esi/fetcher/HttpDataFetcherImpl.cc Tue Nov  8 19:07:20 2011
@@ -0,0 +1,252 @@
+#include "HttpDataFetcherImpl.h"
+#include "Utils.h"
+
+#include <arpa/inet.h>
+
+using std::string;
+using namespace EsiLib;
+
+const int HttpDataFetcherImpl::FETCH_EVENT_ID_BASE = 10000;
+
+inline void HttpDataFetcherImpl::_release(RequestData &req_data) {
+  if (req_data.bufp) {
+    if (req_data.hdr_loc) {
+      INKHandleMLocRelease(req_data.bufp, INK_NULL_MLOC, req_data.hdr_loc);
+      req_data.hdr_loc = 0;
+    }
+    INKMBufferDestroy(req_data.bufp);
+    req_data.bufp = 0;
+  }
+}
+
+HttpDataFetcherImpl::HttpDataFetcherImpl(INKCont contp, unsigned int client_ip, int client_port,
+                                         const char *debug_tag)
+  : _contp(contp), _debug_tag(debug_tag), _n_pending_requests(0), _curr_event_id_base(FETCH_EVENT_ID_BASE),
+    _headers_str(""), _client_ip(client_ip), _client_port(client_port) {
+  _http_parser = INKHttpParserCreate();
+}
+
+HttpDataFetcherImpl::~HttpDataFetcherImpl() { 
+  clear(); 
+  INKHttpParserDestroy(_http_parser); 
+}
+
+inline void
+HttpDataFetcherImpl::_buildHeadersString() {
+  INKDebug(_debug_tag.c_str(), "[%s] Building header string...", __FUNCTION__);
+  _headers_str.clear();
+  for (StringHash::const_iterator iter = _headers.begin(); iter != _headers.end(); ++iter) {
+    _headers_str.append(iter->first);
+    _headers_str.append(": ");
+    _headers_str.append(iter->second);
+    _headers_str += "\r\n";
+  }
+}
+
+void
+HttpDataFetcherImpl::_createRequest(std::string &http_req, const string &url) {
+  http_req.assign("GET ");
+  http_req.append(url);
+  http_req.append(" HTTP/1.0\r\n");
+  if (_headers.size()) {
+    if (!_headers_str.size()) {
+      _buildHeadersString();
+    }
+    http_req.append(_headers_str);
+  }
+  http_req.append("\r\n");
+}
+
+bool
+HttpDataFetcherImpl::addFetchRequest(const string &url, FetchedDataProcessor *callback_obj /* = 0 */) {
+  // do we already have a request for this?
+  std::pair<UrlToContentMap::iterator, bool> insert_result = 
+    _pages.insert(UrlToContentMap::value_type(url, RequestData()));
+  if (callback_obj) {
+    ((insert_result.first)->second).callback_objects.push_back(callback_obj);
+  }
+  if (!insert_result.second) {
+    INKDebug(_debug_tag.c_str(), "[%s] Fetch request for url [%.*s] already added", __FUNCTION__,
+             url.size(), url.data());
+    return true;
+  }
+  
+  string http_req;
+  _createRequest(http_req, url);
+
+  INKFetchEvent event_ids;
+  event_ids.success_event_id = _curr_event_id_base;
+  event_ids.failure_event_id = _curr_event_id_base + 1;
+  event_ids.timeout_event_id = _curr_event_id_base + 2;
+  _curr_event_id_base += 3;
+
+  if (INKFetchUrl(http_req.data(), http_req.size(), _client_ip, _client_port, _contp, AFTER_BODY,
+                  event_ids) == INK_ERROR) {
+    INKError("Failed to add fetch request for URL [%.*s]", url.size(), url.data());
+    return false;
+  }
+  
+  INKDebug(_debug_tag.c_str(), "[%s] Successfully added fetch request for URL [%.*s]",
+           __FUNCTION__, url.size(), url.data());
+  _page_entry_lookup.push_back(insert_result.first);
+  ++_n_pending_requests;
+  return true;
+}
+
+bool
+HttpDataFetcherImpl::_isFetchEvent(INKEvent event, int &base_event_id) const {
+  base_event_id = _getBaseEventId(event);
+  if ((base_event_id < 0) || (base_event_id >= static_cast<int>(_page_entry_lookup.size()))) {
+    INKDebug(_debug_tag.c_str(), "[%s] Event id %d not within fetch event id range [%d, %d)",
+             __FUNCTION__, event, FETCH_EVENT_ID_BASE, FETCH_EVENT_ID_BASE + (_page_entry_lookup.size() * 3));
+    return false;
+  }
+  return true;
+}
+
+bool
+HttpDataFetcherImpl::handleFetchEvent(INKEvent event, void *edata) {
+  int base_event_id;
+  if (!_isFetchEvent(event, base_event_id)) {
+    INKError("[%s] Event %d is not a fetch event", __FUNCTION__, event);
+    return false;
+  }
+
+  UrlToContentMap::iterator &req_entry = _page_entry_lookup[base_event_id];
+  const string &req_str = req_entry->first;
+  RequestData &req_data = req_entry->second;
+
+  if (req_data.complete) {
+    // can only happen if there's a bug in this or fetch API code
+    INKError("[%s] URL [%s] already completed; Retaining original data", __FUNCTION__, req_str.c_str());
+    return false;
+  }
+
+  --_n_pending_requests;
+  req_data.complete = true;
+
+  int event_id = (static_cast<int>(event) - FETCH_EVENT_ID_BASE) % 3;
+  if (event_id != 0) { // failure or timeout
+    INKError("[%s] Received failure/timeout event id %d for request [%.*s]",
+             __FUNCTION__, event_id, req_str.size(), req_str.data());
+    return true;
+  }
+
+  int page_data_len;
+  const char *page_data = INKFetchRespGet(static_cast<INKHttpTxn>(edata), &page_data_len);
+  req_data.response.assign(page_data, page_data_len);
+  bool valid_data_received = false;
+  const char *startptr = req_data.response.data(), *endptr = startptr + page_data_len;
+
+  req_data.bufp = INKMBufferCreate();
+  req_data.hdr_loc = INKHttpHdrCreate(req_data.bufp);
+  INKHttpHdrTypeSet(req_data.bufp, req_data.hdr_loc, INK_HTTP_TYPE_RESPONSE);
+  INKHttpParserClear(_http_parser);
+  
+  if (INKHttpHdrParseResp(_http_parser, req_data.bufp, req_data.hdr_loc, &startptr, endptr) == INK_PARSE_DONE) {
+    INKHttpStatus resp_status = INKHttpHdrStatusGet(req_data.bufp, req_data.hdr_loc);
+    if (resp_status == INK_HTTP_STATUS_OK) {
+      valid_data_received = true;
+      req_data.body_len = endptr - startptr;
+      req_data.body = startptr;
+      INKDebug(_debug_tag.c_str(),
+               "[%s] Inserted page data of size %d starting with [%.6s] for request [%s]", __FUNCTION__,
+               req_data.body_len, (req_data.body_len ? req_data.body : "(null)"), req_str.c_str());
+      for (CallbackObjectList::iterator list_iter = req_data.callback_objects.begin();
+           list_iter != req_data.callback_objects.end(); ++list_iter) {
+        (*list_iter)->processData(req_str.data(), req_str.size(), req_data.body, req_data.body_len);
+      }
+    } else {
+      INKDebug(_debug_tag.c_str(), "[%s] Received non-OK status %d for request [%.*s]",
+               __FUNCTION__, resp_status, req_str.size(), req_str.data());
+    } 
+  } else {
+    INKDebug(_debug_tag.c_str(), "[%s] Could not parse response for request [%.*s]",
+             __FUNCTION__, req_str.size(), req_str.data());
+  }
+
+  if (!valid_data_received) {
+    _release(req_data);
+    req_data.response.clear();
+  }
+
+  return true;
+}
+
+bool
+HttpDataFetcherImpl::getData(const string &url, ResponseData &resp_data) const {
+  UrlToContentMap::const_iterator iter = _pages.find(url);
+  if (iter == _pages.end()) {
+    INKError("Content being requested for unregistered URL [%.*s]", url.size(), url.data());
+    return false;
+  }
+  const RequestData &req_data = iter->second; // handy reference
+  if (!req_data.complete) {
+    // request not completed yet
+    INKError("Request for URL [%.*s] not complete", url.size(), url.data());
+    return false;
+  }
+  if (req_data.response.empty()) {
+    // did not receive valid data
+    INKError("No valid data received for URL [%.*s]; returning empty data to be safe", url.size(), url.data());
+    resp_data.clear();
+    return false;
+  }
+  resp_data.set(req_data.body, req_data.body_len, req_data.bufp, req_data.hdr_loc);
+  INKDebug(_debug_tag.c_str(), "[%s] Found data for URL [%.*s] of size %d starting with [%.5s]", 
+           __FUNCTION__, url.size(), url.data(), req_data.body_len, req_data.body);
+  return true;
+}
+
+void
+HttpDataFetcherImpl::clear() {
+  for (UrlToContentMap::iterator iter = _pages.begin(); iter != _pages.end(); ++iter) {
+    _release(iter->second);
+  }
+  _n_pending_requests = 0;
+  _pages.clear();
+  _page_entry_lookup.clear();
+  _headers_str.clear();
+  _headers.clear();
+  _curr_event_id_base = FETCH_EVENT_ID_BASE;
+}
+
+DataStatus
+HttpDataFetcherImpl::getRequestStatus(const string &url) const {
+  UrlToContentMap::const_iterator iter = _pages.find(url);
+  if (iter == _pages.end()) {
+    INKError("Status being requested for unregistered URL [%.*s]", url.size(), url.data());
+    return STATUS_ERROR;
+  }
+  if (!(iter->second).complete) {
+    return STATUS_DATA_PENDING;
+  }
+  if ((iter->second).response.empty()) {
+    return STATUS_ERROR;
+  }
+  return STATUS_DATA_AVAILABLE;
+}
+
+void
+HttpDataFetcherImpl::useHeader(const HttpHeader &header) {
+  if (Utils::areEqual(header.name, header.name_len,
+                      INK_MIME_FIELD_ACCEPT_ENCODING, INK_MIME_LEN_ACCEPT_ENCODING)) {
+    return;
+  }
+  string name(header.name, header.name_len);
+  string value(header.value, header.value_len);
+  std::pair<StringHash::iterator, bool> result = _headers.insert(StringHash::value_type(name, value));
+  if (!result.second) {
+    result.first->second = value;
+  }
+  if (_headers_str.size()) { // rebuild
+    _buildHeadersString();
+  }
+}
+
+void
+HttpDataFetcherImpl::useHeaders(const HttpHeaderList &headers) {
+  for (HttpHeaderList::const_iterator iter = headers.begin(); iter != headers.end(); ++iter) {
+    useHeader(*iter);
+  }
+}

Added: trafficserver/plugins/trunk/esi/fetcher/HttpDataFetcherImpl.h
URL: http://svn.apache.org/viewvc/trafficserver/plugins/trunk/esi/fetcher/HttpDataFetcherImpl.h?rev=1199388&view=auto
==============================================================================
--- trafficserver/plugins/trunk/esi/fetcher/HttpDataFetcherImpl.h (added)
+++ trafficserver/plugins/trunk/esi/fetcher/HttpDataFetcherImpl.h Tue Nov  8 19:07:20 2011
@@ -0,0 +1,122 @@
+#ifndef _HTTP_DATA_FETCHER_IMPL_H
+#define _HTTP_DATA_FETCHER_IMPL_H
+
+#include <string>
+#include <list>
+#include <vector>
+
+#include "InkAPI.h"
+#include "StringHash.h"
+#include "HttpHeader.h"
+#include "HttpDataFetcher.h"
+
+class HttpDataFetcherImpl : public HttpDataFetcher
+{
+
+public:
+
+  HttpDataFetcherImpl(INKCont contp, unsigned int client_ip, int client_port, const char *debug_tag);
+
+  void useHeader(const EsiLib::HttpHeader &header);
+  
+  void useHeaders(const EsiLib::HttpHeaderList &headers);
+
+  bool addFetchRequest(const std::string &url, FetchedDataProcessor *callback_obj = 0);
+  
+  bool handleFetchEvent(INKEvent event, void *edata);
+
+  bool isFetchEvent(INKEvent event) const {
+    int base_event_id;
+    return _isFetchEvent(event, base_event_id);
+  }
+
+  bool isFetchComplete() const { return (_n_pending_requests == 0); };
+
+  DataStatus getRequestStatus(const std::string &url) const;
+
+  int getNumPendingRequests() const { return _n_pending_requests; };
+
+  // used to return data to callers
+  struct ResponseData {
+    const char *content;
+    int content_len;
+    INKMBuffer bufp;
+    INKMLoc hdr_loc;
+    ResponseData() { set(0, 0, 0, 0); }
+    inline void set(const char *c, int clen, INKMBuffer b, INKMLoc loc);
+    void clear() { set(0, 0, 0, 0); }
+  };
+
+  bool getData(const std::string &url, ResponseData &resp_data) const;
+
+  bool getContent(const std::string &url, const char *&content, int &content_len) const {
+    ResponseData resp;
+    if (getData(url, resp)) {
+      content = resp.content;
+      content_len = resp.content_len;
+      return true;
+    }
+    return false;
+  }
+
+  void clear();
+
+  ~HttpDataFetcherImpl();
+
+private:
+  
+  INKCont _contp;
+  std::string _debug_tag;
+
+  typedef std::list<FetchedDataProcessor *> CallbackObjectList;
+ 
+  // used to track a request that was made
+  struct RequestData {
+    std::string response;
+    const char *body;
+    int body_len;
+    CallbackObjectList callback_objects;
+    bool complete;
+    INKMBuffer bufp;
+    INKMLoc hdr_loc;
+    RequestData() : body(0), body_len(0), complete(false), bufp(0), hdr_loc(0) { };
+  };
+
+  typedef __gnu_cxx::hash_map<std::string, RequestData, EsiLib::StringHasher> UrlToContentMap;
+  UrlToContentMap _pages;
+
+  typedef std::vector<UrlToContentMap::iterator> IteratorArray;
+  IteratorArray _page_entry_lookup; // used to map event ids to requests
+
+  int _n_pending_requests;
+  int _curr_event_id_base;
+  INKHttpParser _http_parser;
+
+  static const int FETCH_EVENT_ID_BASE;
+
+  int _getBaseEventId(INKEvent event) const {
+    return (static_cast<int>(event) - FETCH_EVENT_ID_BASE) / 3; // integer division
+  }
+
+  bool _isFetchEvent(INKEvent event, int &base_event_id) const;
+
+  EsiLib::StringHash _headers;
+  std::string _headers_str;
+  
+  inline void _buildHeadersString();
+  void _createRequest(std::string &http_req, const std::string &url);
+  inline void _release(RequestData &req_data);
+
+  unsigned int _client_ip;
+  int _client_port;
+};
+
+inline void
+HttpDataFetcherImpl::ResponseData::set(const char *c, int clen, INKMBuffer b, INKMLoc loc) {
+  content = c;
+  content_len = clen;
+  bufp = b;
+  hdr_loc = loc;
+}
+
+#endif

Added: trafficserver/plugins/trunk/esi/handlers.cfg
URL: http://svn.apache.org/viewvc/trafficserver/plugins/trunk/esi/handlers.cfg?rev=1199388&view=auto
==============================================================================
--- trafficserver/plugins/trunk/esi/handlers.cfg (added)
+++ trafficserver/plugins/trunk/esi/handlers.cfg Tue Nov  8 19:07:20 2011
@@ -0,0 +1,10 @@
+#
+# Format of this file:
+# 
+# <include-handler-id> <full-path-to-shared-object>
+#
+#
+# Example:
+#
+# ads /home/y/libexec/yts/esi_ads.so
+#

Added: trafficserver/plugins/trunk/esi/lib/Attribute.h
URL: http://svn.apache.org/viewvc/trafficserver/plugins/trunk/esi/lib/Attribute.h?rev=1199388&view=auto
==============================================================================
--- trafficserver/plugins/trunk/esi/lib/Attribute.h (added)
+++ trafficserver/plugins/trunk/esi/lib/Attribute.h Tue Nov  8 19:07:20 2011
@@ -0,0 +1,21 @@
+#ifndef _ESI_ATTRIBUTE_H
+#define _ESI_ATTRIBUTE_H
+
+#include <list>
+
+namespace EsiLib {
+
+struct Attribute {
+  const char *name;
+  int32_t name_len;
+  const char *value;
+  int32_t value_len;
+  Attribute(const char *n = 0, int32_t n_len = 0, const char *v = 0, int32_t v_len = 0)
+    : name(n), name_len(n_len), value(v), value_len(v_len) { };
+};
+
+typedef std::list<Attribute> AttributeList;
+
+};
+
+#endif // _ESI_ATTRIBUTE_H

Added: trafficserver/plugins/trunk/esi/lib/ComponentBase.h
URL: http://svn.apache.org/viewvc/trafficserver/plugins/trunk/esi/lib/ComponentBase.h?rev=1199388&view=auto
==============================================================================
--- trafficserver/plugins/trunk/esi/lib/ComponentBase.h (added)
+++ trafficserver/plugins/trunk/esi/lib/ComponentBase.h Tue Nov  8 19:07:20 2011
@@ -0,0 +1,32 @@
+#ifndef _ESI_COMPONENT_BASE_H
+#define _ESI_COMPONENT_BASE_H
+
+#include <string>
+
+namespace EsiLib {
+
+/** class that has common private characteristics */
+class ComponentBase
+{
+
+public:
+
+  typedef void (*Debug)(const char *, const char *, ...);
+  typedef void (*Error)(const char *, ...);
+
+protected:
+  
+  ComponentBase(const char *debug_tag, Debug debug_func, Error error_func) 
+    : _debug_tag(debug_tag), _debugLog(debug_func), _errorLog(error_func) { };
+  
+  std::string _debug_tag;
+  Debug _debugLog;
+  Error _errorLog;
+  
+  virtual ~ComponentBase() { };
+
+};
+
+};
+
+#endif // _ESI_COMPONENT_BASE_H

Added: trafficserver/plugins/trunk/esi/lib/DocNode.cc
URL: http://svn.apache.org/viewvc/trafficserver/plugins/trunk/esi/lib/DocNode.cc?rev=1199388&view=auto
==============================================================================
--- trafficserver/plugins/trunk/esi/lib/DocNode.cc (added)
+++ trafficserver/plugins/trunk/esi/lib/DocNode.cc Tue Nov  8 19:07:20 2011
@@ -0,0 +1,156 @@
+#include "DocNode.h"
+#include "Utils.h"
+
+using std::string;
+using namespace EsiLib;
+
+const DocNode::TYPE DocNode::TYPE_UNKNOWN = 0;
+const DocNode::TYPE DocNode::TYPE_PRE = 1;
+const DocNode::TYPE DocNode::TYPE_INCLUDE = 2;
+const DocNode::TYPE DocNode::TYPE_COMMENT = 3;
+const DocNode::TYPE DocNode::TYPE_REMOVE = 4;
+const DocNode::TYPE DocNode::TYPE_VARS = 5;
+const DocNode::TYPE DocNode::TYPE_CHOOSE = 6;
+const DocNode::TYPE DocNode::TYPE_WHEN = 7;
+const DocNode::TYPE DocNode::TYPE_OTHERWISE = 8;
+const DocNode::TYPE DocNode::TYPE_TRY = 9;
+const DocNode::TYPE DocNode::TYPE_ATTEMPT = 10;
+const DocNode::TYPE DocNode::TYPE_EXCEPT = 11;
+const DocNode::TYPE DocNode::TYPE_HTML_COMMENT = 12;
+const DocNode::TYPE DocNode::TYPE_SPECIAL_INCLUDE = 13;
+
+const char *DocNode::type_names_[] = { "UNKNOWN",
+                                       "PRE",
+                                       "INCLUDE",
+                                       "COMMENT",
+                                       "REMOVE",
+                                       "VARS",
+                                       "CHOOSE",
+                                       "WHEN",
+                                       "OTHERWISE",
+                                       "TRY",
+                                       "ATTEMPT",
+                                       "EXCEPT",
+                                       "HTML_COMMENT",
+                                       "SPECIAL_INCLUDE"
+};
+
+const char DocNode::VERSION = 1;
+
+// helper functions 
+
+inline void
+packString(const char *str, int32_t str_len, string &buffer) {
+  buffer.append(reinterpret_cast<const char *>(&str_len), sizeof(str_len));
+  if (str_len) {
+    buffer.append(str, str_len);
+  }
+}
+
+inline void
+unpackString(const char *&packed_data, const char *&item, int32_t &item_len) {
+  item_len = *(reinterpret_cast<const int32_t *>(packed_data));
+  packed_data += sizeof(int32_t);
+  item = item_len ? packed_data : 0;
+  packed_data += item_len;
+}
+
+template<typename T> inline void
+unpackItem(const char *&packed_data, T &item) {
+  item = *(reinterpret_cast<const T *>(packed_data));
+  packed_data += sizeof(T);
+}
+
+void
+DocNode::pack(string &buffer) const {
+  int32_t orig_buf_size = buffer.size();
+  buffer += VERSION;
+  buffer.append(sizeof(int32_t), ' '); // reserve space for length
+  buffer.append(reinterpret_cast<const char *>(&type), sizeof(type));
+  packString(data, data_len, buffer);
+  int32_t n_elements = attr_list.size();
+  buffer.append(reinterpret_cast<const char *>(&n_elements), sizeof(n_elements));
+  for (AttributeList::const_iterator iter = attr_list.begin(); iter != attr_list.end(); ++iter) {
+    packString(iter->name, iter->name_len, buffer);
+    packString(iter->value, iter->value_len, buffer);
+  }
+  child_nodes.packToBuffer(buffer);
+  *(reinterpret_cast<int32_t *>(&buffer[orig_buf_size + 1])) = buffer.size() - orig_buf_size;
+}
+
+bool
+DocNode::unpack(const char *packed_data, int packed_data_len, int &node_len) {
+  const char *packed_data_start = packed_data;
+
+  if (!packed_data || (packed_data_len < static_cast<int>((sizeof(char) + sizeof(int32_t))))) {
+    Utils::ERROR_LOG("[%s] Invalid arguments (%p, %d)", __FUNCTION__, packed_data, packed_data_len);
+    return false;
+  }
+  if (*packed_data != VERSION) {
+    Utils::ERROR_LOG("[%s] Version %d not in supported set (%d)",
+                     __FUNCTION__, static_cast<int>(*packed_data), static_cast<int>(VERSION));
+    return false;
+  }
+  ++packed_data;
+
+  int32_t node_size;
+  unpackItem(packed_data, node_size);
+  if (node_size > packed_data_len) {
+    Utils::ERROR_LOG("[%s] Data size (%d) not sufficient to hold node of size %d",
+                     __FUNCTION__, packed_data_len, node_size);
+    return false;
+  }
+  node_len = node_size;
+
+  unpackItem(packed_data, type);
+
+  unpackString(packed_data, data, data_len);
+
+  int32_t n_elements;
+  unpackItem(packed_data, n_elements);
+  Attribute attr;
+  attr_list.clear();
+  for (int i = 0; i < n_elements; ++i) {
+    unpackString(packed_data, attr.name, attr.name_len);
+    unpackString(packed_data, attr.value, attr.value_len);
+    attr_list.push_back(attr);
+  }
+
+  if (!child_nodes.unpack(packed_data, packed_data_len - (packed_data - packed_data_start))) {
+    Utils::ERROR_LOG("[%s] Could not unpack child nodes", __FUNCTION__);
+    return false;
+  }
+  return true;
+}
+
+void
+DocNodeList::packToBuffer(string &buffer) const {
+  int32_t n_elements = size();
+  buffer.append(reinterpret_cast<const char *>(&n_elements), sizeof(n_elements));
+  for (DocNodeList::const_iterator iter = begin(); iter != end(); ++iter) {
+    iter->pack(buffer);
+  }
+}
+
+bool
+DocNodeList::unpack(const char *data, int data_len) {
+  if (!data || (data_len < static_cast<int>(sizeof(int32_t)))) {
+    Utils::ERROR_LOG("[%s] Invalid arguments", __FUNCTION__);
+    return false;
+  }
+  const char *data_start = data;
+  int32_t n_elements;
+  unpackItem(data, n_elements);
+  clear();
+  int data_offset = data - data_start, node_size;
+  DocNode node;
+  for (int i = 0; i < n_elements; ++i) {
+    if (!node.unpack(data_start + data_offset, data_len - data_offset, node_size)) {
+      Utils::ERROR_LOG("[%s] Could not unpack node", __FUNCTION__);
+      return false;
+    }
+    data_offset += node_size;
+    push_back(node);
+  }
+  return true;
+}

Added: trafficserver/plugins/trunk/esi/lib/DocNode.h
URL: http://svn.apache.org/viewvc/trafficserver/plugins/trunk/esi/lib/DocNode.h?rev=1199388&view=auto
==============================================================================
--- trafficserver/plugins/trunk/esi/lib/DocNode.h (added)
+++ trafficserver/plugins/trunk/esi/lib/DocNode.h Tue Nov  8 19:07:20 2011
@@ -0,0 +1,93 @@
+#ifndef _ESI_DOC_NODE_H
+#define _ESI_DOC_NODE_H
+
+#include <stdint.h>
+#include <list>
+#include <string>
+
+#include "Attribute.h"
+
+namespace EsiLib {
+
+struct DocNode;
+
+class DocNodeList : public std::list<DocNode> {
+
+public:
+
+  inline void pack(std::string &buffer, bool retain_buffer_data = false) const {
+    if (!retain_buffer_data) {
+      buffer.clear();
+    }
+    packToBuffer(buffer);
+  }
+
+  inline std::string pack() const {
+    std::string buffer("");
+    pack(buffer);
+    return buffer;
+  }
+  
+  bool unpack(const char *data, int data_len);
+  
+  inline bool unpack(const std::string &data) {
+    return unpack(data.data(), data.size());
+  }
+
+private:
+
+  void packToBuffer(std::string &buffer) const;
+  
+  friend class DocNode; // to use the method above
+
+};
+
+
+class DocNode
+{
+  
+public:
+
+  typedef int32_t TYPE;
+  static const TYPE TYPE_UNKNOWN;
+  static const TYPE TYPE_PRE;
+  static const TYPE TYPE_INCLUDE;
+  static const TYPE TYPE_COMMENT;
+  static const TYPE TYPE_REMOVE;
+  static const TYPE TYPE_VARS;
+  static const TYPE TYPE_CHOOSE;
+  static const TYPE TYPE_WHEN;
+  static const TYPE TYPE_OTHERWISE;
+  static const TYPE TYPE_TRY;
+  static const TYPE TYPE_ATTEMPT;
+  static const TYPE TYPE_EXCEPT;
+  static const TYPE TYPE_HTML_COMMENT;
+  static const TYPE TYPE_SPECIAL_INCLUDE;
+
+  // Use with care - only types defined above will have valid names 
+  static const char *type_names_[];
+
+  TYPE type;
+  const char *data;
+  int32_t data_len;
+
+  AttributeList attr_list;
+
+  DocNodeList child_nodes;
+
+  DocNode(TYPE _type = TYPE_UNKNOWN, const char *_data = 0, int32_t _data_len = 0) 
+    : type(_type), data(_data), data_len(_data_len) { };
+
+  void pack(std::string &buffer) const;
+
+  bool unpack(const char *data, int data_len, int &node_len);
+
+private:
+
+  static const char VERSION;
+
+};
+
+};
+
+#endif // _ESI_DOC_NODE_H

Added: trafficserver/plugins/trunk/esi/lib/EsiParser.cc
URL: http://svn.apache.org/viewvc/trafficserver/plugins/trunk/esi/lib/EsiParser.cc?rev=1199388&view=auto
==============================================================================
--- trafficserver/plugins/trunk/esi/lib/EsiParser.cc (added)
+++ trafficserver/plugins/trunk/esi/lib/EsiParser.cc Tue Nov  8 19:07:20 2011
@@ -0,0 +1,596 @@
+#include "EsiParser.h"
+#include "Utils.h"
+
+#include <ctype.h>
+
+using std::string;
+using namespace EsiLib;
+
+
+const char *EsiParser::ESI_TAG_PREFIX = "<esi:";
+const int EsiParser::ESI_TAG_PREFIX_LEN = 5;
+
+const string EsiParser::SRC_ATTR_STR("src");
+const string EsiParser::TEST_ATTR_STR("test");
+const string EsiParser::HANDLER_ATTR_STR("handler");
+
+const unsigned int EsiParser::MAX_DOC_SIZE = 1024 * 1024;
+
+const EsiParser::EsiNodeInfo EsiParser::ESI_NODES[] = {
+  EsiNodeInfo(DocNode::TYPE_INCLUDE, "include ", 8, "/>", 2),
+  EsiNodeInfo(DocNode::TYPE_REMOVE, "remove>", 7, "</esi:remove>", 13),
+  EsiNodeInfo(DocNode::TYPE_COMMENT, "comment ", 7, "/>", 2),
+  EsiNodeInfo(DocNode::TYPE_VARS, "vars>", 5, "</esi:vars>", 11),
+  EsiNodeInfo(DocNode::TYPE_CHOOSE, "choose>", 7, "</esi:choose>", 13),
+  EsiNodeInfo(DocNode::TYPE_WHEN, "when ", 5, "</esi:when>", 11),
+  EsiNodeInfo(DocNode::TYPE_OTHERWISE, "otherwise>", 10, "</esi:otherwise>", 16),
+  EsiNodeInfo(DocNode::TYPE_TRY, "try>", 4, "</esi:try>", 10),
+  EsiNodeInfo(DocNode::TYPE_ATTEMPT, "attempt> ", 8, "</esi:attempt>", 14),
+  EsiNodeInfo(DocNode::TYPE_EXCEPT, "except> ", 7, "</esi:except>", 13),
+  EsiNodeInfo(DocNode::TYPE_SPECIAL_INCLUDE, "special-include ", 15, "/>", 2),
+  EsiNodeInfo(DocNode::TYPE_UNKNOWN, "", 0, "", 0)  // serves as end marker
+};
+
+const EsiParser::EsiNodeInfo EsiParser::HTML_COMMENT_NODE_INFO(DocNode::TYPE_HTML_COMMENT,
+                                                               "<!--esi ", 8, "-->", 3);
+
+EsiParser::EsiParser(const char *debug_tag, 
+                     ComponentBase::Debug debug_func, 
+                     ComponentBase::Error error_func) 
+  : ComponentBase(debug_tag, debug_func, error_func), _parse_start_pos(-1) {
+  // do this so that object doesn't move around in memory;
+  // (because we return pointers into this object)
+  _data.reserve(MAX_DOC_SIZE);
+}
+
+bool
+EsiParser::_setup(string &data, int &parse_start_pos, size_t &orig_output_list_size,
+                  DocNodeList &node_list, const char *data_ptr, int &data_len) const {
+  bool retval = true;
+  if (!data_ptr || !data_len) {
+    _debugLog(_debug_tag.c_str(), "[%s] Returning true for empty data", __FUNCTION__);
+  }
+  else {
+    if (data_len == -1) {
+      data_len = strlen(data_ptr);
+    }
+    if ((data.size() + data_len) > MAX_DOC_SIZE) {
+      _errorLog("[%s] Cannot allow attempted doc of size %d; Max allowed size is %d", __FUNCTION__,
+                data.size() + data_len, MAX_DOC_SIZE);
+      retval = false;
+    }
+    else {
+      data.append(data_ptr, data_len);
+    }
+  }
+  if (parse_start_pos == -1) { // first time this cycle that input is being provided
+    parse_start_pos = 0;
+    orig_output_list_size = node_list.size();
+  }
+  return retval;
+}
+
+bool
+EsiParser::parseChunk(const char *data, DocNodeList &node_list, int data_len /* = -1 */) {
+  if (!_setup(_data, _parse_start_pos, _orig_output_list_size, node_list, data, data_len)) {
+    return false;
+  }
+  if (!_parse(_data, _parse_start_pos, node_list)) {
+    _errorLog("[%s] Failed to parse chunk of size %d starting with [%.5s]...", __FUNCTION__, data_len,
+              (data_len ? data : "(null)"));
+    return false;
+  }
+  return true;
+}
+
+bool
+EsiParser::_completeParse(string &data, int &parse_start_pos, size_t &orig_output_list_size,
+                          DocNodeList &node_list, const char *data_ptr /* = 0 */,
+                          int data_len /* = -1 */) const {
+  if (!_setup(data, parse_start_pos, orig_output_list_size, node_list, data_ptr, data_len)) {
+    return false;
+  }
+  if (!data.size()) {
+    _debugLog(_debug_tag.c_str(), "[%s] No data to parse!", __FUNCTION__);
+    return true;
+  }
+  if (!_parse(data, parse_start_pos, node_list, true)) {
+    _errorLog("[%s] Failed to complete parse of data of total size %d starting with [%.5s]...", 
+              __FUNCTION__, data.size(), (data.size() ? data.data() : "(null)"));
+    node_list.resize(orig_output_list_size);
+    return false;
+  }
+  return true;
+}
+
+EsiParser::MATCH_TYPE
+EsiParser::_searchData(const string &data, size_t start_pos, const char *str, int str_len, size_t &pos) const {
+  const char *data_ptr = data.data() + start_pos;
+  int data_len = data.size() - start_pos;
+  int i_data = 0, i_str = 0; 
+
+  while (i_data < data_len) {
+    if (data_ptr[i_data] == str[i_str]) {
+      ++i_str;
+      if (i_str == str_len) {
+        break;
+      }
+    } else {
+      i_data -= i_str;
+      i_str = 0;
+    }
+    ++i_data;
+  }
+
+  if (i_str == str_len) {
+    pos = start_pos + i_data + 1 - i_str;
+    _debugLog(_debug_tag.c_str(), "[%s] Found full match of %.*s in [%.5s...] at position %d", 
+              __FUNCTION__, str_len, str, data_ptr, pos);
+    return COMPLETE_MATCH;
+  } else if (i_str) {
+    pos = start_pos + i_data - i_str;
+    _debugLog(_debug_tag.c_str(), "[%s] Found partial match of %.*s in [%.5s...] at position %d", 
+              __FUNCTION__, str_len, str, data_ptr, pos);
+    return PARTIAL_MATCH;
+  } else {
+    _debugLog(_debug_tag.c_str(), "[%s] Found no match of %.*s in [%.5s...]", __FUNCTION__, str_len, str, data_ptr);
+    return NO_MATCH;
+  }
+}
+
+EsiParser::MATCH_TYPE
+EsiParser::_compareData(const string &data, size_t pos, const char *str, int str_len) const {
+  int i_str = 0;
+  size_t i_data = pos;
+  for (; i_data < data.size(); ++i_data) {
+    if (data[i_data] == str[i_str]) {
+      ++i_str;
+      if (i_str == str_len) {
+        _debugLog(_debug_tag.c_str(), "[%s] string [%.*s] is equal to data at position %d", 
+                  __FUNCTION__, str_len, str, pos);
+        return COMPLETE_MATCH;
+      }
+    }
+    else {
+      _debugLog(_debug_tag.c_str(), "[%s] string [%.*s] is not equal to data at position %d", 
+                __FUNCTION__, str_len, str, pos);
+      return NO_MATCH;
+    }
+  }
+  _debugLog(_debug_tag.c_str(), "[%s] string [%.*s] is partially equal to data at position %d", 
+            __FUNCTION__, str_len, str, pos);
+  return PARTIAL_MATCH;
+}
+
+/** This implementation is optimized but not completely correct.  If
+ * the opening tag were to have a repeating opening sequence ('<e<esi'
+ * or something like that), this will break. However that is not the
+ * case for the two opening tags we are looking for */
+EsiParser::MATCH_TYPE
+EsiParser::_findOpeningTag(const string &data, size_t start_pos,
+                           size_t &opening_tag_pos, bool &is_html_comment_node) const {
+  size_t i_data = start_pos;
+  int i_esi = 0, i_html_comment = 0;
+
+  while (i_data < data.size()) {
+    if (data[i_data] == ESI_TAG_PREFIX[i_esi]) {
+      if (++i_esi == ESI_TAG_PREFIX_LEN) {
+        is_html_comment_node = false;
+        opening_tag_pos = i_data - i_esi + 1;
+        return COMPLETE_MATCH;
+      }
+    } else {
+      if (i_esi) {
+        i_esi = 0;
+        --i_data;  // we do this to reexamine the current char as target string might start from here
+        if (i_html_comment) {
+          --i_html_comment; // in case other target string has started matching, adjust it's index
+        }
+      }
+    }
+    // doing the exact same thing for the other target string
+    if (data[i_data] == HTML_COMMENT_NODE_INFO.tag_suffix[i_html_comment]) {
+      if (++i_html_comment == HTML_COMMENT_NODE_INFO.tag_suffix_len) {
+        is_html_comment_node = true;
+        opening_tag_pos = i_data - i_html_comment + 1;
+        return COMPLETE_MATCH;
+      }
+    } else {
+      if (i_html_comment) {
+        i_html_comment = 0;
+        --i_data; // same comments from above applies
+        if (i_esi) {
+          --i_esi;
+        }
+      }
+    }
+    ++i_data;
+  }
+  // partial matches; with the nature of our current opening tags, the
+  // only way we can have a partial match for both target strings is
+  // if the last char of the input string is '<' and that is not
+  // enough information to differentiate the tags; Anyway, the parser
+  // takes no action for a partial match
+  if (i_esi) {
+    is_html_comment_node = false;
+    opening_tag_pos = i_data - i_esi;
+    return PARTIAL_MATCH;
+  }
+  if (i_html_comment) {
+    is_html_comment_node = true;
+    opening_tag_pos = i_data - i_html_comment;
+    return PARTIAL_MATCH;
+  }
+  return NO_MATCH;
+}
+
+inline bool
+EsiParser::_processSimpleContentTag(DocNode::TYPE node_type, const char *data, int data_len,
+                                    DocNodeList &node_list) const {
+  DocNode new_node(node_type);
+  if (!parse(new_node.child_nodes, data, data_len)) {
+    _errorLog("[%s] Could not parse simple content of [%s] node", __FUNCTION__,
+              DocNode::type_names_[node_type]);
+    return false;
+  }
+  node_list.push_back(new_node);
+  return true;
+}
+
+bool
+EsiParser::_parse(const string &data, int &parse_start_pos,
+                  DocNodeList &node_list, bool last_chunk /* = false */) const {
+  size_t orig_list_size = node_list.size();
+  size_t curr_pos, end_pos;
+  const char *data_ptr;
+  const char *const data_start_ptr = data.data();
+  size_t data_size = data.size();
+  const EsiNodeInfo *node_info;
+  MATCH_TYPE search_result;
+  bool is_html_comment_node;
+  bool parse_result;
+
+  while (parse_start_pos < static_cast<int>(data_size)) {
+    search_result = _findOpeningTag(data, static_cast<int>(parse_start_pos), curr_pos, is_html_comment_node);
+    if (search_result == NO_MATCH) {
+      // we could add this chunk as a PRE node, but it might be
+      // possible that the next chunk is also a PRE node, in which
+      // case it is more correct to create one PRE node than two PRE
+      // nodes even though processing would result in the same final
+      // output in either case.  we are sacrificing a little
+      // performance (we'll have to parse this chunk again next time)
+      // for correctness
+      break;
+    }
+    if (search_result == PARTIAL_MATCH) {
+      goto lPartialMatch;
+    }
+
+    // we have a complete match of the opening tag
+    if ((curr_pos - parse_start_pos) > 0) {
+      // add text till here as a PRE node
+      _debugLog(_debug_tag.c_str(), "[%s], Adding data of size %d before (newly found) ESI tag as PRE node", 
+                __FUNCTION__, curr_pos - parse_start_pos);
+      node_list.push_back(DocNode(DocNode::TYPE_PRE, 
+                                  data_start_ptr + parse_start_pos, curr_pos - parse_start_pos));
+      parse_start_pos = curr_pos;
+    }
+    
+    if (is_html_comment_node) {
+      _debugLog(_debug_tag.c_str(), "[%s] Found html comment tag at position %d", __FUNCTION__, curr_pos);
+      data_ptr = data_start_ptr + curr_pos;
+      node_info = &HTML_COMMENT_NODE_INFO;
+    } else {
+      curr_pos += ESI_TAG_PREFIX_LEN;
+      data_ptr = data_start_ptr + curr_pos;
+      
+      for (node_info = ESI_NODES; node_info->type != DocNode::TYPE_UNKNOWN; ++node_info) {
+        search_result = _compareData(data, curr_pos, node_info->tag_suffix, node_info->tag_suffix_len);
+        if (search_result == COMPLETE_MATCH) {
+          _debugLog(_debug_tag.c_str(), "[%s] Found [%s] tag at position %d", 
+                    __FUNCTION__, DocNode::type_names_[node_info->type], curr_pos - ESI_TAG_PREFIX_LEN);
+          break;
+        } else if (search_result == PARTIAL_MATCH) {
+          goto lPartialMatch;
+        }
+      }
+      if (node_info->type == DocNode::TYPE_UNKNOWN) {
+        _errorLog("[%s] Unknown ESI tag starting with [%.10s]...", __FUNCTION__, data_ptr - ESI_TAG_PREFIX_LEN);
+        goto lFail;
+      }
+    }
+
+    curr_pos += node_info->tag_suffix_len;
+    search_result = _searchData(data, curr_pos, node_info->closing_tag, node_info->closing_tag_len, end_pos);
+
+    if ((search_result == NO_MATCH) || (search_result == PARTIAL_MATCH)) {
+      if (last_chunk) {
+        _errorLog("[%s] ESI tag starting with [%.10s]... has no matching closing tag [%.*s]", __FUNCTION__, 
+                  data_ptr - ESI_TAG_PREFIX_LEN, node_info->closing_tag_len, node_info->closing_tag);
+        goto lFail;
+      }
+      else {
+        goto lPartialMatch;
+      }
+    }
+
+    parse_result = false;
+    
+    // now we process only complete nodes
+    if (node_info->type == DocNode::TYPE_INCLUDE) {
+      _debugLog(_debug_tag.c_str(), "[%s] Handling include tag...", __FUNCTION__);
+      parse_result = _processIncludeTag(data, curr_pos, end_pos, node_list);
+    } else if ((node_info->type == DocNode::TYPE_COMMENT) || (node_info->type == DocNode::TYPE_REMOVE)) {
+      _debugLog(_debug_tag.c_str(), "[%s] Adding node [%s]", __FUNCTION__,
+                DocNode::type_names_[node_info->type]);
+      node_list.push_back(DocNode(node_info->type)); // no data required
+      parse_result = true;
+    } else if (node_info->type == DocNode::TYPE_WHEN) {
+      _debugLog(_debug_tag.c_str(), "[%s] Handling when tag...", __FUNCTION__);
+      parse_result = _processWhenTag(data, curr_pos, end_pos, node_list);
+    } else if (node_info->type == DocNode::TYPE_TRY) {
+      _debugLog(_debug_tag.c_str(), "[%s] Handling try tag...", __FUNCTION__);
+      parse_result = _processTryTag(data, curr_pos, end_pos, node_list);
+    } else if (node_info->type == DocNode::TYPE_CHOOSE) {
+      _debugLog(_debug_tag.c_str(), "[%s] Handling choose tag...", __FUNCTION__);
+      parse_result = _processChooseTag(data, curr_pos, end_pos, node_list);
+    } else if ((node_info->type == DocNode::TYPE_OTHERWISE) ||
+               (node_info->type == DocNode::TYPE_ATTEMPT) ||
+               (node_info->type == DocNode::TYPE_EXCEPT)) {
+      _debugLog(_debug_tag.c_str(), "[%s] Handling %s tag...", __FUNCTION__,
+                DocNode::type_names_[node_info->type]);
+      parse_result = _processSimpleContentTag(node_info->type, data.data() + curr_pos,
+                                              end_pos - curr_pos, node_list);
+    } else if ((node_info->type == DocNode::TYPE_VARS) || 
+               (node_info->type == DocNode::TYPE_HTML_COMMENT)) {
+      _debugLog(_debug_tag.c_str(), "[%s] added string of size %d starting with [%.5s] for node %s",
+                __FUNCTION__, end_pos - curr_pos, data.data() + curr_pos,
+                DocNode::type_names_[node_info->type]);
+      node_list.push_back(DocNode(node_info->type, data.data() + curr_pos, end_pos - curr_pos));
+      parse_result = true;
+    } else if (node_info->type == DocNode::TYPE_SPECIAL_INCLUDE) {
+      _debugLog(_debug_tag.c_str(), "[%s] Handling special include tag...", __FUNCTION__);
+      parse_result = _processSpecialIncludeTag(data, curr_pos, end_pos, node_list);
+    }
+
+    if (!parse_result) {
+      _errorLog("[%s] Cannot handle ESI tag [%.*s]", __FUNCTION__, 
+                node_info->tag_suffix_len, node_info->tag_suffix);
+      goto lFail;
+    }
+
+    parse_start_pos = end_pos + node_info->closing_tag_len;
+    continue;
+
+  lPartialMatch:
+    if (last_chunk) {
+      _debugLog(_debug_tag.c_str(), "[%s] Found a partial ESI tag - will be treated as PRE text", __FUNCTION__);
+    } else {
+      _debugLog(_debug_tag.c_str(), "[%s] Deferring to next chunk to find complete tag", __FUNCTION__);
+    }
+    break;
+  }
+  if (last_chunk && (parse_start_pos < static_cast<int>(data_size))) {
+    _debugLog(_debug_tag.c_str(), "[%s] Adding trailing text of size %d starting at [%.5s] as a PRE node", 
+              __FUNCTION__, data_size - parse_start_pos, data_start_ptr + parse_start_pos);
+    node_list.push_back(DocNode(DocNode::TYPE_PRE, 
+                                data_start_ptr + parse_start_pos, data_size - parse_start_pos));
+  }
+  _debugLog(_debug_tag.c_str(), "[%s] Added %d node(s) during parse", __FUNCTION__, node_list.size() - orig_list_size);
+  return true;
+
+lFail:
+  node_list.resize(orig_list_size);   // delete whatever nodes we have added so far
+  return false;
+}
+
+bool
+EsiParser::_processIncludeTag(const string &data, size_t curr_pos, size_t end_pos,
+                              DocNodeList &node_list) const {
+  Attribute src_info;
+  if (!Utils::getAttribute(data, SRC_ATTR_STR, curr_pos, end_pos, src_info)) {
+    _errorLog("[%s] Could not find src attribute", __FUNCTION__);
+    return false;
+  }
+  node_list.push_back(DocNode(DocNode::TYPE_INCLUDE));
+  node_list.back().attr_list.push_back(src_info);
+  _debugLog(_debug_tag.c_str(), "[%s] Added include tag with url [%.*s]",
+            __FUNCTION__, src_info.value_len, src_info.value);
+  return true;
+}
+
+bool
+EsiParser::_processSpecialIncludeTag(const string &data, size_t curr_pos, size_t end_pos,
+                                     DocNodeList &node_list) const {
+  Attribute handler_info;
+  if (!Utils::getAttribute(data, HANDLER_ATTR_STR, curr_pos, end_pos, handler_info)) {
+    _errorLog("[%s] Could not find handler attribute", __FUNCTION__);
+    return false;
+  }
+  node_list.push_back(DocNode(DocNode::TYPE_SPECIAL_INCLUDE));
+  DocNode &node = node_list.back();
+  node.attr_list.push_back(handler_info);
+  node.data = data.data() + curr_pos;
+  node.data_len = end_pos - curr_pos;
+  _debugLog(_debug_tag.c_str(), "[%s] Added special include tag with handler [%.*s] and data [%.*s]",
+            __FUNCTION__, handler_info.value_len, handler_info.value, node.data_len, node.data);
+  return true;
+}
+
+inline bool
+EsiParser::_isWhitespace(const char *data, int data_len) const {
+  for (int i = 0; i < data_len; ++i) {
+    if (!isspace(data[i])) {
+      return false;
+    }
+  }
+  return true;
+}
+
+bool
+EsiParser::_processWhenTag(const string &data, size_t curr_pos, size_t end_pos,
+                           DocNodeList &node_list) const {
+  Attribute test_expr;
+  size_t term_pos;
+  if (!Utils::getAttribute(data, TEST_ATTR_STR, curr_pos, end_pos, test_expr, &term_pos, '>')) {
+    _errorLog("[%s] Could not find test attribute", __FUNCTION__);
+    return false;
+  }
+  ++term_pos; // go past the terminator
+  const char *data_start_ptr = data.data() + term_pos;
+  int data_size = end_pos - term_pos;
+  if (!_processSimpleContentTag(DocNode::TYPE_WHEN, data_start_ptr, data_size, node_list)) {
+    _errorLog("[%s] Could not parse when node's content", __FUNCTION__);
+    return false;
+  }
+  node_list.back().attr_list.push_back(test_expr);
+  _debugLog(_debug_tag.c_str(), "[%s] Added when tag with expression [%.*s] and data starting with [%.5s]",
+            __FUNCTION__, test_expr.value_len, test_expr.value, data_start_ptr);
+  return true;
+}
+
+bool
+EsiParser::_processTryTag(const string &data, size_t curr_pos, size_t end_pos,
+                          DocNodeList &node_list) const {
+  const char *data_start_ptr = data.data() + curr_pos;
+  int data_size = end_pos - curr_pos;
+  DocNode try_node(DocNode::TYPE_TRY);
+  if (!parse(try_node.child_nodes, data_start_ptr, data_size)) {
+    _errorLog("[%s] Could not parse try node's content", __FUNCTION__);
+    return false;
+  }
+
+  DocNodeList::iterator iter, end_node, attempt_node, except_node, temp_iter;
+  end_node = try_node.child_nodes.end();
+  attempt_node = except_node = end_node;
+  iter = try_node.child_nodes.begin();
+  while (iter != end_node) {
+    if (iter->type == DocNode::TYPE_ATTEMPT) {
+      if (attempt_node != end_node) {
+        _errorLog("[%s] Can have exactly one attempt node in try block", __FUNCTION__);
+        return false;
+      }
+      attempt_node = iter;
+    } else if (iter->type == DocNode::TYPE_EXCEPT) {
+      if (except_node != end_node) {
+        _errorLog("[%s] Can have exactly one except node in try block", __FUNCTION__);
+        return false;
+      }
+      except_node = iter;
+    } else if (iter->type == DocNode::TYPE_PRE) {
+      if (!_isWhitespace(iter->data, iter->data_len)) {
+        _errorLog("[%s] Cannot have non-whitespace raw text as top level node in try block", __FUNCTION__);
+        return false;
+      }
+      _debugLog(_debug_tag.c_str(), "[%s] Ignoring top-level whitespace raw text", __FUNCTION__); 
+      temp_iter = iter;
+      ++temp_iter;
+      try_node.child_nodes.erase(iter);
+      iter = temp_iter;
+      continue; // skip the increment
+    } else {
+      _errorLog("[%s] Only attempt/except/text nodes allowed in try block; [%s] node invalid",
+                __FUNCTION__, DocNode::type_names_[iter->type]);
+      return false;
+    }
+    ++iter;
+  }
+  if ((attempt_node == end_node) || (except_node == end_node)) {
+    _errorLog("[%s] try block must contain one each of attempt and except nodes", __FUNCTION__);
+    return false;
+  }
+  node_list.push_back(try_node);
+  _debugLog(_debug_tag.c_str(), "[%s] Added try node successfully", __FUNCTION__);
+  return true;
+}
+
+bool
+EsiParser::_processChooseTag(const string &data, size_t curr_pos, size_t end_pos,
+                             DocNodeList &node_list) const {
+  const char *data_start_ptr = data.data() + curr_pos;
+  size_t data_size = end_pos - curr_pos;
+  DocNode choose_node(DocNode::TYPE_CHOOSE);
+  if (!parse(choose_node.child_nodes, data_start_ptr, data_size)) {
+    _errorLog("[%s] Couldn't parse choose node content", __FUNCTION__);
+    return false;
+  }
+  DocNodeList::iterator end_node = choose_node.child_nodes.end();
+  DocNodeList::iterator otherwise_node = end_node, iter, temp_iter;
+  iter = choose_node.child_nodes.begin();
+  while (iter != end_node) {
+    if (iter->type == DocNode::TYPE_OTHERWISE) {
+      if (otherwise_node != end_node) {
+        _errorLog("[%s] Cannot have more than one esi:otherwise node in an esi:choose node", __FUNCTION__);
+        return false;
+      }
+      otherwise_node = iter;
+    } else if (iter->type == DocNode::TYPE_PRE) {
+      if (!_isWhitespace(iter->data, iter->data_len)) {
+        _errorLog("[%s] Cannot have non-whitespace raw text as top-level node in choose data",
+                  __FUNCTION__, DocNode::type_names_[iter->type]);
+        return false;
+      }
+      _debugLog(_debug_tag.c_str(), "[%s] Ignoring top-level whitespace raw text", __FUNCTION__); 
+      temp_iter = iter;
+      ++temp_iter;
+      choose_node.child_nodes.erase(iter);
+      iter = temp_iter;
+      continue; // skip the increment
+    } else if (iter->type != DocNode::TYPE_WHEN) {
+      _errorLog("[%s] Cannot have %s as top-level node in choose data; only when/otherwise/whitespace-text "
+                "permitted", __FUNCTION__, DocNode::type_names_[iter->type]);
+      return false;
+    }
+    ++iter;
+  }
+  node_list.push_back(choose_node);
+  return true;
+}
+
+void
+EsiParser::clear() {
+  _data.clear();
+  _parse_start_pos = -1;
+}
+
+EsiParser::~EsiParser() {
+}
+
+inline void
+EsiParser::_adjustPointers(DocNodeList::iterator node_iter, DocNodeList::iterator end,
+                           const char *ext_data_ptr, const char *int_data_start) const {
+  AttributeList::iterator attr_iter;
+  for (; node_iter != end; ++node_iter) {
+    if (node_iter->data_len) {
+      node_iter->data = ext_data_ptr + (node_iter->data - int_data_start);
+    }
+    for (attr_iter = node_iter->attr_list.begin(); attr_iter != node_iter->attr_list.end(); ++attr_iter) {
+      if (attr_iter->name_len) {
+        attr_iter->name = ext_data_ptr + (attr_iter->name - int_data_start);
+      }
+      if (attr_iter->value_len) {
+        attr_iter->value = ext_data_ptr + (attr_iter->value - int_data_start);
+      }
+    }
+    if (node_iter->child_nodes.size()) {
+      _adjustPointers(node_iter->child_nodes.begin(), node_iter->child_nodes.end(),
+                      ext_data_ptr, int_data_start);
+    }
+  }
+}
+
+bool
+EsiParser::parse(DocNodeList &node_list, const char *ext_data_ptr, int data_len /* = -1 */) const {
+  string data;
+  size_t orig_output_list_size;
+  int parse_start_pos = -1;
+  bool retval = _completeParse(data, parse_start_pos, orig_output_list_size, node_list, ext_data_ptr, data_len);
+  if (retval && (node_list.size() - orig_output_list_size)) {
+    // adjust all pointers to addresses in input parameter
+    const char *int_data_start = data.data();
+    DocNodeList::iterator node_iter = node_list.begin();
+    for (size_t i = 0; i < orig_output_list_size; ++i, ++node_iter);
+    _adjustPointers(node_iter, node_list.end(), ext_data_ptr, int_data_start);
+  }
+  return retval;
+}

Added: trafficserver/plugins/trunk/esi/lib/EsiParser.h
URL: http://svn.apache.org/viewvc/trafficserver/plugins/trunk/esi/lib/EsiParser.h?rev=1199388&view=auto
==============================================================================
--- trafficserver/plugins/trunk/esi/lib/EsiParser.h (added)
+++ trafficserver/plugins/trunk/esi/lib/EsiParser.h Tue Nov  8 19:07:20 2011
@@ -0,0 +1,129 @@
+#ifndef _ESI_PARSER_H
+#define _ESI_PARSER_H
+
+#include <string>
+
+#include "ComponentBase.h"
+#include "DocNode.h"
+
+class EsiParser : private EsiLib::ComponentBase
+{
+
+public:
+
+  EsiParser(const char *debug_tag, EsiLib::ComponentBase::Debug debug_func,
+            EsiLib::ComponentBase::Error error_func);
+
+  /** clears state */
+  void clear();
+
+  /** parses a chunk of the document; adds complete nodes found;
+   * data is assumed to be NULL-terminated is data_len is set to -1.
+   *
+   * Output nodes contain pointers to internal data; use with care */
+  bool parseChunk(const char *data, EsiLib::DocNodeList &node_list, int data_len = -1);
+
+  /** convenient alternative to method above */
+  bool parseChunk(const std::string &data, EsiLib::DocNodeList &node_list) {
+    return parseChunk(data.data(), node_list, data.size());
+  };
+
+  /** completes the parse including data from previous chunk(s);
+   * adds newly found nodes to list. optionally a final or the 
+   * only chunk can be provided.
+   *
+   * Output nodes contain pointers to internal data; use with care. */
+  bool completeParse(EsiLib::DocNodeList &node_list, const char *data = 0, int data_len = -1) {
+    return _completeParse(_data, _parse_start_pos, _orig_output_list_size, node_list, data, data_len);
+  }
+  
+  /** convenient alternative to method above */
+  bool completeParse(EsiLib::DocNodeList &node_list, const std::string &data) {
+    return completeParse(node_list, data.data(), data.size());
+  }
+
+  /** stateless method that parses data and returns output nodes that
+   * point to addresses in caller space */
+  bool parse(EsiLib::DocNodeList &node_list, const char *ext_data_ptr, int data_len = -1) const;
+
+  /** convenient alternative to method above */
+  bool parse(EsiLib::DocNodeList &node_list, const std::string &ext_data) const {
+    return parse(node_list, ext_data.data(), ext_data.size());
+  }
+
+  virtual ~EsiParser();
+
+private:
+
+  struct EsiNodeInfo 
+  {
+    EsiLib::DocNode::TYPE type;
+    const char *tag_suffix;
+    int tag_suffix_len;
+    const char *closing_tag;
+    int closing_tag_len; 
+    EsiNodeInfo(EsiLib::DocNode::TYPE t, const char *s, int s_len, const char *ct, int ct_len)
+      : type(t), tag_suffix(s), tag_suffix_len(s_len), closing_tag(ct), closing_tag_len(ct_len) { };
+  };
+  
+  std::string _data;
+  int _parse_start_pos;
+  size_t _orig_output_list_size;
+
+  static const EsiNodeInfo ESI_NODES[];
+  static const EsiNodeInfo HTML_COMMENT_NODE_INFO;
+  
+  static const char *ESI_TAG_PREFIX;
+  static const int ESI_TAG_PREFIX_LEN;
+
+  static const std::string SRC_ATTR_STR;
+  static const std::string TEST_ATTR_STR;
+  static const std::string HANDLER_ATTR_STR;
+
+  static const unsigned int MAX_DOC_SIZE;
+
+  enum MATCH_TYPE { NO_MATCH, COMPLETE_MATCH, PARTIAL_MATCH };
+  
+  MATCH_TYPE _searchData(const std::string &data, size_t start_pos, const char *str, int str_len,
+                         size_t &pos) const;
+
+  MATCH_TYPE _compareData(const std::string &data, size_t pos, const char *str, int str_len) const;
+  
+  MATCH_TYPE _findOpeningTag(const std::string &data, size_t start_pos,
+                             size_t &opening_tag_pos, bool &is_html_comment_node) const;
+
+  bool _parse(const std::string &data, int &parse_start_pos, EsiLib::DocNodeList &node_list,
+              bool last_chunk = false) const;
+  
+  bool _processIncludeTag(const std::string &data, size_t curr_pos, size_t end_pos,
+                          EsiLib::DocNodeList &node_list) const;
+
+  bool _processSpecialIncludeTag(const std::string &data, size_t curr_pos, size_t end_pos,
+                                 EsiLib::DocNodeList &node_list) const;
+
+  inline bool _isWhitespace(const char *data, int data_len) const;
+
+  bool _processWhenTag(const std::string &data, size_t curr_pos, size_t end_pos,
+                       EsiLib::DocNodeList &node_list) const;
+
+  bool _processChooseTag(const std::string &data, size_t curr_pos, size_t end_pos,
+                         EsiLib::DocNodeList &node_list) const;
+
+  bool _processTryTag(const std::string &data, size_t curr_pos, size_t end_pos,
+                      EsiLib::DocNodeList &node_list) const;
+
+  inline bool _processSimpleContentTag(EsiLib::DocNode::TYPE node_type, const char *data, int data_len,
+                                       EsiLib::DocNodeList &node_list) const;
+
+  bool _setup(std::string &data, int &parse_start_pos, size_t &orig_output_list_size,
+              EsiLib::DocNodeList &node_list, const char *data_ptr, int &data_len) const;
+
+  bool _completeParse(std::string &data, int &parse_start_pos, size_t &orig_output_list_size,
+                      EsiLib::DocNodeList &node_list, const char *data_ptr = 0, int data_len = -1) const;
+
+  inline void _adjustPointers(EsiLib::DocNodeList::iterator node_iter, EsiLib::DocNodeList::iterator end,
+                              const char *ext_data_ptr, const char *int_data_start) const;
+
+};
+
+#endif // _ESI_PARSER_H



Mime
View raw message