From c23c591f888f6cb1054bd110f7b6ffff9a1173a0 Mon Sep 17 00:00:00 2001 From: Tarun Gupta Date: Sat, 27 Jun 2015 14:29:57 +0530 Subject: Add Internationalized Domain Name Features. Adds IDNConverter interface, ICUConverter using ICU for Stringprep. Also updates Makefile and build.xml by adding path to icu4j to compile tests classpath, so that icu4j.jar can be used in the tests. IDNConverter tests need StringPrepParseException from icu4j jar. License: This patch is BSD-licensed, see Documentation/Licenses/BSD-simplified.txt for details. Test-Information: Added test for IDNConverter, which passes. Change-Id: I56aacf080a10216a2455cf561de567f5666cd0c9 diff --git a/Makefile b/Makefile index 2e81110..0798974 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,7 @@ dist/lib/stroke.jar: third-party/jzlib/jzlib.jar third-party/icu4j.jar third-par .PHONY : test test: dist/lib/stroke.jar third-party/cobertura/cobertura.jar third-party/findbugs/lib/findbugs.jar third-party/pmd/lib/pmd-5.0.0.jar - ant ${DEFINES} -DJUNIT_JAR=${JUNIT} -Dcobertura-jar=third-party/cobertura/cobertura.jar -Djakarta-oro-jar=third-party/cobertura/lib/jakarta-oro-2.0.8.jar -Dlog4j-jar=third-party/cobertura/lib/log4j-1.2.9.jar -Dasm-jar=third-party/cobertura/lib/asm-3.0.jar -Dasm-tree-jar=third-party/cobertura/lib/asm-tree-3.0.jar -Dfindbugs.home=third-party/findbugs -Dpmd.home=third-party/pmd test + ant ${DEFINES} -DJUNIT_JAR=${JUNIT} -Dcobertura-jar=third-party/cobertura/cobertura.jar -Djakarta-oro-jar=third-party/cobertura/lib/jakarta-oro-2.0.8.jar -Dlog4j-jar=third-party/cobertura/lib/log4j-1.2.9.jar -Dasm-jar=third-party/cobertura/lib/asm-3.0.jar -Dasm-tree-jar=third-party/cobertura/lib/asm-tree-3.0.jar -Dicu4j-jar=third-party/icu4j.jar -Dfindbugs.home=third-party/findbugs -Dpmd.home=third-party/pmd test third-party/aalto/aalto-xml.jar: mkdir -p third-party/aalto diff --git a/build.xml b/build.xml index 6c4058f..5cb03b8 100644 --- a/build.xml +++ b/build.xml @@ -104,6 +104,7 @@ + diff --git a/src/com/isode/stroke/idn/ICUConverter.java b/src/com/isode/stroke/idn/ICUConverter.java new file mode 100644 index 0000000..bd347df --- /dev/null +++ b/src/com/isode/stroke/idn/ICUConverter.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2012-2013 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ +/* + * Copyright (c) 2015 Tarun Gupta. + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +package com.isode.stroke.idn; + +import com.isode.stroke.base.SafeByteArray; +import com.isode.stroke.idn.IDNConverter; +import com.isode.stroke.idn.IDNA; +import com.ibm.icu.text.StringPrep; +import com.ibm.icu.text.StringPrepParseException; + +public class ICUConverter implements IDNConverter { + + public String getStringPrepared(String s, StringPrepProfile profile) throws StringPrepParseException { + StringPrep str = StringPrep.getInstance(getICUProfileType(profile)); + + String preparedData = str.prepare(s, StringPrep.DEFAULT); + return preparedData; + } + + public SafeByteArray getStringPrepared(SafeByteArray s, StringPrepProfile profile) throws StringPrepParseException { + StringPrep str = StringPrep.getInstance(getICUProfileType(profile)); + + String preparedData = str.prepare(s.toString(), StringPrep.DEFAULT); + return new SafeByteArray(preparedData); + } + + public String getIDNAEncoded(String s) { + return IDNA.getEncoded(s); + } + + private int getICUProfileType(IDNConverter.StringPrepProfile profile) { + switch(profile) { + case NamePrep: return StringPrep.RFC3491_NAMEPREP; + case XMPPNodePrep: return StringPrep.RFC3920_NODEPREP; + case XMPPResourcePrep: return StringPrep.RFC3920_RESOURCEPREP; + case SASLPrep: return StringPrep.RFC4013_SASLPREP; + } + assert(false); + return StringPrep.RFC3491_NAMEPREP; + } +} \ No newline at end of file diff --git a/src/com/isode/stroke/idn/IDNA.java b/src/com/isode/stroke/idn/IDNA.java index 572369f..e3b86dd 100644 --- a/src/com/isode/stroke/idn/IDNA.java +++ b/src/com/isode/stroke/idn/IDNA.java @@ -13,6 +13,11 @@ import java.net.IDN; public class IDNA { public static String getEncoded(String s) { - return IDN.toASCII(s); + try { + return IDN.toASCII(s, IDN.USE_STD3_ASCII_RULES); + } + catch (IllegalArgumentException e) { + return null; + } } } diff --git a/src/com/isode/stroke/idn/IDNConverter.java b/src/com/isode/stroke/idn/IDNConverter.java new file mode 100644 index 0000000..3566020 --- /dev/null +++ b/src/com/isode/stroke/idn/IDNConverter.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2013 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ +/* + * Copyright (c) 2015 Tarun Gupta. + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +package com.isode.stroke.idn; + +import com.isode.stroke.base.SafeByteArray; +import com.ibm.icu.text.StringPrepParseException; + +public interface IDNConverter { + + public enum StringPrepProfile { + NamePrep, + XMPPNodePrep, + XMPPResourcePrep, + SASLPrep + }; + + public String getStringPrepared(String s, StringPrepProfile profile) throws StringPrepParseException; + public SafeByteArray getStringPrepared(SafeByteArray s, StringPrepProfile profile) throws StringPrepParseException; + + // Thread-safe + public String getIDNAEncoded(String s); +} \ No newline at end of file diff --git a/test/com/isode/stroke/idn/IDNConverterTest.java b/test/com/isode/stroke/idn/IDNConverterTest.java new file mode 100644 index 0000000..a17affc --- /dev/null +++ b/test/com/isode/stroke/idn/IDNConverterTest.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2010 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ +/* + * Copyright (c) 2015 Tarun Gupta. + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +package com.isode.stroke.idn; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import org.junit.Test; +import org.junit.Before; +import com.isode.stroke.base.SafeByteArray; +import com.isode.stroke.idn.IDNConverter; +import com.isode.stroke.idn.IDNA; +import com.isode.stroke.idn.ICUConverter; +import com.ibm.icu.text.StringPrepParseException; + +public class IDNConverterTest { + + private IDNConverter testling; + + @Before + public void setUp() { + testling = new ICUConverter(); + } + + @Test + public void testStringPrep() { + try { + String result = testling.getStringPrepared("tronçon", IDNConverter.StringPrepProfile.NamePrep); + assertEquals("tronçon", result); + } catch (StringPrepParseException e) { + assertTrue("getStringPrep threw " + e, (e == null)); + } + } + + @Test + public void testStringPrep_Empty() { + try{ + assertEquals("", testling.getStringPrepared("", IDNConverter.StringPrepProfile.NamePrep)); + assertEquals("", testling.getStringPrepared("", IDNConverter.StringPrepProfile.XMPPNodePrep)); + assertEquals("", testling.getStringPrepared("", IDNConverter.StringPrepProfile.XMPPResourcePrep)); + } catch (StringPrepParseException e) { + assertTrue("getStringPrep threw " + e, (e == null)); + } + } + + @Test + public void testGetEncoded() { + String result = testling.getIDNAEncoded("www.swift.im"); + assertNotNull(result); + assertEquals("www.swift.im", result); + } + + @Test + public void testGetEncoded_International() { + String result = testling.getIDNAEncoded("www.tronçon.com"); + assertNotNull(result); + assertEquals("www.xn--tronon-zua.com", result); + } + + @Test + public void testGetEncoded_Invalid() { + String result = testling.getIDNAEncoded("www.foo,bar.com"); + assertNull(result); + } +} \ No newline at end of file -- cgit v0.10.2-6-g49f6