blob: bf65b258811d3f826b3941ac0cc4d317b8b449f1 [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 Tanouse5dd4992025-02-17 12:33:40 -08007#include "str_utility.hpp"
8
Ed Tanousd7857202025-01-28 15:32:26 -08009#include <sys/types.h>
10
11#include <boost/url/segments_view.hpp>
Ed Tanouseae855c2021-10-26 11:26:02 -070012#include <boost/url/url.hpp>
Ed Tanous4a7fbef2024-04-06 16:03:49 -070013#include <boost/url/url_view_base.hpp>
Myung Bae8873f322025-03-17 18:24:13 -050014#include <nlohmann/adl_serializer.hpp>
Ed Tanous71f2db72022-05-25 12:28:09 -070015#include <nlohmann/json.hpp>
Nan Zhou1d8782e2021-11-29 22:23:18 -080016
Ed Tanous9ea15c32022-01-04 14:18:22 -080017#include <array>
Ed Tanous80d2ef32025-02-04 09:29:02 -080018#include <bit>
Ed Tanousd7857202025-01-28 15:32:26 -080019#include <concepts>
Ed Tanousc715ec22022-03-10 15:38:01 -080020#include <cstddef>
Ed Tanous7045c8d2017-04-03 10:04:37 -070021#include <cstdint>
Ed Tanous9ea15c32022-01-04 14:18:22 -080022#include <ctime>
Ed Tanous7045c8d2017-04-03 10:04:37 -070023#include <functional>
Ed Tanousd7857202025-01-28 15:32:26 -080024#include <initializer_list>
Ed Tanous9ea15c32022-01-04 14:18:22 -080025#include <limits>
Ed Tanous7045c8d2017-04-03 10:04:37 -070026#include <string>
Ed Tanous9ea15c32022-01-04 14:18:22 -080027#include <string_view>
Ed Tanous9ea15c32022-01-04 14:18:22 -080028#include <type_traits>
29#include <utility>
Szymon Dompkeca1600c2022-03-03 14:42:52 +010030#include <variant>
Ed Tanous7045c8d2017-04-03 10:04:37 -070031
Ed Tanous1abe55e2018-09-05 08:30:59 -070032namespace crow
33{
Ed Tanous47488a92023-06-26 18:19:33 -070034namespace utility
Ed Tanous1abe55e2018-09-05 08:30:59 -070035{
Ed Tanous7045c8d2017-04-03 10:04:37 -070036
Ed Tanous9de65b32024-03-27 13:34:40 -070037constexpr uint64_t getParameterTag(std::string_view url)
Ed Tanous1abe55e2018-09-05 08:30:59 -070038{
Ed Tanous1c30e502022-03-08 18:02:24 -080039 uint64_t tagValue = 0;
40 size_t urlSegmentIndex = std::string_view::npos;
Ed Tanousb00dcc22021-02-23 12:52:50 -080041
Ed Tanous1c30e502022-03-08 18:02:24 -080042 for (size_t urlIndex = 0; urlIndex < url.size(); urlIndex++)
43 {
44 char character = url[urlIndex];
45 if (character == '<')
46 {
47 if (urlSegmentIndex != std::string_view::npos)
48 {
49 return 0;
50 }
51 urlSegmentIndex = urlIndex;
52 }
53 if (character == '>')
54 {
55 if (urlSegmentIndex == std::string_view::npos)
56 {
57 return 0;
58 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -040059 std::string_view tag =
60 url.substr(urlSegmentIndex, urlIndex + 1 - urlSegmentIndex);
Ed Tanous1c30e502022-03-08 18:02:24 -080061
Ed Tanous1c30e502022-03-08 18:02:24 -080062 if (tag == "<str>" || tag == "<string>")
63 {
Ed Tanousd9e89df2024-03-27 14:08:59 -070064 tagValue++;
Ed Tanous1c30e502022-03-08 18:02:24 -080065 }
66 if (tag == "<path>")
67 {
Ed Tanousd9e89df2024-03-27 14:08:59 -070068 tagValue++;
Ed Tanous1c30e502022-03-08 18:02:24 -080069 }
Ed Tanous1c30e502022-03-08 18:02:24 -080070 urlSegmentIndex = std::string_view::npos;
71 }
72 }
73 if (urlSegmentIndex != std::string_view::npos)
Ed Tanous988403c2020-08-24 11:29:49 -070074 {
75 return 0;
76 }
Ed Tanous1c30e502022-03-08 18:02:24 -080077 return tagValue;
Ed Tanous7045c8d2017-04-03 10:04:37 -070078}
Ed Tanous7045c8d2017-04-03 10:04:37 -070079
Ed Tanous80d2ef32025-02-04 09:29:02 -080080constexpr static std::array<char, 64> base64key = {
81 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
82 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
83 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
84 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
85 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
86
87static constexpr char nop = static_cast<char>(-1);
88constexpr std::array<char, 256> getDecodeTable(bool urlSafe)
89{
90 std::array<char, 256> decodeTable{};
91 decodeTable.fill(nop);
92
93 for (size_t index = 0; index < base64key.size(); index++)
94 {
95 char character = base64key[index];
96 decodeTable[std::bit_cast<uint8_t>(character)] =
97 static_cast<char>(index);
98 }
99
100 if (urlSafe)
101 {
102 // Urlsafe decode tables replace the last two characters with - and _
103 decodeTable['+'] = nop;
104 decodeTable['/'] = nop;
105 decodeTable['-'] = 62;
106 decodeTable['_'] = 63;
107 }
108
109 return decodeTable;
110}
111
Ed Tanousee192c02023-12-13 10:49:58 -0800112class Base64Encoder
Adriana Kobylakd830ff52021-01-27 14:15:27 -0600113{
Ed Tanousee192c02023-12-13 10:49:58 -0800114 char overflow1 = '\0';
115 char overflow2 = '\0';
116 uint8_t overflowCount = 0;
117
Ed Tanousee192c02023-12-13 10:49:58 -0800118 // Takes 3 ascii chars, and encodes them as 4 base64 chars
119 static void encodeTriple(char first, char second, char third,
120 std::string& output)
Adriana Kobylakd830ff52021-01-27 14:15:27 -0600121 {
Ed Tanous543f4402022-01-06 13:12:53 -0800122 size_t keyIndex = 0;
Adriana Kobylakd830ff52021-01-27 14:15:27 -0600123
Ed Tanousee192c02023-12-13 10:49:58 -0800124 keyIndex = static_cast<size_t>(first & 0xFC) >> 2;
Ed Tanous80d2ef32025-02-04 09:29:02 -0800125 output += base64key[keyIndex];
Adriana Kobylakd830ff52021-01-27 14:15:27 -0600126
Ed Tanousee192c02023-12-13 10:49:58 -0800127 keyIndex = static_cast<size_t>(first & 0x03) << 4;
128 keyIndex += static_cast<size_t>(second & 0xF0) >> 4;
Ed Tanous80d2ef32025-02-04 09:29:02 -0800129 output += base64key[keyIndex];
Ed Tanousee192c02023-12-13 10:49:58 -0800130
131 keyIndex = static_cast<size_t>(second & 0x0F) << 2;
132 keyIndex += static_cast<size_t>(third & 0xC0) >> 6;
Ed Tanous80d2ef32025-02-04 09:29:02 -0800133 output += base64key[keyIndex];
Ed Tanousee192c02023-12-13 10:49:58 -0800134
135 keyIndex = static_cast<size_t>(third & 0x3F);
Ed Tanous80d2ef32025-02-04 09:29:02 -0800136 output += base64key[keyIndex];
Ed Tanousee192c02023-12-13 10:49:58 -0800137 }
138
139 public:
140 // Accepts a partial string to encode, and writes the encoded characters to
141 // the output stream. requires subsequently calling finalize to complete
142 // stream.
143 void encode(std::string_view data, std::string& output)
144 {
145 // Encode the last round of overflow chars first
146 if (overflowCount == 2)
Adriana Kobylakd830ff52021-01-27 14:15:27 -0600147 {
Ed Tanousee192c02023-12-13 10:49:58 -0800148 if (!data.empty())
Adriana Kobylakd830ff52021-01-27 14:15:27 -0600149 {
Ed Tanousee192c02023-12-13 10:49:58 -0800150 encodeTriple(overflow1, overflow2, data[0], output);
151 overflowCount = 0;
152 data.remove_prefix(1);
Adriana Kobylakd830ff52021-01-27 14:15:27 -0600153 }
Ed Tanousee192c02023-12-13 10:49:58 -0800154 }
155 else if (overflowCount == 1)
156 {
157 if (data.size() >= 2)
Adriana Kobylakd830ff52021-01-27 14:15:27 -0600158 {
Ed Tanousee192c02023-12-13 10:49:58 -0800159 encodeTriple(overflow1, data[0], data[1], output);
160 overflowCount = 0;
161 data.remove_prefix(2);
Adriana Kobylakd830ff52021-01-27 14:15:27 -0600162 }
163 }
Ed Tanousee192c02023-12-13 10:49:58 -0800164
165 while (data.size() >= 3)
166 {
167 encodeTriple(data[0], data[1], data[2], output);
168 data.remove_prefix(3);
169 }
170
171 if (!data.empty() && overflowCount == 0)
172 {
173 overflow1 = data[0];
174 overflowCount++;
175 data.remove_prefix(1);
176 }
177
178 if (!data.empty() && overflowCount == 1)
179 {
180 overflow2 = data[0];
181 overflowCount++;
182 data.remove_prefix(1);
183 }
184 }
185
186 // Completes a base64 output, by writing any MOD(3) characters to the
187 // output, as well as any required trailing =
188 void finalize(std::string& output)
189 {
190 if (overflowCount == 0)
191 {
192 return;
193 }
194 size_t keyIndex = static_cast<size_t>(overflow1 & 0xFC) >> 2;
Ed Tanous80d2ef32025-02-04 09:29:02 -0800195 output += base64key[keyIndex];
Ed Tanousee192c02023-12-13 10:49:58 -0800196
197 keyIndex = static_cast<size_t>(overflow1 & 0x03) << 4;
198 if (overflowCount == 2)
199 {
200 keyIndex += static_cast<size_t>(overflow2 & 0xF0) >> 4;
Ed Tanous80d2ef32025-02-04 09:29:02 -0800201 output += base64key[keyIndex];
Ed Tanousee192c02023-12-13 10:49:58 -0800202 keyIndex = static_cast<size_t>(overflow2 & 0x0F) << 2;
Ed Tanous80d2ef32025-02-04 09:29:02 -0800203 output += base64key[keyIndex];
Ed Tanousee192c02023-12-13 10:49:58 -0800204 }
Adriana Kobylakd830ff52021-01-27 14:15:27 -0600205 else
206 {
Ed Tanous80d2ef32025-02-04 09:29:02 -0800207 output += base64key[keyIndex];
Ed Tanousee192c02023-12-13 10:49:58 -0800208 output += '=';
Adriana Kobylakd830ff52021-01-27 14:15:27 -0600209 }
Ed Tanousee192c02023-12-13 10:49:58 -0800210 output += '=';
211 overflowCount = 0;
Adriana Kobylakd830ff52021-01-27 14:15:27 -0600212 }
213
Ed Tanousee192c02023-12-13 10:49:58 -0800214 // Returns the required output buffer in characters for an input of size
215 // inputSize
216 static size_t constexpr encodedSize(size_t inputSize)
217 {
218 // Base64 encodes 3 character blocks as 4 character blocks
219 // With a possibility of 2 trailing = characters
220 return (inputSize + 2) / 3 * 4;
221 }
222};
223
224inline std::string base64encode(std::string_view data)
225{
226 // Encodes a 3 character stream into a 4 character stream
227 std::string out;
228 Base64Encoder base64;
229 out.reserve(Base64Encoder::encodedSize(data.size()));
230 base64.encode(data, out);
231 base64.finalize(out);
232 return out;
Adriana Kobylakd830ff52021-01-27 14:15:27 -0600233}
234
Kamran Hasan2682a0e2025-09-17 19:50:38 -0700235inline std::string createBasicAuthHeader(std::string_view username,
236 std::string_view password)
237{
238 std::string credentials = "Basic ";
239 Base64Encoder enc;
240 enc.encode(username, credentials);
241 enc.encode(":", credentials);
242 enc.encode(password, credentials);
243 enc.finalize(credentials);
244 return credentials;
245}
246
Ed Tanous80d2ef32025-02-04 09:29:02 -0800247template <bool urlsafe = false>
Ed Tanous26ccae32023-02-16 10:28:44 -0800248inline bool base64Decode(std::string_view input, std::string& output)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700249{
Ed Tanous1abe55e2018-09-05 08:30:59 -0700250 size_t inputLength = input.size();
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100251
Ed Tanous1abe55e2018-09-05 08:30:59 -0700252 // allocate space for output string
253 output.clear();
254 output.reserve(((inputLength + 2) / 3) * 4);
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100255
Ed Tanous80d2ef32025-02-04 09:29:02 -0800256 static constexpr auto decodingData = getDecodeTable(urlsafe);
257
Jonathan Doman5beaf842020-08-14 11:23:33 -0700258 auto getCodeValue = [](char c) {
259 auto code = static_cast<unsigned char>(c);
260 // Ensure we cannot index outside the bounds of the decoding array
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400261 static_assert(
262 std::numeric_limits<decltype(code)>::max() < decodingData.size());
Jonathan Doman5beaf842020-08-14 11:23:33 -0700263 return decodingData[code];
264 };
265
Ed Tanous1abe55e2018-09-05 08:30:59 -0700266 // for each 4-bytes sequence from the input, extract 4 6-bits sequences by
Gunnar Millscaa3ce32020-07-08 14:46:53 -0500267 // dropping first two bits
Ed Tanous1abe55e2018-09-05 08:30:59 -0700268 // and regenerate into 3 8-bits sequences
James Feist5a806642020-07-31 16:40:33 +0000269
Ed Tanous1abe55e2018-09-05 08:30:59 -0700270 for (size_t i = 0; i < inputLength; i++)
271 {
Ed Tanous543f4402022-01-06 13:12:53 -0800272 char base64code0 = 0;
273 char base64code1 = 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700274 char base64code2 = 0; // initialized to 0 to suppress warnings
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100275
Jonathan Doman5beaf842020-08-14 11:23:33 -0700276 base64code0 = getCodeValue(input[i]);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700277 if (base64code0 == nop)
Myung Bae41868c62024-10-09 16:36:49 -0700278 {
279 // non base64 character
Ed Tanous1abe55e2018-09-05 08:30:59 -0700280 return false;
281 }
282 if (!(++i < inputLength))
Myung Bae41868c62024-10-09 16:36:49 -0700283 {
284 // we need at least two input bytes for first byte output
Ed Tanous1abe55e2018-09-05 08:30:59 -0700285 return false;
286 }
Jonathan Doman5beaf842020-08-14 11:23:33 -0700287 base64code1 = getCodeValue(input[i]);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700288 if (base64code1 == nop)
Myung Bae41868c62024-10-09 16:36:49 -0700289 {
290 // non base64 character
Ed Tanous1abe55e2018-09-05 08:30:59 -0700291 return false;
292 }
293 output +=
294 static_cast<char>((base64code0 << 2) | ((base64code1 >> 4) & 0x3));
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100295
Ed Tanous1abe55e2018-09-05 08:30:59 -0700296 if (++i < inputLength)
297 {
298 char c = input[i];
299 if (c == '=')
Myung Bae41868c62024-10-09 16:36:49 -0700300 {
301 // padding , end of input
Ed Tanous1abe55e2018-09-05 08:30:59 -0700302 return (base64code1 & 0x0f) == 0;
303 }
Jonathan Doman5beaf842020-08-14 11:23:33 -0700304 base64code2 = getCodeValue(input[i]);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700305 if (base64code2 == nop)
Myung Bae41868c62024-10-09 16:36:49 -0700306 {
307 // non base64 character
Ed Tanous1abe55e2018-09-05 08:30:59 -0700308 return false;
309 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400310 output += static_cast<char>(
311 ((base64code1 << 4) & 0xf0) | ((base64code2 >> 2) & 0x0f));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700312 }
313
314 if (++i < inputLength)
315 {
316 char c = input[i];
317 if (c == '=')
Myung Bae41868c62024-10-09 16:36:49 -0700318 {
319 // padding , end of input
Ed Tanous1abe55e2018-09-05 08:30:59 -0700320 return (base64code2 & 0x03) == 0;
321 }
Ed Tanousf8fe53e2022-06-30 15:55:45 -0700322 char base64code3 = getCodeValue(input[i]);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700323 if (base64code3 == nop)
Myung Bae41868c62024-10-09 16:36:49 -0700324 {
325 // non base64 character
Ed Tanous1abe55e2018-09-05 08:30:59 -0700326 return false;
327 }
328 output +=
329 static_cast<char>((((base64code2 << 6) & 0xc0) | base64code3));
330 }
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100331 }
332
Ed Tanous1abe55e2018-09-05 08:30:59 -0700333 return true;
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100334}
335
Ed Tanous7f8d8fa2022-08-19 07:00:38 -0700336class OrMorePaths
337{};
338
Ed Tanouseae855c2021-10-26 11:26:02 -0700339template <typename... AV>
Ed Tanousdaadfb22024-12-20 09:25:54 -0800340inline void appendUrlPieces(boost::urls::url& url, AV&&... args)
Willy Tuc6bcedc2022-09-27 05:36:59 +0000341{
Ed Tanousdaadfb22024-12-20 09:25:54 -0800342 // Unclear the correct fix here.
343 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
344 for (const std::string_view arg : {args...})
345 {
346 url.segments().push_back(arg);
347 }
Willy Tuc6bcedc2022-09-27 05:36:59 +0000348}
349
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100350namespace details
351{
352
353// std::reference_wrapper<std::string> - extracts segment to variable
354// std::string_view - checks if segment is equal to variable
Ed Tanous7f8d8fa2022-08-19 07:00:38 -0700355using UrlSegment = std::variant<std::reference_wrapper<std::string>,
356 std::string_view, OrMorePaths>;
357
358enum class UrlParseResult
359{
360 Continue,
361 Fail,
362 Done,
363};
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100364
365class UrlSegmentMatcherVisitor
366{
367 public:
Ed Tanous7f8d8fa2022-08-19 07:00:38 -0700368 UrlParseResult operator()(std::string& output)
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100369 {
Ed Tanous079360a2022-06-29 10:05:19 -0700370 output = segment;
Ed Tanous7f8d8fa2022-08-19 07:00:38 -0700371 return UrlParseResult::Continue;
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100372 }
373
Ed Tanous7f8d8fa2022-08-19 07:00:38 -0700374 UrlParseResult operator()(std::string_view expected)
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100375 {
Ed Tanous079360a2022-06-29 10:05:19 -0700376 if (segment == expected)
Ed Tanous7f8d8fa2022-08-19 07:00:38 -0700377 {
378 return UrlParseResult::Continue;
379 }
380 return UrlParseResult::Fail;
381 }
382
383 UrlParseResult operator()(OrMorePaths /*unused*/)
384 {
385 return UrlParseResult::Done;
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100386 }
387
Ed Tanous079360a2022-06-29 10:05:19 -0700388 explicit UrlSegmentMatcherVisitor(std::string_view segmentIn) :
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100389 segment(segmentIn)
390 {}
391
392 private:
Ed Tanous079360a2022-06-29 10:05:19 -0700393 std::string_view segment;
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100394};
395
Ed Tanous4a7fbef2024-04-06 16:03:49 -0700396inline bool readUrlSegments(const boost::urls::url_view_base& url,
Ed Tanous5be2b142024-03-27 15:27:04 -0700397 std::initializer_list<UrlSegment> segments)
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100398{
Ed Tanous4a7fbef2024-04-06 16:03:49 -0700399 const boost::urls::segments_view& urlSegments = url.segments();
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100400
Ed Tanous7f8d8fa2022-08-19 07:00:38 -0700401 if (!urlSegments.is_absolute())
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100402 {
403 return false;
404 }
405
Ed Tanous4a7fbef2024-04-06 16:03:49 -0700406 boost::urls::segments_view::const_iterator it = urlSegments.begin();
407 boost::urls::segments_view::const_iterator end = urlSegments.end();
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100408
Ed Tanouse5dd4992025-02-17 12:33:40 -0800409 std::string fragment = url.fragment();
410 std::vector<std::string> fragmentParts;
411 bmcweb::split(fragmentParts, fragment, '/');
412 auto fragIt = fragmentParts.begin();
413 auto fragEnd = fragmentParts.end();
414
415 // Url fragments start with a /, so we need to skip the first empty string
416 if (fragIt != fragEnd)
417 {
418 if (fragIt->empty())
419 {
420 fragIt++;
421 }
422 }
423
424 // There will be an empty segment at the end if the URI ends with a "/"
425 // e.g. /redfish/v1/Chassis/
426 if ((it != end) && urlSegments.back().empty())
427 {
428 end--;
429 }
430
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100431 for (const auto& segment : segments)
432 {
Ed Tanouse5dd4992025-02-17 12:33:40 -0800433 UrlParseResult res = UrlParseResult::Fail;
Ed Tanous7f8d8fa2022-08-19 07:00:38 -0700434 if (it == end)
435 {
Ed Tanouse5dd4992025-02-17 12:33:40 -0800436 if (fragIt == fragEnd)
437 {
438 return std::holds_alternative<OrMorePaths>(segment);
439 }
440 res = std::visit(UrlSegmentMatcherVisitor(*fragIt), segment);
441 fragIt++;
Ed Tanous7f8d8fa2022-08-19 07:00:38 -0700442 }
Ed Tanouse5dd4992025-02-17 12:33:40 -0800443 else
444 {
445 res = std::visit(UrlSegmentMatcherVisitor(*it), segment);
446 it++;
447 }
Ed Tanous7f8d8fa2022-08-19 07:00:38 -0700448 if (res == UrlParseResult::Done)
449 {
450 return true;
451 }
452 if (res == UrlParseResult::Fail)
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100453 {
454 return false;
455 }
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100456 }
Carson Labrado4c30e222022-06-24 22:16:00 +0000457
Ed Tanous7f8d8fa2022-08-19 07:00:38 -0700458 return it == end;
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100459}
460
461} // namespace details
462
463template <typename... Args>
Ed Tanous4a7fbef2024-04-06 16:03:49 -0700464inline bool readUrlSegments(const boost::urls::url_view_base& url,
465 Args&&... args)
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100466{
Ed Tanous39662a32023-02-06 15:09:46 -0800467 return details::readUrlSegments(url, {std::forward<Args>(args)...});
Szymon Dompkeca1600c2022-03-03 14:42:52 +0100468}
469
Patrick Williams504af5a2025-02-03 14:29:03 -0500470inline boost::urls::url replaceUrlSegment(
471 const boost::urls::url_view_base& urlView, const uint replaceLoc,
472 std::string_view newSegment)
Carson Labrado1c0bb5c2022-05-18 00:12:52 +0000473{
Ed Tanous4a7fbef2024-04-06 16:03:49 -0700474 const boost::urls::segments_view& urlSegments = urlView.segments();
Carson Labrado1c0bb5c2022-05-18 00:12:52 +0000475 boost::urls::url url("/");
476
477 if (!urlSegments.is_absolute())
478 {
479 return url;
480 }
481
482 boost::urls::segments_view::iterator it = urlSegments.begin();
483 boost::urls::segments_view::iterator end = urlSegments.end();
484
485 for (uint idx = 0; it != end; it++, idx++)
486 {
487 if (idx == replaceLoc)
488 {
489 url.segments().push_back(newSegment);
490 }
491 else
492 {
493 url.segments().push_back(*it);
494 }
495 }
496
497 return url;
498}
499
Ed Tanousa716aa72023-08-01 11:35:53 -0700500inline void setProtocolDefaults(boost::urls::url& url,
501 std::string_view protocol)
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800502{
Ed Tanousa716aa72023-08-01 11:35:53 -0700503 if (url.has_scheme())
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800504 {
Ed Tanousa716aa72023-08-01 11:35:53 -0700505 return;
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800506 }
Ed Tanousa716aa72023-08-01 11:35:53 -0700507 if (protocol == "Redfish" || protocol.empty())
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800508 {
Ed Tanousa716aa72023-08-01 11:35:53 -0700509 if (url.port_number() == 443)
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800510 {
Ed Tanousa716aa72023-08-01 11:35:53 -0700511 url.set_scheme("https");
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800512 }
Ed Tanousa716aa72023-08-01 11:35:53 -0700513 if (url.port_number() == 80)
514 {
Ed Tanous25b54db2024-04-17 15:40:31 -0700515 if constexpr (BMCWEB_INSECURE_PUSH_STYLE_NOTIFICATION)
Ed Tanousa716aa72023-08-01 11:35:53 -0700516 {
517 url.set_scheme("http");
518 }
519 }
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800520 }
Ed Tanousa716aa72023-08-01 11:35:53 -0700521 else if (protocol == "SNMPv2c")
Chicago Duan3d307082020-11-26 14:12:12 +0800522 {
Ed Tanousa716aa72023-08-01 11:35:53 -0700523 url.set_scheme("snmp");
Chicago Duan3d307082020-11-26 14:12:12 +0800524 }
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800525}
526
Ed Tanousa716aa72023-08-01 11:35:53 -0700527inline void setPortDefaults(boost::urls::url& url)
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800528{
529 uint16_t port = url.port_number();
530 if (port != 0)
531 {
Ed Tanousa716aa72023-08-01 11:35:53 -0700532 return;
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800533 }
534
535 // If the user hasn't explicitly stated a port, pick one explicitly for them
536 // based on the protocol defaults
537 if (url.scheme() == "http")
538 {
Ed Tanousa716aa72023-08-01 11:35:53 -0700539 url.set_port_number(80);
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800540 }
541 if (url.scheme() == "https")
542 {
Ed Tanousa716aa72023-08-01 11:35:53 -0700543 url.set_port_number(443);
Ed Tanouseb1c47d2022-02-09 11:47:27 -0800544 }
Chicago Duan3d307082020-11-26 14:12:12 +0800545 if (url.scheme() == "snmp")
546 {
Ed Tanousa716aa72023-08-01 11:35:53 -0700547 url.set_port_number(162);
Chicago Duan3d307082020-11-26 14:12:12 +0800548 }
Ed Tanous11baefe2022-02-09 12:14:12 -0800549}
550
Ed Tanous1abe55e2018-09-05 08:30:59 -0700551} // namespace utility
552} // namespace crow
Ed Tanous71f2db72022-05-25 12:28:09 -0700553
554namespace nlohmann
555{
Ed Tanous4a7fbef2024-04-06 16:03:49 -0700556template <std::derived_from<boost::urls::url_view_base> URL>
557struct adl_serializer<URL>
Ed Tanous71f2db72022-05-25 12:28:09 -0700558{
559 // NOLINTNEXTLINE(readability-identifier-naming)
Ed Tanous4a7fbef2024-04-06 16:03:49 -0700560 static void to_json(json& j, const URL& url)
Ed Tanous71f2db72022-05-25 12:28:09 -0700561 {
Ed Tanous079360a2022-06-29 10:05:19 -0700562 j = url.buffer();
Ed Tanous71f2db72022-05-25 12:28:09 -0700563 }
564};
565} // namespace nlohmann