This is an automated email from the ASF dual-hosted git repository.

zwoop pushed a commit to branch master
in repository https://git-dual.apache.org/repos/asf/trafficserver.git

The following commit(s) were added to refs/heads/master by this push:
       new  3d7cdbf   TS-4147 Allow gzip plugin to be a remap plugin
3d7cdbf is described below

commit 3d7cdbfa1dc52e81c2698dfbac526dec1d336246
Author: Meera Mosale Nataraja <[email protected]>
AuthorDate: Mon Apr 18 12:51:03 2016 -0700

    TS-4147 Allow gzip plugin to be a remap plugin
---
 doc/admin-guide/plugins/gzip.en.rst |   9 +-
 plugins/gzip/gzip.cc                | 159 +++++++++++++++++++-----
 plugins/gzip/tests/test_gzip.py     | 241 ++++++++++++++++++++++++++++++++++++
 3 files changed, 375 insertions(+), 34 deletions(-)

diff --git a/doc/admin-guide/plugins/gzip.en.rst 
b/doc/admin-guide/plugins/gzip.en.rst
index 51a55f3..bf84a18 100644
--- a/doc/admin-guide/plugins/gzip.en.rst
+++ b/doc/admin-guide/plugins/gzip.en.rst
@@ -56,7 +56,8 @@ are no special steps necessary for its installation.
 Configuration
 =============
 
-This plugin is enabled globally for |TS| by adding the following to your
+This plugin can be used as either global plugin or remap plugin.
+It can be enabled globally for |TS| by adding the following to your
 :file:`plugin.config`::
 
     gzip.so
@@ -80,11 +81,17 @@ configuration provided with the plugin's source)::
 
     gzip.so <path-to-plugin>/sample.gzip.config
 
+This can be used as remap plugin by pointing to config file in remap rule 
+:file:`remap.config`::
+    @plugin=gzip.so @pparam=--config=<path-to-plugin>/sample.gzip.config 
+
 The following sections detail the options you may specify in the plugin's
 configuration file. Options may be used globally, or may be specified on a
 per-site basis by preceding them with a `[<site>]` line, where `<site>` is the
 client-facing domain for which the options should apply.
 
+Per site configuration for remap plugin should be ignored.
+
 cache
 -----
 
diff --git a/plugins/gzip/gzip.cc b/plugins/gzip/gzip.cc
index 8c978b7..10970c8 100644
--- a/plugins/gzip/gzip.cc
+++ b/plugins/gzip/gzip.cc
@@ -30,6 +30,7 @@
 #include "debug_macros.h"
 #include "misc.h"
 #include "configuration.h"
+#include "ts/remap.h"
 
 using namespace std;
 using namespace Gzip;
@@ -594,18 +595,23 @@ gzip_transform_add(TSHttpTxn txnp, HostConfiguration *hc, 
int compress_type)
 }
 
 HostConfiguration *
-find_host_configuration(TSHttpTxn /* txnp ATS_UNUSED */, TSMBuffer bufp, 
TSMLoc locp)
+find_host_configuration(TSHttpTxn /* txnp ATS_UNUSED */, TSMBuffer bufp, 
TSMLoc locp, Configuration *config)
 {
   TSMLoc fieldp = TSMimeHdrFieldFind(bufp, locp, TS_MIME_FIELD_HOST, 
TS_MIME_LEN_HOST);
   int strl = 0;
   const char *strv = NULL;
+  HostConfiguration *host_configuration;
 
   if (fieldp) {
     strv = TSMimeHdrFieldValueStringGet(bufp, locp, fieldp, -1, &strl);
     TSHandleMLocRelease(bufp, locp, fieldp);
   }
-
-  return cur_config->find(strv, strl);
+  if (config == NULL) {
+    host_configuration = cur_config->find(strv, strl);
+  } else {
+    host_configuration = config->find(strv, strl);
+  }
+  return host_configuration;
 }
 
 static int
@@ -685,45 +691,67 @@ transform_plugin(TSCont contp, TSEvent event, void *edata)
   return 0;
 }
 
-static int
-transform_global_plugin(TSCont /* contp ATS_UNUSED */, TSEvent event, void 
*edata)
+/**
+ * This handles gzip request
+ * 1. Reads the client request header
+ * 2. For global plugin, get host configuration from global config
+ *    For remap plugin, get host configuration from configs populated through 
remap
+ * 3. Check for Accept encoding
+ * 4. Schedules TS_HTTP_CACHE_LOOKUP_COMPLETE_HOOK and TS_HTTP_TXN_CLOSE_HOOK 
for
+ *    further processing
+ */
+static void
+handle_gzip_request(TSHttpTxn txnp, Configuration *config)
 {
-  TSHttpTxn txnp = (TSHttpTxn)edata;
   TSMBuffer req_buf;
   TSMLoc req_loc;
+  HostConfiguration *hc;
 
-  switch (event) {
-  case TS_EVENT_HTTP_READ_REQUEST_HDR:
-    if (TSHttpTxnClientReqGet(txnp, &req_buf, &req_loc) == TS_SUCCESS) {
-      HostConfiguration *hc = find_host_configuration(txnp, req_buf, req_loc); 
// Get a lease on the
-      bool allowed = false;
-
-      if (hc->enabled()) {
-        if (hc->has_disallows()) {
-          int url_len;
-          char *url = TSHttpTxnEffectiveUrlStringGet(txnp, &url_len);
-
-          allowed = hc->is_url_allowed(url, url_len);
-          TSfree(url);
-        } else {
-          allowed = true;
-        }
-      }
-
-      if (allowed) {
-        TSCont transform_contp = TSContCreate(transform_plugin, NULL);
+  if (TSHttpTxnClientReqGet(txnp, &req_buf, &req_loc) == TS_SUCCESS) {
+    if (config == NULL) {
+      hc = find_host_configuration(txnp, req_buf, req_loc, NULL); // Get a 
lease on the global config
+    } else {
+      hc = find_host_configuration(txnp, req_buf, req_loc, config); // Get a 
lease on the local config passed through doRemap
+    }
+    bool allowed = false;
 
-        info("Kicking off gzip plugin for request");
+    if (hc->enabled()) {
+      if (hc->has_disallows()) {
+        int url_len;
+        char *url = TSHttpTxnEffectiveUrlStringGet(txnp, &url_len);
 
-        TSContDataSet(transform_contp, (void *)hc);
-        normalize_accept_encoding(txnp, req_buf, req_loc);
-        TSHttpTxnHookAdd(txnp, TS_HTTP_CACHE_LOOKUP_COMPLETE_HOOK, 
transform_contp);
-        TSHttpTxnHookAdd(txnp, TS_HTTP_TXN_CLOSE_HOOK, transform_contp); // To 
release the config
+        allowed = hc->is_url_allowed(url, url_len);
+        TSfree(url);
       } else {
-        hc->release(); // No longer need this configuration, release it.
+        allowed = true;
       }
-      TSHandleMLocRelease(req_buf, TS_NULL_MLOC, req_loc);
     }
+
+    if (allowed) {
+      TSCont transform_contp = TSContCreate(transform_plugin, NULL);
+
+      TSContDataSet(transform_contp, (void *)hc);
+
+      info("Kicking off gzip plugin for request");
+      normalize_accept_encoding(txnp, req_buf, req_loc);
+      TSHttpTxnHookAdd(txnp, TS_HTTP_CACHE_LOOKUP_COMPLETE_HOOK, 
transform_contp);
+      TSHttpTxnHookAdd(txnp, TS_HTTP_TXN_CLOSE_HOOK, transform_contp); // To 
release the config
+    } else {
+      hc->release(); // No longer need this configuration, release it.
+    }
+    TSHandleMLocRelease(req_buf, TS_NULL_MLOC, req_loc);
+  }
+}
+
+static int
+transform_global_plugin(TSCont /* contp ATS_UNUSED */, TSEvent event, void 
*edata)
+{
+  TSHttpTxn txnp = (TSHttpTxn)edata;
+
+  switch (event) {
+  case TS_EVENT_HTTP_READ_REQUEST_HDR:
+    // Handle gzip request and use the global configs
+    handle_gzip_request(txnp, NULL);
     break;
 
   default:
@@ -796,3 +824,68 @@ TSPluginInit(int argc, const char *argv[])
   TSHttpHookAdd(TS_HTTP_READ_REQUEST_HDR_HOOK, transform_global_contp);
   info("loaded");
 }
+
+//////////////////////////////////////////////////////////////////////////////
+// Initialize the plugin as a remap plugin.
+//
+TSReturnCode
+TSRemapInit(TSRemapInterface *api_info, char *errbuf, int errbuf_size)
+{
+  if (!api_info) {
+    strncpy(errbuf, "[tsremap_init] - Invalid TSRemapInterface argument", 
errbuf_size - 1);
+    return TS_ERROR;
+  }
+
+  if (api_info->tsremap_version < TSREMAP_VERSION) {
+    snprintf(errbuf, errbuf_size - 1, "[TSRemapInit] - Incorrect API version 
%ld.%ld", api_info->tsremap_version >> 16,
+             (api_info->tsremap_version & 0xffff));
+    return TS_ERROR;
+  }
+
+  info("The gzip plugin is successfully initialized");
+  return TS_SUCCESS;
+}
+
+TSReturnCode
+TSRemapNewInstance(int argc, char *argv[], void **instance, char *errbuf, int 
errbuf_size)
+{
+  info("Instantiating a new gzip plugin remap rule");
+  info("Reading gzip config from file = %s", argv[2]);
+
+  const char *config_path = NULL;
+
+  if (argc > 4) {
+    fatal("The gzip plugin does not accept more than one plugin argument");
+  } else if (argc == 3) {
+    config_path = TSstrdup(argv[2]);
+  }
+  global_hidden_header_name = init_hidden_header_name();
+
+  Configuration *config = Configuration::Parse(config_path);
+  *instance = config;
+
+  free((void *)config_path);
+  info("Configuration loaded");
+  return TS_SUCCESS;
+}
+
+void
+TSRemapDeleteInstance(void *instance)
+{
+  debug("Cleanup configs read from remap");
+  static_cast<Configuration *>(instance)->release_all();
+}
+
+TSRemapStatus
+TSRemapDoRemap(void *instance, TSHttpTxn txnp, TSRemapRequestInfo *rri)
+{
+  if (NULL == instance) {
+    info("No Rules configured, falling back to default");
+  } else {
+    info("Remap Rules configured for gzip");
+    Configuration *config = (Configuration *)instance;
+    // Handle gzip request and use the configs populated from remap instance
+    handle_gzip_request(txnp, config);
+  }
+  return TSREMAP_NO_REMAP;
+}
diff --git a/plugins/gzip/tests/test_gzip.py b/plugins/gzip/tests/test_gzip.py
new file mode 100644
index 0000000..137f271
--- /dev/null
+++ b/plugins/gzip/tests/test_gzip.py
@@ -0,0 +1,241 @@
+#  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.
+
+import requests
+import logging
+import random, string
+
+import tsqa.test_cases
+import tsqa.utils
+import tsqa.endpoint
+import os
+
+origin_content_length = 0
+log = logging.getLogger(__name__)
+
+#Test positive cases of remap gzip plugin
+gzip_remap_bench = [
+             # Test gzip
+            { "args": "@pparam=gzip1.config",
+              "files": [("gzip1.config", "enabled true\nremove-accept-encoding 
true\ncache false\ncompressible-content-type text/*\n")
+                       ],
+            },
+            { "args": "@pparam=gzip2.config",
+              "files": [("gzip2.config", "enabled true\nremove-accept-encoding 
false\ncache false\ncompressible-content-type text/*\n")
+                       ],
+            },
+            { "args": "@pparam=gzip3.config",
+              "files": [("gzip3.config", "enabled true\nremove-accept-encoding 
true\ncache true\ncompressible-content-type text/*\n")
+                       ],
+            },
+            { "args": "@pparam=gzip4.config",
+              "files": [("gzip4.config", "enabled true\nremove-accept-encoding 
true\ncache true\ncompressible-content-type text/*\nflush true\n")
+                       ],
+            },
+            { "args": "@pparam=gzip5.config",
+              "files": [("gzip5.config", "enabled true\nremove-accept-encoding 
true\ncache true\ncompressible-content-type text/*\nflush false\n")
+                       ],
+            },
+            ]
+
+#Test negative cases of remap gzip plugin
+gzip_remap_negative_bench =  [
+            #Test when gzip is disabled
+            { "args": "@pparam=gzip_negative1.config",
+              "files": [("gzip_negative1.config", "enabled 
false\nremove-accept-encoding true\ncache false\ncompressible-content-type 
text/*\n")
+                        ],
+            },
+            #Test when compressible content doesn't match
+            { "args": "@pparam=gzip_negative2.config",
+              "files": [("gzip_negative2.config", "enabled 
true\nremove-accept-encoding true\ncache false\ncompressible-content-type 
!text/*\n")
+                        ],
+            },
+            #Test when disallow is configured to match some pattern
+            { "args": "@pparam=gzip_negative3.config",
+              "files": [("gzip_negative3.config", "enabled 
true\nremove-accept-encoding true\ncache false\ncompressible-content-type 
text/*\ndisallow *test*\n")
+                        ],
+            },
+            ]
+
+#Test global gzip plugin
+gzip_global_bench = [
+            { "args": "gzip_global1.config",
+              "files": [("gzip_global1.config", "enabled 
true\nremove-accept-encoding true\ncache true\ncompressible-content-type 
text/*\n")
+                       ],
+            },
+            ]
+
+#Set up an origin server which returns random string.
+def handler(request):
+    global origin_content_length
+    rand_string = ''.join(random.choice(string.lowercase) for i in range(500))
+    origin_content_length = len(rand_string)
+    return rand_string
+
+def create_config_files(env, test):
+    # Create gzip config files.
+    for file in test['files']:
+        filename = file[0]
+        content = file[1]
+        path = os.path.join(env.layout.prefix, 'etc/trafficserver', filename);
+        with open(path, 'w') as fh:
+            fh.write(content)
+
+class StaticEnvironmentCase(tsqa.test_cases.EnvironmentCase):
+    @classmethod
+    def getEnv(cls):
+        #layout = tsqa.environment.Layout('/opt/gitlab-gzip')
+        layout = tsqa.environment.Layout('/opt/apache/trafficserver.TS-4147')
+        env = tsqa.environment.Environment()
+        env.clone(layout=layout)
+        return env
+
+#Test gzip remap plugin
+class TestGzipRemapPlugin(tsqa.test_cases.DynamicHTTPEndpointCase, 
StaticEnvironmentCase):
+    @classmethod
+    def setUpEnv(cls, env):
+        cls.configs['plugin.config'].add_line('xdebug.so')
+        cls.configs['records.config']['CONFIG'].update({
+           'proxy.config.diags.debug.enabled': 1,
+           'proxy.config.diags.debug.tags': '.*',
+           'proxy.config.diags.debug.tags': 'gzip.*',
+           'proxy.config.url_remap.pristine_host_hdr': 1,})
+
+        cls.http_endpoint.add_handler('/path/to/object', handler)
+
+        def add_remap_rule(remap_prefix, remap_index, test):
+            host = 'test_{0}_{1}.example.com'.format(remap_prefix, remap_index)
+            port = 
cls.configs['records.config']['CONFIG']['proxy.config.http.server_ports']
+            args = test['args']
+            remap_rule = 'map http://{0}:{1} http://127.0.0.1:{2} 
@plugin=gzip.so {3}'.format(host, port, cls.http_endpoint.address[1], args)
+            log.info('  {0}'.format(remap_rule))
+            cls.configs['remap.config'].add_line(remap_rule)
+
+        # Prepare gzip tests related remap rules.
+        i = 0
+        for test in gzip_remap_bench:
+            add_remap_rule("gzip", i, test)
+            create_config_files(env, test)
+            i+=1
+
+        #Prepare negative gzip tests related remap rules.
+        i = 0
+        for test in gzip_remap_negative_bench:
+            add_remap_rule("gzip_negative", i, test)
+            create_config_files(env, test)
+            i+=1
+
+    def send_request(self,remap_prefix, remap_index):
+        host = 'test_{0}_{1}.example.com'.format( remap_prefix, remap_index)
+        port = 
self.configs['records.config']['CONFIG']['proxy.config.http.server_ports']
+        url = 'http://127.0.0.1:{0}/path/to/object'.format(port)
+        log.info('host is {0}, port is {1}, url is {2}'.format(host, port, 
url))
+        s = requests.Session()
+        s.headers.update({'Host': '{0}:{1}'.format(host, port)})
+        s.headers.update({'Accept-Encoding:': 'gzip'})
+        response = s.get(url)
+        log.info('Response headers obtained: {0}'.format(response.headers))
+        return response
+
+    def send_gzip_request(self, remap_prefix, remap_index):
+        '''
+        Sends a gzip request to the traffic server
+        '''
+        response = self.send_request(remap_prefix, remap_index)
+        self.assertEqual(response.status_code, 200)
+        self.assertEqual(response.headers['Content-Encoding'], 'gzip')
+        self.assertLess(int(response.headers['Content-Length']), 
int(origin_content_length))
+
+    def send_gzip_request_negative(self, remap_prefix, remap_index):
+        '''
+        Sends a gzip request to the traffic server
+        '''
+        response = self.send_request(remap_prefix, remap_index)
+        self.assertEqual(response.status_code, 200)
+        self.assertEqual(int(response.headers['Content-Length']), 
int(origin_content_length))
+
+    def test_gzip_remap_plugin(self):
+        i = 0
+        for test in gzip_remap_bench:
+            self.send_gzip_request('gzip', i)
+            i += 1
+
+        i = 0
+        for test in gzip_remap_negative_bench:
+            self.send_gzip_request_negative('gzip_negative', i)
+            i += 1
+
+#Test gzip global plugin
+class TestGzipGlobalPlugin(tsqa.test_cases.DynamicHTTPEndpointCase, 
StaticEnvironmentCase):
+    @classmethod
+    def setUpEnv(cls, env):
+        cls.configs['plugin.config'].add_line('xdebug.so')
+
+        cls.configs['records.config']['CONFIG'].update({
+           'proxy.config.diags.debug.enabled': 1,
+           'proxy.config.diags.debug.tags': 'gzip.*',
+           'proxy.config.url_remap.pristine_host_hdr': 1,})
+
+        cls.http_endpoint.add_handler('/path/to/object', handler)
+
+        def add_remap_rule(remap_prefix, remap_index):
+            host = 'test_{0}_{1}.example.com'.format(remap_prefix, remap_index)
+            port = 
cls.configs['records.config']['CONFIG']['proxy.config.http.server_ports']
+            remap_rule = 'map http://{0}:{1} 
http://127.0.0.1:{2}'.format(host, port, cls.http_endpoint.address[1])
+            log.info('  {0}'.format(remap_rule))
+            cls.configs['remap.config'].add_line(remap_rule)
+
+        def add_global_plugin_rule(test):
+            args = test['args']
+            plugin_rule = 'gzip.so {0}'.format(args)
+            log.info('  {0}'.format(plugin_rule))
+            cls.configs['plugin.config'].add_line(plugin_rule)
+
+        # Prepare gzip plugin rules
+        i = 0
+        for test in gzip_global_bench:
+            add_remap_rule("gzip_global",i)
+            add_global_plugin_rule(test)
+            create_config_files(env, test)
+            i+=1
+
+    def send_request(self,remap_prefix, remap_index):
+        host = 'test_{0}_{1}.example.com'.format( remap_prefix, remap_index)
+        port = 
self.configs['records.config']['CONFIG']['proxy.config.http.server_ports']
+        url = 'http://127.0.0.1:{0}/path/to/object'.format(port)
+        log.info('host is {0}, port is {1}, url is {2}'.format(host, port, 
url))
+        s = requests.Session()
+        s.headers.update({'Host': '{0}:{1}'.format(host, port)})
+        s.headers.update({'Accept-Encoding:': 'gzip'})
+        response = s.get(url)
+        log.info('Response headers obtained: {0}'.format(response.headers))
+        return response
+
+    def send_global_gzip_request(self, remap_prefix, remap_index):
+        '''
+        Sends a gzip request to the traffic server
+        '''
+        response = self.send_request(remap_prefix, remap_index)
+        self.assertEqual(response.status_code, 200)
+        self.assertEqual(response.headers['Content-Encoding'], 'gzip')
+        self.assertLess(int(response.headers['Content-Length']), 
int(origin_content_length))
+
+    def test_gzip_global_plugin(self):
+        i = 0
+        for test in gzip_global_bench:
+            self.send_global_gzip_request("gzip_global", i)
+            i += 1
+

-- 
To stop receiving notification emails like this one, please contact
['"[email protected]" <[email protected]>'].

Reply via email to