diff options
Diffstat (limited to 'server/src/srv.cpp')
| -rw-r--r-- | server/src/srv.cpp | 113 |
1 files changed, 111 insertions, 2 deletions
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 { | |||
| 30 | class gpx_parse_error_category_impl : public std::error_category | 30 | class gpx_parse_error_category_impl : public std::error_category |
| 31 | { | 31 | { |
| 32 | public: | 32 | public: |
| 33 | char const* name() const noexcept override { return "gpx_parse"; } | 33 | auto name() const noexcept -> char const* override { return "gpx_parse"; } |
| 34 | 34 | ||
| 35 | auto message(int condition) const noexcept -> std::string override | 35 | auto message(int condition) const noexcept -> std::string override |
| 36 | { | 36 | { |
| @@ -330,12 +330,120 @@ struct raw_deflate_body | |||
| 330 | }; | 330 | }; |
| 331 | }; | 331 | }; |
| 332 | 332 | ||
| 333 | auto parse_timestamp(std::string_view in) -> std::optional<time::timestamp> | ||
| 334 | { | ||
| 335 | auto res = time::timestamp{}; | ||
| 336 | auto is = std::istringstream{in}; | ||
| 337 | is >> std::chrono::parse("%Y-%m-%dT%H:%MZ", res); | ||
| 338 | return is.fail() ? std::nullopt : std::make_optional(res); | ||
| 339 | } | ||
| 340 | |||
| 333 | auto handler::handle_process_gpx(l0_ctx ctx, http::readable_request r) | 341 | auto handler::handle_process_gpx(l0_ctx ctx, http::readable_request r) |
| 334 | -> net::awaitable<http::presponse> | 342 | -> net::awaitable<http::presponse> |
| 335 | { | 343 | { |
| 336 | auto l = | 344 | auto l = |
| 337 | l_.sub("handle_process_gpx").with("trace_id", ctx.trace_id.as_string()); | 345 | l_.sub("handle_process_gpx").with("trace_id", ctx.trace_id.as_string()); |
| 338 | 346 | ||
| 347 | auto cp_begin = time::timestamp{}; | ||
| 348 | auto cp_end = time::timestamp{}; | ||
| 349 | |||
| 350 | auto const params = ctx.target.params(); | ||
| 351 | if (auto it = params.find("cpbegin"); it != params.end()) | ||
| 352 | { | ||
| 353 | auto mts = parse_timestamp((*it).value); | ||
| 354 | if (!mts) | ||
| 355 | { | ||
| 356 | auto tpl = problem::tpl{ | ||
| 357 | .status = bhttp::status::bad_request, | ||
| 358 | .title = translate("Query parameter has bad value"), | ||
| 359 | .type_uri = | ||
| 360 | "https://routemon.fautchen.eu/problems/query-param-bad-value", | ||
| 361 | }; | ||
| 362 | co_return http::problem_rsp( | ||
| 363 | ctx, tpl.instantiate(), http::keep_alive{false}); | ||
| 364 | } | ||
| 365 | cp_begin = *mts; | ||
| 366 | |||
| 367 | ++it; | ||
| 368 | if (it != params.end() && (*it).key == "cpbegin") | ||
| 369 | { | ||
| 370 | auto tpl = problem::tpl{ | ||
| 371 | .status = bhttp::status::bad_request, | ||
| 372 | .title = translate("Query parameter provided too many times"), | ||
| 373 | .type_uri = "https://routemon.fautchen.eu/problems/" | ||
| 374 | "query-param-too-many-occurrences", | ||
| 375 | }; | ||
| 376 | co_return http::problem_rsp( | ||
| 377 | ctx, tpl.instantiate(), http::keep_alive{false}); | ||
| 378 | } | ||
| 379 | } | ||
| 380 | else | ||
| 381 | { | ||
| 382 | auto tpl = problem::tpl{ | ||
| 383 | .status = bhttp::status::bad_request, | ||
| 384 | .title = translate("Required query parameter not provided"), | ||
| 385 | .type_uri = "https://routemon.fautchen.eu/problems/" | ||
| 386 | "required-query-param-not-provided", | ||
| 387 | }; | ||
| 388 | co_return http::problem_rsp( | ||
| 389 | ctx, tpl.instantiate(), http::keep_alive{false}); | ||
| 390 | } | ||
| 391 | if (auto it = params.find("cpend"); it != params.end()) | ||
| 392 | { | ||
| 393 | auto mts = parse_timestamp((*it).value); | ||
| 394 | if (!mts) | ||
| 395 | { | ||
| 396 | auto tpl = problem::tpl{ | ||
| 397 | .status = bhttp::status::bad_request, | ||
| 398 | .title = translate("Query parameter has bad value"), | ||
| 399 | .type_uri = | ||
| 400 | "https://routemon.fautchen.eu/problems/query-param-bad-value", | ||
| 401 | }; | ||
| 402 | co_return http::problem_rsp( | ||
| 403 | ctx, tpl.instantiate(), http::keep_alive{false}); | ||
| 404 | } | ||
| 405 | cp_end = *mts; | ||
| 406 | |||
| 407 | ++it; | ||
| 408 | if (it != params.end() && (*it).key == "cpend") | ||
| 409 | { | ||
| 410 | auto tpl = problem::tpl{ | ||
| 411 | .status = bhttp::status::bad_request, | ||
| 412 | .title = translate("Query parameter provided too many times"), | ||
| 413 | .type_uri = "https://routemon.fautchen.eu/problems/" | ||
| 414 | "query-param-too-many-occurrences", | ||
| 415 | }; | ||
| 416 | co_return http::problem_rsp( | ||
| 417 | ctx, tpl.instantiate(), http::keep_alive{false}); | ||
| 418 | } | ||
| 419 | } | ||
| 420 | else | ||
| 421 | { | ||
| 422 | auto tpl = problem::tpl{ | ||
| 423 | .status = bhttp::status::bad_request, | ||
| 424 | .title = translate("Required query parameter not provided"), | ||
| 425 | .type_uri = "https://routemon.fautchen.eu/problems/" | ||
| 426 | "required-query-param-not-provided", | ||
| 427 | }; | ||
| 428 | co_return http::problem_rsp( | ||
| 429 | ctx, tpl.instantiate(), http::keep_alive{false}); | ||
| 430 | } | ||
| 431 | |||
| 432 | if (cp_begin >= cp_end) | ||
| 433 | { | ||
| 434 | auto tpl = problem::tpl{ | ||
| 435 | .status = bhttp::status::bad_request, | ||
| 436 | .title = translate("Invalid check period provided"), | ||
| 437 | .type_uri = "https://routemon.fautchen.eu/problems/invalid-check-period", | ||
| 438 | }; | ||
| 439 | co_return http::problem_rsp( | ||
| 440 | ctx, | ||
| 441 | tpl.instantiate().set_detail(translate( | ||
| 442 | "Begin of check period must be before end of check period")), | ||
| 443 | http::keep_alive{false}); | ||
| 444 | } | ||
| 445 | auto cp = time::period{cp_begin, cp_end}; | ||
| 446 | |||
| 339 | auto gpx_file = gpx::file{}; | 447 | auto gpx_file = gpx::file{}; |
| 340 | try | 448 | try |
| 341 | { | 449 | { |
| @@ -378,7 +486,8 @@ auto handler::handle_process_gpx(l0_ctx ctx, http::readable_request r) | |||
| 378 | 486 | ||
| 379 | // TODO: catch handler exceptions and return 500 when raised? | 487 | // TODO: catch handler exceptions and return 500 when raised? |
| 380 | // (keep-alive depends on whether whole request was read) | 488 | // (keep-alive depends on whether whole request was read) |
| 381 | auto mres = inner_.process_gpx(ctx.trace_id, std::move(gpx_file)); | 489 | auto mres = inner_.process_gpx( |
| 490 | ctx.trace_id, std::move(gpx_file), time::period_seq{cp}); | ||
| 382 | if (!mres) | 491 | if (!mres) |
| 383 | { | 492 | { |
| 384 | auto tpl = problem::tpl{ | 493 | auto tpl = problem::tpl{ |