| Ed Tanous | 40e9b92 | 2024-09-10 13:50:16 -0700 | [diff] [blame] | 1 | // SPDX-License-Identifier: Apache-2.0 | 
 | 2 | // SPDX-FileCopyrightText: Copyright OpenBMC Authors | 
| Ed Tanous | 7045c8d | 2017-04-03 10:04:37 -0700 | [diff] [blame] | 3 | #pragma once | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 4 |  | 
| Ed Tanous | 3ccb3ad | 2023-01-13 17:40:03 -0800 | [diff] [blame] | 5 | #include "bmcweb_config.h" | 
 | 6 |  | 
| Ed Tanous | d785720 | 2025-01-28 15:32:26 -0800 | [diff] [blame] | 7 | #include <sys/types.h> | 
 | 8 |  | 
 | 9 | #include <boost/url/segments_view.hpp> | 
| Ed Tanous | eae855c | 2021-10-26 11:26:02 -0700 | [diff] [blame] | 10 | #include <boost/url/url.hpp> | 
| Ed Tanous | 4a7fbef | 2024-04-06 16:03:49 -0700 | [diff] [blame] | 11 | #include <boost/url/url_view_base.hpp> | 
| Myung Bae | 8873f32 | 2025-03-17 18:24:13 -0500 | [diff] [blame^] | 12 | #include <nlohmann/adl_serializer.hpp> | 
| Ed Tanous | 71f2db7 | 2022-05-25 12:28:09 -0700 | [diff] [blame] | 13 | #include <nlohmann/json.hpp> | 
| Nan Zhou | 1d8782e | 2021-11-29 22:23:18 -0800 | [diff] [blame] | 14 |  | 
| Ed Tanous | 9ea15c3 | 2022-01-04 14:18:22 -0800 | [diff] [blame] | 15 | #include <array> | 
| Ed Tanous | 80d2ef3 | 2025-02-04 09:29:02 -0800 | [diff] [blame] | 16 | #include <bit> | 
| Ed Tanous | d785720 | 2025-01-28 15:32:26 -0800 | [diff] [blame] | 17 | #include <concepts> | 
| Ed Tanous | c715ec2 | 2022-03-10 15:38:01 -0800 | [diff] [blame] | 18 | #include <cstddef> | 
| Ed Tanous | 7045c8d | 2017-04-03 10:04:37 -0700 | [diff] [blame] | 19 | #include <cstdint> | 
| Ed Tanous | 9ea15c3 | 2022-01-04 14:18:22 -0800 | [diff] [blame] | 20 | #include <ctime> | 
| Ed Tanous | 7045c8d | 2017-04-03 10:04:37 -0700 | [diff] [blame] | 21 | #include <functional> | 
| Ed Tanous | d785720 | 2025-01-28 15:32:26 -0800 | [diff] [blame] | 22 | #include <initializer_list> | 
| Ed Tanous | 9ea15c3 | 2022-01-04 14:18:22 -0800 | [diff] [blame] | 23 | #include <limits> | 
| Ed Tanous | 7045c8d | 2017-04-03 10:04:37 -0700 | [diff] [blame] | 24 | #include <string> | 
| Ed Tanous | 9ea15c3 | 2022-01-04 14:18:22 -0800 | [diff] [blame] | 25 | #include <string_view> | 
| Ed Tanous | 9ea15c3 | 2022-01-04 14:18:22 -0800 | [diff] [blame] | 26 | #include <type_traits> | 
 | 27 | #include <utility> | 
| Szymon Dompke | ca1600c | 2022-03-03 14:42:52 +0100 | [diff] [blame] | 28 | #include <variant> | 
| Ed Tanous | 7045c8d | 2017-04-03 10:04:37 -0700 | [diff] [blame] | 29 |  | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 30 | namespace crow | 
 | 31 | { | 
| Ed Tanous | 47488a9 | 2023-06-26 18:19:33 -0700 | [diff] [blame] | 32 | namespace utility | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 33 | { | 
| Ed Tanous | 7045c8d | 2017-04-03 10:04:37 -0700 | [diff] [blame] | 34 |  | 
| Ed Tanous | 9de65b3 | 2024-03-27 13:34:40 -0700 | [diff] [blame] | 35 | constexpr uint64_t getParameterTag(std::string_view url) | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 36 | { | 
| Ed Tanous | 1c30e50 | 2022-03-08 18:02:24 -0800 | [diff] [blame] | 37 |     uint64_t tagValue = 0; | 
 | 38 |     size_t urlSegmentIndex = std::string_view::npos; | 
| Ed Tanous | b00dcc2 | 2021-02-23 12:52:50 -0800 | [diff] [blame] | 39 |  | 
| Ed Tanous | 1c30e50 | 2022-03-08 18:02:24 -0800 | [diff] [blame] | 40 |     for (size_t urlIndex = 0; urlIndex < url.size(); urlIndex++) | 
 | 41 |     { | 
 | 42 |         char character = url[urlIndex]; | 
 | 43 |         if (character == '<') | 
 | 44 |         { | 
 | 45 |             if (urlSegmentIndex != std::string_view::npos) | 
 | 46 |             { | 
 | 47 |                 return 0; | 
 | 48 |             } | 
 | 49 |             urlSegmentIndex = urlIndex; | 
 | 50 |         } | 
 | 51 |         if (character == '>') | 
 | 52 |         { | 
 | 53 |             if (urlSegmentIndex == std::string_view::npos) | 
 | 54 |             { | 
 | 55 |                 return 0; | 
 | 56 |             } | 
| Patrick Williams | bd79bce | 2024-08-16 15:22:20 -0400 | [diff] [blame] | 57 |             std::string_view tag = | 
 | 58 |                 url.substr(urlSegmentIndex, urlIndex + 1 - urlSegmentIndex); | 
| Ed Tanous | 1c30e50 | 2022-03-08 18:02:24 -0800 | [diff] [blame] | 59 |  | 
| Ed Tanous | 1c30e50 | 2022-03-08 18:02:24 -0800 | [diff] [blame] | 60 |             if (tag == "<str>" || tag == "<string>") | 
 | 61 |             { | 
| Ed Tanous | d9e89df | 2024-03-27 14:08:59 -0700 | [diff] [blame] | 62 |                 tagValue++; | 
| Ed Tanous | 1c30e50 | 2022-03-08 18:02:24 -0800 | [diff] [blame] | 63 |             } | 
 | 64 |             if (tag == "<path>") | 
 | 65 |             { | 
| Ed Tanous | d9e89df | 2024-03-27 14:08:59 -0700 | [diff] [blame] | 66 |                 tagValue++; | 
| Ed Tanous | 1c30e50 | 2022-03-08 18:02:24 -0800 | [diff] [blame] | 67 |             } | 
| Ed Tanous | 1c30e50 | 2022-03-08 18:02:24 -0800 | [diff] [blame] | 68 |             urlSegmentIndex = std::string_view::npos; | 
 | 69 |         } | 
 | 70 |     } | 
 | 71 |     if (urlSegmentIndex != std::string_view::npos) | 
| Ed Tanous | 988403c | 2020-08-24 11:29:49 -0700 | [diff] [blame] | 72 |     { | 
 | 73 |         return 0; | 
 | 74 |     } | 
| Ed Tanous | 1c30e50 | 2022-03-08 18:02:24 -0800 | [diff] [blame] | 75 |     return tagValue; | 
| Ed Tanous | 7045c8d | 2017-04-03 10:04:37 -0700 | [diff] [blame] | 76 | } | 
| Ed Tanous | 7045c8d | 2017-04-03 10:04:37 -0700 | [diff] [blame] | 77 |  | 
| Ed Tanous | 80d2ef3 | 2025-02-04 09:29:02 -0800 | [diff] [blame] | 78 | constexpr static std::array<char, 64> base64key = { | 
 | 79 |     'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', | 
 | 80 |     'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', | 
 | 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 |     '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'}; | 
 | 84 |  | 
 | 85 | static constexpr char nop = static_cast<char>(-1); | 
 | 86 | constexpr std::array<char, 256> getDecodeTable(bool urlSafe) | 
 | 87 | { | 
 | 88 |     std::array<char, 256> decodeTable{}; | 
 | 89 |     decodeTable.fill(nop); | 
 | 90 |  | 
 | 91 |     for (size_t index = 0; index < base64key.size(); index++) | 
 | 92 |     { | 
 | 93 |         char character = base64key[index]; | 
 | 94 |         decodeTable[std::bit_cast<uint8_t>(character)] = | 
 | 95 |             static_cast<char>(index); | 
 | 96 |     } | 
 | 97 |  | 
 | 98 |     if (urlSafe) | 
 | 99 |     { | 
 | 100 |         // Urlsafe decode tables replace the last two characters with - and _ | 
 | 101 |         decodeTable['+'] = nop; | 
 | 102 |         decodeTable['/'] = nop; | 
 | 103 |         decodeTable['-'] = 62; | 
 | 104 |         decodeTable['_'] = 63; | 
 | 105 |     } | 
 | 106 |  | 
 | 107 |     return decodeTable; | 
 | 108 | } | 
 | 109 |  | 
| Ed Tanous | ee192c0 | 2023-12-13 10:49:58 -0800 | [diff] [blame] | 110 | class Base64Encoder | 
| Adriana Kobylak | d830ff5 | 2021-01-27 14:15:27 -0600 | [diff] [blame] | 111 | { | 
| Ed Tanous | ee192c0 | 2023-12-13 10:49:58 -0800 | [diff] [blame] | 112 |     char overflow1 = '\0'; | 
 | 113 |     char overflow2 = '\0'; | 
 | 114 |     uint8_t overflowCount = 0; | 
 | 115 |  | 
| Ed Tanous | ee192c0 | 2023-12-13 10:49:58 -0800 | [diff] [blame] | 116 |     // Takes 3 ascii chars, and encodes them as 4 base64 chars | 
 | 117 |     static void encodeTriple(char first, char second, char third, | 
 | 118 |                              std::string& output) | 
| Adriana Kobylak | d830ff5 | 2021-01-27 14:15:27 -0600 | [diff] [blame] | 119 |     { | 
| Ed Tanous | 543f440 | 2022-01-06 13:12:53 -0800 | [diff] [blame] | 120 |         size_t keyIndex = 0; | 
| Adriana Kobylak | d830ff5 | 2021-01-27 14:15:27 -0600 | [diff] [blame] | 121 |  | 
| Ed Tanous | ee192c0 | 2023-12-13 10:49:58 -0800 | [diff] [blame] | 122 |         keyIndex = static_cast<size_t>(first & 0xFC) >> 2; | 
| Ed Tanous | 80d2ef3 | 2025-02-04 09:29:02 -0800 | [diff] [blame] | 123 |         output += base64key[keyIndex]; | 
| Adriana Kobylak | d830ff5 | 2021-01-27 14:15:27 -0600 | [diff] [blame] | 124 |  | 
| Ed Tanous | ee192c0 | 2023-12-13 10:49:58 -0800 | [diff] [blame] | 125 |         keyIndex = static_cast<size_t>(first & 0x03) << 4; | 
 | 126 |         keyIndex += static_cast<size_t>(second & 0xF0) >> 4; | 
| Ed Tanous | 80d2ef3 | 2025-02-04 09:29:02 -0800 | [diff] [blame] | 127 |         output += base64key[keyIndex]; | 
| Ed Tanous | ee192c0 | 2023-12-13 10:49:58 -0800 | [diff] [blame] | 128 |  | 
 | 129 |         keyIndex = static_cast<size_t>(second & 0x0F) << 2; | 
 | 130 |         keyIndex += static_cast<size_t>(third & 0xC0) >> 6; | 
| Ed Tanous | 80d2ef3 | 2025-02-04 09:29:02 -0800 | [diff] [blame] | 131 |         output += base64key[keyIndex]; | 
| Ed Tanous | ee192c0 | 2023-12-13 10:49:58 -0800 | [diff] [blame] | 132 |  | 
 | 133 |         keyIndex = static_cast<size_t>(third & 0x3F); | 
| Ed Tanous | 80d2ef3 | 2025-02-04 09:29:02 -0800 | [diff] [blame] | 134 |         output += base64key[keyIndex]; | 
| Ed Tanous | ee192c0 | 2023-12-13 10:49:58 -0800 | [diff] [blame] | 135 |     } | 
 | 136 |  | 
 | 137 |   public: | 
 | 138 |     // Accepts a partial string to encode, and writes the encoded characters to | 
 | 139 |     // the output stream. requires subsequently calling finalize to complete | 
 | 140 |     // stream. | 
 | 141 |     void encode(std::string_view data, std::string& output) | 
 | 142 |     { | 
 | 143 |         // Encode the last round of overflow chars first | 
 | 144 |         if (overflowCount == 2) | 
| Adriana Kobylak | d830ff5 | 2021-01-27 14:15:27 -0600 | [diff] [blame] | 145 |         { | 
| Ed Tanous | ee192c0 | 2023-12-13 10:49:58 -0800 | [diff] [blame] | 146 |             if (!data.empty()) | 
| Adriana Kobylak | d830ff5 | 2021-01-27 14:15:27 -0600 | [diff] [blame] | 147 |             { | 
| Ed Tanous | ee192c0 | 2023-12-13 10:49:58 -0800 | [diff] [blame] | 148 |                 encodeTriple(overflow1, overflow2, data[0], output); | 
 | 149 |                 overflowCount = 0; | 
 | 150 |                 data.remove_prefix(1); | 
| Adriana Kobylak | d830ff5 | 2021-01-27 14:15:27 -0600 | [diff] [blame] | 151 |             } | 
| Ed Tanous | ee192c0 | 2023-12-13 10:49:58 -0800 | [diff] [blame] | 152 |         } | 
 | 153 |         else if (overflowCount == 1) | 
 | 154 |         { | 
 | 155 |             if (data.size() >= 2) | 
| Adriana Kobylak | d830ff5 | 2021-01-27 14:15:27 -0600 | [diff] [blame] | 156 |             { | 
| Ed Tanous | ee192c0 | 2023-12-13 10:49:58 -0800 | [diff] [blame] | 157 |                 encodeTriple(overflow1, data[0], data[1], output); | 
 | 158 |                 overflowCount = 0; | 
 | 159 |                 data.remove_prefix(2); | 
| Adriana Kobylak | d830ff5 | 2021-01-27 14:15:27 -0600 | [diff] [blame] | 160 |             } | 
 | 161 |         } | 
| Ed Tanous | ee192c0 | 2023-12-13 10:49:58 -0800 | [diff] [blame] | 162 |  | 
 | 163 |         while (data.size() >= 3) | 
 | 164 |         { | 
 | 165 |             encodeTriple(data[0], data[1], data[2], output); | 
 | 166 |             data.remove_prefix(3); | 
 | 167 |         } | 
 | 168 |  | 
 | 169 |         if (!data.empty() && overflowCount == 0) | 
 | 170 |         { | 
 | 171 |             overflow1 = data[0]; | 
 | 172 |             overflowCount++; | 
 | 173 |             data.remove_prefix(1); | 
 | 174 |         } | 
 | 175 |  | 
 | 176 |         if (!data.empty() && overflowCount == 1) | 
 | 177 |         { | 
 | 178 |             overflow2 = data[0]; | 
 | 179 |             overflowCount++; | 
 | 180 |             data.remove_prefix(1); | 
 | 181 |         } | 
 | 182 |     } | 
 | 183 |  | 
 | 184 |     // Completes a base64 output, by writing any MOD(3) characters to the | 
 | 185 |     // output, as well as any required trailing = | 
 | 186 |     void finalize(std::string& output) | 
 | 187 |     { | 
 | 188 |         if (overflowCount == 0) | 
 | 189 |         { | 
 | 190 |             return; | 
 | 191 |         } | 
 | 192 |         size_t keyIndex = static_cast<size_t>(overflow1 & 0xFC) >> 2; | 
| Ed Tanous | 80d2ef3 | 2025-02-04 09:29:02 -0800 | [diff] [blame] | 193 |         output += base64key[keyIndex]; | 
| Ed Tanous | ee192c0 | 2023-12-13 10:49:58 -0800 | [diff] [blame] | 194 |  | 
 | 195 |         keyIndex = static_cast<size_t>(overflow1 & 0x03) << 4; | 
 | 196 |         if (overflowCount == 2) | 
 | 197 |         { | 
 | 198 |             keyIndex += static_cast<size_t>(overflow2 & 0xF0) >> 4; | 
| Ed Tanous | 80d2ef3 | 2025-02-04 09:29:02 -0800 | [diff] [blame] | 199 |             output += base64key[keyIndex]; | 
| Ed Tanous | ee192c0 | 2023-12-13 10:49:58 -0800 | [diff] [blame] | 200 |             keyIndex = static_cast<size_t>(overflow2 & 0x0F) << 2; | 
| Ed Tanous | 80d2ef3 | 2025-02-04 09:29:02 -0800 | [diff] [blame] | 201 |             output += base64key[keyIndex]; | 
| Ed Tanous | ee192c0 | 2023-12-13 10:49:58 -0800 | [diff] [blame] | 202 |         } | 
| Adriana Kobylak | d830ff5 | 2021-01-27 14:15:27 -0600 | [diff] [blame] | 203 |         else | 
 | 204 |         { | 
| Ed Tanous | 80d2ef3 | 2025-02-04 09:29:02 -0800 | [diff] [blame] | 205 |             output += base64key[keyIndex]; | 
| Ed Tanous | ee192c0 | 2023-12-13 10:49:58 -0800 | [diff] [blame] | 206 |             output += '='; | 
| Adriana Kobylak | d830ff5 | 2021-01-27 14:15:27 -0600 | [diff] [blame] | 207 |         } | 
| Ed Tanous | ee192c0 | 2023-12-13 10:49:58 -0800 | [diff] [blame] | 208 |         output += '='; | 
 | 209 |         overflowCount = 0; | 
| Adriana Kobylak | d830ff5 | 2021-01-27 14:15:27 -0600 | [diff] [blame] | 210 |     } | 
 | 211 |  | 
| Ed Tanous | ee192c0 | 2023-12-13 10:49:58 -0800 | [diff] [blame] | 212 |     // Returns the required output buffer in characters for an input of size | 
 | 213 |     // inputSize | 
 | 214 |     static size_t constexpr encodedSize(size_t inputSize) | 
 | 215 |     { | 
 | 216 |         // Base64 encodes 3 character blocks as 4 character blocks | 
 | 217 |         // With a possibility of 2 trailing = characters | 
 | 218 |         return (inputSize + 2) / 3 * 4; | 
 | 219 |     } | 
 | 220 | }; | 
 | 221 |  | 
 | 222 | inline std::string base64encode(std::string_view data) | 
 | 223 | { | 
 | 224 |     // Encodes a 3 character stream into a 4 character stream | 
 | 225 |     std::string out; | 
 | 226 |     Base64Encoder base64; | 
 | 227 |     out.reserve(Base64Encoder::encodedSize(data.size())); | 
 | 228 |     base64.encode(data, out); | 
 | 229 |     base64.finalize(out); | 
 | 230 |     return out; | 
| Adriana Kobylak | d830ff5 | 2021-01-27 14:15:27 -0600 | [diff] [blame] | 231 | } | 
 | 232 |  | 
| Ed Tanous | 80d2ef3 | 2025-02-04 09:29:02 -0800 | [diff] [blame] | 233 | template <bool urlsafe = false> | 
| Ed Tanous | 26ccae3 | 2023-02-16 10:28:44 -0800 | [diff] [blame] | 234 | inline bool base64Decode(std::string_view input, std::string& output) | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 235 | { | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 236 |     size_t inputLength = input.size(); | 
| Borawski.Lukasz | 9d8fd30 | 2018-01-05 14:56:09 +0100 | [diff] [blame] | 237 |  | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 238 |     // allocate space for output string | 
 | 239 |     output.clear(); | 
 | 240 |     output.reserve(((inputLength + 2) / 3) * 4); | 
| Borawski.Lukasz | 9d8fd30 | 2018-01-05 14:56:09 +0100 | [diff] [blame] | 241 |  | 
| Ed Tanous | 80d2ef3 | 2025-02-04 09:29:02 -0800 | [diff] [blame] | 242 |     static constexpr auto decodingData = getDecodeTable(urlsafe); | 
 | 243 |  | 
| Jonathan Doman | 5beaf84 | 2020-08-14 11:23:33 -0700 | [diff] [blame] | 244 |     auto getCodeValue = [](char c) { | 
 | 245 |         auto code = static_cast<unsigned char>(c); | 
 | 246 |         // Ensure we cannot index outside the bounds of the decoding array | 
| Patrick Williams | bd79bce | 2024-08-16 15:22:20 -0400 | [diff] [blame] | 247 |         static_assert( | 
 | 248 |             std::numeric_limits<decltype(code)>::max() < decodingData.size()); | 
| Jonathan Doman | 5beaf84 | 2020-08-14 11:23:33 -0700 | [diff] [blame] | 249 |         return decodingData[code]; | 
 | 250 |     }; | 
 | 251 |  | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 252 |     // for each 4-bytes sequence from the input, extract 4 6-bits sequences by | 
| Gunnar Mills | caa3ce3 | 2020-07-08 14:46:53 -0500 | [diff] [blame] | 253 |     // dropping first two bits | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 254 |     // and regenerate into 3 8-bits sequences | 
| James Feist | 5a80664 | 2020-07-31 16:40:33 +0000 | [diff] [blame] | 255 |  | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 256 |     for (size_t i = 0; i < inputLength; i++) | 
 | 257 |     { | 
| Ed Tanous | 543f440 | 2022-01-06 13:12:53 -0800 | [diff] [blame] | 258 |         char base64code0 = 0; | 
 | 259 |         char base64code1 = 0; | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 260 |         char base64code2 = 0; // initialized to 0 to suppress warnings | 
| Borawski.Lukasz | 9d8fd30 | 2018-01-05 14:56:09 +0100 | [diff] [blame] | 261 |  | 
| Jonathan Doman | 5beaf84 | 2020-08-14 11:23:33 -0700 | [diff] [blame] | 262 |         base64code0 = getCodeValue(input[i]); | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 263 |         if (base64code0 == nop) | 
| Myung Bae | 41868c6 | 2024-10-09 16:36:49 -0700 | [diff] [blame] | 264 |         { | 
 | 265 |             // non base64 character | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 266 |             return false; | 
 | 267 |         } | 
 | 268 |         if (!(++i < inputLength)) | 
| Myung Bae | 41868c6 | 2024-10-09 16:36:49 -0700 | [diff] [blame] | 269 |         { | 
 | 270 |             // we need at least two input bytes for first byte output | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 271 |             return false; | 
 | 272 |         } | 
| Jonathan Doman | 5beaf84 | 2020-08-14 11:23:33 -0700 | [diff] [blame] | 273 |         base64code1 = getCodeValue(input[i]); | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 274 |         if (base64code1 == nop) | 
| Myung Bae | 41868c6 | 2024-10-09 16:36:49 -0700 | [diff] [blame] | 275 |         { | 
 | 276 |             // non base64 character | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 277 |             return false; | 
 | 278 |         } | 
 | 279 |         output += | 
 | 280 |             static_cast<char>((base64code0 << 2) | ((base64code1 >> 4) & 0x3)); | 
| Borawski.Lukasz | 9d8fd30 | 2018-01-05 14:56:09 +0100 | [diff] [blame] | 281 |  | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 282 |         if (++i < inputLength) | 
 | 283 |         { | 
 | 284 |             char c = input[i]; | 
 | 285 |             if (c == '=') | 
| Myung Bae | 41868c6 | 2024-10-09 16:36:49 -0700 | [diff] [blame] | 286 |             { | 
 | 287 |                 // padding , end of input | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 288 |                 return (base64code1 & 0x0f) == 0; | 
 | 289 |             } | 
| Jonathan Doman | 5beaf84 | 2020-08-14 11:23:33 -0700 | [diff] [blame] | 290 |             base64code2 = getCodeValue(input[i]); | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 291 |             if (base64code2 == nop) | 
| Myung Bae | 41868c6 | 2024-10-09 16:36:49 -0700 | [diff] [blame] | 292 |             { | 
 | 293 |                 // non base64 character | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 294 |                 return false; | 
 | 295 |             } | 
| Patrick Williams | bd79bce | 2024-08-16 15:22:20 -0400 | [diff] [blame] | 296 |             output += static_cast<char>( | 
 | 297 |                 ((base64code1 << 4) & 0xf0) | ((base64code2 >> 2) & 0x0f)); | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 298 |         } | 
 | 299 |  | 
 | 300 |         if (++i < inputLength) | 
 | 301 |         { | 
 | 302 |             char c = input[i]; | 
 | 303 |             if (c == '=') | 
| Myung Bae | 41868c6 | 2024-10-09 16:36:49 -0700 | [diff] [blame] | 304 |             { | 
 | 305 |                 // padding , end of input | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 306 |                 return (base64code2 & 0x03) == 0; | 
 | 307 |             } | 
| Ed Tanous | f8fe53e | 2022-06-30 15:55:45 -0700 | [diff] [blame] | 308 |             char base64code3 = getCodeValue(input[i]); | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 309 |             if (base64code3 == nop) | 
| Myung Bae | 41868c6 | 2024-10-09 16:36:49 -0700 | [diff] [blame] | 310 |             { | 
 | 311 |                 // non base64 character | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 312 |                 return false; | 
 | 313 |             } | 
 | 314 |             output += | 
 | 315 |                 static_cast<char>((((base64code2 << 6) & 0xc0) | base64code3)); | 
 | 316 |         } | 
| Borawski.Lukasz | 9d8fd30 | 2018-01-05 14:56:09 +0100 | [diff] [blame] | 317 |     } | 
 | 318 |  | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 319 |     return true; | 
| Borawski.Lukasz | 9d8fd30 | 2018-01-05 14:56:09 +0100 | [diff] [blame] | 320 | } | 
 | 321 |  | 
| Ed Tanous | 7f8d8fa | 2022-08-19 07:00:38 -0700 | [diff] [blame] | 322 | class OrMorePaths | 
 | 323 | {}; | 
 | 324 |  | 
| Ed Tanous | eae855c | 2021-10-26 11:26:02 -0700 | [diff] [blame] | 325 | template <typename... AV> | 
| Ed Tanous | daadfb2 | 2024-12-20 09:25:54 -0800 | [diff] [blame] | 326 | inline void appendUrlPieces(boost::urls::url& url, AV&&... args) | 
| Willy Tu | c6bcedc | 2022-09-27 05:36:59 +0000 | [diff] [blame] | 327 | { | 
| Ed Tanous | daadfb2 | 2024-12-20 09:25:54 -0800 | [diff] [blame] | 328 |     // Unclear the correct fix here. | 
 | 329 |     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) | 
 | 330 |     for (const std::string_view arg : {args...}) | 
 | 331 |     { | 
 | 332 |         url.segments().push_back(arg); | 
 | 333 |     } | 
| Willy Tu | c6bcedc | 2022-09-27 05:36:59 +0000 | [diff] [blame] | 334 | } | 
 | 335 |  | 
| Szymon Dompke | ca1600c | 2022-03-03 14:42:52 +0100 | [diff] [blame] | 336 | namespace details | 
 | 337 | { | 
 | 338 |  | 
 | 339 | // std::reference_wrapper<std::string> - extracts segment to variable | 
 | 340 | //                    std::string_view - checks if segment is equal to variable | 
| Ed Tanous | 7f8d8fa | 2022-08-19 07:00:38 -0700 | [diff] [blame] | 341 | using UrlSegment = std::variant<std::reference_wrapper<std::string>, | 
 | 342 |                                 std::string_view, OrMorePaths>; | 
 | 343 |  | 
 | 344 | enum class UrlParseResult | 
 | 345 | { | 
 | 346 |     Continue, | 
 | 347 |     Fail, | 
 | 348 |     Done, | 
 | 349 | }; | 
| Szymon Dompke | ca1600c | 2022-03-03 14:42:52 +0100 | [diff] [blame] | 350 |  | 
 | 351 | class UrlSegmentMatcherVisitor | 
 | 352 | { | 
 | 353 |   public: | 
| Ed Tanous | 7f8d8fa | 2022-08-19 07:00:38 -0700 | [diff] [blame] | 354 |     UrlParseResult operator()(std::string& output) | 
| Szymon Dompke | ca1600c | 2022-03-03 14:42:52 +0100 | [diff] [blame] | 355 |     { | 
| Ed Tanous | 079360a | 2022-06-29 10:05:19 -0700 | [diff] [blame] | 356 |         output = segment; | 
| Ed Tanous | 7f8d8fa | 2022-08-19 07:00:38 -0700 | [diff] [blame] | 357 |         return UrlParseResult::Continue; | 
| Szymon Dompke | ca1600c | 2022-03-03 14:42:52 +0100 | [diff] [blame] | 358 |     } | 
 | 359 |  | 
| Ed Tanous | 7f8d8fa | 2022-08-19 07:00:38 -0700 | [diff] [blame] | 360 |     UrlParseResult operator()(std::string_view expected) | 
| Szymon Dompke | ca1600c | 2022-03-03 14:42:52 +0100 | [diff] [blame] | 361 |     { | 
| Ed Tanous | 079360a | 2022-06-29 10:05:19 -0700 | [diff] [blame] | 362 |         if (segment == expected) | 
| Ed Tanous | 7f8d8fa | 2022-08-19 07:00:38 -0700 | [diff] [blame] | 363 |         { | 
 | 364 |             return UrlParseResult::Continue; | 
 | 365 |         } | 
 | 366 |         return UrlParseResult::Fail; | 
 | 367 |     } | 
 | 368 |  | 
 | 369 |     UrlParseResult operator()(OrMorePaths /*unused*/) | 
 | 370 |     { | 
 | 371 |         return UrlParseResult::Done; | 
| Szymon Dompke | ca1600c | 2022-03-03 14:42:52 +0100 | [diff] [blame] | 372 |     } | 
 | 373 |  | 
| Ed Tanous | 079360a | 2022-06-29 10:05:19 -0700 | [diff] [blame] | 374 |     explicit UrlSegmentMatcherVisitor(std::string_view segmentIn) : | 
| Szymon Dompke | ca1600c | 2022-03-03 14:42:52 +0100 | [diff] [blame] | 375 |         segment(segmentIn) | 
 | 376 |     {} | 
 | 377 |  | 
 | 378 |   private: | 
| Ed Tanous | 079360a | 2022-06-29 10:05:19 -0700 | [diff] [blame] | 379 |     std::string_view segment; | 
| Szymon Dompke | ca1600c | 2022-03-03 14:42:52 +0100 | [diff] [blame] | 380 | }; | 
 | 381 |  | 
| Ed Tanous | 4a7fbef | 2024-04-06 16:03:49 -0700 | [diff] [blame] | 382 | inline bool readUrlSegments(const boost::urls::url_view_base& url, | 
| Ed Tanous | 5be2b14 | 2024-03-27 15:27:04 -0700 | [diff] [blame] | 383 |                             std::initializer_list<UrlSegment> segments) | 
| Szymon Dompke | ca1600c | 2022-03-03 14:42:52 +0100 | [diff] [blame] | 384 | { | 
| Ed Tanous | 4a7fbef | 2024-04-06 16:03:49 -0700 | [diff] [blame] | 385 |     const boost::urls::segments_view& urlSegments = url.segments(); | 
| Szymon Dompke | ca1600c | 2022-03-03 14:42:52 +0100 | [diff] [blame] | 386 |  | 
| Ed Tanous | 7f8d8fa | 2022-08-19 07:00:38 -0700 | [diff] [blame] | 387 |     if (!urlSegments.is_absolute()) | 
| Szymon Dompke | ca1600c | 2022-03-03 14:42:52 +0100 | [diff] [blame] | 388 |     { | 
 | 389 |         return false; | 
 | 390 |     } | 
 | 391 |  | 
| Ed Tanous | 4a7fbef | 2024-04-06 16:03:49 -0700 | [diff] [blame] | 392 |     boost::urls::segments_view::const_iterator it = urlSegments.begin(); | 
 | 393 |     boost::urls::segments_view::const_iterator end = urlSegments.end(); | 
| Szymon Dompke | ca1600c | 2022-03-03 14:42:52 +0100 | [diff] [blame] | 394 |  | 
 | 395 |     for (const auto& segment : segments) | 
 | 396 |     { | 
| Ed Tanous | 7f8d8fa | 2022-08-19 07:00:38 -0700 | [diff] [blame] | 397 |         if (it == end) | 
 | 398 |         { | 
 | 399 |             // If the request ends with an "any" path, this was successful | 
 | 400 |             return std::holds_alternative<OrMorePaths>(segment); | 
 | 401 |         } | 
 | 402 |         UrlParseResult res = std::visit(UrlSegmentMatcherVisitor(*it), segment); | 
 | 403 |         if (res == UrlParseResult::Done) | 
 | 404 |         { | 
 | 405 |             return true; | 
 | 406 |         } | 
 | 407 |         if (res == UrlParseResult::Fail) | 
| Szymon Dompke | ca1600c | 2022-03-03 14:42:52 +0100 | [diff] [blame] | 408 |         { | 
 | 409 |             return false; | 
 | 410 |         } | 
 | 411 |         it++; | 
 | 412 |     } | 
| Carson Labrado | 4c30e22 | 2022-06-24 22:16:00 +0000 | [diff] [blame] | 413 |  | 
 | 414 |     // There will be an empty segment at the end if the URI ends with a "/" | 
 | 415 |     // e.g. /redfish/v1/Chassis/ | 
 | 416 |     if ((it != end) && urlSegments.back().empty()) | 
 | 417 |     { | 
 | 418 |         it++; | 
 | 419 |     } | 
| Ed Tanous | 7f8d8fa | 2022-08-19 07:00:38 -0700 | [diff] [blame] | 420 |     return it == end; | 
| Szymon Dompke | ca1600c | 2022-03-03 14:42:52 +0100 | [diff] [blame] | 421 | } | 
 | 422 |  | 
 | 423 | } // namespace details | 
 | 424 |  | 
 | 425 | template <typename... Args> | 
| Ed Tanous | 4a7fbef | 2024-04-06 16:03:49 -0700 | [diff] [blame] | 426 | inline bool readUrlSegments(const boost::urls::url_view_base& url, | 
 | 427 |                             Args&&... args) | 
| Szymon Dompke | ca1600c | 2022-03-03 14:42:52 +0100 | [diff] [blame] | 428 | { | 
| Ed Tanous | 39662a3 | 2023-02-06 15:09:46 -0800 | [diff] [blame] | 429 |     return details::readUrlSegments(url, {std::forward<Args>(args)...}); | 
| Szymon Dompke | ca1600c | 2022-03-03 14:42:52 +0100 | [diff] [blame] | 430 | } | 
 | 431 |  | 
| Patrick Williams | 504af5a | 2025-02-03 14:29:03 -0500 | [diff] [blame] | 432 | inline boost::urls::url replaceUrlSegment( | 
 | 433 |     const boost::urls::url_view_base& urlView, const uint replaceLoc, | 
 | 434 |     std::string_view newSegment) | 
| Carson Labrado | 1c0bb5c | 2022-05-18 00:12:52 +0000 | [diff] [blame] | 435 | { | 
| Ed Tanous | 4a7fbef | 2024-04-06 16:03:49 -0700 | [diff] [blame] | 436 |     const boost::urls::segments_view& urlSegments = urlView.segments(); | 
| Carson Labrado | 1c0bb5c | 2022-05-18 00:12:52 +0000 | [diff] [blame] | 437 |     boost::urls::url url("/"); | 
 | 438 |  | 
 | 439 |     if (!urlSegments.is_absolute()) | 
 | 440 |     { | 
 | 441 |         return url; | 
 | 442 |     } | 
 | 443 |  | 
 | 444 |     boost::urls::segments_view::iterator it = urlSegments.begin(); | 
 | 445 |     boost::urls::segments_view::iterator end = urlSegments.end(); | 
 | 446 |  | 
 | 447 |     for (uint idx = 0; it != end; it++, idx++) | 
 | 448 |     { | 
 | 449 |         if (idx == replaceLoc) | 
 | 450 |         { | 
 | 451 |             url.segments().push_back(newSegment); | 
 | 452 |         } | 
 | 453 |         else | 
 | 454 |         { | 
 | 455 |             url.segments().push_back(*it); | 
 | 456 |         } | 
 | 457 |     } | 
 | 458 |  | 
 | 459 |     return url; | 
 | 460 | } | 
 | 461 |  | 
| Ed Tanous | a716aa7 | 2023-08-01 11:35:53 -0700 | [diff] [blame] | 462 | inline void setProtocolDefaults(boost::urls::url& url, | 
 | 463 |                                 std::string_view protocol) | 
| Ed Tanous | eb1c47d | 2022-02-09 11:47:27 -0800 | [diff] [blame] | 464 | { | 
| Ed Tanous | a716aa7 | 2023-08-01 11:35:53 -0700 | [diff] [blame] | 465 |     if (url.has_scheme()) | 
| Ed Tanous | eb1c47d | 2022-02-09 11:47:27 -0800 | [diff] [blame] | 466 |     { | 
| Ed Tanous | a716aa7 | 2023-08-01 11:35:53 -0700 | [diff] [blame] | 467 |         return; | 
| Ed Tanous | eb1c47d | 2022-02-09 11:47:27 -0800 | [diff] [blame] | 468 |     } | 
| Ed Tanous | a716aa7 | 2023-08-01 11:35:53 -0700 | [diff] [blame] | 469 |     if (protocol == "Redfish" || protocol.empty()) | 
| Ed Tanous | eb1c47d | 2022-02-09 11:47:27 -0800 | [diff] [blame] | 470 |     { | 
| Ed Tanous | a716aa7 | 2023-08-01 11:35:53 -0700 | [diff] [blame] | 471 |         if (url.port_number() == 443) | 
| Ed Tanous | eb1c47d | 2022-02-09 11:47:27 -0800 | [diff] [blame] | 472 |         { | 
| Ed Tanous | a716aa7 | 2023-08-01 11:35:53 -0700 | [diff] [blame] | 473 |             url.set_scheme("https"); | 
| Ed Tanous | eb1c47d | 2022-02-09 11:47:27 -0800 | [diff] [blame] | 474 |         } | 
| Ed Tanous | a716aa7 | 2023-08-01 11:35:53 -0700 | [diff] [blame] | 475 |         if (url.port_number() == 80) | 
 | 476 |         { | 
| Ed Tanous | 25b54db | 2024-04-17 15:40:31 -0700 | [diff] [blame] | 477 |             if constexpr (BMCWEB_INSECURE_PUSH_STYLE_NOTIFICATION) | 
| Ed Tanous | a716aa7 | 2023-08-01 11:35:53 -0700 | [diff] [blame] | 478 |             { | 
 | 479 |                 url.set_scheme("http"); | 
 | 480 |             } | 
 | 481 |         } | 
| Ed Tanous | eb1c47d | 2022-02-09 11:47:27 -0800 | [diff] [blame] | 482 |     } | 
| Ed Tanous | a716aa7 | 2023-08-01 11:35:53 -0700 | [diff] [blame] | 483 |     else if (protocol == "SNMPv2c") | 
| Chicago Duan | 3d30708 | 2020-11-26 14:12:12 +0800 | [diff] [blame] | 484 |     { | 
| Ed Tanous | a716aa7 | 2023-08-01 11:35:53 -0700 | [diff] [blame] | 485 |         url.set_scheme("snmp"); | 
| Chicago Duan | 3d30708 | 2020-11-26 14:12:12 +0800 | [diff] [blame] | 486 |     } | 
| Ed Tanous | eb1c47d | 2022-02-09 11:47:27 -0800 | [diff] [blame] | 487 | } | 
 | 488 |  | 
| Ed Tanous | a716aa7 | 2023-08-01 11:35:53 -0700 | [diff] [blame] | 489 | inline void setPortDefaults(boost::urls::url& url) | 
| Ed Tanous | eb1c47d | 2022-02-09 11:47:27 -0800 | [diff] [blame] | 490 | { | 
 | 491 |     uint16_t port = url.port_number(); | 
 | 492 |     if (port != 0) | 
 | 493 |     { | 
| Ed Tanous | a716aa7 | 2023-08-01 11:35:53 -0700 | [diff] [blame] | 494 |         return; | 
| Ed Tanous | eb1c47d | 2022-02-09 11:47:27 -0800 | [diff] [blame] | 495 |     } | 
 | 496 |  | 
 | 497 |     // If the user hasn't explicitly stated a port, pick one explicitly for them | 
 | 498 |     // based on the protocol defaults | 
 | 499 |     if (url.scheme() == "http") | 
 | 500 |     { | 
| Ed Tanous | a716aa7 | 2023-08-01 11:35:53 -0700 | [diff] [blame] | 501 |         url.set_port_number(80); | 
| Ed Tanous | eb1c47d | 2022-02-09 11:47:27 -0800 | [diff] [blame] | 502 |     } | 
 | 503 |     if (url.scheme() == "https") | 
 | 504 |     { | 
| Ed Tanous | a716aa7 | 2023-08-01 11:35:53 -0700 | [diff] [blame] | 505 |         url.set_port_number(443); | 
| Ed Tanous | eb1c47d | 2022-02-09 11:47:27 -0800 | [diff] [blame] | 506 |     } | 
| Chicago Duan | 3d30708 | 2020-11-26 14:12:12 +0800 | [diff] [blame] | 507 |     if (url.scheme() == "snmp") | 
 | 508 |     { | 
| Ed Tanous | a716aa7 | 2023-08-01 11:35:53 -0700 | [diff] [blame] | 509 |         url.set_port_number(162); | 
| Chicago Duan | 3d30708 | 2020-11-26 14:12:12 +0800 | [diff] [blame] | 510 |     } | 
| Ed Tanous | 11baefe | 2022-02-09 12:14:12 -0800 | [diff] [blame] | 511 | } | 
 | 512 |  | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 513 | } // namespace utility | 
 | 514 | } // namespace crow | 
| Ed Tanous | 71f2db7 | 2022-05-25 12:28:09 -0700 | [diff] [blame] | 515 |  | 
 | 516 | namespace nlohmann | 
 | 517 | { | 
| Ed Tanous | 4a7fbef | 2024-04-06 16:03:49 -0700 | [diff] [blame] | 518 | template <std::derived_from<boost::urls::url_view_base> URL> | 
 | 519 | struct adl_serializer<URL> | 
| Ed Tanous | 71f2db7 | 2022-05-25 12:28:09 -0700 | [diff] [blame] | 520 | { | 
 | 521 |     // NOLINTNEXTLINE(readability-identifier-naming) | 
| Ed Tanous | 4a7fbef | 2024-04-06 16:03:49 -0700 | [diff] [blame] | 522 |     static void to_json(json& j, const URL& url) | 
| Ed Tanous | 71f2db7 | 2022-05-25 12:28:09 -0700 | [diff] [blame] | 523 |     { | 
| Ed Tanous | 079360a | 2022-06-29 10:05:19 -0700 | [diff] [blame] | 524 |         j = url.buffer(); | 
| Ed Tanous | 71f2db7 | 2022-05-25 12:28:09 -0700 | [diff] [blame] | 525 |     } | 
 | 526 | }; | 
 | 527 | } // namespace nlohmann |