Fix for issue 3374. This patch adds overloads of encodeComponent and
decodeComponent to deal differently with spaces (keeping them as %20
rather than replacing them with +) and therefore allow their use for
path segments (useful when using "RESTful services").
http://gwt-code-reviews.appspot.com/87806
Patch by: t.broyer@gmail.com
Review by: rjrjr@google.com
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@6470 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/http/client/URL.java b/user/src/com/google/gwt/http/client/URL.java
index 79d3697..b498447 100644
--- a/user/src/com/google/gwt/http/client/URL.java
+++ b/user/src/com/google/gwt/http/client/URL.java
@@ -58,6 +58,25 @@
}
/**
+ * Returns a string where all URL component escape sequences have been
+ * converted back to their original character representations.
+ *
+ * @param encodedURLComponent string containing encoded URL component
+ * sequences
+ * @param fromQueryString if <code>true</code>, +'s will be turned into
+ * spaces, otherwise they'll be kept as-is.
+ * @return string with no encoded URL component encoded sequences
+ *
+ * @throws NullPointerException if encodedURLComponent is <code>null</code>
+ */
+ public static String decodeComponent(String encodedURLComponent,
+ boolean fromQueryString) {
+ StringValidator.throwIfNull("encodedURLComponent", encodedURLComponent);
+ return fromQueryString ? decodeComponentImpl(encodedURLComponent)
+ : decodeComponentRawImpl(encodedURLComponent);
+ }
+
+ /**
* Returns a string where all characters that are not valid for a complete URL
* have been escaped. The escaping of a character is done by converting it
* into its UTF-8 encoding and then encoding each of the resulting bytes as a
@@ -131,6 +150,44 @@
return encodeComponentImpl(decodedURLComponent);
}
+ /**
+ * Returns a string where all characters that are not valid for a URL
+ * component have been escaped. The escaping of a character is done by
+ * converting it into its UTF-8 encoding and then encoding each of the
+ * resulting bytes as a %xx hexadecimal escape sequence.
+ *
+ * <p>
+ * The following character sets are <em>not</em> escaped by this method:
+ * <ul>
+ * <li>ASCII digits or letters</li>
+ * <li>ASCII punctuation characters: <pre>- _ . ! ~ * ' ( )</pre></li>
+ * </ul>
+ * </p>
+ *
+ * <p>
+ * Notice that this method <em>does</em> encode the URL component delimiter
+ * characters:<blockquote>
+ *
+ * <pre>
+ * ; / ? : & = + $ , #
+ * </pre>
+ *
+ * </blockquote>
+ * </p>
+ *
+ * @param decodedURLComponent a string containing invalid URL characters
+ * @param queryStringSpaces if <code>true</code>, spaces will be encoded as +'s.
+ * @return a string with all invalid URL characters escaped
+ *
+ * @throws NullPointerException if decodedURLComponent is <code>null</code>
+ */
+ public static String encodeComponent(String decodedURLComponent,
+ boolean queryStringSpaces) {
+ StringValidator.throwIfNull("decodedURLComponent", decodedURLComponent);
+ return queryStringSpaces ? encodeComponentImpl(decodedURLComponent)
+ : encodeComponentRawImpl(decodedURLComponent);
+ }
+
/*
* Note: this method will convert the space character escape short form, '+',
* into a space.
@@ -140,6 +197,10 @@
return decodeURIComponent(encodedURLComponent.replace(regexp, "%20"));
}-*/;
+ private static native String decodeComponentRawImpl(String encodedURLComponent) /*-{
+ return decodeURIComponent(encodedURLComponent);
+ }-*/;
+
private static native String decodeImpl(String encodedURL) /*-{
return decodeURI(encodedURL);
}-*/;
@@ -153,6 +214,10 @@
return encodeURIComponent(decodedURLComponent).replace(regexp, "+");
}-*/;
+ private static native String encodeComponentRawImpl(String decodedURLComponent) /*-{
+ return encodeURIComponent(decodedURLComponent);
+ }-*/;
+
private static native String encodeImpl(String decodedURL) /*-{
return encodeURI(decodedURL);
}-*/;
diff --git a/user/test/com/google/gwt/http/client/URLTest.java b/user/test/com/google/gwt/http/client/URLTest.java
index 3b07b7b..417e888 100644
--- a/user/test/com/google/gwt/http/client/URLTest.java
+++ b/user/test/com/google/gwt/http/client/URLTest.java
@@ -22,10 +22,11 @@
*/
public class URLTest extends GWTTestCase {
- private final String DECODED_URL = "http://www.foo \u00E9 bar.com/1_!~*'();/?@&=+$,#";
- private final String DECODED_URL_COMPONENT = "-_.!~*'():/#?@ \u00E9 ";
- private final String ENCODED_URL = "http://www.foo%20%C3%A9%20bar.com/1_!~*'();/?@&=+$,#";
- private final String ENCODED_URL_COMPONENT = "-_.!~*'()%3A%2F%23%3F%40+%C3%A9+";
+ private final String DECODED_URL = "http://www.foo \u00E9+bar.com/1_!~*'();/?@&=+$,#";
+ private final String DECODED_URL_COMPONENT = "-_.!~*'():/#?@ \u00E9+";
+ private final String ENCODED_URL = "http://www.foo%20%C3%A9+bar.com/1_!~*'();/?@&=+$,#";
+ private final String ENCODED_URL_COMPONENT = "-_.!~*'()%3A%2F%23%3F%40%20%C3%A9%2B";
+ private final String ENCODED_URL_COMPONENT_QS = "-_.!~*'()%3A%2F%23%3F%40+%C3%A9%2B";
public String getModuleName() {
return "com.google.gwt.http.HttpSuite";
@@ -67,6 +68,37 @@
String actualURLComponent = URL.decodeComponent(ENCODED_URL_COMPONENT);
assertEquals(DECODED_URL_COMPONENT, actualURLComponent);
+
+ actualURLComponent = URL.decodeComponent(ENCODED_URL_COMPONENT_QS);
+ assertEquals(DECODED_URL_COMPONENT, actualURLComponent);
+ }
+
+ /**
+ * Test method for
+ * {@link com.google.gwt.http.client.URL#decodeComponent(java.lang.String,boolean)}.
+ */
+ public void testDecodeComponent2() {
+ try {
+ URL.decodeComponent(null);
+ fail("Expected NullPointerException");
+ } catch (NullPointerException ex) {
+ // expected exception was thrown
+ }
+
+ assertEquals("", URL.decodeComponent("", false));
+ assertEquals("", URL.decodeComponent("", true));
+ assertEquals(" ", URL.decodeComponent(" ", false));
+ assertEquals(" ", URL.decodeComponent(" ", true));
+ assertEquals("+", URL.decodeComponent("+", false));
+ assertEquals(" ", URL.decodeComponent("+", true));
+ assertEquals(" ", URL.decodeComponent("%20", false));
+ assertEquals(" ", URL.decodeComponent("%20", true));
+
+ String actualURLComponent = URL.decodeComponent(ENCODED_URL_COMPONENT, false);
+ assertEquals(DECODED_URL_COMPONENT, actualURLComponent);
+
+ actualURLComponent = URL.decodeComponent(ENCODED_URL_COMPONENT_QS, true);
+ assertEquals(DECODED_URL_COMPONENT, actualURLComponent);
}
/**
@@ -104,6 +136,37 @@
assertEquals("+", URL.encodeComponent(" "));
String actualURLComponent = URL.encodeComponent(DECODED_URL_COMPONENT);
+ assertEquals(ENCODED_URL_COMPONENT_QS, actualURLComponent);
+ }
+
+ /**
+ * Test method for
+ * {@link com.google.gwt.http.client.URL#encodeComponent(java.lang.String,boolean)}.
+ */
+ public void testEncodeComponent2() {
+ try {
+ URL.encodeComponent(null, false);
+ fail("Expected NullPointerException");
+ } catch (NullPointerException ex) {
+ // expected exception was thrown
+ }
+
+ try {
+ URL.encodeComponent(null, true);
+ fail("Expected NullPointerException");
+ } catch (NullPointerException ex) {
+ // expected exception was thrown
+ }
+
+ assertEquals("", URL.encodeComponent("", false));
+ assertEquals("", URL.encodeComponent("", true));
+ assertEquals("%20", URL.encodeComponent(" ", false));
+ assertEquals("+", URL.encodeComponent(" ", true));
+
+ String actualURLComponent = URL.encodeComponent(DECODED_URL_COMPONENT, false);
assertEquals(ENCODED_URL_COMPONENT, actualURLComponent);
+
+ actualURLComponent = URL.encodeComponent(DECODED_URL_COMPONENT, true);
+ assertEquals(ENCODED_URL_COMPONENT_QS, actualURLComponent);
}
}