fix percent decoding when parameter is query domain
This commit is contained in:
parent
3a4a3c692f
commit
183041acd3
9 changed files with 78 additions and 17 deletions
|
@ -1,5 +1,5 @@
|
|||
group = org.xbib
|
||||
name = net
|
||||
version = 4.0.0
|
||||
version = 4.0.1
|
||||
|
||||
org.gradle.warning.mode = ALL
|
||||
|
|
|
@ -4,34 +4,39 @@ import org.xbib.net.Parameter;
|
|||
import org.xbib.net.ParameterBuilder;
|
||||
import org.xbib.net.PathNormalizer;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
public class PathDecoder {
|
||||
|
||||
private final String path;
|
||||
|
||||
private final String query;
|
||||
|
||||
private final Charset charset;
|
||||
|
||||
private final ParameterBuilder params;
|
||||
|
||||
public PathDecoder(String pathAndQuery) {
|
||||
this(pathAndQuery, null);
|
||||
public PathDecoder(String pathAndQuery, Charset charset) {
|
||||
this(pathAndQuery, null, charset);
|
||||
}
|
||||
|
||||
public PathDecoder(String pathAndQuery, String queryString) {
|
||||
public PathDecoder(String pathAndQuery, String queryString, Charset charset) {
|
||||
this.charset = charset;
|
||||
int pos = pathAndQuery.indexOf('?');
|
||||
String path = pos > 0 ? pathAndQuery.substring(0, pos) : pathAndQuery;
|
||||
this.query = pos > 0 ? pathAndQuery.substring(pos + 1) : null;
|
||||
this.path = PathNormalizer.normalize(path);
|
||||
this.params = Parameter.builder().domain(Parameter.Domain.PATH).enablePercentDecoding();
|
||||
if (query != null) {
|
||||
this.params.add(query);
|
||||
this.params.add(query, charset);
|
||||
}
|
||||
if (queryString != null) {
|
||||
this.params.add(queryString);
|
||||
this.params.add(queryString, charset);
|
||||
}
|
||||
}
|
||||
|
||||
public void parse(String queryString) {
|
||||
this.params.add(queryString);
|
||||
this.params.add(queryString, charset);
|
||||
}
|
||||
|
||||
public String path() {
|
||||
|
|
|
@ -4,6 +4,8 @@ import org.junit.jupiter.api.Test;
|
|||
import org.xbib.net.Parameter;
|
||||
import org.xbib.net.URL;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
|
||||
|
@ -11,27 +13,27 @@ class PathDecoderTest {
|
|||
|
||||
@Test
|
||||
void testPlusSign() throws Exception {
|
||||
PathDecoder decoder = new PathDecoder("/path?a=b+c", "d=e+f");
|
||||
PathDecoder decoder = new PathDecoder("/path?a=b+c", "d=e+f", StandardCharsets.UTF_8);
|
||||
assertEquals("[b c]", decoder.getParameter().getAll("a", Parameter.Domain.PATH).toString());
|
||||
assertEquals("[e f]", decoder.getParameter().getAll("d", Parameter.Domain.PATH).toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSlash() throws Exception {
|
||||
PathDecoder decoder = new PathDecoder("path/foo/bar/?a=b+c", "d=e+f");
|
||||
PathDecoder decoder = new PathDecoder("path/foo/bar/?a=b+c", "d=e+f", StandardCharsets.UTF_8);
|
||||
assertEquals("[b c]", decoder.getParameter().getAll("a", Parameter.Domain.PATH).toString());
|
||||
assertEquals("[e f]", decoder.getParameter().getAll("d", Parameter.Domain.PATH).toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDoubleSlashes() {
|
||||
PathDecoder decoder = new PathDecoder("//path", "");
|
||||
PathDecoder decoder = new PathDecoder("//path", "", StandardCharsets.UTF_8);
|
||||
assertEquals("/path", decoder.path());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSlashes() throws Exception {
|
||||
PathDecoder decoder = new PathDecoder("//path?a=b+c", "d=e+f");
|
||||
PathDecoder decoder = new PathDecoder("//path?a=b+c", "d=e+f", StandardCharsets.UTF_8);
|
||||
assertEquals("/path", decoder.path());
|
||||
assertEquals("[b c]", decoder.getParameter().getAll("a", Parameter.Domain.PATH).toString());
|
||||
assertEquals("[e f]", decoder.getParameter().getAll("d", Parameter.Domain.PATH).toString());
|
||||
|
@ -39,7 +41,7 @@ class PathDecoderTest {
|
|||
|
||||
@Test
|
||||
void testPlusPercent() throws Exception {
|
||||
PathDecoder decoder = new PathDecoder("//path?a=b%2Bc", "d=e%2Bf");
|
||||
PathDecoder decoder = new PathDecoder("//path?a=b%2Bc", "d=e%2Bf", StandardCharsets.UTF_8);
|
||||
assertEquals("/path", decoder.path());
|
||||
assertEquals("[b+c]", decoder.getParameter().getAll("a", Parameter.Domain.PATH).toString());
|
||||
assertEquals("[e+f]", decoder.getParameter().getAll("d", Parameter.Domain.PATH).toString());
|
||||
|
@ -53,7 +55,7 @@ class PathDecoderTest {
|
|||
assertNull(url.getPort());
|
||||
assertEquals("/pdfconverter/index.gtpl", url.getPath());
|
||||
assertNull(url.getFragment());
|
||||
PathDecoder decoder = new PathDecoder(requestURI);
|
||||
PathDecoder decoder = new PathDecoder(requestURI, StandardCharsets.UTF_8);
|
||||
if (url.getQuery() != null) {
|
||||
decoder.parse(url.getDecodedQuery());
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package org.xbib.net;
|
||||
|
||||
import java.nio.charset.MalformedInputException;
|
||||
import java.nio.charset.UnmappableCharacterException;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
|
@ -102,9 +104,17 @@ public class Parameter implements Iterable<Pair<String, Object>>, Comparable<Par
|
|||
} else {
|
||||
object = null;
|
||||
}
|
||||
return object != null ? object.toString() : null;
|
||||
return object != null ? decodeIfQueryDomain(domain, object.toString()) : null;
|
||||
}
|
||||
return object != null ? decodeIfQueryDomain(domain, object instanceof String ? (String) object : object.toString()) : null;
|
||||
}
|
||||
|
||||
private String decodeIfQueryDomain(Domain domain, String string) throws ParameterException {
|
||||
try {
|
||||
return Domain.QUERY == domain ? builder().percentDecode(string) : string;
|
||||
} catch (UnmappableCharacterException | MalformedInputException e) {
|
||||
throw new ParameterException(e);
|
||||
}
|
||||
return object != null ? object instanceof String ? (String) object : object.toString() : null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
|
|
@ -14,6 +14,8 @@ import java.util.Iterator;
|
|||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.xbib.datastructures.common.ImmutableList;
|
||||
import org.xbib.datastructures.common.MultiMap;
|
||||
import org.xbib.datastructures.common.Pair;
|
||||
|
@ -107,11 +109,25 @@ public class ParameterBuilder implements PairValidator {
|
|||
return this;
|
||||
}
|
||||
|
||||
public String percentEncode(CharSequence text) throws UnmappableCharacterException, MalformedInputException {
|
||||
if (percentEncoder == null) {
|
||||
charset(StandardCharsets.UTF_8);
|
||||
}
|
||||
return percentEncoder.encode(text);
|
||||
}
|
||||
|
||||
public ParameterBuilder percentDecode(PercentDecoder percentDecoder) {
|
||||
this.percentDecoder = percentDecoder;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String percentDecode(CharSequence text) throws UnmappableCharacterException, MalformedInputException {
|
||||
if (percentDecoder == null) {
|
||||
charset(StandardCharsets.UTF_8);
|
||||
}
|
||||
return percentDecoder.decode(text);
|
||||
}
|
||||
|
||||
public ParameterBuilder enablePercentEncoding() {
|
||||
this.enablePercentEncoding = true;
|
||||
charset(StandardCharsets.UTF_8);
|
||||
|
@ -222,7 +238,11 @@ public class ParameterBuilder implements PairValidator {
|
|||
return this;
|
||||
}
|
||||
|
||||
public ParameterBuilder add(String percentEncodedQueryString) {
|
||||
public ParameterBuilder add(String percentEncodedQueryString, Charset charset) {
|
||||
Objects.requireNonNull(charset);
|
||||
if (this.charset == null || !this.charset.equals(charset)) {
|
||||
charset(charset);
|
||||
}
|
||||
try {
|
||||
decodeQueryString(percentEncodedQueryString);
|
||||
} catch (MalformedInputException | UnmappableCharacterException e) {
|
||||
|
@ -235,6 +255,9 @@ public class ParameterBuilder implements PairValidator {
|
|||
if (enableSort) {
|
||||
list.sort(Comparator.comparing(Pair::getKey));
|
||||
}
|
||||
if (percentDecoder == null) {
|
||||
charset(StandardCharsets.UTF_8);
|
||||
}
|
||||
String queryString = null;
|
||||
if (enableQueryString) {
|
||||
try {
|
||||
|
|
|
@ -3,6 +3,10 @@ package org.xbib.net;
|
|||
@SuppressWarnings("serial")
|
||||
public class ParameterException extends Exception {
|
||||
|
||||
public ParameterException(Exception e) {
|
||||
super(e);
|
||||
}
|
||||
|
||||
public ParameterException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
|
|
@ -77,6 +77,17 @@ public class ParameterTest {
|
|||
parameter.getAsQueryString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryParameterDecoding() throws ParameterException {
|
||||
Parameter parameter = Parameter.builder()
|
||||
.domain(Parameter.Domain.QUERY)
|
||||
.add("value1", "Hello%20J%C3%B6rg") // query parameter, no query string mode
|
||||
.add("value2=Hello%20J%C3%B6rg", StandardCharsets.UTF_8) // query string mode
|
||||
.build();
|
||||
assertEquals("Hello Jörg", parameter.getAsString("value1", Parameter.Domain.QUERY));
|
||||
assertEquals("Hello Jörg", parameter.getAsString("value2", Parameter.Domain.QUERY));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParameters() {
|
||||
Map<String, Object> map = Map.of(
|
||||
|
|
|
@ -56,6 +56,11 @@ class PercentDecoderTest {
|
|||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testJoerg() throws UnmappableCharacterException, MalformedInputException {
|
||||
assertEquals("Hello Jörg", decoder.decode("Hello%20J%C3%B6rg"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRandomStrings() throws MalformedInputException, UnmappableCharacterException {
|
||||
PercentEncoder encoder = PercentEncoders.getQueryEncoder(StandardCharsets.UTF_8);
|
||||
|
|
|
@ -3,6 +3,7 @@ package org.xbib.net;
|
|||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.net.URI;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.CodingErrorAction;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
@ -498,7 +499,7 @@ class URLParserTest {
|
|||
private void assertUrlCompatibility(String url) throws Exception {
|
||||
String s = URL.from(url).toExternalForm();
|
||||
assertEquals(s, URL.from(s).toExternalForm());
|
||||
assertEquals(s, new java.net.URL(url).toExternalForm());
|
||||
assertEquals(s, URI.create(url).toURL().toExternalForm());
|
||||
}
|
||||
|
||||
private void assertRoundTrip(String url) {
|
||||
|
|
Loading…
Reference in a new issue