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
67 if (param_val == "false")
68 {
69 val = false;
70 return true;
71 }
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 else if constexpr (std::is_integral_v<T>)
80 {
81 const auto [p, ec] =
82 std::from_chars(param_val.begin(), param_val.end(), val);
83 if (ec != std::errc() || p != param_val.end())
84 {
85 error_reason = fmt::format(
86 "Unable to parse value '{}' in parameter '{}'", param_val, param_key);
87 return false;
88 }
89
90 return true;
91 }
92 else
93 {
94 static_assert(ccf::nonstd::dependent_false<T>::value, "Unsupported type");
95 return false;
96 }
97 }
98
99 template <typename T>
100 static std::optional<T> get_query_value_opt(
101 const ParsedQuery& pq,
102 const std::string_view& param_key,
103 std::string& error_reason)
104 {
105 T val;
106 if (get_query_value(pq, param_key, val, error_reason))
107 {
108 return val;
109 }
110 return std::nullopt;
111 }
112}
Definition http_accept.h:13
std::multimap< std::string_view, std::string_view > ParsedQuery
Definition http_query.h:20
Definition nonstd.h:63