#pragma once
#include <array>
#include <cstddef>
#include <memory>
#include <utility>
#include <vector>
#include "attribute_collector.hpp"
#include "clock.hpp"
#include "context_allocator.hpp"
#include "exclusion/common.hpp"
#include "exclusion/input_filter.hpp"
#include "exclusion/rule_filter.hpp"
#include "input_batch_queue.hpp"
#include "log.hpp"
#include "memory_resource.hpp"
#include "module.hpp"
#include "module_category.hpp"
#include "object.hpp"
#include "object_store.hpp"
#include "pointer.hpp"
#include "processor/base.hpp"
#include "rule.hpp"
#include "ruleset.hpp"
namespace ddwaf {
struct evaluation_cache {
memory::unordered_map<base_processor *, processor_cache> processors;
memory::unordered_map<const rule_filter *, rule_filter::cache_type> rule_filters;
memory::unordered_map<const input_filter *, input_filter::cache_type> input_filters;
std::array<rule_module_cache, rule_module_count> rule_modules;
exclusion_policy exclusions;
};
class evaluation_engine {
public:
evaluation_engine(const evaluation_engine &) = delete;
evaluation_engine &operator=(const evaluation_engine &) = delete;
evaluation_engine(evaluation_engine &&) = default;
evaluation_engine &operator=(evaluation_engine &&) = delete;
~evaluation_engine() = default;
bool insert_batch(owned_object data) noexcept
{
if (!input_batches_.insert_batch(store_, std::move(data))) {
DDWAF_WARN("Illegal WAF call: parameter structure invalid!");
return false;
}
return true;
}
bool insert_batch(map_view data) noexcept
{
if (!input_batches_.insert_batch(store_, data)) {
DDWAF_WARN("Illegal WAF call: parameter structure invalid!");
return false;
}
return true;
}
bool insert_batches(owned_object data) noexcept
{
if (!input_batches_.insert_batches(store_, std::move(data))) {
DDWAF_WARN("Illegal WAF call: parameter structure invalid!");
return false;
}
return true;
}
bool insert_batches(array_view data) noexcept
{
if (!input_batches_.insert_batches(store_, data)) {
DDWAF_WARN("Illegal WAF call: parameter structure invalid!");
return false;
}
return true;
}
bool next_batch() { return input_batches_.next_batch(store_); }
bool insert_and_apply(owned_object data) noexcept
{
return store_.insert_and_apply(std::move(data));
}
bool insert_and_apply(map_view data) noexcept { return store_.insert_and_apply(data); }
std::pair<bool, owned_object> eval(timer &deadline);
static evaluation_engine context_engine(std::shared_ptr<ruleset> ruleset, object_store &store,
nonnull_ptr<memory::memory_resource> output_alloc = memory::get_default_resource())
{
return evaluation_engine{
std::move(ruleset), store, {}, attribute_collector{output_alloc}, output_alloc};
}
static evaluation_engine subcontext_engine(evaluation_engine &engine, object_store &store)
{
return evaluation_engine{engine.ruleset_, store, engine.cache_,
attribute_collector::from_upstream_collector(engine.collector_), engine.output_alloc_};
}
void eval_preprocessors(timer &deadline);
void eval_postprocessors(timer &deadline);
exclusion_policy &eval_filters(timer &deadline);
rule_verdict eval_rules(
const exclusion_policy &policy, std::vector<rule_result> &results, timer &deadline);
protected:
explicit evaluation_engine(std::shared_ptr<ruleset> ruleset, object_store &store,
evaluation_cache cache, attribute_collector &&collector,
nonnull_ptr<memory::memory_resource> output_alloc)
: output_alloc_(output_alloc), ruleset_(std::move(ruleset)), store_(store),
collector_(std::move(collector)), cache_(std::move(cache))
{
cache_.processors.reserve(
ruleset_->preprocessors->size() + ruleset_->postprocessors->size());
cache_.rule_filters.reserve(ruleset_->rule_filters->size());
cache_.input_filters.reserve(ruleset_->input_filters->size());
for (std::size_t i = 0; i < ruleset_->rule_modules.size(); ++i) {
ruleset_->rule_modules[i].init_cache(cache_.rule_modules[i]);
}
}
bool check_new_rule_targets() const
{
for (const auto &[target, str] : ruleset_->rule_addresses) {
if (store_.is_new_target(target)) {
return true;
}
}
return false;
}
bool check_new_filter_targets() const
{
for (const auto &[target, str] : ruleset_->filter_addresses) {
if (store_.is_new_target(target)) {
return true;
}
}
return false;
}
nonnull_ptr<memory::memory_resource> output_alloc_;
std::shared_ptr<ruleset> ruleset_;
object_store &store_;
input_batch_queue input_batches_;
attribute_collector collector_;
evaluation_cache cache_;
};
}