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                             {
    253                                 rewrite_old_query = true;
    254                             }
    255                             else
    256                             {
    257                                 Object values=entry.getValue();
    258                                 for (int i=0;i<LazyList.size(values);i++)
    259                                 {
    260                                     parameters.add(name, LazyList.get(values, i));
    261                                 }
    262                             }
    263                         }
    264                     }
    265
    266                     if (old_query != null && old_query.length()>0)
    267                     {
    268                         if ( rewrite_old_query )
    269                         {
    270                             StringBuffer overridden_query_string = new StringBuffer();
    271                             MultiMap overridden_old_query = new MultiMap();
    272                             UrlEncoded.decodeTo(old_query,overridden_old_query,request.getCharacterEncoding());
    273
    274                             MultiMap overridden_new_query = new MultiMap();
    275                             UrlEncoded.decodeTo(query,overridden_new_query,request.getCharacterEncoding());
    276
    277                             Iterator iter = overridden_old_query.entrySet().iterator();
    278                             while (iter.hasNext())
    279                             {
    280                                 Map.Entry entry = (Map.Entry)iter.next();
    281                                 String name=(String)entry.getKey();
    282                                 if(!overridden_new_query.containsKey(name))
    283                                 {
    284                                     Object values=entry.getValue();
    285                                     for (int i=0;i<LazyList.size(values);i++)
    286                                     {
    287                                         overridden_query_string.append("&"+name+"="+LazyList.get(values, i));
    288                                     }
    289                                 }
    290                             }
    291
    292                             query = query + overridden_query_string;
    293                         }
    294                         else
    295                         {
    296                             query=query+"&"+old_query;
    297                         }
    298                    }
    299
    300                     base_request.setParameters(parameters);
    301                     base_request.setQueryString(query);
    302                 }
    303
    304                 ForwardAttributes attr = new ForwardAttributes(old_attr);
    305
    306                 //If we have already been forwarded previously, then keep using the established
    307                 //original value. Otherwise, this is the first forward and we need to establish the values.
    308                 //Note: the established value on the original request for pathInfo and
    309                 //for queryString is allowed to be null, but cannot be null for the other values.
    310                 if ((String)old_attr.getAttribute(__FORWARD_REQUEST_URI) != null)
    311                 {
    312                     attr._pathInfo=(String)old_attr.getAttribute(__FORWARD_PATH_INFO);
    313                     attr._query=(String)old_attr.getAttribute(__FORWARD_QUERY_STRING);
    314                     attr._requestURI=(String)old_attr.getAttribute(__FORWARD_REQUEST_URI);
    315                     attr._contextPath=(String)old_attr.getAttribute(__FORWARD_CONTEXT_PATH);
    316                     attr._servletPath=(String)old_attr.getAttribute(__FORWARD_SERVLET_PATH);
    317                 }
    318                 else
    319                 {
    320                     attr._pathInfo=old_path_info;
    321                     attr._query=old_query;
    322                     attr._requestURI=old_uri;
    323                     attr._contextPath=old_context_path;
    324                     attr._servletPath=old_servlet_path;
    325                 }
    326
    327
    328
    329                 base_request.setRequestURI(_uri);
    330                 base_request.setContextPath(_contextHandler.getContextPath());
    331                 base_request.setAttributes(attr);
    332                 base_request.setQueryString(query);
    333
    334                 _contextHandler.handle(_path, (HttpServletRequest)request, (HttpServletResponse)response, dispatch);
    335
    336                 if (base_request.getConnection().getResponse().isWriting())
    337                 {
    338                     try {response.getWriter().close();}
    339                     catch(IllegalStateException e) { response.getOutputStream().close(); }
    340                 }
    341                 else
    342                 {
    343                     try {response.getOutputStream().close();}
    344                     catch(IllegalStateException e) { response.getWriter().close(); }
    345                 }
    346             }
    347         }
    348         finally
    349         {
    350             base_request.setRequestURI(old_uri);
    351             base_request.setContextPath(old_context_path);
    352             base_request.setServletPath(old_servlet_path);
    353             base_request.setPathInfo(old_path_info);
    354             base_request.setAttributes(old_attr);
    355             base_request.setParameters(old_params);
    356             base_request.setQueryString(old_query);
    357         }
    358     }
    359
    360
    361     /* ------------------------------------------------------------ */
    362     /* ------------------------------------------------------------ */
    363     /* ------------------------------------------------------------ */
    364     private class ForwardAttributes implements Attributes
    365     {
    366         Attributes _attr;
    367
    368         String _requestURI;
    369         String _contextPath;
    370         String _servletPath;
    371         String _pathInfo;
    372         String _query;
    373
    374         ForwardAttributes(Attributes attributes)
    375         {
    376             _attr=attributes;
    377         }
    378
    379         /* ------------------------------------------------------------ */
    380         public Object getAttribute(String key)
    381         {
    382             if (Dispatcher.this._named==null)
    383             {
    384                 if (key.equals(__FORWARD_PATH_INFO))    return _pathInfo;
    385                 if (key.equals(__FORWARD_REQUEST_URI))  return _requestURI;
    386                 if (key.equals(__FORWARD_SERVLET_PATH)) return _servletPath;
    387                 if (key.equals(__FORWARD_CONTEXT_PATH)) return _contextPath;
    388                 if (key.equals(__FORWARD_QUERY_STRING)) return _query;
    389             }
    390
    391             if (key.startsWith(__INCLUDE_PREFIX) || key.equals(__INCLUDE_JETTY) )
    392                 return null;
    393
    394             if (key.equals(__FORWARD_JETTY))
    395                 return Boolean.TRUE;
    396
    397             return _attr.getAttribute(key);
    398         }
    399
    400         /* ------------------------------------------------------------ */
    401         public Enumeration getAttributeNames()
    402         {
    403             HashSet set=new HashSet();
    404             Enumeration e=_attr.getAttributeNames();
    405             while(e.hasMoreElements())
    406             {
    407                 String name=(String)e.nextElement();
    408                 if (!name.startsWith(__INCLUDE_PREFIX) &&
    409                     !name.startsWith(__FORWARD_PREFIX))
    410                     set.add(name);
    411             }
    412
    413             if (_named==null)
    414             {
    415                 if (_pathInfo!=null)
    416                     set.add(__FORWARD_PATH_INFO);
    417                 else
    418                     set.remove(__FORWARD_PATH_INFO);
    419                 set.add(__FORWARD_REQUEST_URI);
    420                 set.add(__FORWARD_SERVLET_PATH);
    421                 set.add(__FORWARD_CONTEXT_PATH);
    422                 if (_query!=null)
    423                     set.add(__FORWARD_QUERY_STRING);
    424                 else
    425                     set.remove(__FORWARD_QUERY_STRING);
    426             }
    427
    428             return Collections.enumeration(set);
    429         }
    430
    431         /* ------------------------------------------------------------ */
    432         public void setAttribute(String key, Object value)
    433         {
    434             if (_named==null && key.startsWith("javax.servlet."))
    435             {
    436                 if (key.equals(__FORWARD_PATH_INFO))         _pathInfo=(String)value;
    437                 else if (key.equals(__FORWARD_REQUEST_URI))  _requestURI=(String)value;
    438                 else if (key.equals(__FORWARD_SERVLET_PATH)) _servletPath=(String)value;
    439                 else if (key.equals(__FORWARD_CONTEXT_PATH)) _contextPath=(String)value;
    440                 else if (key.equals(__FORWARD_QUERY_STRING)) _query=(String)value;
    441
    442                 else if (value==null)
    443                     _attr.removeAttribute(key);
    444                 else
    445                     _attr.setAttribute(key,value);
    446             }
    447             else if (value==null)
    448                 _attr.removeAttribute(key);
    449             else
    450                 _attr.setAttribute(key,value);
    451         }
    452
    453         /* ------------------------------------------------------------ */
    454         public String toString()
    455         {
    456             return "FORWARD+"+_attr.toString();
    457         }
    458
    459         /* ------------------------------------------------------------ */
    460         public void clearAttributes()
    461         {
    462             throw new IllegalStateException();
    463         }
    464
    465         /* ------------------------------------------------------------ */
    466         public void removeAttribute(String name)
    467         {
    468             setAttribute(name,null);
    469         }
    470     }
    471
    472     /* ------------------------------------------------------------ */
    473     private class IncludeAttributes implements Attributes
    474     {
    475         Attributes _attr;
    476
    477         String _requestURI;
    478         String _contextPath;
    479         String _servletPath;
    480         String _pathInfo;
    481         String _query;
    482
    483         IncludeAttributes(Attributes attributes)
    484         {
    485             _attr=attributes;
    486         }
    487
    488         /* ------------------------------------------------------------ */
    489         /* ------------------------------------------------------------ */
    490         /* ------------------------------------------------------------ */
    491         public Object getAttribute(String key)
    492         {
    493             if (Dispatcher.this._named==null)
    494             {
    495                 if (key.equals(__INCLUDE_PATH_INFO))    return _pathInfo;
    496                 if (key.equals(__INCLUDE_SERVLET_PATH)) return _servletPath;
    497                 if (key.equals(__INCLUDE_CONTEXT_PATH)) return _contextPath;
    498                 if (key.equals(__INCLUDE_QUERY_STRING)) return _query;
    499                 if (key.equals(__INCLUDE_REQUEST_URI))  return _requestURI;
    500             }
    501             else if (key.startsWith(__INCLUDE_PREFIX))
    502                     return null;
    503
    504             if (key.equals(__INCLUDE_JETTY))
    505                 return Boolean.TRUE;
    506
    507             return _attr.getAttribute(key);
    508         }
    509
    510         /* ------------------------------------------------------------ */
    511         public Enumeration getAttributeNames()
    512         {
    513             HashSet set=new HashSet();
    514             Enumeration e=_attr.getAttributeNames();
    515             while(e.hasMoreElements())
    516             {
    517                 String name=(String)e.nextElement();
    518                 if (!name.startsWith(__INCLUDE_PREFIX))
    519                     set.add(name);
    520             }
    521
    522             if (_named==null)
    523             {
    524                 if (_pathInfo!=null)
    525                     set.add(__INCLUDE_PATH_INFO);
    526                 else
    527                     set.remove(__INCLUDE_PATH_INFO);
    528                 set.add(__INCLUDE_REQUEST_URI);
    529                 set.add(__INCLUDE_SERVLET_PATH);
    530                 set.add(__INCLUDE_CONTEXT_PATH);
    531                 if (_query!=null)
    532                     set.add(__INCLUDE_QUERY_STRING);
    533                 else
    534                     set.remove(__INCLUDE_QUERY_STRING);
    535             }
    536
    537             return Collections.enumeration(set);
    538         }
    539
    540         /* ------------------------------------------------------------ */
    541         public void setAttribute(String key, Object value)
    542         {
    543             if (_named==null && key.startsWith("javax.servlet."))
    544             {
    545                 if (key.equals(__INCLUDE_PATH_INFO))         _pathInfo=(String)value;
    546                 else if (key.equals(__INCLUDE_REQUEST_URI))  _requestURI=(String)value;
    547                 else if (key.equals(__INCLUDE_SERVLET_PATH)) _servletPath=(String)value;
    548                 else if (key.equals(__INCLUDE_CONTEXT_PATH)) _contextPath=(String)value;
    549                 else if (key.equals(__INCLUDE_QUERY_STRING)) _query=(String)value;
    550                 else if (value==null)
    551                     _attr.removeAttribute(key);
    552                 else
    553                     _attr.setAttribute(key,value);
    554             }
    555             else if (value==null)
    556                 _attr.removeAttribute(key);
    557             else
    558                 _attr.setAttribute(key,value);
    559         }
    560
    561         /* ------------------------------------------------------------ */
    562         public String toString()
    563         {
    564             return "INCLUDE+"+_attr.toString();
    565         }
    566
    567         /* ------------------------------------------------------------ */
    568         public void clearAttributes()
    569         {
    570             throw new IllegalStateException();
    571         }
    572
    573         /* ------------------------------------------------------------ */
    574         public void removeAttribute(String name)
    575         {
    576             setAttribute(name,null);
    577         }
    578     }
    579 };