You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by os...@apache.org on 2014/08/04 15:57:50 UTC
[3/3] git commit: ats_speed: PageSpeed optimization plugin
ats_speed: PageSpeed optimization plugin
Pull in the plugin code from https://github.com/We-Amp/ats_speed.
This adds the plugin as-is, and doesn't wire up to automake yet.
As this plugin needs to download external libraries to
build, a custom make file is added.
See README.md for setting this up.
For more information see
https://developers.google.com/speed/pagespeed/optimization and
http://www.atsspeed.com/
Plugin is donated by We-Amp, ip cleared via:
http://incubator.apache.org/ip-clearance/ats-ats_speed.html
Jira ticket: https://issues.apache.org/jira/browse/TS-2926
Project: http://git-wip-us.apache.org/repos/asf/trafficserver/repo
Commit: http://git-wip-us.apache.org/repos/asf/trafficserver/commit/083abd4f
Tree: http://git-wip-us.apache.org/repos/asf/trafficserver/tree/083abd4f
Diff: http://git-wip-us.apache.org/repos/asf/trafficserver/diff/083abd4f
Branch: refs/heads/master
Commit: 083abd4ff89994682aab406dee18df891a136518
Parents: fab2025
Author: Otto van der Schaaf <os...@we-amp.com>
Authored: Wed Jul 9 22:01:10 2014 +0200
Committer: Otto van der Schaaf <os...@we-amp.com>
Committed: Wed Jul 9 22:27:00 2014 +0200
----------------------------------------------------------------------
plugins/experimental/ats_speed/.gitignore | 15 +
plugins/experimental/ats_speed/LICENSE | 202 ++++
plugins/experimental/ats_speed/Makefile | 66 ++
.../experimental/ats_speed/Makefile.psol_source | 33 +
plugins/experimental/ats_speed/README.md | 52 +
.../experimental/ats_speed/ats_base_fetch.cc | 135 +++
plugins/experimental/ats_speed/ats_base_fetch.h | 80 ++
.../ats_speed/ats_beacon_intercept.cc | 350 ++++++
.../ats_speed/ats_beacon_intercept.h | 23 +
plugins/experimental/ats_speed/ats_config.cc | 196 ++++
plugins/experimental/ats_speed/ats_config.h | 82 ++
.../experimental/ats_speed/ats_demo_filter.cc | 82 ++
.../experimental/ats_speed/ats_demo_filter.h | 57 +
.../experimental/ats_speed/ats_header_utils.cc | 88 ++
.../experimental/ats_speed/ats_header_utils.h | 33 +
.../ats_speed/ats_log_message_handler.cc | 93 ++
.../ats_speed/ats_log_message_handler.h | 28 +
.../ats_speed/ats_message_handler.cc | 107 ++
.../ats_speed/ats_message_handler.h | 68 ++
.../ats_speed/ats_process_context.cc | 76 ++
.../ats_speed/ats_process_context.h | 49 +
.../ats_speed/ats_resource_intercept.cc | 376 ++++++
.../ats_speed/ats_resource_intercept.h | 21 +
.../ats_speed/ats_rewrite_driver_factory.cc | 178 +++
.../ats_speed/ats_rewrite_driver_factory.h | 102 ++
.../ats_speed/ats_rewrite_options.cc | 256 +++++
.../ats_speed/ats_rewrite_options.h | 95 ++
.../ats_speed/ats_server_context.cc | 38 +
.../experimental/ats_speed/ats_server_context.h | 48 +
plugins/experimental/ats_speed/ats_speed.cc | 1083 ++++++++++++++++++
plugins/experimental/ats_speed/ats_speed.h | 94 ++
.../experimental/ats_speed/ats_thread_system.h | 43 +
plugins/experimental/ats_speed/ethread.patch | 13 +
plugins/experimental/ats_speed/gzip/Makefile | 9 +
plugins/experimental/ats_speed/gzip/README | 4 +
.../ats_speed/gzip/configuration.cc | 264 +++++
.../experimental/ats_speed/gzip/configuration.h | 84 ++
.../experimental/ats_speed/gzip/debug_macros.h | 59 +
plugins/experimental/ats_speed/gzip/gzip.cc | 826 +++++++++++++
plugins/experimental/ats_speed/gzip/gzip.config | 6 +
plugins/experimental/ats_speed/gzip/misc.cc | 197 ++++
plugins/experimental/ats_speed/gzip/misc.h | 84 ++
.../ats_speed/scripts/prepare_psol.sh | 95 ++
43 files changed, 5890 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/083abd4f/plugins/experimental/ats_speed/.gitignore
----------------------------------------------------------------------
diff --git a/plugins/experimental/ats_speed/.gitignore b/plugins/experimental/ats_speed/.gitignore
new file mode 100644
index 0000000..a12b1d2
--- /dev/null
+++ b/plugins/experimental/ats_speed/.gitignore
@@ -0,0 +1,15 @@
+# Compiled Object files
+*.slo
+*.lo
+*.o
+
+# Compiled Dynamic libraries
+*.so
+*.dylib
+
+# Compiled Static libraries
+*.lai
+*.la
+*.a
+*.gz
+*~
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/083abd4f/plugins/experimental/ats_speed/LICENSE
----------------------------------------------------------------------
diff --git a/plugins/experimental/ats_speed/LICENSE b/plugins/experimental/ats_speed/LICENSE
new file mode 100644
index 0000000..e06d208
--- /dev/null
+++ b/plugins/experimental/ats_speed/LICENSE
@@ -0,0 +1,202 @@
+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.
+
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/083abd4f/plugins/experimental/ats_speed/Makefile
----------------------------------------------------------------------
diff --git a/plugins/experimental/ats_speed/Makefile b/plugins/experimental/ats_speed/Makefile
new file mode 100644
index 0000000..a2f5de7
--- /dev/null
+++ b/plugins/experimental/ats_speed/Makefile
@@ -0,0 +1,66 @@
+SHELL := /bin/bash
+TSXS?=tsxs
+# Specify BUILDTYPE=Debug for a debug build
+BUILDTYPE?=Release
+MOD_PAGESPEED_DIR=$(shell pwd)/psol/include/
+PAGESPEED_OUT=$(shell pwd)/psol/lib/$(BUILDTYPE)/linux/x64/
+
+
+os_name=unknown_os
+arch_name=ia32
+uname_os=$(shell uname)
+uname_arch=$(shell uname -m)
+
+ifeq ($(uname_os),Linux)
+ os_name=linux
+endif
+
+ifeq ($(uname_arch), x86_64)
+ arch_name=x64
+endif
+ifeq ($(uname_arch), amd64)
+ arch_name=x64
+endif
+
+INC =-I$(MOD_PAGESPEED_DIR)\
+ -I$(MOD_PAGESPEED_DIR)third_party/chromium/src/\
+ -I$(MOD_PAGESPEED_DIR)third_party/google-sparsehash/src\
+ -I$(MOD_PAGESPEED_DIR)third_party/google-sparsehash/gen/arch/$(os_name)/$(arch_name)/include\
+ -I$(MOD_PAGESPEED_DIR)third_party/protobuf/src\
+ -I$(MOD_PAGESPEED_DIR)third_party/re2/src\
+ -I$(MOD_PAGESPEED_DIR)third_party/out/$(BUILDTYPE)/obj/gen\
+ -I$(MOD_PAGESPEED_DIR)third_party/apr/src/include/\
+ -I$(MOD_PAGESPEED_DIR)third_party/aprutil/src/include/\
+ -I$(MOD_PAGESPEED_DIR)third_party/apr/gen/arch/$(os_name)/$(arch_name)/include/\
+ -I$(MOD_PAGESPEED_DIR)third_party/aprutil/gen/arch/$(os_name)/$(arch_name)/include/\
+ -I$(MOD_PAGESPEED_DIR)out/$(BUILDTYPE)/obj/gen\
+ -I$(MOD_PAGESPEED_DIR)out/$(BUILDTYPE)/obj/gen/protoc_out/instaweb
+
+PSOL_LIBS = $(PAGESPEED_OUT)pagespeed_automatic.a $(PAGESPEED_OUT)libserf.a $(PAGESPEED_OUT)libaprutil.a $(PAGESPEED_OUT)libapr.a
+
+%.so: psol %.cc
+# https://github.com/pagespeed/ngx_pagespeed/issues/433: it would be nice to have -Wall -Werror, only suppressing when needed.
+ g++ $(INC) -shared -o ats_speed.so -g -pipe -O3 -fpic $(MOD_PAGESPEED_DIR)/out/$(BUILDTYPE)/obj/gen/data2c_out/instaweb/net/instaweb/apache/install/mod_pagespeed_example/*.cc $(MOD_PAGESPEED_DIR)/net/instaweb/system/*.cc *.cc -lstdc++ -lstdc++ -lpthread $(PSOL_LIBS) -lrt
+
+all: psol gzip/gzip.so ats_speed.so
+
+1.7.30.4.tar.gz:
+ wget --no-check-certificate https://dl.google.com/dl/page-speed/psol/1.7.30.4.tar.gz
+
+psol/: 1.7.30.4.tar.gz
+ tar -xzvf 1.7.30.4.tar.gz
+
+gzip/gzip.so:
+ cd gzip && make
+
+install: all
+ $(TSXS) -i -o ats_speed.so
+ cd gzip && make install
+
+cleanpsol:
+ rm -rf psol/
+ rm *.gz
+
+clean:
+ rm -f *.lo *.so *.o
+ rm -f gzip/*.lo gzip/*.so gzip/*.o
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/083abd4f/plugins/experimental/ats_speed/Makefile.psol_source
----------------------------------------------------------------------
diff --git a/plugins/experimental/ats_speed/Makefile.psol_source b/plugins/experimental/ats_speed/Makefile.psol_source
new file mode 100755
index 0000000..8428d3a
--- /dev/null
+++ b/plugins/experimental/ats_speed/Makefile.psol_source
@@ -0,0 +1,33 @@
+TSXS?=tsxs
+BUILDTYPE=Release
+MOD_PAGESPEED_DIR=$(HOME)/code/google/mod_pagespeed/src/
+PAGESPEED_OUT=$(MOD_PAGESPEED_DIR)out/$(BUILDTYPE)/
+
+INC =-I$(MOD_PAGESPEED_DIR)\
+ -I$(MOD_PAGESPEED_DIR)third_party/chromium/src/\
+ -I$(MOD_PAGESPEED_DIR)third_party/google-sparsehash/src\
+ -I$(MOD_PAGESPEED_DIR)third_party/google-sparsehash/gen/arch/linux/x64/include\
+ -I$(MOD_PAGESPEED_DIR)third_party/protobuf/src\
+ -I$(MOD_PAGESPEED_DIR)third_party/re2/src\
+ -I$(MOD_PAGESPEED_DIR)third_party/out/$(BUILDTYPE)/obj/gen\
+ -I$(MOD_PAGESPEED_DIR)third_party/apr/src/include/\
+ -I$(MOD_PAGESPEED_DIR)third_party/aprutil/src/include/\
+ -I$(MOD_PAGESPEED_DIR)third_party/apr/gen/arch/linux/x64/include/\
+ -I$(MOD_PAGESPEED_DIR)third_party/aprutil/gen/arch/linux/x64/include/\
+ -I$(PAGESPEED_OUT)obj/gen/\
+ -I$(PAGESPEED_OUT)obj/gen/protoc_out/instaweb/
+
+PSOL_LIBS = $(MOD_PAGESPEED_DIR)net/instaweb/automatic/pagespeed_automatic.a
+
+%.so: %.cc
+ g++ $(INC) -shared -o ats_speed.so -g -pipe -Wall -Werror -O3 -fpic *.cc -lstdc++ -lpthread -lrt $(PSOL_LIBS)
+
+all: gzip/gzip.so ats_speed.so
+
+install: all
+ $(TSXS) -i -o ats_speed.so
+ cp gzip/gzip.so ./
+ $(TSXS) -i -o zip.so
+
+clean:
+ rm -f *.lo *.so *.o
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/083abd4f/plugins/experimental/ats_speed/README.md
----------------------------------------------------------------------
diff --git a/plugins/experimental/ats_speed/README.md b/plugins/experimental/ats_speed/README.md
new file mode 100644
index 0000000..ae5db92
--- /dev/null
+++ b/plugins/experimental/ats_speed/README.md
@@ -0,0 +1,52 @@
+![ScreenShot](http://www.atsspeed.com/images/xATSSPEED_logo_plusshout_728x91.png.pagespeed.ic.8mRpu2PXS0.png
+)
+
+Apache Traffic Server web content optimization plugin powered by Google PageSpeed
+
+http://www.atsspeed.com/
+
+To build, a simple 'make' should work. Use 'sudo make install' to install.
+Optionally, patching ATS with ethread.patch helps with eliminating latency that
+sometimes gets induced when synchronising ATS's and PSOL's thread pools.
+
+After that, update ATS's plugin.config with:
+```
+ats_speed.so
+gzip.so /usr/local/etc/trafficserver/gzip.config
+````
+gzip.so also is build with ats_speed, as it currently is a slightly
+modified version of the official one from the ATS repository.
+
+There are some hard-coded things in the plugin, these directories should exist:
+- /tmp/ps_log/ to exist
+- /tmp/ats_ps/ to exist
+
+Configuration files go into `/usr/local/etc/trafficserver/psol.`
+That folder is monitored, and changes to files in there are picked
+up immediately. A sample configuration:
+
+```
+# [host]
+[192.168.185.185]
+# Force traffic server to cache all origin responses
+override_expiry
+pagespeed FlushHtml on
+pagespeed RewriteLevel CoreFilters
+pagespeed EnableFilters rewrite_domains,trim_urls
+pagespeed MapRewriteDomain http://192.168.185.185 http://www.foo.com
+pagespeed MapOriginDomain http://192.168.185.185 http://www.foo.com
+pagespeed EnableFilters prioritize_critical_css,move_css_to_head,move_css_above_scripts
+pagespeed EnableFilters fallback_rewrite_css_urls,insert_img_dimensions,lazyload_images,local_storage_cache
+pagespeed EnableFilters prioritize_critical_css,rewrite_css
+pagespeed EnableFilters combine_javascript,combine_css
+```
+
+It also expects this in records.config from ATS to function:
+`CONFIG proxy.config.url_remap.pristine_host_hdr INT 0`
+
+You can view debug output of the plugin using `traffic_server -T ".*speed.*"`
+
+The current state compiles against PSOL 1.7.30.4-beta.
+Please note the this plugin will generate asserts when build against
+the debug version of mps (option->Merge from a different thread).
+
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/083abd4f/plugins/experimental/ats_speed/ats_base_fetch.cc
----------------------------------------------------------------------
diff --git a/plugins/experimental/ats_speed/ats_base_fetch.cc b/plugins/experimental/ats_speed/ats_base_fetch.cc
new file mode 100644
index 0000000..7788d8f
--- /dev/null
+++ b/plugins/experimental/ats_speed/ats_base_fetch.cc
@@ -0,0 +1,135 @@
+// Copyright 2013 We-Amp B.V.
+//
+// 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.
+//
+// Author: oschaaf@we-amp.com (Otto van der Schaaf)
+
+#include "ats_base_fetch.h"
+
+#include <ts/ts.h>
+
+#include "ats_server_context.h"
+
+#include "net/instaweb/util/public/string_util.h"
+#include "net/instaweb/util/public/string_writer.h"
+#include "net/instaweb/util/public/google_message_handler.h"
+
+
+using namespace net_instaweb;
+
+// TODO(oschaaf): rename is_resource_fetch -> write_raw_response_headers
+AtsBaseFetch::AtsBaseFetch(AtsServerContext* server_context,
+ const net_instaweb::RequestContextPtr& request_ctx,
+ TSVIO downstream_vio, TSIOBuffer downstream_buffer, bool is_resource_fetch) :
+ AsyncFetch(request_ctx),
+ server_context_(server_context),
+ done_called_(false),
+ last_buf_sent_(false),
+ references_(2),
+ downstream_vio_(downstream_vio),
+ downstream_buffer_(downstream_buffer),
+ is_resource_fetch_(is_resource_fetch),
+ downstream_length_(0),
+ txn_mutex_(TSVIOMutexGet(downstream_vio)) {
+ buffer_.reserve(1024 * 32);
+}
+
+AtsBaseFetch::~AtsBaseFetch() {
+ CHECK(references_ == 0);
+}
+
+// Should be called from the event loop,
+// and thus with the txn mutex held by ATS
+void AtsBaseFetch::Release() {
+ DecrefAndDeleteIfUnreferenced();
+}
+
+void AtsBaseFetch::Lock(){
+ TSMutexLock(txn_mutex_);
+}
+
+void AtsBaseFetch::Unlock() {
+ TSMutexUnlock(txn_mutex_);
+}
+
+bool AtsBaseFetch::HandleWrite(const StringPiece& sp, net_instaweb::MessageHandler* handler) {
+ ForwardData(sp, false, false);
+ return true;
+}
+
+bool AtsBaseFetch::HandleFlush( net_instaweb::MessageHandler* handler ) {
+ ForwardData("", true, false);
+ return true;
+}
+
+void AtsBaseFetch::HandleHeadersComplete() {
+ // oschaaf: ATS will currently send its response headers
+ // earlier than this will fire. So this has become a no-op.
+ // This implies that we can't support convert_meta_tags
+ TSDebug("ats-speed", "HeadersComplete()!");
+ // For resource fetches, we need to output the headers in raw HTTP format.
+ if (is_resource_fetch_) {
+ GoogleMessageHandler mh;
+ GoogleString s;
+ StringWriter string_writer(&s);
+ response_headers()->Add("Connection", "Close");
+ response_headers()->WriteAsHttp(&string_writer, &mh);
+ ForwardData(StringPiece(s.data(),s.size()), true, false);
+ }
+}
+
+void AtsBaseFetch::ForwardData(const StringPiece& sp, bool reenable, bool last) {
+ TSIOBufferBlock downstream_blkp;
+ char *downstream_buffer;
+ int64_t downstream_length;
+ int64_t to_write = sp.size();
+
+ Lock();
+ if (references_ == 2) {
+ while (to_write > 0) {
+ downstream_blkp = TSIOBufferStart(downstream_buffer_);
+ downstream_buffer = TSIOBufferBlockWriteStart(downstream_blkp, &downstream_length);
+ int64_t bytes_written = to_write > downstream_length ? downstream_length : to_write;
+ memcpy(downstream_buffer, sp.data() + (sp.size() - to_write), bytes_written);
+ to_write -= bytes_written;
+ downstream_length_ += bytes_written;
+ TSIOBufferProduce(downstream_buffer_, bytes_written);
+ }
+ CHECK(to_write == 0) << "to_write failure";
+ if (last) {
+ TSVIONBytesSet(downstream_vio_, downstream_length_);
+ }
+ if (reenable) {
+ TSVIOReenable(downstream_vio_);
+ }
+ }
+ Unlock();
+}
+
+void AtsBaseFetch::HandleDone(bool success) {
+ CHECK(!done_called_);
+ CHECK(downstream_vio_);
+ TSDebug("ats-speed", "Done()!");
+
+ Lock();
+ done_called_ = true;
+ ForwardData("", true, true);
+ DecrefAndDeleteIfUnreferenced();
+ Unlock();
+}
+
+void AtsBaseFetch::DecrefAndDeleteIfUnreferenced() {
+ if (__sync_add_and_fetch(&references_, -1) == 0) {
+ delete this;
+ }
+}
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/083abd4f/plugins/experimental/ats_speed/ats_base_fetch.h
----------------------------------------------------------------------
diff --git a/plugins/experimental/ats_speed/ats_base_fetch.h b/plugins/experimental/ats_speed/ats_base_fetch.h
new file mode 100644
index 0000000..4d5f88a
--- /dev/null
+++ b/plugins/experimental/ats_speed/ats_base_fetch.h
@@ -0,0 +1,80 @@
+// Copyright 2013 We-Amp B.V.
+//
+// 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.
+//
+// Author: oschaaf@we-amp.com (Otto van der Schaaf)
+#ifndef ATS_BASE_FETCH_H_
+#define ATS_BASE_FETCH_H_
+
+#include <string>
+
+#include <ts/ts.h>
+
+#include "ats_speed.h"
+
+#include "net/instaweb/http/public/async_fetch.h"
+#include "net/instaweb/http/public/headers.h"
+#include "net/instaweb/util/public/string.h"
+
+
+namespace net_instaweb {
+
+class AtsServerContext;
+class AbstractMutex;
+
+class AtsBaseFetch : public net_instaweb::AsyncFetch {
+
+public:
+ // TODO(oschaaf): change this to take the downstream buffer and vio
+ // instead of AtsData*. Also, make the bytes send a property
+ // of the fetch itself instead of tracking it on data.
+ // Doing so, would allow us to share this with the server intercept
+ // code for resources.
+ AtsBaseFetch(AtsServerContext* server_context,
+ const net_instaweb::RequestContextPtr& request_ctx,
+ TSVIO downstream_vio,
+ TSIOBuffer downstream_buffer,
+ bool is_resource_fetch);
+
+ virtual ~AtsBaseFetch();
+ void Release();
+private:
+ virtual bool HandleWrite(const StringPiece& sp, net_instaweb::MessageHandler* handler);
+ virtual bool HandleFlush( net_instaweb::MessageHandler* handler);
+ virtual void HandleHeadersComplete();
+ virtual void HandleDone(bool success);
+ void Lock();
+ void Unlock();
+ void DecrefAndDeleteIfUnreferenced();
+ void ForwardData(const StringPiece& sp, bool reenable, bool last);
+ GoogleString buffer_;
+ AtsServerContext* server_context_;
+ bool done_called_;
+ bool last_buf_sent_;
+
+ // How many active references there are to this fetch. Starts at two,
+ // decremented once when Done() is called and once when Release() is called.
+ int references_;
+ TSVIO downstream_vio_;
+ TSIOBuffer downstream_buffer_;
+ bool is_resource_fetch_;
+ int64_t downstream_length_;
+
+ // We don't own this mutex
+ TSMutex txn_mutex_;
+};
+
+} /* ats_pagespeed */
+
+
+#endif /* ATS_BASE_FETCH_H_ */
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/083abd4f/plugins/experimental/ats_speed/ats_beacon_intercept.cc
----------------------------------------------------------------------
diff --git a/plugins/experimental/ats_speed/ats_beacon_intercept.cc b/plugins/experimental/ats_speed/ats_beacon_intercept.cc
new file mode 100644
index 0000000..175e218
--- /dev/null
+++ b/plugins/experimental/ats_speed/ats_beacon_intercept.cc
@@ -0,0 +1,350 @@
+// Copyright 2013 We-Amp B.V.
+//
+// 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.
+//
+// Author: oschaaf@we-amp.com (Otto van der Schaaf)
+// 'inspired' by the esi intercept code
+
+#include "ats_beacon_intercept.h"
+#include "ats_speed.h"
+#include "ats_server_context.h"
+
+#include "net/instaweb/system/public/system_request_context.h"
+
+#include <string>
+#include <limits.h>
+#include <strings.h>
+#include <stdio.h>
+
+using std::string;
+using namespace net_instaweb;
+
+#define DEBUG_TAG "ats_speed_beacon"
+
+struct InterceptCtx {
+ TSVConn net_vc;
+ TSCont contp;
+
+ struct IoHandle {
+ TSVIO vio;
+ TSIOBuffer buffer;
+ TSIOBufferReader reader;
+ IoHandle()
+ : vio(0), buffer(0), reader(0) { };
+ ~IoHandle() {
+ if (reader) {
+ TSIOBufferReaderFree(reader);
+ }
+ if (buffer) {
+ TSIOBufferDestroy(buffer);
+ }
+ };
+ };
+
+ IoHandle input;
+ IoHandle output;
+
+ TSHttpParser http_parser;
+ string body;
+ int req_content_len;
+ TSMBuffer req_hdr_bufp;
+ TSMLoc req_hdr_loc;
+ bool req_hdr_parsed;
+ bool initialized;
+ TransformCtx* request_context;
+ InterceptCtx(TSCont cont)
+ : net_vc(0), contp(cont), input(), output(), body(""), req_content_len(0), req_hdr_bufp(0), req_hdr_loc(0),
+ req_hdr_parsed(false), initialized(false) {
+ http_parser = TSHttpParserCreate();
+ }
+
+ bool init(TSVConn vconn);
+
+ void setupWrite();
+
+ ~InterceptCtx() {
+ TSDebug(DEBUG_TAG, "[%s] Destroying continuation data", __FUNCTION__);
+ TSHttpParserDestroy(http_parser);
+ if (req_hdr_loc) {
+ TSHandleMLocRelease(req_hdr_bufp, TS_NULL_MLOC, req_hdr_loc);
+ }
+ if (req_hdr_bufp) {
+ TSMBufferDestroy(req_hdr_bufp);
+ }
+ if (request_context) {
+ ats_ctx_destroy(request_context);
+ request_context = NULL;
+ }
+ };
+};
+
+bool
+InterceptCtx::init(TSVConn vconn)
+{
+ if (initialized) {
+ TSError("[%s] InterceptCtx already initialized!", __FUNCTION__);
+ return false;
+ }
+
+ net_vc = vconn;
+
+ input.buffer = TSIOBufferCreate();
+ input.reader = TSIOBufferReaderAlloc(input.buffer);
+ input.vio = TSVConnRead(net_vc, contp, input.buffer, INT_MAX);
+
+ req_hdr_bufp = TSMBufferCreate();
+ req_hdr_loc = TSHttpHdrCreate(req_hdr_bufp);
+ TSHttpHdrTypeSet(req_hdr_bufp, req_hdr_loc, TS_HTTP_TYPE_REQUEST);
+
+ initialized = true;
+ TSDebug(DEBUG_TAG, "[%s] InterceptCtx initialized!", __FUNCTION__);
+ return true;
+}
+
+void
+InterceptCtx::setupWrite() {
+ TSAssert(output.buffer == 0);
+ output.buffer = TSIOBufferCreate();
+ output.reader = TSIOBufferReaderAlloc(output.buffer);
+ output.vio = TSVConnWrite(net_vc, contp, output.reader, INT_MAX);
+}
+
+// Parses out query params from the request.
+void ps_query_params_handler(StringPiece unparsed_uri, StringPiece* data) {
+ stringpiece_ssize_type question_mark_index = unparsed_uri.find("?");
+ if (question_mark_index == StringPiece::npos) {
+ *data = "";
+ } else {
+ *data = unparsed_uri.substr(
+ question_mark_index+1, unparsed_uri.size() - (question_mark_index+1));
+ }
+}
+
+static bool
+handleRead(InterceptCtx *cont_data, bool &read_complete) {
+ int avail = TSIOBufferReaderAvail(cont_data->input.reader);
+ if (avail == TS_ERROR) {
+ TSError("[%s] Error while getting number of bytes available", __FUNCTION__);
+ return false;
+ }
+
+ TSDebug(DEBUG_TAG, "[%s] Parsed header, avail: %d", __FUNCTION__, avail);
+
+ int consumed = 0;
+ if (avail > 0) {
+ int64_t data_len;
+ const char *data;
+ TSIOBufferBlock block = TSIOBufferReaderStart(cont_data->input.reader);
+ while (block != NULL) {
+ data = TSIOBufferBlockReadStart(block, cont_data->input.reader, &data_len);
+ if (!cont_data->req_hdr_parsed) {
+ const char *endptr = data + data_len;
+ if (TSHttpHdrParseReq(cont_data->http_parser, cont_data->req_hdr_bufp, cont_data->req_hdr_loc,
+ &data, endptr) == TS_PARSE_DONE) {
+ TSDebug(DEBUG_TAG, "[%s] Parsed header", __FUNCTION__);
+ TSMLoc content_len_loc = TSMimeHdrFieldFind(cont_data->req_hdr_bufp, cont_data->req_hdr_loc,
+ TS_MIME_FIELD_CONTENT_LENGTH, -1);
+
+ /*if (!content_len_loc) {
+ TSError("[%s] Error while searching content length header [%s]",
+ __FUNCTION__, TS_MIME_FIELD_CONTENT_LENGTH);
+ return false;
+ }
+ if (!content_len_loc) {
+ TSError("[%s] request doesn't contain content length header [%s]",
+ __FUNCTION__, TS_MIME_FIELD_CONTENT_TYPE);
+ return false;
+ }*/
+ if (!content_len_loc) {
+ cont_data->req_content_len = 0;
+ } else {
+ cont_data->req_content_len = TSMimeHdrFieldValueIntGet(cont_data->req_hdr_bufp, cont_data->req_hdr_loc,
+ content_len_loc, 0);
+ TSHandleMLocRelease(cont_data->req_hdr_bufp, cont_data->req_hdr_loc, content_len_loc);
+ }
+ TSDebug(DEBUG_TAG, "[%s] Got content length as %d", __FUNCTION__, cont_data->req_content_len);
+ if (cont_data->req_content_len < 0) {
+ TSError("[%s] Invalid content length [%d]", __FUNCTION__, cont_data->req_content_len);
+ return false;
+ }
+ if (endptr - data) {
+ TSDebug(DEBUG_TAG, "[%s] Appending %ld bytes to body", __FUNCTION__, static_cast<long int>(endptr - data));
+ cont_data->body.append(data, endptr - data);
+ }
+ cont_data->req_hdr_parsed = true;
+ }
+ } else {
+ //TSDebug(DEBUG_TAG, "[%s] Appending %" PRId64" bytes to body", __FUNCTION__, data_len);
+ cont_data->body.append(data, data_len);
+ }
+ consumed += data_len;
+ block = TSIOBufferBlockNext(block);
+ }
+ }
+
+ TSIOBufferReaderConsume(cont_data->input.reader, consumed);
+
+ TSDebug(DEBUG_TAG, "[%s] Consumed %d bytes from input vio, avail: %d", __FUNCTION__, consumed, avail);
+
+ // Modify the input VIO to reflect how much data we've completed.
+ TSVIONDoneSet(cont_data->input.vio, TSVIONDoneGet(cont_data->input.vio) + consumed);
+
+ if (static_cast<int>(cont_data->body.size()) == cont_data->req_content_len) {
+ TSDebug(DEBUG_TAG, "[%s] Completely read body of size %d", __FUNCTION__, cont_data->req_content_len);
+ read_complete = true;
+ } else {
+ read_complete = false;
+ TSDebug(DEBUG_TAG, "[%s] Reenabling input vio as %ld bytes still need to be read",
+ __FUNCTION__, static_cast<long int>(cont_data->req_content_len - cont_data->body.size()));
+ TSVIOReenable(cont_data->input.vio);
+ }
+ return true;
+}
+
+static bool
+processRequest(InterceptCtx *cont_data) {
+ string reply_header("HTTP/1.1 204 No Content\r\n");
+ int body_size = static_cast<int>(cont_data->body.size());
+ if (cont_data->req_content_len != body_size) {
+ TSError("[%s] Read only %d bytes of body; expecting %d bytes", __FUNCTION__, body_size,
+ cont_data->req_content_len);
+ }
+
+ char buf[64];
+ //snprintf(buf, 64, "%s: %d\r\n\r\n", TS_MIME_FIELD_CONTENT_LENGTH, body_size);
+ snprintf(buf, 64, "%s: %d\r\n\r\n", TS_MIME_FIELD_CONTENT_LENGTH, 0);
+ reply_header.append(buf);
+ reply_header.append("Cache-Control: max-age=0, no-cache");
+ //TSError("[%s] reply header: \n%s", __FUNCTION__, reply_header.data());
+
+ StringPiece query_param_beacon_data;
+ ps_query_params_handler(cont_data->request_context->url_string->c_str(), &query_param_beacon_data);
+
+ GoogleString beacon_data = net_instaweb::StrCat(
+ query_param_beacon_data, "&", cont_data->body);
+ ServerContext* server_context = cont_data->request_context->server_context;
+
+ SystemRequestContext* system_request_context =
+ new SystemRequestContext(server_context->thread_system()->NewMutex(),
+ server_context->timer(),
+ 80,
+ "127.0.0.1");
+
+ if (!server_context->HandleBeacon(
+ beacon_data,
+ cont_data->request_context->user_agent->c_str(),
+ net_instaweb::RequestContextPtr(system_request_context))) {
+ TSError("Beacon handling failure!");
+ } else {
+ //TSDebug(DEBUG_TAG, "Beacon post data processed OK: [%s]", beacon_data.c_str());
+ }
+
+ cont_data->setupWrite();
+ if (TSIOBufferWrite(cont_data->output.buffer, reply_header.data(), reply_header.size()) == TS_ERROR) {
+ TSError("[%s] Error while writing reply header", __FUNCTION__);
+ return false;
+ }
+ /*
+ if (TSIOBufferWrite(cont_data->output.buffer, cont_data->body.data(), body_size) == TS_ERROR) {
+ TSError("[%s] Error while writing content", __FUNCTION__);
+ return false;
+ }*/
+ int total_bytes_written = reply_header.size() + body_size;
+ TSDebug(DEBUG_TAG, "[%s] Wrote reply of size %d", __FUNCTION__, total_bytes_written);
+ TSVIONBytesSet(cont_data->output.vio, total_bytes_written);
+
+ TSVIOReenable(cont_data->output.vio);
+ return true;
+}
+
+static int
+txn_intercept(TSCont contp, TSEvent event, void *edata) {
+ TSDebug(DEBUG_TAG, "[%s] Received event: %d", __FUNCTION__, (int)event);
+
+ InterceptCtx *cont_data = static_cast<InterceptCtx *>(TSContDataGet(contp));
+ bool read_complete = false;
+ bool shutdown = false;
+ switch (event) {
+ case TS_EVENT_NET_ACCEPT:
+ TSDebug(DEBUG_TAG, "[%s] Received net accept event", __FUNCTION__);
+ TSAssert(cont_data->initialized == false);
+ if (!cont_data->init(static_cast<TSVConn>(edata))) {
+ TSError("[%s] Could not initialize continuation data!", __FUNCTION__);
+ return 1;
+ }
+ break;
+ case TS_EVENT_VCONN_READ_READY:
+ TSDebug(DEBUG_TAG, "[%s] Received read ready event", __FUNCTION__);
+ if (!handleRead(cont_data, read_complete)) {
+ TSError("[%s] Error while reading from input vio", __FUNCTION__);
+ //return 0;
+ read_complete = true;
+ }
+ break;
+ case TS_EVENT_VCONN_READ_COMPLETE:
+ case TS_EVENT_VCONN_EOS:
+ // intentional fall-through
+ TSDebug(DEBUG_TAG, "[%s] Received read complete/eos event %d", __FUNCTION__, event);
+ read_complete = true;
+ break;
+ case TS_EVENT_VCONN_WRITE_READY:
+ TSDebug(DEBUG_TAG, "[%s] Received write ready event", __FUNCTION__);
+ break;
+ case TS_EVENT_VCONN_WRITE_COMPLETE:
+ TSDebug(DEBUG_TAG, "[%s] Received write complete event", __FUNCTION__);
+ shutdown = true;
+ break;
+ case TS_EVENT_ERROR:
+ // todo: do some error handling here
+ TSDebug(DEBUG_TAG, "[%s] Received error event; going to shutdown, event: %d", __FUNCTION__, event);
+ TSError("[%s] Received error event; going to shutdown, event: %d", __FUNCTION__, event);
+ shutdown = true;
+ break;
+ default:
+ break;
+ }
+
+ if (read_complete) {
+ if (!processRequest(cont_data)) {
+ TSError("[%s] Failed to process process", __FUNCTION__);
+ } else {
+ TSDebug(DEBUG_TAG, "[%s] Processed request successfully", __FUNCTION__);
+ }
+ }
+
+ if (shutdown) {
+ TSDebug(DEBUG_TAG, "[%s] Completed request processing. Shutting down...", __FUNCTION__);
+ if (cont_data->net_vc) {
+ TSVConnClose(cont_data->net_vc);
+ }
+ delete cont_data;
+ TSContDestroy(contp);
+ }
+
+ return 1;
+}
+
+bool
+hook_beacon_intercept(TSHttpTxn txnp) {
+ TSCont contp = TSContCreate(txn_intercept, TSMutexCreate());
+ if (!contp) {
+ TSError("[%s] Could not create intercept request", __FUNCTION__);
+ return false;
+ }
+ InterceptCtx *cont_data = new InterceptCtx(contp);
+ cont_data->request_context = get_transaction_context(txnp);
+ TSContDataSet(contp, cont_data);
+ TSHttpTxnIntercept(contp, txnp);
+ TSDebug(DEBUG_TAG, "[%s] Setup server intercept successfully", __FUNCTION__);
+ return true;
+}
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/083abd4f/plugins/experimental/ats_speed/ats_beacon_intercept.h
----------------------------------------------------------------------
diff --git a/plugins/experimental/ats_speed/ats_beacon_intercept.h b/plugins/experimental/ats_speed/ats_beacon_intercept.h
new file mode 100644
index 0000000..21a7ea0
--- /dev/null
+++ b/plugins/experimental/ats_speed/ats_beacon_intercept.h
@@ -0,0 +1,23 @@
+// Copyright 2013 We-Amp B.V.
+//
+// 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.
+//
+// Author: oschaaf@we-amp.com (Otto van der Schaaf)
+#ifndef _ATS_BEACON_INTERCEPT_H
+#define _ATS_BEACON_INTERCEPT_H
+
+#include "ts/ts.h"
+
+bool hook_beacon_intercept(TSHttpTxn txnp);
+
+#endif
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/083abd4f/plugins/experimental/ats_speed/ats_config.cc
----------------------------------------------------------------------
diff --git a/plugins/experimental/ats_speed/ats_config.cc b/plugins/experimental/ats_speed/ats_config.cc
new file mode 100644
index 0000000..c9dd73d
--- /dev/null
+++ b/plugins/experimental/ats_speed/ats_config.cc
@@ -0,0 +1,196 @@
+// Copyright 2013 We-Amp B.V.
+//
+// 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.
+//
+// Author: oschaaf@we-amp.com (Otto van der Schaaf)
+#include "ats_config.h"
+
+#include <ts/ts.h>
+#include <fstream>
+
+#include "net/instaweb/util/public/string_util.h"
+
+#include "ats_message_handler.h"
+#include "ats_rewrite_options.h"
+
+namespace net_instaweb {
+
+using namespace std;
+
+
+
+void ltrim_if(string& s, int (* fp) (int)) {
+ for (size_t i = 0; i < s.size();) {
+ if (fp(s[i])) {
+ s.erase(i,1);
+ } else {
+ break;
+ }
+ }
+}
+
+void rtrim_if(string& s, int (* fp) (int)) {
+ for (ssize_t i = (ssize_t)s.size() - 1; i >= 0; i--) {
+ if (fp(s[i])) {
+ s.erase(i,1);
+ } else {
+ break;
+ }
+ }
+}
+
+void trim_if(string& s, int (* fp) (int)) {
+ ltrim_if(s, fp);
+ rtrim_if(s, fp);
+}
+
+vector<string> tokenize(const string &s, int (* fp) (int)) {
+ vector<string> r;
+ string tmp;
+
+ for (size_t i = 0; i < s.size(); i++) {
+ if ( fp(s[i]) ) {
+ if ( tmp.size() ) {
+ r.push_back(tmp);
+ tmp = "";
+ }
+ } else {
+ tmp += s[i];
+ }
+ }
+
+ if ( tmp.size() ) {
+ r.push_back(tmp);
+ }
+
+ return r;
+}
+
+AtsConfig::AtsConfig(AtsThreadSystem* thread_system)
+ : thread_system_(thread_system) {
+ AddHostConfig(new AtsHostConfig(GoogleString("(XXXXXX)"), new AtsRewriteOptions(thread_system_)));
+}
+
+AtsConfig::~AtsConfig() {
+ for (size_t i = 0; i < host_configurations_.size(); i++) {
+ delete host_configurations_[i];
+ host_configurations_.clear();
+ }
+}
+
+void AtsConfig::AddHostConfig(AtsHostConfig* hc){
+ host_configurations_.push_back(hc);
+}
+
+AtsHostConfig::~AtsHostConfig() {
+ if (options_ != NULL) {
+ delete options_;
+ options_ = NULL;
+ }
+}
+
+AtsHostConfig * AtsConfig::Find(const char * host, int host_length) {
+ AtsHostConfig * host_configuration = host_configurations_[0];
+
+ std::string shost(host, host_length);
+
+ for (size_t i = 1; i < host_configurations_.size(); i++ ) {
+ if (host_configurations_[i]->host() == shost){
+ host_configuration = host_configurations_[i];
+ break;
+ }
+ }
+
+ return host_configuration;
+}
+
+bool AtsConfig::Parse(const char * path ) {
+ string pathstring(path);
+
+ // If we have a path and it's not an absolute path, make it relative to the
+ // configuration directory.
+ if (!pathstring.empty() && pathstring[0] != '/') {
+ pathstring.assign(TSConfigDirGet());
+ pathstring.append("/");
+ pathstring.append(path);
+ }
+
+ trim_if(pathstring, isspace);
+
+ AtsHostConfig* current_host_configuration = host_configurations_[0];
+
+ if (pathstring.empty()) {
+ TSError("Empty path passed in AtsConfig::Parse");
+ return false;
+ }
+
+ path = pathstring.c_str();
+ std::ifstream f;
+
+ size_t lineno = 0;
+
+ f.open(path, std::ios::in);
+
+ if (!f.is_open()) {
+ TSError("could not open file [%s], skip",path);
+ return false;
+ }
+
+
+ while (!f.eof()) {
+ std::string line;
+ getline(f, line);
+ ++lineno;
+
+ trim_if(line, isspace);
+ if (line.size() == 0) {
+ continue;
+ }
+ if (line[0] == '#') {
+ continue;
+ }
+
+ vector<string> v = tokenize( line, isspace );
+ if (v.size() == 0)
+ continue;
+ GoogleString msg;
+ AtsMessageHandler handler(thread_system_->NewMutex());
+ if (v.size() == 1) {
+ string token = v[0];
+ if ((token[0] == '[') && (token[token.size()-1] == ']')) {
+ GoogleString current_host = token.substr(1, token.size() - 2);
+ current_host_configuration = new AtsHostConfig(current_host, new AtsRewriteOptions(thread_system_));
+ AddHostConfig(current_host_configuration);
+ } else if (StringCaseEqual(token,"override_expiry")) {
+ current_host_configuration->set_override_expiry(true);
+ } else {
+ msg = "unknown single token on a line";
+ }
+ } else {
+ global_settings settings;
+ v.erase (v.begin());
+ const char* err = current_host_configuration->options()->ParseAndSetOptions(v, &handler, settings);
+ if (err) {
+ msg.append(err);
+ }
+ }
+ if (msg.size() > 0) {
+ TSDebug("ats-speed", "Error parsing line [%s]: [%s]", line.c_str(), msg.c_str());
+ }
+ }
+
+ return true;
+}
+
+
+} // namespace net_instaweb
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/083abd4f/plugins/experimental/ats_speed/ats_config.h
----------------------------------------------------------------------
diff --git a/plugins/experimental/ats_speed/ats_config.h b/plugins/experimental/ats_speed/ats_config.h
new file mode 100644
index 0000000..bc6e7f8
--- /dev/null
+++ b/plugins/experimental/ats_speed/ats_config.h
@@ -0,0 +1,82 @@
+// Copyright 2013 We-Amp B.V.
+//
+// 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.
+//
+// Author: oschaaf@we-amp.com (Otto van der Schaaf)
+#ifndef ATS_CONFIG_H_
+#define ATS_CONFIG_H_
+
+#include <string>
+#include <vector>
+
+#include <ts/ts.h>
+
+#include "ats_thread_system.h"
+
+#include "net/instaweb/util/public/string.h"
+#include "net/instaweb/util/public/string_util.h"
+
+
+namespace net_instaweb {
+
+class AtsRewriteOptions;
+
+class AtsHostConfig {
+public:
+ explicit AtsHostConfig(const GoogleString & host, AtsRewriteOptions* options)
+ : host_(host)
+ , options_(options)
+ {
+ }
+ virtual ~AtsHostConfig();
+
+ inline GoogleString host() { return host_; }
+ inline AtsRewriteOptions* options() { return options_; }
+ inline bool override_expiry() { return override_expiry_; }
+ inline void set_override_expiry(bool x) { override_expiry_ = x; }
+private:
+ GoogleString host_;
+ AtsRewriteOptions* options_;
+ bool override_expiry_;
+ DISALLOW_COPY_AND_ASSIGN(AtsHostConfig);
+}; // class AtsHostConfig
+
+class AtsConfig {
+ friend class AtsHostConfig;
+public:
+ explicit AtsConfig(AtsThreadSystem* thread_system);
+ virtual ~AtsConfig();
+
+ // TODO(oschaaf): destructor??
+ bool Parse(const char * path);
+ AtsHostConfig * Find(const char * host, int host_length);
+ inline AtsHostConfig * GlobalConfiguration() {
+ return host_configurations_[0];
+ }
+ AtsThreadSystem* thread_system() {
+ return thread_system_;
+ }
+
+private:
+ void AddHostConfig(AtsHostConfig* hc);
+
+ std::vector<AtsHostConfig *> host_configurations_;
+ AtsThreadSystem* thread_system_;
+ //todo: destructor. delete owned host configurations
+ DISALLOW_COPY_AND_ASSIGN(AtsConfig);
+}; // class Configuration
+
+
+} // namespace net_instaweb
+
+#endif // ATS_CONFIG_H
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/083abd4f/plugins/experimental/ats_speed/ats_demo_filter.cc
----------------------------------------------------------------------
diff --git a/plugins/experimental/ats_speed/ats_demo_filter.cc b/plugins/experimental/ats_speed/ats_demo_filter.cc
new file mode 100644
index 0000000..18944d5
--- /dev/null
+++ b/plugins/experimental/ats_speed/ats_demo_filter.cc
@@ -0,0 +1,82 @@
+// Copyright 2013 We-Amp B.V.
+//
+// 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.
+//
+// Author: oschaaf@we-amp.com (Otto van der Schaaf)
+#include "net/instaweb/rewriter/public/add_head_filter.h"
+#include "net/instaweb/htmlparse/public/html_parse.h"
+#include "net/instaweb/htmlparse/public/html_element.h"
+#include <string>
+
+#include <ts/ts.h>
+#include "ats_demo_filter.h"
+
+namespace net_instaweb {
+ const char* AtsDemoFilter::kPoweredByHtml =
+ "<div id=\"weamp_poweredby\" style=\"bottom:0; height:30px; left:0; width:100%;\">"
+ "<div style=\"line-height:30px; margin:0 auto; width:100%; text-align:center; \">"
+ "<a target=\"_blank\" title=\"Google PageSpeed optimization demo brought to you by We-Amp\" href=\"http://www.we-amp.com/\">Google PageSpeed optimization demo by We-Amp</a>"
+ "</div>"
+ "</div>";
+
+
+
+AtsDemoFilter::AtsDemoFilter(HtmlParse* parser, bool banner) :
+ parser_(parser),
+ banner_(banner)
+{
+}
+
+void AtsDemoFilter::StartElement(HtmlElement* element) {
+ if (banner_ && element->keyword() == HtmlName::kBody) {
+ HtmlNode* el = parser_->NewCharactersNode(NULL, AtsDemoFilter::kPoweredByHtml);
+ parser_->InsertNodeBeforeCurrent(el);
+ }
+
+ if (element->keyword() == HtmlName::kA || element->keyword() == HtmlName::kBase
+ || element->keyword() == HtmlName::kForm|| element->keyword() == HtmlName::kImg
+ || element->keyword() == HtmlName::kLink || element->keyword() == HtmlName::kScript) {
+ HtmlElement::AttributeList* attributes = element->mutable_attributes();
+ for (HtmlElement::AttributeIterator i(attributes->begin());
+ i != attributes->end(); ++i) {
+
+ HtmlElement::Attribute& attribute = *i;
+ if (attribute.keyword() == HtmlName::kAction || attribute.keyword() == HtmlName::kHref
+ || attribute.keyword() == HtmlName::kSrc) {
+ const char * attribute_value = NULL;
+ if ( attribute.DecodedValueOrNull() != NULL ) {
+ attribute_value = attribute.DecodedValueOrNull();
+ } else {
+ attribute_value = attribute.escaped_value();
+ }
+
+ if ( attribute_value != NULL) {
+ GoogleUrl url( attribute_value );
+ if (url.IsWebValid()) {
+ if (url.Host() == from_domain_) {
+ StringPiece scheme = url.Scheme();
+ StringPiece host = to_domain_.c_str();
+ StringPiece pathAndQuery = url.PathAndLeaf();
+ GoogleString rewritten = StrCat(scheme,"://", host, pathAndQuery);
+ attribute.SetValue(rewritten.c_str());
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+
+} // namespace net_instaweb
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/083abd4f/plugins/experimental/ats_speed/ats_demo_filter.h
----------------------------------------------------------------------
diff --git a/plugins/experimental/ats_speed/ats_demo_filter.h b/plugins/experimental/ats_speed/ats_demo_filter.h
new file mode 100644
index 0000000..dc5aa78
--- /dev/null
+++ b/plugins/experimental/ats_speed/ats_demo_filter.h
@@ -0,0 +1,57 @@
+// Copyright 2013 We-Amp B.V.
+//
+// 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.
+//
+// Author: oschaaf@we-amp.com (Otto van der Schaaf)
+#ifndef ATS_DEMO_FILTER_H_
+#define ATS_DEMO_FILTER_H_
+
+#include "base/basictypes.h"
+#include "base/string_piece.h"
+#include "net/instaweb/htmlparse/public/empty_html_filter.h"
+#include "net/instaweb/util/public/atom.h"
+#include "net/instaweb/htmlparse/public/html_parse.h"
+#include "net/instaweb/htmlparse/public/html_element.h"
+#include <string>
+
+using base::StringPiece;
+
+namespace net_instaweb {
+
+
+
+ class AtsDemoFilter : public EmptyHtmlFilter {
+ public:
+ static const char* kPoweredByHtml;
+
+ explicit AtsDemoFilter(HtmlParse* parser, bool banner);
+ virtual void StartElement(HtmlElement* element);
+ virtual const char* Name() const { return "AtsDemo"; }
+ // TODO: move to constructor
+ void set_domains(const StringPiece& to_domain, const StringPiece& from_domain)
+ {
+ to_domain.CopyToString(&to_domain_);
+ from_domain.CopyToString(&from_domain_);
+ }
+
+ private:
+ std::string to_domain_;
+ std::string from_domain_;
+ HtmlParse* parser_;
+ bool banner_;
+ DISALLOW_COPY_AND_ASSIGN(AtsDemoFilter);
+ };
+
+} // namespace net_instaweb
+
+#endif // ATS_DEMO_FILTER_H_
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/083abd4f/plugins/experimental/ats_speed/ats_header_utils.cc
----------------------------------------------------------------------
diff --git a/plugins/experimental/ats_speed/ats_header_utils.cc b/plugins/experimental/ats_speed/ats_header_utils.cc
new file mode 100644
index 0000000..74e46c9
--- /dev/null
+++ b/plugins/experimental/ats_speed/ats_header_utils.cc
@@ -0,0 +1,88 @@
+// Copyright 2013 We-Amp B.V.
+//
+// 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.
+//
+// Author: oschaaf@we-amp.com (Otto van der Schaaf)
+#include "ats_header_utils.h"
+
+GoogleString get_header(TSMBuffer bufp, TSMLoc hdr_loc, const char * header_name)
+{
+ const char * val = NULL;
+ int val_len;
+ TSMLoc field_loc = TSMimeHdrFieldFind( bufp, hdr_loc, header_name, -1);
+
+ if (field_loc) {
+ val = TSMimeHdrFieldValueStringGet (bufp, hdr_loc, field_loc, 0, &val_len);
+ TSHandleMLocRelease(bufp,hdr_loc,field_loc);
+ return GoogleString(val,val_len);
+ }
+
+ return GoogleString("");
+}
+
+void unset_header(TSMBuffer bufp, TSMLoc hdr_loc, const char * header_name)
+{
+ TSMLoc field_loc = TSMimeHdrFieldFind( bufp, hdr_loc, header_name, -1);
+
+ if (field_loc) {
+ TSMimeHdrFieldDestroy(bufp, hdr_loc, field_loc);
+ TSHandleMLocRelease(bufp, hdr_loc, field_loc);
+ }
+}
+
+void hide_accept_encoding(TSMBuffer reqp, TSMLoc hdr_loc, const char * hidden_header_name)
+{
+ TSMLoc field = TSMimeHdrFieldFind(reqp, hdr_loc, TS_MIME_FIELD_ACCEPT_ENCODING, TS_MIME_LEN_ACCEPT_ENCODING);
+ while (field) {
+ TSMLoc tmp;
+ tmp = TSMimeHdrFieldNextDup(reqp, hdr_loc, field);
+ TSMimeHdrFieldNameSet(reqp, hdr_loc, field, hidden_header_name, -1);
+ TSHandleMLocRelease(reqp, hdr_loc, field);
+ field = tmp;
+ }
+}
+
+void restore_accept_encoding(TSMBuffer reqp, TSMLoc hdr_loc, const char * hidden_header_name)
+{
+ TSMLoc field = TSMimeHdrFieldFind(reqp, hdr_loc, hidden_header_name, -1);
+
+ while (field) {
+ TSMLoc tmp;
+ tmp = TSMimeHdrFieldNextDup(reqp, hdr_loc, field);
+ TSMimeHdrFieldNameSet(reqp, hdr_loc, field, TS_MIME_FIELD_ACCEPT_ENCODING, TS_MIME_LEN_ACCEPT_ENCODING);
+ TSHandleMLocRelease(reqp, hdr_loc, field);
+ field = tmp;
+ }
+}
+
+void set_header(TSMBuffer bufp, TSMLoc hdr_loc, const char * header_name, const char * header_value)
+{
+ TSMLoc field_loc = TSMimeHdrFieldFind( bufp, hdr_loc, header_name, -1);
+
+ if (field_loc) {
+ TSMimeHdrFieldValueStringSet(bufp, hdr_loc, field_loc, -1, header_value, -1);
+ } else {
+ if ( TSMimeHdrFieldCreate(bufp, hdr_loc, &field_loc) == TS_SUCCESS ) {
+ TSMimeHdrFieldNameSet(bufp, hdr_loc, field_loc, header_name, -1);
+ TSMimeHdrFieldAppend(bufp, hdr_loc, field_loc);
+ TSMimeHdrFieldValueStringSet(bufp,hdr_loc,field_loc,-1,header_value,-1);
+ } else {
+ TSError("field creation error for field [%s]", header_name);
+ return;
+ }
+ }
+
+ if (field_loc) {
+ TSHandleMLocRelease(bufp,hdr_loc,field_loc);
+ }
+}
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/083abd4f/plugins/experimental/ats_speed/ats_header_utils.h
----------------------------------------------------------------------
diff --git a/plugins/experimental/ats_speed/ats_header_utils.h b/plugins/experimental/ats_speed/ats_header_utils.h
new file mode 100644
index 0000000..7aa6f7d
--- /dev/null
+++ b/plugins/experimental/ats_speed/ats_header_utils.h
@@ -0,0 +1,33 @@
+// Copyright 2013 We-Amp B.V.
+//
+// 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.
+//
+// Author: oschaaf@we-amp.com (Otto van der Schaaf)
+#ifndef ATS_HEADER_UTILS_H
+#define ATS_HEADER_UTILS_H
+
+#include <string>
+
+#include <ts/ts.h>
+
+#include "net/instaweb/util/public/string.h"
+#include "net/instaweb/util/public/string_util.h"
+
+
+GoogleString get_header(TSMBuffer bufp, TSMLoc hdr_loc, const char * header_name);
+void unset_header(TSMBuffer bufp, TSMLoc hdr_loc, const char * header_name);
+void hide_accept_encoding(TSMBuffer reqp, TSMLoc hdr_loc, const char * hidden_header_name);
+void restore_accept_encoding(TSMBuffer reqp, TSMLoc hdr_loc, const char * hidden_header_name);
+void set_header(TSMBuffer bufp, TSMLoc hdr_loc, const char * header_name, const char * header_value);
+
+#endif // ATS_HEADER_UTILS_H
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/083abd4f/plugins/experimental/ats_speed/ats_log_message_handler.cc
----------------------------------------------------------------------
diff --git a/plugins/experimental/ats_speed/ats_log_message_handler.cc b/plugins/experimental/ats_speed/ats_log_message_handler.cc
new file mode 100644
index 0000000..635a841
--- /dev/null
+++ b/plugins/experimental/ats_speed/ats_log_message_handler.cc
@@ -0,0 +1,93 @@
+// Copyright 2013 We-Amp B.V.
+//
+// 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.
+//
+// Author: oschaaf@we-amp.com (Otto van der Schaaf)
+#include "ats_log_message_handler.h"
+
+#include <ts/ts.h>
+
+#include <unistd.h>
+
+#include <limits>
+#include <string>
+
+#include "base/debug/debugger.h"
+#include "base/debug/stack_trace.h"
+#include "base/logging.h"
+#include "net/instaweb/public/version.h"
+#include "net/instaweb/util/public/string_util.h"
+
+// Make sure we don't attempt to use LOG macros here, since doing so
+// would cause us to go into an infinite log loop.
+#undef LOG
+#define LOG USING_LOG_HERE_WOULD_CAUSE_INFINITE_RECURSION
+
+namespace {
+
+bool LogMessageHandler(int severity, const char* file, int line,
+ size_t message_start, const GoogleString& str) {
+ GoogleString message = str;
+ if (severity == logging::LOG_FATAL) {
+ if (base::debug::BeingDebugged()) {
+ base::debug::BreakDebugger();
+ } else {
+ base::debug::StackTrace trace;
+ std::ostringstream stream;
+ trace.OutputToStream(&stream);
+ message.append(stream.str());
+ }
+ }
+
+ // Trim the newline off the end of the message string.
+ size_t last_msg_character_index = message.length() - 1;
+ if (message[last_msg_character_index] == '\n') {
+ message.resize(last_msg_character_index);
+ }
+
+ TSDebug("ats-speed-vlog", "[%s] %s",
+ net_instaweb::kModPagespeedVersion,
+ message.c_str());
+
+ if (severity == logging::LOG_FATAL) {
+ // Crash the process to generate a dump.
+ base::debug::BreakDebugger();
+ }
+
+ return true;
+}
+
+} // namespace
+
+
+namespace net_instaweb {
+
+namespace log_message_handler {
+
+
+const int kDebugLogLevel = -2;
+
+void Install() {
+ logging::SetLogMessageHandler(&LogMessageHandler);
+
+ // All VLOG(2) and higher will be displayed as DEBUG logs if the nginx log
+ // level is DEBUG.
+ // TODO(oschaaf): from config
+ //if (log->log_level >= NGX_LOG_DEBUG) {
+ logging::SetMinLogLevel(-2);
+ //}
+}
+
+} // namespace log_message_handler
+
+} // namespace net_instaweb
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/083abd4f/plugins/experimental/ats_speed/ats_log_message_handler.h
----------------------------------------------------------------------
diff --git a/plugins/experimental/ats_speed/ats_log_message_handler.h b/plugins/experimental/ats_speed/ats_log_message_handler.h
new file mode 100644
index 0000000..1a113aa
--- /dev/null
+++ b/plugins/experimental/ats_speed/ats_log_message_handler.h
@@ -0,0 +1,28 @@
+// Copyright 2013 We-Amp B.V.
+//
+// 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.
+//
+// Author: oschaaf@we-amp.com (Otto van der Schaaf)
+#ifndef ATS_LOG_MESSAGE_HANDLER_H_
+#define ATS_LOG_MESSAGE_HANDLER_H_
+
+
+namespace net_instaweb {
+
+ namespace log_message_handler {
+ void Install();
+ } // namespace log_message_handler
+
+} // namespace net_instaweb
+
+#endif // ATS_LOG_MESSAGE_HANDLER_H_
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/083abd4f/plugins/experimental/ats_speed/ats_message_handler.cc
----------------------------------------------------------------------
diff --git a/plugins/experimental/ats_speed/ats_message_handler.cc b/plugins/experimental/ats_speed/ats_message_handler.cc
new file mode 100644
index 0000000..7f21660
--- /dev/null
+++ b/plugins/experimental/ats_speed/ats_message_handler.cc
@@ -0,0 +1,107 @@
+// Copyright 2013 Google 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
+//
+// 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.
+
+// Author: oschaaf@gmail.com (Otto van der Schaaf)
+
+#include "ats_message_handler.h"
+
+#include <signal.h>
+#include <unistd.h>
+
+#include "net/instaweb/util/public/abstract_mutex.h"
+#include "net/instaweb/util/public/debug.h"
+#include "net/instaweb/util/public/shared_circular_buffer.h"
+#include "net/instaweb/util/public/string_util.h"
+#include "net/instaweb/public/version.h"
+#include "pagespeed/kernel/base/posix_timer.h"
+#include "pagespeed/kernel/base/time_util.h"
+
+
+namespace {
+
+// This will be prefixed to every logged message.
+const char kModuleName[] = "ats_pagespeed";
+
+} // namespace
+
+namespace net_instaweb {
+
+AtsMessageHandler::AtsMessageHandler(AbstractMutex* mutex)
+ : mutex_(mutex),
+ buffer_(NULL) {
+ SetPidString(static_cast<int64>(getpid()));
+}
+
+
+bool AtsMessageHandler::Dump(Writer* writer) {
+ // Can't dump before SharedCircularBuffer is set up.
+ if (buffer_ == NULL) {
+ return false;
+ }
+ return buffer_->Dump(writer, &handler_);
+}
+
+void AtsMessageHandler::set_buffer(SharedCircularBuffer* buff) {
+ ScopedMutex lock(mutex_.get());
+ buffer_ = buff;
+}
+
+void AtsMessageHandler::MessageVImpl(MessageType type, const char* msg,
+ va_list args) {
+ GoogleString formatted_message = Format(msg, args);
+
+ TSDebug("ats-speed", "[%s %s] %s", kModuleName, kModPagespeedVersion,
+ formatted_message.c_str());
+
+ // Prepare a log message for the SharedCircularBuffer only.
+ // Prepend time and severity to message.
+ // Format is [time] [severity] [pid] message.
+ GoogleString message;
+ GoogleString time;
+ PosixTimer timer;
+ if (!ConvertTimeToString(timer.NowMs(), &time)) {
+ time = "?";
+ }
+
+ StrAppend(&message, "[", time, "] ",
+ "[", MessageTypeToString(type), "] ");
+ StrAppend(&message, pid_string_, " ", formatted_message, "\n");
+ {
+ ScopedMutex lock(mutex_.get());
+ if (buffer_ != NULL) {
+ buffer_->Write(message);
+ }
+ }
+}
+
+void AtsMessageHandler::FileMessageVImpl(MessageType type, const char* file,
+ int line, const char* msg,
+ va_list args) {
+ GoogleString formatted_message = Format(msg, args);
+ TSDebug("ats-speed", "[%s %s] %s:%d:%s",
+ kModuleName, kModPagespeedVersion, file, line,
+ formatted_message.c_str());
+}
+
+// TODO(sligocki): It'd be nice not to do so much string copying.
+GoogleString AtsMessageHandler::Format(const char* msg, va_list args) {
+ GoogleString buffer;
+
+ // Ignore the name of this routine: it formats with vsnprintf.
+ // See base/stringprintf.cc.
+ StringAppendV(&buffer, msg, args);
+ return buffer;
+}
+
+} // namespace net_instaweb
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/083abd4f/plugins/experimental/ats_speed/ats_message_handler.h
----------------------------------------------------------------------
diff --git a/plugins/experimental/ats_speed/ats_message_handler.h b/plugins/experimental/ats_speed/ats_message_handler.h
new file mode 100644
index 0000000..fb40590
--- /dev/null
+++ b/plugins/experimental/ats_speed/ats_message_handler.h
@@ -0,0 +1,68 @@
+// Copyright 2013 Google 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
+//
+// 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.
+
+// Author: oschaaf@gmail.com (Otto van der Schaaf)
+
+#ifndef NGX_MESSAGE_HANDLER_H_
+#define NGX_MESSAGE_HANDLER_H_
+
+#include <ts/ts.h>
+#include <cstdarg>
+
+#include "net/instaweb/util/public/basictypes.h"
+#include "net/instaweb/util/public/google_message_handler.h"
+#include "net/instaweb/util/public/message_handler.h"
+#include "net/instaweb/util/public/scoped_ptr.h"
+#include "net/instaweb/util/public/string.h"
+#include "net/instaweb/util/public/string_util.h"
+
+namespace net_instaweb {
+
+ class AbstractMutex;
+ class SharedCircularBuffer;
+ class Timer;
+ class Writer;
+
+ class AtsMessageHandler : public GoogleMessageHandler {
+ public:
+ explicit AtsMessageHandler(AbstractMutex* mutex);
+
+ void set_buffer(SharedCircularBuffer* buff);
+
+ void SetPidString(const int64 pid) {
+ pid_string_ = StrCat("[", Integer64ToString(pid), "]");
+ }
+ // Dump contents of SharedCircularBuffer.
+ bool Dump(Writer* writer);
+
+ protected:
+ virtual void MessageVImpl(MessageType type, const char* msg, va_list args);
+
+ virtual void FileMessageVImpl(MessageType type, const char* filename,
+ int line, const char* msg, va_list args);
+
+ private:
+ GoogleString Format(const char* msg, va_list args);
+
+ scoped_ptr<AbstractMutex> mutex_;
+ GoogleString pid_string_;
+ GoogleMessageHandler handler_;
+ SharedCircularBuffer* buffer_;
+
+ DISALLOW_COPY_AND_ASSIGN(AtsMessageHandler);
+ };
+
+} // namespace net_instaweb
+
+#endif // NGX_MESSAGE_HANDLER_H_
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/083abd4f/plugins/experimental/ats_speed/ats_process_context.cc
----------------------------------------------------------------------
diff --git a/plugins/experimental/ats_speed/ats_process_context.cc b/plugins/experimental/ats_speed/ats_process_context.cc
new file mode 100644
index 0000000..2cc47a7
--- /dev/null
+++ b/plugins/experimental/ats_speed/ats_process_context.cc
@@ -0,0 +1,76 @@
+// Copyright 2013 We-Amp B.V.
+//
+// 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.
+//
+// Author: oschaaf@we-amp.com (Otto van der Schaaf)
+#include "ats_process_context.h"
+
+#include <vector>
+
+#include "ats_rewrite_driver_factory.h"
+#include "ats_server_context.h"
+#include "ats_message_handler.h"
+#include "ats_thread_system.h"
+
+#include "net/instaweb/automatic/public/proxy_fetch.h"
+#include "net/instaweb/util/public/pthread_shared_mem.h"
+
+namespace net_instaweb {
+
+AtsProcessContext::AtsProcessContext() {
+ AtsThreadSystem* ts = new AtsThreadSystem();
+ message_handler_.reset(new AtsMessageHandler(ts->NewMutex()));
+ driver_factory_.reset(new AtsRewriteDriverFactory(ts));
+ server_context_ = driver_factory()->MakeAtsServerContext();
+
+ AtsRewriteOptions* root_options_ = (AtsRewriteOptions*)driver_factory_->default_options();
+ AtsRewriteOptions* server_options = root_options_->Clone();
+ AtsRewriteOptions* options = new AtsRewriteOptions(driver_factory_->thread_system());
+ server_options->Merge(*options);
+ delete options;
+
+ server_context_->global_options()->Merge(*server_options);
+ delete server_options;
+
+ message_handler_->Message(kInfo,"global default options:\r\n[%s]",driver_factory_->default_options()->OptionsToString().c_str());
+ message_handler_->Message(kInfo,"server ctx default options:\r\n[%s]",server_context_->global_options()->OptionsToString().c_str());
+ std::vector<SystemServerContext*> server_contexts;
+ server_contexts.push_back(server_context_);
+
+ //Statistics* statistics =
+ // driver_factory_->MakeGlobalSharedMemStatistics(*(SystemRewriteOptions*)server_context_->global_options());
+ GoogleString error_message;
+ int error_index = -1;
+ Statistics* global_statistics = NULL;
+ driver_factory_.get()->PostConfig(
+ server_contexts, &error_message, &error_index, &global_statistics);
+ if (error_index != -1) {
+ server_contexts[error_index]->message_handler()->Message(
+ kError, "ngx_pagespeed is enabled. %s", error_message.c_str());
+ //return NGX_ERROR;
+ CHECK(false);
+ }
+
+ AtsRewriteDriverFactory::InitStats(global_statistics);
+
+ driver_factory()->RootInit();
+ driver_factory()->ChildInit();
+
+ proxy_fetch_factory_.reset(new ProxyFetchFactory(server_context_));
+ message_handler_->Message(kInfo, "Process context constructed");
+}
+
+AtsProcessContext::~AtsProcessContext() {
+}
+
+} // namespace net_instaweb
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/083abd4f/plugins/experimental/ats_speed/ats_process_context.h
----------------------------------------------------------------------
diff --git a/plugins/experimental/ats_speed/ats_process_context.h b/plugins/experimental/ats_speed/ats_process_context.h
new file mode 100644
index 0000000..aae2118
--- /dev/null
+++ b/plugins/experimental/ats_speed/ats_process_context.h
@@ -0,0 +1,49 @@
+// Copyright 2013 We-Amp B.V.
+//
+// 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.
+//
+// Author: oschaaf@we-amp.com (Otto van der Schaaf)
+#ifndef ATS_PROCESS_CONTEXT_H_
+#define ATS_PROCESS_CONTEXT_H_
+
+#include "net/instaweb/util/public/google_message_handler.h"
+#include "net/instaweb/util/public/message_handler.h"
+#include "net/instaweb/util/public/scoped_ptr.h"
+
+namespace net_instaweb {
+
+class AtsRewriteDriverFactory;
+class ProxyFetchFactory;
+class AtsServerContext;
+
+class AtsProcessContext {
+ public:
+ explicit AtsProcessContext();
+ virtual ~AtsProcessContext();
+
+ // TODO(oschaaf): const correctness
+ MessageHandler* message_handler() { return message_handler_.get(); }
+ AtsRewriteDriverFactory* driver_factory() { return driver_factory_.get(); }
+ ProxyFetchFactory* proxy_fetch_factory() { return proxy_fetch_factory_.get(); }
+ AtsServerContext* server_context() { return server_context_; }
+ private:
+ scoped_ptr<MessageHandler> message_handler_;
+ scoped_ptr<AtsRewriteDriverFactory> driver_factory_;
+ scoped_ptr<ProxyFetchFactory> proxy_fetch_factory_;
+ AtsServerContext* server_context_;
+};
+
+
+} // namespace net_instaweb
+
+#endif // ATS_PROCESS_CONTEXT_H_