blob: b1010cf8551cc4a55f890f3d4e8bc4019b1353a7 [file] [log] [blame]
/*
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 <cstring>
#include <iterator>
#include <string>
#include "ts/ts.h"
#include "cripts/Transaction.hpp"
#include "cripts/Lulu.hpp"
namespace cripts
{
class Header
{
using self_type = Header;
public:
class Status
{
using self_type = Status;
public:
Status() = delete;
Status(Header *owner) : _owner(owner) {}
operator integer(); // This should not be explicit, nor const
self_type &operator=(int status);
private:
Header *_owner = nullptr;
TSHttpStatus _status = TS_HTTP_STATUS_NONE;
}; // End class cripts::Header::Status
class Reason
{
using self_type = Reason;
public:
Reason() = delete;
Reason(Header *owner) : _owner(owner) {}
self_type &operator=(cripts::string_view reason);
private:
Header *_owner = nullptr;
}; // End class cripts::Header::Reason
class Body
{
using self_type = Body;
public:
Body() = delete;
Body(Header *owner) : _owner(owner) {}
self_type &operator=(cripts::string_view body);
private:
Header *_owner = nullptr;
}; // End class cripts::Header::Body
class Method
{
using self_type = Method;
public:
Method() = delete;
Method(cripts::string_view const &method) : _method(method) {}
Method(const char *const method, int len)
{
_method = cripts::string_view(method, static_cast<cripts::string_view::size_type>(len));
}
Method(Header *owner) : _owner(owner) {}
cripts::string_view GetSV();
operator cripts::string_view() { return GetSV(); }
// ToDo: This is a bit weird, but seems needed (for now) to allow for the
// cripts::Header::Method::* constants.
[[nodiscard]] cripts::string_view::const_pointer
Data() const
{
CAssert(_method.size() > 0);
return _method.data();
}
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();
}
bool
operator==(Method const &rhs)
{
return GetSV().data() == rhs.Data();
}
bool
operator!=(Method const &rhs)
{
return GetSV().data() != rhs.Data();
}
private:
Header *_owner = nullptr;
cripts::string_view _method;
}; // End class cripts::Header::Method
class String : public cripts::StringViewMixin<String>
{
using super_type = cripts::StringViewMixin<String>;
using self_type = String;
public:
~String()
{
if (_field_loc) {
TSHandleMLocRelease(_owner->_bufp, _owner->_hdr_loc, _field_loc);
_field_loc = nullptr;
}
}
public:
// Implemented in Headers.cc, they are pretty large
self_type &operator=(const cripts::string_view str) override;
self_type &operator=(integer val);
self_type &operator+=(const cripts::string_view str);
// 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=(std::nullptr_t) = delete;
self_type &
operator=(char const *str)
{
return operator=(cripts::string_view(str, strlen(str)));
}
self_type &
operator=(const std::string &str)
{
return operator=(cripts::string_view(str));
}
private:
friend class Header;
void
_initialize(cripts::string_view name, cripts::string_view value, Header *owner, TSMLoc field_loc)
{
_setSV(value);
_name = name;
_owner = owner;
_field_loc = field_loc;
}
Header *_owner = nullptr;
TSMLoc _field_loc = nullptr;
cripts::string_view _name;
}; // Class cripts::Header::String
class Name : public cripts::StringViewMixin<Name>
{
using super_type = cripts::StringViewMixin<Name>;
using self_type = Name;
public:
operator cripts::string_view() const { return GetSV(); }
self_type &
operator=(const cripts::string_view str) override
{
_setSV(str);
return *this;
}
using super_type::StringViewMixin;
}; // Class cripts::Header::Name
public:
class Iterator
{
public:
using iterator_category = std::input_iterator_tag;
using value_type = Name;
using difference_type = std::ptrdiff_t;
using pointer = const Name *;
using reference = const Name &;
const static uint32_t END_TAG = UINT32_MAX;
Iterator(Name view, uint32_t tag) : _view(std::move(view)), _tag(tag) {} // Special for the end iterator
Iterator(Name view, uint32_t tag, Header *owner) : _view(std::move(view)), _tag(tag), _owner(owner) {}
reference
operator*() const
{
return _view;
}
pointer
operator->()
{
return &_view;
}
// Prefix increment
Iterator &
operator++()
{
if (_tag != END_TAG) {
CAssert(_tag == _owner->_iterator_tag);
_view = _owner->iterate();
if (_view.empty()) {
_tag = END_TAG;
}
}
return *this;
}
friend bool
operator==(const Iterator &a, const Iterator &b)
{
return a._tag == b._tag;
};
friend bool
operator!=(const Iterator &a, const Iterator &b)
{
return a._tag != b._tag;
};
static const Iterator
end()
{
return _end;
}
private:
Name _view = nullptr;
uint32_t _tag = 0;
Header *_owner = nullptr;
static const Iterator _end;
}; // Class cripts::Header::iterator
Header() : status(this), reason(this), body(this) {}
~Header() { Reset(); }
// Clear anything "cached" in the Header, this is rather draconian, but it's
// safe...
void
Reset()
{
if (_bufp && _hdr_loc) {
TSHandleMLocRelease(_bufp, TS_NULL_MLOC, _hdr_loc);
_hdr_loc = nullptr;
_bufp = nullptr;
}
_initialized = false;
}
[[nodiscard]] TSMBuffer
BufP()
{
_ensure_initialized(this);
return _bufp;
}
[[nodiscard]] TSMLoc
MLoc()
{
_ensure_initialized(this);
return _hdr_loc;
}
String operator[](const cripts::string_view str);
time_t AsDate(const cripts::string_view str);
[[nodiscard]] bool
Initialized() const
{
return _initialized;
}
void
Erase(const cripts::string_view header)
{
_ensure_initialized(this);
operator[](header) = "";
}
Iterator begin();
cripts::string_view iterate(); // This is a little helper for the iterators
[[nodiscard]] Iterator
end() const
{
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;
protected:
static void
_ensure_initialized(self_type *ptr)
{
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
class RequestHeader : public Header
{
using super_type = Header;
using self_type = RequestHeader;
public:
RequestHeader() : method(this) {} // Special case since only this header has a method
Method method;
}; // End class RequestHeader
class ResponseHeader : public Header
{
private:
using super_type = Header;
using self_type = ResponseHeader;
public:
ResponseHeader() = default;
}; // End class ResponseHeader
namespace Client
{
class URL;
class Request : public RequestHeader
{
using super_type = RequestHeader;
using self_type = Request;
public:
Request() = default;
Request(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;
}; // End class Client::Request
class Response : public ResponseHeader
{
using super_type = ResponseHeader;
using self_type = Response;
public:
Response() = default;
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;
}; // End class Client::Response
} // namespace Client
namespace Server
{
class Request : public RequestHeader
{
using super_type = RequestHeader;
using self_type = Request;
public:
Request() = default;
Request(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;
}; // End class Server::Request
class Response : public ResponseHeader
{
using super_type = ResponseHeader;
using self_type = Response;
public:
Response() = default;
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;
}; // End class Server::Response
} // 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
{
#undef DELETE // ToDo: macOS shenanigans here, defining DELETE as a macro
extern const cripts::Header::Method GET;
extern const cripts::Header::Method HEAD;
extern const cripts::Header::Method POST;
extern const cripts::Header::Method PUT;
extern const cripts::Header::Method PUSH;
extern const cripts::Header::Method DELETE;
extern const cripts::Header::Method OPTIONS;
extern const cripts::Header::Method CONNECT;
extern const cripts::Header::Method TRACE;
// This is a special feature of ATS
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
// Formatters for {fmt}
namespace fmt
{
template <> struct formatter<cripts::Header::Method> {
constexpr auto
parse(format_parse_context &ctx) -> decltype(ctx.begin())
{
return ctx.begin();
}
template <typename FormatContext>
auto
format(cripts::Header::Method &method, FormatContext &ctx) const -> decltype(ctx.out())
{
return fmt::format_to(ctx.out(), "{}", method.GetSV());
}
};
template <> struct formatter<cripts::Header::String> {
constexpr auto
parse(format_parse_context &ctx) -> decltype(ctx.begin())
{
return ctx.begin();
}
template <typename FormatContext>
auto
format(const cripts::Header::String &str, FormatContext &ctx) const -> decltype(ctx.out())
{
return fmt::format_to(ctx.out(), "{}", str.GetSV());
}
};
template <> struct formatter<cripts::Header::Name> {
constexpr auto
parse(format_parse_context &ctx) -> decltype(ctx.begin())
{
return ctx.begin();
}
template <typename FormatContext>
auto
format(const cripts::Header::Name &name, FormatContext &ctx) const -> decltype(ctx.out())
{
return fmt::format_to(ctx.out(), "{}", name.GetSV());
}
};
} // namespace fmt