2 // ========================================================================
3 // Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
4 // ------------------------------------------------------------------------
5 // All rights reserved. This program and the accompanying materials
6 // are made available under the terms of the Eclipse Public License v1.0
7 // and Apache License v2.0 which accompanies this distribution.
9 // The Eclipse Public License is available at
10 // http://www.eclipse.org/legal/epl-v10.html
12 // The Apache License v2.0 is available at
13 // http://www.opensource.org/licenses/apache2.0.php
15 // You may elect to redistribute this code under either of these licenses.
16 // ========================================================================
19 package org.eclipse.jetty.server;
21 import java.io.IOException;
22 import java.util.Collections;
23 import java.util.Enumeration;
24 import java.util.HashSet;
25 import javax.servlet.DispatcherType;
26 import javax.servlet.RequestDispatcher;
27 import javax.servlet.ServletException;
28 import javax.servlet.ServletRequest;
29 import javax.servlet.ServletResponse;
30 import javax.servlet.http.HttpServletRequest;
31 import javax.servlet.http.HttpServletResponse;
33 import org.eclipse.jetty.server.handler.ContextHandler;
34 import org.eclipse.jetty.util.Attributes;
35 import org.eclipse.jetty.util.MultiMap;
37 public class Dispatcher implements RequestDispatcher
39 /** Dispatch include attribute names */
40 public final static String __INCLUDE_PREFIX="javax.servlet.include.";
42 /** Dispatch include attribute names */
43 public final static String __FORWARD_PREFIX="javax.servlet.forward.";
45 private final ContextHandler _contextHandler;
46 private final String _uri;
47 private final String _path;
48 private final String _query;
49 private final String _named;
51 public Dispatcher(ContextHandler contextHandler, String uri, String pathInContext, String query)
53 _contextHandler=contextHandler;
60 public Dispatcher(ContextHandler contextHandler, String name) throws IllegalStateException
62 _contextHandler=contextHandler;
70 public void forward(ServletRequest request, ServletResponse response) throws ServletException, IOException
72 forward(request, response, DispatcherType.FORWARD);
75 public void error(ServletRequest request, ServletResponse response) throws ServletException, IOException
77 forward(request, response, DispatcherType.ERROR);
81 public void include(ServletRequest request, ServletResponse response) throws ServletException, IOException
83 Request baseRequest=(request instanceof Request)?((Request)request):HttpChannel.getCurrentHttpChannel().getRequest();
85 if (!(request instanceof HttpServletRequest))
86 request = new ServletRequestHttpWrapper(request);
87 if (!(response instanceof HttpServletResponse))
88 response = new ServletResponseHttpWrapper(response);
90 final DispatcherType old_type = baseRequest.getDispatcherType();
91 final Attributes old_attr=baseRequest.getAttributes();
92 final MultiMap<String> old_query_params=baseRequest.getQueryParameters();
95 baseRequest.setDispatcherType(DispatcherType.INCLUDE);
96 baseRequest.getResponse().include();
99 _contextHandler.handle(_named,baseRequest, (HttpServletRequest)request, (HttpServletResponse)response);
103 IncludeAttributes attr = new IncludeAttributes(old_attr);
105 attr._requestURI=_uri;
106 attr._contextPath=_contextHandler.getContextPath();
107 attr._servletPath=null; // set by ServletHandler
108 attr._pathInfo=_path;
112 baseRequest.mergeQueryParameters(_query, false);
113 baseRequest.setAttributes(attr);
115 _contextHandler.handle(_path, baseRequest, (HttpServletRequest)request, (HttpServletResponse)response);
120 baseRequest.setAttributes(old_attr);
121 baseRequest.getResponse().included();
122 baseRequest.setQueryParameters(old_query_params);
123 baseRequest.resetParameters();
124 baseRequest.setDispatcherType(old_type);
128 protected void forward(ServletRequest request, ServletResponse response, DispatcherType dispatch) throws ServletException, IOException
130 Request baseRequest=(request instanceof Request)?((Request)request):HttpChannel.getCurrentHttpChannel().getRequest();
131 Response base_response=baseRequest.getResponse();
132 base_response.resetForForward();
134 if (!(request instanceof HttpServletRequest))
135 request = new ServletRequestHttpWrapper(request);
136 if (!(response instanceof HttpServletResponse))
137 response = new ServletResponseHttpWrapper(response);
139 final boolean old_handled=baseRequest.isHandled();
140 final String old_uri=baseRequest.getRequestURI();
141 final String old_context_path=baseRequest.getContextPath();
142 final String old_servlet_path=baseRequest.getServletPath();
143 final String old_path_info=baseRequest.getPathInfo();
144 final String old_query=baseRequest.getQueryString();
145 final MultiMap<String> old_query_params=baseRequest.getQueryParameters();
146 final Attributes old_attr=baseRequest.getAttributes();
147 final DispatcherType old_type=baseRequest.getDispatcherType();
151 baseRequest.setHandled(false);
152 baseRequest.setDispatcherType(dispatch);
156 _contextHandler.handle(_named, baseRequest, (HttpServletRequest)request, (HttpServletResponse)response);
160 ForwardAttributes attr = new ForwardAttributes(old_attr);
162 //If we have already been forwarded previously, then keep using the established
163 //original value. Otherwise, this is the first forward and we need to establish the values.
164 //Note: the established value on the original request for pathInfo and
165 //for queryString is allowed to be null, but cannot be null for the other values.
166 if (old_attr.getAttribute(FORWARD_REQUEST_URI) != null)
168 attr._pathInfo=(String)old_attr.getAttribute(FORWARD_PATH_INFO);
169 attr._query=(String)old_attr.getAttribute(FORWARD_QUERY_STRING);
170 attr._requestURI=(String)old_attr.getAttribute(FORWARD_REQUEST_URI);
171 attr._contextPath=(String)old_attr.getAttribute(FORWARD_CONTEXT_PATH);
172 attr._servletPath=(String)old_attr.getAttribute(FORWARD_SERVLET_PATH);
176 attr._pathInfo=old_path_info;
177 attr._query=old_query;
178 attr._requestURI=old_uri;
179 attr._contextPath=old_context_path;
180 attr._servletPath=old_servlet_path;
183 baseRequest.setRequestURI(_uri);
184 baseRequest.setContextPath(_contextHandler.getContextPath());
185 baseRequest.setServletPath(null);
186 baseRequest.setPathInfo(_uri);
188 baseRequest.mergeQueryParameters(_query, true);
189 baseRequest.setAttributes(attr);
191 _contextHandler.handle(_path, baseRequest, (HttpServletRequest)request, (HttpServletResponse)response);
193 if (!baseRequest.getHttpChannelState().isAsync())
194 commitResponse(response,baseRequest);
199 baseRequest.setHandled(old_handled);
200 baseRequest.setRequestURI(old_uri);
201 baseRequest.setContextPath(old_context_path);
202 baseRequest.setServletPath(old_servlet_path);
203 baseRequest.setPathInfo(old_path_info);
204 baseRequest.setQueryString(old_query);
205 baseRequest.setQueryParameters(old_query_params);
206 baseRequest.resetParameters();
207 baseRequest.setAttributes(old_attr);
208 baseRequest.setDispatcherType(old_type);
212 private void commitResponse(ServletResponse response, Request baseRequest) throws IOException
214 if (baseRequest.getResponse().isWriting())
218 response.getWriter().close();
220 catch (IllegalStateException e)
222 response.getOutputStream().close();
229 response.getOutputStream().close();
231 catch (IllegalStateException e)
233 response.getWriter().close();
238 private class ForwardAttributes implements Attributes
240 final Attributes _attr;
248 ForwardAttributes(Attributes attributes)
253 /* ------------------------------------------------------------ */
255 public Object getAttribute(String key)
257 if (Dispatcher.this._named==null)
259 if (key.equals(FORWARD_PATH_INFO))
261 if (key.equals(FORWARD_REQUEST_URI))
263 if (key.equals(FORWARD_SERVLET_PATH))
265 if (key.equals(FORWARD_CONTEXT_PATH))
267 if (key.equals(FORWARD_QUERY_STRING))
271 if (key.startsWith(__INCLUDE_PREFIX))
274 return _attr.getAttribute(key);
278 public Enumeration<String> getAttributeNames()
280 HashSet<String> set=new HashSet<>();
281 Enumeration<String> e=_attr.getAttributeNames();
282 while(e.hasMoreElements())
284 String name=e.nextElement();
285 if (!name.startsWith(__INCLUDE_PREFIX) &&
286 !name.startsWith(__FORWARD_PREFIX))
293 set.add(FORWARD_PATH_INFO);
295 set.remove(FORWARD_PATH_INFO);
296 set.add(FORWARD_REQUEST_URI);
297 set.add(FORWARD_SERVLET_PATH);
298 set.add(FORWARD_CONTEXT_PATH);
300 set.add(FORWARD_QUERY_STRING);
302 set.remove(FORWARD_QUERY_STRING);
305 return Collections.enumeration(set);
309 public void setAttribute(String key, Object value)
311 if (_named==null && key.startsWith("javax.servlet."))
313 if (key.equals(FORWARD_PATH_INFO))
314 _pathInfo=(String)value;
315 else if (key.equals(FORWARD_REQUEST_URI))
316 _requestURI=(String)value;
317 else if (key.equals(FORWARD_SERVLET_PATH))
318 _servletPath=(String)value;
319 else if (key.equals(FORWARD_CONTEXT_PATH))
320 _contextPath=(String)value;
321 else if (key.equals(FORWARD_QUERY_STRING))
322 _query=(String)value;
324 else if (value==null)
325 _attr.removeAttribute(key);
327 _attr.setAttribute(key,value);
329 else if (value==null)
330 _attr.removeAttribute(key);
332 _attr.setAttribute(key,value);
336 public String toString()
338 return "FORWARD+"+_attr.toString();
342 public void clearAttributes()
344 throw new IllegalStateException();
348 public void removeAttribute(String name)
350 setAttribute(name,null);
354 private class IncludeAttributes implements Attributes
356 final Attributes _attr;
364 IncludeAttributes(Attributes attributes)
370 public Object getAttribute(String key)
372 if (Dispatcher.this._named==null)
374 if (key.equals(INCLUDE_PATH_INFO)) return _pathInfo;
375 if (key.equals(INCLUDE_SERVLET_PATH)) return _servletPath;
376 if (key.equals(INCLUDE_CONTEXT_PATH)) return _contextPath;
377 if (key.equals(INCLUDE_QUERY_STRING)) return _query;
378 if (key.equals(INCLUDE_REQUEST_URI)) return _requestURI;
380 else if (key.startsWith(__INCLUDE_PREFIX))
384 return _attr.getAttribute(key);
388 public Enumeration<String> getAttributeNames()
390 HashSet<String> set=new HashSet<>();
391 Enumeration<String> e=_attr.getAttributeNames();
392 while(e.hasMoreElements())
394 String name=e.nextElement();
395 if (!name.startsWith(__INCLUDE_PREFIX))
402 set.add(INCLUDE_PATH_INFO);
404 set.remove(INCLUDE_PATH_INFO);
405 set.add(INCLUDE_REQUEST_URI);
406 set.add(INCLUDE_SERVLET_PATH);
407 set.add(INCLUDE_CONTEXT_PATH);
409 set.add(INCLUDE_QUERY_STRING);
411 set.remove(INCLUDE_QUERY_STRING);
414 return Collections.enumeration(set);
418 public void setAttribute(String key, Object value)
420 if (_named==null && key.startsWith("javax.servlet."))
422 if (key.equals(INCLUDE_PATH_INFO)) _pathInfo=(String)value;
423 else if (key.equals(INCLUDE_REQUEST_URI)) _requestURI=(String)value;
424 else if (key.equals(INCLUDE_SERVLET_PATH)) _servletPath=(String)value;
425 else if (key.equals(INCLUDE_CONTEXT_PATH)) _contextPath=(String)value;
426 else if (key.equals(INCLUDE_QUERY_STRING)) _query=(String)value;
427 else if (value==null)
428 _attr.removeAttribute(key);
430 _attr.setAttribute(key,value);
432 else if (value==null)
433 _attr.removeAttribute(key);
435 _attr.setAttribute(key,value);
439 public String toString()
441 return "INCLUDE+"+_attr.toString();
445 public void clearAttributes()
447 throw new IllegalStateException();
451 public void removeAttribute(String name)
453 setAttribute(name,null);