Issue #5093 Static UrlEncoded (#5098)

* Issue #5093 Static UrlEncoded

Updated UrlEncoded to static only class with no synchronization

* Fixed additional tests

* fixed formatting

Signed-off-by: gregw <gregw@webtide.com>
This commit is contained in:
Greg Wilkins 2020-07-30 17:57:38 +02:00 committed by GitHub
parent aa3bd243b4
commit 7adbf247ec
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 399 additions and 504 deletions

View File

@ -57,6 +57,7 @@ import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
import org.eclipse.jetty.server.handler.ResourceHandler;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.util.MultiMap;
import org.eclipse.jetty.util.TypeUtil;
import org.eclipse.jetty.util.UrlEncoded;
import org.junit.jupiter.api.AfterEach;
@ -834,14 +835,14 @@ public class DispatcherTest
assertEquals(null, request.getPathInfo());
assertEquals(null, request.getPathTranslated());
UrlEncoded query = new UrlEncoded();
query.decode(request.getQueryString());
MultiMap<String> query = new MultiMap<>();
UrlEncoded.decodeTo(request.getQueryString(), query, UrlEncoded.ENCODING);
assertThat(query.getString("do"), is("end"));
// Russian for "selected=Temperature"
UrlEncoded q2 = new UrlEncoded();
q2.decode(query.getString("else"));
String russian = q2.encode();
MultiMap<String> q2 = new MultiMap<>();
UrlEncoded.decodeTo(query.getString("else"), q2, UrlEncoded.ENCODING);
String russian = UrlEncoded.encode(q2, UrlEncoded.ENCODING, false);
assertThat(russian, is("%D0%B2%D1%8B%D0%B1%D1%80%D0%B0%D0%BD%D0%BE=%D0%A2%D0%B5%D0%BC%D0%BF%D0%B5%D1%80%D0%B0%D1%82%D1%83%D1%80%D0%B0"));
assertThat(query.containsKey("test"), is(false));
assertThat(query.containsKey("foreign"), is(false));

View File

@ -44,19 +44,11 @@ import static org.eclipse.jetty.util.TypeUtil.convertHexDigit;
* passing a parameter or setting the "org.eclipse.jetty.util.UrlEncoding.charset"
* System property.
* </p>
* <p>
* The hashtable either contains String single values, vectors
* of String or arrays of Strings.
* </p>
* <p>
* This class is only partially synchronised. In particular, simple
* get operations are not protected from concurrent updates.
* </p>
*
* @see java.net.URLEncoder
*/
@SuppressWarnings("serial")
public class UrlEncoded extends MultiMap<String> implements Cloneable
public class UrlEncoded
{
static final Logger LOG = LoggerFactory.getLogger(UrlEncoded.class);
@ -87,62 +79,8 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable
ENCODING = encoding;
}
public UrlEncoded(UrlEncoded url)
private UrlEncoded()
{
super(url);
}
public UrlEncoded()
{
}
public UrlEncoded(String query)
{
decodeTo(query, this, ENCODING);
}
public void decode(String query)
{
decodeTo(query, this, ENCODING);
}
public void decode(String query, Charset charset)
{
decodeTo(query, this, charset);
}
/**
* Encode MultiMap with % encoding for UTF8 sequences.
*
* @return the MultiMap as a string with % encoding
*/
public String encode()
{
return encode(ENCODING, false);
}
/**
* Encode MultiMap with % encoding for arbitrary Charset sequences.
*
* @param charset the charset to use for encoding
* @return the MultiMap as a string encoded with % encodings
*/
public String encode(Charset charset)
{
return encode(charset, false);
}
/**
* Encode MultiMap with % encoding.
*
* @param charset the charset to encode with
* @param equalsForNullValue if True, then an '=' is always used, even
* for parameters without a value. e.g. <code>"blah?a=&amp;b=&amp;c="</code>.
* @return the MultiMap as a string encoded with % encodings
*/
public synchronized String encode(Charset charset, boolean equalsForNullValue)
{
return encode(this, charset, equalsForNullValue);
}
/**
@ -190,11 +128,10 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable
if (val != null)
{
String str = val;
if (str.length() > 0)
if (val.length() > 0)
{
result.append('=');
result.append(encodeString(str, charset));
result.append(encodeString(val, charset));
}
else if (equalsForNullValue)
result.append('=');
@ -228,6 +165,18 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable
* @param charset the charset to use for decoding
*/
public static void decodeTo(String content, MultiMap<String> map, Charset charset)
{
decodeTo(content, map, charset, -1);
}
/**
* Decoded parameters to Map.
*
* @param content the string containing the encoded parameters
* @param map the MultiMap to put parsed query parameters into
* @param charset the charset to use for decoding
*/
public static void decodeTo(String content, MultiMap<String> map, Charset charset, int maxKeys)
{
if (charset == null)
charset = ENCODING;
@ -238,64 +187,62 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable
return;
}
synchronized (map)
String key = null;
String value;
int mark = -1;
boolean encoded = false;
for (int i = 0; i < content.length(); i++)
{
String key = null;
String value;
int mark = -1;
boolean encoded = false;
for (int i = 0; i < content.length(); i++)
char c = content.charAt(i);
switch (c)
{
char c = content.charAt(i);
switch (c)
{
case '&':
int l = i - mark - 1;
value = l == 0 ? "" : (encoded ? decodeString(content, mark + 1, l, charset) : content.substring(mark + 1, i));
mark = i;
encoded = false;
if (key != null)
{
map.add(key, value);
}
else if (value != null && value.length() > 0)
{
map.add(value, "");
}
key = null;
value = null;
case '&':
int l = i - mark - 1;
value = l == 0 ? "" : (encoded ? decodeString(content, mark + 1, l, charset) : content.substring(mark + 1, i));
mark = i;
encoded = false;
if (key != null)
{
map.add(key, value);
}
else if (value != null && value.length() > 0)
{
map.add(value, "");
}
checkMaxKeys(map, maxKeys);
key = null;
value = null;
break;
case '=':
if (key != null)
break;
case '=':
if (key != null)
break;
key = encoded ? decodeString(content, mark + 1, i - mark - 1, charset) : content.substring(mark + 1, i);
mark = i;
encoded = false;
break;
case '+':
encoded = true;
break;
case '%':
encoded = true;
break;
}
key = encoded ? decodeString(content, mark + 1, i - mark - 1, charset) : content.substring(mark + 1, i);
mark = i;
encoded = false;
break;
case '+':
case '%':
encoded = true;
break;
}
}
if (key != null)
if (key != null)
{
int l = content.length() - mark - 1;
value = l == 0 ? "" : (encoded ? decodeString(content, mark + 1, l, charset) : content.substring(mark + 1));
map.add(key, value);
checkMaxKeys(map, maxKeys);
}
else if (mark < content.length())
{
key = encoded
? decodeString(content, mark + 1, content.length() - mark - 1, charset)
: content.substring(mark + 1);
if (key != null && key.length() > 0)
{
int l = content.length() - mark - 1;
value = l == 0 ? "" : (encoded ? decodeString(content, mark + 1, l, charset) : content.substring(mark + 1));
map.add(key, value);
}
else if (mark < content.length())
{
key = encoded
? decodeString(content, mark + 1, content.length() - mark - 1, charset)
: content.substring(mark + 1);
if (key != null && key.length() > 0)
{
map.add(key, "");
}
map.add(key, "");
checkMaxKeys(map, maxKeys);
}
}
}
@ -316,76 +263,73 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable
public static void decodeUtf8To(String query, int offset, int length, MultiMap<String> map)
{
Utf8StringBuilder buffer = new Utf8StringBuilder();
synchronized (map)
String key = null;
String value;
int end = offset + length;
for (int i = offset; i < end; i++)
{
String key = null;
String value = null;
int end = offset + length;
for (int i = offset; i < end; i++)
char c = query.charAt(i);
switch (c)
{
char c = query.charAt(i);
switch (c)
{
case '&':
value = buffer.toReplacedString();
buffer.reset();
if (key != null)
{
map.add(key, value);
}
else if (value != null && value.length() > 0)
{
map.add(value, "");
}
key = null;
value = null;
break;
case '&':
value = buffer.toReplacedString();
buffer.reset();
if (key != null)
{
map.add(key, value);
}
else if (value != null && value.length() > 0)
{
map.add(value, "");
}
key = null;
break;
case '=':
if (key != null)
{
buffer.append(c);
break;
}
key = buffer.toReplacedString();
buffer.reset();
break;
case '+':
buffer.append((byte)' ');
break;
case '%':
if (i + 2 < end)
{
char hi = query.charAt(++i);
char lo = query.charAt(++i);
buffer.append(decodeHexByte(hi, lo));
}
else
{
throw new Utf8Appendable.NotUtf8Exception("Incomplete % encoding");
}
break;
default:
case '=':
if (key != null)
{
buffer.append(c);
break;
}
}
}
key = buffer.toReplacedString();
buffer.reset();
break;
if (key != null)
{
value = buffer.toReplacedString();
buffer.reset();
map.add(key, value);
}
else if (buffer.length() > 0)
{
map.add(buffer.toReplacedString(), "");
case '+':
buffer.append((byte)' ');
break;
case '%':
if (i + 2 < end)
{
char hi = query.charAt(++i);
char lo = query.charAt(++i);
buffer.append(decodeHexByte(hi, lo));
}
else
{
throw new Utf8Appendable.NotUtf8Exception("Incomplete % encoding");
}
break;
default:
buffer.append(c);
break;
}
}
if (key != null)
{
value = buffer.toReplacedString();
buffer.reset();
map.add(key, value);
}
else if (buffer.length() > 0)
{
map.add(buffer.toReplacedString(), "");
}
}
/**
@ -400,74 +344,70 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable
public static void decode88591To(InputStream in, MultiMap<String> map, int maxLength, int maxKeys)
throws IOException
{
synchronized (map)
StringBuilder buffer = new StringBuilder();
String key = null;
String value;
int b;
int totalLength = 0;
while ((b = in.read()) >= 0)
{
StringBuilder buffer = new StringBuilder();
String key = null;
String value = null;
int b;
int totalLength = 0;
while ((b = in.read()) >= 0)
switch ((char)b)
{
switch ((char)b)
{
case '&':
value = buffer.length() == 0 ? "" : buffer.toString();
buffer.setLength(0);
if (key != null)
{
map.add(key, value);
}
else if (value.length() > 0)
{
map.add(value, "");
}
key = null;
value = null;
checkMaxKeys(map, maxKeys);
break;
case '&':
value = buffer.length() == 0 ? "" : buffer.toString();
buffer.setLength(0);
if (key != null)
{
map.add(key, value);
}
else if (value.length() > 0)
{
map.add(value, "");
}
key = null;
checkMaxKeys(map, maxKeys);
break;
case '=':
if (key != null)
{
buffer.append((char)b);
break;
}
key = buffer.toString();
buffer.setLength(0);
break;
case '+':
buffer.append(' ');
break;
case '%':
int code0 = in.read();
int code1 = in.read();
buffer.append(decodeHexChar(code0, code1));
break;
default:
case '=':
if (key != null)
{
buffer.append((char)b);
break;
}
checkMaxLength(++totalLength, maxLength);
}
}
key = buffer.toString();
buffer.setLength(0);
break;
if (key != null)
{
value = buffer.length() == 0 ? "" : buffer.toString();
buffer.setLength(0);
map.add(key, value);
case '+':
buffer.append(' ');
break;
case '%':
int code0 = in.read();
int code1 = in.read();
buffer.append(decodeHexChar(code0, code1));
break;
default:
buffer.append((char)b);
break;
}
else if (buffer.length() > 0)
{
map.add(buffer.toString(), "");
}
checkMaxKeys(map, maxKeys);
checkMaxLength(++totalLength, maxLength);
}
if (key != null)
{
value = buffer.length() == 0 ? "" : buffer.toString();
buffer.setLength(0);
map.add(key, value);
}
else if (buffer.length() > 0)
{
map.add(buffer.toString(), "");
}
checkMaxKeys(map, maxKeys);
}
/**
@ -482,74 +422,70 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable
public static void decodeUtf8To(InputStream in, MultiMap<String> map, int maxLength, int maxKeys)
throws IOException
{
synchronized (map)
Utf8StringBuilder buffer = new Utf8StringBuilder();
String key = null;
String value;
int b;
int totalLength = 0;
while ((b = in.read()) >= 0)
{
Utf8StringBuilder buffer = new Utf8StringBuilder();
String key = null;
String value = null;
int b;
int totalLength = 0;
while ((b = in.read()) >= 0)
switch ((char)b)
{
switch ((char)b)
{
case '&':
value = buffer.toReplacedString();
buffer.reset();
if (key != null)
{
map.add(key, value);
}
else if (value != null && value.length() > 0)
{
map.add(value, "");
}
key = null;
value = null;
checkMaxKeys(map, maxKeys);
break;
case '&':
value = buffer.toReplacedString();
buffer.reset();
if (key != null)
{
map.add(key, value);
}
else if (value != null && value.length() > 0)
{
map.add(value, "");
}
key = null;
checkMaxKeys(map, maxKeys);
break;
case '=':
if (key != null)
{
buffer.append((byte)b);
break;
}
key = buffer.toReplacedString();
buffer.reset();
break;
case '+':
buffer.append((byte)' ');
break;
case '%':
char code0 = (char)in.read();
char code1 = (char)in.read();
buffer.append(decodeHexByte(code0, code1));
break;
default:
case '=':
if (key != null)
{
buffer.append((byte)b);
break;
}
checkMaxLength(++totalLength, maxLength);
}
}
key = buffer.toReplacedString();
buffer.reset();
break;
if (key != null)
{
value = buffer.toReplacedString();
buffer.reset();
map.add(key, value);
case '+':
buffer.append((byte)' ');
break;
case '%':
char code0 = (char)in.read();
char code1 = (char)in.read();
buffer.append(decodeHexByte(code0, code1));
break;
default:
buffer.append((byte)b);
break;
}
else if (buffer.length() > 0)
{
map.add(buffer.toReplacedString(), "");
}
checkMaxKeys(map, maxKeys);
checkMaxLength(++totalLength, maxLength);
}
if (key != null)
{
value = buffer.toReplacedString();
buffer.reset();
map.add(key, value);
}
else if (buffer.length() > 0)
{
map.add(buffer.toReplacedString(), "");
}
checkMaxKeys(map, maxKeys);
}
public static void decodeUtf16To(InputStream in, MultiMap<String> map, int maxLength, int maxKeys) throws IOException
@ -558,8 +494,7 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable
StringWriter buf = new StringWriter(8192);
IO.copy(input, buf, maxLength);
// TODO implement maxKeys
decodeTo(buf.getBuffer().toString(), map, StandardCharsets.UTF_16);
decodeTo(buf.getBuffer().toString(), map, StandardCharsets.UTF_16, maxKeys);
}
/**
@ -627,77 +562,73 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable
return;
}
synchronized (map)
String key = null;
String value;
int c;
int totalLength = 0;
try (ByteArrayOutputStream2 output = new ByteArrayOutputStream2())
{
String key = null;
String value = null;
int size;
int c;
int totalLength = 0;
try (ByteArrayOutputStream2 output = new ByteArrayOutputStream2())
while ((c = in.read()) > 0)
{
int size = 0;
while ((c = in.read()) > 0)
switch ((char)c)
{
switch ((char)c)
{
case '&':
size = output.size();
value = size == 0 ? "" : output.toString(charset);
output.setCount(0);
if (key != null)
{
map.add(key, value);
}
else if (value != null && value.length() > 0)
{
map.add(value, "");
}
key = null;
value = null;
checkMaxKeys(map, maxKeys);
break;
case '=':
if (key != null)
{
output.write(c);
break;
}
size = output.size();
key = size == 0 ? "" : output.toString(charset);
output.setCount(0);
break;
case '+':
output.write(' ');
break;
case '%':
int code0 = in.read();
int code1 = in.read();
output.write(decodeHexChar(code0, code1));
break;
default:
case '&':
size = output.size();
value = size == 0 ? "" : output.toString(charset);
output.setCount(0);
if (key != null)
{
map.add(key, value);
}
else if (value != null && value.length() > 0)
{
map.add(value, "");
}
key = null;
checkMaxKeys(map, maxKeys);
break;
case '=':
if (key != null)
{
output.write(c);
break;
}
checkMaxLength(++totalLength, maxLength);
}
size = output.size();
key = size == 0 ? "" : output.toString(charset);
output.setCount(0);
break;
case '+':
output.write(' ');
break;
case '%':
int code0 = in.read();
int code1 = in.read();
output.write(decodeHexChar(code0, code1));
break;
default:
output.write(c);
break;
}
size = output.size();
if (key != null)
{
value = size == 0 ? "" : output.toString(charset);
output.setCount(0);
map.add(key, value);
}
else if (size > 0)
{
map.add(output.toString(charset), "");
}
checkMaxKeys(map, maxKeys);
checkMaxLength(++totalLength, maxLength);
}
size = output.size();
if (key != null)
{
value = size == 0 ? "" : output.toString(charset);
output.setCount(0);
map.add(key, value);
}
else if (size > 0)
{
map.add(output.toString(charset), "");
}
checkMaxKeys(map, maxKeys);
}
}
@ -747,7 +678,7 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable
for (int i = 0; i < length; i++)
{
char c = encoded.charAt(offset + i);
if (c < 0 || c > 0xff)
if (c > 0xff)
{
if (buffer == null)
{
@ -808,7 +739,7 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable
for (int i = 0; i < length; i++)
{
char c = encoded.charAt(offset + i);
if (c < 0 || c > 0xff)
if (c > 0xff)
{
if (buffer == null)
{
@ -838,7 +769,7 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable
byte[] ba = new byte[length];
int n = 0;
while (c >= 0 && c <= 0xff)
while (c <= 0xff)
{
if (c == '%')
{
@ -935,18 +866,15 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable
{
if (charset == null)
charset = ENCODING;
byte[] bytes = null;
byte[] bytes;
bytes = string.getBytes(charset);
int len = bytes.length;
byte[] encoded = new byte[bytes.length * 3];
int n = 0;
boolean noEncode = true;
for (int i = 0; i < len; i++)
for (byte b : bytes)
{
byte b = bytes[i];
if (b == ' ')
{
noEncode = false;
@ -981,10 +909,4 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable
return new String(encoded, 0, n, charset);
}
@Override
public Object clone()
{
return new UrlEncoded(this);
}
}

View File

@ -24,15 +24,21 @@ import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Stream;
import org.junit.jupiter.api.DynamicTest;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestFactory;
import org.junit.jupiter.api.condition.EnabledIfSystemProperty;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.DynamicTest.dynamicTest;
@ -49,97 +55,97 @@ public class URLEncodedTest
tests.add(dynamicTest("Initially not empty", () ->
{
UrlEncoded urlEncoded = new UrlEncoded();
MultiMap<String> urlEncoded = new MultiMap<>();
assertEquals(0, urlEncoded.size());
}));
tests.add(dynamicTest("Not empty after decode(\"\")", () ->
{
UrlEncoded urlEncoded = new UrlEncoded();
MultiMap<String> urlEncoded = new MultiMap<>();
urlEncoded.clear();
urlEncoded.decode("");
UrlEncoded.decodeTo("", urlEncoded, UrlEncoded.ENCODING);
assertEquals(0, urlEncoded.size());
}));
tests.add(dynamicTest("Simple encode", () ->
{
UrlEncoded urlEncoded = new UrlEncoded();
MultiMap<String> urlEncoded = new MultiMap<>();
urlEncoded.clear();
urlEncoded.decode("Name1=Value1");
UrlEncoded.decodeTo("Name1=Value1", urlEncoded, UrlEncoded.ENCODING);
assertEquals(1, urlEncoded.size(), "simple param size");
assertEquals("Name1=Value1", urlEncoded.encode(), "simple encode");
assertEquals("Name1=Value1", UrlEncoded.encode(urlEncoded,UrlEncoded.ENCODING, false), "simple encode");
assertEquals("Value1", urlEncoded.getString("Name1"), "simple get");
}));
tests.add(dynamicTest("Dangling param", () ->
{
UrlEncoded urlEncoded = new UrlEncoded();
MultiMap<String> urlEncoded = new MultiMap<>();
urlEncoded.clear();
urlEncoded.decode("Name2=");
UrlEncoded.decodeTo("Name2=", urlEncoded, UrlEncoded.ENCODING);
assertEquals(1, urlEncoded.size(), "dangling param size");
assertEquals("Name2", urlEncoded.encode(), "dangling encode");
assertEquals("Name2", UrlEncoded.encode(urlEncoded,UrlEncoded.ENCODING, false), "dangling encode");
assertEquals("", urlEncoded.getString("Name2"), "dangling get");
}));
tests.add(dynamicTest("noValue param", () ->
{
UrlEncoded urlEncoded = new UrlEncoded();
MultiMap<String> urlEncoded = new MultiMap<>();
urlEncoded.clear();
urlEncoded.decode("Name3");
UrlEncoded.decodeTo("Name3", urlEncoded, UrlEncoded.ENCODING);
assertEquals(1, urlEncoded.size(), "noValue param size");
assertEquals("Name3", urlEncoded.encode(), "noValue encode");
assertEquals("Name3", UrlEncoded.encode(urlEncoded,UrlEncoded.ENCODING, false), "noValue encode");
assertEquals("", urlEncoded.getString("Name3"), "noValue get");
}));
tests.add(dynamicTest("badly encoded param", () ->
{
UrlEncoded urlEncoded = new UrlEncoded();
MultiMap<String> urlEncoded = new MultiMap<>();
urlEncoded.clear();
urlEncoded.decode("Name4=V\u0629lue+4%21");
UrlEncoded.decodeTo("Name4=V\u0629lue+4%21", urlEncoded, UrlEncoded.ENCODING);
assertEquals(1, urlEncoded.size(), "encoded param size");
assertEquals("Name4=V%D8%A9lue+4%21", urlEncoded.encode(), "encoded encode");
assertEquals("Name4=V%D8%A9lue+4%21", UrlEncoded.encode(urlEncoded,UrlEncoded.ENCODING, false), "encoded encode");
assertEquals("V\u0629lue 4!", urlEncoded.getString("Name4"), "encoded get");
}));
tests.add(dynamicTest("encoded param 1", () ->
{
UrlEncoded urlEncoded = new UrlEncoded();
MultiMap<String> urlEncoded = new MultiMap<>();
urlEncoded.clear();
urlEncoded.decode("Name4=Value%2B4%21");
UrlEncoded.decodeTo("Name4=Value%2B4%21", urlEncoded, UrlEncoded.ENCODING);
assertEquals(1, urlEncoded.size(), "encoded param size");
assertEquals("Name4=Value%2B4%21", urlEncoded.encode(), "encoded encode");
assertEquals("Name4=Value%2B4%21", UrlEncoded.encode(urlEncoded,UrlEncoded.ENCODING, false), "encoded encode");
assertEquals("Value+4!", urlEncoded.getString("Name4"), "encoded get");
}));
tests.add(dynamicTest("encoded param 2", () ->
{
UrlEncoded urlEncoded = new UrlEncoded();
MultiMap<String> urlEncoded = new MultiMap<>();
urlEncoded.clear();
urlEncoded.decode("Name4=Value+4%21%20%214");
UrlEncoded.decodeTo("Name4=Value+4%21%20%214", urlEncoded, UrlEncoded.ENCODING);
assertEquals(1, urlEncoded.size(), "encoded param size");
assertEquals("Name4=Value+4%21+%214", urlEncoded.encode(), "encoded encode");
assertEquals("Name4=Value+4%21+%214", UrlEncoded.encode(urlEncoded,UrlEncoded.ENCODING, false), "encoded encode");
assertEquals("Value 4! !4", urlEncoded.getString("Name4"), "encoded get");
}));
tests.add(dynamicTest("multi param", () ->
{
UrlEncoded urlEncoded = new UrlEncoded();
MultiMap<String> urlEncoded = new MultiMap<>();
urlEncoded.clear();
urlEncoded.decode("Name5=aaa&Name6=bbb");
UrlEncoded.decodeTo("Name5=aaa&Name6=bbb", urlEncoded, UrlEncoded.ENCODING);
assertEquals(2, urlEncoded.size(), "multi param size");
assertTrue(urlEncoded.encode().equals("Name5=aaa&Name6=bbb") ||
urlEncoded.encode().equals("Name6=bbb&Name5=aaa"),
"multi encode " + urlEncoded.encode());
assertTrue(UrlEncoded.encode(urlEncoded,UrlEncoded.ENCODING, false).equals("Name5=aaa&Name6=bbb") ||
UrlEncoded.encode(urlEncoded,UrlEncoded.ENCODING, false).equals("Name6=bbb&Name5=aaa"),
"multi encode " + UrlEncoded.encode(urlEncoded,UrlEncoded.ENCODING, false));
assertEquals("aaa", urlEncoded.getString("Name5"), "multi get");
assertEquals("bbb", urlEncoded.getString("Name6"), "multi get");
}));
tests.add(dynamicTest("multiple value encoded", () ->
{
UrlEncoded urlEncoded = new UrlEncoded();
MultiMap<String> urlEncoded = new MultiMap<>();
urlEncoded.clear();
urlEncoded.decode("Name7=aaa&Name7=b%2Cb&Name7=ccc");
assertEquals("Name7=aaa&Name7=b%2Cb&Name7=ccc", urlEncoded.encode(), "multi encode");
UrlEncoded.decodeTo("Name7=aaa&Name7=b%2Cb&Name7=ccc", urlEncoded, UrlEncoded.ENCODING);
assertEquals("Name7=aaa&Name7=b%2Cb&Name7=ccc", UrlEncoded.encode(urlEncoded,UrlEncoded.ENCODING, false), "multi encode");
assertEquals("aaa,b,b,ccc", urlEncoded.getString("Name7"), "list get all");
assertEquals("aaa", urlEncoded.getValues("Name7").get(0), "list get");
assertEquals("b,b", urlEncoded.getValues("Name7").get(1), "list get");
@ -148,11 +154,11 @@ public class URLEncodedTest
tests.add(dynamicTest("encoded param", () ->
{
UrlEncoded urlEncoded = new UrlEncoded();
MultiMap<String> urlEncoded = new MultiMap<>();
urlEncoded.clear();
urlEncoded.decode("Name8=xx%2C++yy++%2Czz");
UrlEncoded.decodeTo("Name8=xx%2C++yy++%2Czz", urlEncoded, UrlEncoded.ENCODING);
assertEquals(1, urlEncoded.size(), "encoded param size");
assertEquals("Name8=xx%2C++yy++%2Czz", urlEncoded.encode(), "encoded encode");
assertEquals("Name8=xx%2C++yy++%2Czz", UrlEncoded.encode(urlEncoded,UrlEncoded.ENCODING, false), "encoded encode");
assertEquals("xx, yy ,zz", urlEncoded.getString("Name8"), "encoded get");
}));
@ -219,7 +225,7 @@ public class URLEncodedTest
{
try (ByteArrayInputStream in3 = new ByteArrayInputStream("name=libell%E9".getBytes(StringUtil.__ISO_8859_1)))
{
MultiMap m3 = new MultiMap();
MultiMap<String> m3 = new MultiMap<>();
Charset nullCharset = null; // use the one from the system property
UrlEncoded.decodeTo(in3, m3, nullCharset, -1, -1);
assertEquals("libell\u00E9", m3.getString("name"), "stream name");
@ -230,11 +236,11 @@ public class URLEncodedTest
public void testUtf8()
throws Exception
{
UrlEncoded urlEncoded = new UrlEncoded();
MultiMap<String> urlEncoded = new MultiMap<>();
assertEquals(0, urlEncoded.size(), "Empty");
urlEncoded.clear();
urlEncoded.decode("text=%E0%B8%9F%E0%B8%AB%E0%B8%81%E0%B8%A7%E0%B8%94%E0%B8%B2%E0%B9%88%E0%B8%81%E0%B8%9F%E0%B8%A7%E0%B8%AB%E0%B8%AA%E0%B8%94%E0%B8%B2%E0%B9%88%E0%B8%AB%E0%B8%9F%E0%B8%81%E0%B8%A7%E0%B8%94%E0%B8%AA%E0%B8%B2%E0%B8%9F%E0%B8%81%E0%B8%AB%E0%B8%A3%E0%B8%94%E0%B9%89%E0%B8%9F%E0%B8%AB%E0%B8%99%E0%B8%81%E0%B8%A3%E0%B8%94%E0%B8%B5&Action=Submit");
UrlEncoded.decodeTo("text=%E0%B8%9F%E0%B8%AB%E0%B8%81%E0%B8%A7%E0%B8%94%E0%B8%B2%E0%B9%88%E0%B8%81%E0%B8%9F%E0%B8%A7%E0%B8%AB%E0%B8%AA%E0%B8%94%E0%B8%B2%E0%B9%88%E0%B8%AB%E0%B8%9F%E0%B8%81%E0%B8%A7%E0%B8%94%E0%B8%AA%E0%B8%B2%E0%B8%9F%E0%B8%81%E0%B8%AB%E0%B8%A3%E0%B8%94%E0%B9%89%E0%B8%9F%E0%B8%AB%E0%B8%99%E0%B8%81%E0%B8%A3%E0%B8%94%E0%B8%B5&Action=Submit", urlEncoded, UrlEncoded.ENCODING);
String hex = "E0B89FE0B8ABE0B881E0B8A7E0B894E0B8B2E0B988E0B881E0B89FE0B8A7E0B8ABE0B8AAE0B894E0B8B2E0B988E0B8ABE0B89FE0B881E0B8A7E0B894E0B8AAE0B8B2E0B89FE0B881E0B8ABE0B8A3E0B894E0B989E0B89FE0B8ABE0B899E0B881E0B8A3E0B894E0B8B5";
String expected = new String(TypeUtil.fromHexString(hex), "utf-8");
@ -245,8 +251,8 @@ public class URLEncodedTest
public void testUtf8MultiByteCodePoint()
{
String input = "text=test%C3%A4";
UrlEncoded urlEncoded = new UrlEncoded();
urlEncoded.decode(input);
MultiMap<String> urlEncoded = new MultiMap<>();
UrlEncoded.decodeTo(input, urlEncoded, UrlEncoded.ENCODING);
// http://www.ltg.ed.ac.uk/~richard/utf-8.cgi?input=00e4&mode=hex
// Should be "testä"
@ -255,4 +261,50 @@ public class URLEncodedTest
String expected = "test\u00e4";
assertThat(urlEncoded.getString("text"), is(expected));
}
public static Stream<Arguments> invalidTestData()
{
ArrayList<Arguments> data = new ArrayList<>();
data.add(Arguments.of("Name=xx%zzyy", UTF_8, IllegalArgumentException.class));
data.add(Arguments.of("Name=%FF%FF%FF", UTF_8, Utf8Appendable.NotUtf8Exception.class));
data.add(Arguments.of("Name=%EF%EF%EF", UTF_8, Utf8Appendable.NotUtf8Exception.class));
data.add(Arguments.of("Name=%E%F%F", UTF_8, IllegalArgumentException.class));
data.add(Arguments.of("Name=x%", UTF_8, Utf8Appendable.NotUtf8Exception.class));
data.add(Arguments.of("Name=x%2", UTF_8, Utf8Appendable.NotUtf8Exception.class));
data.add(Arguments.of("Name=xxx%", UTF_8, Utf8Appendable.NotUtf8Exception.class));
data.add(Arguments.of("name=X%c0%afZ", UTF_8, Utf8Appendable.NotUtf8Exception.class));
return data.stream();
}
@ParameterizedTest
@MethodSource("invalidTestData")
public void testInvalidDecode(String inputString, Charset charset, Class<? extends Throwable> expectedThrowable)
{
assertThrows(expectedThrowable, () ->
{
UrlEncoded.decodeTo(inputString, new MultiMap<>(), charset);
});
}
@ParameterizedTest
@MethodSource("invalidTestData")
public void testInvalidDecodeUtf8ToMap(String inputString, Charset charset, Class<? extends Throwable> expectedThrowable)
{
assertThrows(expectedThrowable, () ->
{
MultiMap<String> map = new MultiMap<>();
UrlEncoded.decodeUtf8To(inputString, map);
});
}
@ParameterizedTest
@MethodSource("invalidTestData")
public void testInvalidDecodeTo(String inputString, Charset charset, Class<? extends Throwable> expectedThrowable)
{
assertThrows(expectedThrowable, () ->
{
MultiMap<String> map = new MultiMap<>();
UrlEncoded.decodeTo(inputString, map, charset);
});
}
}

View File

@ -1,80 +0,0 @@
//
// ========================================================================
// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under
// the terms of the Eclipse Public License 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0
//
// This Source Code may also be made available under the following
// Secondary Licenses when the conditions for such availability set
// forth in the Eclipse Public License, v. 2.0 are satisfied:
// the Apache License v2.0 which is available at
// https://www.apache.org/licenses/LICENSE-2.0
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
package org.eclipse.jetty.util;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.stream.Stream;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.junit.jupiter.api.Assertions.assertThrows;
public class UrlEncodedInvalidEncodingTest
{
public static Stream<Arguments> data()
{
ArrayList<Arguments> data = new ArrayList<>();
data.add(Arguments.of("Name=xx%zzyy", UTF_8, IllegalArgumentException.class));
data.add(Arguments.of("Name=%FF%FF%FF", UTF_8, Utf8Appendable.NotUtf8Exception.class));
data.add(Arguments.of("Name=%EF%EF%EF", UTF_8, Utf8Appendable.NotUtf8Exception.class));
data.add(Arguments.of("Name=%E%F%F", UTF_8, IllegalArgumentException.class));
data.add(Arguments.of("Name=x%", UTF_8, Utf8Appendable.NotUtf8Exception.class));
data.add(Arguments.of("Name=x%2", UTF_8, Utf8Appendable.NotUtf8Exception.class));
data.add(Arguments.of("Name=xxx%", UTF_8, Utf8Appendable.NotUtf8Exception.class));
data.add(Arguments.of("name=X%c0%afZ", UTF_8, Utf8Appendable.NotUtf8Exception.class));
return data.stream();
}
@ParameterizedTest
@MethodSource("data")
public void testDecode(String inputString, Charset charset, Class<? extends Throwable> expectedThrowable)
{
assertThrows(expectedThrowable, () ->
{
UrlEncoded urlEncoded = new UrlEncoded();
urlEncoded.decode(inputString, charset);
});
}
@ParameterizedTest
@MethodSource("data")
public void testDecodeUtf8ToMap(String inputString, Charset charset, Class<? extends Throwable> expectedThrowable)
{
assertThrows(expectedThrowable, () ->
{
MultiMap<String> map = new MultiMap<>();
UrlEncoded.decodeUtf8To(inputString, map);
});
}
@ParameterizedTest
@MethodSource("data")
public void testDecodeTo(String inputString, Charset charset, Class<? extends Throwable> expectedThrowable)
{
assertThrows(expectedThrowable, () ->
{
MultiMap<String> map = new MultiMap<>();
UrlEncoded.decodeTo(inputString, map, charset);
});
}
}

View File

@ -79,7 +79,7 @@ public class SessionDump extends HttpServlet
session = request.getSession(true);
session.setAttribute("test", "value");
session.setAttribute("obj", new ObjectAttributeValue(System.currentTimeMillis()));
session.setAttribute("WEBCL", new MultiMap());
session.setAttribute("WEBCL", new MultiMap<>());
}
else if (session != null)
{
@ -137,7 +137,7 @@ public class SessionDump extends HttpServlet
else
{
if (session.getAttribute("WEBCL") == null)
session.setAttribute("WEBCL", new MultiMap());
session.setAttribute("WEBCL", new MultiMap<>());
try
{
out.println("<b>ID:</b> " + session.getId() + "<br/>");