trafficserver-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From bc...@apache.org
Subject svn commit: r1199398 - in /trafficserver/plugins/trunk/stale_while_revalidate: ./ LICENSE README stale_while_revalidate.conf swr.cpp
Date Tue, 08 Nov 2011 19:27:54 GMT
Author: bcall
Date: Tue Nov  8 19:27:54 2011
New Revision: 1199398

URL: http://svn.apache.org/viewvc?rev=1199398&view=rev
Log:
Stale While Revalidate plugin.  Code came from Yahoo!.

Added:
    trafficserver/plugins/trunk/stale_while_revalidate/
    trafficserver/plugins/trunk/stale_while_revalidate/LICENSE
    trafficserver/plugins/trunk/stale_while_revalidate/README
    trafficserver/plugins/trunk/stale_while_revalidate/stale_while_revalidate.conf
    trafficserver/plugins/trunk/stale_while_revalidate/swr.cpp

Added: trafficserver/plugins/trunk/stale_while_revalidate/LICENSE
URL: http://svn.apache.org/viewvc/trafficserver/plugins/trunk/stale_while_revalidate/LICENSE?rev=1199398&view=auto
==============================================================================
--- trafficserver/plugins/trunk/stale_while_revalidate/LICENSE (added)
+++ trafficserver/plugins/trunk/stale_while_revalidate/LICENSE Tue Nov  8 19:27:54 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/stale_while_revalidate/README
URL: http://svn.apache.org/viewvc/trafficserver/plugins/trunk/stale_while_revalidate/README?rev=1199398&view=auto
==============================================================================
--- trafficserver/plugins/trunk/stale_while_revalidate/README (added)
+++ trafficserver/plugins/trunk/stale_while_revalidate/README Tue Nov  8 19:27:54 2011
@@ -0,0 +1,74 @@
+ytrafficserver plugin to refresh content asynchronously while serving stale data
+
+http://www.mnot.net/drafts/draft-nottingham-http-stale-while-revalidate-00.txt 
+
+Version 0.0.17
+--------------
+* max_age config param added. 
+
+Version 0.0.16
+--------------
+* Pass on connecting IP to HttpConnect
+* use INKHttpIsInternalRequest to check if request is local or not
+
+Version 0.0.15
+------------
+* handle max stale age correctly for only-if-cached + background-fetch
+
+Version 0.0.14
+------------
+* SWR overrides only-if-cached
+* Set cache lookup status to FRESH if within SWR window even for only-if-cached
+
+Version 0.0.13
+------------
+* set cache lookup status to MISS after doing SWR for only-if-cached
+
+Version 0.0.12
+------------
+* Fix for bug [3341089]
+* Support for background fetch on cache miss
+
+Version 0.0.11
+------------
+* Fix for bug [3338245]
+
+Version 0.0.10
+------------
+* use pristine URL in SWR sub request
+
+Version 0.0.9
+------------
+* Respect must-revalidate
+
+Version 0.0.8
+------------
+* Fix for bugs [3260033]
+
+Version 0.0.7
+------------
+* Fix for bugs [3260033 3282115 3275888]
+
+Version 0.0.6
+------------
+* Fix for bug [3263080]
+
+Version 0.0.5
+------------
+* Fix for bug [3262768]
+
+Version 0.0.4
+------------
+* Set cache status after doing SWR
+
+Version 0.0.3
+------------
+* No more time-to-wait support
+
+Version 0.0.2
+-------------
+* Use INKHttpTxnCacheRespGet to get SWR information
+
+Version 0.0.1
+-------------
+* initial version

Added: trafficserver/plugins/trunk/stale_while_revalidate/stale_while_revalidate.conf
URL: http://svn.apache.org/viewvc/trafficserver/plugins/trunk/stale_while_revalidate/stale_while_revalidate.conf?rev=1199398&view=auto
==============================================================================
--- trafficserver/plugins/trunk/stale_while_revalidate/stale_while_revalidate.conf (added)
+++ trafficserver/plugins/trunk/stale_while_revalidate/stale_while_revalidate.conf Tue Nov  8 19:27:54 2011
@@ -0,0 +1,2 @@
+stale_while_revalidate_window             60
+time_to_wait                              10 

Added: trafficserver/plugins/trunk/stale_while_revalidate/swr.cpp
URL: http://svn.apache.org/viewvc/trafficserver/plugins/trunk/stale_while_revalidate/swr.cpp?rev=1199398&view=auto
==============================================================================
--- trafficserver/plugins/trunk/stale_while_revalidate/swr.cpp (added)
+++ trafficserver/plugins/trunk/stale_while_revalidate/swr.cpp Tue Nov  8 19:27:54 2011
@@ -0,0 +1,1206 @@
+/**
+ *   swr.cpp
+ *
+ *   If the cache data has expired but falls within the stale while revalidate window, 
+ *   serve the cached data and make an async request for new data.
+ *
+*/
+
+#include <stdio.h>
+#include <set>
+#include <string>
+#include <sstream>
+#include <iostream>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include "InkAPI.h"
+#include <string.h>
+#include <stdlib.h>
+#include <limits.h>
+
+#define DEBUG 0
+
+static const char SWR_LOG_TAG[] = "http_swr_plugin";
+
+/// Field in Cache control header which defines the SWR window.
+static const char HTTP_VALUE_STALE_WHILE_REVALIDATE[] = "stale-while-revalidate";
+
+/// Field in Cache control header which defines the time to wait for SWR response
+static const char HTTP_VALUE_TIME_TO_WAIT[] = "time-to-wait";
+
+/// Field in Cache control header for background-fetch
+static const char HTTP_VALUE_BACKGROUND_FETCH[] = "background-fetch";
+
+/// This header is added when a SWR request is made.
+/// This is used by the plugin to distinguish between a regular request and a SWR request
+static const char SWR_FETCH_HEADER[] = "X-TS-SWR: 1\r\n\r\n";
+
+/// Can be set with stale_while_revalidate_window config param.
+/// This is overridden by the server's Cache control header.
+static time_t STALE_WHILE_REVALIDATE_WINDOW = 0;
+
+/// Can be set with stale_while_revalidate_window config param.
+/// This is overridden by the server's Cache control header.
+static long STALE_WHILE_REVALIDATE_WINDOW_INFINITE = -1;
+
+/// In milli seconds. Can be set with time_to_wait config param.
+/// Controls the time to wait for asynchronous request to complete before returning stale data.
+static unsigned int TIME_TO_WAIT = 0;
+
+/// Can be set with max_age config param.
+/// This is overridden by the server's Cache control header.
+/// This is needed because some origin servers do not advertise either max-age or mime-field-expires
+static time_t MAX_AGE = 0;
+
+static
+  std::set <
+  std::string >
+  swr_sites_requested;
+static INKMutex swr_mutex = INKMutexCreate();
+
+static const char *SWR_WARNING_HEADER = "110 \"Response is stale\"";
+
+typedef struct
+{
+
+  INKVIO writeVIO;
+  INKVIO readVIO;
+  INKIOBuffer reqBuff;
+  INKIOBufferReader reqReader;
+  INKIOBuffer respBuff;
+  INKIOBufferReader respReader;
+  INKIOBuffer dumpBuff;
+  int iDumpLen;
+
+} FetchData;
+
+struct request_header_values_t
+{
+  bool swr_can_run;
+  bool only_if_cached;
+  bool background_fetch;
+    request_header_values_t();
+};
+
+request_header_values_t::request_header_values_t()
+:
+swr_can_run(true), only_if_cached(false), background_fetch(false)
+{
+
+}
+
+struct response_header_values_t
+{
+  time_t mime_field_expires;
+  long stale_while_revalidate_window;
+  time_t max_age;
+  time_t date;
+  time_t time_to_wait;
+  bool must_revalidate;
+
+  response_header_values_t();
+  void init();
+  time_t get_expiration();
+  time_t get_max_stale_time();
+  time_t get_time_to_wait();
+  long get_swr_window();
+
+};
+
+response_header_values_t::response_header_values_t()
+:
+mime_field_expires(0),
+stale_while_revalidate_window(STALE_WHILE_REVALIDATE_WINDOW), max_age(MAX_AGE), date(0), time_to_wait(TIME_TO_WAIT),
+must_revalidate(false)
+{
+
+}
+
+void
+response_header_values_t::init()
+{
+  mime_field_expires = 0;
+  stale_while_revalidate_window = STALE_WHILE_REVALIDATE_WINDOW;
+  max_age = MAX_AGE;
+  date = 0;
+  time_to_wait = TIME_TO_WAIT;
+}
+
+/**
+* Get expiration time for the page from cache_control header
+* expiration time = date + max_age
+* @param[out] time_t : expiration time for the URL
+*/
+time_t
+response_header_values_t::get_expiration()
+{
+  if (max_age)
+    return date + max_age;
+  else if(mime_field_expires)
+    return mime_field_expires;
+
+  // If max_age and mime_field_expires are 0, expire NOW!
+  return date;
+}
+
+/**
+* Get time until which the page is considered valid.
+* max_stale_time = exp_time + stale_white_revalidate_window
+* @param[out] time_t : time till which the page can be served even if it is past expiration time
+*/
+time_t
+response_header_values_t::get_max_stale_time()
+{
+  time_t expiration_time = get_expiration();
+  if (expiration_time == 0) {
+    return 0;
+  }
+  return (expiration_time + stale_while_revalidate_window);
+}
+
+time_t
+response_header_values_t::get_time_to_wait()
+{
+  return time_to_wait;
+}
+
+long
+response_header_values_t::get_swr_window()
+{
+  return stale_while_revalidate_window;
+}
+
+/**
+* This will be called only in debug mode
+* Dumps out response from origin server
+*/
+static void
+dump_response(INKCont contp)
+{
+
+  FetchData *pData = (FetchData *) INKContDataGet(contp);
+  INKIOBufferReader reader = INKIOBufferReaderAlloc(pData->dumpBuff);
+
+  int iReadTotal = 0;
+  const int BUFF_SIZE = (pData->iDumpLen + 1);
+  char dump[BUFF_SIZE];
+  char *dumpPtr = &dump[0];
+  memset((void *) dumpPtr, 0, BUFF_SIZE);
+
+  int iAvail = INKIOBufferReaderAvail(reader);
+
+  if (iAvail <= 0) {
+    INKDebug(SWR_LOG_TAG, "[swr] nothing to read... ");
+    return;
+  }
+
+
+  INKIOBufferBlock startBlock = INKIOBufferReaderStart(reader);
+
+  while (iAvail > 0 && startBlock != INK_ERROR_PTR) {
+    const char *startPtr = INKIOBufferBlockReadStart(startBlock, reader, &iAvail);
+
+    if (startPtr == INK_ERROR_PTR || iAvail == INK_ERROR) {
+      INKError("[swr] dump: could not get block read starting point \n");
+      break;
+    }
+
+    iReadTotal += iAvail;
+    memcpy((void *) dumpPtr, (void *) startPtr, iAvail);
+    dumpPtr += iAvail;
+    INKIOBufferReaderConsume(reader, iAvail);
+    startBlock = INKIOBufferBlockNext(startBlock);
+    iAvail = INKIOBufferReaderAvail(reader);
+
+    iReadTotal += iAvail;
+    if (iReadTotal > pData->iDumpLen) {
+      INKError
+        ("[swr] dump: read was bigger than expected, aborting. total resp len: %d  wanted to read: %d \n",
+         pData->iDumpLen, iReadTotal);
+      break;
+    }
+  }
+
+  dumpPtr = &dump[0];
+  if (dumpPtr != NULL && strlen(dumpPtr) > 0) {
+    INKDebug(SWR_LOG_TAG, "[swr] dump: successful copy: %s \n", dumpPtr);
+  }
+
+  INKIOBufferReaderFree(reader);
+  return;
+}
+
+/**
+* Read data from VIO
+* Reenable  if there is more data to be read
+*/
+static void
+read_response(INKCont contp)
+{
+  FetchData *pData = (FetchData *) INKContDataGet(contp);
+  if (pData == INK_ERROR_PTR) {
+    INKError("[swr] ERROR could not get data from contp to write fetch");
+    return;
+  }
+
+  int iTodo = INKVIONTodoGet(pData->readVIO);
+  if (iTodo > 0) {
+    int iAvail = INKIOBufferReaderAvail(pData->respReader);
+    if (iAvail == INK_ERROR) {
+      INKError("[swr] could not get avail bytes from read vio, returning");
+      INKVIOReenable(pData->readVIO);
+      return;
+    }
+
+    if (iTodo > iAvail) {
+      iTodo = iAvail;
+    }
+
+    INKDebug(SWR_LOG_TAG, "[swr] going to read in: %d \n", iTodo);
+
+    if (iTodo > 0) {
+      INKIOBufferCopy(pData->dumpBuff, pData->respReader, iTodo, 0);
+
+      // just move pointer in reader, don't actually get data
+      if (INKIOBufferReaderConsume(pData->respReader, iTodo) == INK_ERROR) {
+        INKDebug(SWR_LOG_TAG, "[swr] could not tell resp reader to consume, returning");
+        INKVIOReenable(pData->readVIO);
+        return;
+      }
+      pData->iDumpLen += iTodo;
+      INKDebug(SWR_LOG_TAG, "[swr] bytes to be dumped: %d \n", pData->iDumpLen);
+    }
+
+    iTodo = INKVIONTodoGet(pData->readVIO);
+
+    if (iTodo > 0) {
+      // still have some left to read
+      INKVIOReenable(pData->readVIO);
+      INKDebug(SWR_LOG_TAG, "[swr] more data to read... reenable read vio \n");
+    }
+  }
+
+  return;
+}
+
+/**
+* Write request to server
+*/
+static void
+write_fetch_request(INKCont contp)
+{
+  FetchData *pData = (FetchData *) INKContDataGet(contp);
+
+  if (pData == INK_ERROR_PTR) {
+    INKError("[swr] ERROR could not get data from contp to write fetch");
+    return;
+  }
+
+  int iTodo = INKVIONTodoGet(pData->writeVIO);
+  INKError("[swr] write todo ret: %d", iTodo);
+
+  int iWriteVIONBytes = INKVIONBytesGet(pData->writeVIO);
+  INKDebug(SWR_LOG_TAG, "[swr] writeVIO NBytes ret: %d", iWriteVIONBytes);
+
+
+  if (INKVIOReenable(pData->writeVIO) == INK_ERROR) {
+    INKError("[swr] could not re-enable write vio");
+  }
+
+  return;
+}
+
+static int
+fetch_handler(INKCont contp, INKEvent event, void *edata)
+{
+
+  switch (event) {
+  case INK_EVENT_VCONN_WRITE_READY:
+    {
+      INKDebug(SWR_LOG_TAG, "[swr] FETCH_HANDLER::INK_EVENT_VCONN_WRITE_READY calling write_fetch_request");
+      write_fetch_request(contp);
+      INKDebug(SWR_LOG_TAG, "[swr] FETCH_HANDLER::INK_EVENT_VCONN_WRITE_READY write_fetch_request done");
+      break;
+    }
+
+  case INK_EVENT_VCONN_WRITE_COMPLETE:
+    {
+      INKDebug(SWR_LOG_TAG, "[swr] FETCH_HANDLER::INK_EVENT_VCONN_WRITE_COMPLETE");
+      break;
+    }
+
+  case INK_EVENT_VCONN_READ_READY:
+    {
+      // - there is new data in the read buffer; when we're done reading, re-enable VIO
+      INKDebug(SWR_LOG_TAG, "[swr] FETCH_HANDLER::EVENT_VCONN_READ_READY calling read_response");
+      read_response(contp);
+      INKDebug(SWR_LOG_TAG, "[swr] FETCH_HANDLER::EVENT_VCONN_READ_READY read_response done");
+      break;
+    }
+
+  case INK_EVENT_VCONN_READ_COMPLETE:
+    {
+      // - the VIO has read all the bytes specified by INKVConnRead, vconn can be re-used or tossed
+      INKDebug(SWR_LOG_TAG, "[swr]  FETCH_HANDLER::EVENT_VCONN_READ_COMPLETE");
+      break;
+    }
+
+  case INK_EVENT_VCONN_EOS:
+    {
+      // - occurs when read goes past end of byte stream b/c # bytes specified in VConnRead was bigger
+      INKDebug(SWR_LOG_TAG, "[swr] FETCH_HANDLER::EVENT_VCONN_EOS");
+#if DEBUG
+      dump_response(contp);
+#endif
+
+      FetchData *pData = (FetchData *) INKContDataGet(contp);
+      INKIOBufferDestroy(pData->reqBuff);
+      INKIOBufferDestroy(pData->respBuff);
+      INKIOBufferDestroy(pData->dumpBuff);
+      INKVConn fetchConn = INKVIOVConnGet(pData->writeVIO);
+      INKVConnShutdown(fetchConn, 1, 1);
+      INKVConnClose(fetchConn);
+      delete pData;
+      INKContDestroy(contp);
+
+      break;
+    }
+  case INK_EVENT_ERROR:
+    {
+      INKDebug(SWR_LOG_TAG, "[swr] FETCH_HANDLER::EVENT_ERROR");
+      break;
+    }
+
+  default:
+    {
+      INKDebug(SWR_LOG_TAG, "[swr] FETCH_HANDLER::DEFAULT");
+      break;
+    }
+  }
+
+  return 0;
+}
+
+/**
+* get the request URL
+*/
+static char *
+getURLFromReqHeader(INKHttpTxn & txnp)
+{
+  // MAKE SURE YOU FREE THE RETURNED STRING!
+
+  INKMBuffer req_bufp;
+  INKMLoc hdr_loc;
+  char *url_str;
+  int url_length;
+
+  if (!INKHttpTxnClientReqGet(txnp, &req_bufp, &hdr_loc)) {
+    INKError("[swr] getURLFromReqHeader : couldn't retrieve client response header\n");
+    return NULL;
+  }
+
+  INKMLoc url_loc = INKHttpHdrUrlGet(req_bufp, hdr_loc);
+  if (!url_loc) {
+    INKError("[swr] getURLFromReqHeader : couldn't retrieve request url\n");
+    INKHandleMLocRelease(req_bufp, INK_NULL_MLOC, hdr_loc);
+    return NULL;
+  }
+
+  url_str = INKUrlStringGet(req_bufp, url_loc, &url_length);
+  INKHandleMLocRelease(req_bufp, hdr_loc, url_loc);
+  INKHandleMLocRelease(req_bufp, INK_NULL_MLOC, hdr_loc);
+  return url_str;
+}
+
+/**
+* Check if the req is a Stale while revalidate reques
+* @param[out] bool true if the request is a stale while revalidate request. false otherwise
+*/
+static bool
+isSWR(INKHttpTxn & txnp)
+{
+  INKMBuffer req_bufp;
+  INKMLoc req_loc;
+  bool bRet = false;
+
+  INKHttpTxnClientReqGet(txnp, &req_bufp, &req_loc);
+  INKMLoc swr_loc = NULL;
+  swr_loc = INKMimeHdrFieldFind(req_bufp, req_loc, "X-TS-SWR", strlen("X-TS-SWR"));
+
+  if (swr_loc != INK_ERROR_PTR && swr_loc != NULL) {
+    bRet = true;
+    INKDebug(SWR_LOG_TAG, "[swr] Request is Stale while revalidate");
+  } else {
+    INKDebug(SWR_LOG_TAG, "[swr] Request NOT Stale while revalidate");
+  }
+
+  INKHandleMLocRelease(req_bufp, req_loc, swr_loc);
+  INKHandleMLocRelease(req_bufp, INK_NULL_MLOC, req_loc);
+
+  return bRet;
+}
+
+
+/**
+   
+*/
+static void
+deleteFromHeader(INKMBuffer & req_bufp, INKMLoc & req_loc, const char *header, const char *field, int field_len)
+{
+  INKDebug(SWR_LOG_TAG, "[swr] deleteFromHeader trying to remove from %s : %s ", header, field);
+  INKMLoc header_loc, dup_header_loc;
+  const char *value;
+
+  header_loc = INKMimeHdrFieldFind(req_bufp, req_loc, header, -1);
+  while (header_loc != INK_ERROR_PTR && header_loc != 0) {
+    int nvalues = INKMimeFieldValuesCount(req_bufp, header_loc);
+    for (int i = 0; i < nvalues; i++) {
+      int value_len;
+      value = INKMimeFieldValueGet(req_bufp, header_loc, i, &value_len);
+      if (value_len == field_len && strncasecmp(value, field, field_len) == 0) {
+        INKDebug(SWR_LOG_TAG, "[swr] deleteFromHeader : %s, %s ", header, field);
+        INKMimeHdrFieldValueDelete(req_bufp, req_loc, header_loc, i);
+      }
+
+      INKHandleStringRelease(req_bufp, header_loc, value);
+    }
+
+    // Get next header
+    dup_header_loc = INKMimeHdrFieldNextDup(req_bufp, req_loc, header_loc);
+    INKHandleMLocRelease(req_bufp, req_loc, header_loc);
+    header_loc = dup_header_loc;
+  }
+
+  INKHandleMLocRelease(req_bufp, INK_NULL_MLOC, req_loc);
+}
+
+/**
+* Send request to self
+* Add special SWR_FETCH_HEADER so that this can be differntiated from other requests
+*/
+static bool
+sendRequestToSelf(INKHttpTxn &txnp, response_header_values_t &my_state)
+{
+  INKDebug(SWR_LOG_TAG, "[swr] sendRequestToSelf called");
+  INKVConn fetchOnDemandVC;
+  bool ret = true;
+
+  unsigned int client_ip = INKHttpTxnClientIPGet(txnp);
+  if (INKHttpConnect(htonl(client_ip), 9999, &fetchOnDemandVC) != INK_ERROR) {
+    // writer needs: request to write, 
+    INKCont fetchCont = INKContCreate(fetch_handler, INKMutexCreate());
+    FetchData *pData = new FetchData();
+    if (pData) {
+      INKContDataSet(fetchCont, pData);
+
+      // Create req and resp buffers for background fetch
+      pData->iDumpLen = 0;
+      pData->reqBuff = INKIOBufferCreate();
+      pData->reqReader = INKIOBufferReaderAlloc(pData->reqBuff);
+
+      pData->respBuff = INKIOBufferCreate();
+      pData->respReader = INKIOBufferReaderAlloc(pData->respBuff);
+      pData->dumpBuff = INKIOBufferCreate();
+
+      // get the original request with headers and copy to the background fetch request
+      INKMBuffer req_bufp;
+      INKMLoc req_loc;
+      INKIOBuffer reqBuff;
+      INKIOBufferReader reqReader;
+      int block_avail;
+
+      reqBuff = INKIOBufferCreate();
+      reqReader = INKIOBufferReaderAlloc(reqBuff);
+      INKHttpTxnClientReqGet(txnp, &req_bufp, &req_loc);
+
+      // Get pristine URL
+      INKMLoc pristine_url_loc;
+ 
+      if (INKHttpTxnPristineUrlGet(txnp, &req_bufp, &pristine_url_loc) != INK_ERROR) {
+        // Set pristine URL in request
+        INKDebug(SWR_LOG_TAG, "[swr] setting pristine URL in request");
+        INKHttpHdrUrlSet(req_bufp, req_loc, pristine_url_loc);
+      }
+      // write original header to background fetch request
+      if (INKHttpHdrPrint(req_bufp, req_loc, reqBuff) == INK_ERROR) {
+        INKDebug(SWR_LOG_TAG, "[swr] INKHttpHdrPrint failed");
+        ret = false;
+      } else {
+        INKDebug(SWR_LOG_TAG, "[swr] INKHttpHdrPrint succeeded");
+        if (INKIOBufferReaderAvail(reqReader)) {
+          INKIOBufferBlock block = INKIOBufferReaderStart(reqReader);
+          while (1) {
+            const char *block_start;
+            block_start = INKIOBufferBlockReadStart(block, reqReader, &block_avail);
+            if ((block = INKIOBufferBlockNext(block)) != NULL) {
+              INKIOBufferWrite(pData->reqBuff, block_start, block_avail);
+            } else {
+              // need to truncate the very last newline character as we need to add 
+              // a couple of more headers. (the last newline is treated as terminator)
+              if (block_start[block_avail - 1] == '\n' && block_start[block_avail - 2] == '\r')
+                INKIOBufferWrite(pData->reqBuff, block_start, block_avail - 2);
+              else
+                INKIOBufferWrite(pData->reqBuff, block_start, block_avail - 1);
+              break;
+            }
+          }
+
+          // add a If-Modified-Since header so traffic server will update the cache instead of replacing the entry
+          INKMLoc ims = INKMimeHdrFieldCreate(req_bufp, req_loc);
+          INKMimeFieldNameSet(req_bufp, ims, INK_MIME_FIELD_IF_MODIFIED_SINCE, INK_MIME_LEN_IF_MODIFIED_SINCE);
+          INKMimeHdrFieldValueDateSet(req_bufp, req_loc, ims, my_state.date);
+
+          if (INKIOBufferWrite(pData->reqBuff, SWR_FETCH_HEADER, strlen(SWR_FETCH_HEADER)) == INK_ERROR) {
+            ret = false;
+            INKDebug(SWR_LOG_TAG, "[swr] could not write req to buffer");
+          }
+#if 1
+          block = INKIOBufferReaderStart(pData->reqReader);
+          const char *block_start = INKIOBufferBlockReadStart(block, pData->reqReader,
+                                                              &block_avail);
+          int size = INKIOBufferBlockReadAvail(block, pData->reqReader);
+          INKDebug(SWR_LOG_TAG, "[swr] request string: %.*s", size, block_start);
+#endif
+        }
+      }
+
+      pData->writeVIO = INKVConnWrite(fetchOnDemandVC,
+                                      fetchCont, pData->reqReader, INKIOBufferReaderAvail(pData->reqReader));
+      pData->readVIO = INKVConnRead(fetchOnDemandVC, fetchCont, pData->respBuff, INT_MAX);
+
+      // Release stuff
+      INKIOBufferReaderFree(reqReader);
+      INKIOBufferDestroy(reqBuff);
+      INKHandleMLocRelease(req_bufp, INK_NULL_MLOC, req_loc);
+    } else {
+      ret = false;
+      INKDebug(SWR_LOG_TAG, "[swr] problem creating continuation");
+      INKContDestroy(fetchCont);
+      INKVConnShutdown(fetchOnDemandVC, 0, 0);
+    }
+  } else {
+    ret = false;
+    INKError("[swr] problem doing http connect");
+  }
+  INKDebug(SWR_LOG_TAG, "[swr] sendRequestToSelf ends");
+
+  return ret;
+}
+
+/**
+* Set cache lookup status to whatever is passed in
+*/
+static void
+setCacheStatus(INKHttpTxn & txnp, int lookupStatus)
+{
+  // Set cache status to FRESH
+  INKDebug(SWR_LOG_TAG, "[swr] setCacheStatusFresh : setting cache hit status to %d", lookupStatus);
+  INKHttpTxnCacheLookupStatusSet(txnp, lookupStatus);
+}
+
+/**
+* Add warning header to indicate that response is stale
+*/
+static bool
+addSWRWarningHeader(INKHttpTxn & txnp)
+{
+  INKMBuffer bufp = NULL;
+  INKMLoc hdr_loc = NULL;
+  INKMLoc field_loc = NULL;
+  bool new_field = false;
+  if (!INKHttpTxnClientRespGet(txnp, &bufp, &hdr_loc)) {
+    INKHandleMLocRelease(bufp, INK_NULL_MLOC, hdr_loc);
+    INKDebug(SWR_LOG_TAG, "addSWRWarningHeader : Could not get server response");
+    return false;
+  }
+  INKDebug(SWR_LOG_TAG, "addSWRWarningHeader : trying to add header");
+
+  // look for the field first
+  if ((field_loc = INKMimeHdrFieldFind(bufp, hdr_loc, INK_MIME_FIELD_WARNING, INK_MIME_LEN_WARNING)) == NULL) {
+    // "set" or "append", need to create the field first
+    field_loc = INKMimeHdrFieldCreate(bufp, hdr_loc);
+    INKMimeHdrFieldNameSet(bufp, hdr_loc, field_loc, INK_MIME_FIELD_WARNING, INK_MIME_LEN_WARNING);
+    new_field = true;
+  }
+  // append the value at the end
+  INKMimeHdrFieldValueStringInsert(bufp, hdr_loc, field_loc, -1, SWR_WARNING_HEADER, strlen(SWR_WARNING_HEADER));
+
+  if (new_field) {
+    // append the new field
+    INKMimeHdrFieldAppend(bufp, hdr_loc, field_loc);
+  }
+
+  INKHandleMLocRelease(bufp, hdr_loc, field_loc);
+  INKHandleMLocRelease(bufp, INK_NULL_MLOC, hdr_loc);
+  INKDebug(SWR_LOG_TAG, "addSWRWarningHeader : done");
+  return true;
+}
+
+/**
+* looks for no-cache directive from the client
+*/
+static void
+parseRequestHeaders(INKHttpTxn & txnp, request_header_values_t & my_state)
+{
+  INKDebug(SWR_LOG_TAG, "[swr] parseRequestHeaders called");
+  INKMBuffer req_bufp;
+  INKMLoc req_loc;
+  const char *value;
+
+  if (!INKHttpTxnClientReqGet(txnp, &req_bufp, &req_loc)) {
+    INKError("[swr] parseRequestHeaders : couldn't retrieve client request header.");
+    return;
+  }
+
+  INKMLoc cache_control_loc, dup_cache_control_loc;
+  cache_control_loc = INKMimeHdrFieldFind(req_bufp, req_loc, "Cache-Control", -1);
+  while (cache_control_loc != INK_ERROR_PTR && cache_control_loc != 0) {
+    int nvalues = INKMimeFieldValuesCount(req_bufp, cache_control_loc);
+    for (int i = 0; i < nvalues; i++) {
+      int value_len;
+      value = INKMimeFieldValueGet(req_bufp, cache_control_loc, i, &value_len);
+      if (value_len == INK_HTTP_LEN_NO_CACHE && strncasecmp(value, INK_HTTP_VALUE_NO_CACHE, INK_HTTP_LEN_NO_CACHE) == 0) {
+        INKDebug(SWR_LOG_TAG, "[swr] parseRequestHeader : set swr_can_run to false");
+        my_state.swr_can_run = false;
+      } else if (value_len == INK_HTTP_LEN_ONLY_IF_CACHED &&
+                 strncasecmp(value, INK_HTTP_VALUE_ONLY_IF_CACHED, INK_HTTP_LEN_ONLY_IF_CACHED) == 0) {
+        INKDebug(SWR_LOG_TAG, "[swr] parseRequestHeader : set only_if_cached to true");
+        my_state.only_if_cached = true;
+      } else if (value_len == (int) strlen(HTTP_VALUE_BACKGROUND_FETCH) &&
+                 strncasecmp(value, HTTP_VALUE_BACKGROUND_FETCH, strlen(HTTP_VALUE_BACKGROUND_FETCH)) == 0) {
+        INKDebug(SWR_LOG_TAG, "[swr] parseRequestHeader : set background_fetch to true");
+        my_state.background_fetch = true;
+      }
+
+      INKHandleStringRelease(req_bufp, cache_control_loc, value);
+    }
+
+    // Get next Cache-Control header
+    dup_cache_control_loc = INKMimeHdrFieldNextDup(req_bufp, req_loc, cache_control_loc);
+    INKHandleMLocRelease(req_bufp, req_loc, cache_control_loc);
+    cache_control_loc = dup_cache_control_loc;
+  }
+
+  INKHandleMLocRelease(req_bufp, INK_NULL_MLOC, req_loc);
+  INKDebug(SWR_LOG_TAG, "[swr] parseRequestHeaders ends");
+}
+
+/**
+* looks for max-age, stale-while-revalidate, time-to-wait, must-revalidate 
+*/
+static void
+parseResponseHeaders(INKHttpTxn & txnp, response_header_values_t & my_state)
+{
+  INKMBuffer resp_bufp;
+  INKMLoc resp_loc;
+  const char *value;
+
+  if (!INKHttpTxnCachedRespGet(txnp, &resp_bufp, &resp_loc)) {
+    INKError("[swr] parseResponseHeaders : couldn't retrieve server response header.");
+    return;
+  }
+
+  INKMLoc date_loc;
+  date_loc = INKMimeHdrFieldFind(resp_bufp, resp_loc, INK_MIME_FIELD_DATE, INK_MIME_LEN_DATE);
+  if (date_loc != INK_ERROR_PTR && date_loc != 0) {
+    INKMimeHdrFieldValueDateGet(resp_bufp, resp_loc, date_loc, &my_state.date);
+    INKHandleMLocRelease(resp_bufp, resp_loc, date_loc);
+  }
+
+  INKMLoc cache_control_loc, dup_cache_control_loc;
+  cache_control_loc =
+    INKMimeHdrFieldFind(resp_bufp, resp_loc, INK_MIME_FIELD_CACHE_CONTROL, INK_MIME_LEN_CACHE_CONTROL);
+  while (cache_control_loc != INK_ERROR_PTR && cache_control_loc != 0) {
+    int nvalues = INKMimeFieldValuesCount(resp_bufp, cache_control_loc);
+    for (int i = 0; i < nvalues; i++) {
+      int value_len;
+      value = INKMimeFieldValueGet(resp_bufp, cache_control_loc, i, &value_len);
+      if (value_len >= INK_HTTP_LEN_MAX_AGE + 2) {      // +2 - one for =, atleast another for a number
+        const char *ptr;
+        if (ptr = strcasestr(value, INK_HTTP_VALUE_MAX_AGE)) {
+          ptr += INK_HTTP_LEN_MAX_AGE;
+          if (*ptr == '=') {
+            ptr++;
+            my_state.max_age = atol(ptr);
+          }
+        }
+      }
+
+      if (value_len >= (int) strlen(HTTP_VALUE_STALE_WHILE_REVALIDATE) + 2) {   // +2 - one for =, atleast another for a number
+        const char *ptr;
+        if (ptr = strcasestr(value, HTTP_VALUE_STALE_WHILE_REVALIDATE)) {
+          ptr += strlen(HTTP_VALUE_STALE_WHILE_REVALIDATE);
+          if (*ptr == '=') {
+            ptr++;
+            my_state.stale_while_revalidate_window = atol(ptr);
+          }
+        }
+      }
+
+      if (value_len >= (int) strlen(HTTP_VALUE_TIME_TO_WAIT) + 2) {     //  +2 - one for =, atleast another for a number
+        const char *ptr;
+        if (ptr = strcasestr(value, HTTP_VALUE_TIME_TO_WAIT)) {
+          ptr += strlen(HTTP_VALUE_TIME_TO_WAIT);
+          if (*ptr == '=') {
+            ptr++;
+            my_state.time_to_wait = atol(ptr);
+          }
+        }
+      }
+
+      if (value_len == INK_HTTP_LEN_MUST_REVALIDATE &&
+          strncasecmp(value, INK_HTTP_VALUE_MUST_REVALIDATE, INK_HTTP_LEN_MUST_REVALIDATE) == 0) {
+        my_state.must_revalidate = true;
+      }
+
+      if (value_len == INK_HTTP_LEN_PROXY_REVALIDATE &&
+          strncasecmp(value, INK_HTTP_VALUE_PROXY_REVALIDATE, INK_HTTP_LEN_PROXY_REVALIDATE) == 0) {
+        my_state.must_revalidate = true;
+      }
+
+      INKHandleStringRelease(resp_bufp, cache_control_loc, value);
+    }
+
+    // Get next Cache-Control header
+    dup_cache_control_loc = INKMimeHdrFieldNextDup(resp_bufp, resp_loc, cache_control_loc);
+    INKHandleMLocRelease(resp_bufp, resp_loc, cache_control_loc);
+    cache_control_loc = dup_cache_control_loc;
+  }
+
+  INKMLoc mime_field_expires_loc;
+  mime_field_expires_loc = INKMimeHdrFieldFind(resp_bufp, resp_loc, INK_MIME_FIELD_EXPIRES, INK_MIME_LEN_EXPIRES);
+  if (mime_field_expires_loc != INK_ERROR_PTR && mime_field_expires_loc != 0) {
+    INKMimeHdrFieldValueDateGet(resp_bufp, resp_loc, mime_field_expires_loc, &my_state.mime_field_expires);
+    INKHandleMLocRelease(resp_bufp, resp_loc, mime_field_expires_loc);
+  }
+
+  INKHandleMLocRelease(resp_bufp, INK_NULL_MLOC, resp_loc);
+  INKDebug(SWR_LOG_TAG,
+           "[swr] parseResponseHeaders : mime_field_expires=%ld, stale_while_revalidate_window=%ld, max_age=%ld, date=%ld, time_to_wait=%ld",
+           my_state.mime_field_expires, my_state.stale_while_revalidate_window, my_state.max_age, my_state.date,
+           my_state.time_to_wait);
+}
+
+/**
+* This function gets called only if (curr_time > exp_time)
+* Logic
+*     if ((curr_time<=max stale time)) && (req is not a SWR req))
+*     {
+*         if(no one else has made async req for URL)
+*         {
+*             make async req to self for the URL;
+*         }    
+*         return stale data from cache;
+*     }
+*     else
+*     {
+*         nothing special needs to be done
+*     }
+*  @param[out] int. 0 : Do not serve stale data, as SWR was off or time is past max_stale_time
+*  @param[out] int. 1 : Serve stale data as SWR was done
+*/
+static int
+doStaleWhileRevalidate(INKCont & contp, void *edata, response_header_values_t & my_state)
+{
+  INKHttpTxn txnp = (INKHttpTxn) edata;
+  INKDebug(SWR_LOG_TAG, "[swr] doStaleWhileRevalidate : Started");
+
+  long swr_window = my_state.get_swr_window();
+  if (swr_window == 0) {
+    INKDebug(SWR_LOG_TAG, "[swr] doStaleWhileRevalidate : turned OFF");
+    return 0;
+  }
+  int retval = 0;
+  time_t curr_time = INKhrtime() / 1000000000;
+  time_t max_stale_time = my_state.get_max_stale_time();
+
+  time_t diff = max_stale_time - curr_time;
+  INKDebug(SWR_LOG_TAG,
+           "[swr] doStaleWhileRevalidate : curr_time=%ld, max_stale_time=%ld, diff=%ld",
+           curr_time, max_stale_time, diff);
+  if (diff > 0 || swr_window == STALE_WHILE_REVALIDATE_WINDOW_INFINITE) {
+    if (!isSWR(txnp)) {
+      // If no one else has made the request or is making the request,
+      // Send request to self after adding special header
+
+      char *url = getURLFromReqHeader(txnp);
+      if (url == NULL) {
+        INKError("[swr] doStaleWhileRevalidate : url is NULL");
+        return 0;
+      }
+      // retval to indicate that stale data must be served
+      retval = 1;
+      bool useTimeToWait = true;
+      INKDebug(SWR_LOG_TAG, "[swr] doStaleWhileRevalidate : url=%s", url);
+      if (INKMutexLock(swr_mutex) == INK_SUCCESS) {
+        // Check again after getting the mutex lock as someone else might have requested the URL in the interim
+        if (swr_sites_requested.find(url) == swr_sites_requested.end()) {
+          INKDebug(SWR_LOG_TAG, "[swr] doStaleWhileRevalidate : sending req to self. inserting URL=%s", url);
+
+          // insert URL into sites requested and unlock mutex
+          swr_sites_requested.insert(url);
+          INKMutexUnlock(swr_mutex);
+
+          if (!sendRequestToSelf(txnp, my_state)) {
+            // If sending request to self failed, do not use time for wait
+            // remove URL from sites requested  
+            useTimeToWait = false;
+            if (INKMutexLock(swr_mutex) == INK_SUCCESS) {
+              INKDebug(SWR_LOG_TAG, "[swr] doStaleWhileRevalidate : removing url=%s", url);
+              swr_sites_requested.erase(url);
+              INKMutexUnlock(swr_mutex);
+            }
+          }
+        } else {
+          INKDebug(SWR_LOG_TAG, "[swr] doStaleWhileRevalidate : some one else is requesting URL=%s", url);
+          INKMutexUnlock(swr_mutex);
+          useTimeToWait = false;
+        }
+      } else {
+        useTimeToWait = false;
+      }
+      INKfree((void *) url);
+
+      // wait for time-to-wait milli secs and then set cache lookup status to fresh.
+      // this will give the async request some time to complete.
+      //FIXME 
+      //Commenting out time to wait code as this cannot be implemented easily now
+      /*
+         if (useTimeToWait) {
+         time_t time_to_wait = my_state.get_time_to_wait();
+         INKDebug(SWR_LOG_TAG, "[swr] doStaleWhileRevalidate scheduling continuation after %ld ms", time_to_wait);
+         INKHttpSchedule(contp, txnp, time_to_wait);
+         retval = 2;
+         }
+       */
+
+    } else {
+      INKDebug(SWR_LOG_TAG,
+               "[swr] doStaleWhileRevalidate : swr request received. nothing to do.");
+    }
+  } else {
+    INKDebug(SWR_LOG_TAG, "[swr] doStaleWhileRevalidate : Not doing SWR, as cache data has expired");
+  }
+  INKDebug(SWR_LOG_TAG, "[swr] doStaleWhileRevalidate : Ends");
+  return retval;
+}
+
+/**
+* Remove URL from set of URLs being requested asynchronously
+*/
+static void
+removeURLFromSitesRequested(INKHttpTxn & txnp)
+{
+  char *url = getURLFromReqHeader(txnp);
+  if (url == NULL) {
+    INKError("[swr] removeURLFromSitesRequested : url is NULL");
+    return;
+  }
+  if (INKMutexLock(swr_mutex) != INK_ERROR) {
+    INKDebug(SWR_LOG_TAG, "[swr] removeURLFromSitesRequested : removing url=%s", url);
+    swr_sites_requested.erase(url);
+    INKMutexUnlock(swr_mutex);
+  }
+  INKfree((void *) url);
+}
+
+
+static bool
+isRequestFromLocalhost(INKHttpTxn & txnp)
+{
+    INKDebug(SWR_LOG_TAG, "[swr] isRequestFromLocalhost returning : %d", INKHttpIsInternalRequest(txnp));
+    return INKHttpIsInternalRequest(txnp);
+}
+
+static void
+ignoreOnlyIfCached(INKHttpTxn & txnp)
+{
+  // Delete only-if-cached from Cache-Control
+  INKMBuffer req_bufp;
+  INKMLoc req_loc;
+  INKHttpTxnClientReqGet(txnp, &req_bufp, &req_loc);
+  deleteFromHeader(req_bufp, req_loc, "Cache-Control", INK_HTTP_VALUE_ONLY_IF_CACHED, INK_HTTP_LEN_ONLY_IF_CACHED);
+  INKHandleMLocRelease(req_bufp, INK_NULL_MLOC, req_loc);
+}
+
+static int
+plugin_worker_handler(INKCont contp, INKEvent event, void *edata)
+{
+  switch (event) {
+  case INK_EVENT_HTTP_READ_REQUEST_HDR:
+    {
+      INKDebug(SWR_LOG_TAG, "[swr] MAIN_HANDLER::INK_HTTP_READ_REQUEST_HDR_HOOK");
+      INKHttpTxn txnp = (INKHttpTxn) edata;
+      request_header_values_t pstate;
+
+      parseRequestHeaders(txnp, pstate);
+      // skip RWW if request is SWR and is from localhost
+      if (isSWR(txnp) && isRequestFromLocalhost(txnp)) {
+        INKDebug(SWR_LOG_TAG, "[swr] Disable RWW as this is a SWR request from localhost");
+        INKHttpTxnSkipRww(txnp);
+      }
+
+      if (pstate.swr_can_run) {
+        // Add hook only if SWR can run
+        INKHttpTxnHookAdd(txnp, INK_HTTP_CACHE_LOOKUP_COMPLETE_HOOK, contp);
+      }
+
+      INKHttpTxnReenable(txnp, INK_EVENT_HTTP_CONTINUE);
+      break;
+    }
+  case INK_EVENT_HTTP_SEND_RESPONSE_HDR:
+    {
+      INKDebug(SWR_LOG_TAG, "[swr] MAIN_HANDLER::INK_HTTP_SEND_RESPONSE_HDR_HOOK");
+      INKHttpTxn txnp = (INKHttpTxn) edata;
+      addSWRWarningHeader(txnp);
+      INKHttpTxnReenable(txnp, INK_EVENT_HTTP_CONTINUE);
+      INKDebug(SWR_LOG_TAG, "[swr] MAIN_HANDLER::INK_HTTP_SEND_RESPONSE_HDR ends");
+      break;
+    }
+  case INK_EVENT_HTTP_CACHE_LOOKUP_COMPLETE:
+    {
+      INKHttpTxn txnp = (INKHttpTxn) edata;
+      INKDebug(SWR_LOG_TAG, "[swr] MAIN_HANDLER::INK_HTTP_CACHE_LOOKUP_COMPLETE_HOOK");
+
+      int lookupStatus = 0;
+      if (INKHttpTxnCacheLookupStatusGet(txnp, &lookupStatus) != INK_SUCCESS) {
+        INKDebug(SWR_LOG_TAG, "[swr] cache status get failure");
+      } else {
+        request_header_values_t pstate;
+        bool is_swr_request = false;
+        if (lookupStatus == INK_CACHE_LOOKUP_MISS || lookupStatus == INK_CACHE_LOOKUP_HIT_STALE) {
+          parseRequestHeaders(txnp, pstate);
+          is_swr_request = isSWR(txnp);
+        }
+
+        if (lookupStatus == INK_CACHE_LOOKUP_MISS) {
+          INKDebug(SWR_LOG_TAG, "[swr] cache status MISS");
+          // Code for background fetch on miss if only_if_cached and background_fetch are set by the client
+          if (!is_swr_request) {
+            if (pstate.only_if_cached && pstate.background_fetch) {
+              // Do background fetch only if client Cache-Control has both only-if-cached and background-fetch
+              response_header_values_t resp_values;
+              resp_values.init();
+              resp_values.stale_while_revalidate_window = STALE_WHILE_REVALIDATE_WINDOW_INFINITE;
+              INKDebug(SWR_LOG_TAG, "[swr] doing background fetch");
+              // Ignore return value in this case as we do not want a warning header
+              doStaleWhileRevalidate(contp, edata, resp_values);
+            }
+          } else {
+            // SWR request. Handle background fetch request
+            if (pstate.only_if_cached && pstate.background_fetch) {
+              // Delete only-if-cached from Cache-Control
+              // This will force the core to make a req to the OS
+              INKDebug(SWR_LOG_TAG, "[swr] ignoreOnlyIfCached");
+              ignoreOnlyIfCached(txnp);
+            }
+          }
+        } else if (lookupStatus == INK_CACHE_LOOKUP_HIT_STALE) {
+          INKDebug(SWR_LOG_TAG, "[swr] cache status HIT STALE");
+
+          if (!is_swr_request) {
+
+            response_header_values_t my_state;
+            my_state.init();
+            parseResponseHeaders(txnp, my_state);
+            bool forced_background_fetch = false;
+            if (pstate.only_if_cached && pstate.background_fetch) {
+                // Force background fetch only if document age is within max_stale_time
+                time_t curr_time = INKhrtime() / 1000000000;
+                time_t max_stale_time = my_state.get_max_stale_time();
+                time_t diff = max_stale_time - curr_time;
+                if(diff < 0) {
+                    forced_background_fetch = true;
+                }
+                my_state.stale_while_revalidate_window = STALE_WHILE_REVALIDATE_WINDOW_INFINITE;
+            }
+
+            if (my_state.must_revalidate == false && doStaleWhileRevalidate(contp, edata, my_state) == 1 && !forced_background_fetch) {
+              setCacheStatus(txnp, INK_CACHE_LOOKUP_HIT_FRESH);
+              INKHttpTxnHookAdd(txnp, INK_HTTP_SEND_RESPONSE_HDR_HOOK, contp);
+            } else {
+              INKDebug(SWR_LOG_TAG, "[swr] Not serving stale data");
+              if (pstate.only_if_cached) {
+                // Set cache status to miss
+                // must return an error
+                setCacheStatus(txnp, INK_CACHE_LOOKUP_MISS);
+              }
+            }
+          } else {
+            // SWR request. Handle background fetch request
+            if (pstate.only_if_cached && pstate.background_fetch) {
+              // Delete only-if-cached from Cache-Control
+              // This will force the core to make a req to the OS
+              INKDebug(SWR_LOG_TAG, "[swr] ignoreOnlyIfCached");
+              ignoreOnlyIfCached(txnp);
+            }
+          }
+          //FIXME
+          //The code below should be used when time to wait can be implemented correctly
+          /*
+             if (doStaleWhileRevalidate(contp, event, edata)) {
+             // If doStaleWhileRevalidate returns true, there is an async request happening to OS.
+             // Do not reenable continuation.
+             // Wait for timeout
+             break;
+             }
+           */
+        } else if (lookupStatus == INK_CACHE_LOOKUP_HIT_FRESH) {
+          INKDebug(SWR_LOG_TAG, "[swr] cache status HIT FRESH");
+        } else if (lookupStatus == INK_CACHE_LOOKUP_SKIPPED) {
+          INKDebug(SWR_LOG_TAG, "[swr] cache status SKIPPED");
+        }
+      }
+      INKHttpTxnReenable(txnp, INK_EVENT_HTTP_CONTINUE);
+      INKDebug(SWR_LOG_TAG, "[swr] MAIN_HANDLER::INK_HTTP_CACHE_LOOKUP_COMPLETE_HOOK ends");
+      break;
+    }
+  case INK_EVENT_HTTP_TXN_CLOSE:
+    {
+      INKHttpTxn txnp = (INKHttpTxn) edata;
+      INKDebug(SWR_LOG_TAG, "[swr] MAIN_HANDLER::INK_HTTP_TXN_CLOSE_HOOK");
+      if (isSWR(txnp)) {
+        removeURLFromSitesRequested(txnp);
+      }
+      INKHttpTxnReenable(txnp, INK_EVENT_HTTP_CONTINUE);
+      INKContDestroy(contp);
+      INKDebug(SWR_LOG_TAG, "[swr] MAIN_HANDLER::INK_HTTP_TXN_CLOSE_HOOK ends");
+      break;
+    }
+    //FIXME
+    //The code below should be used when time to wait can be implemented correctly
+    /*
+       case INK_EVENT_IMMEDIATE:
+       {
+       // TIME_TO_WAIT was 0
+       INKDebug(SWR_LOG_TAG, "[swr] MAIN_HANDLER::INK_EVENT_IMMEDIATE_HOOK TIME_TO_WAIT was 0");
+       INKHttpTxn txnp = (INKHttpTxn) edata;
+       setCacheStatus(txnp, INK_CACHE_LOOKUP_HIT_FRESH);
+       INKHttpTxnReenable(txnp, INK_EVENT_HTTP_CONTINUE);
+       INKDebug(SWR_LOG_TAG, "[swr] MAIN_HANDLER::INK_EVENT_IMMEDIATE_HOOK ends");
+       break;
+       }
+       case INK_EVENT_TIMEOUT:
+       {
+       // We have waited long enough for the async request to complete
+       INKDebug(SWR_LOG_TAG, "[swr] MAIN_HANDLER::INK_EVENT_TIMEOUT_HOOK done waiting for response");
+       INKHttpTxn txnp = (INKHttpTxn) edata;
+       setCacheStatus(txnp, INK_CACHE_LOOKUP_HIT_FRESH);
+       INKDebug(SWR_LOG_TAG, "[swr] MAIN_HANDLER::INK_EVENT_TIMEOUT_HOOK txnp = %u", txnp);
+       INKHttpTxnReenable(txnp, INK_EVENT_HTTP_CONTINUE);
+       INKDebug(SWR_LOG_TAG, "[swr] MAIN_HANDLER::INK_EVENT_TIMEOUT_HOOK ends");
+       break;
+       }
+     */
+  default:
+    {
+      INKHttpTxn txnp = (INKHttpTxn) edata;
+      INKDebug(SWR_LOG_TAG, "[swr] default event");
+      INKHttpTxnReenable(txnp, INK_EVENT_HTTP_CONTINUE);
+      break;
+    }
+  }
+
+  return 1;
+}
+
+static int
+plugin_main_handler(INKCont contp, INKEvent event, void *edata)
+{
+  switch (event) {
+  case INK_EVENT_HTTP_TXN_START:
+    {
+      INKDebug(SWR_LOG_TAG, "[swr] MAIN_HANDLER::INK_HTTP_READ_REQUEST_HDR_HOOK");
+      INKHttpTxn txnp = (INKHttpTxn) edata;
+
+      // Create new continuation
+      INKCont workerCont = INKContCreate(plugin_worker_handler, NULL);
+
+      // Add local hooks for the new continuation
+      INKHttpTxnHookAdd(txnp, INK_HTTP_READ_REQUEST_HDR_HOOK, workerCont);
+      INKHttpTxnHookAdd(txnp, INK_HTTP_TXN_CLOSE_HOOK, workerCont);
+      INKHttpTxnReenable(txnp, INK_EVENT_HTTP_CONTINUE);
+      break;
+    }
+  default:
+    {
+      INKDebug(SWR_LOG_TAG, "[swr] default event");
+      INKHttpTxn txnp = (INKHttpTxn) edata;
+      INKHttpTxnReenable(txnp, INK_EVENT_HTTP_CONTINUE);
+      break;
+    }
+  }
+
+  return 1;
+}
+
+static void
+parse_config_line(char *line)
+{
+  std::istringstream conf_line(line);
+
+  std::string key, value;
+  conf_line >> key;
+  conf_line >> value;
+  if (key.empty() || value.empty())
+    return;
+
+  if (key == "stale_while_revalidate_window")
+    STALE_WHILE_REVALIDATE_WINDOW = atol(value.c_str());
+  else if (key == "time_to_wait")
+    TIME_TO_WAIT = atol(value.c_str());
+  else if (key == "max_age")
+    MAX_AGE = atol(value.c_str());
+}
+
+static bool
+read_config(const char *file_name)
+{
+  INKFile conf_file;
+  conf_file = INKfopen(file_name, "r");
+
+  if (conf_file != NULL) {
+    char buf[1024];
+    while (INKfgets(conf_file, buf, sizeof(buf) - 1) != NULL) {
+      if (strlen(buf) == 0 || buf[0] == '#')
+        continue;
+      parse_config_line(buf);
+    }
+    INKfclose(conf_file);
+  } else {
+    fprintf(stderr, "Failed to open stale while revalidate config file %s\n", file_name);
+    return false;
+  }
+  INKDebug(SWR_LOG_TAG, "[swr] STALE_WHILE_REVALIDATE_WINDOW = %ld", STALE_WHILE_REVALIDATE_WINDOW);
+  INKDebug(SWR_LOG_TAG, "[swr] TIME_TO_WAIT = %ld", TIME_TO_WAIT);
+  return true;
+}
+
+void
+INKPluginInit(int argc, const char *argv[])
+{
+  char default_filename[1024];
+  const char *conf_filename;
+
+  if (argc > 1) {
+    conf_filename = argv[1];
+  } else {
+    sprintf(default_filename, "%s/stale_while_revalidate.conf", INKPluginDirGet());
+    conf_filename = default_filename;
+  }
+
+  if (!read_config(conf_filename)) {
+    if (argc > 1) {
+      INKError(SWR_LOG_TAG, "[swr] Plugin conf not valid.");
+    } else {
+      INKError(SWR_LOG_TAG, "[swr] No config file specified in plugin.conf");
+    }
+    INKError(SWR_LOG_TAG, "[swr] Continuing with default values for config parameters");
+  }
+  // Creates parent continuation
+  INKCont mainCont = INKContCreate(plugin_main_handler, NULL);
+
+  // Add global hooks with continuation to be called when the event has to be processed
+  INKHttpHookAdd(INK_HTTP_TXN_START_HOOK, mainCont);
+}



Mime
View raw message