Index: modules/luni/src/test/java/org/apache/harmony/luni/tests/java/net/IDNTest.java =================================================================== --- modules/luni/src/test/java/org/apache/harmony/luni/tests/java/net/IDNTest.java (revision 0) +++ modules/luni/src/test/java/org/apache/harmony/luni/tests/java/net/IDNTest.java (revision 0) @@ -0,0 +1,160 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.luni.tests.java.net; + +import java.net.IDN; + +import junit.framework.TestCase; + +public class IDNTest extends TestCase { + + /** + * @tests {@link java.net.IDN#toASCII(String)} + * + * @since 1.6 + */ + public void test_ToASCII_LString() { + try { + IDN.toASCII(null); + fail("should throw NullPointerException"); + } catch (NullPointerException e) { + // expected + } + + try { + IDN.toASCII("www.m\uE400kitorppa.edu"); + fail("should throw IllegalArgumentException"); + } catch (IllegalArgumentException e) { + // expected + } + + try { + IDN.toASCII("www.\u672C\uFE73\uFFFF.jp"); + fail("should throw IllegalArgumentException"); + } catch (IllegalArgumentException e) { + // expected + } + + assertEquals("www.xn--gwtq9nb2a.jp", IDN + .toASCII("www.\u65E5\u672C\u5E73.jp")); + assertEquals( + "www.xn--vckk7bxa0eza9ezc9d.com", + IDN + .toASCII("www.\u30CF\u30F3\u30C9\u30DC\u30FC\u30EB\u30B5\u30E0\u30BA.com")); + assertEquals("www.xn--frgbolaget-q5a.nu", IDN + .toASCII("www.f\u00E4rgbolaget.nu")); + assertEquals("www.xn--bcher-kva.de", IDN.toASCII("www.b\u00FCcher.de")); + assertEquals("www.xn--brndendekrlighed-vobh.com", IDN + .toASCII("www.br\u00E6ndendek\u00E6rlighed.com")); + assertEquals("www.xn--rksmrgs-5wao1o.se", IDN + .toASCII("www.r\u00E4ksm\u00F6rg\u00E5s.se")); + assertEquals("www.xn--9d0bm53a3xbzui.com", IDN + .toASCII("www.\uC608\uBE44\uAD50\uC0AC.com")); + assertEquals("xn--lck1c3crb1723bpq4a.com", IDN + .toASCII("\u7406\u5BB9\u30CA\u30AB\u30E0\u30E9.com")); + assertEquals("xn--l8je6s7a45b.org", IDN + .toASCII("\u3042\u30FC\u308B\u3044\u3093.org")); + assertEquals("www.xn--frjestadsbk-l8a.net", IDN + .toASCII("www.f\u00E4rjestadsbk.net")); + assertEquals("www.xn--mkitorppa-v2a.edu", IDN + .toASCII("www.m\u00E4kitorppa.edu")); + } + + /** + * @tests {@link java.net.IDN#toASCII(String, int)} + * + * @since 1.6 + */ + public void test_ToASCII_LString_I() { + try { + IDN.toASCII("www.br\u00E6ndendek\u00E6rlighed.com", + IDN.USE_STD3_ASCII_RULES); + } catch (IllegalArgumentException e) { + // expected + } + + try { + IDN.toASCII("www.r\u00E4ksm\u00F6rg\u00E5s.se", + IDN.USE_STD3_ASCII_RULES); + } catch (IllegalArgumentException e) { + // expected + } + + try { + IDN.toASCII("www.f\u00E4rjestadsbk.net", IDN.ALLOW_UNASSIGNED + | IDN.USE_STD3_ASCII_RULES); + } catch (IllegalArgumentException e) { + // expected + } + + assertEquals("www.xn--gwtq9nb2a.jp", IDN.toASCII( + "www.\u65E5\u672C\u5E73.jp", 0)); + assertEquals( + "www.xn--vckk7bxa0eza9ezc9d.com", + IDN + .toASCII( + "www.\u30CF\u30F3\u30C9\u30DC\u30FC\u30EB\u30B5\u30E0\u30BA.com", + 0)); + assertEquals("www.xn--frgbolaget-q5a.nu", IDN.toASCII( + "www.f\u00E4rgbolaget.nu", IDN.ALLOW_UNASSIGNED)); + assertEquals("www.xn--bcher-kva.de", IDN.toASCII("www.b\u00FCcher.de", + IDN.ALLOW_UNASSIGNED)); + assertEquals("www.google.com", IDN.toASCII("www.google\u002Ecom", + IDN.USE_STD3_ASCII_RULES)); + } + + /** + * @tests {@link java.net.IDN#toUnicode(String)} + * + * @since 1.6 + */ + public void test_ToUnicode_LString() { + try { + IDN.toUnicode(null); + fail("should throw NullPointerException"); + } catch (NullPointerException e) { + // expected + } + + assertEquals("", IDN.toUnicode("")); + assertEquals("www.bcher.de", IDN.toUnicode("www.bcher.de")); + assertEquals("www.b\u00FCcher.de", IDN.toUnicode("www.b\u00FCcher.de")); + assertEquals("www.\u65E5\u672C\u5E73.jp", IDN + .toUnicode("www.\u65E5\u672C\u5E73.jp")); + assertEquals("www.\u65E5\u672C\u5E73.jp", IDN.toUnicode("www\uFF0Exn--gwtq9nb2a\uFF61jp")); + assertEquals("www.\u65E5\u672C\u5E73.jp", IDN.toUnicode("www.xn--gwtq9nb2a.jp")); + } + + /** + * @tests {@link java.net.IDN#toUnicode(String, int)} + * + * @since 1.6 + */ + public void test_ToUnicode_LString_I() { + assertEquals("", IDN.toUnicode("", IDN.ALLOW_UNASSIGNED)); + assertEquals("www.f\u00E4rgbolaget.nu", IDN.toUnicode( + "www.f\u00E4rgbolaget.nu", IDN.USE_STD3_ASCII_RULES)); + assertEquals("www.r\u00E4ksm\u00F6rg\u00E5s.nu", IDN.toUnicode( + "www.r\u00E4ksm\u00F6rg\u00E5s\u3002nu", + IDN.USE_STD3_ASCII_RULES)); + // RI bug. It cannot parse "www.xn--gwtq9nb2a.jp" when + // USE_STD3_ASCII_RULES is set. + assertEquals("www.\u65E5\u672C\u5E73.jp", IDN.toUnicode( + "www\uFF0Exn--gwtq9nb2a\uFF61jp", IDN.USE_STD3_ASCII_RULES)); + + } +} Index: modules/luni/src/main/java/java/net/IDN.java =================================================================== --- modules/luni/src/main/java/java/net/IDN.java (revision 0) +++ modules/luni/src/main/java/java/net/IDN.java (revision 0) @@ -0,0 +1,159 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.net; + +import com.ibm.icu.text.IDNA; +import com.ibm.icu.text.StringPrepParseException; + +/** + * Internationalized domain names uses all characters from Unicode set, while + * traditional domain names uses only ASCII code. This class provides + * transformation between Unicode representation and ASCII Compatible Encoding + * (ACE) representation. Refer to RFC 3490 for detailed information. + * + * There are two flags used to adjust the transformation. + * + * 1. ALLOW_UNASSIGNED, if this flag is used, the domain name string to be + * converted can contain unassigned code points in Unicode 3.2. If the flag is + * not used, then no unassigned code points is not permitted. + * + * 2. USE_STD3_ASCII_RULES, if this flag is used, ASCII strings must compile + * with RFC 1122 and RFC 1123. It is an error if they don't compile. + * + * These flags can be logically OR'ed together. + * + * @since 1.6 + */ +public final class IDN { + + /** + * When set, allows IDN to process unassigned unicode points. + */ + public static final int ALLOW_UNASSIGNED = 1; + + /** + * When set, ASCII strings are checked against RFC 1122 & RFC 1123. + */ + public static final int USE_STD3_ASCII_RULES = 2; + + private IDN() { + // Do nothing + } + + /** + * Transform a Unicode String to ASCII Compatible Encoding String according + * to the algorithm defined in RFC 3490. + * + * Invoking this method is the same as invoking: + * + * toASCII(input, 0); + * + * @param input + * the string to be transformed + * @return the transformed String + * @throws IllegalArgumentException - + * if input is not compatible with RFC 3490 specification + */ + public static String toASCII(String input) { + return toASCII(input, 0); + } + + /** + * Transform a Unicode String to ASCII Compatible Encoding String according + * to the algorithm defined in RFC 3490. + * + * If the tramsformation fails, an IllegalArgumentException will be thrown. + * Then the input string is also not a valid IDN. + * + * The toASCII operation can handle both label and entire domain name. The + * entire domain name are always separated by dots. The dots are: \u002E + * (full stop), \u3002 (ideographic full stop), \uFF0E (fullwidth full + * stop), and \uFF61 (halfwidth ideographic full stop). If dots are also + * transformed, all of them will become \u002E (full stop). + * + * @param input + * the string to be transformed + * @param flag + * 0 or any logical OR of possible flags: ALLOW_UNASSIGNED, + * USE_STD3_ASCII_RULES + * @return the transformed String + * @throws IllegalArgumentException + * if the input string doesn't conform to RFC 3490 specification + */ + public static String toASCII(String input, int flag) { + String result; + int ICUFlag = convertFlags(flag); + try { + result = IDNA.convertIDNToASCII(input, ICUFlag).toString(); + } catch (StringPrepParseException e) { + throw new IllegalArgumentException(e.getMessage()); + } + return result; + } + + /** + * Translates a string from ASCII Compatible Encoding (ACE) to Unicode + * according to the algorithm defined in RFC 3490. + * + * ToUnicode never fails. In case of any error, the input string is returned + * unmodified. + * + * The toUnicode operation can handle both label and entire domain name. The + * entire domain name are always separated by dots. The dots are: \u002E + * (full stop), \u3002 (ideographic full stop), \uFF0E (fullwidth full + * stop), and \uFF61 (halfwidth ideographic full stop). + * + * @param input + * the string to be transformed + * @param flag + * 0 or any logical OR of possible flags: ALLOW_UNASSIGNED, + * USE_STD3_ASCII_RULES + * @return the transformed String + */ + public static String toUnicode(String input, int flag) { + String result; + int ICUFlag = convertFlags(flag); + try { + result = IDNA.convertIDNToUnicode(input, ICUFlag).toString(); + } catch (StringPrepParseException e) { + throw new IllegalArgumentException(e.getMessage()); + } + return result; + } + + private static int convertFlags(int flag) { + int ICUFlag = ((flag & IDN.ALLOW_UNASSIGNED) == 0)? 0:IDNA.ALLOW_UNASSIGNED; + ICUFlag |= ((flag & IDN.USE_STD3_ASCII_RULES) == 0)? 0:IDNA.USE_STD3_RULES; + return ICUFlag; + } + + /** + * Translates a string from ASCII Compatible Encoding (ACE) to Unicode + * according to the algorithm defined in RFC 3490. + * + * Invoking this method is the same as invoking: + * + * toUnicode(input, 0); + * + * @param input + * the string to be transformed + * @return the transformed String + */ + public static String toUnicode(String input) { + return toUnicode(input, 0); + } +}