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;