Skip to content

Commit 9a67015

Browse files
authored
Upgrade percent encoding (#155)
* Updated percent encoding functions based on updates to the URL standard * Minor fixes based on feedback from clang-tidy * Simplified existing percent encoding functions
1 parent b1e5776 commit 9a67015

File tree

13 files changed

+228
-77
lines changed

13 files changed

+228
-77
lines changed

include/skyr/v1/percent_encoding/percent_encode.hpp

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,21 +14,11 @@
1414
namespace skyr {
1515
inline namespace v1 {
1616
/// Percent encodes the input
17-
/// \returns The percent encoded output when successful, an error otherwise.
18-
inline auto percent_encode(std::string_view input) {
19-
using percent_encoding::percent_encoded_char;
20-
17+
/// \returns The percent encoded output.
18+
inline auto percent_encode(std::string_view input) -> std::string {
2119
static constexpr auto encode = [] (auto byte) {
22-
if ((byte == '\x2a') || (byte == '\x2d') || (byte == '\x2e') ||
23-
((byte >= '\x30') && (byte <= '\x39')) ||
24-
((byte >= '\x41') && (byte <= '\x5a')) || (byte == '\x5f') ||
25-
((byte >= '\x61') && (byte <= '\x7a'))) {
26-
return percent_encoded_char(
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());
30-
}
31-
return percent_encoded_char(std::byte(byte));
20+
using percent_encoding::percent_encode_byte;
21+
return percent_encode_byte(std::byte(byte), percent_encoding::encode_set::component);
3222
};
3323

3424
auto result = std::string{};

include/skyr/v1/percent_encoding/percent_encoded_char.hpp

Lines changed: 54 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,33 @@ inline constexpr auto is_fragment_byte(std::byte value) {
5252
///
5353
/// \param value
5454
/// \return
55-
inline constexpr auto is_path_byte(std::byte value) {
55+
inline constexpr auto is_query_byte(std::byte value) {
5656
return
57-
is_fragment_byte(value) ||
57+
is_c0_control_byte(value) ||
58+
(value == std::byte(0x20)) ||
59+
(value == std::byte(0x22)) ||
5860
(value == std::byte(0x23)) ||
61+
(value == std::byte(0x3c)) ||
62+
(value == std::byte(0x3e));
63+
}
64+
65+
///
66+
/// \param value
67+
/// \return
68+
inline constexpr auto is_special_query_byte(std::byte value) {
69+
return
70+
is_query_byte(value) ||
71+
(value == std::byte(0x27));
72+
}
73+
74+
///
75+
/// \param value
76+
/// \return
77+
inline constexpr auto is_path_byte(std::byte value) {
78+
return
79+
is_query_byte(value) ||
5980
(value == std::byte(0x3f)) ||
81+
(value == std::byte(0x60)) ||
6082
(value == std::byte(0x7b)) ||
6183
(value == std::byte(0x7d));
6284
}
@@ -78,20 +100,39 @@ inline constexpr auto is_userinfo_byte(std::byte value) {
78100
(value == std::byte(0x5e)) ||
79101
(value == std::byte(0x7c));
80102
}
103+
104+
///
105+
/// \param value
106+
/// \return
107+
inline constexpr auto is_component_byte(std::byte value) {
108+
return
109+
is_userinfo_byte(value) ||
110+
(value == std::byte(0x24)) ||
111+
(value == std::byte(0x25)) ||
112+
(value == std::byte(0x26)) ||
113+
(value == std::byte(0x2b)) ||
114+
(value == std::byte(0x2c));
115+
}
81116
} // namespace details
82117

83118
///
84119
enum class encode_set {
85120
///
86-
none = 0,
121+
any = 0,
87122
///
88123
c0_control,
89124
///
90125
fragment,
91126
///
127+
query,
128+
///
129+
special_query,
130+
///
92131
path,
93132
///
94133
userinfo,
134+
///
135+
component,
95136
};
96137

97138
///
@@ -199,18 +240,24 @@ inline auto percent_encode_byte(std::byte byte, Pred pred) -> percent_encoded_ch
199240

200241
///
201242
/// \param value
202-
/// \param excludes
243+
/// \param encodes
203244
/// \return
204-
inline auto percent_encode_byte(std::byte value, encode_set excludes) -> percent_encoded_char {
205-
switch (excludes) {
206-
case encode_set::none:
245+
inline auto percent_encode_byte(std::byte value, encode_set encodes) -> percent_encoded_char {
246+
switch (encodes) {
247+
case encode_set::any:
207248
return percent_encoding::percent_encoded_char(value);
208249
case encode_set::c0_control:
209250
return percent_encode_byte(value, details::is_c0_control_byte);
251+
case encode_set::component:
252+
return percent_encode_byte(value, details::is_component_byte);
210253
case encode_set::userinfo:
211254
return percent_encode_byte(value, details::is_userinfo_byte);
212255
case encode_set::path:
213256
return percent_encode_byte(value, details::is_path_byte);
257+
case encode_set::special_query:
258+
return percent_encode_byte(value, details::is_special_query_byte);
259+
case encode_set::query:
260+
return percent_encode_byte(value, details::is_query_byte);
214261
case encode_set::fragment:
215262
return percent_encode_byte(value, details::is_fragment_byte);
216263
}

include/skyr/v2/core/parse_path.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ inline auto parse_path(
1919
std::string_view path, bool *validation_error) -> tl::expected<std::vector<std::string>, url_parse_errc> {
2020
auto url = details::basic_parse(path, validation_error, nullptr, nullptr, url_parse_state::path_start);
2121
if (url) {
22-
return url.value().path;
22+
return std::move(url.value()).path;
2323
}
2424
return tl::make_unexpected(url.error());
2525
}

include/skyr/v2/core/parse_query.hpp

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
#include <range/v3/view/split_when.hpp>
1212
#include <range/v3/view/transform.hpp>
1313
#include <skyr/v2/core/parse.hpp>
14-
#include <skyr/v2/percent_encoding/percent_decode.hpp>
1514

1615
namespace skyr::inline v2 {
1716
///
@@ -46,17 +45,17 @@ inline auto parse_query(
4645
if (url) {
4746
static constexpr auto is_separator = [](auto c) { return c == '&' || c == ';'; };
4847

49-
static constexpr auto to_nvp = [](auto &&param) -> query_parameter {
50-
if (ranges::empty(param)) {
48+
static constexpr auto to_nvp = [](auto &&parameter) -> query_parameter {
49+
if (ranges::empty(parameter)) {
5150
return {};
5251
}
5352

54-
auto element = std::string_view(std::addressof(*std::begin(param)), ranges::distance(param));
55-
auto delim = element.find_first_of('=');
53+
auto view = std::string_view(std::addressof(*std::begin(parameter)), ranges::distance(parameter));
54+
auto delim = view.find_first_of('=');
5655
if (delim != std::string_view::npos) {
57-
return {std::string(element.substr(0, delim)), std::string(element.substr(delim + 1))};
56+
return {std::string(view.substr(0, delim)), std::string(view.substr(delim + 1))};
5857
} else {
59-
return {std::string(element)};
58+
return {std::string(view)};
6059
}
6160
};
6261

include/skyr/v2/core/url_parser_context.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -889,7 +889,7 @@ class url_parser_context {
889889
if (!url.query) {
890890
set_empty_query();
891891
}
892-
auto pct_encoded = percent_encode_byte(std::byte(byte), percent_encoding::encode_set::none);
892+
auto pct_encoded = percent_encode_byte(std::byte(byte), percent_encoding::encode_set::any);
893893
url.query.value() += std::move(pct_encoded).to_string();
894894
}
895895

include/skyr/v2/domain/domain.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ inline auto domain_to_ascii_impl(domain_to_ascii_context &&context) -> tl::expec
141141
}
142142
};
143143

144-
constexpr auto process_labels = [](auto &&ctx) -> tl::expected<domain_to_ascii_context, domain_errc> {
144+
constexpr auto process_labels = [](auto &&ctx) -> tl::expected<std::decay_t<decltype(ctx)>, domain_errc> {
145145
using namespace std::string_view_literals;
146146

147147
constexpr auto to_string_view = [](auto &&label) {
@@ -198,7 +198,7 @@ inline auto domain_to_ascii_impl(domain_to_ascii_context &&context) -> tl::expec
198198
};
199199

200200
constexpr auto check_length =
201-
[](domain_to_ascii_context &&ctx) -> tl::expected<domain_to_ascii_context, domain_errc> {
201+
[](auto &&ctx) -> tl::expected<std::decay_t<decltype(ctx)>, domain_errc> {
202202
constexpr auto max_domain_length = 253;
203203
constexpr auto max_label_length = 63;
204204

include/skyr/v2/percent_encoding/percent_encode.hpp

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,10 @@
1414
namespace skyr::inline v2 {
1515
/// Percent encodes the input
1616
/// \returns The percent encoded output when successful, an error otherwise.
17-
inline auto percent_encode(std::string_view input) {
18-
using percent_encoding::percent_encoded_char;
19-
20-
static constexpr auto encode = [](auto byte) {
21-
if ((byte == '\x2a') || (byte == '\x2d') || (byte == '\x2e') || ((byte >= '\x30') && (byte <= '\x39')) ||
22-
((byte >= '\x41') && (byte <= '\x5a')) || (byte == '\x5f') || ((byte >= '\x61') && (byte <= '\x7a'))) {
23-
return percent_encoded_char(std::byte(byte), percent_encoded_char::no_encode());
24-
} else if (byte == '\x20') {
25-
return percent_encoded_char(std::byte('+'), percent_encoded_char::no_encode());
26-
}
27-
return percent_encoded_char(std::byte(byte));
17+
inline auto percent_encode_bytes(std::string_view input, percent_encoding::encode_set encodes) -> std::string {
18+
static auto encode = [&encodes] (auto byte) {
19+
using percent_encoding::percent_encode_byte;
20+
return percent_encode_byte(std::byte(byte), encodes);
2821
};
2922

3023
auto result = std::string{};
@@ -33,6 +26,10 @@ inline auto percent_encode(std::string_view input) {
3326
}
3427
return result;
3528
}
29+
30+
inline auto percent_encode(std::string_view input) -> std::string {
31+
return percent_encode_bytes(input, percent_encoding::encode_set::component);
32+
}
3633
} // namespace skyr::inline v2
3734

3835
#endif // SKYR_V2_PERCENT_ENCODING_PERCENT_ENCODE_HPP

0 commit comments

Comments
 (0)