mirror of
https://github.com/torlando-tech/pyxis.git
synced 2026-08-26 04:29:53 +00:00
149 lines
5.9 KiB
C++
149 lines
5.9 KiB
C++
#include "NomadNetPartialController.h"
|
|
|
|
#include "NomadNetPartialHash.h"
|
|
|
|
#include <algorithm>
|
|
#include <cstring>
|
|
|
|
namespace UI::LXMF::NomadNet {
|
|
|
|
namespace {
|
|
|
|
void wipe(void* memory, std::size_t size) noexcept {
|
|
volatile uint8_t* bytes = static_cast<volatile uint8_t*>(memory);
|
|
for (std::size_t index = 0; index < size; ++index) bytes[index] = 0;
|
|
}
|
|
|
|
std::array<uint8_t, 32> descriptor_identity_hash(
|
|
CompactPage::TextView descriptor) noexcept {
|
|
std::array<char, DocumentParser::MAX_PARTIAL_DESCRIPTOR_BYTES + 2> identity{};
|
|
std::size_t size = 0;
|
|
for (std::size_t index = 0; index < descriptor.size(); ++index) {
|
|
const char value = descriptor.data()[index];
|
|
identity[size++] = value == '`' ? '|' : value;
|
|
}
|
|
return partial_descriptor_sha256(identity.data(), size);
|
|
}
|
|
|
|
} // namespace
|
|
|
|
bool PartialController::prepare(const PartialRequest& request,
|
|
const CompactPage& page,
|
|
const uint8_t* request_data,
|
|
std::size_t request_size) noexcept {
|
|
clear_lease();
|
|
if (request.page_generation == 0 || request.request_token == 0 ||
|
|
request.partial_generation == 0 ||
|
|
request.partial_index >= page.partials().size() ||
|
|
request_size > _request_data.size() ||
|
|
(!request_data && request_size != 0))
|
|
return false;
|
|
const auto& partial = page.partials()[request.partial_index];
|
|
if (partial.descriptor_hash != request.descriptor_hash) return false;
|
|
const auto descriptor = page.partial_descriptor(partial);
|
|
const auto url = page.partial_url(partial);
|
|
const auto selectors = page.partial_selectors(partial);
|
|
if ((!descriptor.data() && !descriptor.empty()) ||
|
|
(!url.data() && !url.empty()) ||
|
|
(!selectors.data() && !selectors.empty()) ||
|
|
descriptor.size() > DocumentParser::MAX_PARTIAL_DESCRIPTOR_BYTES ||
|
|
url.size() > DocumentParser::MAX_PARTIAL_URL_BYTES ||
|
|
selectors.size() > FormState::MAX_SELECTOR_BYTES ||
|
|
descriptor_identity_hash(descriptor) != request.descriptor_hash)
|
|
return false;
|
|
|
|
if (!descriptor.empty())
|
|
std::memcpy(_descriptor.data(), descriptor.data(), descriptor.size());
|
|
if (!url.empty()) std::memcpy(_url.data(), url.data(), url.size());
|
|
if (!selectors.empty())
|
|
std::memcpy(_selectors.data(), selectors.data(), selectors.size());
|
|
if (request_size != 0)
|
|
std::memcpy(_request_data.data(), request_data, request_size);
|
|
_descriptor_size = static_cast<uint16_t>(descriptor.size());
|
|
_url_size = static_cast<uint16_t>(url.size());
|
|
_selectors_size = static_cast<uint16_t>(selectors.size());
|
|
_request_size = static_cast<uint16_t>(request_size);
|
|
_request = request;
|
|
_active = true;
|
|
return true;
|
|
}
|
|
|
|
void PartialController::reset_page(std::size_t base_source_bytes) noexcept {
|
|
clear_lease();
|
|
_fragment_source_bytes = {};
|
|
_base_source_bytes = std::min(base_source_bytes, MAX_EXPANDED_SOURCE_BYTES);
|
|
}
|
|
|
|
void PartialController::cancel() noexcept {
|
|
clear_lease();
|
|
_fragment_source_bytes = {};
|
|
_base_source_bytes = 0;
|
|
}
|
|
|
|
bool PartialController::matches(const PartialRequest& request) const noexcept {
|
|
return _active && request.partial_index == _request.partial_index &&
|
|
request.page_generation == _request.page_generation &&
|
|
request.partial_generation == _request.partial_generation &&
|
|
request.request_token == _request.request_token &&
|
|
request.descriptor_hash == _request.descriptor_hash;
|
|
}
|
|
|
|
bool PartialController::matches(const PartialRequest& request,
|
|
const CompactPage& page) const noexcept {
|
|
if (!matches(request) || request.partial_index >= page.partials().size())
|
|
return false;
|
|
const auto& partial = page.partials()[request.partial_index];
|
|
const auto descriptor = page.partial_descriptor(partial);
|
|
return partial.descriptor_hash == request.descriptor_hash &&
|
|
descriptor.size() == _descriptor_size &&
|
|
(_descriptor_size == 0 || std::memcmp(
|
|
descriptor.data(), _descriptor.data(), _descriptor_size) == 0);
|
|
}
|
|
|
|
std::size_t PartialController::expanded_source_bytes() const noexcept {
|
|
std::size_t total = _base_source_bytes;
|
|
for (const uint32_t bytes : _fragment_source_bytes) {
|
|
if (bytes > MAX_EXPANDED_SOURCE_BYTES -
|
|
std::min(total, MAX_EXPANDED_SOURCE_BYTES))
|
|
return MAX_EXPANDED_SOURCE_BYTES + 1;
|
|
total += bytes;
|
|
}
|
|
return total;
|
|
}
|
|
|
|
bool PartialController::can_accept_fragment(std::size_t partial_index,
|
|
std::size_t source_bytes) const noexcept {
|
|
if (!_active || partial_index != _request.partial_index ||
|
|
partial_index >= _fragment_source_bytes.size() ||
|
|
source_bytes > MAX_RESPONSE_BYTES)
|
|
return false;
|
|
const std::size_t current = expanded_source_bytes();
|
|
if (current > MAX_EXPANDED_SOURCE_BYTES) return false;
|
|
const std::size_t old = _fragment_source_bytes[partial_index];
|
|
const std::size_t without_old = current >= old ? current - old : 0;
|
|
return source_bytes <= MAX_EXPANDED_SOURCE_BYTES -
|
|
std::min(without_old, MAX_EXPANDED_SOURCE_BYTES);
|
|
}
|
|
|
|
bool PartialController::commit_fragment(std::size_t partial_index,
|
|
std::size_t source_bytes) noexcept {
|
|
if (!can_accept_fragment(partial_index, source_bytes)) return false;
|
|
_fragment_source_bytes[partial_index] = static_cast<uint32_t>(source_bytes);
|
|
return true;
|
|
}
|
|
|
|
void PartialController::clear_lease() noexcept {
|
|
wipe(_descriptor.data(), _descriptor.size());
|
|
wipe(_url.data(), _url.size());
|
|
wipe(_selectors.data(), _selectors.size());
|
|
wipe(_request_data.data(), _request_data.size());
|
|
_request = PartialRequest{};
|
|
_descriptor_size = 0;
|
|
_url_size = 0;
|
|
_selectors_size = 0;
|
|
_request_size = 0;
|
|
_active = false;
|
|
}
|
|
|
|
} // namespace UI::LXMF::NomadNet
|