Skip to content

Commit 165c37f

Browse files
authored
Refactored percent encoding, using std::byte which is more appropriate (#139)
1 parent ceb2239 commit 165c37f

File tree

8 files changed

+123
-88
lines changed

8 files changed

+123
-88
lines changed

include/skyr/v1/percent_encoding/percent_decode.hpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,4 @@ inline auto percent_decode(std::string_view input) -> tl::expected<std::string,
3030
} // namespace v1
3131
} // namespace skyr
3232

33-
#endif //SKYR_V1_PERCENT_DECODING_PERCENT_DECODE_HPP
33+
#endif // SKYR_V1_PERCENT_DECODING_PERCENT_DECODE_HPP

include/skyr/v1/percent_encoding/percent_decode_range.hpp

+17-16
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,17 @@ namespace skyr {
1717
inline namespace v1 {
1818
namespace percent_encoding {
1919
namespace details {
20-
inline auto letter_to_hex(char byte) noexcept -> tl::expected<char, percent_encode_errc> {
21-
if ((byte >= '0') && (byte <= '9')) {
22-
return static_cast<char>(byte - '0');
20+
inline auto alnum_to_hex(char value) noexcept -> tl::expected<std::byte, percent_encode_errc> {
21+
if ((value >= '0') && (value <= '9')) {
22+
return static_cast<std::byte>(value - '0');
2323
}
2424

25-
if ((byte >= 'a') && (byte <= 'f')) {
26-
return static_cast<char>(byte + '\x0a' - 'a');
25+
if ((value >= 'a') && (value <= 'f')) {
26+
return static_cast<std::byte>(value + '\x0a' - 'a');
2727
}
2828

29-
if ((byte >= 'A') && (byte <= 'F')) {
30-
return static_cast<char>(byte + '\x0a' - 'A');
29+
if ((value >= 'A') && (value <= 'F')) {
30+
return static_cast<std::byte>(value + '\x0a' - 'A');
3131
}
3232

3333
return tl::make_unexpected(percent_encoding::percent_encode_errc::non_hex_input);
@@ -86,14 +86,15 @@ class percent_decode_iterator {
8686
if (remainder_.size() < 3) {
8787
return tl::make_unexpected(percent_encoding::percent_encode_errc::overflow);
8888
}
89-
auto v0 = details::letter_to_hex(remainder_[1]);
90-
auto v1 = details::letter_to_hex(remainder_[2]);
89+
auto v0 = details::alnum_to_hex(remainder_[1]);
90+
auto v1 = details::alnum_to_hex(remainder_[2]);
9191

9292
if (!v0 || !v1) {
9393
return tl::make_unexpected(percent_encoding::percent_encode_errc::non_hex_input);
9494
}
9595

96-
return static_cast<char>((0x10u * v0.value()) + v1.value());
96+
return static_cast<char>(
97+
(0x10u * std::to_integer<unsigned int>(v0.value())) + std::to_integer<unsigned int>(v1.value()));
9798
} else {
9899
return remainder_[0];
99100
}
@@ -145,26 +146,26 @@ class percent_decode_range {
145146

146147
///
147148
/// \return
148-
[[nodiscard]] auto begin() const noexcept {
149+
[[nodiscard]] auto cbegin() const noexcept {
149150
return it_;
150151
}
151152

152153
///
153154
/// \return
154-
[[nodiscard]] auto end() const noexcept {
155+
[[nodiscard]] auto cend() const noexcept {
155156
return sentinel{};
156157
}
157158

158159
///
159160
/// \return
160-
[[nodiscard]] auto cbegin() const noexcept {
161-
return begin();
161+
[[nodiscard]] auto begin() const noexcept {
162+
return cbegin();
162163
}
163164

164165
///
165166
/// \return
166-
[[nodiscard]] auto cend() const noexcept {
167-
return end();
167+
[[nodiscard]] auto end() const noexcept {
168+
return cend();
168169
}
169170

170171
///

include/skyr/v1/percent_encoding/percent_encode.hpp

+6-6
Original file line numberDiff line numberDiff line change
@@ -19,20 +19,20 @@ inline auto percent_encode(std::string_view input) {
1919
using percent_encoding::percent_encoded_char;
2020

2121
static constexpr auto encode = [] (auto byte) {
22-
if (byte == '\x20') {
23-
return percent_encoded_char('+', percent_encoded_char::no_encode());
24-
} else if ((byte == '\x2a') || (byte == '\x2d') || (byte == '\x2e') ||
22+
if ((byte == '\x2a') || (byte == '\x2d') || (byte == '\x2e') ||
2523
((byte >= '\x30') && (byte <= '\x39')) ||
2624
((byte >= '\x41') && (byte <= '\x5a')) || (byte == '\x5f') ||
2725
((byte >= '\x61') && (byte <= '\x7a'))) {
2826
return percent_encoded_char(
29-
byte, percent_encoded_char::no_encode());
27+
std::byte(byte), percent_encoded_char::no_encode());
28+
} else if (byte == '\x20') {
29+
return percent_encoded_char(std::byte('+'), percent_encoded_char::no_encode());
3030
}
31-
return percent_encoded_char(byte);
31+
return percent_encoded_char(std::byte(byte));
3232
};
3333

3434
auto result = std::string{};
35-
for (auto encoded : input | ranges::views::transform(encode)) {
35+
for (const auto &encoded : input | ranges::views::transform(encode)) {
3636
result += std::string(std::cbegin(encoded), std::cend(encoded));
3737
}
3838
return result;

include/skyr/v1/percent_encoding/percent_encoded_char.hpp

+81-52
Original file line numberDiff line numberDiff line change
@@ -8,59 +8,75 @@
88

99
#include <string>
1010
#include <locale>
11+
#include <cstddef>
1112

1213
namespace skyr {
1314
inline namespace v1 {
1415
namespace percent_encoding {
1516
namespace details {
16-
inline constexpr auto hex_to_letter(char byte) noexcept {
17-
if ((byte >= '\x00') && (byte < '\x0a')) {
18-
return static_cast<char>(byte + '0');
17+
///
18+
/// \param value
19+
/// \return
20+
inline constexpr auto hex_to_alnum(std::byte value) noexcept {
21+
if ((value >= std::byte(0x00)) && (value < std::byte(0x0a))) {
22+
return static_cast<char>(std::to_integer<unsigned>(value) + '0');
1923
}
2024

21-
if ((byte >= '\x0a') && (byte < '\x10')) {
22-
return static_cast<char>(byte - '\x0a' + 'A');
25+
if ((value >= std::byte(0x0a)) && (value < std::byte(0x10))) {
26+
return static_cast<char>(std::to_integer<unsigned>(value) - '\x0a' + 'A');
2327
}
2428

25-
return byte;
29+
return static_cast<char>(value);
2630
}
2731

28-
inline constexpr auto is_c0_control_byte(char byte) noexcept {
29-
return (byte <= '\x1f') || (byte > '\x7e');
32+
///
33+
/// \param value
34+
/// \return
35+
inline constexpr auto is_c0_control_byte(std::byte value) noexcept {
36+
return (value <= std::byte(0x1f)) || (value > std::byte(0x7e));
3037
}
3138

32-
inline constexpr auto is_fragment_byte(char byte) {
39+
///
40+
/// \param value
41+
/// \return
42+
inline constexpr auto is_fragment_byte(std::byte value) {
3343
return
34-
is_c0_control_byte(byte) ||
35-
(byte == '\x20') ||
36-
(byte == '\x22') ||
37-
(byte == '\x3c') ||
38-
(byte == '\x3e') ||
39-
(byte == '\x60');
44+
is_c0_control_byte(value) ||
45+
(value == std::byte(0x20)) ||
46+
(value == std::byte(0x22)) ||
47+
(value == std::byte(0x3c)) ||
48+
(value == std::byte(0x3e)) ||
49+
(value == std::byte(0x60));
4050
}
4151

42-
inline constexpr auto is_path_byte(char byte) {
52+
///
53+
/// \param value
54+
/// \return
55+
inline constexpr auto is_path_byte(std::byte value) {
4356
return
44-
is_fragment_byte(byte) ||
45-
(byte == '\x23') ||
46-
(byte == '\x3f') ||
47-
(byte == '\x7b') ||
48-
(byte == '\x7d');
57+
is_fragment_byte(value) ||
58+
(value == std::byte(0x23)) ||
59+
(value == std::byte(0x3f)) ||
60+
(value == std::byte(0x7b)) ||
61+
(value == std::byte(0x7d));
4962
}
5063

51-
inline constexpr auto is_userinfo_byte(char byte) {
64+
///
65+
/// \param value
66+
/// \return
67+
inline constexpr auto is_userinfo_byte(std::byte value) {
5268
return
53-
is_path_byte(byte) ||
54-
(byte == '\x2f') ||
55-
(byte == '\x3a') ||
56-
(byte == '\x3b') ||
57-
(byte == '\x3d') ||
58-
(byte == '\x40') ||
59-
(byte == '\x5b') ||
60-
(byte == '\x5c') ||
61-
(byte == '\x5d') ||
62-
(byte == '\x5e') ||
63-
(byte == '\x7c');
69+
is_path_byte(value) ||
70+
(value == std::byte(0x2f)) ||
71+
(value == std::byte(0x3a)) ||
72+
(value == std::byte(0x3b)) ||
73+
(value == std::byte(0x3d)) ||
74+
(value == std::byte(0x40)) ||
75+
(value == std::byte(0x5b)) ||
76+
(value == std::byte(0x5c)) ||
77+
(value == std::byte(0x5d)) ||
78+
(value == std::byte(0x5e)) ||
79+
(value == std::byte(0x7c));
6480
}
6581
} // namespace details
6682

@@ -83,6 +99,8 @@ struct percent_encoded_char {
8399

84100
using impl_type = std::string;
85101

102+
static constexpr std::byte mask = std::byte(0x0f);
103+
86104
public:
87105

88106
///
@@ -101,27 +119,38 @@ struct percent_encoded_char {
101119
percent_encoded_char() = default;
102120

103121
///
104-
/// \param byte
105-
percent_encoded_char(char byte, no_encode)
106-
: impl_{byte} {}
122+
/// \param value
123+
percent_encoded_char(std::byte value, no_encode)
124+
: impl_{static_cast<char>(value)} {}
125+
107126
///
108-
/// \param byte
109-
explicit percent_encoded_char(char byte)
127+
/// \param value
128+
explicit percent_encoded_char(std::byte value)
110129
: impl_{
111-
'%',
112-
details::hex_to_letter(static_cast<char>((static_cast<unsigned>(byte) >> 4u) & 0x0fu)),
113-
details::hex_to_letter(static_cast<char>(static_cast<unsigned>(byte) & 0x0fu))} {}
130+
'%', details::hex_to_alnum((value >> 4u) & mask), details::hex_to_alnum(value & mask)} {}
131+
132+
///
133+
/// \return
134+
[[nodiscard]] auto cbegin() const noexcept {
135+
return impl_.cbegin();
136+
}
137+
138+
///
139+
/// \return
140+
[[nodiscard]] auto cend() const noexcept {
141+
return impl_.cend();
142+
}
114143

115144
///
116145
/// \return
117146
[[nodiscard]] auto begin() const noexcept {
118-
return impl_.begin();
147+
return cbegin();
119148
}
120149

121150
///
122151
/// \return
123152
[[nodiscard]] auto end() const noexcept {
124-
return impl_.end();
153+
return cend();
125154
}
126155

127156
///
@@ -160,7 +189,7 @@ struct percent_encoded_char {
160189
/// \param pred
161190
/// \return
162191
template <class Pred>
163-
inline auto percent_encode_byte(char byte, Pred pred) -> percent_encoded_char {
192+
inline auto percent_encode_byte(std::byte byte, Pred pred) -> percent_encoded_char {
164193
if (pred(byte)) {
165194
return percent_encoding::percent_encoded_char(byte);
166195
}
@@ -169,23 +198,23 @@ inline auto percent_encode_byte(char byte, Pred pred) -> percent_encoded_char {
169198
}
170199

171200
///
172-
/// \param byte
201+
/// \param value
173202
/// \param excludes
174203
/// \return
175-
inline auto percent_encode_byte(char byte, encode_set excludes) -> percent_encoded_char {
204+
inline auto percent_encode_byte(std::byte value, encode_set excludes) -> percent_encoded_char {
176205
switch (excludes) {
177206
case encode_set::none:
178-
return percent_encoding::percent_encoded_char(byte);
207+
return percent_encoding::percent_encoded_char(value);
179208
case encode_set::c0_control:
180-
return percent_encode_byte(byte, details::is_c0_control_byte);
209+
return percent_encode_byte(value, details::is_c0_control_byte);
181210
case encode_set::userinfo:
182-
return percent_encode_byte(byte, details::is_userinfo_byte);
211+
return percent_encode_byte(value, details::is_userinfo_byte);
183212
case encode_set::path:
184-
return percent_encode_byte(byte, details::is_path_byte);
213+
return percent_encode_byte(value, details::is_path_byte);
185214
case encode_set::fragment:
186-
return percent_encode_byte(byte, details::is_fragment_byte);
215+
return percent_encode_byte(value, details::is_fragment_byte);
187216
}
188-
return percent_encoding::percent_encoded_char(byte);
217+
return percent_encoding::percent_encoded_char(value);
189218
}
190219

191220
/// Tests whether the input string contains percent encoded values

src/v1/core/host.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ auto parse_opaque_host(std::string_view input,
4040

4141
auto output = std::string();
4242
for (auto c : input) {
43-
auto pct_encoded = percent_encode_byte(c, percent_encoding::encode_set::c0_control);
43+
auto pct_encoded = percent_encode_byte(std::byte(c), percent_encoding::encode_set::c0_control);
4444
output += pct_encoded.to_string();
4545
}
4646
return skyr::v1::opaque_host{output};

src/v1/core/url_parser_context.cpp

+5-5
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,7 @@ auto url_parser_context::parse_authority(char byte) -> tl::expected<url_parse_ac
362362
continue;
363363
}
364364

365-
auto pct_encoded = percent_encode_byte(c, percent_encoding::encode_set::userinfo);
365+
auto pct_encoded = percent_encode_byte(std::byte(c), percent_encoding::encode_set::userinfo);
366366
if (password_token_seen_flag) {
367367
url.password += pct_encoded.to_string();
368368
} else {
@@ -698,7 +698,7 @@ auto url_parser_context::parse_path(char byte) -> tl::expected<url_parse_action,
698698
*validation_error |= true;
699699
}
700700

701-
auto pct_encoded = percent_encode_byte(byte, percent_encoding::encode_set::path);
701+
auto pct_encoded = percent_encode_byte(std::byte(byte), percent_encoding::encode_set::path);
702702
buffer += pct_encoded.to_string();
703703
}
704704

@@ -721,7 +721,7 @@ auto url_parser_context::parse_cannot_be_a_base_url(char byte) -> tl::expected<u
721721
*validation_error |= true;
722722
}
723723
if (!is_eof()) {
724-
auto pct_encoded = percent_encode_byte(byte, percent_encoding::encode_set::c0_control);
724+
auto pct_encoded = percent_encode_byte(std::byte(byte), percent_encoding::encode_set::c0_control);
725725
url.path[0] += pct_encoded.to_string();
726726
}
727727
}
@@ -737,7 +737,7 @@ auto url_parser_context::parse_query(char byte) -> tl::expected<url_parse_action
737737
(byte > '~') ||
738738
(contains(byte, R"("#<>)"sv)) ||
739739
((byte == '\'') && url.is_special())) {
740-
auto pct_encoded = percent_encode_byte(byte, percent_encoding::encode_set::none);
740+
auto pct_encoded = percent_encode_byte(std::byte(byte), percent_encoding::encode_set::none);
741741
url.query.value() += pct_encoded.to_string();
742742
} else {
743743
url.query.value().push_back(byte);
@@ -757,7 +757,7 @@ auto url_parser_context::parse_fragment(char byte) -> tl::expected<url_parse_act
757757
*validation_error |= true;
758758
}
759759

760-
auto pct_encoded = percent_encode_byte(byte, percent_encoding::encode_set::fragment);
760+
auto pct_encoded = percent_encode_byte(std::byte(byte), percent_encoding::encode_set::fragment);
761761
url.fragment.value() += pct_encoded.to_string();
762762
}
763763
return url_parse_action::increment;

src/v1/url/url.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ auto url::set_username(string_view username) -> std::error_code {
8484

8585
new_url.username.clear();
8686
for (auto c : username) {
87-
auto pct_encoded = percent_encode_byte(c, percent_encoding::encode_set::userinfo);
87+
auto pct_encoded = percent_encode_byte(std::byte(c), percent_encoding::encode_set::userinfo);
8888
new_url.username += pct_encoded.to_string();
8989
}
9090

@@ -102,7 +102,7 @@ auto url::set_password(string_view password) -> std::error_code {
102102

103103
new_url.password.clear();
104104
for (auto c : password) {
105-
auto pct_encoded = percent_encode_byte(c, percent_encoding::encode_set::userinfo);
105+
auto pct_encoded = percent_encode_byte(std::byte(c), percent_encoding::encode_set::userinfo);
106106
new_url.password += pct_encoded.to_string();
107107
}
108108

0 commit comments

Comments
 (0)