Malloy
Loading...
Searching...
No Matches
endpoint_http_regex.hpp
1#pragma once
2
3#include "endpoint_http.hpp"
4#include "type_traits.hpp"
5#include "../../core/http/response.hpp"
6#include "../../core/type_traits.hpp"
7
8#include <functional>
9#include <regex>
10#include <cassert>
11
12namespace malloy::server
13{
15 {
16 [[nodiscard]]
17 virtual
18 bool
19 matches_resource(const boost::beast::http::request_header<>& req) const = 0;
20 };
21
22 template<typename Response, concepts::request_filter Handler, bool WantsCapture>
24 public endpoint_http, public resource_matcher
25 {
26 public:
27 template<typename Derived>
28 using req_gen_t = std::shared_ptr<typename http::connection<Derived>::request_generator>;
29
30 template<typename Req>
31 using handler_t = std::conditional_t<
32 WantsCapture,
33 std::function<Response(const Req&, const std::vector<std::string>&)>,
34 std::function<Response(const Req&)>
35 >;
36
37
38 Handler filter;
39 std::regex resource_base;
40 handler_t<typename Handler::request_type> handler;
41 std::function<void(const boost::beast::http::request_header<>&, Response&&, const http::connection_t&)> writer;
42
43 [[nodiscard]]
44 bool
45 matches_resource(const req_header_t& req) const override
46 {
47
48 return std::regex_match(req.target().begin(), req.target().end(), resource_base);
49 }
50
51 [[nodiscard]]
52 bool
53 matches(const req_header_t& req) const override
54 {
55 // Resource
56 if (!matches_resource(req))
57 return false;
58
59 // Base class
60 return endpoint_http::matches(req);
61 }
62
63
64 [[nodiscard]]
65 handle_retr
66 handle(const req_t& gens, const http::connection_t& conn) const override
67 {
68 if (handler) {
69 std::visit(
70 [this, conn]<typename Generator>(Generator && gen) {
71 this->visit_bodies(std::forward<Generator>(gen), conn);
72 },
73 gens
74 );
75
76 return std::nullopt;
77 }
78 else
79 return malloy::http::generator::server_error("no valid handler available.");
80 }
81 private:
82 void
83 handle_req(const auto& req, const http::connection_t& conn) const
84 {
85 if constexpr (WantsCapture) {
86 std::smatch url_matches;
87 std::string url{ req.target() };
88 std::regex_match(url, url_matches, resource_base);
89
90 if (url_matches.empty()) {
91 throw std::logic_error{
92 R"(endpoint_http_regex passed request which does not match: )" +
93 std::string{req.target()} };
94 }
95
96 std::vector<std::string> matches{// match_results[0] is the
97 // input
98 // string
99 url_matches.begin() + 1,
100 url_matches.end() };
101
102 writer(req, handler(req, matches), conn);
103 }
104 else
105 writer(req, handler(req), conn);
106 }
107
108 void
109 visit_bodies(const auto& gen, const http::connection_t& conn) const
110 {
111 using body_t = typename Handler::request_type::body_type;
112 gen->template body<body_t>(
113 [this, conn](const auto& req) {
114 this->handle_req(req, conn);
115 }, [&gen, this](auto& body) { filter.setup_body(gen->header(), body); });
116 }
117 };
118
119}
static response server_error(std::string_view what)
Definition: generator.cpp:47
Definition: endpoint_http_regex.hpp:25
bool matches(const req_header_t &req) const override
Definition: endpoint_http_regex.hpp:53
handle_retr handle(const req_t &gens, const http::connection_t &conn) const override
Definition: endpoint_http_regex.hpp:66
Definition: endpoint_http.hpp:22
virtual bool matches(const req_header_t &req) const
Definition: endpoint_http.hpp:54
Definition: endpoint_http_regex.hpp:15