diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/SelectorManager.java b/jetty-io/src/main/java/org/eclipse/jetty/io/SelectorManager.java index e99114fa18b..b507e614b77 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/SelectorManager.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/SelectorManager.java @@ -61,11 +61,11 @@ public abstract class SelectorManager extends ContainerLifeCycle implements Dump private long _selectorIndex; private int _reservedThreads = -1; - public static int defaultSchedulers(Executor executor) + private static int defaultSelectors(Executor executor) { - if (executor instanceof ThreadPool) + if (executor instanceof ThreadPool.SizedThreadPool) { - int threads = ((ThreadPool)executor).getThreads(); + int threads = ((ThreadPool.SizedThreadPool)executor).getMaxThreads(); int cpus = Runtime.getRuntime().availableProcessors(); return Math.max(1,Math.min(cpus/2,threads/16)); } @@ -87,7 +87,7 @@ public abstract class SelectorManager extends ContainerLifeCycle implements Dump protected SelectorManager(Executor executor, Scheduler scheduler, int selectors) { if (selectors <= 0) - selectors = defaultSchedulers(executor); + selectors = defaultSelectors(executor); this.executor = executor; this.scheduler = scheduler; _selectors = new ManagedSelector[selectors]; diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpServerTestBase.java b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpServerTestBase.java index 67ddd847f7b..41e85d2260a 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpServerTestBase.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpServerTestBase.java @@ -357,7 +357,7 @@ public abstract class HttpServerTestBase extends HttpServerTestFixture try (Socket client = newSocket(_serverURI.getHost(), _serverURI.getPort()); StacklessLogging stackless = new StacklessLogging(HttpConnection.class)) { - Log.getLogger(HttpConnection.class).info("expect header is too large, then ISE extra data ..."); + Log.getLogger(HttpConnection.class).info("expect header is too large ..."); OutputStream os = client.getOutputStream(); byte[] buffer = new byte[64 * 1024]; @@ -379,9 +379,16 @@ public abstract class HttpServerTestBase extends HttpServerTestFixture buffer[15]='H'; buffer[16]=':'; Arrays.fill(buffer,17,buffer.length-1,(byte)'A'); - - os.write(buffer); - os.flush(); + // write the request. + try + { + os.write(buffer); + os.flush(); + } + catch(Exception e) + { + // Ignore exceptions during writing, so long as we can read response below + } // Read the response. try @@ -391,7 +398,8 @@ public abstract class HttpServerTestBase extends HttpServerTestFixture } catch(Exception e) { - // TODO evaluate why we sometimes get an early close on this test + Log.getLogger(HttpServerTestBase.class).warn("TODO Early close???"); + // TODO #1832 evaluate why we sometimes get an early close on this test } } } diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SelectChannelServerSslTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SelectChannelServerSslTest.java index 0a70ac21cb3..7662b192830 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SelectChannelServerSslTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SelectChannelServerSslTest.java @@ -40,6 +40,7 @@ import java.util.regex.Pattern; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLException; import javax.net.ssl.SSLSession; import javax.net.ssl.TrustManagerFactory; import javax.servlet.ServletException; @@ -118,14 +119,7 @@ public class SelectChannelServerSslTest extends HttpServerTestBase @Override public void testFullHeader() throws Exception { - try - { - super.testFullHeader(); - } - catch (SocketException e) - { - Log.getLogger(SslConnection.class).warn("Close overtook 400 response"); - } + super.testFullHeader(); } @Before @@ -167,7 +161,6 @@ public class SelectChannelServerSslTest extends HttpServerTestBase } catch(Exception e) { - e.printStackTrace(); throw new RuntimeException(e); } } diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHolder.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHolder.java index 3c0ce02fdab..9772abd28c9 100644 --- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHolder.java +++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHolder.java @@ -400,9 +400,11 @@ public class ServletHolder extends Holder implements UserIdentity.Scope _config=new Config(); - if (_class!=null && javax.servlet.SingleThreadModel.class.isAssignableFrom(_class)) - _servlet = new SingleThreadedWrapper(); - + synchronized (this) + { + if (_class!=null && javax.servlet.SingleThreadModel.class.isAssignableFrom(_class)) + _servlet = new SingleThreadedWrapper(); + } } @@ -485,18 +487,38 @@ public class ServletHolder extends Holder implements UserIdentity.Scope public synchronized Servlet getServlet() throws ServletException { - // Handle previous unavailability - if (_unavailable!=0) - { - if (_unavailable<0 || _unavailable>0 && System.currentTimeMillis()<_unavailable) - throw _unavailableEx; - _unavailable=0; - _unavailableEx=null; - } + Servlet servlet=_servlet; + if (servlet!=null && _unavailable==0) + return servlet; - if (_servlet==null) - initServlet(); - return _servlet; + synchronized(this) + { + // Handle previous unavailability + if (_unavailable!=0) + { + if (_unavailable<0 || _unavailable>0 && System.currentTimeMillis()<_unavailable) + throw _unavailableEx; + _unavailable=0; + _unavailableEx=null; + } + + servlet=_servlet; + if (servlet!=null) + return servlet; + + if (isRunning()) + { + if (_class == null) + throw new UnavailableException("Servlet Not Initialized"); + if (_unavailable != 0 || !_initOnStartup) + initServlet(); + servlet=_servlet; + if (servlet == null) + throw new UnavailableException("Could not instantiate " + _class); + } + + return servlet; + } } /* ------------------------------------------------------------ */ @@ -505,7 +527,13 @@ public class ServletHolder extends Holder implements UserIdentity.Scope */ public Servlet getServletInstance() { - return _servlet; + Servlet servlet=_servlet; + if (servlet!=null) + return servlet; + synchronized(this) + { + return _servlet; + } } /* ------------------------------------------------------------ */ @@ -604,7 +632,7 @@ public class ServletHolder extends Holder implements UserIdentity.Scope } /* ------------------------------------------------------------ */ - private void initServlet() + private synchronized void initServlet() throws ServletException { Object old_run_as = null; @@ -767,36 +795,17 @@ public class ServletHolder extends Holder implements UserIdentity.Scope protected void prepare (Request baseRequest, ServletRequest request, ServletResponse response) throws ServletException, UnavailableException { - ensureInstance(); + getServlet(); MultipartConfigElement mpce = ((Registration)getRegistration()).getMultipartConfig(); if (mpce != null) baseRequest.setAttribute(Request.__MULTIPART_CONFIG_ELEMENT, mpce); } + @Deprecated public Servlet ensureInstance() - throws ServletException, UnavailableException + throws ServletException, UnavailableException { - if (!isStarted()) - throw new UnavailableException("Servlet not initialized", -1); - - Servlet servlet=_servlet; - if (servlet!=null && _unavailable==0) - return servlet; - - synchronized(this) - { - servlet=_servlet; - if (servlet!=null) - return servlet; - if (_class == null) - throw new UnavailableException("Servlet Not Initialized"); - if (_unavailable != 0 || (!_initOnStartup && servlet == null)) - servlet = getServlet(); - if (servlet == null) - throw new UnavailableException("Could not instantiate " + _class); - - return servlet; - } + return getServlet(); } /* ------------------------------------------------------------ */ @@ -820,7 +829,7 @@ public class ServletHolder extends Holder implements UserIdentity.Scope if (_class==null) throw new UnavailableException("Servlet Not Initialized"); - Servlet servlet = ensureInstance(); + Servlet servlet = getServlet(); // Service the request Object old_run_as = null; @@ -865,26 +874,23 @@ public class ServletHolder extends Holder implements UserIdentity.Scope /* ------------------------------------------------------------ */ - private boolean isJspServlet () + protected boolean isJspServlet () { - if (_servlet == null) - return false; + Servlet servlet = getServletInstance(); + Class c = servlet==null?_class:servlet.getClass(); - Class c = _servlet.getClass(); - - boolean result = false; - while (c != null && !result) + while (c != null) { - result = isJspServlet(c.getName()); + if (isJspServlet(c.getName())) + return true; c = c.getSuperclass(); } - - return result; + return false; } /* ------------------------------------------------------------ */ - private boolean isJspServlet (String classname) + protected boolean isJspServlet (String classname) { if (classname == null) return false; diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/Resource.java b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/Resource.java index fc604a4adf0..5908571fb06 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/Resource.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/Resource.java @@ -447,8 +447,8 @@ public abstract class Resource implements ResourceFactory, Closeable /* ------------------------------------------------------------ */ /** * list of resource names contained in the given resource. - * - * @return a list of resource names contained in the given resource. + * Ordering is unspecified, so callers may wish to sort the return value to ensure deterministic behavior. + * @return a list of resource names contained in the given resource, or null. * Note: The resource names are not URL encoded. */ public abstract String[] list(); diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppClassLoader.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppClassLoader.java index 46bbc6e86c2..7b14d3a6ac8 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppClassLoader.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppClassLoader.java @@ -29,6 +29,7 @@ import java.security.CodeSource; import java.security.PermissionCollection; import java.security.PrivilegedExceptionAction; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.Enumeration; import java.util.HashSet; @@ -328,6 +329,10 @@ public class WebAppClassLoader extends URLClassLoader if (lib.exists() && lib.isDirectory()) { String[] files=lib.list(); + if (files != null) + { + Arrays.sort(files); + } for (int f=0;files!=null && f resources = _loader.getResources("org/acme/clashing.txt"); + assertTrue(resources.hasMoreElements()); + URL resource = resources.nextElement(); + try (InputStream data = resource.openStream()) + { + assertEquals("correct contents of " + resource, "alpha", IO.toString(data)); + } + assertTrue(resources.hasMoreElements()); + resource = resources.nextElement(); + try (InputStream data = resource.openStream()) + { + assertEquals("correct contents of " + resource, "omega", IO.toString(data)); + } + assertFalse(resources.hasMoreElements()); + } + } diff --git a/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebAppContextTest.java b/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebAppContextTest.java index b8841a4b015..d2c9dde505d 100644 --- a/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebAppContextTest.java +++ b/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebAppContextTest.java @@ -23,9 +23,11 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertEquals; import java.io.File; import java.io.IOException; +import java.nio.file.Path; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -46,6 +48,8 @@ import org.eclipse.jetty.server.handler.HandlerList; import org.eclipse.jetty.server.handler.HotSwapHandler; import org.eclipse.jetty.servlet.ErrorPageErrorHandler; import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.toolchain.test.MavenTestingUtils; +import org.eclipse.jetty.util.resource.PathResource; import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.util.resource.ResourceCollection; import org.hamcrest.Matchers; @@ -369,4 +373,19 @@ public class WebAppContextTest server.stop(); } + + @Test + public void ordering() throws Exception + { + Path testWebappDir = MavenTestingUtils.getProjectDirPath("src/test/webapp"); + Resource webapp = new PathResource(testWebappDir); + WebAppContext context = new WebAppContext(); + context.setBaseResource(webapp); + context.setContextPath("/test"); + context.setServer(new Server()); + new MetaInfConfiguration().preConfigure(context); + assertEquals(Arrays.asList("acme.jar", "alpha.jar", "omega.jar"), + context.getMetaData().getWebInfJars().stream().map(r -> r.getURI().toString().replaceFirst(".+/", "")).collect(Collectors.toList())); + } + } diff --git a/jetty-webapp/src/test/webapp/WEB-INF/lib/alpha.jar b/jetty-webapp/src/test/webapp/WEB-INF/lib/alpha.jar new file mode 100644 index 00000000000..a26fb083a56 Binary files /dev/null and b/jetty-webapp/src/test/webapp/WEB-INF/lib/alpha.jar differ diff --git a/jetty-webapp/src/test/webapp/WEB-INF/lib/omega.jar b/jetty-webapp/src/test/webapp/WEB-INF/lib/omega.jar new file mode 100644 index 00000000000..b72fa753024 Binary files /dev/null and b/jetty-webapp/src/test/webapp/WEB-INF/lib/omega.jar differ