diff --git a/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/AttributeNormalizer.java b/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/AttributeNormalizer.java index 45256037322..3541414b1ba 100644 --- a/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/AttributeNormalizer.java +++ b/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/AttributeNormalizer.java @@ -29,9 +29,15 @@ import java.nio.file.Path; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import java.util.Stack; +import java.util.jar.Attributes; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.stream.Collectors; +import java.util.stream.Stream; import org.eclipse.jetty.util.URIUtil; import org.eclipse.jetty.util.log.Log; @@ -55,199 +61,118 @@ public class AttributeNormalizer private static final Logger LOG = Log.getLogger(AttributeNormalizer.class); private static final Pattern __propertyPattern = Pattern.compile("(?<=[^$]|^)\\$\\{([^}]*)\\}"); - private static class PathAttribute + private static class Attribute { - public final Path path; - public final String key; - private boolean isUriBased = false; - private int weight = -1; + final String key; + final String value; - public PathAttribute(String key, Path path) throws IOException + public Attribute(String key, String value) { this.key = key; - this.path = toCanonicalPath(path); - // TODO: Don't allow non-directory paths? (but what if the path doesn't exist?) + this.value = value; } - - public PathAttribute(String key, String systemPropertyKey) throws IOException + } + + private static Path toCanonicalPath(String path) + { + if (path == null) { - this(key, toCanonicalPath(System.getProperty(systemPropertyKey))); + return null; } - - private static Path toCanonicalPath(String path) throws IOException + return toCanonicalPath(FileSystems.getDefault().getPath(path)); + } + + private static Path toCanonicalPath(Path path) + { + if (path == null) { - if (path == null) - { - return null; - } - return toCanonicalPath(FileSystems.getDefault().getPath(path)); + return null; } - - private static Path toCanonicalPath(Path path) throws IOException + if (Files.exists(path)) { - if (path == null) - { - return null; - } - if (Files.exists(path)) + try { return path.toRealPath(); } - return path.toAbsolutePath(); - } - - public String toUri() - { - if (isUriBased) + catch (IOException e) { - // Return "{KEY}" -> "" (including scheme) - return path.toUri().toASCIIString(); - } - else - { - // Return "{KEY}" -> "" (excluding scheme) - return path.toUri().getSchemeSpecificPart(); + throw new IllegalArgumentException(e); } } + return path.toAbsolutePath(); + } + + private static class PathAttribute extends Attribute + { + public final Path path; - public String getNormalizedScheme() + public PathAttribute(String key, Path path) { - if (isUriBased) - { - // If we are treating the {KEY} -> "" (scheme is expanded) - return ""; - } - else - { - // If we are treating the {KEY} -> "" (scheme is not part of KEY) - return "file:"; - } - } - - public PathAttribute treatAsUri() - { - this.isUriBased = true; - return this; - } - - public PathAttribute weight(int newweight) - { - this.weight = newweight; - return this; + super(key,path.toString()); + this.path = path; } @Override public String toString() { - return String.format("PathAttribute[%s=>%s,%d]",key,path,weight); - } - } - - private static class PathAttributeComparator implements Comparator - { - @Override - public int compare(PathAttribute o1, PathAttribute o2) - { - if( (o1.path == null) && (o2.path != null) ) - { - return -1; - } - - if( (o1.path != null) && (o2.path == null) ) - { - return 1; - } - - if( (o1.path == null) && (o2.path == null) ) - { - return 0; - } - - // Different lengths? - int diff = o2.path.getNameCount() - o1.path.getNameCount(); - if(diff != 0) - { - return diff; - } - - // Different names? - diff = o2.path.compareTo(o1.path); - if(diff != 0) - { - return diff; - } - - // The paths are the same, base now on weight - return o2.weight - o1.weight; + return String.format("PathAttribute[%s=>%s]",key,path); } } - private static class PathAttributes extends ArrayList + private static class URIAttribute extends Attribute { - @Override - public boolean add(AttributeNormalizer.PathAttribute pathAttribute) + public final URI uri; + + public URIAttribute(String key, URI uri) { - if (pathAttribute.path == null) - { - return false; - } - return super.add(pathAttribute); + super(key,uri.toASCIIString()); + this.uri = uri; + } + + @Override + public String toString() + { + return String.format("URIAttribute[%s=>%s]",key,uri); } } - public static String uriSeparators(String path) + private static void addPath(Listpaths,String key) { - StringBuilder ret = new StringBuilder(); - for (char c : path.toCharArray()) - { - if ((c == '/') || (c == '\\')) - { - ret.append('/'); - } - else - { - ret.append(c); - } - } - return ret.toString(); + String value = System.getProperty(key); + if (value!=null) + paths.add(new PathAttribute(key,toCanonicalPath(value))); } private URI warURI; - private PathAttributes attributes = new PathAttributes(); + private Map attributes = new HashMap<>(); + private List paths = new ArrayList<>(); + private List uris = new ArrayList<>(); + public AttributeNormalizer(Resource baseResource) { - // WAR URI is always evaluated before paths. - warURI = baseResource == null ? null : baseResource.getURI(); - // We don't normalize or resolve the baseResource URI + if (baseResource==null) + throw new IllegalArgumentException("No base resource!"); + + warURI = baseResource.getURI().normalize(); if (!warURI.isAbsolute()) throw new IllegalArgumentException("WAR URI is not absolute: " + warURI); - try - { - // Track path attributes for expansion - attributes.add(new PathAttribute("jetty.base", "jetty.base").weight(9)); - attributes.add(new PathAttribute("jetty.home", "jetty.home").weight(8)); - attributes.add(new PathAttribute("user.home", "user.home").weight(7)); - attributes.add(new PathAttribute("user.dir", "user.dir").weight(6)); - if(warURI != null && warURI.getScheme().equals("file")) - { - attributes.add(new PathAttribute("WAR", new File(warURI).toPath().toAbsolutePath()).treatAsUri().weight(10)); - } - - Collections.sort(attributes, new PathAttributeComparator()); + + addPath(paths,"jetty.base"); + addPath(paths,"jetty.home"); + addPath(paths,"user.home"); + addPath(paths,"user.dir"); + + uris.add(new URIAttribute("WAR", warURI)); + + Stream.concat(paths.stream(),uris.stream()).forEach(a->attributes.put(a.key,a)); - if (LOG.isDebugEnabled()) - { - int i = 0; - for (PathAttribute attr : attributes) - { - LOG.debug(" [{}] {}", i++, attr); - } - } - } - catch (Exception e) + if (LOG.isDebugEnabled()) { - throw new IllegalArgumentException(e); + for (Attribute attr : attributes.values()) + { + LOG.debug(attr.toString()); + } } } @@ -264,11 +189,11 @@ public class AttributeNormalizer // Find a URI URI uri = null; if (o instanceof URI) - uri = (URI)o; + uri = ((URI)o).normalize(); else if (o instanceof URL) - uri = ((URL)o).toURI(); + uri = ((URL)o).toURI().normalize(); else if (o instanceof File) - uri = ((File)o).toURI(); + uri = ((File)o).toURI().normalize(); else { String s = o.toString(); @@ -299,10 +224,6 @@ public class AttributeNormalizer String suffix = raw.substring(bang); return "jar:" + normal + suffix; } - else if ("file".equalsIgnoreCase(uri.getScheme())) - { - return normalizePath(new File(uri.getRawSchemeSpecificPart()).toPath()); - } else { if(uri.isAbsolute()) @@ -320,30 +241,49 @@ public class AttributeNormalizer public String normalizeUri(URI uri) { - String uriStr = uri.toASCIIString(); - String warStr = warURI.toASCIIString(); - if (uriStr.startsWith(warStr)) + for (URIAttribute a : uris) { - return "${WAR}" + uriStr.substring(warStr.length()); + try + { + if (uri.compareTo(a.uri)==0) + return String.format("${%s}",a.key); + + if (!a.uri.getScheme().equalsIgnoreCase(uri.getScheme())) + continue; + if (a.uri.getHost()==null && uri.getHost()!=null) + continue; + if (a.uri.getHost()!=null && !a.uri.getHost().equals(uri.getHost())) + continue; + + if (a.uri.getPath().equals(uri.getPath())) + return a.value; + + if (!uri.getPath().startsWith(a.uri.getPath())) + continue; + + String s = uri.getPath().substring(a.uri.getPath().length()); + + if (s.charAt(0)!='/') + continue; + + return String.format("${%s}%s",a.key,new URI(s).toASCIIString()); + } + catch(URISyntaxException e) + { + LOG.ignore(e); + } } - return uriStr; + return uri.toASCIIString(); } public String normalizePath(Path path) { - String uriPath = path.toUri().getSchemeSpecificPart(); - - for (PathAttribute attr : attributes) + for (PathAttribute a : paths) { - if (attr.path == null) - continue; - try { - if (path.startsWith(attr.path) || path.equals(attr.path) || Files.isSameFile(path,attr.path)) - { - return attr.getNormalizedScheme() + uriSeparators(URIUtil.addPaths("${" + attr.key + "}", attr.path.relativize(path).toString())); - } + if (path.startsWith(a.path) || path.equals(a.path) || Files.isSameFile(path,a.path)) + return String.format("${%s}%s",a.key,a.path.relativize(path).toString()); } catch (IOException ignore) { @@ -351,7 +291,7 @@ public class AttributeNormalizer } } - return uriSeparators(path.toString()); + return path.toString(); } public String expand(String str) @@ -433,19 +373,14 @@ public class AttributeNormalizer private String getString(String property) { - if(property == null) + if(property==null) { return null; } - // Use known path attributes - for (PathAttribute attr : attributes) - { - if (attr.key.equalsIgnoreCase(property)) - { - return attr.toUri(); - } - } + Attribute a = attributes.get(property); + if (a!=null) + return a.value; // Use system properties next return System.getProperty(property); diff --git a/tests/test-quickstart/src/test/java/org/eclipse/jetty/quickstart/AttributeNormalizerPathTest.java b/tests/test-quickstart/src/test/java/org/eclipse/jetty/quickstart/AttributeNormalizerPathTest.java deleted file mode 100644 index 61064ef3816..00000000000 --- a/tests/test-quickstart/src/test/java/org/eclipse/jetty/quickstart/AttributeNormalizerPathTest.java +++ /dev/null @@ -1,232 +0,0 @@ - // -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.quickstart; - -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertThat; - -import java.io.File; -import java.net.MalformedURLException; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URL; -import java.nio.file.Path; -import java.util.Arrays; -import java.util.List; - -import org.eclipse.jetty.toolchain.test.FS; -import org.eclipse.jetty.toolchain.test.MavenTestingUtils; -import org.eclipse.jetty.util.resource.Resource; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; - -@RunWith(Parameterized.class) -public class AttributeNormalizerPathTest -{ - @Parameters(name="{0} = {1}") - public static List data() - { - String[][] tests = { - { "jetty.home", EnvUtils.toSystemPath("/opt/jetty-distro") }, - { "jetty.base", EnvUtils.toSystemPath("/opt/jetty-distro/demo.base") }, - { "user.home", EnvUtils.toSystemPath("/home/user") }, - { "user.dir", EnvUtils.toSystemPath("/etc/init.d") }, - }; - - return Arrays.asList(tests); - } - - private static Path testRoot; - private static String origJettyBase; - private static String origJettyHome; - private static String origUserHome; - private static String origUserDir; - - static - { - testRoot = MavenTestingUtils.getTargetTestingPath(AttributeNormalizerPathTest.class.getSimpleName()); - FS.ensureEmpty(testRoot); - } - - @BeforeClass - public static void initProperties() - { - origJettyBase = System.getProperty("jetty.base"); - origJettyHome = System.getProperty("jetty.home"); - origUserHome = System.getProperty("user.home"); - origUserDir = System.getProperty("user.dir"); - - System.setProperty("jetty.home","/opt/jetty-distro"); - System.setProperty("jetty.base","/opt/jetty-distro/demo.base"); - System.setProperty("user.home","/home/user"); - System.setProperty("user.dir","/etc/init.d"); - } - - @AfterClass - public static void restoreProperties() - { - if(origJettyBase != null) System.setProperty("jetty.base",origJettyBase); - if(origJettyHome != null) System.setProperty("jetty.home",origJettyHome); - if(origUserHome != null) System.setProperty("user.home",origUserHome); - if(origUserDir != null) System.setProperty("user.dir",origUserDir); - } - - public String key; - public String path; - - private AttributeNormalizer normalizer; - - public AttributeNormalizerPathTest(String key, String path) throws MalformedURLException - { - this.key = key; - this.path = AttributeNormalizer.uriSeparators(path); - this.normalizer = new AttributeNormalizer(Resource.newResource(testRoot.toFile())); - } - - private void assertExpand(String line, String expected) - { - assertThat("normalizer.expand(\"" + line + "\")", normalizer.expand(line), is(expected)); - } - - @Test - public void testEqual() - { - assertThat(normalizer.normalize("file:" + path), is("file:${" + key + "}")); - } - - @Test - public void testExpandEqual() - { - String expectedPath = new File(path).toPath().toUri().getRawSchemeSpecificPart(); - assertExpand("file:${" + key + "}", "file:" + expectedPath); - } - - @Test - public void testEqualsSlash() - { - assertThat(normalizer.normalize("file:" + path + "/"), is("file:${" + key + "}")); - } - - @Test - public void testEqualsSlashFile() - { - assertThat(normalizer.normalize("file:" + path + "/file"), is("file:${" + key + "}/file")); - } - - @Test - public void testURIEquals() throws URISyntaxException - { - assertThat(normalizer.normalize(new URI("file:" + path)), is("file:${" + key + "}")); - } - - @Test - public void testURIEqualsSlash() throws URISyntaxException - { - assertThat(normalizer.normalize(new URI("file:" + path + "/")), is("file:${" + key + "}")); - } - - @Test - public void testURIEqualsSlashFile() throws URISyntaxException - { - assertThat(normalizer.normalize(new URI("file:" + path + "/file")), is("file:${" + key + "}/file")); - } - - @Test - public void testURLEquals() throws MalformedURLException - { - assertThat(normalizer.normalize(new URL("file:" + path)), is("file:${" + key + "}")); - } - - @Test - public void testURLEqualsSlash() throws MalformedURLException - { - assertThat(normalizer.normalize(new URL("file:" + path + "/")), is("file:${" + key + "}")); - } - - @Test - public void testURLEqualsSlashFile() throws MalformedURLException - { - assertThat(normalizer.normalize(new URL("file:" + path + "/file")), is("file:${" + key + "}/file")); - } - - @Test - public void testJarFileEquals_BangFile() - { - assertThat(normalizer.normalize("jar:file:" + path + "!/file"), is("jar:file:${" + key + "}!/file")); - } - - @Test - public void testJarFileEquals_SlashBangFile() - { - assertThat(normalizer.normalize("jar:file:" + path + "/!/file"), is("jar:file:${" + key + "}!/file")); - } - - @Test - public void testJarFileEquals_FileBangFile() - { - assertThat(normalizer.normalize("jar:file:" + path + "/file!/file"), is("jar:file:${" + key + "}/file!/file")); - } - - @Test - public void testExpandJarFileEquals_FileBangFile() - { - String expectedPath = new File(path).toPath().toUri().getRawSchemeSpecificPart(); - assertExpand("jar:file:${" + key + "}/file!/file", "jar:file:" + expectedPath + "/file!/file"); - } - - @Test - public void testJarFileEquals_URIBangFile() throws URISyntaxException - { - assertThat(normalizer.normalize(new URI("jar:file:" + path + "!/file")), is("jar:file:${" + key + "}!/file")); - } - - @Test - public void testJarFileEquals_URISlashBangFile() throws URISyntaxException - { - assertThat(normalizer.normalize(new URI("jar:file:" + path + "/!/file")), is("jar:file:${" + key + "}!/file")); - } - - @Test - public void testJarFileEquals_URIFileBangFile() throws URISyntaxException - { - assertThat(normalizer.normalize(new URI("jar:file:" + path + "/file!/file")), is("jar:file:${" + key + "}/file!/file")); - } - - @Test - public void testJarFileEquals_URLBangFile() throws MalformedURLException - { - assertThat(normalizer.normalize(new URL("jar:file:" + path + "!/file")), is("jar:file:${" + key + "}!/file")); - } - - @Test - public void testJarFileEquals_URLSlashBangFile() throws MalformedURLException - { - assertThat(normalizer.normalize(new URL("jar:file:" + path + "/!/file")), is("jar:file:${" + key + "}!/file")); - } - - @Test - public void testJarFileEquals_URLFileBangFile() throws MalformedURLException - { - assertThat(normalizer.normalize(new URL("jar:file:" + path + "/file!/file")), is("jar:file:${" + key + "}/file!/file")); - } -} diff --git a/tests/test-quickstart/src/test/java/org/eclipse/jetty/quickstart/AttributeNormalizerTest.java b/tests/test-quickstart/src/test/java/org/eclipse/jetty/quickstart/AttributeNormalizerTest.java index 0d8ccb9d69e..26fc5385e46 100644 --- a/tests/test-quickstart/src/test/java/org/eclipse/jetty/quickstart/AttributeNormalizerTest.java +++ b/tests/test-quickstart/src/test/java/org/eclipse/jetty/quickstart/AttributeNormalizerTest.java @@ -18,10 +18,7 @@ package org.eclipse.jetty.quickstart; -import static org.hamcrest.Matchers.anyOf; -import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.not; import static org.junit.Assert.assertThat; import java.io.File; @@ -57,9 +54,8 @@ public class AttributeNormalizerTest result = normalizer.normalize(testWar); assertThat(result, is(testWar)); // only URL, File, URI are supported - URI testWarURI = new File(testWar).toURI(); - // Normalize as URI + URI testWarURI = new File(testWar).toURI(); result = normalizer.normalize(testWarURI); assertThat(result, is("${WAR}")); @@ -75,6 +71,7 @@ public class AttributeNormalizerTest // Normalize deep path as URI result = normalizer.normalize(testWarDeep.toURI()); assertThat(result, is("${WAR}/deep/ref")); + } finally { @@ -83,6 +80,50 @@ public class AttributeNormalizerTest } } + + @Test + public void testNormalizeURIs() throws MalformedURLException + { + String testWar = EnvUtils.toSystemPath("/opt/jetty-distro/demo.base/webapps/FOO"); + + Resource webresource = Resource.newResource(testWar); + AttributeNormalizer normalizer = new AttributeNormalizer(webresource); + String result = null; + + // Normalize as String path + result = normalizer.normalize(testWar); + assertThat(result, is(testWar)); // only URL, File, URI are supported + + // Normalize as URI + URI testWarURI = new File(testWar).toURI(); + result = normalizer.normalize(testWarURI); + assertThat(result, is("${WAR}")); + + // Normalize as URI + URI subURI = new File(testWar,"WEB-INF/web.xml").toURI(); + result = normalizer.normalize(subURI); + assertThat(result, is("${WAR}/WEB-INF/web.xml")); + + // Normalize fake prefix + URI fakeURI = Resource.newResource(EnvUtils.toSystemPath("/opt/jetty-distro/demo.base/webapps/FOOBAR")).getURI(); + result = normalizer.normalize(fakeURI); + assertThat(result, is(fakeURI.toASCIIString())); + + // Normalize as no host + result = normalizer.normalize("file:"+testWarURI.getRawPath()); + assertThat(result, is("${WAR}")); + + // Normalize as null host + result = normalizer.normalize("file://"+testWarURI.getRawPath()); + assertThat(result, is("${WAR}")); + + // Normalize jar file + result = normalizer.normalize("jar:file:"+testWarURI.getRawPath()+"!/some/path"); + assertThat(result, is("jar:${WAR}!/some/path")); + + } + + @Test public void testNormalizeExpandWAR() throws MalformedURLException { @@ -107,26 +148,7 @@ public class AttributeNormalizerTest result = normalizer.expand(line); uri = URI.create("jar:" + webrefFile.toPath().toUri().toASCIIString() + "!/other/file"); assertThat("expand(\"" + line + "\")", URI.create(result), is(uri)); - } - - @Test - public void testWindowsTLD() throws MalformedURLException - { - // Setup AttributeNormalizer - String webref = "http://localhost/resource/webapps/root"; - Resource webresource = Resource.newResource(webref); - AttributeNormalizer normalizer = new AttributeNormalizer(webresource); - // Setup example from windows - String javaUserHome = System.getProperty("user.home"); - String realUserHome = EnvUtils.toSystemPath(javaUserHome); - String userHome = AttributeNormalizer.uriSeparators(realUserHome); - String path = "jar:file:" + userHome + "/.m2/repository/something/somejar.jar!/META-INF/some.tld"; - String result = normalizer.normalize(path); - assertThat(result, is("jar:file:${user.home}/.m2/repository/something/somejar.jar!/META-INF/some.tld")); - - String expanded = normalizer.expand(result); - assertThat(expanded, not(anyOf(containsString("\\"), containsString("${")))); } }