craigmcc 01/07/16 17:14:17 Modified: catalina/src/share/org/apache/catalina/servlets InvokerServlet.java LocalStrings.properties Added: catalina/src/share/org/apache/catalina/servlets InvokerHttpRequest.java Log: Modify the way that the invoker servlet works. Previously, the invoker servlet would dynamically create a new Wrapper (and associated servlet mapping) on the first request to a particular servlet, and then do a RequestDispatcher.forward() to utilize the new Wrapper immediately. This causes problems, though, when the invoker is itself included via a RequestDispatcher -- the semantics of RequestDispatcher.forward() say that the response is closed after the forwarded-to servlet returns, so that any output subsequently added by the including servlet would be ignored. Now, the invoker servlet will still create a new Wrapper and mapping as it did before (these are used on all subsequent requests to the same servlet). However, instead of calling RequestDispatcher.forward(), a new servlet instance is allocated, invoked, and deallocated directly. PR: Bugzilla #1902 Submitted by: Jason Hunter <[EMAIL PROTECTED]> Revision Changes Path 1.6 +85 -51 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/servlets/InvokerServlet.java Index: InvokerServlet.java =================================================================== RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/servlets/InvokerServlet.java,v retrieving revision 1.5 retrieving revision 1.6 diff -u -r1.5 -r1.6 --- InvokerServlet.java 2001/05/16 17:56:46 1.5 +++ InvokerServlet.java 2001/07/17 00:14:17 1.6 @@ -1,7 +1,7 @@ /* - * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/servlets/InvokerServlet.java,v 1.5 2001/05/16 17:56:46 remm Exp $ - * $Revision: 1.5 $ - * $Date: 2001/05/16 17:56:46 $ + * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/servlets/InvokerServlet.java,v 1.6 2001/07/17 00:14:17 craigmcc Exp $ + * $Revision: 1.6 $ + * $Date: 2001/07/17 00:14:17 $ * * ==================================================================== * @@ -86,7 +86,7 @@ * in the web application deployment descriptor. * * @author Craig R. McClanahan - * @version $Revision: 1.5 $ $Date: 2001/05/16 17:56:46 $ + * @version $Revision: 1.6 $ $Date: 2001/07/17 00:14:17 $ */ public final class InvokerServlet @@ -367,58 +367,92 @@ } } - // Ensure that we can actually allocate and release an instance - try { - Servlet instance = wrapper.allocate(); - wrapper.deallocate(instance); - } catch (ServletException e) { - log("serveRequest.load", e); - context.removeServletMapping(pattern); - context.removeChild(wrapper); - Throwable rootCause = e.getRootCause(); - if (rootCause == null) - rootCause = e; - if (included) - throw new ServletException - (sm.getString("invokerServlet.cannotLoad", - inRequestURI), rootCause); - if ((rootCause != null) && - (rootCause instanceof ClassNotFoundException)) { - response.sendError(HttpServletResponse.SC_NOT_FOUND, - inRequestURI); - } else { - response.sendError - (HttpServletResponse.SC_INTERNAL_SERVER_ERROR, - inRequestURI); - } - return; - } catch (Throwable t) { - log("serveRequest.load", t); - context.removeServletMapping(pattern); - context.removeChild(wrapper); - if (included) - throw new ServletException - (sm.getString("invokerServlet.cannotLoad", - inRequestURI), t); - response.sendError - (HttpServletResponse.SC_INTERNAL_SERVER_ERROR, - inRequestURI); - return; - } - } - // Pass this request on to the identified or newly created wrapper + // Create a request wrapper to pass on to the invoked servlet + InvokerHttpRequest wrequest = + new InvokerHttpRequest(request); StringBuffer sb = new StringBuffer(inServletPath); sb.append("/"); sb.append(servletClass); - sb.append(pathInfo); - String dispatcherPath = sb.toString(); - if (debug >= 1) - log("serveRequest: Forwarding to '" + dispatcherPath + "'"); - RequestDispatcher rd = - getServletContext().getRequestDispatcher(dispatcherPath); - rd.forward(request, response); + wrequest.setServletPath(sb.toString()); + if ((pathInfo == null) || (pathInfo.length() < 1)) + wrequest.setPathInfo(null); + else + wrequest.setPathInfo(pathInfo); + wrequest.setQueryString(request.getQueryString()); + + // Allocate a servlet instance to perform this request + Servlet instance = null; + try { + instance = wrapper.allocate(); + } catch (ServletException e) { + log(sm.getString("invokerServlet.allocate", inRequestURI), e); + context.removeServletMapping(pattern); + context.removeChild(wrapper); + Throwable rootCause = e.getRootCause(); + if (rootCause == null) + rootCause = e; + if (rootCause instanceof ClassNotFoundException) { + response.sendError(HttpServletResponse.SC_NOT_FOUND, + inRequestURI); + return; + } else if (rootCause instanceof IOException) { + throw (IOException) rootCause; + } else if (rootCause instanceof RuntimeException) { + throw (RuntimeException) rootCause; + } else if (rootCause instanceof ServletException) { + throw (ServletException) rootCause; + } else { + throw new ServletException + (sm.getString("invokerServlet.allocate", inRequestURI), + rootCause); + } + } catch (Throwable e) { + log(sm.getString("invokerServlet.allocate", inRequestURI), e); + context.removeServletMapping(pattern); + context.removeChild(wrapper); + throw new ServletException + (sm.getString("invokerServlet.allocate", inRequestURI), e); + } + + // Invoke the service() method of the allocated servlet + try { + instance.service(wrequest, response); + } catch (IOException e) { + try { + wrapper.deallocate(instance); + } catch (Throwable f) { + ; + } + throw e; + } catch (ServletException e) { + try { + wrapper.deallocate(instance); + } catch (Throwable f) { + ; + } + throw e; + } catch (RuntimeException e) { + try { + wrapper.deallocate(instance); + } catch (Throwable f) { + ; + } + throw e; + } + + // Deallocate the allocated servlet instance + try { + wrapper.deallocate(instance); + } catch (ServletException e) { + log(sm.getString("invokerServlet.deallocate", inRequestURI), e); + throw e; + } catch (Throwable e) { + log(sm.getString("invokerServlet.deallocate", inRequestURI), e); + throw new ServletException + (sm.getString("invokerServlet.deallocate", inRequestURI), e); + } } 1.8 +2 -0 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/servlets/LocalStrings.properties Index: LocalStrings.properties =================================================================== RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/servlets/LocalStrings.properties,v retrieving revision 1.7 retrieving revision 1.8 diff -u -r1.7 -r1.8 --- LocalStrings.properties 2001/05/14 00:02:32 1.7 +++ LocalStrings.properties 2001/07/17 00:14:17 1.8 @@ -2,7 +2,9 @@ defaultservlet.upto=Up to: defaultservlet.subdirectories=Subdirectories: defaultservlet.files=Files: +invokerServlet.allocate=Cannot allocate servlet instance for path {0} invokerServlet.cannotCreate=Cannot create servlet wrapper for path {0} +invokerServlet.deallocate=Cannot deallocate servlet instance for path {0} invokerServlet.invalidPath=No servlet name or class was specified in path {0} invokerServlet.notNamed=Cannot call invoker servlet with a named dispatcher invokerServlet.noWrapper=Container has not called setWrapper() for this servlet 1.1 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/servlets/InvokerHttpRequest.java Index: InvokerHttpRequest.java =================================================================== /* * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/servlets/InvokerHttpRequest.java,v 1.1 2001/07/17 00:14:16 craigmcc Exp $ * $Revision: 1.1 $ * $Date: 2001/07/17 00:14:16 $ * * ==================================================================== * * The Apache Software License, Version 1.1 * * Copyright (c) 1999 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowlegement: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowlegement may appear in the software itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software * Foundation" must not be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact [EMAIL PROTECTED] * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. * * [Additional notices, if required by prior licensing conditions] * */ package org.apache.catalina.servlets; import java.io.IOException; import java.util.ArrayList; import java.util.Enumeration; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import org.apache.catalina.Globals; import org.apache.catalina.HttpRequest; import org.apache.catalina.connector.HttpRequestFacade; import org.apache.catalina.util.Enumerator; import org.apache.catalina.util.RequestUtil; import org.apache.catalina.util.StringManager; /** * Wrapper around a <code>javax.servlet.http.HttpServletRequest</code> * utilized when <code>InvokerServlet</code> processes the initial request * for an invoked servlet. Subsequent requests will be mapped directly * to the servlet, because a new servlet mapping will have been created. * * @author Craig R. McClanahan * @version $Revision: 1.1 $ $Date: 2001/07/17 00:14:16 $ */ class InvokerHttpRequest extends HttpServletRequestWrapper { // ----------------------------------------------------------- Constructors /** * Construct a new wrapped request around the specified servlet request. * * @param request The servlet request being wrapped */ public InvokerHttpRequest(HttpServletRequest request) { super(request); this.contextPath = request.getContextPath(); this.pathInfo = request.getPathInfo(); this.queryString = request.getQueryString(); this.requestURI = request.getRequestURI(); this.servletPath = request.getServletPath(); } // ----------------------------------------------------- Instance Variables /** * The context path for this request. */ protected String contextPath = null; /** * Descriptive information about this implementation. */ protected static final String info = "org.apache.catalina.servlets.InvokerHttpRequest/1.0"; /** * The path information for this request. */ protected String pathInfo = null; /** * The query string for this request. */ protected String queryString = null; /** * The request URI for this request. */ protected String requestURI = null; /** * The servlet path for this request. */ protected String servletPath = null; /** * The string manager for this package. */ protected static StringManager sm = StringManager.getManager(Constants.Package); // --------------------------------------------- HttpServletRequest Methods /** * Override the <code>getContextPath()</code> method of the wrapped * request. */ public String getContextPath() { return (this.contextPath); } /** * Override the <code>getPathInfo()</code> method of the wrapped request. */ public String getPathInfo() { return (this.pathInfo); } /** * Override the <code>getQueryString()</code> method of the wrapped * request. */ public String getQueryString() { return (this.queryString); } /** * Override the <code>getRequestURI()</code> method of the wrapped * request. */ public String getRequestURI() { return (this.requestURI); } /** * Override the <code>getServletPath()</code> method of the wrapped * request. */ public String getServletPath() { return (this.servletPath); } // -------------------------------------------------------- Package Methods /** * Return descriptive information about this implementation. */ public String getInfo() { return (this.info); } /** * Set the context path for this request. * * @param contextPath The new context path */ void setContextPath(String contextPath) { this.contextPath = contextPath; } /** * Set the path information for this request. * * @param pathInfo The new path info */ void setPathInfo(String pathInfo) { this.pathInfo = pathInfo; } /** * Set the query string for this request. * * @param queryString The new query string */ void setQueryString(String queryString) { this.queryString = queryString; } /** * Set the request URI for this request. * * @param requestURI The new request URI */ void setRequestURI(String requestURI) { this.requestURI = requestURI; } /** * Set the servlet path for this request. * * @param servletPath The new servlet path */ void setServletPath(String servletPath) { this.servletPath = servletPath; } }