virthttp  0.0
libvirt http interface
handler.hpp
Go to the documentation of this file.
1 //
2 // Created by hugo on 09.06.19.
3 //
4 
5 #pragma once
6 
7 #include <utility>
8 #include <boost/beast/http/message.hpp>
9 #include <rapidjson/document.h>
10 #include "handlers/domain.hpp"
12 #include "actions_table.hpp"
13 #include "dispatch.hpp"
14 #include "general_store.hpp"
15 #include "json_utils.hpp"
16 #include "logger.hpp"
17 #include "solver.hpp"
18 #include "urlparser.hpp"
19 #include "virt_wrap.hpp"
20 
21 namespace beast = boost::beast;
22 namespace http = beast::http;
23 
24 template <class Body, class Allocator>
25 rapidjson::StringBuffer handle_json(GeneralStore& gstore, const http::request<Body, http::basic_fields<Allocator>>& req, const TargetParser& target) {
26  JsonRes json_res{};
27  auto error = [&](auto... args) { return json_res.error(args...); };
28 
29  auto object = [&](virt::Connection&& conn, auto resolver, auto jdispatchers, auto t_hdls) -> void {
30  using Object = typename decltype(resolver)::O;
31  using Handlers = typename decltype(t_hdls)::Type;
32  HandlerContext hdl_ctx{conn, json_res, target};
33  Object obj{};
34  Handlers hdls{hdl_ctx, obj};
35 
36  auto skip_resolve = req.method() == http::verb::post;
37  auto objs = !skip_resolve ? resolver(hdl_ctx) : std::vector<Object>{};
38  const auto idx = HandlerMethods::verb_to_idx(req.method());
39  if (idx < 0)
40  return error(3);
41  const auto mth = HandlerMethods::methods[idx];
42  rapidjson::Document json_req{};
43  json_req.Parse(req.body().data());
44 
45  auto exec = jdispatchers[idx](json_req, [&](const auto& jval) { return (hdls.*mth)(jval); });
46  if (skip_resolve)
47  exec(hdls);
48  else
49  for (auto&& v : objs)
50  obj = std::move(v), exec(hdls);
51  };
52 
53  constexpr Resolver domain_resolver{tp<virt::Domain, DomainUnawareHandlers>, "domains", std::array{"by-name"sv, "by-uuid"sv},
54  std::array{+[](const HandlerContext& hc, std::string_view sv) {
55  return hc.conn.domainLookupByName({sv.data(), sv.length()});
56  },
57  +[](const HandlerContext& hc, std::string_view sv) {
58  return hc.conn.domainLookupByUUIDString({sv.data(), sv.length()});
59  }},
60  [](HandlerContext& hc, auto flags) { return hc.conn.listAllDomains(flags); }};
61 
62  constexpr Resolver network_resolver{tp<virt::Network, NetworkUnawareHandlers>, "networks", std::array{"by-name"sv, "by-uuid"sv},
63  std::array{+[](const HandlerContext& hc, std::string_view sv) {
64  return hc.conn.networkLookupByName({sv.data(), sv.length()});
65  },
66  +[](const HandlerContext& hc, std::string_view sv) {
67  return hc.conn.networkLookupByUUIDString({sv.data(), sv.length()});
68  }},
69  [](HandlerContext& hc, auto flags) { return hc.conn.extractAllNetworks(flags); }};
70 
71  constexpr static std::array keys = {"domains"sv, "networks"sv};
72  std::tuple fcns = {std::bind(object, std::placeholders::_1, domain_resolver, domain_jdispatchers, t_<DomainHandlers>),
73  std::bind(object, std::placeholders::_1, network_resolver, network_jdispatchers, t_<NetworkHandlers>)};
74 
75  [&] {
76  auto& config = gstore.config();
77  if (config.isHTTPAuthRequired() && req["X-Auth-Key"] != config.http_auth_key)
78  return error(1);
79  auto path_parts = target.getPathParts();
80  if (path_parts.empty())
81  return error(4); // Empty request (/)
82  if (path_parts.front() != "libvirt")
83  return error(5); // Path does not start by /libvirt
84  if (path_parts.size() <= 1)
85  return error(6); // Path is only /libvirt
86 
87  logger.debug("Opening connection to ", config.getConnURI());
88  virt::Connection conn{config.connURI.c_str()};
89 
90  if (!conn) {
91  logger.error("Failed to open connection to ", config.getConnURI());
92  return error(10);
93  }
94 
95  const auto it = std::find(keys.begin(), keys.end(), path_parts[1]);
96  if (it == keys.end())
97  return error(7);
98 
99  int i = std::distance(keys.begin(), it);
100  return visit(fcns, [&](const auto& e) {
101  if (i-- == 0)
102  e(std::move(conn));
103  });
104  }();
105 
106  rapidjson::StringBuffer buffer;
107  using UTF8_Writer = rapidjson::Writer<rapidjson::StringBuffer, rapidjson::Document::EncodingType, rapidjson::UTF8<>>;
108  UTF8_Writer writer(buffer);
109  json_res.Accept(writer);
110 
111  return buffer;
112 }
const auto & config() const noexcept
Definition: general_store.hpp:20
auto listAllDomains(enums::connection::list::domains::Flag flags) const -> std::vector< Domain >
Definition: Connection.hpp:202
void error(int code)
Definition: json_utils.hpp:57
Domain domainLookupByName(gsl::czstring<>) const noexcept
Definition: Connection.hpp:232
constexpr std::array< JDispatch, std::tuple_size_v< DomainJDispatcherVals > > domain_jdispatchers
Definition: domain.hpp:32
Logger logger
Definition: logger.hpp:58
Network networkLookupByUUIDString(gsl::czstring<> uuid_str) const noexcept
Definition: Connection.hpp:258
Definition: Connection.hpp:47
void error(Ts...msg)
Definition: logger.hpp:25
Network networkLookupByName(gsl::czstring<> name) const noexcept
Definition: Connection.hpp:256
constexpr auto network_jdispatchers
Definition: network.hpp:28
Definition: json_utils.hpp:21
virt::Connection & conn
the connection to perform libvirt operations through (plans to change to a vector) ...
Definition: hdl_ctx.hpp:12
Definition: hdl_ctx.hpp:11
Domain domainLookupByUUIDString(gsl::czstring<>) const noexcept
Definition: Connection.hpp:239
rapidjson::StringBuffer handle_json(GeneralStore &gstore, const http::request< Body, http::basic_fields< Allocator >> &req, const TargetParser &target)
Definition: handler.hpp:25
static constexpr std::array methods
Definition: base.hpp:83
static constexpr long verb_to_idx(boost::beast::http::verb v) noexcept
Definition: base.hpp:100
constexpr const std::vector< std::string_view > & getPathParts() const noexcept
Definition: urlparser.hpp:83
constexpr InputIt find(InputIt first, InputIt last, const T &value)
Definition: cexpr_algs.hpp:4
Definition: urlparser.hpp:36
void visit(T &&t, V &&v)
Definition: utility.hpp:44
std::vector< Network > extractAllNetworks(enums::connection::list::networks::Flag) const
Definition: Connection.hpp:301
Definition: general_store.hpp:5
void debug(Ts...msg)
Definition: logger.hpp:39
Definition: solver.hpp:20