104e438cbSEd Tanous #pragma once
204e438cbSEd Tanous
33ccb3adbSEd Tanous #include "bmcweb_config.h"
43ccb3adbSEd Tanous
56dbe9beaSEd Tanous extern "C"
66dbe9beaSEd Tanous {
704e438cbSEd Tanous #include <openssl/crypto.h>
86dbe9beaSEd Tanous }
904e438cbSEd Tanous
10c867a83eSEd Tanous #include <boost/callable_traits.hpp>
11079360aeSEd Tanous #include <boost/url/parse.hpp>
12eae855c7SEd Tanous #include <boost/url/url.hpp>
13079360aeSEd Tanous #include <boost/url/url_view.hpp>
144a7fbefdSEd Tanous #include <boost/url/url_view_base.hpp>
1571f2db75SEd Tanous #include <nlohmann/json.hpp>
161d8782e7SNan Zhou
179ea15c35SEd Tanous #include <array>
1874849befSEd Tanous #include <chrono>
19c715ec29SEd Tanous #include <cstddef>
2004e438cbSEd Tanous #include <cstdint>
219ea15c35SEd Tanous #include <ctime>
2204e438cbSEd Tanous #include <functional>
239896eaedSEd Tanous #include <iomanip>
249ea15c35SEd Tanous #include <limits>
2504e438cbSEd Tanous #include <stdexcept>
2604e438cbSEd Tanous #include <string>
279ea15c35SEd Tanous #include <string_view>
2804e438cbSEd Tanous #include <tuple>
299ea15c35SEd Tanous #include <type_traits>
309ea15c35SEd Tanous #include <utility>
31ca1600c1SSzymon Dompke #include <variant>
3204e438cbSEd Tanous
3304e438cbSEd Tanous namespace crow
3404e438cbSEd Tanous {
3547488a98SEd Tanous namespace utility
3604e438cbSEd Tanous {
3704e438cbSEd Tanous
getParameterTag(std::string_view url)389de65b34SEd Tanous constexpr uint64_t getParameterTag(std::string_view url)
3904e438cbSEd Tanous {
401c30e500SEd Tanous uint64_t tagValue = 0;
411c30e500SEd Tanous size_t urlSegmentIndex = std::string_view::npos;
42b00dcc27SEd Tanous
431c30e500SEd Tanous for (size_t urlIndex = 0; urlIndex < url.size(); urlIndex++)
441c30e500SEd Tanous {
451c30e500SEd Tanous char character = url[urlIndex];
461c30e500SEd Tanous if (character == '<')
471c30e500SEd Tanous {
481c30e500SEd Tanous if (urlSegmentIndex != std::string_view::npos)
4904e438cbSEd Tanous {
5004e438cbSEd Tanous return 0;
5104e438cbSEd Tanous }
521c30e500SEd Tanous urlSegmentIndex = urlIndex;
531c30e500SEd Tanous }
541c30e500SEd Tanous if (character == '>')
5504e438cbSEd Tanous {
561c30e500SEd Tanous if (urlSegmentIndex == std::string_view::npos)
571c30e500SEd Tanous {
581c30e500SEd Tanous return 0;
591c30e500SEd Tanous }
6089492a15SPatrick Williams std::string_view tag = url.substr(urlSegmentIndex,
6189492a15SPatrick Williams urlIndex + 1 - urlSegmentIndex);
621c30e500SEd Tanous
631c30e500SEd Tanous if (tag == "<str>" || tag == "<string>")
6404e438cbSEd Tanous {
65d9e89dfdSEd Tanous tagValue++;
6604e438cbSEd Tanous }
671c30e500SEd Tanous if (tag == "<path>")
6804e438cbSEd Tanous {
69d9e89dfdSEd Tanous tagValue++;
7004e438cbSEd Tanous }
711c30e500SEd Tanous urlSegmentIndex = std::string_view::npos;
721c30e500SEd Tanous }
731c30e500SEd Tanous }
741c30e500SEd Tanous if (urlSegmentIndex != std::string_view::npos)
751c30e500SEd Tanous {
761c30e500SEd Tanous return 0;
771c30e500SEd Tanous }
781c30e500SEd Tanous return tagValue;
7904e438cbSEd Tanous }
8004e438cbSEd Tanous
81ee192c06SEd Tanous class Base64Encoder
82d830ff5aSAdriana Kobylak {
83ee192c06SEd Tanous char overflow1 = '\0';
84ee192c06SEd Tanous char overflow2 = '\0';
85ee192c06SEd Tanous uint8_t overflowCount = 0;
86ee192c06SEd Tanous
87ee192c06SEd Tanous constexpr static std::array<char, 64> key = {
88d830ff5aSAdriana Kobylak 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
89d830ff5aSAdriana Kobylak 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
90d830ff5aSAdriana Kobylak 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
91d830ff5aSAdriana Kobylak 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
92d830ff5aSAdriana Kobylak '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
93d830ff5aSAdriana Kobylak
94ee192c06SEd Tanous // Takes 3 ascii chars, and encodes them as 4 base64 chars
encodeTriple(char first,char second,char third,std::string & output)95ee192c06SEd Tanous static void encodeTriple(char first, char second, char third,
96ee192c06SEd Tanous std::string& output)
97d830ff5aSAdriana Kobylak {
98543f4400SEd Tanous size_t keyIndex = 0;
99d830ff5aSAdriana Kobylak
100ee192c06SEd Tanous keyIndex = static_cast<size_t>(first & 0xFC) >> 2;
101ee192c06SEd Tanous output += key[keyIndex];
102d830ff5aSAdriana Kobylak
103ee192c06SEd Tanous keyIndex = static_cast<size_t>(first & 0x03) << 4;
104ee192c06SEd Tanous keyIndex += static_cast<size_t>(second & 0xF0) >> 4;
105ee192c06SEd Tanous output += key[keyIndex];
106ee192c06SEd Tanous
107ee192c06SEd Tanous keyIndex = static_cast<size_t>(second & 0x0F) << 2;
108ee192c06SEd Tanous keyIndex += static_cast<size_t>(third & 0xC0) >> 6;
109ee192c06SEd Tanous output += key[keyIndex];
110ee192c06SEd Tanous
111ee192c06SEd Tanous keyIndex = static_cast<size_t>(third & 0x3F);
112ee192c06SEd Tanous output += key[keyIndex];
113ee192c06SEd Tanous }
114ee192c06SEd Tanous
115ee192c06SEd Tanous public:
116ee192c06SEd Tanous // Accepts a partial string to encode, and writes the encoded characters to
117ee192c06SEd Tanous // the output stream. requires subsequently calling finalize to complete
118ee192c06SEd Tanous // stream.
encode(std::string_view data,std::string & output)119ee192c06SEd Tanous void encode(std::string_view data, std::string& output)
120d830ff5aSAdriana Kobylak {
121ee192c06SEd Tanous // Encode the last round of overflow chars first
122ee192c06SEd Tanous if (overflowCount == 2)
123d830ff5aSAdriana Kobylak {
124ee192c06SEd Tanous if (!data.empty())
125ee192c06SEd Tanous {
126ee192c06SEd Tanous encodeTriple(overflow1, overflow2, data[0], output);
127ee192c06SEd Tanous overflowCount = 0;
128ee192c06SEd Tanous data.remove_prefix(1);
129ee192c06SEd Tanous }
130ee192c06SEd Tanous }
131ee192c06SEd Tanous else if (overflowCount == 1)
132ee192c06SEd Tanous {
133ee192c06SEd Tanous if (data.size() >= 2)
134ee192c06SEd Tanous {
135ee192c06SEd Tanous encodeTriple(overflow1, data[0], data[1], output);
136ee192c06SEd Tanous overflowCount = 0;
137ee192c06SEd Tanous data.remove_prefix(2);
138ee192c06SEd Tanous }
139ee192c06SEd Tanous }
140d830ff5aSAdriana Kobylak
141ee192c06SEd Tanous while (data.size() >= 3)
142ee192c06SEd Tanous {
143ee192c06SEd Tanous encodeTriple(data[0], data[1], data[2], output);
144ee192c06SEd Tanous data.remove_prefix(3);
145ee192c06SEd Tanous }
146ee192c06SEd Tanous
147ee192c06SEd Tanous if (!data.empty() && overflowCount == 0)
148ee192c06SEd Tanous {
149ee192c06SEd Tanous overflow1 = data[0];
150ee192c06SEd Tanous overflowCount++;
151ee192c06SEd Tanous data.remove_prefix(1);
152ee192c06SEd Tanous }
153ee192c06SEd Tanous
154ee192c06SEd Tanous if (!data.empty() && overflowCount == 1)
155ee192c06SEd Tanous {
156ee192c06SEd Tanous overflow2 = data[0];
157ee192c06SEd Tanous overflowCount++;
158ee192c06SEd Tanous data.remove_prefix(1);
159ee192c06SEd Tanous }
160ee192c06SEd Tanous }
161ee192c06SEd Tanous
162ee192c06SEd Tanous // Completes a base64 output, by writing any MOD(3) characters to the
163ee192c06SEd Tanous // output, as well as any required trailing =
finalize(std::string & output)164ee192c06SEd Tanous void finalize(std::string& output)
165ee192c06SEd Tanous {
166ee192c06SEd Tanous if (overflowCount == 0)
167ee192c06SEd Tanous {
168ee192c06SEd Tanous return;
169ee192c06SEd Tanous }
170ee192c06SEd Tanous size_t keyIndex = static_cast<size_t>(overflow1 & 0xFC) >> 2;
171ee192c06SEd Tanous output += key[keyIndex];
172ee192c06SEd Tanous
173ee192c06SEd Tanous keyIndex = static_cast<size_t>(overflow1 & 0x03) << 4;
174ee192c06SEd Tanous if (overflowCount == 2)
175ee192c06SEd Tanous {
176ee192c06SEd Tanous keyIndex += static_cast<size_t>(overflow2 & 0xF0) >> 4;
177ee192c06SEd Tanous output += key[keyIndex];
178ee192c06SEd Tanous keyIndex = static_cast<size_t>(overflow2 & 0x0F) << 2;
179ee192c06SEd Tanous output += key[keyIndex];
180d830ff5aSAdriana Kobylak }
181d830ff5aSAdriana Kobylak else
182d830ff5aSAdriana Kobylak {
183ee192c06SEd Tanous output += key[keyIndex];
184ee192c06SEd Tanous output += '=';
185d830ff5aSAdriana Kobylak }
186ee192c06SEd Tanous output += '=';
187ee192c06SEd Tanous overflowCount = 0;
188d830ff5aSAdriana Kobylak }
189ee192c06SEd Tanous
190ee192c06SEd Tanous // Returns the required output buffer in characters for an input of size
191ee192c06SEd Tanous // inputSize
encodedSize(size_t inputSize)192ee192c06SEd Tanous static size_t constexpr encodedSize(size_t inputSize)
193d830ff5aSAdriana Kobylak {
194ee192c06SEd Tanous // Base64 encodes 3 character blocks as 4 character blocks
195ee192c06SEd Tanous // With a possibility of 2 trailing = characters
196ee192c06SEd Tanous return (inputSize + 2) / 3 * 4;
197d830ff5aSAdriana Kobylak }
198ee192c06SEd Tanous };
199d830ff5aSAdriana Kobylak
base64encode(std::string_view data)200ee192c06SEd Tanous inline std::string base64encode(std::string_view data)
201ee192c06SEd Tanous {
202ee192c06SEd Tanous // Encodes a 3 character stream into a 4 character stream
203ee192c06SEd Tanous std::string out;
204ee192c06SEd Tanous Base64Encoder base64;
205ee192c06SEd Tanous out.reserve(Base64Encoder::encodedSize(data.size()));
206ee192c06SEd Tanous base64.encode(data, out);
207ee192c06SEd Tanous base64.finalize(out);
208ee192c06SEd Tanous return out;
209d830ff5aSAdriana Kobylak }
210d830ff5aSAdriana Kobylak
21104e438cbSEd Tanous // TODO this is temporary and should be deleted once base64 is refactored out of
21204e438cbSEd Tanous // crow
base64Decode(std::string_view input,std::string & output)21326ccae32SEd Tanous inline bool base64Decode(std::string_view input, std::string& output)
21404e438cbSEd Tanous {
21504e438cbSEd Tanous static const char nop = static_cast<char>(-1);
21604e438cbSEd Tanous // See note on encoding_data[] in above function
21704e438cbSEd Tanous static const std::array<char, 256> decodingData = {
21804e438cbSEd Tanous nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
21904e438cbSEd Tanous nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
22004e438cbSEd Tanous nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
22104e438cbSEd Tanous nop, 62, nop, nop, nop, 63, 52, 53, 54, 55, 56, 57, 58, 59,
22204e438cbSEd Tanous 60, 61, nop, nop, nop, nop, nop, nop, nop, 0, 1, 2, 3, 4,
22304e438cbSEd Tanous 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
22404e438cbSEd Tanous 19, 20, 21, 22, 23, 24, 25, nop, nop, nop, nop, nop, nop, 26,
22504e438cbSEd Tanous 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
22604e438cbSEd Tanous 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 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, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
23404e438cbSEd Tanous nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
23504e438cbSEd Tanous nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
23604e438cbSEd Tanous nop, nop, nop, nop};
23704e438cbSEd Tanous
23804e438cbSEd Tanous size_t inputLength = input.size();
23904e438cbSEd Tanous
24004e438cbSEd Tanous // allocate space for output string
24104e438cbSEd Tanous output.clear();
24204e438cbSEd Tanous output.reserve(((inputLength + 2) / 3) * 4);
24304e438cbSEd Tanous
24404e438cbSEd Tanous auto getCodeValue = [](char c) {
24504e438cbSEd Tanous auto code = static_cast<unsigned char>(c);
24604e438cbSEd Tanous // Ensure we cannot index outside the bounds of the decoding array
24704e438cbSEd Tanous static_assert(std::numeric_limits<decltype(code)>::max() <
24804e438cbSEd Tanous decodingData.size());
24904e438cbSEd Tanous return decodingData[code];
25004e438cbSEd Tanous };
25104e438cbSEd Tanous
25204e438cbSEd Tanous // for each 4-bytes sequence from the input, extract 4 6-bits sequences by
25304e438cbSEd Tanous // dropping first two bits
25404e438cbSEd Tanous // and regenerate into 3 8-bits sequences
25504e438cbSEd Tanous
25604e438cbSEd Tanous for (size_t i = 0; i < inputLength; i++)
25704e438cbSEd Tanous {
258543f4400SEd Tanous char base64code0 = 0;
259543f4400SEd Tanous char base64code1 = 0;
26004e438cbSEd Tanous char base64code2 = 0; // initialized to 0 to suppress warnings
26104e438cbSEd Tanous
26204e438cbSEd Tanous base64code0 = getCodeValue(input[i]);
26304e438cbSEd Tanous if (base64code0 == nop)
26404e438cbSEd Tanous { // non base64 character
26504e438cbSEd Tanous return false;
26604e438cbSEd Tanous }
26704e438cbSEd Tanous if (!(++i < inputLength))
26804e438cbSEd Tanous { // we need at least two input bytes for first
26904e438cbSEd Tanous // byte output
27004e438cbSEd Tanous return false;
27104e438cbSEd Tanous }
27204e438cbSEd Tanous base64code1 = getCodeValue(input[i]);
27304e438cbSEd Tanous if (base64code1 == nop)
27404e438cbSEd Tanous { // non base64 character
27504e438cbSEd Tanous return false;
27604e438cbSEd Tanous }
27704e438cbSEd Tanous output +=
27804e438cbSEd Tanous static_cast<char>((base64code0 << 2) | ((base64code1 >> 4) & 0x3));
27904e438cbSEd Tanous
28004e438cbSEd Tanous if (++i < inputLength)
28104e438cbSEd Tanous {
28204e438cbSEd Tanous char c = input[i];
28304e438cbSEd Tanous if (c == '=')
28404e438cbSEd Tanous { // padding , end of input
28504e438cbSEd Tanous return (base64code1 & 0x0f) == 0;
28604e438cbSEd Tanous }
28704e438cbSEd Tanous base64code2 = getCodeValue(input[i]);
28804e438cbSEd Tanous if (base64code2 == nop)
28904e438cbSEd Tanous { // non base64 character
29004e438cbSEd Tanous return false;
29104e438cbSEd Tanous }
29204e438cbSEd Tanous output += static_cast<char>(((base64code1 << 4) & 0xf0) |
29304e438cbSEd Tanous ((base64code2 >> 2) & 0x0f));
29404e438cbSEd Tanous }
29504e438cbSEd Tanous
29604e438cbSEd Tanous if (++i < inputLength)
29704e438cbSEd Tanous {
29804e438cbSEd Tanous char c = input[i];
29904e438cbSEd Tanous if (c == '=')
30004e438cbSEd Tanous { // padding , end of input
30104e438cbSEd Tanous return (base64code2 & 0x03) == 0;
30204e438cbSEd Tanous }
303f8fe53e7SEd Tanous char base64code3 = getCodeValue(input[i]);
30404e438cbSEd Tanous if (base64code3 == nop)
30504e438cbSEd Tanous { // non base64 character
30604e438cbSEd Tanous return false;
30704e438cbSEd Tanous }
30804e438cbSEd Tanous output +=
30904e438cbSEd Tanous static_cast<char>((((base64code2 << 6) & 0xc0) | base64code3));
31004e438cbSEd Tanous }
31104e438cbSEd Tanous }
31204e438cbSEd Tanous
31304e438cbSEd Tanous return true;
31404e438cbSEd Tanous }
31504e438cbSEd Tanous
constantTimeStringCompare(std::string_view a,std::string_view b)31626ccae32SEd Tanous inline bool constantTimeStringCompare(std::string_view a, std::string_view b)
31704e438cbSEd Tanous {
31804e438cbSEd Tanous // Important note, this function is ONLY constant time if the two input
31904e438cbSEd Tanous // sizes are the same
32004e438cbSEd Tanous if (a.size() != b.size())
32104e438cbSEd Tanous {
32204e438cbSEd Tanous return false;
32304e438cbSEd Tanous }
32404e438cbSEd Tanous return CRYPTO_memcmp(a.data(), b.data(), a.size()) == 0;
32504e438cbSEd Tanous }
32604e438cbSEd Tanous
32704e438cbSEd Tanous struct ConstantTimeCompare
32804e438cbSEd Tanous {
operator ()crow::utility::ConstantTimeCompare32926ccae32SEd Tanous bool operator()(std::string_view a, std::string_view b) const
33004e438cbSEd Tanous {
33104e438cbSEd Tanous return constantTimeStringCompare(a, b);
33204e438cbSEd Tanous }
33304e438cbSEd Tanous };
33404e438cbSEd Tanous
335eae855c7SEd Tanous namespace details
336eae855c7SEd Tanous {
337eae855c7SEd Tanous inline boost::urls::url
appendUrlPieces(boost::urls::url & url,const std::initializer_list<std::string_view> args)338c6bcedc6SWilly Tu appendUrlPieces(boost::urls::url& url,
339c6bcedc6SWilly Tu const std::initializer_list<std::string_view> args)
340eae855c7SEd Tanous {
34126ccae32SEd Tanous for (std::string_view arg : args)
342eae855c7SEd Tanous {
343eae855c7SEd Tanous url.segments().push_back(arg);
344eae855c7SEd Tanous }
345eae855c7SEd Tanous return url;
346eae855c7SEd Tanous }
347c6bcedc6SWilly Tu
348eae855c7SEd Tanous } // namespace details
349eae855c7SEd Tanous
3507f8d8fa9SEd Tanous class OrMorePaths
3517f8d8fa9SEd Tanous {};
3527f8d8fa9SEd Tanous
353eae855c7SEd Tanous template <typename... AV>
appendUrlPieces(boost::urls::url & url,const AV...args)354c6bcedc6SWilly Tu inline void appendUrlPieces(boost::urls::url& url, const AV... args)
355c6bcedc6SWilly Tu {
356c6bcedc6SWilly Tu details::appendUrlPieces(url, {args...});
357c6bcedc6SWilly Tu }
358c6bcedc6SWilly Tu
359ca1600c1SSzymon Dompke namespace details
360ca1600c1SSzymon Dompke {
361ca1600c1SSzymon Dompke
362ca1600c1SSzymon Dompke // std::reference_wrapper<std::string> - extracts segment to variable
363ca1600c1SSzymon Dompke // std::string_view - checks if segment is equal to variable
3647f8d8fa9SEd Tanous using UrlSegment = std::variant<std::reference_wrapper<std::string>,
3657f8d8fa9SEd Tanous std::string_view, OrMorePaths>;
3667f8d8fa9SEd Tanous
3677f8d8fa9SEd Tanous enum class UrlParseResult
3687f8d8fa9SEd Tanous {
3697f8d8fa9SEd Tanous Continue,
3707f8d8fa9SEd Tanous Fail,
3717f8d8fa9SEd Tanous Done,
3727f8d8fa9SEd Tanous };
373ca1600c1SSzymon Dompke
374ca1600c1SSzymon Dompke class UrlSegmentMatcherVisitor
375ca1600c1SSzymon Dompke {
376ca1600c1SSzymon Dompke public:
operator ()(std::string & output)3777f8d8fa9SEd Tanous UrlParseResult operator()(std::string& output)
378ca1600c1SSzymon Dompke {
379079360aeSEd Tanous output = segment;
3807f8d8fa9SEd Tanous return UrlParseResult::Continue;
381ca1600c1SSzymon Dompke }
382ca1600c1SSzymon Dompke
operator ()(std::string_view expected)3837f8d8fa9SEd Tanous UrlParseResult operator()(std::string_view expected)
384ca1600c1SSzymon Dompke {
385079360aeSEd Tanous if (segment == expected)
3867f8d8fa9SEd Tanous {
3877f8d8fa9SEd Tanous return UrlParseResult::Continue;
3887f8d8fa9SEd Tanous }
3897f8d8fa9SEd Tanous return UrlParseResult::Fail;
3907f8d8fa9SEd Tanous }
3917f8d8fa9SEd Tanous
operator ()(OrMorePaths)3927f8d8fa9SEd Tanous UrlParseResult operator()(OrMorePaths /*unused*/)
3937f8d8fa9SEd Tanous {
3947f8d8fa9SEd Tanous return UrlParseResult::Done;
395ca1600c1SSzymon Dompke }
396ca1600c1SSzymon Dompke
UrlSegmentMatcherVisitor(std::string_view segmentIn)397079360aeSEd Tanous explicit UrlSegmentMatcherVisitor(std::string_view segmentIn) :
398ca1600c1SSzymon Dompke segment(segmentIn)
399ca1600c1SSzymon Dompke {}
400ca1600c1SSzymon Dompke
401ca1600c1SSzymon Dompke private:
402079360aeSEd Tanous std::string_view segment;
403ca1600c1SSzymon Dompke };
404ca1600c1SSzymon Dompke
readUrlSegments(const boost::urls::url_view_base & url,std::initializer_list<UrlSegment> segments)4054a7fbefdSEd Tanous inline bool readUrlSegments(const boost::urls::url_view_base& url,
4065be2b14aSEd Tanous std::initializer_list<UrlSegment> segments)
407ca1600c1SSzymon Dompke {
4084a7fbefdSEd Tanous const boost::urls::segments_view& urlSegments = url.segments();
409ca1600c1SSzymon Dompke
4107f8d8fa9SEd Tanous if (!urlSegments.is_absolute())
411ca1600c1SSzymon Dompke {
412ca1600c1SSzymon Dompke return false;
413ca1600c1SSzymon Dompke }
414ca1600c1SSzymon Dompke
4154a7fbefdSEd Tanous boost::urls::segments_view::const_iterator it = urlSegments.begin();
4164a7fbefdSEd Tanous boost::urls::segments_view::const_iterator end = urlSegments.end();
417ca1600c1SSzymon Dompke
418ca1600c1SSzymon Dompke for (const auto& segment : segments)
419ca1600c1SSzymon Dompke {
4207f8d8fa9SEd Tanous if (it == end)
4217f8d8fa9SEd Tanous {
4227f8d8fa9SEd Tanous // If the request ends with an "any" path, this was successful
4237f8d8fa9SEd Tanous return std::holds_alternative<OrMorePaths>(segment);
4247f8d8fa9SEd Tanous }
4257f8d8fa9SEd Tanous UrlParseResult res = std::visit(UrlSegmentMatcherVisitor(*it), segment);
4267f8d8fa9SEd Tanous if (res == UrlParseResult::Done)
4277f8d8fa9SEd Tanous {
4287f8d8fa9SEd Tanous return true;
4297f8d8fa9SEd Tanous }
4307f8d8fa9SEd Tanous if (res == UrlParseResult::Fail)
431ca1600c1SSzymon Dompke {
432ca1600c1SSzymon Dompke return false;
433ca1600c1SSzymon Dompke }
434ca1600c1SSzymon Dompke it++;
435ca1600c1SSzymon Dompke }
4364c30e226SCarson Labrado
4374c30e226SCarson Labrado // There will be an empty segment at the end if the URI ends with a "/"
4384c30e226SCarson Labrado // e.g. /redfish/v1/Chassis/
4394c30e226SCarson Labrado if ((it != end) && urlSegments.back().empty())
4404c30e226SCarson Labrado {
4414c30e226SCarson Labrado it++;
4424c30e226SCarson Labrado }
4437f8d8fa9SEd Tanous return it == end;
444ca1600c1SSzymon Dompke }
445ca1600c1SSzymon Dompke
446ca1600c1SSzymon Dompke } // namespace details
447ca1600c1SSzymon Dompke
448ca1600c1SSzymon Dompke template <typename... Args>
readUrlSegments(const boost::urls::url_view_base & url,Args &&...args)4494a7fbefdSEd Tanous inline bool readUrlSegments(const boost::urls::url_view_base& url,
4504a7fbefdSEd Tanous Args&&... args)
451ca1600c1SSzymon Dompke {
45239662a3bSEd Tanous return details::readUrlSegments(url, {std::forward<Args>(args)...});
453ca1600c1SSzymon Dompke }
454ca1600c1SSzymon Dompke
4554a7fbefdSEd Tanous inline boost::urls::url
replaceUrlSegment(const boost::urls::url_view_base & urlView,const uint replaceLoc,std::string_view newSegment)4564a7fbefdSEd Tanous replaceUrlSegment(const boost::urls::url_view_base& urlView,
4574a7fbefdSEd Tanous const uint replaceLoc, std::string_view newSegment)
4581c0bb5c6SCarson Labrado {
4594a7fbefdSEd Tanous const boost::urls::segments_view& urlSegments = urlView.segments();
4601c0bb5c6SCarson Labrado boost::urls::url url("/");
4611c0bb5c6SCarson Labrado
4621c0bb5c6SCarson Labrado if (!urlSegments.is_absolute())
4631c0bb5c6SCarson Labrado {
4641c0bb5c6SCarson Labrado return url;
4651c0bb5c6SCarson Labrado }
4661c0bb5c6SCarson Labrado
4671c0bb5c6SCarson Labrado boost::urls::segments_view::iterator it = urlSegments.begin();
4681c0bb5c6SCarson Labrado boost::urls::segments_view::iterator end = urlSegments.end();
4691c0bb5c6SCarson Labrado
4701c0bb5c6SCarson Labrado for (uint idx = 0; it != end; it++, idx++)
4711c0bb5c6SCarson Labrado {
4721c0bb5c6SCarson Labrado if (idx == replaceLoc)
4731c0bb5c6SCarson Labrado {
4741c0bb5c6SCarson Labrado url.segments().push_back(newSegment);
4751c0bb5c6SCarson Labrado }
4761c0bb5c6SCarson Labrado else
4771c0bb5c6SCarson Labrado {
4781c0bb5c6SCarson Labrado url.segments().push_back(*it);
4791c0bb5c6SCarson Labrado }
4801c0bb5c6SCarson Labrado }
4811c0bb5c6SCarson Labrado
4821c0bb5c6SCarson Labrado return url;
4831c0bb5c6SCarson Labrado }
4841c0bb5c6SCarson Labrado
setProtocolDefaults(boost::urls::url & url,std::string_view protocol)485a716aa74SEd Tanous inline void setProtocolDefaults(boost::urls::url& url,
486a716aa74SEd Tanous std::string_view protocol)
487eb1c47d3SEd Tanous {
488a716aa74SEd Tanous if (url.has_scheme())
489eb1c47d3SEd Tanous {
490a716aa74SEd Tanous return;
491eb1c47d3SEd Tanous }
492a716aa74SEd Tanous if (protocol == "Redfish" || protocol.empty())
493a716aa74SEd Tanous {
494a716aa74SEd Tanous if (url.port_number() == 443)
495a716aa74SEd Tanous {
496a716aa74SEd Tanous url.set_scheme("https");
497a716aa74SEd Tanous }
498a716aa74SEd Tanous if (url.port_number() == 80)
499eb1c47d3SEd Tanous {
500*25b54dbaSEd Tanous if constexpr (BMCWEB_INSECURE_PUSH_STYLE_NOTIFICATION)
501eb1c47d3SEd Tanous {
502a716aa74SEd Tanous url.set_scheme("http");
503eb1c47d3SEd Tanous }
504eb1c47d3SEd Tanous }
505a716aa74SEd Tanous }
506a716aa74SEd Tanous else if (protocol == "SNMPv2c")
5073d30708fSChicago Duan {
508a716aa74SEd Tanous url.set_scheme("snmp");
5093d30708fSChicago Duan }
510eb1c47d3SEd Tanous }
511eb1c47d3SEd Tanous
setPortDefaults(boost::urls::url & url)512a716aa74SEd Tanous inline void setPortDefaults(boost::urls::url& url)
513eb1c47d3SEd Tanous {
514eb1c47d3SEd Tanous uint16_t port = url.port_number();
515eb1c47d3SEd Tanous if (port != 0)
516eb1c47d3SEd Tanous {
517a716aa74SEd Tanous return;
518eb1c47d3SEd Tanous }
519eb1c47d3SEd Tanous
520eb1c47d3SEd Tanous // If the user hasn't explicitly stated a port, pick one explicitly for them
521eb1c47d3SEd Tanous // based on the protocol defaults
522eb1c47d3SEd Tanous if (url.scheme() == "http")
523eb1c47d3SEd Tanous {
524a716aa74SEd Tanous url.set_port_number(80);
525eb1c47d3SEd Tanous }
526eb1c47d3SEd Tanous if (url.scheme() == "https")
527eb1c47d3SEd Tanous {
528a716aa74SEd Tanous url.set_port_number(443);
529eb1c47d3SEd Tanous }
5303d30708fSChicago Duan if (url.scheme() == "snmp")
5313d30708fSChicago Duan {
532a716aa74SEd Tanous url.set_port_number(162);
5333d30708fSChicago Duan }
53411baefe4SEd Tanous }
53511baefe4SEd Tanous
53604e438cbSEd Tanous } // namespace utility
53704e438cbSEd Tanous } // namespace crow
53871f2db75SEd Tanous
53971f2db75SEd Tanous namespace nlohmann
54071f2db75SEd Tanous {
5414a7fbefdSEd Tanous template <std::derived_from<boost::urls::url_view_base> URL>
5424a7fbefdSEd Tanous struct adl_serializer<URL>
54371f2db75SEd Tanous {
54471f2db75SEd Tanous // NOLINTNEXTLINE(readability-identifier-naming)
to_jsonnlohmann::adl_serializer5454a7fbefdSEd Tanous static void to_json(json& j, const URL& url)
54671f2db75SEd Tanous {
547079360aeSEd Tanous j = url.buffer();
54871f2db75SEd Tanous }
54971f2db75SEd Tanous };
55071f2db75SEd Tanous } // namespace nlohmann
551