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 884cdd319c Adds convenience APIs / definitions to Cripts (#12155)
884cdd319c is described below
commit 884cdd319cfd5e9e3c395b757cc1364a6f85a0b6
Author: Leif Hedstrom <[email protected]>
AuthorDate: Sat Apr 5 20:23:46 2025 -0600
Adds convenience APIs / definitions to Cripts (#12155)
---
.../cripts/cripts-convenience.en.rst | 140 +++++++++++++
doc/developer-guide/cripts/cripts-global.en.rst | 4 +-
doc/developer-guide/cripts/cripts-misc.en.rst | 4 +-
doc/developer-guide/cripts/cripts-overview.en.rst | 4 +-
doc/developer-guide/cripts/cripts-urls.en.rst | 2 +-
doc/developer-guide/cripts/index.en.rst | 1 +
example/cripts/example1.cc | 2 +-
example/cripts/{example1.cc => example2.cc} | 141 ++++++-------
include/cripts/Connections.hpp | 61 ++++--
include/cripts/Context.hpp | 65 ++++--
include/cripts/Epilogue.hpp | 46 +++--
include/cripts/Headers.hpp | 36 +++-
include/cripts/Preamble.hpp | 15 ++
include/cripts/Urls.hpp | 101 +++++----
src/cripts/Connections.cc | 52 ++---
src/cripts/Context.cc | 28 +--
src/cripts/Headers.cc | 123 ++++++-----
src/cripts/Urls.cc | 229 ++++++++++++---------
18 files changed, 685 insertions(+), 369 deletions(-)
diff --git a/doc/developer-guide/cripts/cripts-convenience.en.rst
b/doc/developer-guide/cripts/cripts-convenience.en.rst
new file mode 100644
index 0000000000..cb2fc4010c
--- /dev/null
+++ b/doc/developer-guide/cripts/cripts-convenience.en.rst
@@ -0,0 +1,140 @@
+.. 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
+
+.. highlight:: cpp
+.. default-domain:: cpp
+
+.. _cripts-convenience:
+
+Convenience APIs
+****************
+
+To make Cripts even more approachable, a set of optional convenience APIs are
added
+to the core and top level name space. These APIs are not required to be used,
and
+are enabled by adding a define to your Cript file (or when compiling the
Cript).
+Making this addition optional allows users to choose whether they want to use
+these convenience APIs or stick with the traditional Cripts API style.
+
+The convenience APIs carries a small (very small) overhead, due to how Cripts
defers
+(or delays) initializations of objects until they are actually used. These new
APIs
+are designed to be as efficient as possible, but they do introduce potential
conflicts
+in the top level namespace. Here's a simple example of how to enable these
APIs:
+
+.. code-block:: cpp
+
+ #define CRIPTS_CONVENIENCE_APIS 1
+
+ #include <cripts/Preamble.hpp>
+
+ do_remap()
+ {
+ urls.request.query.Keep({"foo", "bar"});
+ }
+
+ #include <cripts/Epilogue.hpp>
+
+
+.. _cripts-convenience-toplevel:
+
+Top level API additions
+=======================
+
+For the most common patterns, the top level API additions are ``client``,
``server``, and
+``urls``. These all have sub-level API additions, as explained in the
following table:
+
+=========================== =============================================
+Object Traditional API equivalent
+=========================== =============================================
+``client.request`` ``borrow cripts::Client::Request::Get()``
+``client.response`` ``borrow cripts::Client::Response::Get()``
+``client.connection`` ``borrow cripts::Client::Connection::Get()``
+``client.url`` ``borrow cripts::Client::URL::Get()``
+``server.request`` ``borrow cripts::Server::Request::Get()``
+``server.response`` ``borrow cripts::Server::Response::Get()``
+``server.connection`` ``borrow cripts::Server::Connection::Get()``
+``urls.request`` ``borrow cripts::Client::URL::Get()``
+``urls.pristine`` ``borrow cripts::Pristine::URL::Get()``
+``urls.cache`` ``borrow cripts::Cache::URL::Get()``
+``urls.parent`` ``borrow cripts::Parent::URL::Get()``
+``urls.remap.to`` ``borrow cripts::Remap::To::URL::Get``
+``urls.remap.from`` ``borrow cripts::Remap::From::URL::Get``
+=========================== =============================================
+
+The use of these top-level objects are identical to how you would use them
with the traditinoal
+APIs. The following code shows both the traditional Cripts API and the new
APIs in a simple
+example:
+
+.. code-block:: cpp
+
+ // Traditional Cripts API
+ do_remap()
+ {
+ borrow req = cripts::Client::Request::Get();
+ borrow url = cripts::Client::URL::Get();
+
+ url.query.Keep({"foo", "bar"});
+ req["X-Foo"] = "bar"
+ }
+
+ // Convenience API, does not need the borrow statements
+ do_remap()
+ {
+ urls.request.query.Keep({"foo", "bar"});
+ client.request["X-Foo"] = "bar";
+ }
+
+.. note::
+ Both ``client.url`` and `` urls.request`` refer to the same underlying
object, which is
+ ``cripts::Client::URL``. This means that any changes made to
``urls.request``
+ will also be reflected in ``client.url`` and vice versa.
+
+.. _cripts-convenience-macros:
+
+Convenience macros
+==================
+
+In addition to the top-level APIs, a set of convenience macros are provided as
well,
+enabled with the same ``#define`` as above. The following macros have been
added,
+which again populates in the top level namespace:
+
+===========================
====================================================================
+Macro Traditional API equivalent
+===========================
====================================================================
+``Regex(name, ...)`` ``static cripts::Matcher::PCRE name(...)``
+``ACL(name, ...)`` ``static cripts::Matcher::Range::IP name(...)``
+``CreateCounter(id, name)`` ``instance.metrics[id] =
cripts::Metrics::Counter::Create(name)``
+``CreateGauge(id, name)`` ``instance.metrics[id] =
cripts::Metrics::Gauge::Create(name)``
+``FilePath(name, path)`` ``static const cripts::File::Path name(path)``
+``UniqueUUID()`` ``cripts::UUID::Unique::Get()``
+``TimeNow()`` ``cripts::Time::Local::Now()``
+===========================
====================================================================
+
+An example of using ACLs and regular expressions:
+
+.. code-block:: cpp
+
+ do_remap()
+ {
+ Regex(rex, "^/([^/]+)/(.*)$");
+ ACL(allow, {"192.168.201.0/24", "10.0.0.0/8"});
+
+ if (allow.Match(client.connection.IP()) && rex.Match(urls.request.path)) {
+ // do something
+ }
+ }
diff --git a/doc/developer-guide/cripts/cripts-global.en.rst
b/doc/developer-guide/cripts/cripts-global.en.rst
index 56fd35bb35..e348e84611 100644
--- a/doc/developer-guide/cripts/cripts-global.en.rst
+++ b/doc/developer-guide/cripts/cripts-global.en.rst
@@ -50,9 +50,9 @@ depending on your preference. The file must be readable by
the ATS process. Exam
glb_read_request()
{
- borrow url = cripts::Client::URL::get();
+ borrow url = cripts::Client::URL::Get();
- url.query.keep({"foo", "bar"});
+ url.query.Keep({"foo", "bar"});
}
#include <cripts/Epilogue.hpp>
diff --git a/doc/developer-guide/cripts/cripts-misc.en.rst
b/doc/developer-guide/cripts/cripts-misc.en.rst
index 698be215a5..8fe9c4ed95 100644
--- a/doc/developer-guide/cripts/cripts-misc.en.rst
+++ b/doc/developer-guide/cripts/cripts-misc.en.rst
@@ -56,7 +56,7 @@ Example:
do_remap()
{
- borrow req = cripts::Client::Request::get();
+ borrow req = cripts::Client::Request::Get();
if (req["X-Header"] == "yes") {
cripts::Error::Status::Set(403);
@@ -119,7 +119,7 @@ Example usage to turn off a particular hook conditionally:
do_remap()
{
- static borrow req = cripts::Client::Request::get();
+ static borrow req = cripts::Client::Request::Get();
if (req["X-Header"] == "yes") {
transaction.DisableCallback(cripts::Callback::DO_READ_RESPONSE);
diff --git a/doc/developer-guide/cripts/cripts-overview.en.rst
b/doc/developer-guide/cripts/cripts-overview.en.rst
index 174503049f..ea8704dd6f 100644
--- a/doc/developer-guide/cripts/cripts-overview.en.rst
+++ b/doc/developer-guide/cripts/cripts-overview.en.rst
@@ -94,9 +94,9 @@ depending on your preference. The file must be readable by
the ATS process. Exam
do_remap()
{
- borrow url = cripts::Client::URL::get();
+ borrow url = cripts::Client::URL::Get();
- url.query.keep({"foo", "bar"});
+ url.query.Keep({"foo", "bar"});
}
#include <cripts/Epilogue.hpp>
diff --git a/doc/developer-guide/cripts/cripts-urls.en.rst
b/doc/developer-guide/cripts/cripts-urls.en.rst
index 2b0500ed07..162125bb7b 100644
--- a/doc/developer-guide/cripts/cripts-urls.en.rst
+++ b/doc/developer-guide/cripts/cripts-urls.en.rst
@@ -124,7 +124,7 @@ For example:
.. code-block:: cpp
- borrow url = cripts::Client::URL::get();
+ borrow url = cripts::Client::URL::Get();
url.query.Erase("key"); // Removes the key from the query
url.query.Erase({"key1", "key2"}); // Removes both keys from the query
diff --git a/doc/developer-guide/cripts/index.en.rst
b/doc/developer-guide/cripts/index.en.rst
index c1fb057817..03fa6da08f 100644
--- a/doc/developer-guide/cripts/index.en.rst
+++ b/doc/developer-guide/cripts/index.en.rst
@@ -35,4 +35,5 @@ Cripts
cripts-crypto.en
cripts-misc.en
cripts-bundles.en
+ cripts-convenience.en
cripts-examples.en
diff --git a/example/cripts/example1.cc b/example/cripts/example1.cc
index 205aa90fcf..6270cf4c1b 100644
--- a/example/cripts/example1.cc
+++ b/example/cripts/example1.cc
@@ -59,7 +59,7 @@ do_cache_lookup()
{
borrow url2 = cripts::Cache::URL::Get();
- CDebug("Cache URL: {}", url2.String());
+ CDebug("Cache URL: {}", url2);
CDebug("Cache Host: {}", url2.host);
}
diff --git a/example/cripts/example1.cc b/example/cripts/example2.cc
similarity index 59%
copy from example/cripts/example1.cc
copy to example/cripts/example2.cc
index 205aa90fcf..ca6b88b125 100644
--- a/example/cripts/example1.cc
+++ b/example/cripts/example2.cc
@@ -16,6 +16,8 @@
limitations under the License.
*/
+#define CRIPTS_CONVENIENCE_APIS 1
+
// The primary include file, this has to always be included
#include <cripts/Preamble.hpp>
@@ -23,7 +25,7 @@
#include <cripts/Bundles/Caching.hpp>
// Globals for this Cript
-static cripts::Matcher::Range::IP CRIPT_ALLOW({"192.168.201.0/24",
"10.0.0.0/8"});
+ACL(CRIPT_ALLOW, {"192.168.201.0/24", "10.0.0.0/8"});
// This is called only when the plugin is initialized
do_init()
@@ -33,15 +35,15 @@ do_init()
do_create_instance()
{
- instance.metrics[0] = cripts::Metrics::Counter::Create("cript.example1.c0");
- instance.metrics[1] = cripts::Metrics::Counter::Create("cript.example1.c1");
- instance.metrics[2] = cripts::Metrics::Counter::Create("cript.example1.c2");
- instance.metrics[3] = cripts::Metrics::Counter::Create("cript.example1.c3");
- instance.metrics[4] = cripts::Metrics::Counter::Create("cript.example1.c4");
- instance.metrics[5] = cripts::Metrics::Counter::Create("cript.example1.c5");
- instance.metrics[6] = cripts::Metrics::Counter::Create("cript.example1.c6");
- instance.metrics[7] = cripts::Metrics::Counter::Create("cript.example1.c7");
- instance.metrics[8] = cripts::Metrics::Counter::Create("cript.example1.c8");
// This one should resize() the storage
+ CreateCounter(0, "cript.example1.c0");
+ CreateCounter(1, "cript.example1.c1");
+ CreateCounter(2, "cript.example1.c2");
+ CreateCounter(3, "cript.example1.c3");
+ CreateCounter(4, "cript.example1.c4");
+ CreateCounter(5, "cript.example1.c5");
+ CreateCounter(6, "cript.example1.c6");
+ CreateCounter(7, "cript.example1.c7");
+ CreateCounter(8, "cript.example1.c8"); // This one should resize the storage
cripts::Bundle::Common::Activate().dscp(10);
cripts::Bundle::Caching::Activate().cache_control("max-age=259200");
@@ -49,88 +51,76 @@ do_create_instance()
do_txn_close()
{
- borrow conn = cripts::Client::Connection::Get();
-
- conn.pacing = cripts::Pacing::Off;
+ client.connection.pacing = cripts::Pacing::Off;
CDebug("Cool, TXN close also works");
}
do_cache_lookup()
{
- borrow url2 = cripts::Cache::URL::Get();
-
- CDebug("Cache URL: {}", url2.String());
- CDebug("Cache Host: {}", url2.host);
+ CDebug("Cache URL: {}", urls.cache);
+ CDebug("Cache Host: {}", urls.cache.host);
}
do_send_request()
{
- borrow req = cripts::Server::Request::Get();
-
- req["X-Leif"] = "Meh";
+ server.request["X-Leif"] = "Meh";
}
do_read_response()
{
- borrow resp = cripts::Server::Response::Get();
-
- resp["X-DBJ"] = "Vrooom!";
+ server.response["X-DBJ"] = "Vrooom!";
}
do_send_response()
{
- borrow resp = cripts::Client::Response::Get();
- borrow conn = cripts::Client::Connection::Get();
- string msg = "Eliminate TSCPP";
-
- resp["Server"] = ""; // Deletes the Server header
- resp["X-AMC"] = msg; // New header
- resp["Cache-Control"] = "Private"; // Deletes old CC values, and sets a new
one
- resp["X-UUID"] = cripts::UUID::Unique::Get();
- resp["X-tcpinfo"] = conn.tcpinfo.Log();
- resp["X-Cache-Status"] = resp.cache;
- resp["X-Integer"] = 666;
- resp["X-Data"] = AsString(txn_data[2]);
-
- resp["X-ASN"] = conn.geo.ASN();
- resp["X-ASN-Name"] = conn.geo.ASNName();
- resp["X-Country"] = conn.geo.Country();
- resp["X-ISO-Country"] = conn.geo.CountryCode();
+ string msg = "Eliminate TSCPP";
+
+ client.response["Server"] = ""; // Deletes the Server header
+ client.response["X-AMC"] = msg; // New header
+ client.response["Cache-Control"] = "Private"; // Deletes old CC values, and
sets a new one
+ client.response["X-UUID"] = UniqueUUID();
+ client.response["X-tcpinfo"] = client.connection.tcpinfo.Log();
+ client.response["X-Cache-Status"] = client.response.cache;
+ client.response["X-Integer"] = 666;
+ client.response["X-Data"] = AsString(txn_data[2]);
+
+ client.response["X-ASN"] = client.connection.geo.ASN();
+ client.response["X-ASN-Name"] = client.connection.geo.ASNName();
+ client.response["X-Country"] = client.connection.geo.Country();
+ client.response["X-ISO-Country"] = client.connection.geo.CountryCode();
// Setup some connection parameters
- conn.congestion = "bbr";
- conn.dscp = 8;
- conn.pacing = 100000;
- conn.mark = 17;
+ client.connection.congestion = "bbr";
+ client.connection.dscp = 8;
+ client.connection.pacing = 100000;
+ client.connection.mark = 17;
// Some file operations (note that the paths aren't required here, can just
be strings, but it's a good practice)
- static const cripts::File::Path p1("/tmp/foo");
- static const cripts::File::Path p2("/tmp/secret.txt");
+ FilePath(p1, "/tmp/foo");
+ FilePath(p2, "/tmp/secret.txt");
if (cripts::File::Status(p1).type() == cripts::File::Type::regular) {
- resp["X-Foo-Exists"] = "yes";
+ client.response["X-Foo-Exists"] = "yes";
} else {
- resp["X-Foo-Exists"] = "no";
+ client.response["X-Foo-Exists"] = "no";
}
string secret = cripts::File::Line::Reader(p2);
CDebug("Read secret = {}", secret);
- if (resp.status == 200) {
- resp.status = 222;
+ if (client.response.status == 200) {
+ client.response.status = 222;
}
- CDebug("Txn count: {}", conn.Count());
+ CDebug("Txn count: {}", client.connection.Count());
}
do_remap()
{
- auto now = cripts::Time::Local::Now();
- borrow req = cripts::Client::Request::Get();
- borrow conn = cripts::Client::Connection::Get();
- auto ip = conn.IP();
+ auto ip = client.connection.IP();
+ auto now = TimeNow();
- if (CRIPT_ALLOW.contains(ip)) {
+ if (CRIPT_ALLOW.Match(ip)) {
CDebug("Client IP allowed: {}", ip.string(24, 64));
}
@@ -151,35 +141,34 @@ do_remap()
CDebug("Int config cache.http = {}", proxy.config.http.cache.http.Get());
CDebug("Float config cache.heuristic_lm_factor = {}",
proxy.config.http.cache.heuristic_lm_factor.Get());
CDebug("String config http.response_server_str = {}",
proxy.config.http.response_server_str.GetSV(context));
- CDebug("X-Miles = {}", req["X-Miles"]);
+ CDebug("X-Miles = {}", client.request["X-Miles"]);
CDebug("random(1000) = {}", cripts::Random(1000));
- borrow url = cripts::Client::URL::Get();
- auto old_port = url.port;
+ auto old_port = urls.request.port;
- CDebug("Method is {}", req.method);
- CDebug("Scheme is {}", url.scheme);
- CDebug("Host is {}", url.host);
- CDebug("Port is {}", url.port);
- CDebug("Path is {}", url.path);
- CDebug("Path[1] is {}", url.path[1]);
- CDebug("Query is {}", url.query);
+ CDebug("Method is {}", client.request.method);
+ CDebug("Scheme is {}", urls.request.scheme);
+ CDebug("Host is {}", urls.request.host);
+ CDebug("Port is {}", urls.request.port);
+ CDebug("Path is {}", urls.request.path);
+ CDebug("Path[1] is {}", urls.request.path[1]);
+ CDebug("Query is {}", urls.request.query);
- auto testing_trim = url.path.trim();
+ auto testing_trim = urls.request.path.trim();
CDebug("Trimmed path is {}", testing_trim);
- if (url.query["foo"] > 100) {
+ if (urls.request.query["foo"] > 100) {
CDebug("Query[foo] is > 100");
}
- if (url.path == "some/url" || url.path[0] == "other") {
+ if (urls.request.path == "some/url" || urls.request.path[0] == "other") {
CDebug("The path comparison triggered");
}
- url.host = "foobar.com";
- url.port = "81";
- url.port = old_port;
+ urls.request.host = "foobar.com";
+ urls.request.port = "81";
+ urls.request.port = old_port;
// TXN data slots
txn_data[0] = true;
@@ -187,7 +176,7 @@ do_remap()
txn_data[2] = "DBJ";
// Regular expressions
- static cripts::Matcher::PCRE pcre("^/([^/]+)/(.*)$");
+ Regex(pcre, "^/([^/]+)/(.*)$");
auto res = pcre.Match("/foo/bench/bar"); // Can also call contains(), same
thing
@@ -233,10 +222,10 @@ do_remap()
CDebug("SHA256 = {}", hex);
// Testing iterators
- for (auto hdr : req) {
- CDebug("Header: {} = {}", hdr, req[hdr]);
+ for (auto hdr : client.request) {
+ CDebug("Header: {} = {}", hdr, client.request[hdr]);
if (hdr.starts_with("AWS-")) {
- req[hdr].clear();
+ client.request[hdr].clear();
}
}
diff --git a/include/cripts/Connections.hpp b/include/cripts/Connections.hpp
index 37b645bbeb..ae4dc1d6c4 100644
--- a/include/cripts/Connections.hpp
+++ b/include/cripts/Connections.hpp
@@ -82,6 +82,7 @@ namespace detail
class ConnBase
{
using self_type = ConnBase;
+
class Dscp
{
using self_type = Dscp;
@@ -99,7 +100,7 @@ class ConnBase
void
operator=(int val)
{
- TSAssert(_owner);
+ _ensure_initialized(_owner);
_owner->SetDscp(val);
_val = val;
}
@@ -147,7 +148,7 @@ class ConnBase
self_type &
operator=([[maybe_unused]] cripts::string_view const &str)
{
- TSAssert(_owner);
+ _ensure_initialized(_owner);
#if defined(TCP_CONGESTION)
int connfd = _owner->FD();
int res = setsockopt(connfd, IPPROTO_TCP, TCP_CONGESTION, str.data(),
str.size());
@@ -182,7 +183,7 @@ class ConnBase
void
operator=(int val)
{
- TSAssert(_owner);
+ _ensure_initialized(_owner);
_owner->SetMark(val);
_val = val;
}
@@ -309,23 +310,23 @@ public:
[[nodiscard]] virtual int FD() const = 0; // This needs the txnp from the
Context
[[nodiscard]] struct sockaddr const *
- Socket() const
+ Socket()
{
- TSAssert(_vc);
+ _ensure_initialized(this);
return TSNetVConnRemoteAddrGet(_vc);
}
[[nodiscard]] cripts::IP
- IP() const
+ IP()
{
- TSAssert(Initialized());
+ _ensure_initialized(this);
return cripts::IP{Socket()};
}
[[nodiscard]] bool
Initialized() const
{
- return _state != nullptr;
+ return _initialized;
}
[[nodiscard]] bool
@@ -334,10 +335,17 @@ public:
return TSHttpTxnIsInternal(_state->txnp);
}
- [[nodiscard]] virtual cripts::IP LocalIP() const = 0;
- [[nodiscard]] virtual int Count() const = 0;
- virtual void SetDscp(int val) = 0;
- virtual void SetMark(int val) = 0;
+ [[nodiscard]] virtual cripts::IP LocalIP() const = 0;
+ [[nodiscard]] virtual int Count() const = 0;
+ virtual void SetDscp(int val) const = 0;
+ virtual void SetMark(int val) const = 0;
+
+ // This should only be called from the Context initializers!
+ void
+ set_state(cripts::Transaction *state)
+ {
+ _state = state;
+ }
Dscp dscp;
Congestion congestion;
@@ -349,10 +357,21 @@ public:
cripts::string_view string(unsigned ipv4_cidr = 32, unsigned ipv6_cidr =
128);
protected:
+ static void
+ _ensure_initialized(self_type *ptr)
+ {
+ if (!ptr->Initialized()) [[unlikely]] {
+ ptr->_initialize();
+ }
+ }
+
+ void virtual _initialize() { _initialized = true; }
+
cripts::Transaction *_state = nullptr;
struct sockaddr const *_socket = nullptr;
TSVConn _vc = nullptr;
char _str[INET6_ADDRSTRLEN + 1];
+ bool _initialized = false;
}; // End class ConnBase
@@ -365,8 +384,8 @@ namespace Client
{
class Connection : public detail::ConnBase
{
- using pe = detail::ConnBase;
- using self_type = Connection;
+ using super_type = detail::ConnBase;
+ using self_type = Connection;
public:
Connection() = default;
@@ -376,15 +395,16 @@ namespace Client
[[nodiscard]] int FD() const override;
[[nodiscard]] int Count() const override;
static Connection &_get(cripts::Context *context);
+ void _initialize() override;
void
- SetDscp(int val) override
+ SetDscp(int val) const override
{
TSHttpTxnClientPacketDscpSet(_state->txnp, val);
}
void
- SetMark(int val) override
+ SetMark(int val) const override
{
TSHttpTxnClientPacketMarkSet(_state->txnp, val);
}
@@ -403,8 +423,8 @@ namespace Server
{
class Connection : public detail::ConnBase
{
- using pe = detail::ConnBase;
- using self_type = Connection;
+ using super_type = detail::ConnBase;
+ using self_type = Connection;
public:
Connection() = default;
@@ -414,15 +434,16 @@ namespace Server
[[nodiscard]] int FD() const override;
[[nodiscard]] int Count() const override;
static Connection &_get(cripts::Context *context);
+ void _initialize() override;
void
- SetDscp(int val) override
+ SetDscp(int val) const override
{
TSHttpTxnServerPacketDscpSet(_state->txnp, val);
}
void
- SetMark(int val) override
+ SetMark(int val) const override
{
TSHttpTxnServerPacketMarkSet(_state->txnp, val);
}
diff --git a/include/cripts/Context.hpp b/include/cripts/Context.hpp
index e3592aefe2..be2af90c39 100644
--- a/include/cripts/Context.hpp
+++ b/include/cripts/Context.hpp
@@ -44,7 +44,7 @@ public:
// This will, and should, only be called via the ProxyAllocator as used in
the factory.
Context(TSHttpTxn txn_ptr, TSHttpSsn ssn_ptr, TSRemapRequestInfo *rri_ptr,
cripts::Instance &inst)
- : rri(rri_ptr), p_instance(inst)
+ : rri(rri_ptr), p_instance(inst), _client(this), _server(this),
_urls(this, _client.url)
{
state.txnp = txn_ptr;
state.ssnp = ssn_ptr;
@@ -67,7 +67,6 @@ public:
// These are private, but needs to be visible to our friend classes that
// depends on the Context.
-private:
friend class Client::Request;
friend class Client::Response;
friend class Client::Connection;
@@ -84,18 +83,56 @@ private:
// These are "pre-allocated", but not initialized. They will be initialized
// when used via a factory.
- cripts::Client::Response _client_resp_header;
- cripts::Client::Request _client_req_header;
- cripts::Client::Connection _client_conn;
- cripts::Client::URL _client_url;
- cripts::Remap::From::URL _remap_from_url;
- cripts::Remap::To::URL _remap_to_url;
- cripts::Pristine::URL _pristine_url;
- cripts::Server::Response _server_resp_header;
- cripts::Server::Request _server_req_header;
- cripts::Server::Connection _server_conn;
- cripts::Cache::URL _cache_url;
- cripts::Parent::URL _parent_url;
+ struct _ClientBlock {
+ cripts::Client::Response response;
+ cripts::Client::Request request;
+ cripts::Client::Connection connection;
+ cripts::Client::URL url;
+
+ _ClientBlock(Context *ctx)
+ {
+ response.set_state(&ctx->state);
+ request.set_state(&ctx->state);
+ connection.set_state(&ctx->state);
+ }
+ } _client;
+
+ struct _ServerBlock {
+ cripts::Server::Response response;
+ cripts::Server::Request request;
+ cripts::Server::Connection connection;
+
+ _ServerBlock(Context *ctx)
+ {
+ response.set_state(&ctx->state);
+ request.set_state(&ctx->state);
+ connection.set_state(&ctx->state);
+ }
+
+ } _server;
+
+ struct _UrlBlock {
+ cripts::Client::URL &request;
+ cripts::Pristine::URL pristine;
+ cripts::Cache::URL cache;
+ cripts::Parent::URL parent;
+
+ struct {
+ cripts::Remap::From::URL from;
+ cripts::Remap::To::URL to;
+ } remap;
+
+ _UrlBlock(Context *ctx, cripts::Client::URL &alias) : request(alias)
+ {
+ request.set_context(ctx);
+ pristine.set_context(ctx);
+ cache.set_context(ctx);
+ parent.set_context(ctx);
+ remap.from.set_context(ctx);
+ remap.to.set_context(ctx);
+ }
+
+ } _urls;
}; // End class Context
} // namespace cripts
diff --git a/include/cripts/Epilogue.hpp b/include/cripts/Epilogue.hpp
index 6c63818faf..d0d583032b 100644
--- a/include/cripts/Epilogue.hpp
+++ b/include/cripts/Epilogue.hpp
@@ -441,7 +441,9 @@ http_txn_cont(TSCont contp, TSEvent event, void *edata)
}
CDebug("Entering glb_read_request()");
wrap_glb_read_request(context, true, CaseArg);
- cripts::Client::URL::_get(context).Update(); // Make sure any changes to
the request URL is updated
+ if (context->_urls.request.Modified()) {
+ context->_urls.request._update(); // Make sure any changes to the
request URL is updated
+ }
}
break;
@@ -464,7 +466,9 @@ http_txn_cont(TSCont contp, TSEvent event, void *edata)
CDebug("Entering glb_send_request()");
wrap_glb_send_request(context, true, CaseArg);
}
- cripts::Client::URL::_get(context).Update(); // Make sure any changes to
the request URL is updated
+ if (context->_urls.request.Modified()) {
+ context->_urls.request._update(); // Make sure any changes to the
request URL is updated
+ }
}
break;
@@ -577,8 +581,12 @@ http_txn_cont(TSCont contp, TSEvent event, void *edata)
}
if (!context->state.error.Failed()) {
- cripts::Cache::URL::_get(context).Update(); // Make sure the cache-key
gets updated, if modified
- cripts::Client::URL::_get(context).Update(); // Make sure any changes to
the request URL is updated
+ if (context->_urls.cache.Modified()) {
+ context->_urls.cache._update(); // Make sure the cache-key gets
updated, if modified
+ }
+ if (context->_urls.request.Modified()) {
+ context->_urls.request._update(); // Make sure any changes to the
request URL is updated
+ }
}
break;
@@ -604,8 +612,12 @@ http_txn_cont(TSCont contp, TSEvent event, void *edata)
}
if (!context->state.error.Failed()) {
- cripts::Cache::URL::_get(context).Update(); // Make sure the cache-key
gets updated, if modified
- cripts::Client::URL::_get(context).Update(); // Make sure any changes to
the request URL is updated
+ if (context->_urls.cache.Modified()) {
+ context->_urls.cache._update(); // Make sure the cache-key gets
updated, if modified
+ }
+ if (context->_urls.request.Modified()) {
+ context->_urls.request._update(); // Make sure any changes to the
request URL is updated
+ }
}
break;
@@ -725,7 +737,7 @@ TSPluginInit(int argc, const char *argv[])
}
// ToDo: This InstanceContext should also be usabled / used by other
non-HTTP hooks.
- cripts::InstanceContext *context = new cripts::InstanceContext(*inst);
+ auto *context = new cripts::InstanceContext(*inst);
pthread_once(&init_once_control, global_initialization);
bool needs_glb_init = wrap_glb_init(context, false, CaseArg);
@@ -866,11 +878,11 @@ TSRemapDoRemap(void *ih, TSHttpTxn txnp,
TSRemapRequestInfo *rri)
(wrap_txn_close(static_cast<cripts::Context *>(nullptr), false, CaseArg) ?
cripts::Callbacks::DO_TXN_CLOSE :
cripts::Callbacks::NONE);
- TSHttpSsn ssnp = TSHttpTxnSsnGet(txnp);
- auto *inst = static_cast<cripts::Instance *>(ih);
- auto bundle_cbs = inst->Callbacks();
- auto *context = cripts::Context::Factory(txnp, ssnp, rri, *inst);
- bool keep_context = false;
+ auto ssnp = TSHttpTxnSsnGet(txnp);
+ auto *inst = static_cast<cripts::Instance *>(ih);
+ auto bundle_cbs = inst->Callbacks();
+ auto *context = cripts::Context::Factory(txnp, ssnp, rri, *inst);
+ bool keep_context = false;
context->state.hook = TS_HTTP_READ_REQUEST_HDR_HOOK; // Not quite
true
context->state.enabled_hooks = (enabled_hooks | bundle_cbs);
@@ -887,8 +899,12 @@ TSRemapDoRemap(void *ih, TSHttpTxn txnp,
TSRemapRequestInfo *rri)
// Don't do the callbacks when we are in a failure state.
if (!context->state.error.Failed()) {
- cripts::Cache::URL::_get(context).Update(); // Make sure the cache-key
gets updated, if modified
- cripts::Client::URL::_get(context).Update(); // Make sure any changes to
the request URL is updated
+ if (context->_urls.cache.Modified()) {
+ context->_urls.cache._update(); // Make sure the cache-key gets updated,
if modified
+ }
+ if (context->_urls.request.Modified()) {
+ context->_urls.request._update(); // Make sure any changes to the
request URL is updated
+ }
if (context->state.enabled_hooks >= cripts::Callbacks::DO_POST_REMAP) {
context->contp = TSContCreate(http_txn_cont, nullptr);
@@ -935,7 +951,7 @@ TSRemapDoRemap(void *ih, TSHttpTxn txnp, TSRemapRequestInfo
*rri)
}
// See if the Client URL was modified, which dicates the return code here.
- if (cripts::Client::URL::_get(context).Modified()) {
+ if (context->_urls.request.Modified()) {
context->p_instance.debug("Client::URL was modified, returning
TSREMAP_DID_REMAP");
return TSREMAP_DID_REMAP;
} else {
diff --git a/include/cripts/Headers.hpp b/include/cripts/Headers.hpp
index ba448b02a1..f35a743fc8 100644
--- a/include/cripts/Headers.hpp
+++ b/include/cripts/Headers.hpp
@@ -345,18 +345,20 @@ public:
_hdr_loc = nullptr;
_bufp = nullptr;
}
- _state = nullptr;
+ _initialized = false;
}
[[nodiscard]] TSMBuffer
- BufP() const
+ BufP()
{
+ _ensure_initialized(this);
return _bufp;
}
[[nodiscard]] TSMLoc
- MLoc() const
+ MLoc()
{
+ _ensure_initialized(this);
return _hdr_loc;
}
@@ -365,12 +367,13 @@ public:
[[nodiscard]] bool
Initialized() const
{
- return (_state != nullptr);
+ return _initialized;
}
void
Erase(const cripts::string_view header)
{
+ _ensure_initialized(this);
operator[](header) = "";
}
@@ -383,23 +386,35 @@ public:
return Iterator::end(); // Static end iterator. ToDo: Does this have any
value over making a new one always?
}
+ // This should only be called from the Context initializers!
+ void
+ set_state(cripts::Transaction *state)
+ {
+ _state = state;
+ }
+
Status status;
Reason reason;
Body body;
CacheStatus cache;
protected:
- void
- _initialize(cripts::Transaction *state)
+ static void
+ _ensure_initialized(self_type *ptr)
{
- _state = state;
+ if (!ptr->Initialized()) [[unlikely]] {
+ ptr->_initialize();
+ }
}
+ void virtual _initialize() { _initialized = true; }
+
TSMBuffer _bufp = nullptr;
TSMLoc _hdr_loc = nullptr;
cripts::Transaction *_state = nullptr; // Pointer into the owning
Context's State
TSMLoc _iterator_loc = nullptr;
uint32_t _iterator_tag = 0; // This is used to assure that we
don't have more than one active iterator on a header
+ bool _initialized = false;
}; // End class Header
@@ -440,6 +455,7 @@ namespace Client
// Implemented later, because needs the context.
static self_type &_get(cripts::Context *context);
+ void _initialize() override;
}; // End class Client::Request
@@ -455,6 +471,7 @@ namespace Client
// Implemented later, because needs the context.
static self_type &_get(cripts::Context *context);
+ void _initialize() override;
}; // End class Client::Response
@@ -473,7 +490,9 @@ namespace Server
void operator=(const self_type &) = delete;
// Implemented later, because needs the context.
- static Request &_get(cripts::Context *context);
+ static self_type &_get(cripts::Context *context);
+ void _initialize() override;
+
}; // End class Server::Request
class Response : public ResponseHeader
@@ -488,6 +507,7 @@ namespace Server
// Implemented later, because needs the context.
static self_type &_get(cripts::Context *context);
+ void _initialize() override;
}; // End class Server::Response
diff --git a/include/cripts/Preamble.hpp b/include/cripts/Preamble.hpp
index 518b3bfec2..9f92fa958e 100644
--- a/include/cripts/Preamble.hpp
+++ b/include/cripts/Preamble.hpp
@@ -107,3 +107,18 @@ using fmt::format;
extern cripts::Proxy proxy; // Access to all overridable configurations
extern cripts::Control control; // Access to the HTTP control mechanism
extern cripts::Versions version; // Access to the ATS version information
+
+// These are not enabled by default, since they adds additional overhead
+// and pollution of the top level namespace.
+#if CRIPTS_CONVENIENCE_APIS
+#define client context->_client
+#define server context->_server
+#define urls context->_urls
+#define Regex(_name_, ...) static cripts::Matcher::PCRE
_name_(__VA_ARGS__);
+#define ACL(_name_, ...) static cripts::Matcher::Range::IP
_name_(__VA_ARGS__);
+#define CreateCounter(_id_, _name_) instance.metrics[_id_] =
cripts::Metrics::Counter::Create(_name_);
+#define CreateGauge(_id_, _name_) instance.metrics[_id_] =
cripts::Metrics::Gauge::Create(_name_);
+#define FilePath(_name_, _path_) static const cripts::File::Path
_name_(_path_);
+#define UniqueUUID() cripts::UUID::Unique::Get();
+#define TimeNow() cripts::Time::Local::Now();
+#endif
diff --git a/include/cripts/Urls.hpp b/include/cripts/Urls.hpp
index c3d049112e..47c8c5069e 100644
--- a/include/cripts/Urls.hpp
+++ b/include/cripts/Urls.hpp
@@ -33,6 +33,8 @@ class Context;
class Url
{
+ using self_type = Url;
+
class Component
{
using self_type = Component;
@@ -537,13 +539,14 @@ public:
query.Reset();
path.Reset();
}
- _state = nullptr;
+ _initialized = false;
+ _modified = false;
}
[[nodiscard]] bool
Initialized() const
{
- return (_state != nullptr);
+ return _initialized;
}
[[nodiscard]] bool
@@ -564,8 +567,15 @@ public:
return false;
}
+ // Some of these URL objects needs the full Context, making life miserable.
+ void
+ set_context(cripts::Context *context)
+ {
+ _context = context;
+ }
+
// This is the full string for a URL, which needs allocations.
- [[nodiscard]] cripts::string String() const;
+ [[nodiscard]] cripts::string String();
Scheme scheme;
Host host;
@@ -574,17 +584,28 @@ public:
Query query;
protected:
- void
- _initialize(cripts::Transaction *state)
+ static void
+ _ensure_initialized(self_type *ptr)
+ {
+ if (!ptr->Initialized()) [[unlikely]] {
+ ptr->_initialize();
+ }
+ }
+
+ virtual void
+ _initialize()
{
- _state = state;
+ _initialized = true;
+ _modified = false;
}
- TSMBuffer _bufp = nullptr; // These two gets setup via
initializing, to appropriate headers
- TSMLoc _hdr_loc = nullptr; // Do not release any of this
within the URL classes!
- TSMLoc _urlp = nullptr; // This is owned by us.
- cripts::Transaction *_state = nullptr; // Pointer into the owning
Context's State
- bool _modified = false; // We have pending changes on the
path/query components
+ TSMBuffer _bufp = nullptr; // These two gets setup via
initializing, to appropriate headers
+ TSMLoc _hdr_loc = nullptr; // Do not release any of this
within the URL classes!
+ TSMLoc _urlp = nullptr; // This is owned by us.
+ cripts::Transaction *_state = nullptr; // Pointer into the owning
Context's State
+ cripts::Context *_context = nullptr; // Pointer to the owning Context
+ bool _modified = false; // We have pending changes on
the path/query components
+ bool _initialized = false; // Have we been initialized ?
}; // End class Url
@@ -609,6 +630,9 @@ namespace Pristine
return true;
}
+ protected:
+ void _initialize() override;
+
}; // End class Pristine::URL
} // namespace Pristine
@@ -632,10 +656,10 @@ namespace Client
}
static self_type &_get(cripts::Context *context);
- bool _update(cripts::Context *context);
+ bool _update();
- private:
- void _initialize(cripts::Context *context);
+ protected:
+ void _initialize() override;
}; // End class Client::URL
@@ -668,10 +692,10 @@ namespace Remap
}
static self_type &_get(cripts::Context *context);
- bool _update(cripts::Context *context);
+ bool Update();
private:
- void _initialize(cripts::Context *context);
+ void _initialize() override;
}; // End class Client::URL
@@ -702,10 +726,10 @@ namespace Remap
}
static self_type &_get(cripts::Context *context);
- bool _update(cripts::Context *context);
+ bool Update();
private:
- void _initialize(cripts::Context *context);
+ void _initialize() override;
}; // End class Client::URL
@@ -726,17 +750,10 @@ namespace Cache
void operator=(const self_type &) = delete;
static self_type &_get(cripts::Context *context);
- bool _update(cripts::Context *context);
+ bool _update();
- private:
- void
- _initialize(cripts::Transaction *state, Client::Request *req)
- {
- Url::_initialize(state);
-
- _bufp = req->BufP();
- _hdr_loc = req->MLoc();
- }
+ protected:
+ void _initialize() override;
}; // End class Cache::URL
@@ -755,17 +772,10 @@ namespace Parent
void operator=(const self_type &) = delete;
static self_type &_get(cripts::Context *context);
- bool _update(cripts::Context *context);
-
- private:
- void
- _initialize(cripts::Transaction *state, Client::Request *req)
- {
- Url::_initialize(state);
+ bool Update();
- _bufp = req->BufP();
- _hdr_loc = req->MLoc();
- }
+ protected:
+ void _initialize() override;
}; // End class Cache::URL
@@ -776,6 +786,21 @@ namespace Parent
// Formatters for {fmt}
namespace fmt
{
+template <std::derived_from<cripts::Url> T> struct formatter<T> {
+ constexpr auto
+ parse(format_parse_context &ctx) -> decltype(ctx.begin())
+ {
+ return ctx.begin();
+ }
+
+ template <typename FormatContext>
+ auto
+ format(T &url, FormatContext &ctx) const -> decltype(ctx.out())
+ {
+ return fmt::format_to(ctx.out(), "{}", url.String());
+ }
+};
+
template <> struct formatter<cripts::Url::Scheme> {
constexpr auto
parse(format_parse_context &ctx) -> decltype(ctx.begin())
diff --git a/src/cripts/Connections.cc b/src/cripts/Connections.cc
index 98001cb03d..eac1c223f0 100644
--- a/src/cripts/Connections.cc
+++ b/src/cripts/Connections.cc
@@ -30,7 +30,7 @@ const cripts::Matcher::Range::IP
cripts::Net::RFC1918({"10.0.0.0/8", "172.16.0.0
void
detail::ConnBase::Pacing::operator=(uint32_t val)
{
- TSAssert(_owner);
+ _ensure_initialized(_owner);
if (val == 0) {
val = Off;
}
@@ -51,6 +51,7 @@ void
detail::ConnBase::TcpInfo::initialize()
{
#if defined(TCP_INFO) && defined(HAVE_STRUCT_TCP_INFO)
+ _ensure_initialized(_owner);
if (!_ready) {
int connfd = _owner->FD();
@@ -70,6 +71,7 @@ detail::ConnBase::TcpInfo::initialize()
cripts::string_view
detail::ConnBase::TcpInfo::Log()
{
+ _ensure_initialized(_owner);
initialize();
// We intentionally do not use the old tcpinfo that may be stored, since we
may
// request this numerous times (measurements). Also make sure there's always
a value.
@@ -205,18 +207,19 @@ IP::Sample(double rate, uint32_t seed, unsigned
ipv4_cidr, unsigned ipv6_cidr)
Client::Connection &
Client::Connection::_get(cripts::Context *context)
{
- Client::Connection *conn = &context->_client_conn;
-
- if (!conn->Initialized()) {
- TSAssert(context->state.ssnp);
- TSAssert(context->state.txnp);
+ _ensure_initialized(&context->_client.connection);
+ return context->_client.connection;
+}
- conn->_state = &context->state;
- conn->_vc = TSHttpSsnClientVConnGet(context->state.ssnp);
- conn->_socket = TSHttpTxnClientAddrGet(context->state.txnp);
- }
+void
+Client::Connection::_initialize()
+{
+ TSAssert(_state->ssnp);
+ TSAssert(_state->txnp);
- return context->_client_conn;
+ _vc = TSHttpSsnClientVConnGet(_state->ssnp);
+ _socket = TSHttpTxnClientAddrGet(_state->txnp);
+ super_type::_initialize();
}
int
@@ -233,27 +236,25 @@ Client::Connection::FD() const
int
Client::Connection::Count() const
{
- TSHttpSsn ssn = TSHttpTxnSsnGet(_state->txnp);
-
- TSAssert(_state->txnp);
-
- return ssn ? TSHttpSsnTransactionCount(ssn) : -1;
+ TSAssert(_state->ssnp);
+ return TSHttpSsnTransactionCount(_state->ssnp);
}
Server::Connection &
Server::Connection::_get(cripts::Context *context)
{
- cripts::Server::Connection *conn = &context->_server_conn;
-
- if (!conn->Initialized()) {
- TSAssert(context->state.ssnp);
+ _ensure_initialized(&context->_server.connection);
+ return context->_server.connection;
+}
- conn->_state = &context->state;
- conn->_vc = TSHttpSsnServerVConnGet(context->state.ssnp);
- conn->_socket = TSHttpTxnServerAddrGet(context->state.txnp);
- }
+void
+Server::Connection::_initialize()
+{
+ TSAssert(_state->ssnp);
- return context->_server_conn;
+ _vc = TSHttpSsnServerVConnGet(_state->ssnp);
+ _socket = TSHttpTxnServerAddrGet(_state->txnp);
+ super_type::_initialize();
}
int
@@ -270,6 +271,7 @@ Server::Connection::FD() const
int
Server::Connection::Count() const
{
+ TSAssert(_state->txnp);
return TSHttpTxnServerSsnTransactionCount(_state->txnp);
}
diff --git a/src/cripts/Context.cc b/src/cripts/Context.cc
index 0359aa4c8d..536f8bfde2 100644
--- a/src/cripts/Context.cc
+++ b/src/cripts/Context.cc
@@ -35,28 +35,28 @@ Context::reset()
// Clear the initialized headers before calling next hook
// Note: we don't clear the pristine URL, nor the Remap From/To URLs, they
are static.
// We also don't clear the client URL, since it's from the RRI.
- if (_client_resp_header.Initialized()) {
- _client_resp_header.Reset();
+ if (_client.response.Initialized()) {
+ _client.response.Reset();
}
- if (_server_resp_header.Initialized()) {
- _server_resp_header.Reset();
+ if (_server.response.Initialized()) {
+ _server.response.Reset();
}
- if (_client_req_header.Initialized()) {
- _client_req_header.Reset();
+ if (_client.request.Initialized()) {
+ _client.request.Reset();
}
- if (_server_req_header.Initialized()) {
- _server_req_header.Reset();
+ if (_server.request.Initialized()) {
+ _server.request.Reset();
}
// Clear the initialized URLs before calling next hook
- if (_pristine_url.Initialized()) {
- _pristine_url.Reset();
+ if (_urls.pristine.Initialized()) {
+ _urls.pristine.Reset();
}
- if (_cache_url.Initialized()) {
- _cache_url.Reset();
+ if (_urls.cache.Initialized()) {
+ _urls.cache.Reset();
}
- if (_parent_url.Initialized()) {
- _parent_url.Reset();
+ if (_urls.parent.Initialized()) {
+ _urls.parent.Reset();
}
}
diff --git a/src/cripts/Headers.cc b/src/cripts/Headers.cc
index 8c8e704799..5b199cfe0a 100644
--- a/src/cripts/Headers.cc
+++ b/src/cripts/Headers.cc
@@ -45,6 +45,7 @@ namespace Method
Header::Status &
Header::Status::operator=(int status)
{
+ _ensure_initialized(_owner);
_status = static_cast<TSHttpStatus>(status);
switch (_owner->_state->hook) {
@@ -66,6 +67,7 @@ Header::Status::operator=(int status)
Header::Status::operator integer()
{
if (_status == TS_HTTP_STATUS_NONE) {
+ _ensure_initialized(_owner);
_status = TSHttpHdrStatusGet(_owner->_bufp, _owner->_hdr_loc);
}
return _status;
@@ -74,6 +76,7 @@ Header::Status::operator integer()
Header::Reason &
Header::Reason::operator=(cripts::string_view reason)
{
+ _ensure_initialized(_owner);
TSHttpHdrReasonSet(_owner->_bufp, _owner->_hdr_loc, reason.data(),
reason.size());
_owner->_state->context->p_instance.debug("Setting reason = {}", reason);
@@ -85,6 +88,7 @@ Header::Body::operator=(cripts::string_view body)
{
auto b = static_cast<char *>(TSmalloc(body.size() + 1));
+ _ensure_initialized(_owner);
memcpy(b, body.data(), body.size());
b[body.size()] = '\0';
TSHttpTxnErrorBodySet(_owner->_state->txnp, b, body.size(), nullptr);
@@ -96,6 +100,7 @@ cripts::string_view
Header::Method::GetSV()
{
if (_method.size() == 0) {
+ _ensure_initialized(_owner);
int len;
const char *value = TSHttpHdrMethodGet(_owner->_bufp, _owner->_hdr_loc,
&len);
@@ -116,6 +121,7 @@ Header::CacheStatus::GetSV()
};
int status;
+ _ensure_initialized(_owner);
if (_cache.size() == 0) {
TSAssert(_owner->_state->txnp);
if (TSHttpTxnCacheLookupStatusGet(_owner->_state->txnp, &status) ==
TS_ERROR || status < 0 || status >= 4) {
@@ -131,6 +137,7 @@ Header::CacheStatus::GetSV()
Header::String &
Header::String::operator=(const cripts::string_view str)
{
+ _ensure_initialized(_owner);
if (_field_loc) {
if (str.empty()) {
TSMLoc tmp;
@@ -183,6 +190,7 @@ Header::String::operator=(const cripts::string_view str)
Header::String &
Header::String::operator=(integer val)
{
+ _ensure_initialized(_owner);
if (_field_loc) {
TSMLoc tmp = nullptr;
bool first = true;
@@ -218,6 +226,7 @@ Header::String::operator=(integer val)
Header::String &
Header::String::operator+=(const cripts::string_view str)
{
+ _ensure_initialized(_owner);
if (_field_loc) {
if (!str.empty()) {
// Drop the old field loc for now ... ToDo: Oh well, we need to figure
out how to handle multi-value headers better
@@ -242,6 +251,7 @@ Header::String::operator+=(const cripts::string_view str)
Header::String
Header::operator[](const cripts::string_view str)
{
+ _ensure_initialized(this);
TSAssert(_bufp && _hdr_loc);
TSMLoc field_loc = TSMimeHdrFieldFind(_bufp, _hdr_loc, str.data(),
str.size());
@@ -262,23 +272,26 @@ Header::operator[](const cripts::string_view str)
Client::Request &
Client::Request::_get(cripts::Context *context)
{
- Client::Request *request = &context->_client_req_header;
+ _ensure_initialized(&context->_client.request);
+ return context->_client.request;
+}
- if (!request->Initialized()) {
- TSAssert(context->state.txnp);
- if (TSHttpTxnClientReqGet(context->state.txnp, &request->_bufp,
&request->_hdr_loc) != TS_SUCCESS) {
- context->state.error.Fail();
- } else {
- request->_initialize(&context->state); // Don't initialize unless
properly setup
- }
- }
+void
+Client::Request::_initialize()
+{
+ TSAssert(_state->txnp);
- return context->_client_req_header;
+ if (TSHttpTxnClientReqGet(_state->txnp, &_bufp, &_hdr_loc) != TS_SUCCESS) {
+ _state->error.Fail();
+ } else {
+ super_type::_initialize(); // Don't initialize unless properly setup
+ }
}
Header::Iterator
Header::begin()
{
+ _ensure_initialized(this);
// Cleanup any lingering iterator state
if (_iterator_loc) {
TSHandleMLocRelease(_bufp, _hdr_loc, _iterator_loc);
@@ -304,6 +317,7 @@ Header::begin()
cripts::string_view
Header::iterate()
{
+ _ensure_initialized(this);
TSMLoc next_loc = TSMimeHdrFieldNext(_bufp, _hdr_loc, _iterator_loc);
TSHandleMLocRelease(_bufp, _hdr_loc, _iterator_loc);
@@ -319,69 +333,76 @@ Header::iterate()
}
}
-cripts::Client::Response &
+Client::Response &
Client::Response::_get(cripts::Context *context)
{
- CAssert(context->state.hook != TS_HTTP_READ_REQUEST_HDR_HOOK);
- CAssert(context->state.hook != TS_HTTP_POST_REMAP_HOOK);
- CAssert(context->state.hook != TS_HTTP_SEND_REQUEST_HDR_HOOK);
+ _ensure_initialized(&context->_client.response);
+ return context->_client.response;
+}
- Client::Response *response = &context->_client_resp_header;
+void
+Client::Response::_initialize()
+{
+ CAssert(_state->hook != TS_HTTP_READ_REQUEST_HDR_HOOK);
+ CAssert(_state->hook != TS_HTTP_POST_REMAP_HOOK);
+ CAssert(_state->hook != TS_HTTP_SEND_REQUEST_HDR_HOOK);
- if (!response->Initialized()) {
- TSAssert(context->state.txnp);
- if (TSHttpTxnClientRespGet(context->state.txnp, &response->_bufp,
&response->_hdr_loc) != TS_SUCCESS) {
- context->state.error.Fail();
- } else {
- response->_initialize(&context->state); // Don't initialize unless
properly setup
- }
- }
+ TSAssert(_state->txnp);
- return context->_client_resp_header;
+ if (TSHttpTxnClientRespGet(_state->txnp, &_bufp, &_hdr_loc) != TS_SUCCESS) {
+ _state->error.Fail();
+ } else {
+ super_type::_initialize(); // Don't initialize unless properly setup
+ }
}
Server::Request &
Server::Request::_get(cripts::Context *context)
{
- CAssert(context->state.hook != TS_HTTP_READ_REQUEST_HDR_HOOK);
- CAssert(context->state.hook != TS_HTTP_POST_REMAP_HOOK);
- CAssert(context->state.hook != TS_HTTP_CACHE_LOOKUP_COMPLETE_HOOK);
- CAssert(context->state.hook != TS_HTTP_READ_RESPONSE_HDR_HOOK);
-
- Server::Request *request = &context->_server_req_header;
+ _ensure_initialized(&context->_server.request);
+ return context->_server.request;
+}
- if (!request->Initialized()) {
- TSAssert(context->state.txnp);
- if (TSHttpTxnServerReqGet(context->state.txnp, &request->_bufp,
&request->_hdr_loc) != TS_SUCCESS) {
- context->state.error.Fail();
+void
+Server::Request::_initialize()
+{
+ CAssert(_state->hook != TS_HTTP_READ_REQUEST_HDR_HOOK);
+ CAssert(_state->hook != TS_HTTP_POST_REMAP_HOOK);
+ CAssert(_state->hook != TS_HTTP_CACHE_LOOKUP_COMPLETE_HOOK);
+ CAssert(_state->hook != TS_HTTP_READ_RESPONSE_HDR_HOOK);
+
+ if (!Initialized()) {
+ TSAssert(_state->txnp);
+ if (TSHttpTxnServerReqGet(_state->txnp, &_bufp, &_hdr_loc) != TS_SUCCESS) {
+ _state->error.Fail();
} else {
- request->_initialize(&context->state); // Don't initialize unless
properly setup
+ super_type::_initialize(); // Don't initialize unless properly setup
}
}
-
- return context->_server_req_header;
}
Server::Response &
Server::Response::_get(cripts::Context *context)
{
- CAssert(context->state.hook != TS_HTTP_READ_REQUEST_HDR_HOOK);
- CAssert(context->state.hook != TS_HTTP_POST_REMAP_HOOK);
- CAssert(context->state.hook != TS_HTTP_CACHE_LOOKUP_COMPLETE_HOOK);
- CAssert(context->state.hook != TS_HTTP_SEND_REQUEST_HDR_HOOK);
+ _ensure_initialized(&context->_server.response);
+ return context->_server.response;
+}
+
+void
+Server::Response::_initialize()
+{
+ CAssert(_state->hook != TS_HTTP_READ_REQUEST_HDR_HOOK);
+ CAssert(_state->hook != TS_HTTP_POST_REMAP_HOOK);
+ CAssert(_state->hook != TS_HTTP_CACHE_LOOKUP_COMPLETE_HOOK);
+ CAssert(_state->hook != TS_HTTP_SEND_REQUEST_HDR_HOOK);
- Server::Response *response = &context->_server_resp_header;
+ TSAssert(_state->txnp);
- if (!response->Initialized()) {
- TSAssert(context->state.txnp);
- if (TSHttpTxnServerRespGet(context->state.txnp, &response->_bufp,
&response->_hdr_loc) != TS_SUCCESS) {
- context->state.error.Fail();
- } else {
- response->_initialize(&context->state); // Don't initialize unless
properly setup
- }
+ if (TSHttpTxnServerRespGet(_state->txnp, &_bufp, &_hdr_loc) != TS_SUCCESS) {
+ _state->error.Fail();
+ } else {
+ super_type::_initialize(); // Don't initialize unless properly setup
}
-
- return context->_server_resp_header;
}
} // namespace cripts
diff --git a/src/cripts/Urls.cc b/src/cripts/Urls.cc
index 9d0423371a..749b802602 100644
--- a/src/cripts/Urls.cc
+++ b/src/cripts/Urls.cc
@@ -36,6 +36,7 @@ Url::Scheme::GetSV()
const char *value = nullptr;
int len = 0;
+ _ensure_initialized(_owner);
value = TSUrlSchemeGet(_owner->_bufp, _owner->_urlp, &len);
_data = cripts::string_view(value, len);
}
@@ -47,6 +48,7 @@ Url::Scheme
Url::Scheme::operator=(cripts::string_view scheme)
{
CAssert(!_owner->ReadOnly()); // This can not be a read-only URL
+ _ensure_initialized(_owner);
TSUrlSchemeSet(_owner->_bufp, _owner->_urlp, scheme.data(), scheme.size());
_owner->_modified = true;
Reset();
@@ -62,6 +64,7 @@ Url::Host::GetSV()
const char *value = nullptr;
int len = 0;
+ _ensure_initialized(_owner);
value = TSUrlHostGet(_owner->_bufp, _owner->_urlp, &len);
_data = cripts::string_view(value, len);
_loaded = true;
@@ -73,6 +76,7 @@ Url::Host::GetSV()
Url::Host
Url::Host::operator=(cripts::string_view host)
{
+ _ensure_initialized(_owner);
CAssert(!_owner->ReadOnly()); // This can not be a read-only URL
TSUrlHostSet(_owner->_bufp, _owner->_urlp, host.data(), host.size());
_owner->_modified = true;
@@ -84,6 +88,7 @@ Url::Host::operator=(cripts::string_view host)
Url::Port::operator integer() // This should not be explicit
{
+ _ensure_initialized(_owner);
if (_owner && _port < 0) {
_port = TSUrlPortGet(_owner->_bufp, _owner->_urlp);
}
@@ -94,6 +99,7 @@ Url::Port::operator integer() // This should not be explicit
Url::Port
Url::Port::operator=(int port)
{
+ _ensure_initialized(_owner);
CAssert(!_owner->ReadOnly()); // This can not be a read-only URL
TSUrlPortSet(_owner->_bufp, _owner->_urlp, port);
_owner->_modified = true;
@@ -120,6 +126,7 @@ Url::Path::GetSV()
const char *value = nullptr;
int len = 0;
+ _ensure_initialized(_owner);
value = TSUrlPathGet(_owner->_bufp, _owner->_urlp, &len);
_data = cripts::string_view(value, len);
_size = len;
@@ -134,6 +141,7 @@ Url::Path::operator[](Segments::size_type ix)
{
Url::Path::String ret;
+ _ensure_initialized(_owner);
_parser(); // Make sure the segments are loaded
if (ix < _segments.size()) {
ret._initialize(_segments[ix], this, ix);
@@ -145,6 +153,7 @@ Url::Path::operator[](Segments::size_type ix)
Url::Path
Url::Path::operator=(cripts::string_view path)
{
+ _ensure_initialized(_owner);
CAssert(!_owner->ReadOnly()); // This can not be a read-only URL
TSUrlPathSet(_owner->_bufp, _owner->_urlp, path.data(), path.size());
_owner->_modified = true;
@@ -171,6 +180,7 @@ Url::Path::operator+=(cripts::string_view add)
Url::Path::String &
Url::Path::String::operator=(const cripts::string_view str)
{
+ _ensure_initialized(_owner->_owner);
CAssert(!_owner->_owner->ReadOnly()); // This can not be a read-only URL
_owner->_size -= _owner->_segments[_ix].size();
_owner->_segments[_ix] = str;
@@ -218,6 +228,7 @@ Url::Path::_parser()
Url::Query::Parameter &
Url::Query::Parameter::operator=(const cripts::string_view str)
{
+ _ensure_initialized(_owner->_owner);
CAssert(!_owner->_owner->ReadOnly()); // This can not be a read-only URL
auto iter = _owner->_hashed.find(_name);
@@ -235,6 +246,7 @@ Url::Query::Parameter::operator=(const cripts::string_view
str)
cripts::string_view
Url::Query::GetSV()
{
+ _ensure_initialized(_owner);
if (_ordered.size() > 0) {
_storage.clear();
_storage.reserve(_size);
@@ -278,6 +290,7 @@ Url::Query::GetSV()
Url::Query
Url::Query::operator=(cripts::string_view query)
{
+ _ensure_initialized(_owner);
CAssert(!_owner->ReadOnly()); // This can not be a read-only URL
TSUrlHttpQuerySet(_owner->_bufp, _owner->_urlp, query.data(), query.size());
_owner->_modified = true;
@@ -305,6 +318,7 @@ Url::Query::Parameter
Url::Query::operator[](cripts::string_view param)
{
// Make sure the hash and vector are populated
+ _ensure_initialized(_owner);
_parser();
Parameter ret;
@@ -406,18 +420,18 @@ Url::Query::_parser()
}
cripts::string
-Url::String() const
+Url::String()
{
cripts::string ret;
- if (_state) {
- int full_len = 0;
- char *full_str = TSUrlStringGet(_bufp, _urlp, &full_len);
+ CAssert(_context);
+ _ensure_initialized(this);
+ int full_len = 0;
+ char *full_str = TSUrlStringGet(_bufp, _urlp, &full_len);
- if (full_str) {
- ret.assign(full_str, full_len);
- TSfree(static_cast<void *>(full_str));
- }
+ if (full_str) {
+ ret.assign(full_str, full_len);
+ TSfree(static_cast<void *>(full_str));
}
return ret;
@@ -426,37 +440,41 @@ Url::String() const
Pristine::URL &
Pristine::URL::_get(cripts::Context *context)
{
- if (!context->_pristine_url.Initialized()) {
- Pristine::URL *url = &context->_pristine_url;
+ _ensure_initialized(&context->_urls.pristine);
+ return context->_urls.pristine;
+}
- TSAssert(context->state.txnp);
- if (TSHttpTxnPristineUrlGet(context->state.txnp, &url->_bufp, &url->_urlp)
!= TS_SUCCESS) {
- context->state.error.Fail();
- } else {
- url->_initialize(&context->state);
- }
- }
+void
+Pristine::URL::_initialize()
+{
+ Pristine::URL *url = &_context->_urls.pristine;
- return context->_pristine_url;
+ TSAssert(_context->state.txnp);
+ if (TSHttpTxnPristineUrlGet(_context->state.txnp, &url->_bufp, &url->_urlp)
!= TS_SUCCESS) {
+ _context->state.error.Fail();
+ } else {
+ super_type::_initialize(); // Only if successful
+ }
}
void
-Client::URL::_initialize(cripts::Context *context)
+Client::URL::_initialize()
{
- Url::_initialize(&context->state);
-
- if (context->rri) {
- _bufp = context->rri->requestBufp;
- _hdr_loc = context->rri->requestHdrp;
- _urlp = context->rri->requestUrl;
+ if (_context->rri) {
+ _bufp = _context->rri->requestBufp;
+ _hdr_loc = _context->rri->requestHdrp;
+ _urlp = _context->rri->requestUrl;
+ super_type::_initialize();
} else {
- Client::Request &req = Client::Request::_get(context); // Repurpose /
create the shared request object
+ Client::Request &req = Client::Request::_get(_context); // Repurpose /
create the shared request object
_bufp = req.BufP();
_hdr_loc = req.MLoc();
if (TSHttpHdrUrlGet(_bufp, _hdr_loc, &_urlp) != TS_SUCCESS) {
- context->state.error.Fail();
+ _context->state.error.Fail();
+ } else {
+ super_type::_initialize();
}
}
}
@@ -464,16 +482,14 @@ Client::URL::_initialize(cripts::Context *context)
Client::URL &
Client::URL::_get(cripts::Context *context)
{
- if (!context->_client_url.Initialized()) {
- context->_client_url._initialize(context);
- }
-
- return context->_client_url;
+ _ensure_initialized(&context->_urls.request);
+ return context->_urls.request;
}
bool
-Client::URL::_update(cripts::Context * /* context ATS_UNUSED */)
+Client::URL::_update()
{
+ _ensure_initialized(this);
path.Flush();
query.Flush();
@@ -481,103 +497,106 @@ Client::URL::_update(cripts::Context * /* context
ATS_UNUSED */)
}
void
-Remap::From::URL::_initialize(cripts::Context *context)
+Remap::From::URL::_initialize()
{
- Url::_initialize(&context->state);
-
- _bufp = context->rri->requestBufp;
- _hdr_loc = context->rri->requestHdrp;
- _urlp = context->rri->mapFromUrl;
+ super_type::_initialize();
+ _bufp = _context->rri->requestBufp;
+ _hdr_loc = _context->rri->requestHdrp;
+ _urlp = _context->rri->mapFromUrl;
}
Remap::From::URL &
Remap::From::URL::_get(cripts::Context *context)
{
- if (!context->_remap_from_url.Initialized()) {
- context->_remap_from_url._initialize(context);
- }
-
- return context->_remap_from_url;
+ _ensure_initialized(&context->_urls.remap.from);
+ return context->_urls.remap.from;
}
void
-Remap::To::URL::_initialize(cripts::Context *context)
+Remap::To::URL::_initialize()
{
- Url::_initialize(&context->state);
+ super_type::_initialize();
- _bufp = context->rri->requestBufp;
- _hdr_loc = context->rri->requestHdrp;
- _urlp = context->rri->mapToUrl;
+ _bufp = _context->rri->requestBufp;
+ _hdr_loc = _context->rri->requestHdrp;
+ _urlp = _context->rri->mapToUrl;
}
Remap::To::URL &
Remap::To::URL::_get(cripts::Context *context)
{
- if (!context->_remap_to_url.Initialized()) {
- context->_remap_to_url._initialize(context);
- }
-
- return context->_remap_to_url;
+ _ensure_initialized(&context->_urls.remap.to);
+ return context->_urls.remap.to;
}
Cache::URL &
Cache::URL::_get(cripts::Context *context)
{
- if (!context->_cache_url.Initialized()) {
- Cache::URL *url = &context->_cache_url;
- Client::Request &req = Client::Request::_get(context); // Repurpose /
create the shared request object
-
- switch (context->state.hook) {
- // In these hooks, the internal cache-url has been properly set
- case TS_HTTP_SEND_RESPONSE_HDR_HOOK:
- case TS_HTTP_READ_RESPONSE_HDR_HOOK:
- case TS_HTTP_SEND_REQUEST_HDR_HOOK:
- case TS_HTTP_TXN_CLOSE_HOOK:
- if (TSUrlCreate(req.BufP(), &url->_urlp) == TS_SUCCESS) {
- TSAssert(context->state.txnp);
- if (TSHttpTxnCacheLookupUrlGet(context->state.txnp, req.BufP(),
url->_urlp) == TS_SUCCESS) {
- url->_initialize(&context->state, &req);
- }
- } else {
- context->state.error.Fail();
- }
- break;
- default: { // This means we have to clone. ToDo: For now, this is
implicitly using Client::URL
- Client::URL &src = Client::URL::_get(context);
+ _ensure_initialized(&context->_urls.cache);
+ return context->_urls.cache;
+}
- if (TSUrlClone(req.BufP(), req.BufP(), src.UrlP(), &url->_urlp) ==
TS_SUCCESS) {
- url->_initialize(&context->state, &req);
- } else {
- context->state.error.Fail();
+void
+Cache::URL::_initialize()
+{
+ Cache::URL *url = &_context->_urls.cache;
+ Client::Request &req = Client::Request::_get(_context); // Repurpose /
create the shared request object
+
+ switch (_context->state.hook) {
+ // In these hooks, the internal cache-url has been properly set
+ case TS_HTTP_SEND_RESPONSE_HDR_HOOK:
+ case TS_HTTP_READ_RESPONSE_HDR_HOOK:
+ case TS_HTTP_SEND_REQUEST_HDR_HOOK:
+ case TS_HTTP_TXN_CLOSE_HOOK:
+ if (TSUrlCreate(req.BufP(), &url->_urlp) == TS_SUCCESS) {
+ TSAssert(_context->state.txnp);
+ if (TSHttpTxnCacheLookupUrlGet(_context->state.txnp, req.BufP(),
url->_urlp) != TS_SUCCESS) {
+ _context->state.error.Fail();
+ return;
}
- } break;
+ } else {
+ _context->state.error.Fail();
+ return;
}
+ break;
+ default: { // This means we have to clone. ToDo: For now, this is implicitly
using Client::URL
+ Client::URL &src = Client::URL::_get(_context);
+
+ if (TSUrlClone(req.BufP(), req.BufP(), src.UrlP(), &url->_urlp) !=
TS_SUCCESS) {
+ _context->state.error.Fail();
+ return;
+ }
+ } break;
}
- return context->_cache_url;
+ // Only if we succeeded above
+ super_type::_initialize();
+ _bufp = req.BufP();
+ _hdr_loc = req.MLoc();
}
// This has to be implemented here, since the cripts::Context is not complete
yet
bool
-Cache::URL::_update(cripts::Context *context)
+Cache::URL::_update()
{
// For correctness, we will also make sure the Path and Query objects are
flushed
path.Flush();
query.Flush();
if (_modified) {
- TSAssert(context->state.txnp);
+ _ensure_initialized(&_context->_urls.cache);
+ TSAssert(_context->state.txnp);
_modified = false;
- if (TS_SUCCESS == TSHttpTxnCacheLookupUrlSet(context->state.txnp, _bufp,
_urlp)) {
- if (context->p_instance.DebugOn()) {
- context->p_instance.debug("Successfully setting cache-key to {}",
String());
+ if (TS_SUCCESS == TSHttpTxnCacheLookupUrlSet(_context->state.txnp, _bufp,
_urlp)) {
+ if (_context->p_instance.DebugOn()) {
+ _context->p_instance.debug("Successfully setting cache-key to {}",
String());
}
return true;
} else {
- if (context->p_instance.DebugOn()) {
- context->p_instance.debug("Could not set the cache key to {}",
String());
+ if (_context->p_instance.DebugOn()) {
+ _context->p_instance.debug("Could not set the cache key to {}",
String());
}
- context->state.error.Fail();
+ _context->state.error.Fail();
return false;
}
}
@@ -589,21 +608,31 @@ Cache::URL::_update(cripts::Context *context)
Parent::URL &
Parent::URL::_get(cripts::Context *context)
{
- if (!context->_cache_url.Initialized()) {
- Parent::URL *url = &context->_parent_url;
- Client::Request &req = Client::Request::_get(context); // Repurpose /
create the shared request object
+ _ensure_initialized(&context->_urls.parent);
+ return context->_urls.parent;
+}
- if (TSUrlCreate(req.BufP(), &url->_urlp) == TS_SUCCESS) {
- TSAssert(context->state.txnp);
- if (TSHttpTxnParentSelectionUrlGet(context->state.txnp, req.BufP(),
url->_urlp) == TS_SUCCESS) {
- url->_initialize(&context->state, &req);
- }
- } else {
- context->state.error.Fail();
+void
+Parent::URL::_initialize()
+{
+ Parent::URL *url = &_context->_urls.parent;
+ Client::Request &req = Client::Request::_get(_context); // Repurpose /
create the shared request object
+
+ if (TSUrlCreate(req.BufP(), &url->_urlp) == TS_SUCCESS) {
+ TSAssert(_context->state.txnp);
+ if (TSHttpTxnParentSelectionUrlGet(_context->state.txnp, req.BufP(),
url->_urlp) != TS_SUCCESS) {
+ _context->state.error.Fail();
+ return;
}
+ } else {
+ _context->state.error.Fail();
+ return;
}
- return context->_parent_url;
+ // Only if successful above
+ super_type::_initialize();
+ _bufp = req.BufP();
+ _hdr_loc = req.MLoc();
}
} // namespace cripts