This is an automated email from the ASF dual-hosted git repository.
zwoop pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficserver.git
The following commit(s) were added to refs/heads/master by this push:
new 938b4913d5 HRW: Adds %{INBOUND:SERVER-CERT} and
%{INBOUND:CLIENT-CERT} conds (#12363)
938b4913d5 is described below
commit 938b4913d5b76509306553016421777c1fddbf5e
Author: Leif Hedstrom <[email protected]>
AuthorDate: Thu Aug 21 16:12:06 2025 -0600
HRW: Adds %{INBOUND:SERVER-CERT} and %{INBOUND:CLIENT-CERT} conds (#12363)
* Adds a %{CERT} and %{CLIENT-CERT} cond
* Moved certificates to INBOUND: condition
---
doc/admin-guide/plugins/header_rewrite.en.rst | 40 ++++-
include/cripts/Transaction.hpp | 2 -
plugins/header_rewrite/CMakeLists.txt | 5 +
plugins/header_rewrite/conditions.cc | 223 ++++++++++++++++++++------
plugins/header_rewrite/conditions.h | 9 +-
plugins/header_rewrite/header_rewrite.cc | 28 ++--
plugins/header_rewrite/operators.cc | 111 ++++++-------
plugins/header_rewrite/resources.cc | 49 +++++-
plugins/header_rewrite/resources.h | 67 +++++---
plugins/header_rewrite/statement.h | 26 ++-
plugins/header_rewrite/value.cc | 8 +-
plugins/header_rewrite/value.h | 4 +-
12 files changed, 416 insertions(+), 156 deletions(-)
diff --git a/doc/admin-guide/plugins/header_rewrite.en.rst
b/doc/admin-guide/plugins/header_rewrite.en.rst
index ddfc48397f..7e3760135a 100644
--- a/doc/admin-guide/plugins/header_rewrite.en.rst
+++ b/doc/admin-guide/plugins/header_rewrite.en.rst
@@ -483,7 +483,7 @@ INBOUND
~~~~~~~
::
- cond %{INBOUND:TLS} /./
+ cond %{INBOUND:TLS} ="" [NOT]
This condition provides access to information about the inbound (client, user
agent) connection to ATS.
The data that can be checked is ::
@@ -511,7 +511,7 @@ will be true for *non*-TLS connections because it will be
true when ``%{INBOUND:
string. This happens because the default matching is equality and the default
value the empty
string. Therefore the condition is treated as if it were ::
- cond %{INBOUND:TLS}=""
+ cond %{INBOUND:TLS} =""
which is true when the connection is not TLS. The arguments ``H2``, ``IPV4``,
and ``IPV6`` work the
same way.
@@ -526,6 +526,42 @@ As a special matcher, the inbound IP addresses can be
matched against a list of
and the configuration parser will error out. The format here is very
specific, in particular no
white spaces are allowed between the ranges.
+If |ATS| is built with :ref:`Cripts <developer-guide-cripts>` support, a
number of additional
+qualifiers are available exclusively on TLS sessions, for X509 certificate
introspection.
+The client certificate (for mutual TLS) is accessed with qualifier prefix of
``CLIENT-CERT:``
+and the server certificate with a prefix qualifier of ``SERVER-CERT:``. The
X509 naming of the
+specific fields are the same for the two certificates::
+
+ PEM The PEM-encoded certificate, as a string.
+ SIG The signature of the certificate.
+ SUBJECT The subject of the certificate.
+ ISSUER The issuer of the certificate.
+ SERIAL The serial number of the certificate.
+ NOT_BEFORE The date and time when the certificate becomes valid.
+ NOT_AFTER The date and time when the certificate expires.
+ VERSION The version of the certificate.
+ SAN:DNS The Subject Alternative Name (SAN) DNS entries.
+ SAN:IP The Subject Alternative Name (SAN) IP addresses.
+ SAN:EMAIL The Subject Alternative Name (SAN) email addresses.
+ SAN:URI The Subject Alternative Name (SAN) URIs.
+
+These conditions and qualifiers can be used in conditions of course, but more
importantly,
+are also very useful when adding or modifying headers. For example, you can
add some
+client certificate and server subject to the response headers, so that the
client can see it
+as part of the response ::
+
+ cond %{SEND_RESPONSE_HDR_HOOK} [AND]
+ cond %{INBOUND:TLS} ="" [NOT]
+ set-header X-Client-Cert "%{INBOUND:CLIENT-CERT:PEM}"
+ set-header X-Client-Cert-Subject "%{INBOUND:CLIENT-CERT:SUBJECT}"
+ set-header X-Client-Cert-Issuer "%{INBOUND:CLIENT-CERT:ISSUER}"
+ set-header X-Server-Cert-Subject "%{INBOUND:SERVER-CERT:SUBJECT}""
+
+The ``SAN:`` fields will return a semicolon-separated list of the respective
+values, there can be zero, one or many of each SAN type. Example ::
+
+ cond %{CLIENT-CERT:SAN:DNS} /example\.com/
+
IP
~~
::
diff --git a/include/cripts/Transaction.hpp b/include/cripts/Transaction.hpp
index 29f9b5cc36..f937185e14 100644
--- a/include/cripts/Transaction.hpp
+++ b/include/cripts/Transaction.hpp
@@ -17,8 +17,6 @@
*/
#pragma once
-#include <fmt/core.h>
-
#include "ts/ts.h"
#include "cripts/Error.hpp"
diff --git a/plugins/header_rewrite/CMakeLists.txt
b/plugins/header_rewrite/CMakeLists.txt
index 0837b2d2d8..b46e869505 100644
--- a/plugins/header_rewrite/CMakeLists.txt
+++ b/plugins/header_rewrite/CMakeLists.txt
@@ -42,6 +42,11 @@ target_link_libraries(
PUBLIC libswoc::libswoc
)
+if(ENABLE_CRIPTS)
+ target_link_libraries(header_rewrite PRIVATE ts::cripts)
+ target_compile_definitions(header_rewrite PRIVATE TS_HAS_CRIPTS=1)
+endif()
+
if(maxminddb_FOUND)
target_compile_definitions(header_rewrite PUBLIC TS_USE_HRW_MAXMINDDB=1)
target_sources(header_rewrite PRIVATE conditions_geo_maxmind.cc)
diff --git a/plugins/header_rewrite/conditions.cc
b/plugins/header_rewrite/conditions.cc
index 8a5a4185c4..74ecdc215d 100644
--- a/plugins/header_rewrite/conditions.cc
+++ b/plugins/header_rewrite/conditions.cc
@@ -36,6 +36,10 @@
static const sockaddr *getClientAddr(TSHttpTxn txnp, int txn_private_slot);
+#if TS_HAS_CRIPTS
+#include "cripts/Certs.hpp"
+#endif
+
// ConditionStatus
void
ConditionStatus::initialize(Parser &p)
@@ -287,7 +291,7 @@ ConditionUrl::append_value(std::string &s, const Resources
&res)
if (_type == CLIENT) {
// CLIENT always uses the pristine URL
Dbg(pi_dbg_ctl, " Using the pristine url");
- if (TSHttpTxnPristineUrlGet(res.txnp, &bufp, &url) != TS_SUCCESS) {
+ if (TSHttpTxnPristineUrlGet(res.state.txnp, &bufp, &url) != TS_SUCCESS) {
TSError("[%s] Error getting the pristine URL", PLUGIN_NAME);
return;
}
@@ -510,7 +514,7 @@ ConditionCookie::eval(const Resources &res)
bool
ConditionInternalTxn::eval(const Resources &res)
{
- bool ret = (0 != TSHttpTxnIsInternal(res.txnp));
+ bool ret = (0 != TSHttpTxnIsInternal(res.state.txnp));
Dbg(pi_dbg_ctl, "Evaluating INTERNAL-TRANSACTION() -> %d", ret);
return ret;
@@ -562,16 +566,16 @@ ConditionIp::eval(const Resources &res)
switch (_ip_qual) {
case IP_QUAL_CLIENT:
- addr = getClientAddr(res.txnp, _txn_private_slot);
+ addr = getClientAddr(res.state.txnp, _txn_private_slot);
break;
case IP_QUAL_INBOUND:
- addr = TSHttpTxnIncomingAddrGet(res.txnp);
+ addr = TSHttpTxnIncomingAddrGet(res.state.txnp);
break;
case IP_QUAL_SERVER:
- addr = TSHttpTxnServerAddrGet(res.txnp);
+ addr = TSHttpTxnServerAddrGet(res.state.txnp);
break;
case IP_QUAL_OUTBOUND:
- addr = TSHttpTxnOutgoingAddrGet(res.txnp);
+ addr = TSHttpTxnOutgoingAddrGet(res.state.txnp);
break;
}
@@ -600,17 +604,17 @@ ConditionIp::append_value(std::string &s, const Resources
&res)
switch (_ip_qual) {
case IP_QUAL_CLIENT:
- ip_set = (nullptr != getIP(getClientAddr(res.txnp, _txn_private_slot),
ip));
+ ip_set = (nullptr != getIP(getClientAddr(res.state.txnp,
_txn_private_slot), ip));
break;
case IP_QUAL_INBOUND:
- ip_set = (nullptr != getIP(TSHttpTxnIncomingAddrGet(res.txnp), ip));
+ ip_set = (nullptr != getIP(TSHttpTxnIncomingAddrGet(res.state.txnp), ip));
break;
case IP_QUAL_SERVER:
- ip_set = (nullptr != getIP(TSHttpTxnServerAddrGet(res.txnp), ip));
+ ip_set = (nullptr != getIP(TSHttpTxnServerAddrGet(res.state.txnp), ip));
break;
case IP_QUAL_OUTBOUND:
Dbg(pi_dbg_ctl, "Requesting output ip");
- ip_set = (nullptr != getIP(TSHttpTxnOutgoingAddrGet(res.txnp), ip));
+ ip_set = (nullptr != getIP(TSHttpTxnOutgoingAddrGet(res.state.txnp), ip));
break;
}
@@ -633,10 +637,8 @@ ConditionTransactCount::initialize(Parser &p)
bool
ConditionTransactCount::eval(const Resources &res)
{
- TSHttpSsn ssn = TSHttpTxnSsnGet(res.txnp);
-
- if (ssn) {
- int n = TSHttpSsnTransactionCount(ssn);
+ if (res.state.ssnp) {
+ int n = TSHttpSsnTransactionCount(res.state.ssnp);
Dbg(pi_dbg_ctl, "Evaluating TXN-COUNT()");
return static_cast<MatcherType *>(_matcher.get())->test(n, res);
@@ -649,11 +651,9 @@ ConditionTransactCount::eval(const Resources &res)
void
ConditionTransactCount::append_value(std::string &s, Resources const &res)
{
- TSHttpSsn ssn = TSHttpTxnSsnGet(res.txnp);
-
- if (ssn) {
+ if (res.state.ssnp) {
char value[32]; // enough for UINT64_MAX
- int count = TSHttpSsnTransactionCount(ssn);
+ int count = TSHttpSsnTransactionCount(res.state.ssnp);
int length = ink_fast_itoa(count, value, sizeof(value));
if (length > 0) {
@@ -679,7 +679,7 @@ ConditionNow::get_now_qualified(NowQualifiers qual, const
Resources &resources)
struct tm res;
PrivateSlotData private_data;
- private_data.raw = reinterpret_cast<uint64_t>(TSUserArgGet(resources.txnp,
_txn_private_slot));
+ private_data.raw =
reinterpret_cast<uint64_t>(TSUserArgGet(resources.state.txnp,
_txn_private_slot));
if (private_data.timezone == 1) {
gmtime_r(&now, &res);
} else {
@@ -832,9 +832,9 @@ void
ConditionGeo::append_value(std::string &s, const Resources &res)
{
if (is_int_type()) {
- s += std::to_string(get_geo_int(getClientAddr(res.txnp,
_txn_private_slot)));
+ s += std::to_string(get_geo_int(getClientAddr(res.state.txnp,
_txn_private_slot)));
} else {
- s += get_geo_string(getClientAddr(res.txnp, _txn_private_slot));
+ s += get_geo_string(getClientAddr(res.state.txnp, _txn_private_slot));
}
Dbg(pi_dbg_ctl, "Appending GEO() to evaluation value -> %s", s.c_str());
}
@@ -846,7 +846,7 @@ ConditionGeo::eval(const Resources &res)
Dbg(pi_dbg_ctl, "Evaluating GEO()");
if (is_int_type()) {
- int64_t geo = get_geo_int(getClientAddr(res.txnp, _txn_private_slot));
+ int64_t geo = get_geo_int(getClientAddr(res.state.txnp,
_txn_private_slot));
ret = static_cast<const Matchers<int64_t> *>(_matcher.get())->test(geo,
res);
} else {
@@ -905,7 +905,7 @@ ConditionId::append_value(std::string &s, const Resources
&res ATS_UNUSED)
{
switch (_id_qual) {
case ID_QUAL_REQUEST: {
- s += std::to_string(TSHttpTxnIdGet(res.txnp));
+ s += std::to_string(TSHttpTxnIdGet(res.state.txnp));
} break;
case ID_QUAL_PROCESS: {
TSUuid process = TSProcessUuidGet();
@@ -917,7 +917,7 @@ ConditionId::append_value(std::string &s, const Resources
&res ATS_UNUSED)
case ID_QUAL_UNIQUE: {
char uuid[TS_CRUUID_STRING_LEN + 1];
- if (TS_SUCCESS == TSClientRequestUuidGet(res.txnp, uuid)) {
+ if (TS_SUCCESS == TSClientRequestUuidGet(res.state.txnp, uuid)) {
s += uuid;
}
} break;
@@ -929,7 +929,7 @@ bool
ConditionId::eval(const Resources &res)
{
if (_id_qual == ID_QUAL_REQUEST) {
- uint64_t id = TSHttpTxnIdGet(res.txnp);
+ uint64_t id = TSHttpTxnIdGet(res.state.txnp);
Dbg(pi_dbg_ctl, "Evaluating GEO() -> %" PRIu64, id);
return static_cast<const Matchers<uint64_t> *>(_matcher.get())->test(id,
res);
@@ -1003,7 +1003,7 @@ ConditionCidr::eval(const Resources &res)
void
ConditionCidr::append_value(std::string &s, const Resources &res)
{
- struct sockaddr const *addr = getClientAddr(res.txnp, _txn_private_slot);
+ struct sockaddr const *addr = getClientAddr(res.state.txnp,
_txn_private_slot);
if (addr) {
switch (addr->sa_family) {
@@ -1063,6 +1063,17 @@ ConditionInbound::initialize(Parser &p)
match->set(p.get_arg(), mods());
_matcher = std::move(match);
}
+
+#if TS_HAS_CRIPTS
+ if (_net_qual >= NET_QUAL_CERT_PEM && _net_qual <= NET_QUAL_CERT_SAN_URI) {
+ if (_mtls_cert) {
+ require_resources(RSRC_MTLS_CERTIFICATE);
+ } else {
+ require_resources(RSRC_SERVER_CERTIFICATE);
+ }
+ require_resources(RSRC_CLIENT_CONNECTION);
+ }
+#endif
}
void
@@ -1092,6 +1103,68 @@ ConditionInbound::set_qualifier(const std::string &q)
_net_qual = NET_QUAL_IP_FAMILY;
} else if (q == "STACK") {
_net_qual = NET_QUAL_STACK;
+#if TS_HAS_CRIPTS
+ } else if (q == "SERVER-CERT:PEM") {
+ _net_qual = NET_QUAL_CERT_PEM;
+ } else if (q == "SERVER-CERT:SIG") {
+ _net_qual = NET_QUAL_CERT_SIG;
+ } else if (q == "SERVER-CERT:SUBJECT") {
+ _net_qual = NET_QUAL_CERT_SUBJECT;
+ } else if (q == "SERVER-CERT:ISSUER") {
+ _net_qual = NET_QUAL_CERT_ISSUER;
+ } else if (q == "SERVER-CERT:SERIAL") {
+ _net_qual = NET_QUAL_CERT_SERIAL;
+ } else if (q == "SERVER-CERT:NOT_BEFORE") {
+ _net_qual = NET_QUAL_CERT_NOT_BEFORE;
+ } else if (q == "SERVER-CERT:NOT_AFTER") {
+ _net_qual = NET_QUAL_CERT_NOT_AFTER;
+ } else if (q == "SERVER-CERT:VERSION") {
+ _net_qual = NET_QUAL_CERT_VERSION;
+ } else if (q == "SERVER-CERT:SAN:DNS") {
+ _net_qual = NET_QUAL_CERT_SAN_DNS;
+ } else if (q == "SERVER-CERT:SAN:IP") {
+ _net_qual = NET_QUAL_CERT_SAN_IP;
+ } else if (q == "SERVER-CERT:SAN:EMAIL") {
+ _net_qual = NET_QUAL_CERT_SAN_EMAIL;
+ } else if (q == "SERVER-CERT:SAN:URI") {
+ _net_qual = NET_QUAL_CERT_SAN_URI;
+ } else if (q == "CLIENT-CERT:PEM") {
+ _net_qual = NET_QUAL_CERT_PEM;
+ _mtls_cert = true;
+ } else if (q == "CLIENT-CERT:SIG") {
+ _net_qual = NET_QUAL_CERT_SIG;
+ _mtls_cert = true;
+ } else if (q == "CLIENT-CERT:SUBJECT") {
+ _net_qual = NET_QUAL_CERT_SUBJECT;
+ _mtls_cert = true;
+ } else if (q == "CLIENT-CERT:ISSUER") {
+ _net_qual = NET_QUAL_CERT_ISSUER;
+ _mtls_cert = true;
+ } else if (q == "CLIENT-CERT:SERIAL") {
+ _net_qual = NET_QUAL_CERT_SERIAL;
+ _mtls_cert = true;
+ } else if (q == "CLIENT-CERT:NOT_BEFORE") {
+ _net_qual = NET_QUAL_CERT_NOT_BEFORE;
+ _mtls_cert = true;
+ } else if (q == "CLIENT-CERT:NOT_AFTER") {
+ _net_qual = NET_QUAL_CERT_NOT_AFTER;
+ _mtls_cert = true;
+ } else if (q == "CLIENT-CERT:VERSION") {
+ _net_qual = NET_QUAL_CERT_VERSION;
+ _mtls_cert = true;
+ } else if (q == "CLIENT-CERT:SAN:DNS") {
+ _net_qual = NET_QUAL_CERT_SAN_DNS;
+ _mtls_cert = true;
+ } else if (q == "CLIENT-CERT:SAN:IP") {
+ _net_qual = NET_QUAL_CERT_SAN_IP;
+ _mtls_cert = true;
+ } else if (q == "CLIENT-CERT:SAN:EMAIL") {
+ _net_qual = NET_QUAL_CERT_SAN_EMAIL;
+ _mtls_cert = true;
+ } else if (q == "CLIENT-CERT:SAN:URI") {
+ _net_qual = NET_QUAL_CERT_SAN_URI;
+ _mtls_cert = true;
+#endif
} else {
TSError("[%s] Unknown %s() qualifier: %s", PLUGIN_NAME, TAG, q.c_str());
}
@@ -1106,10 +1179,10 @@ ConditionInbound::eval(const Resources &res)
switch (_net_qual) {
case NET_QUAL_LOCAL_ADDR:
- addr = TSHttpTxnIncomingAddrGet(res.txnp);
+ addr = TSHttpTxnIncomingAddrGet(res.state.txnp);
break;
case NET_QUAL_REMOTE_ADDR:
- addr = getClientAddr(res.txnp, _txn_private_slot);
+ addr = getClientAddr(res.state.txnp, _txn_private_slot);
break;
default:
// Only support actual IP addresses of course...
@@ -1146,43 +1219,59 @@ ConditionInbound::append_value(std::string &s, const
Resources &res, NetworkSess
const char *zret = nullptr;
char text[INET6_ADDRSTRLEN];
+#if TS_HAS_CRIPTS
+ detail::CertBase *cert = nullptr;
+
+ if (_net_qual >= NET_QUAL_CERT_PEM && _net_qual <= NET_QUAL_CERT_SAN_URI) {
+ if (_mtls_cert) {
+ cert = static_cast<detail::CertBase *>(res.mtls_cert);
+ } else {
+ cert = static_cast<detail::CertBase *>(res.server_cert);
+ }
+
+ if (!cert) {
+ return;
+ }
+ }
+#endif
+
switch (qual) {
case NET_QUAL_LOCAL_ADDR: {
- zret = getIP(TSHttpTxnIncomingAddrGet(res.txnp), text);
+ zret = getIP(TSHttpTxnIncomingAddrGet(res.state.txnp), text);
} break;
case NET_QUAL_LOCAL_PORT: {
- uint16_t port = getPort(TSHttpTxnIncomingAddrGet(res.txnp));
+ uint16_t port = getPort(TSHttpTxnIncomingAddrGet(res.state.txnp));
snprintf(text, sizeof(text), "%d", port);
zret = text;
} break;
case NET_QUAL_REMOTE_ADDR: {
- zret = getIP(getClientAddr(res.txnp, _txn_private_slot), text);
+ zret = getIP(getClientAddr(res.state.txnp, _txn_private_slot), text);
} break;
case NET_QUAL_REMOTE_PORT: {
- uint16_t port = getPort(getClientAddr(res.txnp, _txn_private_slot));
+ uint16_t port = getPort(getClientAddr(res.state.txnp, _txn_private_slot));
snprintf(text, sizeof(text), "%d", port);
zret = text;
} break;
case NET_QUAL_TLS:
- zret = TSHttpTxnClientProtocolStackContains(res.txnp, "tls/");
+ zret = TSHttpTxnClientProtocolStackContains(res.state.txnp, "tls/");
break;
case NET_QUAL_H2:
- zret = TSHttpTxnClientProtocolStackContains(res.txnp, "h2");
+ zret = TSHttpTxnClientProtocolStackContains(res.state.txnp, "h2");
break;
case NET_QUAL_IPV4:
- zret = TSHttpTxnClientProtocolStackContains(res.txnp, "ipv4");
+ zret = TSHttpTxnClientProtocolStackContains(res.state.txnp, "ipv4");
break;
case NET_QUAL_IPV6:
- zret = TSHttpTxnClientProtocolStackContains(res.txnp, "ipv6");
+ zret = TSHttpTxnClientProtocolStackContains(res.state.txnp, "ipv6");
break;
case NET_QUAL_IP_FAMILY:
- zret = TSHttpTxnClientProtocolStackContains(res.txnp, "ip");
+ zret = TSHttpTxnClientProtocolStackContains(res.state.txnp, "ip");
break;
case NET_QUAL_STACK: {
std::array<char const *, 8> tags = {};
int count = 0;
size_t len = 0;
- TSHttpTxnClientProtocolStackGet(res.txnp, tags.size(), tags.data(),
&count);
+ TSHttpTxnClientProtocolStackGet(res.state.txnp, tags.size(), tags.data(),
&count);
for (int i = 0; i < count; ++i) {
len += 1 + strlen(tags[i]);
}
@@ -1194,6 +1283,44 @@ ConditionInbound::append_value(std::string &s, const
Resources &res, NetworkSess
s += tags[i];
}
} break;
+#if TS_HAS_CRIPTS
+ case NET_QUAL_CERT_PEM:
+ s += cert->certificate;
+ break;
+ case NET_QUAL_CERT_SIG:
+ s += cert->signature;
+ break;
+ case NET_QUAL_CERT_SUBJECT:
+ s += cert->subject;
+ break;
+ case NET_QUAL_CERT_ISSUER:
+ s += cert->issuer;
+ break;
+ case NET_QUAL_CERT_SERIAL:
+ s += cert->serialNumber;
+ break;
+ case NET_QUAL_CERT_NOT_BEFORE:
+ s += cert->notBefore;
+ break;
+ case NET_QUAL_CERT_NOT_AFTER:
+ s += cert->notAfter;
+ break;
+ case NET_QUAL_CERT_VERSION:
+ s += cert->version;
+ break;
+ case NET_QUAL_CERT_SAN_DNS:
+ s += cert->san.dns.Join(";");
+ break;
+ case NET_QUAL_CERT_SAN_IP:
+ s += cert->san.ipadd.Join(";");
+ break;
+ case NET_QUAL_CERT_SAN_EMAIL:
+ s += cert->san.email.Join(";");
+ break;
+ case NET_QUAL_CERT_SAN_URI:
+ s += cert->san.uri.Join(";");
+ break;
+#endif
}
if (zret) {
@@ -1236,7 +1363,7 @@ ConditionSessionTransactCount::initialize(Parser &p)
bool
ConditionSessionTransactCount::eval(const Resources &res)
{
- int const val = TSHttpTxnServerSsnTransactionCount(res.txnp);
+ int const val = TSHttpTxnServerSsnTransactionCount(res.state.txnp);
Dbg(pi_dbg_ctl, "Evaluating SSN-TXN-COUNT()");
return static_cast<MatcherType *>(_matcher.get())->test(val, res);
@@ -1246,7 +1373,7 @@ 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 count = TSHttpTxnServerSsnTransactionCount(res.state.txnp);
int const length = ink_fast_itoa(count, value, sizeof(value));
if (length > 0) {
@@ -1291,7 +1418,7 @@ void
ConditionTcpInfo::append_value(std::string &s, [[maybe_unused]] Resources
const &res)
{
#if defined(TCP_INFO) && defined(HAVE_STRUCT_TCP_INFO)
- if (TSHttpTxnIsInternal(res.txnp)) {
+ if (TSHttpTxnIsInternal(res.state.txnp)) {
Dbg(pi_dbg_ctl, "No TCP-INFO available for internal transactions");
return;
}
@@ -1299,7 +1426,7 @@ ConditionTcpInfo::append_value(std::string &s,
[[maybe_unused]] Resources const
int fd;
struct tcp_info info;
socklen_t tcp_info_len = sizeof(info);
- tsSsn = TSHttpTxnClientFdGet(res.txnp, &fd);
+ tsSsn = TSHttpTxnClientFdGet(res.state.txnp, &fd);
if (tsSsn != TS_SUCCESS || fd <= 0) {
Dbg(pi_dbg_ctl, "error getting the client socket fd from ssn");
}
@@ -1351,7 +1478,7 @@ ConditionCache::eval(const Resources &res)
void
ConditionCache::append_value(std::string &s, const Resources &res)
{
- TSHttpTxn txn = res.txnp;
+ TSHttpTxn txn = res.state.txnp;
int status;
static const char *names[] = {
@@ -1398,7 +1525,7 @@ ConditionNextHop::append_value(std::string &s, const
Resources &res)
{
switch (_next_hop_qual) {
case NEXT_HOP_HOST: {
- char const *const name = TSHttpTxnNextHopNameGet(res.txnp);
+ char const *const name = TSHttpTxnNextHopNameGet(res.state.txnp);
if (nullptr != name) {
Dbg(pi_dbg_ctl, "Appending '%s' to evaluation value", name);
s.append(name);
@@ -1407,7 +1534,7 @@ ConditionNextHop::append_value(std::string &s, const
Resources &res)
}
} break;
case NEXT_HOP_PORT: {
- int const port = TSHttpTxnNextHopPortGet(res.txnp);
+ int const port = TSHttpTxnNextHopPortGet(res.state.txnp);
Dbg(pi_dbg_ctl, "Appending '%d' to evaluation value", port);
s.append(std::to_string(port));
} break;
@@ -1440,7 +1567,7 @@ ConditionHttpCntl::set_qualifier(const std::string &q)
void
ConditionHttpCntl::append_value(std::string &s, const Resources &res)
{
- s += TSHttpTxnCntlGet(res.txnp, _http_cntl_qual) ? "TRUE" : "FALSE";
+ s += TSHttpTxnCntlGet(res.state.txnp, _http_cntl_qual) ? "TRUE" : "FALSE";
Dbg(pi_dbg_ctl, "Evaluating HTTP-CNTL(%s)", _qualifier.c_str());
}
@@ -1448,7 +1575,7 @@ bool
ConditionHttpCntl::eval(const Resources &res)
{
Dbg(pi_dbg_ctl, "Evaluating HTTP-CNTL()");
- return TSHttpTxnCntlGet(res.txnp, _http_cntl_qual);
+ return TSHttpTxnCntlGet(res.state.txnp, _http_cntl_qual);
}
// ConditionStateFlag
@@ -1476,7 +1603,7 @@ ConditionStateFlag::append_value(std::string &s, const
Resources &res)
bool
ConditionStateFlag::eval(const Resources &res)
{
- auto data = reinterpret_cast<uint64_t>(TSUserArgGet(res.txnp, _txn_slot));
+ auto data = reinterpret_cast<uint64_t>(TSUserArgGet(res.state.txnp,
_txn_slot));
Dbg(pi_dbg_ctl, "Evaluating STATE-FLAG()");
diff --git a/plugins/header_rewrite/conditions.h
b/plugins/header_rewrite/conditions.h
index db8ae26cc3..10144a51fe 100644
--- a/plugins/header_rewrite/conditions.h
+++ b/plugins/header_rewrite/conditions.h
@@ -582,7 +582,10 @@ protected:
private:
NetworkSessionQualifiers _net_qual = NET_QUAL_STACK;
- void append_value(std::string &s, const Resources &res,
NetworkSessionQualifiers qual);
+#if TS_HAS_CRIPTS
+ bool _mtls_cert = false;
+#endif
+ void append_value(std::string &s, const Resources &res,
NetworkSessionQualifiers qual);
};
class ConditionStringLiteral : public Condition
@@ -859,7 +862,7 @@ private:
_get_data(const Resources &res) const
{
TSAssert(_byte_ix >= 0 && _byte_ix < NUM_STATE_INT8S);
- auto ptr = reinterpret_cast<uint64_t>(TSUserArgGet(res.txnp,
_txn_slot));
+ auto ptr = reinterpret_cast<uint64_t>(TSUserArgGet(res.state.txnp,
_txn_slot));
uint8_t data = (ptr & STATE_INT8_MASKS[_byte_ix]) >> (NUM_STATE_FLAGS +
_byte_ix * 8);
return data;
@@ -904,7 +907,7 @@ private:
uint16_t
_get_data(const Resources &res) const
{
- auto ptr = reinterpret_cast<uint64_t>(TSUserArgGet(res.txnp, _txn_slot));
+ auto ptr = reinterpret_cast<uint64_t>(TSUserArgGet(res.state.txnp,
_txn_slot));
return ((ptr & STATE_INT16_MASK) >> 48);
}
diff --git a/plugins/header_rewrite/header_rewrite.cc
b/plugins/header_rewrite/header_rewrite.cc
index 9f5bdce815..e26593651f 100644
--- a/plugins/header_rewrite/header_rewrite.cc
+++ b/plugins/header_rewrite/header_rewrite.cc
@@ -321,7 +321,7 @@ RulesConfig::parse_config(const std::string &fname,
TSHttpHookID default_hook, c
}
// Collect all resource IDs that we need
- for (size_t i = TS_HTTP_READ_REQUEST_HDR_HOOK; i < TS_HTTP_LAST_HOOK; ++i) {
+ for (size_t i = TS_HTTP_READ_REQUEST_HDR_HOOK; i <= TS_HTTP_LAST_HOOK; ++i) {
if (_rules[i]) {
_resids[i] = _rules[i]->get_all_resource_ids();
}
@@ -650,22 +650,24 @@ TSRemapDoRemap(void *ih, TSHttpTxn rh, TSRemapRequestInfo
*rri)
RuleSet *rule = conf->rule(TS_REMAP_PSEUDO_HOOK);
Resources res(rh, rri);
- res.gather(RSRC_CLIENT_REQUEST_HEADERS, TS_REMAP_PSEUDO_HOOK);
- while (rule) {
- const RuleSet::OperatorAndMods &ops = rule->eval(res);
- const OperModifiers rt = rule->exec(ops, res);
+ if (rule) {
+ res.gather(conf->resid(TS_REMAP_PSEUDO_HOOK), TS_REMAP_PSEUDO_HOOK);
- ink_assert((rt & OPER_NO_REENABLE) == 0);
+ do {
+ const RuleSet::OperatorAndMods &ops = rule->eval(res);
+ const OperModifiers rt = rule->exec(ops, res);
- if (res.changed_url == true) {
- rval = TSREMAP_DID_REMAP;
- }
+ ink_assert((rt & OPER_NO_REENABLE) == 0);
- if (rule->last() || (rt & OPER_LAST)) {
- break; // Conditional break, force a break with [L]
- }
+ if (res.changed_url == true) {
+ rval = TSREMAP_DID_REMAP;
+ }
+
+ if (rule->last() || (rt & OPER_LAST)) {
+ break; // Conditional break, force a break with [L]
+ }
- rule = rule->next.get();
+ } while ((rule = rule->next.get()));
}
Dbg(dbg_ctl, "Returning from TSRemapDoRemap with status: %d", rval);
diff --git a/plugins/header_rewrite/operators.cc
b/plugins/header_rewrite/operators.cc
index edd40f5e01..66857721a3 100644
--- a/plugins/header_rewrite/operators.cc
+++ b/plugins/header_rewrite/operators.cc
@@ -52,6 +52,7 @@ handleFetchEvents(TSCont cont, TSEvent event, void *edata)
TSHttpParser parser = TSHttpParserCreate();
TSMBuffer hdr_buf = TSMBufferCreate();
TSMLoc hdr_loc = TSHttpHdrCreate(hdr_buf);
+
TSHttpHdrTypeSet(hdr_buf, hdr_loc, TS_HTTP_TYPE_RESPONSE);
if (TSHttpHdrParseResp(parser, hdr_buf, hdr_loc, &data_start, data_end)
== TS_PARSE_DONE) {
TSHttpTxnErrorBodySet(http_txn, TSstrdup(data_start), (data_end -
data_start), nullptr);
@@ -120,7 +121,7 @@ OperatorSetConfig::initialize(Parser &p)
_config = p.get_arg();
if (TS_SUCCESS == TSHttpTxnConfigFind(_config.c_str(), _config.size(),
&_key, &_type)) {
- _value.set_value(p.get_value());
+ _value.set_value(p.get_value(), this);
} else {
_key = TS_CONFIG_NULL;
TSError("[%s] no such records config: %s", PLUGIN_NAME, _config.c_str());
@@ -133,21 +134,21 @@ OperatorSetConfig::exec(const Resources &res) const
if (TS_CONFIG_NULL != _key) {
switch (_type) {
case TS_RECORDDATATYPE_INT:
- if (TS_SUCCESS == TSHttpTxnConfigIntSet(res.txnp, _key,
_value.get_int_value())) {
+ if (TS_SUCCESS == TSHttpTxnConfigIntSet(res.state.txnp, _key,
_value.get_int_value())) {
Dbg(pi_dbg_ctl, "OperatorSetConfig::exec() invoked on %s=%d",
_config.c_str(), _value.get_int_value());
} else {
Dbg(pi_dbg_ctl, "OperatorSetConfig::exec() invocation failed on
%s=%d", _config.c_str(), _value.get_int_value());
}
break;
case TS_RECORDDATATYPE_FLOAT:
- if (TS_SUCCESS == TSHttpTxnConfigFloatSet(res.txnp, _key,
_value.get_float_value())) {
+ if (TS_SUCCESS == TSHttpTxnConfigFloatSet(res.state.txnp, _key,
_value.get_float_value())) {
Dbg(pi_dbg_ctl, "OperatorSetConfig::exec() invoked on %s=%f",
_config.c_str(), _value.get_float_value());
} else {
Dbg(pi_dbg_ctl, "OperatorSetConfig::exec() invocation failed on
%s=%f", _config.c_str(), _value.get_float_value());
}
break;
case TS_RECORDDATATYPE_STRING:
- if (TS_SUCCESS == TSHttpTxnConfigStringSet(res.txnp, _key,
_value.get_value().c_str(), _value.size())) {
+ if (TS_SUCCESS == TSHttpTxnConfigStringSet(res.state.txnp, _key,
_value.get_value().c_str(), _value.size())) {
Dbg(pi_dbg_ctl, "OperatorSetConfig::exec() invoked on %s=%s",
_config.c_str(), _value.get_value().c_str());
} else {
Dbg(pi_dbg_ctl, "OperatorSetConfig::exec() invocation failed on
%s=%s", _config.c_str(), _value.get_value().c_str());
@@ -167,7 +168,7 @@ OperatorSetStatus::initialize(Parser &p)
{
Operator::initialize(p);
- _status.set_value(p.get_arg());
+ _status.set_value(p.get_arg(), this);
if (nullptr == (_reason =
TSHttpHdrReasonLookup(static_cast<TSHttpStatus>(_status.get_int_value())))) {
TSError("[%s] unknown status %d", PLUGIN_NAME, _status.get_int_value());
@@ -205,7 +206,7 @@ OperatorSetStatus::exec(const Resources &res) const
}
break;
default:
- TSHttpTxnStatusSet(res.txnp,
static_cast<TSHttpStatus>(_status.get_int_value()));
+ TSHttpTxnStatusSet(res.state.txnp,
static_cast<TSHttpStatus>(_status.get_int_value()));
break;
}
@@ -220,7 +221,7 @@ OperatorSetStatusReason::initialize(Parser &p)
{
Operator::initialize(p);
- _reason.set_value(p.get_arg());
+ _reason.set_value(p.get_arg(), this);
require_resources(RSRC_CLIENT_RESPONSE_HEADERS);
require_resources(RSRC_SERVER_RESPONSE_HEADERS);
}
@@ -254,7 +255,7 @@ OperatorSetDestination::initialize(Parser &p)
Operator::initialize(p);
_url_qual = parse_url_qualifier(p.get_arg());
- _value.set_value(p.get_value());
+ _value.set_value(p.get_value(), this);
require_resources(RSRC_CLIENT_REQUEST_HEADERS);
require_resources(RSRC_SERVER_REQUEST_HEADERS);
}
@@ -264,10 +265,10 @@ OperatorSetDestination::exec(const Resources &res) const
{
if (res._rri || (res.bufp && res.hdr_loc)) {
std::string value;
+ TSMBuffer bufp;
+ TSMLoc url_m_loc;
// Determine which TSMBuffer and TSMLoc to use
- TSMBuffer bufp;
- TSMLoc url_m_loc;
if (res._rri && !res.changed_url) {
bufp = res._rri->requestBufp;
url_m_loc = res._rri->requestUrl;
@@ -480,8 +481,8 @@ OperatorSetRedirect::initialize(Parser &p)
{
Operator::initialize(p);
- _status.set_value(p.get_arg());
- _location.set_value(p.get_value());
+ _status.set_value(p.get_arg(), this);
+ _location.set_value(p.get_value(), this);
auto status = _status.get_int_value();
if (status < 300 || status > 399 || status == TS_HTTP_STATUS_NOT_MODIFIED) {
TSError("[%s] unsupported redirect status %d", PLUGIN_NAME, status);
@@ -590,7 +591,7 @@ OperatorSetRedirect::exec(const Resources &res) const
Dbg(pi_dbg_ctl, "Could not set Location field value to: %s",
value.c_str());
}
// Set the new status.
- TSHttpTxnStatusSet(res.txnp,
static_cast<TSHttpStatus>(_status.get_int_value()));
+ TSHttpTxnStatusSet(res.state.txnp,
static_cast<TSHttpStatus>(_status.get_int_value()));
const_cast<Resources &>(res).changed_url = true;
res._rri->redirect = 1;
} else {
@@ -598,7 +599,7 @@ OperatorSetRedirect::exec(const Resources &res) const
// Set the new status code and reason.
TSHttpStatus status = static_cast<TSHttpStatus>(_status.get_int_value());
TSHttpHdrStatusSet(res.bufp, res.hdr_loc, status);
- EditRedirectResponse(res.txnp, value, status, res.bufp, res.hdr_loc);
+ EditRedirectResponse(res.state.txnp, value, status, res.bufp,
res.hdr_loc);
}
Dbg(pi_dbg_ctl, "OperatorSetRedirect::exec() invoked with destination=%s
and status code=%d", value.c_str(),
_status.get_int_value());
@@ -625,7 +626,7 @@ OperatorSetTimeoutOut::initialize(Parser &p)
TSError("[%s] unsupported timeout qualifier: %s", PLUGIN_NAME,
p.get_arg().c_str());
}
- _timeout.set_value(p.get_value());
+ _timeout.set_value(p.get_value(), this);
}
bool
@@ -634,22 +635,22 @@ OperatorSetTimeoutOut::exec(const Resources &res) const
switch (_type) {
case TO_OUT_ACTIVE:
Dbg(pi_dbg_ctl, "OperatorSetTimeoutOut::exec(active, %d)",
_timeout.get_int_value());
- TSHttpTxnActiveTimeoutSet(res.txnp, _timeout.get_int_value());
+ TSHttpTxnActiveTimeoutSet(res.state.txnp, _timeout.get_int_value());
break;
case TO_OUT_INACTIVE:
Dbg(pi_dbg_ctl, "OperatorSetTimeoutOut::exec(inactive, %d)",
_timeout.get_int_value());
- TSHttpTxnNoActivityTimeoutSet(res.txnp, _timeout.get_int_value());
+ TSHttpTxnNoActivityTimeoutSet(res.state.txnp, _timeout.get_int_value());
break;
case TO_OUT_CONNECT:
Dbg(pi_dbg_ctl, "OperatorSetTimeoutOut::exec(connect, %d)",
_timeout.get_int_value());
- TSHttpTxnConnectTimeoutSet(res.txnp, _timeout.get_int_value());
+ TSHttpTxnConnectTimeoutSet(res.state.txnp, _timeout.get_int_value());
break;
case TO_OUT_DNS:
Dbg(pi_dbg_ctl, "OperatorSetTimeoutOut::exec(dns, %d)",
_timeout.get_int_value());
- TSHttpTxnDNSTimeoutSet(res.txnp, _timeout.get_int_value());
+ TSHttpTxnDNSTimeoutSet(res.state.txnp, _timeout.get_int_value());
break;
default:
TSError("[%s] unsupported timeout", PLUGIN_NAME);
@@ -674,7 +675,7 @@ bool
OperatorSkipRemap::exec(const Resources &res) const
{
Dbg(pi_dbg_ctl, "OperatorSkipRemap::exec() skipping remap: %s", _skip_remap
? "True" : "False");
- TSHttpTxnCntlSet(res.txnp, TS_HTTP_CNTL_SKIP_REMAPPING, _skip_remap);
+ TSHttpTxnCntlSet(res.state.txnp, TS_HTTP_CNTL_SKIP_REMAPPING, _skip_remap);
return true;
}
@@ -704,7 +705,7 @@ OperatorAddHeader::initialize(Parser &p)
{
OperatorHeaders::initialize(p);
- _value.set_value(p.get_value());
+ _value.set_value(p.get_value(), this);
}
bool
@@ -741,7 +742,7 @@ OperatorSetHeader::initialize(Parser &p)
{
OperatorHeaders::initialize(p);
- _value.set_value(p.get_value());
+ _value.set_value(p.get_value(), this);
}
bool
@@ -799,7 +800,7 @@ OperatorSetBody::initialize(Parser &p)
{
Operator::initialize(p);
// we want the arg since body only takes one value
- _value.set_value(p.get_arg());
+ _value.set_value(p.get_arg(), this);
}
void
@@ -816,7 +817,7 @@ OperatorSetBody::exec(const Resources &res) const
_value.append_value(value, res);
char *msg = TSstrdup(_value.get_value().c_str());
- TSHttpTxnErrorBodySet(res.txnp, msg, _value.size(), nullptr);
+ TSHttpTxnErrorBodySet(res.state.txnp, msg, _value.size(), nullptr);
return true;
}
@@ -898,7 +899,7 @@ void
OperatorAddCookie::initialize(Parser &p)
{
OperatorCookies::initialize(p);
- _value.set_value(p.get_value());
+ _value.set_value(p.get_value(), this);
}
bool
@@ -944,7 +945,7 @@ void
OperatorSetCookie::initialize(Parser &p)
{
OperatorCookies::initialize(p);
- _value.set_value(p.get_value());
+ _value.set_value(p.get_value(), this);
}
bool
@@ -1082,7 +1083,7 @@ OperatorSetConnDSCP::initialize(Parser &p)
{
Operator::initialize(p);
- _ds_value.set_value(p.get_arg());
+ _ds_value.set_value(p.get_arg(), this);
}
void
@@ -1096,8 +1097,8 @@ OperatorSetConnDSCP::initialize_hooks()
bool
OperatorSetConnDSCP::exec(const Resources &res) const
{
- if (res.txnp) {
- TSHttpTxnClientPacketDscpSet(res.txnp, _ds_value.get_int_value());
+ if (res.state.txnp) {
+ TSHttpTxnClientPacketDscpSet(res.state.txnp, _ds_value.get_int_value());
Dbg(pi_dbg_ctl, " Setting DSCP to %d", _ds_value.get_int_value());
}
return true;
@@ -1109,7 +1110,7 @@ OperatorSetConnMark::initialize(Parser &p)
{
Operator::initialize(p);
- _ds_value.set_value(p.get_arg());
+ _ds_value.set_value(p.get_arg(), this);
}
void
@@ -1123,8 +1124,8 @@ OperatorSetConnMark::initialize_hooks()
bool
OperatorSetConnMark::exec(const Resources &res) const
{
- if (res.txnp) {
- TSHttpTxnClientPacketMarkSet(res.txnp, _ds_value.get_int_value());
+ if (res.state.txnp) {
+ TSHttpTxnClientPacketMarkSet(res.state.txnp, _ds_value.get_int_value());
Dbg(pi_dbg_ctl, " Setting MARK to %d", _ds_value.get_int_value());
}
return true;
@@ -1149,7 +1150,7 @@ OperatorSetDebug::initialize_hooks()
bool
OperatorSetDebug::exec(const Resources &res) const
{
- TSHttpTxnCntlSet(res.txnp, TS_HTTP_CNTL_TXN_DEBUG, true);
+ TSHttpTxnCntlSet(res.state.txnp, TS_HTTP_CNTL_TXN_DEBUG, true);
return true;
}
@@ -1186,10 +1187,10 @@ bool
OperatorSetHttpCntl::exec(const Resources &res) const
{
if (_flag) {
- TSHttpTxnCntlSet(res.txnp, _cntl_qual, true);
+ TSHttpTxnCntlSet(res.state.txnp, _cntl_qual, true);
Dbg(pi_dbg_ctl, " Turning ON %s for transaction",
HttpCntls[static_cast<size_t>(_cntl_qual)]);
} else {
- TSHttpTxnCntlSet(res.txnp, _cntl_qual, false);
+ TSHttpTxnCntlSet(res.state.txnp, _cntl_qual, false);
Dbg(pi_dbg_ctl, " Turning OFF %s for transaction",
HttpCntls[static_cast<size_t>(_cntl_qual)]);
}
return true;
@@ -1241,7 +1242,7 @@ bool
OperatorSetPluginCntl::exec(const Resources &res) const
{
PrivateSlotData private_data;
- private_data.raw = reinterpret_cast<uint64_t>(TSUserArgGet(res.txnp,
_txn_private_slot));
+ private_data.raw = reinterpret_cast<uint64_t>(TSUserArgGet(res.state.txnp,
_txn_private_slot));
switch (_name) {
case PluginCtrl::TIMEZONE:
@@ -1253,7 +1254,7 @@ OperatorSetPluginCntl::exec(const Resources &res) const
}
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));
+ TSUserArgSet(res.state.txnp, _txn_private_slot, reinterpret_cast<void
*>(private_data.raw));
return true;
}
@@ -1323,8 +1324,8 @@ OperatorRunPlugin::exec(const Resources &res) const
{
TSReleaseAssert(_plugin != nullptr);
- if (res._rri && res.txnp) {
- _plugin->doRemap(res.txnp, res._rri);
+ if (res._rri && res.state.txnp) {
+ _plugin->doRemap(res.state.txnp, res._rri);
}
return true;
}
@@ -1335,7 +1336,7 @@ OperatorSetBodyFrom::initialize(Parser &p)
{
Operator::initialize(p);
// we want the arg since body only takes one value
- _value.set_value(p.get_arg());
+ _value.set_value(p.get_arg(), this);
require_resources(RSRC_SERVER_RESPONSE_HEADERS);
require_resources(RSRC_RESPONSE_STATUS);
}
@@ -1349,7 +1350,7 @@ OperatorSetBodyFrom::initialize_hooks()
bool
OperatorSetBodyFrom::exec(const Resources &res) const
{
- if (TSHttpTxnIsInternal(res.txnp)) {
+ if (TSHttpTxnIsInternal(res.state.txnp)) {
// If this is triggered by an internal transaction, a infinte loop may
occur
// It should only be triggered by the original transaction sent by the
client
Dbg(pi_dbg_ctl, "OperatorSetBodyFrom triggered by an internal
transaction");
@@ -1360,9 +1361,9 @@ OperatorSetBodyFrom::exec(const Resources &res) const
int req_buf_size = 0;
if (createRequestString(_value.get_value(), req_buf, &req_buf_size) ==
TS_SUCCESS) {
TSCont fetchCont = TSContCreate(handleFetchEvents, TSMutexCreate());
- TSContDataSet(fetchCont, static_cast<void *>(res.txnp));
+ TSContDataSet(fetchCont, static_cast<void *>(res.state.txnp));
- TSHttpTxnHookAdd(res.txnp, TS_HTTP_TXN_CLOSE_HOOK, fetchCont);
+ TSHttpTxnHookAdd(res.state.txnp, TS_HTTP_TXN_CLOSE_HOOK, fetchCont);
TSFetchEvent event_ids;
event_ids.success_event_id = TS_EVENT_FETCHSM_SUCCESS;
@@ -1379,7 +1380,7 @@ OperatorSetBodyFrom::exec(const Resources &res) const
// Forces original status code in event TSHttpTxnErrorBodySet changed
// the code or another condition was set conflicting with this one.
// Set here because res is the only structure that contains the original
status code.
- TSHttpTxnStatusSet(res.txnp, res.resp_status);
+ TSHttpTxnStatusSet(res.state.txnp, res.resp_status);
} else {
TSError(PLUGIN_NAME, "OperatorSetBodyFrom:exec:: Could not create
request");
return true;
@@ -1429,16 +1430,16 @@ OperatorSetStateFlag::initialize_hooks()
bool
OperatorSetStateFlag::exec(const Resources &res) const
{
- if (!res.txnp) {
+ if (!res.state.txnp) {
TSError("[%s] OperatorSetStateFlag() failed. Transaction is null",
PLUGIN_NAME);
return false;
}
Dbg(pi_dbg_ctl, " Setting state flag %d to %d", _flag_ix, _flag);
- auto data = reinterpret_cast<uint64_t>(TSUserArgGet(res.txnp, _txn_slot));
+ auto data = reinterpret_cast<uint64_t>(TSUserArgGet(res.state.txnp,
_txn_slot));
- TSUserArgSet(res.txnp, _txn_slot, reinterpret_cast<void *>(_flag ? data |
_mask : data & _mask));
+ TSUserArgSet(res.state.txnp, _txn_slot, reinterpret_cast<void *>(_flag ?
data | _mask : data & _mask));
return true;
}
@@ -1455,7 +1456,7 @@ OperatorSetStateInt8::initialize(Parser &p)
return;
}
- _value.set_value(p.get_value());
+ _value.set_value(p.get_value(), this);
if (!_value.has_conds()) {
int v = _value.get_int_value();
@@ -1483,12 +1484,12 @@ OperatorSetStateInt8::initialize_hooks()
bool
OperatorSetStateInt8::exec(const Resources &res) const
{
- if (!res.txnp) {
+ if (!res.state.txnp) {
TSError("[%s] OperatorSetStateInt8() failed. Transaction is null",
PLUGIN_NAME);
return false;
}
- auto ptr = reinterpret_cast<uint64_t>(TSUserArgGet(res.txnp, _txn_slot));
+ auto ptr = reinterpret_cast<uint64_t>(TSUserArgGet(res.state.txnp,
_txn_slot));
int val = 0;
if (_value.has_conds()) { // If there are conditions, we need to evaluate
them, which gives us a string
@@ -1508,7 +1509,7 @@ OperatorSetStateInt8::exec(const Resources &res) const
Dbg(pi_dbg_ctl, " Setting state int8 %d to %d", _byte_ix, val);
ptr &= ~STATE_INT8_MASKS[_byte_ix]; // Clear any old value
ptr |= (static_cast<uint64_t>(val) << (NUM_STATE_FLAGS + _byte_ix * 8));
- TSUserArgSet(res.txnp, _txn_slot, reinterpret_cast<void *>(ptr));
+ TSUserArgSet(res.state.txnp, _txn_slot, reinterpret_cast<void *>(ptr));
return true;
}
@@ -1525,7 +1526,7 @@ OperatorSetStateInt16::initialize(Parser &p)
return;
}
- _value.set_value(p.get_value());
+ _value.set_value(p.get_value(), this);
if (!_value.has_conds()) {
int v = _value.get_int_value();
@@ -1553,12 +1554,12 @@ OperatorSetStateInt16::initialize_hooks()
bool
OperatorSetStateInt16::exec(const Resources &res) const
{
- if (!res.txnp) {
+ if (!res.state.txnp) {
TSError("[%s] OperatorSetStateInt16() failed. Transaction is null",
PLUGIN_NAME);
return false;
}
- auto ptr = reinterpret_cast<uint64_t>(TSUserArgGet(res.txnp, _txn_slot));
+ auto ptr = reinterpret_cast<uint64_t>(TSUserArgGet(res.state.txnp,
_txn_slot));
int val = 0;
if (_value.has_conds()) { // If there are conditions, we need to evaluate
them, which gives us a string
@@ -1578,7 +1579,7 @@ OperatorSetStateInt16::exec(const Resources &res) const
Dbg(pi_dbg_ctl, " Setting state int16 to %d", val);
ptr &= ~STATE_INT16_MASK; // Clear any old value
ptr |= (static_cast<uint64_t>(val) << 48);
- TSUserArgSet(res.txnp, _txn_slot, reinterpret_cast<void *>(ptr));
+ TSUserArgSet(res.state.txnp, _txn_slot, reinterpret_cast<void *>(ptr));
return true;
}
diff --git a/plugins/header_rewrite/resources.cc
b/plugins/header_rewrite/resources.cc
index a7061f286b..2959b8e12e 100644
--- a/plugins/header_rewrite/resources.cc
+++ b/plugins/header_rewrite/resources.cc
@@ -24,6 +24,10 @@
#include "resources.h"
#include "lulu.h"
+#if TS_HAS_CRIPTS
+#include "cripts/Connections.hpp"
+#endif
+
// Collect all resources
void
Resources::gather(const ResourceIDs ids, TSHttpHookID hook)
@@ -34,10 +38,12 @@ Resources::gather(const ResourceIDs ids, TSHttpHookID hook)
ovector_count = 0;
ovector_ptr = nullptr;
+ Dbg(pi_dbg_ctl, "Gathering resources for hook %s with IDs %d",
TSHttpHookNameLookup(hook), ids);
+
// If we need the client request headers, make sure it's also available in
the client vars.
if (ids & RSRC_CLIENT_REQUEST_HEADERS) {
Dbg(pi_dbg_ctl, "\tAdding TXN client request header buffers");
- if (TSHttpTxnClientReqGet(txnp, &client_bufp, &client_hdr_loc) !=
TS_SUCCESS) {
+ if (TSHttpTxnClientReqGet(state.txnp, &client_bufp, &client_hdr_loc) !=
TS_SUCCESS) {
Dbg(pi_dbg_ctl, "could not gather bufp/hdr_loc for request");
return;
}
@@ -48,7 +54,7 @@ Resources::gather(const ResourceIDs ids, TSHttpHookID hook)
// Read response headers from server
if (ids & RSRC_SERVER_RESPONSE_HEADERS) {
Dbg(pi_dbg_ctl, "\tAdding TXN server response header buffers");
- if (TSHttpTxnServerRespGet(txnp, &bufp, &hdr_loc) != TS_SUCCESS) {
+ if (TSHttpTxnServerRespGet(state.txnp, &bufp, &hdr_loc) != TS_SUCCESS) {
Dbg(pi_dbg_ctl, "could not gather bufp/hdr_loc for response");
return;
}
@@ -64,7 +70,7 @@ Resources::gather(const ResourceIDs ids, TSHttpHookID hook)
// Read request headers to server
if (ids & RSRC_SERVER_REQUEST_HEADERS) {
Dbg(pi_dbg_ctl, "\tAdding TXN server request header buffers");
- if (!TSHttpTxnServerReqGet(txnp, &bufp, &hdr_loc)) {
+ if (!TSHttpTxnServerReqGet(state.txnp, &bufp, &hdr_loc)) {
Dbg(pi_dbg_ctl, "could not gather bufp/hdr_loc for request");
return;
}
@@ -84,7 +90,7 @@ Resources::gather(const ResourceIDs ids, TSHttpHookID hook)
// Send response headers to client
if (ids & RSRC_CLIENT_RESPONSE_HEADERS) {
Dbg(pi_dbg_ctl, "\tAdding TXN client response header buffers");
- if (TSHttpTxnClientRespGet(txnp, &bufp, &hdr_loc) != TS_SUCCESS) {
+ if (TSHttpTxnClientRespGet(state.txnp, &bufp, &hdr_loc) != TS_SUCCESS) {
Dbg(pi_dbg_ctl, "could not gather bufp/hdr_loc for request");
return;
}
@@ -116,7 +122,7 @@ Resources::gather(const ResourceIDs ids, TSHttpHookID hook)
case TS_HTTP_TXN_CLOSE_HOOK:
// Get TCP Info at transaction close
Dbg(pi_dbg_ctl, "\tAdding TXN close buffers");
- if (TSHttpTxnClientRespGet(txnp, &bufp, &hdr_loc) != TS_SUCCESS) {
+ if (TSHttpTxnClientRespGet(state.txnp, &bufp, &hdr_loc) != TS_SUCCESS) {
Dbg(pi_dbg_ctl, "could not gather bufp/hdr_loc for request");
return;
}
@@ -126,6 +132,32 @@ Resources::gather(const ResourceIDs ids, TSHttpHookID hook)
break;
}
+ // The following is all the new infrastructure borrowed / reused from
+ // the Cripts library.
+#if TS_HAS_CRIPTS
+ if (ids & (RSRC_CLIENT_CONNECTION | RSRC_MTLS_CERTIFICATE |
RSRC_SERVER_CERTIFICATE)) {
+ Dbg(pi_dbg_ctl, "\tAdding Cripts Client::Connection");
+ client_conn = new cripts::Client::Connection();
+ client_conn->set_state(&state);
+ }
+
+ if (ids & RSRC_SERVER_CONNECTION) {
+ Dbg(pi_dbg_ctl, "\tAdding Cripts Server::Connection");
+ server_conn = new cripts::Server::Connection();
+ server_conn->set_state(&state);
+ }
+
+ if (ids & RSRC_MTLS_CERTIFICATE) {
+ Dbg(pi_dbg_ctl, "\tAdding Cripts Certs::Client");
+ mtls_cert = new cripts::Certs::Client(*client_conn);
+ }
+
+ if (ids & RSRC_SERVER_CERTIFICATE) {
+ Dbg(pi_dbg_ctl, "\tAdding Cripts Certs::Server");
+ server_cert = new cripts::Certs::Server(*client_conn);
+ }
+#endif
+
_ready = true;
}
@@ -144,5 +176,12 @@ Resources::destroy()
}
}
+#if TS_HAS_CRIPTS
+ delete client_conn;
+ delete server_conn;
+ delete mtls_cert;
+ delete server_cert;
+#endif
+
_ready = false;
}
diff --git a/plugins/header_rewrite/resources.h
b/plugins/header_rewrite/resources.h
index 0aa0d82def..a56c808dee 100644
--- a/plugins/header_rewrite/resources.h
+++ b/plugins/header_rewrite/resources.h
@@ -28,30 +28,42 @@
#include "lulu.h"
+#if TS_HAS_CRIPTS
+#include "cripts/Certs.hpp"
+#include "cripts/Transaction.hpp"
+#endif
+
enum ResourceIDs {
RSRC_NONE = 0,
- RSRC_SERVER_RESPONSE_HEADERS = 1,
- RSRC_SERVER_REQUEST_HEADERS = 2,
- RSRC_CLIENT_REQUEST_HEADERS = 4,
- RSRC_CLIENT_RESPONSE_HEADERS = 8,
- RSRC_RESPONSE_STATUS = 16,
+ RSRC_SERVER_RESPONSE_HEADERS = 1 << 0, // 1
+ RSRC_SERVER_REQUEST_HEADERS = 1 << 1, // 2
+ RSRC_CLIENT_REQUEST_HEADERS = 1 << 2, // 4
+ RSRC_CLIENT_RESPONSE_HEADERS = 1 << 3, // 8
+ RSRC_RESPONSE_STATUS = 1 << 4, // 16
+#if TS_HAS_CRIPTS
+ RSRC_CLIENT_CONNECTION = 1 << 5, // 32
+ RSRC_SERVER_CONNECTION = 1 << 6, // 64
+ RSRC_SERVER_CERTIFICATE = 1 << 7, // 128
+ RSRC_MTLS_CERTIFICATE = 1 << 8, // 256
+#endif
};
///////////////////////////////////////////////////////////////////////////////
// Resources holds the minimum resources required to process a request.
//
+#if !TS_HAS_CRIPTS
+struct TransactionState {
+ TSHttpTxn txnp = nullptr;
+ TSHttpSsn ssnp = nullptr;
+};
+#endif
+
class Resources
{
public:
- explicit Resources(TSHttpTxn txnptr, TSCont contptr) : txnp(txnptr),
contp(contptr)
- {
- Dbg(dbg_ctl, "Calling CTOR for Resources (InkAPI)");
- }
+ explicit Resources(TSHttpTxn txnptr, TSCont contptr) : contp(contptr) {
_initialize(txnptr, "InkAPI"); }
- Resources(TSHttpTxn txnptr, TSRemapRequestInfo *rri) : txnp(txnptr),
_rri(rri)
- {
- Dbg(dbg_ctl, "Calling CTOR for Resources (RemapAPI)");
- }
+ explicit Resources(TSHttpTxn txnptr, TSRemapRequestInfo *rri) : _rri(rri) {
_initialize(txnptr, "RemapAPI"); }
~Resources() { destroy(); }
@@ -66,20 +78,37 @@ public:
return _ready;
}
- TSHttpTxn txnp;
TSCont contp = nullptr;
TSRemapRequestInfo *_rri = nullptr;
TSMBuffer bufp = nullptr;
TSMLoc hdr_loc = nullptr;
TSMBuffer client_bufp = nullptr;
TSMLoc client_hdr_loc = nullptr;
- TSHttpStatus resp_status = TS_HTTP_STATUS_NONE;
- const char *ovector_ptr = nullptr;
- int ovector[OVECCOUNT];
- int ovector_count = 0;
- bool changed_url = false;
+#if TS_HAS_CRIPTS
+ cripts::Transaction state; // This now holds txpn / ssnp
+ cripts::Client::Connection *client_conn = nullptr;
+ cripts::Server::Connection *server_conn = nullptr;
+ cripts::Certs::Client *mtls_cert = nullptr;
+ cripts::Certs::Server *server_cert = nullptr;
+#else
+ TransactionState state; // Without cripts, txnp / ssnp goes here
+#endif
+ const char *ovector_ptr = nullptr;
+ TSHttpStatus resp_status = TS_HTTP_STATUS_NONE;
+ int ovector[OVECCOUNT];
+ int ovector_count = 0;
+ bool changed_url = false;
private:
+ void
+ _initialize(TSHttpTxn txnptr, const char *api_type)
+ {
+ state.txnp = txnptr;
+ state.ssnp = TSHttpTxnSsnGet(txnptr); // This is cheap, even if not used
+
+ Dbg(dbg_ctl, "Calling CTOR for Resources (%s)", api_type);
+ }
+
void destroy();
bool _ready = false;
diff --git a/plugins/header_rewrite/statement.h
b/plugins/header_rewrite/statement.h
index 90709e1403..601157cc63 100644
--- a/plugins/header_rewrite/statement.h
+++ b/plugins/header_rewrite/statement.h
@@ -112,6 +112,20 @@ enum NetworkSessionQualifiers {
NET_QUAL_IPV6, ///< 'ipv6' or not.
NET_QUAL_IP_FAMILY, ///< IP protocol family.
NET_QUAL_STACK, ///< Full protocol stack.
+#if TS_HAS_CRIPTS
+ NET_QUAL_CERT_PEM, ///< The PEM encoded certificate
+ NET_QUAL_CERT_SIG, ///< The signature of the certificate
+ NET_QUAL_CERT_SUBJECT, ///< The subject of the certificate
+ NET_QUAL_CERT_ISSUER, ///< The issuer of the certificate
+ NET_QUAL_CERT_SERIAL, ///< The serial number of the certificate
+ NET_QUAL_CERT_NOT_BEFORE, ///< The not before date of the certificate
+ NET_QUAL_CERT_NOT_AFTER, ///< The not after date of the certificate
+ NET_QUAL_CERT_VERSION, ///< The version of the certificate
+ NET_QUAL_CERT_SAN_DNS, ///< The DNS names in the SAN
+ NET_QUAL_CERT_SAN_IP, ///< The IP addresses in the SAN
+ NET_QUAL_CERT_SAN_EMAIL, ///< The email addresses in the SAN
+ NET_QUAL_CERT_SAN_URI, ///< The URIs in the SAN
+#endif
};
class Statement
@@ -173,6 +187,12 @@ public:
return _txn_private_slot;
}
+ void
+ require_resources(const ResourceIDs ids)
+ {
+ _rsrc = static_cast<ResourceIDs>(_rsrc | ids);
+ }
+
protected:
virtual void initialize_hooks();
@@ -180,12 +200,6 @@ protected:
NextHopQualifiers parse_next_hop_qualifier(const std::string &q) const;
TSHttpCntlType parse_http_cntl_qualifier(const std::string &q) const;
- void
- require_resources(const ResourceIDs ids)
- {
- _rsrc = static_cast<ResourceIDs>(_rsrc | ids);
- }
-
virtual bool
need_txn_slot() const
{
diff --git a/plugins/header_rewrite/value.cc b/plugins/header_rewrite/value.cc
index 92d40d5f72..70fd17893a 100644
--- a/plugins/header_rewrite/value.cc
+++ b/plugins/header_rewrite/value.cc
@@ -36,7 +36,7 @@ Value::~Value()
}
void
-Value::set_value(const std::string &val)
+Value::set_value(const std::string &val, Statement *owner)
{
_value = val;
@@ -55,6 +55,7 @@ Value::set_value(const std::string &val)
if (parser.parse_line(cond_token)) {
tcond_val->initialize(parser);
+ require_resources(tcond_val->get_resource_ids());
} else {
// TODO: should we produce error here?
Dbg(dbg_ctl, "Error parsing value '%s'", _value.c_str());
@@ -68,6 +69,11 @@ Value::set_value(const std::string &val)
_cond_vals.push_back(std::unique_ptr<Condition>{tcond_val});
}
}
+
+ // If we have an owner (e.g. an Operator) hoist up the resource
requirements
+ if (owner) {
+ owner->require_resources(get_resource_ids());
+ }
} else {
_int_value = strtol(_value.c_str(), nullptr, 10);
_float_value = strtod(_value.c_str(), nullptr);
diff --git a/plugins/header_rewrite/value.h b/plugins/header_rewrite/value.h
index cae41c8a71..6b96098e50 100644
--- a/plugins/header_rewrite/value.h
+++ b/plugins/header_rewrite/value.h
@@ -37,7 +37,7 @@
// TODO: This is very incomplete, we need to support linked lists of these,
// which evaluate each component and create a "joined" final string.
//
-class Value : Statement
+class Value : public Statement
{
public:
Value() { Dbg(dbg_ctl, "Calling CTOR for Value"); }
@@ -48,7 +48,7 @@ public:
Value(const Value &) = delete;
void operator=(const Value &) = delete;
- void set_value(const std::string &val);
+ void set_value(const std::string &val, Statement *owner = nullptr);
void
append_value(std::string &s, const Resources &res) const