Lenient URI template encoding
URI template encoding ignores mismatched curly braces, treating them as literal parts instead. Issue: SPR-17630
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -756,6 +756,8 @@ final class HierarchicalUriComponents extends UriComponents {
|
||||
|
||||
private final StringBuilder currentLiteral = new StringBuilder();
|
||||
|
||||
private final StringBuilder currentVariable = new StringBuilder();
|
||||
|
||||
private final StringBuilder output = new StringBuilder();
|
||||
|
||||
|
||||
@@ -767,22 +769,21 @@ final class HierarchicalUriComponents extends UriComponents {
|
||||
@Override
|
||||
public String apply(String source, Type type) {
|
||||
|
||||
// Only URI variable, nothing to encode..
|
||||
// Only URI variable (nothing to encode)..
|
||||
if (source.length() > 1 && source.charAt(0) == '{' && source.charAt(source.length() -1) == '}') {
|
||||
return source;
|
||||
}
|
||||
|
||||
// Only literal, encode all..
|
||||
// Only literal (encode full source)..
|
||||
if (source.indexOf('{') == -1) {
|
||||
return encodeUriComponent(source, this.charset, type);
|
||||
}
|
||||
|
||||
// Mixed, encode all except for URI variables..
|
||||
|
||||
// Mixed literal parts and URI variables, maybe (encode literal parts only)..
|
||||
int level = 0;
|
||||
clear(this.currentLiteral);
|
||||
clear(this.currentVariable);
|
||||
clear(this.output);
|
||||
|
||||
for (char c : source.toCharArray()) {
|
||||
if (c == '{') {
|
||||
level++;
|
||||
@@ -790,21 +791,25 @@ final class HierarchicalUriComponents extends UriComponents {
|
||||
encodeAndAppendCurrentLiteral(type);
|
||||
}
|
||||
}
|
||||
if (c == '}') {
|
||||
if (c == '}' && level > 0) {
|
||||
level--;
|
||||
Assert.isTrue(level >=0, "Mismatched open and close braces");
|
||||
this.currentVariable.append('}');
|
||||
if (level == 0) {
|
||||
this.output.append(this.currentVariable);
|
||||
clear(this.currentVariable);
|
||||
}
|
||||
}
|
||||
if (level > 0 || (level == 0 && c == '}')) {
|
||||
this.output.append(c);
|
||||
else if (level > 0) {
|
||||
this.currentVariable.append(c);
|
||||
}
|
||||
else {
|
||||
this.currentLiteral.append(c);
|
||||
}
|
||||
}
|
||||
|
||||
Assert.isTrue(level == 0, "Mismatched open and close braces");
|
||||
if (level > 0) {
|
||||
this.currentLiteral.append(this.currentVariable);
|
||||
}
|
||||
encodeAndAppendCurrentLiteral(type);
|
||||
|
||||
return this.output.toString();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -385,15 +385,22 @@ public class UriComponentsBuilder implements UriBuilder, Cloneable {
|
||||
* @return the URI components
|
||||
*/
|
||||
public UriComponents build(boolean encoded) {
|
||||
return buildInternal(encoded ?
|
||||
EncodingHint.FULLY_ENCODED :
|
||||
this.encodeTemplate ? EncodingHint.ENCODE_TEMPLATE : EncodingHint.NONE);
|
||||
}
|
||||
|
||||
private UriComponents buildInternal(EncodingHint hint) {
|
||||
UriComponents result;
|
||||
if (this.ssp != null) {
|
||||
result = new OpaqueUriComponents(this.scheme, this.ssp, this.fragment);
|
||||
}
|
||||
else {
|
||||
HierarchicalUriComponents uric = new HierarchicalUriComponents(this.scheme, this.fragment,
|
||||
this.userInfo, this.host, this.port, this.pathBuilder.build(), this.queryParams, encoded);
|
||||
this.userInfo, this.host, this.port, this.pathBuilder.build(), this.queryParams,
|
||||
hint == EncodingHint.FULLY_ENCODED);
|
||||
|
||||
result = this.encodeTemplate ? uric.encodeTemplate(this.charset) : uric;
|
||||
result = hint == EncodingHint.ENCODE_TEMPLATE ? uric.encodeTemplate(this.charset) : uric;
|
||||
}
|
||||
if (!this.uriVariables.isEmpty()) {
|
||||
result = result.expand(name -> this.uriVariables.getOrDefault(name, UriTemplateVariables.SKIP_VALUE));
|
||||
@@ -425,24 +432,24 @@ public class UriComponentsBuilder implements UriBuilder, Cloneable {
|
||||
|
||||
@Override
|
||||
public URI build(Object... uriVariables) {
|
||||
return encode().buildAndExpand(uriVariables).toUri();
|
||||
return buildInternal(EncodingHint.ENCODE_TEMPLATE).expand(uriVariables).toUri();
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI build(Map<String, ?> uriVariables) {
|
||||
return encode().buildAndExpand(uriVariables).toUri();
|
||||
return buildInternal(EncodingHint.ENCODE_TEMPLATE).expand(uriVariables).toUri();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Build a URI String. This is a shortcut method which combines calls
|
||||
* to {@link #build()}, then {@link UriComponents#encode()} and finally
|
||||
* {@link UriComponents#toUriString()}.
|
||||
* Build a URI String. This is a shortcut for:
|
||||
* <pre>
|
||||
* String uri = builder.encode().build().toUriString()
|
||||
* </pre>
|
||||
* @since 4.1
|
||||
* @see UriComponents#toUriString()
|
||||
*/
|
||||
public String toUriString() {
|
||||
return encode().build().toUriString();
|
||||
return buildInternal(EncodingHint.ENCODE_TEMPLATE).toUriString();
|
||||
}
|
||||
|
||||
|
||||
@@ -1049,4 +1056,7 @@ public class UriComponentsBuilder implements UriBuilder, Cloneable {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private enum EncodingHint { ENCODE_TEMPLATE, FULLY_ENCODED, NONE }
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user