Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds HRW state variables, 16 flags, 4 int8s and 1 int16 #12015

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
85 changes: 82 additions & 3 deletions doc/admin-guide/plugins/header_rewrite.en.rst
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,17 @@ with the word ``else``. The following example illustrates this::
The ``else`` clause is not a condition, and does not take any flags, it is
of course optional, but when specified must be followed by at least one operator.

State variables
---------------

A set of state variables are also available for both conditions and operators.
There are currently 16 flag states, 4 8-bit integers and one 16-bit integer states.
These states are all transactional, meaning they are usable and persistent across
all hooks.

The flag states are numbers 0-15, the 8-bit integer states are numbered 0-3, and the
one 16-bit integer state is number 0.

Conditions
----------

Expand Down Expand Up @@ -457,9 +468,10 @@ As a special matcher, the inbound IP addresses can be matched against a list of

cond %{INBOUND:REMOTE-ADDR} {192.168.201.0/24,10.0.0.0/8}

Note that this will not work against the non-IP based conditions, such as the protocol families,
and the configuration parser will error out. The format here is very specific, in particular no
white spaces are allowed between the ranges.
.. note::
This will not work against the non-IP based conditions, such as the protocol families,
and the configuration parser will error out. The format here is very specific, in particular no
white spaces are allowed between the ranges.

IP
~~
Expand Down Expand Up @@ -569,6 +581,36 @@ RANDOM

Generates a random integer from ``0`` up to (but not including) ``<n>``. Mathematically, ``[0,n)`` or ``0 <= r < n``.

STATE-FLAG
~~~~~~~~~~
::

cond %{STATE-FLAG:<n>}

This condition allows you to check the state of a flag. The ``<n>`` is the
number of the flag, from 0 to 15. This condition returns a ``true`` or
``false`` value, depending on the state of the flag.

STATE-INT8
~~~~~~~~~~
::

cond %{STATE-INT8:<n>}

This condition allows you to check the state of an 8-bit unsigned integer.
The ``<n>`` is the number of the integer, from 0 to 3. The current value of
the state integer is returned, and all 4 integers are initialized to 0.

STATE-INT16
~~~~~~~~~~~
::

cond %{STATE-INT16<:0>}

This condition allows you to check the state of an 16-bit unsigned integer.
There's only one such integer, and its value is returned from this condition.
As such, the index, ``0``, is optional here.

STATUS
~~~~~~
::
Expand Down Expand Up @@ -920,6 +962,38 @@ location automatically. This operator supports `String concatenations`_ for
``READ_RESPONSE_HDR_HOOK`` (the default when the plugin is global), the
``SEND_RESPONSE_HDR_HOOK``, or the ``REMAP_PSEUDO_HOOK``.

set-state-flag
~~~~~~~~~~~~~~
::

set-state-flag <n> <value>

This operator allows you to set the state of a flag. The ``<n>`` is the
number of the flag, from 0 to 15. The ``<value>`` is either ``true`` or ``false``,
turning the flag on or off.

set-state-int8
~~~~~~~~~~~~~~
::

set-state-int8 <n> <value>

This operator allows you to set the state of an 8-bit unsigned integer.
The ``<n>`` is the number of the integer, from 0 to 3. The ``<value>`` is an
unsigned 8-bit integer, 0-255. It can also be a condition, in which case the
value of the condition is used.

set-state-int16
~~~~~~~~~~~~~~~
::

set-state-int16 0 <value>

This operator allows you to set the state of a 16-bit unsigned integer.
The ``<value>`` is an unsigned 16-bit integer as well, 0-65535. It can also
be a condition, in which case thevalue of the condition is used. The index,
0, is always required eventhough there is only one 16-bit integer state variable.

set-status
~~~~~~~~~~
::
Expand Down Expand Up @@ -1438,6 +1512,11 @@ could each be tagged with a consistent name to make finding logs easier.::

(Then in :file:`logging.yaml`, log ``%<{@PropertyName}cqh>``)

.. note::
With the new ``state-flag``, ``state-int8`` and ``state-int16`` operators, you can
sometimes avoid setting internal ``@`` headers for passing information between hooks.
These internal state variables are much more efficient than setting and reading headers.

Remove Client Query Parameters
------------------------------------

Expand Down
160 changes: 139 additions & 21 deletions plugins/header_rewrite/conditions.cc
Original file line number Diff line number Diff line change
Expand Up @@ -137,10 +137,7 @@ ConditionRandom::eval(const Resources & /* res ATS_UNUSED */)
void
ConditionRandom::append_value(std::string &s, const Resources & /* res ATS_UNUSED */)
{
std::ostringstream oss;

oss << rand_r(&_seed) % _max;
s += oss.str();
s += std::to_string(rand_r(&_seed) % _max);
Dbg(pi_dbg_ctl, "Appending RANDOM(%d) to evaluation value -> %s", _max, s.c_str());
}

Expand Down Expand Up @@ -746,10 +743,7 @@ ConditionNow::set_qualifier(const std::string &q)
void
ConditionNow::append_value(std::string &s, const Resources & /* res ATS_UNUSED */)
{
std::ostringstream oss;

oss << get_now_qualified(_now_qual);
s += oss.str();
s += std::to_string(get_now_qualified(_now_qual));
Dbg(pi_dbg_ctl, "Appending NOW() to evaluation value -> %s", s.c_str());
}

Expand Down Expand Up @@ -822,14 +816,11 @@ ConditionGeo::set_qualifier(const std::string &q)
void
ConditionGeo::append_value(std::string &s, const Resources &res)
{
std::ostringstream oss;

if (is_int_type()) {
oss << get_geo_int(TSHttpTxnClientAddrGet(res.txnp));
s += std::to_string(get_geo_int(TSHttpTxnClientAddrGet(res.txnp)));
} else {
oss << get_geo_string(TSHttpTxnClientAddrGet(res.txnp));
s += get_geo_string(TSHttpTxnClientAddrGet(res.txnp));
}
s += oss.str();
Dbg(pi_dbg_ctl, "Appending GEO() to evaluation value -> %s", s.c_str());
}

Expand Down Expand Up @@ -899,10 +890,7 @@ ConditionId::append_value(std::string &s, const Resources &res ATS_UNUSED)
{
switch (_id_qual) {
case ID_QUAL_REQUEST: {
std::ostringstream oss;

oss << TSHttpTxnIdGet(res.txnp);
s += oss.str();
s += std::to_string(TSHttpTxnIdGet(res.txnp));
} break;
case ID_QUAL_PROCESS: {
TSUuid process = TSProcessUuidGet();
Expand Down Expand Up @@ -1428,16 +1416,146 @@ ConditionNextHop::eval(const Resources &res)

// ConditionHttpCntl: request header.
void
ConditionHttpCntl::initialize(Parser &p)
ConditionHttpCntl::set_qualifier(const std::string &q)
{
Condition::set_qualifier(q);

Dbg(pi_dbg_ctl, "\tParsing %%{HTTP-CNTL:%s}", q.c_str());
_http_cntl_qual = parse_http_cntl_qualifier(q);
}

void
ConditionHttpCntl::append_value(std::string &s, const Resources &res)
{
s += TSHttpTxnCntlGet(res.txnp, _http_cntl_qual) ? "TRUE" : "FALSE";
Dbg(pi_dbg_ctl, "Evaluating HTTP-CNTL(%s)", _qualifier.c_str());
}

bool
ConditionHttpCntl::eval(const Resources &res)
{
Dbg(pi_dbg_ctl, "Evaluating HTTP-CNTL()");
return TSHttpTxnCntlGet(res.txnp, _http_cntl_qual);
}

// ConditionStateFlag
void
ConditionStateFlag::set_qualifier(const std::string &q)
{
Condition::set_qualifier(q);

_flag_ix = strtol(q.c_str(), nullptr, 10);
if (_flag_ix < 0 || _flag_ix >= NUM_STATE_FLAGS) {
TSError("[%s] STATE-FLAG index out of range: %s", PLUGIN_NAME, q.c_str());
} else {
Dbg(pi_dbg_ctl, "\tParsing %%{STATE-FLAG:%s}", q.c_str());
_mask = 1ULL << _flag_ix;
}
}

void
ConditionStateFlag::append_value(std::string &s, const Resources &res)
{
s += eval(res) ? "TRUE" : "FALSE";
Dbg(pi_dbg_ctl, "Evaluating STATE-FLAG(%d)", _flag_ix);
}

bool
ConditionStateFlag::eval(const Resources &res)
{
auto data = reinterpret_cast<uint64_t>(TSUserArgGet(res.txnp, _txn_slot));

Dbg(pi_dbg_ctl, "Evaluating STATE-FLAG()");

return (data & _mask) == _mask;
}

// ConditionStateInt8
void
ConditionStateInt8::initialize(Parser &p)
{
Condition::initialize(p);
MatcherType *match = new MatcherType(_cond_op);

match->set(static_cast<uint8_t>(strtol(p.get_arg().c_str(), nullptr, 10)), mods());
_matcher = match;
}

void
ConditionHttpCntl::set_qualifier(const std::string &q)
ConditionStateInt8::set_qualifier(const std::string &q)
{
Condition::set_qualifier(q);

Dbg(pi_dbg_ctl, "\tParsing %%{HTTP-CNTL:%s}", q.c_str());
_http_cntl_qual = parse_http_cntl_qualifier(q);
_byte_ix = strtol(q.c_str(), nullptr, 10);
if (_byte_ix < 0 || _byte_ix >= NUM_STATE_INT8S) {
TSError("[%s] STATE-INT8 index out of range: %s", PLUGIN_NAME, q.c_str());
} else {
Dbg(pi_dbg_ctl, "\tParsing %%{STATE-INT8:%s}", q.c_str());
}
}

void
ConditionStateInt8::append_value(std::string &s, const Resources &res)
{
uint8_t data = _get_data(res);

s += std::to_string(data);

Dbg(pi_dbg_ctl, "Appending STATE-INT8(%d) to evaluation value -> %s", data, s.c_str());
}

bool
ConditionStateInt8::eval(const Resources &res)
{
uint8_t data = _get_data(res);

Dbg(pi_dbg_ctl, "Evaluating STATE-INT8()");

return static_cast<const MatcherType *>(_matcher)->test(data);
}

// ConditionStateInt16
void
ConditionStateInt16::initialize(Parser &p)
{
Condition::initialize(p);
MatcherType *match = new MatcherType(_cond_op);

match->set(static_cast<uint16_t>(strtol(p.get_arg().c_str(), nullptr, 10)), mods());
_matcher = match;
}

void
ConditionStateInt16::set_qualifier(const std::string &q)
{
Condition::set_qualifier(q);

if (!q.empty()) { // This qualifier is optional, but must be 0 if there
long ix = strtol(q.c_str(), nullptr, 10);

if (ix != 0) {
TSError("[%s] STATE-INT16 index out of range: %s", PLUGIN_NAME, q.c_str());
} else {
Dbg(pi_dbg_ctl, "\tParsing %%{STATE-INT16:%s}", q.c_str());
}
}
}

void
ConditionStateInt16::append_value(std::string &s, const Resources &res)
{
uint16_t data = _get_data(res);

s += std::to_string(data);
Dbg(pi_dbg_ctl, "Appending STATE-INT16(%d) to evaluation value -> %s", data, s.c_str());
}

bool
ConditionStateInt16::eval(const Resources &res)
{
uint16_t data = _get_data(res);

Dbg(pi_dbg_ctl, "Evaluating STATE-INT8()");

return static_cast<const MatcherType *>(_matcher)->test(data);
}
Loading