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