diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/WebAppProvider.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/WebAppProvider.java index 24c6958c667..b531ce1d1ea 100644 --- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/WebAppProvider.java +++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/WebAppProvider.java @@ -22,6 +22,7 @@ import org.eclipse.jetty.deploy.ConfigurationManager; import org.eclipse.jetty.deploy.util.FileID; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.handler.ContextHandler; +import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.URIUtil; import org.eclipse.jetty.util.annotation.ManagedAttribute; import org.eclipse.jetty.util.annotation.ManagedObject; @@ -265,8 +266,18 @@ public class WebAppProvider extends ScanningAppProvider if (!resource.exists()) throw new IllegalStateException("App resource does not exist " + resource); - String context = file.getName(); + final String contextName = file.getName(); + // Resource aliases (after getting name) to ensure baseResource is not an alias + if (resource.isAlias()) + { + file = new File(resource.getAlias()).toPath().toRealPath().toFile(); + resource = Resource.newResource(file); + if (!resource.exists()) + throw new IllegalStateException("App resource does not exist " + resource); + } + + // Handle a context XML file if (resource.exists() && FileID.isXmlFile(file)) { XmlConfiguration xmlc = new XmlConfiguration(resource) @@ -276,11 +287,15 @@ public class WebAppProvider extends ScanningAppProvider { super.initializeDefaults(context); + // If the XML created object is a ContextHandler + if (context instanceof ContextHandler) + // Initialize the context path prior to running context XML + initializeContextPath((ContextHandler)context, contextName, true); + + // If it is a webapp if (context instanceof WebAppContext) - { - WebAppContext webapp = (WebAppContext)context; - initializeWebAppContextDefaults(webapp); - } + // initialize other defaults prior to running context XML + initializeWebAppContextDefaults((WebAppContext)context); } }; @@ -290,56 +305,64 @@ public class WebAppProvider extends ScanningAppProvider xmlc.getProperties().putAll(getConfigurationManager().getProperties()); return (ContextHandler)xmlc.configure(); } - else if (file.isDirectory()) - { - // must be a directory - } - else if (FileID.isWebArchiveFile(file)) - { - // Context Path is the same as the archive. - context = context.substring(0, context.length() - 4); - } - else + // Otherwise it must be a directory or an archive + else if (!file.isDirectory() && !FileID.isWebArchiveFile(file)) { throw new IllegalStateException("unable to create ContextHandler for " + app); } - // Ensure "/" is Not Trailing in context paths. - if (context.endsWith("/") && context.length() > 0) - { - context = context.substring(0, context.length() - 1); - } - - // Start building the webapplication + // Build the web application WebAppContext webAppContext = new WebAppContext(); - webAppContext.setDisplayName(context); - - // special case of archive (or dir) named "root" is / context - if (context.equalsIgnoreCase("root")) - { - context = URIUtil.SLASH; - } - else if (context.toLowerCase(Locale.ENGLISH).startsWith("root-")) - { - int dash = context.toLowerCase(Locale.ENGLISH).indexOf('-'); - String virtual = context.substring(dash + 1); - webAppContext.setVirtualHosts(new String[]{virtual}); - context = URIUtil.SLASH; - } - - // Ensure "/" is Prepended to all context paths. - if (context.charAt(0) != '/') - { - context = "/" + context; - } - - webAppContext.setDefaultContextPath(context); webAppContext.setWar(file.getAbsolutePath()); + initializeContextPath(webAppContext, contextName, !file.isDirectory()); initializeWebAppContextDefaults(webAppContext); return webAppContext; } + protected void initializeContextPath(ContextHandler context, String contextName, boolean stripExtension) + { + String contextPath = contextName; + + // Strip any 3 char extension from non directories + if (stripExtension && contextPath.length() > 4 && contextPath.charAt(contextPath.length() - 4) == '.') + contextPath = contextPath.substring(0, contextPath.length() - 4); + + // Ensure "/" is Not Trailing in context paths. + if (contextPath.endsWith("/") && contextPath.length() > 1) + contextPath = contextPath.substring(0, contextPath.length() - 1); + + // special case of archive (or dir) named "root" is / context + if (contextPath.equalsIgnoreCase("root")) + { + contextPath = URIUtil.SLASH; + } + // handle root with virtual host form + else if (StringUtil.startsWithIgnoreCase(contextPath, "root-")) + { + int dash = contextPath.indexOf('-'); + String virtual = contextPath.substring(dash + 1); + context.setVirtualHosts(virtual.split(",")); + contextPath = URIUtil.SLASH; + } + + // Ensure "/" is Prepended to all context paths. + if (contextPath.charAt(0) != '/') + contextPath = "/" + contextPath; + + // Set the display name and context Path + context.setDisplayName(contextName); + if (context instanceof WebAppContext) + { + WebAppContext webAppContext = (WebAppContext)context; + webAppContext.setDefaultContextPath(contextPath); + } + else + { + context.setContextPath(contextPath); + } + } + @Override protected void fileChanged(String filename) throws Exception { diff --git a/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/providers/WebAppProviderTest.java b/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/providers/WebAppProviderTest.java index 90a687b9663..e0ec2a8e8c4 100644 --- a/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/providers/WebAppProviderTest.java +++ b/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/providers/WebAppProviderTest.java @@ -25,6 +25,7 @@ import java.util.Map; import org.eclipse.jetty.deploy.test.XmlConfiguredJetty; import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.server.handler.HandlerCollection; import org.eclipse.jetty.toolchain.test.MavenTestingUtils; import org.eclipse.jetty.toolchain.test.jupiter.WorkDir; @@ -124,9 +125,12 @@ public class WebAppProviderTest // Check Server for expected Handlers jetty.assertWebAppContextsExists("/bar", "/foo", "/bob"); + // Check that baseResources are not aliases + jetty.getServer().getContainedBeans(ContextHandler.class).forEach(h -> assertFalse(h.getBaseResource().isAlias())); + // Test for expected work/temp directory behaviour File workDir = jetty.getJettyDir("workish"); - assertTrue(hasJettyGeneratedPath(workDir, "bar_war"), "Should have generated directory in work directory: " + workDir); + assertTrue(hasJettyGeneratedPath(workDir, "_war-_bar"), "Should have generated directory in work directory: " + workDir); } @Test diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java index 9e4735621c3..414ff29d510 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java @@ -853,11 +853,15 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu @Override protected void doStart() throws Exception { - _availability.set(Availability.STARTING); - if (_contextPath == null) throw new IllegalStateException("Null contextPath"); + if (getBaseResource() != null && getBaseResource().isAlias()) + LOG.warn("BaseResource {} is aliased to {} in {}. May not be supported in future releases.", + getBaseResource(), getBaseResource().getAlias(), this); + + _availability.set(Availability.STARTING); + if (_logger == null) _logger = LoggerFactory.getLogger(ContextHandler.class.getName() + getLogNameSuffix());