You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by zw...@apache.org on 2017/05/03 14:04:10 UTC

[trafficserver] branch 7.1.x updated (6ff7931 -> 4d3a55a)

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

zwoop pushed a change to branch 7.1.x
in repository https://gitbox.apache.org/repos/asf/trafficserver.git.

      from  6ff7931   Configure option to disable CURL
       new  62631ff   brotli support
       new  823eb7a   new config option for allow urls.
       new  4d3a55a   The Brotli buffer pointer is was not being set to a default value

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "adds" were already present in the repository and have only
been added to this reference.


Summary of changes:
 configure.ac                        |   6 +
 doc/admin-guide/plugins/gzip.en.rst |  34 +++
 plugins/gzip/Makefile.inc           |   4 +
 plugins/gzip/README                 |  21 +-
 plugins/gzip/configuration.cc       |  80 ++++++-
 plugins/gzip/configuration.h        |  26 ++-
 plugins/gzip/gzip.cc                | 415 ++++++++++++++++++++++++++----------
 plugins/gzip/misc.cc                |  12 +-
 plugins/gzip/misc.h                 |  30 ++-
 9 files changed, 498 insertions(+), 130 deletions(-)

-- 
To stop receiving notification emails like this one, please contact
['"commits@trafficserver.apache.org" <co...@trafficserver.apache.org>'].

[trafficserver] 03/03: The Brotli buffer pointer is was not being set to a default value

Posted by zw...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

zwoop pushed a commit to branch 7.1.x
in repository https://gitbox.apache.org/repos/asf/trafficserver.git

commit 4d3a55a2508c90540f646755e8a291f8aad9b41f
Author: Bryan Call <bc...@apache.org>
AuthorDate: Tue May 2 17:22:17 2017 -0700

    The Brotli buffer pointer is was not being set to a default value
    
    (cherry picked from commit de9a9586cbb3648b7a6c8c5d080f7f041a21d446)
---
 plugins/gzip/gzip.cc | 1 +
 1 file changed, 1 insertion(+)

diff --git a/plugins/gzip/gzip.cc b/plugins/gzip/gzip.cc
index 64ac2e2..77a477a 100644
--- a/plugins/gzip/gzip.cc
+++ b/plugins/gzip/gzip.cc
@@ -109,6 +109,7 @@ data_alloc(int compression_type, int compression_algorithms)
     }
   }
 #if HAVE_BROTLI_ENCODE_H
+  data->bstrm.br = nullptr;
   if (compression_type & COMPRESSION_TYPE_BROTLI) {
     debug("gzip-transform: brotli compression. Create Brotli Encoder Instance.");
     data->bstrm.br = BrotliEncoderCreateInstance(0, 0, 0);

-- 
To stop receiving notification emails like this one, please contact
"commits@trafficserver.apache.org" <co...@trafficserver.apache.org>.

[trafficserver] 01/03: brotli support

Posted by zw...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

zwoop pushed a commit to branch 7.1.x
in repository https://gitbox.apache.org/repos/asf/trafficserver.git

commit 62631ffb16ddc597b6c0003f9b4b181e7dbd0101
Author: myraid <sa...@gmail.com>
AuthorDate: Tue Mar 7 15:52:20 2017 -0800

    brotli support
    
    remove enfore-brotli from readme
    
    (cherry picked from commit 39d045ecd4037ac2b8d62944c9a08d20667a23c5)
    
     Conflicts:
    	plugins/gzip/README
---
 configure.ac                        |   6 +
 doc/admin-guide/plugins/gzip.en.rst |  24 +++
 plugins/gzip/Makefile.inc           |   4 +
 plugins/gzip/README                 |  21 +-
 plugins/gzip/configuration.cc       |  38 +++-
 plugins/gzip/configuration.h        |  18 +-
 plugins/gzip/gzip.cc                | 412 ++++++++++++++++++++++++++----------
 plugins/gzip/misc.cc                |  12 +-
 plugins/gzip/misc.h                 |  30 ++-
 9 files changed, 442 insertions(+), 123 deletions(-)

diff --git a/configure.ac b/configure.ac
index 7b1a897..66e71b6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -444,6 +444,12 @@ AC_ARG_WITH([max-threads-per-type],
 )
 AC_SUBST(max_threads_per_type)
 
+# Check Brotli
+AC_CHECK_HEADERS([brotli/encode.h], [has_brotli=1],[has_brotli=0])
+AC_CHECK_LIB([brotlienc],[BrotliEncoderCreateInstance],[AC_SUBST([LIB_BROTLIENC],["-lbrotlienc"])],[has_brotli=0])
+AC_SUBST(has_brotli)
+AM_CONDITIONAL([HAS_BROTLI], [ test "x${has_brotli}" = "x1" ])
+
 #
 # Experimental plugins
 #
diff --git a/doc/admin-guide/plugins/gzip.en.rst b/doc/admin-guide/plugins/gzip.en.rst
index 5ba8363..cbf52be 100644
--- a/doc/admin-guide/plugins/gzip.en.rst
+++ b/doc/admin-guide/plugins/gzip.en.rst
@@ -141,6 +141,14 @@ will leave the header intact if the client provided it.
 - For when the proxy parses responses, and the resulting compression and
   decompression is wasteful.
 
+supported-algorithms
+----------------------
+
+Provides the compression algorithms that are supported. This will allow the proxy to selectively
+support certain compressions. The default is gzip. Multiple algorthims can be selected using ',' delimiter
+
+-- To selectively support only certain compression algorithms.
+
 Examples
 ========
 
@@ -162,6 +170,22 @@ might create a configuration with the following options::
     disallow /notthis/*.js
     flush true
 
+    # Allows brotli encoded response from origin but is not capable of brotli compression
+    [brotli.allowed.com]
+    enabled true
+    compressible-content-type text/*
+    compressible-content-type application/json
+    flush true
+    supported-algorithms gzip,deflate
+
+    # Supports brotli compression
+    [brotli.compress.com]
+    enabled true
+    compressible-content-type text/*
+    compressible-content-type application/json
+    flush true
+    supported-algorithms br, gzip
+
     # This origin does it all
     [bar.example.com]
     enabled false
diff --git a/plugins/gzip/Makefile.inc b/plugins/gzip/Makefile.inc
index 3cd845c..8762e21 100644
--- a/plugins/gzip/Makefile.inc
+++ b/plugins/gzip/Makefile.inc
@@ -16,3 +16,7 @@
 
 pkglib_LTLIBRARIES += gzip/gzip.la
 gzip_gzip_la_SOURCES = gzip/gzip.cc gzip/configuration.cc gzip/misc.cc
+
+gzip_gzip_la_LDFLAGS = \
+  $(AM_LDFLAGS) $(LIB_BROTLIENC)
+
diff --git a/plugins/gzip/README b/plugins/gzip/README
index 4872369..b687cad 100644
--- a/plugins/gzip/README
+++ b/plugins/gzip/README
@@ -9,7 +9,7 @@ make && sudo make install
 
 if no makefile is present, you can compile it using
     tsxs -o gzip.so *.cc
-and then install it using 
+and then install it using
     tsxs -i -o gzip.so
 
 after installation, add a line to plugin.config:
@@ -43,7 +43,12 @@ a sample configuration (sample.gzip.config):
 #
 # compressible-content-type: wildcard pattern for matching compressible content types
 #
-# disallow: wildcard pattern for disablign compression on urls
+# disallow: wildcard pattern for disabling compression on urls
+#
+# allow: wildcard pattern for enabling compression on urls
+#
+# supported-algorithms: compression algorithms supported. comma separated algorithms. Default is gzip
+#
 ######################################################################
 
 #first, we configure the default/global plugin behaviour
@@ -60,7 +65,14 @@ disallow /notthis/*.js
 disallow /notthat*
 disallow */bla*
 
-#override the global configuration for a host. 
+allow */here/*
+#disabling is possible too. trying to deprecate disallow
+allow !*/nothere/*
+
+#supported algorithms
+supported-algorithms br,gzip
+
+#override the global configuration for a host.
 #www.foo.nl does NOT inherit anything
 [www.foo.nl]
 enabled true
@@ -70,3 +82,6 @@ compressible-content-type text/*
 cache false
 disallow /notthis/*.js
 disallow /notthat*
+
+allow /this/*.js
+allow !/notthat/*.css
diff --git a/plugins/gzip/configuration.cc b/plugins/gzip/configuration.cc
index 80d8cf4..e0101a0 100644
--- a/plugins/gzip/configuration.cc
+++ b/plugins/gzip/configuration.cc
@@ -25,6 +25,7 @@
 #include <fstream>
 #include <algorithm>
 #include <vector>
+#include <sstream>
 #include <fnmatch.h>
 
 namespace Gzip
@@ -93,7 +94,8 @@ enum ParserState {
   kParseEnable,
   kParseCache,
   kParseDisallow,
-  kParseFlush
+  kParseFlush,
+  kParseAlgorithms
 };
 
 void
@@ -181,6 +183,34 @@ HostConfiguration::is_content_type_compressible(const char *content_type, int co
   return is_match;
 }
 
+void
+HostConfiguration::add_compression_algorithms(const string &algorithms)
+{
+  istringstream compress_algo(algorithms);
+  string token;
+  compression_algorithms_ = ALGORITHM_DEFAULT; // remove the default gzip.
+  while (getline(compress_algo, token, ',')) {
+    if (token.find("br") != string::npos) {
+#ifdef HAVE_BROTLI_ENCODE_H
+      compression_algorithms_ |= ALGORITHM_BROTLI;
+#else
+      error("supported-algorithms: brotli support not compiled in.");
+#endif
+    } else if (token.find("gzip") != string::npos)
+      compression_algorithms_ |= ALGORITHM_GZIP;
+    else if (token.find("deflate") != string::npos)
+      compression_algorithms_ |= ALGORITHM_DEFLATE;
+    else
+      error("Unknown compression type. Supported compression-algorithms <br,gzip,deflate>.");
+  }
+}
+
+int
+HostConfiguration::compression_algorithms()
+{
+  return compression_algorithms_;
+}
+
 Configuration *
 Configuration::Parse(const char *path)
 {
@@ -263,6 +293,8 @@ Configuration::Parse(const char *path)
           state = kParseDisallow;
         } else if (token == "flush") {
           state = kParseFlush;
+        } else if (token == "supported-algorithms") {
+          state = kParseAlgorithms;
         } else {
           warning("failed to interpret \"%s\" at line %zu", token.c_str(), lineno);
         }
@@ -291,6 +323,10 @@ Configuration::Parse(const char *path)
         current_host_configuration->set_flush(token == "true");
         state = kParseStart;
         break;
+      case kParseAlgorithms:
+        current_host_configuration->add_compression_algorithms(token);
+        state = kParseStart;
+        break;
       }
     }
   }
diff --git a/plugins/gzip/configuration.h b/plugins/gzip/configuration.h
index 04ff023..09c9559 100644
--- a/plugins/gzip/configuration.h
+++ b/plugins/gzip/configuration.h
@@ -33,11 +33,24 @@ namespace Gzip
 {
 typedef std::vector<std::string> StringContainer;
 
+enum CompressionAlgorithm {
+  ALGORITHM_DEFAULT = 0,
+  ALGORITHM_DEFLATE = 1,
+  ALGORITHM_GZIP    = 2,
+  ALGORITHM_BROTLI  = 4 // For bit manipulations
+};
+
 class HostConfiguration
 {
 public:
   explicit HostConfiguration(const std::string &host)
-    : host_(host), enabled_(true), cache_(true), remove_accept_encoding_(false), flush_(false), ref_count_(0)
+    : host_(host),
+      enabled_(true),
+      cache_(true),
+      remove_accept_encoding_(false),
+      flush_(false),
+      compression_algorithms_(ALGORITHM_GZIP),
+      ref_count_(0)
   {
   }
 
@@ -96,6 +109,8 @@ public:
   void add_compressible_content_type(const std::string &content_type);
   bool is_url_allowed(const char *url, int url_len);
   bool is_content_type_compressible(const char *content_type, int content_type_length);
+  void add_compression_algorithms(const std::string &algorithms);
+  int compression_algorithms();
 
   // Ref-counting these host configuration objects
   void
@@ -118,6 +133,7 @@ private:
   bool cache_;
   bool remove_accept_encoding_;
   bool flush_;
+  int compression_algorithms_;
   volatile int ref_count_;
 
   StringContainer compressible_content_types_;
diff --git a/plugins/gzip/gzip.cc b/plugins/gzip/gzip.cc
index 51110b1..ad6bbe0 100644
--- a/plugins/gzip/gzip.cc
+++ b/plugins/gzip/gzip.cc
@@ -24,6 +24,10 @@
 #include <string.h>
 #include <zlib.h>
 
+#if HAVE_BROTLI_ENCODE_H
+#include <brotli/encode.h>
+#endif
+
 #include "ts/ts.h"
 #include "ts/ink_defs.h"
 
@@ -36,7 +40,6 @@ using namespace std;
 using namespace Gzip;
 
 // FIXME: custom dictionaries would be nice. configurable/content-type?
-// FIXME: look into autoscaling the compression level based on connection speed
 // a gprs device might benefit from a higher compression ratio, whereas a desktop w. high bandwith
 // might be served better with little or no compression at all
 // FIXME: look into compressing from the task thread pool
@@ -50,37 +53,48 @@ using namespace Gzip;
 
 const int ZLIB_COMPRESSION_LEVEL = 6;
 const char *global_hidden_header_name;
-const char *dictionary = nullptr;
+const char *dictionary           = nullptr;
+const char *TS_HTTP_VALUE_BROTLI = "br";
+const int TS_HTTP_LEN_BROTLI     = 2;
+
+// brotli compression quality 1-11. Testing proved level '6'
+#if HAVE_BROTLI_ENCODE_H
+const int BROTLI_COMPRESSION_LEVEL = 6;
+const int BROTLI_LGW               = 16;
+#endif
 
 // Current global configuration, and the previous one (for cleanup)
 Configuration *cur_config  = nullptr;
 Configuration *prev_config = nullptr;
 
-static GzipData *
-gzip_data_alloc(int compression_type)
+static Data *
+data_alloc(int compression_type, int compression_algorithms)
 {
-  GzipData *data;
+  Data *data;
   int err;
 
-  data                    = (GzipData *)TSmalloc(sizeof(GzipData));
-  data->downstream_vio    = nullptr;
-  data->downstream_buffer = nullptr;
-  data->downstream_reader = nullptr;
-  data->downstream_length = 0;
-  data->state             = transform_state_initialized;
-  data->compression_type  = compression_type;
-  data->zstrm.next_in     = Z_NULL;
-  data->zstrm.avail_in    = 0;
-  data->zstrm.total_in    = 0;
-  data->zstrm.next_out    = Z_NULL;
-  data->zstrm.avail_out   = 0;
-  data->zstrm.total_out   = 0;
-  data->zstrm.zalloc      = gzip_alloc;
-  data->zstrm.zfree       = gzip_free;
-  data->zstrm.opaque      = (voidpf) nullptr;
-  data->zstrm.data_type   = Z_ASCII;
-
-  int window_bits = (compression_type == COMPRESSION_TYPE_GZIP) ? WINDOW_BITS_GZIP : WINDOW_BITS_DEFLATE;
+  data                         = (Data *)TSmalloc(sizeof(Data));
+  data->downstream_vio         = nullptr;
+  data->downstream_buffer      = nullptr;
+  data->downstream_reader      = nullptr;
+  data->downstream_length      = 0;
+  data->state                  = transform_state_initialized;
+  data->compression_type       = compression_type;
+  data->compression_algorithms = compression_algorithms;
+  data->zstrm.next_in          = Z_NULL;
+  data->zstrm.avail_in         = 0;
+  data->zstrm.total_in         = 0;
+  data->zstrm.next_out         = Z_NULL;
+  data->zstrm.avail_out        = 0;
+  data->zstrm.total_out        = 0;
+  data->zstrm.zalloc           = gzip_alloc;
+  data->zstrm.zfree            = gzip_free;
+  data->zstrm.opaque           = (voidpf) nullptr;
+  data->zstrm.data_type        = Z_ASCII;
+
+  int window_bits = WINDOW_BITS_GZIP;
+  if (compression_type & COMPRESSION_TYPE_DEFLATE)
+    window_bits = WINDOW_BITS_DEFLATE;
 
   err = deflateInit2(&data->zstrm, ZLIB_COMPRESSION_LEVEL, Z_DEFLATED, window_bits, ZLIB_MEMLEVEL, Z_DEFAULT_STRATEGY);
 
@@ -94,12 +108,28 @@ gzip_data_alloc(int compression_type)
       fatal("gzip-transform: ERROR: deflateSetDictionary (%d)!", err);
     }
   }
-
+#if HAVE_BROTLI_ENCODE_H
+  if (compression_type & COMPRESSION_TYPE_BROTLI) {
+    debug("gzip-transform: brotli compression. Create Brotli Encoder Instance.");
+    data->bstrm.br = BrotliEncoderCreateInstance(0, 0, 0);
+    if (!data->bstrm.br) {
+      fatal("gzip-transform: ERROR: Brotli Encoder Instance Failed");
+    }
+    BrotliEncoderSetParameter(data->bstrm.br, BROTLI_PARAM_QUALITY, BROTLI_COMPRESSION_LEVEL);
+    BrotliEncoderSetParameter(data->bstrm.br, BROTLI_PARAM_LGWIN, BROTLI_LGW);
+    data->bstrm.next_in   = nullptr;
+    data->bstrm.avail_in  = 0;
+    data->bstrm.total_in  = 0;
+    data->bstrm.next_out  = nullptr;
+    data->bstrm.avail_out = 0;
+    data->bstrm.total_out = 0;
+  }
+#endif
   return data;
 }
 
 static void
-gzip_data_destroy(GzipData *data)
+data_destroy(Data *data)
 {
   TSReleaseAssert(data);
 
@@ -111,24 +141,41 @@ gzip_data_destroy(GzipData *data)
     TSIOBufferDestroy(data->downstream_buffer);
   }
 
+// brotlidestory
+#if HAVE_BROTLI_ENCODE_H
+  BrotliEncoderDestroyInstance(data->bstrm.br);
+#endif
+
   TSfree(data);
 }
 
 static TSReturnCode
-gzip_content_encoding_header(TSMBuffer bufp, TSMLoc hdr_loc, const int compression_type)
+content_encoding_header(TSMBuffer bufp, TSMLoc hdr_loc, const int compression_type, int algorithm)
 {
   TSReturnCode ret;
   TSMLoc ce_loc;
-
+  const char *value = nullptr;
+  int value_len     = 0;
   // Delete Content-Encoding if present???
+  if (compression_type & COMPRESSION_TYPE_BROTLI && (algorithm & ALGORITHM_BROTLI)) {
+    value     = TS_HTTP_VALUE_BROTLI;
+    value_len = TS_HTTP_LEN_BROTLI;
+  } else if (compression_type & COMPRESSION_TYPE_GZIP && (algorithm & ALGORITHM_GZIP)) {
+    value     = TS_HTTP_VALUE_GZIP;
+    value_len = TS_HTTP_LEN_GZIP;
+  } else if (compression_type & COMPRESSION_TYPE_DEFLATE && (algorithm & ALGORITHM_DEFLATE)) {
+    value     = TS_HTTP_VALUE_DEFLATE;
+    value_len = TS_HTTP_LEN_DEFLATE;
+  }
+
+  if (value_len == 0) {
+    error("no need to add Content-Encoding header");
+    return TS_SUCCESS;
+  }
 
   if ((ret = TSMimeHdrFieldCreateNamed(bufp, hdr_loc, TS_MIME_FIELD_CONTENT_ENCODING, TS_MIME_LEN_CONTENT_ENCODING, &ce_loc)) ==
       TS_SUCCESS) {
-    if (compression_type == COMPRESSION_TYPE_DEFLATE) {
-      ret = TSMimeHdrFieldValueStringInsert(bufp, hdr_loc, ce_loc, -1, TS_HTTP_VALUE_DEFLATE, TS_HTTP_LEN_DEFLATE);
-    } else if (compression_type == COMPRESSION_TYPE_GZIP) {
-      ret = TSMimeHdrFieldValueStringInsert(bufp, hdr_loc, ce_loc, -1, TS_HTTP_VALUE_GZIP, TS_HTTP_LEN_GZIP);
-    }
+    ret = TSMimeHdrFieldValueStringInsert(bufp, hdr_loc, ce_loc, -1, value, value_len);
     if (ret == TS_SUCCESS) {
       ret = TSMimeHdrFieldAppend(bufp, hdr_loc, ce_loc);
     }
@@ -143,7 +190,7 @@ gzip_content_encoding_header(TSMBuffer bufp, TSMLoc hdr_loc, const int compressi
 }
 
 static TSReturnCode
-gzip_vary_header(TSMBuffer bufp, TSMLoc hdr_loc)
+vary_header(TSMBuffer bufp, TSMLoc hdr_loc)
 {
   TSReturnCode ret;
   TSMLoc ce_loc;
@@ -186,7 +233,7 @@ gzip_vary_header(TSMBuffer bufp, TSMLoc hdr_loc)
 // FIXME: the etag alteration isn't proper. it should modify the value inside quotes
 //       specify a very header..
 static TSReturnCode
-gzip_etag_header(TSMBuffer bufp, TSMLoc hdr_loc)
+etag_header(TSMBuffer bufp, TSMLoc hdr_loc)
 {
   TSReturnCode ret = TS_SUCCESS;
   TSMLoc ce_loc;
@@ -220,7 +267,7 @@ gzip_etag_header(TSMBuffer bufp, TSMLoc hdr_loc)
 
 // FIXME: some things are potentially compressible. those responses
 static void
-gzip_transform_init(TSCont contp, GzipData *data)
+compress_transform_init(TSCont contp, Data *data)
 {
   // update the vary, content-encoding, and etag response headers
   // prepare the downstream for transforming
@@ -236,8 +283,8 @@ gzip_transform_init(TSCont contp, GzipData *data)
     return;
   }
 
-  if (gzip_content_encoding_header(bufp, hdr_loc, data->compression_type) == TS_SUCCESS &&
-      gzip_vary_header(bufp, hdr_loc) == TS_SUCCESS && gzip_etag_header(bufp, hdr_loc) == TS_SUCCESS) {
+  if (content_encoding_header(bufp, hdr_loc, data->compression_type, data->compression_algorithms) == TS_SUCCESS &&
+      vary_header(bufp, hdr_loc) == TS_SUCCESS && etag_header(bufp, hdr_loc) == TS_SUCCESS) {
     downstream_conn         = TSTransformOutputVConnGet(contp);
     data->downstream_buffer = TSIOBufferCreate();
     data->downstream_reader = TSIOBufferReaderAlloc(data->downstream_buffer);
@@ -248,14 +295,102 @@ gzip_transform_init(TSCont contp, GzipData *data)
 }
 
 static void
-gzip_transform_one(GzipData *data, TSIOBufferReader upstream_reader, int amount)
+gzip_transform_one(Data *data, const char *upstream_buffer, int64_t upstream_length)
 {
   TSIOBufferBlock downstream_blkp;
-  const char *upstream_buffer;
   char *downstream_buffer;
-  int64_t upstream_length, downstream_length;
+  int64_t downstream_length;
+  int err;
+  data->zstrm.next_in  = (unsigned char *)upstream_buffer;
+  data->zstrm.avail_in = upstream_length;
+
+  while (data->zstrm.avail_in > 0) {
+    downstream_blkp   = TSIOBufferStart(data->downstream_buffer);
+    downstream_buffer = TSIOBufferBlockWriteStart(downstream_blkp, &downstream_length);
+
+    data->zstrm.next_out  = (unsigned char *)downstream_buffer;
+    data->zstrm.avail_out = downstream_length;
+
+    if (!data->hc->flush()) {
+      err = deflate(&data->zstrm, Z_NO_FLUSH);
+    } else {
+      err = deflate(&data->zstrm, Z_SYNC_FLUSH);
+    }
+
+    if (err != Z_OK) {
+      warning("deflate() call failed: %d", err);
+    }
+
+    if (downstream_length > data->zstrm.avail_out) {
+      TSIOBufferProduce(data->downstream_buffer, downstream_length - data->zstrm.avail_out);
+      data->downstream_length += (downstream_length - data->zstrm.avail_out);
+    }
+
+    if (data->zstrm.avail_out > 0) {
+      if (data->zstrm.avail_in != 0) {
+        error("gzip-transform: ERROR: avail_in is (%d): should be 0", data->zstrm.avail_in);
+      }
+    }
+  }
+}
+
+static void
+brotli_transform_one(Data *data, const char *upstream_buffer, int64_t upstream_length)
+{
+#if HAVE_BROTLI_ENCODE_H
+  TSIOBufferBlock downstream_blkp;
+  char *downstream_buffer;
+  int64_t downstream_length;
   int err;
 
+  data->bstrm.avail_in = upstream_length;
+
+  while (data->bstrm.avail_in > 0) {
+    downstream_blkp   = TSIOBufferStart(data->downstream_buffer);
+    downstream_buffer = TSIOBufferBlockWriteStart(downstream_blkp, &downstream_length);
+
+    data->bstrm.next_out  = (unsigned char *)downstream_buffer;
+    data->bstrm.avail_out = downstream_length;
+    data->bstrm.total_out = 0;
+
+    data->bstrm.next_in = (uint8_t *)upstream_buffer;
+    if (!data->hc->flush()) {
+      err = BrotliEncoderCompressStream(data->bstrm.br, BROTLI_OPERATION_PROCESS, &data->bstrm.avail_in,
+                                        (const uint8_t **)&data->bstrm.next_in, &data->bstrm.avail_out, &data->bstrm.next_out,
+                                        &data->bstrm.total_out);
+    } else {
+      err = BrotliEncoderCompressStream(data->bstrm.br, BROTLI_OPERATION_FLUSH, &data->bstrm.avail_in,
+                                        (const uint8_t **)&data->bstrm.next_in, &data->bstrm.avail_out, &data->bstrm.next_out,
+                                        &data->bstrm.total_out);
+    }
+
+    if (err != BROTLI_TRUE) {
+      warning("BrotliEncoderCompressStream() call failed: %d", err);
+    }
+
+    if (downstream_length > (int64_t)data->bstrm.avail_out) {
+      TSIOBufferProduce(data->downstream_buffer, downstream_length - data->bstrm.avail_out);
+      data->downstream_length += (downstream_length - data->bstrm.avail_out);
+    }
+
+    if (data->bstrm.avail_out > 0) {
+      if (data->bstrm.avail_in != 0) {
+        error("brotli-transform: ERROR: brotli avail_in is (%lu): should be 0", data->bstrm.avail_in);
+      }
+    }
+  }
+  data->bstrm.total_in += upstream_length;
+#else
+  error("brotli-transform: ERROR: compile with brotli support");
+#endif
+}
+
+static void
+compress_transform_one(Data *data, TSIOBufferReader upstream_reader, int amount)
+{
+  TSIOBufferBlock downstream_blkp;
+  const char *upstream_buffer;
+  int64_t upstream_length;
   while (amount > 0) {
     downstream_blkp = TSIOBufferReaderStart(upstream_reader);
     if (!downstream_blkp) {
@@ -273,38 +408,13 @@ gzip_transform_one(GzipData *data, TSIOBufferReader upstream_reader, int amount)
       upstream_length = amount;
     }
 
-    data->zstrm.next_in  = (unsigned char *)upstream_buffer;
-    data->zstrm.avail_in = upstream_length;
-
-    while (data->zstrm.avail_in > 0) {
-      downstream_blkp   = TSIOBufferStart(data->downstream_buffer);
-      downstream_buffer = TSIOBufferBlockWriteStart(downstream_blkp, &downstream_length);
-
-      data->zstrm.next_out  = (unsigned char *)downstream_buffer;
-      data->zstrm.avail_out = downstream_length;
-
-      if (!data->hc->flush()) {
-        debug("gzip_transform: deflate with Z_NO_FLUSH");
-        err = deflate(&data->zstrm, Z_NO_FLUSH);
-      } else {
-        debug("gzip_transform: deflate with Z_SYNC_FLUSH");
-        err = deflate(&data->zstrm, Z_SYNC_FLUSH);
-      }
-
-      if (err != Z_OK) {
-        warning("deflate() call failed: %d", err);
-      }
-
-      if (downstream_length > data->zstrm.avail_out) {
-        TSIOBufferProduce(data->downstream_buffer, downstream_length - data->zstrm.avail_out);
-        data->downstream_length += (downstream_length - data->zstrm.avail_out);
-      }
-
-      if (data->zstrm.avail_out > 0) {
-        if (data->zstrm.avail_in != 0) {
-          error("gzip-transform: ERROR: avail_in is (%d): should be 0", data->zstrm.avail_in);
-        }
-      }
+    if (data->compression_type & COMPRESSION_TYPE_BROTLI && (data->compression_algorithms & ALGORITHM_BROTLI)) {
+      brotli_transform_one(data, upstream_buffer, upstream_length);
+    } else if ((data->compression_type & (COMPRESSION_TYPE_GZIP | COMPRESSION_TYPE_DEFLATE)) &&
+               (data->compression_algorithms & (ALGORITHM_GZIP | ALGORITHM_DEFLATE))) {
+      gzip_transform_one(data, upstream_buffer, upstream_length);
+    } else {
+      warning("No compression supported. Shoudn't come here.");
     }
 
     TSIOBufferReaderConsume(upstream_reader, upstream_length);
@@ -313,7 +423,7 @@ gzip_transform_one(GzipData *data, TSIOBufferReader upstream_reader, int amount)
 }
 
 static void
-gzip_transform_finish(GzipData *data)
+gzip_transform_finish(Data *data)
 {
   if (data->state == transform_state_output) {
     TSIOBufferBlock downstream_blkp;
@@ -350,30 +460,94 @@ gzip_transform_finish(GzipData *data)
     if (data->downstream_length != (int64_t)(data->zstrm.total_out)) {
       error("gzip-transform: ERROR: output lengths don't match (%d, %ld)", data->downstream_length, data->zstrm.total_out);
     }
-
+    debug("gzip-transform: Finished gzip");
     gzip_log_ratio(data->zstrm.total_in, data->downstream_length);
   }
 }
 
 static void
-gzip_transform_do(TSCont contp)
+brotli_transform_finish(Data *data)
+{
+#if HAVE_BROTLI_ENCODE_H
+  if (data->state == transform_state_output) {
+    TSIOBufferBlock downstream_blkp;
+    char *downstream_buffer;
+    int64_t downstream_length;
+    int err;
+
+    data->state = transform_state_finished;
+
+    for (;;) {
+      downstream_blkp = TSIOBufferStart(data->downstream_buffer);
+
+      downstream_buffer     = TSIOBufferBlockWriteStart(downstream_blkp, &downstream_length);
+      data->bstrm.next_out  = (unsigned char *)downstream_buffer;
+      data->bstrm.avail_out = downstream_length;
+
+      err = BrotliEncoderCompressStream(data->bstrm.br, BROTLI_OPERATION_FINISH, &data->bstrm.avail_in,
+                                        (const uint8_t **)&data->bstrm.next_in, &data->bstrm.avail_out, &data->bstrm.next_out,
+                                        &data->bstrm.total_out);
+
+      if (downstream_length > (int64_t)data->bstrm.avail_out) {
+        TSIOBufferProduce(data->downstream_buffer, downstream_length - data->bstrm.avail_out);
+        data->downstream_length += (downstream_length - data->bstrm.avail_out);
+      }
+      if (!BrotliEncoderIsFinished(data->bstrm.br)) {
+        continue;
+      }
+
+      if (err != BROTLI_TRUE) { /* some more data to encode */
+        warning("brotli_transform: BrotliEncoderCompressStream should return BROTLI_TRUE");
+      }
+
+      break;
+    }
+
+    if (data->downstream_length != (int64_t)(data->bstrm.total_out)) {
+      error("brotli-transform: ERROR: output lengths don't match (%d, %ld)", data->downstream_length, data->bstrm.total_out);
+    }
+    debug("brotli-transform: Finished brotli");
+    gzip_log_ratio(data->bstrm.total_in, data->downstream_length);
+  }
+#else
+  error("brotli-transform: compile with brotli support");
+#endif
+}
+
+static void
+compress_transform_finish(Data *data)
+{
+  if (data->compression_type & COMPRESSION_TYPE_BROTLI && data->compression_algorithms & ALGORITHM_BROTLI) {
+    brotli_transform_finish(data);
+    debug("brotli-transform: Brolti compression finish.");
+  } else if ((data->compression_type & (COMPRESSION_TYPE_GZIP | COMPRESSION_TYPE_DEFLATE)) &&
+             (data->compression_algorithms & (ALGORITHM_GZIP | ALGORITHM_DEFLATE))) {
+    gzip_transform_finish(data);
+    debug("gzip-transform: Gzip compression finish.");
+  } else {
+    warning("No Compression matched, shouldn't come here.");
+  }
+}
+
+static void
+compress_transform_do(TSCont contp)
 {
   TSVIO upstream_vio;
-  GzipData *data;
+  Data *data;
   int64_t upstream_todo;
   int64_t upstream_avail;
   int64_t downstream_bytes_written;
 
-  data = (GzipData *)TSContDataGet(contp);
+  data = (Data *)TSContDataGet(contp);
   if (data->state == transform_state_initialized) {
-    gzip_transform_init(contp, data);
+    compress_transform_init(contp, data);
   }
 
   upstream_vio             = TSVConnWriteVIOGet(contp);
   downstream_bytes_written = data->downstream_length;
 
   if (!TSVIOBufferGet(upstream_vio)) {
-    gzip_transform_finish(data);
+    compress_transform_finish(data);
 
     TSVIONBytesSet(data->downstream_vio, data->downstream_length);
 
@@ -393,7 +567,7 @@ gzip_transform_do(TSCont contp)
     }
 
     if (upstream_todo > 0) {
-      gzip_transform_one(data, TSVIOReaderGet(upstream_vio), upstream_todo);
+      compress_transform_one(data, TSVIOReaderGet(upstream_vio), upstream_todo);
       TSVIONDoneSet(upstream_vio, TSVIONDoneGet(upstream_vio) + upstream_todo);
     }
   }
@@ -406,7 +580,7 @@ gzip_transform_do(TSCont contp)
       TSContCall(TSVIOContGet(upstream_vio), TS_EVENT_VCONN_WRITE_READY, upstream_vio);
     }
   } else {
-    gzip_transform_finish(data);
+    compress_transform_finish(data);
     TSVIONBytesSet(data->downstream_vio, data->downstream_length);
 
     if (data->downstream_length > downstream_bytes_written) {
@@ -418,10 +592,10 @@ gzip_transform_do(TSCont contp)
 }
 
 static int
-gzip_transform(TSCont contp, TSEvent event, void * /* edata ATS_UNUSED */)
+compress_transform(TSCont contp, TSEvent event, void * /* edata ATS_UNUSED */)
 {
   if (TSVConnClosedGet(contp)) {
-    gzip_data_destroy((GzipData *)TSContDataGet(contp));
+    data_destroy((Data *)TSContDataGet(contp));
     TSContDestroy(contp);
     return 0;
   } else {
@@ -435,14 +609,14 @@ gzip_transform(TSCont contp, TSEvent event, void * /* edata ATS_UNUSED */)
       TSVConnShutdown(TSTransformOutputVConnGet(contp), 0, 1);
       break;
     case TS_EVENT_VCONN_WRITE_READY:
-      gzip_transform_do(contp);
+      compress_transform_do(contp);
       break;
     case TS_EVENT_IMMEDIATE:
-      gzip_transform_do(contp);
+      compress_transform_do(contp);
       break;
     default:
       warning("unknown event [%d]", event);
-      gzip_transform_do(contp);
+      compress_transform_do(contp);
       break;
     }
   }
@@ -451,7 +625,7 @@ gzip_transform(TSCont contp, TSEvent event, void * /* edata ATS_UNUSED */)
 }
 
 static int
-gzip_transformable(TSHttpTxn txnp, bool server, HostConfiguration *host_configuration, int *compress_type)
+transformable(TSHttpTxn txnp, bool server, HostConfiguration *host_configuration, int *compress_type, int *algorithms)
 {
   /* Server response header */
   TSMBuffer bufp;
@@ -468,6 +642,13 @@ gzip_transformable(TSHttpTxn txnp, bool server, HostConfiguration *host_configur
   int i, compression_acceptable, len;
   TSHttpStatus resp_status;
 
+  /*
+    // Before anything, check atleast one compression algorithm is supported
+    if (host_configuration->compression_algorithms() == ALGORITHM_DEFAULT) {
+      info("No compression algorithms configured");
+      return 0;
+    }
+  */
   if (server) {
     if (TS_SUCCESS != TSHttpTxnServerRespGet(txnp, &bufp, &hdr_loc)) {
       return 0;
@@ -503,7 +684,8 @@ gzip_transformable(TSHttpTxn txnp, bool server, HostConfiguration *host_configur
     return 0;
   }
 
-  cfield = TSMimeHdrFieldFind(cbuf, chdr, TS_MIME_FIELD_ACCEPT_ENCODING, TS_MIME_LEN_ACCEPT_ENCODING);
+  *algorithms = host_configuration->compression_algorithms();
+  cfield      = TSMimeHdrFieldFind(cbuf, chdr, TS_MIME_FIELD_ACCEPT_ENCODING, TS_MIME_LEN_ACCEPT_ENCODING);
   if (cfield != TS_NULL_MLOC) {
     compression_acceptable = 0;
     nvalues                = TSMimeHdrFieldValuesCount(cbuf, chdr, cfield);
@@ -513,14 +695,18 @@ gzip_transformable(TSHttpTxn txnp, bool server, HostConfiguration *host_configur
         continue;
       }
 
-      if (strncasecmp(value, "deflate", sizeof("deflate") - 1) == 0) {
-        compression_acceptable = 1;
-        *compress_type         = COMPRESSION_TYPE_DEFLATE;
-        break;
+      if (strncasecmp(value, "br", sizeof("br") - 1) == 0) {
+        if (*algorithms & ALGORITHM_BROTLI)
+          compression_acceptable = 1;
+        *compress_type |= COMPRESSION_TYPE_BROTLI;
+      } else if (strncasecmp(value, "deflate", sizeof("deflate") - 1) == 0) {
+        if (*algorithms & ALGORITHM_DEFLATE)
+          compression_acceptable = 1;
+        *compress_type |= COMPRESSION_TYPE_DEFLATE;
       } else if (strncasecmp(value, "gzip", sizeof("gzip") - 1) == 0) {
-        compression_acceptable = 1;
-        *compress_type         = COMPRESSION_TYPE_GZIP;
-        break;
+        if (*algorithms & ALGORITHM_GZIP)
+          compression_acceptable = 1;
+        *compress_type |= COMPRESSION_TYPE_GZIP;
       }
     }
 
@@ -528,7 +714,7 @@ gzip_transformable(TSHttpTxn txnp, bool server, HostConfiguration *host_configur
     TSHandleMLocRelease(cbuf, TS_NULL_MLOC, chdr);
 
     if (!compression_acceptable) {
-      info("no acceptable encoding found in request header, not compressible");
+      info("no acceptable encoding match found in request header, not compressible");
       TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
       return 0;
     }
@@ -574,21 +760,24 @@ gzip_transformable(TSHttpTxn txnp, bool server, HostConfiguration *host_configur
 }
 
 static void
-gzip_transform_add(TSHttpTxn txnp, HostConfiguration *hc, int compress_type)
+compress_transform_add(TSHttpTxn txnp, HostConfiguration *hc, int compress_type, int algorithms)
 {
   TSVConn connp;
-  GzipData *data;
+  Data *data;
 
   TSHttpTxnUntransformedRespCache(txnp, 1);
 
   if (!hc->cache()) {
+    debug("TransformedRespCache  not enabled");
     TSHttpTxnTransformedRespCache(txnp, 0);
   } else {
+    debug("TransformedRespCache  enabled");
+    TSHttpTxnUntransformedRespCache(txnp, 0);
     TSHttpTxnTransformedRespCache(txnp, 1);
   }
 
-  connp     = TSTransformCreate(gzip_transform, txnp);
-  data      = gzip_data_alloc(compress_type);
+  connp     = TSTransformCreate(compress_transform, txnp);
+  data      = data_alloc(compress_type, algorithms);
   data->txn = txnp;
   data->hc  = hc;
 
@@ -620,7 +809,8 @@ static int
 transform_plugin(TSCont contp, TSEvent event, void *edata)
 {
   TSHttpTxn txnp        = (TSHttpTxn)edata;
-  int compress_type     = COMPRESSION_TYPE_DEFLATE;
+  int compress_type     = COMPRESSION_TYPE_DEFAULT;
+  int algorithms        = ALGORITHM_DEFAULT;
   HostConfiguration *hc = (HostConfiguration *)TSContDataGet(contp);
 
   switch (event) {
@@ -639,8 +829,8 @@ transform_plugin(TSCont contp, TSEvent event, void *edata)
         }
       }
 
-      if (gzip_transformable(txnp, true, hc, &compress_type)) {
-        gzip_transform_add(txnp, hc, compress_type);
+      if (transformable(txnp, true, hc, &compress_type, &algorithms)) {
+        compress_transform_add(txnp, hc, compress_type, algorithms);
       }
     }
     break;
@@ -667,8 +857,8 @@ transform_plugin(TSCont contp, TSEvent event, void *edata)
     if (TS_ERROR != TSHttpTxnCacheLookupStatusGet(txnp, &obj_status) && (TS_CACHE_LOOKUP_HIT_FRESH == obj_status)) {
       if (hc != nullptr) {
         info("handling compression of cached object");
-        if (gzip_transformable(txnp, false, hc, &compress_type)) {
-          gzip_transform_add(txnp, hc, compress_type);
+        if (transformable(txnp, false, hc, &compress_type, &algorithms)) {
+          compress_transform_add(txnp, hc, compress_type, algorithms);
         }
       }
     } else {
@@ -703,7 +893,7 @@ transform_plugin(TSCont contp, TSEvent event, void *edata)
  *    further processing
  */
 static void
-handle_gzip_request(TSHttpTxn txnp, Configuration *config)
+handle_request(TSHttpTxn txnp, Configuration *config)
 {
   TSMBuffer req_buf;
   TSMLoc req_loc;
@@ -721,14 +911,12 @@ handle_gzip_request(TSHttpTxn txnp, Configuration *config)
       if (hc->has_disallows()) {
         int url_len;
         char *url = TSHttpTxnEffectiveUrlStringGet(txnp, &url_len);
-
-        allowed = hc->is_url_allowed(url, url_len);
+        allowed   = hc->is_url_allowed(url, url_len);
         TSfree(url);
       } else {
         allowed = true;
       }
     }
-
     if (allowed) {
       TSCont transform_contp = TSContCreate(transform_plugin, nullptr);
 
@@ -753,7 +941,7 @@ transform_global_plugin(TSCont /* contp ATS_UNUSED */, TSEvent event, void *edat
   switch (event) {
   case TS_EVENT_HTTP_READ_REQUEST_HDR:
     // Handle gzip request and use the global configs
-    handle_gzip_request(txnp, nullptr);
+    handle_request(txnp, nullptr);
     break;
 
   default:
@@ -887,7 +1075,7 @@ TSRemapDoRemap(void *instance, TSHttpTxn txnp, TSRemapRequestInfo *rri)
     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);
+    handle_request(txnp, config);
   }
   return TSREMAP_NO_REMAP;
 }
diff --git a/plugins/gzip/misc.cc b/plugins/gzip/misc.cc
index 161abda..c0d750e 100644
--- a/plugins/gzip/misc.cc
+++ b/plugins/gzip/misc.cc
@@ -47,7 +47,7 @@ normalize_accept_encoding(TSHttpTxn /* txnp ATS_UNUSED */, TSMBuffer reqp, TSMLo
   TSMLoc field = TSMimeHdrFieldFind(reqp, hdr_loc, TS_MIME_FIELD_ACCEPT_ENCODING, TS_MIME_LEN_ACCEPT_ENCODING);
   int deflate  = 0;
   int gzip     = 0;
-
+  int br       = 0;
   // remove the accept encoding field(s),
   // while finding out if gzip or deflate is supported.
   while (field) {
@@ -63,6 +63,9 @@ normalize_accept_encoding(TSHttpTxn /* txnp ATS_UNUSED */, TSMBuffer reqp, TSMLo
         --value_count;
         val = TSMimeHdrFieldValueStringGet(reqp, hdr_loc, field, value_count, &val_len);
 
+        if (val_len == (int)strlen("br")) {
+          br = !strncmp(val, "br", val_len);
+        }
         if (val_len == (int)strlen("gzip")) {
           gzip = !strncmp(val, "gzip", val_len);
         } else if (val_len == (int)strlen("deflate")) {
@@ -78,10 +81,13 @@ normalize_accept_encoding(TSHttpTxn /* txnp ATS_UNUSED */, TSMBuffer reqp, TSMLo
   }
 
   // append a new accept-encoding field in the header
-  if (deflate || gzip) {
+  if (deflate || gzip || br) {
     TSMimeHdrFieldCreate(reqp, hdr_loc, &field);
     TSMimeHdrFieldNameSet(reqp, hdr_loc, field, TS_MIME_FIELD_ACCEPT_ENCODING, TS_MIME_LEN_ACCEPT_ENCODING);
-
+    if (br) {
+      TSMimeHdrFieldValueStringInsert(reqp, hdr_loc, field, -1, "br", strlen("br"));
+      info("normalized accept encoding to br");
+    }
     if (gzip) {
       TSMimeHdrFieldValueStringInsert(reqp, hdr_loc, field, -1, "gzip", strlen("gzip"));
       info("normalized accept encoding to gzip");
diff --git a/plugins/gzip/misc.h b/plugins/gzip/misc.h
index 60f5aea..6c00cc0 100644
--- a/plugins/gzip/misc.h
+++ b/plugins/gzip/misc.h
@@ -29,6 +29,10 @@
 #include <stdlib.h>
 #include <stdio.h>
 
+#if HAVE_BROTLI_ENCODE_H
+#include <brotli/encode.h>
+#endif
+
 #include "configuration.h"
 
 using namespace Gzip;
@@ -39,8 +43,12 @@ static const int WINDOW_BITS_DEFLATE = -15;
 static const int WINDOW_BITS_GZIP    = 31;
 
 // misc
-static const int COMPRESSION_TYPE_DEFLATE = 1;
-static const int COMPRESSION_TYPE_GZIP    = 2;
+enum CompressionType {
+  COMPRESSION_TYPE_DEFAULT = 0,
+  COMPRESSION_TYPE_DEFLATE = 1,
+  COMPRESSION_TYPE_GZIP    = 2,
+  COMPRESSION_TYPE_BROTLI  = 4
+};
 
 // this one is used to rename the accept encoding header
 // it will be restored later on
@@ -53,6 +61,18 @@ enum transform_state {
   transform_state_finished,
 };
 
+#if HAVE_BROTLI_ENCODE_H
+typedef struct {
+  BrotliEncoderState *br;
+  uint8_t *next_in;
+  size_t avail_in;
+  uint8_t *next_out;
+  size_t avail_out;
+  size_t total_in;
+  size_t total_out;
+} b_stream;
+#endif
+
 typedef struct {
   TSHttpTxn txn;
   HostConfiguration *hc;
@@ -63,7 +83,11 @@ typedef struct {
   z_stream zstrm;
   enum transform_state state;
   int compression_type;
-} GzipData;
+  int compression_algorithms;
+#if HAVE_BROTLI_ENCODE_H
+  b_stream bstrm;
+#endif
+} Data;
 
 voidpf gzip_alloc(voidpf opaque, uInt items, uInt size);
 void gzip_free(voidpf opaque, voidpf address);

-- 
To stop receiving notification emails like this one, please contact
"commits@trafficserver.apache.org" <co...@trafficserver.apache.org>.

[trafficserver] 02/03: new config option for allow urls.

Posted by zw...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

zwoop pushed a commit to branch 7.1.x
in repository https://gitbox.apache.org/repos/asf/trafficserver.git

commit 823eb7a2211c333170be8bac9054aa99da3243cb
Author: myraid <sa...@gmail.com>
AuthorDate: Thu Apr 6 00:58:41 2017 +0000

    new config option for allow urls.
    
    (cherry picked from commit 0f5297c331551afb3d836ddf8e597dcad22634f3)
---
 doc/admin-guide/plugins/gzip.en.rst | 10 +++++++++
 plugins/gzip/configuration.cc       | 44 +++++++++++++++++++++++++++++++------
 plugins/gzip/configuration.h        |  8 +++++++
 plugins/gzip/gzip.cc                |  4 ++--
 4 files changed, 57 insertions(+), 9 deletions(-)

diff --git a/doc/admin-guide/plugins/gzip.en.rst b/doc/admin-guide/plugins/gzip.en.rst
index cbf52be..2283f26 100644
--- a/doc/admin-guide/plugins/gzip.en.rst
+++ b/doc/admin-guide/plugins/gzip.en.rst
@@ -117,6 +117,15 @@ of the objects will be cached and returned to clients. This may be useful for
 objects which already have their own compression built-in, to avoid the expense
 of multiple rounds of compression for trivial gains.
 
+allow
+--------
+
+Provides a wildcard pattern which will be applied to request URLs. Any which
+match the pattern will be considered compressible, and only deflated versions
+of the objects will be cached and returned to clients. This may be useful for
+objects which already have their own compression built-in, to avoid the expense
+of multiple rounds of compression for trivial gains.
+
 enabled
 -------
 
@@ -168,6 +177,7 @@ might create a configuration with the following options::
     cache false
     remove-accept-encoding true
     disallow /notthis/*.js
+    allow /this/*.js
     flush true
 
     # Allows brotli encoded response from origin but is not capable of brotli compression
diff --git a/plugins/gzip/configuration.cc b/plugins/gzip/configuration.cc
index e0101a0..4d4677f 100644
--- a/plugins/gzip/configuration.cc
+++ b/plugins/gzip/configuration.cc
@@ -95,7 +95,8 @@ enum ParserState {
   kParseCache,
   kParseDisallow,
   kParseFlush,
-  kParseAlgorithms
+  kParseAlgorithms,
+  kParseAllow
 };
 
 void
@@ -112,6 +113,12 @@ HostConfiguration::add_disallow(const std::string &disallow)
 }
 
 void
+HostConfiguration::add_allow(const std::string &allow)
+{
+  allows_.push_back(allow);
+}
+
+void
 HostConfiguration::add_compressible_content_type(const std::string &content_type)
 {
   compressible_content_types_.push_back(content_type);
@@ -150,14 +157,31 @@ bool
 HostConfiguration::is_url_allowed(const char *url, int url_len)
 {
   string surl(url, url_len);
-
-  for (StringContainer::iterator it = disallows_.begin(); it != disallows_.end(); ++it) {
-    if (fnmatch(it->c_str(), surl.c_str(), 0) == 0) {
-      info("url [%s] disabled for compression, matched on pattern [%s]", surl.c_str(), it->c_str());
-      return false;
+  if (has_disallows()) {
+    for (StringContainer::iterator it = disallows_.begin(); it != disallows_.end(); ++it) {
+      if (fnmatch(it->c_str(), surl.c_str(), 0) == 0) {
+        info("url [%s] disabled for compression, matched disallow pattern [%s]", surl.c_str(), it->c_str());
+        return false;
+      }
     }
   }
-
+  if (has_allows()) {
+    for (StringContainer::iterator allow_it = allows_.begin(); allow_it != allows_.end(); ++allow_it) {
+      const char *match_string = allow_it->c_str();
+      bool exclude             = match_string[0] == '!';
+      if (exclude) {
+        ++match_string; // skip !
+      }
+      if (fnmatch(match_string, surl.c_str(), 0) == 0) {
+        info("url [%s] %s for compression, matched allow pattern [%s]", surl.c_str(), exclude ? "disabled" : "enabled",
+             allow_it->c_str());
+        return !exclude;
+      }
+    }
+    info("url [%s] disabled for compression, did not match any allows pattern", surl.c_str());
+    return false;
+  }
+  info("url [%s] enabled for compression, did not match and disallow pattern ", surl.c_str());
   return true;
 }
 
@@ -295,6 +319,8 @@ Configuration::Parse(const char *path)
           state = kParseFlush;
         } else if (token == "supported-algorithms") {
           state = kParseAlgorithms;
+        } else if (token == "allow") {
+          state = kParseAllow;
         } else {
           warning("failed to interpret \"%s\" at line %zu", token.c_str(), lineno);
         }
@@ -327,6 +353,10 @@ Configuration::Parse(const char *path)
         current_host_configuration->add_compression_algorithms(token);
         state = kParseStart;
         break;
+      case kParseAllow:
+        current_host_configuration->add_allow(token);
+        state = kParseStart;
+        break;
       }
     }
   }
diff --git a/plugins/gzip/configuration.h b/plugins/gzip/configuration.h
index 09c9559..ba34cde 100644
--- a/plugins/gzip/configuration.h
+++ b/plugins/gzip/configuration.h
@@ -105,7 +105,14 @@ public:
     return !disallows_.empty();
   }
 
+  bool
+  has_allows() const
+  {
+    return !allows_.empty();
+  }
+
   void add_disallow(const std::string &disallow);
+  void add_allow(const std::string &allow);
   void add_compressible_content_type(const std::string &content_type);
   bool is_url_allowed(const char *url, int url_len);
   bool is_content_type_compressible(const char *content_type, int content_type_length);
@@ -138,6 +145,7 @@ private:
 
   StringContainer compressible_content_types_;
   StringContainer disallows_;
+  StringContainer allows_;
 
   DISALLOW_COPY_AND_ASSIGN(HostConfiguration);
 };
diff --git a/plugins/gzip/gzip.cc b/plugins/gzip/gzip.cc
index ad6bbe0..64ac2e2 100644
--- a/plugins/gzip/gzip.cc
+++ b/plugins/gzip/gzip.cc
@@ -519,7 +519,7 @@ compress_transform_finish(Data *data)
 {
   if (data->compression_type & COMPRESSION_TYPE_BROTLI && data->compression_algorithms & ALGORITHM_BROTLI) {
     brotli_transform_finish(data);
-    debug("brotli-transform: Brolti compression finish.");
+    debug("brotli-transform: Brotli compression finish.");
   } else if ((data->compression_type & (COMPRESSION_TYPE_GZIP | COMPRESSION_TYPE_DEFLATE)) &&
              (data->compression_algorithms & (ALGORITHM_GZIP | ALGORITHM_DEFLATE))) {
     gzip_transform_finish(data);
@@ -908,7 +908,7 @@ handle_request(TSHttpTxn txnp, Configuration *config)
     bool allowed = false;
 
     if (hc->enabled()) {
-      if (hc->has_disallows()) {
+      if (hc->has_disallows() || hc->has_allows()) {
         int url_len;
         char *url = TSHttpTxnEffectiveUrlStringGet(txnp, &url_len);
         allowed   = hc->is_url_allowed(url, url_len);

-- 
To stop receiving notification emails like this one, please contact
"commits@trafficserver.apache.org" <co...@trafficserver.apache.org>.