Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions doc/admin-guide/plugins/header_rewrite.en.rst
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,24 @@ Refer to `Requests vs. Responses`_ for more information on determining the
context in which the transaction's URL is evaluated. The ``<part>`` may be
specified according to the options documented in `URL Parts`_.

SSN-TXN-COUNT
~~~~~~~~~~~~~
::

cond %{SSN-TXN-COUNT} <operand>

Returns the number of transactions between the Traffic Server proxy and the origin server from a single session.
Any value greater than zero indicates connection reuse.

TCP-INFO
~~~~~~~~
::

cond %{<name>}
add-header @PropertyName "%{TCP-INFO}"

This operation records TCP Info struct field values as an Internal remap as well as global header at the event hook specified by the condition. Supported hook conditions include TXN_START_HOOK, SEND_RESPONSE_HEADER_HOOK and TXN_CLOSE_HOOK in the Global plugin and REMAP_PSEUDO_HOOK, SEND_RESPONSE_HEADER_HOOK and TXN_CLOSE_HOOK in the Remap plugin. Conditions supported as request headers include TXN_START_HOOK and REMAP_PSEUDO_HOOK. The other conditions are supported as response headers. TCP Info fields currently recorded include rtt, rto, snd_cwnd and all_retrans. This operation is not supported on transactions originated within Traffic Server (for e.g using the |TS| :c:func:`TSHttpTxnIsInternal`)

Condition Operands
------------------

Expand Down Expand Up @@ -995,6 +1013,15 @@ cache updates may have been performed. This hook context provides a means to
modify aspects of the response sent to a client, while still caching the
original versions of those attributes delivered by the origin server.

TXN_START_HOOK
~~~~~~~~~~~~~~
Rulesets are evaluated when |TS| receives a request and accepts it. This hook context indicates that a HTTP transaction is initiated and therefore, can only be enabled as a global plugin.

TXN_CLOSE_HOOK
~~~~~~~~~~~~~~

Rulesets are evaluated when |TS| completes a transaction, i.e., after a response has been sent to the client. Therefore, header modifications at this hook condition only makes sense for internal headers.

Affected Conditions
-------------------

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
.. 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:: ../../../common.defs

.. default-domain:: c

TSHttpTxnServerSsnTransactionCount
**********************************

Synopsis
========

.. code-block:: cpp

#include <ts/ts.h>

.. function:: int TSHttpTxnServerSsnTransactionCount(TSHttpTxn txnp)

Description
===========

Gets the number of transactions between the Traffic Server proxy and the origin server from a single session.
Any value greater than zero indicates connection reuse.
9 changes: 9 additions & 0 deletions include/ts/ts.h
Original file line number Diff line number Diff line change
Expand Up @@ -1261,6 +1261,15 @@ tsapi TSReturnCode TSHttpTxnCachedRespGet(TSHttpTxn txnp, TSMBuffer *bufp, TSMLo

tsapi TSReturnCode TSHttpTxnPristineUrlGet(TSHttpTxn txnp, TSMBuffer *bufp, TSMLoc *url_loc);

/**
* @brief Gets the number of transactions between the Traffic Server proxy and the origin server from a single session.
* Any value greater than zero indicates connection reuse.
*
* @param txnp The transaction
* @return int The number of transactions between the Traffic Server proxy and the origin server from a single session
*/
tsapi int TSHttpTxnServerSsnTransactionCount(TSHttpTxn txnp);

/** Get the effective URL for the transaction.
The effective URL is the URL taking in to account both the explicit
URL in the request and the HOST field.
Expand Down
115 changes: 115 additions & 0 deletions plugins/header_rewrite/conditions.cc
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,17 @@
#include "expander.h"
#include "lulu.h"

// This is a bit of a hack, to get the more linux specific tcp_info struct ...
#if HAVE_STRUCT_LINUX_TCP_INFO
#ifndef _LINUX_TCP_H
#define _LINUX_TCP_H
#endif
#elif HAVE_NETINET_IN_H
#ifndef _NETINET_TCP_H
#define _NETINET_TCP_H
#endif
#endif

// ConditionStatus
void
ConditionStatus::initialize(Parser &p)
Expand Down Expand Up @@ -1432,3 +1443,107 @@ ConditionExpandableString::append_value(std::string &s, const Resources &res)
s += ve.expand(res);
TSDebug(PLUGIN_NAME, "Appending to evaluation value -> %s", s.c_str());
}
// ConditionSessionTransactCount
void
ConditionSessionTransactCount::initialize(Parser &p)
{
Condition::initialize(p);
MatcherType *match = new MatcherType(_cond_op);
std::string const &arg = p.get_arg();

match->set(strtol(arg.c_str(), nullptr, 10));
_matcher = match;
}

bool
ConditionSessionTransactCount::eval(const Resources &res)
{
int const val = TSHttpTxnServerSsnTransactionCount(res.txnp);

TSDebug(PLUGIN_NAME, "Evaluating SSN-TXN-COUNT()");
return static_cast<MatcherType *>(_matcher)->test(val);
}

void
ConditionSessionTransactCount::append_value(std::string &s, Resources const &res)
{
char value[32]; // enough for UINT64_MAX
int const count = TSHttpTxnServerSsnTransactionCount(res.txnp);
int const length = ink_fast_itoa(count, value, sizeof(value));

if (length > 0) {
TSDebug(PLUGIN_NAME, "Appending SSN-TXN-COUNT %s to evaluation value %.*s", _qualifier.c_str(), length, value);
s.append(value, length);
}
}

void
ConditionTcpInfo::initialize(Parser &p)
{
Condition::initialize(p);
TSDebug(PLUGIN_NAME, "Initializing TCP Info");
MatcherType *match = new MatcherType(_cond_op);
std::string const &arg = p.get_arg();

match->set(strtol(arg.c_str(), nullptr, 10));
_matcher = match;
}

void
ConditionTcpInfo::initialize_hooks()
{
add_allowed_hook(TS_HTTP_TXN_START_HOOK);
add_allowed_hook(TS_HTTP_TXN_CLOSE_HOOK);
add_allowed_hook(TS_HTTP_SEND_RESPONSE_HDR_HOOK);
}

bool
ConditionTcpInfo::eval(const Resources &res)
{
std::string s;

append_value(s, res);
bool rval = static_cast<const Matchers<std::string> *>(_matcher)->test(s);

TSDebug(PLUGIN_NAME, "Evaluating TCP-Info: %s - rval: %d", s.c_str(), rval);

return rval;
}

void
ConditionTcpInfo::append_value(std::string &s, Resources const &res)
{
#if defined(TCP_INFO) && defined(HAVE_STRUCT_TCP_INFO)
if (TSHttpTxnIsInternal(res.txnp)) {
TSDebug(PLUGIN_NAME, "No TCP-INFO available for internal transactions");
return;
}
TSReturnCode tsSsn;
int fd;
struct tcp_info info;
socklen_t tcp_info_len = sizeof(info);
tsSsn = TSHttpTxnClientFdGet(res.txnp, &fd);
if (tsSsn != TS_SUCCESS || fd <= 0) {
TSDebug(PLUGIN_NAME, "error getting the client socket fd from ssn");
}
if (getsockopt(fd, IPPROTO_TCP, TCP_INFO, &info, &tcp_info_len) != 0) {
TSDebug(PLUGIN_NAME, "getsockopt(%d, TCP_INFO) failed: %s", fd, strerror(errno));
}

if (tsSsn == TS_SUCCESS) {
if (tcp_info_len > 0) {
char buf[12 * 4 + 9]; // 4x uint32's + 4x "; " + '\0'
#if !defined(freebsd) || defined(__GLIBC__)
snprintf(buf, sizeof(buf), "%" PRIu32 ";%" PRIu32 ";%" PRIu32 ";%" PRIu32 "", info.tcpi_rtt, info.tcpi_rto,
info.tcpi_snd_cwnd, info.tcpi_retrans);
#else
snprintf(buf, sizeof(buf), "%" PRIu32 ";%" PRIu32 ";%" PRIu32 ";%" PRIu32 "", info.tcpi_rtt, info.tcpi_rto,
info.tcpi_snd_cwnd, info.__tcpi_retrans);
#endif
s += buf;
}
}
#else
s += "-";
#endif
}
39 changes: 39 additions & 0 deletions plugins/header_rewrite/conditions.h
Original file line number Diff line number Diff line change
Expand Up @@ -575,3 +575,42 @@ class ConditionExpandableString : public Condition
std::string _value;
DISALLOW_COPY_AND_ASSIGN(ConditionExpandableString);
};

// Single Session Transaction Count
class ConditionSessionTransactCount : public Condition
{
typedef Matchers<int> MatcherType;

public:
ConditionSessionTransactCount() { TSDebug(PLUGIN_NAME_DBG, "ConditionSessionTransactCount()"); }

// noncopyable
ConditionSessionTransactCount(const ConditionSessionTransactCount &) = delete;
void operator=(const ConditionSessionTransactCount &) = delete;

void initialize(Parser &p) override;
void append_value(std::string &s, const Resources &res) override;

protected:
bool eval(const Resources &res) override;
};

// Tcp Info
class ConditionTcpInfo : public Condition
{
typedef Matchers<int> MatcherType;

public:
ConditionTcpInfo() { TSDebug(PLUGIN_NAME_DBG, "Calling CTOR for ConditionTcpInfo"); }

// noncopyable
ConditionTcpInfo(const ConditionTcpInfo &) = delete;
void operator=(const ConditionTcpInfo &) = delete;

void initialize(Parser &p) override;
void append_value(std::string &s, const Resources &res) override;

protected:
bool eval(const Resources &res) override;
void initialize_hooks() override; // Return status only valid in certain hooks
};
4 changes: 4 additions & 0 deletions plugins/header_rewrite/factory.cc
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,10 @@ condition_factory(const std::string &cond)
c = new ConditionCidr();
} else if (c_name == "INBOUND") {
c = new ConditionInbound();
} else if (c_name == "SSN-TXN-COUNT") {
c = new ConditionSessionTransactCount();
} else if (c_name == "TCP-INFO") {
c = new ConditionTcpInfo();
} else {
TSError("[%s] Unknown condition %s", PLUGIN_NAME, c_name.c_str());
return nullptr;
Expand Down
6 changes: 6 additions & 0 deletions plugins/header_rewrite/header_rewrite.cc
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,12 @@ cont_rewrite_headers(TSCont contp, TSEvent event, void *edata)
case TS_EVENT_HTTP_SEND_RESPONSE_HDR:
hook = TS_HTTP_SEND_RESPONSE_HDR_HOOK;
break;
case TS_EVENT_HTTP_TXN_START:
hook = TS_HTTP_TXN_START_HOOK;
break;
case TS_EVENT_HTTP_TXN_CLOSE:
hook = TS_HTTP_TXN_CLOSE_HOOK;
break;
default:
TSError("[%s] unknown event for this plugin", PLUGIN_NAME);
TSDebug(PLUGIN_NAME, "unknown event for this plugin");
Expand Down
8 changes: 8 additions & 0 deletions plugins/header_rewrite/parser.cc
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,14 @@ Parser::cond_is_hook(TSHttpHookID &hook) const
hook = TS_REMAP_PSEUDO_HOOK;
return true;
}
if ("TXN_START_HOOK" == _op) {
hook = TS_HTTP_TXN_START_HOOK;
return true;
}
if ("TXN_CLOSE_HOOK" == _op) {
hook = TS_HTTP_TXN_CLOSE_HOOK;
return true;
}

return false;
}
Expand Down
18 changes: 18 additions & 0 deletions plugins/header_rewrite/resources.cc
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,24 @@ Resources::gather(const ResourceIDs ids, TSHttpHookID hook)
}
break;

case TS_HTTP_TXN_START_HOOK:
// Get TCP Info at transaction start
if (client_bufp && client_hdr_loc) {
TSDebug(PLUGIN_NAME, "\tAdding TXN client request header buffers for TXN Start instance");
bufp = client_bufp;
hdr_loc = client_hdr_loc;
}
break;

case TS_HTTP_TXN_CLOSE_HOOK:
// Get TCP Info at transaction close
TSDebug(PLUGIN_NAME, "\tAdding TXN close buffers");
if (TSHttpTxnClientRespGet(txnp, &bufp, &hdr_loc) != TS_SUCCESS) {
TSDebug(PLUGIN_NAME, "could not gather bufp/hdr_loc for request");
return;
}
break;

default:
break;
}
Expand Down
2 changes: 2 additions & 0 deletions plugins/header_rewrite/statement.cc
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ Statement::initialize_hooks()
add_allowed_hook(TS_HTTP_SEND_REQUEST_HDR_HOOK);
add_allowed_hook(TS_HTTP_SEND_RESPONSE_HDR_HOOK);
add_allowed_hook(TS_REMAP_PSEUDO_HOOK);
add_allowed_hook(TS_HTTP_TXN_START_HOOK);
add_allowed_hook(TS_HTTP_TXN_CLOSE_HOOK);
}

// Parse URL qualifiers, this one is special since it's used in a few places.
Expand Down
10 changes: 10 additions & 0 deletions src/traffic_server/InkAPI.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4764,6 +4764,16 @@ TSHttpTxnPristineUrlGet(TSHttpTxn txnp, TSMBuffer *bufp, TSMLoc *url_loc)
return TS_ERROR;
}

int
TSHttpTxnServerSsnTransactionCount(TSHttpTxn txnp)
{
sdk_assert(sdk_sanity_check_txn(txnp) == TS_SUCCESS);

HttpSM *sm = (HttpSM *)txnp;
// Any value greater than zero indicates connection reuse.
return sm->server_transact_count;
}

// Shortcut to just get the URL.
// The caller is responsible to free memory that is allocated for the string
// that is returned.
Expand Down
Loading