Skip to content

Updated IDNA mapping function when processing domain name #140

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jul 8, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions include/skyr/v1/containers/static_vector.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,18 +149,30 @@ class static_vector {

///
/// \return
[[nodiscard]] constexpr auto begin() const noexcept -> const_iterator {
[[nodiscard]] constexpr auto cbegin() const noexcept -> const_iterator {
return impl_.begin();
}

///
/// \return
[[nodiscard]] constexpr auto end() const noexcept -> const_iterator {
[[nodiscard]] constexpr auto cend() const noexcept -> const_iterator {
auto last = impl_.begin();
std::advance(last, size_);
return last;
}

///
/// \return
[[nodiscard]] constexpr auto begin() const noexcept -> const_iterator {
return cbegin();
}

///
/// \return
[[nodiscard]] constexpr auto end() const noexcept -> const_iterator {
return cend();
}

};
} // namespace v1
} // namespace skyr
Expand Down
54 changes: 54 additions & 0 deletions src/v1/domain/idna.hpp → include/skyr/v1/domain/idna.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
#ifndef SKYR_V1_DOMAIN_IDNA_HPP
#define SKYR_V1_DOMAIN_IDNA_HPP

#include <tl/expected.hpp>
#include <skyr/v1/domain/errors.hpp>

namespace skyr {
inline namespace v1 {
namespace idna {
Expand Down Expand Up @@ -45,6 +48,57 @@ auto code_point_status(char32_t code_point) -> idna_status;
/// \return The code point or mapped value, depending on the status of the code
/// point
auto map_code_point(char32_t code_point) -> char32_t;

///
/// \tparam FwdIter
/// \param first
/// \param last
/// \param use_std3_ascii_rules
/// \param transitional_processing
/// \return
template <class FwdIter>
inline auto map_code_points(
FwdIter first,
FwdIter last,
bool use_std3_ascii_rules,
bool transitional_processing) -> tl::expected<FwdIter, domain_errc> {
for (auto it = first; it != last; ++it) {
switch (code_point_status(*it)) {
case idna_status::disallowed:
return tl::make_unexpected(domain_errc::disallowed_code_point);
case idna_status::disallowed_std3_valid:
if (use_std3_ascii_rules) {
return tl::make_unexpected(domain_errc::disallowed_code_point);
} else {
*first++ = *it;
}
break;
case idna_status::disallowed_std3_mapped:
if (use_std3_ascii_rules) {
return tl::make_unexpected(domain_errc::disallowed_code_point);
} else {
*first++ = map_code_point(*it);
}
break;
case idna_status::ignored:
break;
case idna_status::mapped:
*first++ = idna::map_code_point(*it);
break;
case idna_status::deviation:
if (transitional_processing) {
*first++ = idna::map_code_point(*it);
} else {
*first++ = *it;
}
break;
case idna_status::valid:
*first++ = *it;
break;
}
}
return first;
}
} // namespace idna
} // namespace v1
} // namespace skyr
Expand Down
File renamed without changes.
5 changes: 2 additions & 3 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,7 @@ target_sources(skyr-url
v1/network/ipv4_address.cpp
v1/network/ipv6_address.cpp
v1/domain/domain.cpp
v1/domain/idna.hpp
v1/domain/idna.cpp
v1/domain/idna_code_point_map_iterator.hpp
v1/domain/punycode.hpp
v1/url/url.cpp
v1/url/url_search_parameters.cpp

Expand All @@ -52,6 +49,8 @@ target_sources(skyr-url
${PROJECT_SOURCE_DIR}/include/skyr/v1/string/starts_with.hpp
${PROJECT_SOURCE_DIR}/include/skyr/v1/containers/static_vector.hpp
${PROJECT_SOURCE_DIR}/include/skyr/v1/domain/errors.hpp
${PROJECT_SOURCE_DIR}/include/skyr/v1/domain/idna.hpp
${PROJECT_SOURCE_DIR}/include/skyr/v1/domain/punycode.hpp
${PROJECT_SOURCE_DIR}/include/skyr/v1/domain/domain.hpp
${PROJECT_SOURCE_DIR}/include/skyr/v1/platform/endianness.hpp
${PROJECT_SOURCE_DIR}/include/skyr/v1/network/ipv4_address.hpp
Expand Down
60 changes: 23 additions & 37 deletions src/v1/domain/domain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,20 @@
// http://www.boost.org/LICENSE_1_0.txt)

#include <algorithm>
#include <range/v3/algorithm/copy.hpp>
#include <range/v3/iterator.hpp>
#include <range/v3/range/conversion.hpp>
#include <range/v3/view/join.hpp>
#include <range/v3/view/split.hpp>
#include <range/v3/view/transform.hpp>
#include <range/v3/algorithm/copy.hpp>
#include <range/v3/iterator.hpp>
#include <skyr/v1/containers/static_vector.hpp>
#include <skyr/v1/domain/domain.hpp>
#include <skyr/v1/domain/errors.hpp>
#include <skyr/v1/unicode/ranges/transforms/u8_transform.hpp>
#include <skyr/v1/domain/idna.hpp>
#include <skyr/v1/domain/punycode.hpp>
#include <skyr/v1/unicode/ranges/transforms/u32_transform.hpp>
#include <skyr/v1/unicode/ranges/transforms/u8_transform.hpp>
#include <skyr/v1/unicode/ranges/views/u8_view.hpp>
#include "idna.hpp"
#include "idna_code_point_map_iterator.hpp"
#include "punycode.hpp"


/// How many labels can be in a domain?
/// https://www.farsightsecurity.com/blog/txt-record/rrlabel-20171013/
Expand All @@ -30,28 +28,6 @@
namespace skyr {
inline namespace v1 {
namespace {
template <class DomainName>
auto map_code_points(
DomainName &&domain_name,
bool use_std3_ascii_rules,
bool transitional_processing,
std::u32string *result)
-> tl::expected<void, domain_errc> {
auto range = idna::views::map_code_points(domain_name, use_std3_ascii_rules, transitional_processing);
auto first = std::cbegin(range);
auto last = std::cend(range);
for (auto it = first; it != last; ++it) {
if (!*it) {
return tl::make_unexpected((*it).error());
}
result->push_back((*it).value());
if (result->size() == result->max_size()) {
return tl::make_unexpected(domain_errc::invalid_length);
}
}
return {};
}

auto validate_label(std::u32string_view label, [[maybe_unused]] bool use_std3_ascii_rules, bool check_hyphens,
[[maybe_unused]] bool check_bidi, [[maybe_unused]] bool check_joiners, bool transitional_processing)
-> tl::expected<void, domain_errc> {
Expand Down Expand Up @@ -106,19 +82,29 @@ auto domain_to_ascii(

using namespace std::string_view_literals;

auto u32domain_name = unicode::views::as_u8(domain_name) | unicode::transforms::to_u32;
auto mapped_domain_name = std::u32string{};
auto result = map_code_points(u32domain_name, use_std3_ascii_rules, transitional_processing, &mapped_domain_name);
if (!result) {
return tl::make_unexpected(result.error());
auto mapped_domain_name = unicode::as<std::u32string>(
unicode::views::as_u8(domain_name) | unicode::transforms::to_u32);
if (mapped_domain_name) {
auto result = idna::map_code_points(
std::begin(mapped_domain_name.value()),
std::end(mapped_domain_name.value()),
use_std3_ascii_rules,
transitional_processing);
if (result) {
mapped_domain_name.value().erase(result.value(), mapped_domain_name.value().cend());
} else {
return tl::make_unexpected(result.error());
}
} else {
return tl::make_unexpected(domain_errc::encoding_error);
}

static constexpr auto to_string_view = [] (auto &&label) {
return std::u32string_view(std::addressof(*std::begin(label)), ranges::distance(label));
};

auto labels = static_vector<std::u32string, SKYR_DOMAIN_MAX_NUM_LABELS>{};
for (auto &&label : mapped_domain_name | ranges::views::split(U'.') | ranges::views::transform(to_string_view)) {
for (auto &&label : mapped_domain_name.value() | ranges::views::split(U'.') | ranges::views::transform(to_string_view)) {
if (labels.size() == labels.max_size()) {
return tl::make_unexpected(domain_errc::too_many_labels);
}
Expand Down Expand Up @@ -165,15 +151,15 @@ auto domain_to_ascii(
}
}

if (mapped_domain_name.back() == U'.') {
if (mapped_domain_name.value().back() == U'.') {
labels.emplace_back();
}

constexpr auto max_domain_length = 253;
constexpr auto max_label_length = 63;

if (verify_dns_length) {
auto length = mapped_domain_name.size();
auto length = mapped_domain_name.value().size();
if ((length < 1) || (length > max_domain_length)) {
return tl::make_unexpected(domain_errc::invalid_length);
}
Expand Down
4 changes: 2 additions & 2 deletions src/v1/domain/idna.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
// http://www.boost.org/LICENSE_1_0.txt)

#include <algorithm>
#include <iterator>
#include <array>
#include "idna.hpp"
#include <iterator>
#include <skyr/v1/domain/idna.hpp>

namespace skyr {
inline namespace v1 {
Expand Down
Loading