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/20 22:57:47 UTC
[7/7] git commit: ats_pagespeed: rename ats_speed -> ats_pagespeed
ats_pagespeed: rename ats_speed -> ats_pagespeed
Fixes TS-3005
Project: http://git-wip-us.apache.org/repos/asf/trafficserver/repo
Commit: http://git-wip-us.apache.org/repos/asf/trafficserver/commit/1fe51067
Tree: http://git-wip-us.apache.org/repos/asf/trafficserver/tree/1fe51067
Diff: http://git-wip-us.apache.org/repos/asf/trafficserver/diff/1fe51067
Branch: refs/heads/master
Commit: 1fe51067bfa77ff2141d6988d65d7c36976da832
Parents: 335cbf4
Author: Otto van der Schaaf <os...@we-amp.com>
Authored: Wed Aug 20 22:52:56 2014 +0200
Committer: Otto van der Schaaf <os...@we-amp.com>
Committed: Wed Aug 20 22:52:56 2014 +0200
----------------------------------------------------------------------
plugins/experimental/ats_pagespeed/.gitignore | 15 +
plugins/experimental/ats_pagespeed/Makefile | 83 ++
.../ats_pagespeed/Makefile.psol_source | 49 +
plugins/experimental/ats_pagespeed/README.md | 52 +
.../ats_pagespeed/ats_base_fetch.cc | 142 +++
.../experimental/ats_pagespeed/ats_base_fetch.h | 88 ++
.../ats_pagespeed/ats_beacon_intercept.cc | 364 ++++++
.../ats_pagespeed/ats_beacon_intercept.h | 31 +
.../experimental/ats_pagespeed/ats_config.cc | 204 ++++
plugins/experimental/ats_pagespeed/ats_config.h | 90 ++
.../ats_pagespeed/ats_header_utils.cc | 96 ++
.../ats_pagespeed/ats_header_utils.h | 41 +
.../ats_pagespeed/ats_log_message_handler.cc | 101 ++
.../ats_pagespeed/ats_log_message_handler.h | 36 +
.../ats_pagespeed/ats_message_handler.cc | 114 ++
.../ats_pagespeed/ats_message_handler.h | 75 ++
.../experimental/ats_pagespeed/ats_pagespeed.cc | 1093 ++++++++++++++++++
.../experimental/ats_pagespeed/ats_pagespeed.h | 102 ++
.../ats_pagespeed/ats_process_context.cc | 86 ++
.../ats_pagespeed/ats_process_context.h | 58 +
.../ats_pagespeed/ats_resource_intercept.cc | 363 ++++++
.../ats_pagespeed/ats_resource_intercept.h | 29 +
.../ats_pagespeed/ats_rewrite_driver_factory.cc | 196 ++++
.../ats_pagespeed/ats_rewrite_driver_factory.h | 113 ++
.../ats_pagespeed/ats_rewrite_options.cc | 263 +++++
.../ats_pagespeed/ats_rewrite_options.h | 103 ++
.../ats_pagespeed/ats_server_context.cc | 46 +
.../ats_pagespeed/ats_server_context.h | 56 +
.../ats_pagespeed/ats_thread_system.h | 50 +
.../experimental/ats_pagespeed/gzip/Makefile | 24 +
plugins/experimental/ats_pagespeed/gzip/README | 4 +
.../ats_pagespeed/gzip/configuration.cc | 264 +++++
.../ats_pagespeed/gzip/configuration.h | 84 ++
.../ats_pagespeed/gzip/debug_macros.h | 59 +
plugins/experimental/ats_pagespeed/gzip/gzip.cc | 826 +++++++++++++
.../experimental/ats_pagespeed/gzip/gzip.config | 6 +
plugins/experimental/ats_pagespeed/gzip/misc.cc | 197 ++++
plugins/experimental/ats_pagespeed/gzip/misc.h | 84 ++
.../ats_pagespeed/scripts/prepare_psol.sh | 93 ++
plugins/experimental/ats_speed/.gitignore | 15 -
plugins/experimental/ats_speed/Makefile | 83 --
.../experimental/ats_speed/Makefile.psol_source | 49 -
plugins/experimental/ats_speed/README.md | 52 -
.../experimental/ats_speed/ats_base_fetch.cc | 142 ---
plugins/experimental/ats_speed/ats_base_fetch.h | 88 --
.../ats_speed/ats_beacon_intercept.cc | 364 ------
.../ats_speed/ats_beacon_intercept.h | 31 -
plugins/experimental/ats_speed/ats_config.cc | 204 ----
plugins/experimental/ats_speed/ats_config.h | 90 --
.../experimental/ats_speed/ats_header_utils.cc | 96 --
.../experimental/ats_speed/ats_header_utils.h | 41 -
.../ats_speed/ats_log_message_handler.cc | 101 --
.../ats_speed/ats_log_message_handler.h | 36 -
.../ats_speed/ats_message_handler.cc | 114 --
.../ats_speed/ats_message_handler.h | 75 --
.../ats_speed/ats_process_context.cc | 86 --
.../ats_speed/ats_process_context.h | 58 -
.../ats_speed/ats_resource_intercept.cc | 363 ------
.../ats_speed/ats_resource_intercept.h | 29 -
.../ats_speed/ats_rewrite_driver_factory.cc | 196 ----
.../ats_speed/ats_rewrite_driver_factory.h | 113 --
.../ats_speed/ats_rewrite_options.cc | 263 -----
.../ats_speed/ats_rewrite_options.h | 103 --
.../ats_speed/ats_server_context.cc | 46 -
.../experimental/ats_speed/ats_server_context.h | 56 -
plugins/experimental/ats_speed/ats_speed.cc | 1093 ------------------
plugins/experimental/ats_speed/ats_speed.h | 102 --
.../experimental/ats_speed/ats_thread_system.h | 50 -
plugins/experimental/ats_speed/gzip/Makefile | 24 -
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 | 93 --
78 files changed, 5780 insertions(+), 5780 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/1fe51067/plugins/experimental/ats_pagespeed/.gitignore
----------------------------------------------------------------------
diff --git a/plugins/experimental/ats_pagespeed/.gitignore b/plugins/experimental/ats_pagespeed/.gitignore
new file mode 100644
index 0000000..a12b1d2
--- /dev/null
+++ b/plugins/experimental/ats_pagespeed/.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/1fe51067/plugins/experimental/ats_pagespeed/Makefile
----------------------------------------------------------------------
diff --git a/plugins/experimental/ats_pagespeed/Makefile b/plugins/experimental/ats_pagespeed/Makefile
new file mode 100644
index 0000000..9177b44
--- /dev/null
+++ b/plugins/experimental/ats_pagespeed/Makefile
@@ -0,0 +1,83 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+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
+#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_pagespeed.so -g -pipe -O3 -fpic *.cc -lstdc++ -lstdc++ -lpthread $(PSOL_LIBS) -lrt
+
+all: psol gzip/gzip.so ats_pagespeed.so
+
+1.8.31.4.tar.gz:
+ wget --no-check-certificate https://dl.google.com/dl/page-speed/psol/1.8.31.4.tar.gz
+
+psol/: 1.8.31.4.tar.gz
+ tar -xzvf 1.8.31.4.tar.gz
+
+gzip/gzip.so:
+ cd gzip && make
+
+install: all
+ $(TSXS) -i -o ats_pagespeed.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/1fe51067/plugins/experimental/ats_pagespeed/Makefile.psol_source
----------------------------------------------------------------------
diff --git a/plugins/experimental/ats_pagespeed/Makefile.psol_source b/plugins/experimental/ats_pagespeed/Makefile.psol_source
new file mode 100755
index 0000000..f4c35723
--- /dev/null
+++ b/plugins/experimental/ats_pagespeed/Makefile.psol_source
@@ -0,0 +1,49 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+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_pagespeed.so -g -pipe -Wall -Werror -O3 -fpic *.cc -lstdc++ -lpthread -lrt $(PSOL_LIBS)
+
+all: gzip/gzip.so ats_pagespeed.so
+
+install: all
+ $(TSXS) -i -o ats_pagespeed.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/1fe51067/plugins/experimental/ats_pagespeed/README.md
----------------------------------------------------------------------
diff --git a/plugins/experimental/ats_pagespeed/README.md b/plugins/experimental/ats_pagespeed/README.md
new file mode 100644
index 0000000..6c4ff15
--- /dev/null
+++ b/plugins/experimental/ats_pagespeed/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_pagespeed.so
+gzip.so /usr/local/etc/trafficserver/gzip.config
+````
+gzip.so also is build with ats_pagespeed, 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/1fe51067/plugins/experimental/ats_pagespeed/ats_base_fetch.cc
----------------------------------------------------------------------
diff --git a/plugins/experimental/ats_pagespeed/ats_base_fetch.cc b/plugins/experimental/ats_pagespeed/ats_base_fetch.cc
new file mode 100644
index 0000000..769e79b
--- /dev/null
+++ b/plugins/experimental/ats_pagespeed/ats_base_fetch.cc
@@ -0,0 +1,142 @@
+/** @file
+
+ A brief file description
+
+ @section license License
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+#include "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/1fe51067/plugins/experimental/ats_pagespeed/ats_base_fetch.h
----------------------------------------------------------------------
diff --git a/plugins/experimental/ats_pagespeed/ats_base_fetch.h b/plugins/experimental/ats_pagespeed/ats_base_fetch.h
new file mode 100644
index 0000000..63b952f
--- /dev/null
+++ b/plugins/experimental/ats_pagespeed/ats_base_fetch.h
@@ -0,0 +1,88 @@
+/** @file
+
+ A brief file description
+
+ @section license License
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+#ifndef ATS_BASE_FETCH_H_
+#define ATS_BASE_FETCH_H_
+
+#include <string>
+
+#include <ts/ts.h>
+
+#include "ats_pagespeed.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/1fe51067/plugins/experimental/ats_pagespeed/ats_beacon_intercept.cc
----------------------------------------------------------------------
diff --git a/plugins/experimental/ats_pagespeed/ats_beacon_intercept.cc b/plugins/experimental/ats_pagespeed/ats_beacon_intercept.cc
new file mode 100644
index 0000000..88cf016
--- /dev/null
+++ b/plugins/experimental/ats_pagespeed/ats_beacon_intercept.cc
@@ -0,0 +1,364 @@
+/** @file
+
+ A brief file description
+
+ @section license License
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+#include "ats_beacon_intercept.h"
+#include "ats_pagespeed.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_pagespeed_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) {
+ // OS: Looks like on 5.x we sometimes receive read complete / EOS events twice,
+ // which needs looking into. Probably this intercept is doing something it shouldn't
+ if (cont_data->output.buffer) {
+ TSDebug("ats_pagespeed", "Received read complete / EOS twice?!");
+ return true;
+ }
+ 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(),
+ // TODO(oschaaf): determine these for real.
+ "www.foo.com",
+ 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/1fe51067/plugins/experimental/ats_pagespeed/ats_beacon_intercept.h
----------------------------------------------------------------------
diff --git a/plugins/experimental/ats_pagespeed/ats_beacon_intercept.h b/plugins/experimental/ats_pagespeed/ats_beacon_intercept.h
new file mode 100644
index 0000000..d53d81c
--- /dev/null
+++ b/plugins/experimental/ats_pagespeed/ats_beacon_intercept.h
@@ -0,0 +1,31 @@
+/** @file
+
+ A brief file description
+
+ @section license License
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+#ifndef _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/1fe51067/plugins/experimental/ats_pagespeed/ats_config.cc
----------------------------------------------------------------------
diff --git a/plugins/experimental/ats_pagespeed/ats_config.cc b/plugins/experimental/ats_pagespeed/ats_config.cc
new file mode 100644
index 0000000..e0adf42
--- /dev/null
+++ b/plugins/experimental/ats_pagespeed/ats_config.cc
@@ -0,0 +1,204 @@
+/** @file
+
+ A brief file description
+
+ @section license License
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+#include "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/1fe51067/plugins/experimental/ats_pagespeed/ats_config.h
----------------------------------------------------------------------
diff --git a/plugins/experimental/ats_pagespeed/ats_config.h b/plugins/experimental/ats_pagespeed/ats_config.h
new file mode 100644
index 0000000..d3b0e40
--- /dev/null
+++ b/plugins/experimental/ats_pagespeed/ats_config.h
@@ -0,0 +1,90 @@
+/** @file
+
+ A brief file description
+
+ @section license License
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+#ifndef 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/1fe51067/plugins/experimental/ats_pagespeed/ats_header_utils.cc
----------------------------------------------------------------------
diff --git a/plugins/experimental/ats_pagespeed/ats_header_utils.cc b/plugins/experimental/ats_pagespeed/ats_header_utils.cc
new file mode 100644
index 0000000..a61c784
--- /dev/null
+++ b/plugins/experimental/ats_pagespeed/ats_header_utils.cc
@@ -0,0 +1,96 @@
+/** @file
+
+ A brief file description
+
+ @section license License
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+#include "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/1fe51067/plugins/experimental/ats_pagespeed/ats_header_utils.h
----------------------------------------------------------------------
diff --git a/plugins/experimental/ats_pagespeed/ats_header_utils.h b/plugins/experimental/ats_pagespeed/ats_header_utils.h
new file mode 100644
index 0000000..1d6c567
--- /dev/null
+++ b/plugins/experimental/ats_pagespeed/ats_header_utils.h
@@ -0,0 +1,41 @@
+/** @file
+
+ A brief file description
+
+ @section license License
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+#ifndef 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/1fe51067/plugins/experimental/ats_pagespeed/ats_log_message_handler.cc
----------------------------------------------------------------------
diff --git a/plugins/experimental/ats_pagespeed/ats_log_message_handler.cc b/plugins/experimental/ats_pagespeed/ats_log_message_handler.cc
new file mode 100644
index 0000000..f41b9cc
--- /dev/null
+++ b/plugins/experimental/ats_pagespeed/ats_log_message_handler.cc
@@ -0,0 +1,101 @@
+/** @file
+
+ A brief file description
+
+ @section license License
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+#include "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/1fe51067/plugins/experimental/ats_pagespeed/ats_log_message_handler.h
----------------------------------------------------------------------
diff --git a/plugins/experimental/ats_pagespeed/ats_log_message_handler.h b/plugins/experimental/ats_pagespeed/ats_log_message_handler.h
new file mode 100644
index 0000000..bf57634
--- /dev/null
+++ b/plugins/experimental/ats_pagespeed/ats_log_message_handler.h
@@ -0,0 +1,36 @@
+/** @file
+
+ A brief file description
+
+ @section license License
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+#ifndef 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/1fe51067/plugins/experimental/ats_pagespeed/ats_message_handler.cc
----------------------------------------------------------------------
diff --git a/plugins/experimental/ats_pagespeed/ats_message_handler.cc b/plugins/experimental/ats_pagespeed/ats_message_handler.cc
new file mode 100644
index 0000000..370f317
--- /dev/null
+++ b/plugins/experimental/ats_pagespeed/ats_message_handler.cc
@@ -0,0 +1,114 @@
+/** @file
+
+ A brief file description
+
+ @section license License
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+#include "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/1fe51067/plugins/experimental/ats_pagespeed/ats_message_handler.h
----------------------------------------------------------------------
diff --git a/plugins/experimental/ats_pagespeed/ats_message_handler.h b/plugins/experimental/ats_pagespeed/ats_message_handler.h
new file mode 100644
index 0000000..b8248cf
--- /dev/null
+++ b/plugins/experimental/ats_pagespeed/ats_message_handler.h
@@ -0,0 +1,75 @@
+/** @file
+
+ A brief file description
+
+ @section license License
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+#ifndef 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_