| 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 |