Fix #6565 Deploy Symlinked applications (#6567)

Fix #6565 Deploy Symlinked applications by treating extracting context name (which becomes the default context path) from the base resource and then following aliases, so that base resource will not be an alias.   Added warning in ContextHandler if the base resource is an alias that we may not support this in future releases.

Signed-off-by: Greg Wilkins <gregw@webtide.com>
This commit is contained in:
Greg Wilkins 2021-08-02 18:16:34 +10:00 committed by GitHub
parent 90a72b0798
commit 4e3e99c5c5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 78 additions and 47 deletions

View File

@ -22,6 +22,7 @@ import org.eclipse.jetty.deploy.ConfigurationManager;
import org.eclipse.jetty.deploy.util.FileID; import org.eclipse.jetty.deploy.util.FileID;
import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.URIUtil; import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.annotation.ManagedAttribute; import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject; import org.eclipse.jetty.util.annotation.ManagedObject;
@ -265,8 +266,18 @@ public class WebAppProvider extends ScanningAppProvider
if (!resource.exists()) if (!resource.exists())
throw new IllegalStateException("App resource does not exist " + resource); 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)) if (resource.exists() && FileID.isXmlFile(file))
{ {
XmlConfiguration xmlc = new XmlConfiguration(resource) XmlConfiguration xmlc = new XmlConfiguration(resource)
@ -276,11 +287,15 @@ public class WebAppProvider extends ScanningAppProvider
{ {
super.initializeDefaults(context); 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) if (context instanceof WebAppContext)
{ // initialize other defaults prior to running context XML
WebAppContext webapp = (WebAppContext)context; initializeWebAppContextDefaults((WebAppContext)context);
initializeWebAppContextDefaults(webapp);
}
} }
}; };
@ -290,56 +305,64 @@ public class WebAppProvider extends ScanningAppProvider
xmlc.getProperties().putAll(getConfigurationManager().getProperties()); xmlc.getProperties().putAll(getConfigurationManager().getProperties());
return (ContextHandler)xmlc.configure(); return (ContextHandler)xmlc.configure();
} }
else if (file.isDirectory()) // Otherwise it must be a directory or an archive
{ else if (!file.isDirectory() && !FileID.isWebArchiveFile(file))
// 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
{ {
throw new IllegalStateException("unable to create ContextHandler for " + app); throw new IllegalStateException("unable to create ContextHandler for " + app);
} }
// Ensure "/" is Not Trailing in context paths. // Build the web application
if (context.endsWith("/") && context.length() > 0)
{
context = context.substring(0, context.length() - 1);
}
// Start building the webapplication
WebAppContext webAppContext = new WebAppContext(); 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()); webAppContext.setWar(file.getAbsolutePath());
initializeContextPath(webAppContext, contextName, !file.isDirectory());
initializeWebAppContextDefaults(webAppContext); initializeWebAppContextDefaults(webAppContext);
return 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 @Override
protected void fileChanged(String filename) throws Exception protected void fileChanged(String filename) throws Exception
{ {

View File

@ -25,6 +25,7 @@ import java.util.Map;
import org.eclipse.jetty.deploy.test.XmlConfiguredJetty; import org.eclipse.jetty.deploy.test.XmlConfiguredJetty;
import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.HandlerCollection; import org.eclipse.jetty.server.handler.HandlerCollection;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils; import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.toolchain.test.jupiter.WorkDir; import org.eclipse.jetty.toolchain.test.jupiter.WorkDir;
@ -124,9 +125,12 @@ public class WebAppProviderTest
// Check Server for expected Handlers // Check Server for expected Handlers
jetty.assertWebAppContextsExists("/bar", "/foo", "/bob"); 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 // Test for expected work/temp directory behaviour
File workDir = jetty.getJettyDir("workish"); 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 @Test

View File

@ -853,11 +853,15 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
@Override @Override
protected void doStart() throws Exception protected void doStart() throws Exception
{ {
_availability.set(Availability.STARTING);
if (_contextPath == null) if (_contextPath == null)
throw new IllegalStateException("Null contextPath"); 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) if (_logger == null)
_logger = LoggerFactory.getLogger(ContextHandler.class.getName() + getLogNameSuffix()); _logger = LoggerFactory.getLogger(ContextHandler.class.getName() + getLogNameSuffix());