V4.1 Fix "=" character in HttpPostRequestDecoder
Motivation Issue #3004 shows that "=" character was not supported as it should in the HttpPostRequestDecoder in form-data boundary. Modifications: Add 2 methods in StringUtil - split with maxPart argument: String split with max parts only (to prevent multiple '=' to be source of extra split while not needed) - substringAfter: String part after delimiter (since first part is not needed) Use those methods in HttpPostRequestDecoder. Change and the HttpPostRequestDecoderTest to check using a boundary beginning with "=". Results: The fix implies more stability and fix the issue.
This commit is contained in:
parent
a1af35313c
commit
eb415fded6
@ -672,7 +672,7 @@ public class HttpPostMultipartRequestDecoder implements InterfaceHttpPostRequest
|
|||||||
if (checkSecondArg) {
|
if (checkSecondArg) {
|
||||||
// read next values and store them in the map as Attribute
|
// read next values and store them in the map as Attribute
|
||||||
for (int i = 2; i < contents.length; i++) {
|
for (int i = 2; i < contents.length; i++) {
|
||||||
String[] values = StringUtil.split(contents[i], '=');
|
String[] values = StringUtil.split(contents[i], '=', 2);
|
||||||
Attribute attribute;
|
Attribute attribute;
|
||||||
try {
|
try {
|
||||||
String name = cleanString(values[0]);
|
String name = cleanString(values[0]);
|
||||||
@ -721,8 +721,8 @@ public class HttpPostMultipartRequestDecoder implements InterfaceHttpPostRequest
|
|||||||
// Take care of possible "multipart/mixed"
|
// Take care of possible "multipart/mixed"
|
||||||
if (contents[1].equalsIgnoreCase(HttpPostBodyUtil.MULTIPART_MIXED)) {
|
if (contents[1].equalsIgnoreCase(HttpPostBodyUtil.MULTIPART_MIXED)) {
|
||||||
if (currentStatus == MultiPartStatus.DISPOSITION) {
|
if (currentStatus == MultiPartStatus.DISPOSITION) {
|
||||||
String[] values = StringUtil.split(contents[2], '=');
|
String values = StringUtil.substringAfter(contents[2], '=');
|
||||||
multipartMixedBoundary = "--" + values[1];
|
multipartMixedBoundary = "--" + values;
|
||||||
currentStatus = MultiPartStatus.MIXEDDELIMITER;
|
currentStatus = MultiPartStatus.MIXEDDELIMITER;
|
||||||
return decodeMultipart(MultiPartStatus.MIXEDDELIMITER);
|
return decodeMultipart(MultiPartStatus.MIXEDDELIMITER);
|
||||||
} else {
|
} else {
|
||||||
@ -731,11 +731,11 @@ public class HttpPostMultipartRequestDecoder implements InterfaceHttpPostRequest
|
|||||||
} else {
|
} else {
|
||||||
for (int i = 1; i < contents.length; i++) {
|
for (int i = 1; i < contents.length; i++) {
|
||||||
if (contents[i].toLowerCase().startsWith(HttpHeaders.Values.CHARSET)) {
|
if (contents[i].toLowerCase().startsWith(HttpHeaders.Values.CHARSET)) {
|
||||||
String[] values = StringUtil.split(contents[i], '=');
|
String values = StringUtil.substringAfter(contents[i], '=');
|
||||||
Attribute attribute;
|
Attribute attribute;
|
||||||
try {
|
try {
|
||||||
attribute = factory.createAttribute(request, HttpHeaders.Values.CHARSET,
|
attribute = factory.createAttribute(request, HttpHeaders.Values.CHARSET,
|
||||||
cleanString(values[1]));
|
cleanString(values));
|
||||||
} catch (NullPointerException e) {
|
} catch (NullPointerException e) {
|
||||||
throw new ErrorDataDecoderException(e);
|
throw new ErrorDataDecoderException(e);
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
|
@ -169,25 +169,25 @@ public class HttpPostRequestDecoder implements InterfaceHttpPostRequestDecoder {
|
|||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
String[] boundary = StringUtil.split(headerContentType[mrank], '=');
|
String boundary = StringUtil.substringAfter(headerContentType[mrank], '=');
|
||||||
if (boundary.length != 2) {
|
if (boundary == null) {
|
||||||
throw new ErrorDataDecoderException("Needs a boundary value");
|
throw new ErrorDataDecoderException("Needs a boundary value");
|
||||||
}
|
}
|
||||||
if (boundary[1].charAt(0) == '"') {
|
if (boundary.charAt(0) == '"') {
|
||||||
String bound = boundary[1].trim();
|
String bound = boundary.trim();
|
||||||
int index = bound.length() - 1;
|
int index = bound.length() - 1;
|
||||||
if (bound.charAt(index) == '"') {
|
if (bound.charAt(index) == '"') {
|
||||||
boundary[1] = bound.substring(1, index);
|
boundary = bound.substring(1, index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (headerContentType[crank].toLowerCase().startsWith(
|
if (headerContentType[crank].toLowerCase().startsWith(
|
||||||
HttpHeaders.Values.CHARSET)) {
|
HttpHeaders.Values.CHARSET)) {
|
||||||
String[] charset = StringUtil.split(headerContentType[crank], '=');
|
String charset = StringUtil.substringAfter(headerContentType[crank], '=');
|
||||||
if (charset.length > 1) {
|
if (charset != null) {
|
||||||
return new String[] {"--" + boundary[1], charset[1]};
|
return new String[] {"--" + boundary, charset};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new String[] {"--" + boundary[1]};
|
return new String[] {"--" + boundary};
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -111,6 +111,63 @@ public final class StringUtil {
|
|||||||
return res.toArray(new String[res.size()]);
|
return res.toArray(new String[res.size()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Splits the specified {@link String} with the specified delimiter in maxParts maximum parts.
|
||||||
|
* This operation is a simplified and optimized
|
||||||
|
* version of {@link String#split(String, int)}.
|
||||||
|
*/
|
||||||
|
public static String[] split(String value, char delim, int maxParts) {
|
||||||
|
final int end = value.length();
|
||||||
|
final List<String> res = new ArrayList<String>();
|
||||||
|
|
||||||
|
int start = 0;
|
||||||
|
int cpt = 1;
|
||||||
|
for (int i = 0; i < end && cpt < maxParts; i ++) {
|
||||||
|
if (value.charAt(i) == delim) {
|
||||||
|
if (start == i) {
|
||||||
|
res.add(EMPTY_STRING);
|
||||||
|
} else {
|
||||||
|
res.add(value.substring(start, i));
|
||||||
|
}
|
||||||
|
start = i + 1;
|
||||||
|
cpt++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (start == 0) { // If no delimiter was found in the value
|
||||||
|
res.add(value);
|
||||||
|
} else {
|
||||||
|
if (start != end) {
|
||||||
|
// Add the last element if it's not empty.
|
||||||
|
res.add(value.substring(start, end));
|
||||||
|
} else {
|
||||||
|
// Truncate trailing empty elements.
|
||||||
|
for (int i = res.size() - 1; i >= 0; i --) {
|
||||||
|
if (res.get(i).isEmpty()) {
|
||||||
|
res.remove(i);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.toArray(new String[res.size()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the item after one char delim if the delim is found (else null).
|
||||||
|
* This operation is a simplified and optimized
|
||||||
|
* version of {@link String#split(String, int)}.
|
||||||
|
*/
|
||||||
|
public static String substringAfter(String value, char delim) {
|
||||||
|
int pos = value.indexOf(delim);
|
||||||
|
if (pos >= 0) {
|
||||||
|
return value.substring(pos + 1);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts the specified byte value into a 2-digit hexadecimal integer.
|
* Converts the specified byte value into a 2-digit hexadecimal integer.
|
||||||
*/
|
*/
|
||||||
|
@ -70,4 +70,15 @@ public class StringUtilTest {
|
|||||||
public void splitWithDelimiterAtBeginning() {
|
public void splitWithDelimiterAtBeginning() {
|
||||||
assertArrayEquals(new String[] { "", "foo", "bar" }, split("#foo#bar", '#'));
|
assertArrayEquals(new String[] { "", "foo", "bar" }, split("#foo#bar", '#'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void splitMaxPart() {
|
||||||
|
assertArrayEquals(new String[] { "foo", "bar:bar2" }, split("foo:bar:bar2", ':', 2));
|
||||||
|
assertArrayEquals(new String[] { "foo", "bar", "bar2" }, split("foo:bar:bar2", ':', 3));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void substringAfterTest() {
|
||||||
|
assertEquals("bar:bar2", substringAfter("foo:bar:bar2", ':'));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user