diff --git a/pom.xml b/pom.xml
index fa5b1deb..d4ac5a4f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -203,6 +203,7 @@
1.5.11
+ UTF-8
diff --git a/src/main/java/it/geosolutions/geoserver/rest/HTTPUtils.java b/src/main/java/it/geosolutions/geoserver/rest/HTTPUtils.java
index ae1fc7af..1738269c 100644
--- a/src/main/java/it/geosolutions/geoserver/rest/HTTPUtils.java
+++ b/src/main/java/it/geosolutions/geoserver/rest/HTTPUtils.java
@@ -25,15 +25,6 @@
package it.geosolutions.geoserver.rest;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.UnsupportedEncodingException;
-import java.net.ConnectException;
-import java.net.HttpURLConnection;
-import java.net.MalformedURLException;
-import java.net.URL;
-
import org.apache.commons.httpclient.Credentials;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpConnectionManager;
@@ -52,6 +43,17 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.ConnectException;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+
/**
* Low level HTTP utilities.
*/
@@ -60,7 +62,7 @@ public class HTTPUtils {
/**
* Performs an HTTP GET on the given URL.
- *
+ *
* @param url The URL where to connect to.
* @return The HTTP response as a String if the HTTP response code was 200
* (OK).
@@ -73,7 +75,7 @@ public static String get(String url) throws MalformedURLException {
/**
* Performs an HTTP GET on the given URL.
* Basic auth is used if both username and pw are not null.
- *
+ *
* @param url The URL where to connect to.
* @param username Basic auth credential. No basic auth if null.
* @param pw Basic auth credential. No basic auth if null.
@@ -87,8 +89,9 @@ public static String get(String url, String username, String pw) {
HttpClient client = new HttpClient();
HttpConnectionManager connectionManager = client.getHttpConnectionManager();
try {
- setAuth(client, url, username, pw);
- httpMethod = new GetMethod(url);
+ String encodedUrl = encodeUrl(url);
+ setAuth(client, encodedUrl, username, pw);
+ httpMethod = new GetMethod(encodedUrl);
connectionManager.getParams().setConnectionTimeout(5000);
int status = client.executeMethod(httpMethod);
if (status == HttpStatus.SC_OK) {
@@ -117,10 +120,62 @@ public static String get(String url, String username, String pw) {
return null;
}
+ static String encodeUrl(String url) {
+ // perform some simple encoding to the path names. This takes care of cases where
+ // layers or workspaces have illegal http characters.
+ // it cannot fix all
+ String protocol, authority, path, query, fragment = null;
+ String[] protocolPathParts = url.split("://", 2);
+ if (protocolPathParts.length == 1) {
+ // unexpected format so just try out url
+ return url;
+ }
+
+ protocol = protocolPathParts[0];
+ String[] pathQueryParts = protocolPathParts[1].split("\\?", 2);
+ path = pathQueryParts[0];
+ if (pathQueryParts.length == 1) {
+ query = null;
+ } else {
+ query = pathQueryParts[1];
+ }
+
+
+ if (query == null) {
+ String[] fragmentParts = path.split("#", 2);
+ if (fragmentParts.length > 1) {
+ path = fragmentParts[0];
+ fragment = fragmentParts[1];
+ }
+ } else {
+ String[] fragmentParts = query.split("#", 2);
+ if (fragmentParts.length > 1) {
+ query = fragmentParts[0];
+ fragment = fragmentParts[1];
+ }
+ }
+
+ int firstSlash = path.indexOf('/');
+ if (firstSlash > -1) {
+ authority = path.substring(0, firstSlash);
+ path = path.substring(firstSlash);
+ } else {
+ authority = path;
+ path = null;
+ }
+
+ try {
+ return new URI(protocol, authority, path, query, fragment).toString();
+ } catch (URISyntaxException e) {
+ // fallback to original string
+ return url;
+ }
+ }
+
/**
* PUTs a File to the given URL.
* Basic auth is used if both username and pw are not null.
- *
+ *
* @param url The URL where to connect to.
* @param file The File to be sent.
* @param contentType The content-type to advert in the PUT.
@@ -138,7 +193,7 @@ public static String put(String url, File file, String contentType, String usern
/**
* PUTs a String to the given URL.
* Basic auth is used if both username and pw are not null.
- *
+ *
* @param url The URL where to connect to.
* @param content The content to be sent as a String.
* @param contentType The content-type to advert in the PUT.
@@ -161,7 +216,7 @@ public static String put(String url, String content, String contentType, String
/**
* PUTs a String representing an XML document to the given URL.
* Basic auth is used if both username and pw are not null.
- *
+ *
* @param url The URL where to connect to.
* @param content The XML content to be sent as a String.
* @param username Basic auth credential. No basic auth if null.
@@ -178,7 +233,7 @@ public static String putXml(String url, String content, String username, String
/**
* Performs a PUT to the given URL.
* Basic auth is used if both username and pw are not null.
- *
+ *
* @param url The URL where to connect to.
* @param requestEntity The request to be sent.
* @param username Basic auth credential. No basic auth if null.
@@ -195,7 +250,7 @@ public static String put(String url, RequestEntity requestEntity, String usernam
/**
* POSTs a File to the given URL.
* Basic auth is used if both username and pw are not null.
- *
+ *
* @param url The URL where to connect to.
* @param file The File to be sent.
* @param contentType The content-type to advert in the POST.
@@ -213,7 +268,7 @@ public static String post(String url, File file, String contentType, String user
/**
* POSTs a String to the given URL.
* Basic auth is used if both username and pw are not null.
- *
+ *
* @param url The URL where to connect to.
* @param content The content to be sent as a String.
* @param contentType The content-type to advert in the POST.
@@ -236,7 +291,7 @@ public static String post(String url, String content, String contentType, String
/**
* POSTs a String representing an XML document to the given URL.
* Basic auth is used if both username and pw are not null.
- *
+ *
* @param url The URL where to connect to.
* @param content The XML content to be sent as a String.
* @param username Basic auth credential. No basic auth if null.
@@ -253,7 +308,7 @@ public static String postXml(String url, String content, String username, String
/**
* Performs a POST to the given URL.
* Basic auth is used if both username and pw are not null.
- *
+ *
* @param url The URL where to connect to.
* @param requestEntity The request to be sent.
* @param username Basic auth credential. No basic auth if null.
@@ -279,15 +334,16 @@ public static String post(String url, RequestEntity requestEntity, String userna
*
* are accepted as successful codes; in these cases the response string will
* be returned.
- *
+ *
* @return the HTTP response or null on errors.
*/
private static String send(final EntityEnclosingMethod httpMethod, String url,
RequestEntity requestEntity, String username, String pw) {
HttpClient client = new HttpClient();
HttpConnectionManager connectionManager = client.getHttpConnectionManager();
+ String encodedUrl = encodeUrl(url);
try {
- setAuth(client, url, username, pw);
+ setAuth(client, encodedUrl, username, pw);
connectionManager.getParams().setConnectionTimeout(5000);
if (requestEntity != null)
httpMethod.setRequestEntity(requestEntity);
@@ -304,15 +360,15 @@ private static String send(final EntityEnclosingMethod httpMethod, String url,
return response;
default:
LOGGER.warn("Bad response: code[" + status + "]" + " msg[" + httpMethod.getStatusText() + "]"
- + " url[" + url + "]" + " method[" + httpMethod.getClass().getSimpleName()
+ + " url[" + encodedUrl + "]" + " method[" + httpMethod.getClass().getSimpleName()
+ "]: " + IOUtils.toString(httpMethod.getResponseBodyAsStream()));
return null;
}
} catch (ConnectException e) {
- LOGGER.info("Couldn't connect to [" + url + "]");
+ LOGGER.info("Couldn't connect to [" + encodedUrl + "]");
return null;
} catch (IOException e) {
- LOGGER.error("Error talking to " + url + " : " + e.getLocalizedMessage());
+ LOGGER.error("Error talking to " + encodedUrl + " : " + e.getLocalizedMessage());
return null;
} finally {
if (httpMethod != null)
@@ -326,9 +382,10 @@ public static boolean delete(String url, final String user, final String pw) {
DeleteMethod httpMethod = null;
HttpClient client = new HttpClient();
HttpConnectionManager connectionManager = client.getHttpConnectionManager();
+ String encodedUrl = encodeUrl(url);
try {
- setAuth(client, url, user, pw);
- httpMethod = new DeleteMethod(url);
+ setAuth(client, encodedUrl, user, pw);
+ httpMethod = new DeleteMethod(encodedUrl);
connectionManager.getParams().setConnectionTimeout(5000);
int status = client.executeMethod(httpMethod);
String response = "";
@@ -336,23 +393,23 @@ public static boolean delete(String url, final String user, final String pw) {
InputStream is = httpMethod.getResponseBodyAsStream();
response = IOUtils.toString(is);
IOUtils.closeQuietly(is);
- if (response.trim().equals("")) {
+ if (response.trim().equals("")) {
if (LOGGER.isDebugEnabled())
LOGGER
.debug("ResponseBody is empty (this may be not an error since we just performed a DELETE call)");
return true;
}
if (LOGGER.isDebugEnabled())
- LOGGER.debug("(" + status + ") " + httpMethod.getStatusText() + " -- " + url);
+ LOGGER.debug("(" + status + ") " + httpMethod.getStatusText() + " -- " + encodedUrl);
return true;
} else {
- LOGGER.info("(" + status + ") " + httpMethod.getStatusText() + " -- " + url);
+ LOGGER.info("(" + status + ") " + httpMethod.getStatusText() + " -- " + encodedUrl);
LOGGER.info("Response: '" + response + "'");
}
} catch (ConnectException e) {
- LOGGER.info("Couldn't connect to [" + url + "]");
+ LOGGER.info("Couldn't connect to [" + encodedUrl + "]");
} catch (IOException e) {
- LOGGER.info("Error talking to [" + url + "]", e);
+ LOGGER.info("Error talking to [" + encodedUrl + "]", e);
} finally {
if (httpMethod != null)
httpMethod.releaseConnection();
@@ -375,12 +432,13 @@ public static boolean httpPing(String url, String username, String pw) {
HttpClient client = new HttpClient();
HttpConnectionManager connectionManager = client.getHttpConnectionManager();
try {
- setAuth(client, url, username, pw);
- httpMethod = new GetMethod(url);
+ String encodedUrl = encodeUrl(url);
+ setAuth(client, encodedUrl, username, pw);
+ httpMethod = new GetMethod(encodedUrl);
connectionManager.getParams().setConnectionTimeout(2000);
int status = client.executeMethod(httpMethod);
if (status != HttpStatus.SC_OK) {
- LOGGER.warn("PING failed at '" + url + "': (" + status + ") " + httpMethod.getStatusText());
+ LOGGER.warn("PING failed at '" + encodedUrl + "': (" + status + ") " + httpMethod.getStatusText());
return false;
} else {
return true;
@@ -399,7 +457,7 @@ public static boolean httpPing(String url, String username, String pw) {
/**
* Used to query for REST resources.
- *
+ *
* @param url The URL of the REST resource to query about.
* @param username
* @param pw
@@ -412,8 +470,9 @@ public static boolean exists(String url, String username, String pw) {
HttpClient client = new HttpClient();
HttpConnectionManager connectionManager = client.getHttpConnectionManager();
try {
- setAuth(client, url, username, pw);
- httpMethod = new GetMethod(url);
+ String encodedUrl = encodeUrl(url);
+ setAuth(client, encodedUrl, username, pw);
+ httpMethod = new GetMethod(encodedUrl);
connectionManager.getParams().setConnectionTimeout(2000);
int status = client.executeMethod(httpMethod);
switch (status) {
@@ -422,7 +481,7 @@ public static boolean exists(String url, String username, String pw) {
case HttpStatus.SC_NOT_FOUND:
return false;
default:
- throw new RuntimeException("Unhandled response status at '" + url + "': (" + status + ") "
+ throw new RuntimeException("Unhandled response status at '" + encodedUrl + "': (" + status + ") "
+ httpMethod.getStatusText());
}
} catch (ConnectException e) {
@@ -438,7 +497,9 @@ public static boolean exists(String url, String username, String pw) {
private static void setAuth(HttpClient client, String url, String username, String pw)
throws MalformedURLException {
- URL u = new URL(url);
+
+ String encodedUrl = encodeUrl(url);
+ URL u = new URL(encodedUrl);
if (username != null && pw != null) {
Credentials defaultcreds = new UsernamePasswordCredentials(username, pw);
client.getState().setCredentials(new AuthScope(u.getHost(), u.getPort()), defaultcreds);
@@ -449,14 +510,14 @@ private static void setAuth(HttpClient client, String url, String username, Stri
// authentication
} else {
if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("Not setting credentials to access to " + url);
+ LOGGER.debug("Not setting credentials to access to " + encodedUrl);
}
}
}
/**
* @param geoserverURL
- * @return recursively remove ending slashes
+ * @return recursively remove ending slashes
*/
public static String decurtSlash(String geoserverURL) {
if (geoserverURL!=null && geoserverURL.endsWith("/")) {
@@ -464,7 +525,7 @@ public static String decurtSlash(String geoserverURL) {
}
return geoserverURL;
}
-
+
/**
* @param str a string array
* @return create a StringBuilder appending all the passed arguments
@@ -473,7 +534,7 @@ public static StringBuilder append(String ... str){
if (str==null){
return null;
}
-
+
StringBuilder buf=new StringBuilder();
for (String s: str){
if (s!=null)
@@ -481,7 +542,7 @@ public static StringBuilder append(String ... str){
}
return buf;
}
-
+
/**
* Wrapper for {@link #append(String...)}
* @param base base URL
@@ -492,7 +553,7 @@ public static StringBuilder append(URL base, String ... str){
if (str==null){
return append(base.toString());
}
-
+
StringBuilder buf=new StringBuilder(base.toString());
for (String s: str){
if (s!=null)
diff --git a/src/test/java/it/geosolutions/geoserver/rest/HTTPUtilsTest.java b/src/test/java/it/geosolutions/geoserver/rest/HTTPUtilsTest.java
new file mode 100644
index 00000000..22bfc898
--- /dev/null
+++ b/src/test/java/it/geosolutions/geoserver/rest/HTTPUtilsTest.java
@@ -0,0 +1,16 @@
+package it.geosolutions.geoserver.rest;
+
+import junit.framework.TestCase;
+
+public class HTTPUtilsTest extends TestCase {
+ public void testEncodeUrl() throws Exception {
+ assertEquals("http://with%20spaces", HTTPUtils.encodeUrl("http://with spaces"));
+ assertEquals("http://with%20spaces?p1=v1", HTTPUtils.encodeUrl("http://with spaces?p1=v1"));
+ assertEquals("http://without/spaces?p1=v1", HTTPUtils.encodeUrl("http://without/spaces?p1=v1"));
+ assertEquals("http://without/spaces", HTTPUtils.encodeUrl("http://without/spaces"));
+ assertEquals("http://without/spaces#fragment", HTTPUtils.encodeUrl("http://without/spaces#fragment"));
+ assertEquals("http://without/spaces?p1=v1#fragment", HTTPUtils.encodeUrl("http://without/spaces?p1=v1#fragment"));
+ assertEquals("http://with%20spaces#fragment", HTTPUtils.encodeUrl("http://with spaces#fragment"));
+ assertEquals("brokenurl?p1=v1", HTTPUtils.encodeUrl("brokenurl?p1=v1"));
+ }
+}