View Javadoc

    1   // ========================================================================
    2   // Copyright 199-2004 Mort Bay Consulting Pty. Ltd.
    3   // ------------------------------------------------------------------------
    4   // Licensed under the Apache License, Version 2.0 (the "License");
    5   // you may not use this file except in compliance with the License.
    6   // You may obtain a copy of the License at
    7   // http://www.apache.org/licenses/LICENSE-2.0
    8   // Unless required by applicable law or agreed to in writing, software
    9   // distributed under the License is distributed on an "AS IS" BASIS,
    10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  // ========================================================================
    14
    15  package org.mortbay.jetty.servlet;
    16
    17  import java.io.IOException;
    18  import java.util.Collections;
    19  import java.util.Enumeration;
    20  import java.util.HashSet;
    21  import java.util.Iterator;
    22  import java.util.Map;
    23
    24  import javax.servlet.RequestDispatcher;
    25  import javax.servlet.ServletException;
    26  import javax.servlet.ServletRequest;
    27  import javax.servlet.ServletResponse;
    28  import javax.servlet.http.HttpServletRequest;
    29  import javax.servlet.http.HttpServletResponse;
    30
    31  import org.mortbay.jetty.Handler;
    32  import org.mortbay.jetty.HttpConnection;
    33  import org.mortbay.jetty.Request;
    34  import org.mortbay.jetty.handler.ContextHandler;
    35  import org.mortbay.util.Attributes;
    36  import org.mortbay.util.LazyList;
    37  import org.mortbay.util.MultiMap;
    38  import org.mortbay.util.UrlEncoded;
    39
    40  /* ------------------------------------------------------------ */
    41  /** Servlet RequestDispatcher.
    42   *
    43   * @author Greg Wilkins (gregw)
    44   */
    45  public class Dispatcher implements RequestDispatcher
    46  {
    47      /** Dispatch include attribute names */
    48      public final static String __INCLUDE_JETTY="org.mortbay.jetty.included";
    49      public final static String __INCLUDE_PREFIX="javax.servlet.include.";
    50      public final static String __INCLUDE_REQUEST_URI= "javax.servlet.include.request_uri";
    51      public final static String __INCLUDE_CONTEXT_PATH= "javax.servlet.include.context_path";
    52      public final static String __INCLUDE_SERVLET_PATH= "javax.servlet.include.servlet_path";
    53      public final static String __INCLUDE_PATH_INFO= "javax.servlet.include.path_info";
    54      public final static String __INCLUDE_QUERY_STRING= "javax.servlet.include.query_string";
    55
    56      /** Dispatch include attribute names */
    57      public final static String __FORWARD_JETTY="org.mortbay.jetty.forwarded";
    58      public final static String __FORWARD_PREFIX="javax.servlet.forward.";
    59      public final static String __FORWARD_REQUEST_URI= "javax.servlet.forward.request_uri";
    60      public final static String __FORWARD_CONTEXT_PATH= "javax.servlet.forward.context_path";
    61      public final static String __FORWARD_SERVLET_PATH= "javax.servlet.forward.servlet_path";
    62      public final static String __FORWARD_PATH_INFO= "javax.servlet.forward.path_info";
    63      public final static String __FORWARD_QUERY_STRING= "javax.servlet.forward.query_string";
    64
    65      /** JSP attributes */
    66      public final static String __JSP_FILE="org.apache.catalina.jsp_file";
    67
    68      /* ------------------------------------------------------------ */
    69      /** Dispatch type from name
    70       */
    71      public static int type(String type)
    72      {
    73          if ("request".equalsIgnoreCase(type))
    74              return Handler.REQUEST;
    75          if ("forward".equalsIgnoreCase(type))
    76              return Handler.FORWARD;
    77          if ("include".equalsIgnoreCase(type))
    78              return Handler.INCLUDE;
    79          if ("error".equalsIgnoreCase(type))
    80              return Handler.ERROR;
    81          throw new IllegalArgumentException(type);
    82      }
    83
    84
    85      /* ------------------------------------------------------------ */
    86      private ContextHandler _contextHandler;
    87      private String _uri;
    88      private String _path;
    89      private String _dQuery;
    90      private String _named;
    91
    92      /* ------------------------------------------------------------ */
    93      /**
    94       * @param contextHandler
    95       * @param uriInContext
    96       * @param pathInContext
    97       * @param query
    98       */
    99      public Dispatcher(ContextHandler contextHandler, String uri, String pathInContext, String query)
    100     {
    101         _contextHandler=contextHandler;
    102         _uri=uri;
    103         _path=pathInContext;
    104         _dQuery=query;
    105     }
    106
    107
    108     /* ------------------------------------------------------------ */
    109     /** Constructor.
    110      * @param servletHandler
    111      * @param name
    112      */
    113     public Dispatcher(ContextHandler contextHandler,String name)
    114         throws IllegalStateException
    115     {
    116         _contextHandler=contextHandler;
    117         _named=name;
    118     }
    119
    120     /* ------------------------------------------------------------ */
    121     /*
    122      * @see javax.servlet.RequestDispatcher#forward(javax.servlet.ServletRequest, javax.servlet.ServletResponse)
    123      */
    124     public void forward(ServletRequest request, ServletResponse response) throws ServletException, IOException
    125     {
    126         forward(request, response, Handler.FORWARD);
    127     }
    128
    129     /* ------------------------------------------------------------ */
    130     /*
    131      * @see javax.servlet.RequestDispatcher#forward(javax.servlet.ServletRequest, javax.servlet.ServletResponse)
    132      */
    133     public void error(ServletRequest request, ServletResponse response) throws ServletException, IOException
    134     {
    135         forward(request, response, Handler.ERROR);
    136     }
    137
    138     /* ------------------------------------------------------------ */
    139     /*
    140      * @see javax.servlet.RequestDispatcher#include(javax.servlet.ServletRequest, javax.servlet.ServletResponse)
    141      */
    142     public void include(ServletRequest request, ServletResponse response) throws ServletException, IOException
    143     {
    144         Request base_request=(request instanceof Request)?((Request)request):HttpConnection.getCurrentConnection().getRequest();
    145         request.removeAttribute(__JSP_FILE); // TODO remove when glassfish 1044 is fixed
    146
    147         // TODO - allow stream or writer????
    148
    149         Attributes old_attr=base_request.getAttributes();
    150         MultiMap old_params=base_request.getParameters();
    151         try
    152         {
    153             base_request.getConnection().include();
    154             if (_named!=null)
    155                 _contextHandler.handle(_named, (HttpServletRequest)request, (HttpServletResponse)response, Handler.INCLUDE);
    156             else
    157             {
    158                 String query=_dQuery;
    159
    160                 if (query!=null)
    161                 {
    162                     MultiMap parameters=new MultiMap();
    163                     UrlEncoded.decodeTo(query,parameters,request.getCharacterEncoding());
    164
    165                     if (old_params!=null && old_params.size()>0)
    166                     {
    167                         // Merge parameters.
    168                         Iterator iter = old_params.entrySet().iterator();
    169                         while (iter.hasNext())
    170                         {
    171                             Map.Entry entry = (Map.Entry)iter.next();
    172                             String name=(String)entry.getKey();
    173                             Object values=entry.getValue();
    174                             for (int i=0;i<LazyList.size(values);i++)
    175                                 parameters.add(name, LazyList.get(values, i));
    176                         }
    177
    178                     }
    179                     base_request.setParameters(parameters);
    180                 }
    181
    182                 IncludeAttributes attr = new IncludeAttributes(old_attr);
    183
    184                 attr._requestURI=_uri;
    185                 attr._contextPath=_contextHandler.getContextPath();
    186                 attr._servletPath=null; // set by ServletHandler
    187                 attr._pathInfo=_path;
    188                 attr._query=query;
    189
    190                 base_request.setAttributes(attr);
    191
    192                 _contextHandler.handle(_named==null?_path:_named, (HttpServletRequest)request, (HttpServletResponse)response, Handler.INCLUDE);
    193             }
    194         }
    195         finally
    196         {
    197             base_request.setAttributes(old_attr);
    198             base_request.getConnection().included();
    199             base_request.setParameters(old_params);
    200         }
    201     }
    202
    203
    204     /* ------------------------------------------------------------ */
    205     /*
    206      * @see javax.servlet.RequestDispatcher#forward(javax.servlet.ServletRequest, javax.servlet.ServletResponse)
    207      */
    208     protected void forward(ServletRequest request, ServletResponse response, int dispatch) throws ServletException, IOException
    209     {
    210         Request base_request=(request instanceof Request)?((Request)request):HttpConnection.getCurrentConnection().getRequest();
    211         response.resetBuffer();
    212         request.removeAttribute(__JSP_FILE); // TODO remove when glassfish 1044 is fixed
    213
    214         String old_uri=base_request.getRequestURI();
    215         String old_context_path=base_request.getContextPath();
    216         String old_servlet_path=base_request.getServletPath();
    217         String old_path_info=base_request.getPathInfo();
    218         String old_query=base_request.getQueryString();
    219         Attributes old_attr=base_request.getAttributes();
    220         MultiMap old_params=base_request.getParameters();
    221         try
    222         {
    223             if (_named!=null)
    224                 _contextHandler.handle(_named, (HttpServletRequest)request, (HttpServletResponse)response, dispatch);
    225             else
    226             {
    227                 String query=_dQuery;
    228
    229                 if (query!=null)
    230                 {
    231                     MultiMap parameters=new MultiMap();
    232                     UrlEncoded.decodeTo(query,parameters,request.getCharacterEncoding());
    233
    234                     boolean rewrite_old_query = false;
    235
    236                     if( old_params == null )
    237                     {
    238                         base_request.getParameterNames();    // force parameters to be evaluated
    239                         old_params = base_request.getParameters();
    240                     }
    241
    242                     if (old_params!=null && old_params.size()>0)
    243                     {
    244                         // Merge parameters; new parameters of the same name take precedence.
    245                         Iterator iter = old_params.entrySet().iterator();
    246                         while (iter.hasNext())
    247                         {
    248                             Map.Entry entry = (Map.Entry)iter.next();
    249                             String name=(String)entry.getKey();
    250
    251                             if (parameters.containsKey(name))
    252                                 rewrite_old_query = true;
    253                             Object values=entry.getValue();
    254                             for (int i=0;i<LazyList.size(values);i++)
    255                                 parameters.add(name, LazyList.get(values, i));
    256                         }
    257                     }
    258
    259                     if (old_query != null && old_query.length()>0)
    260                     {
    261                         if ( rewrite_old_query )
    262                         {
    263                             StringBuffer overridden_query_string = new StringBuffer();
    264                             MultiMap overridden_old_query = new MultiMap();
    265                             UrlEncoded.decodeTo(old_query,overridden_old_query,request.getCharacterEncoding());
    266
    267                             MultiMap overridden_new_query = new MultiMap();
    268                             UrlEncoded.decodeTo(query,overridden_new_query,request.getCharacterEncoding());
    269
    270                             Iterator iter = overridden_old_query.entrySet().iterator();
    271                             while (iter.hasNext())
    272                             {
    273                                 Map.Entry entry = (Map.Entry)iter.next();
    274                                 String name=(String)entry.getKey();
    275                                 if(!overridden_new_query.containsKey(name))
    276                                 {
    277                                     Object values=entry.getValue();
    278                                     for (int i=0;i<LazyList.size(values);i++)
    279                                     {
    280                                         overridden_query_string.append("&"+name+"="+LazyList.get(values, i));
    281                                     }
    282                                 }
    283                             }
    284
    285                             query = query + overridden_query_string;
    286                         }
    287                         else
    288                         {
    289                             query=query+"&"+old_query;
    290                         }
    291                    }
    292
    293                     base_request.setParameters(parameters);
    294                     base_request.setQueryString(query);
    295                 }
    296
    297                 ForwardAttributes attr = new ForwardAttributes(old_attr);
    298
    299                 //If we have already been forwarded previously, then keep using the established
    300                 //original value. Otherwise, this is the first forward and we need to establish the values.
    301                 //Note: the established value on the original request for pathInfo and
    302                 //for queryString is allowed to be null, but cannot be null for the other values.
    303                 if ((String)old_attr.getAttribute(__FORWARD_REQUEST_URI) != null)
    304                 {
    305                     attr._pathInfo=(String)old_attr.getAttribute(__FORWARD_PATH_INFO);
    306                     attr._query=(String)old_attr.getAttribute(__FORWARD_QUERY_STRING);
    307                     attr._requestURI=(String)old_attr.getAttribute(__FORWARD_REQUEST_URI);
    308                     attr._contextPath=(String)old_attr.getAttribute(__FORWARD_CONTEXT_PATH);
    309                     attr._servletPath=(String)old_attr.getAttribute(__FORWARD_SERVLET_PATH);
    310                 }
    311                 else
    312                 {
    313                     attr._pathInfo=old_path_info;
    314                     attr._query=old_query;
    315                     attr._requestURI=old_uri;
    316                     attr._contextPath=old_context_path;
    317                     attr._servletPath=old_servlet_path;
    318                 }
    319
    320
    321
    322                 base_request.setRequestURI(_uri);
    323                 base_request.setContextPath(_contextHandler.getContextPath());
    324                 base_request.setAttributes(attr);
    325                 base_request.setQueryString(query);
    326
    327                 _contextHandler.handle(_path, (HttpServletRequest)request, (HttpServletResponse)response, dispatch);
    328
    329                 if (base_request.getConnection().getResponse().isWriting())
    330                 {
    331                     try {response.getWriter().close();}
    332                     catch(IllegalStateException e) { response.getOutputStream().close(); }
    333                 }
    334                 else
    335                 {
    336                     try {response.getOutputStream().close();}
    337                     catch(IllegalStateException e) { response.getWriter().close(); }
    338                 }
    339             }
    340         }
    341         finally
    342         {
    343             base_request.setRequestURI(old_uri);
    344             base_request.setContextPath(old_context_path);
    345             base_request.setServletPath(old_servlet_path);
    346             base_request.setPathInfo(old_path_info);
    347             base_request.setAttributes(old_attr);
    348             base_request.setParameters(old_params);
    349             base_request.setQueryString(old_query);
    350         }
    351     }
    352
    353
    354     /* ------------------------------------------------------------ */
    355     /* ------------------------------------------------------------ */
    356     /* ------------------------------------------------------------ */
    357     private class ForwardAttributes implements Attributes
    358     {
    359         Attributes _attr;
    360
    361         String _requestURI;
    362         String _contextPath;
    363         String _servletPath;
    364         String _pathInfo;
    365         String _query;
    366
    367         ForwardAttributes(Attributes attributes)
    368         {
    369             _attr=attributes;
    370         }
    371
    372         /* ------------------------------------------------------------ */
    373         public Object getAttribute(String key)
    374         {
    375             if (Dispatcher.this._named==null)
    376             {
    377                 if (key.equals(__FORWARD_PATH_INFO))    return _pathInfo;
    378                 if (key.equals(__FORWARD_REQUEST_URI))  return _requestURI;
    379                 if (key.equals(__FORWARD_SERVLET_PATH)) return _servletPath;
    380                 if (key.equals(__FORWARD_CONTEXT_PATH)) return _contextPath;
    381                 if (key.equals(__FORWARD_QUERY_STRING)) return _query;
    382             }
    383
    384             if (key.startsWith(__INCLUDE_PREFIX) || key.equals(__INCLUDE_JETTY) )
    385                 return null;
    386
    387             if (key.equals(__FORWARD_JETTY))
    388                 return Boolean.TRUE;
    389
    390             return _attr.getAttribute(key);
    391         }
    392
    393         /* ------------------------------------------------------------ */
    394         public Enumeration getAttributeNames()
    395         {
    396             HashSet set=new HashSet();
    397             Enumeration e=_attr.getAttributeNames();
    398             while(e.hasMoreElements())
    399             {
    400                 String name=(String)e.nextElement();
    401                 if (!name.startsWith(__INCLUDE_PREFIX) &&
    402                     !name.startsWith(__FORWARD_PREFIX))
    403                     set.add(name);
    404             }
    405
    406             if (_named==null)
    407             {
    408                 if (_pathInfo!=null)
    409                     set.add(__FORWARD_PATH_INFO);
    410                 else
    411                     set.remove(__FORWARD_PATH_INFO);
    412                 set.add(__FORWARD_REQUEST_URI);
    413                 set.add(__FORWARD_SERVLET_PATH);
    414                 set.add(__FORWARD_CONTEXT_PATH);
    415                 if (_query!=null)
    416                     set.add(__FORWARD_QUERY_STRING);
    417                 else
    418                     set.remove(__FORWARD_QUERY_STRING);
    419             }
    420
    421             return Collections.enumeration(set);
    422         }
    423
    424         /* ------------------------------------------------------------ */
    425         public void setAttribute(String key, Object value)
    426         {
    427             if (_named==null && key.startsWith("javax.servlet."))
    428             {
    429                 if (key.equals(__FORWARD_PATH_INFO))         _pathInfo=(String)value;
    430                 else if (key.equals(__FORWARD_REQUEST_URI))  _requestURI=(String)value;
    431                 else if (key.equals(__FORWARD_SERVLET_PATH)) _servletPath=(String)value;
    432                 else if (key.equals(__FORWARD_CONTEXT_PATH)) _contextPath=(String)value;
    433                 else if (key.equals(__FORWARD_QUERY_STRING)) _query=(String)value;
    434
    435                 else if (value==null)
    436                     _attr.removeAttribute(key);
    437                 else
    438                     _attr.setAttribute(key,value);
    439             }
    440             else if (value==null)
    441                 _attr.removeAttribute(key);
    442             else
    443                 _attr.setAttribute(key,value);
    444         }
    445
    446         /* ------------------------------------------------------------ */
    447         public String toString()
    448         {
    449             return "FORWARD+"+_attr.toString();
    450         }
    451
    452         /* ------------------------------------------------------------ */
    453         public void clearAttributes()
    454         {
    455             throw new IllegalStateException();
    456         }
    457
    458         /* ------------------------------------------------------------ */
    459         public void removeAttribute(String name)
    460         {
    461             setAttribute(name,null);
    462         }
    463     }
    464
    465     /* ------------------------------------------------------------ */
    466     private class IncludeAttributes implements Attributes
    467     {
    468         Attributes _attr;
    469
    470         String _requestURI;
    471         String _contextPath;
    472         String _servletPath;
    473         String _pathInfo;
    474         String _query;
    475
    476         IncludeAttributes(Attributes attributes)
    477         {
    478             _attr=attributes;
    479         }
    480
    481         /* ------------------------------------------------------------ */
    482         /* ------------------------------------------------------------ */
    483         /* ------------------------------------------------------------ */
    484         public Object getAttribute(String key)
    485         {
    486             if (Dispatcher.this._named==null)
    487             {
    488                 if (key.equals(__INCLUDE_PATH_INFO))    return _pathInfo;
    489                 if (key.equals(__INCLUDE_SERVLET_PATH)) return _servletPath;
    490                 if (key.equals(__INCLUDE_CONTEXT_PATH)) return _contextPath;
    491                 if (key.equals(__INCLUDE_QUERY_STRING)) return _query;
    492                 if (key.equals(__INCLUDE_REQUEST_URI))  return _requestURI;
    493             }
    494             else if (key.startsWith(__INCLUDE_PREFIX))
    495                     return null;
    496
    497             if (key.equals(__INCLUDE_JETTY))
    498                 return Boolean.TRUE;
    499
    500             return _attr.getAttribute(key);
    501         }
    502
    503         /* ------------------------------------------------------------ */
    504         public Enumeration getAttributeNames()
    505         {
    506             HashSet set=new HashSet();
    507             Enumeration e=_attr.getAttributeNames();
    508             while(e.hasMoreElements())
    509             {
    510                 String name=(String)e.nextElement();
    511                 if (!name.startsWith(__INCLUDE_PREFIX))
    512                     set.add(name);
    513             }
    514
    515             if (_named==null)
    516             {
    517                 if (_pathInfo!=null)
    518                     set.add(__INCLUDE_PATH_INFO);
    519                 else
    520                     set.remove(__INCLUDE_PATH_INFO);
    521                 set.add(__INCLUDE_REQUEST_URI);
    522                 set.add(__INCLUDE_SERVLET_PATH);
    523                 set.add(__INCLUDE_CONTEXT_PATH);
    524                 if (_query!=null)
    525                     set.add(__INCLUDE_QUERY_STRING);
    526                 else
    527                     set.remove(__INCLUDE_QUERY_STRING);
    528             }
    529
    530             return Collections.enumeration(set);
    531         }
    532
    533         /* ------------------------------------------------------------ */
    534         public void setAttribute(String key, Object value)
    535         {
    536             if (_named==null && key.startsWith("javax.servlet."))
    537             {
    538                 if (key.equals(__INCLUDE_PATH_INFO))         _pathInfo=(String)value;
    539                 else if (key.equals(__INCLUDE_REQUEST_URI))  _requestURI=(String)value;
    540                 else if (key.equals(__INCLUDE_SERVLET_PATH)) _servletPath=(String)value;
    541                 else if (key.equals(__INCLUDE_CONTEXT_PATH)) _contextPath=(String)value;
    542                 else if (key.equals(__INCLUDE_QUERY_STRING)) _query=(String)value;
    543                 else if (value==null)
    544                     _attr.removeAttribute(key);
    545                 else
    546                     _attr.setAttribute(key,value);
    547             }
    548             else if (value==null)
    549                 _attr.removeAttribute(key);
    550             else
    551                 _attr.setAttribute(key,value);
    552         }
    553
    554         /* ------------------------------------------------------------ */
    555         public String toString()
    556         {
    557             return "INCLUDE+"+_attr.toString();
    558         }
    559
    560         /* ------------------------------------------------------------ */
    561         public void clearAttributes()
    562         {
    563             throw new IllegalStateException();
    564         }
    565
    566         /* ------------------------------------------------------------ */
    567         public void removeAttribute(String name)
    568         {
    569             setAttribute(name,null);
    570         }
    571     }
    572 };