Author: sebb
Date: Wed Jan 14 23:09:12 2015
New Revision: 1651873

URL: http://svn.apache.org/r1651873
Log:
VALIDATOR-356 IDN.toASCII drops trailing dot in Java 6 & 7

Modified:
    commons/proper/validator/trunk/src/changes/changes.xml
    
commons/proper/validator/trunk/src/main/java/org/apache/commons/validator/routines/DomainValidator.java
    
commons/proper/validator/trunk/src/test/java/org/apache/commons/validator/routines/DomainValidatorTest.java
    
commons/proper/validator/trunk/src/test/java/org/apache/commons/validator/routines/UrlValidatorTest.java

Modified: commons/proper/validator/trunk/src/changes/changes.xml
URL: 
http://svn.apache.org/viewvc/commons/proper/validator/trunk/src/changes/changes.xml?rev=1651873&r1=1651872&r2=1651873&view=diff
==============================================================================
--- commons/proper/validator/trunk/src/changes/changes.xml (original)
+++ commons/proper/validator/trunk/src/changes/changes.xml Wed Jan 14 23:09:12 
2015
@@ -43,6 +43,9 @@ The <action> type attribute can be add,u
   <body>
 
   <release version="1.5.0" date="tba" description="tba">
+    <action issue="VALIDATOR-356" dev="seb" type="fix" >
+      IDN.toASCII drops trailing dot in Java 6 & 7
+    </action>
     <action issue="VALIDATOR-355" dev="britter" type="update" >
       Update to Java 6
     </action>

Modified: 
commons/proper/validator/trunk/src/main/java/org/apache/commons/validator/routines/DomainValidator.java
URL: 
http://svn.apache.org/viewvc/commons/proper/validator/trunk/src/main/java/org/apache/commons/validator/routines/DomainValidator.java?rev=1651873&r1=1651872&r2=1651873&view=diff
==============================================================================
--- 
commons/proper/validator/trunk/src/main/java/org/apache/commons/validator/routines/DomainValidator.java
 (original)
+++ 
commons/proper/validator/trunk/src/main/java/org/apache/commons/validator/routines/DomainValidator.java
 Wed Jan 14 23:09:12 2015
@@ -1085,16 +1085,46 @@ public class DomainValidator implements
      */
     // Needed by UrlValidator
     static String unicodeToASCII(String input) {
-        if (isOnlyASCII(input)) { // TODO temporary hack to work round 
IDN.toASCII bug
+        if (isOnlyASCII(input)) { // skip possibly expensive processing
             return input;
         }
         try {
-            return IDN.toASCII(input);
+            final String ascii = IDN.toASCII(input);
+            if (IDNBUGHOLDER.IDN_TOASCII_PRESERVES_TRAILING_DOTS) {
+                return ascii;
+            }
+            final int length = input.length();
+            if (length == 0) {// check there is a last character
+                return input;
+            }
+// RFC3490 3.1. 1)
+//            Whenever dots are used as label separators, the following
+//            characters MUST be recognized as dots: U+002E (full stop), U+3002
+//            (ideographic full stop), U+FF0E (fullwidth full stop), U+FF61
+//            (halfwidth ideographic full stop).
+            char lastChar = input.charAt(length-1);// fetch original last char
+            switch(lastChar) {
+                case '\u002E': // "." full stop
+                case '\u3002': // ideographic full stop
+                case '\uFF0E': // fullwidth full stop
+                case '\uFF61': // halfwidth ideographic full stop
+                    return ascii + "."; // restore the missing stop
+                default:
+                    return ascii;
+            }
         } catch (IllegalArgumentException e) { // input is not valid
             return input;
         }
     }
 
+    private static class IDNBUGHOLDER {
+        private static boolean keepsTrailingDot() {
+            final String input = "a."; // must be a valid name
+            return input.equals(IDN.toASCII(input));
+        }
+        private static final boolean IDN_TOASCII_PRESERVES_TRAILING_DOTS = 
keepsTrailingDot();
+    }
+
     /*
      * Check if input contains only ASCII
      * Treats null as all ASCII

Modified: 
commons/proper/validator/trunk/src/test/java/org/apache/commons/validator/routines/DomainValidatorTest.java
URL: 
http://svn.apache.org/viewvc/commons/proper/validator/trunk/src/test/java/org/apache/commons/validator/routines/DomainValidatorTest.java?rev=1651873&r1=1651872&r2=1651873&view=diff
==============================================================================
--- 
commons/proper/validator/trunk/src/test/java/org/apache/commons/validator/routines/DomainValidatorTest.java
 (original)
+++ 
commons/proper/validator/trunk/src/test/java/org/apache/commons/validator/routines/DomainValidatorTest.java
 Wed Jan 14 23:09:12 2015
@@ -208,6 +208,67 @@ public class DomainValidatorTest extends
         assertFalse("254 chars domain should fail", 
validator.isValidDomainSyntax(longDomain+"x"));
     }
 
+    // Check that IDN.toASCII behaves as it should (when wrapped by 
DomainValidator.unicodeToASCII)
+    // Tests show that method incorrectly trims a trailing "." character 
+    public void testUnicodeToASCII() {
+        String[] asciidots = {
+                "",
+                ",",
+                ".", // fails IDN.toASCII, but should pass wrapped version
+                "a.", // ditto
+                "a.b",
+                "a..b",
+                "a...b",
+                ".a",
+                "..a",
+        };
+        for(String s : asciidots) {
+            assertEquals(s,DomainValidator.unicodeToASCII(s));
+        }
+        // RFC3490 3.1. 1)
+//      Whenever dots are used as label separators, the following
+//      characters MUST be recognized as dots: U+002E (full stop), U+3002
+//      (ideographic full stop), U+FF0E (fullwidth full stop), U+FF61
+//      (halfwidth ideographic full stop).
+        final String otherDots[][] = {
+                {"b\u3002", "b.",},
+                {"b\uFF0E", "b.",},
+                {"b\uFF61", "b.",},
+                {"\u3002", ".",},
+                {"\uFF0E", ".",},
+                {"\uFF61", ".",},
+        };
+        for(String s[] : otherDots) {
+            assertEquals(s[1],DomainValidator.unicodeToASCII(s[0]));
+        }
+    }
+
+    // Check if IDN.toASCII is broken or not
+    public void testIsIDNtoASCIIBroken() {
+        System.out.println(">>DomainValidatorTest.testIsIDNtoASCIIBroken()");
+        final String input = ".";
+        final boolean ok = input.equals(IDN.toASCII(input));
+        System.out.println("IDN.toASCII is " + (ok? "OK" : "BROKEN"));
+        String props[] = {
+        "java.version", //    Java Runtime Environment version
+        "java.vendor", // Java Runtime Environment vendor
+        "java.vm.specification.version", //   Java Virtual Machine 
specification version
+        "java.vm.specification.vendor", //    Java Virtual Machine 
specification vendor
+        "java.vm.specification.name", //  Java Virtual Machine specification 
name
+        "java.vm.version", // Java Virtual Machine implementation version
+        "java.vm.vendor", //  Java Virtual Machine implementation vendor
+        "java.vm.name", //    Java Virtual Machine implementation name
+        "java.specification.version", //  Java Runtime Environment 
specification version
+        "java.specification.vendor", //   Java Runtime Environment 
specification vendor
+        "java.specification.name", // Java Runtime Environment specification 
name
+        "java.class.version", //  Java class format version number
+        };
+        for(String t : props) {
+            System.out.println(t + "=" + System.getProperty(t));
+        }    
+        System.out.println("<<DomainValidatorTest.testIsIDNtoASCIIBroken()");
+    }
+
     // Check array is sorted and is lower-case
     public void test_INFRASTRUCTURE_TLDS_sortedAndLowerCase() throws Exception 
{
         final boolean sorted = isSortedLowerCase("INFRASTRUCTURE_TLDS");

Modified: 
commons/proper/validator/trunk/src/test/java/org/apache/commons/validator/routines/UrlValidatorTest.java
URL: 
http://svn.apache.org/viewvc/commons/proper/validator/trunk/src/test/java/org/apache/commons/validator/routines/UrlValidatorTest.java?rev=1651873&r1=1651872&r2=1651873&view=diff
==============================================================================
--- 
commons/proper/validator/trunk/src/test/java/org/apache/commons/validator/routines/UrlValidatorTest.java
 (original)
+++ 
commons/proper/validator/trunk/src/test/java/org/apache/commons/validator/routines/UrlValidatorTest.java
 Wed Jan 14 23:09:12 2015
@@ -295,6 +295,15 @@ public class UrlValidatorTest extends Te
         assertFalse(urlValidator.isValid("http://www.cnn.invalid./";)); // 
check . does not affect invalid domains
     }
 
+    public void testValidator339IDN(){
+        UrlValidator urlValidator = new UrlValidator();
+        
assertTrue(urlValidator.isValid("http://президент.рф/WORLD/?hpt=sitenav";));
 // without
+        
assertTrue(urlValidator.isValid("http://президент.рф./WORLD/?hpt=sitenav";));
 // with
+        
assertFalse(urlValidator.isValid("http://президент.рф..../";)); // 
very dotty
+        
assertFalse(urlValidator.isValid("http://президент.рф.../";)); // 
triply dotty
+        
assertFalse(urlValidator.isValid("http://президент.рф../";)); // 
doubly dotty
+    }
+
     public void testValidator342(){
         UrlValidator urlValidator = new UrlValidator();
         assertTrue(urlValidator.isValid("http://example.rocks/";));


Reply via email to