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

Reply via email to