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 e64665840a0..70046024f02 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 @@ -25,6 +25,7 @@ import java.util.Collection; import java.util.Collections; import java.util.EnumSet; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.ListIterator; import java.util.Map; @@ -109,6 +110,7 @@ public class ServletHandler extends ScopedHandler private ServletHolder[] _servlets=new ServletHolder[0]; private ServletMapping[] _servletMappings; + private Map _servletPathMappings = new HashMap(); private final Map _filterNameMap= new HashMap<>(); private List _filterPathMappings; @@ -264,6 +266,7 @@ public class ServletHandler extends ScopedHandler _filterPathMappings=null; _filterNameMappings=null; _servletPathMap=null; + _servletPathMappings=null; } /* ------------------------------------------------------------ */ @@ -329,31 +332,26 @@ public class ServletHandler extends ScopedHandler return _servletMappings; } + + /* ------------------------------------------------------------ */ /** - * @return Returns the servletMappings. + * Get the ServletMapping matching the path + * + * @param pathSpec + * @return */ - public ServletMapping getServletMapping(String pattern) + public ServletMapping getServletMapping(String pathSpec) { - ServletMapping theMapping = null; - if (_servletMappings!=null) - { - for (ServletMapping m:_servletMappings) - { - String[] paths=m.getPathSpecs(); - if (paths!=null) - { - for (String path:paths) - { - if (pattern.equals(path)) - theMapping = m; - } - } - } - } - return theMapping; + if (pathSpec == null || _servletPathMappings == null) + return null; + + return _servletPathMappings.get(pathSpec); } + + + /* ------------------------------------------------------------ */ /** Get Servlets. * @return Array of defined servlets @@ -1319,27 +1317,75 @@ public class ServletHandler extends ScopedHandler else { PathMap pm = new PathMap<>(); - - // update the maps - for (ServletMapping servletmapping : _servletMappings) + Map servletPathMappings = new HashMap(); + + //create a map of paths to set of ServletMappings that define that mapping + HashMap> sms = new HashMap>(); + for (ServletMapping servletMapping : _servletMappings) { - ServletHolder servlet_holder = _servletNameMap.get(servletmapping.getServletName()); - if (servlet_holder == null) - throw new IllegalStateException("No such servlet: " + servletmapping.getServletName()); - else if (servlet_holder.isEnabled() && servletmapping.getPathSpecs() != null) + String[] pathSpecs = servletMapping.getPathSpecs(); + if (pathSpecs != null) { - String[] pathSpecs = servletmapping.getPathSpecs(); for (String pathSpec : pathSpecs) - if (pathSpec != null) + { + Set mappings = sms.get(pathSpec); + if (mappings == null) { - ServletHolder previous = pm.put(pathSpec, servlet_holder); - if (previous != null) - throw new IllegalStateException("Multiple servlets map to path: "+pathSpec); + mappings = new HashSet(); + sms.put(pathSpec, mappings); } + mappings.add(servletMapping); + } } } + + //evaluate path to servlet map based on servlet mappings + for (String pathSpec : sms.keySet()) + { + //for each path, look at the mappings where it is referenced + //if a mapping is for a servlet that is not enabled, skip it + Set mappings = sms.get(pathSpec); + + + + ServletMapping finalMapping = null; + for (ServletMapping mapping : mappings) + { + //Get servlet associated with the mapping and check it is enabled + ServletHolder servlet_holder = _servletNameMap.get(mapping.getServletName()); + if (servlet_holder == null) + throw new IllegalStateException("No such servlet: " + mapping.getServletName()); + //if the servlet related to the mapping is not enabled, skip it from consideration + if (!servlet_holder.isEnabled()) + continue; + //only accept a default mapping if we don't have any other + if (finalMapping == null) + finalMapping = mapping; + else + { + //already have a candidate - only accept another one if the candidate is a default + if (finalMapping.isDefault()) + finalMapping = mapping; + else + { + //existing candidate isn't a default, if the one we're looking at isn't a default either, then its an error + if (!mapping.isDefault()) + throw new IllegalStateException("Multiple servlets map to path: "+pathSpec); + } + } + } + if (finalMapping == null) + throw new IllegalStateException ("No acceptable servlet mappings for "+pathSpec); + + if (LOG.isDebugEnabled()) LOG.debug("Chose path={} mapped to servlet={} from default={}", pathSpec, finalMapping.getServletName(), finalMapping.isDefault()); + + servletPathMappings.put(pathSpec, finalMapping); + pm.put(pathSpec,_servletNameMap.get(finalMapping.getServletName())); + } + _servletPathMap=pm; + _servletPathMappings=servletPathMappings; } // flush filter chain cache diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/StandardDescriptorProcessor.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/StandardDescriptorProcessor.java index 3314316522a..11cdb0307fc 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/StandardDescriptorProcessor.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/StandardDescriptorProcessor.java @@ -623,16 +623,15 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor { //no servlet mappings context.getMetaData().setOrigin(servlet_name+".servlet.mappings", descriptor); - ServletMapping mapping = addServletMapping(servlet_name, node, context, descriptor); - mapping.setDefault(context.getMetaData().getOrigin(servlet_name+".servlet.mappings") == Origin.WebDefaults); + addServletMapping(servlet_name, node, context, descriptor); break; } - case WebXml: case WebDefaults: + case WebXml: case WebOverride: { //previously set by a web xml descriptor, if we're parsing another web xml descriptor allow override - //otherwise just ignore it + //otherwise just ignore it as web.xml takes precedence (pg 8-81 5.g.vi) if (!(descriptor instanceof FragmentDescriptor)) { addServletMapping(servlet_name, node, context, descriptor); @@ -1181,7 +1180,8 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor { ServletMapping mapping = new ServletMapping(); mapping.setServletName(servletName); - + mapping.setDefault(descriptor instanceof DefaultsDescriptor); + List paths = new ArrayList(); Iterator iter = node.iterator("url-pattern"); while (iter.hasNext())