diff --git a/jetty-ant/src/main/java/org/eclipse/jetty/ant/AntWebAppContext.java b/jetty-ant/src/main/java/org/eclipse/jetty/ant/AntWebAppContext.java index 47ecd5bc0ea..e00479020ff 100644 --- a/jetty-ant/src/main/java/org/eclipse/jetty/ant/AntWebAppContext.java +++ b/jetty-ant/src/main/java/org/eclipse/jetty/ant/AntWebAppContext.java @@ -30,6 +30,7 @@ import java.security.CodeSource; import java.security.PermissionCollection; import java.util.ArrayList; import java.util.Enumeration; +import java.util.EventListener; import java.util.HashSet; import java.util.Iterator; import java.util.List; @@ -50,9 +51,12 @@ import org.eclipse.jetty.ant.utils.TaskLog; import org.eclipse.jetty.plus.webapp.EnvConfiguration; import org.eclipse.jetty.plus.webapp.PlusConfiguration; import org.eclipse.jetty.server.handler.ContextHandler; +import org.eclipse.jetty.servlet.FilterHolder; +import org.eclipse.jetty.servlet.FilterMapping; import org.eclipse.jetty.servlet.Holder; import org.eclipse.jetty.servlet.ServletHandler; import org.eclipse.jetty.servlet.ServletHolder; +import org.eclipse.jetty.servlet.ServletMapping; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.resource.Resource; @@ -676,6 +680,13 @@ public class AntWebAppContext extends WebAppContext TaskLog.logWithTimestamp("Stopping web application "+this); Thread.currentThread().sleep(500L); super.doStop(); + //remove all filters, servlets and listeners. They will be recreated + //either via application of a context xml file or web.xml or annotation or servlet api + setEventListeners(new EventListener[0]); + getServletHandler().setFilters(new FilterHolder[0]); + getServletHandler().setFilterMappings(new FilterMapping[0]); + getServletHandler().setServlets(new ServletHolder[0]); + getServletHandler().setServletMappings(new ServletMapping[0]); } catch (InterruptedException e) { diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyWebAppContext.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyWebAppContext.java index 83df67c4def..0489a2d875f 100644 --- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyWebAppContext.java +++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyWebAppContext.java @@ -22,6 +22,7 @@ import java.io.File; import java.io.IOException; import java.net.MalformedURLException; import java.util.ArrayList; +import java.util.EventListener; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -29,6 +30,10 @@ import java.util.Set; import java.util.TreeSet; import org.eclipse.jetty.plus.webapp.EnvConfiguration; +import org.eclipse.jetty.servlet.FilterHolder; +import org.eclipse.jetty.servlet.FilterMapping; +import org.eclipse.jetty.servlet.ServletHolder; +import org.eclipse.jetty.servlet.ServletMapping; import org.eclipse.jetty.util.URIUtil; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -296,6 +301,14 @@ public class JettyWebAppContext extends WebAppContext //just wait a little while to ensure no requests are still being processed Thread.currentThread().sleep(500L); super.doStop(); + + //remove all listeners, servlets and filters. This is because we will re-apply + //any context xml file, which means they would potentially be added multiple times. + setEventListeners(new EventListener[0]); + getServletHandler().setFilters(new FilterHolder[0]); + getServletHandler().setFilterMappings(new FilterMapping[0]); + getServletHandler().setServlets(new ServletHolder[0]); + getServletHandler().setServletMappings(new ServletMapping[0]); } @Override diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java index 918eb5bb470..f1f2d6f4af9 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java @@ -169,6 +169,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu private final List _contextAttributeListeners=new CopyOnWriteArrayList<>(); private final List _requestListeners=new CopyOnWriteArrayList<>(); private final List _requestAttributeListeners=new CopyOnWriteArrayList<>(); + private final List _durableListeners = new CopyOnWriteArrayList<>(); private Map _managedAttributes; private String[] _protectedTargets; private final CopyOnWriteArrayList _aliasChecks = new CopyOnWriteArrayList(); @@ -567,6 +568,9 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu { _eventListeners.add(listener); + if (!(isStarted() || isStarting())) + _durableListeners.add(listener); + if (listener instanceof ServletContextListener) _contextListeners.add((ServletContextListener)listener); @@ -623,6 +627,8 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu return _programmaticListeners.contains(listener); } + + /* ------------------------------------------------------------ */ /** * @return true if this context is accepting new requests @@ -821,6 +827,10 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu for (int i = _contextListeners.size(); i-->0;) callContextDestroyed(_contextListeners.get(i),event); } + + //retain only durable listeners + setEventListeners(_durableListeners.toArray(new EventListener[_durableListeners.size()])); + _durableListeners.clear(); if (_errorHandler != null) _errorHandler.stop(); @@ -1821,8 +1831,6 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu query = uriInContext.substring(q + 1); uriInContext = uriInContext.substring(0,q); } - // if ((q = uriInContext.indexOf(';')) > 0) - // uriInContext = uriInContext.substring(0,q); String pathInContext = URIUtil.canonicalPath(URIUtil.decodePath(uriInContext)); if (pathInContext!=null) diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletContextHandler.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletContextHandler.java index eae909e5168..7f7e79ffd79 100644 --- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletContextHandler.java +++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletContextHandler.java @@ -1022,8 +1022,6 @@ public class ServletContextHandler extends ContextHandler if (!_enabled) throw new UnsupportedOperationException(); - //TODO handle partial registrations - final ServletHandler handler = ServletContextHandler.this.getServletHandler(); ServletHolder holder = handler.getServlet(servletName); if (holder == null) diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHandler.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHandler.java index fe4f8bdbbf0..013d6ed7ebd 100644 --- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHandler.java +++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHandler.java @@ -21,10 +21,12 @@ package org.eclipse.jetty.servlet; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.EnumSet; import java.util.HashMap; import java.util.List; +import java.util.ListIterator; import java.util.Map; import java.util.Queue; import java.util.Set; @@ -187,30 +189,81 @@ public class ServletHandler extends ScopedHandler super.doStop(); // Stop filters + List filterHolders = new ArrayList(); + List filterMappings = ArrayUtil.asMutableList(_filterMappings); if (_filters!=null) { for (int i=_filters.length; i-->0;) { try { _filters[i].stop(); }catch(Exception e){LOG.warn(Log.EXCEPTION,e);} + if (_filters[i].getSource() != Source.EMBEDDED) + { + //remove all of the mappings that were for non-embedded filters + _filterNameMap.remove(_filters[i].getName()); + //remove any mappings associated with this filter + ListIterator fmitor = filterMappings.listIterator(); + while (fmitor.hasNext()) + { + FilterMapping fm = fmitor.next(); + if (fm.getFilterName().equals(_filters[i].getName())) + fmitor.remove(); + } + } + else + filterHolders.add(_filters[i]); //only retain embedded } } + + //Retain only filters and mappings that were added using jetty api (ie Source.EMBEDDED) + FilterHolder[] fhs = (FilterHolder[]) LazyList.toArray(filterHolders, FilterHolder.class); + updateBeans(_filters, fhs); + _filters = fhs; + FilterMapping[] fms = (FilterMapping[]) LazyList.toArray(filterMappings, FilterMapping.class); + updateBeans(_filterMappings, fms); + _filterMappings = fms; + + _matchAfterIndex = (_filterMappings == null || _filterMappings.length == 0 ? -1 : _filterMappings.length-1); + _matchBeforeIndex = -1; // Stop servlets + List servletHolders = new ArrayList(); //will be remaining servlets + List servletMappings = ArrayUtil.asMutableList(_servletMappings); //will be remaining mappings if (_servlets!=null) { for (int i=_servlets.length; i-->0;) { try { _servlets[i].stop(); }catch(Exception e){LOG.warn(Log.EXCEPTION,e);} + + if (_servlets[i].getSource() != Source.EMBEDDED) + { + //remove from servlet name map + _servletNameMap.remove(_servlets[i].getName()); + //remove any mappings associated with this servlet + ListIterator smitor = servletMappings.listIterator(); + while (smitor.hasNext()) + { + ServletMapping sm = smitor.next(); + if (sm.getServletName().equals(_servlets[i].getName())) + smitor.remove(); + } + } + else + servletHolders.add(_servlets[i]); //only retain embedded } } + //Retain only Servlets and mappings added via jetty apis (ie Source.EMBEDDED) + ServletHolder[] shs = (ServletHolder[]) LazyList.toArray(servletHolders, ServletHolder.class); + updateBeans(_servlets, shs); + _servlets = shs; + ServletMapping[] sms = (ServletMapping[])LazyList.toArray(servletMappings, ServletMapping.class); + updateBeans(_servletMappings, sms); + _servletMappings = sms; + + //will be regenerated on next start _filterPathMappings=null; _filterNameMappings=null; - _servletPathMap=null; - - _matchBeforeIndex=-1; - _matchAfterIndex=-1; } /* ------------------------------------------------------------ */ @@ -786,7 +839,7 @@ public class ServletHandler extends ScopedHandler */ public ServletHolder addServletWithMapping (String className,String pathSpec) { - ServletHolder holder = newServletHolder(null); + ServletHolder holder = newServletHolder(Holder.Source.EMBEDDED); holder.setName(className+"-"+(_servlets==null?0:_servlets.length)); holder.setClassName(className); addServletWithMapping(holder,pathSpec); @@ -801,7 +854,6 @@ public class ServletHandler extends ScopedHandler { ServletHolder holder = newServletHolder(Holder.Source.EMBEDDED); holder.setHeldClass(servlet); - setServlets(ArrayUtil.addToArray(getServlets(), holder, ServletHolder.class)); addServletWithMapping(holder,pathSpec); return holder; @@ -969,7 +1021,7 @@ public class ServletHandler extends ScopedHandler */ public FilterHolder addFilterWithMapping (String className,String pathSpec,int dispatches) { - FilterHolder holder = newFilterHolder(null); + FilterHolder holder = newFilterHolder(Holder.Source.EMBEDDED); holder.setName(className+"-"+_filters.length); holder.setClassName(className); @@ -1116,7 +1168,7 @@ public class ServletHandler extends ScopedHandler { //programmatically defined filter mappings are prepended to mapping list in the order //in which they were defined. In other words, insert this mapping at the tail of the - //programmatically added filter mappings, BEFORE the first web.xml defined filter mapping. + //programmatically prepended filter mappings, BEFORE the first web.xml defined filter mapping. if (_matchBeforeIndex < 0) { @@ -1159,14 +1211,15 @@ public class ServletHandler extends ScopedHandler { if (pos < 0) throw new IllegalArgumentException("FilterMapping insertion pos < 0"); - FilterMapping[] mappings = getFilterMappings(); + if (mappings==null || mappings.length==0) { return new FilterMapping[] {mapping}; } FilterMapping[] new_mappings = new FilterMapping[mappings.length+1]; + if (before) { //copy existing filter mappings up to but not including the pos @@ -1375,6 +1428,7 @@ public class ServletHandler extends ScopedHandler if (holders!=null) for (ServletHolder holder:holders) holder.setServletHandler(this); + updateBeans(_servlets,holders); _servlets=holders; updateNameMappings(); diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DispatcherTest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DispatcherTest.java index 58971c923ea..df2aa5f7af5 100644 --- a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DispatcherTest.java +++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DispatcherTest.java @@ -226,7 +226,20 @@ public class DispatcherTest _contextHandler.addServlet(DispatchServletServlet.class, "/dispatch/*"); _contextHandler.addServlet(RogerThatServlet.class, "/roger/that"); - String requests="GET /context/dispatch/test?forward=%2e%2e/roger/that HTTP/1.0\n" + "Host: localhost\n\n"; + String requests="GET /context/dispatch/test?forward=/%2e%2e/roger/that HTTP/1.0\n" + "Host: localhost\n\n"; + + String responses = _connector.getResponses(requests); + + assertThat(responses,startsWith("HTTP/1.1 404 ")); + } + + @Test + public void testServletForwardEncodedDotDot() throws Exception + { + _contextHandler.addServlet(DispatchServletServlet.class, "/dispatch/*"); + _contextHandler.addServlet(RogerThatServlet.class, "/roger/that"); + + String requests="GET /context/dispatch/test?forward=/%252e%252e/roger/that HTTP/1.0\n" + "Host: localhost\n\n"; String responses = _connector.getResponses(requests); diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppContext.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppContext.java index 55cb294fef8..c52b7bc2066 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppContext.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppContext.java @@ -1080,6 +1080,7 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL } + /* ------------------------------------------------------------ */ /** * @param extractWAR True if war files are extracted diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebXmlConfiguration.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebXmlConfiguration.java index aad8c963cd7..776eecb1320 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebXmlConfiguration.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebXmlConfiguration.java @@ -120,25 +120,13 @@ public class WebXmlConfiguration extends AbstractConfiguration /* ------------------------------------------------------------------------------- */ @Override public void deconfigure (WebAppContext context) throws Exception - { - // TODO preserve any configuration that pre-existed. - - ServletHandler _servletHandler = context.getServletHandler(); - - _servletHandler.setFilters(null); - _servletHandler.setFilterMappings(null); - _servletHandler.setServlets(null); - _servletHandler.setServletMappings(null); - - context.setEventListeners(null); + { context.setWelcomeFiles(null); if (context.getErrorHandler() instanceof ErrorPageErrorHandler) ((ErrorPageErrorHandler) context.getErrorHandler()).setErrorPages(null); - // TODO remove classpaths from classloader - } } diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ReloadedSessionMissingClassTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ReloadedSessionMissingClassTest.java index 05ca1175133..c34bb6b0123 100644 --- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ReloadedSessionMissingClassTest.java +++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ReloadedSessionMissingClassTest.java @@ -113,7 +113,6 @@ public class ReloadedSessionMissingClassTest webApp.stop(); webApp.setClassLoader(loaderWithoutFoo); - webApp.addServlet("Bar", "/bar"); //restart webapp webApp.start();