Bug 51278 - Unable to override default servlet other than in main web.xml
Summary: Unable to override default servlet other than in main web.xml
Status: RESOLVED FIXED
Alias: None
Product: Tomcat 7
Classification: Unclassified
Component: Catalina (show other bugs)
Version: unspecified
Hardware: PC All
: P2 normal (vote)
Target Milestone: ---
Assignee: Tomcat Developers Mailing List
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2011-05-28 07:12 UTC by Mark Thomas
Modified: 2014-02-17 13:50 UTC (History)
2 users (show)



Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Mark Thomas 2011-05-28 07:12:37 UTC
The default web.xml gets merged into the application's web.xml before processing of fragments, annotations and ServletContextInitializers. This means it can only be overridden in the application's web.xml. It should be possible to override in fragments, annotations and ServletContextInitializers.
Comment 1 Chris Beams 2011-05-28 08:25:07 UTC
Thanks for filing this issue, Mark.  I encountered this behavior when designing a ServletContainerInitializer for the Spring Framework.  The SCI declares @HandlesTypes for a spring-specific SPI (WebApplicationInitializer).  The intent of this interface is to allow users a convenient and automatically detected way to replace web.xml with code.

Many users map Spring's DispatcherServlet to '/', and this works fine when done from web.xml.  However, for the reasons you've described, a direct translation of this mapping into code does not work, because Tomcat's DefaultServlet has already been mapped.

Your suggested resolution sounds like just what we need in the immediate term.  As for the future (i.e. Servlet 3.1), perhaps the EG could consider making the overriding rules a bit more flexible.  For example, FilterRegistration#addMappingForUrlPattern[1] currently accepts a boolean "isMatchAfter" argument that suggests this kind of flexibility.

In any case, short term or long, the question is whether mapping to '/' will be portable.  I'm about to try this same scenario against Jetty and Glassfish; it will be interesting to see if they too have ordering issues with default mappings to '/', or perhaps have already addressed this very scenario.

[1] http://download.oracle.com/javaee/6/api/javax/servlet/FilterRegistration.html#addMappingForUrlPatterns(java.util.EnumSet, boolean, java.lang.String...)
Comment 2 Chris Beams 2011-05-28 09:56:11 UTC
update: I've just tried this same ServletContainerInitializer scenario under Glassfish 3.1 and the override works as desired.  This is especially interesting given that the catalina DefaultServlet is mapped to '/' in this environment as well.  It suggests that they have specifically addressed this issue, perhaps in a fashion similar to the one Mark describes above.
Comment 3 Christopher Schultz 2011-05-31 21:07:07 UTC
That would seem to conflict with the exposure of servlet registration events in the 3.0 API... a registration event that occurs later isn't supposed to conflict with ones occurring earlier (for Servlets, that is... I realize we're discussing Filters, here).
Comment 4 Chris Beams 2011-06-01 07:10:20 UTC
(In reply to comment #3)
> That would seem to conflict with the exposure of servlet registration events in
> the 3.0 API... a registration event that occurs later isn't supposed to
> conflict with ones occurring earlier (for Servlets, that is... I realize we're
> discussing Filters, here).

Hi Christopher,

Actually, we are talking primarily about Servlets here.  I was only mentioning the FilterRegistration API momentarily above.

The critical issue is this: Tomcat users can override the DefaultServlet's mapping to '/' within web.xml, but cannot do so within a ServletContainerInitializer (or presumably any other programmatic context).  This inconsistency means that web.xml cannot be completely replaced by code in a Tomcat environment, which is what we're aiming to facilitate.

I've been unable to pinpoint a passage in the spec that spells out that the status quo is the way things *should* work, but then again - and if I understand things correctly - the spec is silent on the way Tomcat registers its DefaultServlet, so we're probably already in unspecified territory, yes?

Even if the spec did mandate or strongly suggest the status quo, I would go so far as to argue that the spec should be changed.  The ServletContext API now allows for full programmatic registration, let's let users take advantage of it!
Comment 5 Christopher Schultz 2011-06-01 15:41:47 UTC
(In reply to comment #4)
> Actually, we are talking primarily about Servlets here.  I was only mentioning
> the FilterRegistration API momentarily above.

Right. I was just pointing-out that the rules for Servlets and Filters are apparently different.

> The critical issue is this: Tomcat users can override the DefaultServlet's
> mapping to '/' within web.xml, but cannot do so within a
> ServletContainerInitializer (or presumably any other programmatic context). 
> This inconsistency means that web.xml cannot be completely replaced by code in
> a Tomcat environment, which is what we're aiming to facilitate.

Yup, I get it, and you certainly /should/ be able to set these things from within the code. Tomcat's DefaultServlet should be a last-resort that handles requests only when no other servlet can be found.

> I've been unable to pinpoint a passage in the spec that spells out that the
> status quo is the way things *should* work, but then again - and if I
> understand things correctly - the spec is silent on the way Tomcat registers
> its DefaultServlet, so we're probably already in unspecified territory, yes?

The closest I could come was looking at the javadoc for the addServlet and addFilter methods in ServletContext, which have some things to say about the behavior of those methods when a URL mapping already exists.

I guess the question is really whether the DefaultServlet being mapped to "/" really "counts" as a traditional mapping, or if the DefaultServlet should be considered something that just handles all otherwise-unhandled requests. If you think about it that way, then registration of a Servlet on "/" should be able to happen at any time during the lifecycle of the webapp (even long after the context has been started) as long as no previous registration has occurred.

I guess what I'm suggesting is that we might want to register DefaultServlet in a way that is orthogonal to the registration of all other servlets so we don't have to have special-case handling for processing web.xml, then annotations, then fragments, then running all ServletContextListeners, then processing  conf/web.xml to get around this apparent oddity.
Comment 6 Mark Thomas 2011-06-02 15:53:49 UTC
This has now been fixed (it wasn't hard to fix as I feared) in 7.0.x and will be included in 7.0.15 onwards.
Comment 7 Chris Beams 2011-06-03 04:20:44 UTC
That's great news, Mark!  We'll be sure to test it out when 7.0.15 drops - and this is perfect timing for the forthcoming Spring 3.1 M2.
Comment 8 Fernando Ribeiro 2012-09-13 03:48:07 UTC
Just had the same issue in 7.0.30, as reported at https://issues.apache.org/bugzilla/show_bug.cgi?id=53863