This is an automated email from the ASF dual-hosted git repository. andy pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/jena.git
commit 14807c40cfb262342b066b7af3fd52524da62e44 Author: Andy Seaborne <[email protected]> AuthorDate: Fri May 31 17:01:38 2024 +0100 GH-2508: Check and sanitise the servlet context path value --- .../apache/jena/fuseki/main/cmds/FusekiMain.java | 32 ++++++++++----- .../fuseki/main/TestFusekiMainCmdArguments.java | 46 +++++++++++++++++++++- .../org/apache/jena/fuseki/cmd/FusekiMain.java | 29 ++++++++++++++ .../cmd/{FusekiCmd.java => FusekiWebappCmd.java} | 30 ++++++++------ 4 files changed, 114 insertions(+), 23 deletions(-) diff --git a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/cmds/FusekiMain.java b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/cmds/FusekiMain.java index bcd517e094..998c79b979 100644 --- a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/cmds/FusekiMain.java +++ b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/cmds/FusekiMain.java @@ -94,7 +94,7 @@ public class FusekiMain extends CmdARQ { private static ArgDecl argGZip = new ArgDecl(ArgDecl.HasValue, "gzip"); // Set the servlet context path (the initial path for URLs.) for any datasets. // A context of "/path" and a dataset name of "/ds", service "sparql" is accessed as "/path/ds/sparql" - private static ArgDecl argPathBase = new ArgDecl(ArgDecl.HasValue, "pathBase", "contextPath", "pathbase", "contextpath"); + private static ArgDecl argContextPath = new ArgDecl(ArgDecl.HasValue, "pathBase", "contextPath", "pathbase", "contextpath"); // Static files. URLs are affected by argPathBase private static ArgDecl argBase = new ArgDecl(ArgDecl.HasValue, "base", "files"); @@ -212,8 +212,8 @@ public class FusekiMain extends CmdARQ { "Enable GZip compression (HTTP Accept-Encoding) if request header set"); add(argBase, "--base=DIR", "Directory for static content"); - add(argPathBase, "--pathBase=DIR", - "Context path for datasets"); + add(argContextPath, "--contextPath=PATH", + "Context path for the server"); add(argSparqler, "--sparqler=DIR", "Run with SPARQLer services Directory for static content"); add(argValidators, "--validators", @@ -449,13 +449,11 @@ public class FusekiMain extends CmdARQ { // -- Server setup. - if ( contains(argPathBase) ) { - // Static files. - String servletContextPath = getValue(argPathBase); - - if ( ! servletContextPath.equals("/") && servletContextPath.endsWith("/") ) - throw new CmdException("Path base must not end with \"/\": '"+servletContextPath+"'"); - serverConfig.servletContextPath = servletContextPath; + if ( contains(argContextPath) ) { + String contextPath = getValue(argContextPath); + contextPath = sanitizeContextPath(contextPath); + if ( contextPath != null ) + serverConfig.servletContextPath = contextPath; } if ( contains(argBase) ) { @@ -551,6 +549,20 @@ public class FusekiMain extends CmdARQ { } } + private static String sanitizeContextPath(String contextPath) { + if ( contextPath.isEmpty() ) + return null; + if ( contextPath.equals("/") ) + return null; + if ( contextPath.endsWith("/") ) { + throw new CmdException("Path base must not end with \"/\": '"+contextPath+"'"); + //contextPath = StringUtils.chop(contextPath); + } + if ( ! contextPath.startsWith("/") ) + contextPath = "/"+contextPath; + return contextPath; + } + @Override protected void exec() { try { diff --git a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/TestFusekiMainCmdArguments.java b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/TestFusekiMainCmdArguments.java index ca3faf6d6c..323e8e5447 100644 --- a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/TestFusekiMainCmdArguments.java +++ b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/TestFusekiMainCmdArguments.java @@ -42,7 +42,7 @@ public class TestFusekiMainCmdArguments { } @Test - public void test_happy_empty() { + public void test_empty() { // given List<String> arguments = List.of("--port=0", "--empty", "/dataset"); // when @@ -52,7 +52,7 @@ public class TestFusekiMainCmdArguments { } @Test - public void test_happy_localhost() { + public void test_localhost() { // given List<String> arguments = List.of("--port=0", "--localhost", "--mem", "/dataset"); // when @@ -61,6 +61,48 @@ public class TestFusekiMainCmdArguments { assertNotNull(server); } + @Test + public void test_contextpath_1() { + // given + List<String> arguments = List.of("--mem", "--contextpath=/ABC", "/path"); + String expectedMessage = "port : bad port number: 'ERROR'"; + // when + buildServer(buildCmdLineArguments(arguments)); + // then + assertNotNull(server); + } + + @Test + public void test_contextpath_2() { + // given + List<String> arguments = List.of("--mem", "--contextpath=ABC", "/path"); + String expectedMessage = "port : bad port number: 'ERROR'"; + // when + buildServer(buildCmdLineArguments(arguments)); + // then + assertNotNull(server); + } + + @Test + public void test_contextpath_3() { + // given + List<String> arguments = List.of("--mem", "--contextpath=/", "/path"); + String expectedMessage = "port : bad port number: 'ERROR'"; + // when + buildServer(buildCmdLineArguments(arguments)); + // then + assertNotNull(server); + } + + @Test + public void test_error_contextpath() { + // given + List<String> arguments = List.of("--mem", "--contextpath=ABC/", "/path"); + String expectedMessage = "Path base must not end with \"/\": 'ABC/'"; + // when, then + testForCmdException(arguments, expectedMessage); + } + @Test public void test_error_noDataSetProvided() { // given diff --git a/jena-fuseki2/jena-fuseki-webapp/src/main/java/org/apache/jena/fuseki/cmd/FusekiMain.java b/jena-fuseki2/jena-fuseki-webapp/src/main/java/org/apache/jena/fuseki/cmd/FusekiMain.java new file mode 100644 index 0000000000..8e85c948bb --- /dev/null +++ b/jena-fuseki2/jena-fuseki-webapp/src/main/java/org/apache/jena/fuseki/cmd/FusekiMain.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jena.fuseki.cmd; + +/** + * @deprecated Use {@link FusekiWebappCmd}. + */ +@Deprecated(since="5.1.0", forRemoval = true) +public class FusekiMain { + static public void main(String... argv) { + FusekiWebappCmd.main(argv); + } +} diff --git a/jena-fuseki2/jena-fuseki-webapp/src/main/java/org/apache/jena/fuseki/cmd/FusekiCmd.java b/jena-fuseki2/jena-fuseki-webapp/src/main/java/org/apache/jena/fuseki/cmd/FusekiWebappCmd.java similarity index 95% rename from jena-fuseki2/jena-fuseki-webapp/src/main/java/org/apache/jena/fuseki/cmd/FusekiCmd.java rename to jena-fuseki2/jena-fuseki-webapp/src/main/java/org/apache/jena/fuseki/cmd/FusekiWebappCmd.java index e262a44534..040c5591f5 100644 --- a/jena-fuseki2/jena-fuseki-webapp/src/main/java/org/apache/jena/fuseki/cmd/FusekiCmd.java +++ b/jena-fuseki2/jena-fuseki-webapp/src/main/java/org/apache/jena/fuseki/cmd/FusekiWebappCmd.java @@ -49,7 +49,7 @@ import org.slf4j.Logger; /** * Handles the fuseki command, used to start a Fuseki Webapp server. */ -public class FusekiCmd { +public class FusekiWebappCmd { // This allows us to set logging before calling FusekiCmdInner // FusekiCmdInner inherits from CmdMain which statically sets logging. // By java classloading, super class statics run before the @@ -318,15 +318,6 @@ public class FusekiCmd { cmdLine.datasetDescription = cmdLine.datasetDescription+ " (with RDFS)"; } - // This is has proven confusing because it is like --conf. -// // Otherwise -// if ( contains(argAssemblerDecl) ) { -// cmdLine.datasetDescription = "Assembler: "+ modDataset.getAssemblerFile(); -// // Need to add service details. -// Dataset ds = modDataset.createDataset(); -// //cmdLineDataset.dsg = ds.asDatasetGraph(); -// } - if ( cmdlineConfigPresent ) { cmdLine.datasetPath = getPositionalArg(0); if ( cmdLine.datasetPath.length() > 0 && !cmdLine.datasetPath.startsWith("/") ) @@ -351,7 +342,10 @@ public class FusekiCmd { } if ( contains(argContextPath) ) { - jettyServerConfig.contextPath = getValue(argContextPath); + String contextPath = getValue(argContextPath); + contextPath = sanitizeContextPath(contextPath); + if ( contextPath != null ) + jettyServerConfig.contextPath = contextPath; } if ( contains(argJettyConfig) ) { @@ -367,6 +361,20 @@ public class FusekiCmd { } } + private static String sanitizeContextPath(String contextPath) { + if ( contextPath.isEmpty() ) + return null; + if ( contextPath.equals("/") ) + return null; + if ( contextPath.endsWith("/") ) { + throw new CmdException("Path base must not end with \"/\": '"+contextPath+"'"); + //contextPath = StringUtils.chop(contextPath); + } + if ( ! contextPath.startsWith("/") ) + contextPath = "/"+contextPath; + return contextPath; + } + @Override protected void exec() { try {
