From b25462ddf9dcbf0bdc940e7ab1c796520d694093 Mon Sep 17 00:00:00 2001 From: Arjen Poutsma Date: Mon, 19 Apr 2010 08:28:10 +0000 Subject: [PATCH] SPR-7107 - RestTemplate/UriTemplate/UriUtils improperly encoding UTF-8 --- .../springframework/web/util/UriUtils.java | 27 +++++++++++++------ .../client/RestTemplateIntegrationTests.java | 2 +- .../web/util/UriTemplateTests.java | 4 +-- .../web/util/UriUtilsTest.java | 11 ++++---- 4 files changed, 28 insertions(+), 16 deletions(-) diff --git a/org.springframework.web/src/main/java/org/springframework/web/util/UriUtils.java b/org.springframework.web/src/main/java/org/springframework/web/util/UriUtils.java index 4b023395e3d..67da06b8064 100644 --- a/org.springframework.web/src/main/java/org/springframework/web/util/UriUtils.java +++ b/org.springframework.web/src/main/java/org/springframework/web/util/UriUtils.java @@ -424,22 +424,33 @@ public abstract class UriUtils { throws UnsupportedEncodingException { Assert.notNull(source, "'source' must not be null"); Assert.hasLength(encoding, "'encoding' must not be empty"); - ByteArrayOutputStream bos = new ByteArrayOutputStream(source.length() * 2); - for (int i = 0; i < source.length(); i++) { - int ch = source.charAt(i); - if (notEncoded.get(ch)) { - bos.write(ch); + byte[] bytes = encode(source.getBytes(encoding), notEncoded); + return new String(bytes, "US-ASCII"); + } + + private static byte[] encode(byte[] source, BitSet notEncoded) { + Assert.notNull(source, "'source' must not be null"); + + ByteArrayOutputStream bos = new ByteArrayOutputStream(source.length * 2); + + for (int i = 0; i < source.length; i++) { + int b = source[i]; + if (b < 0) { + b += 256; + } + if (notEncoded.get(b)) { + bos.write(b); } else { bos.write('%'); - char hex1 = Character.toUpperCase(Character.forDigit((ch >> 4) & 0xF, 16)); - char hex2 = Character.toUpperCase(Character.forDigit(ch & 0xF, 16)); + char hex1 = Character.toUpperCase(Character.forDigit((b >> 4) & 0xF, 16)); + char hex2 = Character.toUpperCase(Character.forDigit(b & 0xF, 16)); bos.write(hex1); bos.write(hex2); } } - return new String(bos.toByteArray(), encoding); + return bos.toByteArray(); } /** diff --git a/org.springframework.web/src/test/java/org/springframework/web/client/RestTemplateIntegrationTests.java b/org.springframework.web/src/test/java/org/springframework/web/client/RestTemplateIntegrationTests.java index 78fa26c6f04..5f795306a30 100644 --- a/org.springframework.web/src/test/java/org/springframework/web/client/RestTemplateIntegrationTests.java +++ b/org.springframework.web/src/test/java/org/springframework/web/client/RestTemplateIntegrationTests.java @@ -165,7 +165,7 @@ public class RestTemplateIntegrationTests { @Test public void uri() throws InterruptedException, URISyntaxException { String result = template.getForObject(URI + "/uri/{query}", String.class, "Z\u00fcrich"); - assertEquals("Invalid request URI", "/uri/Z%FCrich", result); + assertEquals("Invalid request URI", "/uri/Z%C3%BCrich", result); result = template.getForObject(URI + "/uri/query={query}", String.class, "foo@bar"); assertEquals("Invalid request URI", "/uri/query=foo@bar", result); diff --git a/org.springframework.web/src/test/java/org/springframework/web/util/UriTemplateTests.java b/org.springframework.web/src/test/java/org/springframework/web/util/UriTemplateTests.java index 58bafcd6fbf..7c7c07833a2 100644 --- a/org.springframework.web/src/test/java/org/springframework/web/util/UriTemplateTests.java +++ b/org.springframework.web/src/test/java/org/springframework/web/util/UriTemplateTests.java @@ -87,9 +87,9 @@ public class UriTemplateTests { @Test public void expandEncoded() throws Exception { - UriTemplate template = new UriTemplate("http://example.com//hotel list/{hotel}"); + UriTemplate template = new UriTemplate("http://example.com/hotel list/{hotel}"); URI result = template.expand("Z\u00fcrich"); - assertEquals("Invalid expanded template", new URI("http://example.com//hotel%20list/Z%FCrich"), result); + assertEquals("Invalid expanded template", new URI("http://example.com/hotel%20list/Z%C3%BCrich"), result); } @Test diff --git a/org.springframework.web/src/test/java/org/springframework/web/util/UriUtilsTest.java b/org.springframework.web/src/test/java/org/springframework/web/util/UriUtilsTest.java index a3713d1efa2..36fdae0a396 100644 --- a/org.springframework.web/src/test/java/org/springframework/web/util/UriUtilsTest.java +++ b/org.springframework.web/src/test/java/org/springframework/web/util/UriUtilsTest.java @@ -53,7 +53,7 @@ public class UriUtilsTest { public void encodePath() throws UnsupportedEncodingException { assertEquals("Invalid encoded result", "/foo/bar", UriUtils.encodePath("/foo/bar", ENC)); assertEquals("Invalid encoded result", "/foo%20bar", UriUtils.encodePath("/foo bar", ENC)); - assertEquals("Invalid encoded result", "/Z%FCrich", UriUtils.encodePath("/Z\u00fcrich", ENC)); + assertEquals("Invalid encoded result", "/Z%C3%BCrich", UriUtils.encodePath("/Z\u00fcrich", ENC)); } @Test @@ -67,6 +67,7 @@ public class UriUtilsTest { assertEquals("Invalid encoded result", "foobar", UriUtils.encodeQuery("foobar", ENC)); assertEquals("Invalid encoded result", "foo%20bar", UriUtils.encodeQuery("foo bar", ENC)); assertEquals("Invalid encoded result", "foobar/+", UriUtils.encodeQuery("foobar/+", ENC)); + assertEquals("Invalid encoded result", "T%C5%8Dky%C5%8D", UriUtils.encodeQuery("T\u014dky\u014d", ENC)); } @Test @@ -101,8 +102,8 @@ public class UriUtilsTest { UriUtils.encodeUri("http://www.ietf.org/rfc/rfc3986.txt", ENC)); assertEquals("Invalid encoded URI", "https://www.ietf.org/rfc/rfc3986.txt", UriUtils.encodeUri("https://www.ietf.org/rfc/rfc3986.txt", ENC)); - assertEquals("Invalid encoded URI", "http://www.google.com/?q=z%FCrich", - UriUtils.encodeUri("http://www.google.com/?q=z\u00fcrich", ENC)); + assertEquals("Invalid encoded URI", "http://www.google.com/?q=Z%C3%BCrich", + UriUtils.encodeUri("http://www.google.com/?q=Z\u00fcrich", ENC)); assertEquals("Invalid encoded URI", "http://arjen:foobar@java.sun.com:80/javase/6/docs/api/java/util/BitSet.html?foo=bar#and(java.util.BitSet)", UriUtils.encodeUri( @@ -130,8 +131,8 @@ public class UriUtilsTest { UriUtils.encodeHttpUrl("http://www.ietf.org/rfc/rfc3986.txt", ENC)); assertEquals("Invalid encoded URI", "https://www.ietf.org/rfc/rfc3986.txt", UriUtils.encodeHttpUrl("https://www.ietf.org/rfc/rfc3986.txt", ENC)); - assertEquals("Invalid encoded HTTP URL", "http://www.google.com/?q=z%FCrich", - UriUtils.encodeHttpUrl("http://www.google.com/?q=z\u00fcrich", ENC)); + assertEquals("Invalid encoded HTTP URL", "http://www.google.com/?q=Z%C3%BCrich", + UriUtils.encodeHttpUrl("http://www.google.com/?q=Z\u00fcrich", ENC)); assertEquals("Invalid encoded HTTP URL", "http://arjen:foobar@java.sun.com:80/javase/6/docs/api/java/util/BitSet.html?foo=bar", UriUtils.encodeHttpUrl(