blob: d64b9957bc42b217ed495b754b371be5a13fac1c [file] [log] [blame]
Ed Tanous7045c8d2017-04-03 10:04:37 -07001#pragma once
Ed Tanous1abe55e2018-09-05 08:30:59 -07002
Ed Tanous3ccb3ad2023-01-13 17:40:03 -08003#include "bmcweb_config.h"
4
Ed Tanous51dae672018-09-05 16:07:32 -07005#include <openssl/crypto.h>
6
Ed Tanousc867a832022-03-10 14:17:00 -08007#include <boost/callable_traits.hpp>
Ed Tanous079360a2022-06-29 10:05:19 -07008#include <boost/url/parse.hpp>
Ed Tanouseae855c2021-10-26 11:26:02 -07009#include <boost/url/url.hpp>
Ed Tanous079360a2022-06-29 10:05:19 -070010#include <boost/url/url_view.hpp>
Ed Tanous71f2db72022-05-25 12:28:09 -070011#include <nlohmann/json.hpp>
Nan Zhou1d8782e2021-11-29 22:23:18 -080012
Ed Tanous9ea15c32022-01-04 14:18:22 -080013#include <array>
Ed Tanous74849be2021-02-05 09:47:47 -080014#include <chrono>
Ed Tanousc715ec22022-03-10 15:38:01 -080015#include <cstddef>
Ed Tanous7045c8d2017-04-03 10:04:37 -070016#include <cstdint>
Ed Tanous9ea15c32022-01-04 14:18:22 -080017#include <ctime>
Ed Tanous7045c8d2017-04-03 10:04:37 -070018#include <functional>
Ed Tanous9896eae2022-07-23 15:07:33 -070019#include <iomanip>
Ed Tanous9ea15c32022-01-04 14:18:22 -080020#include <limits>
Ed Tanous7045c8d2017-04-03 10:04:37 -070021#include <stdexcept>
22#include <string>
Ed Tanous9ea15c32022-01-04 14:18:22 -080023#include <string_view>
Ed Tanous7045c8d2017-04-03 10:04:37 -070024#include <tuple>
Ed Tanous9ea15c32022-01-04 14:18:22 -080025#include <type_traits>
26#include <utility>
Szymon Dompkeca1600c2022-03-03 14:42:52 +010027#include <variant>
Ed Tanous7045c8d2017-04-03 10:04:37 -070028
Ed Tanous1abe55e2018-09-05 08:30:59 -070029namespace crow
30{
Ed Tanous47488a92023-06-26 18:19:33 -070031namespace utility
Ed Tanous1abe55e2018-09-05 08:30:59 -070032{
Ed Tanous7045c8d2017-04-03 10:04:37 -070033
Ed Tanousc715ec22022-03-10 15:38:01 -080034enum class TypeCode : uint8_t
35{
36 Unspecified = 0,
Ed Tanous15a42df2023-02-09 18:08:23 -080037 String = 1,
38 Path = 2,
39 Max = 3,
Ed Tanousc715ec22022-03-10 15:38:01 -080040};
41
42// Remove when we have c++23
43template <typename E>
44constexpr typename std::underlying_type<E>::type toUnderlying(E e) noexcept
45{
46 return static_cast<typename std::underlying_type<E>::type>(e);
47}
48
Ed Tanous1c30e502022-03-08 18:02:24 -080049constexpr inline uint64_t getParameterTag(std::string_view url)
Ed Tanous1abe55e2018-09-05 08:30:59 -070050{
Ed Tanous1c30e502022-03-08 18:02:24 -080051 uint64_t tagValue = 0;
52 size_t urlSegmentIndex = std::string_view::npos;
Ed Tanousb00dcc22021-02-23 12:52:50 -080053
Ed Tanous1c30e502022-03-08 18:02:24 -080054 size_t paramIndex = 0;
55
56 for (size_t urlIndex = 0; urlIndex < url.size(); urlIndex++)
57 {
58 char character = url[urlIndex];
59 if (character == '<')
60 {
61 if (urlSegmentIndex != std::string_view::npos)
62 {
63 return 0;
64 }
65 urlSegmentIndex = urlIndex;
66 }
67 if (character == '>')
68 {
69 if (urlSegmentIndex == std::string_view::npos)
70 {
71 return 0;
72 }
Patrick Williams89492a12023-05-10 07:51:34 -050073 std::string_view tag = url.substr(urlSegmentIndex,
74 urlIndex + 1 - urlSegmentIndex);
Ed Tanous1c30e502022-03-08 18:02:24 -080075
76 // Note, this is a really lame way to do std::pow(6, paramIndex)
77 // std::pow doesn't work in constexpr in clang.
78 // Ideally in the future we'd move this to use a power of 2 packing
79 // (probably 8 instead of 6) so that these just become bit shifts
80 uint64_t insertIndex = 1;
81 for (size_t unused = 0; unused < paramIndex; unused++)
82 {
Ed Tanous15a42df2023-02-09 18:08:23 -080083 insertIndex *= 3;
Ed Tanous1c30e502022-03-08 18:02:24 -080084 }
85
Ed Tanous1c30e502022-03-08 18:02:24 -080086 if (tag == "<str>" || tag == "<string>")
87 {
Ed Tanousc715ec22022-03-10 15:38:01 -080088 tagValue += insertIndex * toUnderlying(TypeCode::String);
Ed Tanous1c30e502022-03-08 18:02:24 -080089 }
90 if (tag == "<path>")
91 {
Ed Tanousc715ec22022-03-10 15:38:01 -080092 tagValue += insertIndex * toUnderlying(TypeCode::Path);
Ed Tanous1c30e502022-03-08 18:02:24 -080093 }
94 paramIndex++;
95 urlSegmentIndex = std::string_view::npos;
96 }
97 }
98 if (urlSegmentIndex != std::string_view::npos)
Ed Tanous988403c2020-08-24 11:29:49 -070099 {
100 return 0;
101 }
Ed Tanous1c30e502022-03-08 18:02:24 -0800102 return tagValue;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700103}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700104
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500105template <typename T>
Ed Tanousc867a832022-03-10 14:17:00 -0800106struct FunctionTraits
Ed Tanous1abe55e2018-09-05 08:30:59 -0700107{
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500108 template <size_t i>
Ed Tanousc867a832022-03-10 14:17:00 -0800109 using arg = std::tuple_element_t<i, boost::callable_traits::args_t<T>>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700110};
111
Ed Tanouscfe3bc02023-06-26 12:47:24 -0700112constexpr size_t numArgsFromTag(int tag)
113{
114 size_t ret = 0;
115 while (tag > 0)
116 {
117 // Move to the next tag by removing the bottom bits from the number
Ed Tanous47488a92023-06-26 18:19:33 -0700118 tag /= toUnderlying(TypeCode::Max);
Ed Tanouscfe3bc02023-06-26 12:47:24 -0700119 ret++;
120 }
121 return ret;
122};
123
Ed Tanous26ccae32023-02-16 10:28:44 -0800124inline std::string base64encode(std::string_view data)
Adriana Kobylakd830ff52021-01-27 14:15:27 -0600125{
126 const std::array<char, 64> key = {
127 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
128 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
129 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
130 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
131 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
132
133 size_t size = data.size();
134 std::string ret;
135 ret.resize((size + 2) / 3 * 4);
136 auto it = ret.begin();
137
138 size_t i = 0;
139 while (i < size)
140 {
Ed Tanous543f4402022-01-06 13:12:53 -0800141 size_t keyIndex = 0;
Adriana Kobylakd830ff52021-01-27 14:15:27 -0600142
143 keyIndex = static_cast<size_t>(data[i] & 0xFC) >> 2;
144 *it++ = key[keyIndex];
145
146 if (i + 1 < size)
147 {
148 keyIndex = static_cast<size_t>(data[i] & 0x03) << 4;
149 keyIndex += static_cast<size_t>(data[i + 1] & 0xF0) >> 4;
150 *it++ = key[keyIndex];
151
152 if (i + 2 < size)
153 {
154 keyIndex = static_cast<size_t>(data[i + 1] & 0x0F) << 2;
155 keyIndex += static_cast<size_t>(data[i + 2] & 0xC0) >> 6;
156 *it++ = key[keyIndex];
157
158 keyIndex = static_cast<size_t>(data[i + 2] & 0x3F);
159 *it++ = key[keyIndex];
160 }
161 else
162 {
163 keyIndex = static_cast<size_t>(data[i + 1] & 0x0F) << 2;
164 *it++ = key[keyIndex];
165 *it++ = '=';
166 }
167 }
168 else
169 {
170 keyIndex = static_cast<size_t>(data[i] & 0x03) << 4;
171 *it++ = key[keyIndex];
172 *it++ = '=';
173 *it++ = '=';
174 }
175
176 i += 3;
177 }
178
179 return ret;
180}
181
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100182// TODO this is temporary and should be deleted once base64 is refactored out of
183// crow
Ed Tanous26ccae32023-02-16 10:28:44 -0800184inline bool base64Decode(std::string_view input, std::string& output)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700185{
Ed Tanous271584a2019-07-09 16:24:22 -0700186 static const char nop = static_cast<char>(-1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700187 // See note on encoding_data[] in above function
Jonathan Doman5beaf842020-08-14 11:23:33 -0700188 static const std::array<char, 256> decodingData = {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700189 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
190 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
191 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
192 nop, 62, nop, nop, nop, 63, 52, 53, 54, 55, 56, 57, 58, 59,
193 60, 61, nop, nop, nop, nop, nop, nop, nop, 0, 1, 2, 3, 4,
194 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
195 19, 20, 21, 22, 23, 24, 25, nop, nop, nop, nop, nop, nop, 26,
196 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
197 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, nop, nop, nop,
198 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
199 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
200 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
201 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
202 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
203 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
204 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
205 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
206 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
207 nop, nop, nop, nop};
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100208
Ed Tanous1abe55e2018-09-05 08:30:59 -0700209 size_t inputLength = input.size();
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100210
Ed Tanous1abe55e2018-09-05 08:30:59 -0700211 // allocate space for output string
212 output.clear();
213 output.reserve(((inputLength + 2) / 3) * 4);
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100214
Jonathan Doman5beaf842020-08-14 11:23:33 -0700215 auto getCodeValue = [](char c) {
216 auto code = static_cast<unsigned char>(c);
217 // Ensure we cannot index outside the bounds of the decoding array
218 static_assert(std::numeric_limits<decltype(code)>::max() <
219 decodingData.size());
220 return decodingData[code];
221 };
222
Ed Tanous1abe55e2018-09-05 08:30:59 -0700223 // for each 4-bytes sequence from the input, extract 4 6-bits sequences by
Gunnar Millscaa3ce32020-07-08 14:46:53 -0500224 // dropping first two bits
Ed Tanous1abe55e2018-09-05 08:30:59 -0700225 // and regenerate into 3 8-bits sequences
James Feist5a806642020-07-31 16:40:33 +0000226
Ed Tanous1abe55e2018-09-05 08:30:59 -0700227 for (size_t i = 0; i < inputLength; i++)
228 {
Ed Tanous543f4402022-01-06 13:12:53 -0800229 char base64code0 = 0;
230 char base64code1 = 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700231 char base64code2 = 0; // initialized to 0 to suppress warnings
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100232
Jonathan Doman5beaf842020-08-14 11:23:33 -0700233 base64code0 = getCodeValue(input[i]);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700234 if (base64code0 == nop)
235 { // non base64 character
236 return false;
237 }
238 if (!(++i < inputLength))
239 { // we need at least two input bytes for first
240 // byte output
241 return false;
242 }
Jonathan Doman5beaf842020-08-14 11:23:33 -0700243 base64code1 = getCodeValue(input[i]);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700244 if (base64code1 == nop)
245 { // non base64 character
246 return false;
247 }
248 output +=
249 static_cast<char>((base64code0 << 2) | ((base64code1 >> 4) & 0x3));
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100250
Ed Tanous1abe55e2018-09-05 08:30:59 -0700251 if (++i < inputLength)
252 {
253 char c = input[i];
254 if (c == '=')
255 { // padding , end of input
256 return (base64code1 & 0x0f) == 0;
257 }
Jonathan Doman5beaf842020-08-14 11:23:33 -0700258 base64code2 = getCodeValue(input[i]);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700259 if (base64code2 == nop)
260 { // non base64 character
261 return false;
262 }
263 output += static_cast<char>(((base64code1 << 4) & 0xf0) |
264 ((base64code2 >> 2) & 0x0f));
265 }
266
267 if (++i < inputLength)
268 {
269 char c = input[i];
270 if (c == '=')
271 { // padding , end of input
272 return (base64code2 & 0x03) == 0;
273 }
Ed Tanousf8fe53e2022-06-30 15:55:45 -0700274 char base64code3 = getCodeValue(input[i]);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700275 if (base64code3 == nop)
276 { // non base64 character
277 return false;
278 }
279 output +=
280 static_cast<char>((((base64code2 << 6) & 0xc0) | base64code3));
281 }
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100282 }
283
Ed Tanous1abe55e2018-09-05 08:30:59 -0700284 return true;
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100285}
286
Ed Tanous26ccae32023-02-16 10:28:44 -0800287inline bool constantTimeStringCompare(std::string_view a, std::string_view b)
Ed Tanous51dae672018-09-05 16:07:32 -0700288{
289 // Important note, this function is ONLY constant time if the two input
290 // sizes are the same
291 if (a.size() != b.size())
292 {
293 return false;
294 }
295 return CRYPTO_memcmp(a.data(), b.data(), a.size()) == 0;
296}
297
298struct ConstantTimeCompare
299{
Ed Tanous26ccae32023-02-16 10:28:44 -0800300 bool operator()(std::string_view a, std::string_view b) const
Ed Tanous51dae672018-09-05 16:07:32 -0700301 {
302 return constantTimeStringCompare(a, b);
303 }
304};
305
Ed Tanouseae855c2021-10-26 11:26:02 -0700306namespace details
307{
308inline boost::urls::url
Willy Tuc6bcedc2022-09-27 05:36:59 +0000309 appendUrlPieces(boost::urls::url& url,
310 const std::initializer_list<std::string_view> args)
Ed Tanouseae855c2021-10-26 11:26:02 -0700311{
Ed Tanous26ccae32023-02-16 10:28:44 -0800312 for (std::string_view arg : args)
Ed Tanouseae855c2021-10-26 11:26:02 -0700313 {
314 url.segments().push_back(arg);
315 }
316 return url;
317}
Willy Tuc6bcedc2022-09-27 05:36:59 +0000318
Ed Tanouseae855c2021-10-26 11:26:02 -0700319} // namespace details
320
Ed Tanous7f8d8fa2022-08-19 07:00:38 -0700321class OrMorePaths
322{};
323
Ed Tanouseae855c2021-10-26 11:26:02 -0700324template <typename... AV>
Willy Tuc6bcedc2022-09-27 05:36:59 +0000325inline void appendUrlPieces(boost::urls::url& url, const AV... args)
326{
327 details::appendUrlPieces(url, {args...});
328}
329
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100330namespace details
331{
332
333// std::reference_wrapper<std::string> - extracts segment to variable
334// std::string_view - checks if segment is equal to variable
Ed Tanous7f8d8fa2022-08-19 07:00:38 -0700335using UrlSegment = std::variant<std::reference_wrapper<std::string>,
336 std::string_view, OrMorePaths>;
337
338enum class UrlParseResult
339{
340 Continue,
341 Fail,
342 Done,
343};
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100344
345class UrlSegmentMatcherVisitor
346{
347 public:
Ed Tanous7f8d8fa2022-08-19 07:00:38 -0700348 UrlParseResult operator()(std::string& output)
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100349 {
Ed Tanous079360a2022-06-29 10:05:19 -0700350 output = segment;
Ed Tanous7f8d8fa2022-08-19 07:00:38 -0700351 return UrlParseResult::Continue;
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100352 }
353
Ed Tanous7f8d8fa2022-08-19 07:00:38 -0700354 UrlParseResult operator()(std::string_view expected)
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100355 {
Ed Tanous079360a2022-06-29 10:05:19 -0700356 if (segment == expected)
Ed Tanous7f8d8fa2022-08-19 07:00:38 -0700357 {
358 return UrlParseResult::Continue;
359 }
360 return UrlParseResult::Fail;
361 }
362
363 UrlParseResult operator()(OrMorePaths /*unused*/)
364 {
365 return UrlParseResult::Done;
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100366 }
367
Ed Tanous079360a2022-06-29 10:05:19 -0700368 explicit UrlSegmentMatcherVisitor(std::string_view segmentIn) :
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100369 segment(segmentIn)
370 {}
371
372 private:
Ed Tanous079360a2022-06-29 10:05:19 -0700373 std::string_view segment;
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100374};
375
Ed Tanousd9f466b2023-03-06 15:04:25 -0800376inline bool readUrlSegments(boost::urls::url_view url,
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100377 std::initializer_list<UrlSegment>&& segments)
378{
Ed Tanousd9f466b2023-03-06 15:04:25 -0800379 boost::urls::segments_view urlSegments = url.segments();
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100380
Ed Tanous7f8d8fa2022-08-19 07:00:38 -0700381 if (!urlSegments.is_absolute())
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100382 {
383 return false;
384 }
385
386 boost::urls::segments_view::iterator it = urlSegments.begin();
387 boost::urls::segments_view::iterator end = urlSegments.end();
388
389 for (const auto& segment : segments)
390 {
Ed Tanous7f8d8fa2022-08-19 07:00:38 -0700391 if (it == end)
392 {
393 // If the request ends with an "any" path, this was successful
394 return std::holds_alternative<OrMorePaths>(segment);
395 }
396 UrlParseResult res = std::visit(UrlSegmentMatcherVisitor(*it), segment);
397 if (res == UrlParseResult::Done)
398 {
399 return true;
400 }
401 if (res == UrlParseResult::Fail)
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100402 {
403 return false;
404 }
405 it++;
406 }
Carson Labrado4c30e222022-06-24 22:16:00 +0000407
408 // There will be an empty segment at the end if the URI ends with a "/"
409 // e.g. /redfish/v1/Chassis/
410 if ((it != end) && urlSegments.back().empty())
411 {
412 it++;
413 }
Ed Tanous7f8d8fa2022-08-19 07:00:38 -0700414 return it == end;
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100415}
416
417} // namespace details
418
419template <typename... Args>
Ed Tanousd9f466b2023-03-06 15:04:25 -0800420inline bool readUrlSegments(boost::urls::url_view url, Args&&... args)
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100421{
Ed Tanous39662a32023-02-06 15:09:46 -0800422 return details::readUrlSegments(url, {std::forward<Args>(args)...});
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100423}
424
Ed Tanousd9f466b2023-03-06 15:04:25 -0800425inline boost::urls::url replaceUrlSegment(boost::urls::url_view urlView,
Carson Labrado1c0bb5c2022-05-18 00:12:52 +0000426 const uint replaceLoc,
Ed Tanous26ccae32023-02-16 10:28:44 -0800427 std::string_view newSegment)
Carson Labrado1c0bb5c2022-05-18 00:12:52 +0000428{
Ed Tanousd9f466b2023-03-06 15:04:25 -0800429 boost::urls::segments_view urlSegments = urlView.segments();
Carson Labrado1c0bb5c2022-05-18 00:12:52 +0000430 boost::urls::url url("/");
431
432 if (!urlSegments.is_absolute())
433 {
434 return url;
435 }
436
437 boost::urls::segments_view::iterator it = urlSegments.begin();
438 boost::urls::segments_view::iterator end = urlSegments.end();
439
440 for (uint idx = 0; it != end; it++, idx++)
441 {
442 if (idx == replaceLoc)
443 {
444 url.segments().push_back(newSegment);
445 }
446 else
447 {
448 url.segments().push_back(*it);
449 }
450 }
451
452 return url;
453}
454
Ed Tanousd9f466b2023-03-06 15:04:25 -0800455inline std::string setProtocolDefaults(boost::urls::url_view urlView)
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800456{
Ed Tanous39662a32023-02-06 15:09:46 -0800457 if (urlView.scheme() == "https")
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800458 {
459 return "https";
460 }
Ed Tanous39662a32023-02-06 15:09:46 -0800461 if (urlView.scheme() == "http")
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800462 {
463 if (bmcwebInsecureEnableHttpPushStyleEventing)
464 {
465 return "http";
466 }
467 return "";
468 }
Chicago Duan3d307082020-11-26 14:12:12 +0800469 if (urlView.scheme() == "snmp")
470 {
471 return "snmp";
472 }
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800473 return "";
474}
475
Ed Tanousd9f466b2023-03-06 15:04:25 -0800476inline uint16_t setPortDefaults(boost::urls::url_view url)
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800477{
478 uint16_t port = url.port_number();
479 if (port != 0)
480 {
481 // user picked a port already.
482 return port;
483 }
484
485 // If the user hasn't explicitly stated a port, pick one explicitly for them
486 // based on the protocol defaults
487 if (url.scheme() == "http")
488 {
489 return 80;
490 }
491 if (url.scheme() == "https")
492 {
493 return 443;
494 }
Chicago Duan3d307082020-11-26 14:12:12 +0800495 if (url.scheme() == "snmp")
496 {
497 return 162;
498 }
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800499 return 0;
500}
501
Ed Tanous11baefe2022-02-09 12:14:12 -0800502inline bool validateAndSplitUrl(std::string_view destUrl, std::string& urlProto,
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800503 std::string& host, uint16_t& port,
Ed Tanous11baefe2022-02-09 12:14:12 -0800504 std::string& path)
505{
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800506 boost::urls::result<boost::urls::url_view> url =
Ed Tanous079360a2022-06-29 10:05:19 -0700507 boost::urls::parse_uri(destUrl);
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800508 if (!url)
509 {
510 return false;
511 }
512 urlProto = setProtocolDefaults(url.value());
513 if (urlProto.empty())
Ed Tanous11baefe2022-02-09 12:14:12 -0800514 {
515 return false;
516 }
517
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800518 port = setPortDefaults(url.value());
Ed Tanous11baefe2022-02-09 12:14:12 -0800519
Ed Tanous079360a2022-06-29 10:05:19 -0700520 host = url->encoded_host();
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800521
Ed Tanous079360a2022-06-29 10:05:19 -0700522 path = url->encoded_path();
Ed Tanous11baefe2022-02-09 12:14:12 -0800523 if (path.empty())
524 {
525 path = "/";
526 }
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800527 if (url->has_fragment())
528 {
529 path += '#';
Ed Tanous079360a2022-06-29 10:05:19 -0700530 path += url->encoded_fragment();
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800531 }
532
533 if (url->has_query())
534 {
535 path += '?';
Ed Tanous079360a2022-06-29 10:05:19 -0700536 path += url->encoded_query();
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800537 }
538
Ed Tanous11baefe2022-02-09 12:14:12 -0800539 return true;
540}
541
Ed Tanous1abe55e2018-09-05 08:30:59 -0700542} // namespace utility
543} // namespace crow
Ed Tanous71f2db72022-05-25 12:28:09 -0700544
545namespace nlohmann
546{
547template <>
548struct adl_serializer<boost::urls::url>
549{
550 // nlohmann requires a specific casing to look these up in adl
551 // NOLINTNEXTLINE(readability-identifier-naming)
552 static void to_json(json& j, const boost::urls::url& url)
553 {
Ed Tanous079360a2022-06-29 10:05:19 -0700554 j = url.buffer();
Ed Tanous71f2db72022-05-25 12:28:09 -0700555 }
556};
557
558template <>
559struct adl_serializer<boost::urls::url_view>
560{
561 // NOLINTNEXTLINE(readability-identifier-naming)
Ed Tanousd9f466b2023-03-06 15:04:25 -0800562 static void to_json(json& j, boost::urls::url_view url)
Ed Tanous71f2db72022-05-25 12:28:09 -0700563 {
Ed Tanous079360a2022-06-29 10:05:19 -0700564 j = url.buffer();
Ed Tanous71f2db72022-05-25 12:28:09 -0700565 }
566};
567} // namespace nlohmann