welcome-file-listの挙動

welcome-file-list機能実装の為に仕様を調べました。
悩んでいたのはServlet2.4から仕様に追加された、「welcomeファイルにServletを指定できる」という機能です。
まず根本的なところで、SUNが出しているJ2EE仕様書servlet-2_4_fr-spec.pdf)を元にすると、welcomeファイルを探す時方法については、

The Web server must append each welcome file in the order specified in the deployment descriptor to the partial request and check whether a static resource or servlet in the WAR is mapped to that request URI.

となっています。
ちょい意訳すると、
「ウェブサーバは、リクエストに対してweb.xmlのwelcomeファイルを順に追加して、静的なリソースかサーブレットがそのURIにマップされるかどうかチェックするのはマスト事項」
という感じになっています。まあ妥当な内容と思います。
しかしながら、「サーブレットURIにマップされた場合で処理ができない場合」に関しては、記述がありません。
具体的に言うと、*.doのURLパターンで登録してあるサーブレットに対してwelcome-fileにindex.doをセットしたけどindex.doが処理できないという場合です。
例えば

<welcome-file-list>
 <welcome-file>hoge.jsp</welcome-file>
 <welcome-file>index.jsp</welcome-file>
</welcome-file-list>

とした場合でindex.jspしかない場合はちゃんとindex.jspが出るのですが、それであれば*.do登録でindex.doを処理できないときは、次に処理が回っても然るべきなんじゃないかなと思うからです。

で、仕様書にサンプルが載っていたのですが、

<welcome-file-list>
 <welcome-file>index.html</welcome-file>
 <welcome-file>default.jsp</welcome-file>
</welcome-file-list>

と、サーブレットは使うなと言わんばかりのサンプルだったので、仕方ないのでTomcat先生(5.5)でサンプルを作って動かしてみました。

<?xml version="1.0"?>
<web-app version="2.4"  xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
  <servlet>
      <servlet-name>dotdo</servlet-name>
      <servlet-class>welcomefiletest.DotDoServlet</servlet-class>
  </servlet>
  <servlet>
      <servlet-name>fullnameservlet</servlet-name>
      <servlet-class>welcomefiletest.FullNameServlet</servlet-class>
  </servlet>    

  <servlet-mapping>
    <servlet-name>dotdo</servlet-name>
    <url-pattern>*.do</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>fullnameservlet</servlet-name>
    <url-pattern>/fullname</url-pattern>
  </servlet-mapping>
</web-app>

DodDoServletとFullNameServletはそれぞれout.printで適当な文字列を返すサーブレットで、webのルートディレクトリにはindex.htmlとindex.jspを配置した状態で、以下のwelcome-fileを試しました。

  • dotdo
  • index.do
    • これはOKと思っていたが、意に反してNG。ただし、「index.do」というファイルを置くとOK(dotdoサーブレットが呼ばれます)
  • /index.do
    • NG
  • fullname
    • OK。fullnameservletが呼び出される。
  • /fullname
    • NG 「/」から始まるパスはだめ(仕様書にも書いてある)
  • fullnameservlet
  • index2.jsp
    • NG。404NotFound。
  • index.html
  • index.jsp
    • いずれもOK。

以上の挙動から推測すると、少なくともTomcat先生は、

  1. welcomeファイルの記述と完全にマッチするURLパターンを持つサーブレットを探す(「fullname」に対して「/fullname」のパターンを持つサーブレット)。あった場合、そのサーブレットにフォワードする。
  2. 物理ディレクトリから、welcomeファイルと同じ名前を持つ静的リソースを検索し、あった場合そのURLでフォワードする。
  3. 一度フォワードする、もしくは該当するサーブレットorファイルがない場合、終了。

という風にwelcomeファイルを処理するようです。

フォワード先でエラーになった場合、次に書いてあるwelcomeファイルを探して処理を渡すのかと思っていたので悩んでいましたが、これならすぐに実装できそうです。

ちなみにですが、welcomeファイルへの処理の渡し方については

The container may send the request to the welcome resource with a forward, a redirect, or a container specific mechanism that is indistinguishable from a direct request.

と書いてあり、Tomcat5.5はフォワードを採用していますが、調べたところTomcat4はリダイレクトを利用しているようです。