blob: 5a2dc67d5ba2022e3cb4b2a4c972ed2aeea517af [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 Tanous4a7fbef2024-04-06 16:03:49 -070011#include <boost/url/url_view_base.hpp>
Ed Tanous71f2db72022-05-25 12:28:09 -070012#include <nlohmann/json.hpp>
Nan Zhou1d8782e2021-11-29 22:23:18 -080013
Ed Tanous9ea15c32022-01-04 14:18:22 -080014#include <array>
Ed Tanous74849be2021-02-05 09:47:47 -080015#include <chrono>
Ed Tanousc715ec22022-03-10 15:38:01 -080016#include <cstddef>
Ed Tanous7045c8d2017-04-03 10:04:37 -070017#include <cstdint>
Ed Tanous9ea15c32022-01-04 14:18:22 -080018#include <ctime>
Ed Tanous7045c8d2017-04-03 10:04:37 -070019#include <functional>
Ed Tanous9896eae2022-07-23 15:07:33 -070020#include <iomanip>
Ed Tanous9ea15c32022-01-04 14:18:22 -080021#include <limits>
Ed Tanous7045c8d2017-04-03 10:04:37 -070022#include <stdexcept>
23#include <string>
Ed Tanous9ea15c32022-01-04 14:18:22 -080024#include <string_view>
Ed Tanous7045c8d2017-04-03 10:04:37 -070025#include <tuple>
Ed Tanous9ea15c32022-01-04 14:18:22 -080026#include <type_traits>
27#include <utility>
Szymon Dompkeca1600c2022-03-03 14:42:52 +010028#include <variant>
Ed Tanous7045c8d2017-04-03 10:04:37 -070029
Ed Tanous1abe55e2018-09-05 08:30:59 -070030namespace crow
31{
Ed Tanous47488a92023-06-26 18:19:33 -070032namespace utility
Ed Tanous1abe55e2018-09-05 08:30:59 -070033{
Ed Tanous7045c8d2017-04-03 10:04:37 -070034
Ed Tanous9de65b32024-03-27 13:34:40 -070035constexpr uint64_t getParameterTag(std::string_view url)
Ed Tanous1abe55e2018-09-05 08:30:59 -070036{
Ed Tanous1c30e502022-03-08 18:02:24 -080037 uint64_t tagValue = 0;
38 size_t urlSegmentIndex = std::string_view::npos;
Ed Tanousb00dcc22021-02-23 12:52:50 -080039
Ed Tanous1c30e502022-03-08 18:02:24 -080040 for (size_t urlIndex = 0; urlIndex < url.size(); urlIndex++)
41 {
42 char character = url[urlIndex];
43 if (character == '<')
44 {
45 if (urlSegmentIndex != std::string_view::npos)
46 {
47 return 0;
48 }
49 urlSegmentIndex = urlIndex;
50 }
51 if (character == '>')
52 {
53 if (urlSegmentIndex == std::string_view::npos)
54 {
55 return 0;
56 }
Patrick Williams89492a12023-05-10 07:51:34 -050057 std::string_view tag = url.substr(urlSegmentIndex,
58 urlIndex + 1 - urlSegmentIndex);
Ed Tanous1c30e502022-03-08 18:02:24 -080059
Ed Tanous1c30e502022-03-08 18:02:24 -080060 if (tag == "<str>" || tag == "<string>")
61 {
Ed Tanousd9e89df2024-03-27 14:08:59 -070062 tagValue++;
Ed Tanous1c30e502022-03-08 18:02:24 -080063 }
64 if (tag == "<path>")
65 {
Ed Tanousd9e89df2024-03-27 14:08:59 -070066 tagValue++;
Ed Tanous1c30e502022-03-08 18:02:24 -080067 }
Ed Tanous1c30e502022-03-08 18:02:24 -080068 urlSegmentIndex = std::string_view::npos;
69 }
70 }
71 if (urlSegmentIndex != std::string_view::npos)
Ed Tanous988403c2020-08-24 11:29:49 -070072 {
73 return 0;
74 }
Ed Tanous1c30e502022-03-08 18:02:24 -080075 return tagValue;
Ed Tanous7045c8d2017-04-03 10:04:37 -070076}
Ed Tanous7045c8d2017-04-03 10:04:37 -070077
Ed Tanousee192c02023-12-13 10:49:58 -080078class Base64Encoder
Adriana Kobylakd830ff52021-01-27 14:15:27 -060079{
Ed Tanousee192c02023-12-13 10:49:58 -080080 char overflow1 = '\0';
81 char overflow2 = '\0';
82 uint8_t overflowCount = 0;
83
84 constexpr static std::array<char, 64> key = {
Adriana Kobylakd830ff52021-01-27 14:15:27 -060085 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
86 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
87 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
88 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
89 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
90
Ed Tanousee192c02023-12-13 10:49:58 -080091 // Takes 3 ascii chars, and encodes them as 4 base64 chars
92 static void encodeTriple(char first, char second, char third,
93 std::string& output)
Adriana Kobylakd830ff52021-01-27 14:15:27 -060094 {
Ed Tanous543f4402022-01-06 13:12:53 -080095 size_t keyIndex = 0;
Adriana Kobylakd830ff52021-01-27 14:15:27 -060096
Ed Tanousee192c02023-12-13 10:49:58 -080097 keyIndex = static_cast<size_t>(first & 0xFC) >> 2;
98 output += key[keyIndex];
Adriana Kobylakd830ff52021-01-27 14:15:27 -060099
Ed Tanousee192c02023-12-13 10:49:58 -0800100 keyIndex = static_cast<size_t>(first & 0x03) << 4;
101 keyIndex += static_cast<size_t>(second & 0xF0) >> 4;
102 output += key[keyIndex];
103
104 keyIndex = static_cast<size_t>(second & 0x0F) << 2;
105 keyIndex += static_cast<size_t>(third & 0xC0) >> 6;
106 output += key[keyIndex];
107
108 keyIndex = static_cast<size_t>(third & 0x3F);
109 output += key[keyIndex];
110 }
111
112 public:
113 // Accepts a partial string to encode, and writes the encoded characters to
114 // the output stream. requires subsequently calling finalize to complete
115 // stream.
116 void encode(std::string_view data, std::string& output)
117 {
118 // Encode the last round of overflow chars first
119 if (overflowCount == 2)
Adriana Kobylakd830ff52021-01-27 14:15:27 -0600120 {
Ed Tanousee192c02023-12-13 10:49:58 -0800121 if (!data.empty())
Adriana Kobylakd830ff52021-01-27 14:15:27 -0600122 {
Ed Tanousee192c02023-12-13 10:49:58 -0800123 encodeTriple(overflow1, overflow2, data[0], output);
124 overflowCount = 0;
125 data.remove_prefix(1);
Adriana Kobylakd830ff52021-01-27 14:15:27 -0600126 }
Ed Tanousee192c02023-12-13 10:49:58 -0800127 }
128 else if (overflowCount == 1)
129 {
130 if (data.size() >= 2)
Adriana Kobylakd830ff52021-01-27 14:15:27 -0600131 {
Ed Tanousee192c02023-12-13 10:49:58 -0800132 encodeTriple(overflow1, data[0], data[1], output);
133 overflowCount = 0;
134 data.remove_prefix(2);
Adriana Kobylakd830ff52021-01-27 14:15:27 -0600135 }
136 }
Ed Tanousee192c02023-12-13 10:49:58 -0800137
138 while (data.size() >= 3)
139 {
140 encodeTriple(data[0], data[1], data[2], output);
141 data.remove_prefix(3);
142 }
143
144 if (!data.empty() && overflowCount == 0)
145 {
146 overflow1 = data[0];
147 overflowCount++;
148 data.remove_prefix(1);
149 }
150
151 if (!data.empty() && overflowCount == 1)
152 {
153 overflow2 = data[0];
154 overflowCount++;
155 data.remove_prefix(1);
156 }
157 }
158
159 // Completes a base64 output, by writing any MOD(3) characters to the
160 // output, as well as any required trailing =
161 void finalize(std::string& output)
162 {
163 if (overflowCount == 0)
164 {
165 return;
166 }
167 size_t keyIndex = static_cast<size_t>(overflow1 & 0xFC) >> 2;
168 output += key[keyIndex];
169
170 keyIndex = static_cast<size_t>(overflow1 & 0x03) << 4;
171 if (overflowCount == 2)
172 {
173 keyIndex += static_cast<size_t>(overflow2 & 0xF0) >> 4;
174 output += key[keyIndex];
175 keyIndex = static_cast<size_t>(overflow2 & 0x0F) << 2;
176 output += key[keyIndex];
177 }
Adriana Kobylakd830ff52021-01-27 14:15:27 -0600178 else
179 {
Ed Tanousee192c02023-12-13 10:49:58 -0800180 output += key[keyIndex];
181 output += '=';
Adriana Kobylakd830ff52021-01-27 14:15:27 -0600182 }
Ed Tanousee192c02023-12-13 10:49:58 -0800183 output += '=';
184 overflowCount = 0;
Adriana Kobylakd830ff52021-01-27 14:15:27 -0600185 }
186
Ed Tanousee192c02023-12-13 10:49:58 -0800187 // Returns the required output buffer in characters for an input of size
188 // inputSize
189 static size_t constexpr encodedSize(size_t inputSize)
190 {
191 // Base64 encodes 3 character blocks as 4 character blocks
192 // With a possibility of 2 trailing = characters
193 return (inputSize + 2) / 3 * 4;
194 }
195};
196
197inline std::string base64encode(std::string_view data)
198{
199 // Encodes a 3 character stream into a 4 character stream
200 std::string out;
201 Base64Encoder base64;
202 out.reserve(Base64Encoder::encodedSize(data.size()));
203 base64.encode(data, out);
204 base64.finalize(out);
205 return out;
Adriana Kobylakd830ff52021-01-27 14:15:27 -0600206}
207
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100208// TODO this is temporary and should be deleted once base64 is refactored out of
209// crow
Ed Tanous26ccae32023-02-16 10:28:44 -0800210inline bool base64Decode(std::string_view input, std::string& output)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700211{
Ed Tanous271584a2019-07-09 16:24:22 -0700212 static const char nop = static_cast<char>(-1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700213 // See note on encoding_data[] in above function
Jonathan Doman5beaf842020-08-14 11:23:33 -0700214 static const std::array<char, 256> decodingData = {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700215 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
216 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
217 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
218 nop, 62, nop, nop, nop, 63, 52, 53, 54, 55, 56, 57, 58, 59,
219 60, 61, nop, nop, nop, nop, nop, nop, nop, 0, 1, 2, 3, 4,
220 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
221 19, 20, 21, 22, 23, 24, 25, nop, nop, nop, nop, nop, nop, 26,
222 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
223 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, nop, nop, nop,
224 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
225 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
226 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
227 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
228 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
229 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
230 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
231 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
232 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
233 nop, nop, nop, nop};
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100234
Ed Tanous1abe55e2018-09-05 08:30:59 -0700235 size_t inputLength = input.size();
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100236
Ed Tanous1abe55e2018-09-05 08:30:59 -0700237 // allocate space for output string
238 output.clear();
239 output.reserve(((inputLength + 2) / 3) * 4);
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100240
Jonathan Doman5beaf842020-08-14 11:23:33 -0700241 auto getCodeValue = [](char c) {
242 auto code = static_cast<unsigned char>(c);
243 // Ensure we cannot index outside the bounds of the decoding array
244 static_assert(std::numeric_limits<decltype(code)>::max() <
245 decodingData.size());
246 return decodingData[code];
247 };
248
Ed Tanous1abe55e2018-09-05 08:30:59 -0700249 // for each 4-bytes sequence from the input, extract 4 6-bits sequences by
Gunnar Millscaa3ce32020-07-08 14:46:53 -0500250 // dropping first two bits
Ed Tanous1abe55e2018-09-05 08:30:59 -0700251 // and regenerate into 3 8-bits sequences
James Feist5a806642020-07-31 16:40:33 +0000252
Ed Tanous1abe55e2018-09-05 08:30:59 -0700253 for (size_t i = 0; i < inputLength; i++)
254 {
Ed Tanous543f4402022-01-06 13:12:53 -0800255 char base64code0 = 0;
256 char base64code1 = 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700257 char base64code2 = 0; // initialized to 0 to suppress warnings
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100258
Jonathan Doman5beaf842020-08-14 11:23:33 -0700259 base64code0 = getCodeValue(input[i]);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700260 if (base64code0 == nop)
261 { // non base64 character
262 return false;
263 }
264 if (!(++i < inputLength))
265 { // we need at least two input bytes for first
266 // byte output
267 return false;
268 }
Jonathan Doman5beaf842020-08-14 11:23:33 -0700269 base64code1 = getCodeValue(input[i]);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700270 if (base64code1 == nop)
271 { // non base64 character
272 return false;
273 }
274 output +=
275 static_cast<char>((base64code0 << 2) | ((base64code1 >> 4) & 0x3));
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100276
Ed Tanous1abe55e2018-09-05 08:30:59 -0700277 if (++i < inputLength)
278 {
279 char c = input[i];
280 if (c == '=')
281 { // padding , end of input
282 return (base64code1 & 0x0f) == 0;
283 }
Jonathan Doman5beaf842020-08-14 11:23:33 -0700284 base64code2 = getCodeValue(input[i]);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700285 if (base64code2 == nop)
286 { // non base64 character
287 return false;
288 }
289 output += static_cast<char>(((base64code1 << 4) & 0xf0) |
290 ((base64code2 >> 2) & 0x0f));
291 }
292
293 if (++i < inputLength)
294 {
295 char c = input[i];
296 if (c == '=')
297 { // padding , end of input
298 return (base64code2 & 0x03) == 0;
299 }
Ed Tanousf8fe53e2022-06-30 15:55:45 -0700300 char base64code3 = getCodeValue(input[i]);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700301 if (base64code3 == nop)
302 { // non base64 character
303 return false;
304 }
305 output +=
306 static_cast<char>((((base64code2 << 6) & 0xc0) | base64code3));
307 }
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100308 }
309
Ed Tanous1abe55e2018-09-05 08:30:59 -0700310 return true;
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100311}
312
Ed Tanous26ccae32023-02-16 10:28:44 -0800313inline bool constantTimeStringCompare(std::string_view a, std::string_view b)
Ed Tanous51dae672018-09-05 16:07:32 -0700314{
315 // Important note, this function is ONLY constant time if the two input
316 // sizes are the same
317 if (a.size() != b.size())
318 {
319 return false;
320 }
321 return CRYPTO_memcmp(a.data(), b.data(), a.size()) == 0;
322}
323
324struct ConstantTimeCompare
325{
Ed Tanous26ccae32023-02-16 10:28:44 -0800326 bool operator()(std::string_view a, std::string_view b) const
Ed Tanous51dae672018-09-05 16:07:32 -0700327 {
328 return constantTimeStringCompare(a, b);
329 }
330};
331
Ed Tanouseae855c2021-10-26 11:26:02 -0700332namespace details
333{
334inline boost::urls::url
Willy Tuc6bcedc2022-09-27 05:36:59 +0000335 appendUrlPieces(boost::urls::url& url,
336 const std::initializer_list<std::string_view> args)
Ed Tanouseae855c2021-10-26 11:26:02 -0700337{
Ed Tanous26ccae32023-02-16 10:28:44 -0800338 for (std::string_view arg : args)
Ed Tanouseae855c2021-10-26 11:26:02 -0700339 {
340 url.segments().push_back(arg);
341 }
342 return url;
343}
Willy Tuc6bcedc2022-09-27 05:36:59 +0000344
Ed Tanouseae855c2021-10-26 11:26:02 -0700345} // namespace details
346
Ed Tanous7f8d8fa2022-08-19 07:00:38 -0700347class OrMorePaths
348{};
349
Ed Tanouseae855c2021-10-26 11:26:02 -0700350template <typename... AV>
Willy Tuc6bcedc2022-09-27 05:36:59 +0000351inline void appendUrlPieces(boost::urls::url& url, const AV... args)
352{
353 details::appendUrlPieces(url, {args...});
354}
355
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100356namespace details
357{
358
359// std::reference_wrapper<std::string> - extracts segment to variable
360// std::string_view - checks if segment is equal to variable
Ed Tanous7f8d8fa2022-08-19 07:00:38 -0700361using UrlSegment = std::variant<std::reference_wrapper<std::string>,
362 std::string_view, OrMorePaths>;
363
364enum class UrlParseResult
365{
366 Continue,
367 Fail,
368 Done,
369};
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100370
371class UrlSegmentMatcherVisitor
372{
373 public:
Ed Tanous7f8d8fa2022-08-19 07:00:38 -0700374 UrlParseResult operator()(std::string& output)
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100375 {
Ed Tanous079360a2022-06-29 10:05:19 -0700376 output = segment;
Ed Tanous7f8d8fa2022-08-19 07:00:38 -0700377 return UrlParseResult::Continue;
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100378 }
379
Ed Tanous7f8d8fa2022-08-19 07:00:38 -0700380 UrlParseResult operator()(std::string_view expected)
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100381 {
Ed Tanous079360a2022-06-29 10:05:19 -0700382 if (segment == expected)
Ed Tanous7f8d8fa2022-08-19 07:00:38 -0700383 {
384 return UrlParseResult::Continue;
385 }
386 return UrlParseResult::Fail;
387 }
388
389 UrlParseResult operator()(OrMorePaths /*unused*/)
390 {
391 return UrlParseResult::Done;
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100392 }
393
Ed Tanous079360a2022-06-29 10:05:19 -0700394 explicit UrlSegmentMatcherVisitor(std::string_view segmentIn) :
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100395 segment(segmentIn)
396 {}
397
398 private:
Ed Tanous079360a2022-06-29 10:05:19 -0700399 std::string_view segment;
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100400};
401
Ed Tanous4a7fbef2024-04-06 16:03:49 -0700402inline bool readUrlSegments(const boost::urls::url_view_base& url,
Ed Tanous5be2b142024-03-27 15:27:04 -0700403 std::initializer_list<UrlSegment> segments)
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100404{
Ed Tanous4a7fbef2024-04-06 16:03:49 -0700405 const boost::urls::segments_view& urlSegments = url.segments();
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100406
Ed Tanous7f8d8fa2022-08-19 07:00:38 -0700407 if (!urlSegments.is_absolute())
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100408 {
409 return false;
410 }
411
Ed Tanous4a7fbef2024-04-06 16:03:49 -0700412 boost::urls::segments_view::const_iterator it = urlSegments.begin();
413 boost::urls::segments_view::const_iterator end = urlSegments.end();
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100414
415 for (const auto& segment : segments)
416 {
Ed Tanous7f8d8fa2022-08-19 07:00:38 -0700417 if (it == end)
418 {
419 // If the request ends with an "any" path, this was successful
420 return std::holds_alternative<OrMorePaths>(segment);
421 }
422 UrlParseResult res = std::visit(UrlSegmentMatcherVisitor(*it), segment);
423 if (res == UrlParseResult::Done)
424 {
425 return true;
426 }
427 if (res == UrlParseResult::Fail)
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100428 {
429 return false;
430 }
431 it++;
432 }
Carson Labrado4c30e222022-06-24 22:16:00 +0000433
434 // There will be an empty segment at the end if the URI ends with a "/"
435 // e.g. /redfish/v1/Chassis/
436 if ((it != end) && urlSegments.back().empty())
437 {
438 it++;
439 }
Ed Tanous7f8d8fa2022-08-19 07:00:38 -0700440 return it == end;
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100441}
442
443} // namespace details
444
445template <typename... Args>
Ed Tanous4a7fbef2024-04-06 16:03:49 -0700446inline bool readUrlSegments(const boost::urls::url_view_base& url,
447 Args&&... args)
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100448{
Ed Tanous39662a32023-02-06 15:09:46 -0800449 return details::readUrlSegments(url, {std::forward<Args>(args)...});
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100450}
451
Ed Tanous4a7fbef2024-04-06 16:03:49 -0700452inline boost::urls::url
453 replaceUrlSegment(const boost::urls::url_view_base& urlView,
454 const uint replaceLoc, std::string_view newSegment)
Carson Labrado1c0bb5c2022-05-18 00:12:52 +0000455{
Ed Tanous4a7fbef2024-04-06 16:03:49 -0700456 const boost::urls::segments_view& urlSegments = urlView.segments();
Carson Labrado1c0bb5c2022-05-18 00:12:52 +0000457 boost::urls::url url("/");
458
459 if (!urlSegments.is_absolute())
460 {
461 return url;
462 }
463
464 boost::urls::segments_view::iterator it = urlSegments.begin();
465 boost::urls::segments_view::iterator end = urlSegments.end();
466
467 for (uint idx = 0; it != end; it++, idx++)
468 {
469 if (idx == replaceLoc)
470 {
471 url.segments().push_back(newSegment);
472 }
473 else
474 {
475 url.segments().push_back(*it);
476 }
477 }
478
479 return url;
480}
481
Ed Tanousa716aa72023-08-01 11:35:53 -0700482inline void setProtocolDefaults(boost::urls::url& url,
483 std::string_view protocol)
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800484{
Ed Tanousa716aa72023-08-01 11:35:53 -0700485 if (url.has_scheme())
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800486 {
Ed Tanousa716aa72023-08-01 11:35:53 -0700487 return;
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800488 }
Ed Tanousa716aa72023-08-01 11:35:53 -0700489 if (protocol == "Redfish" || protocol.empty())
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800490 {
Ed Tanousa716aa72023-08-01 11:35:53 -0700491 if (url.port_number() == 443)
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800492 {
Ed Tanousa716aa72023-08-01 11:35:53 -0700493 url.set_scheme("https");
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800494 }
Ed Tanousa716aa72023-08-01 11:35:53 -0700495 if (url.port_number() == 80)
496 {
497 if (bmcwebInsecureEnableHttpPushStyleEventing)
498 {
499 url.set_scheme("http");
500 }
501 }
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800502 }
Ed Tanousa716aa72023-08-01 11:35:53 -0700503 else if (protocol == "SNMPv2c")
Chicago Duan3d307082020-11-26 14:12:12 +0800504 {
Ed Tanousa716aa72023-08-01 11:35:53 -0700505 url.set_scheme("snmp");
Chicago Duan3d307082020-11-26 14:12:12 +0800506 }
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800507}
508
Ed Tanousa716aa72023-08-01 11:35:53 -0700509inline void setPortDefaults(boost::urls::url& url)
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800510{
511 uint16_t port = url.port_number();
512 if (port != 0)
513 {
Ed Tanousa716aa72023-08-01 11:35:53 -0700514 return;
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800515 }
516
517 // If the user hasn't explicitly stated a port, pick one explicitly for them
518 // based on the protocol defaults
519 if (url.scheme() == "http")
520 {
Ed Tanousa716aa72023-08-01 11:35:53 -0700521 url.set_port_number(80);
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800522 }
523 if (url.scheme() == "https")
524 {
Ed Tanousa716aa72023-08-01 11:35:53 -0700525 url.set_port_number(443);
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800526 }
Chicago Duan3d307082020-11-26 14:12:12 +0800527 if (url.scheme() == "snmp")
528 {
Ed Tanousa716aa72023-08-01 11:35:53 -0700529 url.set_port_number(162);
Chicago Duan3d307082020-11-26 14:12:12 +0800530 }
Ed Tanous11baefe2022-02-09 12:14:12 -0800531}
532
Ed Tanous1abe55e2018-09-05 08:30:59 -0700533} // namespace utility
534} // namespace crow
Ed Tanous71f2db72022-05-25 12:28:09 -0700535
536namespace nlohmann
537{
Ed Tanous4a7fbef2024-04-06 16:03:49 -0700538template <std::derived_from<boost::urls::url_view_base> URL>
539struct adl_serializer<URL>
Ed Tanous71f2db72022-05-25 12:28:09 -0700540{
541 // NOLINTNEXTLINE(readability-identifier-naming)
Ed Tanous4a7fbef2024-04-06 16:03:49 -0700542 static void to_json(json& j, const URL& url)
Ed Tanous71f2db72022-05-25 12:28:09 -0700543 {
Ed Tanous079360a2022-06-29 10:05:19 -0700544 j = url.buffer();
Ed Tanous71f2db72022-05-25 12:28:09 -0700545 }
546};
547} // namespace nlohmann