You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by co...@apache.org on 2001/02/06 07:35:56 UTC

cvs commit: jakarta-tomcat/src/facade22/org/apache/tomcat/facade RequestDispatcherImpl.java

costin      01/02/05 22:35:56

  Modified:    src/facade22/org/apache/tomcat/facade
                        RequestDispatcherImpl.java
  Log:
  A bigger change in RequestDispatcherImpl:
  
  - the parameter manipulation ( by using access to the internal representation)
  is removed
  - Parameters is used to provide merging query parameter and restoring the
  old parameters ( same mechanism as before - a stack, but no garbage is
  generated in the common case ).
  
  This also includes few changes needed to deal with the exceptions as
  requested by the spec.
  
  Revision  Changes    Path
  1.15      +156 -229  jakarta-tomcat/src/facade22/org/apache/tomcat/facade/RequestDispatcherImpl.java
  
  Index: RequestDispatcherImpl.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat/src/facade22/org/apache/tomcat/facade/RequestDispatcherImpl.java,v
  retrieving revision 1.14
  retrieving revision 1.15
  diff -u -r1.14 -r1.15
  --- RequestDispatcherImpl.java	2001/01/28 19:45:52	1.14
  +++ RequestDispatcherImpl.java	2001/02/06 06:35:55	1.15
  @@ -63,6 +63,7 @@
   import org.apache.tomcat.core.*;
   import org.apache.tomcat.util.StringManager;
   import org.apache.tomcat.util.compat.*;
  +import org.apache.tomcat.util.http.*;
   import java.io.*;
   import java.util.*;
   import java.security.*;
  @@ -100,11 +101,26 @@
    * @author costin@dnt.ro
    */
   final class RequestDispatcherImpl implements RequestDispatcher {
  +    static final boolean debug=true;
       // Use the strings from core
       private static StringManager sm = StringManager.
   	getManager("org.apache.tomcat.resources");
  +
  +    // Attributes that will be replaced during include
  +    private static final String A_REQUEST_URI=
  +	"javax.servlet.include.request_uri";
  +    private static final String A_CONTEXT_PATH=
  +    	"javax.servlet.include.context_path";
  +    private static final String A_SERVLET_PATH=
  +	"javax.servlet.include.servlet_path";
  +    private static final String A_PATH_INFO=
  +	"javax.servlet.include.path_info";
  +    private static final String A_QUERY_STRING=
  +	"javax.servlet.include.query_string";
  +    
       
       Context context;
  +
       // path dispatchers
       String path;
       String queryString;
  @@ -136,6 +152,8 @@
       }
   
       // -------------------- Public methods --------------------
  +
  +    // Wrappers for jdk1.2 priviledged actions
       Jdk11Compat jdk11Compat=Jdk11Compat.getJdkCompat();
       RDIAction forwardAction=new RDIAction( this,false);
       RDIAction includeAction=new RDIAction( this,true);
  @@ -144,36 +162,34 @@
   	throws ServletException, IOException
       {
   	if( System.getSecurityManager() != null ) {
  -// 	    final ServletRequest req = request;
  -// 	    final ServletResponse res = response;
   	    try {
   		forwardAction.prepare( request, response );
   		jdk11Compat.doPrivileged( forwardAction );
  -
  -// 		java.security.AccessController.doPrivileged(
  -// 		    new java.security.PrivilegedExceptionAction()
  -// 		    {
  -// 			public Object run() throws ServletException, IOException {
  -// 			    doForward(req,res);
  -// 			    return null;
  -// 			}
  -// 		    }               
  -// 		);
  -// 	    } catch( PrivilegedActionException pe) {
  -// 		Exception e = pe.getException();
   	    } catch( Exception e) {
  -		if( e instanceof ServletException )
  -		    throw (ServletException)e;
  -		if( e instanceof RuntimeException )
  -		    throw (RuntimeException)e;
  -		// can only be IOException
  -		throw (IOException)e;
  +		wrapException( e, null );
   	    }
   	} else {
   	    doForward(request,response);
   	}
       }
   
  +    public void include(ServletRequest request, ServletResponse response)
  +	throws ServletException, IOException
  +    {
  +	if( System.getSecurityManager() != null ) {
  +	    try {
  +		includeAction.prepare( request, response );
  +		jdk11Compat.doPrivileged( includeAction );
  +	    } catch( Exception e) {
  +		wrapException( e, null );
  +	    }
  +	} else {
  +	    doInclude(request,response);
  +	}
  +    }
  +
  +    // -------------------- Actual forward/include impl --------------------
  +    
       private void doForward(ServletRequest request, ServletResponse response)
   	throws ServletException, IOException
       {
  @@ -211,8 +227,12 @@
   
   	// merge query string as specified in specs - before, it may affect
   	// the way the request is handled by special interceptors
  -	if( queryString != null )
  -	    addQueryString( realRequest, queryString );
  +	if( queryString != null ) {
  +	    // Append queryString to the request parameters -
  +	    // the original request is changed.
  +	    realRequest.parameters().processParameters( queryString ); 
  +	    //	    addQueryString( realRequest, queryString );
  +	}
   	
   	// run the new request through the context manager
   	// not that this is a very particular case of forwarding
  @@ -221,57 +241,38 @@
   	// unset "included" attribute if any - we may be in a servlet
   	// included from another servlet,
   	// in which case the attribute will create problems
  -	realRequest.removeAttribute( "javax.servlet.include.request_uri");
  -	realRequest.removeAttribute( "javax.servlet.include.servlet_path");
  +	realRequest.removeAttribute( A_REQUEST_URI);
  +	realRequest.removeAttribute( A_SERVLET_PATH);
   
   
   	// CM should have set the wrapper - call it
   	Handler wr=realRequest.getHandler();
  -	if( wr!=null ) 
  -	    invoke( wr, realRequest, realResponse);
  +	if( wr!=null ) {
  +	    try {
  +		wr.service(realRequest, realResponse);
  +	    } catch( Exception ex ) {
  +		realResponse.setErrorException(ex);
  +	    }
  +	}
  +
   	// Clean up the request and response as needed
  -	;       // No action required
  +	// No action required
   
  -	// Rethrow original error if present
   	if ( realResponse.isExceptionPresent() ) {
   	    // if error URI not set, set our URI
   	    if ( null == realResponse.getErrorURI() )
   		realResponse.setErrorURI( context.getPath() + path );
   	    Exception ex = realResponse.getErrorException();
  -	    if ( ex instanceof IOException )
  -		throw (IOException) ex;
  -	    if ( ex instanceof RuntimeException )
  -		throw (RuntimeException) ex;
  -	    else if ( ex instanceof ServletException )
  -		throw (ServletException) ex;
  -	    else
  -		throw new ServletException
  -		    (sm.getString("dispatcher.forwardException"), ex );
  +	    wrapException( ex,
  +			   sm.getString("dispatcher.forwardException"));
   	}
  -
  +	
   	// close the response - output after this point will be discarded.
  +	// XXX XXX Maybe this is Henri's bug !!!
   	realResponse.finish();
       }
   
  -    public void include(ServletRequest request, ServletResponse response)
  -	throws ServletException, IOException
  -    {
  -	if( System.getSecurityManager() != null ) {
  -	    try {
  -		includeAction.prepare( request, response );
  -		jdk11Compat.doPrivileged( includeAction );
  -	    } catch( Exception e) {
  -		if( e instanceof ServletException )
  -		    throw (ServletException)e;
  -		if( e instanceof RuntimeException )
  -		    throw (RuntimeException)e;
  -		// can only be IOException
  -		throw (IOException)e;
  -	    }
  -	} else {
  -	    doInclude(request,response);
  -	}
  -    }
  +    // -------------------- Include --------------------
   
       private void doInclude(ServletRequest request, ServletResponse response)
   	throws ServletException, IOException
  @@ -279,7 +280,13 @@
           Request realRequest = ((HttpServletRequestFacade)request).
   	    getRealRequest();
   	Response realResponse = realRequest.getResponse();
  +	
   
  +	if( debug ) {
  +	    System.out.println("RDI: doInclude: " + path + " " + name +
  +			       " " + queryString );
  +	}
  +	
   	// the strange case in a separate method
   	if( name!=null) {
   	    includeNamed( request, response );
  @@ -294,8 +301,6 @@
   	    realResponse.setIncluded( true );
   	}
   
  -	// Here the spec is very special, pay attention
  -
   	// We need to pass the original request, with all the paths -
   	// and the new paths in special attributes.
   
  @@ -311,7 +316,7 @@
   	    createRequest( context, path );
   	subRequest.setParent( realRequest );
   	subRequest.getTop(); // control inclusion depth
  -	
  +
   	// I hope no interceptor (or code) in processRequest use any
   	// of the original request info ( like Auth headers )
   	//
  @@ -326,64 +331,42 @@
   	subRequest.setResponse( realResponse );
   	
   	context.getContextManager().processRequest(subRequest);
  +	
   	// Now subRequest containse the processed and aliased paths, plus
   	// the wrapper that will handle the request.
   
   	// We will use the stack a bit - save all path attributes, set the
   	// new values, and after return from wrapper revert to the original
  -	Object old_request_uri=realRequest.
  -	    getAttribute("javax.servlet.include.request_uri");
  -	realRequest.setAttribute("javax.servlet.include.request_uri",
  -				 //				 path);
  -				 context.getPath() + path );
  -
  -	Object old_context_path=realRequest.
  -	    getAttribute("javax.servlet.include.context_path");
  -	realRequest.setAttribute("javax.servlet.include.context_path",
  -				 context.getPath());
  -	// never change anyway - RD can't get out
  -
  -	Object old_servlet_path=realRequest.
  -	    getAttribute("javax.servlet.include.servlet_path");
  -	realRequest.setAttribute("javax.servlet.include.servlet_path",
  -				 subRequest.servletPath().toString());
  -	
  -	Object old_path_info=realRequest.
  -	    getAttribute("javax.servlet.include.path_info");
  -	realRequest.setAttribute("javax.servlet.include.path_info",
  -				 subRequest.pathInfo().toString());
  -
  -	Object old_query_string=realRequest.
  -	    getAttribute("javax.servlet.include.query_string");
  -	realRequest.setAttribute("javax.servlet.include.query_string",
  -				 queryString);
  -	
  -	if( false ) {
  -	    System.out.println("RD: " + old_request_uri + " " +
  +	Object old_request_uri=replaceAttribute(realRequest, A_REQUEST_URI,
  +						context.getPath() + path );
  +	Object old_context_path=replaceAttribute(realRequest, A_CONTEXT_PATH,
  +						 context.getPath());
  +	Object old_servlet_path=replaceAttribute(realRequest, A_SERVLET_PATH,
  +					 subRequest.servletPath().toString());
  +	Object old_path_info=replaceAttribute(realRequest, A_PATH_INFO,
  +					  subRequest.pathInfo().toString());
  +	Object old_query_string=replaceAttribute(realRequest, A_QUERY_STRING,
  +						 queryString);
  +
  +	if( debug ) {
  +	    System.out.println("RDI: old " + old_request_uri + " " +
   			       old_context_path + " " + old_servlet_path +
   			       " " + old_path_info + " " + old_query_string);
  -	    System.out.println("NEW: " + context.getPath() + " " + path + " "
  +	    System.out.println("RDI: new "+context.getPath() + " " + path + " "
   			       + subRequest.servletPath().toString() + " " +
   			       subRequest.pathInfo().toString() + " " +
   			       queryString);
   	}
  -	
  -	// Not explicitely stated, but we need to save the old parameters
  -	// before adding the new ones
  -	realRequest.getParameterNames();
  -	// force reading of parameters from POST
  -	Hashtable old_parameters=(Hashtable)realRequest.getParameters().clone();
  -
  -	// NOTE: it has a side effect of _reading_ the form data - which
  -	// is against the specs ( you can't read the post until asked for
  -	// parameters). I see no way of dealing with that -
  -	// if we don't do it and the included request need a parameter,
  -	// the form will be read and we'll have no way to know that.
   
  -	// IMHO the spec should do something about that - or smarter
  -	// people should implement the spec. ( costin )
  +	if( queryString != null ) {
  +	    // the original parameters will be preserved, and a new
  +	    // child Parameters will be used for the included request.
  +	    realRequest.parameters().push();
  +	    Parameters child=realRequest.parameters().getCurrentSet();
   
  -	addQueryString( realRequest, queryString );
  +	    child.processParameters( queryString );
  +	    
  +	}
   
   	Request old_child = realRequest.getChild();
   	realRequest.setChild( subRequest );
  @@ -391,26 +374,34 @@
    	// now it's really strange: we call the wrapper on the subrequest
   	// for the realRequest ( since the real request will still have the
   	// original handler/wrapper )
  +
   	Handler wr=subRequest.getHandler();
  -	if( wr!=null ) 
  -	    invoke( wr, realRequest, realResponse);
  +	if( wr!=null ) {
  +	    try {
  +		wr.service(realRequest, realResponse);
  +	    } catch( Exception ex ) {
  +		realResponse.setErrorException(ex);
  +	    }
  +	}
  +
   	
   	// After request, we want to restore the include attributes - for
   	// chained includes.
  -	realRequest.setChild( old_child );
   
  -	realRequest.setParameters( old_parameters);
  +	realRequest.setChild( old_child );
   
  -	replaceAttribute( realRequest, "javax.servlet.include.request_uri",
  -				 old_request_uri);
  -	replaceAttribute( realRequest, "javax.servlet.include.context_path",
  -				 old_context_path); 
  -	replaceAttribute( realRequest, "javax.servlet.include.servlet_path",
  -				 old_servlet_path);
  -	replaceAttribute( realRequest, "javax.servlet.include.path_info",
  -				 old_path_info);
  -	replaceAttribute( realRequest, "javax.servlet.include.query_string",
  -				 old_query_string);
  +	if( queryString != null ) {
  +	    // restore the parameters
  +	    realRequest.parameters().pop();
  +	}
  +	//realRequest.setParameters( old_parameters);
  +
  +	replaceAttribute( realRequest, A_REQUEST_URI, old_request_uri);
  +	replaceAttribute( realRequest, A_CONTEXT_PATH,old_context_path); 
  +	replaceAttribute( realRequest, A_SERVLET_PATH, old_servlet_path);
  +	replaceAttribute( realRequest, A_PATH_INFO, old_path_info);
  +	replaceAttribute( realRequest, A_QUERY_STRING, old_query_string);
  +	
   	// revert to the response behavior
   	if( ! old_included ) {
   	    realResponse.setIncluded( false );
  @@ -422,24 +413,16 @@
   	    if ( null == realResponse.getErrorURI() )
   		realResponse.setErrorURI( context.getPath() + path );
   	    Exception ex = realResponse.getErrorException();
  -	    if ( ex instanceof IOException )
  -		throw (IOException) ex;
  -	    if ( ex instanceof RuntimeException )
  -		throw (RuntimeException) ex;	
  -	    else if ( ex instanceof ServletException )
  -		throw (ServletException) ex;
  -	    else
  -		throw new ServletException
  -		    (sm.getString("dispatcher.includeException"), ex);
  +	    wrapException( ex, sm.getString("dispatcher.includeException"));
   	}
       }
   
  -	
  +    // -------------------- Special case of "named" dispatcher -------------
   
       /** Named dispatcher include
        *  Separate from normal include - which is still too messy
        */
  -    public void includeNamed(ServletRequest request, ServletResponse response)
  +    private void includeNamed(ServletRequest request, ServletResponse response)
   	throws ServletException, IOException
       {
   	// We got here if name!=null, so assert it
  @@ -453,8 +436,13 @@
   	boolean old_included=realResponse.isIncluded();
   	if( ! old_included ) realResponse.setIncluded( true );
   
  -	if( wr!=null)
  -	    invoke( wr, realRequest, realResponse);
  +	if( wr!=null) {
  +	    try {
  +		wr.service(realRequest, realResponse);
  +	    } catch( Exception ex ) {
  +		realResponse.setErrorException( ex );
  +	    }
  +	}
   
           // Clean up the request and response as needed
   	if( ! old_included ) {
  @@ -466,27 +454,22 @@
   	    // if error URI not set, set our URI
   	    if ( null == realResponse.getErrorURI() )
   		realResponse.setErrorURI( "named servlet: " + name );
  -	    Exception ex = realResponse.getErrorException();
  -	    if ( ex instanceof IOException )
  -		throw (IOException) ex;
  -	    else if ( ex instanceof ServletException )
  -		throw (ServletException) ex;
  -	    else
  -		throw new ServletException
  -		    (sm.getString("dispatcher.includeException", ex));
  +	    wrapException( realResponse.getErrorException(),
  +			   sm.getString("dispatcher.includeException"));
   	}
       }
   
       /** Named forward
        */
  -    public void forwardNamed(ServletRequest request, ServletResponse response)
  +    private void forwardNamed(ServletRequest request, ServletResponse response)
   	throws ServletException, IOException
       {
   	// We got here if name!=null, so assert it
   	Handler wr = context.getServletByName( name );
   
   	// Use the original request - as in specification !
  -	Request realRequest=((HttpServletRequestFacade)request).getRealRequest();
  +	Request realRequest=((HttpServletRequestFacade)request).
  +	    getRealRequest();
   	Response realResponse = realRequest.getResponse();
   
   	// Set the "included" flag so that things like header setting in the
  @@ -494,118 +477,62 @@
   	boolean old_included=realResponse.isIncluded();
   	if( ! old_included ) realResponse.setIncluded( true );
   
  -	if( wr!=null)
  -	    invoke( wr, realRequest, realResponse);
  +	if( wr!=null) {
  +	    try {
  +		wr.service(realRequest, realResponse);
  +	    } catch( Exception ex ) {
  +		wrapException( ex, null );
  +	    }
  +	}
   
   	// Clean up the request and response as needed
  -	;       // No action required
  +	// No action required
   
   	// Rethrow original error if present
   	if ( realResponse.isExceptionPresent() ) {
   	    // if error URI not set, set our URI
   	    if ( null == realResponse.getErrorURI() )
   		realResponse.setErrorURI( "named servlet: " + name );
  -	    Exception ex = realResponse.getErrorException();
  -	    if ( ex instanceof IOException )
  -		throw (IOException) ex;
  -	    else if ( ex instanceof ServletException )
  -		throw (ServletException) ex;
  -	    else
  -		throw new ServletException
  -		    (sm.getString("dispatcher.forwardException", ex));
  +	    wrapException( realResponse.getErrorException(),
  +			   sm.getString("dispatcher.forwardException"));
   	}
       }    
   
  -    /**
  -     * Adds a query string to the existing set of parameters.
  -     * The additional parameters represented by the query string will be
  -     * merged with the existing parameters.
  -     * Used by the RequestDispatcherImpl to add query string parameters
  -     * to the request.
  -     *
  -     * @param inQueryString URLEncoded parameters to add
  -     */
  -    void addQueryString(Request req, String inQueryString) {
  -        // if query string is null, do nothing
  -        if ((inQueryString == null) || (inQueryString.trim().length() <= 0))
  -            return;
  -
  -	Hashtable newParams = HttpUtils.parseQueryString(queryString);
  -	Hashtable parameters= req.getParameters();
  -
  -	// add new to old ( it alters the original hashtable in request)
  -	Enumeration e=newParams.keys();
  -	while(e.hasMoreElements() ) {
  -	    String key=(String)e.nextElement();
  -	    Object oldValue = parameters.get(key);
  -	    Object newValue = newParams.get(key);
  -	    // The simple case -- no existing parameters with this name
  -	    if (oldValue == null) {
  -		parameters.put( key, newValue);
  -		continue;
  -	    }
  -	    // Construct arrays of the old and new values
  -	    String oldValues[] = null;
  -	    if (oldValue instanceof String[]) {
  -		oldValues = (String[]) oldValue;
  -	    } else if (oldValue instanceof String) {
  -		oldValues = new String[1];
  -		oldValues[0] = (String) oldValue;
  -	    } else {
  -		// Can not happen?
  -		oldValues = new String[1];
  -		oldValues[0] = oldValue.toString();
  -	    }
  -	    String newValues[] = null;
  -	    if (newValue instanceof String[]) {
  -		newValues = (String[]) newValue;
  -	    } else if (newValue instanceof String) {
  -		newValues = new String[1];
  -		newValues[0] = (String) newValue;
  -	    } else {
  -		// Can not happen?
  -		newValues = new String[1];
  -		newValues[0] = newValue.toString();
  -	    }
  -	    // Merge the two sets of values into a new array
  -	    String mergedValues[] =
  -		new String[newValues.length + oldValues.length];
  -	    for (int i = 0; i < newValues.length; i++)
  -		mergedValues[i] = newValues[i];	// New values first per spec
  -	    for (int i = newValues.length; i < mergedValues.length; i++)
  -		mergedValues[i] = oldValues[i - newValues.length];
  -	    // Save the merged values list in the original request
  -	    parameters.put(key, mergedValues);
  -	}
  -    }
  +    // -------------------- Special methods --------------------
   
       /** Restore attribute - if value is null, remove the attribute.
  -     *  X Maybe it should be the befavior of setAttribute() - it is not
  -     *  specified what to do with null.
        *  ( or it is - null means no value in getAttribute, so setting to
        *    null should mean setting to no value. ?)
        */
  -    private void replaceAttribute( Request realRequest, String name, Object value) {
  +    private Object replaceAttribute( Request realRequest, String name,
  +				     Object value)
  +    {
  +	Object oldAttribute=realRequest.getAttribute(name);
   	if( value == null )
   	    realRequest.removeAttribute( name );
   	else
   	    realRequest.setAttribute( name, value );
  +	return oldAttribute;
       }
   
  -    private void invoke( Handler wr, Request req, Response resp )
  -	throws IOException, ServletException
  +    // Rethrow original error if present 
  +    private void wrapException(Exception ex, String msg)
  +	throws IOException, ServletException, RuntimeException
       {
  -	try {
  -	    wr.service(req, resp);
  -	} catch( Exception ex ) {
  -	    if( ex instanceof ServletException )
  -		throw (ServletException)ex;
  -	    if( ex instanceof IOException )
  -		throw (IOException)ex;
  -	    throw new ServletException( ex );
  -	}
  +	if ( ex instanceof IOException )
  +	    throw (IOException) ex;
  +	if ( ex instanceof RuntimeException )
  +	    throw (RuntimeException) ex;
  +	else if ( ex instanceof ServletException )
  +	    throw (ServletException) ex;
  +	else
  +	    if( msg==null )
  +		throw new ServletException(ex );
  +	    else
  +		throw new ServletException(msg, ex );
       }
   
  +    // -------------------- Used for doPriviledged in JDK1.2 ----------
       static class RDIAction extends Action {
   	ServletRequest req;
   	ServletResponse res;