Skip to content

Commit

Permalink
[UNDERTOW-1875] - add system property to allow ID less matrix parameters
Browse files Browse the repository at this point in the history
  • Loading branch information
baranowb committed Jan 23, 2023
1 parent afa3c77 commit b7a4122
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 5 deletions.
13 changes: 13 additions & 0 deletions core/src/main/java/io/undertow/UndertowOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,19 @@ public class UndertowOptions {
*/
public static final Option<Boolean> TRACK_ACTIVE_REQUESTS = Option.simple(UndertowOptions.class, "TRACK_ACTIVE_REQUESTS", Boolean.class);

/**
* Specify if matrix parameters without ID should be allowed or not. If set to 'true' '/test;param1,param2/next-path-segment' will be acceptable.
* (spec compliant '/test;PARAM_ID=param1,param2/next-path-segment')
*
* If this is not specified it will be the same as {@link #DEFAULT_ALLOW_ID_LESS_MATRIX_PARAMETERS}.
*/
public static final Option<Boolean> ALLOW_ID_LESS_MATRIX_PARAMETERS = Option.simple(UndertowOptions.class, "ALLOW_ID_LESS_MATRIX_PARAMETERS", Boolean.class);

/**
* Default value of allow ID-less matrix parameters - false. We should comply with spec.
*/
public static final boolean DEFAULT_ALLOW_ID_LESS_MATRIX_PARAMETERS = false;

private UndertowOptions() {

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ public abstract class HttpRequestParser {
private final String charset;
private final int maxCachedHeaderSize;
private final boolean allowUnescapedCharactersInUrl;
private final boolean allowIDLessMatrixParams;

private static final boolean[] ALLOWED_TARGET_CHARACTER = new boolean[256];

Expand Down Expand Up @@ -215,6 +216,7 @@ public HttpRequestParser(OptionMap options) {
charset = options.get(UndertowOptions.URL_CHARSET, StandardCharsets.UTF_8.name());
maxCachedHeaderSize = options.get(UndertowOptions.MAX_CACHED_HEADER_SIZE, UndertowOptions.DEFAULT_MAX_CACHED_HEADER_SIZE);
this.allowUnescapedCharactersInUrl = options.get(UndertowOptions.ALLOW_UNESCAPED_CHARACTERS_IN_URL, false);
this.allowIDLessMatrixParams = options.get(UndertowOptions.ALLOW_ID_LESS_MATRIX_PARAMETERS, UndertowOptions.DEFAULT_ALLOW_ID_LESS_MATRIX_PARAMETERS);
}

public static final HttpRequestParser instance(final OptionMap options) {
Expand Down Expand Up @@ -641,7 +643,7 @@ final void handlePathParameters(ByteBuffer buffer, ParseState state, HttpServerE
if (decode && (next == '+' || next == '%' || next > 127)) {
urlDecodeRequired = true;
}
if (next == '=' && param == null) {
if ((next == '=' || (next == ',' && this.allowIDLessMatrixParams)) && param == null) {
param = decode(stringBuilder.substring(pos), urlDecodeRequired, state, true, true);
urlDecodeRequired = false;
pos = stringBuilder.length() + 1;
Expand All @@ -667,11 +669,11 @@ final void handlePathParameters(ByteBuffer buffer, ParseState state, HttpServerE
state.nextQueryParam = param;
}

private void handleParsedParam(String previouslyParsedParam, String parsedParam, HttpServerExchange exchange, boolean urlDecodeRequired, ParseState state) throws BadRequestException {
if (previouslyParsedParam == null) {
exchange.addPathParam(decode(parsedParam, urlDecodeRequired, state, true, true), "");
private void handleParsedParam(String paramName, String parameterValue, HttpServerExchange exchange, boolean urlDecodeRequired, ParseState state) throws BadRequestException {
if (paramName == null) {
exchange.addPathParam(decode(parameterValue, urlDecodeRequired, state, true, true), "");
} else { // path param already parsed so parse and add the value
exchange.addPathParam(previouslyParsedParam, decode(parsedParam, urlDecodeRequired, state, true, true));
exchange.addPathParam(paramName, decode(parameterValue, urlDecodeRequired, state, true, true));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,28 @@ public void testServletURLMultiLevelMatrixParameterEndingWithNormalPathAndQuery(
Assert.assertTrue(result.isHostIncludedInRequestURI());
}

@Test
public void testIDLessMatrixParameters() throws BadRequestException {
byte[] in = "GET http://localhost:7777/route/v1/driving/13.388860,52.517037;13.397634,52.529407,111;13.428555,52.523219,222?overview=false HTTP/1.1\r\n\r\n".getBytes();
ParseState context = new ParseState(10);
HttpServerExchange result = new HttpServerExchange(null);
OptionMap.Builder builder = OptionMap.builder()
.set(UndertowOptions.ALLOW_ENCODED_SLASH, true)
.set(UndertowOptions.ALLOW_ID_LESS_MATRIX_PARAMETERS, true);
HttpRequestParser.instance(builder.getMap()).handle(ByteBuffer.wrap(in), context, result);
Assert.assertSame(Methods.GET, result.getRequestMethod());
Assert.assertEquals("http://localhost:7777/route/v1/driving/13.388860,52.517037;13.397634,52.529407,111;13.428555,52.523219,222", result.getRequestURI());
Assert.assertEquals("/route/v1/driving/13.388860,52.517037", result.getRequestPath());
Assert.assertEquals("overview=false", result.getQueryString());
Assert.assertEquals("52.529407", result.getPathParameters().get("13.397634").getFirst());
Assert.assertEquals("111", result.getPathParameters().get("13.397634").getLast());
Assert.assertEquals("52.523219", result.getPathParameters().get("13.428555").getFirst());
Assert.assertEquals("222", result.getPathParameters().get("13.428555").getLast());
Assert.assertEquals("false", result.getQueryParameters().get("overview").getFirst());
Assert.assertSame(Protocols.HTTP_1_1, result.getProtocol());
Assert.assertTrue(result.isHostIncludedInRequestURI());
}

@Test
public void testFullUrlRootPath() throws BadRequestException {
byte[] in = "GET http://myurl.com HTTP/1.1\r\n\r\n".getBytes();
Expand Down

0 comments on commit b7a4122

Please sign in to comment.