Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -1919,6 +1919,38 @@ public static synchronized String[] getTLDEntries(final ArrayType table) {
return Arrays.copyOf(array, array.length); // clone the array
}

/*
* Tests whether any label in the input begins or ends with an ASCII hyphen, which is not
* permitted in a host name label. Labels are separated by the dot characters recognized in
* RFC 3490 section 3.1.
*/
private static boolean hasLabelBoundaryHyphen(final String input) {
boolean labelStart = true;
for (int i = 0; i < input.length(); i++) {
final char ch = input.charAt(i);
if (isLabelSeparator(ch)) {
if (i > 0 && input.charAt(i - 1) == '-') {
return true; // label ends with a hyphen
}
labelStart = true;
} else {
if (labelStart && ch == '-') {
return true; // label begins with a hyphen
}
labelStart = false;
}
}
final int last = input.length() - 1;
return last >= 0 && input.charAt(last) == '-';
}

/*
* Tests whether the character is one of the label separators recognized in RFC 3490 section 3.1.
*/
private static boolean isLabelSeparator(final char ch) {
return ch == '.' || ch == '\u3002' || ch == '\uFF0E' || ch == '\uFF61';
}

/*
* Tests whether input contains only ASCII. Treats null as all ASCII.
*/
Expand Down Expand Up @@ -1956,6 +1988,15 @@ static String unicodeToASCII(final String input) {
}
i += Character.charCount(codePoint);
}
// A label must not begin or end with a hyphen (RFC 1123, and RFC 5891 for IDN labels).
// IDN.toASCII with the default flags does not enforce this: it punycode-encodes such a
// label (for example a leading-hyphen "-tést" becomes "xn---tst-cpa") to a form that
// then satisfies the label regex, so the hyphen slips through on a non-ASCII label although
// the all-ASCII form is rejected. Keep the original here and let the label regex reject it
// (VALIDATOR-501).
if (hasLabelBoundaryHyphen(input)) {
return input;
}
try {
final String ascii = IDN.toASCII(input);
if (IDNBUGHOLDER.IDN_TOASCII_PRESERVES_TRAILING_DOTS) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@

import org.apache.commons.validator.routines.DomainValidator.ArrayType;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;

/**
Expand Down Expand Up @@ -506,11 +505,15 @@ void testInvalidDomains() {
}

@Test
@Disabled
void testInvalidDomains501() {
// VALIDATOR-501
// VALIDATOR-501: a non-ASCII label starting or ending with a hyphen is punycode-encoded by
// IDN.toASCII to a form that passes the label regex, so it slipped through although the
// all-ASCII form ("-test.fr" / "test-.fr") is rejected in testInvalidDomains above.
assertFalse(validator.isValid("-tést.fr"));
assertFalse(validator.isValid("tést-.fr"));
assertFalse(validator.isValid("-é.fr"), "single non-ASCII label starting with a hyphen shouldn't validate");
// an interior hyphen on a non-ASCII label is still allowed
assertTrue(validator.isValid("a-é.fr"), "interior hyphen on a non-ASCII label should validate");
}

// Check if IDN.toASCII is broken or not
Expand Down
Loading