Rewrite SafeUriHostedModeUtils#isValid without regexp to workaround what looks like a bug in the Sun/Oracle JVM (error not reproduced with OpenJDK). http://gwt-code-reviews.appspot.com/1449814/ Author: tbroyer Review by: xtof, jlabanca git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@10324 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/safehtml/shared/SafeUriHostedModeUtils.java b/user/src/com/google/gwt/safehtml/shared/SafeUriHostedModeUtils.java index 7b3dbe2..0ebb8e3 100644 --- a/user/src/com/google/gwt/safehtml/shared/SafeUriHostedModeUtils.java +++ b/user/src/com/google/gwt/safehtml/shared/SafeUriHostedModeUtils.java
@@ -22,38 +22,33 @@ import java.net.URISyntaxException; /** - * SafeUri utilities whose implementation differs between Development and - * Production Mode. + * SafeUri utilities whose implementation differs between Development and Production Mode. * * <p> - * This class has a super-source peer that provides the Production Mode - * implementation. + * This class has a super-source peer that provides the Production Mode implementation. * * <p> - * Do not use this class - it is used for implementation only, and its methods - * may change in the future. + * Do not use this class - it is used for implementation only, and its methods may change in the + * future. */ public class SafeUriHostedModeUtils { /** - * All valid Web Addresses, i.e. the href-ucschar production from RFC 3987bis. + * All valid Web Addresses discrete characters, i.e. the reserved, iunreserved, href-ucschar, and + * href-pct-form productions from RFC 3986 and RFC 3987bis, with the exception of character + * ranges. * * @see <a href="http://tools.ietf.org/html/rfc3986#section-2">RFC 3986</a> * @see <a href="http://tools.ietf.org/html/draft-ietf-iri-3987bis-05#section-7.2">RFC 3987bis Web Addresses</a> */ - static final String HREF_UCSCHAR = "(" - + "[" - + ":/?#\\[\\]@!$&'()*+,;=" // reserved - + "a-zA-Z0-9\\-._~" // iunreserved - + " <>\"{}|\\\\^`\u0000-\u001F\u001F-\uD7FF\uE000-\uFFFD" // href-ucschar - + "]" - + "|" - + "[\uD800-\uDBFF][\uDC00-\uDFFF]" // surrogate pairs - + ")*"; + static final String HREF_DISCRETE_UCSCHAR = ":/?#[]@!$&'()*+,;=" // reserved + + "-._~" // iunreserved + + " <>\"{}|\\^`" // href-ucschar + + "%"; // href-pct-form /** - * Name of system property that if set, enables checks in server-side code - * (even if assertions are disabled). + * Name of system property that if set, enables checks in server-side code (even if assertions are + * disabled). */ public static final String FORCE_CHECK_VALID_URI = "com.google.gwt.safehtml.ForceCheckValidUri"; @@ -64,6 +59,37 @@ } /** + * Tests whether all characters in the given URI are valid Web Addresses characters. + */ + // @VisibleForTesting + public static boolean isValidUriCharset(String uri) { + int len = uri.length(); + int i = 0; + while (i < len) { + int codePoint = uri.codePointAt(i); + i += Character.charCount(codePoint); + if (Character.isSupplementaryCodePoint(codePoint)) { + continue; + } + if (HREF_DISCRETE_UCSCHAR.indexOf(codePoint) >= 0) { + continue; + } + // iunreserved ranges + if (('a' <= codePoint && codePoint <= 'z') || ('A' <= codePoint && codePoint <= 'Z') + || ('0' <= codePoint && codePoint <= '9')) { + continue; + } + // href-ucschar ranges + if ((0 <= codePoint && codePoint <= 0x1F) || (0x7F <= codePoint && codePoint <= 0xD7FF) + || (0xE000 <= codePoint && codePoint <= 0xFFFD)) { + continue; + } + return false; + } + return true; + } + + /** * Checks if the provided URI is a valid Web Address (per RFC 3987bis). * * @param uri the URL to check @@ -77,9 +103,8 @@ } /** - * Sets a global flag that controls whether or not - * {@link #maybeCheckValidUri(String)} should perform its check in a - * server-side environment. + * Sets a global flag that controls whether or not {@link #maybeCheckValidUri(String)} should + * perform its check in a server-side environment. * * @param check if true, perform server-side checks. */ @@ -88,9 +113,8 @@ } /** - * Sets a global flag that controls whether or not - * {@link #maybeCheckValidUri(String)} should perform its check in a - * server-side environment from the value of the {@value + * Sets a global flag that controls whether or not {@link #maybeCheckValidUri(String)} should + * perform its check in a server-side environment from the value of the {@value * FORCE_CHECK_VALID_URI} property. */ // The following annotation causes javadoc to crash on Mac OS X 10.5.8, @@ -104,17 +128,12 @@ } private static boolean isValidUri(String uri) { - // TODO(xtof): The regex appears to cause stack overflows in some cases. - // Investigate and re-enable. - // if (!uri.matches(HREF_UCSCHAR)) { - // return false; - // } - /* - * pre-process to turn href-ucschars into ucschars, and encode to URI. - * - * This is done by encoding everything, and decoding back "%25" to "%". - */ - uri = UriUtils.encode(uri).replace("%25", "%"); + if (!isValidUriCharset(uri)) { + return false; + } + + // pre-process to turn href-ucschars into ucschars, and encode to URI. + uri = UriUtils.encodeAllowEscapes(uri); try { new URI(uri); return true;
diff --git a/user/super/com/google/gwt/safehtml/super/com/google/gwt/safehtml/shared/SafeUriHostedModeUtils.java b/user/super/com/google/gwt/safehtml/super/com/google/gwt/safehtml/shared/SafeUriHostedModeUtils.java index 849ac5b..2112624 100644 --- a/user/super/com/google/gwt/safehtml/super/com/google/gwt/safehtml/shared/SafeUriHostedModeUtils.java +++ b/user/super/com/google/gwt/safehtml/super/com/google/gwt/safehtml/shared/SafeUriHostedModeUtils.java
@@ -23,13 +23,14 @@ // Unused in super-source; only defined to avoid compiler warnings public static final String FORCE_CHECK_VALID_URI = null; - static final String HREF_UCSCHAR = null; + static final String HREF_DISCRETE_UCSCHAR = null; public static void maybeCheckValidUri(String uri) { // This check is a noop in web mode. } // Unused in super-source; only defined to avoid compiler warnings + public static boolean isValidUriCharset(String uri) { return true; } public static void setForceCheckValidUri(boolean check) { } - static void setForceCheckValidUriFromProperty() { } + public static void setForceCheckValidUriFromProperty() { } }
diff --git a/user/test/com/google/gwt/safehtml/SafeHtmlGwtSuite.java b/user/test/com/google/gwt/safehtml/SafeHtmlGwtSuite.java index e50b5ce..0ed7951 100644 --- a/user/test/com/google/gwt/safehtml/SafeHtmlGwtSuite.java +++ b/user/test/com/google/gwt/safehtml/SafeHtmlGwtSuite.java
@@ -21,6 +21,8 @@ import com.google.gwt.safehtml.shared.GwtSafeHtmlHostedModeUtilsTest; import com.google.gwt.safehtml.shared.GwtSafeHtmlStringTest; import com.google.gwt.safehtml.shared.GwtSafeHtmlUtilsTest; +import com.google.gwt.safehtml.shared.GwtSafeUriHostedModeUtilsTest; +import com.google.gwt.safehtml.shared.GwtUriUtilsTest; import junit.framework.Test; @@ -37,6 +39,8 @@ suite.addTestSuite(GwtSafeHtmlBuilderTest.class); suite.addTestSuite(SafeHtmlTemplatesTest.class); suite.addTestSuite(GwtSafeHtmlHostedModeUtilsTest.class); + suite.addTestSuite(GwtUriUtilsTest.class); + suite.addTestSuite(GwtSafeUriHostedModeUtilsTest.class); return suite; }
diff --git a/user/test/com/google/gwt/safehtml/SafeHtmlJreSuite.java b/user/test/com/google/gwt/safehtml/SafeHtmlJreSuite.java index aeea6a7..66aedf5 100644 --- a/user/test/com/google/gwt/safehtml/SafeHtmlJreSuite.java +++ b/user/test/com/google/gwt/safehtml/SafeHtmlJreSuite.java
@@ -18,6 +18,7 @@ import com.google.gwt.safehtml.rebind.HtmlTemplateParserTest; import com.google.gwt.safehtml.rebind.ParsedHtmlTemplateTest; import com.google.gwt.safehtml.server.SafeHtmlHostedModeUtilsTest; +import com.google.gwt.safehtml.server.SafeUriHostedModeUtilsTest; import com.google.gwt.safehtml.server.UriUtilsTest; import com.google.gwt.safehtml.shared.SafeHtmlBuilderTest; import com.google.gwt.safehtml.shared.SafeHtmlStringTest; @@ -43,6 +44,8 @@ suite.addTestSuite(HtmlTemplateParserTest.class); suite.addTestSuite(ParsedHtmlTemplateTest.class); suite.addTestSuite(SafeHtmlHostedModeUtilsTest.class); + suite.addTestSuite(SafeUriHostedModeUtilsTest.class); + suite.addTestSuite(com.google.gwt.safehtml.shared.UriUtilsTest.class); return suite; }
diff --git a/user/test/com/google/gwt/safehtml/server/SafeUriHostedModeUtilsTest.java b/user/test/com/google/gwt/safehtml/server/SafeUriHostedModeUtilsTest.java new file mode 100644 index 0000000..dd640d8 --- /dev/null +++ b/user/test/com/google/gwt/safehtml/server/SafeUriHostedModeUtilsTest.java
@@ -0,0 +1,39 @@ +/* + * Copyright 2011 Google Inc. + * + * Licensed 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 com.google.gwt.safehtml.server; + +import com.google.gwt.safehtml.shared.GwtSafeUriHostedModeUtilsTest; +import com.google.gwt.safehtml.shared.SafeUriHostedModeUtils; + +/** + * JUnit tests for {@link SafeUriHostedModeUtils}. + */ +public class SafeUriHostedModeUtilsTest extends GwtSafeUriHostedModeUtilsTest { + + // This forces a GWTTestCase to run as a vanilla JUnit TestCase. + @Override + public String getModuleName() { + return null; + } + + @Override + protected void gwtSetUp() throws Exception { + super.gwtSetUp(); + // Since we can't assume assertions are enabled, force + // SafeUriHostedModeUtils#maybeCheckValidUri to perform its check when running in JRE. + SafeUriHostedModeUtils.setForceCheckValidUri(true); + } +}
diff --git a/user/test/com/google/gwt/safehtml/shared/GwtSafeHtmlHostedModeUtilsTest.java b/user/test/com/google/gwt/safehtml/shared/GwtSafeHtmlHostedModeUtilsTest.java index 9e7fd1c..fcd5f26 100644 --- a/user/test/com/google/gwt/safehtml/shared/GwtSafeHtmlHostedModeUtilsTest.java +++ b/user/test/com/google/gwt/safehtml/shared/GwtSafeHtmlHostedModeUtilsTest.java
@@ -30,8 +30,7 @@ public void testMaybeCheckCompleteHtml() { if (GWT.isProdMode()) { - // SafeHtmlHostedModeUtils#isCompleteHtml always returns true in - // prod mode + // SafeHtmlHostedModeUtils#isCompleteHtml always returns true in prod mode SafeHtmlHostedModeUtils.maybeCheckCompleteHtml("<foo>blah"); SafeHtmlHostedModeUtils.maybeCheckCompleteHtml("baz<em>foo</em> <x"); } else { @@ -48,27 +47,26 @@ assertCheckCompleteHtmlFails("baz<em>foo</em> <x a=\"b\""); assertCheckCompleteHtmlFails("baz<em>foo</em> <x a=\"b\" "); - SafeHtmlHostedModeUtils.maybeCheckCompleteHtml( - "baz<em>foo</em> <x a=\"b\"> "); - SafeHtmlHostedModeUtils.maybeCheckCompleteHtml( - "baz<em>foo</em> <x a=\"b\">sadf"); - SafeHtmlHostedModeUtils.maybeCheckCompleteHtml( - "baz<em>foo</em> <x a=\"b\">"); - SafeHtmlHostedModeUtils.maybeCheckCompleteHtml( - "baz<em>foo</em> <x a=\"b\"/>"); - SafeHtmlHostedModeUtils.maybeCheckCompleteHtml( - "baz<em>foo</em> <x a=\"b\"/>bbb"); + SafeHtmlHostedModeUtils.maybeCheckCompleteHtml("baz<em>foo</em> <x a=\"b\"> "); + SafeHtmlHostedModeUtils.maybeCheckCompleteHtml("baz<em>foo</em> <x a=\"b\">sadf"); + SafeHtmlHostedModeUtils.maybeCheckCompleteHtml("baz<em>foo</em> <x a=\"b\">"); + SafeHtmlHostedModeUtils.maybeCheckCompleteHtml("baz<em>foo</em> <x a=\"b\"/>"); + SafeHtmlHostedModeUtils.maybeCheckCompleteHtml("baz<em>foo</em> <x a=\"b\"/>bbb"); } } private void assertCheckCompleteHtmlFails(String html) { try { SafeHtmlHostedModeUtils.maybeCheckCompleteHtml(html); - fail("maybeCheckCompleteHtml failed to throw exception for: " + html); } catch (IllegalArgumentException e) { // expected + return; } catch (AssertionError e) { // expected + return; } + // This must be outside the try/catch, as it throws an AssertionFailedError which, in some + // versions of JUnit, extends AssertionError + fail("maybeCheckCompleteHtml failed to throw exception for: " + html); } }
diff --git a/user/test/com/google/gwt/safehtml/shared/GwtSafeUriHostedModeUtilsTest.java b/user/test/com/google/gwt/safehtml/shared/GwtSafeUriHostedModeUtilsTest.java new file mode 100644 index 0000000..ae95e0e --- /dev/null +++ b/user/test/com/google/gwt/safehtml/shared/GwtSafeUriHostedModeUtilsTest.java
@@ -0,0 +1,92 @@ +/* + * Copyright 2011 Google Inc. + * + * Licensed 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 com.google.gwt.safehtml.shared; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.junit.client.GWTTestCase; + +/** + * GWT Unit tests for {@link SafeUriHostedModeUtils}. + */ +public class GwtSafeUriHostedModeUtilsTest extends GWTTestCase { + + @Override + public String getModuleName() { + return "com.google.gwt.safehtml.SafeHtmlTestsModule"; + } + + public void testIsValidUriCharset() { + if (GWT.isProdMode()) { + // isValidUriCharset always returns true in prod mode. + // Hence we short-circuit this test in prod mode. + return; + } + assertTrue(SafeUriHostedModeUtils.isValidUriCharset("")); + assertTrue(SafeUriHostedModeUtils.isValidUriCharset("blah")); + assertTrue(SafeUriHostedModeUtils.isValidUriCharset("blah<>foo")); + assertTrue(SafeUriHostedModeUtils.isValidUriCharset("blah%foo")); + assertTrue(SafeUriHostedModeUtils.isValidUriCharset("blah%25foo")); + assertTrue(SafeUriHostedModeUtils.isValidUriCharset(GwtUriUtilsTest.CONSTANT_URL)); + assertTrue(SafeUriHostedModeUtils.isValidUriCharset(GwtUriUtilsTest.MAILTO_URL)); + assertTrue(SafeUriHostedModeUtils.isValidUriCharset(GwtUriUtilsTest.EMPTY_GIF_DATA_URL)); + assertTrue(SafeUriHostedModeUtils.isValidUriCharset(GwtUriUtilsTest.LONG_DATA_URL)); + assertTrue(SafeUriHostedModeUtils.isValidUriCharset(GwtUriUtilsTest.JAVASCRIPT_URL)); + + assertFalse(SafeUriHostedModeUtils + .isValidUriCharset(GwtUriUtilsTest.INVALID_URL_UNPAIRED_SURROGATE)); + } + + public void testMaybeCheckValidUri() { + if (GWT.isProdMode()) { + // SafeUriHostedModeUtils#maybeCheckValidUri is a no-op in prod mode + SafeUriHostedModeUtils.maybeCheckValidUri(GwtUriUtilsTest.INVALID_URL_UNPAIRED_SURROGATE); + } else { + SafeUriHostedModeUtils.maybeCheckValidUri(""); + SafeUriHostedModeUtils.maybeCheckValidUri("blah"); + SafeUriHostedModeUtils.maybeCheckValidUri("blah<>foo"); + SafeUriHostedModeUtils.maybeCheckValidUri("blah%foo"); + SafeUriHostedModeUtils.maybeCheckValidUri("blah%25foo"); + SafeUriHostedModeUtils.maybeCheckValidUri(GwtUriUtilsTest.CONSTANT_URL); + SafeUriHostedModeUtils.maybeCheckValidUri(GwtUriUtilsTest.MAILTO_URL); + SafeUriHostedModeUtils.maybeCheckValidUri(GwtUriUtilsTest.EMPTY_GIF_DATA_URL); + SafeUriHostedModeUtils.maybeCheckValidUri(GwtUriUtilsTest.LONG_DATA_URL); + SafeUriHostedModeUtils.maybeCheckValidUri(GwtUriUtilsTest.JAVASCRIPT_URL); + + assertCheckValidUriFails(GwtUriUtilsTest.INVALID_URL_UNPAIRED_SURROGATE); + assertCheckValidUriFails("http://"); + + if (GWT.isClient()) { + SafeUriHostedModeUtils.maybeCheckValidUri(GWT.getModuleBaseURL()); + SafeUriHostedModeUtils.maybeCheckValidUri(GWT.getHostPageBaseURL()); + } + } + } + + private void assertCheckValidUriFails(String uri) { + try { + SafeUriHostedModeUtils.maybeCheckValidUri(uri); + } catch (IllegalArgumentException e) { + // expected + return; + } catch (AssertionError e) { + // expected + return; + } + // This must be outside the try/catch, as it throws an AssertionFailedError which, in some + // versions of JUnit, extends AssertionError + fail("maybeCheckValidUri failed to throw exception for: " + uri); + } +}
diff --git a/user/test/com/google/gwt/safehtml/shared/GwtUriUtilsTest.java b/user/test/com/google/gwt/safehtml/shared/GwtUriUtilsTest.java index f76c66f..150cc6b 100644 --- a/user/test/com/google/gwt/safehtml/shared/GwtUriUtilsTest.java +++ b/user/test/com/google/gwt/safehtml/shared/GwtUriUtilsTest.java
@@ -23,12 +23,29 @@ */ public class GwtUriUtilsTest extends GWTTestCase { - private static final String JAVASCRIPT_URL = "javascript:alert('BOOM!');"; - private static final String MAILTO_URL = "mailto:foo@example.com"; - private static final String CONSTANT_URL = - "http://gwt.google.com/samples/Showcase/Showcase.html?locale=fr#!CwCheckBox"; - private static final String EMPTY_GIF_DATA_URL = - "data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw=="; + static final String INVALID_URL_UNPAIRED_SURROGATE = "a\uD800b"; + static final String JAVASCRIPT_URL = "javascript:alert('BOOM!');"; + static final String MAILTO_URL = "mailto:foo@example.com?subject=Hello%20world!"; + static final String CONSTANT_URL = + "http://gwt.google.com/samples/Showcase/Showcase.html?locale=fr#!CwCheckBox"; + static final String EMPTY_GIF_DATA_URL = + "data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw=="; + static final String LONG_DATA_URL = + "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAMAAADzjKfhAAAAGXRFWHRTb2Z0d2FyZQ" + + "BBZG9iZSBJbWFnZVJlYWR5ccllPAAAAwBQTFRFZmZm////AgICAwMDBAQEBQUFBgYGBwcHCAgICQkJCgoKCwsL" + + "DAwMDQ0NDg4ODw8PEBAQEREREhISExMTFBQUFRUVFhYWFxcXGBgYGRkZGhoaGxsbHBwcHR0dHh4eHx8fICAgIS" + + "EhIiIiIyMjJCQkJSUlJiYmJycnKCgoKSkpKioqKysrLCwsLS0tLi4uLy8vMDAwMTExMjIyMzMzNDQ0NTU1NjY2" + + "Nzc3ODg4OTk5Ojo6Ozs7PDw8PT09Pj4+Pz8/QEBAQUFBQkJCQ0NDRERERUVFRkZGR0dHSEhISUlJSkpKS0tLTE" + + "xMTU1NTk5OT09PUFBQUVFRUlJSU1NTVFRUVVVVVlZWV1dXWFhYWVlZWlpaW1tbXFxcXV1dXl5eX19fYGBgYWFh" + + "YmJiY2NjZGRkZWVlZmZmZ2dnaGhoaWlpampqa2trbGxsbW1tbm5ub29vcHBwcXFxcnJyc3NzdHR0dXV1dnZ2d3" + + "d3eHh4eXl5enp6e3t7fHx8fX19fn5+f39/gICAgYGBgoKCg4ODhISEhYWFhoaGh4eHiIiIiYmJioqKi4uLjIyM" + + "jY2Njo6Oj4+PkJCQkZGRkpKSk5OTlJSUlZWVlpaWl5eXmJiYmZmZmpqam5ubnJycnZ2dnp6en5+foKCgoaGhoq" + + "Kio6OjpKSkpaWlpqamp6enqKioqampqqqqq6urrKysra2trq6ur6+vsLCwsbGxsrKys7OztLS0tbW1tra2t7e3" + + "uLi4ubm5urq6u7u7vLy8vb29vr6+v7+/wMDAwcHBwsLCw8PDxMTExcXFxsbGx8fHyMjIycnJysrKy8vLzMzMzc" + + "3Nzs7Oz8/P0NDQ0dHR0tLS09PT1NTU1dXV1tbW19fX2NjY2dnZ2tra29vb3Nzc3d3d3t7e39/f4ODg4eHh4uLi" + + "4+Pj5OTk5eXl5ubm5+fn6Ojo6enp6urq6+vr7Ozs7e3t7u7u7+/v8PDw8fHx8vLy8/Pz9PT09fX19vb29/f3+P" + + "j4+fn5+vr6+/v7/Pz8/f39/v7+////AADF2QAAAAJ0Uk5T/wDltzBKAAAAH0lEQVR42mJghAAGGJ0GAQyMYAok" + + "DqLA8mlI6gACDAC8pAaCn/ezogAAAABJRU5ErkJggg=="; public void testEncode_noEscape() { StringBuilder sb = new StringBuilder(UriUtils.DONT_NEED_ENCODING); @@ -80,6 +97,7 @@ assertEquals(CONSTANT_URL, UriUtils.fromTrustedString(CONSTANT_URL).asString()); assertEquals(MAILTO_URL, UriUtils.fromTrustedString(MAILTO_URL).asString()); assertEquals(EMPTY_GIF_DATA_URL, UriUtils.fromTrustedString(EMPTY_GIF_DATA_URL).asString()); + assertEquals(LONG_DATA_URL, UriUtils.fromTrustedString(LONG_DATA_URL).asString()); assertEquals(JAVASCRIPT_URL, UriUtils.fromTrustedString(JAVASCRIPT_URL).asString()); if (GWT.isClient()) { assertEquals(GWT.getModuleBaseURL(), @@ -96,7 +114,7 @@ return; } try { - SafeUri u = UriUtils.fromTrustedString("a\uD800b"); + SafeUri u = UriUtils.fromTrustedString(INVALID_URL_UNPAIRED_SURROGATE); fail("Should have thrown IllegalArgumentException"); } catch (IllegalArgumentException e) { // expected @@ -110,7 +128,8 @@ assertEquals(EMPTY_GIF_DATA_URL, UriUtils.unsafeCastFromUntrustedString(EMPTY_GIF_DATA_URL) .asString()); assertEquals(JAVASCRIPT_URL, UriUtils.unsafeCastFromUntrustedString(JAVASCRIPT_URL).asString()); - assertEquals("a\uD800b", UriUtils.unsafeCastFromUntrustedString("a\uD800b").asString()); + assertEquals(INVALID_URL_UNPAIRED_SURROGATE, + UriUtils.unsafeCastFromUntrustedString(INVALID_URL_UNPAIRED_SURROGATE).asString()); if (GWT.isClient()) { assertEquals(GWT.getModuleBaseURL(), UriUtils.unsafeCastFromUntrustedString( GWT.getModuleBaseURL()).asString());