Skip to content
Open
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
14 changes: 8 additions & 6 deletions src/validity.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ bool is_label_valid(const std::u32string_view label) {
if (c == 0x200c) {
if (i > 0) {
if (std::ranges::binary_search(virama, label[i - 1])) {
return true;
continue;
}
}
if ((i == 0) || (i + 1 >= label.size())) {
Expand All @@ -206,14 +206,16 @@ bool is_label_valid(const std::u32string_view label) {
};
std::u32string_view before = label.substr(0, i);
std::u32string_view after = label.substr(i + 1);
return (std::find_if(before.begin(), before.end(), is_l_or_d) !=
before.end()) &&
(std::find_if(after.begin(), after.end(), is_r_or_d) !=
after.end());
if ((std::find_if(before.begin(), before.end(), is_l_or_d) ==
before.end()) ||
(std::find_if(after.begin(), after.end(), is_r_or_d) ==
after.end())) {
return false;
}
} else if (c == 0x200d) {
if (i > 0) {
if (std::ranges::binary_search(virama, label[i - 1])) {
return true;
continue;
}
}
return false;
Expand Down
15 changes: 15 additions & 0 deletions tests/to_ascii_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,21 @@ TEST(to_ascii_tests, bidi_regression) {
<< "multi-label should fail";
}

TEST(to_ascii_tests, contextj_joiner_does_not_bypass_bidi) {
// A ZWNJ preceded by a virama satisfies the ContextJ rule, but that must not
// short-circuit the Bidi validity check for the rest of the label. Here the
// label starts with L (U+0915) so it is an LTR label, and the trailing AL
// (U+0627) violates Rule 5. It must be rejected.
EXPECT_TRUE(ada::idna::to_ascii("\u0915\u094D\u200C\u0627").empty())
<< "valid ZWNJ must not bypass Bidi rule 5";
// Same with ZWJ (U+200D).
EXPECT_TRUE(ada::idna::to_ascii("\u0915\u094D\u200D\u0627").empty())
<< "valid ZWJ must not bypass Bidi rule 5";
// A contextually valid joiner in an otherwise valid label still converts.
EXPECT_EQ(ada::idna::to_ascii("\u0915\u094D\u200C\u0916"), "xn--11bc8nw90g")
<< "valid ZWNJ label must still convert";
}

// Helper: domain-to-ASCII as URL Standard callers use it (to_ascii + forbidden
// domain code point filter). Empty string means failure.
static std::string domain_to_ascii(std::string_view input) {
Expand Down
Loading