You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@wicket.apache.org by pe...@apache.org on 2012/05/08 00:57:44 UTC

[4/4] git commit: WICKET-4539 move UrlEncoder and UrlDecoder into wicket-util

WICKET-4539 move UrlEncoder and UrlDecoder into wicket-util


Project: http://git-wip-us.apache.org/repos/asf/wicket/repo
Commit: http://git-wip-us.apache.org/repos/asf/wicket/commit/64571736
Tree: http://git-wip-us.apache.org/repos/asf/wicket/tree/64571736
Diff: http://git-wip-us.apache.org/repos/asf/wicket/diff/64571736

Branch: refs/heads/master
Commit: 6457173650c8158258704bc201e9ed84a2c2708b
Parents: 535b2ee
Author: Peter Ertl <pe...@apache.org>
Authored: Tue May 8 00:53:21 2012 +0200
Committer: Peter Ertl <pe...@apache.org>
Committed: Tue May 8 00:53:21 2012 +0200

----------------------------------------------------------------------
 .../org/apache/wicket/markup/html/form/Form.java   |    2 +-
 .../wicket/markup/html/link/DownloadLink.java      |    2 +-
 .../apache/wicket/protocol/http/RequestUtils.java  |    2 +-
 .../protocol/http/mock/MockHttpServletRequest.java |    4 +-
 .../apache/wicket/protocol/http/WicketURLTest.java |    4 +-
 .../main/java/org/apache/wicket/request/Url.java   |    2 +
 .../java/org/apache/wicket/request/UrlDecoder.java |  178 -------
 .../java/org/apache/wicket/request/UrlEncoder.java |  370 ---------------
 .../org/apache/wicket/request/UrlEncoderTest.java  |   52 --
 .../apache/wicket/util/encoding/UrlDecoder.java    |  178 +++++++
 .../apache/wicket/util/encoding/UrlEncoder.java    |  370 +++++++++++++++
 .../wicket/util/encoding/UrlEncoderTest.java       |   53 ++
 12 files changed, 610 insertions(+), 607 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/wicket/blob/64571736/wicket-core/src/main/java/org/apache/wicket/markup/html/form/Form.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/markup/html/form/Form.java b/wicket-core/src/main/java/org/apache/wicket/markup/html/form/Form.java
index f1ef050..b0e9db3 100644
--- a/wicket-core/src/main/java/org/apache/wicket/markup/html/form/Form.java
+++ b/wicket-core/src/main/java/org/apache/wicket/markup/html/form/Form.java
@@ -47,11 +47,11 @@ import org.apache.wicket.request.IRequestParameters;
 import org.apache.wicket.request.Request;
 import org.apache.wicket.request.Response;
 import org.apache.wicket.request.Url;
-import org.apache.wicket.request.UrlDecoder;
 import org.apache.wicket.request.UrlRenderer;
 import org.apache.wicket.request.http.WebRequest;
 import org.apache.wicket.request.mapper.parameter.PageParameters;
 import org.apache.wicket.settings.IApplicationSettings;
+import org.apache.wicket.util.encoding.UrlDecoder;
 import org.apache.wicket.util.lang.Args;
 import org.apache.wicket.util.lang.Bytes;
 import org.apache.wicket.util.string.AppendingStringBuffer;

http://git-wip-us.apache.org/repos/asf/wicket/blob/64571736/wicket-core/src/main/java/org/apache/wicket/markup/html/link/DownloadLink.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/markup/html/link/DownloadLink.java b/wicket-core/src/main/java/org/apache/wicket/markup/html/link/DownloadLink.java
index b3b8848..3974b18 100644
--- a/wicket-core/src/main/java/org/apache/wicket/markup/html/link/DownloadLink.java
+++ b/wicket-core/src/main/java/org/apache/wicket/markup/html/link/DownloadLink.java
@@ -21,10 +21,10 @@ import java.io.File;
 import org.apache.wicket.model.IModel;
 import org.apache.wicket.model.Model;
 import org.apache.wicket.request.IRequestCycle;
-import org.apache.wicket.request.UrlEncoder;
 import org.apache.wicket.request.handler.resource.ResourceStreamRequestHandler;
 import org.apache.wicket.request.resource.ContentDisposition;
 import org.apache.wicket.settings.IResourceSettings;
+import org.apache.wicket.util.encoding.UrlEncoder;
 import org.apache.wicket.util.file.Files;
 import org.apache.wicket.util.lang.Args;
 import org.apache.wicket.util.resource.FileResourceStream;

http://git-wip-us.apache.org/repos/asf/wicket/blob/64571736/wicket-core/src/main/java/org/apache/wicket/protocol/http/RequestUtils.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/protocol/http/RequestUtils.java b/wicket-core/src/main/java/org/apache/wicket/protocol/http/RequestUtils.java
index 0d87a70..cf832bc 100644
--- a/wicket-core/src/main/java/org/apache/wicket/protocol/http/RequestUtils.java
+++ b/wicket-core/src/main/java/org/apache/wicket/protocol/http/RequestUtils.java
@@ -24,9 +24,9 @@ import java.util.List;
 import javax.servlet.http.HttpServletRequest;
 
 import org.apache.wicket.Application;
-import org.apache.wicket.request.UrlDecoder;
 import org.apache.wicket.request.cycle.RequestCycle;
 import org.apache.wicket.request.mapper.parameter.PageParameters;
+import org.apache.wicket.util.encoding.UrlDecoder;
 import org.apache.wicket.util.string.Strings;
 
 /**

http://git-wip-us.apache.org/repos/asf/wicket/blob/64571736/wicket-core/src/main/java/org/apache/wicket/protocol/http/mock/MockHttpServletRequest.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/protocol/http/mock/MockHttpServletRequest.java b/wicket-core/src/main/java/org/apache/wicket/protocol/http/mock/MockHttpServletRequest.java
index 3fa725d..e97ae3a 100755
--- a/wicket-core/src/main/java/org/apache/wicket/protocol/http/mock/MockHttpServletRequest.java
+++ b/wicket-core/src/main/java/org/apache/wicket/protocol/http/mock/MockHttpServletRequest.java
@@ -52,8 +52,8 @@ import org.apache.wicket.WicketRuntimeException;
 import org.apache.wicket.mock.MockRequestParameters;
 import org.apache.wicket.request.Url;
 import org.apache.wicket.request.Url.QueryParameter;
-import org.apache.wicket.request.UrlDecoder;
-import org.apache.wicket.request.UrlEncoder;
+import org.apache.wicket.util.encoding.UrlDecoder;
+import org.apache.wicket.util.encoding.UrlEncoder;
 import org.apache.wicket.util.file.File;
 import org.apache.wicket.util.io.IOUtils;
 import org.apache.wicket.util.string.StringValue;

http://git-wip-us.apache.org/repos/asf/wicket/blob/64571736/wicket-core/src/test/java/org/apache/wicket/protocol/http/WicketURLTest.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/test/java/org/apache/wicket/protocol/http/WicketURLTest.java b/wicket-core/src/test/java/org/apache/wicket/protocol/http/WicketURLTest.java
index d49a858..2098ec8 100644
--- a/wicket-core/src/test/java/org/apache/wicket/protocol/http/WicketURLTest.java
+++ b/wicket-core/src/test/java/org/apache/wicket/protocol/http/WicketURLTest.java
@@ -16,8 +16,8 @@
  */
 package org.apache.wicket.protocol.http;
 
-import org.apache.wicket.request.UrlDecoder;
-import org.apache.wicket.request.UrlEncoder;
+import org.apache.wicket.util.encoding.UrlDecoder;
+import org.apache.wicket.util.encoding.UrlEncoder;
 import org.junit.Assert;
 import org.junit.Test;
 

http://git-wip-us.apache.org/repos/asf/wicket/blob/64571736/wicket-request/src/main/java/org/apache/wicket/request/Url.java
----------------------------------------------------------------------
diff --git a/wicket-request/src/main/java/org/apache/wicket/request/Url.java b/wicket-request/src/main/java/org/apache/wicket/request/Url.java
index acb4287..43941f4 100755
--- a/wicket-request/src/main/java/org/apache/wicket/request/Url.java
+++ b/wicket-request/src/main/java/org/apache/wicket/request/Url.java
@@ -24,6 +24,8 @@ import java.util.Iterator;
 import java.util.List;
 import java.util.Locale;
 
+import org.apache.wicket.util.encoding.UrlDecoder;
+import org.apache.wicket.util.encoding.UrlEncoder;
 import org.apache.wicket.util.lang.Args;
 import org.apache.wicket.util.lang.Generics;
 import org.apache.wicket.util.lang.Objects;

http://git-wip-us.apache.org/repos/asf/wicket/blob/64571736/wicket-request/src/main/java/org/apache/wicket/request/UrlDecoder.java
----------------------------------------------------------------------
diff --git a/wicket-request/src/main/java/org/apache/wicket/request/UrlDecoder.java b/wicket-request/src/main/java/org/apache/wicket/request/UrlDecoder.java
deleted file mode 100644
index 2c361fe..0000000
--- a/wicket-request/src/main/java/org/apache/wicket/request/UrlDecoder.java
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * 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.wicket.request;
-
-import java.io.UnsupportedEncodingException;
-import java.nio.charset.Charset;
-
-/**
- * Adapted from java.net.URLDecoder, but defines instances for query string decoding versus URL path
- * component decoding.
- * <p/>
- * The difference is important because a space is encoded as a + in a query string, but this is a
- * valid value in a path component (and is therefore not decode back to a space).
- * 
- * @author Doug Donohoe
- * @see java.net.URLDecoder
- * @see <a href="http://www.ietf.org/rfc/rfc2396.txt">RFC-2396</a>
- */
-public class UrlDecoder
-{
-	private final boolean decodePlus;
-
-	/**
-	 * Encoder used to decode name or value components of a query string.<br/>
-	 * <br/>
-	 * 
-	 * For example: http://org.acme/notthis/northis/oreventhis?buthis=isokay&asis=thispart
-	 */
-	public static final UrlDecoder QUERY_INSTANCE = new UrlDecoder(true);
-
-	/**
-	 * Encoder used to decode components of a path.<br/>
-	 * <br/>
-	 * 
-	 * For example: http://org.acme/foo/thispart/orthispart?butnot=thispart
-	 */
-	public static final UrlDecoder PATH_INSTANCE = new UrlDecoder(false);
-
-	/**
-	 * Create decoder
-	 * 
-	 * @param decodePlus
-	 *            - whether to decode + to space
-	 */
-	private UrlDecoder(final boolean decodePlus)
-	{
-		this.decodePlus = decodePlus;
-	}
-
-	/**
-	 * @param s
-	 *            string to decode
-	 * @param enc
-	 *            encoding to decode with
-	 * @return decoded string
-	 * @see java.net.URLDecoder#decode(String, String)
-	 */
-	public String decode(final String s, final Charset enc)
-	{
-		return decode(s, enc.name());
-	}
-
-	/**
-	 * @param s
-	 *            string to decode
-	 * @param enc
-	 *            encoding to decode with
-	 * @return decoded string
-	 * @see java.net.URLDecoder#decode(String, String)
-	 */
-	public String decode(final String s, final String enc)
-	{
-		if (s == null)
-		{
-			return null;
-		}
-
-		boolean needToChange = false;
-		int numChars = s.length();
-		StringBuilder sb = new StringBuilder(numChars > 500 ? numChars / 2 : numChars);
-		int i = 0;
-
-		if (enc.length() == 0)
-		{
-			throw new RuntimeException(new UnsupportedEncodingException(
-				"URLDecoder: empty string enc parameter"));
-		}
-
-		char c;
-		byte[] bytes = null;
-		while (i < numChars)
-		{
-			c = s.charAt(i);
-			switch (c)
-			{
-				case '+' :
-					sb.append(decodePlus ? ' ' : '+');
-					i++;
-					needToChange = true;
-					break;
-
-				case '%' :
-					/*
-					 * Starting with this instance of %, process all consecutive substrings of the
-					 * form %xy. Each substring %xy will yield a byte. Convert all consecutive bytes
-					 * obtained this way to whatever character(s) they represent in the provided
-					 * encoding.
-					 */
-					try
-					{
-						// (numChars-i)/3 is an upper bound for the number
-						// of remaining bytes
-						if (bytes == null)
-						{
-							bytes = new byte[(numChars - i) / 3];
-						}
-						int pos = 0;
-
-						while (((i + 2) < numChars) && (c == '%'))
-						{
-							bytes[pos++] = (byte)Integer.parseInt(s.substring(i + 1, i + 3), 16);
-							i += 3;
-							if (i < numChars)
-							{
-								c = s.charAt(i);
-							}
-						}
-
-						// A trailing, incomplete byte encoding such as
-						// "%x" will cause an exception to be thrown
-						if ((i < numChars) && (c == '%'))
-						{
-							throw new IllegalArgumentException(
-								"URLDecoder: Incomplete trailing escape (%) pattern");
-						}
-
-						try
-						{
-							sb.append(new String(bytes, 0, pos, enc));
-						}
-						catch (UnsupportedEncodingException e)
-						{
-							throw new RuntimeException(e);
-						}
-					}
-					catch (NumberFormatException e)
-					{
-						throw new IllegalArgumentException(
-							"URLDecoder: Illegal hex characters in escape (%) pattern - " +
-								e.getMessage());
-					}
-					needToChange = true;
-					break;
-
-				default :
-					sb.append(c);
-					i++;
-					break;
-			}
-		}
-
-		return (needToChange ? sb.toString() : s);
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/wicket/blob/64571736/wicket-request/src/main/java/org/apache/wicket/request/UrlEncoder.java
----------------------------------------------------------------------
diff --git a/wicket-request/src/main/java/org/apache/wicket/request/UrlEncoder.java b/wicket-request/src/main/java/org/apache/wicket/request/UrlEncoder.java
deleted file mode 100644
index b5db2d1..0000000
--- a/wicket-request/src/main/java/org/apache/wicket/request/UrlEncoder.java
+++ /dev/null
@@ -1,370 +0,0 @@
-/*
- * 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.wicket.request;
-
-import java.io.CharArrayWriter;
-import java.io.UnsupportedEncodingException;
-import java.nio.charset.Charset;
-import java.nio.charset.IllegalCharsetNameException;
-import java.nio.charset.UnsupportedCharsetException;
-import java.util.BitSet;
-
-import org.apache.wicket.util.lang.Args;
-
-/**
- * Adapted from java.net.URLEncoder, but defines instances for query string encoding versus URL path
- * component encoding.
- * <p/>
- * The difference is important because a space is encoded as a + in a query string, but this is a
- * valid value in a path component (and is therefore not decode back to a space).
- * 
- * @author Doug Donohoe
- * @see java.net.URLEncoder
- * @see <a href="http://www.ietf.org/rfc/rfc2396.txt">RFC-2396</a>
- */
-public class UrlEncoder
-{
-	/**
-	 * encoder types
-	 */
-	public enum Type {
-		/**
-		 * query type
-		 */
-		QUERY,
-		/**
-		 * path type
-		 */
-		PATH,
-		/**
-		 * full path type
-		 */
-		FULL_PATH
-	}
-
-	// list of what not to decode
-	protected BitSet dontNeedEncoding;
-
-	// E.g. "?" for FULL_PATH encoding when querystring has already been
-	// encoded.
-	private final char stopChar;
-
-	// used in decoding
-	protected static final int caseDiff = ('a' - 'A');
-
-	/**
-	 * Encoder used to encode name or value components of a query string.<br/>
-	 * <br/>
-	 * 
-	 * For example: http://org.acme/notthis/northis/oreventhis?buthis=isokay&asis=thispart
-	 */
-	public static final UrlEncoder QUERY_INSTANCE = new UrlEncoder(Type.QUERY, '\0');
-
-	/**
-	 * Encoder used to encode components of a path.<br/>
-	 * <br/>
-	 * 
-	 * For example: http://org.acme/foo/thispart/orthispart?butnot=thispart
-	 */
-	public static final UrlEncoder PATH_INSTANCE = new UrlEncoder(Type.PATH, '\0');
-
-	/**
-	 * Encoder used to encode all path segments. Querystring will be excluded.<br/>
-	 * <br/>
-	 * 
-	 * For example: http://org.acme/foo/thispart/orthispart?butnot=thispart
-	 */
-	public static final UrlEncoder FULL_PATH_INSTANCE = new UrlEncoder(Type.FULL_PATH, '?');
-
-	/**
-	 * Allow subclass to call constructor.
-	 * 
-	 * @param type
-	 *            encoder type
-	 * @param stopChar
-	 *            stop encoding when stopChar found
-	 */
-	protected UrlEncoder(final Type type, final char stopChar)
-	{
-		this.stopChar = stopChar;
-
-		/*
-		 * This note from java.net.URLEncoder ==================================
-		 * 
-		 * The list of characters that are not encoded has been determined as follows:
-		 * 
-		 * RFC 2396 states: ----- Data characters that are allowed in a URI but do not have a
-		 * reserved purpose are called unreserved. These include upper and lower case letters,
-		 * decimal digits, and a limited set of punctuation marks and symbols.
-		 * 
-		 * unreserved = alphanum | mark
-		 * 
-		 * mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"
-		 * 
-		 * Unreserved characters can be escaped without changing the semantics of the URI, but this
-		 * should not be done unless the URI is being used in a context that does not allow the
-		 * unescaped character to appear. -----
-		 * 
-		 * It appears that both Netscape and Internet Explorer escape all special characters from
-		 * this list with the exception of "-", "_", ".", "*". While it is not clear why they are
-		 * escaping the other characters, perhaps it is safest to assume that there might be
-		 * contexts in which the others are unsafe if not escaped. Therefore, we will use the same
-		 * list. It is also noteworthy that this is consistent with O'Reilly's
-		 * "HTML: The Definitive Guide" (page 164).
-		 * 
-		 * As a last note, Intenet Explorer does not encode the "@" character which is clearly not
-		 * unreserved according to the RFC. We are being consistent with the RFC in this matter, as
-		 * is Netscape.
-		 * 
-		 * This bit added by Doug Donohoe ================================== RFC 3986 (2005) updates
-		 * this (http://tools.ietf.org/html/rfc3986):
-		 * 
-		 * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
-		 * 
-		 * pct-encoded = "%" HEXDIG HEXDIG
-		 * 
-		 * reserved = gen-delims / sub-delims
-		 * 
-		 * gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"
-		 * 
-		 * sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "=" // -- PATH
-		 * COMPONENT -- //
-		 * 
-		 * path = (see RFC for all variations) path-abempty =( "/" segment ) segment =pchar pchar =
-		 * unreserved / pct-encoded / sub-delims / ":" / "@" // -- QUERY COMPONENT -- //
-		 * 
-		 * query =( pchar / "/" / "?" )
-		 */
-
-		// unreserved
-		dontNeedEncoding = new BitSet(256);
-		int i;
-		for (i = 'a'; i <= 'z'; i++)
-		{
-			dontNeedEncoding.set(i);
-		}
-		for (i = 'A'; i <= 'Z'; i++)
-		{
-			dontNeedEncoding.set(i);
-		}
-		for (i = '0'; i <= '9'; i++)
-		{
-			dontNeedEncoding.set(i);
-		}
-		dontNeedEncoding.set('-');
-		dontNeedEncoding.set('.');
-		dontNeedEncoding.set('_');
-		// tilde encoded by java.net.URLEncoder version, but RFC is clear on this
-		dontNeedEncoding.set('~');
-
-		// sub-delims
-		dontNeedEncoding.set('!');
-		dontNeedEncoding.set('$');
-		// "&" needs to be encoded for query stings
-		// "(" and ")" probably don't need encoding, but we'll be conservative
-		dontNeedEncoding.set('*');
-		// "+" needs to be encoded for query strings (since it means =
-		dontNeedEncoding.set(',');
-		// ";" encoded due to use in path and/or query as delim in some
-		// instances (e.g., jsessionid)
-		// "=" needs to be encoded for query strings
-
-		// pchar
-		dontNeedEncoding.set(':'); // allowed and used in wicket interface
-		// params
-		dontNeedEncoding.set('@');
-
-		// encoding type-specific
-		switch (type)
-		{
-			// this code consistent with java.net.URLEncoder version
-			case QUERY :
-				// encoding a space to a + is done in the encode() method
-				dontNeedEncoding.set(' ');
-				// to allow direct passing of URL in query
-				dontNeedEncoding.set('/');
-
-				/*
-				 * the below encoding of a ? is disabled because it interferes in portlet
-				 * environments. as far as i can tell it will not interfere with the ability to pass
-				 * around urls in the query string. however, should it cause problems we can
-				 * re-enable it as portlet environments are not high priority. we can also add a
-				 * switch somewhere to enable/disable this on applicaiton level. (WICKET-4019)
-				 */
-
-				// to allow direct passing of URL in query
-				// dontNeedEncoding.set('?');
-				break;
-
-			// this added to deal with encoding a PATH component
-			case PATH :
-				// encode ' ' with a % instead of + in path portion
-
-				// path component sub-delim values we do not need to escape
-				dontNeedEncoding.set('&');
-				dontNeedEncoding.set('=');
-				dontNeedEncoding.set('+');
-				// don't encode semicolon because it is used in ;jsessionid=
-				dontNeedEncoding.set(';');
-				break;
-
-			// same as path, but '/' will not be encoded
-			case FULL_PATH :
-				// encode ' ' with a % instead of + in path portion
-
-				// path component sub-delim values we do not need to escape
-				dontNeedEncoding.set('&');
-				dontNeedEncoding.set('=');
-				dontNeedEncoding.set('+');
-
-				dontNeedEncoding.set('/');
-				break;
-		}
-	}
-
-	/**
-	 * @param s
-	 *            string to encode
-	 * @param charset
-	 *            charset to use for encoding
-	 * @return encoded string
-	 * @see java.net.URLEncoder#encode(String, String)
-	 */
-	public String encode(final String s, final Charset charset)
-	{
-		return encode(s, charset.name());
-	}
-
-	/**
-	 * @param s
-	 *            string to encode
-	 * @param charsetName
-	 *            encoding to use
-	 * @return encoded string
-	 * @see java.net.URLEncoder#encode(String, String)
-	 */
-	public String encode(final String s, final String charsetName)
-	{
-		boolean needToChange = false;
-		StringBuilder out = new StringBuilder(s.length());
-		Charset charset;
-		CharArrayWriter charArrayWriter = new CharArrayWriter();
-
-		Args.notNull(charsetName, "charsetName");
-
-		try
-		{
-			charset = Charset.forName(charsetName);
-		}
-		catch (IllegalCharsetNameException e)
-		{
-			throw new RuntimeException(new UnsupportedEncodingException(charsetName));
-		}
-		catch (UnsupportedCharsetException e)
-		{
-			throw new RuntimeException(new UnsupportedEncodingException(charsetName));
-		}
-
-		boolean stopEncoding = false;
-		for (int i = 0; i < s.length();)
-		{
-			int c = s.charAt(i);
-
-			if ((stopEncoding == false) && (c == stopChar))
-			{
-				stopEncoding = true;
-			}
-
-			// System.out.println("Examining character: " + c);
-			if ((stopEncoding == true) || dontNeedEncoding.get(c))
-			{
-				if (c == ' ')
-				{
-					c = '+';
-					needToChange = true;
-				}
-				// System.out.println("Storing: " + c);
-				out.append((char)c);
-				i++;
-			}
-			else
-			{
-				// convert to external encoding before hex conversion
-				do
-				{
-					charArrayWriter.write(c);
-					/*
-					 * If this character represents the start of a Unicode surrogate pair, then pass
-					 * in two characters. It's not clear what should be done if a bytes reserved in
-					 * the surrogate pairs range occurs outside of a legal surrogate pair. For now,
-					 * just treat it as if it were any other character.
-					 */
-					if ((c >= 0xD800) && (c <= 0xDBFF))
-					{
-						/*
-						 * System.out.println(Integer.toHexString(c) + " is high surrogate");
-						 */
-						if ((i + 1) < s.length())
-						{
-							int d = s.charAt(i + 1);
-							/*
-							 * System.out.println("\tExamining " + Integer.toHexString(d));
-							 */
-							if ((d >= 0xDC00) && (d <= 0xDFFF))
-							{
-								/*
-								 * System.out.println("\t" + Integer.toHexString(d) + " is low
-								 * surrogate");
-								 */
-								charArrayWriter.write(d);
-								i++;
-							}
-						}
-					}
-					i++;
-				}
-				while ((i < s.length()) && !dontNeedEncoding.get((c = s.charAt(i))));
-
-				charArrayWriter.flush();
-				String str = new String(charArrayWriter.toCharArray());
-				byte[] ba = str.getBytes(charset);
-				for (byte b : ba)
-				{
-					out.append('%');
-					char ch = Character.forDigit((b >> 4) & 0xF, 16);
-					// converting to use uppercase letter as part of
-					// the hex value if ch is a letter.
-					if (Character.isLetter(ch))
-					{
-						ch -= caseDiff;
-					}
-					out.append(ch);
-					ch = Character.forDigit(b & 0xF, 16);
-					if (Character.isLetter(ch))
-					{
-						ch -= caseDiff;
-					}
-					out.append(ch);
-				}
-				charArrayWriter.reset();
-				needToChange = true;
-			}
-		}
-
-		return (needToChange ? out.toString() : s);
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/wicket/blob/64571736/wicket-request/src/test/java/org/apache/wicket/request/UrlEncoderTest.java
----------------------------------------------------------------------
diff --git a/wicket-request/src/test/java/org/apache/wicket/request/UrlEncoderTest.java b/wicket-request/src/test/java/org/apache/wicket/request/UrlEncoderTest.java
deleted file mode 100644
index f44234f..0000000
--- a/wicket-request/src/test/java/org/apache/wicket/request/UrlEncoderTest.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * 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.wicket.request;
-
-import org.apache.wicket.util.crypt.CharEncoding;
-import org.junit.Assert;
-import org.junit.Test;
-
-/**
- * Tests for {@link UrlDecoder}
- */
-public class UrlEncoderTest extends Assert
-{
-
-	/**
-	 * <a href="https://issues.apache.org/jira/browse/WICKET-3721">WICKET-3721</a> Encode
-	 * apostrophes because otherwise they get XML encoded by ComponentTag#writeOutput() to
-	 * &amp;#039; and eventually break links with javascript:
-	 */
-	@Test
-	public void encodeApostrophe()
-	{
-		assertEquals("someone%27s%20bad%20url",
-			UrlEncoder.FULL_PATH_INSTANCE.encode("someone's bad url", CharEncoding.UTF_8));
-	}
-
-	/**
-	 * Do not encode semicolon in the Url's path because it is used in ';jsessionid=...'
-	 *
-	 * https://issues.apache.org/jira/browse/WICKET-4409
-	 */
-	@Test
-	public void dontEncodeSemicolon()
-	{
-		String encoded = UrlEncoder.PATH_INSTANCE.encode("path;jsessionid=1234567890", CharEncoding.UTF_8);
-		assertEquals("path;jsessionid=1234567890", encoded);
-	}
-}

http://git-wip-us.apache.org/repos/asf/wicket/blob/64571736/wicket-util/src/main/java/org/apache/wicket/util/encoding/UrlDecoder.java
----------------------------------------------------------------------
diff --git a/wicket-util/src/main/java/org/apache/wicket/util/encoding/UrlDecoder.java b/wicket-util/src/main/java/org/apache/wicket/util/encoding/UrlDecoder.java
new file mode 100644
index 0000000..5f6d756
--- /dev/null
+++ b/wicket-util/src/main/java/org/apache/wicket/util/encoding/UrlDecoder.java
@@ -0,0 +1,178 @@
+/*
+ * 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.wicket.util.encoding;
+
+import java.io.UnsupportedEncodingException;
+import java.nio.charset.Charset;
+
+/**
+ * Adapted from java.net.URLDecoder, but defines instances for query string decoding versus URL path
+ * component decoding.
+ * <p/>
+ * The difference is important because a space is encoded as a + in a query string, but this is a
+ * valid value in a path component (and is therefore not decode back to a space).
+ * 
+ * @author Doug Donohoe
+ * @see java.net.URLDecoder
+ * @see <a href="http://www.ietf.org/rfc/rfc2396.txt">RFC-2396</a>
+ */
+public class UrlDecoder
+{
+	private final boolean decodePlus;
+
+	/**
+	 * Encoder used to decode name or value components of a query string.<br/>
+	 * <br/>
+	 * 
+	 * For example: http://org.acme/notthis/northis/oreventhis?buthis=isokay&asis=thispart
+	 */
+	public static final UrlDecoder QUERY_INSTANCE = new UrlDecoder(true);
+
+	/**
+	 * Encoder used to decode components of a path.<br/>
+	 * <br/>
+	 * 
+	 * For example: http://org.acme/foo/thispart/orthispart?butnot=thispart
+	 */
+	public static final UrlDecoder PATH_INSTANCE = new UrlDecoder(false);
+
+	/**
+	 * Create decoder
+	 * 
+	 * @param decodePlus
+	 *            - whether to decode + to space
+	 */
+	private UrlDecoder(final boolean decodePlus)
+	{
+		this.decodePlus = decodePlus;
+	}
+
+	/**
+	 * @param s
+	 *            string to decode
+	 * @param enc
+	 *            encoding to decode with
+	 * @return decoded string
+	 * @see java.net.URLDecoder#decode(String, String)
+	 */
+	public String decode(final String s, final Charset enc)
+	{
+		return decode(s, enc.name());
+	}
+
+	/**
+	 * @param s
+	 *            string to decode
+	 * @param enc
+	 *            encoding to decode with
+	 * @return decoded string
+	 * @see java.net.URLDecoder#decode(String, String)
+	 */
+	public String decode(final String s, final String enc)
+	{
+		if (s == null)
+		{
+			return null;
+		}
+
+		boolean needToChange = false;
+		int numChars = s.length();
+		StringBuilder sb = new StringBuilder(numChars > 500 ? numChars / 2 : numChars);
+		int i = 0;
+
+		if (enc.length() == 0)
+		{
+			throw new RuntimeException(new UnsupportedEncodingException(
+				"URLDecoder: empty string enc parameter"));
+		}
+
+		char c;
+		byte[] bytes = null;
+		while (i < numChars)
+		{
+			c = s.charAt(i);
+			switch (c)
+			{
+				case '+' :
+					sb.append(decodePlus ? ' ' : '+');
+					i++;
+					needToChange = true;
+					break;
+
+				case '%' :
+					/*
+					 * Starting with this instance of %, process all consecutive substrings of the
+					 * form %xy. Each substring %xy will yield a byte. Convert all consecutive bytes
+					 * obtained this way to whatever character(s) they represent in the provided
+					 * encoding.
+					 */
+					try
+					{
+						// (numChars-i)/3 is an upper bound for the number
+						// of remaining bytes
+						if (bytes == null)
+						{
+							bytes = new byte[(numChars - i) / 3];
+						}
+						int pos = 0;
+
+						while (((i + 2) < numChars) && (c == '%'))
+						{
+							bytes[pos++] = (byte)Integer.parseInt(s.substring(i + 1, i + 3), 16);
+							i += 3;
+							if (i < numChars)
+							{
+								c = s.charAt(i);
+							}
+						}
+
+						// A trailing, incomplete byte encoding such as
+						// "%x" will cause an exception to be thrown
+						if ((i < numChars) && (c == '%'))
+						{
+							throw new IllegalArgumentException(
+								"URLDecoder: Incomplete trailing escape (%) pattern");
+						}
+
+						try
+						{
+							sb.append(new String(bytes, 0, pos, enc));
+						}
+						catch (UnsupportedEncodingException e)
+						{
+							throw new RuntimeException(e);
+						}
+					}
+					catch (NumberFormatException e)
+					{
+						throw new IllegalArgumentException(
+							"URLDecoder: Illegal hex characters in escape (%) pattern - " +
+								e.getMessage());
+					}
+					needToChange = true;
+					break;
+
+				default :
+					sb.append(c);
+					i++;
+					break;
+			}
+		}
+
+		return (needToChange ? sb.toString() : s);
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/wicket/blob/64571736/wicket-util/src/main/java/org/apache/wicket/util/encoding/UrlEncoder.java
----------------------------------------------------------------------
diff --git a/wicket-util/src/main/java/org/apache/wicket/util/encoding/UrlEncoder.java b/wicket-util/src/main/java/org/apache/wicket/util/encoding/UrlEncoder.java
new file mode 100644
index 0000000..52044da
--- /dev/null
+++ b/wicket-util/src/main/java/org/apache/wicket/util/encoding/UrlEncoder.java
@@ -0,0 +1,370 @@
+/*
+ * 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.wicket.util.encoding;
+
+import java.io.CharArrayWriter;
+import java.io.UnsupportedEncodingException;
+import java.nio.charset.Charset;
+import java.nio.charset.IllegalCharsetNameException;
+import java.nio.charset.UnsupportedCharsetException;
+import java.util.BitSet;
+
+import org.apache.wicket.util.lang.Args;
+
+/**
+ * Adapted from java.net.URLEncoder, but defines instances for query string encoding versus URL path
+ * component encoding.
+ * <p/>
+ * The difference is important because a space is encoded as a + in a query string, but this is a
+ * valid value in a path component (and is therefore not decode back to a space).
+ * 
+ * @author Doug Donohoe
+ * @see java.net.URLEncoder
+ * @see <a href="http://www.ietf.org/rfc/rfc2396.txt">RFC-2396</a>
+ */
+public class UrlEncoder
+{
+	/**
+	 * encoder types
+	 */
+	public enum Type {
+		/**
+		 * query type
+		 */
+		QUERY,
+		/**
+		 * path type
+		 */
+		PATH,
+		/**
+		 * full path type
+		 */
+		FULL_PATH
+	}
+
+	// list of what not to decode
+	protected BitSet dontNeedEncoding;
+
+	// E.g. "?" for FULL_PATH encoding when querystring has already been
+	// encoded.
+	private final char stopChar;
+
+	// used in decoding
+	protected static final int caseDiff = ('a' - 'A');
+
+	/**
+	 * Encoder used to encode name or value components of a query string.<br/>
+	 * <br/>
+	 * 
+	 * For example: http://org.acme/notthis/northis/oreventhis?buthis=isokay&asis=thispart
+	 */
+	public static final UrlEncoder QUERY_INSTANCE = new UrlEncoder(Type.QUERY, '\0');
+
+	/**
+	 * Encoder used to encode components of a path.<br/>
+	 * <br/>
+	 * 
+	 * For example: http://org.acme/foo/thispart/orthispart?butnot=thispart
+	 */
+	public static final UrlEncoder PATH_INSTANCE = new UrlEncoder(Type.PATH, '\0');
+
+	/**
+	 * Encoder used to encode all path segments. Querystring will be excluded.<br/>
+	 * <br/>
+	 * 
+	 * For example: http://org.acme/foo/thispart/orthispart?butnot=thispart
+	 */
+	public static final UrlEncoder FULL_PATH_INSTANCE = new UrlEncoder(Type.FULL_PATH, '?');
+
+	/**
+	 * Allow subclass to call constructor.
+	 * 
+	 * @param type
+	 *            encoder type
+	 * @param stopChar
+	 *            stop encoding when stopChar found
+	 */
+	protected UrlEncoder(final Type type, final char stopChar)
+	{
+		this.stopChar = stopChar;
+
+		/*
+		 * This note from java.net.URLEncoder ==================================
+		 * 
+		 * The list of characters that are not encoded has been determined as follows:
+		 * 
+		 * RFC 2396 states: ----- Data characters that are allowed in a URI but do not have a
+		 * reserved purpose are called unreserved. These include upper and lower case letters,
+		 * decimal digits, and a limited set of punctuation marks and symbols.
+		 * 
+		 * unreserved = alphanum | mark
+		 * 
+		 * mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"
+		 * 
+		 * Unreserved characters can be escaped without changing the semantics of the URI, but this
+		 * should not be done unless the URI is being used in a context that does not allow the
+		 * unescaped character to appear. -----
+		 * 
+		 * It appears that both Netscape and Internet Explorer escape all special characters from
+		 * this list with the exception of "-", "_", ".", "*". While it is not clear why they are
+		 * escaping the other characters, perhaps it is safest to assume that there might be
+		 * contexts in which the others are unsafe if not escaped. Therefore, we will use the same
+		 * list. It is also noteworthy that this is consistent with O'Reilly's
+		 * "HTML: The Definitive Guide" (page 164).
+		 * 
+		 * As a last note, Intenet Explorer does not encode the "@" character which is clearly not
+		 * unreserved according to the RFC. We are being consistent with the RFC in this matter, as
+		 * is Netscape.
+		 * 
+		 * This bit added by Doug Donohoe ================================== RFC 3986 (2005) updates
+		 * this (http://tools.ietf.org/html/rfc3986):
+		 * 
+		 * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
+		 * 
+		 * pct-encoded = "%" HEXDIG HEXDIG
+		 * 
+		 * reserved = gen-delims / sub-delims
+		 * 
+		 * gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"
+		 * 
+		 * sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "=" // -- PATH
+		 * COMPONENT -- //
+		 * 
+		 * path = (see RFC for all variations) path-abempty =( "/" segment ) segment =pchar pchar =
+		 * unreserved / pct-encoded / sub-delims / ":" / "@" // -- QUERY COMPONENT -- //
+		 * 
+		 * query =( pchar / "/" / "?" )
+		 */
+
+		// unreserved
+		dontNeedEncoding = new BitSet(256);
+		int i;
+		for (i = 'a'; i <= 'z'; i++)
+		{
+			dontNeedEncoding.set(i);
+		}
+		for (i = 'A'; i <= 'Z'; i++)
+		{
+			dontNeedEncoding.set(i);
+		}
+		for (i = '0'; i <= '9'; i++)
+		{
+			dontNeedEncoding.set(i);
+		}
+		dontNeedEncoding.set('-');
+		dontNeedEncoding.set('.');
+		dontNeedEncoding.set('_');
+		// tilde encoded by java.net.URLEncoder version, but RFC is clear on this
+		dontNeedEncoding.set('~');
+
+		// sub-delims
+		dontNeedEncoding.set('!');
+		dontNeedEncoding.set('$');
+		// "&" needs to be encoded for query stings
+		// "(" and ")" probably don't need encoding, but we'll be conservative
+		dontNeedEncoding.set('*');
+		// "+" needs to be encoded for query strings (since it means =
+		dontNeedEncoding.set(',');
+		// ";" encoded due to use in path and/or query as delim in some
+		// instances (e.g., jsessionid)
+		// "=" needs to be encoded for query strings
+
+		// pchar
+		dontNeedEncoding.set(':'); // allowed and used in wicket interface
+		// params
+		dontNeedEncoding.set('@');
+
+		// encoding type-specific
+		switch (type)
+		{
+			// this code consistent with java.net.URLEncoder version
+			case QUERY :
+				// encoding a space to a + is done in the encode() method
+				dontNeedEncoding.set(' ');
+				// to allow direct passing of URL in query
+				dontNeedEncoding.set('/');
+
+				/*
+				 * the below encoding of a ? is disabled because it interferes in portlet
+				 * environments. as far as i can tell it will not interfere with the ability to pass
+				 * around urls in the query string. however, should it cause problems we can
+				 * re-enable it as portlet environments are not high priority. we can also add a
+				 * switch somewhere to enable/disable this on applicaiton level. (WICKET-4019)
+				 */
+
+				// to allow direct passing of URL in query
+				// dontNeedEncoding.set('?');
+				break;
+
+			// this added to deal with encoding a PATH component
+			case PATH :
+				// encode ' ' with a % instead of + in path portion
+
+				// path component sub-delim values we do not need to escape
+				dontNeedEncoding.set('&');
+				dontNeedEncoding.set('=');
+				dontNeedEncoding.set('+');
+				// don't encode semicolon because it is used in ;jsessionid=
+				dontNeedEncoding.set(';');
+				break;
+
+			// same as path, but '/' will not be encoded
+			case FULL_PATH :
+				// encode ' ' with a % instead of + in path portion
+
+				// path component sub-delim values we do not need to escape
+				dontNeedEncoding.set('&');
+				dontNeedEncoding.set('=');
+				dontNeedEncoding.set('+');
+
+				dontNeedEncoding.set('/');
+				break;
+		}
+	}
+
+	/**
+	 * @param s
+	 *            string to encode
+	 * @param charset
+	 *            charset to use for encoding
+	 * @return encoded string
+	 * @see java.net.URLEncoder#encode(String, String)
+	 */
+	public String encode(final String s, final Charset charset)
+	{
+		return encode(s, charset.name());
+	}
+
+	/**
+	 * @param s
+	 *            string to encode
+	 * @param charsetName
+	 *            encoding to use
+	 * @return encoded string
+	 * @see java.net.URLEncoder#encode(String, String)
+	 */
+	public String encode(final String s, final String charsetName)
+	{
+		boolean needToChange = false;
+		StringBuilder out = new StringBuilder(s.length());
+		Charset charset;
+		CharArrayWriter charArrayWriter = new CharArrayWriter();
+
+		Args.notNull(charsetName, "charsetName");
+
+		try
+		{
+			charset = Charset.forName(charsetName);
+		}
+		catch (IllegalCharsetNameException e)
+		{
+			throw new RuntimeException(new UnsupportedEncodingException(charsetName));
+		}
+		catch (UnsupportedCharsetException e)
+		{
+			throw new RuntimeException(new UnsupportedEncodingException(charsetName));
+		}
+
+		boolean stopEncoding = false;
+		for (int i = 0; i < s.length();)
+		{
+			int c = s.charAt(i);
+
+			if ((stopEncoding == false) && (c == stopChar))
+			{
+				stopEncoding = true;
+			}
+
+			// System.out.println("Examining character: " + c);
+			if ((stopEncoding == true) || dontNeedEncoding.get(c))
+			{
+				if (c == ' ')
+				{
+					c = '+';
+					needToChange = true;
+				}
+				// System.out.println("Storing: " + c);
+				out.append((char)c);
+				i++;
+			}
+			else
+			{
+				// convert to external encoding before hex conversion
+				do
+				{
+					charArrayWriter.write(c);
+					/*
+					 * If this character represents the start of a Unicode surrogate pair, then pass
+					 * in two characters. It's not clear what should be done if a bytes reserved in
+					 * the surrogate pairs range occurs outside of a legal surrogate pair. For now,
+					 * just treat it as if it were any other character.
+					 */
+					if ((c >= 0xD800) && (c <= 0xDBFF))
+					{
+						/*
+						 * System.out.println(Integer.toHexString(c) + " is high surrogate");
+						 */
+						if ((i + 1) < s.length())
+						{
+							int d = s.charAt(i + 1);
+							/*
+							 * System.out.println("\tExamining " + Integer.toHexString(d));
+							 */
+							if ((d >= 0xDC00) && (d <= 0xDFFF))
+							{
+								/*
+								 * System.out.println("\t" + Integer.toHexString(d) + " is low
+								 * surrogate");
+								 */
+								charArrayWriter.write(d);
+								i++;
+							}
+						}
+					}
+					i++;
+				}
+				while ((i < s.length()) && !dontNeedEncoding.get((c = s.charAt(i))));
+
+				charArrayWriter.flush();
+				String str = new String(charArrayWriter.toCharArray());
+				byte[] ba = str.getBytes(charset);
+				for (byte b : ba)
+				{
+					out.append('%');
+					char ch = Character.forDigit((b >> 4) & 0xF, 16);
+					// converting to use uppercase letter as part of
+					// the hex value if ch is a letter.
+					if (Character.isLetter(ch))
+					{
+						ch -= caseDiff;
+					}
+					out.append(ch);
+					ch = Character.forDigit(b & 0xF, 16);
+					if (Character.isLetter(ch))
+					{
+						ch -= caseDiff;
+					}
+					out.append(ch);
+				}
+				charArrayWriter.reset();
+				needToChange = true;
+			}
+		}
+
+		return (needToChange ? out.toString() : s);
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/wicket/blob/64571736/wicket-util/src/test/java/org/apache/wicket/util/encoding/UrlEncoderTest.java
----------------------------------------------------------------------
diff --git a/wicket-util/src/test/java/org/apache/wicket/util/encoding/UrlEncoderTest.java b/wicket-util/src/test/java/org/apache/wicket/util/encoding/UrlEncoderTest.java
new file mode 100644
index 0000000..6679a63
--- /dev/null
+++ b/wicket-util/src/test/java/org/apache/wicket/util/encoding/UrlEncoderTest.java
@@ -0,0 +1,53 @@
+/*
+ * 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.wicket.util.encoding;
+
+import org.apache.wicket.util.crypt.CharEncoding;
+import org.apache.wicket.util.encoding.UrlEncoder;
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * Tests for {@link org.apache.wicket.util.encoding.UrlDecoder}
+ */
+public class UrlEncoderTest extends Assert
+{
+
+	/**
+	 * <a href="https://issues.apache.org/jira/browse/WICKET-3721">WICKET-3721</a> Encode
+	 * apostrophes because otherwise they get XML encoded by ComponentTag#writeOutput() to
+	 * &amp;#039; and eventually break links with javascript:
+	 */
+	@Test
+	public void encodeApostrophe()
+	{
+		assertEquals("someone%27s%20bad%20url",
+			UrlEncoder.FULL_PATH_INSTANCE.encode("someone's bad url", CharEncoding.UTF_8));
+	}
+
+	/**
+	 * Do not encode semicolon in the Url's path because it is used in ';jsessionid=...'
+	 *
+	 * https://issues.apache.org/jira/browse/WICKET-4409
+	 */
+	@Test
+	public void dontEncodeSemicolon()
+	{
+		String encoded = UrlEncoder.PATH_INSTANCE.encode("path;jsessionid=1234567890", CharEncoding.UTF_8);
+		assertEquals("path;jsessionid=1234567890", encoded);
+	}
+}