diff --git a/documentation/jetty-documentation/src/main/asciidoc/operations-guide/modules/modules.adoc b/documentation/jetty-documentation/src/main/asciidoc/operations-guide/modules/modules.adoc index a9207b77b636..03ef41e8645a 100644 --- a/documentation/jetty-documentation/src/main/asciidoc/operations-guide/modules/modules.adoc +++ b/documentation/jetty-documentation/src/main/asciidoc/operations-guide/modules/modules.adoc @@ -128,7 +128,7 @@ Appends the value to the existing value. This is useful to append a value to properties that accept a comma separated list of values, for example: + ---- -jetty.webapp.addServerClasses+=,com.acme +jetty.webapp.addProtectedClasses+=,com.acme ---- + // TODO: check what happens if the property is empty and +=,value is done: is the comma stripped? If so add a sentence about this. diff --git a/jetty-core/jetty-ee/pom.xml b/jetty-core/jetty-ee/pom.xml new file mode 100644 index 000000000000..8ff96f24bd78 --- /dev/null +++ b/jetty-core/jetty-ee/pom.xml @@ -0,0 +1,61 @@ + + + + 4.0.0 + + org.eclipse.jetty + jetty-core + 12.0.9-SNAPSHOT + + jetty-ee + Core :: EE Common + + + ${project.groupId}.ee + org.eclipse.jetty.ee.* + + + + + org.eclipse.jetty + jetty-server + + + org.slf4j + slf4j-api + + + org.eclipse.jetty + jetty-slf4j-impl + test + + + org.eclipse.jetty.tests + jetty-test-multipart + ${project.version} + test + + + org.eclipse.jetty.toolchain + jetty-test-helper + test + + + + + + + org.apache.felix + maven-bundle-plugin + true + + + org.apache.maven.plugins + maven-surefire-plugin + + @{argLine} ${jetty.surefire.argLine} --add-reads org.eclipse.jetty.ee=org.eclipse.jetty.logging + + + + + diff --git a/jetty-core/jetty-ee/src/main/config/etc/jetty-ee-webapp.xml b/jetty-core/jetty-ee/src/main/config/etc/jetty-ee-webapp.xml new file mode 100644 index 000000000000..0ba8f34ec729 --- /dev/null +++ b/jetty-core/jetty-ee/src/main/config/etc/jetty-ee-webapp.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jetty-core/jetty-ee/src/main/config/modules/ee-webapp.mod b/jetty-core/jetty-ee/src/main/config/modules/ee-webapp.mod new file mode 100644 index 000000000000..db2420cf4f29 --- /dev/null +++ b/jetty-core/jetty-ee/src/main/config/modules/ee-webapp.mod @@ -0,0 +1,31 @@ +# DO NOT EDIT THIS FILE - See: https://eclipse.dev/jetty/documentation/ + +[description] +# tag::description[] +This module provide common configuration of Java Servlet web applications over all environments. +# end::description[] + +[xml] +etc/jetty-ee-webapp.xml + +[lib] +lib/jetty-ee-${jetty.version}.jar + +[ini-template] +# tag::ini-template[] +## Add to the server wide default jars and packages protected or hidden from webapps. +## Protected (aka System) classes cannot be overridden by a webapp. +## Hidden (aka Server) classes cannot be seen by a webapp +## Lists of patterns are comma separated and may be either: +## + a qualified classname e.g. 'com.acme.Foo' +## + a package name e.g. 'net.example.' +## + a jar file e.g. '${jetty.base.uri}/lib/dependency.jar' +## + a directory of jars,resource or classes e.g. '${jetty.base.uri}/resources' +## + A pattern preceded with a '-' is an exclusion, all other patterns are inclusions +## +## The +=, operator appends to a CSV list with a comma as needed. +## +#jetty.server.addProtectedClasses+=,org.example. +#jetty.server.addHiddenClasses+=,org.example. +# end::ini-template[] + diff --git a/jetty-core/jetty-ee/src/main/java/module-info.java b/jetty-core/jetty-ee/src/main/java/module-info.java new file mode 100644 index 000000000000..90f777dc5720 --- /dev/null +++ b/jetty-core/jetty-ee/src/main/java/module-info.java @@ -0,0 +1,22 @@ +// +// ======================================================================== +// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others. +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License v. 2.0 which is available at +// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// ======================================================================== +// + +module org.eclipse.jetty.ee +{ + requires org.slf4j; + + requires transitive org.eclipse.jetty.util; + requires transitive org.eclipse.jetty.server; + + exports org.eclipse.jetty.ee; +} diff --git a/jetty-core/jetty-ee/src/main/java/org/eclipse/jetty/ee/WebAppClassLoading.java b/jetty-core/jetty-ee/src/main/java/org/eclipse/jetty/ee/WebAppClassLoading.java new file mode 100644 index 000000000000..eaf13e52a64a --- /dev/null +++ b/jetty-core/jetty-ee/src/main/java/org/eclipse/jetty/ee/WebAppClassLoading.java @@ -0,0 +1,214 @@ +// +// ======================================================================== +// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others. +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License v. 2.0 which is available at +// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// ======================================================================== +// + +package org.eclipse.jetty.ee; + +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.util.Attributes; +import org.eclipse.jetty.util.ClassMatcher; +import org.eclipse.jetty.util.component.Environment; + +/** + * Common attributes and methods for configuring the {@link ClassLoader Class loading} of web application: + * + *

These protections are set to reasonable defaults {@link #DEFAULT_PROTECTED_CLASSES} and {@link #DEFAULT_HIDDEN_CLASSES}, + * which may be programmatically configured and will affect the defaults applied to all web applications in the same JVM. + * + *

+ * The defaults applied by a specific {@link Server} can be configured using {@link #addProtectedClasses(Server, String...)} and + * {@link #addHiddenClasses(Server, String...)}. Alternately the {@link Server} attributes {@link #PROTECTED_CLASSES_ATTRIBUTE} + * and {@link #HIDDEN_CLASSES_ATTRIBUTE} may be used to direct set a {@link ClassMatcher} to use for all web applications + * within the server instance. + *

+ *

+ * The defaults applied by a specific {@link Environment} can be configured using {@link #addProtectedClasses(Environment, String...)} and + * {@link #addHiddenClasses(Environment, String...)}. Alternately the {@link Environment} attributes {@link #PROTECTED_CLASSES_ATTRIBUTE} + * and {@link #HIDDEN_CLASSES_ATTRIBUTE} may be used to direct set a {@link ClassMatcher} to use for all web applications + * within the server instance. + *

+ *

+ * Ultimately, the configurations set by this class only affects the defaults applied to each web application + * {@link org.eclipse.jetty.server.handler.ContextHandler Context} and the {@link ClassMatcher} fields of the web applications + * can be directly access to configure a specific context. + *

+ */ +public class WebAppClassLoading +{ + public static final String PROTECTED_CLASSES_ATTRIBUTE = "org.eclipse.jetty.webapp.systemClasses"; + public static final String HIDDEN_CLASSES_ATTRIBUTE = "org.eclipse.jetty.webapp.serverClasses"; + + /** + * The default protected (system) classes used by a web application, which will be applied to the {@link ClassMatcher}s created + * by {@link #getProtectedClasses(Environment)}. + */ + public static final ClassMatcher DEFAULT_PROTECTED_CLASSES = new ClassMatcher( + "java.", // Java SE classes (per servlet spec v2.5 / SRV.9.7.2) + "javax.", // Java SE classes (per servlet spec v2.5 / SRV.9.7.2) + "jakarta.", // Jakarta classes (per servlet spec v5.0 / Section 15.2.1) + "org.xml.", // javax.xml + "org.w3c." // javax.xml + ); + + /** + * The default hidden (server) classes used by a web application, which can be applied to the {@link ClassMatcher}s created + * by {@link #getHiddenClasses(Environment)}. + */ + public static final ClassMatcher DEFAULT_HIDDEN_CLASSES = new ClassMatcher( + "org.eclipse.jetty." // hide jetty classes + ); + + /** + * Get the default protected (system) classes for a {@link Server} + * @param server The {@link Server} for the defaults + * @return The default protected (system) classes for the {@link Server}, which will be empty if not previously configured. + */ + public static ClassMatcher getProtectedClasses(Server server) + { + return getClassMatcher(server, PROTECTED_CLASSES_ATTRIBUTE, null); + } + + /** + * Get the default protected (system) classes for an {@link Environment} + * @param environment The {@link Server} for the defaults + * @return The default protected (system) classes for the {@link Environment}, which will be the {@link #DEFAULT_PROTECTED_CLASSES} if not previously configured. + */ + public static ClassMatcher getProtectedClasses(Environment environment) + { + return getClassMatcher(environment, PROTECTED_CLASSES_ATTRIBUTE, DEFAULT_PROTECTED_CLASSES); + } + + /** + * Add a protected (system) Class pattern to use for all WebAppContexts. + * @param patterns the patterns to use + */ + public static void addProtectedClasses(String... patterns) + { + DEFAULT_PROTECTED_CLASSES.add(patterns); + } + + /** + * Add a protected (system) Class pattern to use for all WebAppContexts of a given {@link Server}. + * @param attributes The {@link Attributes} instance to add classes to + * @param patterns the patterns to use + */ + public static void addProtectedClasses(Attributes attributes, String... patterns) + { + if (patterns != null && patterns.length > 0) + getClassMatcher(attributes, PROTECTED_CLASSES_ATTRIBUTE, null).add(patterns); + } + + /** + * Add a protected (system) Class pattern to use for all WebAppContexts of a given {@link Server}. + * @param server The {@link Server} instance to add classes to + * @param patterns the patterns to use + */ + public static void addProtectedClasses(Server server, String... patterns) + { + if (patterns != null && patterns.length > 0) + getClassMatcher(server, PROTECTED_CLASSES_ATTRIBUTE, null).add(patterns); + } + + /** + * Add a protected (system) Class pattern to use for WebAppContexts of a given environment. + * @param environment The {@link Environment} instance to add classes to + * @param patterns the patterns to use + */ + public static void addProtectedClasses(Environment environment, String... patterns) + { + if (patterns != null && patterns.length > 0) + getClassMatcher(environment, PROTECTED_CLASSES_ATTRIBUTE, DEFAULT_PROTECTED_CLASSES).add(patterns); + } + + /** + * Get the default hidden (server) classes for a {@link Server} + * @param server The {@link Server} for the defaults + * @return The default hidden (server) classes for the {@link Server}, which will be empty if not previously configured. + * + */ + public static ClassMatcher getHiddenClasses(Server server) + { + return getClassMatcher(server, HIDDEN_CLASSES_ATTRIBUTE, null); + } + + /** + * Get the default hidden (server) classes for an {@link Environment} + * @param environment The {@link Server} for the defaults + * @return The default hidden (server) classes for the {@link Environment}, which will be {@link #DEFAULT_PROTECTED_CLASSES} if not previously configured. + */ + public static ClassMatcher getHiddenClasses(Environment environment) + { + return getClassMatcher(environment, HIDDEN_CLASSES_ATTRIBUTE, DEFAULT_HIDDEN_CLASSES); + } + + /** + * Add a hidden (server) Class pattern to use for all WebAppContexts of a given {@link Server}. + * @param patterns the patterns to use + */ + public static void addHiddenClasses(String... patterns) + { + DEFAULT_HIDDEN_CLASSES.add(patterns); + } + + /** + * Add a hidden (server) Class pattern to use for all WebAppContexts of a given {@link Server}. + * @param attributes The {@link Attributes} instance to add classes to + * @param patterns the patterns to use + */ + @Deprecated (forRemoval = true) + public static void addHiddenClasses(Attributes attributes, String... patterns) + { + if (patterns != null && patterns.length > 0) + getClassMatcher(attributes, HIDDEN_CLASSES_ATTRIBUTE, null).add(patterns); + } + + /** + * Add a hidden (server) Class pattern to use for all WebAppContexts of a given {@link Server}. + * @param server The {@link Server} instance to add classes to + * @param patterns the patterns to use + */ + public static void addHiddenClasses(Server server, String... patterns) + { + if (patterns != null && patterns.length > 0) + getClassMatcher(server, HIDDEN_CLASSES_ATTRIBUTE, null).add(patterns); + } + + /** + * Add a hidden (server) Class pattern to use for all ee9 WebAppContexts. + * @param environment The {@link Environment} instance to add classes to + * @param patterns the patterns to use + */ + public static void addHiddenClasses(Environment environment, String... patterns) + { + if (patterns != null && patterns.length > 0) + getClassMatcher(environment, HIDDEN_CLASSES_ATTRIBUTE, DEFAULT_HIDDEN_CLASSES).add(patterns); + } + + private static ClassMatcher getClassMatcher(Attributes attributes, String attribute, ClassMatcher defaultPatterns) + { + Object existing = attributes.getAttribute(attribute); + if (existing instanceof ClassMatcher cm) + return cm; + + ClassMatcher classMatcher = (existing instanceof String[] stringArray) + ? new ClassMatcher(stringArray) : new ClassMatcher(defaultPatterns); + attributes.setAttribute(attribute, classMatcher); + return classMatcher; + } + +} diff --git a/jetty-core/jetty-ee/src/test/java/orge/eclipse/jetty/ee/WebAppClassLoadingTest.java b/jetty-core/jetty-ee/src/test/java/orge/eclipse/jetty/ee/WebAppClassLoadingTest.java new file mode 100644 index 000000000000..cf4299986066 --- /dev/null +++ b/jetty-core/jetty-ee/src/test/java/orge/eclipse/jetty/ee/WebAppClassLoadingTest.java @@ -0,0 +1,222 @@ +// +// ======================================================================== +// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others. +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License v. 2.0 which is available at +// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// ======================================================================== +// + +package orge.eclipse.jetty.ee; + +import java.util.Arrays; + +import org.eclipse.jetty.ee.WebAppClassLoading; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.util.ClassMatcher; +import org.eclipse.jetty.util.component.Environment; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasItemInArray; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.sameInstance; + +public class WebAppClassLoadingTest +{ + @BeforeEach + public void beforeEach() + { + Environment.ensure("Test"); + } + + @AfterEach + public void afterEach() + { + Environment.ensure("Test").clearAttributes(); + } + + @Test + public void testServerDefaults() + { + Server server = new Server(); + ClassMatcher protect = WebAppClassLoading.getProtectedClasses(server); + assertThat(protect.size(), is(0)); + assertThat(server.getAttribute(WebAppClassLoading.PROTECTED_CLASSES_ATTRIBUTE), sameInstance(protect)); + ClassMatcher hide = WebAppClassLoading.getHiddenClasses(server); + assertThat(hide.size(), is(0)); + assertThat(server.getAttribute(WebAppClassLoading.HIDDEN_CLASSES_ATTRIBUTE), sameInstance(hide)); + } + + @Test + public void testServerAttributeDefaults() + { + Server server = new Server(); + ClassMatcher protect = new ClassMatcher("org.protect."); + server.setAttribute(WebAppClassLoading.PROTECTED_CLASSES_ATTRIBUTE, protect); + ClassMatcher hide = new ClassMatcher("org.hide."); + server.setAttribute(WebAppClassLoading.HIDDEN_CLASSES_ATTRIBUTE, hide); + + assertThat(WebAppClassLoading.getProtectedClasses(server), sameInstance(protect)); + assertThat(WebAppClassLoading.getHiddenClasses(server), sameInstance(hide)); + } + + @Test + public void testServerStringAttributeDefaults() + { + Server server = new Server(); + server.setAttribute(WebAppClassLoading.PROTECTED_CLASSES_ATTRIBUTE, new String[] {"org.protect."}); + server.setAttribute(WebAppClassLoading.HIDDEN_CLASSES_ATTRIBUTE, new String[] {"org.hide."}); + + ClassMatcher protect = WebAppClassLoading.getProtectedClasses(server); + assertThat(protect.size(), is(1)); + assertThat(Arrays.asList(protect.getPatterns()), contains("org.protect.")); + assertThat(server.getAttribute(WebAppClassLoading.PROTECTED_CLASSES_ATTRIBUTE), sameInstance(protect)); + ClassMatcher hide = WebAppClassLoading.getHiddenClasses(server); + assertThat(hide.size(), is(1)); + assertThat(Arrays.asList(hide.getPatterns()), contains("org.hide.")); + assertThat(server.getAttribute(WebAppClassLoading.HIDDEN_CLASSES_ATTRIBUTE), sameInstance(hide)); + } + + @Test + public void testServerProgrammaticDefaults() + { + Server server = new Server(); + WebAppClassLoading.addProtectedClasses(server, "org.protect."); + WebAppClassLoading.addHiddenClasses(server, "org.hide."); + + ClassMatcher protect = WebAppClassLoading.getProtectedClasses(server); + assertThat(protect.size(), is(1)); + assertThat(Arrays.asList(protect.getPatterns()), contains("org.protect.")); + assertThat(server.getAttribute(WebAppClassLoading.PROTECTED_CLASSES_ATTRIBUTE), sameInstance(protect)); + ClassMatcher hide = WebAppClassLoading.getHiddenClasses(server); + assertThat(hide.size(), is(1)); + assertThat(Arrays.asList(hide.getPatterns()), contains("org.hide.")); + assertThat(server.getAttribute(WebAppClassLoading.HIDDEN_CLASSES_ATTRIBUTE), sameInstance(hide)); + } + + @Test + public void testServerAddPatterns() + { + Server server = new Server(); + ClassMatcher protect = WebAppClassLoading.getProtectedClasses(server); + ClassMatcher hide = WebAppClassLoading.getHiddenClasses(server); + + assertThat(protect.size(), is(0)); + assertThat(hide.size(), is(0)); + + WebAppClassLoading.addProtectedClasses(server, "org.protect.", "com.protect."); + WebAppClassLoading.addHiddenClasses(server, "org.hide.", "com.hide."); + + assertThat(protect.size(), is(2)); + assertThat(Arrays.asList(protect.getPatterns()), containsInAnyOrder("org.protect.", "com.protect.")); + assertThat(server.getAttribute(WebAppClassLoading.PROTECTED_CLASSES_ATTRIBUTE), sameInstance(protect)); + + assertThat(hide.size(), is(2)); + assertThat(Arrays.asList(hide.getPatterns()), containsInAnyOrder("org.hide.", "com.hide.")); + assertThat(server.getAttribute(WebAppClassLoading.HIDDEN_CLASSES_ATTRIBUTE), sameInstance(hide)); + } + + @Test + public void testEnvironmentDefaults() + { + Environment environment = Environment.get("Test"); + ClassMatcher protect = WebAppClassLoading.getProtectedClasses(environment); + assertThat(protect, equalTo(WebAppClassLoading.DEFAULT_PROTECTED_CLASSES)); + assertThat(environment.getAttribute(WebAppClassLoading.PROTECTED_CLASSES_ATTRIBUTE), sameInstance(protect)); + ClassMatcher hide = WebAppClassLoading.getHiddenClasses(environment); + assertThat(hide, equalTo(WebAppClassLoading.DEFAULT_HIDDEN_CLASSES)); + assertThat(environment.getAttribute(WebAppClassLoading.HIDDEN_CLASSES_ATTRIBUTE), sameInstance(hide)); + } + + @Test + public void testEnvironmentAttributeDefaults() + { + Environment environment = Environment.get("Test"); + ClassMatcher protect = new ClassMatcher("org.protect."); + environment.setAttribute(WebAppClassLoading.PROTECTED_CLASSES_ATTRIBUTE, protect); + ClassMatcher hide = new ClassMatcher("org.hide."); + environment.setAttribute(WebAppClassLoading.HIDDEN_CLASSES_ATTRIBUTE, hide); + + assertThat(WebAppClassLoading.getProtectedClasses(environment), sameInstance(protect)); + assertThat(WebAppClassLoading.getHiddenClasses(environment), sameInstance(hide)); + } + + @Test + public void testEnvironmentStringAttributeDefaults() + { + Environment environment = Environment.get("Test"); + environment.setAttribute(WebAppClassLoading.PROTECTED_CLASSES_ATTRIBUTE, new String[] {"org.protect."}); + environment.setAttribute(WebAppClassLoading.HIDDEN_CLASSES_ATTRIBUTE, new String[] {"org.hide."}); + + ClassMatcher protect = WebAppClassLoading.getProtectedClasses(environment); + assertThat(protect.size(), is(1)); + assertThat(Arrays.asList(protect.getPatterns()), contains("org.protect.")); + assertThat(environment.getAttribute(WebAppClassLoading.PROTECTED_CLASSES_ATTRIBUTE), sameInstance(protect)); + ClassMatcher hide = WebAppClassLoading.getHiddenClasses(environment); + assertThat(hide.size(), is(1)); + assertThat(Arrays.asList(hide.getPatterns()), contains("org.hide.")); + assertThat(environment.getAttribute(WebAppClassLoading.HIDDEN_CLASSES_ATTRIBUTE), sameInstance(hide)); + } + + @Test + public void testEnvironmentProgrammaticDefaults() + { + Environment environment = Environment.get("Test"); + WebAppClassLoading.addProtectedClasses(environment, "org.protect."); + WebAppClassLoading.addHiddenClasses(environment, "org.hide."); + + ClassMatcher protect = WebAppClassLoading.getProtectedClasses(environment); + ClassMatcher hide = WebAppClassLoading.getHiddenClasses(environment); + + assertThat(protect.size(), is(WebAppClassLoading.DEFAULT_PROTECTED_CLASSES.size() + 1)); + assertThat(protect.getPatterns(), hasItemInArray("org.protect.")); + for (String pattern : WebAppClassLoading.DEFAULT_PROTECTED_CLASSES) + assertThat(protect.getPatterns(), hasItemInArray(pattern)); + assertThat(environment.getAttribute(WebAppClassLoading.PROTECTED_CLASSES_ATTRIBUTE), sameInstance(protect)); + + assertThat(hide.size(), is(WebAppClassLoading.DEFAULT_HIDDEN_CLASSES.size() + 1)); + assertThat(hide.getPatterns(), hasItemInArray("org.hide.")); + for (String pattern : WebAppClassLoading.DEFAULT_HIDDEN_CLASSES) + assertThat(hide.getPatterns(), hasItemInArray(pattern)); + assertThat(environment.getAttribute(WebAppClassLoading.HIDDEN_CLASSES_ATTRIBUTE), sameInstance(hide)); + } + + @Test + public void testEnvironmentAddPatterns() + { + Environment environment = Environment.get("Test"); + ClassMatcher protect = WebAppClassLoading.getProtectedClasses(environment); + ClassMatcher hide = WebAppClassLoading.getHiddenClasses(environment); + + assertThat(protect, equalTo(WebAppClassLoading.DEFAULT_PROTECTED_CLASSES)); + assertThat(hide, equalTo(WebAppClassLoading.DEFAULT_HIDDEN_CLASSES)); + + WebAppClassLoading.addProtectedClasses(environment, "org.protect.", "com.protect."); + WebAppClassLoading.addHiddenClasses(environment, "org.hide.", "com.hide."); + + assertThat(protect.size(), is(WebAppClassLoading.DEFAULT_PROTECTED_CLASSES.size() + 2)); + assertThat(protect.getPatterns(), hasItemInArray("org.protect.")); + assertThat(protect.getPatterns(), hasItemInArray("com.protect.")); + for (String pattern : WebAppClassLoading.DEFAULT_PROTECTED_CLASSES) + assertThat(protect.getPatterns(), hasItemInArray(pattern)); + assertThat(environment.getAttribute(WebAppClassLoading.PROTECTED_CLASSES_ATTRIBUTE), sameInstance(protect)); + + assertThat(hide.size(), is(WebAppClassLoading.DEFAULT_HIDDEN_CLASSES.size() + 2)); + assertThat(hide.getPatterns(), hasItemInArray("org.hide.")); + assertThat(hide.getPatterns(), hasItemInArray("com.hide.")); + for (String pattern : WebAppClassLoading.DEFAULT_HIDDEN_CLASSES) + assertThat(hide.getPatterns(), hasItemInArray(pattern)); + assertThat(environment.getAttribute(WebAppClassLoading.HIDDEN_CLASSES_ATTRIBUTE), sameInstance(hide)); + } + +} diff --git a/jetty-core/jetty-keystore/src/main/config/modules/test-keystore.mod b/jetty-core/jetty-keystore/src/main/config/modules/test-keystore.mod index 0ff1996dbfed..1c1b98fb3dc0 100644 --- a/jetty-core/jetty-keystore/src/main/config/modules/test-keystore.mod +++ b/jetty-core/jetty-keystore/src/main/config/modules/test-keystore.mod @@ -25,7 +25,7 @@ etc/jetty-test-keystore.xml [ini] bouncycastle.version?=@bouncycastle.version@ -jetty.webapp.addServerClasses+=,${jetty.base.uri}/lib/bouncycastle/ +jetty.webapp.addHiddenClasses+=,${jetty.base.uri}/lib/bouncycastle/ jetty.sslContext.keyStorePath?=etc/test-keystore.p12 jetty.sslContext.keyStoreType?=PKCS12 jetty.sslContext.keyStorePassword?=OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4 diff --git a/jetty-core/jetty-session/src/main/java/org/eclipse/jetty/session/SessionData.java b/jetty-core/jetty-session/src/main/java/org/eclipse/jetty/session/SessionData.java index a5445c76ccac..c33682cb4327 100644 --- a/jetty-core/jetty-session/src/main/java/org/eclipse/jetty/session/SessionData.java +++ b/jetty-core/jetty-session/src/main/java/org/eclipse/jetty/session/SessionData.java @@ -89,7 +89,7 @@ else if (contextLoader instanceof ClassVisibilityChecker) //Clazz not loaded by context classloader, but ask if loadable by context classloader, //because preferable to use context classloader if possible (eg for deep structures). ClassVisibilityChecker checker = (ClassVisibilityChecker)(contextLoader); - isContextLoader = (checker.isSystemClass(clazz) && !(checker.isServerClass(clazz))); + isContextLoader = (checker.isProtectedClass(clazz) && !(checker.isHiddenClass(clazz))); } else { diff --git a/jetty-core/jetty-util/src/main/java/org/eclipse/jetty/util/ClassMatcher.java b/jetty-core/jetty-util/src/main/java/org/eclipse/jetty/util/ClassMatcher.java new file mode 100644 index 000000000000..2fe9fe754c8d --- /dev/null +++ b/jetty-core/jetty-util/src/main/java/org/eclipse/jetty/util/ClassMatcher.java @@ -0,0 +1,810 @@ +// +// ======================================================================== +// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others. +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License v. 2.0 which is available at +// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// ======================================================================== +// + +package org.eclipse.jetty.util; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.AbstractSet; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Predicate; +import java.util.function.Supplier; + +/** + * A matcher for classes based on package and/or location and/or module/ + *

+ * Performs pattern matching of a class against a set of pattern entries. + * A class pattern is a string of one of the forms:

+ * When class is initialized from a classpath pattern string, entries + * in this string should be separated by ':' (semicolon) or ',' (comma). + */ + +public class ClassMatcher extends AbstractSet +{ + public static class Entry + { + private final String _pattern; + private final String _name; + private final boolean _inclusive; + + protected Entry(String name, boolean inclusive) + { + _name = name; + _inclusive = inclusive; + _pattern = inclusive ? _name : ("-" + _name); + } + + public String getPattern() + { + return _pattern; + } + + public String getName() + { + return _name; + } + + @Override + public String toString() + { + return _pattern; + } + + @Override + public int hashCode() + { + return _pattern.hashCode(); + } + + @Override + public boolean equals(Object o) + { + return (o instanceof Entry) && _pattern.equals(((Entry)o)._pattern); + } + + public boolean isInclusive() + { + return _inclusive; + } + } + + private static class PackageEntry extends Entry + { + protected PackageEntry(String name, boolean inclusive) + { + super(name, inclusive); + } + } + + private static class ClassEntry extends Entry + { + protected ClassEntry(String name, boolean inclusive) + { + super(name, inclusive); + } + } + + private static class LocationEntry extends Entry + { + private final Path _path; + + protected LocationEntry(String name, boolean inclusive) + { + super(name, inclusive); + URI uri = URI.create(name); + if (!uri.isAbsolute() && !"file".equalsIgnoreCase(uri.getScheme())) + throw new IllegalArgumentException("Not a valid file URI: " + name); + + _path = Paths.get(uri); + } + + public Path getPath() + { + return _path; + } + } + + private static class ModuleEntry extends Entry + { + private final String _module; + + protected ModuleEntry(String name, boolean inclusive) + { + super(name, inclusive); + if (!getName().startsWith("jrt:")) + throw new IllegalArgumentException(name); + _module = getName().split("/")[1]; + } + + public String getModule() + { + return _module; + } + } + + public static class ByPackage extends AbstractSet implements Predicate + { + private final Index.Mutable _entries = new Index.Builder() + .caseSensitive(true) + .mutable() + .build(); + + @Override + public boolean test(String name) + { + return _entries.getBest(name) != null; + } + + @Override + public Iterator iterator() + { + return _entries.keySet().stream().map(_entries::get).iterator(); + } + + @Override + public int size() + { + return _entries.size(); + } + + @Override + public boolean isEmpty() + { + return _entries.isEmpty(); + } + + @Override + public boolean add(Entry entry) + { + String name = entry.getName(); + if (entry instanceof ClassEntry) + name += "$"; + else if (!(entry instanceof PackageEntry)) + throw new IllegalArgumentException(entry.toString()); + else if (".".equals(name)) + name = ""; + + if (_entries.get(name) != null) + return false; + + return _entries.put(name, entry); + } + + @Override + public boolean remove(Object entry) + { + if (!(entry instanceof Entry)) + return false; + + return _entries.remove(((Entry)entry).getName()) != null; + } + + @Override + public void clear() + { + _entries.clear(); + } + } + + public static class ByClass extends HashSet implements Predicate + { + private final Map _entries = new HashMap<>(); + + @Override + public boolean test(String name) + { + return _entries.containsKey(name); + } + + @Override + public Iterator iterator() + { + return _entries.values().iterator(); + } + + @Override + public int size() + { + return _entries.size(); + } + + @Override + public boolean add(Entry entry) + { + if (!(entry instanceof ClassEntry)) + throw new IllegalArgumentException(entry.toString()); + return _entries.put(entry.getName(), entry) == null; + } + + @Override + public boolean remove(Object entry) + { + if (!(entry instanceof Entry)) + return false; + + return _entries.remove(((Entry)entry).getName()) != null; + } + } + + public static class ByPackageOrName extends AbstractSet implements Predicate + { + private final ByClass _byClass = new ByClass(); + private final ByPackage _byPackage = new ByPackage(); + + @Override + public boolean test(String name) + { + return _byPackage.test(name) || _byClass.test(name); + } + + @Override + public Iterator iterator() + { + // by package contains all entries (classes are also $ packages). + return _byPackage.iterator(); + } + + @Override + public int size() + { + return _byPackage.size(); + } + + @Override + public boolean add(Entry entry) + { + if (entry instanceof PackageEntry) + return _byPackage.add(entry); + + if (entry instanceof ClassEntry) + { + // Add class name to packages also as classes act + // as packages for nested classes. + boolean added = _byPackage.add(entry); + added = _byClass.add(entry) || added; + return added; + } + + throw new IllegalArgumentException(); + } + + @Override + public boolean remove(Object o) + { + if (!(o instanceof Entry)) + return false; + + boolean removedPackage = _byPackage.remove(o); + boolean removedClass = _byClass.remove(o); + + return removedPackage || removedClass; + } + + @Override + public void clear() + { + _byPackage.clear(); + _byClass.clear(); + } + } + + public static class ByLocation extends HashSet implements Predicate + { + @Override + public boolean test(URI uri) + { + if ((uri == null) || (!uri.isAbsolute())) + return false; + if (!uri.getScheme().equals("file")) + return false; + Path path = Paths.get(uri); + + for (Entry entry : this) + { + if (!(entry instanceof LocationEntry)) + throw new IllegalStateException(); + + Path entryPath = ((LocationEntry)entry).getPath(); + + if (Files.isDirectory(entryPath)) + { + if (path.startsWith(entryPath)) + { + return true; + } + } + else + { + try + { + if (Files.isSameFile(path, entryPath)) + { + return true; + } + } + catch (IOException ignore) + { + // this means there is a FileSystem issue preventing comparison. + // Use old technique + if (path.equals(entryPath)) + { + return true; + } + } + } + } + return false; + } + } + + public static class ByModule extends HashSet implements Predicate + { + private final Index.Mutable _entries = new Index.Builder() + .caseSensitive(true) + .mutable() + .build(); + + @Override + public boolean test(URI uri) + { + if ((uri == null) || (!uri.isAbsolute())) + return false; + if (!uri.getScheme().equalsIgnoreCase("jrt")) + return false; + String module = uri.getPath(); + int end = module.indexOf('/', 1); + if (end < 1) + end = module.length(); + return _entries.get(module, 1, end - 1) != null; + } + + @Override + public Iterator iterator() + { + return _entries.keySet().stream().map(_entries::get).iterator(); + } + + @Override + public int size() + { + return _entries.size(); + } + + @Override + public boolean add(Entry entry) + { + if (!(entry instanceof ModuleEntry)) + throw new IllegalArgumentException(entry.toString()); + String module = ((ModuleEntry)entry).getModule(); + + if (_entries.get(module) != null) + return false; + _entries.put(module, entry); + return true; + } + + @Override + public boolean remove(Object entry) + { + if (!(entry instanceof Entry)) + return false; + + return _entries.remove(((Entry)entry).getName()) != null; + } + } + + public static class ByLocationOrModule extends AbstractSet implements Predicate + { + private final ByLocation _byLocation = new ByLocation(); + private final ByModule _byModule = new ByModule(); + + @Override + public boolean test(URI name) + { + if ((name == null) || (!name.isAbsolute())) + return false; + return _byLocation.test(name) || _byModule.test(name); + } + + @Override + public Iterator iterator() + { + Set entries = new HashSet<>(); + entries.addAll(_byLocation); + entries.addAll(_byModule); + return entries.iterator(); + } + + @Override + public int size() + { + return _byLocation.size() + _byModule.size(); + } + + @Override + public boolean add(Entry entry) + { + if (entry instanceof LocationEntry) + return _byLocation.add(entry); + if (entry instanceof ModuleEntry) + return _byModule.add(entry); + + throw new IllegalArgumentException(entry.toString()); + } + + @Override + public boolean remove(Object o) + { + if (o instanceof LocationEntry) + return _byLocation.remove(o); + if (o instanceof ModuleEntry) + return _byModule.remove(o); + return false; + } + + @Override + public void clear() + { + _byLocation.clear(); + _byModule.clear(); + } + } + + protected final Map _entries; + protected final IncludeExcludeSet _patterns; + protected final IncludeExcludeSet _locations; + + protected ClassMatcher(Map entries, IncludeExcludeSet patterns, IncludeExcludeSet locations) + { + _entries = entries; + _patterns = patterns == null ? new IncludeExcludeSet<>(ByPackageOrName.class) : patterns; + _locations = locations == null ? new IncludeExcludeSet<>(ByLocationOrModule.class) : locations; + } + + private ClassMatcher(Map entries) + { + this(entries, null, null); + } + + public ClassMatcher() + { + this(new HashMap<>()); + } + + public ClassMatcher(ClassMatcher patterns) + { + this(new HashMap<>()); + if (patterns != null) + setAll(patterns.getPatterns()); + } + + public ClassMatcher(String... patterns) + { + this(new HashMap<>()); + if (patterns != null && patterns.length > 0) + setAll(patterns); + } + + public ClassMatcher(String pattern) + { + this(new HashMap<>()); + add(pattern); + } + + public ClassMatcher asImmutable() + { + return new ClassMatcher(Map.copyOf(_entries), + _patterns.asImmutable(), + _locations.asImmutable()); + } + + public boolean include(String name) + { + if (name == null) + return false; + return add(newEntry(name, true)); + } + + public boolean include(String... name) + { + boolean added = false; + for (String n : name) + { + if (n != null) + added = add(newEntry(n, true)) || added; + } + return added; + } + + public boolean exclude(String name) + { + if (name == null) + return false; + return add(newEntry(name, false)); + } + + public boolean exclude(String... name) + { + boolean added = false; + for (String n : name) + { + if (n != null) + added = add(newEntry(n, false)) || added; + } + return added; + } + + @Override + public boolean add(String pattern) + { + if (pattern == null) + return false; + return add(newEntry(pattern)); + } + + public boolean add(String... pattern) + { + boolean added = false; + for (String p : pattern) + { + if (p != null) + added = add(newEntry(p)) || added; + } + return added; + } + + protected boolean add(Entry entry) + { + if (_entries.containsKey(entry.getPattern())) + return false; + _entries.put(entry.getPattern(), entry); + + if (entry instanceof LocationEntry || entry instanceof ModuleEntry) + { + if (entry.isInclusive()) + _locations.include(entry); + else + _locations.exclude(entry); + } + else + { + if (entry.isInclusive()) + _patterns.include(entry); + else + _patterns.exclude(entry); + } + return true; + } + + protected Entry newEntry(String pattern) + { + if (pattern.startsWith("-")) + return newEntry(pattern.substring(1), false); + return newEntry(pattern, true); + } + + protected Entry newEntry(String name, boolean inclusive) + { + if (name.startsWith("-")) + throw new IllegalStateException(name); + if (name.startsWith("file:")) + return new LocationEntry(name, inclusive); + if (name.startsWith("jrt:")) + return new ModuleEntry(name, inclusive); + if (name.endsWith(".")) + return new PackageEntry(name, inclusive); + return new ClassEntry(name, inclusive); + } + + @Override + public boolean remove(Object o) + { + if (!(o instanceof String pattern)) + return false; + + Entry entry = _entries.remove(pattern); + if (entry == null) + return false; + + List saved = new ArrayList<>(_entries.values()); + clear(); + for (Entry e : saved) + { + add(e); + } + return true; + } + + @Override + public void clear() + { + _entries.clear(); + _patterns.clear(); + _locations.clear(); + } + + @Override + public Iterator iterator() + { + return _entries.keySet().iterator(); + } + + @Override + public int size() + { + return _entries.size(); + } + + /** + * Initialize the matcher by parsing each classpath pattern in an array + * + * @param classes array of classpath patterns + */ + private void setAll(String[] classes) + { + _entries.clear(); + addAll(classes); + } + + /** + * Add array of classpath patterns. + * @param classes array of classpath patterns + */ + private void addAll(String[] classes) + { + if (classes != null) + addAll(Arrays.asList(classes)); + } + + /** + * @return array of classpath patterns + */ + public String[] getPatterns() + { + return toArray(new String[0]); + } + + /** + * @return array of inclusive classpath patterns + */ + public String[] getInclusions() + { + return _entries.values().stream().filter(Entry::isInclusive).map(Entry::getName).toArray(String[]::new); + } + + /** + * @return array of excluded classpath patterns (without '-' prefix) + */ + public String[] getExclusions() + { + return _entries.values().stream().filter(e -> !e.isInclusive()).map(Entry::getName).toArray(String[]::new); + } + + /** + * Match the class name against the pattern + * + * @param name name of the class to match + * @return true if class matches the pattern + */ + public boolean match(String name) + { + return _patterns.test(name); + } + + /** + * Match the class name against the pattern + * + * @param clazz A class to try to match + * @return true if class matches the pattern + */ + public boolean match(Class clazz) + { + try + { + return combine(_patterns, clazz.getName(), _locations, () -> TypeUtil.getLocationOfClass(clazz)); + } + catch (Exception ignored) + { + } + return false; + } + + public boolean match(String name, URL url) + { + if (url == null) + return false; + + // Strip class suffix for name matching + if (name.endsWith(".class")) + name = name.substring(0, name.length() - 6); + + // Treat path elements as packages for name matching + name = StringUtil.replace(name, '/', '.'); + + return combine(_patterns, name, _locations, () -> + { + try + { + return URIUtil.unwrapContainer(url.toURI()); + } + catch (URISyntaxException ignored) + { + return null; + } + }); + } + + /** + * Match a class against inclusions and exclusions by name and location. + * Name based checks are performed before location checks. For a class to match, + * it must not be excluded by either name or location, and must either be explicitly + * included, or for there to be no inclusions. In the case where the location + * of the class is null, it will match if it is included by name, or + * if there are no location exclusions. + * + * @param names configured inclusions and exclusions by name + * @param name the name to check + * @param locations configured inclusions and exclusions by location + * @param location the location of the class (can be null) + * @return true if the class is not excluded but is included, or there are + * no inclusions. False otherwise. + */ + static boolean combine(IncludeExcludeSet names, String name, IncludeExcludeSet locations, Supplier location) + { + // check the name set + Boolean byName = names.isIncludedAndNotExcluded(name); + + // If we excluded by name, then no match + if (Boolean.FALSE == byName) + return false; + + // check the location set + URI uri = location.get(); + Boolean byLocation = uri == null ? null : locations.isIncludedAndNotExcluded(uri); + + // If we excluded by location or couldn't check location exclusion, then no match + if (Boolean.FALSE == byLocation || (locations.hasExcludes() && uri == null)) + return false; + + // If there are includes, then we must be included to match. + if (names.hasIncludes() || locations.hasIncludes()) + return byName == Boolean.TRUE || byLocation == Boolean.TRUE; + + // Otherwise there are no includes and it was not excluded, so match + return true; + } +} diff --git a/jetty-core/jetty-util/src/main/java/org/eclipse/jetty/util/ClassVisibilityChecker.java b/jetty-core/jetty-util/src/main/java/org/eclipse/jetty/util/ClassVisibilityChecker.java index 3167d9b82d35..12bfaec2322f 100644 --- a/jetty-core/jetty-util/src/main/java/org/eclipse/jetty/util/ClassVisibilityChecker.java +++ b/jetty-core/jetty-util/src/main/java/org/eclipse/jetty/util/ClassVisibilityChecker.java @@ -14,13 +14,33 @@ package org.eclipse.jetty.util; /** - * ClassVisibilityChecker - * * Interface to be implemented by classes capable of checking class visibility * for a context. */ public interface ClassVisibilityChecker { + /** + * Is the class a Protected (System) Class. + * A System class is a class that is visible to a webapplication, + * but that cannot be overridden by the contents of WEB-INF/lib or + * WEB-INF/classes + * + * @param clazz The fully qualified name of the class. + * @return True if the class is a system class. + */ + boolean isProtectedClass(Class clazz); + + /** + * Is the class a Hidden (Server) Class. + * A Server class is a class that is part of the implementation of + * the server and is NIT visible to a webapplication. The web + * application may provide it's own implementation of the class, + * to be loaded from WEB-INF/lib or WEB-INF/classes + * + * @param clazz The fully qualified name of the class. + * @return True if the class is a server class. + */ + boolean isHiddenClass(Class clazz); /** * Is the class a System Class. @@ -30,8 +50,13 @@ public interface ClassVisibilityChecker * * @param clazz The fully qualified name of the class. * @return True if the class is a system class. + * @deprecated use {@link #isProtectedClass(Class)} */ - boolean isSystemClass(Class clazz); + @Deprecated (forRemoval = true, since = "12.0.9") + default boolean isSystemClass(Class clazz) + { + return isProtectedClass(clazz); + } /** * Is the class a Server Class. @@ -42,6 +67,11 @@ public interface ClassVisibilityChecker * * @param clazz The fully qualified name of the class. * @return True if the class is a server class. + * @deprecated use {@link #isHiddenClass(Class)} */ - boolean isServerClass(Class clazz); + @Deprecated (forRemoval = true, since = "12.0.9") + default boolean isServerClass(Class clazz) + { + return isHiddenClass(clazz); + } } diff --git a/jetty-ee10/jetty-ee10-webapp/src/test/java/org/eclipse/jetty/ee10/webapp/ClassMatcherTest.java b/jetty-core/jetty-util/src/test/java/org/eclipse/jetty/util/ClassMatcherTest.java similarity index 97% rename from jetty-ee10/jetty-ee10-webapp/src/test/java/org/eclipse/jetty/ee10/webapp/ClassMatcherTest.java rename to jetty-core/jetty-util/src/test/java/org/eclipse/jetty/util/ClassMatcherTest.java index 069b4df78ab8..e29c994f0112 100644 --- a/jetty-ee10/jetty-ee10-webapp/src/test/java/org/eclipse/jetty/ee10/webapp/ClassMatcherTest.java +++ b/jetty-core/jetty-util/src/test/java/org/eclipse/jetty/util/ClassMatcherTest.java @@ -11,17 +11,15 @@ // ======================================================================== // -package org.eclipse.jetty.ee10.webapp; +package org.eclipse.jetty.util; import java.net.URI; import java.util.Arrays; import java.util.function.Supplier; -import org.eclipse.jetty.ee10.webapp.ClassMatcher.ByLocationOrModule; -import org.eclipse.jetty.ee10.webapp.ClassMatcher.ByPackageOrName; -import org.eclipse.jetty.ee10.webapp.ClassMatcher.Entry; -import org.eclipse.jetty.util.IncludeExcludeSet; -import org.eclipse.jetty.util.TypeUtil; +import org.eclipse.jetty.util.ClassMatcher.ByLocationOrModule; +import org.eclipse.jetty.util.ClassMatcher.ByPackageOrName; +import org.eclipse.jetty.util.ClassMatcher.Entry; import org.hamcrest.Matchers; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; diff --git a/jetty-core/pom.xml b/jetty-core/pom.xml index 7790a54c5e83..97f9ff5401c3 100644 --- a/jetty-core/pom.xml +++ b/jetty-core/pom.xml @@ -17,6 +17,7 @@ jetty-client jetty-demos jetty-deploy + jetty-ee jetty-fcgi jetty-http jetty-http-spi diff --git a/jetty-ee10/jetty-ee10-annotations/src/main/java/org/eclipse/jetty/ee10/annotations/ResourceAnnotationHandler.java b/jetty-ee10/jetty-ee10-annotations/src/main/java/org/eclipse/jetty/ee10/annotations/ResourceAnnotationHandler.java index ca442da47c1d..78cebbd08bac 100644 --- a/jetty-ee10/jetty-ee10-annotations/src/main/java/org/eclipse/jetty/ee10/annotations/ResourceAnnotationHandler.java +++ b/jetty-ee10/jetty-ee10-annotations/src/main/java/org/eclipse/jetty/ee10/annotations/ResourceAnnotationHandler.java @@ -158,7 +158,7 @@ public void handleField(Class clazz, Field field) //try environment scope next if (!bound) - bound = NamingEntryUtil.bindToENC(ServletContextHandler.__environment.getName(), name, mappedName); + bound = NamingEntryUtil.bindToENC(ServletContextHandler.ENVIRONMENT.getName(), name, mappedName); //try Server scope next if (!bound) @@ -313,7 +313,7 @@ public void handleMethod(Class clazz, Method method) //try the environment's scope if (!bound) - bound = NamingEntryUtil.bindToENC(ServletContextHandler.__environment.getName(), name, mappedName); + bound = NamingEntryUtil.bindToENC(ServletContextHandler.ENVIRONMENT.getName(), name, mappedName); //try the server's scope if (!bound) diff --git a/jetty-ee10/jetty-ee10-demos/jetty-ee10-demo-jetty-webapp/src/main/webapp/WEB-INF/jetty-web.xml b/jetty-ee10/jetty-ee10-demos/jetty-ee10-demo-jetty-webapp/src/main/webapp/WEB-INF/jetty-web.xml index 94c1864b1c35..5a92efcbfaf9 100644 --- a/jetty-ee10/jetty-ee10-demos/jetty-ee10-demo-jetty-webapp/src/main/webapp/WEB-INF/jetty-web.xml +++ b/jetty-ee10/jetty-ee10-demos/jetty-ee10-demo-jetty-webapp/src/main/webapp/WEB-INF/jetty-web.xml @@ -9,13 +9,13 @@ org.eclipse.jetty.ee10.servlet.WebApplicationContext object --> - + - org.eclipse.jetty.util. - org.eclipse.jetty.ee10.servlets. - + org.eclipse.jetty.util. + org.eclipse.jetty.ee10.servlets. + diff --git a/jetty-ee10/jetty-ee10-demos/jetty-ee10-demo-proxy-webapp/src/test/java/org/eclipse/jetty/ee10/demos/ProxyWebAppTest.java b/jetty-ee10/jetty-ee10-demos/jetty-ee10-demo-proxy-webapp/src/test/java/org/eclipse/jetty/ee10/demos/ProxyWebAppTest.java index 63562373118a..79390bd4e4b0 100644 --- a/jetty-ee10/jetty-ee10-demos/jetty-ee10-demo-proxy-webapp/src/test/java/org/eclipse/jetty/ee10/demos/ProxyWebAppTest.java +++ b/jetty-ee10/jetty-ee10-demos/jetty-ee10-demo-proxy-webapp/src/test/java/org/eclipse/jetty/ee10/demos/ProxyWebAppTest.java @@ -54,7 +54,7 @@ public void setup() throws Exception // This is a pieced together WebApp. // We don't have a valid WEB-INF/lib to rely on at this point. // So, open up server classes here, for purposes of this testcase. - webapp.getServerClassMatcher().add("-org.eclipse.jetty.ee10.proxy."); + webapp.getHiddenClassMatcher().add("-org.eclipse.jetty.ee10.proxy."); webapp.setWar(MavenTestingUtils.getProjectDirPath("src/main/webapp").toString()); webapp.setExtraClasspath(MavenTestingUtils.getTargetPath().resolve("test-classes").toString()); server.setHandler(webapp); diff --git a/jetty-ee10/jetty-ee10-maven-plugin/src/it/jetty-cdi-start-forked/src/main/jetty/jetty-context.xml b/jetty-ee10/jetty-ee10-maven-plugin/src/it/jetty-cdi-start-forked/src/main/jetty/jetty-context.xml index effcf47f4cf7..9214a93f9c36 100644 --- a/jetty-ee10/jetty-ee10-maven-plugin/src/it/jetty-cdi-start-forked/src/main/jetty/jetty-context.xml +++ b/jetty-ee10/jetty-ee10-maven-plugin/src/it/jetty-cdi-start-forked/src/main/jetty/jetty-context.xml @@ -6,7 +6,7 @@ - + -org.eclipse.jetty.util.Decorator diff --git a/jetty-ee10/jetty-ee10-osgi/test-jetty-ee10-osgi/src/test/java/org/eclipse/jetty/ee10/osgi/test/TestOSGiUtil.java b/jetty-ee10/jetty-ee10-osgi/test-jetty-ee10-osgi/src/test/java/org/eclipse/jetty/ee10/osgi/test/TestOSGiUtil.java index ba27aba40888..971e14827bc3 100644 --- a/jetty-ee10/jetty-ee10-osgi/test-jetty-ee10-osgi/src/test/java/org/eclipse/jetty/ee10/osgi/test/TestOSGiUtil.java +++ b/jetty-ee10/jetty-ee10-osgi/test-jetty-ee10-osgi/src/test/java/org/eclipse/jetty/ee10/osgi/test/TestOSGiUtil.java @@ -234,6 +234,7 @@ public static void coreJettyDependencies(List