#include "processor/uri_parse.hpp"
#include "argument_retriever.hpp"
#include "clock.hpp"
#include "memory_resource.hpp"
#include "object.hpp"
#include "pointer.hpp"
#include "processor/base.hpp"
#include "uri_utils.hpp"
#include <string_view>
#include <unordered_map>
#include <utility>
using namespace std::literals;
namespace ddwaf {
namespace {
owned_object split_query_parameters(
const uri_decomposed &decomposed, nonnull_ptr<memory::memory_resource> alloc)
{
std::unordered_map<std::string_view, owned_object> query_keys;
auto query_remaining = decomposed.query;
while (!query_remaining.empty()) {
std::string_view parameter;
auto separator_pos = query_remaining.find_first_of('&');
if (separator_pos != std::string_view::npos) {
parameter = query_remaining.substr(0, separator_pos);
query_remaining = query_remaining.substr(separator_pos + 1);
} else {
parameter = query_remaining;
query_remaining = {};
}
std::string_view key;
owned_object value = owned_object{};
auto assignment_pos = parameter.find_first_of('=');
if (assignment_pos == std::string_view::npos) {
key = parameter;
if (key.empty()) {
continue;
}
value = owned_object::make_boolean(true);
} else {
key = parameter.substr(0, assignment_pos);
if (key.empty()) {
continue;
}
value = owned_object::make_string(parameter.substr(assignment_pos + 1), alloc);
}
if (key.ends_with("[]")) {
key.remove_suffix(sizeof("[]") - 1);
}
auto it = query_keys.find(key);
if (it == query_keys.end()) {
query_keys.emplace(key, std::move(value));
} else {
if (!it->second.is_array()) {
auto array = owned_object::make_array(2, alloc);
array.emplace_back(std::move(it->second));
it->second = std::move(array);
}
it->second.emplace_back(std::move(value));
}
}
auto query = owned_object::make_map(query_keys.size(), alloc);
for (auto &[key, value] : query_keys) { query.emplace(key, std::move(value)); }
return query;
}
}
owned_object uri_parse_processor::eval_impl(const unary_argument<std::string_view> &input,
processor_cache & , nonnull_ptr<memory::memory_resource> alloc,
ddwaf::timer & ) const
{
auto decomposed = uri_parse(input.value);
if (!decomposed.has_value()) {
return owned_object{};
}
auto output = owned_object::make_map(7, alloc);
output.emplace("scheme", decomposed->scheme);
output.emplace("userinfo", decomposed->authority.userinfo);
output.emplace("host", decomposed->authority.host);
output.emplace("port", decomposed->authority.port);
output.emplace("path", decomposed->path);
output.emplace("query", split_query_parameters(*decomposed, alloc));
output.emplace("fragment", decomposed->fragment);
return output;
}
}