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 a3b78a2ddb Cripts: Refactor the cache key / URL APIs (#12377)
a3b78a2ddb is described below
commit a3b78a2ddba574c353015b9a9e70e715ac68ec26
Author: Leif Hedstrom <[email protected]>
AuthorDate: Thu Aug 14 21:56:38 2025 +0000
Cripts: Refactor the cache key / URL APIs (#12377)
* Cripts: Refactor the cache key / URL APIs
- cleans up the notion around cached URLs and headers, and cache keys.
- adds APIs to set the lookup status as well
* Address review comments
---
.../cripts/cripts-convenience.en.rst | 3 +-
doc/developer-guide/cripts/cripts-headers.en.rst | 35 ++++--
doc/developer-guide/cripts/cripts-misc.en.rst | 16 +--
example/cripts/example1.cc | 9 +-
example/cripts/example2.cc | 8 +-
include/cripts/Context.hpp | 20 +++-
include/cripts/Epilogue.hpp | 12 +-
include/cripts/Headers.hpp | 123 ++++++++++++---------
include/cripts/Instance.hpp | 2 +-
include/cripts/Lulu.hpp | 7 ++
include/cripts/Matcher.hpp | 4 +-
include/cripts/Preamble.hpp | 6 +-
include/cripts/Time.hpp | 70 +++++++++++-
include/cripts/Transaction.hpp | 12 --
include/cripts/Urls.hpp | 4 +-
src/cripts/Bundles/LogsMetrics.cc | 15 +--
src/cripts/Context.cc | 6 +-
src/cripts/Headers.cc | 110 ++++++++++++++----
src/cripts/Urls.cc | 16 +--
19 files changed, 324 insertions(+), 154 deletions(-)
diff --git a/doc/developer-guide/cripts/cripts-convenience.en.rst
b/doc/developer-guide/cripts/cripts-convenience.en.rst
index 03d3cca0de..7a93931364 100644
--- a/doc/developer-guide/cripts/cripts-convenience.en.rst
+++ b/doc/developer-guide/cripts/cripts-convenience.en.rst
@@ -72,9 +72,10 @@ Object Traditional API equivalent
``server.request`` ``borrow cripts::Server::Request::Get()``
``server.response`` ``borrow cripts::Server::Response::Get()``
``server.connection`` ``borrow cripts::Server::Connection::Get()``
+``cached.url`` ``borrow cripts::Cache::URL::Get()``
+``cached.response`` ``borrow cripts::Cache::Response::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()``
diff --git a/doc/developer-guide/cripts/cripts-headers.en.rst
b/doc/developer-guide/cripts/cripts-headers.en.rst
index 2c5e01881d..66ff13df09 100644
--- a/doc/developer-guide/cripts/cripts-headers.en.rst
+++ b/doc/developer-guide/cripts/cripts-headers.en.rst
@@ -43,6 +43,7 @@ Header Object Description
``cripts::Client::Response`` The client response headers.
``cripts::Server::Request`` The server request headers.
``cripts::Server::Response`` The server response headers.
+``cripts::Cache::Response`` The cached response headers (immutable and
conditional).
=============================
===========================================================================
.. note::
@@ -50,6 +51,8 @@ Header Object Description
For all of these headers, except the ``cripts::Client::Request``, the
headers are not
available until the respective hook is called. For example, the
``cripts::Client::Response`` headers
are not available until the response headers are received from the origin
server or cache lookup.
+ The ``cripts::Cache::Response`` header is also immutable, and can only be
used after a successful
+ cache lookup.
Assigning the empty value (``""``) to a header will remove it from the header
list. For example:
@@ -135,16 +138,34 @@ Member Description
==========================
======================================================================
``status`` The status code of the response. E.g. ``200``.
``reason`` The reason phrase of the response. E.g. ``OK``.
-``cache`` The cache status of the response. E.g. ``miss``.
==========================
======================================================================
-Of these, the first two are pretty self explanatory, but the ``cache`` status
is a bit more
-complex. This is a string that represents the cache status of the response.
The possible values
-are:
+
+Lookup Status
+-------------
+
+The ``Cache::Response`` header also hold the status of the cache lookup, in a
member named
+``cachelookup``. This is an integer value that represents the status of the
cache lookup.
+The possible values are:
+
+===============================
======================================================================
+Value Description
+===============================
======================================================================
+``LookupStatus::NONE`` (-1) No lookup status available.
+``LookupStatus::MISS`` (0) The response was not found in the cache.
+``LookupStatus::HIT_STALE`` (1) The response was found in the cache, but it
was stale.
+``LookupStatus::HIT_FRESH`` (2) The response was found in the cache and is
fresh.
+``LookupStatus::SKIPPED`` (3) We skipped cache lookup completely
+===============================
======================================================================
+
+A string representation of the cache lookup status is also available in in the
``lookupstatus`` member,
+via an implicit conversion to a string
+
==========================
======================================================================
Value Description
==========================
======================================================================
+``none`` No lookup status available.
``miss`` The response was not found in the cache.
``hit-stale`` The response was found in the cache, but it was
stale.
``hit-fresh`` The response was found in the cache and is fresh.
@@ -152,14 +173,14 @@ Value Description
==========================
======================================================================
This status can be used to determine if the response was found in the cache,
and if so, if it was
-fresh or stale. Example usage of the cache status:
+fresh or stale. Example usage of the cache lookup status:
.. code-block:: cpp
do_read_response() {
- borrow resp = cripts::Server::Response::Get();
+ borrow cached = cripts::Cache::Response::Get();
- if (resp.cache == "miss") {
+ if (cached.lookupstatus == cripts::LookupStatus::MISS) {
// Do something
}
}
diff --git a/doc/developer-guide/cripts/cripts-misc.en.rst
b/doc/developer-guide/cripts/cripts-misc.en.rst
index f7a37d09f1..dd582e6eda 100644
--- a/doc/developer-guide/cripts/cripts-misc.en.rst
+++ b/doc/developer-guide/cripts/cripts-misc.en.rst
@@ -88,7 +88,6 @@ Function Description
=========================
=======================================================================
``DisableCallback()`` Disables a future callback in this Cript, for this
transaction.
``Aborted()`` Has the transaction been aborted.
-``LookupStatus()`` Returns the cache lookup status for the
transaction.
=========================
=======================================================================
When disabling a callback, use the following names:
@@ -182,9 +181,9 @@ Example usage:
Time
====
-Cripts has encapsulated some common time-related functions in the core. At the
-moment only the localtime is available, via the ``cripts::Time::Local`` object
and its
-``Now()`` method. The ``Now()`` method returns the current time as an object
+Cripts has encapsulated some common time-related functions in the core. Two
different time objects
+are available, ``cripts::Time::Local`` and ``cripts::Time::UTC`` objects and
their respective
+``::Now()`` methods. The ``Now()`` method returns the current time as an object
with the following functions:
=====================
===========================================================================
@@ -199,10 +198,11 @@ Function Description
``Second()`` Returns the second (0-59).
``WeekDay()`` Returns the day of the week (0-6, Sunday is 0).
``YearDay()`` Returns the day of the year (0-365).
+``ToDate()`` Returns a string for the Date in HTTP header format
=====================
===========================================================================
The time as returned by ``Now()`` can also be used directly in comparisons
with previous or future
-times, and can be cast to an integer to get the epoch time.
+times. In addition, the ``Now()`` constructor can take an optional
``cripts::Time::Point`` argument.
Example usage:
@@ -212,12 +212,8 @@ Example usage:
{
auto now = cripts::Time::Local::Now();
- CDebug("Current time: year={}, month={}, day={}",
- now.Year(), now.Month(), now.Day());
+ CDebug("Current time: year={}, month={}, day={}", now.Year(),
now.Month(), now.Day());
CDebug("Epoch time: {}", now.Epoch());
-
- // Can also be used directly as integer
- integer epoch_time = now;
}
.. _cripts-misc-plugins:
diff --git a/example/cripts/example1.cc b/example/cripts/example1.cc
index a2361b5d51..fa1bcd8f06 100644
--- a/example/cripts/example1.cc
+++ b/example/cripts/example1.cc
@@ -79,16 +79,17 @@ do_read_response()
do_send_response()
{
- borrow resp = cripts::Client::Response::Get();
- borrow conn = cripts::Client::Connection::Get();
- string msg = "Eliminate TSCPP";
+ borrow resp = cripts::Client::Response::Get();
+ borrow conn = cripts::Client::Connection::Get();
+ borrow cached = cripts::Cache::Response::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-Cache-Status"] = cached.lookupstatus.GetSV();
resp["X-Integer"] = 666;
resp["X-Data"] = AsString(txn_data[2]);
diff --git a/example/cripts/example2.cc b/example/cripts/example2.cc
index ca6b88b125..c2b8d0185a 100644
--- a/example/cripts/example2.cc
+++ b/example/cripts/example2.cc
@@ -57,8 +57,8 @@ do_txn_close()
do_cache_lookup()
{
- CDebug("Cache URL: {}", urls.cache);
- CDebug("Cache Host: {}", urls.cache.host);
+ CDebug("Cache URL: {}", cached.url);
+ CDebug("Cache Host: {}", cached.url.host);
}
do_send_request()
@@ -80,7 +80,7 @@ do_send_response()
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-Cache-Status"] = cached.response.lookupstatus.GetSV();
client.response["X-Integer"] = 666;
client.response["X-Data"] = AsString(txn_data[2]);
@@ -118,7 +118,7 @@ do_send_response()
do_remap()
{
auto ip = client.connection.IP();
- auto now = TimeNow();
+ auto now = LocalTimeNow();
if (CRIPT_ALLOW.Match(ip)) {
CDebug("Client IP allowed: {}", ip.string(24, 64));
diff --git a/include/cripts/Context.hpp b/include/cripts/Context.hpp
index be2af90c39..4e00a26163 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), _client(this), _server(this),
_urls(this, _client.url)
+ : rri(rri_ptr), p_instance(inst), _client(this), _server(this),
_cache(this), _urls(this, _client.url)
{
state.txnp = txn_ptr;
state.ssnp = ssn_ptr;
@@ -76,8 +76,10 @@ public:
friend class Server::Request;
friend class Server::Response;
friend class Server::Connection;
- friend class Pristine::URL;
+ friend class Server::Response;
+ friend class Cache::Response;
friend class Cache::URL;
+ friend class Pristine::URL;
friend class Parent::URL;
friend class Plugin::Remap;
@@ -111,10 +113,21 @@ public:
} _server;
+ struct _CacheBlock {
+ cripts::Cache::Response response;
+ cripts::Cache::URL url;
+
+ _CacheBlock(Context *ctx)
+ {
+ response.set_state(&ctx->state);
+ url.set_context(ctx);
+ }
+
+ } _cache;
+
struct _UrlBlock {
cripts::Client::URL &request;
cripts::Pristine::URL pristine;
- cripts::Cache::URL cache;
cripts::Parent::URL parent;
struct {
@@ -126,7 +139,6 @@ public:
{
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);
diff --git a/include/cripts/Epilogue.hpp b/include/cripts/Epilogue.hpp
index d0d583032b..c729982898 100644
--- a/include/cripts/Epilogue.hpp
+++ b/include/cripts/Epilogue.hpp
@@ -581,8 +581,8 @@ http_txn_cont(TSCont contp, TSEvent event, void *edata)
}
if (!context->state.error.Failed()) {
- if (context->_urls.cache.Modified()) {
- context->_urls.cache._update(); // Make sure the cache-key gets
updated, if modified
+ if (context->_cache.url.Modified()) {
+ context->_cache.url._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
@@ -612,8 +612,8 @@ http_txn_cont(TSCont contp, TSEvent event, void *edata)
}
if (!context->state.error.Failed()) {
- if (context->_urls.cache.Modified()) {
- context->_urls.cache._update(); // Make sure the cache-key gets
updated, if modified
+ if (context->_cache.url.Modified()) {
+ context->_cache.url._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
@@ -899,8 +899,8 @@ TSRemapDoRemap(void *ih, TSHttpTxn txnp, TSRemapRequestInfo
*rri)
// Don't do the callbacks when we are in a failure state.
if (!context->state.error.Failed()) {
- if (context->_urls.cache.Modified()) {
- context->_urls.cache._update(); // Make sure the cache-key gets updated,
if modified
+ if (context->_cache.url.Modified()) {
+ context->_cache.url._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
diff --git a/include/cripts/Headers.hpp b/include/cripts/Headers.hpp
index f35a743fc8..b1010cf855 100644
--- a/include/cripts/Headers.hpp
+++ b/include/cripts/Headers.hpp
@@ -142,42 +142,6 @@ public:
}; // End class cripts::Header::Method
- class CacheStatus
- {
- using self_type = CacheStatus;
-
- public:
- CacheStatus() = delete;
- CacheStatus(Header *owner) : _owner(owner) {}
-
- cripts::string_view GetSV();
-
- operator cripts::string_view() { return GetSV(); }
-
- cripts::string_view::const_pointer
- Data()
- {
- return GetSV().data();
- }
-
- cripts::string_view::size_type
- Size()
- {
- return GetSV().size();
- }
-
- cripts::string_view::size_type
- Length()
- {
- return GetSV().size();
- }
-
- private:
- Header *_owner = nullptr;
- cripts::string_view _cache;
-
- }; // Class cripts::Header::CacheStatus
-
class String : public cripts::StringViewMixin<String>
{
using super_type = cripts::StringViewMixin<String>;
@@ -198,22 +162,19 @@ public:
self_type &operator=(integer val);
self_type &operator+=(const cripts::string_view str);
- // These specialized assignment operators all use the above
- template <size_t N>
- self_type &
- operator=(const char (&str)[N])
- {
- return operator=(cripts::string_view(str, str[N - 1] ? N : N - 1));
- }
+ // ToDo: This was useful at some point, but was breaking other useful
uses. Leaving
+ // it here for now for maybe future work.
+ // template <size_t N>
+ // self_type &
+ // operator=(const char (&str)[N])
+ //{
+ // return operator=(cripts::string_view(str, str[N - 1] ? N : N - 1));
+ //}
- self_type &
- operator=(char *&str)
- {
- return operator=(cripts::string_view(str, strlen(str)));
- }
+ self_type &operator=(std::nullptr_t) = delete;
self_type &
- operator=(char const *&str)
+ operator=(char const *str)
{
return operator=(cripts::string_view(str, strlen(str)));
}
@@ -331,11 +292,11 @@ public:
static const Iterator _end;
}; // Class cripts::Header::iterator
- Header() : status(this), reason(this), body(this), cache(this) {}
+ Header() : status(this), reason(this), body(this) {}
~Header() { Reset(); }
- // Clear anything "cached" in the Url, this is rather draconian, but it's
+ // Clear anything "cached" in the Header, this is rather draconian, but it's
// safe...
void
Reset()
@@ -363,6 +324,7 @@ public:
}
String operator[](const cripts::string_view str);
+ time_t AsDate(const cripts::string_view str);
[[nodiscard]] bool
Initialized() const
@@ -393,10 +355,9 @@ public:
_state = state;
}
- Status status;
- Reason reason;
- Body body;
- CacheStatus cache;
+ Status status;
+ Reason reason;
+ Body body;
protected:
static void
@@ -513,6 +474,48 @@ namespace Server
} // namespace Server
+namespace Cache
+{
+ class Response : public ResponseHeader
+ {
+ using super_type = ResponseHeader;
+ using self_type = Response;
+
+ class LookupStatus
+ {
+ using self_type = LookupStatus;
+
+ public:
+ LookupStatus() = delete;
+ LookupStatus(Response *owner) : _owner(owner) {}
+
+ cripts::string_view GetSV();
+ self_type &operator=(int status);
+
+ operator integer();
+
+ private:
+ Response *_owner = nullptr;
+ int _lookup = -1; // Note set yet
+
+ }; // Class cripts::Cache::LookupStatus
+
+ public:
+ Response() : ResponseHeader(), lookupstatus(this){};
+
+ Response(const self_type &) = delete;
+ void operator=(const self_type &) = delete;
+
+ // Implemented later, because needs the context.
+ static self_type &_get(cripts::Context *context);
+ void _initialize() override;
+
+ LookupStatus lookupstatus;
+
+ }; // End class Cache::Response
+
+} // namespace Cache
+
// Some static methods for the Method class
namespace Method
{
@@ -530,6 +533,16 @@ namespace Method
extern const cripts::Header::Method PURGE;
} // namespace Method
+// Lookup status constants, these are used in the Cache::Response::lookupstatus
+namespace LookupStatus
+{
+ inline constexpr int NONE = -1;
+ inline constexpr int MISS = TS_CACHE_LOOKUP_MISS;
+ inline constexpr int HIT_STALE = TS_CACHE_LOOKUP_HIT_STALE;
+ inline constexpr int HIT_FRESH = TS_CACHE_LOOKUP_HIT_FRESH;
+ inline constexpr int SKIPPED = TS_CACHE_LOOKUP_SKIPPED;
+} // namespace LookupStatus
+
class Context;
} // namespace cripts
diff --git a/include/cripts/Instance.hpp b/include/cripts/Instance.hpp
index b5317f9efd..bf0af5f622 100644
--- a/include/cripts/Instance.hpp
+++ b/include/cripts/Instance.hpp
@@ -112,7 +112,7 @@ public:
}
}
- std::array<DataType, 32> data;
+ std::array<DataType, 16> data;
cripts::string to_url;
cripts::string from_url;
cripts::string plugin_debug_tag;
diff --git a/include/cripts/Lulu.hpp b/include/cripts/Lulu.hpp
index f003d7714a..4025b8527b 100644
--- a/include/cripts/Lulu.hpp
+++ b/include/cripts/Lulu.hpp
@@ -24,6 +24,7 @@
#include <string_view>
#include <charconv>
#include <type_traits>
+#include <chrono>
#include <fmt/core.h>
@@ -103,6 +104,12 @@ public:
return bool(*this);
}
+ [[nodiscard]] time_t
+ ToDate() const
+ {
+ return TSMimeParseDate(_value.data(), _value.size());
+ }
+
std::vector<mixin_type>
Splitter(mixin_type input, char delim)
{
diff --git a/include/cripts/Matcher.hpp b/include/cripts/Matcher.hpp
index 30574b67ac..6a749910a3 100644
--- a/include/cripts/Matcher.hpp
+++ b/include/cripts/Matcher.hpp
@@ -20,6 +20,7 @@
// Setup for PCRE2
#define PCRE2_CODE_UNIT_WIDTH 8
#include <pcre2.h>
+#include <algorithm>
#include <vector>
#include <tuple>
@@ -151,7 +152,8 @@ namespace List
{
auto data = method.Data();
- return end() != std::find_if(begin(), end(), [&](const
cripts::Header::Method &header) { return header.Data() == data; });
+ return end() !=
+ std::ranges::find_if(begin(), end(), [&](const
cripts::Header::Method &header) { return header.Data() == data; });
}
[[nodiscard]] bool
diff --git a/include/cripts/Preamble.hpp b/include/cripts/Preamble.hpp
index b484826f18..5a2b4b8e96 100644
--- a/include/cripts/Preamble.hpp
+++ b/include/cripts/Preamble.hpp
@@ -115,12 +115,14 @@ extern cripts::Versions version; // Access to the ATS
version information
#define client context->_client
#define server context->_server
#define urls context->_urls
+#define cached context->_cache
#define Regex(_name_, ...) static cripts::Matcher::PCRE
_name_(__VA_ARGS__);
#define ACL(_name_, ...) static cripts::Matcher::Range::IP
_name_(__VA_ARGS__);
#define StatusCode(_name_, ...) cripts::Error::Status::Set(_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();
+#define UniqueUUID() cripts::UUID::Unique::Get()
+#define LocalTimeNow() cripts::Time::Local::Now()
+#define UTCTimeNow() cripts::Time::UTC::Now()
#endif
diff --git a/include/cripts/Time.hpp b/include/cripts/Time.hpp
index 9afc578cb0..40e3d55e02 100644
--- a/include/cripts/Time.hpp
+++ b/include/cripts/Time.hpp
@@ -28,6 +28,12 @@
// std::chrono :-/ Todo: Rewrite this with std::chrono when it has things like
// std::chrono::year_month_day
+namespace cripts::Time
+{
+using Clock = std::chrono::system_clock;
+using Point = Clock::time_point;
+} // namespace cripts::Time
+
namespace detail
{
class BaseTime
@@ -95,16 +101,24 @@ public:
return static_cast<integer>(_result.tm_yday) + 1;
}
+ [[nodiscard]] const cripts::string_view
+ ToDate()
+ {
+ int len = sizeof(_buffer);
+
+ TSMimeFormatDate(_now, _buffer, &len);
+ return {_buffer, len};
+ }
+
protected:
- std::time_t _now = std::time(nullptr);
- std::tm _result = {};
+ char _buffer[64] = {};
+ std::time_t _now = std::time(nullptr);
+ std::tm _result = {};
};
} // namespace detail
namespace cripts::Time
{
-// ToDo: Right now, we only have localtime, but we should support e.g. UTC and
-// other time zone instances.
class Local : public detail::BaseTime
{
using super_type = detail::BaseTime;
@@ -123,8 +137,38 @@ public:
return {};
}
+ explicit Local(Time::Point tp)
+ {
+ _now = Time::Clock::to_time_t(tp);
+ localtime_r(&_now, static_cast<struct tm *>(&_result));
+ }
+
}; // End class Time::Local
+class UTC : public detail::BaseTime
+{
+ using super_type = detail::BaseTime;
+ using self_type = UTC;
+
+public:
+ UTC(const self_type &) = delete;
+ void operator=(const self_type &) = delete;
+
+ UTC() { gmtime_r(&_now, static_cast<struct tm *>(&_result)); }
+
+ explicit UTC(Time::Point tp)
+ {
+ _now = Time::Clock::to_time_t(tp);
+ gmtime_r(&_now, static_cast<struct tm *>(&_result));
+ }
+
+ static UTC
+ Now()
+ {
+ return {};
+ }
+};
+
} // namespace cripts::Time
// Formatters for {fmt}
@@ -139,9 +183,25 @@ template <> struct formatter<cripts::Time::Local> {
template <typename FormatContext>
auto
- format(cripts::Time::Local &time, FormatContext &ctx) const ->
decltype(ctx.out())
+ format(const cripts::Time::Local &time, FormatContext &ctx) const ->
decltype(ctx.out())
+ {
+ return fmt::format_to(ctx.out(), "{}", time.Epoch());
+ }
+};
+
+template <> struct formatter<cripts::Time::UTC> {
+ constexpr auto
+ parse(const format_parse_context &ctx) -> decltype(ctx.begin())
+ {
+ return ctx.begin();
+ }
+
+ template <typename FormatContext>
+ auto
+ format(const cripts::Time::UTC &time, FormatContext &ctx) const ->
decltype(ctx.out())
{
return fmt::format_to(ctx.out(), "{}", time.Epoch());
}
};
+
} // namespace fmt
diff --git a/include/cripts/Transaction.hpp b/include/cripts/Transaction.hpp
index 9bcdb83d33..29f9b5cc36 100644
--- a/include/cripts/Transaction.hpp
+++ b/include/cripts/Transaction.hpp
@@ -81,18 +81,6 @@ public:
return false;
}
- [[nodiscard]] int
- LookupStatus() const
- {
- int status = 0;
-
- if (TSHttpTxnCacheLookupStatusGet(txnp, &status) != TS_SUCCESS) {
- return -1;
- }
-
- return status;
- }
-
}; // class Transaction
} // namespace cripts
diff --git a/include/cripts/Urls.hpp b/include/cripts/Urls.hpp
index 47c8c5069e..1ebf13f7d1 100644
--- a/include/cripts/Urls.hpp
+++ b/include/cripts/Urls.hpp
@@ -17,10 +17,12 @@
*/
#pragma once
+#include <algorithm>
#include <string>
#include <string_view>
#include <unordered_map>
#include <vector>
+#include <concepts>
#include "ts/ts.h"
#include "ts/remap.h"
@@ -500,7 +502,7 @@ public:
// Make sure the hash and vector are populated
_parser();
- std::sort(_ordered.begin(), _ordered.end());
+ std::ranges::sort(_ordered);
_modified = true;
}
diff --git a/src/cripts/Bundles/LogsMetrics.cc
b/src/cripts/Bundles/LogsMetrics.cc
index cc1b34193b..85e9c90aea 100644
--- a/src/cripts/Bundles/LogsMetrics.cc
+++ b/src/cripts/Bundles/LogsMetrics.cc
@@ -113,7 +113,7 @@ LogsMetrics::doTxnClose(cripts::Context *context)
resp["@TCPInfo"] += fmt::format(",TC; {}", conn.tcpinfo.Log());
}
- // .label(str)
+ // .propstats(str)
if (_label.length() > 0) {
instance.metrics[Bundle::PROPSTAT_CLIENT_BYTES_IN]->Increment(TSHttpTxnClientReqHdrBytesGet(transaction.txnp)
+
TSHttpTxnClientReqBodyBytesGet(transaction.txnp));
@@ -170,12 +170,12 @@ LogsMetrics::doSendResponse(cripts::Context *context)
void
LogsMetrics::doCacheLookup(cripts::Context *context)
{
- auto status = transaction.LookupStatus();
+ borrow cached = cripts::Cache::Response::Get();
- // .label(str)
+ // .propstats(str)
if (_label.length() > 0) {
- if (status >= 0 && status <= 3) {
- instance.metrics[status]->Increment(); // This assumes the 4 cache stats
are first
+ if (cached.lookupstatus >= LookupStatus::MISS && cached.lookupstatus <=
LookupStatus::SKIPPED) {
+ instance.metrics[cached.lookupstatus]->Increment(); // This assumes the
4 cache stats are first
}
}
}
@@ -196,8 +196,9 @@ LogsMetrics::doRemap(cripts::Context *context)
// .tcpinfo(bool)
if (_tcpinfo && sampled) {
- borrow req = cripts::Client::Request::Get();
- borrow conn = cripts::Client::Connection::Get();
+ borrow req = cripts::Client::Request::Get();
+ borrow conn = cripts::Client::Connection::Get();
+
req["@TCPInfo"] = fmt::format("TS; {}", conn.tcpinfo.Log());
}
}
diff --git a/src/cripts/Context.cc b/src/cripts/Context.cc
index 536f8bfde2..d71473e3d2 100644
--- a/src/cripts/Context.cc
+++ b/src/cripts/Context.cc
@@ -52,12 +52,12 @@ Context::reset()
if (_urls.pristine.Initialized()) {
_urls.pristine.Reset();
}
- if (_urls.cache.Initialized()) {
- _urls.cache.Reset();
- }
if (_urls.parent.Initialized()) {
_urls.parent.Reset();
}
+ if (_cache.url.Initialized()) {
+ _cache.url.Reset();
+ }
}
Context *
diff --git a/src/cripts/Headers.cc b/src/cripts/Headers.cc
index 5b199cfe0a..1a648391f1 100644
--- a/src/cripts/Headers.cc
+++ b/src/cripts/Headers.cc
@@ -110,30 +110,6 @@ Header::Method::GetSV()
return _method;
}
-cripts::string_view
-Header::CacheStatus::GetSV()
-{
- static std::array<cripts::string_view, 4> names{
- "miss", // TS_CACHE_LOOKUP_MISS,
- "hit-stale", // TS_CACHE_LOOKUP_HIT_STALE,
- "hit-fresh", // TS_CACHE_LOOKUP_HIT_FRESH,
- "skipped" // TS_CACHE_LOOKUP_SKIPPED
- };
- 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) {
- _cache = "none";
- } else {
- _cache = names[status];
- }
- }
-
- return _cache;
-}
-
Header::String &
Header::String::operator=(const cripts::string_view str)
{
@@ -269,6 +245,24 @@ Header::operator[](const cripts::string_view str)
return ret;
}
+time_t
+Header::AsDate(const cripts::string_view str)
+{
+ _ensure_initialized(this);
+ TSAssert(_bufp && _hdr_loc);
+
+ time_t ret = 0;
+ TSMLoc field_loc = TSMimeHdrFieldFind(_bufp, _hdr_loc, str.data(),
str.size());
+
+ if (field_loc) {
+ ret = TSMimeHdrFieldValueDateGet(_bufp, _hdr_loc, field_loc);
+ // Since this is not owned by a Header::String, we have to release it now
+ TSHandleMLocRelease(_bufp, _hdr_loc, field_loc);
+ }
+
+ return ret;
+}
+
Client::Request &
Client::Request::_get(cripts::Context *context)
{
@@ -405,4 +399,72 @@ Server::Response::_initialize()
}
}
+Cache::Response &
+Cache::Response::_get(cripts::Context *context)
+{
+ _ensure_initialized(&context->_cache.response);
+ return context->_cache.response;
+}
+
+void
+Cache::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);
+
+ TSAssert(_state->txnp);
+
+ if (TSHttpTxnCachedRespGet(_state->txnp, &_bufp, &_hdr_loc) != TS_SUCCESS) {
+ _state->error.Fail();
+ } else {
+ super_type::_initialize(); // Don't initialize unless properly setup
+ }
+}
+
+Cache::Response::LookupStatus::operator integer()
+{
+ if (_lookup == -1) {
+ TSAssert(_owner->_state->txnp);
+
+ if (TSHttpTxnCacheLookupStatusGet(_owner->_state->txnp, &_lookup) ==
TS_ERROR || _lookup < 0 || _lookup >= 4) {
+ _lookup = -1;
+ }
+ }
+
+ return _lookup;
+}
+
+cripts::string_view
+Cache::Response::LookupStatus::GetSV()
+{
+ static std::array<cripts::string_view, 4> names{
+ "miss", // TS_CACHE_LOOKUP_MISS,
+ "hit-stale", // TS_CACHE_LOOKUP_HIT_STALE,
+ "hit-fresh", // TS_CACHE_LOOKUP_HIT_FRESH,
+ "skipped" // TS_CACHE_LOOKUP_SKIPPED
+ };
+
+ int status = operator integer();
+
+ if (status == -1) {
+ return "none";
+ } else {
+ return names[status];
+ }
+}
+
+Cache::Response::LookupStatus &
+Cache::Response::LookupStatus::operator=(int lookup)
+{
+ if (TSHttpTxnCacheLookupStatusSet(_owner->_state->txnp, lookup) ==
TS_SUCCESS) {
+ _owner->_state->context->p_instance.debug("Setting LookupStatus = {}",
lookup);
+ } else {
+ // ToDo: Should we fail here?
+ // _owner->_state->error.Fail();
+ }
+
+ return *this;
+}
+
} // namespace cripts
diff --git a/src/cripts/Urls.cc b/src/cripts/Urls.cc
index 749b802602..5052365d06 100644
--- a/src/cripts/Urls.cc
+++ b/src/cripts/Urls.cc
@@ -15,6 +15,7 @@
See the License for the specific language governing permissions and
limitations under the License.
*/
+#include <algorithm>
#include <sstream>
#include "cripts/Lulu.hpp"
@@ -114,7 +115,7 @@ Url::Path::GetSV()
if (_segments.size() > 0) {
std::ostringstream path;
- std::copy(_segments.begin(), _segments.end(),
std::ostream_iterator<cripts::string_view>(path, "/"));
+ std::ranges::copy(_segments,
std::ostream_iterator<cripts::string_view>(path, "/"));
_storage.reserve(_size);
_storage = std::string_view(path.str());
if (_storage.size() > 0) {
@@ -340,7 +341,7 @@ Url::Query::Erase(cripts::string_view param)
_parser();
auto iter = _hashed.find(param);
- auto viter = std::find(_ordered.begin(), _ordered.end(), param);
+ auto viter = std::ranges::find(_ordered, param);
if (iter != _hashed.end()) {
_size -= iter->second.size(); // Size of the erased value
@@ -365,7 +366,7 @@
Url::Query::Erase(std::initializer_list<cripts::string_view> list, bool keep)
_parser();
for (auto viter = _ordered.begin(); viter != _ordered.end();) {
- if (list.end() == std::find(list.begin(), list.end(), *viter)) {
+ if (list.end() == std::ranges::find(list, *viter)) {
auto iter = _hashed.find(*viter);
CAssert(iter != _hashed.end());
@@ -532,14 +533,14 @@ Remap::To::URL::_get(cripts::Context *context)
Cache::URL &
Cache::URL::_get(cripts::Context *context)
{
- _ensure_initialized(&context->_urls.cache);
- return context->_urls.cache;
+ _ensure_initialized(&context->_cache.url);
+ return context->_cache.url;
}
void
Cache::URL::_initialize()
{
- Cache::URL *url = &_context->_urls.cache;
+ Cache::URL *url = &_context->_cache.url;
Client::Request &req = Client::Request::_get(_context); // Repurpose /
create the shared request object
switch (_context->state.hook) {
@@ -547,6 +548,7 @@ Cache::URL::_initialize()
case TS_HTTP_SEND_RESPONSE_HDR_HOOK:
case TS_HTTP_READ_RESPONSE_HDR_HOOK:
case TS_HTTP_SEND_REQUEST_HDR_HOOK:
+ case TS_HTTP_CACHE_LOOKUP_COMPLETE_HOOK:
case TS_HTTP_TXN_CLOSE_HOOK:
if (TSUrlCreate(req.BufP(), &url->_urlp) == TS_SUCCESS) {
TSAssert(_context->state.txnp);
@@ -584,7 +586,7 @@ Cache::URL::_update()
query.Flush();
if (_modified) {
- _ensure_initialized(&_context->_urls.cache);
+ _ensure_initialized(&_context->_cache.url);
TSAssert(_context->state.txnp);
_modified = false;
if (TS_SUCCESS == TSHttpTxnCacheLookupUrlSet(_context->state.txnp, _bufp,
_urlp)) {