blob: edc34adb093bc6bc695676791c2d6d6d0b5bb36a [file] [log] [blame]
Ed Tanous40e9b922024-09-10 13:50:16 -07001// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright OpenBMC Authors
Ed Tanous7045c8d2017-04-03 10:04:37 -07003#pragma once
Ed Tanous1abe55e2018-09-05 08:30:59 -07004
Ed Tanous3ccb3ad2023-01-13 17:40:03 -08005#include "bmcweb_config.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 Williamsbd79bce2024-08-16 15:22:20 -040057 std::string_view tag =
58 url.substr(urlSegmentIndex, 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
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400244 static_assert(
245 std::numeric_limits<decltype(code)>::max() < decodingData.size());
Jonathan Doman5beaf842020-08-14 11:23:33 -0700246 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)
Myung Bae41868c62024-10-09 16:36:49 -0700261 {
262 // non base64 character
Ed Tanous1abe55e2018-09-05 08:30:59 -0700263 return false;
264 }
265 if (!(++i < inputLength))
Myung Bae41868c62024-10-09 16:36:49 -0700266 {
267 // we need at least two input bytes for first byte output
Ed Tanous1abe55e2018-09-05 08:30:59 -0700268 return false;
269 }
Jonathan Doman5beaf842020-08-14 11:23:33 -0700270 base64code1 = getCodeValue(input[i]);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700271 if (base64code1 == nop)
Myung Bae41868c62024-10-09 16:36:49 -0700272 {
273 // non base64 character
Ed Tanous1abe55e2018-09-05 08:30:59 -0700274 return false;
275 }
276 output +=
277 static_cast<char>((base64code0 << 2) | ((base64code1 >> 4) & 0x3));
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100278
Ed Tanous1abe55e2018-09-05 08:30:59 -0700279 if (++i < inputLength)
280 {
281 char c = input[i];
282 if (c == '=')
Myung Bae41868c62024-10-09 16:36:49 -0700283 {
284 // padding , end of input
Ed Tanous1abe55e2018-09-05 08:30:59 -0700285 return (base64code1 & 0x0f) == 0;
286 }
Jonathan Doman5beaf842020-08-14 11:23:33 -0700287 base64code2 = getCodeValue(input[i]);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700288 if (base64code2 == nop)
Myung Bae41868c62024-10-09 16:36:49 -0700289 {
290 // non base64 character
Ed Tanous1abe55e2018-09-05 08:30:59 -0700291 return false;
292 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400293 output += static_cast<char>(
294 ((base64code1 << 4) & 0xf0) | ((base64code2 >> 2) & 0x0f));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700295 }
296
297 if (++i < inputLength)
298 {
299 char c = input[i];
300 if (c == '=')
Myung Bae41868c62024-10-09 16:36:49 -0700301 {
302 // padding , end of input
Ed Tanous1abe55e2018-09-05 08:30:59 -0700303 return (base64code2 & 0x03) == 0;
304 }
Ed Tanousf8fe53e2022-06-30 15:55:45 -0700305 char base64code3 = getCodeValue(input[i]);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700306 if (base64code3 == nop)
Myung Bae41868c62024-10-09 16:36:49 -0700307 {
308 // non base64 character
Ed Tanous1abe55e2018-09-05 08:30:59 -0700309 return false;
310 }
311 output +=
312 static_cast<char>((((base64code2 << 6) & 0xc0) | base64code3));
313 }
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100314 }
315
Ed Tanous1abe55e2018-09-05 08:30:59 -0700316 return true;
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100317}
318
Ed Tanous7f8d8fa2022-08-19 07:00:38 -0700319class OrMorePaths
320{};
321
Ed Tanouseae855c2021-10-26 11:26:02 -0700322template <typename... AV>
Ed Tanousdaadfb22024-12-20 09:25:54 -0800323inline void appendUrlPieces(boost::urls::url& url, AV&&... args)
Willy Tuc6bcedc2022-09-27 05:36:59 +0000324{
Ed Tanousdaadfb22024-12-20 09:25:54 -0800325 // Unclear the correct fix here.
326 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
327 for (const std::string_view arg : {args...})
328 {
329 url.segments().push_back(arg);
330 }
Willy Tuc6bcedc2022-09-27 05:36:59 +0000331}
332
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100333namespace details
334{
335
336// std::reference_wrapper<std::string> - extracts segment to variable
337// std::string_view - checks if segment is equal to variable
Ed Tanous7f8d8fa2022-08-19 07:00:38 -0700338using UrlSegment = std::variant<std::reference_wrapper<std::string>,
339 std::string_view, OrMorePaths>;
340
341enum class UrlParseResult
342{
343 Continue,
344 Fail,
345 Done,
346};
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100347
348class UrlSegmentMatcherVisitor
349{
350 public:
Ed Tanous7f8d8fa2022-08-19 07:00:38 -0700351 UrlParseResult operator()(std::string& output)
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100352 {
Ed Tanous079360a2022-06-29 10:05:19 -0700353 output = segment;
Ed Tanous7f8d8fa2022-08-19 07:00:38 -0700354 return UrlParseResult::Continue;
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100355 }
356
Ed Tanous7f8d8fa2022-08-19 07:00:38 -0700357 UrlParseResult operator()(std::string_view expected)
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100358 {
Ed Tanous079360a2022-06-29 10:05:19 -0700359 if (segment == expected)
Ed Tanous7f8d8fa2022-08-19 07:00:38 -0700360 {
361 return UrlParseResult::Continue;
362 }
363 return UrlParseResult::Fail;
364 }
365
366 UrlParseResult operator()(OrMorePaths /*unused*/)
367 {
368 return UrlParseResult::Done;
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100369 }
370
Ed Tanous079360a2022-06-29 10:05:19 -0700371 explicit UrlSegmentMatcherVisitor(std::string_view segmentIn) :
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100372 segment(segmentIn)
373 {}
374
375 private:
Ed Tanous079360a2022-06-29 10:05:19 -0700376 std::string_view segment;
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100377};
378
Ed Tanous4a7fbef2024-04-06 16:03:49 -0700379inline bool readUrlSegments(const boost::urls::url_view_base& url,
Ed Tanous5be2b142024-03-27 15:27:04 -0700380 std::initializer_list<UrlSegment> segments)
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100381{
Ed Tanous4a7fbef2024-04-06 16:03:49 -0700382 const boost::urls::segments_view& urlSegments = url.segments();
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100383
Ed Tanous7f8d8fa2022-08-19 07:00:38 -0700384 if (!urlSegments.is_absolute())
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100385 {
386 return false;
387 }
388
Ed Tanous4a7fbef2024-04-06 16:03:49 -0700389 boost::urls::segments_view::const_iterator it = urlSegments.begin();
390 boost::urls::segments_view::const_iterator end = urlSegments.end();
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100391
392 for (const auto& segment : segments)
393 {
Ed Tanous7f8d8fa2022-08-19 07:00:38 -0700394 if (it == end)
395 {
396 // If the request ends with an "any" path, this was successful
397 return std::holds_alternative<OrMorePaths>(segment);
398 }
399 UrlParseResult res = std::visit(UrlSegmentMatcherVisitor(*it), segment);
400 if (res == UrlParseResult::Done)
401 {
402 return true;
403 }
404 if (res == UrlParseResult::Fail)
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100405 {
406 return false;
407 }
408 it++;
409 }
Carson Labrado4c30e222022-06-24 22:16:00 +0000410
411 // There will be an empty segment at the end if the URI ends with a "/"
412 // e.g. /redfish/v1/Chassis/
413 if ((it != end) && urlSegments.back().empty())
414 {
415 it++;
416 }
Ed Tanous7f8d8fa2022-08-19 07:00:38 -0700417 return it == end;
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100418}
419
420} // namespace details
421
422template <typename... Args>
Ed Tanous4a7fbef2024-04-06 16:03:49 -0700423inline bool readUrlSegments(const boost::urls::url_view_base& url,
424 Args&&... args)
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100425{
Ed Tanous39662a32023-02-06 15:09:46 -0800426 return details::readUrlSegments(url, {std::forward<Args>(args)...});
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100427}
428
Ed Tanous4a7fbef2024-04-06 16:03:49 -0700429inline boost::urls::url
430 replaceUrlSegment(const boost::urls::url_view_base& urlView,
431 const uint replaceLoc, std::string_view newSegment)
Carson Labrado1c0bb5c2022-05-18 00:12:52 +0000432{
Ed Tanous4a7fbef2024-04-06 16:03:49 -0700433 const boost::urls::segments_view& urlSegments = urlView.segments();
Carson Labrado1c0bb5c2022-05-18 00:12:52 +0000434 boost::urls::url url("/");
435
436 if (!urlSegments.is_absolute())
437 {
438 return url;
439 }
440
441 boost::urls::segments_view::iterator it = urlSegments.begin();
442 boost::urls::segments_view::iterator end = urlSegments.end();
443
444 for (uint idx = 0; it != end; it++, idx++)
445 {
446 if (idx == replaceLoc)
447 {
448 url.segments().push_back(newSegment);
449 }
450 else
451 {
452 url.segments().push_back(*it);
453 }
454 }
455
456 return url;
457}
458
Ed Tanousa716aa72023-08-01 11:35:53 -0700459inline void setProtocolDefaults(boost::urls::url& url,
460 std::string_view protocol)
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800461{
Ed Tanousa716aa72023-08-01 11:35:53 -0700462 if (url.has_scheme())
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800463 {
Ed Tanousa716aa72023-08-01 11:35:53 -0700464 return;
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800465 }
Ed Tanousa716aa72023-08-01 11:35:53 -0700466 if (protocol == "Redfish" || protocol.empty())
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800467 {
Ed Tanousa716aa72023-08-01 11:35:53 -0700468 if (url.port_number() == 443)
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800469 {
Ed Tanousa716aa72023-08-01 11:35:53 -0700470 url.set_scheme("https");
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800471 }
Ed Tanousa716aa72023-08-01 11:35:53 -0700472 if (url.port_number() == 80)
473 {
Ed Tanous25b54db2024-04-17 15:40:31 -0700474 if constexpr (BMCWEB_INSECURE_PUSH_STYLE_NOTIFICATION)
Ed Tanousa716aa72023-08-01 11:35:53 -0700475 {
476 url.set_scheme("http");
477 }
478 }
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800479 }
Ed Tanousa716aa72023-08-01 11:35:53 -0700480 else if (protocol == "SNMPv2c")
Chicago Duan3d307082020-11-26 14:12:12 +0800481 {
Ed Tanousa716aa72023-08-01 11:35:53 -0700482 url.set_scheme("snmp");
Chicago Duan3d307082020-11-26 14:12:12 +0800483 }
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800484}
485
Ed Tanousa716aa72023-08-01 11:35:53 -0700486inline void setPortDefaults(boost::urls::url& url)
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800487{
488 uint16_t port = url.port_number();
489 if (port != 0)
490 {
Ed Tanousa716aa72023-08-01 11:35:53 -0700491 return;
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800492 }
493
494 // If the user hasn't explicitly stated a port, pick one explicitly for them
495 // based on the protocol defaults
496 if (url.scheme() == "http")
497 {
Ed Tanousa716aa72023-08-01 11:35:53 -0700498 url.set_port_number(80);
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800499 }
500 if (url.scheme() == "https")
501 {
Ed Tanousa716aa72023-08-01 11:35:53 -0700502 url.set_port_number(443);
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800503 }
Chicago Duan3d307082020-11-26 14:12:12 +0800504 if (url.scheme() == "snmp")
505 {
Ed Tanousa716aa72023-08-01 11:35:53 -0700506 url.set_port_number(162);
Chicago Duan3d307082020-11-26 14:12:12 +0800507 }
Ed Tanous11baefe2022-02-09 12:14:12 -0800508}
509
Ed Tanous1abe55e2018-09-05 08:30:59 -0700510} // namespace utility
511} // namespace crow
Ed Tanous71f2db72022-05-25 12:28:09 -0700512
513namespace nlohmann
514{
Ed Tanous4a7fbef2024-04-06 16:03:49 -0700515template <std::derived_from<boost::urls::url_view_base> URL>
516struct adl_serializer<URL>
Ed Tanous71f2db72022-05-25 12:28:09 -0700517{
518 // NOLINTNEXTLINE(readability-identifier-naming)
Ed Tanous4a7fbef2024-04-06 16:03:49 -0700519 static void to_json(json& j, const URL& url)
Ed Tanous71f2db72022-05-25 12:28:09 -0700520 {
Ed Tanous079360a2022-06-29 10:05:19 -0700521 j = url.buffer();
Ed Tanous71f2db72022-05-25 12:28:09 -0700522 }
523};
524} // namespace nlohmann