This is an automated email from the ASF dual-hosted git repository.
cmcfarlen pushed a commit to branch 10.1.x
in repository https://gitbox.apache.org/repos/asf/trafficserver.git
The following commit(s) were added to refs/heads/10.1.x by this push:
new 45bc022d18 header_rewrite: Add set-plugin-cntl (#12125)
45bc022d18 is described below
commit 45bc022d182ad3bc7dbfc9676bea731bec5b354c
Author: Masakazu Kitajo <[email protected]>
AuthorDate: Tue May 13 09:50:54 2025 -0600
header_rewrite: Add set-plugin-cntl (#12125)
* header_rewrite: Add set-plugin-cntl
* Fix compile errors on Dbg
(cherry picked from commit 0983b5e783a46dcea0e34405b1abc5e73f7f5934)
---
doc/admin-guide/plugins/header_rewrite.en.rst | 16 +++++++++
plugins/header_rewrite/conditions.cc | 17 ++++++---
plugins/header_rewrite/conditions.h | 8 ++++-
plugins/header_rewrite/factory.cc | 2 ++
plugins/header_rewrite/operators.cc | 51 +++++++++++++++++++++++++++
plugins/header_rewrite/operators.h | 30 ++++++++++++++++
plugins/header_rewrite/statement.cc | 22 ++++++++++++
plugins/header_rewrite/statement.h | 22 ++++++++++--
8 files changed, 160 insertions(+), 8 deletions(-)
diff --git a/doc/admin-guide/plugins/header_rewrite.en.rst
b/doc/admin-guide/plugins/header_rewrite.en.rst
index ba740060da..8875d1a812 100644
--- a/doc/admin-guide/plugins/header_rewrite.en.rst
+++ b/doc/admin-guide/plugins/header_rewrite.en.rst
@@ -1091,6 +1091,22 @@ TXN_DEBUG Enable transaction debugging (default:
``off``)
SKIP_REMAP Don't require a remap match for the transaction (default:
``off``)
================
====================================================================
+set-plugin-cntl
+~~~~~~~~~~~~~~~
+::
+
+ set-plugin-cntl <controller> <value>
+
+This operator lets you control the fundamental behavior of this plugin for a
particular transaction.
+The available controllers are:
+
+================== =====================
=============================================================================================
+Controller Operators/Conditions Description
+================== =====================
=============================================================================================
+TIMEZONE ``NOW`` If ``GMT`` is passed, the operators
and conditions use GMT regardles of the timezone setting
+ on your system. The default value is
``LOCAL``.
+================== =====================
=============================================================================================
+
Operator Flags
--------------
diff --git a/plugins/header_rewrite/conditions.cc
b/plugins/header_rewrite/conditions.cc
index cae6e911ab..6542771200 100644
--- a/plugins/header_rewrite/conditions.cc
+++ b/plugins/header_rewrite/conditions.cc
@@ -659,7 +659,7 @@ ConditionTransactCount::append_value(std::string &s,
Resources const &res)
// Time related functionality for statements. We return an int64_t here, to
assure that
// gettimeofday() / Epoch does not lose bits.
int64_t
-ConditionNow::get_now_qualified(NowQualifiers qual) const
+ConditionNow::get_now_qualified(NowQualifiers qual, const Resources
&resources) const
{
time_t now;
@@ -670,7 +670,14 @@ ConditionNow::get_now_qualified(NowQualifiers qual) const
} else {
struct tm res;
- localtime_r(&now, &res);
+ PrivateSlotData private_data;
+ private_data.raw = reinterpret_cast<uint64_t>(TSUserArgGet(resources.txnp,
_txn_private_slot));
+ if (private_data.timezone == 1) {
+ gmtime_r(&now, &res);
+ } else {
+ localtime_r(&now, &res);
+ }
+
switch (qual) {
case NOW_QUAL_YEAR:
return static_cast<int64_t>(res.tm_year + 1900); // This makes more sense
@@ -741,16 +748,16 @@ ConditionNow::set_qualifier(const std::string &q)
}
void
-ConditionNow::append_value(std::string &s, const Resources & /* res ATS_UNUSED
*/)
+ConditionNow::append_value(std::string &s, const Resources &res)
{
- s += std::to_string(get_now_qualified(_now_qual));
+ s += std::to_string(get_now_qualified(_now_qual, res));
Dbg(pi_dbg_ctl, "Appending NOW() to evaluation value -> %s", s.c_str());
}
bool
ConditionNow::eval(const Resources &res)
{
- int64_t now = get_now_qualified(_now_qual);
+ int64_t now = get_now_qualified(_now_qual, res);
Dbg(pi_dbg_ctl, "Evaluating NOW()");
return static_cast<const MatcherType *>(_matcher)->test(now, res);
diff --git a/plugins/header_rewrite/conditions.h
b/plugins/header_rewrite/conditions.h
index 18912f4c1c..863a009470 100644
--- a/plugins/header_rewrite/conditions.h
+++ b/plugins/header_rewrite/conditions.h
@@ -404,8 +404,14 @@ public:
protected:
bool eval(const Resources &res) override;
+ bool
+ need_txn_private_slot() const override
+ {
+ return true;
+ }
+
private:
- int64_t get_now_qualified(NowQualifiers qual) const;
+ int64_t get_now_qualified(NowQualifiers qual, const Resources &res)
const;
NowQualifiers _now_qual = NOW_QUAL_EPOCH;
};
diff --git a/plugins/header_rewrite/factory.cc
b/plugins/header_rewrite/factory.cc
index 2e28404377..f06029d24e 100644
--- a/plugins/header_rewrite/factory.cc
+++ b/plugins/header_rewrite/factory.cc
@@ -75,6 +75,8 @@ operator_factory(const std::string &op)
o = new OperatorSetBody();
} else if (op == "set-http-cntl") {
o = new OperatorSetHttpCntl();
+ } else if (op == "set-plugin-cntl") {
+ o = new OperatorSetPluginCntl();
} else if (op == "run-plugin") {
o = new OperatorRunPlugin();
} else if (op == "set-body-from") {
diff --git a/plugins/header_rewrite/operators.cc
b/plugins/header_rewrite/operators.cc
index 28c1af6219..b9c55ad53c 100644
--- a/plugins/header_rewrite/operators.cc
+++ b/plugins/header_rewrite/operators.cc
@@ -1193,6 +1193,57 @@ OperatorSetHttpCntl::exec(const Resources &res) const
return true;
}
+void
+OperatorSetPluginCntl::initialize(Parser &p)
+{
+ Operator::initialize(p);
+ const std::string &name = p.get_arg();
+ const std::string &value = p.get_value();
+
+ if (name == "TIMEZONE") {
+ _name = PluginCtrl::TIMEZONE;
+ if (value == "LOCAL") {
+ _value = TIMEZONE_LOCAL;
+ } else if (value == "GMT") {
+ _value = TIMEZONE_GMT;
+ } else {
+ TSError("[%s] Unknown value for TIMZEONE control: %s", PLUGIN_NAME,
value.c_str());
+ }
+ }
+}
+
+// This operator should be allowed everywhere
+void
+OperatorSetPluginCntl::initialize_hooks()
+{
+ add_allowed_hook(TS_HTTP_READ_REQUEST_HDR_HOOK);
+ add_allowed_hook(TS_HTTP_READ_RESPONSE_HDR_HOOK);
+ add_allowed_hook(TS_HTTP_SEND_RESPONSE_HDR_HOOK);
+ add_allowed_hook(TS_REMAP_PSEUDO_HOOK);
+ add_allowed_hook(TS_HTTP_PRE_REMAP_HOOK);
+ add_allowed_hook(TS_HTTP_SEND_REQUEST_HDR_HOOK);
+ add_allowed_hook(TS_HTTP_TXN_CLOSE_HOOK);
+ add_allowed_hook(TS_HTTP_TXN_START_HOOK);
+}
+
+bool
+OperatorSetPluginCntl::exec(const Resources &res) const
+{
+ PrivateSlotData private_data;
+ private_data.raw = reinterpret_cast<uint64_t>(TSUserArgGet(res.txnp,
_txn_private_slot));
+
+ switch (_name) {
+ case PluginCtrl::TIMEZONE:
+ private_data.timezone = _value;
+ break;
+ }
+
+ Dbg(pi_dbg_ctl, " Setting plugin control %d to %d",
static_cast<int>(_name), _value);
+ TSUserArgSet(res.txnp, _txn_private_slot, reinterpret_cast<void
*>(private_data.raw));
+
+ return true;
+}
+
void
OperatorRunPlugin::initialize(Parser &p)
{
diff --git a/plugins/header_rewrite/operators.h
b/plugins/header_rewrite/operators.h
index 12d003c3cf..2d273b19b9 100644
--- a/plugins/header_rewrite/operators.h
+++ b/plugins/header_rewrite/operators.h
@@ -453,6 +453,36 @@ private:
TSHttpCntlType _cntl_qual;
};
+class OperatorSetPluginCntl : public Operator
+{
+public:
+ OperatorSetPluginCntl() { Dbg(dbg_ctl, "Calling CTOR for
OperatorSetPluginCntl"); }
+
+ // noncopyable
+ OperatorSetPluginCntl(const OperatorSetPluginCntl &) = delete;
+ void operator=(const OperatorSetPluginCntl &) = delete;
+
+ void initialize(Parser &p) override;
+
+ enum class PluginCtrl {
+ TIMEZONE,
+ };
+
+protected:
+ void initialize_hooks() override;
+ bool exec(const Resources &res) const override;
+
+ bool
+ need_txn_private_slot() const override
+ {
+ return true;
+ }
+
+private:
+ PluginCtrl _name;
+ int _value;
+};
+
class RemapPluginInst; // Opaque to the HRW operator, but needed in the
implementation.
class OperatorRunPlugin : public Operator
diff --git a/plugins/header_rewrite/statement.cc
b/plugins/header_rewrite/statement.cc
index f9d9fc59b9..979eb8f146 100644
--- a/plugins/header_rewrite/statement.cc
+++ b/plugins/header_rewrite/statement.cc
@@ -95,6 +95,28 @@ Statement::acquire_txn_slot()
_txn_slot = txn_slot_index;
}
+void
+Statement::acquire_txn_private_slot()
+{
+ // Don't do anything if we don't need it
+ if (!need_txn_private_slot() || _txn_private_slot >= 0) {
+ return;
+ }
+
+ // Only call the index reservation once per plugin load
+ static int txn_private_slot_index = []() -> int {
+ int index = -1;
+
+ if (TS_ERROR == TSUserArgIndexReserve(TS_USER_ARGS_TXN, PLUGIN_NAME, "HRW
txn private variables", &index)) {
+ TSError("[%s] failed to reserve user arg index", PLUGIN_NAME);
+ return -1; // Fallback value
+ }
+ return index;
+ }();
+
+ _txn_private_slot = txn_private_slot_index;
+}
+
// Parse NextHop qualifiers
NextHopQualifiers
Statement::parse_next_hop_qualifier(const std::string &q) const
diff --git a/plugins/header_rewrite/statement.h
b/plugins/header_rewrite/statement.h
index 92954749af..bf1020451b 100644
--- a/plugins/header_rewrite/statement.h
+++ b/plugins/header_rewrite/statement.h
@@ -155,6 +155,7 @@ public:
TSReleaseAssert(_initialized == false);
initialize_hooks();
acquire_txn_slot();
+ acquire_txn_private_slot();
_initialized = true;
}
@@ -184,14 +185,31 @@ protected:
return false;
}
- Statement *_next = nullptr; // Linked list
- int _txn_slot = -1;
+ virtual bool
+ need_txn_private_slot() const
+ {
+ return false;
+ }
+
+ Statement *_next = nullptr; // Linked list
+ int _txn_slot = -1;
+ int _txn_private_slot = -1;
private:
void acquire_txn_slot();
+ void acquire_txn_private_slot();
ResourceIDs _rsrc = RSRC_NONE;
TSHttpHookID _hook = TS_HTTP_READ_RESPONSE_HDR_HOOK;
std::vector<TSHttpHookID> _allowed_hooks;
bool _initialized = false;
};
+
+union PrivateSlotData {
+ uint64_t raw;
+ struct {
+ uint64_t timezone : 1; // TIMEZONE_LOCAL, or TIMEZONE_GMT
+ };
+};
+
+enum { TIMEZONE_LOCAL, TIMEZONE_GMT };