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

amc pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficserver.git


The following commit(s) were added to refs/heads/master by this push:
     new 762dd93  Change normalize_ae handling to normalize request from client 
not request to server (for benefit of gzip plugin).
762dd93 is described below

commit 762dd93a0f0b82368442f418045d0301eedf2adc
Author: Walt Karas <wka...@yahoo-inc.com>
AuthorDate: Wed Nov 22 20:15:11 2017 +0000

    Change normalize_ae handling to normalize request from client not request 
to server (for benefit of gzip plugin).
---
 proxy/http/HttpTransact.cc                         |  10 +-
 tests/gold_tests/pluginTest/gzip/greplog.sh        |  23 ++
 tests/gold_tests/pluginTest/gzip/gzip.config       |   7 +
 tests/gold_tests/pluginTest/gzip/gzip.gold         | 296 +++++++++++++++++++++
 tests/gold_tests/pluginTest/gzip/gzip.test.py      | 137 ++++++++++
 tests/gold_tests/pluginTest/gzip/gzip_observer.py  |  26 ++
 tests/gold_tests/pluginTest/gzip/gzip_userver.gold |  19 ++
 7 files changed, 514 insertions(+), 4 deletions(-)

diff --git a/proxy/http/HttpTransact.cc b/proxy/http/HttpTransact.cc
index dbc6c4a..88a0e3e 100644
--- a/proxy/http/HttpTransact.cc
+++ b/proxy/http/HttpTransact.cc
@@ -7523,6 +7523,11 @@ HttpTransact::build_request(State *s, HTTPHdr 
*base_request, HTTPHdr *outgoing_r
         base_request->url_get()->copy(o_url);
       }
     }
+
+    // Peform any configured normalization (including per-remap-rule 
configuration overrides) of the Accept-Encoding header
+    // field (if any).  This has to be done in the request from the client, 
for the benefit of the gzip plugin.
+    //
+    HttpTransactHeaders::normalize_accept_encoding(s->txn_conf, base_request);
   }
 
   HttpTransactHeaders::copy_header_fields(base_request, outgoing_request, 
s->txn_conf->fwd_proxy_auth_to_parent);
@@ -7623,12 +7628,9 @@ HttpTransact::build_request(State *s, HTTPHdr 
*base_request, HTTPHdr *outgoing_r
     TxnDebug("http_trans", "[build_request] request expect 100-continue 
headers removed");
   }
 
-  // Peform any configured normalization (including per-remap-rule 
configuration overrides) of the Accept-Encoding header
-  // field (if any).
-  HttpTransactHeaders::normalize_accept_encoding(s->txn_conf, 
outgoing_request);
-
   s->request_sent_time = ink_local_time();
   s->current.now       = s->request_sent_time;
+
   // The assert is backwards in this case because request is being (re)sent.
   ink_assert(s->request_sent_time >= s->response_received_time);
 
diff --git a/tests/gold_tests/pluginTest/gzip/greplog.sh 
b/tests/gold_tests/pluginTest/gzip/greplog.sh
new file mode 100755
index 0000000..f42f1af
--- /dev/null
+++ b/tests/gold_tests/pluginTest/gzip/greplog.sh
@@ -0,0 +1,23 @@
+#  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.
+
+grep --text \
+ -e 'HTTP/' \
+ -e '^> X-Ats-Gzip-Test:' \
+ -e '^> Accept-Encoding:' \
+ -e '^< Content-' \
+ -e '^< Vary:' \
+ -e '^$'
diff --git a/tests/gold_tests/pluginTest/gzip/gzip.config 
b/tests/gold_tests/pluginTest/gzip/gzip.config
new file mode 100644
index 0000000..c8f4fb6
--- /dev/null
+++ b/tests/gold_tests/pluginTest/gzip/gzip.config
@@ -0,0 +1,7 @@
+cache true
+remove-accept-encoding true
+compressible-content-type text/*
+compressible-content-type application/x-javascript*
+compressible-content-type application/javascript*
+compressible-content-type application/json*
+supported-algorithms gzip,br
diff --git a/tests/gold_tests/pluginTest/gzip/gzip.gold 
b/tests/gold_tests/pluginTest/gzip/gzip.gold
new file mode 100644
index 0000000..8bd76e3
--- /dev/null
+++ b/tests/gold_tests/pluginTest/gzip/gzip.gold
@@ -0,0 +1,296 @@
+> GET http://ae-0/obj0 HTTP/1.1
+> X-Ats-Gzip-Test: ts/0/gzip, deflate, sdch, br
+> Accept-Encoding: gzip, deflate, sdch, br
+< HTTP/1.1 200 OK
+< Content-Type: text/javascript
+< Content-Encoding: br
+< Vary: Accept-Encoding
+< Content-Length: 41
+
+> GET http://ae-0/obj0 HTTP/1.1
+> X-Ats-Gzip-Test: ts/0/gzip
+> Accept-Encoding: gzip
+< HTTP/1.1 200 OK
+< Content-Type: text/javascript
+< Content-Encoding: gzip
+< Vary: Accept-Encoding
+< Content-Length: 60
+
+> GET http://ae-0/obj0 HTTP/1.1
+> X-Ats-Gzip-Test: ts/0/br
+> Accept-Encoding: br
+< HTTP/1.1 200 OK
+< Content-Type: text/javascript
+< Content-Encoding: br
+< Vary: Accept-Encoding
+< Content-Length: 41
+
+> GET http://ae-0/obj0 HTTP/1.1
+> X-Ats-Gzip-Test: ts/0/deflate
+> Accept-Encoding: deflate
+< HTTP/1.1 200 OK
+< Content-Type: text/javascript
+< Content-Length: 41
+
+> GET http://ae-1/obj1 HTTP/1.1
+> X-Ats-Gzip-Test: ts/1/gzip, deflate, sdch, br
+> Accept-Encoding: gzip, deflate, sdch, br
+< HTTP/1.1 200 OK
+< Content-Type: text/javascript
+< Content-Encoding: gzip
+< Vary: Accept-Encoding
+< Content-Length: 60
+
+> GET http://ae-1/obj1 HTTP/1.1
+> X-Ats-Gzip-Test: ts/1/gzip
+> Accept-Encoding: gzip
+< HTTP/1.1 200 OK
+< Content-Type: text/javascript
+< Content-Encoding: gzip
+< Vary: Accept-Encoding
+< Content-Length: 60
+
+> GET http://ae-1/obj1 HTTP/1.1
+> X-Ats-Gzip-Test: ts/1/br
+> Accept-Encoding: br
+< HTTP/1.1 200 OK
+< Content-Type: text/javascript
+< Content-Length: 41
+
+> GET http://ae-1/obj1 HTTP/1.1
+> X-Ats-Gzip-Test: ts/1/deflate
+> Accept-Encoding: deflate
+< HTTP/1.1 200 OK
+< Content-Type: text/javascript
+< Content-Length: 41
+
+> GET http://ae-2/obj2 HTTP/1.1
+> X-Ats-Gzip-Test: ts/2/gzip, deflate, sdch, br
+> Accept-Encoding: gzip, deflate, sdch, br
+< HTTP/1.1 200 OK
+< Content-Type: text/javascript
+< Content-Encoding: br
+< Vary: Accept-Encoding
+< Content-Length: 41
+
+> GET http://ae-2/obj2 HTTP/1.1
+> X-Ats-Gzip-Test: ts/2/gzip
+> Accept-Encoding: gzip
+< HTTP/1.1 200 OK
+< Content-Type: text/javascript
+< Content-Encoding: gzip
+< Vary: Accept-Encoding
+< Content-Length: 60
+
+> GET http://ae-2/obj2 HTTP/1.1
+> X-Ats-Gzip-Test: ts/2/br
+> Accept-Encoding: br
+< HTTP/1.1 200 OK
+< Content-Type: text/javascript
+< Content-Encoding: br
+< Vary: Accept-Encoding
+< Content-Length: 41
+
+> GET http://ae-2/obj2 HTTP/1.1
+> X-Ats-Gzip-Test: ts/2/deflate
+> Accept-Encoding: deflate
+< HTTP/1.1 200 OK
+< Content-Type: text/javascript
+< Content-Length: 41
+
+> GET http://ae-0/obj0 HTTP/1.1
+> X-Ats-Gzip-Test: ts2/0/gzip
+> Accept-Encoding: gzip
+< HTTP/1.1 200 OK
+< Content-Type: text/javascript
+< Content-Encoding: gzip
+< Vary: Accept-Encoding
+< Content-Length: 60
+
+> GET http://ae-0/obj0 HTTP/1.1
+> X-Ats-Gzip-Test: ts2/0/gzip
+> Accept-Encoding: gzip
+< HTTP/1.1 200 OK
+< Content-Type: text/javascript
+< Content-Encoding: gzip
+< Vary: Accept-Encoding
+< Content-Length: 60
+
+> GET http://ae-0/obj0 HTTP/1.1
+> X-Ats-Gzip-Test: ts2/0/br
+> Accept-Encoding: br
+< HTTP/1.1 200 OK
+< Content-Type: text/javascript
+< Content-Encoding: br
+< Vary: Accept-Encoding
+< Content-Length: 41
+
+> GET http://ae-0/obj0 HTTP/1.1
+> X-Ats-Gzip-Test: ts2/0/deflate
+> Accept-Encoding: deflate
+< HTTP/1.1 200 OK
+< Content-Type: text/javascript
+< Content-Length: 41
+
+> GET http://ae-1/obj1 HTTP/1.1
+> X-Ats-Gzip-Test: ts2/1/gzip
+> Accept-Encoding: gzip
+< HTTP/1.1 200 OK
+< Content-Type: text/javascript
+< Content-Encoding: gzip
+< Vary: Accept-Encoding
+< Content-Length: 60
+
+> GET http://ae-1/obj1 HTTP/1.1
+> X-Ats-Gzip-Test: ts2/1/gzip
+> Accept-Encoding: gzip
+< HTTP/1.1 200 OK
+< Content-Type: text/javascript
+< Content-Encoding: gzip
+< Vary: Accept-Encoding
+< Content-Length: 60
+
+> GET http://ae-1/obj1 HTTP/1.1
+> X-Ats-Gzip-Test: ts2/1/br
+> Accept-Encoding: br
+< HTTP/1.1 200 OK
+< Content-Type: text/javascript
+< Content-Length: 41
+
+> GET http://ae-1/obj1 HTTP/1.1
+> X-Ats-Gzip-Test: ts2/1/deflate
+> Accept-Encoding: deflate
+< HTTP/1.1 200 OK
+< Content-Type: text/javascript
+< Content-Length: 41
+
+> GET http://ae-2/obj2 HTTP/1.1
+> X-Ats-Gzip-Test: ts2/2/gzip
+> Accept-Encoding: gzip
+< HTTP/1.1 200 OK
+< Content-Type: text/javascript
+< Content-Encoding: gzip
+< Vary: Accept-Encoding
+< Content-Length: 60
+
+> GET http://ae-2/obj2 HTTP/1.1
+> X-Ats-Gzip-Test: ts2/2/gzip
+> Accept-Encoding: gzip
+< HTTP/1.1 200 OK
+< Content-Type: text/javascript
+< Content-Encoding: gzip
+< Vary: Accept-Encoding
+< Content-Length: 60
+
+> GET http://ae-2/obj2 HTTP/1.1
+> X-Ats-Gzip-Test: ts2/2/br
+> Accept-Encoding: br
+< HTTP/1.1 200 OK
+< Content-Type: text/javascript
+< Content-Encoding: br
+< Vary: Accept-Encoding
+< Content-Length: 41
+
+> GET http://ae-2/obj2 HTTP/1.1
+> X-Ats-Gzip-Test: ts2/2/deflate
+> Accept-Encoding: deflate
+< HTTP/1.1 200 OK
+< Content-Type: text/javascript
+< Content-Length: 41
+
+> GET http://ae-0/obj0 HTTP/1.1
+> X-Ats-Gzip-Test: ts3/0/deflate
+> Accept-Encoding: deflate
+< HTTP/1.1 200 OK
+< Content-Type: text/javascript
+< Content-Length: 41
+
+> GET http://ae-0/obj0 HTTP/1.1
+> X-Ats-Gzip-Test: ts3/0/gzip
+> Accept-Encoding: gzip
+< HTTP/1.1 200 OK
+< Content-Type: text/javascript
+< Content-Encoding: gzip
+< Vary: Accept-Encoding
+< Content-Length: 60
+
+> GET http://ae-0/obj0 HTTP/1.1
+> X-Ats-Gzip-Test: ts3/0/br
+> Accept-Encoding: br
+< HTTP/1.1 200 OK
+< Content-Type: text/javascript
+< Content-Encoding: br
+< Vary: Accept-Encoding
+< Content-Length: 41
+
+> GET http://ae-0/obj0 HTTP/1.1
+> X-Ats-Gzip-Test: ts3/0/deflate
+> Accept-Encoding: deflate
+< HTTP/1.1 200 OK
+< Content-Type: text/javascript
+< Content-Length: 41
+
+> GET http://ae-1/obj1 HTTP/1.1
+> X-Ats-Gzip-Test: ts3/1/deflate
+> Accept-Encoding: deflate
+< HTTP/1.1 200 OK
+< Content-Type: text/javascript
+< Content-Length: 41
+
+> GET http://ae-1/obj1 HTTP/1.1
+> X-Ats-Gzip-Test: ts3/1/gzip
+> Accept-Encoding: gzip
+< HTTP/1.1 200 OK
+< Content-Type: text/javascript
+< Content-Encoding: gzip
+< Vary: Accept-Encoding
+< Content-Length: 60
+
+> GET http://ae-1/obj1 HTTP/1.1
+> X-Ats-Gzip-Test: ts3/1/br
+> Accept-Encoding: br
+< HTTP/1.1 200 OK
+< Content-Type: text/javascript
+< Content-Encoding: br
+< Vary: Accept-Encoding
+< Content-Length: 41
+
+> GET http://ae-1/obj1 HTTP/1.1
+> X-Ats-Gzip-Test: ts3/1/deflate
+> Accept-Encoding: deflate
+< HTTP/1.1 200 OK
+< Content-Type: text/javascript
+< Content-Length: 41
+
+> GET http://ae-2/obj2 HTTP/1.1
+> X-Ats-Gzip-Test: ts3/2/deflate
+> Accept-Encoding: deflate
+< HTTP/1.1 200 OK
+< Content-Type: text/javascript
+< Content-Length: 41
+
+> GET http://ae-2/obj2 HTTP/1.1
+> X-Ats-Gzip-Test: ts3/2/gzip
+> Accept-Encoding: gzip
+< HTTP/1.1 200 OK
+< Content-Type: text/javascript
+< Content-Encoding: gzip
+< Vary: Accept-Encoding
+< Content-Length: 60
+
+> GET http://ae-2/obj2 HTTP/1.1
+> X-Ats-Gzip-Test: ts3/2/br
+> Accept-Encoding: br
+< HTTP/1.1 200 OK
+< Content-Type: text/javascript
+< Content-Encoding: br
+< Vary: Accept-Encoding
+< Content-Length: 41
+
+> GET http://ae-2/obj2 HTTP/1.1
+> X-Ats-Gzip-Test: ts3/2/deflate
+> Accept-Encoding: deflate
+< HTTP/1.1 200 OK
+< Content-Type: text/javascript
+< Content-Length: 41
+
diff --git a/tests/gold_tests/pluginTest/gzip/gzip.test.py 
b/tests/gold_tests/pluginTest/gzip/gzip.test.py
new file mode 100644
index 0000000..8d55cca
--- /dev/null
+++ b/tests/gold_tests/pluginTest/gzip/gzip.test.py
@@ -0,0 +1,137 @@
+'''
+'''
+#  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 os
+import subprocess
+Test.Summary = '''
+Test gzip plugin
+'''
+
+# This test case is very bare-bones.  It only covers a few scenarios that have 
caused problems.
+
+# Skip if plugins not present.
+#
+Test.SkipUnless(Condition.PluginExists('gzip.so'))
+Test.SkipUnless(Condition.PluginExists('conf_remap.so'))
+Test.SkipUnless(Condition.HasProgram("netstat", "netstat need to be installed 
on system for this test to work"))
+
+server = Test.MakeOriginServer("server", options={'--load': 
'{}/gzip_observer.py'.format(Test.TestDirectory)})
+
+# expected response from the origin server
+response_header = {
+    "headers": "HTTP/1.1 200 OK\r\nConnection: close\r\n" +
+    'Etag: "359670651"\r\n' +
+    "Cache-Control: public, max-age=31536000\r\n" +
+    "Accept-Ranges: bytes\r\n" +
+    "Content-Type: text/javascript\r\n" +
+    "\r\n",
+    "timestamp": "1469733493.993",
+    "body": "lets go surfin now everybodys learnin how"
+}
+for i in range(3):
+    # add request/response to the server dictionary
+    request_header = {
+        "headers": "GET /obj{} HTTP/1.1\r\nHost: 
just.any.thing\r\n\r\n".format(i), "timestamp": "1469733493.993", "body": ""
+    }
+    server.addResponse("sessionfile.log", request_header, response_header)
+
+# Ask the OS if the port is ready for connect()
+#
+def CheckPort(Port):
+    return lambda: 0 == subprocess.call('netstat --listen --tcp -n | grep -q 
:{}'.format(Port), shell=True)
+
+def oneTs(name, AeHdr1='gzip, deflate, sdch, br'):
+    global waitForServer
+
+    waitForTs = True
+
+    ts = Test.MakeATSProcess(name)
+
+    ts.Disk.records_config.update({
+        # 'proxy.config.diags.debug.enabled': 1,
+        # 'proxy.config.diags.debug.tags': 'http|gzip|cache',
+        'proxy.config.http.normalize_ae': 0,
+    })
+
+    ts.Disk.remap_config.AddLine(
+        'map http://ae-0/ http://127.0.0.1:{}/'.format(server.Variables.Port) +
+        ' @plugin=gzip.so @pparam={}/gzip.config'.format(Test.TestDirectory)
+    )
+    ts.Disk.remap_config.AddLine(
+        'map http://ae-1/ http://127.0.0.1:{}/'.format(server.Variables.Port) +
+        ' @plugin=conf_remap.so @pparam=proxy.config.http.normalize_ae=1' +
+        ' @plugin=gzip.so @pparam={}/gzip.config'.format(Test.TestDirectory)
+    )
+    ts.Disk.remap_config.AddLine(
+        'map http://ae-2/ http://127.0.0.1:{}/'.format(server.Variables.Port) +
+        ' @plugin=conf_remap.so @pparam=proxy.config.http.normalize_ae=2' +
+        ' @plugin=gzip.so @pparam={}/gzip.config'.format(Test.TestDirectory)
+    )
+
+    def curl(idx, encodingList):
+        return (
+            "curl --verbose --proxy 
http://127.0.0.1:{}".format(ts.Variables.port) +
+            " --header 'X-Ats-Gzip-Test: {}/{}/{}'".format(name, idx, 
encodingList) +
+            " --header 'Accept-Encoding: {0}' 
'http://ae-{1}/obj{1}'".format(encodingList, idx) +
+            " >> {0}/gzip_long.log 2>&1 ; printf '\n\n' >> 
{0}/gzip_long.log".format(Test.RunDirectory)
+        )
+
+    for i in range(3):
+
+        tr = Test.AddTestRun()
+        if (waitForTs):
+            tr.Processes.Default.StartBefore(ts, 
ready=CheckPort(ts.Variables.port))
+        waitForTs = False
+        if (waitForServer):
+            tr.Processes.Default.StartBefore(server, 
ready=CheckPort(server.Variables.Port))
+        waitForServer = False
+        tr.Processes.Default.ReturnCode = 0
+        tr.Processes.Default.Command = curl(i, AeHdr1)
+
+        tr = Test.AddTestRun()
+        tr.Processes.Default.ReturnCode = 0
+        tr.Processes.Default.Command = curl(i, "gzip")
+
+        tr = Test.AddTestRun()
+        tr.Processes.Default.ReturnCode = 0
+        tr.Processes.Default.Command = curl(i, "br")
+
+        tr = Test.AddTestRun()
+        tr.Processes.Default.ReturnCode = 0
+        tr.Processes.Default.Command = curl(i, "deflate")
+
+waitForServer = True
+
+oneTs("ts")
+oneTs("ts2", "gzip")
+oneTs("ts3", "deflate")
+
+tr = Test.AddTestRun()
+tr.Processes.Default.ReturnCode = 0
+tr.Processes.Default.Command = (
+    r"tr -d '\r' < {1}/gzip_long.log | sed 's/\(..*\)\([<>]\)/\1\n\2/' | 
{0}/greplog.sh > {1}/gzip_short.log"
+).format(Test.TestDirectory, Test.RunDirectory)
+f = tr.Disk.File("gzip_short.log")
+f.Content = "gzip.gold"
+
+# Have to comment this out, because caching does not seem to be consistent, 
which is disturbing.
+#
+# tr = Test.AddTestRun()
+# tr.Processes.Default.Command = "echo"
+# f = tr.Disk.File("gzip_userver.log")
+# f.Content = "gzip_userver.gold"
diff --git a/tests/gold_tests/pluginTest/gzip/gzip_observer.py 
b/tests/gold_tests/pluginTest/gzip/gzip_observer.py
new file mode 100755
index 0000000..d61334d
--- /dev/null
+++ b/tests/gold_tests/pluginTest/gzip/gzip_observer.py
@@ -0,0 +1,26 @@
+'''
+For gzip gold test, observer for micro-server.
+'''
+#  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.
+
+log = open('gzip_userver.log', 'w')
+
+def observe(headers):
+    log.write("{}\n".format(headers['X-Ats-Gzip-Test']))
+    log.flush()
+
+Hooks.register(Hooks.ReadRequestHook, observe)
diff --git a/tests/gold_tests/pluginTest/gzip/gzip_userver.gold 
b/tests/gold_tests/pluginTest/gzip/gzip_userver.gold
new file mode 100644
index 0000000..20ce75d
--- /dev/null
+++ b/tests/gold_tests/pluginTest/gzip/gzip_userver.gold
@@ -0,0 +1,19 @@
+ts/0/gzip, deflate, sdch, br
+ts/0/gzip
+ts/0/deflate
+ts/1/gzip, deflate, sdch, br
+ts/1/br
+ts/2/gzip, deflate, sdch, br
+ts/2/gzip
+ts/2/deflate
+ts2/0/gzip
+ts2/0/br
+ts2/0/deflate
+ts2/1/gzip
+ts2/1/br
+ts2/2/gzip
+ts2/2/br
+ts2/2/deflate
+ts3/0/deflate
+ts3/1/deflate
+ts3/2/deflate

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

Reply via email to