From ecf1be3f834c7187312f8eee71f77e448c995388 Mon Sep 17 00:00:00 2001 From: Rutger Broekhoff Date: Tue, 22 Sep 2026 22:28:10 +0200 Subject: Check period selection --- server/src/srv.cpp | 113 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 111 insertions(+), 2 deletions(-) (limited to 'server/src/srv.cpp') diff --git a/server/src/srv.cpp b/server/src/srv.cpp index dc9c814..5de0fc5 100644 --- a/server/src/srv.cpp +++ b/server/src/srv.cpp @@ -30,7 +30,7 @@ namespace routemon::srv { class gpx_parse_error_category_impl : public std::error_category { public: - char const* name() const noexcept override { return "gpx_parse"; } + auto name() const noexcept -> char const* override { return "gpx_parse"; } auto message(int condition) const noexcept -> std::string override { @@ -330,12 +330,120 @@ struct raw_deflate_body }; }; +auto parse_timestamp(std::string_view in) -> std::optional +{ + auto res = time::timestamp{}; + auto is = std::istringstream{in}; + is >> std::chrono::parse("%Y-%m-%dT%H:%MZ", res); + return is.fail() ? std::nullopt : std::make_optional(res); +} + auto handler::handle_process_gpx(l0_ctx ctx, http::readable_request r) -> net::awaitable { auto l = l_.sub("handle_process_gpx").with("trace_id", ctx.trace_id.as_string()); + auto cp_begin = time::timestamp{}; + auto cp_end = time::timestamp{}; + + auto const params = ctx.target.params(); + if (auto it = params.find("cpbegin"); it != params.end()) + { + auto mts = parse_timestamp((*it).value); + if (!mts) + { + auto tpl = problem::tpl{ + .status = bhttp::status::bad_request, + .title = translate("Query parameter has bad value"), + .type_uri = + "https://routemon.fautchen.eu/problems/query-param-bad-value", + }; + co_return http::problem_rsp( + ctx, tpl.instantiate(), http::keep_alive{false}); + } + cp_begin = *mts; + + ++it; + if (it != params.end() && (*it).key == "cpbegin") + { + auto tpl = problem::tpl{ + .status = bhttp::status::bad_request, + .title = translate("Query parameter provided too many times"), + .type_uri = "https://routemon.fautchen.eu/problems/" + "query-param-too-many-occurrences", + }; + co_return http::problem_rsp( + ctx, tpl.instantiate(), http::keep_alive{false}); + } + } + else + { + auto tpl = problem::tpl{ + .status = bhttp::status::bad_request, + .title = translate("Required query parameter not provided"), + .type_uri = "https://routemon.fautchen.eu/problems/" + "required-query-param-not-provided", + }; + co_return http::problem_rsp( + ctx, tpl.instantiate(), http::keep_alive{false}); + } + if (auto it = params.find("cpend"); it != params.end()) + { + auto mts = parse_timestamp((*it).value); + if (!mts) + { + auto tpl = problem::tpl{ + .status = bhttp::status::bad_request, + .title = translate("Query parameter has bad value"), + .type_uri = + "https://routemon.fautchen.eu/problems/query-param-bad-value", + }; + co_return http::problem_rsp( + ctx, tpl.instantiate(), http::keep_alive{false}); + } + cp_end = *mts; + + ++it; + if (it != params.end() && (*it).key == "cpend") + { + auto tpl = problem::tpl{ + .status = bhttp::status::bad_request, + .title = translate("Query parameter provided too many times"), + .type_uri = "https://routemon.fautchen.eu/problems/" + "query-param-too-many-occurrences", + }; + co_return http::problem_rsp( + ctx, tpl.instantiate(), http::keep_alive{false}); + } + } + else + { + auto tpl = problem::tpl{ + .status = bhttp::status::bad_request, + .title = translate("Required query parameter not provided"), + .type_uri = "https://routemon.fautchen.eu/problems/" + "required-query-param-not-provided", + }; + co_return http::problem_rsp( + ctx, tpl.instantiate(), http::keep_alive{false}); + } + + if (cp_begin >= cp_end) + { + auto tpl = problem::tpl{ + .status = bhttp::status::bad_request, + .title = translate("Invalid check period provided"), + .type_uri = "https://routemon.fautchen.eu/problems/invalid-check-period", + }; + co_return http::problem_rsp( + ctx, + tpl.instantiate().set_detail(translate( + "Begin of check period must be before end of check period")), + http::keep_alive{false}); + } + auto cp = time::period{cp_begin, cp_end}; + auto gpx_file = gpx::file{}; try { @@ -378,7 +486,8 @@ auto handler::handle_process_gpx(l0_ctx ctx, http::readable_request r) // TODO: catch handler exceptions and return 500 when raised? // (keep-alive depends on whether whole request was read) - auto mres = inner_.process_gpx(ctx.trace_id, std::move(gpx_file)); + auto mres = inner_.process_gpx( + ctx.trace_id, std::move(gpx_file), time::period_seq{cp}); if (!mres) { auto tpl = problem::tpl{ -- cgit v1.3