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


The following commit(s) were added to refs/heads/7.1.x by this push:
     new 1931ba0  Prevents response body content with a 204
1931ba0 is described below

commit 1931ba095d0efb1e0b4a859fc754ff11e9f9b9c6
Author: Derek Dagit <der...@yahoo-inc.com>
AuthorDate: Mon Jun 12 15:23:15 2017 +0000

    Prevents response body content with a 204
    
    (cherry picked from commit fe24de0f50a6692d6eb9f0eb9fbcf68d414fe4c7)
---
 proxy/http/HttpBodyFactory.cc                      |  10 ++
 proxy/http/HttpSM.cc                               |   4 +-
 proxy/http/HttpTransact.cc                         |  17 +--
 proxy/http/HttpTransact.h                          |   2 +-
 tests/autest.sh                                    |   2 +-
 .../gold_tests/autest-site/trafficserver.test.ext  |   5 +
 .../autest-site/trafficserver_plugins.test.ext     |  44 ++++++
 .../data/www.customplugin204.test_get.txt          |   2 +
 .../data/www.customtemplate204.test_get.txt        |   2 +
 .../body_factory/data/www.default204.test_get.txt  |   2 +
 .../body_factory/gold/http-204-custom-plugin.gold  |  19 +++
 .../body_factory/gold/http-204-custom.gold         |  21 +++
 tests/gold_tests/body_factory/gold/http-204.gold   |   4 +
 .../body_factory/http204_response.test.py          |  93 +++++++++++++
 .../body_factory/http204_response_plugin.test.py   |  52 +++++++
 tests/tools/plugins/custom204plugin.cc             | 153 +++++++++++++++++++++
 tests/tools/tcp_client.py                          |  59 ++++++++
 17 files changed, 479 insertions(+), 12 deletions(-)

diff --git a/proxy/http/HttpBodyFactory.cc b/proxy/http/HttpBodyFactory.cc
index edec63f..3d3ddcf 100644
--- a/proxy/http/HttpBodyFactory.cc
+++ b/proxy/http/HttpBodyFactory.cc
@@ -146,6 +146,11 @@ HttpBodyFactory::fabricate_with_old_api(const char *type, 
HttpTransact::State *c
   // if failed, try to fabricate the default custom response //
   /////////////////////////////////////////////////////////////
   if (buffer == nullptr) {
+    if (is_response_body_precluded(context->http_return_code, 
context->method)) {
+      *resulting_buffer_length = 0;
+      unlock();
+      return nullptr;
+    }
     buffer = fabricate(&acpt_language_list, &acpt_charset_list, "default", 
context, resulting_buffer_length, &lang_ptr,
                        &charset_ptr, &set);
   }
@@ -429,6 +434,8 @@ HttpBodyFactory::fabricate(StrList *acpt_language_list, 
StrList *acpt_charset_li
     set = determine_set_by_language(acpt_language_list, acpt_charset_list);
   } else if (enable_customizations == 3) {
     set = determine_set_by_host(context);
+  } else if (is_response_body_precluded(context->http_return_code, 
context->method)) {
+    return nullptr;
   } else {
     set = "default";
   }
@@ -443,6 +450,9 @@ HttpBodyFactory::fabricate(StrList *acpt_language_list, 
StrList *acpt_charset_li
   // see if we have a custom error page template
   t = find_template(set, template_base, &body_set);
   if (t == nullptr) {
+    if (is_response_body_precluded(context->http_return_code, 
context->method)) {
+      return nullptr;
+    }
     t = find_template(set, type, &body_set); // this executes if the 
template_base is wrong and doesn't exist
   }
   if (t == nullptr) {
diff --git a/proxy/http/HttpSM.cc b/proxy/http/HttpSM.cc
index c8da407..fc21966 100644
--- a/proxy/http/HttpSM.cc
+++ b/proxy/http/HttpSM.cc
@@ -6271,10 +6271,10 @@ HttpSM::setup_100_continue_transfer()
 void
 HttpSM::setup_error_transfer()
 {
-  if (t_state.internal_msg_buffer) {
+  if (t_state.internal_msg_buffer || t_state.http_return_code == 
HTTP_STATUS_NO_CONTENT) {
     // Since we need to send the error message, call the API
     //   function
-    ink_assert(t_state.internal_msg_buffer_size > 0);
+    ink_assert(t_state.internal_msg_buffer_size > 0 || 
t_state.http_return_code == HTTP_STATUS_NO_CONTENT);
     t_state.api_next_action = HttpTransact::SM_ACTION_API_SEND_RESPONSE_HDR;
     do_api_callout();
   } else {
diff --git a/proxy/http/HttpTransact.cc b/proxy/http/HttpTransact.cc
index 631decf..68716b2 100644
--- a/proxy/http/HttpTransact.cc
+++ b/proxy/http/HttpTransact.cc
@@ -8044,11 +8044,6 @@ HttpTransact::build_response(State *s, HTTPHdr 
*base_response, HTTPHdr *outgoing
 
   HttpTransactHeaders::add_server_header_to_response(s->txn_conf, 
outgoing_response);
 
-  // auth-response update
-  // if (!s->state_machine->authAdapter.disabled()) {
-  //  s->state_machine->authAdapter.UpdateResponseHeaders(outgoing_response);
-  // }
-
   if (!s->cop_test_page && is_debug_tag_set("http_hdrs")) {
     if (base_response) {
       DUMP_HEADER("http_hdrs", base_response, s->state_machine_id, "Base 
Header for Building Response");
@@ -8236,9 +8231,15 @@ HttpTransact::build_error_response(State *s, HTTPStatus 
status_code, const char
   s->internal_msg_buffer_size                = len;
   s->internal_msg_buffer_fast_allocator_size = -1;
 
-  s->hdr_info.client_response.value_set(MIME_FIELD_CONTENT_TYPE, 
MIME_LEN_CONTENT_TYPE, body_type, strlen(body_type));
-  s->hdr_info.client_response.value_set(MIME_FIELD_CONTENT_LANGUAGE, 
MIME_LEN_CONTENT_LANGUAGE, body_language,
-                                        strlen(body_language));
+  if (!is_response_body_precluded(status_code, s->method) || len > 0) {
+    // Plugins may create response bodies despite an HTTP spec violation.
+    s->hdr_info.client_response.value_set(MIME_FIELD_CONTENT_TYPE, 
MIME_LEN_CONTENT_TYPE, body_type, strlen(body_type));
+    s->hdr_info.client_response.value_set(MIME_FIELD_CONTENT_LANGUAGE, 
MIME_LEN_CONTENT_LANGUAGE, body_language,
+                                          strlen(body_language));
+  } else {
+    s->hdr_info.client_response.field_delete(MIME_FIELD_CONTENT_TYPE, 
MIME_LEN_CONTENT_TYPE);
+    s->hdr_info.client_response.field_delete(MIME_FIELD_CONTENT_LANGUAGE, 
MIME_LEN_CONTENT_LANGUAGE);
+  }
 
   ////////////////////////////////////////
   // log a description in the error log //
diff --git a/proxy/http/HttpTransact.h b/proxy/http/HttpTransact.h
index 33fa650..4791919 100644
--- a/proxy/http/HttpTransact.h
+++ b/proxy/http/HttpTransact.h
@@ -1363,7 +1363,7 @@ is_response_body_precluded(HTTPStatus status_code, int 
method)
 
   if (((status_code != HTTP_STATUS_OK) &&
        ((status_code == HTTP_STATUS_NOT_MODIFIED) || ((status_code < 
HTTP_STATUS_OK) && (status_code >= HTTP_STATUS_CONTINUE)) ||
-        (status_code == 204))) ||
+        (status_code == HTTP_STATUS_NO_CONTENT))) ||
       (method == HTTP_WKSIDX_HEAD)) {
     return true;
   } else {
diff --git a/tests/autest.sh b/tests/autest.sh
index 45f4d51..33c4d21 100755
--- a/tests/autest.sh
+++ b/tests/autest.sh
@@ -29,7 +29,7 @@ if [ ! -f ./env-test/bin/autest ]; then\
 # this is for rhel or centos systems
 test -r /opt/rh/rh-python35/enable && . /opt/rh/rh-python35/enable
 . env-test/bin/activate
-./env-test/bin/autest -D gold_tests $*
+./env-test/bin/autest -D gold_tests "$@"
 ret=$?
 popd > /dev/null
 exit $ret
diff --git a/tests/gold_tests/autest-site/trafficserver.test.ext 
b/tests/gold_tests/autest-site/trafficserver.test.ext
index 6d4005e..e9245f6 100644
--- a/tests/gold_tests/autest-site/trafficserver.test.ext
+++ b/tests/gold_tests/autest-site/trafficserver.test.ext
@@ -213,6 +213,11 @@ def MakeATSProcess(obj, name, command='traffic_server', 
select_ports=True):
     tmpname = os.path.join(config_dir, fname)
     p.Disk.File(tmpname, id=make_id(fname), typename="ats:config")
 
+    # This is for regex_remap plugin.
+    fname = "maps.reg"
+    tmpname = os.path.join(config_dir, fname)
+    p.Disk.File(tmpname, id=make_id(fname), typename="ats:config")
+
     fname = "socks.config"
     tmpname = os.path.join(config_dir, fname)
     p.Disk.File(tmpname, id=make_id(fname), typename="ats:config")
diff --git a/tests/gold_tests/autest-site/trafficserver_plugins.test.ext 
b/tests/gold_tests/autest-site/trafficserver_plugins.test.ext
new file mode 100644
index 0000000..fb53bd7
--- /dev/null
+++ b/tests/gold_tests/autest-site/trafficserver_plugins.test.ext
@@ -0,0 +1,44 @@
+'''
+Builds, installs, and enables an ATS plugin in the sandbox environment
+'''
+#  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
+
+def prepare_plugin(self, path, tsproc):
+    """Builds, installs, and enables an ATS plugin in the sandbox environment
+
+    The source file at the given path is copied to the sandbox directory of the
+    given traffic server process and compiled into a binary with the file
+    extensioned replaced with '.so'. An entry for this plugin is added to
+    the 'plugin.config' file."""
+
+    # Copy the source to the sandbox directory.
+    plugin_dir = tsproc.Env['PROXY_CONFIG_PLUGIN_PLUGIN_DIR']
+    tsproc.Setup.Copy(path, plugin_dir)
+
+    # Compile the plugin.
+    in_basename = os.path.basename(path)
+    in_path = os.path.join(plugin_dir, in_basename)
+    out_basename = os.path.splitext(in_basename)[0] + '.so'
+    out_path = os.path.join(plugin_dir, out_basename)
+    tsproc.Setup.RunCommand("tsxs -c {0} -o {1}".format(in_path, out_path))
+
+    # Add an entry to plugin.config.
+    tsproc.Disk.plugin_config.AddLine(out_basename)
+
+ExtendTest(prepare_plugin, name="prepare_plugin")
diff --git 
a/tests/gold_tests/body_factory/data/www.customplugin204.test_get.txt 
b/tests/gold_tests/body_factory/data/www.customplugin204.test_get.txt
new file mode 100644
index 0000000..be603f9
--- /dev/null
+++ b/tests/gold_tests/body_factory/data/www.customplugin204.test_get.txt
@@ -0,0 +1,2 @@
+GET HTTP://www.customplugin204.test/ HTTP/1.1
+
diff --git 
a/tests/gold_tests/body_factory/data/www.customtemplate204.test_get.txt 
b/tests/gold_tests/body_factory/data/www.customtemplate204.test_get.txt
new file mode 100644
index 0000000..395d798
--- /dev/null
+++ b/tests/gold_tests/body_factory/data/www.customtemplate204.test_get.txt
@@ -0,0 +1,2 @@
+GET HTTP://www.customtemplate204.test/ HTTP/1.1
+
diff --git a/tests/gold_tests/body_factory/data/www.default204.test_get.txt 
b/tests/gold_tests/body_factory/data/www.default204.test_get.txt
new file mode 100644
index 0000000..e77408a
--- /dev/null
+++ b/tests/gold_tests/body_factory/data/www.default204.test_get.txt
@@ -0,0 +1,2 @@
+GET HTTP://www.default204.test/ HTTP/1.1
+
diff --git a/tests/gold_tests/body_factory/gold/http-204-custom-plugin.gold 
b/tests/gold_tests/body_factory/gold/http-204-custom-plugin.gold
new file mode 100644
index 0000000..cab77b6
--- /dev/null
+++ b/tests/gold_tests/body_factory/gold/http-204-custom-plugin.gold
@@ -0,0 +1,19 @@
+HTTP/1.1 204 No Content
+Connection: keep-alive
+Cache-Control: no-store
+Content-Length: 282
+Content-Type: text/html
+
+<HTML>
+<HEAD>
+<TITLE>Spec-breaking 204!</TITLE>
+</HEAD>
+
+<BODY>
+<H1>This is body content for a 204.</H1>
+<HR>
+
+Description: According to rfc7231 I should not have been sent to you!<BR/>
+This response was sent via the custom204plugin via a call to 
TSHttpTxnErrorBodySet.
+<HR>
+</BODY>
diff --git a/tests/gold_tests/body_factory/gold/http-204-custom.gold 
b/tests/gold_tests/body_factory/gold/http-204-custom.gold
new file mode 100644
index 0000000..fb84d9b
--- /dev/null
+++ b/tests/gold_tests/body_factory/gold/http-204-custom.gold
@@ -0,0 +1,21 @@
+HTTP/1.1 204 No Content
+Connection: keep-alive
+Cache-Control: no-store
+Content-Type: text/html
+Content-Language: en
+Content-Length: 271
+
+<HTML>
+<HEAD>
+<TITLE>Spec-breaking 204!</TITLE>
+</HEAD>
+
+<BODY BGCOLOR="white" FGCOLOR="black">
+<H1>This is body content for a 204.</H1>
+<HR>
+
+<FONT FACE="Helvetica,Arial"><B>
+Description: According to rfc7231 I should not have been sent to you!
+</B></FONT>
+<HR>
+</BODY>
diff --git a/tests/gold_tests/body_factory/gold/http-204.gold 
b/tests/gold_tests/body_factory/gold/http-204.gold
new file mode 100644
index 0000000..2931202
--- /dev/null
+++ b/tests/gold_tests/body_factory/gold/http-204.gold
@@ -0,0 +1,4 @@
+HTTP/1.1 204 No Content
+Connection: keep-alive
+Cache-Control: no-store
+
diff --git a/tests/gold_tests/body_factory/http204_response.test.py 
b/tests/gold_tests/body_factory/http204_response.test.py
new file mode 100644
index 0000000..1fb748f
--- /dev/null
+++ b/tests/gold_tests/body_factory/http204_response.test.py
@@ -0,0 +1,93 @@
+'''
+Tests that 204 responses conform to rfc2616, unless custom templates override.
+'''
+#  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
+
+Test.Summary = '''
+Tests that 204 responses conform to rfc2616, unless custom templates override.
+'''
+
+Test.SkipUnless(Condition.HasProgram("grep","grep needs to be installed on 
system for this test to work"))
+
+ts=Test.MakeATSProcess("ts")
+server=Test.MakeOriginServer("server")
+
+DEFAULT_204_HOST='www.default204.test'
+CUSTOM_TEMPLATE_204_HOST='www.customtemplate204.test'
+
+ts.Disk.records_config.update({
+    # enable domain specific body factory
+    'proxy.config.body_factory.enable_customizations': 3,
+    })
+
+# Create a template body for a 204.
+body_factory_dir=ts.Variables.body_factory_template_dir
+ts.Disk.File(os.path.join(body_factory_dir, 'default', 
CUSTOM_TEMPLATE_204_HOST+'_default')).\
+    WriteOn(
+"""<HTML>
+<HEAD>
+<TITLE>Spec-breaking 204!</TITLE>
+</HEAD>
+
+<BODY BGCOLOR="white" FGCOLOR="black">
+<H1>This is body content for a 204.</H1>
+<HR>
+
+<FONT FACE="Helvetica,Arial"><B>
+Description: According to rfc7231 I should not have been sent to you!
+</B></FONT>
+<HR>
+</BODY>
+""")
+
+ts.Disk.remap_config.AddLine(
+    'map http://{0} http://127.0.0.1:{1} @plugin=regex_remap.so 
@pparam=maps.reg @pparam=no-query-string @pparam=host'
+                    .format(DEFAULT_204_HOST, server.Variables.Port)
+    )
+ts.Disk.remap_config.AddLine(
+    'map http://{0} http://127.0.0.1:{1} @plugin=regex_remap.so 
@pparam=maps.reg @pparam=no-query-string @pparam=host @plugin=conf_remap.so 
@pparam=proxy.config.body_factory.template_base={0}'
+                    .format(CUSTOM_TEMPLATE_204_HOST, server.Variables.Port)
+    )
+ts.Disk.maps_reg.AddLine(
+    '//.*/ http://127.0.0.1:{0} @status=204'
+            .format(server.Variables.Port)
+    )
+
+Test.Setup.Copy(os.path.join(os.pardir,os.pardir,'tools','tcp_client.py'))
+Test.Setup.Copy('data')
+
+defaultTr=Test.AddTestRun("Test domain {0}".format(DEFAULT_204_HOST))
+defaultTr.Processes.Default.StartBefore(Test.Processes.ts)
+defaultTr.StillRunningAfter = ts
+
+defaultTr.Processes.Default.Command="python tcp_client.py 127.0.0.1 {0} {1} | 
grep -v '^Date: '| grep -v '^Server: ATS/'".\
+    format(ts.Variables.port, 'data/{0}_get.txt'.format(DEFAULT_204_HOST))
+defaultTr.Processes.Default.TimeOut=5 # seconds
+defaultTr.Processes.Default.ReturnCode=0
+defaultTr.Processes.Default.Streams.stdout="gold/http-204.gold"
+
+
+customTemplateTr=Test.AddTestRun("Test domain 
{0}".format(CUSTOM_TEMPLATE_204_HOST))
+customTemplateTr.StillRunningBefore = ts
+customTemplateTr.StillRunningAfter = ts
+customTemplateTr.Processes.Default.Command="python tcp_client.py 127.0.0.1 {0} 
{1} | grep -v '^Date: '| grep -v '^Server: ATS/'".\
+    format(ts.Variables.port, 
'data/{0}_get.txt'.format(CUSTOM_TEMPLATE_204_HOST))
+customTemplateTr.Processes.Default.TimeOut=5 # seconds
+customTemplateTr.Processes.Default.ReturnCode=0
+customTemplateTr.Processes.Default.Streams.stdout="gold/http-204-custom.gold"
diff --git a/tests/gold_tests/body_factory/http204_response_plugin.test.py 
b/tests/gold_tests/body_factory/http204_response_plugin.test.py
new file mode 100644
index 0000000..ee3d498
--- /dev/null
+++ b/tests/gold_tests/body_factory/http204_response_plugin.test.py
@@ -0,0 +1,52 @@
+'''
+Tests that plugins may break HTTP by sending 204 respose bodies
+'''
+#  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
+
+Test.Summary = '''
+Tests that plugins may break HTTP by sending 204 respose bodies
+'''
+
+Test.SkipUnless(Condition.HasProgram("grep","grep needs to be installed on 
system for this test to work"))
+
+ts=Test.MakeATSProcess("ts")
+server=Test.MakeOriginServer("server")
+
+CUSTOM_PLUGIN_204_HOST='www.customplugin204.test'
+
+ts.Disk.remap_config.AddLine(
+    'map http://{0} http://127.0.0.1:{1} @plugin=regex_remap.so 
@pparam=maps.reg @pparam=no-query-string @pparam=host'
+            .format(CUSTOM_PLUGIN_204_HOST, server.Variables.Port)
+    )
+ts.Disk.maps_reg.AddLine('//.*/ http://donotcare.test @status=204')
+
+Test.prepare_plugin(os.path.join(Test.Variables.AtsTestToolsDir, 'plugins', 
'custom204plugin.cc'), ts)
+
+Test.Setup.Copy(os.path.join(os.pardir,os.pardir,'tools','tcp_client.py'))
+Test.Setup.Copy('data')
+
+tr=Test.AddTestRun("Test domain {0}".format(CUSTOM_PLUGIN_204_HOST))
+tr.Processes.Default.StartBefore(Test.Processes.ts)
+tr.StillRunningAfter = ts
+
+tr.Processes.Default.Command="python tcp_client.py 127.0.0.1 {0} {1} | grep -v 
'^Date: '| grep -v '^Server: ATS/'".\
+    format(ts.Variables.port, 
'data/{0}_get.txt'.format(CUSTOM_PLUGIN_204_HOST))
+tr.Processes.Default.TimeOut=5 # seconds
+tr.Processes.Default.ReturnCode=0
+tr.Processes.Default.Streams.stdout="gold/http-204-custom-plugin.gold"
diff --git a/tests/tools/plugins/custom204plugin.cc 
b/tests/tools/plugins/custom204plugin.cc
new file mode 100644
index 0000000..98fde58
--- /dev/null
+++ b/tests/tools/plugins/custom204plugin.cc
@@ -0,0 +1,153 @@
+/** @file
+
+  A plugin that sets custom 204 response bodies.
+
+  @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 "ts/ts.h"
+#include "string.h"
+
+#define PLUGIN_NAME "custom204plugintest"
+
+static int
+local_handler(TSCont contp, TSEvent event, void *edata) {
+
+  const char *msg =
+"<HTML>\n"
+"<HEAD>\n"
+"<TITLE>Spec-breaking 204!</TITLE>\n"
+"</HEAD>\n"
+"\n"
+"<BODY>\n"
+"<H1>This is body content for a 204.</H1>\n"
+"<HR>\n"
+"\n"
+"Description: According to rfc7231 I should not have been sent to you!<BR/>\n"
+"This response was sent via the custom204plugin via a call to 
TSHttpTxnErrorBodySet.\n"
+"<HR>\n"
+"</BODY>";
+  TSHttpTxn txnp = (TSHttpTxn) edata;
+  TSMBuffer bufp = nullptr;
+  TSMLoc hdr_loc = nullptr;
+  TSMLoc url_loc = nullptr;;
+  const char *host = nullptr;
+  int host_length;
+  const char *test_host = "www.customplugin204.test";
+
+  switch (event) {
+  case TS_EVENT_HTTP_PRE_REMAP:
+    TSDebug(PLUGIN_NAME, "event TS_EVENT_HTTP_PRE_REMAP received");
+    TSDebug(PLUGIN_NAME, "running plugin logic.");
+    if (TSHttpTxnClientReqGet(txnp, &bufp, &hdr_loc) != TS_SUCCESS) {
+      TSDebug(PLUGIN_NAME, "Couldn't retrieve client request header");
+      TSError("[%s] Couldn't retrieve client request header", PLUGIN_NAME);
+      goto done;
+    }
+    TSDebug(PLUGIN_NAME, "got client request");
+
+    if (TSHttpHdrUrlGet(bufp, hdr_loc, &url_loc) != TS_SUCCESS) {
+      TSError("[%s] Couldn't retrieve request url", PLUGIN_NAME);
+      TSDebug(PLUGIN_NAME, "Couldn't retrieve request url");
+      TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
+      goto done;
+    }
+    TSDebug(PLUGIN_NAME, "got client request url");
+
+    host = TSUrlHostGet(bufp, url_loc, &host_length);
+    if (!host) {
+      TSError("[%s] Couldn't retrieve request hostname", PLUGIN_NAME);
+      TSDebug(PLUGIN_NAME, "Couldn't retrieve request hostname");
+      TSHandleMLocRelease(bufp, hdr_loc, url_loc);
+      TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
+      goto done;
+    }
+    TSDebug(PLUGIN_NAME, "request's host was retrieved");
+
+    if (strncmp(host, test_host, strlen(test_host)) == 0) {
+      TSDebug(PLUGIN_NAME, "host matches, hook 
TS_HTTP_SEND_RESPONSE_HDR_HOOK");
+      TSHttpTxnHookAdd(txnp, TS_HTTP_SEND_RESPONSE_HDR_HOOK, contp);
+      TSHandleMLocRelease(bufp, hdr_loc, url_loc);
+      TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
+      TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
+      return 0;
+    }
+    TSDebug(PLUGIN_NAME, "Host != expected host '%s'", test_host);
+  break;
+  case TS_EVENT_HTTP_SEND_RESPONSE_HDR:
+    TSDebug(PLUGIN_NAME, "Returning 204 with custom response body.");
+    TSHttpTxnSetHttpRetStatus(txnp, TS_HTTP_STATUS_NO_CONTENT);
+    TSHttpTxnErrorBodySet(txnp, TSstrdup(msg), strlen(msg),
+        TSstrdup("text/html"));
+  break;
+
+  case TS_EVENT_HTTP_TXN_CLOSE:
+    TSDebug(PLUGIN_NAME, "event TS_EVENT_HTTP_TXN_CLOSE received");
+    TSContDestroy(contp);
+    break;
+
+  default:
+     TSAssert(!"Unexpected event");
+     break;
+
+  }
+
+done:
+  TSHandleMLocRelease(bufp, hdr_loc, url_loc);
+  TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
+  TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
+  return 1;
+}
+
+static int
+global_handler(TSCont contp, TSEvent event, void *edata) {
+  TSHttpTxn txnp = (TSHttpTxn) edata;
+  TSCont txn_contp = nullptr;
+
+  switch(event) {
+  case TS_EVENT_HTTP_TXN_START:
+    txn_contp = TSContCreate(local_handler, TSMutexCreate());
+    TSHttpTxnHookAdd(txnp, TS_HTTP_PRE_REMAP_HOOK, txn_contp);
+    TSHttpTxnHookAdd(txnp, TS_HTTP_TXN_CLOSE_HOOK, txn_contp);
+    TSDebug(PLUGIN_NAME, "hooked TS_HTTP_OS_DNS_HOOK and 
TS_EVENT_HTTP_TXN_CLOSE_HOOK");
+    break;
+  default:
+    TSAssert(!"Unexpected event");
+    break;
+  }
+  TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
+  return 1;
+}
+
+void
+TSPluginInit(int argc, const char *argv[])
+{
+  TSPluginRegistrationInfo info;
+
+  info.plugin_name   = PLUGIN_NAME;
+  info.vendor_name   = "Apache Software Foundation";
+  info.support_email = "d...@trafficserver.apache.org";
+
+  if (TSPluginRegister(&info) != TS_SUCCESS) {
+    TSError("[%s] Plugin registration failed", PLUGIN_NAME);
+  }
+
+  TSCont contp = TSContCreate(global_handler, TSMutexCreate());
+  TSHttpHookAdd(TS_HTTP_TXN_START_HOOK, contp);
+}
diff --git a/tests/tools/tcp_client.py b/tests/tools/tcp_client.py
new file mode 100644
index 0000000..2fb0c00
--- /dev/null
+++ b/tests/tools/tcp_client.py
@@ -0,0 +1,59 @@
+'''
+A simple command line interface to send/receive bytes over TCP.
+'''
+#  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 argparse
+import socket
+import sys
+
+def tcp_client(host, port, data):
+    pass
+    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+    s.connect((host, port))
+    s.sendall(data.encode())
+    s.shutdown(socket.SHUT_WR)
+    while True:
+        output = s.recv(4096) # suggested bufsize from docs.python.org
+        if len(output) <= 0:
+            break
+        else:
+            sys.stdout.write(output.decode())
+    s.close()
+
+DESCRIPTION=\
+"""A simple command line interface to send/receive bytes over TCP.
+
+The full contents of the given file are sent via a TCP connection to the given
+host and port. Then data is read from the connection and printed to standard
+output. Streaming is not supported."""
+
+def main(argv):
+    parser = argparse.ArgumentParser(description=DESCRIPTION)
+    parser.add_argument('host', help='the target host')
+    parser.add_argument('port', type=int, help='the target port')
+    parser.add_argument('file', help='the file with content to be sent')
+    args = parser.parse_args()
+
+    data = ''
+    with open(args.file, 'r') as f:
+        data = f.read()
+
+    tcp_client(args.host, args.port, data)
+
+if __name__ == "__main__":
+    main(sys.argv)

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

Reply via email to