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 String old_uri=baseRequest.getRequestURI();
209         final String old_context_path=baseRequest.getContextPath();
210         final String old_servlet_path=baseRequest.getServletPath();
211         final String old_path_info=baseRequest.getPathInfo();
212         final String old_query=baseRequest.getQueryString();
213         final Attributes old_attr=baseRequest.getAttributes();
214         final DispatcherType old_type=baseRequest.getDispatcherType();
215         MultiMap<String> old_params=baseRequest.getParameters();
216         
217         try
218         {
219             baseRequest.setDispatcherType(dispatch);
220             
221             if (_named!=null)
222                 _contextHandler.handle(_named,baseRequest, (HttpServletRequest)request, (HttpServletResponse)response);
223             else 
224             {
225                 
226                 // process any query string from the dispatch URL
227                 String query=_dQuery;
228                 if (query!=null)
229                 {
230                     // force parameter extraction
231                     if (old_params==null)
232                     {
233                         baseRequest.extractParameters();
234                         old_params=baseRequest.getParameters();
235                     }
236                     
237                     baseRequest.mergeQueryString(query);
238                 }
239                 
240                 ForwardAttributes attr = new ForwardAttributes(old_attr); 
241                 
242                 //If we have already been forwarded previously, then keep using the established 
243                 //original value. Otherwise, this is the first forward and we need to establish the values.
244                 //Note: the established value on the original request for pathInfo and
245                 //for queryString is allowed to be null, but cannot be null for the other values.
246                 if (old_attr.getAttribute(FORWARD_REQUEST_URI) != null)
247                 {
248                     attr._pathInfo=(String)old_attr.getAttribute(FORWARD_PATH_INFO);
249                     attr._query=(String)old_attr.getAttribute(FORWARD_QUERY_STRING);
250                     attr._requestURI=(String)old_attr.getAttribute(FORWARD_REQUEST_URI);
251                     attr._contextPath=(String)old_attr.getAttribute(FORWARD_CONTEXT_PATH);
252                     attr._servletPath=(String)old_attr.getAttribute(FORWARD_SERVLET_PATH);
253                 }
254                 else
255                 {
256                     attr._pathInfo=old_path_info;
257                     attr._query=old_query;
258                     attr._requestURI=old_uri;
259                     attr._contextPath=old_context_path;
260                     attr._servletPath=old_servlet_path;
261                 }     
262                 
263                 baseRequest.setRequestURI(_uri);
264                 baseRequest.setContextPath(_contextHandler.getContextPath());
265                 baseRequest.setAttributes(attr);
266                 
267                 _contextHandler.handle(_path,baseRequest, (HttpServletRequest)request, (HttpServletResponse)response);
268                 
269                 if (baseRequest.getResponse().isWriting())
270                 {
271                     try {response.getWriter().close();}
272                     catch(IllegalStateException e) 
273                     { 
274                         response.getOutputStream().close(); 
275                     }
276                 }
277                 else
278                 {
279                     try {response.getOutputStream().close();}
280                     catch(IllegalStateException e) 
281                     { 
282                         response.getWriter().close(); 
283                     }
284                 }
285             }
286         }
287         finally
288         {
289             baseRequest.setRequestURI(old_uri);
290             baseRequest.setContextPath(old_context_path);
291             baseRequest.setServletPath(old_servlet_path);
292             baseRequest.setPathInfo(old_path_info);
293             baseRequest.setAttributes(old_attr);
294             baseRequest.setParameters(old_params);
295             baseRequest.setQueryString(old_query);
296             baseRequest.setDispatcherType(old_type);
297         }
298     }
299 
300 
301     /* ------------------------------------------------------------ */
302     /* ------------------------------------------------------------ */
303     /* ------------------------------------------------------------ */
304     private class ForwardAttributes implements Attributes
305     {
306         final Attributes _attr;
307         
308         String _requestURI;
309         String _contextPath;
310         String _servletPath;
311         String _pathInfo;
312         String _query;
313         
314         ForwardAttributes(Attributes attributes)
315         {
316             _attr=attributes;
317         }
318         
319         /* ------------------------------------------------------------ */
320         public Object getAttribute(String key)
321         {
322             if (Dispatcher.this._named==null)
323             {
324                 if (key.equals(FORWARD_PATH_INFO))    
325                     return _pathInfo;
326                 if (key.equals(FORWARD_REQUEST_URI))  
327                     return _requestURI;
328                 if (key.equals(FORWARD_SERVLET_PATH)) 
329                     return _servletPath;
330                 if (key.equals(FORWARD_CONTEXT_PATH)) 
331                     return _contextPath;
332                 if (key.equals(FORWARD_QUERY_STRING)) 
333                     return _query;
334             }
335             
336             if (key.startsWith(__INCLUDE_PREFIX))
337                 return null;
338             
339             return _attr.getAttribute(key);
340         }
341         
342         /* ------------------------------------------------------------ */
343         public Enumeration getAttributeNames()
344         {
345             HashSet set=new HashSet();
346             Enumeration e=_attr.getAttributeNames();
347             while(e.hasMoreElements())
348             {
349                 String name=(String)e.nextElement();
350                 if (!name.startsWith(__INCLUDE_PREFIX) &&
351                     !name.startsWith(__FORWARD_PREFIX))
352                     set.add(name);
353             }
354             
355             if (_named==null)
356             {
357                 if (_pathInfo!=null)
358                     set.add(FORWARD_PATH_INFO);
359                 else
360                     set.remove(FORWARD_PATH_INFO);
361                 set.add(FORWARD_REQUEST_URI);
362                 set.add(FORWARD_SERVLET_PATH);
363                 set.add(FORWARD_CONTEXT_PATH);
364                 if (_query!=null)
365                     set.add(FORWARD_QUERY_STRING);
366                 else
367                     set.remove(FORWARD_QUERY_STRING);
368             }
369 
370             return Collections.enumeration(set);
371         }
372         
373         /* ------------------------------------------------------------ */
374         public void setAttribute(String key, Object value)
375         {
376             if (_named==null && key.startsWith("javax.servlet."))
377             {
378                 if (key.equals(FORWARD_PATH_INFO))         
379                     _pathInfo=(String)value;
380                 else if (key.equals(FORWARD_REQUEST_URI))  
381                     _requestURI=(String)value;
382                 else if (key.equals(FORWARD_SERVLET_PATH)) 
383                     _servletPath=(String)value;
384                 else if (key.equals(FORWARD_CONTEXT_PATH)) 
385                     _contextPath=(String)value;
386                 else if (key.equals(FORWARD_QUERY_STRING)) 
387                     _query=(String)value;
388                 
389                 else if (value==null)
390                     _attr.removeAttribute(key);
391                 else
392                     _attr.setAttribute(key,value); 
393             }
394             else if (value==null)
395                 _attr.removeAttribute(key);
396             else
397                 _attr.setAttribute(key,value);
398         }
399         
400         /* ------------------------------------------------------------ */
401         @Override
402         public String toString() 
403         {
404             return "FORWARD+"+_attr.toString();
405         }
406 
407         /* ------------------------------------------------------------ */
408         public void clearAttributes()
409         {
410             throw new IllegalStateException();
411         }
412 
413         /* ------------------------------------------------------------ */
414         public void removeAttribute(String name)
415         {
416             setAttribute(name,null);
417         }
418     }
419 
420     /* ------------------------------------------------------------ */
421     private class IncludeAttributes implements Attributes
422     {
423         final Attributes _attr;
424         
425         String _requestURI;
426         String _contextPath;
427         String _servletPath;
428         String _pathInfo;
429         String _query;
430         
431         IncludeAttributes(Attributes attributes)
432         {
433             _attr=attributes;
434         }
435         
436         /* ------------------------------------------------------------ */
437         /* ------------------------------------------------------------ */
438         /* ------------------------------------------------------------ */
439         public Object getAttribute(String key)
440         {
441             if (Dispatcher.this._named==null)
442             {
443                 if (key.equals(INCLUDE_PATH_INFO))    return _pathInfo;
444                 if (key.equals(INCLUDE_SERVLET_PATH)) return _servletPath;
445                 if (key.equals(INCLUDE_CONTEXT_PATH)) return _contextPath;
446                 if (key.equals(INCLUDE_QUERY_STRING)) return _query;
447                 if (key.equals(INCLUDE_REQUEST_URI))  return _requestURI;
448             }
449             else if (key.startsWith(__INCLUDE_PREFIX)) 
450                     return null;
451             
452             
453             return _attr.getAttribute(key);
454         }
455         
456         /* ------------------------------------------------------------ */
457         public Enumeration getAttributeNames()
458         {
459             HashSet set=new HashSet();
460             Enumeration e=_attr.getAttributeNames();
461             while(e.hasMoreElements())
462             {
463                 String name=(String)e.nextElement();
464                 if (!name.startsWith(__INCLUDE_PREFIX))
465                     set.add(name);
466             }
467             
468             if (_named==null)
469             {
470                 if (_pathInfo!=null)
471                     set.add(INCLUDE_PATH_INFO);
472                 else
473                     set.remove(INCLUDE_PATH_INFO);
474                 set.add(INCLUDE_REQUEST_URI);
475                 set.add(INCLUDE_SERVLET_PATH);
476                 set.add(INCLUDE_CONTEXT_PATH);
477                 if (_query!=null)
478                     set.add(INCLUDE_QUERY_STRING);
479                 else
480                     set.remove(INCLUDE_QUERY_STRING);
481             }
482             
483             return Collections.enumeration(set);
484         }
485         
486         /* ------------------------------------------------------------ */
487         public void setAttribute(String key, Object value)
488         {
489             if (_named==null && key.startsWith("javax.servlet."))
490             {
491                 if (key.equals(INCLUDE_PATH_INFO))         _pathInfo=(String)value;
492                 else if (key.equals(INCLUDE_REQUEST_URI))  _requestURI=(String)value;
493                 else if (key.equals(INCLUDE_SERVLET_PATH)) _servletPath=(String)value;
494                 else if (key.equals(INCLUDE_CONTEXT_PATH)) _contextPath=(String)value;
495                 else if (key.equals(INCLUDE_QUERY_STRING)) _query=(String)value;
496                 else if (value==null)
497                     _attr.removeAttribute(key);
498                 else
499                     _attr.setAttribute(key,value); 
500             }
501             else if (value==null)
502                 _attr.removeAttribute(key);
503             else
504                 _attr.setAttribute(key,value);
505         }
506         
507         /* ------------------------------------------------------------ */
508         @Override
509         public String toString() 
510         {
511             return "INCLUDE+"+_attr.toString();
512         }
513 
514         /* ------------------------------------------------------------ */
515         public void clearAttributes()
516         {
517             throw new IllegalStateException();
518         }
519 
520         /* ------------------------------------------------------------ */
521         public void removeAttribute(String name)
522         {
523             setAttribute(name,null);
524         }
525     }
526 }