Bug 47378 - welcome-file ignores servlet mapping
Summary: welcome-file ignores servlet mapping
Status: RESOLVED FIXED
Alias: None
Product: Tomcat 7
Classification: Unclassified
Component: Servlet & JSP API (show other bugs)
Version: trunk
Hardware: All All
: P2 enhancement (vote)
Target Milestone: ---
Assignee: Tomcat Developers Mailing List
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2009-06-16 12:52 UTC by Bobby Lawrence
Modified: 2010-06-14 14:50 UTC (History)
1 user (show)



Attachments
Patch against tomcat 6.0 (1.63 KB, patch)
2009-07-30 08:01 UTC, Tim Funk
Details | Diff
War file demonstrating exact mappings (497 bytes, application/octet-stream)
2009-08-03 04:45 UTC, Tim Funk
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Bobby Lawrence 2009-06-16 12:52:31 UTC
Web applications that use a servlet mapping for their welcome-file are ignored
and the server returns either a directory listing or a 404 if the listing is
disabled.
I have JSF servlet defined and a servlet-mapping for *.jsf to go to the
FacesServlet.
I have "index.jsf" listed as by welcome-file and I get a 404 with directory
listing disabled.
I also have a custom servlet defined with its mapping and set the welcome-file
to its mapping and get a 404 as well.
Comment 1 Tim Funk 2009-06-17 04:05:38 UTC
You'll need a physical file called index.jspf as a "placeholder" for the action to occur. The file placeholder can be 0 bytes if you want. Or you can write a filter to detect a directory is requested and forward to index.jspf.

The reason for needing a physical file is the servlet container is to allow for multiple welcome file types. 

Imagine I had welcome files of index.jsp, then index.html, then index.htm.

Imagine I have a directory that is missing index.jsp, but has an index.html. If I always tried to invoke index.jsp like the welcome file list says, then the JSP servlet will return a 404 since there is no mechanism in the servlet api to defer that decision. 

IIRC - there are more discussions of this in the archives, but those talks are REALLY old.
Comment 2 Bobby Lawrence 2009-06-17 06:29:25 UTC
In the scenario that you described (the multiple welcome files index.jsp, index.html, etc), I would think that the container should try each in succession until it finds one that is valid.  The mechanism for "defering that decision" would have to be built into the DefaultServlet.  
This means that if a developer wanted to forward a user to some random servlet, "/dosomething", or to a Struts action, or to a JSF page, I would have to create some dummy file in which all it did was forward the request?
This has been an issue with other jsp/servlet containers in the past and the developer community fixed it.  I was hoping that the Tomcat community would provide a fix for this.  Instead it looks like if I want to run my apps on Tomcat, I will have to modify them all...
Comment 3 Bobby Lawrence 2009-06-17 06:32:04 UTC
The "other" jsp/servlet containers that I was referring to is Jetty.
Weblogic already handles this now.  But since the Tomcat catalina core is used in so many other containers (Geronimo, Glassfish), this has become an issue on those containers as well.
Comment 4 Rex Wang 2009-07-13 01:22:32 UTC
Hi, Dear devs, 
Has this bug been resolved? I am instreseting in it, where can I get a snapshot build to have a try? Was that committed to 7.0 trunk or 6.0 trunk?

-Rex
Comment 5 Rex Wang 2009-07-13 01:57:23 UTC
From my point of view, I don't like the work around to create a dummy file to help  request the servlet. The logic I prefer is:
1. scan welcome list from actual files. If one is found, use it.
2. If none are found, try servlet mappings, for example:
if there is a /Hello in weclome list:
  <welcome-file-list>
    <welcome-file>/Hello</welcome-file>
  </welcome-file-list>
we should find in the wel.xml to look if there is a <servlet-mapping> hold a <url-pattern> that can match "/Hello", such as 
<url-pattern>/Hello</url-pattern> or <url-pattern>/*</url-pattern>

Any thoughts?

-Rex

(In reply to comment #1)
> You'll need a physical file called index.jspf as a "placeholder" for the action
> to occur. The file placeholder can be 0 bytes if you want. Or you can write a
> filter to detect a directory is requested and forward to index.jspf.
> 
> The reason for needing a physical file is the servlet container is to allow for
> multiple welcome file types. 
> 
> Imagine I had welcome files of index.jsp, then index.html, then index.htm.
> 
> Imagine I have a directory that is missing index.jsp, but has an index.html. If
> I always tried to invoke index.jsp like the welcome file list says, then the
> JSP servlet will return a 404 since there is no mechanism in the servlet api to
> defer that decision. 
> 
> IIRC - there are more discussions of this in the archives, but those talks are
> REALLY old.
Comment 6 Mark Thomas 2009-07-13 02:26:45 UTC
This wasn't fixed.

SRV.9.10 makes it clear the servlet mappings in web.xml should be supported. Until this gets fixed, you can use the workaround Tim describes.

Patches are always welcome.
Comment 7 david jencks 2009-07-13 14:18:53 UTC
This issue came up in jetty recently and it became clear in e.g. discussions that the spec wording interpreted literally implies a non-workable solution.  The wording may be clarified in servlet 3.0, meanwhile see

http://jira.codehaus.org/browse/JETTY-936

for the apparent consensus on what is intended.
Comment 8 Tim Funk 2009-07-18 18:26:49 UTC
This might work as a patch to org.apache.tomcat.util.http.mapper.Mapper - add it before // Rule 7 -- Default servlet and after          // Rule 4 -- Welcome resources processing for servlets

        // DAMMIT - welcome file processing - take 2
        // take first matching welcome match
        // its a copy of rule 4 since it needs to do less
        if (mappingData.wrapper == null) {
            boolean checkWelcomeFiles = checkJspWelcomeFiles;
            if (!checkWelcomeFiles) {
                char[] buf = path.getBuffer();
                checkWelcomeFiles = (buf[pathEnd - 1] == '/');
            }
            if (checkWelcomeFiles) {
                for (int i = 0; (i < context.welcomeResources.length)
                         && (mappingData.wrapper == null); i++) {
                    path.setOffset(pathOffset);
                    path.setEnd(pathEnd);
                    path.append(context.welcomeResources[i], 0,
                                context.welcomeResources[i].length());
                    path.setOffset(servletPath);

                    internalMapExtensionWrapper(extensionWrappers,
                                                path, mappingData);
                    if (mappingData.wrapper == null
                        && context.defaultWrapper != null) {
                        mappingData.wrapper =
                            context.defaultWrapper.object;
                        mappingData.requestPath.setChars
                            (path.getBuffer(), path.getStart(),
                             path.getLength());
                        mappingData.wrapperPath.setChars
                            (path.getBuffer(), path.getStart(),
                             path.getLength());
                        mappingData.requestPath.setString(pathStr);
                        mappingData.wrapperPath.setString(pathStr);
                    }
                }

                path.setOffset(servletPath);
                path.setEnd(pathEnd);
            }

        }
Comment 9 Rex Wang 2009-07-29 01:56:26 UTC
hi Tim, I tried adding this, but it does not work...
btw, I added one line: String pathStr = path.toString(); to pass compiling.
-Rex

(In reply to comment #8)
> This might work as a patch to org.apache.tomcat.util.http.mapper.Mapper - add
> it before // Rule 7 -- Default servlet and after          // Rule 4 -- Welcome
> resources processing for servlets
> 
>         // DAMMIT - welcome file processing - take 2
>         // take first matching welcome match
>         // its a copy of rule 4 since it needs to do less
>         if (mappingData.wrapper == null) {
>             boolean checkWelcomeFiles = checkJspWelcomeFiles;
>             if (!checkWelcomeFiles) {
>                 char[] buf = path.getBuffer();
>                 checkWelcomeFiles = (buf[pathEnd - 1] == '/');
>             }
>             if (checkWelcomeFiles) {
>                 for (int i = 0; (i < context.welcomeResources.length)
>                          && (mappingData.wrapper == null); i++) {
>                     path.setOffset(pathOffset);
>                     path.setEnd(pathEnd);
>                     path.append(context.welcomeResources[i], 0,
>                                 context.welcomeResources[i].length());
>                     path.setOffset(servletPath);
> 
>                     internalMapExtensionWrapper(extensionWrappers,
>                                                 path, mappingData);
>                     if (mappingData.wrapper == null
>                         && context.defaultWrapper != null) {
>                         mappingData.wrapper =
>                             context.defaultWrapper.object;
>                         mappingData.requestPath.setChars
>                             (path.getBuffer(), path.getStart(),
>                              path.getLength());
>                         mappingData.wrapperPath.setChars
>                             (path.getBuffer(), path.getStart(),
>                              path.getLength());
>                         mappingData.requestPath.setString(pathStr);
>                         mappingData.wrapperPath.setString(pathStr);
>                     }
>                 }
> 
>                 path.setOffset(servletPath);
>                 path.setEnd(pathEnd);
>             }
> 
>         }
Comment 10 Tim Funk 2009-07-30 08:01:55 UTC
Created attachment 24065 [details]
Patch against tomcat 6.0

Here is a working patch. (At least in a simple test case) Previous attempt was wrong on soooo many levels.
Comment 11 Rex Wang 2009-08-02 19:41:08 UTC
Hi Tim, I tried again.. but still not work. I am not sure if we are on the same page, this is my web.xml:
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ...>
  <welcome-file-list>
    <welcome-file>/Hello</welcome-file>
  </welcome-file-list>
  <servlet>
    <servlet-name>HelloServlet</servlet-name>
    <servlet-class>com.abc.HelloServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>HelloServlet</servlet-name>
    <url-pattern>/Hello</url-pattern>
  </servlet-mapping>
</web-app>

(In reply to comment #10)
> Created an attachment (id=24065) [details]
> Patch against tomcat 6.0
> 
> Here is a working patch. (At least in a simple test case) Previous attempt was
> wrong on soooo many levels.
Comment 12 Rex Wang 2009-08-02 19:43:07 UTC
and I did not create a "placeholder". 

-Rex
Comment 13 Rex Wang 2009-08-02 22:40:08 UTC
Hi, Tim

if I set 
  <welcome-file-list>
    <welcome-file>Hello</welcome-file>      ## not "/Hello" here
  </welcome-file-list>
it seems work correctly.

I tried tracking the code, and if use "Hello", the mappingData.wrapper != null
But, if use "/Hello", the mappingData.wrapper = = null. Then will run into the new logic, why not don't allow "/Hello", which is actually a servlet mapping here?

-Rex
Comment 14 Mark Thomas 2009-08-03 02:18:58 UTC
Because welcome files define file names not servlet mappings. It needs to be Hello to be consistent.
Comment 15 Tim Funk 2009-08-03 03:59:03 UTC
Ahhh ... I see the issue. My patch was to handle the case for file extension matches. For example: index.jsf (which is what was for the original report).

Comment 5 could be considered a "different bug". But in this case:
- Welcome file is /Hello
- Servlet exists mapped to /Hello
- So when calculating welcome files - /Hello (while not existing as a file) is an exact match - so that should be used.

time permitting - I'll take a look later today.
Comment 16 Mark Thomas 2009-08-03 04:13:26 UTC
Given welcome files are defined without the leading / - ie 'index.html' rather than '/index.html' - I still think to match a servlet mapping of '/Hello' the welcome file setting should be 'Hello'. This would also be consistent with the current workaround of creating a dummy file.
Comment 17 Tim Funk 2009-08-03 04:45:22 UTC
Created attachment 24088 [details]
War file demonstrating exact mappings

Exact mappings dont need a physical file. (At least with the way the mapper works right now)

Attached is example working on tomcat 6


as a timesaver ... here is the web.xml
  <servlet>
    <servlet-name>fooo</servlet-name>
    <jsp-file>/foo.jsp</jsp-file>
  </servlet>
  <servlet-mapping>
     <servlet-name>fooo</servlet-name>
     <url-pattern>/TIMMAY</url-pattern>
   </servlet-mapping>
   <welcome-file-list>
     <welcome-file>TIMMAY</welcome-file>
   </welcome-file-list>



If / is requested - then the servlet named fooo (path=/TIMMAY) will be used. All this is without the patch I supplied. 

For   Rex Wang (comments 5,11,12) - I think you have a config issue which needs moved to the user list so they can help you.
Comment 18 Rex Wang 2009-08-03 09:37:45 UTC
All right, many thanks, Tim and Mark!

-Rex
Comment 19 Tim Funk 2009-08-31 07:02:01 UTC
Applied this to trunk - so it should make its way into tomcat7
http://svn.apache.org/viewvc?rev=809596&view=rev

I am not proposing this for backport to tomcat 6. But wouldn't be against it if it were proposed. So I'm moving this to enhancement.
Comment 20 Mark Thomas 2010-06-14 14:50:54 UTC
Backporting this to 6.0.x is going to cause some nasty surprises for users such as bug 49422. Therefore, I think this should be fixed only in Tomcat 7.

I am therefore moving this to Tomcat 7 and marking it as fixed.