View Javadoc

1   // ========================================================================
2   // Copyright (c) 1999-2009 Mort Bay Consulting Pty. Ltd.
3   // ------------------------------------------------------------------------
4   // All rights reserved. This program and the accompanying materials
5   // are made available under the terms of the Eclipse Public License v1.0
6   // and Apache License v2.0 which accompanies this distribution.
7   // The Eclipse Public License is available at 
8   // http://www.eclipse.org/legal/epl-v10.html
9   // The Apache License v2.0 is available at
10  // http://www.opensource.org/licenses/apache2.0.php
11  // You may elect to redistribute this code under either of these licenses. 
12  // ========================================================================
13  
14  package org.eclipse.jetty.server;
15  
16  import java.io.IOException;
17  import java.util.Collections;
18  import java.util.Enumeration;
19  import java.util.HashSet;
20  import java.util.Iterator;
21  import java.util.Map;
22  
23  import javax.servlet.DispatcherType;
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.eclipse.jetty.server.handler.ContextHandler;
32  import org.eclipse.jetty.util.Attributes;
33  import org.eclipse.jetty.util.LazyList;
34  import org.eclipse.jetty.util.MultiMap;
35  import org.eclipse.jetty.util.UrlEncoded;
36  
37  /* ------------------------------------------------------------ */
38  /** Servlet RequestDispatcher.
39   * 
40   * 
41   */
42  public class Dispatcher implements RequestDispatcher
43  {
44      /** Dispatch include attribute names */
45      public final static String __INCLUDE_PREFIX="javax.servlet.include.";
46  
47      /** Dispatch include attribute names */
48      public final static String __FORWARD_PREFIX="javax.servlet.forward.";
49  
50      /** JSP attributes */
51      public final static String __JSP_FILE="org.apache.catalina.jsp_file";
52  
53      /* ------------------------------------------------------------ */
54      private final ContextHandler _contextHandler;
55      private final String _uri;
56      private final String _path;
57      private final String _dQuery;
58      private final String _named;
59      
60      /* ------------------------------------------------------------ */
61      /**
62       * @param contextHandler
63       * @param uri
64       * @param pathInContext
65       * @param query
66       */
67      public Dispatcher(ContextHandler contextHandler, String uri, String pathInContext, String query)
68      {
69          _contextHandler=contextHandler;
70          _uri=uri;
71          _path=pathInContext;
72          _dQuery=query;
73          _named=null;
74      }
75  
76  
77      /* ------------------------------------------------------------ */
78      /** Constructor. 
79       * @param contextHandler
80       * @param name
81       */
82      public Dispatcher(ContextHandler contextHandler,String name)
83          throws IllegalStateException
84      {
85          _contextHandler=contextHandler;
86          _named=name;
87          _uri=null;
88          _path=null;
89          _dQuery=null;
90      }
91      
92      /* ------------------------------------------------------------ */
93      /* 
94       * @see javax.servlet.RequestDispatcher#forward(javax.servlet.ServletRequest, javax.servlet.ServletResponse)
95       */
96      public void forward(ServletRequest request, ServletResponse response) throws ServletException, IOException
97      {
98          forward(request, response, DispatcherType.FORWARD);
99      }
100     
101     /* ------------------------------------------------------------ */
102     /* 
103      * @see javax.servlet.RequestDispatcher#forward(javax.servlet.ServletRequest, javax.servlet.ServletResponse)
104      */
105     public void error(ServletRequest request, ServletResponse response) throws ServletException, IOException
106     {
107         forward(request, response, DispatcherType.ERROR);
108     }
109     
110     /* ------------------------------------------------------------ */
111     /* 
112      * @see javax.servlet.RequestDispatcher#include(javax.servlet.ServletRequest, javax.servlet.ServletResponse)
113      */
114     public void include(ServletRequest request, ServletResponse response) throws ServletException, IOException
115     {
116         Request baseRequest=(request instanceof Request)?((Request)request):HttpConnection.getCurrentConnection().getRequest();
117         request.removeAttribute(__JSP_FILE); // TODO remove when glassfish 1044 is fixed
118         
119         if (!(request instanceof HttpServletRequest))
120             request = new ServletRequestHttpWrapper(request);
121         if (!(response instanceof HttpServletResponse))
122             response = new ServletResponseHttpWrapper(response);
123             
124         
125         // TODO - allow stream or writer????
126         
127         final DispatcherType old_type = baseRequest.getDispatcherType();
128         final Attributes old_attr=baseRequest.getAttributes();
129         MultiMap old_params=baseRequest.getParameters();
130         try
131         {
132             baseRequest.setDispatcherType(DispatcherType.INCLUDE);
133             baseRequest.getConnection().include();
134             if (_named!=null)
135                 _contextHandler.handle(_named,baseRequest, (HttpServletRequest)request, (HttpServletResponse)response);
136             else 
137             {
138                 String query=_dQuery;
139                 
140                 if (query!=null)
141                 {
142                     // force parameter extraction
143                     if (old_params==null)
144                     {
145                         baseRequest.extractParameters();
146                         old_params=baseRequest.getParameters();
147                     }
148                     
149                     MultiMap parameters=new MultiMap();
150                     UrlEncoded.decodeTo(query,parameters,baseRequest.getCharacterEncoding());
151                     
152                     if (old_params!=null && old_params.size()>0)
153                     {
154                         // Merge parameters.
155                         Iterator iter = old_params.entrySet().iterator();
156                         while (iter.hasNext())
157                         {
158                             Map.Entry entry = (Map.Entry)iter.next();
159                             String name=(String)entry.getKey();
160                             Object values=entry.getValue();
161                             for (int i=0;i<LazyList.size(values);i++)
162                                 parameters.add(name, LazyList.get(values, i));
163                         }
164                     }
165                     baseRequest.setParameters(parameters);
166                 }
167                 
168                 IncludeAttributes attr = new IncludeAttributes(old_attr); 
169                 
170                 attr._requestURI=_uri;
171                 attr._contextPath=_contextHandler.getContextPath();
172                 attr._servletPath=null; // set by ServletHandler
173                 attr._pathInfo=_path;
174                 attr._query=query;
175                 
176                 baseRequest.setAttributes(attr);
177                 
178                 _contextHandler.handle(_path,baseRequest, (HttpServletRequest)request, (HttpServletResponse)response);
179             }
180         }
181         finally
182         {
183             baseRequest.setAttributes(old_attr);
184             baseRequest.getConnection().included();
185             baseRequest.setParameters(old_params);
186             baseRequest.setDispatcherType(old_type);
187         }
188     }
189 
190     
191     /* ------------------------------------------------------------ */
192     /* 
193      * @see javax.servlet.RequestDispatcher#forward(javax.servlet.ServletRequest, javax.servlet.ServletResponse)
194      */
195     protected void forward(ServletRequest request, ServletResponse response, DispatcherType dispatch) throws ServletException, IOException
196     {
197         Request baseRequest=(request instanceof Request)?((Request)request):HttpConnection.getCurrentConnection().getRequest();
198         Response base_response=baseRequest.getResponse();
199         response.resetBuffer();
200         base_response.fwdReset();
201         request.removeAttribute(__JSP_FILE); // TODO remove when glassfish 1044 is fixed
202 
203         if (!(request instanceof HttpServletRequest))
204             request = new ServletRequestHttpWrapper(request);
205         if (!(response instanceof HttpServletResponse))
206             response = new ServletResponseHttpWrapper(response);
207         
208         final boolean old_handled=baseRequest.isHandled();
209         final String old_uri=baseRequest.getRequestURI();
210         final String old_context_path=baseRequest.getContextPath();
211         final String old_servlet_path=baseRequest.getServletPath();
212         final String old_path_info=baseRequest.getPathInfo();
213         final String old_query=baseRequest.getQueryString();
214         final Attributes old_attr=baseRequest.getAttributes();
215         final DispatcherType old_type=baseRequest.getDispatcherType();
216         MultiMap<String> old_params=baseRequest.getParameters();
217         
218         try
219         {
220             baseRequest.setHandled(false);
221             baseRequest.setDispatcherType(dispatch);
222             
223             if (_named!=null)
224                 _contextHandler.handle(_named,baseRequest, (HttpServletRequest)request, (HttpServletResponse)response);
225             else 
226             {
227                 
228                 // process any query string from the dispatch URL
229                 String query=_dQuery;
230                 if (query!=null)
231                 {
232                     // force parameter extraction
233                     if (old_params==null)
234                     {
235                         baseRequest.extractParameters();
236                         old_params=baseRequest.getParameters();
237                     }
238                     
239                     baseRequest.mergeQueryString(query);
240                 }
241                 
242                 ForwardAttributes attr = new ForwardAttributes(old_attr); 
243                 
244                 //If we have already been forwarded previously, then keep using the established 
245                 //original value. Otherwise, this is the first forward and we need to establish the values.
246                 //Note: the established value on the original request for pathInfo and
247                 //for queryString is allowed to be null, but cannot be null for the other values.
248                 if (old_attr.getAttribute(FORWARD_REQUEST_URI) != null)
249                 {
250                     attr._pathInfo=(String)old_attr.getAttribute(FORWARD_PATH_INFO);
251                     attr._query=(String)old_attr.getAttribute(FORWARD_QUERY_STRING);
252                     attr._requestURI=(String)old_attr.getAttribute(FORWARD_REQUEST_URI);
253                     attr._contextPath=(String)old_attr.getAttribute(FORWARD_CONTEXT_PATH);
254                     attr._servletPath=(String)old_attr.getAttribute(FORWARD_SERVLET_PATH);
255                 }
256                 else
257                 {
258                     attr._pathInfo=old_path_info;
259                     attr._query=old_query;
260                     attr._requestURI=old_uri;
261                     attr._contextPath=old_context_path;
262                     attr._servletPath=old_servlet_path;
263                 }     
264                 
265                 baseRequest.setRequestURI(_uri);
266                 baseRequest.setContextPath(_contextHandler.getContextPath());
267                 baseRequest.setServletPath(null);
268                 baseRequest.setPathInfo(_uri);
269                 baseRequest.setAttributes(attr);
270                 
271                 _contextHandler.handle(_path,baseRequest, (HttpServletRequest)request, (HttpServletResponse)response);
272                 
273                 if (baseRequest.getResponse().isWriting())
274                 {
275                     try {response.getWriter().close();}
276                     catch(IllegalStateException e) 
277                     { 
278                         response.getOutputStream().close(); 
279                     }
280                 }
281                 else
282                 {
283                     try {response.getOutputStream().close();}
284                     catch(IllegalStateException e) 
285                     { 
286                         response.getWriter().close(); 
287                     }
288                 }
289             }
290         }
291         finally
292         {
293             baseRequest.setHandled(old_handled);
294             baseRequest.setRequestURI(old_uri);
295             baseRequest.setContextPath(old_context_path);
296             baseRequest.setServletPath(old_servlet_path);
297             baseRequest.setPathInfo(old_path_info);
298             baseRequest.setAttributes(old_attr);
299             baseRequest.setParameters(old_params);
300             baseRequest.setQueryString(old_query);
301             baseRequest.setDispatcherType(old_type);
302         }
303     }
304 
305 
306     /* ------------------------------------------------------------ */
307     /* ------------------------------------------------------------ */
308     /* ------------------------------------------------------------ */
309     private class ForwardAttributes implements Attributes
310     {
311         final Attributes _attr;
312         
313         String _requestURI;
314         String _contextPath;
315         String _servletPath;
316         String _pathInfo;
317         String _query;
318         
319         ForwardAttributes(Attributes attributes)
320         {
321             _attr=attributes;
322         }
323         
324         /* ------------------------------------------------------------ */
325         public Object getAttribute(String key)
326         {
327             if (Dispatcher.this._named==null)
328             {
329                 if (key.equals(FORWARD_PATH_INFO))    
330                     return _pathInfo;
331                 if (key.equals(FORWARD_REQUEST_URI))  
332                     return _requestURI;
333                 if (key.equals(FORWARD_SERVLET_PATH)) 
334                     return _servletPath;
335                 if (key.equals(FORWARD_CONTEXT_PATH)) 
336                     return _contextPath;
337                 if (key.equals(FORWARD_QUERY_STRING)) 
338                     return _query;
339             }
340             
341             if (key.startsWith(__INCLUDE_PREFIX))
342                 return null;
343             
344             return _attr.getAttribute(key);
345         }
346         
347         /* ------------------------------------------------------------ */
348         public Enumeration getAttributeNames()
349         {
350             HashSet set=new HashSet();
351             Enumeration e=_attr.getAttributeNames();
352             while(e.hasMoreElements())
353             {
354                 String name=(String)e.nextElement();
355                 if (!name.startsWith(__INCLUDE_PREFIX) &&
356                     !name.startsWith(__FORWARD_PREFIX))
357                     set.add(name);
358             }
359             
360             if (_named==null)
361             {
362                 if (_pathInfo!=null)
363                     set.add(FORWARD_PATH_INFO);
364                 else
365                     set.remove(FORWARD_PATH_INFO);
366                 set.add(FORWARD_REQUEST_URI);
367                 set.add(FORWARD_SERVLET_PATH);
368                 set.add(FORWARD_CONTEXT_PATH);
369                 if (_query!=null)
370                     set.add(FORWARD_QUERY_STRING);
371                 else
372                     set.remove(FORWARD_QUERY_STRING);
373             }
374 
375             return Collections.enumeration(set);
376         }
377         
378         /* ------------------------------------------------------------ */
379         public void setAttribute(String key, Object value)
380         {
381             if (_named==null && key.startsWith("javax.servlet."))
382             {
383                 if (key.equals(FORWARD_PATH_INFO))         
384                     _pathInfo=(String)value;
385                 else if (key.equals(FORWARD_REQUEST_URI))  
386                     _requestURI=(String)value;
387                 else if (key.equals(FORWARD_SERVLET_PATH)) 
388                     _servletPath=(String)value;
389                 else if (key.equals(FORWARD_CONTEXT_PATH)) 
390                     _contextPath=(String)value;
391                 else if (key.equals(FORWARD_QUERY_STRING)) 
392                     _query=(String)value;
393                 
394                 else if (value==null)
395                     _attr.removeAttribute(key);
396                 else
397                     _attr.setAttribute(key,value); 
398             }
399             else if (value==null)
400                 _attr.removeAttribute(key);
401             else
402                 _attr.setAttribute(key,value);
403         }
404         
405         /* ------------------------------------------------------------ */
406         @Override
407         public String toString() 
408         {
409             return "FORWARD+"+_attr.toString();
410         }
411 
412         /* ------------------------------------------------------------ */
413         public void clearAttributes()
414         {
415             throw new IllegalStateException();
416         }
417 
418         /* ------------------------------------------------------------ */
419         public void removeAttribute(String name)
420         {
421             setAttribute(name,null);
422         }
423     }
424 
425     /* ------------------------------------------------------------ */
426     private class IncludeAttributes implements Attributes
427     {
428         final Attributes _attr;
429         
430         String _requestURI;
431         String _contextPath;
432         String _servletPath;
433         String _pathInfo;
434         String _query;
435         
436         IncludeAttributes(Attributes attributes)
437         {
438             _attr=attributes;
439         }
440         
441         /* ------------------------------------------------------------ */
442         /* ------------------------------------------------------------ */
443         /* ------------------------------------------------------------ */
444         public Object getAttribute(String key)
445         {
446             if (Dispatcher.this._named==null)
447             {
448                 if (key.equals(INCLUDE_PATH_INFO))    return _pathInfo;
449                 if (key.equals(INCLUDE_SERVLET_PATH)) return _servletPath;
450                 if (key.equals(INCLUDE_CONTEXT_PATH)) return _contextPath;
451                 if (key.equals(INCLUDE_QUERY_STRING)) return _query;
452                 if (key.equals(INCLUDE_REQUEST_URI))  return _requestURI;
453             }
454             else if (key.startsWith(__INCLUDE_PREFIX)) 
455                     return null;
456             
457             
458             return _attr.getAttribute(key);
459         }
460         
461         /* ------------------------------------------------------------ */
462         public Enumeration getAttributeNames()
463         {
464             HashSet set=new HashSet();
465             Enumeration e=_attr.getAttributeNames();
466             while(e.hasMoreElements())
467             {
468                 String name=(String)e.nextElement();
469                 if (!name.startsWith(__INCLUDE_PREFIX))
470                     set.add(name);
471             }
472             
473             if (_named==null)
474             {
475                 if (_pathInfo!=null)
476                     set.add(INCLUDE_PATH_INFO);
477                 else
478                     set.remove(INCLUDE_PATH_INFO);
479                 set.add(INCLUDE_REQUEST_URI);
480                 set.add(INCLUDE_SERVLET_PATH);
481                 set.add(INCLUDE_CONTEXT_PATH);
482                 if (_query!=null)
483                     set.add(INCLUDE_QUERY_STRING);
484                 else
485                     set.remove(INCLUDE_QUERY_STRING);
486             }
487             
488             return Collections.enumeration(set);
489         }
490         
491         /* ------------------------------------------------------------ */
492         public void setAttribute(String key, Object value)
493         {
494             if (_named==null && key.startsWith("javax.servlet."))
495             {
496                 if (key.equals(INCLUDE_PATH_INFO))         _pathInfo=(String)value;
497                 else if (key.equals(INCLUDE_REQUEST_URI))  _requestURI=(String)value;
498                 else if (key.equals(INCLUDE_SERVLET_PATH)) _servletPath=(String)value;
499                 else if (key.equals(INCLUDE_CONTEXT_PATH)) _contextPath=(String)value;
500                 else if (key.equals(INCLUDE_QUERY_STRING)) _query=(String)value;
501                 else if (value==null)
502                     _attr.removeAttribute(key);
503                 else
504                     _attr.setAttribute(key,value); 
505             }
506             else if (value==null)
507                 _attr.removeAttribute(key);
508             else
509                 _attr.setAttribute(key,value);
510         }
511         
512         /* ------------------------------------------------------------ */
513         @Override
514         public String toString() 
515         {
516             return "INCLUDE+"+_attr.toString();
517         }
518 
519         /* ------------------------------------------------------------ */
520         public void clearAttributes()
521         {
522             throw new IllegalStateException();
523         }
524 
525         /* ------------------------------------------------------------ */
526         public void removeAttribute(String name)
527         {
528             setAttribute(name,null);
529         }
530     }
531 }