Commit 280d7fd3 authored by jan.koester's avatar jan.koester
Browse files

test

parent f3afade3
Loading
Loading
Loading
Loading
+52 −4
Changes for src/store/ConfigStore.cpp: 52 added lines, 4 removed lines.
Original line number Diff line number Diff line
@@ -92,8 +92,9 @@ private:
    size_t _pos = 0;
};

// Deliberately does not touch r.priority -- see the HttpRoutePriority comment in Records.h for
// why that field is persisted as its own section instead of appended here.
// Deliberately does not touch r.priority/r.forceHttpsRedirect -- see the HttpRoutePriority
// comment in Records.h for why fields added after the initial schema are persisted as their
// own section instead of appended here.
void encodeHttpRoute(ByteWriter &w, const HttpRouteRecord &r) {
    w.str(r.id);
    w.str(r.domain);
@@ -104,7 +105,6 @@ void encodeHttpRoute(ByteWriter &w, const HttpRouteRecord &r) {
    w.u8(r.tlsVerifyUpstream ? 1 : 0);
    w.u32(static_cast<uint32_t>(r.tlsPinnedFingerprintsSha256.size()));
    for (const auto &fp : r.tlsPinnedFingerprintsSha256) w.str(fp);
    w.u8(r.forceHttpsRedirect ? 1 : 0);
}
HttpRouteRecord decodeHttpRoute(ByteReader &r) {
    HttpRouteRecord rec;
@@ -118,7 +118,6 @@ HttpRouteRecord decodeHttpRoute(ByteReader &r) {
    uint32_t fpCount = r.u32();
    rec.tlsPinnedFingerprintsSha256.reserve(fpCount);
    for (uint32_t i = 0; i < fpCount; ++i) rec.tlsPinnedFingerprintsSha256.push_back(r.str());
    rec.forceHttpsRedirect = r.u8() != 0;
    return rec;
}

@@ -132,6 +131,20 @@ std::pair<std::string, int32_t> decodeHttpRoutePriority(ByteReader &r) {
    return {routeId, priority};
}

// Same reasoning as HttpRoutePriority above: its own section rather than a field appended to
// encodeHttpRoute/decodeHttpRoute, so an older WAL/snapshot with no entries here just means
// every route defaults to forceHttpsRedirect=false (see listHttpRoutes()'s join) instead of
// desyncing the shared multi-record buffer or throwing on a truncated WAL frame.
void encodeHttpRouteForceHttpsRedirect(ByteWriter &w, const std::string &routeId, bool value) {
    w.str(routeId);
    w.u8(value ? 1 : 0);
}
std::pair<std::string, bool> decodeHttpRouteForceHttpsRedirect(ByteReader &r) {
    std::string routeId = r.str();
    bool value = r.u8() != 0;
    return {routeId, value};
}

void encodeSmtpRule(ByteWriter &w, const SmtpRelayRuleRecord &r) {
    w.str(r.id);
    w.str(r.domain);
@@ -441,6 +454,14 @@ void ConfigStore::applyRecord(RecordTable table, RecordOp op, const std::vector<
                _httpRoutePriorities.erase(r.str());
            }
            break;
        case RecordTable::HttpRouteForceHttpsRedirect:
            if (op == RecordOp::Put) {
                auto [routeId, value] = decodeHttpRouteForceHttpsRedirect(r);
                _httpRouteForceHttpsRedirect[routeId] = value;
            } else {
                _httpRouteForceHttpsRedirect.erase(r.str());
            }
            break;
    }
    ++_version;
}
@@ -456,6 +477,11 @@ void ConfigStore::putHttpRoute(const HttpRouteRecord &rec) {
    encodeHttpRoutePriority(pw, rec.id, rec.priority);
    appendWal(RecordTable::HttpRoutePriority, RecordOp::Put, pw.buffer());
    _httpRoutePriorities[rec.id] = rec.priority;

    ByteWriter fw;
    encodeHttpRouteForceHttpsRedirect(fw, rec.id, rec.forceHttpsRedirect);
    appendWal(RecordTable::HttpRouteForceHttpsRedirect, RecordOp::Put, fw.buffer());
    _httpRouteForceHttpsRedirect[rec.id] = rec.forceHttpsRedirect;
}

void ConfigStore::deleteHttpRoute(const std::string &id) {
@@ -469,6 +495,11 @@ void ConfigStore::deleteHttpRoute(const std::string &id) {
    pw.str(id);
    appendWal(RecordTable::HttpRoutePriority, RecordOp::Delete, pw.buffer());
    _httpRoutePriorities.erase(id);

    ByteWriter fw;
    fw.str(id);
    appendWal(RecordTable::HttpRouteForceHttpsRedirect, RecordOp::Delete, fw.buffer());
    _httpRouteForceHttpsRedirect.erase(id);
}

std::vector<HttpRouteRecord> ConfigStore::listHttpRoutes() const {
@@ -478,6 +509,8 @@ std::vector<HttpRouteRecord> ConfigStore::listHttpRoutes() const {
        out.push_back(rec);
        auto pit = _httpRoutePriorities.find(id);
        out.back().priority = (pit != _httpRoutePriorities.end()) ? pit->second : 0;
        auto fit = _httpRouteForceHttpsRedirect.find(id);
        out.back().forceHttpsRedirect = (fit != _httpRouteForceHttpsRedirect.end()) ? fit->second : false;
    }
    // HttpProxyController::RequestEvent picks the first match off this list -- lowest priority
    // first, id as a stable tiebreak (most commonly every route sitting at the default 0).
@@ -706,6 +739,11 @@ std::vector<uint8_t> ConfigStore::snapshot() const {
    w.u32(static_cast<uint32_t>(_httpRoutePriorities.size()));
    for (const auto &[routeId, priority] : _httpRoutePriorities) encodeHttpRoutePriority(w, routeId, priority);

    w.u32(static_cast<uint32_t>(_httpRouteForceHttpsRedirect.size()));
    for (const auto &[routeId, value] : _httpRouteForceHttpsRedirect) {
        encodeHttpRouteForceHttpsRedirect(w, routeId, value);
    }

    return w.buffer();
}

@@ -728,6 +766,7 @@ bool ConfigStore::applySnapshotIfNewer(const std::vector<uint8_t> &blob) {
    std::unordered_map<std::string, DkimKeyRecord> dkimKeys;
    std::unordered_map<std::string, ListenerTlsAssignmentRecord> listenerTlsAssignments;
    std::unordered_map<std::string, int32_t> httpRoutePriorities;
    std::unordered_map<std::string, bool> httpRouteForceHttpsRedirect;

    uint32_t n = r.u32();
    for (uint32_t i = 0; i < n; ++i) {
@@ -790,6 +829,14 @@ bool ConfigStore::applySnapshotIfNewer(const std::vector<uint8_t> &blob) {
            httpRoutePriorities[routeId] = priority;
        }
    }
    // HTTP route forceHttpsRedirect flags were added after priorities; same guard.
    if (!r.atEnd()) {
        n = r.u32();
        for (uint32_t i = 0; i < n; ++i) {
            auto [routeId, value] = decodeHttpRouteForceHttpsRedirect(r);
            httpRouteForceHttpsRedirect[routeId] = value;
        }
    }

    _httpRoutes = std::move(httpRoutes);
    _smtpRelayRules = std::move(smtpRules);
@@ -800,6 +847,7 @@ bool ConfigStore::applySnapshotIfNewer(const std::vector<uint8_t> &blob) {
    _dkimKeys = std::move(dkimKeys);
    _listenerTlsAssignments = std::move(listenerTlsAssignments);
    _httpRoutePriorities = std::move(httpRoutePriorities);
    _httpRouteForceHttpsRedirect = std::move(httpRouteForceHttpsRedirect);
    _version = incomingVersion;
    return true;
}
+1 −0
Changes for src/store/ConfigStore.h: 1 added line, 0 removed lines.
Original line number Diff line number Diff line
@@ -89,6 +89,7 @@ private:

    std::unordered_map<std::string, HttpRouteRecord> _httpRoutes;
    std::unordered_map<std::string, int32_t> _httpRoutePriorities; // routeId -> HttpRouteRecord::priority
    std::unordered_map<std::string, bool> _httpRouteForceHttpsRedirect; // routeId -> HttpRouteRecord::forceHttpsRedirect
    std::unordered_map<std::string, SmtpRelayRuleRecord> _smtpRelayRules;
    std::unordered_map<std::string, PluginConfigRecord> _pluginConfigs;
    std::unordered_map<std::string, PermissionRegistryRecord> _permissions;
+6 −0
Changes for src/store/Records.h: 6 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -38,6 +38,9 @@ struct HttpRouteRecord {
    // When true, a request matching this route that arrived over a plain (non-TLS) listener
    // gets a 301 redirect to the same host+path under "https://" instead of being proxied --
    // see HttpProxyController::RequestEvent. No effect on a listener that's already TLS.
    // Persisted separately from the rest of this record, same as priority above (see
    // ConfigStore::encodeHttpRoute's comment) -- round-trips through
    // ConfigStore::listHttpRoutes(), not through encodeHttpRoute/decodeHttpRoute directly.
    bool forceHttpsRedirect = false;
};

@@ -178,6 +181,9 @@ enum class RecordTable : uint8_t {
    // section, guarded the same way TlsProfile/UpstreamPool/DkimKey/ListenerTlsAssignment were
    // added, has no such ambiguity.
    HttpRoutePriority = 9,
    // HttpRouteRecord::forceHttpsRedirect's storage -- same reasoning as HttpRoutePriority
    // just above (own section, not a field appended to encodeHttpRoute/decodeHttpRoute).
    HttpRouteForceHttpsRedirect = 10,
};

enum class RecordOp : uint8_t {