diff --git a/core/src/main/java/io/undertow/UndertowOptions.java b/core/src/main/java/io/undertow/UndertowOptions.java index ebde0ca5b5..ccb3b29967 100644 --- a/core/src/main/java/io/undertow/UndertowOptions.java +++ b/core/src/main/java/io/undertow/UndertowOptions.java @@ -460,6 +460,20 @@ public class UndertowOptions { */ public static final Option WEB_SOCKETS_WRITE_TIMEOUT = Option.simple(Options.class, "WEB_SOCKETS_WRITE_TIMEOUT", Integer.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 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() { } diff --git a/core/src/main/java/io/undertow/server/protocol/http/HttpRequestParser.java b/core/src/main/java/io/undertow/server/protocol/http/HttpRequestParser.java index 67fbdf9c29..7dcd75b2bf 100644 --- a/core/src/main/java/io/undertow/server/protocol/http/HttpRequestParser.java +++ b/core/src/main/java/io/undertow/server/protocol/http/HttpRequestParser.java @@ -217,7 +217,11 @@ 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 = Boolean.parseBoolean(System.getProperty(ID_LESS_MATRIX_PARAMS_PROPERTY)); + if(options.contains(UndertowOptions.ALLOW_ID_LESS_MATRIX_PARAMETERS)) { + this.allowIDLessMatrixParams = options.get(UndertowOptions.ALLOW_ID_LESS_MATRIX_PARAMETERS, UndertowOptions.DEFAULT_ALLOW_ID_LESS_MATRIX_PARAMETERS); + } else { + this.allowIDLessMatrixParams = Boolean.parseBoolean(System.getProperty(ID_LESS_MATRIX_PARAMS_PROPERTY)); + } } public static final HttpRequestParser instance(final OptionMap options) { diff --git a/core/src/test/java/io/undertow/server/protocol/http/SimpleParserTestCase.java b/core/src/test/java/io/undertow/server/protocol/http/SimpleParserTestCase.java index 25c7567501..d9cc018e4a 100644 --- a/core/src/test/java/io/undertow/server/protocol/http/SimpleParserTestCase.java +++ b/core/src/test/java/io/undertow/server/protocol/http/SimpleParserTestCase.java @@ -383,6 +383,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();