Repository navigation
Conversation
java.net.IDN implements IDNA2003, so it rejects A-labels whose U-label has code points that IDNA2008 allows in context (U+00DF, U+03C2, U+200C, U+200D). Decode the Punycode directly, require it to round-trip, and leave the code points to the RFC 5892 rules.
|
Review of this PR. I ran a scratch probe on the PR branch for the behavioural points. The length limit and the Punycode decode of invalid A-labels work as intended, but there are a few issues. 1. Valid hostnames are now rejected (
2. Case sensitivity ( 3. 4. Tests
5. Minor
🤖 Generated with Claude Code |
…ints - hostname: check A-labels with RFC5892.isValidALabel, which does not reject code points that the bundled Unicode 5.2 table lists as unassigned when the JDK assigns them (e.g. xn--ls8h.la, U+1F600, Adlam) - Lower-case A-labels before decoding, so XN--BCHER-KVA and xn--Bcher-kva pass - idn-hostname: measure the 63-character limit with Punycode.encode instead of IDN.toASCII, and limit names to 253 characters in A-label form - Check label length before the quadratic Punycode decode - Test IDNA rules once per code point instead of once per char - Make Punycode package-private and drop the unreachable grow branch - Add PunycodeTest, RFC5892Test and HostnameFormatTest - Refresh idn-hostname.json, and draft-next hostname.json and idn-hostname.json
…rt yet The current suite adds idn-hostname cases for UTS 46 mapping, trailing label separators and the RFC 5893 digit rules. These are existing gaps, not regressions, so mark them disabled with a reason instead of widening this PR.
hostname accepted xn--ls8h.la while idn-hostname rejected it, because only hostname ignored the Unicode 5.2 table's UNASSIGNED entries. Use one rule set for both, so idn-hostname accepts every name hostname accepts.
|
Thanks for the careful review. I pushed a commit that addresses each point:
While working on this, I found that the IDNA rule loop stepped by Generated by Claude Code |
|
One more change after my last reply. I said Generated by Claude Code |
|
Review of the latest changes (head 1.
|
… hyphens - Accept a code point the Unicode 5.2 table lists as unassigned only if the JDK classifies it as Ll, Lm, Lo, Mn, Mc or Nd and NFKC and lower-casing leave it unchanged, so emoji, symbols, upper case and bidi controls added since are rejected (an approximation of the RFC 5892 derivation) - Accept ZWJ and ZWNJ after any Canonical_Combining_Class Virama code point, not only U+094D, and read the preceding code point, not char - Count the RFC 5891 4.2.3.1 hyphen positions in code points - Apply RFC 5893 rules 1, 3 and 4 to any label with an R, AL or AN character - Reject Cherokee small letters, which case folding maps to the capitals - Publish the lazily loaded RFC 5892 and joining-type tables with a volatile flag instead of checking BitSet.isEmpty() outside the lock - Walk hostname labels without splitting, and check ASCII without a stream - Replace the incorrect "idn-hostname accepts everything hostname accepts" test with tests for the new rules
|
Thanks again, these were all real. The new commit addresses each one:
I also checked the whole path against Python's Minor: Generated by Claude Code |
Found by comparing against Python idna 3.20 on every assigned code point: - KATAKANA MIDDLE DOT needs a Hiragana, Katakana or Han character anywhere in the label (RFC 5892 A.7), not only right after it. - Greek, Hebrew and Kana/Han checks use Character.UnicodeScript, not code blocks (Coptic in the Greek block, U+30FC is Common). - The ZWNJ joining-type scan steps over supplementary transparent marks by code point instead of by UTF-16 char. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01U6XXMPvkRmkr5kqQuxPXm4
Found by comparing against Python idna 3.20 on every assigned code point: - U+0CF1 and U+0CF2 are PVALID and U+19DA is DISALLOWED since Unicode 6.0 (RFC 6452), unlike the bundled Unicode 5.2 table. - New letters that case folding maps to another letter, such as U+1C80..U+1C88, are rejected, using lower(upper(c)) as the fold. - U+180F, a default-ignorable mark, is rejected. - New Cherokee capitals such as U+13F5 are accepted. The derivation now matches the idna PVALID table for all 41,890 code points assigned after Unicode 5.2. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01U6XXMPvkRmkr5kqQuxPXm4
|
Two more commits after a wider check. I compared the validator against Python It found three issues in the existing CONTEXTO/CONTEXTJ code that
It also found four gaps in how code points outside the Unicode 5.2 table are classified:
With these, the derivation matches the Ready for another look when you have time. Generated by Claude Code |
|
Review of head 1. Bidi rule is applied per label, not to the whole name ( 2. Newer code points are judged by the running JDK's Unicode version ( 3. Virama table is fixed at Unicode 15.1 ( 4. Test gaps ( 5. Dead code in 6. Hyphen check allocates per label ( 7. CHANGELOG ( |
- RFC 5893: once a label has an R, AL or AN character, every label of the name must satisfy the Bidi Rule, in idn-hostname and hostname. Re-enables the three suite cases for rules 1 and 4. - Virama list updated to Unicode 16.0 (Tulu-Tigalari, Gurung Khema). - Hyphen-position check no longer allocates. - Removes the unused block-based isGreek/isHebrew/isKatakana. - Tests: concurrent first use of the tables in a fresh class loader, name-wide Bidi, Unicode 16 virama; U+180F is skipped on JDKs that do not know it. - CHANGELOG split per change, with the known limits. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01U6XXMPvkRmkr5kqQuxPXm4
The Unicode 16 additions were appended out of order, so the binary search missed U+11D45 and U+11D97. Adds a test that the table is sorted. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01U6XXMPvkRmkr5kqQuxPXm4
|
Thanks for probing it directly. Pushed a commit for this round:
|
|
Review of head 1. 2. 3. No 4. Virama table content is untested ( 5. CHANGELOG omits the stricter 6. A-labels are decoded twice per hostname ( 7. Altitude: split Bidi-domain logic behind a public half-validated API ( 8. Hyphen check can be one |
- hostname applies the RFC 5893 Bidi Rule within each A-label only, so 3com.xn--mgbaam7a8h and 1a.xn--4dbc are valid again, as on 3.0.9. - Remove the public satisfiesBidiDomainRule. The cross-label rule stays private to idn-hostname, which checks only the labels without right-to-left characters, since isValidULabel already checked the rest. - HostnameFormat walks the labels once, with no split or second decode. - The hyphen check is one startsWith at the third code point. - Test the virama table against the JDK's combining classes, derived from NFD reordering, on any JDK. - HostnameFormat tests for RTL A-labels; CHANGELOG states the stricter hostname behaviour and which format applies the cross-label rule. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01U6XXMPvkRmkr5kqQuxPXm4
|
Thanks for the careful pass. Commit 954f45a addresses all eight points.
The differential probe against Python idna 3.20 still shows 0 mismatches on Java 24. That covers 462,802 single code points, 400k fuzz labels and 180k names. For names, |
|
Review of head 1. CHANGELOG example ( 2. Virama test cutoff ( 3. 4. Double scan and allocation ( 5. Test duplication and style ( |
- idn-hostname checks each label once: checkULabel reports whether a valid label is right-to-left, so isValid needs no second scan and no label array. Earlier labels are re-checked only when a name turns out to be a Bidi domain name. - The virama test scans every defined code point and requires an exact match with the JDK's combining classes, with no JDK version cutoff. - Pin RFC 5893 rules 4 and 5 for hostname A-labels. - CHANGELOG: use an A-label as the hostname Bidi example. - Share the reflective VIRAMAS read and tidy the test imports. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01U6XXMPvkRmkr5kqQuxPXm4
|
Thanks. Commit cf8e08e covers all five.
Full suite: 10,921 tests, 0 failures. The Python idna differential probe still shows 0 mismatches on Java 24, across 1,042,802 labels and names. |
|
Review of head 1. Virama test fails hard on any newer-Unicode JDK ( 2. Status constants are misnamed ( 3. Earlier A-labels are decoded twice ( |
- The virama test always fails on a code point the table wrongly lists. A missing virama fails only when the JDK's Unicode data is not newer than the table's 16.0; on a newer JDK it is logged instead. - checkULabel returns a LabelStatus enum (INVALID, NO_RTL, HAS_RTL), declared with the other constants. - Keep the U-labels of A-labels, allocated only when a name has one, so an earlier A-label is not decoded again when the first right-to-left label appears. - Test the Punycode decoder's surrogate and out-of-range branches. - CHANGELOG: only Adlam small letters are accepted, not the capitals. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01U6XXMPvkRmkr5kqQuxPXm4
|
Thanks. Commit 263c44b covers all three.
While I was there I also went over the whole diff again. I added tests for the two Punycode decoder branches that had none: a lone surrogate ( |
|
Review of head 1. Unicode-version heuristic is undocumented and unverified ( 2. Earlier-label fallback has three states ( |
- Report missing post-16.0 viramas through JUnit (assumeTrue) instead of an slf4j warning, and detect a JDK newer than Unicode 16.0 from the scripts added in 17.0 (documented UnicodeScript.valueOf behaviour) rather than enum ordering, with a test for the detection. - Keep one source of truth for U-labels in isValid: each label is replaced by its U-label in place, so the Bidi back-check reads labels[m] with no fallback and no extra array.
|
Thanks for the extra differential run. Both points are addressed in the new commit. Unicode version check. The test no longer relies on enum ordering. It asks whether any script added in Unicode 17.0 (Beria Erfe, Sidetic, Tai Yo, Tolong Siki) resolves through UnicodeScript.valueOf, which is documented to throw for an unknown name. Any later version includes those scripts, so this also covers versions that add no script of their own. A new test checks the detection against Character.isDefined over those four blocks, which are unassigned in 16.0. On a newer JDK, missing viramas now abort the test through assumeTrue with the list in the message, so they show in the JUnit report as a skipped test instead of only in an slf4j warning. The slf4j import is gone from the test. |
|
Review of head 1. Any number of trailing separators is accepted ( 2. The new version-detection test only does work on JDK 26 or newer ( 3. 4. |
Reject over-long hostnames and invalid A-labels in the hostname format
The
hostnameformat was a single LDH regex, so it accepted names longer than 253 characters and anyxn--label, including invalid Punycode such asxn--X. RFC 1123 hostnames that use thexn--prefix must be valid A-labels (RFC 5890, section 2.3.2.1).hostnameHostnameFormat: the existing LDH rule, a 253-character limit, and an A-label check for labels that start withxn--in any case.hostnameandidn-hostnamePunycodeclass instead ofjava.net.IDN, which follows IDNA2003 and rejects labels IDNA2008 allows in context (U+00DF, U+03C2, ZWJ/ZWNJ after a virama).xn--ls8h.la), symbols, upper case and bidi controls do not.idn-hostnamePunycode.encodeinstead ofIDN.toASCII), and names are limited to 253 characters in A-label form. Label length is checked before the quadratic decode.Tests
PunycodeTest(RFC 3492 section 7.1 samples, overflow, truncated input, a delimiter at index 0),RFC5892TestandHostnameFormatTest(253/254, 63/64, trailing dot, upper case).hostname.json(draft 4 to 2020-12) andidn-hostname.json(draft 7 to 2020-12) refreshed from the current JSON-Schema-Test-Suite, plusdraft-nextfrom 2020-12. The refreshedidn-hostname.jsonadds 12 cases this validator didn't support before either: UTS 46 mapping, trailing separators and RFC 5893 digit rules. They are markeddisabledwith a reason, for a follow-up PR.mvn -B testpasses locally.