blob: 4025b8527b6bcd04b8735351c3c674a014843a21 [file]
/*
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.
*/
#pragma once
#include <filesystem>
#include <cstring>
#include <string>
#include <string_view>
#include <charconv>
#include <type_traits>
#include <chrono>
#include <fmt/core.h>
#include "swoc/TextView.h"
#include "ts/ts.h"
#include "ts/remap.h"
// Silly typedef's for some PODs
using integer = int64_t;
using boolean = bool;
using namespace std::string_view_literals; // Gives ""sv for example, which can be convenient ...
using namespace std::literals; // For e.g. 24h for times
namespace CFS = std::filesystem; // Simplify the usage of std::filesystem
integer integer_helper(std::string_view sv);
// Some convenience macros
#define borrow auto &
#define CAssert(...) TSReleaseAssert(__VA_ARGS__)
#define CFatal(...) TSFatal(__VA_ARGS__)
#define AsBoolean(arg) std::get<boolean>(arg)
#define AsString(arg) std::get<cripts::string>(arg)
#define AsInteger(arg) std::get<integer>(arg)
#define AsFloat(arg) std::get<double>(arg)
#define AsPointer(arg) std::get<void *>(arg)
namespace cripts
{
// Use cripts::string_view consistently, so that it's a one-stop shop for all string_view needs.
using string_view = swoc::TextView;
namespace details
{
template <typename T> std::vector<T> Splitter(T input, char delim);
} // namespace details
namespace Pacing
{
static constexpr uint32_t Off = std::numeric_limits<uint32_t>::max();
} // namespace Pacing
class Context;
// This is a mixin template class
template <typename ChildT> class StringViewMixin
{
using self_type = StringViewMixin;
using mixin_type = cripts::string_view;
public:
constexpr StringViewMixin() = default;
constexpr StringViewMixin(const char *s) { _value = mixin_type(s, strlen(s)); }
constexpr StringViewMixin(const char *s, mixin_type::size_type count) { _value = mixin_type(s, count); }
constexpr StringViewMixin(const cripts::string_view &str) { _value = str; }
virtual self_type &operator=(const mixin_type str) = 0;
operator integer() const { return integer_helper(_value); }
[[nodiscard]] integer
ToInteger() const
{
return integer(*this);
}
[[nodiscard]] double
ToFloat() const
{
return float(*this);
}
[[nodiscard]] bool
ToBool() const
{
return bool(*this);
}
[[nodiscard]] time_t
ToDate() const
{
return TSMimeParseDate(_value.data(), _value.size());
}
std::vector<mixin_type>
Splitter(mixin_type input, char delim)
{
return details::Splitter<mixin_type>(input, delim);
}
[[nodiscard]] std::vector<mixin_type>
split(char delim)
{
return Splitter(_value, delim);
}
[[nodiscard]] mixin_type
GetSV() const
{
return _value;
}
self_type &
clear()
{
_value = cripts::string_view();
return *this;
}
[[nodiscard]] constexpr bool
empty() const
{
return _value.empty();
}
[[nodiscard]] constexpr mixin_type::const_pointer
data() const
{
return _value.data();
}
[[nodiscard]] constexpr mixin_type::size_type
size() const
{
return _value.size();
}
[[nodiscard]] constexpr mixin_type::size_type
length() const
{
return _value.size();
}
operator mixin_type() { return _value; }
[[nodiscard]] constexpr mixin_type
value() const
{
return _value;
}
bool
operator==(const mixin_type rhs) const
{
return _value == rhs;
}
bool
operator!=(const mixin_type rhs) const
{
return _value != rhs;
}
[[nodiscard]] constexpr mixin_type
substr(mixin_type::size_type pos = 0, mixin_type::size_type count = mixin_type::npos) const
{
return _value.substr(pos, count);
}
constexpr void
remove_prefix(mixin_type::size_type n)
{
_value.remove_prefix(n);
}
constexpr void
remove_suffix(mixin_type::size_type n)
{
_value.remove_suffix(n);
}
ChildT &
ltrim(char c)
{
_value.ltrim(c);
return *(static_cast<ChildT *>(this));
}
ChildT &
rtrim(char c)
{
_value.rtrim(c);
return *(static_cast<ChildT *>(this));
}
ChildT &
trim(char c)
{
_value.trim(c);
return *(static_cast<ChildT *>(this));
}
ChildT &
ltrim(const char *chars = " \t\r\n")
{
_value.ltrim(chars);
return *(static_cast<ChildT *>(this));
}
ChildT &
rtrim(const char *chars = " \t\r\n")
{
_value.rtrim(chars);
return *(static_cast<ChildT *>(this));
}
ChildT &
trim(const char *chars = " \t")
{
_value.trim(chars);
return *(static_cast<ChildT *>(this));
}
[[nodiscard]] constexpr char const *
data_end() const noexcept
{
return _value.data_end();
}
[[nodiscard]] constexpr bool
ends_with(cripts::string_view const suffix) const
{
return _value.ends_with(suffix);
}
[[nodiscard]] constexpr bool
starts_with(cripts::string_view const prefix) const
{
return _value.starts_with(prefix);
}
[[nodiscard]] constexpr mixin_type::size_type
find(cripts::string_view const substr, mixin_type::size_type pos = 0) const
{
return _value.find(substr, pos);
}
[[nodiscard]] constexpr mixin_type::size_type
rfind(cripts::string_view const substr, mixin_type::size_type pos = 0) const
{
return _value.rfind(substr, pos);
}
[[nodiscard]] constexpr bool
contains(cripts::string_view const substr) const
{
return (_value.find(substr) != _value.npos);
}
protected:
void
_setSV(const mixin_type str)
{
_value = str;
}
private:
mixin_type _value;
}; // End class cripts::StringViewMixin
class string : public std::string
{
using super_type = std::string;
using self_type = string;
public:
using std::string::string;
// ToDo: This broke when switching to swoc::TextView
// using std::string::operator cripts::string_view;
using super_type::operator+=;
using super_type::operator[];
self_type &
operator=(const self_type &str)
{
super_type::operator=(str);
return *this;
}
self_type &
operator=(const cripts::string_view &str)
{
super_type::operator=(str);
return *this;
}
self_type &
operator=(const char *str)
{
super_type::operator=(str);
return *this;
}
string(const self_type &that) : super_type(that) {}
// This allows for a std::string to be moved to a cripts::string
string(super_type &&that) : super_type(std::move(that)) {}
string(self_type &&that) noexcept : super_type(that) {}
operator cripts::string_view() const { return {this->c_str(), this->size()}; }
// Make sure to keep these updated with C++20 ...
self_type &
ltrim(char c = ' ')
{
this->erase(0, this->find_first_not_of(c));
return *this;
}
self_type &
rtrim(char c = ' ')
{
this->erase(this->find_last_not_of(c) + 1);
return *this;
}
self_type &
trim(char c = ' ')
{
return this->ltrim(c).rtrim(c);
}
self_type &
ltrim(const char *chars = " \t\r\n")
{
this->erase(0, this->find_first_not_of(chars));
return *this;
}
self_type &
rtrim(const char *chars = " \t\r\n")
{
this->erase(this->find_last_not_of(chars) + 1);
return *this;
}
self_type &
trim(const char *chars)
{
return this->ltrim(chars).rtrim(chars);
}
[[nodiscard]] std::vector<cripts::string_view> split(char delim) const &;
// delete the rvalue ref overload to prevent dangling string_views
// If you are getting an error here, you need to assign a variable to the cripts::string before calling split
// and make sure its lifetime is longer than the returned vector
[[nodiscard]] std::vector<cripts::string_view> split(char delim) const && = delete;
operator integer() const;
operator bool() const;
operator float() const { return std::stod(*this); }
[[nodiscard]] integer
ToInteger() const
{
return integer(*this);
}
[[nodiscard]] double
ToFloat() const
{
return float(*this);
}
[[nodiscard]] bool
ToBool() const
{
return bool(*this);
}
}; // End class cripts::string
// Some helper functions, in the cripts:: generic namespace
int Random(int max);
std::vector<cripts::string_view> Splitter(cripts::string_view input, char delim);
cripts::string Hex(const cripts::string &str);
cripts::string Hex(cripts::string_view sv);
cripts::string UnHex(const cripts::string &str);
cripts::string UnHex(cripts::string_view sv);
class Control
{
class Base
{
using self_type = Base;
public:
Base() = delete;
Base(const self_type &) = delete;
void operator=(const self_type &) = delete;
explicit Base(TSHttpCntlType ctrl) : _ctrl(ctrl) {}
bool _get(cripts::Context *context) const;
void _set(cripts::Context *context, bool flag);
protected:
TSHttpCntlType _ctrl;
};
class Cache
{
using self_type = Cache;
public:
Cache() = default;
Cache(const self_type &) = delete;
void operator=(const self_type &) = delete;
Base response{TS_HTTP_CNTL_RESPONSE_CACHEABLE};
Base request{TS_HTTP_CNTL_REQUEST_CACHEABLE};
Base nostore{TS_HTTP_CNTL_SERVER_NO_STORE};
};
public:
Cache cache;
Base logging{TS_HTTP_CNTL_LOGGING_MODE};
Base intercept{TS_HTTP_CNTL_INTERCEPT_RETRY_MODE};
Base debug{TS_HTTP_CNTL_TXN_DEBUG};
Base remap{TS_HTTP_CNTL_SKIP_REMAPPING};
}; // End class Control
class Versions
{
using self_type = Versions;
public:
Versions() = default;
Versions(const self_type &) = delete;
void operator=(const self_type &) = delete;
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().length();
}
private:
class Major
{
using self_type = Major;
public:
Major() = default;
Major(const self_type &) = delete;
void operator=(const self_type &) = delete;
operator integer() const // This should not be explicit
{
return TSTrafficServerVersionGetMajor();
}
}; // End class Versions::Major
class Minor
{
using self_type = Minor;
public:
Minor() = default;
Minor(const self_type &) = delete;
void operator=(const self_type &) = delete;
operator integer() const // This should not be explicit
{
return TSTrafficServerVersionGetMinor();
}
}; // End class Versions::Minor
class Patch
{
using self_type = Minor;
public:
Patch() = default;
Patch(const self_type &) = delete;
void operator=(const self_type &) = delete;
operator integer() const // This should not be explicit
{
return TSTrafficServerVersionGetPatch();
}
}; // End class Versions::Patch
friend struct fmt::formatter<Versions::Major>;
friend struct fmt::formatter<Versions::Minor>;
friend struct fmt::formatter<Versions::Patch>;
cripts::string_view _version;
public:
Major major;
Minor minor;
Patch patch;
}; // End class Versions
} // namespace cripts
// Formatters for {fmt}
namespace fmt
{
template <> struct formatter<cripts::Versions> {
constexpr auto
parse(format_parse_context &ctx) -> decltype(ctx.begin())
{
return ctx.begin();
}
template <typename FormatContext>
auto
format(cripts::Versions &version, FormatContext &ctx) const -> decltype(ctx.out())
{
return fmt::format_to(ctx.out(), "{}", version.GetSV());
}
};
template <> struct formatter<cripts::Versions::Major> {
constexpr auto
parse(format_parse_context &ctx) -> decltype(ctx.begin())
{
return ctx.begin();
}
template <typename FormatContext>
auto
format(cripts::Versions::Major &major, FormatContext &ctx) const -> decltype(ctx.out())
{
return fmt::format_to(ctx.out(), "{}", integer(major));
}
};
template <> struct formatter<cripts::Versions::Minor> {
constexpr auto
parse(format_parse_context &ctx) -> decltype(ctx.begin())
{
return ctx.begin();
}
template <typename FormatContext>
auto
format(cripts::Versions::Minor &minor, FormatContext &ctx) const -> decltype(ctx.out())
{
return fmt::format_to(ctx.out(), "{}", integer(minor));
}
};
template <> struct formatter<cripts::Versions::Patch> {
constexpr auto
parse(format_parse_context &ctx) -> decltype(ctx.begin())
{
return ctx.begin();
}
template <typename FormatContext>
auto
format(cripts::Versions::Patch &patch, FormatContext &ctx) const -> decltype(ctx.out())
{
return fmt::format_to(ctx.out(), "{}", integer(patch));
}
};
template <> struct formatter<TSHttpStatus> {
constexpr auto
parse(format_parse_context &ctx) -> decltype(ctx.begin())
{
return ctx.begin();
}
template <typename FormatContext>
auto
format(const TSHttpStatus &stat, FormatContext &ctx) const -> decltype(ctx.out())
{
return fmt::format_to(ctx.out(), "{}", static_cast<int>(stat));
}
};
} // namespace fmt