xref: /openbmc/bmcweb/http/utility.hpp (revision 40e9b92ec19acffb46f83a6e55b18974da5d708e)
1*40e9b92eSEd Tanous // SPDX-License-Identifier: Apache-2.0
2*40e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright OpenBMC Authors
304e438cbSEd Tanous #pragma once
404e438cbSEd Tanous 
53ccb3adbSEd Tanous #include "bmcweb_config.h"
63ccb3adbSEd Tanous 
7c867a83eSEd Tanous #include <boost/callable_traits.hpp>
8079360aeSEd Tanous #include <boost/url/parse.hpp>
9eae855c7SEd Tanous #include <boost/url/url.hpp>
10079360aeSEd Tanous #include <boost/url/url_view.hpp>
114a7fbefdSEd Tanous #include <boost/url/url_view_base.hpp>
1271f2db75SEd Tanous #include <nlohmann/json.hpp>
131d8782e7SNan Zhou 
149ea15c35SEd Tanous #include <array>
1574849befSEd Tanous #include <chrono>
16c715ec29SEd Tanous #include <cstddef>
1704e438cbSEd Tanous #include <cstdint>
189ea15c35SEd Tanous #include <ctime>
1904e438cbSEd Tanous #include <functional>
209896eaedSEd Tanous #include <iomanip>
219ea15c35SEd Tanous #include <limits>
2204e438cbSEd Tanous #include <stdexcept>
2304e438cbSEd Tanous #include <string>
249ea15c35SEd Tanous #include <string_view>
2504e438cbSEd Tanous #include <tuple>
269ea15c35SEd Tanous #include <type_traits>
279ea15c35SEd Tanous #include <utility>
28ca1600c1SSzymon Dompke #include <variant>
2904e438cbSEd Tanous 
3004e438cbSEd Tanous namespace crow
3104e438cbSEd Tanous {
3247488a98SEd Tanous namespace utility
3304e438cbSEd Tanous {
3404e438cbSEd Tanous 
getParameterTag(std::string_view url)359de65b34SEd Tanous constexpr uint64_t getParameterTag(std::string_view url)
3604e438cbSEd Tanous {
371c30e500SEd Tanous     uint64_t tagValue = 0;
381c30e500SEd Tanous     size_t urlSegmentIndex = std::string_view::npos;
39b00dcc27SEd Tanous 
401c30e500SEd Tanous     for (size_t urlIndex = 0; urlIndex < url.size(); urlIndex++)
411c30e500SEd Tanous     {
421c30e500SEd Tanous         char character = url[urlIndex];
431c30e500SEd Tanous         if (character == '<')
441c30e500SEd Tanous         {
451c30e500SEd Tanous             if (urlSegmentIndex != std::string_view::npos)
4604e438cbSEd Tanous             {
4704e438cbSEd Tanous                 return 0;
4804e438cbSEd Tanous             }
491c30e500SEd Tanous             urlSegmentIndex = urlIndex;
501c30e500SEd Tanous         }
511c30e500SEd Tanous         if (character == '>')
5204e438cbSEd Tanous         {
531c30e500SEd Tanous             if (urlSegmentIndex == std::string_view::npos)
541c30e500SEd Tanous             {
551c30e500SEd Tanous                 return 0;
561c30e500SEd Tanous             }
57bd79bce8SPatrick Williams             std::string_view tag =
58bd79bce8SPatrick Williams                 url.substr(urlSegmentIndex, urlIndex + 1 - urlSegmentIndex);
591c30e500SEd Tanous 
601c30e500SEd Tanous             if (tag == "<str>" || tag == "<string>")
6104e438cbSEd Tanous             {
62d9e89dfdSEd Tanous                 tagValue++;
6304e438cbSEd Tanous             }
641c30e500SEd Tanous             if (tag == "<path>")
6504e438cbSEd Tanous             {
66d9e89dfdSEd Tanous                 tagValue++;
6704e438cbSEd Tanous             }
681c30e500SEd Tanous             urlSegmentIndex = std::string_view::npos;
691c30e500SEd Tanous         }
701c30e500SEd Tanous     }
711c30e500SEd Tanous     if (urlSegmentIndex != std::string_view::npos)
721c30e500SEd Tanous     {
731c30e500SEd Tanous         return 0;
741c30e500SEd Tanous     }
751c30e500SEd Tanous     return tagValue;
7604e438cbSEd Tanous }
7704e438cbSEd Tanous 
78ee192c06SEd Tanous class Base64Encoder
79d830ff5aSAdriana Kobylak {
80ee192c06SEd Tanous     char overflow1 = '\0';
81ee192c06SEd Tanous     char overflow2 = '\0';
82ee192c06SEd Tanous     uint8_t overflowCount = 0;
83ee192c06SEd Tanous 
84ee192c06SEd Tanous     constexpr static std::array<char, 64> key = {
85d830ff5aSAdriana Kobylak         'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
86d830ff5aSAdriana Kobylak         'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
87d830ff5aSAdriana Kobylak         'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
88d830ff5aSAdriana Kobylak         'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
89d830ff5aSAdriana Kobylak         '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
90d830ff5aSAdriana Kobylak 
91ee192c06SEd Tanous     // Takes 3 ascii chars, and encodes them as 4 base64 chars
encodeTriple(char first,char second,char third,std::string & output)92ee192c06SEd Tanous     static void encodeTriple(char first, char second, char third,
93ee192c06SEd Tanous                              std::string& output)
94d830ff5aSAdriana Kobylak     {
95543f4400SEd Tanous         size_t keyIndex = 0;
96d830ff5aSAdriana Kobylak 
97ee192c06SEd Tanous         keyIndex = static_cast<size_t>(first & 0xFC) >> 2;
98ee192c06SEd Tanous         output += key[keyIndex];
99d830ff5aSAdriana Kobylak 
100ee192c06SEd Tanous         keyIndex = static_cast<size_t>(first & 0x03) << 4;
101ee192c06SEd Tanous         keyIndex += static_cast<size_t>(second & 0xF0) >> 4;
102ee192c06SEd Tanous         output += key[keyIndex];
103ee192c06SEd Tanous 
104ee192c06SEd Tanous         keyIndex = static_cast<size_t>(second & 0x0F) << 2;
105ee192c06SEd Tanous         keyIndex += static_cast<size_t>(third & 0xC0) >> 6;
106ee192c06SEd Tanous         output += key[keyIndex];
107ee192c06SEd Tanous 
108ee192c06SEd Tanous         keyIndex = static_cast<size_t>(third & 0x3F);
109ee192c06SEd Tanous         output += key[keyIndex];
110ee192c06SEd Tanous     }
111ee192c06SEd Tanous 
112ee192c06SEd Tanous   public:
113ee192c06SEd Tanous     // Accepts a partial string to encode, and writes the encoded characters to
114ee192c06SEd Tanous     // the output stream. requires subsequently calling finalize to complete
115ee192c06SEd Tanous     // stream.
encode(std::string_view data,std::string & output)116ee192c06SEd Tanous     void encode(std::string_view data, std::string& output)
117d830ff5aSAdriana Kobylak     {
118ee192c06SEd Tanous         // Encode the last round of overflow chars first
119ee192c06SEd Tanous         if (overflowCount == 2)
120d830ff5aSAdriana Kobylak         {
121ee192c06SEd Tanous             if (!data.empty())
122ee192c06SEd Tanous             {
123ee192c06SEd Tanous                 encodeTriple(overflow1, overflow2, data[0], output);
124ee192c06SEd Tanous                 overflowCount = 0;
125ee192c06SEd Tanous                 data.remove_prefix(1);
126ee192c06SEd Tanous             }
127ee192c06SEd Tanous         }
128ee192c06SEd Tanous         else if (overflowCount == 1)
129ee192c06SEd Tanous         {
130ee192c06SEd Tanous             if (data.size() >= 2)
131ee192c06SEd Tanous             {
132ee192c06SEd Tanous                 encodeTriple(overflow1, data[0], data[1], output);
133ee192c06SEd Tanous                 overflowCount = 0;
134ee192c06SEd Tanous                 data.remove_prefix(2);
135ee192c06SEd Tanous             }
136ee192c06SEd Tanous         }
137d830ff5aSAdriana Kobylak 
138ee192c06SEd Tanous         while (data.size() >= 3)
139ee192c06SEd Tanous         {
140ee192c06SEd Tanous             encodeTriple(data[0], data[1], data[2], output);
141ee192c06SEd Tanous             data.remove_prefix(3);
142ee192c06SEd Tanous         }
143ee192c06SEd Tanous 
144ee192c06SEd Tanous         if (!data.empty() && overflowCount == 0)
145ee192c06SEd Tanous         {
146ee192c06SEd Tanous             overflow1 = data[0];
147ee192c06SEd Tanous             overflowCount++;
148ee192c06SEd Tanous             data.remove_prefix(1);
149ee192c06SEd Tanous         }
150ee192c06SEd Tanous 
151ee192c06SEd Tanous         if (!data.empty() && overflowCount == 1)
152ee192c06SEd Tanous         {
153ee192c06SEd Tanous             overflow2 = data[0];
154ee192c06SEd Tanous             overflowCount++;
155ee192c06SEd Tanous             data.remove_prefix(1);
156ee192c06SEd Tanous         }
157ee192c06SEd Tanous     }
158ee192c06SEd Tanous 
159ee192c06SEd Tanous     // Completes a base64 output, by writing any MOD(3) characters to the
160ee192c06SEd Tanous     // output, as well as any required trailing =
finalize(std::string & output)161ee192c06SEd Tanous     void finalize(std::string& output)
162ee192c06SEd Tanous     {
163ee192c06SEd Tanous         if (overflowCount == 0)
164ee192c06SEd Tanous         {
165ee192c06SEd Tanous             return;
166ee192c06SEd Tanous         }
167ee192c06SEd Tanous         size_t keyIndex = static_cast<size_t>(overflow1 & 0xFC) >> 2;
168ee192c06SEd Tanous         output += key[keyIndex];
169ee192c06SEd Tanous 
170ee192c06SEd Tanous         keyIndex = static_cast<size_t>(overflow1 & 0x03) << 4;
171ee192c06SEd Tanous         if (overflowCount == 2)
172ee192c06SEd Tanous         {
173ee192c06SEd Tanous             keyIndex += static_cast<size_t>(overflow2 & 0xF0) >> 4;
174ee192c06SEd Tanous             output += key[keyIndex];
175ee192c06SEd Tanous             keyIndex = static_cast<size_t>(overflow2 & 0x0F) << 2;
176ee192c06SEd Tanous             output += key[keyIndex];
177d830ff5aSAdriana Kobylak         }
178d830ff5aSAdriana Kobylak         else
179d830ff5aSAdriana Kobylak         {
180ee192c06SEd Tanous             output += key[keyIndex];
181ee192c06SEd Tanous             output += '=';
182d830ff5aSAdriana Kobylak         }
183ee192c06SEd Tanous         output += '=';
184ee192c06SEd Tanous         overflowCount = 0;
185d830ff5aSAdriana Kobylak     }
186ee192c06SEd Tanous 
187ee192c06SEd Tanous     // Returns the required output buffer in characters for an input of size
188ee192c06SEd Tanous     // inputSize
encodedSize(size_t inputSize)189ee192c06SEd Tanous     static size_t constexpr encodedSize(size_t inputSize)
190d830ff5aSAdriana Kobylak     {
191ee192c06SEd Tanous         // Base64 encodes 3 character blocks as 4 character blocks
192ee192c06SEd Tanous         // With a possibility of 2 trailing = characters
193ee192c06SEd Tanous         return (inputSize + 2) / 3 * 4;
194d830ff5aSAdriana Kobylak     }
195ee192c06SEd Tanous };
196d830ff5aSAdriana Kobylak 
base64encode(std::string_view data)197ee192c06SEd Tanous inline std::string base64encode(std::string_view data)
198ee192c06SEd Tanous {
199ee192c06SEd Tanous     // Encodes a 3 character stream into a 4 character stream
200ee192c06SEd Tanous     std::string out;
201ee192c06SEd Tanous     Base64Encoder base64;
202ee192c06SEd Tanous     out.reserve(Base64Encoder::encodedSize(data.size()));
203ee192c06SEd Tanous     base64.encode(data, out);
204ee192c06SEd Tanous     base64.finalize(out);
205ee192c06SEd Tanous     return out;
206d830ff5aSAdriana Kobylak }
207d830ff5aSAdriana Kobylak 
20804e438cbSEd Tanous // TODO this is temporary and should be deleted once base64 is refactored out of
20904e438cbSEd Tanous // crow
base64Decode(std::string_view input,std::string & output)21026ccae32SEd Tanous inline bool base64Decode(std::string_view input, std::string& output)
21104e438cbSEd Tanous {
21204e438cbSEd Tanous     static const char nop = static_cast<char>(-1);
21304e438cbSEd Tanous     // See note on encoding_data[] in above function
21404e438cbSEd Tanous     static const std::array<char, 256> decodingData = {
21504e438cbSEd Tanous         nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
21604e438cbSEd Tanous         nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
21704e438cbSEd Tanous         nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
21804e438cbSEd Tanous         nop, 62,  nop, nop, nop, 63,  52,  53,  54,  55,  56,  57,  58,  59,
21904e438cbSEd Tanous         60,  61,  nop, nop, nop, nop, nop, nop, nop, 0,   1,   2,   3,   4,
22004e438cbSEd Tanous         5,   6,   7,   8,   9,   10,  11,  12,  13,  14,  15,  16,  17,  18,
22104e438cbSEd Tanous         19,  20,  21,  22,  23,  24,  25,  nop, nop, nop, nop, nop, nop, 26,
22204e438cbSEd Tanous         27,  28,  29,  30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40,
22304e438cbSEd Tanous         41,  42,  43,  44,  45,  46,  47,  48,  49,  50,  51,  nop, nop, nop,
22404e438cbSEd Tanous         nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
22504e438cbSEd Tanous         nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
22604e438cbSEd Tanous         nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
22704e438cbSEd Tanous         nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
22804e438cbSEd Tanous         nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
22904e438cbSEd Tanous         nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
23004e438cbSEd Tanous         nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
23104e438cbSEd Tanous         nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
23204e438cbSEd Tanous         nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
23304e438cbSEd Tanous         nop, nop, nop, nop};
23404e438cbSEd Tanous 
23504e438cbSEd Tanous     size_t inputLength = input.size();
23604e438cbSEd Tanous 
23704e438cbSEd Tanous     // allocate space for output string
23804e438cbSEd Tanous     output.clear();
23904e438cbSEd Tanous     output.reserve(((inputLength + 2) / 3) * 4);
24004e438cbSEd Tanous 
24104e438cbSEd Tanous     auto getCodeValue = [](char c) {
24204e438cbSEd Tanous         auto code = static_cast<unsigned char>(c);
24304e438cbSEd Tanous         // Ensure we cannot index outside the bounds of the decoding array
244bd79bce8SPatrick Williams         static_assert(
245bd79bce8SPatrick Williams             std::numeric_limits<decltype(code)>::max() < decodingData.size());
24604e438cbSEd Tanous         return decodingData[code];
24704e438cbSEd Tanous     };
24804e438cbSEd Tanous 
24904e438cbSEd Tanous     // for each 4-bytes sequence from the input, extract 4 6-bits sequences by
25004e438cbSEd Tanous     // dropping first two bits
25104e438cbSEd Tanous     // and regenerate into 3 8-bits sequences
25204e438cbSEd Tanous 
25304e438cbSEd Tanous     for (size_t i = 0; i < inputLength; i++)
25404e438cbSEd Tanous     {
255543f4400SEd Tanous         char base64code0 = 0;
256543f4400SEd Tanous         char base64code1 = 0;
25704e438cbSEd Tanous         char base64code2 = 0; // initialized to 0 to suppress warnings
25804e438cbSEd Tanous 
25904e438cbSEd Tanous         base64code0 = getCodeValue(input[i]);
26004e438cbSEd Tanous         if (base64code0 == nop)
26141868c66SMyung Bae         {
26241868c66SMyung Bae             // non base64 character
26304e438cbSEd Tanous             return false;
26404e438cbSEd Tanous         }
26504e438cbSEd Tanous         if (!(++i < inputLength))
26641868c66SMyung Bae         {
26741868c66SMyung Bae             // we need at least two input bytes for first byte output
26804e438cbSEd Tanous             return false;
26904e438cbSEd Tanous         }
27004e438cbSEd Tanous         base64code1 = getCodeValue(input[i]);
27104e438cbSEd Tanous         if (base64code1 == nop)
27241868c66SMyung Bae         {
27341868c66SMyung Bae             // non base64 character
27404e438cbSEd Tanous             return false;
27504e438cbSEd Tanous         }
27604e438cbSEd Tanous         output +=
27704e438cbSEd Tanous             static_cast<char>((base64code0 << 2) | ((base64code1 >> 4) & 0x3));
27804e438cbSEd Tanous 
27904e438cbSEd Tanous         if (++i < inputLength)
28004e438cbSEd Tanous         {
28104e438cbSEd Tanous             char c = input[i];
28204e438cbSEd Tanous             if (c == '=')
28341868c66SMyung Bae             {
28441868c66SMyung Bae                 // padding , end of input
28504e438cbSEd Tanous                 return (base64code1 & 0x0f) == 0;
28604e438cbSEd Tanous             }
28704e438cbSEd Tanous             base64code2 = getCodeValue(input[i]);
28804e438cbSEd Tanous             if (base64code2 == nop)
28941868c66SMyung Bae             {
29041868c66SMyung Bae                 // non base64 character
29104e438cbSEd Tanous                 return false;
29204e438cbSEd Tanous             }
293bd79bce8SPatrick Williams             output += static_cast<char>(
294bd79bce8SPatrick Williams                 ((base64code1 << 4) & 0xf0) | ((base64code2 >> 2) & 0x0f));
29504e438cbSEd Tanous         }
29604e438cbSEd Tanous 
29704e438cbSEd Tanous         if (++i < inputLength)
29804e438cbSEd Tanous         {
29904e438cbSEd Tanous             char c = input[i];
30004e438cbSEd Tanous             if (c == '=')
30141868c66SMyung Bae             {
30241868c66SMyung Bae                 // padding , end of input
30304e438cbSEd Tanous                 return (base64code2 & 0x03) == 0;
30404e438cbSEd Tanous             }
305f8fe53e7SEd Tanous             char base64code3 = getCodeValue(input[i]);
30604e438cbSEd Tanous             if (base64code3 == nop)
30741868c66SMyung Bae             {
30841868c66SMyung Bae                 // non base64 character
30904e438cbSEd Tanous                 return false;
31004e438cbSEd Tanous             }
31104e438cbSEd Tanous             output +=
31204e438cbSEd Tanous                 static_cast<char>((((base64code2 << 6) & 0xc0) | base64code3));
31304e438cbSEd Tanous         }
31404e438cbSEd Tanous     }
31504e438cbSEd Tanous 
31604e438cbSEd Tanous     return true;
31704e438cbSEd Tanous }
31804e438cbSEd Tanous 
3197f8d8fa9SEd Tanous class OrMorePaths
3207f8d8fa9SEd Tanous {};
3217f8d8fa9SEd Tanous 
322eae855c7SEd Tanous template <typename... AV>
appendUrlPieces(boost::urls::url & url,AV &&...args)323daadfb2eSEd Tanous inline void appendUrlPieces(boost::urls::url& url, AV&&... args)
324c6bcedc6SWilly Tu {
325daadfb2eSEd Tanous     // Unclear the correct fix here.
326daadfb2eSEd Tanous     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
327daadfb2eSEd Tanous     for (const std::string_view arg : {args...})
328daadfb2eSEd Tanous     {
329daadfb2eSEd Tanous         url.segments().push_back(arg);
330daadfb2eSEd Tanous     }
331c6bcedc6SWilly Tu }
332c6bcedc6SWilly Tu 
333ca1600c1SSzymon Dompke namespace details
334ca1600c1SSzymon Dompke {
335ca1600c1SSzymon Dompke 
336ca1600c1SSzymon Dompke // std::reference_wrapper<std::string> - extracts segment to variable
337ca1600c1SSzymon Dompke //                    std::string_view - checks if segment is equal to variable
3387f8d8fa9SEd Tanous using UrlSegment = std::variant<std::reference_wrapper<std::string>,
3397f8d8fa9SEd Tanous                                 std::string_view, OrMorePaths>;
3407f8d8fa9SEd Tanous 
3417f8d8fa9SEd Tanous enum class UrlParseResult
3427f8d8fa9SEd Tanous {
3437f8d8fa9SEd Tanous     Continue,
3447f8d8fa9SEd Tanous     Fail,
3457f8d8fa9SEd Tanous     Done,
3467f8d8fa9SEd Tanous };
347ca1600c1SSzymon Dompke 
348ca1600c1SSzymon Dompke class UrlSegmentMatcherVisitor
349ca1600c1SSzymon Dompke {
350ca1600c1SSzymon Dompke   public:
operator ()(std::string & output)3517f8d8fa9SEd Tanous     UrlParseResult operator()(std::string& output)
352ca1600c1SSzymon Dompke     {
353079360aeSEd Tanous         output = segment;
3547f8d8fa9SEd Tanous         return UrlParseResult::Continue;
355ca1600c1SSzymon Dompke     }
356ca1600c1SSzymon Dompke 
operator ()(std::string_view expected)3577f8d8fa9SEd Tanous     UrlParseResult operator()(std::string_view expected)
358ca1600c1SSzymon Dompke     {
359079360aeSEd Tanous         if (segment == expected)
3607f8d8fa9SEd Tanous         {
3617f8d8fa9SEd Tanous             return UrlParseResult::Continue;
3627f8d8fa9SEd Tanous         }
3637f8d8fa9SEd Tanous         return UrlParseResult::Fail;
3647f8d8fa9SEd Tanous     }
3657f8d8fa9SEd Tanous 
operator ()(OrMorePaths)3667f8d8fa9SEd Tanous     UrlParseResult operator()(OrMorePaths /*unused*/)
3677f8d8fa9SEd Tanous     {
3687f8d8fa9SEd Tanous         return UrlParseResult::Done;
369ca1600c1SSzymon Dompke     }
370ca1600c1SSzymon Dompke 
UrlSegmentMatcherVisitor(std::string_view segmentIn)371079360aeSEd Tanous     explicit UrlSegmentMatcherVisitor(std::string_view segmentIn) :
372ca1600c1SSzymon Dompke         segment(segmentIn)
373ca1600c1SSzymon Dompke     {}
374ca1600c1SSzymon Dompke 
375ca1600c1SSzymon Dompke   private:
376079360aeSEd Tanous     std::string_view segment;
377ca1600c1SSzymon Dompke };
378ca1600c1SSzymon Dompke 
readUrlSegments(const boost::urls::url_view_base & url,std::initializer_list<UrlSegment> segments)3794a7fbefdSEd Tanous inline bool readUrlSegments(const boost::urls::url_view_base& url,
3805be2b14aSEd Tanous                             std::initializer_list<UrlSegment> segments)
381ca1600c1SSzymon Dompke {
3824a7fbefdSEd Tanous     const boost::urls::segments_view& urlSegments = url.segments();
383ca1600c1SSzymon Dompke 
3847f8d8fa9SEd Tanous     if (!urlSegments.is_absolute())
385ca1600c1SSzymon Dompke     {
386ca1600c1SSzymon Dompke         return false;
387ca1600c1SSzymon Dompke     }
388ca1600c1SSzymon Dompke 
3894a7fbefdSEd Tanous     boost::urls::segments_view::const_iterator it = urlSegments.begin();
3904a7fbefdSEd Tanous     boost::urls::segments_view::const_iterator end = urlSegments.end();
391ca1600c1SSzymon Dompke 
392ca1600c1SSzymon Dompke     for (const auto& segment : segments)
393ca1600c1SSzymon Dompke     {
3947f8d8fa9SEd Tanous         if (it == end)
3957f8d8fa9SEd Tanous         {
3967f8d8fa9SEd Tanous             // If the request ends with an "any" path, this was successful
3977f8d8fa9SEd Tanous             return std::holds_alternative<OrMorePaths>(segment);
3987f8d8fa9SEd Tanous         }
3997f8d8fa9SEd Tanous         UrlParseResult res = std::visit(UrlSegmentMatcherVisitor(*it), segment);
4007f8d8fa9SEd Tanous         if (res == UrlParseResult::Done)
4017f8d8fa9SEd Tanous         {
4027f8d8fa9SEd Tanous             return true;
4037f8d8fa9SEd Tanous         }
4047f8d8fa9SEd Tanous         if (res == UrlParseResult::Fail)
405ca1600c1SSzymon Dompke         {
406ca1600c1SSzymon Dompke             return false;
407ca1600c1SSzymon Dompke         }
408ca1600c1SSzymon Dompke         it++;
409ca1600c1SSzymon Dompke     }
4104c30e226SCarson Labrado 
4114c30e226SCarson Labrado     // There will be an empty segment at the end if the URI ends with a "/"
4124c30e226SCarson Labrado     // e.g. /redfish/v1/Chassis/
4134c30e226SCarson Labrado     if ((it != end) && urlSegments.back().empty())
4144c30e226SCarson Labrado     {
4154c30e226SCarson Labrado         it++;
4164c30e226SCarson Labrado     }
4177f8d8fa9SEd Tanous     return it == end;
418ca1600c1SSzymon Dompke }
419ca1600c1SSzymon Dompke 
420ca1600c1SSzymon Dompke } // namespace details
421ca1600c1SSzymon Dompke 
422ca1600c1SSzymon Dompke template <typename... Args>
readUrlSegments(const boost::urls::url_view_base & url,Args &&...args)4234a7fbefdSEd Tanous inline bool readUrlSegments(const boost::urls::url_view_base& url,
4244a7fbefdSEd Tanous                             Args&&... args)
425ca1600c1SSzymon Dompke {
42639662a3bSEd Tanous     return details::readUrlSegments(url, {std::forward<Args>(args)...});
427ca1600c1SSzymon Dompke }
428ca1600c1SSzymon Dompke 
4294a7fbefdSEd Tanous inline boost::urls::url
replaceUrlSegment(const boost::urls::url_view_base & urlView,const uint replaceLoc,std::string_view newSegment)4304a7fbefdSEd Tanous     replaceUrlSegment(const boost::urls::url_view_base& urlView,
4314a7fbefdSEd Tanous                       const uint replaceLoc, std::string_view newSegment)
4321c0bb5c6SCarson Labrado {
4334a7fbefdSEd Tanous     const boost::urls::segments_view& urlSegments = urlView.segments();
4341c0bb5c6SCarson Labrado     boost::urls::url url("/");
4351c0bb5c6SCarson Labrado 
4361c0bb5c6SCarson Labrado     if (!urlSegments.is_absolute())
4371c0bb5c6SCarson Labrado     {
4381c0bb5c6SCarson Labrado         return url;
4391c0bb5c6SCarson Labrado     }
4401c0bb5c6SCarson Labrado 
4411c0bb5c6SCarson Labrado     boost::urls::segments_view::iterator it = urlSegments.begin();
4421c0bb5c6SCarson Labrado     boost::urls::segments_view::iterator end = urlSegments.end();
4431c0bb5c6SCarson Labrado 
4441c0bb5c6SCarson Labrado     for (uint idx = 0; it != end; it++, idx++)
4451c0bb5c6SCarson Labrado     {
4461c0bb5c6SCarson Labrado         if (idx == replaceLoc)
4471c0bb5c6SCarson Labrado         {
4481c0bb5c6SCarson Labrado             url.segments().push_back(newSegment);
4491c0bb5c6SCarson Labrado         }
4501c0bb5c6SCarson Labrado         else
4511c0bb5c6SCarson Labrado         {
4521c0bb5c6SCarson Labrado             url.segments().push_back(*it);
4531c0bb5c6SCarson Labrado         }
4541c0bb5c6SCarson Labrado     }
4551c0bb5c6SCarson Labrado 
4561c0bb5c6SCarson Labrado     return url;
4571c0bb5c6SCarson Labrado }
4581c0bb5c6SCarson Labrado 
setProtocolDefaults(boost::urls::url & url,std::string_view protocol)459a716aa74SEd Tanous inline void setProtocolDefaults(boost::urls::url& url,
460a716aa74SEd Tanous                                 std::string_view protocol)
461eb1c47d3SEd Tanous {
462a716aa74SEd Tanous     if (url.has_scheme())
463eb1c47d3SEd Tanous     {
464a716aa74SEd Tanous         return;
465eb1c47d3SEd Tanous     }
466a716aa74SEd Tanous     if (protocol == "Redfish" || protocol.empty())
467a716aa74SEd Tanous     {
468a716aa74SEd Tanous         if (url.port_number() == 443)
469a716aa74SEd Tanous         {
470a716aa74SEd Tanous             url.set_scheme("https");
471a716aa74SEd Tanous         }
472a716aa74SEd Tanous         if (url.port_number() == 80)
473eb1c47d3SEd Tanous         {
47425b54dbaSEd Tanous             if constexpr (BMCWEB_INSECURE_PUSH_STYLE_NOTIFICATION)
475eb1c47d3SEd Tanous             {
476a716aa74SEd Tanous                 url.set_scheme("http");
477eb1c47d3SEd Tanous             }
478eb1c47d3SEd Tanous         }
479a716aa74SEd Tanous     }
480a716aa74SEd Tanous     else if (protocol == "SNMPv2c")
4813d30708fSChicago Duan     {
482a716aa74SEd Tanous         url.set_scheme("snmp");
4833d30708fSChicago Duan     }
484eb1c47d3SEd Tanous }
485eb1c47d3SEd Tanous 
setPortDefaults(boost::urls::url & url)486a716aa74SEd Tanous inline void setPortDefaults(boost::urls::url& url)
487eb1c47d3SEd Tanous {
488eb1c47d3SEd Tanous     uint16_t port = url.port_number();
489eb1c47d3SEd Tanous     if (port != 0)
490eb1c47d3SEd Tanous     {
491a716aa74SEd Tanous         return;
492eb1c47d3SEd Tanous     }
493eb1c47d3SEd Tanous 
494eb1c47d3SEd Tanous     // If the user hasn't explicitly stated a port, pick one explicitly for them
495eb1c47d3SEd Tanous     // based on the protocol defaults
496eb1c47d3SEd Tanous     if (url.scheme() == "http")
497eb1c47d3SEd Tanous     {
498a716aa74SEd Tanous         url.set_port_number(80);
499eb1c47d3SEd Tanous     }
500eb1c47d3SEd Tanous     if (url.scheme() == "https")
501eb1c47d3SEd Tanous     {
502a716aa74SEd Tanous         url.set_port_number(443);
503eb1c47d3SEd Tanous     }
5043d30708fSChicago Duan     if (url.scheme() == "snmp")
5053d30708fSChicago Duan     {
506a716aa74SEd Tanous         url.set_port_number(162);
5073d30708fSChicago Duan     }
50811baefe4SEd Tanous }
50911baefe4SEd Tanous 
51004e438cbSEd Tanous } // namespace utility
51104e438cbSEd Tanous } // namespace crow
51271f2db75SEd Tanous 
51371f2db75SEd Tanous namespace nlohmann
51471f2db75SEd Tanous {
5154a7fbefdSEd Tanous template <std::derived_from<boost::urls::url_view_base> URL>
5164a7fbefdSEd Tanous struct adl_serializer<URL>
51771f2db75SEd Tanous {
51871f2db75SEd Tanous     // NOLINTNEXTLINE(readability-identifier-naming)
to_jsonnlohmann::adl_serializer5194a7fbefdSEd Tanous     static void to_json(json& j, const URL& url)
52071f2db75SEd Tanous     {
521079360aeSEd Tanous         j = url.buffer();
52271f2db75SEd Tanous     }
52371f2db75SEd Tanous };
52471f2db75SEd Tanous } // namespace nlohmann
525