trafficserver-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From a..@apache.org
Subject trafficserver git commit: TS-3715: Add documentation and example for TS_HTTP_RESPONSE_CLIENT_HOOK
Date Wed, 24 Jun 2015 14:12:33 GMT
Repository: trafficserver
Updated Branches:
  refs/heads/master 738d9ed3c -> e623958d3


TS-3715: Add documentation and example for TS_HTTP_RESPONSE_CLIENT_HOOK


Project: http://git-wip-us.apache.org/repos/asf/trafficserver/repo
Commit: http://git-wip-us.apache.org/repos/asf/trafficserver/commit/e623958d
Tree: http://git-wip-us.apache.org/repos/asf/trafficserver/tree/e623958d
Diff: http://git-wip-us.apache.org/repos/asf/trafficserver/diff/e623958d

Branch: refs/heads/master
Commit: e623958d340c0d69faf0b6d9157db92d3bd53ea5
Parents: 738d9ed
Author: Alan M. Carroll <amc@apache.org>
Authored: Tue Jun 23 21:56:36 2015 -0500
Committer: Alan M. Carroll <amc@apache.org>
Committed: Wed Jun 24 09:11:29 2015 -0500

----------------------------------------------------------------------
 doc/sdk/http-transformation-plugin.en.rst |  18 +++
 example/Makefile.am                       |   2 +
 example/txn-data-sink/txn-data-sink.c     | 176 +++++++++++++++++++++++++
 3 files changed, 196 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/trafficserver/blob/e623958d/doc/sdk/http-transformation-plugin.en.rst
----------------------------------------------------------------------
diff --git a/doc/sdk/http-transformation-plugin.en.rst b/doc/sdk/http-transformation-plugin.en.rst
index ae6c0b5..c22caa7 100644
--- a/doc/sdk/http-transformation-plugin.en.rst
+++ b/doc/sdk/http-transformation-plugin.en.rst
@@ -163,3 +163,21 @@ structure. Since only a single writer is allowed, there is no
 corresponding ``TSIOBufferWriter`` data structure. The writer simply
 modifies the IO buffer directly.
 
+Transaction Data Sink
+~~~~~~~~~~~~~~~~~~~~~
+
+The hook `TS_HTTP_RESPONSE_CLIENT_HOOK` is a hook that supports a special type of transformation,
one with only input and no output.
+Although the transformation doesn't provide data back to Traffic Server it can do anything
else with the data, such as writing it
+to another output device or process. It must, however, consume all the data for the transaction.
There are two primary use cases.
+
+#. Tap in to the transaction to provide the data for external processing.
+#. Maintain the transaction.
+
+For the latter it is important to note that if all consumers of a transaction (primarily
the user agent) shut down the transaction is also
+terminated, including the connection to the origin server. A data sink transform, unlike
a standard transform, is considered to be a consumer
+and will keep the transaction and the origin server connection up. This is useful when the
transaction is in some way expensive and should
+run to completion even if the user agent disconnects. Examples would be a standard transform
that is expensive to initiate, or expensive
+origin server connections that should be :ts:cv:`shared <proxy.config.http.server_session_sharing.match>`.
+
+There is an `example plugin <https://github.com/apache/trafficserver/blob/master/example/txn-data-sink/txn-data-sink.c>`_
that demonstrates
+this used as a pure data sink to keep the transaction up regardless of whether the user agent
disconnects.
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/e623958d/example/Makefile.am
----------------------------------------------------------------------
diff --git a/example/Makefile.am b/example/Makefile.am
index 835f218..a15a1d2 100644
--- a/example/Makefile.am
+++ b/example/Makefile.am
@@ -45,6 +45,7 @@ plugins = \
   ssl-sni.la \
   ssl-sni-whitelist.la \
   thread-1.la \
+  txn-data-sink.la \
   version.la
 
 if BUILD_EXAMPLE_PLUGINS
@@ -74,6 +75,7 @@ remap_header_add_la_SOURCES = remap_header_add/remap_header_add.cc
 response_header_1_la_SOURCES = response-header-1/response-header-1.c
 server_transform_la_SOURCES = server-transform/server-transform.c
 thread_1_la_SOURCES = thread-1/thread-1.c
+txn_data_sink_la_SOURCES = txn-data-sink/txn-data-sink.c
 psi_la_SOURCES = thread-pool/psi.c thread-pool/thread.c
 version_la_SOURCES = version/version.c
 secure_link_la_SOURCES = secure-link/secure-link.c

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/e623958d/example/txn-data-sink/txn-data-sink.c
----------------------------------------------------------------------
diff --git a/example/txn-data-sink/txn-data-sink.c b/example/txn-data-sink/txn-data-sink.c
new file mode 100644
index 0000000..59b8101
--- /dev/null
+++ b/example/txn-data-sink/txn-data-sink.c
@@ -0,0 +1,176 @@
+/** @file
+
+  Example plugin for using TS_HTTP_RESPONSE_CLIENT_HOOK.
+
+  This example is used to maintain the transaction and thence the connection to the origin
server for the full
+  transaction, even if the user agent aborts. This is useful in cases where there are other
reasons to complete
+  the transaction besides providing data to the user agent. For example if the origin server
data should always
+  be cached (that is, force a background fill), or an expensive transform shouldn't be canceled
part way through,
+  or the origin server session is expensive to set up and it's cheaper to run this transaction
to completion to
+  be able to re-use the origin server connection than to set up a new connection.
+
+  @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 <stdio.h>
+#include <unistd.h>
+#include <ts/ts.h>
+
+// This gets the PRI*64 types
+# define __STDC_FORMAT_MACROS 1
+# include <inttypes.h>
+
+# define PLUGIN_NAME "txn-data-sink"
+# define PCP "[" PLUGIN_NAME "]"
+
+// Activate the data sink if this field is present in the request.
+static char const FLAG_MIME_FIELD[] = "TS-Agent";
+static size_t const FLAG_MIME_LEN = sizeof(FLAG_MIME_FIELD) - 1;
+
+typedef struct {
+  int64_t total;
+} SinkData;
+
+// This serves to consume all the data that arrives. If it's not consumed the tunnel gets
stalled
+// and the transaction doesn't complete. Other things could be done with the data, accessible
via
+// the IO buffer @a reader, such as writing it to disk to make an externally accessible copy.
+static int
+client_reader(TSCont contp, TSEvent event, void *edata)
+{
+  SinkData* data = TSContDataGet(contp);
+
+  // If we got closed, we're done.
+  if (TSVConnClosedGet(contp)) {
+    TSfree(data);
+    TSContDestroy(contp);
+    return 0;
+  }
+
+  TSVIO input_vio = TSVConnWriteVIOGet(contp);
+
+  if (!data) {
+    data = TSmalloc(sizeof(SinkData));
+    data->total = 0;
+    TSContDataSet(contp, data);
+  }
+
+  switch (event) {
+  case TS_EVENT_ERROR:
+    TSDebug(PLUGIN_NAME, "Error event");
+    TSContCall(TSVIOContGet(input_vio), TS_EVENT_ERROR, input_vio);
+    break;
+  case TS_EVENT_VCONN_READ_COMPLETE:
+    TSDebug(PLUGIN_NAME, "READ_COMPLETE");
+    break;
+  case TS_EVENT_VCONN_READ_READY:
+  case TS_EVENT_IMMEDIATE:
+    TSDebug(PLUGIN_NAME, "Data event - %s", event == TS_EVENT_IMMEDIATE ? "IMMEDIATE":"READ_READY");
+    // Look for data and if we find any, consume.
+    if (TSVIOBufferGet(input_vio)) {
+      TSIOBufferReader reader = TSVIOReaderGet(input_vio);
+      int64_t n = TSIOBufferReaderAvail(reader);
+      if (n > 0) {
+	TSIOBufferReaderConsume(reader, n);
+	TSVIONDoneSet(input_vio, TSVIONDoneGet(input_vio) + n);
+	data->total += n; // internal accounting so we can print the value at the end.
+	TSDebug(PLUGIN_NAME, "Consumed %" PRId64 " bytes", n);
+      }
+      if (TSVIONTodoGet(input_vio) > 0) {
+	// signal that we can accept more data.
+	TSContCall(TSVIOContGet(input_vio), TS_EVENT_VCONN_WRITE_READY, input_vio);
+      } else {
+	TSDebug(PLUGIN_NAME, "send WRITE_COMPLETE");
+	TSContCall(TSVIOContGet(input_vio), TS_EVENT_VCONN_WRITE_COMPLETE, input_vio);
+      }
+    } else { // buffer gone, we're done.
+      TSDebug(PLUGIN_NAME, "upstream buffer disappeared - %"PRId64" bytes", data->total);
+    }
+    break;
+  default:
+    TSDebug(PLUGIN_NAME, "unhandled event %d", event);
+    break;
+  }
+
+  return 0;
+}
+
+static int
+enable_agent_check(TSHttpTxn txnp)
+{
+  TSMBuffer req_buf;
+  TSMLoc req_loc;
+  int zret = 0;
+
+  // Enable the sink agent if the header is present.
+  if (TS_SUCCESS == TSHttpTxnClientReqGet(txnp, &req_buf, &req_loc)) {
+    TSMLoc range_field = TSMimeHdrFieldFind(req_buf, req_loc, FLAG_MIME_FIELD, FLAG_MIME_LEN);
+    zret = NULL == range_field ? 0 : 1;
+  }
+
+  return zret;
+}
+
+static void
+client_add(TSHttpTxn txnp)
+{
+  // We use @c TSTransformCreate because ATS sees this the same as a transform, but with
only
+  // the input side hooked up and not the output side. Data flows from ATS in to the reader
+  // but not back out to ATS. From the plugin point of view the input data is provided exactly
+  // as it is with a transform.
+  TSHttpTxnHookAdd(txnp, TS_HTTP_RESPONSE_CLIENT_HOOK, TSTransformCreate(client_reader, txnp));
+}
+
+static int
+main_hook(TSCont contp, TSEvent event, void *edata)
+{
+  TSHttpTxn txnp = (TSHttpTxn) edata;
+
+  TSDebug(PLUGIN_NAME, "Checking transaction");
+  switch (event) {
+  case TS_EVENT_HTTP_READ_RESPONSE_HDR:
+    if (enable_agent_check(txnp)) {
+      TSDebug(PLUGIN_NAME, "Adding data sink to transaction");
+      client_add(txnp);
+    }
+    break;
+  default:
+    break;
+  }
+
+  TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
+  return 0;
+}
+
+void
+TSPluginInit(int argc, const char *argv[])
+{
+  TSPluginRegistrationInfo info;
+
+  info.plugin_name = PLUGIN_NAME;
+  info.vendor_name = "Apache Software Foundation";
+  info.support_email = "dev@trafficserver.apache.org";
+
+  if (TSPluginRegister(&info) != TS_SUCCESS) {
+    TSError(PCP "Plugin registration failed.\n");
+    return;
+  }
+
+  TSHttpHookAdd(TS_HTTP_READ_RESPONSE_HDR_HOOK, TSContCreate(main_hook, NULL));
+  return;
+}


Mime
View raw message