CCF
Loading...
Searching...
No Matches
http_query.h
Go to the documentation of this file.
1// Copyright (c) Microsoft Corporation. All rights reserved.
2// Licensed under the Apache 2.0 License.
3#pragma once
4
5#include "ccf/ds/nonstd.h"
6
7#define FMT_HEADER_ONLY
8#include <charconv>
9#include <fmt/format.h>
10#include <map>
11#include <optional>
12#include <string_view>
13
14namespace ccf::http
15{
16 // Query is parsed into a multimap, so that duplicate keys are retained.
17 // Handling of duplicates (or ignoring them entirely) is left to the caller.
18 // Keys and values are both string_views, pointing at subranges of original
19 // query string.
20 using ParsedQuery = std::multimap<std::string_view, std::string_view>;
21
22 static ParsedQuery parse_query(const std::string_view& query)
23 {
24 ParsedQuery parsed;
25 const auto params = ccf::nonstd::split(query, "&");
26 for (const auto& param : params)
27 {
28 // NB: This means both `foo=` and `foo` will be accepted and result in a
29 // `{"foo": ""}` in the map
30 const auto& [key, value] = ccf::nonstd::split_1(param, "=");
31 parsed.emplace(key, value);
32 }
33
34 return parsed;
35 }
36
37 template <typename T>
38 static bool get_query_value(
39 const ParsedQuery& pq,
40 const std::string_view& param_key,
41 T& val,
42 std::string& error_reason)
43 {
44 const auto it = pq.find(param_key);
45
46 if (it == pq.end())
47 {
48 error_reason = fmt::format("Missing query parameter '{}'", param_key);
49 return false;
50 }
51
52 const std::string_view& param_val = it->second;
53
54 if constexpr (std::is_same_v<T, std::string>)
55 {
56 val = T(param_val);
57 return true;
58 }
59 else if constexpr (std::is_same_v<T, bool>)
60 {
61 if (param_val == "true")
62 {
63 val = true;
64 return true;
65 }
66 else if (param_val == "false")
67 {
68 val = false;
69 return true;
70 }
71 else
72 {
73 error_reason = fmt::format(
74 "Unable to parse value '{}' as bool in parameter '{}'",
75 param_val,
76 param_key);
77 return false;
78 }
79 }
80 else if constexpr (std::is_integral_v<T>)
81 {
82 const auto [p, ec] =
83 std::from_chars(param_val.begin(), param_val.end(), val);
84 if (ec != std::errc() || p != param_val.end())
85 {
86 error_reason = fmt::format(
87 "Unable to parse value '{}' in parameter '{}'", param_val, param_key);
88 return false;
89 }
90
91 return true;
92 }
93 else
94 {
95 static_assert(ccf::nonstd::dependent_false<T>::value, "Unsupported type");
96 return false;
97 }
98 }
99
100 template <typename T>
101 static std::optional<T> get_query_value_opt(
102 const ParsedQuery& pq,
103 const std::string_view& param_key,
104 std::string& error_reason)
105 {
106 T val;
107 if (get_query_value(pq, param_key, val, error_reason))
108 {
109 return val;
110 }
111 else
112 {
113 return std::nullopt;
114 }
115 }
116}
Definition http_accept.h:13
std::multimap< std::string_view, std::string_view > ParsedQuery
Definition http_query.h:20
Definition nonstd.h:63